Make Ids composite of Item Id + Server Id

This commit is contained in:
tzugen 2022-07-04 17:31:58 +02:00
parent 177329abcf
commit ad54db5bcb
No known key found for this signature in database
GPG Key ID: 61E9C34BC10EC930
29 changed files with 870 additions and 153 deletions

View File

@ -1,12 +1,22 @@
/*
* Album.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.util.Date import java.util.Date
@Entity(tableName = "albums") @Entity(tableName = "albums", primaryKeys = ["id", "serverId"])
data class Album( data class Album(
@PrimaryKey override var id: String, override var id: String,
@ColumnInfo(defaultValue = "-1")
override var serverId: Int = -1,
override var parent: String? = null, override var parent: String? = null,
override var album: String? = null, override var album: String? = null,
override var title: String? = null, override var title: String? = null,

View File

@ -1,14 +1,24 @@
/*
* Artist.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(tableName = "artists") @Entity(tableName = "artists", primaryKeys = ["id", "serverId"])
data class Artist( data class Artist(
@PrimaryKey override var id: String, override var id: String,
@ColumnInfo(defaultValue = "-1")
override var serverId: Int = -1,
override var name: String? = null, override var name: String? = null,
override var index: String? = null, override var index: String? = null,
override var coverArt: String? = null, override var coverArt: String? = null,
override var albumCount: Long? = null, override var albumCount: Long? = null,
override var closeness: Int = 0 override var closeness: Int = 0
) : ArtistOrIndex(id) ) : ArtistOrIndex(id, serverId)

View File

@ -1,3 +1,10 @@
/*
* ArtistOrIndex.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import androidx.room.Ignore import androidx.room.Ignore
@ -6,6 +13,8 @@ abstract class ArtistOrIndex(
@Ignore @Ignore
override var id: String, override var id: String,
@Ignore @Ignore
open var serverId: Int,
@Ignore
override var name: String? = null, override var name: String? = null,
@Ignore @Ignore
open var index: String? = null, open var index: String? = null,
@ -18,15 +27,15 @@ abstract class ArtistOrIndex(
) : GenericEntry() { ) : GenericEntry() {
fun compareTo(other: ArtistOrIndex): Int { fun compareTo(other: ArtistOrIndex): Int {
when { return when {
this.closeness == other.closeness -> { this.closeness == other.closeness -> {
return 0 0
} }
this.closeness > other.closeness -> { this.closeness > other.closeness -> {
return -1 -1
} }
else -> { else -> {
return 1 1
} }
} }
} }

View File

@ -1,15 +1,25 @@
/*
* Index.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(tableName = "indexes") @Entity(tableName = "indexes", primaryKeys = ["id", "serverId"])
data class Index( data class Index(
@PrimaryKey override var id: String, override var id: String,
@ColumnInfo(defaultValue = "-1")
override var serverId: Int = -1,
override var name: String? = null, override var name: String? = null,
override var index: String? = null, override var index: String? = null,
override var coverArt: String? = null, override var coverArt: String? = null,
override var albumCount: Long? = null, override var albumCount: Long? = null,
override var closeness: Int = 0, override var closeness: Int = 0,
var musicFolderId: String? = null var musicFolderId: String? = null
) : ArtistOrIndex(id) ) : ArtistOrIndex(id, serverId)

View File

@ -1,3 +1,10 @@
/*
* MusicDirectory.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import java.util.Date import java.util.Date
@ -31,6 +38,7 @@ class MusicDirectory : ArrayList<MusicDirectory.Child>() {
abstract class Child : GenericEntry() { abstract class Child : GenericEntry() {
abstract override var id: String abstract override var id: String
abstract var serverId: Int
abstract var parent: String? abstract var parent: String?
abstract var isDirectory: Boolean abstract var isDirectory: Boolean
abstract var album: String? abstract var album: String?

View File

@ -1,13 +1,22 @@
/*
* MusicFolder.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey
/** /**
* Represents a top level directory in which music or other media is stored. * Represents a top level directory in which music or other media is stored.
*/ */
@Entity(tableName = "music_folders") @Entity(tableName = "music_folders", primaryKeys = ["id", "serverId"])
data class MusicFolder( data class MusicFolder(
@PrimaryKey override val id: String, override val id: String,
override val name: String override val name: String,
@ColumnInfo(defaultValue = "-1")
var serverId: Int
) : GenericEntry() ) : GenericEntry()

View File

