1
1
use crate :: { Error , SpotifyId } ;
2
- use std:: { borrow:: Cow , fmt} ;
2
+ use std:: { borrow:: Cow , fmt, str :: FromStr , time :: Duration } ;
3
3
use thiserror:: Error ;
4
4
5
5
use librespot_protocol as protocol;
@@ -65,7 +65,10 @@ pub enum SpotifyUri {
65
65
impl SpotifyUri {
66
66
/// Returns whether this `SpotifyUri` is for a playable audio item, if known.
67
67
pub fn is_playable ( & self ) -> bool {
68
- matches ! ( self , SpotifyUri :: Episode { .. } | SpotifyUri :: Track { .. } )
68
+ matches ! (
69
+ self ,
70
+ SpotifyUri :: Episode { .. } | SpotifyUri :: Track { .. } | SpotifyUri :: Local { .. }
71
+ )
69
72
}
70
73
71
74
/// Gets the item type of this URI as a static string
@@ -147,6 +150,7 @@ impl SpotifyUri {
147
150
} ;
148
151
149
152
let name = parts. next ( ) . ok_or ( SpotifyUriError :: InvalidFormat ) ?;
153
+
150
154
match item_type {
151
155
SPOTIFY_ITEM_TYPE_ALBUM => Ok ( Self :: Album {
152
156
id : SpotifyId :: from_base62 ( name) ?,
@@ -167,12 +171,23 @@ impl SpotifyUri {
167
171
SPOTIFY_ITEM_TYPE_TRACK => Ok ( Self :: Track {
168
172
id : SpotifyId :: from_base62 ( name) ?,
169
173
} ) ,
170
- SPOTIFY_ITEM_TYPE_LOCAL => Ok ( Self :: Local {
171
- artist : "unimplemented" . to_owned ( ) ,
172
- album_title : "unimplemented" . to_owned ( ) ,
173
- track_title : "unimplemented" . to_owned ( ) ,
174
- duration : Default :: default ( ) ,
175
- } ) ,
174
+ SPOTIFY_ITEM_TYPE_LOCAL => {
175
+ let artist = name;
176
+ let album_title = parts. next ( ) . unwrap_or_default ( ) ;
177
+ // enforce track_title exists; spotify:local:::<duration> is a silly URI
178
+ let track_title = parts. next ( ) . ok_or ( SpotifyUriError :: InvalidFormat ) ?;
179
+ let duration_secs = parts
180
+ . next ( )
181
+ . and_then ( |f| u64:: from_str ( f) . ok ( ) )
182
+ . ok_or ( SpotifyUriError :: InvalidFormat ) ?;
183
+
184
+ Ok ( Self :: Local {
185
+ artist : artist. to_owned ( ) ,
186
+ album_title : album_title. to_owned ( ) ,
187
+ track_title : track_title. to_owned ( ) ,
188
+ duration : Duration :: from_secs ( duration_secs) ,
189
+ } )
190
+ }
176
191
_ => Ok ( Self :: Unknown {
177
192
kind : item_type. to_owned ( ) . into ( ) ,
178
193
id : name. to_owned ( ) ,
@@ -533,15 +548,33 @@ mod tests {
533
548
534
549
#[ test]
535
550
fn from_local_uri ( ) {
536
- let actual = SpotifyUri :: from_uri ( "spotify:local:xyz:123" ) . unwrap ( ) ;
551
+ let actual = SpotifyUri :: from_uri (
552
+ "spotify:local:David+Wise:Donkey+Kong+Country%3A+Tropical+Freeze:Snomads+Island:127" ,
553
+ )
554
+ . unwrap ( ) ;
555
+
556
+ assert_eq ! (
557
+ actual,
558
+ SpotifyUri :: Local {
559
+ artist: "David+Wise" . to_owned( ) ,
560
+ album_title: "Donkey+Kong+Country%3A+Tropical+Freeze" . to_owned( ) ,
561
+ track_title: "Snomads+Island" . to_owned( ) ,
562
+ duration: Duration :: from_secs( 127 ) ,
563
+ }
564
+ ) ;
565
+ }
566
+
567
+ #[ test]
568
+ fn from_local_uri_missing_fields ( ) {
569
+ let actual = SpotifyUri :: from_uri ( "spotify:local:::Snomads+Island:127" ) . unwrap ( ) ;
537
570
538
571
assert_eq ! (
539
572
actual,
540
573
SpotifyUri :: Local {
541
- artist: "unimplemented " . to_owned( ) ,
542
- album_title: "unimplemented " . to_owned( ) ,
543
- track_title: "unimplemented " . to_owned( ) ,
544
- duration: Default :: default ( ) ,
574
+ artist: "" . to_owned( ) ,
575
+ album_title: "" . to_owned( ) ,
576
+ track_title: "Snomads+Island " . to_owned( ) ,
577
+ duration: Duration :: from_secs ( 127 ) ,
545
578
}
546
579
) ;
547
580
}
0 commit comments