Skip to content

Commit

Permalink
Merge pull request #37 from xou816/feature/mpris
Browse files Browse the repository at this point in the history
WIP: MPRIS integration
  • Loading branch information
xou816 committed Jan 31, 2021
2 parents a234c54 + c44e594 commit 5a2f934
Show file tree
Hide file tree
Showing 13 changed files with 624 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"options": {
"env": {
"RUST_BACKTRACE": "1",
"https_proxy": "localhost:8080"
//"https_proxy": "localhost:8080"
}
},
"tasks": [
Expand Down
86 changes: 72 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ features = ["v2_60"]
[dependencies.librespot]
version = "0.1.3"
features = ["pulseaudio-backend"]
#path = "../librespot"

[dependencies.protobuf]
version = "2.8.1"
Expand Down Expand Up @@ -60,4 +61,7 @@ gladis = "^0.4.0"
ref_filter_map = "^1.0.1"
regex = "^1.4.3"
async-std = "^1.9.0"
form_urlencoded = "^1.0.0"
form_urlencoded = "^1.0.0"
zbus = "^2.0.0-beta"
zvariant = "^2.5.0"
zvariant_derive = "^2.5.0"
4 changes: 2 additions & 2 deletions dev.alextren.Spot.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
"--socket=fallback-x11",
"--socket=wayland",
"--socket=pulseaudio",
"--talk-name=org.freedesktop.secrets"
"--talk-name=org.freedesktop.secrets",
"--own-name=org.mpris.MediaPlayer2.Spot"
],
"build-options" : {
"append-path" : "/usr/lib/sdk/rust-stable/bin",
"env" : {
"CARGO_HOME" : "/run/build/spot/cargo",
"RUST_BACKTRACE" : "full",
"RUST_LOG" : "spot=debug"
}
Expand Down
1 change: 0 additions & 1 deletion src/app/components/playback/playback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ impl EventListener for Playback {
}
AppEvent::TrackChanged(_) => {
self.update_current_info();
self.toggle_playing();
}
AppEvent::SeekSynced(pos) => {
self.sync_seek(*pos);
Expand Down
12 changes: 1 addition & 11 deletions src/app/components/playback/playback_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,7 @@ impl PlaybackModel {
}

pub fn current_song(&self) -> Option<SongDescription> {
let state = self.state();
if let Some(current_song_id) = state.current_song_id.as_ref() {
state
.playlist
.songs()
.iter()
.find(|song| song.id == *current_song_id)
.cloned()
} else {
None
}
self.state().current_song()
}

pub fn play_next_song(&self) {
Expand Down
138 changes: 138 additions & 0 deletions src/app/dbus/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
use futures::channel::mpsc::Sender;
use std::convert::TryInto;
use std::rc::Rc;
use std::thread;
use zbus::fdo;

use crate::app::components::EventListener;
use crate::app::{models::SongDescription, AppAction, AppEvent, AppModel};

mod mpris;
pub use mpris::*;

mod types;
use types::*;

// This one wraps a connection and reads the app state
pub struct ConnectionWrapper {
object_server: zbus::ObjectServer,
app_model: Rc<AppModel>,
}

impl ConnectionWrapper {
fn new(
connection: zbus::Connection,
player: SpotMprisPlayer,
app_model: Rc<AppModel>,
) -> Result<Self, zbus::Error> {
let object_server = register_mpris(&connection, player)?;
Ok(Self {
object_server,
app_model,
})
}

fn with_player<F: Fn(&SpotMprisPlayer) -> zbus::Result<()>>(&self, f: F) -> zbus::Result<()> {
self.object_server.with(
&"/org/mpris/MediaPlayer2".try_into()?,
|iface: &SpotMprisPlayer| f(iface),
)
}

fn make_track_meta(&self) -> Option<TrackMetadata> {
self.app_model.get_state().current_song().map(
|SongDescription {
id,
title,
artists,
duration,
..
}| TrackMetadata {
id: format!("/dev/alextren/Spot/Track/{}", id),
length: duration as u64,
title,
artist: artists.into_iter().map(|a| a.name).collect(),
},
)
}

fn has_prev_next(&self) -> (bool, bool) {
let state = self.app_model.get_state();
(state.prev_song().is_some(), state.next_song().is_some())
}
}

impl EventListener for ConnectionWrapper {
fn on_event(&mut self, event: &AppEvent) {
match event {
AppEvent::TrackPaused => {
self.with_player(|player| {
player.state.set_playing(false);
player.notify_playback_status()?;
Ok(())
})
.unwrap();
}
AppEvent::TrackResumed => {
self.with_player(|player| {
player.state.set_playing(true);
player.notify_playback_status()?;
Ok(())
})
.unwrap();
}
AppEvent::TrackChanged(_) => {
self.with_player(|player| {
let meta = self.make_track_meta();
let (has_prev, has_next) = self.has_prev_next();
player.state.set_current_track(meta);
player.state.set_has_prev(has_prev);
player.state.set_has_next(has_next);
player.notify_metadata_and_prev_next()?;
Ok(())
})
.unwrap();
}
_ => {}
}
}
}

fn register_mpris(
connection: &zbus::Connection,
player: SpotMprisPlayer,
) -> Result<zbus::ObjectServer, zbus::Error> {
let mut object_server = zbus::ObjectServer::new(&connection);
object_server.at(&"/org/mpris/MediaPlayer2".try_into()?, SpotMpris)?;
object_server.at(&"/org/mpris/MediaPlayer2".try_into()?, player)?;
Ok(object_server)
}

pub fn start_dbus_server(
app_model: Rc<AppModel>,
sender: Sender<AppAction>,
) -> Result<ConnectionWrapper, zbus::Error> {
let state = SharedMprisState::new();

let connection = zbus::Connection::new_session()?;
fdo::DBusProxy::new(&connection)?.request_name(
"org.mpris.MediaPlayer2.Spot",
fdo::RequestNameFlags::AllowReplacement.into(),
)?;

let state_clone = state.clone();
let sender_clone = sender.clone();
let conn_clone = connection.clone();

thread::spawn(move || {
let player = SpotMprisPlayer::new(state_clone, sender_clone);
let mut object_server = register_mpris(&conn_clone, player).unwrap();
loop {
if let Err(err) = object_server.try_handle_next() {
eprintln!("{}", err);
}
}
});
let player = SpotMprisPlayer::new(state, sender);
ConnectionWrapper::new(connection, player, app_model)
}
Loading

0 comments on commit 5a2f934

Please sign in to comment.