Compare commits
No commits in common. "9ecb0db1f858eddeba76d170134c5fae61f23cac" and "c227e8caeaa4f89509a274d36e20ff87ceefbc48" have entirely different histories.
9ecb0db1f8
...
c227e8caea
5 changed files with 130 additions and 173 deletions
12
src/main.vala
Normal file
12
src/main.vala
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
int main (string[] args) {
|
||||||
|
// do it ourselves or it's broken
|
||||||
|
Gtk.disable_setlocale ();
|
||||||
|
Intl.bindtextdomain (Audrey.Config.GETTEXT_PACKAGE, Audrey.Config.LOCALEDIR);
|
||||||
|
Intl.bind_textdomain_codeset (Audrey.Config.GETTEXT_PACKAGE, "UTF-8");
|
||||||
|
Intl.textdomain (Audrey.Config.GETTEXT_PACKAGE);
|
||||||
|
Intl.setlocale (LocaleCategory.ALL, "");
|
||||||
|
Intl.setlocale (LocaleCategory.NUMERIC, "C.UTF-8");
|
||||||
|
|
||||||
|
var app = new Audrey.Application ();
|
||||||
|
return app.run (args);
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ struct MetadataMap {
|
||||||
// mpris
|
// mpris
|
||||||
track_id: Option<OwnedObjectPath>,
|
track_id: Option<OwnedObjectPath>,
|
||||||
length: Option<i64>,
|
length: Option<i64>,
|
||||||
art_url: Option<url::Url>,
|
//art_url: Option<url::Url>,
|
||||||
// xesam
|
// xesam
|
||||||
album: Option<String>,
|
album: Option<String>,
|
||||||
//album_artist: Option<Vec<String>>,
|
//album_artist: Option<Vec<String>>,
|
||||||
|
@ -44,7 +44,6 @@ impl MetadataMap {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}),
|
}),
|
||||||
length: Some(song.duration() * MICROSECONDS as i64),
|
length: Some(song.duration() * MICROSECONDS as i64),
|
||||||
//art_url: Some(song.cover_art_url()), // FIXME: this would leak credentials
|
|
||||||
album: Some(song.album().into()),
|
album: Some(song.album().into()),
|
||||||
artist: Some(vec![song.artist().into()]),
|
artist: Some(vec![song.artist().into()]),
|
||||||
//content_created: song.year().map(|year| chrono::NaiveDate::from_yo_opt(year, 1).unwrap()), // FIXME: replace this unwrap with Some(Err) -> None
|
//content_created: song.year().map(|year| chrono::NaiveDate::from_yo_opt(year, 1).unwrap()), // FIXME: replace this unwrap with Some(Err) -> None
|
||||||
|
@ -63,9 +62,6 @@ impl MetadataMap {
|
||||||
if let Some(track_id) = &self.track_id {
|
if let Some(track_id) = &self.track_id {
|
||||||
map.insert("mpris:trackid", Value::new(track_id.as_ref()));
|
map.insert("mpris:trackid", Value::new(track_id.as_ref()));
|
||||||
}
|
}
|
||||||
if let Some(art_url) = &self.art_url {
|
|
||||||
map.insert("mpris:artUrl", Value::new(art_url.to_string()));
|
|
||||||
}
|
|
||||||
if let Some(length) = &self.length {
|
if let Some(length) = &self.length {
|
||||||
map.insert("mpris:length", Value::new(length));
|
map.insert("mpris:length", Value::new(length));
|
||||||
}
|
}
|
||||||
|
@ -121,10 +117,13 @@ impl Player {
|
||||||
.interface::<_, Self>("/org/mpris/MediaPlayer2")
|
.interface::<_, Self>("/org/mpris/MediaPlayer2")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
playbin.connect_new_track(glib::clone!(
|
playbin.connect_closure(
|
||||||
|
"new-track",
|
||||||
|
false,
|
||||||
|
glib::closure_local!(
|
||||||
#[strong]
|
#[strong]
|
||||||
player_ref,
|
player_ref,
|
||||||
move |_, song| {
|
move |_playbin: &crate::Playbin, song: &crate::playbin::Song| {
|
||||||
let metadata = MetadataMap::from_playbin_song(Some(song));
|
let metadata = MetadataMap::from_playbin_song(Some(song));
|
||||||
|
|
||||||
let player_ref = player_ref.clone();
|
let player_ref = player_ref.clone();
|
||||||
|
@ -137,12 +136,16 @@ impl Player {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
));
|
),
|
||||||
|
);
|
||||||
|
|
||||||
playbin.connect_seeked(glib::clone!(
|
playbin.connect_closure(
|
||||||
|
"seeked",
|
||||||
|
false,
|
||||||
|
glib::closure_local!(
|
||||||
#[strong]
|
#[strong]
|
||||||
player_ref,
|
player_ref,
|
||||||
move |_, position| {
|
move |_playbin: &crate::Playbin, position: f64| {
|
||||||
let player_ref = player_ref.clone();
|
let player_ref = player_ref.clone();
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
player_ref
|
player_ref
|
||||||
|
@ -151,14 +154,15 @@ impl Player {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
));
|
),
|
||||||
|
);
|
||||||
|
|
||||||
playbin.connect_notify_local(
|
playbin.connect_notify_local(
|
||||||
Some("play-queue-length"),
|
Some("play-queue-length"),
|
||||||
glib::clone!(
|
glib::clone!(
|
||||||
#[strong]
|
#[strong]
|
||||||
player_ref,
|
player_ref,
|
||||||
move |_, _| {
|
move |_playbin: &crate::Playbin, _| {
|
||||||
let player_ref = player_ref.clone();
|
let player_ref = player_ref.clone();
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
let player = player_ref.get_mut().await;
|
let player = player_ref.get_mut().await;
|
||||||
|
@ -185,7 +189,7 @@ impl Player {
|
||||||
glib::clone!(
|
glib::clone!(
|
||||||
#[strong]
|
#[strong]
|
||||||
player_ref,
|
player_ref,
|
||||||
move |_, _| {
|
move |_playbin: &crate::Playbin, _| {
|
||||||
let player_ref = player_ref.clone();
|
let player_ref = player_ref.clone();
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
let player = player_ref.get_mut().await;
|
let player = player_ref.get_mut().await;
|
||||||
|
@ -204,7 +208,7 @@ impl Player {
|
||||||
glib::clone!(
|
glib::clone!(
|
||||||
#[strong]
|
#[strong]
|
||||||
player_ref,
|
player_ref,
|
||||||
move |_, _| {
|
move |_playbin: &crate::Playbin, _| {
|
||||||
let player_ref = player_ref.clone();
|
let player_ref = player_ref.clone();
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
let player = player_ref.get_mut().await;
|
let player = player_ref.get_mut().await;
|
||||||
|
@ -219,24 +223,17 @@ impl Player {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn playbin(&self) -> zbus::fdo::Result<crate::Playbin> {
|
|
||||||
match self.playbin.upgrade() {
|
|
||||||
None => Err(zbus::fdo::Error::Failed("playbin was discarded".into())),
|
|
||||||
Some(playbin) => Ok(playbin),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus::interface(name = "org.mpris.MediaPlayer2.Player")]
|
#[zbus::interface(name = "org.mpris.MediaPlayer2.Player")]
|
||||||
impl Player {
|
impl Player {
|
||||||
fn next(&self) -> zbus::fdo::Result<()> {
|
fn next(&self) {
|
||||||
// If CanGoNext is false, attempting to call this method should have no effect.
|
// If CanGoNext is false, attempting to call this method should have no effect.
|
||||||
if !self.can_go_next()? {
|
if !self.can_go_next() {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let playbin = self.playbin()?;
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
if playbin.play_queue_position() + 1 > playbin.play_queue_length() {
|
if playbin.play_queue_position() + 1 > playbin.play_queue_length() {
|
||||||
// If there is no next track (and endless playback and track repeat are both off), stop playback.
|
// If there is no next track (and endless playback and track repeat are both off), stop playback.
|
||||||
// (interpret this as something else than what Stop does)
|
// (interpret this as something else than what Stop does)
|
||||||
|
@ -244,16 +241,14 @@ impl Player {
|
||||||
} else {
|
} else {
|
||||||
playbin.go_to_next_track();
|
playbin.go_to_next_track();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn previous(&self) -> zbus::fdo::Result<()> {
|
fn previous(&self) {
|
||||||
let playbin = self.playbin()?;
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
|
|
||||||
// If CanGoPrevious is false, attempting to call this method should have no effect.
|
// If CanGoPrevious is false, attempting to call this method should have no effect.
|
||||||
if !self.can_go_previous()? {
|
if !self.can_go_previous() {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if playbin.play_queue_position() == 0 {
|
if playbin.play_queue_position() == 0 {
|
||||||
|
@ -263,79 +258,74 @@ impl Player {
|
||||||
} else {
|
} else {
|
||||||
playbin.go_to_prev_track();
|
playbin.go_to_prev_track();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pause(&self) -> zbus::fdo::Result<()> {
|
fn pause(&self) {
|
||||||
let playbin = self.playbin()?;
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
|
|
||||||
// If CanPause is false, attempting to call this method should have no effect.
|
// If CanPause is false, attempting to call this method should have no effect.
|
||||||
if !self.can_pause() {
|
if !self.can_pause() {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If playback is already paused, this has no effect.
|
// If playback is already paused, this has no effect.
|
||||||
if playbin.state() != crate::playbin::State::Playing {
|
if playbin.state() != crate::playbin::State::Playing {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playbin.pause();
|
self.playbin.upgrade().unwrap().pause();
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn play_pause(&self) -> zbus::fdo::Result<()> {
|
fn play_pause(&self) {
|
||||||
// don't think this is exactly according to spec but it looks more reasonable to me
|
// don't think this is exactly according to spec but it looks more reasonable to me
|
||||||
if self.playbin()?.state() == crate::playbin::State::Paused {
|
if self.playbin.upgrade().unwrap().state() == crate::playbin::State::Paused {
|
||||||
self.play()
|
self.play();
|
||||||
} else {
|
} else {
|
||||||
self.pause()
|
self.pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&self) -> zbus::fdo::Result<()> {
|
fn stop(&self) {
|
||||||
let playbin = self.playbin()?;
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
|
|
||||||
// If playback is already stopped, this has no effect.
|
// If playback is already stopped, this has no effect.
|
||||||
if playbin.state() != crate::playbin::State::Playing {
|
if playbin.state() != crate::playbin::State::Playing {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calling Play after this should cause playback to start again from the beginning of the track.
|
// Calling Play after this should cause playback to start again from the beginning of the track.
|
||||||
playbin.pause();
|
playbin.pause();
|
||||||
playbin.seek(0.0);
|
playbin.seek(0.0);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn play(&self) -> zbus::fdo::Result<()> {
|
fn play(&self) {
|
||||||
let playbin = self.playbin()?;
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
|
|
||||||
// If CanPlay is false, attempting to call this method should have no effect.
|
// If CanPlay is false, attempting to call this method should have no effect.
|
||||||
if !self.can_play()? {
|
if !self.can_play() {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If already playing, this has no effect.
|
// If already playing, this has no effect.
|
||||||
if playbin.state() == crate::playbin::State::Playing {
|
if playbin.state() == crate::playbin::State::Playing {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no track to play, this has no effect.
|
// If there is no track to play, this has no effect.
|
||||||
if playbin.play_queue_length() == 0 {
|
if playbin.play_queue_length() == 0 {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playbin.play();
|
playbin.play();
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seek(&self, offset: i64) -> zbus::fdo::Result<()> {
|
fn seek(&self, offset: i64) {
|
||||||
// If the CanSeek property is false, this has no effect.
|
// If the CanSeek property is false, this has no effect.
|
||||||
if !self.can_seek() {
|
if !self.can_seek() {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let playbin = self.playbin()?;
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
// Seeks forward in the current track by the specified number of microseconds.
|
// Seeks forward in the current track by the specified number of microseconds.
|
||||||
let mut new_position = (playbin.position() * MICROSECONDS) as i64 + offset;
|
let mut new_position = (playbin.position() * MICROSECONDS) as i64 + offset;
|
||||||
|
|
||||||
|
@ -350,32 +340,30 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
playbin.seek(new_position as f64 / MICROSECONDS);
|
playbin.seek(new_position as f64 / MICROSECONDS);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_position(&self, track_id: ObjectPath<'_>, position: i64) -> zbus::fdo::Result<()> {
|
fn set_position(&self, track_id: ObjectPath<'_>, position: i64) {
|
||||||
let playbin = self.playbin()?;
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
|
|
||||||
// If the Position argument is less than 0, do nothing.
|
// If the Position argument is less than 0, do nothing.
|
||||||
if position < 0 {
|
if position < 0 {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
// If the Position argument is greater than the track length, do nothing.
|
// If the Position argument is greater than the track length, do nothing.
|
||||||
if position > (playbin.duration() * MICROSECONDS) as i64 {
|
if position > (playbin.duration() * MICROSECONDS) as i64 {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
// If the CanSeek property is false, this has no effect.
|
// If the CanSeek property is false, this has no effect.
|
||||||
if !self.can_seek() {
|
if !self.can_seek() {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
// check if it's stale
|
// check if it's stale
|
||||||
if self.metadata.track_id.as_deref() != Some(&track_id) {
|
if self.metadata.track_id.as_deref() != Some(&track_id) {
|
||||||
// TODO: warn of stale seek
|
// TODO: warn of stale seek
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playbin.seek(position as f64 / MICROSECONDS);
|
playbin.seek(position as f64 / MICROSECONDS);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_uri(&self, _s: &str) -> zbus::fdo::Result<()> {
|
fn open_uri(&self, _s: &str) -> zbus::fdo::Result<()> {
|
||||||
|
@ -386,50 +374,47 @@ impl Player {
|
||||||
async fn seeked(signal_emitter: &SignalEmitter<'_>, position: i64) -> zbus::Result<()>;
|
async fn seeked(signal_emitter: &SignalEmitter<'_>, position: i64) -> zbus::Result<()>;
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn playback_status(&self) -> zbus::fdo::Result<&str> {
|
fn playback_status(&self) -> String {
|
||||||
match self.playbin()?.state() {
|
match self.playbin.upgrade().unwrap().state() {
|
||||||
crate::playbin::State::Stopped => Ok("Stopped"),
|
crate::playbin::State::Stopped => "Stopped".into(),
|
||||||
crate::playbin::State::Playing => Ok("Playing"),
|
crate::playbin::State::Playing => "Playing".into(),
|
||||||
crate::playbin::State::Paused => Ok("Paused"),
|
crate::playbin::State::Paused => "Paused".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn loop_status(&self) -> zbus::fdo::Result<String> {
|
fn loop_status(&self) -> String {
|
||||||
Ok("None".into()) // TODO
|
"None".into() // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn set_loop_status(&self, _loop_status: &str) -> zbus::Result<()> {
|
fn set_loop_status(&self, _loop_status: &str) -> zbus::Result<()> {
|
||||||
Err(zbus::fdo::Error::NotSupported("setting LoopStatus".into()).into()) // TODO
|
Err(zbus::Error::Unsupported) // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn rate(&self) -> zbus::fdo::Result<f64> {
|
fn rate(&self) -> f64 {
|
||||||
Ok(1.0)
|
1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn set_rate(&self, rate: f64) -> zbus::Result<()> {
|
fn set_rate(&self, rate: f64) {
|
||||||
// A value of 0.0 should not be set by the client. If it is, the media player should act as though Pause was called.
|
// A value of 0.0 should not be set by the client. If it is, the media player should act as though Pause was called.
|
||||||
if rate == 0.0 {
|
if rate == 0.0 {
|
||||||
self.pause()?;
|
self.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
// just ignore anything else
|
// just ignore anything else
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
// FIXME: zbus bug (?): this getter can't be infallible
|
fn shuffle(&self) -> bool {
|
||||||
fn shuffle(&self) -> zbus::fdo::Result<bool> {
|
false
|
||||||
Ok(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
// FIXME: zbus bug (?): this setter can't return zbus::fdo::Result
|
|
||||||
fn set_shuffle(&self, _shuffle: bool) -> zbus::Result<()> {
|
fn set_shuffle(&self, _shuffle: bool) -> zbus::Result<()> {
|
||||||
Err(zbus::fdo::Error::NotSupported("setting Shuffle".into()).into())
|
Err(zbus::Error::Unsupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
|
@ -438,25 +423,24 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn volume(&self) -> zbus::fdo::Result<f64> {
|
fn volume(&self) -> f64 {
|
||||||
Ok(self.playbin()?.volume() as f64 / 100.0)
|
self.playbin.upgrade().unwrap().volume() as f64 / 100.0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn set_volume(&mut self, mut volume: f64) -> zbus::fdo::Result<()> {
|
fn set_volume(&mut self, mut volume: f64) {
|
||||||
// When setting, if a negative value is passed, the volume should be set to 0.0.
|
// When setting, if a negative value is passed, the volume should be set to 0.0.
|
||||||
if volume < 0.0 {
|
if volume < 0.0 {
|
||||||
volume = 0.0;
|
volume = 0.0;
|
||||||
}
|
}
|
||||||
let playbin = self.playbin()?;
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
// FIXME: check if this is set by the notify callback: self.volume = volume;
|
// FIXME: check if this is set by the notify callback: self.volume = volume;
|
||||||
playbin.set_volume((volume * 100.0) as i32);
|
playbin.set_volume((volume * 100.0) as i32);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "false"))]
|
#[zbus(property(emits_changed_signal = "false"))]
|
||||||
fn position(&self) -> zbus::fdo::Result<i64> {
|
fn position(&self) -> i64 {
|
||||||
Ok((self.playbin()?.position() * MICROSECONDS) as i64)
|
(self.playbin.upgrade().unwrap().position() * MICROSECONDS) as i64
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
|
@ -470,21 +454,21 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn can_go_next(&self) -> zbus::fdo::Result<bool> {
|
fn can_go_next(&self) -> bool {
|
||||||
// same as can_play
|
// same as can_play
|
||||||
Ok(self.playbin()?.play_queue_length() > 0)
|
self.playbin.upgrade().unwrap().play_queue_length() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn can_go_previous(&self) -> zbus::fdo::Result<bool> {
|
fn can_go_previous(&self) -> bool {
|
||||||
// same as can_play
|
// same as can_play
|
||||||
Ok(self.playbin()?.play_queue_length() > 0)
|
self.playbin.upgrade().unwrap().play_queue_length() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn can_play(&self) -> zbus::fdo::Result<bool> {
|
fn can_play(&self) -> bool {
|
||||||
// it only makes sense to disallow "play" when the play queue is empty
|
// it only makes sense to disallow "play" when the play queue is empty
|
||||||
Ok(self.playbin()?.play_queue_length() > 0)
|
self.playbin.upgrade().unwrap().play_queue_length() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
|
|
|
@ -49,7 +49,6 @@ pub mod ffi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use adw::prelude::*;
|
|
||||||
use glib::translate::{from_glib, from_glib_none, IntoGlib, ToGlibPtr};
|
use glib::translate::{from_glib, from_glib_none, IntoGlib, ToGlibPtr};
|
||||||
use gtk::{gio, glib};
|
use gtk::{gio, glib};
|
||||||
|
|
||||||
|
@ -137,20 +136,4 @@ impl Playbin {
|
||||||
pub fn play_queue(&self) -> gio::ListModel {
|
pub fn play_queue(&self) -> gio::ListModel {
|
||||||
unsafe { from_glib_none(ffi::audrey_playbin_get_play_queue(self.to_glib_none().0)) }
|
unsafe { from_glib_none(ffi::audrey_playbin_get_play_queue(self.to_glib_none().0)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_new_track<F: Fn(&Self, &Song) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
|
||||||
self.connect_closure(
|
|
||||||
"new-track",
|
|
||||||
false,
|
|
||||||
glib::closure_local!(|playbin, song| f(playbin, song)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn connect_seeked<F: Fn(&Self, f64) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
|
||||||
self.connect_closure(
|
|
||||||
"seeked",
|
|
||||||
false,
|
|
||||||
glib::closure_local!(|playbin, position| f(playbin, position)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,6 @@ public class Audrey.PlaybinSong : Object {
|
||||||
public int64 track { get { return inner.track; } }
|
public int64 track { get { return inner.track; } }
|
||||||
public int64 play_count { get { return inner.play_count; } }
|
public int64 play_count { get { return inner.play_count; } }
|
||||||
|
|
||||||
public string cover_art_url { owned get { return this.api.cover_art_uri (this.id); } }
|
|
||||||
public string stream_url { owned get { return this.api.stream_uri (this.id); } }
|
|
||||||
|
|
||||||
public Gdk.Paintable? thumbnail { get; private set; }
|
public Gdk.Paintable? thumbnail { get; private set; }
|
||||||
|
|
||||||
private Cancellable cancel_loading_thumbnail;
|
private Cancellable cancel_loading_thumbnail;
|
||||||
|
@ -366,26 +363,24 @@ public class Audrey.Playbin : GLib.Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void append_track (Subsonic.Song song) {
|
public void append_track (Subsonic.Song song) {
|
||||||
var pb_song = new PlaybinSong (this.api, song);
|
|
||||||
assert (this.mpv.command ({
|
assert (this.mpv.command ({
|
||||||
"loadfile",
|
"loadfile",
|
||||||
pb_song.stream_url,
|
this.api.stream_uri (song.id),
|
||||||
"append",
|
"append",
|
||||||
}) >= 0);
|
}) >= 0);
|
||||||
this._play_queue.append (pb_song);
|
this._play_queue.append (new PlaybinSong (this.api, song));
|
||||||
this.play_queue_length += 1;
|
this.play_queue_length += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void append_track_async (Subsonic.Song song) {
|
public async void append_track_async (Subsonic.Song song) {
|
||||||
var pb_song = new PlaybinSong (this.api, song);
|
|
||||||
var err = yield this.mpv_command_async ({
|
var err = yield this.mpv_command_async ({
|
||||||
"loadfile",
|
"loadfile",
|
||||||
pb_song.stream_url,
|
this.api.stream_uri (song.id),
|
||||||
"append",
|
"append",
|
||||||
});
|
});
|
||||||
assert (err >= 0);
|
assert (err >= 0);
|
||||||
|
|
||||||
this._play_queue.append (pb_song);
|
this._play_queue.append (new PlaybinSong (this.api, song));
|
||||||
this.play_queue_length += 1;
|
this.play_queue_length += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
pub mod ffi {
|
pub mod ffi {
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use std::ffi::c_char;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct AudreyPlaybinSong {
|
pub struct AudreyPlaybinSong {
|
||||||
|
@ -15,16 +14,18 @@ pub mod ffi {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn audrey_playbin_song_get_type() -> glib::ffi::GType;
|
pub fn audrey_playbin_song_get_type() -> glib::ffi::GType;
|
||||||
pub fn audrey_playbin_song_get_counter(self_: *mut AudreyPlaybinSong) -> i64;
|
pub fn audrey_playbin_song_get_counter(self_: *mut AudreyPlaybinSong) -> i64;
|
||||||
pub fn audrey_playbin_song_get_id(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
pub fn audrey_playbin_song_get_id(self_: *mut AudreyPlaybinSong)
|
||||||
pub fn audrey_playbin_song_get_title(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
-> *const std::ffi::c_char;
|
||||||
pub fn audrey_playbin_song_get_artist(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
pub fn audrey_playbin_song_get_title(
|
||||||
pub fn audrey_playbin_song_get_album(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
|
||||||
pub fn audrey_playbin_song_get_duration(self_: *mut AudreyPlaybinSong) -> i64;
|
|
||||||
|
|
||||||
pub fn audrey_playbin_song_get_cover_art_url(
|
|
||||||
self_: *mut AudreyPlaybinSong,
|
self_: *mut AudreyPlaybinSong,
|
||||||
) -> *const c_char;
|
) -> *const std::ffi::c_char;
|
||||||
pub fn audrey_playbin_song_get_stream_url(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
pub fn audrey_playbin_song_get_artist(
|
||||||
|
self_: *mut AudreyPlaybinSong,
|
||||||
|
) -> *const std::ffi::c_char;
|
||||||
|
pub fn audrey_playbin_song_get_album(
|
||||||
|
self_: *mut AudreyPlaybinSong,
|
||||||
|
) -> *const std::ffi::c_char;
|
||||||
|
pub fn audrey_playbin_song_get_duration(self_: *mut AudreyPlaybinSong) -> i64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,22 +65,4 @@ impl Song {
|
||||||
pub fn duration(&self) -> i64 {
|
pub fn duration(&self) -> i64 {
|
||||||
unsafe { ffi::audrey_playbin_song_get_duration(self.to_glib_none().0) }
|
unsafe { ffi::audrey_playbin_song_get_duration(self.to_glib_none().0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cover_art_url(&self) -> url::Url {
|
|
||||||
let url: String = unsafe {
|
|
||||||
from_glib_none(ffi::audrey_playbin_song_get_cover_art_url(
|
|
||||||
self.to_glib_none().0,
|
|
||||||
))
|
|
||||||
};
|
|
||||||
url::Url::parse(&url).expect("invalid url from vala side")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stream_url(&self) -> url::Url {
|
|
||||||
let url: String = unsafe {
|
|
||||||
from_glib_none(ffi::audrey_playbin_song_get_stream_url(
|
|
||||||
self.to_glib_none().0,
|
|
||||||
))
|
|
||||||
};
|
|
||||||
url::Url::parse(&url).expect("invalid url from vala side")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue