Skip to content

johndo100/cleanfy

Repository files navigation

cleanfy

A smart, fast CLI tool to batch normalize and clean filenames with Unicode support, case transformation, and intelligent conflict resolution.

Features

  • 🌍 Unicode Support β€” Converts accented characters and special letters to ASCII equivalents
  • πŸ”§ Case Transformation β€” Lowercase, uppercase, or title case (optional, no forced defaults)
  • πŸ“… Date Prefixing β€” Add file modification date or current date as prefix (optional)
  • ⚑ Conflict Resolution β€” Automatically handles duplicate filenames with numeric suffixes (_2, _3, etc.)
  • πŸƒ Recursive Processing β€” Optionally process subdirectories with -r
  • πŸ‘οΈ Dry-Run Mode β€” Preview all changes before applying (default behavior)
  • πŸ“‹ JSON Output β€” Machine-readable results for automation and scripting
  • πŸš€ Fast & Safe β€” Handles thousands of files efficiently with proper error handling

Installation

From Source

git clone https://github.com/johndo100/cleanfy.git
cd cleanfy
go build -o cleanfy

Binary Release

Download prebuilt binaries from Releases

Quick Start

Preview Changes (Dry-Run)

cleanfy ./photos

Execute Changes

cleanfy -x ./photos

With Options

cleanfy -x -r --case=lower ./all_files

Flags

Flag Long Form Description
-x --execute Execute renames (default: preview only)
-r --recursive Recurse into subdirectories
-q --quiet Suppress output (errors only)
-j --json Output as JSON
-v --version Show version and exit
-a --dotfiles Include hidden files (starting with .)
--case= --case= Case transform: lower, upper, title (optional)
--date= --date= Date prefix: mtime (modified) or now (current) (optional)
--date-format= --date-format= Go time layout (default: 2006-01-02)

Note: All value flags must use the = form (e.g., --case=lower, --date=mtime)

Examples

# Preview changes
cleanfy ./photos

# Apply lowercase transformation to all files
cleanfy -x --case=lower ./photos

# Recursive processing with uppercase
cleanfy -x -r --case=upper ./documents

# Add current date prefix to files
cleanfy -x --date=now ./backup

# Add file modification date as prefix with custom format
cleanfy -x --date=mtime --date-format="20060102_150405" ./archive

# Recursive with date and custom case
cleanfy -x -r --case=title --date=mtime ./library

# Process including hidden files
cleanfy -x -a ./config

# JSON output for scripting
cleanfy -j ./files | jq '.[] | select(.renamed == true)'

# Quiet mode with errors only
cleanfy -x -q -r ./large_directory

# Custom date format examples
cleanfy --date=now --date-format="2006-01-02" ./files         # 2025-11-12
cleanfy --date=now --date-format="Jan 2 2006" ./files         # Nov 12 2025
cleanfy --date=now --date-format="20060102_150405" ./files    # 20251112_165030

What Gets Normalized

Character Transformations

  • Accents β€” cafΓ© β†’ cafe, ZΓΌrich β†’ Zurich
  • Special Ligatures β€” straße β†’ strasse, Γ†ther β†’ AEther
  • Strokes β€” ŁódΕΊ β†’ Lodz, Đàm β†’ dam
  • Quotes & Dashes β€” Smart handling of curly quotes, en-dashes, em-dashes

Filename Cleanup

  • Spaces & Punctuation β€” Converted to underscores: My File! β†’ my_file
  • Multiple Separators β€” Collapsed: file___name β†’ file_name
  • Leading/Trailing β€” Trimmed: .file_ β†’ file
  • Reserved Names β€” Windows reserved names prefixed with _: COM β†’ _com
  • Length β€” Safely truncated while preserving UTF-8 validity

Optional Transforms

  • Case β€” Lower, upper, or title case (opt-in via --case=)
  • Date Prefix β€” Add mtime or current date (opt-in via --date=)

Conflict Resolution

  • Duplicates β€” Auto-resolved with numeric suffixes: file.txt β†’ file_2.txt
  • Always On β€” Prevents overwrites automatically

Output Format

Preview Mode (Text Output)

RENAME  MyFile.txt -> myfile.txt
OK      already_clean.txt
RENAME* Duplicate.pdf -> duplicate_2.pdf   (auto-resolved)
ERR     Protected.txt : permission denied

Execution Mode (Text Output)

RENAME  MyFile.txt -> myfile.txt
RENAME* Duplicate.pdf -> duplicate_2.pdf   (auto-resolved)

JSON Output

[
  {
    "path": "/path/to/myfile.txt",
    "old_name": "MyFile.txt",
    "new_name": "myfile.txt",
    "is_dir": false,
    "renamed": true,
    "auto_renamed": false,
    "skipped": false,
    "error": ""
  }
]

Testing

Run the full test suite:

# Verbose output
go test ./... -v

# With coverage report
go test ./... -cover

# Run benchmarks
go test -bench=. ./...

Current Coverage: 34.5% with 100+ test cases across core functions

Performance

  • Single directory (100 files): ~50ms
  • Recursive (1000 files): ~200ms
  • Large batch (10,000 files): ~2s

Safety Features

βœ… Dry-run by default β€” Use -x to apply changes
βœ… Dotfiles skipped by default β€” Use -a to process hidden files
βœ… No forced transformations β€” Case/date are optional
βœ… Automatic conflict resolution β€” Prevents overwrites
βœ… Error reporting β€” Clear feedback on failures

Platform Support

  • βœ… Linux
  • βœ… macOS (Intel & Apple Silicon)
  • βœ… Windows

Version

Current version is automatically detected from git tags and build metadata.

cleanfy -v
# cleanfy v0.9.0-pre (linux/amd64)

CI/CD

This project uses GitHub Actions for:

  • βœ… Automated testing on push/PR
  • βœ… Cross-platform builds on tag
  • βœ… Automatic release creation

See CI_RELEASE_GUIDE.md for details.

License

See LICENSE file for details

Support

Found a bug or have a feature request?
Please open an issue on GitHub


Made with ❀️ for batch file normalization

About

Experimenting with Go and AI (ChatGPT) to build a smart filename cleaner.

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published