support path list for playlist generation, #258

This commit is contained in:
jb-alvarado 2023-01-22 14:17:51 +01:00
parent af985cb351
commit e752a7a951
7 changed files with 73 additions and 30 deletions

View File

@ -34,7 +34,7 @@ use crate::utils::{
errors::ServiceError, errors::ServiceError,
files::{ files::{
browser, create_directory, remove_file_or_folder, rename_file, upload, MoveObject, browser, create_directory, remove_file_or_folder, rename_file, upload, MoveObject,
PathObject, PathObject, norm_abs_path,
}, },
naive_date_time_from_str, naive_date_time_from_str,
playlist::{delete_playlist, generate_playlist, read_playlist, write_playlist}, playlist::{delete_playlist, generate_playlist, read_playlist, write_playlist},
@ -72,6 +72,12 @@ struct FileObj {
path: String, path: String,
} }
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct PathsObj {
#[serde(default)]
paths: Vec<String>,
}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct ImportObj { pub struct ImportObj {
#[serde(default)] #[serde(default)]
@ -734,16 +740,33 @@ pub async fn save_playlist(
/// A new playlist will be generated and response. /// A new playlist will be generated and response.
/// ///
/// ```BASH /// ```BASH
/// curl -X GET http://127.0.0.1:8787/api/playlist/1/generate/2022-06-20 /// curl -X POST http://127.0.0.1:8787/api/playlist/1/generate/2022-06-20
/// -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' /// -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>'
/// /// -- data '{ "paths": [<list of paths>] }' # <- data is optional
/// ``` /// ```
#[get("/playlist/{id}/generate/{date}")] #[post("/playlist/{id}/generate/{date}")]
#[has_any_role("Role::Admin", "Role::User", type = "Role")] #[has_any_role("Role::Admin", "Role::User", type = "Role")]
pub async fn gen_playlist( pub async fn gen_playlist(
pool: web::Data<Pool<Sqlite>>, pool: web::Data<Pool<Sqlite>>,
params: web::Path<(i32, String)>, params: web::Path<(i32, String)>,
data: Option<web::Json<PathsObj>>,
) -> Result<impl Responder, ServiceError> { ) -> Result<impl Responder, ServiceError> {
match generate_playlist(&pool.into_inner(), params.0, params.1.clone()).await { let (mut config, channel) = playout_config(&pool.into_inner(), &params.0).await?;
config.general.generate = Some(vec![params.1.clone()]);
if let Some(obj) = data {
let mut path_list = vec![];
for path in &obj.paths {
let (p, _, _) = norm_abs_path(&config.storage.path, &path);
path_list.push(p.to_string_lossy().to_string());
}
config.storage.paths = path_list;
}
match generate_playlist(config, channel.name).await {
Ok(playlist) => Ok(web::Json(playlist)), Ok(playlist) => Ok(web::Json(playlist)),
Err(e) => Err(e), Err(e) => Err(e),
} }

View File

@ -49,7 +49,7 @@ pub struct VideoFile {
/// ///
/// This function takes care, that it is not possible to break out from root_path. /// This function takes care, that it is not possible to break out from root_path.
/// It also gives alway a relative path back. /// It also gives alway a relative path back.
fn norm_abs_path(root_path: &str, input_path: &str) -> (PathBuf, String, String) { pub fn norm_abs_path(root_path: &str, input_path: &str) -> (PathBuf, String, String) {
let mut path = PathBuf::from(root_path); let mut path = PathBuf::from(root_path);
let path_relative = RelativePath::new(root_path) let path_relative = RelativePath::new(root_path)
.normalize() .normalize()

View File

@ -5,7 +5,7 @@ use sqlx::{Pool, Sqlite};
use crate::utils::{errors::ServiceError, playout_config}; use crate::utils::{errors::ServiceError, playout_config};
use ffplayout_lib::utils::{ use ffplayout_lib::utils::{
generate_playlist as playlist_generator, json_reader, json_writer, JsonPlaylist, generate_playlist as playlist_generator, json_reader, json_writer, JsonPlaylist, PlayoutConfig,
}; };
pub async fn read_playlist( pub async fn read_playlist(
@ -78,14 +78,10 @@ pub async fn write_playlist(
} }
pub async fn generate_playlist( pub async fn generate_playlist(
conn: &Pool<Sqlite>, config: PlayoutConfig,
id: i32, channel: String,
date: String,
) -> Result<JsonPlaylist, ServiceError> { ) -> Result<JsonPlaylist, ServiceError> {
let (mut config, channel) = playout_config(conn, &id).await?; match playlist_generator(&config, Some(channel)) {
config.general.generate = Some(vec![date.clone()]);
match playlist_generator(&config, Some(channel.name)) {
Ok(playlists) => { Ok(playlists) => {
if !playlists.is_empty() { if !playlists.is_empty() {
Ok(playlists[0].clone()) Ok(playlists[0].clone())

View File

@ -27,6 +27,13 @@ pub struct Args {
)] )]
pub generate: Option<Vec<String>>, pub generate: Option<Vec<String>>,
#[clap(
long,
help = "Optional path list for playlist generations",
multiple_values = true
)]
pub paths: Option<Vec<String>>,
#[clap(short = 'm', long, help = "Playing mode: folder, playlist")] #[clap(short = 'm', long, help = "Playing mode: folder, playlist")]
pub play_mode: Option<ProcessMode>, pub play_mode: Option<ProcessMode>,
@ -46,7 +53,7 @@ pub struct Args {
)] )]
pub import: Option<String>, pub import: Option<String>,
#[clap(short, long, help = "Path from playlist")] #[clap(short, long, help = "Path to playlist, or playlist root folder.")]
pub playlist: Option<String>, pub playlist: Option<String>,
#[clap( #[clap(

View File

@ -38,6 +38,10 @@ pub fn get_config(args: Args) -> PlayoutConfig {
config.general.generate = Some(gen); config.general.generate = Some(gen);
} }
if let Some(paths) = args.paths {
config.storage.paths = paths;
}
if let Some(log_path) = args.log { if let Some(log_path) = args.log {
if Path::new(&log_path).is_dir() { if Path::new(&log_path).is_dir() {
config.logging.log_to_file = true; config.logging.log_to_file = true;

View File

@ -213,6 +213,8 @@ pub struct Playlist {
pub struct Storage { pub struct Storage {
pub help_text: String, pub help_text: String,
pub path: String, pub path: String,
#[serde(skip_serializing, skip_deserializing)]
pub paths: Vec<String>,
pub filler_clip: String, pub filler_clip: String,
pub extensions: Vec<String>, pub extensions: Vec<String>,
pub shuffle: bool, pub shuffle: bool,

View File

@ -32,18 +32,28 @@ impl FolderSource {
current_list: Arc<Mutex<Vec<Media>>>, current_list: Arc<Mutex<Vec<Media>>>,
global_index: Arc<AtomicUsize>, global_index: Arc<AtomicUsize>,
) -> Self { ) -> Self {
let mut path_list = vec![];
let mut media_list = vec![]; let mut media_list = vec![];
let mut index: usize = 0; let mut index: usize = 0;
if !Path::new(&config.storage.path).is_dir() { if config.general.generate.is_some() && !config.storage.paths.is_empty() {
for path in &config.storage.paths {
path_list.push(path.clone())
}
} else {
path_list.push(config.storage.path.clone())
}
for path in &path_list {
if !Path::new(path).is_dir() {
error!( error!(
"Path not exists: <b><magenta>{}</></b>", "Path not exists: <b><magenta>{}</></b>",
config.storage.path path
); );
exit(1); exit(1);
} }
for entry in WalkDir::new(config.storage.path.clone()) for entry in WalkDir::new(path.clone())
.into_iter() .into_iter()
.flat_map(|e| e.ok()) .flat_map(|e| e.ok())
.filter(|f| f.path().is_file()) .filter(|f| f.path().is_file())
@ -53,11 +63,12 @@ impl FolderSource {
media_list.push(media); media_list.push(media);
} }
} }
}
if media_list.is_empty() { if media_list.is_empty() {
error!( error!(
"no playable files found under: <b><magenta>{}</></b>", "no playable files found under: <b><magenta>{:?}</></b>",
config.storage.path path_list
); );
exit(1); exit(1);