fix 3 cases:
1. when playlist is to short, fill with dummy 2. when next playlist not exists 3. when in the middle of playling the current playlist disappeare
This commit is contained in:
parent
bffd296ddc
commit
82a9def158
@ -105,7 +105,6 @@ pub fn play(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for node in get_source {
|
for node in get_source {
|
||||||
// println!("Node begin: {:?}", sec_to_time(node.begin.unwrap()));
|
|
||||||
let cmd = match node.cmd {
|
let cmd = match node.cmd {
|
||||||
Some(cmd) => cmd,
|
Some(cmd) => cmd,
|
||||||
None => break
|
None => break
|
||||||
|
@ -3,44 +3,66 @@ use std::{fs::File, path::Path};
|
|||||||
|
|
||||||
use simplelog::*;
|
use simplelog::*;
|
||||||
|
|
||||||
use crate::utils::{get_date, modified_time, seek_and_length, time_to_sec, Config, Media};
|
use crate::utils::{get_date, get_sec, modified_time, seek_and_length, time_to_sec, Config, Media};
|
||||||
|
|
||||||
|
pub const DUMMY_LEN: f64 = 20.0;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Playlist {
|
pub struct Playlist {
|
||||||
pub date: String,
|
pub date: String,
|
||||||
pub start_sec: Option<f64>,
|
pub start_sec: Option<f64>,
|
||||||
pub current_file: Option<String>,
|
pub current_file: Option<String>,
|
||||||
pub start_index: Option<usize>,
|
|
||||||
pub modified: Option<String>,
|
pub modified: Option<String>,
|
||||||
pub program: Vec<Media>,
|
pub program: Vec<Media>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Playlist {
|
||||||
|
fn new(date: String, start: f64) -> Self {
|
||||||
|
let mut media = Media::new(0, "".to_string());
|
||||||
|
media.begin = Some(start);
|
||||||
|
media.duration = DUMMY_LEN;
|
||||||
|
media.out = DUMMY_LEN;
|
||||||
|
Self {
|
||||||
|
date,
|
||||||
|
start_sec: Some(start),
|
||||||
|
current_file: None,
|
||||||
|
modified: None,
|
||||||
|
program: vec![media],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_json(config: &Config, seek: bool, next_start: f64) -> Playlist {
|
pub fn read_json(config: &Config, seek: bool, next_start: f64) -> Playlist {
|
||||||
let mut playlist_path = Path::new(&config.playlist.path).to_owned();
|
let mut playlist_path = Path::new(&config.playlist.path).to_owned();
|
||||||
let start = &config.playlist.day_start;
|
let start = &config.playlist.day_start;
|
||||||
let mut start_sec = time_to_sec(start);
|
let mut start_sec = time_to_sec(start);
|
||||||
|
let date = get_date(seek, start_sec, next_start);
|
||||||
|
|
||||||
if playlist_path.is_dir() {
|
if playlist_path.is_dir() {
|
||||||
let date = get_date(seek, start_sec, next_start);
|
|
||||||
let d: Vec<&str> = date.split('-').collect();
|
let d: Vec<&str> = date.split('-').collect();
|
||||||
playlist_path = playlist_path
|
playlist_path = playlist_path
|
||||||
.join(d[0])
|
.join(d[0])
|
||||||
.join(d[1])
|
.join(d[1])
|
||||||
.join(date)
|
.join(date.clone())
|
||||||
.with_extension("json");
|
.with_extension("json");
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_file: String = playlist_path.as_path().display().to_string();
|
let current_file: String = playlist_path.as_path().display().to_string();
|
||||||
|
|
||||||
|
if !playlist_path.is_file() {
|
||||||
|
error!("Playlist <b><magenta>{}</></b> not exists!", current_file);
|
||||||
|
return Playlist::new(date, get_sec());
|
||||||
|
}
|
||||||
|
|
||||||
info!("Read Playlist: <b><magenta>{}</></b>", ¤t_file);
|
info!("Read Playlist: <b><magenta>{}</></b>", ¤t_file);
|
||||||
|
|
||||||
let modify = modified_time(current_file.clone());
|
|
||||||
let f = File::open(¤t_file).expect("Could not open json playlist file.");
|
let f = File::open(¤t_file).expect("Could not open json playlist file.");
|
||||||
let mut playlist: Playlist =
|
let mut playlist: Playlist =
|
||||||
serde_json::from_reader(f).expect("Could not read json playlist file.");
|
serde_json::from_reader(f).expect("Could not read json playlist file.");
|
||||||
|
|
||||||
playlist.current_file = Some(current_file);
|
playlist.current_file = Some(current_file.clone());
|
||||||
playlist.start_sec = Some(start_sec.clone());
|
playlist.start_sec = Some(start_sec.clone());
|
||||||
|
let modify = modified_time(current_file);
|
||||||
|
|
||||||
if modify.is_some() {
|
if modify.is_some() {
|
||||||
playlist.modified = Some(modify.unwrap().to_string());
|
playlist.modified = Some(modify.unwrap().to_string());
|
||||||
|
@ -16,7 +16,7 @@ mod playlist;
|
|||||||
pub use arg_parse::get_args;
|
pub use arg_parse::get_args;
|
||||||
pub use config::{get_config, Config};
|
pub use config::{get_config, Config};
|
||||||
pub use folder::{watch_folder, Source};
|
pub use folder::{watch_folder, Source};
|
||||||
pub use json_reader::read_json;
|
pub use json_reader::{read_json, DUMMY_LEN};
|
||||||
pub use logging::init_logging;
|
pub use logging::init_logging;
|
||||||
pub use playlist::CurrentProgram;
|
pub use playlist::CurrentProgram;
|
||||||
|
|
||||||
@ -213,14 +213,14 @@ pub fn is_close(a: f64, b: f64, to: f64) -> bool {
|
|||||||
|
|
||||||
pub fn get_delta(begin: &f64, config: &Config) -> (f64, f64) {
|
pub fn get_delta(begin: &f64, config: &Config) -> (f64, f64) {
|
||||||
let mut current_time = get_sec();
|
let mut current_time = get_sec();
|
||||||
let start = time_to_sec(&config.playlist.day_start);
|
let mut tmp_time = current_time.clone();
|
||||||
|
let start = config.playlist.start_sec.unwrap();
|
||||||
let length = time_to_sec(&config.playlist.length);
|
let length = time_to_sec(&config.playlist.length);
|
||||||
let mut target_length = 86400.0;
|
let mut target_length = 86400.0;
|
||||||
|
|
||||||
if length > 0.0 && length != target_length {
|
if length > 0.0 && length != target_length {
|
||||||
target_length = length
|
target_length = length
|
||||||
}
|
}
|
||||||
|
|
||||||
if begin == &start && start == 0.0 && 86400.0 - current_time < 4.0 {
|
if begin == &start && start == 0.0 && 86400.0 - current_time < 4.0 {
|
||||||
current_time -= target_length
|
current_time -= target_length
|
||||||
} else if start >= current_time && begin != &start {
|
} else if start >= current_time && begin != &start {
|
||||||
@ -233,8 +233,12 @@ pub fn get_delta(begin: &f64, config: &Config) -> (f64, f64) {
|
|||||||
current_delta -= 86400.0
|
current_delta -= 86400.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tmp_time <= start + current_delta.abs() {
|
||||||
|
tmp_time += target_length
|
||||||
|
}
|
||||||
|
|
||||||
let ref_time = target_length + start;
|
let ref_time = target_length + start;
|
||||||
let total_delta = ref_time - begin + current_delta;
|
let total_delta = ref_time - tmp_time;
|
||||||
|
|
||||||
(current_delta, total_delta)
|
(current_delta, total_delta)
|
||||||
}
|
}
|
||||||
@ -265,7 +269,7 @@ pub fn gen_dummy(duration: f64, config: &Config) -> (String, Vec<String>) {
|
|||||||
"-f".to_string(),
|
"-f".to_string(),
|
||||||
"lavfi".to_string(),
|
"lavfi".to_string(),
|
||||||
"-i".to_string(),
|
"-i".to_string(),
|
||||||
format!("anoisesrc=d={duration}:c=pink:r=48000:a=0.05"),
|
format!("anoisesrc=d={duration}:c=pink:r=48000:a=0.3"),
|
||||||
];
|
];
|
||||||
|
|
||||||
(source, cmd)
|
(source, cmd)
|
||||||
|
@ -4,7 +4,7 @@ use simplelog::*;
|
|||||||
|
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
check_sync, gen_dummy, get_delta, get_sec, json_reader::read_json, modified_time,
|
check_sync, gen_dummy, get_delta, get_sec, json_reader::read_json, modified_time,
|
||||||
seek_and_length, time_to_sec, Config, Media,
|
seek_and_length, time_to_sec, Config, Media, DUMMY_LEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -12,7 +12,7 @@ pub struct CurrentProgram {
|
|||||||
config: Config,
|
config: Config,
|
||||||
start_sec: f64,
|
start_sec: f64,
|
||||||
json_mod: String,
|
json_mod: String,
|
||||||
json_path: String,
|
json_path: Option<String>,
|
||||||
nodes: Vec<Media>,
|
nodes: Vec<Media>,
|
||||||
current_node: Media,
|
current_node: Media,
|
||||||
init: bool,
|
init: bool,
|
||||||
@ -24,11 +24,11 @@ impl CurrentProgram {
|
|||||||
let json = read_json(&config, true, 0.0);
|
let json = read_json(&config, true, 0.0);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
config: config,
|
config,
|
||||||
start_sec: json.start_sec.unwrap(),
|
start_sec: json.start_sec.unwrap(),
|
||||||
json_mod: json.modified.unwrap(),
|
json_mod: json.modified.unwrap(),
|
||||||
json_path: json.current_file.unwrap(),
|
json_path: Some(json.current_file.unwrap()),
|
||||||
nodes: json.program.into(),
|
nodes: json.program,
|
||||||
current_node: Media::new(0, "".to_string()),
|
current_node: Media::new(0, "".to_string()),
|
||||||
init: true,
|
init: true,
|
||||||
index: 0,
|
index: 0,
|
||||||
@ -36,7 +36,10 @@ impl CurrentProgram {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_update(&mut self) {
|
fn check_update(&mut self) {
|
||||||
let mod_time = modified_time(self.json_path.clone());
|
match self.json_path.clone() {
|
||||||
|
Some(path) => {
|
||||||
|
if Path::new(&path).is_file() {
|
||||||
|
let mod_time = modified_time(path);
|
||||||
|
|
||||||
if !mod_time.unwrap().to_string().eq(&self.json_mod) {
|
if !mod_time.unwrap().to_string().eq(&self.json_mod) {
|
||||||
// when playlist has changed, reload it
|
// when playlist has changed, reload it
|
||||||
@ -45,6 +48,24 @@ impl CurrentProgram {
|
|||||||
self.json_mod = json.modified.unwrap();
|
self.json_mod = json.modified.unwrap();
|
||||||
self.nodes = json.program.into();
|
self.nodes = json.program.into();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
error!("Playlist <b><magenta>{}</></b> not exists!", path);
|
||||||
|
let mut media = Media::new(0, "".to_string());
|
||||||
|
media.begin = Some(get_sec());
|
||||||
|
media.duration = DUMMY_LEN;
|
||||||
|
media.out = DUMMY_LEN;
|
||||||
|
|
||||||
|
self.json_path = None;
|
||||||
|
self.nodes = vec![media.clone()];
|
||||||
|
self.current_node = media;
|
||||||
|
self.init = true;
|
||||||
|
self.index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_for_next_playlist(&mut self, last: bool) {
|
fn check_for_next_playlist(&mut self, last: bool) {
|
||||||
@ -112,13 +133,8 @@ impl CurrentProgram {
|
|||||||
self.current_node.cmd = None;
|
self.current_node.cmd = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for CurrentProgram {
|
fn get_init_clip(&mut self) {
|
||||||
type Item = Media;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.init {
|
|
||||||
let mut time_sec = get_sec();
|
let mut time_sec = get_sec();
|
||||||
let length = self.config.playlist.length.clone();
|
let length = self.config.playlist.length.clone();
|
||||||
let mut length_sec: f64 = 86400.0;
|
let mut length_sec: f64 = 86400.0;
|
||||||
@ -145,17 +161,47 @@ impl Iterator for CurrentProgram {
|
|||||||
item.duration,
|
item.duration,
|
||||||
));
|
));
|
||||||
self.current_node = handle_list_init(item.clone(), &self.config);
|
self.current_node = handle_list_init(item.clone(), &self.config);
|
||||||
self.current_node.last_ad = self.is_ad(i, false);
|
break
|
||||||
self.current_node.next_ad = self.is_ad(i, false);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
start_sec += item.out - item.seek;
|
start_sec += item.out - item.seek;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.init {
|
|
||||||
return Some(self.current_node.clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Iterator for CurrentProgram {
|
||||||
|
type Item = Media;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.init {
|
||||||
|
debug!("Playlist init");
|
||||||
|
|
||||||
|
if self.json_path.is_some() {
|
||||||
|
self.get_init_clip();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.init {
|
||||||
|
let json = read_json(&self.config, false, get_sec() + DUMMY_LEN);
|
||||||
|
|
||||||
|
if json.current_file.is_some() {
|
||||||
|
self.json_mod = json.modified.unwrap();
|
||||||
|
self.json_path = Some(json.current_file.unwrap());
|
||||||
|
self.nodes = json.program;
|
||||||
|
self.get_init_clip();
|
||||||
|
} else {
|
||||||
|
let mut media = Media::new(0, "".to_string());
|
||||||
|
media.begin = Some(get_sec());
|
||||||
|
media.duration = DUMMY_LEN;
|
||||||
|
media.out = DUMMY_LEN;
|
||||||
|
|
||||||
|
self.current_node = gen_source(media, &self.config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_node.last_ad = self.is_ad(self.index, false);
|
||||||
|
self.current_node.next_ad = self.is_ad(self.index, false);
|
||||||
|
|
||||||
|
return Some(self.current_node.clone());
|
||||||
|
}
|
||||||
if self.index < self.nodes.len() {
|
if self.index < self.nodes.len() {
|
||||||
self.check_update();
|
self.check_update();
|
||||||
|
|
||||||
@ -168,16 +214,20 @@ impl Iterator for CurrentProgram {
|
|||||||
self.check_for_next_playlist(false);
|
self.check_for_next_playlist(false);
|
||||||
Some(self.current_node.clone())
|
Some(self.current_node.clone())
|
||||||
} else {
|
} else {
|
||||||
let (_, time_diff) = get_delta(&get_sec(), &self.config);
|
let (_, time_diff) = get_delta(&self.config.playlist.start_sec.unwrap(), &self.config);
|
||||||
let mut last_ad = self.is_ad(self.index, false);
|
let mut last_ad = self.is_ad(self.index, false);
|
||||||
|
|
||||||
|
// println!("delta: {:?} | time_diff: {:?}", delta, time_diff);
|
||||||
|
|
||||||
if time_diff.abs() > self.config.general.stop_threshold {
|
if time_diff.abs() > self.config.general.stop_threshold {
|
||||||
|
// Test if playlist is to early finish,
|
||||||
|
// and if we have to fill it with a placeholder.
|
||||||
self.current_node = Media::new(self.index + 1, "".to_string());
|
self.current_node = Media::new(self.index + 1, "".to_string());
|
||||||
self.current_node.begin = Some(get_sec());
|
self.current_node.begin = Some(get_sec());
|
||||||
let mut duration = time_diff.abs();
|
let mut duration = time_diff.abs();
|
||||||
|
|
||||||
if duration > 60.0 {
|
if duration > DUMMY_LEN {
|
||||||
duration = 60.0;
|
duration = DUMMY_LEN;
|
||||||
}
|
}
|
||||||
self.current_node.duration = duration;
|
self.current_node.duration = duration;
|
||||||
self.current_node.out = duration;
|
self.current_node.out = duration;
|
||||||
@ -191,12 +241,23 @@ impl Iterator for CurrentProgram {
|
|||||||
return Some(self.current_node.clone());
|
return Some(self.current_node.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let json = read_json(&self.config, false, 0.0);
|
let next_begin =
|
||||||
self.json_mod = json.modified.unwrap();
|
self.current_node.begin.unwrap() + self.current_node.out - self.current_node.seek;
|
||||||
self.json_path = json.current_file.unwrap();
|
|
||||||
self.nodes = json.program.into();
|
|
||||||
|
|
||||||
self.get_current_node(0);
|
// Here we should end up, when we need a new playlist
|
||||||
|
let json = read_json(&self.config, false, next_begin);
|
||||||
|
|
||||||
|
if json.current_file.is_none() {
|
||||||
|
self.init = true;
|
||||||
|
self.json_path = None;
|
||||||
|
self.nodes = json.program;
|
||||||
|
} else {
|
||||||
|
self.json_mod = json.modified.unwrap();
|
||||||
|
self.json_path = Some(json.current_file.unwrap());
|
||||||
|
self.nodes = json.program;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_node = gen_source(self.nodes[0].clone(), &self.config);
|
||||||
self.current_node.last_ad = last_ad;
|
self.current_node.last_ad = last_ad;
|
||||||
self.current_node.next_ad = self.is_ad(0, false);
|
self.current_node.next_ad = self.is_ad(0, false);
|
||||||
|
|
||||||
@ -218,6 +279,7 @@ fn timed_source(node: Media, config: &Config, last: bool) -> Media {
|
|||||||
|
|
||||||
if config.playlist.length.contains(":") {
|
if config.playlist.length.contains(":") {
|
||||||
debug!("Delta: <yellow>{delta}</>");
|
debug!("Delta: <yellow>{delta}</>");
|
||||||
|
debug!("Total delta: <yellow>{total_delta}</>");
|
||||||
check_sync(delta, &config);
|
check_sync(delta, &config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +305,7 @@ fn gen_source(mut node: Media, config: &Config) -> Media {
|
|||||||
} else {
|
} else {
|
||||||
if node.source.chars().count() == 0 {
|
if node.source.chars().count() == 0 {
|
||||||
warn!(
|
warn!(
|
||||||
"Generate filler with <yellow>{}</> seconds length!",
|
"Generate filler with <yellow>{:.2}</> seconds length!",
|
||||||
node.out - node.seek
|
node.out - node.seek
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -262,8 +324,6 @@ fn handle_list_init(mut node: Media, config: &Config) -> Media {
|
|||||||
// handle init clip, but this clip can be the last one in playlist,
|
// handle init clip, but this clip can be the last one in playlist,
|
||||||
// this we have to figure out and calculate the right length
|
// this we have to figure out and calculate the right length
|
||||||
|
|
||||||
debug!("Playlist init");
|
|
||||||
|
|
||||||
let (_, total_delta) = get_delta(&node.begin.unwrap(), config);
|
let (_, total_delta) = get_delta(&node.begin.unwrap(), config);
|
||||||
let mut out = node.out;
|
let mut out = node.out;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user