From 8a6b4738df036c6c259a50bfb5576a599802884b Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Sun, 24 Jul 2022 19:23:12 +0200 Subject: [PATCH 1/8] add frontend submodul, remove preview config parameter --- .gitmodules | 3 +++ ffplayout-frontend | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 ffplayout-frontend diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..4ada2406 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ffplayout-frontend"] + path = ffplayout-frontend + url = git@github.com:ffplayout/ffplayout-frontend.git diff --git a/ffplayout-frontend b/ffplayout-frontend new file mode 160000 index 00000000..be719325 --- /dev/null +++ b/ffplayout-frontend @@ -0,0 +1 @@ +Subproject commit be719325858a3c9403d6d2d778c88d8820b52903 From 06fa5e6e95a7d1374f4ecd79d9ac0ac0b9287b08 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Sun, 24 Jul 2022 19:23:52 +0200 Subject: [PATCH 2/8] add frontend, remove preview config --- .gitignore | 4 +- Cargo.lock | 119 ++++++++++++++++++-------- README.md | 28 +++--- assets/ffpapi.service | 2 +- assets/ffplayout.yml | 18 ---- debian/postinst | 5 ++ debian/postrm | 15 ++++ docs/preview_stream.md | 23 ++++- ffplayout-api/Cargo.toml | 1 + ffplayout-api/src/main.rs | 2 + ffplayout-engine/Cargo.toml | 5 +- ffplayout-engine/src/output/hls.rs | 4 - ffplayout-engine/src/output/stream.rs | 5 -- lib/Cargo.toml | 2 +- lib/src/utils/config.rs | 7 -- scripts/build_all.sh | 15 ++++ 16 files changed, 164 insertions(+), 91 deletions(-) create mode 100644 debian/postrm diff --git a/.gitignore b/.gitignore index 6336f642..e027a52d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,7 @@ *.deb *.rpm /assets/*.db* - +/dist/ +/public/ +tmp/ .vscode/ diff --git a/Cargo.lock b/Cargo.lock index 3583ddb7..8f39f082 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,29 @@ dependencies = [ "tokio-util 0.7.3", ] +[[package]] +name = "actix-files" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d832782fac6ca7369a70c9ee9a20554623c5e51c76e190ad151780ebea1cf689" +dependencies = [ + "actix-http", + "actix-service", + "actix-utils", + "actix-web", + "askama_escape", + "bitflags", + "bytes", + "derive_more", + "futures-core", + "http-range", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", +] + [[package]] name = "actix-grants-proc-macro" version = "2.0.1" @@ -296,6 +319,12 @@ dependencies = [ "password-hash", ] +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + [[package]] name = "async-attributes" version = "1.1.2" @@ -386,7 +415,7 @@ dependencies = [ "async-global-executor", "async-io", "async-lock", - "crossbeam-utils 0.8.10", + "crossbeam-utils 0.8.11", "futures-channel", "futures-core", "futures-io", @@ -558,9 +587,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" [[package]] name = "bytestring" @@ -626,7 +655,7 @@ dependencies = [ [[package]] name = "chrono" version = "0.4.20-beta.1" -source = "git+https://github.com/chronotope/chrono.git#187819ff43e0e4da351b3ea4ac2d3076e06e8251" +source = "git+https://github.com/chronotope/chrono.git#acd4ecf09fd0e5e35e2b5d5e074f6e1cc77172fc" dependencies = [ "num-integer", "num-traits", @@ -636,9 +665,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.12" +version = "3.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8b79fe3946ceb4a0b1c080b4018992b8d27e9ff363644c1c9b6387c854614d" +checksum = "54635806b078b7925d6e36810b1755f2a4b5b4d57560432c1ecf60bcbe10602b" dependencies = [ "atty", "bitflags", @@ -675,9 +704,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "1.2.3" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83827793632c72fa4f73c2edb31e7a997527dd8ffe7077344621fc62c5478157" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" dependencies = [ "cache-padded", ] @@ -796,12 +825,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.10", + "crossbeam-utils 0.8.11", ] [[package]] @@ -843,12 +872,12 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.10", + "crossbeam-utils 0.8.11", ] [[package]] @@ -864,9 +893,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -1000,19 +1029,19 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] [[package]] name = "ffplayout" -version = "0.11.0" +version = "0.12.0" dependencies = [ "clap", - "crossbeam-channel 0.5.5", + "crossbeam-channel 0.5.6", "ffplayout-lib", "futures", "jsonrpc-http-server", @@ -1029,6 +1058,7 @@ dependencies = [ name = "ffplayout-api" version = "0.5.0" dependencies = [ + "actix-files", "actix-multipart", "actix-web", "actix-web-grants", @@ -1056,10 +1086,10 @@ dependencies = [ [[package]] name = "ffplayout-lib" -version = "0.10.5" +version = "0.12.0" dependencies = [ "chrono 0.4.20-beta.1", - "crossbeam-channel 0.5.5", + "crossbeam-channel 0.5.6", "ffprobe", "file-rotate", "jsonrpc-http-server", @@ -1128,9 +1158,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.10.13" +version = "0.10.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ceeb589a3157cac0ab8cc585feb749bd2cea5cb55a6ee802ad72d9fd38303da" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" dependencies = [ "futures-core", "futures-sink", @@ -1476,6 +1506,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + [[package]] name = "httparse" version = "1.7.1" @@ -1725,9 +1761,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lettre" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5677c78c7c7ede1dd68e8a7078012bc625449fb304e7b509b917eaaedfe6e849" +checksum = "2eabca5e0b4d0e98e7f2243fb5b7520b6af2b65d8f87bcc86f2c75185a6ff243" dependencies = [ "base64", "email-encoding", @@ -1845,6 +1881,16 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2364,9 +2410,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a" dependencies = [ "bitflags", ] @@ -2548,18 +2594,18 @@ checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" [[package]] name = "serde" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" dependencies = [ "proc-macro2", "quote", @@ -2664,9 +2710,12 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" @@ -2733,7 +2782,7 @@ dependencies = [ "bytes", "chrono 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", "crc", - "crossbeam-queue 0.3.5", + "crossbeam-queue 0.3.6", "either", "event-listener", "flume", diff --git a/README.md b/README.md index 14c8d600..ddb325c0 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,9 @@ The ffplayout apps are mostly made to run on Linux as system services. But in general they should run on all platforms which are supported by Rust. At the moment the cross compiled version from *ffpapi* runs on Windows and Linux, and not on Mac. If it is needed there, it should be compile natively. -Check the [releases](https://github.com/ffplayout/ffplayout-engine/releases/latest) for pre compiled version. +Check the [releases](https://github.com/ffplayout/ffplayout/releases/latest) for pre compiled version. -**ffplayout-engine (ffplayout)** ------ +## **ffplayout-engine (ffplayout)** [ffplayout](/ffplayout-engine/README.md) is 24/7 broadcasting solution. It can playout a folder with containing video clips, or play for every day a *JSON* playlist, while keeping the current playlist editable. @@ -39,7 +38,6 @@ Check the [releases](https://github.com/ffplayout/ffplayout-engine/releases/late - **aevalsrc** (if video have no audio) - **apad** (add silence if audio duration is to short) - **tpad** (add black frames if video duration is to short) -- [separate preview stream](/docs/preview_stream.md) - [output](/docs/output.md): - **stream** - **desktop** @@ -48,12 +46,13 @@ Check the [releases](https://github.com/ffplayout/ffplayout-engine/releases/late - JSON RPC server, for getting infos about current playing and controlling - [live ingest](/docs/live_ingest.md) -**ffplayout-api (ffpapi)** ------ +For preview stream, read: [/docs/preview_stream.md](/docs/preview_stream.md) + +## **ffplayout-api (ffpapi)** + ffpapi is an [REST API](/ffplayout-api/README.md) for controlling the engine, manipulate playlists, add settings etc. -Requirements ------ +### Requirements - RAM and CPU depends on video resolution, minimum 4 threads and 3GB RAM for 720p are recommend - **ffmpeg** v4.2+ and **ffprobe** (**ffplay** if you want to play on desktop) @@ -61,8 +60,7 @@ Requirements ----- -JSON Playlist Example ------ +### JSON Playlist Example ```json { @@ -95,15 +93,14 @@ JSON Playlist Example } ``` -**Warning** ------ +## **Warning** + (Endless) streaming over multiple days will only work when config have **day_start** value and the **length** value is **24 hours**. If you need only some hours for every day, use a *cron* job, or something similar. ----- -HLS output ------ +## HLS output For outputting to HLS, output parameters should look like: @@ -124,8 +121,7 @@ out: ----- -JSON RPC ------ +## JSON RPC The ffplayout engine can run a JSON RPC server. A request show look like: diff --git a/assets/ffpapi.service b/assets/ffpapi.service index 8cbf18c6..507e5918 100644 --- a/assets/ffpapi.service +++ b/assets/ffpapi.service @@ -3,7 +3,7 @@ Description=Rest API for ffplayout After=network.target remote-fs.target [Service] -ExecStart=/usr/bin/ffpapi -l 127.0.0.1:8000 +ExecStart=/usr/bin/ffpapi -l 0.0.0.0:8000 Restart=always RestartSec=1 User=ffpu diff --git a/assets/ffplayout.yml b/assets/ffplayout.yml index dba10637..71b5204a 100644 --- a/assets/ffplayout.yml +++ b/assets/ffplayout.yml @@ -117,25 +117,7 @@ text: out: 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: >- - -s 512x288 - -c:v libx264 - -crf 24 - -x264-params keyint=50:min-keyint=25:scenecut=-1 - -maxrate 800k - -bufsize 1600k - -preset ultrafast - -tune zerolatency - -profile:v Main - -level 3.1 - -c:a aac - -ar 44100 - -b:a 128k - -flags +global_header - -f flv rtmp://preview.local/live/stream output_param: >- -c:v libx264 -crf 23 diff --git a/debian/postinst b/debian/postinst index 5cff5bd8..1bdeacba 100644 --- a/debian/postinst +++ b/debian/postinst @@ -23,3 +23,8 @@ if [ ! -d "/var/log/ffplayout" ]; then chown ${sysUser}. "/var/log/ffplayout" fi + +tar xf "/usr/share/ffplayout/public.tar.gz" --overwrite -C "/usr/share/ffplayout/" +ln -s "/var/lib/ffplayout/tv-media" "/usr/share/ffplayout/public/" +chown -R ${sysUser}. "/usr/share/ffplayout/public" +yes | rm "/usr/share/ffplayout/public.tar.gz" diff --git a/debian/postrm b/debian/postrm new file mode 100644 index 00000000..349ed77e --- /dev/null +++ b/debian/postrm @@ -0,0 +1,15 @@ +#DEBHELPER# + +sysUser="ffpu" + +if [ -d "/usr/share/ffplayout" ]; then + yes | rm -rf "/usr/share/ffplayout" "/var/lib/ffplayout" +fi + +if [ -d "/var/log/ffplayout" ]; then + yes | rm -rf "/var/log/ffplayout" +fi + +if id $sysUser &>/dev/null; then + userdel -rf $sysUser +fi diff --git a/docs/preview_stream.md b/docs/preview_stream.md index 6ddef57c..d06459fd 100644 --- a/docs/preview_stream.md +++ b/docs/preview_stream.md @@ -1,6 +1,26 @@ ### Preview Stream -The ffplayout engine output provides a setting for previewing. In general you can use any technique to display your streaming preview, even SDL could be possible. +The ffplayout engine has no special preview config parameters, but you can add your settings to the **output_param**, like: + +```YAML + -s 512x288 + -c:v libx264 + -crf 24 + -x264-params keyint=50:min-keyint=25:scenecut=-1 + -maxrate 800k + -bufsize 1600k + -preset ultrafast + -tune zerolatency + -profile:v Main + -level 3.1 + -c:a aac + -ar 44100 + -b:a 128k + -flags +global_header + -f flv rtmp://preview.local/live/stream + + ... +``` In this documentation we suspect, that you are using [ffplayout-frontend](https://github.com/ffplayout/ffplayout-frontend) and that you using [SRS](https://github.com/ossrs/srs) at least for the preview stream. In the past we used HLS for the preview, but now it is possible to also use [HTTP-FLV](https://github.com/ossrs/srs/wiki/v4_EN_DeliveryHttpStream) for less latency. @@ -8,7 +28,6 @@ To get this working we have to follow some steps. ffplayout engine needs a direc ``` ... - 127.0.0.1 preview.local ``` diff --git a/ffplayout-api/Cargo.toml b/ffplayout-api/Cargo.toml index e153be17..35f9e004 100644 --- a/ffplayout-api/Cargo.toml +++ b/ffplayout-api/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" [dependencies] ffplayout-lib = { path = "../lib" } +actix-files = "0.6" actix-multipart = "0.4" actix-web = "4" actix-web-grants = "3" diff --git a/ffplayout-api/src/main.rs b/ffplayout-api/src/main.rs index 9523b8b6..f4104f8e 100644 --- a/ffplayout-api/src/main.rs +++ b/ffplayout-api/src/main.rs @@ -1,5 +1,6 @@ use std::{path::Path, process::exit}; +use actix_files::Files; use actix_web::{dev::ServiceRequest, middleware, web, App, Error, HttpMessage, HttpServer}; use actix_web_grants::permissions::AttachPermissions; use actix_web_httpauth::extractors::bearer::BearerAuth; @@ -107,6 +108,7 @@ async fn main() -> std::io::Result<()> { .service(remove) .service(save_file), ) + .service(Files::new("/", "/usr/share/ffplayout/public/").index_file("index.html")) }) .bind((addr, port))? .run() diff --git a/ffplayout-engine/Cargo.toml b/ffplayout-engine/Cargo.toml index cc316e16..0f1af9dc 100644 --- a/ffplayout-engine/Cargo.toml +++ b/ffplayout-engine/Cargo.toml @@ -4,7 +4,7 @@ description = "24/7 playout based on rust and ffmpeg" license = "GPL-3.0" authors = ["Jonathan Baecker jonbae77@gmail.com"] readme = "README.md" -version = "0.11.0" +version = "0.12.0" edition = "2021" [dependencies] @@ -55,6 +55,7 @@ assets = [ ["../assets/logo.png", "/usr/share/ffplayout/", "644"], ["../assets/ffplayout.yml", "/usr/share/ffplayout/ffplayout.yml.orig", "644"], ["../README.md", "/usr/share/doc/ffplayout/README", "644"], + ["../public.tar.gz", "/usr/share/ffplayout/", "644"], ] maintainer-scripts = "../debian/" systemd-units = { enable = false, unit-scripts = "../assets" } @@ -94,6 +95,8 @@ assets = [ { source = "../assets/logo.png", dest = "/usr/share/ffplayout/logo.png", mode = "644" }, { source = "../assets/ffplayout.yml", dest = "/usr/share/ffplayout/ffplayout.yml.orig", mode = "644" }, { source = "../debian/postinst", dest = "/usr/share/ffplayout/postinst", mode = "755" }, + { source = "../debian/postrm", dest = "/usr/share/ffplayout/postrm", mode = "755" }, ] auto-req = "no" post_install_script = "/usr/share/ffplayout/postinst" +post_uninstall_script = "/usr/share/ffplayout/postrm" diff --git a/ffplayout-engine/src/output/hls.rs b/ffplayout-engine/src/output/hls.rs index 9f9d7ede..c583625d 100644 --- a/ffplayout-engine/src/output/hls.rs +++ b/ffplayout-engine/src/output/hls.rs @@ -149,10 +149,6 @@ pub fn write_hls( proc_control.is_terminated.clone(), ); - if config.out.preview { - warn!("Preview in HLS mode is not supported!"); - } - // spawn a thread for ffmpeg ingest server and create a channel for package sending if config.ingest.enable { thread::spawn(move || ingest_to_hls_server(config_clone, play_stat, proc_control_c)); diff --git a/ffplayout-engine/src/output/stream.rs b/ffplayout-engine/src/output/stream.rs index ae4eec74..85d69f7d 100644 --- a/ffplayout-engine/src/output/stream.rs +++ b/ffplayout-engine/src/output/stream.rs @@ -12,7 +12,6 @@ use ffplayout_lib::vec_strings; pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child { let mut enc_cmd = vec![]; let mut enc_filter = vec![]; - let mut preview_cmd = config.out.preview_cmd.as_ref().unwrap().clone(); let mut output_cmd = config.out.output_cmd.as_ref().unwrap().clone(); let enc_prefix = vec_strings![ @@ -42,10 +41,6 @@ pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child { } } - if config.out.preview { - enc_cmd.append(&mut preview_cmd); - } - enc_cmd.append(&mut output_cmd); let enc_cmd = prepare_output_cmd(enc_prefix, enc_filter, enc_cmd, &config.out.mode); diff --git a/lib/Cargo.toml b/lib/Cargo.toml index ea65a76a..edc8a745 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -4,7 +4,7 @@ description = "Library for ffplayout" license = "GPL-3.0" authors = ["Jonathan Baecker jonbae77@gmail.com"] readme = "README.md" -version = "0.10.5" +version = "0.12.0" edition = "2021" [dependencies] diff --git a/lib/src/utils/config.rs b/lib/src/utils/config.rs index 4c275fa2..483e842a 100644 --- a/lib/src/utils/config.rs +++ b/lib/src/utils/config.rs @@ -154,12 +154,6 @@ pub struct Text { pub struct Out { pub help_text: String, pub mode: String, - pub preview: bool, - pub preview_param: String, - - #[serde(skip_serializing, skip_deserializing)] - pub preview_cmd: Option>, - pub output_param: String, #[serde(skip_serializing, skip_deserializing)] @@ -245,7 +239,6 @@ impl PlayoutConfig { config.processing.settings = Some(settings); config.ingest.input_cmd = split(config.ingest.input_param.as_str()); - config.out.preview_cmd = split(config.out.preview_param.as_str()); config.out.output_cmd = split(config.out.output_param.as_str()); // when text overlay without text_from_filename is on, turn also the RPC server on, diff --git a/scripts/build_all.sh b/scripts/build_all.sh index c75bf920..edd206e7 100755 --- a/scripts/build_all.sh +++ b/scripts/build_all.sh @@ -54,6 +54,21 @@ for target in "${targets[@]}"; do echo "" done + + + +cd ffplayout-frontend + +npm install +npm run build +yes | rm -rf public ../public.tar.gz +mv dist public +tar czf public.tar.gz public +mv public.tar.gz ../ +yes | rm -rf public + +cd .. + cargo deb --target=x86_64-unknown-linux-musl -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_amd64.deb cargo deb --target=aarch64-unknown-linux-gnu --variant=arm64 -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_arm64.deb From 2584051e1b891bd065cdffd1e07be02e60e5966f Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Sun, 24 Jul 2022 19:30:04 +0200 Subject: [PATCH 3/8] change commit --- ffplayout-frontend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ffplayout-frontend b/ffplayout-frontend index be719325..9832a5e1 160000 --- a/ffplayout-frontend +++ b/ffplayout-frontend @@ -1 +1 @@ -Subproject commit be719325858a3c9403d6d2d778c88d8820b52903 +Subproject commit 9832a5e12c4fc604b513a09d3a89c898d477e87d From 088bce28d4784759c80849029b6849c1ed7be9ea Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 25 Jul 2022 17:26:49 +0200 Subject: [PATCH 4/8] include public in assets --- assets/ffpapi.service | 2 +- debian/postinst | 7 +-- docs/api.md | 64 +++++++++++++-------------- ffplayout-api/README.md | 4 +- ffplayout-api/src/main.rs | 14 +++++- ffplayout-api/src/utils/args_parse.rs | 2 +- ffplayout-api/src/utils/routes.rs | 64 +++++++++++++-------------- ffplayout-engine/Cargo.toml | 4 +- ffplayout-frontend | 2 +- scripts/build_all.sh | 23 ++++------ 10 files changed, 96 insertions(+), 90 deletions(-) diff --git a/assets/ffpapi.service b/assets/ffpapi.service index 507e5918..ddf8218c 100644 --- a/assets/ffpapi.service +++ b/assets/ffpapi.service @@ -3,7 +3,7 @@ Description=Rest API for ffplayout After=network.target remote-fs.target [Service] -ExecStart=/usr/bin/ffpapi -l 0.0.0.0:8000 +ExecStart=/usr/bin/ffpapi -l 0.0.0.0:8787 Restart=always RestartSec=1 User=ffpu diff --git a/debian/postinst b/debian/postinst index 1bdeacba..0e99cc00 100644 --- a/debian/postinst +++ b/debian/postinst @@ -16,6 +16,8 @@ if [ ! -d "/usr/share/ffplayout/db" ]; then chown -R ${sysUser}. "/usr/share/ffplayout" chown -R ${sysUser}. "/var/lib/ffplayout" chown -R ${sysUser}. "/etc/ffplayout" + + ln -s "/var/lib/ffplayout/tv-media" "/usr/share/ffplayout/public/" fi if [ ! -d "/var/log/ffplayout" ]; then @@ -23,8 +25,3 @@ if [ ! -d "/var/log/ffplayout" ]; then chown ${sysUser}. "/var/log/ffplayout" fi - -tar xf "/usr/share/ffplayout/public.tar.gz" --overwrite -C "/usr/share/ffplayout/" -ln -s "/var/lib/ffplayout/tv-media" "/usr/share/ffplayout/public/" -chown -R ${sysUser}. "/usr/share/ffplayout/public" -yes | rm "/usr/share/ffplayout/public.tar.gz" diff --git a/docs/api.md b/docs/api.md index 0c9d32de..896922ae 100644 --- a/docs/api.md +++ b/docs/api.md @@ -3,7 +3,7 @@ Run the API thru the systemd service, or like: ```BASH -ffpapi -l 127.0.0.1:8000 +ffpapi -l 127.0.0.1:8787 ``` For all endpoints an (Bearer) authentication is required.\ @@ -14,7 +14,7 @@ For all endpoints an (Bearer) authentication is required.\ **Login** ```BASH -curl -X POST http://127.0.0.1:8000/auth/login/ -H "Content-Type: application/json" \ +curl -X POST http://127.0.0.1:8787/auth/login/ -H "Content-Type: application/json" \ -d '{ "username": "", "password": "" }' ``` **Response:** @@ -34,21 +34,21 @@ From here on all request **must** contain the authorization header:\ **Get current User** ```BASH -curl -X GET 'http://localhost:8000/api/user' -H 'Content-Type: application/json' \ +curl -X GET 'http://127.0.0.1:8787/api/user' -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' ``` **Update current User** ```BASH -curl -X PUT http://localhost:8000/api/user/1 -H 'Content-Type: application/json' \ +curl -X PUT http://127.0.0.1:8787/api/user/1 -H 'Content-Type: application/json' \ -d '{"mail": "", "password": ""}' -H 'Authorization: ' ``` **Add User** ```BASH -curl -X POST 'http://localhost:8000/api/user/' -H 'Content-Type: application/json' \ +curl -X POST 'http://127.0.0.1:8787/api/user/' -H 'Content-Type: application/json' \ -d '{"mail": "", "username": "", "password": "", "role_id": 1, "channel_id": 1}' \ -H 'Authorization: Bearer ' ``` @@ -58,7 +58,7 @@ curl -X POST 'http://localhost:8000/api/user/' -H 'Content-Type: application/jso **Get Settings from Channel** ```BASH -curl -X GET http://127.0.0.1:8000/api/channel/1 -H "Authorization: Bearer " +curl -X GET http://127.0.0.1:8787/api/channel/1 -H "Authorization: Bearer " ``` **Response:** @@ -78,13 +78,13 @@ curl -X GET http://127.0.0.1:8000/api/channel/1 -H "Authorization: Bearer " +curl -X GET http://127.0.0.1:8787/api/channels -H "Authorization: Bearer " ``` **Update Channel** ```BASH -curl -X PATCH http://127.0.0.1:8000/api/channel/1 -H "Content-Type: application/json" \ +curl -X PATCH http://127.0.0.1:8787/api/channel/1 -H "Content-Type: application/json" \ -d '{ "id": 1, "name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \ "config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png", "timezone": "Europe/Berlin"}' \ -H "Authorization: Bearer " @@ -93,7 +93,7 @@ curl -X PATCH http://127.0.0.1:8000/api/channel/1 -H "Content-Type: application/ **Create new Channel** ```BASH -curl -X POST http://127.0.0.1:8000/api/channel/ -H "Content-Type: application/json" \ +curl -X POST http://127.0.0.1:8787/api/channel/ -H "Content-Type: application/json" \ -d '{ "name": "Channel 2", "preview_url": "http://localhost/live/channel2.m3u8", \ "config_path": "/etc/ffplayout/channel2.yml", "extra_extensions": "jpg,jpeg,png", "timezone": "Europe/Berlin", "service": "ffplayout@channel2.service" }' \ @@ -103,7 +103,7 @@ curl -X POST http://127.0.0.1:8000/api/channel/ -H "Content-Type: application/js **Delete Channel** ```BASH -curl -X DELETE http://127.0.0.1:8000/api/channel/2 -H "Authorization: Bearer " +curl -X DELETE http://127.0.0.1:8787/api/channel/2 -H "Authorization: Bearer " ``` #### ffplayout Config @@ -111,7 +111,7 @@ curl -X DELETE http://127.0.0.1:8000/api/channel/2 -H "Authorization: Bearer ' +curl -X GET http://127.0.0.1:8787/api/playout/config/1 -H 'Authorization: ' ``` Response is a JSON object from the ffplayout.yml @@ -119,7 +119,7 @@ Response is a JSON object from the ffplayout.yml **Update Config** ```BASH -curl -X PUT http://localhost:8000/api/playout/config/1 -H "Content-Type: application/json" \ +curl -X PUT http://127.0.0.1:8787/api/playout/config/1 -H "Content-Type: application/json" \ -d { } -H 'Authorization: ' ``` @@ -130,14 +130,14 @@ Text presets are made for sending text messages to the ffplayout engine, to over **Get all Presets** ```BASH -curl -X GET http://localhost:8000/api/presets/ -H 'Content-Type: application/json' \ +curl -X GET http://127.0.0.1:8787/api/presets/ -H 'Content-Type: application/json' \ -H 'Authorization: ' ``` **Update Preset** ```BASH -curl -X PUT http://localhost:8000/api/presets/1 -H 'Content-Type: application/json' \ +curl -X PUT http://127.0.0.1:8787/api/presets/1 -H 'Content-Type: application/json' \ -d '{ "name": "", "text": "", "x": "", "y": "", "fontsize": 24, \ "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \ -H 'Authorization: ' @@ -146,7 +146,7 @@ curl -X PUT http://localhost:8000/api/presets/1 -H 'Content-Type: application/js **Add new Preset** ```BASH -curl -X POST http://localhost:8000/api/presets/ -H 'Content-Type: application/json' \ +curl -X POST http://127.0.0.1:8787/api/presets/ -H 'Content-Type: application/json' \ -d '{ "name": "", "text": "TEXT>", "x": "", "y": "", "fontsize": 24, \ "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \ -H 'Authorization: ' @@ -155,7 +155,7 @@ curl -X POST http://localhost:8000/api/presets/ -H 'Content-Type: application/js **Delete Preset** ```BASH -curl -X DELETE http://localhost:8000/api/presets/1 -H 'Content-Type: application/json' \ +curl -X DELETE http://127.0.0.1:8787/api/presets/1 -H 'Content-Type: application/json' \ -H 'Authorization: ' ``` @@ -170,7 +170,7 @@ here we communicate with the engine for: **Send Text to ffplayout** ```BASH -curl -X POST http://localhost:8000/api/control/1/text/ \ +curl -X POST http://127.0.0.1:8787/api/control/1/text/ \ -H 'Content-Type: application/json' -H 'Authorization: ' \ -d '{"text": "Hello from ffplayout", "x": "(w-text_w)/2", "y": "(h-text_h)/2", \ "fontsize": "24", "line_spacing": "4", "fontcolor": "#ffffff", "box": "1", \ @@ -184,14 +184,14 @@ curl -X POST http://localhost:8000/api/control/1/text/ \ - reset ```BASH -curl -X POST http://localhost:8000/api/control/1/playout/next/ -H 'Content-Type: application/json' +curl -X POST http://127.0.0.1:8787/api/control/1/playout/next/ -H 'Content-Type: application/json' -d '{ "command": "reset" }' -H 'Authorization: ' ``` **Get current Clip** ```BASH -curl -X GET http://localhost:8000/api/control/1/media/current +curl -X GET http://127.0.0.1:8787/api/control/1/media/current -H 'Content-Type: application/json' -H 'Authorization: ' ``` @@ -222,13 +222,13 @@ curl -X GET http://localhost:8000/api/control/1/media/current **Get next Clip** ```BASH -curl -X GET http://localhost:8000/api/control/1/media/next/ -H 'Authorization: ' +curl -X GET http://127.0.0.1:8787/api/control/1/media/next/ -H 'Authorization: ' ``` **Get last Clip** ```BASH -curl -X GET http://localhost:8000/api/control/1/media/last/ +curl -X GET http://127.0.0.1:8787/api/control/1/media/last/ -H 'Content-Type: application/json' -H 'Authorization: ' ``` @@ -241,7 +241,7 @@ Control ffplayout process, like: - status ```BASH -curl -X POST http://localhost:8000/api/control/1/process/ +curl -X POST http://127.0.0.1:8787/api/control/1/process/ -H 'Content-Type: application/json' -H 'Authorization: ' -d '{"command": "start"}' ``` @@ -251,14 +251,14 @@ curl -X POST http://localhost:8000/api/control/1/process/ **Get playlist** ```BASH -curl -X GET http://localhost:8000/api/playlist/1?date=2022-06-20 +curl -X GET http://127.0.0.1:8787/api/playlist/1?date=2022-06-20 -H 'Content-Type: application/json' -H 'Authorization: ' ``` **Save playlist** ```BASH -curl -X POST http://localhost:8000/api/playlist/1/ +curl -X POST http://127.0.0.1:8787/api/playlist/1/ -H 'Content-Type: application/json' -H 'Authorization: ' -- data "{}" ``` @@ -268,14 +268,14 @@ curl -X POST http://localhost:8000/api/playlist/1/ A new playlist will be generated and response. ```BASH -curl -X GET http://localhost:8000/api/playlist/1/generate/2022-06-20 +curl -X GET http://127.0.0.1:8787/api/playlist/1/generate/2022-06-20 -H 'Content-Type: application/json' -H 'Authorization: ' ``` **Delete Playlist** ```BASH -curl -X DELETE http://localhost:8000/api/playlist/1/2022-06-20 +curl -X DELETE http://127.0.0.1:8787/api/playlist/1/2022-06-20 -H 'Content-Type: application/json' -H 'Authorization: ' ``` @@ -284,7 +284,7 @@ curl -X DELETE http://localhost:8000/api/playlist/1/2022-06-20 **Read Log Life** ```BASH -curl -X Get http://localhost:8000/api/log/1 +curl -X Get http://127.0.0.1:8787/api/log/1 -H 'Content-Type: application/json' -H 'Authorization: ' ``` @@ -293,34 +293,34 @@ curl -X Get http://localhost:8000/api/log/1 **Get File/Folder List** ```BASH -curl -X POST http://localhost:8000/api/file/1/browse/ -H 'Content-Type: application/json' +curl -X POST http://127.0.0.1:8787/api/file/1/browse/ -H 'Content-Type: application/json' -d '{ "source": "/" }' -H 'Authorization: ' ``` **Create Folder** ```BASH -curl -X POST http://localhost:8000/api/file/1/create-folder/ -H 'Content-Type: application/json' +curl -X POST http://127.0.0.1:8787/api/file/1/create-folder/ -H 'Content-Type: application/json' -d '{"source": ""}' -H 'Authorization: ' ``` **Rename File** ```BASH -curl -X POST http://localhost:8000/api/file/1/rename/ -H 'Content-Type: application/json' +curl -X POST http://127.0.0.1:8787/api/file/1/rename/ -H 'Content-Type: application/json' -d '{"source": "", "target": ""}' -H 'Authorization: ' ``` **Remove File/Folder** ```BASH -curl -X POST http://localhost:8000/api/file/1/remove/ -H 'Content-Type: application/json' +curl -X POST http://127.0.0.1:8787/api/file/1/remove/ -H 'Content-Type: application/json' -d '{"source": ""}' -H 'Authorization: ' ``` **Upload File** ```BASH -curl -X POST http://localhost:8000/api/file/1/upload/ -H 'Authorization: ' +curl -X POST http://127.0.0.1:8787/api/file/1/upload/ -H 'Authorization: ' -F "file=@file.mp4" ``` diff --git a/ffplayout-api/README.md b/ffplayout-api/README.md index 83c2eecc..cf3c215b 100644 --- a/ffplayout-api/README.md +++ b/ffplayout-api/README.md @@ -18,9 +18,11 @@ ffpapi -u -p -m Then run the API thru the systemd service, or like: ```BASH -ffpapi -l 127.0.0.1:8080 +ffpapi -l 127.0.0.1:8787 ``` 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)** + +ffpapi can also serve the browser based frontend, just run in your browser `127.0.0.1:8787`. diff --git a/ffplayout-api/src/main.rs b/ffplayout-api/src/main.rs index f4104f8e..7e910f38 100644 --- a/ffplayout-api/src/main.rs +++ b/ffplayout-api/src/main.rs @@ -38,6 +38,18 @@ async fn validator(req: ServiceRequest, credentials: BearerAuth) -> Result &'static str { + if Path::new("/usr/share/ffplayout/public/").is_dir() { + return "/usr/share/ffplayout/public/" + } + + if Path::new("./public/").is_dir() { + return "./public/" + } + + "./ffplayout-frontend/dist" +} + #[actix_web::main] async fn main() -> std::io::Result<()> { let args = Args::parse(); @@ -108,7 +120,7 @@ async fn main() -> std::io::Result<()> { .service(remove) .service(save_file), ) - .service(Files::new("/", "/usr/share/ffplayout/public/").index_file("index.html")) + .service(Files::new("/", public_path()).index_file("index.html")) }) .bind((addr, port))? .run() diff --git a/ffplayout-api/src/utils/args_parse.rs b/ffplayout-api/src/utils/args_parse.rs index 0b3a70f2..246da8b9 100644 --- a/ffplayout-api/src/utils/args_parse.rs +++ b/ffplayout-api/src/utils/args_parse.rs @@ -8,7 +8,7 @@ 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")] + #[clap(short, long, help = "Listen on IP:PORT, like: 127.0.0.1:8787")] pub listen: Option, #[clap(short, long, help = "Initialize Database")] diff --git a/ffplayout-api/src/utils/routes.rs b/ffplayout-api/src/utils/routes.rs index 6f96ebd7..d1e7975e 100644 --- a/ffplayout-api/src/utils/routes.rs +++ b/ffplayout-api/src/utils/routes.rs @@ -3,7 +3,7 @@ /// Run the API thru the systemd service, or like: /// /// ```BASH -/// ffpapi -l 127.0.0.1:8000 +/// ffpapi -l 127.0.0.1:8787 /// ``` /// /// For all endpoints an (Bearer) authentication is required.\ @@ -70,7 +70,7 @@ pub struct FileObj { /// **Login** /// /// ```BASH -/// curl -X POST http://127.0.0.1:8000/auth/login/ -H "Content-Type: application/json" \ +/// curl -X POST http://127.0.0.1:8787/auth/login/ -H "Content-Type: application/json" \ /// -d '{ "username": "", "password": "" }' /// ``` /// **Response:** @@ -141,7 +141,7 @@ pub async fn login(credentials: web::Json) -> impl Responder { /// **Get current User** /// /// ```BASH -/// curl -X GET 'http://localhost:8000/api/user' -H 'Content-Type: application/json' \ +/// curl -X GET 'http://127.0.0.1:8787/api/user' -H 'Content-Type: application/json' \ /// -H 'Authorization: Bearer ' /// ``` #[get("/user")] @@ -159,7 +159,7 @@ async fn get_user(user: web::ReqData) -> Result", "password": ""}' -H 'Authorization: ' /// ``` #[put("/user/{id}")] @@ -202,7 +202,7 @@ async fn update_user( /// **Add User** /// /// ```BASH -/// curl -X POST 'http://localhost:8000/api/user/' -H 'Content-Type: application/json' \ +/// curl -X POST 'http://127.0.0.1:8787/api/user/' -H 'Content-Type: application/json' \ /// -d '{"mail": "", "username": "", "password": "", "role_id": 1, "channel_id": 1}' \ /// -H 'Authorization: Bearer ' /// ``` @@ -223,7 +223,7 @@ async fn add_user(data: web::Json) -> Result /// **Get Settings from Channel** /// /// ```BASH -/// curl -X GET http://127.0.0.1:8000/api/channel/1 -H "Authorization: Bearer " +/// curl -X GET http://127.0.0.1:8787/api/channel/1 -H "Authorization: Bearer " /// ``` /// /// **Response:** @@ -252,7 +252,7 @@ async fn get_channel(id: web::Path) -> Result /// **Get settings from all Channels** /// /// ```BASH -/// curl -X GET http://127.0.0.1:8000/api/channels -H "Authorization: Bearer " +/// curl -X GET http://127.0.0.1:8787/api/channels -H "Authorization: Bearer " /// ``` #[get("/channels")] #[has_any_role("Role::Admin", type = "Role")] @@ -267,7 +267,7 @@ async fn get_all_channels() -> Result { /// **Update Channel** /// /// ```BASH -/// curl -X PATCH http://127.0.0.1:8000/api/channel/1 -H "Content-Type: application/json" \ +/// curl -X PATCH http://127.0.0.1:8787/api/channel/1 -H "Content-Type: application/json" \ /// -d '{ "id": 1, "name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \ /// "config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png", "timezone": "Europe/Berlin"}' \ /// -H "Authorization: Bearer " @@ -288,7 +288,7 @@ async fn patch_channel( /// **Create new Channel** /// /// ```BASH -/// curl -X POST http://127.0.0.1:8000/api/channel/ -H "Content-Type: application/json" \ +/// curl -X POST http://127.0.0.1:8787/api/channel/ -H "Content-Type: application/json" \ /// -d '{ "name": "Channel 2", "preview_url": "http://localhost/live/channel2.m3u8", \ /// "config_path": "/etc/ffplayout/channel2.yml", "extra_extensions": "jpg,jpeg,png", /// "timezone": "Europe/Berlin", "service": "ffplayout@channel2.service" }' \ @@ -306,7 +306,7 @@ async fn add_channel(data: web::Json) -> Result" +/// curl -X DELETE http://127.0.0.1:8787/api/channel/2 -H "Authorization: Bearer " /// ``` #[delete("/channel/{id}")] #[has_any_role("Role::Admin", type = "Role")] @@ -323,7 +323,7 @@ async fn remove_channel(id: web::Path) -> Result' +/// curl -X GET http://127.0.0.1:8787/api/playout/config/1 -H 'Authorization: ' /// ``` /// /// Response is a JSON object from the ffplayout.yml @@ -345,7 +345,7 @@ async fn get_playout_config( /// **Update Config** /// /// ```BASH -/// curl -X PUT http://localhost:8000/api/playout/config/1 -H "Content-Type: application/json" \ +/// curl -X PUT http://127.0.0.1:8787/api/playout/config/1 -H "Content-Type: application/json" \ /// -d { } -H 'Authorization: ' /// ``` #[put("/playout/config/{id}")] @@ -378,7 +378,7 @@ async fn update_playout_config( /// **Get all Presets** /// /// ```BASH -/// curl -X GET http://localhost:8000/api/presets/ -H 'Content-Type: application/json' \ +/// curl -X GET http://127.0.0.1:8787/api/presets/ -H 'Content-Type: application/json' \ /// -H 'Authorization: ' /// ``` #[get("/presets/{id}")] @@ -394,7 +394,7 @@ async fn get_presets(id: web::Path) -> Result /// **Update Preset** /// /// ```BASH -/// curl -X PUT http://localhost:8000/api/presets/1 -H 'Content-Type: application/json' \ +/// curl -X PUT http://127.0.0.1:8787/api/presets/1 -H 'Content-Type: application/json' \ /// -d '{ "name": "", "text": "", "x": "", "y": "", "fontsize": 24, \ /// "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \ /// -H 'Authorization: ' @@ -415,7 +415,7 @@ async fn update_preset( /// **Add new Preset** /// /// ```BASH -/// curl -X POST http://localhost:8000/api/presets/ -H 'Content-Type: application/json' \ +/// curl -X POST http://127.0.0.1:8787/api/presets/ -H 'Content-Type: application/json' \ /// -d '{ "name": "", "text": "TEXT>", "x": "", "y": "", "fontsize": 24, \ /// "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \ /// -H 'Authorization: ' @@ -433,7 +433,7 @@ async fn add_preset(data: web::Json) -> Result' /// ``` #[delete("/presets/{id}")] @@ -457,7 +457,7 @@ async fn delete_preset(id: web::Path) -> Result' \ /// -d '{"text": "Hello from ffplayout", "x": "(w-text_w)/2", "y": "(h-text_h)/2", \ /// "fontsize": "24", "line_spacing": "4", "fontcolor": "#ffffff", "box": "1", \ @@ -482,7 +482,7 @@ pub async fn send_text_message( /// - reset /// /// ```BASH -/// curl -X POST http://localhost:8000/api/control/1/playout/next/ -H 'Content-Type: application/json' +/// curl -X POST http://127.0.0.1:8787/api/control/1/playout/next/ -H 'Content-Type: application/json' /// -d '{ "command": "reset" }' -H 'Authorization: ' /// ``` #[post("/control/{id}/playout/")] @@ -500,7 +500,7 @@ pub async fn control_playout( /// **Get current Clip** /// /// ```BASH -/// curl -X GET http://localhost:8000/api/control/1/media/current +/// curl -X GET http://127.0.0.1:8787/api/control/1/media/current /// -H 'Content-Type: application/json' -H 'Authorization: ' /// ``` /// @@ -539,7 +539,7 @@ pub async fn media_current(id: web::Path) -> Result' +/// curl -X GET http://127.0.0.1:8787/api/control/1/media/next/ -H 'Authorization: ' /// ``` #[get("/control/{id}/media/next")] #[has_any_role("Role::Admin", "Role::User", type = "Role")] @@ -553,7 +553,7 @@ pub async fn media_next(id: web::Path) -> Result' /// ``` #[get("/control/{id}/media/last")] @@ -574,7 +574,7 @@ pub async fn media_last(id: web::Path) -> Result' /// -d '{"command": "start"}' /// ``` @@ -592,7 +592,7 @@ pub async fn process_control( /// **Get playlist** /// /// ```BASH -/// curl -X GET http://localhost:8000/api/playlist/1?date=2022-06-20 +/// curl -X GET http://127.0.0.1:8787/api/playlist/1?date=2022-06-20 /// -H 'Content-Type: application/json' -H 'Authorization: ' /// ``` #[get("/playlist/{id}")] @@ -610,7 +610,7 @@ pub async fn get_playlist( /// **Save playlist** /// /// ```BASH -/// curl -X POST http://localhost:8000/api/playlist/1/ +/// curl -X POST http://127.0.0.1:8787/api/playlist/1/ /// -H 'Content-Type: application/json' -H 'Authorization: ' /// -- data "{}" /// ``` @@ -631,7 +631,7 @@ pub async fn save_playlist( /// A new playlist will be generated and response. /// /// ```BASH -/// curl -X GET http://localhost:8000/api/playlist/1/generate/2022-06-20 +/// curl -X GET http://127.0.0.1:8787/api/playlist/1/generate/2022-06-20 /// -H 'Content-Type: application/json' -H 'Authorization: ' /// ``` #[get("/playlist/{id}/generate/{date}")] @@ -648,7 +648,7 @@ pub async fn gen_playlist( /// **Delete Playlist** /// /// ```BASH -/// curl -X DELETE http://localhost:8000/api/playlist/1/2022-06-20 +/// curl -X DELETE http://127.0.0.1:8787/api/playlist/1/2022-06-20 /// -H 'Content-Type: application/json' -H 'Authorization: ' /// ``` #[delete("/playlist/{id}/{date}")] @@ -667,7 +667,7 @@ pub async fn del_playlist( /// **Read Log Life** /// /// ```BASH -/// curl -X Get http://localhost:8000/api/log/1 +/// curl -X Get http://127.0.0.1:8787/api/log/1 /// -H 'Content-Type: application/json' -H 'Authorization: ' /// ``` #[get("/log/{id}")] @@ -684,7 +684,7 @@ pub async fn get_log( /// **Get File/Folder List** /// /// ```BASH -/// curl -X POST http://localhost:8000/api/file/1/browse/ -H 'Content-Type: application/json' +/// curl -X POST http://127.0.0.1:8787/api/file/1/browse/ -H 'Content-Type: application/json' /// -d '{ "source": "/" }' -H 'Authorization: ' /// ``` #[post("/file/{id}/browse/")] @@ -702,7 +702,7 @@ pub async fn file_browser( /// **Create Folder** /// /// ```BASH -/// curl -X POST http://localhost:8000/api/file/1/create-folder/ -H 'Content-Type: application/json' +/// curl -X POST http://127.0.0.1:8787/api/file/1/create-folder/ -H 'Content-Type: application/json' /// -d '{"source": ""}' -H 'Authorization: ' /// ``` #[post("/file/{id}/create-folder/")] @@ -717,7 +717,7 @@ pub async fn add_dir( /// **Rename File** /// /// ```BASH -/// curl -X POST http://localhost:8000/api/file/1/rename/ -H 'Content-Type: application/json' +/// curl -X POST http://127.0.0.1:8787/api/file/1/rename/ -H 'Content-Type: application/json' /// -d '{"source": "", "target": ""}' -H 'Authorization: ' /// ``` #[post("/file/{id}/rename/")] @@ -735,7 +735,7 @@ pub async fn move_rename( /// **Remove File/Folder** /// /// ```BASH -/// curl -X POST http://localhost:8000/api/file/1/remove/ -H 'Content-Type: application/json' +/// curl -X POST http://127.0.0.1:8787/api/file/1/remove/ -H 'Content-Type: application/json' /// -d '{"source": ""}' -H 'Authorization: ' /// ``` #[post("/file/{id}/remove/")] @@ -753,7 +753,7 @@ pub async fn remove( /// **Upload File** /// /// ```BASH -/// curl -X POST http://localhost:8000/api/file/1/upload/ -H 'Authorization: ' +/// curl -X POST http://127.0.0.1:8787/api/file/1/upload/ -H 'Authorization: ' /// -F "file=@file.mp4" /// ``` #[put("/file/{id}/upload/")] diff --git a/ffplayout-engine/Cargo.toml b/ffplayout-engine/Cargo.toml index 0f1af9dc..b2eb4f5c 100644 --- a/ffplayout-engine/Cargo.toml +++ b/ffplayout-engine/Cargo.toml @@ -55,7 +55,7 @@ assets = [ ["../assets/logo.png", "/usr/share/ffplayout/", "644"], ["../assets/ffplayout.yml", "/usr/share/ffplayout/ffplayout.yml.orig", "644"], ["../README.md", "/usr/share/doc/ffplayout/README", "644"], - ["../public.tar.gz", "/usr/share/ffplayout/", "644"], + ["../public/**/*", "/usr/share/ffplayout/public/", "644"], ] maintainer-scripts = "../debian/" systemd-units = { enable = false, unit-scripts = "../assets" } @@ -76,6 +76,7 @@ assets = [ ["../assets/logo.png", "/usr/share/ffplayout/", "644"], ["../assets/ffplayout.yml", "/usr/share/ffplayout/ffplayout.yml.orig", "644"], ["../README.md", "/usr/share/doc/ffplayout/README", "644"], + ["../public/**/*", "/usr/share/ffplayout/public/", "644"], ] # REHL RPM PACKAGE @@ -94,6 +95,7 @@ assets = [ { source = "../LICENSE", dest = "/usr/share/doc/ffplayout/LICENSE", mode = "644" }, { source = "../assets/logo.png", dest = "/usr/share/ffplayout/logo.png", mode = "644" }, { source = "../assets/ffplayout.yml", dest = "/usr/share/ffplayout/ffplayout.yml.orig", mode = "644" }, + { source = "../public/**/*", dest = "/usr/share/ffplayout/public/", mode = "644" }, { source = "../debian/postinst", dest = "/usr/share/ffplayout/postinst", mode = "755" }, { source = "../debian/postrm", dest = "/usr/share/ffplayout/postrm", mode = "755" }, ] diff --git a/ffplayout-frontend b/ffplayout-frontend index 9832a5e1..c02141af 160000 --- a/ffplayout-frontend +++ b/ffplayout-frontend @@ -1 +1 @@ -Subproject commit 9832a5e12c4fc604b513a09d3a89c898d477e87d +Subproject commit c02141af54762961cf559248a3c9d42e9d317e0b diff --git a/scripts/build_all.sh b/scripts/build_all.sh index edd206e7..725376b1 100755 --- a/scripts/build_all.sh +++ b/scripts/build_all.sh @@ -26,7 +26,7 @@ for target in "${targets[@]}"; do cp ./target/${target}/release/ffpapi.exe . cp ./target/${target}/release/ffplayout.exe . - zip -r "ffplayout-v${version}_${target}.zip" assets docs LICENSE README.md ffplayout.exe ffpapi.exe -x *.db + zip -r "ffplayout-v${version}_${target}.zip" assets docs public LICENSE README.md ffplayout.exe ffpapi.exe -x *.db rm -f ffplayout.exe ffpapi.exe elif [[ $target == "x86_64-apple-darwin" ]] || [[ $target == "aarch64-apple-darwin" ]]; then if [[ -f "ffplayout-v${version}_${target}.tar.gz" ]]; then @@ -36,7 +36,7 @@ for target in "${targets[@]}"; do cargo build --release --target=$target --bin ffplayout cp ./target/${target}/release/ffplayout . - tar -czvf "ffplayout-v${version}_${target}.tar.gz" --exclude='*.db' assets docs LICENSE README.md ffplayout + tar -czvf "ffplayout-v${version}_${target}.tar.gz" --exclude='*.db' assets docs public LICENSE README.md ffplayout rm -f ffplayout else if [[ -f "ffplayout-v${version}_${target}.tar.gz" ]]; then @@ -47,33 +47,26 @@ for target in "${targets[@]}"; do cp ./target/${target}/release/ffpapi . cp ./target/${target}/release/ffplayout . - tar -czvf "ffplayout-v${version}_${target}.tar.gz" --exclude='*.db' assets docs LICENSE README.md ffplayout ffpapi + tar -czvf "ffplayout-v${version}_${target}.tar.gz" --exclude='*.db' assets docs public LICENSE README.md ffplayout ffpapi rm -f ffplayout ffpapi fi echo "" done - - - cd ffplayout-frontend npm install npm run build -yes | rm -rf public ../public.tar.gz -mv dist public -tar czf public.tar.gz public -mv public.tar.gz ../ -yes | rm -rf public +yes | rm -rf ../public +mv dist ../public cd .. cargo deb --target=x86_64-unknown-linux-musl -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_amd64.deb - cargo deb --target=aarch64-unknown-linux-gnu --variant=arm64 -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_arm64.deb -# cargo deb --target=armv7-unknown-linux-gnueabihf --variant=armhf -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_armhf.deb - -cargo generate-rpm --target=x86_64-unknown-linux-musl -p ffplayout-engine -o ffplayout-${version}-1.x86_64.rpm +cd ffplayout-engine +cargo generate-rpm --target=x86_64-unknown-linux-musl -o ../ffplayout-${version}-1.x86_64.rpm +cd .. From 717764c5869600570c6241f71054f275d43e2735 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 25 Jul 2022 21:36:00 +0200 Subject: [PATCH 5/8] log only in running state --- ffplayout-engine/src/output/hls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ffplayout-engine/src/output/hls.rs b/ffplayout-engine/src/output/hls.rs index c583625d..38315e26 100644 --- a/ffplayout-engine/src/output/hls.rs +++ b/ffplayout-engine/src/output/hls.rs @@ -109,8 +109,6 @@ fn ingest_to_hls_server( log_line(line, &level); } - info!("Switch from live ingest to {}", config.processing.mode); - proc_control .server_is_running .store(false, Ordering::SeqCst); @@ -122,6 +120,8 @@ fn ingest_to_hls_server( if proc_control.is_terminated.load(Ordering::SeqCst) { break; } + + info!("Switch from live ingest to {}", config.processing.mode); } Ok(()) From 76b33856365c05d0beb53752d38e7dd82fc59b26 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Tue, 26 Jul 2022 11:18:09 +0200 Subject: [PATCH 6/8] no speed change when seek in clip --- lib/src/filter/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/src/filter/mod.rs b/lib/src/filter/mod.rs index b4722b48..ade4edc5 100644 --- a/lib/src/filter/mod.rs +++ b/lib/src/filter/mod.rs @@ -275,18 +275,18 @@ fn realtime_filter( config: &PlayoutConfig, codec_type: &str, ) { - let mut t = ""; - - if codec_type == "audio" { - t = "a" - } - if config.general.generate.is_none() && &config.out.mode.to_lowercase() == "hls" { + let mut t = ""; + + if codec_type == "audio" { + t = "a" + } + let mut speed_filter = format!("{t}realtime=speed=1"); let (delta, _) = get_delta(config, &node.begin.unwrap()); - let duration = node.out - node.seek; - if delta < 0.0 { + if delta < 0.0 && node.seek == 0.0 { + let duration = node.out - node.seek; let speed = duration / (duration + delta); if speed > 0.0 && speed < 1.1 && delta < config.general.stop_threshold { From 95b4dccf8cea915dc1e9494d58c4f344eb3cc8fc Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Tue, 26 Jul 2022 11:18:25 +0200 Subject: [PATCH 7/8] add install.md --- README.md | 4 ++ assets/ffplayout.conf | 75 +++++++++++++++++++++++++++++++++++++ docs/install.md | 24 ++++++++++++ ffplayout-engine/Cargo.toml | 3 ++ 4 files changed, 106 insertions(+) create mode 100644 assets/ffplayout.conf create mode 100644 docs/install.md diff --git a/README.md b/README.md index ddb325c0..7f36e169 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,10 @@ ffpapi is an [REST API](/ffplayout-api/README.md) for controlling the engine, ma - **ffmpeg** v4.2+ and **ffprobe** (**ffplay** if you want to play on desktop) - if you want to overlay text, ffmpeg needs to have **libzmq** +### Install + +Check [install](docs/install.md) for details about how to install ffplayout. + ----- ### JSON Playlist Example diff --git a/assets/ffplayout.conf b/assets/ffplayout.conf new file mode 100644 index 00000000..90d2c12c --- /dev/null +++ b/assets/ffplayout.conf @@ -0,0 +1,75 @@ +server { + listen 80; + + server_name ffplayout.local; + + gzip on; + gzip_types text/plain application/xml text/css application/javascript; + gzip_min_length 1000; + + charset utf-8; + + client_max_body_size 7000M; # should be desirable value + + add_header X-Frame-Options SAMEORIGIN; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + location / { + if ($http_origin ~ '^https?://(localhost|ffplayout\.local)') { + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always; + } + + if ($request_method = OPTIONS ) { + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + + root /var/www/ffplayout-frontend/; + } + + location ~ ^/(api|auth) { + if ($http_origin ~ '^https?://(localhost|ffplayout\.local)') { + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always; + } + + add_header Last-Modified $date_gmt; + add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; + if_modified_since off; + expires off; + etag off; + + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 36000s; + proxy_connect_timeout 36000s; + proxy_send_timeout 36000s; + proxy_buffer_size 128k; + proxy_buffers 4 256k; + proxy_busy_buffers_size 256k; + send_timeout 36000s; + proxy_no_cache 1; + proxy_pass http://127.0.0.1:8000; + + } + + location /live/ { + alias /var/www/srs/live/; + } + + location /preview/stream.flv { + # HTTP-FLV preview + proxy_pass http://preview.local:8080/live/stream.flv; + } +} diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 00000000..03383c9d --- /dev/null +++ b/docs/install.md @@ -0,0 +1,24 @@ +### Install ffplayout + +ffplayout provides ***.deb** amd ***.rpm** packages, which makes it more easy to install and use, but there is still some steps to do. + +1. download the latest ffplayout from [release](https://github.com/ffplayout/ffplayout/releases/latest) page. +2. install it with `apt install /tmp/ffplayout__amd64.deb` +3. install ffmpeg/ffprobe, or compile and copy it to **/usr/local/bin/** +4. activate systemd services: + - `systemctl enable ffplayout` + - `systemctl enable --now ffpapi` +5. initialize sqlite database for ffpapi: + - `ffpapi -i` +6. add admin user to ffpapi: + - `ffpapi -a` +7. use a revers proxy for SSL, Port is **8787**. +8. login with your browser, address without proxy would be: **http://[IP ADDRESS]:8787** + +Default location for playlists and media files are: **/var/lib/ffplayout/**. If you need to change them, the media storage folder needs a symlink to **/usr/share/ffplayout/public/**. + +When you don't need the frontend and API, skip enable the systemd service **ffpapi**. + +When playlists are created and the ffplayout output is configured, you can start the process: `systemctl start ffplayout`, or click start in frontend. + +If you want to configure ffplayout over terminal, you can edit **/etc/ffplayout/ffplayout.yml**. diff --git a/ffplayout-engine/Cargo.toml b/ffplayout-engine/Cargo.toml index b2eb4f5c..dfcdceee 100644 --- a/ffplayout-engine/Cargo.toml +++ b/ffplayout-engine/Cargo.toml @@ -54,6 +54,7 @@ assets = [ ["../assets/ffplayout.yml", "/etc/ffplayout/", "644"], ["../assets/logo.png", "/usr/share/ffplayout/", "644"], ["../assets/ffplayout.yml", "/usr/share/ffplayout/ffplayout.yml.orig", "644"], + ["../assets/ffplayout.conf", "/usr/share/ffplayout/ffplayout.conf.example", "644"], ["../README.md", "/usr/share/doc/ffplayout/README", "644"], ["../public/**/*", "/usr/share/ffplayout/public/", "644"], ] @@ -75,6 +76,7 @@ assets = [ ["../assets/ffplayout.yml", "/etc/ffplayout/", "644"], ["../assets/logo.png", "/usr/share/ffplayout/", "644"], ["../assets/ffplayout.yml", "/usr/share/ffplayout/ffplayout.yml.orig", "644"], + ["../assets/ffplayout.conf", "/usr/share/ffplayout/ffplayout.conf.example", "644"], ["../README.md", "/usr/share/doc/ffplayout/README", "644"], ["../public/**/*", "/usr/share/ffplayout/public/", "644"], ] @@ -95,6 +97,7 @@ assets = [ { source = "../LICENSE", dest = "/usr/share/doc/ffplayout/LICENSE", mode = "644" }, { source = "../assets/logo.png", dest = "/usr/share/ffplayout/logo.png", mode = "644" }, { source = "../assets/ffplayout.yml", dest = "/usr/share/ffplayout/ffplayout.yml.orig", mode = "644" }, + { source = "../assets/ffplayout.conf", dest = "/usr/share/ffplayout/ffplayout.conf.example", mode = "644" }, { source = "../public/**/*", dest = "/usr/share/ffplayout/public/", mode = "644" }, { source = "../debian/postinst", dest = "/usr/share/ffplayout/postinst", mode = "755" }, { source = "../debian/postrm", dest = "/usr/share/ffplayout/postrm", mode = "755" }, From bf516b6ace0c245394afeb3281fb45a548f06838 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Tue, 26 Jul 2022 11:47:08 +0200 Subject: [PATCH 8/8] cargo fmt --- ffplayout-api/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ffplayout-api/src/main.rs b/ffplayout-api/src/main.rs index 7e910f38..12caee4e 100644 --- a/ffplayout-api/src/main.rs +++ b/ffplayout-api/src/main.rs @@ -40,11 +40,11 @@ async fn validator(req: ServiceRequest, credentials: BearerAuth) -> Result &'static str { if Path::new("/usr/share/ffplayout/public/").is_dir() { - return "/usr/share/ffplayout/public/" + return "/usr/share/ffplayout/public/"; } if Path::new("./public/").is_dir() { - return "./public/" + return "./public/"; } "./ffplayout-frontend/dist"