Add "Refetch" option for albums and artists (#93)

This commit is contained in:
vfsfitvnm
2022-07-09 15:14:02 +02:00
parent 3608c912b5
commit 29025da7e9
6 changed files with 632 additions and 56 deletions

View File

@@ -156,6 +156,7 @@ interface Database {
authorsText = null,
thumbnailUrl = null,
shareUrl = null,
timestamp = null,
).also(::insert)
upsert(
@@ -174,7 +175,8 @@ interface Database {
id = artistIds[index],
name = artistName,
thumbnailUrl = null,
info = null
info = null,
timestamp = null,
).also(::insert)
}
}
@@ -212,6 +214,9 @@ interface Database {
@Delete
fun delete(playlist: Playlist)
@Delete
fun delete(playlist: Album)
@Delete
fun delete(songPlaylistMap: SongPlaylistMap)
@@ -249,7 +254,7 @@ interface Database {
views = [
SortedSongPlaylistMap::class
],
version = 12,
version = 13,
exportSchema = true,
autoMigrations = [
AutoMigration(from = 1, to = 2),
@@ -261,6 +266,7 @@ interface Database {
AutoMigration(from = 7, to = 8, spec = DatabaseInitializer.From7To8Migration::class),
AutoMigration(from = 9, to = 10),
AutoMigration(from = 11, to = 12, spec = DatabaseInitializer.From11To12Migration::class),
AutoMigration(from = 12, to = 13),
],
)
@TypeConverters(Converters::class)

View File

@@ -10,5 +10,6 @@ data class Album(
val thumbnailUrl: String? = null,
val year: String? = null,
val authorsText: String? = null,
val shareUrl: String? = null
val shareUrl: String? = null,
val timestamp: Long?
)

View File

@@ -13,4 +13,5 @@ data class Artist(
val shufflePlaylistId: String? = null,
val radioVideoId: String? = null,
val radioPlaylistId: String? = null,
val timestamp: Long?
)

View File

@@ -45,6 +45,9 @@ import it.vfsfitvnm.youtubemusic.YouTube
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
import java.text.DateFormat
import java.util.*
@ExperimentalAnimationApi
@@ -56,32 +59,10 @@ fun AlbumScreen(
val albumResult by remember(browseId) {
Database.album(browseId).map { album ->
album?.takeIf {
album.thumbnailUrl != null
}?.let(Result.Companion::success) ?: YouTube.playlistOrAlbum(browseId)
?.map { youtubeAlbum ->
Album(
id = browseId,
title = youtubeAlbum.title,
thumbnailUrl = youtubeAlbum.thumbnail?.url,
year = youtubeAlbum.year,
authorsText = youtubeAlbum.authors?.joinToString("") { it.name },
shareUrl = youtubeAlbum.url
).also(Database::upsert).also {
youtubeAlbum.withAudioSources().items?.forEachIndexed { position, albumItem ->
albumItem.toMediaItem(browseId, youtubeAlbum)?.let { mediaItem ->
Database.insert(mediaItem)
Database.upsert(
SongAlbumMap(
songId = mediaItem.mediaId,
albumId = browseId,
position = position
)
)
}
}
}
}
album
?.takeIf { album.timestamp != null }
?.let(Result.Companion::success)
?: fetchAlbum(browseId)
}.distinctUntilChanged()
}.collectAsState(initial = null, context = Dispatchers.IO)
@@ -210,6 +191,25 @@ fun AlbumScreen(
}
}
)
MenuEntry(
icon = R.drawable.download,
text = "Refetch",
secondaryText = albumResult?.getOrNull()?.timestamp?.let { timestamp ->
"Last updated on ${DateFormat.getDateTimeInstance().format(Date(timestamp))}"
},
isEnabled = albumResult?.getOrNull() != null,
onClick = {
menuState.hide()
query {
albumResult?.getOrNull()?.let(Database::delete)
runBlocking(Dispatchers.IO) {
fetchAlbum(browseId)
}
}
}
)
}
}
}
@@ -392,3 +392,31 @@ private fun LoadingOrError(
}
}
}
private suspend fun fetchAlbum(browseId: String): Result<Album>? {
return YouTube.playlistOrAlbum(browseId)
?.map { youtubeAlbum ->
Album(
id = browseId,
title = youtubeAlbum.title,
thumbnailUrl = youtubeAlbum.thumbnail?.url,
year = youtubeAlbum.year,
authorsText = youtubeAlbum.authors?.joinToString("") { it.name },
shareUrl = youtubeAlbum.url,
timestamp = System.currentTimeMillis()
).also(Database::upsert).also {
youtubeAlbum.withAudioSources().items?.forEachIndexed { position, albumItem ->
albumItem.toMediaItem(browseId, youtubeAlbum)?.let { mediaItem ->
Database.insert(mediaItem)
Database.upsert(
SongAlbumMap(
songId = mediaItem.mediaId,
albumId = browseId,
position = position
)
)
}
}
}
}
}

