284 lines
11 KiB
JavaScript
284 lines
11 KiB
JavaScript
import { Crypto, _, load } from './lib/cat.js';
|
|
import { LZString } from './lib/lz_string.js';
|
|
|
|
let key = 'manhuagui';
|
|
let HOST = 'https://www.manhuagui.com';
|
|
|
|
let siteKey = '';
|
|
let siteType = 0;
|
|
|
|
let prefixMap = {};
|
|
const VOLUME_KEY_TELECOM = 'tel';
|
|
const VOLUME_KEY_TELECOM1 = 'tel2';
|
|
const VOLUME_KEY_UNICOM = 'uni';
|
|
const VOLUME_KEY_UNICOM1 = 'uni1';
|
|
const VOLUME_KEY_UNICOM2 = 'uni2';
|
|
const VOLUME_KEY_UNICOM3 = 'uni3';
|
|
|
|
const PC_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36';
|
|
|
|
async function request(reqUrl) {
|
|
let resp = await req(reqUrl, {
|
|
headers: {
|
|
'User-Agent': PC_UA,
|
|
},
|
|
});
|
|
return resp.content;
|
|
}
|
|
|
|
// cfg = {skey: siteKey, ext: extend}
|
|
async function init(cfg) {
|
|
siteKey = cfg.skey;
|
|
siteType = cfg.stype;
|
|
|
|
initKeys();
|
|
|
|
String.prototype.splic = function(f) {
|
|
const data = LZString.decompressFromBase64(this);
|
|
return data.split(f);
|
|
}
|
|
}
|
|
|
|
function initKeys() {
|
|
prefixMap[VOLUME_KEY_TELECOM] = {
|
|
key: 'eu',
|
|
name: '电信',
|
|
};
|
|
prefixMap[VOLUME_KEY_TELECOM1] = {
|
|
key: 'eu1',
|
|
name: '电信1',
|
|
};
|
|
prefixMap[VOLUME_KEY_UNICOM] = {
|
|
key: 'us',
|
|
name: '联通',
|
|
};
|
|
prefixMap[VOLUME_KEY_UNICOM1] = {
|
|
key: 'us1',
|
|
name: '联通1',
|
|
};
|
|
prefixMap[VOLUME_KEY_UNICOM2] = {
|
|
key: 'us2',
|
|
name: '联通2',
|
|
};
|
|
prefixMap[VOLUME_KEY_UNICOM3] = {
|
|
key: 'us3',
|
|
name: '联通3',
|
|
};
|
|
}
|
|
|
|
async function home(filter) {
|
|
const classes = [{'type_id':'all','type_name':'漫画大全'}];
|
|
const filterObj = {
|
|
'all':[{'key':'area','name':'地区','init':'','value':[{'n':'全部','v':''},{'n':'日本','v':'japan'},{'n':'港台','v':'hongkon'},{'n':'其它','v':'other'},{'n':'欧美','v':'europe'},{'n':'内地','v':'china'},{'n':'韩国','v':'korea'}]},{'key':'genre','name':'剧情','init':'','value':[{'n':'全部','v':''},{'n':'热血','v':'rexue'},{'n':'冒险','v':'maoxian'},{'n':'魔幻','v':'mohuan'},{'n':'神鬼','v':'shengui'},{'n':'搞笑','v':'gaoxiao'},{'n':'萌系','v':'mengxi'},{'n':'爱情','v':'aiqing'},{'n':'科幻','v':'kehuan'},{'n':'魔法','v':'mofa'},{'n':'格斗','v':'gedou'},{'n':'武侠','v':'wuxia'},{'n':'机战','v':'jizhan'},{'n':'战争','v':'zhanzheng'},{'n':'竞技','v':'jingji'},{'n':'体育','v':'tiyu'},{'n':'校园','v':'xiaoyuan'},{'n':'生活','v':'shenghuo'},{'n':'励志','v':'lizhi'},{'n':'历史','v':'lishi'},{'n':'伪娘','v':'weiniang'},{'n':'宅男','v':'zhainan'},{'n':'腐女','v':'funv'},{'n':'耽美','v':'danmei'},{'n':'百合','v':'baihe'},{'n':'后宫','v':'hougong'},{'n':'治愈','v':'zhiyu'},{'n':'美食','v':'meishi'},{'n':'推理','v':'tuili'},{'n':'悬疑','v':'xuanyi'},{'n':'恐怖','v':'kongbu'},{'n':'四格','v':'sige'},{'n':'职场','v':'zhichan'},{'n':'侦探','v':'zhentan'},{'n':'社会','v':'shehui'},{'n':'音乐','v':'yinyue'},{'n':'舞蹈','v':'wudao'},{'n':'杂志','v':'zazhi'},{'n':'黑道','v':'heidao'}]},{'key':'age','name':'受众','init':'','value':[{'n':'全部','v':''},{'n':'少女','v':'shaonv'},{'n':'少年','v':'shaonian'},{'n':'青年','v':'qingnian'},{'n':'儿童','v':'ertong'},{'n':'通用','v':'tongyong'}]},{'key':'year','name':'年份','init':'','value':[{'n':'全部','v':''},{'n':'2024年','v':'2024'},{'n':'2023年','v':'2023'},{'n':'2022年','v':'2022'},{'n':'2021年','v':'2021'},{'n':'2020年','v':'2020'},{'n':'2019年','v':'2019'},{'n':'2018年','v':'2018'},{'n':'2017年','v':'2017'},{'n':'2016年','v':'2016'},{'n':'2015年','v':'2015'},{'n':'2014年','v':'2014'},{'n':'2013年','v':'2013'},{'n':'2012年','v':'2012'},{'n':'2011年','v':'2011'},{'n':'2010年','v':'2010'},{'n':'00年代','v':'200x'},{'n':'90年代','v':'199x'},{'n':'80年代','v':'198x'},{'n':'更早','v':'197x'}]},{'key':'letter','name':'字母','init':'','value':[{'n':'全部','v':''},{'n':'A','v':'A'},{'n':'B','v':'B'},{'n':'C','v':'C'},{'n':'D','v':'D'},{'n':'E','v':'E'},{'n':'F','v':'F'},{'n':'G','v':'G'},{'n':'H','v':'H'},{'n':'I','v':'I'},{'n':'J','v':'J'},{'n':'K','v':'K'},{'n':'L','v':'L'},{'n':'M','v':'M'},{'n':'N','v':'N'},{'n':'O','v':'O'},{'n':'P','v':'P'},{'n':'Q','v':'Q'},{'n':'R','v':'R'},{'n':'S','v':'S'},{'n':'T','v':'T'},{'n':'U','v':'U'},{'n':'V','v':'V'},{'n':'W','v':'W'},{'n':'X','v':'X'},{'n':'Y','v':'Y'},{'n':'Z','v':'Z'},{'n':'0-9','v':'0-9'}]},{'key':'status','name':'进度','init':'','value':[{'n':'全部','v':''},{'n':'连载','v':'lianzai'},{'n':'完结','v':'wanjie'}]},{'key':'sort','name':'排序','init':'index','value':[{'n':'最新发布','v':'index'},{'n':'最新更新','v':'update'},{'n':'热气最旺','v':'view'},{'n':'评分最高','v':'rate'}]}],
|
|
};
|
|
return JSON.stringify({
|
|
class: classes,
|
|
filters: filterObj,
|
|
});
|
|
}
|
|
|
|
async function category(tid, pg, filter, extend) {
|
|
if (pg == 0) pg = 1;
|
|
const area = getFilterUrlPart(extend, 'area');
|
|
const genre = getFilterUrlPart(extend, 'genre');
|
|
const age = getFilterUrlPart(extend, 'age');
|
|
const year = getFilterUrlPart(extend, 'year');
|
|
const letter = getFilterUrlPart(extend, 'letter');
|
|
const status = getFilterUrlPart(extend, 'status');
|
|
let path1 = `${area}${genre}${age}${year}${letter}${status}`;
|
|
path1 = path1.replace(/_$/, '');
|
|
const sort = getFilterUrlPart(extend, 'sort');
|
|
let path2 = sort;
|
|
if (pg > 1) {
|
|
path2 += `p${pg}`;
|
|
}
|
|
path2 = path2.replace(/_$/, '');
|
|
let path = '';
|
|
if (!_.isEmpty(path1)) {
|
|
path += `/${path1}`;
|
|
}
|
|
if (!_.isEmpty(path2)) {
|
|
path += `/${path2}.html`;
|
|
}
|
|
if (_.isEmpty(path)) {
|
|
path = '/';
|
|
}
|
|
const link = HOST + `/list${path}`;
|
|
const html = await request(link);
|
|
const $ = load(html);
|
|
const list = $('.book-list > #contList > li');
|
|
const books = _.map(list, (item) => {
|
|
const $item = $(item);
|
|
const $cover = $item.find('.bcover');
|
|
const $img = $cover.find('img:first');
|
|
const $remark = $item.find('.updateon em:first');
|
|
let src = $img.attr('src');
|
|
if (_.isEmpty(src)) {
|
|
src = $img.attr('data-src');
|
|
}
|
|
return {
|
|
book_id: $cover.attr('href').replace(/\/comic\/(.*)\//, '$1'),
|
|
book_name: $cover.attr('title'),
|
|
book_pic: 'https:' + src,
|
|
book_remarks: $remark.text(),
|
|
};
|
|
});
|
|
const hasMore = $('.pager-cont a:contains(下一页)').length > 0;
|
|
return {
|
|
page: pg,
|
|
pagecount: hasMore ? pg + 1 : pg,
|
|
list: books,
|
|
};
|
|
}
|
|
|
|
function getFilterUrlPart(extend, part) {
|
|
let result = '';
|
|
if (extend[part]) {
|
|
result = extend[part] + '_';
|
|
}
|
|
return result;
|
|
}
|
|
|
|
async function detail(id) {
|
|
const html = await request(HOST + `/comic/${id}/`);
|
|
const $ = load(html);
|
|
const book = {
|
|
book_name: $('.book-title').text().trim(),
|
|
book_year: $('.detail-list span:contains(出品年代) a').text().trim(),
|
|
book_area: $('.detail-list span:contains(漫画地区) a').text().trim(),
|
|
book_director: $('.detail-list span:contains(漫画作者) a').text().trim(),
|
|
book_content: $('#intro-all').text().trim(),
|
|
};
|
|
const list = $('.chapter-list a');
|
|
const keys = _.keys(prefixMap);
|
|
const urls = _.map(keys, (key) => {
|
|
const volume = prefixMap[key].key;
|
|
return _.map(list, (item) => {
|
|
const $item = $(item);
|
|
const title = $item.attr('title');
|
|
const href = $item.attr('href');
|
|
return title + '$' + href + '|' + volume;
|
|
}).join('#');
|
|
}).join('$$$');
|
|
const volumes = _.map(keys, (key) => {
|
|
return prefixMap[key].name;
|
|
}).join('$$$');
|
|
book.volumes = volumes;
|
|
book.urls = urls;
|
|
|
|
return {
|
|
list: [book],
|
|
};
|
|
}
|
|
|
|
async function play(flag, id, flags) {
|
|
try {
|
|
const info = id.split('|');
|
|
const path = info[0];
|
|
const volumeKey = info[1];
|
|
const html = await request(HOST + path);
|
|
const matches = html.match(/\[\"\\x65\\x76\\x61\\x6c\"\]\((.*)\)/);
|
|
const js = 'var result =' + matches[1] + ';result';
|
|
const data = eval(js);
|
|
const configs = data.match(/SMH\.imgData\((.*?)\)/);
|
|
const json = JSON.parse(configs[1]);
|
|
const jsBase = await js2Proxy(true, siteType, siteKey, 'img/', {});
|
|
const content = _.map(json.files, (file) => {
|
|
const playUrl = `https://${volumeKey}.hamreus.com${json.path}${file}?e=${json.sl.e}&m=${json.sl.m}`;
|
|
return jsBase + base64Encode(playUrl);
|
|
});
|
|
return {
|
|
content: content,
|
|
};
|
|
} catch (e) {
|
|
console.debug('error: ' + e);
|
|
return {
|
|
content: '',
|
|
};
|
|
}
|
|
}
|
|
|
|
function base64Encode(text) {
|
|
return Crypto.enc.Base64.stringify(Crypto.enc.Utf8.parse(text));
|
|
}
|
|
|
|
function base64Decode(text) {
|
|
return Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(text));
|
|
}
|
|
|
|
async function proxy(segments, headers) {
|
|
const what = segments[0];
|
|
const url = base64Decode(segments[1]);
|
|
if (what == 'img') {
|
|
const resp = await req(url, {
|
|
buffer: 1,
|
|
shared: 1,
|
|
headers: {
|
|
'User-Agent': PC_UA,
|
|
Referer: HOST,
|
|
},
|
|
});
|
|
delete resp.headers['transfer-encoding'];
|
|
if (resp.headers['content-encoding'] == 'gzip') {
|
|
delete resp.headers['content-encoding'];
|
|
}
|
|
return {
|
|
code: resp.code,
|
|
buffer: 3,
|
|
content: resp.content,
|
|
headers: resp.headers,
|
|
};
|
|
}
|
|
return {
|
|
code: 500,
|
|
content: '',
|
|
};
|
|
}
|
|
|
|
async function search(wd, quick, pg) {
|
|
if (pg == 0) pg = 1;
|
|
let page = '';
|
|
if (pg > 1) {
|
|
page = `_p${pg}`;
|
|
}
|
|
const link = HOST + `/s/${encodeURIComponent(wd)}${page}.html`;
|
|
const html = await request(link);
|
|
const $ = load(html);
|
|
const list = $('.book-result li.cf');
|
|
const books = _.map(list, (item) => {
|
|
const $item = $(item);
|
|
const $cover = $item.find('.book-cover');
|
|
const $a = $cover.find('a:first');
|
|
const $img = $cover.find('img:first');
|
|
const $remark = $item.find('.book-score .score-avg strong:first');
|
|
let src = $img.attr('src');
|
|
if (_.isEmpty(src)) {
|
|
src = $img.attr('data-src');
|
|
}
|
|
return {
|
|
book_id: $a.attr('href').replace(/\/comic\/(.*)\//, '$1'),
|
|
book_name: $a.attr('title'),
|
|
book_pic: 'https:' + src,
|
|
book_remarks: $remark.text(),
|
|
};
|
|
});
|
|
const hasMore = $('.pager-cont a:contains(下一页)').length > 0;
|
|
return {
|
|
page: pg,
|
|
pagecount: hasMore ? pg + 1 : pg,
|
|
list: books,
|
|
};
|
|
}
|
|
|
|
export function __jsEvalReturn() {
|
|
return {
|
|
init: init,
|
|
home: home,
|
|
category: category,
|
|
detail: detail,
|
|
play: play,
|
|
proxy: proxy,
|
|
search: search,
|
|
};
|
|
}
|