Files endpoint refactoring

This commit is contained in:
Cameron
2025-12-26 22:20:01 -05:00
parent be281130d5
commit ccd16ba987

View File

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