Add Offline support for tracks
This commit is contained in:
parent
ee67f4c744
commit
8490f7115d
|
@ -5,7 +5,7 @@ import androidx.room.PrimaryKey
|
|||
import java.io.Serializable
|
||||
import java.util.Date
|
||||
|
||||
@Entity
|
||||
@Entity(tableName = "tracks")
|
||||
data class Track(
|
||||
@PrimaryKey override var id: String,
|
||||
override var parent: String? = null,
|
||||
|
|
|
@ -24,6 +24,7 @@ class ActiveServerProvider(
|
|||
private val repository: ServerSettingDao
|
||||
) : CoroutineScope by CoroutineScope(Dispatchers.IO) {
|
||||
private var cachedServer: ServerSetting? = null
|
||||
// FIXME cach never set
|
||||
private var cachedDatabase: MetaDatabase? = null
|
||||
private var cachedServerId: Int? = null
|
||||
|
||||
|
@ -110,27 +111,21 @@ class ActiveServerProvider(
|
|||
|
||||
Timber.i("Switching to new database, id:$activeServer")
|
||||
cachedServerId = activeServer
|
||||
return Room.databaseBuilder(
|
||||
UApp.applicationContext(),
|
||||
MetaDatabase::class.java,
|
||||
METADATA_DB + cachedServerId
|
||||
)
|
||||
.addMigrations(META_MIGRATION_2_1)
|
||||
.fallbackToDestructiveMigrationOnDowngrade()
|
||||
.build()
|
||||
cachedDatabase = initDatabase(activeServer)
|
||||
|
||||
return cachedDatabase!!
|
||||
}
|
||||
|
||||
val offlineMetaDatabase: MetaDatabase by lazy {
|
||||
buildDatabase(OFFLINE_DB_ID)
|
||||
initDatabase(0)
|
||||
}
|
||||
|
||||
private fun buildDatabase(id: Int?): MetaDatabase {
|
||||
private fun initDatabase(serverId: Int): MetaDatabase {
|
||||
return Room.databaseBuilder(
|
||||
UApp.applicationContext(),
|
||||
MetaDatabase::class.java,
|
||||
METADATA_DB + id
|
||||
)
|
||||
.fallbackToDestructiveMigration()
|
||||
METADATA_DB + serverId
|
||||
).fallbackToDestructiveMigration()
|
||||
.build()
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ interface AlbumDao : GenericDao<Album> {
|
|||
fun clearByArtist(id: String)
|
||||
|
||||
/**
|
||||
* FIXME: Make generic
|
||||
* TODO: Make generic
|
||||
* Upserts (insert or update) an object to the database
|
||||
*
|
||||
* @param obj the object to upsert
|
||||
|
|
|
@ -7,7 +7,7 @@ import androidx.room.Query
|
|||
import org.moire.ultrasonic.domain.Artist
|
||||
|
||||
@Dao
|
||||
interface ArtistsDao {
|
||||
interface ArtistDao {
|
||||
/**
|
||||
* Insert a list in the database. If the item already exists, replace it.
|
||||
*
|
|
@ -53,6 +53,7 @@ interface IndexDao : GenericDao<Index> {
|
|||
fun get(musicFolderId: String): List<Index>
|
||||
|
||||
/**
|
||||
* TODO: Make generic
|
||||
* Upserts (insert or update) an object to the database
|
||||
*
|
||||
* @param obj the object to upsert
|
||||
|
|
|
@ -1,33 +1,36 @@
|
|||
package org.moire.ultrasonic.data
|
||||
|
||||
import androidx.room.AutoMigration
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverter
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import org.moire.ultrasonic.domain.Album
|
||||
import java.util.Date
|
||||
import org.moire.ultrasonic.domain.Album
|
||||
import org.moire.ultrasonic.domain.Artist
|
||||
import org.moire.ultrasonic.domain.Index
|
||||
import org.moire.ultrasonic.domain.MusicFolder
|
||||
import org.moire.ultrasonic.domain.Track
|
||||
|
||||
/**
|
||||
* This database is used to store and cache the ID3 metadata
|
||||
*/
|
||||
|
||||
@Database(
|
||||
entities = [Artist::class, Album::class, Index::class, MusicFolder::class],
|
||||
version = 2,
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 1, to = 2)
|
||||
entities = [
|
||||
Artist::class,
|
||||
Album::class,
|
||||
Track::class,
|
||||
Index::class,
|
||||
MusicFolder::class
|
||||
],
|
||||
version = 2,
|
||||
exportSchema = true
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class MetaDatabase : RoomDatabase() {
|
||||
abstract fun artistsDao(): ArtistsDao
|
||||
abstract fun artistDao(): ArtistDao
|
||||
|
||||
abstract fun albumDao(): AlbumDao
|
||||
|
||||
|
@ -50,7 +53,6 @@ class Converters {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Check if correct
|
||||
val META_MIGRATION_2_1: Migration = object : Migration(2, 1) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package org.moire.ultrasonic.data
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Query
|
||||
import org.moire.ultrasonic.domain.MusicDirectory
|
||||
import org.moire.ultrasonic.domain.Track
|
||||
|
||||
interface TrackDao {
|
||||
@Dao
|
||||
@Entity(tableName = "tracks")
|
||||
interface TrackDao : GenericDao<Track> {
|
||||
/**
|
||||
* Clear the whole database
|
||||
*/
|
||||
|
@ -14,12 +18,11 @@ interface TrackDao {
|
|||
* Get all albums
|
||||
*/
|
||||
@Query("SELECT * FROM tracks")
|
||||
fun get(): List<MusicDirectory.Album>
|
||||
fun get(): List<Track>
|
||||
|
||||
/**
|
||||
* Get albums by artist
|
||||
*/
|
||||
@Query("SELECT * FROM tracks WHERE albumId LIKE :id")
|
||||
fun byAlbum(id: String): List<MusicDirectory.Entry>
|
||||
|
||||
}
|
||||
fun byAlbum(id: String): List<Track>
|
||||
}
|
||||
|
|
|
@ -600,7 +600,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
|
|||
listModel.getRandom(albumListSize)
|
||||
} else {
|
||||
setTitle(name)
|
||||
if (!isOffline() && Settings.shouldUseId3Tags) {
|
||||
if (!isOffline() && Settings.shouldUseId3Tags || Settings.useId3TagsOffline) {
|
||||
if (isAlbum) {
|
||||
listModel.getAlbum(refresh2, id!!, name)
|
||||
} else {
|
||||
|
|
|
@ -52,8 +52,9 @@ class CachedMusicService(private val musicService: MusicService) : MusicService,
|
|||
private val cachedGenres = TimeLimitedCache<List<Genre>>(10 * 3600, TimeUnit.SECONDS)
|
||||
|
||||
// New Room Database
|
||||
private var cachedArtists = metaDatabase.artistsDao()
|
||||
private var cachedArtists = metaDatabase.artistDao()
|
||||
private var cachedAlbums = metaDatabase.albumDao()
|
||||
private var cachedTracks = metaDatabase.trackDao()
|
||||
private var cachedIndexes = metaDatabase.indexDao()
|
||||
private val cachedMusicFolders = metaDatabase.musicFoldersDao()
|
||||
|
||||
|
@ -353,7 +354,7 @@ class CachedMusicService(private val musicService: MusicService) : MusicService,
|
|||
if (!Util.equals(newUrl, restUrl) || !Util.equals(cachedMusicFolderId, newFolderId)) {
|
||||
// Switch database
|
||||
metaDatabase = activeServerProvider.getActiveMetaDatabase()
|
||||
cachedArtists = metaDatabase.artistsDao()
|
||||
cachedArtists = metaDatabase.artistDao()
|
||||
cachedAlbums = metaDatabase.albumDao()
|
||||
cachedIndexes = metaDatabase.indexDao()
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.moire.ultrasonic.domain.Track
|
|||
import org.moire.ultrasonic.domain.UserInfo
|
||||
import org.moire.ultrasonic.util.AbstractFile
|
||||
import org.moire.ultrasonic.util.Constants
|
||||
import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator
|
||||
import org.moire.ultrasonic.util.FileUtil
|
||||
import org.moire.ultrasonic.util.Storage
|
||||
import org.moire.ultrasonic.util.Util.safeClose
|
||||
|
@ -56,8 +57,9 @@ class OfflineMusicService : MusicService, KoinComponent {
|
|||
private var metaDatabase: MetaDatabase = activeServerProvider.getActiveMetaDatabase()
|
||||
|
||||
// New Room Database
|
||||
private var cachedArtists = metaDatabase.artistsDao()
|
||||
private var cachedArtists = metaDatabase.artistDao()
|
||||
private var cachedAlbums = metaDatabase.albumDao()
|
||||
private var cachedTracks = metaDatabase.trackDao()
|
||||
private var cachedIndexes = metaDatabase.indexDao()
|
||||
private val cachedMusicFolders = metaDatabase.musicFoldersDao()
|
||||
|
||||
|
@ -108,7 +110,7 @@ class OfflineMusicService : MusicService, KoinComponent {
|
|||
|
||||
@Throws(OfflineException::class)
|
||||
override fun getArtists(refresh: Boolean): List<Artist> {
|
||||
var result = cachedArtists.get()
|
||||
val result = cachedArtists.get()
|
||||
|
||||
if (result.isEmpty()) {
|
||||
// use indexes?
|
||||
|
@ -478,7 +480,15 @@ class OfflineMusicService : MusicService, KoinComponent {
|
|||
|
||||
@Throws(OfflineException::class)
|
||||
override fun getAlbum(id: String, name: String?, refresh: Boolean): MusicDirectory {
|
||||
throw OfflineException("getAlbum isn't available in offline mode")
|
||||
|
||||
val list = cachedTracks
|
||||
.byAlbum(id)
|
||||
.sortedWith(EntryByDiscAndTrackComparator())
|
||||
|
||||
var dir = MusicDirectory()
|
||||
dir.addAll(list)
|
||||
|
||||
return dir
|
||||
}
|
||||
|
||||
@Throws(OfflineException::class)
|
||||
|
|
|
@ -86,6 +86,7 @@ object Constants {
|
|||
const val PREFERENCES_KEY_INCREMENT_TIME = "incrementTime"
|
||||
const val PREFERENCES_KEY_SHOW_NOW_PLAYING_DETAILS = "showNowPlayingDetails"
|
||||
const val PREFERENCES_KEY_ID3_TAGS = "useId3Tags"
|
||||
const val PREFERENCES_KEY_ID3_TAGS_OFFLINE = "useId3TagsOffline"
|
||||
const val PREFERENCES_KEY_SHOW_ARTIST_PICTURE = "showArtistPicture"
|
||||
const val PREFERENCES_KEY_CHAT_REFRESH_INTERVAL = "chatRefreshInterval"
|
||||
const val PREFERENCES_KEY_DIRECTORY_CACHE_TIME = "directoryCacheTime"
|
||||
|
|
|
@ -130,6 +130,7 @@ object Settings {
|
|||
@JvmStatic
|
||||
var mediaButtonsEnabled
|
||||
by BooleanSetting(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true)
|
||||
|
||||
var resumePlayOnHeadphonePlug
|
||||
by BooleanSetting(R.string.setting_keys_resume_play_on_headphones_plug, true)
|
||||
|
||||
|
@ -162,6 +163,9 @@ object Settings {
|
|||
@JvmStatic
|
||||
var shouldUseId3Tags by BooleanSetting(Constants.PREFERENCES_KEY_ID3_TAGS, false)
|
||||
|
||||
@JvmStatic
|
||||
var useId3TagsOffline by BooleanSetting(Constants.PREFERENCES_KEY_ID3_TAGS_OFFLINE, false)
|
||||
|
||||
var activeServer by IntSetting(Constants.PREFERENCES_KEY_SERVER_INSTANCE, -1)
|
||||
|
||||
var serverScaling by BooleanSetting(Constants.PREFERENCES_KEY_SERVER_SCALING, false)
|
||||
|
@ -244,8 +248,6 @@ object Settings {
|
|||
|
||||
var useHwOffload by BooleanSetting(Constants.PREFERENCES_KEY_HARDWARE_OFFLOAD, false)
|
||||
|
||||
var useId3TagsOffline = true
|
||||
|
||||
// TODO: Remove in December 2022
|
||||
fun migrateFeatureStorage() {
|
||||
val sp = appContext.getSharedPreferences("feature_flags", Context.MODE_PRIVATE)
|
||||
|
|
|
@ -316,6 +316,8 @@
|
|||
<string name="settings.show_now_playing_details">Show details in Now Playing</string>
|
||||
<string name="settings.use_id3">Browse Using ID3 Tags</string>
|
||||
<string name="settings.use_id3_summary">Use ID3 tag methods instead of file system based methods</string>
|
||||
<string name="settings.use_id3_offline">Use ID3 method also when offline</string>
|
||||
<string name="settings.use_id3_offline_summary">(Experimental)</string>
|
||||
<string name="settings.show_artist_picture">Show artist picture in artist list</string>
|
||||
<string name="settings.show_artist_picture_summary">Displays the artist picture in the artist list if available</string>
|
||||
<string name="main.video" tools:ignore="UnusedResources">Video</string>
|
||||
|
|
|
@ -59,6 +59,12 @@
|
|||
a:summary="@string/settings.use_id3_summary"
|
||||
a:title="@string/settings.use_id3"
|
||||
app:iconSpaceReserved="false"/>
|
||||
<CheckBoxPreference
|
||||
a:defaultValue="true"
|
||||
a:key="useId3TagsOffline"
|
||||
a:summary="@string/settings.use_id3_offline_summary"
|
||||
a:title="@string/settings.use_id3_offline"
|
||||
app:iconSpaceReserved="false"/>
|
||||
<CheckBoxPreference
|
||||
a:defaultValue="true"
|
||||
a:key="showArtistPicture"
|
||||
|
|
Loading…
Reference in New Issue