feature/shuffle-sort #30

Merged
cameron merged 21 commits from feature/shuffle-sort into master 2024-12-06 16:25:44 +00:00
4 changed files with 43 additions and 3 deletions
Showing only changes of commit 6986540295 - Show all commits

1
Cargo.lock generated
View File

@@ -1354,6 +1354,7 @@ dependencies = [
"notify", "notify",
"path-absolutize", "path-absolutize",
"prometheus", "prometheus",
"rand",
"rayon", "rayon",
"serde", "serde",
"serde_json", "serde_json",

View File

@@ -37,3 +37,4 @@ actix-web-prom = "0.9.0"
prometheus = "0.13" prometheus = "0.13"
lazy_static = "1.5" lazy_static = "1.5"
anyhow = "1.0" anyhow = "1.0"
rand = "0.8.5"

View File

@@ -100,6 +100,14 @@ pub struct PhotosResponse {
pub dirs: Vec<String>, pub dirs: Vec<String>,
} }
#[derive(Copy, Clone, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum SortType {
Shuffle,
NameAsc,
NameDesc,
}
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct FilesRequest { pub struct FilesRequest {
pub path: String, pub path: String,
@@ -107,6 +115,7 @@ pub struct FilesRequest {
pub tag_ids: Option<String>, pub tag_ids: Option<String>,
pub tag_filter_mode: Option<FilterMode>, pub tag_filter_mode: Option<FilterMode>,
pub recursive: Option<bool>, pub recursive: Option<bool>,
pub sort: Option<SortType>,
} }
#[derive(Copy, Clone, Deserialize, PartialEq, Debug)] #[derive(Copy, Clone, Deserialize, PartialEq, Debug)]

View File

@@ -16,13 +16,15 @@ use actix_web::{
}; };
use log::{debug, error, info, trace}; use log::{debug, error, info, trace};
use crate::data::{Claims, FilesRequest, FilterMode, PhotosResponse}; use crate::data::{Claims, FilesRequest, FilterMode, PhotosResponse, SortType};
use crate::{create_thumbnails, AppState}; use crate::{create_thumbnails, AppState};
use crate::error::IntoHttpError; use crate::error::IntoHttpError;
use crate::tags::TagDao; use crate::tags::TagDao;
use crate::video::StreamActor; use crate::video::StreamActor;
use path_absolutize::*; use path_absolutize::*;
use rand::prelude::SliceRandom;
use rand::{random, thread_rng};
use serde::Deserialize; use serde::Deserialize;
pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>( pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
@@ -52,6 +54,14 @@ pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
return dao return dao
.get_files_with_any_tag_ids(tag_ids.clone()) .get_files_with_any_tag_ids(tag_ids.clone())
.context(format!("Failed to get files with tag_ids: {:?}", tag_ids)) .context(format!("Failed to get files with tag_ids: {:?}", tag_ids))
.map(|mut tagged_files| {
return if let Some(sort_type) = req.sort {
debug!("Sorting files: {:?}", sort_type);
sort(tagged_files, sort_type)
} else {
tagged_files
};
})
.map(|tagged_files| match filter_mode { .map(|tagged_files| match filter_mode {
FilterMode::Any => tagged_files FilterMode::Any => tagged_files
.iter() .iter()
@@ -89,7 +99,7 @@ pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
if let Ok(files) = file_system.get_files_for_path(search_path) { if let Ok(files) = file_system.get_files_for_path(search_path) {
debug!("Valid search path: {:?}", search_path); debug!("Valid search path: {:?}", search_path);
let photos = files let mut photos = files
.iter() .iter()
.filter(|&f| { .filter(|&f| {
f.metadata().map_or_else( f.metadata().map_or_else(
@@ -127,6 +137,11 @@ pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
}) })
.collect::<Vec<String>>(); .collect::<Vec<String>>();
if let Some(sort_type) = req.sort {
debug!("Sorting files: {:?}", sort_type);
photos = sort(photos, sort_type)
}
let dirs = files let dirs = files
.iter() .iter()
.filter(|&f| f.metadata().map_or(false, |md| md.is_dir())) .filter(|&f| f.metadata().map_or(false, |md| md.is_dir()))
@@ -144,6 +159,20 @@ pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
} }
} }
fn sort(mut files: Vec<String>, sort_type: SortType) -> Vec<String> {
match sort_type {
SortType::Shuffle => files.shuffle(&mut thread_rng()),
SortType::NameAsc => {
files.sort_by(|l, r| l.cmp(&r));
}
SortType::NameDesc => {
files.sort_by(|l, r| r.cmp(&l));
}
}
files
}
pub fn list_files(dir: &Path) -> io::Result<Vec<PathBuf>> { pub fn list_files(dir: &Path) -> io::Result<Vec<PathBuf>> {
let files = read_dir(dir)? let files = read_dir(dir)?
.filter_map(|res| res.ok()) .filter_map(|res| res.ok())