remove some unstable unwarps, clode cleanup
This commit is contained in:
parent
52ce6197f0
commit
2902647200
@ -5,7 +5,7 @@ use crate::utils::GlobalConfig;
|
||||
/// Add loudness normalization.
|
||||
pub fn filter_node(config: &GlobalConfig) -> String {
|
||||
format!(
|
||||
",loudnorm=I={}:TP={}:LRA={}",
|
||||
"loudnorm=I={}:TP={}:LRA={}",
|
||||
config.processing.loud_i, config.processing.loud_tp, config.processing.loud_lra
|
||||
)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ fn audio_filter(config: &GlobalConfig) -> String {
|
||||
let mut audio_chain = ";[0:a]afade=in:st=0:d=0.5".to_string();
|
||||
|
||||
if config.processing.loudnorm_ingest {
|
||||
audio_chain.push(',');
|
||||
audio_chain.push_str(&a_loudnorm::filter_node(config));
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,8 @@ use crate::utils::{get_delta, is_close, GlobalConfig, Media};
|
||||
struct Filters {
|
||||
audio_chain: Option<String>,
|
||||
video_chain: Option<String>,
|
||||
audio_map: Option<String>,
|
||||
video_map: Option<String>,
|
||||
audio_map: String,
|
||||
video_map: String,
|
||||
}
|
||||
|
||||
impl Filters {
|
||||
@ -22,8 +22,8 @@ impl Filters {
|
||||
Filters {
|
||||
audio_chain: None,
|
||||
video_chain: None,
|
||||
audio_map: Some("0:a".to_string()),
|
||||
video_map: Some("0:v".to_string()),
|
||||
audio_map: "1:a".to_string(),
|
||||
video_map: "0:v".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,10 +41,9 @@ impl Filters {
|
||||
if filter.contains("aevalsrc") || filter.contains("anoisesrc") {
|
||||
self.audio_chain = Some(filter.to_string());
|
||||
} else {
|
||||
self.audio_chain =
|
||||
Some(format!("[{}]{filter}", self.audio_map.clone().unwrap()));
|
||||
self.audio_chain = Some(format!("[{}]{filter}", self.audio_map.clone()));
|
||||
}
|
||||
self.audio_map = Some("[aout1]".to_string());
|
||||
self.audio_map = "[aout1]".to_string();
|
||||
}
|
||||
},
|
||||
"video" => match &self.video_chain {
|
||||
@ -57,7 +56,7 @@ impl Filters {
|
||||
}
|
||||
None => {
|
||||
self.video_chain = Some(format!("[0:v]{filter}"));
|
||||
self.video_map = Some("[vout1]".to_string());
|
||||
self.video_map = "[vout1]".to_string();
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
@ -101,18 +100,30 @@ fn fps(fps: f64, chain: &mut Filters, config: &GlobalConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
fn scale(width: i64, height: i64, aspect: f64, chain: &mut Filters, config: &GlobalConfig) {
|
||||
if width != config.processing.width || height != config.processing.height {
|
||||
fn scale(v_stream: &ffprobe::Stream, aspect: f64, chain: &mut Filters, config: &GlobalConfig) {
|
||||
// width: i64, height: i64
|
||||
if let (Some(w), Some(h)) = (v_stream.width, v_stream.height) {
|
||||
if w != config.processing.width || h != config.processing.height {
|
||||
chain.add_filter(
|
||||
&format!(
|
||||
"scale={}:{}",
|
||||
config.processing.width, config.processing.height
|
||||
),
|
||||
"video",
|
||||
)
|
||||
}
|
||||
|
||||
if !is_close(aspect, config.processing.aspect, 0.03) {
|
||||
chain.add_filter(&format!("setdar=dar={}", config.processing.aspect), "video")
|
||||
}
|
||||
} else {
|
||||
chain.add_filter(
|
||||
&format!(
|
||||
"scale={}:{}",
|
||||
config.processing.width, config.processing.height
|
||||
),
|
||||
"video",
|
||||
)
|
||||
}
|
||||
|
||||
if !is_close(aspect, config.processing.aspect, 0.03) {
|
||||
);
|
||||
chain.add_filter(&format!("setdar=dar={}", config.processing.aspect), "video")
|
||||
}
|
||||
}
|
||||
@ -161,20 +172,22 @@ fn overlay(node: &mut Media, chain: &mut Filters, config: &GlobalConfig) {
|
||||
}
|
||||
|
||||
fn extend_video(node: &mut Media, chain: &mut Filters) {
|
||||
let video_streams = node.probe.clone().unwrap().video_streams.unwrap();
|
||||
if !video_streams.is_empty() {
|
||||
if let Some(duration) = &video_streams[0].duration {
|
||||
let duration_float = duration.clone().parse::<f64>().unwrap();
|
||||
if let Some(duration) = node
|
||||
.probe
|
||||
.as_ref()
|
||||
.and_then(|p| p.video_streams.as_ref())
|
||||
.and_then(|v| v[0].duration.as_ref())
|
||||
{
|
||||
let duration_float = duration.clone().parse::<f64>().unwrap();
|
||||
|
||||
if node.out - node.seek > duration_float - node.seek + 0.1 {
|
||||
chain.add_filter(
|
||||
&format!(
|
||||
"tpad=stop_mode=add:stop_duration={}",
|
||||
(node.out - node.seek) - (duration_float - node.seek)
|
||||
),
|
||||
"video",
|
||||
)
|
||||
}
|
||||
if node.out - node.seek > duration_float - node.seek + 0.1 {
|
||||
chain.add_filter(
|
||||
&format!(
|
||||
"tpad=stop_mode=add:stop_duration={}",
|
||||
(node.out - node.seek) - (duration_float - node.seek)
|
||||
),
|
||||
"video",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,8 +211,13 @@ fn add_text(node: &mut Media, chain: &mut Filters, config: &GlobalConfig) {
|
||||
}
|
||||
|
||||
fn add_audio(node: &mut Media, chain: &mut Filters) {
|
||||
let audio_streams = node.probe.clone().unwrap().audio_streams.unwrap();
|
||||
if audio_streams.is_empty() {
|
||||
if node
|
||||
.probe
|
||||
.as_ref()
|
||||
.and_then(|p| p.audio_streams.as_ref())
|
||||
.unwrap_or(&vec![])
|
||||
.is_empty()
|
||||
{
|
||||
warn!("Clip: '{}' has no audio!", node.source);
|
||||
let audio = format!(
|
||||
"aevalsrc=0:channel_layout=stereo:duration={}:sample_rate=48000",
|
||||
@ -210,29 +228,29 @@ fn add_audio(node: &mut Media, chain: &mut Filters) {
|
||||
}
|
||||
|
||||
fn extend_audio(node: &mut Media, chain: &mut Filters) {
|
||||
let audio_streams = node.probe.clone().unwrap().audio_streams.unwrap();
|
||||
if !audio_streams.is_empty() {
|
||||
if let Some(duration) = &audio_streams[0].duration {
|
||||
let duration_float = duration.clone().parse::<f64>().unwrap();
|
||||
if let Some(duration) = node
|
||||
.probe
|
||||
.as_ref()
|
||||
.and_then(|p| p.audio_streams.as_ref())
|
||||
.and_then(|a| a[0].duration.as_ref())
|
||||
{
|
||||
let duration_float = duration.clone().parse::<f64>().unwrap();
|
||||
|
||||
if node.out - node.seek > duration_float - node.seek + 0.1 {
|
||||
chain.add_filter(&format!("apad=whole_dur={}", node.out - node.seek), "audio")
|
||||
}
|
||||
if node.out - node.seek > duration_float - node.seek + 0.1 {
|
||||
chain.add_filter(&format!("apad=whole_dur={}", node.out - node.seek), "audio")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add single pass loudnorm filter to audio line.
|
||||
fn add_loudnorm(node: &mut Media, chain: &mut Filters, config: &GlobalConfig) {
|
||||
if node.probe.is_some()
|
||||
if config.processing.add_loudnorm
|
||||
&& !node
|
||||
.probe
|
||||
.clone()
|
||||
.unwrap()
|
||||
.audio_streams
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.and_then(|p| p.audio_streams.as_ref())
|
||||
.unwrap_or(&vec![])
|
||||
.is_empty()
|
||||
&& config.processing.add_loudnorm
|
||||
{
|
||||
let loud_filter = a_loudnorm::filter_node(config);
|
||||
chain.add_filter(&loud_filter, "audio");
|
||||
@ -259,7 +277,7 @@ fn aspect_calc(aspect_string: &Option<String>, config: &GlobalConfig) -> f64 {
|
||||
}
|
||||
|
||||
fn fps_calc(r_frame_rate: &str) -> f64 {
|
||||
let frame_rate_vec: Vec<&str> = r_frame_rate.split('/').collect();
|
||||
let frame_rate_vec = r_frame_rate.split('/').collect::<Vec<&str>>();
|
||||
let rate: f64 = frame_rate_vec[0].parse().unwrap();
|
||||
let factor: f64 = frame_rate_vec[1].parse().unwrap();
|
||||
let fps: f64 = rate / factor;
|
||||
@ -294,29 +312,24 @@ fn realtime_filter(node: &mut Media, chain: &mut Filters, config: &GlobalConfig,
|
||||
|
||||
pub fn filter_chains(config: &GlobalConfig, node: &mut Media) -> Vec<String> {
|
||||
let mut filters = Filters::new();
|
||||
let mut audio_map = "1:a".to_string();
|
||||
filters.audio_map = Some(audio_map);
|
||||
|
||||
if let Some(probe) = node.probe.clone() {
|
||||
if let Some(probe) = node.probe.as_ref() {
|
||||
if probe.audio_streams.is_some() {
|
||||
audio_map = "0:a".to_string();
|
||||
filters.audio_map = Some(audio_map);
|
||||
filters.audio_map = "0:a".to_string();
|
||||
}
|
||||
|
||||
let v_stream = &probe.video_streams.unwrap()[0];
|
||||
let aspect = aspect_calc(&v_stream.display_aspect_ratio, config);
|
||||
let frame_per_sec = fps_calc(&v_stream.r_frame_rate);
|
||||
if let Some(v_streams) = &probe.video_streams.as_ref() {
|
||||
let v_stream = &v_streams[0];
|
||||
|
||||
let aspect = aspect_calc(&v_stream.display_aspect_ratio, config);
|
||||
let frame_per_sec = fps_calc(&v_stream.r_frame_rate);
|
||||
|
||||
deinterlace(&v_stream.field_order, &mut filters);
|
||||
pad(aspect, &mut filters, config);
|
||||
fps(frame_per_sec, &mut filters, config);
|
||||
scale(v_stream, aspect, &mut filters, config);
|
||||
}
|
||||
|
||||
deinterlace(&v_stream.field_order, &mut filters);
|
||||
pad(aspect, &mut filters, config);
|
||||
fps(frame_per_sec, &mut filters, config);
|
||||
scale(
|
||||
v_stream.width.unwrap(),
|
||||
v_stream.height.unwrap(),
|
||||
aspect,
|
||||
&mut filters,
|
||||
config,
|
||||
);
|
||||
extend_video(node, &mut filters);
|
||||
|
||||
add_audio(node, &mut filters);
|
||||
@ -339,8 +352,8 @@ pub fn filter_chains(config: &GlobalConfig, node: &mut Media) -> Vec<String> {
|
||||
|
||||
if let Some(v_filters) = filters.video_chain {
|
||||
filter_str.push_str(v_filters.as_str());
|
||||
filter_str.push_str(filters.video_map.clone().unwrap().as_str());
|
||||
filter_map.append(&mut vec!["-map".to_string(), filters.video_map.unwrap()]);
|
||||
filter_str.push_str(filters.video_map.clone().as_str());
|
||||
filter_map.append(&mut vec!["-map".to_string(), filters.video_map]);
|
||||
} else {
|
||||
filter_map.append(&mut vec!["-map".to_string(), "0:v".to_string()]);
|
||||
}
|
||||
@ -350,10 +363,10 @@ pub fn filter_chains(config: &GlobalConfig, node: &mut Media) -> Vec<String> {
|
||||
filter_str.push(';')
|
||||
}
|
||||
filter_str.push_str(a_filters.as_str());
|
||||
filter_str.push_str(filters.audio_map.clone().unwrap().as_str());
|
||||
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map.unwrap()]);
|
||||
filter_str.push_str(filters.audio_map.clone().as_str());
|
||||
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map]);
|
||||
} else {
|
||||
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map.unwrap()]);
|
||||
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map]);
|
||||
}
|
||||
|
||||
if filter_str.len() > 10 {
|
||||
|
@ -51,17 +51,15 @@ impl FolderSource {
|
||||
|
||||
for entry in WalkDir::new(config.storage.path.clone())
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
.flat_map(|e| e.ok())
|
||||
.filter(|f| f.path().is_file())
|
||||
{
|
||||
if entry.path().is_file() {
|
||||
let ext = file_extension(entry.path());
|
||||
|
||||
if ext.is_some()
|
||||
&& config
|
||||
.storage
|
||||
.extensions
|
||||
.clone()
|
||||
.contains(&ext.unwrap().to_lowercase())
|
||||
if let Some(ext) = file_extension(entry.path()) {
|
||||
if config
|
||||
.storage
|
||||
.extensions
|
||||
.clone()
|
||||
.contains(&ext.to_lowercase())
|
||||
{
|
||||
let media = Media::new(0, entry.path().display().to_string(), false);
|
||||
media_list.push(media);
|
||||
|
@ -80,30 +80,28 @@ impl CurrentProgram {
|
||||
} else if Path::new(&self.json_path.clone().unwrap()).is_file() {
|
||||
let mod_time = modified_time(&self.json_path.clone().unwrap());
|
||||
|
||||
if !mod_time
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.eq(&self.json_mod.clone().unwrap())
|
||||
{
|
||||
// when playlist has changed, reload it
|
||||
info!(
|
||||
"Reload playlist <b><magenta>{}</></b>",
|
||||
self.json_path.clone().unwrap()
|
||||
);
|
||||
if let Some(m) = mod_time {
|
||||
if !m.to_string().eq(&self.json_mod.clone().unwrap()) {
|
||||
// when playlist has changed, reload it
|
||||
info!(
|
||||
"Reload playlist <b><magenta>{}</></b>",
|
||||
self.json_path.clone().unwrap()
|
||||
);
|
||||
|
||||
let json = read_json(
|
||||
&self.config,
|
||||
self.json_path.clone(),
|
||||
self.is_terminated.clone(),
|
||||
false,
|
||||
0.0,
|
||||
);
|
||||
let json = read_json(
|
||||
&self.config,
|
||||
self.json_path.clone(),
|
||||
self.is_terminated.clone(),
|
||||
false,
|
||||
0.0,
|
||||
);
|
||||
|
||||
self.json_mod = json.modified;
|
||||
*self.nodes.lock().unwrap() = json.program;
|
||||
self.json_mod = json.modified;
|
||||
*self.nodes.lock().unwrap() = json.program;
|
||||
|
||||
self.get_current_clip();
|
||||
self.index.fetch_add(1, Ordering::SeqCst);
|
||||
self.get_current_clip();
|
||||
self.index.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!(
|
||||
|
@ -230,7 +230,6 @@ pub fn json_rpc_server(
|
||||
&& request.headers()["authorization"] == auth
|
||||
{
|
||||
if request.uri() == "/status" {
|
||||
println!("{:?}", request.headers().contains_key("authorization"));
|
||||
Response::ok("Server running OK.").into()
|
||||
} else {
|
||||
request.into()
|
||||
|
@ -240,6 +240,7 @@ impl GlobalConfig {
|
||||
|
||||
if let Some(folder) = args.folder {
|
||||
config.storage.path = folder;
|
||||
config.processing.mode = "folder".into();
|
||||
}
|
||||
|
||||
if let Some(start) = args.start {
|
||||
|
@ -26,28 +26,30 @@ use crate::utils::GlobalConfig;
|
||||
|
||||
/// send log messages to mail recipient
|
||||
fn send_mail(cfg: &GlobalConfig, msg: String) {
|
||||
let email = Message::builder()
|
||||
if let Ok(email) = Message::builder()
|
||||
.from(cfg.mail.sender_addr.parse().unwrap())
|
||||
.to(cfg.mail.recipient.parse().unwrap())
|
||||
.subject(cfg.mail.subject.clone())
|
||||
.header(header::ContentType::TEXT_PLAIN)
|
||||
.body(clean_string(&msg))
|
||||
.unwrap();
|
||||
{
|
||||
let credentials =
|
||||
Credentials::new(cfg.mail.sender_addr.clone(), cfg.mail.sender_pass.clone());
|
||||
|
||||
let credentials = Credentials::new(cfg.mail.sender_addr.clone(), cfg.mail.sender_pass.clone());
|
||||
let mut transporter = SmtpTransport::relay(cfg.mail.smtp_server.clone().as_str());
|
||||
|
||||
let mut transporter = SmtpTransport::relay(cfg.mail.smtp_server.clone().as_str());
|
||||
if cfg.mail.starttls {
|
||||
transporter = SmtpTransport::starttls_relay(cfg.mail.smtp_server.clone().as_str())
|
||||
}
|
||||
|
||||
if cfg.mail.starttls {
|
||||
transporter = SmtpTransport::starttls_relay(cfg.mail.smtp_server.clone().as_str())
|
||||
}
|
||||
let mailer = transporter.unwrap().credentials(credentials).build();
|
||||
|
||||
let mailer = transporter.unwrap().credentials(credentials).build();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(&email) {
|
||||
Ok(_) => (),
|
||||
Err(e) => info!("Could not send email: {:?}", e),
|
||||
// Send the email
|
||||
if let Err(e) = mailer.send(&email) {
|
||||
error!("Could not send email: {:?}", e)
|
||||
}
|
||||
} else {
|
||||
error!("Mail Message failed!")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,16 +69,19 @@ pub struct Media {
|
||||
|
||||
impl Media {
|
||||
pub fn new(index: usize, src: String, do_probe: bool) -> Self {
|
||||
let mut duration: f64 = 0.0;
|
||||
let mut duration = 0.0;
|
||||
let mut probe = None;
|
||||
|
||||
if do_probe && Path::new(&src).is_file() {
|
||||
probe = Some(MediaProbe::new(src.clone()));
|
||||
|
||||
duration = match probe.clone().unwrap().format.unwrap().duration {
|
||||
Some(dur) => dur.parse().unwrap(),
|
||||
None => 0.0,
|
||||
};
|
||||
if let Some(dur) = probe
|
||||
.as_ref()
|
||||
.and_then(|p| p.format.as_ref())
|
||||
.and_then(|f| f.duration.as_ref())
|
||||
{
|
||||
duration = dur.parse().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
@ -103,14 +106,17 @@ impl Media {
|
||||
let probe = MediaProbe::new(self.source.clone());
|
||||
self.probe = Some(probe.clone());
|
||||
|
||||
if self.duration == 0.0 {
|
||||
let duration = match probe.format.unwrap().duration {
|
||||
Some(dur) => dur.parse().unwrap(),
|
||||
None => 0.0,
|
||||
};
|
||||
if let Some(dur) = probe
|
||||
.format
|
||||
.and_then(|f| f.duration)
|
||||
.map(|d| d.parse().unwrap())
|
||||
.filter(|d| !is_close(*d, self.duration, 0.5))
|
||||
{
|
||||
self.duration = dur;
|
||||
|
||||
self.out = duration;
|
||||
self.duration = duration;
|
||||
if self.out == 0.0 {
|
||||
self.out = dur;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,25 +138,22 @@ pub struct MediaProbe {
|
||||
impl MediaProbe {
|
||||
fn new(input: String) -> Self {
|
||||
let probe = ffprobe(&input);
|
||||
let mut a_stream: Vec<Stream> = vec![];
|
||||
let mut v_stream: Vec<Stream> = vec![];
|
||||
let mut a_stream = vec![];
|
||||
let mut v_stream = vec![];
|
||||
|
||||
match probe {
|
||||
Ok(obj) => {
|
||||
for stream in obj.streams {
|
||||
let cp_stream = stream.clone();
|
||||
match cp_stream.codec_type {
|
||||
Some(codec_type) => {
|
||||
if codec_type == "audio" {
|
||||
a_stream.push(stream)
|
||||
} else if codec_type == "video" {
|
||||
v_stream.push(stream)
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
error!("No codec type found for stream: {stream:?}")
|
||||
if let Some(c_type) = cp_stream.codec_type {
|
||||
match c_type.as_str() {
|
||||
"audio" => a_stream.push(stream),
|
||||
"video" => v_stream.push(stream),
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
error!("No codec type found for stream: {stream:?}")
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,15 +190,13 @@ impl MediaProbe {
|
||||
///
|
||||
/// The status file is init in main function and mostly modified in RPC server.
|
||||
pub fn write_status(config: &GlobalConfig, date: &str, shift: f64) {
|
||||
let stat_file = config.general.stat_file.clone();
|
||||
|
||||
let data = json!({
|
||||
"time_shift": shift,
|
||||
"date": date,
|
||||
});
|
||||
|
||||
let status_data: String = serde_json::to_string(&data).expect("Serialize status data failed");
|
||||
if let Err(e) = fs::write(stat_file, &status_data) {
|
||||
if let Err(e) = fs::write(&config.general.stat_file, &status_data) {
|
||||
error!("Unable to write file: {e:?}")
|
||||
};
|
||||
}
|
||||
@ -234,9 +235,7 @@ pub fn get_date(seek: bool, start: f64, next_start: f64) -> String {
|
||||
|
||||
/// Get file modification time.
|
||||
pub fn modified_time(path: &str) -> Option<DateTime<Local>> {
|
||||
let metadata = metadata(path).unwrap();
|
||||
|
||||
if let Ok(time) = metadata.modified() {
|
||||
if let Ok(time) = metadata(path).and_then(|metadata| metadata.modified()) {
|
||||
let date_time: DateTime<Local> = time.into();
|
||||
return Some(date_time);
|
||||
}
|
||||
@ -519,10 +518,11 @@ pub mod mock_time {
|
||||
}
|
||||
|
||||
pub fn set_mock_time(date_time: &str) {
|
||||
let date_obj = NaiveDateTime::parse_from_str(date_time, "%Y-%m-%dT%H:%M:%S");
|
||||
let time = Local.from_local_datetime(&date_obj.unwrap()).unwrap();
|
||||
if let Ok(d) = NaiveDateTime::parse_from_str(date_time, "%Y-%m-%dT%H:%M:%S") {
|
||||
let time = Local.from_local_datetime(&d).unwrap();
|
||||
|
||||
DATE_TIME_DIFF.with(|cell| *cell.borrow_mut() = Some(Local::now() - time));
|
||||
DATE_TIME_DIFF.with(|cell| *cell.borrow_mut() = Some(Local::now() - time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user