Replace brittle index-based host resolution in SteamripScraper with substring checks on the chosen download URL (buzzheavier, gofile, vikingfile, megadb). Add a console log for the resolved link and adjust returned values for gofile. Remove the unnecessary links.index lookup and its exception handling.
Simplify SteamripScraper link/name extraction by using BeautifulSoup results directly (append absolute URLs and use link.get_text()) and avoid fragile regex; adjust scrape_steamrip_game_downloads to accept a full URL argument. Update context menu text: replace "Copy Magnet URI" with "Copy Download Link" in two places and rename "Download Item" to "Download" for clearer UI wording.
Introduce check_running(app) to create and check SingleInstance early in main(), store it on app._single_instance, and reuse that instance in run_gui() instead of constructing a new one. Move single-instance exit logic (print, closehelper, force_exit) into the new helper and wire single.on_raise to show_from_tray. Also replace the previous consoleLog call with print and add a comment indicating the check is for SoftwareManager already running. This centralizes startup single-instance handling and avoids creating multiple SingleInstance objects.
contextmenu.py: Harden context-menu handlers by validating row bounds against state.posts, avoid relying on selectedItems() in places where _context_menu_row is used, and handle directory paths when deleting downloads (os.path.isdir or isfile) before send2trash. Also streamline URL opening with exception handling. main.py: Update SERVER_NAME to "SoftwareManager_KeksPirates". These changes prevent out-of-range/selection errors and ensure directories are trashed safely; also update server identification.
Introduce _apply_layout_fast to update the image overlay quickly on window resize using the cached QImage and FastTransformation. Called from the Resize event handler before the resize timer, it handles wallpaper mode (fast scale, center-crop to parent) and non-wallpaper mode (positioning by state.image_position and state.image_offset) to provide immediate visual feedback without running the heavier _apply_layout.
Add a 100ms single-shot QTimer to debounce Resize events and avoid reloading/layout on every resize. Cache the loaded QImage in _cached_qimage/_cached_path and only reload from disk when the image path changes. Extract layout/apply logic into _apply_layout and clear cache in update_image_overlay when a new path is provided. These changes reduce disk I/O and repeated layout work during rapid resizes.
Improve thread-safety, logging, and various bug fixes across the app.
Key changes:
- Add and use state.downloads_lock around accesses to state.active_downloads in multiple modules (UI, libtorrent, misc, direct downloads) to prevent race conditions.
- Prevent concurrent dl_status_loop runs using a non-blocking _loop_lock and ensure proper iteration over a snapshot of downloads.
- Add metadata timeout when waiting for torrent metadata and fix free-space check logic to remove or reject downloads appropriately.
- Refactor download log persistence: add _load_downloads and _save_downloads helpers and centralize JSON read/write logic in utils/logging/logs.py.
- Optimize DirectDownloadStatus speed window by switching to deque and using popleft to trim older samples.
- Trim console log widget to 500 lines to avoid unbounded growth.
- Add small state fields for custom image positioning (x/y and enabled flag).
- Fix Steamrip scraper caching behavior and make Uztracker return an empty list on fetch failures.
- Add defensive checks in run_download to handle missing links.
These changes focus on stability and correctness for concurrent download handling and durable logging.
Capture the original state.image_path at dialog start, connect the Image Path QLineEdit's textChanged signal to update state.image_path immediately, and restore the original image_path if the settings dialog is cancelled. This matches existing undo behavior for width/offset/opacity and prevents partial image path edits from persisting when the dialog is rejected.
Introduce an accent color preference across the app: add a settings UI input (with restart note), persist it to AppState and config (read/write), and accept it in save_settings. Integrate the value into theming: compute a semi-transparent selection color, apply it to table selection styles, and pass it to qdarktheme as the primary color (including when window transparency is enabled). Also apply the accent to the tracker combo selection styling as a UI polish.
Introduce image positioning presets and UI improvements for image overlay control. image.py: compute overlay coordinates for top-left/top-right/bottom-left/bottom-right/center positions and respect corner offset and opacity. settings.py: replace spinboxes with horizontal sliders (with value labels and custom style), add Wallpaper Mode checkbox and Position combo, wire controls to state and include them in the settings tab; ensure dialog rollback restores new temp settings. config/config.py & utils/settings.py: persist and load new image_as_wallpaper and image_position settings and extend save_settings to accept them. data/state.py: add new state fields and properties for image_position, custom position flags and x/y coordinates; change default image_as_wallpaper to false. These changes enable preset positioning, improved UX for sizing/offset/opacity, and persistence of new image options.
Introduce dynamic wallpaper transparency support for the image overlay. Adds QStackedWidget import and a new _set_wallpaper_transparency method that toggles WA_TranslucentBackground on the main window and key child widgets, updates stylesheets (with originals preserved/restored), and uses darkdetect to adapt combo popup background. Adds state fields (_wallpaper_active, _original_stylesheets), sets overlay opacity from state, and calls the transparency toggler when loading/hiding the overlay to avoid redundant updates.
Add image overlay opacity support and related UI/settings, plus robust config migration and error handling.
Key changes:
- UI: image overlay now uses QGraphicsOpacityEffect, hides when disabled, and updates opacity on state changes (src/interface/dialogs/image.py).
- New NotificationPopup dialog for user alerts (src/interface/dialogs/notificationpopup.py).
- Settings dialog: added Image Opacity control, adjusted labels, persist/rollback behavior on cancel, and include opacity when saving (src/interface/dialogs/settings.py).
- State: added properties for image_opacity and image_enabled with change notifications; renamed image_width setter param for clarity (src/utils/data/state.py).
- Config: switch from config.yml to config.ini, implement one-time migration, typed read/write of values, validation/error handling, automatic backups of corrupted files and user notification (src/utils/config/config.py).
- Settings save: accept and persist image_opacity (src/utils/config/settings.py).
- Startup: initialize QApplication earlier and pass app to run_gui (src/main.py).
- Minor: removed an extra blank line in log handler and small import cleanups.
These changes enable adjustable overlay transparency, improve config reliability, and surface errors to users while preserving/backuping old configs.
Save original image_width/image_offset when opening Settings and restore them if the dialog is cancelled. Add valueChanged handlers to immediately update state.image_width and state.image_offset, enforce an image width maximum of 2500, and refactor Save wiring to a dedicated handler that calls save_settings(dialog.accept, ...). Connect dialog.finished to restore temp values on rejection and clean up dialog layout/logic.
Introduce configurable image overlay options and persist them. Added new state fields (image_width, image_offset, image_enabled) with defaults and wired them into the image overlay: the image display now respects the enabled flag, uses image_width for scaling and image_offset for placement. Extended the Settings dialog (resized, API field sizing) with a new Image tab containing enable checkbox, width and offset spinboxes, and included these values when saving. Updated config read/write to include an Image section so settings persist across runs and extended save_settings to accept image_width and image_offset. Minor import/order cleanup in image dialog.
UI: remove trackertable from the Search tab and reorder widgets to correct layout. Tab helper: add QLayout directly instead of wrapping it in a temporary QWidget to avoid extra nesting. Search helper: clear the trackertable rows and reset state.posts when starting a new search to ensure fresh results. Minor: import check_space in main and simplify an unused loop variable in libtorrent_int for clarity/linting.
Rename scraper method get_magnet -> get_download_link in monkrus, rutracker and uztracker. Update downloader code to call .get_download_link and use the .is_magnet flag on tracker objects (replace dict access). Switch direct_download package imports to absolute paths and perform a small import reorder in direct_download/utils.py. These changes unify the download API and adapt call sites to the new tracker interface.