run task on clip change, #276

This commit is contained in:
jb-alvarado 2023-07-19 21:45:15 +02:00
parent f248e4bf37
commit 5bd1b23513
7 changed files with 104 additions and 47 deletions

View File

@ -117,6 +117,13 @@ text:
style: "x=(w-tw)/2:y=(h-line_h)*0.9:fontsize=24:fontcolor=#ffffff:box=1:boxcolor=#000000:boxborderw=4"
regex: ^.+[/\\](.*)(.mp4|.mkv)$
task:
help_text: Run an external program with a given media object. The media object is in json format
and contains all the information about the current clip. The external program can be a script
or a binary, but should only run for a short time.
enable: false
path:
out:
help_text: The final playout compression. Set the settings to your needs. 'mode'
has the options 'desktop', 'hls', 'null', 'stream'. Use 'stream' and adjust

View File

@ -1,5 +1,6 @@
use std::{
io::{prelude::*, BufReader, BufWriter, Read},
path::Path,
process::{Command, Stdio},
sync::atomic::Ordering,
thread::{self, sleep},
@ -17,6 +18,8 @@ mod stream;
pub use hls::write_hls;
use crate::input::{ingest_server, source_generator};
use crate::utils::task_runner;
use ffplayout_lib::utils::{
sec_to_time, stderr_reader, OutputMode::*, PlayerControl, PlayoutConfig, PlayoutStatus,
ProcessControl, ProcessUnit::*,
@ -83,11 +86,6 @@ pub fn player(
'source_iter: for node in get_source {
*play_control.current_media.lock().unwrap() = Some(node.clone());
let mut cmd = match node.cmd {
Some(cmd) => cmd,
None => break,
};
if !node.process.unwrap() {
continue;
}
@ -99,6 +97,23 @@ pub fn player(
node.audio
);
if config.task.enable {
let task_config = config.clone();
let task_node = node.clone();
let server_running = proc_control.server_is_running.load(Ordering::SeqCst);
if Path::new(&config.task.path).is_file() {
thread::spawn(move || task_runner::run(task_config, task_node, server_running));
} else {
error!("<bright-blue>{}</> executable not exists!", config.task.path);
}
}
let mut cmd = match node.cmd {
Some(cmd) => cmd,
None => break,
};
let mut dec_cmd = vec_strings!["-hide_banner", "-nostats", "-v", &ff_log_format];
dec_cmd.append(&mut cmd);

View File

@ -13,9 +13,10 @@ use std::io::{Cursor, Error as IoError};
use tiny_http::{Header, Method, Request, Response, Server};
use crate::rpc::zmq_send;
use crate::utils::{get_data_map, get_media_map};
use ffplayout_lib::utils::{
get_delta, get_sec, sec_to_time, write_status, Ingest, Media, OutputMode::*, PlayerControl,
PlayoutConfig, PlayoutStatus, ProcessControl,
get_delta, write_status, Ingest, OutputMode::*, PlayerControl, PlayoutConfig,
PlayoutStatus, ProcessControl,
};
#[derive(Default, Deserialize, Clone, Debug)]
@ -129,45 +130,6 @@ fn filter_from_json(raw_text: serde_json::Value) -> String {
filter.to_string()
}
/// map media struct to json object
fn get_media_map(media: Media) -> Value {
json!({
"seek": media.seek,
"out": media.out,
"duration": media.duration,
"category": media.category,
"source": media.source,
})
}
/// prepare json object for response
fn get_data_map(
config: &PlayoutConfig,
media: Media,
server_is_running: bool,
) -> Map<String, Value> {
let mut data_map = Map::new();
let begin = media.begin.unwrap_or(0.0);
data_map.insert("play_mode".to_string(), json!(config.processing.mode));
data_map.insert("ingest_runs".to_string(), json!(server_is_running));
data_map.insert("index".to_string(), json!(media.index));
data_map.insert("start_sec".to_string(), json!(begin));
if begin > 0.0 {
let played_time = get_sec() - begin;
let remaining_time = media.out - played_time;
data_map.insert("start_time".to_string(), json!(sec_to_time(begin)));
data_map.insert("played_sec".to_string(), json!(played_time));
data_map.insert("remaining_sec".to_string(), json!(remaining_time));
}
data_map.insert("current_media".to_string(), get_media_map(media));
data_map
}
#[derive(Debug, Serialize, Deserialize)]
struct ResponseData {
message: String,

View File

@ -4,14 +4,18 @@ use std::{
};
use regex::Regex;
use serde_json::{json, Map, Value};
use simplelog::*;
pub mod arg_parse;
pub mod task_runner;
pub use arg_parse::Args;
use ffplayout_lib::{
filter::Filters,
utils::{time_to_sec, OutputMode::*, PlayoutConfig, ProcessMode::*},
utils::{
get_sec, sec_to_time, time_to_sec, Media, OutputMode::*, PlayoutConfig, ProcessMode::*,
},
vec_strings,
};
@ -207,3 +211,42 @@ pub fn prepare_output_cmd(
cmd
}
/// map media struct to json object
pub fn get_media_map(media: Media) -> Value {
json!({
"seek": media.seek,
"out": media.out,
"duration": media.duration,
"category": media.category,
"source": media.source,
})
}
/// prepare json object for response
pub fn get_data_map(
config: &PlayoutConfig,
media: Media,
server_is_running: bool,
) -> Map<String, Value> {
let mut data_map = Map::new();
let begin = media.begin.unwrap_or(0.0);
data_map.insert("play_mode".to_string(), json!(config.processing.mode));
data_map.insert("ingest_runs".to_string(), json!(server_is_running));
data_map.insert("index".to_string(), json!(media.index));
data_map.insert("start_sec".to_string(), json!(begin));
if begin > 0.0 {
let played_time = get_sec() - begin;
let remaining_time = media.out - played_time;
data_map.insert("start_time".to_string(), json!(sec_to_time(begin)));
data_map.insert("played_sec".to_string(), json!(played_time));
data_map.insert("remaining_sec".to_string(), json!(remaining_time));
}
data_map.insert("current_media".to_string(), get_media_map(media));
data_map
}

View File

@ -0,0 +1,15 @@
use std::process::Command;
use simplelog::*;
use crate::utils::get_data_map;
use ffplayout_lib::utils::{config::PlayoutConfig, Media};
pub fn run(config: PlayoutConfig, node: Media, server_running: bool) {
let obj = serde_json::to_string(&get_data_map(&config, node, server_running)).unwrap();
trace!("Run task: {obj}");
if let Err(e) = Command::new(config.task.path).arg(obj).spawn() {
error!("Couldn't spawn task runner: {e}");
};
}

View File

@ -138,6 +138,8 @@ pub struct PlayoutConfig {
pub playlist: Playlist,
pub storage: Storage,
pub text: Text,
#[serde(default)]
pub task: Task,
pub out: Out,
}
@ -292,6 +294,12 @@ pub struct Text {
pub regex: String,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Task {
pub enable: bool,
pub path: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Out {
pub help_text: String,

7
scripts/task-runner.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/bash
# media object
mObj=$1
# perform a meaningful task
notify-send -u normal "ffplayout" -t 2 -e "Play: $(echo $mObj | jq -r '.current_media.source')"