A 7-slide carousel shown once on first launch:
- the three tabs (Scenes/Movies/Sites)
- search, filters, saved searches, Performers/Tags/Favorites
- long-press actions (hide/duplicate a scene, remove a wrong performer, link diagnostics)
- player gestures (tap controls, double-tap ±15s, swipe to scrub, unmute)
- favorites, Hidden content, PIN lock, the ? report button, Sites ★ ratings
Gated by a SecureStore flag; replayable from Settings ⚙ → Replay tutorial (via a
tiny onboarding bus). Suppresses the What's-new popup for brand-new users (the tour
covers it) and marks the changelog seen on finish.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rates each source on three axes the user asked for:
- freshness: how recently/often new content arrives (newest age + 7d volume)
- richness: metadata coverage (thumbnail/tags/performers/description/studio/duration)
- plays: does it actually play — from real playback telemetry when available,
else a proxy from the resolve mechanism. 0★ = offline (gates the overall stars,
so a fresh+rich source that doesn't play still ranks bottom — the hqfap/4k69 case)
Backend:
- playback_events: fire-and-forget telemetry POST from the app per playback attempt
(origin + success/error + time-to-first-frame), append-only, 30d retention
- source_stats: per-origin computed scores, refreshed by a scheduler job (6h);
/sources joins it and sorts by stars
- models + local migration 0025; new GOON_SCHED_SOURCE_STATS_HOURS setting
Mobile:
- Sites rows show ★ rating; tap the stars for a breakdown (axes + metadata %, plus
whether "plays" is measured or estimated)
- PlayerScreen reports playback success/failure per source (native path only —
symmetric, conservative); origin threaded through Scene/Movie play callsites
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two Movies-list reports. (1) 1044cd34 'do movies have a metadata base for performers/categories/studio/year': yes — 90% have year, 92% studio, 81% performers, 93% tags, and the filter already covered studio/genre/year. Added the missing dimension: a performer search-and-select in MovieFiltersSheet (backend listMovies + api.ts already accepted performer_ids; only the UI was missing). (2) 0200956f 'use the space better': Movies grid goes 2 -> 3 columns (poster card is flex:1, scales fine) so ~50% more films per screen.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Report dc4e91fb: double-tapping to skip ±15s also called setControlsVisible(true), throwing the full controls (big center pause button) on screen for 3.5s. Seek already has its own ±15s hint overlay, so the controls pop was redundant — removed it. Single-tap still toggles controls.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
User-report 18105d14: drop the TLD suffix from Sites list + SiteScenes header (hqporner.com -> hqporner, fpo.xxx -> fpo). Logos skipped (needs a per-site logo source) — TLD strip is the quick win.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
User-report 86a9ec72 ('remove all gay scenes from randomly popping up'): there was no UI to hide a tag, nor to view/undo the blacklist — even though the 'Hide performer' alert promised 'undo from Settings -> Blacklist' (a screen that never existed). New BlacklistScreen: search-and-add any tag to hide (e.g. a category), plus manage/unhide all blacklisted tags/performers/studios. Reached via Settings -> Content -> Hidden content. Backend already drops blacklisted-entity scenes from every /scenes (device-scoped); this just exposes it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Returning to the Scenes list from a scene caused a full reload + phone load spike (report 5df48551). Cause: invalidateQueries(['scenes']) in SceneDetail/Player/Performer/Studio handlers — including the silent auto-enrich-thumbnail that fires on opening any thumbnail-less scene — forces react-query to refetch EVERY loaded page of the infinite list. Added refetchType:'none' to all ['scenes'] invalidations: marks stale without refetching the active list, which refreshes on pull-to-refresh / filter change instead. Scene detail (['scene', id]) still updates immediately.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(1) Scroll jank/device load on long scene lists (report 5b7ca1e1): SceneTile is now React.memo'd so typing in search no longer re-renders every mounted tile, and sceneGridProps bounds the render window (windowSize 7 etc.) — required because removeClippedSubviews stays false to avoid thumbnail blanking. Applies to all scene grids. (2) fpoxxx played an ad instead of the video via the WebView fallback (reports f79beefb/cfa207c7). fpoxxx is KVS with an IP-bound + session-bound get_file token (cross-IP 403 confirmed), so it must resolve phone-side: new fpoxxxResolver fetches the page + follows get_file on the device (KVS real_url port for the function/0 case), wired into SceneDetailScreen like sxyprn/eporner. Verified from a residential IP: get_file -> CDN returns 206 video/mp4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Batch from user feedback: (1) Grid columns 1/2/3 setting (PreferencesContext, persisted) across all scene grids — default 2 was too small on phones. (2) Min-duration filter chips (5/10/20/30+ min) to hide ad-clips. (3) Saved-search chips + Save button (backed by /saved-searches). (4) Re-enabled screen-capture protection (Recents hide + screenshot block) for distributed users — verified active on emulator (screencap returns 0 bytes). (5) 'Checking for updates' gate before the PIN screen so a background OTA restart no longer causes a double PIN prompt. Changelog entry added. Published OTA runtime 1.1 (a9620b12).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- AppLockSettings: a "Source code" row linking the public OSS repo (report 4c5066b8) -
a trust signal for a sideloaded FOSS app (audit / self-host / contribute).
- SceneDetail: a "Refresh thumbnail" button (force) for scenes whose preview is broken
or stale (report d3376a71).
- changelog: new What's New entry for this batch.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
After an OTA bundle is applied, show a one-time popup listing recent changes. The
changelog ships in the bundle (mobile/src/changelog.ts), so it is always in sync with
the code that just arrived. WhatsNewModal compares the newest entry id against the last
one seen (SecureStore); shows unseen entries, marks seen on dismiss, and stays quiet
until the next update adds an entry. First run shows only the newest entry (no history
dump). Mounted over the navigator when signed in.
Each OTA publish should prepend a new entry at the top of CHANGELOG.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>