diff --git a/js/keyun.js b/js/keyun.js new file mode 100644 index 0000000..be28f0e --- /dev/null +++ b/js/keyun.js @@ -0,0 +1,276 @@ +import { Crypto,_} from 'assets://js/lib/cat.js'; +let siteUrl = 'https://sc1080.top'; +let key = 'e59d44b2eef03ba2'; +let iv = 'e59d44b2eef03ba2'; +let siteKey = ''; +let siteType = 0; +let headers = { + 'User-Agent': 'okhttp/3.14.9', + 'app-user-device-id': '', + 'app-version-code': '100', +}; + +let parseMap = {}; +let homeVods = []; +async function request(reqUrl, data, header, method) { + let res = await req(reqUrl, { + method: method || 'get', + data: data || '', + headers: header || headers, + postType: method === 'post' ? 'form' : '', + timeout: 30000, + }); + return res.content; +} + +async function init(cfg) { + siteKey = cfg.skey; + siteType = cfg.stype; + if (cfg.ext) { + siteUrl = cfg.ext.split('|')[0]; + key = cfg.ext.split('|')[1]; + iv = cfg.ext.split('|')[2]; + } +} + +async function home(filter) { + let rets = JSON.parse(await request(siteUrl + '/api.php/getappapi.index/init')).data; + //console.log(rets); + let data = JSON.parse(aesDecode(rets, key, iv)); + //console.log(data); + homeVods = homeVods.concat(data.banner_list); + let filters = {}; + let classes = []; + _.forEach(data.type_list, item => { + if (item.type_id > 0) { + homeVods = homeVods.concat(item.recommend_list); + } + classes.push({ + type_id: item.type_id, + type_name: item.type_name, + }); + filters[item.type_id] = item.type_name; + let filterList = []; + _.forEach(item.filter_type_list, f => { + let filter = {}; + if (f.name === 'class') { + filter['name'] = '分类'; + filter['key'] = f.name; + filter['value'] = _.map(f.list, i => { + return {v:i,n:i}; + }); + } + if (f.name === 'area') { + filter['name'] = '区域'; + filter['key'] = f.name; + filter['value'] = _.map(f.list, i => { + return {v:i,n:i}; + }); + + } + if (f.name === 'lang') { + filter['name'] = '语言'; + filter['key'] = f.name; + filter['value'] = _.map(f.list, i => { + return {v:i,n:i}; + }); + + } + if (f.name === 'year') { + filter['name'] = '年份'; + filter['key'] = f.name; + filter['value'] = _.map(f.list, i => { + return {v:i,n:i}; + }); + + } + if (f.name === 'sort') { + filter['name'] = '排序'; + filter['key'] = f.name; + filter['value'] = _.map(f.list, i => { + return {v:i,n:i}; + }); + } + filterList.push(filter); + }); + filters[item.type_id] = filterList; + }); + return JSON.stringify({ + 'class': classes, + 'filters': filters, + }); +} + +async function homeVod() { + return JSON.stringify({ + list: homeVods, + }); + +} + +async function category(tid, pg, filter, extend) { + if(pg <= 0) pg = 1; + let url = `${siteUrl}/api.php/getappapi.index/typeFilterVodList`; + let params = { + "area": extend['area'] || "全部", + "sort": extend['sort'] || "最新", + "class": extend['class'] || "全部", + "type_id": tid, + "year": extend['year'] || "全部", + "lang": extend['lang'] || '全部', + "page": pg, + } + let encData = JSON.parse(await request(url, params, '', 'post')).data; + //console.log(encData); + let videos = JSON.parse(aesDecode(encData,key, iv)).recommend_list; + + return JSON.stringify({ + page: pg, + pagecount: 9999, + list: videos, + }); +} + +async function detail(id) { + let url = `${siteUrl}/api.php/getappapi.index/vodDetail`; + let info = JSON.parse(aesDecode(JSON.parse(await request(url, {vod_id: id},'', 'post')).data, key, iv)); + //console.log(info); + let videos = { + vod_id: info.vod.vod_id, + vod_name: info.vod.vod_name, + vod_area: info.vod.vod_area, + vod_director: info.vod.vod_director, + vod_actor: info.vod.vod_actor, + vod_pic: info.vod.vod_pic, + vod_content: info.vod.vod_content, + type_name: info.vod.vod_class, + vod_year: info.vod.vod_year + + } + let froms = []; + let urls = []; + _.forEach(info.vod_play_list, item => { + froms.push(item['player_info']['show']); + let parse = item['player_info']['parse']; + let nameUrls = []; + _.forEach(item['urls'], item2 => { + nameUrls.push(item2['name'] + '$' + item2['url']+ '&' + parse +'&'+ item2['token']); + }); + urls.push(nameUrls.join('#')); + }); + videos.vod_play_from = froms.join('$$$'); + videos.vod_play_url = urls.join('$$$'); + return JSON.stringify({ + list: [videos], + }); +} + +async function play(flag, id, flags) { + let playUrl = id.split('&')[0]; + let parse = id.split('&')[1]; + let token = id.split('&')[2]; + if (playUrl.indexOf('m3u8') > 0 || playUrl.indexOf('mp4') > 0) { + return JSON.stringify({ + parse: 0, + url: playUrl, + }); + } + + if(parse.startsWith("http")) { + let parseUrl = parse + playUrl; + if (token) { + parseUrl = parseUrl + '&token=' + token; + } + let rets = await request(parseUrl); + if (rets.indexOf('DOCTYPE html') > -1) { + return JSON.stringify({ + parse: 1, + url: parseUrl, + }); + } + let parseJson = JSON.parse(rets); + return JSON.stringify({ + parse: 0, + url: parseJson['url'] || parseJson['data']['url'], + }); + } + let params = { + 'parse_api': parse, + 'url': aesEncode(playUrl, key, iv), + 'token': token, + } + //console.log(params); + let rets = (await req(`${siteUrl}/api.php/getappapi.index/vodParse`, {data:params, method:'post',postType:'form'})).content; + //console.log(rets); + let url = aesDecode(JSON.parse(rets).data, key, iv); + //console.log(url); + return JSON.stringify({ + parse: 0, + url: JSON.parse(JSON.parse(url).json).url, + }); +} + +async function search(wd, quick, pg) { + let params = { + 'page': '1', + 'type_id': '0', + 'keywords': wd, + } + let url = `${siteUrl}/api.php/getappapi.index/searchList` + let encData = await request(url, params, '', 'post'); + let videos = JSON.parse(aesDecode(JSON.parse(encData).data, key, iv)).search_list; + return JSON.stringify({ + list: videos, + }); +} + +//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); + } + } + + //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(); + } + + //console.log(aesEncode('https://v.qq.com/x/cover/mzc0020036hmb1h/c4100605x48.html', key, iv)); + +function md5(text) { + return Crypto.MD5(text).toString(); +} + +export function __jsEvalReturn() { + return { + init: init, + home: home, + homeVod: homeVod, + category: category, + detail: detail, + play: play, + search: search, + }; +} \ No newline at end of file diff --git a/js/pp.js b/js/pp.js new file mode 100644 index 0000000..ce03aca --- /dev/null +++ b/js/pp.js @@ -0,0 +1,22 @@ +rule = { + name: '皮皮虾影视', + host: 'http://ppxys.vip', + class_name: '剧集&电影&动漫', + class_url: '1&2&3', + homeVod: 'div.module-items > a;&&title;&&href;img&&data-original;.module-item-note&&Text', + url: '/s/fyclass/page/fypage.html', + categoryVod: 'div.module-items > a;&&title;&&href;img&&data-original;.module-item-note&&Text', + detailVod: { + playFrom: '.module-tab-items-box > .module-tab-item > span&&Text', + playUrl: '.module-play-list > .module-play-list-content;a;&&Text;&&href', + }, + lazy: ` + request(HOST + input);||| + const json = getPlay4aJson(html); + request('http://java.shijie.chat/player?url=' + unescape(base64Decode(JSON.parse(json).url)));||| + let encData = html.split('Video: "')[1].split('",')[0]; + playUrl = JSON.parse(aesDecode(encData, 'ASD010QNC636LJY9', 'C636LJY9ASD010QN')).url; + `, + searchUrl: '/vodsearch.html?wd=**', + searchVod: '.module-card-item > a;img&&alt;&&href;img&&data-original;.module-item-note&&Text', +} \ No newline at end of file diff --git a/js/sj.js b/js/sj.js new file mode 100644 index 0000000..1f06a15 --- /dev/null +++ b/js/sj.js @@ -0,0 +1,303 @@ +import { Crypto,_} from 'assets://js/lib/cat.js'; +//import {} from './wrapper/index.js'; + +let siteUrl = 'http://118.25.18.217:6632'; +let siteKey = ''; +let siteType = 0; +let cookies = ''; + +let headers = { + 'User-Agent': 'okhttp/3.12.1', + 'Content-Type': 'application/json;' +}; + +let key = ['TFLYWVJ5EG5YB1PLZLVVMGVLBGRIDCSW', 'nj6E5K4yYYT5W4ScJ3J3rJ2zrzcJkpTk']; + +async function request(reqUrl){ + //console.log('req', reqUrl); + let res = await req(reqUrl, { + method: 'get', + headers: headers, + }); + return res.content; +} + +async function init(cfg) { + siteKey = cfg.skey; + siteType = cfg.stype; + initHost(); +} + +async function home(filter) { + let res = await request(`${siteUrl}/api/v3/drama/getCategory?orderBy=type_id`); + //console.log(res); + let data = JSON.parse(res).data; + let dy = { + "class": "类型", + "area": "地区", + "lang": "语言", + "year": "年份", + "letter": "字母", + "by": "排序", + "sort": "排序", + }; + let filters = {}; + let classes = []; + _.forEach(data, item => { + let jsontype_extend = JSON.parse(item["converUrl"]); + //console.log('jsontype_extend', jsontype_extend); + classes.push({ + type_id: item['id'], + type_name: item['name'] + }); + filters[item['id']] = []; + for (let key in dy) { + if (jsontype_extend[key]) { + let values = jsontype_extend[key].split(','); + filters[item['id']].push({ + key: key, + name: dy[key], + value: _.map(values, v => { + return { + n: v, + v: v + } + }) + }); + } + } + }) + return JSON.stringify({ + class: classes, + filters: filters, + }); +} +//console.log(await home()); + + +async function homeVod() { + let res = await request(`${siteUrl}/api/ex/v3/security/tag/list`); + let data = JSON.parse(res).data; + let result = aes(aes(data, key[0]), key[1], 'decrypt', true); + let videos = _.map(result[0]['carousels'], item => { + //console.log(item); + return { + vod_id: item['link'].split("id=")[1], + vod_name: item["title"], + vod_pic: item["cover"], + vod_remarks: item['sort'], + }; + }) + return JSON.stringify({ + list: videos, + }); +} + +//console.log(await homeVod()); + +async function category(tid, pg, filter, extend) { + let param = ''; + if (extend['area']) { + param = param + "vodArea=" + extend['area'] + "&"; + } + if (extend['class']) { + param = param + "vodClass=" + extend['class'] + "&"; + } + if (extend['lang']) { + param = param + "vodLang=" + extend['lang'] + "&"; + } + if (extend['year']) { + param = param + "vodYear=" + extend['year'] + "&"; + } + param = param + "pagesize=20&typeId1=" +tid + "&page=" + pg; + let path = aes(aes(param, key[1], 'encrypt'), key[0], 'encrypt', true); + let res = await request(`${siteUrl}/api/ex/v3/security/drama/list?query=${path}`); + let data = JSON.parse(res).data; + data = aes(aes(data, key[0]), key[1], 'decrypt', true)['list']; + let videos = _.map(data, item => { + return { + vod_id: item['id'], + vod_name: item['name'], + vod_pic: item['coverImage']['path'], + vod_year: item['year'], + vod_remarks: item['remark'], + }; + }); + return JSON.stringify({ + list: videos, + page: pg, + pagecount: 999, + }); +} +//console.log(await category('2', '1', '', '')); + + +async function detail(id) { + let res = await request(`${siteUrl}/api/v3/drama/getDetail?id=${id}`); + //console.log(res); + let data = JSON.parse(res).data; + let vod = { + 'vod_name': data.name, + 'vod_area': data.area, + 'type_name': data.clazz, + 'vod_actor': data.actor, + 'vod_director': data.director, + 'vod_content': data.brief, + } + let play = [] + let names = [] + let plays = {} + _.forEach(data['videos'], item => { + if(names.indexOf(item['sourceCn']) == -1) { + plays[item['source']] = []; + names.push(item['sourceCn']); + } + let url = `vodPlayFrom=${item['source']}&playUrl=${item['path']}` + if(item['path'] && (item['path'].includes('m3u8') || item['path'].includes('mp4') || item['path'].includes('flv'))) { + url = item['path'] + } + plays[item['source']].push(item['titleOld'] + '$' + url); + }); + //console.log(names); + //console.log(plays); + _.forEach(plays, (item, key) => { + play.push(item.join('#')); + }) + vod.vod_play_url = play.join('$$$'); + vod.vod_play_from = names.join('$$$'); + return JSON.stringify({ + list: [vod], + }); +} +//console.log(await detail('105275')); + +async function play(flag, id) { + let url = id; + if(id.includes('vodPlayFrom')) { + let path = aes(aes(id, key[1], 'encrypt'), key[0], 'encrypt', true); + let res = await request(`${siteUrl}/api/ex/v3/security/videoUsableUrl?query=${path}`); + let data = JSON.parse(res).data; + //console.log(data); + url = aes(aes(data, key[0]), key[1], 'decrypt', true)['playUrl'] + //console.log(url); + if (url.includes('.jpg') || url.includes('.jpeg') || url.includes('.png')) { + const js2Base = await js2Proxy(true, siteType, siteKey, 'm3u8/', {}); + url = js2Base + base64Encode(url); + } + } + return JSON.stringify({ + parse: 0, + url: url, + }); +} +//console.log(await play('', 'vodPlayFrom=Yzm3u8&playUrl=TNB-0C61E2C6562FDAE90B4121E29991104582919875B13189E00C02FDE3D84F41174860905A48FD727E784F72F24055D4D7A0199801E4FFD0D390A573D5AEE119881E2F67ADC7ABFDC5ABF1AFD9170AA7A6B9')); + + + + +async function search(wd, quick, pg = 1) { + let param = `pagesize=20&page=${pg}&searchKeys=${wd}`; + let path = aes(aes(param, key[1], 'encrypt'), key[0], 'encrypt', true); + let res = await request(`${siteUrl}/api/ex/v3/security/drama/list?query=${path}`); + let data = JSON.parse(res).data; + data = aes(aes(data, key[0]), key[1], 'decrypt', true)['list']; + let videos = _.map(data, item => { + return { + vod_id: item['id'], + vod_name: item['name'], + vod_pic: item['coverImage']['path'], + vod_year: item['year'], + vod_remarks: item['remark'], + }; + }); + return JSON.stringify({ + list: videos + }); +} + +//console.log(await search('战狼', '', '1')); + + + +async function proxy(segments, headers) { + let what = segments[0]; + let url = base64Decode(segments[1]); + if (what == 'm3u8') { + let data = await request(url); + // 处理M3U8文件内容 + let lines = data.trim().split('\n'); + lines = lines.map((string, index) => { + if (!string.startsWith('#EXT') && !/^(http|https):\/\//.test(string)) { + return `${durl}${string.startsWith('/') ? '' : '/'}${string}`; + } + return string; + }); + // 返回修改后的内容 + return [200, "application/vnd.apple.mpegurl", lines.join('\n')]; + } + return JSON.stringify({ + code: 500, + 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 initHost() { + try { + let res = await request('https://www.shijue.pro/token.txt'); + siteUrl = JSON.parse(res).domain; + } catch (e) { + console.log('initHost error', e); + } +} +function aes(word, key, mode = 'decrypt', bool = false) { + // 将字符串转换为字节数组,并处理key长度以匹配AES要求(通常是16, 24或32字节) + const secretKey = Crypto.enc.Utf8.parse(key); + + if (mode === 'decrypt') { + // 解码Base64编码的字符串 + const base64Word = Crypto.enc.Base64.parse(word); + const cipherParams = Crypto.lib.CipherParams.create({ ciphertext: base64Word }); + + // 使用AES ECB模式进行解密 + const decrypted = Crypto.AES.decrypt(cipherParams, secretKey, { mode: Crypto.mode.ECB, padding: Crypto.pad.Pkcs7 }); + let result = decrypted.toString(Crypto.enc.Utf8); + + if (bool) { + result = JSON.parse(result); + } + return result; + } else if (mode === 'encrypt') { + // 对word进行AES加密前先转为CryptoJS word数组 + const source = Crypto.enc.Utf8.parse(word); + + // 使用AES ECB模式进行加密 + const encrypted = Crypto.AES.encrypt(source, secretKey, { mode: Crypto.mode.ECB, padding: Crypto.pad.Pkcs7 }); + let result = encrypted.ciphertext.toString(Crypto.enc.Base64); + + if (bool) { + result = encodeURIComponent(result); + } + return result; + } +} + +export function __jsEvalReturn() { + return { + init: init, + home: home, + homeVod: homeVod, + category: category, + detail: detail, + play: play, + search: search, + proxy: proxy, + }; +} \ No newline at end of file