@ -1,13 +1,23 @@
/*
* Track.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
import java.util.Date import java.util.Date
@Entity(tableName = "tracks") @Entity(tableName = "tracks", primaryKeys = ["id", "serverId"])
data class Track( data class Track(
@PrimaryKey override var id: String, override var id: String,
@ColumnInfo(defaultValue = "-1")
override var serverId: Int = -1,
override var parent: String? = null, override var parent: String? = null,
override var isDirectory: Boolean = false, override var isDirectory: Boolean = false,
override var title: String? = null, override var title: String? = null,

View File

@ -0,0 +1,514 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "95e83d6663a862c03ac46f9567453ded",
"entities": [
{
"tableName": "artists",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, `name` TEXT, `index` TEXT, `coverArt` TEXT, `albumCount` INTEGER, `closeness` INTEGER NOT NULL, PRIMARY KEY(`id`, `serverId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "-1"
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "index",
"columnName": "index",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "coverArt",
"columnName": "coverArt",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "albumCount",
"columnName": "albumCount",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "closeness",
"columnName": "closeness",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id",
"serverId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "albums",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, `parent` TEXT, `album` TEXT, `title` TEXT, `name` TEXT, `discNumber` INTEGER, `coverArt` TEXT, `songCount` INTEGER, `created` INTEGER, `artist` TEXT, `artistId` TEXT, `duration` INTEGER, `year` INTEGER, `genre` TEXT, `starred` INTEGER NOT NULL, `path` TEXT, `closeness` INTEGER NOT NULL, `isDirectory` INTEGER NOT NULL, `isVideo` INTEGER NOT NULL, PRIMARY KEY(`id`, `serverId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "-1"
},
{
"fieldPath": "parent",
"columnName": "parent",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "album",
"columnName": "album",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "discNumber",
"columnName": "discNumber",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "coverArt",
"columnName": "coverArt",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "songCount",
"columnName": "songCount",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "created",
"columnName": "created",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "artist",
"columnName": "artist",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "artistId",
"columnName": "artistId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "year",
"columnName": "year",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "genre",
"columnName": "genre",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "starred",
"columnName": "starred",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "path",
"columnName": "path",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "closeness",
"columnName": "closeness",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDirectory",
"columnName": "isDirectory",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isVideo",
"columnName": "isVideo",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id",
"serverId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "tracks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, `parent` TEXT, `isDirectory` INTEGER NOT NULL, `title` TEXT, `album` TEXT, `albumId` TEXT, `artist` TEXT, `artistId` TEXT, `track` INTEGER, `year` INTEGER, `genre` TEXT, `contentType` TEXT, `suffix` TEXT, `transcodedContentType` TEXT, `transcodedSuffix` TEXT, `coverArt` TEXT, `size` INTEGER, `songCount` INTEGER, `duration` INTEGER, `bitRate` INTEGER, `path` TEXT, `isVideo` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `discNumber` INTEGER, `type` TEXT, `created` INTEGER, `closeness` INTEGER NOT NULL, `bookmarkPosition` INTEGER NOT NULL, `userRating` INTEGER, `averageRating` REAL, `name` TEXT, PRIMARY KEY(`id`, `serverId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "-1"
},
{
"fieldPath": "parent",
"columnName": "parent",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "isDirectory",
"columnName": "isDirectory",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "album",
"columnName": "album",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "albumId",
"columnName": "albumId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "artist",
"columnName": "artist",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "artistId",
"columnName": "artistId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "track",
"columnName": "track",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "year",
"columnName": "year",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "genre",
"columnName": "genre",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "contentType",
"columnName": "contentType",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "suffix",
"columnName": "suffix",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "transcodedContentType",
"columnName": "transcodedContentType",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "transcodedSuffix",
"columnName": "transcodedSuffix",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "coverArt",
"columnName": "coverArt",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "size",
"columnName": "size",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "songCount",
"columnName": "songCount",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "bitRate",
"columnName": "bitRate",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "path",
"columnName": "path",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "isVideo",
"columnName": "isVideo",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "starred",
"columnName": "starred",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "discNumber",
"columnName": "discNumber",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "created",
"columnName": "created",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "closeness",
"columnName": "closeness",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "bookmarkPosition",
"columnName": "bookmarkPosition",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userRating",
"columnName": "userRating",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "averageRating",
"columnName": "averageRating",
"affinity": "REAL",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id",
"serverId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "indexes",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, `name` TEXT, `index` TEXT, `coverArt` TEXT, `albumCount` INTEGER, `closeness` INTEGER NOT NULL, `musicFolderId` TEXT, PRIMARY KEY(`id`, `serverId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "-1"
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "index",
"columnName": "index",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "coverArt",
"columnName": "coverArt",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "albumCount",
"columnName": "albumCount",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "closeness",
"columnName": "closeness",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "musicFolderId",
"columnName": "musicFolderId",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id",
"serverId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "music_folders",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, `name` TEXT NOT NULL, PRIMARY KEY(`id`, `serverId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "-1"
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id",
"serverId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"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, '95e83d6663a862c03ac46f9567453ded')"
]
}
}

View File

@ -1,3 +1,10 @@
/*
* ActiveServerProvider.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.data package org.moire.ultrasonic.data
import androidx.room.Room import androidx.room.Room
@ -124,7 +131,9 @@ class ActiveServerProvider(
UApp.applicationContext(), UApp.applicationContext(),
MetaDatabase::class.java, MetaDatabase::class.java,
METADATA_DB + serverId METADATA_DB + serverId
).fallbackToDestructiveMigrationOnDowngrade() )
.addMigrations(META_MIGRATION_2_3)
.fallbackToDestructiveMigrationOnDowngrade()
.build() .build()
} }

View File

@ -1,3 +1,10 @@
/*
* MetaDatabase.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.data package org.moire.ultrasonic.data
import androidx.room.AutoMigration import androidx.room.AutoMigration
@ -5,12 +12,14 @@ import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverter import androidx.room.TypeConverter
import androidx.room.TypeConverters import androidx.room.TypeConverters
import java.util.Date import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import org.moire.ultrasonic.domain.Album import org.moire.ultrasonic.domain.Album
import org.moire.ultrasonic.domain.Artist import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.Index import org.moire.ultrasonic.domain.Index
import org.moire.ultrasonic.domain.MusicFolder import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.domain.Track import org.moire.ultrasonic.domain.Track
import java.util.Date
/** /**
* This database is used to store and cache the ID3 metadata * This database is used to store and cache the ID3 metadata
@ -31,7 +40,7 @@ import org.moire.ultrasonic.domain.Track
), ),
], ],
exportSchema = true, exportSchema = true,
version = 2 version = 3
) )
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class MetaDatabase : RoomDatabase() { abstract class MetaDatabase : RoomDatabase() {
@ -57,3 +66,18 @@ class Converters {
return date?.time return date?.time
} }
} }
val META_MIGRATION_2_3: Migration = object : Migration(2,3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE `albums`")
database.execSQL("DROP TABLE `indexes`")
database.execSQL("DROP TABLE `artists`")
database.execSQL("DROP TABLE `tracks`")
database.execSQL("DROP TABLE `music_folders`")
database.execSQL("CREATE TABLE IF NOT EXISTS `albums` (`id` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, `parent` TEXT, `album` TEXT, `title` TEXT, `name` TEXT, `discNumber` INTEGER, `coverArt` TEXT, `songCount` INTEGER, `created` INTEGER, `artist` TEXT, `artistId` TEXT, `duration` INTEGER, `year` INTEGER, `genre` TEXT, `starred` INTEGER NOT NULL, `path` TEXT, `closeness` INTEGER NOT NULL, `isDirectory` INTEGER NOT NULL, `isVideo` INTEGER NOT NULL, PRIMARY KEY(`id`, `serverId`))")
database.execSQL("CREATE TABLE IF NOT EXISTS `indexes` (`id` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, `name` TEXT, `index` TEXT, `coverArt` TEXT, `albumCount` INTEGER, `closeness` INTEGER NOT NULL, `musicFolderId` TEXT, PRIMARY KEY(`id`, `serverId`))")
database.execSQL("CREATE TABLE IF NOT EXISTS `artists` (`id` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, `name` TEXT, `index` TEXT, `coverArt` TEXT, `albumCount` INTEGER, `closeness` INTEGER NOT NULL, PRIMARY KEY(`id`, `serverId`))")
database.execSQL("CREATE TABLE IF NOT EXISTS `music_folders` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, PRIMARY KEY(`id`, `serverId`))")
database.execSQL("CREATE TABLE IF NOT EXISTS `tracks` (`id` TEXT NOT NULL, `serverId` INTEGER NOT NULL DEFAULT -1, `parent` TEXT, `isDirectory` INTEGER NOT NULL, `title` TEXT, `album` TEXT, `albumId` TEXT, `artist` TEXT, `artistId` TEXT, `track` INTEGER, `year` INTEGER, `genre` TEXT, `contentType` TEXT, `suffix` TEXT, `transcodedContentType` TEXT, `transcodedSuffix` TEXT, `coverArt` TEXT, `size` INTEGER, `songCount` INTEGER, `duration` INTEGER, `bitRate` INTEGER, `path` TEXT, `isVideo` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `discNumber` INTEGER, `type` TEXT, `created` INTEGER, `closeness` INTEGER NOT NULL, `bookmarkPosition` INTEGER NOT NULL, `userRating` INTEGER, `averageRating` REAL, `name` TEXT, PRIMARY KEY(`id`, `serverId`))")
}
}

View File

@ -1,3 +1,10 @@
/*
* APIAlbumConverter.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
// Converts Album entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // Converts Album entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient]
// to app domain entities. // to app domain entities.
@file:JvmName("APIAlbumConverter") @file:JvmName("APIAlbumConverter")
@ -6,8 +13,9 @@ package org.moire.ultrasonic.domain
import org.moire.ultrasonic.api.subsonic.models.Album import org.moire.ultrasonic.api.subsonic.models.Album
typealias DomainAlbum = org.moire.ultrasonic.domain.Album typealias DomainAlbum = org.moire.ultrasonic.domain.Album
fun Album.toDomainEntity(): DomainAlbum = Album( fun Album.toDomainEntity(serverId: Int): DomainAlbum = Album(
id = this@toDomainEntity.id, id = this@toDomainEntity.id,
serverId = serverId,
title = this@toDomainEntity.name ?: this@toDomainEntity.title, title = this@toDomainEntity.name ?: this@toDomainEntity.title,
album = this@toDomainEntity.album, album = this@toDomainEntity.album,
coverArt = this@toDomainEntity.coverArt, coverArt = this@toDomainEntity.coverArt,
@ -21,8 +29,10 @@ fun Album.toDomainEntity(): DomainAlbum = Album(
starred = this@toDomainEntity.starredDate.isNotEmpty() starred = this@toDomainEntity.starredDate.isNotEmpty()
) )
fun Album.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory().apply { fun Album.toMusicDirectoryDomainEntity(serverId: Int): MusicDirectory = MusicDirectory().apply {
addAll(this@toMusicDirectoryDomainEntity.songList.map { it.toTrackEntity() }) addAll(this@toMusicDirectoryDomainEntity.songList.map { it.toTrackEntity(serverId) })
} }
fun List<Album>.toDomainEntityList(): List<DomainAlbum> = this.map { it.toDomainEntity() } fun List<Album>.toDomainEntityList(serverId: Int): List<DomainAlbum> = this.map {
it.toDomainEntity(serverId)
}

View File

@ -1,3 +1,10 @@
/*
* APIArtistConverter.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
// Converts Artist entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // Converts Artist entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient]
// to app domain entities. // to app domain entities.
@file:JvmName("APIArtistConverter") @file:JvmName("APIArtistConverter")
@ -6,24 +13,26 @@ package org.moire.ultrasonic.domain
import org.moire.ultrasonic.api.subsonic.models.Artist as APIArtist import org.moire.ultrasonic.api.subsonic.models.Artist as APIArtist
// When we like to convert to an Artist // When we like to convert to an Artist
fun APIArtist.toDomainEntity(): Artist = Artist( fun APIArtist.toDomainEntity(serverId: Int): Artist = Artist(
id = this@toDomainEntity.id, id = this@toDomainEntity.id,
serverId = serverId,
coverArt = this@toDomainEntity.coverArt, coverArt = this@toDomainEntity.coverArt,
name = this@toDomainEntity.name name = this@toDomainEntity.name
) )
// When we like to convert to an index (eg. a single directory). // When we like to convert to an index (eg. a single directory).
fun APIArtist.toIndexEntity(): Index = Index( fun APIArtist.toIndexEntity(serverId: Int): Index = Index(
id = this@toIndexEntity.id, id = this@toIndexEntity.id,
serverId = serverId,
coverArt = this@toIndexEntity.coverArt, coverArt = this@toIndexEntity.coverArt,
name = this@toIndexEntity.name name = this@toIndexEntity.name
) )
fun APIArtist.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory().apply { fun APIArtist.toMusicDirectoryDomainEntity(serverId: Int): MusicDirectory = MusicDirectory().apply {
name = this@toMusicDirectoryDomainEntity.name name = this@toMusicDirectoryDomainEntity.name
addAll(this@toMusicDirectoryDomainEntity.albumsList.map { it.toDomainEntity() }) addAll(this@toMusicDirectoryDomainEntity.albumsList.map { it.toDomainEntity(serverId) })
} }
fun APIArtist.toDomainEntityList(): List<Album> { fun APIArtist.toDomainEntityList(serverId: Int): List<Album> {
return this.albumsList.map { it.toDomainEntity() } return this.albumsList.map { it.toDomainEntity(serverId) }
} }

View File

@ -1,16 +1,25 @@
/*
* APIBookmarkConverter.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
// Contains helper functions to convert api Bookmark entity to domain entity // Contains helper functions to convert api Bookmark entity to domain entity
@file:JvmName("APIBookmarkConverter") @file:JvmName("APIBookmarkConverter")
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import org.moire.ultrasonic.api.subsonic.models.Bookmark as ApiBookmark import org.moire.ultrasonic.api.subsonic.models.Bookmark as ApiBookmark
fun ApiBookmark.toDomainEntity(): Bookmark = Bookmark( fun ApiBookmark.toDomainEntity(serverId: Int): Bookmark = Bookmark(
position = this@toDomainEntity.position.toInt(), position = this@toDomainEntity.position.toInt(),
username = this@toDomainEntity.username, username = this@toDomainEntity.username,
comment = this@toDomainEntity.comment, comment = this@toDomainEntity.comment,
created = this@toDomainEntity.created?.time, created = this@toDomainEntity.created?.time,
changed = this@toDomainEntity.changed?.time, changed = this@toDomainEntity.changed?.time,
track = this@toDomainEntity.entry.toTrackEntity() track = this@toDomainEntity.entry.toTrackEntity(serverId)
) )
fun List<ApiBookmark>.toDomainEntitiesList(): List<Bookmark> = map { it.toDomainEntity() } fun List<ApiBookmark>.toDomainEntitiesList(serverId: Int): List<Bookmark> =
map { it.toDomainEntity(serverId) }

View File

@ -1,14 +1,22 @@
/*
* APIIndexesConverter.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
// Converts Indexes entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // Converts Indexes entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient]
// to app domain entities. // to app domain entities.
@file:JvmName("APIIndexesConverter") @file:JvmName("APIIndexesConverter")
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import org.moire.ultrasonic.api.subsonic.models.Index as APIIndex import org.moire.ultrasonic.api.subsonic.models.Index as APIIndex
import org.moire.ultrasonic.api.subsonic.models.Indexes as APIIndexes import org.moire.ultrasonic.api.subsonic.models.Indexes as APIIndexes
fun APIIndexes.toArtistList(): List<Artist> { fun APIIndexes.toArtistList(serverId: Int): List<Artist> {
val shortcuts = this.shortcutList.map { it.toDomainEntity() }.toMutableList() val shortcuts = this.shortcutList.map { it.toDomainEntity(serverId) }.toMutableList()
val indexes = this.indexList.foldIndexToArtistList() val indexes = this.indexList.foldIndexToArtistList(serverId)
indexes.forEach { indexes.forEach {
if (!shortcuts.contains(it)) { if (!shortcuts.contains(it)) {
@ -19,9 +27,9 @@ fun APIIndexes.toArtistList(): List<Artist> {
return shortcuts return shortcuts
} }
fun APIIndexes.toIndexList(musicFolderId: String?): List<Index> { fun APIIndexes.toIndexList(serverId: Int, musicFolderId: String?): List<Index> {
val shortcuts = this.shortcutList.map { it.toIndexEntity() }.toMutableList() val shortcuts = this.shortcutList.map { it.toIndexEntity(serverId) }.toMutableList()
val indexes = this.indexList.foldIndexToIndexList(musicFolderId) val indexes = this.indexList.foldIndexToIndexList(musicFolderId, serverId)
indexes.forEach { indexes.forEach {
if (!shortcuts.contains(it)) { if (!shortcuts.contains(it)) {
@ -32,22 +40,23 @@ fun APIIndexes.toIndexList(musicFolderId: String?): List<Index> {
return shortcuts return shortcuts
} }
private fun List<APIIndex>.foldIndexToArtistList(): List<Artist> = this.fold( private fun List<APIIndex>.foldIndexToArtistList(serverId: Int): List<Artist> = this.fold(
listOf(), listOf()
{ acc, index -> ) { acc, index ->
acc + index.artists.map { acc + index.artists.map {
it.toDomainEntity() it.toDomainEntity(serverId)
}
} }
) }
private fun List<APIIndex>.foldIndexToIndexList(musicFolderId: String?): List<Index> = this.fold( private fun List<APIIndex>.foldIndexToIndexList(
listOf(), musicFolderId: String?,
{ acc, index -> serverId: Int
acc + index.artists.map { ): List<Index> = this.fold(
val ret = it.toIndexEntity() listOf()
ret.musicFolderId = musicFolderId ) { acc, index ->
ret acc + index.artists.map {
} val ret = it.toIndexEntity(serverId)
ret.musicFolderId = musicFolderId
ret
} }
) }

View File

@ -1,6 +1,6 @@
/* /*
* APIMusicDirectoryConverter.kt * APIMusicDirectoryConverter.kt
* Copyright (C) 2009-2021 Ultrasonic developers * Copyright (C) 2009-2022 Ultrasonic developers
* *
* Distributed under terms of the GNU GPLv3 license. * Distributed under terms of the GNU GPLv3 license.
*/ */
@ -26,12 +26,12 @@ internal val dateFormat: DateFormat by lazy {
SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault()) SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault())
} }
fun MusicDirectoryChild.toTrackEntity(): Track = Track(id).apply { fun MusicDirectoryChild.toTrackEntity(serverId: Int): Track = Track(id, serverId).apply {
populateCommonProps(this, this@toTrackEntity) populateCommonProps(this, this@toTrackEntity)
populateTrackProps(this, this@toTrackEntity) populateTrackProps(this, this@toTrackEntity)
} }
fun MusicDirectoryChild.toAlbumEntity(): Album = Album(id).apply { fun MusicDirectoryChild.toAlbumEntity(serverId: Int): Album = Album(id, serverId).apply {
populateCommonProps(this, this@toAlbumEntity) populateCommonProps(this, this@toAlbumEntity)
} }
@ -80,24 +80,24 @@ private fun populateTrackProps(
track.averageRating = source.averageRating track.averageRating = source.averageRating
} }
fun List<MusicDirectoryChild>.toDomainEntityList(): List<MusicDirectory.Child> { fun List<MusicDirectoryChild>.toDomainEntityList(serverId: Int): List<MusicDirectory.Child> {
val newList: MutableList<MusicDirectory.Child> = mutableListOf() val newList: MutableList<MusicDirectory.Child> = mutableListOf()
forEach { forEach {
if (it.isDir) if (it.isDir)
newList.add(it.toAlbumEntity()) newList.add(it.toAlbumEntity(serverId))
else else
newList.add(it.toTrackEntity()) newList.add(it.toTrackEntity(serverId))
} }
return newList return newList
} }
fun List<MusicDirectoryChild>.toTrackList(): List<Track> = this.map { fun List<MusicDirectoryChild>.toTrackList(serverId: Int): List<Track> = this.map {
it.toTrackEntity() it.toTrackEntity(serverId)
} }
fun APIMusicDirectory.toDomainEntity(): MusicDirectory = MusicDirectory().apply { fun APIMusicDirectory.toDomainEntity(serverId: Int): MusicDirectory = MusicDirectory().apply {
name = this@toDomainEntity.name name = this@toDomainEntity.name
addAll(this@toDomainEntity.childList.toDomainEntityList()) addAll(this@toDomainEntity.childList.toDomainEntityList(serverId))
} }

