e856172d60
Cleanup pass on the noisy debugPrints we added during the recent debugging sessions. Remaining prints are error-path only: - AlbumCoverCache fetch failed - album/playlist cold-cache fetch failed - audio_handler playbackEventStream error - audio_handler queue supersession (rare race) - audio_handler forward/backward fill failed - artist_detail play failed - cacheFirst fetchAndPopulate failed (only when tag is set) Removed per-event chatter: - audio_handler player-state and processingState subscribers - audio_handler timing measurements (built initial / setAudioSources / forward fill / backward fill) - audio_handler cache hit/miss per-track (fired N times per play) - audio_handler register stream cache (verifiable via Settings) - audio_handler.configure log - albumProvider step-by-step lines (drift miss / online / drift hit / album hit but no tracks) - playlistDetailProvider step-by-step lines (calling get / drift write done / 404 evicted / drift hit / playlist hit but no tracks) - playlistsListProvider wire returned + drift rows lines - playTracks stage timings (serverUrl / token / configure / setQueue / play returned) - metadataPrefetcher warming N artists - artist_detail play tapped — N tracks success log - cacheFirst step-by-step (drift hit / drift miss / online / done) `tag` parameter on cacheFirst preserved for ad-hoc instrumentation.
75 lines
2.6 KiB
Dart
75 lines
2.6 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../library/library_providers.dart';
|
|
import '../models/home_data.dart';
|
|
|
|
/// Pre-warms the drift cache for likely-tap targets. Conservative on
|
|
/// purpose: only warms artistProvider rows (single row, single round
|
|
/// trip per id) and only ever fires once per id per session. Album
|
|
/// detail is NOT prewarmed — the albumProvider auto-fetches its track
|
|
/// list when missing, and pre-warming N albums fans out N parallel
|
|
/// "fetch tracks" round trips that compete with the user's actual
|
|
/// playback request for bandwidth.
|
|
class MetadataPrefetcher {
|
|
MetadataPrefetcher(this._ref) {
|
|
_ref.listen<AsyncValue<HomeData>>(homeProvider, (_, next) {
|
|
next.whenData(_warmHome);
|
|
});
|
|
}
|
|
|
|
final Ref _ref;
|
|
|
|
/// Per-session dedupe so re-rendering a screen (every UI rebuild
|
|
/// fires the data: callback) doesn't trigger N more fetches for
|
|
/// ids we've already warmed.
|
|
final Set<String> _warmedArtists = {};
|
|
|
|
/// Cap per section. Covers what fits on screen without scrolling.
|
|
static const _topN = 8;
|
|
|
|
/// Pre-warm artists. Albums are intentionally not pre-warmed —
|
|
/// see class comment.
|
|
void warmArtists(Iterable<String> ids) {
|
|
var n = 0;
|
|
for (final id in ids) {
|
|
if (id.isEmpty) continue;
|
|
if (!_warmedArtists.add(id)) continue; // already warmed
|
|
if (n++ >= _topN) break;
|
|
_swallow(_ref.read(artistProvider(id).future));
|
|
}
|
|
}
|
|
|
|
void _warmHome(HomeData h) {
|
|
final artistIds = <String>{};
|
|
for (final a in h.recentlyAddedAlbums.take(_topN)) {
|
|
if (a.artistId.isNotEmpty) artistIds.add(a.artistId);
|
|
}
|
|
for (final a in h.rediscoverAlbums.take(_topN)) {
|
|
if (a.artistId.isNotEmpty) artistIds.add(a.artistId);
|
|
}
|
|
for (final ar in h.rediscoverArtists.take(_topN)) {
|
|
if (ar.id.isNotEmpty) artistIds.add(ar.id);
|
|
}
|
|
for (final ar in h.lastPlayedArtists.take(_topN)) {
|
|
if (ar.id.isNotEmpty) artistIds.add(ar.id);
|
|
}
|
|
for (final t in h.mostPlayedTracks.take(_topN)) {
|
|
if (t.artistId.isNotEmpty) artistIds.add(t.artistId);
|
|
}
|
|
warmArtists(artistIds);
|
|
}
|
|
|
|
/// Discards the return value and any error from a fire-and-forget
|
|
/// provider read. We don't care about the value here — we only want
|
|
/// the side effect of writing drift.
|
|
void _swallow(Future<Object?> f) {
|
|
f.then<void>((_) {}).onError((_, __) {});
|
|
}
|
|
}
|
|
|
|
/// Read once at app start to activate the prefetcher (e.g. wire it
|
|
/// from a top-level Consumer or main.dart container override).
|
|
final metadataPrefetcherProvider = Provider<MetadataPrefetcher>((ref) {
|
|
return MetadataPrefetcher(ref);
|
|
});
|