diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 8502b551af..96268a51d9 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1112,6 +1112,52 @@ class PlaybackManager { } }; + self.increasePlaybackRate = function (player) { + player = player || self._currentPlayer; + if (player) { + let current = self.getPlaybackRate(player); + let supported = self.getSupportedPlaybackRates(player); + + let index = -1; + for (let i = 0, length = supported.length; i < length; i++) { + if (supported[i].id === current) { + index = i; + break; + } + } + + index = Math.min(index + 1, supported.length - 1); + self.setPlaybackRate(supported[index].id, player); + } + }; + + self.decreasePlaybackRate = function (player) { + player = player || self._currentPlayer; + if (player) { + let current = self.getPlaybackRate(player); + let supported = self.getSupportedPlaybackRates(player); + + let index = -1; + for (let i = 0, length = supported.length; i < length; i++) { + if (supported[i].id === current) { + index = i; + break; + } + } + + index = Math.max(index - 1, 0); + self.setPlaybackRate(supported[index].id, player); + } + }; + + self.getSupportedPlaybackRates = function (player) { + player = player || self._currentPlayer; + if (player && player.getSupportedPlaybackRates) { + return player.getSupportedPlaybackRates(); + } + return []; + }; + let brightnessOsdLoaded; self.setBrightness = function (val, player) { player = player || self._currentPlayer; @@ -3697,6 +3743,9 @@ class PlaybackManager { case 'SetAspectRatio': this.setAspectRatio(cmd.Arguments.AspectRatio, player); break; + case 'PlaybackRate': + this.setPlaybackRate(cmd.Arguments.PlaybackRate, player); + break; case 'SetBrightness': this.setBrightness(cmd.Arguments.Brightness, player); break; diff --git a/src/components/playback/playersettingsmenu.js b/src/components/playback/playersettingsmenu.js index 71dd7a86ff..cd227afcb4 100644 --- a/src/components/playback/playersettingsmenu.js +++ b/src/components/playback/playersettingsmenu.js @@ -149,6 +149,28 @@ function showAspectRatioMenu(player, btn) { }); } +function showPlaybackRateMenu(player, btn) { + // each has a name and id + const currentId = playbackManager.getPlaybackRate(player); + const menuItems = playbackManager.getSupportedPlaybackRates(player).map(i => ({ + id: i.id, + name: i.name, + selected: i.id === currentId + })); + + return actionsheet.show({ + items: menuItems, + positionTo: btn + }).then(function (id) { + if (id) { + playbackManager.setPlaybackRate(id, player); + return Promise.resolve(); + } + + return Promise.reject(); + }); +} + function showWithUser(options, player, user) { var supportedCommands = playbackManager.getSupportedCommands(player); @@ -166,6 +188,17 @@ function showWithUser(options, player, user) { }); } + if (supportedCommands.indexOf('PlaybackRate') !== -1) { + const currentPlaybackRateId = playbackManager.getPlaybackRate(player); + const currentPlaybackRate = playbackManager.getSupportedPlaybackRates(player).filter(i => i.id === currentPlaybackRateId)[0]; + + menuItems.push({ + name: globalize.translate('PlaybackRate'), + id: 'playbackrate', + asideText: currentPlaybackRate ? currentPlaybackRate.name : null + }); + } + if (user && user.Policy.EnableVideoPlaybackTranscoding) { var secondaryQualityText = getQualitySecondaryText(player); @@ -230,6 +263,8 @@ function handleSelectedOption(id, options, player) { return showQualityMenu(player, options.positionTo); case 'aspectratio': return showAspectRatioMenu(player, options.positionTo); + case 'playbackrate': + return showPlaybackRateMenu(player, options.positionTo); case 'repeatmode': return showRepeatModeMenu(player, options.positionTo); case 'stats': diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index 73540cd636..ea84b9c3f5 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -1243,6 +1243,12 @@ import 'css!assets/css/videoosd'; } break; } + case '>': + playbackManager.increasePlaybackRate(currentPlayer); + break; + case '<': + playbackManager.decreasePlaybackRate(currentPlayer); + break; } } diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index ba497729bb..33f15a741f 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -1634,6 +1634,31 @@ function tryRemoveElement(elem) { return null; } + getSupportedPlaybackRates() { + return [{ + name: '0.5x', + id: 0.5 + }, { + name: '0.75x', + id: 0.75 + }, { + name: '1x', + id: 1.0 + }, { + name: '1.25x', + id: 1.25 + }, { + name: '1.5x', + id: 1.5 + }, { + name: '1.75x', + id: 1.75 + }, { + name: '2x', + id: 2.0 + }]; + } + setVolume(val) { const mediaElement = this.#mediaElement; if (mediaElement) { diff --git a/src/scripts/inputManager.js b/src/scripts/inputManager.js index 077af39bf7..baa3deb0aa 100644 --- a/src/scripts/inputManager.js +++ b/src/scripts/inputManager.js @@ -185,6 +185,12 @@ import appHost from 'apphost'; 'changezoom': () => { playbackManager.toggleAspectRatio(); }, + 'increaseplaybackrate': () => { + playbackManager.increasePlaybackRate(); + }, + 'decreaseplaybackrate': () => { + playbackManager.decreasePlaybackRate(); + }, 'changeaudiotrack': () => { playbackManager.changeAudioStream(); }, diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 0f37014b76..38b79613e2 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -1220,6 +1220,7 @@ "Play": "Play", "PlayAllFromHere": "Play all from here", "PlaybackData": "Playback Data", + "PlaybackRate": "Playback Rate", "PlayCount": "Play count", "PlayFromBeginning": "Play from beginning", "PlayNext": "Play next",