310 lines
9.4 KiB
JavaScript
310 lines
9.4 KiB
JavaScript
/*
|
|
@header({
|
|
searchable: 1,
|
|
filterable: 1,
|
|
quickSearch: 1,
|
|
title: '聚合儿歌[儿]',
|
|
lang: 'cat'
|
|
})
|
|
*/
|
|
|
|
let siteName = '聚合儿歌', siteKey = '', siteType = 0;
|
|
|
|
const platformList = [
|
|
{ name: '贝乐虎', id: 'beilehu' },
|
|
{ name: '兔小贝', id: 'tuxiaobei' }
|
|
];
|
|
|
|
const headers = {
|
|
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
|
|
};
|
|
|
|
const rule = {
|
|
beilehu: {
|
|
host: 'https://vd.ubestkid.com',
|
|
api: '/api/v1/bv/video'
|
|
},
|
|
tuxiaobei: {
|
|
host: 'https://www.tuxiaobei.com',
|
|
listApi: '/list/mip-data',
|
|
playUrl: '/play/',
|
|
searchApi: '/search/'
|
|
}
|
|
};
|
|
|
|
const filterOptions = {
|
|
beilehu: [{
|
|
key: "area", name: "分类",
|
|
value: [
|
|
{ "n": "最新上架", "v": "65" }, { "n": "人气热播", "v": "113" }, { "n": "经典童谣", "v": "56" },
|
|
{ "n": "开心贝乐虎", "v": "137" }, { "n": "律动儿歌", "v": "53" }, { "n": "经典儿歌", "v": "59" },
|
|
{ "n": "超级汽车1", "v": "101" }, { "n": "超级汽车第二季", "v": "119" }, { "n": "超级汽车第三季", "v": "136" },
|
|
{ "n": "三字经", "v": "95" }, { "n": "幼儿手势舞", "v": "133" }, { "n": "哄睡儿歌", "v": "117" },
|
|
{ "n": "英文儿歌", "v": "70" }, { "n": "节日与节气", "v": "116" }, { "n": "恐龙世界", "v": "97" },
|
|
{ "n": "动画片儿歌", "v": "55" }, { "n": "流行歌曲", "v": "57" }, { "n": "贝乐虎入园记", "v": "118" },
|
|
{ "n": "贝乐虎大百科", "v": "106" }, { "n": "经典古诗", "v": "62" }, { "n": "经典故事", "v": "63" },
|
|
{ "n": "萌虎学功夫", "v": "128" }, { "n": "绘本故事", "v": "100" }, { "n": "开心贝乐虎英文版", "v": "121" },
|
|
{ "n": "嗨贝乐虎情商动画", "v": "96" }, { "n": "动物音乐派对", "v": "108" }, { "n": "动物音乐派对英文版", "v": "126" },
|
|
{ "n": "奇妙的身体", "v": "105" }, { "n": "奇妙的身体英文版", "v": "124" }, { "n": "认知卡片", "v": "64" },
|
|
{ "n": "趣味简笔画", "v": "109" }, { "n": "数字儿歌", "v": "78" }, { "n": "识字体验版", "v": "120" },
|
|
{ "n": "启蒙系列体验版", "v": "127" }
|
|
]
|
|
}],
|
|
tuxiaobei: [{
|
|
key: "area", name: "分类",
|
|
value: [
|
|
{ "n": "全部", "v": "" }, { "n": "儿歌", "v": "2" }, { "n": "故事", "v": "3" },
|
|
{ "n": "公益", "v": "27" }, { "n": "十万个为什么", "v": "9" }, { "n": "安全教育", "v": "28" },
|
|
{ "n": "动物奇缘", "v": "29" }, { "n": "弟子规", "v": "7" }, { "n": "古诗", "v": "5" },
|
|
{ "n": "三字经", "v": "6" }, { "n": "千字文", "v": "8" }, { "n": "数学", "v": "11" },
|
|
{ "n": "英语", "v": "25" }, { "n": "折纸", "v": "24" }
|
|
]
|
|
}]
|
|
};
|
|
|
|
const ruleFilterDef = {
|
|
beilehu: { area: '56' },
|
|
tuxiaobei: { area: '2' }
|
|
};
|
|
|
|
function init(cfg) {
|
|
siteName = cfg.skey?.split('_')[1] || cfg.skey || '聚合儿歌';
|
|
siteKey = cfg.skey;
|
|
siteType = cfg.stype;
|
|
}
|
|
|
|
function safeJSONParse(str, defaultValue = {}) {
|
|
if (!str || typeof str === 'object') return str || defaultValue;
|
|
try {
|
|
return JSON.parse(str);
|
|
} catch {
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
async function request(url, options = {}) {
|
|
const reqHeaders = { ...headers, ...options.headers };
|
|
let postType = reqHeaders['Content-Type']?.includes('json') ? 'json' :
|
|
reqHeaders['Content-Type']?.includes('form') ? 'form' : '';
|
|
|
|
try {
|
|
const response = await req(url, {
|
|
method: options.method || 'GET',
|
|
headers: reqHeaders,
|
|
data: options.data,
|
|
postType: postType,
|
|
timeout: options.timeout || 15000
|
|
});
|
|
return response?.content || response?.data || response;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function getPlatList() {
|
|
return platformList;
|
|
}
|
|
|
|
async function getBeilehuList(typeId, page) {
|
|
let videos = [];
|
|
try {
|
|
const postData = {
|
|
age: 1,
|
|
appver: "6.1.9",
|
|
egvip_status: 0,
|
|
svip_status: 0,
|
|
vps: 60,
|
|
subcateId: parseInt(typeId),
|
|
p: page
|
|
};
|
|
|
|
const html = await request(rule.beilehu.host + rule.beilehu.api, {
|
|
method: 'POST',
|
|
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
data: postData
|
|
});
|
|
|
|
const json = safeJSONParse(html);
|
|
const items = json.result?.items || [];
|
|
|
|
videos = items.map(item => ({
|
|
vod_id: `beilehu@${item.url}`,
|
|
vod_name: item.title || '未知视频',
|
|
vod_pic: item.image || '',
|
|
vod_remarks: `贝乐虎 | 播放:${item.viewcount || 0}`,
|
|
vod_content: item.description || ''
|
|
}));
|
|
} catch (e) {}
|
|
return videos;
|
|
}
|
|
|
|
async function getTuxiaobeiList(typeId, page) {
|
|
let videos = [];
|
|
try {
|
|
const url = `${rule.tuxiaobei.host}${rule.tuxiaobei.listApi}?typeId=${typeId}&page=${page}&callback=`;
|
|
const html = await request(url, { headers });
|
|
|
|
const match = html.match(/\((.*?)\);/);
|
|
if (!match) return videos;
|
|
|
|
const data = safeJSONParse(match[1]).data;
|
|
const items = data.items || [];
|
|
|
|
videos = items.map(item => ({
|
|
vod_id: `tuxiaobei@${item.video_id}`,
|
|
vod_name: item.name || '未知视频',
|
|
vod_pic: item.image || '',
|
|
vod_remarks: `兔小贝 | ${item.root_category_name || ''} ${item.duration_string || ''}`,
|
|
vod_content: item.description || ''
|
|
}));
|
|
} catch (e) {}
|
|
return videos;
|
|
}
|
|
|
|
async function getBeilehuDetail(url) {
|
|
return {
|
|
vod_id: url,
|
|
vod_name: '贝乐虎视频',
|
|
vod_remarks: '贝乐虎',
|
|
vod_play_from: '贝乐虎',
|
|
vod_play_url: `点击播放$${url}`
|
|
};
|
|
}
|
|
|
|
async function getTuxiaobeiDetail(id) {
|
|
return {
|
|
vod_id: id,
|
|
vod_name: '兔小贝视频',
|
|
vod_remarks: '兔小贝',
|
|
vod_play_from: '兔小贝',
|
|
vod_play_url: `点击播放$${rule.tuxiaobei.host}${rule.tuxiaobei.playUrl}${id}`
|
|
};
|
|
}
|
|
|
|
async function home(filter) {
|
|
const platForms = getPlatList();
|
|
const classes = platForms.map(item => ({ type_name: item.name, type_id: item.id }));
|
|
const filters = {};
|
|
platForms.forEach(item => { if (filterOptions[item.id]) filters[item.id] = filterOptions[item.id]; });
|
|
return JSON.stringify({ class: classes, filters: filters });
|
|
}
|
|
|
|
async function homeVod() {
|
|
try {
|
|
const platForms = getPlatList();
|
|
const randomPlat = platForms[Math.floor(Math.random() * platForms.length)];
|
|
const randomArea = ruleFilterDef[randomPlat.id]?.area || '';
|
|
const categoryResult = await category(randomPlat.id, 1, { area: randomArea }, {});
|
|
const categoryList = safeJSONParse(categoryResult).list || [];
|
|
return JSON.stringify({ list: categoryList.slice(0, 12) });
|
|
} catch (e) {
|
|
return JSON.stringify({ list: [] });
|
|
}
|
|
}
|
|
|
|
async function category(tid, pg, filter, extend) {
|
|
const page = pg || 1;
|
|
extend = extend || {};
|
|
|
|
const platformItem = platformList.find(p => p.id === tid);
|
|
if (!platformItem) {
|
|
return JSON.stringify({ list: [], page, pagecount: 1, limit: 0, total: 0 });
|
|
}
|
|
|
|
const searchKeyword = extend?.custom;
|
|
if (searchKeyword) {
|
|
return await cfs(tid, searchKeyword, pg);
|
|
}
|
|
|
|
const area = filter?.area || extend?.area || ruleFilterDef[tid]?.area || '';
|
|
const videos = [];
|
|
|
|
try {
|
|
switch (tid) {
|
|
case 'beilehu':
|
|
videos.push(...await getBeilehuList(area, page));
|
|
break;
|
|
case 'tuxiaobei':
|
|
videos.push(...await getTuxiaobeiList(area, page));
|
|
break;
|
|
}
|
|
} catch (e) {}
|
|
|
|
return JSON.stringify({
|
|
list: videos,
|
|
page: page,
|
|
pagecount: page + 1,
|
|
limit: videos.length,
|
|
total: videos.length * (page + 1)
|
|
});
|
|
}
|
|
|
|
async function detail(id) {
|
|
try {
|
|
const parts = id.split('@');
|
|
const platform = parts[0];
|
|
const did = parts.slice(1).join('@');
|
|
|
|
let vod = {};
|
|
if (platform === 'beilehu') {
|
|
vod = await getBeilehuDetail(did);
|
|
} else if (platform === 'tuxiaobei') {
|
|
vod = await getTuxiaobeiDetail(did);
|
|
}
|
|
return JSON.stringify({ list: [vod] });
|
|
} catch (e) {
|
|
return JSON.stringify({ list: [] });
|
|
}
|
|
}
|
|
|
|
async function play(flag, id, flags) {
|
|
try {
|
|
if (flag.includes('贝乐虎')) {
|
|
return JSON.stringify({ parse: 0, url: id, header: headers });
|
|
}
|
|
|
|
if (flag.includes('兔小贝')) {
|
|
try {
|
|
const html = await request(id, { headers });
|
|
let videoUrl = '';
|
|
|
|
const srcMatch = html.match(/video-src=["']([^"']+)["']/);
|
|
if (srcMatch) videoUrl = srcMatch[1];
|
|
|
|
if (!videoUrl) {
|
|
const sourceMatch = html.match(/<source[^>]*src=["']([^"']+)["']/);
|
|
if (sourceMatch) videoUrl = sourceMatch[1];
|
|
}
|
|
|
|
if (!videoUrl) {
|
|
const m3u8Match = html.match(/https?:\/\/[^"']+\.m3u8[^"']*/);
|
|
if (m3u8Match) videoUrl = m3u8Match[0];
|
|
}
|
|
|
|
if (!videoUrl) {
|
|
return JSON.stringify({ parse: 0, url: id, msg: '未找到播放地址' });
|
|
}
|
|
|
|
return JSON.stringify({ parse: 0, url: videoUrl, header: headers });
|
|
} catch (e) {
|
|
return JSON.stringify({ parse: 0, url: id, msg: `播放失败: ${e.message}` });
|
|
}
|
|
}
|
|
|
|
return JSON.stringify({ parse: 0, url: id });
|
|
} catch (e) {
|
|
return JSON.stringify({ parse: 0, url: id, msg: `播放失败: ${e.message}` });
|
|
}
|
|
}
|
|
|
|
async function cfs(siteId, wd, pg) {
|
|
return JSON.stringify({ list: [], page: pg || 1, pagecount: 1, limit: 0, total: 0 });
|
|
}
|
|
|
|
async function search(wd, quick, pg) {
|
|
return JSON.stringify({ list: [], page: pg || 1, pagecount: 1, limit: 0, total: 0 });
|
|
}
|
|
|
|
export function __jsEvalReturn() {
|
|
return { init, home, homeVod, category, detail, play, search };
|
|
} |