diff --git a/web/src/engine/websites/MangaRussia.ts b/web/src/engine/websites/MangaRussia.ts new file mode 100644 index 0000000000..68e1efa45e --- /dev/null +++ b/web/src/engine/websites/MangaRussia.ts @@ -0,0 +1,19 @@ +import { Tags } from '../Tags'; +import icon from './MangaRussia.webp'; +import { DecoratableMangaScraper } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; + +@Common.MangaCSS(/^{origin}\/manga\/[^/]+\.html$/, 'div.mangabookbox div.bookmessagebox h1', TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, TAADD.queryMangas, 1, 1, 0, Common.AnchorInfoExtractor(true)) +@TAADD.ChaptersSinglePageCSS('div.chapterlist table tr td.col1 a', TAADD.ChapterExtractor, false) +@TAADD.PagesSinglePageCSS() +@TAADD.ImageAjaxFromHTML() +export default class extends DecoratableMangaScraper { + public constructor() { + super('mangarussia', `MangaRussia`, 'https://www.mangarussia.com', Tags.Language.Russian, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } +} \ No newline at end of file diff --git a/web/src/engine/websites/legacy/MangaRussia.webp b/web/src/engine/websites/MangaRussia.webp similarity index 100% rename from web/src/engine/websites/legacy/MangaRussia.webp rename to web/src/engine/websites/MangaRussia.webp diff --git a/web/src/engine/websites/MangaRussia_e2e.ts b/web/src/engine/websites/MangaRussia_e2e.ts new file mode 100644 index 0000000000..e82953bcd3 --- /dev/null +++ b/web/src/engine/websites/MangaRussia_e2e.ts @@ -0,0 +1,22 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +new TestFixture({ + plugin: { + id: 'mangarussia', + title: 'MangaRussia' + }, + container: { + url: 'https://www.mangarussia.com/manga/Дандадан.html', + id: encodeURI('/manga/Дандадан.html'), + title: 'Дандадан', + }, + child: { + id: encodeURI('/chapter/Дандадан+16+-+141+Переели+вкусняшек/4332724/'), + title: '16 - 141 Переели вкусняшек', + }, + entry: { + index: 0, + size: 819_587, // 752_216 or 819_587 + type: 'image/jpeg' + } +}).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/NineMangaBR.ts b/web/src/engine/websites/NineMangaBR.ts new file mode 100644 index 0000000000..2a0408a508 --- /dev/null +++ b/web/src/engine/websites/NineMangaBR.ts @@ -0,0 +1,19 @@ +import { Tags } from '../Tags'; +import icon from './NineMangaBR.webp'; +import { DecoratableMangaScraper } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; + +@Common.MangaCSS(/^{origin}\/manga\/[^/]+\.html/, 'div.manga div.ttline h1', TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, TAADD.queryMangas) +@TAADD.ChaptersSinglePageCSS() +@TAADD.PagesSinglePageCSS() +@TAADD.ImageAjaxFromHTML() +export default class extends DecoratableMangaScraper { + public constructor() { + super('ninemanga-br', `NineMangaBR`, 'https://br.ninemanga.com', Tags.Language.Portuguese, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } +} \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaBR.webp b/web/src/engine/websites/NineMangaBR.webp similarity index 100% rename from web/src/engine/websites/legacy/NineMangaBR.webp rename to web/src/engine/websites/NineMangaBR.webp diff --git a/web/src/engine/websites/NineMangaBR_e2e.ts b/web/src/engine/websites/NineMangaBR_e2e.ts new file mode 100644 index 0000000000..abc690ed67 --- /dev/null +++ b/web/src/engine/websites/NineMangaBR_e2e.ts @@ -0,0 +1,23 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +new TestFixture({ + plugin: { + id: 'ninemanga-br', + title: 'NineMangaBR' + }, + container: { + url: 'https://br.ninemanga.com/manga/Kingdom.html', + id: '/manga/Kingdom.html', + title: 'Kingdom', + }, + child: { + id: '/chapter/Kingdom/6718490.html', + title: '762', + timeout: 10000 + }, + entry: { + index: 2, + size: 306_842, + type: 'image/webp' + } +}).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/NineMangaDE.ts b/web/src/engine/websites/NineMangaDE.ts new file mode 100644 index 0000000000..53de2447af --- /dev/null +++ b/web/src/engine/websites/NineMangaDE.ts @@ -0,0 +1,19 @@ +import { Tags } from '../Tags'; +import icon from './NineMangaDE.webp'; +import { DecoratableMangaScraper } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; + +@Common.MangaCSS(/^{origin}\/manga\/[^/]+\.html/, 'div.manga div.ttline h1', TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, TAADD.queryMangas) +@TAADD.ChaptersSinglePageCSS() +@TAADD.PagesSinglePageCSS() +@TAADD.ImageAjaxFromHTML() +export default class extends DecoratableMangaScraper { + public constructor() { + super('ninemanga-de', `NineMangaDE`, 'https://de.ninemanga.com', Tags.Language.German, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } +} \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaDE.webp b/web/src/engine/websites/NineMangaDE.webp similarity index 100% rename from web/src/engine/websites/legacy/NineMangaDE.webp rename to web/src/engine/websites/NineMangaDE.webp diff --git a/web/src/engine/websites/NineMangaDE_e2e.ts b/web/src/engine/websites/NineMangaDE_e2e.ts new file mode 100644 index 0000000000..f9f3e9b179 --- /dev/null +++ b/web/src/engine/websites/NineMangaDE_e2e.ts @@ -0,0 +1,22 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +new TestFixture({ + plugin: { + id: 'ninemanga-de', + title: 'NineMangaDE' + }, + container: { + url: 'https://de.ninemanga.com/manga/Tales+of+Demons+and+Gods.html', + id: '/manga/Tales+of+Demons+and+Gods.html', + title: 'Tales of Demons and Gods', + }, + child: { + id: '/chapter/Tales%20of%20Demons%20and%20Gods/453688.html', + title: 'Tales of Demons and Gods 160.5', //yes, chapter contains two times manga title, :D + }, + entry: { + index: 0, + size: 409_917, //120_614 or 409_917 + type: 'image/jpeg' + } +}).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/NineMangaEN.ts b/web/src/engine/websites/NineMangaEN.ts new file mode 100644 index 0000000000..9145097ffe --- /dev/null +++ b/web/src/engine/websites/NineMangaEN.ts @@ -0,0 +1,19 @@ +import { Tags } from '../Tags'; +import icon from './NineMangaEN.webp'; +import { DecoratableMangaScraper } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; + +@Common.MangaCSS(/^{origin}\/manga\/[^/]+\.html/, 'div.manga div.ttline h1', TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, TAADD.queryMangas) +@TAADD.ChaptersSinglePageCSS() +@TAADD.PagesSinglePageCSS() +@TAADD.ImageAjaxFromHTML() +export default class extends DecoratableMangaScraper { + public constructor() { + super('ninemanga-en', `NineMangaEN`, 'https://en.ninemanga.com', Tags.Language.English, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } +} \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaEN.webp b/web/src/engine/websites/NineMangaEN.webp similarity index 100% rename from web/src/engine/websites/legacy/NineMangaEN.webp rename to web/src/engine/websites/NineMangaEN.webp diff --git a/web/src/engine/websites/NineMangaEN_e2e.ts b/web/src/engine/websites/NineMangaEN_e2e.ts new file mode 100644 index 0000000000..907dfa5fd8 --- /dev/null +++ b/web/src/engine/websites/NineMangaEN_e2e.ts @@ -0,0 +1,22 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +new TestFixture({ + plugin: { + id: 'ninemanga-en', + title: 'NineMangaEN' + }, + container: { + url: 'https://en.ninemanga.com/manga/My+Angel+Childhood+Friend+was+a+Gal+When+We+Met+Again.html', + id: '/manga/My+Angel+Childhood+Friend+was+a+Gal+When+We+Met+Again.html', + title: 'My Angel Childhood Friend was a Gal When We Met Again', + }, + child: { + id: '/chapter/My%20Angel%20Childhood%20Friend%20was%20a%20Gal%20When%20We%20Met%20Again/8875625.html', + title: 'Chapter 14', + }, + entry: { + index: 1, + size: 203_785, + type: 'image/jpeg' + } +}).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/NineMangaES.ts b/web/src/engine/websites/NineMangaES.ts new file mode 100644 index 0000000000..7f77b5c01a --- /dev/null +++ b/web/src/engine/websites/NineMangaES.ts @@ -0,0 +1,19 @@ +import { Tags } from '../Tags'; +import icon from './NineMangaES.webp'; +import { DecoratableMangaScraper } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; + +@Common.MangaCSS(/^{origin}\/manga\/[^/]+\.html/, 'div.manga div.ttline h1', TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, TAADD.queryMangas) +@TAADD.ChaptersSinglePageCSS() +@TAADD.PagesSinglePageCSS() +@TAADD.ImageAjaxFromHTML() +export default class extends DecoratableMangaScraper { + public constructor() { + super('ninemanga-es', `NineMangaES`, 'https://es.ninemanga.com', Tags.Language.English, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } +} \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaES.webp b/web/src/engine/websites/NineMangaES.webp similarity index 100% rename from web/src/engine/websites/legacy/NineMangaES.webp rename to web/src/engine/websites/NineMangaES.webp diff --git a/web/src/engine/websites/NineMangaES_e2e.ts b/web/src/engine/websites/NineMangaES_e2e.ts new file mode 100644 index 0000000000..ee501822b5 --- /dev/null +++ b/web/src/engine/websites/NineMangaES_e2e.ts @@ -0,0 +1,24 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +new TestFixture({ + plugin: { + id: 'ninemanga-es', + title: 'NineMangaES' + }, + container: { + url: 'https://es.ninemanga.com/manga/Martial+Peak.html', + id: '/manga/Martial+Peak.html', + title: 'Martial Peak', + }, + child: { + id: '/chapter/Martial%20Peak/1855269.html', + title: 'Capitulo 3440', + timeout: 15000 + + }, + entry: { + index: 1, + size: 110_242, + type: 'image/webp' + } +}).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/NineMangaFR.ts b/web/src/engine/websites/NineMangaFR.ts new file mode 100644 index 0000000000..cb3bed340c --- /dev/null +++ b/web/src/engine/websites/NineMangaFR.ts @@ -0,0 +1,19 @@ +import { Tags } from '../Tags'; +import icon from './NineMangaFR.webp'; +import { DecoratableMangaScraper } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; + +@Common.MangaCSS(/^{origin}\/manga\/[^/]+\.html/, 'div.manga div.ttline h1', TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, TAADD.queryMangas) +@TAADD.ChaptersSinglePageCSS() +@TAADD.PagesSinglePageCSS() +@TAADD.ImageAjaxFromHTML() +export default class extends DecoratableMangaScraper { + public constructor() { + super('ninemanga-fr', `NineMangaFR`, 'https://fr.ninemanga.com', Tags.Language.French, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } +} \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaIT.webp b/web/src/engine/websites/NineMangaFR.webp similarity index 100% rename from web/src/engine/websites/legacy/NineMangaIT.webp rename to web/src/engine/websites/NineMangaFR.webp diff --git a/web/src/engine/websites/NineMangaFR_e2e.ts b/web/src/engine/websites/NineMangaFR_e2e.ts new file mode 100644 index 0000000000..1a09ac5883 --- /dev/null +++ b/web/src/engine/websites/NineMangaFR_e2e.ts @@ -0,0 +1,24 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +new TestFixture({ + plugin: { + id: 'ninemanga-fr', + title: 'NineMangaFR' + }, + container: { + url: 'https://fr.ninemanga.com/manga/Lycoris+Recoil.html', + id: '/manga/Lycoris+Recoil.html', + title: 'Lycoris Recoil', + }, + child: { + id: '/chapter/Lycoris%20Recoil/722483.html', + title: '4', + timeout: 15000 + + }, + entry: { + index: 1, + size: 108_568, + type: 'image/webp' + } +}).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/NineMangaIT.ts b/web/src/engine/websites/NineMangaIT.ts new file mode 100644 index 0000000000..7c78dda525 --- /dev/null +++ b/web/src/engine/websites/NineMangaIT.ts @@ -0,0 +1,19 @@ +import { Tags } from '../Tags'; +import icon from './NineMangaIT.webp'; +import { DecoratableMangaScraper } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; + +@Common.MangaCSS(/^{origin}\/manga\/[^/]+\.html/, 'div.manga div.ttline h1', TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, TAADD.queryMangas) +@TAADD.ChaptersSinglePageCSS() +@TAADD.PagesSinglePageCSS() +@TAADD.ImageAjaxFromHTML() +export default class extends DecoratableMangaScraper { + public constructor() { + super('ninemanga-it', `NineMangaIT`, 'https://it.ninemanga.com', Tags.Language.Italian, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } +} \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaRU.webp b/web/src/engine/websites/NineMangaIT.webp similarity index 100% rename from web/src/engine/websites/legacy/NineMangaRU.webp rename to web/src/engine/websites/NineMangaIT.webp diff --git a/web/src/engine/websites/NineMangaIT_e2e.ts b/web/src/engine/websites/NineMangaIT_e2e.ts new file mode 100644 index 0000000000..05e87f230f --- /dev/null +++ b/web/src/engine/websites/NineMangaIT_e2e.ts @@ -0,0 +1,22 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +new TestFixture({ + plugin: { + id: 'ninemanga-it', + title: 'NineMangaIT' + }, + container: { + url: 'https://it.ninemanga.com/manga/Level+Up+with+the+Gods.html', + id: '/manga/Level+Up+with+the+Gods.html', + title: 'Level Up with the Gods', + }, + child: { + id: '/chapter/Level%20Up%20with%20the%20Gods/970365.html', + title: '35', + }, + entry: { + index: 1, + size: 869_059, + type: 'image/jpeg' + } +}).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/NineMangaRU.ts b/web/src/engine/websites/NineMangaRU.ts new file mode 100644 index 0000000000..864d5f267b --- /dev/null +++ b/web/src/engine/websites/NineMangaRU.ts @@ -0,0 +1,73 @@ +import { Tags } from '../Tags'; +import icon from './NineMangaRU.webp'; +import { type Chapter, DecoratableMangaScraper, Page } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; +import { Fetch } from '../platform/FetchProvider'; + +@Common.MangaCSS(/^{origin}\/manga\/[^/]+\.html/, 'div.manga div.ttline h1', TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, TAADD.queryMangas) +@TAADD.ChaptersSinglePageCSS() +@Common.ImageAjax() + +export default class extends DecoratableMangaScraper { + public constructor() { + super('ninemanga-ru', `NineMangaRU`, 'https://ru.ninemanga.com', Tags.Language.Russian, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } + + public override async FetchPages(chapter: Chapter): Promise { + const pages: Page[] = []; + + //1) Fetch "server page" & get GO page from button + const chapterUrl = new URL(chapter.Identifier, this.URI); + let request = new Request(chapterUrl, { + headers: { + Referer: this.URI.origin, + } + }); + + let response = await Fetch(request); + const serverPage = response.url; + const buttonLink = new DOMParser().parseFromString(await response.text(), 'text/html').querySelector('a.cool-blue').href; + const cookieValue = new URL(buttonLink, response.url).searchParams.get('cid'); + + //2) get javascript redirect from page + request = new Request(buttonLink, { + headers: { + Referer: serverPage, + } + }); + + response = await Fetch(request); + let data = await response.text(); + const lastLocation = new URL(data.match(/window\.location\.href\s*=\s*['"](.*)['"]/)[1], request.url); + + //3) forge Cookie + const cookieName = 'lrgarden_visit_check_' + lastLocation.pathname.match(/(\d+)\.html$/)[1]; + const cookie = `${cookieName}=${cookieValue};`; + + //4) get pages + request = new Request(lastLocation, { + //credentials: 'include', + headers: { + Referer: buttonLink, + Cookie: cookie + } + }); + response = await Fetch(request); + data = await response.text(); + data = data.replaceAll(/(\r\n|\n|\r)/gm, "").match(/all_imgs_url\s*:\s*(\[[^\]]*\])/)[1]; + + let result; + const pageRegexp = /(http[^'"]+)['"]/g; + while (result = pageRegexp.exec(data)) { + pages.push(new Page(this, chapter, new URL(result[1]), { Referer: lastLocation.href })); + } + + return pages; + } + +} \ No newline at end of file diff --git a/web/src/engine/websites/NineMangaRU.webp b/web/src/engine/websites/NineMangaRU.webp new file mode 100644 index 0000000000..0dc6037190 Binary files /dev/null and b/web/src/engine/websites/NineMangaRU.webp differ diff --git a/web/src/engine/websites/NineMangaRU_e2e.ts b/web/src/engine/websites/NineMangaRU_e2e.ts new file mode 100644 index 0000000000..2fcbb9cada --- /dev/null +++ b/web/src/engine/websites/NineMangaRU_e2e.ts @@ -0,0 +1,24 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +const config = { + plugin: { + id: 'ninemanga-ru', + title: 'NineMangaRU' + }, + container: { + url: 'https://ru.ninemanga.com/manga/Рождение+сильнейшего+мастера.html', + id: encodeURI('/manga/Рождение+сильнейшего+мастера.html'), + title: 'Рождение сильнейшего мастера Манга (The Distinguished Cute Master)', + }, + child: { + id: encodeURI('/chapter/Рождение сильнейшего мастера/3940336.html'), + title: 'Рождение сильнейшего мастера Том 1 Глава 308', + }, + entry: { + index: 0, + size: 375_292, + type: 'image/webp' + } +}; + +new TestFixture(config).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/TAADD.ts b/web/src/engine/websites/TAADD.ts new file mode 100644 index 0000000000..35fd830440 --- /dev/null +++ b/web/src/engine/websites/TAADD.ts @@ -0,0 +1,19 @@ +import { Tags } from '../Tags'; +import icon from './TAADD.webp'; +import { DecoratableMangaScraper } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; + +@Common.MangaCSS(/^{origin}\/book\/[^/]+\.html$/, TAADD.queryMangaTitleFromURI, TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, TAADD.queryMangas) +@TAADD.ChaptersSinglePageCSS() +@TAADD.PagesSinglePageCSS() +@TAADD.ImageAjaxFromHTML() +export default class extends DecoratableMangaScraper { + public constructor() { + super('taadd', `TAADD`, 'https://www.taadd.com', Tags.Language.English, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } +} \ No newline at end of file diff --git a/web/src/engine/websites/legacy/TAADD.webp b/web/src/engine/websites/TAADD.webp similarity index 100% rename from web/src/engine/websites/legacy/TAADD.webp rename to web/src/engine/websites/TAADD.webp diff --git a/web/src/engine/websites/TAADD_e2e.ts b/web/src/engine/websites/TAADD_e2e.ts new file mode 100644 index 0000000000..59d034f961 --- /dev/null +++ b/web/src/engine/websites/TAADD_e2e.ts @@ -0,0 +1,22 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +new TestFixture({ + plugin: { + id: 'taadd', + title: 'TAADD' + }, + container: { + url: 'https://www.taadd.com/book/One+Piece.html', + id: '/book/One+Piece.html', + title: 'One Piece', + }, + child: { + id: '/chapter/OnePieceChapter1086/8624347/', + title: 'Chapter 1086', + }, + entry: { + index: 0, + size: 914_447, + type: 'image/jpeg' + } +}).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/TenManga.ts b/web/src/engine/websites/TenManga.ts new file mode 100644 index 0000000000..4fd5cb0f72 --- /dev/null +++ b/web/src/engine/websites/TenManga.ts @@ -0,0 +1,25 @@ +import { Tags } from '../Tags'; +import icon from './TenManga.webp'; +import { DecoratableMangaScraper } from '../providers/MangaPlugin'; +import * as TAADD from './decorators/TAADDBase'; +import * as Common from './decorators/Common'; +function ChapterExtractor(anchor: HTMLAnchorElement) { + return { + id: anchor.pathname, + title: anchor.getElementsByClassName('chp-idx')[0].textContent.trim() + }; +} + +@Common.MangaCSS(/^{origin}\/book\/[^/]+\.html$/, TAADD.queryMangaTitleFromURI, TAADD.MangaLabelExtractor) +@Common.MangasMultiPageCSS(TAADD.mangaPath, 'section.book-list div.book-item a:first-of-type', 1, 1, 0, Common.AnchorInfoExtractor(true)) +@TAADD.ChaptersSinglePageCSS('div.chp-item a', ChapterExtractor) +@TAADD.PagesSinglePageCSS('div.option-list.chp-selection-list[option_name="page_head"] div[option_val]') +@TAADD.ImageAjaxFromHTML() +export default class extends DecoratableMangaScraper { + public constructor() { + super('tenmanga', `TenManga`, 'https://www.tenmanga.com', Tags.Language.English, Tags.Media.Manga, Tags.Media.Manhua, Tags.Media.Manhwa, Tags.Source.Aggregator); + } + public override get Icon() { + return icon; + } +} \ No newline at end of file diff --git a/web/src/engine/websites/legacy/TenManga.webp b/web/src/engine/websites/TenManga.webp similarity index 100% rename from web/src/engine/websites/legacy/TenManga.webp rename to web/src/engine/websites/TenManga.webp diff --git a/web/src/engine/websites/TenManga_e2e.ts b/web/src/engine/websites/TenManga_e2e.ts new file mode 100644 index 0000000000..0d2042e1f6 --- /dev/null +++ b/web/src/engine/websites/TenManga_e2e.ts @@ -0,0 +1,22 @@ +import { TestFixture } from '../../../test/WebsitesFixture'; + +new TestFixture({ + plugin: { + id: 'tenmanga', + title: 'TenManga' + }, + container: { + url: 'https://www.tenmanga.com/book/Yoroizuka-san+wo+Baburasetai.html', + id: '/book/Yoroizuka-san+wo+Baburasetai.html', + title: 'Yoroizuka-san wo Baburasetai', + }, + child: { + id: '/chapter/YoroizukasanwoBaburasetai20/8875086/', + title: '20', + }, + entry: { + index: 0, + size: 302_559, + type: 'image/jpeg' + } +}).AssertWebsite(); \ No newline at end of file diff --git a/web/src/engine/websites/_index.ts b/web/src/engine/websites/_index.ts index 1437c61e1f..2e492acaf9 100755 --- a/web/src/engine/websites/_index.ts +++ b/web/src/engine/websites/_index.ts @@ -377,6 +377,7 @@ export { default as MangaRolls } from './MangaRolls'; export { default as MangaRomance } from './MangaRomance'; export { default as MangaRose } from './MangaRose'; export { default as MangaRuhu } from './MangaRuhu'; +export { default as MangaRussia } from './MangaRussia'; export { default as MangAs } from './MangAs'; export { default as MangaSail } from './MangaSail'; export { default as MangaScantrad } from './MangaScantrad'; @@ -495,6 +496,13 @@ export { default as NicoNicoSeiga } from './NicoNicoSeiga'; export { default as Nightow } from './Nightow'; export { default as NightScans } from './NightScans'; export { default as NijiTranslations } from './NijiTranslations'; +export { default as NineMangaBR } from './NineMangaBR'; +export { default as NineMangaDE } from './NineMangaDE'; +export { default as NineMangaEN } from './NineMangaEN'; +export { default as NineMangaES } from './NineMangaES'; +export { default as NineMangaFR } from './NineMangaFR'; +export { default as NineMangaIT } from './NineMangaIT'; +export { default as NineMangaRU } from './NineMangaRU'; export { default as NirvanaManga } from './NirvanaManga'; export { default as NitroManga } from './NitroManga'; export { default as NiveraFansub } from './NiveraFansub'; @@ -640,6 +648,7 @@ export { default as SuryaScans } from './SuryaScans'; export { default as SushiScans } from './SushiScans'; export { default as SushiScansFR } from './SushiScansFR'; export { default as SweetTimeScan } from './SweetTimeScan'; +export { default as TAADD } from './TAADD'; export { default as Tapas } from './Tapas'; export { default as TappyToon } from './TappyToon'; export { default as Tapread } from './Tapread'; @@ -651,6 +660,7 @@ export { default as TecnoScan } from './TecnoScan'; export { default as TempestScans } from './TempestScans'; export { default as TempleScan } from './TempleScan'; export { default as Tenkai } from './Tenkai'; +export { default as TenManga } from './TenManga'; export { default as TenshiID } from './TenshiID'; export { default as TheBlank } from './TheBlank'; export { default as ThreeHentai } from './ThreeHentai'; @@ -781,7 +791,6 @@ export { default as MangaOnlineFun } from './legacy/MangaOnlineFun'; export { default as MangaPark } from './legacy/MangaPark'; export { default as MangaParkEN } from './legacy/MangaParkEN'; export { default as MangaReaderSite } from './legacy/MangaReaderSite'; -export { default as MangaRussia } from './legacy/MangaRussia'; export { default as MangaToonCN } from './legacy/MangaToonCN'; export { default as MangaToonEN } from './legacy/MangaToonEN'; export { default as MangaToonES } from './legacy/MangaToonES'; @@ -797,12 +806,6 @@ export { default as MyAnimeListManga } from './legacy/MyAnimeListManga'; export { default as MyReadingManga } from './legacy/MyReadingManga'; export { default as Naver } from './legacy/Naver'; export { default as NhatTruyen } from './legacy/NhatTruyen'; -export { default as NineMangaBR } from './legacy/NineMangaBR'; -export { default as NineMangaDE } from './legacy/NineMangaDE'; -export { default as NineMangaEN } from './legacy/NineMangaEN'; -export { default as NineMangaES } from './legacy/NineMangaES'; -export { default as NineMangaIT } from './legacy/NineMangaIT'; -export { default as NineMangaRU } from './legacy/NineMangaRU'; export { default as NovelcoolBR } from './legacy/NovelcoolBR'; export { default as NovelcoolDE } from './legacy/NovelcoolDE'; export { default as NovelcoolEN } from './legacy/NovelcoolEN'; @@ -821,10 +824,8 @@ export { default as SixMH7 } from './legacy/SixMH7'; export { default as SleepyTranslations } from './legacy/SleepyTranslations'; export { default as SouDongMan } from './legacy/SouDongMan'; export { default as StoriaDash } from './legacy/StoriaDash'; -export { default as TAADD } from './legacy/TAADD'; export { default as TaoManhua } from './legacy/TaoManhua'; export { default as TencentComic } from './legacy/TencentComic'; -export { default as TenManga } from './legacy/TenManga'; export { default as ToomicsDE } from './legacy/ToomicsDE'; export { default as ToomicsEN } from './legacy/ToomicsEN'; export { default as ToomicsES } from './legacy/ToomicsES'; diff --git a/web/src/engine/websites/decorators/TAADDBase.ts b/web/src/engine/websites/decorators/TAADDBase.ts new file mode 100644 index 0000000000..3ad7fd70e4 --- /dev/null +++ b/web/src/engine/websites/decorators/TAADDBase.ts @@ -0,0 +1,184 @@ +import { Fetch, FetchCSS } from '../../platform/FetchProvider'; +import { type MangaScraper, type Manga, Chapter, Page } from '../../providers/MangaPlugin'; +import type { Priority } from '../../taskpool/DeferredTask'; +import DeProxify from '../../transformers/ImageLinkDeProxifier'; +import * as Common from './Common'; +export function MangaLabelExtractor(element: HTMLElement) { + return ((element as HTMLMetaElement).content || element.textContent).replace(/(^\s*[Мм]анга|[Mm]anga\s*$)/, '').trim(); +} + +type LinkExtractor = (this: MangaScraper, element: HTMLElement) => string; +export function ChapterExtractor(element: HTMLAnchorElement) { + return { + id: element.pathname + element.search, + title: element.childNodes[0].nodeValue.trim() + }; +} + +export function PageLinkExtractor(this: MangaScraper, element: HTMLElement) { + switch (element.nodeName) { + case 'OPTION'://Most TAADD websites got a selector with options element + return new URL((element as HTMLOptionElement).value, this.URI).href; + case 'DIV': //Tenmanga = selector is a div full of
; + return element.getAttribute('option_val') || element.textContent; + default: //just in case. People could always use a custom PageLinkExtractor anyway + return element.textContent; + } +} + +export const mangaPath = '/search/?completed_series=either&page={page}'; +export const queryMangaTitleFromURI = 'meta[property="og:title"]'; +export const queryMangas = [ + 'div.clistChr ul li div.intro h2 a', + 'a.bookname', + 'a.resultbookname', +].join(','); + +export const queryChapters = [ + 'div.chapter_list table tr td:first-of-type a', + 'div.chapterbox ul li a.chapter_list_a', //NineManga +].join(','); +export const queryPages = 'select#page option'; +export const queryImages = [ + 'img#comicpic', + 'img.manga_pic' +].join(','); + +/************************************************* + ******** Chapter List Extraction Methods ******** + *************************************************/ + +/** + * An extension method for extracting all chapters for the given {@link manga} using the given CSS {@link query}. + * The chapters are extracted from the composed url based on the `Identifier` of the {@link manga} and the `URI` of the website. + * The purpose of this is to add search params to bypass adult warning. In case you dont need, use Common.ChaptersSinglePageCSS + * @param this - A reference to the {@link MangaScraper} instance which will be used as context for this method + * @param manga - A reference to the {@link Manga} which shall be assigned as parent for the extracted chapters + * @param query - A CSS query to locate the elements from which the chapter identifier and title shall be extracted + * @param extractor - An Extractor to get chapter infos + * @param bypassNsfwWarning - add a param to the url otherwise chapters are hidden for NSFW manga + */ +async function FetchChaptersSinglePageCSS(this: MangaScraper, manga: Manga, query = queryChapters, extractor = ChapterExtractor, bypassNsfwWarning = true): Promise { + const url = new URL(manga.Identifier, this.URI); + if (bypassNsfwWarning) { + url.searchParams.set('warning', '1'); + url.searchParams.set('waring', '1'); //NineManga typo + } + + const data = await FetchCSS(new Request(url), query); + return data.map(element => { + const { id, title } = extractor.call(this, element); + const mangaTitle = manga.Title.replace(/[*^.|$?+\-()[\]{}\\/]/g, '\\$&'); //escape special regex chars in manga name + let finaltitle = title.replace(new RegExpSafe(mangaTitle, 'i'), '') === '' ? title : title.replace(new RegExpSafe(mangaTitle, 'i'), '');//replace manga title in chapter title + finaltitle = finaltitle.replace(/\s*new$/, '').trim(); + return new Chapter(this, manga, id, finaltitle ); + }); +} + +/** + * A class decorator that adds the ability to extract all chapters for a given manga from this website using the given CSS {@link query}. + * The chapters are extracted from the composed url based on the `Identifier` of the manga and the `URI` of the website. + * The purpose of this is to add search params to bypass adult warning. In case you dont need, use Common.ChaptersSinglePageCSS + * @param query - A CSS query to locate the elements from which the chapter identifier and title shall be extracted + * @param extractor - An Extractor to get chapter infos + * @param bypassNsfwWarning - add a param to the url otherwise chapters are hidden for NSFW manga + */ +export function ChaptersSinglePageCSS(query: string = queryChapters, extractor = ChapterExtractor, bypassNsfwWarning = true) { + return function DecorateClass(ctor: T, context?: ClassDecoratorContext): T { + Common.ThrowOnUnsupportedDecoratorContext(context); + + return class extends ctor { + public async FetchChapters(this: MangaScraper, manga: Manga): Promise { + return FetchChaptersSinglePageCSS.call(this, manga, query, extractor, bypassNsfwWarning); + } + }; + }; +} + +/************************************************* + ******** Page List Extraction Methods ************ + *************************************************/ + +/** + * An extension method for extracting all pages for the given {@link chapter} using the given CSS. + * Use this when the chapter is made from multiples pages and each "sub pages" get a single or more images + * @param this - A reference to the {@link MangaScraper} instance which will be used as context for this method + * @param chapter - A reference to the {@link Chapter} which shall be assigned as parent for the extracted pages + * @param query - A CSS selector to the element containing all subpages : Typically opyions elements + * @param extractor - A function to extract the subpage information from a single element (found with {@link query}) + */ + +export function PagesSinglePageCSS(query: string = queryPages, extractor: LinkExtractor = PageLinkExtractor) { + return function DecorateClass(ctor: T, context?: ClassDecoratorContext): T { + Common.ThrowOnUnsupportedDecoratorContext(context); + + return class extends ctor { + public async FetchPages(this: MangaScraper, chapter: Chapter): Promise { + return FetchPagesSinglePagesCSS.call(this, chapter, query, extractor ); + } + }; + }; +} + +/** + * An extension method that adds the ability to get the image data when Page is the link to an HTML Page. + * Use this when Chapter are composed of multiple html Page and each page hold an image + * @param this - A reference to the {@link MangaScraper} instance which will be used as context for this method + * @param page - A reference to the {@link Page} containing the necessary information to acquire the image data + * @param priority - The importance level for ordering the request for the image data within the internal task pool + * @param signal - An abort signal that can be used to cancel the request for the image data + * @param queryImage - a query to get the image in the html page Page + * @param detectMimeType - Force a fingerprint check of the image data to detect its mime-type (instead of relying on the Content-Type header) + * @param deProxifyLink - Remove common image proxies (default false) + */ +export async function FetchImageAjaxFromHTML(this: MangaScraper, page: Page, priority: Priority, signal: AbortSignal, queryImage: string = queryImages, detectMimeType = false, deProxifyLink = false): Promise { + return await this.imageTaskPool.Add(async () => { + let request = new Request(page.Link, { + signal: signal, //To avoid redirection on crappy hosts, DONT USE referrer on html subpages + }); + let realimage = (await FetchCSS(request, queryImage))[0].getAttribute('src'); + realimage = deProxifyLink ? DeProxify(new URL(realimage)).href : realimage; + request = new Request(realimage, { + signal, + headers: { + Referer: page.Parameters?.Referer ? page.Parameters.Referer : page.Link.origin + } + }); + const response = await Fetch(request); + return detectMimeType ? await Common.GetTypedData(await response.arrayBuffer()) : await response.blob(); + + }, priority, signal); +} + +/** + * A class decorator that adds the ability to get the image data when Page is the link to an HTML Page. + * Use this when Chapter are composed of multiple html Page and each page hold an image + * @param queryImage - a query to get the image in the html page Page + * @param detectMimeType - Force a fingerprint check of the image data to detect its mime-type (instead of relying on the Content-Type header) + * @param deProxifyLink - Remove common image proxies (default false) + */ +export function ImageAjaxFromHTML(queryImage: string = queryImages, detectMimeType = false, deProxifyLink = false) { + return function DecorateClass(ctor: T, context?: ClassDecoratorContext): T { + Common.ThrowOnUnsupportedDecoratorContext(context); + return class extends ctor { + public async FetchImage(this: MangaScraper, page: Page, priority: Priority, signal: AbortSignal): Promise { + return FetchImageAjaxFromHTML.call(this, page, priority, signal, queryImage, detectMimeType, deProxifyLink); + } + }; + }; +} \ No newline at end of file diff --git a/web/src/engine/websites/decorators/TAADDBase_e2e.ts b/web/src/engine/websites/decorators/TAADDBase_e2e.ts new file mode 100644 index 0000000000..09c22a4fec --- /dev/null +++ b/web/src/engine/websites/decorators/TAADDBase_e2e.ts @@ -0,0 +1,9 @@ +import '../MangaRussia_e2e'; +import '../NineMangaBR_e2e'; +import '../NineMangaDE_e2e'; +import '../NineMangaEN_e2e'; +import '../NineMangaES_e2e'; +import '../NineMangaFR_e2e'; +import '../NineMangaIT_e2e'; +import '../TAADD_e2e'; +import '../TenManga_e2e'; \ No newline at end of file diff --git a/web/src/engine/websites/legacy/MangaRussia.ts b/web/src/engine/websites/legacy/MangaRussia.ts deleted file mode 100755 index 1981025569..0000000000 --- a/web/src/engine/websites/legacy/MangaRussia.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Auto-Generated export from HakuNeko Legacy -// See: https://gist.github.com/ronny1982/0c8d5d4f0bd9c1f1b21dbf9a2ffbfec9 - -//import { Tags } from '../../Tags'; -import icon from './MangaRussia.webp'; -import { DecoratableMangaScraper } from '../../providers/MangaPlugin'; - -export default class extends DecoratableMangaScraper { - - public constructor() { - super('mangarussia', `MangaRussia`, 'http://www.mangarussia.com' /*, Tags.Language.English, Tags ... */); - } - - public override get Icon() { - return icon; - } -} - -// Original Source -/* -class MangaRussia extends TAADD { - - constructor() { - super(); - super.id = 'mangarussia'; - super.label = 'MangaRussia'; - this.tags = [ 'manga', 'russian' ]; - this.url = 'http://www.mangarussia.com'; - this.requestOptions.headers.set('x-referer', this.url); - - this.bypassAdultWarning = false; - this.queryMangaTitle = 'div.mangabookbox div.bookmessagebox h1'; - this.queryMangas = 'table tr td a.resultbookname'; - this.queryChapters = 'div.chapterlist table tr td.col1 a'; - this.queryPages = 'select#page'; - this.queryImages = 'source#comicpic'; - } -} -*/ \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaBR.ts b/web/src/engine/websites/legacy/NineMangaBR.ts deleted file mode 100755 index ee3db59d54..0000000000 --- a/web/src/engine/websites/legacy/NineMangaBR.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Auto-Generated export from HakuNeko Legacy -// See: https://gist.github.com/ronny1982/0c8d5d4f0bd9c1f1b21dbf9a2ffbfec9 - -//import { Tags } from '../../Tags'; -import icon from './NineMangaBR.webp'; -import { DecoratableMangaScraper } from '../../providers/MangaPlugin'; - -export default class extends DecoratableMangaScraper { - - public constructor() { - super('ninemanga-br', `NineMangaBR`, 'https://br.ninemanga.com' /*, Tags.Language.English, Tags ... */); - } - - public override get Icon() { - return icon; - } -} - -// Original Source -/* -class NineMangaBR extends NineManga { - - constructor() { - super(); - super.id = 'ninemanga-br'; - super.label = 'NineMangaBR'; - this.tags = [ 'manga', 'portuguese' ]; - this.url = 'https://br.ninemanga.com'; - } -} -*/ \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaDE.ts b/web/src/engine/websites/legacy/NineMangaDE.ts deleted file mode 100755 index 824165dace..0000000000 --- a/web/src/engine/websites/legacy/NineMangaDE.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Auto-Generated export from HakuNeko Legacy -// See: https://gist.github.com/ronny1982/0c8d5d4f0bd9c1f1b21dbf9a2ffbfec9 - -//import { Tags } from '../../Tags'; -import icon from './NineMangaDE.webp'; -import { DecoratableMangaScraper } from '../../providers/MangaPlugin'; - -export default class extends DecoratableMangaScraper { - - public constructor() { - super('ninemanga-de', `NineMangaDE`, 'https://de.ninemanga.com' /*, Tags.Language.English, Tags ... */); - } - - public override get Icon() { - return icon; - } -} - -// Original Source -/* -class NineMangaDE extends NineManga { - - constructor() { - super(); - super.id = 'ninemanga-de'; - super.label = 'NineMangaDE'; - this.tags = [ 'manga', 'german' ]; - this.url = 'https://de.ninemanga.com'; - } -} -*/ \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaEN.ts b/web/src/engine/websites/legacy/NineMangaEN.ts deleted file mode 100755 index ed5d12ddff..0000000000 --- a/web/src/engine/websites/legacy/NineMangaEN.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Auto-Generated export from HakuNeko Legacy -// See: https://gist.github.com/ronny1982/0c8d5d4f0bd9c1f1b21dbf9a2ffbfec9 - -//import { Tags } from '../../Tags'; -import icon from './NineMangaEN.webp'; -import { DecoratableMangaScraper } from '../../providers/MangaPlugin'; - -export default class extends DecoratableMangaScraper { - - public constructor() { - super('ninemanga-en', `NineMangaEN`, 'https://en.ninemanga.com' /*, Tags.Language.English, Tags ... */); - } - - public override get Icon() { - return icon; - } -} - -// Original Source -/* -class NineMangaEN extends NineManga { - - constructor() { - super(); - super.id = 'ninemanga-en'; - super.label = 'NineMangaEN'; - this.tags = [ 'manga', 'english' ]; - this.url = 'https://en.ninemanga.com'; - } -} -*/ \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaES.ts b/web/src/engine/websites/legacy/NineMangaES.ts deleted file mode 100755 index 3c844c9d03..0000000000 --- a/web/src/engine/websites/legacy/NineMangaES.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Auto-Generated export from HakuNeko Legacy -// See: https://gist.github.com/ronny1982/0c8d5d4f0bd9c1f1b21dbf9a2ffbfec9 - -//import { Tags } from '../../Tags'; -import icon from './NineMangaES.webp'; -import { DecoratableMangaScraper } from '../../providers/MangaPlugin'; - -export default class extends DecoratableMangaScraper { - - public constructor() { - super('ninemanga-es', `NineMangaES`, 'https://es.ninemanga.com' /*, Tags.Language.English, Tags ... */); - } - - public override get Icon() { - return icon; - } -} - -// Original Source -/* -class NineMangaES extends NineManga { - - constructor() { - super(); - super.id = 'ninemanga-es'; - super.label = 'NineMangaES'; - this.tags = [ 'manga', 'spanish' ]; - this.url = 'https://es.ninemanga.com'; - } -} -*/ \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaIT.ts b/web/src/engine/websites/legacy/NineMangaIT.ts deleted file mode 100755 index 6777f1db08..0000000000 --- a/web/src/engine/websites/legacy/NineMangaIT.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Auto-Generated export from HakuNeko Legacy -// See: https://gist.github.com/ronny1982/0c8d5d4f0bd9c1f1b21dbf9a2ffbfec9 - -//import { Tags } from '../../Tags'; -import icon from './NineMangaIT.webp'; -import { DecoratableMangaScraper } from '../../providers/MangaPlugin'; - -export default class extends DecoratableMangaScraper { - - public constructor() { - super('ninemanga-it', `NineMangaIT`, 'https://it.ninemanga.com' /*, Tags.Language.English, Tags ... */); - } - - public override get Icon() { - return icon; - } -} - -// Original Source -/* -class NineMangaIT extends NineManga { - - constructor() { - super(); - super.id = 'ninemanga-it'; - super.label = 'NineMangaIT'; - this.tags = [ 'manga', 'italian' ]; - this.url = 'https://it.ninemanga.com'; - } -} -*/ \ No newline at end of file diff --git a/web/src/engine/websites/legacy/NineMangaRU.ts b/web/src/engine/websites/legacy/NineMangaRU.ts deleted file mode 100755 index b9553a74c4..0000000000 --- a/web/src/engine/websites/legacy/NineMangaRU.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Auto-Generated export from HakuNeko Legacy -// See: https://gist.github.com/ronny1982/0c8d5d4f0bd9c1f1b21dbf9a2ffbfec9 - -//import { Tags } from '../../Tags'; -import icon from './NineMangaRU.webp'; -import { DecoratableMangaScraper } from '../../providers/MangaPlugin'; - -export default class extends DecoratableMangaScraper { - - public constructor() { - super('ninemanga-ru', `NineMangaRU`, 'https://ru.ninemanga.com' /*, Tags.Language.English, Tags ... */); - } - - public override get Icon() { - return icon; - } -} - -// Original Source -/* -class NineMangaRU extends NineManga { - - constructor() { - super(); - super.id = 'ninemanga-ru'; - super.label = 'NineMangaRU'; - this.tags = [ 'manga', 'russian' ]; - this.url = 'https://ru.ninemanga.com'; - } -} -*/ \ No newline at end of file diff --git a/web/src/engine/websites/legacy/TAADD.ts b/web/src/engine/websites/legacy/TAADD.ts deleted file mode 100755 index 439ef199fb..0000000000 --- a/web/src/engine/websites/legacy/TAADD.ts +++ /dev/null @@ -1,104 +0,0 @@ -// Auto-Generated export from HakuNeko Legacy -// See: https://gist.github.com/ronny1982/0c8d5d4f0bd9c1f1b21dbf9a2ffbfec9 - -//import { Tags } from '../../Tags'; -import icon from './TAADD.webp'; -import { DecoratableMangaScraper } from '../../providers/MangaPlugin'; - -export default class extends DecoratableMangaScraper { - - public constructor() { - super('taadd', `TAADD`, 'https://www.taadd.com' /*, Tags.Language.English, Tags ... */); - } - - public override get Icon() { - return icon; - } -} - -// Original Source -/* -class TAADD extends Connector { - - constructor() { - super(); - super.id = 'taadd'; - super.label = 'TAADD'; - this.tags = [ 'manga', 'english' ]; - this.url = 'https://www.taadd.com'; - this.links = { - login: 'https://my.taadd.com/login.html' - }; - - this.bypassAdultWarning = true; - this.queryMangaTitle = 'meta[property="og:title"]'; - this.queryMangas = 'div.clistChr ul li div.intro h2 a'; - this.queryChapters = 'div.chapter_list table tr td:first-of-type a'; - this.queryPages = 'select#page'; - this.queryImages = 'source#comicpic'; - } - - async _getMangaFromURI(uri) { - let request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryMangaTitle); - let id = uri.pathname; - let title = (data[0].content || data[0].textContent).replace(/(^\s*[Мм]анга|[Mm]anga\s*$)/, '').trim(); - return new Manga(this, id, title); - } - - async _getMangas() { - let mangaList = []; - for(let page = 1, run = true; run; page++) { - let mangas = await this._getMangasFromPage(page); - mangas.length > 0 ? mangaList.push(...mangas) : run = false; - } - return mangaList; - } - - async _getMangasFromPage(page) { - let uri = new URL('/search/', this.url); - uri.searchParams.set('completed_series', 'either'); - uri.searchParams.set('page', page); - let request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryMangas); - return data.map(element => { - this.cfMailDecrypt(element); - return { - id: this.getRootRelativeOrAbsoluteLink(element, this.url), - title: element.title.trim() || element.text.trim() - }; - }); - } - - async _getChapters(manga) { - let uri = new URL(manga.id, this.url); - if(this.bypassAdultWarning) { - uri.searchParams.set('warning', '1'); - // fix query parameter typo for ninemanga - uri.searchParams.set('waring', '1'); - } - let request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryChapters); - return data.map(element => { - this.cfMailDecrypt(element); - return { - id: this.getRootRelativeOrAbsoluteLink(element, this.url), - title: element.text.replace(manga.title, '').replace(/\s*new$/, '').trim(), - language: '' - }; - }); - } - - async _getPages(chapter) { - let request = new Request(new URL(chapter.id, this.url), this.requestOptions); - let data = await this.fetchDOM(request, this.queryPages); - return [...data[0].querySelectorAll('option')].map(option => this.createConnectorURI(this.getAbsolutePath(option.value, request.url))); - } - - async _handleConnectorURI(payload) { - let request = new Request(new URL(payload, this.url), this.requestOptions); - let data = await this.fetchDOM(request, this.queryImages); - return super._handleConnectorURI(this.getAbsolutePath(data[0].src, request.url)); - } -} -*/ \ No newline at end of file diff --git a/web/src/engine/websites/legacy/TenManga.ts b/web/src/engine/websites/legacy/TenManga.ts deleted file mode 100755 index 0994eab37d..0000000000 --- a/web/src/engine/websites/legacy/TenManga.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Auto-Generated export from HakuNeko Legacy -// See: https://gist.github.com/ronny1982/0c8d5d4f0bd9c1f1b21dbf9a2ffbfec9 - -//import { Tags } from '../../Tags'; -import icon from './TenManga.webp'; -import { DecoratableMangaScraper } from '../../providers/MangaPlugin'; - -export default class extends DecoratableMangaScraper { - - public constructor() { - super('tenmanga', `TenManga`, 'https://www.tenmanga.com' /*, Tags.Language.English, Tags ... */); - } - - public override get Icon() { - return icon; - } -} - -// Original Source -/* -class TenManga extends TAADD { - - constructor() { - super(); - super.id = 'tenmanga'; - super.label = 'TenManga'; - this.tags = [ 'manga', 'english' ]; - this.url = 'http://www.tenmanga.com'; - this.links = { - login: 'http://www.tenmanga.com/login' - }; - - //this.bypassAdultWarning = true; - this.queryMangaTitle = 'div.container_book div.book-info h1'; - this.queryMangas = 'ul#list_container li dd.book-list > a:first-of-type'; - this.queryChapters = 'ul.chapter-box li div.chapter-name.short a'; - this.queryPages = 'select.sl-page'; - this.queryImages = 'div.pic_box source.manga_pic'; - } -} -*/ \ No newline at end of file