View File

@ -1,3 +1,10 @@
/*
* APIMusicFolderConverter.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
// Converts MusicFolder entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // Converts MusicFolder entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient]
// to app domain entities. // to app domain entities.
@file:JvmName("APIMusicFolderConverter") @file:JvmName("APIMusicFolderConverter")
@ -5,7 +12,15 @@ package org.moire.ultrasonic.domain
import org.moire.ultrasonic.api.subsonic.models.MusicFolder as APIMusicFolder import org.moire.ultrasonic.api.subsonic.models.MusicFolder as APIMusicFolder
fun APIMusicFolder.toDomainEntity(): MusicFolder = MusicFolder(this.id, this.name) fun APIMusicFolder.toDomainEntity(serverId: Int): MusicFolder = MusicFolder(
id = this.id,
serverId = serverId,
name = this.name
)
fun List<APIMusicFolder>.toDomainEntityList(): List<MusicFolder> = fun List<APIMusicFolder>.toDomainEntityList(serverId: Int): List<MusicFolder> =
this.map { it.toDomainEntity() } this.map {
val item = it.toDomainEntity(serverId)
item.serverId = serverId
item
}

View File

@ -1,6 +1,14 @@
/*
* APIPlaylistConverter.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
// Converts Playlist entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // Converts Playlist entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient]
// to app domain entities. // to app domain entities.
@file:JvmName("APIPlaylistConverter") @file:JvmName("APIPlaylistConverter")
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -10,10 +18,15 @@ import org.moire.ultrasonic.util.Util.ifNotNull
internal val playlistDateFormat by lazy(NONE) { SimpleDateFormat.getInstance() } internal val playlistDateFormat by lazy(NONE) { SimpleDateFormat.getInstance() }
fun APIPlaylist.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory().apply { fun APIPlaylist.toMusicDirectoryDomainEntity(serverId: Int): MusicDirectory =
name = this@toMusicDirectoryDomainEntity.name MusicDirectory().apply {
addAll(this@toMusicDirectoryDomainEntity.entriesList.map { it.toTrackEntity() }) name = this@toMusicDirectoryDomainEntity.name
} addAll(this@toMusicDirectoryDomainEntity.entriesList.map {
val item = it.toTrackEntity(serverId)
item.serverId = serverId
item
})
}
fun APIPlaylist.toDomainEntity(): Playlist = Playlist( fun APIPlaylist.toDomainEntity(): Playlist = Playlist(
this.id, this.name, this.owner, this.id, this.name, this.owner,

View File

@ -1,3 +1,10 @@
/*
* APISearchConverter.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
// Converts SearchResult entities from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // Converts SearchResult entities from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient]
// to app domain entities. // to app domain entities.
@file:JvmName("APISearchConverter") @file:JvmName("APISearchConverter")
@ -7,19 +14,19 @@ import org.moire.ultrasonic.api.subsonic.models.SearchResult as APISearchResult
import org.moire.ultrasonic.api.subsonic.models.SearchThreeResult import org.moire.ultrasonic.api.subsonic.models.SearchThreeResult
import org.moire.ultrasonic.api.subsonic.models.SearchTwoResult import org.moire.ultrasonic.api.subsonic.models.SearchTwoResult
fun APISearchResult.toDomainEntity(): SearchResult = SearchResult( fun APISearchResult.toDomainEntity(serverId: Int): SearchResult = SearchResult(
emptyList(), emptyList(), emptyList(), emptyList(),
this.matchList.map { it.toTrackEntity() } this.matchList.map { it.toTrackEntity(serverId) }
) )
fun SearchTwoResult.toDomainEntity(): SearchResult = SearchResult( fun SearchTwoResult.toDomainEntity(serverId: Int): SearchResult = SearchResult(
this.artistList.map { it.toIndexEntity() }, this.artistList.map { it.toIndexEntity(serverId) },
this.albumList.map { it.toDomainEntity() }, this.albumList.map { it.toDomainEntity(serverId) },
this.songList.map { it.toTrackEntity() } this.songList.map { it.toTrackEntity(serverId) }
) )
fun SearchThreeResult.toDomainEntity(): SearchResult = SearchResult( fun SearchThreeResult.toDomainEntity(serverId: Int): SearchResult = SearchResult(
this.artistList.map { it.toDomainEntity() }, this.artistList.map { it.toDomainEntity(serverId) },
this.albumList.map { it.toDomainEntity() }, this.albumList.map { it.toDomainEntity(serverId) },
this.songList.map { it.toTrackEntity() } this.songList.map { it.toTrackEntity(serverId) }
) )

View File

@ -1,3 +1,10 @@
/*
* APIShareConverter.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
// Contains helper method to convert subsonic api share to domain model // Contains helper method to convert subsonic api share to domain model
@file:JvmName("APIShareConverter") @file:JvmName("APIShareConverter")
package org.moire.ultrasonic.domain package org.moire.ultrasonic.domain
@ -9,11 +16,11 @@ import org.moire.ultrasonic.util.Util.ifNotNull
internal val shareTimeFormat by lazy(NONE) { SimpleDateFormat.getInstance() } internal val shareTimeFormat by lazy(NONE) { SimpleDateFormat.getInstance() }
fun List<APIShare>.toDomainEntitiesList(): List<Share> = this.map { fun List<APIShare>.toDomainEntitiesList(serverId: Int): List<Share> = this.map {
it.toDomainEntity() it.toDomainEntity(serverId)
} }
fun APIShare.toDomainEntity(): Share = Share( fun APIShare.toDomainEntity(serverId: Int): Share = Share(
created = this@toDomainEntity.created.ifNotNull { shareTimeFormat.format(it.time) }, created = this@toDomainEntity.created.ifNotNull { shareTimeFormat.format(it.time) },
description = this@toDomainEntity.description, description = this@toDomainEntity.description,
expires = this@toDomainEntity.expires.ifNotNull { shareTimeFormat.format(it.time) }, expires = this@toDomainEntity.expires.ifNotNull { shareTimeFormat.format(it.time) },
@ -22,5 +29,5 @@ fun APIShare.toDomainEntity(): Share = Share(
url = this@toDomainEntity.url, url = this@toDomainEntity.url,
username = this@toDomainEntity.username, username = this@toDomainEntity.username,
visitCount = this@toDomainEntity.visitCount.toLong(), visitCount = this@toDomainEntity.visitCount.toLong(),
tracks = this@toDomainEntity.items.toTrackList().toMutableList() tracks = this@toDomainEntity.items.toTrackList(serverId).toMutableList()
) )

View File

@ -1,6 +1,6 @@
/* /*
* OfflineMusicService.kt * OfflineMusicService.kt
* Copyright (C) 2009-2021 Ultrasonic developers * Copyright (C) 2009-2022 Ultrasonic developers
* *
* Distributed under terms of the GNU GPLv3 license. * Distributed under terms of the GNU GPLv3 license.
*/ */
@ -66,7 +66,7 @@ class OfflineMusicService : MusicService, KoinComponent {
val root = FileUtil.musicDirectory val root = FileUtil.musicDirectory
for (file in FileUtil.listFiles(root)) { for (file in FileUtil.listFiles(root)) {
if (file.isDirectory) { if (file.isDirectory) {
val index = Index(file.path) val index = Index(id = file.path)
index.id = file.path index.id = file.path
index.index = file.name.substring(0, 1) index.index = file.name.substring(0, 1)
index.name = file.name index.name = file.name

View File

@ -1,6 +1,6 @@
/* /*
* RestMusicService.kt * RESTMusicService.kt
* Copyright (C) 2009-2021 Ultrasonic developers * Copyright (C) 2009-2022 Ultrasonic developers
* *
* Distributed under terms of the GNU GPLv3 license. * Distributed under terms of the GNU GPLv3 license.
*/ */
@ -78,7 +78,7 @@ open class RESTMusicService(
): List<MusicFolder> { ): List<MusicFolder> {
val response = API.getMusicFolders().execute().throwOnFailure() val response = API.getMusicFolders().execute().throwOnFailure()
return response.body()!!.musicFolders.toDomainEntityList() return response.body()!!.musicFolders.toDomainEntityList(activeServerId)
} }
/** /**
@ -91,7 +91,10 @@ open class RESTMusicService(
): List<Index> { ): List<Index> {
val response = API.getIndexes(musicFolderId, null).execute().throwOnFailure() val response = API.getIndexes(musicFolderId, null).execute().throwOnFailure()
return response.body()!!.indexes.toIndexList(musicFolderId) return response.body()!!.indexes.toIndexList(
ActiveServerProvider.getActiveServerId(),
musicFolderId
)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -100,7 +103,7 @@ open class RESTMusicService(
): List<Artist> { ): List<Artist> {
val response = API.getArtists(null).execute().throwOnFailure() val response = API.getArtists(null).execute().throwOnFailure()
return response.body()!!.indexes.toArtistList() return response.body()!!.indexes.toArtistList(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -137,7 +140,7 @@ open class RESTMusicService(
): MusicDirectory { ): MusicDirectory {
val response = API.getMusicDirectory(id).execute().throwOnFailure() val response = API.getMusicDirectory(id).execute().throwOnFailure()
return response.body()!!.musicDirectory.toDomainEntity() return response.body()!!.musicDirectory.toDomainEntity(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -148,7 +151,7 @@ open class RESTMusicService(
): List<Album> { ): List<Album> {
val response = API.getArtist(id).execute().throwOnFailure() val response = API.getArtist(id).execute().throwOnFailure()
return response.body()!!.artist.toDomainEntityList() return response.body()!!.artist.toDomainEntityList(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -159,7 +162,7 @@ open class RESTMusicService(
): MusicDirectory { ): MusicDirectory {
val response = API.getAlbum(id).execute().throwOnFailure() val response = API.getAlbum(id).execute().throwOnFailure()
return response.body()!!.album.toMusicDirectoryDomainEntity() return response.body()!!.album.toMusicDirectoryDomainEntity(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -189,7 +192,7 @@ open class RESTMusicService(
API.search(null, null, null, criteria.query, criteria.songCount, null, null) API.search(null, null, null, criteria.query, criteria.songCount, null, null)
.execute().throwOnFailure() .execute().throwOnFailure()
return response.body()!!.searchResult.toDomainEntity() return response.body()!!.searchResult.toDomainEntity(activeServerId)
} }
/** /**
@ -205,7 +208,7 @@ open class RESTMusicService(
criteria.songCount, null criteria.songCount, null
).execute().throwOnFailure() ).execute().throwOnFailure()
return response.body()!!.searchResult.toDomainEntity() return response.body()!!.searchResult.toDomainEntity(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -218,7 +221,7 @@ open class RESTMusicService(
criteria.songCount, null criteria.songCount, null
).execute().throwOnFailure() ).execute().throwOnFailure()
return response.body()!!.searchResult.toDomainEntity() return response.body()!!.searchResult.toDomainEntity(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -228,7 +231,7 @@ open class RESTMusicService(
): MusicDirectory { ): MusicDirectory {
val response = API.getPlaylist(id).execute().throwOnFailure() val response = API.getPlaylist(id).execute().throwOnFailure()
val playlist = response.body()!!.playlist.toMusicDirectoryDomainEntity() val playlist = response.body()!!.playlist.toMusicDirectoryDomainEntity(activeServerId)
savePlaylist(name, playlist) savePlaylist(name, playlist)
return playlist return playlist
@ -319,7 +322,7 @@ open class RESTMusicService(
"skipped" != podcastEntry.status && "skipped" != podcastEntry.status &&
"error" != podcastEntry.status "error" != podcastEntry.status
) { ) {
val entry = podcastEntry.toTrackEntity() val entry = podcastEntry.toTrackEntity(activeServerId)
entry.track = null entry.track = null
musicDirectory.add(entry) musicDirectory.add(entry)
} }
@ -363,7 +366,7 @@ open class RESTMusicService(
musicFolderId musicFolderId
).execute().throwOnFailure() ).execute().throwOnFailure()
return response.body()!!.albumList.toDomainEntityList() return response.body()!!.albumList.toDomainEntityList(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -383,7 +386,7 @@ open class RESTMusicService(
musicFolderId musicFolderId
).execute().throwOnFailure() ).execute().throwOnFailure()
return response.body()!!.albumList.toDomainEntityList() return response.body()!!.albumList.toDomainEntityList(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -399,7 +402,7 @@ open class RESTMusicService(
).execute().throwOnFailure() ).execute().throwOnFailure()
val result = MusicDirectory() val result = MusicDirectory()
result.addAll(response.body()!!.songsList.toDomainEntityList()) result.addAll(response.body()!!.songsList.toDomainEntityList(activeServerId))
return result return result
} }
@ -408,14 +411,14 @@ open class RESTMusicService(
override fun getStarred(): SearchResult { override fun getStarred(): SearchResult {
val response = API.getStarred(null).execute().throwOnFailure() val response = API.getStarred(null).execute().throwOnFailure()
return response.body()!!.starred.toDomainEntity() return response.body()!!.starred.toDomainEntity(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
override fun getStarred2(): SearchResult { override fun getStarred2(): SearchResult {
val response = API.getStarred2(null).execute().throwOnFailure() val response = API.getStarred2(null).execute().throwOnFailure()
return response.body()!!.starred2.toDomainEntity() return response.body()!!.starred2.toDomainEntity(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -546,7 +549,7 @@ open class RESTMusicService(
): List<Share> { ): List<Share> {
val response = API.getShares().execute().throwOnFailure() val response = API.getShares().execute().throwOnFailure()
return response.body()!!.shares.toDomainEntitiesList() return response.body()!!.shares.toDomainEntitiesList(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -567,7 +570,7 @@ open class RESTMusicService(
val response = API.getSongsByGenre(genre, count, offset, null).execute().throwOnFailure() val response = API.getSongsByGenre(genre, count, offset, null).execute().throwOnFailure()
val result = MusicDirectory() val result = MusicDirectory()
result.addAll(response.body()!!.songsList.toDomainEntityList()) result.addAll(response.body()!!.songsList.toDomainEntityList(activeServerId))
return result return result
} }
@ -601,7 +604,7 @@ open class RESTMusicService(
override fun getBookmarks(): List<Bookmark> { override fun getBookmarks(): List<Bookmark> {
val response = API.getBookmarks().execute().throwOnFailure() val response = API.getBookmarks().execute().throwOnFailure()
return response.body()!!.bookmarkList.toDomainEntitiesList() return response.body()!!.bookmarkList.toDomainEntitiesList(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -626,7 +629,7 @@ open class RESTMusicService(
val response = API.getVideos().execute().throwOnFailure() val response = API.getVideos().execute().throwOnFailure()
val musicDirectory = MusicDirectory() val musicDirectory = MusicDirectory()
musicDirectory.addAll(response.body()!!.videosList.toDomainEntityList()) musicDirectory.addAll(response.body()!!.videosList.toDomainEntityList(activeServerId))
return musicDirectory return musicDirectory
} }
@ -639,7 +642,7 @@ open class RESTMusicService(
): List<Share> { ): List<Share> {
val response = API.createShare(ids, description, expires).execute().throwOnFailure() val response = API.createShare(ids, description, expires).execute().throwOnFailure()
return response.body()!!.shares.toDomainEntitiesList() return response.body()!!.shares.toDomainEntitiesList(activeServerId)
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -663,6 +666,9 @@ open class RESTMusicService(
API.updateShare(id, description, expiresValue).execute().throwOnFailure() API.updateShare(id, description, expiresValue).execute().throwOnFailure()
} }
private val activeServerId: Int
get() = ActiveServerProvider.getActiveServerId()
init { init {
// The client will notice if the minimum supported API version has changed // The client will notice if the minimum supported API version has changed
// By registering a callback we ensure this info is saved in the database as well // By registering a callback we ensure this info is saved in the database as well

View File

@ -7,11 +7,14 @@ import org.amshove.kluent.`should be equal to`
import org.junit.Test import org.junit.Test
import org.moire.ultrasonic.api.subsonic.models.Album import org.moire.ultrasonic.api.subsonic.models.Album
import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild
import org.moire.ultrasonic.data.ActiveServerProvider
/** /**
* Unit test for extension functions in [APIAlbumConverter.kt] file. * Unit test for extension functions in [APIAlbumConverter.kt] file.
*/ */
class APIAlbumConverterTest { class APIAlbumConverterTest {
private val serverId = -1
@Test @Test
fun `Should convert Album to domain entity`() { fun `Should convert Album to domain entity`() {
val entity = Album( val entity = Album(
@ -20,7 +23,7 @@ class APIAlbumConverterTest {
created = Calendar.getInstance(), year = 2017, genre = "some-genre" created = Calendar.getInstance(), year = 2017, genre = "some-genre"
) )
val convertedEntity = entity.toDomainEntity() val convertedEntity = entity.toDomainEntity(serverId)
with(convertedEntity) { with(convertedEntity) {
id `should be equal to` entity.id id `should be equal to` entity.id
@ -46,12 +49,12 @@ class APIAlbumConverterTest {
songList = listOf(MusicDirectoryChild()) songList = listOf(MusicDirectoryChild())
) )
val convertedEntity = entity.toMusicDirectoryDomainEntity() val convertedEntity = entity.toMusicDirectoryDomainEntity(serverId)
with(convertedEntity) { with(convertedEntity) {
name `should be equal to` null name `should be equal to` null
size `should be equal to` entity.songList.size size `should be equal to` entity.songList.size
this[0] `should be equal to` entity.songList[0].toTrackEntity() this[0] `should be equal to` entity.songList[0].toTrackEntity(serverId)
} }
} }
@ -59,12 +62,12 @@ class APIAlbumConverterTest {
fun `Should convert list of Album entities to domain list entities`() { fun `Should convert list of Album entities to domain list entities`() {
val entityList = listOf(Album(id = "455"), Album(id = "1"), Album(id = "1000")) val entityList = listOf(Album(id = "455"), Album(id = "1"), Album(id = "1000"))
val convertedList = entityList.toDomainEntityList() val convertedList = entityList.toDomainEntityList(ActiveServerProvider.getActiveServerId())
with(convertedList) { with(convertedList) {
size `should be equal to` entityList.size size `should be equal to` entityList.size
forEachIndexed { index, entry -> forEachIndexed { index, entry ->
entry `should be equal to` entityList[index].toDomainEntity() entry `should be equal to` entityList[index].toDomainEntity(serverId)
} }
} }
} }

View File

@ -11,12 +11,12 @@ import org.moire.ultrasonic.api.subsonic.models.Artist
/** /**
* Unit test for extension functions in APIArtistConverter.kt file. * Unit test for extension functions in APIArtistConverter.kt file.
*/ */
class APIArtistConverterTest { class APIArtistConverterTest : BaseTest() {
@Test @Test
fun `Should convert artist entity`() { fun `Should convert artist entity`() {
val entity = Artist(id = "10", name = "artist-name", starred = Calendar.getInstance()) val entity = Artist(id = "10", name = "artist-name", starred = Calendar.getInstance())
val convertedEntity = entity.toDomainEntity() val convertedEntity = entity.toDomainEntity(serverId)
with(convertedEntity) { with(convertedEntity) {
id `should be equal to` entity.id id `should be equal to` entity.id
@ -38,12 +38,12 @@ class APIArtistConverterTest {
) )
) )
val convertedEntity = entity.toMusicDirectoryDomainEntity() val convertedEntity = entity.toMusicDirectoryDomainEntity(serverId)
with(convertedEntity) { with(convertedEntity) {
name `should be equal to` entity.name name `should be equal to` entity.name
getChildren() `should be equal to` entity.albumsList getChildren() `should be equal to` entity.albumsList
.map { it.toDomainEntity() }.toMutableList() .map { it.toDomainEntity(serverId) }.toMutableList()
} }
} }
} }

View File

@ -11,7 +11,8 @@ import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild
/** /**
* Unit test for function that converts [Bookmark] api entity to domain. * Unit test for function that converts [Bookmark] api entity to domain.
*/ */
class APIBookmarkConverterTest { class APIBookmarkConverterTest : BaseTest() {
@Test @Test
fun `Should convert to domain entity`() { fun `Should convert to domain entity`() {
val entity = Bookmark( val entity = Bookmark(
@ -19,7 +20,7 @@ class APIBookmarkConverterTest {
Calendar.getInstance(), MusicDirectoryChild(id = "12333") Calendar.getInstance(), MusicDirectoryChild(id = "12333")
) )
val domainEntity = entity.toDomainEntity() val domainEntity = entity.toDomainEntity(serverId)
with(domainEntity) { with(domainEntity) {
position `should be equal to` entity.position.toInt() position `should be equal to` entity.position.toInt()
@ -27,7 +28,7 @@ class APIBookmarkConverterTest {
comment `should be equal to` entity.comment comment `should be equal to` entity.comment
created `should be equal to` entity.created?.time created `should be equal to` entity.created?.time
changed `should be equal to` entity.changed?.time changed `should be equal to` entity.changed?.time
track `should be equal to` entity.entry.toTrackEntity() track `should be equal to` entity.entry.toTrackEntity(serverId)
} }
} }
@ -35,11 +36,11 @@ class APIBookmarkConverterTest {
fun `Should convert list of entities to domain entities`() { fun `Should convert list of entities to domain entities`() {
val entitiesList = listOf(Bookmark(443L), Bookmark(444L)) val entitiesList = listOf(Bookmark(443L), Bookmark(444L))
val domainEntitiesList = entitiesList.toDomainEntitiesList() val domainEntitiesList = entitiesList.toDomainEntitiesList(serverId)
domainEntitiesList.size `should be equal to` entitiesList.size domainEntitiesList.size `should be equal to` entitiesList.size
domainEntitiesList.forEachIndexed({ index, bookmark -> domainEntitiesList.forEachIndexed { index, bookmark ->
bookmark `should be equal to` entitiesList[index].toDomainEntity() bookmark `should be equal to` entitiesList[index].toDomainEntity(serverId)
}) }
} }
} }

View File

@ -7,11 +7,12 @@ import org.amshove.kluent.`should be equal to`
import org.junit.Test import org.junit.Test
import org.moire.ultrasonic.api.subsonic.models.MusicDirectory import org.moire.ultrasonic.api.subsonic.models.MusicDirectory
import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild
import org.moire.ultrasonic.data.ActiveServerProvider
/** /**
* Unit test for extension functions in APIMusicDirectoryConverter.kt file. * Unit test for extension functions in APIMusicDirectoryConverter.kt file.
*/ */
class APIMusicDirectoryConverterTest { class APIMusicDirectoryConverterTest : BaseTest() {
@Test @Test
fun `Should convert MusicDirectory entity`() { fun `Should convert MusicDirectory entity`() {
val entity = MusicDirectory( val entity = MusicDirectory(
@ -20,13 +21,13 @@ class APIMusicDirectoryConverterTest {
childList = listOf(MusicDirectoryChild("1"), MusicDirectoryChild("2")) childList = listOf(MusicDirectoryChild("1"), MusicDirectoryChild("2"))
) )
val convertedEntity = entity.toDomainEntity() val convertedEntity = entity.toDomainEntity(ActiveServerProvider.getActiveServerId())
with(convertedEntity) { with(convertedEntity) {
name `should be equal to` entity.name name `should be equal to` entity.name
size `should be equal to` entity.childList.size size `should be equal to` entity.childList.size
getChildren() `should be equal to` entity.childList getChildren() `should be equal to` entity.childList
.map { it.toTrackEntity() }.toMutableList() .map { it.toTrackEntity(serverId) }.toMutableList()
} }
} }
@ -44,7 +45,7 @@ class APIMusicDirectoryConverterTest {
starred = Calendar.getInstance(), userRating = 3, averageRating = 2.99F starred = Calendar.getInstance(), userRating = 3, averageRating = 2.99F
) )
val convertedEntity = entity.toTrackEntity() val convertedEntity = entity.toTrackEntity(serverId)
with(convertedEntity) { with(convertedEntity) {
id `should be equal to` entity.id id `should be equal to` entity.id
@ -84,7 +85,7 @@ class APIMusicDirectoryConverterTest {
artist = "some-artist", publishDate = Calendar.getInstance() artist = "some-artist", publishDate = Calendar.getInstance()
) )
val convertedEntity = entity.toTrackEntity() val convertedEntity = entity.toTrackEntity(serverId)
with(convertedEntity) { with(convertedEntity) {
id `should be equal to` entity.streamId id `should be equal to` entity.streamId
@ -96,11 +97,11 @@ class APIMusicDirectoryConverterTest {
fun `Should convert list of MusicDirectoryChild to domain entity list`() { fun `Should convert list of MusicDirectoryChild to domain entity list`() {
val entitiesList = listOf(MusicDirectoryChild(id = "45"), MusicDirectoryChild(id = "34")) val entitiesList = listOf(MusicDirectoryChild(id = "45"), MusicDirectoryChild(id = "34"))
val domainList = entitiesList.toDomainEntityList() val domainList = entitiesList.toDomainEntityList(serverId)
domainList.size `should be equal to` entitiesList.size domainList.size `should be equal to` entitiesList.size
domainList.forEachIndexed { index, entry -> domainList.forEachIndexed { index, entry ->
entry `should be equal to` entitiesList[index].toTrackEntity() entry `should be equal to` entitiesList[index].toTrackEntity(serverId)
} }
} }
} }

View File

@ -9,12 +9,12 @@ import org.moire.ultrasonic.api.subsonic.models.MusicFolder
/** /**
* Unit test for extension functions in file APIMusicFolderConverter.kt. * Unit test for extension functions in file APIMusicFolderConverter.kt.
*/ */
class APIMusicFolderConverterTest { class APIMusicFolderConverterTest : BaseTest() {
@Test @Test
fun `Should convert MusicFolder entity`() { fun `Should convert MusicFolder entity`() {
val entity = MusicFolder(id = "10", name = "some-name") val entity = MusicFolder(id = "10", name = "some-name")
val convertedEntity = entity.toDomainEntity() val convertedEntity = entity.toDomainEntity(serverId)
convertedEntity.name `should be equal to` entity.name convertedEntity.name `should be equal to` entity.name
convertedEntity.id `should be equal to` entity.id convertedEntity.id `should be equal to` entity.id
@ -27,7 +27,7 @@ class APIMusicFolderConverterTest {
MusicFolder(id = "4", name = "some-name-4") MusicFolder(id = "4", name = "some-name-4")
) )
val convertedList = entityList.toDomainEntityList() val convertedList = entityList.toDomainEntityList(serverId)
with(convertedList) { with(convertedList) {
size `should be equal to` entityList.size size `should be equal to` entityList.size

View File

@ -7,11 +7,12 @@ import org.amshove.kluent.`should be equal to`
import org.junit.Test import org.junit.Test
import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild
import org.moire.ultrasonic.api.subsonic.models.Playlist import org.moire.ultrasonic.api.subsonic.models.Playlist
import org.moire.ultrasonic.data.ActiveServerProvider
/** /**
* Unit test for extension functions that converts api playlist entity to domain. * Unit test for extension functions that converts api playlist entity to domain.
*/ */
class APIPlaylistConverterTest { class APIPlaylistConverterTest : BaseTest() {
@Test @Test
fun `Should convert Playlist to MusicDirectory domain entity`() { fun `Should convert Playlist to MusicDirectory domain entity`() {
val entity = Playlist( val entity = Playlist(
@ -22,13 +23,13 @@ class APIPlaylistConverterTest {
) )
) )
val convertedEntity = entity.toMusicDirectoryDomainEntity() val convertedEntity = entity.toMusicDirectoryDomainEntity(ActiveServerProvider.getActiveServerId())
with(convertedEntity) { with(convertedEntity) {
name `should be equal to` entity.name name `should be equal to` entity.name
size `should be equal to` entity.entriesList.size size `should be equal to` entity.entriesList.size
this[0] `should be equal to` entity.entriesList[0].toTrackEntity() this[0] `should be equal to` entity.entriesList[0].toTrackEntity(serverId)
this[1] `should be equal to` entity.entriesList[1].toTrackEntity() this[1] `should be equal to` entity.entriesList[1].toTrackEntity(serverId)
} }
} }

View File

@ -11,11 +11,12 @@ import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild
import org.moire.ultrasonic.api.subsonic.models.SearchResult import org.moire.ultrasonic.api.subsonic.models.SearchResult
import org.moire.ultrasonic.api.subsonic.models.SearchThreeResult import org.moire.ultrasonic.api.subsonic.models.SearchThreeResult
import org.moire.ultrasonic.api.subsonic.models.SearchTwoResult import org.moire.ultrasonic.api.subsonic.models.SearchTwoResult
import org.moire.ultrasonic.data.ActiveServerProvider
/** /**
* Unit test for extension function in APISearchConverter.kt file. * Unit test for extension function in APISearchConverter.kt file.
*/ */
class APISearchConverterTest { class APISearchConverterTest : BaseTest() {
@Test @Test
fun `Should convert SearchResult to domain entity`() { fun `Should convert SearchResult to domain entity`() {
val entity = SearchResult( val entity = SearchResult(
@ -26,7 +27,7 @@ class APISearchConverterTest {
) )
) )
val convertedEntity = entity.toDomainEntity() val convertedEntity = entity.toDomainEntity(serverId)
with(convertedEntity) { with(convertedEntity) {
albums `should not be equal to` null albums `should not be equal to` null
@ -34,7 +35,7 @@ class APISearchConverterTest {
artists `should not be equal to` null artists `should not be equal to` null
artists.size `should be equal to` 0 artists.size `should be equal to` 0
songs.size `should be equal to` entity.matchList.size songs.size `should be equal to` entity.matchList.size
songs[0] `should be equal to` entity.matchList[0].toTrackEntity() songs[0] `should be equal to` entity.matchList[0].toTrackEntity(serverId)
} }
} }
@ -46,15 +47,15 @@ class APISearchConverterTest {
listOf(MusicDirectoryChild(id = "9118", parent = "112")) listOf(MusicDirectoryChild(id = "9118", parent = "112"))
) )
val convertedEntity = entity.toDomainEntity() val convertedEntity = entity.toDomainEntity(ActiveServerProvider.getActiveServerId())
with(convertedEntity) { with(convertedEntity) {
artists.size `should be equal to` entity.artistList.size artists.size `should be equal to` entity.artistList.size
artists[0] `should be equal to` entity.artistList[0].toIndexEntity() artists[0] `should be equal to` entity.artistList[0].toIndexEntity(serverId)
albums.size `should be equal to` entity.albumList.size albums.size `should be equal to` entity.albumList.size
albums[0] `should be equal to` entity.albumList[0].toDomainEntity() albums[0] `should be equal to` entity.albumList[0].toDomainEntity(serverId)
songs.size `should be equal to` entity.songList.size songs.size `should be equal to` entity.songList.size
songs[0] `should be equal to` entity.songList[0].toTrackEntity() songs[0] `should be equal to` entity.songList[0].toTrackEntity(serverId)
} }
} }
@ -66,15 +67,15 @@ class APISearchConverterTest {
songList = listOf(MusicDirectoryChild(id = "7123", title = "song1")) songList = listOf(MusicDirectoryChild(id = "7123", title = "song1"))
) )
val convertedEntity = entity.toDomainEntity() val convertedEntity = entity.toDomainEntity(serverId)
with(convertedEntity) { with(convertedEntity) {
artists.size `should be equal to` entity.artistList.size artists.size `should be equal to` entity.artistList.size
artists[0] `should be equal to` entity.artistList[0].toDomainEntity() artists[0] `should be equal to` entity.artistList[0].toDomainEntity(serverId)
albums.size `should be equal to` entity.albumList.size albums.size `should be equal to` entity.albumList.size
albums[0] `should be equal to` entity.albumList[0].toDomainEntity() albums[0] `should be equal to` entity.albumList[0].toDomainEntity(serverId)
songs.size `should be equal to` entity.songList.size songs.size `should be equal to` entity.songList.size
songs[0] `should be equal to` entity.songList[0].toTrackEntity() songs[0] `should be equal to` entity.songList[0].toTrackEntity(serverId)
} }
} }
} }

View File

@ -0,0 +1,12 @@
/*
* BaseTest.kt
* Copyright (C) 2009-2022 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.domain
open class BaseTest {
internal val serverId = -1
}