From f1fc19547add984b3adf47fac7b3ae2db369f6e2 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 27 Jun 2022 10:55:07 +0200 Subject: [PATCH 1/5] simplify code --- ffplayout-api/src/utils/files.rs | 19 ++++++++----------- ffplayout-engine/src/main.rs | 7 +++---- lib/src/utils/config.rs | 2 +- lib/src/utils/json_serializer.rs | 14 ++++++-------- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/ffplayout-api/src/utils/files.rs b/ffplayout-api/src/utils/files.rs index 723f9250..d63db296 100644 --- a/ffplayout-api/src/utils/files.rs +++ b/ffplayout-api/src/utils/files.rs @@ -138,17 +138,15 @@ pub async fn rename_file(id: i64, move_object: &MoveObject) -> Result path.join(source_path.strip_prefix(&relativ_path).unwrap()), + false => path.join(source), + }; - if !target_path.starts_with(&relativ_path) { - target_path = path.join(target); - } else { - target_path = path.join(target_path.strip_prefix(relativ_path).unwrap()); - } + target_path = match target_path.starts_with(&relativ_path) { + true => path.join(target_path.strip_prefix(relativ_path).unwrap()), + false => path.join(target), + }; if !source_path.exists() { return Err(ServiceError::BadRequest("Source file not exist!".into())); @@ -273,7 +271,6 @@ pub async fn upload(id: i64, mut payload: Multipart) -> Result write_hls(&config, play_control, playout_stat, proc_control), // play on desktop or stream to a remote target - player(&config, play_control, playout_stat, proc_control); + _ => player(&config, play_control, playout_stat, proc_control), } info!("Playout done..."); diff --git a/lib/src/utils/config.rs b/lib/src/utils/config.rs index 5371bca9..4c275fa2 100644 --- a/lib/src/utils/config.rs +++ b/lib/src/utils/config.rs @@ -189,7 +189,7 @@ impl PlayoutConfig { println!( "{config_path:?} doesn't exists!\nPut \"ffplayout.yml\" in \"/etc/playout/\" or beside the executable!" ); - process::exit(0x0100); + process::exit(1); } }; diff --git a/lib/src/utils/json_serializer.rs b/lib/src/utils/json_serializer.rs index 489be261..a9d90e39 100644 --- a/lib/src/utils/json_serializer.rs +++ b/lib/src/utils/json_serializer.rs @@ -184,10 +184,9 @@ pub fn read_json( validate_playlist(list_clone, is_terminated, config_clone) }); - if config.playlist.infinit { - return loop_playlist(config, current_file, playlist); - } else { - return set_defaults(playlist, current_file, start_sec); + match config.playlist.infinit { + true => return loop_playlist(config, current_file, playlist), + false => return set_defaults(playlist, current_file, start_sec), } } } @@ -206,10 +205,9 @@ pub fn read_json( thread::spawn(move || validate_playlist(list_clone, is_terminated, config_clone)); - if config.playlist.infinit { - return loop_playlist(config, current_file, playlist); - } else { - return set_defaults(playlist, current_file, start_sec); + match config.playlist.infinit { + true => return loop_playlist(config, current_file, playlist), + false => return set_defaults(playlist, current_file, start_sec), } } From 8433c0d74ae31ee8c236c2511b339e183f587e0d Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 27 Jun 2022 11:46:28 +0200 Subject: [PATCH 2/5] updates --- Cargo.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 293ed0c5..54dbe311 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -472,9 +472,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "base64ct" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" +checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851" [[package]] name = "bitflags" @@ -625,8 +625,8 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.19" -source = "git+https://github.com/chronotope/chrono.git#b1d74aef688c27fccc738c64746535905903471a" +version = "0.4.20-beta.1" +source = "git+https://github.com/chronotope/chrono.git#39ac80a6a51b2a5081750c451feb261c1cb43960" dependencies = [ "num-integer", "num-traits", @@ -1057,7 +1057,7 @@ dependencies = [ name = "ffplayout-lib" version = "0.10.1" dependencies = [ - "chrono 0.4.19 (git+https://github.com/chronotope/chrono.git)", + "chrono 0.4.20-beta.1", "crossbeam-channel 0.5.5", "ffprobe", "file-rotate", @@ -1763,9 +1763,9 @@ dependencies = [ [[package]] name = "linked-hash-map" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "local-channel" @@ -2657,9 +2657,9 @@ checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "smallvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" [[package]] name = "socket2" @@ -3005,9 +3005,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" dependencies = [ "once_cell", ] @@ -3063,9 +3063,9 @@ checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "81dee68f85cab8cf68dec42158baf3a79a1cdc065a8b103025965d6ccb7f6cbd" dependencies = [ "tinyvec", ] From 884082fa0acb0f02bb8cde1ce984a68e181b9deb Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 27 Jun 2022 11:49:43 +0200 Subject: [PATCH 3/5] add null output --- README.md | 1 + assets/ffplayout.yml | 7 ++-- ffplayout-engine/src/output/mod.rs | 2 + ffplayout-engine/src/output/null.rs | 64 +++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 ffplayout-engine/src/output/null.rs diff --git a/README.md b/README.md index 1f4405a2..14c8d600 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ Check the [releases](https://github.com/ffplayout/ffplayout-engine/releases/late - **stream** - **desktop** - **HLS** + - **null** (for debugging) - JSON RPC server, for getting infos about current playing and controlling - [live ingest](/docs/live_ingest.md) diff --git a/assets/ffplayout.yml b/assets/ffplayout.yml index 802e06fd..e285b9d7 100644 --- a/assets/ffplayout.yml +++ b/assets/ffplayout.yml @@ -115,10 +115,9 @@ text: regex: ^.+[/\\](.*)(.mp4|.mkv)$ out: - help_text: The final playout compression. Set the settings to your needs. - 'mode' has the standard options 'desktop', 'hls', 'stream'. Self made - outputs can be define, by adding script in output folder with an 'output' function - inside. 'preview' works only in streaming output and creates a separate preview stream. + help_text: The final playout compression. Set the settings to your needs. 'mode' + has the options 'desktop', 'hls', 'null', 'stream'. + 'preview' works only in streaming output and creates a separate preview stream. mode: 'stream' preview: false preview_param: >- diff --git a/ffplayout-engine/src/output/mod.rs b/ffplayout-engine/src/output/mod.rs index 337753a1..e223413d 100644 --- a/ffplayout-engine/src/output/mod.rs +++ b/ffplayout-engine/src/output/mod.rs @@ -11,6 +11,7 @@ use simplelog::*; mod desktop; mod hls; +mod null; mod stream; pub use hls::write_hls; @@ -55,6 +56,7 @@ pub fn player( // get ffmpeg output instance let mut enc_proc = match config.out.mode.as_str() { "desktop" => desktop::output(config, &ff_log_format), + "null" => null::output(config, &ff_log_format), "stream" => stream::output(config, &ff_log_format), _ => panic!("Output mode doesn't exists!"), }; diff --git a/ffplayout-engine/src/output/null.rs b/ffplayout-engine/src/output/null.rs new file mode 100644 index 00000000..73b73fda --- /dev/null +++ b/ffplayout-engine/src/output/null.rs @@ -0,0 +1,64 @@ +use std::process::{self, Command, Stdio}; + +use simplelog::*; + +use ffplayout_lib::filter::v_drawtext; +use ffplayout_lib::utils::{Media, PlayoutConfig}; +use ffplayout_lib::vec_strings; + +/// Desktop Output +/// +/// Instead of streaming, we run a ffplay instance and play on desktop. +pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child { + let mut enc_filter: Vec = vec![]; + + let mut enc_cmd = vec_strings![ + "-hide_banner", + "-nostats", + "-v", + log_format, + "-re", + "-i", + "pipe:0", + "-f", + "null", + "-" + ]; + + if config.text.add_text && !config.text.text_from_filename { + if let Some(socket) = config.text.bind_address.clone() { + debug!( + "Using drawtext filter, listening on address: {}", + socket + ); + + let mut filter: String = "null,".to_string(); + filter.push_str( + v_drawtext::filter_node(config, &Media::new(0, String::new(), false)).as_str(), + ); + enc_filter = vec!["-vf".to_string(), filter]; + } + } + + enc_cmd.splice(7..7, enc_filter); + + debug!( + "Encoder CMD: \"ffmpeg {}\"", + enc_cmd.join(" ") + ); + + let enc_proc = match Command::new("ffmpeg") + .args(enc_cmd) + .stdin(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + { + Err(e) => { + error!("couldn't spawn encoder process: {e}"); + panic!("couldn't spawn encoder process: {e}") + } + Ok(proc) => proc, + }; + + enc_proc +} From a1cd6486c5a9458e385417caa1689d5e81fe8003 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 27 Jun 2022 14:08:48 +0200 Subject: [PATCH 4/5] fix routes --- docs/api.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api.md b/docs/api.md index 4954b238..1e4f14e2 100644 --- a/docs/api.md +++ b/docs/api.md @@ -129,13 +129,13 @@ Response is in TEXT format - **POST** `api/control/{id}/playout/reset/`\ Response is in TEXT format -- **GET** `/api/control/{id}/media/current/`\ +- **GET** `/api/control/{id}/media/current`\ Response is in JSON format -- **GET** `/api/control/{id}/media/next/`\ +- **GET** `/api/control/{id}/media/next`\ Response is in JSON format -- **GET** `/api/control/{id}/media/last/`\ +- **GET** `/api/control/{id}/media/last`\ Response is in JSON format - **POST** `/api/control/{id}/process/`\ From 643edd0178819d2422cd9dd5a0667217ca56ab19 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 27 Jun 2022 14:10:29 +0200 Subject: [PATCH 5/5] ask for credentials, add postinst script --- Cargo.lock | 15 ++++++- debian/.gitkeep | 0 debian/postinst | 10 +++++ ffplayout-api/Cargo.toml | 3 +- ffplayout-api/README.md | 2 + ffplayout-api/src/utils/args_parse.rs | 3 ++ ffplayout-api/src/utils/mod.rs | 64 ++++++++++++++++++++++++--- ffplayout-engine/Cargo.toml | 16 +++---- 8 files changed, 94 insertions(+), 19 deletions(-) delete mode 100644 debian/.gitkeep create mode 100644 debian/postinst diff --git a/Cargo.lock b/Cargo.lock index 54dbe311..eb9b2aca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1027,7 +1027,7 @@ dependencies = [ [[package]] name = "ffplayout-api" -version = "0.3.1" +version = "0.3.2" dependencies = [ "actix-multipart", "actix-web", @@ -1045,6 +1045,7 @@ dependencies = [ "rand 0.8.5", "relative-path", "reqwest", + "rpassword", "sanitize-filename", "serde", "serde_json", @@ -2454,6 +2455,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rpassword" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf099a1888612545b683d2661a1940089f6c2e5a8e38979b2159da876bfd956" +dependencies = [ + "libc", + "serde", + "serde_json", + "winapi 0.3.9", +] + [[package]] name = "rustc_version" version = "0.4.0" diff --git a/debian/.gitkeep b/debian/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/debian/postinst b/debian/postinst new file mode 100644 index 00000000..b4bc4c02 --- /dev/null +++ b/debian/postinst @@ -0,0 +1,10 @@ +#DEBHELPER# + +if [ ! -d "/usr/share/ffplayout/db" ]; then + mkdir "/usr/share/ffplayout/db" + chmod 777 "/usr/share/ffplayout/db" + + /usr/bin/ffpapi -i + + chown www-data. "/usr/share/ffplayout/db/ffplayout.db" +fi diff --git a/ffplayout-api/Cargo.toml b/ffplayout-api/Cargo.toml index 452d4efd..a1288475 100644 --- a/ffplayout-api/Cargo.toml +++ b/ffplayout-api/Cargo.toml @@ -4,7 +4,7 @@ description = "Rest API for ffplayout" license = "GPL-3.0" authors = ["Jonathan Baecker jonbae77@gmail.com"] readme = "README.md" -version = "0.3.1" +version = "0.3.2" edition = "2021" [dependencies] @@ -24,6 +24,7 @@ once_cell = "1.10" rand = "0.8" relative-path = "1.6" reqwest = { version = "0.11", features = ["blocking", "json"] } +rpassword = "6.0" sanitize-filename = "0.3" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/ffplayout-api/README.md b/ffplayout-api/README.md index 48c7175a..546256a6 100644 --- a/ffplayout-api/README.md +++ b/ffplayout-api/README.md @@ -21,4 +21,6 @@ Then run the API thru the systemd service, or like: ffpapi -l 127.0.0.1:8080 ``` +If you plan to run ffpapi with systemd set permission from **/usr/share/ffplayout** and content to user **www-data:www-data**. + **For possible endpoints read: [api endpoints](/docs/api.md)** diff --git a/ffplayout-api/src/utils/args_parse.rs b/ffplayout-api/src/utils/args_parse.rs index 84d8efa5..2fe65ab4 100644 --- a/ffplayout-api/src/utils/args_parse.rs +++ b/ffplayout-api/src/utils/args_parse.rs @@ -5,6 +5,9 @@ use clap::Parser; about = "REST API for ffplayout", long_about = None)] pub struct Args { + #[clap(short, long, help = "ask for user credentials")] + pub ask: bool, + #[clap(short, long, help = "Listen on IP:PORT, like: 127.0.0.1:8080")] pub listen: Option, diff --git a/ffplayout-api/src/utils/mod.rs b/ffplayout-api/src/utils/mod.rs index b3561173..1fe1eaa3 100644 --- a/ffplayout-api/src/utils/mod.rs +++ b/ffplayout-api/src/utils/mod.rs @@ -1,7 +1,13 @@ -use std::{error::Error, fs::File, path::Path}; +use std::{ + error::Error, + fs::File, + io::{stdin, stdout, Write}, + path::Path, +}; use faccess::PathExt; use once_cell::sync::OnceCell; +use rpassword::read_password; use simplelog::*; pub mod args_parse; @@ -69,20 +75,24 @@ pub async fn init_config() { } pub fn db_path() -> Result> { - let sys_path = Path::new("/usr/share/ffplayout"); - let mut db_path = String::from("./ffplayout.db"); + let sys_path = Path::new("/usr/share/ffplayout/db"); + let mut db_path = "./ffplayout.db".to_string(); + + if sys_path.is_dir() && !sys_path.writable() { + error!("Path {} is not writable!", sys_path.display()); + } if sys_path.is_dir() && sys_path.writable() { - db_path = String::from("/usr/share/ffplayout/ffplayout.db"); + db_path = "/usr/share/ffplayout/db/ffplayout.db".to_string(); } else if Path::new("./assets").is_dir() { - db_path = String::from("./assets/ffplayout.db"); + db_path = "./assets/ffplayout.db".to_string(); } Ok(db_path) } -pub async fn run_args(args: Args) -> Result<(), i32> { - if !args.init && args.listen.is_none() && args.username.is_none() { +pub async fn run_args(mut args: Args) -> Result<(), i32> { + if !args.init && args.listen.is_none() && !args.ask && args.username.is_none() { error!("Wrong number of arguments! Run ffpapi --help for more information."); return Err(0); @@ -96,6 +106,46 @@ pub async fn run_args(args: Args) -> Result<(), i32> { return Err(0); } + if args.ask { + let mut user = String::new(); + print!("Username: "); + stdout().flush().unwrap(); + + stdin() + .read_line(&mut user) + .expect("Did not enter a correct name?"); + if let Some('\n') = user.chars().next_back() { + user.pop(); + } + if let Some('\r') = user.chars().next_back() { + user.pop(); + } + + args.username = Some(user); + + print!("Password: "); + stdout().flush().unwrap(); + let password = read_password(); + + args.password = password.ok(); + + let mut email = String::new(); + print!("EMail: "); + stdout().flush().unwrap(); + + stdin() + .read_line(&mut email) + .expect("Did not enter a correct name?"); + if let Some('\n') = email.chars().next_back() { + email.pop(); + } + if let Some('\r') = email.chars().next_back() { + email.pop(); + } + + args.email = Some(email); + } + if let Some(username) = args.username { if args.email.is_none() || args.password.is_none() { error!("Email/password missing!"); diff --git a/ffplayout-engine/Cargo.toml b/ffplayout-engine/Cargo.toml index 4c4ddcc1..313763ae 100644 --- a/ffplayout-engine/Cargo.toml +++ b/ffplayout-engine/Cargo.toml @@ -41,20 +41,16 @@ suggests = "ffmpeg" copyright = "Copyright (c) 2022, Jonathan Baecker. All rights reserved." conf-files = ["/etc/ffplayout/ffplayout.yml"] assets = [ - [ - "../target/x86_64-unknown-linux-musl/release/ffpapi", - "/usr/bin/ffpapi", - "755" - ], + ["../target/x86_64-unknown-linux-musl/release/ffpapi", "/usr/bin/", "755"], [ "../target/x86_64-unknown-linux-musl/release/ffplayout", - "/usr/bin/ffplayout", + "/usr/bin/", "755" ], - ["../assets/ffpapi.service", "/lib/systemd/system/ffpapi.service", "644"], - ["../assets/11-ffplayout", "/etc/sudoers.d/11-ffplayout", "644"], - ["../assets/ffplayout.yml", "/etc/ffplayout/ffplayout.yml", "644"], - ["../assets/logo.png", "/usr/share/ffplayout/logo.png", "644"], + ["../assets/ffpapi.service", "/lib/systemd/system/", "644"], + ["../assets/11-ffplayout", "/etc/sudoers.d/", "644"], + ["../assets/ffplayout.yml", "/etc/ffplayout/", "644"], + ["../assets/logo.png", "/usr/share/ffplayout/", "644"], ["../README.md", "/usr/share/doc/ffplayout/README", "644"], ] maintainer-scripts = "../debian/"