feat(music): audio downloads and music home rows

Album/artist downloads expand to tracks with pinned parent metadata,
aggregate progress, container deletes with reference-counted album
covers, and a Music tab on the downloads screen with fully offline
album playback. Home rows include music libraries (fixes plex hub
items being filtered to video types) and audio playlists join
download/sync rules.
This commit is contained in:
edde746
2026-07-05 21:51:37 +02:00
parent 7d6a747aa7
commit 764345f021
15 changed files with 1037 additions and 112 deletions
+37
View File
@@ -259,6 +259,43 @@ extension DownloadDatabaseOperations on AppDatabase {
.get();
}
/// Downloaded tracks belonging to an album (parentRatingKey). Mirrors
/// [getEpisodesBySeason] but filters on type so an id collision with a
/// season key can never mix media kinds.
Future<List<DownloadedMediaItem>> getTracksByAlbum(
String albumKey, {
ServerId? serverId,
String? clientScopeId,
bool filterClientScope = false,
}) {
return (select(downloadedMedia)..where(
(t) =>
t.type.equals('track') &
t.parentRatingKey.equals(albumKey) &
_optionalServerPredicate(t.serverId, serverIdOrNull(serverId)) &
_optionalClientScopePredicate(t.clientScopeId, clientScopeId, filterClientScope: filterClientScope),
))
.get();
}
/// Downloaded tracks belonging to an artist (grandparentRatingKey). Mirrors
/// [getEpisodesByShow] with the same type filter as [getTracksByAlbum].
Future<List<DownloadedMediaItem>> getTracksByArtist(
String artistKey, {
ServerId? serverId,
String? clientScopeId,
bool filterClientScope = false,
}) {
return (select(downloadedMedia)..where(
(t) =>
t.type.equals('track') &
t.grandparentRatingKey.equals(artistKey) &
_optionalServerPredicate(t.serverId, serverIdOrNull(serverId)) &
_optionalClientScopePredicate(t.clientScopeId, clientScopeId, filterClientScope: filterClientScope),
))
.get();
}
Future<List<DownloadedMediaItem>> getDownloadsByServerId(ServerId serverId) {
return (select(downloadedMedia)..where((t) => t.serverId.equals(serverId))).get();
}