From 2071466ffa58932bcfeaeca0f6e52d11a5649896 Mon Sep 17 00:00:00 2001 From: Steve Soltys Date: Fri, 22 Nov 2024 06:45:05 +0000 Subject: [PATCH] Fix base URL to allow non-catalog APIs --- .../com/stevesoltys/applemusic/AppleMusic.kt | 68 +++++-- .../applemusic/AppleMusicConfiguration.kt | 2 +- .../applemusic/net/AppleMusicService.kt | 21 +- .../applemusic/AppleMusicE2ETest.kt | 182 +++++++++--------- 4 files changed, 157 insertions(+), 116 deletions(-) diff --git a/src/main/kotlin/com/stevesoltys/applemusic/AppleMusic.kt b/src/main/kotlin/com/stevesoltys/applemusic/AppleMusic.kt index 372de0a..fdac991 100644 --- a/src/main/kotlin/com/stevesoltys/applemusic/AppleMusic.kt +++ b/src/main/kotlin/com/stevesoltys/applemusic/AppleMusic.kt @@ -20,17 +20,10 @@ import retrofit2.Call * @author Steve Soltys */ class AppleMusic( - private val teamId: String, - private val privateKey: ByteArray, - private val keyId: String, - private val storefront: String, + private val configuration: AppleMusicConfiguration, private val retrofitBuilder: AppleMusicRetrofitBuilder? = null ) { - private val configuration: AppleMusicConfiguration by lazy { - AppleMusicConfiguration(teamId, privateKey, keyId, storefront) - } - private val retrofit: AppleMusicRetrofitBuilder by lazy { retrofitBuilder ?: DefaultAppleMusicRetrofitBuilder() } @@ -64,10 +57,11 @@ class AppleMusic( ): SearchResponse { return call( appleMusicService.search( - term, - offset, - limit, - types?.map { it.identifier }?.toTypedArray() + storefront = configuration.storefront, + term = term, + offset = offset, + limit = limit, + types = types?.map { it.identifier }?.toTypedArray() ) ) } @@ -86,6 +80,7 @@ class AppleMusic( ): ChartResponse { return call( appleMusicService.getCatalogCharts( + storefront = configuration.storefront, types = types.map { it.identifier }.toTypedArray(), localization = localization, chart = chart, @@ -104,7 +99,13 @@ class AppleMusic( id: String, include: Set? = null ): ArtistResponse { - return call(appleMusicService.getArtistById(id, include?.toTypedArray())) + return call( + appleMusicService.getArtistById( + storefront = configuration.storefront, + id = id, + types = include?.toTypedArray() + ) + ) } /** @@ -114,7 +115,13 @@ class AppleMusic( id: String, include: Set? = null ): AlbumResponse { - return call(appleMusicService.getAlbumById(id, include?.toTypedArray())) + return call( + appleMusicService.getAlbumById( + storefront = configuration.storefront, + id = id, + types = include?.toTypedArray() + ) + ) } /** @@ -123,7 +130,12 @@ class AppleMusic( fun getAlbumsById( ids: Array ): AlbumResponse { - return call(appleMusicService.getAlbumsById(ids)) + return call( + appleMusicService.getAlbumsById( + storefront = configuration.storefront, + ids = ids + ) + ) } /** @@ -134,7 +146,14 @@ class AppleMusic( offset: String? = null, limit: Int? = null ): AlbumResponse { - return call(appleMusicService.getAlbumsByArtistId(id, offset, limit)) + return call( + appleMusicService.getAlbumsByArtistId( + storefront = configuration.storefront, + id = id, + offset = offset, + limit = limit + ) + ) } /** @@ -144,13 +163,26 @@ class AppleMusic( val limit = 100 var offset = 0 - var currentResponse = call(appleMusicService.getAlbumsByArtistId(id, 0.toString(), limit)) + var currentResponse = call( + appleMusicService.getAlbumsByArtistId( + storefront = configuration.storefront, + id = id, + offset = 0.toString(), + limit = limit + ) + ) + val result = currentResponse.data.toCollection(ArrayList()) while (currentResponse.next != null) { offset += currentResponse.data.size - currentResponse = call(appleMusicService.getAlbumsByArtistId(id, offset.toString(), limit)) + currentResponse = getAlbumsByArtistId( + id = id, + offset = offset.toString(), + limit = limit + ) + result.addAll(currentResponse.data) } diff --git a/src/main/kotlin/com/stevesoltys/applemusic/AppleMusicConfiguration.kt b/src/main/kotlin/com/stevesoltys/applemusic/AppleMusicConfiguration.kt index b0af341..9f37ea9 100644 --- a/src/main/kotlin/com/stevesoltys/applemusic/AppleMusicConfiguration.kt +++ b/src/main/kotlin/com/stevesoltys/applemusic/AppleMusicConfiguration.kt @@ -8,5 +8,5 @@ class AppleMusicConfiguration( val privateKey: ByteArray, val keyId: String, val storefront: String, - val baseUrl: String = "https://api.music.apple.com/v1/catalog/${storefront}/" + val baseUrl: String = "https://api.music.apple.com/v1/" ) diff --git a/src/main/kotlin/com/stevesoltys/applemusic/net/AppleMusicService.kt b/src/main/kotlin/com/stevesoltys/applemusic/net/AppleMusicService.kt index c5384b3..b5ed09f 100644 --- a/src/main/kotlin/com/stevesoltys/applemusic/net/AppleMusicService.kt +++ b/src/main/kotlin/com/stevesoltys/applemusic/net/AppleMusicService.kt @@ -16,16 +16,18 @@ import retrofit2.http.Query */ interface AppleMusicService { - @GET("search") + @GET("catalog/{storefront}/search") fun search( + @Path("storefront") storefront: String, @Query("term") term: String, @Query("offset") offset: String? = null, @Query("limit") limit: Int? = null, @Query("include") types: Array? = null ): Call - @GET("charts") + @GET("catalog/{storefront}/charts") fun getCatalogCharts( + @Path("storefront") storefront: String, @Query("types") types: Array, @Query("l") localization: String? = null, @Query("chart") chart: String? = null, @@ -35,30 +37,35 @@ interface AppleMusicService { @Query("with") with: Array? = null ): Call - @GET("artists/{id}") + @GET("catalog/{storefront}/artists/{id}") fun getArtistById( + @Path("storefront") storefront: String, @Path("id") id: String, @Query("include") types: Array? = null ): Call - @GET("artists") + @GET("catalog/{storefront}/artists") fun getArtistsById( + @Path("storefront") storefront: String, @Query("ids") ids: Array ): Call - @GET("albums/{id}") + @GET("catalog/{storefront}/albums/{id}") fun getAlbumById( + @Path("storefront") storefront: String, @Path("id") id: String, @Query("include") types: Array? = null ): Call - @GET("albums") + @GET("catalog/{storefront}/albums") fun getAlbumsById( + @Path("storefront") storefront: String, @Query("ids") ids: Array ): Call - @GET("artists/{id}/albums") + @GET("catalog/{storefront}/artists/{id}/albums") fun getAlbumsByArtistId( + @Path("storefront") storefront: String, @Path("id") id: String, @Query("offset") offset: String? = null, @Query("limit") limit: Int? = null diff --git a/src/test/kotlin/com/stevesoltys/applemusic/AppleMusicE2ETest.kt b/src/test/kotlin/com/stevesoltys/applemusic/AppleMusicE2ETest.kt index cd4d81d..b695af2 100644 --- a/src/test/kotlin/com/stevesoltys/applemusic/AppleMusicE2ETest.kt +++ b/src/test/kotlin/com/stevesoltys/applemusic/AppleMusicE2ETest.kt @@ -18,96 +18,98 @@ import java.util.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) class AppleMusicE2ETest { - companion object { - private val TEAM_ID = System.getenv("TEAM_ID") - private val PRIVATE_KEY_BASE64 = System.getenv("PRIVATE_KEY_BASE64") - private val KEY_ID = System.getenv("KEY_ID") - private const val STOREFRONT = "us" - - private const val TEST_ARTIST_IDENTIFIER = "485953" - private const val TEST_ARTIST_NAME = "Billy Joel" - - private const val TEST_ALBUM_IDENTIFIER = "259814641" - private const val TEST_ALBUM_NAME = "An Innocent Man" - - private const val TEST_ALBUM_IDENTIFIER_2 = "1440903530" - } - - private lateinit var appleMusic: AppleMusic - - @BeforeAll - fun `set up`() { - appleMusic = AppleMusic( - teamId = TEAM_ID, - privateKey = Base64.getDecoder().decode(PRIVATE_KEY_BASE64), - keyId = KEY_ID, - storefront = STOREFRONT - ) - } - - @Test - fun `can search for artists`() { - val result = appleMusic.search( - TEST_ARTIST_NAME, - types = setOf(SearchResultType.ARTISTS) - ) - - val artists = result.results?.artists?.data - artists shouldNotBe null - artists!!.size shouldBeGreaterThan 0 - } - - @Test - fun `can get artist by identifier`() { - val result = appleMusic.getArtistById(TEST_ARTIST_IDENTIFIER) - - val billyJoelAttributes = result.data.firstOrNull()?.attributes - billyJoelAttributes.shouldNotBeNull() - billyJoelAttributes.name shouldBe TEST_ARTIST_NAME - } - - @Test - fun `can get a single album by identifier`() { - val result = appleMusic.getAllAlbumsByArtistId(TEST_ARTIST_IDENTIFIER) - - val albums = result.data - albums.shouldNotBeNull().shouldNotBeEmpty() - } - - @Test - fun `can get multiple albums by their identifiers`() { - val result = appleMusic.getAlbumsById( - arrayOf(TEST_ALBUM_IDENTIFIER, TEST_ALBUM_IDENTIFIER_2) - ) - - val albums = result.data - albums.shouldNotBeNull().shouldNotBeEmpty() - - albums.first().attributes?.artistName.shouldNotBeNull() - albums.first().relationships?.artists?.data.shouldNotBeNull().shouldHaveSize(1) - } - - @Test - fun `can get album by identifier`() { - val result = appleMusic.getAlbumById(TEST_ALBUM_IDENTIFIER) - - val artistAttributes = result.data.firstOrNull()?.attributes - artistAttributes.shouldNotBeNull() - artistAttributes.name shouldBe TEST_ALBUM_NAME - } - - @Test - fun `can get top 100 album charts`() { - val result = appleMusic.getCatalogCharts( - types = setOf(ChartResultType.ALBUMS), - with = setOf(ChartType.DAILY_GLOBAL_TOP_CHARTS), - limit = 100 - ) - - result.results.albums.shouldNotBeEmpty() - result.results.albums.first().data.shouldHaveSize(100) - result.results.songs.shouldBeEmpty() - } + companion object { + private val TEAM_ID = System.getenv("TEAM_ID") + private val PRIVATE_KEY_BASE64 = System.getenv("PRIVATE_KEY_BASE64") + private val KEY_ID = System.getenv("KEY_ID") + private const val STOREFRONT = "us" + + private const val TEST_ARTIST_IDENTIFIER = "485953" + private const val TEST_ARTIST_NAME = "Billy Joel" + + private const val TEST_ALBUM_IDENTIFIER = "259814641" + private const val TEST_ALBUM_NAME = "An Innocent Man" + + private const val TEST_ALBUM_IDENTIFIER_2 = "1440903530" + } + + private lateinit var appleMusic: AppleMusic + + @BeforeAll + fun `set up`() { + appleMusic = AppleMusic( + configuration = AppleMusicConfiguration( + teamId = TEAM_ID, + privateKey = Base64.getDecoder().decode(PRIVATE_KEY_BASE64), + keyId = KEY_ID, + storefront = STOREFRONT + ) + ) + } + + @Test + fun `can search for artists`() { + val result = appleMusic.search( + TEST_ARTIST_NAME, + types = setOf(SearchResultType.ARTISTS) + ) + + val artists = result.results?.artists?.data + artists shouldNotBe null + artists!!.size shouldBeGreaterThan 0 + } + + @Test + fun `can get artist by identifier`() { + val result = appleMusic.getArtistById(TEST_ARTIST_IDENTIFIER) + + val billyJoelAttributes = result.data.firstOrNull()?.attributes + billyJoelAttributes.shouldNotBeNull() + billyJoelAttributes.name shouldBe TEST_ARTIST_NAME + } + + @Test + fun `can get all albums by artist identifier`() { + val result = appleMusic.getAllAlbumsByArtistId(TEST_ARTIST_IDENTIFIER) + + val albums = result.data + albums.shouldNotBeNull().shouldNotBeEmpty() + } + + @Test + fun `can get multiple albums by their identifiers`() { + val result = appleMusic.getAlbumsById( + arrayOf(TEST_ALBUM_IDENTIFIER, TEST_ALBUM_IDENTIFIER_2) + ) + + val albums = result.data + albums.shouldNotBeNull().shouldNotBeEmpty() + + albums.first().attributes?.artistName.shouldNotBeNull() + albums.first().relationships?.artists?.data.shouldNotBeNull().shouldHaveSize(1) + } + + @Test + fun `can get album by identifier`() { + val result = appleMusic.getAlbumById(TEST_ALBUM_IDENTIFIER) + + val artistAttributes = result.data.firstOrNull()?.attributes + artistAttributes.shouldNotBeNull() + artistAttributes.name shouldBe TEST_ALBUM_NAME + } + + @Test + fun `can get top 100 album charts`() { + val result = appleMusic.getCatalogCharts( + types = setOf(ChartResultType.ALBUMS), + with = setOf(ChartType.DAILY_GLOBAL_TOP_CHARTS), + limit = 100 + ) + + result.results.albums.shouldNotBeEmpty() + result.results.albums.first().data.shouldHaveSize(100) + result.results.songs.shouldBeEmpty() + } @Test fun `can get top 100 song charts`() {