big overhaul
This commit is contained in:
parent
3be9b6ccea
commit
ecfbe8f147
30
src/main.rs
30
src/main.rs
|
|
@ -8,20 +8,26 @@ use structs::{config::Config, data::Data};
|
|||
use crate::update_players::update_players;
|
||||
use crate::update_message::update_message;
|
||||
use crate::print_text::print_text;
|
||||
use crate::print_players::print_players;
|
||||
|
||||
mod update_players;
|
||||
mod update_message;
|
||||
mod print_text;
|
||||
mod structs;
|
||||
mod print_players;
|
||||
|
||||
fn handle_signal(data: &Data, pf: &PlayerFinder) {
|
||||
if data.current_player.is_some() {
|
||||
if let Ok(p) = pf.find_by_name(data.current_player.as_ref().unwrap()) {
|
||||
let _ = p.checked_play_pause();
|
||||
}
|
||||
fn handle_signal(data: &Data) {
|
||||
if let Some(p) = &data.current_player {
|
||||
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() {
|
||||
//dotenvy::dotenv().expect("Failed to read .env file");
|
||||
std::env::set_var("RUST_LOG", "error");
|
||||
|
|
@ -37,18 +43,20 @@ fn main() {
|
|||
|
||||
let pf: PlayerFinder = PlayerFinder::new()
|
||||
.expect("Failed to connect to Dbus!");
|
||||
|
||||
|
||||
if let Err(e) = signal_hook::flag::register(signal_hook::consts::SIGUSR1, Arc::clone(&term)) {
|
||||
panic!("{}", e);
|
||||
}
|
||||
|
||||
loop {
|
||||
thread::sleep(cfg.update_delay);
|
||||
update_players(&pf, &cfg, &mut data);
|
||||
update_message(&pf, &cfg, &mut data);
|
||||
print_text(&cfg, &mut data);
|
||||
if term.load(Ordering::Relaxed) {
|
||||
handle_signal(&data, &pf);
|
||||
match cli.debug {
|
||||
true => print_players(&pf),
|
||||
false => default_loop(&pf, &cfg, &mut data),
|
||||
}
|
||||
|
||||
if term.load(Ordering::Relaxed) {
|
||||
handle_signal(&data);
|
||||
term.swap(false, Ordering::Relaxed);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,13 @@ use clap::Parser;
|
|||
///
|
||||
/// Most configuration is done through config files.
|
||||
#[derive(Parser)]
|
||||
pub struct Cli {
|
||||
pub struct Cli {
|
||||
/// The name of the config file to use.
|
||||
#[arg(short = 'c', long = "config", default_value = "default")]
|
||||
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,
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ impl Config {
|
|||
|
||||
pub fn find_player_priorities_idx(&self, name: &str) -> i32 {
|
||||
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,
|
||||
None => i32::MAX,
|
||||
}
|
||||
|
|
@ -97,6 +97,8 @@ fn ms(str: &str) -> 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> {
|
||||
let mut out: HashMap<String, char> = HashMap::new();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use mpris::Player;
|
||||
|
||||
pub struct Data {
|
||||
pub current_player: Option<String>,
|
||||
pub current_player: Option<Player>,
|
||||
pub display_text: HashMap<String, String>,
|
||||
pub display_prefix: char,
|
||||
}
|
||||
|
|
@ -9,7 +11,7 @@ pub struct Data {
|
|||
impl Default for Data {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
current_player: None,
|
||||
current_player: None,
|
||||
display_text: HashMap::new(),
|
||||
display_prefix: ' ',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,7 @@
|
|||
use log::{debug, trace};
|
||||
use mpris::{PlayerFinder, MetadataValue};
|
||||
use mpris::{MetadataValue};
|
||||
|
||||
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 {
|
||||
match v {
|
||||
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) {
|
||||
if data.current_player.is_some() {
|
||||
update_prefix(cfg, data);
|
||||
let name = &data.current_player.as_ref().unwrap();
|
||||
if let Ok(player) = pf.find_by_name(name) {
|
||||
debug!("found player!");
|
||||
if let Ok(m) = player.get_metadata() {
|
||||
debug!("got metadata!");
|
||||
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);
|
||||
}
|
||||
pub fn update_message(cfg: &Config, data: &mut Data) {
|
||||
if let Some(player) = &data.current_player {
|
||||
if let Ok(meta) = player.get_metadata() {
|
||||
for field in &cfg.metadata_fields {
|
||||
let key = field.field.clone();
|
||||
if field.field.eq("xesam:userRating") {
|
||||
if let Some(rating_string) = rating_to_string(meta.get(&key), &cfg.rating_icons) {
|
||||
data.display_text.insert(key, rating_string);
|
||||
} else {
|
||||
let key = field.field.clone();
|
||||
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:")));
|
||||
},
|
||||
}
|
||||
data.display_text.remove(&key);
|
||||
}
|
||||
} 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:"))),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,17 @@
|
|||
use mpris::PlayerFinder;
|
||||
use log::trace;
|
||||
use mpris::{PlayerFinder, Metadata, Player};
|
||||
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(
|
||||
pf: &PlayerFinder,
|
||||
cfg: &Config,
|
||||
|
|
@ -10,31 +21,30 @@ pub fn update_players(
|
|||
if players.is_empty() {
|
||||
data.current_player = None;
|
||||
} else {
|
||||
let mut active: Vec<(i32, String)> = Vec::new();
|
||||
let mut active: Vec<(i32, Player)> = Vec::new();
|
||||
for player in players {
|
||||
if let Ok(mpris::PlaybackStatus::Playing) = player.get_playback_status() {
|
||||
let name = player.identity();
|
||||
let idx = cfg.find_player_priorities_idx(name);
|
||||
active.push((idx, name.to_owned()));
|
||||
let idx = cfg.find_player_priorities_idx(player.identity());
|
||||
active.push((idx, player));
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
data.current_player = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_lowest(v: &Vec<(i32, String)>) -> String {
|
||||
let mut out = String::new();
|
||||
let mut lowest_index = i32::MAX;
|
||||
for (v_id, v_str) in v.iter() {
|
||||
if v_id < &lowest_index {
|
||||
out = v_str.to_owned();
|
||||
fn get_lowest(v: &mut Vec<(i32, Player)>) -> Player {
|
||||
let mut lowest_index = i32::MAX; //FIXME: use options here instead, also fixes a bug
|
||||
for (v_id, _) in v.into_iter() {
|
||||
if v_id < &mut lowest_index {
|
||||
lowest_index = *v_id;
|
||||
}
|
||||
}
|
||||
out
|
||||
v.swap_remove(lowest_index as usize).1
|
||||
}
|
||||
Loading…
Reference in New Issue