mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Support for faster playback rates.
The HTML5 video element already has a well-supported "playbackRate" attribute which can be used to increase playback rate. This change wires up that control to be displayed in the Jellyfish web player. The playback rates offered are between 0.5x and 2x in 0.25x increments, which matches the YouTube player. This change also wires up the ">" and "<" key events to increase and decrease the playback rate, which mirrors the keyboard shortcuts supported by YouTube.
This commit is contained in:
parent
dc682bce17
commit
afa56c18af
6 changed files with 122 additions and 0 deletions
|
@ -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;
|
let brightnessOsdLoaded;
|
||||||
self.setBrightness = function (val, player) {
|
self.setBrightness = function (val, player) {
|
||||||
player = player || self._currentPlayer;
|
player = player || self._currentPlayer;
|
||||||
|
@ -3697,6 +3743,9 @@ class PlaybackManager {
|
||||||
case 'SetAspectRatio':
|
case 'SetAspectRatio':
|
||||||
this.setAspectRatio(cmd.Arguments.AspectRatio, player);
|
this.setAspectRatio(cmd.Arguments.AspectRatio, player);
|
||||||
break;
|
break;
|
||||||
|
case 'PlaybackRate':
|
||||||
|
this.setPlaybackRate(cmd.Arguments.PlaybackRate, player);
|
||||||
|
break;
|
||||||
case 'SetBrightness':
|
case 'SetBrightness':
|
||||||
this.setBrightness(cmd.Arguments.Brightness, player);
|
this.setBrightness(cmd.Arguments.Brightness, player);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -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) {
|
function showWithUser(options, player, user) {
|
||||||
var supportedCommands = playbackManager.getSupportedCommands(player);
|
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) {
|
if (user && user.Policy.EnableVideoPlaybackTranscoding) {
|
||||||
var secondaryQualityText = getQualitySecondaryText(player);
|
var secondaryQualityText = getQualitySecondaryText(player);
|
||||||
|
|
||||||
|
@ -230,6 +263,8 @@ function handleSelectedOption(id, options, player) {
|
||||||
return showQualityMenu(player, options.positionTo);
|
return showQualityMenu(player, options.positionTo);
|
||||||
case 'aspectratio':
|
case 'aspectratio':
|
||||||
return showAspectRatioMenu(player, options.positionTo);
|
return showAspectRatioMenu(player, options.positionTo);
|
||||||
|
case 'playbackrate':
|
||||||
|
return showPlaybackRateMenu(player, options.positionTo);
|
||||||
case 'repeatmode':
|
case 'repeatmode':
|
||||||
return showRepeatModeMenu(player, options.positionTo);
|
return showRepeatModeMenu(player, options.positionTo);
|
||||||
case 'stats':
|
case 'stats':
|
||||||
|
|
|
@ -1243,6 +1243,12 @@ import 'css!assets/css/videoosd';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case '>':
|
||||||
|
playbackManager.increasePlaybackRate(currentPlayer);
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
playbackManager.decreasePlaybackRate(currentPlayer);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1634,6 +1634,31 @@ function tryRemoveElement(elem) {
|
||||||
return null;
|
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) {
|
setVolume(val) {
|
||||||
const mediaElement = this.#mediaElement;
|
const mediaElement = this.#mediaElement;
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
|
|
|
@ -185,6 +185,12 @@ import appHost from 'apphost';
|
||||||
'changezoom': () => {
|
'changezoom': () => {
|
||||||
playbackManager.toggleAspectRatio();
|
playbackManager.toggleAspectRatio();
|
||||||
},
|
},
|
||||||
|
'increaseplaybackrate': () => {
|
||||||
|
playbackManager.increasePlaybackRate();
|
||||||
|
},
|
||||||
|
'decreaseplaybackrate': () => {
|
||||||
|
playbackManager.decreasePlaybackRate();
|
||||||
|
},
|
||||||
'changeaudiotrack': () => {
|
'changeaudiotrack': () => {
|
||||||
playbackManager.changeAudioStream();
|
playbackManager.changeAudioStream();
|
||||||
},
|
},
|
||||||
|
|
|
@ -1220,6 +1220,7 @@
|
||||||
"Play": "Play",
|
"Play": "Play",
|
||||||
"PlayAllFromHere": "Play all from here",
|
"PlayAllFromHere": "Play all from here",
|
||||||
"PlaybackData": "Playback Data",
|
"PlaybackData": "Playback Data",
|
||||||
|
"PlaybackRate": "Playback Rate",
|
||||||
"PlayCount": "Play count",
|
"PlayCount": "Play count",
|
||||||
"PlayFromBeginning": "Play from beginning",
|
"PlayFromBeginning": "Play from beginning",
|
||||||
"PlayNext": "Play next",
|
"PlayNext": "Play next",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue