Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to remember audio and subtitle selection settings #3754

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ class UserPreferences(context: Context) : SharedPreferenceStore(
*/
var mediaQueuingEnabled = booleanPreference("pref_enable_tv_queuing", true)

/**
* Set audio track to match previous video
*/
var rememberAudio = booleanPreference("pref_remember_audio", true)

/**
* Set subtitle track to match previous video
*/
var rememberSubtitle = booleanPreference("pref_remember_subtitle", true)

/**
* Enable the next up screen or not
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Objects;

import kotlin.Lazy;
import timber.log.Timber;
Expand Down Expand Up @@ -81,6 +82,7 @@ public class PlaybackController implements PlaybackControllerNotifiable {
private Boolean spinnerOff = false;

private VideoOptions mCurrentOptions;
private VideoOptions mPrevOptions;
private int mDefaultSubIndex = -1;
private int mDefaultAudioIndex = -1;
private boolean burningSubs = false;
Expand All @@ -107,6 +109,8 @@ public class PlaybackController implements PlaybackControllerNotifiable {

private Display.Mode[] mDisplayModes;
private RefreshRateSwitchingBehavior refreshRateSwitchingBehavior = RefreshRateSwitchingBehavior.DISABLED;
private Boolean rememberPreviousAudioTrack = false;
private Boolean rememberPreviousSubtitleTrack = false;

public PlaybackController(List<BaseItemDto> items, CustomPlaybackOverlayFragment fragment) {
this(items, fragment, 0);
Expand All @@ -115,13 +119,15 @@ public PlaybackController(List<BaseItemDto> items, CustomPlaybackOverlayFragment
public PlaybackController(List<BaseItemDto> items, CustomPlaybackOverlayFragment fragment, int startIndex) {
mItems = items;
mCurrentIndex = 0;
mPrevOptions = new VideoOptions();
if (items != null && startIndex > 0 && startIndex < items.size()) {
mCurrentIndex = startIndex;
}
mFragment = fragment;
mHandler = new Handler();


rememberPreviousAudioTrack = userPreferences.getValue().get(UserPreferences.Companion.getRememberAudio());
rememberPreviousSubtitleTrack = userPreferences.getValue().get(UserPreferences.Companion.getRememberSubtitle());
refreshRateSwitchingBehavior = userPreferences.getValue().get(UserPreferences.Companion.getRefreshRateSwitchingBehavior());
if (refreshRateSwitchingBehavior != RefreshRateSwitchingBehavior.DISABLED)
getDisplayModes();
Expand Down Expand Up @@ -700,6 +706,49 @@ private Integer bestGuessAudioTrack(MediaSourceInfo info) {
return null;
}

private Integer bestGuessTrackFromPrevious(String trackType, StreamInfo info) {
if (info == null)
return null;

Integer prevTrackIndex = Objects.equals(trackType, "audio") ? mPrevOptions.getAudioStreamIndex() : mPrevOptions.getSubtitleStreamIndex();
List<MediaSourceInfo> prevMediaSources = mPrevOptions.getMediaSources();
if (prevTrackIndex != null && prevMediaSources != null) {
List<MediaStream> prevMediaStreams = prevMediaSources.get(0).getMediaStreams();
if (prevMediaStreams != null) {
MediaStream prevTrackStream = prevMediaStreams.get(prevTrackIndex);
if (prevTrackStream != null) {
List<MediaStream> infoMediaStreams = info.getMediaSource().getMediaStreams();
if (infoMediaStreams != null) {
MediaStream infoAudioStream = infoMediaStreams.get(prevTrackIndex);
if (infoAudioStream != null && Objects.equals(prevTrackStream.getDisplayTitle(), infoAudioStream.getDisplayTitle()))
return prevTrackIndex;

Integer indexOfPrevTrackStreamInInfo = findIndexByDisplayNameAndLang(infoMediaStreams, prevTrackStream.getDisplayTitle(), prevTrackStream.getLanguage());
if (indexOfPrevTrackStreamInInfo != null)
return indexOfPrevTrackStreamInInfo;
}
}
}
}
return info.getMediaSource().getDefaultAudioStreamIndex();
}

// Method to find index of object in array by display name
private Integer findIndexByDisplayNameAndLang(List<MediaStream> mediaStreams, String displayTitle, String lang) {
int fallBackIndex = -1;
for (int i = 0; i < mediaStreams.size(); i++) {
String currentDisplayTitle = mediaStreams.get(i).getDisplayTitle();
String currentLang = mediaStreams.get(i).getLanguage();
if (currentDisplayTitle != null && currentLang != null && currentDisplayTitle.equals(displayTitle) && currentLang.equals(lang)) {
return i; // Return index if display name matches
} else if (currentLang != null && currentLang.equals(lang)) {
fallBackIndex = i; // Fallback will be track that matches language
}
}

return fallBackIndex; // Return index if only language matches
}

private void setDefaultAudioIndex(StreamInfo info) {
if (mDefaultAudioIndex != -1)
return;
Expand All @@ -719,12 +768,15 @@ public void switchAudioStream(int index) {
return;

int currAudioIndex = getAudioStreamIndex();
Timber.d("trying to switch audio stream from %s to %s", currAudioIndex, index);
if (currAudioIndex == index) {
Timber.d("skipping setting audio stream, already set to requested index %s", index);
if (mCurrentOptions.getAudioStreamIndex() == null || mCurrentOptions.getAudioStreamIndex() != index) {
Timber.d("setting mCurrentOptions audio stream index from %s to %s", mCurrentOptions.getAudioStreamIndex(), index);
mCurrentOptions.setAudioStreamIndex(index);
Integer currOptionsAudioIndex = mCurrentOptions.getAudioStreamIndex();
Integer prevOptionsAudioIndex = mPrevOptions.getAudioStreamIndex();
int audioIndexToUse = rememberPreviousAudioTrack && prevOptionsAudioIndex != null ? prevOptionsAudioIndex : index;
Timber.d("trying to switch audio stream from %s to %s", currAudioIndex, audioIndexToUse);
if (currAudioIndex == audioIndexToUse || (prevOptionsAudioIndex != null && prevOptionsAudioIndex == audioIndexToUse)) {
Timber.d("skipping setting audio stream, already set to requested index %s", audioIndexToUse);
if ((currOptionsAudioIndex == null || currOptionsAudioIndex != audioIndexToUse) || (prevOptionsAudioIndex == null || prevOptionsAudioIndex != audioIndexToUse)) {
Timber.d("setting mCurrentOptions audio stream index from %s to %s", currOptionsAudioIndex, audioIndexToUse);
mCurrentOptions.setAudioStreamIndex(audioIndexToUse);
}
Comment on lines +775 to 780
Copy link

@entropicdrifter entropicdrifter Aug 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you wanted these two conditions to be mutually exclusive. Current behavior would only attempt to change the audio stream index when the skip condition is true. That's probably what's leading to your infinite loop.

Suggested change
if (currAudioIndex == audioIndexToUse || (prevOptionsAudioIndex != null && prevOptionsAudioIndex == audioIndexToUse)) {
Timber.d("skipping setting audio stream, already set to requested index %s", audioIndexToUse);
if ((currOptionsAudioIndex == null || currOptionsAudioIndex != audioIndexToUse) || (prevOptionsAudioIndex == null || prevOptionsAudioIndex != audioIndexToUse)) {
Timber.d("setting mCurrentOptions audio stream index from %s to %s", currOptionsAudioIndex, audioIndexToUse);
mCurrentOptions.setAudioStreamIndex(audioIndexToUse);
}
if (currAudioIndex == audioIndexToUse || (prevOptionsAudioIndex != null && prevOptionsAudioIndex == audioIndexToUse)) {
Timber.d("skipping setting audio stream, already set to requested index %s", audioIndexToUse);
} else if ((currOptionsAudioIndex == null || currOptionsAudioIndex != audioIndexToUse) || (prevOptionsAudioIndex == null || prevOptionsAudioIndex != audioIndexToUse)) {
Timber.d("setting mCurrentOptions audio stream index from %s to %s", currOptionsAudioIndex, audioIndexToUse);
mCurrentOptions.setAudioStreamIndex(audioIndexToUse);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ConnorS1110 forgot to tag

return;
}
Expand All @@ -734,11 +786,11 @@ public void switchAudioStream(int index) {

if (!isTranscoding() && mVideoManager.setExoPlayerTrack(index, MediaStreamType.AUDIO, getCurrentlyPlayingItem().getMediaStreams())) {
mCurrentOptions.setMediaSourceId(getCurrentMediaSource().getId());
mCurrentOptions.setAudioStreamIndex(index);
mCurrentOptions.setAudioStreamIndex(audioIndexToUse);
} else {
startSpinner();
mCurrentOptions.setMediaSourceId(getCurrentMediaSource().getId());
mCurrentOptions.setAudioStreamIndex(index);
mCurrentOptions.setAudioStreamIndex(audioIndexToUse);
stop();
playInternal(getCurrentlyPlayingItem(), mCurrentPosition, mCurrentOptions);
mPlaybackState = PlaybackState.BUFFERING;
Expand Down Expand Up @@ -944,6 +996,9 @@ public void next() {
if (mCurrentIndex < mItems.size() - 1) {
stop();
resetPlayerErrors();
mPrevOptions.setSubtitleStreamIndex(mCurrentOptions.getSubtitleStreamIndex());
mPrevOptions.setAudioStreamIndex(mCurrentOptions.getAudioStreamIndex());
mPrevOptions.setMediaSources(mCurrentOptions.getMediaSources());
mCurrentIndex++;
videoQueueManager.getValue().setCurrentMediaPosition(mCurrentIndex);
Timber.d("Moving to index: %d out of %d total items.", mCurrentIndex, mItems.size());
Expand Down Expand Up @@ -1219,8 +1274,13 @@ public void onPrepared() {
} else {
// select or disable subtitles
Integer currentSubtitleIndex = mCurrentOptions.getSubtitleStreamIndex();
if (mDefaultSubIndex >= 0 && currentSubtitleIndex != null && currentSubtitleIndex == mDefaultSubIndex) {
Timber.i("subtitle stream %s is already selected", mDefaultSubIndex);
Integer previousSubtitleIndex = mPrevOptions.getSubtitleStreamIndex();
if (rememberPreviousSubtitleTrack && previousSubtitleIndex != null) {
Timber.i("Enabling sub stream from previous: %d", previousSubtitleIndex);
switchSubtitleStream(previousSubtitleIndex);
}
else if ((mDefaultSubIndex >= 0 && currentSubtitleIndex != null && currentSubtitleIndex == mDefaultSubIndex)) {
Timber.i("subtitle stream %s is already selected", currentSubtitleIndex);
} else {
if (mDefaultSubIndex < 0)
Timber.i("Turning off subs");
Expand All @@ -1230,12 +1290,16 @@ public void onPrepared() {
}

// select an audio track
Integer currentAudioIndex = mCurrentOptions.getAudioStreamIndex();
Integer previousAudioIndex = mPrevOptions.getAudioStreamIndex();
int eligibleAudioTrack = mDefaultAudioIndex;

// if track switching is done without rebuilding the stream, mCurrentOptions is updated
// otherwise, use the server default
if (mCurrentOptions.getAudioStreamIndex() != null) {
eligibleAudioTrack = mCurrentOptions.getAudioStreamIndex();
if (rememberPreviousAudioTrack && previousAudioIndex != null)
eligibleAudioTrack = previousAudioIndex;
else if (currentAudioIndex != null) {
eligibleAudioTrack = currentAudioIndex;
} else if (getCurrentMediaSource().getDefaultAudioStreamIndex() != null) {
eligibleAudioTrack = getCurrentMediaSource().getDefaultAudioStreamIndex();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ class PlaybackAdvancedPreferencesScreen : OptionsFragment() {
setTitle(R.string.lbl_tv_queuing)
bind(userPreferences, UserPreferences.mediaQueuingEnabled)
}

checkbox {
setTitle(R.string.lbl_remember_audio)
setContent(R.string.desc_remember_audio)
bind(userPreferences, UserPreferences.rememberAudio)
}

checkbox {
setTitle(R.string.lbl_remember_subtitle)
setContent(R.string.desc_remember_subtitle)
bind(userPreferences, UserPreferences.rememberSubtitle)
}
}

category {
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@
<string name="lbl_no_items">No items</string>
<string name="lbl_empty">Empty</string>
<string name="lbl_tv_queuing">Play next episode automatically</string>
<string name="lbl_remember_audio">Set audio tracked based on previous item</string>
<string name="desc_remember_audio">Try to set the audio track to the closest match to the last video</string>
<string name="lbl_remember_subtitle">Set subtitle tracked based on previous item</string>
<string name="desc_remember_subtitle">Try to set the subtitle track to the closest match to the last video</string>
<string name="lbl_search_hint">Search text (select for keyboard)</string>
<string name="lbl_play_first_unwatched">Play first unwatched</string>
<string name="lbl_mark_unplayed">Mark unplayed</string>
Expand Down
Loading