Merge pull request #261 from jb-alvarado/nuxt3-frontend
support path list for playlist generation, #258
This commit is contained in:
commit
375ff39b38
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -963,7 +963,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ffplayout"
|
||||
version = "0.17.0-beta1"
|
||||
version = "0.17.0-beta2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
@ -983,7 +983,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ffplayout-api"
|
||||
version = "0.8.4"
|
||||
version = "0.9.0-beta1"
|
||||
dependencies = [
|
||||
"actix-files",
|
||||
"actix-multipart",
|
||||
@ -1015,7 +1015,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ffplayout-lib"
|
||||
version = "0.17.0-beta1"
|
||||
version = "0.17.0-beta2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossbeam-channel",
|
||||
|
@ -4,7 +4,7 @@ description = "Rest API for ffplayout"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Jonathan Baecker jonbae77@gmail.com"]
|
||||
readme = "README.md"
|
||||
version = "0.8.4"
|
||||
version = "0.9.0-beta1"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -33,8 +33,8 @@ use crate::utils::{
|
||||
control::{control_service, control_state, media_info, send_message, Process},
|
||||
errors::ServiceError,
|
||||
files::{
|
||||
browser, create_directory, remove_file_or_folder, rename_file, upload, MoveObject,
|
||||
PathObject,
|
||||
browser, create_directory, norm_abs_path, remove_file_or_folder, rename_file, upload,
|
||||
MoveObject, PathObject,
|
||||
},
|
||||
naive_date_time_from_str,
|
||||
playlist::{delete_playlist, generate_playlist, read_playlist, write_playlist},
|
||||
@ -72,6 +72,12 @@ struct FileObj {
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
pub struct PathsObj {
|
||||
#[serde(default)]
|
||||
paths: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct ImportObj {
|
||||
#[serde(default)]
|
||||
@ -734,16 +740,33 @@ pub async fn save_playlist(
|
||||
/// A new playlist will be generated and response.
|
||||
///
|
||||
/// ```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>'
|
||||
/// /// -- 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")]
|
||||
pub async fn gen_playlist(
|
||||
pool: web::Data<Pool<Sqlite>>,
|
||||
params: web::Path<(i32, String)>,
|
||||
data: Option<web::Json<PathsObj>>,
|
||||
) -> 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(), ¶ms.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)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ pub struct PathObject {
|
||||
parent: Option<String>,
|
||||
folders: Option<Vec<String>>,
|
||||
files: Option<Vec<VideoFile>>,
|
||||
#[serde(default)]
|
||||
pub folders_only: bool,
|
||||
}
|
||||
|
||||
impl PathObject {
|
||||
@ -29,6 +31,7 @@ impl PathObject {
|
||||
parent,
|
||||
folders: Some(vec![]),
|
||||
files: Some(vec![]),
|
||||
folders_only: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,7 +52,7 @@ pub struct VideoFile {
|
||||
///
|
||||
/// This function takes care, that it is not possible to break out from root_path.
|
||||
/// 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 path_relative = RelativePath::new(root_path)
|
||||
.normalize()
|
||||
@ -105,6 +108,7 @@ pub async fn browser(
|
||||
|
||||
let (path, parent, path_component) = norm_abs_path(&config.storage.path, &path_obj.source);
|
||||
let mut obj = PathObject::new(path_component, Some(parent));
|
||||
obj.folders_only = path_obj.folders_only;
|
||||
|
||||
let mut paths: Vec<PathBuf> = match fs::read_dir(path) {
|
||||
Ok(p) => p.filter_map(|r| r.ok()).map(|p| p.path()).collect(),
|
||||
@ -126,7 +130,7 @@ pub async fn browser(
|
||||
|
||||
if path.is_dir() {
|
||||
folders.push(path.file_name().unwrap().to_string_lossy().to_string());
|
||||
} else if path.is_file() {
|
||||
} else if path.is_file() && !path_obj.folders_only {
|
||||
if let Some(ext) = file_extension(&path) {
|
||||
if extensions.contains(&ext.to_string().to_lowercase()) {
|
||||
let media = MediaProbe::new(&path.display().to_string());
|
||||
|
@ -5,7 +5,7 @@ use sqlx::{Pool, Sqlite};
|
||||
|
||||
use crate::utils::{errors::ServiceError, playout_config};
|
||||
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(
|
||||
@ -78,14 +78,10 @@ pub async fn write_playlist(
|
||||
}
|
||||
|
||||
pub async fn generate_playlist(
|
||||
conn: &Pool<Sqlite>,
|
||||
id: i32,
|
||||
date: String,
|
||||
config: PlayoutConfig,
|
||||
channel: String,
|
||||
) -> Result<JsonPlaylist, ServiceError> {
|
||||
let (mut config, channel) = playout_config(conn, &id).await?;
|
||||
config.general.generate = Some(vec![date.clone()]);
|
||||
|
||||
match playlist_generator(&config, Some(channel.name)) {
|
||||
match playlist_generator(&config, Some(channel)) {
|
||||
Ok(playlists) => {
|
||||
if !playlists.is_empty() {
|
||||
Ok(playlists[0].clone())
|
||||
|
@ -4,7 +4,7 @@ description = "24/7 playout based on rust and ffmpeg"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Jonathan Baecker jonbae77@gmail.com"]
|
||||
readme = "README.md"
|
||||
version = "0.17.0-beta1"
|
||||
version = "0.17.0-beta2"
|
||||
edition = "2021"
|
||||
default-run = "ffplayout"
|
||||
|
||||
|
@ -27,6 +27,13 @@ pub struct Args {
|
||||
)]
|
||||
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")]
|
||||
pub play_mode: Option<ProcessMode>,
|
||||
|
||||
@ -46,7 +53,7 @@ pub struct Args {
|
||||
)]
|
||||
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>,
|
||||
|
||||
#[clap(
|
||||
|
@ -38,6 +38,10 @@ pub fn get_config(args: Args) -> PlayoutConfig {
|
||||
config.general.generate = Some(gen);
|
||||
}
|
||||
|
||||
if let Some(paths) = args.paths {
|
||||
config.storage.paths = paths;
|
||||
}
|
||||
|
||||
if let Some(log_path) = args.log {
|
||||
if Path::new(&log_path).is_dir() {
|
||||
config.logging.log_to_file = true;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 072002c68451a5e7e62046a72ddac1d4bae7fcea
|
||||
Subproject commit 92c7a8b041c897fe9ed4819a61c500e61fc5318f
|
@ -4,7 +4,7 @@ description = "Library for ffplayout"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Jonathan Baecker jonbae77@gmail.com"]
|
||||
readme = "README.md"
|
||||
version = "0.17.0-beta1"
|
||||
version = "0.17.0-beta2"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -213,6 +213,8 @@ pub struct Playlist {
|
||||
pub struct Storage {
|
||||
pub help_text: String,
|
||||
pub path: String,
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub paths: Vec<String>,
|
||||
pub filler_clip: String,
|
||||
pub extensions: Vec<String>,
|
||||
pub shuffle: bool,
|
||||
|
@ -1,6 +1,5 @@
|
||||
use std::{
|
||||
path::Path,
|
||||
process::exit,
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
{Arc, Mutex},
|
||||
@ -32,35 +31,40 @@ impl FolderSource {
|
||||
current_list: Arc<Mutex<Vec<Media>>>,
|
||||
global_index: Arc<AtomicUsize>,
|
||||
) -> Self {
|
||||
let mut path_list = vec![];
|
||||
let mut media_list = vec![];
|
||||
let mut index: usize = 0;
|
||||
|
||||
if !Path::new(&config.storage.path).is_dir() {
|
||||
error!(
|
||||
"Path not exists: <b><magenta>{}</></b>",
|
||||
config.storage.path
|
||||
);
|
||||
exit(1);
|
||||
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 entry in WalkDir::new(config.storage.path.clone())
|
||||
.into_iter()
|
||||
.flat_map(|e| e.ok())
|
||||
.filter(|f| f.path().is_file())
|
||||
{
|
||||
if include_file(config.clone(), entry.path()) {
|
||||
let media = Media::new(0, &entry.path().to_string_lossy(), false);
|
||||
media_list.push(media);
|
||||
for path in &path_list {
|
||||
if !Path::new(path).is_dir() {
|
||||
error!("Path not exists: <b><magenta>{path}</></b>");
|
||||
}
|
||||
|
||||
for entry in WalkDir::new(path.clone())
|
||||
.into_iter()
|
||||
.flat_map(|e| e.ok())
|
||||
.filter(|f| f.path().is_file())
|
||||
{
|
||||
if include_file(config.clone(), entry.path()) {
|
||||
let media = Media::new(0, &entry.path().to_string_lossy(), false);
|
||||
media_list.push(media);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if media_list.is_empty() {
|
||||
error!(
|
||||
"no playable files found under: <b><magenta>{}</></b>",
|
||||
config.storage.path
|
||||
"no playable files found under: <b><magenta>{:?}</></b>",
|
||||
path_list
|
||||
);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if config.storage.shuffle {
|
||||
|
Loading…
x
Reference in New Issue
Block a user