Skip to content

Commit 3fb5073

Browse files
authored
Merge pull request #8150 from karyogamy/caption-fix
Fix caption auto-selection not reflected in player GUI
2 parents 75df1fa + 9818f17 commit 3fb5073

3 files changed

Lines changed: 74 additions & 53 deletions

File tree

app/src/main/java/org/schabi/newpipe/player/Player.java

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
import static org.schabi.newpipe.util.ListHelper.getPopupResolutionIndex;
6363
import static org.schabi.newpipe.util.ListHelper.getResolutionIndex;
6464
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
65-
import static org.schabi.newpipe.util.Localization.containsCaseInsensitive;
6665
import static java.util.concurrent.TimeUnit.MILLISECONDS;
6766

6867
import android.animation.Animator;
@@ -130,15 +129,14 @@
130129
import com.google.android.exoplayer2.C;
131130
import com.google.android.exoplayer2.DefaultRenderersFactory;
132131
import com.google.android.exoplayer2.ExoPlayer;
132+
import com.google.android.exoplayer2.Format;
133133
import com.google.android.exoplayer2.PlaybackException;
134134
import com.google.android.exoplayer2.PlaybackParameters;
135135
import com.google.android.exoplayer2.Player.PositionInfo;
136136
import com.google.android.exoplayer2.RenderersFactory;
137137
import com.google.android.exoplayer2.Timeline;
138138
import com.google.android.exoplayer2.TracksInfo;
139139
import com.google.android.exoplayer2.source.MediaSource;
140-
import com.google.android.exoplayer2.source.TrackGroup;
141-
import com.google.android.exoplayer2.source.TrackGroupArray;
142140
import com.google.android.exoplayer2.text.Cue;
143141
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
144142
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
@@ -212,7 +210,6 @@
212210
import org.schabi.newpipe.views.ExpandableSurfaceView;
213211
import org.schabi.newpipe.views.player.PlayerFastSeekOverlay;
214212

215-
import java.util.ArrayList;
216213
import java.util.Collections;
217214
import java.util.List;
218215
import java.util.Objects;
@@ -2530,7 +2527,7 @@ public void onTracksInfoChanged(@NonNull final TracksInfo tracksInfo) {
25302527
Log.d(TAG, "ExoPlayer - onTracksChanged(), "
25312528
+ "track group size = " + tracksInfo.getTrackGroupInfos().size());
25322529
}
2533-
onTextTracksChanged();
2530+
onTextTracksChanged(tracksInfo);
25342531
}
25352532

25362533
@Override
@@ -3516,17 +3513,7 @@ private void buildCaptionMenu(@NonNull final List<String> availableLanguages) {
35163513
return;
35173514
}
35183515
captionPopupMenu.getMenu().removeGroup(POPUP_MENU_ID_CAPTION);
3519-
3520-
final String userPreferredLanguage =
3521-
prefs.getString(context.getString(R.string.caption_user_set_key), null);
3522-
/*
3523-
* only search for autogenerated cc as fallback
3524-
* if "(auto-generated)" was not already selected
3525-
* we are only looking for "(" instead of "(auto-generated)" to hopefully get all
3526-
* internationalized variants such as "(automatisch-erzeugt)" and so on
3527-
*/
3528-
boolean searchForAutogenerated = userPreferredLanguage != null
3529-
&& !userPreferredLanguage.contains("(");
3516+
captionPopupMenu.setOnDismissListener(this);
35303517

