From 6f1ba7f8a6b26006db3a32911d4fa05e00c6e43a Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Wed, 21 Jul 2021 10:38:49 +0300 Subject: [PATCH] Cmd line args, drag&drop, fs event --- Cargo.lock | 141 ++++++++++++++++++ Cargo.toml | 3 +- src/main.rs | 36 ++++- src/stremio_app/stremio_app.rs | 30 +++- .../stremio_wevbiew/stremio_wevbiew.rs | 40 +++-- 5 files changed, 230 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 345f416..c8f38ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,26 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -26,6 +46,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "com" version = "0.2.0" @@ -72,6 +107,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "itoa" version = "0.4.7" @@ -288,6 +341,30 @@ dependencies = [ "toml", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.27" @@ -396,6 +473,7 @@ dependencies = [ "once_cell", "serde", "serde_json", + "structopt", "webview2", "webview2-sys", "winapi", @@ -411,6 +489,36 @@ dependencies = [ "libm", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syn" version = "1.0.73" @@ -422,6 +530,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "toml" version = "0.5.8" @@ -431,12 +548,36 @@ dependencies = [ "serde", ] +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "wasm-bindgen" version = "0.2.74" diff --git a/Cargo.toml b/Cargo.toml index 1ec9197..a06ab41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,5 @@ webview2 = "0.1.0" webview2-sys = "0.1.0-beta.1" mpv = "0.2.3" serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" \ No newline at end of file +serde_json = "1.0" +structopt = "0.3" diff --git a/src/main.rs b/src/main.rs index c3510ae..39616de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,20 @@ use native_windows_gui::{self as nwg, NativeUi}; +use structopt::StructOpt; mod stremio_app; use crate::stremio_app::{stremio_server::StremioServer, MainWindow}; +const WEB_ENDPOINT: &str = "http://app.strem.io/shell-v4.4/"; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(long)] + development: bool, + #[structopt(long, default_value = WEB_ENDPOINT)] + webui_url: String, +} + fn main() { // native-windows-gui has some basic high DPI support with the high-dpi // feature. It supports the "System DPI Awareness" mode, but not the more @@ -14,10 +26,28 @@ fn main() { nwg::set_dpi_awareness() }; - let streaming_server = StremioServer::new(); + let opt = Opt::from_args(); + + let streaming_server: Option = if opt.development { + None + } else { + Some(StremioServer::new()) + }; + + let webui_url = if opt.development && opt.webui_url == WEB_ENDPOINT { + "http://localhost:11470".to_string() + } else { + opt.webui_url + }; nwg::init().expect("Failed to init Native Windows GUI"); - let _app = MainWindow::build_ui(Default::default()).expect("Failed to build UI"); + let _app = MainWindow::build_ui(MainWindow { + webui_url, + ..Default::default() + }) + .expect("Failed to build UI"); nwg::dispatch_thread_events(); - streaming_server.try_kill(); + if let Some(streaming_server) = streaming_server { + streaming_server.try_kill(); + } } diff --git a/src/stremio_app/stremio_app.rs b/src/stremio_app/stremio_app.rs index 4b657ad..bb54d30 100644 --- a/src/stremio_app/stremio_app.rs +++ b/src/stremio_app/stremio_app.rs @@ -43,19 +43,26 @@ struct RPCResponse { #[derive(Default, NwgUi)] pub struct MainWindow { + pub webui_url: String, #[nwg_control(title: "Stremio", flags: "MAIN_WINDOW|VISIBLE")] - #[nwg_events( OnWindowClose: [MainWindow::on_quit], OnInit: [MainWindow::on_init] )] - window: nwg::Window, + #[nwg_events( OnWindowClose: [MainWindow::on_quit], OnInit: [MainWindow::on_init], OnMinMaxInfo: [MainWindow::on_min_max(SELF, EVT_DATA)] )] + pub window: nwg::Window, #[nwg_partial(parent: window)] - webview: WebView, + pub webview: WebView, #[nwg_partial(parent: window)] - player: Player, + pub player: Player, } impl MainWindow { + const MIN_WIDTH: i32 = 1000; + const MIN_HEIGHT: i32 = 600; fn on_init(&self) { + self.webview.endpoint.set(self.webui_url.clone()).ok(); let small_side = cmp::min(nwg::Monitor::width(), nwg::Monitor::height()) * 70 / 100; - let dimensions = (small_side * 16 / 9, small_side); + let dimensions = ( + cmp::max(small_side * 16 / 9, Self::MIN_WIDTH), + cmp::max(small_side, Self::MIN_HEIGHT), + ); let [total_width, total_height] = [nwg::Monitor::width(), nwg::Monitor::height()]; let x = (total_width - dimensions.0) / 2; let y = (total_height - dimensions.1) / 2; @@ -93,7 +100,7 @@ impl MainWindow { web_tx_player.send(resp_json).ok(); } // recv }); // thread - // read message from WebView + thread::spawn(move || loop { let rx = web_rx.lock().unwrap(); if let Ok(msg) = rx.recv() { @@ -131,7 +138,12 @@ impl MainWindow { let resp_json = serde_json::to_string(&args).unwrap(); player_tx.send(resp_json).ok(); } else { - eprintln!("Unsupported command {:?}", args) + match method { + "toggle-fullscreen" => { + println!("full screen toggle requested"); + } + _ => eprintln!("Unsupported command {:?}", args), + } } } } @@ -141,6 +153,10 @@ impl MainWindow { } // recv }); // thread } + fn on_min_max(&self, data: &nwg::EventData) { + let data = data.on_min_max(); + data.set_min_size(Self::MIN_WIDTH, Self::MIN_HEIGHT); + } fn on_quit(&self) { nwg::stop_thread_dispatch(); } diff --git a/src/stremio_app/stremio_wevbiew/stremio_wevbiew.rs b/src/stremio_app/stremio_wevbiew/stremio_wevbiew.rs index 9458065..0cda402 100644 --- a/src/stremio_app/stremio_wevbiew/stremio_wevbiew.rs +++ b/src/stremio_app/stremio_wevbiew/stremio_wevbiew.rs @@ -1,5 +1,6 @@ use native_windows_gui::{self as nwg, PartialUi}; use once_cell::unsync::OnceCell; +use serde_json::json; use std::cell::RefCell; use std::mem; use std::rc::Rc; @@ -12,6 +13,7 @@ use winapi::um::winuser::*; #[derive(Default)] pub struct WebView { + pub endpoint: Rc>, controller: Rc>, pub channel: RefCell, Arc>>)>>, notice: nwg::Notice, @@ -31,7 +33,9 @@ impl WebView { controller.put_bounds(rect).ok(); } controller.put_is_visible(true).ok(); - controller.move_focus(webview2::MoveFocusReason::Programmatic).ok(); + controller + .move_focus(webview2::MoveFocusReason::Programmatic) + .ok(); } } } @@ -42,8 +46,9 @@ impl PartialUi for WebView { parent: Option, ) -> Result<(), nwg::NwgError> { let (tx, rx) = mpsc::channel::(); - let (tx1, rx1) = mpsc::channel::(); - data.channel = RefCell::new(Some((tx, Arc::new(Mutex::new(rx1))))); + let tx_drag_drop = tx.clone(); + let (tx_web, rx_web) = mpsc::channel::(); + data.channel = RefCell::new(Some((tx, Arc::new(Mutex::new(rx_web))))); let parent = parent.expect("No parent window").into(); @@ -53,6 +58,7 @@ impl PartialUi for WebView { .build(&mut data.notice) .ok(); let controller_clone = data.controller.clone(); + let endpoint = data.endpoint.clone(); let hwnd = hwnd as *mut HWND__; let result = webview2::EnvironmentBuilder::new() .with_additional_browser_arguments("--disable-gpu") @@ -75,11 +81,13 @@ impl PartialUi for WebView { let webview = controller .get_webview() .expect("Cannot obtain webview from controller"); + if let Some(endpoint) = endpoint.get() { + if let Err(e) = webview + .navigate(endpoint.as_str()) { + eprintln!("Cannot load WEB UI at '{}': {:?}", &endpoint, e); + }; + } webview - // .navigate("https://www.boyanpetrov.rip/stremio/index.html") - .navigate("http://app.strem.io/shell-v4.4/") - .expect("Cannot load the webUI"); - webview .add_script_to_execute_on_document_created( r##" window.qt={webChannelTransport:{send:window.chrome.webview.postMessage}}; @@ -89,9 +97,24 @@ impl PartialUi for WebView { |_| Ok(()), ) .ok(); + let tx_fs = tx_web.clone(); webview.add_web_message_received(move |_w, msg| { let msg = msg.try_get_web_message_as_string()?; - tx1.send(msg).ok(); + tx_web.send(msg).ok(); + Ok(()) + }).ok(); + webview.add_new_window_requested(move |_w, msg| { + let data = json!({ + "object": "transport", + "type": 1, + "args": ["dragdrop" ,[msg.get_uri().unwrap()]] + }); + tx_drag_drop.send(data.to_string()).ok(); + msg.put_handled(true).ok(); + Ok(()) + }).ok(); + webview.add_contains_full_screen_element_changed(move |_w| { + tx_fs.send(r#"{"id":1, "args": ["toggle-fullscreen"]}"#.to_string()).ok(); Ok(()) }).ok(); WebView::resize_to_window_bounds_and_show(Some(&controller), Some(hwnd)); @@ -129,7 +152,6 @@ impl PartialUi for WebView { ) { use nwg::Event as E; match evt { - E::OnInit => {} E::OnResize | E::OnWindowMaximize => { WebView::resize_to_window_bounds_and_show(self.controller.get(), handle.hwnd()); }