Files
tvbox_collect/tianjitop/llllo4k/js/iysdq.js
T
2026-07-17 09:35:49 +00:00

314 lines
9.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* @File : 影视大全.js
* @Author : opencode
* @Date : 2026-07-09
* @Desc : 影视大全 (www.iysdq.tv) TVBox T4(JS) 源 —— 自包含,MacCMS shoutu45 模板
*
* 站点结构:
* - 服务端渲染 MacCMS(shoutu45),首页/分类/搜索/详情 HTML 直出,无防护盾。
* - 分类:/vodtype/{tid}.html
* - 搜索:/vodsearch/{词}-------------.html (关键词在开头,共 13 个 '-'
* - 详情:/voddetail/{id}.html
* 线路 tab: .anthology-tab a.swiper-slide(按 DOM 顺序)
* 集数列表: 并列的多个 .anthology-list-play,按 DOM 顺序与 tab 一一对应
* 集数链接: /vodplay/{id}-{sid}-{nid}.html
* - 播放:播放页 player_aaaa.url 为明文 m3u8/mp4 直链。
* - 卡片:div.public-list-box > a.public-list-exp[href=/voddetail/xx.html][title]
* 封面 img data-src;备注 span.public-list-prb。
*/
var IYSDQ_VERSION = "20260709-js-1";
var HOST = "https://www.iysdq.tv";
var UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
var CLASSES = [
{ type_id: "1", type_name: "电影" },
{ type_id: "2", type_name: "电视剧" },
{ type_id: "3", type_name: "综艺" },
{ type_id: "4", type_name: "动漫" },
{ type_id: "5", type_name: "短剧" }
];
function log(msg) {
try { console.log("[IYSDQ_JS " + IYSDQ_VERSION + "] " + msg); } catch (e) {}
}
/* ---------------- 通用工具 ---------------- */
function toStr(v) { return v === undefined || v === null ? "" : String(v); }
function encode(s) { return encodeURIComponent(toStr(s)); }
function fixUrl(u) {
u = toStr(u).trim();
if (!u) return "";
if (u.indexOf("//") === 0) return "https:" + u;
if (u.charAt(0) === "/") return HOST + u;
return u;
}
function textClean(s) {
return toStr(s)
.replace(/<[^>]+>/g, "")
.replace(/&nbsp;/g, " ")
.replace(/&amp;/g, "&")
.replace(/&quot;/g, '"')
.replace(/&#39;/g, "'")
.replace(/&#\d+;/g, "")
.replace(/\s+/g, " ")
.trim();
}
function attr(tag, name) {
var r = new RegExp(name + "\\s*=\\s*([\"'])([\\s\\S]*?)\\1", "i");
var m = r.exec(tag || "");
return m ? m[2] : "";
}
function requestHtml(url) {
try {
log("fetch " + url);
var res = req(url, {
method: "GET",
headers: { "User-Agent": UA, "Referer": HOST + "/", "Accept": "text/html" },
timeout: 10000
});
var body = (typeof res === "string") ? res : (res && (res.content || res.body || res.data)) || "";
return toStr(body);
} catch (e) {
log("fetch_error " + e);
return "";
}
}
/* ---------------- 封面提取 ---------------- */
function pickPic(tag) {
var p = attr(tag, "data-src") || attr(tag, "data-original");
if (!p || /img-bj-k\.png/i.test(p)) {
var m = /<img[^>]+data-src="([^"]+)"/i.exec(tag);
if (m) p = m[1];
}
return fixUrl(p);
}
/* ---------------- 列表解析 ---------------- */
// 首页/分类/搜索卡片:div.public-list-box
function parseList(html) {
var list = [];
var seen = {};
// 每个卡片块:从 public-list-box 起,到下一个 public-list-box 或结束
var re = /<div class="public-list-box[^"]*">([\s\S]*?)(?=<div class="public-list-box|<div class="null|<\/body|$)/g;
var m;
while ((m = re.exec(html)) !== null) {
var block = m[1];
var im = /href="\/voddetail\/(\d+)\.html"/.exec(block);
if (!im) continue;
var id = im[1];
if (seen[id]) continue;
seen[id] = true;
// 标题:优先 a.public-list-exp 的 title
var name = "";
var tm = /class="public-list-exp"[^>]*title="([^"]*)"/.exec(block);
if (tm) name = textClean(tm[1]);
if (!name) {
var tm2 = /class="time-title[^"]*"[^>]*title="([^"]*)"/.exec(block);
if (tm2) name = textClean(tm2[1]);
}
if (!name) {
var am = /alt="([^"]+?)封面图"/.exec(block) || /alt="([^"]+)"/.exec(block);
if (am) name = textClean(am[1]);
}
var note = "";
var nm = /class="public-list-prb[^"]*"[^>]*>([\s\S]*?)<\/span>/.exec(block);
if (nm) note = textClean(nm[1]);
list.push({ vod_id: id, vod_name: name, vod_pic: pickPic(block), vod_remarks: note });
}
return list;
}
/* ---------------- 接口实现 ---------------- */
function init(ext) {
if (typeof ext === "string" && /^https?:\/\//.test(ext.trim())) {
HOST = ext.trim().replace(/\/+$/, "");
}
log("init host=" + HOST);
}
function home(filter) {
log("home");
return JSON.stringify({ class: CLASSES });
}
function homeVod() {
log("homeVod");
var html = requestHtml(HOST + "/");
var list = parseList(html).slice(0, 40);
return JSON.stringify({ list: list });
}
function category(tid, pg, filter, extend) {
tid = toStr(tid || "1");
pg = parseInt(pg || 1);
if (!pg || pg < 1) pg = 1;
// 站点分类页无分页参数,首页即全量;仅第 1 页返回数据
if (pg > 1) return JSON.stringify({ page: pg, pagecount: pg, limit: 40, total: 0, list: [] });
var url = HOST + "/vodtype/" + tid + ".html";
var html = requestHtml(url);
var list = parseList(html);
log("category tid=" + tid + " count=" + list.length);
return JSON.stringify({
page: 1,
pagecount: 1,
limit: list.length || 40,
total: list.length,
list: list
});
}
function detail(id) {
var vid = toStr(id).split(",")[0].replace(/[^\d]/g, "");
log("detail id=" + vid);
var html = requestHtml(HOST + "/voddetail/" + vid + ".html");
if (!html) return JSON.stringify({ list: [] });
// 标题
var name = "";
var nm = /<h1[^>]*>([\s\S]*?)<\/h1>/.exec(html);
if (nm) name = textClean(nm[1]);
if (!name) {
var tt = /<title>([^<_\-]+)/.exec(html);
if (tt) name = tt[1].trim();
}
// 封面
var pic = "";
var pm = /property="og:image"\s+content="([^"]+)"/.exec(html);
if (pm) pic = pm[1];
if (!pic) {
var pm2 = /<img[^>]*class="[^"]*lazy[^"]*"[^>]*data-src="([^"]+)"/.exec(html);
if (pm2) pic = pm2[1];
}
var vod = {
vod_id: vid,
vod_name: name,
vod_pic: fixUrl(pic)
};
// 线路名(.anthology-tab 内的 a.swiper-slide,按 DOM 顺序)
var froms = [];
var tabStart = html.indexOf('anthology-tab');
var tabBlock = "";
if (tabStart >= 0) {
var tabEnd = html.indexOf('anthology-list', tabStart);
tabBlock = html.substring(tabStart, tabEnd > tabStart ? tabEnd : tabStart + 3000);
}
var fRe = /class="swiper-slide"[^>]*>([\s\S]*?)<\/a>/g;
var fm;
while ((fm = fRe.exec(tabBlock)) !== null) {
var fn = textClean(fm[1]).replace(/\d+$/, "").trim();
if (fn) froms.push(fn);
}
// 集数 panel:并列的 .anthology-list-play
var playFrom = [];
var playUrl = [];
var panelRe = /class="anthology-list-play[^"]*"[^>]*>([\s\S]*?)<\/ul>/g;
var pm3;
var idx = 0;
while ((pm3 = panelRe.exec(html)) !== null) {
var block = pm3[1];
var eps = [];
var epRe = /<a[^>]*href="(\/vodplay\/[^"]+\.html)"[^>]*>([\s\S]*?)<\/a>/g;
var em;
while ((em = epRe.exec(block)) !== null) {
var epUrl = em[1];
var epName = textClean(em[2]) || (eps.length + 1);
eps.push(epName + "$" + epUrl);
}
if (eps.length) {
playFrom.push(froms[idx] || ("线路" + (idx + 1)));
playUrl.push(eps.join("#"));
}
idx++;
}
if (playFrom.length) {
vod.vod_play_from = playFrom.join("$$$");
vod.vod_play_url = playUrl.join("$$$");
} else {
vod.vod_play_from = "提示";
vod.vod_play_url = "暂无播放源$";
}
return JSON.stringify({ list: [vod] });
}
function play(flag, id, flags) {
var pageUrl = fixUrl(id);
log("play flag=" + flag + " url=" + pageUrl);
var html = requestHtml(pageUrl);
var url = "";
// player_aaaa = {...,"url":"https://...m3u8",...}
var m = /player_\w+\s*=\s*(\{[\s\S]*?\})\s*<\/script>/.exec(html);
if (m) {
try {
var info = JSON.parse(m[1]);
url = info.url || "";
} catch (e) {
log("player parse error " + e);
}
}
// 兜底:直接搜 url 字段 / m3u8 / mp4
if (!url) {
var m2 = /"url"\s*:\s*"(https?:[^"]+?\.(?:m3u8|mp4)[^"]*)"/.exec(html);
if (m2) url = m2[1];
}
if (!url) {
var m3 = html.match(/https?:\/\/[^"'\s\\]+?\.m3u8[^"'\s\\]*/);
if (m3) url = m3[0];
}
if (!url) {
var m4 = html.match(/https?:\/\/[^"'\s\\]+?\.mp4[^"'\s\\]*/);
if (m4) url = m4[0];
}
url = toStr(url).replace(/\\\//g, "/").trim();
if (url && /^https?:\/\//.test(url)) {
var header = { "User-Agent": UA, "Referer": HOST + "/" };
return JSON.stringify({ parse: 0, url: url, header: header });
}
return JSON.stringify({ parse: 1, url: pageUrl });
}
function search(wd, quick, pg) {
pg = parseInt(pg || 1);
if (!pg || pg < 1) pg = 1;
if (pg > 1) return JSON.stringify({ list: [], page: pg, pagecount: pg });
log("search wd=" + wd);
// 关键词在开头,后接 13 个 '-'
var url = HOST + "/vodsearch/" + encode(wd) + "-------------.html";
var html = requestHtml(url);
var list = parseList(html);
return JSON.stringify({ list: list, page: 1, pagecount: 1, limit: list.length, total: list.length });
}
/* ---------------- 导出 ---------------- */
__JS_SPIDER__ = {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search
};