Created
June 1, 2025 06:37
-
-
Save krisstibex/e44aaa9451c2089cd75d2d078b695862 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import threading | |
| import tkinter as tk | |
| from tkinter import filedialog, messagebox, ttk | |
| from tkinterdnd2 import TkinterDnD, DND_FILES | |
| import zipfile | |
| import py7zr | |
| import patoolib | |
| import locale | |
| from PIL import Image, ImageTk | |
| from concurrent.futures import ThreadPoolExecutor | |
| # 多语言支持 | |
| lang = "zh" if locale.getdefaultlocale()[0].startswith("zh") else "en" | |
| L = { | |
| "zh": { | |
| "title": "压缩/解压 工具箱", | |
| "drop_here": "将文件或压缩包拖到此处\n支持 zip / 7z / tar.gz 等", | |
| "advanced": "高级设置", | |
| "format": "压缩格式:", | |
| "level": "压缩率:", | |
| "output_name": "输出文件名:", | |
| "output_dir": "输出目录:", | |
| "password": "密码(可选):", | |
| "save": "保存", | |
| "success": "成功", | |
| "fail": "失败", | |
| "status": "当前状态:", | |
| "log": "日志:" | |
| }, | |
| "en": { | |
| "title": "Compression/Extraction Toolbox", | |
| "drop_here": "Drop files or archives here\nSupports zip / 7z / tar.gz etc.", | |
| "advanced": "Advanced Settings", | |
| "format": "Format:", | |
| "level": "Compression Level:", | |
| "output_name": "Output Name:", | |
| "output_dir": "Output Dir:", | |
| "password": "Password (optional):", | |
| "save": "Save", | |
| "success": "Success", | |
| "fail": "Failed", | |
| "status": "Status:", | |
| "log": "Logs:" | |
| } | |
| }[lang] | |
| # 默认配置 | |
| config = { | |
| "compression_format": "zip", | |
| "compression_level": "normal", | |
| "output_name": "archive", | |
| "output_dir": "", | |
| "password": "" | |
| } | |
| executor = ThreadPoolExecutor(max_workers=4) | |
| # 主界面 | |
| root = TkinterDnD.Tk() | |
| root.title(L["title"]) | |
| root.geometry("500x450") | |
| root.resizable(False, False) | |
| # 图标(可选) | |
| try: | |
| icon_img = Image.open("icon.png").resize((64, 64)) | |
| icon = ImageTk.PhotoImage(icon_img) | |
| tk.Label(root, image=icon).pack(pady=5) | |
| except: | |
| pass | |
| label = tk.Label(root, text=L["drop_here"], width=60, height=10, | |
| relief="groove", bg="#eef", font=("Arial", 12)) | |
| label.pack(pady=10) | |
| label.drop_target_register(DND_FILES) | |
| status_var = tk.StringVar(value=L["status"]) | |
| log_text = tk.Text(root, height=5, state="disabled") | |
| progress = ttk.Progressbar(root, length=400, mode="indeterminate") | |
| progress.pack(pady=5) | |
| tk.Label(root, textvariable=status_var).pack() | |
| log_text.pack(padx=10, pady=5) | |
| tk.Button(root, text=L["advanced"], command=lambda: open_config()).pack() | |
| def log(msg): | |
| log_text.configure(state="normal") | |
| log_text.insert("end", msg + "\n") | |
| log_text.configure(state="disabled") | |
| log_text.see("end") | |
| def update_status(msg): | |
| status_var.set(f"{L['status']} {msg}") | |
| def is_archive(f): | |
| return f.lower().endswith((".zip", ".7z", ".tar.gz", ".tar", ".tgz", ".rar")) | |
| def handle_drop(event): | |
| files = root.tk.splitlist(event.data) | |
| files = [f.strip() for f in files] | |
| executor.submit(process_task, files) | |
| def process_task(files): | |
| update_status("Working...") | |
| progress.start() | |
| try: | |
| if all(is_archive(f) for f in files): | |
| for f in files: | |
| extract_archive(f) | |
| else: | |
| compress_files(files) | |
| except Exception as e: | |
| log(f"{L['fail']} ❌:{str(e)}") | |
| finally: | |
| progress.stop() | |
| update_status("Idle") | |
| def extract_archive(path): | |
| outdir = os.path.dirname(path) | |
| pwd = config.get("password") or None | |
| log(f"解压:{path}") | |
| try: | |
| if path.endswith(".zip"): | |
| with zipfile.ZipFile(path, 'r') as z: | |
| if pwd: | |
| z.setpassword(pwd.encode()) | |
| z.extractall(outdir) | |
| elif path.endswith(".7z"): | |
| with py7zr.SevenZipFile(path, 'r', password=pwd) as z: | |
| z.extractall(outdir) | |
| else: | |
| patoolib.extract_archive(path, outdir=outdir) | |
| log(f"{L['success']} ✅:{path}") | |
| except Exception as e: | |
| log(f"{L['fail']} ❌:{str(e)}") | |
| def compress_files(file_list): | |
| outdir = config["output_dir"] or os.path.dirname(file_list[0]) | |
| outname = config["output_name"] | |
| outpath = os.path.join(outdir, f"{outname}.{config['compression_format']}") | |
| pwd = config.get("password") or None | |
| log(f"压缩到:{outpath}") | |
| try: | |
| if config["compression_format"] == "zip": | |
| with zipfile.ZipFile(outpath, 'w', zipfile.ZIP_DEFLATED) as z: | |
| for f in file_list: | |
| z.write(f, os.path.basename(f)) | |
| elif config["compression_format"] == "7z": | |
| with py7zr.SevenZipFile(outpath, 'w', password=pwd) as z: | |
| for f in file_list: | |
| z.write(f, os.path.basename(f)) | |
| log(f"{L['success']} ✅:{outpath}") | |
| except Exception as e: | |
| log(f"{L['fail']} ❌:{str(e)}") | |
| def open_config(): | |
| win = tk.Toplevel(root) | |
| win.title(L["advanced"]) | |
| win.geometry("300x300") | |
| def save(): | |
| config["compression_format"] = fmt_var.get() | |
| config["compression_level"] = lvl_var.get() | |
| config["output_name"] = name_var.get() | |
| config["output_dir"] = dir_var.get() | |
| config["password"] = pw_var.get() | |
| win.destroy() | |
| tk.Label(win, text=L["format"]).pack() | |
| fmt_var = tk.StringVar(value=config["compression_format"]) | |
| tk.OptionMenu(win, fmt_var, "zip", "7z").pack() | |
| tk.Label(win, text=L["level"]).pack() | |
| lvl_var = tk.StringVar(value=config["compression_level"]) | |
| tk.OptionMenu(win, lvl_var, "store", "normal", "ultra").pack() | |
| tk.Label(win, text=L["output_name"]).pack() | |
| name_var = tk.Entry(win) | |
| name_var.insert(0, config["output_name"]) | |
| name_var.pack() | |
| tk.Label(win, text=L["output_dir"]).pack() | |
| dir_var = tk.Entry(win) | |
| dir_var.insert(0, config["output_dir"]) | |
| dir_var.pack() | |
| tk.Label(win, text=L["password"]).pack() | |
| pw_var = tk.Entry(win, show="*") | |
| pw_var.insert(0, config["password"]) | |
| pw_var.pack() | |
| tk.Button(win, text=L["save"], command=save).pack(pady=10) | |
| label.dnd_bind('<<Drop>>', handle_drop) | |
| root.mainloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment