feat: Add ProBackup.exe executable for Windows XP distribution.

This commit is contained in:
2026-01-30 17:49:26 +08:00
parent b86408e7e6
commit 2915cbbb80
3 changed files with 50 additions and 4 deletions

Binary file not shown.

View File

@@ -4,6 +4,7 @@ import subprocess
import platform import platform
import os import os
import base64 import base64
import sys
# Simple Secret Salt - In a real app, obfuscate this or use asymmetric keys (RSA) # Simple Secret Salt - In a real app, obfuscate this or use asymmetric keys (RSA)
# For this level, a symmetric secret is "good enough" for basic protection. # For this level, a symmetric secret is "good enough" for basic protection.
@@ -14,6 +15,35 @@ CREATE_NO_WINDOW = 0x08000000
class LicenseManager: class LicenseManager:
@staticmethod @staticmethod
def _get_base_dir():
if getattr(sys, 'frozen', False):
return os.path.dirname(sys.executable)
return os.path.dirname(os.path.abspath(__file__))
@staticmethod
def _get_license_path():
return os.path.join(LicenseManager._get_base_dir(), "license.dat")
@staticmethod
def save_license(key):
try:
with open(LicenseManager._get_license_path(), "w") as f:
f.write(key.strip())
return True
except:
return False
@staticmethod
def load_license():
path = LicenseManager._get_license_path()
if not os.path.exists(path):
return None
try:
with open(path, "r") as f:
return f.read().strip()
except:
return None
@staticmethod
def get_motherboard_id(): def get_motherboard_id():
"""Gets the motherboard UUID using WMIC (Windows only).""" """Gets the motherboard UUID using WMIC (Windows only)."""
try: try:

24
main.py
View File

@@ -278,8 +278,11 @@ class BackupApp(QMainWindow):
# Ensure sql_tools folder exists # Ensure sql_tools folder exists
self.ensure_sql_tools_folder() self.ensure_sql_tools_folder()
self.settings = self.load_settings()
self.trial_limit = 10 # Max uses in trial mode
self.load_settings() # Job Queue System
self.job_queue = []
if self.trial_mode: if self.trial_mode:
# Check if strict limit reached immediately # Check if strict limit reached immediately
@@ -1308,9 +1311,9 @@ class BackupApp(QMainWindow):
def scheduled_backup_wrapper(self, job_id): def scheduled_backup_wrapper(self, job_id):
# Determine if we can run # Determine if we can run
if self.worker and self.worker.isRunning(): if self.worker and self.worker.isRunning():
# Concurrent jobs? For now let's skip or queue? # Concurrent jobs? Queue them!
# Simple approach: Skip if busy. self.log(">>> App Sibuk. Job ID {} masuk antrian.".format(job_id))
self.log(">>> Jadwal Skip (App Sibuk) untuk Job ID: {}".format(job_id)) self.job_queue.append(job_id)
return return
# --- Check Trial Limit --- # --- Check Trial Limit ---
@@ -1370,6 +1373,13 @@ class BackupApp(QMainWindow):
if hasattr(self, 'run_single_btn'): if hasattr(self, 'run_single_btn'):
self.run_single_btn.setEnabled(True) self.run_single_btn.setEnabled(True)
self.log(">>> Eksekusi Selesai.") self.log(">>> Eksekusi Selesai.")
# Check Queue
if self.job_queue:
next_job_id = self.job_queue.pop(0)
self.log(">>> Memproses antrian: Job ID {}".format(next_job_id))
# Use QTimer to schedule it on main thread to be safe, though we are likely already on main thread slot
QTimer.singleShot(100, lambda: self.scheduled_backup_wrapper(next_job_id))
def processing_error(self, error_msg): def processing_error(self, error_msg):
self.run_all_btn.setEnabled(True) self.run_all_btn.setEnabled(True)
@@ -1378,6 +1388,12 @@ class BackupApp(QMainWindow):
if hasattr(self, 'run_single_btn'): if hasattr(self, 'run_single_btn'):
self.run_single_btn.setEnabled(True) self.run_single_btn.setEnabled(True)
self.log("!!! Kesalahan Thread: {}".format(error_msg)) self.log("!!! Kesalahan Thread: {}".format(error_msg))
# Check Queue even on error
if self.job_queue:
next_job_id = self.job_queue.pop(0)
self.log(">>> Memproses antrian (setelah error): Job ID {}".format(next_job_id))
QTimer.singleShot(100, lambda: self.scheduled_backup_wrapper(next_job_id))
# --- Tray --- # --- Tray ---
def setup_tray(self): def setup_tray(self):