mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 15:29:15 +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.EntityDownloadStatus
|
||||||
import com.subtracks.data.model.ListDownloadStatus
|
import com.subtracks.data.model.ListDownloadStatus
|
||||||
import com.subtracks.data.model.SongDownload
|
import com.subtracks.data.model.SongDownload
|
||||||
|
import com.subtracks.data.model.SourceCoverArt
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
@@ -125,6 +126,25 @@ interface DownloadDao {
|
|||||||
)
|
)
|
||||||
suspend fun artwork(): List<DownloadArtwork>
|
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")
|
@Query("SELECT * FROM song_downloads WHERE sourceId = :sourceId AND songId = :songId")
|
||||||
suspend fun find(
|
suspend fun find(
|
||||||
sourceId: Long,
|
sourceId: Long,
|
||||||
|
|||||||
@@ -86,6 +86,11 @@ data class DownloadArtwork(
|
|||||||
get() = (albumId != null && albumRow == null) || (artistId != null && artistRow == null)
|
get() = (albumId != null && albumRow == null) || (artistId != null && artistRow == null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class SourceCoverArt(
|
||||||
|
val sourceId: Long,
|
||||||
|
val coverArt: String,
|
||||||
|
)
|
||||||
|
|
||||||
class DownloadStatusConverter {
|
class DownloadStatusConverter {
|
||||||
@ColumnTypeConverter
|
@ColumnTypeConverter
|
||||||
fun fromDownloadStatus(status: DownloadStatus): String = status.name
|
fun fromDownloadStatus(status: DownloadStatus): String = status.name
|
||||||
|
|||||||
@@ -388,9 +388,11 @@ class DownloadRepository(
|
|||||||
) {
|
) {
|
||||||
val song = db.libraryDao().songOnce(sourceId, songId)
|
val song = db.libraryDao().songOnce(sourceId, songId)
|
||||||
val coverArt =
|
val coverArt =
|
||||||
|
(
|
||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
song?.albumId?.let { db.libraryDao().albumOnce(sourceId, it)?.coverArt },
|
song?.albumId?.let { db.libraryDao().albumOnce(sourceId, it)?.coverArt },
|
||||||
song?.artistId?.let { db.libraryDao().artistOnce(sourceId, it)?.coverArt },
|
song?.artistId?.let { db.libraryDao().artistOnce(sourceId, it)?.coverArt },
|
||||||
|
) + db.downloadDao().playlistCoversForSong(sourceId, songId)
|
||||||
).distinct()
|
).distinct()
|
||||||
coverArt.forEach { cover ->
|
coverArt.forEach { cover ->
|
||||||
storeArtwork(sourceId, cover, thumbnail = false)
|
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:
|
* 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.
|
* pruning an album or artist would otherwise delete artwork a download still holds.
|
||||||
*/
|
*/
|
||||||
private suspend fun artworkToKeep(): Map<Long, Set<String>?> =
|
private suspend fun artworkToKeep(): Map<Long, Set<String>?> {
|
||||||
db
|
val playlistCovers = db.downloadDao().downloadedPlaylistCovers().groupBy({ it.sourceId }, { it.coverArt })
|
||||||
|
return db
|
||||||
.downloadDao()
|
.downloadDao()
|
||||||
.artwork()
|
.artwork()
|
||||||
.groupBy { it.sourceId }
|
.groupBy { it.sourceId }
|
||||||
.mapValues { (sourceId, rows) ->
|
.mapValues { (sourceId, rows) ->
|
||||||
if (rows.any { it.hasMissingLibraryRow }) return@mapValues null
|
if (rows.any { it.hasMissingLibraryRow }) return@mapValues null
|
||||||
rows
|
val covers =
|
||||||
.flatMap { row -> listOfNotNull(row.albumCoverArt, row.artistCoverArt) }
|
rows.flatMap { row -> listOfNotNull(row.albumCoverArt, row.artistCoverArt) } +
|
||||||
|
playlistCovers[sourceId].orEmpty()
|
||||||
|
covers
|
||||||
.flatMap { cover -> listOf(false, true).map { thumbnail -> coverArtKey(sourceId, cover, thumbnail) } }
|
.flatMap { cover -> listOf(false, true).map { thumbnail -> coverArtKey(sourceId, cover, thumbnail) } }
|
||||||
.toSet()
|
.toSet()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun recover(row: SongDownload) {
|
private suspend fun recover(row: SongDownload) {
|
||||||
when (row.status) {
|
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
|
@Test
|
||||||
fun theDownloadStartsBeforeItsArtworkIsFetched() =
|
fun theDownloadStartsBeforeItsArtworkIsFetched() =
|
||||||
runTest {
|
runTest {
|
||||||
@@ -1105,5 +1127,6 @@ class DownloadRepositoryTest {
|
|||||||
private companion object {
|
private companion object {
|
||||||
const val ALBUM_ART = "art-al1"
|
const val ALBUM_ART = "art-al1"
|
||||||
const val ARTIST_ART = "art-ar1"
|
const val ARTIST_ART = "art-ar1"
|
||||||
|
const val PLAYLIST_ART = "art-pl1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user