Subtitle Processing v2.4

Bazarr+ v2.4.0 (Prism) adds three subtitle processing features: combined bilingual or trilingual subtitles built from files already on disk, source scoring and direct translation for embedded tracks, and multi-engine synchronization with side-by-side output comparison. This guide covers all three.

Combined subtitles

Combined output takes subtitles you already have on disk and composes them into a single bilingual or trilingual subtitle, written as SRT or ASS. You pick two or three languages, and Bazarr+ aligns their cues into one file.

Jellyfin: combined Hungarian and English subtitle
A film playing in Jellyfin with a combined bilingual subtitle: Hungarian on the top line and English on the bottom line, composed by Bazarr+ as a single ASS file
This is pure composition, not translation. Combined output only stacks subtitles that already exist on disk. It never triggers a translation, never calls a provider, and never extracts an embedded track. If not all of the chosen source languages are present, Bazarr+ skips the combine silently and leaves your existing subtitles untouched.

When more than one variant of a language is on disk, Bazarr+ resolves the source by priority: plain first, then HI, then forced. ASS output supports cue positioning so you can place each language at the bottom, top, or middle of the frame. SRT output stacks the lines in a single block.

Per language profile

Set up combined output once per language profile so it runs automatically as part of normal processing.

  1. Open Settings > Languages and edit a language profile.
  2. In the CombineRuleEditor, toggle combined output on.
  3. Pick 2 or 3 languages to combine.
  4. Choose the output format: SRT or ASS.
  5. Save the profile.

After this, whenever Bazarr+ finishes processing subtitles for an item on that profile and all chosen source languages are present on disk, it builds the combined file automatically. If a source language is missing, the combine is skipped and no error is raised.

On demand

You can also build a combined output now, without waiting for the next processing pass.

  • On a movie, episode, or series detail page, use the Combine Subtitles toolbox button.
  • On the Movies or Series list pages, use the mass-combine action to build combined output across the selected items.

The same source rules apply: only on-disk subtitles are used, source priority is plain > HI > forced, and items that do not have all source languages are skipped.

Managing combined output

Combined subtitles are indexed alongside other generated outputs and marked with a CombinedSubtitleBadge in the subtitle table. Each combined row has an overflow menu:

  • Rebuild: recompose the combined file from the current on-disk sources.
  • View: open the combined subtitle.
  • Edit: open the combined subtitle in the subtitle editor. An SRT combined opens as one stacked cue per timestamp; an ASS combined opens as its separate positioned cues (one per language) without false overlap warnings.
  • Delete: remove the combined file.

A combined output is kept as a single file: rebuilding in a different format removes the stale sibling left in the previous format.

API endpoints

The on-demand and mass-combine actions call these endpoints. The series endpoint is the batch form that combines across the show's episodes.

HTTP
POST /api/movies/<id>/subtitles/combine
POST /api/episodes/<id>/subtitles/combine
POST /api/series/<id>/subtitles/combine

Embedded subtitle scoring and translate-from-embedded

Embedded subtitles are tracks stored inside the media container rather than as separate files. Bazarr+ now treats those in-container tracks as a real subtitle source.

Source scoring in history

An embedded track is recorded in history as a source-quality result at a 100% score. In the subtitle table, the embedded track shows that 100% score so you can see at a glance that the item already carries an in-container subtitle for that language.

Translate from an embedded track

You can translate directly from an embedded text track without first downloading a separate subtitle. The embedded row exposes a translate-only action in its menu.

  1. In the subtitle table, find the embedded track you want to translate from.
  2. Open its action menu and choose the translate-only action.
  3. Bazarr+ extracts the text stream with ffmpeg to {config_dir}/extracted_subs/.
  4. It then runs your configured translator on the extracted text and writes the translated subtitle.
Text-based tracks only. Translate-from-embedded works on text subtitle codecs. Bitmap codecs such as PGS and VobSub cannot be translated this way and are rejected with a clear error, because there is no text to feed the translator. ffmpeg must be available for the extraction step.

Translation uses whatever engine you have set up in Bazarr+. See AI Subtitle Translation for configuring a translator. Sync outputs and combined outputs are intentionally excluded from the list of sources you can translate from, so you translate from real source tracks rather than from generated files.

Multi-engine synchronization

Synchronization shifts subtitle timing to match the audio. Bazarr+ now lets you choose which sync engine to run and compare the result before you keep it.

You can start a sync in two places:

  • From the subtitle editor, on a single subtitle.
  • From the mass-sync form, across multiple items at once.

In either place you pick the engine to run. When an editor sync finishes with results from more than one engine, a Choose Sync Result dialog lists the engines that produced output and you load the one you want into the editor. A single result is loaded straight away without asking. Either way the cues sit in the editor unsaved, so you look at them before writing anything to disk.

Editor sync now fails explicitly. If a sync run produces no output, the editor reports the failure instead of silently leaving the subtitle unchanged. You see that the engine did not produce a result rather than assuming it succeeded.

The three engines

