# Subgen Docker Setup for Whisper Subtitle Generation

> Subgen is a Python service that generates subtitles with Whisper-compatible models and connects to media automation systems such as Plex, Jellyfin, Emby, Tautulli, and Bazarr. Its Docker images support CPU, NVIDIA CUDA, and experimental AMD ROCm deployment, but integration depends on correct paths, tokens, and media event delivery.

**McCloudS/subgen** — Autogenerate subtitles using OpenAI Whisper Model via Jellyfin, Plex, Emby, Tautulli, or Bazarr

- Repository: https://github.com/McCloudS/subgen
- Stars: 1,504 · Forks: 122
- Language: Python
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/mcclouds-subgen

## Subgen's role in a Plex, Jellyfin, or Bazarr workflow

Subgen addresses a specific automation problem: generating timed subtitle files without requiring someone to open every video and send its audio through a hosted transcription service. It is intended for self-hosted library operators who already maintain one or more supported systems. Plex, Jellyfin, and Emby can initiate subtitle work through their event and webhook mechanisms. Tautulli can also trigger processing in supported workflows, while Bazarr uses Subgen as an ASR backend. Subgen is not a media player, library manager, or complete subtitle catalogue. It is the transcription service that sits between those systems and a local Whisper-compatible model.

The distinction matters because Subgen depends on the initiating application describing the correct media item and filesystem path. A token grants access to the server API, but it does not solve path translation. The `docker-compose.yml` includes both `USE_PATH_MAPPING=False` and `PATH_MAPPING_FROM=/tv` with `PATH_MAPPING_TO=/Volumes/TV`. Those values illustrate the central deployment constraint: the filename known by Plex or another host service must correspond to a file that Subgen can actually open after container mounts and optional path mapping are applied.

The project also supports more than conventional video subtitles. Its `LRC_FOR_AUDIO_FILES` setting can generate LRC files for formats including `.mp3`, `.flac`, `.wav`, `.alac`, `.ape`, `.ogg`, `.wma`, `.m4a`, `.m4b`, `.aac`, and `.aiff`. Model output and task selection can also be adjusted through environment variables. This makes Subgen applicable to audio libraries, but the media event and output naming rules remain part of the integration rather than automatic discovery across an entire server.

## FastAPI requests, ASR processing, and subtitle output

Subgen is implemented primarily in Python. Its dependency list includes `fastapi`, `uvicorn`, `python-multipart`, `requests`, `ffmpeg-python`, `faster-whisper`, and `stable-ts-whisperless`. The repository also contains `subgen.py`, `language_code.py`, `launcher.py`, and an `entrypoint.sh`. This layout indicates a containerized web service that receives transcription work through HTTP and delegates audio processing and model inference to the Python packages.

The update history documents the `/asr` endpoint and states that `/asr` can optionally encode uploaded files. That endpoint is particularly relevant to Bazarr integration. By contrast, Bazarr intentionally does not follow `CONCURRENT_TRANSCRIPTIONS` because its requests are time sensitive, so Subgen maintains separate queue behavior for that route. Other integrations can use `CONCURRENT_TRANSCRIPTIONS`; the Compose configuration sets it to `2`. This is a meaningful operational choice. Raising the limit may increase memory use, particularly because Whisper models can consume substantial RAM or VRAM.

Media-server workflows can process an item when playback or a configured event occurs. The compose example sets `PROCADDEDMEDIA=True` and `PROCMEDIAONPLAY=False`, showing that Subgen can act on added media and, when enabled, playback. It also contains Plex connection values such as `PLEXTOKEN`, `PLEXSERVER`, and Jellyfin equivalents. After a task completes, `WEBHOOK_URL_COMPLETED` sends a POST request with a JSON structure, allowing another local service to react after generation.

Subtitle selection is policy-driven rather than simply a request to transcribe everything. Variables include `SKIPIFINTERNALSUBLANG`, `ONLY_SKIP_IF_SUBGEN_SUBTITLE`, `SKIP_IF_LANGUAGE_IS_NOT_SET_BUT_SUBTITLES_EXIST`, `SKIP_UNKNOWN_LANGUAGE`, `PREFERRED_AUDIO_LANGUAGES`, and `SKIP_IF_AUDIO_TRACK_IS`. The June 2026 update also added `IGNORE_FORCED_SUBTITLES`, defaulting to `True`, because forced tracks cover only a small amount of dialogue and should not be mistaken for full subtitle coverage.

## Docker installation and the first media-server request

