Skip to content

Commit 8c903e3

Browse files
committed
finish the readme, a few changes make all our lives easier
1 parent 9af231a commit 8c903e3

File tree

6 files changed

+104
-11
lines changed

6 files changed

+104
-11
lines changed

README.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,22 @@ time, this will likely be accurate within a few milliseconds.
7777

7878
## Using the Library
7979
### The benefits of LinkedResults, PagingObjects, and Cursor-based Paging Objects
80-
tbd
80+
Spotify provides these three object models in order to simplify our lives as developers. So let's see what we
81+
can do with them!
82+
83+
#### PagingObjects
84+
PagingObjects are a container for the requested objects (`items`), but also include
85+
important information useful in future calls. It contains the request's `limit` and `offset`, along with
86+
(sometimes) a link to the next and last page of items and the total number of items returned.
87+
88+
#### Cursor-Based Paging Objects
89+
A cursor-based paging object is a PagingObject with a cursor added on that can be used as a key to find the next
90+
page of items
91+
92+
#### LinkedResults
93+
Some endpoints, like `PlaylistsAPI.getPlaylistTracks`, return a LinkedResult, which is a simple wrapper around the
94+
list of objects. With this, we have access to its Spotify API url (with `href`), and we provide simple methods to parse
95+
that url.
8196

8297
### Generic Request
8398
```kotlin
@@ -99,7 +114,16 @@ tbd
99114
```
100115

101116
### Track Relinking
102-
tbd
117+
Spotify keeps many instances of most tracks on their servers, available in different markets. As such, if we use endpoints
118+
that return tracks, we do not know if these tracks are playable in our market. That's where track relinking comes in.
119+
120+
To relink in a specified market, we must supply a `market` parameter for endpoints where available.
121+
In both Track and SimpleTrack objects in an endpoint response, there is a nullable field called `linked_from`.
122+
If the track is unable to be played in the specified market and there is an alternative that *is* playable, this
123+
will be populated with the href, uri, and, most importantly, the id of the track.
124+
125+
You can then use this track in client actions such as playing or saving the track, knowing that it will be playable
126+
in your market!
103127

104128
### Endpoint List
105129
#### SpotifyAPI:

src/main/kotlin/com/adamratzman/spotify/endpoints/priv/follow/UserFollowAPI.kt

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,17 @@ class UserFollowAPI(api: SpotifyAPI) : SpotifyEndpoint(api) {
121121
})
122122
}
123123

