The live API rejects mimes=image/jpeg on /logos and /icons, so every logo and
icon lookup fell back to generated art. Found with a real key: SuperTux now
gets grid, wide, hero and logo; Beat Saber all five.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Title removal ran the Steam shortcut tidy-up before steamos-delete, which
finds the Proton prefix through that shortcut, so compatdata was left behind
(e2e caught it). steamos-delete runs first again; art/collection tidy-up after.
- Test fixtures are byte-exact: never convert line endings (a text-looking
fixture APK got CRLF on Windows and failed its SHA-256).
- Read index.html/artwork-settings.js as UTF-8 in tests; app-data backup and
OBB shell tests run only on POSIX (they exercise the Frame-side scripts).
- e2e expects the icon under artwork/ now.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Automatic backfill touches only entries marked art_pending at install (a
devkit title Steam registered later) and fills only slots Steam has no art
for: no name, exe, VR flag or icon changes, no clearing. Older installs
without the flag are left alone and refreshed only when the user asks.
- Android remove takes the install lock that install and refresh hold, so a
refresh in progress can't recreate a removed app; a refresh after removal
finds it not installed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- 'Refresh artwork' (settings) and the API's refresh-art --all cover devkit
titles as well as Android apps; frame_titles.py gains refresh-art ID|--all.
- Apps and titles without complete Steam artwork are flagged (art_missing):
the app shows 'Add artwork', and the CLIs' list prints the refresh command.
- When the app lists them and Steam answers, Frame Control re-applies their
art in the background (at most every five minutes), e.g. for a title Steam
registered after an install made while it wasn't running.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Remove: collections and artwork clearing are best effort in Steam's JS, and
the host carries on to delete the files when Steam isn't running (Android
apps and devkit titles).
- Devkit titles: the shortcut is found by devkit id, the saved id, or an
executable/start folder inside the title's folder; never by display name.
Steam's overviews don't carry devkit_gameid (checked on the Frame
2026-09-28), so 'list' now reads exe/start dir from app details.
- Photo-based grid/wide/hero slots render as JPEG (a noise-heavy 3840x1240
hero was over 12 MiB as PNG on the Frame); the logo stays transparent PNG.
Rendering gets 75 s and retries once with generated art. Each slot is
cleared before it is set, since Steam keeps .png and .jpg side by side.
- Devkit titles keep their own VR flag (vr=None skips SetShortcutIsVR) and
their Sideloaded collection.
- A failed title install's cleanup can't replace the original error.
- refresh_art for devkit titles (frame_titles.refresh_art).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Any failure of a source image or SteamGridDB (HTTPException, odd JSON) now
becomes a warning and generated art, never an aborted install; refresh-art
--all reports each app and carries on.
- URL artwork goes through apk_sources._images: public addresses only, at most
three redirects, and one overall deadline for all of an install's fetches.
- PNGs are checked from their header only (any depth or interlace; Steam's
Chromium decodes them), JPEGs may have trailing padding, and 4K screenshots
are within limits. The slow pure-Python decoder is gone.
- SteamGridDB title matching keeps letters of every script and never matches
on an empty name. One warning per source slot, not per candidate.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>