fix(download): restore fast SQL-only duplicate check so huge playlists queue again

This commit is contained in:
zarzet
2026-07-27 01:43:56 +07:00
parent c42a1be76c
commit 55be8fc827
2 changed files with 25 additions and 27 deletions
+10 -20
View File
@@ -1063,34 +1063,24 @@ final downloadHistoryExistsProvider = FutureProvider.autoDispose
);
});
// Deliberately no per-row verifyOrRepairHistoryItem here (issue #495): on a
// >500-track playlist that verify pass meant one SAF stat round-trip per
// already-downloaded track, and any loadedIndexVersion bump mid-pass restarted
// it from zero — above ~500 tracks the future never settled and "Download all"
// silently did nothing. Stale rows are reconciled by the startup repair and
// orphan-cleanup passes; the single-track provider above keeps the verify.
final downloadHistoryBatchExistsProvider = FutureProvider.autoDispose
.family<Set<String>, HistoryBatchLookupRequest>((ref, request) async {
ref.watch(
downloadHistoryProvider.select((state) => state.loadedIndexVersion),
);
final notifier = ref.read(downloadHistoryProvider.notifier);
final rows = await HistoryDatabase.instance.findExistingTracks(
request.tracks,
);
final found = <String>{};
const chunkSize = 16;
for (var start = 0; start < rows.length; start += chunkSize) {
final end = min(start + chunkSize, rows.length);
final checks = await Future.wait(
List.generate(end - start, (offset) async {
final index = start + offset;
final row = rows[index];
if (row == null) return null;
final exists = await notifier.verifyOrRepairHistoryItem(
DownloadHistoryItem.fromJson(row),
);
if (!exists) return null;
return request.tracks[index].lookupKey;
}),
);
found.addAll(checks.whereType<String>());
}
return found;
return <String>{
for (var i = 0; i < rows.length; i++)
if (rows[i] != null) request.tracks[i].lookupKey,
};
});
class DownloadedAlbumTracksRequest {
+15 -7
View File
@@ -7,6 +7,7 @@ import 'package:spotiflac_android/providers/extension_provider.dart';
import 'package:spotiflac_android/providers/library_collections_provider.dart';
import 'package:spotiflac_android/providers/local_library_provider.dart';
import 'package:spotiflac_android/providers/settings_provider.dart';
import 'package:spotiflac_android/utils/logger.dart';
import 'package:spotiflac_android/widgets/download_service_picker.dart';
import 'package:spotiflac_android/widgets/view_queue_snackbar_action.dart';
@@ -142,13 +143,20 @@ Future<void> queueTracksSkippingDownloaded(
final historyLookups = tracks
.map(historyLookupForTrack)
.toList(growable: false);
final existingHistoryKeys = skipExisting
? await ref.read(
downloadHistoryBatchExistsProvider(
HistoryBatchLookupRequest(historyLookups),
).future,
)
: const <String>{};
Set<String> existingHistoryKeys = const {};
if (skipExisting) {
try {
existingHistoryKeys = await ref.read(
downloadHistoryBatchExistsProvider(
HistoryBatchLookupRequest(historyLookups),
).future,
);
} catch (e) {
// Queueing without the skip beats silently doing nothing: several
// callers fire this flow unawaited, so a throw here would vanish.
AppLogger('DownloadFlow').w('Duplicate check failed, queueing all: $e');
}
}
if (!context.mounted) return;
final localLibState =
(skipExisting &&