mirror of
https://github.com/Stremio/stremio-shell-ng.git
synced 2026-05-19 03:41:54 +00:00
Bump libmpv2 crate from 4.1.0 to 5.0.3
The 4.x -> 5.x release folded `EventContext` into `Mpv` and made `wait_event` take `&mut self`, so the previous design (a single `Arc<Mpv>` shared between the message and event threads, with the event thread constructing its own `EventContext` from `mpv.ctx`) no longer compiles. Migration: - Build the main `Mpv` (with `wid`, `title`, etc.) and use it from the message thread for commands and `set_property`. - `create_client(None)` a sub-client `Mpv`, owned by the event thread, which calls `disable_deprecated_events`/`observe_property`/`wait_event` on itself. Global events (`EndFile`, `Shutdown`) and property changes observed by this client land in its event queue. - Replace the old `MpvExt::wake_up` (which woke the main `Mpv`) with an `EventClientWakeup` holding the sub-client's `mpv_handle` pointer, so the message thread can interrupt the event thread's blocking `wait_event` after pushing a new observe request onto the channel. Also removed the `PropertyData::Node(_)` match arm in `communication.rs`: 5.0.0 dropped `mpv_node` support, so the variant no longer exists and the match is exhaustive without it. https://claude.ai/code/session_01CuGHFREBZFkf8tfaiRV4K6
This commit is contained in:
parent
e199d7f38c
commit
9b057a0030
4 changed files with 34 additions and 27 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
|
@ -880,9 +880,9 @@ checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libmpv2"
|
name = "libmpv2"
|
||||||
version = "4.1.0"
|
version = "5.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e0c3802b4bb1a18adbf5659b078ce24cb8e16c79ff695557f4e10af2a44722a"
|
checksum = "88dc8432d3de09ed6e343488d6b208467db6801fb41971a1f726fa2248302fe5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libmpv2-sys",
|
"libmpv2-sys",
|
||||||
]
|
]
|
||||||
|
|
@ -1598,7 +1598,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stremio-shell-ng"
|
name = "stremio-shell-ng"
|
||||||
version = "5.0.20"
|
version = "5.0.21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.4.2",
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ winapi = { version = "0.3.9", features = [
|
||||||
] }
|
] }
|
||||||
webview2 = "0.1.4"
|
webview2 = "0.1.4"
|
||||||
webview2-sys = "0.1.1"
|
webview2-sys = "0.1.1"
|
||||||
libmpv2 = "4.1.0"
|
libmpv2 = "5.0.3"
|
||||||
libmpv2-sys = "4.0.1"
|
libmpv2-sys = "4.0.1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ impl PlayerProprChange {
|
||||||
serde_json::Value::String(s.to_string())
|
serde_json::Value::String(s.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PropertyData::Node(_) => unimplemented!("`PropertyData::Node` is not supported"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_name_value(name: String, value: PropertyData) -> Self {
|
pub fn from_name_value(name: String, value: PropertyData) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::stremio_app::ipc;
|
use crate::stremio_app::ipc;
|
||||||
use crate::stremio_app::RPCResponse;
|
use crate::stremio_app::RPCResponse;
|
||||||
use flume::{Receiver, Sender};
|
use flume::{Receiver, Sender};
|
||||||
use libmpv2::{events::Event, events::EventContext, Format, Mpv, SetData};
|
use libmpv2::{events::Event, Format, Mpv, SetData};
|
||||||
use native_windows_gui::{self as nwg, PartialUi};
|
use native_windows_gui::{self as nwg, PartialUi};
|
||||||
use std::{
|
use std::{
|
||||||
|
ptr::NonNull,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
thread::{self, JoinHandle},
|
thread::{self, JoinHandle},
|
||||||
};
|
};
|
||||||
|
|
@ -19,6 +20,18 @@ struct ObserveProperty {
|
||||||
format: Format,
|
format: Format,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wakes up the event thread blocked in `mpv_wait_event` on the sub-client.
|
||||||
|
// `mpv_wakeup` is documented as safe to call from any thread.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct EventClientWakeup(NonNull<libmpv2_sys::mpv_handle>);
|
||||||
|
unsafe impl Send for EventClientWakeup {}
|
||||||
|
unsafe impl Sync for EventClientWakeup {}
|
||||||
|
impl EventClientWakeup {
|
||||||
|
fn wake_up(&self) {
|
||||||
|
unsafe { libmpv2_sys::mpv_wakeup(self.0.as_ptr()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
pub channel: ipc::Channel,
|
pub channel: ipc::Channel,
|
||||||
|
|
@ -43,21 +56,26 @@ impl PartialUi for Player {
|
||||||
let (observe_property_sender, observe_property_receiver) = flume::unbounded();
|
let (observe_property_sender, observe_property_receiver) = flume::unbounded();
|
||||||
data.channel = ipc::Channel::new(Some((in_msg_sender, rpc_response_receiver)));
|
data.channel = ipc::Channel::new(Some((in_msg_sender, rpc_response_receiver)));
|
||||||
|
|
||||||
let mpv = create_shareable_mpv(window_handle);
|
let mpv = Arc::new(create_mpv(window_handle));
|
||||||
|
let mpv_event_client = mpv
|
||||||
|
.create_client(None)
|
||||||
|
.expect("cannot create MPV event client");
|
||||||
|
let event_wakeup = EventClientWakeup(mpv_event_client.ctx);
|
||||||
|
|
||||||
let _event_thread = create_event_thread(
|
let _event_thread = create_event_thread(
|
||||||
Arc::clone(&mpv),
|
mpv_event_client,
|
||||||
observe_property_receiver,
|
observe_property_receiver,
|
||||||
rpc_response_sender,
|
rpc_response_sender,
|
||||||
);
|
);
|
||||||
let _message_thread = create_message_thread(mpv, observe_property_sender, in_msg_receiver);
|
let _message_thread =
|
||||||
|
create_message_thread(mpv, event_wakeup, observe_property_sender, in_msg_receiver);
|
||||||
// @TODO implement a mechanism to stop threads on `Player` drop if needed
|
// @TODO implement a mechanism to stop threads on `Player` drop if needed
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_shareable_mpv(window_handle: HWND) -> Arc<Mpv> {
|
fn create_mpv(window_handle: HWND) -> Mpv {
|
||||||
let mpv = Mpv::with_initializer(|initializer| {
|
let mpv = Mpv::with_initializer(|initializer| {
|
||||||
macro_rules! set_property {
|
macro_rules! set_property {
|
||||||
($name:literal, $value:expr) => {
|
($name:literal, $value:expr) => {
|
||||||
|
|
@ -79,17 +97,16 @@ fn create_shareable_mpv(window_handle: HWND) -> Arc<Mpv> {
|
||||||
// set_property!("vo", "gpu-next,");
|
// set_property!("vo", "gpu-next,");
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
Arc::new(mpv.expect("cannot build MPV"))
|
mpv.expect("cannot build MPV")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_event_thread(
|
fn create_event_thread(
|
||||||
mpv: Arc<Mpv>,
|
mut mpv_event_client: Mpv,
|
||||||
observe_property_receiver: Receiver<ObserveProperty>,
|
observe_property_receiver: Receiver<ObserveProperty>,
|
||||||
rpc_response_sender: Sender<String>,
|
rpc_response_sender: Sender<String>,
|
||||||
) -> JoinHandle<()> {
|
) -> JoinHandle<()> {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut event_context = EventContext::new(mpv.ctx);
|
mpv_event_client
|
||||||
event_context
|
|
||||||
.disable_deprecated_events()
|
.disable_deprecated_events()
|
||||||
.expect("failed to disable deprecated MPV events");
|
.expect("failed to disable deprecated MPV events");
|
||||||
|
|
||||||
|
|
@ -97,13 +114,13 @@ fn create_event_thread(
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
for ObserveProperty { name, format } in observe_property_receiver.drain() {
|
for ObserveProperty { name, format } in observe_property_receiver.drain() {
|
||||||
event_context
|
mpv_event_client
|
||||||
.observe_property(&name, format, 0)
|
.observe_property(&name, format, 0)
|
||||||
.expect("failed to observer MPV property");
|
.expect("failed to observer MPV property");
|
||||||
}
|
}
|
||||||
|
|
||||||
// -1.0 means to block and wait for an event.
|
// -1.0 means to block and wait for an event.
|
||||||
let event = match event_context.wait_event(-1.) {
|
let event = match mpv_event_client.wait_event(-1.) {
|
||||||
Some(Ok(event)) => event,
|
Some(Ok(event)) => event,
|
||||||
Some(Err(error)) => {
|
Some(Err(error)) => {
|
||||||
eprintln!("Event errored: {error:?}");
|
eprintln!("Event errored: {error:?}");
|
||||||
|
|
@ -141,6 +158,7 @@ fn create_event_thread(
|
||||||
|
|
||||||
fn create_message_thread(
|
fn create_message_thread(
|
||||||
mpv: Arc<Mpv>,
|
mpv: Arc<Mpv>,
|
||||||
|
event_wakeup: EventClientWakeup,
|
||||||
observe_property_sender: Sender<ObserveProperty>,
|
observe_property_sender: Sender<ObserveProperty>,
|
||||||
in_msg_receiver: Receiver<String>,
|
in_msg_receiver: Receiver<String>,
|
||||||
) -> JoinHandle<()> {
|
) -> JoinHandle<()> {
|
||||||
|
|
@ -151,7 +169,7 @@ fn create_message_thread(
|
||||||
observe_property_sender
|
observe_property_sender
|
||||||
.send(ObserveProperty { name, format })
|
.send(ObserveProperty { name, format })
|
||||||
.expect("cannot send ObserveProperty");
|
.expect("cannot send ObserveProperty");
|
||||||
mpv.wake_up();
|
event_wakeup.wake_up();
|
||||||
};
|
};
|
||||||
|
|
||||||
let send_command = |cmd: CmdVal| {
|
let send_command = |cmd: CmdVal| {
|
||||||
|
|
@ -252,13 +270,3 @@ fn create_message_thread(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
trait MpvExt {
|
|
||||||
fn wake_up(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MpvExt for Mpv {
|
|
||||||
// @TODO create a PR to the `libmpv` crate and then remove `libmpv-sys` from Cargo.toml?
|
|
||||||
fn wake_up(&self) {
|
|
||||||
unsafe { libmpv2_sys::mpv_wakeup(self.ctx.as_ptr()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue