don't log missing source when playlist is to short
add validate playlist option
This commit is contained in:
parent
cd4c8727bd
commit
83432ef673
70
Cargo.lock
generated
70
Cargo.lock
generated
@ -485,7 +485,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"parking",
|
"parking",
|
||||||
"polling",
|
"polling",
|
||||||
"rustix 0.37.22",
|
"rustix 0.37.23",
|
||||||
"slab",
|
"slab",
|
||||||
"socket2",
|
"socket2",
|
||||||
"waker-fn",
|
"waker-fn",
|
||||||
@ -535,9 +535,9 @@ checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.69"
|
version = "0.1.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b2d0f03b3640e3a630367e40c468cb7f309529c708ed1d88597047b0e7c6ef7"
|
checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -745,9 +745,9 @@ checksum = "cca491388666e04d7248af3f60f0c40cfb0991c72205595d7c396e3510207d1a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.3.10"
|
version = "4.3.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a"
|
checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -756,9 +756,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.3.10"
|
version = "4.3.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d"
|
checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -840,9 +840,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c"
|
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@ -1452,9 +1452,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
@ -1693,7 +1693,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb"
|
checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"rustix 0.38.2",
|
"rustix 0.38.3",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2392,9 +2392,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.8.4"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
|
checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -2403,9 +2415,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.7.2"
|
version = "0.7.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
|
checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "relative-path"
|
name = "relative-path"
|
||||||
@ -2516,9 +2528,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.37.22"
|
version = "0.37.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c"
|
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"errno",
|
"errno",
|
||||||
@ -2530,9 +2542,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.2"
|
version = "0.38.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aabcb0461ebd01d6b79945797c27f8529082226cb630a9865a71870ff63532a4"
|
checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.3.3",
|
"bitflags 2.3.3",
|
||||||
"errno",
|
"errno",
|
||||||
@ -2632,9 +2644,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.99"
|
version = "1.0.100"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@ -2773,9 +2785,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.10.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
@ -3071,7 +3083,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"redox_syscall 0.3.5",
|
"redox_syscall 0.3.5",
|
||||||
"rustix 0.37.22",
|
"rustix 0.37.23",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3111,18 +3123,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.40"
|
version = "1.0.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
|
checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.40"
|
version = "1.0.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -250,13 +250,19 @@ impl CurrentProgram {
|
|||||||
if !self.playout_stat.list_init.load(Ordering::SeqCst) {
|
if !self.playout_stat.list_init.load(Ordering::SeqCst) {
|
||||||
let time_sec = self.get_current_time();
|
let time_sec = self.get_current_time();
|
||||||
let index = self.index.fetch_add(1, Ordering::SeqCst);
|
let index = self.index.fetch_add(1, Ordering::SeqCst);
|
||||||
|
let nodes = self.nodes.lock().unwrap();
|
||||||
|
let last_index = nodes.len() - 1;
|
||||||
|
|
||||||
// de-instance node to preserve original values in list
|
// de-instance node to preserve original values in list
|
||||||
let mut node_clone = self.nodes.lock().unwrap()[index].clone();
|
let mut node_clone = nodes[index].clone();
|
||||||
|
|
||||||
node_clone.seek = time_sec - node_clone.begin.unwrap();
|
node_clone.seek = time_sec - node_clone.begin.unwrap();
|
||||||
self.current_node =
|
self.current_node = handle_list_init(
|
||||||
handle_list_init(&self.config, node_clone, &self.playout_stat.chain);
|
&self.config,
|
||||||
|
node_clone,
|
||||||
|
&self.playout_stat.chain,
|
||||||
|
last_index,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,6 +275,7 @@ impl Iterator for CurrentProgram {
|
|||||||
self.check_update(self.playout_stat.list_init.load(Ordering::SeqCst));
|
self.check_update(self.playout_stat.list_init.load(Ordering::SeqCst));
|
||||||
|
|
||||||
if self.playout_stat.list_init.load(Ordering::SeqCst) {
|
if self.playout_stat.list_init.load(Ordering::SeqCst) {
|
||||||
|
trace!("Init playlist, from next iterator");
|
||||||
if self.json_path.is_some() {
|
if self.json_path.is_some() {
|
||||||
self.init_clip();
|
self.init_clip();
|
||||||
}
|
}
|
||||||
@ -281,6 +288,7 @@ impl Iterator for CurrentProgram {
|
|||||||
self.current_node = self.nodes.lock().unwrap()[last_index].clone();
|
self.current_node = self.nodes.lock().unwrap()[last_index].clone();
|
||||||
let new_node = self.nodes.lock().unwrap()[last_index].clone();
|
let new_node = self.nodes.lock().unwrap()[last_index].clone();
|
||||||
let new_length = new_node.begin.unwrap() + new_node.duration;
|
let new_length = new_node.begin.unwrap() + new_node.duration;
|
||||||
|
trace!("Init playlist after playlist end");
|
||||||
|
|
||||||
self.check_for_next_playlist();
|
self.check_for_next_playlist();
|
||||||
|
|
||||||
@ -304,13 +312,17 @@ impl Iterator for CurrentProgram {
|
|||||||
current_time += self.config.playlist.length_sec.unwrap() + 1.0;
|
current_time += self.config.playlist.length_sec.unwrap() + 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut media = Media::new(0, "", false);
|
let mut nodes = self.nodes.lock().unwrap();
|
||||||
|
let index = nodes.len();
|
||||||
|
|
||||||
|
let mut media = Media::new(index, "", false);
|
||||||
media.begin = Some(current_time);
|
media.begin = Some(current_time);
|
||||||
media.duration = duration;
|
media.duration = duration;
|
||||||
media.out = duration;
|
media.out = duration;
|
||||||
|
|
||||||
self.current_node = gen_source(&self.config, media, &self.playout_stat.chain);
|
self.current_node =
|
||||||
let mut nodes = self.nodes.lock().unwrap();
|
gen_source(&self.config, media, &self.playout_stat.chain, last_index);
|
||||||
|
|
||||||
nodes.push(self.current_node.clone());
|
nodes.push(self.current_node.clone());
|
||||||
self.index.store(nodes.len(), Ordering::SeqCst);
|
self.index.store(nodes.len(), Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
@ -326,8 +338,9 @@ impl Iterator for CurrentProgram {
|
|||||||
let mut is_last = false;
|
let mut is_last = false;
|
||||||
let index = self.index.load(Ordering::SeqCst);
|
let index = self.index.load(Ordering::SeqCst);
|
||||||
let nodes = self.nodes.lock().unwrap();
|
let nodes = self.nodes.lock().unwrap();
|
||||||
|
let last_index = nodes.len() - 1;
|
||||||
|
|
||||||
if index == nodes.len() - 1 {
|
if index == last_index {
|
||||||
is_last = true
|
is_last = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,6 +349,7 @@ impl Iterator for CurrentProgram {
|
|||||||
&self.config,
|
&self.config,
|
||||||
is_last,
|
is_last,
|
||||||
&self.playout_stat,
|
&self.playout_stat,
|
||||||
|
last_index,
|
||||||
);
|
);
|
||||||
|
|
||||||
drop(nodes);
|
drop(nodes);
|
||||||
@ -370,6 +384,7 @@ impl Iterator for CurrentProgram {
|
|||||||
&self.config,
|
&self.config,
|
||||||
self.current_node.clone(),
|
self.current_node.clone(),
|
||||||
&self.playout_stat.chain,
|
&self.playout_stat.chain,
|
||||||
|
0,
|
||||||
);
|
);
|
||||||
self.nodes.lock().unwrap().push(self.current_node.clone());
|
self.nodes.lock().unwrap().push(self.current_node.clone());
|
||||||
self.last_next_ad();
|
self.last_next_ad();
|
||||||
@ -385,10 +400,12 @@ impl Iterator for CurrentProgram {
|
|||||||
|
|
||||||
// Get first clip from next playlist.
|
// Get first clip from next playlist.
|
||||||
self.index.store(0, Ordering::SeqCst);
|
self.index.store(0, Ordering::SeqCst);
|
||||||
|
let last_index = self.nodes.lock().unwrap().len() - 1;
|
||||||
self.current_node = gen_source(
|
self.current_node = gen_source(
|
||||||
&self.config,
|
&self.config,
|
||||||
self.nodes.lock().unwrap()[0].clone(),
|
self.nodes.lock().unwrap()[0].clone(),
|
||||||
&self.playout_stat.chain,
|
&self.playout_stat.chain,
|
||||||
|
last_index,
|
||||||
);
|
);
|
||||||
self.last_next_ad();
|
self.last_next_ad();
|
||||||
self.current_node.last_ad = last_ad;
|
self.current_node.last_ad = last_ad;
|
||||||
@ -409,12 +426,15 @@ fn timed_source(
|
|||||||
config: &PlayoutConfig,
|
config: &PlayoutConfig,
|
||||||
last: bool,
|
last: bool,
|
||||||
playout_stat: &PlayoutStatus,
|
playout_stat: &PlayoutStatus,
|
||||||
|
last_index: usize,
|
||||||
) -> Media {
|
) -> Media {
|
||||||
let (delta, total_delta) = get_delta(config, &node.begin.unwrap());
|
let (delta, total_delta) = get_delta(config, &node.begin.unwrap());
|
||||||
let mut shifted_delta = delta;
|
let mut shifted_delta = delta;
|
||||||
let mut new_node = node.clone();
|
let mut new_node = node.clone();
|
||||||
new_node.process = Some(false);
|
new_node.process = Some(false);
|
||||||
|
|
||||||
|
trace!("timed source ist last: {last}");
|
||||||
|
|
||||||
if config.playlist.length.contains(':') {
|
if config.playlist.length.contains(':') {
|
||||||
let time_shift = playout_stat.time_shift.lock().unwrap();
|
let time_shift = playout_stat.time_shift.lock().unwrap();
|
||||||
|
|
||||||
@ -443,11 +463,11 @@ fn timed_source(
|
|||||||
{
|
{
|
||||||
// when we are in the 24 hour range, get the clip
|
// when we are in the 24 hour range, get the clip
|
||||||
new_node.process = Some(true);
|
new_node.process = Some(true);
|
||||||
new_node = gen_source(config, node, &playout_stat.chain);
|
new_node = gen_source(config, node, &playout_stat.chain, last_index);
|
||||||
} else if total_delta <= 0.0 {
|
} else if total_delta <= 0.0 {
|
||||||
info!("Begin is over play time, skip: {}", node.source);
|
info!("Begin is over play time, skip: {}", node.source);
|
||||||
} else if total_delta < node.duration - node.seek || last {
|
} else if total_delta < node.duration - node.seek || last {
|
||||||
new_node = handle_list_end(config, node, total_delta, &playout_stat.chain);
|
new_node = handle_list_end(config, node, total_delta, &playout_stat.chain, last_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_node
|
new_node
|
||||||
@ -458,6 +478,7 @@ pub fn gen_source(
|
|||||||
config: &PlayoutConfig,
|
config: &PlayoutConfig,
|
||||||
mut node: Media,
|
mut node: Media,
|
||||||
filter_chain: &Option<Arc<Mutex<Vec<String>>>>,
|
filter_chain: &Option<Arc<Mutex<Vec<String>>>>,
|
||||||
|
last_index: usize,
|
||||||
) -> Media {
|
) -> Media {
|
||||||
let duration = node.out - node.seek;
|
let duration = node.out - node.seek;
|
||||||
|
|
||||||
@ -476,7 +497,16 @@ pub fn gen_source(
|
|||||||
node.cmd = Some(seek_and_length(&node));
|
node.cmd = Some(seek_and_length(&node));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!("Source not found: <b><magenta>\"{}\"</></b>", node.source);
|
trace!(
|
||||||
|
"clip index: {:?} | last index: {:?}",
|
||||||
|
node.index.unwrap_or_default(),
|
||||||
|
last_index
|
||||||
|
);
|
||||||
|
|
||||||
|
if node.index.unwrap_or_default() < last_index {
|
||||||
|
error!("Source not found: <b><magenta>\"{}\"</></b>", node.source);
|
||||||
|
}
|
||||||
|
|
||||||
warn!("Generate filler with <yellow>{duration:.2}</> seconds length!");
|
warn!("Generate filler with <yellow>{duration:.2}</> seconds length!");
|
||||||
|
|
||||||
let probe = MediaProbe::new(&config.storage.filler_clip);
|
let probe = MediaProbe::new(&config.storage.filler_clip);
|
||||||
@ -532,6 +562,7 @@ fn handle_list_init(
|
|||||||
config: &PlayoutConfig,
|
config: &PlayoutConfig,
|
||||||
mut node: Media,
|
mut node: Media,
|
||||||
filter_chain: &Option<Arc<Mutex<Vec<String>>>>,
|
filter_chain: &Option<Arc<Mutex<Vec<String>>>>,
|
||||||
|
last_index: usize,
|
||||||
) -> Media {
|
) -> Media {
|
||||||
debug!("Playlist init");
|
debug!("Playlist init");
|
||||||
let (_, total_delta) = get_delta(config, &node.begin.unwrap());
|
let (_, total_delta) = get_delta(config, &node.begin.unwrap());
|
||||||
@ -542,7 +573,8 @@ fn handle_list_init(
|
|||||||
}
|
}
|
||||||
|
|
||||||
node.out = out;
|
node.out = out;
|
||||||
gen_source(config, node, filter_chain)
|
|
||||||
|
gen_source(config, node, filter_chain, last_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// when we come to last clip in playlist,
|
/// when we come to last clip in playlist,
|
||||||
@ -553,6 +585,7 @@ fn handle_list_end(
|
|||||||
mut node: Media,
|
mut node: Media,
|
||||||
total_delta: f64,
|
total_delta: f64,
|
||||||
filter_chain: &Option<Arc<Mutex<Vec<String>>>>,
|
filter_chain: &Option<Arc<Mutex<Vec<String>>>>,
|
||||||
|
last_index: usize,
|
||||||
) -> Media {
|
) -> Media {
|
||||||
debug!("Playlist end");
|
debug!("Playlist end");
|
||||||
|
|
||||||
@ -580,5 +613,5 @@ fn handle_list_end(
|
|||||||
|
|
||||||
node.process = Some(true);
|
node.process = Some(true);
|
||||||
|
|
||||||
gen_source(config, node, filter_chain)
|
gen_source(config, node, filter_chain, last_index)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::{
|
|||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::exit,
|
process::exit,
|
||||||
sync::{Arc, Mutex},
|
sync::{atomic::AtomicBool, Arc, Mutex},
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,8 +19,9 @@ use ffplayout::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use ffplayout_lib::utils::{
|
use ffplayout_lib::utils::{
|
||||||
generate_playlist, import::import_file, init_logging, send_mail, validate_ffmpeg,
|
generate_playlist, get_date, import::import_file, init_logging, is_remote, send_mail,
|
||||||
OutputMode::*, PlayerControl, PlayoutStatus, ProcessControl,
|
validate_ffmpeg, validate_playlist, JsonPlaylist, OutputMode::*, PlayerControl, PlayoutStatus,
|
||||||
|
ProcessControl,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
@ -159,6 +160,39 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.validate {
|
||||||
|
let mut playlist_path = Path::new(&config.playlist.path).to_owned();
|
||||||
|
let start_sec = config.playlist.start_sec.unwrap();
|
||||||
|
let date = get_date(false, start_sec, 0.0);
|
||||||
|
|
||||||
|
if playlist_path.is_dir() || is_remote(&config.playlist.path) {
|
||||||
|
let d: Vec<&str> = date.split('-').collect();
|
||||||
|
playlist_path = playlist_path
|
||||||
|
.join(d[0])
|
||||||
|
.join(d[1])
|
||||||
|
.join(date.clone())
|
||||||
|
.with_extension("json");
|
||||||
|
}
|
||||||
|
|
||||||
|
let f = File::options()
|
||||||
|
.read(true)
|
||||||
|
.write(false)
|
||||||
|
.open(&playlist_path)
|
||||||
|
.expect("Could not open json playlist file.");
|
||||||
|
|
||||||
|
let playlist: JsonPlaylist = match serde_json::from_reader(f) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => {
|
||||||
|
error!("{e:?}");
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
validate_playlist(playlist, Arc::new(AtomicBool::new(false)), config);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if config.rpc_server.enable {
|
if config.rpc_server.enable {
|
||||||
// If RPC server is enable we also fire up a JSON RPC server.
|
// If RPC server is enable we also fire up a JSON RPC server.
|
||||||
thread::spawn(move || run_server(config_clone, play_ctl, play_stat, proc_ctl2));
|
thread::spawn(move || run_server(config_clone, play_ctl, play_stat, proc_ctl2));
|
||||||
|
@ -41,7 +41,7 @@ pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child {
|
|||||||
}) {
|
}) {
|
||||||
enc_cmd.append(&mut cmd);
|
enc_cmd.append(&mut cmd);
|
||||||
} else {
|
} else {
|
||||||
warn!("Given output parameter a skipped, they are not supported by ffplay!");
|
warn!("Given output parameters are skipped, they are not supported by ffplay!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,9 @@ pub struct Args {
|
|||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
#[clap(long, help = "fake date time, for debugging")]
|
#[clap(long, help = "fake date time, for debugging")]
|
||||||
pub fake_time: Option<String>,
|
pub fake_time: Option<String>,
|
||||||
|
|
||||||
|
#[clap(long, help = "validate given playlist")]
|
||||||
|
pub validate: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get arguments from command line, and return them.
|
/// Get arguments from command line, and return them.
|
||||||
|
@ -39,6 +39,10 @@ pub fn get_config(args: Args) -> PlayoutConfig {
|
|||||||
config.general.generate = Some(gen);
|
config.general.generate = Some(gen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.validate {
|
||||||
|
config.general.validate = true;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(paths) = args.paths {
|
if let Some(paths) = args.paths {
|
||||||
config.storage.paths = paths;
|
config.storage.paths = paths;
|
||||||
}
|
}
|
||||||
|
@ -157,6 +157,9 @@ pub struct General {
|
|||||||
|
|
||||||
#[serde(skip_serializing, skip_deserializing)]
|
#[serde(skip_serializing, skip_deserializing)]
|
||||||
pub ffmpeg_libs: Vec<String>,
|
pub ffmpeg_libs: Vec<String>,
|
||||||
|
|
||||||
|
#[serde(default, skip_serializing, skip_deserializing)]
|
||||||
|
pub validate: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
@ -147,10 +147,16 @@ pub fn validate_playlist(
|
|||||||
if valid_source(&item.source) {
|
if valid_source(&item.source) {
|
||||||
if let Err(e) = check_media(item.clone(), pos, begin, &config) {
|
if let Err(e) = check_media(item.clone(), pos, begin, &config) {
|
||||||
error!("{e}");
|
error!("{e}");
|
||||||
|
} else if config.general.validate {
|
||||||
|
debug!(
|
||||||
|
"Source at <yellow>{}</>, seems fine: <b><magenta>{}</></b>",
|
||||||
|
sec_to_time(begin),
|
||||||
|
item.source
|
||||||
|
)
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
error!(
|
error!(
|
||||||
"Source on position <yellow>{pos}</> {} not exists: <b><magenta>\"{}\"</></b>",
|
"Source on position <yellow>{pos}</> {} not exists: <b><magenta>{}</></b>",
|
||||||
sec_to_time(begin),
|
sec_to_time(begin),
|
||||||
item.source
|
item.source
|
||||||
);
|
);
|
||||||
|
@ -238,6 +238,7 @@ pub fn init_logging(
|
|||||||
} else {
|
} else {
|
||||||
let term_config = log_config
|
let term_config = log_config
|
||||||
.clone()
|
.clone()
|
||||||
|
.set_level_color(Level::Trace, Some(Color::Ansi256(11)))
|
||||||
.set_level_color(Level::Debug, Some(Color::Ansi256(12)))
|
.set_level_color(Level::Debug, Some(Color::Ansi256(12)))
|
||||||
.set_level_color(Level::Info, Some(Color::Ansi256(10)))
|
.set_level_color(Level::Info, Some(Color::Ansi256(10)))
|
||||||
.set_level_color(Level::Warn, Some(Color::Ansi256(208)))
|
.set_level_color(Level::Warn, Some(Color::Ansi256(208)))
|
||||||
|
@ -15,7 +15,7 @@ fn video_audio_input() {
|
|||||||
config.processing.logo = logo_path.to_string_lossy().to_string();
|
config.processing.logo = logo_path.to_string_lossy().to_string();
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let test_filter_cmd =
|
let test_filter_cmd =
|
||||||
vec_strings![
|
vec_strings![
|
||||||
@ -41,7 +41,7 @@ fn video_audio_custom_filter1_input() {
|
|||||||
config.processing.custom_filter = "[0:v]gblur=2[c_v_out];[0:a]volume=0.2[c_a_out]".to_string();
|
config.processing.custom_filter = "[0:v]gblur=2[c_v_out];[0:a]volume=0.2[c_a_out]".to_string();
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let test_filter_cmd = vec_strings![
|
let test_filter_cmd = vec_strings![
|
||||||
"-filter_complex",
|
"-filter_complex",
|
||||||
@ -68,7 +68,7 @@ fn video_audio_custom_filter2_input() {
|
|||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let test_filter_cmd = vec_strings![
|
let test_filter_cmd = vec_strings![
|
||||||
"-filter_complex",
|
"-filter_complex",
|
||||||
@ -94,7 +94,7 @@ fn video_audio_custom_filter3_input() {
|
|||||||
"[v_in];movie=logo.png[l];[v_in][l]overlay[c_v_out];[0:a]volume=0.2[c_a_out]".to_string();
|
"[v_in];movie=logo.png[l];[v_in][l]overlay[c_v_out];[0:a]volume=0.2[c_a_out]".to_string();
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let test_filter_cmd = vec_strings![
|
let test_filter_cmd = vec_strings![
|
||||||
"-filter_complex",
|
"-filter_complex",
|
||||||
@ -119,7 +119,7 @@ fn dual_audio_aevalsrc_input() {
|
|||||||
config.processing.add_logo = false;
|
config.processing.add_logo = false;
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let test_filter_cmd =
|
let test_filter_cmd =
|
||||||
vec_strings![
|
vec_strings![
|
||||||
@ -145,7 +145,7 @@ fn dual_audio_input() {
|
|||||||
config.processing.add_logo = false;
|
config.processing.add_logo = false;
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/dual_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/dual_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let test_filter_cmd = vec_strings![
|
let test_filter_cmd = vec_strings![
|
||||||
"-filter_complex",
|
"-filter_complex",
|
||||||
@ -171,7 +171,7 @@ fn video_separate_audio_input() {
|
|||||||
|
|
||||||
let mut media_obj = Media::new(0, "./assets/no_audio.mp4", true);
|
let mut media_obj = Media::new(0, "./assets/no_audio.mp4", true);
|
||||||
media_obj.audio = "./assets/audio.mp3".to_string();
|
media_obj.audio = "./assets/audio.mp3".to_string();
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let test_filter_cmd = vec_strings![
|
let test_filter_cmd = vec_strings![
|
||||||
"-filter_complex",
|
"-filter_complex",
|
||||||
@ -1333,7 +1333,7 @@ fn video_audio_hls() {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -1422,7 +1422,7 @@ fn video_audio_sub_meta_hls() {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -1512,7 +1512,7 @@ fn video_multi_audio_hls() {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/dual_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/dual_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -1617,7 +1617,7 @@ fn multi_video_audio_hls() {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -1733,7 +1733,7 @@ fn multi_video_multi_audio_hls() {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let media_obj = Media::new(0, "./assets/dual_audio.mp4", true);
|
let media_obj = Media::new(0, "./assets/dual_audio.mp4", true);
|
||||||
let media = gen_source(&config, media_obj, &None);
|
let media = gen_source(&config, media_obj, &None, 1);
|
||||||
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
|
Loading…
Reference in New Issue
Block a user