gdritter repos knurling / master src / widgets / mpd.rs
master

Tree @master (Download .tar.gz)

mpd.rs @masterraw · history · blame

use crate::widgets::widget::{Drawing, Located, Widget};

use std::io::{BufRead, BufReader, Write};
use std::net::TcpStream;

pub struct MPD {
    host: String,
    port: usize,
    last_state: State,
}

enum State {
    Playing(String),
    Stopped,
}

impl MPD {
    pub fn new(host: String, port: usize) -> MPD {
        let last_state = State::Stopped;
        MPD {
            host,
            port,
            last_state,
        }
    }

    fn get_song(&self) -> Result<State, failure::Error> {
        let mut stream = TcpStream::connect(format!("{}:{}", self.host, self.port))?;

        let mut buf = String::new();
        BufReader::new(&stream).read_line(&mut buf)?;
        if !buf.starts_with("OK MPD") {
            return Err(format_err!("Unable to connect to MPD"));
        }
        buf.clear();

        stream.write(b"currentsong\n")?;
        let mut title = None;
        let mut artist = None;

        for l in BufReader::new(&stream).lines() {
            let line = l?;
            if line == "OK" {
                break;
            }

            if line.starts_with("Title") {
                if let Some(idx) = line.find(": ") {
                    title = line.get((idx + 2)..).map(|s| s.to_string());
                }
            }

            if line.starts_with("Artist") {
                if let Some(idx) = line.find(": ") {
                    artist = line.get((idx + 2)..).map(|s| s.to_string());
                }
            }
        }

        if let (Some(artist), Some(title)) = (artist, title) {
            Ok(State::Playing(format!("{}: {}", artist, title)))
        } else {
            Ok(State::Stopped)
        }
    }
}

impl Widget for MPD {
    fn draw(&self, d: &Drawing, loc: Located) -> i32 {
        match self.last_state {
            State::Playing(ref song) => loc.draw_text(d, &format!("[{}]", song)),
            State::Stopped => loc.draw_text(d, &format!("[N/A]")),
        }
    }

    fn update_frequency(&self) -> Option<u64> {
        Some(5)
    }

    fn update(&mut self) {
        match self.get_song() {
            Ok(state) => self.last_state = state,
            Err(err) => eprintln!("Failed to update MPD status: {}", err),
        }
    }
}