mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-07-29 15:28:48 +02:00
perf(disk): byte-cap the cover disk cache with an init sweep
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
@@ -14,6 +15,11 @@ class CoverCacheManager {
|
||||
static const String _cacheKey = 'coverImageCache';
|
||||
static const int _maxCacheObjects = 1000;
|
||||
static const Duration _maxCacheAge = Duration(days: 365);
|
||||
// flutter_cache_manager only caps object count, not bytes; hi-res covers
|
||||
// run 300KB-1.5MB each, so 1000 objects can mean hundreds of MB on a
|
||||
// storage-starved device. Sweep oldest files past the byte cap on init.
|
||||
static const int _maxCacheBytes = 150 << 20;
|
||||
static const int _sweepTargetBytes = 120 << 20;
|
||||
|
||||
static CacheManager? _instance;
|
||||
static bool _initialized = false;
|
||||
@@ -44,11 +50,49 @@ class CoverCacheManager {
|
||||
|
||||
_initialized = true;
|
||||
debugPrint('CoverCacheManager: Initialized successfully');
|
||||
unawaited(_sweepOverByteCap(_cachePath!));
|
||||
} catch (e) {
|
||||
debugPrint('CoverCacheManager: Failed to initialize: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Deletes oldest cover files until the cache is back under
|
||||
/// [_sweepTargetBytes]. Stale JSON repo entries self-heal: a missing file
|
||||
/// is a cache miss and gets re-downloaded on demand.
|
||||
static Future<void> _sweepOverByteCap(String cachePath) async {
|
||||
try {
|
||||
final dir = Directory(cachePath);
|
||||
if (!await dir.exists()) return;
|
||||
|
||||
final files = <File>[];
|
||||
var totalSize = 0;
|
||||
await for (final entity in dir.list(recursive: true)) {
|
||||
if (entity is File && !entity.path.endsWith('.json')) {
|
||||
files.add(entity);
|
||||
totalSize += await entity.length();
|
||||
}
|
||||
}
|
||||
if (totalSize <= _maxCacheBytes) return;
|
||||
|
||||
final stats = <File, FileStat>{
|
||||
for (final file in files) file: await file.stat(),
|
||||
};
|
||||
files.sort(
|
||||
(a, b) => stats[a]!.modified.compareTo(stats[b]!.modified),
|
||||
);
|
||||
for (final file in files) {
|
||||
if (totalSize <= _sweepTargetBytes) break;
|
||||
try {
|
||||
totalSize -= stats[file]!.size;
|
||||
await file.delete();
|
||||
} catch (_) {}
|
||||
}
|
||||
debugPrint('CoverCacheManager: Swept cover cache over byte cap');
|
||||
} catch (e) {
|
||||
debugPrint('CoverCacheManager: Byte-cap sweep failed: $e');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> clearCache() async {
|
||||
if (!_initialized || _instance == null || _cachePath == null) {
|
||||
await initialize();
|
||||
|
||||
Reference in New Issue
Block a user