Skip to content

Serph91P/MediaCurator

Repository files navigation

MediaCurator

Intelligently curate and manage your media library with automated cleanup rules. A Docker-optimized application for Sonarr, Radarr, Emby, and Jellyfin that helps you maintain a clean, organized media collection.

License Main Version Dev Version GitHub last commit (develop)

Features

  • Multiple Service Connections: Connect to multiple Sonarr, Radarr, and Emby instances
  • Watch History Integration: Sync watch history from Emby to make informed cleanup decisions
  • Dry Run Preview: Preview what would be cleaned up before running actual cleanup
  • Import List Exclusions: Automatically add deleted items to Sonarr/Radarr exclusion lists
  • Customizable Cleanup Rules: Create rules based on:
    • Days since last watched
    • Disk space thresholds
    • Minimum age requirements
    • Favorites exclusion
    • Genre/tag filters
    • Rating thresholds
    • Watch progress
  • Notifications: Get notified via Discord, Slack, or custom webhooks when media is cleaned up
  • Scheduled Cleanups: Configure automatic cleanup schedules using cron expressions
  • Secure Web Interface: Modern, responsive UI with JWT authentication
  • Docker Optimized: Built for containerized deployments with minimal resource usage

Quick Start

Docker Compose (Recommended)

  1. Create a docker-compose.yml:
services:
  mediacurator:
    image: ghcr.io/serph91p/mediacurator:latest
    container_name: mediacurator
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - TZ=Europe/Berlin
      - SECRET_KEY=your-secure-secret-key
    volumes:
      - ./data:/app/data
      - ./logs:/app/logs
      - /media:/media:ro  # Same path as your media server
  1. Start the container:
docker compose up -d
  1. Access the web interface at http://localhost:8080

Docker CLI

# Pull specific version
docker pull ghcr.io/serph91p/mediacurator:1.0.0

# Or pull latest stable
docker pull ghcr.io/serph91p/mediacurator:latest

# Or pull development version
docker pull ghcr.io/serph91p/mediacurator:dev

# Run container
docker run -d \
  --name mediacurator \
  -p 8080:8080 \
  -e TZ=Europe/Berlin \
  -e SECRET_KEY=your-secure-secret-key \
  -v $(pwd)/data:/app/data \
  -v $(pwd)/logs:/app/logs \
  -v /media:/media:ro \
  ghcr.io/serph91p/mediacurator:latest

Available Docker Tags

Production releases (main branch):

  • latest - Latest stable release from main branch
  • stable - Alias for latest
  • 0.0.31 - Specific production version (based on commit count)
  • v1.2.3 - Manual tagged releases (when you create a git tag)

Development builds (develop branch):

  • dev - Latest development build from develop branch
  • dev.0.0.30 - Specific development version (based on commit count)

Versioning: Dev und Main teilen sich die gleiche Zählnummer (commit count).

  • Push auf dev → dev.0.0.30
  • Nächster Push auf dev → dev.0.0.31
  • Merge auf main → 0.0.31 (gleiche Nummer!)
  • Push auf dev → dev.0.0.32

Git tagged releases (manual bumps):

  • v1.0.0, v1.2.3 - Manual version tags für MINOR/MAJOR bumps
  • 1.2 - Latest patch version of 1.2.x
  • 1 - Latest minor version of 1.x.x

Example pull commands:

# Latest stable release
docker pull ghcr.io/serph91p/mediacurator:latest

# Specific production version
docker pull ghcr.io/serph91p/mediacurator:0.1.5

# Latest development build
docker pull ghcr.io/serph91p/mediacurator:dev

# Specific development version
docker pull ghcr.io/serph91p/mediacurator:dev.0.0.27

Semantic Versioning

Das Projekt nutzt Semantic Versioning:

Format: MAJOR.MINOR.PATCH (z.B. 1.2.3)

  • MAJOR (1.x.x): Breaking Changes - Inkompatible API-Änderungen
  • MINOR (x.1.x): Neue Features - Rückwärtskompatibel
  • PATCH (x.x.1): Bugfixes - Rückwärtskompatibel

Version 0.x.y: Entwicklungsphase vor dem ersten stabilen Release

  • Die Zahlen können beliebig hoch gehen (0.0.99, 0.1.234, etc.)
  • Es gibt keine Regel, dass bei 9 umgeschaltet wird
  • Wechsel zu 1.0.0 erfolgt, wenn die Software produktionsreif ist

