Add EXIF search infrastructure (Phase 1 & 2)
Implements foundation for EXIF-based photo search capabilities: - Add geo.rs module with GPS distance calculations (Haversine + bounding box) - Extend FilesRequest with EXIF search parameters (camera, GPS, date, media type) - Add MediaType enum and DateTakenAsc/DateTakenDesc sort options - Create date_taken index migration for efficient date queries - Implement ExifDao methods: get_exif_batch, query_by_exif, get_camera_makes - Add FileWithMetadata struct for date-aware sorting - Implement date sorting with filename extraction fallback - Make extract_date_from_filename public for reuse Next: Integrate EXIF filtering into list_photos() and enhance get_all_tags()
This commit is contained in:
58
src/files.rs
58
src/files.rs
@@ -28,6 +28,14 @@ use crate::video::actors::StreamActor;
|
||||
use path_absolutize::*;
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
|
||||
/// File metadata for sorting and filtering
|
||||
/// Includes tag count and optional date for date-based sorting
|
||||
pub struct FileWithMetadata {
|
||||
pub file_name: String,
|
||||
pub tag_count: i64,
|
||||
pub date_taken: Option<i64>, // Unix timestamp from EXIF or filename extraction
|
||||
}
|
||||
use serde::Deserialize;
|
||||
|
||||
pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
|
||||
@@ -264,6 +272,56 @@ fn sort(mut files: Vec<FileWithTagCount>, sort_type: SortType) -> Vec<String> {
|
||||
SortType::TagCountDesc => {
|
||||
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
|
||||
files.sort_by(|l, r| l.file_name.cmp(&r.file_name));
|
||||
}
|
||||
}
|
||||
|
||||
files
|
||||
.iter()
|
||||
.map(|f| f.file_name.clone())
|
||||
.collect::<Vec<String>>()
|
||||
}
|
||||
|
||||
/// Sort files with metadata support (including date sorting)
|
||||
fn sort_with_metadata(mut files: Vec<FileWithMetadata>, sort_type: SortType) -> Vec<String> {
|
||||
match sort_type {
|
||||
SortType::Shuffle => files.shuffle(&mut thread_rng()),
|
||||
SortType::NameAsc => {
|
||||
files.sort_by(|l, r| l.file_name.cmp(&r.file_name));
|
||||
}
|
||||
SortType::NameDesc => {
|
||||
files.sort_by(|l, r| r.file_name.cmp(&l.file_name));
|
||||
}
|
||||
SortType::TagCountAsc => {
|
||||
files.sort_by(|l, r| l.tag_count.cmp(&r.tag_count));
|
||||
}
|
||||
SortType::TagCountDesc => {
|
||||
files.sort_by(|l, r| r.tag_count.cmp(&l.tag_count));
|
||||
}
|
||||
SortType::DateTakenAsc => {
|
||||
files.sort_by(|l, r| {
|
||||
match (l.date_taken, r.date_taken) {
|
||||
(Some(a), Some(b)) => a.cmp(&b),
|
||||
(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