124-
124+
/**
125+
* Add the current user as a follower of a playlist.
126+
*
127+
* @param ownerId The Spotify user ID of the person who owns the playlist.
128+
* @param playlistId The Spotify ID of the playlist. Any playlist can be followed, regardless of its
129+
* public/private status, as long as you know its playlist ID.
130+
* @param followPublicly Defaults to true. If true the playlist will be included in user’s public playlists,
131+
* if false it will remain private. To be able to follow playlists privately, the user must have granted the playlist-modify-private scope.
132+
*
133+
* @throws BadRequestException if the playlist is not found
134+
*/
125135
fun followPlaylist(ownerId: String, playlistId: String, followPublicly: Boolean = true): SpotifyRestAction<Unit> {
126136
return toAction(Supplier {
127137
put("https://api.spotify.com/v1/users/$ownerId/playlists/$playlistId/followers", "{\"public\": $followPublicly}")
@@ -130,20 +140,68 @@ class UserFollowAPI(api: SpotifyAPI) : SpotifyEndpoint(api) {
130140

131141
}
132142

143+
/**
144+
* Remove the current user as a follower of another user
145+
*
146+
* @param userId The user to be unfollowed from
147+
*
148+
* @throws BadRequestException if [userId] is not found
149+
*/
150+
fun unfollowUser(userId: String): SpotifyRestAction<Unit> {
151+
return toAction(Supplier {
152+
unfollowUsers(userId).complete()
153+
})
154+
}
155+
156+
/**
157+
* Remove the current user as a follower of other users
158+
*
159+
* @param userIds The users to be unfollowed from
160+
*
161+
* @throws BadRequestException if an invalid id is provided
162+
*/
133163
fun unfollowUsers(vararg userIds: String): SpotifyRestAction<Unit> {
134164
return toAction(Supplier {
135165
delete("https://api.spotify.com/v1/me/following?type=user&ids=${userIds.joinToString(",") { it.encode() }}")
136166
Unit
137167
})
138168
}
139169

170+
/**
171+
* Remove the current user as a follower of an artist
172+
*
173+
* @param artistId The artist to be unfollowed from
174+
*
175+
* @throws BadRequestException if an invalid id is provided
176+
*/
177+
fun unfollowArtist(artistId: String): SpotifyRestAction<Unit> {
178+
return toAction(Supplier {
179+
unfollowArtists(artistId).complete()
180+
})
181+
}
182+
183+
/**
184+
* Remove the current user as a follower of artists
185+
*
186+
* @param artistIds The artists to be unfollowed from
187+
*
188+
* @throws BadRequestException if an invalid id is provided
189+
*/
140190
fun unfollowArtists(vararg artistIds: String): SpotifyRestAction<Unit> {
141191
return toAction(Supplier {
142192
delete("https://api.spotify.com/v1/me/following?type=artist&ids=${artistIds.joinToString(",")}")
143193
Unit
144194
})
145195
}
146196

197+
/**
198+
* Remove the current user as a follower of a playlist.
199+
*
200+
* @param ownerId The Spotify user ID of the person who owns the playlist.
201+
* @param playlistId The Spotify ID of the playlist that is to be no longer followed.
202+
*
203+
* @throws BadRequestException if the playlist is not found
204+
*/
147205
fun unfollowPlaylist(ownerId: String, playlistId: String): SpotifyRestAction<Unit> {
148206
return toAction(Supplier {
149207
delete("https://api.spotify.com/v1/users/$ownerId/playlists/$playlistId/followers")

src/main/kotlin/com/adamratzman/spotify/endpoints/priv/personalization/PersonalizationAPI.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import java.util.function.Supplier
88
* Endpoints for retrieving information about the user’s listening habits.
99
*/
1010
class PersonalizationAPI(api: SpotifyAPI) : SpotifyEndpoint(api) {
11+
1112
fun getTopArtists(): SpotifyRestAction<PagingObject<Artist>> {
1213
return toAction(Supplier {
1314
get("https://api.spotify.com/v1/me/top/artists").toPagingObject<Artist>(api = api)

src/main/kotlin/com/adamratzman/spotify/endpoints/priv/users/UserAPI.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ import java.util.function.Supplier
1111
* Endpoints for retrieving information about a user’s profile.
1212
*/
1313
class UserAPI(api: SpotifyAPI) : SpotifyEndpoint(api) {
14+
/**
15+
* Get detailed profile information about the current user (including the current user’s username).
16+
*
17+
* The access token must have been issued on behalf of the current user.
18+
* Reading the user’s email address requires the user-read-email scope; reading country and product subscription level
19+
* requires the user-read-private scope. Reading the user’s birthdate requires the user-read-birthdate scope.
20+
*
21+
* @return Never-null [SpotifyUserInformation] object with possibly-null country, email, subscription and birthday fields
22+
*/
1423
fun getUserProfile(): SpotifyRestAction<SpotifyUserInformation> {
1524
return toAction(Supplier {
1625
get("https://api.spotify.com/v1/me").toObject<SpotifyUserInformation>(api)

src/main/kotlin/com/adamratzman/spotify/utils/Helpers.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.google.gson.Gson
66
import org.json.JSONObject
77
import org.jsoup.Connection
88
import org.jsoup.Jsoup
9+
import java.io.InvalidObjectException
910
import java.net.URLEncoder
1011
import java.util.*
1112
import java.util.function.Supplier
@@ -58,24 +59,24 @@ data class PlaylistTrackPagingObject(val href: String, val items: List<PlaylistT
5859
data class SimpleTrackPagingObject(val href: String, val items: List<SimpleTrack>, val limit: Int, val next: String? = null, val offset: Int = 0, val previous: String? = null, val total: Int)
5960

6061
data class LinkedResult<out T>(val href: String, val items: List<T>) {
61-
fun toPlaylistParams(): PlaylistParams? {
62+
fun toPlaylistParams(): PlaylistParams {
6263
if (href.startsWith("https://api.spotify.com/v1/users/")) {
6364
val split = href.removePrefix("https://api.spotify.com/v1/users/").split("/playlists/")
6465
if (split.size == 2) return PlaylistParams(split[0], split[1].split("/")[0])
6566
}
66-
return null
67+
throw InvalidObjectException("This object is not linked to a playlist")
6768
}
68-
fun getArtistId(): String? {
69+
fun getArtistId(): String {
6970
if (href.startsWith("https://api.spotify.com/v1/artists/")) {
7071
return href.removePrefix("https://api.spotify.com/v1/artists/").split("/")[0]
7172
}
72-
return null
73+
throw InvalidObjectException("This object is not linked to an artist")
7374
}
74-
fun getAlbumId(): String? {
75+
fun getAlbumId(): String {
7576
if (href.startsWith("https://api.spotify.com/v1/albums/")) {
7677
return href.removePrefix("https://api.spotify.com/v1/albums/").split("/")[0]
7778
}
78-
return null
79+
throw InvalidObjectException("This object is not linked to an album")
7980
}
8081
}
8182

src/main/kotlin/com/adamratzman/spotify/utils/ResultObjects.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ data class PlaylistTrackInfo(val href: String, val total: Int)
2020
*/
2121
data class Followers(val href: String?, val total: Int)
2222

23-
data class SpotifyUserInformation(val birthdate: String, val country: String, val display_name: String?, val email: String,
23+
data class SpotifyUserInformation(val birthdate: String?, val country: String?, val display_name: String?, val email: String?,
2424
val external_urls: HashMap<String, String>, val followers: Followers, val href: String,
25-
val id: String, val images: List<SpotifyImage>, val product: String, val type: String,
25+
val id: String, val images: List<SpotifyImage>, val product: String?, val type: String,
2626
val uri: String)
2727

2828
data class SpotifyPublicUser(val display_name: String, val external_urls: HashMap<String, String>, val followers: Followers, val href: String,

0 commit comments

Comments
 (0)