rearange file structur, add desktop play

This commit is contained in:
jb-alvarado 2022-02-16 18:27:03 +01:00
parent 92899763f8
commit 5af37c5187
10 changed files with 234 additions and 44 deletions

View File

@ -1,16 +1,16 @@
mod arg_parse;
mod config;
mod output;
mod utils;
// mod folder;
mod json;
use crate::output::desktop;
use crate::utils::get_config;
fn main() {
let config = config::get_config();
let config = get_config();
// println!("{:#?}", config);
// folder::walk(&config.storage.path, config.storage.shuffle, &config.storage.extensions);
json::read(&config);
// read_json(&config);
// let args = arg_parse::get_args();
@ -21,4 +21,6 @@ fn main() {
// println!("{:#?}", utils::get_sec());
// println!("{:#?}", utils::get_timestamp());
desktop::play(config.processing.settings).expect("Play on desktop failed!");
}

92
src/output/desktop.rs Normal file
View File

@ -0,0 +1,92 @@
// use std::io::prelude::*;
use std::{
io,
process::{Command, Stdio},
};
use crate::utils::program;
pub fn play(_settings: Option<Vec<String>>) -> io::Result<()> {
let get_source = program();
let mut enc_proc = Command::new("ffplay")
.args([
"-hide_banner",
"-nostats",
"-v",
"level+error",
"-i",
"pipe:0",
])
.stdin(Stdio::piped())
// .stderr(Stdio::piped())
.spawn()
.unwrap();
// let mut stdin = enc_proc.stdin.unwrap();
// let mut buffer = vec![0; 65376];
if let Some(mut enc_input) = enc_proc.stdin.take() {
for node in get_source {
println!("Play: {}", node.source);
let mut dec_proc = Command::new("ffmpeg")
.args([
"-v",
"level+error",
"-hide_banner",
"-nostats",
"-i",
&node.source,
"-pix_fmt",
"yuv420p",
"-r",
"25",
"-c:v",
"mpeg2video",
"-g",
"1",
"-b:v",
"50000k",
"-minrate",
"50000k",
"-maxrate",
"50000k",
"-bufsize",
"25000k",
"-c:a",
"s302m",
"-strict",
"-2",
"-ar",
"48000",
"-ac",
"2",
"-f",
"mpegts",
"-",
])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
if let Some(mut dec_output) = dec_proc.stdout.take() {
io::copy(&mut dec_output, &mut enc_input).expect("Write to streaming pipe failed!");
dec_proc.wait()?;
let dec_output = dec_proc.wait_with_output()?;
if dec_output.stderr.len() > 0 {
println!("[Encoder] {}", String::from_utf8(dec_output.stderr).unwrap());
}
}
}
enc_proc.wait()?;
let enc_output = enc_proc.wait_with_output()?;
println!("[Encoder] {}", String::from_utf8(enc_output.stderr).unwrap());
}
Ok(())
}

3
src/output/mod.rs Normal file
View File

@ -0,0 +1,3 @@
pub mod desktop;
pub use desktop::play;

View File

@ -17,19 +17,24 @@ pub struct Args {
#[clap(short, long, help = "path from playlist")]
pub playlist: Option<String>,
#[clap(short, long,
help = "start time in 'hh:mm:ss', 'now' for start with first")]
#[clap(
short,
long,
help = "start time in 'hh:mm:ss', 'now' for start with first"
)]
pub start: Option<String>,
#[clap(short = 't',
long, help = "set length in 'hh:mm:ss', 'none' for no length check")]
#[clap(
short = 't',
long,
help = "set length in 'hh:mm:ss', 'none' for no length check"
)]
pub length: Option<String>,
#[clap(short, long, help = "loop playlist infinitely")]
pub infinit: bool,
#[clap(short, long,
help = "set output mode: desktop, hls, stream")]
#[clap(short, long, help = "set output mode: desktop, hls, stream")]
pub output: Option<String>,
#[clap(short, long, help = "set audio volume")]

View File

