Skip to main content

AI-powered media folder analyzer and pruner using local Vision models

Project description

ShutterSort

AI-powered media folder analyzer and pruner. Scan your photo libraries, get intelligent scene analysis from a local Vision model, detect duplicates, and clean up with confidence.

pip install shuttersort
shuttersort

What It Does

Feature Description
AI Scene Analysis Classifies folders as landscape, portrait, event, junk, etc. using llama3.2-vision
Quality Scoring Rates each folder 1-10 based on composition, lighting, and content value
People Detection Counts people and describes appearances, emotions, and context
Duplicate Detection Finds duplicate files across folders using content hashing (first 1MB + file size)
Interactive Cleanup Review each folder in a Rich table, then Keep, Delete (to Trash), Open, or Skip
RAW Support Extracts previews from Sony ARW files using rawpy
Video Support Extracts 3 representative frames from MP4s using OpenCV
100% Local All AI runs locally via Ollama — no cloud, no uploads, no API keys

Quick Install

Prerequisites

  1. Python 3.10+

    python3 --version  # Must be 3.10 or higher
    
  2. Ollama installed and running

    # Install Ollama (macOS)
    brew install ollama
    
    # Start the Ollama service
    ollama serve
    
    # Pull the vision model (required)
    ollama pull llama3.2-vision
    
  3. macOS Full Disk Access (required for scanning Desktop, Downloads, Documents)

    • Open System SettingsPrivacy & SecurityFull Disk Access
    • Click the + button and add your terminal app:
      • Terminal.app: /System/Applications/Utilities/Terminal.app
      • iTerm2: /Applications/iTerm.app
      • VS Code Terminal: /Applications/Visual Studio Code.app
    • Restart your terminal after granting access

    Without Full Disk Access, macOS will silently return empty results when scanning protected folders.

Install ShutterSort

pip install shuttersort

Or from source:

git clone https://github.com/camiloavilacm/ShutterSort.git
cd ShutterSort
pip install -e .

Usage

Basic Scan (Default Paths)

Scans ~/Desktop, ~/Downloads, and ~/Documents:

shuttersort

Custom Paths

# Single path
shuttersort --path ~/Photos

# Multiple paths
shuttersort --path ~/Photos ~/Pictures ~/ExternalDrive

# Shorthand
shuttersort -p ~/Photos

Different Model

shuttersort --model llava
shuttersort -m llava

Dry Run (Preview Only)

See what would be deleted without actually deleting anything:

shuttersort --dry-run

Verbose Output

Show detailed debug logging:

shuttersort --verbose
shuttersort -v

Non-Interactive Mode

Just show the summary table without the interactive review prompts:

shuttersort --no-interactive

How It Works

ShutterSort uses a three-agent architecture:

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  LibrarianAgent │────>│  CuratorAgent   │────>│ DecisionAgent   │
│                 │     │                 │     │                 │
│ • Walks folders │     │ • Calls Ollama  │     │ • Rich table    │
│ • Finds media   │     │ • Analyzes imgs │     │ • [K/D/O/S] loop│
│ • Extracts ARW  │     │ • Scores 1-10   │     │ • AppleScript   │
│ • Finds dupes   │     │ • Detects people│     │ • Trash to Finder│
└─────────────────┘     └─────────────────┘     └─────────────────┘
  1. LibrarianAgent walks your folders, finds all media files (JPG, PNG, ARW, MP4), extracts previews from RAW files, and detects duplicates.
  2. CuratorAgent sends up to 5 representative images per folder to llama3.2-vision and returns a structured analysis (scene type, score, people count, emotions).
  3. DecisionAgent presents everything in a color-coded Rich table and walks you through each folder with an interactive [K]eep / [D]elete / [O]pen / [S]kip loop.

Duplicate Detection

Files are matched by a composite key: MD5 hash of the first 1MB + file size. When duplicates are found across folders, ShutterSort suggests keeping the copy in the folder with the higher AI score.

Delete Behavior (Trash vs Permanent)

When you choose Delete, ShutterSort uses AppleScript to move files to the macOS Trash:

tell application "Finder" to delete POSIX file "/path/to/file"

This is equivalent to right-clicking a file and selecting "Move to Trash." Files can be recovered from the Trash until you empty it. ShutterSort never permanently deletes files.

Temporary File Handling

All extracted previews (from ARW files) and video frames (from MP4s) are saved to temporary files using Python's tempfile module. These are cleaned up automatically after analysis. The gc.collect() call after ARW processing ensures native C memory from rawpy is released promptly, keeping RAM usage low on 16GB machines.

Output Example

ShutterSort — Folder Analysis Summary
┏━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━┓
┃ # ┃ Score ┃ Scene     ┃ People ┃ Folder           ┃ Summary                           ┃ Size     ┃ Pic%   ┃ Vid%   ┃ Dupes ┃
┡━━━╇━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━┩
│ 1 │ 8/10  │ landscape │ 2      │ .../vacation     │ Beautiful beach photos from vac…  │ 245.30 MB│ 100%   │ 0%     │ No    │
│ 2 │ 2/10  │ junk      │ 0      │ .../screenshots  │ Screenshots of documents and re…  │ 12.50 MB │ 100%   │ 0%     │ Yes   │
│ 3 │ 9/10  │ event     │ 6      │ .../family       │ Birthday party with family memb…  │ 512.00 MB│ 80%    │ 20%    │ No    │
└───┴───────┴───────────┴────────┴──────────────────┴───────────────────────────────────┴──────────┴────────┴────────┴───────┘

Troubleshooting

Problem Solution
"No media folders found" Check Full Disk Access for your terminal app (see Prerequisites above)
Ollama connection refused Run ollama serve in another terminal tab
Model not found Run ollama pull llama3.2-vision
ARW files fail to process Ensure rawpy is installed: pip install rawpy
Slow analysis Large folders take longer; use --verbose to see progress
JSON parse errors The retry loop handles this automatically (up to 3 retries)

Contributing

We welcome contributions! See CONTRIBUTING.md for the full guide.

Quick start for contributors:

git clone https://github.com/camiloavilacm/ShutterSort.git
cd ShutterSort
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest -m "not integration"

Branching Model

  • main — Production (auto-publishes to PyPI)
  • develop — Staging (auto-publishes to TestPyPI)
  • feature/* — Feature branches (PR → develop)

CI/CD

Every PR runs lint (ruff), type checks (mypy), and tests (pytest) on Python 3.10–3.13.

License

MIT — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shuttersort-0.1.0.tar.gz (37.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

shuttersort-0.1.0-py3-none-any.whl (29.2 kB view details)

Uploaded Python 3

File details

Details for the file shuttersort-0.1.0.tar.gz.

File metadata

  • Download URL: shuttersort-0.1.0.tar.gz
  • Upload date:
  • Size: 37.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for shuttersort-0.1.0.tar.gz
Algorithm Hash digest
SHA256 cf8b8b0e26645473ed4a522e995ddde648b8187387bc7b96a2361467e1312a24
MD5 00e58d90034a803e95b31363655549ae
BLAKE2b-256 bd1d516a0ca15c8069a3f0831ce216badfa209eacd6414cd7a48ff1ce13fb914

See more details on using hashes here.

File details

Details for the file shuttersort-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: shuttersort-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 29.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for shuttersort-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fe17e70106099bfbc3c3cf379ff8f9bd3959405e0b0203316d1f3e6850188434
MD5 c93e5efb94cc3358a0457dd61e6d3025
BLAKE2b-256 0dd0551eca0330f65c0ec48506a4a41ecc7b773a55dbe0efb447d24c8e76e287

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page