Skip to content

Commit

Permalink
Adding the albums api. (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenquadros authored Apr 26, 2024
1 parent cc08f30 commit 60a6842
Show file tree
Hide file tree
Showing 37 changed files with 13,362 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.rubenquadros.kovibes.api

import io.github.rubenquadros.kovibes.api.album.AlbumApiImpl
import io.github.rubenquadros.kovibes.api.artist.ArtistApiImpl
import io.github.rubenquadros.kovibes.api.browse.BrowseApiImpl
import io.github.rubenquadros.kovibes.api.config.Config
Expand Down Expand Up @@ -31,7 +32,8 @@ object KoVibesApi {
browseApi = BrowseApiImpl(ktorService),
searchApi = SearchApiImpl(ktorService),
recommendationsApi = RecommendationsApiImpl(ktorService),
artistApi = ArtistApiImpl(ktorService)
artistApi = ArtistApiImpl(ktorService),
albumApi = AlbumApiImpl(ktorService)
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package io.github.rubenquadros.kovibes.api

import io.github.rubenquadros.kovibes.api.request.GetRecommendationsRequest
import io.github.rubenquadros.kovibes.api.response.Album
import io.github.rubenquadros.kovibes.api.response.AlbumTracks
import io.github.rubenquadros.kovibes.api.response.Albums
import io.github.rubenquadros.kovibes.api.response.Artist
import io.github.rubenquadros.kovibes.api.response.ArtistTopTracks
import io.github.rubenquadros.kovibes.api.response.Artists
import io.github.rubenquadros.kovibes.api.response.Categories
import io.github.rubenquadros.kovibes.api.response.ErrorBody
import io.github.rubenquadros.kovibes.api.response.Genres
import io.github.rubenquadros.kovibes.api.response.NewAlbumReleases
import io.github.rubenquadros.kovibes.api.response.PlaylistTracks
import io.github.rubenquadros.kovibes.api.response.Playlists
import io.github.rubenquadros.kovibes.api.response.Recommendations
Expand Down Expand Up @@ -278,4 +281,61 @@ interface SpotifyService {
* @return [RelatedArtists] when success and [ErrorBody] when error.
*/
suspend fun getRelatedArtists(id: String): SpotifyApiResponse<RelatedArtists, ErrorBody>

/**
* Get album API returns the details about an album.
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-album).
*
* @param id
* @param market
* @return [Album] when success and [ErrorBody] when error.
*/
suspend fun getAlbum(id: String, market: String? = null): SpotifyApiResponse<Album, ErrorBody>

/**
* Get album tracks API returns all the tracks in an album.
* This is a paginated API.
*
* `offset` is the page you are requesting for. Initially it will be 0.
*
* You will have to increment it for subsequent pages.
*
* You can know if there are more pages from [Tracks.isNext].
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-albums-tracks).
*
* @param id
* @param market
* @param limit
* @param offset
* @return [AlbumTracks] when success and [ErrorBody] when error.
*/
suspend fun getAlbumTracks(
id: String,
market: String? = null,
limit: Int = 20,
offset: Int = 0
): SpotifyApiResponse<AlbumTracks, ErrorBody>

/**
* Get new album releases API returns all the new album releases.
* This is a paginated API.
*
* `offset` is the page you are requesting for. Initially it will be 0.
*
* You will have to increment it for subsequent pages.
*
* You can know if there are more pages from [NewAlbumReleases.isNext].
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-new-releases).
*
* @param limit
* @param offset
* @return [NewAlbumReleases] when success and [ErrorBody] when error.
*/
suspend fun getNewAlbumReleases(
limit: Int = 20,
offset: Int = 0
): SpotifyApiResponse<NewAlbumReleases, ErrorBody>
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
package io.github.rubenquadros.kovibes.api

import io.github.rubenquadros.kovibes.api.album.AlbumApi
import io.github.rubenquadros.kovibes.api.album.toAlbumTracks
import io.github.rubenquadros.kovibes.api.album.toNewAlbumReleases
import io.github.rubenquadros.kovibes.api.artist.ArtistApi
import io.github.rubenquadros.kovibes.api.artist.toArtistTopTracks
import io.github.rubenquadros.kovibes.api.artist.toRelatedArtists
import io.github.rubenquadros.kovibes.api.browse.BrowseApi
import io.github.rubenquadros.kovibes.api.browse.toCategories
import io.github.rubenquadros.kovibes.api.mapper.toAlbum
import io.github.rubenquadros.kovibes.api.mapper.toAlbums
import io.github.rubenquadros.kovibes.api.mapper.toArtist
import io.github.rubenquadros.kovibes.api.playlist.PlaylistApi
import io.github.rubenquadros.kovibes.api.playlist.models.FeaturedPlaylistsResponse
import io.github.rubenquadros.kovibes.api.playlist.models.PlaylistTracksResponse
import io.github.rubenquadros.kovibes.api.playlist.toFeaturedPlayLists
import io.github.rubenquadros.kovibes.api.playlist.toPlaylistTracks
import io.github.rubenquadros.kovibes.api.recommendations.RecommendationsApi
import io.github.rubenquadros.kovibes.api.recommendations.toRecommendations
import io.github.rubenquadros.kovibes.api.request.GetRecommendationsRequest
import io.github.rubenquadros.kovibes.api.response.Album
import io.github.rubenquadros.kovibes.api.response.AlbumTracks
import io.github.rubenquadros.kovibes.api.response.Albums
import io.github.rubenquadros.kovibes.api.response.Artist
import io.github.rubenquadros.kovibes.api.response.ArtistTopTracks
import io.github.rubenquadros.kovibes.api.response.Artists
import io.github.rubenquadros.kovibes.api.response.Categories
import io.github.rubenquadros.kovibes.api.response.ErrorBody
import io.github.rubenquadros.kovibes.api.response.Genres
import io.github.rubenquadros.kovibes.api.response.NewAlbumReleases
import io.github.rubenquadros.kovibes.api.response.PlaylistTracks
import io.github.rubenquadros.kovibes.api.response.Playlists
import io.github.rubenquadros.kovibes.api.response.Recommendations
Expand All @@ -42,21 +47,22 @@ import io.github.rubenquadros.kovibes.api.search.toSearchTrack
* @property searchApi
* @property recommendationsApi
* @property artistApi
* @property albumApi
*/
internal class SpotifyServiceImpl(
private val playlistApi: PlaylistApi,
private val browseApi: BrowseApi,
private val searchApi: SearchApi,
private val recommendationsApi: RecommendationsApi,
private val artistApi: ArtistApi
private val artistApi: ArtistApi,
private val albumApi: AlbumApi
) : SpotifyService {
override suspend fun getFeaturedPlaylists(
locale: String,
limit: Int,
offset: Int
): SpotifyApiResponse<Playlists, ErrorBody> {
val response: ApiResponse<FeaturedPlaylistsResponse, ErrorBody> =
playlistApi.getFeaturedPlaylists(locale, limit, offset)
val response = playlistApi.getFeaturedPlaylists(locale, limit, offset)

return response.getParsedApiResponse { it.toFeaturedPlayLists() }
}
Expand All @@ -68,8 +74,7 @@ internal class SpotifyServiceImpl(
limit: Int,
offset: Int
): SpotifyApiResponse<PlaylistTracks, ErrorBody> {
val response: ApiResponse<PlaylistTracksResponse, ErrorBody> =
playlistApi.getPlaylistTracks(id, market, fields, limit, offset)
val response = playlistApi.getPlaylistTracks(id, market, fields, limit, offset)

return response.getParsedApiResponse { it.toPlaylistTracks() }
}
Expand Down Expand Up @@ -172,4 +177,33 @@ internal class SpotifyServiceImpl(

return response.getParsedApiResponse { it.toRelatedArtists() }
}

override suspend fun getAlbum(
id: String,
market: String?
): SpotifyApiResponse<Album, ErrorBody> {
val response = albumApi.getAlbum(id, market)

return response.getParsedApiResponse { it.toAlbum() }
}

override suspend fun getAlbumTracks(
id: String,
market: String?,
limit: Int,
offset: Int
): SpotifyApiResponse<AlbumTracks, ErrorBody> {
val response = albumApi.getAlbumTracks(id, market, limit, offset)

return response.getParsedApiResponse { it.toAlbumTracks() }
}

override suspend fun getNewAlbumReleases(
limit: Int,
offset: Int
): SpotifyApiResponse<NewAlbumReleases, ErrorBody> {
val response = albumApi.getNewAlbumReleases(limit, offset)

return response.getParsedApiResponse { it.toNewAlbumReleases() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.github.rubenquadros.kovibes.api.album

import io.github.rubenquadros.kovibes.api.ApiResponse
import io.github.rubenquadros.kovibes.api.album.models.GetAlbumTracksResponse
import io.github.rubenquadros.kovibes.api.album.models.GetNewAlbumReleasesResponse
import io.github.rubenquadros.kovibes.api.models.AlbumInfo
import io.github.rubenquadros.kovibes.api.response.ErrorBody

/**
* Album API interface provides methods using which one can get all the information about an album.
*
* Each API returns [ApiResponse]
*/
internal interface AlbumApi {

/**
* Get album API returns the information about an album.
*
* @param id
* @param market
* @return [AlbumInfo] when success and [ErrorBody] when error.
*/
suspend fun getAlbum(id: String, market: String?): ApiResponse<AlbumInfo, ErrorBody>

/**
* Get album tracks API returns all the tracks in an album.
*
* @param id
* @param market
* @param limit
* @param offset
* @return [GetAlbumTracksResponse] when success and [ErrorBody] when error.
*/
suspend fun getAlbumTracks(
id: String,
market: String?,
limit: Int,
offset: Int
): ApiResponse<GetAlbumTracksResponse, ErrorBody>

/**
* Get new album releases API returns all the albums that have newly released.
*
* @param limit
* @param offset
* @return [GetNewAlbumReleasesResponse] when success and [ErrorBody] when error.
*/
suspend fun getNewAlbumReleases(
limit: Int,
offset: Int
): ApiResponse<GetNewAlbumReleasesResponse, ErrorBody>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.github.rubenquadros.kovibes.api.album

import io.github.rubenquadros.kovibes.api.ApiResponse
import io.github.rubenquadros.kovibes.api.KtorService
import io.github.rubenquadros.kovibes.api.album.models.GetNewAlbumReleasesResponse
import io.github.rubenquadros.kovibes.api.album.models.GetAlbumTracksResponse
import io.github.rubenquadros.kovibes.api.getParsedHttpResponse
import io.github.rubenquadros.kovibes.api.models.AlbumInfo
import io.github.rubenquadros.kovibes.api.response.ErrorBody
import io.ktor.client.request.get
import io.ktor.http.path
import io.ktor.util.StringValues
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

internal class AlbumApiImpl(
private val ktorService: KtorService,
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) : AlbumApi {
override suspend fun getAlbum(id: String, market: String?): ApiResponse<AlbumInfo, ErrorBody> {
val response = withContext(dispatcher) {
ktorService.client.get {
url {
path("v1/albums/${id}")

parameters.appendAll(
StringValues.build {
market?.let { this["market"] = market }
}
)
}
}
}

return response.getParsedHttpResponse()
}

override suspend fun getAlbumTracks(
id: String,
market: String?,
limit: Int,
offset: Int
): ApiResponse<GetAlbumTracksResponse, ErrorBody> {
val response = withContext(dispatcher) {
ktorService.client.get {
url {
path("v1/albums/$id/tracks")

parameters.appendAll(
StringValues.build {
market?.let { this["market"] = market }
this["limit"] = limit.toString()
this["offset"] = offset.toString()
}
)
}
}
}

return response.getParsedHttpResponse()
}

override suspend fun getNewAlbumReleases(
limit: Int,
offset: Int
): ApiResponse<GetNewAlbumReleasesResponse, ErrorBody> {
val response = withContext(dispatcher) {
ktorService.client.get {
url {
path("v1/browse/new-releases")

parameters.appendAll(
StringValues.build {
this["limit"] = limit.toString()
this["offset"] = offset.toString()
}
)
}
}
}

return response.getParsedHttpResponse()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.github.rubenquadros.kovibes.api.album

import io.github.rubenquadros.kovibes.api.album.models.GetAlbumTracksResponse
import io.github.rubenquadros.kovibes.api.album.models.GetNewAlbumReleasesResponse
import io.github.rubenquadros.kovibes.api.album.models.SimplifiedTrackInfo
import io.github.rubenquadros.kovibes.api.mapper.toAlbum
import io.github.rubenquadros.kovibes.api.mapper.toArtist
import io.github.rubenquadros.kovibes.api.response.AlbumTrack
import io.github.rubenquadros.kovibes.api.response.AlbumTracks
import io.github.rubenquadros.kovibes.api.response.NewAlbumReleases

/**
* @suppress
* Map [GetAlbumTracksResponse] to [AlbumTracks].
*/
internal fun GetAlbumTracksResponse.toAlbumTracks(): AlbumTracks {
return AlbumTracks(
isNext = next != null,
items = items.map { it.toAlbumTrack() }
)
}

/**
* @suppress
* Map [GetNewAlbumReleasesResponse] to [NewAlbumReleases].
*/
internal fun GetNewAlbumReleasesResponse.toNewAlbumReleases(): NewAlbumReleases {
return NewAlbumReleases(
isNext = albums.next != null,
items = albums.items.map { it.toAlbum() }
)
}

private fun SimplifiedTrackInfo.toAlbumTrack(): AlbumTrack {
return AlbumTrack(
id = id,
name = name,
previewUrl = previewUrl,
duration = duration,
artists = artists.map { it.toArtist() }
)
}
Loading

0 comments on commit 60a6842

Please sign in to comment.