Automatisches Versioning:

  • Develop → main: Automatisch PATCH +1 (0.0.1 → 0.0.2)
  • Für MINOR/MAJOR Bumps: Manuell Git-Tag erstellen (z.B. v0.1.0, v1.0.0)
  • Development Builds: dev.0.0.COMMIT_COUNT

Configuration

Environment Variables

Variable Description Default
TZ Timezone for scheduling UTC
SECRET_KEY JWT signing key (change in production!) -
DATABASE_URL Database connection string sqlite+aiosqlite:////app/config/mediacurator.db
INITIAL_ADMIN_USER Pre-create admin user (optional) -
INITIAL_ADMIN_PASSWORD Password for pre-created admin (optional) -
DEBUG Enable debug logging false

Volume Mounts

Path Description Type
mediacurator_config/app/config Database and persistent data Named volume
mediacurator_logs/app/logs Application logs Named volume
/media Media files (read-only recommended) Bind mount

Note: Named volumes are used for application data and logs, managed automatically by Docker. The config volume is separate from media paths to avoid conflicts with Emby/Jellyfin mounts.

Media Path Mapping (Critical!)

The media path inside MediaCurator must match the path that Emby/Jellyfin uses!

When Emby reports a file location like /data/movies/Movie.mkv, MediaCurator needs to access that exact same path. If the paths don't match, file operations (delete, move to staging) will fail.

Example scenarios:

Emby sees MediaCurator mount Works?
/data/movies/... -v /mnt/storage/movies:/data/movies Yes
/media/... -v /mnt/storage:/media Yes
/data/movies/... -v /mnt/storage/movies:/media/movies No - paths don't match!

Correct setup example:

If your Emby docker-compose looks like this:

# Emby container
volumes:
  - /mnt/storage/movies:/data/movies
  - /mnt/storage/tv:/data/tv

Then MediaCurator should use the same container paths:

# MediaCurator container  
volumes:
  - /mnt/storage/movies:/data/movies      # Same path as Emby!
  - /mnt/storage/tv:/data/tv              # Same path as Emby!
  - /mnt/storage/staging:/data/staging    # For staging system (needs write access)

For staging/delete operations: Remove :ro (read-only) flag to allow MediaCurator to move/delete files.

Usage

Initial Setup

  1. Start the application with docker compose up -d
  2. Open http://localhost:8080 in your browser
  3. You'll be redirected to create your admin account (first user is automatically admin)
  4. Add your service connections (Sonarr, Radarr, Emby)
  5. Test connections to verify API access
  6. Configure libraries from your Emby server
  7. Create cleanup rules or use templates
  8. Set up notification channels (optional)
  9. Configure system settings (schedules, dry-run mode)

Cleanup Rules

Rules define when and how media should be cleaned up. Each rule can have multiple conditions:

  • Not Watched Days: Delete media not watched for X days
  • Disk Space Threshold: Only clean up when disk usage exceeds X%
  • Minimum Age: Don't delete media added less than X days ago
  • Exclude Favorites: Never delete favorited items
  • Exclude Currently Watching: Never delete items someone is actively watching
  • Exclude In Progress: Never delete items that are partially watched
  • Exclude Recently Added: Don't delete items added within X days
  • Genre/Tag Filters: Include or exclude by genre/tag
  • Rating Threshold: Only delete items rated below X
  • Watch Progress Threshold: Only delete if watch progress is below X%
  • Max Items Per Run: Limit how many items are deleted per cleanup run

Actions

  • Delete: Remove from Sonarr/Radarr and delete files
  • Unmonitor: Stop monitoring in Sonarr/Radarr but keep files
  • Notify Only: Send notification without taking action

Import Exclusion Integration

When "Add to Import Exclusion" is enabled on a rule, deleted items will be automatically added to:

  • Sonarr: Import List Exclusions (prevents re-downloading via import lists)
  • Radarr: Movie Exclusions (prevents re-downloading via import lists)

Dry Run Preview

The Preview page lets you see exactly what would be cleaned up without actually deleting anything:

  • View all items that match your rules
  • See detailed reasoning for why each item would/wouldn't be deleted
  • View item details (watch progress, ratings, genres, etc.)
  • Filter by rules or see all at once

Enable Dry Run Mode in Settings to have scheduled cleanups also run in preview mode.

