diff --git a/Cargo.toml b/Cargo.toml index 0f76768..40293ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,8 +35,8 @@ rand = "0.6.5" webbrowser = "0.5" [dependencies.rspotify] -git = "https://github.com/KoffeinFlummi/rspotify" -rev = "1a30afc" +git = "https://github.com/samrayleung/rspotify" +rev = "9d9cf7c" [dependencies.librespot] git = "https://github.com/librespot-org/librespot.git" diff --git a/src/album.rs b/src/album.rs index e45f6ee..9d5699b 100644 --- a/src/album.rs +++ b/src/album.rs @@ -14,13 +14,13 @@ use ui::album::AlbumView; #[derive(Clone, Deserialize, Serialize)] pub struct Album { - pub id: String, + pub id: Option, pub title: String, pub artists: Vec, pub artist_ids: Vec, pub year: String, pub cover_url: Option, - pub url: String, + pub url: Option, pub tracks: Option>, pub added_at: Option>, } @@ -31,14 +31,16 @@ impl Album { return; } - if let Some(fa) = spotify.full_album(&self.id) { - self.tracks = Some( - fa.tracks - .items - .iter() - .map(|st| Track::from_simplified_track(&st, &fa)) - .collect(), - ); + if let Some(ref album_id) = self.id { + if let Some(fa) = spotify.full_album(&album_id) { + self.tracks = Some( + fa.tracks + .items + .iter() + .map(|st| Track::from_simplified_track(&st, &fa)) + .collect(), + ); + } } } } @@ -49,8 +51,20 @@ impl From<&SimplifiedAlbum> for Album { id: sa.id.clone(), title: sa.name.clone(), artists: sa.artists.iter().map(|sa| sa.name.clone()).collect(), - artist_ids: sa.artists.iter().map(|sa| sa.id.clone()).collect(), - year: sa.release_date.split('-').next().unwrap().into(), + artist_ids: sa + .artists + .iter() + .filter(|a| a.id.is_some()) + .map(|sa| sa.id.clone().unwrap()) + .collect(), + year: sa + .release_date + .clone() + .unwrap_or_default() + .split('-') + .next() + .unwrap() + .into(), cover_url: sa.images.get(0).map(|i| i.url.clone()), url: sa.uri.clone(), tracks: None, @@ -70,13 +84,18 @@ impl From<&FullAlbum> for Album { ); Self { - id: fa.id.clone(), + id: Some(fa.id.clone()), title: fa.name.clone(), artists: fa.artists.iter().map(|sa| sa.name.clone()).collect(), - artist_ids: fa.artists.iter().map(|sa| sa.id.clone()).collect(), + artist_ids: fa + .artists + .iter() + .filter(|a| a.id.is_some()) + .map(|sa| sa.id.clone().unwrap()) + .collect(), year: fa.release_date.split('-').next().unwrap().into(), cover_url: fa.images.get(0).map(|i| i.url.clone()), - url: fa.uri.clone(), + url: Some(fa.uri.clone()), tracks, added_at: None, } @@ -101,7 +120,7 @@ impl fmt::Debug for Album { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "({} - {} ({}))", + "({} - {} ({:?}))", self.artists.join(", "), self.title, self.id @@ -117,9 +136,14 @@ impl ListItem for Album { .read() .unwrap() .iter() - .map(|t| t.id.clone()) + .filter(|t| t.id.is_some()) + .map(|t| t.id.clone().unwrap()) + .collect(); + let ids: Vec = tracks + .iter() + .filter(|t| t.id.is_some()) + .map(|t| t.id.clone().unwrap()) .collect(); - let ids: Vec = tracks.iter().map(|t| t.id.clone()).collect(); !ids.is_empty() && playing == ids } else { false diff --git a/src/artist.rs b/src/artist.rs index e3a6608..698bf2d 100644 --- a/src/artist.rs +++ b/src/artist.rs @@ -13,9 +13,9 @@ use ui::artist::ArtistView; #[derive(Clone, Deserialize, Serialize)] pub struct Artist { - pub id: String, + pub id: Option, pub name: String, - pub url: String, + pub url: Option, pub albums: Option>, pub tracks: Option>, pub is_followed: bool, @@ -24,9 +24,9 @@ pub struct Artist { impl Artist { pub fn new(id: String, name: String) -> Self { Self { - id, + id: Some(id), name, - url: "".into(), + url: None, albums: None, tracks: None, is_followed: false, @@ -41,20 +41,24 @@ impl Artist { return; } - if let Some(sas) = spotify.artist_albums(&self.id, 50, 0) { - let mut albums: Vec = Vec::new(); + if let Some(ref artist_id) = self.id { + if let Some(sas) = spotify.artist_albums(artist_id, 50, 0) { + let mut albums: Vec = Vec::new(); - for sa in sas.items { - if Some("appears_on".into()) == sa.album_group { - continue; + for sa in sas.items { + if Some("appears_on".into()) == sa.album_group { + continue; + } + + if let Some(album_id) = sa.id { + if let Some(fa) = spotify.full_album(&album_id).as_ref() { + albums.push(fa.into()); + } + } } - if let Some(fa) = spotify.full_album(&sa.id).as_ref() { - albums.push(fa.into()); - } + self.albums = Some(albums); } - - self.albums = Some(albums); } } @@ -91,9 +95,9 @@ impl From<&SimplifiedArtist> for Artist { impl From<&FullArtist> for Artist { fn from(fa: &FullArtist) -> Self { Self { - id: fa.id.clone(), + id: Some(fa.id.clone()), name: fa.name.clone(), - url: fa.uri.clone(), + url: Some(fa.uri.clone()), albums: None, tracks: None, is_followed: false, @@ -109,7 +113,7 @@ impl fmt::Display for Artist { impl fmt::Debug for Artist { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} ({})", self.name, self.id) + write!(f, "{} ({:?})", self.name, self.id) } } @@ -121,9 +125,14 @@ impl ListItem for Artist { .read() .unwrap() .iter() - .map(|t| t.id.clone()) + .filter(|t| t.id.is_some()) + .map(|t| t.id.clone().unwrap()) + .collect(); + let ids: Vec = tracks + .iter() + .filter(|t| t.id.is_some()) + .map(|t| t.id.clone().unwrap()) .collect(); - let ids: Vec = tracks.iter().map(|t| t.id.clone()).collect(); !ids.is_empty() && playing == ids } else { false diff --git a/src/library.rs b/src/library.rs index 859edd1..8809dfe 100644 --- a/src/library.rs +++ b/src/library.rs @@ -345,7 +345,7 @@ impl Library { artists.extend(page.items.iter().map(|fa| fa.into())); if page.next.is_some() { - last = Some(artists.last().unwrap().id.clone()); + last = artists.last().unwrap().id.clone(); } else { break; } @@ -369,7 +369,10 @@ impl Library { fn insert_artist(&self, id: &str, name: &str) { let mut artists = self.artists.write().unwrap(); - if !artists.iter().any(|a| a.id == id) { + if !artists + .iter() + .any(|a| a.id.clone().unwrap_or_default() == id) + { let mut artist = Artist::new(id.to_string(), name.to_string()); artist.tracks = Some(Vec::new()); artists.push(artist); @@ -402,7 +405,7 @@ impl Library { .items .iter() .enumerate() - .any(|(i, a)| a.album.id != store[i].id) + .any(|(i, a)| a.album.id != store[i].id.clone().unwrap_or_default()) { return; } @@ -501,7 +504,9 @@ impl Library { let index = if let Some(i) = lookup.get(artist_id).cloned() { i } else { - let i = artists.iter().position(|a| &a.id == artist_id); + let i = artists + .iter() + .position(|a| &a.id.clone().unwrap_or_default() == artist_id); lookup.insert(artist_id.clone(), i); i }; @@ -542,7 +547,13 @@ impl Library { if api && self .spotify - .current_user_saved_tracks_add(tracks.iter().map(|t| t.id.clone()).collect()) + .current_user_saved_tracks_add( + tracks + .iter() + .filter(|t| t.id.is_some()) + .map(|t| t.id.clone().unwrap()) + .collect(), + ) .is_none() { return; @@ -575,7 +586,13 @@ impl Library { if api && self .spotify - .current_user_saved_tracks_delete(tracks.iter().map(|t| t.id.clone()).collect()) + .current_user_saved_tracks_delete( + tracks + .iter() + .filter(|t| t.id.is_some()) + .map(|t| t.id.clone().unwrap()) + .collect(), + ) .is_none() { return; @@ -610,12 +627,14 @@ impl Library { return; } - if self - .spotify - .current_user_saved_albums_add(vec![album.id.clone()]) - .is_none() - { - return; + if let Some(ref album_id) = album.id { + if self + .spotify + .current_user_saved_albums_add(vec![album_id.clone()]) + .is_none() + { + return; + } } album.load_tracks(self.spotify.clone()); @@ -639,12 +658,14 @@ impl Library { return; } - if self - .spotify - .current_user_saved_albums_delete(vec![album.id.clone()]) - .is_none() - { - return; + if let Some(ref album_id) = album.id { + if self + .spotify + .current_user_saved_albums_delete(vec![album_id.clone()]) + .is_none() + { + return; + } } album.load_tracks(self.spotify.clone()); @@ -675,12 +696,14 @@ impl Library { return; } - if self - .spotify - .user_follow_artists(vec![artist.id.clone()]) - .is_none() - { - return; + if let Some(ref artist_id) = artist.id { + if self + .spotify + .user_follow_artists(vec![artist_id.clone()]) + .is_none() + { + return; + } } { @@ -704,12 +727,14 @@ impl Library { return; } - if self - .spotify - .user_unfollow_artists(vec![artist.id.clone()]) - .is_none() - { - return; + if let Some(ref artist_id) = artist.id { + if self + .spotify + .user_unfollow_artists(vec![artist_id.clone()]) + .is_none() + { + return; + } } { diff --git a/src/mpris.rs b/src/mpris.rs index 323c7b4..b828d4f 100644 --- a/src/mpris.rs +++ b/src/mpris.rs @@ -29,7 +29,7 @@ fn get_metadata(queue: Arc) -> HashMap>> { "mpris:trackid".to_string(), Variant(Box::new( track - .map(|t| format!("spotify:track:{}", t.id)) + .map(|t| format!("spotify:track:{}", t.id.clone().unwrap_or("0".to_string()))) .unwrap_or_default(), )), ); diff --git a/src/playlist.rs b/src/playlist.rs index 2f78428..02dddc0 100644 --- a/src/playlist.rs +++ b/src/playlist.rs @@ -23,9 +23,15 @@ impl ListItem for Playlist { .read() .unwrap() .iter() - .map(|t| t.id.clone()) + .filter(|t| t.id.is_some()) + .map(|t| t.id.clone().unwrap()) + .collect(); + let ids: Vec = self + .tracks + .iter() + .filter(|t| t.id.is_some()) + .map(|t| t.id.clone().unwrap()) .collect(); - let ids: Vec = self.tracks.iter().map(|t| t.id.clone()).collect(); !ids.is_empty() && playing == ids } diff --git a/src/spotify.rs b/src/spotify.rs index c5e0722..081f569 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -124,9 +124,13 @@ impl futures::Future for Worker { debug!("message received!"); match cmd { WorkerCommand::Load(track) => { - let id = SpotifyId::from_base62(&track.id).expect("could not parse id"); - self.play_task = Box::new(self.player.load(id, false, 0)); - info!("player loading track: {:?}", track); + if let Some(track_id) = &track.id { + let id = SpotifyId::from_base62(track_id).expect("could not parse id"); + self.play_task = Box::new(self.player.load(id, false, 0)); + info!("player loading track: {:?}", track); + } else { + self.events.send(Event::Player(PlayerEvent::FinishedTrack)); + } } WorkerCommand::Play => { self.player.play(); @@ -408,7 +412,11 @@ impl Spotify { pub fn overwrite_playlist(&self, id: &str, tracks: &[Track]) { // extract only track IDs - let mut tracks: Vec = tracks.iter().map(|track| track.id.clone()).collect(); + let mut tracks: Vec = tracks + .iter() + .filter(|track| track.id.is_some()) + .map(|track| track.id.clone().unwrap()) + .collect(); // we can only send 100 tracks per request let mut remainder = if tracks.len() > 100 { diff --git a/src/track.rs b/src/track.rs index 97dd634..1267e3b 100644 --- a/src/track.rs +++ b/src/track.rs @@ -13,7 +13,7 @@ use traits::{ListItem, ViewExt}; #[derive(Clone, Deserialize, Serialize)] pub struct Track { - pub id: String, + pub id: Option, pub title: String, pub track_number: u32, pub disc_number: i32, @@ -21,7 +21,7 @@ pub struct Track { pub artists: Vec, pub artist_ids: Vec, pub album: String, - pub album_id: String, + pub album_id: Option, pub album_artists: Vec, pub cover_url: String, pub url: String, @@ -38,7 +38,8 @@ impl Track { let artist_ids = track .artists .iter() - .map(|ref artist| artist.id.clone()) + .filter(|a| a.id.is_some()) + .map(|ref artist| artist.id.clone().unwrap()) .collect::>(); let album_artists = album .artists @@ -60,7 +61,7 @@ impl Track { artists, artist_ids, album: album.name.clone(), - album_id: album.id.clone(), + album_id: Some(album.id.clone()), album_artists, cover_url, url: track.uri.clone(), @@ -85,7 +86,8 @@ impl From<&FullTrack> for Track { let artist_ids = track .artists .iter() - .map(|ref artist| artist.id.clone()) + .filter(|a| a.id.is_some()) + .map(|ref artist| artist.id.clone().unwrap()) .collect::>(); let album_artists = track .album @@ -135,7 +137,7 @@ impl fmt::Debug for Track { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "({} - {} ({}))", + "({} - {} ({:?}))", self.artists.join(", "), self.title, self.id @@ -190,7 +192,10 @@ impl ListItem for Track { fn album(&self, queue: Arc) -> Option { let spotify = queue.get_spotify(); - spotify.album(&self.album_id).map(|ref fa| fa.into()) + match self.album_id { + Some(ref album_id) => spotify.album(&album_id).map(|ref fa| fa.into()), + None => None, + } } fn artist(&self) -> Option { diff --git a/src/ui/artist.rs b/src/ui/artist.rs index 661d596..e7e8038 100644 --- a/src/ui/artist.rs +++ b/src/ui/artist.rs @@ -37,8 +37,10 @@ impl ArtistView { let spotify = spotify.clone(); let id = artist.id.clone(); thread::spawn(move || { - if let Some(tracks) = spotify.artist_top_tracks(id) { - top_tracks.write().unwrap().extend(tracks); + if let Some(id) = id { + if let Some(tracks) = spotify.artist_top_tracks(id) { + top_tracks.write().unwrap().extend(tracks); + } } }); } @@ -49,8 +51,10 @@ impl ArtistView { let spotify = spotify.clone(); let id = artist.id.clone(); thread::spawn(move || { - if let Some(artists) = spotify.artist_related_artists(id) { - related.write().unwrap().extend(artists); + if let Some(id) = id { + if let Some(artists) = spotify.artist_related_artists(id) { + related.write().unwrap().extend(artists); + } } }); }