Repository: DuckDuckStudio/Fufu_Tools
Pull request #185: feat: 还原之前另存的配置文件
Author: login: DuckDuckStudio
Labels: name: DEV-测试通过
description: 通过测试
name: DEV-开发分支合并
description: 开发分支的合并PR
Created: 2025-03-08T05:16:40Z | Merged: 2025-03-08T10:24:25Z

### 检查清单
- [x] 有链接Issue吗? -- Related #184 <!--←如有请在这里填写具体链接的议题，例如 #114-->
- [x] 你检查过没有其他重复的 [拉取请求](https://github.com/DuckDuckStudio/Fufu_Tools/pulls) 吗?
- [x] 此拉取请求仅针对一个问题/功能吗?
- [ ] 你在本地验证过你的修改吗? - WIP
- [ ] 你确定你的描述足以让开发人员理解你的意图以及解决方案?

### 修改说明

<!--在这里尽可能详细的描述你做的修改，以便开发人员审查你的修改。-->



Diff:
diff --git "a/src/config/\345\244\207\344\273\275.py" "b/src/config/\345\244\207\344\273\275.py"
new file mode 100644
index 0000000..15a218b
--- /dev/null
+++ "b/src/config/\345\244\207\344\273\275.py"
@@ -0,0 +1,86 @@
+import os
+import sys
+import shutil
+import tkinter as tk
+from tkinter import filedialog
+from tkinter import messagebox
+from colorama import init, Fore
+
+def 选择目标文件夹():
+    while True:
+        root = tk.Tk()
+        root.withdraw() # 隐藏主窗口
+
+        目标文件夹 = filedialog.askdirectory(title="你要将配置文件备份到哪里？")
+
+        if 检查文件夹(目标文件夹):
+            return 目标文件夹
+
+def 检查文件夹(目标文件夹):
+    # 检测是否选择了文件夹
+    if not 目标文件夹:
+        # 当用户点击选择文件窗口的“取消”按钮时
+        messagebox.showerror("错误", "未选择文件夹，操作取消。")
+        sys.exit(3)
+        # return False
+    # 检查目标文件夹是否存在，如果不存在则创建
+    if not os.path.exists(目标文件夹):
+        messagebox.showwarning("警告", "目标文件夹不存在，将新建一个同名文件夹。")
+        os.makedirs(目标文件夹)
+    # 检查目标文件夹是否为空
+    if len(os.listdir(目标文件夹)) != 0:
+        messagebox.showerror("错误", "目标文件夹不为空，请选择一个空文件夹。")
+        return False
+    return True # 一切正常
+
+def 复制配置文件(目标文件夹):
+    # 获取当前运行脚本的文件夹路径的上级目录作为源文件夹
+    当前文件夹 = os.path.dirname(os.path.abspath(sys.argv[0]))
+    源文件夹 = os.path.dirname(当前文件夹)
+
+    已复制的文件 = [] # 用于存储已经复制的文件路径
+
+    try:
+        # 遍历源文件夹中的所有文件和子文件夹
+        for root, dirs, files in os.walk(源文件夹):
+            for file in files:
+                if file == 'config.ini':
+                    源路径 = os.path.join(root, file)
+                    if root == 源文件夹:
+                        # 忽略源文件夹中的 config.ini
+                        continue
+                    目标路径 = os.path.join(目标文件夹, os.path.relpath(源路径, 源文件夹))
+                    目标目录 = os.path.dirname(目标路径)
+
+                    # 创建目标文件夹中的子文件夹（如果需要）
+                    if not os.path.exists(目标目录):
+                        os.makedirs(目标目录)
+                    
+                    # 复制文件
+                    shutil.copyfile(源路径, 目标路径)
+                    已复制的文件.append(目标路径) # 记录已复制的文件
+
+        # 如果成功完成所有文件复制
+        messagebox.showinfo("恭喜", "配置文件备份成功！")
+    except KeyboardInterrupt:
+        # 用户按下 Ctrl+C 取消操作
+        messagebox.showerror("错误", "用户已取消操作。")
+        
+        for file_path in 已复制的文件:
+            os.remove(file_path) # 删除已复制的文件
+    except Exception as e:
+        # 出现异常时取消操作并清空已复制的文件
+        messagebox.showerror("错误", f"备份过程中出现错误:\n{e}")
+
+        for file_path in 已复制的文件:
+            os.remove(file_path) # 删除已复制的文件
+
+
+def main():
+    init(autoreset=True)
+    # 让用户选择目标文件夹
+    目标文件夹 = 选择目标文件夹()
+    复制配置文件(目标文件夹)
+
+if __name__ == "__main__":
+    main()
diff --git "a/src/config/\350\277\230\345\216\237.py" "b/src/config/\350\277\230\345\216\237.py"
new file mode 100644
index 0000000..ba7c42e
--- /dev/null
+++ "b/src/config/\350\277\230\345\216\237.py"
@@ -0,0 +1,88 @@
+import os
+import sys
+import configparser
+import tkinter as tk
+from tkinter import filedialog
+from tkinter import messagebox
+from colorama import init, Fore
+import shutil
+
+def 选择备份文件夹():
+    root = tk.Tk()
+    root.withdraw()
+    备份文件夹 = filedialog.askdirectory(title="你之前将配置文件备份到了哪里？")
+    if not os.path.exists(备份文件夹):
+        messagebox.showerror("错误", "备份文件夹不存在")
+    return 备份文件夹
+
+def 比较配置文件键(文件1, 文件2):
+    config1 = configparser.ConfigParser()
+    config2 = configparser.ConfigParser()
+    
+    try:
+        config1.read(文件1)
+        config2.read(文件2)
+    except Exception as e:
+        return False, f"配置文件解析失败: {str(e)}"
+
+    # 比较所有节
+    sections1 = set(config1.sections())
+    sections2 = set(config2.sections())
+    if sections1 != sections2:
+        return False, f"节不一致: 备份文件节={sections1}，目标文件节={sections2}"
+
+    # 比较每个节内的键
+    for section in sections1:
+        keys1 = set(config1[section].keys())
+        keys2 = set(config2[section].keys())
+        if keys1 != keys2:
+            return False, f"节 [{section}] 中: 备份文件键={keys1}，目标文件键={keys2}"
+
+    return True, "键完全一致"
+
+def 还原配置文件(备份文件夹, 目标根目录):
+    init(autoreset=True)
+    已处理文件 = 0
+    跳过文件 = 0
+
+    for root, dirs, files in os.walk(备份文件夹):
+        for file in files:
+            if file == 'config.ini':
+                备份路径 = os.path.join(root, file)
+                相对路径 = os.path.relpath(备份路径, 备份文件夹)
+                目标路径 = os.path.join(目标根目录, 相对路径)
+
+                # 检查目标文件是否存在
+                if not os.path.exists(目标路径):
+                    messagebox.showwarning("警告", f"您使用的版本中不存在配置文件 {相对路径}，跳过还原。")
+                    跳过文件 += 1
+                    continue
+
+                # 比较键
+                键一致, 信息 = 比较配置文件键(备份路径, 目标路径)
+                if not 键一致:
+                    messagebox.showwarning("警告", f"您使用的版本中的配置文件 {相对路径} 与您备份的配置文件的键不一致，跳过还原。\n{信息}")
+                    跳过文件 += 1
+                    continue
+
+                # 覆盖文件
+                try:
+                    shutil.copyfile(备份路径, 目标路径)
+                    已处理文件 += 1
+                except Exception as e:
+                    messagebox.showerror("错误", f"还原配置文件 {相对路径} 失败:\n{str(e)}")
+                    跳过文件 += 1
+
+    messagebox.showinfo("恭喜", f"成功还原配置文件！\n我们一共成功还原了 {已处理文件} 个配置文件，跳过了 {跳过文件} 个配置文件。")
+
+def main():
+    init(autoreset=True)
+    备份文件夹 = 选择备份文件夹()
+    
+    脚本路径 = os.path.abspath(sys.argv[0])
+    目标根目录 = os.path.dirname(os.path.dirname(脚本路径))
+
+    还原配置文件(备份文件夹, 目标根目录)
+
+if __name__ == "__main__":
+    main()
diff --git a/src/temporarily/config-save.py b/src/temporarily/config-save.py
deleted file mode 100644
index 41b2300..0000000
--- a/src/temporarily/config-save.py
+++ /dev/null
@@ -1,98 +0,0 @@
-import os
-import sys
-import shutil
-import tkinter as tk
-from tkinter import filedialog
-from colorama import init, Fore
-
-init(autoreset=True)
-
-def select_destination_folder():
-    print("请选择保存到的文件夹:", end=" ")
-
-    root = tk.Tk()
-    root.withdraw()  # 隐藏主窗口
-
-    destination_folder = filedialog.askdirectory()
-
-    print(f"{Fore.GREEN}\r✓{Fore.RESET} 已选择保存到的文件夹: {Fore.BLUE}{destination_folder}", end=" ")
-    return destination_folder
-
-def check_folder(destination_folder):
-    # 检测是否选择了文件夹
-    if destination_folder == "":
-        print(f"\r{Fore.RED}✕{Fore.RESET} 未选择文件夹，请先选择一个输出位置。")
-        return False
-    # 检查目标文件夹是否存在，如果不存在则创建
-    if not os.path.exists(destination_folder):
-        print(f"\n{Fore.YELLOW}⚠ 目标文件夹不存在，将新建一个同名文件夹。", end=" ")
-        os.makedirs(destination_folder)
-    # 检查目标文件夹是否为空
-    if len(os.listdir(destination_folder)) != 0:
-        print(f"\r{Fore.RED}✕ 错误的目标文件夹: {Fore.BLUE}{destination_folder}\n{Fore.YELLOW}  原因：目标文件夹不为空。")
-        return False
-
-    print(f"{Fore.GREEN}\r✓{Fore.RESET} 已选择保存到的文件夹: {Fore.BLUE}{destination_folder}")# 刷新，避免被顶掉
-    return True # 一切正常
-
-def copy_config_files(destination_folder):
-    # 获取当前运行脚本的文件夹路径的上级目录作为源文件夹
-    current_folder = os.path.dirname(os.path.abspath(os.path.abspath(sys.argv[0])))
-    source_folder = os.path.dirname(current_folder)
-
-    copied_files = []  # 用于存储已经复制的文件路径
-
-    try:
-        # 遍历源文件夹中的所有文件和子文件夹
-        for root, dirs, files in os.walk(source_folder):
-            for file in files:
-                if file == 'config.ini':
-                    source_path = os.path.join(root, file)
-                    relative_path = os.path.relpath(source_path, source_folder)
-                    if root == source_folder:
-                        print(f"{Fore.BLUE}[!]{Fore.RESET} 忽略版本配置文件。")
-                        continue  # 忽略源文件夹中的config.ini
-                    destination_path = os.path.join(destination_folder, relative_path)
-                    destination_dir = os.path.dirname(destination_path)
-
-                    # 创建目标文件夹中的子文件夹（如果需要）
-                    if not os.path.exists(destination_dir):
-                        os.makedirs(destination_dir)
-                    
-                    # 复制文件
-                    shutil.copyfile(source_path, destination_path)
-                    copied_files.append(destination_path)  # 记录已复制的文件
-                    print(f"已复制配置文件 {Fore.BLUE} {source_path} {Fore.RESET} 到 {Fore.BLUE} {destination_path} {Fore.RESET}。")
-
-        # 如果成功完成所有文件复制，则打印成功消息
-        print(f"{Fore.GREEN}✓{Fore.RESET} 已保存配置文件到 {Fore.BLUE} {destination_folder} {Fore.RESET} 中，下次更新可以直接替换配置文件！")
-
-    except KeyboardInterrupt:
-        # 用户按下 Ctrl+C 取消操作
-        print(f"{Fore.RED}✕{Fore.RESET} 用户取消操作.")
-        
-        for file_path in copied_files:
-            os.remove(file_path)  # 删除已复制的文件
-        
-        print(f"{Fore.RED}✕{Fore.RESET} 操作已取消。")
-
-    except Exception as e:
-        # 出现异常时取消操作并清空已复制的文件
-        print(f"\n{Fore.RED}✕{Fore.RESET} 复制文件时发生错误: {str(e)}")
-        
-        for file_path in copied_files:
-            os.remove(file_path)  # 删除已复制的文件
-        
-        print(f"{Fore.RED}✕{Fore.RESET} 出现错误，操作取消.")
-
-
-# 让用户选择目标文件夹
-destination_folder = select_destination_folder()
-
-if check_folder(destination_folder):
-    # 调用函数复制config.ini文件
-    copy_config_files(destination_folder)
-else:
-    print(f"{Fore.RED}\r✕{Fore.RESET} 出现错误，操作取消.")
-
-input("按Enter键继续...")
diff --git "a/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261(for\345\256\211\350\243\205\347\250\213\345\272\217).pyw" "b/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261(for\345\256\211\350\243\205\347\250\213\345\272\217).pyw"
index 1bb06ea..245f10b 100644
--- "a/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261(for\345\256\211\350\243\205\347\250\213\345\272\217).pyw"
+++ "b/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261(for\345\256\211\350\243\205\347\250\213\345\272\217).pyw"
@@ -219,7 +219,8 @@ categories = {
     },
     "关于芙芙工具箱": {
         "检查版本": ".\\Show_version.exe",
-        "另存配置文件": ".\\temporarily\\config-save.exe",
+        "备份配置": ".\\config\\备份.exe",
+        "还原配置": ".\\config\\还原.exe",
         "安装文件夹": os.getcwd(),
         "程序文档": "https://duckduckstudio.github.io/yazicbs.github.io/Tools/Fufu_Tools/wiki/",
         "程序官网": "https://duckduckstudio.github.io/yazicbs.github.io/Tools/Fufu_Tools/",
diff --git "a/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261(for\346\211\223\345\214\205).pyw" "b/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261(for\346\211\223\345\214\205).pyw"
index ea39d24..dd73bea 100644
--- "a/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261(for\346\211\223\345\214\205).pyw"
+++ "b/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261(for\346\211\223\345\214\205).pyw"
@@ -230,7 +230,8 @@ categories = {
     "关于芙芙工具箱": {
         "检查版本": ".\\Show_version.exe",
         "修改开始菜单图标": "link",
-        "另存配置文件": ".\\temporarily\\config-save.exe",
+        "备份配置": ".\\config\\备份.exe",
+        "还原配置": ".\\config\\还原.exe",
         "安装文件夹": os.getcwd(),
         "程序文档": "https://duckduckstudio.github.io/yazicbs.github.io/Tools/Fufu_Tools/wiki/",
         "程序官网": "https://duckduckstudio.github.io/yazicbs.github.io/Tools/Fufu_Tools/",
diff --git "a/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261.pyw" "b/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261.pyw"
index fe2de5d..0b546ef 100644
--- "a/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261.pyw"
+++ "b/src/\350\212\231\350\212\231\345\267\245\345\205\267\347\256\261.pyw"
@@ -233,7 +233,8 @@ categories = {
     "关于芙芙工具箱": {
         "检查版本": ".\\Show_version.py",
         "修改开始菜单图标": "link",
-        "另存配置文件": ".\\temporarily\\config-save.py",
+        "备份配置": ".\\config\\备份.py",
+        "还原配置": ".\\config\\还原.py",
         "安装文件夹": os.path.dirname(os.path.abspath(__file__)),
         "程序文档": "https://duckduckstudio.github.io/yazicbs.github.io/Tools/Fufu_Tools/wiki/",
         "程序官网": "https://duckduckstudio.github.io/yazicbs.github.io/Tools/Fufu_Tools/",


Reviews:
user: login: fjwxzde
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-08T10:20:45Z
user: login: fjwxzde
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-08T10:22:19Z
user: login: Luna-Grace
body: TL;DR
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-08T10:24:24Z

Review comments:
diff_hunk: @@ -0,0 +1,86 @@
+import os
+import sys
+import shutil
+import tkinter as tk
+from tkinter import filedialog
+from tkinter import messagebox
+from colorama import init, Fore
+
+def 选择目标文件夹():
+    while True:
+        root = tk.Tk()
+        root.withdraw() # 隐藏主窗口
+
+        目标文件夹 = filedialog.askdirectory(title="你要将配置文件备份到哪里？")
+
+        if 检查文件夹(目标文件夹):
+            return 目标文件夹
+
+def 检查文件夹(目标文件夹):
+    # 检测是否选择了文件夹
+    if not 目标文件夹:
+        # 当用户点击选择文件窗口的“取消”按钮时
+        messagebox.showerror("错误", "未选择文件夹，操作取消。")
+        sys.exit(3)
+        # return False
+    # 检查目标文件夹是否存在，如果不存在则创建
+    if not os.path.exists(目标文件夹):
+        messagebox.showwarning("警告", "目标文件夹不存在，将新建一个同名文件夹。")
+        os.makedirs(目标文件夹)
+    # 检查目标文件夹是否为空
+    if len(os.listdir(目标文件夹)) != 0:
+        messagebox.showerror("错误", "目标文件夹不为空，请选择一个空文件夹。")
+        return False
+    return True # 一切正常
+
+def 复制配置文件(目标文件夹):
+    # 获取当前运行脚本的文件夹路径的上级目录作为源文件夹
+    当前文件夹 = os.path.dirname(os.path.abspath(sys.argv[0]))
+    源文件夹 = os.path.dirname(当前文件夹)
+
+    已复制的文件 = []  # 用于存储已经复制的文件路径
path: src/config/备份.py
user: login: fjwxzde
body: ```suggestion
    已复制的文件 = [] # 用于存储已经复制的文件路径
```
created_at: 2025-03-08T10:20:00Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,86 @@
+import os
+import sys
+import shutil
+import tkinter as tk
+from tkinter import filedialog
+from tkinter import messagebox
+from colorama import init, Fore
+
+def 选择目标文件夹():
+    while True:
+        root = tk.Tk()
+        root.withdraw() # 隐藏主窗口
+
+        目标文件夹 = filedialog.askdirectory(title="你要将配置文件备份到哪里？")
+
+        if 检查文件夹(目标文件夹):
+            return 目标文件夹
+
+def 检查文件夹(目标文件夹):
+    # 检测是否选择了文件夹
+    if not 目标文件夹:
+        # 当用户点击选择文件窗口的“取消”按钮时
+        messagebox.showerror("错误", "未选择文件夹，操作取消。")
+        sys.exit(3)
+        # return False
+    # 检查目标文件夹是否存在，如果不存在则创建
+    if not os.path.exists(目标文件夹):
+        messagebox.showwarning("警告", "目标文件夹不存在，将新建一个同名文件夹。")
+        os.makedirs(目标文件夹)
+    # 检查目标文件夹是否为空
+    if len(os.listdir(目标文件夹)) != 0:
+        messagebox.showerror("错误", "目标文件夹不为空，请选择一个空文件夹。")
+        return False
+    return True # 一切正常
+
+def 复制配置文件(目标文件夹):
+    # 获取当前运行脚本的文件夹路径的上级目录作为源文件夹
+    当前文件夹 = os.path.dirname(os.path.abspath(sys.argv[0]))
+    源文件夹 = os.path.dirname(当前文件夹)
+
+    已复制的文件 = []  # 用于存储已经复制的文件路径
+
+    try:
+        # 遍历源文件夹中的所有文件和子文件夹
+        for root, dirs, files in os.walk(源文件夹):
+            for file in files:
+                if file == 'config.ini':
+                    源路径 = os.path.join(root, file)
+                    if root == 源文件夹:
+                        # 忽略源文件夹中的 config.ini
+                        continue
+                    目标路径 = os.path.join(目标文件夹, os.path.relpath(源路径, 源文件夹))
+                    目标目录 = os.path.dirname(目标路径)
+
+                    # 创建目标文件夹中的子文件夹（如果需要）
+                    if not os.path.exists(目标目录):
+                        os.makedirs(目标目录)
+                    
+                    # 复制文件
+                    shutil.copyfile(源路径, 目标路径)
+                    已复制的文件.append(目标路径)  # 记录已复制的文件
path: src/config/备份.py
user: login: fjwxzde
body: ```suggestion
                    已复制的文件.append(目标路径) # 记录已复制的文件
```
created_at: 2025-03-08T10:20:17Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,86 @@
+import os
+import sys
+import shutil
+import tkinter as tk
+from tkinter import filedialog
+from tkinter import messagebox
+from colorama import init, Fore
+
+def 选择目标文件夹():
+    while True:
+        root = tk.Tk()
+        root.withdraw() # 隐藏主窗口
+
+        目标文件夹 = filedialog.askdirectory(title="你要将配置文件备份到哪里？")
+
+        if 检查文件夹(目标文件夹):
+            return 目标文件夹
+
+def 检查文件夹(目标文件夹):
+    # 检测是否选择了文件夹
+    if not 目标文件夹:
+        # 当用户点击选择文件窗口的“取消”按钮时
+        messagebox.showerror("错误", "未选择文件夹，操作取消。")
+        sys.exit(3)
+        # return False
+    # 检查目标文件夹是否存在，如果不存在则创建
+    if not os.path.exists(目标文件夹):
+        messagebox.showwarning("警告", "目标文件夹不存在，将新建一个同名文件夹。")
+        os.makedirs(目标文件夹)
+    # 检查目标文件夹是否为空
+    if len(os.listdir(目标文件夹)) != 0:
+        messagebox.showerror("错误", "目标文件夹不为空，请选择一个空文件夹。")
+        return False
+    return True # 一切正常
+
+def 复制配置文件(目标文件夹):
+    # 获取当前运行脚本的文件夹路径的上级目录作为源文件夹
+    当前文件夹 = os.path.dirname(os.path.abspath(sys.argv[0]))
+    源文件夹 = os.path.dirname(当前文件夹)
+
+    已复制的文件 = []  # 用于存储已经复制的文件路径
+
+    try:
+        # 遍历源文件夹中的所有文件和子文件夹
+        for root, dirs, files in os.walk(源文件夹):
+            for file in files:
+                if file == 'config.ini':
+                    源路径 = os.path.join(root, file)
+                    if root == 源文件夹:
+                        # 忽略源文件夹中的 config.ini
+                        continue
+                    目标路径 = os.path.join(目标文件夹, os.path.relpath(源路径, 源文件夹))
+                    目标目录 = os.path.dirname(目标路径)
+
+                    # 创建目标文件夹中的子文件夹（如果需要）
+                    if not os.path.exists(目标目录):
+                        os.makedirs(目标目录)
+                    
+                    # 复制文件
+                    shutil.copyfile(源路径, 目标路径)
+                    已复制的文件.append(目标路径)  # 记录已复制的文件
+
+        # 如果成功完成所有文件复制
+        messagebox.showinfo("恭喜", "配置文件备份成功！")
+    except KeyboardInterrupt:
+        # 用户按下 Ctrl+C 取消操作
+        messagebox.showerror("错误", "用户已取消操作。")
+        
+        for file_path in 已复制的文件:
+            os.remove(file_path) # 删除已复制的文件
+    except Exception as e:
+        # 出现异常时取消操作并清空已复制的文件
+        messagebox.showerror("错误", f"备份过程中出现错误:\n{e}")
+
+        for file_path in 已复制的文件:
+            os.remove(file_path)  # 删除已复制的文件
path: src/config/备份.py
user: login: fjwxzde
body: ```suggestion
            os.remove(file_path) # 删除已复制的文件
```
created_at: 2025-03-08T10:20:25Z
author_association: COLLABORATOR

PR comments:
user: login: sourcery-ai[bot]
created_at: 2025-03-08T05:16:48Z
body: <!-- Generated by sourcery-ai[bot]: start review_guide -->

```html
## Sourcery 审查者指南

此拉取请求引入了读取先前保存的配置文件的功能。它涉及添加用于配置管理的新文件，并修改现有脚本以整合此新功能。

_由于更改看起来很简单，不需要可视化表示，因此未生成图表。_

### 文件级别更改

| 变更 | 详情 | 文件 |
| ------ | ------- | ----- |
| 引入了配置管理文件。 | <ul><li>添加了一个用于通用配置设置的新文件。</li><li>添加了一个用于保存和加载配置的特定设置的新文件。</li></ul> | `b/src/config/保存.py`<br/>`b/src/config/设置.py` |
| 修改了现有脚本以集成配置加载。 | <ul><li>调整了用于通用目的的脚本，以利用新的配置加载机制。</li><li>修改了用于过滤目的的脚本，以利用新的配置加载机制。</li><li>更新了主脚本以整合配置加载功能。</li></ul> | `b/src/批量导出字幕文件(for过滤).pyw`<br/>`b/src/批量导出字幕文件(for批量剪辑).pyw`<br/>`b/src/批量导出字幕文件.pyw` |
| 删除了临时配置保存脚本。 | <ul><li>删除了用于保存配置的临时脚本，因为该功能现在已集成。</li></ul> | `src/temporarily/config-save.py` |

---

<details>
<summary>提示和命令</summary>

#### 与 Sourcery 互动

- **触发新的审查：** 在拉取请求上评论 `@sourcery-ai review`。
- **继续讨论：** 直接回复 Sourcery 的审查评论。
- **从审查评论生成 GitHub issue：** 通过回复审查评论，要求 Sourcery 从该评论创建一个 issue。您也可以回复审查评论并使用 `@sourcery-ai issue` 从该评论创建一个 issue。
- **生成拉取请求标题：** 在拉取请求标题中的任何位置写入 `@sourcery-ai`，以随时生成标题。您也可以在拉取请求上评论 `@sourcery-ai title` 以随时（重新）生成标题。
- **生成拉取请求摘要：** 在拉取请求正文中的任何位置写入 `@sourcery-ai summary`，以随时在您想要的位置生成 PR 摘要。您也可以在拉取请求上评论 `@sourcery-ai summary` 以随时（重新）生成摘要。
- **生成审查者指南：** 在拉取请求上评论 `@sourcery-ai guide` 以随时（重新）生成审查者指南。
- **解决所有 Sourcery 评论：** 在拉取请求上评论 `@sourcery-ai resolve` 以解决所有 Sourcery 评论。如果您已经处理了所有评论并且不想再看到它们，这将非常有用。
- **驳回所有 Sourcery 审查：** 在拉取请求上评论 `@sourcery-ai dismiss` 以驳回所有现有的 Sourcery 审查。如果您想从新的审查开始，这将特别有用 - 不要忘记评论 `@sourcery-ai review` 以触发新的审查！
- **为 issue 生成行动计划：** 在 issue 上评论 `@sourcery-ai plan` 以为其生成行动计划。

#### 自定义您的体验

访问您的 [仪表板](https://app.sourcery.ai) 以：
- 启用或禁用审查功能，例如 Sourcery 生成的拉取请求摘要、审查者指南等。
- 更改审查语言。
- 添加、删除或编辑自定义审查说明。
- 调整其他审查设置。

#### 获取帮助

- [联系我们的支持团队](mailto:support@sourcery.ai) 提出问题或反馈。
- 访问我们的 [文档](https://docs.sourcery.ai) 获取详细的指南和信息。
- 通过在 [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) 或 [GitHub](https://github.com/sourcery-ai) 上关注我们，与 Sourcery 团队保持联系。

</details>
```

<details>
<summary>Original review guide in English</summary>

## Reviewer's Guide by Sourcery

This pull request introduces the functionality to read previously saved configuration files. It involves adding new files for configuration management and modifying existing scripts to incorporate this new functionality.

_No diagrams generated as the changes look simple and do not need a visual representation._

### File-Level Changes

| Change | Details | Files |
| ------ | ------- | ----- |
| Introduced configuration management files. | <ul><li>Added a new file for general configuration settings.</li><li>Added a new file for specific settings related to saving and loading configurations.</li></ul> | `b/src/config/保存.py`<br/>`b/src/config/设置.py` |
| Modified existing scripts to integrate configuration loading. | <ul><li>Adjusted the script for general purposes to utilize the new configuration loading mechanism.</li><li>Modified the script for filtering purposes to utilize the new configuration loading mechanism.</li><li>Updated the main script to incorporate the configuration loading functionality.</li></ul> | `b/src/批量导出字幕文件(for过滤).pyw`<br/>`b/src/批量导出字幕文件(for批量剪辑).pyw`<br/>`b/src/批量导出字幕文件.pyw` |
| Removed temporary configuration saving script. | <ul><li>Deleted the temporary script used for saving configurations, as the functionality is now integrated.</li></ul> | `src/temporarily/config-save.py` |

---

<details>
<summary>Tips and commands</summary>

#### Interacting with Sourcery

- **Trigger a new review:** Comment `@sourcery-ai review` on the pull request.
- **Continue discussions:** Reply directly to Sourcery's review comments.
- **Generate a GitHub issue from a review comment:** Ask Sourcery to create an
  issue from a review comment by replying to it. You can also reply to a
  review comment with `@sourcery-ai issue` to create an issue from it.
- **Generate a pull request title:** Write `@sourcery-ai` anywhere in the pull
  request title to generate a title at any time. You can also comment
  `@sourcery-ai title` on the pull request to (re-)generate the title at any time.
- **Generate a pull request summary:** Write `@sourcery-ai summary` anywhere in
  the pull request body to generate a PR summary at any time exactly where you
  want it. You can also comment `@sourcery-ai summary` on the pull request to
  (re-)generate the summary at any time.
- **Generate reviewer's guide:** Comment `@sourcery-ai guide` on the pull
  request to (re-)generate the reviewer's guide at any time.
- **Resolve all Sourcery comments:** Comment `@sourcery-ai resolve` on the
  pull request to resolve all Sourcery comments. Useful if you've already
  addressed all the comments and don't want to see them anymore.
- **Dismiss all Sourcery reviews:** Comment `@sourcery-ai dismiss` on the pull
  request to dismiss all existing Sourcery reviews. Especially useful if you
  want to start fresh with a new review - don't forget to comment
  `@sourcery-ai review` to trigger a new review!
- **Generate a plan of action for an issue:** Comment `@sourcery-ai plan` on
  an issue to generate a plan of action for it.

#### Customizing Your Experience

Access your [dashboard](https://app.sourcery.ai) to:
- Enable or disable review features such as the Sourcery-generated pull request
  summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.

#### Getting Help

- [Contact our support team](mailto:support@sourcery.ai) for questions or feedback.
- Visit our [documentation](https://docs.sourcery.ai) for detailed guides and information.
- Keep in touch with the Sourcery team by following us on [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) or [GitHub](https://github.com/sourcery-ai).

</details>

</details>

<!-- Generated by sourcery-ai[bot]: end review_guide -->
author_association: NONE
user: login: DuckDuckStudio
created_at: 2025-03-08T10:14:34Z
body: @fjwxzde run test
author_association: OWNER