use futures_channel::{mpsc, oneshot};
use futures_util::StreamExt;
use zbus::{dbus_interface, ConnectionBuilder, Result, SignalContext};
use super::{
player::{RawPlayerInterface, RawRootInterface},
utils::{changed_delegate, signal_delegate},
Action, Server, OBJECT_PATH,
};
use crate::{MaybePlaylist, Playlist, PlaylistId, PlaylistOrdering, PlaylistsInterface};
pub(super) enum PlaylistsAction {
ActivatePlaylist(PlaylistId),
GetPlaylists(
u32,
u32,
PlaylistOrdering,
bool,
oneshot::Sender<Vec<Playlist>>,
),
PlaylistCount(oneshot::Sender<u32>),
Orderings(oneshot::Sender<Vec<PlaylistOrdering>>),
ActivePlaylist(oneshot::Sender<MaybePlaylist>),
}
pub(super) struct RawPlaylistsInterface {
pub(super) tx: mpsc::UnboundedSender<Action>,
}
impl RawPlaylistsInterface {
fn send(&self, action: PlaylistsAction) {
self.tx.unbounded_send(Action::Playlists(action)).unwrap();
}
}
#[dbus_interface(name = "org.mpris.MediaPlayer2.Playlists")]
impl RawPlaylistsInterface {
fn activate_playlist(&self, playlist_id: PlaylistId) {
self.send(PlaylistsAction::ActivatePlaylist(playlist_id));
}
async fn get_playlists(
&self,
index: u32,
max_count: u32,
order: PlaylistOrdering,
reverse_order: bool,
) -> Vec<Playlist> {
let (tx, rx) = oneshot::channel();
self.send(PlaylistsAction::GetPlaylists(
index,
max_count,
order,
reverse_order,
tx,
));
rx.await.unwrap()
}
#[dbus_interface(signal)]
async fn playlist_changed(ctxt: &SignalContext<'_>, playlist: Playlist) -> Result<()>;
#[dbus_interface(property)]
async fn playlist_count(&self) -> u32 {
let (tx, rx) = oneshot::channel();
self.send(PlaylistsAction::PlaylistCount(tx));
rx.await.unwrap()
}
#[dbus_interface(property)]
async fn orderings(&self) -> Vec<PlaylistOrdering> {
let (tx, rx) = oneshot::channel();
self.send(PlaylistsAction::Orderings(tx));
rx.await.unwrap()
}
#[dbus_interface(property)]
async fn active_playlist(&self) -> MaybePlaylist {
let (tx, rx) = oneshot::channel();
self.send(PlaylistsAction::ActivePlaylist(tx));
rx.await.unwrap()
}
}
impl<T> Server<T>
where
T: PlaylistsInterface + 'static,
{
pub async fn run_with_playlists(&self) -> Result<()> {
let (tx, mut rx) = mpsc::unbounded::<Action>();
let connection = ConnectionBuilder::session()?
.name(&self.bus_name)?
.serve_at(OBJECT_PATH, RawRootInterface { tx: tx.clone() })?
.serve_at(OBJECT_PATH, RawPlayerInterface { tx: tx.clone() })?
.serve_at(OBJECT_PATH, RawPlaylistsInterface { tx })?
.build()
.await?;
self.connection
.set(connection)
.expect("server must only be ran once");
while let Some(action) = rx.next().await {
match action {
Action::Root(action) => self.handle_interface_action(action).await,
Action::Player(action) => self.handle_player_interface_action(action).await,
Action::Playlists(action) => self.handle_playlists_interface_action(action).await,
Action::TrackList(_) => unreachable!(),
}
}
Ok(())
}
pub(super) async fn handle_playlists_interface_action(&self, action: PlaylistsAction) {
match action {
PlaylistsAction::ActivatePlaylist(playlist_id) => {
self.imp.activate_playlist(playlist_id).await
}
PlaylistsAction::GetPlaylists(index, max_count, order, reverse_order, sender) => {
sender
.send(
self.imp
.get_playlists(index, max_count, order, reverse_order)
.await,
)
.unwrap();
}
PlaylistsAction::PlaylistCount(sender) => {
sender.send(self.imp.playlist_count().await).unwrap();
}
PlaylistsAction::Orderings(sender) => {
sender.send(self.imp.orderings().await).unwrap();
}
PlaylistsAction::ActivePlaylist(sender) => {
sender.send(self.imp.active_playlist().await).unwrap();
}
}
}
signal_delegate!(RawPlaylistsInterface, playlist_changed(playlist: Playlist));
changed_delegate!(RawPlaylistsInterface, playlist_count_changed);
changed_delegate!(RawPlaylistsInterface, orderings_changed);
changed_delegate!(RawPlaylistsInterface, active_playlist_changed);
}