From 91241ceea1cf156b4ee4398c5b24507b0ff579f7 Mon Sep 17 00:00:00 2001 From: redSpoutnik <15638041+redSpoutnik@users.noreply.github.com> Date: Sat, 30 Mar 2019 22:11:39 +0100 Subject: [PATCH 1/5] Add vtt and ass subtitle-offset in videoplayer --- src/components/htmlvideoplayer/plugin.js | 66 ++++++++++++++++++++++ src/components/playback/playbackmanager.js | 22 ++++++++ src/controllers/videoosd.js | 55 ++++++++++++++++++ src/css/videoosd.css | 7 +++ src/videoosd.html | 7 +++ 5 files changed, 157 insertions(+) diff --git a/src/components/htmlvideoplayer/plugin.js b/src/components/htmlvideoplayer/plugin.js index d25b49163..ca9303426 100644 --- a/src/components/htmlvideoplayer/plugin.js +++ b/src/components/htmlvideoplayer/plugin.js @@ -188,6 +188,8 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa var currentAssRenderer; var customTrackIndex = -1; + var currentTrackOffset; + var videoSubtitlesElem; var currentTrackEvents; @@ -543,6 +545,65 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa setCurrentTrackElement(index); }; + self.setSubtitleOffset = function(offset) { + + var offsetValue = parseFloat(offset); + var videoElement = self._mediaElement; + var mediaStreamTextTracks = getMediaStreamTextTracks(self._currentPlayOptions.mediaSource); + + Array.from(videoElement.textTracks) + .filter(trackElement => { + if (customTrackIndex === -1 ) { + // get showing .vtt textTacks + return trackElement.mode === 'showing'; + } else { + // get current .ass textTrack + return ("textTrack" + customTrackIndex) === trackElement.id; + } + }) + .forEach(trackElement => { + + var track = mediaStreamTextTracks.filter(stream => { + return ("textTrack" + stream.Index) === trackElement.id; + })[0]; + + if(track) { + offsetValue = updateCurrentTrackOffset(offsetValue); + var format = (track.Codec || '').toLowerCase(); + if (format !== 'ass' && format !== 'ssa') { + setVttSubtitleOffset(trackElement, offsetValue); + } + } else { + console.log("No available track, cannot apply offset : " + offsetValue); + } + + }); + }; + + function updateCurrentTrackOffset(offsetValue) { + + var relativeOffset = offsetValue; + var newTrackOffset = offsetValue; + if(currentTrackOffset){ + relativeOffset -= currentTrackOffset; + } + currentTrackOffset = newTrackOffset; + // relative to currentTrackOffset + return relativeOffset; + } + + function setVttSubtitleOffset(currentTrack, offsetValue) { + + if(currentTrack.cues) { + Array.from(currentTrack.cues) + .forEach(cue => { + cue.startTime -= offsetValue; + cue.endTime -= offsetValue; + }); + } + + } + function isAudioStreamSupported(stream, deviceProfile) { var codec = (stream.Codec || '').toLowerCase(); @@ -1167,6 +1228,11 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa function updateSubtitleText(timeMs) { + // handle offset for ass tracks + if(currentTrackOffset) { + timeMs += (currentTrackOffset * 1000); + } + var clock = currentClock; if (clock) { try { diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 33b0b2b79..1588be5d2 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1635,6 +1635,28 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla getPlayerData(player).subtitleStreamIndex = index; }; + self.supportSubtitleOffset = function(player) { + player = player || self._currentPlayer; + return 'setSubtitleOffset' in player; + } + + self.isSubtitleStreamExternal = function(index, player) { + var stream = getSubtitleStream(player, index); + return stream ? getDeliveryMethod(stream) === 'External' : false; + } + + self.setSubtitleOffset = function (sliderValue, player) { + player = player || self._currentPlayer; + player.setSubtitleOffset(self.getOffsetFromSliderValue(sliderValue)); + }; + + self.getOffsetFromSliderValue = function(value) { + var offset = (value - 50) / 50; + // multiply by offset min/max range value (-x to +x) : + offset *= 30; + return offset.toFixed(1); + }; + self.seek = function (ticks, player) { ticks = Math.max(0, ticks); diff --git a/src/controllers/videoosd.js b/src/controllers/videoosd.js index c9befe03c..00ce862f2 100644 --- a/src/controllers/videoosd.js +++ b/src/controllers/videoosd.js @@ -280,6 +280,7 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med btnFastForward.disabled = true; btnRewind.disabled = true; view.querySelector(".btnSubtitles").classList.add("hide"); + view.querySelector(".subtitleSyncSliderContainer").classList.add("hide"); view.querySelector(".btnAudio").classList.add("hide"); view.querySelector(".osdTitle").innerHTML = ""; view.querySelector(".osdMediaInfo").innerHTML = ""; @@ -295,8 +296,23 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med if (playbackManager.subtitleTracks(player).length) { view.querySelector(".btnSubtitles").classList.remove("hide"); + + if(playbackManager.supportSubtitleOffset()) { + var index = playbackManager.getSubtitleStreamIndex(player); + // if there is an external subtitle stream enabled + if(index !== -1 && playbackManager.isSubtitleStreamExternal(index, player)){ + // show subtitle sync slider + subtitleSyncSliderContainer.classList.remove("hide"); + }else{ + // hide subtitle sync slider + subtitleSyncSliderContainer.classList.add("hide"); + } + } + } else { view.querySelector(".btnSubtitles").classList.add("hide"); + // hide subtitle sync slider + subtitleSyncSliderContainer.classList.add("hide"); } if (playbackManager.audioTracks(player).length > 1) { @@ -1008,6 +1024,28 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med if (index !== currentIndex) { playbackManager.setSubtitleStreamIndex(index, player); } + return id; + + }).then(function (id) { + var index = parseInt(id); + // on subtitle stream change + if (playbackManager.supportSubtitleOffset() && index !== currentIndex) { + + /// if there is an external subtitle stream enabled + if (index !== -1 && playbackManager.isSubtitleStreamExternal(index, player)){ + + // set default offset to '0' (slider's middle value) + var subtitleSyncSliderMiddleValue = 50; + subtitleSyncSlider.value = subtitleSyncSliderMiddleValue.toString(); + playbackManager.setSubtitleOffset(subtitleSyncSliderMiddleValue, player); + + // show subtitle sync slider + subtitleSyncSliderContainer.classList.remove("hide"); + } else { + // hide subtitle sync slider + subtitleSyncSliderContainer.classList.add("hide"); + } + } }); }); } @@ -1146,6 +1184,8 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med var programStartDateMs = 0; var programEndDateMs = 0; var playbackStartTimeTicks = 0; + var subtitleSyncSlider = view.querySelector(".subtitleSyncSlider"); + var subtitleSyncSliderContainer = view.querySelector(".subtitleSyncSliderContainer"); var nowPlayingVolumeSlider = view.querySelector(".osdVolumeSlider"); var nowPlayingVolumeSliderContainer = view.querySelector(".osdVolumeSliderContainer"); var nowPlayingPositionSlider = view.querySelector(".osdPositionSlider"); @@ -1268,6 +1308,21 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med nowPlayingVolumeSlider.addEventListener("touchmove", function () { playbackManager.setVolume(this.value, currentPlayer); }); + + subtitleSyncSlider.addEventListener("change", function () { + playbackManager.setSubtitleOffset(this.value, currentPlayer); + }); + subtitleSyncSlider.addEventListener("touchmove", function () { + playbackManager.setSubtitleOffset(this.value, currentPlayer); + }); + + subtitleSyncSlider.getBubbleHtml = function (value) { + var newOffset = playbackManager.getOffsetFromSliderValue(value); + return '

' + + (newOffset > 0 ? "+" : "") + parseFloat(newOffset) + "s" + + "

"; + }; + nowPlayingPositionSlider.addEventListener("change", function () { var player = currentPlayer; diff --git a/src/css/videoosd.css b/src/css/videoosd.css index bd24e4130..5151f87d6 100644 --- a/src/css/videoosd.css +++ b/src/css/videoosd.css @@ -144,6 +144,13 @@ flex-grow: 1 } +.subtitleSyncSliderContainer { + width: 12em; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1 +} + .osdMediaInfo, .volumeButtons { display: -webkit-box; diff --git a/src/videoosd.html b/src/videoosd.html index e70adbe39..d5c117a4d 100644 --- a/src/videoosd.html +++ b/src/videoosd.html @@ -59,6 +59,13 @@ + +
+
+ +
+
+ From b3716dc20b3bf8077df37a5e7c3074fd27434f4f Mon Sep 17 00:00:00 2001 From: redSpoutnik <15638041+redSpoutnik@users.noreply.github.com> Date: Sat, 30 Mar 2019 22:29:45 +0100 Subject: [PATCH 2/5] add redSpoutnik to CONTRIBUTORS --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index bbdb64f7a..2b7a71134 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -20,6 +20,7 @@ - [TtheCreator](https://github.com/Tthecreator) - [RazeLighter777](https://github.com/RazeLighter777) - [LogicalPhallacy](https://github.com/LogicalPhallacy) + - [redSpoutnik](https://github.com/redSpoutnik) # Emby Contributors From 275fd078e2776a167bc28d14d98f3a9b16c83f31 Mon Sep 17 00:00:00 2001 From: redSpoutnik <15638041+redSpoutnik@users.noreply.github.com> Date: Mon, 8 Apr 2019 20:21:16 +0200 Subject: [PATCH 3/5] add showingSubtitle control --- src/components/htmlvideoplayer/plugin.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/components/htmlvideoplayer/plugin.js b/src/components/htmlvideoplayer/plugin.js index ca9303426..ca132ce15 100644 --- a/src/components/htmlvideoplayer/plugin.js +++ b/src/components/htmlvideoplayer/plugin.js @@ -188,6 +188,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa var currentAssRenderer; var customTrackIndex = -1; + var showTrackOffset = false; var currentTrackOffset; var videoSubtitlesElem; @@ -545,6 +546,18 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa setCurrentTrackElement(index); }; + self.enableShowingSubtitleOffset = function() { + showTrackOffset = true; + } + + self.disableShowingSubtitleOffset = function() { + showTrackOffset = false; + } + + self.isShowingSubtitleOffsetEnabled = function() { + return showTrackOffset; + } + self.setSubtitleOffset = function(offset) { var offsetValue = parseFloat(offset); @@ -552,7 +565,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa var mediaStreamTextTracks = getMediaStreamTextTracks(self._currentPlayOptions.mediaSource); Array.from(videoElement.textTracks) - .filter(trackElement => { + .filter((trackElement) => { if (customTrackIndex === -1 ) { // get showing .vtt textTacks return trackElement.mode === 'showing'; @@ -563,7 +576,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa }) .forEach(trackElement => { - var track = mediaStreamTextTracks.filter(stream => { + var track = mediaStreamTextTracks.filter((stream) => { return ("textTrack" + stream.Index) === trackElement.id; })[0]; @@ -596,7 +609,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa if(currentTrack.cues) { Array.from(currentTrack.cues) - .forEach(cue => { + .forEach((cue) => { cue.startTime -= offsetValue; cue.endTime -= offsetValue; }); @@ -604,6 +617,10 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa } + self.getSubtitleOffset = function() { + return currentTrackOffset; + } + function isAudioStreamSupported(stream, deviceProfile) { var codec = (stream.Codec || '').toLowerCase(); From 415ec9e91b822bf84b7125840ed88a608806285f Mon Sep 17 00:00:00 2001 From: redSpoutnik <15638041+redSpoutnik@users.noreply.github.com> Date: Mon, 8 Apr 2019 20:31:18 +0200 Subject: [PATCH 4/5] add subtitleSync overlay in separated folder --- src/components/playback/playbackmanager.js | 36 +++- src/components/playback/playersettingsmenu.js | 14 ++ src/components/subtitlesync/subtitlesync.css | 48 ++++++ src/components/subtitlesync/subtitlesync.js | 163 ++++++++++++++++++ .../subtitlesync/subtitlesync.template.html | 7 + src/controllers/videoosd.js | 91 ++++------ src/css/videoosd.css | 7 - src/scripts/site.js | 1 + src/videoosd.html | 8 +- 9 files changed, 299 insertions(+), 76 deletions(-) create mode 100644 src/components/subtitlesync/subtitlesync.css create mode 100644 src/components/subtitlesync/subtitlesync.js create mode 100644 src/components/subtitlesync/subtitlesync.template.html diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 1588be5d2..79037e773 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1637,7 +1637,22 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla self.supportSubtitleOffset = function(player) { player = player || self._currentPlayer; - return 'setSubtitleOffset' in player; + return player && 'setSubtitleOffset' in player; + } + + self.enableShowingSubtitleOffset = function(player) { + player = player || self._currentPlayer; + player.enableShowingSubtitleOffset(); + } + + self.disableShowingSubtitleOffset = function(player) { + player = player || self._currentPlayer; + player.disableShowingSubtitleOffset(); + } + + self.isShowingSubtitleOffsetEnabled = function(player) { + player = player || self._currentPlayer; + return player.isShowingSubtitleOffsetEnabled(); } self.isSubtitleStreamExternal = function(index, player) { @@ -1645,17 +1660,20 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return stream ? getDeliveryMethod(stream) === 'External' : false; } - self.setSubtitleOffset = function (sliderValue, player) { + self.setSubtitleOffset = function (value, player) { player = player || self._currentPlayer; - player.setSubtitleOffset(self.getOffsetFromSliderValue(sliderValue)); + player.setSubtitleOffset(value); }; - self.getOffsetFromSliderValue = function(value) { - var offset = (value - 50) / 50; - // multiply by offset min/max range value (-x to +x) : - offset *= 30; - return offset.toFixed(1); - }; + self.getPlayerSubtitleOffset = function(player) { + player = player || self._currentPlayer; + return player.getSubtitleOffset(); + } + + self.canHandleOffsetOnCurrentSubtitle = function(player) { + var index = self.getSubtitleStreamIndex(player); + return index !== -1 && self.isSubtitleStreamExternal(index, player); + } self.seek = function (ticks, player) { diff --git a/src/components/playback/playersettingsmenu.js b/src/components/playback/playersettingsmenu.js index b51027fe0..369245211 100644 --- a/src/components/playback/playersettingsmenu.js +++ b/src/components/playback/playersettingsmenu.js @@ -231,6 +231,15 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob }); } + if (options.suboffset) { + + menuItems.push({ + name: globalize.translate('SubtitleOffset'), + id: 'suboffset', + asideText: null + }); + } + menuItems.push({ name: globalize.translate('SubtitleSettings'), id: 'subtitlesettings' @@ -302,6 +311,11 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob options.onOption('stats'); } return Promise.resolve(); + case 'suboffset': + if (options.onOption) { + options.onOption('suboffset'); + } + return Promise.resolve(); default: break; } diff --git a/src/components/subtitlesync/subtitlesync.css b/src/components/subtitlesync/subtitlesync.css new file mode 100644 index 000000000..112e62472 --- /dev/null +++ b/src/components/subtitlesync/subtitlesync.css @@ -0,0 +1,48 @@ +.subtitleSyncContainer { + width: 40%; + margin-left: 30%; + margin-right: 30%; + height: 4.2em; + background: rgba(28,28,28,0.8); + border-radius: .3em; + color: #fff; + position: absolute; +} + +.subtitleSync-closeButton { + position: absolute; + top: 0; + right: 0; + color: #ccc; + z-index: 2; +} + +.subtitleSyncTextField { + position: absolute; + left: 0; + width: 40%; + margin-left: 30%; + margin-right: 30%; + top: 0.1em; + text-align: center; + font-size: 20px; + color: white; + z-index: 2; +} + +#prompt { + flex-shrink: 0; +} + +.subtitleSyncSliderContainer { + width: 98%; + margin-left: 1%; + margin-right: 1%; + top: 2.5em; + height: 1.4em; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + border-radius: .3em; + z-index: 1; +} \ No newline at end of file diff --git a/src/components/subtitlesync/subtitlesync.js b/src/components/subtitlesync/subtitlesync.js new file mode 100644 index 000000000..3389b7bf8 --- /dev/null +++ b/src/components/subtitlesync/subtitlesync.js @@ -0,0 +1,163 @@ +define(['playbackManager', 'text!./subtitlesync.template.html', 'css!./subtitlesync'], function (playbackManager, template, css) { + "use strict"; + + var player; + var subtitleSyncSlider; + var subtitleSyncTextField; + var subtitleSyncCloseButton; + var subtitleSyncContainer; + + function init(instance) { + + var parent = document.createElement('div'); + parent.innerHTML = template; + + subtitleSyncSlider = parent.querySelector(".subtitleSyncSlider"); + subtitleSyncTextField = parent.querySelector(".subtitleSyncTextField"); + subtitleSyncCloseButton = parent.querySelector(".subtitleSync-closeButton"); + subtitleSyncContainer = parent.querySelector(".subtitleSyncContainer"); + + subtitleSyncContainer.classList.add("hide"); + + subtitleSyncTextField.updateOffset = function(offset) { + this.textContent = offset + "s"; + } + + subtitleSyncTextField.addEventListener("keypress", function(event) { + + if(event.key === "Enter"){ + // if input key is enter search for float pattern + var inputOffset = /[-+]?\d+\.?\d*/g.exec(this.textContent); + if(inputOffset) { + inputOffset = inputOffset[0]; + + // replace current text by considered offset + this.textContent = inputOffset + "s"; + + inputOffset = parseFloat(inputOffset); + // set new offset + playbackManager.setSubtitleOffset(inputOffset, player); + // synchronize with slider value + subtitleSyncSlider.updateOffset( + getPercentageFromOffset(inputOffset)); + } else { + this.textContent = (playbackManager.getPlayerSubtitleOffset(player) || 0) + "s"; + } + this.hasFocus = false; + event.preventDefault(); + } else { + // keep focus to prevent fade with bottom layout + this.hasFocus = true; + if(event.key.match(/[+-\d.s]/) === null) { + event.preventDefault(); + } + } + }); + + subtitleSyncSlider.updateOffset = function(percent) { + // default value is 0s = 50% + this.value = percent === undefined ? 50 : percent; + } + + subtitleSyncSlider.addEventListener("change", function () { + // set new offset + playbackManager.setSubtitleOffset(getOffsetFromPercentage(this.value), player); + // synchronize with textField value + subtitleSyncTextField.updateOffset( + getOffsetFromPercentage(this.value)); + }); + + subtitleSyncSlider.addEventListener("touchmove", function () { + // set new offset + playbackManager.setSubtitleOffset(getOffsetFromPercentage(this.value), player); + // synchronize with textField value + subtitleSyncTextField.updateOffset( + getOffsetFromPercentage(this.value)); + }); + + subtitleSyncSlider.getBubbleHtml = function (value) { + var newOffset = getOffsetFromPercentage(value); + return '

' + + (newOffset > 0 ? "+" : "") + parseFloat(newOffset) + "s" + + "

"; + }; + + subtitleSyncCloseButton.addEventListener("click", function() { + playbackManager.disableShowingSubtitleOffset(player); + SubtitleSync.prototype.toggle("forceToHide"); + }); + + document.body.appendChild(parent); + + instance.element = parent; + } + + + function getOffsetFromPercentage(value) { + // convert percent to fraction + var offset = (value - 50) / 50; + // multiply by offset min/max range value (-x to +x) : + offset *= 30; + return offset.toFixed(1); + }; + + function getPercentageFromOffset(value) { + // divide by offset min/max range value (-x to +x) : + var percentValue = value / 30; + // convert fraction to percent + percentValue *= 50; + percentValue += 50; + return Math.min(100, Math.max(0, percentValue.toFixed())); + }; + + function SubtitleSync(currentPlayer) { + player = currentPlayer; + init(this); + } + + SubtitleSync.prototype.destroy = function(){ + SubtitleSync.prototype.toggle("forceToHide"); + if(player){ + playbackManager.disableShowingSubtitleOffset(player); + playbackManager.setSubtitleOffset(0, player); + } + var elem = this.element; + if (elem) { + elem.parentNode.removeChild(elem); + this.element = null; + } + } + + SubtitleSync.prototype.toggle = function(action) { + + if(player && playbackManager.supportSubtitleOffset(player)){ + + switch(action) { + case undefined: + // if showing subtitle sync is enabled + if(playbackManager.isShowingSubtitleOffsetEnabled(player) && + // if there is an external subtitle stream enabled + playbackManager.canHandleOffsetOnCurrentSubtitle(player)){ + // if no subtitle offset is defined + if(!playbackManager.getPlayerSubtitleOffset(player)) { + // set default offset to '0' = 50% + subtitleSyncSlider.value = "50"; + subtitleSyncTextField.textContent = "0s"; + playbackManager.setSubtitleOffset(0, player); + } + // show subtitle sync + subtitleSyncContainer.classList.remove("hide"); + break; // stop here + } // else continue and hide + case "hide": + if(subtitleSyncTextField.hasFocus){break;} // else continue and hide + case "forceToHide": + subtitleSyncContainer.classList.add("hide"); + break; + } + + } + } + + return SubtitleSync; +}); diff --git a/src/components/subtitlesync/subtitlesync.template.html b/src/components/subtitlesync/subtitlesync.template.html new file mode 100644 index 000000000..4ee344333 --- /dev/null +++ b/src/components/subtitlesync/subtitlesync.template.html @@ -0,0 +1,7 @@ +
+ +
0s
+
+ +
+
\ No newline at end of file diff --git a/src/controllers/videoosd.js b/src/controllers/videoosd.js index 00ce862f2..68c0024f7 100644 --- a/src/controllers/videoosd.js +++ b/src/controllers/videoosd.js @@ -280,7 +280,6 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med btnFastForward.disabled = true; btnRewind.disabled = true; view.querySelector(".btnSubtitles").classList.add("hide"); - view.querySelector(".subtitleSyncSliderContainer").classList.add("hide"); view.querySelector(".btnAudio").classList.add("hide"); view.querySelector(".osdTitle").innerHTML = ""; view.querySelector(".osdMediaInfo").innerHTML = ""; @@ -296,23 +295,10 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med if (playbackManager.subtitleTracks(player).length) { view.querySelector(".btnSubtitles").classList.remove("hide"); - - if(playbackManager.supportSubtitleOffset()) { - var index = playbackManager.getSubtitleStreamIndex(player); - // if there is an external subtitle stream enabled - if(index !== -1 && playbackManager.isSubtitleStreamExternal(index, player)){ - // show subtitle sync slider - subtitleSyncSliderContainer.classList.remove("hide"); - }else{ - // hide subtitle sync slider - subtitleSyncSliderContainer.classList.add("hide"); - } - } - + toggleSubtitleSync(); } else { view.querySelector(".btnSubtitles").classList.add("hide"); - // hide subtitle sync slider - subtitleSyncSliderContainer.classList.add("hide"); + toggleSubtitleSync("forceToHide"); } if (playbackManager.audioTracks(player).length > 1) { @@ -435,6 +421,7 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med focusManager.focus(elem.querySelector(".btnPause")); }, 50); } + toggleSubtitleSync(); } } @@ -447,6 +434,7 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med once: true }); currentVisibleMenu = null; + toggleSubtitleSync("hide"); } } @@ -638,6 +626,7 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med function releaseCurrentPlayer() { destroyStats(); + destroySubtitleSync(); resetUpNextDialog(); var player = currentPlayer; @@ -913,11 +902,17 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med var player = currentPlayer; if (player) { + + // show subtitle offset feature only if player and media support it + var showSubOffset = playbackManager.supportSubtitleOffset(player) && + playbackManager.canHandleOffsetOnCurrentSubtitle(player); + playerSettingsMenu.show({ mediaType: "Video", player: player, positionTo: btn, stats: true, + suboffset: showSubOffset, onOption: onSettingsOption }); } @@ -927,6 +922,12 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med function onSettingsOption(selectedOption) { if ("stats" === selectedOption) { toggleStats(); + } else if ("suboffset" === selectedOption) { + var player = currentPlayer; + if (player) { + playbackManager.enableShowingSubtitleOffset(player); + toggleSubtitleSync(); + } } } @@ -1024,32 +1025,30 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med if (index !== currentIndex) { playbackManager.setSubtitleStreamIndex(index, player); } - return id; - }).then(function (id) { - var index = parseInt(id); - // on subtitle stream change - if (playbackManager.supportSubtitleOffset() && index !== currentIndex) { - - /// if there is an external subtitle stream enabled - if (index !== -1 && playbackManager.isSubtitleStreamExternal(index, player)){ - - // set default offset to '0' (slider's middle value) - var subtitleSyncSliderMiddleValue = 50; - subtitleSyncSlider.value = subtitleSyncSliderMiddleValue.toString(); - playbackManager.setSubtitleOffset(subtitleSyncSliderMiddleValue, player); - - // show subtitle sync slider - subtitleSyncSliderContainer.classList.remove("hide"); - } else { - // hide subtitle sync slider - subtitleSyncSliderContainer.classList.add("hide"); - } - } + toggleSubtitleSync(); }); }); } + function toggleSubtitleSync(action) { + require(["subtitleSync"], function (SubtitleSync) { + var player = currentPlayer; + if (subtitleSyncOverlay) { + subtitleSyncOverlay.toggle(action); + } else if(player){ + subtitleSyncOverlay = new SubtitleSync(player); + } + }); + } + + function destroySubtitleSync() { + if (subtitleSyncOverlay) { + subtitleSyncOverlay.destroy(); + subtitleSyncOverlay = null; + } + } + function onWindowKeyDown(e) { if (!currentVisibleMenu && (32 === e.keyCode || 13 === e.keyCode)) { playbackManager.playPause(currentPlayer); @@ -1184,8 +1183,7 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med var programStartDateMs = 0; var programEndDateMs = 0; var playbackStartTimeTicks = 0; - var subtitleSyncSlider = view.querySelector(".subtitleSyncSlider"); - var subtitleSyncSliderContainer = view.querySelector(".subtitleSyncSliderContainer"); + var subtitleSyncOverlay; var nowPlayingVolumeSlider = view.querySelector(".osdVolumeSlider"); var nowPlayingVolumeSliderContainer = view.querySelector(".osdVolumeSliderContainer"); var nowPlayingPositionSlider = view.querySelector(".osdPositionSlider"); @@ -1257,6 +1255,7 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med } destroyStats(); + destroySubtitleSync(); }); var lastPointerDown = 0; dom.addEventListener(view, window.PointerEvent ? "pointerdown" : "click", function (e) { @@ -1309,20 +1308,6 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med playbackManager.setVolume(this.value, currentPlayer); }); - subtitleSyncSlider.addEventListener("change", function () { - playbackManager.setSubtitleOffset(this.value, currentPlayer); - }); - subtitleSyncSlider.addEventListener("touchmove", function () { - playbackManager.setSubtitleOffset(this.value, currentPlayer); - }); - - subtitleSyncSlider.getBubbleHtml = function (value) { - var newOffset = playbackManager.getOffsetFromSliderValue(value); - return '

' + - (newOffset > 0 ? "+" : "") + parseFloat(newOffset) + "s" + - "

"; - }; - nowPlayingPositionSlider.addEventListener("change", function () { var player = currentPlayer; diff --git a/src/css/videoosd.css b/src/css/videoosd.css index 5151f87d6..bd24e4130 100644 --- a/src/css/videoosd.css +++ b/src/css/videoosd.css @@ -144,13 +144,6 @@ flex-grow: 1 } -.subtitleSyncSliderContainer { - width: 12em; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - flex-grow: 1 -} - .osdMediaInfo, .volumeButtons { display: -webkit-box; diff --git a/src/scripts/site.js b/src/scripts/site.js index f984f20eb..6471343ed 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -758,6 +758,7 @@ var AppInfo = {}; define("recordingButton", [componentsPath + "/recordingcreator/recordingbutton"], returnFirstDependency); define("recordingHelper", [componentsPath + "/recordingcreator/recordinghelper"], returnFirstDependency); define("subtitleEditor", [componentsPath + "/subtitleeditor/subtitleeditor"], returnFirstDependency); + define("subtitleSync", [componentsPath + "/subtitlesync/subtitlesync"], returnFirstDependency); define("itemIdentifier", [componentsPath + "/itemidentifier/itemidentifier"], returnFirstDependency); define("mediaInfo", [componentsPath + "/mediainfo/mediainfo"], returnFirstDependency); define("itemContextMenu", [componentsPath + "/itemcontextmenu"], returnFirstDependency); diff --git a/src/videoosd.html b/src/videoosd.html index d5c117a4d..72b93aa83 100644 --- a/src/videoosd.html +++ b/src/videoosd.html @@ -1,4 +1,4 @@ -
+
@@ -60,12 +60,6 @@ -
-
- -
-
- From 0a59b836c036866cfe77f46e8016bfa6e7455e31 Mon Sep 17 00:00:00 2001 From: redSpoutnik <15638041+redSpoutnik@users.noreply.github.com> Date: Sat, 13 Apr 2019 09:17:03 +0200 Subject: [PATCH 5/5] replace arrow functions by function expresions --- src/components/htmlvideoplayer/plugin.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/htmlvideoplayer/plugin.js b/src/components/htmlvideoplayer/plugin.js index ca132ce15..7d5fcaeda 100644 --- a/src/components/htmlvideoplayer/plugin.js +++ b/src/components/htmlvideoplayer/plugin.js @@ -565,7 +565,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa var mediaStreamTextTracks = getMediaStreamTextTracks(self._currentPlayOptions.mediaSource); Array.from(videoElement.textTracks) - .filter((trackElement) => { + .filter(function(trackElement) { if (customTrackIndex === -1 ) { // get showing .vtt textTacks return trackElement.mode === 'showing'; @@ -574,9 +574,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa return ("textTrack" + customTrackIndex) === trackElement.id; } }) - .forEach(trackElement => { + .forEach(function(trackElement) { - var track = mediaStreamTextTracks.filter((stream) => { + var track = mediaStreamTextTracks.filter(function(stream) { return ("textTrack" + stream.Index) === trackElement.id; })[0]; @@ -609,7 +609,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa if(currentTrack.cues) { Array.from(currentTrack.cues) - .forEach((cue) => { + .forEach(function(cue) { cue.startTime -= offsetValue; cue.endTime -= offsetValue; });