Nothing to install. If you run the Docker image, all three engines and ffmpeg are already inside it. There is no separate download, no manual step, and no setting to point at a binary.

  • ffsubsync aligns the subtitle against a reference taken from the video, either an audio track or an embedded subtitle stream. Naming a reference yourself in a manual sync settles it; otherwise Force audio and the original-language settings do.
  • autosubsync aligns against the audio track with a different speech model, so it often succeeds where ffsubsync does not, and the reverse. It has no reference setting of its own: it takes the video, unless a sync you start by hand names another file in Reference, which it then uses instead.
  • ALASS aligns against the reference itself and is built for timing that drifts in blocks: adverts cut out, a different edit, or a subtitle that is right at the start and progressively wrong later. This is usually the one that rescues a file the other two cannot.

All three correct a subtitle that is uniformly early or late. A framerate mismatch, where the subtitle drifts further out the longer the file runs, needs more than a shift. autosubsync estimates that stretch on every run as a matter of course. ffsubsync can do it too but does not by default: No fix framerate ships enabled, and both mass sync and the subtitle editor keep it that way, so turn it off if you want ffsubsync to attempt it. ALASS does not stretch a subtitle at all.

On a bare-metal install, ffsubsync and autosubsync arrive with the Python requirements. ALASS is an external binary and must be on your PATH as alass or alass-cli. ffsubsync and autosubsync read the audio out of the video, so they need ffmpeg and ffprobe too; ALASS handles the reference itself and only reaches for ffprobe when that reference is a video.

Output modes

  • Overwrite replaces the subtitle with the result of the first engine that succeeds, and stops there. The remaining engines are not run.
  • Keep all engine outputs runs the enabled engines and writes each result beside the original as <name>.<engine>.<ext>, keeping the source file's extension: an ASS subtitle produces .alass.ass, not .alass.srt. Compare them and delete the ones you do not want.

A keep-all run does not necessarily run every engine. It skips one whose output is already there and still current, and one that has failed repeatedly on this subtitle, and it says so in the report. Starting the sync yourself overrides both, so a run you asked for always runs.

These modes apply to a sync that writes to your library. A sync started from the subtitle editor works on a temporary copy and cleans up after itself: the results are handed to the editor for you to save or discard, and nothing is left beside your subtitle. The side-by-side comparison view is a separate thing, reached from the episode or movie screen, and it compares the keep-all files a library sync wrote.
Keep-all outputs are never used as a sync source. The <name>.<engine>.<ext> files are recognised as engine output and skipped when a later sync looks for something to align, so those results cannot be stacked on each other. Overwrite mode is different: it replaces the subtitle in place with no marker in the name, so syncing that file again re-aligns an already-aligned subtitle. That is what you want when the first attempt was wrong, and worth knowing about when it was not.

When an engine produces nothing

Engines failing is routine, not a sign of a broken install. A run where two engines produce nothing and the third works is a normal outcome, and it is the reason more than one engine is offered.

autosubsync is the most visible case: it judges its own result against a confidence threshold and reports failure when it does not trust the alignment, rather than handing back a subtitle it believes is wrong. Sparse dialogue, a heavy musical score, or audio in a language its model handles poorly all lower that confidence even when the file itself is fine.

You read the outcome in the notifications drawer. A sync you start on one subtitle from the episode or movie screen is a job of its own and the outcome becomes its name. The automatic sync after a download is not a separate job: it runs inside the download's job and the outcome appears there as a progress message, under the name of the download. An overwrite run that succeeds says only Sync complete, because it stopped at the first engine that worked and never asked the others. A keep-all run where some engines produced nothing says how many did, and then gives a line for each that did not. A run where nothing worked lists them all. Those lines name six different things:

  • declined — the engine ran and rejected its own result. Nothing is wrong with your installation. autosubsync's line quotes the quality it measured and the threshold it was judged against, because it has a number to give; ffsubsync's says only that it reported the run unsuccessful.
  • rejected — the engine claimed success but Bazarr+ refused the result, because the alignment was further out than your configured maximum offset.
  • failed — the engine errored out. This one is worth reading: it carries whatever the engine said on its way down.
  • not installed — something the engine needs could not be found. Usually the engine itself, and on a bare-metal install that usually means ALASS is not on PATH. It also covers ffmpeg and ffprobe: ffsubsync needs both, and a run without them reports ffsubsync as not installed even when ffsubsync is there. On Docker none of this should appear.
  • skipped after repeated failures — the engine has come away from this subtitle empty-handed several times since it last produced a result, and is being left alone. Errors and rejected results both count towards that; an engine that declines its own result neither counts nor clears the tally, because that verdict can change when the reference or the settings do. Only a run that works clears it. Starting a sync yourself runs the engine anyway.
  • output already existed — keep-all found a current result from this engine and kept it rather than doing the work again.

An engine that declines, is rejected, or fails leaves your original subtitle untouched, and the next engine in the chain runs.

A mass sync does not report at this level of detail. It is one job covering many files, so it reports the file it is on and finishes with a tally of how many were done and how many were skipped. To see why a particular engine produced nothing on a particular subtitle, sync that one subtitle on its own, or read System > Logs.

The maximum offset only binds an engine that reports one. Bazarr+ can refuse an alignment for being too far out only when the engine tells it how far it moved the subtitle. ffsubsync and autosubsync do; ALASS does not, so the setting does not constrain it.

Next steps