Skip to content

Commit 0cd3853

Browse files
authored
Merge pull request #185 from adamint/dev
Dev
2 parents 6e73e12 + 810d758 commit 0cd3853

File tree

19 files changed

+340
-237
lines changed

19 files changed

+340
-237
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Kotlin Spotify Web API
2-
[ ![JCenter Download](https://api.bintray.com/packages/bintray/jcenter/com.adamratzman%3Aspotify-api-kotlin/images/download.svg) ](https://bintray.com/bintray/jcenter/com.adamratzman%3Aspotify-api-kotlin/_latestVersion)
2+
[![JCenter](https://maven-badges.herokuapp.com/maven-central/com.adamratzman/spotify-api-kotlin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.adamratzman/spotify-api-kotlin)
33
[![Build Status](http://144.217.240.243:8111/app/rest/builds/aggregated/strob:(buildType:(project:(id:SpotifyWebApiKotlin)))/statusIcon.svg)](http://144.217.240.243:8111/project.html?projectId=SpotifyWebApiKotlin)
44
[![](https://img.shields.io/badge/Documentation-latest-orange.svg)](https://adamint.github.io/spotify-web-api-kotlin/docs/spotify-web-api-kotlin/)
55
![](https://img.shields.io/badge/License-MIT-blue.svg)

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ plugins {
1515
}
1616

1717
group = "com.adamratzman"
18-
version = "3.0.0"
18+
version = "3.0.01"
1919

2020
java {
2121
withSourcesJar()

src/commonMain/kotlin/com.adamratzman.spotify/Builder.kt

Lines changed: 150 additions & 113 deletions
Large diffs are not rendered by default.

src/commonMain/kotlin/com.adamratzman.spotify/SpotifyApi.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ internal const val base = "https://api.spotify.com/v1"
5555
* @property browse Provides access to Spotify [browse endpoints](https://developer.spotify.com/documentation/web-api/reference/browse/)
5656
* @property artists Provides access to Spotify [artist endpoints](https://developer.spotify.com/documentation/web-api/reference/artists/)
5757
* @property tracks Provides access to Spotify [track endpoints](https://developer.spotify.com/documentation/web-api/reference/tracks/)
58-
*
58+
* @property defaultLimit The default amount of objects to retrieve in one request
59+
* @property json The Json serializer/deserializer instance
5960
* @property logger The Spotify event logger
6061
*
6162
*/
@@ -69,6 +70,8 @@ sealed class SpotifyApi<T : SpotifyApi<T, B>, B : ISpotifyApiBuilder<T, B>>(
6970
var retryWhenRateLimited: Boolean,
7071
enableLogger: Boolean,
7172
testTokenValidity: Boolean,
73+
var defaultLimit: Int,
74+
var allowBulkRequests: Boolean,
7275
var json: Json
7376
) {
7477
var useCache = useCache
@@ -349,6 +352,8 @@ class SpotifyAppApi internal constructor(
349352
retryWhenRateLimited: Boolean,
350353
enableLogger: Boolean,
351354
testTokenValidity: Boolean,
355+
defaultLimit: Int,
356+
allowBulkRequests: Boolean,
352357
json: Json
353358
) : SpotifyApi<SpotifyAppApi, SpotifyAppApiBuilder>(
354359
clientId,
@@ -360,6 +365,8 @@ class SpotifyAppApi internal constructor(
360365
retryWhenRateLimited,
361366
enableLogger,
362367
testTokenValidity,
368+
defaultLimit,
369+
allowBulkRequests,
363370
json
364371
) {
365372
constructor(
@@ -377,6 +384,8 @@ class SpotifyAppApi internal constructor(
377384
options.retryWhenRateLimited,
378385
options.enableLogger,
379386
options.testTokenValidity,
387+
options.defaultLimit,
388+
options.allowBulkRequests,
380389
options.json
381390
)
382391

@@ -453,6 +462,8 @@ class SpotifyClientApi internal constructor(
453462
retryWhenRateLimited: Boolean,
454463
enableLogger: Boolean,
455464
testTokenValidity: Boolean,
465+
defaultLimit: Int,
466+
allowBulkRequests: Boolean,
456467
json: Json
457468
) : SpotifyApi<SpotifyClientApi, SpotifyClientApiBuilder>(
458469
clientId,
@@ -464,6 +475,8 @@ class SpotifyClientApi internal constructor(
464475
retryWhenRateLimited,
465476
enableLogger,
466477
testTokenValidity,
478+
defaultLimit,
479+
allowBulkRequests,
467480
json
468481
) {
469482
constructor(
@@ -483,6 +496,8 @@ class SpotifyClientApi internal constructor(
483496
options.retryWhenRateLimited,
484497
options.enableLogger,
485498
options.testTokenValidity,
499+
options.defaultLimit,
500+
options.allowBulkRequests,
486501
options.json
487502
)
488503

src/commonMain/kotlin/com.adamratzman.spotify/endpoints/client/ClientFollowingApi.kt

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
6565
fun isFollowingPlaylist(playlistId: String): SpotifyRestAction<Boolean> {
6666
return toAction {
6767
isFollowingPlaylist(
68-
playlistId,
69-
(api as SpotifyClientApi).userId
68+
playlistId,
69+
(api as SpotifyClientApi).userId
7070
).complete()
7171
}
7272
}
@@ -86,8 +86,8 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
8686
fun isFollowingUsers(vararg users: String): SpotifyRestAction<List<Boolean>> {
8787
return toAction {
8888
get(
89-
EndpointBuilder("/me/following/contains").with("type", "user")
90-
.with("ids", users.joinToString(",") { UserUri(it).id.encodeUrl() }).toString()
89+
EndpointBuilder("/me/following/contains").with("type", "user")
90+
.with("ids", users.joinToString(",") { UserUri(it).id.encodeUrl() }).toString()
9191
).toList(Boolean.serializer().list, api, json)
9292
}
9393
}
@@ -125,8 +125,8 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
125125
fun isFollowingArtists(vararg artists: String): SpotifyRestAction<List<Boolean>> {
126126
return toAction {
127127
get(
128-
EndpointBuilder("/me/following/contains").with("type", "artist")
129-
.with("ids", artists.joinToString(",") { ArtistUri(it).id.encodeUrl() }).toString()
128+
EndpointBuilder("/me/following/contains").with("type", "artist")
129+
.with("ids", artists.joinToString(",") { ArtistUri(it).id.encodeUrl() }).toString()
130130
).toList(Boolean.serializer().list, api, json)
131131
}
132132
}
@@ -138,22 +138,22 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
138138
*
139139
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/follow/get-followed/)**
140140
*
141-
* @param limit The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50.
141+
* @param limit The maximum number of items to return. Default: 50 (or api limit). Minimum: 1. Maximum: 50.
142142
* @param after The last artist ID retrieved from the previous request.
143143
*
144144
* @return [CursorBasedPagingObject] ([Information about them](https://github.com/adamint/spotify-web-api-kotlin/blob/master/README.md#the-benefits-of-linkedresults-pagingobjects-and-cursor-based-paging-objects)
145145
* with full [Artist] objects
146146
*/
147147
fun getFollowedArtists(
148-
limit: Int? = null,
148+
limit: Int? = api.defaultLimit,
149149
after: String? = null
150150
): SpotifyRestActionPaging<Artist, CursorBasedPagingObject<Artist>> {
151151
return toActionPaging {
152152
get(
153-
EndpointBuilder("/me/following").with("type", "artist").with("limit", limit).with(
154-
"after",
155-
after
156-
).toString()
153+
EndpointBuilder("/me/following").with("type", "artist").with("limit", limit).with(
154+
"after",
155+
after
156+
).toString()
157157
).toCursorBasedPagingObject(Artist.serializer(), "artists", this, json)
158158
}
159159
}
@@ -180,14 +180,19 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
180180
*
181181
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/follow/follow-artists-users/)**
182182
*
183+
* @param users User ids or uris. Maximum **50**.
184+
*
183185
* @throws BadRequestException if an invalid id is provided
184186
*/
185187
fun followUsers(vararg users: String): SpotifyRestAction<Unit> {
188+
if (users.size > 50 && !api.allowBulkRequests) throw BadRequestException("Too many users (${users.size}) provided, only 50 allowed", IllegalArgumentException("Bulk requests are not turned on, and too many users were provided"))
186189
return toAction {
187-
put(
188-
EndpointBuilder("/me/following").with("type", "user")
189-
.with("ids", users.joinToString(",") { UserUri(it).id.encodeUrl() }).toString()
190-
)
190+
users.toList().chunked(50).forEach { list ->
191+
put(
192+
EndpointBuilder("/me/following").with("type", "user")
193+
.with("ids", list.joinToString(",") { UserUri(it).id.encodeUrl() }).toString()
194+
)
195+
}
191196
Unit
192197
}
193198
}
@@ -214,14 +219,19 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
214219
*
215220
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/follow/follow-artists-users/)**
216221
*
222+
* @param artists User ids or uris. Maximum **50**.
223+
*
217224
* @throws BadRequestException if an invalid id is provided
218225
*/
219226
fun followArtists(vararg artists: String): SpotifyRestAction<Unit> {
227+
if (artists.size > 50 && !api.allowBulkRequests) throw BadRequestException("Too many artists (${artists.size}) provided, only 50 allowed", IllegalArgumentException("Bulk requests are not turned on, and too many artists were provided"))
220228
return toAction {
221-
put(
222-
EndpointBuilder("/me/following").with("type", "artist")
223-
.with("ids", artists.joinToString(",") { ArtistUri(it).id.encodeUrl() }).toString()
224-
)
229+
artists.toList().chunked(50).forEach { list ->
230+
put(
231+
EndpointBuilder("/me/following").with("type", "artist")
232+
.with("ids", list.joinToString(",") { ArtistUri(it).id.encodeUrl() }).toString()
233+
)
234+
}
225235
Unit
226236
}
227237
}
@@ -248,8 +258,8 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
248258
fun followPlaylist(playlist: String, followPublicly: Boolean = true): SpotifyRestAction<Unit> {
249259
return toAction {
250260
put(
251-
EndpointBuilder("/playlists/${PlaylistUri(playlist).id}/followers").toString(),
252-
"{\"public\": $followPublicly}"
261+
EndpointBuilder("/playlists/${PlaylistUri(playlist).id}/followers").toString(),
262+
"{\"public\": $followPublicly}"
253263
)
254264
Unit
255265
}
@@ -279,16 +289,19 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
279289
*
280290
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/follow/unfollow-artists-users/)**
281291
*
282-
* @param users The users to be unfollowed from
292+
* @param users The users to be unfollowed from. Maximum **50**.
283293
*
284294
* @throws BadRequestException if an invalid id is provided
285295
*/
286296
fun unfollowUsers(vararg users: String): SpotifyRestAction<Unit> {
297+
if (users.size > 50 && !api.allowBulkRequests) throw BadRequestException("Too many users (${users.size}) provided, only 50 allowed", IllegalArgumentException("Bulk requests are not turned on, and too many users were provided"))
287298
return toAction {
288-
delete(
289-
EndpointBuilder("/me/following").with("type", "user")
290-
.with("ids", users.joinToString(",") { UserUri(it).id.encodeUrl() }).toString()
291-
)
299+
users.toList().chunked(50).forEach { list ->
300+
delete(
301+
EndpointBuilder("/me/following").with("type", "user")
302+
.with("ids", list.joinToString(",") { UserUri(it).id.encodeUrl() }).toString()
303+
)
304+
}
292305
Unit
293306
}
294307
}
@@ -317,16 +330,20 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
317330
*
318331
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/follow/unfollow-artists-users/)**
319332
*
320-
* @param artists The artists to be unfollowed from
333+
* @param artists The artists to be unfollowed from. Maximum **50**.
334+
*
321335
*
322336
* @throws BadRequestException if an invalid id is provided
323337
*/
324338
fun unfollowArtists(vararg artists: String): SpotifyRestAction<Unit> {
339+
if (artists.size > 50 && !api.allowBulkRequests) throw BadRequestException("Too many artists (${artists.size}) provided, only 50 allowed", IllegalArgumentException("Bulk requests are not turned on, and too many artists were provided"))
325340
return toAction {
326-
delete(
327-
EndpointBuilder("/me/following").with("type", "artist")
328-
.with("ids", artists.joinToString(",") { ArtistUri(it).id.encodeUrl() }).toString()
329-
)
341+
artists.toList().chunked(50).forEach { list ->
342+
delete(
343+
EndpointBuilder("/me/following").with("type", "artist")
344+
.with("ids", list.joinToString(",") { ArtistUri(it).id.encodeUrl() }).toString()
345+
)
346+
}
330347
Unit
331348
}
332349
}

src/commonMain/kotlin/com.adamratzman.spotify/endpoints/client/ClientLibraryApi.kt

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ class ClientLibraryApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
3636
*
3737
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/library/get-users-saved-tracks/)**
3838
*
39-
* @param limit The number of objects to return. Default: 20. Minimum: 1. Maximum: 50.
39+
* @param limit The number of objects to return. Default: 50 (or api limit). Minimum: 1. Maximum: 50.
4040
* @param offset The index of the first item to return. Default: 0. Use with limit to get the next set of items
4141
* @param market Provide this parameter if you want the list of returned items to be relevant to a particular country.
4242
* If omitted, the returned items will be relevant to all countries.
4343
*
4444
* @return [PagingObject] of [SavedTrack] ordered by position in library
4545
*/
4646
fun getSavedTracks(
47-
limit: Int? = null,
47+
limit: Int? = api.defaultLimit,
4848
offset: Int? = null,
4949
market: Market? = null
5050
): SpotifyRestActionPaging<SavedTrack, PagingObject<SavedTrack>> {
@@ -63,15 +63,15 @@ class ClientLibraryApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
6363
*
6464
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/library/get-users-saved-albums/)**
6565
*
66-
* @param limit The number of objects to return. Default: 20. Minimum: 1. Maximum: 50.
66+
* @param limit The number of objects to return. Default: 50 (or api limit). Minimum: 1. Maximum: 50.
6767
* @param offset The index of the first item to return. Default: 0. Use with limit to get the next set of items
6868
* @param market Provide this parameter if you want the list of returned items to be relevant to a particular country.
6969
* If omitted, the returned items will be relevant to all countries.
7070
*
7171
* @return Paging Object of [SavedAlbum] ordered by position in library
7272
*/
7373
fun getSavedAlbums(
74-
limit: Int? = null,
74+
limit: Int? = api.defaultLimit,
7575
offset: Int? = null,
7676
market: Market? = null
7777
): SpotifyRestActionPaging<SavedAlbum, PagingObject<SavedAlbum>> {
@@ -109,16 +109,19 @@ class ClientLibraryApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
109109
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/library/)**
110110
*
111111
* @param type The type of objects (album or track)
112-
* @param ids The spotify ids or uris of the objects
112+
* @param ids The spotify ids or uris of the objects. Maximum **50** ids.
113113
*
114114
* @throws BadRequestException if any of the provided ids is invalid
115115
*/
116116
fun contains(type: LibraryType, vararg ids: String): SpotifyRestAction<List<Boolean>> {
117+
if (ids.size > 50 && !api.allowBulkRequests) throw BadRequestException("Too many ids (${ids.size}) provided, only 50 allowed", IllegalArgumentException("Bulk requests are not turned on, and too many ids were provided"))
117118
return toAction {
118-
get(
119-
EndpointBuilder("/me/$type/contains").with("ids", ids.joinToString(",") { type.id(it).encodeUrl() })
120-
.toString()
121-
).toList(Boolean.serializer().list, api, json)
119+
ids.toList().chunked(50).map { list ->
120+
get(
121+
EndpointBuilder("/me/$type/contains").with("ids", list.joinToString(",") { type.id(it).encodeUrl() })
122+
.toString()
123+
).toList(Boolean.serializer().list, api, json)
124+
}.flatten()
122125
}
123126
}
124127

@@ -148,13 +151,16 @@ class ClientLibraryApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
148151
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/library/)**
149152
*
150153
* @param type The type of objects to check against (album or track)
151-
* @param ids The spotify ids or uris of the objects
154+
* @param ids The spotify ids or uris of the objects. Maximum **50** ids.
152155
*
153156
* @throws BadRequestException if any of the provided ids is invalid
154157
*/
155158
fun add(type: LibraryType, vararg ids: String): SpotifyRestAction<Unit> {
159+
if (ids.size > 50 && !api.allowBulkRequests) throw BadRequestException("Too many ids (${ids.size}) provided, only 50 allowed", IllegalArgumentException("Bulk requests are not turned on, and too many ids were provided"))
156160
return toAction {
157-
put(EndpointBuilder("/me/$type").with("ids", ids.joinToString(",") { type.id(it).encodeUrl() }).toString())
161+
ids.toList().chunked(50).forEach { list ->
162+
put(EndpointBuilder("/me/$type").with("ids", list.joinToString(",") { type.id(it).encodeUrl() }).toString())
163+
}
158164
Unit
159165
}
160166
}
@@ -189,17 +195,20 @@ class ClientLibraryApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
189195
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/library/)**
190196
*
191197
* @param type The type of objects to check against (album or track)
192-
* @param ids The spotify ids or uris of the objects
198+
* @param ids The spotify ids or uris of the objects. Maximum **50** ids.
193199
*
194200
* @throws BadRequestException if any of the provided ids is invalid
195201
*/
196202
fun remove(type: LibraryType, vararg ids: String): SpotifyRestAction<Unit> {
203+
if (ids.size > 50 && !api.allowBulkRequests) throw BadRequestException("Too many ids (${ids.size}) provided, only 50 allowed", IllegalArgumentException("Bulk requests are not turned on, and too many ids were provided"))
197204
return toAction {
198-
delete(
199-
EndpointBuilder("/me/$type").with(
200-
"ids",
201-
ids.joinToString(",") { type.id(it).encodeUrl() }).toString()
202-
)
205+
ids.toList().chunked(50).forEach { list ->
206+
delete(
207+
EndpointBuilder("/me/$type").with(
208+
"ids",
209+
list.joinToString(",") { type.id(it).encodeUrl() }).toString()
210+
)
211+
}
203212
Unit
204213
}
205214
}

0 commit comments

Comments
 (0)