mirror of
https://github.com/Cp0204/quark-auto-save.git
synced 2026-01-15 17:00:43 +08:00
Update run.py
为旧版本用户更新配置。添
This commit is contained in:
parent
2dc1eacd77
commit
5bf8dc1655
281
app/run.py
281
app/run.py
@ -1,4 +1,4 @@
|
||||
# !/usr/bin/env python3
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from flask import (
|
||||
json,
|
||||
@ -25,11 +25,22 @@ import base64
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import io
|
||||
import threading
|
||||
|
||||
parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
sys.path.insert(0, parent_dir)
|
||||
from quark_auto_save import Quark, Config, MagicRename
|
||||
|
||||
# 用于存储当前运行的日志
|
||||
current_log = io.StringIO()
|
||||
log_lock = threading.Lock()
|
||||
# 添加一个标志来跟踪任务是否正在运行
|
||||
task_running = False
|
||||
# 存储当前运行的进程
|
||||
current_process = None
|
||||
process_lock = threading.Lock()
|
||||
|
||||
|
||||
def get_app_ver():
|
||||
BUILD_SHA = os.environ.get("BUILD_SHA", "")
|
||||
@ -188,6 +199,27 @@ def run_script_now():
|
||||
f">>> 手动运行任务 [{tasklist[0].get('taskname') if len(tasklist)>0 else 'ALL'}] 开始执行..."
|
||||
)
|
||||
|
||||
# 清空当前日志
|
||||
with log_lock:
|
||||
current_log.seek(0)
|
||||
current_log.truncate(0)
|
||||
current_log.write("任务开始执行...\n")
|
||||
|
||||
# 设置任务运行状态
|
||||
global task_running, current_process
|
||||
task_running = True
|
||||
|
||||
# 确保之前的进程已经终止
|
||||
with process_lock:
|
||||
if current_process is not None:
|
||||
try:
|
||||
if current_process.poll() is None:
|
||||
current_process.terminate()
|
||||
current_process.wait(timeout=1)
|
||||
except Exception as e:
|
||||
logging.error(f"终止旧进程失败: {str(e)}")
|
||||
current_process = None
|
||||
|
||||
def generate_output():
|
||||
# 设置环境变量
|
||||
process_env = os.environ.copy()
|
||||
@ -202,24 +234,46 @@ def run_script_now():
|
||||
)
|
||||
if tasklist:
|
||||
process_env["TASKLIST"] = json.dumps(tasklist, ensure_ascii=False)
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
bufsize=1,
|
||||
env=process_env,
|
||||
)
|
||||
|
||||
# 创建进程并保存引用
|
||||
global current_process
|
||||
with process_lock:
|
||||
current_process = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
bufsize=1,
|
||||
env=process_env,
|
||||
)
|
||||
|
||||
try:
|
||||
for line in iter(process.stdout.readline, ""):
|
||||
for line in iter(current_process.stdout.readline, ""):
|
||||
logging.info(line.strip())
|
||||
# 将日志存储到全局变量中
|
||||
with log_lock:
|
||||
current_log.write(line)
|
||||
yield f"data: {line}\n\n"
|
||||
|
||||
# 检查进程退出状态
|
||||
exit_code = current_process.wait()
|
||||
if exit_code != 0:
|
||||
error_msg = f"任务异常结束,退出码: {exit_code}\n"
|
||||
logging.error(error_msg)
|
||||
with log_lock:
|
||||
current_log.write(error_msg)
|
||||
yield f"data: {error_msg}\n\n"
|
||||
|
||||
yield "data: [DONE]\n\n"
|
||||
finally:
|
||||
process.stdout.close()
|
||||
process.wait()
|
||||
if current_process:
|
||||
if current_process.poll() is None:
|
||||
current_process.stdout.close()
|
||||
current_process.wait()
|
||||
# 检查进程状态
|
||||
check_process_status()
|
||||
|
||||
return Response(
|
||||
stream_with_context(generate_output()),
|
||||
@ -227,6 +281,54 @@ def run_script_now():
|
||||
)
|
||||
|
||||
|
||||
# 添加一个函数来检查进程状态
|
||||
def check_process_status():
|
||||
global task_running, current_process
|
||||
with process_lock:
|
||||
if current_process is not None:
|
||||
# 检查进程是否仍在运行
|
||||
poll_result = current_process.poll()
|
||||
if poll_result is None:
|
||||
# 进程仍在运行
|
||||
logging.debug(">>> 检查进程状态:进程仍在运行")
|
||||
task_running = True
|
||||
else:
|
||||
# 进程已结束,记录退出码
|
||||
if poll_result != 0:
|
||||
error_msg = f">>> 检查进程状态:进程异常结束,退出码 {poll_result}"
|
||||
logging.error(error_msg)
|
||||
# 将错误信息添加到日志中
|
||||
with log_lock:
|
||||
if not current_log.getvalue().endswith(
|
||||
f"任务异常结束,退出码: {poll_result}\n"
|
||||
):
|
||||
current_log.write(f"任务异常结束,退出码: {poll_result}\n")
|
||||
else:
|
||||
logging.info(f">>> 检查进程状态:进程正常结束,退出码 {poll_result}")
|
||||
task_running = False
|
||||
current_process = None
|
||||
else:
|
||||
if task_running:
|
||||
logging.info(">>> 检查进程状态:无进程引用但状态为运行中,重置状态")
|
||||
task_running = False
|
||||
else:
|
||||
logging.debug(">>> 检查进程状态:无进程运行")
|
||||
|
||||
|
||||
# 获取当前运行的日志
|
||||
@app.route("/get_current_log")
|
||||
def get_current_log():
|
||||
if not is_login():
|
||||
return jsonify({"success": False, "message": "未登录"})
|
||||
|
||||
# 检查进程状态
|
||||
check_process_status()
|
||||
|
||||
with log_lock:
|
||||
log_content = current_log.getvalue()
|
||||
return jsonify({"success": True, "log": log_content, "running": task_running})
|
||||
|
||||
|
||||
@app.route("/task_suggestions")
|
||||
def get_task_suggestions():
|
||||
if not is_login():
|
||||
@ -299,6 +401,7 @@ def get_share_detail():
|
||||
def preview_regex(data):
|
||||
task = request.json.get("task", {})
|
||||
magic_regex = request.json.get("magic_regex", {})
|
||||
global_regex = request.json.get("global_regex", {})
|
||||
mr = MagicRename(magic_regex)
|
||||
mr.set_taskname(task.get("taskname", ""))
|
||||
account = Quark(config_data["cookie"][0])
|
||||
@ -310,34 +413,64 @@ def get_share_detail():
|
||||
dir_file_list = []
|
||||
dir_filename_list = []
|
||||
|
||||
pattern, replace = mr.magic_regex_conv(
|
||||
# 获取全局正则和任务正则
|
||||
global_regex_enabled = global_regex.get("enabled", False)
|
||||
global_pattern = global_regex.get("pattern", "")
|
||||
global_replace = global_regex.get("replace", "")
|
||||
|
||||
task_pattern, task_replace = mr.magic_regex_conv(
|
||||
task.get("pattern", ""), task.get("replace", "")
|
||||
)
|
||||
|
||||
for share_file in data["list"]:
|
||||
search_pattern = (
|
||||
task["update_subdir"]
|
||||
if share_file["dir"] and task.get("update_subdir")
|
||||
else pattern
|
||||
)
|
||||
if re.search(search_pattern, share_file["file_name"]):
|
||||
# 文件名重命名,目录不重命名
|
||||
file_name_re = (
|
||||
share_file["file_name"]
|
||||
if share_file["dir"]
|
||||
else mr.sub(pattern, replace, share_file["file_name"])
|
||||
)
|
||||
if share_file["dir"]:
|
||||
search_pattern = task.get("update_subdir", "")
|
||||
if re.search(search_pattern, share_file["file_name"]):
|
||||
# 目录不进行重命名
|
||||
share_file["file_name_re"] = share_file["file_name"]
|
||||
continue
|
||||
|
||||
# 初始化重命名后的文件名为原始文件名
|
||||
renamed_name = share_file["file_name"]
|
||||
applied_global_regex = False
|
||||
applied_task_regex = False
|
||||
|
||||
# 应用全局正则(如果启用)
|
||||
if global_regex_enabled and global_pattern:
|
||||
if re.search(global_pattern, renamed_name):
|
||||
global_renamed_name = re.sub(
|
||||
global_pattern, global_replace, renamed_name
|
||||
)
|
||||
renamed_name = global_renamed_name
|
||||
applied_global_regex = True
|
||||
|
||||
# 应用任务正则(如果存在)
|
||||
if task_pattern:
|
||||
if re.search(task_pattern, renamed_name):
|
||||
task_renamed_name = mr.sub(task_pattern, task_replace, renamed_name)
|
||||
renamed_name = task_renamed_name
|
||||
applied_task_regex = True
|
||||
|
||||
# 检查是否应用了任何正则
|
||||
if applied_global_regex or applied_task_regex:
|
||||
if file_name_saved := mr.is_exists(
|
||||
file_name_re,
|
||||
renamed_name,
|
||||
dir_filename_list,
|
||||
(task.get("ignore_extension") and not share_file["dir"]),
|
||||
):
|
||||
share_file["file_name_saved"] = file_name_saved
|
||||
else:
|
||||
share_file["file_name_re"] = file_name_re
|
||||
share_file["file_name_re"] = renamed_name
|
||||
|
||||
# 文件列表排序
|
||||
if re.search(r"\{I+\}", replace):
|
||||
mr.set_dir_file_list(dir_file_list, replace)
|
||||
replace_for_i = ""
|
||||
if task.get("replace"):
|
||||
replace_for_i = task_replace
|
||||
elif global_regex_enabled and global_replace:
|
||||
replace_for_i = global_replace
|
||||
|
||||
if replace_for_i and re.search(r"\{I+\}", replace_for_i):
|
||||
mr.set_dir_file_list(dir_file_list, replace_for_i)
|
||||
mr.sort_file_list(data["list"])
|
||||
|
||||
if request.json.get("task"):
|
||||
@ -375,8 +508,9 @@ def get_savepath_detail():
|
||||
return jsonify({"success": False, "data": {"error": "获取fid失败"}})
|
||||
else:
|
||||
fid = request.args.get("fid", "0")
|
||||
|
||||
file_list = {
|
||||
"list": account.ls_dir(fid)["data"]["list"],
|
||||
"list": account.ls_dir(fid),
|
||||
"paths": paths,
|
||||
}
|
||||
return jsonify({"success": True, "data": file_list})
|
||||
@ -471,8 +605,57 @@ def init():
|
||||
# 读取配置
|
||||
config_data = Config.read_json(CONFIG_PATH)
|
||||
Config.breaking_change_update(config_data)
|
||||
|
||||
# --- 开始进行配置项向后兼容更新 ---
|
||||
|
||||
# 1. 确保 magic_regex 存在
|
||||
if not config_data.get("magic_regex"):
|
||||
config_data["magic_regex"] = MagicRename().magic_regex
|
||||
logging.info("配置升级:已补全 'magic_regex' 默认配置。")
|
||||
|
||||
# 2. 确保 global_regex 存在
|
||||
if not config_data.get("global_regex"):
|
||||
config_data["global_regex"] = {"enabled": False, "pattern": "", "replace": ""}
|
||||
logging.info("配置升级:已补全 'global_regex' 默认配置。")
|
||||
|
||||
# 3. 确保 file_blacklist 存在
|
||||
if "file_blacklist" not in config_data:
|
||||
config_data["file_blacklist"] = []
|
||||
logging.info("配置升级:已补全 'file_blacklist' 默认配置。")
|
||||
|
||||
# 4. 确保 source 存在
|
||||
if "source" not in config_data:
|
||||
config_data["source"] = {
|
||||
"cloudsaver": {"server": "", "username": "", "password": "", "token": ""}
|
||||
}
|
||||
logging.info("配置升级:已补全 'source' 默认配置。")
|
||||
|
||||
# 5. 确保 shortcuts 及其所有子项存在
|
||||
if "shortcuts" not in config_data:
|
||||
config_data["shortcuts"] = {
|
||||
"saveEnabled": True,
|
||||
"runEnabled": False,
|
||||
"autoSaveEnabled": True,
|
||||
}
|
||||
logging.info("配置升级:已补全 'shortcuts' 默认配置。")
|
||||
else:
|
||||
if "saveEnabled" not in config_data["shortcuts"]:
|
||||
config_data["shortcuts"]["saveEnabled"] = True
|
||||
if "runEnabled" not in config_data["shortcuts"]:
|
||||
config_data["shortcuts"]["runEnabled"] = False
|
||||
if "autoSaveEnabled" not in config_data["shortcuts"]:
|
||||
config_data["shortcuts"]["autoSaveEnabled"] = True
|
||||
logging.info("配置升级:为 'shortcuts' 已补全 'autoSaveEnabled' 子项。")
|
||||
|
||||
# 6. 确保 tasklist 中每个任务都包含新参数 (例如 ignore_extension)
|
||||
if config_data.get("tasklist") and isinstance(config_data["tasklist"], list):
|
||||
for task in config_data["tasklist"]:
|
||||
if "ignore_extension" not in task:
|
||||
task["ignore_extension"] = False
|
||||
if "addition" not in task:
|
||||
task["addition"] = {}
|
||||
|
||||
# --- 配置项向后兼容更新结束 ---
|
||||
|
||||
# 默认管理账号
|
||||
config_data["webui"] = {
|
||||
@ -491,10 +674,42 @@ def init():
|
||||
plugins_config_default.update(config_data.get("plugins", {}))
|
||||
config_data["plugins"] = plugins_config_default
|
||||
|
||||
# 更新配置
|
||||
# 更新配置,将所有补全的默认值写回文件
|
||||
Config.write_json(CONFIG_PATH, config_data)
|
||||
|
||||
|
||||
# 添加一个重置任务状态的路由
|
||||
@app.route("/reset_task_status", methods=["POST"])
|
||||
def reset_task_status():
|
||||
if not is_login():
|
||||
return jsonify({"success": False, "message": "未登录"})
|
||||
|
||||
global task_running, current_process
|
||||
|
||||
# 如果有正在运行的进程,尝试终止它
|
||||
with process_lock:
|
||||
if current_process is not None:
|
||||
try:
|
||||
if current_process.poll() is None: # 进程仍在运行
|
||||
current_process.terminate()
|
||||
current_process.wait(timeout=5) # 等待最多5秒
|
||||
current_process = None
|
||||
except Exception as e:
|
||||
logging.error(f"终止进程失败: {str(e)}")
|
||||
|
||||
# 重置任务状态
|
||||
task_running = False
|
||||
|
||||
# 清空日志
|
||||
with log_lock:
|
||||
current_log.seek(0)
|
||||
current_log.truncate(0)
|
||||
current_log.write("任务状态已重置\n")
|
||||
|
||||
logging.info(">>> 任务状态已手动重置")
|
||||
return jsonify({"success": True, "message": "任务状态已重置"})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
init()
|
||||
reload_tasks()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user