# Mulita - Self-Hosted Photo Management Application A self-hosted, Docker-deployed photo management application inspired by Lightroom's workflow. Mulita provides a fast, keyboard-driven interface to browse, organize, tag, and manage your photo library. ## Features - **Photo Organization**: Browse photos in a timeline view with virtual scrolling for performance - **Thumbnail Generation**: Automatic thumbnail generation for all photo formats including RAW - **Metadata Extraction**: Full EXIF/XMP metadata extraction and search - **Keyboard Shortcuts**: Lightroom-style keyboard navigation and actions - **File Support**: JPEG, PNG, RAW formats (CR2, CR3, NEF, ARW, etc.), HEIC/HEIF, and videos - **Heaps**: Temporary collections for organizing photos - **Tags & Ratings**: Organize with tags, star ratings, and color labels - **Dark Mode**: Photography-optimized dark interface ## Tech Stack ### Backend - Python 3.12 with FastAPI - SQLite with SQLAlchemy (async) - Celery + Redis for background tasks - pyvips for fast thumbnail generation - ExifTool for metadata extraction ### Frontend - React 18 with TypeScript - Vite for fast development - TanStack Query for data fetching - TanStack Virtual for virtualized scrolling - Tailwind CSS for styling - Zustand for state management ## Quick Start ### Prerequisites - Docker and Docker Compose - Photo directories to mount ### Setup 1. Clone the repository: ```bash git clone cd muleimage ``` 2. Configure your photo directories in `.env`: ```bash # Edit .env file PHOTO_DIRS=/path/to/your/photos ``` 3. Start the application: ```bash docker-compose up -d ``` 4. Access the application at `http://localhost:3000` ### Photo directory mounts and permissions Mulita is a Lightroom-style manager — file operations (rename, move, discard, empty discard pile) need to mutate the filesystem under your photo mounts. The default `docker-compose.yml` mounts: - `${PHOTO_DIRS}` → `/photos` (read-write) - `~/Pictures` → `/host/Pictures` (**read-write** by default so file operations work on your system Pictures folder out of the box) If you want a strict read-only library — for example pointing at a network share or your authoritative archive — change `:rw` to `:ro` on the mount in `docker-compose.yml`. Mulita will keep working for browsing, rating, color labels, picks, heaps, and the discard flag, but the following endpoints will return an error from the OS (`EROFS` / `Read-only file system`): - `PATCH /photos/{id}` with a new `filename` (rename) - `DELETE /discard/empty` (file unlinks) - Future move / copy endpoints **Heads up**: with `:rw`, Mulita has full write access to whatever host directory you mount under `~/Pictures`. Treat the same way you would Lightroom's catalog folder. ## Architecture The application consists of 5 Docker services: - **frontend**: React SPA served by Nginx - **backend**: FastAPI REST API - **worker**: Celery workers for background tasks - **redis**: Message broker for Celery - **db**: SQLite database (file-based) ## Keyboard Shortcuts | Key | Action | |-----|--------| | `←` `→` `↑` `↓` | Navigate photos | | `Space` | Quick preview | | `Enter` | Open loupe view | | `P` | Pick photo | | `X` | Reject photo | | `1-5` | Set star rating | | `Tab` | Toggle left sidebar | | `I` | Toggle metadata panel | | `G` | Grid view | | `E` | Loupe view | | `Delete` | Move to trash | ## Development ### Backend Development ```bash cd backend pip install -r requirements.txt uvicorn app.main:app --reload ``` ### Frontend Development ```bash cd frontend npm install npm run dev ``` ## Configuration Edit `mulita.yml` to configure: - Source photo directories - Thumbnail sizes and quality - Scanner settings - Performance tuning ## Performance - Handles 100,000+ photos efficiently - Virtual scrolling for smooth timeline navigation - Thumbnail generation at 10+ photos/second - SQLite FTS5 for fast full-text search ## Future Features (Phase 2) - AI-powered scene classification - Face detection and clustering - Smart albums - Duplicate detection - Export presets - Multi-user support ## License MIT