oncutf is a comprehensive file renaming tool with an intuitive PyQt5 GUI. Designed for photographers, content creators, and digital archivists who need precise control over their file naming workflows.
- Architecture Guide — System design & layer structure
- Master Plan — Current status and next steps
- Development Roadmap — Phase progress and milestones
- Original Name: Preserve original filename with optional Greek-to-Greeklish conversion
- Specified Text: Add custom text with context menu shortcuts and original name insertion
- Counter: Sequential numbering with configurable start, step, and padding
- Metadata: Extract file dates or metadata fields for filename generation
- Name Transform: Apply case transformations (lower, UPPER, Capitalize) and separator styles (snake_case, kebab-case, space)
- Final Transform: Post-processing options for case, separator, and Greek-to-Greeklish conversion
- Automatic Backup System: Database backups on shutdown and periodic intervals (every 15 minutes)
- Persistent Storage: SQLite-based database for metadata, hashes, and rename history
- Enhanced Stability: Robust error handling and recovery mechanisms for Qt object lifecycle
- Data Integrity: Backup rotation with configurable retention and timestamp naming
- Drag & Drop Interface:
- File tree to table: Import files/folders with modifier-based metadata loading
- File table to metadata tree: Quick metadata inspection (Shift for extended metadata)
- Multi-selection support with visual feedback
- Intelligent Metadata Loading:
- Fast metadata scanning for common fields
- Extended metadata extraction for comprehensive data
- Smart caching system to avoid redundant operations
- Live Preview: Real-time filename preview before applying changes
- Visual Feedback: Professional icons, tooltips, and status indicators
- Conflict Resolution: Overwrite/Skip/Cancel options for existing files
- Responsive Layout: Splitter-based interface with memory of panel sizes
- Context Menus: Rich right-click functionality throughout the interface
- Configuration Management: JSON-based settings with automatic backup and cross-platform support
- File Dates: Last modified in various formats (ISO, European, US, year-only, etc.)
- Metadata Fields: Camera settings, GPS coordinates, creation dates, and technical metadata
- Dynamic Field Discovery: Automatically detects available metadata fields from loaded files
- Metadata Tree View: Hierarchical display with copy/edit/reset capabilities
- Python 3.12+
- ExifTool - Must be installed and available in system PATH
- PyQt5 - GUI framework
Windows:
- Download from ExifTool website
- Extract to a folder (e.g.,
C:\exiftool) - Add the folder to your system PATH
Linux (Ubuntu/Debian):
sudo apt-get install exiftoolmacOS:
brew install exiftoolManual Installation:
- Download from ExifTool website
- Extract and add to PATH
Verify Installation:
exiftool -ver# Clone the repository
git clone https://github.com/mecondev/oncutf.git
cd oncutf
# Install Python dependencies
pip install -r requirements.txt
# Run the application
python main.pyNote: The application uses Inter fonts from
resources/fonts/by default. Thescripts/generate_fonts_rc.pyscript is only needed for embedded font mode (e.g., PyInstaller packaging). Seeoncutf/config.py→USE_EMBEDDED_FONTS.
# Install in development mode
pip install -e .
# Run with specific Python version
python3.12 main.py- Load Files: Drag folders/files into the application or use the browse button
- Configure Modules: Set up rename modules in the desired order
- Preview Results: Review the generated filenames in the preview pane
- Apply Changes: Click "Rename" to execute the file renaming operation
- Ctrl+O: Browse for files/folders
- Ctrl+S: Save all metadata
- Ctrl+L: Show hash results dialog
- Ctrl+Z: Undo last operation
- Ctrl+Shift+Z: Redo last operation
- Ctrl+Y: Show command history dialog
- Escape: Cancel drag operations
- Shift+Escape: Clear file table
- F5 (File Table): Reload files from current folder
- F5 (File Tree): Refresh file tree view
- F5 (Metadata Tree): Reload metadata from selection
- F5 (Preview): Refresh preview tables
- Ctrl+A: Select all files
- Ctrl+Shift+A: Clear selection
- Ctrl+I: Invert selection
- Ctrl+M: Load basic metadata for selected files
- Ctrl+Shift+M: Load extended metadata for selected files
- Ctrl+H: Calculate hash checksums for selected files
- Ctrl+T: Auto-fit columns to content
- Ctrl+Shift+T: Reset columns to default widths
- Ctrl+Left: Move hovered column left (columns must be unlocked)
- Ctrl+Right: Move hovered column right (columns must be unlocked)
Note: Column reordering is hover-based — no need to click the column header. Simply hover over it and press Ctrl+Left/Right. Columns must be unlocked via the header context menu (right-click on any column header).
Drag & Drop Modifiers:
- No modifier: Skip metadata loading (folders) / Fast metadata (file-to-metadata)
- Ctrl: Load basic metadata
- Ctrl+Shift: Load extended metadata
- Shift: Extended metadata (file-to-metadata drag only)
- No Modifier: Select clicked row, deselect others
- Ctrl: Toggle clicked row (add/remove from selection)
- Shift: Extend selection from anchor to clicked row
- Drag to Metadata Tree (No Modifier): Load fast metadata for selected files
- Drag to Metadata Tree (Shift): Load extended metadata for selected files (requires 3x normal drag distance to prevent accidental triggers)
- Ctrl+Drag (Lasso): Select/deselect rows in range; initial selection XOR dragged range. Compatible with Windows Explorer behavior
- Clicking on already-selected item (no modifier): Preserves multi-selection for drag. If no drag occurs, converts to single selection
- Anchor row is maintained for Shift+Click range selection
- Selection restored after metadata operations
oncutf/
├── main.py # Slim entry point (delegates to boot/)
├── config.py # Global configuration constants
├── ui/ # UI layer (PyQt5 widgets)
│ ├── main_window.py # Main window wired to controllers
│ ├── behaviors/ # Reusable UI behaviors (column mgmt, drag feedback)
│ ├── delegates/ # Custom item delegates (color, validation)
│ ├── dialogs/ # Dialog windows (metadata edit, history)
│ ├── services/ # UI-specific services
│ └── widgets/ # Custom PyQt5 widgets
├── controllers/ # UI-agnostic orchestration layer
│ ├── file_load_controller.py
│ ├── metadata_controller.py
│ ├── rename_controller.py
│ └── main_window_controller.py
├── core/ # Business logic (organized subdirectories)
│ ├── cache/ # Cache management (3 modules)
│ ├── database/ # Database operations (2 modules)
│ ├── drag/ # Drag & drop handling (3 modules)
│ ├── events/ # Event handlers (3 modules)
│ ├── hash/ # Hash operations (4 modules)
│ ├── initialization/ # Startup logic (3 modules)
│ ├── metadata/ # Metadata operations (4 modules)
│ ├── rename/ # Rename engine (3 modules)
│ ├── selection/ # Selection state (2 modules)
│ ├── ui_managers/ # UI managers (7 modules)
│ └── ... # Other flat modules
├── domain/ # Pure domain models
├── models/ # Data models (FileItem, etc.)
├── modules/ # Rename modules (composable steps)
├── services/ # Service protocols (DI support)
├── utils/ # Helper utilities
├── docs/ # Documentation (see docs/README.md)
├── tests/ # Comprehensive test suite (939 tests)
├── scripts/ # Tooling (profiling, maintenance)
└── assets/resources/ # Icons, fonts, images
Comprehensive documentation is available in the docs/ directory:
- Complete Documentation Index — Overview and navigation
- Architecture Guide — System design and layer structure
- Keyboard Shortcuts Reference — Complete keyboard shortcuts guide
- Application Workflow — Complete application flow from startup to rename execution
- Database Quick Start — Get started with persistent storage
- Database System — SQLite-based persistence architecture
- Structured Metadata System — Advanced metadata organization and processing
- Safe Rename Workflow — Enhanced rename operations
- Progress Manager System — Unified progress tracking
- JSON Config System — Configuration management
# Run all tests
pytest tests/ -v
# Run with coverage report
pytest tests/ --cov=widgets --cov=modules --cov=utils --cov=core --cov-report=term-missing
# Run specific test modules
pytest tests/test_rename_logic.py -vThe project uses pyproject.toml for all tool configuration.
# Install development dependencies
pip install -e .[dev]
# Run linting (ruff)
ruff check .
# Run type checking (mypy)
mypy .
# Run all tests
pytest tests/ -vCurrent Status:
- Ruff: All checks passing
- MyPy: Clean (0 errors, 330 source files)
- Pytest: 949 tests passing
See TODO.md for planned features and improvements:
- Last state restoration (sort column persistence)
- Non-blocking conflict resolution UI
- Metadata database search functionality
- Rename preview profiling
See docs/REFACTORING_ROADMAP.md for technical debt and planned refactoring.
Canonical Patterns (Single Source of Truth):
| Domain | Canonical | Legacy/Supporting |
|---|---|---|
| Rename Pipeline | UnifiedRenameEngine |
utils/naming/* (helpers only) |
| Column Management | UnifiedColumnService |
ColumnManager (thin adapter) |
| UI Components | Behaviors (ui/behaviors/) |
Mixins (no new mixins) |
Rules:
- All rename operations go through
UnifiedRenameEngine - New code uses Behaviors, not Mixins
- New column logic goes in
UnifiedColumnService
- Advanced Cache System: Multi-tier caching (memory + disk + database) for 500x speedup
- Persistent ExifTool Process: Uses
-stay_openmode for fast metadata extraction - Intelligent Caching: Smart cache invalidation with 90%+ hit rates
- Threaded Operations: Non-blocking metadata loading with progress feedback
- Batch Operations: Efficient processing of multiple files (10x speedup)
- Signal Debouncing: Prevents excessive UI updates during rapid changes
- Cross-Platform Path Handling: Normalized path operations for Windows/Linux compatibility
- Automatic Database Backups: Scheduled backups every 15 minutes + shutdown backups
- Backup Rotation: Configurable backup count with automatic cleanup of old backups
- Persistent Storage: SQLite database with WAL mode for better concurrency
- Data Recovery: Comprehensive backup system with timestamp-based file naming
- Multi-Selection Aware: Handles complex selection scenarios with modifier keys
- Visual Feedback: Real-time drop zone highlighting and cursor changes
- Conflict Resolution: Smart handling of Qt selection conflicts during drag operations
- Cross-Widget Communication: Seamless data transfer between file tree, table, and metadata views
- Graceful Degradation: Continues operation even when ExifTool encounters issues
- User-Friendly Messages: Clear error reporting without technical jargon
- Recovery Mechanisms: Automatic cleanup and state restoration after failures
- Qt Object Lifecycle Management: Enhanced tooltip system with proper cleanup and error recovery
oncutf is created by Michael Economou as a personal tool to support creative video and photo workflows. The project emphasizes reliability, performance, and user experience over feature bloat.
- Website: oncut.gr
- Instagram: @oncut.gr
- Facebook: Oncut
- GitHub: mecondev/oncutf
This is a hobbyist project. Not affiliated with or endorsed by ExifTool or PyQt5.
This project is licensed under the MIT License. See the LICENSE file for full details.
When bundled with the application (in bin/), the following tools are included under their
respective licenses. The oncutf project does not modify these tools.
| Tool | License | Source |
|---|---|---|
| ExifTool by Phil Harvey | Artistic License 2.0 / GPL | exiftool.org |
| FFmpeg / FFprobe | GPL v3 | ffmpeg.org |
License texts for bundled tools: bin/LICENSE-exiftool-artistic.txt,
bin/LICENSE-ffmpeg-gplv3.txt
