diff --git a/Cargo.lock b/Cargo.lock index 2782da06..cd9a6dce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1002,6 +1002,7 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.3", "regex", + "relative-path", "reqwest", "serde", "serde_json", @@ -2323,6 +2324,12 @@ version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +[[package]] +name = "relative-path" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4e112eddc95bbf25365df3b5414354ad2fe7ee465eddb9965a515faf8c3b6d9" + [[package]] name = "remove_dir_all" version = "0.5.3" diff --git a/Cargo.toml b/Cargo.toml index b1ccf8e5..60137583 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ notify = "4.0" once_cell = "1.10" rand = "0.8" rand_core = { version = "0.6", features = ["std"] } +relative-path = "1.6" regex = "1" reqwest = { version = "0.11", features = ["blocking", "json"] } serde = { version = "1.0", features = ["derive"] } diff --git a/src/api/files.rs b/src/api/files.rs index 9aa4f876..578af9aa 100644 --- a/src/api/files.rs +++ b/src/api/files.rs @@ -1,18 +1,18 @@ -use log::error; +use relative_path::RelativePath; use serde::{Deserialize, Serialize}; -use std::{ - fs::{self, canonicalize}, - path::{self, PathBuf}, -}; +use std::{fs, path::PathBuf}; use simplelog::*; use crate::api::{errors::ServiceError, utils::playout_config}; +use crate::utils::file_extension; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct PathObject { root: String, + #[serde(skip_deserializing)] folders: Vec, + #[serde(skip_deserializing)] files: Vec, } @@ -29,30 +29,42 @@ impl PathObject { pub async fn browser(id: i64, path_obj: &PathObject) -> Result { let config = playout_config(&id).await?; let path = PathBuf::from(config.storage.path); - let absolute = match canonicalize(path_obj.root.clone()) { - Ok(p) => p, + let extensions = config.storage.extensions; + let path_component = RelativePath::new(&path_obj.root) + .normalize() + .to_string() + .replace("../", ""); + let path = path.join(path_component.clone()); + let mut obj = PathObject::new(path_component.clone()); + + let mut paths: Vec<_> = match fs::read_dir(path) { + Ok(p) => p.filter_map(|r| r.ok()).collect(), Err(e) => { - error!("{e}"); + error!("{e} in {path_component}"); return Err(ServiceError::InternalServerError); } }; - let path = path.join(absolute.clone()); - let obj = PathObject::new(path_obj.root.clone()); - println!("absolute: {:?}", absolute); - - let paths = fs::read_dir(path).unwrap(); + paths.sort_by_key(|dir| dir.path()); for path in paths { - println!("Name: {:?}", path); - // if let Ok(p) = path { - // let file_path = p.path().to_owned(); - // if file_path.is_dir() { - // folders.push(file_path.display()) - // } else if file_path.is_file() { - // files.push(file_path.clone().display()) - // } - // } + let file_path = path.path().to_owned(); + let path_str = file_path.display().to_string(); + + // ignore hidden files/folders on unix + if path_str.contains("/.") { + continue; + } + + if file_path.is_dir() { + obj.folders.push(path_str); + } else if file_path.is_file() { + if let Some(ext) = file_extension(&file_path) { + if extensions.contains(&ext.to_string().to_lowercase()) { + obj.files.push(path_str); + } + } + } } Ok(obj) diff --git a/src/api/routes.rs b/src/api/routes.rs index 6d152c7b..78dbaabf 100644 --- a/src/api/routes.rs +++ b/src/api/routes.rs @@ -413,7 +413,7 @@ pub async fn file_browser( data: web::Json, ) -> Result { match browser(*id, &data.into_inner()).await { - Ok(obj) => return Ok(web::Json(obj)), + Ok(obj) => Ok(web::Json(obj)), Err(e) => Err(e), } } diff --git a/src/input/folder.rs b/src/input/folder.rs index 7dbd68d9..a1b10ce6 100644 --- a/src/input/folder.rs +++ b/src/input/folder.rs @@ -1,5 +1,4 @@ use std::{ - ffi::OsStr, path::Path, process::exit, sync::{ @@ -19,7 +18,7 @@ use rand::{seq::SliceRandom, thread_rng}; use simplelog::*; use walkdir::WalkDir; -use crate::utils::{get_sec, Media, PlayoutConfig}; +use crate::utils::{file_extension, get_sec, Media, PlayoutConfig}; /// Folder Sources /// @@ -155,10 +154,6 @@ impl Iterator for FolderSource { } } -fn file_extension(filename: &Path) -> Option<&str> { - filename.extension().and_then(OsStr::to_str) -} - /// Create a watcher, which monitor file changes. /// When a change is register, update the current file list. /// This makes it possible, to play infinitely and and always new files to it. diff --git a/src/utils/mod.rs b/src/utils/mod.rs index e1d11302..38ed54e4 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,4 +1,5 @@ use std::{ + ffi::OsStr, fs::{self, metadata}, io::{BufRead, BufReader, Error}, net::TcpListener, @@ -322,6 +323,11 @@ pub fn sec_to_time(sec: f64) -> String { date_time.format("%H:%M:%S%.3f").to_string() } +/// get file extension +pub fn file_extension(filename: &Path) -> Option<&str> { + filename.extension().and_then(OsStr::to_str) +} + /// Test if given numbers are close to each other, /// with a third number for setting the maximum range. pub fn is_close(a: f64, b: f64, to: f64) -> bool {