Containerized Media Management: Deploying Seerr for Automated Discovery and API-Driven Workflows
If you’re running a media server, you know the headache of friends texting you at 2 AM asking, "Hey, can you add the latest season of that one show?" Seerr solves that by providing a beautiful, automated interface for those requests.
From an architecture perspective, Seerr is brilliant because it acts as a centralized orchestrator. Instead of giving everyone access to your backend (Plex/Jellyfin) or your "arr" apps (Sonarr/Radarr), you give them a safe, read-only frontend.
Decoupling
Users interact with Seerr; Seerr talks to the APIs of your other services.
Authentication
It integrates with Plex/Jellyfin, so users don't need a new set of credentials.
Automation
Once a request is approved, it automatically sends the instructions to your download clients. No manual clicking required.
As engineers, we love containers. It keeps the environment clean and makes updates a breeze. Here is a standard docker-compose.yml snippet to get you started.
services:
seerr:
image: fallenbagel/jellyseerr:latest # Using Jellyseerr for Jellyfin/Plex compatibility
container_name: jellyseerr
environment:
- LOG_LEVEL=info
- TZ=Asia/Tokyo
volumes:
- /path/to/appdata/config:/app/config
ports:
- 5055:5055
restart: unless-stopped
Steps to deploy
Save the code above to a file.
Run docker-compose up -d.
Open your browser and head to http://localhost:5055.
If you want to build custom scripts (e.g., a Telegram bot that checks request status), Seerr has a robust API. Here’s a quick Python example of how you might fetch all pending requests
import requests
# Your Seerr URL and API Key (found in Settings > General)
BASE_URL = "http://your-server-ip:5055/api/v1"
API_KEY = "your_super_secret_api_key"
headers = {
"X-Api-Key": API_KEY,
"Content-Type": "application/json"
}
def get_pending_requests():
response = requests.get(f"{BASE_URL}/request?take=10&skip=0&filter=pending", headers=headers)
if response.status_code == 200:
requests_data = response.json().get('results', [])
for req in requests_data:
print(f"User requested: {req['media']['externalServiceId']} - Status: {req['status']}")
else:
print(f"Error: {response.status_code}")
get_pending_requests()
Notifications
Use the "Notifications" feature to link it to Discord or Slack. You'll get a ping the second a friend requests a movie.
Auto-Approve
You can set rules so that trusted users (like yourself) get their requests approved and sent to the download queue instantly, while others require your manual "OK."
Discovery
It’s not just for requests! It has a "Trending" and "Recommended" section that helps you find what to watch next based on your current library.
It's essentially the "Glue" that makes a DIY media server feel like a professional Netflix-style experience.