feat(cache): CacheFiller background metadata sweeper
Periodic worker that walks cached_artists for missing album lists and cached_albums for missing track lists, then fills them via /api/artists/:id + /api/albums/:id. Newly-discovered album covers are pre-warmed into flutter_cache_manager's disk cache too. Solves the "tap an artist → empty album area → pop in" experience: artistAlbumsProvider was drift-first but the cache only got populated when the user navigated TO an artist. SyncController's /api/library/sync delta doesn't carry per-artist album lists (those are query-time derived). Now the filler pre-populates them in the background so the drift hit is real on first tap. Pacing (intentionally conservative): * 10-second initial delay so SyncController has time to land its first sync — the WHERE NOT EXISTS query has nothing to do until cached_artists is populated. * 5-minute interval thereafter. Once steady state is reached the sweep is a cheap drift query + early exit. * 200ms throttle between per-entity REST requests — never competes with active playback. * 200 entities per sweep cap so a fresh install with thousands of artists doesn't tie up the network for one continuous run. Next sweep picks up where this one left off (NOT EXISTS naturally skips already-filled rows). Wall time estimate for a 1000-artist library: ~3-4 minutes spread over multiple sweeps. Single round-trip per artist (new getArtistDetail API method returns artist + albums in one shot). Activated from app.dart's postFrameCallback alongside the existing SyncController / Prefetcher / MetadataPrefetcher / LiveEvents hooks. Disposed via ref.onDispose when the provider scope tears down (effectively process death in practice).
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'cache/cache_filler.dart';
|
||||
import 'cache/metadata_prefetcher.dart';
|
||||
import 'cache/prefetcher.dart';
|
||||
import 'cache/sync_controller.dart';
|
||||
@@ -39,6 +40,14 @@ class _MinstrelAppState extends ConsumerState<MinstrelApp> {
|
||||
// arrive. Also installs an AppLifecycleState observer for
|
||||
// resume-time defensive invalidation.
|
||||
ref.read(liveEventsDispatcherProvider);
|
||||
// Cache filler: background sweeper that walks cached_artists
|
||||
// / cached_albums for missing relations and fetches the
|
||||
// per-entity detail so tapping an artist surfaces albums
|
||||
// immediately (drift hit, no /api/artists/:id round-trip at
|
||||
// tap time). First sweep 10s after launch; every 5 minutes
|
||||
// thereafter. Throttled 200ms between requests so it never
|
||||
// competes with user activity.
|
||||
ref.read(cacheFillerProvider);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user