Compare commits
	
		
			5 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 83f1811968 | |||
| ffc16830b5 | |||
| 6675a46cb6 | |||
| c6bae39095 | |||
| b6d91355c4 | 
							
								
								
									
										213
									
								
								SpaceSniffer.py
									
									
									
									
									
								
							
							
						
						
									
										213
									
								
								SpaceSniffer.py
									
									
									
									
									
								
							| @@ -1,10 +1,34 @@ | ||||
| import os | ||||
| import sys | ||||
| import webbrowser | ||||
| import threading | ||||
| import tkinter as tk | ||||
| from tkinter import ttk, filedialog, messagebox | ||||
| from queue import Queue | ||||
| from send2trash import send2trash | ||||
| 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(), | ||||
|     ], | ||||
| ) | ||||
|  | ||||
| proxy = {"http": None, "https": None}  # Requests代理设置 | ||||
|  | ||||
|  | ||||
| def format_size(size):  # 格式化文件/目录大小 | ||||
|     units = ["B", "KB", "MB", "GB", "TB"] | ||||
|     index = 0 | ||||
|     while size >= 1024 and index < len(units) - 1: | ||||
|         size /= 1024.0 | ||||
|         index += 1 | ||||
|     return f"{size:.2f} {units[index]}" | ||||
|  | ||||
|  | ||||
| class FolderScanner(threading.Thread): | ||||
| @@ -16,28 +40,32 @@ class FolderScanner(threading.Thread): | ||||
|         self.total_items = 0  # 总共扫描的文件/目录数量 | ||||
|  | ||||
|     def run(self):  # 扫描文件/目录 | ||||
|         logging.info(f"开始扫描目录: {self.start_path}") | ||||
|         self.total_items = sum( | ||||
|             [len(files) + len(dirs) for r, dirs, files in os.walk(self.start_path)] | ||||
|         )  # 计算总共扫描的文件/目录数量 | ||||
|         self.scan_folder(self.start_path)  # 扫描文件/目录 | ||||
|         self.queue.put(None)  # 扫描结束 | ||||
|         logging.info(f"扫描完成: {self.start_path}") | ||||
|  | ||||
|     def scan_folder(self, folder):  # 扫描文件/目录 | ||||
|         scanned_items = 0  # 已扫描的文件/目录数量 | ||||
|         for dirpath, dirnames, filenames in os.walk(folder):  # 遍历文件/目录 | ||||
|             for dirname in dirnames:  # 遍历目录 | ||||
|     def scan_folder(self, folder): | ||||
|         scanned_items = 0 | ||||
|         for dirpath, dirnames, filenames in os.walk(folder): | ||||
|             for dirname in dirnames: | ||||
|                 folder_path = os.path.join(dirpath, dirname) | ||||
|                 size = self.get_size(folder_path) | ||||
|                 self.queue.put((folder_path, size, dirpath, "folder")) | ||||
|                 scanned_items += 1 | ||||
|                 self.update_progress(scanned_items, folder_path) | ||||
|                 logging.info(f"扫描目录: {folder_path} 大小: {format_size(size)} ") | ||||
|  | ||||
|             for filename in filenames:  # 遍历文件 | ||||
|             for filename in filenames: | ||||
|                 file_path = os.path.join(dirpath, filename) | ||||
|                 size = os.path.getsize(file_path) | ||||
|                 self.queue.put((file_path, size, dirpath, "file")) | ||||
|                 scanned_items += 1 | ||||
|                 self.update_progress(scanned_items, file_path) | ||||
|                 logging.info(f"扫描文件: {file_path} 大小: {format_size(size)} ") | ||||
|  | ||||
|     def get_size(self, path):  # 获取文件/目录大小 | ||||
|         total_size = 0 | ||||
| @@ -58,7 +86,7 @@ class App(tk.Tk): | ||||
|     def __init__(self, start_path):  # 初始化 | ||||
|         super().__init__() | ||||
|         self.withdraw() | ||||
|         self.title("目录扫描器 V1.3") | ||||
|         self.title("目录扫描器 V1.4.3") | ||||
|         self.start_path = start_path | ||||
|         self.queue = Queue() | ||||
|         self.progress_queue = Queue() | ||||
| @@ -135,32 +163,80 @@ class App(tk.Tk): | ||||
|         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_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) | ||||
|  | ||||
|     def show_help(self): | ||||
|         messagebox.showinfo( | ||||
|             "帮助", | ||||
|             "1. 双击文件夹可以展开/折叠\n", | ||||
|             "2. 双击文件可以直接打开\n", | ||||
|             "3. 右键单击文件/文件夹可以打开、删除文件/文件夹、进入所在目录\n", | ||||
|             "4. 点击左上角文件菜单可以重新选择目录进行扫描\n", | ||||
|             "5. 点击左上角视图菜单可以根据目录/文件大小、目录/文件名排序、刷新列表\n", | ||||
|             "1. 双击文件夹可以展开/折叠\n2. 双击文件可以直接打开\n3. 右键单击文件/文件夹可以打开、删除文件/文件夹、进入所在目录\n4. 点击左上角文件菜单可以重新选择目录进行扫描\n5. 点击左上角视图菜单可以根据目录/文件大小、目录/文件名排序、刷新列表\n", | ||||
|         ) | ||||
|  | ||||
|     def show_update_log(self): | ||||
|         messagebox.showinfo( | ||||
|             "更新日志", | ||||
|             "V1.0 实现了目录扫描功能,文件/目录大小统计功能\n", | ||||
|             "\n", | ||||
|             "V1.1 实现了重新选择目录扫描功能,新增了进度条显示\n", | ||||
|             "\n", | ||||
|             "V1.2 实现了双击打开目录、文件的功能,实现了右键菜单\n", | ||||
|             "\n", | ||||
|             "V1.3 优化了界面UI\n", | ||||
|         ) | ||||
|         repo_owner = "ahdoawhfo" | ||||
|         repo_name = "SpaceSniffer" | ||||
|         base_url = "https://git.a6.wiki/api/v1/repos" | ||||
|  | ||||
|         try: | ||||
|             # 发送 GET 请求获取最新的 Release | ||||
|             response = requests.get( | ||||
|                 f"{base_url}/{repo_owner}/{repo_name}/releases/latest", proxies=proxy | ||||
|             ) | ||||
|  | ||||
|             if response.status_code == 200: | ||||
|                 release_info = response.json() | ||||
|                 latest_version = release_info["tag_name"] | ||||
|                 release_notes = release_info["body"] | ||||
|                 messagebox.showinfo( | ||||
|                     "更新日志", f"版本: {latest_version}\n\n{release_notes}" | ||||
|                 ) | ||||
|             else: | ||||
|                 messagebox.showinfo( | ||||
|                     "更新日志", | ||||
|                     f"获取更新日志失败:{response.status_code}", | ||||
|                 ) | ||||
|         except requests.RequestException as e: | ||||
|             messagebox.showinfo("更新日志", f"获取更新日志时发生错误:{e}") | ||||
|  | ||||
|     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, is_startup=False) | ||||
|         update_manager.check_latest_release() | ||||
|  | ||||
|     def show_about(self): | ||||
|         messagebox.showinfo("关于", "目录扫描器 V1.3\n作者: ahdoawhfo") | ||||
|         messagebox.showinfo( | ||||
|             "关于", | ||||
|             "一款开源的文件/目录扫描工具\n可以直观地展示目录的文件结构以及文件大小\n\n软件版本 V1.4.3\n作者 ahdoawhfo\n", | ||||
|         ) | ||||
|  | ||||
|     def on_double_click(self, event):  # V1.2 Update:当双击的是文件时,打开文件 | ||||
|         item = self.tree.identify_row(event.y) | ||||
| @@ -179,17 +255,9 @@ class App(tk.Tk): | ||||
|             self.start_path = new_path | ||||
|             self.refresh_tree() | ||||
|  | ||||
|     def format_size(self, size):  # 格式化文件/目录大小 | ||||
|         units = ["B", "KB", "MB", "GB", "TB"] | ||||
|         index = 0 | ||||
|         while size >= 1024 and index < len(units) - 1: | ||||
|             size /= 1024.0 | ||||
|             index += 1 | ||||
|         return f"{size:.2f} {units[index]}" | ||||
|  | ||||
|     def populate_root(self):  # 初始化根目录 | ||||
|         size = self.scanner.get_size(self.start_path) | ||||
|         formatted_size = self.format_size(size) | ||||
|         formatted_size = format_size(size) | ||||
|         self.tree.insert( | ||||
|             "", | ||||
|             "end", | ||||
| @@ -209,7 +277,7 @@ class App(tk.Tk): | ||||
|                     return | ||||
|  | ||||
|                 path, size, parent, tag = item | ||||
|                 formatted_size = self.format_size(size) | ||||
|                 formatted_size = format_size(size) | ||||
|                 parent_iid = self.get_iid(parent) | ||||
|                 if parent == self.start_path: | ||||
|                     parent_iid = self.start_path | ||||
| @@ -398,8 +466,7 @@ class App(tk.Tk): | ||||
|     def on_close(self):  # 关闭程序 | ||||
|         if self.scanner.is_alive(): | ||||
|             self.scanner.join() | ||||
|         self.destroy() | ||||
|         root.destroy() | ||||
|         sys.exit(0) | ||||
|  | ||||
|     def set_window_size(self):  # 设置窗口大小 | ||||
|         screen_width = self.winfo_screenwidth() | ||||
| @@ -452,13 +519,89 @@ class ProgressWindow(tk.Toplevel):  # 进度窗口 | ||||
|         pass  # 禁止关闭进度窗口 | ||||
|  | ||||
|  | ||||
| class UpdateManager: | ||||
|     def __init__(self, root=None, is_startup=True): | ||||
|         self.root = root | ||||
|         self.is_startup = is_startup | ||||
|  | ||||
|     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.3"  # 替换成你的当前软件版本 | ||||
|  | ||||
|         try: | ||||
|             # 发送 GET 请求获取最新的 Release | ||||
|             response = requests.get( | ||||
|                 f"{base_url}/{repo_owner}/{repo_name}/releases/latest", proxies=proxy | ||||
|             ) | ||||
|  | ||||
|             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.is_startup: | ||||
|                             return False | ||||
|                     else: | ||||
|                         return True | ||||
|                 else: | ||||
|                     if not self.is_startup:  # 仅在用户点击检查更新时显示 | ||||
|                         self.show_message("检查更新", "当前版本已经是最新版本") | ||||
|                     return True | ||||
|             else: | ||||
|                 if not self.is_startup:  # 仅在用户点击检查更新时显示 | ||||
|                     self.show_message( | ||||
|                         "获取 Release 失败", | ||||
|                         f"获取最新 Release 失败:{response.status_code}", | ||||
|                     ) | ||||
|                 return True | ||||
|         except requests.RequestException as e: | ||||
|             if not self.is_startup:  # 仅在用户点击检查更新时显示 | ||||
|                 self.show_message("请求错误", f"请求最新 Release 时发生错误:{e}") | ||||
|             return True | ||||
|  | ||||
|     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): | ||||
|         if self.root: | ||||
|             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)  # 清空文件内容 | ||||
|     except Exception as e: | ||||
|         messagebox.showinfo("Error", f"清空日志文件内容时发生错误: {e}") | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     clear_log_file() | ||||
|     root = tk.Tk() | ||||
|     root.withdraw() | ||||
|     update_manager = UpdateManager(root, is_startup=True) | ||||
|     proceed = update_manager.check_latest_release() | ||||
|     if not proceed: | ||||
|         sys.exit(0) | ||||
|     messagebox.showinfo("提示", "请选择你要扫描的目录") | ||||
|     start_path = filedialog.askdirectory() | ||||
|     if start_path: | ||||
|         app = App(start_path) | ||||
|         app.mainloop() | ||||
|     else: | ||||
|         messagebox.showinfo("提示", "没有选中任何目录,程序即将退出") | ||||
|         root.destroy() | ||||
|         sys.exit(0) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user