Compare commits

..

6 Commits

Author SHA1 Message Date
Y_C_Z
2bff5239ce
Merge 50d01bb4d8 into 71b4fca6c2 2025-04-26 18:37:34 +08:00
Cp0204
71b4fca6c2 📝 更新文档
Some checks are pending
Docker Publish / build-and-push (push) Waiting to run
2025-04-26 18:08:29 +08:00
Cp0204
b6aca2e2e9 油猴脚本:一键推送助手更新至 0.4
- QAS 地址支持填入 https
- 变更更新链接为 GitHub 地址
- 添加默认正则和替换设置
2025-04-26 17:04:35 +08:00
Cp0204
996210f8c7 🐛 修复正则预览后搜资源 界面未复位 #73
- 同时修复切换资源提示 非法token
2025-04-26 17:04:35 +08:00
Cp0204
de6e4356a4 🎨 优化样式和布局,显示油猴脚本链接
- 添加教程二维码
- 增强按钮的工具提示功能
2025-04-26 17:04:35 +08:00
Cp0204
da7a5e93c8 🐛 修复网络异常时记录为分享失效 #71
- 调整分享详情和文件列表的返回结构
- 增强网络异常时的错误处理
2025-04-26 17:04:35 +08:00
10 changed files with 163 additions and 82 deletions

View File

