-
-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #63 from mattcarter11/singelton-sync-and-chip-loader
- Loading branch information
Showing
37 changed files
with
3,145 additions
and
1,312 deletions.
There are no files selected for viewing
1,259 changes: 1,259 additions & 0 deletions
1,259
app/schemas/com.dd3boh.outertune.db.InternalDatabase/16.json
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
880 changes: 7 additions & 873 deletions
880
app/src/main/java/com/dd3boh/outertune/db/DatabaseDao.kt
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
185 changes: 185 additions & 0 deletions
185
app/src/main/java/com/dd3boh/outertune/db/daos/AlbumsDao.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
package com.dd3boh.outertune.db.daos | ||
|
||
import androidx.room.Dao | ||
import androidx.room.Delete | ||
import androidx.room.Insert | ||
import androidx.room.OnConflictStrategy | ||
import androidx.room.Query | ||
import androidx.room.RawQuery | ||
import androidx.room.Transaction | ||
import androidx.room.Update | ||
import androidx.room.Upsert | ||
import androidx.sqlite.db.SimpleSQLiteQuery | ||
import androidx.sqlite.db.SupportSQLiteQuery | ||
import com.dd3boh.outertune.constants.AlbumFilter | ||
import com.dd3boh.outertune.constants.AlbumSortType | ||
import com.dd3boh.outertune.db.entities.Album | ||
import com.dd3boh.outertune.db.entities.AlbumArtistMap | ||
import com.dd3boh.outertune.db.entities.AlbumEntity | ||
import com.dd3boh.outertune.db.entities.AlbumWithSongs | ||
import com.dd3boh.outertune.db.entities.ArtistEntity | ||
import com.dd3boh.outertune.db.entities.Song | ||
import com.dd3boh.outertune.db.entities.SongAlbumMap | ||
import com.dd3boh.outertune.extensions.reversed | ||
import com.zionhuang.innertube.models.AlbumItem | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.map | ||
|
||
/* | ||
* Logic related to albums entities and their mapping | ||
*/ | ||
|
||
@Dao | ||
interface AlbumsDao : ArtistsDao { | ||
|
||
// region Gets | ||
@Query(""" | ||
SELECT album.*, count(song.dateDownload) downloadCount | ||
FROM album | ||
LEFT JOIN song ON song.albumId = album.id | ||
WHERE album.id = :id | ||
GROUP BY album.id | ||
""") | ||
fun album(id: String): Flow<Album?> | ||
|
||
@Query(""" | ||
SELECT album.*, count(song.dateDownload) downloadCount | ||
FROM album | ||
LEFT JOIN song ON song.albumId = album.id | ||
WHERE album.title LIKE '%' || :query || '%' AND song.inLibrary IS NOT NULL | ||
GROUP BY album.id | ||
LIMIT :previewSize | ||
""") | ||
fun searchAlbums(query: String, previewSize: Int = Int.MAX_VALUE): Flow<List<Album>> | ||
|
||
@Query(""" | ||
SELECT album.*, count(song.dateDownload) downloadCount | ||
FROM album | ||
LEFT JOIN song ON song.albumId = album.id | ||
WHERE album.id = :albumId | ||
GROUP BY album.id | ||
""") | ||
fun albumWithSongs(albumId: String): Flow<AlbumWithSongs?> | ||
|
||
@Query("SELECT song.* FROM song JOIN song_album_map ON song.id = song_album_map.songId WHERE song_album_map.albumId = :albumId") | ||
fun albumSongs(albumId: String): Flow<List<Song>> | ||
|
||
@Query(""" | ||
SELECT album.*, count(song.dateDownload) downloadCount | ||
FROM album | ||
JOIN song ON album.id = song.albumId | ||
JOIN event ON song.id = event.songId | ||
WHERE event.timestamp > :fromTimeStamp | ||
GROUP BY album.id | ||
ORDER BY SUM(event.playTime) DESC | ||
LIMIT :limit; | ||
""") | ||
fun mostPlayedAlbums(fromTimeStamp: Long, limit: Int = 6): Flow<List<Album>> | ||
|
||
@RawQuery(observedEntities = [AlbumEntity::class]) | ||
fun _getAlbum(query: SupportSQLiteQuery): Flow<List<Album>> | ||
|
||
fun albums(filter: AlbumFilter, sortType: AlbumSortType, descending: Boolean): Flow<List<Album>> { | ||
val orderBy = when (sortType) { | ||
AlbumSortType.CREATE_DATE -> "album.rowId ASC" | ||
AlbumSortType.NAME -> "album.title COLLATE NOCASE ASC" | ||
AlbumSortType.ARTIST -> """ORDER BY ( | ||
SELECT LOWER(GROUP_CONCAT(name, '')) | ||
FROM artist | ||
WHERE id IN (SELECT artistId FROM album_artist_map WHERE albumId = album.id) | ||
ORDER BY name | ||
) COLLATE NOCASE ASC""" | ||
AlbumSortType.YEAR -> "album.year ASC" | ||
AlbumSortType.SONG_COUNT -> "album.songCount ASC" | ||
AlbumSortType.LENGTH -> "album.duration ASC" | ||
AlbumSortType.PLAY_TIME -> "SUM(song.totalPlayTime) ASC" | ||
} | ||
|
||
val where = when (filter) { | ||
AlbumFilter.DOWNLOADED -> "song.dateDownload IS NOT NULL" | ||
AlbumFilter.LIBRARY -> "song.inLibrary IS NOT NULL" | ||
AlbumFilter.LIKED -> "album.bookmarkedAt IS NOT NULL" | ||
} | ||
|
||
val query = SimpleSQLiteQuery(""" | ||
SELECT album.*, count(song.dateDownload) downloadCount | ||
FROM album | ||
LEFT JOIN song ON song.albumId = album.id | ||
WHERE $where | ||
GROUP BY album.id | ||
ORDER BY $orderBy | ||
""") | ||
|
||
return _getAlbum(query).map { it.reversed(descending) } | ||
} | ||
|
||
fun albumsInLibraryAsc() = albums(AlbumFilter.LIBRARY, AlbumSortType.CREATE_DATE, false) | ||
fun albumsLikedAsc() = albums(AlbumFilter.LIKED, AlbumSortType.CREATE_DATE, false) | ||
// endregion | ||
|
||
// region Inserts | ||
@Insert(onConflict = OnConflictStrategy.IGNORE) | ||
fun insert(album: AlbumEntity): Long | ||
|
||
@Insert(onConflict = OnConflictStrategy.IGNORE) | ||
fun insert(map: SongAlbumMap) | ||
|
||
@Insert(onConflict = OnConflictStrategy.IGNORE) | ||
fun insert(map: AlbumArtistMap) | ||
|
||
@Transaction | ||
fun insert(albumItem: AlbumItem) { | ||
if (insert(AlbumEntity( | ||
id = albumItem.browseId, | ||
playlistId = albumItem.playlistId, | ||
title = albumItem.title, | ||
year = albumItem.year, | ||
thumbnailUrl = albumItem.thumbnail, | ||
songCount = 0, | ||
duration = 0 | ||
)) == -1L | ||
) return | ||
albumItem.artists | ||
?.map { artist -> | ||
ArtistEntity( | ||
id = artist.id ?: artistByName(artist.name)?.id ?: ArtistEntity.generateArtistId(), | ||
name = artist.name | ||
) | ||
} | ||
?.onEach(::insert) | ||
?.mapIndexed { index, artist -> | ||
AlbumArtistMap( | ||
albumId = albumItem.browseId, | ||
artistId = artist.id, | ||
order = index | ||
) | ||
} | ||
?.forEach(::insert) | ||
} | ||
// endregion | ||
|
||
// region Updates | ||
@Update | ||
fun update(album: AlbumEntity) | ||
|
||
@Upsert | ||
fun upsert(map: SongAlbumMap) | ||
|
||
@Transaction | ||
@Query("UPDATE album_artist_map SET artistId = :newId WHERE artistId = :oldId") | ||
fun updateAlbumArtistMap(oldId: String, newId: String) | ||
|
||
@Transaction | ||
@Query("DELETE FROM song_artist_map WHERE songId = :songID") | ||
fun unlinkSongArtists(songID: String) | ||
// endregion | ||
|
||
// region Deletes | ||
@Delete | ||
fun delete(album: AlbumEntity) | ||
|
||
@Transaction | ||
@Query("DELETE FROM album WHERE isLocal = 1") | ||
fun nukeLocalAlbums() | ||
// endregion | ||
} |
Oops, something went wrong.