sync the rest of the source models

refactor music download/storage to avoid re-download during reset
add palylist to test server setup
This commit is contained in:
austinried
2025-11-07 15:20:38 +09:00
parent 0e6acbed0f
commit 0c80dbdba5
13 changed files with 451 additions and 149 deletions

View File

@@ -5,6 +5,8 @@ import 'package:drift/drift.dart';
import '../database/database.dart';
import '../sources/music_source.dart';
const kSliceSize = 200;
class SyncService {
SyncService({
required this.source,
@@ -18,28 +20,121 @@ class SyncService {
Future<void> sync() async {
await db.transaction(() async {
await syncArtists();
await Future.wait([
syncArtists(),
syncAlbums(),
syncSongs(),
syncPlaylists(),
syncPlaylistSongs(),
]);
});
}
Future<void> syncArtists() async {
final sourceArtistIds = <String>{};
final sourceIds = <String>{};
await for (final artists in source.allArtists().slices(200)) {
sourceArtistIds.addAll(artists.map((e) => e.id));
await for (final slice in source.allArtists().slices(kSliceSize)) {
sourceIds.addAll(slice.map((e) => e.id));
await db.batch((batch) async {
batch.insertAllOnConflictUpdate(
db.artists,
artists.map((artist) => artist.toDb(sourceId)),
slice.map((artist) => artist.toDb(sourceId)),
);
});
}
for (var slice in sourceArtistIds.slices(kSqliteMaxVariableNumber - 1)) {
for (var slice in sourceIds.slices(kSqliteMaxVariableNumber - 1)) {
await db.artists.deleteWhere(
(tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isNotIn(slice),
);
}
}
Future<void> syncAlbums() async {
final sourceIds = <String>{};
await for (final slice in source.allAlbums().slices(kSliceSize)) {
sourceIds.addAll(slice.map((e) => e.id));
await db.batch((batch) async {
batch.insertAllOnConflictUpdate(
db.albums,
slice.map((e) => e.toDb(sourceId)),
);
});
}
for (var slice in sourceIds.slices(kSqliteMaxVariableNumber - 1)) {
await db.albums.deleteWhere(
(tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isNotIn(slice),
);
}
}
Future<void> syncSongs() async {
final sourceIds = <String>{};
await for (final slice in source.allSongs().slices(kSliceSize)) {
sourceIds.addAll(slice.map((e) => e.id));
await db.batch((batch) async {
batch.insertAllOnConflictUpdate(
db.songs,
slice.map((e) => e.toDb(sourceId)),
);
});
}
for (var slice in sourceIds.slices(kSqliteMaxVariableNumber - 1)) {
await db.songs.deleteWhere(
(tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isNotIn(slice),
);
}
}
Future<void> syncPlaylists() async {
final sourceIds = <String>{};
await for (final slice in source.allPlaylists().slices(kSliceSize)) {
sourceIds.addAll(slice.map((e) => e.id));
await db.batch((batch) async {
batch.insertAllOnConflictUpdate(
db.playlists,
slice.map((e) => e.toDb(sourceId)),
);
});
}
for (var slice in sourceIds.slices(kSqliteMaxVariableNumber - 1)) {
await db.playlists.deleteWhere(
(tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isNotIn(slice),
);
}
}
Future<void> syncPlaylistSongs() async {
final sourceIds = <(String, String)>{};
await for (final slice in source.allPlaylistSongs().slices(kSliceSize)) {
sourceIds.addAll(slice.map((e) => (e.playlistId, e.songId)));
await db.batch((batch) async {
batch.insertAllOnConflictUpdate(
db.playlistSongs,
slice.map((e) => e.toDb(sourceId)),
);
});
}
for (var slice in sourceIds.slices((kSqliteMaxVariableNumber ~/ 2) - 1)) {
await db.playlistSongs.deleteWhere(
(tbl) =>
tbl.sourceId.equals(sourceId) &
tbl.playlistId.isNotIn(slice.map((e) => e.$1)) &
tbl.songId.isNotIn(slice.map((e) => e.$2)),
);
}
}
}