Skip to content

Improve audio/subtitle propagation when episodes have different streams - #96

Open
devildant wants to merge 4 commits into
JourneyDocker:mainfrom
devildant:sercured_by_lang
Open

Improve audio/subtitle propagation when episodes have different streams#96
devildant wants to merge 4 commits into
JourneyDocker:mainfrom
devildant:sercured_by_lang

Conversation

@devildant

Copy link
Copy Markdown

Context

This pull request improves the audio and subtitle propagation logic in Plex-Auto-Languages to better handle TV shows where episodes do not all expose the exact same audio and subtitle streams.

Currently, PAL propagates the selected tracks from a reference episode. This works well when all episodes have the same audio and subtitle streams, but it can produce unnatural results when some episodes have fewer audio tracks, fewer subtitles, or missing forced subtitle tracks.

The goal of this change is to preserve Plex’s natural behavior as much as possible, while avoiding inconsistent combinations such as:

Japanese audio + Japanese subtitles
even though the requested French audio does not exist on the target episode

or:

Subtitles disabled
even though a full subtitle track in the expected language exists and would be a better fallback

Identified issues

1. Propagating None from an episode with no subtitle streams

Some episodes may have burned-in subtitles and therefore contain no subtitle stream that Plex can select.

In that case, the reference episode may be played with:

Subtitles: None

But this does not necessarily mean the user wants to disable subtitles for the whole show. It may simply mean that the episode has no subtitle stream available.

Example:

Episode 1:
Audio: Chinese
Subtitles: no available subtitle stream
Subtitles are burned into the video

Episode 2:
Audio: Chinese
Subtitles: French
No burned-in subtitles

Before:

PAL could propagate "None" to episode 2.
Result: episode 2 stayed without subtitles, even though a French subtitle track was available.

After:

If the reference episode has no subtitle streams at all, PAL does not propagate "None" to other episodes.

2. Reference audio missing on the target episode

Another issue happens when the selected audio stream on the reference episode does not exist on another episode.

Example:

Episode 1:
Audio: French, Japanese
Subtitles: French forced, French

Episode 2:
Audio: Japanese
Subtitles: French

If the user selects on episode 1:

Audio: French
Subtitles: French forced

Episode 2 does not have French audio.

Before:

PAL could still apply the subtitle logic.
If the French forced subtitle did not exist on episode 2, PAL could disable subtitles.

Unnatural result:

Episode 2:
Audio: Japanese
Subtitles: None

After:

If the reference audio does not exist on the target episode, PAL does not directly apply the selected reference subtitle.

This avoids applying a subtitle choice that belongs to an audio stream that could not be applied.

3. Natural fallback when the reference audio is missing and the reference has no subtitle selected

However, there is one case where doing nothing is not enough.

Example:

Episode 1:
Audio: French, Japanese
Subtitles: French forced, French

Episode 2:
Audio: Japanese
Subtitles: French

User sequence:

1. The user plays episode 1 in Japanese.
2. The user disables subtitles.
3. Episode 2 naturally switches to Japanese with no subtitles.

Then:

4. The user switches episode 1 back to French.
5. Subtitles remain disabled.

Episode 2 does not have French audio, but it does have French subtitles.

Expected natural behavior:

Episode 2:
Audio: Japanese
Subtitles: French

Reason:

The requested French audio does not exist on episode 2.
The closest natural equivalent is to keep the available audio and use a full French subtitle track.

This change therefore adds a specific fallback:

If the reference audio is missing on the target episode
AND the reference has no subtitle selected
THEN look for a regular subtitle track matching the reference audio language.

Example:

Reference:
Audio: French
Subtitles: None

Target:
Audio: Japanese only
Subtitles: French

Result:
Audio: Japanese
Subtitles: French

This fallback only uses non-forced subtitle tracks.

4. Reference with a single audio stream applied to a multi-audio target

A selected audio stream on an episode that only has one audio stream is not necessarily a strong user preference. It may simply be the only available stream.

