Flatten Nested Files v0.2
Flatten a 40-Folder-Deep Dataset Without Losing the Captions
- status_message
- files_moved
- paired_files_moved
- stats_json
- log_output
Downloaded datasets and scraped galleries have a signature look: forty levels of nested folders with one image at the bottom. Training data, captioning jobs, and archive cleanups all hit the same wall - you want everything in one flat directory, and doing it by hand is misery. Flatten Nested Files v2 (displayed as v0.2, the naming is optimistic) recursively walks a directory tree and moves the files up, with an unusually thoughtful feature: it keeps paired files together. That's the thing most flattening scripts get wrong, and it's why this node earns its place.
The one required input is main_directory plus operation_mode: flatten_only moves everything straight into the target, flatten_and_organize also creates type subfolders (images/, movies/, text/), and organize_only tidies files in place without moving them up. The optional section is where the real control lives: flatten_depth lets you keep the first level of subfolders (useful when each subfolder is a source you want to preserve, like an Instagram profile), respect_paired_files (on by default) moves photo.jpg together with photo.xmp and photo.txt as a unit, and sidecar_handling decides whether captions ride along into the images folder or go to a sidecars folder.
The rest reads like a checklist of someone who's burned themselves before: dry_run previews without moving anything, handle_conflicts offers rename/skip/overwrite for duplicate filenames, preserve_source_folder prefixes or suffixes the original folder name onto files so you don't lose provenance, remove_empty_folders cleans up after itself, and max_scan_depth guards against pathological nesting. Outputs are status_message, files_moved (INT), paired_files_moved (INT) - a nice touch, because it confirms your captions actually followed their images - plus stats_json and log_output.
The mechanism is straightforward recursion with smart pairing logic, no magic. The trap is the same as any file-mover: this runs when the workflow executes, so a stray Queue press with dry_run off and handle_conflicts on overwrite is a permanent change. The dry_run default being off is the one thing I'd change about this node.
Framing honestly: this is a one-author pack with no community footprint, and Flatten is a utility that earns its keep on real dataset work but won't be in anyone's shareable art workflow. If your training folder looks like a fractal, though, this is the tool that flattens it while keeping every .txt caption glued to its image.
Install the pack and restart:
cd ComfyUI/custom_nodes
git clone https://github.com/EricRollei/AAA_Metadata_System
cd AAA_Metadata_System
pip install -r requirements.txt
Then the smart path: set dry_run to true, run it, read the log, and only flip dry_run off when the preview matches your mental model. Flattening is reversible in theory; doing it wrong is not.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| main_directory | STRING | Main directory where all files will be moved to | |
| operation_mode | COMBO | flatten_only | Choose operation mode: • flatten_only: Move all files directly into main_directory (NO type subfolders) • flatten_and_organize: Move files AND create type subfolders (images/, movies/, etc.) • organize_only: Don't move files up, just organize them in their current locations Note: organize_by_type parameter can override flatten_only to add type folders |
| file_typesopt | COMBO | images_only | Which files to process: • images_only: .jpg, .png, .webp, .gif, etc. • all_media: Images + videos (.mp4, .mov, etc.) • all_files: Everything including .txt, .pdf, etc. |
| flatten_depthopt | INT | 00–10 | Flatten nested folders to this depth: • 0 = Move ALL files to main directory • 1 = Keep 1st level subfolders, flatten everything inside them • 2 = Keep 2 levels, flatten below that Example: If main=instagram and depth=1, processes each profile folder (alisha.maghi/, 777luckyfish/) independently |
| respect_paired_filesopt | BOOLEAN | true | Keep paired files together (e.g., photo.jpg + photo.xmp + photo.txt). Paired files share the same base filename and are moved as a group. |
| skip_organized_foldersopt | BOOLEAN | true | Skip folders that already have type organization (contain images/, movies/, text/ subfolders). Useful to avoid re-organizing already processed directories. |
| organize_by_typeopt | BOOLEAN | false | Create type-based subfolders: • images/ for .jpg, .png, etc. • movies/ for .mp4, .mov, etc. • text/ for .txt, .pdf, .md • sidecars/ for .xmp, .json (unless kept with images) • other/ for unrecognized types When True: Always creates type folders (even with flatten_only mode) When False with flatten_only: All files go directly into main_directory |
| sidecar_handlingopt | COMBO | keep_with_images | Where to put sidecar/metadata files: • keep_with_images: Put .xmp/.json/.txt in images/ folder • separate_folder: Put all sidecars in sidecars/ folder • keep_txt_only: Only .txt with images, others to sidecars/ |
| remove_empty_foldersopt | BOOLEAN | true | Delete empty subdirectories after moving files. Leaves a clean directory structure with no leftover empty folders. |
| dry_runopt | BOOLEAN | false | Preview mode - show what WOULD be moved without actually moving anything. Great for testing settings before committing changes. |
| handle_conflictsopt | COMBO | rename | How to handle duplicate filenames: • rename: Add (1), (2), etc. to filename • skip: Leave original, don't move duplicate • overwrite: Replace existing file with new one |
| max_scan_depthopt | INT | 1001–200 | Maximum folder nesting depth to scan. Increase if you have very deeply nested folders (46+ levels). Prevents infinite loops and excessive scanning. |
| custom_type_mappingsopt | STRING | JSON mapping file extensions to custom folder names. Example: { ".pdf": "documents", ".cr2": "raw_photos", ".psd": "photoshop" } Files with these extensions go to specified folders instead of default type folders. | |
| custom_folder_mappingsopt | STRING | JSON mapping file TYPES to custom folder names. Example: { "movies": "videos", "images": "photos", "text": "documents" } Renames the default type folders (images→photos, movies→videos, etc.). | |
| preserve_source_folderopt | COMBO | none | Add original folder name to filename to preserve context: • none: photo.jpg (no change) • prefix: alisha.maghi_photo.jpg • suffix: photo_alisha.maghi.jpg Useful when flattening to avoid name conflicts and maintain source info. |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| status_message | STRING | — |
| files_moved | INT | — |
| paired_files_moved | INT | — |
| stats_json | STRING | — |
| log_output | STRING | — |