Work on playback rate changes

This commit is contained in:
Sam Potts 2017-07-31 09:58:30 +10:00
parent 7b60e473fa
commit a9957211f4
3 changed files with 120 additions and 148 deletions

4
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,84 +0,0 @@
### Todo
#### To finish
[x] Get list of subtitles/captions available (HTML5, Vimeo)
[x] Add preferred quality option into config
[ ] Update quality options on YouTube play
[ ] Update speed options on YouTube load
[ ] Handle quality change for YouTube
[ ] Handle speed change for YouTube
[ ] Set quality when loading YouTube vid
[ ] Set default values
[ ] Hide unsupported menu items on source change
[ ] Test PiP (need MacOS Sierra)
[ ] Test AirPlay (need MacOS Sierra)
[ ] Add `controlshidden` and `controlsshown` events
[ ] Test custom controls still works (without settings support for now)
[ ] Tidy up small UI for iOS inline
[ ] Finish new loop setup and display in seek bar
[ ] Update docs for removal of setup
#### Later
[ ] Wistia player
[ ] Inlined sprite option
[ ] Start / end time options for all players?
[ ] Get quality options for HTML5 somehow (multi source?)
[ ] Download button - grab first <source> or src attribute (or maybe use currentSrc?) for HTML5 and links for embedded players
[ ] Scale captions size based on video size (in lieu of element queries)
[ ] Allow passing YouTube/Vimeo iframe to setup
#### Bugs
[ ] Fix audio setup bug when calling `.setup()` again
[ ] Fix events on unsupported devices (iOS, old IE)
[x] Fix YouTube rights blocking (origin perhaps?)
### Release notes
- No quality HTML5 support (yet)
- No Vimeo quality support
- No YouTube caption support
- Added Vimeo captions support
- No PiP or AirPlay for Vimeo/YouTube
- Settings won't be supported for custom controls (coming soon, need to work on templating)
- Added `playsinline` support for iOS 10
- Embed setup now accepts an <iframe> as the target element for true progressive enhancement
## Changes
### Config changes
- videoWrapper -> video
- embedWrapper -> embed
- setup and ready classes removed
### API changes
- Can now chain most functions (need to document which can)
- support -> supports
- isFullscreen -> fullscreen.active
- new 'language'
- getType -> type
- getEmbed -> embed
- getContainer removed
- getMedia -> media
- getCurrentTime -> media.currentTime
- getVolume -> media.volume
- isMuted -> media.muted
- isLoading -> media.loading
- isPaused -> media.paused
- updatePoster -> poster
- setVolume -> volume
- increaseVolume (new)
- decreaseVolume (new)
- togglePictureInPicture (new)
- airPlay (new)
- Added `.off` API method
#### Other breaking changes
- New config options for loop
- Selectors changes (new `input` and `display` object) - DOCUMENT
- Custom HTML option now `controls` which accepts a string (HTML), a function (your own template engine) or array (use built in controls)
- `.setup()` is removed in favour of a constructor
- `.loadSprite` removed
- `.support` removed
#### Added
- Seek i8n label
- Loop related i8n labels

View File

