A local web-based photo and video culling tool for macOS. Quickly review a chaotic folder of images and videos with arrow keys — keep the good ones, send the rest to Trash.
← prev → next
↑ keep ↓ delete (Trash)
Apple Photos is fine for managed libraries, but if you have a chaotic folder — a camera dump, an exported WeChat media cache, a Downloads pile — there's no fast way to look at every file and decide. Slidebox is iOS-only. PhotoSweeper is for finding duplicates. This is the in-between: just sit down, hold the arrow keys, and clear out the noise.
Built in an afternoon to deal with a ~170,000-file WeChat cache.
- Single file, no
pip install— pure Python standard library - Keyboard driven — four arrow keys, full screen, no clicking
- Browser UI — runs on
localhost, no app to install - Live folder switching — change source / keep folder from the web UI
- Type filter — all / images only / videos only
- Range-aware video streaming — scrub through video timelines smoothly
- Safe deletes — files go to the macOS Trash, recoverable until you empty it
- macOS (uses
osascriptto talk to Finder for Trash semantics) - Python 3.7+ — already shipped with macOS
There is nothing to install. Just download the script:
curl -O https://raw.githubusercontent.com/questionjie-max/photo-cull/main/photo_cull.pyOr git clone the repo. That's it.
python3 photo_cull.py <source-folder> [keep-folder]Examples:
# Review your camera dump, keep the good ones in ~/Desktop/Selected
python3 photo_cull.py ~/Pictures/Camera ~/Desktop/Selected
# Source only — kept files default to ./kept
python3 photo_cull.py ~/Downloads/photosYour browser will open http://127.0.0.1:8765/ automatically.
| Key | Action |
|---|---|
← |
Previous |
→ |
Next |
↑ |
Keep (move to keep folder) |
↓ |
Delete (move to macOS Trash) |
--port PORT HTTP port (default 8765)
--host HOST Bind address (default 127.0.0.1; use 0.0.0.0 for LAN)
--no-browser Don't auto-open the browser
You can change the source folder and the keep folder from the page header (press Enter or click the button to apply). The type filter (All / Photos / Videos) lets you focus on one kind at a time without restarting.
- Recursively scans the source folder for these extensions:
- Images:
jpg jpeg png gif heic heif webp bmp - Videos:
mp4 mov m4v webm
- Images:
- Serves files via a local HTTP server with HTTP Range support, so videos seek properly.
- Keep =
shutil.moveto the keep folder. Same-filesystem moves are instant and use no extra space. - Delete =
osascripttells Finder to delete the file, which sends it to the Trash. Recoverable until you empty Trash.
Why macOS only?
Trash semantics differ per OS. The Mac path uses osascript so the deletion is identical to Finder's "Move to Trash" — meta-data preserved, undo-from-Finder works. PRs that add Linux (gio trash) or Windows (SHFileOperation / send2trash) support are welcome.
Address already in use on launch?
Either the previous run is still around — lsof -ti:8765 | xargs kill — or another app is on 8765, pass --port 8766.
HEIC images don't render in Chrome? Chrome doesn't decode HEIC. Open the page in Safari instead, or convert to JPEG beforehand.
Some MP4 files won't play? Almost always H.265 / HEVC. Safari plays them, Chrome and Firefox often don't. Either keep them and review with a real video player, or transcode to H.264.
Can I undo a keep? The file is in your keep folder. Move it back manually.
Can I undo a delete? Open Trash, drag it back. It's not really deleted until you empty Trash.
Does it touch my files before I press a key?
No. Scanning is read-only. Files only move when you press ↑ or ↓.