@@ -24,15 +24,20 @@ private fun String.matchType(type: String, allowColon: Boolean): String? {
24
24
return match[1 ].takeIf { it.isNotBlank() || match[2 ].isEmpty() } ? : match[2 ].takeIf { it.isNotEmpty() }
25
25
}
26
26
27
+ private fun String.matchesUserCollectionUri () = this .matches(" ^spotify:user:([^:]+):collection" .toRegex())
28
+
27
29
private fun String.add (type : String , allowColon : Boolean ): String {
28
- this .matchType(type, allowColon)?.let {
30
+ if (type == UserCollectionUriType && matchesUserCollectionUri()) return this
31
+ else this .matchType(type, allowColon)?.let {
29
32
return " spotify:$type :${it.trim()} "
30
33
}
31
34
throw SpotifyUriException (" Illegal Spotify ID/URI: '$this ' isn't convertible to '$type ' uri" )
32
35
}
33
36
34
37
private fun String.remove (type : String , allowColon : Boolean ): String {
35
- this .matchType(type, allowColon)?.let {
38
+ println (type)
39
+ if (type == UserCollectionUriType && matchesUserCollectionUri()) return " collection"
40
+ else this .matchType(type, allowColon)?.let {
36
41
return it.trim()
37
42
}
38
43
throw SpotifyUriException (" Illegal Spotify ID/URI: '$this ' isn't convertible to '$type ' id" )
@@ -112,7 +117,7 @@ public sealed class SpotifyUri(input: String, public val type: String, allowColo
112
117
val constructors = listOf (
113
118
::ArtistUri ,
114
119
PlayableUri .Companion ::invoke,
115
- ImmutableCollectionUri .Companion ::invoke,
120
+ CollectionUri .Companion ::invoke,
116
121
::UserUri ,
117
122
::PlaylistUri
118
123
)
@@ -178,7 +183,7 @@ public sealed class CollectionUri(input: String, type: String, allowColon: Boole
178
183
* Creates an abstract [CollectionUri] of given input. Prefers [PlaylistUri] if the input is ambiguous.
179
184
*/
180
185
public operator fun invoke (input : String ): CollectionUri {
181
- val constructors = listOf (::PlaylistUri , ImmutableCollectionUri .Companion ::invoke)
186
+ val constructors = listOf (::PlaylistUri , :: UserCollectionUri , ImmutableCollectionUri .Companion ::invoke)
182
187
for (ctor in constructors) {
183
188
safeInitiate(input, ctor)?.also { return it }
184
189
}
@@ -372,9 +377,24 @@ public object ShowUriSerializer : KSerializer<ShowUri> by SimpleUriSerializer(::
372
377
*/
373
378
public fun String.toShowUri (): ShowUri = ShowUri (this )
374
379
380
+ private const val UserCollectionUriType = " UserCollectionUri"
381
+
382
+ /* *
383
+ * Represents a Spotify **User Collection URI** URI (spotify:user:XXXX:collection), parsed from either a Spotify ID or taken from an endpoint.
384
+ * It appears that this URI corresponds to the user's saved tracks collection in their library.
385
+ */
386
+ @Serializable(with = UserCollectionUriSerializer ::class )
387
+ public class UserCollectionUri (input : String ) : CollectionUri(input, UserCollectionUriType ), ContextUri
388
+ public object UserCollectionUriSerializer : KSerializer<UserCollectionUri> by SimpleUriSerializer(::UserCollectionUri )
389
+
375
390
/* *
376
- * Represents a Spotify **Context** URI (one of [AlbumUri], [ArtistUri], [PlaylistUri], or [ShowUri]),
377
- */
391
+ * Convert a show id or uri string to a [ShowUri] object
392
+ */
393
+ public fun String.toUserCollectionUri (): UserCollectionUri = UserCollectionUri (this )
394
+
395
+ /* *
396
+ * Represents a Spotify **Context** URI (one of [AlbumUri], [ArtistUri], [PlaylistUri], [UserCollectionUri], or [ShowUri]),
397
+ */
378
398
@Serializable(with = ContextUriSerializer ::class )
379
399
public interface ContextUri : ISpotifyUri {
380
400
public companion object {
0 commit comments