From 7c165b5c3a3ee7a9a8a2ee94cfe8e3ce7f122110 Mon Sep 17 00:00:00 2001 From: vfsfitvnm Date: Fri, 1 Jul 2022 12:54:22 +0200 Subject: [PATCH] Tweak Database class --- .../12.json | 40 +-- .../kotlin/it/vfsfitvnm/vimusic/Database.kt | 239 +++++++++++------- .../vimusic/models/PlaylistWithSongs.kt | 2 +- .../{SongInPlaylist.kt => SongPlaylistMap.kt} | 2 +- ...InPlaylist.kt => SortedSongPlaylistMap.kt} | 4 +- .../vimusic/service/PlayerService.kt | 8 +- .../ui/components/themed/MediaItemMenu.kt | 11 +- .../vimusic/ui/screens/AlbumScreen.kt | 6 +- .../vimusic/ui/screens/IntentUriScreen.kt | 4 +- .../vimusic/ui/screens/LocalPlaylistScreen.kt | 4 +- .../vimusic/ui/screens/PlaylistScreen.kt | 4 +- .../vimusic/ui/screens/SearchScreen.kt | 2 +- .../vimusic/ui/views/PlayerBottomSheet.kt | 14 +- .../vfsfitvnm/vimusic/ui/views/PlayerView.kt | 9 +- .../it/vfsfitvnm/vimusic/utils/utils.kt | 63 +---- 15 files changed, 192 insertions(+), 220 deletions(-) rename app/src/main/kotlin/it/vfsfitvnm/vimusic/models/{SongInPlaylist.kt => SongPlaylistMap.kt} (96%) rename app/src/main/kotlin/it/vfsfitvnm/vimusic/models/{SortedSongInPlaylist.kt => SortedSongPlaylistMap.kt} (69%) diff --git a/app/schemas/it.vfsfitvnm.vimusic.DatabaseInitializer/12.json b/app/schemas/it.vfsfitvnm.vimusic.DatabaseInitializer/12.json index e99803d..18d7ff5 100644 --- a/app/schemas/it.vfsfitvnm.vimusic.DatabaseInitializer/12.json +++ b/app/schemas/it.vfsfitvnm.vimusic.DatabaseInitializer/12.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 12, - "identityHash": "b4ab81f091f9f0d359631c1426b04c49", + "identityHash": "fe9703c1e23ef700d9698e0440e4ad7f", "entities": [ { "tableName": "Song", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `albumId` TEXT, `artistsText` TEXT, `durationText` TEXT NOT NULL, `thumbnailUrl` TEXT, `lyrics` TEXT, `likedAt` INTEGER, `totalPlayTimeMs` INTEGER NOT NULL, `loudnessDb` REAL, `contentLength` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`albumId`) REFERENCES `Album`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `artistsText` TEXT, `durationText` TEXT NOT NULL, `thumbnailUrl` TEXT, `lyrics` TEXT, `likedAt` INTEGER, `totalPlayTimeMs` INTEGER NOT NULL, `loudnessDb` REAL, `contentLength` INTEGER, PRIMARY KEY(`id`))", "fields": [ { "fieldPath": "id", @@ -20,12 +20,6 @@ "affinity": "TEXT", "notNull": true }, - { - "fieldPath": "albumId", - "columnName": "albumId", - "affinity": "TEXT", - "notNull": false - }, { "fieldPath": "artistsText", "columnName": "artistsText", @@ -82,22 +76,10 @@ ] }, "indices": [], - "foreignKeys": [ - { - "table": "Album", - "onDelete": "SET NULL", - "onUpdate": "NO ACTION", - "columns": [ - "albumId" - ], - "referencedColumns": [ - "id" - ] - } - ] + "foreignKeys": [] }, { - "tableName": "SongInPlaylist", + "tableName": "SongPlaylistMap", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`songId` TEXT NOT NULL, `playlistId` INTEGER NOT NULL, `position` INTEGER NOT NULL, PRIMARY KEY(`songId`, `playlistId`), FOREIGN KEY(`songId`) REFERENCES `Song`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`playlistId`) REFERENCES `Playlist`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { @@ -128,22 +110,22 @@ }, "indices": [ { - "name": "index_SongInPlaylist_songId", + "name": "index_SongPlaylistMap_songId", "unique": false, "columnNames": [ "songId" ], "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_SongInPlaylist_songId` ON `${TABLE_NAME}` (`songId`)" + "createSql": "CREATE INDEX IF NOT EXISTS `index_SongPlaylistMap_songId` ON `${TABLE_NAME}` (`songId`)" }, { - "name": "index_SongInPlaylist_playlistId", + "name": "index_SongPlaylistMap_playlistId", "unique": false, "columnNames": [ "playlistId" ], "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_SongInPlaylist_playlistId` ON `${TABLE_NAME}` (`playlistId`)" + "createSql": "CREATE INDEX IF NOT EXISTS `index_SongPlaylistMap_playlistId` ON `${TABLE_NAME}` (`playlistId`)" } ], "foreignKeys": [ @@ -524,13 +506,13 @@ ], "views": [ { - "viewName": "SortedSongInPlaylist", - "createSql": "CREATE VIEW `${VIEW_NAME}` AS SELECT * FROM SongInPlaylist ORDER BY position" + "viewName": "SortedSongPlaylistMap", + "createSql": "CREATE VIEW `${VIEW_NAME}` AS SELECT * FROM SongPlaylistMap ORDER BY position" } ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'b4ab81f091f9f0d359631c1426b04c49')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'fe9703c1e23ef700d9698e0440e4ad7f')" ] } } \ No newline at end of file diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/Database.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/Database.kt index 04ceadd..8b8bb84 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/Database.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/Database.kt @@ -12,6 +12,8 @@ import androidx.sqlite.db.SimpleSQLiteQuery import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase import it.vfsfitvnm.vimusic.models.* +import it.vfsfitvnm.vimusic.utils.getFloatOrNull +import it.vfsfitvnm.vimusic.utils.getLongOrNull import kotlinx.coroutines.flow.Flow @@ -19,49 +21,6 @@ import kotlinx.coroutines.flow.Flow interface Database { companion object : Database by DatabaseInitializer.Instance.database - @Query("SELECT * FROM SearchQuery WHERE query LIKE :query ORDER BY id DESC") - fun getRecentQueries(query: String): Flow> - - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(searchQuery: SearchQuery) - - @Insert(onConflict = OnConflictStrategy.IGNORE) - fun insert(info: Artist): Long - - @Insert(onConflict = OnConflictStrategy.IGNORE) - fun insert(info: Album): Long - - @Insert(onConflict = OnConflictStrategy.ABORT) - fun insert(playlist: Playlist): Long - - @Insert(onConflict = OnConflictStrategy.IGNORE) - fun insert(info: SongInPlaylist): Long - - @Insert(onConflict = OnConflictStrategy.IGNORE) - fun insert(songAlbumMap: SongAlbumMap): Long - - @Query("SELECT * FROM Song WHERE id = :id") - fun songFlow(id: String): Flow - - @Query("SELECT * FROM Song WHERE id = :id") - fun song(id: String): Song? - - @Query("SELECT * FROM Playlist WHERE id = :id") - fun playlist(id: Long): Playlist? - - @Query("SELECT * FROM Song") - fun songs(): Flow> - - @Query("SELECT * FROM Artist WHERE id = :id") - fun artist(id: String): Flow - - @Query("SELECT * FROM Album WHERE id = :id") - fun album(id: String): Flow - - @Transaction - @Query("SELECT * FROM Song WHERE id = :id") - fun songWithInfo(id: String): DetailedSong? - @Transaction @Query("SELECT * FROM Song WHERE totalPlayTimeMs > 0 ORDER BY ROWID DESC") fun history(): Flow> @@ -74,6 +33,24 @@ interface Database { @Query("SELECT * FROM Song WHERE totalPlayTimeMs >= 60000 ORDER BY totalPlayTimeMs DESC LIMIT 20") fun mostPlayed(): Flow> + @Query("SELECT * FROM QueuedMediaItem") + fun queue(): List + + @Query("DELETE FROM QueuedMediaItem") + fun clearQueue() + + @Query("SELECT * FROM SearchQuery WHERE query LIKE :query ORDER BY id DESC") + fun queries(query: String): Flow> + + @Query("SELECT * FROM Song WHERE id = :id") + fun song(id: String): Flow + + @Query("SELECT * FROM Artist WHERE id = :id") + fun artist(id: String): Flow + + @Query("SELECT * FROM Album WHERE id = :id") + fun album(id: String): Flow + @Query("UPDATE Song SET totalPlayTimeMs = totalPlayTimeMs + :addition WHERE id = :id") fun incrementTotalPlayTimeMs(id: String, addition: Long) @@ -81,56 +58,127 @@ interface Database { @Query("SELECT * FROM Playlist WHERE id = :id") fun playlistWithSongs(id: Long): Flow - @Query("SELECT COUNT(*) FROM SongInPlaylist WHERE playlistId = :id") - fun playlistSongCount(id: Long): Int + @Transaction + @Query("SELECT id, name, (SELECT COUNT(*) FROM SongPlaylistMap WHERE playlistId = id) as songCount FROM Playlist") + fun playlistPreviews(): Flow> - @Query("UPDATE SongInPlaylist SET position = position - 1 WHERE playlistId = :playlistId AND position >= :fromPosition") + @Query("SELECT thumbnailUrl FROM Song JOIN SongPlaylistMap ON id = songId WHERE playlistId = :id ORDER BY position LIMIT 4") + fun playlistThumbnailUrls(id: Long): Flow> + + @Transaction + @Query("SELECT * FROM Song JOIN SongArtistMap ON Song.id = SongArtistMap.songId WHERE SongArtistMap.artistId = :artistId ORDER BY Song.ROWID DESC") + @RewriteQueriesToDropUnusedColumns + fun artistSongs(artistId: String): Flow> + + @Transaction + @Query("SELECT * FROM Song JOIN SongAlbumMap ON Song.id = SongAlbumMap.songId WHERE SongAlbumMap.albumId = :albumId AND position IS NOT NULL ORDER BY position") + @RewriteQueriesToDropUnusedColumns + fun albumSongs(albumId: String): Flow> + + @Query("UPDATE SongPlaylistMap SET position = position - 1 WHERE playlistId = :playlistId AND position >= :fromPosition") fun decrementSongPositions(playlistId: Long, fromPosition: Int) - @Query("UPDATE SongInPlaylist SET position = position - 1 WHERE playlistId = :playlistId AND position >= :fromPosition AND position <= :toPosition") + @Query("UPDATE SongPlaylistMap SET position = position - 1 WHERE playlistId = :playlistId AND position >= :fromPosition AND position <= :toPosition") fun decrementSongPositions(playlistId: Long, fromPosition: Int, toPosition: Int) - @Query("UPDATE SongInPlaylist SET position = position + 1 WHERE playlistId = :playlistId AND position >= :fromPosition AND position <= :toPosition") + @Query("UPDATE SongPlaylistMap SET position = position + 1 WHERE playlistId = :playlistId AND position >= :fromPosition AND position <= :toPosition") fun incrementSongPositions(playlistId: Long, fromPosition: Int, toPosition: Int) - @Insert(onConflict = OnConflictStrategy.ABORT) - fun insert(songWithAuthors: SongArtistMap): Long + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(searchQuery: SearchQuery) + + @Insert(onConflict = OnConflictStrategy.IGNORE) + fun insert(info: Artist): Long + + @Insert(onConflict = OnConflictStrategy.IGNORE) + fun insert(info: Album): Long + + @Insert(onConflict = OnConflictStrategy.IGNORE) + fun insert(playlist: Playlist): Long + + @Insert(onConflict = OnConflictStrategy.IGNORE) + fun insert(songPlaylistMap: SongPlaylistMap): Long + + @Insert(onConflict = OnConflictStrategy.IGNORE) + fun insert(songAlbumMap: SongAlbumMap): Long @Insert(onConflict = OnConflictStrategy.ABORT) + fun insert(songArtistMap: SongArtistMap): Long + + @Insert(onConflict = OnConflictStrategy.IGNORE) fun insert(song: Song): Long + @Insert(onConflict = OnConflictStrategy.ABORT) + fun insert(queuedMediaItem: QueuedMediaItem) + + @Transaction + fun insert(mediaItem: MediaItem, block: (Song) -> Song = { it }) { + val song = Song( + id = mediaItem.mediaId, + title = mediaItem.mediaMetadata.title!!.toString(), + artistsText = mediaItem.mediaMetadata.artist?.toString(), + durationText = mediaItem.mediaMetadata.extras?.getString("durationText")!!, + thumbnailUrl = mediaItem.mediaMetadata.artworkUri?.toString(), + loudnessDb = mediaItem.mediaMetadata.extras?.getFloatOrNull("loudnessDb"), + contentLength = mediaItem.mediaMetadata.extras?.getLongOrNull("contentLength"), + ).let(block).also { song -> + if (insert(song) == -1L) return + } + + mediaItem.mediaMetadata.extras?.getString("albumId")?.let { albumId -> + Album( + id = albumId, + title = mediaItem.mediaMetadata.albumTitle?.toString(), + year = null, + authorsText = null, + thumbnailUrl = null, + shareUrl = null, + ).also(::insert) + + upsert( + SongAlbumMap( + songId = song.id, + albumId = albumId, + position = null + ) + ) + } + + mediaItem.mediaMetadata.extras?.getStringArrayList("artistNames")?.let { artistNames -> + mediaItem.mediaMetadata.extras?.getStringArrayList("artistIds")?.let { artistIds -> + artistNames.mapIndexed { index, artistName -> + Artist( + id = artistIds[index], + name = artistName, + thumbnailUrl = null, + info = null + ).also(::insert) + } + } + }?.forEach { artist -> + insert( + SongArtistMap( + songId = song.id, + artistId = artist.id + ) + ) + } + } + @Update fun update(song: Song) @Update fun update(artist: Artist) - fun upsert(artist: Artist) { - if (insert(artist) == -1L) { - update(artist) - } - } - @Update fun update(album: Album) - fun upsert(album: Album) { - if (insert(album) == -1L) { - update(album) - } - } - @Update fun update(songAlbumMap: SongAlbumMap) - fun upsert(songAlbumMap: SongAlbumMap) { - if (insert(songAlbumMap) == -1L) { - update(songAlbumMap) - } - } - @Update - fun update(songInPlaylist: SongInPlaylist) + fun update(songPlaylistMap: SongPlaylistMap) @Update fun update(playlist: Playlist) @@ -145,39 +193,31 @@ interface Database { fun delete(song: Song) @Delete - fun delete(songInPlaylist: SongInPlaylist) + fun delete(songPlaylistMap: SongPlaylistMap) - @Transaction - @Query("SELECT id, name, (SELECT COUNT(*) FROM SongInPlaylist WHERE playlistId = id) as songCount FROM Playlist") - fun playlistPreviews(): Flow> + fun upsert(songAlbumMap: SongAlbumMap) { + if (insert(songAlbumMap) == -1L) { + update(songAlbumMap) + } + } - @Query("SELECT thumbnailUrl FROM Song JOIN SongInPlaylist ON id = songId WHERE playlistId = :id ORDER BY position LIMIT 4") - fun playlistThumbnailUrls(id: Long): Flow> + fun upsert(artist: Artist) { + if (insert(artist) == -1L) { + update(artist) + } + } - @Transaction - @Query("SELECT * FROM Song JOIN SongArtistMap ON Song.id = SongArtistMap.songId WHERE SongArtistMap.artistId = :artistId ORDER BY Song.ROWID DESC") - @RewriteQueriesToDropUnusedColumns - fun artistSongs(artistId: String): Flow> - - @Transaction - @Query("SELECT * FROM Song JOIN SongAlbumMap ON Song.id = SongAlbumMap.songId WHERE SongAlbumMap.albumId = :albumId AND position IS NOT NULL ORDER BY position") - @RewriteQueriesToDropUnusedColumns - fun albumSongs(albumId: String): Flow> - - @Insert(onConflict = OnConflictStrategy.ABORT) - fun insertQueue(queuedMediaItems: List) - - @Query("SELECT * FROM QueuedMediaItem") - fun queue(): List - - @Query("DELETE FROM QueuedMediaItem") - fun clearQueue() + fun upsert(album: Album) { + if (insert(album) == -1L) { + update(album) + } + } } @androidx.room.Database( entities = [ Song::class, - SongInPlaylist::class, + SongPlaylistMap::class, Playlist::class, Artist::class, SongArtistMap::class, @@ -187,9 +227,9 @@ interface Database { QueuedMediaItem::class, ], views = [ - SortedSongInPlaylist::class + SortedSongPlaylistMap::class ], - version = 11, + version = 12, exportSchema = true, autoMigrations = [ AutoMigration(from = 1, to = 2), @@ -199,7 +239,8 @@ interface Database { AutoMigration(from = 5, to = 6), AutoMigration(from = 6, to = 7), AutoMigration(from = 7, to = 8, spec = DatabaseInitializer.From7To8Migration::class), - AutoMigration(from = 9, to = 10) + AutoMigration(from = 9, to = 10), + AutoMigration(from = 11, to = 12, spec = DatabaseInitializer.From11To12Migration::class), ], ) @TypeConverters(Converters::class) @@ -283,6 +324,10 @@ abstract class DatabaseInitializer protected constructor() : RoomDatabase() { it.execSQL("ALTER TABLE Song_new RENAME TO Song;") } } + + @RenameTable("SongInPlaylist", "SongPlaylistMap") + @RenameTable("SortedSongInPlaylist", "SortedSongPlaylistMap") + class From11To12Migration : AutoMigrationSpec } @TypeConverters diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/PlaylistWithSongs.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/PlaylistWithSongs.kt index d40cad3..a98f0fa 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/PlaylistWithSongs.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/PlaylistWithSongs.kt @@ -10,7 +10,7 @@ data class PlaylistWithSongs( parentColumn = "id", entityColumn = "id", associateBy = Junction( - value = SortedSongInPlaylist::class, + value = SortedSongPlaylistMap::class, parentColumn = "playlistId", entityColumn = "songId" ) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SongInPlaylist.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SongPlaylistMap.kt similarity index 96% rename from app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SongInPlaylist.kt rename to app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SongPlaylistMap.kt index ed711e8..9d91e05 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SongInPlaylist.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SongPlaylistMap.kt @@ -24,7 +24,7 @@ import androidx.room.ForeignKey ) ] ) -data class SongInPlaylist( +data class SongPlaylistMap( @ColumnInfo(index = true) val songId: String, @ColumnInfo(index = true) val playlistId: Long, val position: Int diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SortedSongInPlaylist.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SortedSongPlaylistMap.kt similarity index 69% rename from app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SortedSongInPlaylist.kt rename to app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SortedSongPlaylistMap.kt index b269174..eed3332 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SortedSongInPlaylist.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/models/SortedSongPlaylistMap.kt @@ -3,8 +3,8 @@ package it.vfsfitvnm.vimusic.models import androidx.room.ColumnInfo import androidx.room.DatabaseView -@DatabaseView("SELECT * FROM SongInPlaylist ORDER BY position") -data class SortedSongInPlaylist( +@DatabaseView("SELECT * FROM SongPlaylistMap ORDER BY position") +data class SortedSongPlaylistMap( @ColumnInfo(index = true) val songId: String, @ColumnInfo(index = true) val playlistId: Long, val position: Int diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt index dc53a88..2d14abc 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt @@ -205,14 +205,14 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback query { Database.clearQueue() - Database.insertQueue( - mediaItems.mapIndexed { index, mediaItem -> + mediaItems.forEachIndexed { index, mediaItem -> + Database.insert( QueuedMediaItem( mediaItem = mediaItem, position = if (index == mediaItemIndex) mediaItemPosition else null ) - } - ) + ) + } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/MediaItemMenu.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/MediaItemMenu.kt index 439ebe2..7b5ff15 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/MediaItemMenu.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/MediaItemMenu.kt @@ -19,7 +19,7 @@ import it.vfsfitvnm.route.empty import it.vfsfitvnm.vimusic.* import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.models.Playlist -import it.vfsfitvnm.vimusic.models.SongInPlaylist +import it.vfsfitvnm.vimusic.models.SongPlaylistMap import it.vfsfitvnm.vimusic.models.DetailedSong import it.vfsfitvnm.vimusic.ui.components.LocalMenuState import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute @@ -104,7 +104,7 @@ fun InPlaylistMediaItemMenu( onRemoveFromPlaylist = { transaction { Database.delete( - SongInPlaylist( + SongPlaylistMap( songId = song.song.id, playlistId = playlistId, position = positionInPlaylist @@ -214,14 +214,11 @@ fun BaseMediaItemMenu( onEnqueue = onEnqueue, onAddToPlaylist = { playlist, position -> transaction { - val playlistId = Database.playlist(playlist.id)?.id ?: Database.insert(playlist) - Database.insert(mediaItem) - Database.insert( - SongInPlaylist( + SongPlaylistMap( songId = mediaItem.mediaId, - playlistId = playlistId, + playlistId = Database.insert(playlist).takeIf { it != -1L } ?: playlist.id, position = position ) ) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/AlbumScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/AlbumScreen.kt index 25ff36c..bf3f8da 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/AlbumScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/AlbumScreen.kt @@ -37,7 +37,6 @@ import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness import it.vfsfitvnm.vimusic.models.Album import it.vfsfitvnm.vimusic.models.DetailedSong import it.vfsfitvnm.vimusic.models.SongAlbumMap -import it.vfsfitvnm.vimusic.query import it.vfsfitvnm.vimusic.ui.components.LocalMenuState import it.vfsfitvnm.vimusic.ui.components.TopAppBar import it.vfsfitvnm.vimusic.ui.components.themed.* @@ -73,10 +72,11 @@ fun AlbumScreen( shareUrl = youtubeAlbum.url ).also(Database::upsert).also { youtubeAlbum.items?.forEachIndexed { position, albumItem -> - albumItem.toMediaItem(browseId, youtubeAlbum)?.let(Database::insert)?.let { song -> + albumItem.toMediaItem(browseId, youtubeAlbum)?.let { mediaItem -> + Database.insert(mediaItem) Database.upsert( SongAlbumMap( - songId = song.id, + songId = mediaItem.mediaId, albumId = browseId, position = position ) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/IntentUriScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/IntentUriScreen.kt index 8758382..e42bbe7 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/IntentUriScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/IntentUriScreen.kt @@ -24,7 +24,7 @@ import it.vfsfitvnm.vimusic.Database import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.models.Playlist -import it.vfsfitvnm.vimusic.models.SongInPlaylist +import it.vfsfitvnm.vimusic.models.SongPlaylistMap import it.vfsfitvnm.vimusic.transaction import it.vfsfitvnm.vimusic.ui.components.Error import it.vfsfitvnm.vimusic.ui.components.LocalMenuState @@ -109,7 +109,7 @@ fun IntentUriScreen(uri: Uri) { Database.insert(mediaItem) Database.insert( - SongInPlaylist( + SongPlaylistMap( songId = mediaItem.mediaId, playlistId = playlistId, position = index diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/LocalPlaylistScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/LocalPlaylistScreen.kt index 88fc130..b9e3b62 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/LocalPlaylistScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/LocalPlaylistScreen.kt @@ -27,7 +27,7 @@ import it.vfsfitvnm.route.RouteHandler import it.vfsfitvnm.vimusic.* import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.models.PlaylistWithSongs -import it.vfsfitvnm.vimusic.models.SongInPlaylist +import it.vfsfitvnm.vimusic.models.SongPlaylistMap import it.vfsfitvnm.vimusic.models.DetailedSong import it.vfsfitvnm.vimusic.ui.components.LocalMenuState import it.vfsfitvnm.vimusic.ui.components.TopAppBar @@ -302,7 +302,7 @@ fun LocalPlaylistScreen( } Database.update( - SongInPlaylist( + SongPlaylistMap( songId = playlistWithSongs.songs[index].song.id, playlistId = playlistWithSongs.playlist.id, position = reachedIndex diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/PlaylistScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/PlaylistScreen.kt index 6a90296..a0e0da3 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/PlaylistScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/PlaylistScreen.kt @@ -32,7 +32,7 @@ import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness import it.vfsfitvnm.vimusic.models.Playlist -import it.vfsfitvnm.vimusic.models.SongInPlaylist +import it.vfsfitvnm.vimusic.models.SongPlaylistMap import it.vfsfitvnm.vimusic.transaction import it.vfsfitvnm.vimusic.ui.components.LocalMenuState import it.vfsfitvnm.vimusic.ui.components.OutcomeItem @@ -177,7 +177,7 @@ fun PlaylistScreen( Database.insert(mediaItem) Database.insert( - SongInPlaylist( + SongPlaylistMap( songId = mediaItem.mediaId, playlistId = playlistId, position = index diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/SearchScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/SearchScreen.kt index e75eb9e..c5eb1f3 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/SearchScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/SearchScreen.kt @@ -82,7 +82,7 @@ fun SearchScreen( } val history by remember(textFieldValue.text) { - Database.getRecentQueries("%${textFieldValue.text}%").distinctUntilChanged { old, new -> + Database.queries("%${textFieldValue.text}%").distinctUntilChanged { old, new -> old.size == new.size } }.collectAsState(initial = null, context = Dispatchers.IO) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerBottomSheet.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerBottomSheet.kt index 3701a9d..09cd6a3 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerBottomSheet.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerBottomSheet.kt @@ -210,8 +210,10 @@ fun PlayerBottomSheet( lyrics ?: "" }.map { lyrics -> query { - (song ?: mediaItem.let(Database::insert)).let { - Database.update(it.copy(lyrics = lyrics)) + song?.let { + Database.update(song.copy(lyrics = lyrics)) + } ?: Database.insert(mediaItem) { song -> + song.copy(lyrics = lyrics) } } lyrics @@ -234,8 +236,12 @@ fun PlayerBottomSheet( onLyricsUpdate = { lyrics -> val mediaItem = player?.currentMediaItem query { - (song ?: mediaItem?.let(Database::insert))?.let { - Database.update(it.copy(lyrics = lyrics)) + song?.let { + Database.update(song.copy(lyrics = lyrics)) + } ?: mediaItem?.let { + Database.insert(mediaItem) { song -> + song.copy(lyrics = lyrics) + } } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt index 5ea360e..f26cc7f 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt @@ -40,6 +40,7 @@ import it.vfsfitvnm.vimusic.Database import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness +import it.vfsfitvnm.vimusic.models.Song import it.vfsfitvnm.vimusic.query import it.vfsfitvnm.vimusic.ui.components.* import it.vfsfitvnm.vimusic.ui.components.themed.QueuedMediaItemMenu @@ -181,7 +182,7 @@ fun PlayerView( } ) { val song by remember(playerState.mediaItem?.mediaId) { - playerState.mediaItem?.mediaId?.let(Database::songFlow)?.distinctUntilChanged() + playerState.mediaItem?.mediaId?.let(Database::song)?.distinctUntilChanged() ?: flowOf( null ) @@ -550,8 +551,10 @@ fun PlayerView( modifier = Modifier .clickable { query { - (song ?: playerState.mediaItem?.let(Database::insert))?.let { - Database.update(it.toggleLike()) + song?.let { song -> + Database.update(song.toggleLike()) + } ?: playerState.mediaItem?.let { mediaItem -> + Database.insert(mediaItem, Song::toggleLike) } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/utils.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/utils.kt index 18287bc..dca9846 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/utils.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/utils.kt @@ -7,9 +7,7 @@ import androidx.core.net.toUri import androidx.core.os.bundleOf import androidx.media3.common.MediaItem import androidx.media3.common.MediaMetadata -import it.vfsfitvnm.vimusic.Database -import it.vfsfitvnm.vimusic.internal -import it.vfsfitvnm.vimusic.models.* +import it.vfsfitvnm.vimusic.models.DetailedSong import it.vfsfitvnm.youtubemusic.YouTube fun Context.shareAsYouTubeSong(mediaItem: MediaItem) { @@ -22,65 +20,6 @@ fun Context.shareAsYouTubeSong(mediaItem: MediaItem) { startActivity(Intent.createChooser(sendIntent, null)) } -fun Database.insert(mediaItem: MediaItem): Song { - return internal.runInTransaction { - Database.song(mediaItem.mediaId)?.let { - return@runInTransaction it - } - - val song = Song( - id = mediaItem.mediaId, - title = mediaItem.mediaMetadata.title!!.toString(), - artistsText = mediaItem.mediaMetadata.artist!!.toString(), - durationText = mediaItem.mediaMetadata.extras?.getString("durationText")!!, - thumbnailUrl = mediaItem.mediaMetadata.artworkUri!!.toString(), - loudnessDb = mediaItem.mediaMetadata.extras?.getFloatOrNull("loudnessDb"), - contentLength = mediaItem.mediaMetadata.extras?.getLongOrNull("contentLength"), - ).also(::insert) - - mediaItem.mediaMetadata.extras?.getString("albumId")?.let { albumId -> - Album( - id = albumId, - title = mediaItem.mediaMetadata.albumTitle!!.toString(), - year = null, - authorsText = null, - thumbnailUrl = null, - shareUrl = null, - ).also(::insert) - - upsert( - SongAlbumMap( - songId = song.id, - albumId = albumId, - position = null - ) - ) - } - - mediaItem.mediaMetadata.extras?.getStringArrayList("artistNames")?.let { artistNames -> - mediaItem.mediaMetadata.extras!!.getStringArrayList("artistIds")?.let { artistIds -> - artistNames.mapIndexed { index, artistName -> - Artist( - id = artistIds[index], - name = artistName, - thumbnailUrl = null, - info = null - ).also(::insert) - } - } - }?.forEach { artist -> - insert( - SongArtistMap( - songId = song.id, - artistId = artist.id - ) - ) - } - - return@runInTransaction song - } -} - val YouTube.Item.Song.asMediaItem: MediaItem get() = MediaItem.Builder() .setMediaId(info.endpoint!!.videoId!!)