mirror of
https://github.com/Stremio/stremio-shell-ng.git
synced 2026-04-21 16:01:56 +00:00
minor refactor + cargo fmt --all
This commit is contained in:
parent
81e088800b
commit
f10380f60a
6 changed files with 852 additions and 842 deletions
|
|
@ -100,7 +100,10 @@ impl MainWindow {
|
|||
let web_rx = web_rx.clone();
|
||||
// Read message from player
|
||||
thread::spawn(move || loop {
|
||||
player_rx.iter().map(|msg| web_tx_player.send(msg)).for_each(drop);
|
||||
player_rx
|
||||
.iter()
|
||||
.map(|msg| web_tx_player.send(msg))
|
||||
.for_each(drop);
|
||||
}); // thread
|
||||
|
||||
let toggle_fullscreen_sender = self.toggle_fullscreen_notice.sender();
|
||||
|
|
|
|||
|
|
@ -21,13 +21,9 @@ impl RPCRequest {
|
|||
.and_then(|arg| arg.as_str())
|
||||
}
|
||||
pub fn get_params(&self) -> Option<&serde_json::Value> {
|
||||
self.args.as_ref().and_then(|args| {
|
||||
if args.len() > 1 {
|
||||
Some(&args[1])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
self.args
|
||||
.as_ref()
|
||||
.and_then(|args| if args.len() > 1 { Some(&args[1]) } else { None })
|
||||
}
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use core::convert::TryFrom;
|
||||
use libmpv::{events::PropertyData, mpv_end_file_reason, EndFileReason};
|
||||
use parse_display::{Display, FromStr};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use libmpv::{events::PropertyData, EndFileReason, mpv_end_file_reason};
|
||||
|
||||
// Responses
|
||||
const JSON_RESPONSES: [&str; 3] = ["track-list", "video-params", "metadata"];
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
use crate::stremio_app::ipc;
|
||||
use crate::stremio_app::RPCResponse;
|
||||
use flume::{Receiver, Sender};
|
||||
use libmpv::{Mpv, events::Event, Format, SetData};
|
||||
use libmpv::{events::Event, Format, Mpv, SetData};
|
||||
use native_windows_gui::{self as nwg, PartialUi};
|
||||
use std::{
|
||||
sync::Arc,
|
||||
thread::{self, JoinHandle},
|
||||
};
|
||||
use winapi::shared::windef::HWND;
|
||||
use std::{thread::{self, JoinHandle}, sync::Arc};
|
||||
|
||||
use crate::stremio_app::stremio_player::{
|
||||
InMsg, InMsgArgs, InMsgFn, PlayerEnded, PlayerEvent, PlayerProprChange, PlayerResponse,
|
||||
PropKey, PropVal, CmdVal,
|
||||
CmdVal, InMsg, InMsgArgs, InMsgFn, PlayerEnded, PlayerEvent, PlayerProprChange, PlayerResponse,
|
||||
PropKey, PropVal,
|
||||
};
|
||||
|
||||
struct ObserveProperty {
|
||||
|
|
@ -27,22 +30,26 @@ impl PartialUi for Player {
|
|||
data: &mut Self,
|
||||
parent: Option<W>,
|
||||
) -> Result<(), nwg::NwgError> {
|
||||
let (in_msg_sender, in_msg_receiver) = flume::unbounded();
|
||||
let (rpc_response_sender, rpc_response_receiver) = flume::unbounded();
|
||||
|
||||
data.channel = ipc::Channel::new(Some((in_msg_sender, rpc_response_receiver)));
|
||||
// @TODO replace all `expect`s with proper error handling?
|
||||
|
||||
let window_handle = parent
|
||||
.expect("no parent window")
|
||||
.into()
|
||||
.hwnd()
|
||||
.expect("cannot obtain window handle");
|
||||
// @TODO replace all `expect`s with proper error handling?
|
||||
|
||||
let (in_msg_sender, in_msg_receiver) = flume::unbounded();
|
||||
let (rpc_response_sender, rpc_response_receiver) = flume::unbounded();
|
||||
let (observe_property_sender, observe_property_receiver) = flume::unbounded();
|
||||
data.channel = ipc::Channel::new(Some((in_msg_sender, rpc_response_receiver)));
|
||||
|
||||
let mpv = create_shareable_mpv(window_handle);
|
||||
let (observe_property_sender, observe_property_receiver) = flume::unbounded();
|
||||
|
||||
let _event_thread = create_event_thread(Arc::clone(&mpv), observe_property_receiver, rpc_response_sender);
|
||||
let _event_thread = create_event_thread(
|
||||
Arc::clone(&mpv),
|
||||
observe_property_receiver,
|
||||
rpc_response_sender,
|
||||
);
|
||||
let _message_thread = create_message_thread(mpv, observe_property_sender, in_msg_receiver);
|
||||
// @TODO implement a mechanism to stop threads on `Player` drop if needed
|
||||
|
||||
|
|
@ -52,24 +59,43 @@ impl PartialUi for Player {
|
|||
|
||||
fn create_shareable_mpv(window_handle: HWND) -> Arc<Mpv> {
|
||||
let mpv = Mpv::with_initializer(|initializer| {
|
||||
initializer.set_property("wid", window_handle as i64).expect("failed setting wid");
|
||||
initializer
|
||||
.set_property("wid", window_handle as i64)
|
||||
.expect("failed setting wid");
|
||||
// initializer.set_property("vo", "gpu").expect("unable to set vo");
|
||||
// win, opengl: works but least performancy, 10-15% CPU
|
||||
// winvk, vulkan: works as good as d3d11
|
||||
// d3d11, d1d11: works great
|
||||
// dxinterop, auto: works, slightly more cpu use than d3d11
|
||||
// default (auto) seems to be d3d11 (vo/gpu/d3d11)
|
||||
initializer.set_property("gpu-context", "angle").expect("failed setting gpu-contex");
|
||||
initializer.set_property("gpu-api", "auto").expect("failed setting gpu-api");
|
||||
initializer.set_property("title", "Stremio").expect("failed setting title");
|
||||
initializer.set_property("terminal", "yes").expect("failed setting terminal");
|
||||
initializer.set_property("msg-level", "all=no,cplayer=debug").expect("failed setting msg-level");
|
||||
initializer.set_property("quiet", "yes").expect("failed setting quiet");
|
||||
initializer.set_property("hwdec", "auto").expect("failed setting hwdec");
|
||||
initializer
|
||||
.set_property("gpu-context", "angle")
|
||||
.expect("failed setting gpu-contex");
|
||||
initializer
|
||||
.set_property("gpu-api", "auto")
|
||||
.expect("failed setting gpu-api");
|
||||
initializer
|
||||
.set_property("title", "Stremio")
|
||||
.expect("failed setting title");
|
||||
initializer
|
||||
.set_property("terminal", "yes")
|
||||
.expect("failed setting terminal");
|
||||
initializer
|
||||
.set_property("msg-level", "all=no,cplayer=debug")
|
||||
.expect("failed setting msg-level");
|
||||
initializer
|
||||
.set_property("quiet", "yes")
|
||||
.expect("failed setting quiet");
|
||||
initializer
|
||||
.set_property("hwdec", "auto")
|
||||
.expect("failed setting hwdec");
|
||||
// FIXME: very often the audio track isn't selected when using "aid" = "auto"
|
||||
initializer.set_property("aid", 1).expect("failed setting aid");
|
||||
initializer
|
||||
.set_property("aid", 1)
|
||||
.expect("failed setting aid");
|
||||
Ok(())
|
||||
}).expect("cannot build MPV");
|
||||
})
|
||||
.expect("cannot build MPV");
|
||||
|
||||
Arc::new(mpv)
|
||||
}
|
||||
|
|
@ -77,15 +103,19 @@ fn create_shareable_mpv(window_handle: HWND) -> Arc<Mpv> {
|
|||
fn create_event_thread(
|
||||
mpv: Arc<Mpv>,
|
||||
observe_property_receiver: Receiver<ObserveProperty>,
|
||||
rpc_response_sender: Sender<String>
|
||||
rpc_response_sender: Sender<String>,
|
||||
) -> JoinHandle<()> {
|
||||
thread::spawn(move || {
|
||||
let mut event_context = mpv.create_event_context();
|
||||
event_context.disable_deprecated_events().expect("failed to disable deprecated MPV events");
|
||||
event_context
|
||||
.disable_deprecated_events()
|
||||
.expect("failed to disable deprecated MPV events");
|
||||
|
||||
loop {
|
||||
for ObserveProperty { name, format } in observe_property_receiver.drain() {
|
||||
event_context.observe_property(&name, format, 0).expect("failed to observer MPV property");
|
||||
event_context
|
||||
.observe_property(&name, format, 0)
|
||||
.expect("failed to observer MPV property");
|
||||
}
|
||||
|
||||
// -1.0 means to block and wait for an event.
|
||||
|
|
@ -100,32 +130,31 @@ fn create_event_thread(
|
|||
};
|
||||
|
||||
// even if you don't do anything with the events, it is still necessary to empty the event loop
|
||||
let resp_event = match event {
|
||||
Event::PropertyChange {
|
||||
name,
|
||||
change,
|
||||
..
|
||||
} => PlayerResponse(
|
||||
"mpv-prop-change",
|
||||
PlayerEvent::PropChange(PlayerProprChange::from_name_value(
|
||||
name.to_string(),
|
||||
change,
|
||||
)),
|
||||
)
|
||||
.to_value(),
|
||||
Event::EndFile(reason) => PlayerResponse(
|
||||
"mpv-event-ended",
|
||||
PlayerEvent::End(PlayerEnded::from_end_reason(reason)),
|
||||
)
|
||||
.to_value(),
|
||||
let player_response = match event {
|
||||
Event::PropertyChange { name, change, .. } => {
|
||||
PlayerResponse(
|
||||
"mpv-prop-change",
|
||||
PlayerEvent::PropChange(PlayerProprChange::from_name_value(
|
||||
name.to_string(),
|
||||
change,
|
||||
)),
|
||||
)
|
||||
}
|
||||
Event::EndFile(reason) => {
|
||||
PlayerResponse(
|
||||
"mpv-event-ended",
|
||||
PlayerEvent::End(PlayerEnded::from_end_reason(reason)),
|
||||
)
|
||||
}
|
||||
Event::Shutdown => {
|
||||
break;
|
||||
}
|
||||
_ => None,
|
||||
_ => continue,
|
||||
};
|
||||
if resp_event.is_some() {
|
||||
rpc_response_sender.send(RPCResponse::response_message(resp_event)).ok();
|
||||
}
|
||||
|
||||
rpc_response_sender
|
||||
.send(RPCResponse::response_message(player_response.to_value()))
|
||||
.expect("failed to send RPCResponse");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -133,28 +162,32 @@ fn create_event_thread(
|
|||
fn create_message_thread(
|
||||
mpv: Arc<Mpv>,
|
||||
observe_property_sender: Sender<ObserveProperty>,
|
||||
in_msg_receiver: Receiver<String>
|
||||
in_msg_receiver: Receiver<String>,
|
||||
) -> JoinHandle<()> {
|
||||
thread::spawn(move || {
|
||||
// -- Helpers --
|
||||
|
||||
let observe_property = |name: String, format: Format| {
|
||||
observe_property_sender.send(ObserveProperty { name, format }).expect("cannot send ObserveProperty");
|
||||
observe_property_sender
|
||||
.send(ObserveProperty { name, format })
|
||||
.expect("cannot send ObserveProperty");
|
||||
mpv.wake_up();
|
||||
};
|
||||
|
||||
let send_command = |cmd: CmdVal| {
|
||||
let (name, arg) = match cmd {
|
||||
CmdVal::Double(name, arg) => (name, format!(r#""{arg}""#)),
|
||||
CmdVal::Single((name,)) => (name, String::new())
|
||||
CmdVal::Single((name,)) => (name, String::new()),
|
||||
};
|
||||
mpv.command(&name.to_string(), &[&arg]).expect("failed to execute MPV command");
|
||||
if let Err(error) = mpv.command(&name.to_string(), &[&arg]) {
|
||||
eprintln!("failed to execute MPV command: '{error:#}'")
|
||||
}
|
||||
};
|
||||
|
||||
fn set_property(name: impl ToString, value: impl SetData, mpv: &Mpv) {
|
||||
if let Err(error) = mpv.set_property(&name.to_string(), value) {
|
||||
eprintln!("cannot set MPV property: '{error:#}'")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// -- InMsg handler loop --
|
||||
|
|
@ -169,47 +202,26 @@ fn create_message_thread(
|
|||
};
|
||||
|
||||
match in_msg {
|
||||
InMsg(
|
||||
InMsgFn::MpvObserveProp,
|
||||
InMsgArgs::ObProp(PropKey::Bool(prop)),
|
||||
) => {
|
||||
InMsg(InMsgFn::MpvObserveProp, InMsgArgs::ObProp(PropKey::Bool(prop))) => {
|
||||
observe_property(prop.to_string(), Format::Flag);
|
||||
},
|
||||
InMsg(
|
||||
InMsgFn::MpvObserveProp,
|
||||
InMsgArgs::ObProp(PropKey::Int(prop)),
|
||||
) => {
|
||||
}
|
||||
InMsg(InMsgFn::MpvObserveProp, InMsgArgs::ObProp(PropKey::Int(prop))) => {
|
||||
observe_property(prop.to_string(), Format::Int64);
|
||||
},
|
||||
InMsg(
|
||||
InMsgFn::MpvObserveProp,
|
||||
InMsgArgs::ObProp(PropKey::Fp(prop)),
|
||||
) => {
|
||||
}
|
||||
InMsg(InMsgFn::MpvObserveProp, InMsgArgs::ObProp(PropKey::Fp(prop))) => {
|
||||
observe_property(prop.to_string(), Format::Double);
|
||||
},
|
||||
InMsg(
|
||||
InMsgFn::MpvObserveProp,
|
||||
InMsgArgs::ObProp(PropKey::Str(prop)),
|
||||
) => {
|
||||
}
|
||||
InMsg(InMsgFn::MpvObserveProp, InMsgArgs::ObProp(PropKey::Str(prop))) => {
|
||||
observe_property(prop.to_string(), Format::String);
|
||||
},
|
||||
InMsg(
|
||||
InMsgFn::MpvSetProp,
|
||||
InMsgArgs::StProp(prop, PropVal::Bool(value)),
|
||||
) => {
|
||||
set_property(prop, value, &mpv);
|
||||
}
|
||||
InMsg(
|
||||
InMsgFn::MpvSetProp,
|
||||
InMsgArgs::StProp(prop, PropVal::Num(value)),
|
||||
) => {
|
||||
set_property(prop, value, &mpv);
|
||||
InMsg(InMsgFn::MpvSetProp, InMsgArgs::StProp(name, PropVal::Bool(value))) => {
|
||||
set_property(name, value, &mpv);
|
||||
}
|
||||
InMsg(
|
||||
InMsgFn::MpvSetProp,
|
||||
InMsgArgs::StProp(prop, PropVal::Str(value)),
|
||||
) => {
|
||||
set_property(prop, value, &mpv);
|
||||
InMsg(InMsgFn::MpvSetProp, InMsgArgs::StProp(name, PropVal::Num(value))) => {
|
||||
set_property(name, value, &mpv);
|
||||
}
|
||||
InMsg(InMsgFn::MpvSetProp, InMsgArgs::StProp(name, PropVal::Str(value))) => {
|
||||
set_property(name, value, &mpv);
|
||||
}
|
||||
InMsg(InMsgFn::MpvCommand, InMsgArgs::Cmd(cmd)) => {
|
||||
send_command(cmd);
|
||||
|
|
@ -222,7 +234,6 @@ fn create_message_thread(
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
trait MpvExt {
|
||||
fn wake_up(&self);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use std::os::windows::process::CommandExt;
|
||||
use std::process::Command;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use win32job::Job;
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue