Separate file/folder numbering by default, with shared numbering option in the numbering rule popup. Text editor now loads names from previous pipeline steps instead of originals, and uses absolute position so it works correctly with any numbering mode. Folders sort before files for consistent ordering. Spacebar works in the text editor textarea without triggering drag.
113 lines
2.9 KiB
Rust
113 lines
2.9 KiB
Rust
pub mod rules;
|
|
pub mod pipeline;
|
|
pub mod filter;
|
|
pub mod metadata;
|
|
pub mod preset;
|
|
pub mod bru;
|
|
pub mod undo;
|
|
pub mod scanner;
|
|
|
|
use chrono::{DateTime, Utc};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::path::PathBuf;
|
|
use thiserror::Error;
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum NominaError {
|
|
#[error("Invalid regex pattern: {pattern} - {reason}")]
|
|
InvalidRegex { pattern: String, reason: String },
|
|
|
|
#[error("File not found: {path}")]
|
|
FileNotFound { path: PathBuf },
|
|
|
|
#[error("Rename conflict: {count} files would produce the name '{name}'")]
|
|
NamingConflict { name: String, count: usize },
|
|
|
|
#[error("Invalid filename '{name}': {reason}")]
|
|
InvalidFilename { name: String, reason: String },
|
|
|
|
#[error("Filesystem error on '{path}': {source}")]
|
|
Filesystem {
|
|
path: PathBuf,
|
|
#[source]
|
|
source: std::io::Error,
|
|
},
|
|
|
|
#[error("Preset parse error: {reason}")]
|
|
PresetError { reason: String },
|
|
|
|
#[error("BRU import error at line {line}: {reason}")]
|
|
BruImportError { line: usize, reason: String },
|
|
|
|
#[error("EXIF read error for '{path}': {reason}")]
|
|
ExifError { path: PathBuf, reason: String },
|
|
}
|
|
|
|
pub type Result<T> = std::result::Result<T, NominaError>;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct RenameContext {
|
|
pub index: usize,
|
|
pub total: usize,
|
|
pub absolute_index: usize,
|
|
pub original_name: String,
|
|
pub extension: String,
|
|
pub path: PathBuf,
|
|
pub size: u64,
|
|
pub created: Option<DateTime<Utc>>,
|
|
pub modified: Option<DateTime<Utc>>,
|
|
pub accessed: Option<DateTime<Utc>>,
|
|
pub date_taken: Option<DateTime<Utc>>,
|
|
pub parent_folder: String,
|
|
}
|
|
|
|
impl RenameContext {
|
|
pub fn dummy(index: usize) -> Self {
|
|
Self {
|
|
index,
|
|
total: 1,
|
|
absolute_index: index,
|
|
original_name: String::new(),
|
|
extension: String::new(),
|
|
path: PathBuf::new(),
|
|
size: 0,
|
|
created: None,
|
|
modified: None,
|
|
accessed: None,
|
|
date_taken: None,
|
|
parent_folder: String::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait RenameRule: Send + Sync {
|
|
fn apply(&self, filename: &str, context: &RenameContext) -> String;
|
|
fn display_name(&self) -> &str;
|
|
fn rule_type(&self) -> &str;
|
|
fn is_enabled(&self) -> bool;
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct FileEntry {
|
|
pub path: PathBuf,
|
|
pub name: String,
|
|
pub stem: String,
|
|
pub extension: String,
|
|
pub size: u64,
|
|
pub is_dir: bool,
|
|
pub is_hidden: bool,
|
|
pub created: Option<DateTime<Utc>>,
|
|
pub modified: Option<DateTime<Utc>>,
|
|
pub accessed: Option<DateTime<Utc>>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct PreviewResult {
|
|
pub original_path: PathBuf,
|
|
pub original_name: String,
|
|
pub new_name: String,
|
|
pub has_conflict: bool,
|
|
pub has_error: bool,
|
|
pub error_message: Option<String>,
|
|
}
|