Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix mpris jammy #169

Merged
merged 1 commit into from
Dec 11, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 109 additions & 38 deletions cosmic-applet-audio/src/mpris_subscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
player::{PlaybackStatus, Player},
};
use tokio::join;
use zbus::Connection;
use zbus::{fdo::DBusProxy, Connection};

#[derive(Clone, Debug)]
pub struct PlayerStatus {
Expand All @@ -25,8 +25,8 @@
}

impl PlayerStatus {
async fn new(player: Player) -> Self {
let metadata = player.metadata().await.unwrap();
async fn new(player: Player) -> Option<Self> {
let metadata = player.metadata().await.ok()?;
let title = metadata.title().map(Cow::from);
let artists = metadata
.artists()
Expand All @@ -49,7 +49,7 @@
player.can_go_previous(),
player.can_go_next()
);
Self {
Some(Self {
icon,
title,
artists,
Expand All @@ -59,7 +59,7 @@
can_go_previous: can_go_previous.unwrap_or_default(),
can_go_next: can_go_next.unwrap_or_default(),
player,
}
})
}
}

Expand All @@ -78,7 +78,7 @@
#[derive(Debug)]
pub enum State {
Setup,
Player(Player),
Player(Player, DBusProxy<'static>),
Finished,
}

Expand All @@ -102,22 +102,23 @@
State::Setup => {
let Ok(conn) = Connection::session().await else {
tracing::error!("Failed to connect to session bus.");
_ = output.send(MprisUpdate::Finished).await;
return State::Finished;
};
let mut players = mpris2_zbus::media_player::MediaPlayer::new_all(&conn)
.await
.unwrap_or_else(|_| Vec::new());
let Ok(dbus_proxy) = zbus::fdo::DBusProxy::builder(&conn)
.path("/org/freedesktop/DBus")
.unwrap()
.build()
.await
else {
tracing::error!("Failed to create dbus proxy.");
return State::Finished;
};
if players.is_empty() {
let Ok(dbus) = zbus::fdo::DBusProxy::builder(&conn)
.path("/org/freedesktop/DBus")
.unwrap()
.build()
.await
else {
tracing::error!("Failed to create dbus proxy.");
return State::Finished;
};
let Ok(mut stream) = dbus.receive_name_owner_changed().await else {
let Ok(mut stream) = dbus_proxy.receive_name_owner_changed().await else {
tracing::error!("Failed to receive name owner changed signal.");
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
// restart from the beginning
Expand All @@ -126,61 +127,131 @@
while let Some(c) = stream.next().await {
if let Ok(args) = c.args() {
if args.name.contains("org.mpris.MediaPlayer2") {
if let Ok(p) =
MediaPlayer::new(&conn, args.name().to_owned().into()).await
{
players.push(p);
}
break;
}
}
}
if let Ok(p) = mpris2_zbus::media_player::MediaPlayer::new_all(&conn).await {
players = p;
} else {
// restart from the beginning
return State::Setup;
}
}

let Some(player) = find_active(players).await else {
tracing::error!("Failed to find active media player.");
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
return State::Finished;
return State::Setup;
};

let player_status = PlayerStatus::new(player.clone()).await;
let Some(player_status) = PlayerStatus::new(player.clone()).await else {
tracing::error!("Failed to get player status.");
return State::Setup;
};

_ = output.send(MprisUpdate::Player(player_status)).await;
State::Player(player)
State::Player(player, dbus_proxy)
}
State::Player(player) => {
let mut paused = player.receive_playback_status_changed().await;
State::Player(player, dbus_proxy) => {
let Ok(mut name_owner_changed) = player.receive_owner_changed().await else {
tracing::error!("Failed to receive owner changed signal.");
// restart from the beginning
return State::Setup;
};
let mut metadata_changed = player.receive_metadata_changed().await;
let Ok(mut new_mpris) = dbus_proxy.receive_name_owner_changed().await else {
tracing::error!("Failed to receive name owner changed signal.");
// restart from the beginning
return State::Setup;
};
let conn = player.connection();
let media_players = mpris2_zbus::media_player::MediaPlayer::new_all(&conn)

Check warning on line 168 in cosmic-applet-audio/src/mpris_subscription.rs

View workflow job for this annotation

GitHub Actions / linting

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> cosmic-applet-audio/src/mpris_subscription.rs:168:81 | 168 | let media_players = mpris2_zbus::media_player::MediaPlayer::new_all(&conn) | ^^^^^ help: change this to: `conn` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `#[warn(clippy::needless_borrow)]` on by default

Check warning on line 168 in cosmic-applet-audio/src/mpris_subscription.rs

View workflow job for this annotation

GitHub Actions / linting

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> cosmic-applet-audio/src/mpris_subscription.rs:168:81 | 168 | let media_players = mpris2_zbus::media_player::MediaPlayer::new_all(&conn) | ^^^^^ help: change this to: `conn` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `#[warn(clippy::needless_borrow)]` on by default
.await
.unwrap_or_else(|_| Vec::new());

let mut players = Vec::with_capacity(media_players.len());
for p in media_players {
if let Ok(p) = p.player().await {
players.push(p);
}
}

loop {
let mut listeners = Vec::with_capacity(players.len());
for p in &players {
listeners.push(p.receive_playback_status_changed().await);
}
let mut player_state_changed_list = Vec::with_capacity(listeners.len());
for l in &mut listeners {
player_state_changed_list.push(Box::pin(async move {
let changed = l.next().await;
if let Some(c) = changed {
c.get().await.ok()
} else {
tracing::error!("Failed to receive playback status changed signal.");
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
None
}
}));
}
let any_player_state_changed =
futures::future::select_all(player_state_changed_list);
let keep_going = tokio::select! {
p = paused.next() => {
p.is_some()
},
m = metadata_changed.next() => {
m.is_some()
},
n = name_owner_changed.next() => {
n.map(|n| n.is_some()).unwrap_or_default()
},
_ = new_mpris.next() => {
true
},
_ = any_player_state_changed => {
true
},
};

if keep_going {
let update = PlayerStatus::new(player.clone()).await;
let stopped = update.status == PlaybackStatus::Stopped;
_ = output.send(MprisUpdate::Player(update)).await;
if stopped {
_ = output.send(MprisUpdate::Setup).await;
if !keep_going {
break;
}

if let Some(update) = PlayerStatus::new(player.clone()).await {
if matches!(update.status, PlaybackStatus::Stopped) {
break;
}

// if paused check if any players are playing
// if they are, break
if !matches!(update.status, PlaybackStatus::Playing) {
let conn = player.connection();
let players = mpris2_zbus::media_player::MediaPlayer::new_all(&conn)

Check warning on line 227 in cosmic-applet-audio/src/mpris_subscription.rs

View workflow job for this annotation

GitHub Actions / linting

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> cosmic-applet-audio/src/mpris_subscription.rs:227:87 | 227 | let players = mpris2_zbus::media_player::MediaPlayer::new_all(&conn) | ^^^^^ help: change this to: `conn` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

Check warning on line 227 in cosmic-applet-audio/src/mpris_subscription.rs

View workflow job for this annotation

GitHub Actions / linting

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> cosmic-applet-audio/src/mpris_subscription.rs:227:87 | 227 | let players = mpris2_zbus::media_player::MediaPlayer::new_all(&conn) | ^^^^^ help: change this to: `conn` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
.await
.unwrap_or_else(|_| Vec::new());
if let Some(active) = find_active(players).await {
if active.destination() != player.destination() {
break;
}
}
}
_ = output.send(MprisUpdate::Player(update)).await;
} else {
break;
}
}
_ = output.send(MprisUpdate::Setup).await;
State::Setup
}
State::Finished => iced::futures::future::pending().await,
}
}

async fn find_active(players: Vec<MediaPlayer>) -> Option<Player> {
async fn find_active(mut players: Vec<MediaPlayer>) -> Option<Player> {
// pre-sort by path so that the same player is always selected
players.sort_by(|a, b| {
let a = a.destination();
let b = b.destination();
a.cmp(&b)

Check warning on line 253 in cosmic-applet-audio/src/mpris_subscription.rs

View workflow job for this annotation

GitHub Actions / linting

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> cosmic-applet-audio/src/mpris_subscription.rs:253:15 | 253 | a.cmp(&b) | ^^ help: change this to: `b` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

Check warning on line 253 in cosmic-applet-audio/src/mpris_subscription.rs

View workflow job for this annotation

GitHub Actions / linting

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> cosmic-applet-audio/src/mpris_subscription.rs:253:15 | 253 | a.cmp(&b) | ^^ help: change this to: `b` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
});
let mut best = (0, None);
let eval = |p: Player| async move {
let v = {
Expand All @@ -202,7 +273,7 @@
Err(_) => continue,
};
let v = eval(p.clone()).await;
if v >= best.0 {
if v > best.0 {
best = (v, Some(p));
}
}
Expand Down
Loading