Started on error handling, Safari icon fix
This commit is contained in:
		
							
								
								
									
										2
									
								
								dist/plyr.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										21
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								readme.md
									
									
									
									
									
								
							| @ -3,18 +3,15 @@ Beware: This branch is currently in beta and not production-ready | ||||
| --- | ||||
|  | ||||
| # Plyr | ||||
| A simple, accessible and customizable HTML5, YouTube and Vimeo media player. | ||||
|  | ||||
| [Donate to support Plyr](#donate) | ||||
| A simple, lightweight, accessible and customizable HTML5, YouTube and Vimeo media player that supports [*modern*](#browser-support) browsers. | ||||
|  | ||||
| [Checkout the demo](https://plyr.io) | ||||
| [Checkout the demo](https://plyr.io) - [Donate to support Plyr](#donate) | ||||
|  | ||||
| [](https://plyr.io) | ||||
|  | ||||
| ## Why? | ||||
| We wanted a lightweight, accessible and customizable media player that supports [*modern*](#browser-support) browsers. Sure, there are many other players out there but we wanted to keep things simple, using the right elements for the job. | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| - **Accessible** - full support for VTT captions and screen readers | ||||
| - **Lightweight** - just 18KB minified and gzipped | ||||
| - **[Customisable](#html)** - make the player look how you want with the markup you want | ||||
| @ -52,18 +49,22 @@ Created and maintained by Dominik Pschenitschni ([@dpschen](https://github.com/d | ||||
| You can grab the source using one of the following package managers. | ||||
|  | ||||
| ### npm | ||||
|  | ||||
| ``` | ||||
| npm install plyr | ||||
| ``` | ||||
| [https://www.npmjs.com/package/plyr](https://www.npmjs.com/package/plyr) | ||||
|  | ||||
| ## Quick setup | ||||
|  | ||||
| Here's a quick run through on getting up and running. There's also a [demo on Codepen](http://codepen.io/sampotts/pen/jARJYp). | ||||
|  | ||||
| ### HTML | ||||
|  | ||||
| Plyr extends upon the standard HTML5 markup so that's all you need for those types. More info on advanced HTML markup can be found under [initialising](#initialising). | ||||
|  | ||||
| #### HTML5 Video | ||||
|  | ||||
| ```html | ||||
| <video poster="/path/to/poster.jpg" id="player" controls> | ||||
|     <source src="/path/to/video.mp4" type="video/mp4"> | ||||
| @ -75,6 +76,7 @@ Plyr extends upon the standard HTML5 markup so that's all you need for those typ | ||||
| ``` | ||||
|  | ||||
| #### HTML5 Audio | ||||
|  | ||||
| ```html | ||||
| <audio id="player" controls> | ||||
|     <source src="/path/to/audio.mp3" type="audio/mp3"> | ||||
| @ -85,6 +87,7 @@ Plyr extends upon the standard HTML5 markup so that's all you need for those typ | ||||
| For YouTube and Vimeo, Plyr uses the standard YouTube API markup (an empty `<div>`): | ||||
|  | ||||
| #### YouTube embed | ||||
|  | ||||
| ```html | ||||
| <div id="player" data-type="youtube" data-video-id="bTqVqk7FSmY"></div> | ||||
| ``` | ||||
| @ -92,12 +95,14 @@ For YouTube and Vimeo, Plyr uses the standard YouTube API markup (an empty `<div | ||||
| Note: `data-video-id` value can now be the ID or URL for the video. This attribute name will change in a future release to reflect this change. | ||||
|  | ||||
| #### Vimeo embed | ||||
|  | ||||
| ```html | ||||
| <div id="player" data-type="vimeo" data-video-id="143418951"></div> | ||||
| ``` | ||||
| Note: `data-video-id` value can now be the ID or URL for the video. This attribute name will change in a future release to reflect this change. | ||||
|  | ||||
| ### JavaScript | ||||
|  | ||||
| Include the `plyr.js` script before the closing `</body>` tag and then call `plyr.setup()`. More info on `setup()` can be found under [initialising](#initialising). | ||||
|  | ||||
| ```html | ||||
| @ -112,6 +117,7 @@ If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for t | ||||
| ``` | ||||
|  | ||||
| ### CSS | ||||
|  | ||||
| Include the `plyr.css` stylsheet into your `<head>` | ||||
|  | ||||
| ```html | ||||
| @ -203,6 +209,7 @@ const player = new Plyr('#player', { /* options */ }); | ||||
| The constructor will return a Plyr object that can be used with the [API](#api) methods. See the [API](#api) section for more info. | ||||
|  | ||||
| #### Options | ||||
|  | ||||
| Options can be passed as an object to the constructor as above or as JSON in `data-plyr` attribute on each of your target elements: | ||||
|  | ||||
| ```html | ||||
| @ -468,6 +475,7 @@ Event Type | Description | ||||
| `ready` | Triggered when the instance is ready for API calls. | ||||
|  | ||||
| #### HTML5 only | ||||
|  | ||||
| Event Type | Description | ||||
| ---------- | ----------- | ||||
| `loadstart` | Sent when loading of the media begins. | ||||
| @ -482,6 +490,7 @@ Event Type | Description | ||||
| `error` | Sent when an error occurs. The element's `error` attribute contains more information. | ||||
|  | ||||
| #### YouTube only | ||||
|  | ||||
| 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. | ||||
|  | ||||
							
								
								
									
										9
									
								
								src/js/controls.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								src/js/controls.js
									
									
									
									
										vendored
									
									
								
							| @ -75,14 +75,11 @@ const controls = { | ||||
|         const use = document.createElementNS(namespace, 'use'); | ||||
|         const path = `${iconPath}-${type}`; | ||||
|  | ||||
|         // If the new `href` attribute is supported, use that | ||||
|         // Set `href` attributes | ||||
|         // https://github.com/sampotts/plyr/issues/460 | ||||
|         // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href | ||||
|         if ('href' in use) { | ||||
|             use.setAttribute('href', path); | ||||
|         } else { | ||||
|             use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path); | ||||
|         } | ||||
|         use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path); | ||||
|         use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path); | ||||
|  | ||||
|         // Add <use> to <svg> | ||||
|         icon.appendChild(use); | ||||
|  | ||||
| @ -341,7 +341,14 @@ const listeners = { | ||||
|         // Proxy events to container | ||||
|         // Bubble up key events for Edge | ||||
|         utils.on(this.media, this.config.events.concat(['keyup', 'keydown']).join(' '), event => { | ||||
|             utils.dispatchEvent.call(this, this.elements.container, event.type, true); | ||||
|             let detail = {}; | ||||
|  | ||||
|             // Get error details from media | ||||
|             if (event.type === 'error') { | ||||
|                 detail = this.media.error; | ||||
|             } | ||||
|  | ||||
|             utils.dispatchEvent.call(this, this.elements.container, event.type, true, detail); | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|  | ||||
| @ -37,7 +37,8 @@ const vimeo = { | ||||
|     setAspectRatio(input) { | ||||
|         const ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':'); | ||||
|         const padding = 100 / ratio[0] * ratio[1]; | ||||
|         const offset = (300 - padding) / 6; | ||||
|         const height = 200; | ||||
|         const offset = (height - padding) / (height / 50); | ||||
|         this.elements.wrapper.style.paddingBottom = `${padding}%`; | ||||
|         this.media.style.transform = `translateY(-${offset}%)`; | ||||
|     }, | ||||
| @ -70,23 +71,27 @@ const vimeo = { | ||||
|         // https://github.com/vimeo/player.js | ||||
|         player.embed = new window.Vimeo.Player(iframe); | ||||
|  | ||||
|         // Create a faux HTML5 API using the Vimeo API | ||||
|         player.media.play = () => { | ||||
|             player.embed.play(); | ||||
|             player.media.paused = false; | ||||
|         }; | ||||
|         player.media.pause = () => { | ||||
|             player.embed.pause(); | ||||
|             player.media.paused = true; | ||||
|         }; | ||||
|         player.media.stop = () => { | ||||
|             player.embed.stop(); | ||||
|             player.media.paused = true; | ||||
|         }; | ||||
|  | ||||
|         player.media.paused = true; | ||||
|         player.media.currentTime = 0; | ||||
|  | ||||
|         // Create a faux HTML5 API using the Vimeo API | ||||
|         player.media.play = () => { | ||||
|             player.embed.play().then(() => { | ||||
|                 player.media.paused = false; | ||||
|             }); | ||||
|         }; | ||||
|         player.media.pause = () => { | ||||
|             player.embed.pause().then(() => { | ||||
|                 player.media.paused = true; | ||||
|             }); | ||||
|         }; | ||||
|         player.media.stop = () => { | ||||
|             player.embed.stop().then(() => { | ||||
|                 player.media.paused = true; | ||||
|                 player.currentTime = 0; | ||||
|             }); | ||||
|         }; | ||||
|  | ||||
|         // Seeking | ||||
|         let { currentTime } = player.media; | ||||
|         Object.defineProperty(player.media, 'currentTime', { | ||||
| @ -121,9 +126,10 @@ const vimeo = { | ||||
|                 return speed; | ||||
|             }, | ||||
|             set(input) { | ||||
|                 speed = input; | ||||
|                 player.embed.setPlaybackRate(input); | ||||
|                 utils.dispatchEvent.call(player, player.media, 'ratechange'); | ||||
|                 player.embed.setPlaybackRate(input).then(() => { | ||||
|                     speed = input; | ||||
|                     utils.dispatchEvent.call(player, player.media, 'ratechange'); | ||||
|                 }); | ||||
|             }, | ||||
|         }); | ||||
|  | ||||
| @ -134,9 +140,10 @@ const vimeo = { | ||||
|                 return volume; | ||||
|             }, | ||||
|             set(input) { | ||||
|                 volume = input; | ||||
|                 player.embed.setVolume(input); | ||||
|                 utils.dispatchEvent.call(player, player.media, 'volumechange'); | ||||
|                 player.embed.setVolume(input).then(() => { | ||||
|                     volume = input; | ||||
|                     utils.dispatchEvent.call(player, player.media, 'volumechange'); | ||||
|                 }); | ||||
|             }, | ||||
|         }); | ||||
|  | ||||
| @ -148,9 +155,11 @@ const vimeo = { | ||||
|             }, | ||||
|             set(input) { | ||||
|                 const toggle = utils.is.boolean(input) ? input : false; | ||||
|                 muted = toggle; | ||||
|                 player.embed.setVolume(toggle ? 0 : player.config.volume); | ||||
|                 utils.dispatchEvent.call(player, player.media, 'volumechange'); | ||||
|  | ||||
|                 player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => { | ||||
|                     muted = toggle; | ||||
|                     utils.dispatchEvent.call(player, player.media, 'volumechange'); | ||||
|                 }); | ||||
|             }, | ||||
|         }); | ||||
|  | ||||
| @ -161,8 +170,11 @@ const vimeo = { | ||||
|                 return loop; | ||||
|             }, | ||||
|             set(input) { | ||||
|                 loop = utils.is.boolean(input) ? input : player.config.loop.active; | ||||
|                 player.embed.setLoop(loop); | ||||
|                 const toggle = utils.is.boolean(input) ? input : player.config.loop.active; | ||||
|  | ||||
|                 player.embed.setLoop(toggle).then(() => { | ||||
|                     loop = toggle; | ||||
|                 }); | ||||
|             }, | ||||
|         }); | ||||
|  | ||||
| @ -269,6 +281,11 @@ const vimeo = { | ||||
|             utils.dispatchEvent.call(player, player.media, 'ended'); | ||||
|         }); | ||||
|  | ||||
|         player.embed.on('error', detail => { | ||||
|             player.media.error = detail; | ||||
|             utils.dispatchEvent.call(player, player.media, 'error'); | ||||
|         }); | ||||
|  | ||||
|         // Rebuild UI | ||||
|         window.setTimeout(() => ui.build.call(player), 0); | ||||
|     }, | ||||
|  | ||||
| @ -81,10 +81,47 @@ const youtube = { | ||||
|             }, | ||||
|             events: { | ||||
|                 onError(event) { | ||||
|                     utils.dispatchEvent.call(player, player.media, 'error', true, { | ||||
|                     // If we've already fired an error, don't do it again | ||||
|                     // YouTube fires onError twice | ||||
|                     if (utils.is.object(player.media.error)) { | ||||
|                         return; | ||||
|                     } | ||||
|  | ||||
|                     const detail = { | ||||
|                         code: event.data, | ||||
|                         embed: event.target, | ||||
|                     }); | ||||
|                     }; | ||||
|  | ||||
|                     // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError | ||||
|                     switch (event.data) { | ||||
|                         case 2: | ||||
|                             detail.message = | ||||
|                                 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.'; | ||||
|                             break; | ||||
|  | ||||
|                         case 5: | ||||
|                             detail.message = | ||||
|                                 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.'; | ||||
|                             break; | ||||
|  | ||||
|                         case 100: | ||||
|                             detail.message = | ||||
|                                 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.'; | ||||
|                             break; | ||||
|  | ||||
|                         case 101: | ||||
|                         case 150: | ||||
|                             detail.message = | ||||
|                                 'The owner of the requested video does not allow it to be played in embedded players.'; | ||||
|                             break; | ||||
|  | ||||
|                         default: | ||||
|                             detail.message = 'An unknown error occured'; | ||||
|                             break; | ||||
|                     } | ||||
|  | ||||
|                     player.media.error = detail; | ||||
|  | ||||
|                     utils.dispatchEvent.call(player, player.media, 'error'); | ||||
|                 }, | ||||
|                 onPlaybackQualityChange(event) { | ||||
|                     // Get the instance | ||||
|  | ||||
| @ -525,7 +525,7 @@ const utils = { | ||||
|     }, | ||||
|  | ||||
|     // Trigger event | ||||
|     dispatchEvent(element, type, bubbles, properties) { | ||||
|     dispatchEvent(element, type, bubbles, detail) { | ||||
|         // Bail if no element | ||||
|         if (!element || !type) { | ||||
|             return; | ||||
| @ -534,7 +534,7 @@ const utils = { | ||||
|         // Create and dispatch the event | ||||
|         const event = new CustomEvent(type, { | ||||
|             bubbles: utils.is.boolean(bubbles) ? bubbles : false, | ||||
|             detail: Object.assign({}, properties, { | ||||
|             detail: Object.assign({}, detail, { | ||||
|                 plyr: this instanceof Plyr ? this : null, | ||||
|             }), | ||||
|         }); | ||||
|  | ||||
| @ -53,7 +53,7 @@ | ||||
| .plyr__play-large { | ||||
|     display: none; | ||||
|     position: absolute; | ||||
|     z-index: 1; | ||||
|     z-index: 3; | ||||
|     top: 50%; | ||||
|     left: 50%; | ||||
|     transform: translate(-50%, -50%); | ||||
|  | ||||
| @ -6,7 +6,8 @@ | ||||
| .plyr__video-embed { | ||||
|     // Default to 16:9 ratio but this is set by JavaScript based on config | ||||
|     @padding: ((100 / 16) * 9); | ||||
|     @offset: unit((300 - @padding) / 6, ~'%'); | ||||
|     @height: 200; | ||||
|     @offset: unit((@height - @padding) / (@height / 50), ~'%'); | ||||
|  | ||||
|     padding-bottom: unit(@padding, ~'%'); | ||||
|     height: 0; | ||||
| @ -24,7 +25,7 @@ | ||||
|     // Vimeo hack | ||||
|     > div { | ||||
|         position: relative; | ||||
|         padding-bottom: 300%; | ||||
|         padding-bottom: unit(@height, ~'%'); | ||||
|         transform: translateY(-@offset); | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user