summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs153
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()
+}