Skip to content
This repository was archived by the owner on Mar 23, 2025. It is now read-only.

Commit 0a1d45d

Browse files
authored
Merge pull request #21 from hkalexling/feature/mangadex-v2
Update MangaDex plugin to target the v2 plugin API
2 parents f045ecd + 3ae5ce5 commit 0a1d45d

File tree

8 files changed

+181
-181
lines changed

8 files changed

+181
-181
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ To install a plugin, simply download the folder containing the desired plugin (e
88

99
## Contributing
1010

11-
Pull requests are always welcome! Please check out the [development guidelne](https://github.com/hkalexling/mango-plugins/wiki/Development-Guideline).
11+
Pull requests are always welcome! Please check out the [development guidelne](https://github.com/hkalexling/mango-plugins/wiki/Development-Guideline-v2).

plugins/mangadex/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
storage.json
2+
subscriptions.json

plugins/mangadex/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
# MangaDex Plugin
22

3-
This is the Mango plugin for [MangaDex](https://mangadex.org/). It's developed to demonstrate the usage of the plugin system, and you should use the built-in MangaDex downloader in Mango instead.
3+
This is the official Mango plugin for [MangaDex](https://mangadex.org/).
4+
5+
If you are looking for the v1 version of this plugin (deprecated), check out commit f045ecd5752823f100baf4f298d89f2f99237cd4.
6+
7+
### Configuration
8+
9+
Under the `settings` field in `info.json`, you can customize the following values:
10+
11+
#### `language`
12+
13+
You can list one or more language codes in this field (separated by commas) for the plugin to search MangaDex in. Only chapters in one of the specified languages will be shown and used. Check [here](https://api.mangadex.org/docs.html#section/Language-Codes-and-Localization) for the list of available language codes. When it's not set, the plugin will show you chapters in all languages, and you probably don't want that.
14+
15+
#### `listChapterLimit`
16+
17+
This field controls the maximum number of chapters the plugin lists when browsing a manga or when checking for updates. It can be anything between `1` and `500`. Unset it to use the default value `100` from MangaDex.
418

519
Maintained by [@hkalexling](https://github.com/hkalexling).

plugins/mangadex/index.js

Lines changed: 155 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,174 @@
1-
var chapter;
2-
var currentPage;
3-
4-
function listChapters(query) {
5-
var json = {};
6-
var URL = 'https://mangadex.org/api/manga/' + query;
7-
try {
8-
json = JSON.parse(mango.get(URL).body);
9-
} catch (e) {
10-
mango.raise('Failed to get JSON from ' + URL);
1+
function getCoverURL(mangaId, coverId) {
2+
const res = mango.get('https://api.mangadex.org/cover/' + coverId);
3+
if (res.status_code !== 200)
4+
mango.raise('Failed to cover ID. Status ' + res.status_code);
5+
const filename = JSON.parse(res.body).data.attributes.fileName;
6+
return 'https://uploads.mangadex.org/covers/' + mangaId + '/' + filename;
7+
}
8+
9+
function getManga(mangaId) {
10+
const res = mango.get('https://api.mangadex.org/manga/' + mangaId);
11+
if (res.status_code !== 200)
12+
mango.raise('Failed to get manga. Status ' + res.status_code);
13+
return JSON.parse(res.body).data;
14+
}
15+
16+
function formatChapter(json, mangaTitle) {
17+
var title = json.attributes.title || "";
18+
if (json.attributes.volume)
19+
title += ' Vol. ' + json.attributes.volume;
20+
if (json.attributes.chapter)
21+
title += ' Ch. ' + json.attributes.chapter;
22+
var groupId;
23+
for (i = 0; i < json.relationships.length; i++) {
24+
const obj = json.relationships[i];
25+
if (obj.type === 'scanlation_group') {
26+
groupId = obj.id;
27+
break;
28+
}
1129
}
30+
const obj = {
31+
id: json.id,
32+
title: title,
33+
manga_title: mangaTitle,
34+
pages: json.attributes.pages,
35+
volume: json.attributes.volume,
36+
chapter: json.attributes.chapter,
37+
language: json.attributes.translatedLanguage,
38+
group_id: groupId || null,
39+
published_at: Date.parse(json.attributes.publishAt),
40+
};
41+
return obj;
42+
}
1243

13-
if (json.status !== 'OK')
14-
mango.raise('JSON status: ' + json.status);
44+
function formatTimestamp(timestamp) {
45+
return new Date(timestamp).toISOString().replace('.000Z', '');
46+
}
1547

16-
var chapters = [];
17-
Object.keys(json.chapter).forEach(function(id) {
18-
var obj = json.chapter[id];
48+
function searchManga(query) {
49+
const res = mango.get('https://api.mangadex.org/manga?title=' + encodeURIComponent(query));
50+
if (res.status_code !== 200)
51+
mango.raise('Failed to search for manga. Status ' + res.status_code);
52+
const manga = JSON.parse(res.body).data;
53+
if (!manga)
54+
mango.raise('Failed to search for manga.');
1955

20-
var groups = [];
21-
['group_name', 'group_name_2', 'group_name_3'].forEach(function(key) {
22-
if (obj[key]) {
23-
groups.push(obj[key]);
56+
return JSON.stringify(manga.map(function(m) {
57+
const ch = {
58+
id: m.id,
59+
title: m.attributes.title.en,
60+
};
61+
for (i = 0; i < m.relationships.length; i++) {
62+
const obj = m.relationships[i];
63+
if (obj.type === 'cover_art') {
64+
ch.cover_url = getCoverURL(m.id, obj.id);
65+
break;
2466
}
67+
}
68+
return ch;
69+
}));
70+
}
71+
72+
function listChapters(id) {
73+
const manga = getManga(id);
74+
const title = manga.attributes.title.en;
75+
76+
var url = 'https://api.mangadex.org/manga/' + id + '/feed?';
77+
78+
const langStr = mango.settings('language');
79+
if (langStr) {
80+
const langAry = langStr.split(',').forEach(function(lang) {
81+
url += 'translatedLanguage[]=' + lang.trim() + '&';
2582
});
26-
groups = groups.join(', ');
27-
var time = new Date(obj.timestamp * 1000);
28-
29-
var slimObj = {};
30-
slimObj['id'] = id;
31-
slimObj['volume'] = obj['volume'];
32-
slimObj['chapter'] = obj['chapter'];
33-
slimObj['title'] = obj['title'];
34-
slimObj['lang'] = obj['lang_code'];
35-
slimObj['groups'] = groups;
36-
slimObj['time'] = time;
37-
38-
chapters.push(slimObj);
39-
});
83+
}
4084

41-
return JSON.stringify({
42-
title: json.manga.title,
43-
chapters: chapters
44-
});
85+
const limit = mango.settings('listChapterLimit');
86+
if (limit) {
87+
url += 'limit=' + limit.trim() + '&';
88+
}
89+
90+
const res = mango.get(url);
91+
if (res.status_code !== 200)
92+
mango.raise('Failed to list chapters. Status ' + res.status_code);
93+
94+
const chapters = JSON.parse(res.body).data;
95+
96+
return JSON.stringify(chapters.map(function(ch) {
97+
return formatChapter(ch, title);
98+
}));
99+
}
100+
101+
function newChapters(mangaId, after) {
102+
var url = 'https://api.mangadex.org/manga/' + mangaId + '/feed?publishAtSince=' + formatTimestamp(after) + '&';
103+
104+
const langStr = mango.settings('language');
105+
if (langStr) {
106+
const langAry = langStr.split(',').forEach(function(lang) {
107+
url += 'translatedLanguage[]=' + lang.trim() + '&';
108+
});
109+
}
110+
111+
const limit = mango.settings('listChapterLimit');
112+
if (limit) {
113+
url += 'limit=' + limit.trim() + '&';
114+
}
115+
116+
const res = mango.get(url);
117+
if (res.status_code !== 200)
118+
mango.raise('Failed to list new chapters. Status ' + res.status_code);
119+
120+
const chapters = JSON.parse(res.body).data;
121+
122+
const manga = getManga(mangaId);
123+
const title = manga.attributes.title.en;
124+
125+
return JSON.stringify(chapters.map(function(ch) {
126+
return formatChapter(ch, title);
127+
}));
45128
}
46129

47130
function selectChapter(id) {
48-
var json = {};
49-
var URL = 'https://mangadex.org/api/chapter/' + id;
50-
try {
51-
json = JSON.parse(mango.get(URL).body);
52-
} catch (e) {
53-
mango.raise('Failed to get JSON from ' + URL);
131+
const res = mango.get('https://api.mangadex.org/chapter/' + id);
132+
if (res.status_code !== 200)
133+
mango.raise('Failed to get chapter. Status ' + res.status_code);
134+
135+
const chapter = JSON.parse(res.body).data;
136+
var mangaId;
137+
for (i = 0; i < chapter.relationships.length; i++) {
138+
const obj = chapter.relationships[i];
139+
if (obj.type === 'manga') {
140+
mangaId = obj.id;
141+
break;
142+
}
54143
}
55144

56-
if (json.status !== 'OK')
57-
mango.raise('JSON status: ' + json.status);
145+
if (!mangaId)
146+
mango.raise('Failed to get Manga ID from chapter');
58147

59-
chapter = json;
60-
currentPage = 0;
148+
const manga = getManga(mangaId);
149+
const title = manga.attributes.title.en;
61150

62-
var info = {
63-
title: json.title.trim() || ('Ch.' + json.chapter),
64-
pages: json.page_array.length
65-
};
66-
return JSON.stringify(info);
151+
const atHome = mango.get('https://api.mangadex.org/at-home/server/' + id);
152+
if (atHome.status_code !== 200)
153+
mango.raise('Failed to get at-home server. Status ' + atHome.status_code);
154+
155+
const atHomeData = JSON.parse(atHome.body);
156+
157+
mango.storage('atHomeData', JSON.stringify(atHomeData));
158+
mango.storage('page', '0');
159+
160+
return JSON.stringify(formatChapter(chapter, title));
67161
}
68162

69163
function nextPage() {
70-
if (currentPage >= chapter.page_array.length)
71-
return JSON.stringify({});
164+
const page = parseInt(mango.storage('page'));
165+
const atHome = JSON.parse(mango.storage('atHomeData'));
166+
const filename = atHome.chapter.data[page]
167+
mango.storage('page', (page + 1).toString());
168+
if (!filename) return JSON.stringify({});
72169

73-
var fn = chapter.page_array[currentPage];
74-
var info = {
75-
filename: fn,
76-
url: chapter.server + chapter.hash + '/' + fn
77-
};
78-
79-
currentPage += 1;
80-
return JSON.stringify(info);
170+
return JSON.stringify({
171+
url: atHome.baseUrl + '/data/' + atHome.chapter.hash + '/' + filename,
172+
filename: filename,
173+
});
81174
}

plugins/mangadex/info.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
"id": "mangadex",
33
"title": "MangaDex",
44
"author": "Alex Ling - [email protected]",
5-
"version": "v1.0",
6-
"placeholder": "MangaDex manga ID (e.g., 7139)",
7-
"wait_seconds": 5
5+
"version": "v2.0",
6+
"placeholder": "Search MangaDex",
7+
"wait_seconds": 5,
8+
"api_version": 2,
9+
"settings": {
10+
"language": "en",
11+
"listChapterLimit": "200"
12+
}
813
}

plugins/mangadexV5/README.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

plugins/mangadexV5/index.js

Lines changed: 0 additions & 101 deletions
This file was deleted.

plugins/mangadexV5/info.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)