Skip to content

Commit 9f350f0

Browse files
authored
Add Playerctld to get the correct audio device (#212)
1 parent c5ed29f commit 9f350f0

File tree

5 files changed

+84
-40
lines changed

5 files changed

+84
-40
lines changed

Cargo.lock

Lines changed: 25 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,4 @@ mpris = "2.0.1"
4949
runtime-format = "0.1.3"
5050
strfmt = "0.2.4"
5151
clap = { version = "4.5.53", features = ["derive"] }
52+
playerctld = "0.1.1"

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ bindsym XF86AudioNext exec swayosd-client --playerctl next
148148
- You can list your input audio devices using `pactl list short sources`, for outputs replace `sources` with `sinks`.
149149
- You can list your brightness devices using `brightnessctl -l`, for backlights, use `brightnessctl -l -c backlight`.
150150

151+
### Notes on using `--player`:
152+
153+
- It is for playerctl only.
154+
- If it is omitted, the default playerctld device is used.
155+
- Use `playerctl -l` for available players.
156+
- Special operators are "all", "shift" and "unshift". The last two call `playerctld [un]shift`; use to cycle players.
157+
151158
### Notes on using `--monitor`:
152159

153160
- By default, without using --monitor the osd will be shown on all monitors

src/args.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub struct ArgsClient {
100100
pub playerctl: Option<String>,
101101

102102
/// For which player to run the playerctl commands
103-
#[arg(long, value_name = "auto|all|(playerctl -l)")]
103+
#[arg(long, value_name = "auto|(playerctl -l)|all|shift|unshift")]
104104
pub player: Option<String>,
105105

106106
/// Message to display

src/mpris-backend/mod.rs

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use mpris::{Metadata, PlaybackStatus, Player, PlayerFinder};
2+
use playerctld::PlayerctldProxyBlocking;
3+
use zbus::blocking::Connection;
24

35
use super::config::user::ServerConfig;
4-
use crate::utils::get_player;
6+
use crate::utils::get_player as get_player_raw;
57
use std::{error::Error, sync::Arc, thread::sleep, time::Duration};
68
use PlaybackStatus::*;
79
use PlayerctlAction::*;
@@ -21,6 +23,8 @@ pub enum PlayerctlDeviceRaw {
2123
None,
2224
All,
2325
Some(String),
26+
Shift,
27+
Unshift,
2428
}
2529

2630
pub enum PlayerctlDevice {
@@ -36,27 +40,54 @@ pub struct Playerctl {
3640
fmt_str: Option<String>,
3741
}
3842

43+
fn get_player(player: PlayerctlDeviceRaw) -> Result<PlayerctlDevice, Box<dyn Error>> {
44+
fn get_playerctld<'a>() -> Result<PlayerctldProxyBlocking<'a>, Box<dyn Error>> {
45+
Ok(PlayerctldProxyBlocking::new(&Connection::session()?)?)
46+
}
47+
48+
fn get_playerctld_devices() -> Result<Vec<String>, Box<dyn Error>> {
49+
Ok(get_playerctld()?.player_names()?)
50+
}
51+
52+
fn get_single_player(player: String) -> Result<PlayerctlDevice, Box<dyn Error>> {
53+
let possible_player = PlayerFinder::new()?.find_all()?.into_iter().find(|p| {
54+
let bus = p.bus_name();
55+
bus.contains(&player)
56+
});
57+
match possible_player {
58+
Some(player) => Ok(PlayerctlDevice::Some(player)),
59+
None => Err(From::from(mpris::FindingError::NoPlayerFound)),
60+
}
61+
}
62+
63+
match player {
64+
PlayerctlDeviceRaw::None => {
65+
let fallback = || -> Result<PlayerctlDevice, Box<dyn Error>> {
66+
Ok(PlayerctlDevice::Some(PlayerFinder::new()?.find_active()?))
67+
};
68+
let Ok(players) = get_playerctld_devices() else {
69+
return fallback();
70+
};
71+
let Some(player) = players.first() else {
72+
return fallback();
73+
};
74+
get_single_player(player.to_string())
75+
}
76+
PlayerctlDeviceRaw::Some(name) => get_single_player(name),
77+
PlayerctlDeviceRaw::All => Ok(PlayerctlDevice::All(PlayerFinder::new()?.find_all()?)),
78+
79+
PlayerctlDeviceRaw::Shift => get_single_player(get_playerctld()?.shift()?),
80+
PlayerctlDeviceRaw::Unshift => get_single_player(get_playerctld()?.unshift()?),
81+
}
82+
}
83+
3984
impl Playerctl {
4085
pub fn new(
4186
action: PlayerctlAction,
4287
config: Arc<ServerConfig>,
4388
) -> Result<Playerctl, Box<dyn Error>> {
44-
let playerfinder = PlayerFinder::new()?;
45-
let player = get_player();
46-
let player = match player {
47-
PlayerctlDeviceRaw::None => PlayerctlDevice::Some(playerfinder.find_active()?),
48-
PlayerctlDeviceRaw::Some(name) => {
49-
let possible_player = playerfinder.find_all()?.into_iter().find(|p| {
50-
let bus = p.bus_name();
51-
bus.strip_prefix("org.mpris.MediaPlayer2.").unwrap_or(bus) == name
52-
});
53-
match possible_player {
54-
Some(player) => PlayerctlDevice::Some(player),
55-
None => return Err(From::from(mpris::FindingError::NoPlayerFound)),
56-
}
57-
}
58-
PlayerctlDeviceRaw::All => PlayerctlDevice::All(playerfinder.find_all()?),
59-
};
89+
let player = get_player_raw();
90+
let player = get_player(player)?;
6091
let fmt_str = config.playerctl_format.clone();
6192
Ok(Self {
6293
player,
@@ -230,6 +261,8 @@ impl PlayerctlDeviceRaw {
230261
match player.as_str() {
231262
"auto" | "" => Ok(None),
232263
"all" => Ok(All),
264+
"shift" => Ok(Shift),
265+
"unshift" => Ok(Unshift),
233266
_ => Ok(Some(player)),
234267
}
235268
}

0 commit comments

Comments
 (0)