View File

@@ -82,21 +82,10 @@ fun ArtistScreen(
val artistResult by remember(browseId) {
Database.artist(browseId).map { artist ->
artist?.takeIf {
artist.shufflePlaylistId != null
}?.let(Result.Companion::success) ?: YouTube.artist(browseId)
?.map { youtubeArtist ->
Artist(
id = browseId,
name = youtubeArtist.name,
thumbnailUrl = youtubeArtist.thumbnail?.url,
info = youtubeArtist.description,
shuffleVideoId = youtubeArtist.shuffleEndpoint?.videoId,
shufflePlaylistId = youtubeArtist.shuffleEndpoint?.playlistId,
radioVideoId = youtubeArtist.radioEndpoint?.videoId,
radioPlaylistId = youtubeArtist.radioEndpoint?.playlistId,
).also(Database::upsert)
}
artist
?.takeIf { artist.timestamp != null }
?.let(Result.Companion::success)
?: fetchArtist(browseId)
}.distinctUntilChanged()
}.collectAsState(initial = null, context = Dispatchers.IO)
@@ -139,17 +128,6 @@ fun ArtistScreen(
contentDescription = null,
modifier = Modifier
.clip(CircleShape)
.clickable {
query {
runBlocking {
Database
.artist(browseId)
.first()
?.copy(shufflePlaylistId = null)
?.let(Database::update)
}
}
}
.size(Dimensions.thumbnails.artist)
)
@@ -177,6 +155,12 @@ fun ArtistScreen(
playlistId = artist.shufflePlaylistId
)
)
query {
runBlocking {
fetchArtist(browseId)
}
}
}
.shadow(elevation = 2.dp, shape = CircleShape)
.background(
@@ -200,6 +184,12 @@ fun ArtistScreen(
playlistId = artist.radioPlaylistId
)
)
query {
runBlocking {
fetchArtist(browseId)
}
}
}
.shadow(elevation = 2.dp, shape = CircleShape)
.background(
@@ -285,7 +275,10 @@ fun ArtistScreen(
artistResult?.getOrNull()?.info?.let { description ->
item {
TextCard {
TextCard(
modifier = Modifier
.fillMaxWidth()
) {
Title(text = "Information")
Text(text = description)
}
@@ -329,3 +322,20 @@ private fun LoadingOrError(
}
}
}
private suspend fun fetchArtist(browseId: String): Result<Artist>? {
return YouTube.artist(browseId)
?.map { youtubeArtist ->
Artist(
id = browseId,
name = youtubeArtist.name,
thumbnailUrl = youtubeArtist.thumbnail?.url,
info = youtubeArtist.description,
shuffleVideoId = youtubeArtist.shuffleEndpoint?.videoId,
shufflePlaylistId = youtubeArtist.shuffleEndpoint?.playlistId,
radioVideoId = youtubeArtist.radioEndpoint?.videoId,
radioPlaylistId = youtubeArtist.radioEndpoint?.playlistId,
timestamp = System.currentTimeMillis()
).also(Database::upsert)
}
}