Compare commits

...

7 Commits

Author SHA1 Message Date
Cp0204
5e8ecd4052 📝 修改插件标志描述
Some checks failed
Docker Publish / build-and-push (push) Has been cancelled
2024-12-13 14:54:36 +08:00
Cp0204
3c4b92160d 🎨 调整任务建议样式 2024-12-13 14:47:04 +08:00
Cp0204
30a0d07b1a ️ 优化任务建议显示逻辑 2024-12-13 14:47:04 +08:00
Cp0204
9593ec4811 🎨 任务建议改为显示在上方 2024-12-13 14:47:04 +08:00
Cp0204
a59af79423 🐛 修复一些交互问题 2024-12-13 14:47:04 +08:00
Cp0204
7d1552eeca 添加任务建议
- 新增 `/task_suggestions` 路由,用于获取任务建议
- 添加任务建议的下拉菜单和搜索按钮
- 实现前端逻辑,支持根据任务名称搜索建议并显示结果
2024-12-13 14:47:04 +08:00
Cp0204
d05db559ab 保存路径和任务名称智能关联填写 2024-12-13 14:47:03 +08:00
3 changed files with 128 additions and 16 deletions

View File

@ -110,7 +110,7 @@ services:
| ---------------- | ---------- | -------- | | ---------------- | ---------- | -------- |
| `WEBUI_USERNAME` | `admin` | 管理账号 | | `WEBUI_USERNAME` | `admin` | 管理账号 |
| `WEBUI_PASSWORD` | `admin123` | 管理密码 | | `WEBUI_PASSWORD` | `admin123` | 管理密码 |
| `PLUGIN_FLAGS` | | 插件标志,示例使用 `-emby,-aria2` 来关闭插件 | | `PLUGIN_FLAGS` | | 插件标志,`-emby,-aria2` 禁用某些插件 |
#### 一键更新 #### 一键更新

View File

@ -15,8 +15,10 @@ from flask import (
from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.cron import CronTrigger
import subprocess import subprocess
import requests
import hashlib import hashlib
import logging import logging
import base64
import json import json
import sys import sys
import os import os
@ -139,7 +141,9 @@ def logout():
def index(): def index():
if not is_login(): if not is_login():
return redirect(url_for("login")) return redirect(url_for("login"))
return render_template("index.html", version=app.config["APP_VERSION"], plugin_flags=PLUGIN_FLAGS) return render_template(
"index.html", version=app.config["APP_VERSION"], plugin_flags=PLUGIN_FLAGS
)
# 获取配置数据 # 获取配置数据
@ -212,6 +216,21 @@ def run_script_now():
) )
@app.route("/task_suggestions")
def get_task_suggestions():
if not is_login():
return jsonify({"error": "未登录"})
base_url = base64.b64decode("aHR0cHM6Ly9zLjkxNzc4OC54eXo=").decode()
query = request.args.get("q", "").lower()
deep = request.args.get("d", "").lower()
url = f"{base_url}/task_suggestions?q={query}&d={deep}"
try:
response = requests.get(url)
return jsonify(response.json())
except Exception as e:
return jsonify({"error": str(e)})
@app.route("/get_share_detail") @app.route("/get_share_detail")
def get_share_files(): def get_share_files():
if not is_login(): if not is_login():

View File

