All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Tkinter desktop GUI (
gui.py,run-gui.sh): the web UI (FastAPI + React) is now the single graphical frontend.--guiis deprecated and launches the web UI instead. All GUI features (settings persistence, Steam Guard prompts, dry run, stop-app-ids, live logs/report) already had web UI equivalents viaBotController.
-
Web UI — new FastAPI + React interface (
./run-web.shorpython -m steam_idle_bot --web), replacing the Tkinter GUI as the recommended graphical frontend. Minimalist dark-green/emerald design. Live dashboard (status, account, session time, per-game cards/drops/idle table) streamed over WebSocket, full settings editor persisting to.env(password write-only/masked), live color-coded logs with copy/clear/auto-scroll, session report view, and Steam Guard code dialog. Backend:steam_idle_bot.webapi(BotControllerworker-thread lifecycle + REST/WS API on port 8765). Frontend: React 19 + Vite 8 + TypeScript 6 + Tailwind 4 underfrontend/(built assets served by the backend;run-web.shbuilds on demand). A parity test enforces that the React settings form covers everySettingsfield. -
Runner: colored terminal output restored —
run.shroutes bot output through a FIFO (not a TTY), which maderichsilently disable all color; the runner now exportsFORCE_COLOR=1when the real destination is a terminal, and strips ANSI codes from thelogs/runs/transcript copy so it stays greppable. -
Reliability: exponential backoff with jitter on failed reconnects (10s doubling to a 5-minute cap, reset on success) — replaces the fixed 10s cooldown so a Steam outage no longer produces a tight reconnect storm.
-
Terminal panel: the status panel is now reprinted on every refresh interval (not only when the game list changes), so the idle-time and session columns stay live.
-
Packaging:
pyproject.tomlgained a build system (hatchling),steam-idle-botconsole entry point, license/authors/classifiers/urls — groundwork for PyPI publication (pipx install steam-idle-bot). -
CI: ruff lint + format check and mypy now gate the pipeline; coverage floor enforced with
--cov-fail-under=85;pytest-timeout(120s, thread method) kills hung tests. -
Logs:
DetailedLoggeroutputs are now bounded — append-style JSON files keep the last 500 entries andgame_filtering_*.jsonsnapshots are pruned to the newest 50. -
GUI: dark theme — full Tokyo Night-inspired dark palette across all widgets (inputs, treeview, tabs, scrollbars, console, report, badges). Log lines color-coded by level (INFO/WARNING/ERROR/DEBUG/SUCCESS).
-
GUI: keyboard shortcuts —
Ctrl+Enterstart,Escapestop,Ctrl+Lclear logs,Ctrl+Ssave settings. -
GUI: auto-scroll toggle and clear buttons for both Live Logs and Session Report tabs.
-
GUI: all CLI flags now have GUI equivalents —
Keep completed drops,Dry run,Stop App IDsmaintenance,Log Level,Log File. -
GUI: 171 tests covering construction, settings loading/building, status badges, log/report operations, UI events, auth requests, status panel updates, start/stop lifecycle, collapsible sections, keyboard shortcuts, mousewheel scrolling, and the bot worker thread.
-
CLI/config: checkpoint report mode —
--checkpoint-minutes N(CHECKPOINT_MINUTES) writes a structured JSON + Markdown snapshot of the live session (selected games, card counts, drops, durations, totals) tologs/checkpoints/every N minutes;--duration-minutes(DURATION_MINUTES) stops idling after a fixed run length. NewIdleTracker.to_dict(). -
CLI/config: delayed post-run verification —
--post-run-verify-seconds N(POST_RUN_VERIFY_SECONDS) re-scrapes card counts N seconds after stopping, because Steam badge pages can lag behind the actual drops at the moment idling ends. -
CLI:
--stop-app-idsmaintenance mode — stop running steam-utility idles for the given App IDs (JSON or CSV) and exit, without starting the bot. -
Preflight: advisory environment checks for the
steam_utilitybackend — warn when no local Steam client is running, and additionally when no graphical session (DISPLAY/WAYLAND_DISPLAY) is available to launch it. Never aborts; skipped for thepythonbackend and on platforms without/proc. -
steam_utility: idle process reconciliation before starting — existing idles for target App IDs (e.g. from a previous run) are detected via
/proc, the first is reused (adopted), duplicates are stopped, and idles for non-target apps are left untouched and reported. Avoids spawning duplicate idlers across restarts. Linux-only; a no-op without/proc. -
Drops: persistent no-drop cache (
.cache/no_drop_cards.json, per account) — games confirmed without remaining drops are skipped on later runs, so each run scans less. New settingsDROP_CACHE_PATH/DROP_CACHE_TTL_DAYS. -
Auth: session verification before trusting card-drop verdicts — a logged-out / store-only (
web:store) session is detected and reported instead of silently idling drained games. -
Auth: browser cookie recovery — recover a valid
web:communitysession from a locally logged-in browser. New settingsAUTO_BROWSER_COOKIES/BROWSER_COOKIES_BROWSER(via the optionalbrowser-cookie3dependency, import-guarded). -
UX: rich terminal status panel (game names, cards remaining, idle time) at start and on each refresh; resolved game names from the Steam API.
-
UX: card-drop counts parsed from badge pages so the panel and session report show real numbers even when the badge API has no
cards_remaining. -
CLI:
--config PATHto load a custom configuration file. -
CLI/config:
--refresh-interval-secondsflag andREFRESH_INTERVAL_SECONDSsetting (default 600, min 10) to tune how often the selection pipeline re-runs while idling — previously hard-coded to 10 minutes. -
README: language toggle badges (English / Português-BR).
- GUI/UX: dropdowns for fixed-choice fields — Backend, Log Level and Browser are now
read-only
ttk.Comboboxes instead of free-text entries, so typos can no longer fail the Start with a validation error. - GUI/UX: one clear card-filter control — the contradictory "Filter completed drops" + "Keep completed drops" checkboxes were merged into a single "Skip already-farmed games (no drops left)" toggle, removing the confusing inverse-of-an-inverse logic.
- GUI/UX: live card counts in the Status Panel — the "Cards Left" column now shows the
most recent count (
cards_after) while idling, falling back to the start-of-session count. - GUI/UX: polish — numeric fields reject non-numeric input as you type; per-field hover tooltips explain every setting; a "Show password" toggle; the Dry-run option sits right above Start (no longer buried in a collapsed section); the window centers itself on launch.
- GUI: complete UI overhaul — dark theme replacing light palette, reorganized form with collapsible sections (no emoji prefixes), horizontal button row (Start | Stop | Save), themed Treeview status panel, and consistent dark treatment across all widgets.
- Drops: card-drop scraping only re-checks games that still had drops plus new games;
per-game scrape/badge log spam moved to
DEBUG, with concise summaries and scan progress. - Docs (EN/PT-BR): rewritten for clarity — added Authentication & card-drop accuracy guide,
idling backends, caches, GUI, and a full configuration reference;
.envis now the documented primary config path. Security policy now covers cookie handling and the accepted protobuf advisories.
-
Tests: hanging
_main_loopsuite — threetest_main_extra.pyloop tests patchedtime.sleepto break the loop, but_main_loopsleeps viaself.client.sleep(); the no-opDummyClient.sleepnever set the stop event, so the loop span forever (the whole pytest run froze). The tests now drive the stop throughclient.sleep. -
Tests: env-dependent
steam_utilityfailures —TestRunJsonCommandmockedsubprocess.runbutrun_json_commandfirst resolves the project root by filesystem autodiscovery, so the tests passed locally (siblingsteam-utility-multiplataformrepo present) yet failed in CI. They now stubbridge._project_root. -
Tooling: cleaned lint in the new
*_extratest files andgitignores rotated log backups (*.log.*) and local.claude/settings. -
Main loop
UnboundLocalError:new_gameswas referenced outside itsif now - last_refreshblock, causingcannot access local variable 'new_games'errors every ~31 seconds until the first refresh interval triggered. Moved the game-comparison logic inside the refresh block. -
Idle tracker:
update_games()now properly accumulates idle time when games are added/removed mid-session, andend_session()usesstop_game()for consistent timing. -
Card-drop filtering no longer idles fully-farmed games (or misses games with real drops) when the web session is not genuinely authenticated against
steamcommunity.com. -
Terminal status panel now shows a live, growing idle/session duration instead of a frozen
0 min:IdleTrackerdurations fall back to the current time while a session is still running (end_timenot yet set). -
Logging: switched the file handler to a rotating one (10 MB × 3 backups) so a long-running idle session can no longer grow a single log file without bound.
-
Trading-card detection tolerates malformed Steam
appdetailspayloads (e.g. app2321720returning a list where a dict is expected) instead of treating them as errors. -
Shutdown:
SIGINT/SIGTERMnow trigger a graceful stop that still emits the session report and runs cleanup. PreviouslySIGTERM(e.g. whenrun.shis terminated) killed the process before thefinallyreport could run. -
Report: final card counts are now backfilled to 0 for games that started with known cards but are no longer reported by the authenticated badge/scraper read at stop — a drained badge means no remaining drops, so the session report shows a confident before/after instead of
?. Backfill only runs when an authenticated read actually returned data.
- Account-name redaction is now consistent across both idling backends: the shared
utils.redaction.mask_usernamehelper masks the active account name insteam_utilityconnection logs (previously logged in full), matching the python backend. - Documented why
protobufstays pinned<4(enforced bysteam[client]), making advisories GHSA-8qvm-5x2c-j2w7 / GHSA-7gcm-g887-7qv7 non-actionable; accepted as tolerable risk (only trusted Steam-server data is deserialized).