Files
minstrel/flutter_client/lib/cache/shuffle_source.dart
T
bvandeusen 035b000bb0 fix(analyze): drop unused drift import in shuffle_source
Query-builder methods come through the generated AppDb, not the
drift package directly — the import was dead. (#427 S4a)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:44:46 -04:00

68 lines
2.2 KiB
Dart

// "Shuffle all" source (#427 S4). Always-present; the pool degrades
// gracefully with reachability:
// online → GET /api/library/shuffle (random over the whole library)
// offline → a client shuffle over the entire local cache index
//
// Offline is a UNION over every cached track regardless of storage
// bucket — liked AND recently-played both included. The two-bucket
// split (S2) is storage/eviction-only and never filters playback,
// which is exactly the property this relies on.
import 'dart:math';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../library/library_providers.dart' show libraryApiProvider;
import '../models/track.dart';
import 'adapters.dart';
import 'audio_cache_manager.dart' show appDbProvider;
import 'offline_provider.dart';
class ShuffleSource {
ShuffleSource(this._ref);
final Ref _ref;
/// Returns up to [limit] tracks to play as a shuffle-all. Online:
/// server-random. Offline: every cached track (liked + recent),
/// shuffled client-side. Empty offline → nothing is cached yet.
Future<List<TrackRef>> tracks({int limit = 100}) async {
if (_ref.read(offlineProvider)) {
return _offline(limit);
}
final api = await _ref.read(libraryApiProvider.future);
return api.shuffle(limit: limit);
}
Future<List<TrackRef>> _offline(int limit) async {
final db = _ref.read(appDbProvider);
final cachedIds =
(await db.select(db.audioCacheIndex).get()).map((r) => r.trackId).toSet();
if (cachedIds.isEmpty) return const [];
final meta = await (db.select(db.cachedTracks)
..where((t) => t.id.isIn(cachedIds.toList())))
.get();
if (meta.isEmpty) return const [];
final artistName = {
for (final a in await db.select(db.cachedArtists).get()) a.id: a.name
};
final albumTitle = {
for (final a in await db.select(db.cachedAlbums).get()) a.id: a.title
};
final refs = [
for (final t in meta)
t.toRef(
artistName: artistName[t.artistId] ?? '',
albumTitle: albumTitle[t.albumId] ?? '',
)
];
refs.shuffle(Random());
return refs.length > limit ? refs.sublist(0, limit) : refs;
}
}
final shuffleSourceProvider =
Provider<ShuffleSource>((ref) => ShuffleSource(ref));