mirror of
https://github.com/RealityNet/kobackupdec.git
synced 2026-06-06 09:52:34 +08:00
feat: Add GUI v1.1 features (drag-and-drop, persistence, export logs, open output)
This commit is contained in:
parent
04512877e9
commit
08c3d373e3
12
CHANGELOG.md
12
CHANGELOG.md
@ -2,7 +2,17 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [GUI Edition] — 2026-05-08
|
||||
## [GUI_v1.1] — 2026-05-08
|
||||
|
||||
### Added
|
||||
- **Drag-and-Drop:** Added `tkinterdnd2` support allowing users to drag backup folders directly into the application.
|
||||
- **Settings Persistence:** Created `config.json` integration to save and automatically load user preferences and selected directories across sessions.
|
||||
- **Log Exporting:** Added an "Export Log" button to save the current terminal output to a text file for auditing.
|
||||
- **Output Folder Quick Access:** Added an "Open Output" button that becomes clickable after a successful decryption to instantly view the extracted files.
|
||||
|
||||
---
|
||||
|
||||
## [GUI_v1.0] — 2026-05-08
|
||||
|
||||
### Added
|
||||
- **Full GUI application** (`kobackupdec_gui.py`) with modern dark theme
|
||||
|
||||
20
README.md
20
README.md
@ -2,12 +2,12 @@
|
||||
<h1 align="center">🔐 KoBackup Decryptor</h1>
|
||||
<p align="center">
|
||||
<strong>Decrypt Huawei HiSuite & KoBackup encrypted backups</strong><br>
|
||||
CLI + Modern GUI • Selective Folder Decryption • Password Verification
|
||||
CLI + Modern GUI • Selective Folder Decryption • Drag & Drop • Password Verification
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="#-installation"><img src="https://img.shields.io/badge/python-3.7%2B-blue?logo=python&logoColor=white" alt="Python 3.7+"></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="MIT License"></a>
|
||||
<a href="#-changelog"><img src="https://img.shields.io/badge/version-20200705--GUI-purple" alt="Version"></a>
|
||||
<a href="#-changelog"><img src="https://img.shields.io/badge/version-GUI_v1.1-purple" alt="Version"></a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
@ -39,7 +39,11 @@ This fork adds a **full-featured graphical interface** built with tkinter, bring
|
||||
| Decrypt full backups | ✅ | ✅ |
|
||||
| Password verification before decrypt | — | ✅ |
|
||||
| **Selective folder decryption** | — | ✅ |
|
||||
| **Drag and Drop support** | — | ✅ |
|
||||
| **Settings persistence** | — | ✅ |
|
||||
| Pause / Resume / Stop controls | — | ✅ |
|
||||
| Export decryption logs | — | ✅ |
|
||||
| Open Output folder button | — | ✅ |
|
||||
| Real-time color-coded log output | — | ✅ |
|
||||
| Progress tracking with status updates | — | ✅ |
|
||||
| Responsive dark-themed interface | — | ✅ |
|
||||
@ -69,6 +73,7 @@ pip install -r requirements.txt
|
||||
| Package | Purpose |
|
||||
|---|---|
|
||||
| `pycryptodome` | AES / PBKDF2 / HMAC cryptographic operations |
|
||||
| `tkinterdnd2` | Drag and drop functionality for the GUI |
|
||||
| `tkinter` | GUI framework (bundled with Python on most platforms) |
|
||||
|
||||
> **Note:** On some Linux distributions, tkinter may need to be installed separately:
|
||||
@ -95,11 +100,12 @@ python kobackupdec_gui.py
|
||||
#### GUI Workflow
|
||||
|
||||
1. **Enter Password** — Type your backup password (toggle visibility with 👁)
|
||||
2. **Select Backup Folder** — Browse to the Huawei backup directory
|
||||
2. **Select Backup Folder** — Drag and drop your Huawei backup directory right into the application, or click **Browse**
|
||||
3. **Select Destination** — Choose where to save decrypted files (pick a parent, name the output folder)
|
||||
4. **Configure Options** — Toggle TAR expansion, writable permissions, and log verbosity
|
||||
5. **Select Folders** — After setting the backup path, click **🔍 Scan** or it auto-scans to show available folders. Check/uncheck individual folders (pictures, video, audios, etc.)
|
||||
5. **Select Folders** — After setting the backup path, check/uncheck individual folders (pictures, video, audios, etc.) to decrypt only what you need
|
||||
6. **Start Decryption** — Click **🔓 Start Decryption**
|
||||
7. **Open Output** — When finished, click **📂 Open Output** to view your files immediately
|
||||
|
||||
#### GUI Controls
|
||||
|
||||
@ -108,6 +114,8 @@ python kobackupdec_gui.py
|
||||
| 🔓 **Start Decryption** | Verifies password first, then begins decryption |
|
||||
| ⏸ **Pause / ▶ Resume** | Temporarily halt and resume the process |
|
||||
| ⏹ **Stop** | Cancel the decryption (partially decrypted files are kept) |
|
||||
| 📂 **Open Output** | Opens destination folder in Windows Explorer (enabled after success) |
|
||||
| **Export Log** | Save decryption logs to a text file for auditing |
|
||||
| **Select All / Deselect All** | Quickly toggle all folder checkboxes |
|
||||
| **🔍 Scan** | Re-scan backup directory for available folders |
|
||||
| **Clear Log** | Clear the log output panel |
|
||||
@ -116,7 +124,9 @@ python kobackupdec_gui.py
|
||||
|
||||
- **🔑 Password Verification** — Validates the password against `info.xml` before starting decryption. Wrong passwords are caught instantly.
|
||||
- **📂 Selective Folder Decryption** — Only decrypt what you need (e.g., just pictures and contacts, skip video and apps).
|
||||
- **📊 Real-Time Progress** — Status bar shows current phase and folder being processed.
|
||||
- **💾 Settings Persistence** — The app remembers your selected folders and checkboxes across launches via `config.json`.
|
||||
- **🖱️ Drag and Drop** — Seamlessly drop backup folders into the app instead of browsing manually.
|
||||
- **📊 Real-Time Progress & Logs** — Status bar shows current phase. Export logs anytime.
|
||||
- **🎨 Dark Theme** — Modern, responsive dark interface with color-coded log levels (green=info, yellow=warning, red=error).
|
||||
- **📐 Responsive Layout** — Resizes gracefully from 600×500 to fullscreen. Folder checkboxes reflow automatically.
|
||||
|
||||
|
||||
@ -16,6 +16,9 @@ import tkinter as tk
|
||||
from tkinter import filedialog, messagebox, simpledialog, ttk
|
||||
import queue
|
||||
import time
|
||||
import json
|
||||
import subprocess
|
||||
from tkinterdnd2 import TkinterDnD, DND_FILES
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Logging handler that forwards records into a thread-safe queue
|
||||
@ -36,7 +39,7 @@ class QueueHandler(logging.Handler):
|
||||
# Main GUI Application
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class KoBackupDecGUI(tk.Tk):
|
||||
class KoBackupDecGUI(TkinterDnD.Tk):
|
||||
"""Tkinter-based GUI for the Huawei KoBackup decryptor."""
|
||||
|
||||
# -- Colour palette (dark mode) ----------------------------------------
|
||||
@ -112,6 +115,12 @@ class KoBackupDecGUI(tk.Tk):
|
||||
# Bind resize to reflow folder checkboxes
|
||||
self.bind("<Configure>", self._on_resize)
|
||||
|
||||
# Load saved settings
|
||||
self._load_config()
|
||||
|
||||
# Save config on exit
|
||||
self.protocol("WM_DELETE_WINDOW", self._on_closing)
|
||||
|
||||
# Start polling the log queue
|
||||
self._poll_log_queue()
|
||||
|
||||
@ -245,6 +254,10 @@ class KoBackupDecGUI(tk.Tk):
|
||||
highlightcolor=self.ACCENT)
|
||||
entry.pack(side="left", fill="x", expand=True, ipady=7, padx=(0, 8))
|
||||
|
||||
# Enable Drag and Drop
|
||||
entry.drop_target_register(DND_FILES)
|
||||
entry.dnd_bind('<<Drop>>', lambda e, v=var, t=tag: self._on_drop(e, v, t))
|
||||
|
||||
btn = tk.Button(row, text="Browse", font=("Segoe UI", 9, "bold"),
|
||||
bg=self.ACCENT, fg="#ffffff",
|
||||
activebackground=self.ACCENT_HOVER,
|
||||
@ -517,6 +530,37 @@ class KoBackupDecGUI(tk.Tk):
|
||||
)
|
||||
self.stop_btn.pack(side="left", padx=(10, 0))
|
||||
|
||||
self.open_output_btn = tk.Button(
|
||||
btn_row,
|
||||
text="📂 Open Output",
|
||||
font=("Segoe UI", 9),
|
||||
bg=self.SUCCESS,
|
||||
fg="#1a1a2e",
|
||||
activebackground="#10b981",
|
||||
activeforeground="#1a1a2e",
|
||||
relief="flat", bd=0,
|
||||
cursor="hand2",
|
||||
padx=14, pady=8,
|
||||
state="disabled",
|
||||
command=self._open_output_folder
|
||||
)
|
||||
self.open_output_btn.pack(side="right", padx=(10, 0))
|
||||
|
||||
self.export_log_btn = tk.Button(
|
||||
btn_row,
|
||||
text="Export Log",
|
||||
font=("Segoe UI", 9),
|
||||
bg=self.BG_INPUT,
|
||||
fg=self.FG_DIM,
|
||||
activebackground=self.BG_HOVER,
|
||||
activeforeground=self.FG,
|
||||
relief="flat", bd=0,
|
||||
cursor="hand2",
|
||||
padx=14, pady=8,
|
||||
command=self._export_log
|
||||
)
|
||||
self.export_log_btn.pack(side="right", padx=(10, 0))
|
||||
|
||||
self.clear_log_btn = tk.Button(
|
||||
btn_row,
|
||||
text="Clear Log",
|
||||
@ -919,12 +963,14 @@ class KoBackupDecGUI(tk.Tk):
|
||||
self._running = False
|
||||
self.progress.stop()
|
||||
self._set_controls_running(False)
|
||||
self.open_output_btn.configure(state="disabled")
|
||||
|
||||
if stopped:
|
||||
self.status_var.set('⏹ Decryption stopped by user')
|
||||
self._append_log('')
|
||||
self._append_log('WARNING: ⏹ Decryption was stopped by the user.')
|
||||
elif success:
|
||||
self.open_output_btn.configure(state="normal")
|
||||
self.status_var.set('✅ Decryption completed successfully!')
|
||||
self._append_log('')
|
||||
self._append_log('=' * 50)
|
||||
@ -939,6 +985,87 @@ class KoBackupDecGUI(tk.Tk):
|
||||
'Decryption failed.\n'
|
||||
'Check the log output for details.')
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# New Utilities
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
def _on_drop(self, event, var, tag):
|
||||
path = event.data
|
||||
if path.startswith('{') and path.endswith('}'):
|
||||
path = path[1:-1]
|
||||
var.set(path)
|
||||
if tag == "backup":
|
||||
self._scan_backup_folders()
|
||||
|
||||
def _export_log(self):
|
||||
log_content = self.log_text.get("1.0", "end-1c")
|
||||
if not log_content.strip():
|
||||
messagebox.showinfo("Export Log", "The log is empty.")
|
||||
return
|
||||
filepath = filedialog.asksaveasfilename(
|
||||
defaultextension=".txt",
|
||||
filetypes=[("Text files", "*.txt"), ("All files", "*.*")],
|
||||
title="Save Log Output"
|
||||
)
|
||||
if filepath:
|
||||
try:
|
||||
with open(filepath, "w", encoding="utf-8") as f:
|
||||
f.write(log_content)
|
||||
messagebox.showinfo("Success", "Log exported successfully.")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"Failed to save log:\n{e}")
|
||||
|
||||
def _open_output_folder(self):
|
||||
path = self.dest_var.get().strip()
|
||||
if os.path.isdir(path):
|
||||
if sys.platform == "win32":
|
||||
os.startfile(path)
|
||||
elif sys.platform == "darwin":
|
||||
subprocess.Popen(["open", path])
|
||||
else:
|
||||
subprocess.Popen(["xdg-open", path])
|
||||
|
||||
def _get_config_path(self):
|
||||
return os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json")
|
||||
|
||||
def _load_config(self):
|
||||
config_path = self._get_config_path()
|
||||
if os.path.exists(config_path):
|
||||
try:
|
||||
with open(config_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
if "backup_path" in data:
|
||||
self.backup_var.set(data["backup_path"])
|
||||
self._scan_backup_folders()
|
||||
if "dest_path" in data:
|
||||
self.dest_var.set(data["dest_path"])
|
||||
if "expandtar" in data:
|
||||
self.expandtar_var.set(data["expandtar"])
|
||||
if "writable" in data:
|
||||
self.writable_var.set(data["writable"])
|
||||
if "verbose" in data:
|
||||
self.verbose_var.set(data["verbose"])
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to load config: {e}")
|
||||
|
||||
def _save_config(self):
|
||||
config_path = self._get_config_path()
|
||||
data = {
|
||||
"backup_path": self.backup_var.get(),
|
||||
"dest_path": self.dest_var.get(),
|
||||
"expandtar": self.expandtar_var.get(),
|
||||
"writable": self.writable_var.get(),
|
||||
"verbose": self.verbose_var.get()
|
||||
}
|
||||
try:
|
||||
with open(config_path, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to save config: {e}")
|
||||
|
||||
def _on_closing(self):
|
||||
self._save_config()
|
||||
self.destroy()
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Entry point
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user