2023-04-25 01:44:03 +00:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
2023-05-01 14:13:08 +00:00
|
|
|
use anyhow::anyhow;
|
|
|
|
use async_std::{
|
|
|
|
io::{prelude::BufReadExt, BufReader, WriteExt},
|
|
|
|
net::TcpStream,
|
|
|
|
};
|
2023-04-25 01:26:27 +00:00
|
|
|
use mpdrs::lsinfo::LsInfoResponse;
|
|
|
|
|
2023-04-27 01:40:19 +00:00
|
|
|
pub(crate) fn host() -> String {
|
|
|
|
let host = std::env::var("MPD_HOST").unwrap_or("localhost".to_string());
|
|
|
|
let port = std::env::var("MPD_PORT").unwrap_or("6600".to_string());
|
|
|
|
format!("{host}:{port}")
|
|
|
|
}
|
2023-04-25 01:26:27 +00:00
|
|
|
|
2023-04-25 14:32:35 +00:00
|
|
|
pub(crate) fn connect() -> Result<mpdrs::Client, mpdrs::error::Error> {
|
2023-04-27 01:40:19 +00:00
|
|
|
mpdrs::Client::connect(host())
|
2023-04-25 14:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn ls(path: &str) -> anyhow::Result<Vec<Entry>> {
|
|
|
|
let info = connect()?.lsinfo(path)?;
|
2023-04-25 01:26:27 +00:00
|
|
|
|
2023-04-25 01:44:03 +00:00
|
|
|
fn filename(path: &str) -> Cow<str> {
|
|
|
|
std::path::Path::new(path)
|
|
|
|
.file_name()
|
|
|
|
.map(|x| x.to_string_lossy())
|
|
|
|
.unwrap_or(Cow::Borrowed("n/a"))
|
|
|
|
}
|
|
|
|
|
2023-04-25 01:26:27 +00:00
|
|
|
Ok(info
|
|
|
|
.iter()
|
|
|
|
.map(|e| match e {
|
|
|
|
LsInfoResponse::Song(song) => Entry::Song {
|
|
|
|
name: song.title.as_ref().unwrap_or(&song.file).clone(),
|
|
|
|
artist: song.artist.clone().unwrap_or(String::new()),
|
|
|
|
path: song.file.clone(),
|
|
|
|
},
|
|
|
|
|
2023-04-25 14:32:35 +00:00
|
|
|
LsInfoResponse::Directory { path, .. } => Entry::Directory {
|
|
|
|
name: filename(path).to_string(),
|
|
|
|
path: path.to_string(),
|
|
|
|
},
|
2023-04-25 01:26:27 +00:00
|
|
|
|
|
|
|
LsInfoResponse::Playlist { path, .. } => Entry::Playlist {
|
2023-04-25 01:44:03 +00:00
|
|
|
name: filename(path).to_string(),
|
2023-04-25 01:26:27 +00:00
|
|
|
path: path.to_string(),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.collect())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct QueueItem {
|
2023-04-27 01:40:19 +00:00
|
|
|
pub(crate) file: String,
|
2023-04-25 01:26:27 +00:00
|
|
|
pub(crate) title: String,
|
2023-04-27 01:40:19 +00:00
|
|
|
pub(crate) artist: Option<String>,
|
2023-04-25 01:26:27 +00:00
|
|
|
pub(crate) playing: bool,
|
|
|
|
}
|
|
|
|
|
2023-04-25 14:32:35 +00:00
|
|
|
pub(crate) fn playlist() -> anyhow::Result<Vec<QueueItem>> {
|
|
|
|
let mut client = connect()?;
|
2023-04-25 01:26:27 +00:00
|
|
|
|
|
|
|
let current = client.status()?.song;
|
|
|
|
|
|
|
|
let queue = client
|
|
|
|
.queue()?
|
|
|
|
.into_iter()
|
|
|
|
.map(|song| QueueItem {
|
2023-04-27 01:40:19 +00:00
|
|
|
file: song.file.clone(),
|
2023-04-25 01:26:27 +00:00
|
|
|
title: song.title.as_ref().unwrap_or(&song.file).clone(),
|
2023-04-27 01:40:19 +00:00
|
|
|
artist: song.artist.clone(),
|
2023-04-25 01:26:27 +00:00
|
|
|
playing: current == song.place,
|
|
|
|
})
|
|
|
|
.collect();
|
2023-04-25 14:32:35 +00:00
|
|
|
|
2023-04-25 01:26:27 +00:00
|
|
|
Ok(queue)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) enum Entry {
|
|
|
|
Song {
|
|
|
|
name: String,
|
|
|
|
artist: String,
|
|
|
|
path: String,
|
|
|
|
},
|
|
|
|
Directory {
|
|
|
|
name: String,
|
|
|
|
path: String,
|
|
|
|
},
|
|
|
|
Playlist {
|
|
|
|
name: String,
|
|
|
|
path: String,
|
|
|
|
},
|
|
|
|
}
|
2023-05-01 14:13:08 +00:00
|
|
|
|
|
|
|
pub(crate) async fn idle(systems: &[&str]) -> anyhow::Result<Vec<String>> {
|
|
|
|
let mut stream = TcpStream::connect(host()).await?;
|
|
|
|
let mut reader = BufReader::new(stream.clone());
|
|
|
|
|
|
|
|
// skip OK MPD line
|
|
|
|
// TODO check if it is indeed OK
|
|
|
|
let mut buffer = String::new();
|
|
|
|
reader.read_line(&mut buffer).await?;
|
|
|
|
|
|
|
|
let systems = systems.join(" ");
|
|
|
|
let command = format!("idle {systems}\n");
|
|
|
|
stream.write_all(command.as_bytes()).await?;
|
|
|
|
|
|
|
|
let mut updated = vec![];
|
|
|
|
loop {
|
|
|
|
buffer.clear();
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|