1308 lines
39 KiB
JavaScript
1308 lines
39 KiB
JavaScript
import {
|
||
distance
|
||
} from "./mod.js";
|
||
import {
|
||
sortListByCN
|
||
} from "./sortName.js";
|
||
import cheerio from "assets://js/lib/cheerio.min.js"
|
||
String.prototype.rstrip = function(chars) {
|
||
let regex = new RegExp(chars + "$");
|
||
return this.replace(regex, "")
|
||
};
|
||
var showMode = "single";
|
||
var searchDriver = "";
|
||
var search_type = "";
|
||
var detail_order = "name";
|
||
var __poster_mode = true;
|
||
var __filter_data = null;
|
||
let __imageServer = "https://"
|
||
let __imageSource = '@Referer=https://api.douban.com/@User-Agent=Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/113.0.0.0%20Safari/537.36';
|
||
const __folder_img = "https://pic.616pic.com/ys_bnew_img/00/46/91/Kduke9oSev.jpg";
|
||
const __play_list_img = "https://pic.616pic.com/ys_bnew_img/00/24/42/xp3ozLGSm4.jpg";
|
||
const __num = "200";
|
||
const request_timeout = 10000;
|
||
const VERSION = "alist v2/v3 202402020830";
|
||
|
||
function print(any) {
|
||
any = any || "";
|
||
if (typeof any == "object" && Object.keys(any).length > 0) {
|
||
try {
|
||
any = JSON.stringify(any);
|
||
console.log(any)
|
||
} catch (e) {
|
||
console.log(typeof any + ":" + any.length)
|
||
}
|
||
} else if (typeof any == "object" && Object.keys(any).length < 1) {
|
||
console.log("null object")
|
||
} else {
|
||
console.log(any)
|
||
}
|
||
}
|
||
const http = function(url, options = {},noAuth = false,timeout = request_timeout) {
|
||
if (options.method === "POST" && options.data) {
|
||
options.body = JSON.stringify(options.data);
|
||
options.headers = Object.assign({
|
||
"content-type": "application/json"
|
||
}, options.headers);
|
||
if (!noAuth){
|
||
options.headers = Object.assign({
|
||
'Authorization': 'alist-09ceb38a-f143-47f7-b255-c3eec819cd7b8RfQ6P4fxESnlox2sKdJQqlPfDrWzbgSOIqyFAmIlHmUFrcQ97CSr5yoGA5wkw70'
|
||
}, options.headers);
|
||
}
|
||
}
|
||
options.timeout = timeout;
|
||
try {
|
||
const res = req(url, options);
|
||
res.json = () => res && res.content ? JSON.parse(res.content) : null;
|
||
res.text = () => res && res.content ? res.content : "";
|
||
return res
|
||
} catch (e) {
|
||
return {
|
||
json() {
|
||
return null
|
||
},
|
||
text() {
|
||
return ""
|
||
}
|
||
}
|
||
}
|
||
};
|
||
["get", "post"].forEach(method => {
|
||
http[method] = function(url, options = {},noAuth = false,timeout = request_timeout) {
|
||
return http(url, Object.assign(options, {
|
||
method: method.toUpperCase()
|
||
}),noAuth,timeout)
|
||
}
|
||
});
|
||
const __drives = {};
|
||
|
||
function isMedia(file) {
|
||
return /\.(dff|dsf|mp3|aac|wav|wma|cda|flac|m4a|mid|mka|mp2|mpa|mpc|ape|ofr|ogg|ra|wv|tta|ac3|dts|tak|webm|wmv|mpeg|mov|ram|swf|mp4|avi|rm|rmvb|flv|mpg|mkv|m3u8|ts|3gp|asf)$/.test(file.toLowerCase())
|
||
}
|
||
|
||
function get_drives_path(tid) {
|
||
const index = tid.indexOf("$");
|
||
const name = tid.substring(0, index);
|
||
const path = tid.substring(index + 1);
|
||
return {
|
||
drives: get_drives(name),
|
||
path: path
|
||
}
|
||
}
|
||
|
||
function get_drives(name) {
|
||
const {
|
||
settings,
|
||
api,
|
||
server
|
||
} = __drives[name];
|
||
if (settings.v3 == null) {
|
||
settings.title = "小雅的分类 Alist";
|
||
settings.v3 = true;
|
||
settings.version = "小雅魔改版";
|
||
settings.enableSearch = false
|
||
api.path = settings.v3 ? "/api/fs/list" : "/api/public/path";
|
||
api.file = settings.v3 ? "/api/fs/get" : "/api/public/path";
|
||
api.search = settings.v3 ? "/api/public/search" : "/api/public/search"
|
||
}
|
||
return __drives[name]
|
||
}
|
||
|
||
function init(ext) {
|
||
console.log("当前版本号:" + VERSION);
|
||
let data;
|
||
if (typeof ext == "object") {
|
||
data = ext;
|
||
print("alist ext:object")
|
||
} else if (typeof ext == "string") {
|
||
if (ext.startsWith("http")) {
|
||
let alist_data = ext.split(";");
|
||
let alist_data_url = alist_data[0];
|
||
search_type = alist_data.length > 2 ? alist_data[2] : search_type;
|
||
print(alist_data_url);
|
||
data = http.get(alist_data_url).json()
|
||
} else {
|
||
print("alist ext:json string");
|
||
data = JSON.parse(ext)
|
||
}
|
||
}
|
||
let drives = [];
|
||
if (Array.isArray(data) && data.length > 0 && data[0].hasOwnProperty("server") && data[0].hasOwnProperty("name")) {
|
||
drives = data
|
||
} else if (!Array.isArray(data) && data.hasOwnProperty("drives") && Array.isArray(data.drives)) {
|
||
drives = data.drives.filter(it => it.type && it.type === "alist" || !it.type)
|
||
}
|
||
print(drives);
|
||
__poster_mode = true;
|
||
searchDriver = (drives.find(x => x.search) || {}).name || "";
|
||
if (!searchDriver && drives.length > 0) {
|
||
searchDriver = drives[0].name
|
||
__poster_mode = false;
|
||
}
|
||
print(searchDriver);
|
||
drives.forEach(item => {
|
||
let _path_param = [];
|
||
if (item.params) {
|
||
_path_param = Object.keys(item.params);
|
||
_path_param.sort((a, b) => a.length - b.length)
|
||
}
|
||
let servers = item.server.split(";");
|
||
servers.forEach((server, index, array) => {
|
||
array[index] = server.replace(/\/$/, '');
|
||
});
|
||
let server = servers[0];
|
||
__drives[item.name] = {
|
||
name: item.name,
|
||
server: server,
|
||
servers: servers,
|
||
startPage: item.startPage || "/",
|
||
showAll: item.showAll === true,
|
||
search: !!item.search,
|
||
noAuth: !!item.noAuth,
|
||
noPoster: !!item.noPoster,
|
||
pathByApi: !!item.pathByApi,
|
||
isPreview: !!item.isPreview,
|
||
params: item.params || {},
|
||
_path_param: _path_param,
|
||
settings: {},
|
||
api: {},
|
||
isFullList: false,
|
||
getParams(path) {
|
||
const key = this._path_param.find(x => path.startsWith(x));
|
||
return Object.assign({}, this.params[key], {
|
||
path: path
|
||
})
|
||
},
|
||
getPath(path) {
|
||
try {
|
||
const res = http.post(this.server + this.api.path, {
|
||
data: this.getParams(path)
|
||
}, this.noAuth,5000);
|
||
return this.settings.v3 ? res.json().data.content : res.json().data.files;
|
||
} catch (error) {
|
||
}
|
||
|
||
for (const server of this.servers) {
|
||
try {
|
||
if (server !== this.server) {
|
||
const res = http.post(server + this.api.path, {
|
||
data: this.getParams(path)
|
||
}, this.noAuth,5000);
|
||
|
||
this.server = server;
|
||
return this.settings.v3 ? res.json().data.content : res.json().data.files;
|
||
}
|
||
} catch (error) {
|
||
}
|
||
}
|
||
|
||
return null;
|
||
},
|
||
getFile(path) {
|
||
let raw_url = this.server + "/d" + path;
|
||
raw_url = encodeURI(raw_url);
|
||
let previewSuccess = false;
|
||
try
|
||
{
|
||
if (isMedia(path) && this.isPreview)
|
||
{
|
||
const res = http.post(this.server + "/api/fs/other", {
|
||
data: Object.assign({},this.getParams(path),{method: "video_preview"})
|
||
}).json();
|
||
let urls = res.data.video_preview_play_info.live_transcoding_task_list;
|
||
raw_url = urls[urls.length-1].url;
|
||
previewSuccess = true;
|
||
}
|
||
}
|
||
catch(e)
|
||
{
|
||
previewSuccess = false;
|
||
raw_url = this.server + "/d" + path;
|
||
raw_url = encodeURI(raw_url);
|
||
}
|
||
|
||
if (!previewSuccess && this.pathByApi)
|
||
{
|
||
const res = http.post(this.server + "/api/fs/get", {
|
||
data: this.getParams(path)
|
||
}, this.noAuth).json();
|
||
raw_url = res.data.raw_url;
|
||
}
|
||
|
||
return {
|
||
raw_url: raw_url
|
||
}
|
||
},
|
||
isFolder(data) {
|
||
return data.type === 1
|
||
},
|
||
isVideo(data) {
|
||
return this.settings.v3 ? data.type === 2 || data.type === 0 || data.type === 3 : data.type === 3 || data.type === 0 || data.type === 4
|
||
},
|
||
is_subt(data) {
|
||
if (data.type === 1) {
|
||
return false
|
||
}
|
||
const ext = /\.(srt|ass|scc|stl|ttml)$/;
|
||
return ext.test(data.name)
|
||
},
|
||
getPic(data) {
|
||
let pic = this.settings.v3 ? data.thumb : data.thumbnail;
|
||
return pic || (this.isFolder(data) ? __folder_img : "")
|
||
},
|
||
getTime(data, isStandard) {
|
||
isStandard = isStandard || false;
|
||
try {
|
||
let tTime = data.updated_at || data.time_str || data.modified || "";
|
||
let date = "";
|
||
if (tTime) {
|
||
tTime = tTime.split("T");
|
||
date = tTime[0];
|
||
if (isStandard) {
|
||
date = date.replace(/-/g, "/")
|
||
}
|
||
tTime = tTime[1].split(/Z|\./);
|
||
date += " " + tTime[0]
|
||
}
|
||
return date
|
||
} catch (e) {
|
||
return ""
|
||
}
|
||
}
|
||
}
|
||
});
|
||
//__imageServer = __drives[searchDriver].server + "/image/";
|
||
try
|
||
{
|
||
__filter_data = http.get(__drives[searchDriver].server + "/tvbox/json/alist.filters.json").json().startPages;
|
||
}catch(e)
|
||
{
|
||
__filter_data = null;
|
||
}
|
||
print("init执行完毕")
|
||
}
|
||
|
||
function genFilters(tid){
|
||
let {
|
||
drives,
|
||
path
|
||
} = get_drives_path(tid);
|
||
if (!__poster_mode || drives.noPoster)
|
||
{
|
||
return [];
|
||
}
|
||
let values = [{
|
||
n: "全部分类",
|
||
v: "all"
|
||
}];
|
||
try
|
||
{
|
||
var data = __filter_data;
|
||
data = data.find(it => it.startPage === path).names;
|
||
data.forEach(item => {
|
||
let subpath = item;
|
||
values.push({
|
||
n: subpath,
|
||
v: subpath
|
||
});
|
||
});
|
||
} catch (e){
|
||
const list = drives.getPath(path);
|
||
list.forEach(item => {
|
||
if (drives.isFolder(item)) {
|
||
let subpath = item.name;
|
||
values.push({
|
||
n: subpath,
|
||
v: subpath
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
let filters = [{
|
||
key: "subpath",
|
||
name: "分类:",
|
||
value: values
|
||
},{
|
||
key: "douban",
|
||
name: "豆瓣评分:",
|
||
value: [{
|
||
n: "全部评分",
|
||
v: "0"
|
||
},{
|
||
n: "9分以上",
|
||
v: "9"
|
||
},{
|
||
n: "8分以上",
|
||
v: "8"
|
||
},{
|
||
n: "7分以上",
|
||
v: "7"
|
||
},{
|
||
n: "6分以上",
|
||
v: "6"
|
||
},{
|
||
n: "5分以上",
|
||
v: "5"
|
||
}]
|
||
},{
|
||
key: "doubansort",
|
||
name: "豆瓣排序:",
|
||
value: [{
|
||
n: "原始顺序",
|
||
v: "0"
|
||
},{
|
||
n: "豆瓣评分⬇️",
|
||
v: "1"
|
||
},{
|
||
n: "豆瓣评分⬆️",
|
||
v: "2"
|
||
}]
|
||
},{
|
||
key: "random",
|
||
name: "随机显示:",
|
||
value: [{
|
||
n: "固定显示",
|
||
v: "0"
|
||
},{
|
||
n: "随机显示️",
|
||
v: "9999999999"
|
||
},{
|
||
n: "随机200个️",
|
||
v: "200"
|
||
},{
|
||
n: "随机500个️",
|
||
v: "500"
|
||
}]
|
||
}];
|
||
|
||
return filters;
|
||
}
|
||
|
||
function home(filter) {
|
||
let classes = Object.keys(__drives).map(key => ({
|
||
type_id: `${key}$${__drives[key].startPage}`,
|
||
type_name: key,
|
||
type_flag: __drives[key].startPage === "/" || !__poster_mode || __drives[key].noPoster? "1" : "2"
|
||
}));
|
||
let filter_dict = {};
|
||
classes.forEach(it => {
|
||
filter_dict[it.type_id] = genFilters(it.type_id);
|
||
});
|
||
print("----home----");
|
||
print(classes);
|
||
return JSON.stringify({
|
||
class: classes,
|
||
filters: filter_dict
|
||
})
|
||
}
|
||
|
||
function homeVod(params) {
|
||
if (!searchDriver) {
|
||
return JSON.stringify({
|
||
list: []
|
||
})
|
||
} else {
|
||
let driver = __drives[searchDriver];
|
||
driver.vods = getAllVods("filter=last&num=" + __num,driver.name).list;
|
||
return JSON.stringify({
|
||
list: driver.vods
|
||
});
|
||
}
|
||
}
|
||
|
||
function parseSou(htmlContent){
|
||
const regex = /<a\s+href=([^>]*)>/g;
|
||
let matches = [];
|
||
let match;
|
||
while ((match = regex.exec(htmlContent)) !== null) {
|
||
if (match[1] === "/" || match[1] === "https://t.me/xiaoyaliu"){
|
||
continue;
|
||
}
|
||
matches.push(match[1]);
|
||
}
|
||
return matches;
|
||
}
|
||
|
||
function getAllVods (para,drivename,pg = "0",filter = false,extend={}) {
|
||
let driver = __drives[drivename];
|
||
let orgdrive = __drives[drivename];
|
||
let surl = driver.server + "/sou?" + para + "&type=video&num=" + __num;
|
||
|
||
let fl = filter ? extend : {};
|
||
let isflmode = !!fl.subpath || !!fl.doubansort || !!fl.douban || !!fl.random;
|
||
let fullList = false;
|
||
pg = parseInt(pg);
|
||
|
||
if (!pg || pg > 1 || isflmode){
|
||
surl = driver.server + "/sou?" + para + "&type=video";
|
||
fullList = true;
|
||
}
|
||
|
||
if (pg === 1 && !isflmode && orgdrive.name === "每日更新")
|
||
{
|
||
surl = driver.server + "/sou?filter=last&num=" + __num + "&type=video";
|
||
}
|
||
|
||
if (orgdrive.startPage !== "/"){
|
||
if (orgdrive.isFullList || (!fullList && orgdrive.vods != null)){
|
||
return {
|
||
list: orgdrive.vods
|
||
};
|
||
}
|
||
}
|
||
else
|
||
{
|
||
orgdrive.isFullList = true;
|
||
}
|
||
|
||
let html = http.get(surl).text();
|
||
let lists = parseSou(html);
|
||
let vods = [];
|
||
let vods_pikpak = [];
|
||
let vods_ali = [];
|
||
let excludeReg = /\.(pdf|epub|mobi|txt|doc|lrc)$/;
|
||
let pikpakRegex = /pikpak/;
|
||
let cnt = 0;
|
||
lists.forEach(it => {
|
||
let isPikpak = false;
|
||
let vhref = it;
|
||
if (vhref) {
|
||
vhref = unescape(vhref)
|
||
}
|
||
if (excludeReg.test(vhref.toLowerCase())) {
|
||
return
|
||
}
|
||
if (pikpakRegex.test(vhref.toLowerCase())) {
|
||
isPikpak = true;
|
||
}
|
||
const parts = vhref.split('#')
|
||
if (parts.length >= 2) {
|
||
vhref = parts[0]
|
||
}
|
||
cnt++;
|
||
let vid = __drives[drivename].name + "$" + vhref + "#search#";
|
||
if (showMode === "all") {
|
||
vid += "#all#"
|
||
}
|
||
|
||
let have_pic = 0;
|
||
let vod_dbid = "";
|
||
let poster = '';
|
||
let douban_rate = '';
|
||
let display_path = '';
|
||
if (parts.length === 5) {
|
||
let uri_parts = parts[4].split('://')
|
||
poster = __imageServer + uri_parts[1] + __imageSource;
|
||
have_pic = 1;
|
||
}
|
||
else{
|
||
// return
|
||
}
|
||
|
||
if (parts.length >= 4) {
|
||
douban_rate = parts[3] ;
|
||
}
|
||
if (parts.length >= 3) {
|
||
vod_dbid = parts[2] ;
|
||
}
|
||
if (parts.length < 2) {
|
||
let path_list = parts[0].split('/');
|
||
//display_path = path_list[path_list.length - 2] + '/' + path_list[path_list.length - 1];
|
||
display_path = path_list[path_list.length - 1];
|
||
}
|
||
|
||
vods = vods_ali;
|
||
if (isPikpak){
|
||
vods = vods_pikpak;
|
||
}
|
||
|
||
vods.push({
|
||
vod_id: vid,
|
||
vod_dbid: vod_dbid,
|
||
vod_name: parts.length <2 ? display_path :parts[1],
|
||
vod_tag: "file",
|
||
vod_pic: have_pic ? poster : "http://img.xiaoya.pro/xiaoya.jpg",
|
||
vod_remarks: douban_rate == '' ? "" : "豆瓣:" + douban_rate,
|
||
vod_fullpath: parts[0],
|
||
vod_poster: have_pic
|
||
});
|
||
});
|
||
|
||
vods = vods_ali.concat(vods_pikpak);
|
||
if (!orgdrive.isFullList){
|
||
orgdrive.isFullList = fullList;
|
||
}
|
||
|
||
let vods_poster = vods.filter(it => it.vod_poster);
|
||
let vods_none_poster = vods.filter(it => !it.vod_poster);
|
||
|
||
vods = vods_poster.concat(vods_none_poster);
|
||
orgdrive.vods = vods;
|
||
|
||
return {
|
||
list: vods
|
||
}
|
||
}
|
||
|
||
function removeDuplicates(arr) {
|
||
const seen = new Set();
|
||
|
||
return arr.filter((item) => {
|
||
const itemString = JSON.stringify(item);
|
||
if (!seen.has(itemString)) {
|
||
seen.add(itemString);
|
||
return true;
|
||
}
|
||
return false;
|
||
});
|
||
}
|
||
|
||
function root_category(tid, pg, filter, extend) {
|
||
let vods = [];
|
||
let orid = tid.replace(/#all#|#search#/g, "");
|
||
let {
|
||
drives,
|
||
path
|
||
} = get_drives_path(orid);
|
||
|
||
drives.vods = getAllVods("box=" + path,drives.name,pg,filter,extend).list
|
||
|
||
let fullpath = path;
|
||
let fl = filter ? extend : {};
|
||
if(fl.subpath && fl.subpath !== "all"){
|
||
fullpath = path + "/" + fl.subpath;
|
||
}
|
||
drives.vods.forEach(it => {
|
||
const pattern = new RegExp("^" + fullpath);
|
||
if (!pattern.test(it.vod_fullpath))
|
||
{
|
||
return
|
||
}
|
||
vods.push(it);
|
||
});
|
||
|
||
let douban = 0;
|
||
if(fl.douban){
|
||
douban = parseFloat(fl.douban);
|
||
}
|
||
|
||
let highRatedVods = vods.filter(vod => {
|
||
var ratingString = vod.vod_remarks.replace("豆瓣:", "").trim();
|
||
if (ratingString === ""){
|
||
ratingString="0";
|
||
}
|
||
return ratingString !== '' && parseFloat(ratingString) >= douban;
|
||
});
|
||
vods = highRatedVods;
|
||
|
||
if(fl.doubansort && fl.doubansort === "1"){
|
||
vods.sort((a, b) => {
|
||
const ratingA = parseFloat(a.vod_remarks.replace("豆瓣:", "").trim()) || 0;
|
||
const ratingB = parseFloat(b.vod_remarks.replace("豆瓣:", "").trim()) || 0;
|
||
return ratingB - ratingA;
|
||
});
|
||
}
|
||
|
||
if(fl.doubansort && fl.doubansort === "2"){
|
||
vods.sort((a, b) => {
|
||
const ratingA = parseFloat(a.vod_remarks.replace("豆瓣:", "").trim()) || 0;
|
||
const ratingB = parseFloat(b.vod_remarks.replace("豆瓣:", "").trim()) || 0;
|
||
return ratingA - ratingB;
|
||
});
|
||
}
|
||
|
||
let random = 0;
|
||
if(fl.random)
|
||
{
|
||
random = parseInt(fl.random);
|
||
}
|
||
|
||
if(random !== 0)
|
||
{
|
||
let keepsequence = (fl.doubansort && fl.doubansort !== "0");
|
||
vods = getRandomElements(vods,random,keepsequence);
|
||
}
|
||
|
||
return JSON.stringify({
|
||
page: 1,
|
||
pagecount: drives.isFullList ? 1 : 2,
|
||
//pagecount: 2,
|
||
//limit: vods.length,
|
||
//total: vods.length,
|
||
list: vods
|
||
})
|
||
}
|
||
|
||
function getRandomElements(arr, count, keepsequence) {
|
||
if (arr.length <= count) {
|
||
if (keepsequence) {
|
||
return arr.slice();
|
||
} else {
|
||
const shuffledArray = arr.slice();
|
||
for (let i = shuffledArray.length - 1; i > 0; i--) {
|
||
const j = Math.floor(Math.random() * (i + 1));
|
||
[shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]];
|
||
}
|
||
return shuffledArray;
|
||
}
|
||
}
|
||
|
||
const randomIndexes = [];
|
||
const selectedIndexes = new Set();
|
||
|
||
while (randomIndexes.length < count) {
|
||
const index = Math.floor(Math.random() * arr.length);
|
||
|
||
if (!selectedIndexes.has(index)) {
|
||
selectedIndexes.add(index);
|
||
randomIndexes.push(index);
|
||
}
|
||
}
|
||
|
||
if (keepsequence) {
|
||
randomIndexes.sort((a, b) => a - b);
|
||
}
|
||
|
||
const result = randomIndexes.map(index => arr[index]);
|
||
|
||
return result;
|
||
}
|
||
|
||
function category(tid, pg, filter, extend) {
|
||
let orid = tid.replace(/#all#|#search#/g, "");
|
||
let {
|
||
drives,
|
||
path
|
||
} = get_drives_path(orid);
|
||
|
||
if ( __poster_mode && !drives.noPoster && path !=="/" && path === drives.startPage){
|
||
return root_category(tid, pg, filter, extend);
|
||
}
|
||
|
||
const id = orid.endsWith("/") ? orid : orid + "/";
|
||
let list = null;
|
||
if (!filter && extend.list)
|
||
{
|
||
list = extend.list;
|
||
}else
|
||
{
|
||
list = drives.getPath(path);
|
||
}
|
||
let subList = [];
|
||
let vodFiles = [];
|
||
let allList = [];
|
||
let fl = filter ? extend : {};
|
||
if (fl.show) {
|
||
showMode = fl.show
|
||
}
|
||
list.forEach(item => {
|
||
if (drives.is_subt(item)) {
|
||
subList.push(item.name)
|
||
}
|
||
|
||
if ( !drives.isFolder(item) && !/\.(dff|dsf|mp3|aac|wav|wma|cda|flac|m4a|mid|mka|mp2|mpa|mpc|ape|ofr|ogg|ra|wv|tta|ac3|dts|tak|webm|wmv|mpeg|mov|ram|swf|mp4|avi|rm|rmvb|flv|mpg|mkv|m3u8|ts|3gp|asf)$/.test(item.name)){
|
||
return
|
||
}
|
||
if (!drives.showAll && !drives.isFolder(item) && !drives.isVideo(item)) {
|
||
return
|
||
}
|
||
let vod_time = drives.getTime(item);
|
||
let vod_size = get_size(item.size);
|
||
let remark = vod_time.split(" ")[0].substr(3) + "\t" + vod_size;
|
||
let vod_id = id + item.name + (drives.isFolder(item) ? "/" : "");
|
||
if (showMode === "all") {
|
||
vod_id += "#all#"
|
||
}
|
||
print(vod_id);
|
||
const vod = {
|
||
vod_id: vod_id,
|
||
vod_name: item.name.replaceAll("$", "").replaceAll("#", ""),
|
||
vod_pic: drives.getPic(item),
|
||
vod_time: vod_time,
|
||
vod_size: item.size,
|
||
vod_tag: drives.isFolder(item) ? "folder" : "file",
|
||
// vod_tag: "file",
|
||
vod_remarks: drives.isFolder(item) ? remark + " 文件夹" : remark
|
||
};
|
||
if (drives.isVideo(item)) {
|
||
vodFiles.push(vod)
|
||
}
|
||
allList.push(vod)
|
||
});
|
||
if (vodFiles.length === 1 && subList.length > 0) {
|
||
let sub;
|
||
if (subList.length === 1) {
|
||
sub = subList[0]
|
||
} else {
|
||
let subs = JSON.parse(JSON.stringify(subList));
|
||
subs.sort((a, b) => {
|
||
let a_similar = (a.includes("chs") ? 100 : 0) + levenshteinDistance(a, vodFiles[0].vod_name);
|
||
let b_similar = (b.includes("chs") ? 100 : 0) + levenshteinDistance(b, vodFiles[0].vod_name);
|
||
if (a_similar > b_similar) {
|
||
return 1
|
||
} else {
|
||
return -1
|
||
}
|
||
});
|
||
sub = subs.slice(-1)[0]
|
||
}
|
||
vodFiles[0].vod_id += "@@@" + sub;
|
||
vodFiles[0].vod_remarks += "🏷️"
|
||
} else {
|
||
vodFiles.forEach(item => {
|
||
var lh = 0;
|
||
let sub;
|
||
subList.forEach(s => {
|
||
const l = levenshteinDistance(s, item.vod_name);
|
||
if (l > 60 && l > lh) {
|
||
sub = s
|
||
lh = l;
|
||
}
|
||
});
|
||
if (sub) {
|
||
item.vod_id += "@@@" + sub;
|
||
item.vod_remarks += "🏷️"
|
||
}
|
||
})
|
||
}
|
||
if (fl.order) {
|
||
let key = fl.order.split("_").slice(0, -1).join("_");
|
||
let order = fl.order.split("_").slice(-1)[0];
|
||
print(`排序key:${key},排序order:${order}`);
|
||
if (key.includes("name")) {
|
||
detail_order = "name";
|
||
allList = sortListByName(allList, key, order)
|
||
} else if (key.includes("cn")) {
|
||
detail_order = "cn";
|
||
allList = sortListByCN(allList, "vod_name", order)
|
||
} else if (key.includes("time")) {
|
||
detail_order = "time";
|
||
allList = sortListByTime(allList, key, order)
|
||
} else if (key.includes("size")) {
|
||
detail_order = "size";
|
||
allList = sortListBySize(allList, key, order)
|
||
} else if (fl.order.includes("none")) {
|
||
detail_order = "none";
|
||
print("不排序")
|
||
}
|
||
} else {
|
||
if (detail_order !== "none") {
|
||
allList = sortListByName(allList, "vod_name", "asc")
|
||
}
|
||
}
|
||
if (pg && vodFiles.length > 1) {
|
||
const vod = {
|
||
vod_id: id + "~playlist",
|
||
vod_name: "播放列表",
|
||
vod_pic: __play_list_img,
|
||
vod_tag: "file",
|
||
vod_remarks: "共" + vodFiles.length + "集"
|
||
};
|
||
allList.unshift(vod)
|
||
}
|
||
print("----category----" + `tid:${tid},detail_order:${detail_order},showMode:${showMode}`);
|
||
return JSON.stringify({
|
||
page: 1,
|
||
pagecount: 1,
|
||
limit: allList.length,
|
||
total: allList.length,
|
||
list: allList
|
||
})
|
||
}
|
||
|
||
function getAll(otid, tid, drives, path,ls = null,nopic = false) {
|
||
try {
|
||
const content = category(tid, null, false, {list: ls});
|
||
const isFile = isMedia(otid.replace(/#all#|#search#/g, "").split("@@@")[0]);
|
||
const {
|
||
list
|
||
} = JSON.parse(content);
|
||
let vod_play_url = [];
|
||
list.forEach(x => {
|
||
if (x.vod_tag === "file") {
|
||
let vid = x.vod_id.replace(/#all#|#search#/g, "");
|
||
vod_play_url.push(`${x.vod_name}$${drives.name}~~~${vid.substring(vid.indexOf("$")+1)}`)
|
||
}
|
||
});
|
||
const pl = path.split("/").filter(it => it);
|
||
let vod_name = pl[pl.length - 1] || drives.name;
|
||
if (vod_name === drives.name) {
|
||
print(pl)
|
||
}
|
||
if (otid.includes("#search#")) {
|
||
// vod_name += "[搜]"
|
||
}
|
||
|
||
let orvod = nopic ? null : findVodById(drives,tid);
|
||
|
||
let vod_pic = orvod !== null ? orvod.vod_pic : "https://avatars.githubusercontent.com/u/97389433?s=120&v=4";
|
||
|
||
let vod = {
|
||
vod_id: otid,
|
||
vod_name: vod_name,
|
||
type_name: "文件夹",
|
||
vod_pic: vod_pic,
|
||
vod_content: tid,
|
||
vod_tag: isFile ? "file" : "folder",
|
||
vod_play_from: drives.name,
|
||
vod_play_url: vod_play_url.join("#"),
|
||
vod_remarks: drives.settings.title
|
||
};
|
||
print("----detail1----");
|
||
print(vod);
|
||
return JSON.stringify({
|
||
list: [vod]
|
||
})
|
||
} catch (e) {
|
||
print(e.message);
|
||
return JSON.stringify({
|
||
list: [{}]
|
||
})
|
||
}
|
||
}
|
||
|
||
function playlist(otid, tid, drives, path) {
|
||
tid = tid.replace('/~playlist', '')
|
||
otid = otid.replace('/~playlist', '')
|
||
path = path.replace('/~playlist', '')
|
||
return getAll(otid, tid, drives, path)
|
||
}
|
||
|
||
function findVodById(drives, targetVodId) {
|
||
|
||
targetVodId = targetVodId.replace(/#all#|#search#/g, "");
|
||
let foundVod = null;
|
||
|
||
// 使用 Array.find 查找元素
|
||
if (drives !== null && drives.vods != null) {
|
||
foundVod = drives.vods.find(vod => vod.vod_id.replace(/#all#|#search#/g, "") === targetVodId);
|
||
}
|
||
|
||
if (!foundVod)
|
||
{
|
||
try
|
||
{
|
||
const result = get_drives_path(targetVodId);
|
||
let driver = drives;
|
||
let path = result.path;
|
||
let wd = "/";
|
||
const parts = path.split('/');
|
||
if (parts.length >1)
|
||
{
|
||
wd += parts[1];
|
||
}
|
||
if (wd !== "/" && !drives.noPoster)
|
||
{
|
||
foundVod = getAllVods("box=" + wd,driver.name).list.find(vod =>{
|
||
let r = get_drives_path(vod.vod_id.replace(/#all#|#search#/g, ""));
|
||
return path === r.path;
|
||
});
|
||
}
|
||
}catch(e)
|
||
{
|
||
foundVod = null;
|
||
}
|
||
}
|
||
|
||
return foundVod || null;
|
||
}
|
||
|
||
function isPathFolder(path) {
|
||
return !(/\.(dff|dsf|mp3|aac|wav|wma|cda|flac|m4a|mid|mka|mp2|mpa|mpc|ape|ofr|ogg|ra|wv|tta|ac3|dts|tak|webm|wmv|mpeg|mov|ram|swf|mp4|avi|rm|rmvb|flv|mpg|mkv|m3u8|ts|3gp|asf|nfo)$/.test(path.toLowerCase()));
|
||
}
|
||
|
||
function genFolderPlayList(drives,path,url,from)
|
||
{
|
||
let vod_play_url = url;
|
||
let vod_play_from =from;
|
||
let subFolderList = [];
|
||
try
|
||
{
|
||
let list = drives.getPath(path);
|
||
list.forEach(item => {
|
||
if (!drives.isFolder(item)) {
|
||
return
|
||
}
|
||
subFolderList.push(item.name)
|
||
});
|
||
|
||
var searchurl = drives.name + "$" + path;
|
||
var tempvod = getAll(searchurl + "#search#", searchurl, drives, "/" + path,list,true);
|
||
if (JSON.parse(tempvod).list[0].vod_play_url != "")
|
||
{
|
||
vod_play_url = vod_play_url+"$$$"+JSON.parse(tempvod).list[0].vod_play_url;
|
||
vod_play_from = vod_play_from+"$$$"+path.substring(path.lastIndexOf("/") + 1);
|
||
}
|
||
}
|
||
catch(e)
|
||
{
|
||
vod_play_url = url;
|
||
vod_play_from =from;
|
||
}
|
||
|
||
subFolderList.forEach(item => {
|
||
const result = genFolderPlayList(drives,path + "/" + item,vod_play_url,vod_play_from);
|
||
vod_play_url = result.vod_play_url;
|
||
vod_play_from = result.vod_play_from;
|
||
});
|
||
|
||
return {
|
||
vod_play_url: vod_play_url,
|
||
vod_play_from: vod_play_from
|
||
};
|
||
}
|
||
|
||
function getDoubanInfo(id) {
|
||
try{
|
||
if (id === "")
|
||
{
|
||
return {};
|
||
}
|
||
const url = "https://movie.douban.com/subject/" + id +"/";
|
||
let html = http.get(url).text();
|
||
const $ = cheerio.load(html);
|
||
let plot = $('#link-report-intra span[property="v:summary"]').text().trim();
|
||
const yearElement = $('.year');
|
||
let year = yearElement.text().replace(/\(|\)/g, '');
|
||
let region = "";
|
||
var text = html;
|
||
var regex = /<span class="pl">制片国家\/地区:<\/span>[\s\n]*([^<]+)/;
|
||
var match = text.match(regex);
|
||
if (match && match[1]) {
|
||
region = match[1].trim();
|
||
}
|
||
const actorElements = $('meta[property^="video:actor"]');
|
||
let actors = actorElements.map((index, element) => {
|
||
return $(element).attr('content');
|
||
}).get();
|
||
actors = actors.join('/');
|
||
const directorElement = $('meta[property="video:director"]');
|
||
const director = directorElement.attr('content');
|
||
const genreElement = $('span.pl:contains("类型:")');
|
||
const type = genreElement.nextAll('span[property="v:genre"]').map((index, element) => {
|
||
return $(element).text();
|
||
}).get().join('/');
|
||
|
||
return {
|
||
plot,
|
||
year,
|
||
region,
|
||
actors,
|
||
director,
|
||
type
|
||
};
|
||
}catch(e){
|
||
return {};
|
||
}
|
||
}
|
||
|
||
function getFolderVodDetail(tid){
|
||
let orid = tid.replace(/#all#|#search#/g, "");
|
||
let {
|
||
drives,
|
||
path
|
||
} = get_drives_path(orid);
|
||
|
||
if (!isPathFolder(path.toLowerCase())){
|
||
return "";
|
||
}
|
||
|
||
if (path.endsWith("/~playlist")){
|
||
return "";
|
||
}
|
||
|
||
let orvod = findVodById(drives,tid) ;
|
||
let vod_pic = orvod !== null ? orvod.vod_pic : "https://avatars.githubusercontent.com/u/97389433?s=120&v=4";
|
||
|
||
let {
|
||
vod_play_url,
|
||
vod_play_from
|
||
} = genFolderPlayList(drives,path,"","");
|
||
vod_play_from = vod_play_from.replace(/^[$]{3}/, '');
|
||
vod_play_url = vod_play_url.replace(/^[$]{3}/, '');
|
||
|
||
let doubanInfo = {};
|
||
let vod_name = path.substring(path.lastIndexOf("/") + 1);
|
||
if (orvod)
|
||
{
|
||
vod_name = orvod.vod_name;
|
||
doubanInfo = getDoubanInfo(orvod.vod_dbid);
|
||
}
|
||
let vod_content = doubanInfo.plot ? doubanInfo.plot + " \n\n文件路径:" + path : path;
|
||
let vod = {
|
||
vod_id: orid,
|
||
vod_name: vod_name,
|
||
type_name: doubanInfo.type,
|
||
vod_pic: vod_pic,
|
||
vod_content: vod_content,
|
||
vod_actor: doubanInfo.actors,
|
||
vod_area: doubanInfo.region,
|
||
vod_director: doubanInfo.director,
|
||
vod_year: doubanInfo.year,
|
||
vod_play_from: vod_play_from,
|
||
vod_play_url: vod_play_url,
|
||
vod_remarks: drives.settings.title
|
||
};
|
||
|
||
return JSON.stringify({
|
||
list: [vod]
|
||
})
|
||
}
|
||
|
||
function detail(tid) {
|
||
let folderVod = getFolderVodDetail(tid.split("@@@")[0]);
|
||
if (folderVod !== ""){
|
||
return folderVod;
|
||
}
|
||
let isSearch = tid.includes("#search#");
|
||
let isAll = tid.includes("#all#");
|
||
let otid = tid;
|
||
tid = tid.replace(/#all#|#search#/g, "");
|
||
let isFile = isMedia(tid.split("@@@")[0]);
|
||
print(`isFile:${tid}?${isFile}`);
|
||
let {
|
||
drives,
|
||
path
|
||
} = get_drives_path(tid);
|
||
print(`drives:${drives},path:${path}`);
|
||
|
||
if (path.endsWith("/")) {
|
||
return getAll(otid, tid, drives, path)
|
||
} else if (path.endsWith("/~playlist")) {
|
||
return playlist(otid, tid, drives, path)
|
||
} else {
|
||
if (isSearch && !isFile) {
|
||
return getAll(otid, tid, drives, path)
|
||
} else if (isAll) {
|
||
let new_tid;
|
||
if (isFile) {
|
||
new_tid = tid.split("/").slice(0, -1).join("/") + "/"
|
||
} else {
|
||
new_tid = tid
|
||
}
|
||
print(`全集模式 tid:${tid}=>tid:${new_tid}`);
|
||
let {
|
||
drives,
|
||
path
|
||
} = get_drives_path(new_tid);
|
||
return getAll(otid, new_tid, drives, path)
|
||
} else if (isFile) {
|
||
let paths = path.split("@@@");
|
||
let orvod = findVodById(drives,tid);
|
||
let vod_pic = orvod !== null ? orvod.vod_pic : "https://avatars.githubusercontent.com/u/97389433?s=120&v=4";
|
||
|
||
let doubanInfo = {};
|
||
let vod_name = paths[0].substring(paths[0].lastIndexOf("/") + 1);
|
||
if (orvod)
|
||
{
|
||
vod_name = orvod.vod_name;
|
||
doubanInfo = getDoubanInfo(orvod.vod_dbid);
|
||
}
|
||
let vod_content = doubanInfo.plot ? doubanInfo.plot + " \n\n文件路径:" + paths[0]: paths[0];
|
||
|
||
let vod = {
|
||
vod_id: otid,
|
||
vod_name: vod_name,
|
||
type_name: doubanInfo.type,
|
||
vod_pic: vod_pic,
|
||
vod_content: vod_content,
|
||
vod_actor: doubanInfo.actors,
|
||
vod_area: doubanInfo.region,
|
||
vod_director: doubanInfo.director,
|
||
vod_year: doubanInfo.year,
|
||
vod_play_from: drives.name,
|
||
vod_play_url: vod_name + "$" + drives.name + "~~~" + path,
|
||
vod_remarks: drives.settings.title
|
||
};
|
||
print("----detail2----");
|
||
print(vod);
|
||
return JSON.stringify({
|
||
list: [vod]
|
||
})
|
||
} else {
|
||
return JSON.stringify({
|
||
list: []
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
function play(flag, id, flags) {
|
||
if (__drives[flag]==null){
|
||
//flag = __drives[searchDriver].name;
|
||
}
|
||
let urls = id.split("@@@");
|
||
flag = urls[0].split("~~~")[0];
|
||
urls[0] = urls[0].split("~~~")[1];
|
||
const drives = get_drives(flag);
|
||
let vod = {
|
||
parse: 0,
|
||
playUrl: "",
|
||
url: drives.getFile(urls[0]).raw_url
|
||
};
|
||
if (urls.length >= 2) {
|
||
const path = urls[0].substring(0, urls[0].lastIndexOf("/") + 1);
|
||
vod.subt = drives.getFile(path + urls[1]).raw_url
|
||
}
|
||
print("----play----");
|
||
print(vod);
|
||
return JSON.stringify(vod)
|
||
}
|
||
|
||
function search(wd, quick) {
|
||
print(__drives);
|
||
print("可搜索的alist驱动:" + searchDriver);
|
||
if (!searchDriver || !wd) {
|
||
return JSON.stringify({
|
||
list: []
|
||
})
|
||
} else {
|
||
let driver = __drives[searchDriver];
|
||
wd = wd.split(" ").filter(it => it.trim()).join("+");
|
||
print(driver);
|
||
driver.vods = getAllVods("box=" + wd,driver.name).list;
|
||
return JSON.stringify({
|
||
page: 1,
|
||
pagecount: 1,
|
||
list: driver.vods
|
||
});
|
||
}
|
||
}
|
||
|
||
function get_size(sz) {
|
||
if (sz <= 0) {
|
||
return ""
|
||
}
|
||
let filesize = "";
|
||
if (sz > 1024 * 1024 * 1024 * 1024) {
|
||
sz /= 1024 * 1024 * 1024 * 1024;
|
||
filesize = "TB"
|
||
} else if (sz > 1024 * 1024 * 1024) {
|
||
sz /= 1024 * 1024 * 1024;
|
||
filesize = "GB"
|
||
} else if (sz > 1024 * 1024) {
|
||
sz /= 1024 * 1024;
|
||
filesize = "MB"
|
||
} else if (sz > 1024) {
|
||
sz /= 1024;
|
||
filesize = "KB"
|
||
} else {
|
||
filesize = "B"
|
||
}
|
||
let sizeStr = sz.toFixed(2) + filesize,
|
||
index = sizeStr.indexOf("."),
|
||
dou = sizeStr.substr(index + 1, 2);
|
||
if (dou === "00") {
|
||
return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
|
||
} else {
|
||
return sizeStr
|
||
}
|
||
}
|
||
|
||
function levenshteinDistance(str1, str2) {
|
||
return 100 - 100 * distance(str1, str2) / Math.max(str1.length, str2.length)
|
||
}
|
||
|
||
function naturalSort(options) {
|
||
if (!options) {
|
||
options = {}
|
||
}
|
||
return function(a, b) {
|
||
if (options.key) {
|
||
a = a[options.key];
|
||
b = b[options.key]
|
||
}
|
||
var EQUAL = 0;
|
||
var GREATER = options.order === "desc" ? -1 : 1;
|
||
var SMALLER = -GREATER;
|
||
var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi;
|
||
var sre = /(^[ ]*|[ ]*$)/g;
|
||
var dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/;
|
||
var hre = /^0x[0-9a-f]+$/i;
|
||
var ore = /^0/;
|
||
var normalize = function normalize(value) {
|
||
var string = "" + value;
|
||
return options.caseSensitive ? string : string.toLowerCase()
|
||
};
|
||
var x = normalize(a).replace(sre, "") || "";
|
||
var y = normalize(b).replace(sre, "") || "";
|
||
var xN = x.replace(re, "\0$1\0").replace(/\0$/, "").replace(/^\0/, "").split("\0");
|
||
var yN = y.replace(re, "\0$1\0").replace(/\0$/, "").replace(/^\0/, "").split("\0");
|
||
if (!x && !y) return EQUAL;
|
||
if (!x && y) return GREATER;
|
||
if (x && !y) return SMALLER;
|
||
var xD = parseInt(x.match(hre)) || xN.length != 1 && x.match(dre) && Date.parse(x);
|
||
var yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null;
|
||
var oFxNcL, oFyNcL;
|
||
if (yD) {
|
||
if (xD < yD) return SMALLER;
|
||
else if (xD > yD) return GREATER
|
||
}
|
||
for (var cLoc = 0, numS = Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
|
||
oFxNcL = !(xN[cLoc] || "").match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
|
||
oFyNcL = !(yN[cLoc] || "").match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
|
||
if (isNaN(oFxNcL) !== isNaN(oFyNcL)) return isNaN(oFxNcL) ? GREATER : SMALLER;
|
||
else if (typeof oFxNcL !== typeof oFyNcL) {
|
||
oFxNcL += "";
|
||
oFyNcL += ""
|
||
}
|
||
if (oFxNcL < oFyNcL) return SMALLER;
|
||
if (oFxNcL > oFyNcL) return GREATER
|
||
}
|
||
return EQUAL
|
||
}
|
||
}
|
||
const sortListByName = (vodList, key, order) => {
|
||
if (!key) {
|
||
return vodList
|
||
}
|
||
order = order || "asc";
|
||
return vodList.sort(naturalSort({
|
||
key: key,
|
||
order: order,
|
||
caseSensitive: true
|
||
}))
|
||
};
|
||
const getTimeInt = timeStr => {
|
||
return new Date(timeStr).getTime()
|
||
};
|
||
const sortListByTime = (vodList, key, order) => {
|
||
if (!key) {
|
||
return vodList
|
||
}
|
||
let ASCarr = vodList.sort((a, b) => {
|
||
a = a[key];
|
||
b = b[key];
|
||
return getTimeInt(a) - getTimeInt(b)
|
||
});
|
||
if (order === "desc") {
|
||
ASCarr.reverse()
|
||
}
|
||
return ASCarr
|
||
};
|
||
const sortListBySize = (vodList, key, order) => {
|
||
if (!key) {
|
||
return vodList
|
||
}
|
||
let ASCarr = vodList.sort((a, b) => {
|
||
a = a[key];
|
||
b = b[key];
|
||
return (Number(a) || 0) - (Number(b) || 0)
|
||
});
|
||
if (order === "desc") {
|
||
ASCarr.reverse()
|
||
}
|
||
return ASCarr
|
||
};
|
||
export default {
|
||
init: init,
|
||
home: home,
|
||
homeVod: homeVod,
|
||
category: category,
|
||
detail: detail,
|
||
play: play,
|
||
search: search
|
||
};
|
||
|