Skip to content

Commit f61c36e

Browse files
committed
add configurable json serializer/deserializer
1 parent 778cc60 commit f61c36e

File tree

22 files changed

+188
-149
lines changed

22 files changed

+188
-149
lines changed

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

Lines changed: 92 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,39 @@ package com.adamratzman.spotify
33

44
import com.adamratzman.spotify.http.HttpConnection
55
import com.adamratzman.spotify.http.HttpRequestMethod
6-
import com.adamratzman.spotify.models.SpotifyAuthenticationException
76
import com.adamratzman.spotify.models.Token
7+
import com.adamratzman.spotify.models.serialization.stableJson
88
import com.adamratzman.spotify.models.serialization.toObject
99
import com.adamratzman.spotify.utils.runBlocking
1010
import kotlinx.coroutines.CancellationException
1111
import kotlinx.coroutines.CoroutineScope
1212
import kotlinx.coroutines.Job
1313
import kotlinx.coroutines.launch
14+
import kotlinx.serialization.json.Json
1415

1516
// Kotlin DSL builders
1617

18+
fun spotifyAppApi(clientId: String, clientSecret: String, block: SpotifyAppApiBuilder.() -> Unit) =
19+
SpotifyAppApiBuilder().apply(block).apply {
20+
credentials {
21+
this.clientId = clientId
22+
this.clientSecret = clientSecret
23+
}
24+
}
25+
26+
fun spotifyClientApi(
27+
clientId: String,
28+
clientSecret: String,
29+
redirectUri: String,
30+
block: SpotifyClientApiBuilder.() -> Unit
31+
) = SpotifyClientApiBuilder().apply(block).apply {
32+
credentials {
33+
this.clientId = clientId
34+
this.clientSecret = clientSecret
35+
this.redirectUri = redirectUri
36+
}
37+
}
38+
1739
fun spotifyAppApi(block: SpotifyAppApiBuilder.() -> Unit) = SpotifyAppApiBuilder().apply(block)
1840
fun spotifyClientApi(block: SpotifyClientApiBuilder.() -> Unit) = SpotifyClientApiBuilder().apply(block)
1941

