Compare commits
No commits in common. "71b4fca6c2c3672ac6ec79024f415fdf4c697e5a" and "546f4300a1f07c1635a9257e5c53a1ea88508cea" have entirely different histories.
71b4fca6c2
...
546f4300a1
20
README.md
@ -29,13 +29,13 @@
|
|||||||
> ⛔️⛔️⛔️ 注意!资源不会每时每刻更新,**严禁设定过高的定时运行频率!** 以免账号风控和给夸克服务器造成不必要的压力。雪山崩塌,每一片雪花都有责任!
|
> ⛔️⛔️⛔️ 注意!资源不会每时每刻更新,**严禁设定过高的定时运行频率!** 以免账号风控和给夸克服务器造成不必要的压力。雪山崩塌,每一片雪花都有责任!
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> 开发者≠客服,开源免费≠帮你解决使用问题;本项目Wiki和已经相对完善,遇到问题请先翻阅 Issues 和 Wiki ,请勿盲目发问。
|
> 因不想当客服处理各种使用咨询,即日起 Issues 关闭,如果你发现了 bug 、有好的想法或功能建议,欢迎通过 PR 和我对话,谢谢!
|
||||||
|
|
||||||
## 功能
|
## 功能
|
||||||
|
|
||||||
- 部署方式
|
- 部署方式
|
||||||
- [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,14 +167,12 @@ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtow
|
|||||||
|
|
||||||
## 打赏
|
## 打赏
|
||||||
|
|
||||||
如果这个项目让你受益,你可以无偿赠与我1块钱,让我知道开源有价值。谢谢!
|
如果这个项目让你受益,你可以打赏我1块钱,让我知道开源有价值。谢谢!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 声明
|
## 声明
|
||||||
|
|
||||||
本项目为个人兴趣开发,旨在通过程序自动化提高网盘使用效率。
|
本程序为个人兴趣开发,开源仅供学习与交流使用。
|
||||||
|
|
||||||
程序没有任何破解行为,只是对于夸克已有的API进行封装,所有数据来自于夸克官方API;本人不对网盘内容负责、不对夸克官方API未来可能的变动导致的影响负责,请自行斟酌使用。
|
程序没有任何破解行为,只是对于夸克已有的API进行封装,所有数据来自于夸克官方API,本人不对网盘内容负责、不对夸克官方API未来可能的改动导致的后果负责。
|
||||||
|
|
||||||
开源仅供学习与交流使用,未盈利也未授权商业使用,严禁用于非法用途。
|
|
||||||
31
app/run.py
@ -268,26 +268,15 @@ 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:
|
||||||
get_stoken = account.get_stoken(pwd_id, passcode)
|
is_sharing, stoken = account.get_stoken(pwd_id, passcode)
|
||||||
if get_stoken.get("status") == 200:
|
if not is_sharing:
|
||||||
stoken = get_stoken["data"]["stoken"]
|
return jsonify({"success": False, "data": {"error": 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
|
||||||
if share_detail.get("code") != 0:
|
share_detail["stoken"] = stoken
|
||||||
return jsonify(
|
|
||||||
{"success": False, "data": {"error": share_detail.get("message")}}
|
|
||||||
)
|
|
||||||
|
|
||||||
data = share_detail["data"]
|
|
||||||
data["paths"] = paths
|
|
||||||
data["stoken"] = stoken
|
|
||||||
|
|
||||||
# 正则处理预览
|
# 正则处理预览
|
||||||
def preview_regex(data):
|
def preview_regex(share_detail):
|
||||||
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", ""),
|
||||||
@ -295,7 +284,7 @@ def get_share_detail():
|
|||||||
regex.get("taskname", ""),
|
regex.get("taskname", ""),
|
||||||
regex.get("magic_regex", {}),
|
regex.get("magic_regex", {}),
|
||||||
)
|
)
|
||||||
for item in data["list"]:
|
for item in share_detail["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"] = (
|
||||||
@ -304,9 +293,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(data)
|
share_detail = preview_regex(share_detail)
|
||||||
|
|
||||||
return jsonify({"success": True, "data": data})
|
return jsonify({"success": True, "data": share_detail})
|
||||||
|
|
||||||
|
|
||||||
@app.route("/get_savepath_detail")
|
@app.route("/get_savepath_detail")
|
||||||
@ -339,7 +328,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)["data"]["list"],
|
"list": account.ls_dir(fid),
|
||||||
"paths": paths,
|
"paths": paths,
|
||||||
}
|
}
|
||||||
return jsonify({"success": True, "data": file_list})
|
return jsonify({"success": True, "data": file_list})
|
||||||
|
|||||||
@ -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, 0.1);
|
box-shadow: inset -1px 0 0 rgba(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: 0.5rem;
|
padding-top: .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,8 +125,9 @@ table.jsoneditor-tree > tbody > tr.jsoneditor-expandable:first-child {
|
|||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sidebar-heading {
|
.sidebar-heading {
|
||||||
font-size: 0.75rem;
|
font-size: .75rem;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,10 +136,10 @@ table.jsoneditor-tree > tbody > tr.jsoneditor-expandable:first-child {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.navbar-brand {
|
.navbar-brand {
|
||||||
padding-top: 0.75rem;
|
padding-top: .75rem;
|
||||||
padding-bottom: 0.75rem;
|
padding-bottom: .75rem;
|
||||||
background-color: rgba(0, 0, 0, 0.25);
|
background-color: rgba(0, 0, 0, .25);
|
||||||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.25);
|
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar .navbar-toggler {
|
.navbar .navbar-toggler {
|
||||||
@ -146,53 +147,22 @@ table.jsoneditor-tree > tbody > tr.jsoneditor-expandable:first-child {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navbar .form-control {
|
.navbar .form-control {
|
||||||
padding: 0.75rem 1rem;
|
padding: .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, 0.1);
|
background-color: rgba(255, 255, 255, .1);
|
||||||
border-color: rgba(255, 255, 255, 0.1);
|
border-color: rgba(255, 255, 255, .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, 0.25);
|
box-shadow: 0 0 0 3px rgba(255, 255, 255, .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;
|
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
@ -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.4
|
// @version 0.3
|
||||||
// @description 在夸克网盘分享页面添加推送到 QAS 的按钮
|
// @description 在夸克网盘分享页面添加推送到 QAS 的按钮
|
||||||
// @icon https://pan.quark.cn/favicon.ico
|
// @icon https://pan.quark.cn/favicon.ico
|
||||||
// @author Cp0204
|
// @author Cp0204
|
||||||
@ -11,8 +11,8 @@
|
|||||||
// @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://cdn.jsdelivr.net/gh/Cp0204/quark-auto-save@refs/heads/main/app/static/js/qas.addtask.user.js
|
// @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
|
||||||
// @updateURL 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
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
@ -20,44 +20,32 @@
|
|||||||
|
|
||||||
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="如: http://192.168.1.8:5005" value="${qas_base}">
|
<input id="qas_base" class="swal2-input" placeholder="例如: 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, default_pattern: default_pattern, default_replace: default_replace }
|
return { qas_base: qas_base, qas_token: qas_token }
|
||||||
}
|
}
|
||||||
}).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(); // 执行回调函数
|
||||||
}
|
}
|
||||||
@ -105,18 +93,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]).replace('*101', '-') : document.querySelector('.author-name').textContent;
|
taskname = currentUrl.lastIndexOf('-') > 0 ? decodeURIComponent(currentUrl.match(/.*\/[^-]+-(.+)$/)[1]) : 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}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,19 +119,11 @@
|
|||||||
qasButton.addEventListener('click', () => {
|
qasButton.addEventListener('click', () => {
|
||||||
getData(); // 点击时重新获取数据,确保最新
|
getData(); // 点击时重新获取数据,确保最新
|
||||||
|
|
||||||
// 检查 qas_base 是否包含 http 或 https,如果没有则添加 http://
|
const apiUrl = `http://${qas_base}/api/add_task?token=${qas_token}`;
|
||||||
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({
|
||||||
@ -162,7 +142,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="${qasApiBase}" target="_blank">去 QAS 查看</a>
|
<a href="http://${qas_base}" target="_blank">去 QAS 查看</a>
|
||||||
<small>`,
|
<small>`,
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
|
|||||||
@ -49,17 +49,9 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="nav-bottom text-center">
|
<div class="text-center" style="position: absolute; bottom: 32px; width: 100%; font-size: small;">
|
||||||
<p class="position-relative" hidden>
|
<p><a class="" target="_blank" href="https://github.com/Cp0204/quark-auto-save/wiki"><i class="bi bi-wechat"></i> 使用交流</a></p>
|
||||||
<b class="text-success"><i class="bi bi-record-circle mr-1"></i>视频教程</b>
|
<p><a target="_blank" href="https://github.com/Cp0204/quark-auto-save"><i class="bi bi-github"></i> quark-auto-save</a></p>
|
||||||
<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>
|
||||||
@ -399,9 +391,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bottom-buttons">
|
<div class="bottom-buttons">
|
||||||
<button class="btn btn-success" data-toggle="tooltip" data-placement="top" title="保存 CTRL+S"><i class="bi bi-floppy2-fill"></i></button>
|
<button class="btn btn-success" title="保存 CTRL+S"><i class="bi bi-floppy2-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-primary" title="运行 CTRL+R" @click="runScriptNow()"><i class="bi bi-play-fill"></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>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
@ -613,7 +605,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="position-absolute badge badge-pill badge-danger">${latestVersion}</span></sup>`;
|
this.versionTips += ` <sup><span class="badge badge-pill badge-danger">${latestVersion}</span></sup>`;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
@ -930,8 +922,6 @@
|
|||||||
},
|
},
|
||||||
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() {
|
||||||
@ -1031,12 +1021,10 @@
|
|||||||
this.fileSelect.fileList = [];
|
this.fileSelect.fileList = [];
|
||||||
this.fileSelect.paths = [];
|
this.fileSelect.paths = [];
|
||||||
this.fileSelect.error = undefined;
|
this.fileSelect.error = undefined;
|
||||||
// 如果分享链接发生变化,则重置 stoken
|
if (this.getShareurl(this.fileSelect.shareurl) != this.getShareurl(this.formData.tasklist[index].shareurl)) {
|
||||||
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 = newShareurl;
|
this.fileSelect.shareurl = shareurl || this.formData.tasklist[index].shareurl;
|
||||||
this.fileSelect.index = index;
|
this.fileSelect.index = index;
|
||||||
$('#fileSelectModal').modal('toggle');
|
$('#fileSelectModal').modal('toggle');
|
||||||
this.getShareDetail();
|
this.getShareDetail();
|
||||||
|
|||||||
BIN
img/run_log.png
|
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 354 KiB After Width: | Height: | Size: 266 KiB |
|
Before Width: | Height: | Size: 313 KiB After Width: | Height: | Size: 216 KiB |
@ -240,9 +240,7 @@ 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 = (
|
fake_response._content = b'{"status": 500, "message": "request error"}'
|
||||||
b'{"status": 500, "code": 1, "message": "request error"}'
|
|
||||||
)
|
|
||||||
return fake_response
|
return fake_response
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
@ -314,7 +312,10 @@ class Quark:
|
|||||||
response = self._send_request(
|
response = self._send_request(
|
||||||
"POST", url, json=payload, params=querystring
|
"POST", url, json=payload, params=querystring
|
||||||
).json()
|
).json()
|
||||||
return response
|
if response.get("status") == 200:
|
||||||
|
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 = []
|
||||||
@ -337,7 +338,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 response
|
return {"error": response["message"]}
|
||||||
if response["data"]["list"]:
|
if response["data"]["list"]:
|
||||||
list_merge += response["data"]["list"]
|
list_merge += response["data"]["list"]
|
||||||
page += 1
|
page += 1
|
||||||
@ -346,7 +347,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
|
return response["data"]
|
||||||
|
|
||||||
def get_fids(self, file_paths):
|
def get_fids(self, file_paths):
|
||||||
fids = []
|
fids = []
|
||||||
@ -368,7 +369,7 @@ class Quark:
|
|||||||
return fids
|
return fids
|
||||||
|
|
||||||
def ls_dir(self, pdir_fid, **kwargs):
|
def ls_dir(self, pdir_fid, **kwargs):
|
||||||
list_merge = []
|
file_list = []
|
||||||
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"
|
||||||
@ -386,16 +387,15 @@ 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 response
|
return {"error": response["message"]}
|
||||||
if response["data"]["list"]:
|
if response["data"]["list"]:
|
||||||
list_merge += response["data"]["list"]
|
file_list += response["data"]["list"]
|
||||||
page += 1
|
page += 1
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
if len(list_merge) >= response["metadata"]["_total"]:
|
if len(file_list) >= response["metadata"]["_total"]:
|
||||||
break
|
break
|
||||||
response["data"]["list"] = list_merge
|
return file_list
|
||||||
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)["data"]["stoken"]
|
_, stoken = self.get_stoken(pwd_id, passcode)
|
||||||
share_file_list = self.get_detail(pwd_id, stoken, pdir_fid)["data"]["list"]
|
share_file_list = self.get_detail(pwd_id, stoken, pdir_fid)["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)["data"]["list"]
|
dir_file_list = self.ls_dir(to_pdir_fid)
|
||||||
del_list = [
|
del_list = [
|
||||||
item["fid"]
|
item["fid"]
|
||||||
for item in dir_file_list
|
for item in dir_file_list
|
||||||
@ -644,16 +644,10 @@ class Quark:
|
|||||||
pwd_id, passcode, pdir_fid, _ = self.extract_url(task["shareurl"])
|
pwd_id, passcode, pdir_fid, _ = self.extract_url(task["shareurl"])
|
||||||
|
|
||||||
# 获取stoken,同时可验证资源是否失效
|
# 获取stoken,同时可验证资源是否失效
|
||||||
get_stoken = self.get_stoken(pwd_id, passcode)
|
is_sharing, stoken = self.get_stoken(pwd_id, passcode)
|
||||||
if get_stoken.get("status") == 200:
|
if not is_sharing:
|
||||||
stoken = get_stoken["data"]["stoken"]
|
add_notify(f"❌《{task['taskname']}》:{stoken}\n")
|
||||||
elif get_stoken.get("status") == 500:
|
task["shareurl_ban"] = stoken
|
||||||
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)
|
||||||
|
|
||||||
@ -668,7 +662,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)["data"]["list"]
|
share_file_list = self.get_detail(pwd_id, stoken, pdir_fid)["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:
|
||||||
@ -684,7 +678,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"]
|
||||||
)["data"]["list"]
|
)["list"]
|
||||||
|
|
||||||
# 获取目标目录文件列表
|
# 获取目标目录文件列表
|
||||||
savepath = re.sub(r"/{2,}", "/", f"/{task['savepath']}{subdir_path}")
|
savepath = re.sub(r"/{2,}", "/", f"/{task['savepath']}{subdir_path}")
|
||||||
@ -695,7 +689,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)["data"]["list"]
|
dir_file_list = self.ls_dir(to_pdir_fid)
|
||||||
# print("dir_file_list: ", dir_file_list)
|
# print("dir_file_list: ", dir_file_list)
|
||||||
|
|
||||||
tree.create_node(
|
tree.create_node(
|
||||||
@ -814,7 +808,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])["data"]["list"]
|
dir_file_list = self.ls_dir(self.savepath_fid[savepath])
|
||||||
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:
|
||||||
|
|||||||