Skip to content

Commit

Permalink
[flatmanga] revise isolation of shared behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronny committed Feb 15, 2025
1 parent 2dda748 commit 7da5792
Show file tree
Hide file tree
Showing 27 changed files with 314 additions and 220 deletions.
15 changes: 10 additions & 5 deletions web/src/engine/websites/HolyManga.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { Tags } from '../Tags';
import icon from './HolyManga.webp';
import * as Common from './decorators/Common';
import { FetchWindowScript } from '../platform/FetchProvider';
import { FlatManga, MangaLabelExtractor, queryMangaTitle } from './templates/FlatManga';
import { DecoratableMangaScraper } from '../providers/MangaPlugin';
import * as FlatManga from './templates/FlatManga';
import * as Common from './decorators/Common';

@Common.MangaCSS(/^https:\/\/w\d+\.holymanga\.net\/[^/]+\.html$/, queryMangaTitle, MangaLabelExtractor)
export default class extends FlatManga {
@Common.MangaCSS(/^https:\/\/w\d+\.holymanga\.net\/[^/]+\.html$/, FlatManga.queryMangaTitle)
@Common.MangasMultiPageCSS(FlatManga.pathMangasMultiPage, FlatManga.queryMangas)
@Common.ChaptersSinglePageCSS(FlatManga.queryChapters, Common.AnchorInfoExtractor(true))
@Common.PagesSinglePageCSS(FlatManga.queryPages, (img: HTMLImageElement) => img.dataset.original ?? img.src)
@Common.ImageAjax()
export default class extends DecoratableMangaScraper {

public constructor() {
super('holymanga', 'Holy Manga', 'https://w34.holymanga.net', Tags.Media.Manga, Tags.Media.Manhwa, Tags.Language.English, Tags.Accessibility.DomainRotation);
super('holymanga', 'Holy Manga', 'https://w34.holymanga.net' /* 193.36.132.201 */, Tags.Media.Manga, Tags.Media.Manhwa, Tags.Language.English, Tags.Accessibility.DomainRotation);
}

public override get Icon() {
Expand Down
14 changes: 7 additions & 7 deletions web/src/engine/websites/HolyManga_e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ new TestFixture({
title: 'Holy Manga'
},
container: {
url: 'https://w34.holymanga.net/manga-grand-metal-organs.html',
id: '/manga-grand-metal-organs.html',
title: 'Grand Metal Organs'
url: 'https://w34.holymanga.net/manga-nano-machine.html',
id: '/manga-nano-machine.html',
title: 'Nano Machine'
},
child: {
id: '/read-grand-metal-organs-chapter-3.1.html',
title: 'Vol.1 Chapter 3.1'
id: '/read-nano-machine-chapter-90.html',
title: 'Chapter 90: Qualifications Of A Vice-Lord (4)'
},
entry: {
index: 0,
size: 382_318,
index: 1,
size: 267_752,
type: 'image/jpeg'
}
}).AssertWebsite();
65 changes: 58 additions & 7 deletions web/src/engine/websites/KLManga.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,69 @@
import { Tags } from '../Tags';
import icon from './KLManga.webp';
import { DecoratableMangaScraper, type Manga, type Chapter, type Page } from '../providers/MangaPlugin';
import * as FlatManga from './templates/FlatManga';
import * as Common from './decorators/Common';
import { ChapterScript, FlatManga, MangaExtractor, PageScript, pathSinglePageManga } from './templates/FlatManga';

@Common.MangasSinglePagesCSS([pathSinglePageManga], 'span[data-toggle="mangapop"] a', MangaExtractor)
@Common.ChaptersSinglePageJS(ChapterScript('a.chapter:not([href="#"])'), 1500)
@Common.PagesSinglePageJS(PageScript(), 1500)
export default class extends FlatManga {
function RandomString(length: number) {
return Array.from({ length }, () => Math.random().toString(36).at(-1)).join('');
}

@Common.MangaCSS(FlatManga.pathManga, FlatManga.queryMangaTitle)
@Common.MangasSinglePagesCSS([ FlatManga.pathMangasSinglePage ], 'span[data-toggle="mangapop"] a')
@Common.ImageAjax()
export default class extends DecoratableMangaScraper {

public constructor() {
super('klmanga', 'KLManga', 'https://klz9.com', Tags.Media.Manga, Tags.Language.Japanese, Tags.Source.Aggregator);
}

public override get Icon() {
return icon;
}

public override async FetchChapters(manga: Manga): Promise<Chapter[]> {
return FlatManga.FetchChaptersAJAX.call(this, manga, `/${RandomString(25)}.lstc?slug={manga}`, 'table td a.chapter');
}

public override async FetchPages(chapter: Chapter): Promise<Page[]> {
return FlatManga.FetchPagesAJAX.call(
this,
chapter,
/load_image\s*\(\s*(\d+)\s*,\s*'list-imga'\s*\)/g,
`/${RandomString(30)}.iog?cid={chapter}`,
'img.chapter-img:not([src*="olimposcan"]):not([src$=".gif"])',
img => img.src);
}
}

/*
type APIChapters = {
id: string,
chapter: string,
name: string,
}[];
@Common.MangaCSS(/^{origin}\/[^/]+\.html$/, queryMangaTitle)
@Common.MangasSinglePagesCSS([ pathMangasSinglePage ], 'span[data-toggle="mangapop"] a')
@Common.PagesSinglePageCSS('img.chapter-img:not([src*="olimposcan"]):not([src$=".gif"])')
@Common.ImageAjax()
export default class extends DecoratableMangaScraper {
public constructor() {
super('klmanga', 'KLManga', 'https://klz9.com', Tags.Language.Japanese, Tags.Media.Manga, Tags.Source.Aggregator);
super('klmanga', 'KLManga', 'https://klz9.com', Tags.Media.Manga, Tags.Language.Japanese, Tags.Source.Aggregator);
}
public override get Icon() {
return icon;
}
}
public override async FetchChapters(manga: Manga): Promise<Chapter[]> {
const uri = new URL(`/${RandomString(20)}.lst?manga=` + ExtractMangaSlug(manga), this.URI);
const chapters = await FetchJSON<APIChapters>(new Request(uri));
return chapters.map(chapter => {
const title = [ 'Chapter ' + chapter.chapter, chapter.name ].filter(segment => segment).join(' - ').trim();
return new Chapter(this, manga, `/${RandomString(30)}.iog?cid=${chapter.id}`, title);
});
}
}
*/
12 changes: 6 additions & 6 deletions web/src/engine/websites/KLManga_e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ import { TestFixture } from '../../../test/WebsitesFixture';
new TestFixture({
plugin: {
id: 'klmanga',
title: 'KLManga'
title: 'KLManga',
},
container: {
url: 'https://klz9.com/ybed-isekai-koushoku-musou-roku-isekai-tensei-no-chie-to-chikara-wo-tada-hitasura-xxxx-suru-tame-ni-tsukau.html',
id: '/ybed-isekai-koushoku-musou-roku-isekai-tensei-no-chie-to-chikara-wo-tada-hitasura-xxxx-suru-tame-ni-tsukau.html',
title: 'ISEKAI KOUSHOKU MUSOU ROKU - ISEKAI TENSEI NO CHIE TO CHIKARA WO, TADA HITASURA XXXX SURU TAME NI TSUKAU'
title: 'ISEKAI KOUSHOKU MUSOU ROKU - ISEKAI TENSEI NO CHIE TO CHIKARA WO, TADA HITASURA XXXX SURU TAME NI TSUKAU',
},
child: {
id: '/jxsh-isekai-koushoku-musou-roku-isekai-tensei-no-chie-to-chikara-wo-tada-hitasura-xxxx-suru-tame-ni-tsukau-chapter-16.html',
title: 'Chapter 16'
title: 'Chapter 16',
},
entry: {
index: 0,
size: 494_933,
type: 'image/jpeg'
index: 16,
size: 386_180,
type: 'image/jpeg',
}
}).AssertWebsite();
24 changes: 20 additions & 4 deletions web/src/engine/websites/MangaGun.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Tags } from '../Tags';
import icon from './MangaGun.webp';
import { DecoratableMangaScraper, type Manga, type Chapter, type Page } from '../providers/MangaPlugin';
import * as FlatManga from './templates/FlatManga';
import * as Common from './decorators/Common';
import { FlatManga, ChapterScript, PageScript } from './templates/FlatManga';

@Common.ChaptersSinglePageJS(ChapterScript(), 1500)
@Common.PagesSinglePageJS(PageScript(), 1500)
export default class extends FlatManga {
@Common.MangaCSS(FlatManga.pathManga, FlatManga.queryMangaTitle)
@Common.MangasMultiPageCSS(FlatManga.pathMangasMultiPage, FlatManga.queryMangas)
@Common.ImageAjax()
export default class extends DecoratableMangaScraper {

public constructor() {
super('mangagun', 'MangaGun', 'https://mangagun.net', Tags.Language.English, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator);
Expand All @@ -14,4 +16,18 @@ export default class extends FlatManga {
public override get Icon() {
return icon;
}

public override async FetchChapters(manga: Manga): Promise<Chapter[]> {
return FlatManga.FetchChaptersAJAX.call(this, manga, '/app/manga/controllers/cont.Listchapter.php?slug={manga}', FlatManga.queryChapters);
}

public override async FetchPages(chapter: Chapter): Promise<Page[]> {
return FlatManga.FetchPagesAJAX.call(
this,
chapter,
/load_image\s*\(\s*(\d+)\s*,\s*'imgsChapter'\s*\)/g,
'/app/manga/controllers/cont.Showimage.php?cid={chapter}',
FlatManga.queryPages,
img => img.dataset.srcset);
}
}
2 changes: 1 addition & 1 deletion web/src/engine/websites/MangaGun_e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ new TestFixture({
container: {
url: 'https://mangagun.net/manga-oshi-no-ko-raw.html',
id: '/manga-oshi-no-ko-raw.html',
title: 'OSHI NO KO'
title: 'OSHI NO KO - RAW'
},
child: {
id: '/read-oshi-no-ko-raw-chapter-146.html',
Expand Down
46 changes: 11 additions & 35 deletions web/src/engine/websites/MangaTR.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Tags } from '../Tags';
import icon from './MangaTR.webp';
import { Chapter, type Manga } from '../providers/MangaPlugin';
import { FetchCSS, FetchWindowScript } from '../platform/FetchProvider';
import { FetchWindowScript } from '../platform/FetchProvider';
import { DecoratableMangaScraper, type Manga, type Chapter } from '../providers/MangaPlugin';
import * as FlatManga from './templates/FlatManga';
import * as Common from './decorators/Common';
import { CleanTitle, FlatManga } from './templates/FlatManga';

function MangaLabelExtractor(element: HTMLTitleElement) {
return element.text.split(' - ')[0].trim();
}
@Common.MangaCSS(FlatManga.pathManga, 'body title', (element: HTMLTitleElement) => element.text.split(' - ').at(0).trim())
@Common.MangasSinglePagesCSS([ '/manga-list.html' ], 'div.container a[data-toggle="mangapop"]:not([data-original-title=""])')
@Common.PagesSinglePageCSS(FlatManga.queryPages)
@Common.ImageAjax()
export default class extends DecoratableMangaScraper {

@Common.MangaCSS(/^{origin}\/manga-[^/]+\.html$/, 'body title', MangaLabelExtractor)
@Common.MangasSinglePagesCSS(['/manga-list.html'], 'div.container a[data-toggle="mangapop"]:not([data-original-title=""])')
export default class extends FlatManga {
public constructor() {
super('mangatr', `Manga-TR`, 'https://manga-tr.com', Tags.Language.Turkish, Tags.Media.Manga, Tags.Media.Manhwa, Tags.Source.Aggregator);
super('mangatr', 'Manga-TR', 'https://manga-tr.com', Tags.Media.Manga, Tags.Media.Manhwa, Tags.Language.Turkish, Tags.Source.Aggregator);
}

public override get Icon() {
return icon;
}
Expand All @@ -24,30 +24,6 @@ export default class extends FlatManga {
}

public override async FetchChapters(manga: Manga): Promise<Chapter[]> {
const chapterList = [];
for (let page = 1, run = true; run; page++) {
const chapters = await this.GetChaptersFromPage(manga, page);
chapters.length > 0 ? chapterList.push(...chapters) : run = false;
}
return chapterList;
}
private async GetChaptersFromPage(manga: Manga, page: number): Promise<Chapter[]>{
const mangaSlug = manga.Identifier.match(/manga-([^/]+)\.html/)[1];
const url = new URL(`/cek/fetch_pages_manga.php?manga_cek=${mangaSlug}`, this.URI);
const request = new Request(url, {
method: 'POST',
body: 'page=' + page,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'x-requested-with': 'XMLHttpRequest'
}
});

const data = await FetchCSS<HTMLAnchorElement>(request, 'table.table tr td.table-bordered:first-of-type > a');
return data.map(chapter => {
const title = CleanTitle(chapter.text.replace(manga.Title, '')) || chapter.text.trim();
return new Chapter(this, manga, chapter.pathname, title);
});
return FlatManga.FetchChaptersAJAX.call(this, manga, '/cek/fetch_pages_manga.php?manga_cek={manga}', 'table.table tr td[align="left"] > a');
}

}
8 changes: 4 additions & 4 deletions web/src/engine/websites/MangaTR_e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ new TestFixture({
title: 'Mairimashita! Iruma-kun'
},
child: {
id: '/id-153837-read-mairimashita-iruma-kun-chapter-174.html',
title: '174'
id: '/id-127778-read-mairimashita-iruma-kun-chapter-100.html',
title: '100'
},
entry: {
index: 1,
size: 342_746,
index: 2,
size: 265_812,
type: 'image/webp'
}
}).AssertWebsite();
9 changes: 5 additions & 4 deletions web/src/engine/websites/Manhwa18.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Tags } from '../Tags';
import icon from './Manhwa18.webp';
import { DecoratableMangaScraper } from '../providers/MangaPlugin';
import * as FlatManga from './templates/FlatManga';
import * as Common from './decorators/Common';

@Common.MangaCSS(/^{origin}\/manga\/[^/]+$/, 'span.series-name')
@Common.MangasMultiPageCSS('/manga-list?page={page}', 'div.series-title a')
@Common.ChaptersSinglePageCSS('ul.list-chapters a', Common.AnchorInfoExtractor(true))
@Common.MangaCSS(/^{origin}\/manga\/[^/]+$/, 'meta[property="og:title"]')
@Common.MangasMultiPageCSS('/manga-list?page={page}', FlatManga.queryMangas)
@Common.ChaptersSinglePageCSS(FlatManga.queryChapters, Common.AnchorInfoExtractor(true))
@Common.PagesSinglePageCSS('div#chapter-content img.lazy')
@Common.ImageAjax()
export default class extends DecoratableMangaScraper {

public constructor() {
super('manhwa18', `Manhwa 18 (.com)`, 'https://manhwa18.com', Tags.Language.English, Tags.Media.Manhwa, Tags.Source.Aggregator, Tags.Rating.Pornographic);
super('manhwa18', 'Manhwa 18 (.com)', 'https://manhwa18.com', Tags.Media.Manhwa, Tags.Language.English, Tags.Source.Aggregator, Tags.Rating.Pornographic);
}

public override get Icon() {
Expand Down
Binary file modified web/src/engine/websites/Manhwa18.webp
Binary file not shown.
18 changes: 9 additions & 9 deletions web/src/engine/websites/Manhwa18_e2e.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { TestFixture, type Config } from '../../../test/WebsitesFixture';
/* NW.js crash on website initialize => CloudFlare
import { TestFixture } from '../../../test/WebsitesFixture';
const config: Config = {
new TestFixture({
plugin: {
id: 'manhwa18',
title: 'Manhwa 18 (.com)'
title: 'Manhwa 18 (.com)',
},
container: {
url: 'https://manhwa18.com/manga/may-i-help-you',
id: '/manga/may-i-help-you',
title: 'May I Help You?'
title: 'May I Help You?',
},
child: {
id: '/manga/may-i-help-you/chap-01-678',
title: 'chap 01'
title: 'chap 01',
},
entry: {
index: 0,
size: 476_512,
type: 'image/jpeg'
type: 'image/jpeg',
}
};

new TestFixture(config).AssertWebsite();
}).AssertWebsite();
*/
9 changes: 5 additions & 4 deletions web/src/engine/websites/ManhwaEighteen.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Tags } from '../Tags';
import icon from './ManhwaEighteen.webp';
import { DecoratableMangaScraper } from '../providers/MangaPlugin';
import * as FlatManga from './templates/FlatManga';
import * as Common from './decorators/Common';

@Common.MangaCSS(/^{origin}\/manga\/[^/]+$/, 'span.series-name')
@Common.MangasMultiPageCSS('/manga-list?page={page}', 'div.series-title a')
@Common.ChaptersSinglePageCSS('ul.list-chapters a', Common.AnchorInfoExtractor(true))
@Common.MangaCSS(/^{origin}\/manga\/[^/]+$/, 'meta[property="og:title"]')
@Common.MangasMultiPageCSS('/manga-list?page={page}', FlatManga.queryMangas)
@Common.ChaptersSinglePageCSS(FlatManga.queryChapters, Common.AnchorInfoExtractor(true))
@Common.PagesSinglePageCSS('div#chapter-content img.lazy')
@Common.ImageAjax()
export default class extends DecoratableMangaScraper {

public constructor() {
super('manhwa18-int', `Manhwa 18 (.net)`, 'https://manhwa18.net', Tags.Language.English, Tags.Media.Manhwa, Tags.Source.Aggregator, Tags.Rating.Pornographic);
super('manhwa18-int', 'Manhwa 18 (.net)', 'https://manhwa18.net', Tags.Media.Manhwa, Tags.Language.English, Tags.Source.Aggregator, Tags.Rating.Pornographic);
}

public override get Icon() {
Expand Down
Binary file modified web/src/engine/websites/ManhwaEighteen.webp
Binary file not shown.
Loading

0 comments on commit 7da5792

Please # to comment.