Add files via upload
This commit is contained in:
parent
7661aecbfc
commit
3ec10f3aef
419
JN/dr_py/js/直播转点播[合].js
Normal file
419
JN/dr_py/js/直播转点播[合].js
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
/**
|
||||||
|
* 支持本地包直播链接
|
||||||
|
* 传参 ?type=url¶ms=../json/live2cms.json
|
||||||
|
live2cms.json
|
||||||
|
支持m3u类直播,支持线路归并。支持筛选切换显示模式
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "GitHub",
|
||||||
|
"url": "https://ghproxy.net/https://raw.githubusercontent.com/ssili126/tv/main/itvlist.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CNTV",
|
||||||
|
"url": "./live_cntv.txt"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* m3u直播格式转一般直播格式
|
||||||
|
* @param m3u
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function convertM3uToNormal(m3u) {
|
||||||
|
try {
|
||||||
|
const lines = m3u.split('\n');
|
||||||
|
let result = '';
|
||||||
|
let TV = '';
|
||||||
|
// let flag='#genre#';
|
||||||
|
let flag = '#m3u#';
|
||||||
|
let currentGroupTitle = '';
|
||||||
|
lines.forEach((line) => {
|
||||||
|
if (line.startsWith('#EXTINF:')) {
|
||||||
|
const groupTitle = line.split('"')[1].trim();
|
||||||
|
TV = line.split('"')[2].substring(1);
|
||||||
|
if (currentGroupTitle !== groupTitle) {
|
||||||
|
currentGroupTitle = groupTitle;
|
||||||
|
result += `\n${currentGroupTitle},${flag}\n`;
|
||||||
|
}
|
||||||
|
} else if (line.startsWith('http')) {
|
||||||
|
const splitLine = line.split(',');
|
||||||
|
result += `${TV}\,${splitLine[0]}\n`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result.trim()
|
||||||
|
} catch (e) {
|
||||||
|
log(`m3u直播转普通直播发生错误:${e.message}`);
|
||||||
|
return m3u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线路归类/小棉袄算法
|
||||||
|
* @param arr 数组
|
||||||
|
* @param parse 解析式
|
||||||
|
* @returns {[[*]]}
|
||||||
|
*/
|
||||||
|
function splitArray(arr, parse) {
|
||||||
|
parse = parse && typeof (parse) == 'function' ? parse : '';
|
||||||
|
let result = [[arr[0]]];
|
||||||
|
for (let i = 1; i < arr.length; i++) {
|
||||||
|
let index = -1;
|
||||||
|
for (let j = 0; j < result.length; j++) {
|
||||||
|
if (parse && result[j].map(parse).includes(parse(arr[i]))) {
|
||||||
|
index = j;
|
||||||
|
} else if ((!parse) && result[j].includes(arr[i])) {
|
||||||
|
index = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index >= result.length - 1) {
|
||||||
|
result.push([]);
|
||||||
|
result[result.length - 1].push(arr[i]);
|
||||||
|
} else {
|
||||||
|
result[index + 1].push(arr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索结果生成分组字典
|
||||||
|
* @param arr
|
||||||
|
* @param parse x=>x.split(',')[0]
|
||||||
|
* @returns {{}}
|
||||||
|
*/
|
||||||
|
function gen_group_dict(arr, parse) {
|
||||||
|
let dict = {};
|
||||||
|
arr.forEach((it) => {
|
||||||
|
let k = it.split(',')[0];
|
||||||
|
if (parse && typeof (parse) === 'function') {
|
||||||
|
k = parse(k);
|
||||||
|
}
|
||||||
|
if (!dict[k]) {
|
||||||
|
dict[k] = [it];
|
||||||
|
} else {
|
||||||
|
dict[k].push(it);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return dict
|
||||||
|
}
|
||||||
|
|
||||||
|
globalThis.convertM3uToNormal = convertM3uToNormal;
|
||||||
|
globalThis.splitArray = splitArray;
|
||||||
|
globalThis.gen_group_dict = gen_group_dict;
|
||||||
|
globalThis.getRandomItem = function (items) {//从列表随机取出一个元素
|
||||||
|
return items[Math.random() * items.length | 0];
|
||||||
|
}
|
||||||
|
globalThis.__ext = {data_dict: {}};
|
||||||
|
var rule = {
|
||||||
|
title: '直播转点播[合]',
|
||||||
|
author: '道长',
|
||||||
|
version: '20240627 beta3',
|
||||||
|
update_info: `
|
||||||
|
20240627 beta1:
|
||||||
|
1.将原drpy项目的live2cms.js转换成hipy传参源。
|
||||||
|
【特别说明】支持m3u和txt的直播
|
||||||
|
`,
|
||||||
|
host: '',
|
||||||
|
homeUrl: '',
|
||||||
|
searchUrl: '#wd=**&pg=#TruePage##page=fypage',
|
||||||
|
url: 'fyclass#pg=fypage&t=fyfilter',
|
||||||
|
filter_url: '{{fl.show}}',
|
||||||
|
headers: {'User-Agent': 'MOBILE_UA'},
|
||||||
|
timeout: 5000, // class_name: '电影&电视剧&综艺&动漫',
|
||||||
|
limit: 20,
|
||||||
|
search_limit: 5, // 搜索限制取前5个,可以注释掉,就不限制搜索
|
||||||
|
searchable: 1,//是否启用全局搜索,
|
||||||
|
quickSearch: 0,//是否启用快速搜索,
|
||||||
|
filterable: 1,//是否启用分类筛选,
|
||||||
|
play_parse: true,
|
||||||
|
// params: 'http://127.0.0.1:5707/files/json/live2cms.json',
|
||||||
|
// 下面自定义一些源的配置
|
||||||
|
def_pic: 'https://avatars.githubusercontent.com/u/97389433?s=120&v=4', //默认列表图片
|
||||||
|
showMode: 'groups',// groups按组分类显示 all全部一条线路展示
|
||||||
|
groupDict: {},// 搜索分组字典
|
||||||
|
tips: '', //二级提示信息
|
||||||
|
预处理: $js.toString(() => {
|
||||||
|
// 初始化保存的数据
|
||||||
|
rule.showMode = getItem('showMode', 'groups');
|
||||||
|
rule.groupDict = JSON.parse(getItem('groupDict', '{}'));
|
||||||
|
rule.tips = `道长直播转点播js-当前版本${rule.version}`;
|
||||||
|
|
||||||
|
if (typeof (batchFetch) === 'function') {
|
||||||
|
// 支持批量请求直接放飞自我。搜索限制最大线程数量16
|
||||||
|
rule.search_limit = 16;
|
||||||
|
log('当前程序支持批量请求[batchFetch],搜索限制已设置为16');
|
||||||
|
}
|
||||||
|
let _url = rule.params;
|
||||||
|
if (_url && typeof (_url) === 'string' && /^(http|file)/.test(_url)) {
|
||||||
|
let html = request(_url);
|
||||||
|
let json = JSON.parse(html);
|
||||||
|
|
||||||
|
let _classes = [];
|
||||||
|
rule.filter = {};
|
||||||
|
rule.filter_def = {};
|
||||||
|
json.forEach(it => {
|
||||||
|
if (it.url && !/^(http|file)/.test(it.url)) {
|
||||||
|
it.url = urljoin(_url, it.url);
|
||||||
|
}
|
||||||
|
let _obj = {
|
||||||
|
type_name: it.name,
|
||||||
|
type_id: it.url,
|
||||||
|
img: it.img,
|
||||||
|
};
|
||||||
|
_classes.push(_obj);
|
||||||
|
let json1 = [{'n': '多线路分组', 'v': 'groups'}, {'n': '单线路', 'v': 'all'}];
|
||||||
|
try {
|
||||||
|
rule.filter[_obj.type_id] = [
|
||||||
|
{'key': 'show', 'name': '播放展示', 'value': json1}
|
||||||
|
];
|
||||||
|
if (json1.length > 0) {
|
||||||
|
rule.filter_def[it.url] = {"show": json1[0].v};
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
rule.filter[it.url] = json1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
__ext.data = json;
|
||||||
|
rule.classes = _classes;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
class_parse: $js.toString(() => {
|
||||||
|
input = rule.classes;
|
||||||
|
}),
|
||||||
|
推荐: $js.toString(() => {
|
||||||
|
let update_info = [{
|
||||||
|
vod_name: '更新日志',
|
||||||
|
vod_id: 'update_info',
|
||||||
|
vod_remarks: `版本:${rule.version}`,
|
||||||
|
vod_pic: 'https://ghproxy.net/https://raw.githubusercontent.com/hjdhnx/hipy-server/master/app/static/img/logo.png'
|
||||||
|
}];
|
||||||
|
VODS = [];
|
||||||
|
if (rule.classes) {
|
||||||
|
let randomClass = getRandomItem(rule.classes);
|
||||||
|
let _get_url = randomClass.type_id;
|
||||||
|
// let current_vod = rule.classes.find(item => item.type_id === _get_url);
|
||||||
|
// let _pic = current_vod ? current_vod.img : '';
|
||||||
|
let _pic = randomClass.img;
|
||||||
|
let html;
|
||||||
|
if (__ext.data_dict[_get_url]) {
|
||||||
|
html = __ext.data_dict[_get_url];
|
||||||
|
} else {
|
||||||
|
html = request(_get_url);
|
||||||
|
if (/#EXTM3U/.test(html)) {
|
||||||
|
html = convertM3uToNormal(html);
|
||||||
|
}
|
||||||
|
__ext.data_dict[_get_url] = html;
|
||||||
|
}
|
||||||
|
let arr = html.match(/.*?[,,]#[\s\S].*?#/g); // 可能存在中文逗号
|
||||||
|
try {
|
||||||
|
arr.forEach(it => {
|
||||||
|
let vname = it.split(/[,,]/)[0];
|
||||||
|
let vtab = it.match(/#(.*?)#/)[0];
|
||||||
|
VODS.push({
|
||||||
|
vod_name: vname,
|
||||||
|
vod_id: _get_url + '$' + vname,
|
||||||
|
vod_pic: _pic || rule.def_pic,
|
||||||
|
vod_remarks: vtab,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
log(`直播转点播获取首页推荐发送错误:${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VODS = update_info.concat(VODS);
|
||||||
|
}),
|
||||||
|
一级: $js.toString(() => {
|
||||||
|
VODS = [];
|
||||||
|
// 一级限制页数不允许翻页
|
||||||
|
if (rule.classes && MY_PAGE <= 1) {
|
||||||
|
if (MY_FL.show) {
|
||||||
|
rule.showMode = MY_FL.show;
|
||||||
|
setItem('showMode', rule.showMode);
|
||||||
|
}
|
||||||
|
let _get_url = input.split('#')[0];
|
||||||
|
let current_vod = rule.classes.find(item => item.type_id === MY_CATE);
|
||||||
|
let _pic = current_vod ? current_vod.img : '';
|
||||||
|
let html;
|
||||||
|
if (__ext.data_dict[_get_url]) {
|
||||||
|
html = __ext.data_dict[_get_url];
|
||||||
|
} else {
|
||||||
|
html = request(_get_url);
|
||||||
|
if (/#EXTM3U/.test(html)) {
|
||||||
|
html = convertM3uToNormal(html);
|
||||||
|
}
|
||||||
|
__ext.data_dict[_get_url] = html;
|
||||||
|
}
|
||||||
|
let arr = html.match(/.*?[,,]#[\s\S].*?#/g); // 可能存在中文逗号
|
||||||
|
try {
|
||||||
|
arr.forEach(it => {
|
||||||
|
let vname = it.split(/[,,]/)[0];
|
||||||
|
let vtab = it.match(/#(.*?)#/)[0];
|
||||||
|
VODS.push({
|
||||||
|
// vod_name:it.split(',')[0],
|
||||||
|
vod_name: vname,
|
||||||
|
vod_id: _get_url + '$' + vname,
|
||||||
|
vod_pic: _pic || rule.def_pic,
|
||||||
|
vod_remarks: vtab,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
log(`直播转点播获取一级分类页发生错误:${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
二级: $js.toString(() => {
|
||||||
|
VOD = {};
|
||||||
|
if (orId === 'update_info') {
|
||||||
|
VOD = {
|
||||||
|
vod_content: rule.update_info.trim(),
|
||||||
|
vod_name: '更新日志',
|
||||||
|
type_name: '更新日志',
|
||||||
|
vod_pic: 'https://resource-cdn.tuxiaobei.com/video/FtWhs2mewX_7nEuE51_k6zvg6awl.png',
|
||||||
|
vod_remarks: `版本:${rule.version}`,
|
||||||
|
vod_play_from: '道长在线',
|
||||||
|
// vod_play_url: '嗅探播放$https://resource-cdn.tuxiaobei.com/video/10/8f/108fc9d1ac3f69d29a738cdc097c9018.mp4',
|
||||||
|
vod_play_url: '随机小视频$http://api.yujn.cn/api/zzxjj.php',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
if (rule.classes) {
|
||||||
|
let _get_url = orId.split('$')[0];
|
||||||
|
let _tab = orId.split('$')[1];
|
||||||
|
if (orId.includes('#search#')) {
|
||||||
|
let vod_name = _tab.replace('#search#', '');
|
||||||
|
let vod_play_from = '来自搜索';
|
||||||
|
vod_play_from += `:${_get_url}`;
|
||||||
|
let vod_play_url = rule.groupDict[_get_url].map(x => x.replace(',', '$')).join('#');
|
||||||
|
log(orId);
|
||||||
|
VOD = {
|
||||||
|
vod_name: '搜索:' + vod_name,
|
||||||
|
type_name: "直播列表",
|
||||||
|
vod_pic: rule.def_pic,
|
||||||
|
// vod_content: orId,
|
||||||
|
vod_content: orId.replace(getHome(orId), 'http://***'),
|
||||||
|
vod_play_from: vod_play_from,
|
||||||
|
vod_play_url: vod_play_url,
|
||||||
|
vod_director: rule.tips,
|
||||||
|
vod_remarks: rule.tips,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let current_vod = rule.classes.find(item => item.type_id === _get_url);
|
||||||
|
let _pic = current_vod ? current_vod.img : '';
|
||||||
|
let html;
|
||||||
|
if (__ext.data_dict[_get_url]) {
|
||||||
|
html = __ext.data_dict[_get_url];
|
||||||
|
} else {
|
||||||
|
html = request(_get_url);
|
||||||
|
if (/#EXTM3U/.test(html)) {
|
||||||
|
html = convertM3uToNormal(html);
|
||||||
|
}
|
||||||
|
__ext.data_dict[_get_url] = html;
|
||||||
|
}
|
||||||
|
let a = new RegExp(`.*?${_tab.replace('(','\\(').replace(')','\\)')}[,,]#[\\s\\S].*?#`);
|
||||||
|
let b = html.match(a)[0];
|
||||||
|
let c = html.split(b)[1];
|
||||||
|
if (c.match(/.*?[,,]#[\s\S].*?#/)) {
|
||||||
|
let d = c.match(/.*?[,,]#[\s\S].*?#/)[0];
|
||||||
|
c = c.split(d)[0];
|
||||||
|
}
|
||||||
|
let arr = c.trim().split('\n');
|
||||||
|
let _list = [];
|
||||||
|
arr.forEach((it) => {
|
||||||
|
if (it.trim()) {
|
||||||
|
let t = it.trim().split(',')[0];
|
||||||
|
let u = it.trim().split(',')[1];
|
||||||
|
_list.push(t + '$' + u);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let vod_name = __ext.data.find(x => x.url === _get_url).name;
|
||||||
|
let vod_play_url;
|
||||||
|
let vod_play_from;
|
||||||
|
|
||||||
|
if (rule.showMode === 'groups') {
|
||||||
|
let groups = splitArray(_list, x => x.split('$')[0]);
|
||||||
|
let tabs = [];
|
||||||
|
for (let i = 0; i < groups.length; i++) {
|
||||||
|
if (i === 0) {
|
||||||
|
tabs.push(vod_name + '1');
|
||||||
|
} else {
|
||||||
|
tabs.push(` ${i + 1} `);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vod_play_url = groups.map(it => it.join('#')).join('$$$');
|
||||||
|
vod_play_from = tabs.join('$$$');
|
||||||
|
} else {
|
||||||
|
vod_play_url = _list.join('#');
|
||||||
|
vod_play_from = vod_name;
|
||||||
|
}
|
||||||
|
log(orId);
|
||||||
|
VOD = {
|
||||||
|
vod_id: orId,
|
||||||
|
vod_name: vod_name + '|' + _tab,
|
||||||
|
type_name: "直播列表",
|
||||||
|
vod_pic: _pic || rule.def_pic,
|
||||||
|
// vod_content: orId,
|
||||||
|
vod_content: orId.replace(getHome(orId), 'http://***'),
|
||||||
|
vod_play_from: vod_play_from,
|
||||||
|
vod_play_url: vod_play_url,
|
||||||
|
vod_director: rule.tips,
|
||||||
|
vod_remarks: rule.tips,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
搜索: $js.toString(() => {
|
||||||
|
VODS = [];
|
||||||
|
if (rule.classes && MY_PAGE <= 1) {
|
||||||
|
let _get_url = __ext.data[0].url;
|
||||||
|
let current_vod = rule.classes.find(item => item.type_id === _get_url);
|
||||||
|
let _pic = current_vod ? current_vod.img : '';
|
||||||
|
let html;
|
||||||
|
if (__ext.data_dict[_get_url]) {
|
||||||
|
html = __ext.data_dict[_get_url];
|
||||||
|
} else {
|
||||||
|
html = request(_get_url);
|
||||||
|
if (/#EXTM3U/.test(html)) {
|
||||||
|
html = convertM3uToNormal(html);
|
||||||
|
}
|
||||||
|
__ext.data_dict[_get_url] = html;
|
||||||
|
}
|
||||||
|
let str = '';
|
||||||
|
Object.keys(__ext.data_dict).forEach(() => {
|
||||||
|
str += __ext.data_dict[_get_url];
|
||||||
|
});
|
||||||
|
let links = str.split('\n').filter(it => it.trim() && it.includes(',') && it.split(',')[1].trim().startsWith('http'));
|
||||||
|
links = links.map(it => it.trim());
|
||||||
|
let plays = Array.from(new Set(links));
|
||||||
|
log('搜索关键词:' + KEY);
|
||||||
|
log('过滤前:' + plays.length);
|
||||||
|
// plays = plays.filter(it => it.includes(KEY));
|
||||||
|
plays = plays.filter(it => new RegExp(KEY, 'i').test(it));
|
||||||
|
log('过滤后:' + plays.length);
|
||||||
|
log(plays);
|
||||||
|
let new_group = gen_group_dict(plays);
|
||||||
|
rule.groupDict = Object.assign(rule.groupDict, new_group);
|
||||||
|
// 搜索分组结果存至本地方便二级调用
|
||||||
|
setItem('groupDict', JSON.stringify(rule.groupDict));
|
||||||
|
// 返回的还是搜索的new_group
|
||||||
|
Object.keys(new_group).forEach((it) => {
|
||||||
|
VODS.push({
|
||||||
|
'vod_name': it,
|
||||||
|
'vod_id': it + '$' + KEY + '#search#',
|
||||||
|
'vod_pic': _pic || rule.def_pic,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
lazy: $js.toString(() => {
|
||||||
|
if (/\.(m3u8|mp4)/.test(input)) {
|
||||||
|
input = {parse: 0, url: input}
|
||||||
|
} else if (/yangshipin/.test(input)) {
|
||||||
|
input = {parse: 1, url: input, js: '', header: {'User-Agent': PC_UA}, parse_extra: '&is_pc=1'};
|
||||||
|
} else {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user