35313518
// Add option for turning off caption
35323519
final MenuItem captionOffItem = captionPopupMenu.getMenu().add(POPUP_MENU_ID_CAPTION,
@@ -3549,30 +3536,42 @@ private void buildCaptionMenu(@NonNull final List<String> availableLanguages) {
35493536
captionItem.setOnMenuItemClickListener(menuItem -> {
35503537
final int textRendererIndex = getCaptionRendererIndex();
35513538
if (textRendererIndex != RENDERER_UNAVAILABLE) {
3539+
// DefaultTrackSelector will select for text tracks in the following order.
3540+
// When multiple tracks share the same rank, a random track will be chosen.
3541+
// 1. ANY track exactly matching preferred language name
3542+
// 2. ANY track exactly matching preferred language stem
3543+
// 3. ROLE_FLAG_CAPTION track matching preferred language stem
3544+
// 4. ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND track matching preferred language stem
3545+
// This means if a caption track of preferred language is not available,
3546+
// then an auto-generated track of that language will be chosen automatically.
35523547
trackSelector.setParameters(trackSelector.buildUponParameters()
3553-
.setPreferredTextLanguage(captionLanguage)
3548+
.setPreferredTextLanguages(captionLanguage,
3549+
PlayerHelper.captionLanguageStemOf(captionLanguage))
3550+
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
35543551
.setRendererDisabled(textRendererIndex, false));
35553552
prefs.edit().putString(context.getString(R.string.caption_user_set_key),
35563553
captionLanguage).apply();
35573554
}
35583555
return true;
35593556
});
3560-
// apply caption language from previous user preference
3561-
if (userPreferredLanguage != null
3562-
&& (captionLanguage.equals(userPreferredLanguage)
3563-
|| (searchForAutogenerated && captionLanguage.startsWith(userPreferredLanguage))
3564-
|| (userPreferredLanguage.contains("(") && captionLanguage.startsWith(
3565-
userPreferredLanguage.substring(0, userPreferredLanguage.indexOf('(')))))) {
3566-
final int textRendererIndex = getCaptionRendererIndex();
3567-
if (textRendererIndex != RENDERER_UNAVAILABLE) {
3568-
trackSelector.setParameters(trackSelector.buildUponParameters()
3569-
.setPreferredTextLanguage(captionLanguage)
3570-
.setRendererDisabled(textRendererIndex, false));
3571-
}
3572-
searchForAutogenerated = false;
3573-
}
35743557
}
3575-
captionPopupMenu.setOnDismissListener(this);
3558+
3559+
// apply caption language from previous user preference
3560+
final List<String> selectedPreferredLanguages =
3561+
trackSelector.getParameters().preferredTextLanguages;
3562+
final String userPreferredLanguage =
3563+
prefs.getString(context.getString(R.string.caption_user_set_key), null);
3564+
final int textRendererIndex = getCaptionRendererIndex();
3565+
3566+
if (userPreferredLanguage != null
3567+
&& !selectedPreferredLanguages.contains(userPreferredLanguage)
3568+
&& textRendererIndex != RENDERER_UNAVAILABLE) {
3569+
trackSelector.setParameters(trackSelector.buildUponParameters()
3570+
.setPreferredTextLanguages(userPreferredLanguage,
3571+
PlayerHelper.captionLanguageStemOf(userPreferredLanguage))
3572+
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
3573+
.setRendererDisabled(textRendererIndex, false));
3574+
}
35763575
}
35773576

