mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-17 02:48:19 -07:00
Merge pull request #2621 from iwalton3/auto-set-tracks
Add subtitle/audio auto-set feature.
This commit is contained in:
commit
ee20a51c48
@ -2107,7 +2107,7 @@ class PlaybackManager {
|
||||
}
|
||||
}
|
||||
|
||||
function playInternal(item, playOptions, onPlaybackStartedFn) {
|
||||
function playInternal(item, playOptions, onPlaybackStartedFn, prevSource) {
|
||||
if (item.IsPlaceHolder) {
|
||||
loading.hide();
|
||||
showPlaybackInfoErrorMessage(self, 'PlaybackErrorPlaceHolder');
|
||||
@ -2132,7 +2132,7 @@ class PlaybackManager {
|
||||
const mediaType = item.MediaType;
|
||||
|
||||
const onBitrateDetectionFailure = function () {
|
||||
return playAfterBitrateDetect(getSavedMaxStreamingBitrate(ServerConnections.getApiClient(item.ServerId), mediaType), item, playOptions, onPlaybackStartedFn);
|
||||
return playAfterBitrateDetect(getSavedMaxStreamingBitrate(ServerConnections.getApiClient(item.ServerId), mediaType), item, playOptions, onPlaybackStartedFn, prevSource);
|
||||
};
|
||||
|
||||
if (!isServerItem(item) || itemHelper.isLocalItem(item)) {
|
||||
@ -2145,7 +2145,7 @@ class PlaybackManager {
|
||||
return apiClient.detectBitrate().then(function (bitrate) {
|
||||
appSettings.maxStreamingBitrate(endpointInfo.IsInNetwork, mediaType, bitrate);
|
||||
|
||||
return playAfterBitrateDetect(bitrate, item, playOptions, onPlaybackStartedFn);
|
||||
return playAfterBitrateDetect(bitrate, item, playOptions, onPlaybackStartedFn, prevSource);
|
||||
}, onBitrateDetectionFailure);
|
||||
} else {
|
||||
onBitrateDetectionFailure();
|
||||
@ -2226,7 +2226,104 @@ class PlaybackManager {
|
||||
});
|
||||
}
|
||||
|
||||
function playAfterBitrateDetect(maxBitrate, item, playOptions, onPlaybackStartedFn) {
|
||||
function rankStreamType(prevIndex, prevSource, mediaSource, streamType) {
|
||||
if (prevIndex == -1) {
|
||||
console.debug(`AutoSet ${streamType} - No Stream Set`);
|
||||
if (streamType == 'Subtitle')
|
||||
mediaSource.DefaultSubtitleStreamIndex = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!prevSource.MediaStreams || !mediaSource.MediaStreams) {
|
||||
console.debug(`AutoSet ${streamType} - No MediaStreams`);
|
||||
return;
|
||||
}
|
||||
|
||||
let bestStreamIndex = null;
|
||||
let bestStreamScore = 0;
|
||||
const prevStream = prevSource.MediaStreams[prevIndex];
|
||||
|
||||
if (!prevStream) {
|
||||
console.debug(`AutoSet ${streamType} - No prevStream`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug(`AutoSet ${streamType} - Previous was ${prevStream.Index} - ${prevStream.DisplayTitle}`);
|
||||
|
||||
let prevRelIndex = 0;
|
||||
for (const stream of prevSource.MediaStreams) {
|
||||
if (stream.Type != streamType)
|
||||
continue;
|
||||
|
||||
if (stream.Index == prevIndex)
|
||||
break;
|
||||
|
||||
prevRelIndex += 1;
|
||||
}
|
||||
|
||||
let newRelIndex = 0;
|
||||
for (const stream of mediaSource.MediaStreams) {
|
||||
if (stream.Type != streamType)
|
||||
continue;
|
||||
|
||||
let score = 0;
|
||||
|
||||
if (prevStream.Codec == stream.Codec)
|
||||
score += 1;
|
||||
if (prevRelIndex == newRelIndex)
|
||||
score += 1;
|
||||
if (prevStream.Title && prevStream.Title == stream.Title)
|
||||
score += 2;
|
||||
if (prevStream.Language && prevStream.Language != 'und' && prevStream.Language == stream.Language)
|
||||
score += 2;
|
||||
|
||||
console.debug(`AutoSet ${streamType} - Score ${score} for ${stream.Index} - ${stream.DisplayTitle}`);
|
||||
if (score > bestStreamScore && score >= 3) {
|
||||
bestStreamScore = score;
|
||||
bestStreamIndex = stream.Index;
|
||||
}
|
||||
|
||||
newRelIndex += 1;
|
||||
}
|
||||
|
||||
if (bestStreamIndex != null) {
|
||||
console.debug(`AutoSet ${streamType} - Using ${bestStreamIndex} score ${bestStreamScore}.`);
|
||||
if (streamType == 'Subtitle')
|
||||
mediaSource.DefaultSubtitleStreamIndex = bestStreamIndex;
|
||||
if (streamType == 'Audio')
|
||||
mediaSource.DefaultAudioStreamIndex = bestStreamIndex;
|
||||
} else {
|
||||
console.debug(`AutoSet ${streamType} - Threshold not met. Using default.`);
|
||||
}
|
||||
}
|
||||
|
||||
function autoSetNextTracks(prevSource, mediaSource) {
|
||||
try {
|
||||
if (!prevSource) return;
|
||||
|
||||
if (!mediaSource) {
|
||||
console.warn('AutoSet - No mediaSource');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof prevSource.DefaultAudioStreamIndex != 'number'
|
||||
|| typeof prevSource.DefaultSubtitleStreamIndex != 'number')
|
||||
return;
|
||||
|
||||
if (typeof mediaSource.DefaultAudioStreamIndex != 'number'
|
||||
|| typeof mediaSource.DefaultSubtitleStreamIndex != 'number') {
|
||||
console.warn('AutoSet - No stream indexes (but prevSource has them)');
|
||||
return;
|
||||
}
|
||||
|
||||
rankStreamType(prevSource.DefaultAudioStreamIndex, prevSource, mediaSource, 'Audio');
|
||||
rankStreamType(prevSource.DefaultSubtitleStreamIndex, prevSource, mediaSource, 'Subtitle');
|
||||
} catch (e) {
|
||||
console.error(`AutoSet - Caught unexpected error: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
function playAfterBitrateDetect(maxBitrate, item, playOptions, onPlaybackStartedFn, prevSource) {
|
||||
const startPosition = playOptions.startPositionTicks;
|
||||
|
||||
const player = getPlayer(item, playOptions);
|
||||
@ -2285,6 +2382,9 @@ class PlaybackManager {
|
||||
playOptions.items = null;
|
||||
|
||||
return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex).then(function (mediaSource) {
|
||||
if (userSettings.enableSetUsingLastTracks())
|
||||
autoSetNextTracks(prevSource, mediaSource);
|
||||
|
||||
const streamInfo = createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition, player);
|
||||
|
||||
streamInfo.fullscreen = playOptions.fullscreen;
|
||||
@ -2643,6 +2743,16 @@ class PlaybackManager {
|
||||
return self.previousTrack(player);
|
||||
};
|
||||
|
||||
function getPreviousSource(player) {
|
||||
const prevSource = self.currentMediaSource(player);
|
||||
const prevPlayerData = getPlayerData(player);
|
||||
return {
|
||||
...prevSource,
|
||||
DefaultAudioStreamIndex: prevPlayerData.audioStreamIndex,
|
||||
DefaultSubtitleStreamIndex: prevPlayerData.subtitleStreamIndex
|
||||
};
|
||||
}
|
||||
|
||||
self.nextTrack = function (player) {
|
||||
player = player || self._currentPlayer;
|
||||
if (player && !enableLocalPlaylistManagement(player)) {
|
||||
@ -2658,7 +2768,7 @@ class PlaybackManager {
|
||||
|
||||
playInternal(newItemInfo.item, newItemPlayOptions, function () {
|
||||
setPlaylistState(newItemInfo.item.PlaylistItemId, newItemInfo.index);
|
||||
});
|
||||
}, getPreviousSource(player));
|
||||
}
|
||||
};
|
||||
|
||||
@ -2679,7 +2789,7 @@ class PlaybackManager {
|
||||
|
||||
playInternal(newItem, newItemPlayOptions, function () {
|
||||
setPlaylistState(newItem.PlaylistItemId, newIndex);
|
||||
});
|
||||
}, getPreviousSource(player));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -195,6 +195,7 @@ import template from './playbackSettings.template.html';
|
||||
context.querySelector('.chkPreferFmp4HlsContainer').checked = userSettings.preferFmp4HlsContainer();
|
||||
context.querySelector('.chkEnableCinemaMode').checked = userSettings.enableCinemaMode();
|
||||
context.querySelector('.chkEnableNextVideoOverlay').checked = userSettings.enableNextVideoInfoOverlay();
|
||||
context.querySelector('.chkSetUsingLastTracks').checked = userSettings.enableSetUsingLastTracks();
|
||||
context.querySelector('.chkExternalVideoPlayer').checked = appSettings.enableSystemExternalPlayers();
|
||||
|
||||
setMaxBitrateIntoField(context.querySelector('.selectVideoInNetworkQuality'), true, 'Video');
|
||||
@ -236,6 +237,7 @@ import template from './playbackSettings.template.html';
|
||||
userSettingsInstance.enableCinemaMode(context.querySelector('.chkEnableCinemaMode').checked);
|
||||
|
||||
userSettingsInstance.enableNextVideoInfoOverlay(context.querySelector('.chkEnableNextVideoOverlay').checked);
|
||||
userSettingsInstance.enableSetUsingLastTracks(context.querySelector('.chkSetUsingLastTracks').checked);
|
||||
userSettingsInstance.chromecastVersion(context.querySelector('.selectChromecastVersion').value);
|
||||
userSettingsInstance.skipForwardLength(context.querySelector('.selectSkipForwardLength').value);
|
||||
userSettingsInstance.skipBackLength(context.querySelector('.selectSkipBackLength').value);
|
||||
|
@ -82,6 +82,14 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkSetUsingLastTracks" />
|
||||
<span>${SetUsingLastTracks}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${SetUsingLastTracksHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldEnableNextVideoOverlay hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkEnableNextVideoOverlay" />
|
||||
|
@ -169,6 +169,19 @@ export class UserSettings {
|
||||
return val !== 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'SetUsingLastTracks' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'SetUsingLastTracks' or undefined.
|
||||
* @return {boolean} 'SetUsingLastTracks' state.
|
||||
*/
|
||||
enableSetUsingLastTracks(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('enableSetUsingLastTracks', val.toString());
|
||||
}
|
||||
|
||||
return this.get('enableSetUsingLastTracks', false) !== 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Theme Songs' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'Theme Songs' or undefined.
|
||||
@ -528,6 +541,7 @@ export const allowedAudioChannels = currentSettings.allowedAudioChannels.bind(cu
|
||||
export const preferFmp4HlsContainer = currentSettings.preferFmp4HlsContainer.bind(currentSettings);
|
||||
export const enableCinemaMode = currentSettings.enableCinemaMode.bind(currentSettings);
|
||||
export const enableNextVideoInfoOverlay = currentSettings.enableNextVideoInfoOverlay.bind(currentSettings);
|
||||
export const enableSetUsingLastTracks = currentSettings.enableSetUsingLastTracks.bind(currentSettings);
|
||||
export const enableThemeSongs = currentSettings.enableThemeSongs.bind(currentSettings);
|
||||
export const enableThemeVideos = currentSettings.enableThemeVideos.bind(currentSettings);
|
||||
export const enableFastFadein = currentSettings.enableFastFadein.bind(currentSettings);
|
||||
|
@ -1362,6 +1362,8 @@
|
||||
"Settings": "Settings",
|
||||
"SettingsSaved": "Settings saved.",
|
||||
"SettingsWarning": "Changing these values may cause instability or connectivity failures. If you experience any problems, we recommend changing them back to default.",
|
||||
"SetUsingLastTracks": "Set Subtitle/Audio Tracks with Previous Item",
|
||||
"SetUsingLastTracksHelp": "Attempts to set the Subtitle/Audio track to the closest match to the last video.",
|
||||
"Share": "Share",
|
||||
"ShowAdvancedSettings": "Show advanced settings",
|
||||
"ShowIndicatorsFor": "Show indicators for:",
|
||||
|
Loading…
Reference in New Issue
Block a user