From 10b83805a9df899be36349aeb1d251b89f9ba501 Mon Sep 17 00:00:00 2001
From: tzugen <tzugen@riseup.net>
Date: Tue, 21 Dec 2021 12:16:40 +0100
Subject: [PATCH] Create a correctly typed list from getMusicDirectory()

---
 .../moire/ultrasonic/domain/MusicDirectory.kt |  28 ++--
 .../ultrasonic/domain/APIAlbumConverter.kt    |   2 +-
 .../ultrasonic/domain/APIBookmarkConverter.kt |   2 +-
 .../domain/APIMusicDirectoryConverter.kt      | 121 ++++++++++++------
 .../ultrasonic/domain/APIPlaylistConverter.kt |   2 +-
 .../ultrasonic/domain/APISearchConverter.kt   |   6 +-
 .../ultrasonic/domain/APIShareConverter.kt    |   2 +-
 .../ultrasonic/service/RESTMusicService.kt    |   3 +-
 .../domain/APIAlbumConverterTest.kt           |   2 +-
 .../domain/APIBookmarkConverterTest.kt        |   2 +-
 .../domain/APIMusicDirectoryConverterTest.kt  |   8 +-
 .../domain/APIPlaylistConverterTest.kt        |   4 +-
 .../domain/APISearchConverterTest.kt          |   6 +-
 13 files changed, 118 insertions(+), 70 deletions(-)

diff --git a/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt b/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt
index e316dc42..cf28ccdd 100644
--- a/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt
+++ b/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt
@@ -39,15 +39,15 @@ class MusicDirectory : ArrayList<MusicDirectory.Child>() {
         abstract var album: String?
         abstract var title: String?
         abstract override val name: String?
-        abstract val discNumber: Int?
+        abstract var discNumber: Int?
         abstract var coverArt: String?
-        abstract val songCount: Long?
-        abstract val created: Date?
+        abstract var songCount: Long?
+        abstract var created: Date?
         abstract var artist: String?
-        abstract val artistId: String?
-        abstract val duration: Int?
-        abstract val year: Int?
-        abstract val genre: String?
+        abstract var artistId: String?
+        abstract var duration: Int?
+        abstract var year: Int?
+        abstract var genre: String?
         abstract var starred: Boolean
         abstract var path: String?
         abstract var closeness: Int
@@ -120,15 +120,15 @@ class MusicDirectory : ArrayList<MusicDirectory.Child>() {
         override var album: String? = null,
         override var title: String? = null,
         override val name: String? = null,
-        override val discNumber: Int = 0,
+        override var discNumber: Int? = 0,
         override var coverArt: String? = null,
-        override val songCount: Long? = null,
-        override val created: Date? = null,
+        override var songCount: Long? = null,
+        override var created: Date? = null,
         override var artist: String? = null,
-        override val artistId: String? = null,
-        override val duration: Int = 0,
-        override val year: Int = 0,
-        override val genre: String? = null,
+        override var artistId: String? = null,
+        override var duration: Int? = 0,
+        override var year: Int? = 0,
+        override var genre: String? = null,
         override var starred: Boolean = false,
         override var path: String? = null,
         override var closeness: Int = 0,
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt
index eb42d409..5fd70782 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt
@@ -21,7 +21,7 @@ fun Album.toDomainEntity(): MusicDirectory.Album = MusicDirectory.Album(
 )
 
 fun Album.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory().apply {
-    addAll(this@toMusicDirectoryDomainEntity.songList.map { it.toDomainEntity() })
+    addAll(this@toMusicDirectoryDomainEntity.songList.map { it.toTrackEntity() })
 }
 
 fun List<Album>.toDomainEntityList(): List<MusicDirectory.Album> = this.map { it.toDomainEntity() }
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt
index e7ac4e97..19f61f32 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt
@@ -10,7 +10,7 @@ fun ApiBookmark.toDomainEntity(): Bookmark = Bookmark(
     comment = this@toDomainEntity.comment,
     created = this@toDomainEntity.created?.time,
     changed = this@toDomainEntity.changed?.time,
-    entry = this@toDomainEntity.entry.toDomainEntity()
+    entry = this@toDomainEntity.entry.toTrackEntity()
 )
 
 fun List<ApiBookmark>.toDomainEntitiesList(): List<Bookmark> = map { it.toDomainEntity() }
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt
index adff7ee5..4999751d 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt
@@ -1,5 +1,10 @@
-// Converts MusicDirectory entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient]
-// to app domain entities.
+/*
+ * APIMusicDirectoryConverter.kt
+ * Copyright (C) 2009-2021 Ultrasonic developers
+ *
+ * Distributed under terms of the GNU GPLv3 license.
+ */
+
 @file:JvmName("APIMusicDirectoryConverter")
 package org.moire.ultrasonic.domain
 
@@ -9,48 +14,90 @@ import java.util.Locale
 import org.moire.ultrasonic.api.subsonic.models.MusicDirectory as APIMusicDirectory
 import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild
 
+/*
+ * Converts MusicDirectory entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient]
+ * to app domain entities.
+ *
+ * Unlike other API endpoints getMusicDirectory doesn't return instances of Albums or Songs,
+ * but just children, which can be albums or songs.
+ */
+
 internal val dateFormat: DateFormat by lazy {
     SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault())
 }
 
-fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry = MusicDirectory.Entry(id).apply {
-    parent = this@toDomainEntity.parent
-    isDirectory = this@toDomainEntity.isDir
-    title = this@toDomainEntity.title
-    album = this@toDomainEntity.album
-    albumId = this@toDomainEntity.albumId
-    artist = this@toDomainEntity.artist
-    artistId = this@toDomainEntity.artistId
-    track = this@toDomainEntity.track
-    year = this@toDomainEntity.year
-    genre = this@toDomainEntity.genre
-    contentType = this@toDomainEntity.contentType
-    suffix = this@toDomainEntity.suffix
-    transcodedContentType = this@toDomainEntity.transcodedContentType
-    transcodedSuffix = this@toDomainEntity.transcodedSuffix
-    coverArt = this@toDomainEntity.coverArt
-    size = this@toDomainEntity.size
-    duration = this@toDomainEntity.duration
-    bitRate = this@toDomainEntity.bitRate
-    path = this@toDomainEntity.path
-    isVideo = this@toDomainEntity.isVideo
-    created = this@toDomainEntity.created?.time
-    starred = this@toDomainEntity.starred != null
-    discNumber = this@toDomainEntity.discNumber
-    type = this@toDomainEntity.type
-    if (this@toDomainEntity.streamId.isNotBlank()) {
-        id = this@toDomainEntity.streamId
-    }
-    if (this@toDomainEntity.publishDate != null) {
-        artist = dateFormat.format(this@toDomainEntity.publishDate!!.time)
-    }
-    userRating = this@toDomainEntity.userRating
-    averageRating = this@toDomainEntity.averageRating
+fun MusicDirectoryChild.toTrackEntity(): MusicDirectory.Entry = MusicDirectory.Entry(id).apply {
+    populateCommonProps(this, this@toTrackEntity)
+    populateTrackProps(this, this@toTrackEntity)
 }
 
-fun List<MusicDirectoryChild>.toDomainEntityList() = this.map { it.toDomainEntity() }
+fun MusicDirectoryChild.toAlbumEntity(): MusicDirectory.Album = MusicDirectory.Album(id).apply {
+    populateCommonProps(this, this@toAlbumEntity)
+}
+
+private fun populateCommonProps(
+    entry: MusicDirectory.Child,
+    source: MusicDirectoryChild
+) {
+    entry.parent = source.parent
+    entry.isDirectory = source.isDir
+    entry.title = source.title
+    entry.album = source.album
+    entry.artist = source.artist
+    entry.artistId = source.artistId
+    entry.year = source.year
+    entry.genre = source.genre
+    entry.coverArt = source.coverArt
+    entry.duration = source.duration
+    entry.path = source.path
+    entry.isVideo = source.isVideo
+    entry.created = source.created?.time
+    entry.starred = source.starred != null
+    entry.discNumber = source.discNumber
+
+    if (source.streamId.isNotBlank()) {
+        entry.id = source.streamId
+    }
+    if (source.publishDate != null) {
+        entry.artist = dateFormat.format(source.publishDate!!.time)
+    }
+}
+
+private fun populateTrackProps(
+    entry: MusicDirectory.Entry,
+    source: MusicDirectoryChild
+) {
+    entry.size = source.size
+    entry.contentType = source.contentType
+    entry.suffix = source.suffix
+    entry.transcodedContentType = source.transcodedContentType
+    entry.transcodedSuffix = source.transcodedSuffix
+    entry.track = source.track
+    entry.albumId = source.albumId
+    entry.bitRate = source.bitRate
+    entry.type = source.type
+    entry.userRating = source.userRating
+    entry.averageRating = source.averageRating
+}
+
+fun List<MusicDirectoryChild>.toDomainEntityList(): List<MusicDirectory.Child> {
+    val newList: MutableList<MusicDirectory.Child> = mutableListOf()
+
+    forEach {
+        if (it.isDir)
+            newList.add(it.toAlbumEntity())
+        else
+            newList.add(it.toTrackEntity())
+    }
+
+    return newList
+}
+
+fun List<MusicDirectoryChild>.toTrackList(): List<MusicDirectory.Entry> = this.map {
+    it.toTrackEntity()
+}
 
 fun APIMusicDirectory.toDomainEntity(): MusicDirectory = MusicDirectory().apply {
     name = this@toDomainEntity.name
-    addAll(this@toDomainEntity.childList.map { it.toDomainEntity() })
+    addAll(this@toDomainEntity.childList.toDomainEntityList())
 }
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt
index 57f7e29d..7286163a 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt
@@ -12,7 +12,7 @@ internal val playlistDateFormat by lazy(NONE) { SimpleDateFormat.getInstance() }
 
 fun APIPlaylist.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory().apply {
     name = this@toMusicDirectoryDomainEntity.name
-    addAll(this@toMusicDirectoryDomainEntity.entriesList.map { it.toDomainEntity() })
+    addAll(this@toMusicDirectoryDomainEntity.entriesList.map { it.toTrackEntity() })
 }
 
 fun APIPlaylist.toDomainEntity(): Playlist = Playlist(
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt
index b1dfdf6a..a8833bbe 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt
@@ -9,17 +9,17 @@ import org.moire.ultrasonic.api.subsonic.models.SearchTwoResult
 
 fun APISearchResult.toDomainEntity(): SearchResult = SearchResult(
     emptyList(), emptyList(),
-    this.matchList.map { it.toDomainEntity() }
+    this.matchList.map { it.toTrackEntity() }
 )
 
 fun SearchTwoResult.toDomainEntity(): SearchResult = SearchResult(
     this.artistList.map { it.toDomainEntity() },
     this.albumList.map { it.toDomainEntity() },
-    this.songList.map { it.toDomainEntity() }
+    this.songList.map { it.toTrackEntity() }
 )
 
 fun SearchThreeResult.toDomainEntity(): SearchResult = SearchResult(
     this.artistList.map { it.toDomainEntity() },
     this.albumList.map { it.toDomainEntity() },
-    this.songList.map { it.toDomainEntity() }
+    this.songList.map { it.toTrackEntity() }
 )
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt
index 408f42f7..39162de2 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt
@@ -22,5 +22,5 @@ fun APIShare.toDomainEntity(): Share = Share(
     url = this@toDomainEntity.url,
     username = this@toDomainEntity.username,
     visitCount = this@toDomainEntity.visitCount.toLong(),
-    entries = this@toDomainEntity.items.toDomainEntityList().toMutableList()
+    entries = this@toDomainEntity.items.toTrackList().toMutableList()
 )
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt
index 74c7c3ea..0289af48 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt
@@ -41,6 +41,7 @@ import org.moire.ultrasonic.domain.toDomainEntity
 import org.moire.ultrasonic.domain.toDomainEntityList
 import org.moire.ultrasonic.domain.toIndexList
 import org.moire.ultrasonic.domain.toMusicDirectoryDomainEntity
+import org.moire.ultrasonic.domain.toTrackEntity
 import org.moire.ultrasonic.util.FileUtil
 import org.moire.ultrasonic.util.Settings
 import timber.log.Timber
@@ -317,7 +318,7 @@ open class RESTMusicService(
                 "skipped" != podcastEntry.status &&
                 "error" != podcastEntry.status
             ) {
-                val entry = podcastEntry.toDomainEntity()
+                val entry = podcastEntry.toTrackEntity()
                 entry.track = null
                 musicDirectory.add(entry)
             }
diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt
index 4d8eab69..b4b39932 100644
--- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt
+++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt
@@ -51,7 +51,7 @@ class APIAlbumConverterTest {
         with(convertedEntity) {
             name `should be equal to` null
             size `should be equal to` entity.songList.size
-            this[0] `should be equal to` entity.songList[0].toDomainEntity()
+            this[0] `should be equal to` entity.songList[0].toTrackEntity()
         }
     }
 
diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt
index b9b24fe0..f20da140 100644
--- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt
+++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt
@@ -27,7 +27,7 @@ class APIBookmarkConverterTest {
             comment `should be equal to` entity.comment
             created `should be equal to` entity.created?.time
             changed `should be equal to` entity.changed?.time
-            entry `should be equal to` entity.entry.toDomainEntity()
+            entry `should be equal to` entity.entry.toTrackEntity()
         }
     }
 
diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt
index e1b626cb..3bb559ca 100644
--- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt
+++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt
@@ -26,7 +26,7 @@ class APIMusicDirectoryConverterTest {
             name `should be equal to` entity.name
             size `should be equal to` entity.childList.size
             getChildren() `should be equal to` entity.childList
-                .map { it.toDomainEntity() }.toMutableList()
+                .map { it.toTrackEntity() }.toMutableList()
         }
     }
 
@@ -44,7 +44,7 @@ class APIMusicDirectoryConverterTest {
             starred = Calendar.getInstance(), userRating = 3, averageRating = 2.99F
         )
 
-        val convertedEntity = entity.toDomainEntity()
+        val convertedEntity = entity.toTrackEntity()
 
         with(convertedEntity) {
             id `should be equal to` entity.id
@@ -84,7 +84,7 @@ class APIMusicDirectoryConverterTest {
             artist = "some-artist", publishDate = Calendar.getInstance()
         )
 
-        val convertedEntity = entity.toDomainEntity()
+        val convertedEntity = entity.toTrackEntity()
 
         with(convertedEntity) {
             id `should be equal to` entity.streamId
@@ -100,7 +100,7 @@ class APIMusicDirectoryConverterTest {
 
         domainList.size `should be equal to` entitiesList.size
         domainList.forEachIndexed { index, entry ->
-            entry `should be equal to` entitiesList[index].toDomainEntity()
+            entry `should be equal to` entitiesList[index].toTrackEntity()
         }
     }
 }
diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt
index 7c06d540..9756af80 100644
--- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt
+++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt
@@ -27,8 +27,8 @@ class APIPlaylistConverterTest {
         with(convertedEntity) {
             name `should be equal to` entity.name
             size `should be equal to` entity.entriesList.size
-            this[0] `should be equal to` entity.entriesList[0].toDomainEntity()
-            this[1] `should be equal to` entity.entriesList[1].toDomainEntity()
+            this[0] `should be equal to` entity.entriesList[0].toTrackEntity()
+            this[1] `should be equal to` entity.entriesList[1].toTrackEntity()
         }
     }
 
diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt
index ff3b30f8..d54a3a76 100644
--- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt
+++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt
@@ -34,7 +34,7 @@ class APISearchConverterTest {
             artists `should not be equal to` null
             artists.size `should be equal to` 0
             songs.size `should be equal to` entity.matchList.size
-            songs[0] `should be equal to` entity.matchList[0].toDomainEntity()
+            songs[0] `should be equal to` entity.matchList[0].toTrackEntity()
         }
     }
 
@@ -54,7 +54,7 @@ class APISearchConverterTest {
             albums.size `should be equal to` entity.albumList.size
             albums[0] `should be equal to` entity.albumList[0].toDomainEntity()
             songs.size `should be equal to` entity.songList.size
-            songs[0] `should be equal to` entity.songList[0].toDomainEntity()
+            songs[0] `should be equal to` entity.songList[0].toTrackEntity()
         }
     }
 
@@ -74,7 +74,7 @@ class APISearchConverterTest {
             albums.size `should be equal to` entity.albumList.size
             albums[0] `should be equal to` entity.albumList[0].toDomainEntity()
             songs.size `should be equal to` entity.songList.size
-            songs[0] `should be equal to` entity.songList[0].toDomainEntity()
+            songs[0] `should be equal to` entity.songList[0].toTrackEntity()
         }
     }
 }