35783577
/**
@@ -3668,41 +3667,43 @@ private void setupSubtitleView() {
36683667
binding.subtitleView.setStyle(captionStyle);
36693668
}
36703669

3671-
private void onTextTracksChanged() {
3672-
final int textRenderer = getCaptionRendererIndex();
3673-
3670+
private void onTextTracksChanged(@NonNull final TracksInfo currentTrackInfo) {
36743671
if (binding == null) {
36753672
return;
36763673
}
3674+
36773675
if (trackSelector.getCurrentMappedTrackInfo() == null
3678-
|| textRenderer == RENDERER_UNAVAILABLE) {
3676+
|| !currentTrackInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_TEXT)) {
36793677
binding.captionTextView.setVisibility(View.GONE);
36803678
return;
36813679
}
36823680

3683-
final TrackGroupArray textTracks = trackSelector.getCurrentMappedTrackInfo()
3684-
.getTrackGroups(textRenderer);
3685-
36863681
// Extract all loaded languages
3687-
final List<String> availableLanguages = new ArrayList<>(textTracks.length);
3688-
for (int i = 0; i < textTracks.length; i++) {
3689-
final TrackGroup textTrack = textTracks.get(i);
3690-
if (textTrack.length > 0) {
3691-
availableLanguages.add(textTrack.getFormat(0).language);
3692-
}
3693-
}
3682+
final List<TracksInfo.TrackGroupInfo> textTracks = currentTrackInfo
3683+
.getTrackGroupInfos()
3684+
.stream()
3685+
.filter(trackGroupInfo -> C.TRACK_TYPE_TEXT == trackGroupInfo.getTrackType())
3686+
.collect(Collectors.toList());
3687+
final List<String> availableLanguages = textTracks.stream()
3688+
.map(TracksInfo.TrackGroupInfo::getTrackGroup)
3689+
.filter(textTrack -> textTrack.length > 0)
3690+
.map(textTrack -> textTrack.getFormat(0).language)
3691+
.collect(Collectors.toList());
3692+
3693+
// Find selected text track
3694+
final Optional<Format> selectedTracks = textTracks.stream()
3695+
.filter(TracksInfo.TrackGroupInfo::isSelected)
3696+
.filter(info -> info.getTrackGroup().length >= 1)
3697+
.map(info -> info.getTrackGroup().getFormat(0))
3698+
.findFirst();
36943699

3695-
// Normalize mismatching language strings
3696-
final String preferredLanguage = trackSelector.getParameters()
3697-
.preferredTextLanguages.stream().findFirst().orElse(null);
36983700
// Build UI
36993701
buildCaptionMenu(availableLanguages);
3700-
if (trackSelector.getParameters().getRendererDisabled(textRenderer)
3701-
|| preferredLanguage == null || (!availableLanguages.contains(preferredLanguage)
3702-
&& !containsCaseInsensitive(availableLanguages, preferredLanguage))) {
3702+
if (trackSelector.getParameters().getRendererDisabled(getCaptionRendererIndex())
3703+
|| !selectedTracks.isPresent()) {
37033704
binding.captionTextView.setText(R.string.caption_none);
37043705
} else {
3705-
binding.captionTextView.setText(preferredLanguage);
3706+
binding.captionTextView.setText(selectedTracks.get().language);
37063707
}
37073708
binding.captionTextView.setVisibility(
37083709
availableLanguages.isEmpty() ? View.GONE : View.VISIBLE);

app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,21 @@ public static String captionLanguageOf(@NonNull final Context context,
144144
? " (" + context.getString(R.string.caption_auto_generated) + ")" : "");
145145
}
146146

147+
@NonNull
148+
public static String captionLanguageStemOf(@NonNull final String language) {
149+
if (!language.contains("(") || !language.contains(")")) {
150+
return language;
151+
}
152+
153+
if (language.startsWith("(")) {
154+
// language text is right-to-left
155+
final String[] parts = language.split("\\)");
156+
return parts[parts.length - 1].trim();
157+
}
158+
159+
return language.split("\\(")[0].trim();
160+
}
161+
147162
@NonNull
148163
public static String resizeTypeOf(@NonNull final Context context,
149164
@ResizeMode final int resizeMode) {

app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import androidx.annotation.NonNull;
77
import androidx.annotation.Nullable;
88

9+
import com.google.android.exoplayer2.C;
910
import com.google.android.exoplayer2.MediaItem;
1011
import com.google.android.exoplayer2.source.MediaSource;
1112
import com.google.android.exoplayer2.source.MergingMediaSource;
@@ -116,9 +117,13 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
116117
if (mimeType == null) {
117118
continue;
118119
}
120+
final @C.RoleFlags int textRoleFlag = subtitle.isAutoGenerated()
121+
? C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND
122+
: C.ROLE_FLAG_CAPTION;
119123
final MediaItem.SubtitleConfiguration textMediaItem =
120124
new MediaItem.SubtitleConfiguration.Builder(Uri.parse(subtitle.getUrl()))
121125
.setMimeType(mimeType)
126+
.setRoleFlags(textRoleFlag)
122127
.setLanguage(PlayerHelper.captionLanguageOf(context, subtitle))
123128
.build();
124129
final MediaSource textSource = dataSource

0 commit comments

Comments
 (0)