diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e99e36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a6735e5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.typeCheckingMode": "off" +} \ No newline at end of file diff --git a/MLEP-IRS.md b/MLEP-IRS.md new file mode 100644 index 0000000..bca1e83 --- /dev/null +++ b/MLEP-IRS.md @@ -0,0 +1,51 @@ +# [Manga Loader with more features]() + +## What is an MLEP +`EP` is abbreviation of `Enhance Proposal`. +There are `PEP`(Python EP), `CEP`(Cython EP), `NEP`(NumPy EP)... +So here is Manga Loader Enhance Proposal, `MLEP`. ;) +In my opinion, an `EP` is more of a concept than a specific implementation. + +## MLEP: Implementation Repository System +### Why Implementation Repository System +Currently, Manga Loader puts all implementations inside itself. +This means that browser have to load ALL implementations EVERY time. +Also, when someone adds a new implementation or fixes an existing implementation, they have to commit to the whole manga loader script. + +### Main part of Implementation Repository System +#### Server +An Implementation Repository should have: +- a plain text file indicating its version (version file) +- a `json` file containing subrepo name and URL regex of every implementation (information file) +- directories containing implementation `js` files (subrepos) +#### Client +When loading implementations, manga loader does following things: +- fetch version file from repository and update information file if local version is outdated +- test every URL regex on window URL and find out which implementation to use +- fetch and save implementation `js` file from repo if it is not available locally and eval the implementation + +### Direct match (optional) +If name of an implementation is a substring of its URL regex, then it is a "direct match". +When looking for appropriate implementation, for direct matches, only subtring search (`name in pageUrl`) is performed. +This is because regex matching is a heavy operation and should be avoided to save time. However, for small repos, support for this can be dropped by marking every implementation as regex match. + +### Map to existing implementation (optional) +There are situations that multiple sites can use the same implementation, and this action used to be done by making the regex of an implementation match all the target sites. +However, this can make git diff messer when a site in such group is added or deleted, so here is "map to existing implementation". +It is handled in information file. +Note: User Override should be prior to mapping. For example, when `A` is mapped to `B` and a User Override of `A` exists, Manga Loader should read User Override of `A`. +Suggestions on mapping: +- When there are multiple sites based on the same template and evidence indicates the other sites are copying from one site, map copying sites to copied site. +- When there are multiple sites based on the same template and the template is public, create a separate file for the template and map all sites to implementation for the template. (For example, `foolslide`.) +- When multiple sites turns out to be mirrors of the same site, do not use mapping and just update regex for the main site. +- When nothing is known or it is hard to decide, map the site that is added later to earlier ones. + +### Subrepos and NSFW control +Just put NSFW implementations in a separate subrepo and make normal version give up searching implementations from it. + +### User Override +The measures above comes with trouble in implementation developing and debugging: you have to modify remote files to test changes. Thus, "User Override" is introduced. +When loading an implementation of a certain name, Manga Loader will try to load User Override instead of script from repository. Note that User Override is just a "mask", the repo scripts are still updated as usual. + +### Migrating from original code +Can be done with scripts. See `utils/parse_impls.py`. \ No newline at end of file diff --git "a/impls/normal/2comic.com \345\213\225\346\274\253\346\230\223.js" "b/impls/normal/2comic.com \345\213\225\346\274\253\346\230\223.js" new file mode 100644 index 0000000..fda10a5 --- /dev/null +++ "b/impls/normal/2comic.com \345\213\225\346\274\253\346\230\223.js" @@ -0,0 +1,40 @@ +// METADATA +// match: http://twocomic.com/view/comic_\d+.html + +var impl_src = { + img: '#TheImg', + next: function() { + return '#'; + }, + pages: function(url, num, cb, ex) { + W.p++; + var ss = W.ss; + var c = W.c; + var ti = W.ti; + var nn = W.nn; + var p = W.p; + var mm = W.mm; + var f = W.f; + var img = 'http://img' + ss(c, 4, 2) + '.8comic.com/' + ss(c, 6, 1) + '/' + ti + '/' + ss(c, 0, 4) + '/' + nn(p) + '_' + ss(c, mm(p) + 10, 3, f) + '.jpg'; + cb(img, num - 1); + }, + numpages: function() { + return W.ps * 1; + }, + curpage: function() { + return W.p; + }, + numchaps: function() { + return W.chs; + }, + curchap: function() { + return W.ch; + }, + nextchap: function() { + return W.ch < W.chs ? W.replaceurl('ch', W.ni) : false; + }, + prevchap: function() { + return W.ch > 1 ? W.replaceurl('ch', W.pi) : false; + }, + wait:'#TheImg' +} \ No newline at end of file diff --git a/impls/normal/3asq.js b/impls/normal/3asq.js new file mode 100644 index 0000000..5b12328 --- /dev/null +++ b/impls/normal/3asq.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://www\.3asq\.org/[^/]+/[0-9.]+ +// mapto: manga-cow \ No newline at end of file diff --git a/impls/normal/930mh.js b/impls/normal/930mh.js new file mode 100644 index 0000000..02623e0 --- /dev/null +++ b/impls/normal/930mh.js @@ -0,0 +1,25 @@ +// METADATA +// match: http://www\.930mh\.com/manhua/\d+/\d+.html + +var impl_src = { + img: '#images > img', + next: function() { + return location.origin + location.pathname + '?p=' + (W.SinTheme.getPage() + 1); + }, + pages: function(url, num, cb, ex) { + cb(new URL(W.pageImage).origin + '/' + W.chapterPath + W.chapterImages[num - 1], num - 1); + }, + curpage: function() { + return W.SinTheme.getPage(); + }, + numpages: function() { + return W.chapterImages.length; + }, + nextchap: function(){ + return W.nextChapterData.id && W.nextChapterData.id > 0 ? W.comicUrl + W.nextChapterData.id + '.html' : null; + }, + prevchap: function(){ + return W.prevChapterData.id && W.prevChapterData.id > 0 ? W.comicUrl + W.prevChapterData.id + '.html' : null; + }, + wait: '#images > img' +} \ No newline at end of file diff --git a/impls/normal/abandonedkittenscans.js b/impls/normal/abandonedkittenscans.js new file mode 100644 index 0000000..ffd73cb --- /dev/null +++ b/impls/normal/abandonedkittenscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://abandonedkittenscans\.mokkori\.fr/reader/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/anime-a.js b/impls/normal/anime-a.js new file mode 100644 index 0000000..8cb2491 --- /dev/null +++ b/impls/normal/anime-a.js @@ -0,0 +1,19 @@ +// METADATA +// match: ^https?://manga\.animea.net/.+chapter-[0-9]+(-page-[0-9]+)?.html + +var impl_src = { + _page: null, + img: '#scanmr', + next: function() { + if(this._page === null) this._page = W.page; + return W.series_url + W.chapter + '-page-' + (this._page += 1) + '.html'; + }, + numpages: '.pageselect', + curpage: '.pageselect', + nextchap: function(prev) { + return W.series_url + 'chapter-' + (parseInt(W.chapter.match(/[0-9]+/)[0]) + (prev ? -1 : 1)) + '-page-1.html'; + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/batoto.js b/impls/normal/batoto.js new file mode 100644 index 0000000..a0f5204 --- /dev/null +++ b/impls/normal/batoto.js @@ -0,0 +1,50 @@ +// METADATA +// match: ^https?://bato.to/reader.* + +var impl_src = { + img: function(ctx) { + var img = getEl('#comic_page', ctx); + if(img) { + return img.src; + } else { + var imgs = getEls('#content > div:nth-child(8) > img', ctx).map(function(page) { + return page.src; + }); + if(imgs.length > 0) { + this.next = function() { return imgs[0]; }; + this.numpages = function() { return imgs.length; }; + this.pages = function(url, num, cb, ex) { + cb(imgs[num - 1], num); + }; + return imgs[0]; + } + } + }, + next: function() { + if(!this._numpage) { + this._numpage = extractInfo(this.curpage, {type: 'index'}); + this._id = location.hash.split('_')[0].slice(1); + } + return '/areader?id=' + this._id + '&p=' + (++this._numpage); + }, + numpages: '#page_select', + curpage: '#page_select', + curchap: 'select[name=chapter_select]', + numchaps: 'select[name=chapter_select]', + nextchap: function(prev) { + //var link = extractInfo('select[name=chapter_select]', {type: 'value', val: prev ? 1 : -1}); + //return link && link.replace(/https?/, document.location.href.split(':')[0]); // fix for batotos broken https pages + var menu = getEls('div.moderation_bar > ul > li', getEl('#reader')); + for (var i = 0; i != menu.length; i += 1) { + var img = getEl('img', menu[i]); + if (img && img.title == (prev ? "Previous Chapter" : "Next Chapter")) { + return img.parentNode.href.replace(/https?/, document.location.href.split(':')[0]); + } + } + return null; + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: '#comic_page' +} \ No newline at end of file diff --git a/impls/normal/biamamscans.com.js b/impls/normal/biamamscans.com.js new file mode 100644 index 0000000..421b146 --- /dev/null +++ b/impls/normal/biamamscans.com.js @@ -0,0 +1,12 @@ +// METADATA +// match: ^https?://biamamscans\.com/read/.+ + +var impl_src = { + //nextchap and prevchap broken + img: '.manga-image', + next: 'span.float-right:nth-child(2) > div:nth-child(2) > a:nth-child(1)', + numpages: '#page-select', + curpage: '#page-select', + nextchap: '#chapter-select', + prevchap: '#chapter-select' +} \ No newline at end of file diff --git a/impls/normal/br.mangahost.com.js b/impls/normal/br.mangahost.com.js new file mode 100644 index 0000000..64a6bd7 --- /dev/null +++ b/impls/normal/br.mangahost.com.js @@ -0,0 +1,9 @@ +// METADATA +// match: ^http(s)?://br.mangahost.com/manga/[^/]+/.+ + +var impl_src = { + img: 'img.open', + next: '.image-content > a', + curpage: '.viewerPage', + numpages: '.viewerPage' +} \ No newline at end of file diff --git a/impls/normal/cafeconirst.js b/impls/normal/cafeconirst.js new file mode 100644 index 0000000..a6d482f --- /dev/null +++ b/impls/normal/cafeconirst.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.cafeconirst\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/cartoonmad.js b/impls/normal/cartoonmad.js new file mode 100644 index 0000000..28907b7 --- /dev/null +++ b/impls/normal/cartoonmad.js @@ -0,0 +1,24 @@ +// METADATA +// match: https?://(www\.)?(cartoonmad|comicnad)\.com/comic/[0-9]+\.html + +var impl_src = { + img: 'tr:nth-child(5) > td > table > tbody > tr:nth-child(1) > td > a > img', + next: 'a.onpage+a', + curpage: 'a.onpage', + numpages: function() { + return extractInfo('select[name=jump]') - 1; + }, + nextchap: function() { + let filter = getEls('.pages').filter(function(i) { + return i.textContent.match('下一話'); + }); + return filter.length ? filter[0].href : null; + }, + prevchap: function() { + let filter = getEls('.pages').filter(function(i) { + return i.textContent.match('上一話'); + }); + return filter.length ? filter[0].href : null; + }, + +} \ No newline at end of file diff --git a/impls/normal/casanovascans.js b/impls/normal/casanovascans.js new file mode 100644 index 0000000..e130730 --- /dev/null +++ b/impls/normal/casanovascans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://casanovascans\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/central-de-mangas.js b/impls/normal/central-de-mangas.js new file mode 100644 index 0000000..b20c9ad --- /dev/null +++ b/impls/normal/central-de-mangas.js @@ -0,0 +1,20 @@ +// METADATA +// match: ^https?://(centraldemangas\.org|[^\.]+\.com\.br/leitura)/online/[^/]*/[0-9]* + +var impl_src = { + img: '#manga-page', + next: '#manga-page', + numpages: '#manga_pages', + curpage: '#manga_pages', + nextchap: function(prev) { + var next = extractInfo('#manga_caps', {type: 'value', val: (prev ? -1 : 1)}); + if(next) return window.location.href.replace(/[^\/]+$/, next); + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + url = url.slice(0, url.lastIndexOf('-') + 1) + ("0" + num).slice(-2) + url.slice(url.lastIndexOf('.')); + cb(url, url); + } +} \ No newline at end of file diff --git a/impls/normal/championscans.js b/impls/normal/championscans.js new file mode 100644 index 0000000..4f962b8 --- /dev/null +++ b/impls/normal/championscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.championscans\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/chuixue.js b/impls/normal/chuixue.js new file mode 100644 index 0000000..2edc611 --- /dev/null +++ b/impls/normal/chuixue.js @@ -0,0 +1,19 @@ +// METADATA +// match: ^https?://www.chuixue.com/manhua/[0-9]+/[0-9]+.html + +var impl_src = { + img: '#qTcms_pic', + next: '#qTcms_pic', + curpage: '#qTcms_select_i', + numpages: '#qTcms_select_i', + pages: function(url, num, cb, ex) { + if(!this._pages) { + this._pages = W.qTcms_S_m_murl.split('$qingtiandy$'); + } + cb(this._pages[num - 1], num); + }, + nextchap: function() { + return W.qTcms_Pic_nextArr; + }, + wait: '#qTcms_pic' +} \ No newline at end of file diff --git a/impls/normal/comicastle.js b/impls/normal/comicastle.js new file mode 100644 index 0000000..2ca2d66 --- /dev/null +++ b/impls/normal/comicastle.js @@ -0,0 +1,14 @@ +// METADATA +// match: ^https?://comicastle\.org/read-.+ + +var impl_src = { + img: '.chapter-img', + next: '.chapter-content > select + a.label', + numpages: '.chapter-content > select', + curpage: '.chapter-content > select', + numchaps: '.form-control', + curchap: '.form-control', + nextchap: '.form-control', + prevchap: '.form-control', + invchap: true +} \ No newline at end of file diff --git a/impls/normal/demonicscans.js b/impls/normal/demonicscans.js new file mode 100644 index 0000000..1692ca1 --- /dev/null +++ b/impls/normal/demonicscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://www\.demonicscans\.com/FoOlSlide/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/dm5.js b/impls/normal/dm5.js new file mode 100644 index 0000000..770d1a8 --- /dev/null +++ b/impls/normal/dm5.js @@ -0,0 +1,23 @@ +// METADATA +// match: ^https?://[^\.]*\.dm5\.com/m[0-9]* + +var impl_src = { + img: function (){ + return getEl('img.load-src').getAttribute('data-src'); + }, + next: function(){ + return '#'; + }, + numpages: function () { + return W.pages.length; + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1].getAttribute('data-src'), num - 1); + }, + nextchap: 'a.logo_2', + prevchap: 'a.logo_1', + wait: function (){ + W.pages = getEls('img.load-src'); + return true; + } +} \ No newline at end of file diff --git a/impls/normal/dmzj.js b/impls/normal/dmzj.js new file mode 100644 index 0000000..a9fb03c --- /dev/null +++ b/impls/normal/dmzj.js @@ -0,0 +1,20 @@ +// METADATA +// match: ^https?://www.dmzj.com/view/[^/]+/.+\.html + +var impl_src = { + img: '.comic_wraCon > img', + next: '.comic_wraCon > img', + numpages: function() { + return parseInt(W.pic_total); + }, + curpage: function() { + var match = location.href.match(/page=([0-9])/); + return match ? parseInt(match[1]) : 1; + }, + nextchap: '.next > a', + prevchap: '.pre > a', + pages: function(url, num, cb, ex) { + cb(W.img_prefix + W.picArry[num - 1], num); + }, + wait: '.comic_wraCon > img' +} \ No newline at end of file diff --git a/impls/normal/eatmanga.js b/impls/normal/eatmanga.js new file mode 100644 index 0000000..d9a4f0f --- /dev/null +++ b/impls/normal/eatmanga.js @@ -0,0 +1,12 @@ +// METADATA +// match: ^https?://eatmanga.com/Manga-Scan/[^/]+/.+ + +var impl_src = { + img: '#eatmanga_image, #eatmanga_image_big', + next: '#page_next', + numpages: '#pages', + curpage: '#pages', + nextchap: '#bottom_chapter_list', + prevchap: '#bottom_chapter_list', + invchap: true +} \ No newline at end of file diff --git a/impls/normal/egscans.js b/impls/normal/egscans.js new file mode 100644 index 0000000..336936a --- /dev/null +++ b/impls/normal/egscans.js @@ -0,0 +1,22 @@ +// METADATA +// match: ^https?://read.egscans.com/.+ + +var impl_src = { + img: '#image_frame img', + next: '#image_frame img', + curpage: 'select[name=page]', + numpages: 'select[name=page]', + nextchap: function(prev) { + var data = getEl(this.curchap).getAttribute('onchange').match(/'[^']+'/g); + var next = extractInfo(this.curchap, { type: 'value', val: (prev ? -1 : 1) }); + if(next) return location.origin + '/' + data[0].slice(1, -1) + '/' + next; + }, + prevchap: function() { + return this.nextchap(true); + }, + curchap: 'select[name=chapter]', + numchaps: 'select[name=chapter]', + pages: function(url, num, cb, ex) { + cb('/' + W.img_url[num], num); + } +} \ No newline at end of file diff --git a/impls/normal/evilflowers.js b/impls/normal/evilflowers.js new file mode 100644 index 0000000..59cc395 --- /dev/null +++ b/impls/normal/evilflowers.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.evilflowers\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/famatg.js b/impls/normal/famatg.js new file mode 100644 index 0000000..d249a5d --- /dev/null +++ b/impls/normal/famatg.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://manga\.famatg\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/foolslide.js b/impls/normal/foolslide.js new file mode 100644 index 0000000..b341a5e --- /dev/null +++ b/impls/normal/foolslide.js @@ -0,0 +1,39 @@ +// METADATA +// match: META + +var impl_src = { + img: function() { + return W.pages[W.current_page].url; + }, + next: function() { + return 'N/A'; + }, + numpages: function() { + return W.pages.length; + }, + curpage: function() { + return W.current_page + 1; + }, + nextchap: function(prev) { + var desired; + var dropdown = getEls('ul.dropdown')[1] || getEls('ul.uk-nav')[1] || getEls('ul.dropdown-menu')[3]; + if(!dropdown) return; + getEls('a', dropdown).forEach(function(chap, idx, arr) { + if(location.href.indexOf(chap.href) === 0) desired = arr[idx + (prev ? 1 : -1)]; + }); + return desired && desired.href; + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1].url, num); + }, + wait: function() { + if(W.location.href.indexOf('gomanga.co') !== -1) { + var match = document.body.innerHTML.match(/(\w+)\[id\]\.url/); + W.pages = match && match[1] && W[match[1]]; + } + return W.pages; + } +} \ No newline at end of file diff --git a/impls/normal/friendshipscans.js b/impls/normal/friendshipscans.js new file mode 100644 index 0000000..4d72d15 --- /dev/null +++ b/impls/normal/friendshipscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://www\.friendshipscans\.com/slide/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/gmanga.js b/impls/normal/gmanga.js new file mode 100644 index 0000000..0808a87 --- /dev/null +++ b/impls/normal/gmanga.js @@ -0,0 +1,35 @@ +// METADATA +// match: ^https?://gmanga.me/mangas/ + +var impl_src = { + img: function() { + return W.pages[W.firstImg - 1]; + }, + next: function() { + return location.href + '#' + (W.firstImg + 1); + }, + numpages: function() { + return W.totalImgs; + }, + curpage: function() { + return W.firstImg; + }, + nextchap: function(prev) { + var num = parseInt(extractInfo('#chapter', {type: 'value', val: prev ? 1 : -1})); + return num && location.href.replace(/(\/mangas\/[^\/]+\/)[0-9]+(\/[^\/]+)/, '$1' + num + '$2'); + }, + prevchap: function() { + return this.nextchap(true); + }, + numchaps: '#chapter', + curchap: '#chapter', + invchap: true, + pages: function(url, num, cb, ex) { + var nexturl = location.href + '#' + (num + 1); + cb(W.pages[num - 1], nexturl); + }, + wait: function() { + W.pages = W.release_pages && W.release_pages[1]; + return W.pages; + } +} \ No newline at end of file diff --git a/impls/normal/gomanga.js b/impls/normal/gomanga.js new file mode 100644 index 0000000..944f0f3 --- /dev/null +++ b/impls/normal/gomanga.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://gomanga\.co/reader/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/hatigarmscans.js b/impls/normal/hatigarmscans.js new file mode 100644 index 0000000..b76730d --- /dev/null +++ b/impls/normal/hatigarmscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://hatigarmscans\.eu/hs/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/hellocomic.js b/impls/normal/hellocomic.js new file mode 100644 index 0000000..fc6dc66 --- /dev/null +++ b/impls/normal/hellocomic.js @@ -0,0 +1,13 @@ +// METADATA +// match: https?://hellocomic.com/[^/]+/[^/]+/p[0-9]+ + +var impl_src = { + img: '.coverIssue img', + next: '.coverIssue a', + numpages: '#e1', + curpage: '#e1', + nextchap: '#e2', + prevchap: '#e2', + curchap: '#e2', + numchaps: '#e2' +} \ No newline at end of file diff --git a/impls/normal/helveticascans.js b/impls/normal/helveticascans.js new file mode 100644 index 0000000..b751838 --- /dev/null +++ b/impls/normal/helveticascans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://helveticascans\.com/r/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/hotchocolatescans.js b/impls/normal/hotchocolatescans.js new file mode 100644 index 0000000..14c3eab --- /dev/null +++ b/impls/normal/hotchocolatescans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://hotchocolatescans\.com/fs/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/hqbr.js b/impls/normal/hqbr.js new file mode 100644 index 0000000..0c7b597 --- /dev/null +++ b/impls/normal/hqbr.js @@ -0,0 +1,25 @@ +// METADATA +// match: ^https?://hqbr.com.br/hqs/[^/]+/capitulo/[0-9]+/leitor/0 + +var impl_src = { + img: '#hq-page', + next: '#hq-page', + numpages: function() { + return W.pages.length; + }, + curpage: function() { + return W.paginaAtual + 1; + }, + nextchap: function(prev) { + var chapters = getEls('#chapter-dropdown a'), + current = parseInt(W.capituloIndex), + chapter = chapters[current + (prev ? -1 : 1)]; + return chapter && chapter.href; + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1], num); + } +} \ No newline at end of file diff --git a/impls/normal/ikanman.js b/impls/normal/ikanman.js new file mode 100644 index 0000000..75977e4 --- /dev/null +++ b/impls/normal/ikanman.js @@ -0,0 +1,37 @@ +// METADATA +// match: https?://(www|tw)\.(ikanman|manhuagui)\.com/comic/[0-9]+/[0-9]+\.html + +var impl_src = { + img: '#mangaFile', + next: function() { + return W._next; + }, + curpage: '#page', + numpages: '#pageSelect', + nextchap: function(prev) { + var chap = prev ? W._prevchap : W._nextchap; + if (chap > 0) { + return location.href.replace(/(\/comic\/[0-9]+\/)[0-9]+\.html.*/, "$1" + chap + ".html"); + } else { + return false; + } + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: function() { + if (getEl('#mangaFile')) { + W._nextchap = W.cInfo.nextId; + W._prevchap = W.cInfo.prevId; + var ex = extractInfo.bind(this); + W._next = location.href.replace(/(_p[0-9]+)?\.html.*/, '_p' + (ex('curpage') + 1) + '.html'); + W._base = ex('img').replace(/[^\/]+$/, ''); + return true; + } + }, + pages: function(url, num, cb, ex) { + var nexturl = url.replace(/(_p[0-9]+)?\.html.*/, '_p' + (num + 1) + '.html'); + var imgurl = W._base + W.cInfo.files[num - 1]; + cb(imgurl, nexturl); + } +} \ No newline at end of file diff --git a/impls/normal/imperialscans.js b/impls/normal/imperialscans.js new file mode 100644 index 0000000..3ec7825 --- /dev/null +++ b/impls/normal/imperialscans.js @@ -0,0 +1,29 @@ +// METADATA +// match: ^https?://imperialscans.com/read/.+ + +var impl_src = { + img: '#page-img', + next: '#page-url', + curpage: function() { + return extractInfo('#page-select', { type: 'index', val: -1 }); + }, + numpages: function() { + return extractInfo('#page-select') - 1; + }, + curchap: function() { + var options = getEls('#chapter-select option:not([disabled])'); + var chapter = 1; + options.some(function(value, index) { + if (location.pathname === value.value) { + chapter = options.length - index; + return true; + } + }); + return chapter; + }, + numchaps: function() { + return extractInfo('#chapter-select'); + }, + nextchap: '#page-control > li:nth-child(5) > a', + prevchap: '#page-control > li:nth-child(1) > a' +} \ No newline at end of file diff --git a/impls/normal/inpowerz.js b/impls/normal/inpowerz.js new file mode 100644 index 0000000..ca5b9d4 --- /dev/null +++ b/impls/normal/inpowerz.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://manga\.inpowerz\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/jaiminisbox.js b/impls/normal/jaiminisbox.js new file mode 100644 index 0000000..b2323df --- /dev/null +++ b/impls/normal/jaiminisbox.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://jaiminisbox\.com/reader/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/japscan.js b/impls/normal/japscan.js new file mode 100644 index 0000000..54141ac --- /dev/null +++ b/impls/normal/japscan.js @@ -0,0 +1,11 @@ +// METADATA +// match: ^https?://www\.japscan\.com/lecture-en-ligne/[^/]*/[0-9]* + +var impl_src = { + img: '#image', + next: '#img_link', + numpages: '#pages', + curpage: '#pages', + nextchap: '#next_chapter', + prevchap: '#back_chapter' +} \ No newline at end of file diff --git a/impls/normal/kawaii.js b/impls/normal/kawaii.js new file mode 100644 index 0000000..82e3df4 --- /dev/null +++ b/impls/normal/kawaii.js @@ -0,0 +1,16 @@ +// METADATA +// match: ^https://kawaii.ca/reader/.+ + +var impl_src = { + img: '.picture', + next: 'select[name=page] + a', + numpages: 'select[name=page]', + curpage: 'select[name=page]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', {type:'value', val: (prev ? -1 : 1)}); + if(next) return location.href.replace(/\/reader\/([^/]+)(\/.+)?$/, '/reader/$1/' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/kireicake,js b/impls/normal/kireicake,js new file mode 100644 index 0000000..3c1e926 --- /dev/null +++ b/impls/normal/kireicake,js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.kireicake\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/kirishimafansub.js b/impls/normal/kirishimafansub.js new file mode 100644 index 0000000..846636b --- /dev/null +++ b/impls/normal/kirishimafansub.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://lector\.kirishimafansub\.com/lector/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/kiss-manga.js b/impls/normal/kiss-manga.js new file mode 100644 index 0000000..66dfe3d --- /dev/null +++ b/impls/normal/kiss-manga.js @@ -0,0 +1,22 @@ +// METADATA +// match: ^https?://kissmanga\.com/Manga/[^/]+/.+ + +var impl_src = { + img: '#divImage img', + next: '#divImage img', + numpages: function() { + return (W.lstOLA || W.lstImages).length; + }, + curpage: function() { + if(getEls('#divImage img').length > 1) { + return 1; + } else { + return W.currImage + 1; + } + }, + nextchap: '#selectChapter, .selectChapter', + prevchap: '#selectChapter, .selectChapter', + pages: function(url, num, cb, ex) { + cb((W.lstOLA || W.lstImages)[num - 1], num); + } +} \ No newline at end of file diff --git a/impls/normal/kobato.hologfx.js b/impls/normal/kobato.hologfx.js new file mode 100644 index 0000000..91032a2 --- /dev/null +++ b/impls/normal/kobato.hologfx.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://kobato\.hologfx\.com/reader/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/komikstation.js b/impls/normal/komikstation.js new file mode 100644 index 0000000..00fa50f --- /dev/null +++ b/impls/normal/komikstation.js @@ -0,0 +1,19 @@ +// METADATA +// match: ^https?://www\.komikstation\.com/.+/.+/.+ + +var impl_src = { + img: '#mainpage', + next: function() { + return W._base + '?page=' + (W.glbCurrentpage + 1); + }, + numpages: '#index select', + curpage: '#index select', + pages: function(url, num, cb, ex) { + next = W._base + '?page=' + (num + 1); + cb(W.pages[num - 1], next); + }, + wait: function() { + W._base = location.href.replace(/[?#].+$/, ''); + return W.pages; + } +} \ No newline at end of file diff --git a/impls/normal/kukudm.js b/impls/normal/kukudm.js new file mode 100644 index 0000000..44d5a7a --- /dev/null +++ b/impls/normal/kukudm.js @@ -0,0 +1,22 @@ +// METADATA +// match: ^https?://(www|comic|comic2|comic3).kukudm.com/comiclist/[0-9]+/[0-9]+/[0-9]+.htm + +var impl_src = { + img: function(ctx) { + var script = getEl('td > script[language=javascript]', ctx); + if(script) { + return 'http://n.kukudm.com/' + script.textContent.match(/\+"([^']+)/)[1]; + } + }, + next: function(ctx) { + var links = getEls('td > a', ctx); + return links[links.length - 1].getAttribute('href'); + }, + numpages: function(cur) { + return parseInt(document.body.textContent.match(/共([0-9]+)页/)[1]); + }, + curpage: function() { + return parseInt(document.body.textContent.match(/第([0-9]+)页/)[1]); + }, + beforexhr: reuse.encodeChinese +} \ No newline at end of file diff --git a/impls/normal/lhtranslation.js b/impls/normal/lhtranslation.js new file mode 100644 index 0000000..588b993 --- /dev/null +++ b/impls/normal/lhtranslation.js @@ -0,0 +1,14 @@ +// METADATA +// match: ^https?://read.lhtranslation\.com/read-.+ + +var impl_src = { + img: 'img.chapter-img', + next: '.chapter-content > select + a.label', + numpages: '.chapter-content > select', + curpage: '.chapter-content > select', + numchaps: '.form-control', + curchap: '.form-control', + nextchap: '.form-control', + prevchap: '.form-control', + invchap: true +} \ No newline at end of file diff --git a/impls/normal/lonemanga.js b/impls/normal/lonemanga.js new file mode 100644 index 0000000..3e5ba43 --- /dev/null +++ b/impls/normal/lonemanga.js @@ -0,0 +1,16 @@ +// METADATA +// match: ^https?://lonemanga.com/manga/[^/]+/[^/]+ + +var impl_src = { + img: '#imageWrapper img', + next: '#imageWrapper a', + numpages: '.viewerPage', + curpage: '.viewerPage', + nextchap: function(prev) { + var next = extractInfo('.viewerChapter', {type:'value', val: (prev ? 1 : -1)}); + if(next) return location.href.replace(/\/manga\/([^/]+)\/.+$/, '/manga/$1/' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/madokami.js b/impls/normal/madokami.js new file mode 100644 index 0000000..007ad64 --- /dev/null +++ b/impls/normal/madokami.js @@ -0,0 +1,21 @@ +// METADATA +// match: ^https?://manga\.madokami\.al/reader/.+ + +var impl_src = { + img: 'img', + next: 'img', + curpage: function() { + return parseInt(query().index) + 1; + }, + numpages: function() { + if(!this._pages) { + this._pages = JSON.parse(getEl('#reader').dataset.files); + } + return this._pages.length; + }, + pages: function(url, num, cb, ex) { + url = url.replace(/file=.+$/, 'file=' + this._pages[num - 1]); + cb(url, url); + }, + wait: '#reader' +} \ No newline at end of file diff --git a/impls/normal/manga-ar.js b/impls/normal/manga-ar.js new file mode 100644 index 0000000..d079bb6 --- /dev/null +++ b/impls/normal/manga-ar.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://(www\.)?manga-ar\.net/manga/.+/.+/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/manga-cat.js b/impls/normal/manga-cat.js new file mode 100644 index 0000000..e4f8d96 --- /dev/null +++ b/impls/normal/manga-cat.js @@ -0,0 +1,13 @@ +// METADATA +// match: ^https?://www.mangacat.me/[^/]+/[^/]+/[^\.]+.html + +var impl_src = { + img: '.img', + next: '.img-link', + numpages: '#page', + curpage: '#page', + nextchap: '#chapter', + prevchap: '#chapter', + invchap: true, + wait: '#chapter option' +} \ No newline at end of file diff --git a/impls/normal/manga-cow.js b/impls/normal/manga-cow.js new file mode 100644 index 0000000..124bb91 --- /dev/null +++ b/impls/normal/manga-cow.js @@ -0,0 +1,17 @@ +// METADATA +// match: ^https?://(manga|mng)cow\.(co|id|info|com)/[^/]+/[0-9.]+ + +var impl_src = { + img: '.prw a > img', + next: '.prw a', + numpages: 'select.cbo_wpm_pag', + curpage: 'select.cbo_wpm_pag', + nextchap: function(prev) { + var next = extractInfo('select.cbo_wpm_chp', {type: 'value', val: (prev ? 1 : -1)}); + if(next) return window.location.href.replace(/\/[0-9.]+\/?([0-9]+\/?)?[^/]*$/, '/' + next); + }, + prevchap: function() { + return this.nextchap(true); + }, + URLregex: true +} \ No newline at end of file diff --git a/impls/normal/manga-doom,js b/impls/normal/manga-doom,js new file mode 100644 index 0000000..42747f7 --- /dev/null +++ b/impls/normal/manga-doom,js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://mangadoom\.(co|id|info|com)/[^/]+/[0-9.]+ +// mapto: manga-cow \ No newline at end of file diff --git a/impls/normal/manga-download.js b/impls/normal/manga-download.js new file mode 100644 index 0000000..91c3333 --- /dev/null +++ b/impls/normal/manga-download.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.manga-download\.org/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/manga-here mobile.js b/impls/normal/manga-here mobile.js new file mode 100644 index 0000000..47643fa --- /dev/null +++ b/impls/normal/manga-here mobile.js @@ -0,0 +1,9 @@ +// METADATA +// match: ^https?://m.mangahere.c[oc]/manga/[^/]+/[^/]+ + +var impl_src = { + img: '#image', + next: '#viewer a', + numpages: '.mangaread-page', + curpage: '.mangaread-page' +} \ No newline at end of file diff --git a/impls/normal/manga-here.js b/impls/normal/manga-here.js new file mode 100644 index 0000000..5155ac2 --- /dev/null +++ b/impls/normal/manga-here.js @@ -0,0 +1,21 @@ +// METADATA +// match: ^https?://www.mangahere.c[oc]/manga/[^/]+/[^/]+ + +var impl_src = { + img: '#viewer img:last-child', + next: '#viewer a', + numpages: 'select.wid60', + curpage: 'select.wid60', + numchaps: '#top_chapter_list', + curchap: '#top_chapter_list', + nextchap: function(prev) { + var chapter = W.chapter_list[W.current_chapter_index + (prev ? -1 : 1)]; + return chapter && chapter[1]; + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: function() { + return areDefined(W.current_chapter_index, W.chapter_list, getEl('#top_chapter_list')); + } +} \ No newline at end of file diff --git a/impls/normal/manga-indo.js b/impls/normal/manga-indo.js new file mode 100644 index 0000000..4b2ef3a --- /dev/null +++ b/impls/normal/manga-indo.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://mangaindo\.(co|id|info|com)/[^/]+/[0-9.]+ +// mapto: manga-cow \ No newline at end of file diff --git a/impls/normal/manga-joy.js b/impls/normal/manga-joy.js new file mode 100644 index 0000000..f9c9b22 --- /dev/null +++ b/impls/normal/manga-joy.js @@ -0,0 +1,16 @@ +// METADATA +// match: ^https?://manga-joy.com/[^/]*/[0-9]* + +var impl_src = { + img: '.prw img', + next: '.nxt', + numpages: '.wpm_nav_rdr li:nth-child(3) > select', + curpage: '.wpm_nav_rdr li:nth-child(3) > select', + nextchap: function(prev) { + var next = extractInfo('.wpm_nav_rdr li:nth-child(2) > select', {type: 'value', val: prev ? 1 : -1}); + if(next) return window.location.href.replace(/\/[0-9.]+\/?([0-9]+(\/.*)?)?$/, '/' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/manga-kaka.js b/impls/normal/manga-kaka.js new file mode 100644 index 0000000..0788f60 --- /dev/null +++ b/impls/normal/manga-kaka.js @@ -0,0 +1,16 @@ +// METADATA +// match: ^https?://www\.(mangahen|mangamap)\.com/[^/]+/[0-9]+ + +var impl_src = { + img: 'img.manga-page', + next: '.nav_pag > li:nth-child(1) > a', + numpages: 'select.cbo_wpm_pag', + curpage: 'select.cbo_wpm_pag', + nextchap: function(prev) { + var chapter = extractInfo('select.cbo_wpm_chp', { type: 'value', val: (prev ? 1 : -1) }); + if(chapter) return window.location.href.replace(/\/[0-9\.]+\/?([0-9]+\/?)?$/, '/' + chapter); + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/manga-panda.js b/impls/normal/manga-panda.js new file mode 100644 index 0000000..2a7e716 --- /dev/null +++ b/impls/normal/manga-panda.js @@ -0,0 +1,11 @@ +// METADATA +// match: ^https?://www.mangapanda.com/.*/[0-9]* + +var impl_src = { + img: '#img', + next: '.next a', + numpages: '#pageMenu', + curpage: '#pageMenu', + nextchap: '#mangainfofooter > #mangainfo_bas table tr:first-child a', + prevchap: '#mangainfofooter > #mangainfo_bas table tr:last-child a' +} \ No newline at end of file diff --git a/impls/normal/manga-park.js b/impls/normal/manga-park.js new file mode 100644 index 0000000..a6495ad --- /dev/null +++ b/impls/normal/manga-park.js @@ -0,0 +1,27 @@ +// METADATA +// match: ^https?://mangapark\.me/manga/[^/]+/[^/]+/[^/]+ + +var impl_src = { + img: '.img-link > img', + next: '.page > span:last-child > a', + numpages: function() { + if(W.sel_load && W.sel_load.options[W.sel_load.selectedIndex].value) { + return extractInfo('#sel_page_1'); + } else { + var links = getEls('.img-link > img').map(function(img) { return img.src; }); + this.pages = function(url, num, cb, ex) { + cb(links[num - 1], num); + }; + return links.length; + } + }, + curpage: '#sel_page_1', + nextchap: function(prev) { + var next = extractInfo('#sel_book_1', {type: 'value', val: (prev ? -1 : 1)}); + if(next) return window.location.href.replace(/(\/manga\/[^\/]+).+$/, '$1' + next + '/1'); + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: '#sel_book_1 option' +} \ No newline at end of file diff --git a/impls/normal/manga-reader.js b/impls/normal/manga-reader.js new file mode 100644 index 0000000..4d0187b --- /dev/null +++ b/impls/normal/manga-reader.js @@ -0,0 +1,12 @@ +// METADATA +// match: ^https?://www.mangareader.net/.*/.* + +var impl_src = { + img: '#img', + next: '.next a', + numpages: '#pageMenu', + curpage: '#pageMenu', + nextchap: '#chapterMenu', + prevchap: '#chapterMenu', + wait: '#chapterMenu option' +} \ No newline at end of file diff --git a/impls/normal/manga-stream.js b/impls/normal/manga-stream.js new file mode 100644 index 0000000..6cefec9 --- /dev/null +++ b/impls/normal/manga-stream.js @@ -0,0 +1,25 @@ +// METADATA +// match: ^https?://(readms|mangastream).(net|com)/(r|read)/[^/]*/[^/]* + +var impl_src = { + img: '#manga-page', + next: '.next a', + numpages: function() { + var lastPage = getEl('.subnav-wrapper .controls .btn-group:last-child ul li:last-child'); + return parseInt(lastPage.textContent.match(/[0-9]/g).join(''), 10); + }, + nextchap: function(prev) { + var found; + var chapters = [].slice.call(document.querySelectorAll('.controls > div:first-child > .dropdown-menu > li a')); + chapters.pop(); + for (var i = 0; i < chapters.length; i++) { + if (window.location.href.indexOf(chapters[i].href) !== -1) { + found = chapters[i + (prev ? 1 : -1)]; + if (found) return found.href; + } + } + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/manga-town.js b/impls/normal/manga-town.js new file mode 100644 index 0000000..190c3ac --- /dev/null +++ b/impls/normal/manga-town.js @@ -0,0 +1,12 @@ +// METADATA +// match: ^https?://www.mangatown.com/manga/[^/]+/[^/]+ + +var impl_src = { + img: '#image', + next: '#viewer a', + numpages: '.page_select select', + curpage: '.page_select select', + nextchap: '#top_chapter_list', + prevchap: '#top_chapter_list', + wait: 1000 +} \ No newline at end of file diff --git a/impls/normal/manga-wall.js b/impls/normal/manga-wall.js new file mode 100644 index 0000000..755adcd --- /dev/null +++ b/impls/normal/manga-wall.js @@ -0,0 +1,19 @@ +// METADATA +// match: ^https?://mangawall\.com/manga/[^/]*/[0-9]* + +var impl_src = { + _page: null, + img: 'img.scan', + next: function() { + if(this._page === null) this._page = W.page; + return W.series_url + '/' + W.chapter + '/' + (this._page += 1); + }, + numpages: '.pageselect', + curpage: '.pageselect', + nextchap: function(prev) { + return W.series_url + '/' + (parseInt(W.chapter.slice(1)) + (prev ? -1 : 1)) + '/1'; + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/manga.ae.js b/impls/normal/manga.ae.js new file mode 100644 index 0000000..0d17831 --- /dev/null +++ b/impls/normal/manga.ae.js @@ -0,0 +1,10 @@ +// METADATA +// match: https?://www.manga.ae/[^/]+/[^/]+/ + +var impl_src = { + img: '#showchaptercontainer img', + next: '#showchaptercontainer a', + curpage: 'a.chpage', + nextchap: '.chapter:last-child', + prevchap: '.chapter:first-child' +} \ No newline at end of file diff --git a/impls/normal/mangachapter.js b/impls/normal/mangachapter.js new file mode 100644 index 0000000..641c288 --- /dev/null +++ b/impls/normal/mangachapter.js @@ -0,0 +1,13 @@ +// METADATA +// match: ^https?://www\.mangachapter\.me/[^/]+/[^/]+/[^/]+.html + +var impl_src = { + img: '#mangaImg, #viewer > table > tbody > tr > td:nth-child(1) > a:nth-child(2) > img', + next: '.page-select + a.button-page', + numpages: '.page-select select', + curpage: '.page-select select', + invchap: true, + nextchap: '#top_chapter_list', + prevchap: '#top_chapter_list', + wait: '#top_chapter_list' +} \ No newline at end of file diff --git a/impls/normal/mangadex.org.js b/impls/normal/mangadex.org.js new file mode 100644 index 0000000..f3b2bd9 --- /dev/null +++ b/impls/normal/mangadex.org.js @@ -0,0 +1,26 @@ +// METADATA +// match: ^https?://mangadex\.org/chapter/[0-9]+/[0-9]+ + +var impl_src = { + img: '#current_page', + next: function() { + return this._base + ++this._page; + }, + numpages: '#jump_page', + curpage: '#jump_page', + nextchap: function() { + var chapter = document.querySelector('#jump_chapter').selectedOptions[0].previousElementSibling; + return (chapter === null) ? false : (this._base.replace(/[0-9]+\/$/, chapter.value)); + }, + prevchap: function() { + var chapter = document.querySelector('#jump_chapter').selectedOptions[0].nextElementSibling; + return (chapter === null) ? false : (this._base.replace(/[0-9]+\/$/, chapter.value)); + }, + wait: function() { + var loc = document.location.toString(); + var num = loc.match(/[0-9]+$/); + this._base = loc.slice(0, -num.length); + this._page = parseInt(num); + return true; + } +} \ No newline at end of file diff --git a/impls/normal/mangaeden.js b/impls/normal/mangaeden.js new file mode 100644 index 0000000..21eb5fb --- /dev/null +++ b/impls/normal/mangaeden.js @@ -0,0 +1,21 @@ +// METADATA +// match: ^https?://(www\.)?mangaeden\.com/(en|it)/(en|it)-manga/.+ + +var impl_src = { + img: '#mainImg', + next: '#nextA', + numpages: '#pageSelect', + curpage: '#pageSelect', + numchaps: '#combobox', + curchap: '#combobox', + invchap: true, + nextchap: function (prev) { + var cbox = getEl('#combobox'); + var opt = cbox[prev ? cbox.selectedIndex + 1 : cbox.selectedIndex - 1]; + var span = getEl('span.hideM0 a'); + return opt && span && span.href + parseInt(opt.value) + '/1/'; + }, + prevchap: function () { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/mangaforall.js b/impls/normal/mangaforall.js new file mode 100644 index 0000000..2b9bdfe --- /dev/null +++ b/impls/normal/mangaforall.js @@ -0,0 +1,14 @@ +// METADATA +// match: https?://mangaforall.com/manga/[^/]+/[^/]+/ + +var impl_src = { + img: '#page > img', + next: '#page > img', + numpages: '#chapter > div:nth-child(1) > div > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-left.uk-text-center-small > div > div > div > ul', + curpage: '#chapter > div:nth-child(1) > div > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-left.uk-text-center-small > div > a.uk-button.uk-button-primary.number.uk-button-danger', + nextchap: '#chapter > div:nth-child(5) > div.uk-grid.uk-grid-collapse.uk-margin-top > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-left.uk-text-center-small > a', + prevchap: '#chapter > div:nth-child(5) > div.uk-grid.uk-grid-collapse.uk-margin-top > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-right.uk-text-center-small > a', + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1].url, num); + } +} \ No newline at end of file diff --git a/impls/normal/mangafox.js b/impls/normal/mangafox.js new file mode 100644 index 0000000..61289a7 --- /dev/null +++ b/impls/normal/mangafox.js @@ -0,0 +1,33 @@ +// METADATA +// match: ^https?://(fan|manga)fox.(me|la|net)/manga/[^/]*/[^/]*/[^/]* + +var impl_src = { + img: '.reader-main img', + next: '.pager-list-left > span > a:last-child', + numpages: function() { return W.imagecount; }, + curpage: function () { return W.imagepage; }, + nextchap: '.pager-list-left > a:last-child', + prevchap: '.pager-list-left > a:first-child', + imgURLs: [], + pages: function(url, num, cb, ex) { + var imp = this; + if (this.imgURLs[num]) + cb(this.imgURLs[num], num); + else + ajax({ + url: 'chapterfun.ashx?cid=' + W.chapterid + '&page=' + num, + onload: function(e) { + eval(e.target.responseText); + for (var i = 0; i < d.length; i++) { + imp.imgURLs[num + i] = d[i]; + } + cb(d[0], num); + } + }); + }, + wait: function () { + el = getEl('.reader-main img'); + + return el && el.getAttribute('src') != el.getAttribute('data-loading-img'); + } +} \ No newline at end of file diff --git a/impls/normal/mangago.js b/impls/normal/mangago.js new file mode 100644 index 0000000..e0b6e55 --- /dev/null +++ b/impls/normal/mangago.js @@ -0,0 +1,27 @@ +// METADATA +// match: ^https?://(www.)?mangago.me/read-manga/[^/]+/[^/]+/[^/]+ + +var impl_src = { + img: '#page1', + next: '#pic_container', + numpages: '#dropdown-menu-page', + curpage: function() { + return parseInt(getEls('#page-mainer a.btn.dropdown-toggle')[1].textContent.match(/[0-9]+/)[0]); + }, + nextchap: function(prev) { + var chapters = getEls('ul.dropdown-menu.chapter a'), + curName = getEls('#page-mainer a.btn.dropdown-toggle')[0].textContent, + curIdx; + chapters.some(function(chap, idx) { + if(chap.textContent.indexOf(curName) === 0) { + curIdx = idx; + return true; + } + }); + var chapter = chapters[curIdx + (prev ? 1 : -1)]; + return chapter && chapter.href; + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/mangahome.js b/impls/normal/mangahome.js new file mode 100644 index 0000000..7408c9d --- /dev/null +++ b/impls/normal/mangahome.js @@ -0,0 +1,21 @@ +// METADATA +// match: https?://www\.mangahome\.com/manga/.+/.+ + +var impl_src = { + img: '#image', + next: '#viewer > a', + curpage: '.mangaread-page select', + numpages: '.mangaread-page select', + nextchap: function(prev) { + var buttons = getEls('.mangaread-footer .left > .btn-three'); + for (var i = 0; i < buttons.length; i++) { + if (buttons[i].textContent.indexOf(prev ? 'Prev Chapter' : 'Next Chapter') > - 1) { + return buttons[i].href; + } + } + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: '#image' +} \ No newline at end of file diff --git a/impls/normal/mangaichiscans.js b/impls/normal/mangaichiscans.js new file mode 100644 index 0000000..8a80ef7 --- /dev/null +++ b/impls/normal/mangaichiscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://mangaichiscans\.mokkori\.fr/fs/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/mangainn.js b/impls/normal/mangainn.js new file mode 100644 index 0000000..00a3190 --- /dev/null +++ b/impls/normal/mangainn.js @@ -0,0 +1,21 @@ +// METADATA +// match: ^https?://www.mangainn.net/manga/chapter/.+ + +var impl_src = { + img: '#imgPage', + next: function() { + if(!this._count) this._count = extractInfo(this.curpage, {type: 'value'}); + var url = location.href; + if(!/page_[0-9]+/.test(url)) url += '/page_1'; + return url.replace(/page_[0-9]+/, 'page_' + (++this._count)); + }, + numpages: '#cmbpages', + curpage: '#cmbpages', + nextchap: function(prev) { + var next = extractInfo('#chapters', {type:'value', val: (prev ? -1 : 1)}); + if(next) return location.href.replace(/\/chapter\/.+$/, '/chapter/' + next + '/page_1'); + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/mangalator.js b/impls/normal/mangalator.js new file mode 100644 index 0000000..7052fa4 --- /dev/null +++ b/impls/normal/mangalator.js @@ -0,0 +1,16 @@ +// METADATA +// match: ^https?://mangalator.ch/show.php\?gallery=[0-9]+ + +var impl_src = { + img: '.image img', + next: '#next', + numpages: 'select[name=image]', + curpage: 'select[name=image]', + nextchap: function(prev) { + var next = extractInfo('select[name=gallery]', {type: 'value', val: (prev ? 1 : -1)}); + if(next) return location.href.replace(/\?gallery=[0-9]+/, '?gallery=' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/mangasail.js b/impls/normal/mangasail.js new file mode 100644 index 0000000..a982975 --- /dev/null +++ b/impls/normal/mangasail.js @@ -0,0 +1,17 @@ +// METADATA +// match: https?://www\.mangasail\.com/[^/]+ + +var impl_src = { + img: '#images img', + next: '#images a', + curpage: '#edit-select-page', + numpages: '#edit-select-page', + nextchap: function(prev) { + return location.origin + '/node/' + extractInfo('#edit-select-node', {type: 'value', val: prev ? -1 : 1}); + }, + prevchap: function() { + return this.nextchap(true); + }, + curchap: '#select_node', + numchaps: '#select_node' +} \ No newline at end of file diff --git a/impls/normal/mangatail.js b/impls/normal/mangatail.js new file mode 100644 index 0000000..143638e --- /dev/null +++ b/impls/normal/mangatail.js @@ -0,0 +1,3 @@ +// METADATA +// match: https?://www\.mangatail\.com/[^/]+ +// mapto: mangasail \ No newline at end of file diff --git a/impls/normal/mangatopia.js b/impls/normal/mangatopia.js new file mode 100644 index 0000000..a91426b --- /dev/null +++ b/impls/normal/mangatopia.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://mangatopia\.net/slide/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/mangatraders.js b/impls/normal/mangatraders.js new file mode 100644 index 0000000..a946b23 --- /dev/null +++ b/impls/normal/mangatraders.js @@ -0,0 +1,19 @@ +// METADATA +// match: ^https?://mangatraders\.biz/read-online/.+ + +var impl_src = { + img: 'img.CurImage', + next: '.image-container a', + numpages: '.PageSelect', + curpage: '.PageSelect', + nextchap: function(prev) { + var next = extractInfo('.ChapterSelect', {type:'text', val: (prev ? -1 : 1)}); + if(next) { + var chapter = next.match(/[0-9.]+/)[0]; + return location.href.replace(/chapter-[0-9.]+/, 'chapter-' + chapter).replace(/page-[0-9]+/, 'page-1'); + } + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/manhua-dmzj.js b/impls/normal/manhua-dmzj.js new file mode 100644 index 0000000..2024ddf --- /dev/null +++ b/impls/normal/manhua-dmzj.js @@ -0,0 +1,20 @@ +// METADATA +// match: ^https?://manhua.dmzj.com/[^/]*/[0-9]+(-[0-9]+)?\.shtml + +var impl_src = { + img: '#center_box > img', + next: '#center_box > img', + numpages: function() { + return W.arr_pages.length; + }, + curpage: function() { + var match = location.href.match(/page=([0-9]+)/); + return match ? parseInt(match[1]) : 1; + }, + nextchap: '#next_chapter', + prevchap: '#prev_chapter', + pages: function(url, num, cb, ex) { + cb(W.img_prefix + W.arr_pages[num - 1], num); + }, + wait: '#center_box > img' +} \ No newline at end of file diff --git a/impls/normal/moonbunnycafe.js b/impls/normal/moonbunnycafe.js new file mode 100644 index 0000000..7639642 --- /dev/null +++ b/impls/normal/moonbunnycafe.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://moonbunnycafe\.com/[^/]+/[0-9.]+ +// mapto: manga-cow \ No newline at end of file diff --git a/impls/normal/mymh8.js b/impls/normal/mymh8.js new file mode 100644 index 0000000..3c95991 --- /dev/null +++ b/impls/normal/mymh8.js @@ -0,0 +1,24 @@ +// METADATA +// match: ^https?://(www\.)?mymh8\.com/chapter/.+ + +var impl_src = { + img: '#viewimg', + next: reuse.na, + numpages: function() { + return W.maxpages; + }, + curpage: '#J_showpage > span', + nextchap: function(prev) { + var button = prev ? getEl('div.m3p > input:first-of-type') : getEl('div.m3p > input:last-of-type'); + return button && button.attributes.onclick.value.match(/\.href='([^']+)'/)[1]; + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + cb(W.WebimgServerURL[0] + W.imageslist[num], num); + }, + wait: function() { + return W.imageslist.length > 0; + } +} \ No newline at end of file diff --git a/impls/normal/necron99scans.js b/impls/normal/necron99scans.js new file mode 100644 index 0000000..47d337e --- /dev/null +++ b/impls/normal/necron99scans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://necron99scans\.com/reader/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/otakusmash.js b/impls/normal/otakusmash.js new file mode 100644 index 0000000..0adc0ab --- /dev/null +++ b/impls/normal/otakusmash.js @@ -0,0 +1,19 @@ +// METADATA +// match: https?://www\.otakusmash\.com/(read-comics|read-manga)/.+ + +var impl_src = { + img: 'img.picture', + next: 'select[name=page] + a', + curpage: 'select[name=page]', + numpages: 'select[name=page]', + nextchap: function(prev) { + var nextChap = extractInfo('select[name=chapter]', {type: 'value', val: prev ? 1 : -1}); + return nextChap ? location.href.replace(/(read-(comics|manga)\/[^\/]+).*/, '$1/' + nextChap) : null; + }, + prevchap: function() { + return this.nextchap(true); + }, + numchaps: 'select[name=chapter]', + curchap: 'select[name=chapter]', + invchap: true +} \ No newline at end of file diff --git a/impls/normal/otscans.js b/impls/normal/otscans.js new file mode 100644 index 0000000..089c385 --- /dev/null +++ b/impls/normal/otscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://otscans\.com/foolslide/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/pecintakomik.js b/impls/normal/pecintakomik.js new file mode 100644 index 0000000..b83da36 --- /dev/null +++ b/impls/normal/pecintakomik.js @@ -0,0 +1,16 @@ +// METADATA +// match: ^https?://www\.pecintakomik\.com/manga/[^/]*/[^/]* + +var impl_src = { + img: '.picture', + next: '.pager a:nth-child(3)', + numpages: 'select[name=page]', + curpage: 'select[name=page]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', {type: 'value', val: (prev ? 1 : -1)}); + if(next) return window.location.href.replace(/\/([^\/]+)\/[0-9]+\/?$/, '/$1/' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/psscans,js b/impls/normal/psscans,js new file mode 100644 index 0000000..ec8e516 --- /dev/null +++ b/impls/normal/psscans,js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.psscans\.info/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/read-comic-online.js b/impls/normal/read-comic-online.js new file mode 100644 index 0000000..064498c --- /dev/null +++ b/impls/normal/read-comic-online.js @@ -0,0 +1,18 @@ +// METADATA +// match: ^https?://readcomiconline\.to/Comic/[^/]+/.+ + +var impl_src = { + img: '#divImage img', + next: '#divImage img', + numpages: function() { + return W.lstImages.length; + }, + curpage: function() { + return getEls('#divImage img').length > 1 ? 1 : W.currImage + 1; + }, + nextchap: '#selectEpisode, .selectEpisode', + prevchap: '#selectEpisode, .selectEpisode', + pages: function(url, num, cb, ex) { + cb(W.lstImages[num - 1], num); + } +} \ No newline at end of file diff --git a/impls/normal/readcomics.js b/impls/normal/readcomics.js new file mode 100644 index 0000000..e13ccd9 --- /dev/null +++ b/impls/normal/readcomics.js @@ -0,0 +1,14 @@ +// METADATA +// match: https?://(www\.)?readcomics\.tv/.+/chapter-[0-9]+(/[0-9]+|$) + +var impl_src = { + img: '#main_img', + next: '.nav.next', + curpage: 'select[name=page_select]', + numpages: 'select[name=page_select]', + nextchap: 'select[name=chapter_select]', + prevchap: 'select[name=chapter_select]', + curchap: 'select[name=chapter_select]', + numchaps: 'select[name=chapter_select]', + wait: 'select[name=page_select]' +} \ No newline at end of file diff --git a/impls/normal/readmng.com.js b/impls/normal/readmng.com.js new file mode 100644 index 0000000..06bf2c7 --- /dev/null +++ b/impls/normal/readmng.com.js @@ -0,0 +1,12 @@ +// METADATA +// match: ^https?://www\.readmng\.com/[^/]+/.+ + +var impl_src = { + img: '.page_chapter-2 img', + next: '.list-switcher-2 > li:nth-child(3) > a, .list-switcher-2 > li:nth-child(2) > a', + numpages: '.list-switcher-2 select[name=category_type]', + curpage: '.list-switcher-2 select[name=category_type]', + nextchap: '.jump-menu[name=chapter_list]', + prevchap: '.jump-menu[name=chapter_list]', + invchap: true +} \ No newline at end of file diff --git a/impls/normal/redhawkscans.js b/impls/normal/redhawkscans.js new file mode 100644 index 0000000..3b2972f --- /dev/null +++ b/impls/normal/redhawkscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://manga\.redhawkscans\.com/reader/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/roseliascans.js b/impls/normal/roseliascans.js new file mode 100644 index 0000000..ff66908 --- /dev/null +++ b/impls/normal/roseliascans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.roseliascans\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/s2smanga,js b/impls/normal/s2smanga,js new file mode 100644 index 0000000..5d0eb54 --- /dev/null +++ b/impls/normal/s2smanga,js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.s2smanga\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/senmanga.js b/impls/normal/senmanga.js new file mode 100644 index 0000000..6e86efd --- /dev/null +++ b/impls/normal/senmanga.js @@ -0,0 +1,21 @@ +// METADATA +// match: ^https?://[^\.]+\.senmanga\.com/[^/]*/.+ + +var impl_src = { + img: '#picture', + next: '#reader > a', + numpages: 'select[name=page]', + curpage: 'select[name=page]', + numchaps: 'select[name=chapter]', + curchap: 'select[name=chapter]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', {type: 'value', val: (prev ? 1 : -1)}); + if(next) { + var manga = window.location.pathname.slice(1).split('/')[0]; + return window.location.origin + '/' + manga + '/' + next + '/1'; + } + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/sensescans.js b/impls/normal/sensescans.js new file mode 100644 index 0000000..4f1ffeb --- /dev/null +++ b/impls/normal/sensescans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://sensescans\.com/reader/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/sh-arab.js b/impls/normal/sh-arab.js new file mode 100644 index 0000000..27b614d --- /dev/null +++ b/impls/normal/sh-arab.js @@ -0,0 +1,18 @@ +// METADATA +// match: ^https?://www.sh-arab.com/manga/.+ + +var impl_src = { + img: 'img.picture', + next: '#omv td > a', + curpage: 'select[name=page]', + numpages: 'select[name=page]', + curchap: 'select[name=chapter]', + numchaps: 'select[name=chapter]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', {type:'value', val: (prev ? -1 : 1)}); + if (next) return location.href.replace(/[^\/]+$/, next); + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/normal/shoujosense.js b/impls/normal/shoujosense.js new file mode 100644 index 0000000..7c6e894 --- /dev/null +++ b/impls/normal/shoujosense.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.shoujosense\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/spinybackmanga and titaniascans.js b/impls/normal/spinybackmanga and titaniascans.js new file mode 100644 index 0000000..75a8853 --- /dev/null +++ b/impls/normal/spinybackmanga and titaniascans.js @@ -0,0 +1,38 @@ +// METADATA +// match: ^https?://(spinybackmanga.com/\?manga=[^&]+&chapter=.+|www\.titaniascans\.com/reader/.+/.+) + +var impl_src = { + img: '#thePicLink img', + next: '#thePicLink', + curpage: function() { + return W.current; + }, + numpages: function() { + return getEl('#loadingbar tr').children.length; + }, + curchap: function() { + return parseInt(getEls('.selector')[1].firstChild.textContent.match(/[0-9]+/)[0]); + }, + numchaps: function() { + return getEls('.selector .options')[1].children.length; + }, + nextchap: function(prev) { + var nextChap = document.scripts[2].textContent.match(/location.href = "([^"]+)"/)[1]; + if(prev) { + [].some.call(getEls('.selector .options')[1].children, function(child, index, children) { + if(child.href === nextChap) { + nextChap = children[index - 2] && children[index - 2].href; + return true; + } + }); + } + return nextChap; + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + var next = url.replace(/(?:(\/)2\/|[0-9]*)$/, '$1' + (num + 1)); + cb(W.imageArray[num - 1], next); + } +} \ No newline at end of file diff --git a/impls/normal/substitutescans.js b/impls/normal/substitutescans.js new file mode 100644 index 0000000..f3e185f --- /dev/null +++ b/impls/normal/substitutescans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://substitutescans\.com/reader/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/the-spectrum-scans.js b/impls/normal/the-spectrum-scans.js new file mode 100644 index 0000000..a404968 --- /dev/null +++ b/impls/normal/the-spectrum-scans.js @@ -0,0 +1,35 @@ +// METADATA +// match: ^https?://view\.thespectrum\.net/series/[^\.]+\.html + +var impl_src = { + img: '#mainimage', + next: function() { + if (++this._page < this._pages.length) { + return this._pages[this._page]; + } + }, + numpages: '.selectpage', + curpage: '.selectpage', + nextchap: function(prev) { + var ps = document.pageSelector1; + var chnum = ps.ch.selectedIndex + (prev ? -1 : 1); + if (chnum < ps.ch.length && chnum > -1) { + return ps.action.split('?')[0] + '?ch=' + ps.ch[chnum].value + '&page=1'; + } else { + return false; + } + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: function() { + var ps = document.pageSelector1; + this._pages = []; + var base = ps.action.split('?')[0]; + for (var i = 0; i < ps.page.length; i++) { + this._pages.push(base + '?ch=' + ps.ch.value + '&page=' + ps.page[i].value); + } + this._page = ps.page[ps.page.selectedIndex].value - 1; + return true; + } +} \ No newline at end of file diff --git a/impls/normal/thecatscans.js b/impls/normal/thecatscans.js new file mode 100644 index 0000000..04d0a3f --- /dev/null +++ b/impls/normal/thecatscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.thecatscans\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/twistedhelscans.js b/impls/normal/twistedhelscans.js new file mode 100644 index 0000000..367717a --- /dev/null +++ b/impls/normal/twistedhelscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://www\.twistedhelscans\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/unionmangas.js b/impls/normal/unionmangas.js new file mode 100644 index 0000000..77d0f48 --- /dev/null +++ b/impls/normal/unionmangas.js @@ -0,0 +1,22 @@ +// METADATA +// match: https?://(www\.)?unionmangas\.net/leitor/.+ + +var impl_src = { + img: '.slick-active img.real', + next: reuse.na, + numpages: '.selectPage', + curpage: '.selectPage', + numchaps: '#cap_manga1', + curchap: '#cap_manga1', + nextchap: '#cap_manga1', + prevchap: '#cap_manga1', + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1], num); + }, + wait: function() { + W.pages = getEls('img.real').map(function(el) { + return el.src || el.dataset.lazy; + }); + return W.pages && W.pages.length > 0; + } +} \ No newline at end of file diff --git a/impls/normal/vortex-scans.js b/impls/normal/vortex-scans.js new file mode 100644 index 0000000..55d1513 --- /dev/null +++ b/impls/normal/vortex-scans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.vortex-scans\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/whiteoutscans.js b/impls/normal/whiteoutscans.js new file mode 100644 index 0000000..7bf3643 --- /dev/null +++ b/impls/normal/whiteoutscans.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://reader\.whiteoutscans\.com/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/world-three b/impls/normal/world-three new file mode 100644 index 0000000..4d9fe26 --- /dev/null +++ b/impls/normal/world-three @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://www\.slide\.world-three\.org/read/.+ +// mapto: foolslide \ No newline at end of file diff --git a/impls/normal/yonkouprod.js b/impls/normal/yonkouprod.js new file mode 100644 index 0000000..fe52bc7 --- /dev/null +++ b/impls/normal/yonkouprod.js @@ -0,0 +1,3 @@ +// METADATA +// match: ^https?://yonkouprod\.com/reader/read/.+ +// mapto: foolslide \ No newline at end of file diff --git "a/impls/normal/\346\274\253\347\225\253\347\216\213.js" "b/impls/normal/\346\274\253\347\225\253\347\216\213.js" new file mode 100644 index 0000000..8acc480 --- /dev/null +++ "b/impls/normal/\346\274\253\347\225\253\347\216\213.js" @@ -0,0 +1,20 @@ +// METADATA +// match: https://www\.mangabox\.me/reader/\d+/episodes/\d+/ + +var impl_src = { + img: 'img.jsNext', + next: function() { + return '#'; + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1].src, num - 1); + }, + numpages: function() { + return W.pages.length; + }, + nextchap: '.lastSlider_nextButton', + wait: function (){ + W.pages = getEls('img.jsNext'); + return true; + } +} \ No newline at end of file diff --git a/impls/nsfw/8muses.js b/impls/nsfw/8muses.js new file mode 100644 index 0000000..80c9884 --- /dev/null +++ b/impls/nsfw/8muses.js @@ -0,0 +1,12 @@ +// METADATA +// match: ^http(s)?://www.8muses.com/comix/picture/[^/]+/[^/]+/[^/]+/.+ + +var impl_src = { + img: function(ctx) { + var img = getEl('.photo img.image', ctx); + return img ? img.src : getEl('#imageDir', ctx).value + getEl('#imageName', ctx).value; + }, + next: '.photo > a', + curpage: '#page-select-s', + numpages: '#page-select-s' +} \ No newline at end of file diff --git a/impls/nsfw/doujin-moe.js b/impls/nsfw/doujin-moe.js new file mode 100644 index 0000000..51d81dd --- /dev/null +++ b/impls/nsfw/doujin-moe.js @@ -0,0 +1,22 @@ +// METADATA +// match: ^https?://doujins\.com/.+ + +var impl_src = { + _pages: null, + img: 'img.picture', + next: reuse.na, + numpages: function() { + if (!this._pages) { + this._pages = getEls('#gallery djm').map(function(file) { + return file.getAttribute('file').replace('static2.', 'static.'); + }); + } + return this._pages.length; + }, + curpage: function() { + return parseInt(getEl('.counter').textContent.match(/^[0-9]+/)[0]); + }, + pages: function(url, num, cb, ex) { + cb(this._pages[num - 1], num); + } +} \ No newline at end of file diff --git a/impls/nsfw/ero-senmanga.js b/impls/nsfw/ero-senmanga.js new file mode 100644 index 0000000..2127d1a --- /dev/null +++ b/impls/nsfw/ero-senmanga.js @@ -0,0 +1,19 @@ +// METADATA +// match: ^https?://ero\.senmanga\.com/[^/]*/[^/]*/[0-9]* + +var impl_src = { + img: '#picture', + next: '#omv > table > tbody > tr:nth-child(2) > td > a', + numpages: 'select[name=page]', + curpage: 'select[name=page]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', { + type: 'value', + val: (prev ? -1 : 1) + }); + if (next) return window.location.href.replace(/\/[^\/]*\/[0-9]+\/?$/, '') + '/' + next + '/1'; + }, + prevchap: function() { + return this.nextchap(true); + } +} \ No newline at end of file diff --git a/impls/nsfw/fakku.js b/impls/nsfw/fakku.js new file mode 100644 index 0000000..454111f --- /dev/null +++ b/impls/nsfw/fakku.js @@ -0,0 +1,20 @@ +// METADATA +// match: ^http(s)?://www.fakku.net/.*/.*/read + +var impl_src = { + img: '.current-page', + next: '.current-page', + numpages: '.drop', + curpage: '.drop', + pages: function(url, num, cb, ex) { + var firstNum = url.lastIndexOf('/'), + lastDot = url.lastIndexOf('.'); + var c = url.charAt(firstNum); + while (c && !/[0-9]/.test(c)) { + c = url.charAt(++firstNum); + } + var curPage = parseInt(url.slice(firstNum, lastDot), 10); + url = url.slice(0, firstNum) + ('00' + (curPage + 1)).slice(-3) + url.slice(lastDot); + cb(url, url); + } +} \ No newline at end of file diff --git a/impls/nsfw/geh-and-exh.js b/impls/nsfw/geh-and-exh.js new file mode 100644 index 0000000..b4b79fc --- /dev/null +++ b/impls/nsfw/geh-and-exh.js @@ -0,0 +1,9 @@ +// METADATA +// match: ^https?://(e-hentai|exhentai).org/s/.*/.* + +var impl_src = { + img: '.sni > a > img, #img', + next: '.sni > a, #i3 a', + numpages: 'div.sn > div > span:nth-child(2)', + curpage: 'div.sn > div > span:nth-child(1)' +} \ No newline at end of file diff --git a/impls/nsfw/hentai-here.js b/impls/nsfw/hentai-here.js new file mode 100644 index 0000000..5bc9091 --- /dev/null +++ b/impls/nsfw/hentai-here.js @@ -0,0 +1,33 @@ +// METADATA +// match: ^https?://(www\.)?hentaihere.com/m/[^/]+/[0-9]+/[0-9]+ + +var impl_src = { + img: '#arf-reader-img', + next: reuse.na, + curpage: function() { + return parseInt(W.rff_thisIndex); + }, + numpages: function() { + return W.rff_imageList.length; + }, + pages: function(url, num, cb, ex) { + cb(W.imageCDN + W.rff_imageList[num - 1], num); + }, + nextchap: function() { + return W.rff_nextChapter; + }, + prevchap: function() { + return W.rff_previousChapter; + }, + curchap: function() { + var curchap; + getEls('ul.dropdown-menu.text-left li').some(function(li, index) { + if(getEl('a.bg-info', li)) { + curchap = index + 1; + } + }); + return curchap; + }, + numchaps: 'ul.dropdown-menu.text-left', + wait: 'ul.dropdown-menu.text-left' +} \ No newline at end of file diff --git a/impls/nsfw/hentai-rules.js b/impls/nsfw/hentai-rules.js new file mode 100644 index 0000000..74daf10 --- /dev/null +++ b/impls/nsfw/hentai-rules.js @@ -0,0 +1,16 @@ +// METADATA +// match: ^https?://www\.hentairules\.net/galleries[0-9]*/picture\.php.+ + +var impl_src = { + img: '#theMainImage', + next: '#linkNext', + imgmod: { + altProp: 'data-src' + }, + numpages: function(cur) { + return parseInt(getEl('.imageNumber').textContent.replace(/([0-9]+)\/([0-9]+)/, cur ? '$1' : '$2')); + }, + curpage: function() { + return this.numpages(true); + } +} \ No newline at end of file diff --git a/impls/nsfw/hentaifr.js b/impls/nsfw/hentaifr.js new file mode 100644 index 0000000..86dbe59 --- /dev/null +++ b/impls/nsfw/hentaifr.js @@ -0,0 +1,18 @@ +// METADATA +// match: ^https?://hentaifr\.net/.+\.php\?id=[0-9]+ + +var impl_src = { + img: function(ctx, next) { + var img = getEls('img[width]', ctx).filter(function(img) { + return img.getAttribute('src').indexOf('contenu/doujinshis') !== -1; + })[0]; + return next ? img : (img ? img.getAttribute('src') : null); + }, + next: function(ctx) { + var img = this.img(ctx, true); + return img ? img.parentNode.getAttribute('href') : null; + }, + wait: function() { + return this.img() && this.next(); + } +} \ No newline at end of file diff --git a/impls/nsfw/hitomi.js b/impls/nsfw/hitomi.js new file mode 100644 index 0000000..be8b582 --- /dev/null +++ b/impls/nsfw/hitomi.js @@ -0,0 +1,17 @@ +// METADATA +// match: ^http(s)?://hitomi.la/reader/[0-9]+.html + +var impl_src = { + img: '#comicImages > img', + next: '#comicImages > img', + numpages: function() { + return W.images.length; + }, + curpage: function() { + return parseInt(W.curPanel); + }, + pages: function(url, num, cb, ex) { + cb(W.images[num - 1].path, num); + }, + wait: '#comicImages > img' +} \ No newline at end of file diff --git a/impls/nsfw/nhentai.js b/impls/nsfw/nhentai.js new file mode 100644 index 0000000..dd7c3b6 --- /dev/null +++ b/impls/nsfw/nhentai.js @@ -0,0 +1,13 @@ +// METADATA +// match: ^https?://nhentai\.net\/g\/[0-9]+/[0-9]+ + +var impl_src = { + img: '#image-container > a img', + next: '#image-container > a', + numpages: '.num-pages', + curpage: '.current', + imgmod: { + altProp: 'data-cfsrc' + }, + +} \ No newline at end of file diff --git a/impls/nsfw/nowshelf.js b/impls/nsfw/nowshelf.js new file mode 100644 index 0000000..6da71b7 --- /dev/null +++ b/impls/nsfw/nowshelf.js @@ -0,0 +1,16 @@ +// METADATA +// match: ^https?://nowshelf.com/watch/[0-9]* + +var impl_src = { + img: '#image', + next: '#image', + numpages: function() { + return parseInt(getEl('#page').textContent.slice(3), 10); + }, + curpage: function() { + return parseInt(getEl('#page > input').value, 10); + }, + pages: function(url, num, cb, ex) { + cb(page[num], num); + } +} \ No newline at end of file diff --git a/impls/nsfw/prism-blush.js b/impls/nsfw/prism-blush.js new file mode 100644 index 0000000..6c76167 --- /dev/null +++ b/impls/nsfw/prism-blush.js @@ -0,0 +1,7 @@ +// METADATA +// match: ^https?://prismblush.com/comic/.+ + +var impl_src = { + img: '#comic img', + next: '#comic a' +} \ No newline at end of file diff --git a/impls/nsfw/pururin.js b/impls/nsfw/pururin.js new file mode 100644 index 0000000..a4dde3c --- /dev/null +++ b/impls/nsfw/pururin.js @@ -0,0 +1,14 @@ +// METADATA +// match: https?://pururin\.us/read/.+ + +var impl_src = { + img: 'img.image-next', + next: 'a.image-next', + numpages: function() { + return Object.keys(chapters).length; + }, + curpage: 'option:checked', + pages: function(url, num, cb, ex) { + cb(chapters[num].image, num); + } +} \ No newline at end of file diff --git a/impls/old_raw/RAW_IMPLs.js b/impls/old_raw/RAW_IMPLs.js new file mode 100644 index 0000000..6511246 --- /dev/null +++ b/impls/old_raw/RAW_IMPLs.js @@ -0,0 +1,1249 @@ +ALL_IMPLS = [{ + name: 'batoto', + match: "^https?://bato.to/reader.*", + img: function(ctx) { + var img = getEl('#comic_page', ctx); + if(img) { + return img.src; + } else { + var imgs = getEls('#content > div:nth-child(8) > img', ctx).map(function(page) { + return page.src; + }); + if(imgs.length > 0) { + this.next = function() { return imgs[0]; }; + this.numpages = function() { return imgs.length; }; + this.pages = function(url, num, cb, ex) { + cb(imgs[num - 1], num); + }; + return imgs[0]; + } + } + }, + next: function() { + if(!this._numpage) { + this._numpage = extractInfo(this.curpage, {type: 'index'}); + this._id = location.hash.split('_')[0].slice(1); + } + return '/areader?id=' + this._id + '&p=' + (++this._numpage); + }, + numpages: '#page_select', + curpage: '#page_select', + curchap: 'select[name=chapter_select]', + numchaps: 'select[name=chapter_select]', + nextchap: function(prev) { + //var link = extractInfo('select[name=chapter_select]', {type: 'value', val: prev ? 1 : -1}); + //return link && link.replace(/https?/, document.location.href.split(':')[0]); // fix for batotos broken https pages + var menu = getEls('div.moderation_bar > ul > li', getEl('#reader')); + for (var i = 0; i != menu.length; i += 1) { + var img = getEl('img', menu[i]); + if (img && img.title == (prev ? "Previous Chapter" : "Next Chapter")) { + return img.parentNode.href.replace(/https?/, document.location.href.split(':')[0]); + } + } + return null; + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: '#comic_page' +}, { + name: 'manga-panda', + match: "^https?://www.mangapanda.com/.*/[0-9]*", + img: '#img', + next: '.next a', + numpages: '#pageMenu', + curpage: '#pageMenu', + nextchap: '#mangainfofooter > #mangainfo_bas table tr:first-child a', + prevchap: '#mangainfofooter > #mangainfo_bas table tr:last-child a' +}, { + name: 'mangafox', + match: "^https?://(fan|manga)fox.(me|la|net)/manga/[^/]*/[^/]*/[^/]*", + img: '.reader-main img', + next: '.pager-list-left > span > a:last-child', + numpages: function() { return W.imagecount; }, + curpage: function () { return W.imagepage; }, + nextchap: '.pager-list-left > a:last-child', + prevchap: '.pager-list-left > a:first-child', + imgURLs: [], + pages: function(url, num, cb, ex) { + var imp = this; + if (this.imgURLs[num]) + cb(this.imgURLs[num], num); + else + ajax({ + url: 'chapterfun.ashx?cid=' + W.chapterid + '&page=' + num, + onload: function(e) { + eval(e.target.responseText); + for (var i = 0; i < d.length; i++) { + imp.imgURLs[num + i] = d[i]; + } + cb(d[0], num); + } + }); + }, + wait: function () { + el = getEl('.reader-main img'); + + return el && el.getAttribute('src') != el.getAttribute('data-loading-img'); + } +}, { + name: 'manga-stream', + match: "^https?://(readms|mangastream).(net|com)/(r|read)/[^/]*/[^/]*", + img: '#manga-page', + next: '.next a', + numpages: function() { + var lastPage = getEl('.subnav-wrapper .controls .btn-group:last-child ul li:last-child'); + return parseInt(lastPage.textContent.match(/[0-9]/g).join(''), 10); + }, + nextchap: function(prev) { + var found; + var chapters = [].slice.call(document.querySelectorAll('.controls > div:first-child > .dropdown-menu > li a')); + chapters.pop(); + for (var i = 0; i < chapters.length; i++) { + if (window.location.href.indexOf(chapters[i].href) !== -1) { + found = chapters[i + (prev ? 1 : -1)]; + if (found) return found.href; + } + } + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'manga-reader', + match: "^https?://www.mangareader.net/.*/.*", + img: '#img', + next: '.next a', + numpages: '#pageMenu', + curpage: '#pageMenu', + nextchap: '#chapterMenu', + prevchap: '#chapterMenu', + wait: '#chapterMenu option' +}, { + name: 'manga-town', + match: "^https?://www.mangatown.com/manga/[^/]+/[^/]+", + img: '#image', + next: '#viewer a', + numpages: '.page_select select', + curpage: '.page_select select', + nextchap: '#top_chapter_list', + prevchap: '#top_chapter_list', + wait: 1000 +}, { + name: 'manga-cow, manga-doom, manga-indo, 3asq.info, moonbunnnycafe', + match: "^https?://(mngcow|mangadoom|mangaindo|merakiscans|www\\.3asq|moonbunnycafe)\\.(co|id|info|com)/[^/]+/[0-9.]+", + img: '.prw a > img', + next: '.prw a', + numpages: 'select.cbo_wpm_pag', + curpage: 'select.cbo_wpm_pag', + nextchap: function(prev) { + var next = extractInfo('select.cbo_wpm_chp', {type: 'value', val: (prev ? 1 : -1)}); + if(next) return window.location.href.replace(/\/[0-9.]+\/?([0-9]+\/?)?[^/]*$/, '/' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'manga-here', + match: "^https?://www.mangahere.c[oc]/manga/[^/]+/[^/]+", + img: '#viewer img:last-child', + next: '#viewer a', + numpages: 'select.wid60', + curpage: 'select.wid60', + numchaps: '#top_chapter_list', + curchap: '#top_chapter_list', + nextchap: function(prev) { + var chapter = W.chapter_list[W.current_chapter_index + (prev ? -1 : 1)]; + return chapter && chapter[1]; + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: function() { + return areDefined(W.current_chapter_index, W.chapter_list, getEl('#top_chapter_list')); + } +}, { + name: 'manga-here mobile', + match: "^https?://m.mangahere.c[oc]/manga/[^/]+/[^/]+", + img: '#image', + next: '#viewer a', + numpages: '.mangaread-page', + curpage: '.mangaread-page' +}, { + name: 'manga-park', + match: "^https?://mangapark\\.me/manga/[^/]+/[^/]+/[^/]+", + img: '.img-link > img', + next: '.page > span:last-child > a', + numpages: function() { + if(W.sel_load && W.sel_load.options[W.sel_load.selectedIndex].value) { + return extractInfo('#sel_page_1'); + } else { + var links = getEls('.img-link > img').map(function(img) { return img.src; }); + this.pages = function(url, num, cb, ex) { + cb(links[num - 1], num); + }; + return links.length; + } + }, + curpage: '#sel_page_1', + nextchap: function(prev) { + var next = extractInfo('#sel_book_1', {type: 'value', val: (prev ? -1 : 1)}); + if(next) return window.location.href.replace(/(\/manga\/[^\/]+).+$/, '$1' + next + '/1'); + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: '#sel_book_1 option' +}, { + name: 'central-de-mangas', + match: "^https?://(centraldemangas\\.org|[^\\.]+\\.com\\.br/leitura)/online/[^/]*/[0-9]*", + img: '#manga-page', + next: '#manga-page', + numpages: '#manga_pages', + curpage: '#manga_pages', + nextchap: function(prev) { + var next = extractInfo('#manga_caps', {type: 'value', val: (prev ? -1 : 1)}); + if(next) return window.location.href.replace(/[^\/]+$/, next); + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + url = url.slice(0, url.lastIndexOf('-') + 1) + ("0" + num).slice(-2) + url.slice(url.lastIndexOf('.')); + cb(url, url); + } +}, { + name: 'manga-joy', + match: "^https?://manga-joy.com/[^/]*/[0-9]*", + img: '.prw img', + next: '.nxt', + numpages: '.wpm_nav_rdr li:nth-child(3) > select', + curpage: '.wpm_nav_rdr li:nth-child(3) > select', + nextchap: function(prev) { + var next = extractInfo('.wpm_nav_rdr li:nth-child(2) > select', {type: 'value', val: prev ? 1 : -1}); + if(next) return window.location.href.replace(/\/[0-9.]+\/?([0-9]+(\/.*)?)?$/, '/' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'dm5', + match: "^https?://[^\\.]*\\.dm5\\.com/m[0-9]*", + img: function (){ + return getEl('img.load-src').getAttribute('data-src'); + }, + next: function(){ + return '#'; + }, + numpages: function () { + return W.pages.length; + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1].getAttribute('data-src'), num - 1); + }, + nextchap: 'a.logo_2', + prevchap: 'a.logo_1', + wait: function (){ + W.pages = getEls('img.load-src'); + return true; + } +}, { + name: 'senmanga', + match: "^https?://[^\\.]+\\.senmanga\\.com/[^/]*/.+", + img: '#picture', + next: '#reader > a', + numpages: 'select[name=page]', + curpage: 'select[name=page]', + numchaps: 'select[name=chapter]', + curchap: 'select[name=chapter]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', {type: 'value', val: (prev ? 1 : -1)}); + if(next) { + var manga = window.location.pathname.slice(1).split('/')[0]; + return window.location.origin + '/' + manga + '/' + next + '/1'; + } + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'japscan', + match: "^https?://www\\.japscan\\.com/lecture-en-ligne/[^/]*/[0-9]*", + img: '#image', + next: '#img_link', + numpages: '#pages', + curpage: '#pages', + nextchap: '#next_chapter', + prevchap: '#back_chapter' +}, { + name: 'pecintakomik', + match: "^https?://www\\.pecintakomik\\.com/manga/[^/]*/[^/]*", + img: '.picture', + next: '.pager a:nth-child(3)', + numpages: 'select[name=page]', + curpage: 'select[name=page]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', {type: 'value', val: (prev ? 1 : -1)}); + if(next) return window.location.href.replace(/\/([^\/]+)\/[0-9]+\/?$/, '/$1/' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'manga-kaka', + match: "^https?://www\\.(mangahen|mangamap)\\.com/[^/]+/[0-9]+", + img: 'img.manga-page', + next: '.nav_pag > li:nth-child(1) > a', + numpages: 'select.cbo_wpm_pag', + curpage: 'select.cbo_wpm_pag', + nextchap: function(prev) { + var chapter = extractInfo('select.cbo_wpm_chp', { type: 'value', val: (prev ? 1 : -1) }); + if(chapter) return window.location.href.replace(/\/[0-9\.]+\/?([0-9]+\/?)?$/, '/' + chapter); + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'manga-wall', + _page: null, + match: "^https?://mangawall\\.com/manga/[^/]*/[0-9]*", + img: 'img.scan', + next: function() { + if(this._page === null) this._page = W.page; + return W.series_url + '/' + W.chapter + '/' + (this._page += 1); + }, + numpages: '.pageselect', + curpage: '.pageselect', + nextchap: function(prev) { + return W.series_url + '/' + (parseInt(W.chapter.slice(1)) + (prev ? -1 : 1)) + '/1'; + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'anime-a', + _page: null, + match: "^https?://manga\\.animea.net/.+chapter-[0-9]+(-page-[0-9]+)?.html", + img: '#scanmr', + next: function() { + if(this._page === null) this._page = W.page; + return W.series_url + W.chapter + '-page-' + (this._page += 1) + '.html'; + }, + numpages: '.pageselect', + curpage: '.pageselect', + nextchap: function(prev) { + return W.series_url + 'chapter-' + (parseInt(W.chapter.match(/[0-9]+/)[0]) + (prev ? -1 : 1)) + '-page-1.html'; + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'kiss-manga', + match: "^https?://kissmanga\\.com/Manga/[^/]+/.+", + img: '#divImage img', + next: '#divImage img', + numpages: function() { + return (W.lstOLA || W.lstImages).length; + }, + curpage: function() { + if(getEls('#divImage img').length > 1) { + return 1; + } else { + return W.currImage + 1; + } + }, + nextchap: '#selectChapter, .selectChapter', + prevchap: '#selectChapter, .selectChapter', + pages: function(url, num, cb, ex) { + cb((W.lstOLA || W.lstImages)[num - 1], num); + } +}, { + name: 'the-spectrum-scans', + match: "^https?://view\\.thespectrum\\.net/series/[^\\.]+\\.html", + img: '#mainimage', + next: function() { + if (++this._page < this._pages.length) { + return this._pages[this._page]; + } + }, + numpages: '.selectpage', + curpage: '.selectpage', + nextchap: function(prev) { + var ps = document.pageSelector1; + var chnum = ps.ch.selectedIndex + (prev ? -1 : 1); + if (chnum < ps.ch.length && chnum > -1) { + return ps.action.split('?')[0] + '?ch=' + ps.ch[chnum].value + '&page=1'; + } else { + return false; + } + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: function() { + var ps = document.pageSelector1; + this._pages = []; + var base = ps.action.split('?')[0]; + for (var i = 0; i < ps.page.length; i++) { + this._pages.push(base + '?ch=' + ps.ch.value + '&page=' + ps.page[i].value); + } + this._page = ps.page[ps.page.selectedIndex].value - 1; + return true; + } +}, { + name: 'manhua-dmzj', + match: "^https?://manhua.dmzj.com/[^/]*/[0-9]+(-[0-9]+)?\\.shtml", + img: '#center_box > img', + next: '#center_box > img', + numpages: function() { + return W.arr_pages.length; + }, + curpage: function() { + var match = location.href.match(/page=([0-9]+)/); + return match ? parseInt(match[1]) : 1; + }, + nextchap: '#next_chapter', + prevchap: '#prev_chapter', + pages: function(url, num, cb, ex) { + cb(W.img_prefix + W.arr_pages[num - 1], num); + }, + wait: '#center_box > img' +}, { + name: 'hqbr', + match: "^https?://hqbr.com.br/hqs/[^/]+/capitulo/[0-9]+/leitor/0", + img: '#hq-page', + next: '#hq-page', + numpages: function() { + return W.pages.length; + }, + curpage: function() { + return W.paginaAtual + 1; + }, + nextchap: function(prev) { + var chapters = getEls('#chapter-dropdown a'), + current = parseInt(W.capituloIndex), + chapter = chapters[current + (prev ? -1 : 1)]; + return chapter && chapter.href; + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1], num); + } +}, { + name: 'dmzj', + match: "^https?://www.dmzj.com/view/[^/]+/.+\\.html", + img: '.comic_wraCon > img', + next: '.comic_wraCon > img', + numpages: function() { + return parseInt(W.pic_total); + }, + curpage: function() { + var match = location.href.match(/page=([0-9])/); + return match ? parseInt(match[1]) : 1; + }, + nextchap: '.next > a', + prevchap: '.pre > a', + pages: function(url, num, cb, ex) { + cb(W.img_prefix + W.picArry[num - 1], num); + }, + wait: '.comic_wraCon > img' +}, { + name: 'mangago', + match: "^https?://(www.)?mangago.me/read-manga/[^/]+/[^/]+/[^/]+", + img: '#page1', + next: '#pic_container', + numpages: '#dropdown-menu-page', + curpage: function() { + return parseInt(getEls('#page-mainer a.btn.dropdown-toggle')[1].textContent.match(/[0-9]+/)[0]); + }, + nextchap: function(prev) { + var chapters = getEls('ul.dropdown-menu.chapter a'), + curName = getEls('#page-mainer a.btn.dropdown-toggle')[0].textContent, + curIdx; + chapters.some(function(chap, idx) { + if(chap.textContent.indexOf(curName) === 0) { + curIdx = idx; + return true; + } + }); + var chapter = chapters[curIdx + (prev ? 1 : -1)]; + return chapter && chapter.href; + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'mangalator', + match: "^https?://mangalator.ch/show.php\\?gallery=[0-9]+", + img: '.image img', + next: '#next', + numpages: 'select[name=image]', + curpage: 'select[name=image]', + nextchap: function(prev) { + var next = extractInfo('select[name=gallery]', {type: 'value', val: (prev ? 1 : -1)}); + if(next) return location.href.replace(/\?gallery=[0-9]+/, '?gallery=' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'eatmanga', + match: "^https?://eatmanga.com/Manga-Scan/[^/]+/.+", + img: '#eatmanga_image, #eatmanga_image_big', + next: '#page_next', + numpages: '#pages', + curpage: '#pages', + nextchap: '#bottom_chapter_list', + prevchap: '#bottom_chapter_list', + invchap: true +}, { + name: 'manga-cat', + match: "^https?://www.mangacat.me/[^/]+/[^/]+/[^\\.]+.html", + img: '.img', + next: '.img-link', + numpages: '#page', + curpage: '#page', + nextchap: '#chapter', + prevchap: '#chapter', + invchap: true, + wait: '#chapter option' +}, { + name: 'readmng.com', + match: "^https?://www\\.readmng\\.com/[^/]+/.+", + img: '.page_chapter-2 img', + next: '.list-switcher-2 > li:nth-child(3) > a, .list-switcher-2 > li:nth-child(2) > a', + numpages: '.list-switcher-2 select[name=category_type]', + curpage: '.list-switcher-2 select[name=category_type]', + nextchap: '.jump-menu[name=chapter_list]', + prevchap: '.jump-menu[name=chapter_list]', + invchap: true +}, { + name: 'mangadex.org', + match: "^https?://mangadex\\.org/chapter/[0-9]+/[0-9]+", + img: '#current_page', + next: function() { + return this._base + ++this._page; + }, + numpages: '#jump_page', + curpage: '#jump_page', + nextchap: function() { + var chapter = document.querySelector('#jump_chapter').selectedOptions[0].previousElementSibling; + return (chapter === null) ? false : (this._base.replace(/[0-9]+\/$/, chapter.value)); + }, + prevchap: function() { + var chapter = document.querySelector('#jump_chapter').selectedOptions[0].nextElementSibling; + return (chapter === null) ? false : (this._base.replace(/[0-9]+\/$/, chapter.value)); + }, + + wait: function() { + var loc = document.location.toString(); + var num = loc.match(/[0-9]+$/); + this._base = loc.slice(0, -num.length); + this._page = parseInt(num); + return true; + } +}, { + name: 'biamamscans.com', + match: "^https?://biamamscans\\.com/read/.+", //nextchap and prevchap broken + img: '.manga-image', + next: 'span.float-right:nth-child(2) > div:nth-child(2) > a:nth-child(1)', + numpages: '#page-select', + curpage: '#page-select', + nextchap: '#chapter-select', + prevchap: '#chapter-select' +}, { + name: 'lhtranslation', + match: "^https?://read.lhtranslation\\.com/read-.+", + img: 'img.chapter-img', + next: '.chapter-content > select + a.label', + numpages: '.chapter-content > select', + curpage: '.chapter-content > select', + numchaps: '.form-control', + curchap: '.form-control', + nextchap: '.form-control', + prevchap: '.form-control', + invchap: true +}, { + name: 'foolslide', + match: "^https?://(" + [ + "manga.redhawkscans.com/reader/read/.+", + "reader.s2smanga.com/read/.+", + "casanovascans.com/read/.+", + "reader.vortex-scans.com/read/.+", + "reader.roseliascans.com/read/.+", + "mangatopia.net/slide/read/.+", + "www.twistedhelscans.com/read/.+", + "sensescans.com/reader/read/.+", + "reader.kireicake.com/read/.+", + "substitutescans.com/reader/read/.+", + "mangaichiscans.mokkori.fr/fs/read/.+", + "reader.shoujosense.com/read/.+", + "www.friendshipscans.com/slide/read/.+", + "manga.famatg.com/read/.+", + "www.demonicscans.com/FoOlSlide/read/.+", + "necron99scans.com/reader/read/.+", + "www.demonicscans.com/FoOlSlide/read/.+", + "reader.psscans.info/read/.+", + "otscans.com/foolslide/read/.+", + "necron99scans.com/reader/read/.+", + "manga.inpowerz.com/read/.+", + "reader.evilflowers.com/read/.+", + "reader.cafeconirst.com/read/.+", + "kobato.hologfx.com/reader/read/.+", + "jaiminisbox.com/reader/read/.+", + "abandonedkittenscans.mokkori.fr/reader/read/.+", + "gomanga.co/reader/read/.+", + "reader\.manga-download\.org/read/.+", + "(www\.)?manga-ar\.net/manga/.+/.+/.+", + "helveticascans.com/r/read/.+", + "reader.thecatscans.com/read/.+", + "yonkouprod.com/reader/read/.+", + "reader.championscans.com/read/.+", + "reader.whiteoutscans.com/read/.+", + "hatigarmscans.eu/hs/read/.+", + "lector.kirishimafansub.com/lector/read/.+", + "hotchocolatescans.com/fs/read/.+", + "www.slide.world-three.org/read/.+", + ].join('|') + ")", + img: function() { + return W.pages[W.current_page].url; + }, + next: function() { + return 'N/A'; + }, + numpages: function() { + return W.pages.length; + }, + curpage: function() { + return W.current_page + 1; + }, + nextchap: function(prev) { + var desired; + var dropdown = getEls('ul.dropdown')[1] || getEls('ul.uk-nav')[1] || getEls('ul.dropdown-menu')[3]; + if(!dropdown) return; + getEls('a', dropdown).forEach(function(chap, idx, arr) { + if(location.href.indexOf(chap.href) === 0) desired = arr[idx + (prev ? 1 : -1)]; + }); + return desired && desired.href; + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1].url, num); + }, + wait: function() { + if(W.location.href.indexOf('gomanga.co') !== -1) { + var match = document.body.innerHTML.match(/(\w+)\[id\]\.url/); + W.pages = match && match[1] && W[match[1]]; + } + return W.pages; + } +}, { + name: 'mangatraders', + match: "^https?://mangatraders\\.biz/read-online/.+", + img: 'img.CurImage', + next: '.image-container a', + numpages: '.PageSelect', + curpage: '.PageSelect', + nextchap: function(prev) { + var next = extractInfo('.ChapterSelect', {type:'text', val: (prev ? -1 : 1)}); + if(next) { + var chapter = next.match(/[0-9.]+/)[0]; + return location.href.replace(/chapter-[0-9.]+/, 'chapter-' + chapter).replace(/page-[0-9]+/, 'page-1'); + } + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'mangainn', + match: "^https?://www.mangainn.net/manga/chapter/.+", + img: '#imgPage', + next: function() { + if(!this._count) this._count = extractInfo(this.curpage, {type: 'value'}); + var url = location.href; + if(!/page_[0-9]+/.test(url)) url += '/page_1'; + return url.replace(/page_[0-9]+/, 'page_' + (++this._count)); + }, + numpages: '#cmbpages', + curpage: '#cmbpages', + nextchap: function(prev) { + var next = extractInfo('#chapters', {type:'value', val: (prev ? -1 : 1)}); + if(next) return location.href.replace(/\/chapter\/.+$/, '/chapter/' + next + '/page_1'); + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'kukudm', + match: "^https?://(www|comic|comic2|comic3).kukudm.com/comiclist/[0-9]+/[0-9]+/[0-9]+.htm", + img: function(ctx) { + var script = getEl('td > script[language=javascript]', ctx); + if(script) { + return 'http://n.kukudm.com/' + script.textContent.match(/\+"([^']+)/)[1]; + } + }, + next: function(ctx) { + var links = getEls('td > a', ctx); + return links[links.length - 1].getAttribute('href'); + }, + numpages: function(cur) { + return parseInt(document.body.textContent.match(/共([0-9]+)页/)[1]); + }, + curpage: function() { + return parseInt(document.body.textContent.match(/第([0-9]+)页/)[1]); + }, + beforexhr: reuse.encodeChinese +}, { + name: 'mangachapter', + match: "^https?://www\\.mangachapter\\.me/[^/]+/[^/]+/[^/]+.html", + img: '#mangaImg, #viewer > table > tbody > tr > td:nth-child(1) > a:nth-child(2) > img', + next: '.page-select + a.button-page', + numpages: '.page-select select', + curpage: '.page-select select', + invchap: true, + nextchap: '#top_chapter_list', + prevchap: '#top_chapter_list', + wait: '#top_chapter_list' +}, { + name: 'kawaii', + match: "^https://kawaii.ca/reader/.+", + img: '.picture', + next: 'select[name=page] + a', + numpages: 'select[name=page]', + curpage: 'select[name=page]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', {type:'value', val: (prev ? -1 : 1)}); + if(next) return location.href.replace(/\/reader\/([^/]+)(\/.+)?$/, '/reader/$1/' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'lonemanga', + match: "^https?://lonemanga.com/manga/[^/]+/[^/]+", + img: '#imageWrapper img', + next: '#imageWrapper a', + numpages: '.viewerPage', + curpage: '.viewerPage', + nextchap: function(prev) { + var next = extractInfo('.viewerChapter', {type:'value', val: (prev ? 1 : -1)}); + if(next) return location.href.replace(/\/manga\/([^/]+)\/.+$/, '/manga/$1/' + next); + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'madokami', + match: "^https?://manga\\.madokami\\.al/reader/.+", + img: 'img', + next: 'img', + curpage: function() { + return parseInt(query().index) + 1; + }, + numpages: function() { + if(!this._pages) { + this._pages = JSON.parse(getEl('#reader').dataset.files); + } + return this._pages.length; + }, + pages: function(url, num, cb, ex) { + url = url.replace(/file=.+$/, 'file=' + this._pages[num - 1]); + cb(url, url); + }, + wait: '#reader' +}, { + name: 'egscans', + match: '^https?://read.egscans.com/.+', + img: '#image_frame img', + next: '#image_frame img', + curpage: 'select[name=page]', + numpages: 'select[name=page]', + nextchap: function(prev) { + var data = getEl(this.curchap).getAttribute('onchange').match(/'[^']+'/g); + var next = extractInfo(this.curchap, { type: 'value', val: (prev ? -1 : 1) }); + if(next) return location.origin + '/' + data[0].slice(1, -1) + '/' + next; + }, + prevchap: function() { + return this.nextchap(true); + }, + curchap: 'select[name=chapter]', + numchaps: 'select[name=chapter]', + pages: function(url, num, cb, ex) { + cb('/' + W.img_url[num], num); + } +}, { + name: 'imperialscans', + match: '^https?://imperialscans.com/read/.+', + img: '#page-img', + next: '#page-url', + curpage: function() { + return extractInfo('#page-select', { type: 'index', val: -1 }); + }, + numpages: function() { + return extractInfo('#page-select') - 1; + }, + curchap: function() { + var options = getEls('#chapter-select option:not([disabled])'); + var chapter = 1; + options.some(function(value, index) { + if (location.pathname === value.value) { + chapter = options.length - index; + return true; + } + }); + return chapter; + }, + numchaps: function() { + return extractInfo('#chapter-select'); + }, + nextchap: '#page-control > li:nth-child(5) > a', + prevchap: '#page-control > li:nth-child(1) > a' +}, { + name: 'chuixue', + match: "^https?://www.chuixue.com/manhua/[0-9]+/[0-9]+.html", + img: '#qTcms_pic', + next: '#qTcms_pic', + curpage: '#qTcms_select_i', + numpages: '#qTcms_select_i', + pages: function(url, num, cb, ex) { + if(!this._pages) { + this._pages = W.qTcms_S_m_murl.split('$qingtiandy$'); + } + cb(this._pages[num - 1], num); + }, + nextchap: function() { + return W.qTcms_Pic_nextArr; + }, + wait: '#qTcms_pic' +}, { + name: 'sh-arab', + match: '^https?://www.sh-arab.com/manga/.+', + img: 'img.picture', + next: '#omv td > a', + curpage: 'select[name=page]', + numpages: 'select[name=page]', + curchap: 'select[name=chapter]', + numchaps: 'select[name=chapter]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', {type:'value', val: (prev ? -1 : 1)}); + if (next) return location.href.replace(/[^\/]+$/, next); + }, + prevchap: function() { + return this.nextchap(true); + } +}, { + name: 'br.mangahost.com', + match: "^http(s)?://br.mangahost.com/manga/[^/]+/.+", + img: 'img.open', + next: '.image-content > a', + curpage: '.viewerPage', + numpages: '.viewerPage' +}, { + name: 'spinybackmanga and titaniascans', + match: '^https?://(spinybackmanga.com/\\?manga=[^&]+&chapter=.+|www\.titaniascans\.com/reader/.+/.+)', + img: '#thePicLink img', + next: '#thePicLink', + curpage: function() { + return W.current; + }, + numpages: function() { + return getEl('#loadingbar tr').children.length; + }, + curchap: function() { + return parseInt(getEls('.selector')[1].firstChild.textContent.match(/[0-9]+/)[0]); + }, + numchaps: function() { + return getEls('.selector .options')[1].children.length; + }, + nextchap: function(prev) { + var nextChap = document.scripts[2].textContent.match(/location.href = "([^"]+)"/)[1]; + if(prev) { + [].some.call(getEls('.selector .options')[1].children, function(child, index, children) { + if(child.href === nextChap) { + nextChap = children[index - 2] && children[index - 2].href; + return true; + } + }); + } + return nextChap; + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + var next = url.replace(/(?:(\/)2\/|[0-9]*)$/, '$1' + (num + 1)); + cb(W.imageArray[num - 1], next); + } +}, { + name: 'manga.ae', + match: "https?://www.manga.ae/[^/]+/[^/]+/", + img: '#showchaptercontainer img', + next: '#showchaptercontainer a', + curpage: 'a.chpage', + nextchap: '.chapter:last-child', + prevchap: '.chapter:first-child' +}, { + name: 'mangaforall', + match: "https?://mangaforall.com/manga/[^/]+/[^/]+/", + img: '#page > img', + next: '#page > img', + numpages: '#chapter > div:nth-child(1) > div > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-left.uk-text-center-small > div > div > div > ul', + curpage: '#chapter > div:nth-child(1) > div > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-left.uk-text-center-small > div > a.uk-button.uk-button-primary.number.uk-button-danger', + nextchap: '#chapter > div:nth-child(5) > div.uk-grid.uk-grid-collapse.uk-margin-top > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-left.uk-text-center-small > a', + prevchap: '#chapter > div:nth-child(5) > div.uk-grid.uk-grid-collapse.uk-margin-top > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-right.uk-text-center-small > a', + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1].url, num); + } +}, { + name: 'hellocomic', + match: "https?://hellocomic.com/[^/]+/[^/]+/p[0-9]+", + img: '.coverIssue img', + next: '.coverIssue a', + numpages: '#e1', + curpage: '#e1', + nextchap: '#e2', + prevchap: '#e2', + curchap: '#e2', + numchaps: '#e2' +}, { + name: 'read-comic-online', + match: "^https?://readcomiconline\\.to/Comic/[^/]+/.+", + img: '#divImage img', + next: '#divImage img', + numpages: function() { + return W.lstImages.length; + }, + curpage: function() { + return getEls('#divImage img').length > 1 ? 1 : W.currImage + 1; + }, + nextchap: '#selectEpisode, .selectEpisode', + prevchap: '#selectEpisode, .selectEpisode', + pages: function(url, num, cb, ex) { + cb(W.lstImages[num - 1], num); + } +}, { + name: 'mangaeden', + match: "^https?://(www\\.)?mangaeden\\.com/(en|it)/(en|it)-manga/.+", + img: '#mainImg', + next: '#nextA', + numpages: '#pageSelect', + curpage: '#pageSelect', + numchaps: '#combobox', + curchap: '#combobox', + invchap: true, + nextchap: function (prev) { + var cbox = getEl('#combobox'); + var opt = cbox[prev ? cbox.selectedIndex + 1 : cbox.selectedIndex - 1]; + var span = getEl('span.hideM0 a'); + return opt && span && span.href + parseInt(opt.value) + '/1/'; + }, + prevchap: function () { + return this.nextchap(true); + } +}, { + name: 'comicastle', + match: "^https?://comicastle\\.org/read-.+", + img: '.chapter-img', + next: '.chapter-content > select + a.label', + numpages: '.chapter-content > select', + curpage: '.chapter-content > select', + numchaps: '.form-control', + curchap: '.form-control', + nextchap: '.form-control', + prevchap: '.form-control', + invchap: true +}, { + name: 'mymh8', + match: "^https?://(www\\.)?mymh8\\.com/chapter/.+", + img: '#viewimg', + next: reuse.na, + numpages: function() { + return W.maxpages; + }, + curpage: '#J_showpage > span', + nextchap: function(prev) { + var button = prev ? getEl('div.m3p > input:first-of-type') : getEl('div.m3p > input:last-of-type'); + return button && button.attributes.onclick.value.match(/\.href='([^']+)'/)[1]; + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + cb(W.WebimgServerURL[0] + W.imageslist[num], num); + }, + wait: function() { + return W.imageslist.length > 0; + } +}, { + name: 'unionmangas', + match: "https?://(www\\.)?unionmangas\\.net/leitor/.+", + img: '.slick-active img.real', + next: reuse.na, + numpages: '.selectPage', + curpage: '.selectPage', + numchaps: '#cap_manga1', + curchap: '#cap_manga1', + nextchap: '#cap_manga1', + prevchap: '#cap_manga1', + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1], num); + }, + wait: function() { + W.pages = getEls('img.real').map(function(el) { + return el.src || el.dataset.lazy; + }); + return W.pages && W.pages.length > 0; + } +}, { + name: 'otakusmash', + match: "https?://www\\.otakusmash\\.com/(read-comics|read-manga)/.+", + img: 'img.picture', + next: 'select[name=page] + a', + curpage: 'select[name=page]', + numpages: 'select[name=page]', + nextchap: function(prev) { + var nextChap = extractInfo('select[name=chapter]', {type: 'value', val: prev ? 1 : -1}); + return nextChap ? location.href.replace(/(read-(comics|manga)\/[^\/]+).*/, '$1/' + nextChap) : null; + }, + prevchap: function() { + return this.nextchap(true); + }, + numchaps: 'select[name=chapter]', + curchap: 'select[name=chapter]', + invchap: true +}, { + name: 'mangahome', + match: "https?://www\\.mangahome\\.com/manga/.+/.+", + img: '#image', + next: '#viewer > a', + curpage: '.mangaread-page select', + numpages: '.mangaread-page select', + nextchap: function(prev) { + var buttons = getEls('.mangaread-footer .left > .btn-three'); + for (var i = 0; i < buttons.length; i++) { + if (buttons[i].textContent.indexOf(prev ? 'Prev Chapter' : 'Next Chapter') > - 1) { + return buttons[i].href; + } + } + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: '#image' +}, { + name: 'readcomics', + match: "https?://(www\\.)?readcomics\\.tv/.+/chapter-[0-9]+(/[0-9]+|$)", + img: '#main_img', + next: '.nav.next', + curpage: 'select[name=page_select]', + numpages: 'select[name=page_select]', + nextchap: 'select[name=chapter_select]', + prevchap: 'select[name=chapter_select]', + curchap: 'select[name=chapter_select]', + numchaps: 'select[name=chapter_select]', + wait: 'select[name=page_select]' +}, { + name: 'cartoonmad', + match: "https?://(www\\.)?(cartoonmad|comicnad)\.com/comic/[0-9]+\.html", + img: 'tr:nth-child(5) > td > table > tbody > tr:nth-child(1) > td > a > img', + next: 'a.onpage+a', + curpage: 'a.onpage', + numpages: function() { + return extractInfo('select[name=jump]') - 1; + }, + nextchap: function() { + let filter = getEls('.pages').filter(function(i) { + return i.textContent.match('下一話'); + }); + return filter.length ? filter[0].href : null; + }, + prevchap: function() { + let filter = getEls('.pages').filter(function(i) { + return i.textContent.match('上一話'); + }); + return filter.length ? filter[0].href : null; + }, +}, { + name: 'ikanman', + match: "https?://(www|tw)\.(ikanman|manhuagui)\.com/comic/[0-9]+/[0-9]+\.html", + img: '#mangaFile', + next: function() { + return W._next; + }, + curpage: '#page', + numpages: '#pageSelect', + nextchap: function(prev) { + var chap = prev ? W._prevchap : W._nextchap; + if (chap > 0) { + return location.href.replace(/(\/comic\/[0-9]+\/)[0-9]+\.html.*/, "$1" + chap + ".html"); + } else { + return false; + } + }, + prevchap: function() { + return this.nextchap(true); + }, + wait: function() { + if (getEl('#mangaFile')) { + W._nextchap = W.cInfo.nextId; + W._prevchap = W.cInfo.prevId; + var ex = extractInfo.bind(this); + W._next = location.href.replace(/(_p[0-9]+)?\.html.*/, '_p' + (ex('curpage') + 1) + '.html'); + W._base = ex('img').replace(/[^\/]+$/, ''); + return true; + } + }, + pages: function(url, num, cb, ex) { + var nexturl = url.replace(/(_p[0-9]+)?\.html.*/, '_p' + (num + 1) + '.html'); + var imgurl = W._base + W.cInfo.files[num - 1]; + cb(imgurl, nexturl); + } +}, { + name: 'mangasail and mangatail', + match: 'https?://www\.manga(sail|tail)\.com/[^/]+', + img: '#images img', + next: '#images a', + curpage: '#edit-select-page', + numpages: '#edit-select-page', + nextchap: function(prev) { + return location.origin + '/node/' + extractInfo('#edit-select-node', {type: 'value', val: prev ? -1 : 1}); + }, + prevchap: function() { + return this.nextchap(true); + }, + curchap: '#select_node', + numchaps: '#select_node' +}, { + name: 'komikstation', + match: "^https?://www\.komikstation\.com/.+/.+/.+", + img: '#mainpage', + next: function() { + return W._base + '?page=' + (W.glbCurrentpage + 1); + }, + numpages: '#index select', + curpage: '#index select', + pages: function(url, num, cb, ex) { + next = W._base + '?page=' + (num + 1); + cb(W.pages[num - 1], next); + }, + wait: function() { + W._base = location.href.replace(/[?#].+$/, ''); + return W.pages; + } +}, { + name: 'gmanga', + match: "^https?://gmanga.me/mangas/", + img: function() { + return W.pages[W.firstImg - 1]; + }, + next: function() { + return location.href + '#' + (W.firstImg + 1); + }, + numpages: function() { + return W.totalImgs; + }, + curpage: function() { + return W.firstImg; + }, + nextchap: function(prev) { + var num = parseInt(extractInfo('#chapter', {type: 'value', val: prev ? 1 : -1})); + return num && location.href.replace(/(\/mangas\/[^\/]+\/)[0-9]+(\/[^\/]+)/, '$1' + num + '$2'); + }, + prevchap: function() { + return this.nextchap(true); + }, + numchaps: '#chapter', + curchap: '#chapter', + invchap: true, + pages: function(url, num, cb, ex) { + var nexturl = location.href + '#' + (num + 1); + cb(W.pages[num - 1], nexturl); + }, + wait: function() { + W.pages = W.release_pages && W.release_pages[1]; + return W.pages; + } +}, { + name: '930mh', + match: "http://www\.930mh\.com/manhua/\\d+/\\d+.html", + img: '#images > img', + next: function() { + return location.origin + location.pathname + '?p=' + (W.SinTheme.getPage() + 1); + }, + pages: function(url, num, cb, ex) { + cb(new URL(W.pageImage).origin + '/' + W.chapterPath + W.chapterImages[num - 1], num - 1); + }, + curpage: function() { + return W.SinTheme.getPage(); + }, + numpages: function() { + return W.chapterImages.length; + }, + nextchap: function(){ + return W.nextChapterData.id && W.nextChapterData.id > 0 ? W.comicUrl + W.nextChapterData.id + '.html' : null; + }, + prevchap: function(){ + return W.prevChapterData.id && W.prevChapterData.id > 0 ? W.comicUrl + W.prevChapterData.id + '.html' : null; + }, + wait: '#images > img' +}, { + name: '漫畫王', + match: "https://www\.mangabox\.me/reader/\\d+/episodes/\\d+/", + img: 'img.jsNext', + next: function() { + return '#'; + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1].src, num - 1); + }, + numpages: function() { + return W.pages.length; + }, + nextchap: '.lastSlider_nextButton', + wait: function (){ + W.pages = getEls('img.jsNext'); + return true; + } +}, { + name: '2comic.com 動漫易', + match: "http://twocomic.com/view/comic_\\d+.html", + img: '#TheImg', + next: function() { + return '#'; + }, + pages: function(url, num, cb, ex) { + W.p++; + var ss = W.ss; + var c = W.c; + var ti = W.ti; + var nn = W.nn; + var p = W.p; + var mm = W.mm; + var f = W.f; + var img = 'http://img' + ss(c, 4, 2) + '.8comic.com/' + ss(c, 6, 1) + '/' + ti + '/' + ss(c, 0, 4) + '/' + nn(p) + '_' + ss(c, mm(p) + 10, 3, f) + '.jpg'; + cb(img, num - 1); + }, + numpages: function() { + return W.ps * 1; + }, + curpage: function() { + return W.p; + }, + numchaps: function() { + return W.chs; + }, + curchap: function() { + return W.ch; + }, + nextchap: function() { + return W.ch < W.chs ? W.replaceurl('ch', W.ni) : false; + }, + prevchap: function() { + return W.ch > 1 ? W.replaceurl('ch', W.pi) : false; + }, + wait:'#TheImg' +}]; diff --git a/impls/old_raw/RAW_NSFW_IMPLS.js b/impls/old_raw/RAW_NSFW_IMPLS.js new file mode 100644 index 0000000..7cba255 --- /dev/null +++ b/impls/old_raw/RAW_NSFW_IMPLS.js @@ -0,0 +1,464 @@ +ALL_NSFW_IMPLS = [{ + name: 'geh-and-exh', + match: "^https?://(e-hentai|exhentai).org/s/.*/.*", + img: '.sni > a > img, #img', + next: '.sni > a, #i3 a', + numpages: 'div.sn > div > span:nth-child(2)', + curpage: 'div.sn > div > span:nth-child(1)' + }, { + name: 'fakku', + match: "^http(s)?://www.fakku.net/.*/.*/read", + img: '.current-page', + next: '.current-page', + numpages: '.drop', + curpage: '.drop', + pages: function(url, num, cb, ex) { + var firstNum = url.lastIndexOf('/'), + lastDot = url.lastIndexOf('.'); + var c = url.charAt(firstNum); + while (c && !/[0-9]/.test(c)) { + c = url.charAt(++firstNum); + } + var curPage = parseInt(url.slice(firstNum, lastDot), 10); + url = url.slice(0, firstNum) + ('00' + (curPage + 1)).slice(-3) + url.slice(lastDot); + cb(url, url); + } + }, { + name: 'nowshelf', + match: "^https?://nowshelf.com/watch/[0-9]*", + img: '#image', + next: '#image', + numpages: function() { + return parseInt(getEl('#page').textContent.slice(3), 10); + }, + curpage: function() { + return parseInt(getEl('#page > input').value, 10); + }, + pages: function(url, num, cb, ex) { + cb(page[num], num); + } + }, { + name: 'nhentai', + match: "^https?://nhentai\\.net\\/g\\/[0-9]+/[0-9]+", + img: '#image-container > a img', + next: '#image-container > a', + numpages: '.num-pages', + curpage: '.current', + imgmod: { + altProp: 'data-cfsrc' + }, + }, { + name: '8muses', + match: "^http(s)?://www.8muses.com/comix/picture/[^/]+/[^/]+/[^/]+/.+", + img: function(ctx) { + var img = getEl('.photo img.image', ctx); + return img ? img.src : getEl('#imageDir', ctx).value + getEl('#imageName', ctx).value; + }, + next: '.photo > a', + curpage: '#page-select-s', + numpages: '#page-select-s' + }, { + name: 'hitomi', + match: "^http(s)?://hitomi.la/reader/[0-9]+.html", + img: '#comicImages > img', + next: '#comicImages > img', + numpages: function() { + return W.images.length; + }, + curpage: function() { + return parseInt(W.curPanel); + }, + pages: function(url, num, cb, ex) { + cb(W.images[num - 1].path, num); + }, + wait: '#comicImages > img' + }, { + name: 'doujin-moe', + _pages: null, + match: "^https?://doujins\.com/.+", + img: 'img.picture', + next: reuse.na, + numpages: function() { + if (!this._pages) { + this._pages = getEls('#gallery djm').map(function(file) { + return file.getAttribute('file').replace('static2.', 'static.'); + }); + } + return this._pages.length; + }, + curpage: function() { + return parseInt(getEl('.counter').textContent.match(/^[0-9]+/)[0]); + }, + pages: function(url, num, cb, ex) { + cb(this._pages[num - 1], num); + } + }, { + name: 'pururin', + match: "https?://pururin\\.us/read/.+", + img: 'img.image-next', + next: 'a.image-next', + numpages: function() { + return Object.keys(chapters).length; + }, + curpage: 'option:checked', + pages: function(url, num, cb, ex) { + cb(chapters[num].image, num); + } + }, { + name: 'hentai-rules', + match: "^https?://www\\.hentairules\\.net/galleries[0-9]*/picture\\.php.+", + img: '#theMainImage', + next: '#linkNext', + imgmod: { + altProp: 'data-src' + }, + numpages: function(cur) { + return parseInt(getEl('.imageNumber').textContent.replace(/([0-9]+)\/([0-9]+)/, cur ? '$1' : '$2')); + }, + curpage: function() { + return this.numpages(true); + } + }, { + name: 'ero-senmanga', + match: "^https?://ero\\.senmanga\\.com/[^/]*/[^/]*/[0-9]*", + img: '#picture', + next: '#omv > table > tbody > tr:nth-child(2) > td > a', + numpages: 'select[name=page]', + curpage: 'select[name=page]', + nextchap: function(prev) { + var next = extractInfo('select[name=chapter]', { + type: 'value', + val: (prev ? -1 : 1) + }); + if (next) return window.location.href.replace(/\/[^\/]*\/[0-9]+\/?$/, '') + '/' + next + '/1'; + }, + prevchap: function() { + return this.nextchap(true); + } + }, { + name: 'hentaifr', + match: "^https?://hentaifr\\.net/.+\\.php\\?id=[0-9]+", + img: function(ctx, next) { + var img = getEls('img[width]', ctx).filter(function(img) { + return img.getAttribute('src').indexOf('contenu/doujinshis') !== -1; + })[0]; + return next ? img : (img ? img.getAttribute('src') : null); + }, + next: function(ctx) { + var img = this.img(ctx, true); + return img ? img.parentNode.getAttribute('href') : null; + }, + wait: function() { + return this.img() && this.next(); + } + }, { + name: 'prism-blush', + match: "^https?://prismblush.com/comic/.+", + img: '#comic img', + next: '#comic a' + }, { + name: 'hentai-here', + match: "^https?://(www\\.)?hentaihere.com/m/[^/]+/[0-9]+/[0-9]+", + img: '#arf-reader-img', + next: reuse.na, + curpage: function() { + return parseInt(W.rff_thisIndex); + }, + numpages: function() { + return W.rff_imageList.length; + }, + pages: function(url, num, cb, ex) { + cb(W.imageCDN + W.rff_imageList[num - 1], num); + }, + nextchap: function() { + return W.rff_nextChapter; + }, + prevchap: function() { + return W.rff_previousChapter; + }, + curchap: function() { + var curchap; + getEls('ul.dropdown-menu.text-left li').some(function(li, index) { + if(getEl('a.bg-info', li)) { + curchap = index + 1; + } + }); + return curchap; + }, + numchaps: 'ul.dropdown-menu.text-left', + wait: 'ul.dropdown-menu.text-left' + }, { + name: 'foolslide', + match: "^https?://(" + [ + 'reader.yuriproject.net/read/.+', + 'ecchi.japanzai.com/read/.+', + 'h.japanzai.com/read/.+', + 'reader.japanzai.com/read/.+', + '(raws\\.)?yomanga.co(/reader)?/read/.+', + 'hentai.cafe/manga/read/.+', + '(www\\.)?yuri-ism\\.net/slide/read/.' + ].join('|') + ")", + img: function() { + return W.pages[W.current_page].url; + }, + next: reuse.na, + numpages: function() { + return W.pages.length; + }, + curpage: function() { + return W.current_page + 1; + }, + nextchap: function(prev) { + var desired; + var dropdown = getEls('ul.dropdown')[1] || getEls('ul.uk-nav')[1]; + if(!dropdown) return; + getEls('a', dropdown).forEach(function(chap, idx, arr) { + if(location.href.indexOf(chap.href) === 0) desired = arr[idx + (prev ? 1 : -1)]; + }); + return desired && desired.href; + }, + prevchap: function() { + return this.nextchap(true); + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1].url, num); + }, + wait: function() { + if(W.location.href.indexOf('yomanga') !== -1) { + // select all possible variable names for data structure + var matches = [].slice.call(document.body.innerHTML.match(/\w+\s*=\s*\[\{"id"/ig)); + // extract actual variable name from match + var tokens = matches.map(function(m) { + var tok = m.match(/^(\w+)\s*=/i); + return tok && tok[1]; + }); + // determine the variable that holds the largest data structure + var largest; + var max = 0; + tokens.forEach(function(token) { + var cur = W[token]; + if(cur && cur.length > max && [].every.call(cur, function(pg) { return pg.url.endsWith(pg.filename); })) { + max = cur.length; + largest = cur; + } + }); + W.pages = largest || 'fail'; + } + return W.pages; + } + }, { + name: 'tsumino', + match: '^https?://(www\\.)?tsumino.com/Read/View/.+', + img: '.reader-img', + next: reuse.na, + numpages: function(curpage) { + return W.reader_max_page; + }, + curpage: function() { + return W.reader_current_pg; + }, + pages: function(url, num, cb) { + var self = this; + if(!self._pages) { + ajax({ + method: 'POST', + url: '/Read/Load', + data: 'q=' + W.location.href.match(/View\/(\d+)/)[1], + responseType: 'json', + beforeSend: function(xhr) { + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + }, + onload: function(e) { + var res = e.target.response; + if(!res) return log('failed to load tsumino pages, site has probably been updated, report on forums', 'error'); + self._pages = res.reader_page_urls.map(function(page) { + return W.reader_baseobj_url + '?name=' + encodeURIComponent(page); + }); + cb(self._pages[num - 1], num); + } + }); + } else { + cb(self._pages[num - 1], num); + } + }, + wait: '.reader-img' + }, { + name: 'dynasty-scans', + match: "^https?://dynasty-scans.com/chapters/.*", + img: '#image > img', + next: reuse.na, + numpages: function() { + return W.pages.length; + }, + curpage: function() { + return parseInt(getEl('#image > div.pages-list > a.page.active').getAttribute('href').slice(1)); + }, + nextchap: '#next_link', + prevchap: '#prev_link', + pages: function(url, num, cb, ex) { + url = W.pages[num - 1].image; + cb(url, url); + } + }, { + name: 'hentaibox', + match: 'https?://www\\.hentaibox\\.net/hentai-manga/[^/]+/[0-9]+', + img: 'td > center > a > img', + next: 'td > center > a', + numpages: function(cur) { + var sel = getEl('select[name=np2]'); + if(sel) { + var info = sel.options[0].textContent.match(/Page ([0-9]+) out of ([0-9]+)/i); + if(info && info.length >= 3) return parseInt(cur ? info[1] : info[2]); + } + }, + curpage: function() { + return this.numpages(true); + } + }, { + name: 'hentai-free', // trying to only show button on manga pages, but URL scheme makes it tough. + match: "^http://hentai-free.org/(?!(?:tag|manga-doujinshi|hentai-video|hentai-wall|tags-map)/|.*\\?).+/$", + img: function() { + return W.pages[0]; + }, + next: reuse.na, + numpages: function() { + return W.pages.length; + }, + curpage: function() { + return 1; + }, + wait: function() { + var links = getEls('.gallery-item a, a.bwg_lightbox_0'); + if (links.length > 0) { + W.pages = links.map(function(el) { + return el.href.replace(/\?.*$/, ''); + }); + return true; + } + return false; + }, + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1], num); + } + }, { + name: 'mangafap', + match: "^https?://mangafap\\.com/image/.+", + img: '#p', + next: '#lbanner + div > a', + numpages: 'select.span2', + curpage: '.pagination li.active a' + }, { + name: 'hentai4manga', + match: "^https?://hentai4manga\\.com/hentai_manga/.+/\\d+/$", + img: '#textboxContent img', + next: '#textboxContent a', + numpages: '#sl', + curpage: '#sl' + }, { + name: 'heymanga', + match: "https?://(www\\.)?heymanga\\.me/manga/[^/]+/[0-9.]+/[0-9]+", + img: '#img-content', + next: function(context) { + var num = this.curpage(context) + 1; + return document.location.href.replace(/([0-9]+)$/, num); + }, + numpages: function() { + exUtil.clearAllTimeouts(); // site things mloader is an adblocker because it removes elems and blocks page, this removes the interval that checks for it + return getEl('#page_list').length - 1; + }, + curpage: function(context) { + var match = getEls('#page_list > option[selected]', context); + return parseInt(match[match.length - 1].value); // dumb site always marks page 1 as "selected" in addition to actual selected page + }, + nextchap: 'section > .row.text-center > p + a, section > .row.text-center .ti-line-dotted + a', + prevchap: 'section > .row.text-center .ti-hand-point-left + a', + wait: '#page_list > option[selected]' + }, { + name: 'simply-hentai', + match: "https?://(.+\\.)?simply-hentai\\.com/.+/page/[0-9]+", + img: function(ctx) { + return getEl('#image span:nth-of-type(2)', ctx).dataset.src; + }, + next: '#nextLink', + numpages: function() { + return parseInt(getEl('.inner-content .row .m10b.bold').textContent.match(/Page\s*\d+\s*of\s*(\d+)/)[1]); + }, + curpage: function() { + return parseInt(getEl('.inner-content .row .m10b.bold').textContent.match(/Page\s*(\d+)/)[1]); + }, + wait: '#image img' + }, { + name: 'gameofscanlation', + match: "https?://gameofscanlation\.moe/projects/.+/.+", + img: '.chapterPages img:first-of-type', + next: function() { + return location.href; + }, + numpages: function() { + return getEls('.chapterPages img').length; + }, + nextchap: '.comicNextPageUrl', + prevchap: '.comicPreviousPageUrl', + curchap: 'select[name=chapter_list]', + numchaps: 'select[name=chapter_list]', + pages: function(url, num, cb, ex) { + cb(W.pages[num - 1], location.href + '#' + num); + }, + wait: function() { + W.pages = getEls('.chapterPages img').map(function (el) { + return el.src; + }); + return W.pages && W.pages.length > 0; + } + }, { + name: 'luscious', + match: "https?://luscious\\.net/c/.+?/pictures/album/.+?/id/.+", + img: '.icon-download', + next: '#next', + curpage: function() { + return parseInt(getEl('#pj_page_no').value); + }, + numpages: '#pj_no_pictures' + }, { + name: 'hentaifox', + match: "https?://hentaifox\\.com/g/.+", + img: '.gallery_content img.lazy', + next: '.gallery_content a.next_nav', + curpage: function() { + return parseInt(extractInfo('.pag_info', {type: 'text'})); + }, + numpages: function() { + return extractInfo('.pag_info') - 2; + } + }, { + name: 'hentai2read', + match: "https?://hentai2read\\.com/.+", + img: '#arf-reader', + next: '#arf-reader', + curpage: function() { + return parseInt(ARFfwk.doReader.data.index); + }, + numpages: function() { + return ARFfwk.doReader.data['images'].length; + }, + nextchap: function(){ + return ARFfwk.doReader.data.nextURL; + }, + prevchap: function(){ + return ARFfwk.doReader.data.previousURL; + }, + pages: function(url, num, cb, ex) { + cb(ARFfwk.doReader.getImageUrl(ARFfwk.doReader.data['images'][num - 1]), num); + } + }, { + name: 'hentai.ms', + match: "http://www.hentai.ms/manga/[^/]+/.+", + img: 'center > a > img', + next: 'center > a:last-child', + curpage: function() { + return parseInt(getEl('center > a').parentNode.textContent.match(/([0-9]+)\//)[1]); + }, + numpages: function() { + return parseInt(getEl('center > a').parentNode.textContent.match(/\/([0-9]+)/)[1]); + } + }] \ No newline at end of file diff --git a/impls/repo.json b/impls/repo.json new file mode 100644 index 0000000..8ba9552 --- /dev/null +++ b/impls/repo.json @@ -0,0 +1,167 @@ +{ + "normal": { + "direct_match": { + "3asq": "^https?://www\\.3asq\\.org/[^/]+/[0-9.]+", + "930mh": "http://www\\.930mh\\.com/manhua/\\d+/\\d+.html", + "abandonedkittenscans": "^https?://abandonedkittenscans\\.mokkori\\.fr/reader/read/.+", + "biamamscans.com": "^https?://biamamscans\\.com/read/.+", + "br.mangahost.com": "^http(s)?://br.mangahost.com/manga/[^/]+/.+", + "cafeconirst": "^https?://reader\\.cafeconirst\\.com/read/.+", + "cartoonmad": "https?://(www\\.)?(cartoonmad|comicnad)\\.com/comic/[0-9]+\\.html", + "casanovascans": "^https?://casanovascans\\.com/read/.+", + "championscans": "^https?://reader\\.championscans\\.com/read/.+", + "chuixue": "^https?://www.chuixue.com/manhua/[0-9]+/[0-9]+.html", + "comicastle": "^https?://comicastle\\.org/read-.+", + "demonicscans": "^https?://www\\.demonicscans\\.com/FoOlSlide/read/.+", + "dm5": "^https?://[^\\.]*\\.dm5\\.com/m[0-9]*", + "dmzj": "^https?://www.dmzj.com/view/[^/]+/.+\\.html", + "eatmanga": "^https?://eatmanga.com/Manga-Scan/[^/]+/.+", + "egscans": "^https?://read.egscans.com/.+", + "evilflowers": "^https?://reader\\.evilflowers\\.com/read/.+", + "famatg": "^https?://manga\\.famatg\\.com/read/.+", + "friendshipscans": "^https?://www\\.friendshipscans\\.com/slide/read/.+", + "gmanga": "^https?://gmanga.me/mangas/", + "gomanga": "^https?://gomanga\\.co/reader/read/.+", + "hatigarmscans": "^https?://hatigarmscans\\.eu/hs/read/.+", + "hellocomic": "https?://hellocomic.com/[^/]+/[^/]+/p[0-9]+", + "helveticascans": "^https?://helveticascans\\.com/r/read/.+", + "hotchocolatescans": "^https?://hotchocolatescans\\.com/fs/read/.+", + "hqbr": "^https?://hqbr.com.br/hqs/[^/]+/capitulo/[0-9]+/leitor/0", + "ikanman": "https?://(www|tw)\\.(ikanman|manhuagui)\\.com/comic/[0-9]+/[0-9]+\\.html", + "imperialscans": "^https?://imperialscans.com/read/.+", + "inpowerz": "^https?://manga\\.inpowerz\\.com/read/.+", + "jaiminisbox": "^https?://jaiminisbox\\.com/reader/read/.+", + "japscan": "^https?://www\\.japscan\\.com/lecture-en-ligne/[^/]*/[0-9]*", + "kawaii": "^https://kawaii.ca/reader/.+", + "kirishimafansub": "^https?://lector\\.kirishimafansub\\.com/lector/read/.+", + "kobato.hologfx": "^https?://kobato\\.hologfx\\.com/reader/read/.+", + "komikstation": "^https?://www\\.komikstation\\.com/.+/.+/.+", + "kukudm": "^https?://(www|comic|comic2|comic3).kukudm.com/comiclist/[0-9]+/[0-9]+/[0-9]+.htm", + "lhtranslation": "^https?://read.lhtranslation\\.com/read-.+", + "lonemanga": "^https?://lonemanga.com/manga/[^/]+/[^/]+", + "madokami": "^https?://manga\\.madokami\\.al/reader/.+", + "manga-ar": "^https?://(www\\.)?manga-ar\\.net/manga/.+/.+/.+", + "manga-download": "^https?://reader\\.manga-download\\.org/read/.+", + "manga-joy": "^https?://manga-joy.com/[^/]*/[0-9]*", + "manga.ae": "https?://www.manga.ae/[^/]+/[^/]+/", + "mangachapter": "^https?://www\\.mangachapter\\.me/[^/]+/[^/]+/[^/]+.html", + "mangadex.org": "^https?://mangadex\\.org/chapter/[0-9]+/[0-9]+", + "mangaeden": "^https?://(www\\.)?mangaeden\\.com/(en|it)/(en|it)-manga/.+", + "mangaforall": "https?://mangaforall.com/manga/[^/]+/[^/]+/", + "mangago": "^https?://(www.)?mangago.me/read-manga/[^/]+/[^/]+/[^/]+", + "mangahome": "https?://www\\.mangahome\\.com/manga/.+/.+", + "mangaichiscans": "^https?://mangaichiscans\\.mokkori\\.fr/fs/read/.+", + "mangainn": "^https?://www.mangainn.net/manga/chapter/.+", + "mangalator": "^https?://mangalator.ch/show.php\\?gallery=[0-9]+", + "mangasail": "https?://www\\.mangasail\\.com/[^/]+", + "mangatail": "https?://www\\.mangatail\\.com/[^/]+", + "mangatopia": "^https?://mangatopia\\.net/slide/read/.+", + "mangatraders": "^https?://mangatraders\\.biz/read-online/.+", + "moonbunnycafe": "^https?://moonbunnycafe\\.com/[^/]+/[0-9.]+", + "mymh8": "^https?://(www\\.)?mymh8\\.com/chapter/.+", + "necron99scans": "^https?://necron99scans\\.com/reader/read/.+", + "otakusmash": "https?://www\\.otakusmash\\.com/(read-comics|read-manga)/.+", + "otscans": "^https?://otscans\\.com/foolslide/read/.+", + "pecintakomik": "^https?://www\\.pecintakomik\\.com/manga/[^/]*/[^/]*", + "readcomics": "https?://(www\\.)?readcomics\\.tv/.+/chapter-[0-9]+(/[0-9]+|$)", + "readmng.com": "^https?://www\\.readmng\\.com/[^/]+/.+", + "redhawkscans": "^https?://manga\\.redhawkscans\\.com/reader/read/.+", + "roseliascans": "^https?://reader\\.roseliascans\\.com/read/.+", + "senmanga": "^https?://[^\\.]+\\.senmanga\\.com/[^/]*/.+", + "sensescans": "^https?://sensescans\\.com/reader/read/.+", + "sh-arab": "^https?://www.sh-arab.com/manga/.+", + "shoujosense": "^https?://reader\\.shoujosense\\.com/read/.+", + "substitutescans": "^https?://substitutescans\\.com/reader/read/.+", + "thecatscans": "^https?://reader\\.thecatscans\\.com/read/.+", + "twistedhelscans": "^https?://www\\.twistedhelscans\\.com/read/.+", + "unionmangas": "https?://(www\\.)?unionmangas\\.net/leitor/.+", + "vortex-scans": "^https?://reader\\.vortex-scans\\.com/read/.+", + "whiteoutscans": "^https?://reader\\.whiteoutscans\\.com/read/.+", + "yonkouprod": "^https?://yonkouprod\\.com/reader/read/.+" + }, + "regex": { + "2comic.com \u52d5\u6f2b\u6613": "http://twocomic.com/view/comic_\\d+.html", + "anime-a": "^https?://manga\\.animea.net/.+chapter-[0-9]+(-page-[0-9]+)?.html", + "batoto": "^https?://bato.to/reader.*", + "central-de-mangas": "^https?://(centraldemangas\\.org|[^\\.]+\\.com\\.br/leitura)/online/[^/]*/[0-9]*", + "foolslide": "META", + "kiss-manga": "^https?://kissmanga\\.com/Manga/[^/]+/.+", + "manga-cat": "^https?://www.mangacat.me/[^/]+/[^/]+/[^\\.]+.html", + "manga-cow": "^https?://(manga|mng)cow\\.(co|id|info|com)/[^/]+/[0-9.]+", + "manga-here mobile": "^https?://m.mangahere.c[oc]/manga/[^/]+/[^/]+", + "manga-here": "^https?://www.mangahere.c[oc]/manga/[^/]+/[^/]+", + "manga-indo": "^https?://mangaindo\\.(co|id|info|com)/[^/]+/[0-9.]+", + "manga-kaka": "^https?://www\\.(mangahen|mangamap)\\.com/[^/]+/[0-9]+", + "manga-panda": "^https?://www.mangapanda.com/.*/[0-9]*", + "manga-park": "^https?://mangapark\\.me/manga/[^/]+/[^/]+/[^/]+", + "manga-reader": "^https?://www.mangareader.net/.*/.*", + "manga-stream": "^https?://(readms|mangastream).(net|com)/(r|read)/[^/]*/[^/]*", + "manga-town": "^https?://www.mangatown.com/manga/[^/]+/[^/]+", + "manga-wall": "^https?://mangawall\\.com/manga/[^/]*/[0-9]*", + "mangafox": "^https?://(fan|manga)fox.(me|la|net)/manga/[^/]*/[^/]*/[^/]*", + "manhua-dmzj": "^https?://manhua.dmzj.com/[^/]*/[0-9]+(-[0-9]+)?\\.shtml", + "read-comic-online": "^https?://readcomiconline\\.to/Comic/[^/]+/.+", + "spinybackmanga and titaniascans": "^https?://(spinybackmanga.com/\\?manga=[^&]+&chapter=.+|www\\.titaniascans\\.com/reader/.+/.+)", + "the-spectrum-scans": "^https?://view\\.thespectrum\\.net/series/[^\\.]+\\.html", + "\u6f2b\u756b\u738b": "https://www\\.mangabox\\.me/reader/\\d+/episodes/\\d+/" + }, + "mapto": { + "3asq": "manga-cow", + "abandonedkittenscans": "foolslide", + "cafeconirst": "foolslide", + "casanovascans": "foolslide", + "championscans": "foolslide", + "demonicscans": "foolslide", + "evilflowers": "foolslide", + "famatg": "foolslide", + "friendshipscans": "foolslide", + "gomanga": "foolslide", + "hatigarmscans": "foolslide", + "helveticascans": "foolslide", + "hotchocolatescans": "foolslide", + "inpowerz": "foolslide", + "jaiminisbox": "foolslide", + "kirishimafansub": "foolslide", + "kobato.hologfx": "foolslide", + "manga-ar": "foolslide", + "manga-download": "foolslide", + "manga-indo": "manga-cow", + "mangaichiscans": "foolslide", + "mangatail": "mangasail", + "mangatopia": "foolslide", + "moonbunnycafe": "manga-cow", + "necron99scans": "foolslide", + "otscans": "foolslide", + "redhawkscans": "foolslide", + "roseliascans": "foolslide", + "sensescans": "foolslide", + "shoujosense": "foolslide", + "substitutescans": "foolslide", + "thecatscans": "foolslide", + "twistedhelscans": "foolslide", + "vortex-scans": "foolslide", + "whiteoutscans": "foolslide", + "yonkouprod": "foolslide" + } + }, + "nsfw": { + "direct_match": { + "8muses": "^http(s)?://www.8muses.com/comix/picture/[^/]+/[^/]+/[^/]+/.+", + "fakku": "^http(s)?://www.fakku.net/.*/.*/read", + "hentaifr": "^https?://hentaifr\\.net/.+\\.php\\?id=[0-9]+", + "hitomi": "^http(s)?://hitomi.la/reader/[0-9]+.html", + "nhentai": "^https?://nhentai\\.net\\/g\\/[0-9]+/[0-9]+", + "nowshelf": "^https?://nowshelf.com/watch/[0-9]*", + "pururin": "https?://pururin\\.us/read/.+" + }, + "regex": { + "doujin-moe": "^https?://doujins\\.com/.+", + "ero-senmanga": "^https?://ero\\.senmanga\\.com/[^/]*/[^/]*/[0-9]*", + "geh-and-exh": "^https?://(e-hentai|exhentai).org/s/.*/.*", + "hentai-here": "^https?://(www\\.)?hentaihere.com/m/[^/]+/[0-9]+/[0-9]+", + "hentai-rules": "^https?://www\\.hentairules\\.net/galleries[0-9]*/picture\\.php.+", + "prism-blush": "^https?://prismblush.com/comic/.+" + }, + "mapto": {} + } +} \ No newline at end of file diff --git a/impls/sample/SAMPLE.js b/impls/sample/SAMPLE.js new file mode 100644 index 0000000..f8f197c --- /dev/null +++ b/impls/sample/SAMPLE.js @@ -0,0 +1,20 @@ +var impl_src = { + name: 'something' // name of the implementation + , match: "^https?://domain.com/.*" // the url to react to for manga loading + , img: '#image' // css selector to get the page's manga image + , next: '#next_page' // css selector to get the link to the next page + , numpages: '#page_select' // css selector to get the number of pages. elements like (select, span, etc) + , curpage: '#page_select' // css selector to get the current page. usually the same as numPages if it's a select element + , numchaps: '#chapters' // css selector to get the number of chapters in manga + , curchap: '#chapters' // css selector to get the number of the current chapter + , nextchap: '#next_chap' // css selector to get the link to the next chapter + , prevchap: '#prev_chap' // same as above except for previous + , wait: 3000 // how many ms to wait before auto loading (to wait for elements to load), or a css selector to keep trying until it returns an elem + , pages: function(next_url, current_page_number, callback, extract_function) { + // gets called requesting a certain page number (current_page_number) + // to continue loading execute callback with img to append as first parameter and next url as second parameter + // only really needs to be used on sites that have really unusual ways of loading images or depend on javascript + } + + //Any of the CSS selectors can be functions instead that return the desired value. +} \ No newline at end of file diff --git a/impls/version b/impls/version new file mode 100644 index 0000000..4e379d2 --- /dev/null +++ b/impls/version @@ -0,0 +1 @@ +0.0.2 diff --git a/manga-loader.user.js b/manga-loader.user.js index a5050ff..39c884e 100644 --- a/manga-loader.user.js +++ b/manga-loader.user.js @@ -1,5 +1,5 @@ // ==UserScript== -// @name Manga Loader +// @name Manga Loader ALL // @namespace https://github.com/fuzetsu/manga-loader // @version 1.11.29 // @description Support for over 70 sites! Loads manga chapter into one page in a long strip format, supports switching chapters, minimal script with no dependencies, easy to implement new sites, loads quickly and works on mobile devices through bookmarklet @@ -8,125 +8,9 @@ // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue -// @match *://bato.to/reader* -// @match *://mangafox.me/manga/*/*/* -// @match *://mangafox.la/manga/*/*/* -// @match *://fanfox.net/manga/*/*/* -// @match *://readms.net/r/*/* -// @match *://readms.net/read/*/* -// @match *://mangastream.com/r/*/*/*/* -// @match *://mangastream.com/read/*/*/*/* -// @match *://www.mangareader.net/*/* -// @match *://*.mangahere.co/manga/*/* -// @match *://*.mangahere.cc/manga/*/* -// @match *://www.mangapanda.com/*/* -// @match *://mangapark.me/manga/*/*/* -// @match *://mngcow.co/*/* -// @match *://centraldemangas.org/online/*/* -// @match *://*.com.br/leitura/online/capitulo/* -// @match *://www.mangatown.com/manga/*/* -// @match *://manga-joy.com/*/* -// @match *://*.dm5.com/m* -// @match *://*.senmanga.com/*/* -// @match *://www.japscan.com/lecture-en-ligne/* -// @match *://www.pecintakomik.com/manga/*/* -// @match *://mangawall.com/manga/*/* -// @match *://manga.animea.net/* -// @match *://kissmanga.com/Manga/*/* -// @match *://view.thespectrum.net/series/* -// @match *://manhua.dmzj.com/*/* -// @match *://hqbr.com.br/hqs/*/capitulo/*/leitor/0 -// @match *://www.dmzj.com/view/*/* -// @match *://mangaindo.id/*/* -// @match *://mangadoom.co/*/* -// @match *://*.mangago.me/read-manga/*/* -// @match *://mangalator.ch/show.php?gallery=* -// @match *://eatmanga.com/Manga-Scan/*/* -// @match *://www.mangacat.me/*/*/* -// @match *://www.mangahen.com/*/* -// @match *://www.readmng.com/*/* -// @match *://mangatraders.biz/read-online/* -// @match *://www.mangainn.net/manga/chapter/* -// @match *://*.kukudm.com/comiclist/*/* -// @match *://www.mangamap.com/*/* -// @match *://www.mangachapter.me/*/*/*.html -// @match *://kawaii.ca/reader/* -// @match *://lonemanga.com/manga/*/* -// @match *://read.egscans.com/om/manga/*/* -// @match *://manga.madokami.al/reader/* -// @match *://read.egscans.com/* -// @match *://imperialscans.com/read/* -// @match *://www.chuixue.com/manhua/*/* -// @match *://www.sh-arab.com/manga/* -// @match *://spinybackmanga.com/* -// @match *://br.mangahost.com/manga/*/* -// @match *://www.manga.ae/*/*/* -// @match *://mangaforall.com/manga/*/*/* -// @match *://hellocomic.com/*/*/* -// @match *://www.3asq.info/*/* -// @match *://*.readcomiconline.to/Comic/* -// @match *://*.moonbunnycafe.com/* -// @match *://*.mangaeden.com/* -// @match *://*.comicastle.org/read-* -// @match *://*.mymh8.com/chapter/* -// @match *://*.unionmangas.net/leitor/* -// @match *://*.otakusmash.com/*/* -// @match *://*.mangahome.com/manga/*/* -// @match *://*.readcomics.tv/*/chapter* -// @match *://*.cartoonmad.com/comic/* -// @match *://*.comicnad.com/comic/* -// @match *://*.ikanman.com/comic/*/* -// @match *://*.manhuagui.com/comic/*/* -// @match *://*.mangasail.com/* -// @match *://*.mangatail.com/* -// @match *://*.titaniascans.com/reader/*/* -// @match *://*.komikstation.com/*/*/* -// @match *://*.gmanga.me/mangas/*/*/* -// @match *://mangadex.org/chapter/* -// @match *://merakiscans.com/*/* -// @match *://biamamscans.com/read/* -// @match *://read.lhtranslation.com/*.html -// @match *://www.930mh.com/manhua/*/*.html* -// @match *://www.mangabox.me/reader/*/episodes/*/ -// @match *://twocomic.com/view/comic_*.html?ch=* -// -- FOOLSLIDE START -// @match *://manga.redhawkscans.com/reader/read/* -// @match *://reader.s2smanga.com/read/* -// @match *://casanovascans.com/read/* -// @match *://reader.vortex-scans.com/read/* -// @match *://reader.roseliascans.com/read/* -// @match *://mangatopia.net/slide/read/* -// @match *://www.twistedhelscans.com/read/* -// @match *://sensescans.com/reader/read/* -// @match *://reader.kireicake.com/read/* -// @match *://substitutescans.com/reader/read/* -// @match *://mangaichiscans.mokkori.fr/fs/read/* -// @match *://reader.shoujosense.com/read/* -// @match *://www.friendshipscans.com/slide/read/* -// @match *://manga.famatg.com/read/* -// @match *://www.demonicscans.com/FoOlSlide/read/* -// @match *://reader.psscans.info/read/* -// @match *://otscans.com/foolslide/read/* -// @match *://necron99scans.com/reader/read/* -// @match *://manga.inpowerz.com/read/* -// @match *://reader.evilflowers.com/read/* -// @match *://reader.cafeconirst.com/read/* -// @match *://kobato.hologfx.com/reader/read/* -// @match *://abandonedkittenscans.mokkori.fr/reader/read/* -// @match *://jaiminisbox.com/reader/read/* -// @match *://*.gomanga.co/reader/read/* -// @match *://reader.manga-download.org/read/*/* -// @match *://*.manga-ar.net/manga/*/*/* -// @match *://*.helveticascans.com/r/read/* -// @match *://reader.thecatscans.com/read/* -// @match *://yonkouprod.com/reader/read/* -// @match *://reader.championscans.com/read/* -// @match *://reader.whiteoutscans.com/read/* -// @match *://hatigarmscans.eu/hs/read/* -// @match *://lector.kirishimafansub.com/lector/read/* -// @match *://hotchocolatescans.com/fs/read/* -// @match *://*.slide.world-three.org/read/* -// -- FOOLSLIDE END +// @grant GM_listValues +// @connect * +// @match *://*/* // ==/UserScript== // short reference to unsafeWindow (or window if unsafeWindow is unavailable e.g. bookmarklet) @@ -149,1280 +33,19 @@ var reuse = { } }; -/** -Sample Implementation: -{ - name: 'something' // name of the implementation - , match: "^https?://domain.com/.*" // the url to react to for manga loading - , img: '#image' // css selector to get the page's manga image - , next: '#next_page' // css selector to get the link to the next page - , numpages: '#page_select' // css selector to get the number of pages. elements like (select, span, etc) - , curpage: '#page_select' // css selector to get the current page. usually the same as numPages if it's a select element - , numchaps: '#chapters' // css selector to get the number of chapters in manga - , curchap: '#chapters' // css selector to get the number of the current chapter - , nextchap: '#next_chap' // css selector to get the link to the next chapter - , prevchap: '#prev_chap' // same as above except for previous - , wait: 3000 // how many ms to wait before auto loading (to wait for elements to load), or a css selector to keep trying until it returns an elem - , pages: function(next_url, current_page_number, callback, extract_function) { - // gets called requesting a certain page number (current_page_number) - // to continue loading execute callback with img to append as first parameter and next url as second parameter - // only really needs to be used on sites that have really unusual ways of loading images or depend on javascript - } - - Any of the CSS selectors can be functions instead that return the desired value. -} -*/ - -var implementations = [{ - name: 'batoto', - match: "^https?://bato.to/reader.*", - img: function(ctx) { - var img = getEl('#comic_page', ctx); - if(img) { - return img.src; - } else { - var imgs = getEls('#content > div:nth-child(8) > img', ctx).map(function(page) { - return page.src; - }); - if(imgs.length > 0) { - this.next = function() { return imgs[0]; }; - this.numpages = function() { return imgs.length; }; - this.pages = function(url, num, cb, ex) { - cb(imgs[num - 1], num); - }; - return imgs[0]; - } - } - }, - next: function() { - if(!this._numpage) { - this._numpage = extractInfo(this.curpage, {type: 'index'}); - this._id = location.hash.split('_')[0].slice(1); - } - return '/areader?id=' + this._id + '&p=' + (++this._numpage); - }, - numpages: '#page_select', - curpage: '#page_select', - curchap: 'select[name=chapter_select]', - numchaps: 'select[name=chapter_select]', - nextchap: function(prev) { - //var link = extractInfo('select[name=chapter_select]', {type: 'value', val: prev ? 1 : -1}); - //return link && link.replace(/https?/, document.location.href.split(':')[0]); // fix for batotos broken https pages - var menu = getEls('div.moderation_bar > ul > li', getEl('#reader')); - for (var i = 0; i != menu.length; i += 1) { - var img = getEl('img', menu[i]); - if (img && img.title == (prev ? "Previous Chapter" : "Next Chapter")) { - return img.parentNode.href.replace(/https?/, document.location.href.split(':')[0]); - } - } - return null; - }, - prevchap: function() { - return this.nextchap(true); - }, - wait: '#comic_page' -}, { - name: 'manga-panda', - match: "^https?://www.mangapanda.com/.*/[0-9]*", - img: '#img', - next: '.next a', - numpages: '#pageMenu', - curpage: '#pageMenu', - nextchap: '#mangainfofooter > #mangainfo_bas table tr:first-child a', - prevchap: '#mangainfofooter > #mangainfo_bas table tr:last-child a' -}, { - name: 'mangafox', - match: "^https?://(fan|manga)fox.(me|la|net)/manga/[^/]*/[^/]*/[^/]*", - img: '.reader-main img', - next: '.pager-list-left > span > a:last-child', - numpages: function() { return W.imagecount; }, - curpage: function () { return W.imagepage; }, - nextchap: '.pager-list-left > a:last-child', - prevchap: '.pager-list-left > a:first-child', - imgURLs: [], - pages: function(url, num, cb, ex) { - var imp = this; - if (this.imgURLs[num]) - cb(this.imgURLs[num], num); - else - ajax({ - url: 'chapterfun.ashx?cid=' + W.chapterid + '&page=' + num, - onload: function(e) { - eval(e.target.responseText); - for (var i = 0; i < d.length; i++) { - imp.imgURLs[num + i] = d[i]; - } - cb(d[0], num); - } - }); - }, - wait: function () { - el = getEl('.reader-main img'); - - return el && el.getAttribute('src') != el.getAttribute('data-loading-img'); - } -}, { - name: 'manga-stream', - match: "^https?://(readms|mangastream).(net|com)/(r|read)/[^/]*/[^/]*", - img: '#manga-page', - next: '.next a', - numpages: function() { - var lastPage = getEl('.subnav-wrapper .controls .btn-group:last-child ul li:last-child'); - return parseInt(lastPage.textContent.match(/[0-9]/g).join(''), 10); - }, - nextchap: function(prev) { - var found; - var chapters = [].slice.call(document.querySelectorAll('.controls > div:first-child > .dropdown-menu > li a')); - chapters.pop(); - for (var i = 0; i < chapters.length; i++) { - if (window.location.href.indexOf(chapters[i].href) !== -1) { - found = chapters[i + (prev ? 1 : -1)]; - if (found) return found.href; - } +var exUtil = { + clearAllTimeouts: function() { + var id = window.setTimeout(function() {}, 0); + while (id--) { + window.clearTimeout(id); } - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'manga-reader', - match: "^https?://www.mangareader.net/.*/.*", - img: '#img', - next: '.next a', - numpages: '#pageMenu', - curpage: '#pageMenu', - nextchap: '#chapterMenu', - prevchap: '#chapterMenu', - wait: '#chapterMenu option' -}, { - name: 'manga-town', - match: "^https?://www.mangatown.com/manga/[^/]+/[^/]+", - img: '#image', - next: '#viewer a', - numpages: '.page_select select', - curpage: '.page_select select', - nextchap: '#top_chapter_list', - prevchap: '#top_chapter_list', - wait: 1000 -}, { - name: 'manga-cow, manga-doom, manga-indo, 3asq.info, moonbunnnycafe', - match: "^https?://(mngcow|mangadoom|mangaindo|merakiscans|www\\.3asq|moonbunnycafe)\\.(co|id|info|com)/[^/]+/[0-9.]+", - img: '.prw a > img', - next: '.prw a', - numpages: 'select.cbo_wpm_pag', - curpage: 'select.cbo_wpm_pag', - nextchap: function(prev) { - var next = extractInfo('select.cbo_wpm_chp', {type: 'value', val: (prev ? 1 : -1)}); - if(next) return window.location.href.replace(/\/[0-9.]+\/?([0-9]+\/?)?[^/]*$/, '/' + next); - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'manga-here', - match: "^https?://www.mangahere.c[oc]/manga/[^/]+/[^/]+", - img: '#viewer img:last-child', - next: '#viewer a', - numpages: 'select.wid60', - curpage: 'select.wid60', - numchaps: '#top_chapter_list', - curchap: '#top_chapter_list', - nextchap: function(prev) { - var chapter = W.chapter_list[W.current_chapter_index + (prev ? -1 : 1)]; - return chapter && chapter[1]; - }, - prevchap: function() { - return this.nextchap(true); - }, - wait: function() { - return areDefined(W.current_chapter_index, W.chapter_list, getEl('#top_chapter_list')); - } -}, { - name: 'manga-here mobile', - match: "^https?://m.mangahere.c[oc]/manga/[^/]+/[^/]+", - img: '#image', - next: '#viewer a', - numpages: '.mangaread-page', - curpage: '.mangaread-page' -}, { - name: 'manga-park', - match: "^https?://mangapark\\.me/manga/[^/]+/[^/]+/[^/]+", - img: '.img-link > img', - next: '.page > span:last-child > a', - numpages: function() { - if(W.sel_load && W.sel_load.options[W.sel_load.selectedIndex].value) { - return extractInfo('#sel_page_1'); - } else { - var links = getEls('.img-link > img').map(function(img) { return img.src; }); - this.pages = function(url, num, cb, ex) { - cb(links[num - 1], num); - }; - return links.length; - } - }, - curpage: '#sel_page_1', - nextchap: function(prev) { - var next = extractInfo('#sel_book_1', {type: 'value', val: (prev ? -1 : 1)}); - if(next) return window.location.href.replace(/(\/manga\/[^\/]+).+$/, '$1' + next + '/1'); - }, - prevchap: function() { - return this.nextchap(true); - }, - wait: '#sel_book_1 option' -}, { - name: 'central-de-mangas', - match: "^https?://(centraldemangas\\.org|[^\\.]+\\.com\\.br/leitura)/online/[^/]*/[0-9]*", - img: '#manga-page', - next: '#manga-page', - numpages: '#manga_pages', - curpage: '#manga_pages', - nextchap: function(prev) { - var next = extractInfo('#manga_caps', {type: 'value', val: (prev ? -1 : 1)}); - if(next) return window.location.href.replace(/[^\/]+$/, next); - }, - prevchap: function() { - return this.nextchap(true); - }, - pages: function(url, num, cb, ex) { - url = url.slice(0, url.lastIndexOf('-') + 1) + ("0" + num).slice(-2) + url.slice(url.lastIndexOf('.')); - cb(url, url); - } -}, { - name: 'manga-joy', - match: "^https?://manga-joy.com/[^/]*/[0-9]*", - img: '.prw img', - next: '.nxt', - numpages: '.wpm_nav_rdr li:nth-child(3) > select', - curpage: '.wpm_nav_rdr li:nth-child(3) > select', - nextchap: function(prev) { - var next = extractInfo('.wpm_nav_rdr li:nth-child(2) > select', {type: 'value', val: prev ? 1 : -1}); - if(next) return window.location.href.replace(/\/[0-9.]+\/?([0-9]+(\/.*)?)?$/, '/' + next); - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'dm5', - match: "^https?://[^\\.]*\\.dm5\\.com/m[0-9]*", - img: function (){ - return getEl('img.load-src').getAttribute('data-src'); - }, - next: function(){ - return '#'; - }, - numpages: function () { - return W.pages.length; - }, - pages: function(url, num, cb, ex) { - cb(W.pages[num - 1].getAttribute('data-src'), num - 1); - }, - nextchap: 'a.logo_2', - prevchap: 'a.logo_1', - wait: function (){ - W.pages = getEls('img.load-src'); - return true; - } -}, { - name: 'senmanga', - match: "^https?://[^\\.]+\\.senmanga\\.com/[^/]*/.+", - img: '#picture', - next: '#reader > a', - numpages: 'select[name=page]', - curpage: 'select[name=page]', - numchaps: 'select[name=chapter]', - curchap: 'select[name=chapter]', - nextchap: function(prev) { - var next = extractInfo('select[name=chapter]', {type: 'value', val: (prev ? 1 : -1)}); - if(next) { - var manga = window.location.pathname.slice(1).split('/')[0]; - return window.location.origin + '/' + manga + '/' + next + '/1'; - } - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'japscan', - match: "^https?://www\\.japscan\\.com/lecture-en-ligne/[^/]*/[0-9]*", - img: '#image', - next: '#img_link', - numpages: '#pages', - curpage: '#pages', - nextchap: '#next_chapter', - prevchap: '#back_chapter' -}, { - name: 'pecintakomik', - match: "^https?://www\\.pecintakomik\\.com/manga/[^/]*/[^/]*", - img: '.picture', - next: '.pager a:nth-child(3)', - numpages: 'select[name=page]', - curpage: 'select[name=page]', - nextchap: function(prev) { - var next = extractInfo('select[name=chapter]', {type: 'value', val: (prev ? 1 : -1)}); - if(next) return window.location.href.replace(/\/([^\/]+)\/[0-9]+\/?$/, '/$1/' + next); - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'manga-kaka', - match: "^https?://www\\.(mangahen|mangamap)\\.com/[^/]+/[0-9]+", - img: 'img.manga-page', - next: '.nav_pag > li:nth-child(1) > a', - numpages: 'select.cbo_wpm_pag', - curpage: 'select.cbo_wpm_pag', - nextchap: function(prev) { - var chapter = extractInfo('select.cbo_wpm_chp', { type: 'value', val: (prev ? 1 : -1) }); - if(chapter) return window.location.href.replace(/\/[0-9\.]+\/?([0-9]+\/?)?$/, '/' + chapter); - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'manga-wall', - _page: null, - match: "^https?://mangawall\\.com/manga/[^/]*/[0-9]*", - img: 'img.scan', - next: function() { - if(this._page === null) this._page = W.page; - return W.series_url + '/' + W.chapter + '/' + (this._page += 1); - }, - numpages: '.pageselect', - curpage: '.pageselect', - nextchap: function(prev) { - return W.series_url + '/' + (parseInt(W.chapter.slice(1)) + (prev ? -1 : 1)) + '/1'; - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'anime-a', - _page: null, - match: "^https?://manga\\.animea.net/.+chapter-[0-9]+(-page-[0-9]+)?.html", - img: '#scanmr', - next: function() { - if(this._page === null) this._page = W.page; - return W.series_url + W.chapter + '-page-' + (this._page += 1) + '.html'; - }, - numpages: '.pageselect', - curpage: '.pageselect', - nextchap: function(prev) { - return W.series_url + 'chapter-' + (parseInt(W.chapter.match(/[0-9]+/)[0]) + (prev ? -1 : 1)) + '-page-1.html'; - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'kiss-manga', - match: "^https?://kissmanga\\.com/Manga/[^/]+/.+", - img: '#divImage img', - next: '#divImage img', - numpages: function() { - return (W.lstOLA || W.lstImages).length; - }, - curpage: function() { - if(getEls('#divImage img').length > 1) { - return 1; - } else { - return W.currImage + 1; - } - }, - nextchap: '#selectChapter, .selectChapter', - prevchap: '#selectChapter, .selectChapter', - pages: function(url, num, cb, ex) { - cb((W.lstOLA || W.lstImages)[num - 1], num); - } -}, { - name: 'the-spectrum-scans', - match: "^https?://view\\.thespectrum\\.net/series/[^\\.]+\\.html", - img: '#mainimage', - next: function() { - if (++this._page < this._pages.length) { - return this._pages[this._page]; - } - }, - numpages: '.selectpage', - curpage: '.selectpage', - nextchap: function(prev) { - var ps = document.pageSelector1; - var chnum = ps.ch.selectedIndex + (prev ? -1 : 1); - if (chnum < ps.ch.length && chnum > -1) { - return ps.action.split('?')[0] + '?ch=' + ps.ch[chnum].value + '&page=1'; - } else { - return false; - } - }, - prevchap: function() { - return this.nextchap(true); - }, - wait: function() { - var ps = document.pageSelector1; - this._pages = []; - var base = ps.action.split('?')[0]; - for (var i = 0; i < ps.page.length; i++) { - this._pages.push(base + '?ch=' + ps.ch.value + '&page=' + ps.page[i].value); - } - this._page = ps.page[ps.page.selectedIndex].value - 1; - return true; - } -}, { - name: 'manhua-dmzj', - match: "^https?://manhua.dmzj.com/[^/]*/[0-9]+(-[0-9]+)?\\.shtml", - img: '#center_box > img', - next: '#center_box > img', - numpages: function() { - return W.arr_pages.length; - }, - curpage: function() { - var match = location.href.match(/page=([0-9]+)/); - return match ? parseInt(match[1]) : 1; - }, - nextchap: '#next_chapter', - prevchap: '#prev_chapter', - pages: function(url, num, cb, ex) { - cb(W.img_prefix + W.arr_pages[num - 1], num); - }, - wait: '#center_box > img' -}, { - name: 'hqbr', - match: "^https?://hqbr.com.br/hqs/[^/]+/capitulo/[0-9]+/leitor/0", - img: '#hq-page', - next: '#hq-page', - numpages: function() { - return W.pages.length; - }, - curpage: function() { - return W.paginaAtual + 1; - }, - nextchap: function(prev) { - var chapters = getEls('#chapter-dropdown a'), - current = parseInt(W.capituloIndex), - chapter = chapters[current + (prev ? -1 : 1)]; - return chapter && chapter.href; - }, - prevchap: function() { - return this.nextchap(true); - }, - pages: function(url, num, cb, ex) { - cb(W.pages[num - 1], num); } -}, { - name: 'dmzj', - match: "^https?://www.dmzj.com/view/[^/]+/.+\\.html", - img: '.comic_wraCon > img', - next: '.comic_wraCon > img', - numpages: function() { - return parseInt(W.pic_total); - }, - curpage: function() { - var match = location.href.match(/page=([0-9])/); - return match ? parseInt(match[1]) : 1; - }, - nextchap: '.next > a', - prevchap: '.pre > a', - pages: function(url, num, cb, ex) { - cb(W.img_prefix + W.picArry[num - 1], num); - }, - wait: '.comic_wraCon > img' -}, { - name: 'mangago', - match: "^https?://(www.)?mangago.me/read-manga/[^/]+/[^/]+/[^/]+", - img: '#page1', - next: '#pic_container', - numpages: '#dropdown-menu-page', - curpage: function() { - return parseInt(getEls('#page-mainer a.btn.dropdown-toggle')[1].textContent.match(/[0-9]+/)[0]); - }, - nextchap: function(prev) { - var chapters = getEls('ul.dropdown-menu.chapter a'), - curName = getEls('#page-mainer a.btn.dropdown-toggle')[0].textContent, - curIdx; - chapters.some(function(chap, idx) { - if(chap.textContent.indexOf(curName) === 0) { - curIdx = idx; - return true; - } - }); - var chapter = chapters[curIdx + (prev ? 1 : -1)]; - return chapter && chapter.href; - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'mangalator', - match: "^https?://mangalator.ch/show.php\\?gallery=[0-9]+", - img: '.image img', - next: '#next', - numpages: 'select[name=image]', - curpage: 'select[name=image]', - nextchap: function(prev) { - var next = extractInfo('select[name=gallery]', {type: 'value', val: (prev ? 1 : -1)}); - if(next) return location.href.replace(/\?gallery=[0-9]+/, '?gallery=' + next); - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'eatmanga', - match: "^https?://eatmanga.com/Manga-Scan/[^/]+/.+", - img: '#eatmanga_image, #eatmanga_image_big', - next: '#page_next', - numpages: '#pages', - curpage: '#pages', - nextchap: '#bottom_chapter_list', - prevchap: '#bottom_chapter_list', - invchap: true -}, { - name: 'manga-cat', - match: "^https?://www.mangacat.me/[^/]+/[^/]+/[^\\.]+.html", - img: '.img', - next: '.img-link', - numpages: '#page', - curpage: '#page', - nextchap: '#chapter', - prevchap: '#chapter', - invchap: true, - wait: '#chapter option' -}, { - name: 'readmng.com', - match: "^https?://www\\.readmng\\.com/[^/]+/.+", - img: '.page_chapter-2 img', - next: '.list-switcher-2 > li:nth-child(3) > a, .list-switcher-2 > li:nth-child(2) > a', - numpages: '.list-switcher-2 select[name=category_type]', - curpage: '.list-switcher-2 select[name=category_type]', - nextchap: '.jump-menu[name=chapter_list]', - prevchap: '.jump-menu[name=chapter_list]', - invchap: true -}, { - name: 'mangadex.org', - match: "^https?://mangadex\\.org/chapter/[0-9]+/[0-9]+", - img: '#current_page', - next: function() { - return this._base + ++this._page; - }, - numpages: '#jump_page', - curpage: '#jump_page', - nextchap: function() { - var chapter = document.querySelector('#jump_chapter').selectedOptions[0].previousElementSibling; - return (chapter === null) ? false : (this._base.replace(/[0-9]+\/$/, chapter.value)); - }, - prevchap: function() { - var chapter = document.querySelector('#jump_chapter').selectedOptions[0].nextElementSibling; - return (chapter === null) ? false : (this._base.replace(/[0-9]+\/$/, chapter.value)); - }, +}; - wait: function() { - var loc = document.location.toString(); - var num = loc.match(/[0-9]+$/); - this._base = loc.slice(0, -num.length); - this._page = parseInt(num); - return true; - } -}, { - name: 'biamamscans.com', - match: "^https?://biamamscans\\.com/read/.+", //nextchap and prevchap broken - img: '.manga-image', - next: 'span.float-right:nth-child(2) > div:nth-child(2) > a:nth-child(1)', - numpages: '#page-select', - curpage: '#page-select', - nextchap: '#chapter-select', - prevchap: '#chapter-select' -}, { - name: 'lhtranslation', - match: "^https?://read.lhtranslation\\.com/read-.+", - img: 'img.chapter-img', - next: '.chapter-content > select + a.label', - numpages: '.chapter-content > select', - curpage: '.chapter-content > select', - numchaps: '.form-control', - curchap: '.form-control', - nextchap: '.form-control', - prevchap: '.form-control', - invchap: true -}, { - name: 'foolslide', - match: "^https?://(" + [ - "manga.redhawkscans.com/reader/read/.+", - "reader.s2smanga.com/read/.+", - "casanovascans.com/read/.+", - "reader.vortex-scans.com/read/.+", - "reader.roseliascans.com/read/.+", - "mangatopia.net/slide/read/.+", - "www.twistedhelscans.com/read/.+", - "sensescans.com/reader/read/.+", - "reader.kireicake.com/read/.+", - "substitutescans.com/reader/read/.+", - "mangaichiscans.mokkori.fr/fs/read/.+", - "reader.shoujosense.com/read/.+", - "www.friendshipscans.com/slide/read/.+", - "manga.famatg.com/read/.+", - "www.demonicscans.com/FoOlSlide/read/.+", - "necron99scans.com/reader/read/.+", - "www.demonicscans.com/FoOlSlide/read/.+", - "reader.psscans.info/read/.+", - "otscans.com/foolslide/read/.+", - "necron99scans.com/reader/read/.+", - "manga.inpowerz.com/read/.+", - "reader.evilflowers.com/read/.+", - "reader.cafeconirst.com/read/.+", - "kobato.hologfx.com/reader/read/.+", - "jaiminisbox.com/reader/read/.+", - "abandonedkittenscans.mokkori.fr/reader/read/.+", - "gomanga.co/reader/read/.+", - "reader\.manga-download\.org/read/.+", - "(www\.)?manga-ar\.net/manga/.+/.+/.+", - "helveticascans.com/r/read/.+", - "reader.thecatscans.com/read/.+", - "yonkouprod.com/reader/read/.+", - "reader.championscans.com/read/.+", - "reader.whiteoutscans.com/read/.+", - "hatigarmscans.eu/hs/read/.+", - "lector.kirishimafansub.com/lector/read/.+", - "hotchocolatescans.com/fs/read/.+", - "www.slide.world-three.org/read/.+", - ].join('|') + ")", - img: function() { - return W.pages[W.current_page].url; - }, - next: function() { - return 'N/A'; - }, - numpages: function() { - return W.pages.length; - }, - curpage: function() { - return W.current_page + 1; - }, - nextchap: function(prev) { - var desired; - var dropdown = getEls('ul.dropdown')[1] || getEls('ul.uk-nav')[1] || getEls('ul.dropdown-menu')[3]; - if(!dropdown) return; - getEls('a', dropdown).forEach(function(chap, idx, arr) { - if(location.href.indexOf(chap.href) === 0) desired = arr[idx + (prev ? 1 : -1)]; - }); - return desired && desired.href; - }, - prevchap: function() { - return this.nextchap(true); - }, - pages: function(url, num, cb, ex) { - cb(W.pages[num - 1].url, num); - }, - wait: function() { - if(W.location.href.indexOf('gomanga.co') !== -1) { - var match = document.body.innerHTML.match(/(\w+)\[id\]\.url/); - W.pages = match && match[1] && W[match[1]]; - } - return W.pages; - } -}, { - name: 'mangatraders', - match: "^https?://mangatraders\\.biz/read-online/.+", - img: 'img.CurImage', - next: '.image-container a', - numpages: '.PageSelect', - curpage: '.PageSelect', - nextchap: function(prev) { - var next = extractInfo('.ChapterSelect', {type:'text', val: (prev ? -1 : 1)}); - if(next) { - var chapter = next.match(/[0-9.]+/)[0]; - return location.href.replace(/chapter-[0-9.]+/, 'chapter-' + chapter).replace(/page-[0-9]+/, 'page-1'); - } - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'mangainn', - match: "^https?://www.mangainn.net/manga/chapter/.+", - img: '#imgPage', - next: function() { - if(!this._count) this._count = extractInfo(this.curpage, {type: 'value'}); - var url = location.href; - if(!/page_[0-9]+/.test(url)) url += '/page_1'; - return url.replace(/page_[0-9]+/, 'page_' + (++this._count)); - }, - numpages: '#cmbpages', - curpage: '#cmbpages', - nextchap: function(prev) { - var next = extractInfo('#chapters', {type:'value', val: (prev ? -1 : 1)}); - if(next) return location.href.replace(/\/chapter\/.+$/, '/chapter/' + next + '/page_1'); - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'kukudm', - match: "^https?://(www|comic|comic2|comic3).kukudm.com/comiclist/[0-9]+/[0-9]+/[0-9]+.htm", - img: function(ctx) { - var script = getEl('td > script[language=javascript]', ctx); - if(script) { - return 'http://n.kukudm.com/' + script.textContent.match(/\+"([^']+)/)[1]; - } - }, - next: function(ctx) { - var links = getEls('td > a', ctx); - return links[links.length - 1].getAttribute('href'); - }, - numpages: function(cur) { - return parseInt(document.body.textContent.match(/共([0-9]+)页/)[1]); - }, - curpage: function() { - return parseInt(document.body.textContent.match(/第([0-9]+)页/)[1]); - }, - beforexhr: reuse.encodeChinese -}, { - name: 'mangachapter', - match: "^https?://www\\.mangachapter\\.me/[^/]+/[^/]+/[^/]+.html", - img: '#mangaImg, #viewer > table > tbody > tr > td:nth-child(1) > a:nth-child(2) > img', - next: '.page-select + a.button-page', - numpages: '.page-select select', - curpage: '.page-select select', - invchap: true, - nextchap: '#top_chapter_list', - prevchap: '#top_chapter_list', - wait: '#top_chapter_list' -}, { - name: 'kawaii', - match: "^https://kawaii.ca/reader/.+", - img: '.picture', - next: 'select[name=page] + a', - numpages: 'select[name=page]', - curpage: 'select[name=page]', - nextchap: function(prev) { - var next = extractInfo('select[name=chapter]', {type:'value', val: (prev ? -1 : 1)}); - if(next) return location.href.replace(/\/reader\/([^/]+)(\/.+)?$/, '/reader/$1/' + next); - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'lonemanga', - match: "^https?://lonemanga.com/manga/[^/]+/[^/]+", - img: '#imageWrapper img', - next: '#imageWrapper a', - numpages: '.viewerPage', - curpage: '.viewerPage', - nextchap: function(prev) { - var next = extractInfo('.viewerChapter', {type:'value', val: (prev ? 1 : -1)}); - if(next) return location.href.replace(/\/manga\/([^/]+)\/.+$/, '/manga/$1/' + next); - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'madokami', - match: "^https?://manga\\.madokami\\.al/reader/.+", - img: 'img', - next: 'img', - curpage: function() { - return parseInt(query().index) + 1; - }, - numpages: function() { - if(!this._pages) { - this._pages = JSON.parse(getEl('#reader').dataset.files); - } - return this._pages.length; - }, - pages: function(url, num, cb, ex) { - url = url.replace(/file=.+$/, 'file=' + this._pages[num - 1]); - cb(url, url); - }, - wait: '#reader' -}, { - name: 'egscans', - match: '^https?://read.egscans.com/.+', - img: '#image_frame img', - next: '#image_frame img', - curpage: 'select[name=page]', - numpages: 'select[name=page]', - nextchap: function(prev) { - var data = getEl(this.curchap).getAttribute('onchange').match(/'[^']+'/g); - var next = extractInfo(this.curchap, { type: 'value', val: (prev ? -1 : 1) }); - if(next) return location.origin + '/' + data[0].slice(1, -1) + '/' + next; - }, - prevchap: function() { - return this.nextchap(true); - }, - curchap: 'select[name=chapter]', - numchaps: 'select[name=chapter]', - pages: function(url, num, cb, ex) { - cb('/' + W.img_url[num], num); - } -}, { - name: 'imperialscans', - match: '^https?://imperialscans.com/read/.+', - img: '#page-img', - next: '#page-url', - curpage: function() { - return extractInfo('#page-select', { type: 'index', val: -1 }); - }, - numpages: function() { - return extractInfo('#page-select') - 1; - }, - curchap: function() { - var options = getEls('#chapter-select option:not([disabled])'); - var chapter = 1; - options.some(function(value, index) { - if (location.pathname === value.value) { - chapter = options.length - index; - return true; - } - }); - return chapter; - }, - numchaps: function() { - return extractInfo('#chapter-select'); - }, - nextchap: '#page-control > li:nth-child(5) > a', - prevchap: '#page-control > li:nth-child(1) > a' -}, { - name: 'chuixue', - match: "^https?://www.chuixue.com/manhua/[0-9]+/[0-9]+.html", - img: '#qTcms_pic', - next: '#qTcms_pic', - curpage: '#qTcms_select_i', - numpages: '#qTcms_select_i', - pages: function(url, num, cb, ex) { - if(!this._pages) { - this._pages = W.qTcms_S_m_murl.split('$qingtiandy$'); - } - cb(this._pages[num - 1], num); - }, - nextchap: function() { - return W.qTcms_Pic_nextArr; - }, - wait: '#qTcms_pic' -}, { - name: 'sh-arab', - match: '^https?://www.sh-arab.com/manga/.+', - img: 'img.picture', - next: '#omv td > a', - curpage: 'select[name=page]', - numpages: 'select[name=page]', - curchap: 'select[name=chapter]', - numchaps: 'select[name=chapter]', - nextchap: function(prev) { - var next = extractInfo('select[name=chapter]', {type:'value', val: (prev ? -1 : 1)}); - if (next) return location.href.replace(/[^\/]+$/, next); - }, - prevchap: function() { - return this.nextchap(true); - } -}, { - name: 'br.mangahost.com', - match: "^http(s)?://br.mangahost.com/manga/[^/]+/.+", - img: 'img.open', - next: '.image-content > a', - curpage: '.viewerPage', - numpages: '.viewerPage' -}, { - name: 'spinybackmanga and titaniascans', - match: '^https?://(spinybackmanga.com/\\?manga=[^&]+&chapter=.+|www\.titaniascans\.com/reader/.+/.+)', - img: '#thePicLink img', - next: '#thePicLink', - curpage: function() { - return W.current; - }, - numpages: function() { - return getEl('#loadingbar tr').children.length; - }, - curchap: function() { - return parseInt(getEls('.selector')[1].firstChild.textContent.match(/[0-9]+/)[0]); - }, - numchaps: function() { - return getEls('.selector .options')[1].children.length; - }, - nextchap: function(prev) { - var nextChap = document.scripts[2].textContent.match(/location.href = "([^"]+)"/)[1]; - if(prev) { - [].some.call(getEls('.selector .options')[1].children, function(child, index, children) { - if(child.href === nextChap) { - nextChap = children[index - 2] && children[index - 2].href; - return true; - } - }); - } - return nextChap; - }, - prevchap: function() { - return this.nextchap(true); - }, - pages: function(url, num, cb, ex) { - var next = url.replace(/(?:(\/)2\/|[0-9]*)$/, '$1' + (num + 1)); - cb(W.imageArray[num - 1], next); - } -}, { - name: 'manga.ae', - match: "https?://www.manga.ae/[^/]+/[^/]+/", - img: '#showchaptercontainer img', - next: '#showchaptercontainer a', - curpage: 'a.chpage', - nextchap: '.chapter:last-child', - prevchap: '.chapter:first-child' -}, { - name: 'mangaforall', - match: "https?://mangaforall.com/manga/[^/]+/[^/]+/", - img: '#page > img', - next: '#page > img', - numpages: '#chapter > div:nth-child(1) > div > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-left.uk-text-center-small > div > div > div > ul', - curpage: '#chapter > div:nth-child(1) > div > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-left.uk-text-center-small > div > a.uk-button.uk-button-primary.number.uk-button-danger', - nextchap: '#chapter > div:nth-child(5) > div.uk-grid.uk-grid-collapse.uk-margin-top > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-left.uk-text-center-small > a', - prevchap: '#chapter > div:nth-child(5) > div.uk-grid.uk-grid-collapse.uk-margin-top > div.uk-width-large-1-3.uk-width-medium-1-3.uk-width-small-1-1.uk-text-right.uk-text-center-small > a', - pages: function(url, num, cb, ex) { - cb(W.pages[num - 1].url, num); - } -}, { - name: 'hellocomic', - match: "https?://hellocomic.com/[^/]+/[^/]+/p[0-9]+", - img: '.coverIssue img', - next: '.coverIssue a', - numpages: '#e1', - curpage: '#e1', - nextchap: '#e2', - prevchap: '#e2', - curchap: '#e2', - numchaps: '#e2' -}, { - name: 'read-comic-online', - match: "^https?://readcomiconline\\.to/Comic/[^/]+/.+", - img: '#divImage img', - next: '#divImage img', - numpages: function() { - return W.lstImages.length; - }, - curpage: function() { - return getEls('#divImage img').length > 1 ? 1 : W.currImage + 1; - }, - nextchap: '#selectEpisode, .selectEpisode', - prevchap: '#selectEpisode, .selectEpisode', - pages: function(url, num, cb, ex) { - cb(W.lstImages[num - 1], num); - } -}, { - name: 'mangaeden', - match: "^https?://(www\\.)?mangaeden\\.com/(en|it)/(en|it)-manga/.+", - img: '#mainImg', - next: '#nextA', - numpages: '#pageSelect', - curpage: '#pageSelect', - numchaps: '#combobox', - curchap: '#combobox', - invchap: true, - nextchap: function (prev) { - var cbox = getEl('#combobox'); - var opt = cbox[prev ? cbox.selectedIndex + 1 : cbox.selectedIndex - 1]; - var span = getEl('span.hideM0 a'); - return opt && span && span.href + parseInt(opt.value) + '/1/'; - }, - prevchap: function () { - return this.nextchap(true); - } -}, { - name: 'comicastle', - match: "^https?://comicastle\\.org/read-.+", - img: '.chapter-img', - next: '.chapter-content > select + a.label', - numpages: '.chapter-content > select', - curpage: '.chapter-content > select', - numchaps: '.form-control', - curchap: '.form-control', - nextchap: '.form-control', - prevchap: '.form-control', - invchap: true -}, { - name: 'mymh8', - match: "^https?://(www\\.)?mymh8\\.com/chapter/.+", - img: '#viewimg', - next: reuse.na, - numpages: function() { - return W.maxpages; - }, - curpage: '#J_showpage > span', - nextchap: function(prev) { - var button = prev ? getEl('div.m3p > input:first-of-type') : getEl('div.m3p > input:last-of-type'); - return button && button.attributes.onclick.value.match(/\.href='([^']+)'/)[1]; - }, - prevchap: function() { - return this.nextchap(true); - }, - pages: function(url, num, cb, ex) { - cb(W.WebimgServerURL[0] + W.imageslist[num], num); - }, - wait: function() { - return W.imageslist.length > 0; - } -}, { - name: 'unionmangas', - match: "https?://(www\\.)?unionmangas\\.net/leitor/.+", - img: '.slick-active img.real', - next: reuse.na, - numpages: '.selectPage', - curpage: '.selectPage', - numchaps: '#cap_manga1', - curchap: '#cap_manga1', - nextchap: '#cap_manga1', - prevchap: '#cap_manga1', - pages: function(url, num, cb, ex) { - cb(W.pages[num - 1], num); - }, - wait: function() { - W.pages = getEls('img.real').map(function(el) { - return el.src || el.dataset.lazy; - }); - return W.pages && W.pages.length > 0; - } -}, { - name: 'otakusmash', - match: "https?://www\\.otakusmash\\.com/(read-comics|read-manga)/.+", - img: 'img.picture', - next: 'select[name=page] + a', - curpage: 'select[name=page]', - numpages: 'select[name=page]', - nextchap: function(prev) { - var nextChap = extractInfo('select[name=chapter]', {type: 'value', val: prev ? 1 : -1}); - return nextChap ? location.href.replace(/(read-(comics|manga)\/[^\/]+).*/, '$1/' + nextChap) : null; - }, - prevchap: function() { - return this.nextchap(true); - }, - numchaps: 'select[name=chapter]', - curchap: 'select[name=chapter]', - invchap: true -}, { - name: 'mangahome', - match: "https?://www\\.mangahome\\.com/manga/.+/.+", - img: '#image', - next: '#viewer > a', - curpage: '.mangaread-page select', - numpages: '.mangaread-page select', - nextchap: function(prev) { - var buttons = getEls('.mangaread-footer .left > .btn-three'); - for (var i = 0; i < buttons.length; i++) { - if (buttons[i].textContent.indexOf(prev ? 'Prev Chapter' : 'Next Chapter') > - 1) { - return buttons[i].href; - } - } - }, - prevchap: function() { - return this.nextchap(true); - }, - wait: '#image' -}, { - name: 'readcomics', - match: "https?://(www\\.)?readcomics\\.tv/.+/chapter-[0-9]+(/[0-9]+|$)", - img: '#main_img', - next: '.nav.next', - curpage: 'select[name=page_select]', - numpages: 'select[name=page_select]', - nextchap: 'select[name=chapter_select]', - prevchap: 'select[name=chapter_select]', - curchap: 'select[name=chapter_select]', - numchaps: 'select[name=chapter_select]', - wait: 'select[name=page_select]' -}, { - name: 'cartoonmad', - match: "https?://(www\\.)?(cartoonmad|comicnad)\.com/comic/[0-9]+\.html", - img: 'tr:nth-child(5) > td > table > tbody > tr:nth-child(1) > td > a > img', - next: 'a.onpage+a', - curpage: 'a.onpage', - numpages: function() { - return extractInfo('select[name=jump]') - 1; - }, - nextchap: function() { - let filter = getEls('.pages').filter(function(i) { - return i.textContent.match('下一話'); - }); - return filter.length ? filter[0].href : null; - }, - prevchap: function() { - let filter = getEls('.pages').filter(function(i) { - return i.textContent.match('上一話'); - }); - return filter.length ? filter[0].href : null; - }, -}, { - name: 'ikanman', - match: "https?://(www|tw)\.(ikanman|manhuagui)\.com/comic/[0-9]+/[0-9]+\.html", - img: '#mangaFile', - next: function() { - return W._next; - }, - curpage: '#page', - numpages: '#pageSelect', - nextchap: function(prev) { - var chap = prev ? W._prevchap : W._nextchap; - if (chap > 0) { - return location.href.replace(/(\/comic\/[0-9]+\/)[0-9]+\.html.*/, "$1" + chap + ".html"); - } else { - return false; - } - }, - prevchap: function() { - return this.nextchap(true); - }, - wait: function() { - if (getEl('#mangaFile')) { - W._nextchap = W.cInfo.nextId; - W._prevchap = W.cInfo.prevId; - var ex = extractInfo.bind(this); - W._next = location.href.replace(/(_p[0-9]+)?\.html.*/, '_p' + (ex('curpage') + 1) + '.html'); - W._base = ex('img').replace(/[^\/]+$/, ''); - return true; - } - }, - pages: function(url, num, cb, ex) { - var nexturl = url.replace(/(_p[0-9]+)?\.html.*/, '_p' + (num + 1) + '.html'); - var imgurl = W._base + W.cInfo.files[num - 1]; - cb(imgurl, nexturl); - } -}, { - name: 'mangasail and mangatail', - match: 'https?://www\.manga(sail|tail)\.com/[^/]+', - img: '#images img', - next: '#images a', - curpage: '#edit-select-page', - numpages: '#edit-select-page', - nextchap: function(prev) { - return location.origin + '/node/' + extractInfo('#edit-select-node', {type: 'value', val: prev ? -1 : 1}); - }, - prevchap: function() { - return this.nextchap(true); - }, - curchap: '#select_node', - numchaps: '#select_node' -}, { - name: 'komikstation', - match: "^https?://www\.komikstation\.com/.+/.+/.+", - img: '#mainpage', - next: function() { - return W._base + '?page=' + (W.glbCurrentpage + 1); - }, - numpages: '#index select', - curpage: '#index select', - pages: function(url, num, cb, ex) { - next = W._base + '?page=' + (num + 1); - cb(W.pages[num - 1], next); - }, - wait: function() { - W._base = location.href.replace(/[?#].+$/, ''); - return W.pages; - } -}, { - name: 'gmanga', - match: "^https?://gmanga.me/mangas/", - img: function() { - return W.pages[W.firstImg - 1]; - }, - next: function() { - return location.href + '#' + (W.firstImg + 1); - }, - numpages: function() { - return W.totalImgs; - }, - curpage: function() { - return W.firstImg; - }, - nextchap: function(prev) { - var num = parseInt(extractInfo('#chapter', {type: 'value', val: prev ? 1 : -1})); - return num && location.href.replace(/(\/mangas\/[^\/]+\/)[0-9]+(\/[^\/]+)/, '$1' + num + '$2'); - }, - prevchap: function() { - return this.nextchap(true); - }, - numchaps: '#chapter', - curchap: '#chapter', - invchap: true, - pages: function(url, num, cb, ex) { - var nexturl = location.href + '#' + (num + 1); - cb(W.pages[num - 1], nexturl); - }, - wait: function() { - W.pages = W.release_pages && W.release_pages[1]; - return W.pages; - } -}, { - name: '930mh', - match: "http://www\.930mh\.com/manhua/\\d+/\\d+.html", - img: '#images > img', - next: function() { - return location.origin + location.pathname + '?p=' + (W.SinTheme.getPage() + 1); - }, - pages: function(url, num, cb, ex) { - cb(new URL(W.pageImage).origin + '/' + W.chapterPath + W.chapterImages[num - 1], num - 1); - }, - curpage: function() { - return W.SinTheme.getPage(); - }, - numpages: function() { - return W.chapterImages.length; - }, - nextchap: function(){ - return W.nextChapterData.id && W.nextChapterData.id > 0 ? W.comicUrl + W.nextChapterData.id + '.html' : null; - }, - prevchap: function(){ - return W.prevChapterData.id && W.prevChapterData.id > 0 ? W.comicUrl + W.prevChapterData.id + '.html' : null; - }, - wait: '#images > img' -}, { - name: '漫畫王', - match: "https://www\.mangabox\.me/reader/\\d+/episodes/\\d+/", - img: 'img.jsNext', - next: function() { - return '#'; - }, - pages: function(url, num, cb, ex) { - cb(W.pages[num - 1].src, num - 1); - }, - numpages: function() { - return W.pages.length; - }, - nextchap: '.lastSlider_nextButton', - wait: function (){ - W.pages = getEls('img.jsNext'); - return true; - } -}, { - name: '2comic.com 動漫易', - match: "http://twocomic.com/view/comic_\\d+.html", - img: '#TheImg', - next: function() { - return '#'; - }, - pages: function(url, num, cb, ex) { - W.p++; - var ss = W.ss; - var c = W.c; - var ti = W.ti; - var nn = W.nn; - var p = W.p; - var mm = W.mm; - var f = W.f; - var img = 'http://img' + ss(c, 4, 2) + '.8comic.com/' + ss(c, 6, 1) + '/' + ti + '/' + ss(c, 0, 4) + '/' + nn(p) + '_' + ss(c, mm(p) + 10, 3, f) + '.jpg'; - cb(img, num - 1); - }, - numpages: function() { - return W.ps * 1; - }, - curpage: function() { - return W.p; - }, - numchaps: function() { - return W.chs; - }, - curchap: function() { - return W.ch; - }, - nextchap: function() { - return W.ch < W.chs ? W.replaceurl('ch', W.ni) : false; - }, - prevchap: function() { - return W.ch > 1 ? W.replaceurl('ch', W.pi) : false; - }, - wait:'#TheImg' -}]; -// END OF IMPL +var default_repo_url = 'https://raw.githubusercontent.com/fuzetsu/manga-loader/master/impls/' + +// Change this variable to control if you want to load NSFW implementations. +var repo_enabled = ["nsfw", "normal"]; var log = function(msg, type) { type = type || 'log'; @@ -1477,11 +100,24 @@ var storeSet = function(key, value) { return GM_setValue(key, value); }; +var storeList = function() { + if (typeof GM_listValues === "undefined") { + var klist = []; + for (var i = 0; i < localStorage.length; i++) { + klist.append(localStorage.key(i)); + } + return klist; + } + //return GM_listValues(); + // workaround + return GM_listValues().filter(function(v) {return GM_getValue(v) ? true : false}); +}; + var storeDel = function(key) { if (typeof GM_deleteValue === "undefined") { - return localStorage.removeItem(key); + localStorage.removeItem(key); } - return GM_deleteValue(key); + GM_deleteValue(key); }; var areDefined = function() { @@ -1688,7 +324,16 @@ var getViewer = function(prevChapter, nextChapter) { }, '.ml-setting-key input'), autoloadSettingCss = toStyleStr({ 'vertical-align': 'middle' - }, '.ml-setting-autoload'); + }, '.ml-setting-autoload'), + flexContainerCss = toStyleStr({ + 'display': 'inline-flex', + 'align-content': 'flex-start', + 'flex-flow': 'row wrap' + }, '.ml-images'), + flexElementCss = toStyleStr({ + 'box-sizing': 'border-box', + 'flex': '0 0 ' + 100 / (storeGet('mColNum') || 1) + '%' + }, '.ml-images>div'); // clear all styles and scripts var title = document.title; document.head.innerHTML = ''; @@ -1710,7 +355,7 @@ var getViewer = function(prevChapter, nextChapter) { // combine ui elements document.body.innerHTML = nav + '
' + nav + floatingMsg + stats; // add main styles - addStyle('main', true, viewerCss, imagesCss, imageCss, counterCss, navCss, navHoverCss, statsCss, statsCollapseCss, statsHoverCss, boxCss, floatingMsgCss, buttonCss, keySettingCss, autoloadSettingCss, floatingMsgAnchorCss); + addStyle('main', true, viewerCss, imagesCss, imageCss, counterCss, navCss, navHoverCss, statsCss, statsCollapseCss, statsHoverCss, boxCss, floatingMsgCss, buttonCss, keySettingCss, autoloadSettingCss, floatingMsgAnchorCss, flexContainerCss, flexElementCss); // add user styles var userCss = storeGet('ml-setting-css-profiles'); var curProf = storeGet('ml-setting-css-current') || 'Default'; @@ -1802,12 +447,21 @@ var getViewer = function(prevChapter, nextChapter) { var target = e.target; UI.images.removeEventListener('click', imgClick, false); UI.images.style.cursor = ''; - if(target.nodeName === 'IMG' && target.parentNode.className === 'ml-images') { + if(target.nodeName === 'IMG') { showFloatingMsg(''); if(!target.title) { - showFloatingMsg('Reloading "' + target.src + '"', 3000); - if(target.complete) target.onload = null; - target.src = target.src + (target.src.indexOf('?') !== -1 ? '&' : '?') + new Date().getTime(); + var pgnum = target.id.substr(10) + showFloatingMsg('Fetching URL of picture of page ' + pgnum, 3000); + sessionStorage.setItem("RimgUrl", 'notyet'); + window.reload = function() { + var pgsrc = sessionStorage.getItem("RimgUrl"); + log('pagenum : ' + pgnum + ', pagesrc : ' + pgsrc); + showFloatingMsg('Reloading "' + pgsrc + '"', 3000); + if(target.complete) target.onload = null; + target.src = pgsrc + (pgsrc.indexOf('?') !== -1 ? '&' : '?') + new Date().getTime(); + } + //the function reload was inserted into the function dummy_addAndLoad inside the function getUrl to make sure reload was done after URL of the picture is fetched + getUrl(pgnum) } } else { showFloatingMsg('Cancelled manual reload...', 3000); @@ -1884,9 +538,9 @@ var getViewer = function(prevChapter, nextChapter) { '