The README excerpt does not include a complete installation command, so this tutorial does not invent one. It directs users toward the repository's Docker setup, and the repository includes `Dockerfile`, `Dockerfile.AMD`, `Dockerfile.cpu`, `docker-compose.yml`, `subgen.env`, and launcher files. A new user should first copy the Compose configuration into the deployment directory, replace every example token and server URL, and confirm the host directory variables used by its volumes.

The repository's Compose file shows the published service port as `9000`, maps `${TV}` to `/tv` and `${MOVIES}` to `/movies`, and stores models under `/subgen/models`. The Compose variables `${TV}`, `${MOVIES}`, and `${APPDATA}` are deployment-specific and cannot be copied without editing. The example also selects `WHISPER_MODEL=medium` and `TRANSCRIBE_DEVICE=cpu`. `PROCADDEDMEDIA=True` means the first practical test can follow adding a media item rather than pressing play.

For an NVIDIA deployment, the Compose file includes commented GPU reservation instructions and the default Dockerfile uses an NVIDIA CUDA base image with `CUDA 12.8.1`. CPU deployment is represented separately by `Dockerfile.cpu`. The AMD image is `mccloud/subgen:amd`, and its repository comments require changing the image and setting `TRANSCRIBE_DEVICE=cuda`. However, the March 2026 update calls AMD support potentially added and explicitly says it was not testable by the maintainer. Do not treat AMD compatibility as a verified adoption criterion.

After editing the actual Compose file, run the Compose command appropriate to the installed Compose implementation. The README excerpt does not state that command, so no unverifiable invocation is presented here. The expected result is a `subgen` service exposing container port `9000` with readable media volumes and a persistent model directory. For the first real use, add one short media file through the connected Plex, Jellyfin, or Emby library, leave `PROCMEDIAONPLAY=False`, and inspect Subgen logs. The documentation does not define exact log strings, so verify whether the server accepts the event, finds the audio, and writes a subtitle file.

Do not place real tokens in committed Compose files. The example values such as `plextoken` and `token here` are placeholders, not working credentials.

## Model selection, timing offsets, and memory controls

Subgen supports Whisper model choices, and the update history specifically mentions `large-v3-turbo` and `distil-large-v3.5`. The supplied example chooses `medium`. Model size is not just a quality choice in this service. It affects model download requirements, memory consumption, transcription time, and whether a particular CPU or GPU has enough capacity. `MODEL_PATH=./models` in the Compose example keeps models in a volume-backed directory, while the Dockerfile redirects `HF_HOME` and `XDG_CACHE_HOME` into `/cache`.

Memory cleanup receives explicit attention. `CLEAR_VRAM_ON_COMPLETE=True` appears in the Compose example, while `MODEL_CLEANUP_DELAY` was added to wait before purging a model from RAM or VRAM. That delay is particularly relevant when Bazarr is the caller or `CONCURRENT_TRANSCRIPTIONS` is `1`. Purging too early can force a model reload for the next request; retaining it consumes memory between jobs. The setting exposes that trade-off instead of imposing one fixed policy.

Timing receives a separate correction path. The April 2026 update says Whisper can ignore silence padding, causing subtitles to be early in files with audio stream offsets, including Amazon WEB-DL sources. Subgen detects the condition with `ffprobe` and compensates when the source video is accessible. This is conditional. If the service can transcribe an extracted audio file but cannot access the original video, automatic offset compensation may not have the source information it requires.

Transcription options can be passed through `SUBGEN_KWARGS`, overriding `model.transcribe` with most options supported by Whisper, faster-whisper, or stable-ts. Prompts are available through `USE_MODEL_PROMPT` and `CUSTOM_MODEL_PROMPT`. These controls are useful for punctuation and audio edge cases, but they also move responsibility to the operator. The repository does not document a validation layer that proves every override is compatible with every installed model and backend.

## Operational limits of Subgen's service integrations

The clearest wrong-tool case is a library that cannot expose local paths or original media files to the Subgen container. A successful webhook request can still fail later if Subgen cannot open the source. This is why `USE_PATH_MAPPING`, `PATH_MAPPING_FROM`, and `PATH_MAPPING_TO` exist. The mapping must match both syntax and mount layout rather than merely similar directory names. The April 2025 update specifically clarified path instructions for Emby, Plex, and Jellyfin, which indicates that path interpretation is a recurring integration issue.

