Files endpoint refactoring
This commit is contained in:
178
src/files.rs
178
src/files.rs
@@ -43,6 +43,56 @@ pub struct FileWithMetadata {
|
||||
}
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Apply sorting to files with EXIF data support for date-based sorting
|
||||
/// Handles both date sorting (with EXIF/filename fallback) and regular sorting
|
||||
fn apply_sorting_with_exif(
|
||||
files: Vec<FileWithTagCount>,
|
||||
sort_type: SortType,
|
||||
exif_dao: &mut Box<dyn ExifDao>,
|
||||
span_context: &opentelemetry::Context,
|
||||
) -> Vec<String> {
|
||||
match sort_type {
|
||||
SortType::DateTakenAsc | SortType::DateTakenDesc => {
|
||||
info!("Date sorting requested, fetching EXIF data");
|
||||
|
||||
// Collect file paths for batch EXIF query
|
||||
let file_paths: Vec<String> = files.iter().map(|f| f.file_name.clone()).collect();
|
||||
|
||||
// Batch fetch EXIF data
|
||||
let exif_map: std::collections::HashMap<String, i64> = exif_dao
|
||||
.get_exif_batch(span_context, &file_paths)
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter_map(|exif| exif.date_taken.map(|dt| (exif.file_path, dt)))
|
||||
.collect();
|
||||
|
||||
// Convert to FileWithMetadata with date fallback logic
|
||||
let files_with_metadata: Vec<FileWithMetadata> = files
|
||||
.into_iter()
|
||||
.map(|f| {
|
||||
// Try EXIF date first
|
||||
let date_taken = exif_map.get(&f.file_name).copied().or_else(|| {
|
||||
// Fallback to filename extraction
|
||||
extract_date_from_filename(&f.file_name).map(|dt| dt.timestamp())
|
||||
});
|
||||
|
||||
FileWithMetadata {
|
||||
file_name: f.file_name,
|
||||
tag_count: f.tag_count,
|
||||
date_taken,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
sort_with_metadata(files_with_metadata, sort_type)
|
||||
}
|
||||
_ => {
|
||||
// Use regular sort for non-date sorting
|
||||
sort(files, sort_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
|
||||
_: Claims,
|
||||
request: HttpRequest,
|
||||
@@ -264,51 +314,13 @@ pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
|
||||
.collect::<Vec<FileWithTagCount>>()
|
||||
})
|
||||
.map(|files| {
|
||||
// Handle sorting - use FileWithMetadata for date sorting to support EXIF dates
|
||||
// Handle sorting - use helper function that supports EXIF date sorting
|
||||
let sort_type = req.sort.unwrap_or(NameAsc);
|
||||
match sort_type {
|
||||
SortType::DateTakenAsc | SortType::DateTakenDesc => {
|
||||
info!("Date sorting requested in tagged/recursive search, fetching EXIF data");
|
||||
|
||||
// Collect file paths for batch EXIF query
|
||||
let file_paths: Vec<String> =
|
||||
files.iter().map(|f| f.file_name.clone()).collect();
|
||||
|
||||
// Batch fetch EXIF data
|
||||
let mut exif_dao_guard = exif_dao.lock().expect("Unable to get ExifDao");
|
||||
let exif_map: std::collections::HashMap<String, i64> = exif_dao_guard
|
||||
.get_exif_batch(&span_context, &file_paths)
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter_map(|exif| exif.date_taken.map(|dt| (exif.file_path, dt)))
|
||||
.collect();
|
||||
drop(exif_dao_guard);
|
||||
|
||||
// Convert to FileWithMetadata with date fallback logic
|
||||
let files_with_metadata: Vec<FileWithMetadata> = files
|
||||
.into_iter()
|
||||
.map(|f| {
|
||||
// Try EXIF date first
|
||||
let date_taken = exif_map.get(&f.file_name).copied().or_else(|| {
|
||||
// Fallback to filename extraction
|
||||
extract_date_from_filename(&f.file_name).map(|dt| dt.timestamp())
|
||||
});
|
||||
|
||||
FileWithMetadata {
|
||||
file_name: f.file_name,
|
||||
tag_count: f.tag_count,
|
||||
date_taken,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
sort_with_metadata(files_with_metadata, sort_type)
|
||||
}
|
||||
_ => {
|
||||
// Use regular sort for non-date sorting
|
||||
sort(files, sort_type)
|
||||
}
|
||||
}
|
||||
let mut exif_dao_guard = exif_dao.lock().expect("Unable to get ExifDao");
|
||||
let result =
|
||||
apply_sorting_with_exif(files, sort_type, &mut exif_dao_guard, &span_context);
|
||||
drop(exif_dao_guard);
|
||||
result
|
||||
})
|
||||
.inspect(|files| debug!("Found {:?} files", files.len()))
|
||||
.map(|tagged_files: Vec<String>| {
|
||||
@@ -439,53 +451,13 @@ pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
|
||||
|
||||
info!("After all filters, {} files remain", photos.len());
|
||||
|
||||
// Handle sorting - use FileWithMetadata for date sorting to support EXIF dates
|
||||
// Handle sorting - use helper function that supports EXIF date sorting
|
||||
let response_files = if let Some(sort_type) = req.sort {
|
||||
match sort_type {
|
||||
SortType::DateTakenAsc | SortType::DateTakenDesc => {
|
||||
info!("Date sorting requested, fetching EXIF data");
|
||||
|
||||
// Collect file paths for batch EXIF query
|
||||
let file_paths: Vec<String> =
|
||||
photos.iter().map(|f| f.file_name.clone()).collect();
|
||||
|
||||
// Batch fetch EXIF data
|
||||
let mut exif_dao_guard = exif_dao.lock().expect("Unable to get ExifDao");
|
||||
let exif_map: std::collections::HashMap<String, i64> = exif_dao_guard
|
||||
.get_exif_batch(&span_context, &file_paths)
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter_map(|exif| exif.date_taken.map(|dt| (exif.file_path, dt)))
|
||||
.collect();
|
||||
drop(exif_dao_guard);
|
||||
|
||||
// Convert to FileWithMetadata with date fallback logic
|
||||
let files_with_metadata: Vec<FileWithMetadata> = photos
|
||||
.into_iter()
|
||||
.map(|f| {
|
||||
// Try EXIF date first
|
||||
let date_taken =
|
||||
exif_map.get(&f.file_name).copied().or_else(|| {
|
||||
// Fallback to filename extraction
|
||||
extract_date_from_filename(&f.file_name)
|
||||
.map(|dt| dt.timestamp())
|
||||
});
|
||||
|
||||
FileWithMetadata {
|
||||
file_name: f.file_name,
|
||||
tag_count: f.tag_count,
|
||||
date_taken,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
sort_with_metadata(files_with_metadata, sort_type)
|
||||
}
|
||||
_ => {
|
||||
// Use regular sort for non-date sorting
|
||||
sort(photos, sort_type)
|
||||
}
|
||||
}
|
||||
let mut exif_dao_guard = exif_dao.lock().expect("Unable to get ExifDao");
|
||||
let result =
|
||||
apply_sorting_with_exif(photos, sort_type, &mut exif_dao_guard, &span_context);
|
||||
drop(exif_dao_guard);
|
||||
result
|
||||
} else {
|
||||
// No sorting requested
|
||||
photos
|
||||
@@ -540,9 +512,9 @@ fn sort(mut files: Vec<FileWithTagCount>, sort_type: SortType) -> Vec<String> {
|
||||
files.sort_by(|l, r| r.tag_count.cmp(&l.tag_count));
|
||||
}
|
||||
SortType::DateTakenAsc | SortType::DateTakenDesc => {
|
||||
// Date sorting not yet implemented for FileWithTagCount
|
||||
// Will be implemented when integrating with FileWithMetadata
|
||||
// For now, fall back to name sorting
|
||||
// Date sorting not implemented for FileWithTagCount
|
||||
// We shouldn't be hitting this code
|
||||
warn!("Date sorting not implemented for FileWithTagCount");
|
||||
files.sort_by(|l, r| l.file_name.cmp(&r.file_name));
|
||||
}
|
||||
}
|
||||
@@ -569,26 +541,22 @@ fn sort_with_metadata(mut files: Vec<FileWithMetadata>, sort_type: SortType) ->
|
||||
SortType::TagCountDesc => {
|
||||
files.sort_by(|l, r| r.tag_count.cmp(&l.tag_count));
|
||||
}
|
||||
SortType::DateTakenAsc => {
|
||||
SortType::DateTakenAsc | SortType::DateTakenDesc => {
|
||||
files.sort_by(|l, r| {
|
||||
match (l.date_taken, r.date_taken) {
|
||||
(Some(a), Some(b)) => a.cmp(&b),
|
||||
(Some(a), Some(b)) => {
|
||||
if sort_type == SortType::DateTakenAsc {
|
||||
a.cmp(&b)
|
||||
} else {
|
||||
b.cmp(&a)
|
||||
}
|
||||
}
|
||||
(Some(_), None) => std::cmp::Ordering::Less, // Dated photos first
|
||||
(None, Some(_)) => std::cmp::Ordering::Greater,
|
||||
(None, None) => l.file_name.cmp(&r.file_name), // Fallback to name
|
||||
}
|
||||
});
|
||||
}
|
||||
SortType::DateTakenDesc => {
|
||||
files.sort_by(|l, r| {
|
||||
match (l.date_taken, r.date_taken) {
|
||||
(Some(a), Some(b)) => b.cmp(&a), // Reverse for descending
|
||||
(Some(_), None) => std::cmp::Ordering::Less, // Dated photos first
|
||||
(None, Some(_)) => std::cmp::Ordering::Greater,
|
||||
(None, None) => r.file_name.cmp(&l.file_name), // Fallback reversed
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
files
|
||||
|
||||
Reference in New Issue
Block a user