From abc663f6f6ecca6c7c4babe35b057e3c938f884e Mon Sep 17 00:00:00 2001 From: Ivan Schurawel Date: Sun, 13 Nov 2022 20:22:55 -0500 Subject: [PATCH] fix: update ssa/ass checks, custom track location, offsets --- src/components/playback/playbackmanager.js | 12 ++--- src/controllers/playback/video/index.js | 34 +++++++------ src/plugins/htmlVideoPlayer/plugin.js | 58 +++++++++++++++------- src/plugins/htmlVideoPlayer/style.scss | 1 + 4 files changed, 65 insertions(+), 40 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index f6c366b7ae..9104eceb78 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -887,7 +887,7 @@ class PlaybackManager { * - or if it can be paired with a secondary subtitle when used as a primary subtitle */ self.trackHasSecondarySubtitleSupport = function (track, player = self._currentPlayer) { - if (!player || !self.playerHasSecondarySubtitleSupport(player)) return false; + if (!player) return false; const format = (track.Codec || '').toLowerCase(); // Currently, only non-SSA/non-ASS external subtitles are supported. // Showing secondary subtitles does not work with any SSA/ASS subtitle combinations because @@ -1578,8 +1578,9 @@ class PlaybackManager { player.setSubtitleStreamIndex(selectedTrackElementIndex); - // Also disable secondary subtitles when disabling the primary subtitles - if (selectedTrackElementIndex === -1) { + // Also disable secondary subtitles when disabling the primary + // subtitles, or if it doesn't support a secondary pair + if (selectedTrackElementIndex === -1 || !self.trackHasSecondarySubtitleSupport(newStream)) { self.setSecondarySubtitleStreamIndex(selectedTrackElementIndex); } @@ -1605,12 +1606,9 @@ class PlaybackManager { return; } - const clearingStream = currentStream && !newStream; - const changingStream = currentStream && newStream; - const addingStream = !currentStream && newStream; // Secondary subtitles are currently only handled client side // Changes to the server code are required before we can handle other delivery methods - if (!clearingStream && (changingStream || addingStream) && getDeliveryMethod(newStream) !== 'External') { + if (newStream && getDeliveryMethod(newStream) !== 'External') { return; } diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index 84e7a8d719..ccbc295987 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -1035,10 +1035,26 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components setTimeout(resetIdle, 0); } + /** + * Only show option if: + * - player has support + * - has more than 1 subtitle track + * - has valid secondary tracks + * - primary subtitle is not off + * - primary subtitle has support (index + 1 because `'Off'` is index 0 in `streams` array) + */ + function currentTrackCanHaveSecondarySubtitle(player, streams, currentIndex) { + const secondaryStreams = playbackManager.secondarySubtitleTracks(player); + return playbackManager.playerHasSecondarySubtitleSupport(player) && + streams.length > 1 && + secondaryStreams.length > 0 && + currentIndex !== -1 && + playbackManager.trackHasSecondarySubtitleSupport(streams[currentIndex + 1], player); + } + function showSubtitleTrackSelection() { const player = currentPlayer; const streams = playbackManager.subtitleTracks(player); - const secondaryStreams = playbackManager.secondarySubtitleTracks(player); let currentIndex = playbackManager.getSubtitleStreamIndex(player); if (currentIndex == null) { @@ -1062,21 +1078,7 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components return opt; }); - /** - * Only show option if: - * - player has support - * - has more than 1 subtitle track - * - has valid secondary tracks - * - primary subtitle is not off - * - primary subtitle is `External` - */ - if ( - playbackManager.playerHasSecondarySubtitleSupport(player) && - streams.length > 1 && - secondaryStreams.length > 0 && - currentIndex !== -1 && - playbackManager.isSubtitleStreamExternal(currentIndex, player) - ) { + if (currentTrackCanHaveSecondarySubtitle(player, streams, currentIndex)) { const secondarySubtitleMenuItem = { name: globalize.translate('SecondarySubtitles'), id: 'secondarysubtitle' diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index b8903ee326..a40b99a273 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -225,6 +225,14 @@ function tryRemoveElement(elem) { * @type {number | undefined} */ #currentTrackOffset; + /** + * @type {HTMLElement | null | undefined} + */ + #secondaryTrackOffset; + /** + * @type {number | null | undefined} + */ + #subtitleVerticalPosition; /** * @type {HTMLElement | null | undefined} */ @@ -539,6 +547,7 @@ function tryRemoveElement(elem) { resetSubtitleOffset() { this.#currentTrackOffset = 0; + this.#secondaryTrackOffset = 0; this.#showTrackOffset = false; } @@ -581,7 +590,7 @@ function tryRemoveElement(elem) { const trackElements = this.getTextTracks(); // if .vtt currently rendering if (trackElements.length > 0) { - trackElements.forEach(function (trackElement, index) { + trackElements.forEach((trackElement, index) => { this.setTextTrackSubtitleOffset(trackElement, offsetValue, index); }); } else if (this.#currentTrackEvents || this.#currentSecondaryTrackEvents) { @@ -596,24 +605,25 @@ function tryRemoveElement(elem) { /** * @private */ - updateCurrentTrackOffset(offsetValue, currentTrackIndex = 0) { - const skipRelativeOffset = currentTrackIndex !== PRIMARY_TEXT_TRACK_INDEX; + updateCurrentTrackOffset(offsetValue, currentTrackIndex = PRIMARY_TEXT_TRACK_INDEX) { + let offsetToCompare = this.#currentTrackOffset; + if (this.isSecondaryTrack(currentTrackIndex)) { + offsetToCompare = this.#secondaryTrackOffset; + } + let relativeOffset = offsetValue; const newTrackOffset = offsetValue; - if (this.#currentTrackOffset && !skipRelativeOffset) { - /** - * Only calculate the offset for the first track. - * The offset gets set after this method is first called. - * Subsequent method calls (when playing multiple tracks) - * will have the calculated relative offset cancel out - * and will be `0` - * @example - * first_call: (relativeOffset = -2) -= (this.#currentTrackOffset = -1) -> 1 - * second_call: (relativeOffset = -2) -= (this.#currentTrackOffset = -2) -> 0 - */ - relativeOffset -= this.#currentTrackOffset; + + if (offsetToCompare) { + relativeOffset -= offsetToCompare; } - this.#currentTrackOffset = newTrackOffset; + + if (this.isSecondaryTrack(currentTrackIndex)) { + this.#secondaryTrackOffset = newTrackOffset; + } else { + this.#currentTrackOffset = newTrackOffset; + } + // relative to currentTrackOffset return relativeOffset; } @@ -1132,6 +1142,7 @@ function tryRemoveElement(elem) { this.destroyNativeTracks(videoElement, targetTrackIndex); this.destroyStoredTrackInfo(targetTrackIndex); + this.#subtitleVerticalPosition = null; this.#currentClock = null; this._currentAspectRatio = null; @@ -1322,6 +1333,14 @@ function tryRemoveElement(elem) { * @private */ renderSubtitlesWithCustomElement(videoElement, track, item, targetTextTrackIndex) { + if (this.#subtitleVerticalPosition == null) { + import('../../scripts/settings/userSettings').then((userSettings) => { + const subtitleAppearance = userSettings.getSubtitleAppearanceSettings(); + this.#subtitleVerticalPosition = subtitleAppearance.verticalPosition; + this.#subtitleVerticalPosition = parseInt(subtitleAppearance.verticalPosition, 10); + }); + } + this.fetchSubtitles(track, item).then((data) => { if (!this.#videoSubtitlesElem && !this.isSecondaryTrack(targetTextTrackIndex)) { let subtitlesContainer = document.querySelector('.videoSubtitles'); @@ -1341,7 +1360,12 @@ function tryRemoveElement(elem) { if (!subtitlesContainer) return; const secondarySubtitlesElement = document.createElement('div'); secondarySubtitlesElement.classList.add('videoSecondarySubtitlesInner'); - subtitlesContainer.prepend(secondarySubtitlesElement); + // determine the order of the subtitles + if (this.#subtitleVerticalPosition < 0) { + subtitlesContainer.prepend(secondarySubtitlesElement); + } else { + subtitlesContainer.appendChild(secondarySubtitlesElement); + } this.#videoSecondarySubtitlesElem = secondarySubtitlesElement; this.setSubtitleAppearance(subtitlesContainer, this.#videoSecondarySubtitlesElem); this.#currentSecondaryTrackEvents = data.TrackEvents; diff --git a/src/plugins/htmlVideoPlayer/style.scss b/src/plugins/htmlVideoPlayer/style.scss index 54137685b7..21b2047392 100644 --- a/src/plugins/htmlVideoPlayer/style.scss +++ b/src/plugins/htmlVideoPlayer/style.scss @@ -80,6 +80,7 @@ video[controls]::-webkit-media-controls { margin: auto; display: block; min-height: 0 !important; + margin-top: 0.5em !important; margin-bottom: 0.5em !important; }