@@ -79,7 +79,8 @@ sealed class SpotifyApi<T : SpotifyApi<T, B>, B : ISpotifyApiBuilder<T, B>>(
79
79
var defaultLimit : Int ,
80
80
var allowBulkRequests : Boolean ,
81
81
var requestTimeoutMillis : Long? ,
82
- var json : Json
82
+ var json : Json ,
83
+ var refreshTokenProducer : suspend (SpotifyApi <* ,* >) -> Token
83
84
) {
84
85
var useCache = useCache
85
86
set(value) {
@@ -232,7 +233,7 @@ sealed class SpotifyApi<T : SpotifyApi<T, B>, B : ISpotifyApiBuilder<T, B>>(
232
233
* @return The old access token if refresh was successful
233
234
* @throws BadRequestException if refresh fails
234
235
*/
235
- abstract suspend fun suspendRefreshToken (): Token
236
+ suspend fun suspendRefreshToken () = refreshTokenProducer( this ). apply { this @SpotifyApi.token = this }
236
237
237
238
companion object {
238
239
/*
@@ -301,7 +302,8 @@ class SpotifyAppApi internal constructor(
301
302
defaultLimit : Int ,
302
303
allowBulkRequests : Boolean ,
303
304
requestTimeoutMillis : Long? ,
304
- json : Json
305
+ json : Json ,
306
+ refreshTokenProducer : (suspend (GenericSpotifyApi ) -> Token )?
305
307
) : SpotifyApi<SpotifyAppApi, SpotifyAppApiBuilder>(
306
308
clientId,
307
309
clientSecret,
@@ -315,7 +317,8 @@ class SpotifyAppApi internal constructor(
315
317
defaultLimit,
316
318
allowBulkRequests,
317
319
requestTimeoutMillis,
318
- json
320
+ json,
321
+ refreshTokenProducer ? : defaultAppApiTokenRefreshProducer
319
322
) {
320
323
constructor (
321
324
clientId: String ,
@@ -335,7 +338,8 @@ class SpotifyAppApi internal constructor(
335
338
options.defaultLimit,
336
339
options.allowBulkRequests,
337
340
options.requestTimeoutMillis,
338
- options.json
341
+ options.json,
342
+ options.refreshTokenProducer
339
343
)
340
344
341
345
override val search: SearchApi = SearchApi (this )
@@ -359,15 +363,6 @@ class SpotifyAppApi internal constructor(
359
363
*/
360
364
override val following: FollowingApi = FollowingApi (this )
361
365
362
- override suspend fun suspendRefreshToken (): Token {
363
- require(clientId != null && clientSecret != null ) { " Either the client id or the client secret is not set" }
364
- val currentToken = this .token
365
-
366
- token = getCredentialedToken(clientId, clientSecret, this , json)
367
-
368
- return currentToken
369
- }
370
-
371
366
override val endpoints: List <SpotifyEndpoint >
372
367
get() = listOf (
373
368
search,
@@ -394,6 +389,14 @@ class SpotifyAppApi internal constructor(
394
389
395
390
useCache = this @SpotifyAppApi.useCache
396
391
}
392
+
393
+ companion object {
394
+ private val defaultAppApiTokenRefreshProducer: suspend (SpotifyApi <* ,* >) -> Token = { api ->
395
+ require(api.clientId != null && api.clientSecret != null ) { " Either the client id or the client secret is not set" }
396
+
397
+ getCredentialedToken(api.clientId, api.clientSecret, api, api.json)
398
+ }
399
+ }
397
400
}
398
401
399
402
/* *
@@ -414,7 +417,8 @@ open class SpotifyClientApi internal constructor(
414
417
defaultLimit : Int ,
415
418
allowBulkRequests : Boolean ,
416
419
requestTimeoutMillis : Long? ,
417
- json : Json
420
+ json : Json ,
421
+ refreshTokenProducer : (suspend (SpotifyApi <* , * >) -> Token )?
418
422
) : SpotifyApi<SpotifyClientApi, SpotifyClientApiBuilder>(
419
423
clientId,
420
424
clientSecret,
@@ -428,7 +432,8 @@ open class SpotifyClientApi internal constructor(
428
432
defaultLimit,
429
433
allowBulkRequests,
430
434
requestTimeoutMillis,
431
- json
435
+ json,
436
+ refreshTokenProducer ? : defaultClientApiTokenRefreshProducer
432
437
) {
433
438
constructor (
434
439
clientId: String ,
@@ -450,7 +455,8 @@ open class SpotifyClientApi internal constructor(
450
455
options.defaultLimit,
451
456
options.allowBulkRequests,
452
457
options.requestTimeoutMillis,
453
- options.json
458
+ options.json,
459
+ options.refreshTokenProducer
454
460
)
455
461
456
462
override val albums: AlbumApi = AlbumApi (this )
@@ -541,44 +547,6 @@ open class SpotifyClientApi internal constructor(
541
547
runExecutableFunctions = false
542
548
}
543
549
544
- override suspend fun suspendRefreshToken (): Token {
545
- require(clientId != null && clientSecret != null ) { " Either the client id or the client secret is not set" }
546
-
547
- val currentToken = this .token
548
-
549
- val response = executeTokenRequest(
550
- HttpConnection (
551
- " https://accounts.spotify.com/api/token" ,
552
- HttpRequestMethod .POST ,
553
- mapOf (
554
- " grant_type" to " refresh_token" ,
555
- " refresh_token" to token.refreshToken
556
- ),
557
- null ,
558
- " application/x-www-form-urlencoded" ,
559
- listOf (),
560
- this
561
- ), clientId, clientSecret
562
- )
563
-
564
- if (response.responseCode / 200 == 1 ) {
565
- val tempToken = response.body.toObject(Token .serializer(), this , json)
566
- this .token = tempToken.copy(
567
- refreshToken = tempToken.refreshToken ? : this .token.refreshToken,
568
- scopeString = tempToken.scopeString
569
- )
570
-
571
- logger.logInfo(" Successfully refreshed the Spotify token" )
572
- return currentToken
573
- } else throw BadRequestException (
574
- response.body.toObject(
575
- AuthenticationError .serializer(),
576
- this ,
577
- json
578
- )
579
- )
580
- }
581
-
582
550
override val endpoints: List <SpotifyEndpoint >
583
551
get() = listOf (
584
552
search,
@@ -639,6 +607,40 @@ open class SpotifyClientApi internal constructor(
639
607
else ! isTokenValid(false ).isValid &&
640
608
token.scopes?.contains(scope) == true &&
641
609
scopes.all { token.scopes?.contains(it) == true }
610
+
611
+ companion object {
612
+ private val defaultClientApiTokenRefreshProducer: suspend (SpotifyApi <* ,* >) -> Token = { api ->
613
+ require(api.clientId != null && api.clientSecret != null ) { " Either the client id or the client secret is not set" }
614
+
615
+ val currentToken = api.token
616
+
617
+ val response = executeTokenRequest(
618
+ HttpConnection (
619
+ " https://accounts.spotify.com/api/token" ,
620
+ HttpRequestMethod .POST ,
621
+ mapOf (
622
+ " grant_type" to " refresh_token" ,
623
+ " refresh_token" to currentToken.refreshToken
624
+ ),
625
+ null ,
626
+ " application/x-www-form-urlencoded" ,
627
+ listOf (),
628
+ api
629
+ ), api.clientId, api.clientSecret
630
+ )
631
+
632
+ if (response.responseCode / 200 == 1 ) {
633
+ api.logger.logInfo(" Successfully refreshed the Spotify token" )
634
+ response.body.toObject(Token .serializer(), api, api.json)
635
+ } else throw BadRequestException (
636
+ response.body.toObject(
637
+ AuthenticationError .serializer(),
638
+ api,
639
+ api.json
640
+ )
641
+ )
642
+ }
643
+ }
642
644
}
643
645
644
646
/* *
@@ -673,12 +675,9 @@ class SpotifyImplicitGrantApi(
673
675
defaultLimit,
674
676
allowBulkRequests,
675
677
requestTimeoutMillis,
676
- json
677
- ) {
678
- override suspend fun suspendRefreshToken (): Token {
679
- throw IllegalStateException (" You cannot refresh an implicit grant access token!" )
680
- }
681
- }
678
+ json,
679
+ { throw IllegalStateException ("You cannot refresh an implicit grant access token!") }
680
+ )
682
681
683
682
@Deprecated(" API name has been updated for kotlin convention consistency" , ReplaceWith (" SpotifyApi" ))
684
683
typealias SpotifyAPI <T , B > = SpotifyApi <T , B >
@@ -687,6 +686,8 @@ typealias SpotifyClientAPI = SpotifyClientApi
687
686
@Deprecated(" API name has been updated for kotlin convention consistency" , ReplaceWith (" SpotifyAppApi" ))
688
687
typealias SpotifyAppAPI = SpotifyAppApi
689
688
689
+ typealias GenericSpotifyApi = SpotifyApi <* , * >
690
+
690
691
/* *
691
692
*
692
693
* Get an application token (can only access public methods) that can be used to instantiate a new [SpotifyAppApi]
0 commit comments