@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
use serde_yaml::{self};
use std::fs::File;
use std::path::Path;
use std::{fs::File, path::Path, process};
// use regex::Regex;
use crate::arg_parse;
use crate::utils::get_args;
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
@ -62,6 +61,7 @@ pub struct Processing {
pub loud_lra: f32,
pub output_count: u32,
pub volume: String,
pub settings: Option<Vec<String>>,
}
#[derive(Debug, Serialize, Deserialize)]
@ -105,18 +105,61 @@ pub struct Out {
}
pub fn get_config() -> Config {
let args = arg_parse::get_args();
let args = get_args();
let mut config_path: String = "ffplayout.yml".to_string();
if args.config.is_some() {
config_path = args.config.unwrap();
} else if Path::new("/etc/ffplayout/ffplayout.yml").exists() {
} else if Path::new("/etc/ffplayout/ffplayout.yml").is_file() {
config_path = "/etc/ffplayout/ffplayout.yml".to_string();
}
if !Path::new(&config_path).is_file() {
println!(
"{} '{config_path}'\n{}",
"ffplayout config doesn't exists:",
"Put 'ffplayout.yml' in '/etc/playout/' or beside the executable!"
);
process::exit(0x0100);
}
let f = File::open(config_path).expect("Could not open config file.");
let mut config: Config = serde_yaml::from_reader(f)
.expect("Could not read config file.");
let mut config: Config = serde_yaml::from_reader(f).expect("Could not read config file.");
let fps = config.processing.fps.to_string();
let bitrate = config.processing.width * config.processing.height / 10;
let settings: Vec<String> = vec![
"-pix_fmt",
"yuv420p",
"-r",
&fps,
"-c:v",
"mpeg2video",
"-g",
"1",
"-b:v",
format!("{}k", bitrate).as_str(),
"-minrate",
format!("{}k", bitrate).as_str(),
"-maxrate",
format!("{}k", bitrate).as_str(),
"-bufsize",
format!("{}k", bitrate / 2).as_str(),
"-c:a",
"s302m",
"-strict",
"-2",
"-ar",
"48000",
"-ac",
"2",
"-f",
"mpegts",
"-",
].iter().map(|&s|s.into()).collect();
config.processing.settings = Some(settings);
if args.playlist.is_some() {
config.playlist.path = args.playlist.unwrap();

View File

@ -1,13 +1,14 @@
use notify::DebouncedEvent::{Create, Remove, Rename};
use notify::{watcher, RecursiveMode, Watcher};
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::ffi::OsStr;
use std::path::Path;
use std::process;
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::time::Duration;
use std::{thread, time};
use rand::(seq::SliceRandom, thread_rng);
use std::{
ffi::OsStr,
path::Path,
process,
sync::mpsc::{channel, Receiver, TryRecvError},
thread, time,
time::Duration,
};
use walkdir::WalkDir;
#[derive(Clone)]
@ -78,12 +79,12 @@ fn watch_folder(source: &mut Source, receiver: &Receiver<notify::DebouncedEvent>
);
}
_ => (),
}
},
Err(err) => {
if err == TryRecvError::Disconnected {
println!("Folder watch error: {:?}", err)
}
},
}
}
}

View File

@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use std::fs::File;
use std::path::Path;
use crate::config::Config;
use crate::utils::Config;
use crate::utils::{get_date, modified_time};
#[derive(Debug, Serialize, Deserialize)]
@ -12,7 +12,7 @@ pub struct Playlist {
pub program: Vec<Program>,
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Program {
#[serde(rename = "in")]
pub seek: f32,
@ -22,7 +22,7 @@ pub struct Program {
pub source: String,
}
pub fn read(config: &Config) -> Playlist {
pub fn read_json(config: &Config) -> Playlist {
let mut playlist_path = Path::new(&config.playlist.path).to_owned();
let start = &config.playlist.day_start;
@ -48,8 +48,6 @@ pub fn read(config: &Config) -> Playlist {
);
let modify = modified_time(playlist_path.as_path().display().to_string());
println!("{:?}", modify);
let f = File::open(playlist_path).expect("Could not open json playlist file.");
let mut playlist: Playlist =
serde_json::from_reader(f).expect("Could not read json playlist file.");
@ -58,7 +56,5 @@ pub fn read(config: &Config) -> Playlist {
playlist.modified = Some(modify.unwrap().to_string());
}
println!("{:#?}", playlist);
playlist
}

View File

@ -2,12 +2,17 @@ use chrono::prelude::*;
use chrono::Duration;
use std::fs::metadata;
pub fn get_sec() -> f64 {
let local: DateTime<Local> = Local::now();
mod arg_parse;
mod config;
// mod folder;
mod json_reader;
mod playlist;
(local.hour() * 3600 + local.minute() * 60 + local.second()
) as f64 + (local.nanosecond() as f64 / 1000000000.0)
}
pub use arg_parse::get_args;
pub use config::{Config, get_config};
// pub use folder::walk;
pub use json_reader::read_json;
pub use playlist::program;
// pub fn get_timestamp() -> i64 {
// let local: DateTime<Local> = Local::now();
@ -15,15 +20,22 @@ pub fn get_sec() -> f64 {
// local.timestamp_millis() as i64
// }
pub fn get_sec() -> f64 {
let local: DateTime<Local> = Local::now();
(local.hour() * 3600 + local.minute() * 60 + local.second()) as f64
+ (local.nanosecond() as f64 / 1000000000.0)
}
pub fn get_date(seek: bool, start: f64, next: f64) -> String {
let local: DateTime<Local> = Local::now();
if seek && start > get_sec() {
return (local - Duration::days(1)).format("%Y-%m-%d").to_string()
return (local - Duration::days(1)).format("%Y-%m-%d").to_string();
}
if start == 0.0 && next >= 86400.0 {
return (local + Duration::days(1)).format("%Y-%m-%d").to_string()
return (local + Duration::days(1)).format("%Y-%m-%d").to_string();
}
local.format("%Y-%m-%d").to_string()
@ -34,7 +46,7 @@ pub fn modified_time(path: String) -> Option<DateTime<Local>> {
if let Ok(time) = metadata.modified() {
let date_time: DateTime<Local> = time.into();
return Some(date_time)
return Some(date_time);
}
None

36
src/utils/playlist.rs Normal file
View File

@ -0,0 +1,36 @@
use crate::utils::get_config;
use crate::utils::json_reader::{Program, read_json};
pub struct CurrentProgram {
nodes: Vec<Program>,
idx: usize,
}
impl Iterator for CurrentProgram {
type Item = Program;
fn next(&mut self) -> Option<Self::Item> {
if self.idx == self.nodes.len() - 1 {
let current = self.nodes[self.idx].clone();
self.idx = 0;
Some(current)
} else {
let current = self.nodes[self.idx].clone();
self.idx += 1;
Some(current)
}
}
}
pub fn program() -> CurrentProgram {
let config = get_config();
let program: Vec<Program> = read_json(&config).program;
CurrentProgram {
nodes: program,
idx: 0,
}
}