Merge pull request #159 from jb-alvarado/master
initial multi channel support
This commit is contained in:
commit
efdbf28874
63
Cargo.lock
generated
63
Cargo.lock
generated
@ -626,7 +626,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.20-beta.1"
|
||||
source = "git+https://github.com/chronotope/chrono.git#051e1170c41477ce162301c8711110a4577c1a23"
|
||||
source = "git+https://github.com/chronotope/chrono.git#187819ff43e0e4da351b3ea4ac2d3076e06e8251"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
@ -636,9 +636,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.8"
|
||||
version = "3.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
|
||||
checksum = "ab8b79fe3946ceb4a0b1c080b4018992b8d27e9ff363644c1c9b6387c854614d"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
@ -675,9 +675,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "1.2.2"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
|
||||
checksum = "83827793632c72fa4f73c2edb31e7a997527dd8ffe7077344621fc62c5478157"
|
||||
dependencies = [
|
||||
"cache-padded",
|
||||
]
|
||||
@ -880,9 +880,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ccfd8c0ee4cce11e45b3fd6f9d5e69e0cc62912aa6a0cb1bf4617b0eba5a12f"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
@ -1009,7 +1009,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ffplayout"
|
||||
version = "0.10.5"
|
||||
version = "0.11.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"crossbeam-channel 0.5.5",
|
||||
@ -1027,7 +1027,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ffplayout-api"
|
||||
version = "0.4.2"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"actix-multipart",
|
||||
"actix-web",
|
||||
@ -1056,7 +1056,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ffplayout-lib"
|
||||
version = "0.10.4"
|
||||
version = "0.10.5"
|
||||
dependencies = [
|
||||
"chrono 0.4.20-beta.1",
|
||||
"crossbeam-channel 0.5.5",
|
||||
@ -1135,7 +1135,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project",
|
||||
"spin 0.9.3",
|
||||
"spin 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1406,9 +1406,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
@ -1543,7 +1543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.2",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2084,9 +2084,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.1.0"
|
||||
version = "6.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
|
||||
|
||||
[[package]]
|
||||
name = "paris"
|
||||
@ -2167,9 +2167,9 @@ checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
|
||||
|
||||
[[package]]
|
||||
name = "pem"
|
||||
version = "1.0.2"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947"
|
||||
checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4"
|
||||
dependencies = [
|
||||
"base64",
|
||||
]
|
||||
@ -2548,18 +2548,18 @@ checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.138"
|
||||
version = "1.0.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
|
||||
checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.138"
|
||||
version = "1.0.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
|
||||
checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2591,9 +2591,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.25"
|
||||
version = "0.8.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ec0091e1f5aa338283ce049bd9dfefd55e1f168ac233e85c1ffe0038fb48cbe"
|
||||
checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"ryu",
|
||||
@ -2692,9 +2692,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d"
|
||||
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
@ -2932,10 +2932,11 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.19.2"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439"
|
||||
checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
@ -3070,9 +3071,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
@ -3391,7 +3392,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "zeromq"
|
||||
version = "0.3.3"
|
||||
source = "git+https://github.com/zeromq/zmq.rs.git#9e0eb7c16950146d285d952939ea8d5a5fc812c9"
|
||||
source = "git+https://github.com/zeromq/zmq.rs.git#c7cbd1c0d589c9d671626c7fa5ba26843c0ab219"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-trait",
|
||||
|
@ -1,3 +1,5 @@
|
||||
# give user www-data permission to control the ffplayout systemd service
|
||||
# give user ffpu permission to control the ffplayout systemd service
|
||||
|
||||
www-data ALL = NOPASSWD: /bin/systemctl start ffplayout.service, /bin/systemctl stop ffplayout.service, /bin/systemctl reload ffplayout.service, /bin/systemctl restart ffplayout.service, /bin/systemctl status ffplayout.service, /bin/systemctl is-active ffplayout.service
|
||||
ffpu ALL = NOPASSWD: /usr/bin/systemctl start ffplayout.service, /usr/bin/systemctl stop ffplayout.service, /usr/bin/systemctl restart ffplayout.service, /usr/bin/systemctl status ffplayout.service, /usr/bin/systemctl is-active ffplayout.service, /usr/bin/systemctl enable ffplayout.service, /usr/bin/systemctl disable ffplayout.service
|
||||
|
||||
ffpu ALL = NOPASSWD: /usr/bin/systemctl start ffplayout@*, /usr/bin/systemctl stop ffplayout@*, /usr/bin/systemctl restart ffplayout@*, /usr/bin/systemctl status ffplayout@*, /usr/bin/systemctl is-active ffplayout@*, /usr/bin/systemctl enable ffplayout@*, /usr/bin/systemctl disable ffplayout@*
|
||||
|
@ -6,8 +6,8 @@ After=network.target remote-fs.target
|
||||
ExecStart=/usr/bin/ffpapi -l 127.0.0.1:8000
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
User=www-data
|
||||
Group=www-data
|
||||
User=ffpu
|
||||
Group=ffpu
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
@ -7,8 +7,8 @@ ExecStart=/usr/bin/ffplayout
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
KillMode=mixed
|
||||
User=www-data
|
||||
Group=www-data
|
||||
User=ffpu
|
||||
Group=ffpu
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
@ -85,7 +85,7 @@ playlist:
|
||||
should always start at the begin. 'length' represent the target length from
|
||||
playlist, when is blank real length will not consider. 'infinit true' works with
|
||||
single playlist file and loops it infinitely.
|
||||
path: /playlists
|
||||
path: /var/lib/ffplayout/playlists
|
||||
day_start: "5:59:25"
|
||||
length: "24:00:00"
|
||||
infinit: false
|
||||
@ -94,8 +94,8 @@ storage:
|
||||
help_text: Play ordered or randomly files from path. 'filler_clip' is for fill
|
||||
the end to reach 24 hours, it will loop when is necessary. 'extensions' search
|
||||
only files with this extension. Set 'shuffle' to 'True' to pick files randomly.
|
||||
path: "/mediaStorage"
|
||||
filler_clip: "/mediaStorage/filler/filler.mp4"
|
||||
path: "/var/lib/ffplayout/tv-media"
|
||||
filler_clip: "/var/lib/ffplayout/tv-media/filler/filler.mp4"
|
||||
extensions:
|
||||
- "mp4"
|
||||
- "mkv"
|
||||
|
14
assets/ffplayout@.service
Normal file
14
assets/ffplayout@.service
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Rust and ffmpeg based multi channel playout solution
|
||||
After=network.target remote-fs.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/ffplayout %I
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
KillMode=mixed
|
||||
User=ffpu
|
||||
Group=ffpu
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
28
debian/postinst
vendored
28
debian/postinst
vendored
@ -1,27 +1,25 @@
|
||||
#DEBHELPER#
|
||||
|
||||
sysUser="ffpu"
|
||||
|
||||
if ! id $sysUser &>/dev/null; then
|
||||
adduser --system $sysUser
|
||||
fi
|
||||
|
||||
if [ ! -d "/usr/share/ffplayout/db" ]; then
|
||||
mkdir "/usr/share/ffplayout/db"
|
||||
chmod 777 "/usr/share/ffplayout/db"
|
||||
mkdir "/var/lib/ffplayout/playlists"
|
||||
mkdir "/var/lib/ffplayout/tv-media"
|
||||
|
||||
/usr/bin/ffpapi -i
|
||||
|
||||
if id "www-data" &>/dev/null; then
|
||||
chown www-data. "/usr/share/ffplayout/db/ffplayout.db"
|
||||
else
|
||||
sed -i "s|www-data|root|g" /lib/systemd/system/ffpapi.service
|
||||
sed -i "s|www-data|root|g" /lib/systemd/system/ffplayout.service
|
||||
rm -f /etc/sudoers.d/11-ffplayout
|
||||
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
chown -R ${sysUser}. "/usr/share/ffplayout"
|
||||
chown -R ${sysUser}. "/var/lib/ffplayout"
|
||||
chown -R ${sysUser}. "/etc/ffplayout"
|
||||
fi
|
||||
|
||||
if [ ! -d "/var/log/ffplayout" ]; then
|
||||
mkdir /var/log/ffplayout
|
||||
mkdir "/var/log/ffplayout"
|
||||
|
||||
if id "www-data" &>/dev/null; then
|
||||
chown www-data. /var/log/ffplayout
|
||||
chown -R www-data. /etc/ffplayout
|
||||
fi
|
||||
chown ${sysUser}. "/var/log/ffplayout"
|
||||
fi
|
||||
|
35
docs/api.md
35
docs/api.md
@ -55,10 +55,10 @@ curl -X POST 'http://localhost:8000/api/user/' -H 'Content-Type: application/jso
|
||||
|
||||
#### ffpapi Settings
|
||||
|
||||
**Get Settings**
|
||||
**Get Settings from Channel**
|
||||
|
||||
```BASH
|
||||
curl -X GET http://127.0.0.1:8000/api/settings/1 -H "Authorization: Bearer <TOKEN>"
|
||||
curl -X GET http://127.0.0.1:8000/api/channel/1 -H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
@ -66,7 +66,7 @@ curl -X GET http://127.0.0.1:8000/api/settings/1 -H "Authorization: Bearer <TOKE
|
||||
```JSON
|
||||
{
|
||||
"id": 1,
|
||||
"channel_name": "Channel 1",
|
||||
"name": "Channel 1",
|
||||
"preview_url": "http://localhost/live/preview.m3u8",
|
||||
"config_path": "/etc/ffplayout/ffplayout.yml",
|
||||
"extra_extensions": "jpg,jpeg,png",
|
||||
@ -75,22 +75,37 @@ curl -X GET http://127.0.0.1:8000/api/settings/1 -H "Authorization: Bearer <TOKE
|
||||
}
|
||||
```
|
||||
|
||||
**Get all Settings**
|
||||
**Get settings from all Channels**
|
||||
|
||||
```BASH
|
||||
curl -X GET http://127.0.0.1:8000/api/settings -H "Authorization: Bearer <TOKEN>"
|
||||
curl -X GET http://127.0.0.1:8000/api/channels -H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
**Update Settings**
|
||||
**Update Channel**
|
||||
|
||||
```BASH
|
||||
curl -X PATCH http://127.0.0.1:8000/api/settings/1 -H "Content-Type: application/json" \
|
||||
-d '{ "id": 1, "channel_name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \
|
||||
"config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png",
|
||||
"role_id": 1, "channel_id": 1 }' \
|
||||
curl -X PATCH http://127.0.0.1:8000/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>"
|
||||
```
|
||||
|
||||
**Create new Channel**
|
||||
|
||||
```BASH
|
||||
curl -X POST http://127.0.0.1:8000/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" }' \
|
||||
-H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
**Delete Channel**
|
||||
|
||||
```BASH
|
||||
curl -X DELETE http://127.0.0.1:8000/api/channel/2 -H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
#### ffplayout Config
|
||||
|
||||
**Get Config**
|
||||
|
@ -4,7 +4,7 @@ description = "Rest API for ffplayout"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Jonathan Baecker jonbae77@gmail.com"]
|
||||
readme = "README.md"
|
||||
version = "0.4.2"
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -15,11 +15,11 @@ use utils::{
|
||||
auth, db_path, init_config,
|
||||
models::LoginUser,
|
||||
routes::{
|
||||
add_dir, add_preset, add_user, control_playout, del_playlist, delete_preset, file_browser,
|
||||
gen_playlist, get_all_settings, get_log, get_playlist, get_playout_config, get_presets,
|
||||
get_settings, get_user, login, media_current, media_last, media_next, move_rename,
|
||||
patch_settings, process_control, remove, save_file, save_playlist, send_text_message,
|
||||
update_playout_config, update_preset, update_user,
|
||||
add_channel, add_dir, add_preset, add_user, control_playout, del_playlist, delete_preset,
|
||||
file_browser, gen_playlist, get_all_channels, get_channel, get_log, get_playlist,
|
||||
get_playout_config, get_presets, get_user, login, media_current, media_last, media_next,
|
||||
move_rename, patch_channel, process_control, remove, remove_channel, save_file,
|
||||
save_playlist, send_text_message, update_playout_config, update_preset, update_user,
|
||||
},
|
||||
run_args, Role,
|
||||
};
|
||||
@ -84,9 +84,11 @@ async fn main() -> std::io::Result<()> {
|
||||
.service(get_presets)
|
||||
.service(update_preset)
|
||||
.service(delete_preset)
|
||||
.service(get_settings)
|
||||
.service(get_all_settings)
|
||||
.service(patch_settings)
|
||||
.service(get_channel)
|
||||
.service(get_all_channels)
|
||||
.service(patch_channel)
|
||||
.service(add_channel)
|
||||
.service(remove_channel)
|
||||
.service(update_user)
|
||||
.service(send_text_message)
|
||||
.service(control_playout)
|
||||
|
44
ffplayout-api/src/utils/channels.rs
Normal file
44
ffplayout-api/src/utils/channels.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use std::fs;
|
||||
|
||||
use simplelog::*;
|
||||
|
||||
use crate::utils::{
|
||||
control::control_service,
|
||||
errors::ServiceError,
|
||||
handles::{db_add_channel, db_delete_channel, db_get_channel},
|
||||
models::Channel,
|
||||
};
|
||||
|
||||
pub async fn create_channel(target_channel: Channel) -> Result<Channel, ServiceError> {
|
||||
if !target_channel.service.starts_with("ffplayout@") {
|
||||
return Err(ServiceError::BadRequest("Bad service name!".to_string()));
|
||||
}
|
||||
|
||||
if !target_channel.config_path.starts_with("/etc/ffplayout") {
|
||||
return Err(ServiceError::BadRequest("Bad config path!".to_string()));
|
||||
}
|
||||
|
||||
fs::copy(
|
||||
"/usr/share/ffplayout/ffplayout.yml.orig",
|
||||
&target_channel.config_path,
|
||||
)?;
|
||||
|
||||
let new_channel = db_add_channel(target_channel).await?;
|
||||
control_service(new_channel.id, "enable").await?;
|
||||
|
||||
Ok(new_channel)
|
||||
}
|
||||
|
||||
pub async fn delete_channel(id: i64) -> Result<(), ServiceError> {
|
||||
let channel = db_get_channel(&id).await?;
|
||||
control_service(channel.id, "stop").await?;
|
||||
control_service(channel.id, "disable").await?;
|
||||
|
||||
if let Err(e) = fs::remove_file(channel.config_path) {
|
||||
error!("{e}");
|
||||
};
|
||||
|
||||
db_delete_channel(&id).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -7,7 +7,7 @@ use reqwest::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use simplelog::*;
|
||||
|
||||
use crate::utils::{errors::ServiceError, handles::db_get_settings, playout_config};
|
||||
use crate::utils::{errors::ServiceError, handles::db_get_channel, playout_config};
|
||||
use ffplayout_lib::vec_strings;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
@ -57,14 +57,32 @@ struct SystemD {
|
||||
|
||||
impl SystemD {
|
||||
async fn new(id: i64) -> Result<Self, ServiceError> {
|
||||
let settings = db_get_settings(&id).await?;
|
||||
let channel = db_get_channel(&id).await?;
|
||||
|
||||
Ok(Self {
|
||||
service: settings.service,
|
||||
cmd: vec_strings!["systemctl"],
|
||||
service: channel.service,
|
||||
cmd: vec_strings!["/usr/bin/systemctl"],
|
||||
})
|
||||
}
|
||||
|
||||
fn enable(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd
|
||||
.append(&mut vec!["enable".to_string(), self.service]);
|
||||
|
||||
Command::new("sudo").args(self.cmd).spawn()?;
|
||||
|
||||
Ok("Success".to_string())
|
||||
}
|
||||
|
||||
fn disable(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd
|
||||
.append(&mut vec!["disable".to_string(), self.service]);
|
||||
|
||||
Command::new("sudo").args(self.cmd).spawn()?;
|
||||
|
||||
Ok("Success".to_string())
|
||||
}
|
||||
|
||||
fn start(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd
|
||||
.append(&mut vec!["start".to_string(), self.service]);
|
||||
@ -167,6 +185,8 @@ pub async fn control_service(id: i64, command: &str) -> Result<String, ServiceEr
|
||||
let system_d = SystemD::new(id).await?;
|
||||
|
||||
match command {
|
||||
"enable" => system_d.enable(),
|
||||
"disable" => system_d.disable(),
|
||||
"start" => system_d.start(),
|
||||
"stop" => system_d.stop(),
|
||||
"restart" => system_d.restart(),
|
||||
|
@ -9,7 +9,7 @@ use sqlx::{migrate::MigrateDatabase, sqlite::SqliteQueryResult, Pool, Sqlite, Sq
|
||||
|
||||
use crate::utils::{
|
||||
db_path,
|
||||
models::{Settings, TextPreset, User},
|
||||
models::{Channel, TextPreset, User},
|
||||
GlobalSettings,
|
||||
};
|
||||
|
||||
@ -33,16 +33,16 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
name TEXT NOT NULL,
|
||||
UNIQUE(name)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS settings
|
||||
CREATE TABLE IF NOT EXISTS channels
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
channel_name TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
preview_url TEXT NOT NULL,
|
||||
config_path TEXT NOT NULL,
|
||||
extra_extensions TEXT NOT NULL,
|
||||
timezone TEXT NOT NULL,
|
||||
service TEXT NOT NULL,
|
||||
UNIQUE(channel_name)
|
||||
UNIQUE(name, service)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS presets
|
||||
(
|
||||
@ -59,7 +59,7 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
boxborderw TEXT NOT NULL,
|
||||
alpha TEXT NOT NULL,
|
||||
channel_id INTEGER NOT NULL DEFAULT 1,
|
||||
FOREIGN KEY (channel_id) REFERENCES settings (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
FOREIGN KEY (channel_id) REFERENCES channels (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
UNIQUE(name)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS user
|
||||
@ -72,7 +72,7 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
role_id INTEGER NOT NULL DEFAULT 2,
|
||||
channel_id INTEGER NOT NULL DEFAULT 1,
|
||||
FOREIGN KEY (role_id) REFERENCES roles (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
FOREIGN KEY (channel_id) REFERENCES settings (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
FOREIGN KEY (channel_id) REFERENCES channels (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
UNIQUE(mail, username)
|
||||
);";
|
||||
let result = sqlx::query(query).execute(&conn).await;
|
||||
@ -111,7 +111,7 @@ pub async fn db_init(domain: Option<String>) -> Result<&'static str, Box<dyn std
|
||||
SELECT RAISE(FAIL, 'Database is already initialized!');
|
||||
END;
|
||||
INSERT INTO global(secret) VALUES($1);
|
||||
INSERT INTO settings(channel_name, preview_url, config_path, extra_extensions, timezone, service)
|
||||
INSERT INTO channels(name, preview_url, config_path, extra_extensions, timezone, service)
|
||||
VALUES('Channel 1', $2, '/etc/ffplayout/ffplayout.yml', 'jpg,jpeg,png', 'UTC', 'ffplayout.service');
|
||||
INSERT INTO roles(name) VALUES('admin'), ('user'), ('guest');
|
||||
INSERT INTO presets(name, text, x, y, fontsize, line_spacing, fontcolor, box, boxcolor, boxborderw, alpha, channel_id)
|
||||
@ -147,37 +147,38 @@ pub async fn db_global() -> Result<GlobalSettings, sqlx::Error> {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_get_settings(id: &i64) -> Result<Settings, sqlx::Error> {
|
||||
pub async fn db_get_channel(id: &i64) -> Result<Channel, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
let query = "SELECT * FROM settings WHERE id = $1";
|
||||
let result: Settings = sqlx::query_as(query).bind(id).fetch_one(&conn).await?;
|
||||
let query = "SELECT * FROM channels WHERE id = $1";
|
||||
let result: Channel = sqlx::query_as(query).bind(id).fetch_one(&conn).await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_get_all_settings() -> Result<Vec<Settings>, sqlx::Error> {
|
||||
pub async fn db_get_all_channels() -> Result<Vec<Channel>, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
let query = "SELECT * FROM settings";
|
||||
let result: Vec<Settings> = sqlx::query_as(query).fetch_all(&conn).await?;
|
||||
let query = "SELECT * FROM channels";
|
||||
let result: Vec<Channel> = sqlx::query_as(query).fetch_all(&conn).await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_update_settings(
|
||||
pub async fn db_update_channel(
|
||||
id: i64,
|
||||
settings: Settings,
|
||||
channel: Channel,
|
||||
) -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
|
||||
let query = "UPDATE settings SET channel_name = $2, preview_url = $3, config_path = $4, extra_extensions = $5 WHERE id = $1";
|
||||
let query = "UPDATE channels SET name = $2, preview_url = $3, config_path = $4, extra_extensions = $5, timezone = $6 WHERE id = $1";
|
||||
let result: SqliteQueryResult = sqlx::query(query)
|
||||
.bind(id)
|
||||
.bind(settings.channel_name.clone())
|
||||
.bind(settings.preview_url.clone())
|
||||
.bind(settings.config_path.clone())
|
||||
.bind(settings.extra_extensions.clone())
|
||||
.bind(channel.name)
|
||||
.bind(channel.preview_url)
|
||||
.bind(channel.config_path)
|
||||
.bind(channel.extra_extensions)
|
||||
.bind(channel.timezone)
|
||||
.execute(&conn)
|
||||
.await?;
|
||||
conn.close().await;
|
||||
@ -185,6 +186,38 @@ pub async fn db_update_settings(
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_add_channel(channel: Channel) -> Result<Channel, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
|
||||
let query = "INSERT INTO channels (name, preview_url, config_path, extra_extensions, timezone, service) VALUES($1, $2, $3, $4, $5, $6)";
|
||||
let result = sqlx::query(query)
|
||||
.bind(channel.name)
|
||||
.bind(channel.preview_url)
|
||||
.bind(channel.config_path)
|
||||
.bind(channel.extra_extensions)
|
||||
.bind(channel.timezone)
|
||||
.bind(channel.service)
|
||||
.execute(&conn)
|
||||
.await?;
|
||||
let new_channel: Channel = sqlx::query_as("SELECT * FROM channels WHERE id = $1")
|
||||
.bind(result.last_insert_rowid())
|
||||
.fetch_one(&conn)
|
||||
.await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(new_channel)
|
||||
}
|
||||
|
||||
pub async fn db_delete_channel(id: &i64) -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
|
||||
let query = "DELETE FROM channels WHERE id = $1";
|
||||
let result: SqliteQueryResult = sqlx::query(query).bind(id).execute(&conn).await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_role(id: &i64) -> Result<String, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
let query = "SELECT name FROM roles WHERE id = $1";
|
||||
|
@ -12,6 +12,7 @@ use simplelog::*;
|
||||
|
||||
pub mod args_parse;
|
||||
pub mod auth;
|
||||
pub mod channels;
|
||||
pub mod control;
|
||||
pub mod errors;
|
||||
pub mod files;
|
||||
@ -23,8 +24,8 @@ pub mod routes;
|
||||
use crate::utils::{
|
||||
args_parse::Args,
|
||||
errors::ServiceError,
|
||||
handles::{db_add_user, db_get_settings, db_global, db_init},
|
||||
models::{Settings, User},
|
||||
handles::{db_add_user, db_get_channel, db_global, db_init},
|
||||
models::{Channel, User},
|
||||
};
|
||||
use ffplayout_lib::utils::PlayoutConfig;
|
||||
|
||||
@ -183,10 +184,10 @@ pub fn read_playout_config(path: &str) -> Result<PlayoutConfig, Box<dyn Error>>
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub async fn playout_config(channel_id: &i64) -> Result<(PlayoutConfig, Settings), ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(channel_id).await {
|
||||
if let Ok(config) = read_playout_config(&settings.config_path.clone()) {
|
||||
return Ok((config, settings));
|
||||
pub async fn playout_config(channel_id: &i64) -> Result<(PlayoutConfig, Channel), ServiceError> {
|
||||
if let Ok(channel) = db_get_channel(channel_id).await {
|
||||
if let Ok(config) = read_playout_config(&channel.config_path.clone()) {
|
||||
return Ok((config, channel));
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,7 +197,7 @@ pub async fn playout_config(channel_id: &i64) -> Result<(PlayoutConfig, Settings
|
||||
}
|
||||
|
||||
pub async fn read_log_file(channel_id: &i64, date: &str) -> Result<String, ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(channel_id).await {
|
||||
if let Ok(channel) = db_get_channel(channel_id).await {
|
||||
let mut date_str = "".to_string();
|
||||
|
||||
if !date.is_empty() {
|
||||
@ -204,7 +205,7 @@ pub async fn read_log_file(channel_id: &i64, date: &str) -> Result<String, Servi
|
||||
date_str.push_str(date);
|
||||
}
|
||||
|
||||
if let Ok(config) = read_playout_config(&settings.config_path) {
|
||||
if let Ok(config) = read_playout_config(&channel.config_path) {
|
||||
let mut log_path = Path::new(&config.logging.log_path)
|
||||
.join("ffplayout.log")
|
||||
.display()
|
||||
|
@ -59,16 +59,13 @@ pub struct TextPreset {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
|
||||
pub struct Settings {
|
||||
pub struct Channel {
|
||||
#[serde(skip_deserializing)]
|
||||
pub id: i64,
|
||||
pub channel_name: String,
|
||||
pub name: String,
|
||||
pub preview_url: String,
|
||||
pub config_path: String,
|
||||
pub extra_extensions: String,
|
||||
pub timezone: String,
|
||||
#[sqlx(default)]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub secret: String,
|
||||
pub service: String,
|
||||
}
|
||||
|
@ -75,10 +75,10 @@ pub async fn write_playlist(id: i64, json_data: JsonPlaylist) -> Result<String,
|
||||
}
|
||||
|
||||
pub async fn generate_playlist(id: i64, date: String) -> Result<JsonPlaylist, ServiceError> {
|
||||
let (mut config, settings) = playout_config(&id).await?;
|
||||
let (mut config, channel) = playout_config(&id).await?;
|
||||
config.general.generate = Some(vec![date.clone()]);
|
||||
|
||||
match playlist_generator(&config, Some(settings.channel_name)) {
|
||||
match playlist_generator(&config, Some(channel.name)) {
|
||||
Ok(playlists) => {
|
||||
if !playlists.is_empty() {
|
||||
Ok(playlists[0].clone())
|
||||
|
@ -22,6 +22,7 @@ use simplelog::*;
|
||||
|
||||
use crate::utils::{
|
||||
auth::{create_jwt, Claims},
|
||||
channels::{create_channel, delete_channel},
|
||||
control::{control_service, control_state, media_info, send_message, Process},
|
||||
errors::ServiceError,
|
||||
files::{
|
||||
@ -29,11 +30,11 @@ use crate::utils::{
|
||||
PathObject,
|
||||
},
|
||||
handles::{
|
||||
db_add_preset, db_add_user, db_delete_preset, db_get_all_settings, db_get_presets,
|
||||
db_get_settings, db_get_user, db_login, db_role, db_update_preset, db_update_settings,
|
||||
db_add_preset, db_add_user, db_delete_preset, db_get_all_channels, db_get_channel,
|
||||
db_get_presets, db_get_user, db_login, db_role, db_update_channel, db_update_preset,
|
||||
db_update_user,
|
||||
},
|
||||
models::{LoginUser, Settings, TextPreset, User},
|
||||
models::{Channel, LoginUser, TextPreset, User},
|
||||
playlist::{delete_playlist, generate_playlist, read_playlist, write_playlist},
|
||||
read_log_file, read_playout_config, Role,
|
||||
};
|
||||
@ -219,10 +220,10 @@ async fn add_user(data: web::Json<User>) -> Result<impl Responder, ServiceError>
|
||||
|
||||
/// #### ffpapi Settings
|
||||
///
|
||||
/// **Get Settings**
|
||||
/// **Get Settings from Channel**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X GET http://127.0.0.1:8000/api/settings/1 -H "Authorization: Bearer <TOKEN>"
|
||||
/// curl -X GET http://127.0.0.1:8000/api/channel/1 -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
///
|
||||
/// **Response:**
|
||||
@ -230,7 +231,7 @@ async fn add_user(data: web::Json<User>) -> Result<impl Responder, ServiceError>
|
||||
/// ```JSON
|
||||
/// {
|
||||
/// "id": 1,
|
||||
/// "channel_name": "Channel 1",
|
||||
/// "name": "Channel 1",
|
||||
/// "preview_url": "http://localhost/live/preview.m3u8",
|
||||
/// "config_path": "/etc/ffplayout/ffplayout.yml",
|
||||
/// "extra_extensions": "jpg,jpeg,png",
|
||||
@ -238,53 +239,85 @@ async fn add_user(data: web::Json<User>) -> Result<impl Responder, ServiceError>
|
||||
/// "service": "ffplayout.service"
|
||||
/// }
|
||||
/// ```
|
||||
#[get("/settings/{id}")]
|
||||
#[get("/channel/{id}")]
|
||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||
async fn get_settings(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(&id).await {
|
||||
return Ok(web::Json(settings));
|
||||
async fn get_channel(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(channel) = db_get_channel(&id).await {
|
||||
return Ok(web::Json(channel));
|
||||
}
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
||||
|
||||
/// **Get all Settings**
|
||||
/// **Get settings from all Channels**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X GET http://127.0.0.1:8000/api/settings -H "Authorization: Bearer <TOKEN>"
|
||||
/// curl -X GET http://127.0.0.1:8000/api/channels -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
#[get("/settings")]
|
||||
#[get("/channels")]
|
||||
#[has_any_role("Role::Admin", type = "Role")]
|
||||
async fn get_all_settings() -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(settings) = db_get_all_settings().await {
|
||||
return Ok(web::Json(settings));
|
||||
async fn get_all_channels() -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(channel) = db_get_all_channels().await {
|
||||
return Ok(web::Json(channel));
|
||||
}
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
||||
|
||||
/// **Update Settings**
|
||||
/// **Update Channel**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X PATCH http://127.0.0.1:8000/api/settings/1 -H "Content-Type: application/json" \
|
||||
/// -d '{ "id": 1, "channel_name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \
|
||||
/// "config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png",
|
||||
/// "role_id": 1, "channel_id": 1 }' \
|
||||
/// curl -X PATCH http://127.0.0.1:8000/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>"
|
||||
/// ```
|
||||
#[patch("/settings/{id}")]
|
||||
#[patch("/channel/{id}")]
|
||||
#[has_any_role("Role::Admin", type = "Role")]
|
||||
async fn patch_settings(
|
||||
async fn patch_channel(
|
||||
id: web::Path<i64>,
|
||||
data: web::Json<Settings>,
|
||||
data: web::Json<Channel>,
|
||||
) -> Result<impl Responder, ServiceError> {
|
||||
if db_update_settings(*id, data.into_inner()).await.is_ok() {
|
||||
if db_update_channel(*id, data.into_inner()).await.is_ok() {
|
||||
return Ok("Update Success");
|
||||
};
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
||||
|
||||
/// **Create new Channel**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X POST http://127.0.0.1:8000/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" }' \
|
||||
/// -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
#[post("/channel/")]
|
||||
#[has_any_role("Role::Admin", type = "Role")]
|
||||
async fn add_channel(data: web::Json<Channel>) -> Result<impl Responder, ServiceError> {
|
||||
match create_channel(data.into_inner()).await {
|
||||
Ok(c) => Ok(web::Json(c)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// **Delete Channel**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X DELETE http://127.0.0.1:8000/api/channel/2 -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
#[delete("/channel/{id}")]
|
||||
#[has_any_role("Role::Admin", type = "Role")]
|
||||
async fn remove_channel(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||
if delete_channel(*id).await.is_ok() {
|
||||
return Ok("Delete Channel Success");
|
||||
}
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
||||
|
||||
/// #### ffplayout Config
|
||||
///
|
||||
/// **Get Config**
|
||||
@ -300,8 +333,8 @@ async fn get_playout_config(
|
||||
id: web::Path<i64>,
|
||||
_details: AuthDetails<Role>,
|
||||
) -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(&id).await {
|
||||
if let Ok(config) = read_playout_config(&settings.config_path) {
|
||||
if let Ok(channel) = db_get_channel(&id).await {
|
||||
if let Ok(config) = read_playout_config(&channel.config_path) {
|
||||
return Ok(web::Json(config));
|
||||
}
|
||||
};
|
||||
@ -321,11 +354,11 @@ async fn update_playout_config(
|
||||
id: web::Path<i64>,
|
||||
data: web::Json<PlayoutConfig>,
|
||||
) -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(&id).await {
|
||||
if let Ok(channel) = db_get_channel(&id).await {
|
||||
if let Ok(f) = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&settings.config_path)
|
||||
.open(&channel.config_path)
|
||||
{
|
||||
serde_yaml::to_writer(f, &data).unwrap();
|
||||
|
||||
|
@ -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.10.5"
|
||||
version = "0.11.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@ -48,9 +48,11 @@ assets = [
|
||||
"755"
|
||||
],
|
||||
["../assets/ffpapi.service", "/lib/systemd/system/", "644"],
|
||||
["../assets/ffplayout@.service", "/lib/systemd/system/", "644"],
|
||||
["../assets/11-ffplayout", "/etc/sudoers.d/", "644"],
|
||||
["../assets/ffplayout.yml", "/etc/ffplayout/", "644"],
|
||||
["../assets/logo.png", "/usr/share/ffplayout/", "644"],
|
||||
["../assets/ffplayout.yml", "/usr/share/ffplayout/ffplayout.yml.orig", "644"],
|
||||
["../README.md", "/usr/share/doc/ffplayout/README", "644"],
|
||||
]
|
||||
maintainer-scripts = "../debian/"
|
||||
@ -66,10 +68,12 @@ assets = [
|
||||
{ source = "../assets/ffplayout.yml", dest = "/etc/ffplayout/ffplayout.yml", mode = "644", config = true },
|
||||
{ source = "../assets/ffpapi.service", dest = "/lib/systemd/system/ffpapi.service", mode = "644" },
|
||||
{ source = "../assets/ffplayout.service", dest = "/lib/systemd/system/ffplayout.service", mode = "644" },
|
||||
{ source = "../assets/ffplayout@.service", dest = "/lib/systemd/system/ffplayout@.service", mode = "644" },
|
||||
{ source = "../assets/11-ffplayout", dest = "/etc/sudoers.d/11-ffplayout", mode = "644" },
|
||||
{ source = "../README.md", dest = "/usr/share/doc/ffplayout/README", mode = "644", doc = true },
|
||||
{ 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 = "../debian/postinst", dest = "/usr/share/ffplayout/postinst", mode = "755" },
|
||||
]
|
||||
auto-req = "no"
|
||||
|
@ -6,6 +6,9 @@ use clap::Parser;
|
||||
override_usage = "Run without any command to use config file only, or with commands to override parameters:\n\n ffplayout [OPTIONS]",
|
||||
long_about = None)]
|
||||
pub struct Args {
|
||||
#[clap(index = 1, value_parser)]
|
||||
pub channel: Option<String>,
|
||||
|
||||
#[clap(short, long, help = "File path to ffplayout.yml")]
|
||||
pub config: Option<String>,
|
||||
|
||||
@ -15,7 +18,7 @@ pub struct Args {
|
||||
#[clap(
|
||||
short,
|
||||
long,
|
||||
help = "Generate playlist for date or date-range, like: 2022-01-01 - 2022-01-10",
|
||||
help = "Generate playlist for dates, like: 2022-01-01 - 2022-01-10",
|
||||
name = "YYYY-MM-DD",
|
||||
multiple_values = true
|
||||
)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub mod arg_parse;
|
||||
|
||||
@ -6,7 +6,20 @@ pub use arg_parse::Args;
|
||||
use ffplayout_lib::utils::{time_to_sec, PlayoutConfig};
|
||||
|
||||
pub fn get_config(args: Args) -> PlayoutConfig {
|
||||
let mut config = PlayoutConfig::new(args.config);
|
||||
let cfg_path = match args.channel {
|
||||
Some(c) => {
|
||||
let path = PathBuf::from(format!("/etc/ffplayout/{c}.yml"));
|
||||
|
||||
if path.is_file() {
|
||||
Some(path.display().to_string())
|
||||
} else {
|
||||
println!("no file");
|
||||
args.config
|
||||
}
|
||||
}
|
||||
None => args.config,
|
||||
};
|
||||
let mut config = PlayoutConfig::new(cfg_path);
|
||||
|
||||
if let Some(gen) = args.generate {
|
||||
config.general.generate = Some(gen);
|
||||
|
@ -4,7 +4,7 @@ description = "Library for ffplayout"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Jonathan Baecker jonbae77@gmail.com"]
|
||||
readme = "README.md"
|
||||
version = "0.10.4"
|
||||
version = "0.10.5"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -188,6 +188,7 @@ pub fn init_logging(
|
||||
.add_filter_ignore_str("hyper")
|
||||
.add_filter_ignore_str("sqlx")
|
||||
.add_filter_ignore_str("reqwest")
|
||||
.add_filter_ignore_str("rpc")
|
||||
.set_level_padding(LevelPadding::Left)
|
||||
.set_time_level(time_level)
|
||||
.clone();
|
||||
|
Loading…
Reference in New Issue
Block a user