mirror of
https://github.com/ls125781003/tvboxtg.git
synced 2026-11-03 18:23:27 +00:00
1230
This commit is contained in:
1 parent
ea11a77fae
commit
135c13982d
36 files changed
+13070
-9881
No files matched your search
File renamed without changes.
-289
@@ -1,289 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 基于原作者 @嗷呜 版本修改
|
||||
# 本资源来源于互联网公开渠道,仅可用于个人学习爬虫技术。
|
||||
# 严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
|
||||
|
||||
from base.spider import Spider
|
||||
from urllib.parse import urlparse, urlencode
|
||||
import re,sys,time,json,urllib3,hashlib,datetime
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
sys.path.append('..')
|
||||
|
||||
class Spider(Spider):
|
||||
api,apisignkey,datasignkey,detail_type,search_data = '', '' , '','',''
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'okhttp/4.12.0',
|
||||
}
|
||||
|
||||
def init(self, extend=""):
|
||||
ext = extend.rstrip()
|
||||
if ext.startswith('http'):
|
||||
self.api = ext.rstrip('/')
|
||||
else:
|
||||
arr = json.loads(ext)
|
||||
self.api = arr['api'].rstrip('/')
|
||||
if self.api.endswith('v1.vod'):
|
||||
self.detail_type = arr.get('detail_type','')
|
||||
self.apisignkey = arr.get('apisignkey', '')
|
||||
if self.apisignkey:
|
||||
self.datasignkey = arr.get('datasignkey', '6QQNUsP3PkD2ajJCPCY8')
|
||||
|
||||
def homeContent(self, filter):
|
||||
if self.api.endswith('v1.vod'):
|
||||
path = '/types'
|
||||
if self.apisignkey and self.datasignkey:
|
||||
path = self.datasign(path)
|
||||
data = self.fetch(f"{self.api}{path}", headers=self.headers, verify=False).text
|
||||
data = json.loads(data[1:] if data.startswith('\ufeff') else data)
|
||||
data = data['data']
|
||||
else:
|
||||
data = self.fetch(f"{self.api}/nav?token=", headers=self.headers, verify=False).json()
|
||||
keys = ["class", "area", "lang", "year", "letter", "by", "sort"]
|
||||
filters = {}
|
||||
classes = []
|
||||
for item in data.get('list',data.get('data',[])):
|
||||
has_non_empty_field = False
|
||||
jsontype_extend = item["type_extend"]
|
||||
classes.append({"type_name": item["type_name"], "type_id": item["type_id"]})
|
||||
for key in keys:
|
||||
if key in jsontype_extend and jsontype_extend[key].strip() != "":
|
||||
has_non_empty_field = True
|
||||
break
|
||||
if has_non_empty_field:
|
||||
filters[str(item["type_id"])] = []
|
||||
for dkey in jsontype_extend:
|
||||
if dkey in keys and jsontype_extend[dkey].strip() != "":
|
||||
values = jsontype_extend[dkey].split(",")
|
||||
value_array = [{"n": value.strip(), "v": value.strip()} for value in values if
|
||||
value.strip() != ""]
|
||||
filters[str(item["type_id"])].append({"key": dkey, "name": dkey, "value": value_array})
|
||||
result = {"class": classes, "filters": filters}
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
if self.api.endswith('v1.vod'):
|
||||
path = '/vodPhbAll'
|
||||
if self.apisignkey and self.datasignkey:
|
||||
keytime = self.keytime()
|
||||
path += self.datasign(f'?apikey={self.apikey()}&keytime={keytime}',keytime)
|
||||
data = self.fetch(f"{self.api}{path}", headers=self.headers, verify=False).text
|
||||
data = json.loads(data[1:] if data.startswith('\ufeff') else data)
|
||||
data = data['data']
|
||||
else:
|
||||
data = self.fetch(f"{self.api}/index_video?token=", headers=self.headers, verify=False).json()
|
||||
videos = []
|
||||
if self.api.endswith('v1.vod'):
|
||||
for item in data['list']: videos.extend(item['vod_list'])
|
||||
elif 'list' in data:
|
||||
for item in data['list']: videos.extend(item['vlist'])
|
||||
elif 'data' in data:
|
||||
for item in data['data']: videos.extend(item['vlist'])
|
||||
return {'list': videos}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
if self.api.endswith('v1.vod'):
|
||||
path = f"?type={tid}&class={extend.get('class', '')}&lang={extend.get('lang', '')}&area={extend.get('area', '')}&year={extend.get('year', '')}&by=&page={pg}&limit=9"
|
||||
if self.apisignkey and self.datasignkey:
|
||||
keytime = self.keytime()
|
||||
path = self.datasign(f'{path}&apikey={self.apikey()}&keytime={keytime}' ,keytime)
|
||||
data = self.fetch(f"{self.api}{path}", headers=self.headers, verify=False).text
|
||||
data = json.loads(data[1:] if data.startswith('\ufeff') else data)
|
||||
data = data['data']
|
||||
else:
|
||||
params = {'tid': tid, 'class': extend.get('class', ''), 'area': extend.get('area', ''), 'lang': extend.get('lang', ''), 'year': extend.get('year', ''), 'limit': '18', 'pg': pg}
|
||||
data = self.fetch(f"{self.api}/video", params=params, headers=self.headers, verify=False).json()
|
||||
if 'data' in data:
|
||||
data = {'list':data['data']}
|
||||
return data
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
if self.api.endswith('v1.vod'):
|
||||
path = f"?page={pg}&limit=10&wd={key}"
|
||||
if self.apisignkey and self.datasignkey:
|
||||
keytime = self.keytime()
|
||||
path = self.datasign(f'{path}&apikey={self.apikey()}&keytime={keytime}',keytime)
|
||||
else:
|
||||
path = f"/search?text={key}&pg={pg}"
|
||||
data = self.fetch(f"{self.api}{path}", headers=self.headers, verify=False).text
|
||||
data = json.loads(data[1:] if data.startswith('\ufeff') else data)
|
||||
if self.api.endswith('v1.vod') and self.detail_type == 'search':
|
||||
self.search_data = data
|
||||
data2 = data.get('list',data.get('data',[]))
|
||||
if 'type' in data2:
|
||||
for item in data2:
|
||||
item.pop('type', None)
|
||||
if not 'list' in data2:
|
||||
data2 = {'list': data2, 'page': pg}
|
||||
return data2
|
||||
|
||||
def detailContent(self, ids):
|
||||
if self.detail_type == 'search':
|
||||
for i in self.search_data['data']['list']:
|
||||
if str(i['vod_id']) == str(ids[0]):
|
||||
data = i
|
||||
break
|
||||
else:
|
||||
if self.api.endswith('v1.vod'):
|
||||
path = f'/detail?vod_id={ids[0]}&rel_limit=10'
|
||||
if self.apisignkey and self.datasignkey:
|
||||
keytime = self.keytime()
|
||||
path = self.datasign(f'{path}&apikey={self.apikey()}&keytime={keytime}',keytime)
|
||||
else:
|
||||
path = f'/video_detail?id={ids[0]}'
|
||||
data = self.fetch(f"{self.api}{path}", headers=self.headers, verify=False).text
|
||||
data = json.loads(data[1:] if data.startswith('\ufeff') else data)
|
||||
data = data['data']
|
||||
if 'vod_info' in data:
|
||||
data = data['vod_info']
|
||||
show = []
|
||||
vod_play_url = []
|
||||
if 'vod_url_with_player' in data:
|
||||
for i in data['vod_url_with_player']:
|
||||
if i['code'] == i['name']:
|
||||
show.append(i['name'])
|
||||
else:
|
||||
show.append(f"{i['name']}\u2005({i['code']})")
|
||||
parse_api = i.get('parse_api','')
|
||||
if parse_api and parse_api.startswith('http'):
|
||||
url = i.get('url','')
|
||||
if url:
|
||||
url2 = '#'.join([i+ '@' + parse_api for i in url.split('#')])
|
||||
vod_play_url.append(url2)
|
||||
else:
|
||||
vod_play_url.append(i.get('url', ''))
|
||||
data.pop('vod_url_with_player')
|
||||
if 'vod_play_list' in data:
|
||||
vod_play_list = data['vod_play_list']
|
||||
for i in vod_play_list.values() if isinstance(vod_play_list, dict) else vod_play_list:
|
||||
parses = ''
|
||||
player_info = i['player_info']
|
||||
if player_info['show'] == i['from']:
|
||||
show.append(player_info['show'])
|
||||
else:
|
||||
show.append(f"{player_info['show']}\u2005({i['from']})")
|
||||
parse = player_info.get('parse','').strip()
|
||||
parse2 = player_info.get('parse2','').strip()
|
||||
if 'parse' in player_info and parse.startswith('http'):
|
||||
parses += parse + ','
|
||||
if 'parse2' in player_info and parse2.startswith('http') and parse2 != parse:
|
||||
parses += parse2
|
||||
parses = parses.rstrip(',')
|
||||
url = ''
|
||||
urls = i['urls']
|
||||
for j in urls.values() if isinstance(urls, dict) else urls:
|
||||
if parse:
|
||||
url += f"{j['name']}${j['url']}@{parses}#"
|
||||
else:
|
||||
url += f"{j['name']}${j['url']}#"
|
||||
url = url.rstrip('#')
|
||||
vod_play_url.append(url)
|
||||
if 'vod_play_list' in data:
|
||||
data.pop('vod_play_list')
|
||||
if 'rel_vods' in data:
|
||||
data.pop('rel_vods')
|
||||
if 'type' in data:
|
||||
data.pop('type')
|
||||
if show:
|
||||
data['vod_play_from'] = '$$$'.join(show)
|
||||
if vod_play_url:
|
||||
data['vod_play_url'] = '$$$'.join(vod_play_url)
|
||||
return {'list': [data]}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
video_pattern = re.compile(r'https?:\/\/.*\.(?:m3u8|mp4|flv)')
|
||||
jx,url,ua = 0,'','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36'
|
||||
if '@' in id:
|
||||
rawurl, jxapi = id.split('@', 1)
|
||||
jxapis = jxapi.split(',', 1) if ',' in jxapi else [jxapi]
|
||||
for jxapi_ in jxapis:
|
||||
try:
|
||||
res = self.fetch(f"{jxapi_}{rawurl}", headers=self.headers, timeout=10, verify=False).text
|
||||
res = json.loads(res[1:] if res.startswith('\ufeff') else res)
|
||||
url = res.get('url', '')
|
||||
if url.startswith('http'):
|
||||
jxua = res.get('ua')
|
||||
if jxua:
|
||||
ua = jxua
|
||||
except Exception:
|
||||
url = ''
|
||||
continue
|
||||
if url.startswith('http'):
|
||||
jx = 0
|
||||
else:
|
||||
url = rawurl
|
||||
jx = 0 if video_pattern.match(rawurl) else 1
|
||||
else:
|
||||
url = id
|
||||
jx = 0 if video_pattern.match(id) else 1
|
||||
if url.startswith('NBY'):
|
||||
jx, url = 0,''
|
||||
return {'jx': jx,'parse': 0,'url': url,'header': {'User-Agent': ua}}
|
||||
|
||||
def keytime(self):
|
||||
return str(int(datetime.datetime.now().timestamp()))
|
||||
|
||||
def md5(self, str):
|
||||
hash_obj = hashlib.md5()
|
||||
hash_obj.update(str.encode('utf-8'))
|
||||
return hash_obj.hexdigest()
|
||||
|
||||
def apikey(self):
|
||||
date = datetime.datetime.now()
|
||||
year = str(date.year)
|
||||
hour = str(date.hour)
|
||||
minute = str(date.minute)
|
||||
if len(hour) < 2:
|
||||
hour = "0" + hour
|
||||
if len(minute) < 2:
|
||||
minute = "0" + minute
|
||||
str_value = self.apisignkey
|
||||
sign_str = f"{year}:{hour}:{year}:{minute}:{str_value}"
|
||||
md5_hash = self.md5(sign_str)
|
||||
return md5_hash
|
||||
|
||||
def datasign(self, url='', timestamp=''):
|
||||
parsed_url = urlparse(url)
|
||||
query_params = self._parse_query_params(parsed_url.query)
|
||||
if not timestamp:
|
||||
timestamp = str(time.time())
|
||||
query_params["timestamp"] = timestamp
|
||||
sorted_params = sorted(query_params.items(), key=lambda x: x[0])
|
||||
sign = self._generate_signature(sorted_params)
|
||||
query_params["datasign"] = sign
|
||||
new_query = urlencode(query_params)
|
||||
new_url = parsed_url._replace(query=new_query).geturl()
|
||||
return new_url
|
||||
|
||||
def _parse_query_params(self, query_str):
|
||||
params = {}
|
||||
if not query_str:
|
||||
return params
|
||||
for param in query_str.split('&'):
|
||||
if '=' not in param:
|
||||
continue
|
||||
key, value = param.split('=', 1)
|
||||
if value:
|
||||
params[key] = value
|
||||
return params
|
||||
|
||||
def _generate_signature(self, sorted_params):
|
||||
param_str = '&'.join([f"{k}={v}" for k, v in sorted_params])
|
||||
raw_sign_str = f"{param_str}{self.datasignkey}"
|
||||
md5_hash = hashlib.md5(raw_sign_str.encode('utf-8')).hexdigest()
|
||||
return md5_hash
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
@@ -0,0 +1,663 @@
|
||||
/*小心儿悠悠
|
||||
配置说明:
|
||||
{
|
||||
"host": "https://xxx", // 必填,站点地址
|
||||
"ver": 1, // 可选,API版本:1或2,默认1
|
||||
"cms": "", // 可选,CMS地址
|
||||
"from": "", // 可选,搜索来源
|
||||
"category": 1, // 可选,分类模式:0-无分类 1-普通 2-搜索
|
||||
"timeout": 5, // 可选,超时时间(秒),默认5
|
||||
"custom_first": 0, // 可选,自定义解析优先:0-否 1-是
|
||||
"source_order": ["线路A", "线路B"], // 可选,线路排序
|
||||
|
||||
// UA配置//可选,特殊站点需要自定义
|
||||
"ua": {
|
||||
"host": "UA字符串", // 主机检测UA
|
||||
"config": "UA字符串", // 配置获取UA
|
||||
"home": "UA字符串", // 首页UA
|
||||
"category": "UA字符串", // 分类页UA
|
||||
"search": "UA字符串", // 搜索页UA
|
||||
"parse": "UA字符串", // 解析UA
|
||||
"player": "UA字符串" // 播放UA
|
||||
},
|
||||
|
||||
// 解析配置
|
||||
"parse": {
|
||||
"线路名": "解析地址或parse:前缀"
|
||||
}
|
||||
}
|
||||
|
||||
使用示例:
|
||||
{
|
||||
"host": "https://xxx",
|
||||
"ver": 1,
|
||||
"source_order": ["超清", "高清", "标清"],
|
||||
"ua": {
|
||||
"home": "Mozilla/5.0...",
|
||||
"player": "Mozilla/5.0..."
|
||||
},
|
||||
"parse": {
|
||||
"超清": "https://jx.xxx/?url=",
|
||||
"高清": "parse:https://parse.xxx.com/"
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
import { Crypto, _ } from 'assets://js/lib/cat.js';
|
||||
|
||||
const 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";
|
||||
const TV_UA = "Dalvik/2.1.0 (Linux; U; Android 9; Pixel Build/PI)";
|
||||
var def_header = {'User-Agent': TV_UA};
|
||||
var cachedPlayUrls = {};
|
||||
var HOST;
|
||||
|
||||
var foxConfig = {
|
||||
host: '',
|
||||
headers: {'User-Agent': TV_UA},
|
||||
timeout: 5000,
|
||||
ver: 1,
|
||||
uas: {},
|
||||
parses: {},
|
||||
custom_parses: {},
|
||||
froms: '',
|
||||
detail: [],
|
||||
custom_first: 0,
|
||||
category: 1,
|
||||
cms: '',
|
||||
sourceOrder: []
|
||||
};
|
||||
|
||||
var recommendCache = {
|
||||
data: [],
|
||||
timestamp: 0,
|
||||
cacheTime: 30 * 60 * 1000
|
||||
};
|
||||
|
||||
function decodeBase64(str) {
|
||||
try {
|
||||
return Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(str));
|
||||
} catch (e) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
function request(reqUrl, header, data, method) {
|
||||
try {
|
||||
let optObj = {
|
||||
headers: header || foxConfig.headers,
|
||||
method: method || 'get',
|
||||
timeout: foxConfig.timeout,
|
||||
};
|
||||
if (method === 'post') {
|
||||
optObj.data = data || {};
|
||||
optObj.postType = 'form';
|
||||
}
|
||||
let res = req(reqUrl, optObj);
|
||||
return res.content;
|
||||
} catch (e) {
|
||||
throw new Error('请求失败: ' + reqUrl);
|
||||
}
|
||||
}
|
||||
|
||||
function getdata(url, data, method) {
|
||||
try {
|
||||
url = /^http/.test(url) ? url : `${HOST}${url}`;
|
||||
let res = request(url, foxConfig.headers, data, method);
|
||||
return JSON.parse(res);
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function sortSources(play_from, play_urls) {
|
||||
if (!foxConfig.sourceOrder || foxConfig.sourceOrder.length === 0) {
|
||||
return { play_from, play_urls };
|
||||
}
|
||||
|
||||
let sourceMap = new Map();
|
||||
for (let i = 0; i < play_from.length; i++) {
|
||||
if (i < play_urls.length) {
|
||||
sourceMap.set(play_from[i], {
|
||||
originalName: play_from[i],
|
||||
url: play_urls[i],
|
||||
index: i
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let sorted_play_from = [];
|
||||
let sorted_play_urls = [];
|
||||
|
||||
for (let sourceName of foxConfig.sourceOrder) {
|
||||
for (let [key, source] of sourceMap) {
|
||||
if (key.includes(sourceName)) {
|
||||
sorted_play_from.push(source.originalName);
|
||||
sorted_play_urls.push(source.url);
|
||||
sourceMap.delete(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let [key, source] of sourceMap) {
|
||||
sorted_play_from.push(source.originalName);
|
||||
sorted_play_urls.push(source.url);
|
||||
}
|
||||
|
||||
return {
|
||||
play_from: sorted_play_from,
|
||||
play_urls: sorted_play_urls
|
||||
};
|
||||
}
|
||||
|
||||
async function getRecommendVideos() {
|
||||
try {
|
||||
const now = Date.now();
|
||||
if (recommendCache.data.length > 0 && now - recommendCache.timestamp < recommendCache.cacheTime) {
|
||||
return recommendCache.data;
|
||||
}
|
||||
|
||||
let headers = Object.assign({}, foxConfig.headers);
|
||||
let recommend_ua = foxConfig.uas.home || foxConfig.uas.homeVideo;
|
||||
if (recommend_ua) headers['User-Agent'] = recommend_ua;
|
||||
|
||||
let videos = [];
|
||||
let res = request(HOST + '/api.php/Appfox/vodList?sort=热门&page=1&limit=12', headers);
|
||||
let response = JSON.parse(res);
|
||||
|
||||
if (response.data && response.data.list) {
|
||||
videos = response.data.list.slice(0, 12);
|
||||
} else if (response.data && response.data.recommend_list) {
|
||||
videos = response.data.recommend_list.slice(0, 12);
|
||||
} else if (Array.isArray(response.data)) {
|
||||
videos = response.data.slice(0, 12);
|
||||
}
|
||||
|
||||
if (videos.length > 0) {
|
||||
recommendCache.data = videos;
|
||||
recommendCache.timestamp = now;
|
||||
}
|
||||
|
||||
return videos;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function init(cfg) {
|
||||
try {
|
||||
if (!cfg.ext) throw new Error('配置参数为空');
|
||||
|
||||
let extValue = cfg.ext;
|
||||
|
||||
if (typeof extValue === 'string') {
|
||||
try {
|
||||
extValue = decodeBase64(extValue);
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
extValue = JSON.parse(extValue);
|
||||
} catch (e) {
|
||||
if (extValue.startsWith('http')) {
|
||||
extValue = {host: extValue};
|
||||
} else {
|
||||
throw new Error('配置格式错误');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let host = extValue.host || '';
|
||||
if (!host) throw new Error('主机地址为空');
|
||||
|
||||
if (!host.match(/^https?:\/\/[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:\d+)?(\/)?$/)) {
|
||||
let headers = Object.assign({}, foxConfig.headers);
|
||||
let custom_ua = foxConfig.uas.host;
|
||||
if (custom_ua) headers['User-Agent'] = custom_ua;
|
||||
|
||||
let res = request(host, headers);
|
||||
let result = JSON.parse(res);
|
||||
host = result.apiDomain;
|
||||
}
|
||||
|
||||
foxConfig.host = host.replace(/\/+$/, '');
|
||||
HOST = foxConfig.host;
|
||||
|
||||
foxConfig.ver = extValue.ver === 2 ? 2 : 1;
|
||||
foxConfig.cms = extValue.cms || '';
|
||||
foxConfig.froms = extValue.from || '';
|
||||
foxConfig.custom_parses = extValue.parse || {};
|
||||
foxConfig.custom_first = extValue.custom_first || 0;
|
||||
foxConfig.category = extValue.category || 1;
|
||||
foxConfig.timeout = (extValue.timeout || 5) * 1000;
|
||||
foxConfig.sourceOrder = extValue.source_order || [];
|
||||
|
||||
let ua = extValue.ua;
|
||||
if (ua) {
|
||||
if (typeof ua === 'string') {
|
||||
foxConfig.headers['User-Agent'] = ua;
|
||||
} else if (typeof ua === 'object') {
|
||||
foxConfig.uas = {
|
||||
host: ua.host,
|
||||
config: ua.config,
|
||||
home: ua.home,
|
||||
category: ua.category,
|
||||
search: ua.search,
|
||||
parse: ua.parse,
|
||||
player: ua.player || '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'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (foxConfig.cms) {
|
||||
let cms = foxConfig.cms.replace(/\/+$/, '');
|
||||
if (cms.match(/^https?:\/\/.*\/vod/)) {
|
||||
cms += cms.includes('?') ? '&' : '?';
|
||||
foxConfig.cms = cms;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
throw new Error('初始化失败: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function home(filter) {
|
||||
try {
|
||||
if (!HOST || foxConfig.category === 0) return '{"class":[]}';
|
||||
|
||||
let headers = Object.assign({}, foxConfig.headers);
|
||||
let custom_ua = foxConfig.uas.home;
|
||||
if (custom_ua) headers['User-Agent'] = custom_ua;
|
||||
|
||||
if (foxConfig.cms && foxConfig.category !== 2) {
|
||||
let class_url = foxConfig.cms.replace(/&ac=videolist|ac=videolist&|ac=videolist|ac=detail/g, '');
|
||||
if (!class_url.includes('ac=')) class_url += 'ac=list';
|
||||
|
||||
let classRes = request(class_url, headers);
|
||||
let classes = JSON.parse(classRes).class;
|
||||
|
||||
let recommendVideos = await getRecommendVideos();
|
||||
let dataRes = request(foxConfig.cms.replace(/&$/, ''), headers);
|
||||
let data = JSON.parse(dataRes);
|
||||
data.class = classes;
|
||||
|
||||
if (recommendVideos.length > 0) {
|
||||
data.recommend = recommendVideos;
|
||||
}
|
||||
|
||||
return JSON.stringify(data);
|
||||
} else {
|
||||
let res = request(HOST + '/api.php/Appfox/init', headers);
|
||||
let response = JSON.parse(res);
|
||||
let classes = [];
|
||||
for (let i of response.data.type_list) {
|
||||
classes.push({type_id: i.type_id, type_name: i.type_name});
|
||||
}
|
||||
|
||||
let recommendVideos = await getRecommendVideos();
|
||||
let result = {class: classes};
|
||||
|
||||
if (recommendVideos.length > 0) {
|
||||
result.recommend = recommendVideos;
|
||||
}
|
||||
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
} catch (e) {
|
||||
return '{"class":[]}';
|
||||
}
|
||||
}
|
||||
|
||||
async function homeVod() {
|
||||
try {
|
||||
if (!HOST || foxConfig.category === 0) return '{"list":[]}';
|
||||
|
||||
if (foxConfig.cms && foxConfig.category !== 2) {
|
||||
let headers = Object.assign({}, foxConfig.headers);
|
||||
let custom_ua = foxConfig.uas.homeVideo || foxConfig.uas.home;
|
||||
if (custom_ua) headers['User-Agent'] = custom_ua;
|
||||
|
||||
let res = request(foxConfig.cms.replace(/&$/, ''), headers);
|
||||
let data = JSON.parse(res);
|
||||
|
||||
if (!data.list || data.list.length === 0) {
|
||||
let recommendVideos = await getRecommendVideos();
|
||||
if (recommendVideos.length > 0) {
|
||||
data.list = recommendVideos;
|
||||
}
|
||||
}
|
||||
|
||||
if (foxConfig.category === 2 && data.list) {
|
||||
for (let i of data.list) {
|
||||
i.vod_id = 'msearch:' + i.vod_id;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
|
||||
let headers = Object.assign({}, foxConfig.headers);
|
||||
let custom_ua = foxConfig.uas.homeVideo || foxConfig.uas.home;
|
||||
if (custom_ua) headers['User-Agent'] = custom_ua;
|
||||
|
||||
let path = foxConfig.ver === 2 ? 'nav' : 'index';
|
||||
let res = request(HOST + '/api.php/Appfox/' + path, headers);
|
||||
let response = JSON.parse(res);
|
||||
let videos = [];
|
||||
|
||||
if (foxConfig.ver === 2) {
|
||||
let navigationId = '';
|
||||
for (let i of response.data) {
|
||||
if (i.navigationId) {
|
||||
navigationId = i.navigationId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (navigationId) {
|
||||
let navRes = request(HOST + '/api.php/Appfox/nav_video?id=' + navigationId, headers);
|
||||
let navData = JSON.parse(navRes);
|
||||
for (let item of navData.data) {
|
||||
if (item.videos) {
|
||||
videos = videos.concat(item.videos);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let item of response.data) {
|
||||
if (item.banner) videos = videos.concat(item.banner);
|
||||
if (item.categories) {
|
||||
for (let cat of item.categories) {
|
||||
if (cat.videos) videos = videos.concat(cat.videos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (videos.length === 0) {
|
||||
videos = await getRecommendVideos();
|
||||
}
|
||||
|
||||
if (foxConfig.category === 2) {
|
||||
for (let i of videos) {
|
||||
i.vod_id = 'msearch:' + i.vod_id;
|
||||
}
|
||||
}
|
||||
return JSON.stringify({list: videos.slice(0, 20)});
|
||||
} catch (e) {
|
||||
try {
|
||||
let recommendVideos = await getRecommendVideos();
|
||||
return JSON.stringify({list: recommendVideos});
|
||||
} catch (e2) {
|
||||
return '{"list":[]}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function category(tid, pg, filter, extend) {
|
||||
try {
|
||||
if (!HOST) return '{"list":[]}';
|
||||
|
||||
pg = parseInt(pg) || 1;
|
||||
let headers = Object.assign({}, foxConfig.headers);
|
||||
let category_ua = foxConfig.uas.category;
|
||||
if (category_ua) headers['User-Agent'] = category_ua;
|
||||
|
||||
if (foxConfig.cms && foxConfig.category !== 2) {
|
||||
let res = request(foxConfig.cms + 'pg=' + pg + '&t=' + tid, headers);
|
||||
let data = JSON.parse(res);
|
||||
if (foxConfig.category === 2 && data.list) {
|
||||
for (let i of data.list) {
|
||||
i.vod_id = 'msearch:' + i.vod_id;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(data);
|
||||
} else {
|
||||
let res = request(HOST + '/api.php/Appfox/vodList?type_id=' + tid + '&page=' + pg, headers);
|
||||
let response = JSON.parse(res);
|
||||
let videos = response.data?.list || response.data?.recommend_list || [];
|
||||
let data = {list: videos};
|
||||
if (foxConfig.category === 2) {
|
||||
for (let i of data.list) {
|
||||
i.vod_id = 'msearch:' + i.vod_id;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
} catch (e) {
|
||||
return '{"list":[]}';
|
||||
}
|
||||
}
|
||||
|
||||
async function search(wd, quick, pg) {
|
||||
try {
|
||||
if (!HOST) return '{"list":[]}';
|
||||
|
||||
pg = parseInt(pg) || 1;
|
||||
let headers = Object.assign({}, foxConfig.headers);
|
||||
let search_ua = foxConfig.uas.search;
|
||||
if (search_ua) headers['User-Agent'] = search_ua;
|
||||
|
||||
if (foxConfig.cms) {
|
||||
let cms = foxConfig.cms.split('?')[0] + '?';
|
||||
let res = request(cms + 'ac=detail&wd=' + encodeURIComponent(wd), headers);
|
||||
let response = JSON.parse(res);
|
||||
foxConfig.detail = response.list || [];
|
||||
return JSON.stringify(response);
|
||||
} else {
|
||||
let path = HOST + '/api.php/Appfox/vod?ac=detail&wd=' + encodeURIComponent(wd);
|
||||
if (foxConfig.froms) path += '&from=' + foxConfig.froms;
|
||||
let res = request(path, headers);
|
||||
let response = JSON.parse(res);
|
||||
foxConfig.detail = response.list || [];
|
||||
return JSON.stringify(response);
|
||||
}
|
||||
} catch (e) {
|
||||
return '{"list":[]}';
|
||||
}
|
||||
}
|
||||
|
||||
async function detail(id) {
|
||||
try {
|
||||
let headers = Object.assign({}, foxConfig.headers);
|
||||
let detail_ua = foxConfig.uas.detail || foxConfig.uas.search;
|
||||
if (detail_ua) headers['User-Agent'] = detail_ua;
|
||||
|
||||
let video = null;
|
||||
for (let i of foxConfig.detail) {
|
||||
if (String(i.vod_id) === String(id)) {
|
||||
video = Object.assign({}, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!video) {
|
||||
if (foxConfig.cms) {
|
||||
let cms = foxConfig.cms.split('?')[0] + '?';
|
||||
let res = request(cms + 'ac=detail&ids=' + id, headers);
|
||||
let response = JSON.parse(res);
|
||||
video = response.list?.[0] || null;
|
||||
} else {
|
||||
let res = request(HOST + '/api.php/Appfox/vod?ac=detail&ids=' + id, headers);
|
||||
let response = JSON.parse(res);
|
||||
video = response.list?.[0] || null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!video) return '{"list":[]}';
|
||||
|
||||
let play_from = video.vod_play_from ? video.vod_play_from.split('$$$') : [];
|
||||
let play_urls = video.vod_play_url ? video.vod_play_url.split('$$$') : [];
|
||||
|
||||
let sortedSources = sortSources(play_from, play_urls);
|
||||
play_from = sortedSources.play_from;
|
||||
play_urls = sortedSources.play_urls;
|
||||
|
||||
try {
|
||||
let config_headers = Object.assign({}, foxConfig.headers);
|
||||
let custom_ua = foxConfig.uas.config;
|
||||
if (custom_ua) config_headers['User-Agent'] = custom_ua;
|
||||
|
||||
let res = request(HOST + '/api.php/Appfox/config', config_headers);
|
||||
let config_response = JSON.parse(res);
|
||||
let player_list = config_response.data?.playerList || [];
|
||||
let jiexi_data_list = config_response.data?.jiexiDataList || [];
|
||||
|
||||
let player_map = {};
|
||||
for (let player of player_list) {
|
||||
player_map[player.playerCode] = player;
|
||||
}
|
||||
|
||||
let processed_play_urls = [];
|
||||
for (let idx = 0; idx < play_from.length; idx++) {
|
||||
let play_code = play_from[idx];
|
||||
if (player_map[play_code]) {
|
||||
let player_info = player_map[play_code];
|
||||
if (player_info.playerCode !== player_info.playerName) {
|
||||
play_from[idx] = player_info.playerName + '\u2005(' + play_code + ')';
|
||||
}
|
||||
}
|
||||
if (idx < play_urls.length) {
|
||||
let urls = play_urls[idx].split('#');
|
||||
let processed_urls = [];
|
||||
for (let url of urls) {
|
||||
let parts = url.split('$');
|
||||
if (parts.length >= 2) {
|
||||
parts[1] = play_code + '@' + parts[1];
|
||||
processed_urls.push(parts.join('$'));
|
||||
} else {
|
||||
processed_urls.push(url);
|
||||
}
|
||||
}
|
||||
processed_play_urls.push(processed_urls.join('#'));
|
||||
}
|
||||
}
|
||||
|
||||
video.vod_play_from = play_from.join('$$$');
|
||||
video.vod_play_url = processed_play_urls.join('$$$');
|
||||
|
||||
foxConfig.parses = {};
|
||||
for (let p of jiexi_data_list) {
|
||||
if (p.url && p.url.startsWith('http')) {
|
||||
foxConfig.parses[p.playerCode] = p.url;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
return JSON.stringify({list: [video]});
|
||||
} catch (e) {
|
||||
return '{"list":[]}';
|
||||
}
|
||||
}
|
||||
|
||||
async function play(flag, id, flags) {
|
||||
try {
|
||||
let parts = id.split('@', 2);
|
||||
if (parts.length < 2) {
|
||||
throw new Error('ID格式错误');
|
||||
}
|
||||
let play_from = parts[0];
|
||||
let raw_url = parts[1];
|
||||
|
||||
let jx = 0, parse = 0, parsed = 0;
|
||||
let headers = Object.assign({}, foxConfig.headers);
|
||||
let parse_ua = foxConfig.uas.parse;
|
||||
if (parse_ua) headers['User-Agent'] = parse_ua;
|
||||
|
||||
let player_ua = foxConfig.uas.player || MOBILE_UA;
|
||||
let url = raw_url;
|
||||
|
||||
let parses_main = [];
|
||||
if (foxConfig.custom_first === 1) {
|
||||
parses_main.push(foxConfig.custom_parses);
|
||||
parses_main.push(foxConfig.parses);
|
||||
} else {
|
||||
parses_main.push(foxConfig.parses);
|
||||
parses_main.push(foxConfig.custom_parses);
|
||||
}
|
||||
|
||||
outer: for (let parses2 of parses_main) {
|
||||
if (!parsed && !url.match(/https?:\/\/.*\.(m3u8|mp4|flv|mkv)/)) {
|
||||
for (let key in parses2) {
|
||||
if (!play_from.includes(key)) continue;
|
||||
|
||||
let parsers = parses2[key];
|
||||
if (Array.isArray(parsers)) {
|
||||
for (let parser of parsers) {
|
||||
if (parser && parser.startsWith('parse:')) {
|
||||
url = parser.split('parse:')[1] + raw_url;
|
||||
jx = 0;
|
||||
parse = 1;
|
||||
break outer;
|
||||
}
|
||||
if (parser && parser.startsWith('http')) {
|
||||
try {
|
||||
let res = request(parser + raw_url, headers);
|
||||
let response = JSON.parse(res);
|
||||
if (response.url && response.url.startsWith('http')) {
|
||||
url = response.url;
|
||||
parsed = 1;
|
||||
break outer;
|
||||
}
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (parsers && parsers.startsWith('parse:')) {
|
||||
url = parsers.split('parse:')[1] + raw_url;
|
||||
jx = 0;
|
||||
parse = 1;
|
||||
break outer;
|
||||
}
|
||||
if (parsers && parsers.startsWith('http')) {
|
||||
try {
|
||||
let res = request(parsers + raw_url, headers);
|
||||
let response = JSON.parse(res);
|
||||
if (response.url && response.url.startsWith('http')) {
|
||||
url = response.url;
|
||||
parsed = 1;
|
||||
break outer;
|
||||
}
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parsed || parse) break;
|
||||
}
|
||||
}
|
||||
if (parsed || parse) break;
|
||||
}
|
||||
|
||||
if (!(url.match(/https?:\/\/.*\.(m3u8|mp4|flv|mkv)/) || parsed === 1)) {
|
||||
jx = 1;
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
jx: jx,
|
||||
parse: parse,
|
||||
url: url,
|
||||
header: {'User-Agent': player_ua}
|
||||
});
|
||||
} catch (e) {
|
||||
return JSON.stringify({
|
||||
jx: 0,
|
||||
parse: 0,
|
||||
url: id,
|
||||
header: {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function __jsEvalReturn() {
|
||||
return {
|
||||
init: init,
|
||||
home: home,
|
||||
homeVod: homeVod,
|
||||
category: category,
|
||||
search: search,
|
||||
detail: detail,
|
||||
play: play
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user