111 lines
3.6 KiB
Python
111 lines
3.6 KiB
Python
"""
|
|
Stock Screener Launcher
|
|
=======================
|
|
Startup sequence:
|
|
1. Generate HWID
|
|
2. Load stored license key — show activation dialog if none found
|
|
3. Verify license against Supabase (with 30-min offline grace period)
|
|
4. Silently check for and apply updates
|
|
5. Launch the bundled screener_gui
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import tkinter as tk
|
|
from tkinter import messagebox
|
|
|
|
# Add dist/ to path so screener_gui and stock_screener are importable
|
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "dist"))
|
|
|
|
# Fix SSL certificate path for PyInstaller frozen builds.
|
|
# Without this, requests raises "Could not find a suitable TLS CA certificate bundle".
|
|
if getattr(sys, "frozen", False):
|
|
import certifi
|
|
os.environ["REQUESTS_CA_BUNDLE"] = certifi.where()
|
|
os.environ["SSL_CERT_FILE"] = certifi.where()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def _fatal(title: str, message: str) -> None:
|
|
"""Show an error dialog and exit."""
|
|
root = tk.Tk()
|
|
root.withdraw()
|
|
messagebox.showerror(title, message)
|
|
root.destroy()
|
|
sys.exit(1)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Main
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def main():
|
|
# ------------------------------------------------------------------
|
|
# Step 1: HWID
|
|
# ------------------------------------------------------------------
|
|
try:
|
|
from hwid import get_hwid
|
|
hwid = get_hwid()
|
|
except Exception as exc:
|
|
_fatal("Ultimate Investment Tool", f"Could not generate hardware ID:\n\n{exc}")
|
|
return
|
|
|
|
# ------------------------------------------------------------------
|
|
# Step 2: Load or activate license
|
|
# ------------------------------------------------------------------
|
|
import license_check
|
|
|
|
license_key = license_check.load_license_key(hwid)
|
|
|
|
if license_key is None:
|
|
import activation_dialog
|
|
activated = activation_dialog.run_activation(hwid)
|
|
if not activated:
|
|
sys.exit(0)
|
|
license_key = license_check.load_license_key(hwid)
|
|
if license_key is None:
|
|
_fatal("Ultimate Investment Tool", "Activation failed. Please restart and try again.")
|
|
return
|
|
|
|
# ------------------------------------------------------------------
|
|
# Step 3: Verify license on every launch
|
|
# ------------------------------------------------------------------
|
|
valid, reason = license_check.verify_license(license_key, hwid)
|
|
|
|
if not valid:
|
|
license_check.delete_license_key()
|
|
_fatal(
|
|
"Ultimate Investment Tool — License Error",
|
|
f"{reason}\n\nThe application will now close."
|
|
)
|
|
return
|
|
|
|
# ------------------------------------------------------------------
|
|
# Step 4: Silent update check
|
|
# ------------------------------------------------------------------
|
|
try:
|
|
import updater
|
|
updater.check_and_apply_update()
|
|
except Exception:
|
|
pass
|
|
|
|
# ------------------------------------------------------------------
|
|
# Step 5: Launch bundled app
|
|
# ------------------------------------------------------------------
|
|
try:
|
|
import screener_gui
|
|
screener_gui.main()
|
|
except Exception:
|
|
import traceback
|
|
_fatal(
|
|
"Ultimate Investment Tool — Startup Error",
|
|
f"The application failed to start:\n\n{traceback.format_exc()}"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|