import { Crypto, _ } from 'assets://js/lib/cat.js';
let siteUrl = '';
let key = '';
let iv = '';
let siteKey = '';
let siteType = 3;
let apiPrefix = 'getappapi.index';
const prefixMap = {
'1': 'getappapi.index',
'2': 'qijiappapi.index',
'3': 'appapi'
};
let enableVerifyTimeSign = false;
let headers = {
'User-Agent': 'okhttp/3.10.0',
'app-user-device-id': '291b226282010337c9443590d6457be15',
'app-version-code': '112'
};
let parseMap = {};
let homeVods = [];
let Searchstatus = false;
let searchApiSuffix = '';
let souParamName = '';
let souSalt = '';
let extraSearchHeaders = {};
let initSuffix = 'init';
let hasCustomInit = false;
let thirdDanmuBaseUrl = '';
let customPlayUa = ''; // 新增:自定义播放链接UA
let request = async (reqUrl, data, header, method) => {
let finalHeaders = { ...headers };
if (enableVerifyTimeSign) {
const timestamp = Math.floor(Date.now() / 1000).toString();
const sign = aesEncode(timestamp, key, iv);
finalHeaders['app-api-verify-time'] = timestamp;
finalHeaders['app-api-verify-sign'] = sign;
}
if (header) {
finalHeaders = { ...finalHeaders, ...header };
}
let res = await req(reqUrl, {
method: method || 'get',
data: data || '',
headers: finalHeaders,
postType: method === 'post' ? 'form' : '',
timeout: 10000,
});
return res.content;
};
let request_text = async (reqUrl, data, header, method, tobase64) => {
let finalHeaders = { ...headers };
if (enableVerifyTimeSign) {
const timestamp = Math.floor(Date.now() / 1000).toString();
const sign = aesEncode(timestamp, key, iv);
finalHeaders['app-api-verify-time'] = timestamp;
finalHeaders['app-api-verify-sign'] = sign;
}
if (header) {
finalHeaders = { ...finalHeaders, ...header };
}
let optObj = {
headers: finalHeaders,
method: method || 'get',
data: method === 'post' ? data : undefined,
postType: method === 'post' ? (data ? 'raw' : 'form') : undefined,
timeout: 10000,
};
if (tobase64) {
optObj.buffer = 2;
}
let res = await req(reqUrl, optObj);
return res.content;
};
async function init(cfg) {
siteKey = cfg.skey;
siteType = cfg.stype;
if (!cfg.ext) return;
let extObj;
if (typeof cfg.ext === 'string') {
extObj = JSON.parse(cfg.ext);
} else if (typeof cfg.ext === 'object' && cfg.ext !== null) {
extObj = cfg.ext;
} else {
return;
}
if (extObj.init && typeof extObj.init === 'string' && extObj.init.startsWith('V')) {
initSuffix = 'init' + extObj.init;
hasCustomInit = true;
}
if (extObj.time !== undefined) {
const timeVal = String(extObj.time);
enableVerifyTimeSign = (timeVal === '1' || timeVal === 'true' || timeVal === '1');
}
if (extObj.code !== undefined) {
forceVerifyCode = String(extObj.code).trim();
}
// 新增:读取自定义播放UA
if (extObj.ua2 !== undefined) {
customPlayUa = String(extObj.ua2).trim();
}
if (extObj.head && typeof extObj.head === 'string') {
const headStr = extObj.head.trim();
if (headStr) {
const items = headStr.split(',');
for (let item of items) {
const trimmed = item.trim();
if (!trimmed) continue;
const colonIndex = trimmed.indexOf(':');
if (colonIndex > 0) {
const hKey = trimmed.substring(0, colonIndex).trim();
const hValue = trimmed.substring(colonIndex + 1).trim();
if (hKey && hValue) {
headers[hKey] = hValue;
}
}
}
}
}
let host = extObj.host || '';
if (host) {
if (host.startsWith('http') && (host.endsWith('.txt') || host.endsWith('.json'))) {
let response = await request(host, null, headers, 'get');
let urls = response.split('\n').map(line => line.trim()).filter(line => line && line.startsWith('http'));
if (urls.length > 0) {
host = urls[0];
}
}
siteUrl = host.replace(/\/+$/, '');
if (!siteUrl.includes('php')) {
siteUrl += '/api.php';
}
}
key = extObj.key || '';
iv = extObj.iv || key;
if (extObj.api && prefixMap[extObj.api]) {
apiPrefix = prefixMap[extObj.api];
}
if (extObj.version) {
headers['app-version-code'] = String(extObj.version);
}
if (extObj.id) {
headers['app-user-device-id'] = extObj.id;
}
if (extObj.token) {
headers['app-user-token'] = extObj.token;
}
if (extObj.ua) {
headers['User-Agent'] = extObj.ua;
}
}
function processSignatureValue(sig) {
if (sig.length < 8) {
return sig.split('').reverse().join('');
} else {
let rear = sig.slice(-8).split('').reverse().join('');
let front = sig.slice(0, -8).split('').reverse().join('');
return front + rear;
}
}
async function home(filter) {
let initUrl = `${siteUrl}/${apiPrefix}/${initSuffix}`;
let rets = JSON.parse(await request(initUrl)).data;
let data = JSON.parse(aesDecode(rets, key, iv));
let rawDanmuUrl = data.config?.third_danmu_url || '';
if (Array.isArray(rawDanmuUrl)) {
rawDanmuUrl = rawDanmuUrl.find(u => u && typeof u === 'string' && u.trim()) || '';
} else if (typeof rawDanmuUrl !== 'string') {
rawDanmuUrl = '';
}
if (rawDanmuUrl) {
thirdDanmuBaseUrl = rawDanmuUrl.trim();
let lower = thirdDanmuBaseUrl.toLowerCase();
if (!lower.match(/[?&]url=$/)) {
thirdDanmuBaseUrl += thirdDanmuBaseUrl.includes('?') ? '&url=' : '?url=';
}
} else {
thirdDanmuBaseUrl = 'https://dmku.hls.one/?ac=dm&url=';
}
if (data.box_config) {
let originalKey = key;
let swappedKey = originalKey.split('').reverse().join('');
let md5Key = md5(swappedKey);
let dynamicIv = md5Key.substring(0, 16);
let decrypted = aesDecode(data.box_config, swappedKey, dynamicIv);
let boxJson = JSON.parse(decrypted);
if (boxJson.search_name) {
searchApiSuffix = boxJson.search_name;
}
if (boxJson.signature_name && boxJson.signature_value) {
souParamName = boxJson.signature_name;
souSalt = processSignatureValue(boxJson.signature_value);
}
if (boxJson.api_header && boxJson.api_header.key && boxJson.api_header.value) {
extraSearchHeaders[boxJson.api_header.key] = boxJson.api_header.value;
}
} else {
searchApiSuffix = 'searchList';
souParamName = '';
souSalt = '';
}
Searchstatus = data.config?.system_search_verify_status || false;
let filters = {};
let classes = [];
homeVods = [];
_.forEach(data.type_list, item => {
if (item.type_id > 0) {
if (item.recommend_list && Array.isArray(item.recommend_list)) {
homeVods = homeVods.concat(item.recommend_list);
}
}
classes.push({
type_id: item.type_id,
type_name: item.type_name,
});
let filterList = [];
_.forEach(item.filter_type_list, f => {
let filter = {};
if (f.name === 'class') {
filter['name'] = '分类';
filter['key'] = f.name;
filter['value'] = _.map(f.list, i => ({ v: i, n: i }));
}
if (f.name === 'area') {
filter['name'] = '区域';
filter['key'] = f.name;
filter['value'] = _.map(f.list, i => ({ v: i, n: i }));
}
if (f.name === 'lang') {
filter['name'] = '语言';
filter['key'] = f.name;
filter['value'] = _.map(f.list, i => ({ v: i, n: i }));
}
if (f.name === 'year') {
filter['name'] = '年份';
filter['key'] = f.name;
filter['value'] = _.map(f.list, i => ({ v: i, n: i }));
}
if (f.name === 'sort') {
filter['name'] = '排序';
filter['key'] = f.name;
filter['value'] = _.map(f.list, i => ({ v: i, n: i }));
}
if (Object.keys(filter).length > 0) {
filterList.push(filter);
}
});
if (filterList.length > 0) {
filters[item.type_id] = filterList;
}
});
return JSON.stringify({
'class': classes,
'filters': filters,
});
}
async function homeVod() {
return JSON.stringify({
list: homeVods,
});
}
async function category(tid, pg, filter, extend) {
if (pg <= 0) pg = 1;
let url = `${siteUrl}/${apiPrefix}/typeFilterVodList`;
let params = {
"area": extend['area'] || "全部",
"sort": extend['sort'] || "最新",
"class": extend['class'] || "全部",
"type_id": tid,
"year": extend['year'] || "全部",
"lang": extend['lang'] || '全部',
"page": pg,
};
let encData = JSON.parse(await request(url, params, '', 'post')).data;
let videos = JSON.parse(aesDecode(encData, key, iv)).recommend_list;
return JSON.stringify({
page: pg,
pagecount: 9999,
list: videos,
});
}
async function detail(id) {
let url = `${siteUrl}/${apiPrefix}/vodDetail`;
let resp = await request(url, { vod_id: id }, '', 'post');
let jsonResp = JSON.parse(resp);
let encData = jsonResp.data;
let decoded = aesDecode(encData, key, iv);
let info = JSON.parse(decoded);
let videos = {
vod_id: info.vod.vod_id,
vod_name: info.vod.vod_name,
vod_area: info.vod.vod_area,
vod_director: info.vod.vod_director,
vod_actor: info.vod.vod_actor,
vod_pic: info.vod.vod_pic,
vod_content: info.vod.vod_content,
type_name: info.vod.vod_class,
vod_year: info.vod.vod_year
};
let froms = [];
let urls = [];
let playSources = _.map(info.vod_play_list, item => {
const playerInfo = item.player_info || {};
const parse = playerInfo.parse || '';
const ua = playerInfo.user_agent || customPlayUa || ''; // 修改:优先使用自定义UA,如果没有则使用原有的
const nameUrls = _.map(item.urls || [], item2 => {
const { name = '', url = '', token = '', parse_api_url = '', nid = 1 } = item2;
return `${name}$${url}@@${parse}@@${token}@@${parse_api_url}@@${ua}@@${info.vod.vod_id}@@${nid}`;
}).join('#');
return {
show: playerInfo.show || 'Unknown',
urls: nameUrls
};
});
let showCount = {};
playSources = _.map(playSources, source => {
let showName = source.show;
if (showCount[showName]) {
showCount[showName]++;
showName = `${showName}${showCount[showName]}`;
} else {
showCount[showName] = 1;
}
return {
show: showName,
urls: source.urls
};
});
playSources.sort((a, b) => {
const aShow = a.show.toLowerCase();
const bShow = b.show.toLowerCase();
const getPriority = (show) => {
if (show.includes('4k')) return 1;
if (show.includes('K')) return 2;
if (show.includes('独家')) return 3;
if (show.includes('秒播')) return 4;
if (show.includes('自建')) return 5;
if (show.includes('蓝光')) return 6;
if (show.includes('专线')) return 7;
return 8;
};
return getPriority(aShow) - getPriority(bShow);
});
froms = _.map(playSources, source => source.show);
urls = _.map(playSources, source => source.urls);
videos.vod_play_from = froms.join('$$$');
videos.vod_play_url = urls.join('$$$');
return JSON.stringify({
list: [videos],
});
}
async function play(flag, id, flags) {
let parts = id.split('@@');
let playUrl = parts[0];
let parse = parts[1] || '';
let token = parts[2] || '';
let parse_api_url = parts[3] || '';
let ua = parts[4] || ''; // 新增:获取UA
let vodId = parts[5] || '';
let nidStr = parts[6] || '1';
let danmakuUrl = '';
if (thirdDanmuBaseUrl && vodId) {
let nid = parseInt(nidStr, 10);
if (isNaN(nid) || nid < 1) nid = 1;
let urlPosition = nid - 1;
let danmuParams = {
url_position: urlPosition.toString(),
vod_id: vodId
};
let danmuRet = await request(`${siteUrl}/${apiPrefix}/danmuList`, danmuParams, '', 'post');
let danmuResponse = JSON.parse(danmuRet);
if (danmuResponse.data) {
let decryptedDanmu = JSON.parse(aesDecode(danmuResponse.data, key, iv));
if (decryptedDanmu && decryptedDanmu.official_url) {
let realDanmuUrl = thirdDanmuBaseUrl + decryptedDanmu.official_url;
let EncodedUrl = encodeURIComponent(realDanmuUrl);
let headerJson = JSON.stringify(headers);
danmakuUrl = js2Proxy(
false,
siteType,
siteKey || '',
EncodedUrl,
headers
);
}
}
}
// 修改:如果存在自定义UA,添加到返回参数中
if (
(playUrl.includes('http://') || playUrl.includes('https://')) &&
(playUrl.includes('m3u8') || playUrl.includes('mp4') || playUrl.includes('mkv')) &&
!parse_api_url
) {
let result = {
parse: 0,
url: playUrl,
danmaku: danmakuUrl
};
// 如果存在自定义UA,添加到返回结果中
if (ua) {
result.header = { 'User-Agent': ua };
}
return JSON.stringify(result);
}
if (parse.startsWith("http")) {
let parseUrl = parse + playUrl;
if (token) {
parseUrl += '&token=' + token;
}
// 如果存在自定义UA,在请求解析接口时使用
let requestHeaders = {};
if (ua) {
requestHeaders['User-Agent'] = ua;
}
let rets = await request(parseUrl, null, requestHeaders, 'get');
if (rets.indexOf('DOCTYPE html') > -1) {
let result = {
parse: 1,
url: parseUrl,
danmaku: danmakuUrl
};
if (ua) {
result.header = { 'User-Agent': ua };
}
return JSON.stringify(result);
}
let parseJson = JSON.parse(rets);
let result = {
parse: 0,
url: parseJson['url'] || parseJson['data']['url'] || '',
danmaku: danmakuUrl
};
// 如果存在自定义UA,添加到返回结果中
if (ua) {
result.header = { 'User-Agent': ua };
}
return JSON.stringify(result);
}
let params = {
'parse_api': parse,
'url': aesEncode(playUrl, key, iv),
'token': token,
};
// 如果存在自定义UA,在请求时使用
let requestHeaders = {};
if (ua) {
requestHeaders['User-Agent'] = ua;
}
let rets = await request(`${siteUrl}/${apiPrefix}/vodParse`, params, requestHeaders, 'post');
let urlDecoded = aesDecode(JSON.parse(rets).data, key, iv);
let finalPlayUrl = '';
let parsed = JSON.parse(urlDecoded);
finalPlayUrl = JSON.parse(parsed.json).url || '';
let result = {
parse: 0,
url: finalPlayUrl,
danmaku: danmakuUrl
};
// 如果存在自定义UA,添加到返回结果中
if (ua) {
result.header = { 'User-Agent': ua };
}
return JSON.stringify(result);
}
async function search(wd, quick, pg) {
if (hasCustomInit) {
await home({});
}
let searchPath = searchApiSuffix || 'searchList';
let url = `${siteUrl}/${apiPrefix}/${searchPath}`;
let retryCount = 0;
const maxRetries = 1;
let videos = [];
let attemptedCaptcha = false;
let attemptedSlider = false;
let sliderVerified = false;
let sliderId = '';
let params = {
'page': '1',
'type_id': '0',
'keywords': wd,
};
if (souParamName && souSalt) {
const currentTimestamp = Math.floor(Date.now() / 1000).toString();
const souString = `/${souParamName}-${currentTimestamp}-sb-0-${souSalt}`;
const md5Value = md5(souString);
const finalValue = `${currentTimestamp}-sb-0-${md5Value}`;
params[souParamName] = finalValue;
}
let searchHeaders = { ...headers, ...extraSearchHeaders };
if (forceVerifyCode) {
params['code'] = forceVerifyCode;
const random_uuid = generateUUID();
params['key'] = random_uuid;
}
const maxWaitRetries = 2;
let waitRetryCount = 0;
while (true) {
let encData = await request(url, params, searchHeaders, 'post');
let response = JSON.parse(encData);
if (response.code === 1001 && response.need_slider === true && !attemptedSlider) {
attemptedSlider = true;
let getSliderUrl = `${siteUrl}/${apiPrefix}/getSlider`;
let sliderResponse = await request(getSliderUrl, {}, searchHeaders, 'post');
let sliderJson = JSON.parse(sliderResponse);
if (sliderJson.code === 1 && sliderJson.data) {
let sliderDecrypted = aesDecode(sliderJson.data, key, iv);
let sliderData = JSON.parse(sliderDecrypted);
sliderId = sliderData.slider_id || '';
let targetX = parseInt(sliderData.target_x) || 0;
let targetY = parseInt(sliderData.target_y) || 0;
if (sliderId && targetX > 0) {
let posX = targetX;
if (targetX > 0) {
let randomOffset = Math.floor(Math.random() * 3) - 1;
posX = targetX + randomOffset;
if (posX < 1) posX = 1;
if (posX > (sliderData.bg_width || 280)) posX = sliderData.bg_width || 280;
}
let timestamp = Date.now();
await new Promise(resolve => setTimeout(resolve, 1000));
let verifyParams = {
pos_x: posX.toString(),
slider_id: sliderId,
timestamp: timestamp.toString()
};
let verifySliderUrl = `${siteUrl}/${apiPrefix}/verifySlider`;
let verifyResponse = await request(verifySliderUrl, verifyParams, searchHeaders, 'post');
let verifyJson = JSON.parse(verifyResponse);
if (verifyJson.code === 1 && verifyJson.data) {
let verifyDecrypted = aesDecode(verifyJson.data, key, iv);
let verifyResult = JSON.parse(verifyDecrypted);
if (verifyResult.verified === true) {
sliderVerified = true;
continue;
}
}
}
}
if (!sliderVerified) {
if (!forceVerifyCode && (Searchstatus || (response.code === 0 && response.msg && response.msg.includes('验证码')))) {
if (attemptedCaptcha) break;
attemptedCaptcha = true;
const random_uuid = generateUUID();
let modifiedApiPrefix = apiPrefix.replace('.index', '');
let verifyUrl = `${siteUrl}/${modifiedApiPrefix}.verify/create?key=${random_uuid}`;
let base64Img = await request_text(verifyUrl, null, headers, 'get', true);
base64Img = base64Img.replace(/\n/g, '');
let ocrResult = await request_text('https://api.nn.ci/ocr/b64/text', base64Img, { 'User-Agent': 'okhttp/3.10.0' }, 'post');
params['code'] = ocrResult.trim();
params['key'] = random_uuid;
retryCount++;
continue;
} else {
break;
}
}
}
if (response.code === 0 &&
(!response.data || response.data.length === 0) &&
response.msg &&
/等.*秒|等待.*秒|等|搜|请等待|稍等|稍候/i.test(response.msg)) {
if (waitRetryCount >= maxWaitRetries) break;
let waitSeconds = extractWaitTime(response.msg);
if (waitSeconds < 1) waitSeconds = 2;
if (waitSeconds > 30) waitSeconds = 30;
const actualWait = waitSeconds + 1;
await new Promise(resolve => setTimeout(resolve, actualWait * 1000));
waitRetryCount++;
continue;
}
if (response.data && response.data.length > 0) {
let decodedData = JSON.parse(aesDecode(response.data, key, iv));
videos = decodedData.search_list || [];
break;
} else if (!forceVerifyCode && (Searchstatus || (response.code === 0 && response.msg && response.msg.includes('验证码')))) {
if (attemptedCaptcha) break;
attemptedCaptcha = true;
const random_uuid = generateUUID();
let modifiedApiPrefix = apiPrefix.replace('.index', '');
let verifyUrl = `${siteUrl}/${modifiedApiPrefix}.verify/create?key=${random_uuid}`;
let base64Img = await request_text(verifyUrl, null, headers, 'get', true);
base64Img = base64Img.replace(/\n/g, '');
let ocrResult = await request_text('https://api.nn.ci/ocr/b64/text', base64Img, { 'User-Agent': 'okhttp/3.10.0' }, 'post');
params['code'] = ocrResult.trim();
params['key'] = random_uuid;
retryCount++;
continue;
} else {
break;
}
}
return JSON.stringify({
list: videos,
});
}
function generateUUID() {
const chars = '0123456789abcdef';
const uuidTemplate = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
return uuidTemplate.replace(/[xy]/g, (c) => {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return chars[v];
});
}
function aesDecode(str, keyStr, ivStr, type) {
const key = Crypto.enc.Utf8.parse(keyStr);
if (type === 'hex') {
str = Crypto.enc.Hex.parse(str);
return Crypto.AES.decrypt({
ciphertext: str
}, key, {
iv: Crypto.enc.Utf8.parse(ivStr),
mode: Crypto.mode.CBC,
padding: Crypto.pad.Pkcs7
}).toString(Crypto.enc.Utf8);
} else {
return Crypto.AES.decrypt(str, key, {
iv: Crypto.enc.Utf8.parse(ivStr),
mode: Crypto.mode.CBC,
padding: Crypto.pad.Pkcs7
}).toString(Crypto.enc.Utf8);
}
}
function aesEncode(str, keyStr, ivStr, type) {
const key = Crypto.enc.Utf8.parse(keyStr);
let encData = Crypto.AES.encrypt(str, key, {
iv: Crypto.enc.Utf8.parse(ivStr),
mode: Crypto.mode.CBC,
padding: Crypto.pad.Pkcs7
});
if (type === 'hex') return encData.ciphertext.toString(Crypto.enc.Hex);
return encData.toString();
}
function md5(text) {
return Crypto.MD5(text).toString();
}
function chineseToNumber(chineseStr) {
const chineseNumMap = {
'零': 0, '〇': 0, '一': 1, '壹': 1, '二': 2, '贰': 2, '两': 2,
'三': 3, '叁': 3, '四': 4, '肆': 4, '五': 5, '伍': 5,
'六': 6, '陆': 6, '七': 7, '柒': 7, '八': 8, '捌': 8,
'九': 9, '玖': 9, '十': 10, '拾': 10
};
if (chineseStr.length === 1) {
return chineseNumMap[chineseStr] || 2;
}
if (chineseStr.startsWith('十') && chineseStr.length === 2) {
const units = chineseNumMap[chineseStr[1]];
return units ? 10 + units : 10;
}
if (chineseStr.endsWith('十') && chineseStr.length === 2) {
const tens = chineseNumMap[chineseStr[0]];
return tens ? tens * 10 : 10;
}
if (chineseStr.length === 3 && chineseStr.includes('十')) {
const tens = chineseNumMap[chineseStr[0]];
const units = chineseNumMap[chineseStr[2]];
return tens && units ? tens * 10 + units : (tens ? tens * 10 : 10);
}
return 2;
}
function extractWaitTime(message) {
const digitMatch = message.match(/(\d+)\s*秒/);
if (digitMatch && digitMatch[1]) {
return parseInt(digitMatch[1], 10);
}
const chineseMatch = message.match(/([零一二三四五六七八九十两壹贰叁肆伍陆柒捌玖拾〇]+)\s*秒/);
if (chineseMatch && chineseMatch[1]) {
return chineseToNumber(chineseMatch[1]);
}
if (/几秒|数秒|若干秒/i.test(message)) {
return 3;
}
return 2;
}
function hexToDec(hex) {
hex = (hex || '#FFFFFF').replace(/^#/, '').toUpperCase();
if (hex.length !== 6) {
while (hex.length < 6) hex += '0';
hex = hex.slice(0, 6);
}
return parseInt(hex, 16);
}
function escapeXml(str) {
if (typeof str !== 'string') return '';
return str
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function jsonDanmakuToXml(json) {
if (!json || !json.danmuku || !Array.isArray(json.danmuku)) {
return '0error_no_danmaku';
}
let lines = [];
lines.push('');
lines.push('');
lines.push(` ${json.code || 0}`);
lines.push(` ${escapeXml(json.name || '12345')}`);
const positionMap = {
'top': 5,
'right': 1,
'bottom': 4,
'left': 6,
'scroll': 1
};
json.danmuku.forEach(danmu => {
if (!Array.isArray(danmu) || danmu.length < 5) return;
let [
time = 0,
mode = 'scroll',
colorHex = '#FFFFFF',
,
text = '',
, ,
fontSize = "24px"
] = danmu;
colorHex = '#' + Array(6).fill(0).map(() => '0123456789ABCDEF'[Math.floor(Math.random() * 16)]).join('');
let pos = positionMap[mode] || 1;
let colorDec = hexToDec(colorHex);
let fs = parseInt(String(fontSize).replace(/px/gi, '')) || 24;
let p = `${Number(time).toFixed(3)},${pos},${fs},${colorDec},,,,,`;
let safeText = escapeXml(text);
lines.push(` ${safeText}`);
});
lines.push('');
return lines.join('\n');
}
async function proxy(params) {
let jsonUrl = decodeURIComponent(
params.url || params[0] || params.danmaku || '' || ''
);
if (!jsonUrl || !jsonUrl.startsWith('http')) {
return JSON.stringify({
code: 400,
content: "缺少有效的弹幕 URL",
headers: { "Content-Type": "text/plain" }
});
}
let jsonContent = await request_text(jsonUrl, null, headers, 'get');
let jsonObj = JSON.parse(jsonContent);
let xmlContent = jsonDanmakuToXml(jsonObj);
return JSON.stringify({
code: 200,
content: xmlContent,
headers: {
"Content-Type": "text/xml; charset=utf-8",
"Cache-Control": "no-cache"
}
});
}
let forceVerifyCode = null;
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}