@ -36,6 +36,16 @@
max-height: calc(100vh - 200px); max-height: calc(100vh - 200px);
overflow-y: auto; overflow-y: auto;
} }
.task-suggestions {
width: 100%;
max-height: 500px;
overflow-y: auto;
transform: translate(0, -100%);
top: 0;
margin-top: -5px;
border: 1px solid #007bff;
}
</style> </style>
</head> </head>
@ -176,10 +186,23 @@
<label class="col-sm-2 col-form-label">任务名称</label> <label class="col-sm-2 col-form-label">任务名称</label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="input-group"> <div class="input-group">
<input type="text" name="taskname[]" class="form-control" v-model="task.taskname" placeholder="必填"> <input type="text" name="taskname[]" class="form-control" v-model="task.taskname" placeholder="必填" @focus="smart_param.showSuggestions=true;focusTaskname(index, task)" @input="changeTaskname(index, task)">
<div class="input-group-append" v-if="task.taskname"> <div class="dropdown-menu show task-suggestions" v-if="smart_param.showSuggestions && smart_param.taskSuggestions.length && smart_param.index === index">
<div class="input-group-text"> <div class="text-muted text-center" style="font-size: small;">以下资源来自第三方,网络公开搜集,请自行辨识,如有侵权请联系夸克官方</div>
<a target="_blank" :href="`https://www.google.com/search?q=%22pan.quark%22+${task.taskname}`"><i class="bi bi-search"></i></a> <div v-for="suggestion in smart_param.taskSuggestions" :key="suggestion.taskname" class="dropdown-item" @click.prevent="selectSuggestion(task, suggestion)" style="cursor: pointer;">
<span v-html="suggestion.verify ? '✅': '❔'"></span> {{ suggestion.taskname }}
<small class="text-muted">
<a :href="suggestion.shareurl" target="_blank" @click.stop>{{ suggestion.shareurl }}</a>
</small>
</div>
</div>
<div class="input-group-append" title="深度搜索">
<button class="btn btn-primary" type="button" @click="searchSuggestions(index, task.taskname)">
<i v-if="smart_param.isSearching && smart_param.index === index" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></i>
<i v-else class="bi bi-search-heart"></i>
</button>
<div class="input-group-text" title="谷歌搜索">
<a target="_blank" :href="`https://www.google.com/search?q=%22pan.quark.cn/s%22+${task.taskname}`"><i class="bi bi-google"></i></a>
</div> </div>
</div> </div>
</div> </div>
@ -202,8 +225,10 @@
<label class="col-sm-2 col-form-label">保存路径</label> <label class="col-sm-2 col-form-label">保存路径</label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="input-group"> <div class="input-group">
<input type="text" name="savepath[]" class="form-control" v-model="task.savepath" placeholder="必填"> <input type="text" name="savepath[]" class="form-control" v-model="task.savepath" placeholder="必填" @focus="focusTaskname(index, task)">
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-secondary" type="button" v-if="smart_param.savepath && smart_param.index == index && task.savepath != smart_param.origin_savepath" @click="task.savepath = smart_param.origin_savepath"><i class="
bi bi-reply"></i></button>
<button class="btn btn-outline-secondary dropdown-toggle" type="button" @click="getSavepathDirs(task.savepath)" data-toggle="dropdown" aria-expanded="false">选择</button> <button class="btn btn-outline-secondary dropdown-toggle" type="button" @click="getSavepathDirs(task.savepath)" data-toggle="dropdown" aria-expanded="false">选择</button>
<div class="dropdown-menu" style="max-height: 300px; overflow-y: auto;"> <div class="dropdown-menu" style="max-height: 300px; overflow-y: auto;">
<a class="dropdown-item" @click.stop.prevent="selectSavepath(index,getParentDirectory(task.savepath),'..')" href="#">..</a> <a class="dropdown-item" @click.stop.prevent="selectSavepath(index,getParentDirectory(task.savepath),'..')" href="#">..</a>
@ -391,7 +416,7 @@
newTask: { newTask: {
taskname: "", taskname: "",
shareurl: "", shareurl: "",
savepath: "", savepath: "/",
pattern: "", pattern: "",
replace: "", replace: "",
enddate: "", enddate: "",
@ -406,7 +431,16 @@
savepaths: [], savepaths: [],
modalLoading: false, modalLoading: false,
shareFiles: [], shareFiles: [],
forceTaskIndex: null forceTaskIndex: null,
smart_param: {
index: null,
savepath: "",
origin_savepath: "",
taskSuggestions: [],
showSuggestions: false,
lastSuggestionsTime: 0,
isSearching: false,
},
}, },
filters: { filters: {
ts2date: function (value) { ts2date: function (value) {
@ -429,6 +463,11 @@
this.checkNewVersion(); this.checkNewVersion();
$('[data-toggle="tooltip"]').tooltip(); $('[data-toggle="tooltip"]').tooltip();
document.addEventListener('keydown', this.handleKeyDown); document.addEventListener('keydown', this.handleKeyDown);
document.addEventListener('click', (e) => {
if (!e.target.closest('.input-group')) {
this.smart_param.showSuggestions = false;
}
});
}, },
methods: { methods: {
checkNewVersion() { checkNewVersion() {
@ -510,12 +549,18 @@
}, },
addTask() { addTask() {
newTask = { ...this.newTask } newTask = { ...this.newTask }
newTask.taskname = this.taskNameFilter newTask.taskname = this.taskNameFilter;
lastTask = this.formData.tasklist[this.formData.tasklist.length - 1] if (this.formData.tasklist.length > 0) {
if (this.formData.tasklist.length > 0 && lastTask.taskname) { lastTask = this.formData.tasklist[this.formData.tasklist.length - 1];
newTask.savepath = lastTask.savepath.replace(lastTask.taskname, 'TASKNAME') if (this.taskDirSelected) {
} else { newTask.savepath = this.taskDirSelected + '/TASKNAME';
newTask.savepath = this.taskDirSelected + "/" + newTask.taskname } else {
if (newTask.taskname) {
newTask.savepath = lastTask.savepath.replace(lastTask.taskname, newTask.taskname);
} else {
newTask.savepath = lastTask.taskname ? lastTask.savepath.replace(lastTask.taskname, 'TASKNAME') : lastTask.savepath;
}
}
} }
this.formData.tasklist.push(newTask); this.formData.tasklist.push(newTask);
// 滚到最下 // 滚到最下
@ -525,6 +570,23 @@
}); });
}, 1); }, 1);
}, },
focusTaskname(index, task) {
this.smart_param.index = index
this.smart_param.origin_savepath = task.savepath
regex = new RegExp(`/${task.taskname.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(/|$)`)
if (task.savepath.includes('TASKNAME')) {
this.smart_param.savepath = task.savepath;
} else if (task.savepath.match(regex)) {
this.smart_param.savepath = task.savepath.replace(task.taskname, 'TASKNAME');
} else {
this.smart_param.savepath = undefined;
}
},
changeTaskname(index, task) {
this.searchSuggestions(index, task.taskname, 500);
if (this.smart_param.savepath)
task.savepath = this.smart_param.savepath.replace('TASKNAME', task.taskname);
},
removeTask(index) { removeTask(index) {
if (confirm("确认删除任务 [#" + (index + 1) + ": " + this.formData.tasklist[index].taskname + "] 吗?")) if (confirm("确认删除任务 [#" + (index + 1) + ": " + this.formData.tasklist[index].taskname + "] 吗?"))
this.formData.tasklist.splice(index, 1); this.formData.tasklist.splice(index, 1);
@ -665,7 +727,38 @@
} else { } else {
task.runweek = [1, 2, 3, 4, 5, 6, 7]; task.runweek = [1, 2, 3, 4, 5, 6, 7];
} }
} },
searchSuggestions(index, taskname, limit_msec = 0) {
if (taskname.length == 0)
return
if (limit_msec > 0) {
const now = Date.now();
if (now - this.smart_param.lastSuggestionsTime < limit_msec)
return;
this.smart_param.lastSuggestionsTime = now;
}
this.smart_param.isSearching = true
this.smart_param.index = index;
axios.get('/task_suggestions', {
params: {
q: taskname,
d: limit_msec == 0 ? 1 : 0
}
}).then(response => {
this.smart_param.taskSuggestions = response.data;
this.smart_param.showSuggestions = true;
}).catch(error => {
console.error('Error fetching suggestions:', error);
}).finally(() => {
this.smart_param.isSearching = false;
});
},
selectSuggestion(task, suggestion) {
task.taskname = suggestion.taskname;
task.shareurl = suggestion.shareurl;
this.changeShareurl(task);
this.smart_param.showSuggestions = false;
},
} }
}); });
</script> </script>