@@ -250,41 +272,42 @@ class SpotifyClientApiBuilder(
250272
require((clientId != null && clientSecret != null && redirectUri != null) || authorization.token != null || authorization.tokenString != null) { "You need to specify a valid clientId, clientSecret, and redirectUri in the credentials block!" }
251273
return when {
252274
authorization.authorizationCode != null -> try {
253-
require(clientId != null && clientSecret != null && redirectUri != null) { "You need to specify a valid clientId, clientSecret, and redirectUri in the credentials block!" }
254-
255-
val response = executeTokenRequest(
256-
HttpConnection(
257-
"https://accounts.spotify.com/api/token",
258-
HttpRequestMethod.POST,
259-
mapOf(
260-
"grant_type" to "authorization_code",
261-
"code" to authorization.authorizationCode,
262-
"redirect_uri" to redirectUri
263-
),
264-
null,
265-
"application/x-www-form-urlencoded",
266-
listOf(),
267-
null
268-
), clientId, clientSecret
269-
)
270-
271-
SpotifyClientApi(
272-
clientId,
273-
clientSecret,
274-
redirectUri,
275-
response.body.toObject(Token.serializer(), null),
276-
options.useCache,
277-
options.cacheLimit,
278-
options.automaticRefresh,
279-
options.retryWhenRateLimited,
280-
options.enableLogger,
281-
options.testTokenValidity
282-
)
283-
} catch (e: CancellationException) {
284-
throw e
285-
} catch (e: Exception) {
286-
throw SpotifyAuthenticationException("Invalid credentials provided in the login process", e)
287-
}
275+
require(clientId != null && clientSecret != null && redirectUri != null) { "You need to specify a valid clientId, clientSecret, and redirectUri in the credentials block!" }
276+
277+
val response = executeTokenRequest(
278+
HttpConnection(
279+
"https://accounts.spotify.com/api/token",
280+
HttpRequestMethod.POST,
281+
mapOf(
282+
"grant_type" to "authorization_code",
283+
"code" to authorization.authorizationCode,
284+
"redirect_uri" to redirectUri
285+
),
286+
null,
287+
"application/x-www-form-urlencoded",
288+
listOf(),
289+
null
290+
), clientId, clientSecret
291+
)
292+
293+
SpotifyClientApi(
294+
clientId,
295+
clientSecret,
296+
redirectUri,
297+
response.body.toObject(Token.serializer(), null, options.json),
298+
options.useCache,
299+
options.cacheLimit,
300+
options.automaticRefresh,
301+
options.retryWhenRateLimited,
302+
options.enableLogger,
303+
options.testTokenValidity,
304+
options.json
305+
)
306+
} catch (e: CancellationException) {
307+
throw e
308+
} catch (e: Exception) {
309+
throw SpotifyException.AuthenticationException("Invalid credentials provided in the login process", e)
310+
}
288311
authorization.token != null -> SpotifyClientApi(
289312
clientId,
290313
clientSecret,
@@ -295,7 +318,8 @@ class SpotifyClientApiBuilder(
295318
options.automaticRefresh,
296319
options.retryWhenRateLimited,
297320
options.enableLogger,
298-
options.testTokenValidity
321+
options.testTokenValidity,
322+
options.json
299323
)
300324
authorization.tokenString != null -> SpotifyClientApi(
301325
clientId,
@@ -313,7 +337,8 @@ class SpotifyClientApiBuilder(
313337
false,
314338
options.retryWhenRateLimited,
315339
options.enableLogger,
316-
options.testTokenValidity
340+
options.testTokenValidity,
341+
options.json
317342
)
318343
else -> throw IllegalArgumentException(
319344
"At least one of: authorizationCode, tokenString, or token must be provided " +
@@ -338,19 +363,18 @@ class SpotifyAppApiBuilder(
338363
val clientSecret = credentials.clientSecret
339364
require((clientId != null && clientSecret != null) || authorization.token != null || authorization.tokenString != null) { "You didn't specify a client id or client secret in the credentials block!" }
340365
return when {
341-
authorization.token != null -> {
342-
SpotifyAppApi(
343-
clientId,
344-
clientSecret,
345-
authorization.token!!,
346-
options.useCache,
347-
options.cacheLimit,
348-
false,
349-
options.retryWhenRateLimited,
350-
options.enableLogger,
351-
options.testTokenValidity
352-
)
353-
}
366+
authorization.token != null -> SpotifyAppApi(
367+
clientId ,
368+
clientSecret,
369+
authorization.token!!,
370+
options.useCache,
371+
options.cacheLimit,
372+
false,
373+
options.retryWhenRateLimited,
374+
options.enableLogger,
375+
options.testTokenValidity,
376+
options.json
377+
)
354378
authorization.tokenString != null -> {
355379
SpotifyAppApi(
356380
clientId,
@@ -364,12 +388,13 @@ class SpotifyAppApiBuilder(
364388
false,
365389
options.retryWhenRateLimited,
366390
options.enableLogger,
367-
options.testTokenValidity
391+
options.testTokenValidity,
392+
options.json
368393
)
369394
}
370395
else -> try {
371396
require(clientId != null && clientSecret != null) { "Illegal credentials provided" }
372-
val token = getCredentialedToken(clientId, clientSecret, null)
397+
val token = getCredentialedToken(clientId, clientSecret, null, options.json)
373398
SpotifyAppApi(
374399
clientId,
375400
clientSecret,
@@ -379,12 +404,13 @@ class SpotifyAppApiBuilder(
379404
false,
380405
options.retryWhenRateLimited,
381406
options.enableLogger,
382-
options.testTokenValidity
407+
options.testTokenValidity,
408+
options.json
383409
)
384410
} catch (e: CancellationException) {
385411
throw e
386412
} catch (e: Exception) {
387-
throw SpotifyAuthenticationException("Invalid credentials provided in the login process", e)
413+
throw SpotifyException.AuthenticationException("Invalid credentials provided in the login process", e)
388414
}
389415
}
390416
}
@@ -451,17 +477,19 @@ class SpotifyApiOptionsBuilder(
451477
var retryWhenRateLimited: Boolean = true,
452478
var enableLogger: Boolean = true,
453479
var testTokenValidity: Boolean = false,
454-
var enableAllOptions: Boolean = false
480+
var enableAllOptions: Boolean = false,
481+
var json: Json = stableJson
455482
) {
456483
fun build() =
457484
if (enableAllOptions)
458485
SpotifyApiOptions(
459486
true,
460487
200,
461-
automaticRefresh = false,
462-
retryWhenRateLimited = true,
463-
enableLogger = true,
464-
testTokenValidity = true
488+
false,
489+
true,
490+
true,
491+
true,
492+
json
465493
)
466494
else
467495
SpotifyApiOptions(
@@ -470,7 +498,8 @@ class SpotifyApiOptionsBuilder(
470498
automaticRefresh,
471499
retryWhenRateLimited,
472500
enableLogger,
473-
testTokenValidity
501+
testTokenValidity,
502+
json
474503
)
475504
}
476505

@@ -480,7 +509,8 @@ data class SpotifyApiOptions(
480509
var automaticRefresh: Boolean,
481510
var retryWhenRateLimited: Boolean,
482511
var enableLogger: Boolean,
483-
var testTokenValidity: Boolean
512+
var testTokenValidity: Boolean,
513+
var json: Json
484514
)
485515

486516
typealias SpotifyUtilities = SpotifyApiOptions

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import com.adamratzman.spotify.http.HttpResponse
2222
import com.adamratzman.spotify.http.SpotifyEndpoint
2323
import com.adamratzman.spotify.http.base64ByteEncode
2424
import com.adamratzman.spotify.models.AuthenticationError
25-
import com.adamratzman.spotify.models.SpotifyAuthenticationException
2625
import com.adamratzman.spotify.models.Token
2726
import com.adamratzman.spotify.models.TokenValidityResponse
2827
import com.adamratzman.spotify.models.serialization.toObject

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,7 @@ sealed class SpotifyException(message: String, cause: Throwable? = null) : Excep
3434
)
3535
}
3636

37-
class SpotifyParseException(message: String, cause: Throwable? = null) : SpotifyException(message, cause)
37+
class ParseException(message: String, cause: Throwable? = null) : SpotifyException(message, cause)
38+
39+
class AuthenticationException(message: String, cause: Throwable? = null) : SpotifyException(message, cause)
3840
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
8080
get(
8181
EndpointBuilder("/me/following/contains").with("type", "user")
8282
.with("ids", users.joinToString(",") { UserUri(it).id.encodeUrl() }).toString()
83-
).toList(Boolean.serializer().list, api)
83+
).toList(Boolean.serializer().list, api, json)
8484
}
8585
}
8686

@@ -115,7 +115,7 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
115115
get(
116116
EndpointBuilder("/me/following/contains").with("type", "artist")
117117
.with("ids", artists.joinToString(",") { ArtistUri(it).id.encodeUrl() }).toString()
118-
).toList(Boolean.serializer().list, api)
118+
).toList(Boolean.serializer().list, api, json)
119119
}
120120
}
121121

