All apps · 0 apps
MediaOps
Docker app from MediaOps' Repository
Overview
Readme
View on GitHubUnraid Deployment
MediaOps runs on Unraid from prebuilt GHCR images and stores application-owned runtime data in appdata.
Images
Stable/default:
ghcr.io/miakkia/mediaops:latest
Development:
ghcr.io/miakkia/mediaops:dev
Recommended basics:
- Network Type: Bridge
- Privileged: Off
- Docker socket: not mounted
- Movies/Series/Downloads shares: not mounted for current provider API workflows
- MediaOps host ports: none required for current core features
- Persistent data:
/mnt/user/appdata/mediaops->/data
Provider selection
The current Unraid template supports:
MEDIA_PROVIDER=emby | jellyfin
REQUEST_PROVIDER=ombi | seerr
Only configure credentials for the providers you select.
Existing Emby + Ombi installations
Existing installations remain supported:
MEDIA_PROVIDER=emby
EMBY_URL=http://YOUR-EMBY-HOST:8096
EMBY_API_KEY=REPLACE_ME
REQUEST_PROVIDER=ombi
OMBI_URL=http://YOUR-OMBI-HOST:3579
OMBI_API_KEY=REPLACE_ME
OMBI_AUTO_APPROVE is no longer used by current MediaOps. Ombi's own user/role policy controls approval. An older installation that had OMBI_AUTO_APPROVE=false can safely remove that variable when updating.
Jellyfin + Seerr
MEDIA_PROVIDER=jellyfin
JELLYFIN_URL=http://YOUR-JELLYFIN-HOST:8096
JELLYFIN_API_KEY=REPLACE_ME
REQUEST_PROVIDER=seerr
SEERR_URL=http://YOUR-SEERR-HOST:5055
SEERR_API_KEY=REPLACE_ME
When Jellyfin/Seerr are selected, Emby/Ombi credentials are not required.
Discord setup
Each self-hosted MediaOps deployment uses its operator-owned Discord application/bot. Configure:
DISCORD_TOKEN
DISCORD_CLIENT_ID
DISCORD_GUILD_ID
Use least-privilege Discord permissions rather than Administrator.
Register guild commands after startup:
docker exec MediaOps npm run deploy-commands
Persistent data
Main MediaOps state:
| Container path | Recommended Unraid host path |
|---|---|
/data |
/mnt/user/appdata/mediaops |
Set MEDIAOPS_DATA_DIR=/data.
MediaOps Discord Router
The companion router retains its historical image name for compatibility:
ghcr.io/miakkia/mediaops-ombi-discord-router:latest
It now accepts both provider webhook routes:
POST /ombi
POST /seerr
The router is a messenger/routing addon. It can create a Discord Forum post, persist the provider/media/request-to-thread association, append lifecycle updates to the same thread, and update Forum lifecycle tags.
Recommended router appdata:
/mnt/user/appdata/mediaops-discord-router/data -> /data
Keep the mapped directory writable by the configured non-root router UID/GID. Do not use 777, privileged mode, or root execution as a workaround.
For dynamic Forum tag changes, inject DISCORD_BOT_TOKEN at runtime and grant only the Discord permissions required for the target Forum/thread.
Prefer a private user-defined Docker network between Ombi/Seerr and the router. No public router port is required when the request provider can address the router by container name.
Updating from latest
- Force Update/pull
ghcr.io/miakkia/mediaops:latest. - Preserve
/dataand your environment variables. - Keep your selected provider values.
- Run
/healthafter restart. - Test
/movie,/tv,/latest, and/request. - If using the Router, verify one provider webhook lifecycle and confirm same-thread status/tag changes.
Adding Jellyfin/Seerr support does not require an existing Emby/Ombi operator to migrate providers.
Upgrade acceptance checks
For Emby + Ombi:
/healthreports Emby and Ombi online;/movie,/tv,/lateststill return expected library results;/requestcreates an Ombi request under Ombi's configured approval policy;- Watch Party behavior remains operational when configured.
For Jellyfin + Seerr:
/healthreports Jellyfin and Seerr online;- movie/series search and artwork work;
- request search/create works;
- Router
/seerrevents reach the Discord Forum when enabled.
Security posture
- non-root runtime;
- no privileged mode;
- no Docker socket;
- no direct media-library mounts for current API workflows;
- no unnecessary host ports;
- secrets supplied only at runtime;
- private Docker/LAN provider communication preferred;
- appdata access limited to application-owned state.
See SECURITY_MODEL.md and the repository SECURITY.md.
Requirements
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/miakkia/mediaops:latestRuntime arguments
- Network
bridge- Shell
bash- Privileged
- false
Template configuration
Persistent MediaOps runtime data and scheduled Watch Party state.
- Target
- /data
- Default
- /mnt/user/appdata/mediaops
Public-facing bot name used by MediaOps panels and messages. This does not rename your Discord application itself.
- Target
- MEDIAOPS_BOT_NAME
- Default
- MediaOps Bot
Friendly media-server/community name used in public MediaOps panels.
- Target
- MEDIAOPS_SERVER_NAME
- Default
- My Media Server
Set true for public/demo deployments. MediaOps keeps Watch Party controls visible but disables join links so configured Watch Party URLs are never emitted into Discord.
- Target
- MEDIAOPS_DEMO_MODE
- Default
- false
Media provider backend. Supported values: emby or jellyfin.
- Target
- MEDIA_PROVIDER
- Default
- emby
Secret token for the Discord bot/application you created for this MediaOps deployment.
- Target
- DISCORD_TOKEN
Application/client ID for your Discord application.
- Target
- DISCORD_CLIENT_ID
Discord server/guild ID for this self-hosted deployment and guild-scoped command registration.
- Target
- DISCORD_GUILD_ID
Emby base URL reachable from this container. Required only when MEDIA_PROVIDER=emby.
- Target
- EMBY_URL
Emby API key used by MediaOps. Required only when MEDIA_PROVIDER=emby.
- Target
- EMBY_API_KEY
Jellyfin base URL reachable from this container. Required only when MEDIA_PROVIDER=jellyfin.
- Target
- JELLYFIN_URL
Jellyfin API key used by MediaOps. Required only when MEDIA_PROVIDER=jellyfin.
- Target
- JELLYFIN_API_KEY
Optional request backend. Supported values: none, ombi or seerr.
- Target
- REQUEST_PROVIDER
- Default
- none
Ombi base URL reachable from MediaOps. Required only when REQUEST_PROVIDER=ombi.
- Target
- OMBI_URL
Ombi API key used to search and create requests. Required only when REQUEST_PROVIDER=ombi.
- Target
- OMBI_API_KEY
Seerr base URL reachable from MediaOps. Required only when REQUEST_PROVIDER=seerr.
- Target
- SEERR_URL
Seerr API key used to search and create requests. Required only when REQUEST_PROVIDER=seerr.
- Target
- SEERR_API_KEY
Optional Discord Forum channel used for request lifecycle synchronization.
- Target
- MEDIA_REQUESTS_FORUM_ID
Exact Discord webhook ID allowed to drive Forum status changes. This is an ID, not the secret webhook URL/token.
- Target
- MEDIA_REQUESTS_WEBHOOK_ID
Discord Forum tag ID for newly submitted requests.
- Target
- MEDIA_TAG_REQUESTED
Discord Forum tag ID for approved/in-process requests.
- Target
- MEDIA_TAG_PROCESSING
Discord Forum terminal tag ID for available media.
- Target
- MEDIA_TAG_AVAILABLE
Discord Forum terminal tag ID for failed processing/acquisition.
- Target
- MEDIA_TAG_FAILED
Discord Forum terminal tag ID for denied/rejected requests.
- Target
- MEDIA_TAG_DENIED
Discord Forum tag ID identifying movie requests.
- Target
- MEDIA_TAG_MOVIE
Discord Forum tag ID identifying TV-series requests.
- Target
- MEDIA_TAG_SERIES
Public URL of the Watch Party service. Demo Mode prevents this URL from being emitted into Discord.
- Target
- WATCHPARTY_URL
Optional LAN/internal Watch Party URL used by MediaOps API calls.
- Target
- WATCHPARTY_INTERNAL_URL
Dedicated non-admin Emby account used to create and host Watch Parties.
- Target
- WATCHPARTY_EMBY_USER
Password for the dedicated Watch Party Emby account.
- Target
- WATCHPARTY_EMBY_PASSWORD
Days to keep completed/cancelled Watch Party history.
- Target
- WATCHPARTY_RETENTION_DAYS
- Default
- 30
Default language for automated messages. Supported: en or fr.
- Target
- MEDIAOPS_LOCALE
- Default
- en
IANA timezone used for Watch Party scheduling input without an explicit offset.
- Target
- MEDIAOPS_TIMEZONE
- Default
- America/Toronto
Container path for persistent runtime data.
- Target
- MEDIAOPS_DATA_DIR
- Default
- /data