Getting started¶
This page walks the full media-ingest workflow on a real project, from an unorganized dump of trip footage to renamed, per-day folders you can drop into DaVinci Resolve.
Requirements¶
- Python 3.12 or newer.
- uv to install and run the tool.
- exiftool on your
PATH. Thescanstep shells out to it to read metadata.
exiftool is the only external dependency, and it is only needed at scan time. Everything after scan works from the manifest that scan writes.
Install¶
Clone the repository and sync its dependencies with uv:
You can then invoke the CLI with uv run media-ingest from anywhere, or install it onto your PATH with uv tool install . and call it as media-ingest. The examples below use the bare media-ingest form; prefix them with uv run if you have not installed the tool globally.
A real project¶
Say your trip footage has been copied off the cameras into a folder on an external drive, with each device dumped into its own subfolder:
/Volumes/T7/PROJECTS/2026-03_my-trip/
DCIM/ # DJI Osmo cards
iphone-export/ # AirDrop / Photos export
mic/ # DJI Mic internal recordings
1. Initialize¶
Change into the project directory and write a config file. Pass the trip timezone and the trip date range:
cd "/Volumes/T7/PROJECTS/2026-03_my-trip"
media-ingest init --timezone -04:00 --start 2026-03-14 --end 2026-03-22
This writes ingest.toml at the project root. init also pre-fills the [scan] include list with the media-looking subdirectories it found, but you should open the file and confirm it lists only the folders that hold raw, unrenamed media. See init and the timezone model for details on the timezone option.
2. Scan¶
Read metadata and content hashes for every file in the included directories:
Scan is read-only. It runs exiftool once over all the files, classifies each into a device profile, computes a fast content hash, and writes everything to .ingest/manifest.json. It prints a per-device count so you can sanity-check that every camera is recognized. If any files come back as unknown, the next step will list them.
3. Plan¶
Compute the renames, run the quality checks, and build the HTML timeline report:
Plan is also read-only. It writes .ingest/plan.json (the exact list of moves) and .ingest/report.html (the visual review), and prints a summary of planned renames, exclusions, and warnings. Nothing has moved yet.
4. Review the report¶
Open the timeline report and look it over:
The report lays out each day as a set of device swimlanes. A wrong timezone offset shows up immediately as mic bars that do not line up with the camera clips they were recorded with. Use the day filter chips and drag-to-zoom to inspect a single day closely. See the timeline report page for a full tour.
5. Spot-check with align¶
If a DJI clip looks like it is in the wrong place, or a timezone warning fired, cross-check it against iPhone media, whose clock is authoritative:
This lists everything captured around that clip's corrected time, with iPhone rows highlighted. Open a neighboring iPhone photo and confirm the scenes agree. See align.
6. Apply¶
When the plan looks right, execute it:
Apply asks for confirmation, then renames each file. It re-hashes every file immediately before moving it, refuses to overwrite anything, only renames within the project volume, and appends each completed move to .ingest/apply-log.jsonl. Pass --yes to skip the prompt.
The result is per-day folders with names that sort chronologically across all devices:
media/source/action_cameras/2026-03-16/
2026-03-16T184422 - OsmoPocket3 - 0105.mp4
media/source/iphones/2026-03-16/
2026-03-16T184510 - iPhone 17 Pro - IMG_4821.mov
7. Undo if needed¶
Every move is journaled, so the whole operation reverses cleanly:
Because apply is idempotent, an interrupted run can simply be re-run instead of undone. See the safety model for how this works.
The state directory¶
Everything media-ingest produces lives in a .ingest/ directory at the project root:
manifest.jsonis the output of scan: metadata, device detection, and hashes.plan.jsonis the output of plan: the exact moves, exclusions, and warnings.report.htmlis the self-contained timeline report.apply-log.jsonlis the journal that apply writes and undo reads.
You can safely delete .ingest/ to start over from scan.