Krolyxon
Commit 579b09b

rmptui579b09b

add dmenu selector

Author
krolxon
Date
2024-04-22 13:02 +0530
Parent
e5e6928
Commit
579b09b61dd15776244a060d99e7d704eb651c33

+108 −43

4 files changed

  1. M Cargo.lock +7 −0
  2. M Cargo.toml +1 −0
  3. M src/connection.rs +78 −41
  4. M src/main.rs +22 −2
M Cargo.lock View
@@ -142,6 +142,7 @@ dependencies = [
142142 "clap",
143143 "mpd",
144144 "rust_fzf",
145+ "simple-dmenu",
145146 ]
146147
147148 [[package]]
@@ -150,6 +151,12 @@ version = "0.3.1"
150151 source = "registry+https://github.com/rust-lang/crates.io-index"
151152 checksum = "76a94b9c6a9880356cc6de038a52397509f8ac86a18c30d76da904b08fec2cb1"
152153
154+[[package]]
155+name = "simple-dmenu"
156+version = "0.1.0"
157+source = "registry+https://github.com/rust-lang/crates.io-index"
158+checksum = "2f392360283341235b298e79f0360bd924db6e6ad1e0964cbf4c43ea79c237eb"
159+
153160 [[package]]
154161 name = "strsim"
155162 version = "0.11.1"
M Cargo.toml View
@@ -9,3 +9,4 @@ edition = "2021"
99 mpd = "0.1.0"
1010 clap = { version = "4.0.29", features = ["derive"] }
1111 rust_fzf = "0.3.1"
12+simple-dmenu = "0.1.0"
M src/connection.rs View
@@ -1,66 +1,53 @@
11 use mpd::song::Song;
22 use mpd::Client;
3+use simple_dmenu::dmenu;
4+use std::process::Command;
35
46 pub struct Connection {
57 pub conn: Client,
8+ pub songs_filenames: Vec<String>,
69 }
710
811 impl Connection {
912 pub fn new(addrs: &str) -> Result<Self, mpd::error::Error> {
10− let conn = Client::connect(addrs)?;
11− Ok(Self { conn })
13+ let mut conn = Client::connect(addrs)?;
14+ let mut songs_filenames: Vec<String> = Vec::new();
15+ get_file_tree_into_vec(&mut conn, &mut songs_filenames, ".", ".");
16+
17+ Ok(Self {
18+ conn,
19+ songs_filenames,
20+ })
1221 }
1322
1423 pub fn play_fzf(&mut self) {
15− let mut ss: Vec<String> = Vec::new();
16− self.get_file_tree_into_vec(&mut ss, ".", ".");
17−
18− let choice: usize;
24+ let ss = &self.songs_filenames;
1925 let fzf_choice = rust_fzf::select(ss.clone(), Vec::new()).unwrap();
20− if let Some(index) = ss.iter().position(|s| s == fzf_choice.get(0).unwrap()) {
21− choice = index;
22− } else {
23− return;
24− }
26+ let index = get_choice_index(&self.songs_filenames, fzf_choice.get(0).unwrap());
27+ let song = self.get_song_with_only_filename(ss.get(index).unwrap());
28+ self.push(&song);
29+ }
2530
26− let song = self.get_song(ss.get(choice).unwrap());
31+ pub fn play_dmenu(&mut self) {
32+ let ss: Vec<&str> = self.songs_filenames.iter().map(|x| x.as_str()).collect();
33+ let op = dmenu!(iter &ss; args "-l", "30");
34+ let index = get_choice_index(&self.songs_filenames, &op);
35+ let song = self.get_song_with_only_filename(ss.get(index).unwrap());
36+ self.push(&song);
37+ }
2738
39+ fn push(&mut self, song: &Song) {
40+ self.conn.push(song).unwrap();
2841 if self.conn.queue().unwrap().is_empty() {
29− self.push(song);
42+ self.conn.push(song).unwrap();
3043 self.conn.play().unwrap();
3144 } else {
32− self.push(song);
45+ self.conn.push(song).unwrap();
3346 self.conn.next().unwrap();
3447 }
3548 }
3649
37− fn get_file_tree_into_vec(&mut self, vec: &mut Vec<String>, path: &str, dir_append: &str) {
38− let songs = self.conn.listfiles(path).unwrap_or_default();
39− for (i, s) in songs {
40− // Output of listfiles contains the last-modified thing, we dont want that
41− if i != "Last-Modified" {
42− if i == "directory" {
43− self.get_file_tree_into_vec(vec, &s, &s);
44− } else {
45− // We parse the string as float because the output of listfiles contains some random numbers, we dont want that
46− if !s.parse::<f32>().is_ok() {
47− let mut sam: String = String::new();
48− sam.push_str(dir_append);
49− sam.push_str(r"/");
50− sam.push_str(s.as_str());
51− vec.push(sam);
52− }
53− }
54− }
55− }
56− }
57−
58− fn push(&mut self, song: Song) {
59− self.conn.push(song).unwrap();
60−
61− }
62−
63− fn get_song(&self, filename: &str) -> Song {
50+ fn get_song_with_only_filename(&self, filename: &str) -> Song {
6451 Song {
6552 file: filename.to_string(),
6653 artist: None,
@@ -89,4 +76,54 @@ impl Connection {
8976 status.volume, status.repeat, status.random, status.single, status.consume
9077 );
9178 }
79+
80+ // Play controls
81+ pub fn pause(&mut self) {
82+ self.conn.pause(true).unwrap();
83+ }
84+
85+ pub fn toggle_pause(&mut self) {
86+ self.conn.toggle_pause().unwrap();
87+ }
88+
89+ // Volume controls
90+ pub fn inc_volume(&mut self, inc: i8) {
91+ let cur = self.conn.status().unwrap().volume;
92+ self.conn.volume(cur + inc).unwrap();
93+ }
94+
95+ pub fn dec_volume(&mut self, dec: i8) {
96+ let cur = self.conn.status().unwrap().volume;
97+ self.conn.volume(cur - dec).unwrap();
98+ }
99+}
100+
101+fn get_file_tree_into_vec(conn: &mut Client, vec: &mut Vec<String>, path: &str, dir_append: &str) {
102+ let songs = conn.listfiles(path).unwrap_or_default();
103+ for (i, s) in songs {
104+ // Output of listfiles contains the last-modified thing, we dont want that
105+ if i != "Last-Modified" {
106+ if i == "directory" {
107+ get_file_tree_into_vec(conn, vec, &s, &s);
108+ } else {
109+ // We parse the string as float because the output of listfiles contains some random numbers, we dont want that
110+ if !s.parse::<f32>().is_ok() {
111+ let mut sam: String = String::new();
112+ sam.push_str(dir_append);
113+ sam.push_str(r"/");
114+ sam.push_str(s.as_str());
115+ vec.push(sam);
116+ }
117+ }
118+ }
119+ }
120+}
121+
122+fn get_choice_index(ss: &Vec<String>, selection: &str) -> usize {
123+ let mut choice: usize = 0;
124+ if let Some(index) = ss.iter().position(|s| s == selection) {
125+ choice = index;
126+ }
127+
128+ choice
92129 }
M src/main.rs View
@@ -5,29 +5,49 @@ use connection::Connection;
55 #[derive(Parser, Debug)]
66 #[command(version, about, long_about = None)]
77 struct Args {
8− /// Ignore case in search
8+ /// pause
99 #[arg(short, long, default_value = "false")]
1010 pub pause: bool,
1111
12+ /// toggle pause
1213 #[arg(short, long, default_value = "false")]
1314 pub toggle_pause: bool,
1415
16+ /// show current status
1517 #[arg(short, long, default_value = "false")]
1618 pub show_status: bool,
1719
20+ /// use fzf selector for selecting songs
1821 #[arg(short, long, default_value = "false")]
1922 pub fzf_select: bool,
23+
24+ /// use dmenu selector for selecting songss
25+ #[arg(short, long, default_value = "false")]
26+ pub dmenu_select: bool,
2027 }
2128
2229 fn main() -> Result<(), Box<dyn std::error::Error>> {
2330 let args = Args::parse();
2431 let mut conn = Connection::new("127.0.0.1:6600")?;
32+
2533 if args.show_status {
2634 conn.status();
2735 }
2836
37+ if args.toggle_pause {
38+ conn.toggle_pause();
39+ }
40+
41+ if args.pause {
42+ conn.pause();
43+ }
44+
2945 if args.fzf_select {
30− conn.play_fzf()
46+ conn.play_fzf();
47+ }
48+
49+ if args.dmenu_select {
50+ conn.play_dmenu();
3151 }
3252
3353 Ok(())