mirror of https://github.com/FongMi/CatVodOpen.git
parent
065a42ccf1
commit
3e1ec9f555
@ -0,0 +1,5 @@ |
||||
`npm install` |
||||
|
||||
`node test.js` |
||||
|
||||
`node build.js` |
||||
@ -0,0 +1,275 @@ |
||||
import { _ } from './lib/cat.js'; |
||||
import { findBestLCS } from './lib/similarity.js'; |
||||
|
||||
const http = async function (url, options = {}) { |
||||
if (options.method == 'POST' && options.data) { |
||||
options.body = JSON.stringify(options.data); |
||||
options.headers = Object.assign({ 'content-type': 'application/json' }, options.headers); |
||||
} |
||||
const res = await req(url, options); |
||||
res.json = () => (res.content ? JSON.parse(res.content) : null); |
||||
res.text = () => res.content; |
||||
return res; |
||||
}; |
||||
['get', 'post'].forEach((method) => { |
||||
http[method] = function (url, options = {}) { |
||||
return http(url, Object.assign(options, { method: method.toUpperCase() })); |
||||
}; |
||||
}); |
||||
|
||||
const __drives = {}; |
||||
const __subtitle_cache = {}; |
||||
|
||||
async function get_drives_path(tid) { |
||||
const index = tid.indexOf('/', 1); |
||||
const name = tid.substring(1, index); |
||||
const path = tid.substring(index); |
||||
return { drives: await get_drives(name), path }; |
||||
} |
||||
|
||||
async function get_drives(name) { |
||||
const { settings, api, server } = __drives[name]; |
||||
if (settings.v3 == null) { |
||||
//获取 设置
|
||||
settings.v3 = false; |
||||
const data = (await http.get(server + '/api/public/settings')).json().data; |
||||
if (_.isArray(data)) { |
||||
settings.title = data.find((x) => x.key == 'title')?.value; |
||||
settings.v3 = false; |
||||
settings.version = data.find((x) => x.key == 'version')?.value; |
||||
settings.enableSearch = data.find((x) => x.key == 'enable search')?.value == 'true'; |
||||
} else { |
||||
settings.title = data.title; |
||||
settings.v3 = true; |
||||
settings.version = data.version; |
||||
settings.enableSearch = false; //v3 没有找到 搜索配置
|
||||
} |
||||
//不同版本 接口不一样
|
||||
api.path = settings.v3 ? '/api/fs/list' : '/api/public/path'; |
||||
api.file = settings.v3 ? '/api/fs/get' : '/api/public/path'; |
||||
api.search = settings.v3 ? '/api/public/search' : '/api/public/search'; |
||||
api.other = settings.v3 ? '/api/fs/other' : null; |
||||
} |
||||
return __drives[name]; |
||||
} |
||||
|
||||
let siteKey = ''; |
||||
let siteType = 0; |
||||
|
||||
function init(cfg) { |
||||
siteKey = cfg.skey; |
||||
siteType = cfg.stype; |
||||
cfg.ext.forEach( |
||||
(item) => |
||||
(__drives[item.name] = { |
||||
name: item.name, |
||||
server: item.server.endsWith('/') ? item.server.substring(0, item.server.length - 1) : item.server, |
||||
startPage: item.startPage || '/', //首页
|
||||
showAll: item.showAll === true, //默认只显示 视频和文件夹,如果想显示全部 showAll 设置true
|
||||
params: item.params || {}, |
||||
_path_param: item.params |
||||
? _.sortBy(Object.keys(item.params), function (x) { |
||||
return -x.length; |
||||
}) |
||||
: [], |
||||
settings: {}, |
||||
api: {}, |
||||
getParams(path) { |
||||
const key = this._path_param.find((x) => path.startsWith(x)); |
||||
return Object.assign({}, this.params[key], { path }); |
||||
}, |
||||
async getPath(path) { |
||||
const res = (await http.post(this.server + this.api.path, { data: this.getParams(path) })).json(); |
||||
return this.settings.v3 ? res.data.content : res.data.files; |
||||
}, |
||||
async getFile(path) { |
||||
const res = (await http.post(this.server + this.api.file, { data: this.getParams(path) })).json(); |
||||
const data = this.settings.v3 ? res.data : res.data.files[0]; |
||||
if (!this.settings.v3) data.raw_url = data.url; //v2 的url和v3不一样
|
||||
return data; |
||||
}, |
||||
async getOther(method, path) { |
||||
const data = this.getParams(path); |
||||
data.method = method; |
||||
const res = (await http.post(this.server + this.api.other, { data: data })).json(); |
||||
return res; |
||||
}, |
||||
isFolder(data) { |
||||
return data.type == 1; |
||||
}, |
||||
isVideo(data) { |
||||
//判断是否是 视频文件
|
||||
return this.settings.v3 ? data.type == 2 : data.type == 3; |
||||
}, |
||||
isSubtitle(data) { |
||||
if (data.type == 1) return false; |
||||
const ext = ['.srt', '.ass', '.scc', '.stl', '.ttml']; |
||||
return ext.some((x) => data.name.endsWith(x)); |
||||
}, |
||||
getType(data) { |
||||
const isVideo = this.isVideo(data); |
||||
return this.isFolder(data) ? 0 : isVideo ? 10 : 1; |
||||
}, |
||||
getPic(data) { |
||||
let pic = this.settings.v3 ? data.thumb : data.thumbnail; |
||||
return pic || (this.isFolder(data) ? 'http://img1.3png.com/281e284a670865a71d91515866552b5f172b.png' : ''); |
||||
}, |
||||
getSize(data) { |
||||
let sz = data.size || 0; |
||||
if (sz <= 0) return ''; |
||||
let filesize = ''; |
||||
if (sz > 1024 * 1024 * 1024 * 1024.0) { |
||||
sz /= 1024 * 1024 * 1024 * 1024.0; |
||||
filesize = 'TB'; |
||||
} else if (sz > 1024 * 1024 * 1024.0) { |
||||
sz /= 1024 * 1024 * 1024.0; |
||||
filesize = 'GB'; |
||||
} else if (sz > 1024 * 1024.0) { |
||||
sz /= 1024 * 1024.0; |
||||
filesize = 'MB'; |
||||
} else { |
||||
sz /= 1024.0; |
||||
filesize = 'KB'; |
||||
} |
||||
return sz.toFixed(2) + filesize; |
||||
}, |
||||
getRemark(data) { |
||||
return ''; |
||||
}, |
||||
}) |
||||
); |
||||
} |
||||
|
||||
async function dir(dir, pg) { |
||||
for (const k in __subtitle_cache) { |
||||
delete __subtitle_cache[k]; |
||||
} |
||||
pg = pg || 1; |
||||
if (pg == 0) pg == 1; |
||||
if (dir === '/' || dir === '') { |
||||
const result = _.map(__drives, function (d) { |
||||
return { name: d.name, path: '/' + d.name + d.startPage, type: 0, thumb: '' }; |
||||
}); |
||||
return JSON.stringify({ |
||||
parent: '', |
||||
page: pg, |
||||
pagecount: pg, |
||||
list: result, |
||||
}); |
||||
} |
||||
|
||||
let { drives, path } = await get_drives_path(dir); |
||||
const id = dir.endsWith('/') ? dir : dir + '/'; |
||||
const list = await drives.getPath(path); |
||||
let subtList = []; |
||||
let videos = []; |
||||
let allList = []; |
||||
list.forEach((item) => { |
||||
if (drives.isSubtitle(item)) subtList.push(item.name); |
||||
const isVideo = drives.isVideo(item); |
||||
if (!drives.showAll && !drives.isFolder(item) && !isVideo) return; |
||||
const file = { |
||||
name: item.name.replaceAll('$', '_').replaceAll('#', '_'), |
||||
path: id + item.name + (drives.isFolder(item) ? '/' : ''), |
||||
thumb: drives.getPic(item), |
||||
type: drives.getType(item), |
||||
size: drives.getSize(item), |
||||
remark: drives.getRemark(item), |
||||
}; |
||||
if (drives.isVideo(item)) videos.push(file); |
||||
allList.push(file); |
||||
}); |
||||
if (subtList.length > 0) { |
||||
videos.forEach((item) => { |
||||
var sbust = findBestLCS(item.name, subtList); |
||||
if (sbust.bestMatch) __subtitle_cache[item.path] = [id + sbust.bestMatch.target]; |
||||
}); |
||||
} |
||||
return JSON.stringify({ |
||||
parent: id, |
||||
page: pg, |
||||
pagecount: pg, |
||||
list: allList, |
||||
}); |
||||
} |
||||
|
||||
async function file(file) { |
||||
let { drives, path } = await get_drives_path(file); |
||||
const item = await drives.getFile(path); |
||||
const subs = []; |
||||
if (__subtitle_cache[file]) { |
||||
for (const sub of __subtitle_cache[file]) { |
||||
try { |
||||
let subP = await get_drives_path(sub); |
||||
const subItem = await drives.getFile(subP.path); |
||||
subs.push(subItem.raw_url); |
||||
} catch (error) {} |
||||
} |
||||
} |
||||
if (item.provider === 'AliyundriveShare2Open' && drives.api.other) { |
||||
const urls = ['原画', item.raw_url]; |
||||
try { |
||||
const res = await drives.getOther('video_preview', path); |
||||
for (const live of res.data.video_preview_play_info.live_transcoding_task_list) { |
||||
if (live.status === 'finished') { |
||||
urls.push(live.template_id); |
||||
urls.push(live.url); |
||||
} |
||||
} |
||||
} catch (error) {} |
||||
const result = { |
||||
name: item.name, |
||||
url: urls, |
||||
size: drives.getSize(item), |
||||
remark: drives.getRemark(item), |
||||
header: {}, |
||||
extra: { |
||||
subt: subs, |
||||
}, |
||||
}; |
||||
return JSON.stringify(result); |
||||
} else if (item.provider === '123Pan') { |
||||
let url = item.raw_url; |
||||
try { |
||||
url = (await http.get(url)).json().data.redirect_url; |
||||
} catch (error) {} |
||||
const result = { |
||||
name: item.name, |
||||
url: url, |
||||
size: drives.getSize(item), |
||||
remark: drives.getRemark(item), |
||||
header: {}, |
||||
extra: { |
||||
subt: subs, |
||||
}, |
||||
}; |
||||
return JSON.stringify(result); |
||||
} else { |
||||
const result = { |
||||
name: item.name, |
||||
url: item.raw_url, |
||||
size: drives.getSize(item), |
||||
remark: drives.getRemark(item), |
||||
header: {}, |
||||
extra: { |
||||
subt: subs, |
||||
}, |
||||
}; |
||||
return JSON.stringify(result); |
||||
} |
||||
} |
||||
|
||||
function search(wd) { |
||||
return JSON.stringify({ |
||||
list: [], |
||||
}); |
||||
} |
||||
|
||||
export function __jsEvalReturn() { |
||||
return { |
||||
init: init, |
||||
dir: dir, |
||||
file: file, |
||||
search: search, |
||||
}; |
||||
} |
||||
@ -0,0 +1,8 @@ |
||||
function __jsEvalReturn() { |
||||
return { |
||||
isVideoFormat: function (url) { |
||||
return !0; |
||||
}, |
||||
}; |
||||
} |
||||
export { __jsEvalReturn }; |
||||
@ -0,0 +1,61 @@ |
||||
import fs from 'node:fs'; |
||||
import path from 'path'; |
||||
import uglifyjs from 'uglify-js'; |
||||
|
||||
const copySpider = ['app', 'kunyu77_open', 'alist_open']; |
||||
|
||||
const root = process.cwd(); |
||||
|
||||
const src = path.join(root); |
||||
const out = path.join(root, 'dist'); |
||||
|
||||
function minify(s, d) { |
||||
var jsContent = fs.readFileSync(s).toString(); |
||||
jsContent = jsContent.replace('./lib/cat.js', 'assets://js/lib/cat.js'); |
||||
jsContent = jsContent.replace('./cat.js', 'assets://js/lib/cat.js'); |
||||
jsContent = uglifyjs.minify(jsContent, { |
||||
mangle: false, |
||||
}); |
||||
fs.writeFileSync(d, jsContent.code); |
||||
} |
||||
|
||||
function listAllFiles(dirPath, arrayOfFiles) { |
||||
var files = fs.readdirSync(dirPath); |
||||
|
||||
arrayOfFiles = arrayOfFiles || []; |
||||
|
||||
files.forEach(function (file) { |
||||
if (fs.statSync(dirPath + '/' + file).isDirectory()) { |
||||
arrayOfFiles = listAllFiles(dirPath + '/' + file, arrayOfFiles); |
||||
} else { |
||||
arrayOfFiles.push(path.join(dirPath, '/', file)); |
||||
} |
||||
}); |
||||
|
||||
return arrayOfFiles; |
||||
} |
||||
|
||||
function src2Out() { |
||||
if (fs.existsSync(out)) fs.rmSync(out, { recursive: true, force: true }); |
||||
|
||||
fs.mkdirSync(out, { recursive: true }); |
||||
const libSrc = path.join(src, 'lib'); |
||||
const libOut = path.join(out, 'lib'); |
||||
fs.mkdirSync(libOut, { recursive: true }); |
||||
const libs = listAllFiles(libSrc); |
||||
for (let index = 0; index < libs.length; index++) { |
||||
const element = libs[index]; |
||||
const relative = path.relative(libSrc, element); |
||||
minify(element, path.join(libOut, relative)); |
||||
} |
||||
|
||||
for (const sp of copySpider) { |
||||
minify(path.join(src, sp + '.js'), path.join(out, sp + '.js')); |
||||
} |
||||
} |
||||
|
||||
src2Out(); |
||||
|
||||
fs.copyFileSync(path.join(src, 'config_open.json'), path.join(out, 'config_open.json')); |
||||
|
||||
console.log('done'); |
||||
@ -0,0 +1,337 @@ |
||||
import { Crypto, dayjs, jinja2, Uri, _ } from './lib/cat.js'; |
||||
|
||||
let key = 'kunyu77'; |
||||
let url = 'http://api.tyun77.cn'; |
||||
let device = {}; |
||||
let timeOffset = 0; |
||||
let siteKey = ''; |
||||
let siteType = 0; |
||||
|
||||
async function request(reqUrl, agentSp) { |
||||
let sj = dayjs().unix() - timeOffset; |
||||
let uri = new Uri(reqUrl); |
||||
uri.addQueryParam('pcode', '010110005'); |
||||
uri.addQueryParam('version', '2.1.6'); |
||||
uri.addQueryParam('devid', device.id); |
||||
uri.addQueryParam('package', 'com.sevenVideo.app.android'); |
||||
uri.addQueryParam('sys', 'android'); |
||||
uri.addQueryParam('sysver', device.release); |
||||
uri.addQueryParam('brand', device.brand); |
||||
uri.addQueryParam('model', device.model.replaceAll(' ', '_')); |
||||
uri.addQueryParam('sj', sj); |
||||
let keys = []; |
||||
for (var i = 0; i < uri.queryPairs.length; i++) { |
||||
keys.push(uri.queryPairs[i][0]); |
||||
} |
||||
keys = _.sortBy(keys, function (name) { |
||||
return name; |
||||
}); |
||||
let tkSrc = uri.path(); |
||||
for (let k of keys) { |
||||
let v = uri.getQueryParamValue(k); |
||||
v = encodeURIComponent(v); |
||||
tkSrc += v; |
||||
} |
||||
tkSrc += sj; |
||||
tkSrc += 'XSpeUFjJ'; |
||||
console.log(tkSrc); |
||||
let tk = Crypto.MD5(tkSrc).toString().toLowerCase(); |
||||
console.log(tk); |
||||
let header = { |
||||
'user-agent': agentSp || 'okhttp/3.12.0', |
||||
t: sj, |
||||
TK: tk, |
||||
}; |
||||
let res = await req(uri.toString(), { |
||||
headers: header, |
||||
}); |
||||
|
||||
let serverTime = res.headers.date; // dart all response header key is lowercase
|
||||
let content = res.content; |
||||
let serverTimeS = dayjs(serverTime).unix(); |
||||
timeOffset = dayjs().unix() - serverTimeS; |
||||
// console.log(content);
|
||||
return content; |
||||
} |
||||
|
||||
async function init(cfg) { |
||||
siteKey = cfg.skey; |
||||
siteType = cfg.stype; |
||||
var deviceKey = 'device'; |
||||
var deviceInfo = await local.get(key, deviceKey); |
||||
if (deviceInfo.length > 0) { |
||||
try { |
||||
device = JSON.parse(deviceInfo); |
||||
} catch (error) {} |
||||
} |
||||
if (_.isEmpty(device)) { |
||||
device = randDevice(); |
||||
device.id = randStr(32).toLowerCase(); |
||||
device.ua = 'Dalvik/2.1.0 (Linux; U; Android ' + device.release + '; ' + device.model + ' Build/' + device.buildId + ')'; |
||||
await local.set(key, deviceKey, JSON.stringify(device)); |
||||
} |
||||
} |
||||
|
||||
async function home(filter) { |
||||
let data = JSON.parse(await request(url + '/api.php/provide/filter')).data; |
||||
let classes = []; |
||||
let filterObj = {}; |
||||
let filterAll = []; |
||||
for (const key in data) { |
||||
classes.push({ |
||||
type_id: key, |
||||
type_name: data[key][0].cat, |
||||
}); |
||||
if (!filter) continue; |
||||
try { |
||||
let typeId = key.toString(); |
||||
if (_.isEmpty(filterAll)) { |
||||
let filterData = JSON.parse(await request(url + '/api.php/provide/searchFilter?type_id=0&pagenum=1&pagesize=1')).data.conditions; |
||||
// console.log(filterData);
|
||||
// 年份
|
||||
let year = { |
||||
key: 'year', |
||||
name: '年份', |
||||
init: '', |
||||
}; |
||||
let yearValues = []; |
||||
yearValues.push({ n: '全部', v: '' }); |
||||
filterData.y.forEach((e) => { |
||||
yearValues.push({ n: e.name, v: e.value }); |
||||
}); |
||||
year['value'] = yearValues; |
||||
// 地区
|
||||
let area = { |
||||
key: 'area', |
||||
name: '地区', |
||||
init: '', |
||||
}; |
||||
let areaValues = []; |
||||
areaValues.push({ n: '全部', v: '' }); |
||||
filterData.a.forEach((e) => { |
||||
areaValues.push({ n: e.name, v: e.value }); |
||||
}); |
||||
area['value'] = areaValues; |
||||
// 类型
|
||||
let type = { |
||||
key: 'category', |
||||
name: '类型', |
||||
init: '', |
||||
}; |
||||
let typeValues = []; |
||||
typeValues.push({ n: '全部', v: '' }); |
||||
filterData.scat.forEach((e) => { |
||||
typeValues.push({ n: e.name, v: e.value }); |
||||
}); |
||||
type['value'] = typeValues; |
||||
|
||||
filterAll.push(year, area, type); |
||||
} |
||||
if (!_.isEmpty(filterAll)) { |
||||
filterObj[typeId] = filterAll; |
||||
} |
||||
} catch (e) { |
||||
console.log(e); |
||||
} |
||||
} |
||||
// console.log(classes);
|
||||
// console.log(filterObj);
|
||||
return JSON.stringify({ |
||||
class: classes, |
||||
filters: filterObj, |
||||
}); |
||||
} |
||||
|
||||
async function homeVod() { |
||||
let data = JSON.parse(await request(url + '/api.php/provide/homeBlock?type_id=0')).data; |
||||
let blocks = data.blocks; |
||||
let videos = []; |
||||
for (const block of blocks) { |
||||
let name = block.block_name; |
||||
if (name.indexOf('热播') >= 0) continue; |
||||
let contents = block.contents; |
||||
for (const content of contents) { |
||||
videos.push({ |
||||
vod_id: content.id, |
||||
vod_name: content.title, |
||||
vod_pic: content.videoCover, |
||||
vod_remarks: content.msg, |
||||
}); |
||||
} |
||||
} |
||||
return JSON.stringify({ |
||||
list: videos, |
||||
}); |
||||
} |
||||
|
||||
async function category(tid, pg, filter, extend) { |
||||
let reqUrl = url + '/api.php/provide/searchFilter?type_id=' + tid + '&pagenum=' + pg + '&pagesize=24&'; |
||||
reqUrl += jinja2('year={{ext.year}}&category={{ext.category}}&area={{ext.area}}', { ext: extend }); |
||||
let data = JSON.parse(await request(reqUrl)).data; |
||||
let videos = []; |
||||
for (const vod of data.result) { |
||||
videos.push({ |
||||
vod_id: vod.id, |
||||
vod_name: vod.title, |
||||
vod_pic: vod.videoCover, |
||||
vod_remarks: vod.msg, |
||||
}); |
||||
} |
||||
return JSON.stringify({ |
||||
page: parseInt(data.page), |
||||
pagecount: data.pagesize, |
||||
limit: 24, |
||||
total: data.total, |
||||
list: videos, |
||||
}); |
||||
} |
||||
|
||||
async function detail(id) { |
||||
let data = JSON.parse(await request(url + '/api.php/provide/videoDetail?ids=' + id)).data; |
||||
console.log(data); |
||||
let vod = { |
||||
vod_id: data.id, |
||||
vod_name: data.videoName, |
||||
vod_pic: data.videoCover, |
||||
type_name: data.subCategory, |
||||
vod_year: data.year, |
||||
vod_area: data.area, |
||||
vod_remarks: data.msg, |
||||
vod_actor: data.actor, |
||||
vod_director: data.director, |
||||
vod_content: data.brief.trim(), |
||||
}; |
||||
let episodes = JSON.parse(await request(url + '/api.php/provide/videoPlaylist?ids=' + id)).data.episodes; |
||||
let playlist = {}; |
||||
for (const episode of episodes) { |
||||
let playurls = episode.playurls; |
||||
for (const playurl of playurls) { |
||||
let from = playurl.playfrom; |
||||
let t = formatPlayUrl(vod.vod_name, playurl.title); |
||||
if (t.length == 0) t = playurl.title.trim(); |
||||
if (!playlist.hasOwnProperty(from)) { |
||||
playlist[from] = []; |
||||
} |
||||
playlist[from].push(t + '$' + playurl.playurl); |
||||
} |
||||
} |
||||
vod.vod_play_from = _.keys(playlist).join('$$$'); |
||||
let urls = _.values(playlist); |
||||
let vod_play_url = []; |
||||
for (const urlist of urls) { |
||||
vod_play_url.push(urlist.join('#')); |
||||
} |
||||
vod.vod_play_url = vod_play_url.join('$$$'); |
||||
return JSON.stringify({ |
||||
list: [vod], |
||||
}); |
||||
} |
||||
|
||||
async function play(flag, id, flags) { |
||||
try { |
||||
let data = JSON.parse(await request(url + '/api.php/provide/parserUrl?url=' + id + '&retryNum=0')).data; |
||||
let playHeader = data.playHeader; |
||||
let jxUrl = data.url; |
||||
let res = await req(jxUrl, { |
||||
headers: { |
||||
'user-agent': 'okhttp/3.12.0', |
||||
}, |
||||
}); |
||||
let result = jsonParse(id, JSON.parse(res.content)); |
||||
result['parse'] = 0; |
||||
if (playHeader) { |
||||
result.header = _.merge(result.header, playHeader); |
||||
} |
||||
return JSON.stringify(result); |
||||
} catch (e) { |
||||
return JSON.stringify({ |
||||
parse: 0, |
||||
url: id, |
||||
}); |
||||
} |
||||
} |
||||
|
||||
async function search(wd, quick) { |
||||
let data = JSON.parse(await request(url + '/api.php/provide/searchVideo?searchName=' + wd + '&pg=1', 'okhttp/3.12.0')).data; |
||||
let videos = []; |
||||
for (const vod of data) { |
||||
videos.push({ |
||||
vod_id: vod.id, |
||||
vod_name: vod.videoName, |
||||
vod_pic: vod.videoCover, |
||||
vod_remarks: vod.msg, |
||||
}); |
||||
} |
||||
return JSON.stringify({ |
||||
list: videos, |
||||
}); |
||||
} |
||||
|
||||
const charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789'; |
||||
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 randDevice() { |
||||
return { |
||||
brand: 'Huawei', |
||||
model: 'HUAWEI Mate 20', |
||||
release: '10', |
||||
buildId: randStr(3, false).toUpperCase() + _.random(11, 99) + randStr(1, false).toUpperCase(), |
||||
}; |
||||
} |
||||
|
||||
function formatPlayUrl(src, name) { |
||||
return name |
||||
.trim() |
||||
.replaceAll(src, '') |
||||
.replace(/<|>|《|》/g, '') |
||||
.replace(/\$|#/g, ' ') |
||||
.trim(); |
||||
} |
||||
|
||||
function jsonParse(input, json) { |
||||
try { |
||||
let url = json.url ?? ''; |
||||
if (url.startsWith('//')) { |
||||
url = 'https:' + url; |
||||
} |
||||
if (!url.startsWith('http')) { |
||||
return {}; |
||||
} |
||||
let headers = json['headers'] || {}; |
||||
let ua = (json['user-agent'] || '').trim(); |
||||
if (ua.length > 0) { |
||||
headers['User-Agent'] = ua; |
||||
} |
||||
let referer = (json['referer'] || '').trim(); |
||||
if (referer.length > 0) { |
||||
headers['Referer'] = referer; |
||||
} |
||||
return { |
||||
header: headers, |
||||
url: url, |
||||
}; |
||||
} catch (error) { |
||||
console.log(error); |
||||
} |
||||
return {}; |
||||
} |
||||
|
||||
export function __jsEvalReturn() { |
||||
return { |
||||
init: init, |
||||
home: home, |
||||
homeVod: homeVod, |
||||
category: category, |
||||
detail: detail, |
||||
play: play, |
||||
search: search, |
||||
}; |
||||
} |
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,47 @@ |
||||
function compareTwoStrings(first, second) { |
||||
if ((first = first.replace(/\s+/g, '')) === (second = second.replace(/\s+/g, ''))) return 1; |
||||
if (first.length < 2 || second.length < 2) return 0; |
||||
var firstBigrams = new Map(); |
||||
for (let i = 0; i < first.length - 1; i++) { |
||||
var bigram = first.substring(i, i + 2), |
||||
count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) + 1 : 1; |
||||
firstBigrams.set(bigram, count); |
||||
} |
||||
let intersectionSize = 0; |
||||
for (let i = 0; i < second.length - 1; i++) { |
||||
const bigram = second.substring(i, i + 2), |
||||
count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) : 0; |
||||
0 < count && (firstBigrams.set(bigram, count - 1), intersectionSize++); |
||||
} |
||||
return (2 * intersectionSize) / (first.length + second.length - 2); |
||||
} |
||||
function findBestMatch(mainString, targetStrings) { |
||||
var ratings = []; |
||||
let bestMatchIndex = 0; |
||||
for (let i = 0; i < targetStrings.length; i++) { |
||||
var currentTargetString = targetStrings[i], |
||||
currentRating = compareTwoStrings(mainString, currentTargetString); |
||||
ratings.push({ target: currentTargetString, rating: currentRating }), currentRating > ratings[bestMatchIndex].rating && (bestMatchIndex = i); |
||||
} |
||||
return { ratings: ratings, bestMatch: ratings[bestMatchIndex], bestMatchIndex: bestMatchIndex }; |
||||
} |
||||
function lcs(str1, str2) { |
||||
if (!str1 || !str2) return { length: 0, sequence: '', offset: 0 }; |
||||
for (var sequence = '', str1Length = str1.length, str2Length = str2.length, num = new Array(str1Length), maxlen = 0, lastSubsBegin = 0, i = 0; i < str1Length; i++) { |
||||
for (var subArray = new Array(str2Length), j = 0; j < str2Length; j++) subArray[j] = 0; |
||||
num[i] = subArray; |
||||
} |
||||
for (var thisSubsBegin = null, i = 0; i < str1Length; i++) for (j = 0; j < str2Length; j++) str1[i] !== str2[j] ? (num[i][j] = 0) : ((num[i][j] = 0 === i || 0 === j ? 1 : 1 + num[i - 1][j - 1]), num[i][j] > maxlen && ((maxlen = num[i][j]), lastSubsBegin === (thisSubsBegin = i - num[i][j] + 1) ? (sequence += str1[i]) : ((lastSubsBegin = thisSubsBegin), (sequence = ''), (sequence += str1.substr(lastSubsBegin, i + 1 - lastSubsBegin))))); |
||||
return { length: maxlen, sequence: sequence, offset: thisSubsBegin }; |
||||
} |
||||
function findBestLCS(mainString, targetStrings) { |
||||
var results = []; |
||||
let bestMatchIndex = 0; |
||||
for (let i = 0; i < targetStrings.length; i++) { |
||||
var currentTargetString = targetStrings[i], |
||||
currentLCS = lcs(mainString, currentTargetString); |
||||
results.push({ target: currentTargetString, lcs: currentLCS }), currentLCS.length > results[bestMatchIndex].lcs.length && (bestMatchIndex = i); |
||||
} |
||||
return { allLCS: results, bestMatch: results[bestMatchIndex], bestMatchIndex: bestMatchIndex }; |
||||
} |
||||
export { compareTwoStrings, findBestMatch, findBestLCS }; |
||||
@ -0,0 +1,342 @@ |
||||
{ |
||||
"name": "CatVodOpenJSSpider", |
||||
"version": "1.0.0", |
||||
"lockfileVersion": 2, |
||||
"requires": true, |
||||
"packages": { |
||||
"": { |
||||
"name": "CatVodOpenJSSpider", |
||||
"version": "1.0.0", |
||||
"license": "ISC", |
||||
"dependencies": { |
||||
"axios": "^1.4.0", |
||||
"qs": "^6.11.2" |
||||
}, |
||||
"devDependencies": { |
||||
"@types/node": "^20.1.5", |
||||
"uglify-js": "^3.17.4" |
||||
} |
||||
}, |
||||
"node_modules/@types/node": { |
||||
"version": "20.4.2", |
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.4.2.tgz", |
||||
"integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==", |
||||
"dev": true |
||||
}, |
||||
"node_modules/asynckit": { |
||||
"version": "0.4.0", |
||||
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", |
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" |
||||
}, |
||||
"node_modules/axios": { |
||||
"version": "1.4.0", |
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.4.0.tgz", |
||||
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", |
||||
"dependencies": { |
||||
"follow-redirects": "^1.15.0", |
||||
"form-data": "^4.0.0", |
||||
"proxy-from-env": "^1.1.0" |
||||
} |
||||
}, |
||||
"node_modules/call-bind": { |
||||
"version": "1.0.2", |
||||
"resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz", |
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", |
||||
"dependencies": { |
||||
"function-bind": "^1.1.1", |
||||
"get-intrinsic": "^1.0.2" |
||||
} |
||||
}, |
||||
"node_modules/combined-stream": { |
||||
"version": "1.0.8", |
||||
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", |
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", |
||||
"dependencies": { |
||||
"delayed-stream": "~1.0.0" |
||||
}, |
||||
"engines": { |
||||
"node": ">= 0.8" |
||||
} |
||||
}, |
||||
"node_modules/delayed-stream": { |
||||
"version": "1.0.0", |
||||
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", |
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", |
||||
"engines": { |
||||
"node": ">=0.4.0" |
||||
} |
||||
}, |
||||
"node_modules/follow-redirects": { |
||||
"version": "1.15.2", |
||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz", |
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", |
||||
"engines": { |
||||
"node": ">=4.0" |
||||
}, |
||||
"peerDependenciesMeta": { |
||||
"debug": { |
||||
"optional": true |
||||
} |
||||
} |
||||
}, |
||||
"node_modules/form-data": { |
||||
"version": "4.0.0", |
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz", |
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", |
||||
"dependencies": { |
||||
"asynckit": "^0.4.0", |
||||
"combined-stream": "^1.0.8", |
||||
"mime-types": "^2.1.12" |
||||
}, |
||||
"engines": { |
||||
"node": ">= 6" |
||||
} |
||||
}, |
||||
"node_modules/function-bind": { |
||||
"version": "1.1.1", |
||||
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz", |
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" |
||||
}, |
||||
"node_modules/get-intrinsic": { |
||||
"version": "1.2.1", |
||||
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz", |
||||
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", |
||||
"dependencies": { |
||||
"function-bind": "^1.1.1", |
||||
"has": "^1.0.3", |
||||
"has-proto": "^1.0.1", |
||||
"has-symbols": "^1.0.3" |
||||
} |
||||
}, |
||||
"node_modules/has": { |
||||
"version": "1.0.3", |
||||
"resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", |
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", |
||||
"dependencies": { |
||||
"function-bind": "^1.1.1" |
||||
}, |
||||
"engines": { |
||||
"node": ">= 0.4.0" |
||||
} |
||||
}, |
||||
"node_modules/has-proto": { |
||||
"version": "1.0.1", |
||||
"resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz", |
||||
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", |
||||
"engines": { |
||||
"node": ">= 0.4" |
||||
} |
||||
}, |
||||
"node_modules/has-symbols": { |
||||
"version": "1.0.3", |
||||
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", |
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", |
||||
"engines": { |
||||
"node": ">= 0.4" |
||||
} |
||||
}, |
||||
"node_modules/mime-db": { |
||||
"version": "1.52.0", |
||||
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", |
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", |
||||
"engines": { |
||||
"node": ">= 0.6" |
||||
} |
||||
}, |
||||
"node_modules/mime-types": { |
||||
"version": "2.1.35", |
||||
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", |
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", |
||||
"dependencies": { |
||||
"mime-db": "1.52.0" |
||||
}, |
||||
"engines": { |
||||
"node": ">= 0.6" |
||||
} |
||||
}, |
||||
"node_modules/object-inspect": { |
||||
"version": "1.12.3", |
||||
"resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", |
||||
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" |
||||
}, |
||||
"node_modules/proxy-from-env": { |
||||
"version": "1.1.0", |
||||
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", |
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" |
||||
}, |
||||
"node_modules/qs": { |
||||
"version": "6.11.2", |
||||
"resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.2.tgz", |
||||
"integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", |
||||
"dependencies": { |
||||
"side-channel": "^1.0.4" |
||||
}, |
||||
"engines": { |
||||
"node": ">=0.6" |
||||
} |
||||
}, |
||||
"node_modules/side-channel": { |
||||
"version": "1.0.4", |
||||
"resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz", |
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", |
||||
"dependencies": { |
||||
"call-bind": "^1.0.0", |
||||
"get-intrinsic": "^1.0.2", |
||||
"object-inspect": "^1.9.0" |
||||
} |
||||
}, |
||||
"node_modules/uglify-js": { |
||||
"version": "3.17.4", |
||||
"resolved": "https://registry.npmmirror.com/uglify-js/-/uglify-js-3.17.4.tgz", |
||||
"integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", |
||||
"dev": true, |
||||
"bin": { |
||||
"uglifyjs": "bin/uglifyjs" |
||||
}, |
||||
"engines": { |
||||
"node": ">=0.8.0" |
||||
} |
||||
} |
||||
}, |
||||
"dependencies": { |
||||
"@types/node": { |
||||
"version": "20.4.2", |
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.4.2.tgz", |
||||
"integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==", |
||||
"dev": true |
||||
}, |
||||
"asynckit": { |
||||
"version": "0.4.0", |
||||
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", |
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" |
||||
}, |
||||
"axios": { |
||||
"version": "1.4.0", |
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.4.0.tgz", |
||||
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", |
||||
"requires": { |
||||
"follow-redirects": "^1.15.0", |
||||
"form-data": "^4.0.0", |
||||
"proxy-from-env": "^1.1.0" |
||||
} |
||||
}, |
||||
"call-bind": { |
||||
"version": "1.0.2", |
||||
"resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz", |
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", |
||||
"requires": { |
||||
"function-bind": "^1.1.1", |
||||
"get-intrinsic": "^1.0.2" |
||||
} |
||||
}, |
||||
"combined-stream": { |
||||
"version": "1.0.8", |
||||
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", |
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", |
||||
"requires": { |
||||
"delayed-stream": "~1.0.0" |
||||
} |
||||
}, |
||||
"delayed-stream": { |
||||
"version": "1.0.0", |
||||
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", |
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" |
||||
}, |
||||
"follow-redirects": { |
||||
"version": "1.15.2", |
||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz", |
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" |
||||
}, |
||||
"form-data": { |
||||
"version": "4.0.0", |
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz", |
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", |
||||
"requires": { |
||||
"asynckit": "^0.4.0", |
||||
"combined-stream": "^1.0.8", |
||||
"mime-types": "^2.1.12" |
||||
} |
||||
}, |
||||
"function-bind": { |
||||
"version": "1.1.1", |
||||
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz", |
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" |
||||
}, |
||||
"get-intrinsic": { |
||||
"version": "1.2.1", |
||||
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz", |
||||
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", |
||||
"requires": { |
||||
"function-bind": "^1.1.1", |
||||
"has": "^1.0.3", |
||||
"has-proto": "^1.0.1", |
||||
"has-symbols": "^1.0.3" |
||||
} |
||||
}, |
||||
"has": { |
||||
"version": "1.0.3", |
||||
"resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", |
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", |
||||
"requires": { |
||||
"function-bind": "^1.1.1" |
||||
} |
||||
}, |
||||
"has-proto": { |
||||
"version": "1.0.1", |
||||
"resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz", |
||||
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" |
||||
}, |
||||
"has-symbols": { |
||||
"version": "1.0.3", |
||||
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", |
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" |
||||
}, |
||||
"mime-db": { |
||||
"version": "1.52.0", |
||||
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", |
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" |
||||
}, |
||||
"mime-types": { |
||||
"version": "2.1.35", |
||||
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", |
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", |
||||
"requires": { |
||||
"mime-db": "1.52.0" |
||||
} |
||||
}, |
||||
"object-inspect": { |
||||
"version": "1.12.3", |
||||
"resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", |
||||
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" |
||||
}, |
||||
"proxy-from-env": { |
||||
"version": "1.1.0", |
||||
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", |
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" |
||||
}, |
||||
"qs": { |
||||
"version": "6.11.2", |
||||
"resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.2.tgz", |
||||
"integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", |
||||
"requires": { |
||||
"side-channel": "^1.0.4" |
||||
} |
||||
}, |
||||
"side-channel": { |
||||
"version": "1.0.4", |
||||
"resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz", |
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", |
||||
"requires": { |
||||
"call-bind": "^1.0.0", |
||||
"get-intrinsic": "^1.0.2", |
||||
"object-inspect": "^1.9.0" |
||||
} |
||||
}, |
||||
"uglify-js": { |
||||
"version": "3.17.4", |
||||
"resolved": "https://registry.npmmirror.com/uglify-js/-/uglify-js-3.17.4.tgz", |
||||
"integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", |
||||
"dev": true |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
{ |
||||
"name": "CatVodOpenJSSpider", |
||||
"version": "1.0.0", |
||||
"description": "", |
||||
"main": "app.js", |
||||
"type": "module", |
||||
"directories": { |
||||
"lib": "lib" |
||||
}, |
||||
"scripts": {}, |
||||
"author": "", |
||||
"license": "ISC", |
||||
"dependencies": { |
||||
"axios": "^1.4.0", |
||||
"qs": "^6.11.2" |
||||
}, |
||||
"devDependencies": { |
||||
"@types/node": "^20.1.5", |
||||
"uglify-js": "^3.17.4" |
||||
} |
||||
} |
||||
@ -0,0 +1,9 @@ |
||||
import {} from './wrapper/index.js'; |
||||
|
||||
// import { test } from './testVideo.js';
|
||||
import { test } from './testAlist.js'; |
||||
|
||||
(async function () { |
||||
await test(); |
||||
debugger; |
||||
})(); |
||||
@ -0,0 +1,51 @@ |
||||
import { __jsEvalReturn } from './kunyu77_open.js'; |
||||
|
||||
var spider = __jsEvalReturn(); |
||||
|
||||
async function test() { |
||||
var spType = null; |
||||
var spVid = null; |
||||
spType = '2'; |
||||
// spVid = '95873';
|
||||
|
||||
await spider.init({ skey: 'siteKey', ext: '' }); |
||||
var classes = JSON.parse(await spider.home(true)); |
||||
console.log(classes); |
||||
var homeVod = JSON.parse(await spider.homeVod()); |
||||
console.log(homeVod); |
||||
if (classes.class && classes.class.length > 0) { |
||||
var page = JSON.parse(await spider.category(spType || classes.class[0].type_id, 0, undefined, {})); |
||||
console.log(page); |
||||
if (page.list && page.list.length > 0) { |
||||
for (const k in page.list) { |
||||
if (k >= 5) break; |
||||
var detail = JSON.parse(await spider.detail(spVid || page.list[k].vod_id)); |
||||
console.log(detail); |
||||
if (detail.list && detail.list.length > 0) { |
||||
var pFlag = detail.list[0].vod_play_from.split('$$$'); |
||||
var pUrls = detail.list[0].vod_play_url.split('$$$'); |
||||
if (pFlag.length > 0 && pUrls.length > 0) { |
||||
for (const i in pFlag) { |
||||
var flag = pFlag[i]; |
||||
var urls = pUrls[i].split('#'); |
||||
if (urls.length > 0) { |
||||
var url = urls[0].split('$')[1]; |
||||
console.log(flag, url); |
||||
var playUrl = await spider.play(flag, url, []); |
||||
console.log(playUrl); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if (spVid) break; |
||||
} |
||||
} |
||||
} |
||||
var search = JSON.parse(await spider.search('奥特曼')); |
||||
console.log(search); |
||||
|
||||
search = JSON.parse(await spider.search('喜欢')); |
||||
console.log(search); |
||||
} |
||||
|
||||
export { test }; |
||||
@ -0,0 +1,266 @@ |
||||
// !!!!! Do not use in release mode. Just a native inject fake wrapper for test spider. !!!!!
|
||||
// !!!!! Do not use in release mode. Just a native inject fake wrapper for test spider. !!!!!
|
||||
// !!!!! Do not use in release mode. Just a native inject fake wrapper for test spider. !!!!!
|
||||
import axios from 'axios'; |
||||
import crypto from 'crypto'; |
||||
import https from 'https'; |
||||
import fs from 'node:fs'; |
||||
import qs from 'qs'; |
||||
import { Uri, _ } from '../lib/cat.js'; |
||||
|
||||
const confs = {}; |
||||
|
||||
function initLocalStorage(storage) { |
||||
if (!_.has(confs, storage)) { |
||||
if (!fs.existsSync('local')) { |
||||
fs.mkdirSync('local'); |
||||
} |
||||
|
||||
const storagePath = 'local/js_' + storage; |
||||
|
||||
if (!fs.existsSync(storagePath)) { |
||||
fs.writeFileSync(storagePath, '{}'); |
||||
confs[storage] = {}; |
||||
} else { |
||||
confs[storage] = JSON.parse(fs.readFileSync(storagePath).toString()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
function localGet(storage, key) { |
||||
initLocalStorage(storage); |
||||
return _.get(confs[storage], key, ''); |
||||
} |
||||
|
||||
function localSet(storage, key, value) { |
||||
initLocalStorage(storage); |
||||
confs[storage][key] = value; |
||||
fs.writeFileSync('local/js_' + storage, JSON.stringify(confs[storage])); |
||||
} |
||||
|
||||
async function request(url, opt) { |
||||
try { |
||||
var data = opt ? opt.data || null : null; |
||||
var postType = opt ? opt.postType || null : null; |
||||
var returnBuffer = opt ? opt.buffer || 0 : 0; |
||||
var timeout = opt ? opt.timeout || 5000 : 5000; |
||||
|
||||
var headers = opt ? opt.headers || {} : {}; |
||||
if (postType == 'form') { |
||||
headers['Content-Type'] = 'application/x-www-form-urlencoded'; |
||||
|
||||
if (data != null) { |
||||
data = qs.stringify(data, { encode: false }); |
||||
} |
||||
} |
||||
let respType = returnBuffer == 1 || returnBuffer == 2 ? 'arraybuffer' : undefined; |
||||
var resp = await axios(url, { |
||||
responseType: respType, |
||||
method: opt ? opt.method || 'get' : 'get', |
||||
headers: headers, |
||||
data: data, |
||||
timeout: timeout, |
||||
httpsAgent: https.Agent({ |
||||
rejectUnauthorized: false, |
||||
}), |
||||
}); |
||||
var data = resp.data; |
||||
|
||||
var resHeader = {}; |
||||
for (const hks of resp.headers) { |
||||
var v = hks[1]; |
||||
resHeader[hks[0]] = Array.isArray(v) ? (v.length == 1 ? v[0] : v) : v; |
||||
} |
||||
|
||||
if (!returnBuffer) { |
||||
if (typeof data === 'object') { |
||||
data = JSON.stringify(data); |
||||
} |
||||
} else if (returnBuffer == 1) { |
||||
return { code: resp.status, headers: resHeader, content: data }; |
||||
} else if (returnBuffer == 2) { |
||||
return { code: resp.status, headers: resHeader, content: data.toString('base64') }; |
||||
} |
||||
return { code: resp.status, headers: resHeader, content: data }; |
||||
} catch (error) { |
||||
console.error(error); |
||||
} |
||||
return { headers: {}, content: '' }; |
||||
} |
||||
|
||||
function base64EncodeBuf(buff, urlsafe = false) { |
||||
return buff.toString(urlsafe ? 'base64url' : 'base64'); |
||||
} |
||||
|
||||
function base64Encode(text, urlsafe = false) { |
||||
return base64EncodeBuf(Buffer.from(text, 'utf8'), urlsafe); |
||||
} |
||||
|
||||
function base64DecodeBuf(text) { |
||||
return Buffer.from(text, 'base64'); |
||||
} |
||||
|
||||
function base64Decode(text) { |
||||
return base64DecodeBuf(text).toString('utf8'); |
||||
} |
||||
|
||||
function md5(text) { |
||||
return crypto.createHash('md5').update(Buffer.from(text, 'utf8')).digest('hex'); |
||||
} |
||||
|
||||
function aes(mode, encrypt, input, inBase64, key, iv, outBase64) { |
||||
if (iv.length == 0) iv = null; |
||||
try { |
||||
if (mode.startsWith('AES/CBC')) { |
||||
switch (key.length) { |
||||
case 16: |
||||
mode = 'aes-128-cbc'; |
||||
break; |
||||
case 32: |
||||
mode = 'aes-256-cbc'; |
||||
break; |
||||
} |
||||
} else if (mode.startsWith('AES/ECB')) { |
||||
switch (key.length) { |
||||
case 16: |
||||
mode = 'aes-128-ecb'; |
||||
break; |
||||
case 32: |
||||
mode = 'aes-256-ecb'; |
||||
break; |
||||
} |
||||
} |
||||
const inBuf = inBase64 ? base64DecodeBuf(input) : Buffer.from(input, 'utf8'); |
||||
let keyBuf = Buffer.from(key); |
||||
if (keyBuf.length < 16) keyBuf = Buffer.concat([keyBuf], 16); |
||||
let ivBuf = iv == null ? Buffer.alloc(0) : Buffer.from(iv); |
||||
if (iv != null && ivBuf.length < 16) ivBuf = Buffer.concat([ivBuf], 16); |
||||
const cipher = encrypt ? crypto.createCipheriv(mode, keyBuf, ivBuf) : crypto.createDecipheriv(mode, keyBuf, ivBuf); |
||||
const outBuf = Buffer.concat([cipher.update(inBuf), cipher.final()]); |
||||
return outBase64 ? base64EncodeBuf(outBuf) : outBuf.toString('utf8'); |
||||
} catch (error) { |
||||
console.log(error); |
||||
} |
||||
return ''; |
||||
} |
||||
|
||||
function des(mode, encrypt, input, inBase64, key, iv, outBase64) { |
||||
try { |
||||
if (mode.startsWith('DESede/CBC')) { |
||||
// https://stackoverflow.com/questions/29831300/convert-desede-ecb-nopadding-algorithm-written-in-java-into-nodejs-using-crypto
|
||||
switch (key.length) { |
||||
case 16: |
||||
mode = 'des-ede-cbc'; |
||||
break; |
||||
case 24: |
||||
mode = 'des-ede3-cbc'; |
||||
break; |
||||
} |
||||
} |
||||
const inBuf = inBase64 ? base64DecodeBuf(input) : Buffer.from(input, 'utf8'); |
||||
let keyBuf = Buffer.from(key); |
||||
if (keyBuf.length < 16) keyBuf = Buffer.concat([keyBuf], 16); |
||||
let ivBuf = iv == null ? Buffer.alloc(0) : Buffer.from(iv); |
||||
if (iv != null && ivBuf.length < 8) ivBuf = Buffer.concat([ivBuf], 8); |
||||
const cipher = encrypt ? crypto.createCipheriv(mode, keyBuf, ivBuf) : crypto.createDecipheriv(mode, keyBuf, ivBuf); |
||||
const outBuf = Buffer.concat([cipher.update(inBuf), cipher.final()]); |
||||
return outBase64 ? base64EncodeBuf(outBuf) : outBuf.toString('utf8'); |
||||
} catch (error) { |
||||
console.log(error); |
||||
} |
||||
return ''; |
||||
} |
||||
|
||||
// pkcs8 only
|
||||
function rsa(mode, pub, encrypt, input, inBase64, key, outBase64) { |
||||
try { |
||||
let pd = undefined; |
||||
const keyObj = pub ? crypto.createPublicKey(key) : crypto.createPrivateKey(key); |
||||
if (!keyObj.asymmetricKeyDetails || !keyObj.asymmetricKeyDetails.modulusLength) return ''; |
||||
const moduleLen = keyObj.asymmetricKeyDetails.modulusLength; |
||||
let blockLen = moduleLen / 8; |
||||
switch (mode) { |
||||
case 'RSA/PKCS1': |
||||
pd = crypto.constants.RSA_PKCS1_PADDING; |
||||
blockLen = encrypt ? blockLen - 11 : blockLen; |
||||
break; |
||||
case 'RSA/None/NoPadding': |
||||
pd = crypto.constants.RSA_NO_PADDING; |
||||
break; |
||||
case 'RSA/None/OAEPPadding': |
||||
pd = crypto.constants.RSA_PKCS1_OAEP_PADDING; |
||||
blockLen = encrypt ? blockLen - 41 : blockLen; |
||||
break; |
||||
default: |
||||
throw Error('not support ' + mode); |
||||
} |
||||
let inBuf = inBase64 ? base64DecodeBuf(input) : Buffer.from(input, 'utf8'); |
||||
let bufIdx = 0; |
||||
let outBuf = Buffer.alloc(0); |
||||
while (bufIdx < inBuf.length) { |
||||
const bufEndIdx = Math.min(bufIdx + blockLen, inBuf.length); |
||||
let tmpInBuf = inBuf.subarray(bufIdx, bufEndIdx); |
||||
if (pd == crypto.constants.RSA_NO_PADDING) { |
||||
if (tmpInBuf.length < blockLen) { |
||||
tmpInBuf = Buffer.concat([Buffer.alloc(128 - tmpInBuf.length), tmpInBuf]); |
||||
} |
||||
} |
||||
let tmpBuf; |
||||
if (pub) { |
||||
tmpBuf = encrypt ? crypto.publicEncrypt({ key: keyObj, padding: pd }, tmpInBuf) : crypto.publicDecrypt({ key: keyObj, padding: pd }, tmpInBuf); |
||||
} else { |
||||
tmpBuf = encrypt ? crypto.privateEncrypt({ key: keyObj, padding: pd }, tmpInBuf) : crypto.privateDecrypt({ key: keyObj, padding: pd }, tmpInBuf); |
||||
} |
||||
bufIdx = bufEndIdx; |
||||
outBuf = Buffer.concat([outBuf, tmpBuf]); |
||||
} |
||||
return outBase64 ? base64EncodeBuf(outBuf) : outBuf.toString('utf8'); |
||||
} catch (error) { |
||||
console.log(error); |
||||
} |
||||
return ''; |
||||
} |
||||
|
||||
var charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789'; |
||||
|
||||
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; |
||||
} |
||||
|
||||
globalThis.local = { |
||||
get: async function (storage, key) { |
||||
return localGet(storage, key); |
||||
}, |
||||
set: async function (storage, key, val) { |
||||
localSet(storage, key, val); |
||||
}, |
||||
}; |
||||
|
||||
globalThis.md5X = md5; |
||||
globalThis.rsaX = rsa; |
||||
globalThis.aesX = aes; |
||||
globalThis.desX = des; |
||||
|
||||
globalThis.req = request; |
||||
|
||||
globalThis.url2Proxy = async function (type, url, headers) { |
||||
let hd = Object.keys(headers).length == 0 ? '_' : encodeURIComponent(JSON.stringify(headers)); |
||||
let uri = new Uri(url); |
||||
let path = uri.path(); |
||||
path = path.substring(path.lastIndexOf('/')); |
||||
let ext = path.indexOf('.') >= 0 ? path.substring(path.indexOf('.')) : '.bin'; |
||||
return 'http://127.0.0.1:13333/up/' + randStr(6) + '/' + type + '/' + hd + '/' + encodeURIComponent(url) + '/' + ext; |
||||
}; |
||||
|
||||
globalThis.js2Proxy = async function (dynamic, siteType, site, url, headers) { |
||||
let hd = Object.keys(headers).length == 0 ? '_' : encodeURIComponent(JSON.stringify(headers)); |
||||
return (dynamic ? 'js2p://_WEB_/' : 'http://127.0.0.1:13333/jp/') + randStr(6) + '/' + siteType + '/' + site + '/' + hd + '/' + encodeURIComponent(url); |
||||
}; |
||||
|
||||
export default {}; |
||||
Loading…
Reference in new issue