1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
extern crate notify_rust; use std::collections::HashMap; use notify_rust::Notification; const BREAK_TAG: &'static str = "!break!"; const VALID_TAGS: [&'static str; 11] = ["status", "url", "file", "artist", "album", "discnumber", "tracknumber", "title", "date", "duration", BREAK_TAG]; pub type Metadata = HashMap<String, String>; pub fn print_usage() { println!("You must set cmus to call this script as notifier"); } pub fn parse(cmus_data: String) -> Metadata { let mut result = Metadata::new(); let mut split_data: Vec<&str> = cmus_data.split(" ").collect(); split_data.push(BREAK_TAG); let mut last_tag_found: Option<&str> = None; let mut value_collector: Vec<&str> = vec![]; for part in split_data.iter() { if VALID_TAGS.contains(part) { if value_collector.len() > 0 { if let Some(tag) = last_tag_found { result.insert(tag.to_string(), value_collector.join(" ")); value_collector.clear(); } } last_tag_found = Some(part); continue; } value_collector.push(part); } result } pub fn format_notification_body(m: &Metadata) -> String { let mut notification_body = match m.get("title") { Some(t) => t.to_string(), None => "Unknown".to_string() }; if let Some(artist) = m.get("artist") { notification_body = format!("{} by {}", notification_body, artist); if let Some(album) = m.get("album") { notification_body = format!("{}, {}", notification_body, album); } } notification_body } pub trait Notifier { fn send(&self, summary: String, content: String); } pub struct DbusNotifier { } impl Notifier for DbusNotifier { fn send(&self, summary: String, content: String) { Notification::new() .summary(&summary) .body(&content) .show().unwrap(); } } pub fn run<T>(n: &T, cmus_data: String) where T: Notifier { let metadata = parse(cmus_data); let notification_body = format_notification_body(&metadata); n.send("Cmustify - Current song".to_string(), notification_body); } #[cfg(test)] mod tests { use super::*; use std::cell::RefCell; #[test] fn parse_cmus_data_correctly() { let cmus_data = "artist Todd album Reno title super song".to_string(); let result = parse(cmus_data); assert_eq!(result.get("artist").unwrap(), "Todd"); assert_eq!(result.get("album").unwrap(), "Reno"); assert_eq!(result.get("title").unwrap(), "super song"); } #[test] fn format_notification_body_correctly() { let mut metadata = Metadata::new(); metadata.insert("title".to_string(), "Super title".to_string()); metadata.insert("artist".to_string(), "Todd".to_string()); let notification_body = format_notification_body(&metadata); assert!(notification_body.contains("Super title")); assert!(notification_body.contains("Todd")); } #[test] fn run_send_notification() { struct NotifyMock { called: RefCell<bool> } impl Notifier for NotifyMock { fn send(&self, _summary: String, _content: String) { *self.called.borrow_mut() = true; } } let notifier_mock = NotifyMock { called: RefCell::new(false) }; let notification_body = "Hola".to_string(); run(¬ifier_mock, notification_body); assert!(*notifier_mock.called.borrow()) } }