diff --git a/README.md b/README.md index b80f2ce..50d2e88 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,12 @@ ## Configuration Empede is configured using environment variables: -| Name | Default | Description | -| --------------- | ------------ | --------------------------------- | -| **MPD_HOST** | localhost | MPD server host | -| **MPD_PORT** | 6600 | MPD server port | -| **EMPEDE_BIND** | 0.0.0.0:8080 | Address for Empede to bind to | +| Name | Default | Description | +| ---------------- | ------------ | --------------------------------- | +| **MPD_HOST** | localhost | MPD server host | +| **MPD_PORT** | 6600 | MPD server port | +| **MPD_PASSWORD** | | MPD server password | +| **EMPEDE_BIND** | 0.0.0.0:8080 | Address for Empede to bind to | ## Running ### Linux diff --git a/src/main.rs b/src/main.rs index 566c79a..e2cd734 100644 --- a/src/main.rs +++ b/src/main.rs @@ -165,8 +165,10 @@ async fn sse(_req: tide::Request<()>, sender: tide::sse::Sender) -> tide::Result sender.send("playlist", "", None).await?; sender.send("player", "", None).await?; + let mut mpd = mpd::Mpd::connect().await?; + loop { - let systems = mpd::idle(&["playlist", "player", "database"]).await?; + let systems = mpd.idle(&["playlist", "player", "database"]).await?; for system in systems { sender.send(&system, "", None).await?; } diff --git a/src/mpd.rs b/src/mpd.rs index 94887f4..3e15ca7 100644 --- a/src/mpd.rs +++ b/src/mpd.rs @@ -14,7 +14,14 @@ pub(crate) fn host() -> String { } pub(crate) fn connect() -> Result { - mpdrs::Client::connect(host()) + let mut client = mpdrs::Client::connect(host())?; + + let password = std::env::var("MPD_PASSWORD").unwrap_or(String::new()); + if !password.is_empty() { + client.login(&password)?; + } + + Ok(client) } pub(crate) fn ls(path: &str) -> anyhow::Result> { @@ -91,31 +98,58 @@ pub(crate) enum Entry { }, } -pub(crate) async fn idle(systems: &[&str]) -> anyhow::Result> { - let mut stream = TcpStream::connect(host()).await?; - let mut reader = BufReader::new(stream.clone()); +pub(crate) struct Mpd { + stream: TcpStream, + reader: BufReader, +} - // skip OK MPD line - // TODO check if it is indeed OK - let mut buffer = String::new(); - reader.read_line(&mut buffer).await?; +impl Mpd { + fn escape_str(s: &str) -> String { + s.replace("\"", "\\\"").replace("'", "\\'") + } - let systems = systems.join(" "); - let command = format!("idle {systems}\n"); - stream.write_all(command.as_bytes()).await?; + pub async fn connect() -> anyhow::Result { + let mut stream = TcpStream::connect(host()).await?; + let mut reader = BufReader::new(stream.clone()); - let mut updated = vec![]; - loop { - buffer.clear(); + // skip OK MPD line + // TODO check if it is indeed OK + let mut buffer = String::new(); reader.read_line(&mut buffer).await?; - if buffer == "OK\n" { - break Ok(updated); + + let password = std::env::var("MPD_PASSWORD").unwrap_or(String::new()); + if !password.is_empty() { + let password = Self::escape_str(&password); + let command = format!("password \"{password}\"\n"); + stream.write_all(command.as_bytes()).await?; + + buffer.clear(); + reader.read_line(&mut buffer).await?; } - let (_, changed) = buffer - .trim_end() - .split_once(": ") - .ok_or(anyhow!("unexpected response from MPD"))?; - updated.push(changed.to_string()); + Ok(Self { stream, reader }) + } + + pub(crate) async fn idle(&mut self, systems: &[&str]) -> anyhow::Result> { + let mut buffer = String::new(); + + let systems = systems.join(" "); + let command = format!("idle {systems}\n"); + self.stream.write_all(command.as_bytes()).await?; + + let mut updated = vec![]; + loop { + buffer.clear(); + self.reader.read_line(&mut buffer).await?; + if buffer == "OK\n" { + break Ok(updated); + } + + let (_, changed) = buffer + .trim_end() + .split_once(": ") + .ok_or(anyhow!("unexpected response from MPD"))?; + updated.push(changed.to_string()); + } } }