audrey/src/playbin2.rs

199 lines
5.2 KiB
Rust
Raw Normal View History

2024-11-03 12:41:02 +00:00
use crate::mpv;
2024-11-03 13:59:54 +00:00
use crate::signal::SignalEmitter;
2024-11-03 12:41:02 +00:00
use event_listener::EventListener;
2024-11-03 13:59:54 +00:00
use std::cell::{Ref, RefCell};
use url::Url;
2024-11-03 12:41:02 +00:00
2024-11-03 13:59:54 +00:00
pub trait PlaybinEntry {
fn url(&self) -> &Url;
}
impl PlaybinEntry for Url {
fn url(&self) -> &Url {
self
}
}
// E: generic entry type
pub struct Playbin<E> {
2024-11-03 12:41:02 +00:00
mpv: mpv::Handle,
2024-11-03 13:59:54 +00:00
entries: RefCell<Vec<E>>,
paused_changed: SignalEmitter<()>,
current_entry_changed: SignalEmitter<()>,
entry_inserted: SignalEmitter<u32>,
stopped: SignalEmitter<()>,
entry_removed: SignalEmitter<u32>,
2024-11-03 12:41:02 +00:00
}
2024-11-03 13:59:54 +00:00
impl<E> Default for Playbin<E> {
2024-11-03 12:41:02 +00:00
fn default() -> Self {
let mpv = mpv::Handle::new();
mpv.set_property("audio-client-name", "audrey").unwrap();
mpv.set_property("user-agent", crate::USER_AGENT).unwrap();
mpv.set_property("video", false).unwrap();
mpv.set_property("prefetch-playlist", true).unwrap();
mpv.set_property("gapless-audio", true).unwrap();
2024-11-03 13:59:54 +00:00
mpv.observe_property(0, "pause").unwrap();
mpv.observe_property(1, "playlist-pos").unwrap();
// "Useful to drain property changes before a new file is loaded."
mpv.add_hook(0, "on_before_start_file", 0).unwrap();
Self {
mpv,
entries: RefCell::new(vec![]),
paused_changed: Default::default(),
current_entry_changed: Default::default(),
2024-11-03 12:41:02 +00:00
2024-11-03 13:59:54 +00:00
entry_inserted: Default::default(),
stopped: Default::default(),
entry_removed: Default::default(),
}
2024-11-03 12:41:02 +00:00
}
}
2024-11-03 13:59:54 +00:00
impl<E> Playbin<E>
where
E: PlaybinEntry,
{
pub fn paused(&self) -> bool {
self.mpv.get_property("pause").unwrap()
}
pub fn set_paused(&self, paused: bool) {
self.mpv.set_property("pause", paused).unwrap();
}
pub fn position(&self) -> Option<f64> {
todo!()
}
pub fn current_entry(&self) -> Option<u32> {
self.mpv
.get_property::<i64>("playlist-pos")
.unwrap()
.try_into()
.ok()
}
pub fn seek(&self, _position: f64) {
todo!()
}
pub fn next_entry(&self) {
self.mpv.command(["playlist-next"]).unwrap();
}
pub fn prev_entry(&self) {
self.mpv.command(["playlist-prev"]).unwrap();
}
pub fn play_entry(&self, index: u32) {
self.mpv
.command(["playlist-play-index", &index.to_string()])
.unwrap();
}
pub fn entries(&self) -> Ref<'_, [E]> {
Ref::map(self.entries.borrow(), Vec::as_ref)
}
pub fn push_entry(&self, entry: E) {
let mut entries = self.entries.borrow_mut();
self.mpv
.command(["loadfile", entry.url().as_str(), "append-play"])
.unwrap();
let index = entries.len();
entries.push(entry);
drop(entries);
self.entry_inserted.emit(index as u32);
}
pub fn insert_entry(&self, index: u32, entry: E) {
let mut entries = self.entries.borrow_mut();
self.mpv
.command(["loadfile", entry.url().as_str(), "insert-at-play"])
.unwrap();
entries.insert(index as usize, entry);
drop(entries);
self.entry_inserted.emit(index);
}
// stop playback and clear playlist
pub fn stop(&self) {
let mut entries = self.entries.borrow_mut();
self.mpv.command(["stop"]).unwrap();
entries.clear();
drop(entries);
self.stopped.emit(());
}
pub fn remove_entry(&self, index: u32) {
let mut entries = self.entries.borrow_mut();
self.mpv.command(["remove", &index.to_string()]).unwrap();
entries.remove(index as usize);
drop(entries);
self.entry_removed.emit(index);
}
pub fn move_entry(&self, _from: u32, _to: u32) {
todo!()
}
2024-11-03 12:41:02 +00:00
pub fn tick(&self) -> EventListener {
let listener = self.mpv.wakeup_listener();
while let Some(event) = self.mpv.wait_event(0.0) {
self.handle_event(event);
}
listener
}
fn handle_event(&self, event: mpv::Event) {
2024-11-03 13:59:54 +00:00
match event {
mpv::Event::PropertyChange(event) => match event.reply_userdata {
0 => {
assert_eq!(&event.name, "pause");
self.paused_changed.emit(());
println!("new paused! {:?}", self.paused());
}
1 => {
assert_eq!(&event.name, "playlist-pos");
self.current_entry_changed.emit(());
println!("new current_entry! {:?}", self.current_entry());
}
_ => unreachable!(),
},
mpv::Event::Hook(event) => match event.reply_userdata {
0 => {
assert_eq!(&event.name, "on_before_start_file");
// just use this as a barrier
println!("on_before_start_file triggered");
2024-11-03 14:06:11 +00:00
self.mpv.continue_hook(event.id).unwrap();
2024-11-03 13:59:54 +00:00
}
_ => unreachable!(),
},
_ => println!("mpv event {:?}", event),
}
2024-11-03 12:41:02 +00:00
}
}
2024-11-03 13:59:54 +00:00
impl<E> Drop for Playbin<E> {
2024-11-03 12:41:02 +00:00
fn drop(&mut self) {
println!("dropping Playbin2");
self.mpv.command(["quit"]).unwrap();
}
}