Intelligent duplicate movie detection with multi-user play status analysis
A Go application that helps you safely identify and remove duplicate movies from your Jellyfin server while preserving user watch history. The application analyzes movie metadata, file paths, and play status across all users to provide intelligent recommendations for safe duplicate removal.
- Fetches all movies from your Jellyfin server
- Identifies potential duplicates based on movie name and production year
- Uses Levenshtein distance to analyze file paths for similarity
- Classifies duplicates vs mismatches (95% similarity threshold)
- Multi-user play status analysis - checks if users have seen different versions
- Play status discrepancy detection - identifies when users have seen one version but not the other
- Safe deletion guidance - only recommends deletion when play status is identical
- Play status synchronization - allows marking movies as seen for specific users
- Movie deletion - permanently remove duplicate movies from Jellyfin
-
Start the container:
jellyfin-duplicate: image: raymice/jellyfin-duplicate:latest container_name: jellyfin-duplicate ports: - "8080:8080" environment: - JELLYFIN_URL=${JELLYFIN_URL} - JELLYFIN_API_KEY=${JELLYFIN_API_KEY} - JELLYFIN_ADMIN_USER_ID=${JELLYFIN_ADMIN_USER_ID} restart: unless-stopped
-
Run the container:
docker run -d \ -p 8080:8080 \ -e JELLYFIN_URL="your-jellyfin-url" \ -e JELLYFIN_API_KEY="your-api-key" \ -e JELLYFIN_ADMIN_USER_ID="your-user-id" \ --name jellyfin-duplicate \ raymice/jellyfin-duplicate:latest
-
Build the Docker image:
-
amd64
docker build --platform linux/amd64 -t jellyfin-duplicate . -
arm64
docker build --platform linux/arm64 -t jellyfin-duplicate .
-
-
Run the container:
docker run -d \ -p 8080:8080 \ -e JELLYFIN_URL="your-jellyfin-url" \ -e JELLYFIN_API_KEY="your-api-key" \ -e JELLYFIN_ADMIN_USER_ID="your-user-id" \ --name jellyfin-duplicate \ jellyfin-duplicate
-
(Optional) Mount a custom configuration file:
docker run -d \ -p 8080:8080 \ -v /path/to/your/config.json:/app/config.prod.json \ -e JELLYFIN_URL="your-jellyfin-url" \ -e JELLYFIN_API_KEY="your-api-key" \ -e JELLYFIN_ADMIN_USER_ID="your-user-id" \ --name jellyfin-duplicate \ jellyfin-duplicate
- Go to the release page of the target version in GitHub.
- Download the binary according to your OS & Architecture
- Run the binary with your environment variables or set your environment variables in your OS before;
# macOS amd64 (Intel)
# Current Session Only, otherwise set variables in your bashrc
JELLYFIN_URL=XXX JELLYFIN_API_KEY=XXX JELLYFIN_ADMIN_USER_ID=XXX jellyfin-duplicate-darwin-amd64
# macOS arm64 (Apple Silicon)
# Current Session Only, otherwise set variables in your bashrc
JELLYFIN_URL=XXX JELLYFIN_API_KEY=XXX JELLYFIN_ADMIN_USER_ID=XXX jellyfin-duplicate-darwin-arm64
# windows amd64/arm64
# Current Session Only, otherwise set variables in your User Level environment values
set JELLYFIN_URL=XXX
set JELLYFIN_API_KEY=XXX
set JELLYFIN_ADMIN_USER_ID=XXX
jellyfin-duplicate-windows-amd64.exe-
Clone this repository
-
Install dependencies:
go mod download
-
Create .env file (look at .env.example)
-
Run the application:
go run main.go
The application need to be configured using environment variables:
JELLYFIN_URL: URL of your Jellyfin server (required)JELLYFIN_API_KEY: Jellyfin API key (required)JELLYFIN_ADMIN_USER_ID: Jellyfin Admin user ID (required)
Access the web interface at: http://localhost:8080
Available endpoints:
-
Web interface:
http://localhost:8080- Interactive duplicate analysis -
Analysis page:
http://localhost:8080/analysis- Detailed results with play status
- The application fetches all movies from your Jellyfin libraries
- It groups movies by their name and production year
- For each group with multiple movies, it compares file paths using Levenshtein distance
- If path similarity is ≥95%, it's classified as a potential duplicate
- If path similarity is <95%, it's classified as a potential mismatch
- Play status analysis: For each duplicate pair, the application checks if users have seen both versions
- Safe deletion guidance: Only shows delete buttons when both versions have identical play status
- Discrepancy detection: Identifies when users have seen one version but not the other
The application analyzes play status across all users to prevent data loss:
- ✅ Safe to delete: When both versions have identical play status (same users have seen both)
- ❌ Not safe to delete: When users have seen one version but not the other
- 🔄 Play status discrepancies: The application helps you synchronize play status before deletion
- Identical play status: Both versions have been seen by the same users → Safe to delete one
- Different play status: User A saw version 1, User B saw version 2 → NOT safe to delete
- Partial overlap: Some users saw both, others saw only one → Requires synchronization
The application provides tools to mark movies as seen for specific users, ensuring you don't lose watch history when removing duplicates.
- Gin - Web framework
- Resty - HTTP client
- Levenshtein - String similarity
- Lo - Utility functions for Go
- Logrus - Structured logging
- Run analysis: Access the
/analysispage to see all potential duplicates - Review duplicates: Check the similarity percentage and file paths
- Check play status: Look for the "✅ Safe to delete" notice or play status discrepancies
- Handle discrepancies: If users have seen different versions:
- Use the "Update Selected Users" button to synchronize play status
- Select which users should have the other version marked as seen
- Delete safely: Only delete movies that show the "✅ Safe to delete" notice
- Verify results: Refresh the page to ensure the duplicate is removed
- Always check play status before deleting any movie
- Synchronize play status when users have seen different versions
- Delete one version at a time and verify the results
- Backup your library before making bulk deletions
- Check file paths to ensure you're deleting the correct version
MIT