Improved seek command to allow more units (#682)

* `seek` command accepts fancy duration

* Use default formatting

* Better var naming

* Documented `seek` command
This commit is contained in:
cyqsimon
2021-12-27 16:28:49 +08:00
committed by GitHub
parent 0947a074d9
commit e0ec759730
4 changed files with 101 additions and 26 deletions

67
Cargo.lock generated
View File

@@ -611,7 +611,7 @@ dependencies = [
"lazy_static 1.4.0", "lazy_static 1.4.0",
"libc", "libc",
"log", "log",
"num", "num 0.3.1",
"owning_ref", "owning_ref",
"syn", "syn",
"unicode-segmentation", "unicode-segmentation",
@@ -1470,7 +1470,7 @@ dependencies = [
"hyper-proxy", "hyper-proxy",
"librespot-protocol", "librespot-protocol",
"log", "log",
"num-bigint", "num-bigint 0.4.3",
"num-integer", "num-integer",
"num-traits", "num-traits",
"once_cell", "once_cell",
@@ -1738,6 +1738,7 @@ dependencies = [
"log", "log",
"notify-rust", "notify-rust",
"pancurses 0.17.0", "pancurses 0.17.0",
"parse_duration",
"platform-dirs", "platform-dirs",
"rand", "rand",
"regex", "regex",
@@ -1919,16 +1920,41 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "num"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36"
dependencies = [
"num-bigint 0.2.6",
"num-complex 0.2.4",
"num-integer",
"num-iter",
"num-rational 0.2.4",
"num-traits",
]
[[package]] [[package]]
name = "num" name = "num"
version = "0.3.1" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f"
dependencies = [ dependencies = [
"num-complex", "num-complex 0.3.1",
"num-integer", "num-integer",
"num-iter", "num-iter",
"num-rational", "num-rational 0.3.2",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg",
"num-integer",
"num-traits", "num-traits",
] ]
@@ -1944,6 +1970,16 @@ dependencies = [
"rand", "rand",
] ]
[[package]]
name = "num-complex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95"
dependencies = [
"autocfg",
"num-traits",
]
[[package]] [[package]]
name = "num-complex" name = "num-complex"
version = "0.3.1" version = "0.3.1"
@@ -1985,6 +2021,18 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "num-rational"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
dependencies = [
"autocfg",
"num-bigint 0.2.6",
"num-integer",
"num-traits",
]
[[package]] [[package]]
name = "num-rational" name = "num-rational"
version = "0.3.2" version = "0.3.2"
@@ -2259,6 +2307,17 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "parse_duration"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7037e5e93e0172a5a96874380bf73bc6ecef022e26fa25f2be26864d6b3ba95d"
dependencies = [
"lazy_static 1.4.0",
"num 0.2.1",
"regex",
]
[[package]] [[package]]
name = "pbkdf2" name = "pbkdf2"
version = "0.8.0" version = "0.8.0"

View File

@@ -47,6 +47,7 @@ ioctl-rs = { version = "0.2", optional = true }
serde_cbor = "0.11.2" serde_cbor = "0.11.2"
pancurses = { version = "0.17.0", features = ["win32"], optional = true } pancurses = { version = "0.17.0", features = ["win32"], optional = true }
libc = "0.2.111" libc = "0.2.111"
parse_duration = "2.1.1"
[dependencies.rspotify] [dependencies.rspotify]
version = "0.11.3" version = "0.11.3"

View File

@@ -265,6 +265,7 @@ The following commands are supported:
| `logout` | Remove any cached credentials from disk and quit `ncspot`. | | `logout` | Remove any cached credentials from disk and quit `ncspot`. |
| `toggle` | Toggle playback. | | `toggle` | Toggle playback. |
| `stop` | Stop playback. | | `stop` | Stop playback. |
| `seek [+\|-]<time>` | Seek to the specified position, or seek relative to current position by prepending `+`/`-`. Supports mixing time units (e.g. `seek 1m42s`). Default unit is `millisecond`. |
| `previous` | Play previous track. | | `previous` | Play previous track. |
| `next` | Play next track. | | `next` | Play next track. |
| `clear` | Clear playlist. | | `clear` | Clear playlist. |

View File

@@ -377,29 +377,43 @@ pub fn parse(input: &str) -> Option<Vec<Command>> {
Some(Command::Repeat(mode)) Some(Command::Repeat(mode))
} }
"seek" => args.get(0).and_then(|arg| match arg.chars().next() { "seek" => {
Some(x) if x == '-' || x == '+' => arg let arg = args.join(" ");
.chars() let first_char = arg.chars().next();
.skip(1) let duration_raw = match first_char {
.collect::<String>() Some('+' | '-') => arg.chars().skip(1).collect(),
.parse::<i32>() _ => arg.to_string(),
};
duration_raw
.parse::<u32>() // accept raw milliseconds for backward compatibility
.ok() .ok()
.map(|amount| { .or_else(|| {
Command::Seek(SeekDirection::Relative( parse_duration::parse(&duration_raw) // accept fancy duration
amount .ok()
* match x { .and_then(|dur| dur.as_millis().try_into().ok())
'-' => -1, })
_ => 1, .and_then(|unsigned_millis| {
}, match first_char {
)) // handle i32::MAX < unsigned_millis < u32::MAX gracefully
}), Some('+') => {
_ => arg i32::try_from(unsigned_millis)
.chars() .ok()
.collect::<String>() .map(|unsigned_millis_i32| {
.parse() SeekDirection::Relative(unsigned_millis_i32)
.ok() })
.map(|amount| Command::Seek(SeekDirection::Absolute(amount))), }
}), Some('-') => {
i32::try_from(unsigned_millis)
.ok()
.map(|unsigned_millis_i32| {
SeekDirection::Relative(-unsigned_millis_i32)
})
}
_ => Some(SeekDirection::Absolute(unsigned_millis)),
}
.map(|direction| Command::Seek(direction))
})
}
"focus" => args "focus" => args
.get(0) .get(0)
.map(|target| Command::Focus((*target).to_string())), .map(|target| Command::Focus((*target).to_string())),