上传文件至「js」

This commit is contained in:
2026-08-15 10:27:57 +02:00
parent bc8c872cec
commit e80e63704c
4 changed files with 3539 additions and 0 deletions
+1659
View File
@@ -0,0 +1,1659 @@
/*
@header({
searchable: 1,
filterable: 0,
quickSearch: 0,
title: '⚽ 体育cat|聚合',
author: 'OpenClaw',
lang: 'cat',
style: { type: 'rect', ratio: 0.75 }
})
*/
const __sports_src_0 = (function () {
let host = 'https://www.88kanqiu.la';
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36';
const headers = {
'User-Agent': UA,
'Referer': host + '/',
'Accept': 'text/html,application/json,*/*'
};
const B64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
function stripHtml(s) {
return String(s || '')
.replace(/<script[\s\S]*?<\/script>/gi, '')
.replace(/<style[\s\S]*?<\/style>/gi, '')
.replace(/<[^>]+>/g, '')
.replace(/&nbsp;/g, ' ')
.replace(/&amp;/g, '&')
.replace(/&quot;/g, '"')
.replace(/&#39;/g, "'")
.replace(/\s+/g, ' ')
.trim();
}
function absUrl(url) {
url = String(url || '').trim();
if (!url) return '';
if (/^https?:\/\//i.test(url)) return url;
if (url.indexOf('//') === 0) return 'https:' + url;
if (url.charAt(0) === '/') return host + url;
return host + '/' + url;
}
function safeJson(text, def) {
try { return JSON.parse(text || '{}'); } catch (e) { return def || {}; }
}
// TV 端 JS 环境不一定有 atob/TextDecoder;这里按 PHP 源的 base64_decode 逻辑手写 UTF-8 解码。
function base64ToUtf8(str) {
str = String(str || '').replace(/[^A-Za-z0-9+/=]/g, '');
const bytes = [];
for (let i = 0; i < str.length; i += 4) {
const c1 = B64_CHARS.indexOf(str.charAt(i));
const c2 = B64_CHARS.indexOf(str.charAt(i + 1));
const c3 = B64_CHARS.indexOf(str.charAt(i + 2));
const c4 = B64_CHARS.indexOf(str.charAt(i + 3));
if (c1 < 0 || c2 < 0) continue;
const n = (c1 << 18) | (c2 << 12) | ((c3 < 0 ? 0 : c3) << 6) | (c4 < 0 ? 0 : c4);
bytes.push((n >> 16) & 255);
if (str.charAt(i + 2) !== '=') bytes.push((n >> 8) & 255);
if (str.charAt(i + 3) !== '=') bytes.push(n & 255);
}
let out = '';
for (let i = 0; i < bytes.length;) {
const b1 = bytes[i++];
if (b1 < 0x80) {
out += String.fromCharCode(b1);
} else if (b1 >= 0xc0 && b1 < 0xe0) {
const b2 = bytes[i++] || 0;
out += String.fromCharCode(((b1 & 0x1f) << 6) | (b2 & 0x3f));
} else if (b1 >= 0xe0 && b1 < 0xf0) {
const b2 = bytes[i++] || 0;
const b3 = bytes[i++] || 0;
out += String.fromCharCode(((b1 & 0x0f) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3f));
} else {
const b2 = bytes[i++] || 0;
const b3 = bytes[i++] || 0;
const b4 = bytes[i++] || 0;
const cp = ((b1 & 0x07) << 18) | ((b2 & 0x3f) << 12) | ((b3 & 0x3f) << 6) | (b4 & 0x3f);
const u = cp - 0x10000;
out += String.fromCharCode(0xd800 + (u >> 10), 0xdc00 + (u & 0x3ff));
}
}
return out;
}
function decodePlaySource(raw) {
raw = String(raw || '').trim();
if (!raw) return null;
for (let prefix = 0; prefix <= 8; prefix++) {
for (let suffix = 0; suffix <= 4; suffix++) {
if (raw.length <= prefix + suffix) continue;
const candidate = raw.slice(prefix, raw.length - suffix);
try {
const decoded = base64ToUtf8(candidate);
const pos = decoded.indexOf('{');
if (pos < 0) continue;
const obj = JSON.parse(decoded.slice(pos));
if (obj && typeof obj === 'object') return obj;
} catch (e) {}
}
}
return null;
}
function toDirectPlayUrl(url) {
url = String(url || '').trim();
if (!url) return '';
const m = url.match(/[?&]url=([^&]+)/);
if (m && m[1]) {
try { return decodeURIComponent(m[1]); } catch (e) { return m[1]; }
}
return url;
}
async function fetchText(url, referer) {
const hd = {
'User-Agent': UA,
'Referer': referer || host + '/',
'Accept': 'text/html,application/json,*/*'
};
// 部分壳只有 Java.req,部分壳只有 req;两种都兼容。
if (typeof Java !== 'undefined' && Java && Java.req) {
const r = Java.req(url, { headers: hd });
return String((r && (r.body || r.content)) || '');
}
const r2 = await req(url, { headers: hd });
return String((r2 && (r2.content || r2.body)) || '');
}
function getClasses() {
return [
{ type_id: 'live', type_name: '正在直播' },
{ type_id: '0', type_name: '全部直播' },
{ type_id: '1', type_name: '篮球直播' },
{ type_id: '8', type_name: '足球直播' },
{ type_id: '21', type_name: '其他直播' }
];
}
function parseList(html, onlyLiving) {
const list = [];
const reg = /<li[^>]*class=["'][^"']*list-group-item[^"']*["'][^>]*>[\s\S]*?<\/li>/gi;
let m;
while ((m = reg.exec(String(html || ''))) !== null) {
const item = m[0];
const hrefMatch = item.match(/<a[^>]+href=["']([^"']*\/live\/\d+\/play[^"']*)["'][^>]*>/i);
if (!hrefMatch) continue;
const time = stripHtml((item.match(/class=["'][^"']*category-game-time[^"']*["'][^>]*>([\s\S]*?)<\//i) || [])[1]);
const gameType = stripHtml((item.match(/class=["'][^"']*game-type[^"']*["'][^>]*>([\s\S]*?)<\//i) || [])[1]);
const teams = [];
const teamReg = /class=["'][^"']*team-name[^"']*["'][^>]*>([\s\S]*?)<\//gi;
let tm;
while ((tm = teamReg.exec(item)) !== null) teams.push(stripHtml(tm[1]));
let title = [time, gameType, teams.length >= 2 ? teams[0] + ' vs ' + teams[1] : teams.join(' vs ')].filter(Boolean).join(' ').trim();
if (!title || title === 'vs') title = stripHtml(item).replace(/直播中|观看|高清|视频直播/g, '').trim();
if (!title) continue;
const btnTextMatch = item.match(/<a[^>]+href=["'][^"']*\/live\/\d+\/play[^"']*["'][^>]*>([\s\S]*?)<\/a>/i);
const remark = stripHtml(btnTextMatch ? btnTextMatch[1] : '') || '直播中';
if (onlyLiving && remark !== '直播中') continue;
const picMatch = item.match(/<img[^>]+(?:data-src|src)=["']([^"']+)["']/i);
list.push({
vod_id: absUrl(hrefMatch[1]) + '###' + encodeURIComponent(title),
vod_name: title,
vod_pic: absUrl(picMatch ? picMatch[1] : '/static/img/default.png'),
vod_remarks: remark
});
}
return list;
}
async function fetchGroupList(group) {
let paths = ['/'];
if (group === 'basketball') {
paths = ['/match/1/live', '/match/2/live', '/match/20/live', '/match/4/live'];
} else if (group === 'football') {
paths = ['/match/3/live', '/match/8/live', '/match/9/live', '/match/10/live', '/match/14/live', '/match/15/live', '/match/12/live', '/match/13/live', '/match/7/live', '/match/11/live', '/match/27/live', '/match/26/live', '/match/31/live', '/match/23/live'];
} else if (group === 'other') {
paths = ['/match/21/live', '/match/29/live', '/match/25/live', '/match/19/live', '/match/38/live'];
}
const all = [];
const seen = {};
for (let i = 0; i < paths.length; i++) {
try {
const html = await fetchText(host + paths[i], host + '/');
const items = parseList(html);
for (let j = 0; j < items.length; j++) {
const key = items[j].vod_id;
if (seen[key]) continue;
seen[key] = true;
all.push(items[j]);
}
} catch (e) {}
}
return all;
}
async function init(cfg) {
if (cfg && cfg.ext && String(cfg.ext).indexOf('http') === 0) host = String(cfg.ext).trim().replace(/\/$/, '');
}
async function home(filter) {
return JSON.stringify({ class: getClasses(), filters: {} });
}
async function homeVod() {
return await category('0', 1, false, {});
}
async function category(tid, pg, filter, extend) {
tid = String((extend && extend.cateId) || tid || '0');
pg = parseInt(pg) || 1;
let group = '';
if (tid === '1' || tid === 'basketball') group = 'basketball';
else if (tid === '8' || tid === 'football') group = 'football';
else if (tid === '21' || tid === 'other') group = 'other';
let list = [];
try {
const onlyLiving = tid === 'live';
list = group ? await fetchGroupList(group) : parseList(await fetchText(host + '/', host + '/'), onlyLiving);
} catch (e) {
list = [];
}
return JSON.stringify({ code: 1, msg: '数据列表', page: pg, pagecount: 1, limit: 20, total: list.length, list });
}
async function detail(id) {
id = Array.isArray(id) ? id[0] : id;
let realId = String(id || '');
let displayName = '赛事直播';
if (realId.indexOf('###') >= 0) {
const parts = realId.split('###');
realId = parts[0];
try { displayName = decodeURIComponent(parts[1] || '赛事直播'); } catch (e) { displayName = parts[1] || '赛事直播'; }
}
const match = realId.match(/\/live\/(\d+)\/play/);
const gameId = match ? match[1] : '';
if (!gameId) return JSON.stringify({ code: 1, page: 1, pagecount: 1, limit: 0, total: 0, list: [] });
let playUrls = '';
try {
const content = await fetchText(host + '/live/' + gameId + '/source', realId);
const json = safeJson(content, {});
const data = decodePlaySource(json.data || '');
const links = (data && data.links) || [];
const arr = [];
for (let i = 0; i < links.length; i++) {
const u = toDirectPlayUrl(links[i].url || '');
if (u) arr.push((links[i].name || ('线路' + (i + 1))) + '$' + u);
}
playUrls = arr.join('#');
} catch (e) {
playUrls = '';
}
return JSON.stringify({
code: 1,
msg: '数据列表',
page: 1,
pagecount: 1,
limit: 1,
total: 1,
list: [{
vod_id: realId,
vod_name: displayName,
vod_pic: host + '/static/img/default.png',
vod_remarks: '直播中',
vod_play_from: '88看球',
vod_play_url: playUrls,
vod_content: '实时体育直播'
}]
});
}
async function search(wd, quick, pg) {
return JSON.stringify({ code: 1, msg: '数据列表', page: parseInt(pg) || 1, pagecount: 1, limit: 20, total: 0, list: [] });
}
async function play(flag, id, flags) {
const isDirect = /\.(m3u8|mp4)(\?|$)/i.test(String(id || ''));
return JSON.stringify({ parse: isDirect ? 0 : 1, url: id, header: headers });
}
// OK影视/部分 CAT 壳兼容入口。
async function homeContent(filter) { return safeJson(await home(filter), { class: [], filters: {} }); }
async function homeVideoContent() { return safeJson(await homeVod(), { list: [] }); }
async function categoryContent(tid, pg, filter, extend) { return safeJson(await category(tid, pg, filter, extend || {}), { list: [] }); }
async function detailContent(ids) { return safeJson(await detail(ids), { list: [] }); }
async function searchContent(wd, quick, pg) { return safeJson(await search(wd, quick, pg || 1), { list: [] }); }
async function playerContent(flag, id, flags) { return safeJson(await play(flag, id, flags), { parse: 1, url: id }); }
return { init, home, homeVod, category, search, detail, play, homeContent, homeVideoContent, categoryContent, detailContent, searchContent, playerContent };
})();
const __sports_src_1 = (function () {
let host = 'https://kafeizhibo.cc';
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36';
const headers = {
'User-Agent': UA,
'Referer': host + '/pc',
'Accept': 'application/json, text/plain, */*'
};
function safeJson(text, def) {
try { return JSON.parse(text || '{}'); } catch (e) { return def || {}; }
}
function absUrl(url) {
url = String(url || '').trim();
if (!url) return '';
if (/^https?:\/\//i.test(url)) return url;
if (url.indexOf('//') === 0) return 'https:' + url;
if (url.charAt(0) === '/') return host + url;
return host + '/' + url;
}
function clean(s) {
return String(s || '').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();
}
async function fetchJson(url) {
const r = await req(url, { headers });
return safeJson((r && (r.content || r.body)) || '{}', {});
}
function getClasses() {
return [
{ type_id: 'all', type_name: '全部直播' },
{ type_id: 'hot', type_name: '热门直播' },
{ type_id: 'nba', type_name: 'NBA' },
{ type_id: '1', type_name: '足球直播' },
{ type_id: '2', type_name: '篮球直播' },
{ type_id: '3', type_name: '网球直播' },
{ type_id: '19', type_name: '台球直播' },
{ type_id: 'schedule', type_name: '赛程列表' },
{ type_id: 'recordings', type_name: '录像' }
];
}
function titleOf(it) {
const mi = it.match_info || {};
const league = it.league_name || mi.league_name || it.league || '';
const home = it.home_team || mi.home_team || (it.homeTeam && it.homeTeam.name) || '';
const away = it.away_team || mi.away_team || (it.awayTeam && it.awayTeam.name) || '';
const title = it.title || it.name || '';
if (title && title !== it.name) return clean(title);
if (league && home && away) return clean(league + ' ' + home + ' vs ' + away);
return clean(title || it.name || ('直播间 ' + (it.room_id || it.id || '')));
}
function remarkOf(it) {
const parts = [];
const status = it.status || (it.match_info && it.match_info.status) || '';
if (status === 'live' || it.is_live) parts.push('直播中');
else if (status === 'online') parts.push('在线');
else if (status === 'upcoming') parts.push('未开赛');
else if (status) parts.push(status);
const score = (it.home_score !== undefined && it.away_score !== undefined) ? (it.home_score + '-' + it.away_score) : '';
if (score && score !== '0-0') parts.push(score);
if (it.heat) parts.push('热度:' + it.heat);
if (it.name && it.title && it.name !== it.title) parts.push(it.name);
return clean(parts.join(' ')) || '直播';
}
function picOf(it) {
return absUrl(it.screenshot || it.avatar || it.home_team_logo || it.away_team_logo || (it.homeTeam && it.homeTeam.logo) || (it.awayTeam && it.awayTeam.logo) || '/images/logo.png');
}
function itemToVod(it) {
const roomId = it.room_id || (it.archor && it.archor.room_id) || (Array.isArray(it.archors) && it.archors[0] && it.archors[0].room_id) || '';
if (!roomId) return null;
return {
vod_id: String(roomId) + '###' + encodeURIComponent(titleOf(it)),
vod_name: titleOf(it),
vod_pic: picOf(it),
vod_remarks: remarkOf(it)
};
}
function recordingToVod(it) {
const matchId = it.match_id || it.id || '';
if (!matchId) return null;
const name = titleOf(it);
return {
vod_id: 'rec$' + String(matchId) + '###' + encodeURIComponent(name),
vod_name: name,
vod_pic: absUrl(it.cover_image || it.screenshot || it.home_team_logo || it.away_team_logo || '/images/logo.png'),
vod_remarks: clean([it.start_time || '', it.recording_count ? ('录像:' + it.recording_count) : '录像'].filter(Boolean).join(' '))
};
}
async function init(cfg) {
if (cfg && cfg.ext && String(cfg.ext).indexOf('http') === 0) host = String(cfg.ext).trim().replace(/\/$/, '');
}
async function home(filter) {
return JSON.stringify({ class: getClasses(), filters: {} });
}
async function homeVod() {
return await category('all', 1, false, {});
}
async function category(tid, pg, filter, extend) {
tid = String((extend && extend.cateId) || tid || 'all');
pg = parseInt(pg) || 1;
const size = 30;
let apiUrl = '';
if (tid === 'schedule') {
apiUrl = host + '/api/v1/schedule?type=all&page=' + pg + '&size=' + size + '&_t=' + Date.now();
} else if (tid === 'recordings') {
apiUrl = host + '/api/v1/recordings?page=' + pg + '&size=' + size + '&_t=' + Date.now();
} else if (tid === 'nba') {
// 官网没有单独 nba 参数;用篮球赛程聚合后按 NBA 关键字过滤,有 NBA 时显示 NBA,无 NBA 时为空不混入其他篮球。
apiUrl = host + '/api/v1/schedule?type=2&page=' + pg + '&size=100&_t=' + Date.now();
} else {
const type = tid === 'all' ? '' : tid;
apiUrl = host + '/api/v1/archor?type=' + encodeURIComponent(type) + '&_t=' + Date.now();
}
let list = [];
let total = 0;
try {
const json = await fetchJson(apiUrl);
const data = Array.isArray(json.data) ? json.data : [];
const seen = {};
for (let i = 0; i < data.length; i++) {
if (tid === 'recordings') {
const vod = recordingToVod(data[i]);
if (vod && !seen[vod.vod_id]) { seen[vod.vod_id] = true; list.push(vod); }
} else if (tid === 'nba') {
const title = titleOf(data[i]);
if (!/NBA|美职篮|美国职业篮球/i.test(title)) continue;
if (Array.isArray(data[i].archors) && data[i].archors.length) {
for (let j = 0; j < data[i].archors.length; j++) {
const merged = Object.assign({}, data[i], data[i].archors[j], {
title,
screenshot: data[i].screenshot || data[i].archors[j].screenshot
});
const vod = itemToVod(merged);
if (vod && !seen[vod.vod_id]) { seen[vod.vod_id] = true; list.push(vod); }
}
} else {
const vod = itemToVod(data[i]);
if (vod && !seen[vod.vod_id]) { seen[vod.vod_id] = true; list.push(vod); }
}
} else if (tid === 'schedule' && Array.isArray(data[i].archors) && data[i].archors.length) {
for (let j = 0; j < data[i].archors.length; j++) {
const merged = Object.assign({}, data[i], data[i].archors[j], {
title: titleOf(data[i]),
screenshot: data[i].screenshot || data[i].archors[j].screenshot
});
const vod = itemToVod(merged);
if (vod && !seen[vod.vod_id]) { seen[vod.vod_id] = true; list.push(vod); }
}
} else {
const vod = itemToVod(data[i]);
if (vod && !seen[vod.vod_id]) { seen[vod.vod_id] = true; list.push(vod); }
}
}
total = tid === 'nba' ? list.length : (json.total || list.length);
} catch (e) {
list = [];
}
return JSON.stringify({ code: 1, msg: '数据列表', page: pg, pagecount: 1, limit: size, total, list });
}
async function detail(id) {
id = Array.isArray(id) ? id[0] : id;
let roomId = String(id || '');
let displayName = '咖啡直播';
if (roomId.indexOf('###') >= 0) {
const parts = roomId.split('###');
roomId = parts[0];
try { displayName = decodeURIComponent(parts[1] || displayName); } catch (e) { displayName = parts[1] || displayName; }
}
if (roomId.indexOf('rec$') === 0) {
const matchId = roomId.slice(4);
let vod = {
vod_id: roomId,
vod_name: displayName,
vod_pic: host + '/images/logo.png',
vod_remarks: '录像',
vod_play_from: '咖啡录像',
vod_play_url: '',
vod_content: '咖啡直播赛事录像'
};
try {
const json = await fetchJson(host + '/api/v1/match/' + encodeURIComponent(matchId) + '/recordings?_t=' + Date.now());
const data = json.data || {};
const match = data.match || {};
const urls = [];
const replays = Array.isArray(data.replays) ? data.replays : [];
const highlights = Array.isArray(data.highlights) ? data.highlights : [];
for (let i = 0; i < replays.length; i++) {
if (replays[i].video_url) urls.push(clean(replays[i].title || ('录像' + (i + 1))) + '$' + replays[i].video_url);
}
for (let i = 0; i < highlights.length; i++) {
if (highlights[i].video_url) urls.push(clean(highlights[i].title || ('集锦' + (i + 1))) + '$' + highlights[i].video_url);
}
vod = {
vod_id: roomId,
vod_name: titleOf(match) || displayName,
vod_pic: absUrl((replays[0] && replays[0].cover_image) || match.cover_image || match.home_team_logo || match.away_team_logo || '/images/logo.png'),
vod_remarks: clean([match.start_time || '', match.home_score !== undefined ? (match.home_score + '-' + match.away_score) : ''].filter(Boolean).join(' ')) || '录像',
vod_play_from: '咖啡录像',
vod_play_url: urls.join('#'),
vod_content: '咖啡直播赛事录像'
};
} catch (e) {}
return JSON.stringify({ code: 1, msg: '数据列表', page: 1, pagecount: 1, limit: 1, total: 1, list: [vod] });
}
if (!roomId) return JSON.stringify({ code: 1, page: 1, pagecount: 1, limit: 0, total: 0, list: [] });
let vod = {
vod_id: roomId,
vod_name: displayName,
vod_pic: host + '/images/logo.png',
vod_remarks: '直播',
vod_play_from: '咖啡直播',
vod_play_url: '',
vod_content: '咖啡直播实时体育直播'
};
try {
const json = await fetchJson(host + '/api/v1/room/' + encodeURIComponent(roomId) + '?_t=' + Date.now());
const data = json.data || {};
const room = data.room_info || {};
const archor = data.archor || {};
const signals = Array.isArray(data.signals) ? data.signals : [];
const urls = [];
const seen = {};
function addLine(name, url) {
url = String(url || '').trim();
if (!url || seen[url]) return;
seen[url] = true;
urls.push(clean(name || ('线路' + (urls.length + 1))) + '$' + url);
}
for (let i = 0; i < signals.length; i++) addLine(signals[i].name, signals[i].stream_url);
addLine(archor.name, archor.stream_url);
const title = room.title || displayName;
vod = {
vod_id: roomId,
vod_name: clean(title),
vod_pic: absUrl(archor.screenshot || room.avatar || archor.avatar || '/images/logo.png'),
vod_remarks: remarkOf(Object.assign({}, room, archor)),
vod_play_from: '咖啡直播',
vod_play_url: urls.join('#'),
vod_content: clean(room.notice || room.notice_h5 || '咖啡直播实时体育直播')
};
} catch (e) {}
return JSON.stringify({ code: 1, msg: '数据列表', page: 1, pagecount: 1, limit: 1, total: 1, list: [vod] });
}
async function search(wd, quick, pg) {
return JSON.stringify({ code: 1, msg: '数据列表', page: parseInt(pg) || 1, pagecount: 1, limit: 20, total: 0, list: [] });
}
async function play(flag, id, flags) {
return JSON.stringify({ parse: 0, url: id, header: headers });
}
async function homeContent(filter) { return safeJson(await home(filter), { class: [], filters: {} }); }
async function homeVideoContent() { return safeJson(await homeVod(), { list: [] }); }
async function categoryContent(tid, pg, filter, extend) { return safeJson(await category(tid, pg, filter, extend || {}), { list: [] }); }
async function detailContent(ids) { return safeJson(await detail(ids), { list: [] }); }
async function searchContent(wd, quick, pg) { return safeJson(await search(wd, quick, pg || 1), { list: [] }); }
async function playerContent(flag, id, flags) { return safeJson(await play(flag, id, flags), { parse: 0, url: id }); }
return { init, home, homeVod, category, search, detail, play, homeContent, homeVideoContent, categoryContent, detailContent, searchContent, playerContent };
})();
const __sports_src_2 = (function () {
const API_BASE = 'https://01cs01.fusk39cd.com/api/web/live_lists';
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
const headers = {
'User-Agent': UA,
'Accept': 'application/json, text/plain, */*',
'Referer': 'https://01cs01.fusk39cd.com/'
};
const PAGE_SIZE = 20;
function safeString(v) {
if (v === null || v === undefined || v === 'null') return '';
return String(v);
}
function safeJson(text, def) {
if (text && typeof text === 'object') return text;
try { return JSON.parse(text || '{}'); } catch (e) { return def || {}; }
}
async function fetchJson(url) {
if (typeof Java !== 'undefined' && Java && Java.req) {
const r = Java.req(url, { headers });
return safeJson((r && (r.body || r.content)) || '{}', {});
}
const r2 = await req(url, { headers });
return safeJson((r2 && (r2.content || r2.body)) || '{}', {});
}
function getClasses() {
return [
{ type_id: '1', type_name: '全部' },
{ type_id: '2', type_name: '足球' },
{ type_id: '3', type_name: '篮球' }
];
}
async function init(cfg) {}
async function home(filter) {
return JSON.stringify({ class: getClasses(), filters: {} });
}
async function homeVod() {
return await category('1', 1, false, {});
}
async function category(tid, pg, filter, extend) {
const page = Math.max(parseInt(pg || '1', 10) || 1, 1);
const typeId = safeString(tid || '1') || '1';
const list = [];
try {
const url = API_BASE + '/' + encodeURIComponent(typeId);
const json = await fetchJson(url);
const rows = json && json.code === 200 && json.data && Array.isArray(json.data.data) ? json.data.data : [];
for (let i = 0; i < rows.length; i++) {
const item = rows[i];
if (!item.tournament_id) continue;
const type = safeString(item.type || typeId);
const tournamentId = safeString(item.tournament_id);
const memberId = safeString(item.member_id);
const homeTeam = safeString(item.home_team_zh);
const awayTeam = safeString(item.away_team_zh);
const name = [homeTeam, awayTeam].filter(Boolean).join(' VS ') || safeString(item.league_name_zh) || tournamentId;
list.push({
vod_id: type + '|' + tournamentId + '|' + memberId,
vod_name: name,
vod_pic: safeString(item.cover),
vod_remarks: safeString(item.league_name_zh) || safeString(item.match_time) || safeString(item.status)
});
}
} catch (e) {
return JSON.stringify({ code: 1, page, pagecount: 1, limit: PAGE_SIZE, total: 0, list: [] });
}
return JSON.stringify({
code: 1,
msg: '数据列表',
page,
pagecount: list.length >= PAGE_SIZE ? page + 1 : page,
limit: PAGE_SIZE,
total: list.length,
list
});
}
async function detail(id) {
const idList = Array.isArray(id) ? id : String(id || '').split(',').filter(Boolean);
const list = [];
for (let n = 0; n < idList.length; n++) {
const vid = safeString(idList[n]).trim();
const parts = vid.split('|');
if (parts.length !== 3) continue;
const type = parts[0];
const tournamentId = parts[1];
const memberId = parts[2];
try {
const url = API_BASE + '/' + encodeURIComponent(type) + '/detail/' + encodeURIComponent(tournamentId) + '?member_id=' + encodeURIComponent(memberId);
const json = await fetchJson(url);
if (!json || json.code !== 200) continue;
const detailObj = json.data && json.data.detail ? json.data.detail : {};
const moreArr = json.data && Array.isArray(json.data.more) ? json.data.more : [];
const homeTeam = safeString(detailObj.home_team_zh);
const awayTeam = safeString(detailObj.away_team_zh);
const vodName = [homeTeam, awayTeam].filter(Boolean).join(' VS ') || safeString(detailObj.league_name_zh) || vid;
const playFromList = [];
const playUrlList = [];
for (let i = 0; i < moreArr.length; i++) {
const source = moreArr[i];
const username = safeString(source.username) || ('线路' + (i + 1));
const urls = [];
const flv = safeString(source.screen_url);
const m3u8 = safeString(source.screen_url_m3u8);
if (flv) urls.push('线路一$' + flv);
if (m3u8) urls.push('线路二$' + m3u8);
if (!urls.length) continue;
playFromList.push(username.replace(/\$|#/g, ''));
playUrlList.push(urls.join('#'));
}
list.push({
vod_id: vid,
vod_name: vodName,
vod_pic: safeString(detailObj.cover),
type_name: safeString(detailObj.league_name_zh),
vod_remarks: safeString(detailObj.match_time) || safeString(detailObj.status),
vod_content: safeString(detailObj.room_notice) || '体育直播',
vod_play_from: playFromList.join('$$$') || '919体育',
vod_play_url: playUrlList.join('$$$') || ('暂无播放$' + vid)
});
} catch (e) {}
}
return JSON.stringify({ code: 1, msg: '数据列表', page: 1, pagecount: 1, limit: list.length, total: list.length, list });
}
async function search(wd, quick, pg) {
return JSON.stringify({ code: 1, msg: '数据列表', page: parseInt(pg) || 1, pagecount: 1, limit: 20, total: 0, list: [] });
}
async function play(flag, id, flags) {
const url = safeString(id).replace(/\*\*\*/g, '#');
if (!/^https?:\/\//i.test(url)) return JSON.stringify({ parse: 0, jx: 0, url: '', msg: '暂无播放地址' });
return JSON.stringify({ parse: 0, jx: 0, url, header: headers });
}
async function homeContent(filter) { return safeJson(await home(filter), { class: [], filters: {} }); }
async function homeVideoContent() { return safeJson(await homeVod(), { list: [] }); }
async function categoryContent(tid, pg, filter, extend) { return safeJson(await category(tid, pg, filter, extend || {}), { list: [] }); }
async function detailContent(ids) { return safeJson(await detail(ids), { list: [] }); }
async function searchContent(wd, quick, pg) { return safeJson(await search(wd, quick, pg || 1), { list: [] }); }
async function playerContent(flag, id, flags) { return safeJson(await play(flag, id, flags), { parse: 0, url: id }); }
return { init, home, homeVod, category, search, detail, play, homeContent, homeVideoContent, categoryContent, detailContent, searchContent, playerContent };
})();
const __sports_src_3 = (function () {
let host = 'https://m.jrskk.com';
const hosts = ['https://m.jrskk.com', 'https://m.jrs21.com', 'https://www.jrs33.com', 'https://3.swjrzx.com'];
const UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';
const defaultPic = 'https://im-imgs-bucket.oss-accelerate.aliyuncs.com/icon-192.png';
let cacheTime = 0;
let cacheHtml = '';
const B64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
function stripHtml(s) {
return String(s || '')
.replace(/<script[\s\S]*?<\/script>/gi, '')
.replace(/<style[\s\S]*?<\/style>/gi, '')
.replace(/<[^>]+>/g, '')
.replace(/&nbsp;/g, ' ')
.replace(/&amp;/g, '&')
.replace(/&quot;/g, '"')
.replace(/&#39;/g, "'")
.replace(/\s+/g, ' ')
.trim();
}
function cleanText(s) { return String(s || '').replace(/\s+/g, ' ').trim(); }
function absUrl(url, base) {
url = String(url || '').trim();
base = base || host;
if (!url) return '';
if (/^https?:\/\//i.test(url)) return url;
if (url.indexOf('//') === 0) return 'https:' + url;
if (url.charAt(0) === '/') return base + url;
return base + '/' + url;
}
function utf8ToBase64Url(str) {
str = unescape(encodeURIComponent(String(str || '')));
let out = '';
for (let i = 0; i < str.length; i += 3) {
const c1 = str.charCodeAt(i);
const c2 = str.charCodeAt(i + 1);
const c3 = str.charCodeAt(i + 2);
out += B64_CHARS.charAt(c1 >> 2);
out += B64_CHARS.charAt(((c1 & 3) << 4) | ((c2 || 0) >> 4));
out += isNaN(c2) ? '=' : B64_CHARS.charAt(((c2 & 15) << 2) | ((c3 || 0) >> 6));
out += isNaN(c3) ? '=' : B64_CHARS.charAt(c3 & 63);
}
return out.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}
function base64UrlToUtf8(str) {
str = String(str || '').replace(/-/g, '+').replace(/_/g, '/');
while (str.length % 4) str += '=';
let bytes = [];
for (let i = 0; i < str.length; i += 4) {
const c1 = B64_CHARS.indexOf(str.charAt(i));
const c2 = B64_CHARS.indexOf(str.charAt(i + 1));
const c3 = B64_CHARS.indexOf(str.charAt(i + 2));
const c4 = B64_CHARS.indexOf(str.charAt(i + 3));
if (c1 < 0 || c2 < 0) continue;
const n = (c1 << 18) | (c2 << 12) | ((c3 < 0 ? 0 : c3) << 6) | (c4 < 0 ? 0 : c4);
bytes.push((n >> 16) & 255);
if (str.charAt(i + 2) !== '=') bytes.push((n >> 8) & 255);
if (str.charAt(i + 3) !== '=') bytes.push(n & 255);
}
let raw = '';
for (let j = 0; j < bytes.length; j++) raw += String.fromCharCode(bytes[j]);
try { return decodeURIComponent(escape(raw)); } catch (e) { return raw; }
}
function safeJson(text, def) { try { return JSON.parse(text || '{}'); } catch (e) { return def || {}; } }
function matchCategory(tid, league, name, stype, hot) {
tid = String(tid || 'all');
const text = league + ' ' + name;
if (tid === 'all' || tid === 'live') return true;
if (tid === 'hot') return !!hot || /(NBA|CBA|英超|西甲|意甲|德甲|法甲|欧冠|中超|世界杯|世俱杯|亚冠|热门)/i.test(text);
if (tid === 'basketball') return stype === 'lq' || /(NBA|CBA|WNBA|NBL|篮球|篮)/i.test(text);
if (tid === 'football') return stype === 'zq' || (/(足球|英超|西甲|意甲|德甲|法甲|欧冠|欧联|中超|亚冠|足协|世界杯|世俱|巴西甲|巴西乙|日职|韩K|联赛|杯)/i.test(text) && !/(NBA|CBA|WNBA|NBL|篮球|篮)/i.test(text));
if (tid === 'other') return !matchCategory('basketball', league, name, stype, hot) && !matchCategory('football', league, name, stype, hot);
return true;
}
async function fetchText(url, referer) {
const hd = { 'User-Agent': UA, 'Referer': referer || host + '/', 'Accept': 'text/html,application/json,*/*', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8' };
if (typeof Java !== 'undefined' && Java && Java.req) {
const r = await Java.req(url, { headers: hd });
if (typeof r === 'string') return r;
return String((r && (r.body || r.content || r.data)) || '');
}
const r2 = await req(url, { headers: hd });
return String((r2 && (r2.content || r2.body)) || '');
}
async function fetchHome(force) {
if (!force && cacheHtml && Date.now() - cacheTime < 60000) return cacheHtml;
for (let i = 0; i < hosts.length; i++) {
try {
const html = await fetchText(hosts[i] + '/', hosts[i] + '/');
if (html && (/loc_match|lab_team|JRKAN|play\/steam/i).test(html)) {
host = hosts[i]; cacheHtml = html; cacheTime = Date.now(); return html;
}
} catch (e) {}
}
return cacheHtml || '';
}
function firstMatch(text, reg) { const m = String(text || '').match(reg); return m ? m[1] : ''; }
function parseList(html, tid) {
const list = [];
const reg = /<ul\b[^>]*class=["'][^"']*item[^"']*["'][^>]*>[\s\S]*?<\/ul>/gi;
let m;
while ((m = reg.exec(String(html || ''))) !== null) {
const item = m[0];
if (!/class=["'][^"']*ok[^"']*me[^"']*["']/i.test(item)) continue;
const links = [];
const areg = /<a\b([^>]*class=["'][^"']*ok[^"']*me[^"']*["'][^>]*)>([\s\S]*?)<\/a>/gi;
let am;
while ((am = areg.exec(item)) !== null) {
const attrs = am[1];
const href = firstMatch(attrs, /href=["']([^"']+)["']/i) || firstMatch(attrs, /data-play=["']([^"']+)["']/i);
if (!href || href === 'javascript:void(0)') continue;
const name = stripHtml(am[2]) || ('线路' + (links.length + 1));
links.push({ name, url: absUrl(href, host) });
}
if (!links.length) continue;
const league = stripHtml(firstMatch(item, /class=["'][^"']*lab_events[^"']*["'][\s\S]*?<span[^>]*class=["']name["'][^>]*>([\s\S]*?)<\/span>/i));
const time = stripHtml(firstMatch(item, /class=["'][^"']*lab_time[^"']*["'][^>]*>([\s\S]*?)<\/li>/i));
const home = stripHtml(firstMatch(item, /class=["'][^"']*lab_team_home[^"']*["'][\s\S]*?<strong[^>]*class=["']name["'][^>]*>([\s\S]*?)<\/strong>/i));
const away = stripHtml(firstMatch(item, /class=["'][^"']*lab_team_away[^"']*["'][\s\S]*?<strong[^>]*class=["']name["'][^>]*>([\s\S]*?)<\/strong>/i));
const stype = firstMatch(item, /data-stype=["']([^"']+)["']/i);
const hot = /class=["'][^"']*hot[^"']*["']/i.test(item);
let name = [time, league, [home, away].filter(Boolean).join(' vs ')].filter(Boolean).join(' ');
if (!name) name = stripHtml(item).slice(0, 80) || '赛事直播';
if (!matchCategory(tid, league, name, stype, hot)) continue;
const pic = absUrl(firstMatch(item, /<img[^>]+src=["']([^"']+)["']/i) || defaultPic, host);
const payload = { name, pic, links };
list.push({ vod_id: 'jrs$' + utf8ToBase64Url(JSON.stringify(payload)), vod_name: name, vod_pic: pic, vod_remarks: links.map(x => x.name).slice(0, 3).join('/') || '直播' });
}
return list;
}
function getClasses() {
return [
{ type_id: 'live', type_name: '正在直播' },
{ type_id: 'all', type_name: '全部赛程' },
{ type_id: 'basketball', type_name: '篮球直播' },
{ type_id: 'football', type_name: '足球直播' },
{ type_id: 'hot', type_name: '热门赛事' },
{ type_id: 'other', type_name: '其他赛事' }
];
}
async function init(cfg) { if (cfg && cfg.ext && String(cfg.ext).indexOf('http') === 0) host = String(cfg.ext).replace(/\/$/, ''); }
async function home(filter) { return JSON.stringify({ class: getClasses(), filters: {} }); }
async function homeVod() { return await category('live', 1, false, {}); }
async function category(tid, pg, filter, extend) {
const html = await fetchHome(false);
const list = parseList(html, tid || 'all');
return JSON.stringify({ code: 1, msg: '数据列表', page: parseInt(pg) || 1, pagecount: 1, limit: list.length, total: list.length, list });
}
async function detail(id) {
id = Array.isArray(id) ? id[0] : id;
let payload = null;
id = String(id || '');
if (id.indexOf('jrs$') === 0) payload = safeJson(base64UrlToUtf8(id.slice(4)), null);
if (!payload && /^https?:\/\//i.test(id)) payload = { name: '赛事直播', pic: defaultPic, links: [{ name: '直播', url: id }] };
if (!payload) return JSON.stringify({ code: 1, list: [], page: 1, pagecount: 1, total: 0 });
const playUrl = (payload.links || []).map((x, i) => (x.name || ('线路' + (i + 1))) + '$' + x.url).join('#');
return JSON.stringify({ code: 1, msg: '数据列表', page: 1, pagecount: 1, limit: 1, total: 1, list: [{ vod_id: id, vod_name: payload.name || '赛事直播', vod_pic: payload.pic || defaultPic, vod_remarks: '直播', vod_content: 'JRKAN 体育赛事直播。部分线路为网页播放器,播放器可嗅探播放。', vod_play_from: 'JRS直播', vod_play_url: playUrl }] });
}
async function search(wd, quick, pg) { return JSON.stringify({ code: 1, msg: '数据列表', page: parseInt(pg) || 1, pagecount: 1, limit: 20, total: 0, list: [] }); }
async function play(flag, id, flags) { return JSON.stringify({ parse: /\.(m3u8|mp4|flv)(\?|$)/i.test(String(id || '')) ? 0 : 1, url: id, header: { 'User-Agent': UA, 'Referer': host + '/' } }); }
async function homeContent(filter) { return safeJson(await home(filter), { class: [], filters: {} }); }
async function homeVideoContent() { return safeJson(await homeVod(), { list: [] }); }
async function categoryContent(tid, pg, filter, extend) { return safeJson(await category(tid, pg, filter, extend || {}), { list: [] }); }
async function detailContent(ids) { return safeJson(await detail(ids), { list: [] }); }
async function searchContent(wd, quick, pg) { return safeJson(await search(wd, quick, pg || 1), { list: [] }); }
async function playerContent(flag, id, flags) { return safeJson(await play(flag, id, flags), { parse: 1, url: id }); }
return { init, home, homeVod, category, search, detail, play, homeContent, homeVideoContent, categoryContent, detailContent, searchContent, playerContent };
})();
const __sports_src_4 = (function () {
let host = 'https://www.iqzhibo.com';
const dbHost = 'https://www.doubaozhibo.com';
const dbScheduleApi = dbHost + '/api/v1/schedules/public/local';
const dbPlaybackApi = dbHost + '/api/v1/playbacks';
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36';
function getHeaders(referer) {
return {
'User-Agent': UA,
'Referer': referer || host + '/',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
};
}
function getHeaderValue(headers, name) {
if (!headers) return '';
const lower = String(name || '').toLowerCase();
for (const k in headers) {
if (String(k).toLowerCase() === lower) {
const v = headers[k];
return Array.isArray(v) ? String(v[0] || '') : String(v || '');
}
}
return '';
}
function stripHtml(s) {
return String(s || '')
.replace(/<script[\s\S]*?<\/script>/gi, '')
.replace(/<style[\s\S]*?<\/style>/gi, '')
.replace(/<[^>]+>/g, '')
.replace(/&nbsp;/g, ' ')
.replace(/&amp;/g, '&')
.replace(/&quot;/g, '"')
.replace(/&#39;/g, "'")
.replace(/\s+/g, ' ')
.trim();
}
function cleanText(s) {
return stripHtml(s).replace(/\s+/g, ' ').trim();
}
function absUrl(url, base) {
url = String(url || '').trim();
base = base || host;
if (!url) return '';
if (/^https?:\/\//i.test(url)) return url;
if (url.indexOf('//') === 0) return 'https:' + url;
if (url.charAt(0) === '/') return base.replace(/\/$/, '') + url;
return base.replace(/\/$/, '') + '/' + url;
}
function safeJson(text, def) {
try { return JSON.parse(text || '{}'); } catch (e) { return def || {}; }
}
async function fetchText(url, referer) {
const hd = getHeaders(referer || host + '/');
if (typeof Java !== 'undefined' && Java && Java.req) {
const r = await Java.req(url, { headers: hd });
if (typeof r === 'string') return r;
const code = Number((r && (r.statusCode || r.status || r.code)) || 0);
const loc = getHeaderValue(r && r.headers, 'location');
if (loc && code >= 300 && code < 400) return await fetchText(absUrl(loc, url.indexOf(dbHost) === 0 ? dbHost : host), url);
return String((r && (r.body || r.content || r.data)) || '');
}
const r2 = await req(url, { headers: hd });
if (typeof r2 === 'string') return r2;
const code2 = Number((r2 && (r2.statusCode || r2.status || r2.code)) || 0);
const loc2 = getHeaderValue(r2 && r2.headers, 'location');
if (loc2 && code2 >= 300 && code2 < 400) return await fetchText(absUrl(loc2, url.indexOf(dbHost) === 0 ? dbHost : host), url);
return String((r2 && (r2.content || r2.body || r2.data)) || '');
}
function getClasses() {
return [
{ type_id: 'zuqiu', type_name: '足球直播' },
{ type_id: 'lanqiu', type_name: '篮球直播' },
{ type_id: 'sssc', type_name: '实时赛程' },
{ type_id: 'huifang', type_name: '赛事回放' },
{ type_id: 'fifa', type_name: '世界杯' },
{ type_id: 'zhongchao', type_name: '中超' },
{ type_id: 'yingchao', type_name: '英超' },
{ type_id: 'xijia', type_name: '西甲' },
{ type_id: 'dejia', type_name: '德甲' },
{ type_id: 'yijia', type_name: '意甲' },
{ type_id: 'fajia', type_name: '法甲' }
];
}
function parseIqList(html) {
html = String(html || '');
const list = [];
const reg = /<li>\s*<div class=["']liveinfo["'][\s\S]*?<\/li>/gi;
let m;
while ((m = reg.exec(html)) !== null) {
const item = m[0];
const title = cleanText((item.match(/class=["']title["'][^>]*>([\s\S]*?)<\/div>/i) || [])[1]);
const homeBlock = (item.match(/class=["']team-zhu["'][^>]*>([\s\S]*?)<\/div>/i) || [])[1] || '';
const awayBlock = (item.match(/class=["']team-ke["'][^>]*>([\s\S]*?)<\/div>/i) || [])[1] || '';
const home = cleanText(homeBlock.replace(/<img[\s\S]*$/i, ''));
const away = cleanText(awayBlock.replace(/^[\s\S]*?<img[^>]*>/i, ''));
const hrefMatch = item.match(/<div class=["']livesource["'][\s\S]*?<a[^>]+href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/i);
if (!hrefMatch) continue;
const imgMatch = item.match(/<img[^>]+src=["']([^"']+)["']/i);
const teams = [home, away].filter(Boolean).join(' vs ');
const name = [title, teams].filter(Boolean).join(' ');
list.push({
vod_id: absUrl(hrefMatch[1], host),
vod_name: name || teams || title || '赛事直播',
vod_pic: absUrl(imgMatch ? imgMatch[1] : '/logo.png', host),
vod_remarks: cleanText(hrefMatch[2]) || '高清'
});
}
return list;
}
function matchCategory(tid, league, name, dataType) {
tid = String(tid || '');
league = cleanText(league);
name = cleanText(name);
dataType = String(dataType || '');
const text = league + ' ' + name;
if (!tid || tid === 'sssc' || tid === 'huifang') return true;
if (tid === 'zuqiu') return dataType === 'football' || (/(足|超|甲|乙|冠|欧联|日职|韩K|世界杯|世俱|足球|杯)/i.test(text) && !/(篮|NBA|CBA|WNBA|NBL|篮球)/i.test(text));
if (tid === 'lanqiu') return dataType === 'basketball' || /(篮|NBA|CBA|WNBA|NBL|篮球)/i.test(text);
const rules = {
fifa: /(世界杯|世俱杯|世预赛|国际足联|FIFA)/i,
zhongchao: /(中超|足协杯|中国超级联赛)/i,
yingchao: /(英超|英格兰超级联赛)/i,
xijia: /(西甲|西班牙甲级联赛)/i,
dejia: /(德甲|德国甲级联赛)/i,
yijia: /(意甲|意大利甲级联赛)/i,
fajia: /(法甲|法国甲级联赛)/i
};
return rules[tid] ? rules[tid].test(text) : true;
}
function formatTimeText(matchTime) {
const d = new Date(matchTime);
if (!matchTime || isNaN(d.getTime())) return '';
const pad = function (n) { return String(n).padStart(2, '0'); };
return pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
}
async function fetchJson(url, referer) {
const text = await fetchText(url, referer || dbHost + '/');
try { return JSON.parse(text || '{}'); } catch (e) { return {}; }
}
function parseApiSchedule(json, tid) {
const days = json && json.data && Array.isArray(json.data.days) ? json.data.days : [];
const list = [];
for (let i = 0; i < days.length; i++) {
const rows = Array.isArray(days[i].live) ? days[i].live : [];
for (let j = 0; j < rows.length; j++) {
const item = rows[j];
const signals = Array.isArray(item.signals) ? item.signals : [];
if (!signals.length) continue;
const name = [formatTimeText(item.matchTime), cleanText(item.league), cleanText(item.teamA) + ' vs ' + cleanText(item.teamB)].filter(Boolean).join(' ');
if (!matchCategory(tid, item.league, name, item.dataType)) continue;
const links = signals.map(function (s, idx) {
return { name: cleanText(s.name || s.label) || ('信号' + (idx + 1)), url: dbHost + '/play/' + s.playId + '?device=pc_web' };
});
list.push({
vod_id: 'db$' + encodeURIComponent(JSON.stringify({ name: name, links: links })),
vod_name: name,
vod_pic: item.teamAImage || item.teamBImage || host + '/logo.png',
vod_remarks: links.map(function (x) { return x.name; }).join('/') || '直播'
});
}
}
return list;
}
function parsePlaybackList(json, tid) {
const rows = json && json.data && Array.isArray(json.data.list) ? json.data.list : [];
const list = [];
for (let i = 0; i < rows.length; i++) {
const s = rows[i].schedule || {};
const p = rows[i].playback || {};
const lines = Array.isArray(p.lines) ? p.lines : [];
if (!lines.length) continue;
const fullName = cleanText(p.title) || [formatTimeText(s.matchTime), cleanText(s.league), cleanText(s.teamA) + ' vs ' + cleanText(s.teamB), '回放'].filter(Boolean).join(' ');
if (!matchCategory(tid, s.league, fullName, s.dataType)) continue;
const shortName = (cleanText(s.teamA) + ' vs ' + cleanText(s.teamB)).replace(/^\s*vs\s*|\s*vs\s*$/g, '') || fullName.replace(/^\d{4}年\d{1,2}月\d{1,2}日\s*/, '').replace(/\s*赛事回放$/, '');
const remarkPrefix = [formatTimeText(s.matchTime), cleanText(s.league)].filter(Boolean).join(' ');
const links = lines.map(function (line, idx) {
return { name: cleanText(line.title) || ('回放' + (idx + 1)), url: absUrl(line.proxyUrl, dbHost) };
});
list.push({
vod_id: 'db$' + encodeURIComponent(JSON.stringify({ name: fullName, links: links })),
vod_name: shortName,
vod_pic: s.teamAImage || s.teamBImage || host + '/logo.png',
vod_remarks: [remarkPrefix, links.map(function (x) { return x.name; }).join('/')].filter(Boolean).join(' · ') || '回放'
});
}
return list;
}
function parseProxySchedule(html, tid) {
html = String(html || '');
const list = [];
const reg = /<article[^>]*class=["'][^"']*px-3 py-3 sm:px-4[^"']*["'][^>]*>[\s\S]*?<\/article>/gi;
let m;
while ((m = reg.exec(html)) !== null) {
const item = m[0];
const ps = [];
const pReg = /<p[^>]*>([\s\S]*?)<\/p>/gi;
let pm;
while ((pm = pReg.exec(item)) !== null) ps.push(cleanText(pm[1]));
const time = ps[0] || '';
const league = ps[1] || '';
const teams = [];
const spanReg = /<span[^>]*class=["'][^"']*truncate[^"']*["'][^>]*>([\s\S]*?)<\/span>/gi;
let sm;
while ((sm = spanReg.exec(item)) !== null) {
const t = cleanText(sm[1]);
if (t && !/^信号|高清|返回/.test(t) && teams.indexOf(t) < 0) teams.push(t);
}
if (teams.length < 2) continue;
const name = [time, league, teams[0] + ' vs ' + teams[1]].filter(Boolean).join(' ');
if (!matchCategory(tid, league, name)) continue;
const links = [];
const aReg = /<a[^>]+href=["']([^"']+)["'][^>]*class=["'][^"']*home-signal-link[^"']*["'][^>]*>([\s\S]*?)<\/a>/gi;
let am;
while ((am = aReg.exec(item)) !== null) {
const title = (am[0].match(/title=["']([^"']+)["']/i) || [])[1] || cleanText(am[2]) || ('信号' + (links.length + 1));
links.push({ name: title, url: absUrl(am[1], dbHost) });
}
if (!links.length) continue;
const img = (item.match(/<img[^>]+src=["']([^"']+)["']/i) || [])[1] || '/logo.png';
list.push({
vod_id: 'db$' + encodeURIComponent(JSON.stringify({ name: name, links: links })),
vod_name: name,
vod_pic: absUrl(img, dbHost),
vod_remarks: links.map(function (x) { return x.name; }).join('/') || '直播'
});
}
return list;
}
async function init(cfg) {
if (cfg && cfg.ext && String(cfg.ext).indexOf('http') === 0) host = String(cfg.ext).trim().replace(/\/$/, '');
}
async function home(filter) {
return JSON.stringify({ class: getClasses(), filters: {} });
}
async function homeVod() {
return await category('zuqiu', 1, false, {});
}
async function category(tid, pg, filter, extend) {
tid = String((extend && extend.cateId) || tid || 'zuqiu');
pg = parseInt(pg) || 1;
let list = [];
try {
if (tid === 'huifang') {
list = parsePlaybackList(await fetchJson(dbPlaybackApi + '?page=' + pg + '&pageSize=20&dataType=all', dbHost + '/'), tid);
} else {
list = parseApiSchedule(await fetchJson(dbScheduleApi, dbHost + '/'), tid);
if (!list.length && tid !== 'lanqiu') {
list = parseProxySchedule(await fetchText(host + '/proxy.php', host + '/sssc/'), tid);
}
}
} catch (e) {
list = [];
}
return JSON.stringify({ code: 1, msg: '数据列表', page: pg, pagecount: list.length >= 20 ? pg + 1 : 1, limit: 50, total: list.length, list: list });
}
function parseNuxtProxy(html) {
html = String(html || '');
const hls = html.match(/(?:\\u002F|\/)hls(?:\\u002F|\/)[A-Za-z0-9._-]+\.m3u8/i);
if (hls) return absUrl(hls[0].replace(/\\u002F/g, '/'), dbHost);
const m = html.match(/"proxyUrl"\s*:\s*"((?:\\.|[^"\\])*)"/);
if (m) {
try { return absUrl(JSON.parse('"' + m[1] + '"'), dbHost); } catch (e) { return absUrl(m[1].replace(/\\u002F/g, '/'), dbHost); }
}
const iframe = html.match(/https?:\/\/www\.kanqiuge\.com\/embed\/play\/[A-Za-z0-9._-]+/i);
if (iframe) return iframe[0];
return '';
}
async function resolvePlayUrl(playUrl) {
playUrl = String(playUrl || '');
if (/\.(m3u8|flv|mp4)(\?|$)/i.test(playUrl)) return playUrl;
try {
const html = await fetchText(playUrl, host + '/sssc/');
return parseNuxtProxy(html) || playUrl;
} catch (e) {
return playUrl;
}
}
async function detail(id) {
id = Array.isArray(id) ? id[0] : id;
id = String(id || '');
if (id.indexOf('db$') === 0) {
let data = { name: '实时赛程', links: [] };
try { data = JSON.parse(decodeURIComponent(id.slice(3))); } catch (e) {}
const playUrls = (data.links || []).map(function (x) { return (x.name || '线路') + '$' + x.url; }).join('#');
return JSON.stringify({
code: 1,
msg: '数据列表',
page: 1,
pagecount: 1,
limit: 1,
total: 1,
list: [{
vod_id: id,
vod_name: data.name || '实时赛程',
vod_pic: host + '/logo.png',
vod_remarks: '直播',
vod_play_from: '爱球直播',
vod_play_url: playUrls,
vod_content: '爱球直播实时赛程,播放时解析豆包直播信号。'
}]
});
}
let name = '赛事直播';
let time = '';
let playUrls = '';
try {
const html = await fetchText(id, host + '/');
name = cleanText((html.match(/<h1[^>]*>([\s\S]*?)<\/h1>/i) || [])[1]) || name;
time = cleanText((html.match(/<div class=["']match-header["'][\s\S]*?<p[^>]*>([\s\S]*?)<\/p>/i) || [])[1]);
const arr = [];
const aReg = /<div class=["']gohome["'][\s\S]*?<\/div>/i;
const block = (html.match(aReg) || [])[0] || '';
const linkReg = /<a[^>]+href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi;
let lm;
while ((lm = linkReg.exec(block)) !== null) {
const text = cleanText(lm[2]) || ('信号' + (arr.length + 1));
if (/赛程|返回|首页/.test(text)) continue;
const href = lm[1];
arr.push(text + '$' + (href === '/sssc/' || href.indexOf('/sssc/') >= 0 ? host + '/proxy.php' : absUrl(href, host)));
}
if (!arr.length) arr.push('赛程$' + host + '/proxy.php');
playUrls = arr.join('#');
} catch (e) {
playUrls = '赛程$' + host + '/proxy.php';
}
return JSON.stringify({
code: 1,
msg: '数据列表',
page: 1,
pagecount: 1,
limit: 1,
total: 1,
list: [{
vod_id: id,
vod_name: name,
vod_pic: host + '/logo.png',
vod_remarks: time,
vod_play_from: '爱球直播',
vod_play_url: playUrls,
vod_content: time || '爱球直播赛事导航'
}]
});
}
async function search(wd, quick, pg) {
pg = parseInt(pg) || 1;
let list = [];
try {
const html = await fetchText(host + '/search.html?keywords=' + encodeURIComponent(wd || '') + '&method=1', host + '/');
list = parseIqList(html);
} catch (e) {
list = [];
}
return JSON.stringify({ code: 1, msg: '数据列表', page: pg, pagecount: 1, limit: 20, total: list.length, list: list });
}
async function play(flag, id, flags) {
const url = await resolvePlayUrl(id);
const direct = /\.(m3u8|flv|mp4)(\?|$)/i.test(String(url || ''));
return JSON.stringify({
parse: direct ? 0 : 1,
url: url,
header: {
'User-Agent': UA,
'Referer': String(url || '').indexOf('doubaozhibo.com') >= 0 ? dbHost + '/' : host + '/'
}
});
}
async function homeContent(filter) { return safeJson(await home(filter), { class: [], filters: {} }); }
async function homeVideoContent() { return safeJson(await homeVod(), { list: [] }); }
async function categoryContent(tid, pg, filter, extend) { return safeJson(await category(tid, pg, filter, extend || {}), { list: [] }); }
async function detailContent(ids) { return safeJson(await detail(ids), { list: [] }); }
async function searchContent(wd, quick, pg) { return safeJson(await search(wd, quick, pg || 1), { list: [] }); }
async function playerContent(flag, id, flags) { return safeJson(await play(flag, id, flags), { parse: 1, url: id }); }
return { init, home, homeVod, category, search, detail, play, homeContent, homeVideoContent, categoryContent, detailContent, searchContent, playerContent };
})();
const __sports_src_5 = (function () {
const API_BASE = 'https://aapi2.xbncs.com/api';
const HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
'Accept': 'application/json, text/plain, */*',
'Referer': 'https://aapi2.xbncs.com/'
};
const PAGE_SIZE = 30;
function safeString(v) { if (v === null || v === undefined || v === 'null') return ''; return String(v); }
function safeJson(text, def) { if (text && typeof text === 'object') return text; try { return JSON.parse(text || '{}'); } catch (e) { return def || {}; } }
async function requestJson(url) {
if (typeof Java !== 'undefined' && Java && Java.req) {
const r = await Java.req(url, { headers: HEADERS });
if (typeof r === 'string') return safeJson(r, {});
return safeJson((r && (r.body || r.content || r.data)) || '{}', {});
}
const r2 = await req(url, { headers: HEADERS });
return safeJson((r2 && (r2.content || r2.body || r2.data)) || '{}', {});
}
function getClasses() { return [{ type_id: '-1', type_name: '全部' }, { type_id: '1', type_name: '足球' }, { type_id: '2', type_name: '篮球' }]; }
async function init(cfg) {}
async function home(filter) { return JSON.stringify({ class: getClasses(), filters: {} }); }
async function homeVod() { return await category('-1', 1, false, {}); }
async function category(tid, pg, filter, extend) {
const page = Math.max(parseInt(pg || '1', 10) || 1, 1);
const navId = tid === '-1' || tid === undefined || tid === null ? '' : String(tid);
const url = API_BASE + '/room/page?roomType=&navId=' + encodeURIComponent(navId) + '&roomId=&word=&page=' + page + '&pageSize=' + PAGE_SIZE + '&channelId=3&platform=1';
const list = [];
try {
const json = await requestJson(url);
const rows = json && json.data && Array.isArray(json.data.list) ? json.data.list : [];
for (let i = 0; i < rows.length; i++) {
const item = rows[i];
const roomId = safeString(item.roomId);
if (!roomId) continue;
list.push({
vod_id: roomId,
vod_name: safeString(item.title) || safeString(item.nickName) || ('房间 ' + roomId),
vod_pic: safeString(item.cover),
vod_remarks: safeString(item.navName) || safeString(item.statusName) || safeString(item.liveStatus) || '直播'
});
}
} catch (e) {}
return JSON.stringify({ code: 1, msg: '数据列表', page: page, pagecount: list.length >= PAGE_SIZE ? page + 1 : page, limit: PAGE_SIZE, total: list.length, list: list });
}
async function detail(id) {
id = Array.isArray(id) ? id[0] : id;
const roomId = safeString(id).trim();
if (!roomId) return JSON.stringify({ code: 1, list: [], page: 1, pagecount: 1, total: 0 });
const vod = { vod_id: roomId, vod_name: '房间 ' + roomId, vod_pic: '', vod_content: '体育直播', type_name: '', vod_play_from: '球通', vod_play_url: '' };
try {
const json = await requestJson(API_BASE + '/room/info?roomId=' + encodeURIComponent(roomId) + '&channelId=3&platform=1');
const data = json && json.data ? json.data : null;
if (data) {
vod.vod_name = safeString(data.title) || vod.vod_name;
vod.vod_pic = safeString(data.cover);
vod.vod_content = safeString(data.description) || safeString(data.notice) || '体育直播';
vod.type_name = safeString(data.nickName) || safeString(data.navName);
const playUrls = [];
const pushUrl = safeString(data.pushUrl);
const pullUrl = safeString(data.pullUrl);
if (pushUrl) playUrls.push('flv$' + pushUrl);
if (pullUrl) playUrls.push('m3u8$' + pullUrl);
vod.vod_play_url = playUrls.join('#');
}
} catch (e) {}
if (!vod.vod_play_url) vod.vod_play_url = '暂无播放$' + roomId;
return JSON.stringify({ code: 1, msg: '数据列表', page: 1, pagecount: 1, limit: 1, total: 1, list: [vod] });
}
async function search(wd, quick, pg) { return JSON.stringify({ code: 1, msg: '数据列表', page: parseInt(pg) || 1, pagecount: 1, limit: 0, total: 0, list: [] }); }
async function play(flag, id, flags) { id = safeString(id).replace(/\*\*\*/g, '#'); return JSON.stringify({ parse: /^https?:\/\//i.test(id) ? 0 : 1, jx: 0, url: /^https?:\/\//i.test(id) ? id : '', msg: /^https?:\/\//i.test(id) ? '' : '暂无播放地址', header: HEADERS }); }
async function homeContent(filter) { return safeJson(await home(filter), { class: [], filters: {} }); }
async function homeVideoContent() { return safeJson(await homeVod(), { list: [] }); }
async function categoryContent(tid, pg, filter, extend) { return safeJson(await category(tid, pg, filter, extend || {}), { list: [] }); }
async function detailContent(ids) { return safeJson(await detail(ids), { list: [] }); }
async function searchContent(wd, quick, pg) { return safeJson(await search(wd, quick, pg || 1), { list: [] }); }
async function playerContent(flag, id, flags) { return safeJson(await play(flag, id, flags), { parse: 1, url: id }); }
return { init, home, homeVod, category, search, detail, play, homeContent, homeVideoContent, categoryContent, detailContent, searchContent, playerContent };
})();
const SOURCES = [
{ id: 's0', name: '88看球', api: __sports_src_0 },
{ id: 's1', name: '咖啡直播', api: __sports_src_1 },
{ id: 's2', name: '919体育', api: __sports_src_2 },
{ id: 's3', name: 'JRS直播', api: __sports_src_3 },
{ id: 's4', name: '爱球直播', api: __sports_src_4 },
{ id: 's5', name: '球通体育', api: __sports_src_5 }
];
const SOURCE_CATS = {
s0: [
{ n: '正在直播', v: 'live' },
{ n: '全部直播', v: '0' },
{ n: '篮球直播', v: '1' },
{ n: '足球直播', v: '8' },
{ n: '其他直播', v: '21' }
],
s1: [
{ n: '全部直播', v: 'all' },
{ n: '热门直播', v: 'hot' },
{ n: 'NBA', v: 'nba' },
{ n: '足球直播', v: '1' },
{ n: '篮球直播', v: '2' },
{ n: '网球直播', v: '3' },
{ n: '台球直播', v: '19' },
{ n: '赛程列表', v: 'schedule' },
{ n: '录像', v: 'recordings' }
],
s2: [
{ n: '全部', v: '1' },
{ n: '足球', v: '2' },
{ n: '篮球', v: '3' }
],
s3: [
{ n: '正在直播', v: 'live' },
{ n: '全部赛程', v: 'all' },
{ n: '篮球直播', v: 'basketball' },
{ n: '足球直播', v: 'football' },
{ n: '热门赛事', v: 'hot' },
{ n: '其他赛事', v: 'other' }
],
s4: [
{ n: '足球直播', v: 'zuqiu' },
{ n: '篮球直播', v: 'lanqiu' },
{ n: '实时赛程', v: 'sssc' },
{ n: '赛事回放', v: 'huifang' },
{ n: '世界杯', v: 'fifa' },
{ n: '中超', v: 'zhongchao' },
{ n: '英超', v: 'yingchao' },
{ n: '西甲', v: 'xijia' },
{ n: '德甲', v: 'dejia' },
{ n: '意甲', v: 'yijia' },
{ n: '法甲', v: 'fajia' }
],
s5: [
{ n: '全部', v: '-1' },
{ n: '足球', v: '1' },
{ n: '篮球', v: '2' }
]
};
function __safeJson(text, def) {
if (text && typeof text === 'object') return text;
try { return JSON.parse(text || '{}'); } catch (e) { return def || {}; }
}
function __packId(srcId, id) {
return srcId + '@@@' + String(id || '');
}
function __splitId(id) {
const s = String(Array.isArray(id) ? id[0] : (id || ''));
const p = s.indexOf('@@@');
if (p < 0) return { srcId: '', raw: s };
return { srcId: s.slice(0, p), raw: s.slice(p + 3) };
}
function __srcById(srcId) {
for (let i = 0; i < SOURCES.length; i++) if (SOURCES[i].id === srcId) return SOURCES[i];
return null;
}
function __firstCat(srcId) {
const arr = SOURCE_CATS[srcId] || [];
return arr.length ? arr[0].v : 'home';
}
function __classes() {
const arr = [];
for (let i = 0; i < SOURCES.length; i++) {
arr.push({ type_id: SOURCES[i].id, type_name: SOURCES[i].name });
}
return arr;
}
function __filters() {
const filters = {};
for (let i = 0; i < SOURCES.length; i++) {
const src = SOURCES[i];
const values = SOURCE_CATS[src.id] || [];
filters[src.id] = [{ key: 'cat', name: '分类', value: values }];
}
return filters;
}
function __pickExtendCat(extend) {
extend = extend || {};
return String(extend.cat || extend.type || extend.class || extend.cate || '');
}
function __prefixList(list, src) {
list = Array.isArray(list) ? list : [];
const out = [];
for (let i = 0; i < list.length; i++) {
const it = list[i] || {};
const id = String(it.vod_id || '');
if (!id) continue;
out.push(Object.assign({}, it, {
vod_id: __packId(src.id, id),
vod_name: String(it.vod_name || ''),
vod_remarks: it.vod_remarks || src.name
}));
}
return out;
}
async function __callList(src, subTid, pg, filter, extend) {
try {
subTid = subTid || __firstCat(src.id);
const obj = __safeJson(await src.api.category(subTid, pg || 1, filter || false, extend || {}), {});
return __prefixList(obj.list || [], src);
} catch (e) {
return [];
}
}
async function init(cfg) {
for (let i = 0; i < SOURCES.length; i++) {
try { if (SOURCES[i].api.init) await SOURCES[i].api.init(cfg || {}); } catch (e) {}
}
}
async function home(filter) {
return JSON.stringify({ class: __classes(), filters: __filters() });
}
async function homeVod() {
// 首页只加载第一个源的默认二级分类,避免一进源就把所有体育站数据全量请求一遍。
const src = SOURCES[0];
const list = await __callList(src, __firstCat(src.id), 1, false, {});
return JSON.stringify({ code: 1, msg: '数据列表', page: 1, pagecount: 1, limit: list.length, total: list.length, list });
}
async function category(tid, pg, filter, extend) {
tid = String(tid || SOURCES[0].id);
extend = extend || {};
const src = __srcById(tid) || SOURCES[0];
const subTid = __pickExtendCat(extend) || __firstCat(src.id);
const list = await __callList(src, subTid, pg || 1, filter, extend);
return JSON.stringify({ code: 1, msg: '数据列表', page: parseInt(pg) || 1, pagecount: 1, limit: list.length, total: list.length, list });
}
async function detail(id) {
const sp = __splitId(id);
const src = __srcById(sp.srcId);
if (!src) return JSON.stringify({ code: 1, list: [], page: 1, pagecount: 1, total: 0 });
try {
const obj = __safeJson(await src.api.detail(sp.raw), {});
const list = Array.isArray(obj.list) ? obj.list : [];
for (let i = 0; i < list.length; i++) {
if (list[i]) list[i].vod_id = __packId(src.id, list[i].vod_id || sp.raw);
}
obj.list = list;
return JSON.stringify(obj);
} catch (e) {
return JSON.stringify({ code: 1, list: [], page: 1, pagecount: 1, total: 0, msg: String(e && e.message || e) });
}
}
async function search(wd, quick, pg) {
const list = [];
for (let i = 0; i < SOURCES.length; i++) {
try {
const obj = __safeJson(await SOURCES[i].api.search(wd, quick, pg || 1), {});
const part = __prefixList(obj.list || [], SOURCES[i]);
for (let j = 0; j < part.length; j++) list.push(part[j]);
} catch (e) {}
}
return JSON.stringify({ code: 1, msg: '数据列表', page: parseInt(pg) || 1, pagecount: 1, limit: list.length, total: list.length, list });
}
async function play(flag, id, flags) {
return JSON.stringify(await playerContent(flag, id, flags));
}
async function playerContent(flag, id, flags) {
const sp = __splitId(id);
const src = __srcById(sp.srcId);
if (!src) return { parse: 1, url: sp.raw || id };
try {
if (src.api.playerContent) return await src.api.playerContent(flag, sp.raw, flags);
return __safeJson(await src.api.play(flag, sp.raw, flags), { parse: 1, url: sp.raw });
} catch (e) {
return { parse: 1, url: sp.raw };
}
}
async function homeContent(filter) { return __safeJson(await home(filter), { class: [], filters: {} }); }
async function homeVideoContent() { return __safeJson(await homeVod(), { list: [] }); }
async function categoryContent(tid, pg, filter, extend) { return __safeJson(await category(tid, pg, filter, extend || {}), { list: [] }); }
async function detailContent(ids) { return __safeJson(await detail(ids), { list: [] }); }
async function searchContent(wd, quick, pg) { return __safeJson(await search(wd, quick, pg || 1), { list: [] }); }
export function __jsEvalReturn() {
return { init, home, homeVod, category, search, detail, play, homeContent, homeVideoContent, categoryContent, detailContent, searchContent, playerContent };
}
+1119
View File
@@ -0,0 +1,1119 @@
// @name 咖啡直播
// @author modified by ChatGPT
// @description 咖啡直播体育赛事直播 + 录像回放
// @version 1.3.0
//const host = 'https://kafeizhibo.com';
const host = 'https://kafeizhibo.cc';
const headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36',
'Accept': 'application/json, text/plain, */*',
'Referer': host + '/pc/live',
'Origin': host
};
// ========== 工具函数 ==========
function fixUrl(path) {
if (!path) return '';
const value = String(path).trim();
if (!value) return '';
if (value.startsWith('http')) return value;
if (value.startsWith('//')) return 'https:' + value;
return host + (value.startsWith('/') ? '' : '/') + value;
}
function safeText(value, fallback = '') {
if (value === undefined || value === null) return fallback;
return String(value).trim();
}
function safeNumber(value, fallback = '') {
if (value === undefined || value === null || value === '') return fallback;
return String(value);
}
function cleanName(name) {
return safeText(name, '播放').replace(/[$#]/g, ' ').trim() || '播放';
}
function cleanPlayUrl(url) {
return safeText(url).replace(/#/g, '%23');
}
function buildQuery(params = {}) {
const arr = [];
for (const [key, value] of Object.entries(params)) {
if (value === undefined || value === null || value === '') continue;
arr.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
}
return arr.join('&');
}
function getContent(res) {
if (!res) return '';
if (typeof res === 'string') return res;
if (typeof res.content === 'string') return res.content;
if (typeof res.body === 'string') return res.body;
if (typeof res.data === 'string') return res.data;
if (typeof res.content === 'object') return JSON.stringify(res.content);
if (typeof res.body === 'object') return JSON.stringify(res.body);
if (typeof res.data === 'object') return JSON.stringify(res.data);
return '';
}
async function requestText(url, params = {}, extraHeaders = {}) {
const query = buildQuery(params);
const finalUrl = query ? `${url}${url.includes('?') ? '&' : '?'}${query}` : url;
const r = await req(finalUrl, {
headers: Object.assign({}, headers, extraHeaders)
});
return getContent(r);
}
async function requestJson(url, params = {}, extraHeaders = {}) {
const text = await requestText(url, params, extraHeaders);
if (!text) return null;
return JSON.parse(text);
}
async function requestJsonSafe(url, params = {}, extraHeaders = {}) {
try {
return await requestJson(url, params, extraHeaders);
} catch (e) {
return null;
}
}
async function requestTextSafe(url, params = {}, extraHeaders = {}) {
try {
return await requestText(url, params, extraHeaders);
} catch (e) {
return '';
}
}
function isOk(data) {
return data && (
data.code === 200 ||
data.code === '200' ||
data.status === 200 ||
data.status === '200' ||
data.success === true ||
data.data !== undefined
);
}
function pick(obj, keys = [], fallback = '') {
if (!obj || typeof obj !== 'object') return fallback;
for (const key of keys) {
if (obj[key] !== undefined && obj[key] !== null && obj[key] !== '') {
return obj[key];
}
}
return fallback;
}
function todayString() {
const d = new Date();
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${y}-${m}-${day}`;
}
function uniqueByVodId(list = []) {
const seen = new Set();
const result = [];
list.forEach(item => {
if (!item || !item.vod_id) return;
const key = String(item.vod_id);
if (seen.has(key)) return;
seen.add(key);
result.push(item);
});
return result;
}
function encodeLiveId(item = {}) {
try {
return 'live|' + encodeURIComponent(JSON.stringify(item));
} catch (e) {
return 'live|' + encodeURIComponent(JSON.stringify({
id: pick(item, ['id', 'match_id', 'matchId', 'room_id', 'roomId'])
}));
}
}
function decodeLiveId(id) {
const raw = String(id || '');
if (!raw.startsWith('live|')) return null;
try {
return JSON.parse(decodeURIComponent(raw.slice(5)));
} catch (e) {
return null;
}
}
function isMediaUrl(url) {
const value = safeText(url).toLowerCase();
if (!value) return false;
return value.includes('.m3u8') ||
value.includes('m3u8?') ||
value.includes('.flv') ||
value.includes('flv?') ||
value.includes('.mp4') ||
value.includes('mp4?') ||
value.startsWith('rtmp') ||
value.startsWith('rtsp') ||
value.startsWith('p2p') ||
value.startsWith('mitv');
}
function isLivePageUrl(url) {
const value = safeText(url).toLowerCase();
return value.includes('/pc/room/') || value.includes('/room/');
}
function normalizeTypeValue(tid) {
const raw = String(tid || '');
if (raw === 'live') return '';
if (raw === 'live_hot') return '';
if (raw === 'live_football') return '1';
if (raw === 'live_basketball') return '2';
if (raw === 'live_tennis') return '3';
if (raw === 'live_billiards') return '4';
if (raw === 'live_nba') return '';
if (raw === 'all') return '';
if (raw === 'football') return '1';
if (raw === 'basketball') return '2';
if (raw === 'nba') return '';
return raw;
}
function joinTitle(home, away, league) {
const h = safeText(home, '');
const a = safeText(away, '');
const l = safeText(league, '赛事');
if (h && a) return `${l} ${h} vs ${a}`;
if (h) return `${l} ${h}`;
if (a) return `${l} ${a}`;
return l;
}
// ========== 分类配置 ==========
const classes = [
{ type_id: 'live', type_name: '全部直播' },
{ type_id: 'live_hot', type_name: '热门直播' },
{ type_id: 'live_football', type_name: '足球直播' },
{ type_id: 'live_basketball', type_name: '篮球直播' },
{ type_id: 'live_nba', type_name: 'NBA直播' },
{ type_id: 'live_tennis', type_name: '网球直播' },
{ type_id: 'live_billiards', type_name: '台球直播' },
{ type_id: 'all', type_name: '全部录像' },
{ type_id: 'football', type_name: '足球录像' },
{ type_id: 'basketball', type_name: '篮球录像' },
{ type_id: 'nba', type_name: 'NBA录像' }
];
const leagueAll = [
{ n: '全部', v: '' },
{ n: 'NBA', v: 'NBA' },
{ n: 'CBA', v: 'CBA' },
{ n: '英超', v: '英超' },
{ n: '西甲', v: '西甲' },
{ n: '意甲', v: '意甲' },
{ n: '德甲', v: '德甲' },
{ n: '法甲', v: '法甲' },
{ n: '欧冠', v: '欧冠' },
{ n: '中超', v: '中超' },
{ n: '中乙', v: '中乙' }
];
const filters = {
live: [{ key: 'league', name: '联赛', value: leagueAll }],
live_hot: [{ key: 'league', name: '联赛', value: leagueAll }],
live_football: [{ key: 'league', name: '联赛', value: leagueAll }],
live_basketball: [{ key: 'league', name: '联赛', value: leagueAll }],
live_nba: [{ key: 'league', name: '联赛', value: [{ n: 'NBA', v: 'NBA' }] }],
all: [{ key: 'league', name: '联赛', value: leagueAll }],
football: [{ key: 'league', name: '联赛', value: leagueAll }],
basketball: [{ key: 'league', name: '联赛', value: leagueAll }],
nba: [{ key: 'league', name: '联赛', value: [{ n: 'NBA', v: 'NBA' }] }]
};
// ========== 通用数据提取 ==========
function findBestArray(node, depth = 0) {
if (!node || depth > 6) return [];
if (Array.isArray(node)) return node;
if (typeof node !== 'object') return [];
const keys = [
'list', 'items', 'rows', 'data', 'records',
'matches', 'matchList', 'schedules', 'scheduleList',
'lives', 'liveList', 'rooms', 'roomList',
'events', 'result'
];
for (const key of keys) {
if (Array.isArray(node[key])) return node[key];
const arr = findBestArray(node[key], depth + 1);
if (arr.length) return arr;
}
for (const value of Object.values(node)) {
const arr = findBestArray(value, depth + 1);
if (arr.length) return arr;
}
return [];
}
function getDataArray(data) {
if (!data) return [];
if (Array.isArray(data)) return data;
if (isOk(data)) return findBestArray(data.data);
return findBestArray(data);
}
function getLeagueText(item) {
return safeText(pick(item, [
'league_name', 'leagueName', 'league',
'competition_name', 'competitionName',
'event_name', 'eventName',
'match_type', 'matchType'
]), '');
}
function getSportTypeText(item) {
return safeText(pick(item, [
'type', 'type_id', 'typeId',
'sport_type', 'sportType',
'category_id', 'categoryId',
'sport', 'category'
]), '');
}
function liveTitleText(item = {}) {
const title = safeText(pick(item, ['title', 'name', 'match_name', 'matchName'], ''));
const league = getLeagueText(item);
const home = safeText(pick(item, ['home_team', 'homeTeam', 'home_name', 'homeName', 'team1', 'home'], ''));
const away = safeText(pick(item, ['away_team', 'awayTeam', 'away_name', 'awayName', 'team2', 'away'], ''));
return [title, league, home, away].filter(Boolean).join(' ');
}
function isLiveItem(item) {
if (!item || typeof item !== 'object') return false;
const status = safeText(pick(item, [
'status', 'match_status', 'matchStatus',
'state', 'live_status', 'liveStatus',
'status_text', 'statusText'
])).toLowerCase();
const liveFlag = pick(item, ['is_live', 'isLive', 'live', 'living'], '');
const hasLiveFlag = liveFlag === true || String(liveFlag) === '1';
const hasRoom = !!pick(item, [
'room_id', 'roomId', 'roomid',
'live_room_id', 'liveRoomId',
'room_url', 'roomUrl'
], '');
const hasPlayUrl = !!firstPlayableUrl(item);
if (hasLiveFlag || hasPlayUrl || hasRoom) return true;
if (status.includes('live')) return true;
if (status.includes('正在')) return true;
if (status.includes('直播')) return true;
if (status === '1' || status === '2') return true;
return false;
}
function filterLiveItems(items = [], league = '', type = '', isHot = false) {
const leagueText = safeText(league).toLowerCase();
const typeText = safeText(type);
return items.filter(item => {
if (!item || typeof item !== 'object') return false;
if (!isLiveItem(item)) return false;
const title = liveTitleText(item);
const titleLower = title.toLowerCase();
const itemLeague = getLeagueText(item).toLowerCase();
const itemType = getSportTypeText(item);
if (leagueText) {
if (!itemLeague.includes(leagueText) && !titleLower.includes(leagueText)) {
return false;
}
}
if (isHot) {
const hotValue = pick(item, ['is_hot', 'isHot', 'hot', 'recommend', 'is_recommend'], '');
const hotOk = hotValue === true || String(hotValue) === '1' || title.includes('热门');
if (!hotOk) return false;
}
if (typeText === '1') {
const ok = itemType === '1' ||
itemType.includes('足球') ||
title.includes('足球') ||
title.includes('英超') ||
title.includes('西甲') ||
title.includes('意甲') ||
title.includes('德甲') ||
title.includes('法甲') ||
title.includes('欧冠') ||
title.includes('中超') ||
title.includes('中乙');
if (!ok) return false;
}
if (typeText === '2') {
const ok = itemType === '2' ||
itemType.includes('篮球') ||
title.includes('篮球') ||
title.includes('NBA') ||
title.includes('CBA') ||
title.includes('WNBA');
if (!ok) return false;
}
if (typeText === '3') {
const ok = itemType === '3' || itemType.includes('网球') || title.includes('网球');
if (!ok) return false;
}
if (typeText === '4') {
const ok = itemType === '4' || itemType.includes('台球') || title.includes('台球');
if (!ok) return false;
}
return true;
});
}
// ========== 直播接口 ==========
async function fetchLiveByApi(page = 1, size = 30, league = '', type = '', isHot = false) {
const date = todayString();
const urls = [
`${host}/api/v1/live`,
`${host}/api/v1/lives`,
`${host}/api/v1/live/list`,
`${host}/api/v1/lives/list`,
`${host}/api/v1/live/matches`,
`${host}/api/v1/matches/live`,
`${host}/api/v1/rooms`,
`${host}/api/v1/room/list`,
`${host}/api/v1/schedule`,
`${host}/api/v1/schedules`,
`${host}/api/v1/schedule/today`,
`${host}/api/v1/matches`
];
const paramList = [
{ page, size, limit: size, league, type, date },
{ page, pageSize: size, league, type, date },
{ page, per_page: size, league, type, date },
{ page, size, league, type, status: 'live' },
{ page, size, league, type, live: 1 },
{ page, size, league, type, is_live: 1 }
];
for (const url of urls) {
for (const params of paramList) {
const cleanParams = {};
Object.keys(params).forEach(key => {
if (params[key] !== undefined && params[key] !== null && params[key] !== '') {
cleanParams[key] = params[key];
}
});
const data = await requestJsonSafe(url, cleanParams, {
Referer: host + '/pc/live'
});
const arr = getDataArray(data);
if (!arr.length) continue;
const filtered = filterLiveItems(arr, league, type, isHot);
if (filtered.length) return filtered.slice(0, size);
}
}
return [];
}
function parseLiveCardsFromHtml(html = '') {
const text = safeText(html);
if (!text || text === '加载中...') return [];
const list = [];
const roomReg = /\/pc\/room\/(\d+)/g;
let m;
while ((m = roomReg.exec(text)) !== null) {
const roomId = m[1];
const start = Math.max(0, m.index - 800);
const end = Math.min(text.length, m.index + 800);
const block = text.slice(start, end);
const titleMatch = block.match(/([\u4e00-\u9fa5A-Za-z0-9\s]+?\s+vs\s+[\u4e00-\u9fa5A-Za-z0-9\s]+)/i);
const title = titleMatch ? titleMatch[1].replace(/\s+/g, ' ').trim() : `直播房间 ${roomId}`;
const imgMatch = block.match(/https?:\/\/[^"'<>]+?\.(?:jpg|jpeg|png|webp)/i);
const pic = imgMatch ? imgMatch[0] : '';
list.push({
id: roomId,
room_id: roomId,
room_url: `${host}/pc/room/${roomId}`,
title: title,
cover: pic,
status_text: 'LIVE',
is_live: 1
});
}
return list;
}
async function fetchLiveByPage(page = 1, size = 30, league = '', type = '', isHot = false) {
const html = await requestTextSafe(`${host}/pc/live`, {}, {
Referer: host + '/pc/live',
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
});
const arr = parseLiveCardsFromHtml(html);
return filterLiveItems(arr, league, type, isHot).slice(0, size);
}
async function fetchLiveMatches(page = 1, size = 30, league = '', type = '', isHot = false) {
let list = await fetchLiveByApi(page, size, league, type, isHot);
if (!list.length) {
list = await fetchLiveByPage(page, size, league, type, isHot);
}
return list;
}
async function fetchLiveDetail(roomOrMatchId) {
const id = safeText(roomOrMatchId);
if (!id) return null;
const urls = [
`${host}/api/v1/room/${encodeURIComponent(id)}`,
`${host}/api/v1/rooms/${encodeURIComponent(id)}`,
`${host}/api/v1/live/${encodeURIComponent(id)}`,
`${host}/api/v1/lives/${encodeURIComponent(id)}`,
`${host}/api/v1/match/${encodeURIComponent(id)}/live`,
`${host}/api/v1/match/${encodeURIComponent(id)}/streams`,
`${host}/api/v1/matches/${encodeURIComponent(id)}`,
`${host}/api/v1/match/${encodeURIComponent(id)}`
];
for (const url of urls) {
const data = await requestJsonSafe(url, {}, {
Referer: `${host}/pc/room/${encodeURIComponent(id)}`
});
if (!data) continue;
if (isOk(data)) return data.data;
if (typeof data === 'object') return data;
}
return null;
}
// ========== 录像接口 ==========
async function fetchRecordings(page = 1, size = 30, league = '', type = '') {
const params = { page, size };
if (league) {
params.league = league;
} else if (type && type !== 'all' && type !== 'nba') {
params.type = type;
}
return await requestJsonSafe(`${host}/api/v1/recordings`, params, {
Referer: host + '/pc/replay'
});
}
async function fetchMatchRecordings(matchId) {
return await requestJsonSafe(`${host}/api/v1/match/${encodeURIComponent(matchId)}/recordings`, {}, {
Referer: host + '/pc/replay'
});
}
// ========== 播放源提取 ==========
function addPlayable(arr, name, url) {
const value = cleanPlayUrl(url);
if (!value) return;
const line = `${cleanName(name)}$${value}`;
if (arr.indexOf(line) >= 0) return;
arr.push(line);
}
function collectPlayableLinks(node, prefix = '线路', arr = [], depth = 0) {
if (!node || depth > 7) return arr;
if (typeof node === 'string') {
if (isMediaUrl(node)) {
addPlayable(arr, prefix, node);
}
return arr;
}
if (Array.isArray(node)) {
node.forEach((item, idx) => {
collectPlayableLinks(item, `${prefix}${idx + 1}`, arr, depth + 1);
});
return arr;
}
if (typeof node !== 'object') return arr;
const name = cleanName(pick(node, [
'name', 'title', 'line', 'line_name', 'lineName',
'source_name', 'sourceName', 'quality', 'label'
], prefix));
const directKeys = [
'play_url', 'playUrl',
'video_url', 'videoUrl',
'stream_url', 'streamUrl',
'live_url', 'liveUrl',
'm3u8', 'flv', 'hls',
'url', 'src', 'link',
'hd', 'sd', 'uhd',
'source', 'stream'
];
directKeys.forEach(key => {
const value = node[key];
if (typeof value === 'string' && isMediaUrl(value)) {
addPlayable(arr, name, value);
}
});
Object.keys(node).forEach(key => {
if ([
'cover', 'cover_image', 'coverImage',
'logo', 'home_team_logo', 'away_team_logo',
'homeLogo', 'awayLogo', 'avatar'
].includes(key)) {
return;
}
collectPlayableLinks(node[key], name, arr, depth + 1);
});
return arr;
}
function firstPlayableUrl(item) {
const arr = collectPlayableLinks(item, '线路', [], 0);
if (!arr.length) return '';
const parts = arr[0].split('$');
return parts.length > 1 ? parts.slice(1).join('$') : '';
}
function buildLivePlayLine(liveItem = {}, detailData = null) {
const arr = [];
collectPlayableLinks(liveItem, '线路', arr);
collectPlayableLinks(detailData, '线路', arr);
if (!arr.length) {
const roomId = safeText(pick(liveItem, [
'_live_room_id',
'room_id', 'roomId', 'roomid',
'live_room_id', 'liveRoomId',
'id', 'match_id', 'matchId'
], ''));
const pageUrl = safeText(pick(liveItem, [
'_live_page_url',
'room_url', 'roomUrl',
'page_url', 'pageUrl',
'link'
], ''));
const finalPage = pageUrl || (roomId ? `${host}/pc/room/${encodeURIComponent(roomId)}` : `${host}/pc/live`);
addPlayable(arr, '打开直播间', fixUrl(finalPage));
}
return arr.join('#');
}
function buildEpisodeLine(items = [], prefix = '录像') {
const arr = [];
if (!Array.isArray(items)) return '';
items.forEach((rec, idx) => {
const url = cleanPlayUrl(pick(rec, [
'video_url', 'videoUrl',
'url',
'play_url', 'playUrl'
], ''));
if (!url) return;
const name = cleanName(pick(rec, ['title', 'name'], `${prefix}${idx + 1}`));
arr.push(`${name}$${url}`);
});
return arr.join('#');
}
// ========== 列表解析 ==========
function parseLiveList(items = []) {
if (!Array.isArray(items)) return [];
return items.map(item => {
const titleRaw = safeText(pick(item, ['title', 'name', 'match_name', 'matchName'], ''));
const league = safeText(getLeagueText(item), '直播');
const home = safeText(pick(item, [
'home_team', 'homeTeam',
'home_name', 'homeName',
'team1', 'home'
], ''));
const away = safeText(pick(item, [
'away_team', 'awayTeam',
'away_name', 'awayName',
'team2', 'away'
], ''));
const title = titleRaw || joinTitle(home, away, league);
const time = safeText(pick(item, [
'start_time', 'startTime',
'match_time', 'matchTime',
'time'
], '正在直播'));
const roomId = safeText(pick(item, [
'room_id', 'roomId', 'roomid',
'live_room_id', 'liveRoomId',
'id', 'match_id', 'matchId'
], ''));
const status = safeText(pick(item, [
'status_text', 'statusText',
'status', 'match_status', 'matchStatus',
'state'
], 'LIVE'));
let pic = pick(item, [
'cover_image', 'coverImage',
'cover', 'thumb', 'thumbnail',
'home_team_logo', 'homeLogo',
'away_team_logo', 'awayLogo',
'logo', 'pic'
], '');
pic = fixUrl(pic);
const liveItem = Object.assign({}, item, {
_live_title: title,
_live_league: league,
_live_time: time,
_live_room_id: roomId,
_live_page_url: roomId ? `${host}/pc/room/${encodeURIComponent(roomId)}` : fixUrl(pick(item, ['room_url', 'roomUrl', 'link'], ''))
});
return {
vod_id: encodeLiveId(liveItem),
vod_name: title,
vod_pic: pic,
vod_remarks: `🔴 ${status || 'LIVE'} | ${time}`
};
}).filter(v => v.vod_id && v.vod_name);
}
function parseVideoList(items = [], showScore = true) {
if (!Array.isArray(items)) return [];
return items.map(item => {
const home = safeText(pick(item, [
'home_team', 'homeTeam',
'home_name', 'homeName',
'team1', 'home'
], '主队'));
const away = safeText(pick(item, [
'away_team', 'awayTeam',
'away_name', 'awayName',
'team2', 'away'
], '客队'));
const league = safeText(pick(item, [
'league_name', 'leagueName',
'league',
'competition_name', 'competitionName'
], '赛事'));
const title = joinTitle(home, away, league);
const homeScore = safeNumber(pick(item, ['home_score', 'homeScore', 'score_home'], '-'));
const awayScore = safeNumber(pick(item, ['away_score', 'awayScore', 'score_away'], '-'));
const score = `${homeScore} - ${awayScore}`;
const time = safeText(pick(item, [
'start_time', 'startTime',
'match_time', 'matchTime',
'time'
], ''));
const count = safeNumber(pick(item, [
'recording_count', 'recordingCount',
'replay_count', 'video_count'
], '0'));
let pic = pick(item, [
'cover_image', 'coverImage',
'cover',
'home_team_logo', 'homeLogo',
'away_team_logo', 'awayLogo',
'logo', 'pic'
], '');
pic = fixUrl(pic);
if (pic.includes('default_cover')) {
pic = fixUrl(pick(item, [
'home_team_logo', 'homeLogo',
'away_team_logo', 'awayLogo',
'logo'
], ''));
}
return {
vod_id: String(pick(item, ['match_id', 'matchId', 'id'], '')),
vod_name: title,
vod_pic: pic,
vod_remarks: showScore ? `${score} | ${time} | ${count}个录像` : time
};
}).filter(v => v.vod_id && v.vod_name);
}
// ========== 壳子接口 ==========
async function init(cfg) {
return JSON.stringify({});
}
async function home(filter) {
try {
return JSON.stringify({
class: classes,
filters: filters
});
} catch (e) {
return JSON.stringify({ class: [] });
}
}
async function homeVod() {
try {
const liveItems = await fetchLiveMatches(1, 30, '', '', false);
const liveList = parseLiveList(liveItems);
const data = await fetchRecordings(1, 20);
const replayList = isOk(data) ? parseVideoList(getDataArray(data)) : [];
return JSON.stringify({
list: uniqueByVodId([].concat(liveList, replayList))
});
} catch (e) {
return JSON.stringify({ list: [] });
}
}
async function category(tid, pg, filter, extend = {}) {
try {
const page = parseInt(pg) || 1;
const size = 30;
let league = '';
let type = normalizeTypeValue(tid);
const isHot = String(tid || '') === 'live_hot';
if (extend && extend.league) {
league = extend.league;
} else if (String(tid || '') === 'live_nba' || String(tid || '') === 'nba') {
league = 'NBA';
}
if (String(tid || '').startsWith('live')) {
const liveItems = await fetchLiveMatches(page, size, league, type, isHot);
const list = parseLiveList(liveItems);
const pagecount = list.length >= size ? page + 1 : page;
return JSON.stringify({
page: page,
pagecount: pagecount,
limit: size,
total: list.length,
list: list
});
}
const data = await fetchRecordings(page, size, league, type);
const list = isOk(data) ? parseVideoList(getDataArray(data)) : [];
const pagecount = list.length >= size ? page + 1 : page;
return JSON.stringify({
page: page,
pagecount: pagecount,
limit: size,
total: list.length,
list: list
});
} catch (e) {
return JSON.stringify({
page: parseInt(pg) || 1,
pagecount: 0,
limit: 0,
total: 0,
list: []
});
}
}
async function detail(id) {
try {
const rawId = String(id || '').trim();
if (!rawId) return JSON.stringify({ list: [] });
const liveItem = decodeLiveId(rawId);
if (liveItem) {
const roomId = safeText(pick(liveItem, [
'_live_room_id',
'room_id', 'roomId', 'roomid',
'live_room_id', 'liveRoomId',
'id', 'match_id', 'matchId'
], ''));
const detailData = roomId ? await fetchLiveDetail(roomId) : null;
const title = safeText(pick(liveItem, [
'_live_title',
'title', 'name', 'match_name', 'matchName'
], '正在直播'));
const league = safeText(pick(liveItem, [
'_live_league',
'league_name', 'leagueName',
'league',
'competition_name', 'competitionName'
], '直播'));
const time = safeText(pick(liveItem, [
'_live_time',
'start_time', 'startTime',
'match_time', 'matchTime',
'time'
], '正在直播'));
const pic = fixUrl(pick(liveItem, [
'cover_image', 'coverImage',
'cover', 'thumb', 'thumbnail',
'home_team_logo', 'homeLogo',
'away_team_logo', 'awayLogo',
'logo', 'pic'
], ''));
const playLine = buildLivePlayLine(liveItem, detailData);
const vodInfo = {
vod_id: rawId,
vod_name: title,
vod_pic: pic,
vod_remarks: '正在直播',
vod_content: `${league} ${title},比赛时间:${time}`,
vod_play_from: playLine ? '正在直播' : '',
vod_play_url: playLine,
type_name: league
};
return JSON.stringify({ list: [vodInfo] });
}
const matchId = rawId;
const data = await fetchMatchRecordings(matchId);
if (!isOk(data)) return JSON.stringify({ list: [] });
const root = data.data || {};
const match = root.match || {};
const replays = root.replays || [];
const highlights = root.highlights || [];
const home = safeText(pick(match, [
'home_team', 'homeTeam',
'home_name', 'homeName',
'team1', 'home'
], '主队'));
const away = safeText(pick(match, [
'away_team', 'awayTeam',
'away_name', 'awayName',
'team2', 'away'
], '客队'));
const league = safeText(pick(match, [
'league_name', 'leagueName',
'league',
'competition_name', 'competitionName'
], '赛事'));
const title = joinTitle(home, away, league);
const score = `${safeNumber(pick(match, ['home_score', 'homeScore', 'score_home'], '-'))} - ${safeNumber(pick(match, ['away_score', 'awayScore', 'score_away'], '-'))}`;
const time = safeText(pick(match, [
'start_time', 'startTime',
'match_time', 'matchTime',
'time'
], ''));
const round = safeText(pick(match, ['match_round', 'matchRound', 'round'], ''));
const playFrom = [];
const playUrls = [];
const replayLine = buildEpisodeLine(replays, '录像');
if (replayLine) {
playFrom.push('全场录像');
playUrls.push(replayLine);
}
const highlightLine = buildEpisodeLine(highlights, '集锦');
if (highlightLine) {
playFrom.push('比赛集锦');
playUrls.push(highlightLine);
}
const pic = fixUrl(pick(match, [
'cover_image', 'coverImage',
'cover',
'home_team_logo', 'homeLogo',
'away_team_logo', 'awayLogo',
'logo', 'pic'
], ''));
const vodInfo = {
vod_id: matchId,
vod_name: title,
vod_pic: pic,
vod_remarks: score,
vod_content: `${league} ${round} ${home} vs ${away},比分 ${score},比赛时间:${time}`,
vod_play_from: playFrom.join('$$$'),
vod_play_url: playUrls.join('$$$'),
type_name: league
};
return JSON.stringify({ list: [vodInfo] });
} catch (e) {
return JSON.stringify({ list: [] });
}
}
async function search(wd, quick, pg = 1) {
try {
const keyword = safeText(wd).toLowerCase();
if (!keyword) {
return JSON.stringify({
page: 1,
pagecount: 0,
list: []
});
}
const liveItems = await fetchLiveMatches(1, 100);
const filteredLive = liveItems.filter(item => {
return liveTitleText(item).toLowerCase().includes(keyword);
});
const liveList = parseLiveList(filteredLive);
const data = await fetchRecordings(1, 100);
let replayList = [];
if (isOk(data)) {
const arr = getDataArray(data);
const filteredReplay = arr.filter(item => {
const title = [
pick(item, ['title', 'name', 'match_name', 'matchName'], ''),
pick(item, ['home_team', 'homeTeam', 'home_name', 'homeName'], ''),
pick(item, ['away_team', 'awayTeam', 'away_name', 'awayName'], ''),
pick(item, ['league_name', 'leagueName', 'league'], '')
].join(' ').toLowerCase();
return title.includes(keyword);
});
replayList = parseVideoList(filteredReplay);
}
const list = uniqueByVodId([].concat(liveList, replayList));
return JSON.stringify({
page: parseInt(pg) || 1,
pagecount: 1,
limit: list.length,
total: list.length,
list: list
});
} catch (e) {
return JSON.stringify({
page: parseInt(pg) || 1,
pagecount: 0,
list: []
});
}
}
async function play(flag, id, flags) {
try {
const url = cleanPlayUrl(id);
const needParse = isLivePageUrl(url) && !isMediaUrl(url);
return JSON.stringify({
parse: needParse ? 1 : 0,
url: url,
header: {
'User-Agent': headers['User-Agent'],
'Referer': isLivePageUrl(url) ? host + '/pc/live' : host,
'Origin': host
}
});
} catch (e) {
return JSON.stringify({
parse: 0,
url: id || ''
});
}
}
export default {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
search: search,
play: play
};
+141
View File
@@ -0,0 +1,141 @@
import { Crypto, load, _, jinja2 } from 'assets://js/lib/cat.js';
let key = 'ff';
let HOST = 'https://ffzy5.tv';
let siteKey = '';
let siteType = 0;
const UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1';
async function request(reqUrl, agentSp) {
let res = await req(reqUrl, {
method: 'get',
headers: {
'User-Agent': agentSp || UA,
'Referer': HOST
},
});
return res.content;
}
async function init(cfg) {
siteKey = cfg.skey;
siteType = cfg.stype;
}
async function home(filter) {
let classes = [{"type_id":1,"type_name":"电影"},{"type_id":2,"type_name":"连续剧"},{"type_id":3,"type_name":"综艺"},{"type_id":4,"type_name":"动漫"}];
let filterObj = {
"2":[{"key":"cateId","name":"类型","value":[{"n":"全部","v":"2"},{"n":"短剧","v":"36"},{"n":"陆剧","v":"13"},{"n":"韩剧","v":"15"},{"n":"欧美剧","v":"16"},{"n":"港剧","v":"14"},{"n":"台剧","v":"21"},{"n":"日剧","v":"22"},{"n":"海外剧","v":"23"},{"n":"泰剧","v":"24"},{"n":"纪录片","v":"20"}]}],
"1":[{"key":"cateId","name":"类型","value":[{"n":"全部","v":"1"},{"n":"动作片","v":"6"},{"n":"喜剧片","v":"7"},{"n":"爱情片","v":"8"},{"n":"科幻片","v":"9"},{"n":"恐怖片","v":"10"},{"n":"剧情片","v":"11"},{"n":"战争片","v":"12"}]}],
"3":[{"key":"cateId","name":"类型","value":[{"n":"全部","v":"3"},{"n":"国综","v":"25"},{"n":"港综","v":"26"},{"n":"韩日综","v":"27"},{"n":"欧美综","v":"28"}]}],
"4":[{"key":"cateId","name":"类型","value":[{"n":"全部","v":"4"},{"n":"国漫","v":"29"},{"n":"日韩动漫","v":"30"},{"n":"欧美动漫","v":"31"},{"n":"港漫","v":"32"},{"n":"海外动漫","v":"33"}]}]
};
return JSON.stringify({
class: classes,
filters: filterObj,
});
}
async function homeVod() {}
async function category(tid, pg, filter, extend) {
if (pg <= 0) pg = 1;
let data = JSON.parse(await request(HOST + '/index.php/ajax/data?mid=1&tid=' + (extend.cateId || tid) + '&page=' + pg + '&limit=20'));
let videos = [];
for (const vod of data.list) {
videos.push({
vod_id: vod.vod_id,
vod_name: vod.vod_name,
vod_pic: vod.vod_pic,
vod_remarks: '',
});
}
return JSON.stringify({
page: parseInt(data.page),
pagecount: data.pagecount,
limit: 20,
total: data.total,
list: videos,
});
}
async function detail(id) {
var html = await request(HOST + '/index.php/vod/detail/id/' + id + '.html');
var $ = load(html);
let pList = $('.people .right p');
let getTxt = (label) => {
let text = '';
pList.each((idx, el) => {
let t = $(el).text().trim();
if (t.startsWith(label)) {
text = t.replace(label, '').trim();
}
});
return text;
};
var vod = {
vod_id: id,
vod_name: getTxt('片名:'),
vod_type: getTxt('类型:').replace(/&nbsp;/g, ''),
vod_actor: getTxt('演员:'),
vod_director: getTxt('导演:'),
vod_pic: $('.people .left img').attr('src'),
vod_remarks: getTxt('状态:') || '',
vod_content: $('.vod_content').text().replace(/&nbsp;/g, '').trim(),
};
const playlist = _.map($('div.ffm3u8 > li > a[target*=_blank]'), (it) => {
return it.attribs.title + '$' + it.attribs.href;
});
vod.vod_play_from = "非凡直达";
vod.vod_play_url = playlist.join('#');
return JSON.stringify({
list: [vod],
});
}
async function play(flag, id, flags) {
return JSON.stringify({
parse: 0,
url: id,
});
}
async function search(wd, quick, pg) {
if (pg <= 0) pg = 1;
let data = JSON.parse(await request(HOST + '/api.php/provide/vod/?wd=' + wd + '&pg=' + pg + '&ac=detail'));
let videos = [];
for (const vod of data.list) {
videos.push({
vod_id: vod.vod_id,
vod_name: vod.vod_name,
vod_pic: vod.vod_pic,
vod_remarks: '',
});
}
return JSON.stringify({
page: parseInt(data.page),
pagecount: data.pagecount,
limit: 20,
total: data.total,
list: videos,
});
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
+620
View File
@@ -0,0 +1,620 @@
// 本资源来源于互联网公开渠道,仅可用于个人学习爬虫技术。
// 严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
import {
Crypto as e
} from "assets://js/lib/cat.js";
let t, n = "https://web.88spa-03.com:8443",
r = "https://88api.omwjhz.com:18888";
const o = {
"User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
Accept: "application/json, text/plain, */*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cache-Control": "no-cache",
Origin: n,
Pragma: "no-cache",
Referer: `${n}`,
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "cross-site",
"sec-ch-ua": '"Not/A)Brand";v="8", "Chromium";v="143", "Google Chrome";v="143"',
"sec-ch-ua-mobile": "?1",
"sec-ch-ua-platform": '"Android"'
},
a = "function" == typeof js2Proxy && "function" == typeof desX && "function" != typeof getProxy;
async function s(e) {}
async function i(e) {
let n = [{
type_id: "1",
type_name: "电影"
}, {
type_id: "2",
type_name: "连续剧"
}, {
type_id: "3",
type_name: "综艺"
}, {
type_id: "4",
type_name: "动漫"
}];
a && n.unshift({
type_id: "home",
type_name: "首页"
});
try {
if (!e) return JSON.stringify({
class: n,
filters: {}
});
if (t) return JSON.stringify({
class: n,
filters: t
});
const a = `${r}/v1/vod-list-options`,
s = await req(a, {
headers: o,
timeout: 8e3
});
let i = {};
if (s && s.content) {
let e = "string" == typeof s.content ? JSON.parse(s.content) : s.content;
const n = e.areas || {},
r = e.types || {},
o = e.languages || [];
let a = [{
n: "全部",
v: "全部"
}];
Array.isArray(o) && o.forEach(e => {
"全部" !== e.name && a.push({
n: e.name,
v: e.name
})
});
let c = [{
n: "全部",
v: ""
}];
["2026", "2025", "2024", "2023", "2022", "2021", "2020", "2019", "2018", "2017", "2016", "2015", "2014", "2013", "2012", "2011", "2010"].forEach(e => {
c.push({
n: e,
v: e
})
});
let p = [{
n: "全部",
v: "全部"
}];
for (let e = 65; e <= 90; e++) p.push({
n: String.fromCharCode(e),
v: String.fromCharCode(e)
});
for (let e = 0; e <= 9; e++) p.push({
n: e.toString(),
v: e.toString()
});
let l = [{
n: "最新",
v: "time"
}, {
n: "最热",
v: "hot"
}, {
n: "评分",
v: "score"
}];
const d = {
1: "电影",
2: "连续剧",
3: "综艺",
4: "动漫"
};
for (const e in d) {
const t = d[e];
let o = [],
s = [{
n: "全部",
v: e
}];
Array.isArray(r[t]) && r[t].forEach(e => {
"全部" !== e.name && s.push({
n: e.name,
v: e.id.toString()
})
}), o.push({
key: "cateId",
name: "类型",
init: e,
value: s
});
let u = [{
n: "全部",
v: "全部"
}];
Array.isArray(n[t]) && n[t].forEach(e => {
"全部" !== e.name && u.push({
n: e.name,
v: e.name
})
}), o.push({
key: "area",
name: "地区",
init: "全部",
value: u
}), o.push({
key: "lang",
name: "语言",
init: "全部",
value: a
}), o.push({
key: "year",
name: "年份",
init: "",
value: c
}), o.push({
key: "letter",
name: "字母",
init: "全部",
value: p
}), o.push({
key: "orderBy",
name: "排序",
init: "time",
value: l
}), i[e] = o
}
t = i
}
return JSON.stringify({
class: n,
filters: t || {}
})
} catch (e) {
return JSON.stringify({
class: n,
filters: {}
})
}
}
async function c() {
try {
const e = `${r}/v1/home-list`,
t = await req(e, {
headers: o,
timeout: 8e3
});
if (!t || !t.content) return JSON.stringify({
list: []
});
let n = "string" == typeof t.content ? JSON.parse(t.content) : t.content,
a = new Map;
for (const e in n) Array.isArray(n[e]) && n[e].forEach(e => {
if (e && e.VodID) {
const t = e.VodID.toString();
a.has(t) || a.set(t, {
vod_id: t,
vod_name: e.VodName,
vod_pic: e.VodPic,
vod_remarks: e.VodRemarks
})
}
});
const s = Array.from(a.values());
return JSON.stringify({
list: s
})
} catch (e) {
return JSON.stringify({
list: []
})
}
}
async function p(e, t, n, a) {
try {
if ("home" === e) {
let e = JSON.parse(await c());
return JSON.stringify({
list: e.list || [],
page: 1,
pagecount: 1
})
}
const n = a.cateId ? encodeURIComponent(a.cateId) : e,
s = "全部",
i = a.area ? encodeURIComponent(a.area) : "全部",
p = a.lang ? encodeURIComponent(a.lang) : "全部",
l = a.year ? encodeURIComponent(a.year) : "",
d = a.letter ? encodeURIComponent(a.letter) : "全部",
u = a.orderBy ? encodeURIComponent(a.orderBy) : "time",
g = `${r}/v1/vod-list?orderBy=${u}&type=${n}&class=${s}&area=${i}&year=${l}&lang=${p}&letter=${d}&page=${t}`,
f = await req(g, {
headers: o,
timeout: 8e3
});
if (!f || !f.content) return JSON.stringify({
list: [],
page: parseInt(t),
pagecount: parseInt(t)
});
let y = "string" == typeof f.content ? JSON.parse(f.content) : f.content;
if (0 !== y.status || !y.data) return JSON.stringify({
list: [],
page: parseInt(t),
pagecount: parseInt(t)
});
const m = y.data.map(e => ({
vod_id: e.VodID.toString(),
vod_name: e.VodName,
vod_pic: e.VodPic,
vod_remarks: e.VodRemarks
})),
h = y.qty || 0,
v = h > 0 ? Math.ceil(h / 60) : parseInt(t);
return JSON.stringify({
list: m,
page: parseInt(t),
pagecount: v
})
} catch (e) {
return JSON.stringify({
list: [],
page: parseInt(t),
pagecount: parseInt(t)
})
}
}
async function l(e, t, n = 1) {
try {
const t = encodeURIComponent(e),
a = `${r}/v1/search?keyword=${t}&cate=undefined&page=${n}`,
s = await req(a, {
headers: o,
timeout: 8e3
});
if (!s || !s.content) return JSON.stringify({
list: [],
page: parseInt(n),
pagecount: parseInt(n)
});
let i = "string" == typeof s.content ? JSON.parse(s.content) : s.content;
if (0 !== i.status || !i.data) return JSON.stringify({
list: [],
page: parseInt(n),
pagecount: parseInt(n)
});
const c = i.data.map(e => ({
vod_id: e.VodID.toString(),
vod_name: e.VodName,
vod_pic: e.VodPic,
vod_remarks: e.VodRemarks
})),
p = i.qty || 0,
l = p > 0 ? Math.ceil(p / 60) : parseInt(n);
return JSON.stringify({
list: c,
page: parseInt(n),
pagecount: l
})
} catch (e) {
return JSON.stringify({
list: [],
page: parseInt(n),
pagecount: parseInt(n)
})
}
}
async function d(e) {
try {
const t = `${r}/v1/vod-details?id=${e}`,
n = await req(t, {
headers: o,
timeout: 8e3
});
if (!n || !n.content) return JSON.stringify({
list: []
});
let a = "string" == typeof n.content ? JSON.parse(n.content) : n.content;
if (0 !== a.status || !a.vod) return JSON.stringify({
list: []
});
const s = a.vod,
i = s.VodPlayServer || [],
c = s.VodPlayUrls || {};
let p = [],
l = [];
i.forEach(e => {
if (1 === e.Status) {
const t = e.From,
n = e.Show,
r = c[t] || [];
if (r.length > 0) {
const e = r.map(e => `${e[0]}$${e[1]}`).join("#");
p.push(n), l.push(e)
}
}
});
const d = p.join("$$$"),
u = l.join("$$$"),
g = {
vod_id: s.VodID.toString(),
vod_name: s.VodName,
vod_pic: s.VodPic,
type_name: a.VodClass ? a.VodClass.TypeName : "",
vod_year: s.VodYear || "",
vod_area: s.VodArea || "",
vod_remarks: s.VodRemarks || "",
vod_actor: s.VodActor || "",
vod_director: s.VodDirector || "",
vod_content: s.VodContent ? s.VodContent.replace(/<\/?[^>]+(>|$)/g, "") : "",
vod_play_from: d,
vod_play_url: u
};
return JSON.stringify({
list: [g]
})
} catch (e) {
return JSON.stringify({
list: []
})
}
}
async function u(t, r, a) {
try {
const t = /^(https?:)?\/\//i.test(r) ? r : `https://vip.jsjinfu.com:8443/?url=${r}`;
let a = await async function(t, n) {
let r = {
"User-Agent": o["User-Agent"],
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "zh-CN,zh;q=0.9",
"cache-control": "no-cache",
pragma: "no-cache",
referer: n,
"upgrade-insecure-requests": "1"
};
try {
const n = (await req(t, {
headers: r
})).content,
a = h(n, "video_url");
if (a) return a;
const s = h(n, "Domain"),
i = h(n, "Time"),
c = h(n, "Version"),
p = h(n, "Vurl"),
l = h(n, "Vkey"),
d = h(n, "Key"),
u = h(n, "Ref"),
S = s || "vip.jsjinfu.com";
if (!(i && p && l && d)) return null;
const $ = md5X(l);
let _ = y(d, $),
N = g.encryptToBase64(d, _);
const k = s + S + i + p + d + _;
let O = m(md5X(k)),
C = f.encode(O, "971a0e7224fecb61b1868f1211a6360d"),
A = y(C, $),
I = g.encryptToBase64(C, A),
V = m(md5X(k + C + A)),
b = f.encode(V, i + "52bc46dec47a199abc82793bfabe56f6"),
J = y(b, $),
w = g.encryptToBase64(b, J),
U = `${l}-${d}-${C}-${b}`,
E = `${_}-${A}-${J}`;
const D = U + E;
let R = g.encryptToBase64(D + N + I + w, S + s + i),
B = {
url: p,
wap: "0",
ios: "0",
host: S,
referer: u,
time: i,
key: d,
key1: _,
sign: C,
sign1: A,
token: b,
token1: J
},
X = function(t, n) {
let r = e.enc.Latin1.parse(n.substring(0, 16)),
o = e.enc.Latin1.parse(n.substring(16, 32));
return e.AES.encrypt(e.enc.Base64.stringify(e.enc.Utf8.parse(t)), r, {
iv: o,
mode: e.mode.CBC,
padding: e.pad.Pkcs7
}).toString()
}(JSON.stringify(B), md5X(R));
B.ckey = "110#" + e.enc.Base64.stringify(e.enc.Latin1.parse(X));
let q = function(e) {
let t = String(e.time),
n = e.key,
r = e.key1,
o = e.sign1,
a = e.token1,
s = ["2", "6", "2", "4"],
i = t.split("")[s[0]] || "e",
c = n.split("")[s[1]] || "t",
p = r.split("")[s[2]] || "c",
l = o.split("")[o.split("").length - s[3]] || "n",
d = a.split(""),
u = [];
for (let e = 0; 2 * e < d.length; e++) switch (u.push(d[d.length - e - 1]), e < d.length - e - 1 && u.push(a[e]), e) {
case 1:
u.push(i);
break;
case 2:
u.push(c);
break;
case 3:
u.push(p);
break;
case 4:
u.push(l)
}
return u.join("")
}(B),
T = 1024 * i,
j = `https://${s}:8443/Api.php?ver=${c}&timestamp=${T}&appkey=${md5X(S+T+c)}`,
x = {
"User-Agent": o["User-Agent"],
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
Vkey: l,
Md5: md5X(D + R + q),
Version: c,
"Access-Token0": U,
"Access-Token1": E,
"Access-Token2": R,
"Access-Token3": q,
Origin: `https://${S}:8443`,
Referer: t
};
const M = await req(j, {
method: "post",
headers: x,
data: v(B),
postType: "form"
});
let P = "string" == typeof M.content ? JSON.parse(M.content) : M.content;
if (P && 1 === P.Status) {
let t = P.Appkey + P.Md5 + P.Version,
n = md5X(t),
r = e.enc.Latin1.parse(n.substring(0, 16)),
o = e.enc.Latin1.parse(n.substring(16, 32)),
a = e.AES.decrypt(P.Data, r, {
iv: o,
mode: e.mode.CBC,
padding: e.pad.Pkcs7
}),
s = JSON.parse(e.enc.Utf8.stringify(a)),
i = f.decode(s.url, md5X(S + b));
return decodeURIComponent(i)
}
} catch (e) {}
return null
}(t, `${n}/`);
if (a) return JSON.stringify({
parse: 0,
url: a,
header: {
"User-Agent": o["User-Agent"]
}
})
} catch (e) {}
return JSON.stringify({
parse: 1,
url: r,
header: {}
})
}
const g = (e => {
if (!e) throw new Error("");
const t = (e, t) => {
const n = e.words,
r = e.sigBytes,
o = r + 3 >> 2,
a = new Array(t ? o + 1 : o);
for (let e = 0; e < r; e++) a[e >> 2] |= (n[e >> 2] >>> 24 - e % 4 * 8 & 255) << ((3 & e) << 3);
return t && (a[o] = r), a
},
n = (e, t, n, r, o, a) => (n >>> 5 ^ t << 2) + (t >>> 3 ^ n << 4) ^ (e ^ t) + (a[3 & r ^ o] ^ n);
return {
encryptToBase64(r, o) {
if (!r || 0 === r.length) return r;
const a = t(e.enc.Utf8.parse(r), !0),
s = t(e.enc.Utf8.parse(o), !1);
return e.enc.Base64.stringify((t => {
const n = t.length,
r = [];
for (let e = 0; e < n; e++) {
const n = t[e];
r[e] = (255 & n) << 24 | (n >>> 8 & 255) << 16 | (n >>> 16 & 255) << 8 | n >>> 24
}
return e.lib.WordArray.create(r, 4 * n)
})(((e, t) => {
t.length < 4 && (t.length = 4);
const r = e.length,
o = r - 1;
let a, s = e[o],
i = 0;
for (let c = 0 | Math.floor(6 + 52 / r); c > 0; --c) {
i = i + 2654435769 & 4294967295;
const r = i >>> 2 & 3;
for (let c = 0; c < o; ++c) a = e[c + 1], s = e[c] = e[c] + n(i, a, s, c, r, t) & 4294967295;
a = e[0], s = e[o] = e[o] + n(i, a, s, o, r, t) & 4294967295
}
return e
})(a, s)))
}
}
})(void 0 !== e ? e : null),
f = function() {
const t = () => Math.floor(Date.now() / 1e3),
n = function(n, r = "DECODE", o = "liangcheng", a = 0) {
o = md5X(o);
const s = md5X(o.substring(0, 16)),
i = md5X(o.substring(16, 32));
let c = "";
if ("DECODE" === r) c = n.substring(0, 4);
else {
const e = md5X((() => {
const e = Date.now(),
t = Math.floor(e / 1e3);
return (e - 1e3 * t) / 1e3 + " " + t
})());
c = e.substring(e.length - 4)
}
const p = e.enc.Utf8.parse(s + md5X(s + c));
let l = "";
if ("DECODE" === r) {
let r = e.enc.Base64.parse(n.substring(4)),
o = e.RC4.decrypt({
ciphertext: r
}, p);
l = e.enc.Latin1.stringify(o);
const a = parseInt(l.substring(0, 10), 10),
s = 0 === a || a - t() > 0,
c = l.substring(10, 26) === md5X(l.substring(26) + i).substring(0, 16);
return s && c ? l.substring(26) : ""
} {
a = a ? a + t() : 0;
const r = String(a).padStart(10, "0") + md5X(n + i).substring(0, 16) + n;
return l = e.RC4.encrypt(e.enc.Latin1.parse(r), p).toString(), c + l.replace(/=/g, "")
}
};
return {
encode: (e, t, r) => n(e, "ENCODE", t, r).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "."),
decode: (e, t) => n(e.replace(/-/g, "+").replace(/_/g, "/").replace(/\./g, "="), "DECODE", t)
}
}();
function y(t, n) {
return e.AES.encrypt(e.enc.Utf8.parse(t), e.enc.Utf8.parse(n), {
mode: e.mode.ECB
}).ciphertext.toString()
}
function m(e) {
return md5X(`17325841932717338791732584194271733878${e}`.replace(/[\-|\,]/g, ""))
}
function h(e, t) {
const n = e.match(new RegExp(`var\\s+${t}\\s*=\\s*['"]([^'"]+)['"]`));
return n ? n[1] : null
}
function v(e) {
let t = {};
for (let n in e) t[n] = a ? encodeURIComponent(e[n] || "") : e[n];
return t
}
export function __jsEvalReturn() {
return {
init: s,
home: i,
homeVod: c,
category: p,
search: l,
detail: d,
play: u
}
}