Sync all projects
This commit is contained in:
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
@header({
|
||||
searchable: 1,
|
||||
filterable: 0,
|
||||
quickSearch: 1,
|
||||
title: '百度短剧',
|
||||
lang: 'cat'
|
||||
})
|
||||
*/
|
||||
import { Crypto as CryptoJS } from 'assets://js/lib/cat.js';
|
||||
|
||||
let key = '百度短剧';
|
||||
let siteName = '';
|
||||
let siteKey = '';
|
||||
let siteType = 0;
|
||||
let shuaCache = [];
|
||||
|
||||
let UA = "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36";
|
||||
let clarity_order = {'蓝光': 1, '超清': 2, '标清': 3};
|
||||
|
||||
// ==================== URL配置集中管理 ====================
|
||||
let rule = {
|
||||
host: 'https://mbd.baidu.com',
|
||||
detailHost: 'https://sv.baidu.com',
|
||||
listUrl: '/feedapi/v1/videoserver/playlets/list?service=bdbox',
|
||||
searchUrl: '/feedapi/v1/videoserver/playlets/search?service=bdbox',
|
||||
detailUrl: '/haokan/ui-video/playlet/rec/detail?log=vhk&tn=1020970b&ctn=1008350n&blur=1',
|
||||
playUrl: '/appui/api?cmd=video/relate&log=vhk&tn=1020970b&ctn=1008350n&blur=1',
|
||||
};
|
||||
|
||||
function init(cfg) {
|
||||
siteName = (cfg.skey?.split('_')[1] || cfg.skey) || (cfg.key?.split('_')[1] || cfg.key) || '未知';
|
||||
siteKey = cfg.skey;
|
||||
siteType = cfg.stype;
|
||||
}
|
||||
|
||||
function home(filter) {
|
||||
let he = ["全部", "新剧", "限时免费", "精选", "独播"];
|
||||
let ticailist = [
|
||||
"神医", "连续剧", "都市", "现代言情", "异能", "逆袭", "甜宠", "总裁", "萌宝", "战神", "宫斗宅斗", "神豪",
|
||||
"虐恋", "闪婚", "玄幻", "穿越重生", "年代", "家庭伦理", "古代言情", "武侠武打", "赘婿", "单元剧", "青春校园",
|
||||
"历史架空", "王妃", "鉴宝", "科幻", "军旅战争", "种田"
|
||||
];
|
||||
|
||||
let classes = he.map(name => ({
|
||||
type_id: name,
|
||||
type_name: name
|
||||
}));
|
||||
|
||||
classes = classes.concat(ticailist.map(name => ({
|
||||
type_id: name === "全部" ? "全部题材" : name,
|
||||
type_name: name
|
||||
})));
|
||||
|
||||
return JSON.stringify({
|
||||
class: classes,
|
||||
filters: {}
|
||||
});
|
||||
}
|
||||
|
||||
async function homeVod() {
|
||||
const categoryResult = await category('新剧', 1, {}, {});
|
||||
const categoryList = JSON.parse(categoryResult).list;
|
||||
|
||||
return JSON.stringify({
|
||||
list: [
|
||||
{
|
||||
vod_id: 'shua',
|
||||
vod_name: '发现精彩',
|
||||
vod_pic: 'https://t8.baidu.com/it/u=615012979,225344800&fm=193'
|
||||
},
|
||||
...categoryList
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并请求函数 - 统一处理 data 和 body,支持 form-urlencoded 和 JSON
|
||||
*/
|
||||
async function request(url, options = {}) {
|
||||
try {
|
||||
console.log(`【${siteName}】${options.method || 'GET'} ${url.split('?')[0]}`);
|
||||
|
||||
// 准备基础配置
|
||||
let requestConfig = {
|
||||
method: options.method || 'GET',
|
||||
headers: { "User-Agent": UA, ...options.headers }
|
||||
};
|
||||
|
||||
// 获取内容类型
|
||||
let contentType = requestConfig.headers['Content-Type'] || '';
|
||||
|
||||
// 辅助函数:将对象转换为字符串
|
||||
function stringifyData(data, format) {
|
||||
if (format.includes('json')) {
|
||||
return JSON.stringify(data);
|
||||
} else {
|
||||
// 默认 form-urlencoded
|
||||
const parts = [];
|
||||
for (let key in data) {
|
||||
let value = data[key];
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
|
||||
}
|
||||
return parts.join('&');
|
||||
}
|
||||
}
|
||||
|
||||
// 处理数据 - 无论 data 还是 body,统一处理
|
||||
let requestData = options.data || options.body;
|
||||
|
||||
if (requestData) {
|
||||
if (typeof requestData === 'string') {
|
||||
// 已经是字符串,直接使用
|
||||
requestConfig.body = requestData;
|
||||
} else if (typeof requestData === 'object') {
|
||||
// 对象,根据内容类型转换
|
||||
if (!contentType) {
|
||||
// 没有指定内容类型,默认 form-urlencoded
|
||||
contentType = 'application/x-www-form-urlencoded';
|
||||
requestConfig.headers['Content-Type'] = contentType;
|
||||
}
|
||||
requestConfig.body = stringifyData(requestData, contentType);
|
||||
}
|
||||
}
|
||||
|
||||
const res = await req(url, requestConfig);
|
||||
return res.content || '';
|
||||
} catch (e) {
|
||||
console.log(`【${siteName}】请求失败: ${e.message}`);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
async function category(tid, pg, filter, extend) {
|
||||
pg = pg <= 0 ? 1 : pg;
|
||||
let sub = ["新剧", "限时免费", "精选", "独播"].includes(tid) ? tid : "新剧";
|
||||
let tcsub = tid === "全部" || tid === "全部题材" ? "" : tid;
|
||||
|
||||
let t = Math.floor(Date.now() / 1000);
|
||||
let version = await md5(t + "v2");
|
||||
|
||||
// 直接传对象
|
||||
let postData = {
|
||||
'data': {
|
||||
"data": {
|
||||
"extRequest": { "flow_tabid": "13" },
|
||||
"from": "feed",
|
||||
"page": "channel_video_landing",
|
||||
"pd": "feed",
|
||||
"refreshIndex": pg,
|
||||
"cursor": "",
|
||||
"theme": "",
|
||||
"timestamp": t,
|
||||
"version": version,
|
||||
"themes": [
|
||||
{ "kind": "综合", "names": [sub] },
|
||||
{ "kind": "题材", "names": [tcsub] }
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let html = await request(`${rule.host}${rule.listUrl}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Connection": "Keep-Alive",
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
data: postData // 可以用 data
|
||||
});
|
||||
|
||||
let res = JSON.parse(html);
|
||||
let items = res.data.items;
|
||||
|
||||
let videos = items.map(it => ({
|
||||
vod_id: it.collId,
|
||||
vod_name: it.title,
|
||||
vod_pic: it.img,
|
||||
vod_remarks: it.updateStatus,
|
||||
vod_content: it.description
|
||||
}));
|
||||
|
||||
return JSON.stringify({
|
||||
page: pg,
|
||||
pagecount: pg + 1,
|
||||
limit: 20,
|
||||
total: items.length * (pg + 1),
|
||||
list: videos
|
||||
});
|
||||
}
|
||||
|
||||
async function detail(id) {
|
||||
if (id === 'shua') {
|
||||
return JSON.stringify({
|
||||
list: [{
|
||||
vod_id: 'shua',
|
||||
vod_name: '发现精彩',
|
||||
vod_pic: 'https://t8.baidu.com/it/u=615012979,225344800&fm=193',
|
||||
vod_play_from: '百度短剧',
|
||||
vod_play_url: '刷刷看$shua',
|
||||
vod_tag: '[SHUA][JUMP][V]'
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
// 也可以用 body
|
||||
let html = await request(`${rule.detailHost}${rule.detailUrl}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: { // body 传对象也会自动处理
|
||||
playlet_id: id,
|
||||
vid: "undefined"
|
||||
}
|
||||
});
|
||||
|
||||
let res = JSON.parse(html);
|
||||
let dthtml = res.data;
|
||||
let vids = dthtml.vid_list;
|
||||
let playArr = vids.map((vid, index) => `第${index + 1}集$${vid}`);
|
||||
|
||||
const vod = {
|
||||
vod_id: id,
|
||||
vod_name: dthtml.playlet_title,
|
||||
vod_pic: dthtml.playlet_poster,
|
||||
vod_content: dthtml.description,
|
||||
vod_remarks: `共${vids.length}集 热度值:${dthtml.hot_value} 集数:${dthtml.episodes_num}`,
|
||||
vod_director: dthtml.tag_text,
|
||||
vod_year: dthtml.create_time,
|
||||
vod_play_from: "百度短剧",
|
||||
vod_play_url: playArr.join('#')
|
||||
};
|
||||
|
||||
return JSON.stringify({ list: [vod] });
|
||||
}
|
||||
|
||||
async function play(flag, id, flags) {
|
||||
if (id == 'shua') {
|
||||
if (shuaCache.length == 0) {
|
||||
const randomPage = getRnd(1, 20);
|
||||
const categories = ["新剧", "限时免费", "精选", "独播"];
|
||||
const randomCate = categories[Math.floor(Math.random() * categories.length)];
|
||||
|
||||
const categoryResult = await category(randomCate, randomPage, {}, {});
|
||||
const res = JSON.parse(categoryResult);
|
||||
const videos = [];
|
||||
|
||||
for (const it of res.list.slice(0, 10)) {
|
||||
const detailResult = await detail(it.vod_id);
|
||||
const detailObj = JSON.parse(detailResult);
|
||||
const vod = detailObj.list[0];
|
||||
|
||||
const match = vod.vod_remarks.match(/(\d+)/);
|
||||
const episodeCount = match[1];
|
||||
|
||||
videos.push({
|
||||
parse: 0,
|
||||
url: it.vod_id,
|
||||
shuaTitle: vod.vod_name,
|
||||
shuaDes: '共' + episodeCount + '集 | ' + vod.vod_content.replace(/\s/g, ''),
|
||||
shuaActions: { play: it.vod_id },
|
||||
errorPlayNext: true
|
||||
});
|
||||
}
|
||||
shuaCache.push(...videos);
|
||||
}
|
||||
|
||||
const cache = shuaCache.shift();
|
||||
const detailResult = await detail(cache.url);
|
||||
const detailObj = JSON.parse(detailResult);
|
||||
const vod = detailObj.list[0];
|
||||
|
||||
const playUrls = vod.vod_play_url.split('#');
|
||||
const firstEpisode = playUrls[0];
|
||||
const vid = firstEpisode.split('$')[1];
|
||||
|
||||
const playHtml = await request(`${rule.detailHost}${rule.playUrl}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
data: { // 用 data 或 body 都可以
|
||||
method: "post",
|
||||
vid: vid
|
||||
}
|
||||
});
|
||||
|
||||
const playRes = JSON.parse(playHtml);
|
||||
const playJson = playRes["video/relate"].data.cur_video;
|
||||
const urls = [];
|
||||
|
||||
for (const item of playJson.clarityUrl) {
|
||||
urls.push({
|
||||
title: item.title,
|
||||
url: item.url,
|
||||
order: clarity_order[item.title] || 999
|
||||
});
|
||||
}
|
||||
urls.sort(function (a, b) { return a.order - b.order; });
|
||||
cache.url = urls[0].url;
|
||||
|
||||
return JSON.stringify(cache);
|
||||
}
|
||||
|
||||
const html = await request(`${rule.detailHost}${rule.playUrl}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: { // body 传对象
|
||||
method: "post",
|
||||
vid: id
|
||||
}
|
||||
});
|
||||
|
||||
const res = JSON.parse(html);
|
||||
const json = res["video/relate"].data.cur_video;
|
||||
const urls = [];
|
||||
|
||||
for (const item of json.clarityUrl) {
|
||||
urls.push({
|
||||
title: item.title,
|
||||
url: item.url,
|
||||
order: clarity_order[item.title] || 999
|
||||
});
|
||||
}
|
||||
urls.sort(function (a, b) { return a.order - b.order; });
|
||||
|
||||
const flat = [];
|
||||
for (const item of urls) {
|
||||
flat.push(item.title);
|
||||
flat.push(item.url);
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
parse: 0,
|
||||
url: flat,
|
||||
header: {
|
||||
'User-Agent': UA,
|
||||
'Referer': rule.host
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function search(wd, quick, pg) {
|
||||
pg = pg <= 0 ? 1 : pg;
|
||||
|
||||
let postData = {
|
||||
'data': {
|
||||
"data": {
|
||||
"query": wd,
|
||||
"page": pg,
|
||||
"attribute": ["title"],
|
||||
"fe_page_type": "search",
|
||||
"extra": {
|
||||
"tab_id": "216",
|
||||
"flow_tabid": "13",
|
||||
"shortplay_source": "feed",
|
||||
"from": "feed",
|
||||
"tab_type": "搜索",
|
||||
"sub_template": "playlet_search_result"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let html = await request(`${rule.host}${rule.searchUrl}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Connection": "Keep-Alive",
|
||||
"Accept-Encoding": "gzip",
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
data: postData // 用 data
|
||||
});
|
||||
|
||||
let res = JSON.parse(html);
|
||||
let items = res.data.itemList;
|
||||
|
||||
let videos = items.map(it => ({
|
||||
vod_id: it.nid.split("_")[1],
|
||||
vod_name: it.title,
|
||||
vod_pic: it.img,
|
||||
vod_remarks: it.collNum + '集',
|
||||
vod_content: it.description
|
||||
}));
|
||||
|
||||
return JSON.stringify({
|
||||
page: pg,
|
||||
pagecount: pg + 1,
|
||||
limit: 20,
|
||||
total: items.length * (pg + 1),
|
||||
list: videos
|
||||
});
|
||||
}
|
||||
|
||||
function getRnd(min, max, hexNum, isUpper) {
|
||||
var r = parseInt(Math.random() * (max - min + 1) + min, 10);
|
||||
if (hexNum) {
|
||||
r = isUpper ? r.toString(hexNum).toUpperCase() : r.toString(hexNum);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
async function md5(str) {
|
||||
return CryptoJS.MD5(str).toString(CryptoJS.enc.Hex).toLowerCase();
|
||||
}
|
||||
|
||||
async function action(action, value) {
|
||||
if (action === 'shuaPlay') {
|
||||
return JSON.stringify({
|
||||
action: {
|
||||
actionId: '__detail__',
|
||||
ids: value,
|
||||
keep: true
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function __jsEvalReturn() {
|
||||
return {
|
||||
init: init,
|
||||
home: home,
|
||||
homeVod: homeVod,
|
||||
category: category,
|
||||
detail: detail,
|
||||
play: play,
|
||||
search: search,
|
||||
action: action
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user