Refactor Windows installer configuration and improve logging functionality

- Changed installation scope from "perMachine" to "perUser" in the Windows installer configuration.
- Updated installation directory from "ProgramFiles64Folder" to "LocalAppDataFolder" for user-specific installations.
- Enhanced the configuration saving method to create parent directories if they don't exist.
- Improved the main window script loading logic to support multiple installation scenarios (development, PyInstaller, MSI).
- Added detailed logging for script loading failures and success messages.
- Implemented a new method to reconfigure logging settings at runtime, allowing dynamic updates from the settings dialog.
- Enhanced the settings dialog to handle configuration saving, including log level changes and error handling.
This commit is contained in:
claudi 2026-02-19 15:48:59 +01:00
parent 0c276b9022
commit 8f3f859e5b
9 changed files with 3068 additions and 2905 deletions

View file

@ -448,32 +448,72 @@ class MainWindow(QMainWindow):
config_code = self._generate_config_injection_script()
# Load bridge script from file
# Using intercept script - prevents browser drag, hands off to Qt
# Support both development mode and PyInstaller bundle
# Try multiple paths to support dev mode, PyInstaller bundle, and MSI installation
# 1. Development mode: __file__.parent / script.js
# 2. PyInstaller bundle: sys._MEIPASS / webdrop_bridge / ui / script.js
# 3. MSI installation: Same directory as executable
script_path = None
download_interceptor_path = None
# List of paths to try in order of preference
search_paths = []
# 1. Development mode
search_paths.append(Path(__file__).parent / "bridge_script_intercept.js")
# 2. PyInstaller bundle (via sys._MEIPASS)
if hasattr(sys, '_MEIPASS'):
# Running as PyInstaller bundle
script_path = Path(sys._MEIPASS) / "webdrop_bridge" / "ui" / "bridge_script_intercept.js" # type: ignore
else:
# Running in development mode
script_path = Path(__file__).parent / "bridge_script_intercept.js"
search_paths.append(Path(sys._MEIPASS) / "webdrop_bridge" / "ui" / "bridge_script_intercept.js") # type: ignore
# 3. Installed executable's directory (handles MSI installation where all files are packaged together)
exe_dir = Path(sys.executable).parent
search_paths.append(exe_dir / "webdrop_bridge" / "ui" / "bridge_script_intercept.js")
# Find the bridge script
for path in search_paths:
if path.exists():
script_path = path
logger.debug(f"Found bridge script at: {script_path}")
break
if script_path is None:
# Log all attempted paths for debugging
logger.error("Bridge script NOT found at any expected location:")
for i, path in enumerate(search_paths, 1):
logger.error(f" [{i}] {path} (exists: {path.exists()})")
logger.error(f"sys._MEIPASS: {getattr(sys, '_MEIPASS', 'NOT SET')}")
logger.error(f"sys.executable: {sys.executable}")
logger.error(f"__file__: {__file__}")
try:
if script_path is None:
raise FileNotFoundError("bridge_script_intercept.js not found in any expected location")
with open(script_path, 'r', encoding='utf-8') as f:
bridge_code = f.read()
# Load download interceptor
# Load download interceptor using similar search path logic
download_search_paths = []
download_search_paths.append(Path(__file__).parent / "download_interceptor.js")
if hasattr(sys, '_MEIPASS'):
download_interceptor_path = Path(sys._MEIPASS) / "webdrop_bridge" / "ui" / "download_interceptor.js" # type: ignore
else:
download_interceptor_path = Path(__file__).parent / "download_interceptor.js"
download_search_paths.append(Path(sys._MEIPASS) / "webdrop_bridge" / "ui" / "download_interceptor.js") # type: ignore
download_search_paths.append(exe_dir / "webdrop_bridge" / "ui" / "download_interceptor.js")
download_interceptor_code = ""
try:
with open(download_interceptor_path, 'r', encoding='utf-8') as f:
download_interceptor_code = f.read()
logger.debug(f"Loaded download interceptor from {download_interceptor_path}")
except (OSError, IOError) as e:
logger.warning(f"Download interceptor not found: {e}")
for path in download_search_paths:
if path.exists():
download_interceptor_path = path
break
if download_interceptor_path:
try:
with open(download_interceptor_path, 'r', encoding='utf-8') as f:
download_interceptor_code = f.read()
logger.debug(f"Loaded download interceptor from {download_interceptor_path}")
except (OSError, IOError) as e:
logger.warning(f"Download interceptor exists but failed to load: {e}")
else:
logger.debug("Download interceptor not found (optional)")
# Combine: qwebchannel.js + config + bridge script + download interceptor
combined_code = qwebchannel_code + "\n\n" + config_code + "\n\n" + bridge_code
@ -492,9 +532,13 @@ class MainWindow(QMainWindow):
script.setSourceCode(combined_code)
self.web_view.page().scripts().insert(script)
logger.debug(f"Installed bridge script from {script_path}")
logger.debug(f"✅ Successfully installed bridge script")
logger.debug(f" Script size: {len(combined_code)} chars")
logger.debug(f" Loaded from: {script_path}")
except (OSError, IOError) as e:
logger.warning(f"Failed to load bridge script: {e}")
logger.error(f"❌ Failed to load bridge script: {e}")
logger.error(f" This will break drag-and-drop functionality!")
# Don't re-raise - allow app to start (will show error in logs)
def _generate_config_injection_script(self) -> str:
"""Generate JavaScript code that injects configuration.