From e8a86f8df8f98ea1ca15c095c1ae2dab267d71af Mon Sep 17 00:00:00 2001
From: KanouAo <214709230@qq.com>
Date: Tue, 20 May 2025 22:48:32 +0800
Subject: [PATCH 1/5] 5.20
---
.gitignore | 11 +
test.js | 63 +
...200\205hmjz100\347\232\204\350\257\235.md" | 50 +
...0\275\275\345\212\251\346\211\213.user.js" | 2006 +++++++++++++----
4 files changed, 1690 insertions(+), 440 deletions(-)
create mode 100644 .gitignore
create mode 100644 test.js
create mode 100644 "\347\273\231\345\274\200\345\217\221\350\200\205hmjz100\347\232\204\350\257\235.md"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..01d737d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+# 忽略所有文件
+!网盘直链下载助手.user.js # 保留这个文件
+!给开发者hmjz100的话.md
+
+/config/
+node_modules/
+package-lock.json
+*.json
+*.css
+LICENSE
+README.md
\ No newline at end of file
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..ca51db1
--- /dev/null
+++ b/test.js
@@ -0,0 +1,63 @@
+// let callCounter = 0; // 全局计数器
+
+// async function getFilesByOnce(file) {
+// // 每调用50次暂停3秒
+// if (callCounter >= 50) {
+// console.log('已调用50次,暂停3秒...');
+// await new Promise(resolve => setTimeout(resolve, 3000)); // 暂停3秒
+// callCounter = 0; // 重置计数器
+// }
+
+// console.log(`防反爬计数器: ${callCounter}`);
+// callCounter++; // 增加计数器
+
+// // 这里模拟获取文件的操作
+// // 实际操作可能包括网络请求等异步任务
+// // 返回文件数据或链接
+// return `链接: ${file}`;
+// }
+
+// // 创建一个异步迭代器,模拟动态生成文件
+// async function* fileGenerator(totalFiles) {
+// let index = 0;
+// while (index < totalFiles) {
+// // 模拟异步生成文件
+// await new Promise(resolve => setTimeout(resolve, 100));
+// yield `file ${index++}`;
+// }
+// }
+
+// async function processFilesWithLimit(fileIterator, limit) {
+// const executing = new Set();
+// const results = [];
+
+// for await (const file of fileIterator) {
+// const result = getFilesByOnce(file);
+// results.push(result);
+// executing.add(result);
+
+// if (executing.size >= limit) {
+// await Promise.race(executing);
+// }
+
+// // 当一个文件处理完毕后,从执行集合中移除
+// executing.delete(result);
+// }
+
+// // 等待所有剩余的文件处理完毕
+// await Promise.all(executing);
+// return results;
+// }
+
+// (async () => {
+// const totalFiles = 500; // 总文件数
+// const limit = 10; // 并发限制
+
+// // 创建文件迭代器
+// const files = fileGenerator(totalFiles);
+
+// // 使用并发限制处理所有文件
+// const results = await processFilesWithLimit(files, limit);
+
+// console.log('所有文件处理完毕', results);
+// })();
\ No newline at end of file
diff --git "a/\347\273\231\345\274\200\345\217\221\350\200\205hmjz100\347\232\204\350\257\235.md" "b/\347\273\231\345\274\200\345\217\221\350\200\205hmjz100\347\232\204\350\257\235.md"
new file mode 100644
index 0000000..a09ecdb
--- /dev/null
+++ "b/\347\273\231\345\274\200\345\217\221\350\200\205hmjz100\347\232\204\350\257\235.md"
@@ -0,0 +1,50 @@
+我增加了下载文件夹功能,一键下载文件夹下所有的文件(多个)文件夹嵌套文件夹的这种目录组织都能下载下来,测试环境 win11、edge 浏览器、RPC 发 Aira2
+
+我只动了(改)网盘直链下载助手.user,其它我都没改
+我虽然会写代码,但油猴我第 1 次做,爬网站数据是第 2 次,上次还是咸鱼捡二手的提醒,
+我虽然会 JS 但并不是主 JS 的,对 js 同步异步这边不是很熟悉,你可以看情况修改
+标注 TODO 的都是要注意一下的。
+
+我是从 gitee 上找到这项目的,结果我改好了,才看到你 github 也上传了,你 gitee 上没写 github 上的链接,然后发现你 Gitee 上没同步,进度落下几个月……。
+我 Gitee 和 GitHub 都同时推送,你可以选择任意一个合并,Gitee 毕竟是国内的,政策之类的怕删代码我不怎么用。
+
+因为目录算是特殊的文件,我始终假设返回的是文件,统一起 file 这系列的名字,后续再判断是否文件夹
+
+获取下载链接的时候,我觉得每获取 1 个都展示出来太快,会晃花眼,我调整了下每批次才展示 1 次,你觉得不合适可以改回去
+
+有的网盘给的链接只有几小时时效,推荐拉高下载器同时任务数,或者等失败了再用脚本再请求次再下载(需要注意设置不覆盖同名文件),
+
+我平时不怎么下载东西,所以只是简单测试,不知道有没有问题
+
+广度和递归遍历文件夹我犹豫了很久,广度可以改成并发访问多个文件夹加快速度,甚至写了一半了,后来还是觉得递归好点,一是更贴合人类访问逻辑,防反爬,二是一般人分享文件,不会存那么多个文件夹,会是少数几个文件夹里放大量的文件,导致广度并发比递归快不了多少。
+
+百度:
+已完成
+
+阿里:
+关于分享的那部分,原作者的就有问题,我就没做
+
+移动:
+关于分享的那部分,原作者的就有问题,我就没做
+移动网盘文件数量多,比如几百个的时候,发 RPC 会卡住,但是正常发 RPC,发完会才能操作,这边应该是你这边的问题,请看下(测试环境: windows 发本地的 AriaNg Native 客户端)。
+
+夸克:
+我认为连续访问网盘的接口不如直接拿全部 ID 合适,post 协议本身不作数据长度上限,即使后台限制为 1M,也有 65536 个文件 ID 了,你如果觉得不合适可以修改
+我发觉我下个 37 个 G 的单个文件,只有 30 几 K 的速度,连接数只有 1,其实小点的哪个十多个 G 的文件都是正常的,先骂个夸克。
+
+天翼:
+拿分享的时候有 1 次不完整,不知是不是我看错了
+
+UC:
+1、我看到 user-agent 写的是夸克的,怕你写错,你注意下。
+2、我认为连续访问网盘的接口不如直接拿全部 ID 合适,post 协议本身不作数据长度上限,即使后台限制为 1M,也有 65536 个文件 ID 了,你如果觉得不合适可以修改
+
+123:
+1、我测试时发现大量上传名字按顺序,但内容一样的记事本,它会提示风控,可能抓得严,但名字内容随机就没所谓,要注意下。
+2、遍历文件的请求 URL 中间有 XXX=时间戳-XXX-XXX 的格式,我发觉那放 3 个随机数竟然也行,如果不合适你就找下。
+cookies 有串 CNZZDATA128030xxxx=191082xxxx-174757xxxx 看起来有点像,可以试试
+3、123 网盘的分享站有 3 个,www.123pan.com、www.123684.com、www.123912.com,这3个站请求的url不一样,但都适配www.123pan.com,如果反爬虫你注意下
+4、我想测试下带密码的那种分享的,哎呀妈呀,都没找到网盘资源,好不容易找到个网站,还有 2 个钟就关站了,注册都卡界面 404,BING 找到几个分享,还都不用密码……,最后我分享我自己的,但这样可能会有问题,比如天翼进自己的分享和进别人的分享状况不一样,要不你自己测试下。
+5、123 网盘你没做需要密码的分享的那种适配,不用密码的功能正常。我简单看了看,在 cookies 没找到密码,按理说应该有的,我就懒得看代码了。不过按理来说,123 的分享一般都是没密码的,实在不行转换思维让用户自己输密码。
+6、123 用着夸克的系统?我看着有的就像从夸克那没注意抄过来的我就删除了,你注意下。
+7、然后平台是 IOS 不是 WEB?我就改了下,觉得不行你就改回来。
diff --git "a/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js" "b/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js"
index 25342f7..e14a8ca 100644
--- "a/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js"
+++ "b/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js"
@@ -2,7 +2,7 @@
// @name LinkSwift
// @namespace github.com/hmjz100
// @version 1.1.0.1
-// @author Hmjz100、油小猴
+// @author KanouAo、Hmjz100、油小猴
// @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNMTAzLjYgMTA3LjRjMy41LTIuMiA4LjktNi4xIDEzLjgtMTIuNXM3LjMtMTIuNSA4LjUtMTYuNWMuNS0xLjcgMi4yLTcuNSAyLjItMTQuNyAwLTEwLjEtMy4zLTI1LjEtMTUuNC0zNi44LTE0LjUtMTQtMzIuMS0xNC4zLTM1LjctMTQuMy04IDAtMTUuNyAxLjktMjIuNiA1LjJDNDQgMjMgMzUuNyAzMS40IDMwLjggNDEuN2MtMS4zIDIuOC00IDQuNy03LjEgNS00IC4zLTcuNSA0LjQtOC45IDkuNi0uNSAxLjktMS42IDMuNS0zLjEgNC43QzQuNCA2Ni44IDAgNzUuNyAwIDg1YzAgNi44IDIuMyAxMy4xIDYuMSAxOC4yIDUuNSA3LjQgMTQuMiAxMi4yIDI0IDEyLjJoNDcuMWM0LjQgMCAxMS0uNSAxOC4zLTMuNSAzLjItMS40IDUuOS0zIDguMS00LjV6IiBmaWxsPSIjQTA5OUYwIi8+PHBhdGggZD0iTTExOS44IDY0LjNjLjEtMTcuMS0xMC40LTI4LTEyLjUtMzAuMUM5NSAyMi4xIDc5LjkgMjEuOCA3Ni45IDIxLjhjLTE3LjYgMC0zMy4zIDEwLjUtMzkuOSAyNi43LS42IDEuMy0xLjggMi4zLTMuNCAyLjNoLS40Yy01LjggMC0xMC42IDQuOC0xMC42IDEwLjd2LjVjMCAxLjQtLjggMi42LTEuOSAzLjNDMTMuNCA2OSA4LjggNzYuOCA4LjggODVjMCAxMi4yIDkuOSAyMi4zIDIyLjIgMjIuM2g0NS4yYzMuNi0uMSAxNy42LS45IDI5LjYtMTIgMi45LTIuOCAxMy45LTEzLjcgMTQtMzF6IiBmaWxsPSIjNTc0QUI4Ii8+PHBhdGggZD0iTTExMC44IDU3LjRsLjIgMy4zYzAgMS4zLTEuMSAyLjQtMi4zIDIuNC0xLjMgMC0yLjMtMS4xLTIuMy0yLjRsLS4xLTIuOHYtLjNjMC0xLjIuOS0yLjIgMi4xLTIuM2guM2MuNyAwIDEuMy4zIDEuNy43LS4yLjEuMy41LjQgMS40em0tMy4zLTEwLjNjMCAxLjItMSAyLjMtMi4yIDIuM2gtLjFjLS44IDAtMS42LS41LTItMS4yLTQuNi04LjMtMTMuMy0xMy41LTIyLjgtMTMuNS0xLjIgMC0yLjMtMS0yLjMtMi4ydi0uMWMwLTEuMiAxLTIuMyAyLjItMi4zaC4xYTMwLjM3IDMwLjM3IDAgMCAxIDE1LjggNC40YzQuNiAyLjggOC40IDYuOCAxMS4xIDExLjUuMS4zLjIuNy4yIDEuMXpNODguMyA3My44TDczLjUgOTMuMmMtMS41IDEuOS0zLjUgMy4xLTUuNyAzLjVoLS4yYy0uNC4xLS44LjEtMS4yLjEtLjYgMC0xLjEtLjEtMS42LS4yLTIuMi0uNC00LjItMS43LTUuNi0zLjVMNDQuMyA3My45Yy0yLTIuNi0yLjUtNS40LTEuNC03LjcuMS0uMS4xLS4yLjItLjIgMS4yLTIgMy41LTMuMiA2LjQtMy4yaDYuNnYtNS43YzAtNi44IDQuNy0xMiAxMC45LTEyIDQuOCAwIDguNSAyLjYgMTAuMyA3LjIuNSAxLjMtLjIgMi43LTEuNSAzLjJzLTIuOC0uMS0zLjMtMS40Yy0xLjEtMi43LTIuOS00LTUuNS00LTMuNSAwLTYgMy02IDd2OC4xYzAgLjUtLjIgMS0uNiAxLjQtLjYuNy0xLjcgMS4xLTIuNiAxLjFoLTguNGMtMS4zIDAtMiAuNC0yLjEuNy0uMi40IDAgMS4zLjkgMi40TDYzLjEgOTBjLjkgMS4yIDIuMSAxLjggMy4zIDEuOHMyLjMtLjYgMy4xLTEuN2wxNC44LTE5LjNjLjktMS4xIDEuMS0yIC45LTIuNC0uMi0uMy0uOS0uNy0yLjEtLjdoLTcuNmMtLjkgMC0xLjctLjUtMi4xLTEuMi0uMy0uNC0uNC0uOC0uNC0xLjMgMC0xLjQgMS4xLTIuNSAyLjUtMi41aDcuNmMzLjEgMCA1LjUgMS4zIDYuNiAzLjVsLjMuN2MuNyAyLjEuMSA0LjYtMS43IDYuOXoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=
// @description 《也许同类型中最好用?》系列 - 一个基于 JavaScript 的网盘文件下载地址获取工具,基于【网盘直链下载助手】修改 | 支持 百度网盘/阿里云盘/中国移动云盘/天翼云盘/迅雷云盘/夸克网盘/UC网盘/123云盘 八大网盘 | 开源・自用・去广 | 改界面・添功能・修Bug | 既超越原版,亦是同类中最好用版本!👋
// @description:zh-TW 《也許同類型中最好用?》系列 - 一個基於 JavaScript 的網盤檔案下載地址獲取工具,基於【網盤直鏈下載助手】改編 | 支援 百度網盤/阿里雲盤/中國移動雲盤/天翼雲盤/迅雷雲盤/夸克網盤/UC網盤/123雲盤 八大平台 | 開源・自用・除廣 | 改介面・擴功能・修Bug | 既超越原版,亦是同類中最好用版本!👋
@@ -108,10 +108,9 @@
* @license AGPL-3.0-or-later
* @see {@link https://github.com/hmjz100/LinkSwift/ Github 仓库}
*/
-(function linkSwift() {
+(function linkSwift() {
// 严格模式,确保代码安全执行
'use strict';
-
// unsafeWindow 检测
if (typeof unsafeWindow === 'undefined') {
window.unsafeWindow = window;
@@ -140,7 +139,10 @@
sversion = (scriptInfo?.version?.toString() || "1.1.0.1"),
sicon = (scriptInfo?.icon || "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNMTAzLjYgMTA3LjRjMy41LTIuMiA4LjktNi4xIDEzLjgtMTIuNXM3LjMtMTIuNSA4LjUtMTYuNWMuNS0xLjcgMi4yLTcuNSAyLjItMTQuNyAwLTEwLjEtMy4zLTI1LjEtMTUuNC0zNi44LTE0LjUtMTQtMzIuMS0xNC4zLTM1LjctMTQuMy04IDAtMTUuNyAxLjktMjIuNiA1LjJDNDQgMjMgMzUuNyAzMS40IDMwLjggNDEuN2MtMS4zIDIuOC00IDQuNy03LjEgNS00IC4zLTcuNSA0LjQtOC45IDkuNi0uNSAxLjktMS42IDMuNS0zLjEgNC43QzQuNCA2Ni44IDAgNzUuNyAwIDg1YzAgNi44IDIuMyAxMy4xIDYuMSAxOC4yIDUuNSA3LjQgMTQuMiAxMi4yIDI0IDEyLjJoNDcuMWM0LjQgMCAxMS0uNSAxOC4zLTMuNSAzLjItMS40IDUuOS0zIDguMS00LjV6IiBmaWxsPSIjQTA5OUYwIi8+PHBhdGggZD0iTTExOS44IDY0LjNjLjEtMTcuMS0xMC40LTI4LTEyLjUtMzAuMUM5NSAyMi4xIDc5LjkgMjEuOCA3Ni45IDIxLjhjLTE3LjYgMC0zMy4zIDEwLjUtMzkuOSAyNi43LS42IDEuMy0xLjggMi4zLTMuNCAyLjNoLS40Yy01LjggMC0xMC42IDQuOC0xMC42IDEwLjd2LjVjMCAxLjQtLjggMi42LTEuOSAzLjNDMTMuNCA2OSA4LjggNzYuOCA4LjggODVjMCAxMi4yIDkuOSAyMi4zIDIyLjIgMjIuM2g0NS4yYzMuNi0uMSAxNy42LS45IDI5LjYtMTIgMi45LTIuOCAxMy45LTEzLjcgMTQtMzF6IiBmaWxsPSIjNTc0QUI4Ii8+PHBhdGggZD0iTTExMC44IDU3LjRsLjIgMy4zYzAgMS4zLTEuMSAyLjQtMi4zIDIuNC0xLjMgMC0yLjMtMS4xLTIuMy0yLjRsLS4xLTIuOHYtLjNjMC0xLjIuOS0yLjIgMi4xLTIuM2guM2MuNyAwIDEuMy4zIDEuNy43LS4yLjEuMy41LjQgMS40em0tMy4zLTEwLjNjMCAxLjItMSAyLjMtMi4yIDIuM2gtLjFjLS44IDAtMS42LS41LTItMS4yLTQuNi04LjMtMTMuMy0xMy41LTIyLjgtMTMuNS0xLjIgMC0yLjMtMS0yLjMtMi4ydi0uMWMwLTEuMiAxLTIuMyAyLjItMi4zaC4xYTMwLjM3IDMwLjM3IDAgMCAxIDE1LjggNC40YzQuNiAyLjggOC40IDYuOCAxMS4xIDExLjUuMS4zLjIuNy4yIDEuMXpNODguMyA3My44TDczLjUgOTMuMmMtMS41IDEuOS0zLjUgMy4xLTUuNyAzLjVoLS4yYy0uNC4xLS44LjEtMS4yLjEtLjYgMC0xLjEtLjEtMS42LS4yLTIuMi0uNC00LjItMS43LTUuNi0zLjVMNDQuMyA3My45Yy0yLTIuNi0yLjUtNS40LTEuNC03LjcuMS0uMS4xLS4yLjItLjIgMS4yLTIgMy41LTMuMiA2LjQtMy4yaDYuNnYtNS43YzAtNi44IDQuNy0xMiAxMC45LTEyIDQuOCAwIDguNSAyLjYgMTAuMyA3LjIuNSAxLjMtLjIgMi43LTEuNSAzLjJzLTIuOC0uMS0zLjMtMS40Yy0xLjEtMi43LTIuOS00LTUuNS00LTMuNSAwLTYgMy02IDd2OC4xYzAgLjUtLjIgMS0uNiAxLjQtLjYuNy0xLjcgMS4xLTIuNiAxLjFoLTguNGMtMS4zIDAtMiAuNC0yLjEuNy0uMi40IDAgMS4zLjkgMi40TDYzLjEgOTBjLjkgMS4yIDIuMSAxLjggMy4zIDEuOHMyLjMtLjYgMy4xLTEuN2wxNC44LTE5LjNjLjktMS4xIDEuMS0yIC45LTIuNC0uMi0uMy0uOS0uNy0yLjEtLjdoLTcuNmMtLjkgMC0xLjctLjUtMi4xLTEuMi0uMy0uNC0uNC0uOC0uNC0xLjMgMC0xLjQgMS4xLTIuNSAyLjUtMi41aDcuNmMzLjEgMCA1LjUgMS4zIDYuNiAzLjVsLjMuN2MuNyAyLjEuMSA0LjYtMS43IDYuOXoiIGZpbGw9IiNmZmYiLz48L3N2Zz4="),
mhandler = GM_info.scriptHandler,
- mversion = GM_info.version;
+ mversion = GM_info.version,
+ globalSleep=500, //延时,统一在1个地方修改方便用,可以考虑做个接口给用户修改,做好限制,别让用户做死
+ globalSleepRandSeed=100,//延时随机种子,直接在上面的数值上加
+ globalBatchsize=50;//每次处理批次的大小
/* 设置选项 */
// Shell类型(用于curl下载)
@@ -225,6 +227,7 @@
* 基础配置集合
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
*/
const config = {
base: {
@@ -270,8 +273,14 @@
downloadLink: "pan.baidu.com"
},
getAccessToken: "https://openapi.baidu.com/oauth/2.0/authorize?response_type=token&scope=basic,netdisk&client_id=IlLqBbU3GjQ0t46TRwFateTprHWl39zF&redirect_uri=oob&confirm_login=0",
- getLink: "https://pan.baidu.com/rest/2.0/xpan/multimedia?method=filemetas&dlink=1",
- getFiles: "https://pan.baidu.com/rest/2.0/xpan/file?method=list&showempty=1",
+ getLink:{
+ home:"https://pan.baidu.com/rest/2.0/xpan/multimedia?method=filemetas&dlink=1",
+ share:""
+ },
+ getFiles:{
+ home:"https://pan.baidu.com/rest/2.0/xpan/file?method=list&showempty=1",
+ share:""
+ },
getShareLink: "https://pan.baidu.com/api/sharedownload?channel=chunlei&clienttype=0&web=1&app_id=250528",
getShareInfo: "https://pan.baidu.com/share/tplconfig?fields=sign,timestamp&channel=chunlei&web=1&app_id=250528&clienttype=0",
getShareFiles: "https://pan.baidu.com/rest/2.0/xpan/share?method=list&showempty=1"
@@ -284,8 +293,14 @@
},
$aliyun: {
api: {
- getLink: "https://api.aliyundrive.com/v2/file/get_download_url",
- getShareLink: "https://api.aliyundrive.com/v2/file/get_share_link_download_url"
+ getLink:{
+ home:"https://api.aliyundrive.com/v2/file/get_download_url",
+ share:"https://api.aliyundrive.com/v2/file/get_share_link_download_url"
+ },
+ getFiles:{
+ home:"https://api.aliyundrive.com/adrive/v3/file/list?jsonmask=next_marker%2Citems(name%2Cfile_id%2Cdrive_id%2Ctype%2Csize%2Ccreated_at%2Cupdated_at%2Ccategory%2Cfile_extension%2Cparent_file_id%2Cmime_type%2Cstarred%2Cthumbnail%2Curl%2Cstreams_info%2Ccontent_hash%2Cuser_tags%2Cuser_meta%2Ctrashed%2Cvideo_media_metadata%2Cvideo_preview_metadata%2Csync_meta%2Csync_device_flag%2Csync_flag%2Cpunish_flag%2Cfrom_share_id)",
+ share:"https://api.aliyundrive.com/adrive/v2/file/list_by_share"
+ },
},
mount: {
home: "[class^=\"header--\"]>[class^=\"actions--\"]",
@@ -297,7 +312,14 @@
},
$mcloud: {
api: {
- getLink: "https://personal-kd-njs.yun.139.com/hcy/file/getDownloadUrl"
+ getLink:{
+ home:"https://personal-kd-njs.yun.139.com/hcy/file/getDownloadUrl",
+ share:""
+ },
+ getFiles:{
+ home:"https://personal-kd-njs.yun.139.com/hcy/file/list",
+ share:""
+ },
},
mount: {
home: ".top_button",
@@ -307,7 +329,14 @@
$tcloud: {
api: {
getAccessToken: "https://api.cloud.189.cn/open/oauth2/ssoH5.action",
- getLink: "https://api.cloud.189.cn/open/file/getFileDownloadUrl.action"
+ getLink:{
+ home:"https://api.cloud.189.cn/open/file/getFileDownloadUrl.action",
+ share:""
+ },
+ getFiles:{
+ home:"https://cloud.189.cn/api/open/file/listFiles.action",
+ share:"https://cloud.189.cn/api/open/share/listShareDir.action"
+ },
},
mount: {
home: "[class*=\"FileHead_file-head-left\"]",
@@ -319,7 +348,14 @@
mirror: [
"vod0007-h05-vip-lixian.xunlei.com", "vod0008-h05-vip-lixian.xunlei.com", "vod0009-h05-vip-lixian.xunlei.com", "vod0010-h05-vip-lixian.xunlei.com", "vod0011-h05-vip-lixian.xunlei.com", "vod0012-h05-vip-lixian.xunlei.com", "vod0013-h05-vip-lixian.xunlei.com", "vod0014-h05-vip-lixian.xunlei.com", "vod0067-aliyun08-vip-lixian.xunlei.com", "vod0254-aliyun08-vip-lixian.xunlei.com", "vod0255-aliyun08-vip-lixian.xunlei.com", "vod0256-aliyun08-vip-lixian.xunlei.com", "vod0257-aliyun08-vip-lixian.xunlei.com", "vod0258-aliyun08-vip-lixian.xunlei.com", "vod0259-aliyun08-vip-lixian.xunlei.com", "vod0260-aliyun08-vip-lixian.xunlei.com", "vod0261-aliyun08-vip-lixian.xunlei.com", "vod0262-aliyun08-vip-lixian.xunlei.com", "vod0263-aliyun08-vip-lixian.xunlei.com", "vod0264-aliyun08-vip-lixian.xunlei.com", "vod0265-aliyun08-vip-lixian.xunlei.com", "vod0266-aliyun08-vip-lixian.xunlei.com", "vod0267-aliyun08-vip-lixian.xunlei.com", "vod0554-aliyun06-vip-lixian.xunlei.com", "vod0555-aliyun06-vip-lixian.xunlei.com", "vod0556-aliyun06-vip-lixian.xunlei.com", "vod0680-aliyun08-vip-lixian.xunlei.com", "vod0681-aliyun08-vip-lixian.xunlei.com", "vod0682-aliyun08-vip-lixian.xunlei.com", "vod0683-aliyun08-vip-lixian.xunlei.com", "vod0684-aliyun08-vip-lixian.xunlei.com", "vod0685-aliyun08-vip-lixian.xunlei.com", "vod0686-aliyun08-vip-lixian.xunlei.com", "vod0687-aliyun08-vip-lixian.xunlei.com", "vod0688-aliyun08-vip-lixian.xunlei.com", "vod0689-aliyun08-vip-lixian.xunlei.com", "vod0690-aliyun08-vip-lixian.xunlei.com", "vod0724-aliyun08-vip-lixian.xunlei.com", "vod0725-aliyun08-vip-lixian.xunlei.com", "vod0726-aliyun08-vip-lixian.xunlei.com", "vod0727-aliyun08-vip-lixian.xunlei.com", "vod0728-aliyun08-vip-lixian.xunlei.com", "vod0075.aliyun06.vip.lixian.xunlei.com", "vod0076.aliyun06.vip.lixian.xunlei.com", "vod0077.aliyun06.vip.lixian.xunlei.com", "vod0779-aliyun04-vip-lixian.xunlei.com", "vod0078.aliyun06.vip.lixian.xunlei.com", "vod0780-aliyun04-vip-lixian.xunlei.com", "vod0781-aliyun04-vip-lixian.xunlei.com", "vod0079.aliyun06.vip.lixian.xunlei.com", "vod0080.aliyun06.vip.lixian.xunlei.com", "vod0117.aliyun04.vip.lixian.xunlei.com", "vod0118.aliyun04.vip.lixian.xunlei.com", "vod0119.aliyun04.vip.lixian.xunlei.com", "vod1284-aliyun06-vip-lixian.xunlei.com", "vod1285-aliyun06-vip-lixian.xunlei.com", "vod1363-aliyun06-vip-lixian.xunlei.com", "vod1371-aliyun06-vip-lixian.xunlei.com", "vod1372-aliyun06-vip-lixian.xunlei.com", "vod1426-aliyun06-vip-lixian.xunlei.com", "vod1427-aliyun06-vip-lixian.xunlei.com", "vod1428-aliyun06-vip-lixian.xunlei.com", "vod1429-aliyun06-vip-lixian.xunlei.com", "vod1442-aliyun06-vip-lixian.xunlei.com", "vod1443-aliyun06-vip-lixian.xunlei.com", "vod1444-aliyun06-vip-lixian.xunlei.com", "vod1445-aliyun06-vip-lixian.xunlei.com", "vod1446-aliyun06-vip-lixian.xunlei.com", "vod1447-aliyun06-vip-lixian.xunlei.com", "vod1469-aliyun06-vip-lixian.xunlei.com", "vod1470-aliyun06-vip-lixian.xunlei.com", "vod1471-aliyun06-vip-lixian.xunlei.com", "vod1489-aliyun06-vip-lixian.xunlei.com", "vod1490-aliyun06-vip-lixian.xunlei.com", "vod1491-aliyun06-vip-lixian.xunlei.com", "vod1492-aliyun06-vip-lixian.xunlei.com", "vod1493-aliyun06-vip-lixian.xunlei.com", "vod0215.aliyun06.vip.lixian.xunlei.com", "vod0216.aliyun06.vip.lixian.xunlei.com", "vod0217.aliyun06.vip.lixian.xunlei.com", "vod0218.aliyun06.vip.lixian.xunlei.com", "vod0219.aliyun06.vip.lixian.xunlei.com", "vod0220.aliyun06.vip.lixian.xunlei.com", "vod0241.aliyun08.vip.lixian.xunlei.com", "vod0244.aliyun08.vip.lixian.xunlei.com", "vod0251.aliyun08.vip.lixian.xunlei.com", "vod0252.aliyun08.vip.lixian.xunlei.com", "vod0253.aliyun08.vip.lixian.xunlei.com", "vod0254.aliyun08.vip.lixian.xunlei.com", "vod0255.aliyun08.vip.lixian.xunlei.com", "vod0256.aliyun08.vip.lixian.xunlei.com", "vod0257.aliyun08.vip.lixian.xunlei.com", "vod0260.aliyun08.vip.lixian.xunlei.com", "vod0261.aliyun08.vip.lixian.xunlei.com", "vod0262.aliyun08.vip.lixian.xunlei.com", "vod0263.aliyun08.vip.lixian.xunlei.com", "vod0264.aliyun08.vip.lixian.xunlei.com", "vod0265.aliyun08.vip.lixian.xunlei.com", "vod0266.aliyun08.vip.lixian.xunlei.com", "vod0267.aliyun08.vip.lixian.xunlei.com", "vod3379-aliyun04-vip-lixian.xunlei.com", "vod3380-aliyun04-vip-lixian.xunlei.com", "vod3429-aliyun04-vip-lixian.xunlei.com", "vod3458-aliyun04-vip-lixian.xunlei.com", "vod3459-aliyun04-vip-lixian.xunlei.com", "vod3496-aliyun04-vip-lixian.xunlei.com", "vod3497-aliyun04-vip-lixian.xunlei.com", "vod3498-aliyun04-vip-lixian.xunlei.com", "vod3499-aliyun04-vip-lixian.xunlei.com", "vod3500-aliyun04-vip-lixian.xunlei.com", "vod3501-aliyun04-vip-lixian.xunlei.com", "vod3522-aliyun04-vip-lixian.xunlei.com", "vod3523-aliyun04-vip-lixian.xunlei.com", "vod3533-aliyun04-vip-lixian.xunlei.com", "vod3534-aliyun04-vip-lixian.xunlei.com", "vod3535-aliyun04-vip-lixian.xunlei.com", "vod3536-aliyun04-vip-lixian.xunlei.com", "vod3549-aliyun04-vip-lixian.xunlei.com", "vod3550-aliyun04-vip-lixian.xunlei.com", "vod3551-aliyun04-vip-lixian.xunlei.com", "vod3552-aliyun04-vip-lixian.xunlei.com", "vod3553-aliyun04-vip-lixian.xunlei.com", "vod3554-aliyun04-vip-lixian.xunlei.com", "vod3555-aliyun04-vip-lixian.xunlei.com", "vod0551.aliyun06.vip.lixian.xunlei.com", "vod0552.aliyun06.vip.lixian.xunlei.com", "vod0553.aliyun06.vip.lixian.xunlei.com", "vod0554.aliyun06.vip.lixian.xunlei.com", "vod0555.aliyun06.vip.lixian.xunlei.com", "vod0556.aliyun06.vip.lixian.xunlei.com", "vod0686.aliyun08.vip.lixian.xunlei.com", "vod0687.aliyun08.vip.lixian.xunlei.com", "vod0688.aliyun08.vip.lixian.xunlei.com", "vod0689.aliyun08.vip.lixian.xunlei.com", "vod0724.aliyun08.vip.lixian.xunlei.com", "vod0725.aliyun08.vip.lixian.xunlei.com", "vod0726.aliyun08.vip.lixian.xunlei.com", "vod0727.aliyun08.vip.lixian.xunlei.com", "vod0728.aliyun08.vip.lixian.xunlei.com", "vod0759.aliyun04.vip.lixian.xunlei.com", "vod0760.aliyun04.vip.lixian.xunlei.com", "vod0769.aliyun04.vip.lixian.xunlei.com", "vod0770.aliyun04.vip.lixian.xunlei.com", "vod0771.aliyun04.vip.lixian.xunlei.com", "vod0772.aliyun04.vip.lixian.xunlei.com", "vod0773.aliyun04.vip.lixian.xunlei.com", "vod0774.aliyun04.vip.lixian.xunlei.com", "vod0775.aliyun04.vip.lixian.xunlei.com", "vod0776.aliyun04.vip.lixian.xunlei.com", "vod0777.aliyun04.vip.lixian.xunlei.com", "vod0778.aliyun04.vip.lixian.xunlei.com", "vod0779.aliyun04.vip.lixian.xunlei.com", "vod0780.aliyun04.vip.lixian.xunlei.com", "vod0781.aliyun04.vip.lixian.xunlei.com", "vod3522.aliyun04.vip.lixian.xunlei.com", "vod3523.aliyun04.vip.lixian.xunlei.com", "vod3533.aliyun04.vip.lixian.xunlei.com", "vod3535.aliyun04.vip.lixian.xunlei.com", "vod3550.aliyun04.vip.lixian.xunlei.com", "vod3551.aliyun04.vip.lixian.xunlei.com", "vod3552.aliyun04.vip.lixian.xunlei.com", "vod3553.aliyun04.vip.lixian.xunlei.com", "vod3554.aliyun04.vip.lixian.xunlei.com", "vod3555.aliyun04.vip.lixian.xunlei.com"
],
- getLink: "https://api-pan.xunlei.com/drive/v1/files/"
+ getLink:{
+ home:"https://api-pan.xunlei.com/drive/v1/files/",
+ share:""
+ },
+ getFiles:{
+ home:"https://api-pan.xunlei.com/drive/v1/files?",
+ share:"https://api.aliyundrive.com/adrive/v2/file/list_by_share"
+ },
},
mount: {
home: "[class^=\"FileMenu__menu--\"]",
@@ -331,7 +367,14 @@
ua: {
downloadLink: "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"
},
- getLink: "https://drive.quark.cn/1/clouddrive/file/download?pr=ucpro&fr=pc"
+ getLink:{
+ home:"https://drive.quark.cn/1/clouddrive/file/download?pr=ucpro&fr=pc",
+ share:""
+ },
+ getFiles:{
+ home:"https://drive.quark.cn/1/clouddrive/file/sort?pr=ucpro&fr=pc",
+ share:""
+ }
},
mount: {
home: ".btn-operate .btn-main",
@@ -341,9 +384,18 @@
$uc: {
api: {
ua: {
- downloadLink: "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"
+ //TODO 为啥是夸克的?怕你写错改了下
+ // downloadLink: "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"
+ downloadLink: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"
+ },
+ getLink:{
+ home:"https://pc-api.uc.cn/1/clouddrive/file/download?pr=UCBrowser&fr=pc",
+ share:""
+ },
+ getFiles:{
+ home:"https://pc-api.uc.cn/1/clouddrive/file/sort",
+ share:""
},
- getLink: "https://pc-api.uc.cn/1/clouddrive/file/download?pr=UCBrowser&fr=pc"
},
mount: {
home: ".btn-operate .btn-main",
@@ -352,8 +404,14 @@
},
$123pan: {
api: {
- getLink: "https://www.123pan.com/api/file/download_info",
- getShareLink: "https://www.123pan.com/api/share/download/info"
+ getLink:{
+ home:"https://www.123pan.com/api/file/download_info",
+ share:"https://www.123pan.com/api/share/download/info"
+ },
+ getFiles:{
+ home:"https://www.123pan.com/b/api/file/list/new",
+ share:"https://www.123pan.com/b/api/share/get"
+ },
},
mount: {
home: "main.ant-layout-content .site-layout-background .homeClass .wenserh",
@@ -366,6 +424,7 @@
* 基础工具集合
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
*/
let base = {
/**
@@ -418,19 +477,21 @@
* 发送链接到 RPC 下载器
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
* @description RPC 下载必备
* @param {string} link - 下载链接
* @param {string} filename - 文件名
* @param {string} [header] - 自定义请求头参数(可选)
+ * @param {string} path - 下载路径
* @returns {Promise<'success'|'fail'>} 发送态结果
*/
- async sendLinkToRPC(link, filename, header) {
+ async sendLinkToRPC(link, filename, path, header) {
let rpc = {
domain: base.getValue('setting_rpc_domain'),
port: base.getValue('setting_rpc_port'),
path: base.getValue('setting_rpc_path'),
token: base.getValue('setting_rpc_token'),
- dir: base.getValue('setting_rpc_dir'),
+ dir: base.getValue('setting_rpc_dir')+path,
};
let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
@@ -1313,6 +1374,14 @@
return new Promise(resolve => setTimeout(resolve, time));
},
+ /**
+ * 延时执行(随机)
+ * @author KanouAo
+ */
+ customSleep(){
+ base.sleep(globalSleep+Math.random()*globalSleepRandSeed);
+ },
+
/**
* 判断版本号新旧
* @author hmjz100
@@ -2934,8 +3003,13 @@
* 百度网盘
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
*/
let $baidu = {
+ cnt:0,//计数器,用于控制随机延迟
+ fileCount:0,//文件计数
+ accessToken:"",
+
_getExtra() {
let seKey = decodeURIComponent(base.getCookie('BDCLND'));
return '{' + '"sekey":"' + seKey + '"' + "}";
@@ -3257,7 +3331,7 @@
target.prepend(base.createLoading());
let BDUSS = $baidu.getBDUSS();
- let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename, [`User-Agent: ${config.$baidu.api.ua.downloadLink}`, `Cookie: BDUSS=${BDUSS}`]);
+ let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename,e.currentTarget.dataset.path, [`User-Agent: ${config.$baidu.api.ua.downloadLink}`, `Cookie: BDUSS=${BDUSS}`]);
if (res === 'success') {
$('.listener-rpc-task').show();
target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
@@ -3591,6 +3665,93 @@
})
},
+ async getFilesByOnce(file,params){
+ try {
+ let res;
+ if(page=="home"||page=="main"){
+ //我找的链接获取文件,1页100个,这个能获取文件夹所有文件我就直接用了
+ //TODO path属性被占用,原变量就请求下载时用一次,就 path 改成 _path
+ let url = `${config.$baidu.api.getFiles.home}&dir=${encodeURIComponent(file._path)}&access_token=${this.accessToken}`;
+ res = await base.get(url, { "User-Agent": config.$baidu.api.ua.downloadLink});
+ }else if(page=="share"){
+ }else{
+ return message.error(`提示: 网站页面错误`);
+ }
+ return res;
+ } catch (e) {
+ return message.error(`提示: 文件获取请求失败`);
+ }
+ },
+
+ async getFileUrlByOnce(file,params) {
+ try {
+ let res;
+ if(page=="home"||page=="main"){
+ let url = `${config.$baidu.api.getLink.home}&fsids=${params.fsids}&access_token=${this.accessToken}`;
+ res = await base.get(url, { "User-Agent": config.$baidu.api.ua.downloadLink });
+ }else if(page=="share"){
+ }else{
+ return message.error(`提示: 网站页面错误`);
+ }
+ return res;
+ } catch (e) {
+ return message.error(`提示: 文件下载链接请求失败`);
+ }
+ },
+
+ async fetchAllPages(file) {
+ //分页获取文件夹内文件数据
+ let files=[];//文件数据列表
+ let res;
+
+ //随机停顿防反爬
+ this.cnt++;
+ if (this.cnt >= 50+Math.random()*10) {
+ doc.find('.loading-popup .swal2-html-container').html(`
休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ this.cnt = 0;
+ }
+
+ //发送请求
+ let params={"_path":file._path};
+ res=await this.getFilesByOnce(file,params);
+
+ //请求失败
+ if(res?.errno){
+ return message.error(`提示:休息 3 秒...
`);
- await base.sleep(3000);
- cnt = 0;
- }
- }
- return files;
+ //获取文件目录结构(递归)
+ for (let file of selectList) {
+ //遍历选中文件
+ //统一变量名
+ fileList = fileList.concat(await this.fetchFiles(file,fileTree));
}
- let files = selectList.filter(f => !f.isdir);
-
- if (selectList.some(f => f.isdir)) {
- files = files.concat(await fetchFiles(selectList.filter(f => f.isdir)));
- }
- if (!files.length) {
+ //文件夹为空
+ if (!fileList.length) {
return message.error('提示:休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ };
+
+ //累加批次
+ i += batchSize;
+ batchSize = globalBatchsize+Math.ceil(Math.random()*5)
}
if (linkList.length) {
+ for (let i = 0; i < linkList.length; i++) {//重写下载路径
+ linkList[i].path = filesDict[linkList[i].fs_id].path;
+ }
base.showMainDialog(config.base.dom.button[mode].title, this.generateDom(linkList), config.base.dom.button[mode].footer);
} else {
return message.error('提示:休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ this.cnt = 0;
+ }
+
+ //发送请求
+ let param={"drive_id":file.drive_id,"parent_file_id":file.file_id,"marker":marker};
+ res=await this.getFilesByOnce(file,param);
+
+ //请求失败
+ if(!res?.items){
+ return message.error(`提示:休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ };
- // 每次处理完一个批次后,等待 1 秒
- await base.sleep(1000);
+ //累加批次
+ i += batchSize;
+ batchSize = 15+Math.ceil(Math.random()*5)
}
} else {
return message.error('提示:休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ this.cnt = 0;
+ }
+
+ //发送请求
+ let params={"parent_file_id":file.fileId,"pageCursor":nextPageCursor};
+ res=await this.getFilesByOnce(file,params);
+
+ //请求失败
+ if(!res.success){//注意变量名
+ return message.error(`提示:休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ };
+
+ //累加批次
+ i += batchSize;
+ batchSize = 15+Math.ceil(Math.random()*5)
}
} else {
return message.error('提示:>休息 ${globalSleep} 毫秒...
`);
+ await base.sleep(globalSleep+Math.random()*globalSleepRandSeed);
+ this.cnt = 0;
+ }
+ //发送请求
+ let param={"pageNum":pageNum,"id":file.id};
+ res=await this.getFilesByOnce(file,param);
+
+ //请求失败
+ if(!(res?.res_code==0&&res?.res_message=="成功")){
+ return message.error(`提示:休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ };
+
+ //累加批次
+ i += batchSize;
+ batchSize = globalBatchsize+Math.ceil(Math.random()*5)
}
- let html = this.generateDom(selectList);
+ let html = this.generateDom(fileList);
base.showMainDialog(config.base.dom.button[mode].title, html, config.base.dom.button[mode].footer);
},
@@ -5657,10 +6255,11 @@
let content = '';
let alinkAllText = '';
list.forEach((v, i) => {
- if (v.isFolder) return;
- let filename = v.fileName;
+ if (v?.isFolder) return;
+ let filename = v.name;
let size = base.sizeFormat(v.size);
let dlink = v.downloadUrl;
+ let dpath=v.path;
if (!dlink || !dlink.includes("http")) {
content += `
${filename}
@@ -5696,9 +6295,19 @@
}
if (mode === 'rpc') {
content += `
-
${filename}
-
将 ${filename} 推送到 RPC 下载器
-
`;
+
${filename}
+
+
+
+
+
+
+ 将 ${filename} 推送到 RPC 下载器
+
+
`;
}
if (mode === 'curl') {
let alink = base.convertLinkToCurl(dlink, filename);
@@ -5788,8 +6397,14 @@
* 迅雷云盘
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
*/
let $xunlei = {
+ cnt:0,//计数器,用于控制随机延迟
+ fileCount:0,//文件计数
+ authorization:"",
+ token:{},
+
addPageListener() {
/*
防止代码因其他原因被执行多次
@@ -5972,7 +6587,7 @@
target.find('.pl-loading').remove();
target.prepend(base.createLoading());
- let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename);
+ let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename,e.currentTarget.dataset.path);
if (res === 'success') {
$('.listener-rpc-task').show();
target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
@@ -6077,33 +6692,121 @@
return token;
},
+ async getFilesByOnce(item,params){
+ let res;
+ try {
+ if(page=="home"){
+ //limit最多只能获取到200,res返回参数里有个 next_page_token 是令牌,如果是空的就说明不需要下一页
+ //中间奇怪的那段是URL编码的JSON字符串,第1次请求是不带parent_id之前的&的,后面请求是带parent_id前的&的,但都适用
+ let url=`${config.$xunlei.api.getFiles.home}page_token=${params.next_page_token}&parent_id=${params.parent_id}&filters=%7B%22phase%22%3A%7B%22eq%22%3A%22PHASE_TYPE_COMPLETE%22%7D%2C%22trashed%22%3A%7B%22eq%22%3Afalse%7D%7D&with_audit=true&limit=50`;
+ res = await base.get(url, {
+ 'Authorization': this.authorization,
+ 'content-type': "application/json",
+ 'x-captcha-token': this.token.captcha.token,
+ 'x-device-id': this.token.deviceid,
+ });
+ }else if(page=="share"){
+ }else{
+ return message.error(`提示:
网站页面错误`);
+ }
+ return res;
+ } catch (e) {
+ return message.error('提示:
请先登录网盘后再刷新页面呢~');
+ }
+ },
+
async getFileUrlByOnce(item, index, token) {
+ let res;
try {
- if (item.downloadUrl) return {
- index,
- downloadUrl: item.downloadUrl
- };
- let res = await base.get(config.$xunlei.api.getLink + item.id, {
- 'Authorization': `${token.credentials.token_type} ${token.credentials.access_token}`,
- 'content-type': "application/json",
- 'x-captcha-token': token.captcha.token,
- 'x-device-id': token.deviceid,
- });
- if (res.web_content_link) {
- return {
- index,
- downloadUrl: res.web_content_link
- };
- } else {
- return {
+ if(page=="home"){
+ if (item.downloadUrl) return {
index,
- downloadUrl: '获取下载地址失败,刷新后再试试吧~'
+ downloadUrl: item.downloadUrl
};
+ res = await base.get(config.$xunlei.api.getLink.home + item.id, {
+ 'Authorization': `${token.credentials.token_type} ${token.credentials.access_token}`,
+ 'content-type': "application/json",
+ 'x-captcha-token': token.captcha.token,
+ 'x-device-id': token.deviceid,
+ });
+ if (res.web_content_link) {
+ return {
+ index,
+ downloadUrl: res.web_content_link
+ };
+ } else {
+ return {
+ index,
+ downloadUrl: '获取下载地址失败,刷新后再试试吧~'
+ };
+ }
+ }else if(page=="share"){
+ }else{
+ return message.error(`提示:
网站页面错误`);
}
+ return res;
} catch (e) {
return message.error('提示:
请先登录网盘后再刷新页面呢~');
}
},
+
+ async fetchAllPages(file) {
+ //分页获取文件夹内文件数据
+ let files=[];//文件数据列表
+ let next_page_token='';//文件夹内下一段数据的令牌
+ let res;
+ while (true) {
+ //随机停顿防反爬
+ this.cnt++;
+ if (this.cnt >= 50+Math.random()*10) {
+ doc.find('.loading-popup .swal2-html-container').html(`
正遍历到的大型文件夹已获取 ${files.length} 个文件~
休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ this.cnt = 0;
+ }
+
+ //发送请求
+ let param={"next_page_token":next_page_token,"parent_id":file.id};
+ res=await this.getFilesByOnce(file,param);
+
+ //请求失败
+ if(!res?.files){//注意变量名
+ return message.error(`提示:
请求失败,失败码: ${res?.code} 失败信息:${res.message}`);
+ }
+
+ //请求成功
+ files=files.concat(res.files)//注意变量名
+ next_page_token=res.next_page_token;
+ if (!next_page_token)
+ break;
+ }
+ return files;
+ },
+
+ async fetchFiles(file,pNode) {
+ //获取文件目录结构(递归)
+ //节点
+ let fileNode={
+ name:file.name,//注意变量名
+ path:pNode.name === 'root' ? `` : `${pNode.path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ children:[]
+ }
+ pNode.children.push(fileNode);
+ file.path=fileNode.path;
+
+ //判断是否文件夹
+ if (file?.kind!='drive#folder') {//注意变量名
+ this.fileCount++;
+ doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${this.fileCount} 个文件~
`);
+ return file;
+ }
+
+ //文件夹内文件遍历
+ let files=[];
+ for (let f of await this.fetchAllPages(file)) {
+ files= files.concat(await this.fetchFiles(f,fileNode));
+ }
+ return files;
+ },
async getLink() {
Swal.fire({
@@ -6131,40 +6834,72 @@
if (selectList.length === 0) {
return message.error('提示:
请勾选要下载的文件哦~');
}
- if (this.isOnlyFolder()) {
- return message.error('提示:
请打开文件夹后再勾选文件~');
+
+ if(page=="home"){
+ }else if(page=="share"){
+ //分享页面所需的变量
+ }else{
+ return message.error('提示:
页面错误~');
}
+ this.token = this.getToken();
+ this.authorization = `${this.token.credentials.token_type} ${this.token.credentials.access_token}`;
+
+ this.cnt=0;
+ this.fileCount=0;//文件计数
+ let fileList=[];//文件列表,只有文件没有文件夹
+ let fileTree = { name: "root", path: ``, children: [] }; // 文件目录树
if (page === 'home') {
- let token = this.getToken();
- let batchSize = 15;
- let processed = 0;
+ //获取文件目录结构(递归)
+ for (let file of selectList) {
+ //遍历选中文件
+ //统一变量名
+ fileList = fileList.concat(await this.fetchFiles(file,fileTree));
+ }
+
+ //文件夹为空
+ if (!fileList.length) {
+ return message.error('提示:
文件夹是空的哦~');
+ }
+
+ //获取下载链接
doc.find('.loading-popup .loading-title').html(`链接获取中`);
doc.find('.loading-popup .swal2-html-container').html(`
正在获取文件对应的下载链接~
`);
- for (let i = 0; i < selectList.length; i += batchSize) {
- let batch = selectList.slice(i, i + batchSize);
- let queue = [];
+ let batchSize = globalBatchsize+Math.ceil(Math.random()*5);
+ let i=0;
+ while (i < fileList.length){
+ // 分批获取链接
+ let batch = fileList.slice(i, i + batchSize);
+ // 生成请求队列
+ let queue = [];
batch.forEach((item, localIndex) => {
let globalIndex = i + localIndex;
- queue.push(this.getFileUrlByOnce(item, globalIndex, token)
+ queue.push(this.getFileUrlByOnce(item, globalIndex, this.token)
.then(val => {
- processed++;
- doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${processed} / ${selectList.length} 个链接~
`);
+ // doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${processed} / ${selectList.length} 个链接~
`);
return val;
}));
});
let res = await Promise.all(queue);
res.forEach(val => {
- selectList[val.index].downloadUrl = val.downloadUrl;
+ fileList[val.index].downloadUrl = val.downloadUrl;
});
- await base.sleep(1000);
+ // 每次处理完一个批次后,等待
+ if (i + batchSize < fileList.length){
+ doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${i+batch.length} / ${fileList.length} 个链接,请耐心等待哦~
休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ };
+
+ //累加批次
+ i += batchSize;
+ batchSize = globalBatchsize+Math.ceil(Math.random()*5)
}
} else {
return message.error('提示:
页面错误~');
}
- let html = this.generateDom(selectList);
+ let html = this.generateDom(fileList);
base.showMainDialog(config.base.dom.button[mode].title, html, config.base.dom.button[mode].footer);
},
@@ -6180,6 +6915,7 @@
let filename = v.name;
let size = base.sizeFormat(+v.size);
let dlink = v.downloadUrl;
+ let dpath=v.path;
if (!dlink || !dlink.includes("http")) {
content += `
${filename}
@@ -6216,9 +6952,19 @@
}
if (mode === 'rpc') {
content += `
-
${filename}
-
将 ${filename} 推送到 RPC 下载器
-
`;
+
${filename}
+
+
+
+
+
+
+ 将 ${filename} 推送到 RPC 下载器
+
+
`;
}
if (mode === 'curl') {
let alink = base.convertLinkToCurl(dlink, filename);
@@ -6316,8 +7062,12 @@
* 夸克网盘
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
*/
let $quark = {
+ cnt:0,//计数器,用于控制随机延迟
+ fileCount:0,//文件计数
+
addPageListener() {
/*
防止代码因其他原因被执行多次
@@ -6503,7 +7253,7 @@
target.find('.pl-loading').remove();
target.prepend(base.createLoading());
- let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename, [`Cookie: ${document.cookie}`]);
+ let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename,e.currentTarget.dataset.path, [`Cookie: ${document.cookie}`]);
if (res === 'success') {
$('.listener-rpc-task').show();
target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
@@ -6629,6 +7379,91 @@
})
},
+ async getFilesByOnce(item,params){
+ try {
+ let res;
+ if(page=="home"){
+ let url=`${config.$quark.api.getFiles.home}&uc_param_str=&pdir_fid=${item.fid}&_page=${params.pageNum}&_size=50&_fetch_total=1&_fetch_sub_dirs=0&_sort=file_type:asc,file_name:asc`;
+ res = await base.get(url, { "User-Agent": config.$quark.api.ua.downloadLink });
+ }else if(page=="share"){
+ }else{
+ return message.error(`提示:
网站页面错误`);
+ }
+ return res;
+ } catch (e) {
+ return message.error(`提示:
文件获取请求失败`);
+ }
+ },
+
+ async getFileUrlByOnce(item, params) {
+ try {
+ let res;
+ if(page=="home"){
+ res = await base.post(config.$quark.api.getLink.home, { "fids": params.fids }, { "content-type": "application/json;charset=utf-8", "user-agent": config.$quark.api.ua.downloadLink });
+ }else if(page=="share"){
+ }else{
+ return message.error(`提示:
网站页面错误`);
+ }
+ return res;
+ } catch (e) {
+ return message.error(`提示:
文件下载链接请求失败`);
+ }
+ },
+
+ async fetchAllPages(file) {
+ //分页获取文件夹内文件数据
+ let files=[];//文件数据列表
+ let pageCount=Math.ceil(file.include_items/50);//总页数
+ for (let pageNum=1;pageNum<=pageCount;pageNum++) {
+ //随机停顿防反爬
+ this.cnt++;
+ if (this.cnt >= 50+Math.random()*10) {
+ doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${this.fileCount} 个文件~
休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ this.cnt = 0;
+ }
+ //发送请求
+ let param={"page":pageNum};
+ let res=await this.getFilesByOnce(file,param);
+ //请求失败
+ if (res.code === 31001) {//TODO 可能是这样,没测试,可能要等很久账号掉了,我没时间等
+ return message.error('提示:
请先登录网盘~
代码:' + res.code);
+ }
+ if (res.code !== 0) {
+ return message.error('提示:
获取链接失败了~
代码:' + res.code);
+ }
+ //请求成功
+ files=files.concat(res.data.list)
+ }
+ return files;
+ },
+
+ async fetchFiles(file,pNode) {
+ //获取文件目录结构(递归)
+ //节点
+ let fileNode={
+ name:file.file_name,
+ path:pNode.name === 'root' ? `` : `${pNode.path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ children:[]
+ }
+ pNode.children.push(fileNode)
+ file.path=fileNode.path;
+
+ //判断是否文件夹
+ if (!file?.dir) {
+ this.fileCount++;
+ doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${this.fileCount} 个文件~
`);
+ return file;
+ }
+
+ //文件夹内文件遍历
+ let files=[];
+ for (let f of await this.fetchAllPages(file)) {
+ files= files.concat(await this.fetchFiles(f,fileNode));
+ }
+ return files;
+ },
+
async getLink() {
Swal.fire({
showConfirmButton: false,
@@ -6655,46 +7490,53 @@
if (selectList.length === 0) {
return message.error('提示:
请勾选要下载的文件哦~');
}
- if (this.isOnlyFolder()) {
- return message.error('提示:
请打开文件夹后再勾选文件~');
- }
- if (page === 'home') {
- let data = [];
- let batchSize = 15;
- let processed = 0;
- selectList = selectList.filter(item => item.file === true)
-
- for (let i = 0; i < selectList.length; i += batchSize) {
- // 获取当前批次文件
- let batch = selectList.slice(i, i + batchSize);
- console.log()
- let fids = batch.map(item => item.fid);
-
- // 发起请求获取链接
- let res = await base.post(config.$quark.api.getLink, { "fids": fids }, { "content-type": "application/json;charset=utf-8", "user-agent": config.$quark.api.ua.downloadLink });
-
- if (res?.code === 31001) {
- return message.error('提示:
请先登录网盘~
代码:' + res.code);
- }
- if (res?.code !== 0) {
- return message.error('提示:
获取链接失败了~
代码:' + res.code);
- }
- // 合并响应数据
- if (res?.data) {
- data.push(...res.data);
- }
+ if(page=="home"){
+ }else if(page=="share"){
+ //分享页面所需的变量
+ }else{
+ return message.error('提示:
页面错误~');
+ }
+
+ this.cnt=0; //计数器,用于控制随机延迟
+ this.fileCount=0;//文件计数
+ let fileList=[];//文件列表,只有文件没有文件夹
+ let fileTree = { name: "root", path: ``, children: [] }; // 文件目录树
- // 更新处理进度
- processed += batch.length;
+ if (page === 'home') {
+ //获取文件目录结构(递归)
+ for (let file of selectList) {
+ //遍历选中文件
+ //统一变量名
+ fileList = fileList.concat(await this.fetchFiles(file,fileTree));
+ }
- // 更新UI显示
- doc.find('.loading-popup .loading-title').html(`链接获取中`);
- doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${processed} / ${selectList.length} 个链接~
`);
+ //文件夹为空
+ if (!fileList.length) {
+ return message.error('提示:
文件夹是空的哦~');
+ }
- // 请求间隔节流
- await base.sleep(1000);
+ //获取下载链接
+ //TODO 我认为连续访问网盘的接口不如直接拿全部ID合适,post协议本身不作数据长度上限,即使后台限制为1M,也有65536个文件ID了,你如果觉得不合适可以修改
+ let fids = fileList.map(item => item.fid);
+ let params={"fids":fids};
+ let res = await this.getFileUrlByOnce(undefined,params);
+ if (res.code === 31001) {
+ return message.error('提示:
请先登录网盘~
代码:' + res.code);
}
+ if (res.code !== 0) {
+ return message.error('提示:
获取链接失败了~
代码:' + res.code);
+ }
+ if (res.data.length!=fids.length)
+ return message.error('提示:
获取下载链接数目不对,请重新尝试,若文件数目太多,如好几万个文件,请联系作者修改
');
+
+ //显示下载GUI
+ let data = res.data.map((element, index) => {
+ return {
+ ...element,
+ path: fileList[index].path//TODO 请求的ID和返回的ID的列表顺序是一一对应的,如果有问题请告诉我或自行修改
+ };
+ });
let html = this.generateDom(data);
base.showMainDialog(config.base.dom.button[mode].title, html, config.base.dom.button[mode].footer);
} else {
@@ -6714,6 +7556,7 @@
let fid = v.fid;
let size = base.sizeFormat(v.size);
let dlink = v.download_url;
+ let dpath=v.path;
if (!dlink || !dlink.includes("http")) {
content += `
${filename}
@@ -6749,9 +7592,19 @@
}
if (mode === 'rpc') {
content += `
-
${filename}
-
将 ${filename} 推送到 RPC 下载器
-
`;
+
${filename}
+
+
+
+
+
+
+ 将 ${filename} 推送到 RPC 下载器
+
+
`;
}
if (mode === 'curl') {
let alink = base.convertLinkToCurl(dlink, filename, `-b "${document.cookie}"`);
@@ -6853,8 +7706,12 @@
* UC网盘
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
*/
let $uc = {
+ cnt:0,//计数器,用于控制随机延迟
+ fileCount:0,//文件计数
+
addPageListener() {
/*
防止代码因其他原因被执行多次
@@ -7033,7 +7890,7 @@
target.find('.pl-loading').remove();
target.prepend(base.createLoading());
- let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename, [`Cookie: ${document.cookie}`]);
+ let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename,e.currentTarget.dataset.path, [`Cookie: ${document.cookie}`]);
if (res === 'success') {
$('.listener-rpc-task').show();
target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
@@ -7128,6 +7985,110 @@
})
},
+ async getFilesByOnce(item,params){
+ try {
+ let res;
+ if(page=="home"){
+ let url=`${config.$uc.api.getFiles.home}?pr=UCBrowser&fr=pc&pdir_fid=${params.fid}&_page=${params.pageNum}&_size=50&_fetch_total=1&_fetch_sub_dirs=0&_sort=file_type:asc,updated_at:desc`;
+ res = await base.get(url, {
+ "content-type": "application/json;charset=utf-8",
+ // "user-agent": config.$quark.api.ua.downloadLink //TODO 怎么是夸克的?
+ "user-agent": config.$uc.api.ua.downloadLink
+ });
+ }else if(page=="share"){
+
+ }else{
+ return message.error(`提示:
网站页面错误`);
+ }
+ return res;
+ } catch (e) {
+ return message.error(`提示:
文件获取请求失败`);
+ }
+ },
+
+ async getFileUrlByOnce(item, index, token) {
+ try {
+ if (item.downloadUrl) return {
+ index,
+ downloadUrl: item.downloadUrl
+ };
+ let res = await base.get(config.$xunlei.api.getLink.home + item.id, {
+ 'Authorization': `${token.credentials.token_type} ${token.credentials.access_token}`,
+ 'content-type': "application/json",
+ 'x-captcha-token': token.captcha.token,
+ 'x-device-id': token.deviceid,
+ });
+ if (res.web_content_link) {
+ return {
+ index,
+ downloadUrl: res.web_content_link
+ };
+ } else {
+ return {
+ index,
+ downloadUrl: '获取下载地址失败,刷新后再试试吧~'
+ };
+ }
+ } catch (e) {
+ return message.error('提示:
请先登录网盘后再刷新页面呢~');
+ }
+ },
+
+ async fetchAllPages(file) {
+ //分页获取文件夹内文件数据
+ let res;
+ let files=[];//文件数据列表
+ let pageCount=Math.ceil(file.include_items/50);//总页数
+ for (let pageNum=1;pageNum<=pageCount;pageNum++) {
+ //随机停顿防反爬
+ this.cnt++;
+ if (this.cnt >= 50+Math.random()*10) {
+ doc.find('.loading-popup .swal2-html-container').html(`
正遍历到的大型文件夹已获取 ${files.length} 个文件~
休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ this.cnt = 0;
+ }
+
+ //发送请求
+ let param={"fid":file.fid,"pageNum":pageNum};
+ res=await this.getFilesByOnce(file,param);
+
+ //请求失败
+ if(res?.code){//注意变量名
+ return message.error(`提示:
请求失败,失败码: ${res?.code} 失败信息:${res.message}`);
+ }
+
+ //请求成功
+ files=files.concat(res.data.list)//注意变量名
+ }
+ return files;
+ },
+
+ async fetchFiles(file,pNode) {
+ //获取文件目录结构(递归)
+ //节点
+ let fileNode={
+ name:file.file_name,//注意变量名
+ path:pNode.name === 'root' ? `` : `${pNode.path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ children:[]
+ }
+ pNode.children.push(fileNode);
+ file.path=fileNode.path;
+
+ //判断是否文件夹
+ if (!file?.dir) {//注意变量名
+ this.fileCount++;
+ doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${this.fileCount} 个文件~
`);
+ return file;
+ }
+
+ //文件夹内文件遍历
+ let files=[];
+ for (let f of await this.fetchAllPages(file)) {
+ files= files.concat(await this.fetchFiles(f,fileNode));
+ }
+ return files;
+ },
+
async getLink() {
Swal.fire({
showConfirmButton: false,
@@ -7154,46 +8115,49 @@
if (selectList.length === 0) {
return message.error('提示:
请勾选要下载的文件哦~');
}
- if (this.isOnlyFolder()) {
- return message.error('提示:
请打开文件夹后再勾选文件~');
- }
- if (page === 'home') {
- let data = [];
- let batchSize = 15;
- let processed = 0;
- selectList = selectList.filter(item => item.file === true)
-
- for (let i = 0; i < selectList.length; i += batchSize) {
- // 获取当前批次文件
- let batch = selectList.slice(i, i + batchSize);
- console.log()
- let fids = batch.map(item => item.fid);
-
- // 发起请求获取链接
- let res = await base.post(config.$uc.api.getLink, { "fids": fids }, { "content-type": "application/json;charset=utf-8", "user-agent": config.$quark.api.ua.downloadLink });
-
- if (res?.code === 31001) {
- return message.error('提示:
请先登录网盘~
代码:' + res.code);
- }
- if (res?.code !== 0) {
- return message.error('提示:
获取链接失败了~
代码:' + res.code);
- }
-
- // 合并响应数据
- if (res?.data) {
- data.push(...res.data);
- }
-
- // 更新处理进度
- processed += batch.length;
- // 更新UI显示
- doc.find('.loading-popup .loading-title').html(`链接获取中`);
- doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${processed} / ${selectList.length} 个链接~
`);
+ if(page=="home"){
+ }else if(page=="share"){
+ //分享页面所需的变量
+ }else{
+ return message.error('提示:
页面错误~');
+ }
- // 请求间隔节流
- await base.sleep(1000);
+ this.cnt=0;
+ this.fileCount=0;//文件计数
+ let fileList=[];//文件列表,只有文件没有文件夹
+ let fileTree = { name: "root", path: ``, children: [] }; // 文件目录树
+ if (page === 'home') {
+ //获取文件目录结构(递归)
+ for (let file of selectList) {
+ //遍历选中文件
+ //统一变量名
+ fileList = fileList.concat(await this.fetchFiles(file,fileTree));
+ }
+
+ //文件夹为空
+ if (!fileList.length) {
+ return message.error('提示:
文件夹是空的哦~');
}
+
+ //获取下载链接
+ //TODO 我认为连续访问网盘的接口不如直接拿全部ID合适,post协议本身不作数据长度上限,即使后台限制为1M,也有65536个文件ID了,你如果觉得不合适可以修改
+ let fids = fileList.map(item => item.fid);
+ // 发起请求获取链接
+ let res = await base.post(config.$uc.api.getLink.home, { "fids": fids }, { "content-type": "application/json;charset=utf-8", "user-agent": config.$uc.api.ua.downloadLink });
+ if (res.code !== 0) {
+ return message.error(`提示:
请求失败,失败码: ${res?.code} 失败信息:${res.message}`);
+ }
+ if (res.data.length!=fids.length)
+ return message.error('提示:
获取下载链接数目不对,请重新尝试,若文件数目太多,如好几万个文件,请联系作者修改
');
+
+ //显示下载GUI
+ let data = res.data.map((element, index) => {
+ return {
+ ...element,
+ path: fileList[index].path//TODO 请求的ID和返回的ID的列表顺序是一一对应的,如果有问题请告诉我或自行修改
+ };
+ });
let html = this.generateDom(data);
base.showMainDialog(config.base.dom.button[mode].title, html, config.base.dom.button[mode].footer);
} else {
@@ -7213,6 +8177,7 @@
let fid = v.fid;
let size = base.sizeFormat(v.size);
let dlink = v.download_url;
+ let dpath=v.path;
if (!dlink || !dlink.includes("http")) {
content += `
${filename}
@@ -7248,9 +8213,19 @@
}
if (mode === 'rpc') {
content += `
-
${filename}
-
将 ${filename} 推送到 RPC 下载器
-
`;
+
${filename}
+
+
+
+
+
+
+ 将 ${filename} 推送到 RPC 下载器
+
+
`;
}
if (mode === 'curl') {
let alink = base.convertLinkToCurl(dlink, filename, `-b "${document.cookie}"`);
@@ -7352,8 +8327,14 @@
* 123云盘
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
*/
let $123pan = {
+ cnt:0,//计数器,用于控制随机延迟
+ fileCount:0,//文件计数
+ token:{},
+ ShareKey:"",
+
addPageListener() {
/*
防止代码因其他原因被执行多次
@@ -7520,7 +8501,7 @@
target.find('.pl-loading').remove();
target.prepend(base.createLoading());
- let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename);
+ let res = await base.sendLinkToRPC(e.currentTarget.dataset.link, e.currentTarget.dataset.filename,e.currentTarget.dataset.path);
if (res === 'success') {
$('.listener-rpc-task').show();
target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
@@ -7609,6 +8590,171 @@
let token = base.getStorage("authorToken");
return token;
},
+
+ getRandomNum(len) {
+ len = len || 16;
+ let $chars = '0123456789';
+ let maxPos = $chars.length;
+ let pwd = '';
+ for (let i = 0; i < len; i++) {
+ pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
+ }
+ return pwd;
+ },
+
+ async getFilesByOnce(item,params){
+ try {
+ let res;
+ params.driveId=0;//TODO 看起来是个变量,但我定值是0,也没细看这变量怎么产生的,以后出问题再看。
+ params.operateType=8;//文件夹初次打开拿第1页数据时是4,鼠标下滑增加数据是8
+ params.next=0;//如何是100以内不用拉数据的是0,超过100的是-1,都填0都适配
+ let time = Date.now();
+ if(page=="home"){
+ //TODO 这URL中间有XXX=时间戳-XXX-XXX的格式,我发觉那放3个随机数竟然也行,如果不合适你就找下。
+ let url=`${config.$123pan.api.getFiles.home}?${this.getRandomNum()}=${time}-${this.getRandomNum()}-${this.getRandomNum()}&driveId=${params.driveId}&limit=100&next=${params.next}&orderBy=update_time&orderDirection=desc&parentFileId=${params.FileId}&trashed=false&SearchData=&Page=${params.pageNum}&OnlyLookAbnormalFile=0&event=homeListFile&operateType=${params.operateType}&inDirectSpace=false`;
+ res = await base.get(url, {
+ "content-type": "application/json;charset=utf-8",
+ "authorization": `Bearer ${this.token}`,
+ "platform": "web"//TODO ios?打错?不合适就换回来
+ });
+ }else if(page=="share"){
+ //TODO 这URL中间有XXX=时间戳-XXX-XXX的格式,我发觉那放3个随机数竟然也行,如果不合适你就找下。
+ let url=`${config.$123pan.api.getFiles.share}?${this.getRandomNum()}=${time}-${this.getRandomNum()}-${this.getRandomNum()}&limit=100&next=${params.next}&orderBy=file_name&orderDirection=asc&shareKey=${this.ShareKey}&ParentFileId=${params.FileId}&Page=${params.pageNum}&event=homeListFile&operateType=${params.operateType}`;
+ res = await base.get(url, {
+ "content-type": "application/json;charset=utf-8",
+ "authorization": `Bearer ${this.token}`,
+ "platform": "web"//TODO ios?打错?不合适就换回来
+ });
+ }else{
+ return message.error(`提示:
网站页面错误`);
+ }
+ return res;
+ } catch (e) {
+ return message.error(`提示:
文件获取请求失败`);
+ }
+ },
+
+ async getFileUrlByOnce(item, index) {
+ try {
+ if (item.DownloadUrl) return {
+ index,
+ downloadUrl: item.DownloadUrl
+ };
+ let res = null;
+ if (this.ShareKey) {
+ res = await base.post(config.$123pan.api.getLink.share, {
+ "ShareKey": this.ShareKey,
+ "FileID": item.FileId,
+ "S3keyFlag": item.S3KeyFlag,
+ "Size": item.Size,
+ "Etag": item.Etag
+ }, {
+ "content-type": "application/json;charset=utf-8",
+ "authorization": `Bearer ${this.token}`,
+ "platform": "ios"//为啥IOS不是WEB?IOS更好点?
+ });
+ } else {
+ res = await base.post(config.$123pan.api.getLink.home, {
+ "driveId": 0,
+ "etag": item.Etag,
+ "fileId": item.FileId,
+ "s3keyFlag": item.S3KeyFlag,
+ "type": item.Type,
+ "fileName": item.FileName,
+ "size": item.Size
+ }, {
+ "content-type": "application/json;charset=utf-8",
+ "authorization": `Bearer ${this.token}`,
+ "platform": "web"//TODO ios?打错?不合适就换回来
+ });
+ }
+ if (res.data?.DownloadUrl) {
+ let url = res.data.DownloadUrl;
+ let surl = new URL(url).searchParams.get("params");
+ if (surl) url = base.decodeBase(surl);
+ url = await base.getFinalUrl(url);
+ return {
+ index,
+ downloadUrl: url
+ };
+ } else if (res.data?.DownloadURL) {
+ let url = res.data.DownloadURL;
+ let surl = new URL(url).searchParams.get("params");
+ if (surl) url = base.decodeBase(surl);
+ url = await base.getFinalUrl(url);
+ return {
+ index,
+ downloadUrl: url
+ };
+ } else if (res?.code === 5112) {
+ return message.error('提示:
请先登录网盘后再获取链接呢~');
+ } else {
+ return {
+ index,
+ downloadUrl: '获取下载地址失败,刷新后再试试吧~'
+ };
+ }
+ } catch (e) {
+ return {
+ index,
+ downloadUrl: '获取下载地址失败,刷新后再试试吧~'
+ };
+ }
+ },
+
+ async fetchAllPages(file) {
+ //分页获取文件夹内文件数据
+ let res;
+ let files=[];//文件数据列表
+ let pageCount=1;//总页数,先设1,之后根据res返回的值修改//share没有file.fileCount,兼容适配
+ for (let pageNum=1;pageNum<=pageCount;pageNum++) {
+ //随机停顿防反爬
+ this.cnt++;
+ if (this.cnt >= 50+Math.random()*10) {
+ doc.find('#loadingText').html(`
文件获取中
已获取 ${this.fileCount} 个文件,请耐心等待哦~
>休息 ${globalSleep} 毫秒...
`);
+ await base.sleep(globalSleep+Math.random()*globalSleepRandSeed);
+ this.cnt = 0;
+ }
+ //发送请求
+ let param={"pageNum":pageNum,"FileId":file.FileId};
+ res=await this.getFilesByOnce(file,param);
+
+ //请求失败
+ if(!(res?.code==0&&res?.message=="ok")){
+ return message.error(`提示:
请求失败,失败码: ${res?.res_code} 失败信息:${res.res_message}`);
+ }
+ //请求成功
+ if(pageCount==1)pageCount=Math.ceil(res.data.Total/100);
+ files=files.concat(res.data.InfoList);//注意变量名
+ }
+ return files;
+ },
+
+ async fetchFiles(file,pNode) {
+ //获取文件目录结构(递归)
+ //节点
+ let fileNode={
+ name:file.FileName,//注意变量名
+ path:pNode.name === 'root' ? `` : `${pNode.path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ children:[]
+ }
+ pNode.children.push(fileNode);
+ file.path=fileNode.path;
+
+ //判断是否文件夹
+ if (file.Type === 0) {//注意变量名
+ this.fileCount++;
+ doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${this.fileCount} 个文件~
`);
+ return file;
+ }
+
+ //文件夹内文件遍历
+ let files=[];
+ for (let f of await this.fetchAllPages(file)) {
+ files= files.concat(await this.fetchFiles(f,fileNode));
+ }
+ return files;
+ },
async getLink() {
Swal.fire({
@@ -7636,137 +8782,106 @@
if (selectList.length === 0) {
return message.error('提示:
请勾选要下载的文件哦~');
}
- if (this.isOnlyFolder()) {
- return message.error('提示:
请打开文件夹后再勾选文件~');
- }
- console.log(selectList);
- if (page === 'home') {
- let token = this.getToken();
- let batchSize = 15;
- let processed = 0;
- selectList = selectList.filter(item => item.Type === 0);
- for (let i = 0; i < selectList.length; i += batchSize) {
- let batch = selectList.slice(i, i + batchSize);
- let queue = [];
- doc.find('.loading-popup .loading-title').html(`链接获取中`);
- doc.find('.loading-popup .swal2-html-container').html(`
正在获取文件对应的下载链接~
`);
- batch.forEach((item, localIndex) => {
- let globalIndex = i + localIndex;
- queue.push(this.getFileUrlByOnce(item, globalIndex, token)
- .then(val => {
- processed++;
- doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${processed} / ${selectList.length} 个链接~
`);
- return val;
- }));
- });
-
- let res = await Promise.all(queue);
- res.forEach(val => {
- selectList[val.index].DownloadUrl = val.downloadUrl;
- });
-
- await base.sleep(1000);
- }
- let html = this.generateDom(selectList);
- base.showMainDialog(config.base.dom.button[mode].title, html, config.base.dom.button[mode].footer);
- } else if (page === 'share') {
- let token = this.getToken();
- let batchSize = 15;
- let processed = 0;
- selectList = selectList.filter(item => item.Type === 0);
+ if(page=="home"){
+ }else if(page=="share"){
+ //分享页面所需的变量
let pathSplit = location.pathname.split('/').filter(Boolean);
- let ShareKey = pathSplit[1];
- console.log(selectList)
- for (let i = 0; i < selectList.length; i += batchSize) {
- let batch = selectList.slice(i, i + batchSize);
- let queue = [];
+ this.ShareKey = pathSplit[1];
+ }else{
+ return message.error('提示:
页面错误~');
+ }
+ this.token = this.getToken();
+
+ this.cnt=0;
+ this.fileCount=0;//文件计数
+ let fileList=[];//文件列表,只有文件没有文件夹
+ let fileTree = { name: "root", path: ``, children: [] }; // 文件目录树
+ // if (page === 'home') {
+ //获取文件目录结构(递归)
+ for (let file of selectList) {
+ //遍历选中文件
+ //统一变量名
+ fileList = fileList.concat(await this.fetchFiles(file,fileTree));
+ }
+
+ //文件夹为空
+ if (!fileList.length) {
+ return message.error('提示:
文件夹是空的哦~');
+ }
+
+ //获取下载链接
+ doc.find('.loading-popup .loading-title').html(`链接获取中`);
+ doc.find('.loading-popup .swal2-html-container').html(`
正在获取文件对应的下载链接~
`);
+ let batchSize = globalBatchsize+Math.ceil(Math.random()*5);
+ let i=0;
+ while (i < fileList.length){
+ // 分批获取链接
+ let batch = fileList.slice(i, i + batchSize);
- doc.find('.loading-popup .loading-title').html(`链接获取中`);
- doc.find('.loading-popup .swal2-html-container').html(`
正在获取文件对应的下载链接~
`);
+ // 生成请求队列
+ let queue = [];
batch.forEach((item, localIndex) => {
let globalIndex = i + localIndex;
- queue.push(this.getFileUrlByOnce(item, globalIndex, token, ShareKey)
+ queue.push(this.getFileUrlByOnce(item, globalIndex)
.then(val => {
- processed++;
- doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${processed} / ${selectList.length} 个链接~
`);
+ // processed++;
+ // doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${processed} / ${selectList.length} 个链接~
`);
return val;
}));
});
+ // 等待本批次的请求结果
let res = await Promise.all(queue);
res.forEach(val => {
- selectList[val.index].DownloadUrl = val.downloadUrl;
+ fileList[val.index].DownloadUrl = val.downloadUrl;
});
- await base.sleep(1000);
+ // 每次处理完一个批次后,等待
+ if (i + batchSize < fileList.length){
+ doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${i+batch.length} / ${fileList.length} 个链接,请耐心等待哦~
休息 ${globalSleep} 毫秒...
`);
+ await base.customSleep();
+ };
+
+ //累加批次
+ i += batchSize;
+ batchSize = globalBatchsize+Math.ceil(Math.random()*5)
}
- let html = this.generateDom(selectList);
+ let html = this.generateDom(fileList);
base.showMainDialog(config.base.dom.button[mode].title, html, config.base.dom.button[mode].footer);
- } else {
- return message.error('提示:
页面错误~');
- }
- },
-
- async getFileUrlByOnce(item, index, token, ShareKey) {
- if (item.DownloadUrl) return {
- index,
- downloadUrl: item.DownloadUrl
- };
- let res = null;
- if (ShareKey) {
- res = await base.post(config.$123pan.api.getShareLink, {
- "ShareKey": ShareKey,
- "FileID": item.FileId,
- "S3keyFlag": item.S3KeyFlag,
- "Size": item.Size,
- "Etag": item.Etag
- }, {
- "content-type": "application/json;charset=utf-8",
- "authorization": `Bearer ${token}`,
- "platform": "ios"
- });
- } else {
- res = await base.post(config.$123pan.api.getLink, {
- "driveId": 0,
- "etag": item.Etag,
- "fileId": item.FileId,
- "s3keyFlag": item.S3KeyFlag,
- "type": item.Type,
- "fileName": item.FileName,
- "size": item.Size
- }, {
- "content-type": "application/json;charset=utf-8",
- "authorization": `Bearer ${token}`,
- "platform": "ios"
- });
- }
- if (res.data?.DownloadUrl) {
- let url = res.data.DownloadUrl;
- let surl = new URL(url).searchParams.get("params");
- if (surl) url = base.decodeBase(surl);
- url = await base.getFinalUrl(url);
- return {
- index,
- downloadUrl: url
- };
- } else if (res.data?.DownloadURL) {
- let url = res.data.DownloadURL;
- let surl = new URL(url).searchParams.get("params");
- if (surl) url = base.decodeBase(surl);
- url = await base.getFinalUrl(url);
- return {
- index,
- downloadUrl: url
- };
- } else if (res?.code === 5112) {
- return message.error('提示:
请先登录网盘后再获取链接呢~');
- } else {
- return {
- index,
- downloadUrl: '获取下载地址失败,刷新后再试试吧~'
- };
- }
+ // } else if (page === 'share') {
+ // let batchSize = 15;
+ // let processed = 0;
+ // selectList = selectList.filter(item => item.Type === 0);
+ // console.log(selectList)
+ // for (let i = 0; i < selectList.length; i += batchSize) {
+ // let batch = selectList.slice(i, i + batchSize);
+ // let queue = [];
+
+ // doc.find('.loading-popup .loading-title').html(`链接获取中`);
+ // doc.find('.loading-popup .swal2-html-container').html(`
正在获取文件对应的下载链接~
`);
+ // batch.forEach((item, localIndex) => {
+ // let globalIndex = i + localIndex;
+ // queue.push(this.getFileUrlByOnce(item, globalIndex)
+ // .then(val => {
+ // processed++;
+ // doc.find('.loading-popup .swal2-html-container').html(`
已获取 ${processed} / ${selectList.length} 个链接~
`);
+ // return val;
+ // }));
+ // });
+
+ // let res = await Promise.all(queue);
+ // res.forEach(val => {
+ // selectList[val.index].DownloadUrl = val.downloadUrl;
+ // });
+
+ // await base.sleep(1000);
+ // }
+ // let html = this.generateDom(selectList);
+ // base.showMainDialog(config.base.dom.button[mode].title, html, config.base.dom.button[mode].footer);
+ // } else {
+ // return message.error('提示:
页面错误~');
+ // }
},
generateDom(list) {
@@ -7781,6 +8896,7 @@
let fileid = v.FileId;
let size = base.sizeFormat(v.Size);
let dlink = v.DownloadUrl || v.DownloadURL;
+ let dpath=v.path;
if (!dlink || !dlink.includes("http")) {
content += `
${filename}
@@ -7816,9 +8932,19 @@
}
if (mode === 'rpc') {
content += `
-
${filename}
-
将 ${filename} 推送到 RPC 下载器
-
`;
+
${filename}
+
+
+
+
+
+
+ 将 ${filename} 推送到 RPC 下载器
+
+
`;
}
if (mode === 'curl') {
let alink = base.convertLinkToCurl(dlink, filename);
From 489dbf6f2a00c931f14f6b7a3b6c1a148406fa46 Mon Sep 17 00:00:00 2001
From: KanouAo <214709230@qq.com>
Date: Tue, 20 May 2025 23:47:22 +0800
Subject: [PATCH 2/5] 5.20
---
...\350\275\275\345\212\251\346\211\213.user.js" | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git "a/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js" "b/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js"
index e14a8ca..4cfd11f 100644
--- "a/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js"
+++ "b/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js"
@@ -3670,8 +3670,8 @@
let res;
if(page=="home"||page=="main"){
//我找的链接获取文件,1页100个,这个能获取文件夹所有文件我就直接用了
- //TODO path属性被占用,原变量就请求下载时用一次,就 path 改成 _path
- let url = `${config.$baidu.api.getFiles.home}&dir=${encodeURIComponent(file._path)}&access_token=${this.accessToken}`;
+ //TODO path属性被占用,原来设想的从选中文件夹开始的路径改成_path
+ let url = `${config.$baidu.api.getFiles.home}&dir=${encodeURIComponent(file.path)}&access_token=${this.accessToken}`;
res = await base.get(url, { "User-Agent": config.$baidu.api.ua.downloadLink});
}else if(page=="share"){
}else{
@@ -3713,8 +3713,7 @@
}
//发送请求
- let params={"_path":file._path};
- res=await this.getFilesByOnce(file,params);
+ res=await this.getFilesByOnce(file,undefined);
//请求失败
if(res?.errno){
@@ -3730,12 +3729,11 @@
//节点
let fileNode={
name:file.server_filename,//注意变量名
- path:pNode.name === 'root' ? `` : `${pNode.path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ _path:pNode.name === 'root' ? `` : `${pNode._path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
children:[]
}
pNode.children.push(fileNode);
- file._path=file.path;//TODO path属性被占用,原变量就请求下载时有用就 path 改成 _path
- file.path=fileNode.path;
+ file._path=fileNode._path;//TODO path属性被占用,改成 _path
//判断是否文件夹
if (!file?.isdir) {//注意变量名
@@ -3977,7 +3975,7 @@
if (linkList.length) {
for (let i = 0; i < linkList.length; i++) {//重写下载路径
- linkList[i].path = filesDict[linkList[i].fs_id].path;
+ linkList[i]._path = filesDict[linkList[i].fs_id]._path;
}
base.showMainDialog(config.base.dom.button[mode].title, this.generateDom(linkList), config.base.dom.button[mode].footer);
} else {
@@ -3999,7 +3997,7 @@
if (v.isdir === 1) return;
let filename = v.server_filename || v.filename;
let size = base.sizeFormat(v.size);
- let dpath=v.path;
+ let dpath=v._path;//属性被占用
if (!v?.dlink || !v?.dlink.includes("http")) {
content += `
${filename}
From 49cfc01c8b8debe13c4d96fc25497c6e925d6d52 Mon Sep 17 00:00:00 2001
From: KanouAo <214709230@qq.com>
Date: Wed, 21 May 2025 02:33:00 +0800
Subject: [PATCH 3/5] =?UTF-8?q?5.20=EF=BC=8CAria=E3=80=81RPC=E4=B8=8B?=
=?UTF-8?q?=E8=BD=BD=E8=B7=AF=E5=BE=84=E8=A7=A3=E5=86=B3=EF=BC=8Ccurl?=
=?UTF-8?q?=E6=94=AF=E6=8C=81win11=E3=80=81armbian(linux)=E5=B9=B3?=
=?UTF-8?q?=E5=8F=B0=E6=B2=A1=E6=B5=8B=E8=AF=95=E8=8B=B9=E6=9E=9C=E7=94=B5?=
=?UTF-8?q?=E8=84=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...200\205hmjz100\347\232\204\350\257\235.md" | 24 +++-
...0\275\275\345\212\251\346\211\213.user.js" | 133 +++++++++---------
2 files changed, 92 insertions(+), 65 deletions(-)
diff --git "a/\347\273\231\345\274\200\345\217\221\350\200\205hmjz100\347\232\204\350\257\235.md" "b/\347\273\231\345\274\200\345\217\221\350\200\205hmjz100\347\232\204\350\257\235.md"
index a09ecdb..11cfcd0 100644
--- "a/\347\273\231\345\274\200\345\217\221\350\200\205hmjz100\347\232\204\350\257\235.md"
+++ "b/\347\273\231\345\274\200\345\217\221\350\200\205hmjz100\347\232\204\350\257\235.md"
@@ -1,7 +1,29 @@
我增加了下载文件夹功能,一键下载文件夹下所有的文件(多个)文件夹嵌套文件夹的这种目录组织都能下载下来,测试环境 win11、edge 浏览器、RPC 发 Aira2
+这些下载器我基本都不认识,我只能简单测试下,可能要你去仔细试试,路径我都在网页元素那写好了,"dpath"元素就是。
+
+API:
+Blob 流我不会,老实说,我不会修改下载路径,如果的确没法改,请告诉用户。
+
+Aria:
+测试环境:是 win11 的 Aira2c 的控制台命令行。
+修改了下载路径。(话说这个有必要吗?不也是 RPC 发到 Aria2?)。
+
+RPC:
+测试环境:我发到 win11 和轻 nas armbian 上的 Aira2 的都可以
+修改了下载路径。
+
+CURL:
+测试环境:win11、armbian(linux)
+win11 用 curl 命令,如果目录不存在会失败,所以加了创建目录的,但在命令行里测的,不知其它平台和下载器是否适用,如果不行就删掉吧。
+AI 说 为了使命令在 Linux/macOS 上也能工作,可以将其修改为:mkdir -p "下载测试 2" >/dev/null && curl ……
+我在 armbian(linux)上测试了上面这条成功,但我没苹果电脑,只有苹果手机,就没测试。
+
+BC:
+测试环境:win11
+老实说,我不会修改下载路径,如果的确没法改,请告诉用户。
我只动了(改)网盘直链下载助手.user,其它我都没改
-我虽然会写代码,但油猴我第 1 次做,爬网站数据是第 2 次,上次还是咸鱼捡二手的提醒,
+我虽然会写代码,但方向不是这方面的,油猴我第 1 次做,爬网站数据是第 2 次,上次还是咸鱼捡二手的提醒,
我虽然会 JS 但并不是主 JS 的,对 js 同步异步这边不是很熟悉,你可以看情况修改
标注 TODO 的都是要注意一下的。
diff --git "a/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js" "b/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js"
index 4cfd11f..f89b864 100644
--- "a/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js"
+++ "b/\357\274\210\346\224\271\357\274\211\347\275\221\347\233\230\347\233\264\351\223\276\344\270\213\350\275\275\345\212\251\346\211\213.user.js"
@@ -431,15 +431,17 @@
* 生成 Aria2 下载命令
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
* @description 将链接转换为 Aria2 格式命令,自动处理文件名特殊字符
* @param {string} link - 下载链接
* @param {string} filename - 文件名
+ * @param {string} path - 下载路径
* @param {string} [header] - 自定义请求头参数(可选)
* @returns {string} 编码后的 aria2c 命令字符串
*/
- convertLinkToAria(link, filename, header) {
+ convertLinkToAria(link, filename, path, header) {
filename = base.fixFilename(filename);
- return encodeURIComponent(`aria2c "${link}" --out "${filename}"${header ? (" " + header) : ""}`);
+ return encodeURIComponent(`aria2c "${link}" --out "${path}/${filename}"${header ? (" " + header) : ""}`);
},
/**
@@ -461,16 +463,19 @@
* 生成 cURL 下载命令
* @author 油小猴
* @author hmjz100
+ * @author KanouAo
* @description 根据终端类型生成对应 curl 命令,支持断点续传,自动处理文件名特殊字符
* @param {string} link - 下载链接
* @param {string} filename - 文件名
+ * @param {string} path - 下载路径
* @param {string} [header] - 自定义请求头参数(可选)
* @returns {string} 编码后的 curl 命令字符串
*/
- convertLinkToCurl(link, filename, header) {
+ convertLinkToCurl(link, filename,path, header) {
let terminal = base.getValue('setting_terminal_type');
filename = base.fixFilename(filename);
- return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"${header ? (" " + header) : ""}`);
+ //TODO win11用curl命令,如果目录不存在会失败,所以加了创建目录的,但在命令行里测的,不知其它平台和下载器是否适用
+ return encodeURIComponent(`mkdir "${path}" ${(terminal !== 'wp' && terminal !== 'wc') ? '>/dev/null &&' : '2>nul &'} ${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${path}/${filename}"${header ? (" " + header) : ""}`);
},
/**
@@ -3729,7 +3734,7 @@
//节点
let fileNode={
name:file.server_filename,//注意变量名
- _path:pNode.name === 'root' ? `` : `${pNode._path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ _path:pNode.name === 'root' ? `` : (pNode._path === '' ? pNode.name : `${pNode._path}/${pNode.name}`),//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
children:[]
}
pNode.children.push(fileNode);
@@ -4008,7 +4013,7 @@
if (mode === 'api') {
alinkAllText += dlink + '\r\n';
content += `
-
${filename}
+
${filename}
增强下载(基于浏览器文件流)
直接下载(基于浏览器链接)
复制链接
@@ -4027,23 +4032,23 @@
}
let BDUSS = this.getBDUSS();
if (mode === 'aria') {
- let alink = base.convertLinkToAria(dlink, filename, `--header "User-Agent: ${config.$baidu.api.ua.downloadLink}" --header "Cookie: BDUSS=${BDUSS}"`);
+ let alink = base.convertLinkToAria(dlink, filename, dpath, `--header "User-Agent: ${config.$baidu.api.ua.downloadLink}" --header "Cookie: BDUSS=${BDUSS}"`);
if (typeof (alink) === 'object') {
content += `
`;
} else {
alinkAllText += alink + '\r\n';
content += `
`;
}
}
if (mode === 'rpc') {
content += `
-
${filename}
+
${filename}
`;
}
if (mode === 'curl') {
- let alink = base.convertLinkToCurl(dlink, filename, `-A "${config.$baidu.api.ua.downloadLink}" -b "BDUSS=${BDUSS}"`);
+ let alink = base.convertLinkToCurl(dlink, filename, dpath, `-A "${config.$baidu.api.ua.downloadLink}" -b "BDUSS=${BDUSS}"`);
if (typeof (alink) === 'object') {
content += ``;
} else {
alinkAllText += alink + '\r\n';
content += ``;
}
@@ -4077,13 +4082,13 @@
if (typeof (alink) === 'object') {
alinkAllText += decodeURIComponent(alink.text) + '\r\n';
content += ``;
} else {
alinkAllText += alink + '\r\n';
content += ``;
}
@@ -4701,7 +4706,7 @@
//节点
let fileNode={
name:file.name,//注意变量名
- path:pNode.name === 'root' ? `` : `${pNode.path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ path:pNode.name === 'root' ? `` : (pNode.path === '' ? pNode.name : `${pNode.path}/${pNode.name}`),//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
children:[]
}
pNode.children.push(fileNode);
@@ -4848,7 +4853,7 @@
if (mode === 'api') {
alinkAllText += dlink + '\r\n';
content += `
-
${filename}
+
${filename}
增强下载(基于浏览器文件流)
直接下载(基于浏览器链接)
复制名称
@@ -4867,10 +4872,10 @@
`;
}
if (mode === 'aria') {
- let alink = base.convertLinkToAria(dlink, filename, `--header "Referer: https://${location.host}/"`);
+ let alink = base.convertLinkToAria(dlink, filename, dpath, `--header "Referer: https://${location.host}/"`);
alinkAllText += alink + '\r\n';
content += ``;
}
@@ -4892,10 +4897,10 @@
`;
}
if (mode === 'curl') {
- let alink = base.convertLinkToCurl(dlink, filename, `&refer=${encodeURIComponent(`https://${location.host}/`)}`);
+ let alink = base.convertLinkToCurl(dlink, filename, dpath, `&refer=${encodeURIComponent(`https://${location.host}/`)}`);
alinkAllText += alink + '\r\n';
content += `
`;
}
@@ -4903,7 +4908,7 @@
let alink = base.convertLinkToBC(dlink, filename, `-e "https://${location.host}/"`);
alinkAllText += alink + '\r\n';
content += `
`;
}
@@ -5469,7 +5474,7 @@
//节点
let fileNode={
name:file.name,//注意变量名
- path:pNode.name === 'root' ? `` : `${pNode.path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ path:pNode.name === 'root' ? `` : (pNode.path === '' ? pNode.name : `${pNode.path}/${pNode.name}`),//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
children:[]
}
pNode.children.push(fileNode);
@@ -5603,7 +5608,7 @@
if (mode === 'api') {
alinkAllText += dlink + '\r\n';
content += `
-
${filename}
+
${filename}
增强下载(基于浏览器文件流)
直接下载(基于浏览器链接)
复制链接
@@ -5620,10 +5625,10 @@
`;
}
if (mode === 'aria') {
- let alink = base.convertLinkToAria(dlink, filename);
+ let alink = base.convertLinkToAria(dlink, filename, dpath);
alinkAllText += alink + '\r\n';
content += `
`;
}
@@ -5644,10 +5649,10 @@
`;
}
if (mode === 'curl') {
- let alink = base.convertLinkToCurl(dlink, filename);
+ let alink = base.convertLinkToCurl(dlink, filename, dpath);
alinkAllText += alink + '\r\n';
content += `
`;
}
@@ -5655,7 +5660,7 @@
let alink = base.convertLinkToBC(dlink, filename);
alinkAllText += alink + '\r\n';
content += `
`;
}
@@ -6113,7 +6118,7 @@
//节点 这的节点树因为不怎么需要就没做完整
let fileNode={
name:file.name,//注意变量名
- path:pNode.name === 'root' ? `` : `${pNode.path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ path:pNode.name === 'root' ? `` : (pNode.path === '' ? pNode.name : `${pNode.path}/${pNode.name}`),//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
children:[]
}
pNode.children.push(fileNode);
@@ -6267,7 +6272,7 @@
if (mode === 'api') {
alinkAllText += dlink + '\r\n';
content += `
-
${filename}
+
${filename}
增强下载(基于浏览器文件流)
直接下载(基于浏览器链接)
复制链接
@@ -6284,10 +6289,10 @@
`;
}
if (mode === 'aria') {
- let alink = base.convertLinkToAria(dlink, filename);
+ let alink = base.convertLinkToAria(dlink, filename, dpath);
alinkAllText += alink + '\r\n';
content += `
`;
}
@@ -6308,10 +6313,10 @@
`;
}
if (mode === 'curl') {
- let alink = base.convertLinkToCurl(dlink, filename);
+ let alink = base.convertLinkToCurl(dlink, filename, dpath);
alinkAllText += alink + '\r\n';
content += `
`;
}
@@ -6319,7 +6324,7 @@
let alink = base.convertLinkToBC(dlink, filename);
alinkAllText += alink + '\r\n';
content += `
`;
}
@@ -6785,7 +6790,7 @@
//节点
let fileNode={
name:file.name,//注意变量名
- path:pNode.name === 'root' ? `` : `${pNode.path}/${pNode.name}`,//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
+ path:pNode.name === 'root' ? `` : (pNode.path === '' ? pNode.name : `${pNode.path}/${pNode.name}`),//一般来说,路径不要特别特别长,不然可能会出问题,不过正常是不会的
children:[]
}
pNode.children.push(fileNode);
@@ -6923,7 +6928,7 @@
if (mode === 'api') {
alinkAllText += dlink + '\r\n';
content += `
-
${filename}
+
${filename}
增强下载(基于浏览器文件流)
直接下载(基于浏览器链接)
复制名称
@@ -6941,10 +6946,10 @@
`;
}
if (mode === 'aria') {
- let alink = base.convertLinkToAria(dlink, filename);
+ let alink = base.convertLinkToAria(dlink, filename, dpath);
alinkAllText += alink + '\r\n';
content += `
`;
}
@@ -6965,10 +6970,10 @@
`;
}
if (mode === 'curl') {
- let alink = base.convertLinkToCurl(dlink, filename);
+ let alink = base.convertLinkToCurl(dlink, filename, dpath);
alinkAllText += alink + '\r\n';
content += `