223 lines
6.3 KiB
Rust
223 lines
6.3 KiB
Rust
extern crate libnotify;
|
|
extern crate mpd;
|
|
|
|
use libnotify::Notification;
|
|
use mpd::{Client, Query, Song, State, Term};
|
|
use std::{env, time::Duration};
|
|
|
|
pub trait Noise {
|
|
fn find(&mut self, query: &Vec<String>, max: Option<u32>, append: bool);
|
|
fn search(&mut self, query: &Vec<String>, max: Option<u32>);
|
|
fn crossfade(&mut self, seconds: Option<i64>);
|
|
fn play(&mut self, track: Option<u32>);
|
|
fn toggle(&mut self);
|
|
fn munch(&mut self);
|
|
fn length(&mut self);
|
|
fn vol(&mut self, percentage: Option<i8>);
|
|
fn toggle_consume(&mut self);
|
|
fn toggle_repeat(&mut self);
|
|
fn toggle_random(&mut self);
|
|
fn toggle_single(&mut self);
|
|
fn shuf(&mut self);
|
|
fn get_status(&mut self, verbose: bool) -> String;
|
|
fn list_queue(&mut self, file: bool, _verbose: bool);
|
|
}
|
|
|
|
impl Noise for Client {
|
|
fn find(&mut self, query: &Vec<String>, max: Option<u32>, append: bool) {
|
|
let query = query.join(" ");
|
|
let max = max.unwrap_or(self.stats().unwrap().songs);
|
|
|
|
if append {
|
|
self.findadd(&Query::new().and(Term::Any, query)).unwrap();
|
|
} else {
|
|
self.find(&Query::new().and(Term::Any, query), (0, max))
|
|
.unwrap()
|
|
.iter()
|
|
.for_each(|x| println!("{}", x.file));
|
|
}
|
|
}
|
|
|
|
fn search(&mut self, query: &Vec<String>, max: Option<u32>) {
|
|
let query = query.join(" ");
|
|
let max = max.unwrap_or(self.stats().unwrap().songs);
|
|
|
|
self.search(&Query::new().and(Term::Any, query), (0, max))
|
|
.unwrap()
|
|
.iter()
|
|
.for_each(|x| println!("{}", x.file));
|
|
}
|
|
|
|
fn crossfade(&mut self, seconds: Option<i64>) {
|
|
if let Some(seconds) = seconds {
|
|
self.crossfade(seconds).unwrap();
|
|
} else {
|
|
println!(
|
|
"Crossfade: {}",
|
|
self.status()
|
|
.unwrap()
|
|
.crossfade
|
|
.map_or("Disabled".into(), |d| d.as_secs().to_string())
|
|
)
|
|
}
|
|
}
|
|
|
|
fn play(&mut self, track: Option<u32>) {
|
|
if let Some(i) = track {
|
|
self.switch(i).unwrap();
|
|
} else {
|
|
self.play().unwrap();
|
|
}
|
|
}
|
|
|
|
fn toggle(&mut self) {
|
|
if self.status().unwrap().state == State::Stop {
|
|
self.play().unwrap();
|
|
} else {
|
|
self.toggle_pause().unwrap();
|
|
}
|
|
}
|
|
|
|
fn munch(&mut self) {
|
|
let current_song = self.currentsong().unwrap().unwrap().place.unwrap();
|
|
self.delete(current_song.pos).unwrap();
|
|
}
|
|
|
|
fn length(&mut self) {
|
|
let length = self.status().unwrap().queue_len;
|
|
println!("{length}");
|
|
}
|
|
|
|
fn vol(&mut self, percentage: Option<i8>) {
|
|
if let Some(volume) = percentage {
|
|
self.volume(volume).unwrap()
|
|
}
|
|
let vol = self.status().unwrap().volume;
|
|
println!("Volume at {vol}%")
|
|
}
|
|
|
|
fn toggle_consume(&mut self) {
|
|
let consume_state = self.status().unwrap().consume;
|
|
self.consume(!consume_state).unwrap();
|
|
}
|
|
|
|
fn toggle_repeat(&mut self) {
|
|
let repeat_state = self.status().unwrap().repeat;
|
|
self.repeat(!repeat_state).unwrap();
|
|
}
|
|
|
|
fn toggle_random(&mut self) {
|
|
let random_state = self.status().unwrap().random;
|
|
self.random(!random_state).unwrap();
|
|
}
|
|
|
|
fn toggle_single(&mut self) {
|
|
let single_state = self.status().unwrap().single;
|
|
self.single(!single_state).unwrap();
|
|
}
|
|
|
|
fn shuf(&mut self) {
|
|
send_notification("Shuffling queueueu...");
|
|
println!("Shuffling queueueu...");
|
|
self.shuffle(..).unwrap();
|
|
}
|
|
|
|
fn list_queue(&mut self, file: bool, _verbose: bool) {
|
|
self.queue().unwrap().iter().for_each(|x| {
|
|
println!(
|
|
"{:<02} {}",
|
|
x.place.unwrap().pos,
|
|
if file {
|
|
x.file.clone()
|
|
} else {
|
|
format_song(x.clone())
|
|
}
|
|
)
|
|
});
|
|
}
|
|
|
|
fn get_status(&mut self, verbose: bool) -> String {
|
|
let current_song = if let Some(song) = self.currentsong().unwrap() {
|
|
format_song(song)
|
|
} else {
|
|
"No song playing".into()
|
|
};
|
|
send_notification(¤t_song);
|
|
|
|
if !verbose {
|
|
return current_song;
|
|
}
|
|
|
|
let mut output = Vec::with_capacity(3);
|
|
|
|
output.push(current_song);
|
|
|
|
let status = self.status().unwrap();
|
|
|
|
let fmt = |x| match x {
|
|
true => "On",
|
|
false => "Off",
|
|
};
|
|
|
|
output.push(format!(
|
|
"volume: {vol:<6} repeat: {repeat:<6} random: {rnd:<6} single: {single:<6} consume: {consume:<6}",
|
|
vol = format!("{}%", status.volume),
|
|
repeat = fmt(status.repeat),
|
|
rnd = fmt(status.random),
|
|
single = fmt(status.single),
|
|
consume = fmt(status.consume)
|
|
));
|
|
|
|
let state = match status.state {
|
|
State::Stop => "stopped",
|
|
State::Pause => "paused",
|
|
State::Play => "playing",
|
|
};
|
|
|
|
fn to_mins_string(dur: Duration) -> String {
|
|
let seconds = dur.as_secs();
|
|
|
|
let minutes = seconds / 60;
|
|
let rem_seconds = seconds % 60;
|
|
|
|
format!("{minutes:02}:{rem_seconds:02}")
|
|
}
|
|
|
|
let duration = status.time.map_or("".into(), |(stamp, total)| {
|
|
let stamp = to_mins_string(stamp);
|
|
let total = to_mins_string(total);
|
|
format!("{stamp}/{total}")
|
|
});
|
|
|
|
// let pos_in_queue = format!("{current_pos}/{queue_lenth}");
|
|
|
|
output.push(format!("[{state}] {duration}"));
|
|
|
|
output.join("\n")
|
|
}
|
|
}
|
|
|
|
fn format_song(song: Song) -> String {
|
|
format!(
|
|
"{} - {}",
|
|
song.artist.unwrap_or("Unknown".into()),
|
|
song.title.unwrap()
|
|
)
|
|
}
|
|
|
|
// fn get_status(client: &mut Client, verbose: bool) -> String {}
|
|
|
|
fn send_notification(body: &str) {
|
|
let key = "XDG_SESSION_TYPE";
|
|
match env::var(key) {
|
|
Ok(key) => {
|
|
if key != "tty" {
|
|
libnotify::init("noise").unwrap();
|
|
let notify = Notification::new("Noise", Some(body), None);
|
|
notify.show().unwrap();
|
|
libnotify::uninit();
|
|
}
|
|
}
|
|
Err(_) => return,
|
|
}
|
|
}
|