Sync all projects
This commit is contained in:
+1068
@@ -0,0 +1,1068 @@
|
||||
import { Crypto, _ } from 'assets://js/lib/cat.js'
|
||||
|
||||
let host = '';
|
||||
let header = {
|
||||
'User-Agent': 'okhttp/3.12.11'
|
||||
};
|
||||
let siteKey = '';
|
||||
let siteType = '';
|
||||
let siteJx = '';
|
||||
|
||||
const urlPattern1 = /api\.php\/.*?\/vod/;
|
||||
const urlPattern2 = /api\.php\/.+?\.vod/;
|
||||
const parsePattern = /\/.+\\?.+=/;
|
||||
const parsePattern1 = /.*(url|v|vid|php\?id)=/;
|
||||
const parsePattern2 = /https?:\/\/[^\/]*/;
|
||||
|
||||
const htmlVideoKeyMatch = [
|
||||
/player=new/,
|
||||
/<div id="video"/,
|
||||
/<div id="[^"]*?player"/,
|
||||
/\/\/视频链接/,
|
||||
/HlsJsPlayer\(/,
|
||||
/<iframe[\s\S]*?src="[^"]+?"/,
|
||||
/<video[\s\S]*?src="[^"]+?"/,
|
||||
];
|
||||
|
||||
const parseUrlMap = new Map();
|
||||
|
||||
async function init(cfg) {
|
||||
siteKey = cfg.skey;
|
||||
siteType = cfg.stype;
|
||||
host = cfg.ext;
|
||||
if (cfg.ext.hasOwnProperty('host')) {
|
||||
host = cfg.ext.host;
|
||||
siteJx = cfg.ext;
|
||||
}
|
||||
};
|
||||
|
||||
async function request(reqUrl, ua, timeout = 60000) {
|
||||
let res = await req(reqUrl, {
|
||||
method: 'get',
|
||||
headers: ua ? ua : {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36'},
|
||||
timeout: timeout,
|
||||
});
|
||||
return res.content;
|
||||
}
|
||||
|
||||
async function home(filter) {
|
||||
try {
|
||||
// 苹果CMS V10模式检测
|
||||
if (host.includes('/vod') || host.includes('/provide/vod')) {
|
||||
const url = host;
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
const result = { class: [] };
|
||||
|
||||
if (obj.class && Array.isArray(obj.class)) {
|
||||
for (const item of obj.class) {
|
||||
const typeName = item.type_name;
|
||||
if (isBan(typeName)) continue;
|
||||
result.class.push({
|
||||
type_id: item.type_id,
|
||||
type_name: typeName
|
||||
});
|
||||
}
|
||||
}
|
||||
return JSON.stringify(result);
|
||||
} else {
|
||||
// 原有AppYsV2模式
|
||||
let url = getCateUrl(host);
|
||||
let jsonArray = null;
|
||||
|
||||
if (url) {
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
|
||||
if (obj.hasOwnProperty("class") && Array.isArray(obj.class)) {
|
||||
jsonArray = obj.class;
|
||||
} else if (obj.hasOwnProperty("list") && Array.isArray(obj.list)) {
|
||||
jsonArray = obj.list;
|
||||
} else if (obj.hasOwnProperty("data") && obj.data.hasOwnProperty("list") && Array.isArray(obj.data.list)) {
|
||||
jsonArray = obj.data.list;
|
||||
} else if (obj.hasOwnProperty("data") && Array.isArray(obj.data)) {
|
||||
jsonArray = obj.data;
|
||||
}
|
||||
} else {
|
||||
const filterStr = getFilterTypes(url, null);
|
||||
const classes = filterStr.split("\n")[0].split("+");
|
||||
jsonArray = [];
|
||||
for (let i = 1; i < classes.length; i++) {
|
||||
const kv = classes[i].trim().split("=");
|
||||
if (kv.length < 2) continue;
|
||||
const newCls = {
|
||||
type_name: kv[0].trim(),
|
||||
type_id: kv[1].trim(),
|
||||
};
|
||||
jsonArray.push(newCls);
|
||||
}
|
||||
}
|
||||
|
||||
const result = { class: [] };
|
||||
if (jsonArray != null) {
|
||||
for (let i = 0; i < jsonArray.length; i++) {
|
||||
const jObj = jsonArray[i];
|
||||
const typeName = jObj.type_name;
|
||||
if (isBan(typeName)) continue;
|
||||
const typeId = jObj.type_id;
|
||||
const newCls = {
|
||||
type_id: typeId,
|
||||
type_name: (typeName || "").replace(/奇迹云|-加q群[::]?\s*\d+\s*获取更多免费资源/g, ''),
|
||||
};
|
||||
const typeExtend = jObj.type_extend;
|
||||
if (filter) {
|
||||
const filterStr = getFilterTypes(url, typeExtend);
|
||||
|
||||
const filters = filterStr.split("\n");
|
||||
const filterArr = [];
|
||||
for (let k = (url) ? 1 : 0; k < filters.length; k++) {
|
||||
const l = filters[k].trim();
|
||||
if (!l) continue;
|
||||
const oneLine = l.split("+");
|
||||
|
||||
let type = oneLine[0].trim();
|
||||
let typeN = type;
|
||||
if (type.includes("筛选")) {
|
||||
type = type.replace(/筛选/g, "");
|
||||
if (type === "class") typeN = "类型";
|
||||
else if (type === "area") typeN = "地区";
|
||||
else if (type === "lang") typeN = "语言";
|
||||
else if (type === "year") typeN = "年份";
|
||||
}
|
||||
const jOne = {
|
||||
key: type,
|
||||
name: typeN,
|
||||
value: [],
|
||||
};
|
||||
for (let j = 1; j < oneLine.length; j++) {
|
||||
const kv = oneLine[j].trim();
|
||||
const sp = kv.indexOf("=");
|
||||
|
||||
if (sp === -1) {
|
||||
if (isBan(kv)) continue;
|
||||
jOne.value.push({ n: kv, v: kv });
|
||||
} else {
|
||||
const n = kv.substring(0, sp);
|
||||
if (isBan(n)) continue;
|
||||
jOne.value.push({
|
||||
n: n.trim(),
|
||||
v: kv.substring(sp + 1).trim(),
|
||||
});
|
||||
}
|
||||
}
|
||||
filterArr.push(jOne);
|
||||
}
|
||||
if (!result.hasOwnProperty("filters")) {
|
||||
result.filters = {};
|
||||
}
|
||||
result.filters[typeId] = filterArr;
|
||||
}
|
||||
result.class.push(newCls);
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
} catch (e) {
|
||||
SpiderDebug.log("分类接口错误:" + e);
|
||||
}
|
||||
return JSON.stringify({ class: [] });
|
||||
}
|
||||
|
||||
async function homeVod() {
|
||||
try {
|
||||
// 苹果CMS V10模式检测
|
||||
if (host.includes('/vod') || host.includes('/provide/vod')) {
|
||||
const url = `${host}?ac=videolist&t=1&pg=1`;
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
const videos = [];
|
||||
|
||||
if (obj.list && Array.isArray(obj.list)) {
|
||||
for (const item of obj.list) {
|
||||
videos.push({
|
||||
vod_id: item.vod_id,
|
||||
vod_name: (item.vod_name || "").replace(/奇迹云/g, ''),
|
||||
vod_pic: item.vod_pic || "",
|
||||
vod_remarks: (item.vod_remarks || "").replace(/奇迹云/g, '')
|
||||
});
|
||||
}
|
||||
}
|
||||
return JSON.stringify({ list: videos });
|
||||
} else {
|
||||
// 原有AppYsV2模式
|
||||
const apiUrl = host;
|
||||
let url = getRecommendUrl(apiUrl);
|
||||
let isTV = false;
|
||||
|
||||
if (!url) {
|
||||
url = getCateFilterUrlPrefix(apiUrl) + "movie&page=1&area=&type=&start=";
|
||||
isTV = true;
|
||||
}
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
const videos = [];
|
||||
if (isTV) {
|
||||
const jsonArray = obj.data;
|
||||
for (let i = 0; i < jsonArray.length; i++) {
|
||||
const vObj = jsonArray[i];
|
||||
const v = {
|
||||
vod_id: vObj.nextlink,
|
||||
vod_name: (vObj.title || "").replace(/奇迹云/g, ''),
|
||||
vod_pic: vObj.pic,
|
||||
vod_remarks: (vObj.state || "").replace(/奇迹云/g, ''),
|
||||
};
|
||||
videos.push(v);
|
||||
}
|
||||
} else {
|
||||
const arrays = [];
|
||||
findJsonArray(obj, "vlist", arrays);
|
||||
if (arrays.length === 0) {
|
||||
findJsonArray(obj, "vod_list", arrays);
|
||||
}
|
||||
const ids = [];
|
||||
for (const jsonArray of arrays) {
|
||||
for (let i = 0; i < jsonArray.length; i++) {
|
||||
const vObj = jsonArray[i];
|
||||
const vid = vObj.vod_id;
|
||||
if (ids.includes(vid)) continue;
|
||||
ids.push(vid);
|
||||
const v = {
|
||||
vod_id: vid,
|
||||
vod_name: (vObj.vod_name || "").replace(/奇迹云/g, ''),
|
||||
vod_pic: vObj.vod_pic,
|
||||
vod_remarks: (vObj.vod_remarks || "").replace(/奇迹云/g, ''),
|
||||
};
|
||||
videos.push(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = {
|
||||
list: videos,
|
||||
};
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
} catch (e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
async function category(tid, pg, filter, extend) {
|
||||
try {
|
||||
// 苹果CMS V10模式检测
|
||||
if (host.includes('/vod') || host.includes('/provide/vod')) {
|
||||
const url = `${host}?ac=videolist&t=${tid}&pg=${pg}`;
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
const videos = [];
|
||||
|
||||
if (obj.list && Array.isArray(obj.list)) {
|
||||
for (const item of obj.list) {
|
||||
videos.push({
|
||||
vod_id: item.vod_id,
|
||||
vod_name: (item.vod_name || "").replace(/奇迹云/g, ''),
|
||||
vod_pic: item.vod_pic || "",
|
||||
vod_remarks: (item.vod_remarks || "").replace(/奇迹云/g, '')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
page: pg,
|
||||
pagecount: obj.pagecount || 1,
|
||||
limit: obj.limit || 20,
|
||||
total: obj.total || 0,
|
||||
list: videos
|
||||
});
|
||||
} else {
|
||||
// 原有AppYsV2模式
|
||||
const apiUrl = host;
|
||||
let url = getCateFilterUrlPrefix(apiUrl) + tid + getCateFilterUrlSuffix(apiUrl);
|
||||
url = url.replace(/#PN#/g, pg);
|
||||
url = url.replace(/筛选class/g, extend?.class ?? "");
|
||||
url = url.replace(/筛选area/g, extend?.area ?? "");
|
||||
url = url.replace(/筛选lang/g, extend?.lang ?? "");
|
||||
url = url.replace(/筛选year/g, extend?.year ?? "");
|
||||
url = url.replace(/排序/g, extend?.排序 ?? "");
|
||||
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
|
||||
let totalPg = Infinity;
|
||||
try {
|
||||
if (obj.totalpage !== undefined && typeof obj.totalpage === "number") {
|
||||
totalPg = obj.totalpage;
|
||||
} else if (
|
||||
obj.pagecount !== undefined &&
|
||||
typeof obj.pagecount === "number"
|
||||
) {
|
||||
totalPg = obj.pagecount;
|
||||
} else if (
|
||||
obj.data !== undefined &&
|
||||
typeof obj.data === "object" &&
|
||||
obj.data.total !== undefined &&
|
||||
typeof obj.data.total === "number" &&
|
||||
obj.data.limit !== undefined &&
|
||||
typeof obj.data.limit === "number"
|
||||
) {
|
||||
const limit = obj.data.limit;
|
||||
const total = obj.data.total;
|
||||
totalPg = total % limit === 0 ? total / limit : Math.floor(total / limit) + 1;
|
||||
}
|
||||
} catch (e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
|
||||
const jsonArray =
|
||||
obj.list !== undefined
|
||||
? obj.list
|
||||
: obj.data !== undefined && obj.data.list !== undefined
|
||||
? obj.data.list
|
||||
: obj.data;
|
||||
const videos = [];
|
||||
|
||||
if (jsonArray !== undefined) {
|
||||
for (let i = 0; i < jsonArray.length; i++) {
|
||||
const vObj = jsonArray[i];
|
||||
const v = {
|
||||
vod_id: vObj.vod_id !== undefined ? vObj.vod_id : vObj.nextlink,
|
||||
vod_name: ((vObj.vod_name !== undefined ? vObj.vod_name : vObj.title) || "").replace(/奇迹云/g, ''),
|
||||
vod_pic: vObj.vod_pic !== undefined ? vObj.vod_pic : vObj.pic,
|
||||
vod_remarks: ((vObj.vod_remarks !== undefined ? vObj.vod_remarks : vObj.state) || "").replace(/奇迹云/g, ''),
|
||||
};
|
||||
videos.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
const result = {
|
||||
page: pg,
|
||||
pagecount: totalPg,
|
||||
limit: 90,
|
||||
total: Infinity,
|
||||
list: videos,
|
||||
};
|
||||
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
} catch (e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 辅助函数:只替换文字,不改变分隔符和结构
|
||||
function replacePlayUrlText(playUrl) {
|
||||
if (!playUrl) return playUrl;
|
||||
// 使用正则匹配 $$$ 或 # 作为分隔符,但保留原始分隔符不变
|
||||
// 匹配模式:任意内容后跟 $$$ 或 #,或者末尾
|
||||
let result = '';
|
||||
let i = 0;
|
||||
while (i < playUrl.length) {
|
||||
// 查找 $$$ 或 # 的位置
|
||||
let found = -1;
|
||||
let sep = '';
|
||||
let dollarPos = playUrl.indexOf('$$$', i);
|
||||
let hashPos = playUrl.indexOf('#', i);
|
||||
|
||||
if (dollarPos !== -1 && (hashPos === -1 || dollarPos < hashPos)) {
|
||||
found = dollarPos;
|
||||
sep = '$$$';
|
||||
} else if (hashPos !== -1) {
|
||||
found = hashPos;
|
||||
sep = '#';
|
||||
}
|
||||
|
||||
if (found !== -1) {
|
||||
let segment = playUrl.substring(i, found);
|
||||
// 替换 segment 中 $ 前面的集数名称里的文字
|
||||
let dollarInSegment = segment.indexOf('$');
|
||||
if (dollarInSegment > 0) {
|
||||
let episodeName = segment.substring(0, dollarInSegment);
|
||||
let urlPart = segment.substring(dollarInSegment);
|
||||
episodeName = episodeName.replace(/奇迹云/g, '');
|
||||
result += episodeName + urlPart;
|
||||
} else {
|
||||
result += segment.replace(/奇迹云/g, '');
|
||||
}
|
||||
result += sep;
|
||||
i = found + sep.length;
|
||||
} else {
|
||||
// 最后一段
|
||||
let segment = playUrl.substring(i);
|
||||
let dollarInSegment = segment.indexOf('$');
|
||||
if (dollarInSegment > 0) {
|
||||
let episodeName = segment.substring(0, dollarInSegment);
|
||||
let urlPart = segment.substring(dollarInSegment);
|
||||
episodeName = episodeName.replace(/奇迹云/g, '');
|
||||
result += episodeName + urlPart;
|
||||
} else {
|
||||
result += segment.replace(/奇迹云/g, '');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function detail(ids) {
|
||||
try {
|
||||
// 苹果CMS V10模式检测
|
||||
if (host.includes('/vod') || host.includes('/provide/vod')) {
|
||||
const url = `${host}?ac=detail&ids=${ids}`;
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
const result = { list: [] };
|
||||
const vod = {};
|
||||
|
||||
const data = obj.list && obj.list[0] ? obj.list[0] : {};
|
||||
vod.vod_id = data.vod_id || ids;
|
||||
vod.vod_name = (data.vod_name || "").replace(/奇迹云/g, '');
|
||||
vod.vod_pic = data.vod_pic || "";
|
||||
vod.type_name = (data.type_name || "").replace(/奇迹云/g, '');
|
||||
vod.vod_year = (data.vod_year || "").replace(/奇迹云/g, '');
|
||||
vod.vod_area = (data.vod_area || "").replace(/奇迹云/g, '');
|
||||
vod.vod_remarks = (data.vod_remarks || "").replace(/奇迹云/g, '');
|
||||
vod.vod_actor = (data.vod_actor || "").replace(/奇迹云/g, '');
|
||||
vod.vod_director = (data.vod_director || "").replace(/奇迹云/g, '');
|
||||
vod.vod_content = (data.vod_content || "").replace(/奇迹云/g, '');
|
||||
|
||||
// 处理线路名称
|
||||
let playFrom = data.vod_play_from || "";
|
||||
if (playFrom) {
|
||||
let lines = playFrom.split('$$$');
|
||||
let newLines = [];
|
||||
for (let line of lines) {
|
||||
if (line && line.toLowerCase().includes('qijiyun4k')) {
|
||||
newLines.push('奇迹云4k');
|
||||
} else {
|
||||
newLines.push((line || "").replace(/奇迹云/g, ''));
|
||||
}
|
||||
}
|
||||
vod.vod_play_from = newLines.join('$$$');
|
||||
} else {
|
||||
vod.vod_play_from = "";
|
||||
}
|
||||
|
||||
// 处理选集:只替换文字,保留原始分隔符和结构
|
||||
vod.vod_play_url = replacePlayUrlText(data.vod_play_url || "");
|
||||
|
||||
result.list.push(vod);
|
||||
return JSON.stringify(result);
|
||||
} else {
|
||||
// 原有AppYsV2模式
|
||||
const apiUrl = host;
|
||||
const url = getPlayUrlPrefix(apiUrl) + ids;
|
||||
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
const result = {
|
||||
list: [],
|
||||
};
|
||||
const vod = {};
|
||||
genPlayList(apiUrl, obj, json, vod, ids);
|
||||
|
||||
// 替换详情中的所有文字
|
||||
if (vod.vod_name) vod.vod_name = vod.vod_name.replace(/奇迹云/g, '');
|
||||
if (vod.type_name) vod.type_name = vod.type_name.replace(/奇迹云/g, '');
|
||||
if (vod.vod_year) vod.vod_year = vod.vod_year.replace(/奇迹云/g, '');
|
||||
if (vod.vod_area) vod.vod_area = vod.vod_area.replace(/奇迹云/g, '');
|
||||
if (vod.vod_remarks) vod.vod_remarks = vod.vod_remarks.replace(/奇迹云/g, '');
|
||||
if (vod.vod_actor) vod.vod_actor = vod.vod_actor.replace(/奇迹云/g, '');
|
||||
if (vod.vod_director) vod.vod_director = vod.vod_director.replace(/奇迹云/g, '');
|
||||
if (vod.vod_content) vod.vod_content = vod.vod_content.replace(/奇迹云/g, '');
|
||||
|
||||
// 替换线路名称
|
||||
if (vod.vod_play_from) {
|
||||
let lines = vod.vod_play_from.split('$$$');
|
||||
let newLines = [];
|
||||
for (let line of lines) {
|
||||
if (line && line.toLowerCase().includes('qijiyun4k')) {
|
||||
newLines.push('奇迹云4k');
|
||||
} else {
|
||||
newLines.push((line || "").replace(/奇迹云/g, ''));
|
||||
}
|
||||
}
|
||||
vod.vod_play_from = newLines.join('$$$');
|
||||
}
|
||||
|
||||
// 处理选集:只替换文字,保留原始分隔符和结构
|
||||
vod.vod_play_url = replacePlayUrlText(vod.vod_play_url || "");
|
||||
|
||||
result.list.push(vod);
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
} catch (e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
async function play(flag, id, vipFlags) {
|
||||
try {
|
||||
let parseUrls = siteJx[flag];
|
||||
if (!parseUrls) {
|
||||
if (siteJx.hasOwnProperty('*')) {
|
||||
parseUrls = siteJx['*'];
|
||||
} else {
|
||||
parseUrls = [];
|
||||
}
|
||||
}
|
||||
|
||||
if (parseUrls.length > 0) {
|
||||
const result = await getFinalVideo(flag, parseUrls, id);
|
||||
if (result !== null) {
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (isVideoFormat(id)) {
|
||||
const result = {
|
||||
parse: 0,
|
||||
playUrl: "",
|
||||
url: id
|
||||
};
|
||||
return JSON.stringify(result);
|
||||
} else {
|
||||
const result = {
|
||||
parse: 1,
|
||||
jx: "1",
|
||||
url: id
|
||||
};
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
} catch (e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
async function search(key, quick) {
|
||||
try {
|
||||
// 苹果CMS V10模式检测
|
||||
if (host.includes('/vod') || host.includes('/provide/vod')) {
|
||||
const url = `${host}?ac=videolist&wd=${encodeURIComponent(key)}&pg=1`;
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
const videos = [];
|
||||
|
||||
if (obj.list && Array.isArray(obj.list)) {
|
||||
for (const item of obj.list) {
|
||||
videos.push({
|
||||
vod_id: item.vod_id,
|
||||
vod_name: (item.vod_name || "").replace(/奇迹云/g, ''),
|
||||
vod_pic: item.vod_pic || "",
|
||||
vod_remarks: (item.vod_remarks || "").replace(/奇迹云/g, '')
|
||||
});
|
||||
}
|
||||
}
|
||||
return JSON.stringify({ list: videos });
|
||||
} else {
|
||||
// 原有AppYsV2模式
|
||||
const apiUrl = host;
|
||||
const url = getSearchUrl(apiUrl, encodeURIComponent(key));
|
||||
const json = await request(url, getHeaders(url));
|
||||
const obj = JSON.parse(json);
|
||||
let jsonArray = null;
|
||||
const videos = [];
|
||||
|
||||
if (obj.list instanceof Array) {
|
||||
jsonArray = obj.list;
|
||||
} else if (obj.data instanceof Object && obj.data.list instanceof Array) {
|
||||
jsonArray = obj.data.list;
|
||||
} else if (obj.data instanceof Array) {
|
||||
jsonArray = obj.data;
|
||||
}
|
||||
|
||||
if (jsonArray !== null) {
|
||||
for (const vObj of jsonArray) {
|
||||
if (vObj.vod_id) {
|
||||
const v = {
|
||||
vod_id: vObj.vod_id,
|
||||
vod_name: (vObj.vod_name || "").replace(/奇迹云/g, ''),
|
||||
vod_pic: vObj.vod_pic,
|
||||
vod_remarks: (vObj.vod_remarks || "").replace(/奇迹云/g, '')
|
||||
};
|
||||
videos.push(v);
|
||||
} else {
|
||||
const v = {
|
||||
vod_id: vObj.nextlink,
|
||||
vod_name: (vObj.title || "").replace(/奇迹云/g, ''),
|
||||
vod_pic: vObj.pic,
|
||||
vod_remarks: (vObj.state || "").replace(/奇迹云/g, '')
|
||||
};
|
||||
videos.push(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = { list: videos };
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
} catch (error) {
|
||||
SpiderDebug.log(error);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
async function getFinalVideo(flag, parseUrls, url) {
|
||||
let htmlPlayUrl = "";
|
||||
for (const parseUrl of parseUrls) {
|
||||
if (parseUrl === "" || parseUrl === "null") {
|
||||
continue;
|
||||
}
|
||||
const playUrl = parseUrl + url;
|
||||
const content = await request(playUrl, null, 10000);
|
||||
let tryJson = null;
|
||||
try {
|
||||
tryJson = jsonParse(url, content);
|
||||
} catch (error) { }
|
||||
|
||||
if (tryJson !== null && tryJson.hasOwnProperty("url") && tryJson.hasOwnProperty("header")) {
|
||||
tryJson.header = JSON.stringify(tryJson.header);
|
||||
return tryJson;
|
||||
}
|
||||
|
||||
if (content.includes("<html")) {
|
||||
let sniffer = false;
|
||||
for (const p of htmlVideoKeyMatch) {
|
||||
if (p.test(content)) {
|
||||
sniffer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sniffer) {
|
||||
htmlPlayUrl = parseUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (htmlPlayUrl !== "") {
|
||||
const result = {
|
||||
parse: 0,
|
||||
playUrl: "",
|
||||
url: url
|
||||
};
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function genPlayList(URL, object, json, vod, vid) {
|
||||
const playUrls = [];
|
||||
const playFlags = [];
|
||||
|
||||
// 苹果CMS V10模式
|
||||
if (URL.includes('/vod') || URL.includes('/provide/vod')) {
|
||||
const data = object.list && object.list[0] ? object.list[0] : {};
|
||||
vod.vod_id = data.vod_id || vid;
|
||||
vod.vod_name = data.vod_name || "";
|
||||
vod.vod_pic = data.vod_pic || "";
|
||||
vod.type_name = data.type_name || "";
|
||||
vod.vod_year = data.vod_year || "";
|
||||
vod.vod_area = data.vod_area || "";
|
||||
vod.vod_remarks = data.vod_remarks || "";
|
||||
vod.vod_actor = data.vod_actor || "";
|
||||
vod.vod_director = data.vod_director || "";
|
||||
vod.vod_content = data.vod_content || "";
|
||||
|
||||
vod.vod_play_from = data.vod_play_from || "";
|
||||
vod.vod_play_url = data.vod_play_url || "";
|
||||
return;
|
||||
}
|
||||
|
||||
// AppYsV2模式
|
||||
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
|
||||
const data = object.data || {};
|
||||
vod.vod_id = data.vod_id || vid;
|
||||
vod.vod_name = data.vod_name || "";
|
||||
vod.vod_pic = data.vod_pic || "";
|
||||
vod.type_name = data.vod_class || "";
|
||||
vod.vod_year = data.vod_year || "";
|
||||
vod.vod_area = data.vod_area || "";
|
||||
vod.vod_remarks = data.vod_remarks || "";
|
||||
vod.vod_actor = data.vod_actor || "";
|
||||
vod.vod_director = data.vod_director || "";
|
||||
vod.vod_content = data.vod_content || "";
|
||||
|
||||
// 处理播放源
|
||||
if (data.vod_url_with_player && Array.isArray(data.vod_url_with_player)) {
|
||||
for (const from of data.vod_url_with_player) {
|
||||
let flag = from.code?.trim() || from.name?.trim() || "";
|
||||
if (!flag) continue;
|
||||
|
||||
playFlags.push(flag);
|
||||
playUrls.push(from.url || "");
|
||||
|
||||
// 处理解析地址
|
||||
if (from.parse_api) {
|
||||
const parseUrls = parseUrlMap.get(flag) || [];
|
||||
if (!parseUrls.includes(from.parse_api)) {
|
||||
parseUrls.push(from.parse_api);
|
||||
}
|
||||
parseUrlMap.set(flag, parseUrls);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (URL.includes(".vod")) {
|
||||
const data = object.data || {};
|
||||
vod.vod_id = data.vod_id || vid;
|
||||
vod.vod_name = data.vod_name || "";
|
||||
vod.vod_pic = data.vod_pic || "";
|
||||
vod.type_name = data.vod_class || "";
|
||||
vod.vod_year = data.vod_year || "";
|
||||
vod.vod_area = data.vod_area || "";
|
||||
vod.vod_remarks = data.vod_remarks || "";
|
||||
vod.vod_actor = data.vod_actor || "";
|
||||
vod.vod_director = data.vod_director || "";
|
||||
vod.vod_content = data.vod_content || "";
|
||||
|
||||
if (data.vod_play_list && Array.isArray(data.vod_play_list)) {
|
||||
for (const from of data.vod_play_list) {
|
||||
let flag = from.player_info?.from?.trim() || from.player_info?.show?.trim() || "";
|
||||
if (!flag) continue;
|
||||
|
||||
playFlags.push(flag);
|
||||
playUrls.push(from.url || "");
|
||||
|
||||
// 处理解析地址
|
||||
try {
|
||||
const parseUrls = parseUrlMap.get(flag) || [];
|
||||
if (from.player_info?.parse) {
|
||||
const parse1 = from.player_info.parse.split(",");
|
||||
parse1.forEach(purl => {
|
||||
if (purl && !parseUrls.includes(purl)) {
|
||||
parseUrls.push(purl);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (from.player_info?.parse2) {
|
||||
const parse2 = from.player_info.parse2.split(",");
|
||||
parse2.forEach(purl => {
|
||||
if (purl && !parseUrls.includes(purl)) {
|
||||
parseUrls.push(purl);
|
||||
}
|
||||
});
|
||||
}
|
||||
parseUrlMap.set(flag, parseUrls);
|
||||
} catch (e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (urlPattern1.test(URL)) {
|
||||
const data = object.list && object.list[0] ? object.list[0] : {};
|
||||
vod.vod_id = data.vod_id || vid;
|
||||
vod.vod_name = data.vod_name || "";
|
||||
vod.vod_pic = data.vod_pic || "";
|
||||
vod.type_name = data.type_name || "";
|
||||
vod.vod_year = data.vod_year || "";
|
||||
vod.vod_area = data.vod_area || "";
|
||||
vod.vod_remarks = data.vod_remarks || "";
|
||||
vod.vod_actor = data.vod_actor || "";
|
||||
vod.vod_director = data.vod_director || "";
|
||||
vod.vod_content = data.vod_content || "";
|
||||
|
||||
vod.vod_play_from = data.vod_play_from || "";
|
||||
vod.vod_play_url = data.vod_play_url || "";
|
||||
}
|
||||
|
||||
// 合并播放源
|
||||
if (playFlags.length > 0 && playUrls.length > 0) {
|
||||
vod.vod_play_from = playFlags.join("$$$");
|
||||
vod.vod_play_url = playUrls.join("$$$");
|
||||
}
|
||||
}
|
||||
|
||||
function jsonParse(input, json) {
|
||||
try {
|
||||
let jsonPlayData = JSON.parse(json);
|
||||
if (jsonPlayData.hasOwnProperty("data") && typeof jsonPlayData.data === "object" && !jsonPlayData.hasOwnProperty("url")) {
|
||||
jsonPlayData = jsonPlayData.data;
|
||||
}
|
||||
|
||||
let url = jsonPlayData.url;
|
||||
|
||||
if (url.startsWith("//")) {
|
||||
url = "https:" + url;
|
||||
}
|
||||
if (!url.trim().startsWith("http")) {
|
||||
return null;
|
||||
}
|
||||
if (url === input) {
|
||||
if (isVip(url) || !isVideoFormat(url)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (isBlackVodUrl(input, url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let headers = {};
|
||||
if (jsonPlayData.hasOwnProperty("header")) {
|
||||
headers = jsonPlayData.header;
|
||||
} else if (jsonPlayData.hasOwnProperty("Header")) {
|
||||
headers = jsonPlayData.Header;
|
||||
} else if (jsonPlayData.hasOwnProperty("headers")) {
|
||||
headers = jsonPlayData.headers;
|
||||
} else if (jsonPlayData.hasOwnProperty("Headers")) {
|
||||
headers = jsonPlayData.Headers;
|
||||
}
|
||||
|
||||
let ua = "";
|
||||
if (jsonPlayData.hasOwnProperty("user-agent")) {
|
||||
ua = jsonPlayData["user-agent"];
|
||||
} else if (jsonPlayData.hasOwnProperty("User-Agent")) {
|
||||
ua = jsonPlayData["User-Agent"];
|
||||
}
|
||||
if (ua.trim().length > 0) {
|
||||
headers["User-Agent"] = " " + ua;
|
||||
}
|
||||
|
||||
let referer = "";
|
||||
if (jsonPlayData.hasOwnProperty("referer")) {
|
||||
referer = jsonPlayData.referer;
|
||||
} else if (jsonPlayData.hasOwnProperty("Referer")) {
|
||||
referer = jsonPlayData.Referer;
|
||||
}
|
||||
if (referer.trim().length > 0) {
|
||||
headers["Referer"] = " " + referer;
|
||||
}
|
||||
|
||||
headers = fixJsonVodHeader(headers, input, url);
|
||||
|
||||
const taskResult = {
|
||||
header: headers,
|
||||
url: url,
|
||||
parse: "0"
|
||||
};
|
||||
|
||||
return taskResult;
|
||||
} catch (error) {
|
||||
SpiderDebug.log(error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isVip(url) {
|
||||
try {
|
||||
let isVip = false;
|
||||
const host = new URL(url).hostname;
|
||||
const vipWebsites = ["iqiyi.com", "v.qq.com", "youku.com", "le.com", "tudou.com", "mgtv.com", "sohu.com", "acfun.cn", "bilibili.com", "baofeng.com", "pptv.com"];
|
||||
for (let b = 0; b < vipWebsites.length; b++) {
|
||||
if (host.includes(vipWebsites[b])) {
|
||||
if (vipWebsites[b] === "iqiyi.com") {
|
||||
if (url.includes("iqiyi.com/a_") || url.includes("iqiyi.com/w_") || url.includes("iqiyi.com/v_")) {
|
||||
isVip = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
isVip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isVip;
|
||||
} catch (e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isBlackVodUrl(input, url) {
|
||||
return url.includes("973973.xyz") || url.includes(".fit:");
|
||||
}
|
||||
|
||||
function fixJsonVodHeader(headers, input, url) {
|
||||
if (headers === null) {
|
||||
headers = {};
|
||||
}
|
||||
|
||||
if (input.includes("www.mgtv.com")) {
|
||||
headers["Referer"] = " ";
|
||||
headers["User-Agent"] = " Mozilla/5.0";
|
||||
} else if (url.includes("titan.mgtv")) {
|
||||
headers["Referer"] = " ";
|
||||
headers["User-Agent"] = " Mozilla/5.0";
|
||||
} else if (input.includes("bilibili")) {
|
||||
headers["Referer"] = " https://www.bilibili.com/";
|
||||
headers["User-Agent"] = " " + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
const snifferMatch = /http((?!http).){26,}?\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg)\?.*|http((?!http).){26,}\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg)|http((?!http).){26,}\/m3u8\?pt=m3u8.*|http((?!http).)*?default\.ixigua\.com\/.*|http((?!http).)*?cdn-tos[^\?]*|http((?!http).)*?\/obj\/tos[^\?]*|http.*?\/player\/m3u8play\.php\?url=.*|http.*?\/player\/.*?[pP]lay\.php\?url=.*|http.*?\/playlist\/m3u8\/\?vid=.*|http.*?\.php\?type=m3u8&.*|http.*?\/download.aspx\?.*|http.*?\/api\/up_api.php\?.*|https.*?\.66yk\.cn.*|http((?!http).)*?netease\.com\/file\/.*/;
|
||||
|
||||
function isVideoFormat(url) {
|
||||
if (snifferMatch.test(url)) {
|
||||
return !url.includes("cdn-tos") || !url.includes(".js");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isVideo(url) {
|
||||
return !url.includes(".mp4") && !url.includes(".m3u8");
|
||||
}
|
||||
|
||||
function UA(url) {
|
||||
if (url.includes(".vod")) {
|
||||
return "okhttp/4.1.0";
|
||||
}
|
||||
return "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
|
||||
}
|
||||
|
||||
function getCateUrl(URL) {
|
||||
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
|
||||
return URL + "nav?token=";
|
||||
} else if (URL.includes(".vod")) {
|
||||
return URL + "/types";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function getPlayUrlPrefix(URL) {
|
||||
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
|
||||
return URL + "video_detail?id=";
|
||||
} else if (URL.includes(".vod")) {
|
||||
return URL + "/detail?vod_id=";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function getRecommendUrl(URL) {
|
||||
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
|
||||
return URL + "index_video?token=";
|
||||
} else if (URL.includes(".vod")) {
|
||||
return URL + "/vodPhbAll";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function getFilterTypes(URL, typeExtend) {
|
||||
let str = "";
|
||||
|
||||
if (typeExtend !== null) {
|
||||
for (let key in typeExtend) {
|
||||
if (key === "class" || key === "area" || key === "lang" || key === "year") {
|
||||
try {
|
||||
str += "筛选" + key + "+全部=+" + typeExtend[key].replace(/,/g, "+") + "\n";
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (URL.includes(".vod")) {
|
||||
str += "\n" + "排序+全部=+最新=time+最热=hits+评分=score";
|
||||
} else if (URL.includes("api.php/app") || URL.includes("xgapp")) {
|
||||
// Do nothing, leave the string as it is.
|
||||
} else {
|
||||
str = "分类+全部=+电影=movie+连续剧=tvplay+综艺=tvshow+动漫=comic+4K=movie_4k+体育=tiyu\n筛选class+全部=+喜剧+爱情+恐怖+动作+科幻+剧情+战争+警匪+犯罪+动画+奇幻+武侠+冒险+枪战+恐怖+悬疑+惊悚+经典+青春+文艺+微电影+古装+历史+运动+农村+惊悚+惊悚+伦理+情色+福利+三级+儿童+网络电影\n筛选area+全部=+大陆+香港+台湾+美国+英国+法国+日本+韩国+德国+泰国+印度+西班牙+加拿大+其他\n筛选year+全部=+2025+2024+2023+2022+2021+2020+2019+2018+2017+2016+2015+2014+2013+2012+2011+2010+2009+2008+2007+2006+2005+2004+2003+2002+2001+2000";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
function getCateFilterUrlSuffix(URL) {
|
||||
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
|
||||
return "&class=筛选class&area=筛选area&lang=筛选lang&year=筛选year&limit=18&pg=#PN#";
|
||||
} else if (URL.includes(".vod")) {
|
||||
return "&class=筛选class&area=筛选area&lang=筛选lang&year=筛选year&by=排序&limit=18&page=#PN#";
|
||||
} else {
|
||||
return "&page=#PN#&area=筛选area&type=筛选class&start=筛选year";
|
||||
}
|
||||
}
|
||||
|
||||
function getCateFilterUrlPrefix(URL) {
|
||||
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
|
||||
return URL + "video?tid=";
|
||||
} else if (URL.includes(".vod")) {
|
||||
return URL + "?type=";
|
||||
} else {
|
||||
return URL + "?ac=list&class=";
|
||||
}
|
||||
}
|
||||
|
||||
function isBan(key) {
|
||||
return key === "伦理" || key === "情色" || key === "福利";
|
||||
}
|
||||
|
||||
function getSearchUrl(URL, KEY) {
|
||||
if (URL.includes(".vod")) {
|
||||
return URL + "?wd=" + KEY + "&page=";
|
||||
} else if (URL.includes("api.php/app") || URL.includes("xgapp")) {
|
||||
return URL + "search?text=" + KEY + "&pg=";
|
||||
} else if (urlPattern1.test(URL)) {
|
||||
return URL + "?ac=list&zm=" + KEY + "&page=";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function findJsonArray(obj, match, result) {
|
||||
Object.keys(obj).forEach((k) => {
|
||||
try {
|
||||
const o = obj[k];
|
||||
if (k === match && Array.isArray(o)) {
|
||||
result.push(o);
|
||||
}
|
||||
if (typeof o === "object" && o !== null) {
|
||||
if (Array.isArray(o)) {
|
||||
o.forEach((item) => {
|
||||
if (typeof item === "object" && item !== null) {
|
||||
findJsonArray(item, match, result);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
findJsonArray(o, match, result);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function jsonArr2Str(array) {
|
||||
const strings = [];
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
try {
|
||||
strings.push(array[i]);
|
||||
} catch (e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
return strings.join(",");
|
||||
}
|
||||
|
||||
function getHeaders(URL) {
|
||||
const headers = {};
|
||||
headers["User-Agent"] = UA(URL);
|
||||
return headers;
|
||||
}
|
||||
|
||||
function isJsonString(str) {
|
||||
try {
|
||||
JSON.parse(str);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function __jsEvalReturn() {
|
||||
return {
|
||||
init: init,
|
||||
home: home,
|
||||
homeVod: homeVod,
|
||||
category: category,
|
||||
detail: detail,
|
||||
play: play,
|
||||
search: search,
|
||||
};
|
||||
}
|
||||
@@ -124,7 +124,7 @@ async function detail(id) {
|
||||
return JSON.stringify({ list: [{ vod_id: id, vod_name: '加载失败', vod_play_url: '' }] });
|
||||
}
|
||||
|
||||
vod.vod_play_from = '金牌影院';
|
||||
vod.vod_play_from = '琉芸专线';
|
||||
if (vod.episodelist?.length) {
|
||||
const name = vod.episodelist.length > 1 ? vod.episodelist[0].name : vod.vod_name;
|
||||
vod.vod_play_url = vod.episodelist.map(ep => `${name}$${id}@@${ep.nid}`).join('#');
|
||||
-250
@@ -1,250 +0,0 @@
|
||||
/*
|
||||
title: '月光影视', author: '小可乐/v5.12.1'
|
||||
说明:可以不写ext,也可以写ext,ext支持的参数和格式参数如下
|
||||
"ext": {
|
||||
"host": "xxxx", //站点网址
|
||||
"timeout": 6000 //请求超时,单位毫秒
|
||||
}
|
||||
*/
|
||||
var HOST;
|
||||
const MOBILE_UA = 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36';
|
||||
const DefHeader = {'User-Agent': MOBILE_UA};
|
||||
const KParams = {
|
||||
headers: {'User-Agent': MOBILE_UA},
|
||||
timeout: 5000
|
||||
};
|
||||
|
||||
async function init(cfg) {
|
||||
try {
|
||||
let host = cfg.ext?.host?.trim() || 'https://www.dzwhs.com';
|
||||
HOST = host.replace(/\/$/, '');
|
||||
KParams.headers['Referer'] = HOST;
|
||||
let parseTimeout = parseInt(cfg.ext?.timeout?.trim(), 10);
|
||||
KParams.timeout = parseTimeout > 0 ? parseTimeout : 5000;
|
||||
KParams.resHtml = await request(HOST);
|
||||
} catch (e) {
|
||||
console.error('初始化参数失败:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function home(filter) {
|
||||
try {
|
||||
let resHtml = KParams.resHtml;
|
||||
if (!resHtml) {throw new Error('源码为空');}
|
||||
let classes = cutStr(resHtml, '/zwhstp', '/a>', '', false, 1, true).map(it => {
|
||||
let cName = cutStr(it, '>', '<', '分类名');
|
||||
let cId = cutStr(it, '/', '.', '分类值');
|
||||
return {type_name: cName, type_id: cId};
|
||||
});
|
||||
let filters = {
|
||||
"1":[
|
||||
{"key":"cateId","name":"类型","value":[{"n":"全部","v":"全部"},{"n":"动作片","v":"6"},{"n":"喜剧片","v":"7"},{"n":"爱情片","v":"8"},{"n":"科幻片","v":"9"},{"n":"恐怖片","v":"10"},{"n":"剧情片","v":"11"},{"n":"战争片","v":"12"},{"n":"纪录片","v":"13"},{"n":"悬疑片","v":"14"},{"n":"犯罪片","v":"15"},{"n":"奇幻片","v":"16"},{"n":"动画片","v":"31"},{"n":"预告片","v":"32"}]}
|
||||
],
|
||||
"2":[
|
||||
{"key":"cateId","name":"类型","value":[{"n":"全部","v":"全部"},{"n":"国产剧","v":"17"},{"n":"港台剧","v":"18"},{"n":"日韩剧","v":"20"},{"n":"欧美剧","v":"21"},{"n":"海外剧","v":"22"}]}
|
||||
],
|
||||
"3":[
|
||||
{"key":"cateId","name":"类型","value":[{"n":"全部","v":"全部"},{"n":"大陆综艺","v":"23"},{"n":"日韩综艺","v":"24"},{"n":"欧美综艺","v":"25"},{"n":"港台综艺","v":"26"}]}
|
||||
],
|
||||
"4":[
|
||||
{"key":"cateId","name":"类型","value":[{"n":"全部","v":"全部"},{"n":"国产动漫","v":"27"},{"n":"日韩动漫","v":"28"},{"n":"欧美动漫","v":"29"},{"n":"其他动漫","v":"30"}]}
|
||||
]
|
||||
};
|
||||
return JSON.stringify({class: classes, filters: filters});
|
||||
} catch (e) {
|
||||
console.error('获取分类失败:', e.message);
|
||||
return JSON.stringify({class: [], filters: {}});
|
||||
}
|
||||
}
|
||||
|
||||
async function homeVod() {
|
||||
try {
|
||||
let resHtml = KParams.resHtml;
|
||||
let VODS = getVodList(resHtml);
|
||||
return JSON.stringify({list: VODS});
|
||||
} catch (e) {
|
||||
console.error('推荐页获取失败:', e.message);
|
||||
return JSON.stringify({list: []});
|
||||
}
|
||||
}
|
||||
|
||||
async function category(tid, pg, filter, extend) {
|
||||
try {
|
||||
pg = parseInt(pg, 10);
|
||||
pg = pg > 0 ? pg : 1;
|
||||
let cateUrl = `${HOST}/zwhstp/${extend?.cateId ?? tid}-${pg}.html`;
|
||||
let resHtml = await request(cateUrl);
|
||||
let VODS = getVodList(resHtml);
|
||||
let pagecount = 999;
|
||||
return JSON.stringify({list: VODS, page: pg, pagecount: pagecount, limit: 30, total: 30*pagecount});
|
||||
} catch (e) {
|
||||
console.error('类别页获取失败:', e.message);
|
||||
return JSON.stringify({list: [], page: 1, pagecount: 0, limit: 30, total: 0});
|
||||
}
|
||||
}
|
||||
|
||||
async function search(wd, quick, pg) {
|
||||
try {
|
||||
pg = parseInt(pg, 10);
|
||||
pg = pg > 0 ? pg : 1;
|
||||
let searchUrl = `${HOST}/zwhstp/id.html?wd=${wd}&page=${pg}`;
|
||||
let resHtml = await request(searchUrl);
|
||||
let VODS = getVodList(resHtml);
|
||||
return JSON.stringify({list: VODS, page: pg, pagecount: 10, limit: 30, total: 300});
|
||||
} catch (e) {
|
||||
console.error('搜索页获取失败:', e.message);
|
||||
return JSON.stringify({list: [], page: 1, pagecount: 0, limit: 30, total: 0});
|
||||
}
|
||||
}
|
||||
|
||||
function getVodList(khtml) {
|
||||
try {
|
||||
if (!khtml) {throw new Error('源码为空');}
|
||||
let kvods = [];
|
||||
let listArr = cutStr(khtml, 'lazyload"', '/a>', '', false, 1, true);
|
||||
for (let it of listArr) {
|
||||
let kname = cutStr(it, 'title="', '"', '名称');
|
||||
let kpic = cutStr(it, 'data-original="', '"', '图片');
|
||||
let kremarks = cutStr(it, 'text-right">', '<', '状态');
|
||||
kvods.push({
|
||||
vod_name: kname,
|
||||
vod_pic: kpic,
|
||||
vod_remarks:'🌲'+ kremarks,
|
||||
vod_id: `${cutStr(it, 'href="', '"', 'Id')}@${kname}@${kpic}@${kremarks}`
|
||||
});
|
||||
}
|
||||
return kvods;
|
||||
} catch (e) {
|
||||
console.error(`生成视频列表失败:`, e.message);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function detail(ids) {
|
||||
try {
|
||||
let [id, kname, kpic, kremarks] = ids.split('@');
|
||||
let detailUrl = !/^http/.test(id) ? `${HOST}${id}` : id;
|
||||
let resHtml = await request(detailUrl);
|
||||
if (!resHtml) {throw new Error('源码为空');}
|
||||
let intros = cutStr(resHtml, 'stui-content col-pd', 'play-btn', '', false);
|
||||
let ktabs = cutStr(resHtml, 'pull-right"></span>', '/h3>', '', false, 1, true).map((it,idx) => cutStr(it, 'title">', '<', `线-${idx+1}`));
|
||||
let kurls = cutStr(resHtml, '"stui-content__playlist', '</ul>', '', false, 1, true).map(item => {
|
||||
let kurl = cutStr(item, '<a', '/a>', '', false, 1, true).map(it => { return cutStr(it, '>', '<', 'noEpi') + '$' + cutStr(it, 'href="', '"', 'noUrl'); });
|
||||
return kurl.join('#');
|
||||
});
|
||||
let VOD = {
|
||||
vod_id: detailUrl,
|
||||
vod_name: kname,
|
||||
vod_pic: kpic,
|
||||
type_name: cutStr(intros, '类型:', '<span', '类型'),
|
||||
vod_remarks:'🌲'+ kremarks,
|
||||
vod_year: cutStr(intros, '年份:', '</p>', '1000'),
|
||||
vod_area: cutStr(intros, '地区:', '<span', '地区'),
|
||||
vod_lang: '语言',
|
||||
vod_director: cutStr(intros, '导演:', '</p>', '导演'),
|
||||
vod_actor: cutStr(intros, '主演:', '</p>', '主演'),
|
||||
vod_content:'【琉🔹芸❤广告勿信👉剧情】 '+ cutStr(intros, 'detail-content£>', '</span>', '简介'),
|
||||
vod_play_from: ktabs.join('$$$💕琉芸👉'),
|
||||
vod_play_url: kurls.join('$$$')
|
||||
};
|
||||
return JSON.stringify({list: [VOD]});
|
||||
} catch (e) {
|
||||
console.error('详情页获取失败:', e.message);
|
||||
return JSON.stringify({list: []});
|
||||
}
|
||||
}
|
||||
|
||||
async function play(flag, ids, flags) {
|
||||
try {
|
||||
let playUrl = !/^http/.test(ids) ? `${HOST}${ids}` : ids;
|
||||
let kp = 0;
|
||||
let resHtml = await request(playUrl);
|
||||
let kcode = safeParseJSON(cutStr(resHtml, 'var player_£=', '<', '', false));
|
||||
let kurl = kcode?.url ?? '';
|
||||
if (!/m3u8|mp4|mkv/.test(kurl)) {
|
||||
kp = 1;
|
||||
kurl = playUrl;
|
||||
}
|
||||
return JSON.stringify({jx: 0, parse: kp, url: kurl, header: DefHeader});
|
||||
} catch (e) {
|
||||
console.error('播放失败:', e.message);
|
||||
return JSON.stringify({jx: 0, parse: 0, url: '', header: {}});
|
||||
}
|
||||
}
|
||||
|
||||
function cutStr(str, prefix = '', suffix = '', defaultVal = 'cutFaile', clean = true, i = 1, all = false) {
|
||||
try {
|
||||
if (!str || typeof str !== 'string') {throw new Error('被截取对象需为非空字符串');}
|
||||
const dealStr = ds => String(ds).replace(/<[^>]*?>/g, ' ').replace(/( |\u00A0|\s)+/g, ' ').trim().replace(/\s+/g, ' ');
|
||||
const esc = s => String(s).replace(/[.*+?${}()|[\]\\/^]/g, '\\$&');
|
||||
let pre = esc(prefix).replace(/£/g, '[^]*?');
|
||||
let end = esc(suffix);
|
||||
let regex = new RegExp(`${pre ? pre : '^'}([^]*?)${end ? end : '$'}`, 'g');
|
||||
let matchArr = [...str.matchAll(regex)];
|
||||
if (all) {
|
||||
return matchArr.map(it => {
|
||||
const val = it[1] ?? defaultVal;
|
||||
return clean && val !== defaultVal ? dealStr(val) : val;
|
||||
});
|
||||
}
|
||||
i = parseInt(i, 10);
|
||||
if (isNaN(i) || i < 1) {throw new Error('序号需为大于0的整数');}
|
||||
i = i - 1;
|
||||
if (i >= matchArr.length) {throw new Error('序号越界');}
|
||||
let result = matchArr[i][1] ?? defaultVal;
|
||||
return clean && result !== defaultVal ? dealStr(result) : result;
|
||||
} catch (e) {
|
||||
console.error(`字符串截取失败:`, e.message);
|
||||
return all ? ['cutErr'] : 'cutErr';
|
||||
}
|
||||
}
|
||||
|
||||
function safeParseJSON(jStr){
|
||||
try {return JSON.parse(jStr);} catch(e) {return null;}
|
||||
}
|
||||
|
||||
async function request(reqUrl, options = {}) {
|
||||
try {
|
||||
if (typeof reqUrl !== 'string' || !reqUrl.trim()) { throw new Error('reqUrl需为字符串且非空'); }
|
||||
if (typeof options !== 'object' || Array.isArray(options) || !options) { throw new Error('options类型需为非null对象'); }
|
||||
options.method = options.method?.toLowerCase() || 'get';
|
||||
if (['get', 'head'].includes(options.method)) {
|
||||
delete options.data;
|
||||
delete options.postType;
|
||||
} else {
|
||||
options.data = options.data ?? '';
|
||||
options.postType = options.postType?.toLowerCase() || 'form';
|
||||
}
|
||||
let {headers, timeout, charset, toBase64 = false, ...restOpts } = options;
|
||||
const optObj = {
|
||||
headers: (typeof headers === 'object' && !Array.isArray(headers) && headers) ? headers : KParams.headers,
|
||||
timeout: parseInt(timeout, 10) > 0 ? parseInt(timeout, 10) : KParams.timeout,
|
||||
charset: charset?.toLowerCase() || 'utf-8',
|
||||
buffer: toBase64 ? 2 : 0,
|
||||
...restOpts
|
||||
};
|
||||
const res = await req(reqUrl, optObj);
|
||||
if (options.withHeaders) {
|
||||
const resHeaders = typeof res.headers === 'object' && !Array.isArray(res.headers) && res.headers ? res.headers : {};
|
||||
const resWithHeaders = { ...resHeaders, body: res?.content ?? '' };
|
||||
return JSON.stringify(resWithHeaders);
|
||||
}
|
||||
return res?.content ?? '';
|
||||
} catch (e) {
|
||||
console.error(`${reqUrl}→请求失败:`, e.message);
|
||||
return options?.withHeaders ? JSON.stringify({ body: '' }) : '';
|
||||
}
|
||||
}
|
||||
|
||||
export function __jsEvalReturn() {
|
||||
return {
|
||||
init: init,
|
||||
home: home,
|
||||
homeVod: homeVod,
|
||||
category: category,
|
||||
search: search,
|
||||
detail: detail,
|
||||
play: play,
|
||||
proxy: null
|
||||
};
|
||||
}
|
||||
+4
-4
@@ -44,7 +44,7 @@ function getList(html) {
|
||||
vod_id: id,
|
||||
vod_name: name,
|
||||
vod_pic: fixPic(pic),
|
||||
vod_remarks: remarks.trim()
|
||||
vod_remarks:'💕蓝光💕' + remarks.trim()
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -112,8 +112,8 @@ async function detail(id) {
|
||||
vod_id: id,
|
||||
vod_name: name,
|
||||
vod_pic: pic,
|
||||
vod_content: content || "暂无简介",
|
||||
vod_play_from: playFrom,
|
||||
vod_content: content || "【琉🔹芸❤广告勿信👉剧情】📢暂无简介",
|
||||
vod_play_from:'💕' + playFrom,
|
||||
vod_play_url: playUrl
|
||||
}]
|
||||
});
|
||||
@@ -135,4 +135,4 @@ async function play(flag, id, flags) {
|
||||
return JSON.stringify({ parse: 1, url: `${host}/dsshiyipy/${id}.html` });
|
||||
}
|
||||
|
||||
export default { init, home, homeVod, category, detail, search, play };
|
||||
export default { init, home, homeVod, category, detail, search, play };
|
||||
|
||||
@@ -83,10 +83,10 @@ async function init(cfg) {}
|
||||
|
||||
async function home(filter) {
|
||||
const classes = [
|
||||
{ type_id: '2', type_name: '连续剧' },
|
||||
{ type_id: '1', type_name: '电影' },
|
||||
{ type_id: '3', type_name: '综艺' },
|
||||
{ type_id: '4', type_name: '动漫' }
|
||||
{ type_id: '1', type_name: '琉芸电影' },
|
||||
{ type_id: '2', type_name: '琉芸连续剧' },
|
||||
{ type_id: '3', type_name: '琉芸综艺' },
|
||||
{ type_id: '4', type_name: '琉芸动漫' }
|
||||
];
|
||||
return JSON.stringify({ class: classes });
|
||||
}
|
||||
@@ -163,7 +163,7 @@ async function detail(id) {
|
||||
vod_actor: Array.isArray(data.Actor) ? data.Actor.join(',') : data.Actor,
|
||||
vod_director: data.Director,
|
||||
vod_content:'【琉🔹芸❤广告勿信👉剧情】📢'+data.Description,
|
||||
vod_play_from: '💕琉芸👉独家',
|
||||
vod_play_from: '琉芸专线',
|
||||
vod_play_url: playUrls,
|
||||
type_name: `${data.Genre || ''},${data.Scenario || ''}`
|
||||
}]
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"请求头": "User-Agent$MOBILE_UA",
|
||||
"编码": "UTF-8",
|
||||
"主页url": "http://www.hairuiyy.com/",
|
||||
"二次截取": "",
|
||||
"数组": "lazyload\"&&</li>",
|
||||
"标题": "title=\"&&\"",
|
||||
"图片": "data-original=\"&&\"",
|
||||
"副标题": "🌲+text-right\">&&</span>",
|
||||
"链接": "href=\"&&\"",
|
||||
"简介": "none;\"&&<br>",
|
||||
"播放数组": "playlist clearfix column&&</ul>",
|
||||
"播放列表": "<a&&a>",
|
||||
"播放链接": "href=\"&&\"",
|
||||
"播放标题": ">&&<",
|
||||
"线路数组": "#playlist&&</li>",
|
||||
"线路标题": "\">&&</a >",
|
||||
"搜索url": "http://www.hairuiyy.com/search/{wd}----------{pg}---.html",
|
||||
"搜索模式": "1",
|
||||
"搜索后缀": "",
|
||||
"搜索二次截取": "",
|
||||
"搜索数组": "active clearfix\"&&</li>",
|
||||
"搜索标题": "title=\"&&\"",
|
||||
"搜索图片": "data-original=\"&&\"",
|
||||
"搜索副标题": "text-right\">&&<",
|
||||
"搜索链接": "href=\"&&\"",
|
||||
"跳转播放链接": "var player_*\"url\":\"&&\"",
|
||||
"分类url": "http://www.hairuiyy.com/show/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html",
|
||||
"分类": "电影$1#电视剧$2#综艺$3#动漫$4#短剧$36"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{ "简介": "&&",
|
||||
"副标题": "琉芸✨-+right\">&&<",
|
||||
"线路标题": "panel-hd\">&&",
|
||||
"分类url": "https://www.shanhuzs.com/fqsansw/5-{area}--{cateId}-----{catePg}---{year}.html",
|
||||
"分类": "女频$女频恋爱#反转$反转爽#悬疑$脑洞悬疑#穿越$年代穿越#古装$古装仙侠#都市$现代都市"
|
||||
}
|
||||
+33
-89
@@ -27,18 +27,10 @@
|
||||
"类型": "影視" }
|
||||
},
|
||||
{
|
||||
"key": "py_liuyun",
|
||||
"key": "js_liuyun",
|
||||
"name": "🍘┃琉璃┃ 影視",
|
||||
"type": 3,
|
||||
"api": "https://d.kstore.dev/download/12194/TS/琉璃.py",
|
||||
"ext": {"site": "https://www.tjrongze.com,https://y2s52n7.com,https://m.hkybqufgh.com",
|
||||
"类型": "影視" }
|
||||
},
|
||||
{
|
||||
"key": "csp_Duboku",
|
||||
"name": "🎯┃影視┃ 独播",
|
||||
"type": 3,
|
||||
"api": "csp_Duboku",
|
||||
"api": "https://d.kstore.dev/download/12194/TS/琉璃.js",
|
||||
"类型": "影視"
|
||||
},
|
||||
{
|
||||
@@ -70,6 +62,13 @@
|
||||
"type": 3,
|
||||
"ext": "https://www.xlysw.ggff.net"
|
||||
},
|
||||
{
|
||||
"key": "csp_Duboku",
|
||||
"name": "🎯┃影視┃ 独播",
|
||||
"type": 3,
|
||||
"api": "csp_Duboku",
|
||||
"类型": "影視"
|
||||
},
|
||||
{
|
||||
"key" : "chengzi",
|
||||
"name" : "🌰┃影視┃ 瓜子",
|
||||
@@ -119,8 +118,7 @@
|
||||
"name": "🌟┃影視┃ 星辰",
|
||||
"type": 3,
|
||||
"api": "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/TS/星辰.js",
|
||||
"ext": {"host": "https://www.xcyycn.com",
|
||||
"类型": "影視" }
|
||||
"类型": "影視"
|
||||
},
|
||||
{
|
||||
"key": "js_永乐",
|
||||
@@ -137,18 +135,18 @@
|
||||
"类型": "影視"
|
||||
},
|
||||
{
|
||||
"key": "py_华数",
|
||||
"name": "🚩┃影視┃ 华数",
|
||||
"key": "js_文才",
|
||||
"name": "🚩┃影視┃ 文才",
|
||||
"type": 3,
|
||||
"api": "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/TS/华数.py",
|
||||
"ext": {"host": "https://www.wasu.cn",
|
||||
"类型": "影視" }
|
||||
"api": "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/TS/文才.js",
|
||||
"类型": "影視"
|
||||
},
|
||||
{
|
||||
"key" : "py_壹影视",
|
||||
"name" : "🦗┃影視┃ 壹影",
|
||||
"key" : "js_奇迹云",
|
||||
"name" : "🦗┃影視┃ 奇迹",
|
||||
"type" : 3,
|
||||
"api": "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/TS/壹影.py",
|
||||
"api" : "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/TS/奇迹云.js",
|
||||
"ext" : "http://cmsyun2.qijiyun.vip/api.php/app/",
|
||||
"类型": "影視"
|
||||
},
|
||||
{
|
||||
@@ -175,22 +173,6 @@
|
||||
"ext": "https://gitee.com/lyun_1_0/tb/raw/master/XP/枫叶.json",
|
||||
"jar" : "https://gitee.com/lyun_1_0/tb/raw/master/JAR/00.jar"
|
||||
},
|
||||
{
|
||||
"key" : "csp_人人",
|
||||
"name" : "🤵🏻┃影視┃人人",
|
||||
"type" : 3,
|
||||
"api" : "csp_XBPQ",
|
||||
"ext" : "https://gitee.com/lyun_1_0/tb/raw/master/XP/人人.json",
|
||||
"jar" : "https://gitee.com/lyun_1_0/tb/raw/master/JAR/00.jar"
|
||||
},
|
||||
{
|
||||
"key" : "csp_青蛙",
|
||||
"name" : "🖥┃影視┃青蛙",
|
||||
"type" : 3,
|
||||
"api" : "csp_XBPQ",
|
||||
"ext" : "https://gitee.com/lyun_1_0/tb/raw/master/XP/青蛙.json",
|
||||
"jar" : "https://gitee.com/lyun_1_0/tb/raw/master/JAR/00.jar"
|
||||
},
|
||||
{
|
||||
"key" : "csp_云播",
|
||||
"name" : "🌩┃影視┃云播",
|
||||
@@ -463,26 +445,6 @@
|
||||
"dataKey": "5a9w6x58dsq6z3a6",
|
||||
"dataIv": "5a9w6x58dsq6z3a6"}
|
||||
},
|
||||
{
|
||||
"key": "csp_星河",
|
||||
"name": "🌐┃星河┃ APP",
|
||||
"type": 3,
|
||||
"api": "csp_AppQi",
|
||||
"ext": {
|
||||
"site": "https://xinlanyinghb.oss-cn-wuhan-lr.aliyuncs.com/xly.txt",
|
||||
"dataKey": "ca94b06ca359d80e",
|
||||
"dataIv": "ca94b06ca359d80e",
|
||||
"init": "initV120",
|
||||
"ua": "okhttp/3.10.0"}
|
||||
},
|
||||
{
|
||||
"key": "csp_闪影",
|
||||
"name": "🌐┃闪影┃ APP",
|
||||
"type": 3,
|
||||
"api": "csp_AppYs",
|
||||
"ext": "https://qpcj.69mini.com/api.php/app/",
|
||||
"类型": "APP"
|
||||
},
|
||||
{
|
||||
"key": "HemaDJ",
|
||||
"name": "♨️┃短劇┃ 盒马 ",
|
||||
@@ -505,43 +467,25 @@
|
||||
"genre": "shortdrama"
|
||||
},
|
||||
{
|
||||
"key": "py_西饭短剧",
|
||||
"name": "♨️┃短劇┃ 稀饭",
|
||||
"type": 3,
|
||||
"api": "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/TS/西饭短剧.py",
|
||||
"ext": {"host": "https://xifan-api-cn.youlishipin.com",
|
||||
"类型": "短剧" }
|
||||
"key" : "csp_憨塔",
|
||||
"name" : "♨️┃短劇┃ 憨塔",
|
||||
"type" : 3,
|
||||
"api" : "csp_XBPQ",
|
||||
"ext" : "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/XYQ/憨塔.png"
|
||||
},
|
||||
{
|
||||
"key": "py_星芽短剧",
|
||||
"name": "♨️┃短劇┃ 星芽",
|
||||
"type": 3,
|
||||
"api": "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/TS/星芽.py",
|
||||
"ext": {"host": "https://app.whjzjx.cn",
|
||||
"类型": "短剧" }
|
||||
"key" : "csp_喵喵",
|
||||
"name" : "♨️┃短劇┃ 喵喵",
|
||||
"type" : 3,
|
||||
"api" : "csp_XBPQ",
|
||||
"ext" : "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/XYQ/喵喵.png"
|
||||
},
|
||||
{
|
||||
"key": "py_喜福短剧",
|
||||
"name": "♨️┃短劇┃ 喜福",
|
||||
"type": 3,
|
||||
"api": "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/TS/喜福.py",
|
||||
"类型": "短剧"
|
||||
},
|
||||
{
|
||||
"key": "py_七猫短剧",
|
||||
"name": "♨️┃短劇┃ 七猫",
|
||||
"type": 3,
|
||||
"api": "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/TS/七猫.py",
|
||||
"ext": {"host": "https://api-read.qmplaylet.com",
|
||||
"类型": "短剧" }
|
||||
},
|
||||
{
|
||||
"key": "py_河马短剧",
|
||||
"name": "♨️┃短劇┃ 河马",
|
||||
"type": 3,
|
||||
"api": "https://gh-proxy.com/raw.githubusercontent.com/LIUJEI/TB/master/TS/河马.py",
|
||||
"ext": {"host": "https://www.kuaikaw.cn",
|
||||
"类型": "短剧" }
|
||||
"key" : "csp_茄子",
|
||||
"name" : "♨️┃短劇┃ 茄子",
|
||||
"type" : 3,
|
||||
"api" : "csp_XBPQ",
|
||||
"ext" : "https://ghproxy.net/https://raw.githubusercontent.com/LIUJEI/TB/master/XYQ/茄子.png"
|
||||
},
|
||||
{
|
||||
"key": "dr_腾迅",
|
||||
|
||||
Reference in New Issue
Block a user