Compare commits
2 commits
e4c54dc6f5
...
c827dd4863
Author | SHA1 | Date | |
---|---|---|---|
c827dd4863 | |||
4fd1723f37 |
4 changed files with 48 additions and 30 deletions
17
src/lib.rs
17
src/lib.rs
|
@ -1,15 +1,16 @@
|
||||||
pub mod globals {
|
pub mod globals {
|
||||||
pub fn art_path() -> &'static std::path::Path {
|
use std::path::PathBuf;
|
||||||
static ART_PATH: std::sync::LazyLock<std::path::PathBuf> = std::sync::LazyLock::new(|| {
|
use tokio::sync::Mutex;
|
||||||
let xdg_dirs =
|
|
||||||
xdg::BaseDirectories::with_prefix("audrey").expect("failed to get xdg dirs");
|
pub fn xdg_dirs() -> &'static xdg::BaseDirectories {
|
||||||
xdg_dirs
|
static DIRS: std::sync::LazyLock<xdg::BaseDirectories> = std::sync::LazyLock::new(|| {
|
||||||
.place_state_file("mpris-art")
|
xdg::BaseDirectories::with_prefix("audrey").expect("failed to get xdg dirs")
|
||||||
.expect("failed to create mpris art state dir")
|
|
||||||
});
|
});
|
||||||
&ART_PATH
|
&DIRS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub static MPRIS_ART_PATH: Mutex<Option<PathBuf>> = Mutex::const_new(None);
|
||||||
|
|
||||||
pub fn runtime() -> &'static tokio::runtime::Runtime {
|
pub fn runtime() -> &'static tokio::runtime::Runtime {
|
||||||
static RUNTIME: std::sync::LazyLock<tokio::runtime::Runtime> =
|
static RUNTIME: std::sync::LazyLock<tokio::runtime::Runtime> =
|
||||||
std::sync::LazyLock::new(|| {
|
std::sync::LazyLock::new(|| {
|
||||||
|
|
|
@ -30,6 +30,8 @@ mod imp {
|
||||||
duration: Cell<i64>,
|
duration: Cell<i64>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
track: Cell<i64>,
|
track: Cell<i64>,
|
||||||
|
#[property(get, set)]
|
||||||
|
cover_art: RefCell<String>,
|
||||||
|
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
stream_url: RefCell<String>,
|
stream_url: RefCell<String>,
|
||||||
|
@ -83,6 +85,7 @@ impl Song {
|
||||||
.property("duration", song.duration as i64)
|
.property("duration", song.duration as i64)
|
||||||
.property("track", song.track.map(i64::from).unwrap_or(-1))
|
.property("track", song.track.map(i64::from).unwrap_or(-1))
|
||||||
.property("stream-url", api.stream_url(&song.id).as_str())
|
.property("stream-url", api.stream_url(&song.id).as_str())
|
||||||
|
.property("cover-art", &song.cover_art)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
song
|
song
|
||||||
|
|
|
@ -92,10 +92,11 @@ impl Player {
|
||||||
|
|
||||||
#[tracing::instrument(skip(self), parent = None, target = "audrey::mpris", level = Level::DEBUG, ret)]
|
#[tracing::instrument(skip(self), parent = None, target = "audrey::mpris", level = Level::DEBUG, ret)]
|
||||||
fn set_position(&self, track_id: ObjectPath<'_>, position: i64) -> zbus::fdo::Result<()> {
|
fn set_position(&self, track_id: ObjectPath<'_>, position: i64) -> zbus::fdo::Result<()> {
|
||||||
let metadata = self.metadata();
|
//let metadata = self.metadata();
|
||||||
if Some(&track_id.into()) == metadata.get("track_id") {
|
// TODO: reimplment stale seeks
|
||||||
self.window().set_time_pos(position as f64 / MICROSECONDS);
|
//if Some(&track_id.into()) == metadata.get("track_id") {
|
||||||
}
|
self.window().set_time_pos(position as f64 / MICROSECONDS);
|
||||||
|
//}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,31 +154,29 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
fn metadata(&self) -> HashMap<&'static str, Value<'_>> {
|
async fn metadata(&self) -> HashMap<&'static str, Value<'_>> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
let mpris_art_path = audrey::globals::MPRIS_ART_PATH.lock().await;
|
||||||
|
|
||||||
if let Some(song) = self.window().song() {
|
if let Some(song) = self.window().song() {
|
||||||
map.insert(
|
map.insert(
|
||||||
"mpris:trackid",
|
"mpris:trackid",
|
||||||
Value::new(format!("/eu/callcc/audrey/Track/{}", song.counter())).to_owned(),
|
format!("/eu/callcc/audrey/Track/{}", song.counter()).into(),
|
||||||
);
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
"mpris:length",
|
"mpris:length",
|
||||||
Value::new((self.window().duration() * MICROSECONDS) as i64),
|
((self.window().duration() * MICROSECONDS) as i64).into(),
|
||||||
);
|
);
|
||||||
map.insert(
|
if let Some(path) = mpris_art_path.as_ref() {
|
||||||
"mpris:artUrl",
|
map.insert(
|
||||||
Value::new(
|
"mpris:artUrl",
|
||||||
url::Url::from_file_path(audrey::globals::art_path())
|
(url::Url::from_file_path(path).unwrap().to_string()).into(),
|
||||||
.unwrap()
|
);
|
||||||
.to_string(),
|
}
|
||||||
)
|
map.insert("xesam:album", song.album().into());
|
||||||
.to_owned(),
|
|
||||||
);
|
|
||||||
map.insert("xesam:album", Value::new(song.album()));
|
|
||||||
// TODO: use the right opensubsonic data
|
// TODO: use the right opensubsonic data
|
||||||
map.insert("xesam:artist", Value::new(vec![song.artist()]));
|
map.insert("xesam:artist", vec![song.artist()].into());
|
||||||
map.insert("xesam:title", Value::new(song.title()));
|
map.insert("xesam:title", song.title().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
map
|
map
|
||||||
|
|
|
@ -733,7 +733,7 @@ mod imp {
|
||||||
self.mpris_player_playback_status_changed();
|
self.mpris_player_playback_status_changed();
|
||||||
|
|
||||||
let window = self.obj().clone();
|
let window = self.obj().clone();
|
||||||
let song_id = window.song().unwrap().id();
|
let song_id = song.id();
|
||||||
if let Some(handle) = self
|
if let Some(handle) = self
|
||||||
.loading_cover_handle
|
.loading_cover_handle
|
||||||
.replace(Some(glib::spawn_future_local(async move {
|
.replace(Some(glib::spawn_future_local(async move {
|
||||||
|
@ -754,12 +754,27 @@ mod imp {
|
||||||
|
|
||||||
// we consume image below into a pixbuf so we need a copy for save
|
// we consume image below into a pixbuf so we need a copy for save
|
||||||
let image_copy = image.clone();
|
let image_copy = image.clone();
|
||||||
|
let save_path = audrey::globals::xdg_dirs()
|
||||||
|
.place_state_file(format!("{}.jpg", song.cover_art()))
|
||||||
|
.expect("failed to create mpris art state dir");
|
||||||
|
let save_path_copy = save_path.clone();
|
||||||
|
let mut mpris_art_path = audrey::globals::MPRIS_ART_PATH.lock().await;
|
||||||
let save_future = audrey::globals::runtime().spawn_blocking(
|
let save_future = audrey::globals::runtime().spawn_blocking(
|
||||||
move || -> Result<(), image::ImageError> {
|
move || -> Result<(), image::ImageError> {
|
||||||
let save_path = audrey::globals::art_path();
|
// TODO: wipe xdg state folder on init
|
||||||
|
if let Some(path) = mpris_art_path.take() {
|
||||||
|
if let Err(err) = std::fs::remove_file(&path) {
|
||||||
|
event!(
|
||||||
|
Level::ERROR,
|
||||||
|
"could not remove previous mpris art at {}: {err}",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
let resized =
|
let resized =
|
||||||
image_copy.resize(400, 400, image::imageops::FilterType::Lanczos3);
|
image_copy.resize(400, 400, image::imageops::FilterType::Lanczos3);
|
||||||
resized.save_with_format(save_path, image::ImageFormat::Jpeg)?;
|
resized.save_with_format(&save_path_copy, image::ImageFormat::Jpeg)?;
|
||||||
|
*mpris_art_path = Some(save_path_copy);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue