Merge pull request '新增了扫描日志、检查更新功能' (#5) from dev into main
Reviewed-on: #5
This commit is contained in:
		
							
								
								
									
										144
									
								
								SpaceSniffer.py
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								SpaceSniffer.py
									
									
									
									
									
								
							@@ -1,10 +1,22 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import webbrowser
 | 
				
			||||||
import threading
 | 
					import threading
 | 
				
			||||||
import tkinter as tk
 | 
					import tkinter as tk
 | 
				
			||||||
from tkinter import ttk, filedialog, messagebox
 | 
					from tkinter import ttk, filedialog, messagebox
 | 
				
			||||||
from queue import Queue
 | 
					from queue import Queue
 | 
				
			||||||
from send2trash import send2trash
 | 
					from send2trash import send2trash
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					logging.basicConfig(
 | 
				
			||||||
 | 
					    level=logging.INFO,
 | 
				
			||||||
 | 
					    format="%(asctime)s - %(levelname)s - %(message)s",
 | 
				
			||||||
 | 
					    handlers=[
 | 
				
			||||||
 | 
					        logging.FileHandler("scanner.log", encoding="utf-8"),
 | 
				
			||||||
 | 
					        logging.StreamHandler(),
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FolderScanner(threading.Thread):
 | 
					class FolderScanner(threading.Thread):
 | 
				
			||||||
@@ -16,28 +28,32 @@ class FolderScanner(threading.Thread):
 | 
				
			|||||||
        self.total_items = 0  # 总共扫描的文件/目录数量
 | 
					        self.total_items = 0  # 总共扫描的文件/目录数量
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run(self):  # 扫描文件/目录
 | 
					    def run(self):  # 扫描文件/目录
 | 
				
			||||||
 | 
					        logging.info(f"开始扫描目录: {self.start_path}")
 | 
				
			||||||
        self.total_items = sum(
 | 
					        self.total_items = sum(
 | 
				
			||||||
            [len(files) + len(dirs) for r, dirs, files in os.walk(self.start_path)]
 | 
					            [len(files) + len(dirs) for r, dirs, files in os.walk(self.start_path)]
 | 
				
			||||||
        )  # 计算总共扫描的文件/目录数量
 | 
					        )  # 计算总共扫描的文件/目录数量
 | 
				
			||||||
        self.scan_folder(self.start_path)  # 扫描文件/目录
 | 
					        self.scan_folder(self.start_path)  # 扫描文件/目录
 | 
				
			||||||
        self.queue.put(None)  # 扫描结束
 | 
					        self.queue.put(None)  # 扫描结束
 | 
				
			||||||
 | 
					        logging.info(f"扫描完成: {self.start_path}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def scan_folder(self, folder):  # 扫描文件/目录
 | 
					    def scan_folder(self, folder):
 | 
				
			||||||
        scanned_items = 0  # 已扫描的文件/目录数量
 | 
					        scanned_items = 0
 | 
				
			||||||
        for dirpath, dirnames, filenames in os.walk(folder):  # 遍历文件/目录
 | 
					        for dirpath, dirnames, filenames in os.walk(folder):
 | 
				
			||||||
            for dirname in dirnames:  # 遍历目录
 | 
					            for dirname in dirnames:
 | 
				
			||||||
                folder_path = os.path.join(dirpath, dirname)
 | 
					                folder_path = os.path.join(dirpath, dirname)
 | 
				
			||||||
                size = self.get_size(folder_path)
 | 
					                size = self.get_size(folder_path)
 | 
				
			||||||
                self.queue.put((folder_path, size, dirpath, "folder"))
 | 
					                self.queue.put((folder_path, size, dirpath, "folder"))
 | 
				
			||||||
                scanned_items += 1
 | 
					                scanned_items += 1
 | 
				
			||||||
                self.update_progress(scanned_items, folder_path)
 | 
					                self.update_progress(scanned_items, folder_path)
 | 
				
			||||||
 | 
					                logging.info(f"扫描目录: {folder_path} 大小: {size} 字节")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for filename in filenames:  # 遍历文件
 | 
					            for filename in filenames:
 | 
				
			||||||
                file_path = os.path.join(dirpath, filename)
 | 
					                file_path = os.path.join(dirpath, filename)
 | 
				
			||||||
                size = os.path.getsize(file_path)
 | 
					                size = os.path.getsize(file_path)
 | 
				
			||||||
                self.queue.put((file_path, size, dirpath, "file"))
 | 
					                self.queue.put((file_path, size, dirpath, "file"))
 | 
				
			||||||
                scanned_items += 1
 | 
					                scanned_items += 1
 | 
				
			||||||
                self.update_progress(scanned_items, file_path)
 | 
					                self.update_progress(scanned_items, file_path)
 | 
				
			||||||
 | 
					                logging.info(f"扫描文件: {file_path} 大小: {size} 字节")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_size(self, path):  # 获取文件/目录大小
 | 
					    def get_size(self, path):  # 获取文件/目录大小
 | 
				
			||||||
        total_size = 0
 | 
					        total_size = 0
 | 
				
			||||||
@@ -58,7 +74,7 @@ class App(tk.Tk):
 | 
				
			|||||||
    def __init__(self, start_path):  # 初始化
 | 
					    def __init__(self, start_path):  # 初始化
 | 
				
			||||||
        super().__init__()
 | 
					        super().__init__()
 | 
				
			||||||
        self.withdraw()
 | 
					        self.withdraw()
 | 
				
			||||||
        self.title("目录扫描器 V1.3")
 | 
					        self.title("目录扫描器 V1.4")
 | 
				
			||||||
        self.start_path = start_path
 | 
					        self.start_path = start_path
 | 
				
			||||||
        self.queue = Queue()
 | 
					        self.queue = Queue()
 | 
				
			||||||
        self.progress_queue = Queue()
 | 
					        self.progress_queue = Queue()
 | 
				
			||||||
@@ -135,6 +151,8 @@ class App(tk.Tk):
 | 
				
			|||||||
        menu_bar.add_cascade(label="帮助", menu=help_menu)
 | 
					        menu_bar.add_cascade(label="帮助", menu=help_menu)
 | 
				
			||||||
        help_menu.add_command(label="帮助", command=self.show_help)
 | 
					        help_menu.add_command(label="帮助", command=self.show_help)
 | 
				
			||||||
        help_menu.add_command(label="更新日志", command=self.show_update_log)
 | 
					        help_menu.add_command(label="更新日志", command=self.show_update_log)
 | 
				
			||||||
 | 
					        help_menu.add_command(label="扫描日志", command=self.show_log)
 | 
				
			||||||
 | 
					        help_menu.add_command(label="检查更新", command=self.check_updates)
 | 
				
			||||||
        help_menu.add_command(label="关于", command=self.show_about)
 | 
					        help_menu.add_command(label="关于", command=self.show_about)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def show_help(self):
 | 
					    def show_help(self):
 | 
				
			||||||
@@ -150,17 +168,58 @@ class App(tk.Tk):
 | 
				
			|||||||
    def show_update_log(self):
 | 
					    def show_update_log(self):
 | 
				
			||||||
        messagebox.showinfo(
 | 
					        messagebox.showinfo(
 | 
				
			||||||
            "更新日志",
 | 
					            "更新日志",
 | 
				
			||||||
            "V1.0 实现了目录扫描功能,文件/目录大小统计功能\n",
 | 
					            "V1.0 实现了基本的目录扫描、文件/目录大小统计功能\n",
 | 
				
			||||||
            "\n",
 | 
					            "\n",
 | 
				
			||||||
            "V1.1 实现了重新选择目录扫描功能,新增了进度条显示\n",
 | 
					            "V1.1 新增了重新选择目录扫描功能,新增了进度条显示\n",
 | 
				
			||||||
            "\n",
 | 
					            "\n",
 | 
				
			||||||
            "V1.2 实现了双击打开目录、文件的功能,实现了右键菜单\n",
 | 
					            "V1.2 新增了双击打开目录、文件的功能,实现了右键菜单\n",
 | 
				
			||||||
            "\n",
 | 
					            "\n",
 | 
				
			||||||
            "V1.3 优化了界面UI\n",
 | 
					            "V1.3 优化了界面UI\n",
 | 
				
			||||||
 | 
					            "\n",
 | 
				
			||||||
 | 
					            "V1.4 新增了扫描日志、检查更新功能\n",
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_log(self):
 | 
				
			||||||
 | 
					        log_content = self.read_log_file()  # 从日志文件中读取日志内容
 | 
				
			||||||
 | 
					        log_window = tk.Toplevel(self)
 | 
				
			||||||
 | 
					        log_window.title("扫描日志")
 | 
				
			||||||
 | 
					        log_window.geometry("1000x400")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        text_widget = tk.Text(log_window, wrap=tk.WORD)
 | 
				
			||||||
 | 
					        text_widget.pack(expand=True, fill=tk.BOTH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        scrollbar = tk.Scrollbar(text_widget)
 | 
				
			||||||
 | 
					        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
 | 
				
			||||||
 | 
					        text_widget.config(yscrollcommand=scrollbar.set)
 | 
				
			||||||
 | 
					        scrollbar.config(command=text_widget.yview)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        text_widget.insert(tk.END, log_content)
 | 
				
			||||||
 | 
					        text_widget.config(state=tk.DISABLED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def read_log_file(self):
 | 
				
			||||||
 | 
					        log_file_path = "scanner.log"  # 日志文件路径
 | 
				
			||||||
 | 
					        if os.path.exists(log_file_path):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                with open(log_file_path, "r", encoding="utf-8") as log_file:
 | 
				
			||||||
 | 
					                    return log_file.read()
 | 
				
			||||||
 | 
					            except UnicodeDecodeError:
 | 
				
			||||||
 | 
					                return "日志文件编码错误,无法解析。"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return "日志文件不存在。"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def check_updates(self):
 | 
				
			||||||
 | 
					        # 创建一个新的 UpdateManager 实例,不销毁程序
 | 
				
			||||||
 | 
					        update_manager = UpdateManager(self)
 | 
				
			||||||
 | 
					        update_manager.check_latest_release()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def show_about(self):
 | 
					    def show_about(self):
 | 
				
			||||||
        messagebox.showinfo("关于", "目录扫描器 V1.3\n作者: ahdoawhfo")
 | 
					        messagebox.showinfo(
 | 
				
			||||||
 | 
					            "关于",
 | 
				
			||||||
 | 
					            "一款开源的文件/目录扫描工具\n",
 | 
				
			||||||
 | 
					            "可以直观地展示目录的文件结构以及文件大小\n",
 | 
				
			||||||
 | 
					            "软件版本 V1.4\n",
 | 
				
			||||||
 | 
					            "作者 ahdoawhfo\n",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def on_double_click(self, event):  # V1.2 Update:当双击的是文件时,打开文件
 | 
					    def on_double_click(self, event):  # V1.2 Update:当双击的是文件时,打开文件
 | 
				
			||||||
        item = self.tree.identify_row(event.y)
 | 
					        item = self.tree.identify_row(event.y)
 | 
				
			||||||
@@ -452,9 +511,74 @@ class ProgressWindow(tk.Toplevel):  # 进度窗口
 | 
				
			|||||||
        pass  # 禁止关闭进度窗口
 | 
					        pass  # 禁止关闭进度窗口
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UpdateManager:
 | 
				
			||||||
 | 
					    def __init__(self, root):
 | 
				
			||||||
 | 
					        self.root = root
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def check_latest_release(self):
 | 
				
			||||||
 | 
					        # Gitea 仓库信息和当前软件版本
 | 
				
			||||||
 | 
					        repo_owner = "ahdoawhfo"
 | 
				
			||||||
 | 
					        repo_name = "SpaceSniffer"
 | 
				
			||||||
 | 
					        base_url = "https://git.a6.wiki/api/v1/repos"
 | 
				
			||||||
 | 
					        current_version = "1.4"  # 替换成你的当前软件版本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            # 发送 GET 请求获取最新的 Release
 | 
				
			||||||
 | 
					            response = requests.get(
 | 
				
			||||||
 | 
					                f"{base_url}/{repo_owner}/{repo_name}/releases/latest"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if response.status_code == 200:
 | 
				
			||||||
 | 
					                release_info = response.json()
 | 
				
			||||||
 | 
					                latest_version = release_info["tag_name"]
 | 
				
			||||||
 | 
					                release_notes = release_info["body"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # 比较最新版本和当前软件版本
 | 
				
			||||||
 | 
					                if latest_version > current_version:
 | 
				
			||||||
 | 
					                    # 提示用户更新
 | 
				
			||||||
 | 
					                    choice = self.prompt_update(latest_version, release_notes)
 | 
				
			||||||
 | 
					                    if choice:
 | 
				
			||||||
 | 
					                        # 打开浏览器到 release 页面
 | 
				
			||||||
 | 
					                        release_url = release_info["html_url"]
 | 
				
			||||||
 | 
					                        webbrowser.open_new(release_url)
 | 
				
			||||||
 | 
					                        if self.root:
 | 
				
			||||||
 | 
					                            self.destroy()
 | 
				
			||||||
 | 
					                            root.destroy()
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    self.show_message("检查更新", "当前版本已经是最新版本")
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.show_message(
 | 
				
			||||||
 | 
					                    "检查更新",
 | 
				
			||||||
 | 
					                    f"获取最新 Release 失败:{response.status_code}",
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					        except requests.RequestException as e:
 | 
				
			||||||
 | 
					            self.show_message("检查更新", f"请求最新 Release 时发生错误:{e}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def prompt_update(self, latest_version, release_notes):
 | 
				
			||||||
 | 
					        prompt_message = f"检查更新: {latest_version}\n\n更新说明:\n{release_notes}\n\n是否立即更新?"
 | 
				
			||||||
 | 
					        choice = messagebox.askyesno("更新提示", prompt_message)
 | 
				
			||||||
 | 
					        return choice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_message(self, title, message):
 | 
				
			||||||
 | 
					        messagebox.showinfo(title, message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def clear_log_file():
 | 
				
			||||||
 | 
					    log_file = "scanner.log"
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        with open(log_file, "w", encoding="utf-8") as f:
 | 
				
			||||||
 | 
					            f.truncate(0)  # 清空文件内容
 | 
				
			||||||
 | 
					        print(f"已清空日志文件 {log_file} 的内容")
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        print(f"清空日志文件内容时发生错误: {e}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    clear_log_file()
 | 
				
			||||||
    root = tk.Tk()
 | 
					    root = tk.Tk()
 | 
				
			||||||
    root.withdraw()
 | 
					    root.withdraw()
 | 
				
			||||||
 | 
					    app = UpdateManager(root)
 | 
				
			||||||
 | 
					    app.check_latest_release()
 | 
				
			||||||
    start_path = filedialog.askdirectory()
 | 
					    start_path = filedialog.askdirectory()
 | 
				
			||||||
    if start_path:
 | 
					    if start_path:
 | 
				
			||||||
        app = App(start_path)
 | 
					        app = App(start_path)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user