Example:

Episode 1:
Audio: French, Japanese
Subtitles: French forced, French

Episode 2:
Audio: Japanese
Subtitles: French

If the user plays episode 2:

Audio: Japanese
Subtitles: French

Before:

PAL could propagate this selection to episode 1.

But on episode 2, Japanese audio was not necessarily an explicit user choice: it was the only available audio stream.

After:

If the reference episode has only one audio stream
AND the target episode has multiple audio streams,
PAL does not change the target episode audio.

However, subtitles may still be applied if the target episode is already using the same audio language as the reference.

Allowed example:

Reference episode:
Audio: French only
Subtitles: French non-forced

Target episode:
Audio: French, English
Currently selected audio: French
Subtitles: French forced, French, English

Result:
PAL may select the French non-forced subtitle on the target episode.
PAL does not modify the audio.

Blocked example:

Reference episode:
Audio: Japanese only
Subtitles: French

Target episode:
Audio: French, Japanese
Currently selected audio: French

Result:
PAL does not modify either audio or subtitles.

5. Forced subtitle handling

The forced subtitle logic must remain the priority when a matching forced subtitle exists on the target episode.

Example:

Reference episode:
Audio: French
Subtitles: French forced

Target episode:
Audio: French
Subtitles: French forced, French

Expected result:

PAL selects French forced.

This logic remains unchanged: if the matching forced subtitle exists, it is selected.

6. Missing forced subtitle: fallback or disable depending on the audio language

The most subtle case is when the forced subtitle selected on the reference episode does not exist on the target episode.

Two situations must be handled differently.

Case A: audio and forced subtitle are in different languages

Example:

Reference episode:
Audio: Japanese
Subtitles: French forced

Target episode:
Audio: Japanese
Subtitles: French

The French forced subtitle does not exist on the target episode, but a full French subtitle exists.

Expected behavior:

PAL uses the regular French subtitle as a fallback.

Reason:

The audio is Japanese.
The French forced subtitle was probably used to translate required parts.
If the forced subtitle does not exist, the full French subtitle is a better fallback than no subtitles.

Result:

Target episode:
Audio: Japanese
Subtitles: French

Case B: audio and forced subtitle are in the same language

Example:

Reference episode:
Audio: French
Subtitles: French forced

Target episode:
Audio: French
Subtitles: French

The French forced subtitle does not exist on the target episode, but a full French subtitle exists.

Expected behavior:

PAL should not select the full French subtitle.
PAL should disable subtitles.

Reason:

The audio is already French.
A French forced subtitle usually only displays a few specific parts.
If the forced subtitle does not exist, selecting the full French subtitle is not equivalent.

Result:

Target episode:
Audio: French
Subtitles: None

7. Missing regular subtitle

If the user selects a regular subtitle on the reference episode, but that subtitle does not exist on the target episode, PAL should not aggressively disable the existing subtitle selection.

Example:

Reference:
Audio: Japanese
Subtitles: French regular

Target:
Audio: Japanese
Subtitles: English

Expected behavior:

PAL does not find a matching French regular subtitle.
PAL keeps the target episode current subtitle state unchanged.

This avoids clearing an existing selection when there is no clear equivalent subtitle available.

Summary of added rules

1. If the reference episode has no subtitle streams available:
   → do not propagate "None".

2. If the reference audio is missing on the target episode
   AND a subtitle is selected on the reference:
   → do not directly apply that subtitle.

3. If the reference audio is missing on the target episode
   AND the reference has no subtitle selected:
   → look for a regular subtitle matching the reference audio language.

4. If the reference has only one audio stream
   AND the target has multiple audio streams:
   → do not modify the target audio.
   → allow subtitle changes only if the target is already using the same audio language.

5. If a forced subtitle is selected:
   → use the forced subtitle if available.

6. If a forced subtitle is selected but missing on the target:
   → if audio and subtitle are in different languages, fall back to a regular subtitle in the same subtitle language.
   → if audio and subtitle are in the same language, disable subtitles.

7. If a regular subtitle is selected but missing on the target:
   → do not disable the existing subtitles.

Validation examples

Example 1

Episode 1:
Audio: French, Japanese
Subtitles: French forced, French

Episode 2:
Audio: Japanese
Subtitles: French

Action:

Episode 1 → Japanese audio + French forced subtitle

Expected result on episode 2:

Audio: Japanese
Subtitles: French

Reason:

Japanese audio exists on episode 2.
The French forced subtitle does not exist.
Since Japanese audio != French subtitle, PAL uses the regular French subtitle as a fallback.

Example 2

Episode 1:
Audio: French, Japanese
Subtitles: French forced, French

Episode 2:
Audio: French
Subtitles: French

Action:

Episode 1 → French audio + French forced subtitle

Expected result on episode 2:

Audio: French
Subtitles: None

Reason:

The French forced subtitle does not exist on episode 2.
Since French audio == French subtitle, PAL should not select the full French subtitle instead.

Example 3

Episode 1:
Audio: French, Japanese
Subtitles: French forced, French

Episode 2:
Audio: Japanese
Subtitles: French

Action:

Episode 1 → French audio + no subtitle

Expected result on episode 2:

Audio: Japanese
Subtitles: French

Reason:

French audio does not exist on episode 2.
The reference has no subtitle selected.
PAL therefore uses a regular French subtitle as fallback.

Example 4

Episode 1:
Audio: French, Japanese
Subtitles: French forced, French

Episode 2:
Audio: Japanese
Subtitles: French

Action:

Episode 2 → Japanese audio + French subtitle

Expected result on episode 1:

Episode 1 audio should not be changed automatically.
Subtitles should only be modified if episode 1 is already using Japanese audio.

Reason:

Episode 2 has only one audio stream.
That stream does not necessarily represent an explicit user choice.

Known limitations

This change does not attempt to fix incorrect file metadata.

PAL still depends on the information exposed by Plex:

languageCode
forced
hearingImpaired
title
displayTitle
extendedDisplayTitle
codec

If two tracks are incorrectly tagged, have no distinctive name, or use different language codes despite visually appearing as the same language, PAL may still not select the expected track.

Examples of cases not covered:

- "fr" on one episode and "fre" on another.
- forced subtitle not tagged as forced and without the word "forced" in its title.
- multiple subtitle tracks in the same language without distinctive titles.
- SDH / hearing impaired subtitles incorrectly tagged.

In these cases, the issue is more likely caused by file metadata or by what Plex exposes through its API.

Goal of this PR

This PR aims to make track propagation safer and closer to Plex’s natural behavior when episodes of the same show do not expose exactly the same audio and subtitle streams.

It mainly avoids:

- disabling useful subtitles when a natural fallback exists;
- applying a subtitle that belongs to an unavailable audio stream;
- too aggressively propagating a selection from an episode with only one audio stream;
- replacing a missing forced subtitle with a full subtitle when the audio is already in the same language.

@devildant

Copy link
Copy Markdown
Author

I've tested all the slightly dodgy scenarios my deranged brain could come up with ^^, but it would be good to have other testers

@JourneyOver

Copy link
Copy Markdown
Member

Will take a look into this and #97 when I can get a chance, been kind of busy so I haven't really had a whole lot of time to sit down and look at these PRs yet.

@devildant

Copy link
Copy Markdown
Author

No problem, it's the holiday period :) I'm currently using my 2 PRs, which gives me more time for testing 😀

@devildant

Copy link
Copy Markdown
Author

It's ok for me, I didn't have any problems

@JourneyOver

Copy link
Copy Markdown
Member

Did you mean to comment that on the closed PR :P @devildant

I'm still thinking about this one mainly btw, I'll probably get around to merging and pushing some others out first before I get around to looking more into this PR.

@devildant

Copy link
Copy Markdown
Author

No, no, it was just to say that I've been using the code from this PR since I created it and it works well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants