Compare commits
2 commits
4e434a7929
...
a6378b281a
Author | SHA1 | Date | |
---|---|---|---|
a6378b281a | |||
02e3415e72 |
9 changed files with 117 additions and 110 deletions
42
build.rs
42
build.rs
|
@ -1,53 +1,21 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
std::env::var("MESON_BUILD_ROOT").expect("build this through meson please!!");
|
let meson_build_root =
|
||||||
let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
std::env::var("MESON_BUILD_ROOT").expect("build this through meson please!!");
|
||||||
|
|
||||||
// compile blueprints
|
|
||||||
{
|
|
||||||
let mut command = std::process::Command::new("blueprint-compiler");
|
|
||||||
|
|
||||||
command
|
|
||||||
.arg("batch-compile")
|
|
||||||
.arg(out_path.join("resources"))
|
|
||||||
.arg("resources");
|
|
||||||
|
|
||||||
for source in [
|
|
||||||
"play_queue.blp",
|
|
||||||
"play_queue_song.blp",
|
|
||||||
"playbar.blp",
|
|
||||||
"setup.blp",
|
|
||||||
"window.blp",
|
|
||||||
] {
|
|
||||||
command.arg(format!("resources/{source}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = command.output().unwrap();
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"blueprint-compiler failed with exit status {} and stdout:\n{}",
|
|
||||||
output.status,
|
|
||||||
String::from_utf8_lossy(&output.stdout)
|
|
||||||
);
|
|
||||||
|
|
||||||
println!("cargo::rerun-if-changed=resources");
|
|
||||||
}
|
|
||||||
|
|
||||||
glib_build_tools::compile_resources(
|
glib_build_tools::compile_resources(
|
||||||
&[PathBuf::from("resources"), out_path.join("resources")],
|
&["resources", &format!("{meson_build_root}/resources")],
|
||||||
"resources/audrey.gresource.xml",
|
"resources/audrey.gresource.xml",
|
||||||
"audrey.gresource",
|
"audrey.gresource",
|
||||||
);
|
);
|
||||||
println!("cargo::rerun-if-changed=resources/audrey.gresource.xml");
|
println!("cargo::rerun-if-changed=resources/audrey.gresource.xml");
|
||||||
|
|
||||||
// TODO: consider using meson to pass include paths
|
// TODO: consider using meson to pass include paths
|
||||||
println!("cargo::rustc-link-lib=mpv");
|
println!("cargo:rustc-link-lib=mpv");
|
||||||
let bindings = bindgen::Builder::default()
|
let bindings = bindgen::Builder::default()
|
||||||
.header("src/mpv/wrapper.h")
|
.header("src/mpv/wrapper.h")
|
||||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
||||||
.generate()
|
.generate()
|
||||||
.expect("could not generate bindings for mpv");
|
.expect("could not generate bindings for mpv");
|
||||||
|
let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
||||||
bindings
|
bindings
|
||||||
.write_to_file(out_path.join("mpv_ffi.rs"))
|
.write_to_file(out_path.join("mpv_ffi.rs"))
|
||||||
.expect("could not write mpv bindings");
|
.expect("could not write mpv bindings");
|
||||||
|
|
|
@ -38,6 +38,7 @@ add_project_arguments(
|
||||||
|
|
||||||
subdir('data')
|
subdir('data')
|
||||||
subdir('po')
|
subdir('po')
|
||||||
|
subdir('resources')
|
||||||
subdir('src')
|
subdir('src')
|
||||||
|
|
||||||
if get_option('buildtype') == 'debug'
|
if get_option('buildtype') == 'debug'
|
||||||
|
@ -59,6 +60,7 @@ custom_target(
|
||||||
'cargo-build',
|
'cargo-build',
|
||||||
build_by_default: true,
|
build_by_default: true,
|
||||||
build_always_stale: true,
|
build_always_stale: true,
|
||||||
|
depends: blueprints,
|
||||||
input: config_rs,
|
input: config_rs,
|
||||||
console: true,
|
console: true,
|
||||||
# means nothing (always stale and uncopied), we can't cp since env: drops the /bin/sh wrapper
|
# means nothing (always stale and uncopied), we can't cp since env: drops the /bin/sh wrapper
|
||||||
|
|
24
resources/meson.build
Normal file
24
resources/meson.build
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
blueprints = custom_target(
|
||||||
|
'blueprints',
|
||||||
|
input: files(
|
||||||
|
'play_queue.blp',
|
||||||
|
'play_queue_song.blp',
|
||||||
|
'playbar.blp',
|
||||||
|
'setup.blp',
|
||||||
|
'window.blp',
|
||||||
|
),
|
||||||
|
output: [
|
||||||
|
'play_queue.ui',
|
||||||
|
'play_queue_song.ui',
|
||||||
|
'playbar.ui',
|
||||||
|
'setup.ui',
|
||||||
|
'window.ui',
|
||||||
|
],
|
||||||
|
command: [
|
||||||
|
find_program('blueprint-compiler'),
|
||||||
|
'batch-compile',
|
||||||
|
'@OUTDIR@',
|
||||||
|
'@CURRENT_SOURCE_DIR@',
|
||||||
|
'@INPUT@',
|
||||||
|
],
|
||||||
|
)
|
|
@ -36,7 +36,7 @@ template $AudreyUiPlaybar: Adw.Bin {
|
||||||
|
|
||||||
xalign: 0;
|
xalign: 0;
|
||||||
halign: start;
|
halign: start;
|
||||||
label: bind $song_title(template.song) as <string>;
|
label: bind template.song as <$AudreyPlaybinSong>.title;
|
||||||
ellipsize: end;
|
ellipsize: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ template $AudreyUiPlaybar: Adw.Bin {
|
||||||
]
|
]
|
||||||
|
|
||||||
xalign: 0;
|
xalign: 0;
|
||||||
label: bind $song_artist(template.song) as <string>;
|
label: bind template.song as <$AudreyPlaybinSong>.artist;
|
||||||
ellipsize: end;
|
ellipsize: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ template $AudreyUiPlaybar: Adw.Bin {
|
||||||
]
|
]
|
||||||
|
|
||||||
xalign: 0;
|
xalign: 0;
|
||||||
label: bind $song_album(template.song) as <string>;
|
label: bind template.song as <$AudreyPlaybinSong>.album;
|
||||||
ellipsize: end;
|
ellipsize: end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ template $AudreyUiPlaybar: Adw.Bin {
|
||||||
name: "seek-scale";
|
name: "seek-scale";
|
||||||
orientation: horizontal;
|
orientation: horizontal;
|
||||||
width-request: 400;
|
width-request: 400;
|
||||||
// sensitive: bind $playbin_active (template.playbin as <$AudreyPlaybin>.state as <$AudreyPlaybinState>) as <bool>;
|
sensitive: bind template.idle-active inverted;
|
||||||
adjustment: Adjustment {
|
adjustment: Adjustment {
|
||||||
lower: 0;
|
lower: 0;
|
||||||
value: bind template.position;
|
value: bind template.position;
|
||||||
|
@ -111,35 +111,35 @@ template $AudreyUiPlaybar: Adw.Bin {
|
||||||
Button {
|
Button {
|
||||||
icon-name: "media-skip-backward";
|
icon-name: "media-skip-backward";
|
||||||
valign: center;
|
valign: center;
|
||||||
// sensitive: bind $playbin_active (template.playbin as <$AudreyPlaybin>.state as <$AudreyPlaybinState>) as <bool>;
|
sensitive: bind template.idle-active inverted;
|
||||||
clicked => $on_skip_backward_clicked() swapped;
|
clicked => $on_skip_backward_clicked() swapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
icon-name: "media-seek-backward";
|
icon-name: "media-seek-backward";
|
||||||
valign: center;
|
valign: center;
|
||||||
// sensitive: bind $playbin_active (template.playbin as <$AudreyPlaybin>.state as <$AudreyPlaybinState>) as <bool>;
|
sensitive: bind template.idle-active inverted;
|
||||||
clicked => $seek_backward() swapped;
|
clicked => $seek_backward() swapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
icon-name: bind $play_pause_icon_name(template.idle-active, template.pause) as <string>;
|
icon-name: bind $play_pause_icon_name(template.idle-active, template.pause) as <string>;
|
||||||
valign: center;
|
valign: center;
|
||||||
// sensitive: bind $can_press_play (template.playbin as <$AudreyPlaybin>.state as <$AudreyPlaybinState>, template.playbin as <$AudreyPlaybin>.play-queue-length) as <bool>;
|
sensitive: bind $play_pause_sensitive(template.playlist-count) as <bool>;
|
||||||
clicked => $on_play_pause_clicked() swapped;
|
clicked => $on_play_pause_clicked() swapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
icon-name: "media-seek-forward";
|
icon-name: "media-seek-forward";
|
||||||
valign: center;
|
valign: center;
|
||||||
// sensitive: bind $playbin_active (template.playbin as <$AudreyPlaybin>.state as <$AudreyPlaybinState>) as <bool>;
|
sensitive: bind template.idle-active inverted;
|
||||||
clicked => $seek_forward() swapped;
|
clicked => $seek_forward() swapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
icon-name: "media-skip-forward";
|
icon-name: "media-skip-forward";
|
||||||
valign: center;
|
valign: center;
|
||||||
// sensitive: bind $playbin_active (template.playbin as <$AudreyPlaybin>.state as <$AudreyPlaybinState>) as <bool>;
|
sensitive: bind template.idle-active inverted;
|
||||||
clicked => $on_skip_forward_clicked() swapped;
|
clicked => $on_skip_forward_clicked() swapped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,14 +141,15 @@ template $AudreyUiWindow: Adw.ApplicationWindow {
|
||||||
[bottom]
|
[bottom]
|
||||||
$AudreyUiPlaybar playbar {
|
$AudreyUiPlaybar playbar {
|
||||||
song: bind template.song;
|
song: bind template.song;
|
||||||
playing_cover_art: bind template.playing_cover_art;
|
playing-cover-art: bind template.playing-cover-art;
|
||||||
show_cover_art: bind $show_playbar_cover_art(stack.visible-child-name) as <bool>;
|
show-cover-art: bind $show_playbar_cover_art(stack.visible-child-name) as <bool>;
|
||||||
volume: bind template.volume bidirectional;
|
volume: bind template.volume bidirectional;
|
||||||
mute: bind template.mute bidirectional;
|
mute: bind template.mute bidirectional;
|
||||||
pause: bind template.pause bidirectional;
|
pause: bind template.pause bidirectional;
|
||||||
position: bind template.time-pos;
|
position: bind template.time-pos;
|
||||||
duration: bind template.song as <$AudreyPlaybinSong>.duration;
|
duration: bind template.duration;
|
||||||
idle-active: bind template.idle-active;
|
idle-active: bind template.idle-active;
|
||||||
|
playlist-count: bind template.playlist-count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
use std::future::Future;
|
|
||||||
use std::task::Waker;
|
|
||||||
|
|
||||||
pub struct WaitEvent<'a>(&'a Handle);
|
|
||||||
|
|
||||||
impl Future for WaitEvent {
|
|
||||||
type Output = Event;
|
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
// set wakeup before polling, don't miss any wakeup events
|
|
||||||
{
|
|
||||||
let waker = self.0.wakeup.lock();
|
|
||||||
match waker.as_mut() {
|
|
||||||
None => *waker = cx.waker().clone(),
|
|
||||||
Some(waker) if !cx.waker().will_wake(waker) => *waker = cx.waker().clone,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.0.wait_event_timeout(0.0) {
|
|
||||||
Some(event) => Poll::Ready(event),
|
|
||||||
None => Poll::Pending,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) extern "C" fn callback(d: *mut c_void) {
|
|
||||||
let d = d as *const Mutex<Option<Waker>>;
|
|
||||||
let waker = unsafe { &*d };
|
|
||||||
let waker = waker.lock().unwrap();
|
|
||||||
if let Some(waker) = waker.take() {
|
|
||||||
waker.wake();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@ mod imp {
|
||||||
#[template(resource = "/eu/callcc/audrey/play_queue_song.ui")]
|
#[template(resource = "/eu/callcc/audrey/play_queue_song.ui")]
|
||||||
#[properties(wrapper_type = super::Song)]
|
#[properties(wrapper_type = super::Song)]
|
||||||
pub struct Song {
|
pub struct Song {
|
||||||
#[property(type = i64, set = Self::set_playlist_pos)]
|
#[property(type = i32, set = Self::set_playlist_pos)]
|
||||||
_playlist_pos: (),
|
_playlist_pos: (),
|
||||||
|
|
||||||
#[property(set, get)]
|
#[property(set, get)]
|
||||||
|
@ -163,9 +163,9 @@ mod imp {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_playlist_pos(&self, playlist_pos: i64) {
|
fn set_playlist_pos(&self, playlist_pos: i32) {
|
||||||
self.obj()
|
self.obj()
|
||||||
.set_current(playlist_pos == self.position.get() as i64);
|
.set_current(playlist_pos == self.position.get() as i32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,17 @@ mod imp {
|
||||||
#[property(get, set, default = true)]
|
#[property(get, set, default = true)]
|
||||||
show_cover_art: Cell<bool>,
|
show_cover_art: Cell<bool>,
|
||||||
|
|
||||||
|
// synced with root window
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
_volume: Cell<i64>,
|
_volume: Cell<u32>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
_mute: Cell<bool>,
|
_mute: Cell<bool>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
_pause: Cell<bool>,
|
_pause: Cell<bool>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
_idle_active: Cell<bool>,
|
_idle_active: Cell<bool>,
|
||||||
|
#[property(get, set)]
|
||||||
|
_playlist_count: Cell<u32>,
|
||||||
|
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
position: Cell<f64>,
|
position: Cell<f64>,
|
||||||
|
@ -58,21 +61,6 @@ mod imp {
|
||||||
|
|
||||||
#[gtk::template_callbacks]
|
#[gtk::template_callbacks]
|
||||||
impl Playbar {
|
impl Playbar {
|
||||||
#[template_callback]
|
|
||||||
fn song_title(&self, song: Option<&PlaybinSong>) -> Option<String> {
|
|
||||||
song.map(|song| song.title())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[template_callback]
|
|
||||||
fn song_artist(&self, song: Option<&PlaybinSong>) -> Option<String> {
|
|
||||||
song.map(|song| song.artist())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[template_callback]
|
|
||||||
fn song_album(&self, song: Option<&PlaybinSong>) -> Option<String> {
|
|
||||||
song.map(|song| song.album())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn format_timestamp(&self, s: f64) -> String {
|
fn format_timestamp(&self, s: f64) -> String {
|
||||||
format!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60)
|
format!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60)
|
||||||
|
@ -164,6 +152,11 @@ mod imp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn play_pause_sensitive(&self, playlist_count: u32) -> bool {
|
||||||
|
playlist_count > 0
|
||||||
|
}
|
||||||
|
|
||||||
fn window(&self) -> crate::ui::Window {
|
fn window(&self) -> crate::ui::Window {
|
||||||
self.obj().root().unwrap().dynamic_cast().unwrap()
|
self.obj().root().unwrap().dynamic_cast().unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,18 +36,22 @@ mod imp {
|
||||||
#[property(get)]
|
#[property(get)]
|
||||||
playlist_model: gio::ListStore,
|
playlist_model: gio::ListStore,
|
||||||
|
|
||||||
#[property(type = i64, get = Self::volume, set = Self::set_volume)]
|
#[property(type = u32, get = Self::volume, set = Self::set_volume)]
|
||||||
_volume: (),
|
_volume: (),
|
||||||
#[property(type = bool, get = Self::mute, set = Self::set_mute)]
|
#[property(type = bool, get = Self::mute, set = Self::set_mute)]
|
||||||
_mute: (),
|
_mute: (),
|
||||||
#[property(type = bool, get = Self::pause, set = Self::set_pause)]
|
#[property(type = bool, get = Self::pause, set = Self::set_pause)]
|
||||||
_pause: (),
|
_pause: (),
|
||||||
#[property(type = i64, get = Self::playlist_pos)]
|
#[property(type = i32, get = Self::playlist_pos)]
|
||||||
_playlist_pos: (),
|
_playlist_pos: (),
|
||||||
#[property(type = f64, get = Self::time_pos)]
|
#[property(type = f64, get = Self::time_pos)]
|
||||||
_time_pos: (),
|
_time_pos: (),
|
||||||
|
#[property(type = f64, get = Self::duration)]
|
||||||
|
_duration: (), // as reported by mpv, compare with song.duration
|
||||||
#[property(type = bool, get = Self::idle_active)]
|
#[property(type = bool, get = Self::idle_active)]
|
||||||
_idle_active: (),
|
_idle_active: (),
|
||||||
|
#[property(type = u32, get = Self::playlist_count)]
|
||||||
|
_playlist_count: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Window {
|
impl Default for Window {
|
||||||
|
@ -65,6 +69,8 @@ mod imp {
|
||||||
mpv.observe_property(3, "playlist-pos").unwrap();
|
mpv.observe_property(3, "playlist-pos").unwrap();
|
||||||
mpv.observe_property(4, "idle-active").unwrap();
|
mpv.observe_property(4, "idle-active").unwrap();
|
||||||
mpv.observe_property(5, "time-pos").unwrap();
|
mpv.observe_property(5, "time-pos").unwrap();
|
||||||
|
mpv.observe_property(6, "playlist-count").unwrap();
|
||||||
|
mpv.observe_property(7, "duration").unwrap();
|
||||||
|
|
||||||
// "Useful to drain property changes before a new file is loaded."
|
// "Useful to drain property changes before a new file is loaded."
|
||||||
mpv.add_hook(0, "on_before_start_file", 0).unwrap();
|
mpv.add_hook(0, "on_before_start_file", 0).unwrap();
|
||||||
|
@ -85,7 +91,9 @@ mod imp {
|
||||||
_pause: (),
|
_pause: (),
|
||||||
_playlist_pos: (),
|
_playlist_pos: (),
|
||||||
_time_pos: (),
|
_time_pos: (),
|
||||||
|
_duration: (),
|
||||||
_idle_active: (),
|
_idle_active: (),
|
||||||
|
_playlist_count: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,6 +161,16 @@ mod imp {
|
||||||
window.notify("time-pos");
|
window.notify("time-pos");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6 => {
|
||||||
|
assert_eq!(event.name, "playlist-count");
|
||||||
|
window.notify("playlist-count");
|
||||||
|
}
|
||||||
|
|
||||||
|
7 => {
|
||||||
|
assert_eq!(event.name, "duration");
|
||||||
|
window.notify("duration");
|
||||||
|
}
|
||||||
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -296,12 +314,16 @@ mod imp {
|
||||||
self.setup.present(Some(self.obj().as_ref()));
|
self.setup.present(Some(self.obj().as_ref()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn volume(&self) -> i64 {
|
fn volume(&self) -> u32 {
|
||||||
self.mpv.get_property("volume").unwrap()
|
self.mpv
|
||||||
|
.get_property::<i64>("volume")
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_volume(&self, volume: i64) {
|
fn set_volume(&self, volume: u32) {
|
||||||
self.mpv.set_property("volume", volume).unwrap();
|
self.mpv.set_property("volume", volume as i64).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mute(&self) -> bool {
|
fn mute(&self) -> bool {
|
||||||
|
@ -320,8 +342,12 @@ mod imp {
|
||||||
self.mpv.set_property("pause", pause).unwrap();
|
self.mpv.set_property("pause", pause).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn playlist_pos(&self) -> i64 {
|
fn playlist_pos(&self) -> i32 {
|
||||||
self.mpv.get_property("playlist-pos").unwrap()
|
self.mpv
|
||||||
|
.get_property::<i64>("playlist-pos")
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn time_pos(&self) -> f64 {
|
fn time_pos(&self) -> f64 {
|
||||||
|
@ -333,10 +359,37 @@ mod imp {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn duration(&self) -> f64 {
|
||||||
|
let duration = match self.mpv.get_property::<f64>("duration") {
|
||||||
|
Ok(duration) => Ok(Some(duration)),
|
||||||
|
Err(err) if err.is_property_unavailable() => {
|
||||||
|
Ok(self.song().as_ref().map(|song| song.duration() as f64))
|
||||||
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
duration.map(|f| f as i64),
|
||||||
|
self.song().as_ref().map(crate::PlaybinSong::duration),
|
||||||
|
"mpv duration doesn not match subsonic duration (this should probably be a warn)"
|
||||||
|
);
|
||||||
|
|
||||||
|
duration.unwrap_or(0.0) // placeholder
|
||||||
|
}
|
||||||
|
|
||||||
fn idle_active(&self) -> bool {
|
fn idle_active(&self) -> bool {
|
||||||
self.mpv.get_property("idle-active").unwrap()
|
self.mpv.get_property("idle-active").unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn playlist_count(&self) -> u32 {
|
||||||
|
self.mpv
|
||||||
|
.get_property::<i64>("playlist-count")
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn song(&self) -> Option<PlaybinSong> {
|
fn song(&self) -> Option<PlaybinSong> {
|
||||||
if self.obj().playlist_pos() < 0 {
|
if self.obj().playlist_pos() < 0 {
|
||||||
None
|
None
|
||||||
|
|
Loading…
Reference in a new issue