mirror of
https://github.com/qist/tvbox.git
synced 2025-11-03 05:32:32 +00:00
update CAT
This commit is contained in:
282
cat/tjs/lib/quark_api.js
Normal file
282
cat/tjs/lib/quark_api.js
Normal file
@@ -0,0 +1,282 @@
|
||||
/**
|
||||
* File: /workspaces/TVSpider/lib/quark_api.js
|
||||
* Project: /workspaces/TVSpider
|
||||
* Created Date: Monday, May 20th 2024, 6:38:12 am
|
||||
* Author: jade
|
||||
* -----
|
||||
* Last Modified: Tue May 21 2024
|
||||
* Modified By: jade
|
||||
* -----
|
||||
* Copyright (c) 2024 samples
|
||||
* ------------------------------------
|
||||
* Javascript will save your soul!
|
||||
*/
|
||||
import {_,Crypto} from "../lib/cat.js";
|
||||
import * as Utils from "../lib/utils.js"
|
||||
import {Item} from "../lib/quark_object.js"
|
||||
|
||||
class Quark{
|
||||
constructor(){
|
||||
this.apiUrl = "https://drive-pc.quark.cn/1/clouddrive/"
|
||||
this.cookie = ""
|
||||
this.ckey = ""
|
||||
this.shareTokenCache = {}
|
||||
this.pr = "pr=ucpro&fr=pc"
|
||||
this.subtitleExts = ['.srt', '.ass', '.scc', '.stl', '.ttml'];
|
||||
this.saveFileIdCaches = {}
|
||||
this.saveDirId = null
|
||||
this.saveDirName = 'TV';
|
||||
|
||||
}
|
||||
async initQuark(cookie) {
|
||||
this.ckey = Crypto.enc.Hex.stringify(Crypto.MD5(cookie)).toString();
|
||||
let localCfg = await local.get("quark", "cookie");
|
||||
if (!_.isEmpty(localCfg)){
|
||||
this.cookie = JSON.parse(localCfg)[this.ckey]
|
||||
}else{
|
||||
this.cookie = cookie
|
||||
}
|
||||
}
|
||||
|
||||
getHeaders(){
|
||||
return {
|
||||
'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",
|
||||
"Cookie":this.cookie,
|
||||
"Host":"drive-pc.quark.cn"
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
async api(url,data,retry,method){
|
||||
const leftRetry = retry || 3;
|
||||
let resp = await req(this.apiUrl + url,{
|
||||
method:method || "post",
|
||||
data:data,
|
||||
headers:this.getHeaders()
|
||||
})
|
||||
if (resp.headers['set-cookie']) {
|
||||
const puus = [resp.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]}`);
|
||||
let cookieDic = {}
|
||||
cookieDic[this.ckey] = this.cookie
|
||||
await local.set("quark",this.cookie, JSON.stringify(cookieDic));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resp.code !== 200 && leftRetry > 0) {
|
||||
Utils.sleep(1)
|
||||
return await this.api(url, data, leftRetry - 1);
|
||||
}
|
||||
return JSON.parse(resp.content) || {};
|
||||
}
|
||||
|
||||
getShareData(url) {
|
||||
let regex = /https:\/\/pan\.quark\.cn\/s\/([^\\|#/]+)/;
|
||||
let matches = regex.exec(url);
|
||||
if (matches) {
|
||||
return {
|
||||
shareId: matches[1],
|
||||
folderId: '0',
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
async getShareToken(shareData) {
|
||||
if (!this.shareTokenCache[shareData.shareId]) {
|
||||
delete this.shareTokenCache[shareData.shareId];
|
||||
const shareToken = await this.api(`share/sharepage/token?${this.pr}`, {
|
||||
pwd_id: shareData.shareId,
|
||||
passcode: shareData.sharePwd || '',
|
||||
});
|
||||
if (shareToken.data && shareToken.data.stoken) {
|
||||
this.shareTokenCache[shareData.shareId] = shareToken.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
async listFile (shareIndex,shareData,videos,subtitles,shareId, folderId, page) {
|
||||
const prePage = 200;
|
||||
page = page || 1;
|
||||
const listData = await this.api(`share/sharepage/detail?${this.pr}&pwd_id=${shareId}&stoken=${encodeURIComponent(this.shareTokenCache[shareId].stoken)}&pdir_fid=${folderId}&force=0&_page=${page}&_size=${prePage}&_sort=file_type:asc,file_name:asc`, null,null, 'get');
|
||||
if (!listData.data) return [];
|
||||
const items = listData.data.list;
|
||||
if (!items) return [];
|
||||
const subDir = [];
|
||||
for (const item of items) {
|
||||
if (item.dir === true) {
|
||||
subDir.push(item);
|
||||
} else if (item.file === true && item.obj_category === 'video') {
|
||||
if (item.size < 1024 * 1024 * 5) continue;
|
||||
item.stoken = this.shareTokenCache[shareData.shareId].stoken;
|
||||
videos.push(Item.objectFrom(item,shareData.shareId,shareIndex));
|
||||
} else if (item.type === 'file' && this.subtitleExts.some((x) => item.file_name.endsWith(x))) {
|
||||
subtitles.push(Item.objectFrom(item,shareData,shareIndex));
|
||||
}
|
||||
}
|
||||
if (page < Math.ceil(listData.metadata._total / prePage)) {
|
||||
const nextItems = await this.listFile(shareIndex,shareData.shareId,videos,subtitles,shareId, folderId, page + 1);
|
||||
for (const item of nextItems) {
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
for (const dir of subDir) {
|
||||
const subItems = await this.listFile(shareIndex,shareData,videos,subtitles,shareId, dir.fid);
|
||||
for (const item of subItems) {
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
return items;
|
||||
};
|
||||
|
||||
findBestLCS(mainItem, targetItems) {
|
||||
const results = [];
|
||||
let bestMatchIndex = 0;
|
||||
for (let i = 0; i < targetItems.length; i++) {
|
||||
const currentLCS = Utils.lcs(mainItem.name, targetItems[i].name);
|
||||
results.push({ target: targetItems[i], lcs: currentLCS });
|
||||
if (currentLCS.length > results[bestMatchIndex].lcs.length) {
|
||||
bestMatchIndex = i;
|
||||
}
|
||||
}
|
||||
const bestMatch = results[bestMatchIndex];
|
||||
return { allLCS: results, bestMatch: bestMatch, bestMatchIndex: bestMatchIndex };
|
||||
}
|
||||
|
||||
async getFilesByShareUrl(shareIndex,shareInfo,videos,subtitles){
|
||||
const shareData = typeof shareInfo === 'string' ? this.getShareData(shareInfo) : shareInfo;
|
||||
if (!shareData) return [];
|
||||
await this.getShareToken(shareData);
|
||||
if (!this.shareTokenCache[shareData.shareId]) return [];
|
||||
await this.listFile(shareIndex,shareData,videos,subtitles,shareData.shareId, shareData.folderId);
|
||||
if (subtitles.length > 0) {
|
||||
videos.forEach((item) => {
|
||||
var matchSubtitle = this.findBestLCS(item, subtitles);
|
||||
if (matchSubtitle.bestMatch) {
|
||||
item.subtitle = matchSubtitle.bestMatch.target;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
clean(){
|
||||
const saves = Object.keys(this.saveFileIdCaches);
|
||||
for (const save of saves) {
|
||||
delete this.saveFileIdCaches[save];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async clearSaveDir() {
|
||||
const listData = await this.api(`file/sort?${this.pr}&pdir_fid=${this.saveDirId}&_page=1&_size=200&_sort=file_type:asc,updated_at:desc`, {}, {}, 'get');
|
||||
if (listData.data && listData.data.list && listData.data.list.length > 0) {
|
||||
await this.api(`file/delete?${this.pr}`, {
|
||||
action_type: 2,
|
||||
filelist: listData.data.list.map((v) => v.fid),
|
||||
exclude_fids: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async createSaveDir(clean) {
|
||||
if (this.saveDirId) {
|
||||
// 删除所有子文件
|
||||
if (clean) await this.clearSaveDir();
|
||||
return;
|
||||
}
|
||||
const listData = await this.api(`file/sort?${this.pr}&pdir_fid=0&_page=1&_size=200&_sort=file_type:asc,updated_at:desc`, {}, {}, 'get');
|
||||
if (listData.data && listData.data.list)
|
||||
for (const item of listData.data.list) {
|
||||
if (item.file_name === this.saveDirName) {
|
||||
this.saveDirId = item.fid;
|
||||
await this.clearSaveDir();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!this.saveDirId) {
|
||||
const create = await this.api(`file?${this.pr}`, {
|
||||
pdir_fid: '0',
|
||||
file_name: this.saveDirName,
|
||||
dir_path: '',
|
||||
dir_init_lock: false,
|
||||
});
|
||||
if (create.data && create.data.fid) {
|
||||
this.saveDirId = create.data.fid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async save(shareId, stoken, fileId, fileToken, clean) {
|
||||
await this.createSaveDir(clean);
|
||||
if (clean) {
|
||||
this.clean()
|
||||
}
|
||||
if (!this.saveDirId) return null;
|
||||
if (!stoken) {
|
||||
await this.getShareToken({
|
||||
shareId: shareId,
|
||||
});
|
||||
if (!this.shareTokenCache[shareId]) return null;
|
||||
}
|
||||
const saveResult = await this.api(`share/sharepage/save?${this.pr}`, {
|
||||
fid_list: [fileId],
|
||||
fid_token_list: [fileToken],
|
||||
to_pdir_fid: this.saveDirId,
|
||||
pwd_id: shareId,
|
||||
stoken: stoken || this.shareTokenCache[shareId].stoken,
|
||||
pdir_fid: '0',
|
||||
scene: 'link',
|
||||
});
|
||||
if (saveResult.data && saveResult.data.task_id) {
|
||||
let retry = 0;
|
||||
// wait task finish
|
||||
while (true) {
|
||||
const taskResult = await this.api(`task?${this.pr}&task_id=${saveResult.data.task_id}&retry_index=${retry}`, {}, {}, 'get');
|
||||
if (taskResult.data && taskResult.data.save_as && taskResult.data.save_as.save_as_top_fids && taskResult.data.save_as.save_as_top_fids.length > 0) {
|
||||
return taskResult.data.save_as.save_as_top_fids[0];
|
||||
}
|
||||
retry++;
|
||||
if (retry > 2) break;
|
||||
Utils.sleep(1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
async getLiveTranscoding(shareId, stoken, fileId, fileToken) {
|
||||
if (!this.saveFileIdCaches[fileId]) {
|
||||
const saveFileId = await this.save(shareId, stoken, fileId, fileToken, true);
|
||||
if (!saveFileId) return null;
|
||||
this.saveFileIdCaches[fileId] = saveFileId;
|
||||
}
|
||||
const transcoding = await this.api(`file/v2/play?${this.pr}`, {
|
||||
fid: this.saveFileIdCaches[fileId],
|
||||
resolutions: 'normal,low,high,super,2k,4k',
|
||||
supports: 'fmp4',
|
||||
});
|
||||
if (transcoding.data && transcoding.data.video_list) {
|
||||
return transcoding.data.video_list;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async getDownload(shareId, stoken, fileId, fileToken, clean) {
|
||||
if (!this.saveFileIdCaches[fileId]) {
|
||||
const saveFileId = await this.save(shareId, stoken, fileId, fileToken, clean);
|
||||
if (!saveFileId) return null;
|
||||
this.saveFileIdCaches[fileId] = saveFileId;
|
||||
}
|
||||
const down = await this.api(`file/download?${this.pr}&uc_param_str=`, {
|
||||
fids: [this.saveFileIdCaches[fileId]],
|
||||
});
|
||||
if (down.data) {
|
||||
return down.data[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
export {Quark}
|
||||
Reference in New Issue
Block a user