All notable changes to Steam Library Manager will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Statistics i18n - all chart labels fully translated (Deck status, ProtonDB tiers, review scores, PEGI ratings, achievement buckets, playtime ranges). Labels built lazily to avoid circular import issues at module init.
- Genre tab - falls back to Steam tags when game_genres table is empty.
- Comparison tab - triggers on autocomplete selection (not just Enter). HLTB values rounded to 1 decimal place.
- Donut "Others" overflow bucket label translated.
- Readable bucket labels - all internal keys (op_95, lt_1h, etc.) replaced with human-readable text in all chart legends.
- Statistics screenshots (EN + DE) in README.
- Statistics Dashboard - complete overhaul with 7 interactive tabs:
- Overview: 4 metric cards (total games, playtime, never played, perfect games)
- genre donut chart + top 5 most played bar chart
- Genre: side-by-side donuts (by count vs by playtime) with insight text showing "You own most RPGs but play Shooters the most"
- Platform: 3 donuts showing real per-platform playtime (Windows/Linux/ Steam Deck/Mac), Deck compatibility status, and ProtonDB tier distribution
- Achievements: metric cards (unlocked, rare, ultra-rare, perfect) + completion buckets donut + almost-done bar + Trophy Wall with cover art
- Playtime: playtime buckets + HLTB analysis + shame pile (installed never-played games sorted by HLTB estimate)
- Ratings: PEGI distribution + review score buckets + top 10 developers
- Comparison: search and compare any 2 games side-by-side across all metrics
- Overview: 4 metric cards (total games, playtime, never played, perfect games)
- Chart Engine - custom QPainter-based DonutChart and BarChart widgets with hover effects, responsive legends, and "Others" bucketing. No external charting dependencies.
- Platform Playtime Tracking - per-platform playtime (Windows, Linux, Mac, Steam Deck) persisted in database from Steam API. Shows where you actually play instead of just "supported platforms".
- Playtime Persistence - game playtime and last-played timestamps saved to SQLite database, surviving Steam API outages.
- DB Schema v11 - added playtime_minutes, last_played, playtime_windows, playtime_linux, playtime_mac, playtime_deck columns to games table.
- Statistics dialog rebuilt as tabbed package (
ui/dialogs/statistics/) replacing the old 177-line monolithic dialog.
- API keys not loading from keyring - circular import at module init time prevented TokenStore from loading keys. Now deferred to bootstrap phase.
- i18n: Massive cleanup - eliminated 120+ duplicate translation keys across
all JSON files. Common terms (Username, Password, Settings, Name, Platform,
etc.) consolidated into
common.json. Cloud Sync keys moved frommain.jsontosettings.jsonwhere they belong. - i18n: rclone setup dialog - German labels ("Passwort", "Benutzername")
hardcoded in Python source replaced with proper
t()calls. English users no longer see German UI text.
- DRY: User-Agent constants - Chrome and app User-Agent strings centralized
in
config.py(USER_AGENT_BROWSER,USER_AGENT_APP), replacing 7 scattered hardcoded copies. - DRY: Database path - duplicated
_get_db_path()in 4 action files replaced with a singleMainWindow.db_pathproperty.
- Steam Store rate limiting - increased request interval to 1.5s and added automatic 30s backoff on HTTP 429 responses. Prevents Steam from DNS-blocking the client during bulk PEGI rating fetches.
- Network error abort - all enrichment threads now abort after 3 consecutive DNS resolution or rate-limit errors instead of pointlessly retrying thousands of requests against an unreachable server.
- API keys moved to system keyring -
STEAM_API_KEYandSTEAMGRIDDB_API_KEYare now stored in the OS keyring (or encrypted file fallback) instead of plaintextsettings.json. Existing keys are auto-migrated on first launch.
- Steam-Running false positive:
steam.pipepersists after Steam exits, causing SLM to always detect Steam as running. Now uses non-blocking pipe open to check if Steam is actually reading the pipe (ENXIO = not running). Fixes GitHub #12.
- Flatpak: Steam-Running detection: The Steam-running warning never appeared
when running as Flatpak because
psutil.process_iter()cannot see host processes from inside the sandbox. Now checks for Steam's named pipe (~/.steam/steam.pipe) first, which is visible via--filesystem=~/.steam:ro. Falls back to psutil for native installations.
- Flatpak dependencies: Added missing
pybind11(Pillow build dependency) andsix(steam library dependency) to Flatpak manifest.
- Crash on First Run (again): Profile setup dialog crashed with
AttributeError: 'ProfileSetupDialog' object has no attribute 'selected_steam_id_64'. The AI-slop refactoring shortenedselected_steam_id_64tosidandselected_display_nametonamebut main.py still used the old names (GitHub #11). - Force Refresh broken: After HLTB or Steam API enrichment, the force-refresh
prompt never appeared because
enrichment_starters.pyreferenceddialog.wants_force_refreshinstead of the renameddialog.force_refresh. - Crash on category drag-drop: Dragging games onto a category in the sidebar
crashed because
category_change_handler.pyreferenceddetails_widget.current_gameinstead of the renameddetails_widget.game. - Pre-update save broken: The update dialog tried to call the non-existent
game_manager.save_to_cloud()before restarting. Now correctly callsMainWindow.save_collections()to persist collections before auto-update.
- Crash on First Run: Profile setup dialog crashed on startup for new
users (GitHub #10). The
_foundlist attribute shadowed the_found()signal handler, causing a TypeError when connecting the account scan signal.
- PEGI Enrichment: Age rating enrichment never worked due to a parameter name mismatch in configure() (silent TypeError). Both individual and bulk enrichment are now functional.
- New Games: Newly purchased games are now automatically synced to the database on startup with full metadata and tags from appinfo.vdf.
- Smart Collections: Games matched by smart collections no longer appear in "Ohne Kategorie" (uncategorized).
- Enrich All Dialog: PEGI chain failure no longer blocks the progress dialog from closing.
- Smart Collections: PEGI age rating (Altersfreigabe) available as filter field (3, 7, 12, 16, 18).
- Flatpak: Manifest updated with all required finish-args for Lutris, Heroic, Bottles, itch.io, and Flatpak game detection.
- Crash: Games with integer developer/publisher fields in appinfo.vdf (e.g. Cherry Tree Comedy Club) caused a TypeError on startup.
- Split
game_service.load_and_prepare()into focused submethods. - Centralize timeout/delay constants in
utils/timeouts.py. - Standardize copyright headers on all source files.
- 24 database migration tests covering schema v3 through v9.
- Packaging: Database schema SQL file was missing from built wheel/package, causing database creation to fail on first run (AUR, pip install).
- Removed unused legacy database_schema.sql (superseded by core/db/schema.sql).
- Smart Collections: Automatic sidecar backup (smart_collections.json) on every create/update/delete. Auto-recovery on startup when the database is empty, so Smart Collections survive installation or device changes.
- Curators: Auto-register existing curators from Steam collections when opening the management dialog. Fuzzy name matching strips emojis, punctuation, and whitespace for reliable preset detection.
- Curators: Cloud storage parser as additional source for collection names, catching dynamic/filter-based collections that game_manager does not see.
- Collections: Steam-internal names "favorite" and "hidden" (lowercase English) are now recognized as protected system collections and sort correctly instead of appearing alphabetically in the sidebar.
- Smart Collections: Brain emoji now appears as suffix (after name, before count) consistent with dynamic and external platform collection emojis.
- Smart Collections: Name validation in SmartCollectionManager.create() prevents saving collections without a name.
- Curators: Popular/Top Curators dialogs now have scroll areas and a max height so they don't fill the entire screen on smaller displays.
- Smart Collections: Achievement percentage, total, unlocked, and perfect were never loaded from database into Game objects at startup, causing achievement-based Smart Collections to always show 0 results.
- Smart Collections: tag_ids were not transferred during database enrichment, breaking tag-based filtering.
- Smart Collections: BETWEEN operator now auto-swaps reversed min/max values so "BETWEEN 50 30" works the same as "BETWEEN 30 50".
- Release Dates: Refactored release_year from string to UNIX timestamp (int) across the entire codebase. Dates are now stored and compared as timestamps internally, displayed as localized strings only in the UI. Added to_timestamp() and year_from_timestamp() date conversion helpers.
- Date Parsing: Steam API date strings (English month names like "Oct 10, 2007") are now parsed correctly regardless of system locale.
- Security: JWT access tokens no longer leak into log files when HTTP errors occur. Exception messages are now sanitized to show only the status code or exception type.
- Security: Token file (tokens.enc) and settings file (settings.json) are now written with owner-only permissions (0o600).
- Enrichment: Fixed PEGI track counter logic in EnrichAllCoordinator that could cause double-increment or missed completion signals.
- Stability: Fixed database connection leaks in menu builder and enrichment coordinator (could cause "database is locked" errors).
- Thread Safety: HLTB client endpoint discovery is now protected by a threading lock to prevent concurrent races.
- Thread Cleanup: External Games dialog now properly waits for background threads before closing.
- Removed UIHelper dependency from CategoryService (service layer violation).
- Replaced silent exception swallowing with proper logging in achievement enrichment and HLTB API endpoint discovery.
- Dock Integration: Unified StartupWMClass across all .desktop files to match Wayland app_id (io.github.switch_bros.SteamLibraryManager). Fixes Cairo Dock, Plank, and other docks not recognizing the app window.
- AppImage Update: Desktop entry now updates after AppImage self-update, so the application launcher always points to the correct binary.
- AppImage Naming: Simplified to version-free filename (SteamLibraryManager-x86_64.AppImage) to avoid stale paths after updates.
- Pyright: Fixed type warnings in update service (QByteArray conversion, optional QNetworkReply checks).
- AUR: Removed checkdepends/check() to fix paru dependency resolution.
- Steam Deck Support: Responsive UI scaling for 1280x800 displays. Gallery images, metadata grid, and spacing automatically adapt to smaller screens. Handles rotated displays (Deck is natively 800x1280 portrait).
- Library Auto-Sync: Automatically reconcile saved library paths with Steam's libraryfolders.vdf on startup. Removes dead paths (e.g. after drive swap), adds new paths Steam reports. Skips dead VDF entries.
- Multi-Format Packaging: New .deb, .rpm, and tar.gz packages alongside existing AppImage and AUR. CI/CD builds all formats automatically on release.
- Tests: Fixed 3 pre-existing test failures in test_file_actions.py (Mock parent widget crash in force_save dialog)
- Module Rename:
src/renamed tosteam_library_manager/for PEP 423 compliance. The generic module namesrcconflicts with other packages when installed system-wide.steam_library_manageris globally unique and enables proper Python packaging. (Requested by AUR user yochananmarqos)
- AUR: DATA_DIR now uses XDG_DATA_HOME for all install types (fixes PermissionError crash)
- AUR: Icons use correct reverse-DNS names (io.github.switch_bros.SteamLibraryManager)
- Images: All PEGI icons, default placeholders, and QR login converted from PNG to WebP
- Steam Library Management: Full collection management with cloud sync
- 16 AutoCat Types: Genre, Tags, Playtime, HLTB, Review Score, Developer, Publisher, Platform, Language, Release Year, Store Tags, Flags, PEGI Rating, Steam Deck Compatibility, ProtonDB Rating, Hybrid Rule Groups
- Smart Collections: AND/OR/NOT boolean logic with 21 filter fields and 12 operators (what Steam can't do)
- External Games: 9 platform parsers (Heroic Epic/GOG/Amazon, Lutris, Bottles, itch.io, Flatpak, ShortcutsVDF, ROM Emulation with 16 emulators across 10 systems)
- Data Enrichment: HLTB (94.8% match rate via Steam Import API), ProtonDB, Steam Deck compatibility, Steam Store metadata, Steam Curator recommendations with overlap scoring
- Secure Auth: QR code + password login, keyring + AES-GCM fallback token storage, automatic token refresh
- Import/Export: VDF, CSV (Simple + Full), JSON, Smart Collections JSON, Database backup with rotation
- Library Health Check: Store availability, data completeness, cache analysis
- Curator Enhancement: DB persistence, enrichment pipeline, management dialog, auto-discovery (top curators + subscribed), JSON export/import with merge logic
- Game Discovery: licensecache decryption (Valve XOR cipher) x packageinfo.vdf cross-reference for complete owned games detection (incl. F2P, gifted, key-redeemed)
- Keyboard Shortcuts: 15+ shortcuts, layered ESC, Konami code Easter egg
- Multilingual: Full English + German UI with zero hardcoded strings and separate tag language setting
- Profiles: Save/restore complete configuration states
- AppImage Auto-Update: GitHub Releases API check, download with progress, atomic replace + rollback
- Dual-Language README: English + German with dark/light theme support
- 186 Python source files, 104 test files, 1567 tests passing
- SQLite database Schema v9 (curators, curator_recommendations tables, 10 modular database modules using mixin pattern)
- Zero hardcoded strings (complete i18n with 17 JSON files)
- Linux-first with PyQt6 (Wayland + X11)
- Pre-commit hooks: Black, flake8, mypy enforced