Krolyxon
Commit a0582ea

rmptuisrcconnection.rs

144 lines · 4.0 KB · Rust

1use mpd::song::Song;
2use mpd::{Client, State};
3use simple_dmenu::dmenu;
4use std::process::Command;
5
6pub type Result<T> = core::result::Result<T, Error>;
7pub type Error = Box<dyn std::error::Error>;
8
9#[derive(Debug)]
10pub struct Connection {
11 pub conn: Client,
12 pub songs_filenames: Vec<String>,
13}
14
15impl Connection {
16 pub fn new(addrs: &str) -> Result<Self> {
17 let mut conn = Client::connect(addrs).unwrap();
18 let songs_filenames: Vec<String> = conn
19 .listall()
20 .unwrap()
21 .into_iter()
22 .map(|x| x.file)
23 .collect();
24
25 Ok(Self {
26 conn,
27 songs_filenames,
28 })
29 }
30
31 pub fn play_fzf(&mut self) -> Result<()> {
32 is_installed("fzf").map_err(|ex| ex)?;
33
34 let ss = &self.songs_filenames;
35 let fzf_choice = rust_fzf::select(ss.clone(), Vec::new()).unwrap();
36 let index = get_choice_index(&self.songs_filenames, fzf_choice.get(0).unwrap());
37 let song = self.get_song_with_only_filename(ss.get(index).unwrap());
38 self.push(&song)?;
39
40 Ok(())
41 }
42
43 pub fn play_dmenu(&mut self) -> Result<()> {
44 is_installed("dmenu").map_err(|ex| ex)?;
45 let ss: Vec<&str> = self.songs_filenames.iter().map(|x| x.as_str()).collect();
46 let op = dmenu!(iter &ss; args "-l", "30");
47 let index = get_choice_index(&self.songs_filenames, &op);
48 let song = self.get_song_with_only_filename(ss.get(index).unwrap());
49 self.push(&song)?;
50 Ok(())
51 }
52
53 pub fn push(&mut self, song: &Song) -> Result<()> {
54 if self.conn.queue().unwrap().is_empty() {
55 self.conn.push(song).unwrap();
56 self.conn.play().unwrap();
57 } else {
58 self.conn.push(song).unwrap();
59 if self.conn.status().unwrap().state == State::Stop {
60 self.conn.play().unwrap();
61 }
62 self.conn.next().unwrap();
63 }
64
65 Ok(())
66 }
67
68 pub fn get_song_with_only_filename(&self, filename: &str) -> Song {
69 Song {
70 file: filename.to_string(),
71 artist: None,
72 title: None,
73 duration: None,
74 last_mod: None,
75 name: None,
76 place: None,
77 range: None,
78 tags: vec![("".to_string(), "".to_string())],
79 }
80 }
81
82 pub fn get_current_song(&mut self) -> Option<String> {
83 self.conn.currentsong().unwrap().unwrap_or_default().title
84
85 }
86 pub fn status(&mut self) {
87 let current_song = self.conn.currentsong();
88 let status = self.conn.status().unwrap();
89
90 if current_song.is_ok() && status.state != State::Stop {
91 let song = current_song.unwrap();
92 if let Some(s) = song {
93 println!("{} - {}", s.artist.unwrap(), s.title.unwrap());
94 }
95 }
96 println!(
97 "volume: {}\trepeat: {}\trandom: {}\tsingle: {}\tconsume: {}",
98 status.volume, status.repeat, status.random, status.single, status.consume
99 );
100 }
101
102 // Playback controls
103 pub fn pause(&mut self) {
104 self.conn.pause(true).unwrap();
105 }
106
107 pub fn toggle_pause(&mut self) {
108 self.conn.toggle_pause().unwrap();
109 }
110
111 // Volume controls
112 pub fn set_volume(&mut self, u: String) {
113 let cur = self.conn.status().unwrap().volume;
114 let sym = u.get(0..1).unwrap();
115 let u: i8 = u.parse::<i8>().unwrap();
116 if sym == "+" || sym == "-" {
117 self.conn.volume(cur + u).unwrap();
118 } else {
119 self.conn.volume(u).unwrap();
120 }
121 }
122}
123
124fn get_choice_index(ss: &Vec<String>, selection: &str) -> usize {
125 let mut choice: usize = 0;
126 if let Some(index) = ss.iter().position(|s| s == selection) {
127 choice = index;
128 }
129
130 choice
131}
132
133fn is_installed(ss: &str) -> Result<()> {
134 let output = Command::new("which")
135 .arg(ss)
136 .output()
137 .expect("Failed to execute command");
138 if output.status.success() {
139 Ok(())
140 } else {
141 let err = format!("{} not installed", ss);
142 Err(err.into())
143 }
144}