From 35ded7bc59fdc6b82bc44739591a327f6938821c Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 27 Aug 2025 17:06:40 +0530 Subject: [PATCH] fix(rust): Match Go CLI's album-based export directory structure Switch from date-based (YYYY/MM-Month) to album-based directory structure to ensure compatibility with Go CLI. Files now export to AlbumName/ folders with "Uncategorized" for files without albums. Co-Authored-By: Claude --- rust/src/commands/export.rs | 55 ++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/rust/src/commands/export.rs b/rust/src/commands/export.rs index 0cb1ce1401..b4e6daddcf 100644 --- a/rust/src/commands/export.rs +++ b/rust/src/commands/export.rs @@ -440,43 +440,23 @@ fn generate_export_path( metadata: Option<&FileMetadata>, pub_magic_metadata: Option<&serde_json::Value>, ) -> Result { - use chrono::{TimeZone, Utc}; - // Start with export directory let mut path = export_dir.to_path_buf(); - // Add date-based directory structure (YYYY/MM-MonthName) - // Use updation_time as creation time proxy - let datetime = Utc - .timestamp_micros(file.updation_time) - .single() - .ok_or_else(|| crate::Error::Generic("Invalid timestamp".into()))?; - - let year = datetime.format("%Y").to_string(); - let month = datetime.format("%m-%B").to_string(); // e.g., "01-January" - - path.push(year); - path.push(month); - - // Add collection name if available - if let Some(col) = collection + // Match Go CLI structure: export_dir/AlbumName/filename + // Use collection/album name as folder, or "Uncategorized" if none + let album_folder = if let Some(col) = collection && let Some(ref name) = col.name && !name.is_empty() - && name != "Uncategorized" { - // Sanitize collection name for filesystem - let safe_name: String = name - .chars() - .map(|c| match c { - '/' | '\\' | ':' | '*' | '?' | '"' | '<' | '>' | '|' => '_', - c if c.is_control() => '_', - c => c, - }) - .collect::() - .trim() - .to_string(); - path.push(safe_name); - } + // Sanitize collection name for filesystem (matching Go's approach) + sanitize_album_name(name) + } else { + // Files without a collection go to "Uncategorized" (matching Go CLI) + "Uncategorized".to_string() + }; + + path.push(album_folder); // Use filename from public magic metadata (edited name) or regular metadata let filename = { @@ -565,6 +545,19 @@ fn sanitize_filename(name: &str) -> String { .to_string() } +/// Sanitize an album/collection name for filesystem (matching Go CLI's logic) +fn sanitize_album_name(name: &str) -> String { + // Go CLI replaces : and / with _ in album names + name.chars() + .map(|c| match c { + ':' | '/' => '_', + c => c, + }) + .collect::() + .trim() + .to_string() +} + /// Decrypt file metadata fn decrypt_file_metadata( file: &crate::api::models::File,