Merge pull request #166 from jb-alvarado/master

integrate frontend
This commit is contained in:
jb-alvarado 2022-07-26 12:03:42 +02:00 committed by GitHub
commit 4111a6f20a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 363 additions and 174 deletions

4
.gitignore vendored
View File

@ -19,5 +19,7 @@
*.deb
*.rpm
/assets/*.db*
/dist/
/public/
tmp/
.vscode/

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "ffplayout-frontend"]
path = ffplayout-frontend
url = git@github.com:ffplayout/ffplayout-frontend.git

119
Cargo.lock generated
View File

@ -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",

View File

@ -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,21 +46,25 @@ 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)
- 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
-----
### JSON Playlist Example
```json
{
@ -95,15 +97,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 +125,7 @@ out:
-----
JSON RPC
-----
## JSON RPC
The ffplayout engine can run a JSON RPC server. A request show look like:

View File

@ -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:8787
Restart=always
RestartSec=1
User=ffpu

75
assets/ffplayout.conf Normal file
View File

@ -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;
}
}

View File

@ -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

2
debian/postinst vendored
View File

@ -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

15
debian/postrm vendored Normal file
View File

@ -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

View File

@ -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": "<USER>", "password": "<PASS>" }'
```
**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 <TOKEN>'
```
**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": "<MAIL>", "password": "<PASS>"}' -H 'Authorization: <TOKEN>'
```
**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": "<MAIL>", "username": "<USER>", "password": "<PASS>", "role_id": 1, "channel_id": 1}' \
-H 'Authorization: Bearer <TOKEN>'
```
@ -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 <TOKEN>"
curl -X GET http://127.0.0.1:8787/api/channel/1 -H "Authorization: Bearer <TOKEN>"
```
**Response:**
@ -78,13 +78,13 @@ curl -X GET http://127.0.0.1:8000/api/channel/1 -H "Authorization: Bearer <TOKEN
**Get settings from all Channels**
```BASH
curl -X GET http://127.0.0.1:8000/api/channels -H "Authorization: Bearer <TOKEN>"
curl -X GET http://127.0.0.1:8787/api/channels -H "Authorization: Bearer <TOKEN>"
```
**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 <TOKEN>"
@ -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 <TOKEN>"
curl -X DELETE http://127.0.0.1:8787/api/channel/2 -H "Authorization: Bearer <TOKEN>"
```
#### ffplayout Config
@ -111,7 +111,7 @@ curl -X DELETE http://127.0.0.1:8000/api/channel/2 -H "Authorization: Bearer <TO
**Get Config**
```BASH
curl -X GET http://localhost:8000/api/playout/config/1 -H 'Authorization: <TOKEN>'
curl -X GET http://127.0.0.1:8787/api/playout/config/1 -H 'Authorization: <TOKEN>'
```
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 { <CONFIG DATA> } -H 'Authorization: <TOKEN>'
```
@ -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: <TOKEN>'
```
**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": "<PRESET NAME>", "text": "<TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
"line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \
-H 'Authorization: <TOKEN>'
@ -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": "<PRESET NAME>", "text": "TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
"line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \
-H 'Authorization: <TOKEN>'
@ -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: <TOKEN>'
```
@ -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: <TOKEN>' \
-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: <TOKEN>'
```
**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: <TOKEN>'
```
@ -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: <TOKEN>'
curl -X GET http://127.0.0.1:8787/api/control/1/media/next/ -H 'Authorization: <TOKEN>'
```
**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: <TOKEN>'
```
@ -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: <TOKEN>'
-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: <TOKEN>'
```
**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: <TOKEN>'
-- data "{<JSON playlist 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: <TOKEN>'
```
**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: <TOKEN>'
```
@ -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: <TOKEN>'
```
@ -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: <TOKEN>'
```
**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": "<FOLDER PATH>"}' -H 'Authorization: <TOKEN>'
```
**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": "<SOURCE>", "target": "<TARGET>"}' -H 'Authorization: <TOKEN>'
```
**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": "<SOURCE>"}' -H 'Authorization: <TOKEN>'
```
**Upload File**
```BASH
curl -X POST http://localhost:8000/api/file/1/upload/ -H 'Authorization: <TOKEN>'
curl -X POST http://127.0.0.1:8787/api/file/1/upload/ -H 'Authorization: <TOKEN>'
-F "file=@file.mp4"
```

24
docs/install.md Normal file
View File

@ -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_<VERSION>_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**.

View File

@ -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
```

View File

@ -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"

View File

@ -18,9 +18,11 @@ ffpapi -u <USERNAME> -p <PASSWORD> -m <MAIL ADDRESS>
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`.

View File

@ -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;
@ -37,6 +38,18 @@ async fn validator(req: ServiceRequest, credentials: BearerAuth) -> Result<Servi
Ok(req)
}
fn public_path() -> &'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();
@ -107,6 +120,7 @@ async fn main() -> std::io::Result<()> {
.service(remove)
.service(save_file),
)
.service(Files::new("/", public_path()).index_file("index.html"))
})
.bind((addr, port))?
.run()

View File

@ -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<String>,
#[clap(short, long, help = "Initialize Database")]

View File

@ -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": "<USER>", "password": "<PASS>" }'
/// ```
/// **Response:**
@ -141,7 +141,7 @@ pub async fn login(credentials: web::Json<User>) -> 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 <TOKEN>'
/// ```
#[get("/user")]
@ -159,7 +159,7 @@ async fn get_user(user: web::ReqData<LoginUser>) -> Result<impl Responder, Servi
/// **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": "<MAIL>", "password": "<PASS>"}' -H 'Authorization: <TOKEN>'
/// ```
#[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": "<MAIL>", "username": "<USER>", "password": "<PASS>", "role_id": 1, "channel_id": 1}' \
/// -H 'Authorization: Bearer <TOKEN>'
/// ```
@ -223,7 +223,7 @@ async fn add_user(data: web::Json<User>) -> Result<impl Responder, ServiceError>
/// **Get Settings from Channel**
///
/// ```BASH
/// curl -X GET http://127.0.0.1:8000/api/channel/1 -H "Authorization: Bearer <TOKEN>"
/// curl -X GET http://127.0.0.1:8787/api/channel/1 -H "Authorization: Bearer <TOKEN>"
/// ```
///
/// **Response:**
@ -252,7 +252,7 @@ async fn get_channel(id: web::Path<i64>) -> Result<impl Responder, ServiceError>
/// **Get settings from all Channels**
///
/// ```BASH
/// curl -X GET http://127.0.0.1:8000/api/channels -H "Authorization: Bearer <TOKEN>"
/// curl -X GET http://127.0.0.1:8787/api/channels -H "Authorization: Bearer <TOKEN>"
/// ```
#[get("/channels")]
#[has_any_role("Role::Admin", type = "Role")]
@ -267,7 +267,7 @@ async fn get_all_channels() -> Result<impl Responder, ServiceError> {
/// **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 <TOKEN>"
@ -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<Channel>) -> Result<impl Responder, Service
/// **Delete Channel**
///
/// ```BASH
/// curl -X DELETE http://127.0.0.1:8000/api/channel/2 -H "Authorization: Bearer <TOKEN>"
/// curl -X DELETE http://127.0.0.1:8787/api/channel/2 -H "Authorization: Bearer <TOKEN>"
/// ```
#[delete("/channel/{id}")]
#[has_any_role("Role::Admin", type = "Role")]
@ -323,7 +323,7 @@ async fn remove_channel(id: web::Path<i64>) -> Result<impl Responder, ServiceErr
/// **Get Config**
///
/// ```BASH
/// curl -X GET http://localhost:8000/api/playout/config/1 -H 'Authorization: <TOKEN>'
/// curl -X GET http://127.0.0.1:8787/api/playout/config/1 -H 'Authorization: <TOKEN>'
/// ```
///
/// 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 { <CONFIG DATA> } -H 'Authorization: <TOKEN>'
/// ```
#[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: <TOKEN>'
/// ```
#[get("/presets/{id}")]
@ -394,7 +394,7 @@ async fn get_presets(id: web::Path<i64>) -> Result<impl Responder, ServiceError>
/// **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": "<PRESET NAME>", "text": "<TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
/// "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \
/// -H 'Authorization: <TOKEN>'
@ -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": "<PRESET NAME>", "text": "TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
/// "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \
/// -H 'Authorization: <TOKEN>'
@ -433,7 +433,7 @@ async fn add_preset(data: web::Json<TextPreset>) -> Result<impl Responder, Servi
/// **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: <TOKEN>'
/// ```
#[delete("/presets/{id}")]
@ -457,7 +457,7 @@ async fn delete_preset(id: web::Path<i64>) -> Result<impl Responder, ServiceErro
/// **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: <TOKEN>' \
/// -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: <TOKEN>'
/// ```
#[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: <TOKEN>'
/// ```
///
@ -539,7 +539,7 @@ pub async fn media_current(id: web::Path<i64>) -> Result<impl Responder, Service
/// **Get next Clip**
///
/// ```BASH
/// curl -X GET http://localhost:8000/api/control/1/media/next/ -H 'Authorization: <TOKEN>'
/// curl -X GET http://127.0.0.1:8787/api/control/1/media/next/ -H 'Authorization: <TOKEN>'
/// ```
#[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<i64>) -> Result<impl Responder, ServiceErr
/// **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: <TOKEN>'
/// ```
#[get("/control/{id}/media/last")]
@ -574,7 +574,7 @@ pub async fn media_last(id: web::Path<i64>) -> Result<impl Responder, ServiceErr
/// - 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: <TOKEN>'
/// -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: <TOKEN>'
/// ```
#[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: <TOKEN>'
/// -- data "{<JSON playlist 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: <TOKEN>'
/// ```
#[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: <TOKEN>'
/// ```
#[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: <TOKEN>'
/// ```
#[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: <TOKEN>'
/// ```
#[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": "<FOLDER PATH>"}' -H 'Authorization: <TOKEN>'
/// ```
#[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": "<SOURCE>", "target": "<TARGET>"}' -H 'Authorization: <TOKEN>'
/// ```
#[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": "<SOURCE>"}' -H 'Authorization: <TOKEN>'
/// ```
#[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: <TOKEN>'
/// curl -X POST http://127.0.0.1:8787/api/file/1/upload/ -H 'Authorization: <TOKEN>'
/// -F "file=@file.mp4"
/// ```
#[put("/file/{id}/upload/")]

View File

@ -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]
@ -54,7 +54,9 @@ 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"],
]
maintainer-scripts = "../debian/"
systemd-units = { enable = false, unit-scripts = "../assets" }
@ -74,7 +76,9 @@ 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"],
]
# REHL RPM PACKAGE
@ -93,7 +97,11 @@ 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" },
]
auto-req = "no"
post_install_script = "/usr/share/ffplayout/postinst"
post_uninstall_script = "/usr/share/ffplayout/postrm"

View File

@ -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(())
@ -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));

View File

@ -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);

1
ffplayout-frontend Submodule

@ -0,0 +1 @@
Subproject commit c02141af54762961cf559248a3c9d42e9d317e0b

View File

@ -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]

View File

@ -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 {

View File

@ -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<Vec<String>>,
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,

View File

@ -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,18 +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
cargo deb --target=x86_64-unknown-linux-musl -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_amd64.deb
cd ffplayout-frontend
npm install
npm run build
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 ..