cejs
Version:
A JavaScript module framework that is simple to use.
289 lines (247 loc) • 10.1 kB
JavaScript
/**
* @name CeL module for downloading SinMH CMS? comics.
*
* @fileoverview 本檔案包含了解析並處理、批量下載中國大陸常見漫畫管理系統: 可能是 圣樱漫画管理系统 (圣樱CMS) 2013年版 的工具。
*
* TODO: https://m.999comics.com/
*
* <code>
CeL.SinMH2013(configuration).start(work_id);
</code>
*
* modify from archive/2manhua.js
*
* 57mh 介面程式碼類似於 999comics。manhuagui 似乎是在這基礎上經過修改? 57mh 這一批介面外觀與
* CeL.application.net.work_crawler.sites.SinMH 類似,但介面程式碼有些差距。或可稱為
* CeL.application.net.work_crawler.sites.SinMH2013 或
* CeL.application.net.work_crawler.sites.SMH。
*
* @see https://www.999comics.com/static/scripts/main.js?v=1.0 MHD (MHD: 漫画岛
* http://www.manhuadao.com/book/baiqianjiadeyaoguaiwangzi/)
* http://www.wuqimh.com/templates/wuqi/default/scripts/main.js?v=1.0.3 MHW
* https://cf.hamreus.com/scripts_tw/main_EB87BCACAD66FA68CA738D0C925DC508.js
* main_EB87BCACAD66FA68CA738D0C925DC508.js 末: SMH = { update: "2013/4/1" }
*
* @since 2019/6/18 6:13:11 模組化 MHD模板?
*/
// More examples:
// @see
// https://github.com/kanasimi/work_crawler/blob/master/comic.cmn-Hans-CN/57mh.js
;
// --------------------------------------------------------------------------------------------
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
typeof CeL === 'function' && CeL.run({
// module name
name : 'application.net.work_crawler.sites.SinMH2013',
require : 'application.net.work_crawler.'
//
+ '|application.net.work_crawler.sites.SinMH.',
// 設定不匯出的子函式。
no_extend : '*',
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
code : module_code
});
function module_code(library_namespace) {
// requiring
// --------------------------------------------------------------------------------------------
var default_configuration = {
// 所有的子檔案要修訂註解說明時,應該都要順便更改在CeL.application.net.comic中Comic_site.prototype內的母comments,並以其為主體。
// 本站常常無法取得圖片,因此得多重新檢查。
// recheck:從頭檢測所有作品之所有章節與所有圖片。不會重新擷取圖片。對漫畫應該僅在偶爾需要從頭檢查時開啟此選項。
// recheck : true,
// 當無法取得chapter資料時,直接嘗試下一章節。在手動+監視下recheck時可併用此項。
// skip_chapter_data_error : true,
// 36145 前任攻略 19话 057.jpg
// {Natural}MIN_LENGTH:最小容許圖案檔案大小 (bytes)。
MIN_LENGTH : 400,
// 當圖像檔案過小,或是被偵測出非圖像(如不具有EOI)時,依舊強制儲存檔案。
skip_error : true,
// one_by_one : true,
// base_URL : '',
// 取得伺服器列表。
// use_server_cache : true,
// http://www.5qmh.com/templates/wuqi/default/scripts/configs.js?v=1.0.3
server_URL : 'templates/wuqi/default/scripts/configs.js',
parse_server_list : function(html) {
// console.log(html);
var server_list = [];
Object.values(JSON.parse(
// var pageConfig = { 'host': { ...
html.replace(/^[^{]+/, '').replace(/[^}]+$/, '')
//
.replace(/'/g, '"')).host)
//
.forEach(function(_server_list) {
_server_list.forEach(function(server) {
if (server) {
if (!server.endsWith('/'))
server += '/';
server_list.push(server);
}
});
});
return server_list;
},
// 解析 作品名稱 → 作品id get_work()
search_URL : 'handler/suggest?cb=_&key=',
parse_search_result : function(html) {
// console.log(html);
// e.g.,
// _([{"id":"28015","t":"民工勇者","u":"/comic/28015/","cid":"/comic/28015/0208","ct":"207话","s":"0"},{"id":"28093","t":"无敌勇者王(民工勇者)","u":"/comic/28093/","cid":"/comic/28093/02","ct":"199话","s":"0"}])
var id_data = html ? JSON.parse(html.between('(').replace(
/\)[^)]*$/, '')) : [];
return [ id_data, id_data ];
},
id_of_search_result : function(cached_data) {
return cached_data.id | 0;
},
title_of_search_result : 't',
// 取得作品的章節資料。 get_work_data()
work_URL : function(work_id) {
// e.g., http://www.5qmh.com/28437/
return work_id + '/';
},
parse_work_data : library_namespace.SinMH.default_configuration.parse_work_data,
get_chapter_list : function(work_data, html, get_label) {
// console.log(html);
work_data.chapter_list = [];
var matched, part_title, part_NO = 0, page,
// 2017/7/22: 57mh.js 章節編號順序為 21 43 65.
// e.g., 银魂 http://www.wuqimh.com/8/
// matched: [ all, part_title, page inner ]
PATTERN_page = /<h4><span>(.+?)<\/span><\/h4>|<ul (?:style="display:block;")?>([\s\S]+?)<\/ul>/g,
/**
* e.g., 57mh.js 只發現過多page頁面,沒有發現過多part <code>
<h4><span>单话</span></h4><div class="chapter-page cf mt10" id="chpater-page-1"><ul>
<li ><a href="javascript:;" title="第1页">第1页<i></i></a></li>
...
<li class="on"><a href="javascript:;" title="第7页">第7页<i></i></a></li>
</ul></div>
<div class="chapter-list cf mt10" id="chpater-list-1"><ul >
<li><a href="/8/065.html" title="155话" class="status0" target="_blank"><span>155话<i>21p</i></span></a></li>
...
</ul></div>
</code>
*
* e.g., 999comics.js 只發現過多part,沒有發現過多page頁面 <code>
<h4><span>單話</span></h4>
<div class="chapter-list cf mt10">
<ul style="display:block;">
<li><a href="/comic/26060/72192e0511125993c37cbd5264c971b6.html" title="第371回" class="status0" target="_blank"><span>371回</span></a></li>
...
</ul>
</div><h4><span>番外篇</span></h4>
<div class="chapter-list cf mt10">
<ul style="display:block;">
<li><a href="/comic/26060/b0da0b7c0767f1332684a0ae111b3696.html" title="Jump next出張篇" class="status0" target="_blank"><span>Jump</span></a></li>
...
</ul>
</div>
</code> 單話 番外篇 單行本
*
* <code>
<li><a href="/comic/25652/072.html" title="72回 碧霞坠" class="status0" target="_blank"><span>72回<i>14p</i></span></a></li>
</code>
*/
PATTERN_chapter =
// matched: [ all, href, title, inner ]
/<li><a href="([^"<>]+)" title="([^"<>]+)"[^<>]*>(.+?)<\/a><\/li>/g;
while (page = PATTERN_page.exec(html)) {
if (page[1]) {
part_title = get_label(page[1]);
part_NO++;
// library_namespace.info('part_title: ' + part_title);
continue;
}
page = page[2];
// console.log(page);
var chapter_list = [];
while (matched = PATTERN_chapter.exec(page)) {
matched[2] = matched[2].trim();
if (matched[3] = matched[3].between('<i>', '</i>')) {
// add page count
matched[2] = matched[2] + ' ' + matched[3];
}
chapter_list.push({
part : part_title,
part_NO : part_NO,
title : get_label(matched[2]),
url : encodeURI(matched[1])
});
}
if (!this.no_need_to_revert)
chapter_list = chapter_list.reverse();
work_data.chapter_list.append(chapter_list);
}
work_data.chapter_list.part_NO = part_NO;
return;
// 已被棄置的排序方法。
work_data.chapter_list
.sort(function(chapter_data_1, chapter_data_2) {
var matched_1 = chapter_data_1.url.match(/(\d+)\.htm/),
// 依照.url排序。
matched_2 = chapter_data_2.url.match(/(\d+)\.htm/);
if (matched_1 && matched_2) {
return matched_1[1] - matched_2[1];
}
return chapter_data_1.url < chapter_data_2.url ? -1 : 1;
// 依照.title排序。
return chapter_data_1.title < chapter_data_2.title ? -1
: 1;
});
},
parse_chapter_data : function(html, work_data, get_label, chapter_NO) {
// decode chapter data
function decode(code) {
code = eval(code).replace(/^[^=]+/, 'code');
return eval(code);
}
var chapter_data = html
.match(/[>;\n\s]var\s+cInfo\s*=\s*(\{[\s\S]+?\})[;\n]/);
if (chapter_data) {
// 999comics.js
// console.log(chapter_data[1]);
eval('chapter_data=' + chapter_data[1]);
// https://www.999comics.com/static/scripts/core2.js?v=20180206
// preload: function(t) {...}
// r("<img />")[0].src = "//www.999comics.com/g.php?"+o.cid+'/'+
// o.fs[i - 1]
chapter_data.fs = chapter_data.fs.map(function(i) {
return this.full_URL('g.php?'
//
+ chapter_data.cid + '/' + i);
}, this);
} else if (chapter_data = html.between(
'<script type="text/javascript">eval', '\n')) {
// 57mh.js
chapter_data = decode(chapter_data);
}
if (!chapter_data) {
library_namespace.warn({
// gettext_config:{"id":"unable-to-parse-chapter-data-for-«$1»-§$2"}
T : [ '無法解析《%1》§%2 之章節資料!', work_data.title, chapter_NO ]
});
return;
}
// console.log(chapter_data);
// 設定必要的屬性。
chapter_data.title = get_label(html.between('<h2>', '</h2>'));
chapter_data.image_count = chapter_data.fc;
chapter_data.image_list = chapter_data.fs;
if (!chapter_data.fs.at(-1)) {
// for http://www.5qmh.com/6908/0296.html?p=9
chapter_data.fs.pop();
chapter_data.image_count--;
}
return chapter_data;
}
};
// --------------------------------------------------------------------------------------------
function new_SinMH2013_comics_crawler(configuration) {
configuration = configuration ? Object.assign(Object.create(null),
default_configuration, configuration) : default_configuration;
// 每次呼叫皆創建一個新的實體。
return new library_namespace.work_crawler(configuration);
}
return new_SinMH2013_comics_crawler;
}