Skip to content

Commit

Permalink
Fix base URL to allow non-catalog APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
stevesoltys committed Nov 22, 2024
1 parent 8659eb6 commit 2071466
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 116 deletions.
68 changes: 50 additions & 18 deletions src/main/kotlin/com/stevesoltys/applemusic/AppleMusic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down Expand Up @@ -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()
)
)
}
Expand All @@ -86,6 +80,7 @@ class AppleMusic(
): ChartResponse {
return call(
appleMusicService.getCatalogCharts(
storefront = configuration.storefront,
types = types.map { it.identifier }.toTypedArray(),
localization = localization,
chart = chart,
Expand All @@ -104,7 +99,13 @@ class AppleMusic(
id: String,
include: Set<String>? = null
): ArtistResponse {
return call(appleMusicService.getArtistById(id, include?.toTypedArray()))
return call(
appleMusicService.getArtistById(
storefront = configuration.storefront,
id = id,
types = include?.toTypedArray()
)
)
}

/**
Expand All @@ -114,7 +115,13 @@ class AppleMusic(
id: String,
include: Set<String>? = null
): AlbumResponse {
return call(appleMusicService.getAlbumById(id, include?.toTypedArray()))
return call(
appleMusicService.getAlbumById(
storefront = configuration.storefront,
id = id,
types = include?.toTypedArray()
)
)
}

/**
Expand All @@ -123,7 +130,12 @@ class AppleMusic(
fun getAlbumsById(
ids: Array<String>
): AlbumResponse {
return call(appleMusicService.getAlbumsById(ids))
return call(
appleMusicService.getAlbumsById(
storefront = configuration.storefront,
ids = ids
)
)
}

/**
Expand All @@ -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
)
)
}

/**
Expand All @@ -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)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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/"
)
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>? = null
): Call<SearchResponse>

@GET("charts")
@GET("catalog/{storefront}/charts")
fun getCatalogCharts(
@Path("storefront") storefront: String,
@Query("types") types: Array<String>,
@Query("l") localization: String? = null,
@Query("chart") chart: String? = null,
Expand All @@ -35,30 +37,35 @@ interface AppleMusicService {
@Query("with") with: Array<String>? = null
): Call<ChartResponse>

@GET("artists/{id}")
@GET("catalog/{storefront}/artists/{id}")
fun getArtistById(
@Path("storefront") storefront: String,
@Path("id") id: String,
@Query("include") types: Array<String>? = null
): Call<ArtistResponse>

@GET("artists")
@GET("catalog/{storefront}/artists")
fun getArtistsById(
@Path("storefront") storefront: String,
@Query("ids") ids: Array<String>
): Call<ArtistResponse>

@GET("albums/{id}")
@GET("catalog/{storefront}/albums/{id}")
fun getAlbumById(
@Path("storefront") storefront: String,
@Path("id") id: String,
@Query("include") types: Array<String>? = null
): Call<AlbumResponse>

@GET("albums")
@GET("catalog/{storefront}/albums")
fun getAlbumsById(
@Path("storefront") storefront: String,
@Query("ids") ids: Array<String>
): Call<AlbumResponse>

@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
Expand Down
182 changes: 92 additions & 90 deletions src/test/kotlin/com/stevesoltys/applemusic/AppleMusicE2ETest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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`() {
Expand Down

0 comments on commit 2071466

Please sign in to comment.