diff --git a/Cargo.lock b/Cargo.lock index cd6a96a6..c9eeb00e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,7 +150,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -161,7 +161,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1320,7 +1320,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1492,7 +1492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1843,7 +1843,7 @@ dependencies = [ "gobject-sys", "libc", "system-deps", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4391,7 +4391,7 @@ dependencies = [ "itertools 0.14.0", "kasuari", "lru", - "strum 0.27.2", + "strum", "thiserror 2.0.18", "unicode-segmentation", "unicode-truncate", @@ -4439,7 +4439,7 @@ dependencies = [ "itertools 0.14.0", "line-clipping", "ratatui-core", - "strum 0.27.2", + "strum", "time", "unicode-segmentation", "unicode-width", @@ -4699,9 +4699,9 @@ dependencies = [ [[package]] name = "rspotify" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e4f3254b449534ab3891331881d922d50ec36bd07c155147253a747fa5d475" +checksum = "1e731e399d4d7d7874e81d2ea1438fd5cdcb94090f58fb699fecaa2a042b2e7c" dependencies = [ "async-stream", "async-trait", @@ -4709,7 +4709,7 @@ dependencies = [ "chrono", "dotenvy", "futures", - "getrandom 0.2.17", + "getrandom 0.3.4", "log", "maybe-async", "rspotify-http", @@ -4725,9 +4725,9 @@ dependencies = [ [[package]] name = "rspotify-http" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed8a6b6d3cfea3040a2436e02366e5cb8d84f7658667be7075f6ed1cc64360da" +checksum = "82de318f57084b084779e4111f1de982380b67355985a0cf636630b5af61bb2e" dependencies = [ "async-trait", "log", @@ -4739,21 +4739,21 @@ dependencies = [ [[package]] name = "rspotify-macros" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559fad82b639297c093c5cc8ef406001dd0cb55cd9f5125a8fb40310e38b95d9" +checksum = "7f1fcd8df7d47c14f3cb46634f4a61506b303b305077e8d26ba19d8b7d353b0d" [[package]] name = "rspotify-model" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd00345ab89d2dd8059f0d0c168a6b0f858099795d7e318554411303b827d95" +checksum = "c1f55c05fbb7a22d50438457228c5b64c1b9a9476395abc2142c883ccd92ee1a" dependencies = [ "chrono", "enum_dispatch", "serde", "serde_json", - "strum 0.26.3", + "strum", "thiserror 2.0.18", ] @@ -4815,7 +4815,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5330,35 +5330,13 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros 0.26.4", -] - [[package]] name = "strum" version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ - "strum_macros 0.27.2", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", + "strum_macros", ] [[package]] @@ -5588,7 +5566,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix 1.1.3", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5955,7 +5933,7 @@ checksum = "97505cbb8633edb0f727724b72a71dec4b810499cdbda7c10727b57e83581950" dependencies = [ "colorgrad", "ratatui-core", - "strum 0.27.2", + "strum", ] [[package]] @@ -6450,7 +6428,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4e0ec717..d97895fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ exclude = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rspotify = { version = "0.14", default-features = false, features = ["cli", "env-file", "client-reqwest", "reqwest-rustls-tls"] } +rspotify = { version = "0.16", default-features = false, features = ["cli", "env-file", "client-reqwest", "reqwest-rustls-tls"] } ratatui = { version = "0.30", features = ["crossterm", "layout-cache"], default-features = false } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/cli/cli_app.rs b/src/cli/cli_app.rs index 073079a0..67556b92 100644 --- a/src/cli/cli_app.rs +++ b/src/cli/cli_app.rs @@ -87,6 +87,7 @@ impl CliApp { "https://open.spotify.com/episode/{}", episode.id.id() )), + _ => Err(anyhow!("unknown playable item type")), } } else { Err(anyhow!( @@ -115,6 +116,7 @@ impl CliApp { "https://open.spotify.com/show/{}", episode.show.id.id() )), + _ => Err(anyhow!("unknown playable item type")), } } else { Err(anyhow!( @@ -314,6 +316,7 @@ impl CliApp { let duration = match item { PlayableItem::Track(track) => track.duration.num_milliseconds() as u32, PlayableItem::Episode(episode) => episode.duration.num_milliseconds() as u32, + _ => return Err(anyhow!("unknown playable item type")), }; (ms.num_milliseconds() as u32, duration) @@ -368,6 +371,7 @@ impl CliApp { Some(i) => match i { PlayableItem::Track(t) => t.id.ok_or_else(|| anyhow!("item has no id")), PlayableItem::Episode(_) => Err(anyhow!("saving episodes not yet implemented")), + _ => Err(anyhow!("unknown playable item type")), }, None => Err(anyhow!("no item playing")), }?; @@ -469,6 +473,7 @@ impl CliApp { ))); hs } + _ => return Err(anyhow!("unknown playable item type")), }; hs.push(Format::Device(context.device.name)); @@ -487,7 +492,7 @@ impl CliApp { if let Ok(playlist_id) = rspotify::model::idtypes::PlaylistId::from_id(id_str) { match self.net.spotify.playlist(playlist_id, None, None).await { Ok(p) => { - let num = p.tracks.total; + let num = p.items.total; Some(thread_rng().gen_range(0..num) as usize) } Err(e) => { diff --git a/src/cli/util.rs b/src/cli/util.rs index 6bd499f3..3c9e71b5 100644 --- a/src/cli/util.rs +++ b/src/cli/util.rs @@ -218,17 +218,17 @@ impl Format { } FormatType::Show(r) => { let uri = r.id.uri(); - vec![ - Self::Artist(r.publisher), - Self::Show(r.name), - Self::Uri(uri), - ] + #[allow(deprecated)] + let publisher = r.publisher; + vec![Self::Artist(publisher), Self::Show(r.name), Self::Uri(uri)] } FormatType::Episode(e) => { let uri = e.id.uri(); + #[allow(deprecated)] + let publisher = e.show.publisher.clone(); vec![ Self::Show(e.show.name), - Self::Artist(e.show.publisher), + Self::Artist(publisher), Self::Track(e.name), Self::Uri(uri), ] diff --git a/src/core/app.rs b/src/core/app.rs index 2fdd8b19..8f5d522d 100644 --- a/src/core/app.rs +++ b/src/core/app.rs @@ -23,6 +23,7 @@ use rspotify::{ }, prelude::*, // Adds Id trait for .id() method }; +use serde::de::DeserializeOwned; use std::cell::Cell; use std::sync::mpsc::Sender; #[cfg(any(feature = "streaming", all(feature = "mpris", target_os = "linux")))] @@ -91,7 +92,7 @@ impl ScrollableResultPages { // Offset-keyed page caches are always kept sorted by page.offset, but the cache can be sparse. // Visible-page identity must be derived from page.offset, not raw cache index adjacency. -impl ScrollableResultPages> { +impl ScrollableResultPages> { pub fn page_index_for_offset(&self, offset: u32) -> Option { self .pages @@ -1270,6 +1271,7 @@ impl App { let duration_ms = match item { PlayableItem::Track(track) => track.duration.num_milliseconds() as u32, PlayableItem::Episode(episode) => episode.duration.num_milliseconds() as u32, + _ => return, }; let event = if seek_ms < duration_ms { @@ -1380,6 +1382,7 @@ impl App { let duration_ms = match item { PlayableItem::Track(track) => track.duration.num_milliseconds() as u128, PlayableItem::Episode(episode) => episode.duration.num_milliseconds() as u128, + _ => return, }; self.song_progress_ms = (self.song_progress_ms + tick_rate_ms).min(duration_ms); @@ -1400,6 +1403,7 @@ impl App { let duration_ms = match item { PlayableItem::Track(track) => track.duration.num_milliseconds() as u32, PlayableItem::Episode(episode) => episode.duration.num_milliseconds() as u32, + _ => return, }; let old_progress = match self.seek_ms { @@ -1955,6 +1959,7 @@ impl App { self.handle_error(anyhow!("failed to set clipboard content: {}", e)); } } + _ => {} } } } @@ -1991,6 +1996,7 @@ impl App { self.handle_error(anyhow!("failed to set clipboard content: {}", e)); } } + _ => {} } } } @@ -2012,7 +2018,7 @@ impl App { let mut positions: Vec = Vec::new(); for (idx, item) in playlist_track_page.items.iter().enumerate() { - if let Some(PlayableItem::Track(full_track)) = item.track.as_ref() { + if let Some(PlayableItem::Track(full_track)) = item.item.as_ref() { tracks.push(full_track.clone()); if let Some(track_id) = full_track.id.as_ref() { track_ids.push(track_id.clone().into_static()); @@ -2747,6 +2753,7 @@ impl App { )); } + #[allow(deprecated)] pub fn get_user_country(&self) -> Option { self.user.as_ref().and_then(|user| user.country) } @@ -3543,6 +3550,7 @@ mod tests { use std::collections::HashMap; use std::sync::mpsc::channel; + #[allow(deprecated)] fn full_track(id: &str, name: &str) -> FullTrack { FullTrack { album: SimplifiedAlbum { @@ -3569,6 +3577,7 @@ mod tests { popularity: 50, preview_url: None, track_number: 1, + r#type: rspotify::model::Type::Track, } } diff --git a/src/core/test_helpers.rs b/src/core/test_helpers.rs index 0e28af17..55bc7d9d 100644 --- a/src/core/test_helpers.rs +++ b/src/core/test_helpers.rs @@ -8,6 +8,7 @@ use rspotify::model::{ }; use std::collections::HashMap; +#[allow(deprecated)] pub fn private_user(id: &str) -> PrivateUser { PrivateUser { country: None, @@ -23,6 +24,7 @@ pub fn private_user(id: &str) -> PrivateUser { } } +#[allow(deprecated)] pub fn public_user(id: &str, display_name: &str) -> PublicUser { PublicUser { display_name: Some(display_name.to_string()), @@ -34,12 +36,17 @@ pub fn public_user(id: &str, display_name: &str) -> PublicUser { } } +#[allow(deprecated)] pub fn simplified_playlist( id: &str, name: &str, owner_id: &str, collaborative: bool, ) -> SimplifiedPlaylist { + let tracks = PlaylistTracksRef { + href: format!("https://api.spotify.com/v1/playlists/{id}/tracks"), + total: 5, + }; SimplifiedPlaylist { collaborative, external_urls: HashMap::new(), @@ -50,9 +57,7 @@ pub fn simplified_playlist( owner: public_user(owner_id, owner_id), public: Some(false), snapshot_id: "snapshot".to_string(), - tracks: PlaylistTracksRef { - href: format!("https://api.spotify.com/v1/playlists/{id}/tracks"), - total: 5, - }, + tracks: tracks.clone(), + items: tracks, } } diff --git a/src/infra/network/library.rs b/src/infra/network/library.rs index a20b16b4..72517e49 100644 --- a/src/infra/network/library.rs +++ b/src/infra/network/library.rs @@ -7,7 +7,7 @@ use crate::core::app::{ use anyhow::anyhow; use reqwest::Method; use rspotify::model::{ - idtypes::{AlbumId, PlaylistId, ShowId, TrackId, UserId}, + idtypes::{AlbumId, LibraryId, PlaylistId, ShowId, TrackId, UserId}, page::Page, playlist::PlaylistItem, track::SavedTrack, @@ -570,11 +570,11 @@ impl LibraryNetwork for Network { &mut self, _playlist_owner_id: UserId<'static>, playlist_id: PlaylistId<'static>, - is_public: Option, + _is_public: Option, ) { match self .spotify - .playlist_follow(playlist_id, Some(is_public.unwrap_or(false))) + .library_add([LibraryId::Playlist(playlist_id)]) .await { Ok(_) => { @@ -589,7 +589,11 @@ impl LibraryNetwork for Network { _user_id: UserId<'static>, playlist_id: PlaylistId<'static>, ) { - match self.spotify.playlist_unfollow(playlist_id).await { + match self + .spotify + .library_remove([LibraryId::Playlist(playlist_id)]) + .await + { Ok(_) => { // Handled } @@ -737,7 +741,7 @@ impl LibraryNetwork for Network { } for item in page.items { - if let Some(PlayableItem::Track(full_track)) = item.track { + if let Some(PlayableItem::Track(full_track)) = item.item { all_tracks.push(full_track); } } @@ -771,6 +775,7 @@ mod tests { use rspotify::model::{artist::SimplifiedArtist, track::FullTrack}; use std::collections::{HashMap, HashSet}; + #[allow(deprecated)] fn full_track(id: &str) -> FullTrack { FullTrack { album: rspotify::model::album::SimplifiedAlbum { @@ -797,6 +802,7 @@ mod tests { popularity: 50, preview_url: None, track_number: 1, + r#type: rspotify::model::Type::Track, } } diff --git a/src/infra/network/metadata.rs b/src/infra/network/metadata.rs index 19d3c5da..ac62b2d0 100644 --- a/src/infra/network/metadata.rs +++ b/src/infra/network/metadata.rs @@ -10,7 +10,7 @@ use rspotify::model::{ album::SimplifiedAlbum, artist::FullArtist, enums::Country, - idtypes::{AlbumId, ArtistId, ShowId, TrackId}, + idtypes::{AlbumId, ArtistId, LibraryId, ShowId, TrackId}, page::Page, show::SimplifiedShow, Market, @@ -48,8 +48,8 @@ impl MetadataNetwork for Network { ) { let artist_id_str = artist_id.id().to_string(); let market = country.map(Market::Country); + #[allow(deprecated)] let top_tracks_req = self.spotify.artist_top_tracks(artist_id.clone(), market); - // rspotify 0.14 artist_related_artists is not deprecated or we suppress #[allow(deprecated)] let related_artists_req = self.spotify.artist_related_artists(artist_id.clone()); let albums_req = self.spotify.artist_albums(artist_id.clone(), None, market); @@ -244,7 +244,11 @@ impl MetadataNetwork for Network { } async fn user_unfollow_artists(&mut self, artist_ids: Vec>) { - match self.spotify.user_unfollow_artists(artist_ids).await { + match self + .spotify + .library_remove(artist_ids.into_iter().map(LibraryId::Artist)) + .await + { Ok(_) => { // Handled } @@ -253,7 +257,11 @@ impl MetadataNetwork for Network { } async fn user_follow_artists(&mut self, artist_ids: Vec>) { - match self.spotify.user_follow_artists(artist_ids).await { + match self + .spotify + .library_add(artist_ids.into_iter().map(LibraryId::Artist)) + .await + { Ok(_) => { // Handled } @@ -264,7 +272,7 @@ impl MetadataNetwork for Network { async fn user_artist_check_follow(&mut self, artist_ids: Vec>) { match self .spotify - .user_artist_check_follow(artist_ids.clone()) + .library_contains(artist_ids.iter().map(|id| LibraryId::Artist(id.as_ref()))) .await { Ok(is_following) => { diff --git a/src/infra/network/mod.rs b/src/infra/network/mod.rs index 3fc21d8b..0bec27b7 100644 --- a/src/infra/network/mod.rs +++ b/src/infra/network/mod.rs @@ -568,7 +568,7 @@ impl Network { t.id.as_ref().map(|id| id.uri()).unwrap_or_default() } Some(rspotify::model::PlayableItem::Episode(e)) => e.id.uri(), - None => return, + Some(_) | None => return, }; (uri, ctx.is_playing) } @@ -746,7 +746,7 @@ impl Network { t.id.as_ref().map(|id| id.uri()).unwrap_or_default() } Some(rspotify::model::PlayableItem::Episode(e)) => e.id.uri(), - None => String::new(), + Some(_) | None => String::new(), }, None => String::new(), }; diff --git a/src/infra/network/playback.rs b/src/infra/network/playback.rs index 89dffd91..d73ed611 100644 --- a/src/infra/network/playback.rs +++ b/src/infra/network/playback.rs @@ -226,6 +226,7 @@ impl PlaybackNetwork for Network { }; } PlayableItem::Episode(_episode) => { /*should map this to following the podcast show*/ } + _ => {} } }; @@ -266,6 +267,7 @@ impl PlaybackNetwork for Network { let image = match playable { PlayableItem::Track(t) => t.album.images.first(), PlayableItem::Episode(e) => e.images.first(), + _ => None, }; if let Some(image) = image { @@ -296,6 +298,7 @@ impl PlaybackNetwork for Network { let api_track_name = match item { PlayableItem::Track(t) => &t.name, PlayableItem::Episode(e) => &e.name, + _ => return, }; // Only clear if names match (API caught up to native player) if api_track_name == &native_info.name { @@ -871,6 +874,7 @@ impl PlaybackNetwork for Network { let current_id = match item { PlayableItem::Track(t) => t.id.map(|id| id.id().to_string()), PlayableItem::Episode(e) => Some(e.id.id().to_string()), + _ => None, }; if current_id == Some(previous_track_id) diff --git a/src/infra/network/recommend.rs b/src/infra/network/recommend.rs index 5b7d9afc..1d56216d 100644 --- a/src/infra/network/recommend.rs +++ b/src/infra/network/recommend.rs @@ -65,10 +65,9 @@ impl RecommendationNetwork for Network { let mut full_tracks = Vec::new(); if !track_ids.is_empty() { - // Chunk it if needed (50 limit) - for chunk in track_ids.chunks(50) { - if let Ok(tracks) = self.spotify.tracks(chunk.iter().cloned(), None).await { - full_tracks.extend(tracks); + for id in &track_ids { + if let Ok(track) = self.spotify.track(id.clone(), None).await { + full_tracks.push(track); } } } diff --git a/src/infra/network/user.rs b/src/infra/network/user.rs index 06915eb6..87981871 100644 --- a/src/infra/network/user.rs +++ b/src/infra/network/user.rs @@ -120,6 +120,7 @@ impl UserNetwork for Network { // 2. Get top tracks for each artist for artist in artists { + #[allow(deprecated)] if let Ok(tracks) = self.spotify.artist_top_tracks(artist.id, None).await { all_tracks.extend(tracks); } diff --git a/src/main.rs b/src/main.rs index 36b55ed7..f706ab5c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -221,6 +221,7 @@ fn build_discord_playback(app: &App) -> Option { }, is_playing, ), + _ => return None, } } else { return None; @@ -266,6 +267,7 @@ fn get_mpris_metadata(app: &App) -> Option { .and_then(|item| match item { PlayableItem::Track(t) => t.album.images.first().map(|i| i.url.clone()), PlayableItem::Episode(e) => e.images.first().map(|i| i.url.clone()), + _ => None, }); return Some(( native_info.name.clone(), @@ -293,6 +295,7 @@ fn get_mpris_metadata(app: &App) -> Option { episode.duration.num_milliseconds() as u32, episode.images.first().map(|image| image.url.clone()), )), + _ => None, } } else { None @@ -321,6 +324,7 @@ fn get_macos_metadata(app: &App) -> Option { episode.duration.num_milliseconds() as u32, episode.images.first().map(|image| image.url.clone()), )), + _ => None, } } else { None @@ -647,6 +651,7 @@ async fn account_supports_native_streaming( spotify: &AuthCodePkceSpotify, ) -> (bool, Option<&'static str>) { match spotify.me().await { + #[allow(deprecated)] Ok(user) => match user.product { Some(rspotify::model::SubscriptionLevel::Premium) => (true, None), Some(level) => { diff --git a/src/tui/handlers/mod.rs b/src/tui/handlers/mod.rs index 3201a5d1..2cec33ab 100644 --- a/src/tui/handlers/mod.rs +++ b/src/tui/handlers/mod.rs @@ -415,6 +415,7 @@ fn handle_jump_to_album(app: &mut App) { PlayableItem::Episode(episode) => { app.dispatch(IoEvent::GetShowEpisodes(Box::new(episode.show))); } + _ => {} }; } } @@ -436,6 +437,7 @@ fn handle_jump_to_artist_album(app: &mut App) { PlayableItem::Episode(_episode) => { // Do nothing for episode (yet!) } + _ => {} } }; } diff --git a/src/tui/handlers/mouse.rs b/src/tui/handlers/mouse.rs index a8083810..ce9771e9 100644 --- a/src/tui/handlers/mouse.rs +++ b/src/tui/handlers/mouse.rs @@ -882,6 +882,7 @@ mod tests { app.push_navigation_stack(RouteId::Settings, ActiveBlock::Settings); } + #[allow(deprecated)] fn with_playbar_context(app: &mut App) { let item = PlayableItem::Track(FullTrack { album: SimplifiedAlbum { @@ -908,6 +909,7 @@ mod tests { popularity: 50, preview_url: None, track_number: 1, + r#type: rspotify::model::Type::Track, }); app.current_playback_context = Some(CurrentPlaybackContext { diff --git a/src/tui/handlers/playbar.rs b/src/tui/handlers/playbar.rs index aef3de03..c29af8a2 100644 --- a/src/tui/handlers/playbar.rs +++ b/src/tui/handlers/playbar.rs @@ -51,6 +51,7 @@ pub(crate) fn toggle_like_currently_playing_item(app: &mut App) { episode.id.into_static(), ))); } + _ => {} }; }; } @@ -68,6 +69,7 @@ pub(crate) fn add_currently_playing_track_to_playlist(app: &mut App) { PlayableItem::Episode(_) => { app.set_status_message("Only tracks can be added to playlists".to_string(), 4); } + _ => {} }; } else { app.set_status_message("No track currently playing".to_string(), 4); diff --git a/src/tui/handlers/playlist.rs b/src/tui/handlers/playlist.rs index 6cfe6944..91619651 100644 --- a/src/tui/handlers/playlist.rs +++ b/src/tui/handlers/playlist.rs @@ -103,7 +103,12 @@ mod tests { use std::sync::mpsc::channel; use std::time::SystemTime; + #[allow(deprecated)] fn test_playlist(id: &str, name: &str) -> SimplifiedPlaylist { + let tracks = PlaylistTracksRef { + href: "https://example.com/playlist/tracks".to_string(), + total: 2, + }; SimplifiedPlaylist { collaborative: false, external_urls: HashMap::new(), @@ -121,10 +126,8 @@ mod tests { }, public: Some(false), snapshot_id: "snapshot".to_string(), - tracks: PlaylistTracksRef { - href: "https://example.com/playlist/tracks".to_string(), - total: 2, - }, + tracks: tracks.clone(), + items: tracks, } } diff --git a/src/tui/handlers/search_results.rs b/src/tui/handlers/search_results.rs index 282a08bd..fc7fdd7e 100644 --- a/src/tui/handlers/search_results.rs +++ b/src/tui/handlers/search_results.rs @@ -573,6 +573,7 @@ mod tests { }; use std::{collections::HashMap, sync::mpsc::channel, time::SystemTime}; + #[allow(deprecated)] fn full_track(id: &str, name: &str) -> FullTrack { FullTrack { album: SimplifiedAlbum { @@ -599,6 +600,7 @@ mod tests { popularity: 50, preview_url: None, track_number: 1, + r#type: rspotify::model::Type::Track, } } diff --git a/src/tui/handlers/sort_menu.rs b/src/tui/handlers/sort_menu.rs index 3b974d50..4312ef72 100644 --- a/src/tui/handlers/sort_menu.rs +++ b/src/tui/handlers/sort_menu.rs @@ -221,7 +221,12 @@ mod tests { use std::sync::mpsc::channel; use std::time::SystemTime; + #[allow(deprecated)] fn test_playlist(id: &str, name: &str) -> SimplifiedPlaylist { + let tracks = PlaylistTracksRef { + href: "https://example.com/playlist/tracks".to_string(), + total: 2, + }; SimplifiedPlaylist { collaborative: false, external_urls: HashMap::new(), @@ -239,10 +244,8 @@ mod tests { }, public: Some(false), snapshot_id: "snapshot".to_string(), - tracks: PlaylistTracksRef { - href: "https://example.com/playlist/tracks".to_string(), - total: 2, - }, + tracks: tracks.clone(), + items: tracks, } } diff --git a/src/tui/handlers/track_table.rs b/src/tui/handlers/track_table.rs index 064be0e7..408a14b5 100644 --- a/src/tui/handlers/track_table.rs +++ b/src/tui/handlers/track_table.rs @@ -600,6 +600,7 @@ mod tests { use std::sync::mpsc::channel; use std::time::SystemTime; + #[allow(deprecated)] fn full_track(id: &str, name: &str) -> FullTrack { FullTrack { album: rspotify::model::album::SimplifiedAlbum { @@ -626,6 +627,7 @@ mod tests { popularity: 50, preview_url: None, track_number: 1, + r#type: rspotify::model::Type::Track, } } diff --git a/src/tui/ui/player.rs b/src/tui/ui/player.rs index dc43bc41..9ebacb9d 100644 --- a/src/tui/ui/player.rs +++ b/src/tui/ui/player.rs @@ -391,6 +391,7 @@ fn extract_track_info(app: &App) -> (Option, Option) { let (name, artists) = match track_item { PlayableItem::Track(track) => (track.name.clone(), create_artist_string(&track.artists)), PlayableItem::Episode(episode) => (episode.name.clone(), episode.show.name.clone()), + _ => return (None, None), }; return (Some(name), Some(artists)); } @@ -587,6 +588,7 @@ pub fn draw_playbar(f: &mut Frame<'_>, app: &App, layout_chunk: Rect) { episode.name.to_owned(), episode.duration, ), + _ => return, }; // Use native track info for instant display when available (e.g., after skipping tracks) @@ -602,6 +604,7 @@ pub fn draw_playbar(f: &mut Frame<'_>, app: &App, layout_chunk: Rect) { let artists_str = match track_item { PlayableItem::Track(track) => create_artist_string(&track.artists), PlayableItem::Episode(episode) => format!("{} - {}", episode.name, episode.show.name), + _ => return, }; ( name.clone(), diff --git a/src/tui/ui/popups.rs b/src/tui/ui/popups.rs index 0ef4e6d7..c57c67d7 100644 --- a/src/tui/ui/popups.rs +++ b/src/tui/ui/popups.rs @@ -89,6 +89,7 @@ fn queue_item_line(item: &PlayableItem) -> String { PlayableItem::Episode(episode) => { format!("{} - {}", episode.name, episode.show.name) } + _ => String::from("Unknown item"), } } diff --git a/src/tui/ui/search.rs b/src/tui/ui/search.rs index b4cce944..ebc1680a 100644 --- a/src/tui/ui/search.rs +++ b/src/tui/ui/search.rs @@ -159,6 +159,7 @@ pub fn draw_search_results(f: &mut Frame<'_>, app: &App, layout_chunk: Rect) { context.item.and_then(|item| match item { PlayableItem::Track(track) => track.id.map(|id| id.id().to_string()), PlayableItem::Episode(episode) => Some(episode.id.id().to_string()), + _ => None, }) }) .unwrap_or_default(); @@ -323,7 +324,9 @@ pub fn draw_search_results(f: &mut Frame<'_>, app: &App, layout_chunk: Rect) { if app.saved_show_ids_set.contains(item.id.id()) { show_name.push_str(&app.user_config.padded_liked_icon()); } - show_name.push_str(&format!("{:} - {}", item.name, item.publisher)); + #[allow(deprecated)] + let publisher = &item.publisher; + show_name.push_str(&format!("{:} - {}", item.name, publisher)); show_name }) .collect(), diff --git a/src/tui/ui/tables.rs b/src/tui/ui/tables.rs index e3c84244..1be72203 100644 --- a/src/tui/ui/tables.rs +++ b/src/tui/ui/tables.rs @@ -125,12 +125,13 @@ pub fn draw_podcast_table(f: &mut Frame<'_>, app: &App, layout_chunk: Rect) { let items = saved_shows .items .iter() - .map(|show_page| TableItem { - id: show_page.show.id.id().to_string(), - format: vec![ - show_page.show.name.to_owned(), - show_page.show.publisher.to_owned(), - ], + .map(|show_page| { + #[allow(deprecated)] + let publisher = show_page.show.publisher.to_owned(); + TableItem { + id: show_page.show.id.id().to_string(), + format: vec![show_page.show.name.to_owned(), publisher], + } }) .collect::>(); @@ -546,6 +547,7 @@ pub fn draw_show_episodes(f: &mut Frame<'_>, app: &App, layout_chunk: Rect) { }) .collect::>(); + #[allow(deprecated)] let title = match &app.episode_table_context { EpisodeTableContext::Simplified => match &app.selected_show_simplified { Some(selected_show) => { @@ -677,6 +679,7 @@ fn draw_table( let episode_id_str = episode.id.id().to_string(); items.iter().position(|item| episode_id_str == item.id) } + _ => None, }) });