Merge pull request #769 from jb-alvarado/master

reorder process stop to prevent out of sync, fix #735
This commit is contained in:
jb-alvarado 2024-09-29 17:27:46 +02:00 committed by GitHub
commit 8ff154abd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 414 additions and 387 deletions

103
Cargo.lock generated
View File

@ -113,7 +113,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
dependencies = [
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -151,7 +151,7 @@ dependencies = [
"parse-size",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -311,7 +311,7 @@ dependencies = [
"actix-router",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -386,7 +386,7 @@ checksum = "008f98f5a68eeacf5e6d44ed74ce03c1b906baa53eabfb41faf0f5f40bd685f8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -555,7 +555,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -735,9 +735,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.1.21"
version = "1.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
dependencies = [
"jobserver",
"libc",
@ -822,7 +822,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1003,7 +1003,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1014,7 +1014,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1061,7 +1061,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1081,7 +1081,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
"unicode-xid",
]
@ -1105,7 +1105,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1438,7 +1438,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1852,7 +1852,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -2411,9 +2411,12 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.19.0"
version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
dependencies = [
"portable-atomic",
]
[[package]]
name = "paris"
@ -2558,6 +2561,12 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "portable-atomic"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]]
name = "powerfmt"
version = "0.2.0"
@ -2591,7 +2600,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -2727,9 +2736,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.10.6"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
dependencies = [
"aho-corasick",
"memchr",
@ -2739,9 +2748,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
@ -2756,9 +2765,9 @@ checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
[[package]]
name = "regex-syntax"
version = "0.8.4"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "relative-path"
@ -2926,9 +2935,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
version = "1.8.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55"
[[package]]
name = "rustls-webpki"
@ -3010,7 +3019,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -3114,7 +3123,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -3139,7 +3148,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -3326,7 +3335,7 @@ dependencies = [
"quote",
"sqlx-core",
"sqlx-macros-core",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -3349,7 +3358,7 @@ dependencies = [
"sqlx-mysql",
"sqlx-postgres",
"sqlx-sqlite",
"syn 2.0.77",
"syn 2.0.79",
"tempfile",
"tokio",
"url",
@ -3602,9 +3611,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.77"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
@ -3628,7 +3637,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -3647,9 +3656,9 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.12.0"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
dependencies = [
"cfg-if",
"fastrand",
@ -3705,7 +3714,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -3790,7 +3799,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -3877,7 +3886,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -4106,7 +4115,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
"wasm-bindgen-shared",
]
@ -4140,7 +4149,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -4250,7 +4259,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -4261,7 +4270,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -4492,7 +4501,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
"synstructure",
]
@ -4514,7 +4523,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -4534,7 +4543,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
"synstructure",
]
@ -4590,7 +4599,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]

View File

@ -955,6 +955,7 @@ pub async fn process_control(
}
}
ProcessCtl::Start => {
manager.channel.lock().unwrap().active = true;
manager.async_start().await;
}
ProcessCtl::Stop => {

View File

@ -392,7 +392,11 @@ fn delete_ts<P: AsRef<Path> + Clone + std::fmt::Debug>(
) -> io::Result<()> {
let ts_file = params
.iter()
.filter(|f| f.to_lowercase().ends_with(".ts") || f.to_lowercase().ends_with(".m3u8"))
.filter(|f| {
f.to_lowercase().ends_with(".ts")
|| f.to_lowercase().ends_with(".m3u8")
|| f.to_lowercase().ends_with(".vtt")
})
.collect::<Vec<&String>>();
for entry in WalkDir::new(path.clone())

View File

@ -47,6 +47,7 @@ fn server_monitor(
.iter()
.any(|i| line.contains(*i))
{
error!(target: Target::file_mail(), channel = id; "Hit unrecoverable error!");
channel_mgr.channel.lock().unwrap().active = false;
channel_mgr.stop_all();
}

View File

@ -638,6 +638,8 @@ pub fn loop_image(config: &PlayoutConfig, node: &Media) -> Vec<String> {
]);
} else if vtt_dummy.is_file() {
source_cmd.append(&mut vec_strings!["-i", vtt_dummy.to_string_lossy()]);
} else {
error!("WebVTT enabled, but no vtt or dummy file found!");
}
}
@ -677,6 +679,8 @@ pub fn loop_filler(config: &PlayoutConfig, node: &Media) -> Vec<String> {
]);
} else if vtt_dummy.is_file() {
source_cmd.append(&mut vec_strings!["-i", vtt_dummy.to_string_lossy()]);
} else {
error!("WebVTT enabled, but no vtt or dummy file found!");
}
}
@ -789,6 +793,8 @@ pub fn gen_dummy(config: &PlayoutConfig, duration: f64) -> (String, Vec<String>)
if vtt_dummy.is_file() {
source_cmd.append(&mut vec_strings!["-i", vtt_dummy.to_string_lossy()]);
} else {
error!("WebVTT enabled, but no vtt or dummy file found!");
}
}
@ -906,6 +912,7 @@ pub fn stderr_reader(
|| (line.contains("No such file or directory")
&& !line.contains("failed to delete old segment"))
{
error!(target: Target::file_mail(), channel = id; "Hit unrecoverable error!");
manager.channel.lock().unwrap().active = false;
manager.stop_all();
}

View File

@ -145,6 +145,22 @@ pub async fn control_state(
match command {
"back" => {
if index > 1 && current_list.len() > 1 {
let mut data_map = Map::new();
let mut media = current_list[index - 2].clone();
let (delta, _) = get_delta(&config, &media.begin.unwrap_or(0.0));
info!(target: Target::file_mail(), channel = id; "Move to last clip");
manager.current_index.fetch_sub(2, Ordering::SeqCst);
if let Err(e) = media.add_probe(false) {
error!(target: Target::file_mail(), channel = id; "{e:?}");
};
manager.channel.lock().unwrap().time_shift = delta;
date.clone_from(&current_date);
handles::update_stat(conn, config.general.channel_id, current_date, delta).await?;
if let Some(proc) = manager.decoder.lock().unwrap().as_mut() {
if let Err(e) = proc.kill() {
error!(target: Target::file_mail(), channel = id; "Decoder {e:?}")
@ -157,20 +173,6 @@ pub async fn control_state(
return Err(ServiceError::InternalServerError);
}
info!(target: Target::file_mail(), channel = id; "Move to last clip");
let mut data_map = Map::new();
let mut media = current_list[index - 2].clone();
manager.current_index.fetch_sub(2, Ordering::SeqCst);
if let Err(e) = media.add_probe(false) {
error!(target: Target::file_mail(), channel = id; "{e:?}");
};
let (delta, _) = get_delta(&config, &media.begin.unwrap_or(0.0));
manager.channel.lock().unwrap().time_shift = delta;
date.clone_from(&current_date);
handles::update_stat(conn, config.general.channel_id, current_date, delta).await?;
data_map.insert("operation".to_string(), json!("move_to_last"));
data_map.insert("shifted_seconds".to_string(), json!(delta));
data_map.insert("media".to_string(), get_media_map(media));
@ -181,6 +183,20 @@ pub async fn control_state(
"next" => {
if index < current_list.len() {
let mut data_map = Map::new();
let mut media = current_list[index].clone();
let (delta, _) = get_delta(&config, &media.begin.unwrap_or(0.0));
info!(target: Target::file_mail(), channel = id; "Move to next clip");
if let Err(e) = media.add_probe(false) {
error!(target: Target::file_mail(), channel = id; "{e:?}");
};
manager.channel.lock().unwrap().time_shift = delta;
date.clone_from(&current_date);
handles::update_stat(conn, config.general.channel_id, current_date, delta).await?;
if let Some(proc) = manager.decoder.lock().unwrap().as_mut() {
if let Err(e) = proc.kill() {
error!(target: Target::file_mail(), channel = id; "Decoder {e:?}")
@ -193,20 +209,6 @@ pub async fn control_state(
return Err(ServiceError::InternalServerError);
}
info!(target: Target::file_mail(), channel = id; "Move to next clip");
let mut data_map = Map::new();
let mut media = current_list[index].clone();
if let Err(e) = media.add_probe(false) {
error!(target: Target::file_mail(), channel = id; "{e:?}");
};
let (delta, _) = get_delta(&config, &media.begin.unwrap_or(0.0));
manager.channel.lock().unwrap().time_shift = delta;
date.clone_from(&current_date);
handles::update_stat(conn, config.general.channel_id, current_date, delta).await?;
data_map.insert("operation".to_string(), json!("move_to_next"));
data_map.insert("shifted_seconds".to_string(), json!(delta));
data_map.insert("media".to_string(), get_media_map(media));
@ -216,6 +218,16 @@ pub async fn control_state(
}
"reset" => {
let mut data_map = Map::new();
info!(target: Target::file_mail(), channel = id; "Reset playout to original state");
manager.channel.lock().unwrap().time_shift = 0.0;
date.clone_from(&current_date);
manager.list_init.store(true, Ordering::SeqCst);
handles::update_stat(conn, config.general.channel_id, current_date, 0.0).await?;
if let Some(proc) = manager.decoder.lock().unwrap().as_mut() {
if let Err(e) = proc.kill() {
error!(target: Target::file_mail(), channel = id; "Decoder {e:?}")
@ -228,29 +240,11 @@ pub async fn control_state(
return Err(ServiceError::InternalServerError);
}
info!(target: Target::file_mail(), channel = id; "Reset playout to original state");
let mut data_map = Map::new();
manager.channel.lock().unwrap().time_shift = 0.0;
date.clone_from(&current_date);
manager.list_init.store(true, Ordering::SeqCst);
handles::update_stat(conn, config.general.channel_id, current_date, 0.0).await?;
data_map.insert("operation".to_string(), json!("reset_playout_state"));
return Ok(data_map);
}
"stop_all" => {
manager.channel.lock().unwrap().active = false;
manager.stop_all();
let mut data_map = Map::new();
data_map.insert("message".to_string(), json!("Stop playout!"));
return Ok(data_map);
}
_ => {
return Err(ServiceError::ServiceUnavailable(
"Command not found!".to_string(),

View File

@ -11,47 +11,47 @@
<thead class="top-0 sticky z-10">
<tr class="bg-base-100 rounded-tr-lg">
<th v-if="!configStore.playout.playlist.infinit" class="w-[85px] p-0 text-left">
<div class="border-b border-my-gray px-4 py-3 -mb-[2px]">
<div class="border-b border-my-gray px-4 py-3">
{{ t('player.start') }}
</div>
</th>
<th class="w-full p-0 text-left">
<div class="border-b border-my-gray px-4 py-3 -mb-[2px]">
<div class="border-b border-my-gray px-4 py-3">
{{ t('player.file') }}
</div>
</th>
<th class="w-[85px] p-0 text-center">
<div class="border-b border-my-gray px-4 py-3 -mb-[2px]">
<div class="border-b border-my-gray px-4 py-3">
{{ t('player.play') }}
</div>
</th>
<th class="w-[85px] p-0 text-center hidden 2xs:table-cell">
<div class="border-b border-my-gray px-4 py-3 -mb-[2px]">
<div class="border-b border-my-gray px-4 py-3">
{{ t('player.duration') }}
</div>
</th>
<th class="w-[85px] p-0 text-center hidden xl:table-cell">
<div class="border-b border-my-gray px-4 py-3 -mb-[2px]">
<div class="border-b border-my-gray px-4 py-3">
{{ t('player.in') }}
</div>
</th>
<th class="w-[85px] p-0 text-center hidden xl:table-cell">
<div class="border-b border-my-gray px-4 py-3 -mb-[2px]">
<div class="border-b border-my-gray px-4 py-3">
{{ t('player.out') }}
</div>
</th>
<th class="w-[85px] p-0 text-center hidden xl:table-cell justify-center">
<div class="border-b border-my-gray px-4 py-3 -mb-[2px]">
<div class="border-b border-my-gray px-4 py-3">
{{ t('player.ad') }}
</div>
</th>
<th class="w-[85px] p-0 text-center">
<div class="border-b border-my-gray px-4 py-3 -mb-[2px]">
<div class="border-b border-my-gray px-4 py-3">
{{ t('player.edit') }}
</div>
</th>
<th class="w-[85px] p-0 text-center hidden 2xs:table-cell justify-center">
<div class="border-b border-my-gray px-4 py-3 -mb-[2px]">
<div class="border-b border-my-gray px-4 py-3">
{{ t('player.delete') }}
</div>
</th>

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "frontend",
"version": "0.12.1",
"version": "0.12.2",
"description": "Web GUI for ffplayout",
"author": "Jonathan Baecker",
"private": true,
@ -39,9 +39,9 @@
"mini-svg-data-uri": "^1.4.4",
"postcss": "^8.4.47",
"postcss-loader": "^8.1.1",
"sass": "^1.79.3",
"sass": "^1.79.4",
"sass-loader": "^16.0.2",
"vue": "^3.5.8",
"vue": "^3.5.10",
"vue-router": "^4.4.5"
}
}

View File

@ -1,5 +1,5 @@
<template>
<div class="flex w-full h-full ps-1">
<div class="flex w-full h-[calc(100vh-60px)] ps-1">
<div class="flex-none w-[70px] join join-vertical me-3 pt-7">
<button
class="join-item w-full btn btn-sm btn-primary duration-500"
@ -31,7 +31,8 @@
{{ t('config.user') }}
</button>
</div>
<div class="w-[calc(100%-70px)] mt-10 px-6">
<div class="w-[calc(100%-70px)] mt-6 px-6 overflow-auto">
<div>
<div v-if="activeConf === 1" class="w-full flex justify-center">
<ConfigChannel />
</div>
@ -49,6 +50,7 @@
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">