Compare commits

..

No commits in common. "main" and "1.1.1" have entirely different histories.
main ... 1.1.1

10 changed files with 58 additions and 328 deletions

View file

@ -1,2 +0,0 @@
[build]
target = ["x86_64-unknown-linux-gnu", "x86_64-pc-windows-gnu", "aarch64-unknown-linux-gnu"]

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target /target
/Cargo.lock

230
Cargo.lock generated
View file

@ -1,230 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "ff2mpv-rust"
version = "1.1.4"
dependencies = [
"serde",
"serde_json",
"windows",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "indexmap"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "proc-macro2"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "serde"
version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "windows"
version = "0.56.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
dependencies = [
"windows-core",
"windows-targets",
]
[[package]]
name = "windows-core"
version = "0.56.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6"
dependencies = [
"windows-implement",
"windows-interface",
"windows-result",
"windows-targets",
]
[[package]]
name = "windows-implement"
version = "0.56.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.56.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-result"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"

View file

@ -1,21 +1,13 @@
[package] [package]
name = "ff2mpv-rust" name = "ff2mpv-rust"
version = "1.1.5" version = "1.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
serde = { version = "1.0.*", features = ["derive"] } serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.*", features = ["preserve_order"] } serde_json = { version = "1.0.93", features = ["preserve_order"] }
[target.'cfg(windows)'.dependencies] [profile.release-full]
windows = { version = "0.56", features = ["Win32_System_Threading"] } inherits = "release"
[profile.dev-optimized]
inherits = "dev"
opt-level = 3
[profile.release]
strip = "symbols" strip = "symbols"
lto = "fat" lto = "fat"
panic = "abort"
codegen-units = 1

View file

@ -18,11 +18,6 @@ After that get native messasing host manifest:
``` ```
ff2mpv-rust manifest ff2mpv-rust manifest
``` ```
Or for Chromium/Chrome:
```
ff2mpv-rust manifest_chromium
```
Install it following manual installation instructions on [ff2mpv wiki](https://github.com/woodruffw/ff2mpv/wiki). Install it following manual installation instructions on [ff2mpv wiki](https://github.com/woodruffw/ff2mpv/wiki).
# Configuration # Configuration
@ -40,8 +35,7 @@ See [example configuration](ff2mpv-rust.json).
ff2mpv-rust provides command line interface with following commands: ff2mpv-rust provides command line interface with following commands:
``` ```
help: prints help message help: prints help message
manifest: prints manifest for Firefox configuration manifest: prints manifest for browser configuration
manifest_chromium: prints manifest for Chromium/Chrome configuration
validate: checks configration file for validity validate: checks configration file for validity
``` ```
Note that it won't fail on invalid commands, but instead assume it is called from browser, blocking the input. Note that it won't fail on invalid commands, but instead assume it is called from browser, blocking the input.

View file

@ -1,13 +1,13 @@
use std::io::{self, Read, Write};
use serde::Deserialize; use serde::Deserialize;
use std::io;
use std::io::BufReader;
use std::io::{Read, Write};
use crate::error::FF2MpvError; use crate::error::FF2MpvError;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct FF2MpvMessage { pub struct FF2MpvMessage {
pub url: String, pub url: String,
pub options: Vec<String>,
} }
pub fn send_reply() -> Result<(), io::Error> { pub fn send_reply() -> Result<(), io::Error> {
@ -22,23 +22,23 @@ pub fn get_mpv_message() -> Result<FF2MpvMessage, FF2MpvError> {
} }
fn read_message() -> Result<String, io::Error> { fn read_message() -> Result<String, io::Error> {
let mut stdin = io::stdin().lock(); let mut stdin = io::stdin();
let mut buf: [u8; 4] = [0; 4];
stdin.read_exact(&mut buf)?;
let mut len = 0_u32.to_ne_bytes(); let length = u32::from_ne_bytes(buf);
stdin.read_exact(&mut len)?; let mut reader = BufReader::new(stdin.take(length as u64));
let len = u32::from_ne_bytes(len);
let mut reader = stdin.take(len as u64); let mut string = String::with_capacity(length as usize);
let mut msg = String::with_capacity(len as usize); reader.read_to_string(&mut string)?;
reader.read_to_string(&mut msg)?; Ok(string)
Ok(msg)
} }
fn send_message(message: &str) -> Result<(), io::Error> { fn send_message(message: &str) -> Result<(), io::Error> {
let length = (message.len() as u32).to_ne_bytes(); let length = (message.len() as u32).to_ne_bytes();
let message = message.as_bytes(); let message = message.as_bytes();
let mut stdout = io::stdout().lock(); let mut stdout = io::stdout();
stdout.write_all(&length)?; stdout.write_all(&length)?;
stdout.write_all(message)?; stdout.write_all(message)?;
Ok(()) Ok(())

View file

@ -1,8 +1,7 @@
use std::env; use std::env;
use std::io; use std::io;
use std::process; use std::process;
use serde_json::{self, json};
use serde_json::json;
use crate::browser; use crate::browser;
use crate::config::Config; use crate::config::Config;
@ -11,19 +10,18 @@ use crate::error::FF2MpvError;
pub enum Command { pub enum Command {
ShowHelp, ShowHelp,
ShowManifest, ShowManifest,
ShowManifestChromium,
ValidateConfig, ValidateConfig,
FF2Mpv, FF2Mpv
} }
impl Command { impl Command {
pub fn execute(&self) -> Result<(), FF2MpvError> { pub fn execute(&self) -> Result<(), FF2MpvError> {
match self { match self {
Command::ShowHelp => Self::show_help(), Command::ShowHelp => Self::show_help(),
Command::ShowManifest => Self::show_manifest(false), Command::ShowManifest => Self::show_manifest(),
Command::ShowManifestChromium => Self::show_manifest(true),
Command::ValidateConfig => Self::validate_config(), Command::ValidateConfig => Self::validate_config(),
Command::FF2Mpv => Self::ff2mpv(), Command::FF2Mpv => Self::ff2mpv()
} }
} }
@ -31,8 +29,7 @@ impl Command {
println!("Usage: ff2mpv-rust <command>"); println!("Usage: ff2mpv-rust <command>");
println!("Commands:"); println!("Commands:");
println!(" help: prints help message"); println!(" help: prints help message");
println!(" manifest: prints manifest for Firefox configuration"); println!(" manifest: prints manifest for browser configuration");
println!(" manifest_chromium: prints manifest for Chromium/Chrome configuration");
println!(" validate: checks configration file for validity"); println!(" validate: checks configration file for validity");
println!("Note: Invalid commands won't fail"); println!("Note: Invalid commands won't fail");
println!("Note: It will assume that binary is called from browser, blocking for input"); println!("Note: It will assume that binary is called from browser, blocking for input");
@ -40,23 +37,14 @@ impl Command {
Ok(()) Ok(())
} }
fn show_manifest(chromium: bool) -> Result<(), FF2MpvError> { fn show_manifest() -> Result<(), FF2MpvError>{
let executable_path = env::current_exe()?; let executable_path = env::current_exe()?;
let allowed_keyvalue = if chromium {
(
"allowed_origins",
"chrome-extension://ephjcajbkgplkjmelpglennepbpmdpjg/",
)
} else {
("allowed_extensions", "ff2mpv@yossarian.net")
};
let manifest = json!({ let manifest = json!({
"name": "ff2mpv", "name": "ff2mpv",
"description": "ff2mpv's external manifest", "description": "ff2mpv's external manifest",
"path": executable_path, "path": executable_path,
"type": "stdio", "type": "stdio",
allowed_keyvalue.0: [allowed_keyvalue.1] "allowed_extensions": ["ff2mpv@yossarian.net"]
}); });
let manifest = serde_json::to_string_pretty(&manifest)?; let manifest = serde_json::to_string_pretty(&manifest)?;
@ -75,43 +63,20 @@ impl Command {
fn ff2mpv() -> Result<(), FF2MpvError> { fn ff2mpv() -> Result<(), FF2MpvError> {
let config = Config::build(); let config = Config::build();
let ff2mpv_message = browser::get_mpv_message()?; let ff2mpv_message = browser::get_mpv_message()?;
let args = [config.player_args, ff2mpv_message.options].concat(); Command::launch_mpv(config.player_command, config.player_args, &ff2mpv_message.url)?;
Command::launch_mpv(config.player_command, args, &ff2mpv_message.url)?;
browser::send_reply()?; browser::send_reply()?;
Ok(()) Ok(())
} }
fn launch_mpv(command: String, args: Vec<String>, url: &str) -> Result<(), io::Error> { fn launch_mpv(command: String, args: Vec<String>, url: &str) -> Result<(), io::Error> {
let mut command = process::Command::new(command); process::Command::new(command)
.stdout(process::Stdio::null())
command.stdout(process::Stdio::null()); .stderr(process::Stdio::null())
command.stderr(process::Stdio::null()); .args(args)
command.arg("--no-terminal"); .arg(url)
command.args(args); .spawn()?;
command.arg("--");
command.arg(url);
Command::detach_mpv(&mut command);
command.spawn()?;
Ok(()) Ok(())
} }
// NOTE: Make sure the subprocess is not killed.
// See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#closing_the_native_app
#[cfg(unix)]
fn detach_mpv(command: &mut process::Command) {
use std::os::unix::process::CommandExt;
command.process_group(0);
}
#[cfg(windows)]
fn detach_mpv(command: &mut process::Command) {
use std::os::windows::process::CommandExt;
use windows::Win32::System::Threading::CREATE_BREAKAWAY_FROM_JOB;
command.creation_flags(CREATE_BREAKAWAY_FROM_JOB.0);
}
} }

View file

@ -1,32 +1,35 @@
use std::env; use std::env;
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use serde::Deserialize; use serde::Deserialize;
use crate::error::FF2MpvError; use crate::error::FF2MpvError;
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(default)]
pub struct Config { pub struct Config {
#[serde(default = "default_player_command")]
pub player_command: String, pub player_command: String,
#[serde(default = "default_player_args")]
pub player_args: Vec<String>, pub player_args: Vec<String>,
} }
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
player_command: "mpv".to_owned(), player_command: default_player_command(),
player_args: vec![], player_args: default_player_args(),
} }
} }
} }
impl Config { impl Config {
const CONFIG_FILENAME: &'static str = "ff2mpv-rust.json";
pub fn build() -> Self { pub fn build() -> Self {
Config::parse_config_file().unwrap_or_default() if let Ok(config) = Config::parse_config_file() {
config
} else {
Config::default()
}
} }
pub fn parse_config_file() -> Result<Self, FF2MpvError> { pub fn parse_config_file() -> Result<Self, FF2MpvError> {
@ -41,7 +44,7 @@ impl Config {
Ok(config) Ok(config)
} }
#[cfg(unix)] #[cfg(target_family = "unix")]
fn get_config_location() -> PathBuf { fn get_config_location() -> PathBuf {
let mut path = PathBuf::new(); let mut path = PathBuf::new();
@ -54,17 +57,25 @@ impl Config {
path.push("/etc"); path.push("/etc");
} }
path.push(Self::CONFIG_FILENAME); path.push("ff2mpv-rust.json");
path path
} }
#[cfg(windows)] #[cfg(target_family = "windows")]
fn get_config_location() -> PathBuf { fn get_config_location() -> PathBuf {
let mut path = PathBuf::new(); let mut path = PathBuf::new();
let appdata = env::var("APPDATA").unwrap(); let appdata = env::var("APPDATA").unwrap();
path.push(appdata); path.push(appdata);
path.push(Self::CONFIG_FILENAME); path.push("ff2mpv-rust.json");
path path
} }
} }
fn default_player_command() -> String {
"mpv".to_owned()
}
fn default_player_args() -> Vec<String> {
vec![]
}

View file

@ -1,6 +1,6 @@
use std::io;
use std::fmt; use std::fmt;
use std::fmt::Display; use std::fmt::Display;
use std::io;
pub enum FF2MpvError { pub enum FF2MpvError {
NoConfig, NoConfig,

View file

@ -19,7 +19,6 @@ fn get_command(name: &str) -> Command {
match name { match name {
"help" => Command::ShowHelp, "help" => Command::ShowHelp,
"manifest" => Command::ShowManifest, "manifest" => Command::ShowManifest,
"manifest_chromium" => Command::ShowManifestChromium,
"validate" => Command::ValidateConfig, "validate" => Command::ValidateConfig,
_ => Command::FF2Mpv, _ => Command::FF2Mpv,
} }