rearange file structur, add desktop play
This commit is contained in:
parent
92899763f8
commit
5af37c5187
14
src/main.rs
14
src/main.rs
@ -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
92
src/output/desktop.rs
Normal 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
3
src/output/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod desktop;
|
||||
|
||||
pub use desktop::play;
|
@ -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")]
|
@ -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();
|
@ -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)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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
36
src/utils/playlist.rs
Normal 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,
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user