cejs
Version:
A JavaScript module framework that is simple to use.
243 lines (195 loc) • 7.5 kB
JavaScript
/**
* @name CeL module for downloading Toomics comics.
*
* @fileoverview 本檔案包含了解析並處理、批量下載 Toomics 韓國漫畫 之 **非韓語版**(外語版本) 的工具。
*
* <code>
CeL.toomics(configuration).start(work_id);
</code>
*
* @since 2019/7/12 20:21:25 模組化。
*/
// More examples:
// @see
// https://github.com/kanasimi/work_crawler/blob/master/comic.cmn-Hans-CN/toomics_sc.js
;
// --------------------------------------------------------------------------------------------
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
typeof CeL === 'function' && CeL.run({
// module name
name : 'application.net.work_crawler.sites.toomics',
require : 'application.net.work_crawler.',
// 設定不匯出的子函式。
no_extend : '*',
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
code : module_code
});
function module_code(library_namespace) {
// requiring
// --------------------------------------------------------------------------------------------
var default_configuration = {
// 所有的子檔案要修訂註解說明時,應該都要順便更改在CeL.application.net.comic中Comic_site.prototype內的母comments,並以其為主體。
// {Natural}MIN_LENGTH:最小容許圖案檔案大小 (bytes)。
// 對於有些圖片只有一條細橫桿的情況。
MIN_LENGTH : 200,
// 圖像檔案下載失敗處理方式:忽略/跳過圖像錯誤。當404圖像不存在、檔案過小,或是被偵測出非圖像(如不具有EOI)時,依舊強制儲存檔案。default:false
// skip_error : true,
// one_by_one : true,
base_URL : 'https://toomics.com/',
// LANG_PREFIX : '',
// 解析 作品名稱 → 作品id get_work()
search_URL : function(work_title) {
return [ this.LANG_PREFIX + '/webtoon/ajax_search', {
toonData : work_title,
offset : 0,
limit : 20
} ];
},
parse_search_result : function(html, get_label) {
html = html.between('<ul>', '</ul>');
// console.log(html);
function parser(token) {
// console.log(token);
return [ +token.match(/toon=(\d+)&/)[1],
/**
* <code>
<a href="/sc/webtoon/search/?toon=4866&return=%2Fsc%2Fwebtoon%2Fepisode%2Ftoon%2F4866">
<div class="search_box">
<p class="img"><img src="https://thumb-g.toomics.com/upload/thumbnail/20180629102024/2019_03_15_15526329389053.jpg" alt="郑主任为何这样"></p>
</code>
*/
token.between('alt="', '"') ];
}
return library_namespace.work_crawler
.extract_work_id_from_search_result_link(
/<li(?:[^<>]*)>([\s\S]+?)<\/li>/g, html, parser);
},
// 取得作品的章節資料。 get_work_data()
work_URL : '/webtoon/episode/toon/',
parse_work_data : function(html, get_label, extract_work_data) {
// console.log(html);
var text = html.between('<header class="ep-cover_ch"', '</header>');
var work_data = {
// 必要屬性:須配合網站平台更改。
title : get_label(text.between('<h1>', '</h1>')),
author : get_label(text.between(
/**
* <code>
<span class="writer">李玄敏 <span class="text-muted">|</span> Miyune</span>
</p>
</code>
*/
'<span class="writer">', '</p>')).replace(/ +\|/g, ','),
// 選擇性屬性:須配合網站平台更改。
description : get_label(text.between('<h2>', '</h2>')),
genre : get_label(
text.between('<span class="type">', '</span>'))
.replace(/\s{2,}/g, ' '),
// e.g., Updated every Friday
update_weekday : text.between('<span class="date">', '</span>')
};
extract_work_data(work_data, html);
// console.log(work_data);
return work_data;
},
get_chapter_list : function(work_data, html, get_label) {
html = html.between('<ol class="list-ep">', '</ol>');
var matched, PATTERN_chapter =
//
/<li><a href="([^<>"]+)"[^<>]*>([\s\S]+?)<\/li>/g;
work_data.chapter_list = [];
/**
* <code>
<a href="javascript:;" onclick="Webtoon.chkec(this);location.href='/en/webtoon/detail/code/97236/ep/0/toon/4630'" onkeypress="this.onclick"
data-e="NDYzMA==" data-c="OTcyMzY="
data-v="">
</code>
*/
html.each_between('<li', '</li>', function(token) {
var url = token.between("location.href='", "'");
if (!url) {
// limited
return;
}
work_data.chapter_list.push({
title : get_label(token.between('<div class="cell-num">',
'</div>')),
date : token.between('datetime="', '"'),
type : token
.between('<span class="coin-type1">', '</span>'),
thumb : token.between('data-original="', '"'),
rating : token.between('<span class="star-stat">',
'</span>'),
url : url
});
});
// console.log(work_data.chapter_list);
},
pre_parse_chapter_data
// 執行在解析章節資料 process_chapter_data() 之前的作業 (async)。
// 必須自行保證執行 callback(),不丟出異常、中斷。
: function(XMLHttp, work_data, callback, chapter_NO) {
if (this.verificated) {
callback()
return;
}
this.get_URL(this.LANG_PREFIX
// https://toomics.com/tc/age_verification
// 年齡認證 如需關閉安全模式,請確認您已年滿18歲。
+ '/age_verification', function(XMLHttp) {
// console.log(XMLHttp);
this.get_URL(this.LANG_PREFIX
// https://toomics.com/sc/index/set_display/?display=A&return=/sc/webtoon/detail/code/55556/ep/1/toon/2509
+ '/index/set_display/?display=A&return=/' + this.LANG_PREFIX
+ '/help/notice_list', function(XMLHttp) {
// console.log(XMLHttp);
// console.log(this.get_URL_options);
this.verificated = true;
callback();
});
});
},
parse_chapter_data : function(html, work_data, get_label, chapter_NO) {
var chapter_data = work_data.chapter_list[chapter_NO - 1];
// console.log(chapter_data);
// console.log(html);
Object.assign(chapter_data, {
title : html.between('<div class="viewer-title">', '</div>')
/**
* <code>
<div class="viewer-title">
<a href="/en/webtoon/episode/toon/4630" title="List">Too Pretty<em>Episode 1</em></a>
</div>
</code>
*/
.between('<em>', '</em>'),
image_list : html
// 2019: '<main class="viewer-body">'
// 2020/8: '<main class="viewer-body viewer-body-scroll">'
.between('<main class="viewer-body', '</main>')
// 2019: .all_between('data-original="', '"')
// 2020/8: .all_between('data-src="', '"')
.all_between('data-src="', '"')
});
if (chapter_data.image_list.length === 0) {
// 改版?
// console.trace(html);
}
// console.log(chapter_data);
return chapter_data;
}
};
// --------------------------------------------------------------------------------------------
function new_toomics_comics_crawler(configuration) {
configuration = Object.assign(Object.create(null),
//
default_configuration, {
work_URL : configuration.LANG_PREFIX
+ default_configuration.work_URL
}, configuration);
// 每次呼叫皆創建一個新的實體。
var crawler = new library_namespace.work_crawler(configuration);
return crawler;
}
return new_toomics_comics_crawler;
}