From c08f4ace80be9e0bd3eb71ed09a86cb1029198b8 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 11 May 2026 17:41:07 -0400 Subject: [PATCH] fix(flutter): cache usage display reflects actual disk, not just index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Storage card has been showing "0 B" for users who only stream (never explicitly pin or download an album). usageBytes() summed SUM(size_bytes) from audio_cache_index — but the streaming path through audio_handler writes files via LockCachingAudioSource without ever inserting an index row, so the index undercounts (often to zero) for normal use. Walk the cache directory instead. Catches everything on disk: manually pinned tracks (registered in the index), stream-cached tracks (LockCaching), partial downloads. Falls back gracefully when a file is racing against concurrent writes / deletes. Eviction still operates on the index (it needs the source/recency metadata to pick eviction order). Stream-cached files aren't subject to eviction today — separate problem; addressed when we wire a download-complete hook from LockCaching back into the index. --- .../lib/cache/audio_cache_manager.dart | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/flutter_client/lib/cache/audio_cache_manager.dart b/flutter_client/lib/cache/audio_cache_manager.dart index 9733eba9..34a4a061 100644 --- a/flutter_client/lib/cache/audio_cache_manager.dart +++ b/flutter_client/lib/cache/audio_cache_manager.dart @@ -96,13 +96,25 @@ class AudioCacheManager { .go(); } - /// Total bytes used by the cache. + /// Total bytes used by the cache. Walks the cache directory directly + /// instead of summing the index, because the streaming-as-you-play + /// path (audio_handler's LockCachingAudioSource) writes files + /// without registering an index row. The index sum would always + /// understate (often to zero) for users who only stream. Future usageBytes() async { - final result = await _db.customSelect( - 'SELECT COALESCE(SUM(size_bytes), 0) AS total FROM audio_cache_index', - readsFrom: {_db.audioCacheIndex}, - ).getSingle(); - return result.read('total'); + final dir = Directory(await _tracksDir()); + if (!await dir.exists()) return 0; + var total = 0; + await for (final entity in dir.list(followLinks: false)) { + if (entity is File) { + try { + total += await entity.length(); + } catch (_) { + // Race against concurrent writes / deletes — just skip. + } + } + } + return total; } /// Evicts files until usage ≤ targetBytes. Eviction order: