import { Crypto, load, _ } from 'assets://js/lib/cat.js'; /** * 发布页:https://kan80.app/ */ const MOBILE_UA = 'Mozilla/5.0 (Linux; Android 11; M2007J3SC Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045714 Mobile Safari/537.36'; 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'; const UA = 'Mozilla/5.0'; const UC_UA = 'Mozilla/5.0 (Linux; U; Android 9; zh-CN; MI 9 Build/PKQ1.181121.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.5.5.1035 Mobile Safari/537.36'; const IOS_UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'; const RULE_CK = 'cookie'; // 源cookie的key值 let html = ''; var charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789'; let HOST = ''; let validUrl = HOST + '/index.php/verify/index.html?'; let validCheckUrl = 'https://www.hdmyy.com/index.php/ajax/verify_check?type=search&verify=' let siteKey = ''; let siteType = 0; let COOKIE = 'PHPSESSID=' + randStr(26, true); let maxRetryTime = 5; let currentRetryTime = 0; let parseUrl = []; var rule = {}; let ext = {}; let classes = []; let videos = []; let videoDetail = {}; let filterObj = {}; let pagecount = 999; let page = 1; let classId = ''; let flagParse = {}; let playFlag; let playUrl = ''; let searchUrl = ''; let input = ''; let timeout = 10000; let headers = { 'User-Agent': PC_UA, 'Referer': HOST, 'Cookie': COOKIE }; async function request(reqUrl, data, header, method) { let res = await req(reqUrl, { method: method || 'get', data: data || '', headers: header || headers, postType: method === 'post' ? 'form-data' : '', timeout: timeout, }); return res.content; } // cfg = {skey: siteKey, ext: extend} async function init(cfg) { siteKey = cfg.skey; siteType = cfg.stype; if (cfg.ext) { await parseRule(cfg.ext);//解析规则 headers.Referer = HOST; } if (rule.initHost) { html = await request(HOST); if (html.indexOf('document.cookie = ') > 0) { COOKIE = html.match(/document.cookie = "(.*?)"/)[1]; //console.log('cookie', COOKIE); html = await request(HOST); } } //await parseHost();//解析HOST主页地址 } async function parseRule(ext) { let ruleText = ''; if(typeof(ext) == 'string' && ext.startsWith('http')) { ruleText = await request(ext); eval(ruleText); } else { rule = ext; } //console.log('rule', rule); await parseHost(); } async function parseHost() { //console.log('rule', rule); //rule.hostJs = 'const host = "http://baidu.com";request(host)||console.log("html", html)' //console.log('host', rule.host); if(rule.host) { HOST = rule.host; } if(rule.headers) { Object.assign(headers, rule.headers); } if(rule.timeout) timeout = rule.timeout; const initParse = rule.initJs || rule.hostJs; if(initParse) { const split = initParse.split('||'); for(let i = 0; i < split.length; i++) { if(split[i].indexOf('request(') >= 0) { html = await eval(split[i]); } else { eval(split[i]); } } } //console.log('HOST', HOST); } async function home(filter) { classes = []; if (rule.class_name) { let class_name = rule.class_name.split('&'); for (let i = 0; i < class_name.length; i++) { let type_id = rule.class_url.split('&')[i]; classes.push({'type_id':type_id,'type_name':class_name[i]}); } } else if (rule.class_parse) { let homeUrl = rule.homeUrl; if (homeUrl) { if (homeUrl.startsWith('/')) { homeUrl = HOST + homeUrl; } html = await request(homeUrl); } const $ = load(html); const split = rule.class_parse.split(';'); _.forEach($(split[0]), item => { let typeId = getCssVal($, item, split[2]); let typeName = getCssVal($, item, split[1]); classes.push({'type_id':typeId,'type_name':typeName}); }); } if (rule.filter) { filterObj = rule.filter; } if (rule.homeJS) { await evalCustomerJs(rule.homeJS); } //let classes = [{'type_id':1,'type_name':'电影'},{'type_id':2,'type_name':'电视剧'},{'type_id':3,'type_name':'综艺'},{'type_id':4,'type_name':'动漫'},{'type_id':63,'type_name':'纪录片'}]; //let filterObj = return JSON.stringify({ class: classes, filters: filterObj, }); } /** * css选择器获取属性值方法 * $: js选择器驱动 * item: 父节点表达式 * parse:子节点表达式&&值属性&&正则表达式 */ function getCssVal($, item, parse) { if (!parse) return ''; let xpa = parse.split('&&'); if (!xpa || xpa.length < 2) return ''; let el; if(item) { if (xpa[0]) { el = $(item).find(xpa[0]); } else { el = $(item); } } else { el = $(xpa[0]); } let v = ''; //console.log('xpa[1]', xpa[1]); if (xpa[1].indexOf('||') > 0) { const attrs = xpa[1].split('||'); v = $(el).attr(attrs[0]) || $(el).attr(attrs[1]); } else if(xpa[1] == 'Text') { v = $(el).text().trim(); } else { v = $(el).attr(xpa[1]); } if(xpa[2]) { const match = v.match(new RegExp(xpa[2])); if (match) v = match[1]; } return v; } function getCssValArray($, item, parse) { if (!parse) return ''; let xpa = parse.split('&&'); if (!xpa || xpa.length < 2) return ''; let val = []; let el; if(item) { if (xpa[0]) { el = $(item).find(xpa[0]); } else { el = $(item); } } else { el = $(xpa[0]); } _.forEach(el, item => { let v = ''; if (xpa[1].indexOf('||') > 0) { const attrs = xpa[1].split('||'); v = $(item).attr(attrs[0]) || $(item).attr(attrs[0]); } else if(xpa[1] == 'Text') { v = $(item).text().trim(); } else { v = $(item).attr(xpa[1]); } if(xpa[2]) { const match = v.match(new RegExp(xpa[2])); if (match) v = match[1]; } if (v) { val.push(v); } }); return val; } async function homeVod() { videos = []; const vodParse = rule.homeVod || rule.推荐; const vodParseJS = rule.homeVodJS || rule.推荐JS; if (vodParse) { let url = HOST; if(rule.homeUrl && rule.homeUrl.startsWith('/')) { url = HOST + rule.homeUrl; } else if (rule.homeUrl && rule.homeUrl.startsWith('http')) { url = rule.homeUrl; } const $ = load(await request(url)); videos = getVideoByCssParse($, vodParse); return JSON.stringify({ list: videos, }); } else if(vodParseJS) { await evalCustomerJs(vodParseJS); return JSON.stringify({ list: videos, }); } } function getVideoByCssParse($, cssParse) { let videos = []; const split = cssParse.split(';'); _.forEach($(split[0]), item => { let vod_id = getCssVal($, item, split[2]); if(vod_id) { let pic = getCssVal($, item, split[3]); if(rule.picHost) pic = rule.picHost + pic; if(pic.startsWith('/')) pic = HOST + pic; videos.push({ vod_id: vod_id, vod_name: getCssVal($, item, split[1]), vod_pic: pic, vod_remarks: getCssVal($, item, split[4]), }) } }); return videos; } async function category(tid, pg, filter, extend) { videos = []; if (pg <= 0) pg = 1; classId = tid; ext = extend; page = pg; if(rule.url) { let url = rule.url.replaceAll('fypage', page).replaceAll('fyclass', tid); if (!url.startsWith('http')) { url = HOST + url; } const regex = /\{\{(.*?)\}\}/g; const matches = url.match(regex); if(matches) { _.forEach(matches, match => { let param = match.replace(/\{\{(.*?)\}\}/, '$1').trim(); url = url.replace(match, extend[param] || ''); }); } //console.log('cate url', url); html = await request(url); //console.log('cate res', res); const vodParse = rule.一级 || rule.categoryVod; if (vodParse) { const $ = load(html); videos = getVideoByCssParse($, vodParse); return JSON.stringify({ list: videos, filters: filterObj, page: page, pagecount: pagecount, }); } } const vodParseJS = rule.一级JS || rule.categoryVodJS; if(vodParseJS) { await evalCustomerJs(vodParseJS); return JSON.stringify({ list: videos, filters: filterObj, page: page, pagecount: pagecount, }); } return '{}'; } async function detail(id) { videos = []; input = id; let url = id; if (rule.detailUrl) url = rule.detailUrl; if(url.startsWith('/')) url = HOST + url; url = url.replace('fyid', id); const vod = { } const parse = rule.二级 || rule.detailVod; const jsCode = rule.二级JS || rule.detailVodJS; if (parse) { html = await request(url); const $ = load(html); if ('object' === typeof(parse)) { if (parse['director']) { vod.vod_director = getCssValArray($,'',parse['director']).join(' '); } if(parse['actor']) { vod.vod_actor = getCssValArray($,'',parse['actor']).join(' '); } if(parse['area']) { vod.vod_area = getCssVal($, '', parse['area']); } if(parse['year']) { vod.vod_year = getCssVal($, '', parse['year']); } if(parse['remarks']) { vod.vod_remarks = getCssVal($, '', parse['remarks']); } if(parse['content']) { vod.vod_content = '关注公众号【蹲街捏蚂蚁】\r\n' + getCssVal($, '', parse['content']); } if (parse['type_name']) { vod.type_name = getCssValArray($, '', parse['type_name']).join('/'); } if (parse['playFrom'] && parse['playUrl']) { const playMap = {}; const tabNames = getCssValArray($, '', parse['playFrom']); //console.log('playFrom', tabNames); const split = parse['playUrl'].split(';'); const tabs = $(split[0]); _.each(tabs, (tab,i) => { //console.log('tab_exclude', parse['tab_exclude'].indexOf(tabNames[i])); if(rule['tab_exclude'] && rule['tab_exclude'].indexOf(tabNames[i]) > -1) { return; } _.each($(tab).find(split[1] || 'a'), it => { const title = getCssVal($, it, split[2]); const playUrl = getCssVal($, it, split[3]); if(!playMap.hasOwnProperty(tabNames[i])) { playMap[tabNames[i]] = []; } playMap[tabNames[i]].push(title + '$' + playUrl); }); }); vod.vod_play_from = _.keys(playMap).join('$$$'); let idx = vod.vod_play_from.indexOf('$$$'); if(idx == -1) {vod.vod_play_from = '公众号【蹲街捏蚂蚁】'} else {vod.vod_play_from = '公众号【蹲街捏蚂蚁】'+ vod.vod_play_from.substr(idx);} const urls = _.values(playMap); const vod_play_url = _.map(urls, (urlist) => { return urlist.join('#'); }); vod.vod_play_url = vod_play_url.join('$$$'); } } return JSON.stringify({ list: [vod], }); } else if(jsCode) { videoDetail = {}; await evalCustomerJs(jsCode); } return JSON.stringify({ list: videos, }); } async function play(flag, id, flags) { let url = id; playFlag = flag; input = id; if (url.startsWith('magnet:')) { return JSON.stringify({ parse: 0, url: url, }); } if (url.startsWith('/')) { url = HOST + url; } playUrl = url; if (rule.lazy) { try { await evalCustomerJs(rule.lazy); return JSON.stringify({ parse: 0, url: playUrl, header: headers }); } catch(error) { console.log(error); } } if(/\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)$/.test(playUrl.split('?')[0])) { return JSON.stringify({ parse: 0, url: playUrl, header: headers }); } try { html = await request(url); const json = getPlay4aJson(html); if (json) { let js = JSON.parse(json); playUrl = js.url; if (js.encrypt == 1) { playUrl = unescape(playUrl); } else if (js.encrypt == 2) { playUrl = unescape(base64Decode(playUrl)); } } if(/\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)$/.test(playUrl.split('?')[0])) { return JSON.stringify({ parse: 0, url: playUrl, header: headers }); } } catch(error) { console.log(error); } return JSON.stringify({ parse: 1, url: playUrl, }); } function getPlay4aJson(html) { let $ = load(html); return $('script:contains(player_aaaa)').text().replace('var player_aaaa=',''); } function base64Decode(text) { return Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(text)); } //aes加密 function aesEncode(str, keyStr, ivStr, type) { const key = Crypto.enc.Utf8.parse(keyStr); let encData = Crypto.AES.encrypt(str, key, { iv: Crypto.enc.Utf8.parse(ivStr), mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7 }); if (type === 'hex') return encData.ciphertext.toString(Crypto.enc.Hex); return encData.toString(Crypto.enc.Utf8); } //aes解密 function aesDecode(str, keyStr, ivStr, type) { const key = Crypto.enc.Utf8.parse(keyStr); if (type === 'hex') { str = Crypto.enc.Hex.parse(str); return Crypto.AES.decrypt({ ciphertext: str }, key, { iv: Crypto.enc.Utf8.parse(ivStr), mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7 }).toString(Crypto.enc.Utf8); } else { return Crypto.AES.decrypt(str, key, { iv: Crypto.enc.Utf8.parse(ivStr), mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7 }).toString(Crypto.enc.Utf8); } } function md5(text) { return Crypto.MD5(text).toString(); } function sha1(text) { return Crypto.SHA1(text).toString(); } async function search(wd, quick, pg) { try{ videos = []; input = wd; if (!pg) pg = ''; let url = '/search.php?searchword=' + wd; if(rule.searchUrl) url = rule.searchUrl; url = url.replace('**', wd).replace('fypage', page); if(!url.startsWith('http')) url = HOST + url; searchUrl = url; if(rule.searchVodJS) { //执行自定义js await evalCustomerJs(rule.searchVodJS); } else if (rule.searchVod) { let html = await request(url); //按css选择器组装数据 const $ = load(html); videos = getVideoByCssParse($, rule.searchVod) } return JSON.stringify({ list: videos, }); // const $ = load(html); // const title = $('title').text(); // if(currentRetryTime >= maxRetryTime) { // currentRetryTime = 0; // return '{}'; // } // if(title === '系统安全验证') { // currentRetryTime = currentRetryTime + 1; // if(currentRetryTime >= 1) { // await sleep(5000); // } // await validCode(validUrl); // return await search(wd, quick, pg); // } else { // const cards = $('div.module-item-pic'); // let videos = _.map(cards, (n) => { // let id = $($(n).find('a')[0]).attr('href'); // let name = $($(n).find('a')[0]).attr('title').replaceAll('立刻播放', ''); // let pic = $($(n).find('img')[0]).attr('data-src'); // return { // vod_id: id, // vod_name: name, // vod_pic: pic, // vod_remarks: '', // }; // }); // return JSON.stringify({ // list: videos, // }); // } currentRetryTime = 0; } catch(error) { console.log(error); currentRetryTime = 0; return '{}'; } } async function validCode(url) { try { //获取验证码的base64 const res = await req(url, { buffer: 2, headers: { 'User-Agent': UA, 'Referer': HOST, 'Cookie': COOKIE } }); const response = await req('https://api.nn.ci/ocr/b64/text', { method: 'post', data: res.content, headers: { 'Content-Type': 'text/plain', }, }); if(response['code'] === 200) { let checkRes = await request(validCheckUrl + response.content); } } catch (error) { console.error(error); } } function randStr(len, withNum) { var _str = ''; let containsNum = withNum === undefined ? true : withNum; for (var i = 0; i < len; i++) { let idx = _.random(0, containsNum ? charStr.length - 1 : charStr.length - 11); _str += charStr[idx]; } return _str; } function sleep(ms) { //return new Promise(resolve => setTimeout(resolve, ms)); let now = new Date(); const exitTime = now.getTime() + ms; while(true) { now = new Date(); if(now.getTime() > exitTime) return; } } async function evalCustomerJs(jsCode) { const split = jsCode.split('|||'); for(let i = 0; i < split.length; i++) { if(split[i].indexOf('request(') >= 0) { html = await eval(split[i]); } else { eval(split[i]); } } } export function __jsEvalReturn() { return { init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search, validCode: validCode, }; }