@@ -140,7 +140,7 @@ class ClientFollowingApi(api: SpotifyApi<*, *>) : FollowingApi(api) {
140140
"after",
141141
after
142142
).toString()
143-
).toCursorBasedPagingObject(Artist.serializer(), "artists", this)
143+
).toCursorBasedPagingObject(Artist.serializer(), "artists", this, json)
144144
}
145145
}
146146

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ClientLibraryApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
4646
get(
4747
EndpointBuilder("/me/tracks").with("limit", limit).with("offset", offset).with("market", market?.name)
4848
.toString()
49-
).toPagingObject(SavedTrack.serializer(), endpoint = this)
49+
).toPagingObject(SavedTrack.serializer(), endpoint = this, json = json)
5050
}
5151
}
5252

@@ -71,7 +71,7 @@ class ClientLibraryApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
7171
get(
7272
EndpointBuilder("/me/albums").with("limit", limit).with("offset", offset).with("market", market?.name)
7373
.toString()
74-
).toPagingObject(SavedAlbum.serializer(), endpoint = this)
74+
).toPagingObject(SavedAlbum.serializer(), endpoint = this, json = json)
7575
}
7676
}
7777

@@ -106,7 +106,7 @@ class ClientLibraryApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
106106
get(
107107
EndpointBuilder("/me/$type/contains").with("ids", ids.joinToString(",") { type.id(it).encodeUrl() })
108108
.toString()
109-
).toList(Boolean.serializer().list, api)
109+
).toList(Boolean.serializer().list, api, json)
110110
}
111111
}
112112

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class ClientPersonalizationApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
5858
get(
5959
EndpointBuilder("/me/top/artists").with("limit", limit).with("offset", offset)
6060
.with("time_range", timeRange).toString()
61-
).toPagingObject(Artist.serializer(), endpoint = this)
61+
).toPagingObject(Artist.serializer(), endpoint = this, json = json)
6262
}
6363
}
6464

@@ -90,7 +90,7 @@ class ClientPersonalizationApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
9090
get(
9191
EndpointBuilder("/me/top/tracks").with("limit", limit).with("offset", offset)
9292
.with("time_range", timeRange).toString()
93-
).toPagingObject(Track.serializer(), endpoint = this)
93+
).toPagingObject(Track.serializer(), endpoint = this, json = json)
9494
}
9595
}
9696
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class ClientPlayerApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
4242
*/
4343
fun getDevices(): SpotifyRestAction<List<Device>> {
4444
return toAction {
45-
get(EndpointBuilder("/me/player/devices").toString()).toInnerObject(Device.serializer().list, "devices")
45+
get(EndpointBuilder("/me/player/devices").toString()).toInnerObject(Device.serializer().list, "devices", json)
4646
}
4747
}
4848

@@ -55,7 +55,7 @@ class ClientPlayerApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
5555
return toAction {
5656
val obj = catch {
5757
get(EndpointBuilder("/me/player").toString())
58-
.toObject(CurrentlyPlayingContext.serializer(), api)
58+
.toObject(CurrentlyPlayingContext.serializer(), api, json)
5959
}
6060
if (obj?.timestamp == null) null else obj
6161
}
@@ -80,7 +80,7 @@ class ClientPlayerApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
8080
get(
8181
EndpointBuilder("/me/player/recently-played")
8282
.with("limit", limit).with("before", before).with("after", after).toString()
83-
).toCursorBasedPagingObject(PlayHistory.serializer(), endpoint = this)
83+
).toCursorBasedPagingObject(PlayHistory.serializer(), endpoint = this, json = json)
8484
}
8585
}
8686

@@ -94,7 +94,7 @@ class ClientPlayerApi(api: SpotifyApi<*, *>) : SpotifyEndpoint(api) {
9494
val obj =
9595
catch {
9696
get(EndpointBuilder("/me/player/currently-playing").toString())
97-
.toObject(CurrentlyPlayingObject.serializer(), api)
97+
.toObject(CurrentlyPlayingObject.serializer(), api, json)
9898
}
9999
if (obj?.timestamp == null) null else obj
100100
}

0 commit comments

Comments
 (0)