Skip to content

Commit

Permalink
Adding the artist api.
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenquadros committed Apr 24, 2024
1 parent 3e4d666 commit 4c501b3
Show file tree
Hide file tree
Showing 33 changed files with 9,828 additions and 101 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.artist.ArtistApiImpl
import io.github.rubenquadros.kovibes.api.browse.BrowseApiImpl
import io.github.rubenquadros.kovibes.api.playlist.PlaylistApiImpl
import io.github.rubenquadros.kovibes.api.recommendations.RecommendationsApiImpl
Expand All @@ -25,7 +26,8 @@ object KoVibesApi {
playlistApi = PlaylistApiImpl(ktorService),
browseApi = BrowseApiImpl(ktorService),
searchApi = SearchApiImpl(ktorService),
recommendationsApi = RecommendationsApiImpl(ktorService)
recommendationsApi = RecommendationsApiImpl(ktorService),
artistApi = ArtistApiImpl(ktorService)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package io.github.rubenquadros.kovibes.api

import io.github.rubenquadros.kovibes.api.request.GetRecommendationsRequest
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
Expand Down Expand Up @@ -214,4 +216,55 @@ interface SpotifyService {
suspend fun getRecommendations(
getRecommendationsRequest: GetRecommendationsRequest
): SpotifyApiResponse<Recommendations, ErrorBody>

/**
* Get artist API returns the information about the artist.
*
* See [Spotify Doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artist).
*
* @param id
* @return [Artist] when success and [ErrorBody] when error.
*/
suspend fun getArtist(id: String): SpotifyApiResponse<Artist, ErrorBody>

/**
* Get artist albums API returns all the albums of the artist.
* 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 [Albums.isNext].
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artists-albums).
*
* @param id
* @param includeGroups
* @param market
* @param limit
* @param offset
* @return [Albums] when success and [ErrorBody] when error.
*/
suspend fun getArtistAlbums(
id: String,
includeGroups: List<String> = listOf("album"),
market: String? = null,
limit: Int = 20,
offset: Int = 0
): SpotifyApiResponse<Albums, ErrorBody>

/**
* Get artist top tracks API returns the top tracks of the artist.
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artists-top-tracks).
*
* @param id
* @param market
* @return [ArtistTopTracks] when success and [ErrorBody] when error.
*/
suspend fun getArtistTopTracks(
id: String,
market: String? = null
): SpotifyApiResponse<ArtistTopTracks, ErrorBody>
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package io.github.rubenquadros.kovibes.api

import io.github.rubenquadros.kovibes.api.artist.ArtistApi
import io.github.rubenquadros.kovibes.api.artist.toArtistTopTracks
import io.github.rubenquadros.kovibes.api.browse.BrowseApi
import io.github.rubenquadros.kovibes.api.browse.toCategories
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
Expand All @@ -11,6 +15,8 @@ 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.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
Expand All @@ -21,7 +27,6 @@ import io.github.rubenquadros.kovibes.api.response.Recommendations
import io.github.rubenquadros.kovibes.api.response.SpotifyApiResponse
import io.github.rubenquadros.kovibes.api.response.Tracks
import io.github.rubenquadros.kovibes.api.search.SearchApi
import io.github.rubenquadros.kovibes.api.search.toSearchAlbum
import io.github.rubenquadros.kovibes.api.search.toSearchArtist
import io.github.rubenquadros.kovibes.api.search.toSearchPlaylist
import io.github.rubenquadros.kovibes.api.search.toSearchTrack
Expand All @@ -34,12 +39,14 @@ import io.github.rubenquadros.kovibes.api.search.toSearchTrack
* @property browseApi
* @property searchApi
* @property recommendationsApi
* @property artistApi
*/
internal class SpotifyServiceImpl(
private val playlistApi: PlaylistApi,
private val browseApi: BrowseApi,
private val searchApi: SearchApi,
private val recommendationsApi: RecommendationsApi
private val recommendationsApi: RecommendationsApi,
private val artistApi: ArtistApi
) : SpotifyService {
override suspend fun getFeaturedPlaylists(
locale: String,
Expand Down Expand Up @@ -100,7 +107,7 @@ internal class SpotifyServiceImpl(
): SpotifyApiResponse<Albums, ErrorBody> {
val response = searchApi.searchAlbum(query, market, limit, offset)

return response.getParsedApiResponse { it.toSearchAlbum() }
return response.getParsedApiResponse { it.albumResponse.toAlbums() }
}

override suspend fun searchArtist(
Expand Down Expand Up @@ -130,4 +137,31 @@ internal class SpotifyServiceImpl(

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

override suspend fun getArtist(id: String): SpotifyApiResponse<Artist, ErrorBody> {
val response = artistApi.getArtist(id)

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

override suspend fun getArtistAlbums(
id: String,
includeGroups: List<String>,
market: String?,
limit: Int,
offset: Int
): SpotifyApiResponse<Albums, ErrorBody> {
val response = artistApi.getArtistAlbums(id, includeGroups, market, limit, offset)

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

override suspend fun getArtistTopTracks(
id: String,
market: String?
): SpotifyApiResponse<ArtistTopTracks, ErrorBody> {
val response = artistApi.getArtistTopTracks(id, market)

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

import io.github.rubenquadros.kovibes.api.ApiResponse
import io.github.rubenquadros.kovibes.api.artist.models.GetArtistTopTracksResponse
import io.github.rubenquadros.kovibes.api.models.AlbumResponse
import io.github.rubenquadros.kovibes.api.models.ArtistInfo
import io.github.rubenquadros.kovibes.api.response.ErrorBody

/**
* Artist API interface provides methods using which one can get information about the artist.
* You can get artists' top tracks, albums and also other related artists.
*
* Each API returns [ApiResponse].
*/
internal interface ArtistApi {

/**
* Get artist API returns the artist information from the given ID.
*
* @param id
* @return [ArtistInfo] when success and [ErrorBody] when error.
*/
suspend fun getArtist(id: String): ApiResponse<ArtistInfo, ErrorBody>

/**
* Get artist albums API returns the albums, single, features and compilations of the artist.
*
* @param id
* @param includeGroups
* @param market
* @param limit
* @param offset
* @return [AlbumResponse] when success and [ErrorBody] when error.
*/
suspend fun getArtistAlbums(
id: String,
includeGroups: List<String>,
market: String?,
limit: Int,
offset: Int
): ApiResponse<AlbumResponse, ErrorBody>

/**
* Get artist top tracks API returns the top tracks of the artist.
*
* @param id
* @param market
* @return [GetArtistTopTracksResponse] when success and [ErrorBody] when error.
*/
suspend fun getArtistTopTracks(
id: String,
market: String?
): ApiResponse<GetArtistTopTracksResponse, ErrorBody>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package io.github.rubenquadros.kovibes.api.artist

import io.github.rubenquadros.kovibes.api.ApiResponse
import io.github.rubenquadros.kovibes.api.KtorService
import io.github.rubenquadros.kovibes.api.artist.models.GetArtistTopTracksResponse
import io.github.rubenquadros.kovibes.api.getParsedHttpResponse
import io.github.rubenquadros.kovibes.api.models.AlbumResponse
import io.github.rubenquadros.kovibes.api.models.ArtistInfo
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

/**
* @suppress
* ArtistApiImpl is the implementation of [ArtistApi].
*
* @property ktorService
* @property dispatcher
*/
internal class ArtistApiImpl(
private val ktorService: KtorService,
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) : ArtistApi {
override suspend fun getArtist(id: String): ApiResponse<ArtistInfo, ErrorBody> {
val response = withContext(dispatcher) {
ktorService.client.get {
url {
path("v1/artists/$id")
}
}
}

return response.getParsedHttpResponse()
}

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

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

return response.getParsedHttpResponse()
}

override suspend fun getArtistTopTracks(
id: String,
market: String?
): ApiResponse<GetArtistTopTracksResponse, ErrorBody> {
val response = withContext(dispatcher) {
ktorService.client.get {
url {
path("v1/artists/$id/top-tracks")

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

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

import io.github.rubenquadros.kovibes.api.artist.models.GetArtistTopTracksResponse
import io.github.rubenquadros.kovibes.api.mapper.toTrack
import io.github.rubenquadros.kovibes.api.response.ArtistTopTracks

/**
* @suppress
* Map [GetArtistTopTracksResponse] to [ArtistTopTracks].
*/
internal fun GetArtistTopTracksResponse.toArtistTopTracks(): ArtistTopTracks {
return ArtistTopTracks(
tracks = tracks.map { it.toTrack() }
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.github.rubenquadros.kovibes.api.artist.models

import io.github.rubenquadros.kovibes.api.ExcludeFromCoverage
import io.github.rubenquadros.kovibes.api.models.TrackInfo
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@ExcludeFromCoverage
@Serializable
internal data class GetArtistTopTracksResponse(
@SerialName("tracks")
val tracks: List<TrackInfo>
)
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package io.github.rubenquadros.kovibes.api.mapper

import io.github.rubenquadros.kovibes.api.models.AlbumInfo
import io.github.rubenquadros.kovibes.api.models.AlbumResponse
import io.github.rubenquadros.kovibes.api.models.ArtistInfo
import io.github.rubenquadros.kovibes.api.models.ImageInfo
import io.github.rubenquadros.kovibes.api.models.PlaylistInfo
import io.github.rubenquadros.kovibes.api.models.TrackInfo
import io.github.rubenquadros.kovibes.api.playlist.models.RestrictionInfo
import io.github.rubenquadros.kovibes.api.response.Album
import io.github.rubenquadros.kovibes.api.response.Albums
import io.github.rubenquadros.kovibes.api.response.Artist
import io.github.rubenquadros.kovibes.api.response.Image
import io.github.rubenquadros.kovibes.api.response.Playlist
Expand Down Expand Up @@ -51,7 +53,8 @@ internal fun ArtistInfo.toArtist(): Artist {
*/
internal fun AlbumInfo.toAlbum(): Album {
return Album(
albumType = type,
albumGroup = albumGroup.orEmpty(),
albumType = albumType,
availableMarkets = availableMarkets,
id = id,
name = name,
Expand Down Expand Up @@ -103,4 +106,15 @@ internal fun PlaylistInfo.toPlayList(): Playlist {
imageInfo.toImage()
}
)
}

/**
* @suppress
* Map [AlbumResponse] to [Albums]
*/
internal fun AlbumResponse.toAlbums(): Albums {
return Albums(
isNext = next != null,
items = items.map { it.toAlbum() }
)
}
Loading

0 comments on commit 4c501b3

Please sign in to comment.