diff --git a/doc/users.md b/doc/users.md
index e39e05920..1f8d2e777 100644
--- a/doc/users.md
+++ b/doc/users.md
@@ -128,11 +128,12 @@ When pressing O:
| Shift+X | Copy the URL to the **currently playing track** to the system clipboard. |
### Queue
-| Key | Command |
-|------------------------------|--------------------------------------|
-| C | Clear the entire queue. |
-| D | Delete the currently selected track. |
-| Ctrl+S | Save the current queue. |
+| Key | Command |
+|------------------------------|-----------------------------------------------------|
+| C | Clear the entire queue. |
+| D | Delete the currently selected track. |
+| Ctrl+S | Save the current queue. |
+| Z | Randomize the queue tracks (put into random order). |
### Library
| Key | Command |
diff --git a/src/command.rs b/src/command.rs
index 5d48a0182..064246b09 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -143,6 +143,7 @@ pub enum Command {
VolumeDown(u16),
Repeat(Option),
Shuffle(Option),
+ Randomize,
#[cfg(feature = "share_clipboard")]
Share(TargetMode),
Back,
@@ -220,6 +221,7 @@ impl fmt::Display for Command {
| Command::SaveQueue
| Command::Add
| Command::AddCurrent
+ | Command::Randomize
| Command::Delete
| Command::Back
| Command::Help
@@ -259,6 +261,7 @@ impl Command {
Command::VolumeDown(_) => "voldown",
Command::Repeat(_) => "repeat",
Command::Shuffle(_) => "shuffle",
+ Command::Randomize => "randomize",
#[cfg(feature = "share_clipboard")]
Command::Share(_) => "share",
Command::Back => "back",
@@ -547,6 +550,7 @@ pub fn parse(input: &str) -> Result, CommandParseError> {
}?;
Command::Shuffle(switch)
}
+ "randomize" => Command::Randomize,
#[cfg(feature = "share_clipboard")]
"share" => {
let &target_mode_raw = args.first().ok_or(InsufficientArgs {
diff --git a/src/commands.rs b/src/commands.rs
index 94d663275..dcca97170 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -173,6 +173,10 @@ impl CommandManager {
self.queue.set_shuffle(mode);
Ok(None)
}
+ Command::Randomize => {
+ self.queue.randomize();
+ Ok(None)
+ }
Command::Repeat(mode) => {
let mode = mode.unwrap_or_else(|| match self.queue.get_repeat() {
RepeatSetting::None => RepeatSetting::RepeatPlaylist,
@@ -452,6 +456,7 @@ impl CommandManager {
kb.insert("r".into(), vec![Command::Repeat(None)]);
kb.insert("z".into(), vec![Command::Shuffle(None)]);
+ kb.insert("Ctrl+z".into(), vec![Command::Randomize]);
#[cfg(feature = "share_clipboard")]
{
diff --git a/src/mpris.rs b/src/mpris.rs
index 365ed036a..afa2b4701 100644
--- a/src/mpris.rs
+++ b/src/mpris.rs
@@ -263,6 +263,12 @@ impl MprisPlayer {
self.event.trigger();
}
+ /*#[dbus_interface(property)]
+ fn randomize(&self, _b: bool) {
+ self.queue.randomize();
+ self.event.trigger();
+ }*/
+
#[dbus_interface(property)]
fn volume(&self) -> f64 {
self.spotify.volume() as f64 / 65535_f64
diff --git a/src/queue.rs b/src/queue.rs
index 09324c221..f21a9e0a0 100644
--- a/src/queue.rs
+++ b/src/queue.rs
@@ -467,6 +467,35 @@ impl Queue {
}
}
+ /// Randomize the queue ("shuffle" all the entries of the underlying Vec). Different from the `Shuffle`
+ /// option in that this actually changes the track positions in the queue (that gets displayed to the user),
+ /// but leaves the play order running from top to bottom. Useful If you want to shuffle a playlist,
+ /// but still want to add songs to be played next.
+ ///
+ /// This deactivates `Shuffle`.
+ pub fn randomize(&self) {
+ // stop playlist, because we completely invalidate any playing order
+ let previous_playback_state = self.cfg.state().playback_state.clone();
+ self.stop();
+
+ // deactivate `Shuffle` feature, because it usually wouldn't make sense to use both
+ if self.get_shuffle() == true {
+ self.set_shuffle(false);
+ }
+
+ // permutate the queue Vec
+ let mut queue = self.queue.write().unwrap();
+ queue.shuffle(&mut thread_rng());
+
+ // resetting playing position to start of queue doesn't seem necessary
+ // my guess is that stop() does that
+
+ // resume playback if we were playing before
+ if previous_playback_state == PlaybackState::Playing {
+ self.toggleplayback();
+ }
+ }
+
/// Handle events that are specific to the queue.
pub fn handle_event(&self, event: QueueEvent) {
match event {