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 @@
+
\ 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;
});