Skip to content
This repository was archived by the owner on Nov 20, 2021. It is now read-only.

Commit ae5b0f4

Browse files
committed
Add SenManga
1 parent 3d759b1 commit ae5b0f4

File tree

5 files changed

+540
-0
lines changed

5 files changed

+540
-0
lines changed

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ Misc. sources for scanlators and aggregators.
66
* https://glitchycomics.com/
77
* https://www.novelcool.com/
88
* https://rainofsnow.com/
9+
* https://raw.senmanga.com/
910
* https://voidscans.net/

‎src/SenManga/SenManga.ts

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import {
2+
Chapter,
3+
ChapterDetails,
4+
HomeSection,
5+
Manga,
6+
MangaUpdates,
7+
PagedResults,
8+
Request, RequestHeaders, RequestManager,
9+
SearchRequest,
10+
Source,
11+
SourceInfo,
12+
TagSection,
13+
} from "paperback-extensions-common"
14+
import {SenMangaParser} from "./SenMangaParser";
15+
16+
const BASE = "https://raw.senmanga.com"
17+
18+
export const SenMangaInfo: SourceInfo = {
19+
icon: "icon.png",
20+
version: "1.0.0",
21+
name: "SenManga",
22+
author: "PythonCoderAS",
23+
authorWebsite: "https://github.com/PythonCoderAS",
24+
description: "Extension that pulls manga from SenManga",
25+
language: "jp",
26+
hentaiSource: false,
27+
websiteBaseURL: BASE
28+
}
29+
30+
export class SenManga extends Source {
31+
32+
private readonly parser: SenMangaParser = new SenMangaParser();
33+
34+
private readonly header: RequestHeaders = {
35+
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
36+
}
37+
38+
readonly requestManager: RequestManager = createRequestManager({
39+
requestTimeout: 15000,
40+
requestsPerSecond: 4
41+
});
42+
43+
globalRequestHeaders(): RequestHeaders {
44+
return this.header;
45+
}
46+
47+
getMangaShareUrl(mangaId: string): string {
48+
return `${BASE}/${mangaId}`;
49+
}
50+
51+
async getTags(): Promise<TagSection[]> {
52+
const options: Request = createRequestObject({
53+
url: `${BASE}`,
54+
method: 'GET',
55+
headers: this.header
56+
});
57+
let response = await this.requestManager.schedule(options, 1);
58+
let $ = this.cheerio.load(response.data);
59+
return this.parser.parseGlobalTagList($);
60+
}
61+
62+
async getHomePageSections(sectionCallback: (section: HomeSection) => void): Promise<void> {
63+
const options: Request = createRequestObject({
64+
url: `${BASE}`,
65+
method: 'GET',
66+
headers: this.header
67+
});
68+
let response = await this.requestManager.schedule(options, 1);
69+
let $ = this.cheerio.load(response.data);
70+
sectionCallback(createHomeSection({
71+
id: "last_update",
72+
items: this.parser.parseLatestUpdates($, BASE),
73+
title: "Latest Updates",
74+
view_more: true
75+
}));
76+
sectionCallback(createHomeSection({
77+
id: "popular",
78+
items: this.parser.parseMostPopular($, BASE),
79+
title: "Popular Manga",
80+
view_more: true
81+
}));
82+
sectionCallback(createHomeSection({
83+
id: "new_series",
84+
items: this.parser.parseNewSeries($, BASE),
85+
title: "New Series",
86+
view_more: true
87+
}));
88+
}
89+
90+
private async getPagedResults(url: string, metadata: { page?: number | null, [key: string]: any }){
91+
if (typeof metadata !== "object"){
92+
metadata = {page: metadata}
93+
}
94+
let page = 1;
95+
if (metadata.page){
96+
page = metadata.page;
97+
}
98+
if (page === null){
99+
return createPagedResults({results: []});
100+
}
101+
let pageAdder = `?page=${page}`;
102+
if (url.includes("?")){
103+
pageAdder = `&page=${page}`;
104+
}
105+
const options: Request = createRequestObject({
106+
url: url+pageAdder,
107+
method: 'GET',
108+
headers: this.header
109+
});
110+
let response = await this.requestManager.schedule(options, 1);
111+
let $ = this.cheerio.load(response.data);
112+
const data = this.parser.parseDirectory($, BASE);
113+
let newPage: number | null = page + 1;
114+
if (data.max >= newPage){
115+
newPage = null;
116+
}
117+
metadata.page = newPage;
118+
return createPagedResults({
119+
results: data.data
120+
});
121+
}
122+
123+
async getWebsiteMangaDirectory(metadata: { page?: number | null, [key: string]: any }): Promise<PagedResults> {
124+
return await this.getPagedResults(`${BASE}/directory`, metadata)
125+
}
126+
127+
async getChapterDetails(mangaId: string, chapterId: string): Promise<ChapterDetails> {
128+
const options: Request = createRequestObject({
129+
url: this.getMangaShareUrl(mangaId) + "/" + chapterId,
130+
method: 'GET',
131+
headers: this.header,
132+
cookies: [
133+
createCookie({
134+
name: "viewer",
135+
value: "1",
136+
domain: BASE,
137+
path: "/",
138+
created: new Date(),
139+
expires: new Date(2147483647)
140+
})
141+
]
142+
});
143+
let response = await this.requestManager.schedule(options, 1);
144+
return createChapterDetails({
145+
id: chapterId,
146+
mangaId: mangaId,
147+
longStrip: false,
148+
pages: await this.parser.parsePages(response.data)
149+
});
150+
}
151+
152+
async getChapters(mangaId: string): Promise<Chapter[]> {
153+
const options: Request = createRequestObject({
154+
url: this.getMangaShareUrl(mangaId),
155+
method: 'GET',
156+
headers: this.header
157+
});
158+
let response = await this.requestManager.schedule(options, 1);
159+
let $ = this.cheerio.load(response.data);
160+
return this.parser.parseChapterList($, mangaId, BASE);
161+
}
162+
163+
async getMangaDetails(mangaId: string): Promise<Manga> {
164+
const options: Request = createRequestObject({
165+
url: this.getMangaShareUrl(mangaId),
166+
method: 'GET',
167+
headers: this.header
168+
});
169+
let response = await this.requestManager.schedule(options, 1);
170+
let $ = this.cheerio.load(response.data);
171+
return this.parser.parseManga($, mangaId);
172+
}
173+
174+
async searchRequest(query: SearchRequest, metadata: any): Promise<PagedResults> {
175+
return await this.getPagedResults(`${BASE}/search?s=${query.title}`, metadata);
176+
}
177+
178+
async getViewMoreItems(homepageSectionId: string, metadata: any): Promise<PagedResults> {
179+
return await this.getPagedResults(`${BASE}/directory/${homepageSectionId}`, metadata);
180+
}
181+
182+
async filterUpdatedManga(mangaUpdatesFoundCallback: (updates: MangaUpdates) => void, time: Date, ids: string[]): Promise<void> {
183+
const options: Request = createRequestObject({
184+
url: `${BASE}`,
185+
method: 'GET',
186+
headers: this.header
187+
});
188+
let response = await this.requestManager.schedule(options, 1);
189+
let $ = this.cheerio.load(response.data);
190+
const idList: string[] = [];
191+
let tiles = this.parser.parseLatestUpdates($, BASE, true);
192+
for (let i = 0; i < tiles.length; i++) {
193+
const tile = tiles[i];
194+
const parsedTime = this.parser.parseDateTime(tile.primaryText?.text || "")
195+
if (parsedTime && parsedTime > time && ids.includes(tile.id)){
196+
idList.push(tile.id);
197+
}
198+
}
199+
mangaUpdatesFoundCallback(createMangaUpdates({
200+
ids: idList
201+
}));
202+
}
203+
}

0 commit comments

Comments
 (0)