123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727 |
- globalThis.MOBILE_UA = 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36';
- globalThis.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';
- globalThis.UA = 'Mozilla/5.0';
- globalThis.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';
- globalThis.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';
- globalThis.RULE_CK = 'cookie'; // 源cookie的key值
- globalThis.CATE_EXCLUDE = '首页|留言|APP|下载|资讯|新闻|动态';
- globalThis.TAB_EXCLUDE = '猜你|喜欢|下载|剧情|榜|评论';
- globalThis.OCR_RETRY = 3;//ocr验证重试次数
- globalThis.OCR_API = 'https://api.nn.ci/ocr/b64/text';//ocr在线识别接口
- globalThis.nodata = {
- list: [{
- vod_name: '无数据,防无限请求',
- vod_id: 'no_data',
- vod_remarks: '不要点,会崩的',
- vod_pic: 'https://ghproxy.net/https://raw.githubusercontent.com/hjdhnx/dr_py/main/404.jpg'
- }],
- total: 1, pagecount: 1, page: 1, limit: 1
- };
- globalThis.SPECIAL_URL = /^(ftp|magnet|thunder|ws):/;
- globalThis.是否正版 = function (vipUrl) {
- let flag = new RegExp('qq\.com|iqiyi\.com|youku\.com|mgtv\.com|bilibili\.com|sohu\.com|ixigua\.com|pptv\.com|miguvideo\.com|le\.com|1905\.com|fun\.tv');
- return flag.test(vipUrl);
- }
- globalThis.urlDeal = function (vipUrl) {
- if (!vipUrl) {
- return ''
- }
- if (!是否正版(vipUrl)) {
- return vipUrl
- }
- if (!/miguvideo/.test(vipUrl)) {
- vipUrl = vipUrl.split('#')[0].split('?')[0];
- }
- return vipUrl
- }
- /**
- * 判断是否需要解析
- * @param url
- * @returns {number|number}
- */
- function tellIsJx(url) {
- try {
- let is_vip = !/\.(m3u8|mp4|m4a)$/.test(url.split('?')[0]) && 是否正版(url);
- return is_vip ? 1 : 0
- } catch (e) {
- return 1
- }
- }
- globalThis.tellIsJx = tellIsJx;
- globalThis.setResult = function (d) {
- if (!Array.isArray(d)) {
- return []
- }
- let vods = [];
- d.forEach(function (it) {
- let obj = {
- vod_id: it.url || '',
- vod_name: it.title || '',
- vod_remarks: it.desc || '',
- vod_content: it.content || '',
- vod_pic: it.pic_url || it.img || '',
- };
- let keys = Object.keys(it);
- if (keys.includes('tname')) {
- obj.type_name = it.tname || '';
- }
- if (keys.includes('tid')) {
- obj.type_id = it.tid || '';
- }
- if (keys.includes('year')) {
- obj.vod_year = it.year || '';
- }
- if (keys.includes('actor')) {
- obj.vod_actor = it.actor || '';
- }
- if (keys.includes('director')) {
- obj.vod_director = it.director || '';
- }
- if (keys.includes('area')) {
- obj.vod_area = it.area || '';
- }
- vods.push(obj);
- });
- return vods
- }
- globalThis.setResult2 = function (res) {
- return res.list || []
- }
- globalThis.setHomeResult = function (res) {
- if (!res || typeof (res) !== 'object') {
- return []
- }
- return setResult(res.list);
- }
- /**
- * 将base64编码进行url编译
- * @param str
- * @returns {string}
- */
- globalThis.urlencode = function (str) {
- str = (str + '').toString();
- return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
- }
- /**
- * url编码,同 encodeURI
- * @param str
- * @returns {string}
- */
- globalThis.encodeUrl = function (str) {
- if (typeof (encodeURI) == 'function') {
- return encodeURI(str)
- } else {
- str = (str + '').toString();
- return encodeURIComponent(str).replace(/%2F/g, '/').replace(/%3F/g, '?').replace(/%3A/g, ':').replace(/%40/g, '@').replace(/%3D/g, '=').replace(/%3A/g, ':').replace(/%2C/g, ',').replace(/%2B/g, '+').replace(/%24/g, '$');
- }
- }
- globalThis.uint8ArrayToBase64 = function (uint8Array) {
- let binaryString = String.fromCharCode.apply(null, Array.from(uint8Array));
- return btoa(binaryString);
- }
- globalThis.Utf8ArrayToStr = function (array) {
- var out, i, len, c;
- var char2, char3;
- out = "";
- len = array.length;
- i = 0;
- while (i < len) {
- c = array[i++];
- switch (c >> 4) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- out += String.fromCharCode(c);
- break;
- case 12:
- case 13:
- char2 = array[i++];
- out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f));
- break;
- case 14:
- char2 = array[i++];
- char3 = array[i++];
- out += String.fromCharCode(
- ((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0)
- );
- break;
- }
- }
- return out;
- }
- /**
- * gzip压缩base64|压缩率80%+
- * @param str
- * @returns {string}
- */
- globalThis.gzip = function (str) {
- let arr = pako.gzip(str, {
- // to: 'string'
- });
- return uint8ArrayToBase64(arr)
- }
- /**
- * gzip解压base64数据
- * @param b64Data
- * @returns {string}
- */
- globalThis.ungzip = function (b64Data) {
- let strData = atob(b64Data);
- const charData = strData.split('').map(function (x) {
- return x.charCodeAt(0);
- });
- const binData = new Uint8Array(charData);
- const data = pako.inflate(binData);
- return Utf8ArrayToStr(data);
- }
- /**
- * 字符串按指定编码
- * @param input
- * @param encoding
- * @returns {*}
- */
- globalThis.encodeStr = function (input, encoding) {
- encoding = encoding || 'gbk';
- if (encoding.startsWith('gb')) {
- const strTool = gbkTool();
- input = strTool.encode(input);
- }
- return input
- }
- /**
- * 字符串指定解码
- * @param input
- * @param encoding
- * @returns {*}
- */
- globalThis.decodeStr = function (input, encoding) {
- encoding = encoding || 'gbk';
- if (encoding.startsWith('gb')) {
- const strTool = gbkTool();
- input = strTool.decode(input);
- }
- return input
- }
- globalThis.getCryptoJS = function () {
- // return request('https://ghproxy.net/https://raw.githubusercontent.com/hjdhnx/dr_py/main/libs/crypto-hiker.js');
- return 'console.log("CryptoJS已装载");'
- }
- // 封装的RSA加解密类
- globalThis.RSA = {
- decode: function (data, key, option) {
- option = option || {};
- if (typeof (JSEncrypt) === 'function') {
- let chunkSize = option.chunkSize || 117; // 默认分段长度为117
- let privateKey = this.getPrivateKey(key); // 获取私钥
- const decryptor = new JSEncrypt(); //创建解密对象实例
- decryptor.setPrivateKey(privateKey); //设置秘钥
- let uncrypted = '';
- // uncrypted = decryptor.decrypt(data);
- uncrypted = decryptor.decryptUnicodeLong(data);
- return uncrypted;
- } else {
- return false
- }
- },
- encode: function (data, key, option) {
- option = option || {};
- if (typeof (JSEncrypt) === 'function') {
- let chunkSize = option.chunkSize || 117; // 默认分段长度为117
- let publicKey = this.getPublicKey(key); // 获取公钥
- const encryptor = new JSEncrypt();
- encryptor.setPublicKey(publicKey); // 设置公钥
- let encrypted = ''; // 加密结果
- // const textLen = data.length; // 待加密文本长度
- // let offset = 0; // 分段偏移量
- // // 分段加密
- // while (offset < textLen) {
- // let chunk = data.slice(offset, chunkSize); // 提取分段数据
- // let enc = encryptor.encrypt(chunk); // 加密分段数据
- // encrypted += enc; // 连接加密结果
- // offset += chunkSize; // 更新偏移量
- // }
- encrypted = encryptor.encryptUnicodeLong(data);
- return encrypted
- } else {
- return false
- }
- },
- fixKey(key, prefix, endfix) {
- if (!key.includes(prefix)) {
- key = prefix + key;
- }
- if (!key.includes(endfix)) {
- key += endfix
- }
- return key
- },
- getPrivateKey(key) {
- let prefix = '-----BEGIN RSA PRIVATE KEY-----';
- let endfix = '-----END RSA PRIVATE KEY-----';
- return this.fixKey(key, prefix, endfix);
- },
- getPublicKey(key) {
- let prefix = '-----BEGIN PUBLIC KEY-----';
- let endfix = '-----END PUBLIC KEY-----';
- return this.fixKey(key, prefix, endfix);
- }
- };
- /**
- * 智能对比去除广告。支持嵌套m3u8。只需要传入播放地址
- * @param m3u8_url m3u8播放地址
- * @param headers 自定义访问m3u8的请求头,可以不传
- * @returns {string}
- */
- globalThis.fixAdM3u8Ai = async function (m3u8_url, headers) {
- let ts = (new Date).getTime();
- let option = headers ? {
- headers: headers
- } : {};
- function b(s1, s2) {
- let i = 0;
- while (i < s1.length) {
- if (s1[i] !== s2[i]) {
- break
- }
- i++
- }
- return i
- }
- function reverseString(str) {
- return str.split("").reverse().join("")
- }
- let m3u8 = (await req(m3u8_url, option)).content;
- m3u8 = m3u8.trim().split("\n").map(it => it.startsWith("#") ? it : urljoin(m3u8_url, it)).join("\n");
- m3u8 = m3u8.replace(/\n\n/gi, "\n");
- let last_url = m3u8.split("\n").slice(-1)[0];
- if (last_url.length < 5) {
- last_url = m3u8.split("\n").slice(-2)[0]
- }
- if (last_url.includes(".m3u8") && last_url !== m3u8_url) {
- m3u8_url = urljoin(m3u8_url, last_url);
- log("嵌套的m3u8_url:" + m3u8_url);
- m3u8 = (await req(m3u8_url, option)).content;
- }
- let s = m3u8.trim().split("\n").filter(it => it.trim()).join("\n");
- let ss = s.split("\n");
- let firststr = "";
- let maxl = 0;
- let kk = 0;
- let kkk1 = 1;
- let kkk2 = 0;
- let secondstr = "";
- for (let i = 0; i < ss.length; i++) {
- let s = ss[i];
- if (!s.startsWith("#")) {
- if (kk == 0)
- firststr = s;
- if (kk > 0) {
- if (maxl > b(firststr, s) + 1) {
- if (secondstr.length < 5)
- secondstr = s;
- kkk2++
- } else {
- maxl = b(firststr, s);
- kkk1++
- }
- }
- kk++;
- if (kk >= 30)
- break
- }
- }
- if (kkk2 > kkk1)
- firststr = secondstr;
- let firststrlen = firststr.length;
- let ml = Math.round(ss.length / 2).toString().length;
- let maxc = 0;
- let laststr = ss.toReversed().find(x => {
- if (!x.startsWith("#")) {
- let k = b(reverseString(firststr), reverseString(x));
- maxl = b(firststr, x);
- maxc++;
- if (firststrlen - maxl <= ml + k || maxc > 10) {
- return true
- }
- }
- return false
- }
- );
- log("最后一条切片:" + laststr);
- let ad_urls = [];
- for (let i = 0; i < ss.length; i++) {
- let s = ss[i];
- if (!s.startsWith("#")) {
- if (b(firststr, s) < maxl) {
- ad_urls.push(s);
- ss.splice(i - 1, 2);
- i = i - 2
- } else {
- ss[i] = urljoin(m3u8_url, s)
- }
- } else {
- ss[i] = s.replace(/URI=\"(.*)\"/, 'URI="' + urljoin(m3u8_url, "$1") + '"')
- }
- }
- log("处理的m3u8地址:" + m3u8_url);
- log("----广告地址----");
- log(ad_urls);
- m3u8 = ss.join("\n");
- log("处理耗时:" + ((new Date).getTime() - ts).toString());
- log(m3u8);
- return m3u8
- }
- /**
- * 强制正序算法
- * @param lists 待正序列表
- * @param key 正序键
- * @param option 单个元素处理函数
- * @returns {*}
- */
- globalThis.forceOrder = function (lists, key, option) {
- let start = Math.floor(lists.length / 2);
- let end = Math.min(lists.length - 1, start + 1);
- if (start >= end) {
- return lists;
- }
- let first = lists[start];
- let second = lists[end];
- if (key) {
- try {
- first = first[key];
- second = second[key];
- } catch (e) {
- }
- }
- if (option && typeof (option) === 'function') {
- try {
- first = option(first);
- second = option(second);
- } catch (e) {
- }
- }
- first += '';
- second += '';
- // console.log(first,second);
- if (first.match(/(\d+)/) && second.match(/(\d+)/)) {
- let num1 = Number(first.match(/(\d+)/)[1]);
- let num2 = Number(second.match(/(\d+)/)[1]);
- if (num1 > num2) {
- lists.reverse();
- }
- }
- return lists
- }
- /**
- * 获取链接的query请求转为js的object字典对象
- * @param url
- * @returns {{}}
- */
- globalThis.getQuery = function (url) {
- try {
- if (url.indexOf('?') > -1) {
- url = url.slice(url.indexOf('?') + 1);
- }
- let arr = url.split("#")[0].split("&");
- const resObj = {};
- arr.forEach(item => {
- let arr1 = item.split("=");
- let key = arr1[0];
- let value = arr1.slice(1).join('=');
- resObj[key] = value;
- });
- return resObj;
- } catch (err) {
- log(`getQuery发生错误:${e.message}`)
- return {};
- }
- }
- const defaultParser = {
- pdfh: pdfh,
- pdfa: pdfa,
- pd: pd,
- };
- const parseTags = {
- jsp: {
- pdfh: pdfh,
- pdfa: pdfa,
- pd: pd,
- },
- json: {
- pdfh(html, parse) {
- if (!parse || !parse.trim()) {
- return '';
- }
- if (typeof (html) === 'string') {
- // print('jsonpath:pdfh字符串转dict');
- html = JSON.parse(html);
- }
- parse = parse.trim();
- if (!parse.startsWith('$.')) {
- parse = '$.' + parse;
- }
- parse = parse.split('||');
- for (let ps of parse) {
- let ret = cheerio.jp(ps, html);
- if (Array.isArray(ret)) {
- ret = ret[0] || '';
- } else {
- ret = ret || ''
- }
- if (ret && typeof (ret) !== 'string') {
- ret = ret.toString();
- }
- if (ret) {
- return ret
- }
- }
- return '';
- },
- pdfa(html, parse) {
- if (!parse || !parse.trim()) {
- return '';
- }
- if (typeof (html) === 'string') {
- // print('jsonpath:pdfa字符串转dict');
- html = JSON.parse(html);
- }
- parse = parse.trim()
- if (!parse.startsWith('$.')) {
- parse = '$.' + parse;
- }
- let ret = cheerio.jp(parse, html);
- if (Array.isArray(ret) && Array.isArray(ret[0]) && ret.length === 1) {
- return ret[0] || []
- }
- return ret || []
- },
- pd(html, parse) {
- let ret = parseTags.json.pdfh(html, parse);
- if (ret) {
- return urljoin(MY_URL, ret);
- }
- return ret
- },
- },
- jq: {
- pdfh(html, parse) {
- if (!html || !parse || !parse.trim()) {
- return ''
- }
- parse = parse.trim();
- let result = defaultParser.pdfh(html, parse);
- // print(`pdfh解析${parse}=>${result}`);
- return result;
- },
- pdfa(html, parse) {
- if (!html || !parse || !parse.trim()) {
- return [];
- }
- parse = parse.trim();
- let result = defaultParser.pdfa(html, parse);
- // print(result);
- print(`pdfa解析${parse}=>${result.length}`);
- return result;
- },
- pd(html, parse, base_url) {
- if (!html || !parse || !parse.trim()) {
- return ''
- }
- parse = parse.trim();
- base_url = base_url || MY_URL;
- return defaultParser.pd(html, parse, base_url);
- },
- },
- getParse(p0) {//非js开头的情况自动获取解析标签
- if (p0.startsWith('jsp:')) {
- return this.jsp
- } else if (p0.startsWith('json:')) {
- return this.json
- } else if (p0.startsWith('jq:')) {
- return this.jq
- } else {
- return this.jq
- }
- }
- };
- globalThis.stringify = JSON.stringify;
- // const jsp = parseTags.jsp;
- // const jq = parseTags.jq;
- /**
- * 处理返回的json数据
- * @param html
- * @returns {*}
- */
- globalThis.dealJson = function (html) {
- try {
- // html = html.match(/[\w|\W|\s|\S]*?(\{[\w|\W|\s|\S]*\})/).group[1];
- html = html.trim();
- if (!((html.startsWith('{') && html.endsWith('}')) || (html.startsWith('[') && html.endsWith(']')))) {
- html = '{' + html.match(/.*?\{(.*)\}/m)[1] + '}';
- }
- } catch (e) {
- }
- try {
- html = JSON.parse(html);
- } catch (e) {
- }
- // console.log(typeof(html));
- return html;
- }
- /**
- * 验证码识别逻辑,需要java实现(js没有bytes类型,无法调用后端的传递图片二进制获取验证码文本的接口)
- * @type {{api: string, classification: (function(*=): string)}}
- */
- globalThis.OcrApi = {
- api: OCR_API,
- classification: async function (img) { // img是byte类型,这里不方便搞啊
- let code = '';
- try {
- // let html = request(this.api,{data:{img:img},headers:{'User-Agent':PC_UA},'method':'POST'},true);
- // html = JSON.parse(html);
- // code = html.url||'';
- log('通过drpy_ocr验证码接口过验证...');
- let html = '';
- if (this.api.endsWith('drpy/text')) {
- html = (await req(this.api, {
- data: {img: img},
- headers: {'User-Agent': PC_UA},
- 'method': 'POST'
- })).content;
- } else {
- html = (await req(this.api, {body: img, headers: {'User-Agent': PC_UA}, 'method': 'POST'})).content;
- }
- code = html || '';
- } catch (e) {
- log(`OCR识别验证码发生错误:${e.message}`)
- }
- return code
- }
- };
- /**
- * 获取链接的host(带http协议的完整链接)
- * @param url 任意一个正常完整的Url,自动提取根
- * @returns {string}
- */
- globalThis.getHome = function (url) {
- if (!url) {
- return ''
- }
- let tmp = url.split('//');
- url = tmp[0] + '//' + tmp[1].split('/')[0];
- try {
- url = decodeURIComponent(url);
- } catch (e) {
- }
- return url
- }
- /**
- * get参数编译链接,类似python params字典自动拼接
- * @param url 访问链接
- * @param obj 参数字典
- * @returns {*}
- */
- globalThis.buildUrl = function (url, obj) {
- obj = obj || {};
- if (url.indexOf('?') < 0) {
- url += '?'
- }
- let param_list = [];
- let keys = Object.keys(obj);
- keys.forEach(it => {
- param_list.push(it + '=' + obj[it])
- });
- let prs = param_list.join('&');
- if (keys.length > 0 && !url.endsWith('?')) {
- url += '&'
- }
- url += prs;
- return url
- }
- /**
- * 远程依赖执行函数
- * @param url 远程js地址
- */
- function $require(url) {
- eval(request(url));
- }
- //字符串To对象
- globalThis.parseQueryString = function (query) {
- const params = {};
- query.split('&').forEach(function (part) {
- // 使用正则表达式匹配键和值,直到遇到第一个等号为止
- const regex = /^(.*?)=(.*)/;
- const match = part.match(regex);
- if (match) {
- const key = decodeURIComponent(match[1]);
- const value = decodeURIComponent(match[2]);
- params[key] = value;
- }
- });
- return params;
- }
- //URL需要转码字符串
- globalThis.encodeIfContainsSpecialChars = function (value) {
- // 定义在URL中需要编码的特殊字符
- const specialChars = ":/?#[]@!$'()*+,;=%";
- // 检查值中是否包含特殊字符
- if (specialChars.split('').some(char => value.toString().includes(char))) {
- // 如果包含,则使用encodeURIComponent进行编码
- return encodeURIComponent(value);
- }
- // 如果不包含特殊字符,返回原值
- return value;
- }
- //对象To字符串
- globalThis.objectToQueryString = function (obj) {
- const encoded = [];
- for (let key in obj) {
- if (obj.hasOwnProperty(key)) {
- encoded.push(encodeURIComponent(key) + '=' + encodeIfContainsSpecialChars(obj[key]));
- }
- }
- return encoded.join('&');
- }
|