screentinker/frontend
screentinker 04a2ad99d1
Check what is IN a cached update, and add a way to throw it away (#274)
A panel on prod looped on an update it could never apply, reporting a download
failure that was not one.

The staged-APK cache is keyed by FILENAME, and the filename is built from the
version the SERVER advertised. Prod advertised 1.9.34 while still serving the
1.9.33 file, so the panel saved 1.9.33 as `ScreenTinker-1.9.34.apk`. On every
retry it found that file, verified the signature — which passed, same key — reused
it, and installed a no-op. The version never changed, so the update was offered
again. Fixing the server did not help: the poisoned file is reused before anything
is fetched. It took `adb rm` to break the loop.

Two changes:

CHECK THE VERSION INSIDE. A cached APK is reused only when the versionName in the
file matches the version being installed, and a fresh download is checked the same
way before install. A server serving stale bytes now fails with what actually
happened — "server served 1.9.33 but advertised 1.9.34 — the update on the server
is stale" — instead of a download error, and the bad file is deleted rather than
kept to poison the next attempt. That makes this class self-healing: the panel
recovers on its own once the server is fixed.

A WAY TO CLEAR IT. `clear_update_cache` deletes every staged APK across all three
staging directories, with a button on the device page next to Force Update. Gated
on `system.self_update` — a player that can update itself is one that can hold a
bad download. Only caches are deleted; they are re-fetched on demand.

The version check should make the button rarely necessary. It exists because it
would have turned tonight's hands-on ADB recovery into one click, and because a
panel already holding a bad file predates the fix and cannot benefit from it.

1668/1668 pass; Android unit tests and lint clean.
2026-08-14 08:37:05 -05:00
..
assets Landing: replace iframe mock with dashboard screenshot 2026-04-21 19:47:13 -05:00
compare feat(seo): strengthen integrations internal linking + drop public status link (#178) 2026-07-13 12:11:30 -05:00
css Fix main content width shrinking to narrow column 2026-08-10 22:14:10 +00:00
guides Pi installer: stop advertising what was never installed (#245) 2026-08-10 10:50:34 -05:00
integrations feat(seo): strengthen integrations internal linking + drop public status link (#178) 2026-07-13 12:11:30 -05:00
js Check what is IN a cached update, and add a way to throw it away (#274) 2026-08-14 08:37:05 -05:00
legal docs(privacy): disclose error and diagnostic telemetry from players 2026-05-15 15:31:21 -05:00
vendor test(api): fix spec scope drift + guard it in CI; Redoc provenance 2026-06-12 18:45:09 -05:00
41498e6c84045d9d187f4504c122e54f.txt feat(seo): IndexNow + landing-page optimization (schema, FAQ, CWV, content) (#177) 2026-07-13 11:22:37 -05:00
agency.html feat(agency): per-token upload folder — auto-created, subtree-confined (#158) (#171) 2026-07-12 21:23:25 -05:00
api-docs.html docs(api): OpenAPI spec, Redoc at /docs, CI spec-lint 2026-06-12 18:45:09 -05:00
index.html Fix banner shifting whole dashboard layout 2026-08-10 22:06:45 +00:00
landing.html feat(seo): strengthen integrations internal linking + drop public status link (#178) 2026-07-13 12:11:30 -05:00
manifest.json Initial open source release 2026-04-08 12:14:53 -05:00
robots.txt SEO: add meta tags, sitemap, robots.txt, comparison pages, guides, internal linking 2026-04-28 20:54:32 -05:00
sitemap.xml feat(seo): IndexNow + landing-page optimization (schema, FAQ, CWV, content) (#177) 2026-07-13 11:22:37 -05:00
sw-admin.js fix(sw): stop the admin service worker from breaking video playback 2026-06-08 23:08:13 -05:00