commit a37de57a39322c15fbdd0fb94ff0f7096d924d52 Author: Baldomo Date: Tue Jul 2 15:51:02 2019 +0200 Initial commit: main.rs, base project layout diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..40c7ccb --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,69 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "open-in-mpv" +version = "0.1.0" +dependencies = [ + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "smallvec" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" +"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..610292d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "open-in-mpv" +version = "0.1.0" +authors = ["Leonardo Baldin "] +edition = "2018" + +[dependencies] +percent-encoding = "1.0.1" +url = "1.7.2" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..c2397ec --- /dev/null +++ b/src/main.rs @@ -0,0 +1,147 @@ +use std::{collections::HashMap, env, process::{Command, exit}, vec::Vec}; +use url::{percent_encoding::percent_decode, Url}; + +#[derive(Debug)] +struct MpvOption { + url: String, + fullscreen: bool, + pip: bool, + enqueue: bool, +} + +fn build_option( + url: Option<&String>, + fullscreen: Option<&String>, + pip: Option<&String>, + enqueue: Option<&String>, +) -> MpvOption { + MpvOption { + url: match url { + None => String::new(), + Some(s) => percent_decode(s.as_bytes()) + .decode_utf8() + .unwrap() + .as_ref() + .to_owned(), + }, + fullscreen: match fullscreen { + None => false, + Some(s) => match s.to_owned().as_ref() { + "1" => true, + "0" => false, + _ => false, + }, + }, + pip: match pip { + None => false, + Some(s) => match s.to_owned().as_ref() { + "1" => true, + "0" => false, + _ => false, + }, + }, + enqueue: match enqueue { + None => false, + Some(s) => match s.to_owned().as_ref() { + "1" => true, + "0" => false, + _ => false, + }, + }, + } +} + +fn build_args(mo: MpvOption) -> Vec { + let mut ret: Vec = Vec::new(); + if mo.fullscreen { + ret.push("--fs".to_owned()); + } + + if mo.pip { + ret.push("--ontop".to_owned()); + ret.push("--no-border".to_owned()); + ret.push("--autofit=384x216".to_owned()); + ret.push("--geometry=98%:98%".to_owned()); + } + + if mo.enqueue { + // TODO: figure this out + } + + ret.push(mo.url); + + return ret; +} + +fn main() { + // mpv:///open?url=XXXXXXX&full_screen=1&pip=1&enqueue=0 + let raw_url: String = env::args_os().nth(1).unwrap().into_string().unwrap(); + let parsed_url: Url = match Url::parse(&raw_url) { + Err(why) => panic!("{:?}", why), + Ok(parsed) => parsed, + }; + + if parsed_url.scheme() != "mpv" { + println!("Unsupported protocol: {}", parsed_url.scheme()); + exit(1); + } + + if parsed_url.path() != "/open" { + println!("Unsupported method: {}", parsed_url.path()); + exit(1); + } + + let query: HashMap = parsed_url.query_pairs().into_owned().collect(); + + let mo = build_option( + query.get("url"), + query.get("full_screen"), + query.get("pip"), + query.get("enqueue"), + ); + + Command::new("mpv") + .args(build_args(mo)) + .output() + .expect("failed to open mpv"); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_build_option() { + let one: String = String::from("1"); + let zero: String = String::from("0"); + let encoded_url: String = String::from("https%3A%2F%2Fst3x_plus.cdnfile.info%2Fuser592%2F5543369133e06eedecc4907bfcd0fd45%2FEP.1.360p.mp4%3Ftoken%3DZDpvjlchVpTP0yb_5AsaEw%26expires%3D1562085204%26title%3D(360P%2520-%2520mp4)%2520Terminator%2B4%253A%2BSalvation%2BHD-720p"); + + let url_option: Option<&String> = Some(&encoded_url); + let fullscreen_option: Option<&String> = Some(&one); + let pip_option: Option<&String> = Some(&zero); + let enqueue_option: Option<&String> = Some(&one); + + let expected_url: String = String::from("https://st3x_plus.cdnfile.info/user592/5543369133e06eedecc4907bfcd0fd45/EP.1.360p.mp4?token=ZDpvjlchVpTP0yb_5AsaEw&expires=1562085204&title=(360P%20-%20mp4)%20Terminator+4%3A+Salvation+HD-720p"); + + let mo: MpvOption = build_option(url_option, fullscreen_option, pip_option, enqueue_option); + + assert_eq!(mo.url, expected_url); + assert_eq!(mo.fullscreen, true); + assert_eq!(mo.pip, false); + assert_eq!(mo.enqueue, true); + } + + #[test] + fn test_build_args() { + let mo: MpvOption = MpvOption { + url: String::from("invalid_url_but_who_cares"), + fullscreen: true, + pip: false, + enqueue: true, + }; + + let args: Vec = build_args(mo); + assert_eq!(args[0], "--fs".to_owned()); + assert_eq!(args[1], "invalid_url_but_who_cares".to_owned()); + } +}