gdritter repos knurling / ae2ab0a
Add MPD now playing widget Getty Ritter 3 years ago
2 changed file(s) with 77 addition(s) and 1 deletion(s). Collapse all Expand all
11 pub mod battery;
2 pub mod mpd;
23 pub mod standard;
34 pub mod widget;
45
56 pub use crate::widgets::widget::{Located,Drawing,Size,Widget};
67
7 const ALL_WIDGETS: [(&str, &dyn Fn(&toml::map::Map<String, toml::Value>) -> Result<Box<dyn Widget>, failure::Error>); 5] = [
8 const ALL_WIDGETS: [(&str, &dyn Fn(&toml::map::Map<String, toml::Value>) -> Result<Box<dyn Widget>, failure::Error>); 6] = [
89 ("box", &|_| Ok(Box::new(standard::Time::new()))),
910 ("battery", &|_| Ok(Box::new(battery::Battery::new()?))),
1011 ("caesura", &|_| Ok(Box::new(standard::Caesura))),
12 ("mpd", &|config| {
13 let host = config["host"].as_str().ok_or_else(|| format_err!("MPD host should be a string"))?;
14 let port = config["port"].as_integer().ok_or_else(|| format_err!("MPD port should be an integer"))?;
15 Ok(Box::new(mpd::MPD::new(host.to_string(), port as usize)))
16 }),
1117 ("stdin", &|_| Ok(Box::new(standard::Stdin::new()))),
1218 ("time", &|_| Ok(Box::new(standard::Time::new()))),
1319 ];
1 use crate::widgets::widget::{Widget,Drawing,Located};
2
3 use std::io::{Write, BufRead, BufReader};
4 use std::net::TcpStream;
5
6 pub struct MPD {
7 host: String,
8 port: usize,
9 }
10
11 enum State {
12 Playing(String),
13 Stopped,
14 }
15
16 impl MPD {
17 pub fn new(host: String, port: usize) -> MPD {
18 MPD {host, port}
19 }
20
21 fn get_song(&self) -> Result<State, failure::Error> {
22 let mut stream = TcpStream::connect(format!("{}:{}", self.host, self.port))?;
23
24 let mut buf = String::new();
25 BufReader::new(&stream).read_line(&mut buf)?;
26 if !buf.starts_with("OK MPD") {
27 return Err(format_err!("Unable to connect to MPD"));
28 }
29 buf.clear();
30
31 stream.write(b"currentsong\n")?;
32 let mut title = None;
33 let mut artist = None;
34
35 for l in BufReader::new(&stream).lines() {
36 let line = l?;
37 if line == "OK" {
38 break;
39 }
40
41 if line.starts_with("Title") {
42 if let Some(idx) = line.find(": ") {
43 title = line.get((idx + 2)..).map(|s| s.to_string());
44 }
45 }
46
47 if line.starts_with("Artist") {
48 if let Some(idx) = line.find(": ") {
49 artist = line.get((idx + 2)..).map(|s| s.to_string());
50 }
51 }
52 }
53
54 if let (Some(artist), Some(title)) = (artist, title) {
55 Ok(State::Playing(format!("{}: {}", artist, title)))
56 } else {
57 Ok(State::Stopped)
58 }
59 }
60 }
61
62 impl Widget for MPD {
63 fn draw(&self, d: &Drawing, loc: Located) -> i32 {
64 match self.get_song() {
65 Ok(State::Playing(song)) => loc.draw_text(d, &format!("[{}]", song)),
66 Ok(State::Stopped) => loc.draw_text(d, &format!("[N/A]")),
67 Err(_err) => loc.draw_text(d, &format!("[Error]")),
68 }
69 }
70 }