diff --git a/ffplayout/src/api/routes.rs b/ffplayout/src/api/routes.rs index 7c7b4f8e..a0f1b460 100644 --- a/ffplayout/src/api/routes.rs +++ b/ffplayout/src/api/routes.rs @@ -10,7 +10,7 @@ /// `{id}` represent the channel id, and at default is 1. use std::{ env, - path::PathBuf, + path::{Path, PathBuf}, sync::{atomic::Ordering, Arc, Mutex}, }; @@ -659,14 +659,24 @@ async fn get_playout_config( async fn update_playout_config( pool: web::Data>, id: web::Path, - data: web::Json, + mut data: web::Json, controllers: web::Data>, role: AuthDetails, user: web::ReqData, ) -> Result { let manager = controllers.lock().unwrap().get(*id).unwrap(); + let p = manager.channel.lock().unwrap().storage_path.clone(); + let storage_path = Path::new(&p); let config_id = manager.config.lock().unwrap().general.id; + let (_, _, logo) = norm_abs_path(&storage_path, &data.processing.logo)?; + let (_, _, filler) = norm_abs_path(&storage_path, &data.storage.filler)?; + let (_, _, font) = norm_abs_path(&storage_path, &data.text.font)?; + + data.processing.logo = logo; + data.storage.filler = filler; + data.text.font = font; + handles::update_configuration(&pool, config_id, data.clone()).await?; let new_config = get_config(&pool, *id).await?; diff --git a/ffplayout/src/db/handles.rs b/ffplayout/src/db/handles.rs index d74e9270..c85cf642 100644 --- a/ffplayout/src/db/handles.rs +++ b/ffplayout/src/db/handles.rs @@ -252,12 +252,12 @@ pub async fn update_configuration( .bind(config.playlist.day_start) .bind(config.playlist.length) .bind(config.playlist.infinit) - .bind(config.storage.filler.to_string_lossy().to_string()) + .bind(config.storage.filler) .bind(config.storage.extensions.join(";")) .bind(config.storage.shuffle) .bind(config.text.add_text) .bind(config.text.text_from_filename) - .bind(config.text.fontfile) + .bind(config.text.font) .bind(config.text.style) .bind(config.text.regex) .bind(config.task.enable) diff --git a/ffplayout/src/db/models.rs b/ffplayout/src/db/models.rs index 4d730a22..08fe36e8 100644 --- a/ffplayout/src/db/models.rs +++ b/ffplayout/src/db/models.rs @@ -384,12 +384,12 @@ impl Configuration { playlist_length: config.playlist.length, playlist_infinit: config.playlist.infinit, storage_help: config.storage.help_text, - storage_filler: config.storage.filler.to_string_lossy().to_string(), + storage_filler: config.storage.filler, storage_extensions: config.storage.extensions.join(";"), storage_shuffle: config.storage.shuffle, text_help: config.text.help_text, text_add: config.text.add_text, - text_font: config.text.fontfile, + text_font: config.text.font, text_from_filename: config.text.text_from_filename, text_style: config.text.style, text_regex: config.text.regex, diff --git a/ffplayout/src/player/filter/mod.rs b/ffplayout/src/player/filter/mod.rs index 41b04ae9..004f8ee5 100644 --- a/ffplayout/src/player/filter/mod.rs +++ b/ffplayout/src/player/filter/mod.rs @@ -355,14 +355,14 @@ fn fade( fn overlay(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) { if config.processing.add_logo - && Path::new(&config.processing.logo).is_file() + && Path::new(&config.processing.logo_path).is_file() && &node.category != "advertisement" { let mut logo_chain = format!( "null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa={}", config .processing - .logo + .logo_path .replace('\\', "/") .replace(':', "\\\\:"), config.processing.logo_opacity, diff --git a/ffplayout/src/player/filter/v_drawtext.rs b/ffplayout/src/player/filter/v_drawtext.rs index 58835135..c2dfbc5c 100644 --- a/ffplayout/src/player/filter/v_drawtext.rs +++ b/ffplayout/src/player/filter/v_drawtext.rs @@ -20,8 +20,8 @@ pub fn filter_node( let mut filter = String::new(); let mut font = String::new(); - if Path::new(&config.text.fontfile).is_file() { - font = format!(":fontfile='{}'", config.text.fontfile) + if Path::new(&config.text.font_path).is_file() { + font = format!(":fontfile='{}'", config.text.font_path) } let zmq_socket = match node.map(|n| n.unit) { diff --git a/ffplayout/src/player/input/playlist.rs b/ffplayout/src/player/input/playlist.rs index c87fd029..1378134c 100644 --- a/ffplayout/src/player/input/playlist.rs +++ b/ffplayout/src/player/input/playlist.rs @@ -669,7 +669,7 @@ pub fn gen_source( // Set list_init to true, to stay in sync. manager.list_init.store(true, Ordering::SeqCst); - if config.storage.filler.is_dir() && !fillers.is_empty() { + if config.storage.filler_path.is_dir() && !fillers.is_empty() { let index = manager.filler_index.fetch_add(1, Ordering::SeqCst); let mut filler_media = fillers[index].clone(); @@ -697,11 +697,11 @@ pub fn gen_source( node.cmd = Some(loop_filler(&node)); node.probe = filler_media.probe; } else { - match MediaProbe::new(&config.storage.filler.to_string_lossy()) { + match MediaProbe::new(&config.storage.filler_path.to_string_lossy()) { Ok(probe) => { if config .storage - .filler + .filler_path .to_string_lossy() .to_string() .rsplit_once('.') @@ -709,7 +709,12 @@ pub fn gen_source( .filter(|c| IMAGE_FORMAT.contains(&c.as_str())) .is_some() { - node.source = config.storage.filler.clone().to_string_lossy().to_string(); + node.source = config + .storage + .filler_path + .clone() + .to_string_lossy() + .to_string(); node.cmd = Some(loop_image(&node)); node.probe = Some(probe); } else if let Some(filler_duration) = probe @@ -725,7 +730,12 @@ pub fn gen_source( filler_out = duration; } - node.source = config.storage.filler.clone().to_string_lossy().to_string(); + node.source = config + .storage + .filler_path + .clone() + .to_string_lossy() + .to_string(); node.seek = 0.0; node.out = filler_out; node.duration = filler_duration; diff --git a/ffplayout/src/player/utils/folder.rs b/ffplayout/src/player/utils/folder.rs index 965bdb7f..0279998d 100644 --- a/ffplayout/src/player/utils/folder.rs +++ b/ffplayout/src/player/utils/folder.rs @@ -174,10 +174,10 @@ pub fn fill_filler_list( ) -> Vec { let id = config.general.channel_id; let mut filler_list = vec![]; - let filler_path = &config.storage.filler; + let filler_path = &config.storage.filler_path; if filler_path.is_dir() { - for (index, entry) in WalkDir::new(&config.storage.filler) + for (index, entry) in WalkDir::new(&config.storage.filler_path) .into_iter() .flat_map(|e| e.ok()) .filter(|f| f.path().is_file()) @@ -211,7 +211,7 @@ pub fn fill_filler_list( f.lock().unwrap().clone_from(&filler_list); } } else if filler_path.is_file() { - let mut media = Media::new(0, &config.storage.filler.to_string_lossy(), false); + let mut media = Media::new(0, &config.storage.filler_path.to_string_lossy(), false); if fillers.is_none() { if let Err(e) = media.add_probe(false) { diff --git a/ffplayout/src/utils/config.rs b/ffplayout/src/utils/config.rs index 9800fddc..33269699 100644 --- a/ffplayout/src/utils/config.rs +++ b/ffplayout/src/utils/config.rs @@ -317,6 +317,8 @@ pub struct Processing { pub fps: f64, pub add_logo: bool, pub logo: String, + #[serde(skip_serializing, skip_deserializing)] + pub logo_path: String, pub logo_scale: String, pub logo_opacity: f64, pub logo_position: String, @@ -345,6 +347,7 @@ impl Processing { fps: config.processing_fps, add_logo: config.processing_add_logo, logo: config.processing_logo.clone(), + logo_path: config.processing_logo.clone(), logo_scale: config.processing_logo_scale.clone(), logo_opacity: config.processing_logo_opacity, logo_position: config.processing_logo_position.clone(), @@ -411,7 +414,9 @@ pub struct Storage { pub path: PathBuf, #[serde(skip_serializing, skip_deserializing)] pub paths: Vec, - pub filler: PathBuf, + pub filler: String, + #[serde(skip_serializing, skip_deserializing)] + pub filler_path: PathBuf, pub extensions: Vec, pub shuffle: bool, #[serde(skip_serializing, skip_deserializing)] @@ -424,7 +429,8 @@ impl Storage { help_text: config.storage_help.clone(), path, paths: vec![], - filler: PathBuf::from(config.storage_filler.clone()), + filler: config.storage_filler.clone(), + filler_path: PathBuf::from(config.storage_filler.clone()), extensions: config .storage_extensions .split(';') @@ -446,7 +452,9 @@ pub struct Text { pub zmq_stream_socket: Option, #[serde(skip_serializing, skip_deserializing)] pub zmq_server_socket: Option, - pub fontfile: String, + pub font: String, + #[serde(skip_serializing, skip_deserializing)] + pub font_path: String, pub text_from_filename: bool, pub style: String, pub regex: String, @@ -460,7 +468,8 @@ impl Text { node_pos: None, zmq_stream_socket: None, zmq_server_socket: None, - fontfile: config.text_font.clone(), + font: config.text_font.clone(), + font_path: config.text_font.clone(), text_from_filename: config.text_from_filename, style: config.text_style.clone(), regex: config.text_regex.clone(), @@ -591,9 +600,11 @@ impl PlayoutConfig { tokio::fs::create_dir_all(&channel.logging_path).await?; } - let (filler_path, _, _) = norm_abs_path(&channel.storage_path, &config.storage_filler)?; + let (filler_path, _, filler) = + norm_abs_path(&channel.storage_path, &config.storage_filler)?; - storage.filler = filler_path; + storage.filler = filler; + storage.filler_path = filler_path; playlist.start_sec = Some(time_to_sec(&playlist.day_start)); @@ -603,13 +614,14 @@ impl PlayoutConfig { playlist.length_sec = Some(86400.0); } - let (logo_path, _, _) = norm_abs_path(&channel.storage_path, &processing.logo)?; + let (logo_path, _, logo) = norm_abs_path(&channel.storage_path, &processing.logo)?; if processing.add_logo && !logo_path.is_file() { processing.add_logo = false; } - processing.logo = logo_path.to_string_lossy().to_string(); + processing.logo = logo; + processing.logo_path = logo_path.to_string_lossy().to_string(); if processing.audio_tracks < 1 { processing.audio_tracks = 1 @@ -715,8 +727,9 @@ impl PlayoutConfig { text.node_pos = None; } - let (text_path, _, _) = norm_abs_path(&channel.storage_path, &text.fontfile)?; - text.fontfile = text_path.to_string_lossy().to_string(); + let (font_path, _, font) = norm_abs_path(&channel.storage_path, &text.font)?; + text.font = font; + text.font_path = font_path.to_string_lossy().to_string(); Ok(Self { channel, @@ -735,15 +748,7 @@ impl PlayoutConfig { } pub async fn dump(pool: &Pool, id: i32) -> Result<(), ServiceError> { - let mut config = Self::new(pool, id).await?; - config.storage.filler.clone_from( - &config - .storage - .filler - .strip_prefix(config.channel.storage_path.clone()) - .unwrap_or(&config.storage.filler) - .to_path_buf(), - ); + let config = Self::new(pool, id).await?; let toml_string = toml_edit::ser::to_string_pretty(&config)?; tokio::fs::write(&format!("ffplayout_{id}.toml"), toml_string).await?; diff --git a/ffplayout/src/utils/files.rs b/ffplayout/src/utils/files.rs index b7daa3ca..af9f1175 100644 --- a/ffplayout/src/utils/files.rs +++ b/ffplayout/src/utils/files.rs @@ -65,15 +65,15 @@ pub fn norm_abs_path( .normalize() .to_string() .replace("../", ""); - let mut source_relative = RelativePath::new(input_path) - .normalize() - .to_string() - .replace("../", ""); let path_suffix = root_path .file_name() .unwrap_or_default() .to_string_lossy() .to_string(); + let mut source_relative = RelativePath::new(input_path) + .normalize() + .to_string() + .replace("../", ""); if input_path.starts_with(&*root_path.to_string_lossy()) || source_relative.starts_with(&path_relative) diff --git a/frontend b/frontend index bb744685..e7afc852 160000 --- a/frontend +++ b/frontend @@ -1 +1 @@ -Subproject commit bb7446850c683c3a4465c336e348476d3c8bb49c +Subproject commit e7afc85243980e060f9d5806f98ea88eff0a17ab diff --git a/tests/src/engine_cmd.rs b/tests/src/engine_cmd.rs index 7187d1b3..04518ffa 100644 --- a/tests/src/engine_cmd.rs +++ b/tests/src/engine_cmd.rs @@ -49,7 +49,7 @@ fn video_audio_input() { config.output.mode = Stream; config.processing.add_logo = true; let logo_path = fs::canonicalize("./assets/logo.png").unwrap(); - config.processing.logo = logo_path.to_string_lossy().to_string(); + config.processing.logo_path = logo_path.to_string_lossy().to_string(); let media_obj = Media::new(0, "./assets/media_mix/with_audio.mp4", true); let media = gen_source(&config, media_obj, &manager, 1); @@ -57,7 +57,7 @@ fn video_audio_input() { let test_filter_cmd = vec_strings![ "-filter_complex", - format!("[0:v:0]scale=1024:576,null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa=0.7[l];[v][l]overlay=W-w-12:12:shortest=1[vout0];[0:a:0]anull[aout0]", config.processing.logo) + format!("[0:v:0]scale=1024:576,null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa=0.7[l];[v][l]overlay=W-w-12:12:shortest=1[vout0];[0:a:0]anull[aout0]", config.processing.logo_path) ]; let test_filter_map = vec_strings!["-map", "[vout0]", "-map", "[aout0]"]; @@ -383,7 +383,7 @@ fn video_audio_filter2_stream() { config.output.mode = Stream; config.processing.add_logo = false; config.text.add_text = true; - config.text.fontfile = String::new(); + config.text.font_path = String::new(); config.output.output_filter = Some("[0:v]gblur=2[vout0];[0:a]volume=0.2[aout0]".to_string()); config.output.output_cmd = Some(vec_strings![ "-map", @@ -467,7 +467,7 @@ fn video_audio_filter3_stream() { config.output.mode = Stream; config.processing.add_logo = false; config.text.add_text = true; - config.text.fontfile = String::new(); + config.text.font_path = String::new(); config.output.output_filter = Some( "[0:v]null[o];movie=/path/to/lower_third.png[l];[o][l]overlay=shortest=1[vout0]" .to_string(), @@ -554,7 +554,7 @@ fn video_audio_filter4_stream() { config.output.mode = Stream; config.processing.add_logo = false; config.text.add_text = true; - config.text.fontfile = String::new(); + config.text.font_path = String::new(); config.output.output_filter = Some( "[0:v]null[o];movie=/path/to/lower_third.png[l];[o][l]overlay=shortest=1[vout0];[0:a:0]volume=0.2[aout0]" .to_string(), @@ -713,7 +713,7 @@ fn video_dual_audio_filter_stream() { config.output.mode = Stream; config.processing.add_logo = false; config.processing.audio_tracks = 2; - config.text.fontfile = String::new(); + config.text.font_path = String::new(); config.output.output_cmd = Some(vec_strings![ "-c:v", "libx264", @@ -999,7 +999,7 @@ fn video_audio_text_multi_stream() { config.output.mode = Stream; config.processing.add_logo = false; config.text.add_text = true; - config.text.fontfile = String::new(); + config.text.font_path = String::new(); config.output.output_count = 2; config.output.output_cmd = Some(vec_strings![ "-c:v", @@ -1114,7 +1114,7 @@ fn video_dual_audio_multi_filter_stream() { config.processing.add_logo = false; config.processing.audio_tracks = 2; config.output.output_count = 2; - config.text.fontfile = String::new(); + config.text.font_path = String::new(); config.output.output_cmd = Some(vec_strings![ "-map", "0:v", @@ -1244,7 +1244,7 @@ fn video_audio_text_filter_stream() { config.processing.add_logo = false; config.processing.audio_tracks = 1; config.text.add_text = true; - config.text.fontfile = String::new(); + config.text.font_path = String::new(); config.output.output_count = 2; config.output.output_cmd = Some(vec_strings![ "-map",