@ -1270,6 +1270,31 @@
})); }));
} }
// Trap focus inside container
function focusTrap() {
var tabbables = getElements('input:not([disabled]), button:not([disabled])');
var first = tabbables[0];
var last = tabbables[tabbables.length - 1];
function checkFocus(event) {
// If it is tab
if (event.which === 9 && player.fullscreen.active) {
if (event.target === last && !event.shiftKey) {
// Move focus to first element that can be tabbed if Shift isn't used
event.preventDefault();
first.focus();
} else if (event.target === first && event.shiftKey) {
// Move focus to last element that can be tabbed if Shift is used
event.preventDefault();
last.focus();
}
}
}
// Bind the handler
utils.on(player.elements.container, 'keydown', checkFocus, false);
}
// Find all elements // Find all elements
function getElements(selector) { function getElements(selector) {
return player.elements.container.querySelectorAll(selector); return player.elements.container.querySelectorAll(selector);
@ -1280,6 +1305,7 @@
return getElements(selector)[0]; return getElements(selector)[0];
} }
// Remove an element
function removeElement(element) { function removeElement(element) {
// Remove reference from player.elements cache // Remove reference from player.elements cache
if (utils.is.string(element)) { if (utils.is.string(element)) {
@ -1303,31 +1329,6 @@
} }
} }
// Trap focus inside container
function focusTrap() {
var tabbables = getElements('input:not([disabled]), button:not([disabled])');
var first = tabbables[0];
var last = tabbables[tabbables.length - 1];
function checkFocus(event) {
// If it is TAB
if (event.which === 9 && player.fullscreen.active) {
if (event.target === last && !event.shiftKey) {
// Move focus to first element that can be tabbed if Shift isn't used
event.preventDefault();
first.focus();
} else if (event.target === first && event.shiftKey) {
// Move focus to last element that can be tabbed if Shift is used
event.preventDefault();
last.focus();
}
}
}
// Bind the handler
utils.on(player.elements.container, 'keydown', checkFocus, false);
}
// Get icon URL // Get icon URL
function getIconUrl() { function getIconUrl() {
return { return {
@ -1972,7 +1973,7 @@
} }
// Set a list of available captions languages // Set a list of available captions languages
function setSpeedMenu(options) { function setSpeedMenu() {
var list = player.elements.settings.panes.speed.querySelector('ul'); var list = player.elements.settings.panes.speed.querySelector('ul');
// Show the pane and tab // Show the pane and tab
@ -1982,12 +1983,8 @@
// Empty the menu // Empty the menu
utils.emptyElement(list); utils.emptyElement(list);
// If there's no captions, bail // Create items
if (!utils.is.array(options)) { player.config.speed.options.forEach(function(speed) {
options = player.config.speed.options;
}
options.forEach(function(speed) {
var item = utils.createElement('li'); var item = utils.createElement('li');
var label = utils.createElement('label', { var label = utils.createElement('label', {
@ -2000,15 +1997,42 @@
value: speed, value: speed,
})); }));
if (speed === player.config.speed.selected) {
radio.checked = true;
}
label.appendChild(radio); label.appendChild(radio);
label.insertAdjacentHTML('beforeend', getSpeedLabel(speed)); label.insertAdjacentHTML('beforeend', getSpeedLabel(speed));
item.appendChild(label); item.appendChild(label);
list.appendChild(item); list.appendChild(item);
}); });
setSelectedSpeed(list);
}
// Update the UI
function setSelectedSpeed(list) {
var speed = player.config.speed.selected;
// Unsupported speed
if (!utils.inArray(player.config.speed.options, speed)) {
return;
}
// Get the list if we need to
if (!utils.is.htmlElement(list)) {
list = player.elements.settings.panes.speed.querySelector('ul');
}
// Find the radio option
var target = list.querySelector('[value="' + speed + '"]');
if (!utils.is.htmlElement(target)) {
return;
}
// Check it
target.checked = true;
// Find the label
var label = player.elements.settings.tabs.speed.querySelector('.' + player.config.classes.menu.value);
label.innerHTML = getSpeedLabel(speed);
} }
// Setup fullscreen // Setup fullscreen
@ -2622,7 +2646,17 @@
var quality = instance.getPlaybackQuality(); var quality = instance.getPlaybackQuality();
// var set = player.setPlaybackQuality(); // var set = player.setPlaybackQuality();
console.warn(quality); console.warn('quality change', quality);
},
'onPlaybackRateChange': function(event) {
// Get the instance
var instance = event.target;
// Get current speed
player.media.playbackRate = instance.getPlaybackRate();
// Trigger timeupdate
trigger(player.media, 'ratechange');
}, },
'onReady': function(event) { 'onReady': function(event) {
// Get the instance // Get the instance
@ -2647,10 +2681,9 @@
player.media.muted = instance.isMuted(); player.media.muted = instance.isMuted();
// Get available speeds // Get available speeds
var speed = instance.getPlaybackRate(); player.config.speed.selected = instance.getPlaybackRate();
var speedOptions = instance.getAvailablePlaybackRates(); player.config.speed.options = instance.getAvailablePlaybackRates();
//var set = instance.setPlaybackRate(); setSpeedMenu();
console.warn(speed, speedOptions);
// Set title // Set title
player.config.title = instance.getVideoData().title; player.config.title = instance.getVideoData().title;
@ -3834,7 +3867,7 @@
// Settings - Language // Settings - Language
if (utils.matches(event.target, player.config.selectors.inputs.language)) { if (utils.matches(event.target, player.config.selectors.inputs.language)) {
handlerProxy.call(this, event, player.config.listeners.language, function() { handlerProxy.call(this, event, player.config.listeners.language, function() {
player.language(event.target.value.toLowerCase()); player.setLanguage(event.target.value.toLowerCase());
}); });
} }
@ -4024,6 +4057,20 @@
}, false); }, false);
} }
// Speed change
utils.on(player.media, 'ratechange', function(event) {
// Store current speed
player.config.speed.selected = player.media.playbackRate;
// Update UI
setSelectedSpeed();
// Save speed to localStorage
updateStorage({
speed: player.config.speed.selected
});
});
// Proxy events to container // Proxy events to container
// Bubble up key events for Edge // Bubble up key events for Edge
utils.on(player.media, player.config.events.concat(['keyup', 'keydown']).join(' '), function(event) { utils.on(player.media, player.config.events.concat(['keyup', 'keydown']).join(' '), function(event) {
@ -4562,7 +4609,6 @@
// Embeds // Embeds
if (utils.inArray(types.embed, player.type)) { if (utils.inArray(types.embed, player.type)) {
// YouTube
switch (player.type) { switch (player.type) {
case 'youtube': case 'youtube':
player.embed[player.media.muted ? 'mute' : 'unMute'](); player.embed[player.media.muted ? 'mute' : 'unMute']();
@ -4599,22 +4645,26 @@
speed = 2.0; speed = 2.0;
} }
if (!utils.is.array(player.config.speed.options)) { if (!utils.inArray(player.config.speed.options, speed)) {
player.core.warn('Invalid speeds format'); player.core.warn('Unsupported speed (' + speed + ')');
return; return;
} }
// Store current speed // Set media speed
player.config.speed.selected = speed; switch (player.type) {
case 'youtube':
player.embed.setPlaybackRate(speed);
break;
// Set HTML5 speed case 'vimeo':
// TODO: set YouTube // Vimeo not supported (https://github.com/vimeo/player.js)
player.media.playbackRate = speed; player.core.warn('Vimeo playback rate change is not supported');
break;
// Save speed to localStorage default:
player.core.updateStorage({ player.media.playbackRate = speed;
speed: speed break;
}); }
// Allow chaining // Allow chaining
return player; return player;
@ -4794,18 +4844,19 @@
return player; return player;
}; };
// Select active caption // Set caption language
Plyr.prototype.language = function(language) { Plyr.prototype.setLanguage = function(language) {
var player = this; var player = this;
if (utils.is.string(language)) { // Nothing specified
// Update config if (!utils.is.string(language)) {
player.config.captions.language = language.toLowerCase(); player.core.warn('Language is required');
} else { return;
// If no language passed, return current language
return player.config.captions.language;
} }
// Update config
player.config.captions.language = language.toLowerCase();
// Clear caption // Clear caption
player.core.setCaption(); player.core.setCaption();
@ -4816,6 +4867,11 @@
return player; return player;
}; };
// Get current language
Plyr.prototype.getLanguage = function() {
return this.config.captions.language;
};
// Toggle fullscreen // Toggle fullscreen
// Requires user input event // Requires user input event
Plyr.prototype.toggleFullscreen = function(event) { Plyr.prototype.toggleFullscreen = function(event) {