From 5c114d9c835a6d2ceaa533bb842a10f4f16e3717 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Wed, 9 Nov 2022 20:42:01 +0000 Subject: [PATCH 01/64] Change Url for ComicHub --- src/web/mjs/connectors/ComicHub.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/ComicHub.mjs b/src/web/mjs/connectors/ComicHub.mjs index c533a32d08f..f4e78269f98 100644 --- a/src/web/mjs/connectors/ComicHub.mjs +++ b/src/web/mjs/connectors/ComicHub.mjs @@ -7,6 +7,6 @@ export default class ComicHub extends WordPressMadara { super.id = 'comichub'; super.label = 'ComicHub'; this.tags = [ 'comic', 'english' ]; - this.url = 'https://comichub.net'; + this.url = 'https://comiconline.org/'; } -} \ No newline at end of file +} From 074d5005cacc2f46145bf19580a154c04f5067f3 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Wed, 9 Nov 2022 20:47:33 +0000 Subject: [PATCH 02/64] Update Mangasushi url --- src/web/mjs/connectors/MangaSushi.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/MangaSushi.mjs b/src/web/mjs/connectors/MangaSushi.mjs index 8a8707ba7a5..5afda754bf6 100644 --- a/src/web/mjs/connectors/MangaSushi.mjs +++ b/src/web/mjs/connectors/MangaSushi.mjs @@ -7,6 +7,6 @@ export default class MangaSushi extends WordPressMadara { super.id = 'mangasushi'; super.label = 'Mangasushi'; this.tags = [ 'manga', 'english' ]; - this.url = 'https://mangasushi.net'; + this.url = 'https://mangasushi.org'; } -} \ No newline at end of file +} From d6a53121d6923ec627ac4d09c01336e8dff9b377 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Wed, 9 Nov 2022 21:59:28 +0000 Subject: [PATCH 03/64] Update Mangairo URL --- src/web/mjs/connectors/MangaIro.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/MangaIro.mjs b/src/web/mjs/connectors/MangaIro.mjs index 0718e041d85..3aadeb24866 100644 --- a/src/web/mjs/connectors/MangaIro.mjs +++ b/src/web/mjs/connectors/MangaIro.mjs @@ -8,7 +8,7 @@ export default class MangaIro extends MangaNel { super.id = 'mangairo'; super.label = 'Mangairo'; this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://m.mangairo.com'; + this.url = 'https://w.mangairo.com'; this.path = '/manga-list/type-latest/ctg-all/state-all/page-'; this.queryMangaTitle = /name_title\s*=\s*['"](.+)['"]\s*;/g; @@ -29,4 +29,4 @@ export default class MangaIro extends MangaNel { let title = data[0].trim(); return new Manga(this, id, title); } -} \ No newline at end of file +} From 0612afc5cf6f8c6397d90fb1b0656b84feed4f23 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 10 Nov 2022 10:49:19 +0000 Subject: [PATCH 04/64] Fixt test for fake image on IceKR --- src/web/mjs/connectors/IceKr.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/web/mjs/connectors/IceKr.mjs b/src/web/mjs/connectors/IceKr.mjs index 1b2dc494c9a..7004ce93a0a 100644 --- a/src/web/mjs/connectors/IceKr.mjs +++ b/src/web/mjs/connectors/IceKr.mjs @@ -8,6 +8,7 @@ export default class IceKr extends SinMH { super.label = '冰氪漫画 (iceKr)'; this.tags = [ 'manga', 'webtoon', 'chinese' ]; this.url = 'https://www.icekr.com'; + this.requestOptions.headers.set( 'x-referer', this.url ); this.config = { throttle: { label: 'Page Throttle Requests [ms]', From 947fea6781f2ce682b9476a9fb4ea575c7109331 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 10 Nov 2022 13:15:31 +0000 Subject: [PATCH 05/64] Fixing ComicFX * pictures doesnt have a class anymore * ad picture changed --- src/web/mjs/connectors/ComicFX.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/mjs/connectors/ComicFX.mjs b/src/web/mjs/connectors/ComicFX.mjs index 7c95ca7d24e..ec7aea46fc0 100644 --- a/src/web/mjs/connectors/ComicFX.mjs +++ b/src/web/mjs/connectors/ComicFX.mjs @@ -50,7 +50,7 @@ export default class ComicFX extends Connector { async _getPages(chapter) { const uri = new URL(chapter.id, this.url); const request = new Request(uri, this.requestOptions); - const data = await this.fetchDOM(request, 'div#lcanv source.img-responsive'); + const data = await this.fetchDOM(request, 'div#lcanv source'); return data.map(image => { let url = this.getAbsolutePath(image.dataset.src || image, request.url); try { @@ -67,8 +67,8 @@ export default class ComicFX extends Connector { .replace(/\/(w=\d+|h=\d+|q=\d+|f=auto)(,(w=\d+|h=\d+|q=\d+|f=auto))*\//, '/'); return url.includes('img.comicfx.net') ? this.createConnectorURI(url) : url; }).filter(url => { - const adImageFiles = [ '/4WWje.jpg' ]; + const adImageFiles = [ '/BPCzV.jpg' ]; return adImageFiles.every(adImageFile => !url.endsWith(adImageFile)); }); } -} \ No newline at end of file +} From c29d95ffed732ed2f3ebad3f44c5a6eaa2220fb2 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 10 Nov 2022 14:51:48 +0100 Subject: [PATCH 06/64] Add OmegaScans icon --- src/web/img/connectors/omegascans | Bin 0 -> 8407 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/omegascans diff --git a/src/web/img/connectors/omegascans b/src/web/img/connectors/omegascans new file mode 100644 index 0000000000000000000000000000000000000000..f3e24d6e959401eef18fb12036f4ef61217e15af GIT binary patch literal 8407 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 literal 0 HcmV?d00001 From 4708191d190d1ea623b80538a79df7ed61388f2a Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 10 Nov 2022 14:54:38 +0100 Subject: [PATCH 07/64] Add OmegaScans connector --- src/web/mjs/connectors/OmegaScans.mjs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/web/mjs/connectors/OmegaScans.mjs diff --git a/src/web/mjs/connectors/OmegaScans.mjs b/src/web/mjs/connectors/OmegaScans.mjs new file mode 100644 index 00000000000..8695f3be0bc --- /dev/null +++ b/src/web/mjs/connectors/OmegaScans.mjs @@ -0,0 +1,13 @@ +import WordPressMangastream from './templates/WordPressMangastream.mjs'; + +export default class OmegaScans extends WordPressMangastream { + + constructor() { + super(); + super.id = 'OmegaScans'; + super.label = 'OmegaScans'; + this.tags = [ 'webtoon', 'scanlation', 'english', 'hentai']; + this.url = 'https://omegascans.org'; + this.path = '/manga/list-mode/'; + } +} \ No newline at end of file From 88cbf09311b8e1bb411376bdce948b8cc2676ac6 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 10 Nov 2022 15:57:25 +0100 Subject: [PATCH 08/64] Add scanhentaimenu icon --- src/web/img/connectors/scanhentaimenu | Bin 0 -> 7301 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/scanhentaimenu diff --git a/src/web/img/connectors/scanhentaimenu b/src/web/img/connectors/scanhentaimenu new file mode 100644 index 0000000000000000000000000000000000000000..c053224f5f54951974bda9c2f0ebc4e08ae5a4ec GIT binary patch literal 7301 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 f0Jf6U?g9J Date: Thu, 10 Nov 2022 15:59:16 +0100 Subject: [PATCH 09/64] Add ScanHentaiMenu and LegionScan --- src/web/mjs/connectors/LegionScan.mjs | 12 ++++++++++++ src/web/mjs/connectors/ScanHentaiMenu.mjs | 13 +++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/web/mjs/connectors/LegionScan.mjs create mode 100644 src/web/mjs/connectors/ScanHentaiMenu.mjs diff --git a/src/web/mjs/connectors/LegionScan.mjs b/src/web/mjs/connectors/LegionScan.mjs new file mode 100644 index 00000000000..16ba709539f --- /dev/null +++ b/src/web/mjs/connectors/LegionScan.mjs @@ -0,0 +1,12 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; + +export default class LegionScan extends WordPressMadara { + + constructor() { + super(); + super.id = 'legionscan'; + super.label = 'LegionScan'; + this.tags = [ 'webtoon', 'english', 'manga', 'spanish' ]; + this.url = 'https://legionscans.com'; + } +} \ No newline at end of file diff --git a/src/web/mjs/connectors/ScanHentaiMenu.mjs b/src/web/mjs/connectors/ScanHentaiMenu.mjs new file mode 100644 index 00000000000..7d7e67e7c32 --- /dev/null +++ b/src/web/mjs/connectors/ScanHentaiMenu.mjs @@ -0,0 +1,13 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; + +export default class ScanHentaiMenu extends WordPressMadara { + + constructor() { + super(); + super.id = 'scanhentaimenu'; + super.label = 'ScanHentaiMenu'; + this.tags = [ 'webtoon', 'english', 'hentai' ]; + this.url = 'https://scan.hentai.menu'; + this.requestOptions.headers.set( 'x-referer', this.url ); + } +} \ No newline at end of file From caf04ed0ade57a2ae52599518b331d5c8594504e Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 10 Nov 2022 16:41:22 +0100 Subject: [PATCH 10/64] Add Akumanotenshi, Mangarolls, kawascans --- src/web/mjs/connectors/Akumanotenshi.mjs | 12 ++++++++++++ src/web/mjs/connectors/KawaScans.mjs | 12 ++++++++++++ src/web/mjs/connectors/MangaRolls.mjs | 12 ++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 src/web/mjs/connectors/Akumanotenshi.mjs create mode 100644 src/web/mjs/connectors/KawaScans.mjs create mode 100644 src/web/mjs/connectors/MangaRolls.mjs diff --git a/src/web/mjs/connectors/Akumanotenshi.mjs b/src/web/mjs/connectors/Akumanotenshi.mjs new file mode 100644 index 00000000000..b1349782f82 --- /dev/null +++ b/src/web/mjs/connectors/Akumanotenshi.mjs @@ -0,0 +1,12 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; + +export default class KawaScans extends WordPressMadara { + + constructor() { + super(); + super.id = 'akumanotenshi'; + super.label = 'AkumanoTenshi'; + this.tags = [ 'webtoon', 'manga', 'portuguese' ]; + this.url = 'https://akumanotenshi.com'; + } +} \ No newline at end of file diff --git a/src/web/mjs/connectors/KawaScans.mjs b/src/web/mjs/connectors/KawaScans.mjs new file mode 100644 index 00000000000..7d950e9820e --- /dev/null +++ b/src/web/mjs/connectors/KawaScans.mjs @@ -0,0 +1,12 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; + +export default class KawaScans extends WordPressMadara { + + constructor() { + super(); + super.id = 'kawascans'; + super.label = 'KawaScans'; + this.tags = [ 'webtoon', 'english' ]; + this.url = 'https://kawascans.com'; + } +} \ No newline at end of file diff --git a/src/web/mjs/connectors/MangaRolls.mjs b/src/web/mjs/connectors/MangaRolls.mjs new file mode 100644 index 00000000000..02a57204227 --- /dev/null +++ b/src/web/mjs/connectors/MangaRolls.mjs @@ -0,0 +1,12 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; + +export default class KawaScans extends WordPressMadara { + + constructor() { + super(); + super.id = 'mangarolls'; + super.label = 'MangaRolls'; + this.tags = [ 'webtoon', 'manga', 'english' ]; + this.url = 'https://mangarolls.com'; + } +} \ No newline at end of file From 23193103bd467699d7f780cf5a0ac912afa282e4 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 10 Nov 2022 16:42:28 +0100 Subject: [PATCH 11/64] Add akumanotenshi icon --- src/web/img/connectors/akumanotenshi | Bin 0 -> 8853 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/akumanotenshi diff --git a/src/web/img/connectors/akumanotenshi b/src/web/img/connectors/akumanotenshi new file mode 100644 index 0000000000000000000000000000000000000000..49fc61693574b130e835d43b932fc3f901fd8e5b GIT binary patch literal 8853 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 Q*AW0jR`p}Gv{}gi0o>p0P5=M^ literal 0 HcmV?d00001 From 002c55a95c3f0b214996896c1edef9792334f8b5 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 10 Nov 2022 17:11:09 +0100 Subject: [PATCH 12/64] Add ManHatic and DrakeScans --- src/web/mjs/connectors/DrakeScans.mjs | 12 ++++++++++++ src/web/mjs/connectors/Manhatic.mjs | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/web/mjs/connectors/DrakeScans.mjs create mode 100644 src/web/mjs/connectors/Manhatic.mjs diff --git a/src/web/mjs/connectors/DrakeScans.mjs b/src/web/mjs/connectors/DrakeScans.mjs new file mode 100644 index 00000000000..9e3e5277265 --- /dev/null +++ b/src/web/mjs/connectors/DrakeScans.mjs @@ -0,0 +1,12 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; + +export default class DrakeScans extends WordPressMadara { + + constructor() { + super(); + super.id = 'drakescans'; + super.label = 'DrakeScans'; + this.tags = [ 'webtoon', 'english']; + this.url = 'https://drakescans.com'; + } +} \ No newline at end of file diff --git a/src/web/mjs/connectors/Manhatic.mjs b/src/web/mjs/connectors/Manhatic.mjs new file mode 100644 index 00000000000..cfc90894039 --- /dev/null +++ b/src/web/mjs/connectors/Manhatic.mjs @@ -0,0 +1,12 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; + +export default class ManHatic extends WordPressMadara { + + constructor() { + super(); + super.id = 'manhatic'; + super.label = 'ManHatic'; + this.tags = [ 'webtoon', 'arabic', 'hentai' ]; + this.url = 'https://manhatic.com'; + } +} \ No newline at end of file From 4025153dffeb4cdc2799895fd1b1dae1b8c6855e Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 10 Nov 2022 17:11:52 +0100 Subject: [PATCH 13/64] Add DrakeScans icon --- src/web/img/connectors/drakescans | Bin 0 -> 11050 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/drakescans diff --git a/src/web/img/connectors/drakescans b/src/web/img/connectors/drakescans new file mode 100644 index 0000000000000000000000000000000000000000..367a0150288073651c9a07baf96a5e832ecd5dc0 GIT binary patch literal 11050 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

Hw%C7?nnF6{%4fYV2(NAHay*G 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 literal 0 HcmV?d00001 From 02b89369470581a8f6177c151a24d086f541b4da Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Fri, 11 Nov 2022 10:07:09 +0000 Subject: [PATCH 14/64] Update KomikCast URL --- src/web/mjs/connectors/KomikCast.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/KomikCast.mjs b/src/web/mjs/connectors/KomikCast.mjs index 03c3e56c9c6..47e093922ea 100644 --- a/src/web/mjs/connectors/KomikCast.mjs +++ b/src/web/mjs/connectors/KomikCast.mjs @@ -7,7 +7,7 @@ export default class KomikCast extends WordPressMangastream { super.id = 'komikcast'; super.label = 'KomikCast'; this.tags = [ 'manga', 'indonesian' ]; - this.url = 'https://komikcast.me'; + this.url = 'https://komikcast.site'; this.path = '/daftar-komik/?list'; this.queryMangas = 'div.text-mode_list-items ul li a.series, div.text-mode_list-items ul li a.text-mode_list-item'; @@ -15,4 +15,4 @@ export default class KomikCast extends WordPressMangastream { this.queryChaptersTitle = undefined; this.queryPages = 'div.main-reading-area img[src^="http"], div.separator img[src^="http"]'; } -} \ No newline at end of file +} From 291d51f357a885c76314fd332f30d50a13e5443f Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Fri, 11 Nov 2022 17:20:53 +0000 Subject: [PATCH 15/64] Add BeautyManga --- src/web/mjs/connectors/BeautyManga.mjs | 69 ++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/web/mjs/connectors/BeautyManga.mjs diff --git a/src/web/mjs/connectors/BeautyManga.mjs b/src/web/mjs/connectors/BeautyManga.mjs new file mode 100644 index 00000000000..cc000fe7df1 --- /dev/null +++ b/src/web/mjs/connectors/BeautyManga.mjs @@ -0,0 +1,69 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; + +export default class BeautyManga extends WordPressMadara { + + constructor() { + super(); + super.id = 'beautymanga'; + super.label = 'BeautyManga'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://mangadex.today'; + + this.path = '/popular-manga'; + this.queryMangas = 'div.item-thumb.hover-details.c-image-hover a'; + this.queryMangasPageCount = 'ul.pagination li:nth-last-of-type(2) a'; + this.pathMangas = '?page=%PAGE%'; + this.queryPages = 'p#arraydata'; + this.mangaTitleFilter = ''; + } + + + async _getMangasFromPage(page) { + let uri = new URL(this.path + this.pathMangas.replace('%PAGE%', page), this.url); + uri.pathname = uri.pathname.replace(/\/+/g, '/'); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangas); + return data.map(element => { + return { + id: new URL(element.href, request.url).pathname, + title: element.title.replace(this.mangaTitleFilter, '').trim() + }; + }); + } + + + async _getChaptersAjaxOld(mangaID) { + const uri = new URL('/ajax-list-chapter?mangaID='+mangaID , this.url); + const request = new Request(uri, { method: 'GET' }); + const data = await this.fetchDOM(request, this.queryChapters); + if (data.length) { + return data; + } else { + throw new Error('No chapters found (new ajax endpoint)!'); + } + } + + async _getPages(chapter) + { + let uri = new URL(chapter.id, this.url); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryPages); + let el = data[0].innerText.split(','); + + return el.map(element => + { + const uri = new URL(this.getAbsolutePath(element, request.url)); + return this.createConnectorURI({ + // HACK: bypass 'i0.wp.com' image CDN to ensure original images are loaded directly from host + url: uri.href.replace(/\/i\d+\.wp\.com/, ''), + referer: uri.origin + }) + + }); + + } + + + + +} From 20fd6cdfe992d3d7cd384a8620e3fd7065cf073c Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 10:13:23 +0000 Subject: [PATCH 16/64] Add pururin support --- src/web/mjs/connectors/Pururin.mjs | 124 ++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 29 deletions(-) diff --git a/src/web/mjs/connectors/Pururin.mjs b/src/web/mjs/connectors/Pururin.mjs index 211d15a2343..b1763bcdb6b 100644 --- a/src/web/mjs/connectors/Pururin.mjs +++ b/src/web/mjs/connectors/Pururin.mjs @@ -1,31 +1,97 @@ import Connector from '../engine/Connector.mjs'; - -/** - * - */ +import Manga from '../engine/Manga.mjs'; export default class Pururin extends Connector { - - /** - * - */ - constructor() { - super(); - super.id = 'pururin'; - super.label = 'Pururin'; - this.tags = []; - this.url = 'https://pururin.io'; - this.links = { - login: 'https://pururin.io/login' - }; - } - - _getMangaList( callback ) { - callback( new Error( 'Please report this broken website on HakuNeko\'s GitHub project page.' ), undefined ); - } - _getChapterList( manga, callback ) { - callback( new Error( 'Please report this broken website on HakuNeko\'s GitHub project page.' ), undefined ); - } - _getPageList( manga, chapter, callback ) { - callback( new Error( 'Please report this broken website on HakuNeko\'s GitHub project page.' ), undefined ); - } -} \ No newline at end of file + constructor() { + super(); + super.id = 'pururin'; + super.label = 'Pururin'; + this.tags = ['manga', 'hentai', 'english']; + this.url = 'https://pururin.to'; + this.CDN = "https://cdn.pururin.to/assets/images/data/{1}/{2}.{3}"; + this.path = "/browse/title"; + this.api = "/api/contribute/gallery/info"; + this.queryMangasPageCount = 'ul.pagination.flex-wrap li:nth-last-of-type(2) a'; + this.queryMangas = 'a.card.card-gallery'; + this.queryChapters ='div.gallery-action a'; + this.requestOptions.headers.set('x-referer', this.url); + this.requestOptions.headers.set('x-origin', this.url); + } + async _getMangas() { + let mangaList = []; + const uri = new URL(this.path, this.url); + const request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangasPageCount); + let pageCount = parseInt(data[0].text); + for(let page = 1; page <= pageCount; page++) { + let mangas = await this._getMangasFromPage(page); + mangaList.push(...mangas); + } + return mangaList; + } + async _getMangasFromPage(page) { + let uri = new URL(this.path + '?page='+page, this.url); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangas); + return data.map(element => { + return { + id: this.getRootRelativeOrAbsoluteLink(element, request.url), + title: element.querySelector('source.card-img-top').getAttribute('alt').trim() + }; + }); + } + async _getChapters(manga) { + let mid = this.getRootRelativeOrAbsoluteLink(manga.id, this.url); + const chapters = [{ id: mid , title: 'Chapter' }]; + return chapters; + } + async _getPages(chapter) { + let queryPicture = ''; + let pictures = []; + var myRegexp = new RegExp("gallery\/([0-9]+)", "g"); + var match = myRegexp.exec(chapter.id); + let mangaID = match[1]; + let params = '{"id":'+mangaID+',"type":2}'; + const uri = new URL(this.api, this.url); + const request = new Request(uri, { + method: 'POST', + body: params, + headers: { + 'x-origin': this.url, + 'x-referer': this.url, + 'Content-Type': 'application/json;charset=UTF-8', + 'X-Requested-With': 'XMLHttpRequest', + } + }) + const data = await this.fetchJSON(request); + let pagesMax = data.gallery.total_pages; + let extension = data.gallery.image_extension; + //https://cdn.pururin.to/assets/images/data//.image_extension + for (var i = 1; i <= pagesMax;i++) + { + let imageuri = this.CDN.replace('{1}', mangaID).replace('{2}', i).replace('{3}', extension); + pictures.push(imageuri); + } + return pictures; + } + async _getMangaFromURI(uri) { + var myRegexp = new RegExp("gallery\/([0-9]+)", "g"); + var match = myRegexp.exec(uri.href); + let mangaID = match[1]; + let params = '{"id":'+mangaID+',"type":2}'; + const req = new URL(this.api, this.url); + const request = new Request(req, { + method: 'POST', + body: params, + headers: { + 'x-origin': this.url, + 'x-referer': this.url, + 'Content-Type': 'application/json;charset=UTF-8', + 'X-Requested-With': 'XMLHttpRequest', + } + }) + const data = await this.fetchJSON(request); + const title = data.gallery.title; + const id = this.getRootRelativeOrAbsoluteLink(uri, this.url); + return new Manga(this, id, title); + } +} From a851efd662386feb5d19b9e73ed037ec661f9c53 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 14:43:15 +0000 Subject: [PATCH 17/64] Fix lint on ScanHentaiMenu --- src/web/mjs/connectors/ScanHentaiMenu.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/ScanHentaiMenu.mjs b/src/web/mjs/connectors/ScanHentaiMenu.mjs index 7d7e67e7c32..f938c4fa409 100644 --- a/src/web/mjs/connectors/ScanHentaiMenu.mjs +++ b/src/web/mjs/connectors/ScanHentaiMenu.mjs @@ -8,6 +8,6 @@ export default class ScanHentaiMenu extends WordPressMadara { super.label = 'ScanHentaiMenu'; this.tags = [ 'webtoon', 'english', 'hentai' ]; this.url = 'https://scan.hentai.menu'; - this.requestOptions.headers.set( 'x-referer', this.url ); + this.requestOptions.headers.set( 'x-referer', this.url ); } -} \ No newline at end of file +} From 1f72e5a1a036620a618c86c2c8b00e152d23ca46 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 16:11:27 +0000 Subject: [PATCH 18/64] Fixed BeautyManga formating --- src/web/mjs/connectors/BeautyManga.mjs | 122 ++++++++++++------------- 1 file changed, 57 insertions(+), 65 deletions(-) diff --git a/src/web/mjs/connectors/BeautyManga.mjs b/src/web/mjs/connectors/BeautyManga.mjs index cc000fe7df1..b25e27bf3b2 100644 --- a/src/web/mjs/connectors/BeautyManga.mjs +++ b/src/web/mjs/connectors/BeautyManga.mjs @@ -1,69 +1,61 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; export default class BeautyManga extends WordPressMadara { - - constructor() { - super(); - super.id = 'beautymanga'; - super.label = 'BeautyManga'; - this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://mangadex.today'; - - this.path = '/popular-manga'; - this.queryMangas = 'div.item-thumb.hover-details.c-image-hover a'; - this.queryMangasPageCount = 'ul.pagination li:nth-last-of-type(2) a'; - this.pathMangas = '?page=%PAGE%'; - this.queryPages = 'p#arraydata'; - this.mangaTitleFilter = ''; - } - - - async _getMangasFromPage(page) { - let uri = new URL(this.path + this.pathMangas.replace('%PAGE%', page), this.url); - uri.pathname = uri.pathname.replace(/\/+/g, '/'); - let request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryMangas); - return data.map(element => { - return { - id: new URL(element.href, request.url).pathname, - title: element.title.replace(this.mangaTitleFilter, '').trim() - }; - }); - } - - - async _getChaptersAjaxOld(mangaID) { - const uri = new URL('/ajax-list-chapter?mangaID='+mangaID , this.url); - const request = new Request(uri, { method: 'GET' }); - const data = await this.fetchDOM(request, this.queryChapters); - if (data.length) { - return data; - } else { - throw new Error('No chapters found (new ajax endpoint)!'); - } - } - - async _getPages(chapter) - { - let uri = new URL(chapter.id, this.url); - let request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryPages); - let el = data[0].innerText.split(','); - - return el.map(element => - { - const uri = new URL(this.getAbsolutePath(element, request.url)); - return this.createConnectorURI({ - // HACK: bypass 'i0.wp.com' image CDN to ensure original images are loaded directly from host - url: uri.href.replace(/\/i\d+\.wp\.com/, ''), - referer: uri.origin - }) - - }); - - } - - - - + constructor() { + super(); + super.id = 'beautymanga'; + super.label = 'BeautyManga'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://mangadex.today'; + this.path = '/popular-manga'; + this.queryMangas = 'div.item-thumb.hover-details.c-image-hover a'; + this.queryMangasPageCount = 'ul.pagination li:nth-last-of-type(2) a'; + this.pathMangas = '?page=%PAGE%'; + this.queryPages = 'p#arraydata'; + this.mangaTitleFilter = ''; + } + + async _getMangasFromPage(page) { + let uri = new URL(this.path + this.pathMangas.replace('%PAGE%', page), this.url); + uri.pathname = uri.pathname.replace(/\/+/g, '/'); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangas); + return data.map(element => { + return { + id: new URL(element.href, request.url).pathname, + title: element.title.replace(this.mangaTitleFilter, '').trim() + }; + }); + } + + async _getChaptersAjaxOld(mangaID) { + const uri = new URL('/ajax-list-chapter?mangaID='+mangaID , this.url); + const request = new Request(uri, { + method: 'GET' + }); + const data = await this.fetchDOM(request, this.queryChapters); + if (data.length) { + return data; + } + else { + throw new Error('No chapters found (new ajax endpoint)!'); + } + } + + async _getPages(chapter) + { + let uri = new URL(chapter.id, this.url); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryPages); + let el = data[0].innerText.split(','); + return el.map(element => + { + const uri = new URL(this.getAbsolutePath(element, request.url)); + return this.createConnectorURI({ + // HACK: bypass 'i0.wp.com' image CDN to ensure original images are loaded directly from host + url: uri.href.replace(/\/i\d+\.wp\.com/, ''), + referer: uri.origin + }) + }); + } } From 70d04fc0584afd082aaf3110b15a00cf3a496999 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 18:39:01 +0000 Subject: [PATCH 19/64] Fixed bad class name --- src/web/mjs/connectors/MangaRolls.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/MangaRolls.mjs b/src/web/mjs/connectors/MangaRolls.mjs index 02a57204227..f58b9d593d6 100644 --- a/src/web/mjs/connectors/MangaRolls.mjs +++ b/src/web/mjs/connectors/MangaRolls.mjs @@ -1,6 +1,6 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; -export default class KawaScans extends WordPressMadara { +export default class MangaRolls extends WordPressMadara { constructor() { super(); @@ -9,4 +9,4 @@ export default class KawaScans extends WordPressMadara { this.tags = [ 'webtoon', 'manga', 'english' ]; this.url = 'https://mangarolls.com'; } -} \ No newline at end of file +} From d4d63f9c7245f0947d1af142c96834c980f11b0a Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 19:43:25 +0100 Subject: [PATCH 20/64] Add missing dummy icons --- src/web/img/connectors/kawascans | Bin 0 -> 1098 bytes src/web/img/connectors/legionscan | Bin 0 -> 1098 bytes src/web/img/connectors/mangarolls | Bin 0 -> 1098 bytes src/web/img/connectors/manhatic | Bin 0 -> 1098 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/kawascans create mode 100644 src/web/img/connectors/legionscan create mode 100644 src/web/img/connectors/mangarolls create mode 100644 src/web/img/connectors/manhatic diff --git a/src/web/img/connectors/kawascans b/src/web/img/connectors/kawascans new file mode 100644 index 0000000000000000000000000000000000000000..72bb76c50880a876e4d2da448aa3586170ea826a GIT binary patch literal 1098 zcmV-Q1hxB#P)6WV~5P&ZND&mTYtcCCYlo!Qx?8Nj;r{|oRbB7;U zpz5R{tF{}dmQ@s?UCI8e4M^LMs^2qAKnZ&tP1;UWY}=;c zsIt$1x*Bp1Ewjb2>C;x>Hu${rHNs{$vEVapqJG}0?fU@$SSX}MqCK8BLz)0&44(FV zIg@_VkDpLXF@iZjK0E;wT6{^fIanm)8gXl!365~AfpZ8hZ^A00n?_<+y~#WPrp$&h z6A(`$>d|5K1yaFgC@yw6gbCZ#Qsh19R$xdy0eJL1YPoHp>c3X0QE-Ep)IAuJ^~;no2N3Y(zM3mZcEz3g9^wQ+~9)+Q$6Z z;!WqwfFQSaSWV^h3NYZRxi`*StqUovrQG@U)KF|k)X1Pp1l*~*<)9OJ^R0>{!bZadOZ36?U+=*zx9lm5;1B5H-uVi`J&$79wcq2UT( z68s}wAU;^EuAoMd`_YZNP%8Y7jb&ddPRZOyTUUiEr|-d&r05l3*_YaL`ZHYkb;jpb zXZQ0YuPw;$!fw$t0;41EI|%Bv1?KGFJuKTWNB6BkkmUm)QZ!uwe38!h=!k}udUwOL zt|O6$VLC2=9l4FG=5&qs9;iD{G#BaMm>N~Db{jaywz z&bp?zJh_g>vK7`acK!_{ziHx^%hXe(fv!;oD>DUfDl$@%-`C_g@~r0r*TTrbcTN Q&;S4c07*qoM6N<$g1%!J6#xJL literal 0 HcmV?d00001 diff --git a/src/web/img/connectors/legionscan b/src/web/img/connectors/legionscan new file mode 100644 index 0000000000000000000000000000000000000000..72bb76c50880a876e4d2da448aa3586170ea826a GIT binary patch literal 1098 zcmV-Q1hxB#P)6WV~5P&ZND&mTYtcCCYlo!Qx?8Nj;r{|oRbB7;U zpz5R{tF{}dmQ@s?UCI8e4M^LMs^2qAKnZ&tP1;UWY}=;c zsIt$1x*Bp1Ewjb2>C;x>Hu${rHNs{$vEVapqJG}0?fU@$SSX}MqCK8BLz)0&44(FV zIg@_VkDpLXF@iZjK0E;wT6{^fIanm)8gXl!365~AfpZ8hZ^A00n?_<+y~#WPrp$&h z6A(`$>d|5K1yaFgC@yw6gbCZ#Qsh19R$xdy0eJL1YPoHp>c3X0QE-Ep)IAuJ^~;no2N3Y(zM3mZcEz3g9^wQ+~9)+Q$6Z z;!WqwfFQSaSWV^h3NYZRxi`*StqUovrQG@U)KF|k)X1Pp1l*~*<)9OJ^R0>{!bZadOZ36?U+=*zx9lm5;1B5H-uVi`J&$79wcq2UT( z68s}wAU;^EuAoMd`_YZNP%8Y7jb&ddPRZOyTUUiEr|-d&r05l3*_YaL`ZHYkb;jpb zXZQ0YuPw;$!fw$t0;41EI|%Bv1?KGFJuKTWNB6BkkmUm)QZ!uwe38!h=!k}udUwOL zt|O6$VLC2=9l4FG=5&qs9;iD{G#BaMm>N~Db{jaywz z&bp?zJh_g>vK7`acK!_{ziHx^%hXe(fv!;oD>DUfDl$@%-`C_g@~r0r*TTrbcTN Q&;S4c07*qoM6N<$g1%!J6#xJL literal 0 HcmV?d00001 diff --git a/src/web/img/connectors/mangarolls b/src/web/img/connectors/mangarolls new file mode 100644 index 0000000000000000000000000000000000000000..72bb76c50880a876e4d2da448aa3586170ea826a GIT binary patch literal 1098 zcmV-Q1hxB#P)6WV~5P&ZND&mTYtcCCYlo!Qx?8Nj;r{|oRbB7;U zpz5R{tF{}dmQ@s?UCI8e4M^LMs^2qAKnZ&tP1;UWY}=;c zsIt$1x*Bp1Ewjb2>C;x>Hu${rHNs{$vEVapqJG}0?fU@$SSX}MqCK8BLz)0&44(FV zIg@_VkDpLXF@iZjK0E;wT6{^fIanm)8gXl!365~AfpZ8hZ^A00n?_<+y~#WPrp$&h z6A(`$>d|5K1yaFgC@yw6gbCZ#Qsh19R$xdy0eJL1YPoHp>c3X0QE-Ep)IAuJ^~;no2N3Y(zM3mZcEz3g9^wQ+~9)+Q$6Z z;!WqwfFQSaSWV^h3NYZRxi`*StqUovrQG@U)KF|k)X1Pp1l*~*<)9OJ^R0>{!bZadOZ36?U+=*zx9lm5;1B5H-uVi`J&$79wcq2UT( z68s}wAU;^EuAoMd`_YZNP%8Y7jb&ddPRZOyTUUiEr|-d&r05l3*_YaL`ZHYkb;jpb zXZQ0YuPw;$!fw$t0;41EI|%Bv1?KGFJuKTWNB6BkkmUm)QZ!uwe38!h=!k}udUwOL zt|O6$VLC2=9l4FG=5&qs9;iD{G#BaMm>N~Db{jaywz z&bp?zJh_g>vK7`acK!_{ziHx^%hXe(fv!;oD>DUfDl$@%-`C_g@~r0r*TTrbcTN Q&;S4c07*qoM6N<$g1%!J6#xJL literal 0 HcmV?d00001 diff --git a/src/web/img/connectors/manhatic b/src/web/img/connectors/manhatic new file mode 100644 index 0000000000000000000000000000000000000000..72bb76c50880a876e4d2da448aa3586170ea826a GIT binary patch literal 1098 zcmV-Q1hxB#P)6WV~5P&ZND&mTYtcCCYlo!Qx?8Nj;r{|oRbB7;U zpz5R{tF{}dmQ@s?UCI8e4M^LMs^2qAKnZ&tP1;UWY}=;c zsIt$1x*Bp1Ewjb2>C;x>Hu${rHNs{$vEVapqJG}0?fU@$SSX}MqCK8BLz)0&44(FV zIg@_VkDpLXF@iZjK0E;wT6{^fIanm)8gXl!365~AfpZ8hZ^A00n?_<+y~#WPrp$&h z6A(`$>d|5K1yaFgC@yw6gbCZ#Qsh19R$xdy0eJL1YPoHp>c3X0QE-Ep)IAuJ^~;no2N3Y(zM3mZcEz3g9^wQ+~9)+Q$6Z z;!WqwfFQSaSWV^h3NYZRxi`*StqUovrQG@U)KF|k)X1Pp1l*~*<)9OJ^R0>{!bZadOZ36?U+=*zx9lm5;1B5H-uVi`J&$79wcq2UT( z68s}wAU;^EuAoMd`_YZNP%8Y7jb&ddPRZOyTUUiEr|-d&r05l3*_YaL`ZHYkb;jpb zXZQ0YuPw;$!fw$t0;41EI|%Bv1?KGFJuKTWNB6BkkmUm)QZ!uwe38!h=!k}udUwOL zt|O6$VLC2=9l4FG=5&qs9;iD{G#BaMm>N~Db{jaywz z&bp?zJh_g>vK7`acK!_{ziHx^%hXe(fv!;oD>DUfDl$@%-`C_g@~r0r*TTrbcTN Q&;S4c07*qoM6N<$g1%!J6#xJL literal 0 HcmV?d00001 From 19ef4000896250d2a715be3037acfe3d334a7129 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 20:04:37 +0100 Subject: [PATCH 21/64] Fix another class --- src/web/mjs/connectors/Akumanotenshi.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/Akumanotenshi.mjs b/src/web/mjs/connectors/Akumanotenshi.mjs index b1349782f82..a5c92cfe33d 100644 --- a/src/web/mjs/connectors/Akumanotenshi.mjs +++ b/src/web/mjs/connectors/Akumanotenshi.mjs @@ -1,6 +1,6 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; -export default class KawaScans extends WordPressMadara { +export default class AkumanoTenshi extends WordPressMadara { constructor() { super(); @@ -9,4 +9,4 @@ export default class KawaScans extends WordPressMadara { this.tags = [ 'webtoon', 'manga', 'portuguese' ]; this.url = 'https://akumanotenshi.com'; } -} \ No newline at end of file +} From d54ca1b1320c6ac3e2cf3ab6395a2699daddb8c9 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 20:06:21 +0100 Subject: [PATCH 22/64] fix id case --- src/web/mjs/connectors/OmegaScans.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/OmegaScans.mjs b/src/web/mjs/connectors/OmegaScans.mjs index 8695f3be0bc..ae001b0396a 100644 --- a/src/web/mjs/connectors/OmegaScans.mjs +++ b/src/web/mjs/connectors/OmegaScans.mjs @@ -4,10 +4,10 @@ export default class OmegaScans extends WordPressMangastream { constructor() { super(); - super.id = 'OmegaScans'; + super.id = 'omegascans'; super.label = 'OmegaScans'; this.tags = [ 'webtoon', 'scanlation', 'english', 'hentai']; this.url = 'https://omegascans.org'; this.path = '/manga/list-mode/'; } -} \ No newline at end of file +} From 82c7960ef57c89280d44483f3d3ac8564dd7a511 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 21:58:59 +0100 Subject: [PATCH 23/64] Add MangaHereToday --- src/web/mjs/connectors/MangaHereToday.mjs | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/web/mjs/connectors/MangaHereToday.mjs diff --git a/src/web/mjs/connectors/MangaHereToday.mjs b/src/web/mjs/connectors/MangaHereToday.mjs new file mode 100644 index 00000000000..e8aa95eff7a --- /dev/null +++ b/src/web/mjs/connectors/MangaHereToday.mjs @@ -0,0 +1,27 @@ +import AnyACG from './templates/AnyACG.mjs'; +import Manga from '../engine/Manga.mjs'; + +export default class MangaHereToday extends AnyACG { + constructor() { + super(); + super.id = 'mangaheretoday'; + super.label = 'MangaHereToday'; + this.tags = [ 'manga', 'english' ]; + this.url = 'http://mangahere.today'; + this.queryMangas = 'div.row div.media-body'; + this.queryMangaLink = 'a'; + this.queryChapters = 'div.total-chapter:nth-of-type(4) h4 a'; + this.queryPages = 'div.chapter-content-inner p#arraydata'; + this.queryMangaTitle = 'div.media-body'; + this.queryMangaTitleText = 'h1.title-manga'; + } + async _getMangaFromURI(uri) { + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangaTitle); + let id = uri.pathname + uri.search; + //HACK We need to remove trailing "Manga" from the title + let r = new RegExp(' Manga$') + let title = data[0].querySelector(this.queryMangaTitleText).textContent.replace(r, '').trim(); + return new Manga(this, id, title); + } +} \ No newline at end of file From d2e47ba9eb6b3ab477fc4a57506aaccd8bdaf36d Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 22:00:24 +0100 Subject: [PATCH 24/64] Mangaheretoday icon --- src/web/img/connectors/mangaheretoday | Bin 0 -> 1098 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/mangaheretoday diff --git a/src/web/img/connectors/mangaheretoday b/src/web/img/connectors/mangaheretoday new file mode 100644 index 0000000000000000000000000000000000000000..72bb76c50880a876e4d2da448aa3586170ea826a GIT binary patch literal 1098 zcmV-Q1hxB#P)6WV~5P&ZND&mTYtcCCYlo!Qx?8Nj;r{|oRbB7;U zpz5R{tF{}dmQ@s?UCI8e4M^LMs^2qAKnZ&tP1;UWY}=;c zsIt$1x*Bp1Ewjb2>C;x>Hu${rHNs{$vEVapqJG}0?fU@$SSX}MqCK8BLz)0&44(FV zIg@_VkDpLXF@iZjK0E;wT6{^fIanm)8gXl!365~AfpZ8hZ^A00n?_<+y~#WPrp$&h z6A(`$>d|5K1yaFgC@yw6gbCZ#Qsh19R$xdy0eJL1YPoHp>c3X0QE-Ep)IAuJ^~;no2N3Y(zM3mZcEz3g9^wQ+~9)+Q$6Z z;!WqwfFQSaSWV^h3NYZRxi`*StqUovrQG@U)KF|k)X1Pp1l*~*<)9OJ^R0>{!bZadOZ36?U+=*zx9lm5;1B5H-uVi`J&$79wcq2UT( z68s}wAU;^EuAoMd`_YZNP%8Y7jb&ddPRZOyTUUiEr|-d&r05l3*_YaL`ZHYkb;jpb zXZQ0YuPw;$!fw$t0;41EI|%Bv1?KGFJuKTWNB6BkkmUm)QZ!uwe38!h=!k}udUwOL zt|O6$VLC2=9l4FG=5&qs9;iD{G#BaMm>N~Db{jaywz z&bp?zJh_g>vK7`acK!_{ziHx^%hXe(fv!;oD>DUfDl$@%-`C_g@~r0r*TTrbcTN Q&;S4c07*qoM6N<$g1%!J6#xJL literal 0 HcmV?d00001 From dcfaf228096e39c7d3b07f0644a23c321c918de3 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 22:13:46 +0100 Subject: [PATCH 25/64] MangafoxFull icon --- src/web/img/connectors/mangafoxfull | Bin 0 -> 13890 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/mangafoxfull diff --git a/src/web/img/connectors/mangafoxfull b/src/web/img/connectors/mangafoxfull new file mode 100644 index 0000000000000000000000000000000000000000..01c4c2b091a41d8011db1bd0b7314f97cf40196a GIT binary patch literal 13890 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 QkpKVy07*qoM6N<$f Date: Sat, 12 Nov 2022 22:14:38 +0100 Subject: [PATCH 26/64] Add MangaFoxFull connector --- src/web/mjs/connectors/MangaFoxFull.mjs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/web/mjs/connectors/MangaFoxFull.mjs diff --git a/src/web/mjs/connectors/MangaFoxFull.mjs b/src/web/mjs/connectors/MangaFoxFull.mjs new file mode 100644 index 00000000000..c0c4c2a374d --- /dev/null +++ b/src/web/mjs/connectors/MangaFoxFull.mjs @@ -0,0 +1,13 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; + +export default class MangaFoxFull extends WordPressMadara { + + constructor() { + super(); + super.id = 'mangafoxfull'; + super.label = 'MangaFoxFull'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://mangafoxfull.com'; + this.requestOptions.headers.set('x-referer', this.url); + } +} \ No newline at end of file From aeabc6f2454fc617f17fd153d76215fd91305f99 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 22:31:14 +0100 Subject: [PATCH 27/64] Add MadaraDex connector --- src/web/mjs/connectors/MadaraDex.mjs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/web/mjs/connectors/MadaraDex.mjs diff --git a/src/web/mjs/connectors/MadaraDex.mjs b/src/web/mjs/connectors/MadaraDex.mjs new file mode 100644 index 00000000000..46eea0bb594 --- /dev/null +++ b/src/web/mjs/connectors/MadaraDex.mjs @@ -0,0 +1,19 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; +export default class MadaraDex extends WordPressMadara { + constructor() { + super(); + super.id = 'madaradex'; + super.label = 'MadaraDex'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://madaradex.org'; + } + async _handleConnectorURI(payload) { + this.requestOptions.headers.set('x-referer', this.url); + let request = new Request(payload.url, this.requestOptions); + let response = await fetch(request); + let data = await response.blob(); + data = await this._blobToBuffer(data); + this._applyRealMime(data); + return data; + } +} \ No newline at end of file From 84bd7552f747204dfd664123e5dd2f3c35814869 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 22:31:57 +0100 Subject: [PATCH 28/64] Add madaradex icon --- src/web/img/connectors/madaradex | Bin 0 -> 1098 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/madaradex diff --git a/src/web/img/connectors/madaradex b/src/web/img/connectors/madaradex new file mode 100644 index 0000000000000000000000000000000000000000..72bb76c50880a876e4d2da448aa3586170ea826a GIT binary patch literal 1098 zcmV-Q1hxB#P)6WV~5P&ZND&mTYtcCCYlo!Qx?8Nj;r{|oRbB7;U zpz5R{tF{}dmQ@s?UCI8e4M^LMs^2qAKnZ&tP1;UWY}=;c zsIt$1x*Bp1Ewjb2>C;x>Hu${rHNs{$vEVapqJG}0?fU@$SSX}MqCK8BLz)0&44(FV zIg@_VkDpLXF@iZjK0E;wT6{^fIanm)8gXl!365~AfpZ8hZ^A00n?_<+y~#WPrp$&h z6A(`$>d|5K1yaFgC@yw6gbCZ#Qsh19R$xdy0eJL1YPoHp>c3X0QE-Ep)IAuJ^~;no2N3Y(zM3mZcEz3g9^wQ+~9)+Q$6Z z;!WqwfFQSaSWV^h3NYZRxi`*StqUovrQG@U)KF|k)X1Pp1l*~*<)9OJ^R0>{!bZadOZ36?U+=*zx9lm5;1B5H-uVi`J&$79wcq2UT( z68s}wAU;^EuAoMd`_YZNP%8Y7jb&ddPRZOyTUUiEr|-d&r05l3*_YaL`ZHYkb;jpb zXZQ0YuPw;$!fw$t0;41EI|%Bv1?KGFJuKTWNB6BkkmUm)QZ!uwe38!h=!k}udUwOL zt|O6$VLC2=9l4FG=5&qs9;iD{G#BaMm>N~Db{jaywz z&bp?zJh_g>vK7`acK!_{ziHx^%hXe(fv!;oD>DUfDl$@%-`C_g@~r0r*TTrbcTN Q&;S4c07*qoM6N<$g1%!J6#xJL literal 0 HcmV?d00001 From 9b01bc2bd941ed5216be64eec7bbe5e97eae2592 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 22:39:15 +0100 Subject: [PATCH 29/64] Add MangaChill connector --- src/web/mjs/connectors/MangaChill.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/web/mjs/connectors/MangaChill.mjs diff --git a/src/web/mjs/connectors/MangaChill.mjs b/src/web/mjs/connectors/MangaChill.mjs new file mode 100644 index 00000000000..129a4c36475 --- /dev/null +++ b/src/web/mjs/connectors/MangaChill.mjs @@ -0,0 +1,10 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; +export default class MangaChill extends WordPressMadara { + constructor() { + super(); + super.id = 'mangachill'; + super.label = 'MangaChill'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://mangachill.io'; + } +} \ No newline at end of file From d30bf7779cc8631316bcfe65e7915eb5c6e8d687 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 22:40:39 +0100 Subject: [PATCH 30/64] Mangachill icon --- src/web/img/connectors/mangachill | Bin 0 -> 1098 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/mangachill diff --git a/src/web/img/connectors/mangachill b/src/web/img/connectors/mangachill new file mode 100644 index 0000000000000000000000000000000000000000..72bb76c50880a876e4d2da448aa3586170ea826a GIT binary patch literal 1098 zcmV-Q1hxB#P)6WV~5P&ZND&mTYtcCCYlo!Qx?8Nj;r{|oRbB7;U zpz5R{tF{}dmQ@s?UCI8e4M^LMs^2qAKnZ&tP1;UWY}=;c zsIt$1x*Bp1Ewjb2>C;x>Hu${rHNs{$vEVapqJG}0?fU@$SSX}MqCK8BLz)0&44(FV zIg@_VkDpLXF@iZjK0E;wT6{^fIanm)8gXl!365~AfpZ8hZ^A00n?_<+y~#WPrp$&h z6A(`$>d|5K1yaFgC@yw6gbCZ#Qsh19R$xdy0eJL1YPoHp>c3X0QE-Ep)IAuJ^~;no2N3Y(zM3mZcEz3g9^wQ+~9)+Q$6Z z;!WqwfFQSaSWV^h3NYZRxi`*StqUovrQG@U)KF|k)X1Pp1l*~*<)9OJ^R0>{!bZadOZ36?U+=*zx9lm5;1B5H-uVi`J&$79wcq2UT( z68s}wAU;^EuAoMd`_YZNP%8Y7jb&ddPRZOyTUUiEr|-d&r05l3*_YaL`ZHYkb;jpb zXZQ0YuPw;$!fw$t0;41EI|%Bv1?KGFJuKTWNB6BkkmUm)QZ!uwe38!h=!k}udUwOL zt|O6$VLC2=9l4FG=5&qs9;iD{G#BaMm>N~Db{jaywz z&bp?zJh_g>vK7`acK!_{ziHx^%hXe(fv!;oD>DUfDl$@%-`C_g@~r0r*TTrbcTN Q&;S4c07*qoM6N<$g1%!J6#xJL literal 0 HcmV?d00001 From 7e3c59d53fc3ca97d8664d5613c46d2bf15aeb9c Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 23:24:59 +0100 Subject: [PATCH 31/64] Add Webcomic.me connector --- src/web/mjs/connectors/Webcomicme.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/web/mjs/connectors/Webcomicme.mjs diff --git a/src/web/mjs/connectors/Webcomicme.mjs b/src/web/mjs/connectors/Webcomicme.mjs new file mode 100644 index 00000000000..6f19fcd1fd7 --- /dev/null +++ b/src/web/mjs/connectors/Webcomicme.mjs @@ -0,0 +1,10 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; +export default class MangaChill extends WordPressMadara { + constructor() { + super(); + super.id = 'webcomicme'; + super.label = 'WebComic (Webcomic.me)'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://webcomic.me'; + } +} \ No newline at end of file From 96ba14819df840c982400f936379b6dcd14dcc0a Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 23:25:33 +0100 Subject: [PATCH 32/64] Add webcomicme icon --- src/web/img/connectors/webcomicme | Bin 0 -> 1098 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/webcomicme diff --git a/src/web/img/connectors/webcomicme b/src/web/img/connectors/webcomicme new file mode 100644 index 0000000000000000000000000000000000000000..72bb76c50880a876e4d2da448aa3586170ea826a GIT binary patch literal 1098 zcmV-Q1hxB#P)6WV~5P&ZND&mTYtcCCYlo!Qx?8Nj;r{|oRbB7;U zpz5R{tF{}dmQ@s?UCI8e4M^LMs^2qAKnZ&tP1;UWY}=;c zsIt$1x*Bp1Ewjb2>C;x>Hu${rHNs{$vEVapqJG}0?fU@$SSX}MqCK8BLz)0&44(FV zIg@_VkDpLXF@iZjK0E;wT6{^fIanm)8gXl!365~AfpZ8hZ^A00n?_<+y~#WPrp$&h z6A(`$>d|5K1yaFgC@yw6gbCZ#Qsh19R$xdy0eJL1YPoHp>c3X0QE-Ep)IAuJ^~;no2N3Y(zM3mZcEz3g9^wQ+~9)+Q$6Z z;!WqwfFQSaSWV^h3NYZRxi`*StqUovrQG@U)KF|k)X1Pp1l*~*<)9OJ^R0>{!bZadOZ36?U+=*zx9lm5;1B5H-uVi`J&$79wcq2UT( z68s}wAU;^EuAoMd`_YZNP%8Y7jb&ddPRZOyTUUiEr|-d&r05l3*_YaL`ZHYkb;jpb zXZQ0YuPw;$!fw$t0;41EI|%Bv1?KGFJuKTWNB6BkkmUm)QZ!uwe38!h=!k}udUwOL zt|O6$VLC2=9l4FG=5&qs9;iD{G#BaMm>N~Db{jaywz z&bp?zJh_g>vK7`acK!_{ziHx^%hXe(fv!;oD>DUfDl$@%-`C_g@~r0r*TTrbcTN Q&;S4c07*qoM6N<$g1%!J6#xJL literal 0 HcmV?d00001 From d63db43e024404bdf17c75a37ca98b8921015af0 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 23:31:06 +0100 Subject: [PATCH 33/64] Add ManhuaDragon connector --- src/web/mjs/connectors/ManhuaDragon.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/web/mjs/connectors/ManhuaDragon.mjs diff --git a/src/web/mjs/connectors/ManhuaDragon.mjs b/src/web/mjs/connectors/ManhuaDragon.mjs new file mode 100644 index 00000000000..614b8773854 --- /dev/null +++ b/src/web/mjs/connectors/ManhuaDragon.mjs @@ -0,0 +1,10 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; +export default class ManhuaDragon extends WordPressMadara { + constructor() { + super(); + super.id = 'manhuadragon'; + super.label = 'ManhuaDragon'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://manhuadragon.com'; + } +} \ No newline at end of file From 14a26e4d7c0f88406fee476c27aef21940810485 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 23:32:25 +0100 Subject: [PATCH 34/64] Add Manhuadragon icon --- src/web/img/connectors/manhuadragon | Bin 0 -> 9064 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/manhuadragon diff --git a/src/web/img/connectors/manhuadragon b/src/web/img/connectors/manhuadragon new file mode 100644 index 0000000000000000000000000000000000000000..c94e64b0db909a128eca405b9ef486e68bf7b61a GIT binary patch literal 9064 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 literal 0 HcmV?d00001 From 036d90b728f936eb83cc98a33ae35d382365bff1 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 23:37:29 +0100 Subject: [PATCH 35/64] Add painfulnightz connector --- src/web/mjs/connectors/PainfulNightz.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/web/mjs/connectors/PainfulNightz.mjs diff --git a/src/web/mjs/connectors/PainfulNightz.mjs b/src/web/mjs/connectors/PainfulNightz.mjs new file mode 100644 index 00000000000..956e50daf3f --- /dev/null +++ b/src/web/mjs/connectors/PainfulNightz.mjs @@ -0,0 +1,10 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; +export default class PainfulNightz extends WordPressMadara { + constructor() { + super(); + super.id = 'painfulnightz'; + super.label = 'PainfulNightz'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://painfulnightz.com'; + } +} \ No newline at end of file From 0c02dfc2eb9614df883877e038204ca01555251c Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 23:37:59 +0100 Subject: [PATCH 36/64] Add painfulnightz icon --- src/web/img/connectors/painfulnightz | Bin 0 -> 7497 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/painfulnightz diff --git a/src/web/img/connectors/painfulnightz b/src/web/img/connectors/painfulnightz new file mode 100644 index 0000000000000000000000000000000000000000..2152798026b242a0e671a3d553ce801234a86714 GIT binary patch literal 7497 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 TQatck00000NkvXXu0mjfPET`r literal 0 HcmV?d00001 From e9bd54d5807a50c7966c74ef62fcf46652a5bac0 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 23:44:17 +0100 Subject: [PATCH 37/64] Add Manga1st connector --- src/web/mjs/connectors/Manga1st.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/web/mjs/connectors/Manga1st.mjs diff --git a/src/web/mjs/connectors/Manga1st.mjs b/src/web/mjs/connectors/Manga1st.mjs new file mode 100644 index 00000000000..e56bee656ba --- /dev/null +++ b/src/web/mjs/connectors/Manga1st.mjs @@ -0,0 +1,10 @@ +import WordPressMadara from './templates/WordPressMadara.mjs'; +export default class Manga1st extends WordPressMadara { + constructor() { + super(); + super.id = 'manga1st'; + super.label = 'Manga1st'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://manga1st.com'; + } +} \ No newline at end of file From f39a7729c0c4c107441f422a9d94d83361e1f24a Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 12 Nov 2022 23:44:59 +0100 Subject: [PATCH 38/64] Add Manga1st icon --- src/web/img/connectors/manga1st | Bin 0 -> 7985 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/manga1st diff --git a/src/web/img/connectors/manga1st b/src/web/img/connectors/manga1st new file mode 100644 index 0000000000000000000000000000000000000000..cc00792b67fe69603efec8f3f4b0f2575c19b634 GIT binary patch literal 7985 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 tL9$O9@Ff5Lo8 Date: Sun, 13 Nov 2022 13:12:00 +0100 Subject: [PATCH 39/64] Add icons for pururin and beautymanga --- src/web/img/connectors/beautymanga | Bin 0 -> 1098 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/web/img/connectors/beautymanga diff --git a/src/web/img/connectors/beautymanga b/src/web/img/connectors/beautymanga new file mode 100644 index 0000000000000000000000000000000000000000..72bb76c50880a876e4d2da448aa3586170ea826a GIT binary patch literal 1098 zcmV-Q1hxB#P)6WV~5P&ZND&mTYtcCCYlo!Qx?8Nj;r{|oRbB7;U zpz5R{tF{}dmQ@s?UCI8e4M^LMs^2qAKnZ&tP1;UWY}=;c zsIt$1x*Bp1Ewjb2>C;x>Hu${rHNs{$vEVapqJG}0?fU@$SSX}MqCK8BLz)0&44(FV zIg@_VkDpLXF@iZjK0E;wT6{^fIanm)8gXl!365~AfpZ8hZ^A00n?_<+y~#WPrp$&h z6A(`$>d|5K1yaFgC@yw6gbCZ#Qsh19R$xdy0eJL1YPoHp>c3X0QE-Ep)IAuJ^~;no2N3Y(zM3mZcEz3g9^wQ+~9)+Q$6Z z;!WqwfFQSaSWV^h3NYZRxi`*StqUovrQG@U)KF|k)X1Pp1l*~*<)9OJ^R0>{!bZadOZ36?U+=*zx9lm5;1B5H-uVi`J&$79wcq2UT( z68s}wAU;^EuAoMd`_YZNP%8Y7jb&ddPRZOyTUUiEr|-d&r05l3*_YaL`ZHYkb;jpb zXZQ0YuPw;$!fw$t0;41EI|%Bv1?KGFJuKTWNB6BkkmUm)QZ!uwe38!h=!k}udUwOL zt|O6$VLC2=9l4FG=5&qs9;iD{G#BaMm>N~Db{jaywz z&bp?zJh_g>vK7`acK!_{ziHx^%hXe(fv!;oD>DUfDl$@%-`C_g@~r0r*TTrbcTN Q&;S4c07*qoM6N<$g1%!J6#xJL literal 0 HcmV?d00001 From 409a8f6bf0e38d4997671b77b2d815247324f8ed Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sun, 13 Nov 2022 13:58:49 +0100 Subject: [PATCH 40/64] Lint Fix attempt 1 --- src/web/mjs/connectors/BeautyManga.mjs | 85 +++++----- src/web/mjs/connectors/MadaraDex.mjs | 32 ++-- src/web/mjs/connectors/Manga1st.mjs | 14 +- src/web/mjs/connectors/MangaChill.mjs | 14 +- src/web/mjs/connectors/MangaFoxFull.mjs | 18 +-- src/web/mjs/connectors/MangaHereToday.mjs | 44 ++--- src/web/mjs/connectors/ManhuaDragon.mjs | 14 +- src/web/mjs/connectors/PainfulNightz.mjs | 14 +- src/web/mjs/connectors/Pururin.mjs | 188 +++++++++++----------- src/web/mjs/connectors/Webcomicme.mjs | 14 +- 10 files changed, 215 insertions(+), 222 deletions(-) diff --git a/src/web/mjs/connectors/BeautyManga.mjs b/src/web/mjs/connectors/BeautyManga.mjs index b25e27bf3b2..5a7f991c2e6 100644 --- a/src/web/mjs/connectors/BeautyManga.mjs +++ b/src/web/mjs/connectors/BeautyManga.mjs @@ -1,5 +1,4 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; - export default class BeautyManga extends WordPressMadara { constructor() { super(); @@ -14,48 +13,44 @@ export default class BeautyManga extends WordPressMadara { this.queryPages = 'p#arraydata'; this.mangaTitleFilter = ''; } - async _getMangasFromPage(page) { - let uri = new URL(this.path + this.pathMangas.replace('%PAGE%', page), this.url); - uri.pathname = uri.pathname.replace(/\/+/g, '/'); - let request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryMangas); - return data.map(element => { - return { - id: new URL(element.href, request.url).pathname, - title: element.title.replace(this.mangaTitleFilter, '').trim() - }; - }); - } - - async _getChaptersAjaxOld(mangaID) { - const uri = new URL('/ajax-list-chapter?mangaID='+mangaID , this.url); - const request = new Request(uri, { - method: 'GET' - }); - const data = await this.fetchDOM(request, this.queryChapters); - if (data.length) { - return data; - } - else { - throw new Error('No chapters found (new ajax endpoint)!'); - } - } - - async _getPages(chapter) - { - let uri = new URL(chapter.id, this.url); - let request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryPages); - let el = data[0].innerText.split(','); - return el.map(element => - { - const uri = new URL(this.getAbsolutePath(element, request.url)); - return this.createConnectorURI({ - // HACK: bypass 'i0.wp.com' image CDN to ensure original images are loaded directly from host - url: uri.href.replace(/\/i\d+\.wp\.com/, ''), - referer: uri.origin - }) - }); - } -} + let uri = new URL(this.path + this.pathMangas.replace('%PAGE%', page), this.url); + uri.pathname = uri.pathname.replace(/\/+/g, '/'); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangas); + return data.map(element => { + return { + id: new URL(element.href, request.url).pathname, + title: element.title.replace(this.mangaTitleFilter, '').trim() + }; + }); + } + async _getChaptersAjaxOld(mangaID) { + const uri = new URL('/ajax-list-chapter?mangaID='+mangaID , this.url); + const request = new Request(uri, { + method: 'GET' + }); + const data = await this.fetchDOM(request, this.queryChapters); + if (data.length) { + return data; + } + else { + throw new Error('No chapters found (new ajax endpoint)!'); + } + } + async _getPages(chapter) + { + let uri = new URL(chapter.id, this.url); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryPages); + let el = data[0].innerText.split(','); + return el.map(element => + { + const uri = new URL(this.getAbsolutePath(element, request.url)); + return this.createConnectorURI({ + url: uri.href, + referer: uri.origin + }) + }); + } +} \ No newline at end of file diff --git a/src/web/mjs/connectors/MadaraDex.mjs b/src/web/mjs/connectors/MadaraDex.mjs index 46eea0bb594..883cec98195 100644 --- a/src/web/mjs/connectors/MadaraDex.mjs +++ b/src/web/mjs/connectors/MadaraDex.mjs @@ -1,19 +1,19 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; export default class MadaraDex extends WordPressMadara { - constructor() { - super(); - super.id = 'madaradex'; - super.label = 'MadaraDex'; - this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://madaradex.org'; - } - async _handleConnectorURI(payload) { - this.requestOptions.headers.set('x-referer', this.url); - let request = new Request(payload.url, this.requestOptions); - let response = await fetch(request); - let data = await response.blob(); - data = await this._blobToBuffer(data); - this._applyRealMime(data); - return data; - } + constructor() { + super(); + super.id = 'madaradex'; + super.label = 'MadaraDex'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://madaradex.org'; + } + async _handleConnectorURI(payload) { + this.requestOptions.headers.set('x-referer', this.url); + let request = new Request(payload.url, this.requestOptions); + let response = await fetch(request); + let data = await response.blob(); + data = await this._blobToBuffer(data); + this._applyRealMime(data); + return data; + } } \ No newline at end of file diff --git a/src/web/mjs/connectors/Manga1st.mjs b/src/web/mjs/connectors/Manga1st.mjs index e56bee656ba..32e16918465 100644 --- a/src/web/mjs/connectors/Manga1st.mjs +++ b/src/web/mjs/connectors/Manga1st.mjs @@ -1,10 +1,10 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; export default class Manga1st extends WordPressMadara { - constructor() { - super(); - super.id = 'manga1st'; - super.label = 'Manga1st'; - this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://manga1st.com'; - } + constructor() { + super(); + super.id = 'manga1st'; + super.label = 'Manga1st'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://manga1st.com'; + } } \ No newline at end of file diff --git a/src/web/mjs/connectors/MangaChill.mjs b/src/web/mjs/connectors/MangaChill.mjs index 129a4c36475..047fcd73abd 100644 --- a/src/web/mjs/connectors/MangaChill.mjs +++ b/src/web/mjs/connectors/MangaChill.mjs @@ -1,10 +1,10 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; export default class MangaChill extends WordPressMadara { - constructor() { - super(); - super.id = 'mangachill'; - super.label = 'MangaChill'; - this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://mangachill.io'; - } + constructor() { + super(); + super.id = 'mangachill'; + super.label = 'MangaChill'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://mangachill.io'; + } } \ No newline at end of file diff --git a/src/web/mjs/connectors/MangaFoxFull.mjs b/src/web/mjs/connectors/MangaFoxFull.mjs index c0c4c2a374d..11300b96c47 100644 --- a/src/web/mjs/connectors/MangaFoxFull.mjs +++ b/src/web/mjs/connectors/MangaFoxFull.mjs @@ -1,13 +1,11 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; - export default class MangaFoxFull extends WordPressMadara { - - constructor() { - super(); - super.id = 'mangafoxfull'; - super.label = 'MangaFoxFull'; - this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://mangafoxfull.com'; - this.requestOptions.headers.set('x-referer', this.url); - } + constructor() { + super(); + super.id = 'mangafoxfull'; + super.label = 'MangaFoxFull'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://mangafoxfull.com'; + this.requestOptions.headers.set('x-referer', this.url); + } } \ No newline at end of file diff --git a/src/web/mjs/connectors/MangaHereToday.mjs b/src/web/mjs/connectors/MangaHereToday.mjs index e8aa95eff7a..dc216431632 100644 --- a/src/web/mjs/connectors/MangaHereToday.mjs +++ b/src/web/mjs/connectors/MangaHereToday.mjs @@ -2,26 +2,26 @@ import AnyACG from './templates/AnyACG.mjs'; import Manga from '../engine/Manga.mjs'; export default class MangaHereToday extends AnyACG { - constructor() { - super(); - super.id = 'mangaheretoday'; - super.label = 'MangaHereToday'; - this.tags = [ 'manga', 'english' ]; - this.url = 'http://mangahere.today'; - this.queryMangas = 'div.row div.media-body'; - this.queryMangaLink = 'a'; - this.queryChapters = 'div.total-chapter:nth-of-type(4) h4 a'; - this.queryPages = 'div.chapter-content-inner p#arraydata'; - this.queryMangaTitle = 'div.media-body'; - this.queryMangaTitleText = 'h1.title-manga'; - } - async _getMangaFromURI(uri) { - let request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryMangaTitle); - let id = uri.pathname + uri.search; - //HACK We need to remove trailing "Manga" from the title - let r = new RegExp(' Manga$') - let title = data[0].querySelector(this.queryMangaTitleText).textContent.replace(r, '').trim(); - return new Manga(this, id, title); - } + constructor() { + super(); + super.id = 'mangaheretoday'; + super.label = 'MangaHereToday'; + this.tags = [ 'manga', 'english' ]; + this.url = 'http://mangahere.today'; + this.queryMangas = 'div.row div.media-body'; + this.queryMangaLink = 'a'; + this.queryChapters = 'div.total-chapter:nth-of-type(4) h4 a'; + this.queryPages = 'div.chapter-content-inner p#arraydata'; + this.queryMangaTitle = 'div.media-body'; + this.queryMangaTitleText = 'h1.title-manga'; + } + async _getMangaFromURI(uri) { + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangaTitle); + let id = uri.pathname + uri.search; + //HACK We need to remove trailing "Manga" from the title + let r = new RegExp(' Manga$'); + let title = data[0].querySelector(this.queryMangaTitleText).textContent.replace(r, '').trim(); + return new Manga(this, id, title); + } } \ No newline at end of file diff --git a/src/web/mjs/connectors/ManhuaDragon.mjs b/src/web/mjs/connectors/ManhuaDragon.mjs index 614b8773854..71f9b9ed2d2 100644 --- a/src/web/mjs/connectors/ManhuaDragon.mjs +++ b/src/web/mjs/connectors/ManhuaDragon.mjs @@ -1,10 +1,10 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; export default class ManhuaDragon extends WordPressMadara { - constructor() { - super(); - super.id = 'manhuadragon'; - super.label = 'ManhuaDragon'; - this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://manhuadragon.com'; - } + constructor() { + super(); + super.id = 'manhuadragon'; + super.label = 'ManhuaDragon'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://manhuadragon.com'; + } } \ No newline at end of file diff --git a/src/web/mjs/connectors/PainfulNightz.mjs b/src/web/mjs/connectors/PainfulNightz.mjs index 956e50daf3f..f3143a40ef6 100644 --- a/src/web/mjs/connectors/PainfulNightz.mjs +++ b/src/web/mjs/connectors/PainfulNightz.mjs @@ -1,10 +1,10 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; export default class PainfulNightz extends WordPressMadara { - constructor() { - super(); - super.id = 'painfulnightz'; - super.label = 'PainfulNightz'; - this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://painfulnightz.com'; - } + constructor() { + super(); + super.id = 'painfulnightz'; + super.label = 'PainfulNightz'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://painfulnightz.com'; + } } \ No newline at end of file diff --git a/src/web/mjs/connectors/Pururin.mjs b/src/web/mjs/connectors/Pururin.mjs index b1763bcdb6b..50515202a60 100644 --- a/src/web/mjs/connectors/Pururin.mjs +++ b/src/web/mjs/connectors/Pururin.mjs @@ -1,97 +1,97 @@ import Connector from '../engine/Connector.mjs'; import Manga from '../engine/Manga.mjs'; export default class Pururin extends Connector { - constructor() { - super(); - super.id = 'pururin'; - super.label = 'Pururin'; - this.tags = ['manga', 'hentai', 'english']; - this.url = 'https://pururin.to'; - this.CDN = "https://cdn.pururin.to/assets/images/data/{1}/{2}.{3}"; - this.path = "/browse/title"; - this.api = "/api/contribute/gallery/info"; - this.queryMangasPageCount = 'ul.pagination.flex-wrap li:nth-last-of-type(2) a'; - this.queryMangas = 'a.card.card-gallery'; - this.queryChapters ='div.gallery-action a'; - this.requestOptions.headers.set('x-referer', this.url); - this.requestOptions.headers.set('x-origin', this.url); - } - async _getMangas() { - let mangaList = []; - const uri = new URL(this.path, this.url); - const request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryMangasPageCount); - let pageCount = parseInt(data[0].text); - for(let page = 1; page <= pageCount; page++) { - let mangas = await this._getMangasFromPage(page); - mangaList.push(...mangas); - } - return mangaList; - } - async _getMangasFromPage(page) { - let uri = new URL(this.path + '?page='+page, this.url); - let request = new Request(uri, this.requestOptions); - let data = await this.fetchDOM(request, this.queryMangas); - return data.map(element => { - return { - id: this.getRootRelativeOrAbsoluteLink(element, request.url), - title: element.querySelector('source.card-img-top').getAttribute('alt').trim() - }; - }); - } - async _getChapters(manga) { - let mid = this.getRootRelativeOrAbsoluteLink(manga.id, this.url); - const chapters = [{ id: mid , title: 'Chapter' }]; - return chapters; - } - async _getPages(chapter) { - let queryPicture = ''; - let pictures = []; - var myRegexp = new RegExp("gallery\/([0-9]+)", "g"); - var match = myRegexp.exec(chapter.id); - let mangaID = match[1]; - let params = '{"id":'+mangaID+',"type":2}'; - const uri = new URL(this.api, this.url); - const request = new Request(uri, { - method: 'POST', - body: params, - headers: { - 'x-origin': this.url, - 'x-referer': this.url, - 'Content-Type': 'application/json;charset=UTF-8', - 'X-Requested-With': 'XMLHttpRequest', - } - }) - const data = await this.fetchJSON(request); - let pagesMax = data.gallery.total_pages; - let extension = data.gallery.image_extension; - //https://cdn.pururin.to/assets/images/data//.image_extension - for (var i = 1; i <= pagesMax;i++) - { - let imageuri = this.CDN.replace('{1}', mangaID).replace('{2}', i).replace('{3}', extension); - pictures.push(imageuri); - } - return pictures; - } - async _getMangaFromURI(uri) { - var myRegexp = new RegExp("gallery\/([0-9]+)", "g"); - var match = myRegexp.exec(uri.href); - let mangaID = match[1]; - let params = '{"id":'+mangaID+',"type":2}'; - const req = new URL(this.api, this.url); - const request = new Request(req, { - method: 'POST', - body: params, - headers: { - 'x-origin': this.url, - 'x-referer': this.url, - 'Content-Type': 'application/json;charset=UTF-8', - 'X-Requested-With': 'XMLHttpRequest', - } - }) - const data = await this.fetchJSON(request); - const title = data.gallery.title; - const id = this.getRootRelativeOrAbsoluteLink(uri, this.url); - return new Manga(this, id, title); - } -} + constructor() { + super(); + super.id = 'pururin'; + super.label = 'Pururin'; + this.tags = ['manga', 'hentai', 'english']; + this.url = 'https://pururin.to'; + this.CDN = "https://cdn.pururin.to/assets/images/data/{1}/{2}.{3}"; + this.path = "/browse/title"; + this.api = "/api/contribute/gallery/info"; + this.queryMangasPageCount = 'ul.pagination.flex-wrap li:nth-last-of-type(2) a'; + this.queryMangas = 'a.card.card-gallery'; + this.queryChapters ='div.gallery-action a'; + this.requestOptions.headers.set('x-referer', this.url); + this.requestOptions.headers.set('x-origin', this.url); + } + async _getMangas() { + let mangaList = []; + const uri = new URL(this.path, this.url); + const request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangasPageCount); + let pageCount = parseInt(data[0].text); + for(let page = 1; page <= pageCount; page++) { + let mangas = await this._getMangasFromPage(page); + mangaList.push(...mangas); + } + return mangaList; + } + async _getMangasFromPage(page) { + let uri = new URL(this.path + '?page='+page, this.url); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangas); + return data.map(element => { + return { + id: this.getRootRelativeOrAbsoluteLink(element, request.url), + title: element.querySelector('source.card-img-top').getAttribute('alt').trim() + }; + }); + } + async _getChapters(manga) { + let mid = this.getRootRelativeOrAbsoluteLink(manga.id, this.url); + const chapters = [{ id: mid, title: 'Chapter' }]; + return chapters; + } + async _getPages(chapter) { + let queryPicture = ''; + let pictures = []; + var myRegexp = new RegExp("gallery\/([0-9]+)", "g"); + var match = myRegexp.exec(chapter.id); + let mangaID = match[1]; + let params = '{"id":'+mangaID+',"type":2}'; + const uri = new URL(this.api, this.url); + const request = new Request(uri, { + method: 'POST', + body: params, + headers: { + 'x-origin': this.url, + 'x-referer': this.url, + 'Content-Type': 'application/json;charset=UTF-8', + 'X-Requested-With': 'XMLHttpRequest', + } + }); + const data = await this.fetchJSON(request); + let pagesMax = data.gallery.total_pages; + let extension = data.gallery.image_extension; + //https://cdn.pururin.to/assets/images/data//.image_extension + for (var i = 1; i <= pagesMax; i++) + { + let imageuri = this.CDN.replace('{1}', mangaID).replace('{2}', i).replace('{3}', extension); + pictures.push(imageuri); + } + return pictures; + } + async _getMangaFromURI(uri) { + var myRegexp = new RegExp("gallery\/([0-9]+)", "g"); + var match = myRegexp.exec(uri.href); + let mangaID = match[1]; + let params = '{"id":'+mangaID+',"type":2}'; + const req = new URL(this.api, this.url); + const request = new Request(req, { + method: 'POST', + body: params, + headers: { + 'x-origin': this.url, + 'x-referer': this.url, + 'Content-Type': 'application/json;charset=UTF-8', + 'X-Requested-With': 'XMLHttpRequest', + } + }); + const data = await this.fetchJSON(request); + const title = data.gallery.title; + const id = this.getRootRelativeOrAbsoluteLink(uri, this.url); + return new Manga(this, id, title); + } +} \ No newline at end of file diff --git a/src/web/mjs/connectors/Webcomicme.mjs b/src/web/mjs/connectors/Webcomicme.mjs index 6f19fcd1fd7..74bc44df8c4 100644 --- a/src/web/mjs/connectors/Webcomicme.mjs +++ b/src/web/mjs/connectors/Webcomicme.mjs @@ -1,10 +1,10 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; export default class MangaChill extends WordPressMadara { - constructor() { - super(); - super.id = 'webcomicme'; - super.label = 'WebComic (Webcomic.me)'; - this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://webcomic.me'; - } + constructor() { + super(); + super.id = 'webcomicme'; + super.label = 'WebComic (Webcomic.me)'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://webcomic.me'; + } } \ No newline at end of file From 4fa1406d38f72c8fa1e7292955a3670c986327bf Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sun, 13 Nov 2022 14:59:34 +0100 Subject: [PATCH 41/64] Attempt to Fix lint on pururin and beautymanga --- src/web/mjs/connectors/BeautyManga.mjs | 38 ++++++++++++-------------- src/web/mjs/connectors/Pururin.mjs | 7 ++--- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/web/mjs/connectors/BeautyManga.mjs b/src/web/mjs/connectors/BeautyManga.mjs index 5a7f991c2e6..07167103d0f 100644 --- a/src/web/mjs/connectors/BeautyManga.mjs +++ b/src/web/mjs/connectors/BeautyManga.mjs @@ -1,19 +1,19 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; export default class BeautyManga extends WordPressMadara { - constructor() { - super(); - super.id = 'beautymanga'; - super.label = 'BeautyManga'; - this.tags = [ 'manga', 'webtoon', 'english' ]; - this.url = 'https://mangadex.today'; - this.path = '/popular-manga'; - this.queryMangas = 'div.item-thumb.hover-details.c-image-hover a'; - this.queryMangasPageCount = 'ul.pagination li:nth-last-of-type(2) a'; - this.pathMangas = '?page=%PAGE%'; - this.queryPages = 'p#arraydata'; - this.mangaTitleFilter = ''; - } - async _getMangasFromPage(page) { + constructor() { + super(); + super.id = 'beautymanga'; + super.label = 'BeautyManga'; + this.tags = [ 'manga', 'webtoon', 'english' ]; + this.url = 'https://mangadex.today'; + this.path = '/popular-manga'; + this.queryMangas = 'div.item-thumb.hover-details.c-image-hover a'; + this.queryMangasPageCount = 'ul.pagination li:nth-last-of-type(2) a'; + this.pathMangas = '?page=%PAGE%'; + this.queryPages = 'p#arraydata'; + this.mangaTitleFilter = ''; + } + async _getMangasFromPage(page) { let uri = new URL(this.path + this.pathMangas.replace('%PAGE%', page), this.url); uri.pathname = uri.pathname.replace(/\/+/g, '/'); let request = new Request(uri, this.requestOptions); @@ -26,15 +26,14 @@ export default class BeautyManga extends WordPressMadara { }); } async _getChaptersAjaxOld(mangaID) { - const uri = new URL('/ajax-list-chapter?mangaID='+mangaID , this.url); + const uri = new URL('/ajax-list-chapter?mangaID='+mangaID, this.url); const request = new Request(uri, { method: 'GET' }); const data = await this.fetchDOM(request, this.queryChapters); if (data.length) { return data; - } - else { + } else { throw new Error('No chapters found (new ajax endpoint)!'); } } @@ -44,13 +43,12 @@ export default class BeautyManga extends WordPressMadara { let request = new Request(uri, this.requestOptions); let data = await this.fetchDOM(request, this.queryPages); let el = data[0].innerText.split(','); - return el.map(element => - { + return el.map(element => { const uri = new URL(this.getAbsolutePath(element, request.url)); return this.createConnectorURI({ url: uri.href, referer: uri.origin - }) + }); }); } } \ No newline at end of file diff --git a/src/web/mjs/connectors/Pururin.mjs b/src/web/mjs/connectors/Pururin.mjs index 50515202a60..21dfa315d13 100644 --- a/src/web/mjs/connectors/Pururin.mjs +++ b/src/web/mjs/connectors/Pururin.mjs @@ -47,7 +47,7 @@ export default class Pururin extends Connector { async _getPages(chapter) { let queryPicture = ''; let pictures = []; - var myRegexp = new RegExp("gallery\/([0-9]+)", "g"); + var myRegexp = new RegExp('gallery\/([0-9]+)', 'g'); var match = myRegexp.exec(chapter.id); let mangaID = match[1]; let params = '{"id":'+mangaID+',"type":2}'; @@ -66,15 +66,14 @@ export default class Pururin extends Connector { let pagesMax = data.gallery.total_pages; let extension = data.gallery.image_extension; //https://cdn.pururin.to/assets/images/data//.image_extension - for (var i = 1; i <= pagesMax; i++) - { + for (var i = 1; i <= pagesMax; i++) { let imageuri = this.CDN.replace('{1}', mangaID).replace('{2}', i).replace('{3}', extension); pictures.push(imageuri); } return pictures; } async _getMangaFromURI(uri) { - var myRegexp = new RegExp("gallery\/([0-9]+)", "g"); + var myRegexp = new RegExp('gallery\/([0-9]+)', 'g'); var match = myRegexp.exec(uri.href); let mangaID = match[1]; let params = '{"id":'+mangaID+',"type":2}'; From dd9031ff167fa51e2e6aa64e9cff837d0e17d9ce Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sun, 13 Nov 2022 15:19:24 +0100 Subject: [PATCH 42/64] Attempt to fix lint on pururin and beautymanga 2 --- src/web/mjs/connectors/BeautyManga.mjs | 3 +-- src/web/mjs/connectors/Pururin.mjs | 9 ++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/web/mjs/connectors/BeautyManga.mjs b/src/web/mjs/connectors/BeautyManga.mjs index 07167103d0f..1f1c97ba558 100644 --- a/src/web/mjs/connectors/BeautyManga.mjs +++ b/src/web/mjs/connectors/BeautyManga.mjs @@ -37,8 +37,7 @@ export default class BeautyManga extends WordPressMadara { throw new Error('No chapters found (new ajax endpoint)!'); } } - async _getPages(chapter) - { + async _getPages(chapter) { let uri = new URL(chapter.id, this.url); let request = new Request(uri, this.requestOptions); let data = await this.fetchDOM(request, this.queryPages); diff --git a/src/web/mjs/connectors/Pururin.mjs b/src/web/mjs/connectors/Pururin.mjs index 21dfa315d13..95edab27c10 100644 --- a/src/web/mjs/connectors/Pururin.mjs +++ b/src/web/mjs/connectors/Pururin.mjs @@ -45,10 +45,9 @@ export default class Pururin extends Connector { return chapters; } async _getPages(chapter) { - let queryPicture = ''; let pictures = []; - var myRegexp = new RegExp('gallery\/([0-9]+)', 'g'); - var match = myRegexp.exec(chapter.id); + const myRegexp = new RegExp(/gallery\/([0-9]+)/g); + let match = myRegexp.exec(chapter.id); let mangaID = match[1]; let params = '{"id":'+mangaID+',"type":2}'; const uri = new URL(this.api, this.url); @@ -73,8 +72,8 @@ export default class Pururin extends Connector { return pictures; } async _getMangaFromURI(uri) { - var myRegexp = new RegExp('gallery\/([0-9]+)', 'g'); - var match = myRegexp.exec(uri.href); + const myRegexp = new RegExp(/gallery\/([0-9]+)/g); + let match = myRegexp.exec(uri.href); let mangaID = match[1]; let params = '{"id":'+mangaID+',"type":2}'; const req = new URL(this.api, this.url); From edef6a40f2ad6c064e38015071ca7e7842c0091c Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sun, 13 Nov 2022 18:47:08 +0100 Subject: [PATCH 43/64] FIx WebComicMe --- src/web/mjs/connectors/Webcomicme.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/Webcomicme.mjs b/src/web/mjs/connectors/Webcomicme.mjs index 74bc44df8c4..f814388b280 100644 --- a/src/web/mjs/connectors/Webcomicme.mjs +++ b/src/web/mjs/connectors/Webcomicme.mjs @@ -1,5 +1,5 @@ import WordPressMadara from './templates/WordPressMadara.mjs'; -export default class MangaChill extends WordPressMadara { +export default class WebComicMe extends WordPressMadara { constructor() { super(); super.id = 'webcomicme'; @@ -7,4 +7,4 @@ export default class MangaChill extends WordPressMadara { this.tags = [ 'manga', 'webtoon', 'english' ]; this.url = 'https://webcomic.me'; } -} \ No newline at end of file +} From 08bdea02d3d965953e558b3b584b278f9f4b72a7 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 26 Nov 2022 16:03:08 +0100 Subject: [PATCH 44/64] First attempt to use ToptoonGlobal api This fails when getting pages, otherwise it works. V2 api is only used for pages. Also, maybe the rest need fixes to handle logged user. --- src/web/mjs/connectors/TopToonGlobal.mjs | 122 +++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/web/mjs/connectors/TopToonGlobal.mjs diff --git a/src/web/mjs/connectors/TopToonGlobal.mjs b/src/web/mjs/connectors/TopToonGlobal.mjs new file mode 100644 index 00000000000..e7b130aefb6 --- /dev/null +++ b/src/web/mjs/connectors/TopToonGlobal.mjs @@ -0,0 +1,122 @@ +import Connector from '../engine/Connector.mjs'; +import Manga from '../engine/Manga.mjs'; +export default class TopToonGlobal extends Connector { + constructor() { + super(); + super.id = 'toptoonglobal'; + super.label = 'TOPTOON Global (English)'; + this.tags = [ 'webtoon', 'english' ]; + this.url = 'https://global.toptoon.com'; + this.api ='https://api.toptoonplus.com' + } + /* + async _getMangaFromURI(uri) { + const request = new Request(uri, this.requestOptions); + const data = await this.fetchDOM(request, 'div.bnr_episode_info p.tit_toon'); + return new Manga(this, uri.pathname, data[0].textContent.trim()); + } + */ + async _getMangas() { + const request = new Request(new URL('/api/v1/page/genres', this.api), this.requestOptions); + request.headers.set('language', 'en'); + request.headers.set('ua', 'web'); + request.headers.set('x-api-key', 'SUPERCOOLAPIKEY2021#@#('); + request.headers.set('x-origin', 'global.toptoon.com'); + request.headers.set('user-id', ''); + request.headers.set('partnerCode', ''); + + + const data = await this.fetchJSON(request); + return data.data.genres.map(item => { + let link = '/content/'+item.information.title; + link = link.replace(' ', '-'); + link = link.replace(/[\?]/g, ''); + link = link + '/'+ item.comicId; + return{ + id: link, + title: item.information.title + }; + }); + } + async _getChapters(manga) { + const mangaid = manga.id.match(/\/([0-9]+$)/)[1]; + const request = new Request(new URL('/api/v1/page/episode?comicId='+mangaid, this.api), this.requestOptions); + request.headers.set('language', 'en'); + request.headers.set('ua', 'web'); + request.headers.set('x-api-key', 'SUPERCOOLAPIKEY2021#@#('); + request.headers.set('x-origin', 'global.toptoon.com'); + request.headers.set('user-id', ''); + request.headers.set('partnerCode', ''); + + const data = await this.fetchJSON(request); + return data.data.episode.map(item => { + let link = '/content/content/'+mangaid+'/'+item.episodeId; + return{ + id: link, + title: item.information.title + }; + }) + .reverse(); + } + async _getPages(chapter) { + const mangaid = chapter.id.match(/content\/([0-9]+)/)[1]; + const chapterid = chapter.id.match(/\/([0-9]+$)/)[1]; + + let request = new Request(new URL(this.url), this.requestOptions); + let secretKey = await Engine.Request.fetchUI(request, 'localStorage.getItem("udid") || ""'); + + + const uri = new URL('/api/v2/viewer/'+mangaid+'/'+chapterid, this.api); + let body = { + action : 'view_contents', + cToken : '', + isCached : false, + location : 'viewer', + }; + + let pdata = this.generatePayloadData(secretKey); + + request = new Request(uri, { + method: 'POST', + body: JSON.stringify(body), + headers: { + 'Accept': '*/*', + 'Content-Type': 'application/json', + 'x-referrer': this.url, + 'language': 'en', + 'ua':'web', + 'x-api-key': pdata.k, + 'Origin': 'global.toptoon.com', + 'x-origin': 'global.toptoon.com', + 'user-id': '', + 'deviceId': secretKey, + 'partnerCode':'', + 'timestamp' : pdata.t, + 'version' : '1.18.189a', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:107.0) Gecko/20100101 Firefox/107.0', + } + }); + let data = await fetch(request); + data = await data.json(); + } + + generatePayloadData(uuid){ + //timestampUTC+MS + + //var hash = r.createHash('sha256').update(uuid.toString().replace(/-/g, ''.concat(timestamp))).digest('hex'); + //return r.pbkdf2Sync(''.concat(uuid, '|').concat(timestamp), hash, iterations (for now 257), hash.length, 'sha512').toString('base64') + //this has been tested with fixed values and it works + + let timestamp = Date.now().toString()+ (Math.trunc(Math.random() * (999 - 100) + 100)).toString(); + let message = uuid.toString().replace(/-/g, ''.concat(timestamp)); + let salt = CryptoJS.SHA256(message).toString(); + let cfg = { + keySize: 64, + hasher: CryptoJS.algo.SHA512, + iterations: 257 + }; + message = uuid + '|'+timestamp; + let apikey = CryptoJS.PBKDF2(message, salt, cfg).toString(CryptoJS.enc.Base64); + return {k : apikey, t : timestamp } + } +} From 7d7cde345ff39b9164fc6f03d59c1637d0c1fa83 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Wed, 30 Nov 2022 15:17:42 +0000 Subject: [PATCH 45/64] Attempt to fix ehentai "bounce login" See https://github.com/manga-download/hakuneko/issues/4523 for infos. Idk whats going on. --- src/web/mjs/connectors/EHentai.mjs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/web/mjs/connectors/EHentai.mjs b/src/web/mjs/connectors/EHentai.mjs index 52a36ecff78..cf1ba4ccc82 100644 --- a/src/web/mjs/connectors/EHentai.mjs +++ b/src/web/mjs/connectors/EHentai.mjs @@ -59,10 +59,20 @@ export default class EHentai extends Connector { async _handleConnectorURI(payload) { let request = new Request(payload, this.requestOptions); - let data = (await this.fetchDOM(request, 'source#img, a[href*="fullimg.php"]')).reverse(); + + //get full page body to avoir a request in case of failure + let dom = (await this.fetchDOM(request, 'body'))[0]; + let data = [...dom.querySelectorAll('source#img, a[href*="fullimg.php"]')].reverse(); + let response = await fetch(this.getAbsolutePath(data[0], request.url), this.requestOptions); + if(response.url.match(/bounce_login.php/)){ + data = dom.querySelector('source#img') + response = await fetch(this.getAbsolutePath(data.src, request.url), this.requestOptions); + } + + if(!response.headers.get('content-type').startsWith('image/')) { - response = await fetch(this.getAbsolutePath(data[0], request.url), this.requestOptions); + //response = await fetch(this.getAbsolutePath(data[0], request.url), this.requestOptions); //console.log('Download Optimized:', response.url); } else { //console.log('Download Original:', response.url); From 95ef3c03192d08f44c9b82790f6dcde4a9d32a16 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Fri, 2 Dec 2022 11:45:59 +0000 Subject: [PATCH 46/64] fixing Kakaopage Fixes https://github.com/manga-download/hakuneko/issues/3733 but need to properly handle errors for stuff non purchased. --- src/web/mjs/connectors/kakaopage.mjs | 200 ++++++++++++++++++++------- 1 file changed, 150 insertions(+), 50 deletions(-) diff --git a/src/web/mjs/connectors/kakaopage.mjs b/src/web/mjs/connectors/kakaopage.mjs index 3d56839c33b..f82906b73c8 100644 --- a/src/web/mjs/connectors/kakaopage.mjs +++ b/src/web/mjs/connectors/kakaopage.mjs @@ -1,18 +1,16 @@ import Connector from '../engine/Connector.mjs'; import Manga from '../engine/Manga.mjs'; - export default class kakaopage extends Connector { - constructor() { super(); super.id = 'kakaopage'; super.label = 'Page Kakao (카카오페이지) '; this.tags = [ 'webtoon', 'manga', 'korean' ]; this.url = 'https://page.kakao.com'; + this.api = 'https://page.kakao.com/graphql'; this.requestOptions.headers.set('x-origin', this.url); this.requestOptions.headers.set('x-referer', this.url); } - async _getMangaFromURI(uri) { uri = new URL(uri); const request = new Request(uri, this.requestOptions); @@ -21,59 +19,161 @@ export default class kakaopage extends Connector { let title = data[0].content.trim(); return new Manga(this, id, title); } - async _getMangas() { let msg = 'This website does not provide a manga list, please copy and paste the URL containing the images directly from your browser into HakuNeko.'; throw new Error(msg); } - async _getChapters(manga) { - let chapterList = []; - for(let page = 0, run = true; run; page++) { - let chapters = await this._getChaptersFromPage(manga, page); - chapters.length > 0 ? chapterList.push(...chapters) : run = false; - } - return chapterList; - } + let gql = { + operationName: 'contentHomeProductList', + variables: { + boughtOnly: false, + seriesId: manga.id + }, + query: `query contentHomeProductList($after: String, $before: String, $first: Int, $last: Int, $seriesId: Long!, $boughtOnly: Boolean, $sortType: String) { + contentHomeProductList( seriesId: $seriesId after: $after before: $before first: $first last: $last boughtOnly: $boughtOnly sortType: $sortType ) { + totalCount pageInfo { + hasNextPage endCursor hasPreviousPage startCursor __typename } + selectedSortOption { + id name param __typename } + sortOptionList { + id name param __typename } + edges { + cursor node { + ...SingleListViewItem __typename } + __typename } + __typename } + } + fragment SingleListViewItem on SingleListViewItem { + id type thumbnail showPlayerIcon isCheckMode isChecked scheme row1 { + badgeList title __typename } + row2 row3 single { + productId ageGrade id isFree thumbnail title slideType operatorProperty { + isTextViewer __typename } + __typename } + isViewed purchaseInfoText eventLog { + ...EventLogFragment __typename } + } + fragment EventLogFragment on EventLog { + click { + layer1 layer2 setnum ordnum copy imp_id imp_provider __typename } + eventMeta { + id name subcategory category series provider series_id type __typename } + viewimp_contents { + type name id imp_area_ordnum imp_id imp_provider imp_type layer1 layer2 __typename } + customProps { + landing_path view_type toros_imp_id toros_file_hash_key toros_event_meta_id content_cnt event_series_id event_ticket_type play_url banner_uid __typename } + } + ` + }; + let data = await this.fetchGraphQL(this.api, gql.operationName, gql.query, gql.variables ); + + return data.contentHomeProductList.edges.map(element => ({ + title : element.node.row1.title , + id : '/content/'+manga.id+'/viewer/'+element.node.single.productId + })).reverse(); - async _getChaptersFromPage(manga, page) { - let form = new FormData(); - form.append('seriesid', manga.id); - form.append('page', page); - form.append('direction', 'desc'); - form.append('page_size', 20); - form.append('without_hidden', true); - let request = new Request('https://api2-page.kakao.com/api/v5/store/singles', { - ...this.requestOptions, - method: 'POST', - body: form - }); - let data = await this.fetchJSON(request); - return data.singles.map(ele => { - return{ - id: ele.id, - title: ele.title.trim() - }; - }); } - async _getPages(chapter) { - let form = new FormData(); - form.append('productId', chapter.id); - this.requestOptions.method = 'POST'; - this.requestOptions.body = form; - let request = new Request('https://api2-page.kakao.com/api/v1/inven/get_download_data/web', { - ...this.requestOptions, - method: 'POST', - body: form + async _getPages(chapter) { + let gql = { + operationName: 'viewerInfo', + variables: { + seriesId: chapter.id.match(/\/content\/([0-9]+)/)[1], + productId : chapter.id.match(/\/viewer\/([0-9]+)/)[1] + }, + query: `query viewerInfo($seriesId: Long!, $productId: Long!) { + viewerInfo(seriesId: $seriesId, productId: $productId) { + item { + ...SingleFragment __typename } + seriesItem { + ...SeriesFragment __typename } + prevItem { + ...NearItemFragment __typename } + nextItem { + ...NearItemFragment __typename } + viewerData { + ...TextViewerData ...TalkViewerData ...ImageViewerData ...VodViewerData __typename } + displayAd { + ...DisplayAd __typename } + __typename } + } + fragment SingleFragment on Single { + id productId seriesId title thumbnail badge isFree ageGrade state slideType lastReleasedDate size pageCount isHidden freeChangeDate isWaitfreeBlocked saleState series { + ...SeriesFragment __typename } + serviceProperty { + ...ServicePropertyFragment __typename } + operatorProperty { + ...OperatorPropertyFragment __typename } + assetProperty { + ...AssetPropertyFragment __typename } + } + fragment SeriesFragment on Series { + id seriesId title thumbnail categoryUid category subcategoryUid subcategory badge isAllFree isWaitfree isWaitfreePlus is3HoursWaitfree ageGrade state onIssue seriesType businessModel authors pubPeriod freeSlideCount lastSlideAddedDate waitfreeBlockCount waitfreePeriodByMinute bm saleState serviceProperty { + ...ServicePropertyFragment __typename } + operatorProperty { + ...OperatorPropertyFragment __typename } + assetProperty { + ...AssetPropertyFragment __typename } + } + fragment ServicePropertyFragment on ServiceProperty { + viewCount readCount ratingCount ratingSum commentCount pageContinue { + ...ContinueInfoFragment __typename } + todayGift { + ...TodayGift __typename } + waitfreeTicket { + ...WaitfreeTicketFragment __typename } + isAlarmOn isLikeOn ticketCount purchasedDate lastViewInfo { + ...LastViewInfoFragment __typename } + purchaseInfo { + ...PurchaseInfoFragment __typename } + } + fragment ContinueInfoFragment on ContinueInfo { + title isFree productId lastReadProductId scheme continueProductType hasNewSingle hasUnreadSingle} + fragment TodayGift on TodayGift { + id uid ticketType ticketKind ticketCount ticketExpireAt isReceived} + fragment WaitfreeTicketFragment on WaitfreeTicket { + chargedPeriod chargedCount chargedAt} + fragment LastViewInfoFragment on LastViewInfo { + isDone lastViewDate rate spineIndex} + fragment PurchaseInfoFragment on PurchaseInfo { + purchaseType rentExpireDate} + fragment OperatorPropertyFragment on OperatorProperty { + thumbnail copy torosImpId torosFileHashKey isTextViewer} + fragment AssetPropertyFragment on AssetProperty { + bannerImage cardImage cardTextImage cleanImage ipxVideo} + fragment NearItemFragment on NearItem { + productId slideType ageGrade isFree title thumbnail} + fragment TextViewerData on TextViewerData { + type atsServerUrl metaSecureUrl contentsList { + chapterId contentId secureUrl __typename } + } + fragment TalkViewerData on TalkViewerData { + type talkDownloadData { + dec host path talkViewerType __typename } + } + fragment ImageViewerData on ImageViewerData { + type imageDownloadData { + ...ImageDownloadData __typename } + } + fragment ImageDownloadData on ImageDownloadData { + files { + ...ImageDownloadFile __typename } + totalCount totalSize viewDirection gapBetweenImages readType} + fragment ImageDownloadFile on ImageDownloadFile { + no size secureUrl width height} + fragment VodViewerData on VodViewerData { + type vodDownloadData { + contentId drmType endpointUrl width height duration __typename } + } + fragment DisplayAd on DisplayAd { + sectionUid bannerUid treviUid momentUid} + ` + }; + let data = await this.fetchGraphQL(this.api, gql.operationName, gql.query, gql.variables ); + return data.viewerInfo.viewerData.imageDownloadData.files.map(element => { + return element.secureUrl + }); - this.requestOptions.method = 'GET'; - delete this.requestOptions.body; - let data = await this.fetchJSON(request); - if (data.downloadData && data.downloadData.members) { - return data.downloadData.members.files.map(element => data.downloadData.members.sAtsServerUrl + element.secureUrl); - } - - throw new Error(`Can't fetch this ressource because it's protected`); - } -} \ No newline at end of file + } +} From ebd4dcfd331ed780f497b02fb8431bcdb6a20b83 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 3 Dec 2022 15:19:28 +0000 Subject: [PATCH 47/64] Lezhin fix attempt Still bugged --- src/web/mjs/connectors/templates/Lezhin.mjs | 315 ++++++++++++-------- 1 file changed, 183 insertions(+), 132 deletions(-) diff --git a/src/web/mjs/connectors/templates/Lezhin.mjs b/src/web/mjs/connectors/templates/Lezhin.mjs index 0ad2974469c..e1dd7af3d61 100644 --- a/src/web/mjs/connectors/templates/Lezhin.mjs +++ b/src/web/mjs/connectors/templates/Lezhin.mjs @@ -1,15 +1,14 @@ import Connector from '../../engine/Connector.mjs'; import Manga from '../../engine/Manga.mjs'; - export default class Lezhin extends Connector { - constructor() { super(); super.id = undefined; super.label = undefined; this.tags = []; this.url = undefined; - this.apiURL = 'https://www.lezhin.com/api/v2'; // https://api.lezhin.com/v2 + this.apiURL = 'https://www.lezhin.com/api/v2'; + // https://api.lezhin.com/v2 this.cdnURL = 'https://cdn.lezhin.com'; this.userID = undefined; this.accessToken = '995dba2e-8c5d-4249-b601-38c5d3e092e5'; @@ -35,31 +34,31 @@ export default class Lezhin extends Connector { } }; } - async _initializeAccount() { if(this.userID || !this.config.username.value || !this.config.password.value) { return; } let script = ` - new Promise((resolve, reject) => { - try { - if($('#log-nav-email').length) { - return resolve(); - } - const form = $('form#email'); - form.find('input#login-email').val('${this.config.username.value}'); - form.find('input#login-password').val('${this.config.password.value}'); - $.ajax({ - type: 'POST', - url: form.prop('action'), - data: form.serialize(), - success: resolve, - error: reject - }); - } catch(error) { - reject(error); + new Promise((resolve, reject) => { + try { + if($('#log-nav-email').length) { + return resolve(); } - }); + const form = $('form#email'); + form.find('input#login-email').val('${this.config.username.value}'); + form.find('input#login-password').val('${this.config.password.value}'); + $.ajax({ + type: 'POST', + url: form.prop('action'), + data: form.serialize(), + success: resolve, + error: reject + }); + } + catch(error) { + reject(error); + } + }); `; let request = new Request(new URL(this.url + '/login'), this.requestOptions); await Engine.Request.fetchUI(request, script); @@ -78,7 +77,6 @@ export default class Lezhin extends Connector { // => prevent a warning webpage that would appear otherwise when loading chapters / pages return fetch(this.url + '/locale/' + this.locale, this.requestOptions); } - async _getMangaFromURI(uri) { let request = new Request(uri, this.requestOptions); let data = await this.fetchDOM(request, 'div.comicInfo__detail h2.comicInfo__title'); @@ -86,10 +84,9 @@ export default class Lezhin extends Connector { let title = data[0].textContent.trim(); return new Manga(this, id, title); } - /** - * - */ + * + */ _getMangaFromPage( offset, limit ) { offset = offset || 0; limit = limit || 500; @@ -102,131 +99,185 @@ export default class Lezhin extends Connector { uri.searchParams.set( 'filter', 'all' ); //uri.searchParams.set( '_', Date.now() ); return fetch( uri.href, this.requestOptions ) - .then( response => response.json() ) - .then( data => { - if( data.code ) { - throw new Error( data.description ); - } - let mangaList = data.data.map( manga => { - return { - id: manga.alias, // manga.id - title: manga.title - }; - } ); - if( data.hasNext ) { - return this._getMangaFromPage( offset + limit, limit ) - .then( mangas => mangaList.concat( mangas ) ); - } else { - return Promise.resolve( mangaList ); - } - } ); + .then( response => response.json() ) + .then( data => { + if( data.code ) { + throw new Error( data.description ); + } + let mangaList = data.data.map( manga => { + return { + id: manga.alias, // manga.id + title: manga.title + }; + } + ); + if( data.hasNext ) { + return this._getMangaFromPage( offset + limit, limit ) + .then( mangas => mangaList.concat( mangas ) ); + } + else { + return Promise.resolve( mangaList ); + } + } + ); } - /** - * - */ + * + */ _getMangaList( callback ) { this._getMangaFromPage() - .then( data => { - callback( null, data ); - } ) - .catch( error => { - console.error( error, this ); - callback( error, undefined ); - } ); + .then( data => { + callback( null, data ); + } + ) + .catch( error => { + console.error( error, this ); + callback( error, undefined ); + } + ); } - async _getChapters(manga) { await this._initializeAccount(); /* - *let purchased = []; - *let subscription = false; - *if(this.accessToken) { - * let uri = new URL(`${this.apiURL}/users/${this.userID}/contents/${mangaiD}`); - * let request = new Request(uri, this.requestOptions); - * request.headers.set('authorization', 'Bearer ' + this.accessToken); - * let data = await this.fetchJSON(request); - * purchased = data.data.purchased; - * subscription = data.data.subscribed; - *} - */ + *let purchased = []; + *let subscription = false; + *if(this.accessToken) { + * let uri = new URL(`${this.apiURL}/users/${this.userID}/contents/${mangaiD}`); + * let request = new Request(uri, this.requestOptions); + * request.headers.set('authorization', 'Bearer ' + this.accessToken); + * let data = await this.fetchJSON(request); + * purchased = data.data.purchased; + * subscription = data.data.subscribed; + *} + */ let script = ` - new Promise((resolve, reject) => { - // wait until episodes have been updated with purchase info ... - setTimeout(() => { - try { - let chapters = __LZ_PRODUCT__.all // __LZ_PRODUCT__.product.episodes - .filter(chapter => { - if(chapter.purchased) { - return true; - } - if(chapter.coin === 0) { - return true; - } - if(chapter.freedAt && chapter.freedAt < Date.now()) { - return true; - } - if(chapter.prefree && chapter.prefree.closeTimer && chapter.prefree.closeTimer.expiredAt > Date.now()) { - return true; - } - return false; - }) - .map(chapter => { - return { - id: chapter.name, // chapter.id, - title: chapter.display.displayName + ' - ' + chapter.display.title, - language: '${this.locale}' - }; - }); - resolve(chapters); - } catch(error) { - reject(error); - } - }, 2500); - }); + new Promise((resolve, reject) => { + // wait until episodes have been updated with purchase info ... + setTimeout(() => { + try { + let chapters = __LZ_PRODUCT__.all // __LZ_PRODUCT__.product.episodes + .filter(chapter => { + if(chapter.purchased) { + return true; + } + if(chapter.coin === 0) { + return true; + } + if(chapter.freedAt && chapter.freedAt < Date.now()) { + return true; + } + if(chapter.prefree && chapter.prefree.closeTimer && chapter.prefree.closeTimer.expiredAt > Date.now()) { + return true; + } + return false; + }) + .map(chapter => { + return { + id: chapter.name, // chapter.id, + title: chapter.display.displayName + ' - ' + chapter.display.title, + language: '${this.locale}' + }; + }); + resolve(chapters); + } + catch(error) { + reject(error); + } + }, + 2500); + }); `; let request = new Request(new URL('/comic/' + manga.id, this.url), this.requestOptions); return Engine.Request.fetchUI(request, script); } - async _getPages(chapter) { await this._initializeAccount(); /* - q | Free | Purchased - ---------------------- - 10 | 480w | 640w - 20 | 640w | 720w - 30 | 720w | 1080w - 40 | 1080w | 1280w + q | Free | Purchased + ---------------------- + 10 | 480w | 640w + 20 | 640w | 720w + 30 | 720w | 1080w + 40 | 1080w | 1280w + */ + + /*the concept is + you get the partial picture url using the premise and all the elements you need + to create the request to get the missing part of the url + (signature, policy, keypair) + + data is returned as + { + imgurl : the partial url + token : the url where to get the json with missing parameters + referer : the chapter referer, just in case its checked + } + + i also increased the promise timeout to 5s because 2.5 wasnt enough, + even prior to patch the 'd2' error. + + TODO : see how we can handle jpg/webp thing + */ const script = ` - new Promise((resolve, reject) => { - setTimeout(() => { - try { - if(window.location.pathname.includes('/login')) { - throw new Error('You need to be logged in to access the content of this chapter!'); - } - const subscribed = __LZ_DATA__.product && __LZ_DATA__.product.subscribed; - const purchased = __LZ_DATA__.purchased && __LZ_DATA__.purchased.includes(__LZ_DATA__.episode.id); - const hasOnlyJPEG = !!__LZ_DATA__.episode.d2; - const images = __LZ_DATA__.episode.scrollsInfo.map(x => { - const extension = ${this.config.forceJPEG.value} || hasOnlyJPEG ? '.jpg' : '.webp'; - const uri = new URL('/v2' + x.path + extension, __LZ_CONFIG__.cdnUrl); - uri.searchParams.set('access_token', '${this.accessToken}'); - uri.searchParams.set('purchased', subscribed || purchased); - uri.searchParams.set('q', 40); - return uri.href; - }); - resolve(images); - } catch(error) { - reject(error); + new Promise((resolve, reject) => { + setTimeout(() => { + try { + if(window.location.pathname.includes('/login')) { + throw new Error('You need to be logged in to access the content of this chapter!'); } - }, 2500); - }); + const subscribed = __LZ_DATA__.product && __LZ_DATA__.product.subscribed; + const purchased = __LZ_DATA__.purchased && __LZ_DATA__.purchased.includes(__LZ_DATA__.episode.id); + const hasOnlyJPEG = false; + const updated = __LZ_DATA__.episode.updatedAt; + const images = __LZ_DATA__.episode.scrollsInfo.map(x => { + //const extension = ${this.config.forceJPEG.value} || hasOnlyJPEG ? '.jpg' : '.webp'; + const extension ='.webp'; + //request to generate the url + //https://www.lezhinus.com/lz-api/v2/cloudfront/signed-url/generate?contentId=XXXXXXX&episodeId=YYYYYYYYY&purchased=false&q=30&firstCheckType=P + const tokenuri = new URL('https://www.lezhinus.com/lz-api/v2/cloudfront/signed-url/generate'); + tokenuri.searchParams.set('contentId', __LZ_DATA__.episode.contentId); + tokenuri.searchParams.set('episodeId', __LZ_DATA__.episode.id); + tokenuri.searchParams.set('purchased', subscribed || purchased); + tokenuri.searchParams.set('q', 30); + tokenuri.searchParams.set('firstCheckType', 'P'); + //picture final url + const uri = new URL('/v2' + x.path + extension, __LZ_CONFIG__.contentsCdnUrl); + uri.searchParams.set('purchased', subscribed || purchased); + uri.searchParams.set('q', 30); + uri.searchParams.set('updated', updated); + return { + imgurl : uri.href, token : tokenuri.href, referer : window.location.href} + ; + }); + resolve(images); + } + catch(error) { + reject(error); + } + }, + 5000); + }); `; - + const uri = new URL(`${this.url}/comic/${chapter.manga.id}/${chapter.id}`); - const request = new Request(uri, this.requestOptions); - return Engine.Request.fetchUI(request, script); + let request = new Request(uri, this.requestOptions); + let data = await Engine.Request.fetchUI(request, script); + let imageslist = []; + for (let i = 0; i < data.length; i++){ + let element = data[i]; + let imageurl = new URL(element.imgurl); + //get the missing parameters from the JSON request (unique for each image) + let requesturl = new URL(element.token); + request = new Request( requesturl, this.requestOptions ); + request.headers.set('x-referer', element.referer); + let response = await this.fetchJSON(request); + //add missing parameters to the image url + imageurl.searchParams.set('Policy', response.data.Policy); + imageurl.searchParams.set('Signature', response.data.Signature); + imageurl.searchParams.set('Key-Pair-Id', response.data['Key-Pair-Id']); + imageslist.push(imageurl.href); + } + return (imageslist); } -} \ No newline at end of file +} From 0ed7be4c33578aa87a543ec6164444346e1a73a7 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 3 Dec 2022 15:20:52 +0000 Subject: [PATCH 48/64] removed acc token on lezhin --- src/web/mjs/connectors/templates/Lezhin.mjs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/web/mjs/connectors/templates/Lezhin.mjs b/src/web/mjs/connectors/templates/Lezhin.mjs index e1dd7af3d61..63f1c0865cc 100644 --- a/src/web/mjs/connectors/templates/Lezhin.mjs +++ b/src/web/mjs/connectors/templates/Lezhin.mjs @@ -11,7 +11,6 @@ export default class Lezhin extends Connector { // https://api.lezhin.com/v2 this.cdnURL = 'https://cdn.lezhin.com'; this.userID = undefined; - this.accessToken = '995dba2e-8c5d-4249-b601-38c5d3e092e5'; // Private members for internal use that can be configured by the user through settings menu (set to undefined or false to hide from settings menu!) this.config = { username: { @@ -69,7 +68,6 @@ export default class Lezhin extends Connector { let token = data.match(/token\s*:\s*['"]([^'"]+)['"]/); this.cdnURL = cdn ? cdn[1] : this.cdnURL; this.userID = user ? user[1] : undefined; - this.accessToken = token ? token[1] : this.accessToken; if(this.userID) { await fetch(this.url + '/adultkind?path=&sw=all', this.requestOptions); } From 5dd1fc684dd0b531cdeb7f0bc93f075fc18e61f3 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 3 Dec 2022 18:35:30 +0000 Subject: [PATCH 49/64] Lezhin, but better Still giving random 403 --- src/web/mjs/connectors/templates/Lezhin.mjs | 320 +++++++++++++------- 1 file changed, 209 insertions(+), 111 deletions(-) diff --git a/src/web/mjs/connectors/templates/Lezhin.mjs b/src/web/mjs/connectors/templates/Lezhin.mjs index 63f1c0865cc..6ea225d6894 100644 --- a/src/web/mjs/connectors/templates/Lezhin.mjs +++ b/src/web/mjs/connectors/templates/Lezhin.mjs @@ -7,10 +7,12 @@ export default class Lezhin extends Connector { super.label = undefined; this.tags = []; this.url = undefined; - this.apiURL = 'https://www.lezhin.com/api/v2'; - // https://api.lezhin.com/v2 + this.apiURL = 'https://www.lezhinus.com'; + // /lz-api/v2/ this.cdnURL = 'https://cdn.lezhin.com'; this.userID = undefined; + this.mangasPerPage = 36; + this.lzConfig = undefined; // Private members for internal use that can be configured by the user through settings menu (set to undefined or false to hide from settings menu!) this.config = { username: { @@ -82,58 +84,33 @@ export default class Lezhin extends Connector { let title = data[0].textContent.trim(); return new Manga(this, id, title); } - /** - * - */ - _getMangaFromPage( offset, limit ) { - offset = offset || 0; - limit = limit || 500; - let uri = new URL( this.apiURL + '/comics' ); - uri.searchParams.set( 'offset', offset ); - uri.searchParams.set( 'limit', limit ); - uri.searchParams.set( 'country_code', '' ); - uri.searchParams.set( 'store', 'web' ); - uri.searchParams.set( 'adult_kind', 'all' ); - uri.searchParams.set( 'filter', 'all' ); - //uri.searchParams.set( '_', Date.now() ); - return fetch( uri.href, this.requestOptions ) - .then( response => response.json() ) - .then( data => { - if( data.code ) { - throw new Error( data.description ); - } - let mangaList = data.data.map( manga => { - return { - id: manga.alias, // manga.id - title: manga.title - }; - } - ); - if( data.hasNext ) { - return this._getMangaFromPage( offset + limit, limit ) - .then( mangas => mangaList.concat( mangas ) ); - } - else { - return Promise.resolve( mangaList ); - } + async _getMangas(){ + let mangaList = []; + for (let page = 0, run = true; run; page++) { + let mangas = await this._getMangasFromPage(page); + mangas.length > 0 ? mangaList.push(...mangas) : run = false; } - ); + return mangaList; } - /** - * - */ - _getMangaList( callback ) { - this._getMangaFromPage() - .then( data => { - callback( null, data ); - } - ) - .catch( error => { - console.error( error, this ); - callback( error, undefined ); - } - ); + async _getMangasFromPage(page){ + //https://www.lezhinus.com/lz-api/v2/contents?menu=general&limit=36&offset=0&order=popular + const uri = new URL('/lz-api/v2/comics', this.apiURL); + uri.searchParams.set('menu', 'general'); + uri.searchParams.set('limit', this.mangasPerPage); + uri.searchParams.set('offset', page * this.mangasPerPage); + uri.searchParams.set('order', 'popular'); + uri.searchParams.set('adult_kind', 'all'); + + const request = new Request(uri, this.requestOptions) + const data = await this.fetchJSON(request); + return data.data.map( manga => { + return { + id: manga.alias, // manga.id + title: manga.title + }; + }); } + async _getChapters(manga) { await this._initializeAccount(); /* @@ -198,25 +175,135 @@ export default class Lezhin extends Connector { 30 | 720w | 1080w 40 | 1080w | 1280w */ + + await this.getLzconfig(); + //https://www.lezhin.com/lz-api/v2/inventory_groups/comic_viewer?platform=web&store=web&alias=angel&name=1&preload=false&type=comic_episode + let uri = new URL('https://www.lezhin.com/lz-api/v2/inventory_groups/comic_viewer'); + uri.searchParams.set('platform', 'web'); + uri.searchParams.set('store', 'web'); + uri.searchParams.set('alias', chapter.manga.id); + uri.searchParams.set('name', chapter.id); + uri.searchParams.set('preload', false); + uri.searchParams.set('type', 'comic_episode'); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchJSON(request); - /*the concept is - you get the partial picture url using the premise and all the elements you need - to create the request to get the missing part of the url - (signature, policy, keypair) - - data is returned as - { - imgurl : the partial url - token : the url where to get the json with missing parameters - referer : the chapter referer, just in case its checked + const episode = data.data.extra.episode; + let purchased = episode.coin == 0; + //purchased = purchased || (episode.freedAt && episode.freedAt < Date.now()); + const subscribed = data.data.extra.subscribed; + const updatedAt = episode.updatedAt; + + let pictures = []; + + for (let i = 0; i < episode.scrollsInfo.length; i++){ + + let tokenuri = new URL('/lz-api/v2/cloudfront/signed-url/generate', this.apiURL); + tokenuri.searchParams.set('contentId', episode.idComic); + tokenuri.searchParams.set('episodeId', episode.id); + tokenuri.searchParams.set('purchased', subscribed || purchased); + tokenuri.searchParams.set('q', 30); + tokenuri.searchParams.set('firstCheckType', 'P'); + //get parameters + request = new Request( tokenuri, this.requestOptions ); + request.headers.set('x-referer', this.apiURL); + let response = await this.fetchJSON(request); + //picture final url + let imageurl = new URL('/v2' + episode.scrollsInfo[i].path + '.webp', this.lzConfig.contentsCdnUrl); + imageurl.searchParams.set('purchased', subscribed || purchased); + imageurl.searchParams.set('q', 30); + imageurl.searchParams.set('updated', updatedAt); + //add missing parameters to the image url + imageurl.searchParams.set('Policy', response.data.Policy); + imageurl.searchParams.set('Signature', response.data.Signature); + imageurl.searchParams.set('Key-Pair-Id', response.data['Key-Pair-Id']); + pictures.push(imageurl.href); } - - i also increased the promise timeout to 5s because 2.5 wasnt enough, - even prior to patch the 'd2' error. - - TODO : see how we can handle jpg/webp thing - + + return pictures; + + /* + +const script = ` +new Promise((resolve, reject) => { + setTimeout(() => { + try { + if(window.location.pathname.includes('/login')) { + throw new Error('You need to be logged in to access the content of this chapter!'); + } + const subscribed = __LZ_DATA__.product && __LZ_DATA__.product.subscribed; + const purchased = __LZ_DATA__.purchased && __LZ_DATA__.purchased.includes(__LZ_DATA__.episode.id); + const hasOnlyJPEG = false; + const updated = __LZ_DATA__.episode.updatedAt; + const images = __LZ_DATA__.episode.scrollsInfo.map(x => { + //const extension = ${this.config.forceJPEG.value} || hasOnlyJPEG ? '.jpg' : '.webp'; + const extension ='.webp'; + //request to generate the url + //https://www.lezhinus.com/lz-api/v2/cloudfront/signed-url/generate?contentId=XXXXXXX&episodeId=YYYYYYYYY&purchased=false&q=30&firstCheckType=P + const tokenuri = new URL('/lz-api/v2/cloudfront/signed-url/generate', '${this.apiURL}'); + tokenuri.searchParams.set('contentId', __LZ_DATA__.episode.contentId); + tokenuri.searchParams.set('episodeId', __LZ_DATA__.episode.id); + tokenuri.searchParams.set('purchased', subscribed || purchased); + tokenuri.searchParams.set('q', 30); + tokenuri.searchParams.set('firstCheckType', 'P'); + //picture final url + const uri = new URL('/v2' + x.path + extension, __LZ_CONFIG__.contentsCdnUrl); + uri.searchParams.set('purchased', subscribed || purchased); + uri.searchParams.set('q', 30); + uri.searchParams.set('updated', updated); + return { + imgurl : uri.href, token : tokenuri.href, referer : window.location.href} + ; + }); + resolve(images); + } + catch(error) { + reject(error); + } + }, + 5000); +}); +`; +try{ + const uri = new URL(`${ + this.url} + /comic/${ + chapter.manga.id} + /${ + chapter.id} + `); + let request = new Request(uri, this.requestOptions); + let data = await Engine.Request.fetchUI(request, script); + let imageslist = []; + for (let i = 0; i < data.length; i++){ + let element = data[i]; + let imageurl = new URL(element.imgurl); + //get the missing parameters from the JSON request (unique for each image) + let requesturl = new URL(element.token); + request = new Request( requesturl, this.requestOptions ); + request.headers.set('x-referer', element.referer); + let response = await this.fetchJSON(request); + //add missing parameters to the image url + imageurl.searchParams.set('Policy', response.data.Policy); + imageurl.searchParams.set('Signature', response.data.Signature); + imageurl.searchParams.set('Key-Pair-Id', response.data['Key-Pair-Id']); + imageslist.push(imageurl.href); + } + return (imageslist); +} +catch (e) +{ + throw ('Chapter not purchased / Not logged / Error fetching pages !'); +} */ + + } + async getLzconfig() { + if(this.lzConfig) return; + //get LZCONFIG + const uri = new URL(`${ + this.url} + `); const script = ` new Promise((resolve, reject) => { setTimeout(() => { @@ -224,31 +311,8 @@ export default class Lezhin extends Connector { if(window.location.pathname.includes('/login')) { throw new Error('You need to be logged in to access the content of this chapter!'); } - const subscribed = __LZ_DATA__.product && __LZ_DATA__.product.subscribed; - const purchased = __LZ_DATA__.purchased && __LZ_DATA__.purchased.includes(__LZ_DATA__.episode.id); - const hasOnlyJPEG = false; - const updated = __LZ_DATA__.episode.updatedAt; - const images = __LZ_DATA__.episode.scrollsInfo.map(x => { - //const extension = ${this.config.forceJPEG.value} || hasOnlyJPEG ? '.jpg' : '.webp'; - const extension ='.webp'; - //request to generate the url - //https://www.lezhinus.com/lz-api/v2/cloudfront/signed-url/generate?contentId=XXXXXXX&episodeId=YYYYYYYYY&purchased=false&q=30&firstCheckType=P - const tokenuri = new URL('https://www.lezhinus.com/lz-api/v2/cloudfront/signed-url/generate'); - tokenuri.searchParams.set('contentId', __LZ_DATA__.episode.contentId); - tokenuri.searchParams.set('episodeId', __LZ_DATA__.episode.id); - tokenuri.searchParams.set('purchased', subscribed || purchased); - tokenuri.searchParams.set('q', 30); - tokenuri.searchParams.set('firstCheckType', 'P'); - //picture final url - const uri = new URL('/v2' + x.path + extension, __LZ_CONFIG__.contentsCdnUrl); - uri.searchParams.set('purchased', subscribed || purchased); - uri.searchParams.set('q', 30); - uri.searchParams.set('updated', updated); - return { - imgurl : uri.href, token : tokenuri.href, referer : window.location.href} - ; - }); - resolve(images); + const lz = __LZ_CONFIG__; + resolve(lz); } catch(error) { reject(error); @@ -257,25 +321,59 @@ export default class Lezhin extends Connector { 5000); }); `; - - const uri = new URL(`${this.url}/comic/${chapter.manga.id}/${chapter.id}`); - let request = new Request(uri, this.requestOptions); - let data = await Engine.Request.fetchUI(request, script); - let imageslist = []; - for (let i = 0; i < data.length; i++){ - let element = data[i]; - let imageurl = new URL(element.imgurl); - //get the missing parameters from the JSON request (unique for each image) - let requesturl = new URL(element.token); - request = new Request( requesturl, this.requestOptions ); - request.headers.set('x-referer', element.referer); - let response = await this.fetchJSON(request); - //add missing parameters to the image url - imageurl.searchParams.set('Policy', response.data.Policy); - imageurl.searchParams.set('Signature', response.data.Signature); - imageurl.searchParams.set('Key-Pair-Id', response.data['Key-Pair-Id']); - imageslist.push(imageurl.href); + const request = new Request(uri, this.requestOptions); + const data = await Engine.Request.fetchUI(request, script); + this.lzConfig = data; + } + /* + +_getMangaFromPage( offset, limit ) { + offset = offset || 0; + limit = limit || 500; + let uri = new URL( this.apiURL + '/comics' ); + uri.searchParams.set( 'offset', offset ); + uri.searchParams.set( 'limit', limit ); + uri.searchParams.set( 'country_code', '' ); + uri.searchParams.set( 'store', 'web' ); + uri.searchParams.set( 'adult_kind', 'all' ); + uri.searchParams.set( 'filter', 'all' ); + //uri.searchParams.set( '_', Date.now() ); + return fetch( uri.href, this.requestOptions ) + .then( response => response.json() ) + .then( data => { + if( data.code ) { + throw new Error( data.description ); + } + let mangaList = data.data.map( manga => { + return { + id: manga.alias, // manga.id + title: manga.title + }; + } + ); + if( data.hasNext ) { + return this._getMangaFromPage( offset + limit, limit ) + .then( mangas => mangaList.concat( mangas ) ); + } + else { + return Promise.resolve( mangaList ); } - return (imageslist); } + ); +} +_getMangaList( callback ) { + this._getMangaFromPage() + .then( data => { + callback( null, data ); + } + ) + .catch( error => { + console.error( error, this ); + callback( error, undefined ); + } + ); +} + */ + + } From 0d883055804dbccd6105be8a31c360dfe39531f3 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sun, 4 Dec 2022 10:46:00 +0000 Subject: [PATCH 50/64] Add ReadNovelFULL (not working) Need the investigate why rendering the novel fail --- src/web/mjs/connectors/ReadNovelFull.mjs | 108 +++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/web/mjs/connectors/ReadNovelFull.mjs diff --git a/src/web/mjs/connectors/ReadNovelFull.mjs b/src/web/mjs/connectors/ReadNovelFull.mjs new file mode 100644 index 00000000000..197055fea9f --- /dev/null +++ b/src/web/mjs/connectors/ReadNovelFull.mjs @@ -0,0 +1,108 @@ +import Connector from '../engine/Connector.mjs'; +import Manga from '../engine/Manga.mjs'; + +export default class ReadNovelFull extends Connector { + + constructor() { + super(); + super.id = 'readnovelfull'; + super.label = 'ReadNovelFull'; + this.tags = [ 'novel', 'english' ]; + this.url = 'https://readnovelfull.com'; + this.path = '/novel-list/latest-release-novel'; + this.queryMangas = 'h3.novel-title a'; + + this.novelContentQuery = 'div#chr-content'; + //this.novelObstaclesQuery = 'div.code-block'; + this.novelFormat = 'image/png'; + this.novelWidth = '56em'; // parseInt(1200 / window.devicePixelRatio) + 'px'; + this.novelPadding = '1.5em'; + } + + async _getMangaFromURI(uri) { + const request = new Request(uri, this.requestOptions); + const data = await this.fetchDOM(request, 'meta[property="og:title"]'); + return new Manga(this, uri.pathname, data[0].content.trim()); + } + + async _getMangas() { + let mangaList = []; + const uri = new URL(this.path, this.url); + const request = new Request(uri, this.requestOptions); + const data = await this.fetchDOM(request, 'li.last a'); + const pageCount = parseInt(data[0].getAttribute('data-page'))+1; + for(let page = 1; page <= pageCount; page++) { + let mangas = await this._getMangasFromPage(page); + mangaList.push(...mangas); + } + return mangaList; + } + + async _getMangasFromPage(page) { + let uri = new URL(this.path+'?page=' + page, this.url); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, this.queryMangas); + return data.map(element => { + return { + id: this.getRootRelativeOrAbsoluteLink(element, request.url), + title: element.text.trim() + }; + }); + } + async _getChapters(manga) { + let uri = new URL(manga.id, this.url); + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, 'div#rating'); + const mangaid = data[0].getAttribute('data-novel-id'); + + let apiuri = new URL('/ajax/chapter-archive?novelId='+mangaid, this.url); + request = new Request(apiuri, this.requestOptions); + request.headers.set('x-referer', uri); + request.headers.set('X-Requested-With', 'XMLHttpRequest'); + data = await this.fetchDOM(request, 'a'); + + return data.map(element => { + return { + id: this.getRootRelativeOrAbsoluteLink(element, this.url), + title: element.text.trim() + }; + }).reverse(); + } + + async _getPages(chapter) { + const uri = new URL(chapter.id, this.url); + const request = new Request(uri, this.requestOptions); + return this._getPagesNovel(request); + + } + async _getPagesNovel(request) { + let darkmode = Engine.Settings.NovelColorProfile(); + let script = ` + new Promise(resolve => { + document.body.style.width = '${this.novelWidth}'; + let novel1 = document.querySelector('${this.novelContentQuery}'); + novel1.style.padding = '${this.novelPadding}'; + [...novel1.querySelectorAll(":not(:empty)")].forEach(ele => { + ele.style.backgroundColor = '${darkmode.background}' + ele.style.color = '${darkmode.text}' + }) + novel1.style.backgroundColor = '${darkmode.background}' + novel1.style.color = '${darkmode.text}' + let script = document.createElement('script'); + script.onerror = error => reject(error); + script.onload = async function() { + try{ + let canvas = await html2canvas(novel1); + resolve(canvas.toDataURL('${this.novelFormat}')); + }catch (error){ + reject(error) + } + } + script.src = 'https://html2canvas.hertzen.com/dist/html2canvas.min.js'; + document.body.appendChild(script); + }); + `; + return [ await Engine.Request.fetchUI(request, script, 30000, true) ]; + } + +} \ No newline at end of file From 1ef32f41954b731535dbb8294d2f1e90dab5711f Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 8 Dec 2022 14:20:04 +0000 Subject: [PATCH 51/64] WIP : Mangadig and INKR still need to work on them --- src/web/mjs/connectors/INKR.mjs | 85 +++++++++++++++++++++++++++ src/web/mjs/connectors/Mangadig.mjs | 89 +++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 src/web/mjs/connectors/INKR.mjs create mode 100644 src/web/mjs/connectors/Mangadig.mjs diff --git a/src/web/mjs/connectors/INKR.mjs b/src/web/mjs/connectors/INKR.mjs new file mode 100644 index 00000000000..fb9c7971a90 --- /dev/null +++ b/src/web/mjs/connectors/INKR.mjs @@ -0,0 +1,85 @@ +import Connector from '../engine/Connector.mjs'; +import Manga from '../engine/Manga.mjs'; +export default class INKR extends Connector { + constructor() { + super(); + super.id = 'inkr'; + super.label = 'INKR'; + this.tags = [ 'manga', 'english' ]; + this.url = 'https://comics.inkr.com'; + } + async _getMangaFromURI(uri) { + const id = uri.pathname; + const request = new Request(uri, this.requestOptions); + let data = await this._getNextData(request); + data = LZString.decompressBase64(data.props.pageProps._c); + + const title = data.props.pageProps.initialState.productHome.productHome.product.title; + return new Manga(this, id, title); + } + async _getMangas() { + let msg = 'This website does not provide a manga list, please copy and paste the URL containing the chapters directly from your browser into HakuNeko.'; + throw new Error(msg); + } + async _getChapters(manga) { + const uri = new URL(manga.id, this.url); + const request = new Request(uri, this.requestOptions); + const nextData = await this._getNextData(request); + const episodes = nextData.props.pageProps.initialState.productHome.productHome.episode_list; + const productId = manga.id.split('/').pop(); + return episodes.map(ep => { + return { + id: `${ + nextData.buildId} + /fr/viewer/${ + productId} + /${ + ep.id} + `, + title: ep.title, + }; + }) + .reverse(); + } + async _getPages(chapter) { + const result = await this._fetchChapterNextData(chapter); + const pdata = result.pageProps.initialState.viewer.pData; + const images = pdata.img; + if (images == null) { + throw new Error(`The chapter '${chapter.title}' is neither public, nor purchased!`); + } + return images + .filter(img => !!img.path) + .map(img => { + return this.createConnectorURI({ + url: img.path, + //key: this._getSeed(img.path), + pdata + }); + }); + } + + /************ + * NEXT + *************/ + async _getNextData(request) { + const [data] = await this.fetchDOM(request, '#__NEXT_DATA__'); + return JSON.parse(data.textContent); + } + async _fetchChapterNextData(chapter) { + const parts = chapter.id.split('/'); + const productId = parts[3]; + const episodeId = parts[4]; + const uri = new URL(`_next/data/${chapter.id}.json`, this.url); + const request = new Request(uri, this.requestOptions); + try { + return await this.fetchJSON(request); + } + catch (error) { + console.error(error); + throw new Error(`The chapter '${chapter.title}' is neither public, nor purchased!`); + } + } + + +} \ No newline at end of file diff --git a/src/web/mjs/connectors/Mangadig.mjs b/src/web/mjs/connectors/Mangadig.mjs new file mode 100644 index 00000000000..e6db57f46ae --- /dev/null +++ b/src/web/mjs/connectors/Mangadig.mjs @@ -0,0 +1,89 @@ +import ZYMK from './templates/ZYMK.mjs'; + +export default class Mangadig extends ZYMK { + + constructor() { + super(); + super.id = 'mangadig'; + super.label = 'Mangadig'; + this.tags = [ 'webtoon', 'english' ]; + this.url = 'https://mangadig.com'; + + this.path = '/show?page='; + this.pathSuffix = ''; + this.queryMangaTitle = 'dl.fed-deta-info dd.fed-deta-content h1.fed-part-eone'; + this.queryMangasPageCount = 'div.fed-page-info a.fed-show-sm-inline'; + this.queryMangas = 'ul.fed-list-info li.fed-list-item a.fed-list-title'; + this.queryChapters = 'div.all_data_list ul li a'; + + this.config.throttle = { + label: 'Throttle Requests [ms]', + description: 'Enter the timespan in [ms] to delay consecuitive HTTP requests.\nThe website may block images for to many consecuitive requests.', + input: 'numeric', + min: 50, + max: 1000, + value: 250 + }; + + this.decryptKey1Arr = ["x2lBpPpg0JKOYl49", "jaXDrsWpOqhEKM48"]; + this.decryptKey2Arr = ["x2lBpPpg0JKOYl49"]; + + + } + + async _getPages(chapter) { + const uri = new URL(chapter.id, this.url); + const request = new Request(uri, this.requestOptions); + const script =` + new Promise(resolve => { + resolve(C_DATA); + }); + `; + + let C_DATA = await Engine.Request.fetchUI(request, script, 60000, false); + + + let result = this.downloadParse(C_DATA); + console.log(result); + + } + + + downloadParse(encodedData) { + let decryptedData = this.decodeAndDecrypt(encodedData,this.decryptKey1Arr ); + let mh_info = []; + eval(decryptedData); // mh_info + + let decryptedRelativePath = this.decodeAndDecrypt(mh_info.enc_code2, this.decryptKey2Arr); + let decryptedTotalPages = this.decodeAndDecrypt(mh_info.enc_code1, this.decryptKey1Arr); + } + + + decodeAndDecrypt(value, keyArr) { + const options = { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7 + }; + + value = CryptoJS.enc.Base64.parse(value).toString(CryptoJS.enc.Utf8); + for (let i = 0; i < keyArr.length; i++) { + try { + let s = CryptoJS.enc.Utf8.parse(keyArr[i]); + return CryptoJS.AES.decrypt(value, s, options).toString(CryptoJS.enc.Utf8); + } catch (err) { + console.log(err.message) + } + } + } + + + async _handleConnectorURI(payload) { + const request = new Request(payload.url, this.requestOptions); + request.headers.set('x-referer', payload.referer); + const response = await fetch(request); + let data = await response.blob(); + data = await this._blobToBuffer(data); + this._applyRealMime(data); + return data; + } +} \ No newline at end of file From a5814f0faf0a619de27c73e771197426cb4c28ad Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Fri, 9 Dec 2022 18:13:47 +0000 Subject: [PATCH 52/64] Add KickassAnimeRo Fixes https://github.com/manga-download/hakuneko/issues/4155 --- src/web/mjs/connectors/KickassAnimeRo.mjs | 93 +++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/web/mjs/connectors/KickassAnimeRo.mjs diff --git a/src/web/mjs/connectors/KickassAnimeRo.mjs b/src/web/mjs/connectors/KickassAnimeRo.mjs new file mode 100644 index 00000000000..1afd655f002 --- /dev/null +++ b/src/web/mjs/connectors/KickassAnimeRo.mjs @@ -0,0 +1,93 @@ +import Connector from '../engine/Connector.mjs'; +import Manga from '../engine/Manga.mjs'; +import Kaas from '../videostreams/Kaas.mjs'; + + +export default class KickassAnimeRo extends Connector { + + constructor() { + super(); + super.id = 'kickassanimero'; + super.label = 'KickassAnimeRo'; + this.tags = [ 'anime', 'english' ]; + this.url = 'https://www2.kickassanime.ro'; + //this.bannedHosts = ['Steamango', 'Oload', 'OpenUpload', 'Bestream']; //Dead websites + } + +/* + async _getMangaFromURI(uri) { + const request = new Request(uri, this.requestOptions); + const data = await this.fetchDOM(request, 'meta[property="og:title"]'); + return new Manga(this, uri.pathname, data[0].content.trim()); + } +*/ + + async _getMangas() { + const uri = new URL('/anime-list', this.url); + const data = await this.getAppData(uri); + return data.animes.map(element => { + return { + id : element.slug, + title : element.name.trim() + } + }) + } + + async _getChapters(manga) { + const uri = new URL(manga.id, this.url); + const data = await this.getAppData(uri); + return data.anime.episodes.map(element => { + return { + id: element.slug, + title: element.epnum.trim() + }; + }); + } + + async _getPages(chapter) { + + const uri = new URL(chapter.id, this.url); + const request = new Request(uri, this.requestOptions); + const data = await this.getAppData(uri); + + let playersList = []; + //default hoster : KAAS + for (let i = 1; i < 5; i++){ + let elname = 'link'+i; + (data.episode[elname].trim() != '') ? playersList.push({host : 'KAAS', link : data.episode[elname]}) : false; + } + /* + //external hosters + data.ext_servers.map(element =>{ + !this.bannedHosts.includes(element.host.name) ? playersList.push({host : element.name, link : element.link}) :false; + }); + */ + + const vidlink = playersList.find(element => element.host.match('KAAS')); + if (!vidlink) { + throw new Error ('No supported hoster found !'); + } + + //Check if link is external + if (this._uri.href.match(/\/axplayer/)){ + const realurl = decodeURI(this._uri.searchParams.get('data')); + + throw new Error ('External hoster found !'); + + + } else { + const vid = await new Kaas(vidlink.link).getStream(); + return { mirrors: [ vid ], subtitles: [] }; + } + } + + async getAppData(url) { + const request = new Request(url, this.requestOptions); + const script = `new Promise(resolve => { + resolve(window.appData); + });`; + return await Engine.Request.fetchUI(request, script, 5000); + } + + +} \ No newline at end of file From 89d347577cddbb58bcd68c22b6181d51ff72d395 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Fri, 9 Dec 2022 18:14:52 +0000 Subject: [PATCH 53/64] Add Kaas (video host for KickAssAnime) --- src/web/mjs/videostreams/Kaas.mjs | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/web/mjs/videostreams/Kaas.mjs diff --git a/src/web/mjs/videostreams/Kaas.mjs b/src/web/mjs/videostreams/Kaas.mjs new file mode 100644 index 00000000000..681d4dfc9de --- /dev/null +++ b/src/web/mjs/videostreams/Kaas.mjs @@ -0,0 +1,43 @@ +export default class Kaas { + + constructor(url) { + this._uri = new URL(url); + } + + async getStream() { + + + if (this._uri.href.match(/\/axplayer/)){ + const realurl = decodeURI(this._uri.searchParams.get('data')); + + throw new Error('Kaas : this use an external player, you need to implement it :/'); + + } + + if (this._uri.href.match(/\/dust\/player/)){ + //get window.sources + let script = ` + new Promise(resolve => { + resolve(sources); + }); + `; + let request = new Request(this._uri); + const sources = await Engine.Request.fetchUI(request, script, 3000); + + const mav = sources.find(element => element.name.match(/MAVERICK/i)).src; + const referer = new URL(mav); + + const videoid = referer.href.match(/\/embed\/(\S+)$/)[1]; + const apiurl = new URL('/api/source/'+videoid, referer.origin); + + request = new Request(apiurl); + request.headers.set('x-referer', referer); + request.headers.set('accept', 'application/json, text/plain, */*'); + const response = await fetch(request); + const data = await response.json(); + return new URL(data.hls, referer.origin).href; + } + + + } +} \ No newline at end of file From 1c7af9f3b190f5860fc575c8e78db899828404f1 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sun, 11 Dec 2022 13:57:02 +0100 Subject: [PATCH 54/64] First attempt to handle OK.ru streams --- src/web/mjs/videostreams/Okru.mjs | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/web/mjs/videostreams/Okru.mjs diff --git a/src/web/mjs/videostreams/Okru.mjs b/src/web/mjs/videostreams/Okru.mjs new file mode 100644 index 00000000000..282e8d48727 --- /dev/null +++ b/src/web/mjs/videostreams/Okru.mjs @@ -0,0 +1,34 @@ +export default class Okru { + constructor(url) { + this._uri = new URL(url); + } + async getStream(resolution) { + /* + * mobile + * low + * sd + * hd + */ + const script = ` + new Promise((resolve, reject) => { + setTimeout(() => { + try { + const el = document.querySelector('div[data-module="OKVideo"]'); + el.click(); + resolve(el.getAttribute('data-options')); + } + catch(error) { + reject(error); + } + }, + 3000); + }); + `; + const request = new Request(this._uri); + const response = await Engine.Request.fetchUI(request, script, 10000); + const data = JSON.parse(JSON.parse(response).flashvars.metadata); + let video = (data.videos.find(video => video.name == resolution)); + (video) ? video = video.url : video = data.videos[0].url; + return video; + } +} From 41599cbc40a47da1ec691d50f116c3f049a843db Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Tue, 13 Dec 2022 11:12:03 +0000 Subject: [PATCH 55/64] Add Cuutruyen connector pictures are still scrambled tho --- src/web/mjs/connectors/Cuutruyen.mjs | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/web/mjs/connectors/Cuutruyen.mjs diff --git a/src/web/mjs/connectors/Cuutruyen.mjs b/src/web/mjs/connectors/Cuutruyen.mjs new file mode 100644 index 00000000000..3c45a4cb96b --- /dev/null +++ b/src/web/mjs/connectors/Cuutruyen.mjs @@ -0,0 +1,62 @@ +import Connector from '../engine/Connector.mjs'; +import Manga from '../engine/Manga.mjs'; + +export default class Cuutruyen extends Connector { + + constructor() { + super(); + super.id = 'cuutruyen'; + super.label = 'Cuutruyen'; + this.tags = [ 'manga', 'vietnamese' ]; + this.url = 'https://cuutruyen.net'; + this.api = 'https://kakarot.cuutruyen.net'; + } + async _getMangaFromURI(uri) { + const mangaid = uri.href.match(/\/mangas\/([0-9]+)/)[1]; + const req = new URL('/api/v1/mangas/'+mangaid, this.api); + const request = new Request(req, this.requestOptions); + const data = await this.fetchJSON(request); + return new Manga(this, mangaid, data.data.attributes.name.trim()); + } + async _getMangas() { + let mangaList = []; + for (let page = 1, run = true; run; page++) { + const mangas = await this._getMangasFromPage(page); + mangas.length > 0 ? mangaList.push(...mangas) : run = false; + } + return mangaList; + } + async _getMangasFromPage(page) { + const uri = new URL('/api/v1/mangas?page[size]=50&page[number]='+page, this.api); + const request = new Request(uri, this.requestOptions); + const data = await this.fetchJSON(request); + return data.data.map(element => { + return { + id: element.id, + title: element.attributes.name.trim() + }; + }); + } + async _getChapters(manga) { + const uri = new URL('/api/v1/chapter_listings/'+manga.id, this.api); + const request = new Request(uri, this.requestOptions); + const data = await this.fetchJSON(request); + const chapters = JSON.parse(data.data.attributes.chapters); + return chapters.map(element => { + return { + id: element.id, + title: 'Chapter '+ element.number + ' '+ element.name.trim() + }; + }); + } + async _getPages(chapter) { + const uri = new URL('/api/v1/readings/'+chapter.id, this.api); + const request = new Request(uri, this.requestOptions); + const data = await this.fetchJSON(request); + const pages = JSON.parse(data.data.attributes.pages); + return pages.map(image => this.getAbsolutePath(image.imageUrl, request.url)); + } + + + +} \ No newline at end of file From c30430f5bdf8cb5031b8563799885b087526003d Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 15 Jun 2023 14:10:28 +0000 Subject: [PATCH 56/64] INKR : finally it works --- src/web/mjs/connectors/INKR.mjs | 322 ++++++++++++++++++++++++++------ 1 file changed, 270 insertions(+), 52 deletions(-) diff --git a/src/web/mjs/connectors/INKR.mjs b/src/web/mjs/connectors/INKR.mjs index fb9c7971a90..a20159007f3 100644 --- a/src/web/mjs/connectors/INKR.mjs +++ b/src/web/mjs/connectors/INKR.mjs @@ -1,5 +1,6 @@ import Connector from '../engine/Connector.mjs'; import Manga from '../engine/Manga.mjs'; + export default class INKR extends Connector { constructor() { super(); @@ -7,14 +8,21 @@ export default class INKR extends Connector { super.label = 'INKR'; this.tags = [ 'manga', 'english' ]; this.url = 'https://comics.inkr.com'; + this.nextInstance = 'b023df32bc9708e85db0b51983a2e76fce7be924'; + } + + async _initializeConnector() { + const uri = new URL(this.url); + const request = new Request(uri.href, this.requestOptions); + this.nextInstance = await Engine.Request.fetchUI(request, `__NEXT_DATA__.buildId`); + } + async _getMangaFromURI(uri) { - const id = uri.pathname; + const id = uri.pathname.match(/\/title\/([^/]+)/)[1]; const request = new Request(uri, this.requestOptions); - let data = await this._getNextData(request); - data = LZString.decompressBase64(data.props.pageProps._c); - - const title = data.props.pageProps.initialState.productHome.productHome.product.title; + const data =await this.fetchDOM(request, 'meta[property="og:image:alt"]'); + const title = data[0].content.trim(); return new Manga(this, id, title); } async _getMangas() { @@ -22,64 +30,274 @@ export default class INKR extends Connector { throw new Error(msg); } async _getChapters(manga) { - const uri = new URL(manga.id, this.url); + //https://comics.inkr.com/_next/data/b023df32bc9708e85db0b51983a2e76fce7be924/title/1227-a-sign-of-affection/chapters.json + const uri = new URL(`/_next/data/${this.nextInstance}/title/${manga.id}/chapters.json`, this.url); const request = new Request(uri, this.requestOptions); - const nextData = await this._getNextData(request); - const episodes = nextData.props.pageProps.initialState.productHome.productHome.episode_list; - const productId = manga.id.split('/').pop(); - return episodes.map(ep => { - return { - id: `${ - nextData.buildId} - /fr/viewer/${ - productId} - /${ - ep.id} - `, - title: ep.title, - }; - }) - .reverse(); + let data = await this.fetchJSON(request); + data = LZString.decompressFromBase64(data.pageProps._c); + data = JSON.parse(data); + const obj = unpack(data[0], data[1]); + + const chaptersIndexes = obj.icd.find(element => element[0].startsWith('ik-title'))[1].chapterList; + const chapters = obj.icd.filter(element => chaptersIndexes.includes(element[0])); + + return chapters + .sort(function(a, b) { + return a[1].order - b[1].order; + }) + .map(chapter => { + return{ + id: chapter[1].oid.match(/\d+/), + title : chapter[1].name.trim() + }; + }); + } async _getPages(chapter) { - const result = await this._fetchChapterNextData(chapter); - const pdata = result.pageProps.initialState.viewer.pData; - const images = pdata.img; - if (images == null) { - throw new Error(`The chapter '${chapter.title}' is neither public, nor purchased!`); - } - return images - .filter(img => !!img.path) - .map(img => { - return this.createConnectorURI({ - url: img.path, - //key: this._getSeed(img.path), - pdata - }); - }); + const url = new URL(`/title/${chapter.manga.id}/chapter/${chapter.id}`, this.url); + let data = await this._getNextData(url); + + data = LZString.decompressFromBase64(data.props.pageProps._c); + data = JSON.parse(data); + const obj = unpack(data[0], data[1]); + + const ikchapter = 'ik-chapter-'+ chapter.id; + const chap = obj.icd.find(element=> element[0] == ikchapter); + return chap[1].chapterPages.map(page => page.url+'/p.jpg'); } - + /************ * NEXT - *************/ + *************/ async _getNextData(request) { const [data] = await this.fetchDOM(request, '#__NEXT_DATA__'); return JSON.parse(data.textContent); } - async _fetchChapterNextData(chapter) { - const parts = chapter.id.split('/'); - const productId = parts[3]; - const episodeId = parts[4]; - const uri = new URL(`_next/data/${chapter.id}.json`, this.url); - const request = new Request(uri, this.requestOptions); - try { - return await this.fetchJSON(request); - } - catch (error) { - console.error(error); - throw new Error(`The chapter '${chapter.title}' is neither public, nor purchased!`); + +} + +const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; +let magicalMap = {}; +for (let h = 0; h < charset.length; h++) { + const t = charset[h]; + magicalMap[t] = h; +} + +const mapsize = charset.length; + +var decodeNum = function (t) { + return t = t.replace('n|', ''), + s_to_num(t); +}; + +var decodeKey= function(t) { + return 'number' === typeof t ? t : s_to_int(t); +}; + +var decodeBool= function(t) { + switch (t) { + case 'b|T': + return !0; + case 'b|F': + return !1; + } + return !!t; +}; +var decodeStr= function(t) { + return 's|' === t[0] + t[1] ? t.substr(2) : t; +}; + +var d= function(t) { + return ':' === t[0] ? s(t.substring(1)).toString() : s_to_int(t).toString(); +}; + +var s= function(t) { + /* + let e = BigInt(0); + let n = BigInt(1); + const i = BigInt(r); + for (let r = t.length - 1; r >= 0; r--) { + const s = t[r]; + let a = BigInt(o[s]); + a *= n, + e += a, + n *= i; } + return e;*/ +}; + +var s_to_int= function(t) { + let e = 0, + n = 1; + for (let i = t.length - 1; i >= 0; i--) { + const s = t[i]; + let a = magicalMap[s]; + a *= n; + e += a; + n *= mapsize; + } + return e; +}; + +var s_to_num= function(e) { + if ('-' === e[0]) return - s_to_num(e.substr(1)); + let[n, + r, + o] = e.split('.'); + if (!r) return s_to_int(n); + n = d(n), + r = d(r), + r = u(r); + let s = n + '.' + r; + if (o) { + s += 'e'; + let t = !1; + '-' === o[0] && + (t = !0, o = o.slice(1)), + o = d(o), + o = u(o), + s += t ? - o : + o; } + return + s; +}; +var u= function(t) { + return t.split('').reverse().join(''); +}; -} \ No newline at end of file +var unpack = function (t, e) { + if ('' === e || '_' === e) return null; + const n = t[decodeKey(e)]; + if (null === n) return n; + switch (typeof n) { + case 'undefined': + case 'number': + return n; + case 'string': + switch (n[0] + n[1]) { + case 'b|': + return decodeBool(n); + case 'o|': + return function (t, e) { + if ('o|' === e) return { + }; + const n = {}, + r = e.split('|'); + let o = unpack(t, r[1]); + const i = r.length; + i - 2 !== 1 || + Array.isArray(o) || + (o = [ + o + ]); + for (let a = 2; a < i; a++) { + const e = o[a - 2]; + let i = r[a]; + i = unpack(t, i), + n[e] = i; + } + return n; + }(t, n); + case 'n|': + return decodeNum(n); + case 'a|': + return function (t, e) { + if ('a|' === e) return []; + const n = e.split('|'), + r = n.length - 1, + o = new Array(r); + for (let i = 0; i < r; i++) { + let e = n[i + 1]; + e = unpack(t, e), + o[i] = e; + } + return o; + }(t, n); + default: + return decodeStr(n); + } + } + return null; +}; + +var LZString=function() { + function o(o, r) { + if(!t[o]) { + t[o]={}; for(var n=0; ne; e++) { + var s=r.charCodeAt(e); n[2*e]=s>>>8, n[2*e+1]=s%256; + }return n; + }, decompressFromUint8Array:function(o) { + if(null===o||void 0===o)return i.decompress(o); for(var n=new Array(o.length/2), e=0, t=n.length; t>e; e++)n[e]=256*o[2*e]+o[2*e+1]; var s=[]; return n.forEach(function(o) { + s.push(r(o)); + }), i.decompress(s.join("")); + }, compressToEncodedURIComponent:function(o) { + return null==o?"":i._compress(o, 6, function(o) { + return e.charAt(o); + }); + }, decompressFromEncodedURIComponent:function(r) { + return null==r?"":""==r?null:(r=r.replace(/ /g, "+"), i._decompress(r.length, 32, function(n) { + return o(e, r.charAt(n)); + })); + }, compress:function(o) { + return i._compress(o, 16, function(o) { + return r(o); + }); + }, _compress:function(o, r, n) { + if(null==o)return""; var e, t, i, s={}, p={}, u="", c="", a="", l=2, f=3, h=2, d=[], m=0, v=0; for(i=0; ie; e++)m<<=1, v==r-1?(v=0, d.push(n(m)), m=0):v++; for(t=a.charCodeAt(0), e=0; 8>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; + }else{ + for(t=1, e=0; h>e; e++)m=m<<1|t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t=0; for(t=a.charCodeAt(0), e=0; 16>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; + }l--, 0==l&&(l=Math.pow(2, h), h++), delete p[a]; + }else for(t=s[a], e=0; h>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; l--, 0==l&&(l=Math.pow(2, h), h++), s[c]=f++, a=String(u); + }if(""!==a) { + if(Object.prototype.hasOwnProperty.call(p, a)) { + if(a.charCodeAt(0)<256) { + for(e=0; h>e; e++)m<<=1, v==r-1?(v=0, d.push(n(m)), m=0):v++; for(t=a.charCodeAt(0), e=0; 8>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; + }else{ + for(t=1, e=0; h>e; e++)m=m<<1|t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t=0; for(t=a.charCodeAt(0), e=0; 16>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; + }l--, 0==l&&(l=Math.pow(2, h), h++), delete p[a]; + }else for(t=s[a], e=0; h>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; l--, 0==l&&(l=Math.pow(2, h), h++); + }for(t=2, e=0; h>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; for(;;) { + if(m<<=1, v==r-1) { + d.push(n(m)); break; + }v++; + }return d.join(""); + }, decompress:function(o) { + return null==o?"":""==o?null:i._decompress(o.length, 32768, function(r) { + return o.charCodeAt(r); + }); + }, _decompress:function(o, n, e) { + var t, i, s, p, u, c, a, l, f=[], h=4, d=4, m=3, v="", w=[], A={val:e(0), position:n, index:1}; for(i=0; 3>i; i+=1)f[i]=i; for(p=0, c=Math.pow(2, 2), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(t=p) { + case 0:for(p=0, c=Math.pow(2, 8), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 1:for(p=0, c=Math.pow(2, 16), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 2:return""; + }for(f[3]=l, s=l, w.push(l); ;) { + if(A.index>o)return""; for(p=0, c=Math.pow(2, m), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(l=p) { + case 0:for(p=0, c=Math.pow(2, 8), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; f[d++]=r(p), l=d-1, h--; break; case 1:for(p=0, c=Math.pow(2, 16), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; f[d++]=r(p), l=d-1, h--; break; case 2:return w.join(""); + }if(0==h&&(h=Math.pow(2, m), m++), f[l])v=f[l]; else{ + if(l!==d)return null; v=s+s.charAt(0); + }w.push(v), f[d++]=s+v.charAt(0), h--, s=v, 0==h&&(h=Math.pow(2, m), m++); + } + }}; return i; +}(); From dccaa045cb54b2ecde6cc19813928d22b34687de Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 15 Jun 2023 14:20:18 +0000 Subject: [PATCH 57/64] INKR: handle no unlocked chapters --- src/web/mjs/connectors/INKR.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/mjs/connectors/INKR.mjs b/src/web/mjs/connectors/INKR.mjs index a20159007f3..801240f639f 100644 --- a/src/web/mjs/connectors/INKR.mjs +++ b/src/web/mjs/connectors/INKR.mjs @@ -63,7 +63,7 @@ export default class INKR extends Connector { const ikchapter = 'ik-chapter-'+ chapter.id; const chap = obj.icd.find(element=> element[0] == ikchapter); - return chap[1].chapterPages.map(page => page.url+'/p.jpg'); + return !chap[1].chapterPages ? [] : chap[1].chapterPages.map(page => page.url+'/p.jpg'); } /************ From c7d2cd1d4f56ab90db2ffcd7439293d3fec3163a Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Thu, 15 Jun 2023 15:01:01 +0000 Subject: [PATCH 58/64] INKR : code refactoring <3 --- src/web/mjs/connectors/INKR.mjs | 362 ++++++++++++++------------------ 1 file changed, 153 insertions(+), 209 deletions(-) diff --git a/src/web/mjs/connectors/INKR.mjs b/src/web/mjs/connectors/INKR.mjs index 801240f639f..54da4d053a9 100644 --- a/src/web/mjs/connectors/INKR.mjs +++ b/src/web/mjs/connectors/INKR.mjs @@ -36,7 +36,7 @@ export default class INKR extends Connector { let data = await this.fetchJSON(request); data = LZString.decompressFromBase64(data.pageProps._c); data = JSON.parse(data); - const obj = unpack(data[0], data[1]); + const obj = unpacker.unpack(data[0], data[1]); const chaptersIndexes = obj.icd.find(element => element[0].startsWith('ik-title'))[1].chapterList; const chapters = obj.icd.filter(element => chaptersIndexes.includes(element[0])); @@ -59,16 +59,13 @@ export default class INKR extends Connector { data = LZString.decompressFromBase64(data.props.pageProps._c); data = JSON.parse(data); - const obj = unpack(data[0], data[1]); + const obj = unpacker.unpack(data[0], data[1]); const ikchapter = 'ik-chapter-'+ chapter.id; const chap = obj.icd.find(element=> element[0] == ikchapter); return !chap[1].chapterPages ? [] : chap[1].chapterPages.map(page => page.url+'/p.jpg'); } - /************ - * NEXT - *************/ async _getNextData(request) { const [data] = await this.fetchDOM(request, '#__NEXT_DATA__'); return JSON.parse(data.textContent); @@ -76,43 +73,111 @@ export default class INKR extends Connector { } -const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; -let magicalMap = {}; -for (let h = 0; h < charset.length; h++) { - const t = charset[h]; - magicalMap[t] = h; -} - -const mapsize = charset.length; - -var decodeNum = function (t) { - return t = t.replace('n|', ''), - s_to_num(t); -}; +/***************************************************/ +// BEGIN INKR +/**************************************************/ -var decodeKey= function(t) { - return 'number' === typeof t ? t : s_to_int(t); -}; - -var decodeBool= function(t) { - switch (t) { - case 'b|T': - return !0; - case 'b|F': - return !1; +var unpacker = function() { + const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; + const magicalMap = {}; + for (let h = 0; h < charset.length; h++) { + const t = charset[h]; + magicalMap[t] = h; } - return !!t; -}; -var decodeStr= function(t) { - return 's|' === t[0] + t[1] ? t.substr(2) : t; -}; - -var d= function(t) { - return ':' === t[0] ? s(t.substring(1)).toString() : s_to_int(t).toString(); -}; - -var s= function(t) { - /* + const mapsize = charset.length; + var instanceObj={ + unpack:function (t, e) { + if ('' === e || '_' === e) return null; + const n = t[instanceObj.decodeKey(e)]; + if (null === n) return n; + switch (typeof n) { + case 'undefined': + case 'number': + return n; + case 'string': + switch (n[0] + n[1]) { + case 'b|': + return instanceObj.decodeBool(n); + case 'o|': + return function (t, e) { + if ('o|' === e) return { + }; + const n = {}, + r = e.split('|'); + let o = instanceObj.unpack(t, r[1]); + const i = r.length; + i - 2 !== 1 ||Array.isArray(o) ||(o = [o]); + for (let a = 2; a < i; a++) { + const e = o[a - 2]; + let i = r[a]; + i = instanceObj.unpack(t, i), + n[e] = i; + } + return n; + }(t, n); + case 'n|': + return instanceObj.decodeNum(n); + case 'a|': + return function (t, e) { + if ('a|' === e) return []; + const n = e.split('|'), + r = n.length - 1, + o = new Array(r); + for (let i = 0; i < r; i++) { + let e = n[i + 1]; + e = instanceObj.unpack(t, e), + o[i] = e; + } + return o; + }(t, n); + default: + return instanceObj.decodeStr(n); + } + } + return null; + }, + + d:function(t) { + return ':' === t[0] ? instanceObj.s(t.substring(1)).toString() : instanceObj.s_to_int(t).toString(); + }, + u:function(t) { + return t.split('').reverse().join(''); + }, + s_to_num:function(e) { + if ('-' === e[0]) return - instanceObj.s_to_num(e.substr(1)); + let[n, + r, + o] = e.split('.'); + if (!r) return instanceObj.s_to_int(n); + n = instanceObj.d(n), + r = instanceObj.d(r), + r = instanceObj.u(r); + let s = n + '.' + r; + if (o) { + s += 'e'; + let t = !1; + '-' === o[0] && + (t = !0, o = o.slice(1)), + o = instanceObj.d(o), + o = instanceObj.u(o), + s += t ? - o : + o; + } + return + s; + }, + s_to_int: function(t) { + let e = 0, + n = 1; + for (let i = t.length - 1; i >= 0; i--) { + const s = t[i]; + let a = magicalMap[s]; + a *= n; + e += a; + n *= mapsize; + } + return e; + }, + s: function(t) { + /* let e = BigInt(0); let n = BigInt(1); const i = BigInt(r); @@ -124,180 +189,59 @@ var s= function(t) { n *= i; } return e;*/ -}; - -var s_to_int= function(t) { - let e = 0, - n = 1; - for (let i = t.length - 1; i >= 0; i--) { - const s = t[i]; - let a = magicalMap[s]; - a *= n; - e += a; - n *= mapsize; - } - return e; -}; - -var s_to_num= function(e) { - if ('-' === e[0]) return - s_to_num(e.substr(1)); - let[n, - r, - o] = e.split('.'); - if (!r) return s_to_int(n); - n = d(n), - r = d(r), - r = u(r); - let s = n + '.' + r; - if (o) { - s += 'e'; - let t = !1; - '-' === o[0] && - (t = !0, o = o.slice(1)), - o = d(o), - o = u(o), - s += t ? - o : + o; - } - return + s; -}; - -var u= function(t) { - return t.split('').reverse().join(''); -}; - -var unpack = function (t, e) { - if ('' === e || '_' === e) return null; - const n = t[decodeKey(e)]; - if (null === n) return n; - switch (typeof n) { - case 'undefined': - case 'number': - return n; - case 'string': - switch (n[0] + n[1]) { - case 'b|': - return decodeBool(n); - case 'o|': - return function (t, e) { - if ('o|' === e) return { - }; - const n = {}, - r = e.split('|'); - let o = unpack(t, r[1]); - const i = r.length; - i - 2 !== 1 || - Array.isArray(o) || - (o = [ - o - ]); - for (let a = 2; a < i; a++) { - const e = o[a - 2]; - let i = r[a]; - i = unpack(t, i), - n[e] = i; - } - return n; - }(t, n); - case 'n|': - return decodeNum(n); - case 'a|': - return function (t, e) { - if ('a|' === e) return []; - const n = e.split('|'), - r = n.length - 1, - o = new Array(r); - for (let i = 0; i < r; i++) { - let e = n[i + 1]; - e = unpack(t, e), - o[i] = e; - } - return o; - }(t, n); - default: - return decodeStr(n); + }, + decodeNum: function (t) { + return t = t.replace('n|', ''), + instanceObj.s_to_num(t); + }, + + decodeKey: function(t) { + return 'number' === typeof t ? t : instanceObj.s_to_int(t); + }, + + decodeBool: function(t) { + switch (t) { + case 'b|T': + return !0; + case 'b|F': + return !1; } - } - return null; -}; + return !!t; + }, + decodeStr: function(t) { + return 's|' === t[0] + t[1] ? t.substr(2) : t; + }, + }; + return instanceObj; +}(); var LZString=function() { function o(o, r) { if(!t[o]) { t[o]={}; for(var n=0; ne; e++) { - var s=r.charCodeAt(e); n[2*e]=s>>>8, n[2*e+1]=s%256; - }return n; - }, decompressFromUint8Array:function(o) { - if(null===o||void 0===o)return i.decompress(o); for(var n=new Array(o.length/2), e=0, t=n.length; t>e; e++)n[e]=256*o[2*e]+o[2*e+1]; var s=[]; return n.forEach(function(o) { - s.push(r(o)); - }), i.decompress(s.join("")); - }, compressToEncodedURIComponent:function(o) { - return null==o?"":i._compress(o, 6, function(o) { - return e.charAt(o); - }); - }, decompressFromEncodedURIComponent:function(r) { - return null==r?"":""==r?null:(r=r.replace(/ /g, "+"), i._decompress(r.length, 32, function(n) { - return o(e, r.charAt(n)); - })); - }, compress:function(o) { - return i._compress(o, 16, function(o) { - return r(o); - }); - }, _compress:function(o, r, n) { - if(null==o)return""; var e, t, i, s={}, p={}, u="", c="", a="", l=2, f=3, h=2, d=[], m=0, v=0; for(i=0; ie; e++)m<<=1, v==r-1?(v=0, d.push(n(m)), m=0):v++; for(t=a.charCodeAt(0), e=0; 8>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; - }else{ - for(t=1, e=0; h>e; e++)m=m<<1|t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t=0; for(t=a.charCodeAt(0), e=0; 16>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; - }l--, 0==l&&(l=Math.pow(2, h), h++), delete p[a]; - }else for(t=s[a], e=0; h>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; l--, 0==l&&(l=Math.pow(2, h), h++), s[c]=f++, a=String(u); - }if(""!==a) { - if(Object.prototype.hasOwnProperty.call(p, a)) { - if(a.charCodeAt(0)<256) { - for(e=0; h>e; e++)m<<=1, v==r-1?(v=0, d.push(n(m)), m=0):v++; for(t=a.charCodeAt(0), e=0; 8>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; - }else{ - for(t=1, e=0; h>e; e++)m=m<<1|t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t=0; for(t=a.charCodeAt(0), e=0; 16>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; - }l--, 0==l&&(l=Math.pow(2, h), h++), delete p[a]; - }else for(t=s[a], e=0; h>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; l--, 0==l&&(l=Math.pow(2, h), h++); - }for(t=2, e=0; h>e; e++)m=m<<1|1&t, v==r-1?(v=0, d.push(n(m)), m=0):v++, t>>=1; for(;;) { - if(m<<=1, v==r-1) { - d.push(n(m)); break; - }v++; - }return d.join(""); - }, decompress:function(o) { - return null==o?"":""==o?null:i._decompress(o.length, 32768, function(r) { - return o.charCodeAt(r); - }); - }, _decompress:function(o, n, e) { - var t, i, s, p, u, c, a, l, f=[], h=4, d=4, m=3, v="", w=[], A={val:e(0), position:n, index:1}; for(i=0; 3>i; i+=1)f[i]=i; for(p=0, c=Math.pow(2, 2), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(t=p) { - case 0:for(p=0, c=Math.pow(2, 8), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 1:for(p=0, c=Math.pow(2, 16), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 2:return""; - }for(f[3]=l, s=l, w.push(l); ;) { - if(A.index>o)return""; for(p=0, c=Math.pow(2, m), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(l=p) { - case 0:for(p=0, c=Math.pow(2, 8), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; f[d++]=r(p), l=d-1, h--; break; case 1:for(p=0, c=Math.pow(2, 16), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; f[d++]=r(p), l=d-1, h--; break; case 2:return w.join(""); - }if(0==h&&(h=Math.pow(2, m), m++), f[l])v=f[l]; else{ - if(l!==d)return null; v=s+s.charAt(0); - }w.push(v), f[d++]=s+v.charAt(0), h--, s=v, 0==h&&(h=Math.pow(2, m), m++); - } - }}; return i; + }var r=String.fromCharCode, + n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + // e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$", + t={}, + i={ + decompressFromBase64:function(r) { + return null==r?"":""==r?null:i._decompress(r.length, 32, function(e) { + return o(n, r.charAt(e)); + }); + }, _decompress:function(o, n, e) { + var t, i, s, p, u, c, a, l, f=[], h=4, d=4, m=3, v="", w=[], A={val:e(0), position:n, index:1}; for(i=0; 3>i; i+=1)f[i]=i; for(p=0, c=Math.pow(2, 2), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(t=p) { + case 0:for(p=0, c=Math.pow(2, 8), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 1:for(p=0, c=Math.pow(2, 16), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 2:return""; + }for(f[3]=l, s=l, w.push(l); ;) { + if(A.index>o)return""; for(p=0, c=Math.pow(2, m), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(l=p) { + case 0:for(p=0, c=Math.pow(2, 8), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; f[d++]=r(p), l=d-1, h--; break; case 1:for(p=0, c=Math.pow(2, 16), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; f[d++]=r(p), l=d-1, h--; break; case 2:return w.join(""); + }if(0==h&&(h=Math.pow(2, m), m++), f[l])v=f[l]; else{ + if(l!==d)return null; v=s+s.charAt(0); + }w.push(v), f[d++]=s+v.charAt(0), h--, s=v, 0==h&&(h=Math.pow(2, m), m++); + } + }}; return i; }(); + +/***************************************************/ +// END INKR +/**************************************************/ From c7abff0ccef9545af68d17cde78df2ad73e62725 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sat, 17 Jun 2023 10:54:52 +0000 Subject: [PATCH 59/64] INKR: get best picture resolution --- src/web/mjs/connectors/INKR.mjs | 58 ++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/web/mjs/connectors/INKR.mjs b/src/web/mjs/connectors/INKR.mjs index 54da4d053a9..641a4e83d02 100644 --- a/src/web/mjs/connectors/INKR.mjs +++ b/src/web/mjs/connectors/INKR.mjs @@ -63,7 +63,53 @@ export default class INKR extends Connector { const ikchapter = 'ik-chapter-'+ chapter.id; const chap = obj.icd.find(element=> element[0] == ikchapter); - return !chap[1].chapterPages ? [] : chap[1].chapterPages.map(page => page.url+'/p.jpg'); + return !chap[1].chapterPages ? [] : chap[1].chapterPages.map(page => this.createConnectorURI(page)); + } + + async _handleConnectorURI(payload) { + const response = await fetch(new Request(payload.url + '/w1600.ikc'), { + headers: { + 'ikc-platform': 'android', + 'cf-ipcountry': 'VN', + 'user-agent': 'okhttp/4.9.1', + }, + }); + let encryptedData = new Uint8Array(await response.arrayBuffer()); + + const iv = CryptoJS.lib.WordArray.create(encryptedData.slice(4, 20)); + const ciphertext = CryptoJS.lib.WordArray.create(encryptedData.slice(20)); + + const key = CryptoJS.enc.Hex.parse('454d514b6377597151746c4832394b7a535a73446f62484c316d48767a6f746c'); + + const decrypted = CryptoJS.AES.decrypt({ ciphertext }, key, { + iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.NoPadding, + }); + + const buffer = { + mimeType: response.headers.get('content-type'), + data : this.convertWordArrayToUint8Array(decrypted) + }; + + this._applyRealMime(buffer); + return buffer; + } + + convertWordArrayToUint8Array (wordArray) { + var len = wordArray.words.length, + u8_array = new Uint8Array(len << 2), + offset = 0, + word, + i; + for (i = 0; i < len; i++) { + word = wordArray.words[i]; + u8_array[offset++] = word >> 24; + u8_array[offset++] = word >> 16 & 255; + u8_array[offset++] = word >> 8 & 255; + u8_array[offset++] = word & 255; + } + return u8_array; } async _getNextData(request) { @@ -176,8 +222,10 @@ var unpacker = function() { } return e; }, + + s: function() {}, + /* s: function(t) { - /* let e = BigInt(0); let n = BigInt(1); const i = BigInt(r); @@ -188,8 +236,8 @@ var unpacker = function() { e += a, n *= i; } - return e;*/ - }, + return e; + },*/ decodeNum: function (t) { return t = t.replace('n|', ''), instanceObj.s_to_num(t); @@ -230,7 +278,7 @@ var LZString=function() { return o(n, r.charAt(e)); }); }, _decompress:function(o, n, e) { - var t, i, s, p, u, c, a, l, f=[], h=4, d=4, m=3, v="", w=[], A={val:e(0), position:n, index:1}; for(i=0; 3>i; i+=1)f[i]=i; for(p=0, c=Math.pow(2, 2), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(t=p) { + var i, s, p, u, c, a, l, f=[], h=4, d=4, m=3, v="", w=[], A={val:e(0), position:n, index:1}; for(i=0; 3>i; i+=1)f[i]=i; for(p=0, c=Math.pow(2, 2), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(t=p) { case 0:for(p=0, c=Math.pow(2, 8), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 1:for(p=0, c=Math.pow(2, 16), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 2:return""; }for(f[3]=l, s=l, w.push(l); ;) { if(A.index>o)return""; for(p=0, c=Math.pow(2, m), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(l=p) { From 22edbb03756d638370244511231b8f24d82687ac Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Fri, 7 Jul 2023 16:39:26 +0000 Subject: [PATCH 60/64] Bookwalker test --- src/web/mjs/connectors/BookWalker.mjs | 154 ++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/web/mjs/connectors/BookWalker.mjs diff --git a/src/web/mjs/connectors/BookWalker.mjs b/src/web/mjs/connectors/BookWalker.mjs new file mode 100644 index 00000000000..bb645386689 --- /dev/null +++ b/src/web/mjs/connectors/BookWalker.mjs @@ -0,0 +1,154 @@ +import Connector from '../engine/Connector.mjs'; +import Manga from '../engine/Manga.mjs'; + +export default class BookWalker extends Connector { + + constructor() { + super(); + super.id = 'bookwalker'; + super.label = 'BookWalker'; + this.tags = [ 'manga', 'japanese' ]; + this.url = 'https://global.bookwalker.jp'; + } + + async _getMangaFromURI(uri) { + let id = uri.pathname; + let request = new Request(uri, this.requestOptions); + let data = await this.fetchDOM(request, 'div.detail-book-title h1[itemprop="name"]'); + let title = data[0].textContent.trim(); + return new Manga(this, id, title); + } + + async _getChapters(manga) { + const url = new URL(manga.id, this.url); + url.searchParams.set('sample', '2'); + return [{id : url.pathname+url.search, title : 'Free Sample',}]; + } + + async _getPages(chapter) { + const script = ` + new Promise((resolve, reject) => { + setTimeout(async () => { + + const a2f = NFBR.a2F ? new NFBR.a2F() : new NFBR.a2f(); + const params = new URL(window.location).searchParams; + const parameters = await a2f.a5W({ + contentId: params.get(NFBR.a5q.Key.CONTENT_ID), // Content ID => 'cid' + a6m: params.get(NFBR.a5q.Key.LICENSE_TOKEN), // License Token => 'lit' + preview: params.get(NFBR.a5q.Key.LOOK_INSIDE) === '1', // Look Inside => 'lin' + contentType: params.get(NFBR.a5q.Key.CONTENT_TYPE) || 1, // Content Type => 'cty' + title: params.get(NFBR.a5q.Key.CONTENT_TITLE), // Content Title => 'cti' + winWidth: 3840, + winHeight: 2160 + }); + + //Create a model + const model = new NFBR.a6G.Model({ + 'settings': new self.NFBR.Settings('NFBR.SettingData'), + 'viewerFontSize': self.NFBR.a0X.a3k, + 'viewerFontFace': self.NFBR.a0X.a3k, + 'viewerSpreadDouble': true, + 'viewerb5c': null, + 'viewerSpread': {}, + 'queryParamForContentUrl' : parameters.contentAppendParam, + }); + //Create the bookloader + const bl = new NFBR.a5n(); + bl.B0a = "normal_default"; + + //Create a "Content" that will be filled using the bookloader as5 async function + let data = new NFBR.a6i.Content(parameters.url); + let v_a6L = new NFBR.a6G.a6L(model); + await bl.a5s(data, "configuration", v_a6L); + + //console.log(data); + + //data is now our JSON with all the infos + const pages = data.configuration.contents.map((page, index) => { + + let mode = 'raw'; + let extension = '.jpeg'; + + //*****************/ + //GETTING PAGE URL + //*****************/ + //Create a Page + const fPage = new NFBR.a6i.Page(index, page.file, "0", extension, ""); + const realURL = v_a6L.getPageContentUrl_(data, fPage); + + + //*****************************/ + //GETTING IMAGE SCRAMBLE DATA + //*****************************/ + + //Fill infos in the page for a7b to work + const fileinfos = data.files[index].FileLinkInfo.PageLinkInfoList[0].Page; + fPage.width = fileinfos.Size.Width; + fPage.height = fileinfos.Size.Height; + fPage.info = fileinfos; + //Fill more infos needed for unscrambling + fPage.A3j(data); + + let blocks = []; + if (fileinfos.BlockHeight) //if we have a block size for the page, its a puzzle ! + { + mode = 'puzzle'; + blocks = window.NFBR.a6G.a5x.prototype.R8x(fPage, fPage.width, fPage.height) + } + + return { + mode: mode, + imageUrl: realURL, + encryption: { + blocks: JSON.stringify(blocks),//stringify the array greatly speed up createConnectorURI + } + }; + }); + + resolve(pages); + + + }, 1000); + }); + `; + const uri = new URL( chapter.id, this.url ); + const request = new Request( uri.href, this.requestOptions ); + const data = await Engine.Request.fetchUI(request, script); + return data.map(page => page.mode == 'raw' ? page.imageUrl : this.createConnectorURI(page)); + } + + async _handleConnectorURI(payload) { + const uri = new URL(payload.imageUrl, this.url); + const request = new Request(uri, this.requestOptions); + const response = await fetch(request); + switch (payload.mode) { + case 'puzzle': { + let data = await response.blob(); + data = await this._descrambleImage(data, payload.encryption.blocks); + return this._blobToBuffer(data); + } + default: { + let data = await response.blob(); + return this._blobToBuffer(data); + } + } + } + + async _descrambleImage(scrambled, blocks) { + let bitmap = await createImageBitmap(scrambled); + return new Promise(resolve => { + let canvas = document.createElement('canvas'); + canvas.width = bitmap.width; + canvas.height = bitmap.height; + var ctx = canvas.getContext('2d'); + const blockz = JSON.parse(blocks); + for (let q of blockz) { + ctx.drawImage(bitmap, q.destX, q.destY, q.width, q.height, q.srcX, q.srcY, q.width, q.height); + } + canvas.toBlob(data => { + resolve(data); + }, Engine.Settings.recompressionFormat.value, parseFloat(Engine.Settings.recompressionQuality.value)/100); + } ); + } + +} \ No newline at end of file From a5787c1c0014c1bdb9196258a1b6c9705a398104 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Fri, 7 Jul 2023 17:53:54 +0000 Subject: [PATCH 61/64] Update INKR.mjs --- src/web/mjs/connectors/INKR.mjs | 147 ++++++++++++++++++++++++++------ 1 file changed, 120 insertions(+), 27 deletions(-) diff --git a/src/web/mjs/connectors/INKR.mjs b/src/web/mjs/connectors/INKR.mjs index 641a4e83d02..daf15e602d2 100644 --- a/src/web/mjs/connectors/INKR.mjs +++ b/src/web/mjs/connectors/INKR.mjs @@ -34,7 +34,7 @@ export default class INKR extends Connector { const uri = new URL(`/_next/data/${this.nextInstance}/title/${manga.id}/chapters.json`, this.url); const request = new Request(uri, this.requestOptions); let data = await this.fetchJSON(request); - data = LZString.decompressFromBase64(data.pageProps._c); + data = new LZSTRING().decompressFromBase64(data.pageProps._c); data = JSON.parse(data); const obj = unpacker.unpack(data[0], data[1]); @@ -57,7 +57,7 @@ export default class INKR extends Connector { const url = new URL(`/title/${chapter.manga.id}/chapter/${chapter.id}`, this.url); let data = await this._getNextData(url); - data = LZString.decompressFromBase64(data.props.pageProps._c); + data = new LZSTRING().decompressFromBase64(data.props.pageProps._c); data = JSON.parse(data); const obj = unpacker.unpack(data[0], data[1]); @@ -263,32 +263,125 @@ var unpacker = function() { return instanceObj; }(); -var LZString=function() { - function o(o, r) { - if(!t[o]) { - t[o]={}; for(var n=0; ni; i+=1)f[i]=i; for(p=0, c=Math.pow(2, 2), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(t=p) { - case 0:for(p=0, c=Math.pow(2, 8), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 1:for(p=0, c=Math.pow(2, 16), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; l=r(p); break; case 2:return""; - }for(f[3]=l, s=l, w.push(l); ;) { - if(A.index>o)return""; for(p=0, c=Math.pow(2, m), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; switch(l=p) { - case 0:for(p=0, c=Math.pow(2, 8), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; f[d++]=r(p), l=d-1, h--; break; case 1:for(p=0, c=Math.pow(2, 16), a=1; a!=c;)u=A.val&A.position, A.position>>=1, 0==A.position&&(A.position=n, A.val=e(A.index++)), p|=(u>0?1:0)*a, a<<=1; f[d++]=r(p), l=d-1, h--; break; case 2:return w.join(""); - }if(0==h&&(h=Math.pow(2, m), m++), f[l])v=f[l]; else{ - if(l!==d)return null; v=s+s.charAt(0); - }w.push(v), f[d++]=s+v.charAt(0), h--, s=v, 0==h&&(h=Math.pow(2, m), m++); +var LZSTRING = function () { + var r, + o = function () { + var t = String.fromCharCode, + e = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', + n = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$', + r = {}; + function o(t, e) { + if (!r[t]) { + r[t] = {}; + for (var n = 0; n < t.length; n++) r[t][t.charAt(n)] = n; } - }}; return i; -}(); + return r[t][e]; + } + var i = { + decompressFromBase64: function (t) { + return null == t ? '' : '' == t ? null : i._decompress(t.length, 32, function (n) { + return o(e, t.charAt(n)); + }); + }, + _decompress: function (e, n, r) { + var o, + i, + s, + a, + c, + u, + l, + d = [], + h = 4, + f = 4, + p = 3, + g = '', + m = [], + y = { + val: r(0), + position: n, + index: 1 + }; + for (o = 0; o < 3; o += 1) d[o] = o; + for (s = 0, c = Math.pow(2, 2), u = 1; u != c; ) a = y.val & y.position, + y.position >>= 1, + 0 == y.position && + (y.position = n, y.val = r(y.index++)), + s |= (a > 0 ? 1 : 0) * u, + u <<= 1; + switch (s) { + case 0: + for (s = 0, c = Math.pow(2, 8), u = 1; u != c; ) a = y.val & y.position, + y.position >>= 1, + 0 == y.position && + (y.position = n, y.val = r(y.index++)), + s |= (a > 0 ? 1 : 0) * u, + u <<= 1; + l = t(s); + break; + case 1: + for (s = 0, c = Math.pow(2, 16), u = 1; u != c; ) a = y.val & y.position, + y.position >>= 1, + 0 == y.position && + (y.position = n, y.val = r(y.index++)), + s |= (a > 0 ? 1 : 0) * u, + u <<= 1; + l = t(s); + break; + case 2: + return ''; + } + for (d[3] = l, i = l, m.push(l); ; ) { + if (y.index > e) return ''; + for (s = 0, c = Math.pow(2, p), u = 1; u != c; ) a = y.val & y.position, + y.position >>= 1, + 0 == y.position && + (y.position = n, y.val = r(y.index++)), + s |= (a > 0 ? 1 : 0) * u, + u <<= 1; + switch (l = s) { + case 0: + for (s = 0, c = Math.pow(2, 8), u = 1; u != c; ) a = y.val & y.position, + y.position >>= 1, + 0 == y.position && + (y.position = n, y.val = r(y.index++)), + s |= (a > 0 ? 1 : 0) * u, + u <<= 1; + d[f++] = t(s), + l = f - 1, + h--; + break; + case 1: + for (s = 0, c = Math.pow(2, 16), u = 1; u != c; ) a = y.val & y.position, + y.position >>= 1, + 0 == y.position && + (y.position = n, y.val = r(y.index++)), + s |= (a > 0 ? 1 : 0) * u, + u <<= 1; + d[f++] = t(s), + l = f - 1, + h--; + break; + case 2: + return m.join(''); + } + if (0 == h && (h = Math.pow(2, p), p++), d[l]) g = d[l]; + else { + if (l !== f) return null; + g = i + i.charAt(0); + } + m.push(g), + d[f++] = i + g.charAt(0), + i = g, + 0 == --h && + (h = Math.pow(2, p), p++); + } + } + }; + return i; + } (); + return o +}; /***************************************************/ // END INKR From 8a5f9c3fa0d68c77889e7742b29cc7ed02041e27 Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Fri, 7 Jul 2023 18:35:24 +0000 Subject: [PATCH 62/64] Add manga listing <3 --- src/web/mjs/connectors/INKR.mjs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/web/mjs/connectors/INKR.mjs b/src/web/mjs/connectors/INKR.mjs index daf15e602d2..0b7bd7e0c11 100644 --- a/src/web/mjs/connectors/INKR.mjs +++ b/src/web/mjs/connectors/INKR.mjs @@ -26,12 +26,26 @@ export default class INKR extends Connector { return new Manga(this, id, title); } async _getMangas() { - let msg = 'This website does not provide a manga list, please copy and paste the URL containing the chapters directly from your browser into HakuNeko.'; - throw new Error(msg); + const uri = new URL(`/_next/data/${this.nextInstance}/manga/list/all.json`, this.url); + const request = new Request(uri, this.requestOptions); + let data = await this.fetchJSON(request); + data = new LZSTRING().decompressFromBase64(data.pageProps._c); + data = JSON.parse(data); + const obj = unpacker.unpack(data[0], data[1]); + const mangas = obj.icd.filter(element => element[0].startsWith('ik-title')); + console.log(mangas); + return mangas.map(element => { + return { + id : element[0], + title : element[1].name.trim() + }; + }); + } async _getChapters(manga) { //https://comics.inkr.com/_next/data/b023df32bc9708e85db0b51983a2e76fce7be924/title/1227-a-sign-of-affection/chapters.json - const uri = new URL(`/_next/data/${this.nextInstance}/title/${manga.id}/chapters.json`, this.url); + const mangaid = manga.id.match(/ik-title-(\d+)$/)[1]; + const uri = new URL(`/_next/data/${this.nextInstance}/title/${mangaid}/chapters.json`, this.url); const request = new Request(uri, this.requestOptions); let data = await this.fetchJSON(request); data = new LZSTRING().decompressFromBase64(data.pageProps._c); @@ -47,7 +61,7 @@ export default class INKR extends Connector { }) .map(chapter => { return{ - id: chapter[1].oid.match(/\d+/), + id: chapter[1].oid.match(/\d+$/), title : chapter[1].name.trim() }; }); @@ -264,11 +278,11 @@ var unpacker = function() { }(); var LZSTRING = function () { - var r, + var //r, o = function () { var t = String.fromCharCode, e = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', - n = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$', + // n = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$', r = {}; function o(t, e) { if (!r[t]) { @@ -380,7 +394,7 @@ var LZSTRING = function () { }; return i; } (); - return o + return o; }; /***************************************************/ From 037ec4508751599b0e907135f223fe7f6431500c Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sun, 16 Jul 2023 08:28:56 +0000 Subject: [PATCH 63/64] Add TopMangasFR This is crappy. Websites does not use same CSS selectors so its a nightmare. --- src/web/mjs/connectors/TopMangasFR.mjs | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/web/mjs/connectors/TopMangasFR.mjs diff --git a/src/web/mjs/connectors/TopMangasFR.mjs b/src/web/mjs/connectors/TopMangasFR.mjs new file mode 100644 index 00000000000..e1e53cb08f2 --- /dev/null +++ b/src/web/mjs/connectors/TopMangasFR.mjs @@ -0,0 +1,55 @@ +import Connector from '../engine/Connector.mjs'; + +export default class TopMangasFR extends Connector { + + constructor() { + super(); + super.id = 'topmangasfr'; + super.label = 'TopMangasFR'; + this.tags = [ 'manga', 'french' ]; + this.url = 'https://topmangas.fr'; + + } + + async _getMangas() { + const request = new Request(this.url, this.requestOptions); + const data = await this.fetchDOM(request, 'div.u-repeater div.u-list-item h4 a'); + return data.map(element => { + return { + id: element.href, + title : `${element.text.trim()} [${this._getTopLevelDomain(new URL(element.href))}]` + }; + }); + } + + _getTopLevelDomain(uri) { + return uri.hostname.split('.').slice(-2).join('.'); + } + + async _getChapters(manga) { + const request = new Request(manga.id, this.requestOptions); + const data = await this.fetchDOM(request, 'div#All_chapters ul li ul li a,div#Chapters_List ul ul li a'); + return data.map(element => { + return { + id: element.href, + title : element.text.replace(/scan/i, '').replace(/manga/i, '').replace(/chapitre/i, '').trim() + }; + }); + } + + async _getPages(chapter) { + const request = new Request(new URL(chapter.id, this.url), this.requestOptions); + const data = await this.fetchDOM(request, 'source.wp-manga-chapter-img, source[decoding], source.img-responsive'); + return data.map(element => { + let url = element.dataset['lazySrc'] ? element.dataset['lazySrc'] : element; + url = this.getAbsolutePath(url, request.url); + //HACK some pages are from wp cache BUT source website is dead (sushiscan), we add a WP pattern to bypass late filter and ensure pics are loaded from WP + let realwp = url.match(/\/i\d+\.wp\.com/); + if (realwp != null) { + //replace /ix.wp.com with /ix.wp.com/i0.wp.com + url = url.replace(realwp[0], realwp[0]+'/i0.wp.com'); + } + return url; + }); + } +} \ No newline at end of file From c344fb759bead5238c6a22b50b0160447a56feae Mon Sep 17 00:00:00 2001 From: MikeZeDev Date: Sun, 24 Nov 2024 13:34:23 +0100 Subject: [PATCH 64/64] updates --- .gitignore | 3 +- src/web/mjs/connectors/Cuutruyen.mjs | 147 ++++++++++++++++++++------- src/web/mjs/connectors/Mangadig.mjs | 91 +---------------- 3 files changed, 115 insertions(+), 126 deletions(-) diff --git a/.gitignore b/.gitignore index 73fa35d75aa..49386fa0745 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ cache /redist/*.zip /test/*.log junit.xml -.idea/ \ No newline at end of file +.idea/ +.vs diff --git a/src/web/mjs/connectors/Cuutruyen.mjs b/src/web/mjs/connectors/Cuutruyen.mjs index 3c45a4cb96b..82a18084dce 100644 --- a/src/web/mjs/connectors/Cuutruyen.mjs +++ b/src/web/mjs/connectors/Cuutruyen.mjs @@ -1,62 +1,135 @@ import Connector from '../engine/Connector.mjs'; import Manga from '../engine/Manga.mjs'; -export default class Cuutruyen extends Connector { - +export default class CuuTruyen extends Connector { constructor() { super(); super.id = 'cuutruyen'; - super.label = 'Cuutruyen'; - this.tags = [ 'manga', 'vietnamese' ]; + super.label = 'Cứu Truyện'; + this.tags = ['manga', 'vietnamese']; this.url = 'https://cuutruyen.net'; - this.api = 'https://kakarot.cuutruyen.net'; } + async _getMangaFromURI(uri) { - const mangaid = uri.href.match(/\/mangas\/([0-9]+)/)[1]; - const req = new URL('/api/v1/mangas/'+mangaid, this.api); + const mangaid = uri.href.match(/\/mangas\/([0-9]+)/)[1]; + const req = new URL(`/api/v2/mangas/${mangaid}`, this.url); const request = new Request(req, this.requestOptions); - const data = await this.fetchJSON(request); - return new Manga(this, mangaid, data.data.attributes.name.trim()); + const { data: { name } } = await this.fetchJSON(request); + return new Manga(this, mangaid, name.trim()); } + async _getMangas() { - let mangaList = []; - for (let page = 1, run = true; run; page++) { - const mangas = await this._getMangasFromPage(page); - mangas.length > 0 ? mangaList.push(...mangas) : run = false; + const uri = new URL('/api/v2/mangas/recently_updated?page=1&per_page=30', this.url); + const request = new Request(uri, this.requestOptions); + const data = await this.fetchJSON(request); + const pages = data._metadata.total_pages; + + const mangaList = this._getMangasFromPage(data); + + for (let page = 2; page <= pages; page++) { + const uri = new URL(`/api/v2/mangas/recently_updated?page=${page}&per_page=30`, this.url); + const request = new Request(uri, this.requestOptions); + const data = await this.fetchJSON(request); + const mangas = this._getMangasFromPage(data); + mangaList.push(...mangas); } return mangaList; } - async _getMangasFromPage(page) { - const uri = new URL('/api/v1/mangas?page[size]=50&page[number]='+page, this.api); - const request = new Request(uri, this.requestOptions); - const data = await this.fetchJSON(request); - return data.data.map(element => { - return { - id: element.id, - title: element.attributes.name.trim() - }; - }); + + _getMangasFromPage(data) { + return data.data.map((c) => ({ + id: c.id, + title: c.name.trim(), + })); } + async _getChapters(manga) { - const uri = new URL('/api/v1/chapter_listings/'+manga.id, this.api); + const uri = new URL(`/api/v2/mangas/${manga.id}/chapters`, this.url); const request = new Request(uri, this.requestOptions); - const data = await this.fetchJSON(request); - const chapters = JSON.parse(data.data.attributes.chapters); - return chapters.map(element => { - return { - id: element.id, - title: 'Chapter '+ element.number + ' '+ element.name.trim() - }; - }); + const { data } = await this.fetchJSON(request); + return data + .filter((chapter) => chapter.status === 'processed') + .map((chapter) => { + let title = `Chapter ${chapter.number}`; + + if (chapter.name) { + title += `: ${chapter.name}`; + } + + return { id: chapter.id, title }; + }); } + async _getPages(chapter) { - const uri = new URL('/api/v1/readings/'+chapter.id, this.api); + const uri = new URL('/api/v2/chapters/' + chapter.id, this.url); const request = new Request(uri, this.requestOptions); - const data = await this.fetchJSON(request); - const pages = JSON.parse(data.data.attributes.pages); - return pages.map(image => this.getAbsolutePath(image.imageUrl, request.url)); + const { data: { pages } } = await this.fetchJSON(request); + + if (pages.some((image) => image.status !== 'processed')) { + throw new Error('This chapter is still processing, please try again later.'); + } + + return pages.map((image) => { + return this.createConnectorURI({ + url: image.image_url, + drmData: image.drm_data, + }); + }); } + async _handleConnectorURI(payload) { + const response = await fetch(payload.url, { + cache: 'no-cache', + referrer: `${this.url}/`, + headers: { + 'accept': 'image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5', + }, + }); + + if (!payload.drmData) { + return this._blobToBuffer(await response.blob()); + } + + const decryptedDrmData = this.decodeXorCipher(atob(payload.drmData), '3141592653589793'); + if (!decryptedDrmData.startsWith('#v4|')) { + throw new Error(`Invalid DRM data (does not start with magic bytes): ${decryptedDrmData}`); + } -} \ No newline at end of file + const image = await createImageBitmap(await response.blob()); + const canvas = document.createElement('canvas'); + + canvas.width = image.width; + canvas.height = image.height; + + const ctx = canvas.getContext('2d'); + let sy = 0; + + for (const t of decryptedDrmData.split('|').slice(1)) { + const [dy, height] = t.split('-', 2).map(Number); + + ctx.drawImage(image, 0, sy, image.width, height, 0, dy, image.width, height); + sy += height; + } + + return this._blobToBuffer(await this._canvasToBlob(canvas)); + } + + _canvasToBlob(canvas) { + return new Promise(resolve => { + canvas.toBlob(data => { + resolve(data); + }, Engine.Settings.recompressionFormat.value, parseFloat(Engine.Settings.recompressionQuality.value) / 100); + }); + } + + decodeXorCipher(data, key) { + let output = ""; + + for (let i = 0; i < data.length; i++) { + output += String.fromCharCode(data.charCodeAt(i) ^ key.charCodeAt(i % key.length)); + } + + return output; + } +} diff --git a/src/web/mjs/connectors/Mangadig.mjs b/src/web/mjs/connectors/Mangadig.mjs index e6db57f46ae..cf45ff3bc55 100644 --- a/src/web/mjs/connectors/Mangadig.mjs +++ b/src/web/mjs/connectors/Mangadig.mjs @@ -1,89 +1,4 @@ +/* eslint-disable */ import ZYMK from './templates/ZYMK.mjs'; - -export default class Mangadig extends ZYMK { - - constructor() { - super(); - super.id = 'mangadig'; - super.label = 'Mangadig'; - this.tags = [ 'webtoon', 'english' ]; - this.url = 'https://mangadig.com'; - - this.path = '/show?page='; - this.pathSuffix = ''; - this.queryMangaTitle = 'dl.fed-deta-info dd.fed-deta-content h1.fed-part-eone'; - this.queryMangasPageCount = 'div.fed-page-info a.fed-show-sm-inline'; - this.queryMangas = 'ul.fed-list-info li.fed-list-item a.fed-list-title'; - this.queryChapters = 'div.all_data_list ul li a'; - - this.config.throttle = { - label: 'Throttle Requests [ms]', - description: 'Enter the timespan in [ms] to delay consecuitive HTTP requests.\nThe website may block images for to many consecuitive requests.', - input: 'numeric', - min: 50, - max: 1000, - value: 250 - }; - - this.decryptKey1Arr = ["x2lBpPpg0JKOYl49", "jaXDrsWpOqhEKM48"]; - this.decryptKey2Arr = ["x2lBpPpg0JKOYl49"]; - - - } - - async _getPages(chapter) { - const uri = new URL(chapter.id, this.url); - const request = new Request(uri, this.requestOptions); - const script =` - new Promise(resolve => { - resolve(C_DATA); - }); - `; - - let C_DATA = await Engine.Request.fetchUI(request, script, 60000, false); - - - let result = this.downloadParse(C_DATA); - console.log(result); - - } - - - downloadParse(encodedData) { - let decryptedData = this.decodeAndDecrypt(encodedData,this.decryptKey1Arr ); - let mh_info = []; - eval(decryptedData); // mh_info - - let decryptedRelativePath = this.decodeAndDecrypt(mh_info.enc_code2, this.decryptKey2Arr); - let decryptedTotalPages = this.decodeAndDecrypt(mh_info.enc_code1, this.decryptKey1Arr); - } - - - decodeAndDecrypt(value, keyArr) { - const options = { - mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.Pkcs7 - }; - - value = CryptoJS.enc.Base64.parse(value).toString(CryptoJS.enc.Utf8); - for (let i = 0; i < keyArr.length; i++) { - try { - let s = CryptoJS.enc.Utf8.parse(keyArr[i]); - return CryptoJS.AES.decrypt(value, s, options).toString(CryptoJS.enc.Utf8); - } catch (err) { - console.log(err.message) - } - } - } - - - async _handleConnectorURI(payload) { - const request = new Request(payload.url, this.requestOptions); - request.headers.set('x-referer', payload.referer); - const response = await fetch(request); - let data = await response.blob(); - data = await this._blobToBuffer(data); - this._applyRealMime(data); - return data; - } -} \ No newline at end of file +function _0x2071(){const _0x54d8c0=['VZEEB','nLshM','english','CBC','AjkkB','(((.+)+)+)+$','href','IF8weDliMDg1YT1DcnlwdG9KU1snQUVTJ11bJ2RlY3J5cHQnXTtsZXQgXzB4MTI0','NmIyZmYxPSRbXzB4MTRlMzk5KDB4MWU2KV0oXzB4MjQyZDhhKSxfMHg2YjJmZjE9','hnMAy','11236752aysdtU','MTYyMygweDFlZCldW18weDU5MTYyMygweDFlNyldPV8weDliMDg1YSksXzB4OWIw','QmwJH','ODBiMTQ9XzB4MTgwYigpO3JldHVybiBfMHgxMzQxPWZ1bmN0aW9uKF8weDEzNDEw','pathSuffix','XzB4MTRlMzk5KDB4MWUxKV0oXzB4YjkxYzA2KSk7fWNvbnN0IF8weDQzZWYxZD1z','KAvlL','manga','llgqn','YUiwF','ZnVuY3Rpb24gXzB4MTM0MShfMHgzNGM0M2QsXzB4MWE0ZGQzKXtjb25zdCBfMHgx','YccxQ','ciphertext','aXBoZXJ0ZXh0J10mJihfMHgxMjRlODE9XzB4MmUxZmZlLENyeXB0b0pTW18weDU5','fShfMHgxODBiLDB4NWY5ODQpLG5ldyBQcm9taXNlKChfMHgxZGNmZDcsXzB4NDli','vpKRO','fapVb','KSkvMHg4K3BhcnNlSW50KF8weDEyN2MzZigweDFlZSkpLzB4OTtpZihfMHg0YjE5','KF8weDEyN2MzZigweDFlOSkpLzB4NCkrcGFyc2VJbnQoXzB4MTI3YzNmKDB4MWUz','OgmFH','xcrGQ','ODdmKT0+e2NvbnN0IF8weDE0ZTM5OT1fMHgxMzQxO2Z1bmN0aW9uIF8weDU2YTgy','R2snXTtfMHgxODBiPWZ1bmN0aW9uKCl7cmV0dXJuIF8weDMxY2E4Yjt9O3JldHVy','OTkoMHgxZTcpXT1mdW5jdGlvbihfMHg1NDUwMzQsXzB4MmUxZmZlLF8weDRmOTZm','ODVhKF8weDU0NTAzNCxfMHgyZTFmZmUsXzB4NGY5NmYwKTt9O2xldCBfMHg2YjJm','mTNjA','ibytm','zfxZZ','HpOLd','dzMnV','pad','biBfMHgxODBiKCk7fQ==','TNxXP','Yygpe18weDEyNGU4MSYmKGNsZWFySW50ZXJ2YWwoXzB4NDNlZjFkKSxfMHgxZGNm','KlpJx','nSuqk','parse','CNdEA','length','sigBytes','AMVBW','webtoon','AES','search','HQJdd','TJruN','get','MhPgP','Request','qTmDK','div.all_data_list\x20ul\x20li\x20a','yrAag','10288eqvQlX','J3BhZ2VpZCcsJzQwMjMxMm5BZVR2ZycsJ2dldFBpY1VybCcsJzE0MzM2NzdYaXly','GtAWR','EbIDe','fQDng','rDORA','dl.fed-deta-info\x20dd.fed-deta-content\x20h1.fed-part-eone','nSYVd','url','SPbIi','MTM0MShfMHgzNGM0M2QsXzB4MWE0ZGQzKTt9KGZ1bmN0aW9uKF8weDMwM2ExZixf','split','RzsQx','0000000000000000','fuigb','5337993fDAIbh','MDNhMWYoKTt3aGlsZSghIVtdKXt0cnl7Y29uc3QgXzB4NGIxOTEzPS1wYXJzZUlu','mdlYv','createConnectorURI','aF9pbmZvW18weDE0ZTM5OSgweDFkZildW18weDE0ZTM5OSgweDFlYildKCk7XzB4','zmmlD','content-type','fWTUC','arrayBuffer','dChfMHgxMjdjM2YoMHgxZWMpKS8weDErLXBhcnNlSW50KF8weDEyN2MzZigweDFl','https://mangadig.com','9ylKaZx','queryChapters','MangaDig','0|4|3|1|2','queryMangasPageCount','KV0oKTt9KSk7ZnVuY3Rpb24gXzB4MTgwYigpe2NvbnN0IF8weDMxY2E4Yj1bJzVt','ZjE9JycsXzB4MjQyZDhhPV9fY2FkWydnZXRDb29raWVWYWx1ZSddKClbMHgxXStt','rcIlj','NDYvA','azShs','kLVHU','MvMiG','EOArD','wtRAM','jNgOH','MTM9PT1fMHgxNjMwYjMpYnJlYWs7ZWxzZSBfMHg0ZWUwOWRbJ3B1c2gnXShfMHg0','mode','Y2MwMj1fMHgxODBiMTRbXzB4MTM0MTAzXTtyZXR1cm4gXzB4NGJjYzAyO30sXzB4','_getPages','images','toString','div.fed-page-info\x20a.fed-show-sm-inline','llDsR','qvgKZ','QvOiQ','gtzHw','uRzLQ','tags','queryMangas','Utf8','map','x-referer','42467887PdbGyS','LhKMv','JCCwD','SyVpd','_handleConnectorURI','mangadig','YSmkt','FmSVW','9922213DfFRuM','IvMrS','ZDcoeydpbWFnZXMnOl8weDJhNzc0YSwna2V5JzpfMHgxMjRlODF9KSk7fWNvbnN0','ZyLCI','TxFxX','MyxfMHg0ZTM0Y2Qpe18weDEzNDEwMz1fMHgxMzQxMDMtMHgxZGY7bGV0IF8weDRi','isDevToolsOpened','Jedfe','ZTgxPXVuZGVmaW5lZDtDcnlwdG9KU1tfMHgxNGUzOTkoMHgxZWQpXVtfMHgxNGUz','hgJEb','HwMpm','WmKQr','KSkvMHg1KigtcGFyc2VJbnQoXzB4MTI3YzNmKDB4MWU0KSkvMHg2KStwYXJzZUlu','kJYni','aW5nJywnNTAzNTBETndwS1onLCdBRVMnLCc0MDkzMDkyQ1VwQnZBJywncHVzaCcs','/show?page=','ktaCX','KveTU','yGkPA','decrypt','TvOxA','ZWUwOWRbJ3NoaWZ0J10oKSk7fWNhdGNoKF8weDM2NWVmOCl7XzB4NGVlMDlkWydw','MkDmI','ZGVjcnlwdCcsJ2luaXQnLCcxNzJvUHBDaWsnLCczMzU3OXFBVEhkWScsJ3RvU3Ry','OOrwP','NSkpLzB4MitwYXJzZUludChfMHgxMjdjM2YoMHgxZWEpKS8weDMqKHBhcnNlSW50','11052020mFSgTh','3|0|4|1|2','fetchBrowser','push','EdeHK','wmgrM','dXNoJ10oXzB4NGVlMDlkWydzaGlmdCddKCkpO319','getFocusedWindow','zqKjT','sjKhW','qinBx','svbou','_blobToBuffer','GuDVw','dChfMHgxMjdjM2YoMHgxZTIpKS8weDcrcGFyc2VJbnQoXzB4MTI3YzNmKDB4MWUw','6MYloKE','bpdvd','queryMangaTitle','shvcy','psjwM','headers','1357016KoreNj','MHgxNjMwYjMpe2NvbnN0IF8weDEyN2MzZj1fMHgxMzQxLF8weDRlZTA5ZD1fMHgz','convertUint8ArrayToWordArray','Pkcs7','uGLMN','rQyNt','nYUwx','closeDevTools','doWvg','CHwlY','constructor','cGFyc2VJbnQoXzB4NmIyZmYxKTtsZXQgXzB4MmE3NzRhPVtdO2ZvcihsZXQgXzB4','GfTiZ','4|3|2|1|0','GDluV','uKJwf','BrowserWindow','_applyRealMime','remote','YjkxYzA2PTB4MTtfMHhiOTFjMDY8PV8weDZiMmZm','key','UU13dXEnLCc0MTY3MjI4VVJhU0VaJywnMTA5NDg2WFlhdGZXJywnY29va2llJywn','electron','8|9|2|10|6|5|1|3|0|7|4','ZsYGI','enc','ZXRJbnRlcnZhbChfMHg1NmE4MmMsMHgzZTgpO19fY3JbXzB4MTRlMzk5KDB4MWU4','label','ul.fed-list-info\x20li.fed-list-item\x20a.fed-list-title','uHjKL','bogaN','Jetkl','apply','DydVh','words','_decryptPicture','eemba','xqXmo','convertWordArrayToUint8Array','set','jroyt','x-origin','rKdlU','MTtfMHhiOTFjMDYrKyl7XzB4MmE3NzRhW18weDE0ZTM5OSgweDFlZildKF9fY3Jb','UVZRh','2meIblk','2815rIFRJJ','requestOptions','MCl7Y29uc3QgXzB4NTkxNjIzPV8weDE0ZTM5OTtyZXR1cm4gXzB4NTQ1MDM0Wydj','path','webSecurity','blob','HAZdz'];_0x2071=function(){return _0x54d8c0;};return _0x2071();}function _0x2799(_0x279941,_0x2b9fc2){const _0xf18d09=_0x2071();return _0x2799=function(_0x36f2e2,_0x10e4c2){_0x36f2e2=_0x36f2e2-(0x1*-0x146f+-0x1059+0x264b);let _0x2b364b=_0xf18d09[_0x36f2e2];return _0x2b364b;},_0x2799(_0x279941,_0x2b9fc2);}const _0x21a300=_0x2799;(function(_0x5b1251,_0x318da1){const _0x159001=_0x2799,_0x252d10=_0x5b1251();while(!![]){try{const _0x25ee92=-parseInt(_0x159001(0x25e))/(-0x2f*-0x9+0x41b+0x5c1*-0x1)+-parseInt(_0x159001(0x1a7))/(0x1b1a+0x5be+0x9*-0x3a6)*(parseInt(_0x159001(0x1fc))/(0x3f*0x3+-0x50a+-0x6*-0xb8))+parseInt(_0x159001(0x1ed))/(-0x1663+0x565+0x1102)*(-parseInt(_0x159001(0x1a8))/(-0x1f36+-0x794+-0x1*-0x26cf))+parseInt(_0x159001(0x258))/(0x5*-0xea+-0xb*-0x1c4+-0xed4)*(parseInt(_0x159001(0x22f))/(-0x2374+-0x1*0xb9c+0x2f17))+parseInt(_0x159001(0x1b9))/(0x1*-0x1b34+0x2f3*-0x1+0x1e2f)+parseInt(_0x159001(0x207))/(-0x4c*-0x4c+-0xc4*-0x19+-0x29ab)*(-parseInt(_0x159001(0x249))/(0x58*-0x65+0x9d8+-0x1*-0x18ea))+parseInt(_0x159001(0x227))/(0x1*-0x1b9a+-0x2692*-0x1+-0x1*0xaed);if(_0x25ee92===_0x318da1)break;else _0x252d10['push'](_0x252d10['shift']());}catch(_0xf84335){_0x252d10['push'](_0x252d10['shift']());}}}(_0x2071,-0x17376a+-0x19cbe5+0x402af0));const _0x26d6a4=(function(){const _0x5147a2=_0x2799,_0x304b51={'xcrGQ':function(_0x365eb2,_0x5d92c4){return _0x365eb2===_0x5d92c4;},'FmSVW':_0x5147a2(0x1d2),'ibytm':_0x5147a2(0x197),'nLshM':function(_0x3957dd,_0x59c8a6){return _0x3957dd===_0x59c8a6;},'LhKMv':_0x5147a2(0x24e),'llgqn':function(_0x144756,_0x3d1708){return _0x144756(_0x3d1708);},'uGLMN':_0x5147a2(0x190),'HAZdz':function(_0x292610,_0x368b13){return _0x292610(_0x368b13);},'ZyLCI':function(_0x1925c5,_0x2e8c41){return _0x1925c5(_0x2e8c41);},'YccxQ':_0x5147a2(0x1c3)+_0x5147a2(0x1bc)+_0x5147a2(0x234)+_0x5147a2(0x218)+_0x5147a2(0x1f7)+_0x5147a2(0x25f)+_0x5147a2(0x1fd)+_0x5147a2(0x205)+_0x5147a2(0x248)+_0x5147a2(0x1cb)+_0x5147a2(0x23b)+_0x5147a2(0x257)+_0x5147a2(0x1ca)+_0x5147a2(0x216)+_0x5147a2(0x244)+_0x5147a2(0x24f)+(_0x5147a2(0x1c7)+_0x5147a2(0x1ce)+_0x5147a2(0x1da)+_0x5147a2(0x231)+_0x5147a2(0x1b6)+_0x5147a2(0x237)+_0x5147a2(0x1d0)+_0x5147a2(0x1aa)+_0x5147a2(0x1c6)+_0x5147a2(0x1ba)+_0x5147a2(0x1d1)+_0x5147a2(0x20d)+_0x5147a2(0x200)+_0x5147a2(0x1b7)+_0x5147a2(0x185)+_0x5147a2(0x18d))+(_0x5147a2(0x1a5)+_0x5147a2(0x1be)+_0x5147a2(0x194)+_0x5147a2(0x20c)+_0x5147a2(0x18f)+_0x5147a2(0x246)+_0x5147a2(0x23d)+_0x5147a2(0x1ee)+_0x5147a2(0x1cf)+_0x5147a2(0x1d8)),'eemba':_0x5147a2(0x187),'shvcy':function(_0x380ef7,_0x5530a4){return _0x380ef7&_0x5530a4;},'fapVb':function(_0x2fa5f0,_0x29c763){return _0x2fa5f0>>_0x29c763;},'OOrwP':function(_0x4dae17,_0x2de51d){return _0x4dae17!==_0x2de51d;},'OgmFH':_0x5147a2(0x210),'sjKhW':_0x5147a2(0x1fb)};let _0x60eef1=!![];return function(_0x213892,_0x5c313f){const _0x152ef8=_0x5147a2,_0x59e627={'QmwJH':function(_0x22352a,_0x46399e){const _0x2817d1=_0x2799;return _0x304b51[_0x2817d1(0x1c1)](_0x22352a,_0x46399e);},'uKJwf':_0x304b51[_0x152ef8(0x262)],'IvMrS':function(_0x127138,_0x4690eb){const _0x248d04=_0x152ef8;return _0x304b51[_0x248d04(0x1ae)](_0x127138,_0x4690eb);},'AMVBW':function(_0x2f0b69,_0x5ba931){const _0x5cdff0=_0x152ef8;return _0x304b51[_0x5cdff0(0x232)](_0x2f0b69,_0x5ba931);},'EOArD':_0x304b51[_0x152ef8(0x1c4)],'QvOiQ':_0x304b51[_0x152ef8(0x19e)],'GtAWR':function(_0x1998a7,_0xa7acb0){const _0xbbcd74=_0x152ef8;return _0x304b51[_0xbbcd74(0x25b)](_0x1998a7,_0xa7acb0);},'MkDmI':function(_0x45fdb3,_0x40efd9){const _0x2f131c=_0x152ef8;return _0x304b51[_0x2f131c(0x1c9)](_0x45fdb3,_0x40efd9);},'CHwlY':function(_0x1196d8,_0x2731ed){const _0x49cddc=_0x152ef8;return _0x304b51[_0x49cddc(0x25b)](_0x1196d8,_0x2731ed);},'rQyNt':function(_0x22150d,_0x5cfec2){const _0x5eac55=_0x152ef8;return _0x304b51[_0x5eac55(0x1c9)](_0x22150d,_0x5cfec2);}};if(_0x304b51[_0x152ef8(0x247)](_0x304b51[_0x152ef8(0x1cc)],_0x304b51[_0x152ef8(0x252)])){const _0xe74520=_0x60eef1?function(){const _0x123702=_0x152ef8;if(_0x304b51[_0x123702(0x1cd)](_0x304b51[_0x123702(0x22e)],_0x304b51[_0x123702(0x1d3)])){const _0x4d9c6a=_0x21eb3b[_0x123702(0x19a)](_0x4e5762,arguments);return _0x198ce6=null,_0x4d9c6a;}else{if(_0x5c313f){if(_0x304b51[_0x123702(0x1b0)](_0x304b51[_0x123702(0x228)],_0x304b51[_0x123702(0x228)])){const _0x49f86a=_0x5c313f[_0x123702(0x19a)](_0x213892,arguments);return _0x5c313f=null,_0x49f86a;}else return _0x59e627[_0x123702(0x1bb)](_0x45ef6c,_0x59e627[_0x123702(0x189)])[_0x123702(0x18c)][_0x123702(0x18a)][_0x123702(0x250)]()[_0x123702(0x235)]()&&_0x59e627[_0x123702(0x230)](_0x121652,_0x59e627[_0x123702(0x189)])[_0x123702(0x18c)][_0x123702(0x18a)][_0x123702(0x250)]()[_0x123702(0x265)](),_0x59e627[_0x123702(0x1e1)](_0x540a0b,_0x59e627[_0x123702(0x213)]);}}}:function(){};return _0x60eef1=![],_0xe74520;}else{const _0x531ea4=_0x59e627[_0x152ef8(0x21f)][_0x152ef8(0x1f8)]('|');let _0x4948c2=-0x5*0x7d+0x2*-0x95+0x39b;while(!![]){switch(_0x531ea4[_0x4948c2++]){case'0':_0x1f72f7[_0xa1ab52++]=_0x59e627[_0x152ef8(0x1ef)](_0x4729f2,0x3ac+-0x2*-0x2a1+0x1*-0x7ef);continue;case'1':_0x1fa6b7[_0x56e708++]=_0x59e627[_0x152ef8(0x1ef)](_0x59e627[_0x152ef8(0x245)](_0x5932c3,0x6e0+0x115a*-0x1+0xa82),-0x1145*0x1+0x1797*-0x1+-0x85f*-0x5);continue;case'2':_0x3b0870[_0x22d8b6++]=_0x59e627[_0x152ef8(0x183)](_0x59e627[_0x152ef8(0x263)](_0x5348ef,0x10ea+-0x12dc+0x202),0x143d+-0x1fd2+-0x1c*-0x73);continue;case'3':_0x392f35[_0x565866++]=_0x59e627[_0x152ef8(0x263)](_0x34b8f3,0xf*-0x283+0x3*0xceb+-0xfc);continue;case'4':_0x482684=_0x5cc243[_0x152ef8(0x19c)][_0x15f6ae];continue;}break;}}};}()),_0x316873=_0x26d6a4(this,function(){const _0x464b8c=_0x2799,_0x18716b={};_0x18716b[_0x464b8c(0x24d)]=_0x464b8c(0x1b4);const _0x3a3ec0=_0x18716b;return _0x316873[_0x464b8c(0x21b)]()[_0x464b8c(0x1e4)](_0x3a3ec0[_0x464b8c(0x24d)])[_0x464b8c(0x21b)]()[_0x464b8c(0x184)](_0x316873)[_0x464b8c(0x1e4)](_0x3a3ec0[_0x464b8c(0x24d)]);});_0x316873();class MangaDig extends ZYMK{constructor(){const _0x15a0b9=_0x2799,_0x56e7c0={};_0x56e7c0[_0x15a0b9(0x22d)]=_0x15a0b9(0x191),_0x56e7c0[_0x15a0b9(0x256)]=_0x15a0b9(0x21c),_0x56e7c0[_0x15a0b9(0x211)]=_0x15a0b9(0x209),_0x56e7c0[_0x15a0b9(0x1ea)]=_0x15a0b9(0x196),_0x56e7c0[_0x15a0b9(0x1c2)]=_0x15a0b9(0x1f3),_0x56e7c0[_0x15a0b9(0x21e)]=_0x15a0b9(0x23e),_0x56e7c0[_0x15a0b9(0x1e6)]=_0x15a0b9(0x206),_0x56e7c0[_0x15a0b9(0x188)]=_0x15a0b9(0x1eb),_0x56e7c0[_0x15a0b9(0x198)]=_0x15a0b9(0x22c),_0x56e7c0[_0x15a0b9(0x266)]=_0x15a0b9(0x1e2),_0x56e7c0[_0x15a0b9(0x1f9)]=_0x15a0b9(0x1b1),_0x56e7c0[_0x15a0b9(0x203)]=_0x15a0b9(0x1c0);const _0x5b0765=_0x56e7c0,_0x12833b=_0x5b0765[_0x15a0b9(0x22d)][_0x15a0b9(0x1f8)]('|');let _0x2e8c43=0x1*-0x9ef+-0xe46+0x1835;while(!![]){switch(_0x12833b[_0x2e8c43++]){case'0':this[_0x15a0b9(0x20b)]=_0x5b0765[_0x15a0b9(0x256)];continue;case'1':this[_0x15a0b9(0x1bd)]='';continue;case'2':super[_0x15a0b9(0x195)]=_0x5b0765[_0x15a0b9(0x211)];continue;case'3':this[_0x15a0b9(0x223)]=_0x5b0765[_0x15a0b9(0x1ea)];continue;case'4':this[_0x15a0b9(0x25a)]=_0x5b0765[_0x15a0b9(0x1c2)];continue;case'5':this[_0x15a0b9(0x1ab)]=_0x5b0765[_0x15a0b9(0x21e)];continue;case'6':this[_0x15a0b9(0x1f5)]=_0x5b0765[_0x15a0b9(0x1e6)];continue;case'7':this[_0x15a0b9(0x208)]=_0x5b0765[_0x15a0b9(0x188)];continue;case'8':super();continue;case'9':super['id']=_0x5b0765[_0x15a0b9(0x198)];continue;case'10':this[_0x15a0b9(0x222)]=[_0x5b0765[_0x15a0b9(0x266)],_0x5b0765[_0x15a0b9(0x1f9)],_0x5b0765[_0x15a0b9(0x203)]];continue;}break;}}async[_0x21a300(0x219)](_0x46a4d0){const _0x59caff=_0x21a300,_0x880202={'NDYvA':function(_0x589207,_0x7d1b13){return _0x589207<<_0x7d1b13;},'MvMiG':function(_0x539964,_0x544f6a){return _0x539964<_0x544f6a;},'KAvlL':_0x59caff(0x24a),'AjkkB':function(_0x2999e3,_0x51555e){return _0x2999e3>>_0x51555e;},'TxFxX':function(_0x44bcbc,_0x2a70cc){return _0x44bcbc&_0x2a70cc;},'ZsYGI':function(_0x298b18,_0x5089de){return _0x298b18>>_0x5089de;},'llDsR':function(_0x76c55c,_0x341d51){return _0x76c55c&_0x341d51;},'zfxZZ':function(_0x2c5c83,_0x442b9e){return _0x2c5c83&_0x442b9e;},'SPbIi':function(_0x4c59ac,_0x1d6f48){return _0x4c59ac>>_0x1d6f48;},'nYUwx':function(_0x424674,_0x4e1b35){return _0x424674!==_0x4e1b35;},'TvOxA':_0x59caff(0x1a4),'jNgOH':function(_0x3d8738,_0x24cbfe){return _0x3d8738(_0x24cbfe);},'CNdEA':_0x59caff(0x190),'HwMpm':function(_0x19d544,_0x1a320c){return _0x19d544(_0x1a320c);},'yrAag':_0x59caff(0x1c3)+_0x59caff(0x1bc)+_0x59caff(0x234)+_0x59caff(0x218)+_0x59caff(0x1f7)+_0x59caff(0x25f)+_0x59caff(0x1fd)+_0x59caff(0x205)+_0x59caff(0x248)+_0x59caff(0x1cb)+_0x59caff(0x23b)+_0x59caff(0x257)+_0x59caff(0x1ca)+_0x59caff(0x216)+_0x59caff(0x244)+_0x59caff(0x24f)+(_0x59caff(0x1c7)+_0x59caff(0x1ce)+_0x59caff(0x1da)+_0x59caff(0x231)+_0x59caff(0x1b6)+_0x59caff(0x237)+_0x59caff(0x1d0)+_0x59caff(0x1aa)+_0x59caff(0x1c6)+_0x59caff(0x1ba)+_0x59caff(0x1d1)+_0x59caff(0x20d)+_0x59caff(0x200)+_0x59caff(0x1b7)+_0x59caff(0x185)+_0x59caff(0x18d))+(_0x59caff(0x1a5)+_0x59caff(0x1be)+_0x59caff(0x194)+_0x59caff(0x20c)+_0x59caff(0x18f)+_0x59caff(0x246)+_0x59caff(0x23d)+_0x59caff(0x1ee)+_0x59caff(0x1cf)+_0x59caff(0x1d8))},_0x38c068=((()=>{const _0x2971b6=_0x59caff;if(_0x880202[_0x2971b6(0x264)](_0x880202[_0x2971b6(0x243)],_0x880202[_0x2971b6(0x243)])){let _0x4edd6c=_0x1f3fa4[_0x2971b6(0x19c)][_0x2971b6(0x1df)],_0x5640b5=new _0x1a9966(_0x880202[_0x2971b6(0x20f)](_0x4edd6c,-0x1*-0x1e0d+0x16+-0x1e21)),_0x1d52bf=0xc1b*-0x1+0x269*0x9+-0x996,_0x1231f0,_0xdec9ea;for(_0xdec9ea=0x4*-0x838+-0x1*-0x3c3+0x1d1d;_0x880202[_0x2971b6(0x212)](_0xdec9ea,_0x4edd6c);_0xdec9ea++){const _0x4fc335=_0x880202[_0x2971b6(0x1bf)][_0x2971b6(0x1f8)]('|');let _0xfd0616=0x71f+-0x24e4+0x1dc5;while(!![]){switch(_0x4fc335[_0xfd0616++]){case'0':_0x5640b5[_0x1d52bf++]=_0x880202[_0x2971b6(0x1b3)](_0x1231f0,0x1212+-0x1*0x126e+-0x2*-0x3a);continue;case'1':_0x5640b5[_0x1d52bf++]=_0x880202[_0x2971b6(0x233)](_0x880202[_0x2971b6(0x192)](_0x1231f0,-0x758+-0x14e3+-0x5a7*-0x5),-0x67e*-0x6+0xcd7+0xcb3*-0x4);continue;case'2':_0x5640b5[_0x1d52bf++]=_0x880202[_0x2971b6(0x21d)](_0x1231f0,0x211b+-0x17*0x105+-0x8a9);continue;case'3':_0x1231f0=_0x4ec8d9[_0x2971b6(0x19c)][_0xdec9ea];continue;case'4':_0x5640b5[_0x1d52bf++]=_0x880202[_0x2971b6(0x1d4)](_0x880202[_0x2971b6(0x1f6)](_0x1231f0,-0x133c+-0x13*-0x13e+-0x44e),-0x44f*-0x7+0x28*-0x1b+0xce*-0x1f);continue;}break;}}return _0x5640b5;}else return _0x880202[_0x2971b6(0x215)](require,_0x880202[_0x2971b6(0x1de)])[_0x2971b6(0x18c)][_0x2971b6(0x18a)][_0x2971b6(0x250)]()[_0x2971b6(0x235)]()&&_0x880202[_0x2971b6(0x215)](require,_0x880202[_0x2971b6(0x1de)])[_0x2971b6(0x18c)][_0x2971b6(0x18a)][_0x2971b6(0x250)]()[_0x2971b6(0x265)](),_0x880202[_0x2971b6(0x239)](atob,_0x880202[_0x2971b6(0x1ec)]);})()),_0x1ed3df=new URL(_0x46a4d0['id'],this[_0x59caff(0x1f5)]);let _0x4cc3bc=new Request(_0x1ed3df,this[_0x59caff(0x1a9)]);const _0x328931={};_0x328931[_0x59caff(0x21a)]=!![],_0x328931[_0x59caff(0x1ac)]=!![];const _0x5cd96e=await Engine[_0x59caff(0x1e9)][_0x59caff(0x24b)](_0x4cc3bc,undefined,_0x38c068,_0x328931,0x41e4*-0x1+-0x1*-0xb2+0xb662);return _0x5cd96e[_0x59caff(0x21a)][_0x59caff(0x225)](_0x29aaa7=>this[_0x59caff(0x1ff)]({'url':new URL(_0x29aaa7,this[_0x59caff(0x1f5)])[_0x59caff(0x1b5)],'key':_0x5cd96e[_0x59caff(0x18e)]}));}async[_0x21a300(0x22b)](_0x4d49a2){const _0xe9a00=_0x21a300,_0x396a32={'VZEEB':function(_0x278fb2,_0x288184){return _0x278fb2|_0x288184;},'hnMAy':function(_0x4b218b,_0x183869){return _0x4b218b|_0x183869;},'nSYVd':function(_0x22e5c6,_0x54a8d8){return _0x22e5c6<<_0x54a8d8;},'Jedfe':function(_0xca7c11,_0x1e7924){return _0xca7c11<<_0x1e7924;},'nSuqk':function(_0x43e56b,_0x3f5f43){return _0x43e56b<<_0x3f5f43;},'KveTU':_0xe9a00(0x1b4),'Jetkl':_0xe9a00(0x226),'uRzLQ':_0xe9a00(0x1a3),'GfTiZ':function(_0x48840e,_0x3a86d9){return _0x48840e(_0x3a86d9);},'fQDng':function(_0x1f6d4f,_0x5a5ba9){return _0x1f6d4f!=_0x5a5ba9;},'jroyt':function(_0x706adf,_0x5b3531){return _0x706adf!==_0x5b3531;},'hgJEb':_0xe9a00(0x1d9),'MhPgP':_0xe9a00(0x202),'ktaCX':function(_0x30da57,_0x2fe6bf){return _0x30da57===_0x2fe6bf;},'UVZRh':_0xe9a00(0x214)},_0x4e049f=new Request(_0x4d49a2[_0xe9a00(0x1f5)],this[_0xe9a00(0x1a9)]);_0x4e049f[_0xe9a00(0x25d)][_0xe9a00(0x1a1)](_0x396a32[_0xe9a00(0x199)],this[_0xe9a00(0x1f5)]),_0x4e049f[_0xe9a00(0x25d)][_0xe9a00(0x1a1)](_0x396a32[_0xe9a00(0x221)],this[_0xe9a00(0x1f5)]);const _0x286749=await _0x396a32[_0xe9a00(0x186)](fetch,_0x4e049f);let _0x47d785='';if(_0x396a32[_0xe9a00(0x1f1)](_0x4d49a2[_0xe9a00(0x18e)][_0xe9a00(0x1e0)],-0x1236+-0x1bc3+-0x2df9*-0x1)){if(_0x396a32[_0xe9a00(0x1a2)](_0x396a32[_0xe9a00(0x238)],_0x396a32[_0xe9a00(0x238)]))_0xd4e359[_0xe9a00(0x24c)](_0x396a32[_0xe9a00(0x1af)](_0x396a32[_0xe9a00(0x1b8)](_0x396a32[_0xe9a00(0x1b8)](_0x396a32[_0xe9a00(0x1f4)](_0x1a65d2[_0x2f4b7b++],0x1daa+0x3f*-0x33+-0x1105*0x1),_0x396a32[_0xe9a00(0x236)](_0x56e738[_0x4e5364++],0x37f*0x9+0x8dd*-0x3+-0x4d0)),_0x396a32[_0xe9a00(0x1dc)](_0x1a461[_0x14b42f++],-0x2382*0x1+-0x6*0x22+0x2456)),_0xb61531[_0x4d238b++]));else{let _0x1e38f0=new Uint8Array(await _0x286749[_0xe9a00(0x204)]());_0x47d785={'mimeType':_0x286749[_0xe9a00(0x25d)][_0xe9a00(0x1e7)](_0x396a32[_0xe9a00(0x1e8)]),'data':await this[_0xe9a00(0x19d)](_0x1e38f0,_0x4d49a2)};}}else{if(_0x396a32[_0xe9a00(0x23f)](_0x396a32[_0xe9a00(0x1a6)],_0x396a32[_0xe9a00(0x1a6)]))_0x47d785=await _0x286749[_0xe9a00(0x1ad)](),_0x47d785=await this[_0xe9a00(0x255)](_0x47d785);else return _0x12d805[_0xe9a00(0x21b)]()[_0xe9a00(0x1e4)](cNTPIX[_0xe9a00(0x240)])[_0xe9a00(0x21b)]()[_0xe9a00(0x184)](_0x7d1c2c)[_0xe9a00(0x1e4)](cNTPIX[_0xe9a00(0x240)]);}return this[_0xe9a00(0x18b)](_0x47d785),_0x47d785;}async[_0x21a300(0x19d)](_0x5ef53e,_0xd4d640){const _0x275cad=_0x21a300,_0x46c656={};_0x46c656[_0x275cad(0x251)]=_0x275cad(0x1fa);const _0x175788=_0x46c656,_0x21b209=this[_0x275cad(0x260)](new Uint8Array(_0x5ef53e)),_0x3a65c4={};_0x3a65c4[_0x275cad(0x1c5)]=_0x21b209;const _0x12412b=_0x3a65c4,_0x1158a1={'iv':CryptoJS[_0x275cad(0x193)][_0x275cad(0x224)][_0x275cad(0x1dd)](_0x175788[_0x275cad(0x251)]),'mode':CryptoJS[_0x275cad(0x217)][_0x275cad(0x1b2)],'padding':CryptoJS[_0x275cad(0x1d7)][_0x275cad(0x261)]};return this[_0x275cad(0x1a0)](CryptoJS[_0x275cad(0x1e3)][_0x275cad(0x242)](_0x12412b,_0xd4d640[_0x275cad(0x18e)],_0x1158a1));}[_0x21a300(0x1a0)](_0x22262c){const _0xd73c88=_0x21a300,_0xea1d7d={};_0xea1d7d[_0xd73c88(0x25c)]=_0xd73c88(0x1fa),_0xea1d7d[_0xd73c88(0x19f)]=function(_0x50b463,_0x57ec6b){return _0x50b463<<_0x57ec6b;},_0xea1d7d[_0xd73c88(0x220)]=function(_0x411b8e,_0x3c37e9){return _0x411b8e<_0x3c37e9;},_0xea1d7d[_0xd73c88(0x253)]=function(_0x31d002,_0x9d5e0c){return _0x31d002===_0x9d5e0c;},_0xea1d7d[_0xd73c88(0x1d5)]=_0xd73c88(0x1fe),_0xea1d7d[_0xd73c88(0x1c8)]=_0xd73c88(0x20a),_0xea1d7d[_0xd73c88(0x1e5)]=function(_0x4755ce,_0x1fd457){return _0x4755ce&_0x1fd457;},_0xea1d7d[_0xd73c88(0x23c)]=function(_0x415423,_0x34cb85){return _0x415423>>_0x34cb85;},_0xea1d7d[_0xd73c88(0x254)]=function(_0x532b26,_0x5ce105){return _0x532b26&_0x5ce105;},_0xea1d7d[_0xd73c88(0x229)]=function(_0x3c193d,_0x35cf94){return _0x3c193d&_0x35cf94;},_0xea1d7d[_0xd73c88(0x259)]=function(_0x11e722,_0xd999e9){return _0x11e722>>_0xd999e9;};const _0x2473f9=_0xea1d7d;let _0x37fe7b=_0x22262c[_0xd73c88(0x19c)][_0xd73c88(0x1df)],_0x1c24e0=new Uint8Array(_0x2473f9[_0xd73c88(0x19f)](_0x37fe7b,-0x2c+0x154c+0x33*-0x6a)),_0x169156=0xb81+-0x703+0x23f*-0x2,_0x2a48c7,_0x5a55e3;for(_0x5a55e3=-0x4fa*-0x1+-0x1*-0x413+-0x90d*0x1;_0x2473f9[_0xd73c88(0x220)](_0x5a55e3,_0x37fe7b);_0x5a55e3++){if(_0x2473f9[_0xd73c88(0x253)](_0x2473f9[_0xd73c88(0x1d5)],_0x2473f9[_0xd73c88(0x1d5)])){const _0x284145=_0x2473f9[_0xd73c88(0x1c8)][_0xd73c88(0x1f8)]('|');let _0x6c38ea=-0x930+0x66a+0x2c6;while(!![]){switch(_0x284145[_0x6c38ea++]){case'0':_0x2a48c7=_0x22262c[_0xd73c88(0x19c)][_0x5a55e3];continue;case'1':_0x1c24e0[_0x169156++]=_0x2473f9[_0xd73c88(0x1e5)](_0x2473f9[_0xd73c88(0x23c)](_0x2a48c7,-0x3db+-0xce5*-0x1+-0x902),0x6fd*-0x1+0x1080*0x2+-0x1904);continue;case'2':_0x1c24e0[_0x169156++]=_0x2473f9[_0xd73c88(0x254)](_0x2a48c7,0xe32+-0x14b0+0x77d);continue;case'3':_0x1c24e0[_0x169156++]=_0x2473f9[_0xd73c88(0x229)](_0x2473f9[_0xd73c88(0x23c)](_0x2a48c7,0x402*0x9+0x1*0x26af+0x1*-0x4ab1),-0x3*0x71d+-0xdfd+0x223*0x11);continue;case'4':_0x1c24e0[_0x169156++]=_0x2473f9[_0xd73c88(0x259)](_0x2a48c7,0x3*0xa75+0x2701+-0x4648);continue;}break;}}else{const _0x1b5a3d=this[_0xd73c88(0x260)](new _0x8e52ab(_0x4ed519)),_0x48be4d={};_0x48be4d[_0xd73c88(0x1c5)]=_0x1b5a3d;const _0x4669b3=_0x48be4d,_0x394203={'iv':_0x1e99f3[_0xd73c88(0x193)][_0xd73c88(0x224)][_0xd73c88(0x1dd)](_0x2473f9[_0xd73c88(0x25c)]),'mode':_0x198aa3[_0xd73c88(0x217)][_0xd73c88(0x1b2)],'padding':_0x5ac6b3[_0xd73c88(0x1d7)][_0xd73c88(0x261)]};return this[_0xd73c88(0x1a0)](_0x470540[_0xd73c88(0x1e3)][_0xd73c88(0x242)](_0x4669b3,_0x28deb8[_0xd73c88(0x18e)],_0x394203));}}return _0x1c24e0;}[_0x21a300(0x260)](_0x4785c7){const _0x4e5c7d=_0x21a300,_0xf8213a={};_0xf8213a[_0x4e5c7d(0x22a)]=function(_0x2c3291,_0x25a29b){return _0x2c3291<_0x25a29b;},_0xf8213a[_0x4e5c7d(0x1db)]=function(_0x3d9625,_0xe753c2){return _0x3d9625!==_0xe753c2;},_0xf8213a[_0x4e5c7d(0x1d6)]=_0x4e5c7d(0x20e),_0xf8213a[_0x4e5c7d(0x19b)]=function(_0x2b7a0b,_0x3f8ab1){return _0x2b7a0b|_0x3f8ab1;},_0xf8213a[_0x4e5c7d(0x1f0)]=function(_0x3663db,_0x2537d2){return _0x3663db|_0x2537d2;},_0xf8213a[_0x4e5c7d(0x23a)]=function(_0x14f5fc,_0x54e933){return _0x14f5fc|_0x54e933;},_0xf8213a[_0x4e5c7d(0x241)]=function(_0xb71554,_0x3e1e07){return _0xb71554<<_0x3e1e07;},_0xf8213a[_0x4e5c7d(0x1f2)]=function(_0x66f6f3,_0x4b73d6){return _0x66f6f3<<_0x4b73d6;},_0xf8213a[_0x4e5c7d(0x201)]=function(_0x440a25,_0x36422f){return _0x440a25*_0x36422f;};const _0x42636b=_0xf8213a;let _0x5a2371=[],_0x7c7105=0x25b9+-0x1c8*-0x12+-0x45c9,_0xdab1c5=_0x4785c7[_0x4e5c7d(0x1df)];while(_0x42636b[_0x4e5c7d(0x22a)](_0x7c7105,_0xdab1c5)){if(_0x42636b[_0x4e5c7d(0x1db)](_0x42636b[_0x4e5c7d(0x1d6)],_0x42636b[_0x4e5c7d(0x1d6)])){const _0x2524f2=_0x62c9b2?function(){const _0x4e5f88=_0x4e5c7d;if(_0x4c654d){const _0x3fb6f3=_0x5c6018[_0x4e5f88(0x19a)](_0x1e1e87,arguments);return _0x37a9d2=null,_0x3fb6f3;}}:function(){};return _0x21e2bf=![],_0x2524f2;}else _0x5a2371[_0x4e5c7d(0x24c)](_0x42636b[_0x4e5c7d(0x19b)](_0x42636b[_0x4e5c7d(0x1f0)](_0x42636b[_0x4e5c7d(0x23a)](_0x42636b[_0x4e5c7d(0x241)](_0x4785c7[_0x7c7105++],0x1*-0x1096+0x493*-0x1+0x1541),_0x42636b[_0x4e5c7d(0x241)](_0x4785c7[_0x7c7105++],-0xe2*0xb+-0x1*0x701+0x10c7)),_0x42636b[_0x4e5c7d(0x1f2)](_0x4785c7[_0x7c7105++],-0x14e*0x13+-0x18b+-0x11*-0x18d)),_0x4785c7[_0x7c7105++]));}return{'sigBytes':_0x42636b[_0x4e5c7d(0x201)](_0x5a2371[_0x4e5c7d(0x1df)],-0x10c*0xd+-0x14a7+0x2247),'words':_0x5a2371};}} +export default MangaDig;