Files
sg/open/erge_juhe.js
2026-08-14 11:23:40 +02:00

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 };
}