Configuration

What's Configured Where?

Configuration Where Description
Service URLs & API Keys Web UI (Services) Stored in database
Cleanup Rules Web UI (Rules) Stored in database
Schedules Web UI (Settings) Stored in database
System Settings Web UI (Settings) Stored in database
Timezone (TZ) Environment Variable Container-level setting
SECRET_KEY Environment Variable Should not change after setup
Volume Mounts Docker Compose File system paths

API Documentation

The API documentation is available at /api/docs when running the application.

Development

Prerequisites

  • Python 3.114+
  • Node.js 24+
  • Docker (optional)

Local Development

# Backend
cd backend
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload

# Frontend
cd frontend
npm install
npm run dev

Docker Development

docker compose -f docker-compose.dev.yml up

Roadmap & TODOs

Testing & Deployment

  • Activate tests.yml workflow for automated testing
  • Add pytest unit tests for backend services
  • Add Vitest tests for frontend components
  • Extend release.yml for automatic Docker image builds
  • Push Docker images to GitHub Container Registry (ghcr.io)
  • Create production-optimized Docker image (multi-stage build)
  • Add health checks and monitoring endpoints

Performance & Optimization

  • Implement in-memory caching for Emby API calls (library items, watch status)
  • Optimize TanStack Query staleTime/gcTime (5-10 minutes for rarely-changed data)
  • Add SQLAlchemy eager loading where appropriate (reduce N+1 queries)
  • Implement pagination for large result sets (rules, media items, logs)
  • Add database indexes on frequently queried columns (external_id, service_connection_id)
  • Implement debouncing for search/filter inputs
  • Collapsible sidebar to maximize content area

UI/UX Improvements

  • Redesign sidebar with proper icon positioning and hover states
  • Mobile-responsive layout with hamburger menu
  • Create ResponsiveTable component for mobile-friendly data display
  • Add series evaluation mode and delete target options (9 granular options)
  • Improve conditions form spacing and grouping for better readability
  • Convert existing table pages to use ResponsiveTable component (History)
  • Add loading skeletons for better perceived performance
  • Implement toast notifications for all user actions
  • Add confirmation dialogs for destructive actions
  • Dark/Light theme toggle with system preference support
  • Mobile First Design
  • Dashboard with Watch Statistics (Most Viewed/Popular Movies & Series)
  • Libraries page with detailed per-library stats cards

Notifications & Integration

  • Migrate to Apprise URL-schema for 90+ notification services
  • Add notification preview/test button
  • Implement notification templates (customize message format)
  • Add webhook retry logic with exponential backoff
  • Support multiple notification channels per event type

Security & Auth

  • Add rate limiting for API endpoints
  • Implement session management with refresh tokens
  • Add audit logging for admin actions

Monitoring & Observability

  • Implement structured logging with correlation IDs
  • Add performance monitoring for slow queries

Features & Enhancements

  • Bulk operations for rules (enable/disable multiple)
  • Export/import rules as JSON
  • Per-library staging settings (with global fallback)
  • User tracking from Emby (MediaServerUser, UserWatchHistory models)
  • Most Popular Movies/Series by unique users (popularity stats)
  • Most Active Users statistics
  • Detailed library statistics API (/libraries/stats)
  • Advanced scheduling (different schedules per rule)
  • Dry-run per rule (not just global)
  • Media tags auto-management based on watch patterns

Statistics & Analytics (Planned)

  • Library Detail View (Overview, Media Browser, Activity Log per library)
  • Users Page (list all users with stats, last watched, watch time, last seen)
  • User Detail View (Overview, Activity, Timeline per user)
  • Global Activity Log (all playback sessions with filtering)
  • Statistics Dashboard with Charts (Daily Play Count, Play by Day/Hour)
  • Genre Distribution Charts (by duration and play count)
  • User Activity Timeline (when each user watched what)
  • Watch Patterns/Heatmap (peak hours and days)
  • Concurrent Streams Analysis (how many users watch simultaneously)
  • Watch Duration Stats (average session length)
  • Completion Rate Analytics (how often content is finished)
  • Binge-Watch Detection (detect series marathon sessions)
  • Shared vs. Solo Content (which content is watched by multiple users)
  • Cleanup Rules per User ("Delete only if NO user watched in X days")

Note: See PLANNED_FEATURES.md for detailed descriptions of planned features.

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting a pull request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors