diff --git a/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiGetRandomSongsTest.kt b/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiGetRandomSongsTest.kt new file mode 100644 index 00000000..9f45b8a7 --- /dev/null +++ b/subsonic-api/src/integrationTest/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicApiGetRandomSongsTest.kt @@ -0,0 +1,90 @@ +package org.moire.ultrasonic.api.subsonic + +import org.amshove.kluent.`should equal to` +import org.amshove.kluent.`should equal` +import org.junit.Test +import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild + +/** + * Integration test for [SubsonicAPIClient] for getRandomSongs call. + */ +class SubsonicApiGetRandomSongsTest : SubsonicAPIClientTest() { + @Test + fun `Should handle error response`() { + val response = checkErrorCallParsed(mockWebServerRule) { + client.api.getRandomSongs().execute() + } + + response.songsList `should equal` emptyList() + } + + @Test + fun `Should handle ok response`() { + mockWebServerRule.enqueueResponse("get_random_songs_ok.json") + + val response = client.api.getRandomSongs().execute() + + assertResponseSuccessful(response) + with(response.body().songsList) { + size `should equal to` 3 + this[1] `should equal` MusicDirectoryChild(id = 3061, parent = 3050, isDir = false, + title = "Sure as Hell", album = "Who Are You Now?", artist = "This Providence", + track = 1, year = 2009, genre = "Indie Rock", coverArt = "3050", + size = 1969692, contentType = "audio/mpeg", suffix = "mp3", duration = 110, + bitRate = 142, path = "This Providence/Who Are You Now_/01 Sure as Hell.mp3", + isVideo = false, playCount = 0, discNumber = 1, + created = parseDate("2016-10-23T21:32:46.000Z"), albumId = 272, + artistId = 152, type = "music") + } + } + + @Test + fun `Should pass size in request param`() { + val size = 384433 + + mockWebServerRule.assertRequestParam(responseResourceName = "get_random_songs_ok.json", + expectedParam = "size=$size") { + client.api.getRandomSongs(size = size).execute() + } + } + + @Test + fun `Should pass genre in request param`() { + val genre = "PostRock" + + mockWebServerRule.assertRequestParam(responseResourceName = "get_random_songs_ok.json", + expectedParam = "genre=$genre") { + client.api.getRandomSongs(genre = genre).execute() + } + } + + @Test + fun `Should pass from year in request param`() { + val fromYear = 1919 + + mockWebServerRule.assertRequestParam(responseResourceName = "get_random_songs_ok.json", + expectedParam = "fromYear=$fromYear") { + client.api.getRandomSongs(fromYear = fromYear).execute() + } + } + + @Test + fun `Should pass to year in request params`() { + val toYear = 2012 + + mockWebServerRule.assertRequestParam(responseResourceName = "get_random_songs_ok.json", + expectedParam = "toYear=$toYear") { + client.api.getRandomSongs(toYear = toYear).execute() + } + } + + @Test + fun `Should pass music folder id in request param`() { + val musicFolderId = 4919L + + mockWebServerRule.assertRequestParam(responseResourceName = "get_random_songs_ok.json", + expectedParam = "musicFolderId=$musicFolderId") { + client.api.getRandomSongs(musicFolderId = musicFolderId).execute() + } + } +} diff --git a/subsonic-api/src/integrationTest/resources/get_random_songs_ok.json b/subsonic-api/src/integrationTest/resources/get_random_songs_ok.json new file mode 100644 index 00000000..be02b3a3 --- /dev/null +++ b/subsonic-api/src/integrationTest/resources/get_random_songs_ok.json @@ -0,0 +1,81 @@ +{ + "subsonic-response" : { + "status" : "ok", + "version" : "1.15.0", + "randomSongs" : { + "song" : [ { + "id" : "4426", + "parent" : "4417", + "isDir" : false, + "title" : "Permanent", + "album" : "Phantoms", + "artist" : "Acceptance", + "track" : 11, + "year" : 2005, + "genre" : "Rock", + "coverArt" : "4417", + "size" : 4444381, + "contentType" : "audio/mpeg", + "suffix" : "mp3", + "duration" : 185, + "bitRate" : 192, + "path" : "Acceptance/Phantoms/11 Permanent.mp3", + "isVideo" : false, + "playCount" : 0, + "discNumber" : 1, + "created" : "2016-10-23T15:31:49.000Z", + "albumId" : "409", + "artistId" : "254", + "type" : "music" + }, { + "id" : "3061", + "parent" : "3050", + "isDir" : false, + "title" : "Sure as Hell", + "album" : "Who Are You Now?", + "artist" : "This Providence", + "track" : 1, + "year" : 2009, + "genre" : "Indie Rock", + "coverArt" : "3050", + "size" : 1969692, + "contentType" : "audio/mpeg", + "suffix" : "mp3", + "duration" : 110, + "bitRate" : 142, + "path" : "This Providence/Who Are You Now_/01 Sure as Hell.mp3", + "isVideo" : false, + "playCount" : 0, + "discNumber" : 1, + "created" : "2016-10-23T21:32:46.000Z", + "albumId" : "272", + "artistId" : "152", + "type" : "music" + }, { + "id" : "2455", + "parent" : "2451", + "isDir" : false, + "title" : "I Dare You", + "album" : "Us and Them", + "artist" : "Shinedown", + "track" : 4, + "year" : 2005, + "genre" : "Rock", + "coverArt" : "2451", + "size" : 6489382, + "contentType" : "audio/mpeg", + "suffix" : "mp3", + "duration" : 234, + "bitRate" : 221, + "path" : "Shinedown/Us and Them/04 I Dare You.mp3", + "isVideo" : false, + "playCount" : 0, + "discNumber" : 1, + "created" : "2016-10-23T21:16:21.000Z", + "albumId" : "209", + "artistId" : "112", + "type" : "music" + } ] + } + } +} \ No newline at end of file diff --git a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicAPIDefinition.kt b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicAPIDefinition.kt index 2b665ad7..6be4263b 100644 --- a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicAPIDefinition.kt +++ b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/SubsonicAPIDefinition.kt @@ -12,6 +12,7 @@ import org.moire.ultrasonic.api.subsonic.response.GetMusicDirectoryResponse import org.moire.ultrasonic.api.subsonic.response.GetPlaylistResponse import org.moire.ultrasonic.api.subsonic.response.GetPlaylistsResponse import org.moire.ultrasonic.api.subsonic.response.GetPodcastsResponse +import org.moire.ultrasonic.api.subsonic.response.GetRandomSongsResponse import org.moire.ultrasonic.api.subsonic.response.LicenseResponse import org.moire.ultrasonic.api.subsonic.response.MusicFoldersResponse import org.moire.ultrasonic.api.subsonic.response.SearchResponse @@ -144,4 +145,11 @@ interface SubsonicAPIDefinition { @Query("toYear") toYear: Int? = null, @Query("genre") genre: String? = null, @Query("musicFolderId") musicFolderId: Long? = null): Call + + @GET("getRandomSongs.view") + fun getRandomSongs(@Query("size") size: Int? = null, + @Query("genre") genre: String? = null, + @Query("fromYear") fromYear: Int? = null, + @Query("toYear") toYear: Int? = null, + @Query("musicFolderId") musicFolderId: Long? = null): Call } diff --git a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/response/GetRandomSongsResponse.kt b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/response/GetRandomSongsResponse.kt new file mode 100644 index 00000000..603e7744 --- /dev/null +++ b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/response/GetRandomSongsResponse.kt @@ -0,0 +1,19 @@ +package org.moire.ultrasonic.api.subsonic.response + +import com.fasterxml.jackson.annotation.JsonProperty +import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions +import org.moire.ultrasonic.api.subsonic.SubsonicError +import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild + +class GetRandomSongsResponse(status: Status, + version: SubsonicAPIVersions, + error: SubsonicError?) + : SubsonicResponse(status, version, error) { + @JsonProperty("randomSongs") private val songsWrapper = RandomSongsWrapper() + + val songsList + get() = songsWrapper.songsList +} + +private class RandomSongsWrapper( + @JsonProperty("song") val songsList: List = emptyList()) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java index ebe8a4ca..382436e8 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java @@ -69,6 +69,7 @@ import org.moire.ultrasonic.api.subsonic.response.GetMusicDirectoryResponse; import org.moire.ultrasonic.api.subsonic.response.GetPlaylistResponse; import org.moire.ultrasonic.api.subsonic.response.GetPlaylistsResponse; import org.moire.ultrasonic.api.subsonic.response.GetPodcastsResponse; +import org.moire.ultrasonic.api.subsonic.response.GetRandomSongsResponse; import org.moire.ultrasonic.api.subsonic.response.LicenseResponse; import org.moire.ultrasonic.api.subsonic.response.MusicFoldersResponse; import org.moire.ultrasonic.api.subsonic.response.SearchResponse; @@ -699,30 +700,19 @@ public class RESTMusicService implements MusicService return result; } - @Override - public MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception - { - checkServerVersion(context, "1.2", "Random songs not supported."); + @Override + public MusicDirectory getRandomSongs(int size, + Context context, + ProgressListener progressListener) throws Exception { + updateProgressListener(progressListener, R.string.parser_reading); + Response response = subsonicAPIClient.getApi() + .getRandomSongs(size, null, null, null, null).execute(); + checkResponseSuccessful(response); - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List names = new ArrayList(); - List values = new ArrayList(); - - names.add("size"); - values.add(size); - - Reader reader = getReader(context, progressListener, "getRandomSongs", params, names, values); - try - { - return new RandomSongsParser(context).parse(reader, progressListener); - } - finally - { - Util.close(reader); - } - } + MusicDirectory result = new MusicDirectory(); + result.addAll(APIMusicDirectoryConverter.toDomainEntityList(response.body().getSongsList())); + return result; + } @Override public SearchResult getStarred(Context context, ProgressListener progressListener) throws Exception