Media Request & Lifecycle Management for Plex & Jellyfin
Features • Quick Start • Configuration • VIPER • API
Flexerr manages your entire media lifecycle - from request to cleanup. Users add content to their watchlist, Flexerr coordinates with your media management tools (Sonarr/Radarr) to acquire and organize content, then intelligently cleans it up when everyone's done watching.
- Multi-Server Support - Works with Plex (OAuth) and Jellyfin (username/password)
- Watchlist Integration - Sync with Plex watchlists or Jellyfin favorites for automatic media requests
- Media Automation - Watchlist additions seamlessly integrate with Sonarr/Radarr for hands-free library management
- Auto-Invite - Automatically invite new users to your Plex server with configured library access
- VIPER - Intelligent episode cleanup based on user watch velocity
- Media Protection - Protect specific movies/shows from any cleanup rules
- Leaving Soon Collection - Grace period before deletion with collection visibility
- Watchlist Sync & Restoration - Tracks watchlist removals and re-adds; re-adding triggers automatic restoration and fresh download
- Rules Engine - Flexible cleanup rules based on watch status, age, ratings, and more
- Auto Convert - Hardware-accelerated video conversion with NVIDIA NVENC support
- Multi-User Support - Each user has their own watchlist and viewing history
- Connected Services Management - Configure and test services from the Settings page
- Debug Logging - Configurable log verbosity (OFF/BASIC/VERBOSE/TRACE) for troubleshooting
User Watchlist → Media Acquisition → Watch → VIPER Cleanup → Re-watchlist Restores
- User adds content to their Plex watchlist or Jellyfin favorites
- Flexerr detects the addition and coordinates with Sonarr/Radarr
- Content is acquired and organized in your library
- User watches the content
- VIPER tracks watch progress and velocity
- Cleanup rules add content to "Leaving Soon" collection (grace period)
- Content is cleaned up to save storage
- If user re-adds to watchlist later, Flexerr detects the re-add and triggers a fresh acquisition cycle (restoration)
Note: Protected items bypass all cleanup rules regardless of other settings.
Now available on Docker Hub!
docker pull sybersects/flexerr:latest
- Docker and Docker Compose
- Plex Media Server with OAuth enabled OR Jellyfin server
- Sonarr (for TV shows)
- Radarr (for movies)
- TMDB API Key (get one free)
Note: Flexerr is not compatible with Overseerr, Jellyseerr, or similar request management tools. Flexerr manages requests directly through Sonarr/Radarr and should be used as a standalone solution.
Option 1: Docker Hub (Recommended)
# Create a directory for Flexerr
mkdir flexerr && cd flexerr
# Download the example compose file
curl -O https://raw.githubusercontent.com/sybethiesant/flexerr/main/docker-compose.example.yml
mv docker-compose.example.yml docker-compose.yml
# Start Flexerr
docker compose up -dOption 2: Build from Source
git clone https://github.com/sybethiesant/flexerr.git
cd flexerr
docker compose up -d-
Open http://localhost:5505 in your browser
-
Choose your media server type:
- Plex: Sign in with your Plex account (first user becomes admin)
- Jellyfin: Enter your server URL and login credentials
-
Complete the setup wizard:
- Enter your TMDB API key
- Connect Sonarr and Radarr
- Configure your preferences
That's it! Users can now browse content, add to watchlists, and Flexerr handles the rest.
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 5505 |
TZ |
Timezone for scheduled tasks | UTC |
JWT_SECRET |
Secret for JWT tokens | Default fallback (set for production) |
NODE_ENV |
Environment mode | production |
Required if using: Auto Convert (DV5 conversion) or direct file deletion
Flexerr needs access to your media files for these features. The path inside the container must match what Sonarr/Radarr report as file paths.
To find the correct path:
- Go to Sonarr/Radarr → Activity → History
- Look at any completed download's file path
- Mount that root path into Flexerr
Example: If Sonarr shows files at /data/media/TV/Show Name/...
volumes:
- /your/host/path:/data/media # Maps to same path Sonarr usesCommon setups:
# If Sonarr/Radarr use /data/media internally
- /mnt/storage/media:/data/media
# If they use /movies and /tv separately
- /mnt/movies:/movies
- /mnt/tv:/tvservices:
flexerr:
# ...
volumes:
- flexerr-data:/app/data
# Media mount - required for Auto Convert and file deletion
# Path must match what Sonarr/Radarr report (see above)
- /your/media/path:/data/media
environment:
- TZ=America/New_York
# Optional: Fixed JWT secret
- JWT_SECRET=your-secret-here
# GPU access - required for hardware-accelerated Auto Convert
# devices:
# - /dev/dri:/dev/driGPU acceleration is only needed if you plan to convert incompatible files. If you're using the "Search for Alternate Release" feature without conversion fallback, no GPU is required.
-
Install the NVIDIA Container Toolkit on your host
-
Run the container with NVIDIA runtime:
docker run -d \
--name flexerr \
--runtime=nvidia \
-e NVIDIA_VISIBLE_DEVICES=all \
-e NVIDIA_DRIVER_CAPABILITIES=compute,video,utility \
-p 5505:5505 \
-v flexerr-data:/app/data \
-v /path/to/media:/Media \
sybersects/flexerr:latest- Verify GPU access:
docker exec flexerr nvidia-smi
docker exec flexerr ffmpeg -encoders 2>/dev/null | grep nvencDocker Compose (NVIDIA):
services:
flexerr:
image: sybersects/flexerr:latest
container_name: flexerr
restart: unless-stopped
runtime: nvidia
ports:
- "5505:5505"
volumes:
- flexerr-data:/app/data
- /path/to/media:/Media
environment:
- TZ=America/New_York
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=compute,video,utility
volumes:
flexerr-data:Supported encoders: h264_nvenc, hevc_nvenc, av1_nvenc
-
Ensure your host has VAAPI drivers installed (mesa-va-drivers on Debian/Ubuntu)
-
Pass through the render device:
docker run -d \
--name flexerr \
--device /dev/dri:/dev/dri \
-p 5505:5505 \
-v flexerr-data:/app/data \
-v /path/to/media:/Media \
sybersects/flexerr:latest- Verify VAAPI access:
docker exec flexerr ffmpeg -encoders 2>/dev/null | grep vaapiDocker Compose (VAAPI):
services:
flexerr:
image: sybersects/flexerr:latest
container_name: flexerr
restart: unless-stopped
devices:
- /dev/dri:/dev/dri
ports:
- "5505:5505"
volumes:
- flexerr-data:/app/data
- /path/to/media:/Media
environment:
- TZ=America/New_York
volumes:
flexerr-data:Supported encoders: h264_vaapi, hevc_vaapi
Install the Nvidia-Driver plugin from Community Applications, then add to your container template:
- Extra Parameters:
--runtime=nvidia - Add these environment variables:
NVIDIA_VISIBLE_DEVICES=allNVIDIA_DRIVER_CAPABILITIES=compute,video,utility
Automatically convert incompatible media formats for better playback compatibility. All conversions are optional and can be enabled individually in Settings.
Supported Conversions:
| Conversion | Description | Speed |
|---|---|---|
| DV Profile 5 → HDR10 | Fixes Plex-incompatible Dolby Vision | Slow (re-encode) |
| DV Profile 7 → HDR10 | Improves device compatibility | Slow (re-encode) |
| DV Profile 8 → HDR10 | Broadest compatibility | Slow (re-encode) |
| AV1 → HEVC | For devices without AV1 decode | Slow (re-encode) |
| MKV → MP4 | Container remux for iOS/web | Fast (no re-encode) |
| TrueHD/DTS-HD → EAC3 | Audio for streaming devices | Medium (audio only) |
Search for Alternate Release (Smart Mode):
Instead of converting immediately, Flexerr can try to find a compatible release first:
- Detects incompatible format in newly imported file
- Quarantines the file (moves to temp location)
- Optionally blocklists the release in Sonarr/Radarr (prevents re-download)
- Triggers a new search for alternate releases
- Waits for a configurable time (default 24 hours) for an alternate
- If compatible alternate arrives → deletes quarantined file, done
- If no alternate found → restores file and converts (if enabled)
This is ideal when you want the best possible quality - conversion should be the fallback, not the default. You can even disable conversion entirely and just use this to find better releases.
Configure via Settings → Auto Convert → "Search for Alternate Release".
Notes:
- All options are disabled by default
- Hardware acceleration (NVENC/VAAPI) dramatically speeds up conversions
- Original files can optionally be preserved
- MKV remux is the fastest option (just repackages, no quality loss)
- "Prefer Alternate Release" requires Sonarr/Radarr to be configured
Automatically invite new users to your Plex server when they sign in to Flexerr:
- Go to Settings → Media Sync tab
- Enable "Auto-Invite New Users"
- Select which libraries to share with new users
- When a new user authenticates via Plex OAuth, they'll receive an email invitation to your Plex server
This allows you to share a Flexerr link with friends - they sign in with Plex, automatically get invited to your server, and can immediately start adding content to their watchlist.
Flexerr can sync watchlists for Plex friends who haven't logged in to Flexerr, using the server owner's token to query Plex's API on their behalf.
- Go to Settings → Media Sync
- Ensure "Auto Import Plex Users" is enabled
- Enable "Friend Watchlist Sync"
- Set the sync interval (default: 5 minutes)
- Flexerr discovers friends via Plex's API and matches them to existing users
- For friends without a personal token, Flexerr fetches their watchlist using the admin's token
- Watchlist items are processed identically to direct sync — TMDB lookup, Sonarr/Radarr requests, availability checks
- If a friend later logs in via OAuth, they seamlessly transition from friend sync to direct sync with no duplicates
- Friends must have their Plex watchlist visibility set to "Friends" or "Everyone" (Plex account settings → Privacy)
- If a friend's watchlist is private, they'll appear with a "Private" badge on the Users page
The Users page shows a Watchlist column indicating each user's sync method:
- Direct — User logged in with their own Plex token
- Friend — Synced via admin token (friend hasn't logged in)
- Private — Friend's watchlist privacy blocks access
- None — No watchlist sync active
The page also includes a search bar, role and watchlist quick filters, and pagination for larger user lists.
Flexerr continuously syncs with Plex watchlists and Jellyfin favorites, detecting both additions and removals.
- Addition Detection - New watchlist items are automatically coordinated with Sonarr/Radarr
- Removal Tracking - Items removed from watchlist are marked as removed in Flexerr
- Re-Add Detection - If a user adds back a previously removed item, Flexerr detects this as a restoration
- Automatic Restoration - Re-added items trigger fresh acquisition cycle, removing from exclusion lists and resetting lifecycle
This enables users to recover content that was cleaned up:
- User watches a show, removes from watchlist
- Smart cleanup eventually deletes the files
- Months later, user wants to rewatch
- User simply adds back to Plex watchlist or Jellyfin favorites
- Flexerr automatically:
- Detects the re-add
- Removes from Sonarr/Radarr exclusion lists
- Resets lifecycle status
- Triggers fresh download
No admin intervention required - users can self-service restore their content.
VIPER intelligently manages TV show episodes based on each user's watch progress and velocity.
- Tracks Watch Progress - Monitors where each user is in each show
- Calculates Velocity - Determines how fast users watch (episodes per day)
- Smart Buffer - Keeps enough episodes ahead based on watch speed
- Safe Cleanup - Only deletes when ALL active users have moved past
- Proactive Redownload - Re-downloads episodes before slower users need them
- Respects Protection - Never deletes protected items regardless of velocity
| Setting | Description | Default |
|---|---|---|
| Days Buffer | Days of watching to keep ahead | 10 |
| Max Episodes Ahead | Hard cap on episodes to keep | 20 |
| Unknown Velocity Buffer | Fallback when velocity unknown | 10 |
| Min Velocity Samples | Episodes needed to trust velocity | 3 |
| Proactive Redownload | Auto-redownload deleted episodes | Enabled |
A household of 3 users watching "Breaking Bad" (62 episodes):
| User | Watch Speed | Current Position |
|---|---|---|
| Dad | Finished | Season 5 Complete |
| Mom | 1 ep/day | Season 2, Episode 5 |
| Teen | Paused for 2 weeks | Season 1, Episode 3 |
What VIPER keeps:
- S1E01-S1E02 → Cleaned (everyone's past them)
- S1E03 + buffer ahead → Protected (Teen's bubble)
- S2E05 + buffer ahead → Protected (Mom's bubble)
- S2E06 through S5 → Cleaned (Dad's done, outside Mom's forward buffer)
The gap cleanup: Episodes between Teen's bubble and Mom's bubble, and between Mom's bubble and the end, get cleaned. Only the bubbles around active viewers are preserved.
What happens next:
- Teen resumes watching, finishes S1 → Teen's bubble moves forward
- Gap between Teen and Mom shrinks, more episodes become cleanable behind Teen
- Mom continues steady pace, her bubble moves forward with her
- Storage is reclaimed gradually as bubbles move and gaps open up
The key insight: Each user has an invisible bubble around their position. Content is only cleaned when it falls outside ALL users' bubbles. Large gaps between viewers get cleaned automatically.
Protect specific movies or TV shows from any deletion - a priority override for all cleanup rules. Protection now automatically ensures content is available!
- Navigate to any movie or TV show detail page
- Click the Shield icon to toggle protection ON
- Protected items display a shield badge
- Priority 1 Override - Protected items are NEVER deleted by any rule
- Bypasses VIPER Cleanup - Ignored by velocity-based episode management
- Bypasses Rules Engine - Ignored by all cleanup rules
- Auto-Monitor (NEW!) - Automatically sets to monitored in Sonarr/Radarr
- Auto-Search (TV Shows) - Triggers search for ALL episodes to ensure availability
- Stats Visibility - Protected items shown separately in cleanup stats
- Persistent - Protection remains until manually toggled off
TV Shows:
- Series set to
monitored: truein Sonarr - ALL episodes set to monitored (including previously unmonitored ones)
- Series search triggered to download any missing episodes
- Episodes will never be deleted by VIPER or rules
Movies:
- Movie set to
monitored: truein Radarr - Will never be deleted by rules
Create custom cleanup rules for content that doesn't fit the VIPER model.
| Condition | Description |
|---|---|
| Watched | Has any user watched this? |
| View Count | Total times watched across users |
| Days Since Watched | Days since last watch |
| Days Since Added | Days since added to library |
| On Watchlist | Is any user's watchlist? |
| Rating | TMDB/IMDB rating |
| File Size (GB) | Total file size |
| Genre | Content genre |
| Release Year | Year of release |
| Action | Description |
|---|---|
| Add to Leaving Soon | Queue for deletion with grace period |
| Delete from Plex/Jellyfin | Remove from media server |
| Delete from Sonarr/Radarr | Remove from *arr apps |
| Unmonitor | Stop tracking for upgrades |
| Delete Files | Remove actual media files |
Note: Protected items are always skipped by rules, regardless of conditions.
Watched Movies Cleanup:
- Watched = Yes AND Days Since Watched > 30 AND On Watchlist = No
- Action: Add to Leaving Soon (15 day buffer)
Large File Cleanup:
- File Size > 50GB AND Watched = Yes
- Action: Add to Leaving Soon
Old Unwatched Content:
- Days Since Added > 90 AND Watched = No AND On Watchlist = No
- Action: Add to Leaving Soon
Flexerr uses Plex OAuth - no manual token setup needed. The first user to sign in becomes the admin. Additional users are automatically synced from your Plex server.
Jellyfin uses username/password authentication:
- Enter your Jellyfin server URL during setup
- Login with your Jellyfin credentials
- The first user to sign in becomes the admin
Important Notes:
- Jellyfin uses Favorites as a watchlist equivalent since Jellyfin lacks native watchlist support
- Smart cleanup currently requires Plex - Jellyfin velocity tracking is in development
- Basic features work: browsing, requesting, watch history, collections
- Advanced features (VIPER, velocity tracking) are Plex-only for now
- Go to Settings → Connected Services
- Click "Add Service"
- Select Sonarr or Radarr
- Enter:
- URL: Your Sonarr/Radarr URL (e.g.,
http://192.168.1.100:8989) - API Key: Found in Sonarr/Radarr Settings → General
- URL: Your Sonarr/Radarr URL (e.g.,
- Click "Test Connection" then "Save"
- Create a free account at themoviedb.org
- Go to Settings → API
- Request an API key
- Enter the key during Flexerr setup (or in Settings → General)
The admin dashboard provides:
- Statistics - Requests, deletions, storage saved
- User Management - View users, watchlists, admin status
- Rules Management - Create, edit, and run cleanup rules
- Queue - View and manage pending deletions
- VIPER Dashboard - Real-time view of tracked users, watch velocities, protected episodes, and per-show episode analysis with visual protection bubbles
- Logs - Activity and error logging
- Connected Services - Manage media server and download managers
- Debug Logging - Configure log verbosity for troubleshooting (Settings → Debug)
- Ensure Plex OAuth is enabled in your Plex server settings
- Check that your Plex server is accessible from Flexerr
- Verify no firewall blocking the connection
- Verify the server URL is correct and accessible
- Check username/password are correct
- Ensure Jellyfin server is running and accepting connections
- Verify Sonarr/Radarr connection in Connected Services
- Check that the content has a TVDB/TMDB ID
- Ensure Sonarr/Radarr have root folders and quality profiles configured
- Smart cleanup requires Plex - Jellyfin velocity tracking coming soon
- Check Settings → VIPER is enabled
- Verify the cleanup schedule is set
- Check Media Server Sync is enabled and running
- Check logs for errors - admin dashboard shows detailed error reporting
- Increase "Days Buffer" in VIPER
- Use the Protect toggle on the media detail page - this is the only way to permanently protect content from all cleanup rules and VIPER
- Check "Leaving Soon" collection for upcoming deletions
- Go to Settings → Debug tab (admin only)
- Set debug level:
- BASIC - Errors, warnings, key events
- VERBOSE - API calls, sync operations (recommended for most issues)
- TRACE - Everything (generates lots of output)
- Reproduce the issue
- View logs:
docker logs flexerr --tail 500 - Set back to OFF when done to reduce log noise
POST /api/auth/plex/start - Start Plex OAuth flow
GET /api/auth/plex/callback/:id - Complete OAuth
POST /api/jellyfin/auth - Jellyfin authentication
POST /api/auth/refresh - Refresh JWT token
GET /api/auth/me - Get current user
GET /api/discover/search?q= - Search TMDB
GET /api/discover/trending - Trending content
GET /api/discover/movie/:id - Movie details
GET /api/discover/tv/:id - TV show details
GET /api/watchlist - User's watchlist
POST /api/watchlist - Add to watchlist
DELETE /api/watchlist/:tmdbId/:mediaType - Remove from watchlist
GET /api/protection/:mediaType/:tmdbId - Get protection status
POST /api/protection/:mediaType/:tmdbId - Toggle protection
GET /api/rules - List rules
POST /api/rules - Create rule
GET /api/settings - Get settings
PUT /api/settings - Update settings
GET /api/settings/debug - Get debug level and options
PUT /api/settings/debug - Set debug level (0-3)
GET /api/services - List services
POST /api/services - Add service
- Frontend: React 18, Tailwind CSS
- Backend: Node.js, Express, SQLite (better-sqlite3)
- Authentication: Plex OAuth, Jellyfin Auth, JWT
- APIs: TMDB, Sonarr, Radarr, Plex, Jellyfin
flexerr/
├── backend/
│ ├── server.js # Express server & routes
│ ├── database.js # SQLite database
│ └── services/
│ ├── auth.js # Plex OAuth + Jellyfin Auth + JWT
│ ├── plex.js # Plex API client
│ ├── sonarr.js # Sonarr integration
│ ├── radarr.js # Radarr integration
│ ├── tmdb.js # TMDB API
│ ├── rules-engine.js # Cleanup rules
│ ├── smart-episodes.js # VIPER engine
│ ├── scheduler.js # Job scheduling
│ ├── plex-sync.js # Plex library & watch sync
│ ├── collection-sync.js # Collection management
│ ├── notifications.js # Webhook notifications
│ ├── auto-convert.js # Media format conversion
│ └── media-server/ # Multi-server abstraction
│ ├── media-server.js
│ ├── plex-media-server.js
│ ├── jellyfin-media-server.js
│ └── media-server-factory.js
├── frontend/src/
│ ├── App.jsx # Routes & auth context
│ └── pages/ # Page components
├── Dockerfile
├── docker-compose.yml
└── README.md
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
MIT License - see LICENSE file.
- Issues: GitHub Issues
- Discussions: GitHub Discussions








