Removed YouTube quality controls

This commit is contained in:
Sam Potts 2018-08-13 23:43:08 +10:00
parent 468b20d227
commit 211ad6c8f5
7 changed files with 95 additions and 168 deletions

View File

@ -3,6 +3,7 @@
- Accessibility improvements (see #905) - Accessibility improvements (see #905)
- Improvements to the way the controls work on iOS - Improvements to the way the controls work on iOS
- Demo code clean up - Demo code clean up
- YouTube quality selection removed due to their poor support for it. As a result, the `qualityrequested` event has been removed
# v3.3.23 # v3.3.23

115
readme.md
View File

@ -8,26 +8,26 @@ A simple, lightweight, accessible and customizable HTML5, YouTube and Vimeo medi
## Features ## Features
* **Accessible** - full support for VTT captions and screen readers - **Accessible** - full support for VTT captions and screen readers
* **[Customisable](#html)** - make the player look how you want with the markup you want - **[Customisable](#html)** - make the player look how you want with the markup you want
* **Good HTML** - uses the _right_ elements. `<input type="range">` for volume and `<progress>` for progress and well, `<button>`s for buttons. There's no - **Good HTML** - uses the _right_ elements. `<input type="range">` for volume and `<progress>` for progress and well, `<button>`s for buttons. There's no
`<span>` or `<a href="#">` button hacks `<span>` or `<a href="#">` button hacks
* **Responsive** - works with any screen size - **Responsive** - works with any screen size
* **HTML Video & Audio** - support for both formats - **HTML Video & Audio** - support for both formats
* **[Embedded Video](#embeds)** - support for YouTube and Vimeo video playback - **[Embedded Video](#embeds)** - support for YouTube and Vimeo video playback
* **[Monetization](#ads)** - make money from your videos - **[Monetization](#ads)** - make money from your videos
* **[Streaming](#try-plyr-online)** - support for hls.js, Shaka and dash.js streaming playback - **[Streaming](#try-plyr-online)** - support for hls.js, Shaka and dash.js streaming playback
* **[API](#api)** - toggle playback, volume, seeking, and more through a standardized API - **[API](#api)** - toggle playback, volume, seeking, and more through a standardized API
* **[Events](#events)** - no messing around with Vimeo and YouTube APIs, all events are standardized across formats - **[Events](#events)** - no messing around with Vimeo and YouTube APIs, all events are standardized across formats
* **[Fullscreen](#fullscreen)** - supports native fullscreen with fallback to "full window" modes - **[Fullscreen](#fullscreen)** - supports native fullscreen with fallback to "full window" modes
* **[Shortcuts](#shortcuts)** - supports keyboard shortcuts - **[Shortcuts](#shortcuts)** - supports keyboard shortcuts
* **Picture-in-Picture** - supports Safari's picture-in-picture mode - **Picture-in-Picture** - supports Safari's picture-in-picture mode
* **Playsinline** - supports the `playsinline` attribute - **Playsinline** - supports the `playsinline` attribute
* **Speed controls** - adjust speed on the fly - **Speed controls** - adjust speed on the fly
* **Multiple captions** - support for multiple caption tracks - **Multiple captions** - support for multiple caption tracks
* **i18n support** - support for internationalization of controls - **i18n support** - support for internationalization of controls
* **No dependencies** - written in "vanilla" ES6 JavaScript, no jQuery required - **No dependencies** - written in "vanilla" ES6 JavaScript, no jQuery required
* **SASS** - to include in your build processes - **SASS** - to include in your build processes
Oh and yes, it works with Bootstrap. Oh and yes, it works with Bootstrap.
@ -164,9 +164,9 @@ reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.4.0-
Plyr has partnered up with [vi.ai](https://vi.ai/publisher-video-monetization/?aid=plyrio) to offer monetization options for your videos. Getting setup is easy: Plyr has partnered up with [vi.ai](https://vi.ai/publisher-video-monetization/?aid=plyrio) to offer monetization options for your videos. Getting setup is easy:
* [Sign up for a vi.ai account](https://vi.ai/publisher-video-monetization/?aid=plyrio) - [Sign up for a vi.ai account](https://vi.ai/publisher-video-monetization/?aid=plyrio)
* Grab your publisher ID from the code snippet - Grab your publisher ID from the code snippet
* Enable ads in the [config options](#options) and enter your publisher ID - Enable ads in the [config options](#options) and enter your publisher ID
Any questions regarding the ads can be sent straight to vi.ai and any issues with rendering raised through GitHub issues. Any questions regarding the ads can be sent straight to vi.ai and any issues with rendering raised through GitHub issues.
@ -213,10 +213,10 @@ WebVTT captions are supported. To add a caption track, check the HTML example ab
You can specify a range of arguments for the constructor to use: You can specify a range of arguments for the constructor to use:
* A CSS string selector that's compatible with [`querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector) - A CSS string selector that's compatible with [`querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)
* A [`HTMLElement`](https://developer.mozilla.org/en/docs/Web/API/HTMLElement) - A [`HTMLElement`](https://developer.mozilla.org/en/docs/Web/API/HTMLElement)
* A [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList) - A [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList)
* A [jQuery](https://jquery.com) object - A [jQuery](https://jquery.com) object
_Note_: If a `NodeList`, `Array`, or jQuery object are passed, the first element will be used for setup. To setup multiple players, see [setting up multiple players](#setting-up-multiple-players) below. _Note_: If a `NodeList`, `Array`, or jQuery object are passed, the first element will be used for setup. To setup multiple players, see [setting up multiple players](#setting-up-multiple-players) below.
@ -392,7 +392,7 @@ player.fullscreen.active; // false;
``` ```
| Property | Getter | Setter | Description | | Property | Getter | Setter | Description |
| -------------------- | ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | -------------------- | ------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isHTML5` | ✓ | - | Returns a boolean indicating if the current player is HTML5. | | `isHTML5` | ✓ | - | Returns a boolean indicating if the current player is HTML5. |
| `isEmbed` | ✓ | - | Returns a boolean indicating if the current player is an embedded player. | | `isEmbed` | ✓ | - | Returns a boolean indicating if the current player is an embedded player. |
| `playing` | ✓ | - | Returns a boolean indicating if the current player is playing. | | `playing` | ✓ | - | Returns a boolean indicating if the current player is playing. |
@ -565,6 +565,7 @@ player.on('ready', event => {
| `loadstart` | Sent when loading of the media begins. | | `loadstart` | Sent when loading of the media begins. |
| `loadeddata` | The first frame of the media has finished loading. | | `loadeddata` | The first frame of the media has finished loading. |
| `loadedmetadata` | The media's metadata has finished loading; all attributes now contain as much useful information as they're going to. | | `loadedmetadata` | The media's metadata has finished loading; all attributes now contain as much useful information as they're going to. |
| `qualitychange` | The quality of playback has changed. |
| `canplay` | Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the `HAVE_ENOUGH_DATA` `readyState`. | | `canplay` | Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the `HAVE_ENOUGH_DATA` `readyState`. |
| `canplaythrough` | Sent when the ready state changes to `CAN_PLAY_THROUGH`, indicating that the entire media can be played without interruption, assuming the download rate remains at least at the current level. _Note:_ Manually setting the `currentTime` will eventually fire a `canplaythrough` event in firefox. Other browsers might not fire this event. | | `canplaythrough` | Sent when the ready state changes to `CAN_PLAY_THROUGH`, indicating that the entire media can be played without interruption, assuming the download rate remains at least at the current level. _Note:_ Manually setting the `currentTime` will eventually fire a `canplaythrough` event in firefox. Other browsers might not fire this event. |
| `stalled` | Sent when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming. | | `stalled` | Sent when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming. |
@ -576,10 +577,8 @@ player.on('ready', event => {
#### YouTube only #### YouTube only
| Event Type | Description | | Event Type | Description |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `statechange` | The state of the player has changed. The code can be accessed via `event.detail.code`. Possible values are `-1`: Unstarted, `0`: Ended, `1`: Playing, `2`: Paused, `3`: Buffering, `5`: Video cued. See the [YouTube Docs](https://developers.google.com/youtube/iframe_api_reference#onStateChange) for more information. | | `statechange` | The state of the player has changed. The code can be accessed via `event.detail.code`. Possible values are `-1`: Unstarted, `0`: Ended, `1`: Playing, `2`: Paused, `3`: Buffering, `5`: Video cued. See the [YouTube Docs](https://developers.google.com/youtube/iframe_api_reference#onStateChange) for more information. |
| `qualitychange` | The quality of playback has changed. |
| `qualityrequested` | A change to playback quality has been requested. _Note:_ A change to quality can only be _requested_ via the API. There is no guarantee the quality will change to the level requested. You should listen to the `qualitychange` event for true changes. |
_Note:_ These events also bubble up the DOM. The event target will be the container element. _Note:_ These events also bubble up the DOM. The event target will be the container element.
@ -591,8 +590,8 @@ YouTube and Vimeo are currently supported and function much like a HTML5 video.
to access the API's directly. You can do so via the `embed` property of your player object - e.g. `player.embed`. You can then use the relevant methods from the to access the API's directly. You can do so via the `embed` property of your player object - e.g. `player.embed`. You can then use the relevant methods from the
third party APIs. More info on the respective API's here: third party APIs. More info on the respective API's here:
* [YouTube iframe API Reference](https://developers.google.com/youtube/iframe_api_reference) - [YouTube iframe API Reference](https://developers.google.com/youtube/iframe_api_reference)
* [Vimeo player.js Reference](https://github.com/vimeo/player.js) - [Vimeo player.js Reference](https://github.com/vimeo/player.js)
_Note_: Not all API methods may work 100%. Your mileage may vary. It's better to use the Plyr API where possible. _Note_: Not all API methods may work 100%. Your mileage may vary. It's better to use the Plyr API where possible.
@ -652,9 +651,9 @@ const supported = Plyr.supported('video', 'html5', true);
The arguments are: The arguments are:
* Media type (`audio` or `video`) - Media type (`audio` or `video`)
* Provider (`html5`, `youtube` or `vimeo`) - Provider (`html5`, `youtube` or `vimeo`)
* Whether the player has the `playsinline` attribute (only applicable to iOS 10+) - Whether the player has the `playsinline` attribute (only applicable to iOS 10+)
### Disable support programatically ### Disable support programatically
@ -687,33 +686,33 @@ Plyr is developed by [@sam_potts](https://twitter.com/sam_potts) / [sampotts.me]
Plyr costs money to run, not only my time. I donate my time for free as I enjoy building Plyr but unfortunately have to pay for domains, hosting, and more. Any help with costs is appreciated... Plyr costs money to run, not only my time. I donate my time for free as I enjoy building Plyr but unfortunately have to pay for domains, hosting, and more. Any help with costs is appreciated...
* [Donate via Patron](https://www.patreon.com/plyr) - [Donate via Patron](https://www.patreon.com/plyr)
* [Donate via PayPal](https://www.paypal.me/pottsy/20usd) - [Donate via PayPal](https://www.paypal.me/pottsy/20usd)
## Mentions ## Mentions
* [ProductHunt](https://www.producthunt.com/tech/plyr) - [ProductHunt](https://www.producthunt.com/tech/plyr)
* [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/) - [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/)
* [HTML5 Weekly #177](http://html5weekly.com/issues/177) - [HTML5 Weekly #177](http://html5weekly.com/issues/177)
* [Responsive Design #149](http://us4.campaign-archive2.com/?u=559bc631fe5294fc66f5f7f89&id=451a61490f) - [Responsive Design #149](http://us4.campaign-archive2.com/?u=559bc631fe5294fc66f5f7f89&id=451a61490f)
* [Web Design Weekly #174](https://web-design-weekly.com/2015/02/24/web-design-weekly-174/) - [Web Design Weekly #174](https://web-design-weekly.com/2015/02/24/web-design-weekly-174/)
* [Hacker News](https://news.ycombinator.com/item?id=9136774) - [Hacker News](https://news.ycombinator.com/item?id=9136774)
* [Web Platform Daily](http://webplatformdaily.org/releases/2015-03-04) - [Web Platform Daily](http://webplatformdaily.org/releases/2015-03-04)
* [LayerVault Designer News](https://news.layervault.com/stories/45394-plyr--a-simple-html5-media-player) - [LayerVault Designer News](https://news.layervault.com/stories/45394-plyr--a-simple-html5-media-player)
* [The Treehouse Show #131](https://teamtreehouse.com/library/episode-131-origami-react-responsive-hero-images) - [The Treehouse Show #131](https://teamtreehouse.com/library/episode-131-origami-react-responsive-hero-images)
* [noupe.com](http://www.noupe.com/design/html5-plyr-is-a-responsive-and-accessible-video-player-94389.html) - [noupe.com](http://www.noupe.com/design/html5-plyr-is-a-responsive-and-accessible-video-player-94389.html)
## Used by ## Used by
* [Selz.com](https://selz.com) - [Selz.com](https://selz.com)
* [Peugeot.fr](http://www.peugeot.fr/marque-et-technologie/technologies/peugeot-i-cockpit.html) - [Peugeot.fr](http://www.peugeot.fr/marque-et-technologie/technologies/peugeot-i-cockpit.html)
* [Peugeot.de](http://www.peugeot.de/modelle/modellberater/208-3-turer/fotos-videos.html) - [Peugeot.de](http://www.peugeot.de/modelle/modellberater/208-3-turer/fotos-videos.html)
* [TomTom.com](http://prioritydriving.tomtom.com/) - [TomTom.com](http://prioritydriving.tomtom.com/)
* [DIGBMX](http://digbmx.com/) - [DIGBMX](http://digbmx.com/)
* [Grime Archive](https://grimearchive.com/) - [Grime Archive](https://grimearchive.com/)
* [koel - A personal music streaming server that works.](http://koel.phanan.net/) - [koel - A personal music streaming server that works.](http://koel.phanan.net/)
* [Oscar Radio](http://oscar-radio.xyz/) - [Oscar Radio](http://oscar-radio.xyz/)
* [Sparkk TV](https://www.sparkktv.com/) - [Sparkk TV](https://www.sparkktv.com/)
Let me know on [Twitter](https://twitter.com/sam_potts) I can add you to the above list. It'd be awesome to see how you're using Plyr :-) Let me know on [Twitter](https://twitter.com/sam_potts) I can add you to the above list. It'd be awesome to see how you're using Plyr :-)
@ -721,8 +720,8 @@ Let me know on [Twitter](https://twitter.com/sam_potts) I can add you to the abo
Credit to the PayPal HTML5 Video player from which Plyr's caption functionality was originally ported from: Credit to the PayPal HTML5 Video player from which Plyr's caption functionality was originally ported from:
* [PayPal's Accessible HTML5 Video Player](https://github.com/paypal/accessible-html5-video-player) - [PayPal's Accessible HTML5 Video Player](https://github.com/paypal/accessible-html5-video-player)
* [An awesome guide for Plyr in Japanese!](http://syncer.jp/how-to-use-plyr-io) by [@arayutw](https://twitter.com/arayutw) - [An awesome guide for Plyr in Japanese!](http://syncer.jp/how-to-use-plyr-io) by [@arayutw](https://twitter.com/arayutw)
## Thanks ## Thanks

View File

@ -68,19 +68,7 @@ const defaults = {
// Quality default // Quality default
quality: { quality: {
default: 576, default: 576,
options: [ options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240],
4320,
2880,
2160,
1440,
1080,
720,
576,
480,
360,
240,
'default', // YouTube's "auto"
],
}, },
// Set loops // Set loops
@ -268,8 +256,9 @@ const defaults = {
// YouTube // YouTube
'statechange', 'statechange',
// Quality
'qualitychange', 'qualitychange',
'qualityrequested',
// Ads // Ads
'adsloaded', 'adsloaded',

View File

@ -82,6 +82,9 @@ const html5 = {
triggerEvent.call(player, player.media, 'qualitychange', false, { triggerEvent.call(player, player.media, 'qualitychange', false, {
quality: input, quality: input,
}); });
// Save to storage
player.storage.set({ quality: input });
}, },
}); });
}, },

View File

@ -430,12 +430,6 @@ class Listeners {
player.storage.set({ speed: player.speed }); player.storage.set({ speed: player.speed });
}); });
// Quality request
on.call(player, player.media, 'qualityrequested', event => {
// Save to storage
player.storage.set({ quality: event.detail.quality });
});
// Quality change // Quality change
on.call(player, player.media, 'qualitychange', event => { on.call(player, player.media, 'qualitychange', event => {
// Update UI // Update UI

View File

@ -2,9 +2,7 @@
// YouTube plugin // YouTube plugin
// ========================================================================== // ==========================================================================
import controls from '../controls';
import ui from '../ui'; import ui from '../ui';
import { dedupe } from '../utils/arrays';
import { createElement, replaceElement, toggleClass } from '../utils/elements'; import { createElement, replaceElement, toggleClass } from '../utils/elements';
import { triggerEvent } from '../utils/events'; import { triggerEvent } from '../utils/events';
import fetch from '../utils/fetch'; import fetch from '../utils/fetch';
@ -23,37 +21,6 @@ function parseId(url) {
return url.match(regex) ? RegExp.$2 : url; return url.match(regex) ? RegExp.$2 : url;
} }
// Standardise YouTube quality unit
function mapQualityUnit(input) {
const qualities = {
hd2160: 2160,
hd1440: 1440,
hd1080: 1080,
hd720: 720,
large: 480,
medium: 360,
small: 240,
tiny: 144,
};
const entry = Object.entries(qualities).find(entry => entry.includes(input));
if (entry) {
// Get the match corresponding to the input
return entry.find(value => value !== input);
}
return 'default';
}
function mapQualityUnits(levels) {
if (is.empty(levels)) {
return levels;
}
return dedupe(levels.map(level => mapQualityUnit(level)));
}
// Set playback state and trigger change (only on actual change) // Set playback state and trigger change (only on actual change)
function assurePlaybackState(play) { function assurePlaybackState(play) {
if (play && !this.embed.hasPlayed) { if (play && !this.embed.hasPlayed) {
@ -225,11 +192,6 @@ const youtube = {
triggerEvent.call(player, player.media, 'error'); triggerEvent.call(player, player.media, 'error');
} }
}, },
onPlaybackQualityChange() {
triggerEvent.call(player, player.media, 'qualitychange', false, {
quality: player.media.quality,
});
},
onPlaybackRateChange(event) { onPlaybackRateChange(event) {
// Get the instance // Get the instance
const instance = event.target; const instance = event.target;
@ -299,16 +261,6 @@ const youtube = {
}, },
}); });
// Quality
Object.defineProperty(player.media, 'quality', {
get() {
return mapQualityUnit(instance.getPlaybackQuality());
},
set(input) {
instance.setPlaybackQuality(mapQualityUnit(input));
},
});
// Volume // Volume
let { volume } = player.config; let { volume } = player.config;
Object.defineProperty(player.media, 'volume', { Object.defineProperty(player.media, 'volume', {
@ -457,12 +409,6 @@ const youtube = {
player.media.duration = instance.getDuration(); player.media.duration = instance.getDuration();
triggerEvent.call(player, player.media, 'durationchange'); triggerEvent.call(player, player.media, 'durationchange');
} }
// Get quality
controls.setQualityMenu.call(
player,
mapQualityUnits(instance.getAvailableQualityLevels()),
);
} }
break; break;

View File

@ -698,11 +698,6 @@ class Plyr {
quality = value; quality = value;
} }
// Trigger request event
triggerEvent.call(this, this.media, 'qualityrequested', false, {
quality,
});
// Update config // Update config
config.selected = quality; config.selected = quality;