Bazarr users face different queue semantics. Its ASR requests are expected to return within a time-sensitive workflow, so Bazarr intentionally bypasses the normal `CONCURRENT_TRANSCRIPTIONS` limit. Subgen also exposes `ASR_TIMEOUT` for limiting endpoint transcriptions. A timeout can prevent an ASR request from waiting indefinitely, but the documentation does not state how a timed-out transcription is retried or whether partial output is retained.

Subgen removed its `/subsync` endpoint in March 2024 and removed the web user interface in September 2024. Operators upgrading an older deployment must therefore remove any workflow that calls `/subsync` or expects configuration at a browser address. Configuration now belongs in environment variables, files such as `subgen.env`, or the launcher and Compose setup.

The AMD path has another explicit boundary. The repository describes `mccloud/subgen:amd` as about 10 GB at the time of the update, and says ROCm support may not work, particularly on unsupported AMD APUs or older cards. `HSA_OVERRIDE_GFX_VERSION` may sometimes make a card appear supported, but the maintainer directs users to conduct their own hardware research. That makes Subgen's AMD image experimental according to its own documentation.

Finally, standalone folder monitoring exists through `MONITOR` and `TRANSCRIBE_FOLDERS`, but it is a separate mode from media-server automation. It should not be assumed to reconcile subtitles, rename files, or update metadata across Plex, Jellyfin, and Emby. The documentation describes starting transcription when monitored folders change, not a general library synchronization system.

## Subgen maintenance, release model, and MIT license

The repository is not archived, and its last push was on 2026-08-07. The update history records changes through June 2026, including forced-subtitle coverage handling, audio-offset correction, webhook completion notifications, and AMD image work. However, the repository has no GitHub releases. That means there is no release history in which to inspect versioned artifacts or migration notes, so the `main` branch image and recent repository updates are the relevant upgrade signals.

Upgrade planning should account for more than Python dependencies. A model change can alter memory use, latency, and subtitle formatting. A container change can alter CUDA or ROCm requirements. Environment variables were renamed in August 2025 while retaining backward compatibility, but future compatibility cannot be assumed from that single event. The November 2024 notice about minor hiccups following the major overhaul is relevant when comparing older setups with current code.

Subgen is distributed under the MIT License. That permits use, modification, distribution, and sublicensing subject to the license's conditions, including preservation of its copyright and permission notice. This is a licensing summary, not legal advice. The repository includes an `LICENSE` file, which should be reviewed for the exact obligations attached to a particular distribution.

There is no GitHub release cadence or formal upgrade policy documented in the available repository text. An operator should therefore treat container image changes, model availability, server webhook changes, and environment-variable compatibility as separate checks. The last push date confirms recent repository activity, but it does not by itself guarantee compatibility with every media server or accelerator.

## Conclusion

Subgen suits self-hosted media libraries that can share paths with the service and want local subtitle generation through a media-server event or the Bazarr ASR endpoint. It is a poor fit for users who need a verified AMD ROCm setup, a browser-based configuration interface, or a plug-and-play service with no container and model planning. Before adoption, verify the selected Docker image against the host hardware, confirm that Subgen sees the same media paths as the initiating service, and test a short transcription with the intended model, language, and skip settings.

## FAQ

### Which media servers and subtitle tools can connect to Subgen?

The project description lists Plex, Jellyfin, Emby, Tautulli, and Bazarr. Bazarr uses Subgen through its ASR integration, while the other listed systems can initiate media processing through supported events or webhook workflows.

### Does Subgen support NVIDIA, CPU, and AMD hardware?

The repository contains NVIDIA CUDA and CPU Dockerfiles, and it also publishes an `mccloud/subgen:amd` image for ROCm. The maintainer describes AMD support as potentially added and untested, so CUDA and CPU are the documented deployment paths with clearer support.

### Does Subgen have a web interface or configuration wizard?

The web user interface was removed in September 2024. Configuration is handled through environment variables and repository configuration files, although a launcher wizard remains documented for common standalone Bazarr settings.

### What happens after Subgen finishes a transcription?

Subgen can send a POST request containing a JSON structure when `WEBHOOK_URL_COMPLETED` is configured. The documented use is to notify another service after task completion, not to provide a complete callback workflow by itself.

## Sources

- [Issues](https://github.com/McCloudS/subgen/issues)
- [License: MIT](https://github.com/McCloudS/subgen/blob/main/LICENSE)
- [McCloudS/subgen on GitHub](https://github.com/McCloudS/subgen)
- [README](https://github.com/McCloudS/subgen/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mcclouds-subgen
