上传文件至「js」
This commit is contained in:
@@ -0,0 +1,469 @@
|
||||
import cheerio from 'assets://js/lib/cheerio.min.js';
|
||||
|
||||
const appConfig = {
|
||||
siteName: "伦理专题影片",
|
||||
siteUrl: "http://yoxayg.com"
|
||||
};
|
||||
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";
|
||||
|
||||
async function init(ext) {
|
||||
console.log("初始化爬虫:", appConfig.siteName);
|
||||
}
|
||||
|
||||
const classList = [
|
||||
{ type_id: "1", type_name: "电影" },
|
||||
{ type_id: "2", type_name: "电视剧" },
|
||||
{ type_id: "3", type_name: "综艺" },
|
||||
{ type_id: "4", type_name: "动漫" },
|
||||
{ type_id: "36", type_name: "短剧" },
|
||||
{ type_id: "6", type_name: "动作片" },
|
||||
{ type_id: "7", type_name: "喜剧片" },
|
||||
{ type_id: "8", type_name: "爱情片" },
|
||||
{ type_id: "9", type_name: "科幻片" },
|
||||
{ type_id: "10", type_name: "恐怖片" },
|
||||
{ type_id: "11", type_name: "剧情片" },
|
||||
{ type_id: "12", type_name: "战争片" },
|
||||
{ type_id: "20", type_name: "记录片" },
|
||||
{ type_id: "34", type_name: "伦理片" },
|
||||
{ type_id: "13", type_name: "国产剧" },
|
||||
{ type_id: "14", type_name: "香港剧" },
|
||||
{ type_id: "15", type_name: "韩国剧" },
|
||||
{ type_id: "16", type_name: "欧美剧" },
|
||||
{ type_id: "21", type_name: "台湾剧" },
|
||||
{ type_id: "22", type_name: "日本剧" },
|
||||
{ type_id: "23", type_name: "海外剧" },
|
||||
{ type_id: "24", type_name: "泰国剧" },
|
||||
{ type_id: "25", type_name: "大陆综艺" },
|
||||
{ type_id: "26", type_name: "港台综艺" },
|
||||
{ type_id: "27", type_name: "日韩综艺" },
|
||||
{ type_id: "28", type_name: "欧美综艺" },
|
||||
{ type_id: "29", type_name: "国产动漫" },
|
||||
{ type_id: "30", type_name: "日韩动漫" },
|
||||
{ type_id: "31", type_name: "欧美动漫" },
|
||||
{ type_id: "32", type_name: "港台动漫" },
|
||||
{ type_id: "33", type_name: "海外动漫" }
|
||||
];
|
||||
|
||||
const typeSlugMap = {
|
||||
"1": "dianying", "2": "dianshiju", "3": "zongyi", "4": "dongman", "6": "dongzuopian",
|
||||
"7": "xijupian", "8": "aiqingpian", "9": "kehuanpian", "10": "kongbupian", "11": "juqingpian",
|
||||
"12": "zhanzhengpian", "13": "guochanju", "14": "xianggangju", "15": "hanguoju", "16": "oumeiju",
|
||||
"20": "jilupian", "21": "taiwanju", "22": "ribenju", "23": "haiwaiju", "24": "taiguoju",
|
||||
"25": "daluzongyi", "26": "gangtaizongyi", "27": "rihanzongyi", "28": "oumeizongyi",
|
||||
"29": "guochandongman", "30": "rihandongman", "31": "oumeidongman", "32": "gangtaidongman",
|
||||
"33": "haiwaidongman", "34": "lunlipian", "36": "duanju"
|
||||
};
|
||||
|
||||
const typeParentMap = {
|
||||
"1": 0, "2": 0, "3": 0, "4": 0, "6": 1, "7": 1, "8": 1, "9": 1, "10": 1,
|
||||
"11": 1, "12": 1, "13": 2, "14": 2, "15": 2, "16": 2, "20": 1, "21": 2, "22": 2,
|
||||
"23": 2, "24": 2, "25": 3, "26": 3, "27": 3, "28": 3, "29": 4, "30": 4,
|
||||
"31": 4, "32": 4, "33": 4, "34": 1, "36": 2
|
||||
};
|
||||
|
||||
function topType(tid) {
|
||||
tid = parseInt(tid || 0, 10);
|
||||
if (tid === 36) return 36;
|
||||
const p = parseInt(typeParentMap[String(tid)] || 0, 10);
|
||||
return p > 0 ? p : tid;
|
||||
}
|
||||
|
||||
function typeSlug(tid) {
|
||||
return typeSlugMap[String(parseInt(tid || 0, 10))] || ('type' + parseInt(tid || 0, 10));
|
||||
}
|
||||
|
||||
function getAreaFilter() {
|
||||
return {
|
||||
"key": "area", "name": "地区", "value": [
|
||||
{ "n": "全部", "v": "" }, { "n": "大陆", "v": "大陆" }, { "n": "香港", "v": "香港" },
|
||||
{ "n": "台湾", "v": "台湾" }, { "n": "美国", "v": "美国" }, { "n": "日本", "v": "日本" },
|
||||
{ "n": "韩国", "v": "韩国" }, { "n": "英国", "v": "英国" }, { "n": "法国", "v": "法国" },
|
||||
{ "n": "德国", "v": "德国" }, { "n": "泰国", "v": "泰国" }, { "n": "印度", "v": "印度" },
|
||||
{ "n": "其他", "v": "其他" }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function getYearFilter() {
|
||||
let years = [{ "n": "全部", "v": "" }];
|
||||
const currentYear = new Date().getFullYear();
|
||||
for (let y = currentYear; y >= 2010; y--) {
|
||||
years.push({ "n": String(y), "v": String(y) });
|
||||
}
|
||||
return { "key": "year", "name": "年份", "value": years };
|
||||
}
|
||||
|
||||
const commonFilters = [getAreaFilter(), getYearFilter()];
|
||||
|
||||
const myFilters = {};
|
||||
classList.forEach(item => {
|
||||
myFilters[item.type_id] = commonFilters;
|
||||
});
|
||||
|
||||
function fixUrl(u) {
|
||||
if (!u) return '';
|
||||
if (u.startsWith('http')) return u;
|
||||
if (u.startsWith('//')) return 'http:' + u;
|
||||
if (u.startsWith('/')) return appConfig.siteUrl + u;
|
||||
return u;
|
||||
}
|
||||
|
||||
async function home(filter) {
|
||||
let list = [];
|
||||
try {
|
||||
const html = (await req(appConfig.siteUrl, {
|
||||
method: "GET",
|
||||
headers: { "User-Agent": UA }
|
||||
})).content;
|
||||
const $ = cheerio.load(html);
|
||||
let seen = {};
|
||||
|
||||
$(".tpl-card[href]").each(function () {
|
||||
let vod_id = $(this).attr("href");
|
||||
if (!vod_id || seen[vod_id]) return;
|
||||
|
||||
let vod_name = $(this).attr("title") || $(this).find("strong").first().text().trim() || "";
|
||||
vod_name = vod_name.replace(/免费在线观看$/, "");
|
||||
let vod_pic = fixUrl($(this).find("img").first().attr("src") || "");
|
||||
let vod_remarks = $(this).find("em").first().text().trim();
|
||||
|
||||
if (vod_name && vod_id) {
|
||||
seen[vod_id] = true;
|
||||
list.push({ vod_id, vod_name, vod_pic, vod_remarks });
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("首页推荐获取失败:", e.message);
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
class: classList,
|
||||
filters: myFilters,
|
||||
list: list.slice(0, 30)
|
||||
});
|
||||
}
|
||||
|
||||
function buildCategoryUrl(tid, pg, extend) {
|
||||
extend = extend || {};
|
||||
let top = topType(tid);
|
||||
let topSlug = typeSlug(top);
|
||||
let childSlug = (tid != top) ? typeSlug(tid) : '';
|
||||
|
||||
let path;
|
||||
if (childSlug && tid != 36) {
|
||||
path = `/${topSlug}/${childSlug}/`;
|
||||
} else {
|
||||
path = `/${topSlug}/`;
|
||||
}
|
||||
|
||||
if (pg > 1) {
|
||||
path += `page-${pg}.html`;
|
||||
}
|
||||
|
||||
let area = extend.area || '';
|
||||
let year = extend.year || '';
|
||||
if (area || year) {
|
||||
let params = [];
|
||||
if (area) params.push('area=' + encodeURIComponent(area));
|
||||
if (year) params.push('year=' + encodeURIComponent(year));
|
||||
return appConfig.siteUrl + `/api_proxy.php?ac=list&t=${tid}&pg=${pg}&${params.join('&')}`;
|
||||
}
|
||||
|
||||
return appConfig.siteUrl + path;
|
||||
}
|
||||
|
||||
function parseListHtml(html) {
|
||||
const $ = cheerio.load(html);
|
||||
let list = [];
|
||||
let vodIds = {};
|
||||
|
||||
$(".tpl-card.card-poster, .tpl-card.card-wide").each(function () {
|
||||
let $a = $(this);
|
||||
let vod_id = $a.attr("href");
|
||||
if (!vod_id || vodIds[vod_id]) return;
|
||||
|
||||
let vod_name = $a.attr("title") || $a.find("strong").first().text().trim() || "";
|
||||
vod_name = vod_name.replace(/免费在线观看$/, "");
|
||||
let vod_pic = fixUrl($a.find("img").first().attr("src") || "");
|
||||
let vod_remarks = $a.find("em").first().text().trim() || $a.find("small").first().text().trim();
|
||||
|
||||
if (vod_name && vod_id) {
|
||||
vodIds[vod_id] = true;
|
||||
list.push({ vod_id, vod_name, vod_pic, vod_remarks });
|
||||
}
|
||||
});
|
||||
|
||||
if (list.length === 0) {
|
||||
try {
|
||||
let data = JSON.parse(html);
|
||||
if (data.list && Array.isArray(data.list)) {
|
||||
data.list.forEach(item => {
|
||||
let vod_id = `/${typeSlug(topType(item.type_id))}/${(item.vod_en || item.vod_name || '').toLowerCase().replace(/[^a-z0-9]+/g, '')}.html`;
|
||||
let vod_name = item.vod_name || "";
|
||||
let vod_pic = item.vod_pic || "";
|
||||
let vod_remarks = item.vod_remarks || "";
|
||||
if (vod_name) {
|
||||
list.push({ vod_id, vod_name, vod_pic, vod_remarks });
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
let pagecount = 1;
|
||||
$(".pagination a").each(function () {
|
||||
let href = $(this).attr("href") || '';
|
||||
let m = href.match(/page-(\d+)/);
|
||||
if (m) {
|
||||
let p = parseInt(m[1]);
|
||||
if (p > pagecount) pagecount = p;
|
||||
}
|
||||
});
|
||||
|
||||
return { list, pagecount };
|
||||
}
|
||||
|
||||
async function category(tid, pg, filter, extend) {
|
||||
pg = pg || 1;
|
||||
extend = extend || {};
|
||||
|
||||
let url = buildCategoryUrl(tid, pg, extend);
|
||||
|
||||
try {
|
||||
const html = (await req(url, {
|
||||
method: "GET",
|
||||
headers: { "User-Agent": UA, "Referer": appConfig.siteUrl }
|
||||
})).content;
|
||||
const result = parseListHtml(html);
|
||||
return JSON.stringify(result);
|
||||
} catch (e) {
|
||||
console.error("分类列表获取失败:", e.message);
|
||||
return JSON.stringify({ list: [], pagecount: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
async function search(wd, quick, page) {
|
||||
page = page || 1;
|
||||
try {
|
||||
const url = `${appConfig.siteUrl}/search-${encodeURIComponent(wd)}${page > 1 ? '-page-' + page : ''}.html`;
|
||||
const html = (await req(url, {
|
||||
method: "GET",
|
||||
headers: { "User-Agent": UA, "Referer": appConfig.siteUrl }
|
||||
})).content;
|
||||
const result = parseListHtml(html);
|
||||
return JSON.stringify(result);
|
||||
} catch (e) {
|
||||
console.error("搜索失败:", e.message);
|
||||
return JSON.stringify({ list: [], pagecount: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
async function detail(id) {
|
||||
try {
|
||||
const html = (await req(appConfig.siteUrl + id, {
|
||||
method: "GET",
|
||||
headers: { "User-Agent": UA, "Referer": appConfig.siteUrl }
|
||||
})).content;
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
let vod_name = $("h1").first().text().trim();
|
||||
|
||||
let vod_pic = fixUrl($(".detail-poster img").first().attr("src") || "");
|
||||
|
||||
let vod_director = "";
|
||||
let vod_actor = "";
|
||||
let vod_area = "";
|
||||
let vod_year = "";
|
||||
let vod_content = "";
|
||||
let vod_class = "";
|
||||
let vod_remarks = "";
|
||||
|
||||
$(".detail-tags span").each(function () {
|
||||
let text = $(this).text().trim();
|
||||
if (/^\d{4}$/.test(text) && !vod_year) vod_year = text;
|
||||
else if (/大陆|香港|台湾|美国|日本|韩国|英国|法国|德国|泰国|印度|其他/.test(text) && !vod_area) vod_area = text;
|
||||
else if (!vod_class && text !== vod_year && text !== vod_area && !/更新至|集|期|TC|HD|正片/.test(text)) vod_class = text;
|
||||
});
|
||||
|
||||
vod_remarks = $(".detail-poster span").first().text().trim();
|
||||
|
||||
$(".detail-meta p").each(function () {
|
||||
let text = $(this).text();
|
||||
if (text.includes("主演:") && !vod_actor) {
|
||||
vod_actor = text.replace("主演:", "").trim();
|
||||
}
|
||||
if (text.includes("导演:") && !vod_director) {
|
||||
vod_director = text.replace("导演:", "").trim();
|
||||
}
|
||||
});
|
||||
|
||||
let $intro = $(".detail-intro");
|
||||
if ($intro.length > 0) {
|
||||
vod_content = $intro.first().text().replace("简介:", "").trim();
|
||||
}
|
||||
if (!vod_content) {
|
||||
$intro = $(".article-text");
|
||||
if ($intro.length > 0) {
|
||||
vod_content = $intro.first().text().trim();
|
||||
}
|
||||
}
|
||||
|
||||
let lines = [];
|
||||
let playlists = [];
|
||||
let epArray = [];
|
||||
|
||||
$(".episode-grid a").each(function () {
|
||||
let name = $(this).text().trim();
|
||||
let href = $(this).attr('href') || '';
|
||||
if (name && href) {
|
||||
epArray.push({ name, href });
|
||||
}
|
||||
});
|
||||
|
||||
epArray.sort((a, b) => {
|
||||
let numA = parseInt(a.name.match(/第(\d+)/)?.[1] || 0);
|
||||
let numB = parseInt(b.name.match(/第(\d+)/)?.[1] || 0);
|
||||
return numA - numB;
|
||||
});
|
||||
|
||||
let episodes = epArray.map(ep => `${ep.name}$${ep.href}`);
|
||||
|
||||
if (episodes.length > 0) {
|
||||
lines.push("默认");
|
||||
playlists.push(episodes);
|
||||
} else {
|
||||
let playHref = $(".detail-actions a.btn-primary").attr("href") || "";
|
||||
if (playHref) {
|
||||
lines.push("默认");
|
||||
playlists.push([`正片$${playHref}`]);
|
||||
}
|
||||
}
|
||||
|
||||
if (lines.length === 0) {
|
||||
lines.push("默认");
|
||||
playlists.push([`暂无播放地址$${id}`]);
|
||||
}
|
||||
|
||||
const { vod_play_from, vod_play_url } = buildVodPlayData(lines, playlists);
|
||||
|
||||
return JSON.stringify({
|
||||
list: [{
|
||||
vod_id: id,
|
||||
vod_name,
|
||||
vod_pic,
|
||||
vod_actor,
|
||||
vod_director,
|
||||
vod_remarks,
|
||||
vod_year,
|
||||
vod_area,
|
||||
vod_content,
|
||||
vod_class,
|
||||
vod_play_from,
|
||||
vod_play_url
|
||||
}]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`解析详情页异常 [ID: ${id}]:`, error);
|
||||
return JSON.stringify({ list: [] });
|
||||
}
|
||||
}
|
||||
|
||||
function buildVodPlayData(lines, playlists) {
|
||||
const processedPlaylists = playlists.map(eps => eps.join('#'));
|
||||
return {
|
||||
vod_play_from: lines.filter(Boolean).join('$$$'),
|
||||
vod_play_url: processedPlaylists.join('$$$')
|
||||
};
|
||||
}
|
||||
|
||||
async function play(flag, id, flags) {
|
||||
try {
|
||||
if (id.startsWith("http")) {
|
||||
return JSON.stringify({
|
||||
parse: 0,
|
||||
Header: { "User-Agent": UA, "Referer": appConfig.siteUrl },
|
||||
url: id
|
||||
});
|
||||
}
|
||||
|
||||
const html = (await req(`${appConfig.siteUrl}${id}`, {
|
||||
method: "GET",
|
||||
headers: { "User-Agent": UA, "Referer": appConfig.siteUrl }
|
||||
})).content;
|
||||
|
||||
// 方式1:从 noscript 中提取 m3u8 URL
|
||||
let noscriptMatch = html.match(/<noscript>.*?当前播放地址[::]\s*(https?:\/\/[^\s<"]+\.m3u8[^\s<"]*)/);
|
||||
if (noscriptMatch) {
|
||||
return JSON.stringify({
|
||||
parse: 0,
|
||||
Header: { "User-Agent": UA, "Referer": appConfig.siteUrl },
|
||||
url: noscriptMatch[1]
|
||||
});
|
||||
}
|
||||
|
||||
// 方式2:从 JS 中提取 var src="..."
|
||||
let srcMatch = html.match(/var\s+src\s*=\s*["'](https?:\/\/[^"']+\.m3u8[^"']*)/);
|
||||
if (srcMatch) {
|
||||
return JSON.stringify({
|
||||
parse: 0,
|
||||
Header: { "User-Agent": UA, "Referer": appConfig.siteUrl },
|
||||
url: srcMatch[1]
|
||||
});
|
||||
}
|
||||
|
||||
// 方式3:直接匹配 m3u8 URL
|
||||
let urlMatch = html.match(/(https?:\/\/[^"'\s<>]+\.m3u8[^"'\s<>]*)/);
|
||||
if (urlMatch) {
|
||||
return JSON.stringify({
|
||||
parse: 0,
|
||||
Header: { "User-Agent": UA, "Referer": appConfig.siteUrl },
|
||||
url: urlMatch[1]
|
||||
});
|
||||
}
|
||||
|
||||
// 方式4:player_aaaa
|
||||
let playerMatch = html.match(/var player_aaaa\s*=\s*(\{.+?\});/);
|
||||
if (playerMatch) {
|
||||
try {
|
||||
let playerData = JSON.parse(playerMatch[1]);
|
||||
if (playerData.url) {
|
||||
return JSON.stringify({
|
||||
parse: 0,
|
||||
Header: { "User-Agent": UA, "Referer": appConfig.siteUrl },
|
||||
url: playerData.url
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 方式5:video 标签的 src
|
||||
const $ = cheerio.load(html);
|
||||
let videoSrc = $("video").attr("src") || $("video source").attr("src");
|
||||
if (videoSrc) {
|
||||
return JSON.stringify({
|
||||
parse: 0,
|
||||
Header: { "User-Agent": UA, "Referer": appConfig.siteUrl },
|
||||
url: fixUrl(videoSrc)
|
||||
});
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
parse: 1,
|
||||
Header: { "User-Agent": UA, "Referer": appConfig.siteUrl },
|
||||
url: appConfig.siteUrl + id
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("播放失败:", e);
|
||||
return JSON.stringify({ parse: 0, url: "" });
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
init,
|
||||
home,
|
||||
category,
|
||||
detail,
|
||||
search,
|
||||
play
|
||||
};
|
||||
+1659
@@ -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(/ /g, ' ')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/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(/ /g, ' ')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/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(/ /g, ' ')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/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 };
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
//本资源来源于互联网公开渠道,仅可用于个人学习爬虫技术。
|
||||
//严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
|
||||
import{load as n,Crypto as v}from"assets://js/lib/cat.js";let e="https://vip.wwgz.cn:5200",t=!1,i={"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Snapchat/10.77.5.59 (like Safari/604.1)",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","upgrade-insecure-requests":"1"};async function a(n){let v=n.ext;"string"==typeof v&&v.startsWith("http")&&(e=v),e.endsWith("/")&&(e=e.slice(0,-1)),"function"==typeof js2Proxy&&"function"==typeof desX&&"function"!=typeof getProxy&&(t=!0)}async function r(n){let v={class:[{type_id:"1",type_name:"电影"},{type_id:"2",type_name:"连续剧"},{type_id:"3",type_name:"综艺"},{type_id:"4",type_name:"动漫"},{type_id:"26",type_name:"短剧"}],filters:{1:[{key:"id",name:"类型",init:"",value:[{n:"全部",v:""},{n:"动作片",v:"5"},{n:"喜剧片",v:"6"},{n:"爱情片",v:"7"},{n:"科幻片",v:"8"},{n:"恐怖片",v:"9"},{n:"剧情片",v:"10"},{n:"战争片",v:"11"},{n:"惊悚片",v:"16"},{n:"奇幻片",v:"17"}]},{key:"area",name:"地区",init:"",value:[{n:"全部",v:""},{n:"大陆",v:"大陆"},{n:"香港",v:"香港"},{n:"台湾",v:"台湾"},{n:"美国",v:"美国"},{n:"韩国",v:"韩国"},{n:"日本",v:"日本"},{n:"泰国",v:"泰国"},{n:"新加坡",v:"新加坡"},{n:"马来西亚",v:"马来西亚"},{n:"印度",v:"印度"},{n:"英国",v:"英国"},{n:"法国",v:"法国"},{n:"加拿大",v:"加拿大"},{n:"西班牙",v:"西班牙"},{n:"俄罗斯",v:"俄罗斯"},{n:"其它",v:"其它"}]},{key:"year",name:"年份",init:"",value:[{n:"全部",v:""},{n:"2026",v:"2026"},{n:"2025",v:"2025"},{n:"2024",v:"2024"},{n:"2023",v:"2023"},{n:"2022",v:"2022"},{n:"2021",v:"2021"},{n:"2020",v:"2020"},{n:"2019",v:"2019"},{n:"2018",v:"2018"},{n:"2017",v:"2017"},{n:"2016",v:"2016"},{n:"2015",v:"2015"},{n:"2014",v:"2014"},{n:"2013",v:"2013"},{n:"2012",v:"2012"},{n:"2011",v:"2011"},{n:"2010",v:"2010"},{n:"2009",v:"2009"},{n:"2008",v:"2008"},{n:"2007",v:"2007"},{n:"2006",v:"2006"},{n:"2005",v:"2005"},{n:"2004",v:"2004"},{n:"2003",v:"2003"},{n:"2002",v:"2002"},{n:"2001",v:"2001"},{n:"2000",v:"2000"},{n:"1999",v:"1999"},{n:"1998",v:"1998"},{n:"1997",v:"1997"},{n:"1996",v:"1996"},{n:"1995",v:"1995"},{n:"1994",v:"1994"},{n:"1993",v:"1993"},{n:"1992",v:"1992"},{n:"1991",v:"1991"},{n:"1990",v:"1990"},{n:"1989",v:"1989"},{n:"1988",v:"1988"},{n:"1987",v:"1987"},{n:"1986",v:"1986"},{n:"1985",v:"1985"},{n:"1984",v:"1984"},{n:"1983",v:"1983"},{n:"1982",v:"1982"},{n:"1981",v:"1981"},{n:"1980",v:"1980"},{n:"1979",v:"1979"},{n:"1978",v:"1978"},{n:"1977",v:"1977"},{n:"1976",v:"1976"},{n:"1975",v:"1975"},{n:"1974",v:"1974"},{n:"1973",v:"1973"},{n:"1972",v:"1972"},{n:"1971",v:"1971"},{n:"1970",v:"1970"},{n:"1969",v:"1969"},{n:"1968",v:"1968"},{n:"1967",v:"1967"},{n:"1966",v:"1966"},{n:"1965",v:"1965"},{n:"1964",v:"1964"},{n:"1963",v:"1963"},{n:"1962",v:"1962"},{n:"1961",v:"1961"},{n:"1960",v:"1960"},{n:"1959",v:"1959"},{n:"1958",v:"1958"},{n:"1957",v:"1957"},{n:"1956",v:"1956"},{n:"1955",v:"1955"},{n:"1954",v:"1954"},{n:"1953",v:"1953"},{n:"1952",v:"1952"},{n:"1951",v:"1951"},{n:"1950",v:"1950"},{n:"1949",v:"1949"},{n:"1948",v:"1948"},{n:"1947",v:"1947"},{n:"1946",v:"1946"},{n:"1945",v:"1945"},{n:"1944",v:"1944"},{n:"1943",v:"1943"},{n:"1942",v:"1942"},{n:"1941",v:"1941"},{n:"1940",v:"1940"},{n:"1939",v:"1939"},{n:"1938",v:"1938"},{n:"1937",v:"1937"},{n:"1936",v:"1936"},{n:"1935",v:"1935"},{n:"1934",v:"1934"},{n:"1933",v:"1933"},{n:"1932",v:"1932"},{n:"1931",v:"1931"},{n:"1930",v:"1930"},{n:"1929",v:"1929"},{n:"1928",v:"1928"},{n:"1927",v:"1927"},{n:"1926",v:"1926"},{n:"1925",v:"1925"},{n:"1924",v:"1924"},{n:"1923",v:"1923"},{n:"1922",v:"1922"},{n:"1921",v:"1921"},{n:"1920",v:"1920"},{n:"1919",v:"1919"},{n:"1918",v:"1918"},{n:"1917",v:"1917"},{n:"1916",v:"1916"},{n:"1915",v:"1915"},{n:"1914",v:"1914"},{n:"1913",v:"1913"},{n:"1912",v:"1912"},{n:"1911",v:"1911"},{n:"1910",v:"1910"},{n:"1909",v:"1909"},{n:"1908",v:"1908"},{n:"1907",v:"1907"},{n:"1906",v:"1906"},{n:"1905",v:"1905"},{n:"1904",v:"1904"},{n:"1903",v:"1903"},{n:"1902",v:"1902"},{n:"1901",v:"1901"},{n:"1900",v:"1900"}]},{key:"by",name:"排序",init:"time",value:[{n:"全部",v:"time"},{n:"人气",v:"hits"},{n:"评分",v:"score"}]}],2:[{key:"id",name:"类型",init:"",value:[{n:"全部",v:""},{n:"国产剧",v:"12"},{n:"港台泰",v:"13"},{n:"日韩剧",v:"14"},{n:"欧美剧",v:"15"}]},{key:"area",name:"地区",init:"",value:[{n:"全部",v:""},{n:"大陆",v:"大陆"},{n:"香港",v:"香港"},{n:"台湾",v:"台湾"},{n:"美国",v:"美国"},{n:"韩国",v:"韩国"},{n:"日本",v:"日本"},{n:"泰国",v:"泰国"},{n:"新加坡",v:"新加坡"},{n:"马来西亚",v:"马来西亚"},{n:"印度",v:"印度"},{n:"英国",v:"英国"},{n:"法国",v:"法国"},{n:"加拿大",v:"加拿大"},{n:"西班牙",v:"西班牙"},{n:"俄罗斯",v:"俄罗斯"},{n:"其它",v:"其它"}]},{key:"year",name:"年份",init:"",value:[{n:"全部",v:""},{n:"2026",v:"2026"},{n:"2025",v:"2025"},{n:"2024",v:"2024"},{n:"2023",v:"2023"},{n:"2022",v:"2022"},{n:"2021",v:"2021"},{n:"2020",v:"2020"},{n:"2019",v:"2019"},{n:"2018",v:"2018"},{n:"2017",v:"2017"},{n:"2016",v:"2016"},{n:"2015",v:"2015"},{n:"2014",v:"2014"},{n:"2013",v:"2013"},{n:"2012",v:"2012"},{n:"2011",v:"2011"},{n:"2010",v:"2010"},{n:"2009",v:"2009"},{n:"2008",v:"2008"},{n:"2007",v:"2007"},{n:"2006",v:"2006"},{n:"2005",v:"2005"},{n:"2004",v:"2004"},{n:"2003",v:"2003"},{n:"2002",v:"2002"},{n:"2001",v:"2001"},{n:"2000",v:"2000"},{n:"1999",v:"1999"},{n:"1998",v:"1998"},{n:"1997",v:"1997"},{n:"1996",v:"1996"},{n:"1995",v:"1995"},{n:"1994",v:"1994"},{n:"1993",v:"1993"},{n:"1992",v:"1992"},{n:"1991",v:"1991"},{n:"1990",v:"1990"},{n:"1989",v:"1989"},{n:"1988",v:"1988"},{n:"1987",v:"1987"},{n:"1986",v:"1986"},{n:"1985",v:"1985"},{n:"1984",v:"1984"},{n:"1983",v:"1983"},{n:"1982",v:"1982"},{n:"1981",v:"1981"},{n:"1980",v:"1980"},{n:"1979",v:"1979"},{n:"1978",v:"1978"},{n:"1977",v:"1977"},{n:"1976",v:"1976"},{n:"1975",v:"1975"},{n:"1974",v:"1974"},{n:"1973",v:"1973"},{n:"1972",v:"1972"},{n:"1971",v:"1971"},{n:"1970",v:"1970"},{n:"1969",v:"1969"},{n:"1968",v:"1968"},{n:"1967",v:"1967"},{n:"1966",v:"1966"},{n:"1965",v:"1965"},{n:"1964",v:"1964"},{n:"1963",v:"1963"},{n:"1962",v:"1962"},{n:"1961",v:"1961"},{n:"1960",v:"1960"},{n:"1959",v:"1959"},{n:"1958",v:"1958"},{n:"1957",v:"1957"},{n:"1956",v:"1956"},{n:"1955",v:"1955"},{n:"1954",v:"1954"},{n:"1953",v:"1953"},{n:"1952",v:"1952"},{n:"1951",v:"1951"},{n:"1950",v:"1950"},{n:"1949",v:"1949"},{n:"1948",v:"1948"},{n:"1947",v:"1947"},{n:"1946",v:"1946"},{n:"1945",v:"1945"},{n:"1944",v:"1944"},{n:"1943",v:"1943"},{n:"1942",v:"1942"},{n:"1941",v:"1941"},{n:"1940",v:"1940"},{n:"1939",v:"1939"},{n:"1938",v:"1938"},{n:"1937",v:"1937"},{n:"1936",v:"1936"},{n:"1935",v:"1935"},{n:"1934",v:"1934"},{n:"1933",v:"1933"},{n:"1932",v:"1932"},{n:"1931",v:"1931"},{n:"1930",v:"1930"},{n:"1929",v:"1929"},{n:"1928",v:"1928"},{n:"1927",v:"1927"},{n:"1926",v:"1926"},{n:"1925",v:"1925"},{n:"1924",v:"1924"},{n:"1923",v:"1923"},{n:"1922",v:"1922"},{n:"1921",v:"1921"},{n:"1920",v:"1920"},{n:"1919",v:"1919"},{n:"1918",v:"1918"},{n:"1917",v:"1917"},{n:"1916",v:"1916"},{n:"1915",v:"1915"},{n:"1914",v:"1914"},{n:"1913",v:"1913"},{n:"1912",v:"1912"},{n:"1911",v:"1911"},{n:"1910",v:"1910"},{n:"1909",v:"1909"},{n:"1908",v:"1908"},{n:"1907",v:"1907"},{n:"1906",v:"1906"},{n:"1905",v:"1905"},{n:"1904",v:"1904"},{n:"1903",v:"1903"},{n:"1902",v:"1902"},{n:"1901",v:"1901"},{n:"1900",v:"1900"}]},{key:"by",name:"排序",init:"time",value:[{n:"全部",v:"time"},{n:"人气",v:"hits"},{n:"评分",v:"score"}]}],3:[{key:"id",name:"类型",init:"",value:[{n:"全部",v:""}]},{key:"area",name:"地区",init:"",value:[{n:"全部",v:""},{n:"大陆",v:"大陆"},{n:"香港",v:"香港"},{n:"台湾",v:"台湾"},{n:"美国",v:"美国"},{n:"韩国",v:"韩国"},{n:"日本",v:"日本"},{n:"泰国",v:"泰国"},{n:"新加坡",v:"新加坡"},{n:"马来西亚",v:"马来西亚"},{n:"印度",v:"印度"},{n:"英国",v:"英国"},{n:"法国",v:"法国"},{n:"加拿大",v:"加拿大"},{n:"西班牙",v:"西班牙"},{n:"俄罗斯",v:"俄罗斯"},{n:"其它",v:"其它"}]},{key:"year",name:"年份",init:"",value:[{n:"全部",v:""},{n:"2026",v:"2026"},{n:"2025",v:"2025"},{n:"2024",v:"2024"},{n:"2023",v:"2023"},{n:"2022",v:"2022"},{n:"2021",v:"2021"},{n:"2020",v:"2020"},{n:"2019",v:"2019"},{n:"2018",v:"2018"},{n:"2017",v:"2017"},{n:"2016",v:"2016"},{n:"2015",v:"2015"},{n:"2014",v:"2014"},{n:"2013",v:"2013"},{n:"2012",v:"2012"},{n:"2011",v:"2011"},{n:"2010",v:"2010"},{n:"2009",v:"2009"},{n:"2008",v:"2008"},{n:"2007",v:"2007"},{n:"2006",v:"2006"},{n:"2005",v:"2005"},{n:"2004",v:"2004"},{n:"2003",v:"2003"},{n:"2002",v:"2002"},{n:"2001",v:"2001"},{n:"2000",v:"2000"},{n:"1999",v:"1999"},{n:"1998",v:"1998"},{n:"1997",v:"1997"},{n:"1996",v:"1996"},{n:"1995",v:"1995"},{n:"1994",v:"1994"},{n:"1993",v:"1993"},{n:"1992",v:"1992"},{n:"1991",v:"1991"},{n:"1990",v:"1990"},{n:"1989",v:"1989"},{n:"1988",v:"1988"},{n:"1987",v:"1987"},{n:"1986",v:"1986"},{n:"1985",v:"1985"},{n:"1984",v:"1984"},{n:"1983",v:"1983"},{n:"1982",v:"1982"},{n:"1981",v:"1981"},{n:"1980",v:"1980"},{n:"1979",v:"1979"},{n:"1978",v:"1978"},{n:"1977",v:"1977"},{n:"1976",v:"1976"},{n:"1975",v:"1975"},{n:"1974",v:"1974"},{n:"1973",v:"1973"},{n:"1972",v:"1972"},{n:"1971",v:"1971"},{n:"1970",v:"1970"},{n:"1969",v:"1969"},{n:"1968",v:"1968"},{n:"1967",v:"1967"},{n:"1966",v:"1966"},{n:"1965",v:"1965"},{n:"1964",v:"1964"},{n:"1963",v:"1963"},{n:"1962",v:"1962"},{n:"1961",v:"1961"},{n:"1960",v:"1960"},{n:"1959",v:"1959"},{n:"1958",v:"1958"},{n:"1957",v:"1957"},{n:"1956",v:"1956"},{n:"1955",v:"1955"},{n:"1954",v:"1954"},{n:"1953",v:"1953"},{n:"1952",v:"1952"},{n:"1951",v:"1951"},{n:"1950",v:"1950"},{n:"1949",v:"1949"},{n:"1948",v:"1948"},{n:"1947",v:"1947"},{n:"1946",v:"1946"},{n:"1945",v:"1945"},{n:"1944",v:"1944"},{n:"1943",v:"1943"},{n:"1942",v:"1942"},{n:"1941",v:"1941"},{n:"1940",v:"1940"},{n:"1939",v:"1939"},{n:"1938",v:"1938"},{n:"1937",v:"1937"},{n:"1936",v:"1936"},{n:"1935",v:"1935"},{n:"1934",v:"1934"},{n:"1933",v:"1933"},{n:"1932",v:"1932"},{n:"1931",v:"1931"},{n:"1930",v:"1930"},{n:"1929",v:"1929"},{n:"1928",v:"1928"},{n:"1927",v:"1927"},{n:"1926",v:"1926"},{n:"1925",v:"1925"},{n:"1924",v:"1924"},{n:"1923",v:"1923"},{n:"1922",v:"1922"},{n:"1921",v:"1921"},{n:"1920",v:"1920"},{n:"1919",v:"1919"},{n:"1918",v:"1918"},{n:"1917",v:"1917"},{n:"1916",v:"1916"},{n:"1915",v:"1915"},{n:"1914",v:"1914"},{n:"1913",v:"1913"},{n:"1912",v:"1912"},{n:"1911",v:"1911"},{n:"1910",v:"1910"},{n:"1909",v:"1909"},{n:"1908",v:"1908"},{n:"1907",v:"1907"},{n:"1906",v:"1906"},{n:"1905",v:"1905"},{n:"1904",v:"1904"},{n:"1903",v:"1903"},{n:"1902",v:"1902"},{n:"1901",v:"1901"},{n:"1900",v:"1900"}]},{key:"by",name:"排序",init:"time",value:[{n:"全部",v:"time"},{n:"人气",v:"hits"},{n:"评分",v:"score"}]}],4:[{key:"id",name:"类型",init:"",value:[{n:"全部",v:""},{n:"动漫剧",v:"18"}]},{key:"area",name:"地区",init:"",value:[{n:"全部",v:""},{n:"大陆",v:"大陆"},{n:"香港",v:"香港"},{n:"台湾",v:"台湾"},{n:"美国",v:"美国"},{n:"韩国",v:"韩国"},{n:"日本",v:"日本"},{n:"泰国",v:"泰国"},{n:"新加坡",v:"新加坡"},{n:"马来西亚",v:"马来西亚"},{n:"印度",v:"印度"},{n:"英国",v:"英国"},{n:"法国",v:"法国"},{n:"加拿大",v:"加拿大"},{n:"西班牙",v:"西班牙"},{n:"俄罗斯",v:"俄罗斯"},{n:"其它",v:"其它"}]},{key:"year",name:"年份",init:"",value:[{n:"全部",v:""},{n:"2026",v:"2026"},{n:"2025",v:"2025"},{n:"2024",v:"2024"},{n:"2023",v:"2023"},{n:"2022",v:"2022"},{n:"2021",v:"2021"},{n:"2020",v:"2020"},{n:"2019",v:"2019"},{n:"2018",v:"2018"},{n:"2017",v:"2017"},{n:"2016",v:"2016"},{n:"2015",v:"2015"},{n:"2014",v:"2014"},{n:"2013",v:"2013"},{n:"2012",v:"2012"},{n:"2011",v:"2011"},{n:"2010",v:"2010"},{n:"2009",v:"2009"},{n:"2008",v:"2008"},{n:"2007",v:"2007"},{n:"2006",v:"2006"},{n:"2005",v:"2005"},{n:"2004",v:"2004"},{n:"2003",v:"2003"},{n:"2002",v:"2002"},{n:"2001",v:"2001"},{n:"2000",v:"2000"},{n:"1999",v:"1999"},{n:"1998",v:"1998"},{n:"1997",v:"1997"},{n:"1996",v:"1996"},{n:"1995",v:"1995"},{n:"1994",v:"1994"},{n:"1993",v:"1993"},{n:"1992",v:"1992"},{n:"1991",v:"1991"},{n:"1990",v:"1990"},{n:"1989",v:"1989"},{n:"1988",v:"1988"},{n:"1987",v:"1987"},{n:"1986",v:"1986"},{n:"1985",v:"1985"},{n:"1984",v:"1984"},{n:"1983",v:"1983"},{n:"1982",v:"1982"},{n:"1981",v:"1981"},{n:"1980",v:"1980"},{n:"1979",v:"1979"},{n:"1978",v:"1978"},{n:"1977",v:"1977"},{n:"1976",v:"1976"},{n:"1975",v:"1975"},{n:"1974",v:"1974"},{n:"1973",v:"1973"},{n:"1972",v:"1972"},{n:"1971",v:"1971"},{n:"1970",v:"1970"},{n:"1969",v:"1969"},{n:"1968",v:"1968"},{n:"1967",v:"1967"},{n:"1966",v:"1966"},{n:"1965",v:"1965"},{n:"1964",v:"1964"},{n:"1963",v:"1963"},{n:"1962",v:"1962"},{n:"1961",v:"1961"},{n:"1960",v:"1960"},{n:"1959",v:"1959"},{n:"1958",v:"1958"},{n:"1957",v:"1957"},{n:"1956",v:"1956"},{n:"1955",v:"1955"},{n:"1954",v:"1954"},{n:"1953",v:"1953"},{n:"1952",v:"1952"},{n:"1951",v:"1951"},{n:"1950",v:"1950"},{n:"1949",v:"1949"},{n:"1948",v:"1948"},{n:"1947",v:"1947"},{n:"1946",v:"1946"},{n:"1945",v:"1945"},{n:"1944",v:"1944"},{n:"1943",v:"1943"},{n:"1942",v:"1942"},{n:"1941",v:"1941"},{n:"1940",v:"1940"},{n:"1939",v:"1939"},{n:"1938",v:"1938"},{n:"1937",v:"1937"},{n:"1936",v:"1936"},{n:"1935",v:"1935"},{n:"1934",v:"1934"},{n:"1933",v:"1933"},{n:"1932",v:"1932"},{n:"1931",v:"1931"},{n:"1930",v:"1930"},{n:"1929",v:"1929"},{n:"1928",v:"1928"},{n:"1927",v:"1927"},{n:"1926",v:"1926"},{n:"1925",v:"1925"},{n:"1924",v:"1924"},{n:"1923",v:"1923"},{n:"1922",v:"1922"},{n:"1921",v:"1921"},{n:"1920",v:"1920"},{n:"1919",v:"1919"},{n:"1918",v:"1918"},{n:"1917",v:"1917"},{n:"1916",v:"1916"},{n:"1915",v:"1915"},{n:"1914",v:"1914"},{n:"1913",v:"1913"},{n:"1912",v:"1912"},{n:"1911",v:"1911"},{n:"1910",v:"1910"},{n:"1909",v:"1909"},{n:"1908",v:"1908"},{n:"1907",v:"1907"},{n:"1906",v:"1906"},{n:"1905",v:"1905"},{n:"1904",v:"1904"},{n:"1903",v:"1903"},{n:"1902",v:"1902"},{n:"1901",v:"1901"},{n:"1900",v:"1900"}]},{key:"by",name:"排序",init:"time",value:[{n:"全部",v:"time"},{n:"人气",v:"hits"},{n:"评分",v:"score"}]}],26:[{key:"id",name:"类型",init:"",value:[{n:"全部",v:""}]},{key:"area",name:"地区",init:"",value:[{n:"全部",v:""},{n:"大陆",v:"大陆"},{n:"香港",v:"香港"},{n:"台湾",v:"台湾"},{n:"美国",v:"美国"},{n:"韩国",v:"韩国"},{n:"日本",v:"日本"},{n:"泰国",v:"泰国"},{n:"新加坡",v:"新加坡"},{n:"马来西亚",v:"马来西亚"},{n:"印度",v:"印度"},{n:"英国",v:"英国"},{n:"法国",v:"法国"},{n:"加拿大",v:"加拿大"},{n:"西班牙",v:"西班牙"},{n:"俄罗斯",v:"俄罗斯"},{n:"其它",v:"其它"}]},{key:"year",name:"年份",init:"",value:[{n:"全部",v:""},{n:"2026",v:"2026"},{n:"2025",v:"2025"},{n:"2024",v:"2024"},{n:"2023",v:"2023"},{n:"2022",v:"2022"},{n:"2021",v:"2021"},{n:"2020",v:"2020"},{n:"2019",v:"2019"},{n:"2018",v:"2018"},{n:"2017",v:"2017"},{n:"2016",v:"2016"},{n:"2015",v:"2015"},{n:"2014",v:"2014"},{n:"2013",v:"2013"},{n:"2012",v:"2012"},{n:"2011",v:"2011"},{n:"2010",v:"2010"},{n:"2009",v:"2009"},{n:"2008",v:"2008"},{n:"2007",v:"2007"},{n:"2006",v:"2006"},{n:"2005",v:"2005"},{n:"2004",v:"2004"},{n:"2003",v:"2003"},{n:"2002",v:"2002"},{n:"2001",v:"2001"},{n:"2000",v:"2000"},{n:"1999",v:"1999"},{n:"1998",v:"1998"},{n:"1997",v:"1997"},{n:"1996",v:"1996"},{n:"1995",v:"1995"},{n:"1994",v:"1994"},{n:"1993",v:"1993"},{n:"1992",v:"1992"},{n:"1991",v:"1991"},{n:"1990",v:"1990"},{n:"1989",v:"1989"},{n:"1988",v:"1988"},{n:"1987",v:"1987"},{n:"1986",v:"1986"},{n:"1985",v:"1985"},{n:"1984",v:"1984"},{n:"1983",v:"1983"},{n:"1982",v:"1982"},{n:"1981",v:"1981"},{n:"1980",v:"1980"},{n:"1979",v:"1979"},{n:"1978",v:"1978"},{n:"1977",v:"1977"},{n:"1976",v:"1976"},{n:"1975",v:"1975"},{n:"1974",v:"1974"},{n:"1973",v:"1973"},{n:"1972",v:"1972"},{n:"1971",v:"1971"},{n:"1970",v:"1970"},{n:"1969",v:"1969"},{n:"1968",v:"1968"},{n:"1967",v:"1967"},{n:"1966",v:"1966"},{n:"1965",v:"1965"},{n:"1964",v:"1964"},{n:"1963",v:"1963"},{n:"1962",v:"1962"},{n:"1961",v:"1961"},{n:"1960",v:"1960"},{n:"1959",v:"1959"},{n:"1958",v:"1958"},{n:"1957",v:"1957"},{n:"1956",v:"1956"},{n:"1955",v:"1955"},{n:"1954",v:"1954"},{n:"1953",v:"1953"},{n:"1952",v:"1952"},{n:"1951",v:"1951"},{n:"1950",v:"1950"},{n:"1949",v:"1949"},{n:"1948",v:"1948"},{n:"1947",v:"1947"},{n:"1946",v:"1946"},{n:"1945",v:"1945"},{n:"1944",v:"1944"},{n:"1943",v:"1943"},{n:"1942",v:"1942"},{n:"1941",v:"1941"},{n:"1940",v:"1940"},{n:"1939",v:"1939"},{n:"1938",v:"1938"},{n:"1937",v:"1937"},{n:"1936",v:"1936"},{n:"1935",v:"1935"},{n:"1934",v:"1934"},{n:"1933",v:"1933"},{n:"1932",v:"1932"},{n:"1931",v:"1931"},{n:"1930",v:"1930"},{n:"1929",v:"1929"},{n:"1928",v:"1928"},{n:"1927",v:"1927"},{n:"1926",v:"1926"},{n:"1925",v:"1925"},{n:"1924",v:"1924"},{n:"1923",v:"1923"},{n:"1922",v:"1922"},{n:"1921",v:"1921"},{n:"1920",v:"1920"},{n:"1919",v:"1919"},{n:"1918",v:"1918"},{n:"1917",v:"1917"},{n:"1916",v:"1916"},{n:"1915",v:"1915"},{n:"1914",v:"1914"},{n:"1913",v:"1913"},{n:"1912",v:"1912"},{n:"1911",v:"1911"},{n:"1910",v:"1910"},{n:"1909",v:"1909"},{n:"1908",v:"1908"},{n:"1907",v:"1907"},{n:"1906",v:"1906"},{n:"1905",v:"1905"},{n:"1904",v:"1904"},{n:"1903",v:"1903"},{n:"1902",v:"1902"},{n:"1901",v:"1901"},{n:"1900",v:"1900"}]},{key:"by",name:"排序",init:"time",value:[{n:"全部",v:"time"},{n:"人气",v:"hits"},{n:"评分",v:"score"}]}]}};return t&&v.class.unshift({type_id:"home",type_name:"首页"}),JSON.stringify(v)}async function s(v,t,i,a){if("home"===v)return JSON.stringify({page:1,pagecount:1,list:m(n(await d(e+"/")))});let r=a||{},s=(r.id||v).match(/\d+/)?.[0]||"1";const o=n=>null==n||""===n?"":n;let l=`${e}/index.php?m=vod-list-id-${s}-pg-${t||1}-order--by-${r.by||"time"}-class-${o(r.class)}-year-${o(r.year)}-letter-${r.letter||""}-area-${encodeURIComponent(o(r.area))}-lang-${encodeURIComponent(o(r.lang))}.html`,c=m(n(await d(l)));return JSON.stringify({page:parseInt(t||1),pagecount:c.length>0?parseInt(t||1)+1:1,list:c})}async function o(v,a=!1,r=1){let s=`${e}/index.php?m=vod-search`,o=await req(s,{method:"POST",postType:"form",headers:{...i,Referer:`${e}/vod-search`},data:{wd:t?encodeURIComponent(v):v}}),l=n(o.content),c=[];return l("#data_list li").each((n,v)=>{let e=l(v).find(".pic a"),t=e.attr("href");if(t&&t.includes("vod-detail-id")){let n=e.find("img").attr("data-src")||e.find("img").attr("src"),i=l(v).find(".txt .sTit").text().trim(),a=l(v).find(".pic .sStyle").text().trim(),r=l(v).find('.txt .sDes:contains("评分")').text().replace(/评分[::]?\s*/,"").trim(),s=l(v).find('.txt .sDes:contains("主演")').text().replace(/主演[::]?\s*/,"").trim(),o=[];a&&o.push(a),r&&o.push(`${r}分`),s&&o.push(s);let m=o.join(" | ");c.push({vod_id:t,vod_name:i,vod_pic:p(n),vod_remarks:m})}}),JSON.stringify({list:c})}async function l(v){let t=v.startsWith("http")?v:e+v,i=n(await d(t)),a={vod_id:v,vod_name:i(".page-bd h1.title").text().trim(),vod_pic:p(i(".page-hd img").attr("src")),vod_year:i('.desc_item:contains("年代:") a').text().trim(),vod_remarks:i('.desc_item:contains("状态:") font').text().trim(),vod_actor:i('.desc_item:contains("主演:") a').map((n,v)=>i(v).text()).get().join(" ").trim(),vod_content:i(".detail-con p").text().replace(/简[\s\S]*?介[::]\s*/,"").trim(),vod_play_from:"",vod_play_url:""},r=i(".page-btn a.greenBtn").attr("href");if(r){let n=await d(r.startsWith("http")?r:e+r,t),v=n.match(/mac_from='([^']+)'/)?.[1],i=n.match(/mac_url='([^']+)'/)?.[1];if(v&&i){a.vod_play_from=v;try{a.vod_play_url=unescape(i)}catch(n){a.vod_play_url=i}}}return JSON.stringify({list:[a]})}async function c(n,e,t){let a=0,r=function(n){if(!n)return"";if((n=n.replace(/#+$/,"")).length<66)return"";let e=n.substring(0,66),t=n.substring(66),i="";for(let n=0;n<e.length;n+=2)i+=e[n];let a=i+t.replace(/O0O0O/g,"=").replace(/oo00o/g,"/").replace(/o000o/g,"+");try{return v.enc.Utf8.stringify(v.enc.Base64.parse(a))}catch(n){return""}}(e);if(!r||!r.startsWith("http")){let n="https://api.nmvod.me:520/player/?url=",v=await d(`${n}${e}`);r=v.match(/"url"\s*:\s*"([^"]+)"/)?.[1]?.replace(/\\\//g,"/"),r||(r=`${n}${e}`,a=1)}return JSON.stringify({parse:a,url:r,header:{"User-Agent":i["User-Agent"]}})}function m(n){let v=[];return n(".globalPicList li, .resize_list li").each((e,t)=>{let i=n(t).find("a"),a=i.attr("href");if(a?.includes("vod-detail-id")){let n=i.find("img").attr("data-echo")||i.find("img").attr("src");v.push({vod_id:a,vod_name:i.attr("title")||i.find(".sTit").text().trim(),vod_pic:p(n),vod_remarks:i.find(".sBottom span").text().replace(/<em>.*<\/em>/g,"").trim()||i.find(".covericon").text().trim()})}}),v}function p(n){return n?(n.startsWith("//")?n="http:"+n:n.startsWith("/")&&(n=e+n),n):""}async function d(n,v){let t={...i,Referer:v||e+"/","sec-fetch-site":v?"same-origin":"none"};return(await req(n,{headers:t})).content}export function __jsEvalReturn(){return{init:a,home:r,homeVod:()=>s("home",1,0,{}),category:s,search:o,detail:l,play:c}}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
let host = 'https://www.ylys.tv';
|
||||
let headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
||||
"Referer": host + "/",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9"
|
||||
};
|
||||
const init = async () => {};
|
||||
const extractVideos = html => {
|
||||
if (!html) return [];
|
||||
return pdfa(html, '.module-item,.module-card-item').map(it => {
|
||||
const href = pdfh(it, 'a&&href') || '';
|
||||
const id = href.match(/voddetail\/(\d+)/)?.[1];
|
||||
const name = pdfh(it, 'a&&title') || pdfh(it, 'strong&&Text') || pdfh(it, '.module-item-title&&Text') || "";
|
||||
const pic = pdfh(it, 'img&&data-original') || pdfh(it, 'img&&src') || "";
|
||||
const remarks = pdfh(it, '.module-item-text&&Text') || pdfh(it, '.module-item-note&&Text') || "";
|
||||
if (!id || !name) return null;
|
||||
return {
|
||||
vod_id: id,
|
||||
vod_name: name.trim(),
|
||||
vod_pic: pic.startsWith('/') ? host + pic : pic,
|
||||
vod_remarks: remarks.trim()
|
||||
};
|
||||
}).filter(Boolean);
|
||||
};
|
||||
const generateFilters = () => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const years = [{n:"全部",v:""}, ...Array.from({length:15},(_,i)=>{const y=currentYear-i;return{n:y+"",v:y+""}})];
|
||||
return {
|
||||
"1": [{"key":"class","name":"类型","value":[{"n":"全部","v":""},{"n":"动作片","v":"6"},{"n":"喜剧片","v":"7"},{"n":"爱情片","v":"8"},{"n":"科幻片","v":"9"},{"n":"恐怖片","v":"11"}]},{"key":"year","name":"年份","value":years}],
|
||||
"2": [{"key":"class","name":"类型","value":[{"n":"全部","v":""},{"n":"国产剧","v":"13"},{"n":"港台剧","v":"14"},{"n":"日剧","v":"15"},{"n":"韩剧","v":"33"},{"n":"欧美剧","v":"16"}]},{"key":"year","name":"年份","value":years}],
|
||||
"3": [{"key":"class","name":"类型","value":[{"n":"全部","v":""},{"n":"内地综艺","v":"27"},{"n":"港台综艺","v":"28"},{"n":"日本综艺","v":"29"},{"n":"韩国综艺","v":"36"}]},{"key":"year","name":"年份","value":years}],
|
||||
"4": [{"key":"class","name":"类型","value":[{"n":"全部","v":""},{"n":"国产动漫","v":"31"},{"n":"日本动漫","v":"32"},{"n":"欧美动漫","v":"42"},{"n":"其他动漫","v":"43"}]},{"key":"year","name":"年份","value":years}]
|
||||
};
|
||||
};
|
||||
const homeVod = async () => {
|
||||
const resp = await req(host, { headers });
|
||||
return JSON.stringify({ list: extractVideos(resp?.content || '') });
|
||||
};
|
||||
const home = async () => {
|
||||
const { list } = JSON.parse(await homeVod());
|
||||
return JSON.stringify({
|
||||
class: [
|
||||
{type_id:"1",type_name:"电影"},
|
||||
{type_id:"2",type_name:"剧集"},
|
||||
{type_id:"3",type_name:"综艺"},
|
||||
{type_id:"4",type_name:"动漫"}
|
||||
],
|
||||
filters: generateFilters(),
|
||||
list
|
||||
});
|
||||
};
|
||||
const category = async (tid, pg, _, extend) => {
|
||||
const cat = extend?.class || tid;
|
||||
const year = extend?.year || '';
|
||||
const url = `${host}/vodshow/${cat}--------${pg}---${year}/`;
|
||||
const html = (await req(url, { headers }))?.content || '';
|
||||
const list = extractVideos(html);
|
||||
const pagecount = html.match(/page\/(\d+)\/[^>]*>尾页/) ? +RegExp.$1 : 999;
|
||||
return JSON.stringify({ list, page: +pg, pagecount, limit: 20 });
|
||||
};
|
||||
const detail = async id => {
|
||||
const html = (await req(`${host}/voddetail/${id}/`, { headers }))?.content || '';
|
||||
if (!html) return JSON.stringify({ list: [] });
|
||||
let tabs = pdfa(html, '.module-tab-item');
|
||||
const lists = pdfa(html, '.module-play-list-content');
|
||||
if (tabs.length === 0 && lists.length > 0) tabs = ["默认"];
|
||||
const playFrom = tabs.map(t => pdfh(t, 'span&&Text') || "线路").join('$$$');
|
||||
const playUrl = lists.slice(0, tabs.length).map(l =>
|
||||
pdfa(l, 'a').map(a => {
|
||||
const name = pdfh(a, 'span&&Text') || "播放";
|
||||
const vid = (pdfh(a, 'a&&href') || "").match(/play\/([^\/]+)/)?.[1];
|
||||
return vid ? `${name}$${vid}` : null;
|
||||
}).filter(Boolean).join('#')
|
||||
).join('$$$');
|
||||
if (!playFrom || !playUrl) return JSON.stringify({ list: [] });
|
||||
return JSON.stringify({
|
||||
list: [{
|
||||
vod_id: id,
|
||||
vod_name: (html.match(/<h1>(.*?)<\/h1>/) || ["", ""])[1],
|
||||
vod_pic: (() => {
|
||||
const pic = (html.match(/data-original="(.*?)"/) || ["", ""])[1];
|
||||
return pic?.startsWith('/') ? host + pic : pic || "";
|
||||
})(),
|
||||
vod_content: ((html.match(/introduction-content">.*?<p>(.*?)<\/p>/s) || ["", ""])[1]?.replace(/<.*?>/g, "") || "暂无简介"),
|
||||
vod_year: (html.match(/href="\/vodshow\/\d+-----------(\d{4})\//) || ["", ""])[1] || "",
|
||||
vod_director: (html.match(/导演:.*?<a[^>]*>([^<]+)<\/a>/) || ["", ""])[1] || "",
|
||||
vod_actor: [...html.matchAll(/主演:.*?<a[^>]*>([^<]+)<\/a>/g)]
|
||||
.map(m => m[1])
|
||||
.filter(Boolean)
|
||||
.join(" / "),
|
||||
vod_play_from: playFrom,
|
||||
vod_play_url: playUrl
|
||||
}]
|
||||
});
|
||||
};
|
||||
const search = async (wd, _, pg = 1) => {
|
||||
const url = `${host}/vodsearch/${encodeURIComponent(wd)}----------${pg}---/`;
|
||||
const resp = await req(url, { headers });
|
||||
return JSON.stringify({ list: extractVideos(resp?.content || '') });
|
||||
};
|
||||
const play = async (_, id) => {
|
||||
const url = `${host}/play/${id}/`;
|
||||
const resp = await req(url, { headers });
|
||||
const m3u8 = resp?.content?.match(/"url":"([^"]+\.m3u8)"/);
|
||||
if (m3u8) return JSON.stringify({ parse: 0, url: m3u8[1].replace(/\\/g, ""), header: headers });
|
||||
return JSON.stringify({ parse: 1, url, header: headers });
|
||||
};
|
||||
export default { init, home, homeVod, category, detail, search, play };
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
@header({
|
||||
searchable: 0,
|
||||
filterable: 1,
|
||||
quickSearch: 0,
|
||||
title: '蜘蛛直播[体]',
|
||||
author: 'OpenClaw',
|
||||
lang: 'cat'
|
||||
})
|
||||
*/
|
||||
|
||||
let host = 'https://zzzbvip429.com';
|
||||
let apiHost = 'https://uwnyqabbrnve9xkwrhb01.k8v4dh4.app';
|
||||
let businessApi = apiHost + '/business';
|
||||
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 makeHeaders(extra = {}) {
|
||||
return {
|
||||
'User-Agent': ua,
|
||||
'Referer': host + '/',
|
||||
'Origin': host,
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Content-Type': 'application/json;charset=UTF-8',
|
||||
'DeviceInfo': 'web,openclaw',
|
||||
...extra
|
||||
};
|
||||
}
|
||||
|
||||
function safeJson(text) {
|
||||
try { return JSON.parse(text || '{}'); } catch (e) { return {}; }
|
||||
}
|
||||
|
||||
function firstArray(obj, keys) {
|
||||
for (const k of keys) {
|
||||
const v = obj && obj[k];
|
||||
if (Array.isArray(v)) return v;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function uniqByHouse(items) {
|
||||
const seen = new Set();
|
||||
const out = [];
|
||||
(items || []).forEach(it => {
|
||||
const id = String(it.houseId || it.appNumber || '').trim();
|
||||
if (!id || seen.has(id)) return;
|
||||
seen.add(id);
|
||||
out.push(it);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
function picOf(it) {
|
||||
return it.houseImage || it.loadingCover || it.userImage || it.cover || '';
|
||||
}
|
||||
|
||||
function titleOf(it) {
|
||||
return it.houseName || it.houseNameEn || it.houseNameTw || it.nickName || ('直播间 ' + (it.houseId || ''));
|
||||
}
|
||||
|
||||
function remarkOf(it) {
|
||||
const nick = it.nickName ? `主播:${it.nickName}` : '';
|
||||
const watch = it.visitHistory ? `热度:${it.visitHistory}` : '';
|
||||
return [nick, watch].filter(Boolean).join(' ') || (Number(it.liveStatus) === 2 ? '直播中' : '直播');
|
||||
}
|
||||
|
||||
function normalizePlayUrl(url) {
|
||||
url = String(url || '').trim();
|
||||
if (!url) return '';
|
||||
if (url.startsWith('webrtc://')) return '';
|
||||
return url;
|
||||
}
|
||||
|
||||
async function refreshApiHost() {
|
||||
try {
|
||||
const r = await req(host + '/config.json', { headers: makeHeaders({ 'Cache-Control': 'no-cache' }) });
|
||||
const cfg = safeJson(r.content);
|
||||
if (cfg && cfg['api-endpoint']) {
|
||||
apiHost = String(cfg['api-endpoint']).replace(/\/$/, '');
|
||||
businessApi = apiHost + '/business';
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
async function init(cfg) {
|
||||
if (cfg.ext && cfg.ext.startsWith('http')) host = cfg.ext.trim().replace(/\/$/, '');
|
||||
await refreshApiHost();
|
||||
}
|
||||
|
||||
async function home(filter) {
|
||||
return JSON.stringify({
|
||||
class: [
|
||||
{ type_id: 'live', type_name: '全部直播' },
|
||||
{ type_id: 'hot', type_name: '热门直播' },
|
||||
{ type_id: 'anchor', type_name: '主播直播' },
|
||||
{ type_id: 'match', type_name: '赛事列表' }
|
||||
],
|
||||
filters: {}
|
||||
});
|
||||
}
|
||||
|
||||
async function homeVod() {
|
||||
return await category('live', 1, null, {});
|
||||
}
|
||||
|
||||
async function fetchLiveIndex() {
|
||||
await refreshApiHost();
|
||||
const r = await req(apiHost + '/api/c5/business/livehouse/index', { headers: makeHeaders() });
|
||||
return safeJson(r.content);
|
||||
}
|
||||
|
||||
async function fetchAnchorList(pg) {
|
||||
await refreshApiHost();
|
||||
const r = await req(businessApi + '/anchor/list?page=' + pg + '&size=20', { headers: makeHeaders() });
|
||||
return safeJson(r.content);
|
||||
}
|
||||
|
||||
function liveItemsToVod(items) {
|
||||
return uniqByHouse(items).map(it => ({
|
||||
vod_id: String(it.houseId || it.appNumber || ''),
|
||||
vod_name: titleOf(it),
|
||||
vod_pic: picOf(it),
|
||||
vod_remarks: remarkOf(it)
|
||||
})).filter(it => it.vod_id && it.vod_name);
|
||||
}
|
||||
|
||||
function matchItemsToVod(items) {
|
||||
return (items || []).map(it => {
|
||||
const home = it.homeTeam && it.homeTeam.teamName || '';
|
||||
const away = it.awayTeam && it.awayTeam.teamName || '';
|
||||
const comp = it.competitionName || (it.competition && it.competition.competitionName) || '';
|
||||
const title = [comp, home && away ? `${home} VS ${away}` : ''].filter(Boolean).join(' ');
|
||||
const appoints = it.anchorAppointmentVoList || it.reservedAnchors || [];
|
||||
const houseId = appoints[0] && (appoints[0].houseId || appoints[0].appNumber);
|
||||
return {
|
||||
vod_id: houseId ? String(houseId) : ('match$' + (it.matchId || '')),
|
||||
vod_name: title || ('赛事 ' + (it.matchId || '')),
|
||||
vod_pic: '',
|
||||
vod_remarks: houseId ? '可观看' : '暂无主播'
|
||||
};
|
||||
}).filter(it => it.vod_id && !it.vod_id.endsWith('undefined'));
|
||||
}
|
||||
|
||||
async function category(tid, pg, filter, extend = {}) {
|
||||
tid = tid || 'live';
|
||||
pg = Number(pg || 1);
|
||||
let list = [];
|
||||
let pagecount = 1;
|
||||
|
||||
if (tid === 'match') {
|
||||
await refreshApiHost();
|
||||
const r = await req(apiHost + '/api/c7/business/match/list?pageNum=' + pg + '&pageSize=30', { headers: makeHeaders() });
|
||||
const json = safeJson(r.content);
|
||||
const data = json.data || {};
|
||||
list = matchItemsToVod(data.records || []);
|
||||
pagecount = data.pages || data.totalPage || 1;
|
||||
} else if (tid === 'anchor') {
|
||||
const json = await fetchAnchorList(pg);
|
||||
const data = json.data || {};
|
||||
list = liveItemsToVod(data.records || []);
|
||||
pagecount = data.pages || 1;
|
||||
} else {
|
||||
const json = await fetchLiveIndex();
|
||||
const data = json.data || {};
|
||||
let items = [];
|
||||
if (tid === 'hot') {
|
||||
items = firstArray(data, ['streamingAnchorRanking', 'ongoingLivestreams']);
|
||||
} else {
|
||||
items = []
|
||||
.concat(firstArray(data, ['ongoingLivestreams']))
|
||||
.concat(firstArray(data, ['anchorLivestreams']))
|
||||
.concat(firstArray(data, ['streamingAnchorRanking']));
|
||||
}
|
||||
list = liveItemsToVod(items);
|
||||
}
|
||||
|
||||
return JSON.stringify({ page: pg, pagecount, limit: 20, total: list.length, list });
|
||||
}
|
||||
|
||||
async function detail(id) {
|
||||
if (String(id || '').startsWith('match$')) {
|
||||
return JSON.stringify({ list: [] });
|
||||
}
|
||||
|
||||
await refreshApiHost();
|
||||
const houseId = String(id || '').trim();
|
||||
const r = await req(businessApi + '/anchor/detail?houseId=' + encodeURIComponent(houseId), { headers: makeHeaders() });
|
||||
const json = safeJson(r.content);
|
||||
const it = json.data || {};
|
||||
if (!it.houseId && !houseId) return JSON.stringify({ list: [] });
|
||||
|
||||
const urls = [];
|
||||
const u1 = normalizePlayUrl(it.playStreamAddress2 || it.playStreamAddress);
|
||||
const u2 = normalizePlayUrl(it.playStreamAddress && it.playStreamAddress !== u1 ? it.playStreamAddress : '');
|
||||
const u3 = normalizePlayUrl(it.playStreamAddress3);
|
||||
if (u1) urls.push('高清线路$' + u1);
|
||||
if (u2) urls.push('备用线路$' + u2);
|
||||
if (u3) urls.push('WebRTC$' + u3);
|
||||
|
||||
return JSON.stringify({
|
||||
list: [{
|
||||
vod_id: houseId,
|
||||
vod_name: titleOf(it) || ('直播间 ' + houseId),
|
||||
vod_pic: picOf(it),
|
||||
vod_remarks: Number(it.liveStatus) === 2 ? '直播中' : '直播',
|
||||
vod_play_from: '蜘蛛直播',
|
||||
vod_play_url: urls.join('#'),
|
||||
vod_content: (it.anchorAnnouncement || it.marquee || '蜘蛛直播实时体育直播').replace(/<[^>]+>/g, '')
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
async function search(wd, quick, pg = 1) {
|
||||
return JSON.stringify({ page: pg, list: [] });
|
||||
}
|
||||
|
||||
async function play(flag, id, flags) {
|
||||
return JSON.stringify({ parse: 0, url: id, header: makeHeaders() });
|
||||
}
|
||||
|
||||
export function __jsEvalReturn() {
|
||||
return { init, home, homeVod, category, search, detail, play };
|
||||
}
|
||||
Reference in New Issue
Block a user