Skip to content

Commit a101526

Browse files
authored
Merge pull request #271 from hkalexling/rc/0.25.0
v0.25.0
2 parents dc5edc0 + eca47e3 commit a101526

26 files changed

+645
-153
lines changed

README.md

+4-11
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.24.0
54+
Mango - Manga Server and Web Reader. Version 0.25.0
5555
5656
Usage:
5757
@@ -80,30 +80,23 @@ base_url: /
8080
session_secret: mango-session-secret
8181
library_path: ~/mango/library
8282
db_path: ~/mango/mango.db
83+
queue_db_path: ~/mango/queue.db
8384
scan_interval_minutes: 5
8485
thumbnail_generation_interval_hours: 24
8586
log_level: info
8687
upload_path: ~/mango/uploads
8788
plugin_path: ~/mango/plugins
8889
download_timeout_seconds: 30
8990
library_cache_path: ~/mango/library.yml.gz
90-
cache_enabled: false
91+
cache_enabled: true
9192
cache_size_mbs: 50
9293
cache_log_enabled: true
9394
disable_login: false
9495
default_username: ""
9596
auth_proxy_header_name: ""
96-
mangadex:
97-
base_url: https://mangadex.org
98-
api_url: https://api.mangadex.org/v2
99-
download_wait_seconds: 5
100-
download_retries: 4
101-
download_queue_db_path: ~/mango/queue.db
102-
chapter_rename_rule: '[Vol.{volume} ][Ch.{chapter} ]{title|id}'
103-
manga_rename_rule: '{title}'
10497
```
10598
106-
- `scan_interval_minutes`, `thumbnail_generation_interval_hours` and `db_optimization_interval_hours` can be any non-negative integer. Setting them to `0` disables the periodic tasks
99+
- `scan_interval_minutes`, `thumbnail_generation_interval_hours` can be any non-negative integer. Setting them to `0` disables the periodic tasks
107100
- `log_level` can be `debug`, `info`, `warn`, `error`, `fatal` or `off`. Setting it to `off` disables the logging
108101
- You can disable authentication by setting `disable_login` to true. Note that `default_username` must be set to an existing username for this to work.
109102
- By setting `cache_enabled` to `true`, you can enable an experimental feature where Mango caches library metadata to improve page load time. You can further fine-tune the feature with `cache_size_mbs` and `cache_log_enabled`.

migration/sort_title.12.cr

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
class SortTitle < MG::Base
2+
def up : String
3+
<<-SQL
4+
-- add sort_title column to ids and titles
5+
ALTER TABLE ids ADD COLUMN sort_title TEXT;
6+
ALTER TABLE titles ADD COLUMN sort_title TEXT;
7+
SQL
8+
end
9+
10+
def down : String
11+
<<-SQL
12+
-- remove sort_title column from ids
13+
ALTER TABLE ids RENAME TO tmp;
14+
15+
CREATE TABLE ids (
16+
path TEXT NOT NULL,
17+
id TEXT NOT NULL,
18+
signature TEXT,
19+
unavailable INTEGER NOT NULL DEFAULT 0
20+
);
21+
22+
INSERT INTO ids
23+
SELECT path, id, signature, unavailable
24+
FROM tmp;
25+
26+
DROP TABLE tmp;
27+
28+
-- recreate the indices
29+
CREATE UNIQUE INDEX path_idx ON ids (path);
30+
CREATE UNIQUE INDEX id_idx ON ids (id);
31+
32+
-- recreate the foreign key constraint on thumbnails
33+
ALTER TABLE thumbnails RENAME TO tmp;
34+
35+
CREATE TABLE thumbnails (
36+
id TEXT NOT NULL,
37+
data BLOB NOT NULL,
38+
filename TEXT NOT NULL,
39+
mime TEXT NOT NULL,
40+
size INTEGER NOT NULL,
41+
FOREIGN KEY (id) REFERENCES ids (id)
42+
ON UPDATE CASCADE
43+
ON DELETE CASCADE
44+
);
45+
46+
INSERT INTO thumbnails
47+
SELECT * FROM tmp;
48+
49+
DROP TABLE tmp;
50+
51+
CREATE UNIQUE INDEX tn_index ON thumbnails (id);
52+
53+
-- remove sort_title column from titles
54+
ALTER TABLE titles RENAME TO tmp;
55+
56+
CREATE TABLE titles (
57+
id TEXT NOT NULL,
58+
path TEXT NOT NULL,
59+
signature TEXT,
60+
unavailable INTEGER NOT NULL DEFAULT 0
61+
);
62+
63+
INSERT INTO titles
64+
SELECT id, path, signature, unavailable
65+
FROM tmp;
66+
67+
DROP TABLE tmp;
68+
69+
-- recreate the indices
70+
CREATE UNIQUE INDEX titles_id_idx on titles (id);
71+
CREATE UNIQUE INDEX titles_path_idx on titles (path);
72+
73+
-- recreate the foreign key constraint on tags
74+
ALTER TABLE tags RENAME TO tmp;
75+
76+
CREATE TABLE tags (
77+
id TEXT NOT NULL,
78+
tag TEXT NOT NULL,
79+
UNIQUE (id, tag),
80+
FOREIGN KEY (id) REFERENCES titles (id)
81+
ON UPDATE CASCADE
82+
ON DELETE CASCADE
83+
);
84+
85+
INSERT INTO tags
86+
SELECT * FROM tmp;
87+
88+
DROP TABLE tmp;
89+
90+
CREATE INDEX tags_id_idx ON tags (id);
91+
CREATE INDEX tags_tag_idx ON tags (tag);
92+
SQL
93+
end
94+
end

public/js/download-manager.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const component = () => {
5555
jobAction(action, event) {
5656
let url = `${base_url}api/admin/mangadex/queue/${action}`;
5757
if (event) {
58-
const id = event.currentTarget.closest('tr').id.split('-')[1];
58+
const id = event.currentTarget.closest('tr').id.split('-').slice(1).join('-');
5959
url = `${url}?${$.param({
6060
id: id
6161
})}`;

public/js/plugin-download.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ const buildTable = (chapters) => {
6868
$('table').append(thead);
6969

7070
const rows = chapters.map(ch => {
71-
const tds = Object.values(ch).map(v => `<td>${v}</td>`).join('');
71+
const tds = Object.values(ch).map(v => {
72+
const maxLength = 40;
73+
const shouldShrink = v && v.length > maxLength;
74+
const content = shouldShrink ? `<span title="${v}">${v.substring(0, maxLength)}...</span><div uk-dropdown><span>${v}</span></div>` : v;
75+
return `<td>${content}</td>`
76+
}).join('');
7277
return `<tr data-id="${ch.id}" data-title="${ch.title}">${tds}</tr>`;
7378
});
7479
const tbody = `<tbody id="selectable">${rows}</tbody>`;

public/js/reader.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const readerComponent = () => {
1313
selectedIndex: 0, // 0: not selected; 1: the first page
1414
margin: 30,
1515
preloadLookahead: 3,
16+
enableRightToLeft: false,
1617

1718
/**
1819
* Initialize the component by fetching the page dimensions
@@ -64,6 +65,13 @@ const readerComponent = () => {
6465

6566
const savedFlipAnimation = localStorage.getItem('enableFlipAnimation');
6667
this.enableFlipAnimation = savedFlipAnimation === null || savedFlipAnimation === 'true';
68+
69+
const savedRightToLeft = localStorage.getItem('enableRightToLeft');
70+
if (savedRightToLeft === null) {
71+
this.enableRightToLeft = false;
72+
} else {
73+
this.enableRightToLeft = (savedRightToLeft === 'true');
74+
}
6775
})
6876
.catch(e => {
6977
const errMsg = `Failed to get the page dimensions. ${e}`;
@@ -114,9 +122,9 @@ const readerComponent = () => {
114122
if (this.mode === 'continuous') return;
115123

116124
if (event.key === 'ArrowLeft' || event.key === 'k')
117-
this.flipPage(false);
125+
this.flipPage(false ^ this.enableRightToLeft);
118126
if (event.key === 'ArrowRight' || event.key === 'j')
119-
this.flipPage(true);
127+
this.flipPage(true ^ this.enableRightToLeft);
120128
},
121129
/**
122130
* Flips to the next or the previous page
@@ -136,7 +144,7 @@ const readerComponent = () => {
136144
this.toPage(newIdx);
137145

138146
if (this.enableFlipAnimation) {
139-
if (isNext)
147+
if (isNext ^ this.enableRightToLeft)
140148
this.flipAnimation = 'right';
141149
else
142150
this.flipAnimation = 'left';
@@ -320,5 +328,9 @@ const readerComponent = () => {
320328
enableFlipAnimationChanged() {
321329
localStorage.setItem('enableFlipAnimation', this.enableFlipAnimation);
322330
},
331+
332+
enableRightToLeftChanged() {
333+
localStorage.setItem('enableRightToLeft', this.enableRightToLeft);
334+
},
323335
};
324336
}

public/js/title.js

+62-6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ function showModal(encodedPath, pages, percentage, encodedeTitle, encodedEntryTi
6060
UIkit.modal($('#modal')).show();
6161
}
6262

63+
UIkit.util.on(document, 'hidden', '#modal', () => {
64+
$('#read-btn').off('click');
65+
$('#unread-btn').off('click');
66+
});
67+
6368
const updateProgress = (tid, eid, page) => {
6469
let url = `${base_url}api/progress/${tid}/${page}`
6570
const query = $.param({
@@ -90,8 +95,6 @@ const renameSubmit = (name, eid) => {
9095
const upload = $('.upload-field');
9196
const titleId = upload.attr('data-title-id');
9297

93-
console.log(name);
94-
9598
if (name.length === 0) {
9699
alert('danger', 'The display name should not be empty');
97100
return;
@@ -122,15 +125,47 @@ const renameSubmit = (name, eid) => {
122125
});
123126
};
124127

128+
const renameSortNameSubmit = (name, eid) => {
129+
const upload = $('.upload-field');
130+
const titleId = upload.attr('data-title-id');
131+
132+
const params = {};
133+
if (eid) params.eid = eid;
134+
if (name) params.name = name;
135+
const query = $.param(params);
136+
let url = `${base_url}api/admin/sort_title/${titleId}?${query}`;
137+
138+
$.ajax({
139+
type: 'PUT',
140+
url,
141+
contentType: 'application/json',
142+
dataType: 'json'
143+
})
144+
.done(data => {
145+
if (data.error) {
146+
alert('danger', `Failed to update sort title. Error: ${data.error}`);
147+
return;
148+
}
149+
location.reload();
150+
})
151+
.fail((jqXHR, status) => {
152+
alert('danger', `Failed to update sort title. Error: [${jqXHR.status}] ${jqXHR.statusText}`);
153+
});
154+
};
155+
125156
const edit = (eid) => {
126157
const cover = $('#edit-modal #cover');
127158
let url = cover.attr('data-title-cover');
128159
let displayName = $('h2.uk-title > span').text();
160+
let fileTitle = $('h2.uk-title').attr('data-file-title');
161+
let sortTitle = $('h2.uk-title').attr('data-sort-title');
129162

130163
if (eid) {
131164
const item = $(`#${eid}`);
132165
url = item.find('img').attr('data-src');
133166
displayName = item.find('.uk-card-title').attr('data-title');
167+
fileTitle = item.find('.uk-card-title').attr('data-file-title');
168+
sortTitle = item.find('.uk-card-title').attr('data-sort-title');
134169
$('#title-progress-control').attr('hidden', '');
135170
} else {
136171
$('#title-progress-control').removeAttr('hidden');
@@ -140,21 +175,43 @@ const edit = (eid) => {
140175

141176
const displayNameField = $('#display-name-field');
142177
displayNameField.attr('value', displayName);
143-
console.log(displayNameField);
178+
displayNameField.attr('placeholder', fileTitle);
144179
displayNameField.keyup(event => {
145180
if (event.keyCode === 13) {
146-
renameSubmit(displayNameField.val(), eid);
181+
renameSubmit(displayNameField.val() || fileTitle, eid);
147182
}
148183
});
149184
displayNameField.siblings('a.uk-form-icon').click(() => {
150-
renameSubmit(displayNameField.val(), eid);
185+
renameSubmit(displayNameField.val() || fileTitle, eid);
186+
});
187+
188+
const sortTitleField = $('#sort-title-field');
189+
sortTitleField.val(sortTitle);
190+
sortTitleField.attr('placeholder', fileTitle);
191+
sortTitleField.keyup(event => {
192+
if (event.keyCode === 13) {
193+
renameSortNameSubmit(sortTitleField.val(), eid);
194+
}
195+
});
196+
sortTitleField.siblings('a.uk-form-icon').click(() => {
197+
renameSortNameSubmit(sortTitleField.val(), eid);
151198
});
152199

153200
setupUpload(eid);
154201

155202
UIkit.modal($('#edit-modal')).show();
156203
};
157204

205+
UIkit.util.on(document, 'hidden', '#edit-modal', () => {
206+
const displayNameField = $('#display-name-field');
207+
displayNameField.off('keyup');
208+
displayNameField.off('click');
209+
210+
const sortTitleField = $('#sort-title-field');
211+
sortTitleField.off('keyup');
212+
sortTitleField.off('click');
213+
});
214+
158215
const setupUpload = (eid) => {
159216
const upload = $('.upload-field');
160217
const bar = $('#upload-progress').get(0);
@@ -166,7 +223,6 @@ const setupUpload = (eid) => {
166223
queryObj['eid'] = eid;
167224
const query = $.param(queryObj);
168225
const url = `${base_url}api/admin/upload/cover?${query}`;
169-
console.log(url);
170226
UIkit.upload('.upload-field', {
171227
url: url,
172228
name: 'file',

shard.yml

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

44
authors:
55
- Alex Ling <[email protected]>

0 commit comments

Comments
 (0)