A CLI tool for renaming video and photo files after a day of shooting. Built as a learning project to explore Go.
mfren walks a directory and renames media files into a consistent, date-stamped format. It supports camera IDs, dry-run previews, and both flat and nested directory structures.
For the reasoning behind key design decisions, see Learning Go: CLI Design Decisions That Held Up.
go install github.com/bmcfads/mfren@latestOr build from source:
git clone https://github.com/bmcfads/mfren
cd mfren
go install .Usage:
mfren <directory> [flags]
Flags:
-c, --camera string camera ID override
-d, --date string date override (YYYY-MM-DD)
-n, --dry-run print renames without applying them
-h, --help help for mfren
--list-extensions print supported file extensions
--verbose print each rename as it happens
-v, --version version for mfren
<YYYY-MM-DD>-<camera-id>-<NNN>.<ext>
Note
The camera ID is a free-form string and may itself contain dashes.
For example, with a camera ID of max2-c01:
2026-03-21-max2-c01-001.360
2026-03-21-max2-c01-002.360
2026-03-21-max2-c01-003.360
Rename files in a flat directory, using the directory name as the camera ID:
mfren ./mediaOverride the camera ID:
mfren ./media --camera max2-c01Override the date:
mfren ./media --date 2026-03-21Rename files across multiple camera subdirectories, using each subdirectory name as the camera ID:
mfren ./media
# media/
# max2-c01/ -> 2026-03-21-max2-c01-001.360 ...
# hb12-c01/ -> 2026-03-21-hb12-c01-001.mp4 ...Preview renames without applying them:
mfren ./media --dry-runPrint supported extensions:
mfren --list-extensionsWarning
The script deletes and recreates the media directory at the destination on each run.
A script is provided to generate mock media files for manual testing:
./scripts/gen-test-files.sh [destination]If no destination is provided, files are created under /tmp/media. The script will prompt you to select a scenario:
Scenario 1: Flat directory
Creates a single directory with 10 .360 files and a shoot-notes.txt:
media/
GS01000001.360
...
GS01000010.360
shoot-notes.txt
Scenario 2: Subdirectories with top level files
Creates a top-level directory with files plus three camera subdirectories, each with a different file type:
media/
GS01000001.360 ... GS01000010.360
shoot-notes.txt
cam-id-01/
GS01000001.360 ... GS01000010.360
shoot-notes.txt
cam-id-02/
GX01000001.mp4 ... GX01000010.mp4
shoot-notes.txt
cam-id-03/
GOPR000001.jpg ... GOPR000010.jpg
shoot-notes.txt
- If no subdirectories exist, files in the target directory are renamed directly.
- If the target directory contains subdirectories, files within each subdirectory are renamed independently using the subdirectory name as the camera ID. Top level files are ignored.
- Only one level of subdirectories is searched. No recursion.
- File count resets to
001per subdirectory.
- If subdirectories are present and
--camerais provided,mfrenwill exit with an error. Target a single directory or rely on subdirectory names as camera IDs instead. - If subdirectories are present and
--camerais not provided, each subdirectory name is used as the camera ID. - If no subdirectories are present and
--camerais provided, the provided value is used as the camera ID. - If no subdirectories are present and
--camerais not provided, the target directory name is used as the camera ID.
- Only media files are renamed. Use
--list-extensionsto see supported extensions. - Unsupported file extensions are skipped silently.
- Hidden files (starting with
.) are skipped.
- A confirmation prompt is shown before renaming since the operation is destructive and cannot be undone.
- Use
--dry-runto verify the expected output before committing.
- Silent on success by default. No news is good news.
- The current date is used by default. Use
--dateto override. - Use
--verboseto print each rename as it happens. - Use
--dry-runto preview renames without applying them. Skips the confirmation prompt.
mfren is a learning project built to get comfortable with Go, Cobra, and CLI tool design patterns. It solves a real problem I had (renaming media files consistently after a shoot) while serving as a foundation for more complex Go projects.
MIT - see LICENSE for details.