implement file move, fix #440
This commit is contained in:
parent
8dcd3603c1
commit
498f4b27d0
@ -1,5 +1,4 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fs,
|
|
||||||
io::Write,
|
io::Write,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
@ -12,6 +11,7 @@ use rand::{distributions::Alphanumeric, Rng};
|
|||||||
use relative_path::RelativePath;
|
use relative_path::RelativePath;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{Pool, Sqlite};
|
use sqlx::{Pool, Sqlite};
|
||||||
|
use tokio::fs;
|
||||||
|
|
||||||
use simplelog::*;
|
use simplelog::*;
|
||||||
|
|
||||||
@ -22,6 +22,7 @@ use ffplayout_lib::utils::{file_extension, MediaProbe};
|
|||||||
pub struct PathObject {
|
pub struct PathObject {
|
||||||
pub source: String,
|
pub source: String,
|
||||||
parent: Option<String>,
|
parent: Option<String>,
|
||||||
|
parent_folders: Option<Vec<String>>,
|
||||||
folders: Option<Vec<String>>,
|
folders: Option<Vec<String>>,
|
||||||
files: Option<Vec<VideoFile>>,
|
files: Option<Vec<VideoFile>>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@ -33,6 +34,7 @@ impl PathObject {
|
|||||||
Self {
|
Self {
|
||||||
source,
|
source,
|
||||||
parent,
|
parent,
|
||||||
|
parent_folders: Some(vec![]),
|
||||||
folders: Some(vec![]),
|
folders: Some(vec![]),
|
||||||
files: Some(vec![]),
|
files: Some(vec![]),
|
||||||
folders_only: false,
|
folders_only: false,
|
||||||
@ -108,59 +110,98 @@ pub async fn browser(
|
|||||||
.split(',')
|
.split(',')
|
||||||
.map(|e| e.to_string())
|
.map(|e| e.to_string())
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
let mut parent_folders = vec![];
|
||||||
let mut extensions = config.storage.extensions;
|
let mut extensions = config.storage.extensions;
|
||||||
extensions.append(&mut channel_extensions);
|
extensions.append(&mut channel_extensions);
|
||||||
|
|
||||||
let (path, parent, path_component) = norm_abs_path(&config.storage.path, &path_obj.source);
|
let (path, parent, path_component) = norm_abs_path(&config.storage.path, &path_obj.source);
|
||||||
|
|
||||||
|
let parent_path = if !path_component.is_empty() {
|
||||||
|
path.parent().unwrap()
|
||||||
|
} else {
|
||||||
|
&config.storage.path
|
||||||
|
};
|
||||||
|
|
||||||
let mut obj = PathObject::new(path_component, Some(parent));
|
let mut obj = PathObject::new(path_component, Some(parent));
|
||||||
obj.folders_only = path_obj.folders_only;
|
obj.folders_only = path_obj.folders_only;
|
||||||
|
|
||||||
let mut paths: Vec<PathBuf> = match fs::read_dir(path) {
|
if path != parent_path && !path_obj.folders_only {
|
||||||
Ok(p) => p.filter_map(|r| r.ok()).map(|p| p.path()).collect(),
|
let mut parents = fs::read_dir(&parent_path).await?;
|
||||||
Err(e) => {
|
|
||||||
error!("{e} in {}", path_obj.source);
|
while let Some(child) = parents.next_entry().await? {
|
||||||
return Err(ServiceError::NoContent(e.to_string()));
|
if child.metadata().await?.is_dir() {
|
||||||
}
|
parent_folders.push(
|
||||||
};
|
child
|
||||||
|
.path()
|
||||||
|
.file_name()
|
||||||
|
.unwrap()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_folders.path_sort(natural_lexical_cmp);
|
||||||
|
|
||||||
|
obj.parent_folders = Some(parent_folders);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut paths_obj = fs::read_dir(path).await?;
|
||||||
|
|
||||||
paths.path_sort(natural_lexical_cmp);
|
|
||||||
let mut files = vec![];
|
let mut files = vec![];
|
||||||
let mut folders = vec![];
|
let mut folders = vec![];
|
||||||
|
|
||||||
for path in paths {
|
while let Some(child) = paths_obj.next_entry().await? {
|
||||||
|
let f_meta = child.metadata().await?;
|
||||||
|
|
||||||
// ignore hidden files/folders on unix
|
// ignore hidden files/folders on unix
|
||||||
if path.display().to_string().contains("/.") {
|
if child.path().to_string_lossy().to_string().contains("/.") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if path.is_dir() {
|
if f_meta.is_dir() {
|
||||||
folders.push(path.file_name().unwrap().to_string_lossy().to_string());
|
folders.push(
|
||||||
} else if path.is_file() && !path_obj.folders_only {
|
child
|
||||||
if let Some(ext) = file_extension(&path) {
|
.path()
|
||||||
|
.file_name()
|
||||||
|
.unwrap()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
} else if f_meta.is_file() && !path_obj.folders_only {
|
||||||
|
if let Some(ext) = file_extension(&child.path()) {
|
||||||
if extensions.contains(&ext.to_string().to_lowercase()) {
|
if extensions.contains(&ext.to_string().to_lowercase()) {
|
||||||
match MediaProbe::new(&path.display().to_string()) {
|
files.push(child.path())
|
||||||
Ok(probe) => {
|
|
||||||
let mut duration = 0.0;
|
|
||||||
|
|
||||||
if let Some(dur) = probe.format.duration {
|
|
||||||
duration = dur.parse().unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
let video = VideoFile {
|
|
||||||
name: path.file_name().unwrap().to_string_lossy().to_string(),
|
|
||||||
duration,
|
|
||||||
};
|
|
||||||
files.push(video);
|
|
||||||
}
|
|
||||||
Err(e) => error!("{e:?}"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
folders.path_sort(natural_lexical_cmp);
|
||||||
|
files.path_sort(natural_lexical_cmp);
|
||||||
|
let mut media_files = vec![];
|
||||||
|
|
||||||
|
for file in files {
|
||||||
|
match MediaProbe::new(&file.to_string_lossy().to_string()) {
|
||||||
|
Ok(probe) => {
|
||||||
|
let mut duration = 0.0;
|
||||||
|
|
||||||
|
if let Some(dur) = probe.format.duration {
|
||||||
|
duration = dur.parse().unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
let video = VideoFile {
|
||||||
|
name: file.file_name().unwrap().to_string_lossy().to_string(),
|
||||||
|
duration,
|
||||||
|
};
|
||||||
|
media_files.push(video);
|
||||||
|
}
|
||||||
|
Err(e) => error!("{e:?}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
obj.folders = Some(folders);
|
obj.folders = Some(folders);
|
||||||
obj.files = Some(files);
|
obj.files = Some(media_files);
|
||||||
|
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
}
|
}
|
||||||
@ -173,36 +214,50 @@ pub async fn create_directory(
|
|||||||
let (config, _) = playout_config(conn, &id).await?;
|
let (config, _) = playout_config(conn, &id).await?;
|
||||||
let (path, _, _) = norm_abs_path(&config.storage.path, &path_obj.source);
|
let (path, _, _) = norm_abs_path(&config.storage.path, &path_obj.source);
|
||||||
|
|
||||||
if let Err(e) = fs::create_dir_all(&path) {
|
if let Err(e) = fs::create_dir_all(&path).await {
|
||||||
return Err(ServiceError::BadRequest(e.to_string()));
|
return Err(ServiceError::BadRequest(e.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("create folder: <b><magenta>{}</></b>", path.display());
|
info!(
|
||||||
|
"create folder: <b><magenta>{}</></b>",
|
||||||
|
path.to_string_lossy()
|
||||||
|
);
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().into())
|
Ok(HttpResponse::Ok().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn copy_and_delete(source: &PathBuf, target: &PathBuf) -> Result<PathObject, ServiceError> {
|
async fn copy_and_delete(source: &PathBuf, target: &PathBuf) -> Result<MoveObject, ServiceError> {
|
||||||
// match fs::copy(&source, &target) {
|
match fs::copy(&source, &target).await {
|
||||||
// Ok(_) => {
|
Ok(_) => {
|
||||||
// if let Err(e) = fs::remove_file(source) {
|
if let Err(e) = fs::remove_file(source).await {
|
||||||
// error!("{e}");
|
error!("{e}");
|
||||||
// return Err(ServiceError::BadRequest(
|
return Err(ServiceError::BadRequest(
|
||||||
// "Removing File not possible!".into(),
|
"Removing File not possible!".into(),
|
||||||
// ));
|
));
|
||||||
// };
|
};
|
||||||
|
|
||||||
// return Ok(PathObject::new(target.display().to_string()));
|
return Ok(MoveObject {
|
||||||
// }
|
source: source
|
||||||
// Err(e) => {
|
.file_name()
|
||||||
// error!("{e}");
|
.unwrap_or_default()
|
||||||
// Err(ServiceError::BadRequest("Error in file copy!".into()))
|
.to_string_lossy()
|
||||||
// }
|
.to_string(),
|
||||||
// }
|
target: target
|
||||||
// }
|
.file_name()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("{e}");
|
||||||
|
Err(ServiceError::BadRequest("Error in file copy!".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn rename(source: &PathBuf, target: &PathBuf) -> Result<MoveObject, ServiceError> {
|
async fn rename(source: &PathBuf, target: &PathBuf) -> Result<MoveObject, ServiceError> {
|
||||||
match fs::rename(source, target) {
|
match fs::rename(source, target).await {
|
||||||
Ok(_) => Ok(MoveObject {
|
Ok(_) => Ok(MoveObject {
|
||||||
source: source
|
source: source
|
||||||
.file_name()
|
.file_name()
|
||||||
@ -217,7 +272,7 @@ fn rename(source: &PathBuf, target: &PathBuf) -> Result<MoveObject, ServiceError
|
|||||||
}),
|
}),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("{e}");
|
error!("{e}");
|
||||||
Err(ServiceError::BadRequest("Rename failed!".into()))
|
copy_and_delete(source, target).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +292,7 @@ pub async fn rename_file(
|
|||||||
|
|
||||||
if (source_path.is_dir() || source_path.is_file()) && source_path.parent() == Some(&target_path)
|
if (source_path.is_dir() || source_path.is_file()) && source_path.parent() == Some(&target_path)
|
||||||
{
|
{
|
||||||
return rename(&source_path, &target_path);
|
return rename(&source_path, &target_path).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
if target_path.is_dir() {
|
if target_path.is_dir() {
|
||||||
@ -251,7 +306,7 @@ pub async fn rename_file(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if source_path.is_file() && target_path.parent().is_some() {
|
if source_path.is_file() && target_path.parent().is_some() {
|
||||||
return rename(&source_path, &target_path);
|
return rename(&source_path, &target_path).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(ServiceError::InternalServerError)
|
Err(ServiceError::InternalServerError)
|
||||||
@ -270,7 +325,7 @@ pub async fn remove_file_or_folder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if source.is_dir() {
|
if source.is_dir() {
|
||||||
match fs::remove_dir(source) {
|
match fs::remove_dir(source).await {
|
||||||
Ok(_) => return Ok(()),
|
Ok(_) => return Ok(()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("{e}");
|
error!("{e}");
|
||||||
@ -282,7 +337,7 @@ pub async fn remove_file_or_folder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if source.is_file() {
|
if source.is_file() {
|
||||||
match fs::remove_file(source) {
|
match fs::remove_file(source).await {
|
||||||
Ok(_) => return Ok(()),
|
Ok(_) => return Ok(()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("{e}");
|
error!("{e}");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user