Files
uzVideo/js/spider/panTools.js

187 lines
16 KiB
JavaScript
Raw Normal View History

2024-09-29 15:58:33 +08:00
// ignore
import {} from "../core/uzVideo.js";
import {} from "../core/uzHome.js";
import {} from "../core/uz3lib.js";
import {} from "../core/uzUtils.js";
// ignore
/**
* 网盘类型
* 环境变量 key PanType.xx + "Cookie",请在 json 文件中添加
*/
const PanType = {
/**
* 夸克
**/
Quark: "夸克",
/**
* UC
**/
UC: "UC",
};
/**
* 播放信息
**/
class PanPlayInfo {
constructor(url = "", error = "", playHeaders = {}) {
this.url = url;
this.error = error;
this.playHeaders = playHeaders;
}
}
/**
* 网盘视频项
*/
class PanVideoItem {
constructor() {
/**
2024-09-30 10:27:56 +08:00
* 展示名称 例如 老友记
2024-09-29 15:58:33 +08:00
*/
this.name = "";
/**
* 分组名称 例如 原画 普画 非必须
*/
this.fromName = "";
/**
* 网盘类型 用于获取播放信息时
* @type {PanType}
**/
this.panType = PanType.UC;
/**
* 关键数据 用于获取播放信息时
* @type {Object}
*/
this.data;
}
}
/**
* 网盘播放列表
*/
class PanListDetail {
constructor() {
/**
* @type {PanVideoItem[]}
* 视频列表
*/
this.videos = [];
this.error = "";
}
}
//MARK: - 夸克 UC 相关实现
// 抄自 https://github.com/jadehh/TVSpider
// prettier-ignore
class QuarkUCVideoItem { constructor() { this.fileId = ""; this.shareId = ""; this.shareToken = ""; this.shareFileToken = ""; this.seriesId = ""; this.name = ""; this.type = ""; this.formatType = ""; this.size = ""; this.parent = ""; this.shareData = null; this.lastUpdateAt = 0; this.subtitle = null; } static objectFrom(itemJson, shareId) { const item = new QuarkUCVideoItem(); item.fileId = itemJson.fid || ""; item.shareId = shareId; item.shareToken = itemJson.stoken || ""; item.shareFileToken = itemJson.share_fid_token || ""; item.seriesId = itemJson.series_id || ""; item.name = itemJson.file_name || ""; item.type = itemJson.obj_category || ""; item.formatType = itemJson.format_type || ""; item.size = (itemJson.size || "").toString(); item.parent = itemJson.pdir_fid || ""; item.lastUpdateAt = itemJson.last_update_at || 0; return item; } }
2024-09-30 10:27:56 +08:00
// prettier-ignore
class QuarkClient { static apiUrl = "https://drive-pc.quark.cn/1/clouddrive/"; static pr = "pr=ucpro&fr=pc"; static httpHeaders = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) quark-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch", Referer: "https://pan.quark.cn/", "Content-Type": "application/json", }; }
// prettier-ignore
class UCClient { static apiUrl = "https://pc-api.uc.cn/1/clouddrive/"; static pr = "pr=UCBrowser&fr=pc"; static httpHeaders = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) uc-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch", referer: "https://drive.uc.cn", "Content-Type": "application/json", }; }
// prettier-ignore
class QuarkUC { constructor(isQuark = false) { this.isQuark = isQuark; this.cookie = ""; this.shareTokenCache = {}; this.saveFileIdCaches = {}; this.saveDirId = null; this.saveDirName = "uz影视"; this.isVip = false; this.updateCookie = () => {}; } get panName() { if (this.isQuark) { return PanType.Quark; } else { return PanType.UC; } } get apiUrl() { if (this.isQuark) { return QuarkClient.apiUrl; } else { return UCClient.apiUrl; } } get pr() { if (this.isQuark) { return QuarkClient.pr; } else { return UCClient.pr; } } get headers() { const headers = this.isQuark ? QuarkClient.httpHeaders : UCClient.httpHeaders; headers["Cookie"] = this.cookie; return headers; } /** * 获取文件列表 * @param {string} shareUrl * @returns {@Promise<PanListDetail>} **/ async getFilesByShareUrl( shareUrl ) { const data = new PanListDetail(); await this.getVip(); const shareData = this.getShareData(shareUrl); if (shareData == null) { data.error = "分享链接无效"; return data; } await this.getShareToken(shareData); const videos = []; const subtitles = []; if (!this.shareTokenCache.hasOwnProperty(shareData.shareId)) { data.error = "资源获取失败"; return data; } await this.listFile( shareData, videos, subtitles, shareData.shareId, shareData.folderId ); if (subtitles.length > 0) { for (const item of videos) { const matchSubtitle = this.findBestLCS(item, subtitles); if (matchSubtitle.bestMatch != null) { item.subtitle = matchSubtitle.bestMatch.target; } } } const playForm = this.getPlayForm(); for (let index = 0; index < playForm.length; index++) { const flag = playForm[index]; for (let index = 0; index < videos.length; index++) { const element = videos[index]; element.flag = flag; const videoItem = new PanVideoItem(); videoItem.data = element; videoItem.panType = this.panName; videoItem.name = element.name; videoItem.fromName = flag; data.videos.push(videoItem); } } return data; } /** * 获取播放信息 * @param {{flag:string,shareId:string,shareToken:string,fileId:string,shareFileToken:string }} data * @returns {@Promise<PanPlayInfo>} */ async getPlayUrl( data ) { if (this.cookie.length === 0) { return new PanPlayInfo( "", "请在 设置 -> 数据管理 -> 环境变量 中为" + this.panName + "Cookie" + " 添加值" ); } await this.getVip(); let playData; try { const { flag, shareId, shareToken, fileId, shareFileToken } = data; if (flag.includes("原画")) { playData = await this.getDownload( shareId, shareToken, fileId, shareFileToken, true ); } else { playData = await this.getLiveTranscoding( shareId, shareToken, fileId, shareFileToken, flag ); } } catch (error) { playData = new PanPlayInfo("", error.toString()); } playData.playHeaders = { cookie: this.cookie }; return playData; } async api(url, data = null, retry = 3, method = "post") { let leftRetry = retry; while (leftRetry > 0) { try { const response = await req(this.apiUrl + url, { method: method, headers: this.headers, data: JSON.stringify(data), }); if (response.code === 401) { this.cookie = ""; return {}; } const resp = response.data; if (response.headers["set-cookie"]) { const puus = [response.headers["set-cookie"]] .join(";;;") .match(/__puus=([^;]+)/); if (puus) { if (this.cookie.match(/__puus=([^;]+)/)[1] != puus[1]) { this.cookie = this.cookie.replace( /__puus=[^;]+/, `__puus=${puus[1]}` ); this.updateCookie(); } } } return resp; } catch (e) {} leftRetry--; await new Promise((resolve) => setTimeout(resolve, 1000)); } return resp; } /** * 根据链接获取分享ID和文件夹ID * @param {string} url * @returns {null|{shareId: string, folderId: string}} */ getShareData( url ) { let regex = /https:\/\/pan\.quark\.cn\/s\/([^\\|#/]+)/; if (!this.isQuark) { regex = /https:\/\/drive\.uc\.cn\/s\/([^\\|#/]+)/; } const matches = regex.exec(url); if (matches != null) { return { shareId: matches[1], folderId: "0" }; } return null; } /** * 获取分享token * @param {{shareId: string, sharePwd: string}} shareData */ async getShareToken( shareData ) { if (!this.shareTokenCache.hasOwnProperty(shareData.shareId)) { delete this.shareTokenCache[shareData.shareId]; const shareTo
2024-09-29 15:58:33 +08:00
//MARK: 网盘扩展统一入口
/**
* 网盘工具
*/
class PanTools {
constructor() {
//MARK: 在这里初始化 对应网盘的具体实现对象
this.quark = new QuarkUC(true);
this.uc = new QuarkUC(false);
/**
* 扩展运行标识 ** uzApp 运行时自动赋值请勿修改 **
*/
this.uzTag = "";
}
/**
* 获取 cookie ** 无法在 PanTools 外部操作**
* 环境变量 key PanType.xx + "Cookie",请在 json 文件中添加
* @param {PanType} panType
* @returns {@Promise<string>}
*/
async getCookie(panType) {
const cookie = await getEnv(this.uzTag, panType + "Cookie");
return cookie;
}
/**
* 更新 cookie ** 无法在 PanTools 外部操作**
* @param {PanType} panType
* @param {string} cookie
*/
async updateCookie(panType, cookie) {
await setEnv(this.uzTag, panType + "Cookie", cookie);
}
/**
* 获取网盘资源列表
* @param {string} shareUrl
* @returns {@Promise<PanListDetail>}
*/
async getShareVideos(shareUrl) {
if (shareUrl.includes("https://pan.quark.cn")) {
/// 如果需要 cookie 请在这里获取
// this.quark.cookie = await this.getCookie(PanType.Quark);
const data = await this.quark.getFilesByShareUrl(shareUrl);
return data;
} else if (shareUrl.includes("https://drive.uc.cn")) {
shareUrl = shareUrl.split("?")[0];
/// 如果需要 cookie 请在这里获取
// this.uc.cookie = await this.getCookie(PanType.UC);
const data = await this.uc.getFilesByShareUrl(shareUrl);
return data;
}
const data = new PanListDetail();
2024-09-30 10:27:56 +08:00
data.error = "";
2024-09-29 15:58:33 +08:00
return data;
}
/**
* 获取播放信息
* @param {PanVideoItem} item
* @returns {@Promise<PanPlayInfo>}
*/
async getPlayInfo(item) {
if (item.panType === PanType.Quark) {
/// 如果需要 cookie 请在这里获取
this.quark.cookie = await this.getCookie(PanType.Quark);
/// 更新 Quark cookie
this.quark.updateCookie = () => {
this.updateCookie(PanType.Quark, this.quark.cookie);
};
if (this.quark.cookie === "") {
return new PanPlayInfo("", "获取 " + PanType.Quark + " cookie 失败~");
}
const data = await this.quark.getPlayUrl(item.data);
return data;
} else if (item.panType === PanType.UC) {
/// 如果需要 cookie 请在这里获取
this.uc.cookie = await this.getCookie(PanType.UC);
/// 更新 UC cookie
this.uc.updateCookie = () => {
this.updateCookie(PanType.UC, this.uc.cookie);
};
if (this.uc.cookie === "") {
return new PanPlayInfo("", "获取 " + PanType.UC + " cookie 失败~");
}
const data = await this.uc.getPlayUrl(item.data);
return data;
}
return new PanPlayInfo("", "暂不支持该网盘类型");
}
}
// 固定实例名称
const uzPanToolsInstance = new PanTools();