EN — A polished desktop app that sorts your folders automatically — with preview, undo, rules, bulk rename, duplicate detection, and real-time watch mode.
ES — Una elegante aplicación de escritorio que organiza tus carpetas automáticamente, con vista previa, deshacer, reglas, cambio de nombre masivo, detección de duplicados y modo de supervisión en tiempo real.
Built with CustomTkinter · Python 3.11+ / Creado con CustomTkinter · Python 3.11+ Available in English and Spanish — switch instantly from Settings / Disponible en inglés y español: cambia de idioma al instante desde Ajustes.
- Automatic organization by category: Images, Documents, Videos, Audio, Design, Installers & Archives, and more
- Files with no matching category go to an
Othersfolder - Metadata hierarchy — when enabled, images are organized into EXIF-date subfolders (
Images/2024/01 - January/) and audio by artist and album (Audio/Radiohead/OK Computer/). Files without metadata land in the base folder unchanged - Custom rules engine with 7 condition types — name contains, glob pattern, extension, size, modification date — evaluated before extensions; first match wins
- Resilient processing — if a file is locked, the app skips it, logs the error, and continues with the rest
- Three duplicate policies — auto-rename (
file_1.txt), overwrite, or skip
- Preview before organizing — collapsible tree showing exactly where each file will go, with destination category and individual file size; total data to be moved appears in the summary. No file is moved until you confirm
- Undo — instantly reverts the last organization and removes empty folders left behind, including nested hierarchies up to 3 levels deep
- Duplicate detector — scans the folder by content (MD5 hash) and groups identical files into cards; by default keeps the oldest file and marks the rest for deletion, with a confirmation dialog before deleting
- Bulk renamer — templates with 17 variables (
{counter},{year},{artist},{photo_year}, etc.), extension filter, live preview table with collision detection, nothing is renamed until you apply
- Watch Mode — real-time monitoring via
watchdog; automatically organizes every new file that appears in the root folder with an 800 ms debounce. Closing the window while Watch Mode is active minimizes to the system tray instead of quitting - System tray icon — context menu to show the window, toggle Watch Mode, and quit; system notifications when organizing in the background
- Five-tab settings panel:
- Extensions — enable/disable extensions per category (including custom ones), add your own
- Categories — create and delete categories without touching code
- Rules — add, enable/disable, and delete custom rules
- Exclusions — glob patterns for files to ignore (e.g.
.*,desktop.ini,temp_*) - Config — metadata hierarchy, duplicate policy, export/import
config.json, clear history
- Export / Import category configuration to share or migrate to another machine
- Session history — last 20 organizations with date, folder, files moved, and errors
- Post-organization dashboard — donut chart with category breakdown, collapsible errors section, and button to open the report
.txtreport saved in the organized folder with sections "FILES MOVED", "FILES NOT MOVED" (with error type), and "SKIPPED FILES"
- Drag & Drop — drag a folder directly onto the window to select it (requires
tkinterdnd2) - App icon visible in the window title bar and the taskbar / dock
- Resizable window with a 700 × 420 minimum size
- Font adapted to the OS: Segoe UI (Windows), Helvetica Neue (macOS), DejaVu Sans (Linux)
- Animated progress bar and pulsing status indicator (idle / working / success / warning / error)
- Persistent configuration in JSON files; everything the user configures is preserved between sessions
- Python 3.11 or higher
# 1. Clone the repository
git clone https://github.com/HenryXCC/Filo.git
cd filo
# 2. Create and activate a virtual environment
python -m venv .venv
.venv\Scripts\activate # Windows
source .venv/bin/activate # Linux / macOS
# 3. Install dependencies
pip install -r requirements.txt
# 4. Run
python main.py| Package | Min version | Purpose |
|---|---|---|
customtkinter |
5.2.0 | Graphical interface |
pillow |
10.0.0 | EXIF image metadata + tray icon |
mutagen |
1.47.0 | Audio metadata (ID3, Vorbis, APEv2…) |
watchdog |
4.0.0 | Watch Mode — real-time monitoring |
pystray |
0.19.4 | System tray icon and notifications |
tkinterdnd2 |
0.3.0 | Folder drag & drop |
matplotlib |
3.8.0 | Donut chart in the dashboard |
All dependencies are optional at runtime: if one is missing the corresponding feature is silently disabled and the rest of the app works normally.
filo/
├── main.py # Entry point
├── LICENSE # Licencia del proyecto
├── assets/
│ ├── icon.ico # App icon (Windows .ico)
│ ├── icon.png # App icon (Linux / macOS / fallback)
│ └── screenshots/
│ ├── en/ # English UI screenshots
│ └── es/ # Spanish UI screenshots
│
├── core/ # Business logic
│ ├── organizer.py # Organize, undo, config, error handling
│ ├── watcher.py # Watch Mode (watchdog)
│ ├── rules.py # Custom rules engine
│ ├── history.py # Session history (last 20)
│ ├── metadata.py # EXIF and ID3 extraction
│ ├── duplicates.py # Duplicate detection by MD5 hash
│ └── renamer.py # Bulk rename engine with templates
│
├── gui/ # Graphical interface
│ ├── i18n.py # Strings, translations (EN / ES), live refresh
│ ├── theme.py # Color palette, typography, category icons
│ ├── interface.py # Main window (AppFilo)
│ ├── preview.py # Preview with collapsible tree and sizes
│ ├── dashboard.py # Post-organization dashboard with donut chart
│ ├── settings.py # Settings with 5 tabs (CTkTabview)
│ ├── duplicates.py # Duplicate detector window
│ ├── renamer.py # Bulk renamer window
│ └── tray.py # System tray icon
│
├── utils/
│ └── helpers.py # Unique names, MD5 hash
│
├── tests/
│ └── test_organizer.py # 56 test cases
│
├── requirements.txt
├── pyproject.toml
└── README.md
| Variable (EN) | Variable (ES) | Value |
|---|---|---|
{name} |
{nombre} |
Filename without extension |
{extension} |
{extension} |
Extension with dot (.mp3) |
{ext} |
{ext} |
Extension without dot (mp3) |
{year} |
{año} |
Modification year |
{month} |
{mes} |
Modification month (01–12) |
{day} |
{dia} |
Modification day (01–31) |
{hour} |
{hora} |
Modification hour |
{min} |
{min} |
Modification minutes |
{counter} |
{contador} |
Zero-padded sequential number (001, 002…) |
{artist} |
{artista} |
Artist — audio tags (requires mutagen) |
{album} |
{album} |
Album — audio tags (requires mutagen) |
{title} |
{titulo} |
Track title (requires mutagen) |
{track} |
{pista} |
Track number (requires mutagen) |
{photo_year} |
{año_foto} |
EXIF year — image (requires Pillow) |
{photo_month} |
{mes_foto} |
EXIF month — image (requires Pillow) |
{photo_day} |
{dia_foto} |
EXIF day — image (requires Pillow) |
{camera} |
{camara} |
EXIF camera model (requires Pillow) |
Variables work in both languages — you can mix them freely in the same template.
Template examples:
{year}-{month}-{day}_{name}{extension} → 2024-03-15_vacation.jpg
{artist} - {title}{extension} → Radiohead - Karma Police.mp3
{counter}_{name}{extension} → 001_report.pdf
{photo_year}/{photo_month}/{name}{extension} → 2023/08/DSC_0042.jpg
Tip: when inserting variables via the chip buttons, date variables (
{year},{month},{day}), time variables ({hour},{min}), and audio variables ({artist},{album},{title},{track}) automatically receive a-separator between them. Typing the template by hand gives you full control.
| Type | Condition |
|---|---|
| Name contains | The filename includes the specified text |
| Name matches pattern | The filename matches a glob pattern (invoice_*.pdf) |
| Extension is | The file extension matches exactly |
| Size greater than (MB) | The file is larger than the specified value in MB |
| Size less than (MB) | The file is smaller than the specified value in MB |
| Modified before | The modification date is before the specified date |
| Modified after | The modification date is after the specified date |
Rules are evaluated in definition order. The first match determines the destination folder and the rest are ignored. Rules take priority over extension-based classification.
If the app encounters a file it cannot move (for example, an .xlsx open in Excel) it does not stop. Instead:
- It skips that file and continues with the rest.
- At the end, the status indicator turns amber (partial success).
- The dashboard opens with the errors section expanded, showing the error type for each failed file.
- The
.txtreport documents both lists with the detail of each failure.
pip install pytest
pytestThe test suite covers core/organizer.py, core/renamer.py, and utils/helpers.py with 56 test cases including normal flows, partial error handling, name collisions, resilient undo, renamer template engine, and English variable alias tests.
A ready-to-use executable is published in GitHub Releases — no Python required.
To build it yourself:
pip install pyinstallerpyinstaller --name "Filo" --windowed --icon "assets/icon.ico" --add-data "assets;assets" --add-data "config.json;." --add-data "app_settings.json;." --noconfirm main.pyOn Linux / macOS replace the semicolons with colons:
assets:assets
After building, the dist/ folder will contain:
dist/
└── Filo/
├── Filo.exe ← Main executable (double-click to run)
└── _internal/ ← All dependencies (do NOT delete)
├── customtkinter/
├── PIL/
└── ...
Distribute the entire Filo/ folder. The user runs Filo.exe directly — no Python installation needed.
This project is licensed under the MIT License - see the LICENSE file for details.
- Organización automática por categoría: Imágenes, Documentos, Videos, Audios, Diseño, Instaladores y Comprimidos, y más
- Los archivos sin categoría van a una carpeta
Otros - Jerarquía por metadatos — al activarla, las imágenes se organizan en subcarpetas por fecha EXIF (
Imágenes/2024/01 - Enero/) y el audio por artista y álbum (Audios/Radiohead/OK Computer/). Los archivos sin metadatos van a la carpeta base sin cambios - Motor de reglas personalizadas con 7 tipos de condición — nombre contiene, patrón glob, extensión, tamaño, fecha de modificación — evaluadas antes que las extensiones; gana la primera que coincide
- Procesamiento resiliente — si un archivo está bloqueado el programa lo omite, registra el error y continúa con el resto
- Tres políticas ante duplicados — renombrar automáticamente (
archivo_1.txt), sobrescribir o saltar
- Previsualizar antes de organizar — árbol colapsable que muestra exactamente a dónde irá cada archivo, con la categoría destino y el tamaño de cada uno; el total de datos a mover aparece en el resumen. Ningún archivo se mueve hasta confirmar
- Deshacer — revierte la última organización al instante y elimina las carpetas vacías resultantes, incluyendo jerarquías anidadas de hasta 3 niveles
- Detector de duplicados — escanea la carpeta por contenido (hash MD5) y agrupa los archivos idénticos en tarjetas; por defecto conserva el más antiguo y marca el resto para eliminar, con diálogo de confirmación antes de borrar
- Renombrador masivo — plantillas con 17 variables (
{contador},{año},{artista},{año_foto}, etc.), filtro por extensión, tabla de vista previa en tiempo real con detección de colisiones, nada se renombra hasta aplicar
- Watch Mode — vigilancia en tiempo real mediante
watchdog; organiza automáticamente cada archivo nuevo que aparece en la carpeta raíz con un debounce de 800 ms. Al cerrar la ventana con Watch Mode activo la app se minimiza a la bandeja en lugar de cerrar - Icono en bandeja del sistema — menú contextual para mostrar la ventana, activar/desactivar Watch Mode y salir; con notificaciones del sistema al organizar en segundo plano
- Panel de ajustes con cinco pestañas:
- Extensiones — activar o desactivar extensiones por categoría (incluidas las personalizadas), añadir extensiones propias
- Categorías — crear y eliminar categorías sin tocar el código
- Reglas — añadir, activar/desactivar y eliminar reglas personalizadas
- Exclusiones — patrones glob de archivos a ignorar (ej.
.*,desktop.ini,temp_*) - Config — jerarquía por metadatos, política de duplicados, exportar/importar
config.json, limpiar historial
- Exportar / Importar la configuración de categorías para compartirla o migrarla a otro equipo
- Historial de sesiones — últimas 20 organizaciones con fecha, carpeta, archivos movidos y errores
- Dashboard post-organización — gráfica de dona con desglose por categoría, sección de errores colapsable y botón para abrir el reporte
- Reporte
.txtguardado en la carpeta organizada con secciones "ARCHIVOS MOVIDOS", "ARCHIVOS NO MOVIDOS" (con tipo de error) y "ARCHIVOS OMITIDOS"
- Drag & Drop — arrastra una carpeta directamente sobre la ventana para seleccionarla (requiere
tkinterdnd2) - Icono de la app visible en la barra de título de la ventana y en la barra de tareas / dock
- Ventana redimensionable con tamaño mínimo de 700 × 420
- Tipografía adaptada al sistema operativo: Segoe UI (Windows), Helvetica Neue (macOS), DejaVu Sans (Linux)
- Barra de progreso animada e indicador de estado con pulso (idle / working / success / warning / error)
- Configuración persistente en archivos JSON; todo lo que el usuario configure se conserva entre sesiones
- Python 3.11 o superior
# 1. Clonar el repositorio
git clone https://github.com/HenryXCC/Filo.git
cd filo
# 2. Crear y activar entorno virtual
python -m venv .venv
.venv\Scripts\activate # Windows
source .venv/bin/activate # Linux / macOS
# 3. Instalar dependencias
pip install -r requirements.txt
# 4. Ejecutar
python main.py| Paquete | Versión mínima | Para qué |
|---|---|---|
customtkinter |
5.2.0 | Interfaz gráfica |
pillow |
10.0.0 | Metadatos EXIF de imágenes + icono de bandeja |
mutagen |
1.47.0 | Metadatos de audio (ID3, Vorbis, APEv2…) |
watchdog |
4.0.0 | Watch Mode — vigilancia en tiempo real |
pystray |
0.19.4 | Icono en la bandeja del sistema y notificaciones |
tkinterdnd2 |
0.3.0 | Drag & Drop de carpetas |
matplotlib |
3.8.0 | Gráfica de dona en el dashboard |
Todas las dependencias son opcionales en tiempo de ejecución: si alguna no está instalada la funcionalidad correspondiente se desactiva silenciosamente y el resto de la app sigue funcionando.
filo/
├── main.py # Punto de entrada
├── LICENSE # Licencia del proyecto
├── assets/
│ ├── icon.ico # Icono de la app (Windows .ico)
│ ├── icon.png # Icono de la app (Linux / macOS / fallback)
│ └── screenshots/
│ ├── en/ # Capturas con UI en inglés
│ └── es/ # Capturas con UI en español
│
├── core/ # Lógica de negocio
│ ├── organizer.py # Organizar, deshacer, config, manejo de errores
│ ├── watcher.py # Watch Mode (watchdog)
│ ├── rules.py # Motor de reglas personalizadas
│ ├── history.py # Historial de sesiones (últimas 20)
│ ├── metadata.py # Extracción de EXIF e ID3
│ ├── duplicates.py # Detección de duplicados por hash MD5
│ └── renamer.py # Motor de renombrado masivo con plantillas
│
├── gui/ # Interfaz gráfica
│ ├── i18n.py # Strings, traducciones (EN / ES), refresco en vivo
│ ├── theme.py # Paleta, tipografía e iconos por categoría
│ ├── interface.py # Ventana principal (AppFilo)
│ ├── preview.py # Vista previa con árbol y tamaños
│ ├── dashboard.py # Dashboard post-organización con dona
│ ├── settings.py # Ajustes con 5 pestañas (CTkTabview)
│ ├── duplicates.py # Ventana detector de duplicados
│ ├── renamer.py # Ventana renombrador masivo
│ └── tray.py # Icono de bandeja del sistema
│
├── utils/
│ └── helpers.py # Nombres únicos, hash MD5
│
├── tests/
│ └── test_organizer.py # 56 casos de prueba
│
├── requirements.txt
├── pyproject.toml
└── README.md
| Variable (ES) | Variable (EN) | Valor |
|---|---|---|
{nombre} |
{name} |
Nombre del archivo sin extensión |
{extension} |
{extension} |
Extensión con punto (.mp3) |
{ext} |
{ext} |
Extensión sin punto (mp3) |
{año} |
{year} |
Año de modificación |
{mes} |
{month} |
Mes de modificación (01–12) |
{dia} |
{day} |
Día de modificación (01–31) |
{hora} |
{hour} |
Hora de modificación |
{min} |
{min} |
Minutos de modificación |
{contador} |
{counter} |
Número secuencial con ceros (001, 002…) |
{artista} |
{artist} |
Artista — audio con tags (requiere mutagen) |
{album} |
{album} |
Álbum — audio con tags (requiere mutagen) |
{titulo} |
{title} |
Título de la pista (requiere mutagen) |
{pista} |
{track} |
Número de pista (requiere mutagen) |
{año_foto} |
{photo_year} |
Año EXIF de la foto (requiere Pillow) |
{mes_foto} |
{photo_month} |
Mes EXIF de la foto (requiere Pillow) |
{dia_foto} |
{photo_day} |
Día EXIF de la foto (requiere Pillow) |
{camara} |
{camera} |
Modelo de cámara EXIF (requiere Pillow) |
Las variables funcionan en ambos idiomas — puedes mezclarlas libremente en la misma plantilla.
Ejemplos de plantillas:
{año}-{mes}-{dia}_{nombre}{extension} → 2024-03-15_vacaciones.jpg
{artista} - {titulo}{extension} → Radiohead - Karma Police.mp3
{contador}_{nombre}{extension} → 001_informe.pdf
{año_foto}/{mes_foto}/{nombre}{extension} → 2023/08/DSC_0042.jpg
Tip: al insertar variables con los botones chip, las variables de fecha (
{año},{mes},{dia}), de hora ({hora},{min}) y de audio ({artista},{album},{titulo},{pista}) reciben automáticamente un separador-entre ellas. Escribir la plantilla a mano te da control total.
| Tipo | Condición |
|---|---|
| Nombre contiene | El nombre del archivo incluye el texto indicado |
| Nombre coincide con patrón | El nombre coincide con un patrón glob (factura_*.pdf) |
| Extensión es | La extensión del archivo es exactamente la indicada |
| Tamaño mayor que (MB) | El archivo pesa más del valor indicado en MB |
| Tamaño menor que (MB) | El archivo pesa menos del valor indicado en MB |
| Modificado antes de | La fecha de modificación es anterior a la fecha indicada |
| Modificado después de | La fecha de modificación es posterior a la fecha indicada |
Las reglas se evalúan en orden de definición. La primera que coincide determina la carpeta destino y las demás se ignoran. Las reglas tienen prioridad sobre la clasificación por extensión.
Si el programa encuentra un archivo que no puede mover (por ejemplo, un .xlsx abierto en Excel) no se detiene. En su lugar:
- Omite ese archivo y continúa con el resto.
- Al finalizar, el indicador de estado cambia a ámbar (éxito parcial).
- Se abre el dashboard con la sección de errores expandida, mostrando el tipo de error de cada archivo fallido.
- El reporte
.txtdocumenta ambas listas con el detalle de cada fallo.
pip install pytest
pytestEl archivo de tests cubre core/organizer.py, core/renamer.py y utils/helpers.py con 56 casos de prueba que incluyen flujos normales, manejo de errores parciales, colisiones de nombres, deshacido resiliente, motor de plantillas de renombrado y tests de alias en inglés.
Un ejecutable listo para usar se publica en GitHub Releases — sin necesidad de instalar Python.
Para generarlo tú mismo:
pip install pyinstallerColoca los archivos de icono en la carpeta assets/ antes de compilar:
assets/
├── icon.ico ← Icono Windows (se muestra en la barra de título Y en la barra de tareas)
└── icon.png ← Fallback PNG (Linux / macOS / renderizado con Pillow)
La app carga ambos archivos automáticamente al arrancar.
icon.icocontrola el icono nativo de Windows en la barra de tareas y se aplica automáticamente a todas las ventanas secundarias (preview, dashboard, ajustes, renombrador, duplicados, etc.).
pyinstaller --name "Filo" --windowed --icon "assets/icon.ico" --add-data "assets;assets" --add-data "config.json;." --add-data "app_settings.json;." --noconfirm main.pyEn Linux / macOS reemplaza los puntos y coma por dos puntos:
assets:assets
Tras compilar, la carpeta dist/ contendrá:
dist/
└── Filo/
├── Filo.exe ← Ejecutable principal (doble clic para iniciar)
└── _internal/ ← Todas las dependencias (NO eliminar)
├── customtkinter/
├── PIL/
└── ...
Distribuye la carpeta Filo/ completa. El usuario ejecuta Filo.exe directamente — no necesita Python instalado.
Este proyecto está licenciado bajo la Licencia MIT - consulte el archivo LICENSE para más detalles.