mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 23:21:59 +01:00
download a song's playlist artwork too
This commit is contained in:
@@ -8,6 +8,7 @@ import com.subtracks.data.model.DownloadedSong
|
||||
import com.subtracks.data.model.EntityDownloadStatus
|
||||
import com.subtracks.data.model.ListDownloadStatus
|
||||
import com.subtracks.data.model.SongDownload
|
||||
import com.subtracks.data.model.SourceCoverArt
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
@@ -125,6 +126,25 @@ interface DownloadDao {
|
||||
)
|
||||
suspend fun artwork(): List<DownloadArtwork>
|
||||
|
||||
@Query(
|
||||
"SELECT DISTINCT p.coverArt AS coverArt FROM playlist_songs ps " +
|
||||
"JOIN playlists p ON p.sourceId = ps.sourceId AND p.id = ps.playlistId " +
|
||||
"WHERE ps.sourceId = :sourceId AND ps.songId = :songId AND p.coverArt IS NOT NULL",
|
||||
)
|
||||
suspend fun playlistCoversForSong(
|
||||
sourceId: Long,
|
||||
songId: String,
|
||||
): List<String>
|
||||
|
||||
@Query(
|
||||
"SELECT DISTINCT ps.sourceId AS sourceId, p.coverArt AS coverArt " +
|
||||
"FROM playlist_songs ps " +
|
||||
"JOIN playlists p ON p.sourceId = ps.sourceId AND p.id = ps.playlistId " +
|
||||
"JOIN song_downloads d ON d.sourceId = ps.sourceId AND d.songId = ps.songId " +
|
||||
"WHERE p.coverArt IS NOT NULL",
|
||||
)
|
||||
suspend fun downloadedPlaylistCovers(): List<SourceCoverArt>
|
||||
|
||||
@Query("SELECT * FROM song_downloads WHERE sourceId = :sourceId AND songId = :songId")
|
||||
suspend fun find(
|
||||
sourceId: Long,
|
||||
|
||||
@@ -86,6 +86,11 @@ data class DownloadArtwork(
|
||||
get() = (albumId != null && albumRow == null) || (artistId != null && artistRow == null)
|
||||
}
|
||||
|
||||
data class SourceCoverArt(
|
||||
val sourceId: Long,
|
||||
val coverArt: String,
|
||||
)
|
||||
|
||||
class DownloadStatusConverter {
|
||||
@ColumnTypeConverter
|
||||
fun fromDownloadStatus(status: DownloadStatus): String = status.name
|
||||
|
||||
@@ -388,9 +388,11 @@ class DownloadRepository(
|
||||
) {
|
||||
val song = db.libraryDao().songOnce(sourceId, songId)
|
||||
val coverArt =
|
||||
listOfNotNull(
|
||||
song?.albumId?.let { db.libraryDao().albumOnce(sourceId, it)?.coverArt },
|
||||
song?.artistId?.let { db.libraryDao().artistOnce(sourceId, it)?.coverArt },
|
||||
(
|
||||
listOfNotNull(
|
||||
song?.albumId?.let { db.libraryDao().albumOnce(sourceId, it)?.coverArt },
|
||||
song?.artistId?.let { db.libraryDao().artistOnce(sourceId, it)?.coverArt },
|
||||
) + db.downloadDao().playlistCoversForSong(sourceId, songId)
|
||||
).distinct()
|
||||
coverArt.forEach { cover ->
|
||||
storeArtwork(sourceId, cover, thumbnail = false)
|
||||
@@ -423,18 +425,22 @@ class DownloadRepository(
|
||||
* rows could not all be resolved against the library, in which case nothing is swept for it:
|
||||
* pruning an album or artist would otherwise delete artwork a download still holds.
|
||||
*/
|
||||
private suspend fun artworkToKeep(): Map<Long, Set<String>?> =
|
||||
db
|
||||
private suspend fun artworkToKeep(): Map<Long, Set<String>?> {
|
||||
val playlistCovers = db.downloadDao().downloadedPlaylistCovers().groupBy({ it.sourceId }, { it.coverArt })
|
||||
return db
|
||||
.downloadDao()
|
||||
.artwork()
|
||||
.groupBy { it.sourceId }
|
||||
.mapValues { (sourceId, rows) ->
|
||||
if (rows.any { it.hasMissingLibraryRow }) return@mapValues null
|
||||
rows
|
||||
.flatMap { row -> listOfNotNull(row.albumCoverArt, row.artistCoverArt) }
|
||||
val covers =
|
||||
rows.flatMap { row -> listOfNotNull(row.albumCoverArt, row.artistCoverArt) } +
|
||||
playlistCovers[sourceId].orEmpty()
|
||||
covers
|
||||
.flatMap { cover -> listOf(false, true).map { thumbnail -> coverArtKey(sourceId, cover, thumbnail) } }
|
||||
.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun recover(row: SongDownload) {
|
||||
when (row.status) {
|
||||
|
||||
@@ -323,6 +323,28 @@ class DownloadRepositoryTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun downloadingASongAlsoStoresTheArtworkOfPlaylistsThatContainIt() =
|
||||
runTest {
|
||||
seedLibrary()
|
||||
runBlocking {
|
||||
db.libraryDao().upsertPlaylists(
|
||||
listOf(Playlist(1, "pl1", "Playlist", comment = null, coverArt = PLAYLIST_ART, songCount = 2, created = 0)),
|
||||
)
|
||||
db.libraryDao().upsertPlaylistSongs(listOf(PlaylistSong(1, "pl1", "s1", 0)))
|
||||
}
|
||||
|
||||
runBlocking { repository.download(1, "s1") }
|
||||
|
||||
listOf(false, true).forEach { thumbnail ->
|
||||
val key = coverArtKey(1, PLAYLIST_ART, thumbnail)
|
||||
assertNotNull("expected stored playlist art for $key", artwork.uri(1, key))
|
||||
}
|
||||
|
||||
runBlocking { repository.reconcile() }
|
||||
assertNotNull(artwork.uri(1, coverArtKey(1, PLAYLIST_ART, false)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theDownloadStartsBeforeItsArtworkIsFetched() =
|
||||
runTest {
|
||||
@@ -1105,5 +1127,6 @@ class DownloadRepositoryTest {
|
||||
private companion object {
|
||||
const val ALBUM_ART = "art-al1"
|
||||
const val ARTIST_ART = "art-ar1"
|
||||
const val PLAYLIST_ART = "art-pl1"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user