From c4936dc4ff22c03cb30da82a41e431e984fe9563 Mon Sep 17 00:00:00 2001 From: Sijmen Date: Sun, 7 May 2023 01:50:06 +0200 Subject: [PATCH] Add buttons to play/queue an entire folder Fixes #2 --- src/main.rs | 25 +++++++++++++-- src/mpd.rs | 43 +++++++++++++++++++++++-- static/style.css | 39 +++++++++++++++-------- templates/browser.html | 72 ++++++++++++++++++++++++++---------------- templates/queue.html | 2 +- 5 files changed, 136 insertions(+), 45 deletions(-) diff --git a/src/main.rs b/src/main.rs index e2cd734..562dbb7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -92,12 +92,33 @@ async fn get_browser(req: tide::Request<()>) -> tide::Result { #[derive(Deserialize)] struct PostQueueQuery { path: String, + #[serde(default)] + replace: bool, + #[serde(default)] + next: bool, + #[serde(default)] + play: bool, } async fn post_queue(req: tide::Request<()>) -> tide::Result { let query: PostQueueQuery = req.query()?; let path = percent_decode_str(&query.path).decode_utf8_lossy(); - mpd::connect()?.add(&path)?; + let mut mpd = mpd::Mpd::connect().await?; + + if query.replace { + mpd.clear().await?; + } + + if query.next { + mpd.add_pos(&path, "+0").await?; + } else { + mpd.add(&path).await?; + } + + if query.play { + mpd.play().await?; + } + Ok("".into()) } @@ -178,7 +199,7 @@ async fn sse(_req: tide::Request<()>, sender: tide::sse::Sender) -> tide::Result #[async_std::main] async fn main() -> tide::Result<()> { tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) + .with_max_level(tracing::Level::WARN) .init(); let mut app = tide::new(); diff --git a/src/mpd.rs b/src/mpd.rs index 3e15ca7..e391629 100644 --- a/src/mpd.rs +++ b/src/mpd.rs @@ -104,8 +104,8 @@ pub(crate) struct Mpd { } impl Mpd { - fn escape_str(s: &str) -> String { - s.replace("\"", "\\\"").replace("'", "\\'") + pub fn escape_str(s: &str) -> String { + s.replace('\"', "\\\"").replace('\'', "\\'") } pub async fn connect() -> anyhow::Result { @@ -130,6 +130,45 @@ impl Mpd { Ok(Self { stream, reader }) } + pub async fn command(&mut self, command: &str) -> anyhow::Result<()> { + self.stream + .write_all(format!("{command}\n").as_bytes()) + .await?; + + let mut buffer = String::new(); + loop { + buffer.clear(); + self.reader.read_line(&mut buffer).await?; + + let split: Vec<_> = buffer.trim_end().split_ascii_whitespace().collect(); + + if split[0] == "OK" { + break Ok(()); + } else if split[0] == "ACK" { + break Err(anyhow!(buffer)); + } + } + } + + pub async fn clear(&mut self) -> anyhow::Result<()> { + self.command("clear").await + } + + pub async fn add(&mut self, path: &str) -> anyhow::Result<()> { + let path = Self::escape_str(path); + self.command(&format!("add \"{path}\"")).await + } + + pub async fn add_pos(&mut self, path: &str, pos: &str) -> anyhow::Result<()> { + let path = Self::escape_str(path); + let pos = Self::escape_str(pos); + self.command(&format!("add \"{path}\" \"{pos}\"")).await + } + + pub async fn play(&mut self) -> anyhow::Result<()> { + self.command("play").await + } + pub(crate) async fn idle(&mut self, systems: &[&str]) -> anyhow::Result> { let mut buffer = String::new(); diff --git a/static/style.css b/static/style.css index 74b0afc..15058cd 100644 --- a/static/style.css +++ b/static/style.css @@ -32,6 +32,14 @@ button { background-color: transparent; border: none; color: inherit; + padding: 0; + font-weight: bold; + display: flex; + line-height: 24px; + cursor: pointer; +} +button .material-symbols-outlined { + margin-right: 0.25rem; } .browser { @@ -71,14 +79,6 @@ ul { font-weight: bold; flex: 1; } -.queue-clear { - font-weight: bold; - display: flex; - line-height: 24px; -} -.queue-clear .material-symbols-outlined { - margin-right: 0.25rem; -} .queue { margin-top: 0.5rem; @@ -112,15 +112,28 @@ ul { -webkit-box-orient: vertical; } +.browser .header { + display: flex; + flex-flow: column; + background-color: #334; + border-radius: 0.25rem; + padding: 0.75rem 1rem; + margin: 16px 16px 0; +} + +.browser .buttons { + display: flex; + flex-flow: row; + margin-top: 0.75rem; +} +.browser .buttons button { + margin-right: 1.0rem; +} + ul.breadcrumb { display: flex; - margin-bottom: 1rem; flex-wrap: wrap; list-style: none; - background-color: #334; - border-radius: .25rem; - padding: .75rem 1rem; - margin: 16px 16px 0; } @media (prefers-contrast: more) { ul.breadcrumb { diff --git a/templates/browser.html b/templates/browser.html index 99f15f0..cef6191 100644 --- a/templates/browser.html +++ b/templates/browser.html @@ -1,31 +1,49 @@ {# #} - +
+ + +
+ {% let encoded = path.join("/")|urlencode %} + + + +
+
    {% for entry in entries %} diff --git a/templates/queue.html b/templates/queue.html index 09192c5..2c66649 100644 --- a/templates/queue.html +++ b/templates/queue.html @@ -3,7 +3,7 @@
    Next in queue
    -