Skip to content

Commit 1fb4864

Browse files
authored
Merge pull request #322 from getmango/rc/0.27.0
v0.27.0
2 parents 61dc928 + 7ceb91f commit 1fb4864

28 files changed

+679
-223
lines changed

.ameba.yml

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ Layout/LineLength:
1212
MaxLength: 80
1313
Excluded:
1414
- src/routes/api.cr
15+
- spec/plugin_spec.cr

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ The official docker images are available on [Dockerhub](https://hub.docker.com/r
5151
### CLI
5252

5353
```
54-
Mango - Manga Server and Web Reader. Version 0.26.2
54+
Mango - Manga Server and Web Reader. Version 0.27.0
5555
5656
Usage:
5757

public/js/plugin-download.js

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const component = () => {
22
return {
33
plugins: [],
4+
subscribable: false,
45
info: undefined,
56
pid: undefined,
67
chapters: undefined, // undefined: not searched yet, []: empty
@@ -60,6 +61,7 @@ const component = () => {
6061
.then((data) => {
6162
if (!data.success) throw new Error(data.error);
6263
this.info = data.info;
64+
this.subscribable = data.subscribable;
6365
this.pid = pid;
6466
})
6567
.catch((e) => {
@@ -70,6 +72,9 @@ const component = () => {
7072
});
7173
},
7274
pluginChanged() {
75+
this.manga = undefined;
76+
this.chapters = undefined;
77+
this.mid = undefined;
7378
this.loadPlugin(this.pid);
7479
localStorage.setItem("plugin", this.pid);
7580
},
@@ -140,6 +145,7 @@ const component = () => {
140145
if (!query) return;
141146

142147
this.manga = undefined;
148+
this.mid = undefined;
143149
if (this.info.version === 1) {
144150
this.searchChapters(query);
145151
} else {

public/js/reader.js

+33-8
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const readerComponent = () => {
1414
margin: 30,
1515
preloadLookahead: 3,
1616
enableRightToLeft: false,
17+
fitType: 'vert',
1718

1819
/**
1920
* Initialize the component by fetching the page dimensions
@@ -29,14 +30,16 @@ const readerComponent = () => {
2930
return {
3031
id: i + 1,
3132
url: `${base_url}api/page/${tid}/${eid}/${i+1}`,
32-
width: d.width,
33-
height: d.height,
33+
width: d.width == 0 ? "100%" : d.width,
34+
height: d.height == 0 ? "100%" : d.height,
3435
};
3536
});
3637

37-
const avgRatio = this.items.reduce((acc, cur) => {
38+
// Note: for image types not supported by image_size.cr, the width and height will be 0, and so `avgRatio` will be `Infinity`.
39+
// TODO: support more image types in image_size.cr
40+
const avgRatio = dimensions.reduce((acc, cur) => {
3841
return acc + cur.height / cur.width
39-
}, 0) / this.items.length;
42+
}, 0) / dimensions.length;
4043

4144
console.log(avgRatio);
4245
this.longPages = avgRatio > 2;
@@ -58,11 +61,16 @@ const readerComponent = () => {
5861

5962
// Preload Images
6063
this.preloadLookahead = +(localStorage.getItem('preloadLookahead') ?? 3);
61-
const limit = Math.min(page + this.preloadLookahead, this.items.length + 1);
64+
const limit = Math.min(page + this.preloadLookahead, this.items.length);
6265
for (let idx = page + 1; idx <= limit; idx++) {
6366
this.preloadImage(this.items[idx - 1].url);
6467
}
6568

69+
const savedFitType = localStorage.getItem('fitType');
70+
if (savedFitType) {
71+
this.fitType = savedFitType;
72+
$('#fit-select').val(savedFitType);
73+
}
6674
const savedFlipAnimation = localStorage.getItem('enableFlipAnimation');
6775
this.enableFlipAnimation = savedFlipAnimation === null || savedFlipAnimation === 'true';
6876

@@ -135,7 +143,11 @@ const readerComponent = () => {
135143
const idx = parseInt(this.curItem.id);
136144
const newIdx = idx + (isNext ? 1 : -1);
137145

138-
if (newIdx <= 0 || newIdx > this.items.length) return;
146+
if (newIdx <= 0) return;
147+
if (newIdx > this.items.length) {
148+
this.showControl(idx);
149+
return;
150+
}
139151

140152
if (newIdx + this.preloadLookahead < this.items.length + 1) {
141153
this.preloadImage(this.items[newIdx + this.preloadLookahead - 1].url);
@@ -253,12 +265,20 @@ const readerComponent = () => {
253265
});
254266
},
255267
/**
256-
* Shows the control modal
268+
* Handles clicked image
257269
*
258270
* @param {Event} event - The triggering event
259271
*/
260-
showControl(event) {
272+
clickImage(event) {
261273
const idx = event.currentTarget.id;
274+
this.showControl(idx);
275+
},
276+
/**
277+
* Shows the control modal
278+
*
279+
* @param {number} idx - selected page index
280+
*/
281+
showControl(idx) {
262282
this.selectedIndex = idx;
263283
UIkit.modal($('#modal-sections')).show();
264284
},
@@ -321,6 +341,11 @@ const readerComponent = () => {
321341
this.toPage(this.selectedIndex);
322342
},
323343

344+
fitChanged(){
345+
this.fitType = $('#fit-select').val();
346+
localStorage.setItem('fitType', this.fitType);
347+
},
348+
324349
preloadLookaheadChanged() {
325350
localStorage.setItem('preloadLookahead', this.preloadLookahead);
326351
},

shard.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: mango
2-
version: 0.26.2
2+
version: 0.27.0
33

44
authors:
55
- Alex Ling <hkalexling@gmail.com>

spec/asset/plugins/plugin/index.js

Whitespace-only changes.

spec/asset/plugins/plugin/info.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"id": "test",
3+
"title": "Test Plugin",
4+
"placeholder": "placeholder",
5+
"wait_seconds": 1
6+
}

spec/config_spec.cr

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
11
require "./spec_helper"
22

33
describe Config do
4-
it "creates config if it does not exist" do
5-
with_default_config do |_, path|
4+
it "creates default config if it does not exist" do
5+
with_default_config do |config, path|
66
File.exists?(path).should be_true
7+
config.port.should eq 9000
78
end
89
end
910

1011
it "correctly loads config" do
1112
config = Config.load "spec/asset/test-config.yml"
1213
config.port.should eq 3000
14+
config.base_url.should eq "/"
15+
end
16+
17+
it "correctly reads config defaults from ENV" do
18+
ENV["LOG_LEVEL"] = "debug"
19+
config = Config.load "spec/asset/test-config.yml"
20+
config.log_level.should eq "debug"
21+
config.base_url.should eq "/"
22+
end
23+
24+
it "correctly handles ENV truthiness" do
25+
ENV["CACHE_ENABLED"] = "false"
26+
config = Config.load "spec/asset/test-config.yml"
27+
config.cache_enabled.should be_false
28+
config.cache_log_enabled.should be_true
29+
config.disable_login.should be_false
1330
end
1431
end

spec/plugin_spec.cr

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
require "./spec_helper"
2+
3+
describe Plugin do
4+
describe "helper functions" do
5+
it "mango.text" do
6+
with_plugin do |plugin|
7+
res = plugin.eval <<-JS
8+
mango.text('<a href="https://github.com">Click Me<a>');
9+
JS
10+
res.should eq "Click Me"
11+
end
12+
end
13+
14+
it "mango.text returns empty string when no text" do
15+
with_plugin do |plugin|
16+
res = plugin.eval <<-JS
17+
mango.text('<img src="https://github.com" />');
18+
JS
19+
res.should eq ""
20+
end
21+
end
22+
23+
it "mango.css" do
24+
with_plugin do |plugin|
25+
res = plugin.eval <<-JS
26+
mango.css('<ul><li class="test">A</li><li class="test">B</li><li>C</li></ul>', 'li.test');
27+
28+
JS
29+
res.should eq ["<li class=\"test\">A</li>", "<li class=\"test\">B</li>"]
30+
end
31+
end
32+
33+
it "mango.css returns empty array when no match" do
34+
with_plugin do |plugin|
35+
res = plugin.eval <<-JS
36+
mango.css('<ul><li class="test">A</li><li class="test">B</li><li>C</li></ul>', 'li.noclass');
37+
JS
38+
res.should eq [] of String
39+
end
40+
end
41+
42+
it "mango.attribute" do
43+
with_plugin do |plugin|
44+
res = plugin.eval <<-JS
45+
mango.attribute('<a href="https://github.com">Click Me<a>', 'href');
46+
JS
47+
res.should eq "https://github.com"
48+
end
49+
end
50+
51+
it "mango.attribute returns undefined when no match" do
52+
with_plugin do |plugin|
53+
res = plugin.eval <<-JS
54+
mango.attribute('<div />', 'href') === undefined;
55+
JS
56+
res.should be_true
57+
end
58+
end
59+
60+
# https://github.com/hkalexling/Mango/issues/320
61+
it "mango.attribute handles tags in attribute values" do
62+
with_plugin do |plugin|
63+
res = plugin.eval <<-JS
64+
mango.attribute('<div data-a="<img />" data-b="test" />', 'data-b');
65+
JS
66+
res.should eq "test"
67+
end
68+
end
69+
end
70+
end

spec/spec_helper.cr

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ require "../src/queue"
33
require "../src/server"
44
require "../src/config"
55
require "../src/main_fiber"
6+
require "../src/plugin/plugin"
67

78
class State
89
@@hash = {} of String => String
@@ -54,3 +55,10 @@ def with_storage
5455
end
5556
end
5657
end
58+
59+
def with_plugin
60+
with_default_config do
61+
plugin = Plugin.new "test", "spec/asset/plugins"
62+
yield plugin
63+
end
64+
end

src/config.cr

+43-23
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,51 @@
11
require "yaml"
22

33
class Config
4+
private OPTIONS = {
5+
"host" => "0.0.0.0",
6+
"port" => 9000,
7+
"base_url" => "/",
8+
"session_secret" => "mango-session-secret",
9+
"library_path" => "~/mango/library",
10+
"library_cache_path" => "~/mango/library.yml.gz",
11+
"db_path" => "~/mango.db",
12+
"queue_db_path" => "~/mango/queue.db",
13+
"scan_interval_minutes" => 5,
14+
"thumbnail_generation_interval_hours" => 24,
15+
"log_level" => "info",
16+
"upload_path" => "~/mango/uploads",
17+
"plugin_path" => "~/mango/plugins",
18+
"download_timeout_seconds" => 30,
19+
"cache_enabled" => true,
20+
"cache_size_mbs" => 50,
21+
"cache_log_enabled" => true,
22+
"disable_login" => false,
23+
"default_username" => "",
24+
"auth_proxy_header_name" => "",
25+
"plugin_update_interval_hours" => 24,
26+
}
27+
428
include YAML::Serializable
529

630
@[YAML::Field(ignore: true)]
7-
property path = ""
8-
property host = "0.0.0.0"
9-
property port : Int32 = 9000
10-
property base_url = "/"
11-
property session_secret = "mango-session-secret"
12-
property library_path = "~/mango/library"
13-
property library_cache_path = "~/mango/library.yml.gz"
14-
property db_path = "~/mango/mango.db"
15-
property queue_db_path = "~/mango/queue.db"
16-
property scan_interval_minutes : Int32 = 5
17-
property thumbnail_generation_interval_hours : Int32 = 24
18-
property log_level = "info"
19-
property upload_path = "~/mango/uploads"
20-
property plugin_path = "~/mango/plugins"
21-
property download_timeout_seconds : Int32 = 30
22-
property cache_enabled = true
23-
property cache_size_mbs = 50
24-
property cache_log_enabled = true
25-
property disable_login = false
26-
property default_username = ""
27-
property auth_proxy_header_name = ""
28-
property plugin_update_interval_hours : Int32 = 24
31+
property path : String = ""
32+
33+
# Go through the options constant above and define them as properties.
34+
# Allow setting the default values through environment variables.
35+
# Overall precedence: config file > environment variable > default value
36+
{% begin %}
37+
{% for k, v in OPTIONS %}
38+
{% if v.is_a? StringLiteral %}
39+
property {{k.id}} : String = ENV[{{k.upcase}}]? || {{ v }}
40+
{% elsif v.is_a? NumberLiteral %}
41+
property {{k.id}} : Int32 = (ENV[{{k.upcase}}]? || {{ v.id }}).to_i
42+
{% elsif v.is_a? BoolLiteral %}
43+
property {{k.id}} : Bool = env_is_true? {{ k.upcase }}, {{ v.id }}
44+
{% else %}
45+
raise "Unknown type in config option: {{ v.class_name.id }}"
46+
{% end %}
47+
{% end %}
48+
{% end %}
2949

3050
@@singlet : Config?
3151

@@ -38,7 +58,7 @@ class Config
3858
end
3959

4060
def self.load(path : String?)
41-
path = "~/.config/mango/config.yml" if path.nil?
61+
path = (ENV["CONFIG_PATH"]? || "~/.config/mango/config.yml") if path.nil?
4262
cfg_path = File.expand_path path, home: true
4363
if File.exists? cfg_path
4464
config = self.from_yaml File.read cfg_path

0 commit comments

Comments
 (0)