Cobb asked for views + durations back in the subs feed without
giving up the 5-10× RSS speedup vc=56 bought. Hybrid path:
1. Rust wrapper — new enrich_feed_item(video_url) ->
EnrichedFeedMetadata { view_count, duration_seconds }. Thin
wrapper around stream_info that discards the heavy play-URL
payload. Future opt: parse watch-page HTML JSON state directly
to skip JS deobf entirely. ~150 lines of pluck logic, punted.
2. EnrichmentStore — new SharedPreferences-lite store keyed by
videoId, value Enrichment(viewCount, durationSeconds,
fetchedAt). Bound to Settings.cacheTtl for staleness. Hard cap
5000 entries with oldest-eviction.
3. SubscriptionFeedViewModel — after the RSS refresh paints,
enrichVisibleItems() fans out enrichFeedItem for the first 30
items (skipping any already enriched fresh). Bounded at 8 wide
so we don't hammer YT; each call ~500ms full streamInfo so
30 items in ~2s. Runs on StrawApp.globalScope so a
refresh-cancel doesn't kill the in-flight enrichment.
mergeFromCache overlays the enrichment via .withEnrichment()
so RSS rows pick up viewCount + durationSeconds the moment
they land. The Enrichment store's StateFlow.value is read on
every merge call; the enrichment-complete handler triggers a
_ui.update that re-merges.
Net behavior: feed paints instantly from RSS (no view/duration),
~2s later the visible top-N populate with full metadata. Cached
forever (or until TTL/cap). Subsequent opens read straight from
EnrichmentStore.
StrawApp.onCreate inits the new store alongside the existing
SP-backed ones.