1
1
/* Spotify Web API - Kotlin Wrapper; MIT License, 2019; Original author: Adam Ratzman */
2
2
package com.adamratzman.spotify.models
3
3
4
+ import kotlinx.serialization.Decoder
5
+ import kotlinx.serialization.Encoder
6
+ import kotlinx.serialization.KSerializer
7
+ import kotlinx.serialization.SerialDescriptor
4
8
import kotlinx.serialization.Serializable
5
- import kotlinx.serialization.modules.SerializersModule
6
-
7
- internal val spotifyUriSerializersModule = SerializersModule {
8
- polymorphic(SpotifyUri ::class ) {
9
- AlbumUri ::class with AlbumUri .serializer()
10
- ArtistUri ::class with ArtistUri .serializer()
11
- TrackUri ::class with TrackUri .serializer()
12
- LocalTrackUri ::class with LocalTrackUri .serializer()
13
- UserUri ::class with UserUri .serializer()
14
- PlaylistUri ::class with PlaylistUri .serializer()
15
- }
16
- }
9
+ import kotlinx.serialization.Serializer
10
+ import kotlinx.serialization.internal.StringDescriptor
17
11
18
12
private fun String.matchType (type : String ): String? {
19
13
val typeRegex = " ^spotify:(?:.*:)*$type :([^:]+)(?::.*)*$|^([^:]+)$" .toRegex()
@@ -35,26 +29,27 @@ private fun String.remove(type: String): String {
35
29
throw SpotifyUriException (" Illegal Spotify ID/URI: '$this ' isn't convertible to '$type ' id" )
36
30
}
37
31
32
+ private class SimpleUriSerializer <T : SpotifyUri >(val ctor : (String ) -> T ) : KSerializer<T> {
33
+ override val descriptor: SerialDescriptor = StringDescriptor
34
+ override fun deserialize (decoder : Decoder ): T = ctor(decoder.decodeString())
35
+ override fun serialize (encoder : Encoder , obj : T ) = encoder.encodeString(obj.uri)
36
+ }
37
+
38
38
/* *
39
39
* Represents a Spotify URI, parsed from either a Spotify ID or taken from an endpoint.
40
40
*
41
41
* @property uri retrieve this URI as a string
42
42
* @property id representation of this uri as an id
43
43
*/
44
44
@Serializable
45
- sealed class SpotifyUri (val input : String , val type : UriType ) {
45
+ sealed class SpotifyUri (input : String , type : UriType ) {
46
46
val uri: String
47
47
val id: String
48
48
49
49
init {
50
50
input.replace(" " , " " ).let {
51
- if (input == " spotify:user:" ) {
52
- this .uri = input
53
- this .id = input
54
- } else {
55
- this .uri = it.add(type.toString())
56
- this .id = it.remove(type.toString())
57
- }
51
+ this .uri = it.add(type.toString())
52
+ this .id = it.remove(type.toString())
58
53
}
59
54
}
60
55
@@ -84,49 +79,89 @@ sealed class SpotifyUri(val input: String, val type: UriType) {
84
79
override fun toString () = typeStr
85
80
}
86
81
87
- companion object {
82
+ @Serializer(forClass = SpotifyUri ::class )
83
+ companion object : KSerializer <SpotifyUri > {
88
84
fun isUriType (uri : String , type : UriType ) = uri.matchType(type.toString()) != null
85
+
86
+ override val descriptor: SerialDescriptor = StringDescriptor
87
+ override fun deserialize (decoder : Decoder ): SpotifyUri = SpotifyUri (decoder.decodeString())
88
+ override fun serialize (encoder : Encoder , obj : SpotifyUri ) = encoder.encodeString(obj.uri)
89
+
90
+ private inline fun <T : SpotifyUri > safeInitiate (uri : String , ctor : (String ) -> T ): T ? {
91
+ return try {
92
+ ctor(uri).takeIf { it.uri == uri }
93
+ } catch (e: SpotifyUriException ) {
94
+ null
95
+ }
96
+ }
97
+
98
+ operator fun invoke (input : String ): SpotifyUri {
99
+ val constructors = listOf (::AlbumUri , ::ArtistUri , ::TrackUri , ::UserUri , ::PlaylistUri )
100
+ for (ctor in constructors) {
101
+ safeInitiate(input, ctor)?.also { return it }
102
+ }
103
+
104
+ throw SpotifyUriException (" Illegal Spotify ID/URI: '$input ' isn't convertible to any arbitrary id" )
105
+ }
89
106
}
90
107
}
91
108
92
109
/* *
93
110
* Represents a Spotify **Album** URI, parsed from either a Spotify ID or taken from an endpoint.
94
111
*/
95
112
@Serializable
96
- class AlbumUri (private val inputString : String ) : SpotifyUri(inputString, UriType .ALBUM )
113
+ class AlbumUri (val input : String ) : SpotifyUri(input, UriType .ALBUM ) {
114
+ @Serializer(forClass = AlbumUri ::class )
115
+ companion object : KSerializer <AlbumUri > by SimpleUriSerializer (::AlbumUri )
116
+ }
97
117
typealias AlbumURI = AlbumUri
98
118
99
119
/* *
100
120
* Represents a Spotify **Artist** URI, parsed from either a Spotify ID or taken from an endpoint.
101
121
*/
102
122
@Serializable
103
- class ArtistUri (private val inputString : String ) : SpotifyUri(inputString, UriType .ARTIST )
123
+ class ArtistUri (val input : String ) : SpotifyUri(input, UriType .ARTIST ) {
124
+ @Serializer(forClass = ArtistUri ::class )
125
+ companion object : KSerializer <ArtistUri > by SimpleUriSerializer (::ArtistUri )
126
+ }
104
127
typealias ArtistURI = ArtistUri
105
128
106
129
/* *
107
130
* Represents a Spotify **Track** URI, parsed from either a Spotify ID or taken from an endpoint.
108
131
*/
109
132
@Serializable
110
- class TrackUri (private val inputString : String ) : SpotifyUri(inputString, UriType .TRACK )
133
+ class TrackUri (val input : String ) : SpotifyUri(input, UriType .TRACK ) {
134
+ @Serializer(forClass = TrackUri ::class )
135
+ companion object : KSerializer <TrackUri > by SimpleUriSerializer (::TrackUri )
136
+ }
111
137
typealias TrackURI = TrackUri
112
138
113
139
/* *
114
140
* Represents a Spotify **User** URI, parsed from either a Spotify ID or taken from an endpoint.
115
141
*/
116
142
@Serializable
117
- class UserUri (private val inputString : String ) : SpotifyUri(inputString, UriType .USER )
143
+ class UserUri (val input : String ) : SpotifyUri(input, UriType .USER ) {
144
+ @Serializer(forClass = UserUri ::class )
145
+ companion object : KSerializer <UserUri > by SimpleUriSerializer (::UserUri )
146
+ }
118
147
typealias UserURI = UserUri
119
148
120
149
/* *
121
150
* Represents a Spotify **Playlist** URI, parsed from either a Spotify ID or taken from an endpoint.
122
151
*/
123
152
@Serializable
124
- class PlaylistUri (private val inputString : String ) : SpotifyUri(inputString, UriType .PLAYLIST )
153
+ class PlaylistUri (val input : String ) : SpotifyUri(input, UriType .PLAYLIST ) {
154
+ @Serializer(forClass = PlaylistUri ::class )
155
+ companion object : KSerializer <PlaylistUri > by SimpleUriSerializer (::PlaylistUri )
156
+ }
125
157
typealias PlaylistURI = PlaylistUri
126
158
127
159
/* *
128
160
* Represents a Spotify **local track** URI
129
161
*/
130
162
@Serializable
131
- class LocalTrackUri (private val inputString : String ) : SpotifyUri(inputString, UriType .LOCAL_TRACK )
163
+ class LocalTrackUri (val input : String ) : SpotifyUri(input, UriType .LOCAL_TRACK ) {
164
+ @Serializer(forClass = LocalTrackUri ::class )
165
+ companion object : KSerializer <LocalTrackUri > by SimpleUriSerializer (::LocalTrackUri )
166
+ }
132
167
typealias LocalTrackURI = LocalTrackUri
0 commit comments