diff --git a/README.md b/README.md index 5662362..75a5685 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,8 @@ depending on your desktop environment settings. Have a look at the * `F3`: Library * `d` deletes the currently selected playlist * Tracks and playlists can be played using `Return` and queued using `Space` -* `.` will move to the currently playing track in the queue. +* `n` will play the selected item after the currently playing track +* `.` will move to the currently playing track in the queue * `s` will save, `d` will remove the currently selected track to/from your library * `o` will open a detail view or context menu for the selected item diff --git a/src/album.rs b/src/album.rs index 0e4e7f9..508a13d 100644 --- a/src/album.rs +++ b/src/album.rs @@ -189,6 +189,16 @@ impl ListItem for Album { } } + fn play_next(&mut self, queue: Arc) { + self.load_tracks(queue.get_spotify()); + + if let Some(tracks) = self.tracks.as_ref() { + for t in tracks.iter().rev() { + queue.insert_after_current(Playable::Track(t.clone())); + } + } + } + fn queue(&mut self, queue: Arc) { self.load_tracks(queue.get_spotify()); diff --git a/src/artist.rs b/src/artist.rs index d9b259a..1fb09bf 100644 --- a/src/artist.rs +++ b/src/artist.rs @@ -185,6 +185,16 @@ impl ListItem for Artist { } } + fn play_next(&mut self, queue: Arc) { + self.load_albums(queue.get_spotify()); + + if let Some(tracks) = self.tracks.as_ref() { + for t in tracks.iter().rev() { + queue.insert_after_current(Playable::Track(t.clone())); + } + } + } + fn queue(&mut self, queue: Arc) { self.load_albums(queue.get_spotify()); diff --git a/src/command.rs b/src/command.rs index e5b7f4b..63d0076 100644 --- a/src/command.rs +++ b/src/command.rs @@ -83,6 +83,7 @@ pub enum Command { Next, Clear, Queue, + PlayNext, Play, UpdateLibrary, Save, @@ -117,6 +118,7 @@ impl fmt::Display for Command { Command::Next => "next".to_string(), Command::Clear => "clear".to_string(), Command::Queue => "queue".to_string(), + Command::PlayNext => "play next".to_string(), Command::Play => "play".to_string(), Command::UpdateLibrary => "update".to_string(), Command::Save => "save".to_string(), @@ -208,6 +210,7 @@ pub fn parse(input: &str) -> Option { "previous" => Some(Command::Previous), "next" => Some(Command::Next), "clear" => Some(Command::Clear), + "playnext" => Some(Command::PlayNext), "queue" => Some(Command::Queue), "play" => Some(Command::Play), "update" => Some(Command::UpdateLibrary), diff --git a/src/commands.rs b/src/commands.rs index 1575227..736784c 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -177,6 +177,7 @@ impl CommandManager { | Command::Move(_, _) | Command::Shift(_, _) | Command::Play + | Command::PlayNext | Command::Queue | Command::Save | Command::Delete @@ -269,6 +270,7 @@ impl CommandManager { kb.insert(">".into(), Command::Next); kb.insert("c".into(), Command::Clear); kb.insert("Space".into(), Command::Queue); + kb.insert("n".into(), Command::PlayNext); kb.insert("Enter".into(), Command::Play); kb.insert("s".into(), Command::Save); kb.insert("Ctrl+s".into(), Command::SaveQueue); diff --git a/src/episode.rs b/src/episode.rs index 946442a..6d6f400 100644 --- a/src/episode.rs +++ b/src/episode.rs @@ -84,6 +84,10 @@ impl ListItem for Episode { queue.play(index, true, false); } + fn play_next(&mut self, queue: Arc) { + queue.insert_after_current(Playable::Episode(self.clone())); + } + fn queue(&mut self, queue: Arc) { queue.append(Playable::Episode(self.clone())); } diff --git a/src/playable.rs b/src/playable.rs index a92981f..dad2594 100644 --- a/src/playable.rs +++ b/src/playable.rs @@ -88,6 +88,10 @@ impl ListItem for Playable { self.as_listitem().play(queue) } + fn play_next(&mut self, queue: Arc) { + self.as_listitem().play_next(queue) + } + fn queue(&mut self, queue: Arc) { self.as_listitem().queue(queue) } diff --git a/src/playlist.rs b/src/playlist.rs index d3f6e61..d4ee5df 100644 --- a/src/playlist.rs +++ b/src/playlist.rs @@ -165,6 +165,16 @@ impl ListItem for Playlist { } } + fn play_next(&mut self, queue: Arc) { + self.load_tracks(queue.get_spotify()); + + if let Some(tracks) = self.tracks.as_ref() { + for track in tracks.iter().rev() { + queue.insert_after_current(Playable::Track(track.clone())); + } + } + } + fn queue(&mut self, queue: Arc) { self.load_tracks(queue.get_spotify()); diff --git a/src/queue.rs b/src/queue.rs index 70fa981..4137b89 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -96,6 +96,28 @@ impl Queue { *self.current_track.read().unwrap() } + pub fn insert_after_current(&self, track: Playable) { + if let Some(index) = self.get_current_index() { + let mut random_order = self.random_order.write().unwrap(); + if let Some(order) = random_order.as_mut() { + let next_i = order.iter().position(|&i| i == index).unwrap(); + // shift everything after the insertion in order + let size = order.len(); + for i in 0..size { + if order[i] > index { + order[i] += 1; + } + } + // finally, add the next track index + order.insert(next_i + 1, index + 1); + } + let mut q = self.queue.write().unwrap(); + q.insert(index + 1, track); + } else { + self.append(track); + } + } + pub fn append(&self, track: Playable) { let mut random_order = self.random_order.write().unwrap(); if let Some(order) = random_order.as_mut() { diff --git a/src/show.rs b/src/show.rs index e9b2f77..dd252a3 100644 --- a/src/show.rs +++ b/src/show.rs @@ -124,6 +124,16 @@ impl ListItem for Show { queue.play(index, true, true); } + fn play_next(&mut self, queue: Arc) { + self.load_episodes(queue.get_spotify()); + + if let Some(episodes) = self.episodes.as_ref() { + for ep in episodes.iter().rev() { + queue.insert_after_current(Playable::Episode(ep.clone())); + } + } + } + fn queue(&mut self, queue: Arc) { self.load_episodes(queue.get_spotify()); diff --git a/src/spotify.rs b/src/spotify.rs index cc17066..cefb8e4 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -46,12 +46,12 @@ use url::Url; use core::task::Poll; use std::pin::Pin; +use std::str::FromStr; use std::sync::atomic::{AtomicU16, Ordering}; use std::sync::RwLock; use std::thread; use std::time::{Duration, SystemTime}; use std::{env, io}; -use std::str::FromStr; use crate::artist::Artist; use crate::config; @@ -401,7 +401,7 @@ impl Spotify { ) { let bitrate_str = cfg.bitrate.unwrap_or(320).to_string(); let bitrate = Bitrate::from_str(&bitrate_str); - if bitrate.is_err(){ + if bitrate.is_err() { error!("invalid bitrate, will use 320 instead") } diff --git a/src/track.rs b/src/track.rs index 112ae58..c9ab820 100644 --- a/src/track.rs +++ b/src/track.rs @@ -154,7 +154,7 @@ impl ListItem for Track { } fn display_center(&self) -> String { - format!("{}", self.album) + self.album.to_string() } fn display_right(&self, library: Arc) -> String { @@ -175,6 +175,10 @@ impl ListItem for Track { queue.play(index, true, false); } + fn play_next(&mut self, queue: Arc) { + queue.insert_after_current(Playable::Track(self.clone())); + } + fn queue(&mut self, queue: Arc) { queue.append(Playable::Track(self.clone())); } diff --git a/src/traits.rs b/src/traits.rs index 2b4f788..21c5796 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -19,6 +19,7 @@ pub trait ListItem: Sync + Send + 'static { fn display_right(&self, library: Arc) -> String; fn play(&mut self, queue: Arc); fn queue(&mut self, queue: Arc); + fn play_next(&mut self, queue: Arc); fn toggle_saved(&mut self, library: Arc); fn save(&mut self, library: Arc); fn unsave(&mut self, library: Arc); diff --git a/src/ui/listview.rs b/src/ui/listview.rs index dab3211..2280043 100644 --- a/src/ui/listview.rs +++ b/src/ui/listview.rs @@ -338,6 +338,15 @@ impl ViewExt for ListView { return Ok(CommandResult::Consumed(None)); } + Command::PlayNext => { + info!("played next"); + let mut content = self.content.write().unwrap(); + if let Some(item) = content.get_mut(self.selected) { + item.play_next(self.queue.clone()); + } + + return Ok(CommandResult::Consumed(None)); + } Command::Queue => { let mut content = self.content.write().unwrap(); if let Some(item) = content.get_mut(self.selected) { diff --git a/src/ui/queue.rs b/src/ui/queue.rs index 12c68f8..0144b12 100644 --- a/src/ui/queue.rs +++ b/src/ui/queue.rs @@ -95,6 +95,9 @@ impl ViewExt for QueueView { self.queue.play(self.list.get_selected_index(), true, false); return Ok(CommandResult::Consumed(None)); } + Command::PlayNext => { + return Ok(CommandResult::Ignored); + } Command::Queue => { return Ok(CommandResult::Ignored); }