diff options
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..59cb4f1 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,153 @@ +use std::{thread::sleep, time::Duration}; + +use clap::Parser; +use mpris::{DBusError, FindingError, PlaybackStatus, Player, PlayerFinder}; + +const PLAYER_IDENTITY: &str = "Spotify"; +const BROWSER_IDENTITY: &str = "Mozilla zen"; + +// config +// percentages +const LOWER_VOLUME: u8 = 45; +const NORMAL_VOLUME: u8 = 80; + +#[derive(Parser)] +struct Args { + #[arg( + short, long + )] + daemon: bool, + + #[arg( + short, long + )] + lower: bool, + + #[arg( + short, long + )] + normal: bool, +} + +fn get_player() -> Option<Player> { + find_player(PLAYER_IDENTITY) +} + +fn get_browser() -> Option<Player> { + find_player(BROWSER_IDENTITY) +} + +fn find_player(name: &str) -> Option<Player> { + match PlayerFinder::new() + .expect("Failed to create PlayerFinder") + .find_by_name(name) + { + Ok(p) => Some(p), + Err(e) => { + if let FindingError::DBusError(e) = e { + panic!("DBus err: {e}") + } else { + None + } + } + } +} + +fn normalize_volume(volume: f64) -> u8 { + (volume * 100.0) as u8 +} + +fn denormal_volume(volume: u8) -> f64 { + volume as f64 / 100.0 +} + +fn set_volume(player: &Player, volume: u8) -> Vec<Result<(), DBusError>> { + let mut res = Vec::new(); + let current_volume = normalize_volume( + player + .get_volume() + .expect("Failed to retrieve {player} volume"), + ); + if current_volume > volume { + for v in (volume..=current_volume).rev() { + res.push(player.set_volume(denormal_volume(v))); + } + } else { + for v in current_volume..=volume { + res.push(player.set_volume(denormal_volume(v))); + } + } + res +} + +fn is_playing(player: &Player) -> bool { + player + .get_playback_status() + .map(|s| s == PlaybackStatus::Playing) + .unwrap_or(false) +} + +fn daemon() -> ! { + let mut had_browser = false; + loop { + let player = match get_player() { + Some(p) => p, + None => { + sleep(Duration::from_secs(5)); + continue; + } + }; + match get_browser() { + Some(browser) => { + let is_playing = is_playing(&browser); + if !had_browser && is_playing { + set_lower(&player); + had_browser = true; + } else if had_browser && !is_playing { + set_normal(&player); + had_browser = false; + } + } + None => { + if had_browser { + set_normal(&player); + had_browser = false; + } + } + } + + sleep(Duration::from_secs(1)); + } +} + +fn set_lower(player: &Player) { + set_volume(player, LOWER_VOLUME) + .into_iter() + .for_each(|r| r.unwrap()); +} + +fn set_normal(player: &Player) { + set_volume(player, NORMAL_VOLUME) + .into_iter() + .for_each(|r| r.unwrap()); +} + +fn main() { + let args = Args::parse(); + + if args.daemon { + daemon() + } + + let player = get_player().unwrap_or_else(|| panic!("Player {PLAYER_IDENTITY} not found")); + + if args.lower { + set_lower(&player); + return; + } else if args.normal { + set_normal(&player); + return; + } + + daemon() +} |
