Merge pull request #261 from jb-alvarado/nuxt3-frontend

support path list for playlist generation, #258
This commit is contained in:
jb-alvarado 2023-01-23 07:42:20 +01:00 committed by GitHub
commit 375ff39b38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 82 additions and 42 deletions

6
Cargo.lock generated
View File

@ -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",

View File

@ -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]

View File

@ -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(), &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)),
Err(e) => Err(e),
}

View File

@ -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());

View File

@ -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())

View File

@ -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"

View File

@ -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(

View File

@ -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

View File

@ -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]

View File

@ -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,

View File

@ -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 {