Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pyc
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.analysis.typeCheckingMode": "off"
}
51 changes: 51 additions & 0 deletions MLEP-IRS.md
Original file line number Diff line number Diff line change
@@ -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`.
40 changes: 40 additions & 0 deletions impls/normal/2comic.com 動漫易.js
Original file line number Diff line number Diff line change
@@ -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'
}
3 changes: 3 additions & 0 deletions impls/normal/3asq.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// METADATA
// match: ^https?://www\.3asq\.org/[^/]+/[0-9.]+
// mapto: manga-cow
25 changes: 25 additions & 0 deletions impls/normal/930mh.js
Original file line number Diff line number Diff line change
@@ -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'
}
3 changes: 3 additions & 0 deletions impls/normal/abandonedkittenscans.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// METADATA
// match: ^https?://abandonedkittenscans\.mokkori\.fr/reader/read/.+
// mapto: foolslide
19 changes: 19 additions & 0 deletions impls/normal/anime-a.js
Original file line number Diff line number Diff line change
@@ -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);
}
}
50 changes: 50 additions & 0 deletions impls/normal/batoto.js
Original file line number Diff line number Diff line change
@@ -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'
}
12 changes: 12 additions & 0 deletions impls/normal/biamamscans.com.js
Original file line number Diff line number Diff line change
@@ -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'
}
9 changes: 9 additions & 0 deletions impls/normal/br.mangahost.com.js
Original file line number Diff line number Diff line change
@@ -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'
}
3 changes: 3 additions & 0 deletions impls/normal/cafeconirst.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// METADATA
// match: ^https?://reader\.cafeconirst\.com/read/.+
// mapto: foolslide
24 changes: 24 additions & 0 deletions impls/normal/cartoonmad.js
Original file line number Diff line number Diff line change
@@ -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;
},

}
3 changes: 3 additions & 0 deletions impls/normal/casanovascans.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// METADATA
// match: ^https?://casanovascans\.com/read/.+
// mapto: foolslide
20 changes: 20 additions & 0 deletions impls/normal/central-de-mangas.js
Original file line number Diff line number Diff line change
@@ -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);
}
}
3 changes: 3 additions & 0 deletions impls/normal/championscans.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// METADATA
// match: ^https?://reader\.championscans\.com/read/.+
// mapto: foolslide
19 changes: 19 additions & 0 deletions impls/normal/chuixue.js
Original file line number Diff line number Diff line change
@@ -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'
}
14 changes: 14 additions & 0 deletions impls/normal/comicastle.js
Original file line number Diff line number Diff line change
@@ -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
}
3 changes: 3 additions & 0 deletions impls/normal/demonicscans.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// METADATA
// match: ^https?://www\.demonicscans\.com/FoOlSlide/read/.+
// mapto: foolslide
23 changes: 23 additions & 0 deletions impls/normal/dm5.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
20 changes: 20 additions & 0 deletions impls/normal/dmzj.js
Original file line number Diff line number Diff line change
@@ -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'
}
Loading