big overhaul

This commit is contained in:
Djairo Hougee 2023-05-09 13:41:54 +02:00
parent 3be9b6ccea
commit ecfbe8f147
7 changed files with 87 additions and 72 deletions

View File

@ -8,20 +8,26 @@ use structs::{config::Config, data::Data};
use crate::update_players::update_players; use crate::update_players::update_players;
use crate::update_message::update_message; use crate::update_message::update_message;
use crate::print_text::print_text; use crate::print_text::print_text;
use crate::print_players::print_players;
mod update_players; mod update_players;
mod update_message; mod update_message;
mod print_text; mod print_text;
mod structs; mod structs;
mod print_players;
fn handle_signal(data: &Data, pf: &PlayerFinder) { fn handle_signal(data: &Data) {
if data.current_player.is_some() { if let Some(p) = &data.current_player {
if let Ok(p) = pf.find_by_name(data.current_player.as_ref().unwrap()) { let _ = p.checked_play_pause();
let _ = p.checked_play_pause();
}
} }
} }
fn default_loop(pf: &PlayerFinder, cfg: &Config, data: &mut Data) {
update_players(pf, cfg, data);
update_message(cfg, data);
print_text(cfg, data);
}
fn main() { fn main() {
//dotenvy::dotenv().expect("Failed to read .env file"); //dotenvy::dotenv().expect("Failed to read .env file");
std::env::set_var("RUST_LOG", "error"); std::env::set_var("RUST_LOG", "error");
@ -44,11 +50,13 @@ fn main() {
loop { loop {
thread::sleep(cfg.update_delay); thread::sleep(cfg.update_delay);
update_players(&pf, &cfg, &mut data); match cli.debug {
update_message(&pf, &cfg, &mut data); true => print_players(&pf),
print_text(&cfg, &mut data); false => default_loop(&pf, &cfg, &mut data),
if term.load(Ordering::Relaxed) { }
handle_signal(&data, &pf);
if term.load(Ordering::Relaxed) {
handle_signal(&data);
term.swap(false, Ordering::Relaxed); term.swap(false, Ordering::Relaxed);
}; };
} }

17
src/print_players.rs Normal file
View File

@ -0,0 +1,17 @@
use mpris::PlayerFinder;
pub fn print_players(pf: &PlayerFinder) {
match pf.find_all() {
Ok(players) => {
if players.is_empty() {
println!("No players found!");
} else {
for player in players {
println!("{}", player.identity());
}
}
},
Err(e) => println!("{}", e),
}
}

View File

@ -8,4 +8,9 @@ pub struct Cli {
/// The name of the config file to use. /// The name of the config file to use.
#[arg(short = 'c', long = "config", default_value = "default")] #[arg(short = 'c', long = "config", default_value = "default")]
pub config_file: String, pub config_file: String,
/// Enable debug mod.
///
/// This mode prints all active players to stdout, to allow one to find the appropriate player names to use in the config files.
#[arg(short = 'd', long = "debug")]
pub debug: bool,
} }

View File

@ -86,7 +86,7 @@ impl Config {
pub fn find_player_priorities_idx(&self, name: &str) -> i32 { pub fn find_player_priorities_idx(&self, name: &str) -> i32 {
match self.player_priorities.iter() match self.player_priorities.iter()
.position(|x| x.to_ascii_lowercase().eq(&name.to_ascii_lowercase())) { .position(|x| x.eq(&name)) {
Some(idx) => idx as i32, Some(idx) => idx as i32,
None => i32::MAX, None => i32::MAX,
} }
@ -97,6 +97,8 @@ fn ms(str: &str) -> String {
str.to_string() str.to_string()
} }
// FIXME: changed some functions to use case-sensitive matching instead, breaking this
// and also all my existing config files. Whoops
fn default_player_prefixes() -> HashMap<String, char> { fn default_player_prefixes() -> HashMap<String, char> {
let mut out: HashMap<String, char> = HashMap::new(); let mut out: HashMap<String, char> = HashMap::new();

View File

@ -1,7 +1,9 @@
use std::collections::HashMap; use std::collections::HashMap;
use mpris::Player;
pub struct Data { pub struct Data {
pub current_player: Option<String>, pub current_player: Option<Player>,
pub display_text: HashMap<String, String>, pub display_text: HashMap<String, String>,
pub display_prefix: char, pub display_prefix: char,
} }

View File

@ -1,22 +1,7 @@
use log::{debug, trace}; use mpris::{MetadataValue};
use mpris::{PlayerFinder, MetadataValue};
use crate::structs::{config::{Rating, Config}, data::Data}; use crate::structs::{config::{Rating, Config}, data::Data};
fn update_prefix(cfg: &Config, data: &mut Data) {
if data.current_player.is_some() {
let c = cfg.player_prefixes.get(&data.current_player.as_ref().unwrap().to_ascii_lowercase());
if let Some(char) = c {
data.display_prefix = char.clone();
trace!("updated prefix to {}", data.display_prefix);
} else {
data.display_prefix = cfg.player_prefixes.get("default").unwrap_or(&'>').clone();
trace!("set prefix to default ({})", data.display_prefix);
}
}
}
fn value_to_string(v: &MetadataValue, sep: char) -> String { fn value_to_string(v: &MetadataValue, sep: char) -> String {
match v { match v {
MetadataValue::String(v) => v.to_string(), MetadataValue::String(v) => v.to_string(),
@ -72,36 +57,22 @@ fn rating_to_string(r: Option<&MetadataValue>, map: &Rating) -> Option<String> {
} }
} }
pub fn update_message(pf: &PlayerFinder, cfg: &Config, data: &mut Data) { pub fn update_message(cfg: &Config, data: &mut Data) {
if data.current_player.is_some() { if let Some(player) = &data.current_player {
update_prefix(cfg, data); if let Ok(meta) = player.get_metadata() {
let name = &data.current_player.as_ref().unwrap(); for field in &cfg.metadata_fields {
if let Ok(player) = pf.find_by_name(name) { let key = field.field.clone();
debug!("found player!"); if field.field.eq("xesam:userRating") {
if let Ok(m) = player.get_metadata() { if let Some(rating_string) = rating_to_string(meta.get(&key), &cfg.rating_icons) {
debug!("got metadata!"); data.display_text.insert(key, rating_string);
for field in &cfg.metadata_fields {
if field.field.eq("xesam:userRating") || field.field.eq("xesam:autoRating") {
let key = field.field.clone();
let string = rating_to_string(m.get(&key), &cfg.rating_icons);
if let Some(str) = string {
data.display_text.insert(key, str);
} else {
data.display_text.remove(&key);
}
} else { } else {
let key = field.field.clone(); data.display_text.remove(&key);
match m.get(&key) {
Some(value) => {
debug!("inserting {}: '{}'", key, value_to_string(value, cfg.array_separator));
data.display_text.insert(key, value_to_string(value, cfg.array_separator));
},
None => {
debug!("field {} is empty!", key);
data.display_text.insert(key, format!("No {}", field.field.clone().trim_start_matches("xesam:")));
},
}
} }
} else {
match meta.get(&key) {
Some(value) => data.display_text.insert(key, value_to_string(value, cfg.array_separator)),
None => data.display_text.insert(key, format!("No {}", field.field.clone().trim_start_matches("xesam:"))),
};
} }
} }
} }

View File

@ -1,6 +1,17 @@
use mpris::PlayerFinder; use log::trace;
use mpris::{PlayerFinder, Metadata, Player};
use crate::structs::{data::Data, config::Config}; use crate::structs::{data::Data, config::Config};
fn update_prefix(cfg: &Config, data: &mut char, name: &str) {
if let Some(char) = cfg.player_prefixes.get(name) {
*data = char.clone();
trace!("updated prefix to {}", data);
} else {
*data = cfg.player_prefixes.get("default").unwrap_or(&'>').clone();
trace!("set prefix to default ({})", data);
}
}
pub fn update_players( pub fn update_players(
pf: &PlayerFinder, pf: &PlayerFinder,
cfg: &Config, cfg: &Config,
@ -10,31 +21,30 @@ pub fn update_players(
if players.is_empty() { if players.is_empty() {
data.current_player = None; data.current_player = None;
} else { } else {
let mut active: Vec<(i32, String)> = Vec::new(); let mut active: Vec<(i32, Player)> = Vec::new();
for player in players { for player in players {
if let Ok(mpris::PlaybackStatus::Playing) = player.get_playback_status() { if let Ok(mpris::PlaybackStatus::Playing) = player.get_playback_status() {
let name = player.identity(); let idx = cfg.find_player_priorities_idx(player.identity());
let idx = cfg.find_player_priorities_idx(name); active.push((idx, player));
active.push((idx, name.to_owned()));
} }
} }
if !active.is_empty() { if !active.is_empty() {
data.current_player = Some(get_lowest(&active)); let cur = get_lowest(&mut active);
update_prefix(cfg, &mut data.display_prefix, cur.identity());
data.current_player = Some(cur);
} else { } else {
data.current_player = None; data.current_player = None;
} }
} }
} }
fn get_lowest(v: &Vec<(i32, String)>) -> String { fn get_lowest(v: &mut Vec<(i32, Player)>) -> Player {
let mut out = String::new(); let mut lowest_index = i32::MAX; //FIXME: use options here instead, also fixes a bug
let mut lowest_index = i32::MAX; for (v_id, _) in v.into_iter() {
for (v_id, v_str) in v.iter() { if v_id < &mut lowest_index {
if v_id < &lowest_index {
out = v_str.to_owned();
lowest_index = *v_id; lowest_index = *v_id;
} }
} }
out v.swap_remove(lowest_index as usize).1
} }