Skip to content

Commit 8e8fd15

Browse files
first commit
0 parents  commit 8e8fd15

File tree

4 files changed

+287
-0
lines changed

4 files changed

+287
-0
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# J18 Plugin
2+
3+
This plugin allows you to read the comic content from [J18 - doujin.io](https://doujin.io/) in Rulia Reader
4+
5+
## Description
6+
7+
- Although this plugin only has basic functionality, at least it exists.
8+
- After installing this plugin, please fill in the cookie; otherwise, it will not function properly.
9+
- I will try to find time to maintain this plugin outside of my regular work.
10+
11+
## Download
12+
13+
- You can click [here](https://github.com/LittleStar-OuO/plugin.J18/releases) to download.
14+
15+
## Config
16+
17+
- Please note that the value of cookie should be in this format: 'remember_web_5......joiIn0%3D'.

icon.png

6.25 KB
Loading

index.js

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
const userConfig = window.Rulia.getUserConfig();
2+
3+
async function setMangaListFilterOptions() {
4+
const url = 'https://doujin.io/api/tags';
5+
try {
6+
let result = [{
7+
label: 'Tags',
8+
name: 'Tags',
9+
options: [{
10+
label: 'Newest Releases',
11+
value: 'Newest'
12+
},
13+
{
14+
label: 'My Likes',
15+
value: 'Likes'
16+
}
17+
]
18+
}]
19+
const rawResponse = await window.Rulia.httpRequest({
20+
url: url,
21+
method: 'GET',
22+
contentType: 'application/json'
23+
});
24+
const response = JSON.parse(rawResponse);
25+
for (let item of response.data) {
26+
result[0].options.push({
27+
label: item.name,
28+
value: item.slug
29+
})
30+
}
31+
window.Rulia.endWithResult(result);
32+
} catch (error) {
33+
window.Rulia.endWithResult([])
34+
}
35+
}
36+
37+
async function getMangaListByNewest(page, pageSize) {
38+
const url =
39+
'https://doujin.io/api/mangas/newest';
40+
try {
41+
const rawResponse = await window.Rulia.httpRequest({
42+
url: url,
43+
method: 'POST',
44+
payload: JSON.stringify({
45+
limit: pageSize,
46+
offset: (pageSize * (page - 1))
47+
}),
48+
contentType: 'application/json'
49+
})
50+
const response = JSON.parse(rawResponse);
51+
let result = {
52+
list: []
53+
}
54+
for (let manga of response.data) {
55+
let comic = {
56+
title: manga.title,
57+
url: 'https://doujin.io/manga/' + manga.optimus_id + '/' + manga.slug,
58+
coverUrl: manga.thumb
59+
}
60+
result.list.push(comic);
61+
}
62+
window.Rulia.endWithResult(result);
63+
} catch (error) {
64+
window.Rulia.endWithException(error.message);
65+
}
66+
}
67+
68+
async function getMangaListByLikes(page, pageSize) {
69+
let url = 'https://doujin.io/api/mangas/favorites';
70+
try {
71+
const payload = new URLSearchParams()
72+
payload.append('page', page.toString())
73+
const rawResponse = await window.Rulia.httpRequest({
74+
url: url,
75+
method: 'GET',
76+
payload: payload.toString(),
77+
headers: {
78+
accept: 'application/json, text/plain, */*',
79+
referer: 'https://doujin.io/likes',
80+
cookie: userConfig.cookie
81+
}
82+
});
83+
const response = JSON.parse(rawResponse);
84+
let result = {
85+
list: []
86+
}
87+
for (let manga of response.data) {
88+
let comic = {
89+
title: manga.title,
90+
url: 'https://doujin.io/manga/' + manga.optimus_id + '/' + manga.slug,
91+
coverUrl: manga.thumb
92+
}
93+
result.list.push(comic);
94+
}
95+
window.Rulia.endWithResult(result);
96+
} catch (error) {
97+
window.Rulia.endWithException('Please configure the User Config in the Plugin config of this plugin');
98+
}
99+
}
100+
101+
async function getMangaListByTags(page, pageSize, filterOptions) {
102+
103+
if (filterOptions.Tags == 'Newest') {
104+
return await getMangaListByNewest(page, pageSize);
105+
} else if (filterOptions.Tags == 'Likes') {
106+
return await getMangaListByLikes(page, pageSize);
107+
} else {
108+
const url = 'https://doujin.io/api/tags/mangas';
109+
try {
110+
const rawResponse = await window.Rulia.httpRequest({
111+
url: url,
112+
method: 'POST',
113+
payload: JSON.stringify({
114+
tag: filterOptions.Tags,
115+
page: page,
116+
sort: "published_at",
117+
sort_dir: "desc"
118+
}),
119+
contentType: 'application/json'
120+
})
121+
const response = JSON.parse(rawResponse);
122+
let result = {
123+
list: []
124+
}
125+
for (let manga of response.data.data) {
126+
let comic = {
127+
title: manga.title,
128+
url: 'https://doujin.io/manga/' + manga.optimus_id + '/' + manga.slug,
129+
coverUrl: manga.thumb
130+
}
131+
result.list.push(comic);
132+
}
133+
window.Rulia.endWithResult(result);
134+
} catch (error) {
135+
window.Rulia.endWithException(error.message);
136+
}
137+
}
138+
}
139+
140+
async function getMangaListBySearching(page, pageSize, keyword) {
141+
const url =
142+
'https://doujin.io/api/mangas/search';
143+
try {
144+
const rawResponse = await window.Rulia.httpRequest({
145+
url: url,
146+
method: 'POST',
147+
payload: JSON.stringify({
148+
keyword: keyword,
149+
tags: [],
150+
page: page,
151+
sort: "published_at",
152+
sort_dir: "desc"
153+
}),
154+
contentType: 'application/json'
155+
})
156+
const response = JSON.parse(rawResponse);
157+
let result = {
158+
list: []
159+
}
160+
for (let manga of response.data.data) {
161+
let comic = {
162+
title: manga.title,
163+
url: 'https://doujin.io/manga/' + manga.optimus_id + '/' + manga.slug,
164+
coverUrl: manga.thumb
165+
}
166+
result.list.push(comic);
167+
}
168+
window.Rulia.endWithResult(result);
169+
} catch (error) {
170+
window.Rulia.endWithException(error.message);
171+
}
172+
}
173+
174+
async function getMangaList(page, pageSize, keyword, rawFilterOptions) {
175+
if (keyword) {
176+
return await getMangaListBySearching(page, pageSize, keyword);
177+
} else {
178+
return await getMangaListByTags(page, pageSize, JSON.parse(rawFilterOptions));
179+
}
180+
}
181+
182+
async function getMangaData(dataPageUrl) {
183+
const seasonIdMatchExp = /\/manga\/(\d+)\//;
184+
const seasonIdMatch = dataPageUrl.match(seasonIdMatchExp);
185+
const detailUrl = 'https://doujin.io/api/mangas/' + seasonIdMatch[1];
186+
const chapterListUrl = 'https://doujin.io/api/chapters';
187+
const chapterListPayload = new URLSearchParams();
188+
chapterListPayload.append('manga_id', seasonIdMatch[1].toString());
189+
try {
190+
const detailRawResponse = await window.Rulia.httpRequest({
191+
url: detailUrl,
192+
method: 'GET'
193+
})
194+
const detailResponse = JSON.parse(detailRawResponse);
195+
let result = {
196+
title: detailResponse.data.title,
197+
description: detailResponse.data.description,
198+
coverUrl: detailResponse.data.thumb,
199+
chapterList: []
200+
}
201+
const chapterListRawResponse = await window.Rulia.httpRequest({
202+
url: chapterListUrl,
203+
method: 'GET',
204+
payload: chapterListPayload.toString()
205+
});
206+
const chapterListResponse = JSON.parse(chapterListRawResponse);
207+
208+
for (let manga of chapterListResponse.data) {
209+
let comic = {
210+
title: '[' + manga.chapter_name + '][' + manga.created + ']',
211+
url: 'https://doujin.io/manga/' + seasonIdMatch[1] + '/chapter/' + manga.optimus_id
212+
}
213+
result.chapterList.push(comic);
214+
}
215+
window.Rulia.endWithResult(result);
216+
} catch (error) {
217+
window.Rulia.endWithException(error.message);
218+
}
219+
}
220+
221+
async function getChapterImageList(chapterUrl) {
222+
const episodeIdMatchExp = /\/manga\/(\d+)\/chapter\/(\d+)/;
223+
const episodeIdMatch = chapterUrl.match(episodeIdMatchExp);
224+
const url = 'https://doujin.io/api/mangas/' + episodeIdMatch[1] + '/' + episodeIdMatch[2] + '/manifest';
225+
try {
226+
const rawResponse = await window.Rulia.httpRequest({
227+
url: url,
228+
method: 'GET',
229+
payload: 'format=json',
230+
headers: {
231+
accept: 'application/json, text/plain, */*',
232+
referer: 'https://doujin.io/likes',
233+
cookie: userConfig.cookie
234+
}
235+
});
236+
const response = JSON.parse(rawResponse);
237+
let result = [];
238+
239+
for (let imageDetail of response.readingOrder) {
240+
result.push({
241+
url: imageDetail.href,
242+
width: imageDetail.width,
243+
height: imageDetail.height
244+
});
245+
}
246+
result.pop()
247+
window.Rulia.endWithResult(result);
248+
} catch (error) {
249+
window.Rulia.endWithException('Please configure the User Config in the Plugin config of this plugin');
250+
}
251+
}
252+
253+
async function getImageUrl(path) {
254+
window.Rulia.endWithResult(path);
255+
}

package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "@rulia/J18",
3+
"title": "J18 Plugin",
4+
"description": "doujin.io plugin.",
5+
"version": "0.0.1",
6+
"author": "LittleStar_OuO",
7+
"tags": ["doujin", "Manga", "J18"],
8+
"homepage": "https://github.com/LittleStar-OuO/plugin.J18",
9+
"userConfig": {
10+
"cookie": {
11+
"displayName": "cookie",
12+
"description": "Please use the 'Web Developer Tools' to retrieve cookies from doujin.io"
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)