@ -29,13 +29,13 @@
> ⛔️⛔️⛔️ 注意!资源不会每时每刻更新,**严禁设定过高的定时运行频率!** 以免账号风控和给夸克服务器造成不必要的压力。雪山崩塌,每一片雪花都有责任! > ⛔️⛔️⛔️ 注意!资源不会每时每刻更新,**严禁设定过高的定时运行频率!** 以免账号风控和给夸克服务器造成不必要的压力。雪山崩塌,每一片雪花都有责任!
> [!NOTE] > [!NOTE]
> 因不想当客服处理各种使用咨询,即日起 Issues 关闭,如果你发现了 bug 、有好的想法或功能建议,欢迎通过 PR 和我对话,谢谢! > 开发者≠客服开源免费≠帮你解决使用问题本项目Wiki和已经相对完善遇到问题请先翻阅 Issues 和 Wiki ,请勿盲目发问。
## 功能 ## 功能
- 部署方式 - 部署方式
- [x] 兼容青龙 - [x] 可能~~兼容青龙~~
- [x] 支持 Docker 独立部署WebUI 配置 - [x] Docker 部署WebUI 配置
- 分享链接 - 分享链接
- [x] 支持分享链接的子目录 - [x] 支持分享链接的子目录
@ -58,7 +58,7 @@
- 媒体库整合 - 媒体库整合
- [x] 根据任务名搜索 Emby 媒体库 - [x] 根据任务名搜索 Emby 媒体库
- [x] 追更或整理后自动刷新 Emby 媒体库 - [x] 追更或整理后自动刷新 Emby 媒体库
- [x] **媒体库模块化,用户可很方便地[开发自己的媒体库hook模块](./plugins)** - [x] 媒体库模块化,用户可很方便地[开发自己的媒体库hook模块](./plugins)
- 其它 - 其它
- [x] 每日签到领空间 <sup>[?](https://github.com/Cp0204/quark-auto-save/wiki/使用技巧集锦#每日签到领空间)</sup> - [x] 每日签到领空间 <sup>[?](https://github.com/Cp0204/quark-auto-save/wiki/使用技巧集锦#每日签到领空间)</sup>
@ -74,10 +74,10 @@ Docker 部署提供 WebUI 管理配置,图形化配置已能满足绝大多数
```shell ```shell
docker run -d \ docker run -d \
--name quark-auto-save \ --name quark-auto-save \
-p 5005:5005 \ -p 5005:5005 \ # 映射端口,:前的可以改,即部署后访问的端口,:后的不可改
-e WEBUI_USERNAME=admin \ -e WEBUI_USERNAME=admin \
-e WEBUI_PASSWORD=admin123 \ -e WEBUI_PASSWORD=admin123 \
-v ./quark-auto-save/config:/app/config \ -v ./quark-auto-save/config:/app/config \ # 必须,配置持久化
-v ./quark-auto-save/media:/media \ # 可选模块alist_strm_gen生成strm使用 -v ./quark-auto-save/media:/media \ # 可选模块alist_strm_gen生成strm使用
--network bridge \ --network bridge \
--restart unless-stopped \ --restart unless-stopped \
@ -167,12 +167,14 @@ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtow
## 打赏 ## 打赏
如果这个项目让你受益,你可以打赏我1块钱让我知道开源有价值。谢谢 如果这个项目让你受益,你可以无偿赠与我1块钱让我知道开源有价值。谢谢
![WeChatPay](https://cdn.jsdelivr.net/gh/Cp0204/Cp0204@main/img/wechat_pay_qrcode.png) ![WeChatPay](https://cdn.jsdelivr.net/gh/Cp0204/Cp0204@main/img/wechat_pay_qrcode.png)
## 声明 ## 声明
程序为个人兴趣开发,开源仅供学习与交流使用 项目为个人兴趣开发,旨在通过程序自动化提高网盘使用效率
程序没有任何破解行为只是对于夸克已有的API进行封装所有数据来自于夸克官方API本人不对网盘内容负责、不对夸克官方API未来可能的改动导致的后果负责。 程序没有任何破解行为只是对于夸克已有的API进行封装所有数据来自于夸克官方API本人不对网盘内容负责、不对夸克官方API未来可能的变动导致的影响负责请自行斟酌使用。
开源仅供学习与交流使用,未盈利也未授权商业使用,严禁用于非法用途。

View File

@ -268,15 +268,26 @@ def get_share_detail():
account = Quark("", 0) account = Quark("", 0)
pwd_id, passcode, pdir_fid, paths = account.extract_url(shareurl) pwd_id, passcode, pdir_fid, paths = account.extract_url(shareurl)
if not stoken: if not stoken:
is_sharing, stoken = account.get_stoken(pwd_id, passcode) get_stoken = account.get_stoken(pwd_id, passcode)
if not is_sharing: if get_stoken.get("status") == 200:
return jsonify({"success": False, "data": {"error": stoken}}) stoken = get_stoken["data"]["stoken"]
else:
return jsonify(
{"success": False, "data": {"error": get_stoken.get("message")}}
)
share_detail = account.get_detail(pwd_id, stoken, pdir_fid, _fetch_share=1) share_detail = account.get_detail(pwd_id, stoken, pdir_fid, _fetch_share=1)
share_detail["paths"] = paths
share_detail["stoken"] = stoken if share_detail.get("code") != 0:
return jsonify(
{"success": False, "data": {"error": share_detail.get("message")}}
)
data = share_detail["data"]
data["paths"] = paths
data["stoken"] = stoken
# 正则处理预览 # 正则处理预览
def preview_regex(share_detail): def preview_regex(data):
regex = request.json.get("regex", {}) regex = request.json.get("regex", {})
pattern, replace = account.magic_regex_func( pattern, replace = account.magic_regex_func(
regex.get("pattern", ""), regex.get("pattern", ""),
@ -284,7 +295,7 @@ def get_share_detail():
regex.get("taskname", ""), regex.get("taskname", ""),
regex.get("magic_regex", {}), regex.get("magic_regex", {}),
) )
for item in share_detail["list"]: for item in data["list"]:
file_name = item["file_name"] file_name = item["file_name"]
if re.search(pattern, item["file_name"]): if re.search(pattern, item["file_name"]):
item["file_name_re"] = ( item["file_name_re"] = (
@ -293,9 +304,9 @@ def get_share_detail():
return share_detail return share_detail
if request.json.get("regex"): if request.json.get("regex"):
share_detail = preview_regex(share_detail) share_detail = preview_regex(data)
return jsonify({"success": True, "data": share_detail}) return jsonify({"success": True, "data": data})
@app.route("/get_savepath_detail") @app.route("/get_savepath_detail")
@ -328,7 +339,7 @@ def get_savepath_detail():
else: else:
fid = request.args.get("fid", "0") fid = request.args.get("fid", "0")
file_list = { file_list = {
"list": account.ls_dir(fid), "list": account.ls_dir(fid)["data"]["list"],
"paths": paths, "paths": paths,
} }
return jsonify({"success": True, "data": file_list}) return jsonify({"success": True, "data": file_list})

View File

@ -45,7 +45,7 @@ body {
margin-bottom: 10px; margin-bottom: 10px;
} }
table.jsoneditor-tree>tbody>tr.jsoneditor-expandable:first-child { table.jsoneditor-tree > tbody > tr.jsoneditor-expandable:first-child {
display: none; display: none;
} }
@ -82,14 +82,14 @@ table.jsoneditor-tree>tbody>tr.jsoneditor-expandable:first-child {
/* Behind the navbar */ /* Behind the navbar */
padding: 54px 0 0; padding: 54px 0 0;
/* Height of navbar */ /* Height of navbar */
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.1);
} }
.sidebar-sticky { .sidebar-sticky {
position: relative; position: relative;
top: 0; top: 0;
height: calc(100vh - 54px); height: calc(100vh - 54px);
padding-top: .5rem; padding-top: 0.5rem;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
/* Scrollable contents if viewport is shorter than content. */ /* Scrollable contents if viewport is shorter than content. */
@ -125,9 +125,8 @@ table.jsoneditor-tree>tbody>tr.jsoneditor-expandable:first-child {
color: white !important; color: white !important;
} }
.sidebar-heading { .sidebar-heading {
font-size: .75rem; font-size: 0.75rem;
text-transform: uppercase; text-transform: uppercase;
} }
@ -136,10 +135,10 @@ table.jsoneditor-tree>tbody>tr.jsoneditor-expandable:first-child {
*/ */
.navbar-brand { .navbar-brand {
padding-top: .75rem; padding-top: 0.75rem;
padding-bottom: .75rem; padding-bottom: 0.75rem;
background-color: rgba(0, 0, 0, .25); background-color: rgba(0, 0, 0, 0.25);
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.25);
} }
.navbar .navbar-toggler { .navbar .navbar-toggler {
@ -147,22 +146,53 @@ table.jsoneditor-tree>tbody>tr.jsoneditor-expandable:first-child {
} }
.navbar .form-control { .navbar .form-control {
padding: .75rem 1rem; padding: 0.75rem 1rem;
border-width: 0; border-width: 0;
border-radius: 0; border-radius: 0;
} }
.form-control-dark { .form-control-dark {
color: #fff; color: #fff;
background-color: rgba(255, 255, 255, .1); background-color: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, .1); border-color: rgba(255, 255, 255, 0.1);
} }
.form-control-dark:focus { .form-control-dark:focus {
border-color: transparent; border-color: transparent;
box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25);
} }
.cursor-pointer { .cursor-pointer {
cursor: pointer cursor: pointer;
}
.nav-bottom {
position: absolute;
bottom: 32px;
width: 100%;
font-size: small;
}
.position-relative:hover .position-absolute {
display: block !important;
}
.qrcode-tutorial {
display: none;
left: 50%;
transform: translateX(-50%);
bottom: 100%;
margin-bottom: 10px;
z-index: 1000;
border: 1px solid #ddd;
background-color: #fff;
padding: 10px;
border-radius: 5px;
max-width: 100%;
text-align: center;
}
.qrcode-tutorial img {
max-width: 100%;
height: auto;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -2,7 +2,7 @@
// @name QAS一键推送助手 // @name QAS一键推送助手
// @namespace https://github.com/Cp0204/quark-auto-save // @namespace https://github.com/Cp0204/quark-auto-save
// @license AGPL // @license AGPL
// @version 0.3 // @version 0.4
// @description 在夸克网盘分享页面添加推送到 QAS 的按钮 // @description 在夸克网盘分享页面添加推送到 QAS 的按钮
// @icon https://pan.quark.cn/favicon.ico // @icon https://pan.quark.cn/favicon.ico
// @author Cp0204 // @author Cp0204
@ -11,41 +11,53 @@
// @grant GM_setValue // @grant GM_setValue
// @grant GM_xmlhttpRequest // @grant GM_xmlhttpRequest
// @require https://cdn.jsdelivr.net/npm/sweetalert2@11 // @require https://cdn.jsdelivr.net/npm/sweetalert2@11
// @downloadURL https://update.greasyfork.org/scripts/533201/QAS%E4%B8%80%E9%94%AE%E6%8E%A8%E9%80%81%E5%8A%A9%E6%89%8B.user.js // @downloadURL https://cdn.jsdelivr.net/gh/Cp0204/quark-auto-save@refs/heads/main/app/static/js/qas.addtask.user.js
// @updateURL https://update.greasyfork.org/scripts/533201/QAS%E4%B8%80%E9%94%AE%E6%8E%A8%E9%80%81%E5%8A%A9%E6%89%8B.meta.js // @updateURL https://cdn.jsdelivr.net/gh/Cp0204/quark-auto-save@refs/heads/main/app/static/js/qas.addtask.user.js
// ==/UserScript== // ==/UserScript==
(function() { (function () {
'use strict'; 'use strict';
let qas_base = GM_getValue('qas_base', ''); let qas_base = GM_getValue('qas_base', '');
let qas_token = GM_getValue('qas_token', ''); let qas_token = GM_getValue('qas_token', '');
let default_pattern = GM_getValue('default_pattern', '');
let default_replace = GM_getValue('default_replace', '');
// QAS 设置弹窗函数 // QAS 设置弹窗函数
function showQASSettingDialog(callback) { function showQASSettingDialog(callback) {
Swal.fire({ Swal.fire({
title: 'QAS 设置', title: 'QAS 设置',
showCancelButton: true,
html: ` html: `
<label for="qas_base">QAS 服务器</label> <label for="qas_base">QAS 地址</label>
<input id="qas_base" class="swal2-input" placeholder="如: 192.168.1.8:5005" value="${qas_base}"> <input id="qas_base" class="swal2-input" placeholder="如: http://192.168.1.8:5005" value="${qas_base}">
<label for="qas_token">QAS Token</label> <label for="qas_token">QAS Token</label>
<input id="qas_token" class="swal2-input" placeholder="v0.5+ 系统配置中查找" value="${qas_token}"> <input id="qas_token" class="swal2-input" placeholder="v0.5+ 系统配置中查找" value="${qas_token}">
<label for="qas_token">默认正则</label>
<input id="default_pattern" class="swal2-input" placeholder="如 $TV" value="${default_pattern}">
<label for="qas_token">默认替换</label><input id="default_replace" class="swal2-input" value="${default_replace}">
`, `,
focusConfirm: false, focusConfirm: false,
preConfirm: () => { preConfirm: () => {
qas_base = document.getElementById('qas_base').value; qas_base = document.getElementById('qas_base').value;
qas_token = document.getElementById('qas_token').value; qas_token = document.getElementById('qas_token').value;
default_pattern = document.getElementById('default_pattern').value;
default_replace = document.getElementById('default_replace').value;
if (!qas_base || !qas_token) { if (!qas_base || !qas_token) {
Swal.showValidationMessage('请填写 QAS 服务器和 Token'); Swal.showValidationMessage('请填写 QAS 地址和 Token');
} }
return { qas_base: qas_base, qas_token: qas_token } return { qas_base: qas_base, qas_token: qas_token, default_pattern: default_pattern, default_replace: default_replace }
} }
}).then((result) => { }).then((result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
GM_setValue('qas_base', result.value.qas_base); GM_setValue('qas_base', result.value.qas_base);
GM_setValue('qas_token', result.value.qas_token); GM_setValue('qas_token', result.value.qas_token);
GM_setValue('default_pattern', result.value.default_pattern);
GM_setValue('default_replace', result.value.default_replace);
qas_base = result.value.qas_base; qas_base = result.value.qas_base;
qas_token = result.value.qas_token; qas_token = result.value.qas_token;
default_pattern = result.value.default_pattern;
default_replace = result.value.default_replace;
if (callback) { if (callback) {
callback(); // 执行回调函数 callback(); // 执行回调函数
} }
@ -93,18 +105,18 @@
qasButton.type = 'button'; qasButton.type = 'button';
qasButton.className = 'ant-btn share-save'; qasButton.className = 'ant-btn share-save';
qasButton.style.marginLeft = '10px'; qasButton.style.marginLeft = '10px';
qasButton.innerHTML = '<span class="share-save-ico"></span><span>推送到QAS</span>'; qasButton.innerHTML = '<span class="share-save-ico"></span><span>创建QAS任务</span>';
let taskname, shareurl, savepath; // 声明变量 let taskname, shareurl, savepath; // 声明变量
// 获取数据函数 // 获取数据函数
function getData() { function getData() {
const currentUrl = window.location.href; const currentUrl = window.location.href;
taskname = currentUrl.lastIndexOf('-') > 0 ? decodeURIComponent(currentUrl.match(/.*\/[^-]+-(.+)$/)[1]) : document.querySelector('.author-name').textContent; taskname = currentUrl.lastIndexOf('-') > 0 ? decodeURIComponent(currentUrl.match(/.*\/[^-]+-(.+)$/)[1]).replace('*101', '-') : document.querySelector('.author-name').textContent;
shareurl = currentUrl; shareurl = currentUrl;
let pathElement = document.querySelector('.path-name') let pathElement = document.querySelector('.path-name');
savepath = pathElement ? pathElement.title.replace('全部文件', '').trim() : ""; savepath = pathElement ? pathElement.title.replace('全部文件', '').trim() : "";
savepath += "/" + taskname savepath += "/" + taskname;
qasButton.title = `任务名称: ${taskname}\n分享链接: ${shareurl}\n保存路径: ${savepath}`; qasButton.title = `任务名称: ${taskname}\n分享链接: ${shareurl}\n保存路径: ${savepath}`;
} }
@ -119,11 +131,19 @@
qasButton.addEventListener('click', () => { qasButton.addEventListener('click', () => {
getData(); // 点击时重新获取数据,确保最新 getData(); // 点击时重新获取数据,确保最新
const apiUrl = `http://${qas_base}/api/add_task?token=${qas_token}`; // 检查 qas_base 是否包含 http 或 https如果没有则添加 http://
let qasApiBase = qas_base;
if (!qasApiBase.startsWith('http')) {
qasApiBase = 'http://' + qasApiBase;
}
const apiUrl = `${qasApiBase}/api/add_task?token=${qas_token}`;
const data = { const data = {
"taskname": taskname, "taskname": taskname,
"shareurl": shareurl, "shareurl": shareurl,
"savepath": savepath, "savepath": savepath,
"pattern": default_pattern,
"replace": default_replace,
}; };
GM_xmlhttpRequest({ GM_xmlhttpRequest({
@ -133,7 +153,7 @@
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
data: JSON.stringify(data), data: JSON.stringify(data),
onload: function(response) { onload: function (response) {
try { try {
const jsonResponse = JSON.parse(response.responseText); const jsonResponse = JSON.parse(response.responseText);
if (jsonResponse.success) { if (jsonResponse.success) {
@ -142,7 +162,7 @@
html: `<small> html: `<small>
<b>任务名称:</b> ${taskname}<br><br> <b>任务名称:</b> ${taskname}<br><br>
<b>保存路径:</b> ${savepath}<br><br> <b>保存路径:</b> ${savepath}<br><br>
<a href="http://${qas_base}" target="_blank"> QAS 查看</a> <a href="${qasApiBase}" target="_blank"> QAS 查看</a>
<small>`, <small>`,
icon: 'success' icon: 'success'
}); });
@ -161,7 +181,7 @@
}); });
} }
}, },
onerror: function(error) { onerror: function (error) {
Swal.fire({ Swal.fire({
title: '任务创建失败', title: '任务创建失败',
text: error, text: error,

View File

@ -49,9 +49,17 @@
</a> </a>
</li> </li>
</ul> </ul>
<div class="text-center" style="position: absolute; bottom: 32px; width: 100%; font-size: small;"> <div class="nav-bottom text-center">
<p><a class="" target="_blank" href="https://github.com/Cp0204/quark-auto-save/wiki"><i class="bi bi-wechat"></i> 使用交流</a></p> <p class="position-relative" hidden>
<p><a target="_blank" href="https://github.com/Cp0204/quark-auto-save"><i class="bi bi-github"></i> quark-auto-save</a></p> <b class="text-success"><i class="bi bi-record-circle mr-1"></i>视频教程</b>
<span class="position-absolute qrcode-tutorial">
使用夸克扫码查看<br>
<img src="./static/img/qrcode_tutorial.png">
</span>
</p>
<p><a target="_blank" href="https://github.com/Cp0204/quark-auto-save/wiki"><i class="bi bi-wechat mr-1"></i>使用交流</a></p>
<p><a href="./static/js/qas.addtask.user.js"><i class="bi bi-cloud-plus-fill mr-1"></i>推送任务油猴脚本</a></p>
<p><a target="_blank" href="https://github.com/Cp0204/quark-auto-save"><i class="bi bi-github mr-1"></i>quark-auto-save</a></p>
<p><span v-html="versionTips"></span></p> <p><span v-html="versionTips"></span></p>
</div> </div>
</div> </div>
@ -391,9 +399,9 @@
</div> </div>
<div class="bottom-buttons"> <div class="bottom-buttons">
<button class="btn btn-success" title="保存 CTRL+S"><i class="bi bi-floppy2-fill"></i></button> <button class="btn btn-success" data-toggle="tooltip" data-placement="top" title="保存 CTRL+S"><i class="bi bi-floppy2-fill"></i></button>
<button type="button" class="btn btn-primary" title="运行 CTRL+R" @click="runScriptNow()"><i class="bi bi-play-fill"></i></button> <button type="button" class="btn btn-primary" data-toggle="tooltip" data-placement="top" title="运行 CTRL+R" @click="runScriptNow()"><i class="bi bi-play-fill"></i></button>
<button type="button" class="btn btn-info" @click="scrollToX(0)" @dblclick="scrollToX()" data-toggle="tooltip" data-placement="top" title="单击回顶,双击到底"><i class="bi bi-chevron-bar-up"></i></button> <button type="button" class="btn btn-info" data-toggle="tooltip" data-placement="top" title="单击回顶,双击到底" @click="scrollToX(0)" @dblclick="scrollToX()"><i class="bi bi-chevron-bar-up"></i></button>
</div> </div>
</form> </form>
</main> </main>
@ -605,7 +613,7 @@
latestVersion = response.data[0].name; latestVersion = response.data[0].name;
console.log(`检查版本:当前 ${this.version} 最新 ${latestVersion}`); console.log(`检查版本:当前 ${this.version} 最新 ${latestVersion}`);
if (latestVersion != this.version) { if (latestVersion != this.version) {
this.versionTips += ` <sup><span class="badge badge-pill badge-danger">${latestVersion}</span></sup>`; this.versionTips += ` <sup><span class="position-absolute badge badge-pill badge-danger">${latestVersion}</span></sup>`;
} }
}) })
.catch(error => { .catch(error => {
@ -922,6 +930,8 @@
}, },
selectSuggestion(index, suggestion) { selectSuggestion(index, suggestion) {
this.smart_param.showSuggestions = false; this.smart_param.showSuggestions = false;
this.fileSelect.selectDir = true;
this.fileSelect.previewRegex = false;
this.showShareSelect(index, suggestion.shareurl); this.showShareSelect(index, suggestion.shareurl);
}, },
addMagicRegex() { addMagicRegex() {
@ -1021,10 +1031,12 @@
this.fileSelect.fileList = []; this.fileSelect.fileList = [];
this.fileSelect.paths = []; this.fileSelect.paths = [];
this.fileSelect.error = undefined; this.fileSelect.error = undefined;
if (this.getShareurl(this.fileSelect.shareurl) != this.getShareurl(this.formData.tasklist[index].shareurl)) { // 如果分享链接发生变化,则重置 stoken
const newShareurl = shareurl || this.formData.tasklist[index].shareurl
if (this.getShareurl(this.fileSelect.shareurl) != this.getShareurl(newShareurl)) {
this.fileSelect.stoken = ""; this.fileSelect.stoken = "";
} }
this.fileSelect.shareurl = shareurl || this.formData.tasklist[index].shareurl; this.fileSelect.shareurl = newShareurl;
this.fileSelect.index = index; this.fileSelect.index = index;
$('#fileSelectModal').modal('toggle'); $('#fileSelectModal').modal('toggle');
this.getShareDetail(); this.getShareDetail();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 313 KiB

View File

@ -240,7 +240,9 @@ class Quark:
print(f"_send_request error:\n{e}") print(f"_send_request error:\n{e}")
fake_response = requests.Response() fake_response = requests.Response()
fake_response.status_code = 500 fake_response.status_code = 500
fake_response._content = b'{"status": 500, "message": "request error"}' fake_response._content = (
b'{"status": 500, "code": 1, "message": "request error"}'
)
return fake_response return fake_response
def init(self): def init(self):
@ -312,10 +314,7 @@ class Quark:
response = self._send_request( response = self._send_request(
"POST", url, json=payload, params=querystring "POST", url, json=payload, params=querystring
).json() ).json()
if response.get("status") == 200: return response
return True, response["data"]["stoken"]
else:
return False, response["message"]
def get_detail(self, pwd_id, stoken, pdir_fid, _fetch_share=0): def get_detail(self, pwd_id, stoken, pdir_fid, _fetch_share=0):
list_merge = [] list_merge = []
@ -338,7 +337,7 @@ class Quark:
} }
response = self._send_request("GET", url, params=querystring).json() response = self._send_request("GET", url, params=querystring).json()
if response["code"] != 0: if response["code"] != 0:
return {"error": response["message"]} return response
if response["data"]["list"]: if response["data"]["list"]:
list_merge += response["data"]["list"] list_merge += response["data"]["list"]
page += 1 page += 1
@ -347,7 +346,7 @@ class Quark:
if len(list_merge) >= response["metadata"]["_total"]: if len(list_merge) >= response["metadata"]["_total"]:
break break
response["data"]["list"] = list_merge response["data"]["list"] = list_merge
return response["data"] return response
def get_fids(self, file_paths): def get_fids(self, file_paths):
fids = [] fids = []
@ -369,7 +368,7 @@ class Quark:
return fids return fids
def ls_dir(self, pdir_fid, **kwargs): def ls_dir(self, pdir_fid, **kwargs):
file_list = [] list_merge = []
page = 1 page = 1
while True: while True:
url = f"{self.BASE_URL}/1/clouddrive/file/sort" url = f"{self.BASE_URL}/1/clouddrive/file/sort"
@ -387,15 +386,16 @@ class Quark:
} }
response = self._send_request("GET", url, params=querystring).json() response = self._send_request("GET", url, params=querystring).json()
if response["code"] != 0: if response["code"] != 0:
return {"error": response["message"]} return response
if response["data"]["list"]: if response["data"]["list"]:
file_list += response["data"]["list"] list_merge += response["data"]["list"]
page += 1 page += 1
else: else:
break break
if len(file_list) >= response["metadata"]["_total"]: if len(list_merge) >= response["metadata"]["_total"]:
break break
return file_list response["data"]["list"] = list_merge
return response
def save_file(self, fid_list, fid_token_list, to_pdir_fid, pwd_id, stoken): def save_file(self, fid_list, fid_token_list, to_pdir_fid, pwd_id, stoken):
url = f"{self.BASE_URL}/1/clouddrive/share/sharepage/save" url = f"{self.BASE_URL}/1/clouddrive/share/sharepage/save"
@ -595,8 +595,8 @@ class Quark:
def do_save_check(self, shareurl, savepath): def do_save_check(self, shareurl, savepath):
try: try:
pwd_id, passcode, pdir_fid, _ = self.extract_url(shareurl) pwd_id, passcode, pdir_fid, _ = self.extract_url(shareurl)
_, stoken = self.get_stoken(pwd_id, passcode) stoken = self.get_stoken(pwd_id, passcode)["data"]["stoken"]
share_file_list = self.get_detail(pwd_id, stoken, pdir_fid)["list"] share_file_list = self.get_detail(pwd_id, stoken, pdir_fid)["data"]["list"]
fid_list = [item["fid"] for item in share_file_list] fid_list = [item["fid"] for item in share_file_list]
fid_token_list = [item["share_fid_token"] for item in share_file_list] fid_token_list = [item["share_fid_token"] for item in share_file_list]
file_name_list = [item["file_name"] for item in share_file_list] file_name_list = [item["file_name"] for item in share_file_list]
@ -612,7 +612,7 @@ class Quark:
if save_file["code"] == 41017: if save_file["code"] == 41017:
return return
elif save_file["code"] == 0: elif save_file["code"] == 0:
dir_file_list = self.ls_dir(to_pdir_fid) dir_file_list = self.ls_dir(to_pdir_fid)["data"]["list"]
del_list = [ del_list = [
item["fid"] item["fid"]
for item in dir_file_list for item in dir_file_list
@ -644,10 +644,16 @@ class Quark:
pwd_id, passcode, pdir_fid, _ = self.extract_url(task["shareurl"]) pwd_id, passcode, pdir_fid, _ = self.extract_url(task["shareurl"])
# 获取stoken同时可验证资源是否失效 # 获取stoken同时可验证资源是否失效
is_sharing, stoken = self.get_stoken(pwd_id, passcode) get_stoken = self.get_stoken(pwd_id, passcode)
if not is_sharing: if get_stoken.get("status") == 200:
add_notify(f"❌《{task['taskname']}》:{stoken}\n") stoken = get_stoken["data"]["stoken"]
task["shareurl_ban"] = stoken elif get_stoken.get("status") == 500:
print(f"跳过任务:网络异常 {get_stoken.get("message")}")
return
else:
message = get_stoken.get("message")
add_notify(f"❌《{task['taskname']}》:{message}\n")
task["shareurl_ban"] = message
return return
# print("stoken: ", stoken) # print("stoken: ", stoken)
@ -662,7 +668,7 @@ class Quark:
def dir_check_and_save(self, task, pwd_id, stoken, pdir_fid="", subdir_path=""): def dir_check_and_save(self, task, pwd_id, stoken, pdir_fid="", subdir_path=""):
tree = Tree() tree = Tree()
# 获取分享文件列表 # 获取分享文件列表
share_file_list = self.get_detail(pwd_id, stoken, pdir_fid)["list"] share_file_list = self.get_detail(pwd_id, stoken, pdir_fid)["data"]["list"]
# print("share_file_list: ", share_file_list) # print("share_file_list: ", share_file_list)
if not share_file_list: if not share_file_list:
@ -678,7 +684,7 @@ class Quark:
print("🧠 该分享是一个文件夹,读取文件夹内列表") print("🧠 该分享是一个文件夹,读取文件夹内列表")
share_file_list = self.get_detail( share_file_list = self.get_detail(
pwd_id, stoken, share_file_list[0]["fid"] pwd_id, stoken, share_file_list[0]["fid"]
)["list"] )["data"]["list"]
# 获取目标目录文件列表 # 获取目标目录文件列表
savepath = re.sub(r"/{2,}", "/", f"/{task['savepath']}{subdir_path}") savepath = re.sub(r"/{2,}", "/", f"/{task['savepath']}{subdir_path}")
@ -689,7 +695,7 @@ class Quark:
print(f"❌ 目录 {savepath} fid获取失败跳过转存") print(f"❌ 目录 {savepath} fid获取失败跳过转存")
return tree return tree
to_pdir_fid = self.savepath_fid[savepath] to_pdir_fid = self.savepath_fid[savepath]
dir_file_list = self.ls_dir(to_pdir_fid) dir_file_list = self.ls_dir(to_pdir_fid)["data"]["list"]
# print("dir_file_list: ", dir_file_list) # print("dir_file_list: ", dir_file_list)
# 清空目标文件夹 # 清空目标文件夹
fid_list = [item["fid"] for item in dir_file_list] fid_list = [item["fid"] for item in dir_file_list]
@ -819,7 +825,7 @@ class Quark:
savepath = re.sub(r"/{2,}", "/", f"/{task['savepath']}{subdir_path}") savepath = re.sub(r"/{2,}", "/", f"/{task['savepath']}{subdir_path}")
if not self.savepath_fid.get(savepath): if not self.savepath_fid.get(savepath):
self.savepath_fid[savepath] = self.get_fids([savepath])[0]["fid"] self.savepath_fid[savepath] = self.get_fids([savepath])[0]["fid"]
dir_file_list = self.ls_dir(self.savepath_fid[savepath]) dir_file_list = self.ls_dir(self.savepath_fid[savepath])["data"]["list"]
dir_file_name_list = [item["file_name"] for item in dir_file_list] dir_file_name_list = [item["file_name"] for item in dir_file_list]
is_rename_count = 0 is_rename_count = 0
for dir_file in dir_file_list: for dir_file in dir_file_list: