Add "Only Forced Subtitles" option to subtitle selection (#589)

## Description

Adds a client-side "Only Forced Subtitles" option when selecting
subtitles, per the discussion in #571.

  ### Changes

  - **TrackIndex.ONLY_FORCED** (`-3`): New constant for the special case
- **StreamChoiceService**: Intercepts `ONLY_FORCED` at the top of
`chooseSubtitleStream()` before server-side `SubtitlePlaybackMode` logic
(which remains untouched)
  - **UI**: Adds "Only Forced Subtitles" option to both:
    - In-player subtitle menu (`PlaybackDialog.kt`)
    - Pre-playback stream selection dialog (`Dialogs.kt`)

  ### Forced track detection

Uses metadata `isForced` flag as primary check, with title-based
fallback ("forced", "signs", "songs" patterns) when language matches
audio.

  ### Related issues

  Closes #571

  ### Screenshots

  N/A - subtitle selection menu only

  ### AI/LLM usage

  Used Claude Code for assistance and to draft PR description.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Damontecres <damontecres@gmail.com>
This commit is contained in:
Justin Caveda 2026-01-11 12:11:39 -06:00 committed by GitHub
parent 8bdc8a6f8f
commit ed67e5575f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 279 additions and 5 deletions

View file

@ -133,7 +133,7 @@ class ItemPlaybackRepository
Timber.v("Saving track selection %s", toSave)
toSave = saveItemPlayback(toSave)
val seriesId = item.data.seriesId
if (seriesId != null && trackIndex != TrackIndex.UNSPECIFIED) {
if (seriesId != null && (trackIndex >= 0 || trackIndex == TrackIndex.DISABLED)) {
if (type == MediaStreamType.AUDIO) {
val stream = source.mediaStreams?.first { it.index == trackIndex }
if (stream?.language != null) {
@ -147,7 +147,7 @@ class ItemPlaybackRepository
subtitlesDisabled = true,
)
} else {
val stream = source.mediaStreams?.first { it.index == trackIndex }
val stream = source.mediaStreams?.firstOrNull { it.index == trackIndex }
if (stream?.language != null) {
streamChoiceService.updateSubtitles(
item.data,

View file

@ -54,4 +54,9 @@ object TrackIndex {
* The user has explicitly disabled the tracks (eg turned off subtitles)
*/
const val DISABLED = -2
/**
* The user wants only forced subtitles (for foreign language dialogue, signs, etc.)
*/
const val ONLY_FORCED = -3
}