Compare commits

...

9 Commits

Author SHA1 Message Date
3b69f47590 v1.6.2 2016-05-01 12:52:07 +10:00
8172e2339d Caption change position on controls hidden 2016-05-01 12:49:04 +10:00
44bb6c077c Fixed merge 2016-05-01 12:00:37 +10:00
e11a58a841 Bug fixes 2016-05-01 11:30:51 +10:00
Sam
c4e3b5a242 Bug fixes 2016-05-01 00:35:30 +10:00
f1b44e6da0 Error handling 2016-04-30 19:52:10 +10:00
aa093b6c42 Merge branch 'pr/196' into develop
# Conflicts:
#	dist/plyr.js
2016-04-30 11:08:42 +10:00
48399f6364 Merge remote-tracking branch 'org/develop' into develop 2016-04-25 22:43:44 -07:00
47e0800f02 Add support for soundcloud 2016-04-17 20:57:55 -07:00
9 changed files with 360 additions and 145 deletions

2
.gitignore vendored
View File

@ -7,3 +7,5 @@ docs/index.dev.html
*.mp4 *.mp4
index-dev.html index-dev.html
notes.txt notes.txt
*.vtt
docs/index.dev.php

View File

@ -1,5 +1,12 @@
# Changelog # Changelog
## v1.6.2
- Fix for tooltip displaying when duration is not set (fixes #177)
- `showPosterOnEnd` option to show poster when HTML5 video ended (fixes #59)
- Error handler for YouTube (fixes #189)
- Initial SoundCloud support (fixes #194)
- Other minor bug fixes
## v1.6.1 ## v1.6.1
- Tooltip changes for accessibility - Tooltip changes for accessibility

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

4
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "plyr", "name": "plyr",
"version": "1.6.1", "version": "1.6.2",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player", "description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "http://plyr.io", "homepage": "http://plyr.io",
"main": "src/js/plyr.js", "main": "src/js/plyr.js",

View File

@ -40,7 +40,7 @@ If you have any cool ideas or features, please let me know by [creating an issue
## Implementation ## Implementation
Check `docs/index.html` and `docs/dist/docs.js` for an example setup. Check `docs/index.html` and `docs/dist/docs.js` for an example setup.
**Heads up:** the example `index.html` file needs to be served from a webserver (such as Apache, Nginx, IIS or similar) unless you change the file sources to include http or https. e.g. change `//cdn.plyr.io/1.6.1/plyr.js` to `https://cdn.plyr.io/1.6.1/plyr.js` **Heads up:** the example `index.html` file needs to be served from a webserver (such as Apache, Nginx, IIS or similar) unless you change the file sources to include http or https. e.g. change `//cdn.plyr.io/1.6.2/plyr.js` to `https://cdn.plyr.io/1.6.2/plyr.js`
### Node Package Manager (NPM) ### Node Package Manager (NPM)
@ -71,11 +71,11 @@ More info is on [npm](https://www.npmjs.com/package/ember-cli-plyr) and [GitHub]
If you want to use our CDN, you can use the following: If you want to use our CDN, you can use the following:
```html ```html
<link rel="stylesheet" href="https://cdn.plyr.io/1.6.1/plyr.css"> <link rel="stylesheet" href="https://cdn.plyr.io/1.6.2/plyr.css">
<script src="https://cdn.plyr.io/1.6.1/plyr.js"></script> <script src="https://cdn.plyr.io/1.6.2/plyr.js"></script>
``` ```
You can also access the `sprite.svg` file at `https://cdn.plyr.io/1.6.1/sprite.svg`. You can also access the `sprite.svg` file at `https://cdn.plyr.io/1.6.2/sprite.svg`.
### CSS & Styling ### CSS & Styling
If you want to use the default css, add the `plyr.css` file from `/dist` into your head, or even better use `plyr.less` or `plyr.scss` file included in `/src` in your build to save a request. If you want to use the default css, add the `plyr.css` file from `/dist` into your head, or even better use `plyr.less` or `plyr.scss` file included in `/src` in your build to save a request.
@ -113,7 +113,7 @@ Using AJAX means you can load the sprite from a different origin. Avoiding the i
c.innerHTML = a.responseText; c.innerHTML = a.responseText;
b.insertBefore(c, b.childNodes[0]); b.insertBefore(c, b.childNodes[0]);
}; };
})(document, 'https://cdn.plyr.io/1.6.1/sprite.svg'); })(document, 'https://cdn.plyr.io/1.6.2/sprite.svg');
</script> </script>
``` ```
@ -188,7 +188,7 @@ Be sure to [validate your caption files](https://quuz.org/webvtt/)
Here's an example of a default setup: Here's an example of a default setup:
```html ```html
<script src="https://cdn.plyr.io/1.6.1/plyr.js"></script> <script src="https://cdn.plyr.io/1.6.2/plyr.js"></script>
<script>plyr.setup();</script> <script>plyr.setup();</script>
``` ```

View File

@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr // Plyr
// plyr.js v1.6.1 // plyr.js v1.6.2
// https://github.com/selz/plyr // https://github.com/selz/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
@ -42,6 +42,7 @@
iconUrl: '', iconUrl: '',
clickToPlay: true, clickToPlay: true,
hideControls: true, hideControls: true,
showPosterOnEnd: false,
tooltips: { tooltips: {
controls: false, controls: false,
seek: true seek: true
@ -131,7 +132,7 @@
frameTitle: 'Player for {title}' frameTitle: 'Player for {title}'
}, },
types: { types: {
embed: ['youtube', 'vimeo'], embed: ['youtube', 'vimeo', 'soundcloud'],
html5: ['video', 'audio'] html5: ['video', 'audio']
}, },
// URLs // URLs
@ -141,6 +142,9 @@
}, },
youtube: { youtube: {
api: 'https://www.youtube.com/iframe_api' api: 'https://www.youtube.com/iframe_api'
},
soundcloud: {
api: 'https://w.soundcloud.com/player/api.js'
} }
}, },
// Custom control listeners // Custom control listeners
@ -333,7 +337,7 @@
// Remove an element // Remove an element
function _remove(element) { function _remove(element) {
if(!element) { if (!element) {
return; return;
} }
element.parentNode.removeChild(element); element.parentNode.removeChild(element);
@ -411,7 +415,7 @@
// Bind along with custom handler // Bind along with custom handler
function _proxyListener(element, eventName, userListener, defaultListener, useCapture) { function _proxyListener(element, eventName, userListener, defaultListener, useCapture) {
_on(element, eventName, function(event) { _on(element, eventName, function(event) {
if(userListener) { if (userListener) {
userListener.apply(element, [event]); userListener.apply(element, [event]);
} }
defaultListener.apply(element, [event]); defaultListener.apply(element, [event]);
@ -424,7 +428,7 @@
// Whether the listener is a capturing listener or not // Whether the listener is a capturing listener or not
// Default to false // Default to false
if(typeof useCapture !== 'boolean') { if (typeof useCapture !== 'boolean') {
useCapture = false; useCapture = false;
} }
@ -445,14 +449,22 @@
} }
// Trigger event // Trigger event
function _triggerEvent(element, eventName, properties) { function _triggerEvent(element, eventName, bubbles, properties) {
// Bail if no element // Bail if no element
if(!element || !eventName) { if (!element || !eventName) {
return; return;
} }
// create and dispatch the event // Default bubbles to false
var event = new CustomEvent(eventName, properties); if (typeof bubbles !== 'boolean') {
bubbles = false;
}
// Create and dispatch the event
var event = new CustomEvent(eventName, {
bubbles: bubbles,
detail: properties
});
// Dispatch the event // Dispatch the event
element.dispatchEvent(event); element.dispatchEvent(event);
@ -462,7 +474,7 @@
// http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles
function _toggleState(target, state) { function _toggleState(target, state) {
// Bail if no target // Bail if no target
if(!target) { if (!target) {
return; return;
} }
@ -491,12 +503,12 @@
var objects = arguments; var objects = arguments;
// Bail if nothing to merge // Bail if nothing to merge
if(!objects.length) { if (!objects.length) {
return; return;
} }
// Return first if specified but nothing to merge // Return first if specified but nothing to merge
if(objects.lenth == 1) { if (objects.lenth == 1) {
return objects[0]; return objects[0];
} }
@ -597,7 +609,7 @@
function _storage() { function _storage() {
var storage = { var storage = {
supported: (function() { supported: (function() {
if(!('localStorage' in window)) { if (!('localStorage' in window)) {
return false; return false;
} }
@ -943,7 +955,7 @@
index = 0; index = 0;
// Incase caption numbers are added // Incase caption numbers are added
if(parts[index].indexOf(":") === -1) { if (parts[index].indexOf(":") === -1) {
index = 1; index = 1;
} }
@ -971,6 +983,7 @@
// Set the current caption // Set the current caption
function _setCaption(caption) { function _setCaption(caption) {
/* jshint unused:false */
var container = _getElement(config.selectors.captions), var container = _getElement(config.selectors.captions),
content = document.createElement('span'); content = document.createElement('span');
@ -978,12 +991,12 @@
container.innerHTML = ''; container.innerHTML = '';
// Default to empty // Default to empty
if(typeof caption === 'undefined') { if (typeof caption === 'undefined') {
caption = ''; caption = '';
} }
// Set the span content // Set the span content
if(typeof caption === 'string') { if (typeof caption === 'string') {
content.innerHTML = caption.trim(); content.innerHTML = caption.trim();
} }
else { else {
@ -993,7 +1006,7 @@
// Set new caption text // Set new caption text
container.appendChild(content); container.appendChild(content);
// Force redraw // Force redraw (for Safari)
var redraw = container.offsetHeight; var redraw = container.offsetHeight;
} }
@ -1170,7 +1183,7 @@
if (config.selectors.controls.container !== null) { if (config.selectors.controls.container !== null) {
container = config.selectors.controls.container; container = config.selectors.controls.container;
if(typeof selector === 'string') { if (typeof selector === 'string') {
container = document.querySelector(container); container = document.querySelector(container);
} }
} }
@ -1259,7 +1272,7 @@
// Toggle native controls // Toggle native controls
function _toggleNativeControls(toggle) { function _toggleNativeControls(toggle) {
if(toggle) { if (toggle) {
plyr.media.setAttribute('controls', ''); plyr.media.setAttribute('controls', '');
} }
else { else {
@ -1344,7 +1357,7 @@
// Setup YouTube/Vimeo // Setup YouTube/Vimeo
function _setupEmbed() { function _setupEmbed() {
var container = document.createElement('div'), var container = document.createElement('div'),
videoId = plyr.embedId, mediaId = plyr.embedId,
id = plyr.type + '-' + Math.floor(Math.random() * (10000)); id = plyr.type + '-' + Math.floor(Math.random() * (10000));
// Remove old containers // Remove old containers
@ -1367,7 +1380,7 @@
// Setup API // Setup API
if (typeof YT === 'object') { if (typeof YT === 'object') {
_youTubeReady(videoId, container); _youTubeReady(mediaId, container);
} }
else { else {
// Load the API // Load the API
@ -1377,7 +1390,7 @@
window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || []; window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];
// Add to queue // Add to queue
window.onYouTubeReadyCallbacks.push(function() { _youTubeReady(videoId, container) }); window.onYouTubeReadyCallbacks.push(function() { _youTubeReady(mediaId, container) });
// Set callback to process queue // Set callback to process queue
window.onYouTubeIframeAPIReady = function () { window.onYouTubeIframeAPIReady = function () {
@ -1388,14 +1401,14 @@
// Vimeo // Vimeo
else if (plyr.type === 'vimeo') { else if (plyr.type === 'vimeo') {
// Inject the iframe // Inject the iframe
var iframe = document.createElement('iframe'); var vimeo = document.createElement('iframe');
// Watch for iframe load // Watch for iframe load
iframe.loaded = false; vimeo.loaded = false;
_on(iframe, 'load', function() { iframe.loaded = true; }); _on(vimeo, 'load', function() { vimeo.loaded = true; });
_setAttributes(iframe, { _setAttributes(vimeo, {
'src': 'https://player.vimeo.com/video/' + videoId + '?player_id=' + id + '&api=1&badge=0&byline=0&portrait=0&title=0', 'src': 'https://player.vimeo.com/video/' + mediaId + '?player_id=' + id + '&api=1&badge=0&byline=0&portrait=0&title=0',
'id': id, 'id': id,
'webkitallowfullscreen': '', 'webkitallowfullscreen': '',
'mozallowfullscreen': '', 'mozallowfullscreen': '',
@ -1404,24 +1417,54 @@
}); });
// If full support, we can use custom controls (hiding Vimeos), if not, use Vimeo // If full support, we can use custom controls (hiding Vimeos), if not, use Vimeo
if(plyr.supported.full) { if (plyr.supported.full) {
container.appendChild(iframe); container.appendChild(vimeo);
plyr.media.appendChild(container); plyr.media.appendChild(container);
} }
else { else {
plyr.media.appendChild(iframe); plyr.media.appendChild(vimeo);
} }
// Load the API // Load the API if not already
if (!('$f' in window)) { if (!('$f' in window)) {
_injectScript(config.urls.vimeo.api); _injectScript(config.urls.vimeo.api);
} }
// Wait for fragaloop load // Wait for fragaloop load
var timer = window.setInterval(function() { var vimeoTimer = window.setInterval(function() {
if ('$f' in window && iframe.loaded) { if ('$f' in window && vimeo.loaded) {
window.clearInterval(timer); window.clearInterval(vimeoTimer);
_vimeoReady.call(iframe); _vimeoReady.call(vimeo);
}
}, 50);
}
// Soundcloud
else if (plyr.type === 'soundcloud') {
// Inject the iframe
var soundCloud = document.createElement('iframe');
// Watch for iframe load
soundCloud.loaded = false;
_on(soundCloud, 'load', function() { soundCloud.loaded = true; });
_setAttributes(soundCloud, {
'src': 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/' + mediaId,
'id': id
});
container.appendChild(soundCloud);
plyr.media.appendChild(container);
// Load the API if not already
if (!window.SC) {
_injectScript(config.urls.soundcloud.api);
}
// Wait for SC load
var soundCloudTimer = window.setInterval(function() {
if (window.SC && soundCloud.loaded) {
window.clearInterval(soundCloudTimer);
_soundcloudReady.call(soundCloud);
} }
}, 50); }, 50);
} }
@ -1452,19 +1495,25 @@
plyr.embed = new YT.Player(container.id, { plyr.embed = new YT.Player(container.id, {
videoId: videoId, videoId: videoId,
playerVars: { playerVars: {
autoplay: (config.autoplay ? 1 : 0), autoplay: (config.autoplay ? 1 : 0),
controls: (plyr.supported.full ? 0 : 1), controls: (plyr.supported.full ? 0 : 1),
rel: 0, rel: 0,
showinfo: 0, showinfo: 0,
iv_load_policy: 3, iv_load_policy: 3,
cc_load_policy: (config.captions.defaultActive ? 1 : 0), cc_load_policy: (config.captions.defaultActive ? 1 : 0),
cc_lang_pref: 'en', cc_lang_pref: 'en',
wmode: 'transparent', wmode: 'transparent',
modestbranding: 1, modestbranding: 1,
disablekb: 1, disablekb: 1,
origin: '*' // https://code.google.com/p/gdata-issues/issues/detail?id=5788#c45 origin: '*' // https://code.google.com/p/gdata-issues/issues/detail?id=5788#c45
}, },
events: { events: {
'onError': function(event) {
_triggerEvent(plyr.container, 'error', true, {
code: event.data,
embed: event.target
});
},
'onReady': function(event) { 'onReady': function(event) {
// Get the instance // Get the instance
var instance = event.target; var instance = event.target;
@ -1628,7 +1677,7 @@
plyr.media.buffered = data.percent; plyr.media.buffered = data.percent;
_triggerEvent(plyr.media, 'progress'); _triggerEvent(plyr.media, 'progress');
if(parseInt(data.percent) === 1) { if (parseInt(data.percent) === 1) {
// Trigger event // Trigger event
_triggerEvent(plyr.media, 'canplaythrough'); _triggerEvent(plyr.media, 'canplaythrough');
} }
@ -1649,16 +1698,95 @@
}); });
} }
// Soundcloud ready
function _soundcloudReady() {
/* jshint validthis: true */
plyr.embed = window.SC.Widget(this);
// Setup on ready
plyr.embed.bind(window.SC.Widget.Events.READY, function() {
// Create a faux HTML5 API using the Soundcloud API
plyr.media.play = function() {
plyr.embed.play();
plyr.media.paused = false;
};
plyr.media.pause = function() {
plyr.embed.pause();
plyr.media.paused = true;
};
plyr.media.stop = function() {
plyr.embed.seekTo(0);
plyr.embed.pause();
plyr.media.paused = true;
};
plyr.media.paused = true;
plyr.media.currentTime = 0;
// Update UI
_embedReady();
plyr.embed.getPosition(function(value) {
plyr.media.currentTime = value;
// Trigger timeupdate
_triggerEvent(plyr.media, 'timeupdate');
});
plyr.embed.getDuration(function(value) {
plyr.media.duration = value/1000;
// Display duration if available
_displayDuration();
});
plyr.embed.bind(window.SC.Widget.Events.PLAY, function() {
plyr.media.paused = false;
_triggerEvent(plyr.media, 'play');
_triggerEvent(plyr.media, 'playing');
});
plyr.embed.bind(window.SC.Widget.Events.PAUSE, function() {
plyr.media.paused = true;
_triggerEvent(plyr.media, 'pause');
});
plyr.embed.bind(window.SC.Widget.Events.PLAY_PROGRESS, function(data) {
plyr.media.seeking = false;
plyr.media.currentTime = data.currentPosition/1000;
_triggerEvent(plyr.media, 'timeupdate');
});
plyr.embed.bind(window.SC.Widget.Events.LOAD_PROGRESS, function(data) {
plyr.media.buffered = data.loadProgress;
_triggerEvent(plyr.media, 'progress');
if (parseInt(data.loadProgress) === 1) {
// Trigger event
_triggerEvent(plyr.media, 'canplaythrough');
}
});
plyr.embed.bind(window.SC.Widget.Events.FINISH, function() {
plyr.media.paused = true;
_triggerEvent(plyr.media, 'ended');
});
// Autoplay
if (config.autoplay) {
plyr.embed.play();
}
});
}
// Play media // Play media
function _play() { function _play() {
if('play' in plyr.media) { if ('play' in plyr.media) {
plyr.media.play(); plyr.media.play();
} }
} }
// Pause media // Pause media
function _pause() { function _pause() {
if('pause' in plyr.media) { if ('pause' in plyr.media) {
plyr.media.pause(); plyr.media.pause();
} }
} }
@ -1700,9 +1828,9 @@
// Seek to time // Seek to time
// The input parameter can be an event or a number // The input parameter can be an event or a number
function _seek(input) { function _seek(input) {
var targetTime = 0, var targetTime = 0,
paused = plyr.media.paused, paused = plyr.media.paused,
duration = _getDuration(); duration = _getDuration();
// Explicit position // Explicit position
if (typeof input === 'number') { if (typeof input === 'number') {
@ -1723,10 +1851,8 @@
targetTime = duration; targetTime = duration;
} }
// Update progress // Update seek range and progress
if(plyr.progress && plyr.progress.played) { _updateSeekDisplay(targetTime);
plyr.progress.played.value = ((100 / duration) * targetTime);
}
// Set the current time // Set the current time
// Try/catch incase the media isn't set and we're calling seek() from source() and IE moans // Try/catch incase the media isn't set and we're calling seek() from source() and IE moans
@ -1736,7 +1862,7 @@
catch(e) {} catch(e) {}
// Embeds // Embeds
if(_inArray(config.types.embed, plyr.type)) { if (_inArray(config.types.embed, plyr.type)) {
// YouTube // YouTube
switch(plyr.type) { switch(plyr.type) {
case 'youtube': case 'youtube':
@ -1747,6 +1873,10 @@
// Round to nearest second for vimeo // Round to nearest second for vimeo
plyr.embed.api('seekTo', targetTime.toFixed(0)); plyr.embed.api('seekTo', targetTime.toFixed(0));
break; break;
case 'soundcloud':
plyr.embed.seekTo(targetTime * 1000);
break;
} }
if (paused) { if (paused) {
@ -1770,10 +1900,18 @@
// Get the duration (or custom if set) // Get the duration (or custom if set)
function _getDuration() { function _getDuration() {
// It should be a number, but parse it just incase // It should be a number, but parse it just incase
var duration = parseInt(config.duration); var duration = parseInt(config.duration),
// True duration
mediaDuration = 0;
// Only if duration available
if(plyr.media.duration !== null && !isNaN(plyr.media.duration)) {
mediaDuration = plyr.media.duration;
}
// If custom duration is funky, use regular duration // If custom duration is funky, use regular duration
return (isNaN(duration) ? plyr.media.duration : duration); return (isNaN(duration) ? mediaDuration : duration);
} }
// Check playing state // Check playing state
@ -1826,7 +1964,7 @@
_toggleClass(plyr.container, config.classes.fullscreen.active, plyr.isFullscreen); _toggleClass(plyr.container, config.classes.fullscreen.active, plyr.isFullscreen);
// Trap focus // Trap focus
if(plyr.isFullscreen) { if (plyr.isFullscreen) {
plyr.container.setAttribute('tabindex', '-1'); plyr.container.setAttribute('tabindex', '-1');
} }
else { else {
@ -1865,12 +2003,12 @@
plyr.media.muted = muted; plyr.media.muted = muted;
// If volume is 0 after unmuting, set to default // If volume is 0 after unmuting, set to default
if(plyr.media.volume === 0) { if (plyr.media.volume === 0) {
_setVolume(config.volume); _setVolume(config.volume);
} }
// Embeds // Embeds
if(_inArray(config.types.embed, plyr.type)) { if (_inArray(config.types.embed, plyr.type)) {
// YouTube // YouTube
switch(plyr.type) { switch(plyr.type) {
case 'youtube': case 'youtube':
@ -1880,6 +2018,10 @@
case 'vimeo': case 'vimeo':
plyr.embed.api('setVolume', plyr.media.muted ? 0 : parseFloat(config.volume / 10)); plyr.embed.api('setVolume', plyr.media.muted ? 0 : parseFloat(config.volume / 10));
break; break;
case 'soundcloud':
plyr.embed.setVolume(plyr.media.muted ? 0 : parseFloat(config.volume / 10));
break;
} }
// Trigger volumechange for embeds // Trigger volumechange for embeds
@ -1903,7 +2045,7 @@
} }
// Use config if all else fails // Use config if all else fails
if(volume === null || isNaN(volume)) { if (volume === null || isNaN(volume)) {
volume = config.volume; volume = config.volume;
} }
@ -1925,7 +2067,7 @@
} }
// Embeds // Embeds
if(_inArray(config.types.embed, plyr.type)) { if (_inArray(config.types.embed, plyr.type)) {
// YouTube // YouTube
switch(plyr.type) { switch(plyr.type) {
case 'youtube': case 'youtube':
@ -1935,6 +2077,10 @@
case 'vimeo': case 'vimeo':
plyr.embed.api('setVolume', plyr.media.volume); plyr.embed.api('setVolume', plyr.media.volume);
break; break;
case 'soundcloud':
plyr.embed.setVolume(plyr.media.volume);
break;
} }
// Trigger volumechange for embeds // Trigger volumechange for embeds
@ -2017,7 +2163,6 @@
// Update <progress> elements // Update <progress> elements
function _updateProgress(event) { function _updateProgress(event) {
var progress = plyr.progress.played, var progress = plyr.progress.played,
text = false,
value = 0, value = 0,
duration = _getDuration(); duration = _getDuration();
@ -2038,8 +2183,7 @@
// Check buffer status // Check buffer status
case 'playing': case 'playing':
case 'progress': case 'progress':
progress = plyr.progress.buffer.bar; progress = plyr.progress.buffer;
text = plyr.progress.buffer.text;
value = (function() { value = (function() {
var buffered = plyr.media.buffered; var buffered = plyr.media.buffered;
@ -2060,11 +2204,27 @@
} }
// Set values // Set values
if (progress) { _setProgress(progress, value);
}
// Set <progress> value
function _setProgress(progress, value) {
if (typeof value === 'undefined') {
value = 0;
}
// One progress element passed
if (progress instanceof HTMLElement) {
progress.value = value; progress.value = value;
} }
if (text) { // Object of progress + text element
text.innerHTML = value; else {
if (progress.bar) {
progress.bar.value = value;
}
if (progress.text) {
progress.text.innerHTML = value;
}
} }
} }
@ -2124,7 +2284,7 @@
_updateTimeDisplay(plyr.media.currentTime, plyr.currentTime); _updateTimeDisplay(plyr.media.currentTime, plyr.currentTime);
// Ignore updates while seeking // Ignore updates while seeking
if(event && event.type == 'timeupdate' && plyr.media.seeking) { if (event && event.type == 'timeupdate' && plyr.media.seeking) {
return; return;
} }
@ -2132,10 +2292,33 @@
_updateProgress(event); _updateProgress(event);
} }
// Update seek range and progress
function _updateSeekDisplay(time) {
// Default to 0
if (typeof time !== 'number') {
time = 0;
}
var duration = _getDuration(),
value = _getPercentage(time, duration);
// Update progress
if (plyr.progress && plyr.progress.played) {
plyr.progress.played.value = value;
}
// Update seek range input
if (plyr.buttons && plyr.buttons.seek) {
plyr.buttons.seek.value = value;
}
}
// Update hover tooltip for seeking // Update hover tooltip for seeking
function _updateSeekTooltip(event) { function _updateSeekTooltip(event) {
var duration = _getDuration();
// Bail if setting not true // Bail if setting not true
if (!config.tooltips.seek || plyr.browser.touch || !plyr.progress.container) { if (!config.tooltips.seek || !plyr.progress.container || duration === 0) {
return; return;
} }
@ -2146,7 +2329,7 @@
// Determine percentage, if already visible // Determine percentage, if already visible
if (!event) { if (!event) {
if(_hasClass(plyr.progress.tooltip, visible)) { if (_hasClass(plyr.progress.tooltip, visible)) {
percent = plyr.progress.tooltip.style.left.replace('%', ''); percent = plyr.progress.tooltip.style.left.replace('%', '');
} }
else { else {
@ -2166,14 +2349,14 @@
} }
// Display the time a click would seek to // Display the time a click would seek to
_updateTimeDisplay(((_getDuration() / 100) * percent), plyr.progress.tooltip); _updateTimeDisplay(((duration / 100) * percent), plyr.progress.tooltip);
// Set position // Set position
plyr.progress.tooltip.style.left = percent + "%"; plyr.progress.tooltip.style.left = percent + "%";
// Show/hide the tooltip // Show/hide the tooltip
// If the event is a moues in/out and percentage is inside bounds // If the event is a moues in/out and percentage is inside bounds
if(event && _inArray(['mouseenter', 'mouseleave'], event.type)) { if (event && _inArray(['mouseenter', 'mouseleave'], event.type)) {
_toggleClass(plyr.progress.tooltip, visible, (event.type === 'mouseenter')); _toggleClass(plyr.progress.tooltip, visible, (event.type === 'mouseenter'));
} }
} }
@ -2188,8 +2371,8 @@
show = toggle; show = toggle;
// Default to false if no boolean // Default to false if no boolean
if(typeof toggle !== "boolean") { if (typeof toggle !== "boolean") {
if(toggle && toggle.type) { if (toggle && toggle.type) {
// Is the enter fullscreen event // Is the enter fullscreen event
isEnterFullscreen = (toggle.type === 'enterfullscreen'); isEnterFullscreen = (toggle.type === 'enterfullscreen');
@ -2215,21 +2398,21 @@
window.clearTimeout(plyr.timers.hover); window.clearTimeout(plyr.timers.hover);
// If the mouse is not over the controls, set a timeout to hide them // If the mouse is not over the controls, set a timeout to hide them
if(show || plyr.media.paused) { if (show || plyr.media.paused) {
_toggleClass(plyr.container, config.classes.hideControls, false); _toggleClass(plyr.container, config.classes.hideControls, false);
// Always show controls when paused // Always show controls when paused
if(plyr.media.paused) { if (plyr.media.paused) {
return; return;
} }
} }
// If toggle is false or if we're playing (regardless of toggle), then // If toggle is false or if we're playing (regardless of toggle), then
// set the timer to hide the controls // set the timer to hide the controls
if(!show || !plyr.media.paused) { if (!show || !plyr.media.paused) {
plyr.timers.hover = window.setTimeout(function() { plyr.timers.hover = window.setTimeout(function() {
// If the mouse is over the controls (and not entering fullscreen), bail // If the mouse is over the controls (and not entering fullscreen), bail
if(plyr.controls.active && !isEnterFullscreen) { if (plyr.controls.active && !isEnterFullscreen) {
return; return;
} }
@ -2241,7 +2424,7 @@
// Add common function to retrieve media source // Add common function to retrieve media source
function _source(source) { function _source(source) {
// If not null or undefined, parse it // If not null or undefined, parse it
if(typeof source !== 'undefined') { if (typeof source !== 'undefined') {
_updateSource(source); _updateSource(source);
return; return;
} }
@ -2259,6 +2442,12 @@
}); });
break; break;
case 'soundcloud':
plyr.embed.getCurrentSound(function(object) {
url = object.permalink_url;
});
break;
default: default:
url = plyr.media.currentSrc; url = plyr.media.currentSrc;
break; break;
@ -2278,13 +2467,14 @@
// Pause playback // Pause playback
_pause(); _pause();
// Set seek input to 0 // Update seek range and progress
if (plyr.buttons && plyr.buttons.seek) { _updateSeekDisplay();
plyr.buttons.seek.value = 0;
} // Reset buffer progress
if (plyr.progress && plyr.progress.played) { _setProgress(plyr.progress.buffer);
plyr.progress.played.value = 0;
} // Cancel current network requests
_cancelRequests();
// Clean up YouTube stuff // Clean up YouTube stuff
if (plyr.type === 'youtube') { if (plyr.type === 'youtube') {
@ -2295,6 +2485,7 @@
window.clearInterval(plyr.timer.buffering); window.clearInterval(plyr.timer.buffering);
window.clearInterval(plyr.timer.playing); window.clearInterval(plyr.timer.playing);
} }
// HTML5 Video
else if (plyr.type === 'video' && plyr.videoContainer) { else if (plyr.type === 'video' && plyr.videoContainer) {
// Remove video wrapper // Remove video wrapper
_remove(plyr.videoContainer); _remove(plyr.videoContainer);
@ -2303,9 +2494,6 @@
// Remove embed object // Remove embed object
plyr.embed = null; plyr.embed = null;
// Cancel current network requests
_cancelRequests();
// Remove the old media // Remove the old media
_remove(plyr.media); _remove(plyr.media);
@ -2314,10 +2502,10 @@
plyr.type = source.type; plyr.type = source.type;
// Get child type for video (it might be an embed) // Get child type for video (it might be an embed)
if(plyr.type === 'video') { if (plyr.type === 'video') {
var firstSource = source.sources[0]; var firstSource = source.sources[0];
if('type' in firstSource && _inArray(config.types.embed, firstSource.type)) { if ('type' in firstSource && _inArray(config.types.embed, firstSource.type)) {
plyr.type = firstSource.type; plyr.type = firstSource.type;
} }
} }
@ -2338,6 +2526,7 @@
case 'youtube': case 'youtube':
case 'vimeo': case 'vimeo':
case 'soundcloud':
plyr.media = document.createElement('div'); plyr.media = document.createElement('div');
plyr.embedId = source.sources[0].src; plyr.embedId = source.sources[0].src;
break; break;
@ -2437,7 +2626,7 @@
target = plyr.buttons[play ? 'pause' : 'play']; target = plyr.buttons[play ? 'pause' : 'play'];
// Get the last play button to account for the large play button // Get the last play button to account for the large play button
if(target && target.length > 1) { if (target && target.length > 1) {
target = target[target.length - 1]; target = target[target.length - 1];
} }
else { else {
@ -2445,13 +2634,13 @@
} }
// Setup focus and tab focus // Setup focus and tab focus
if(target) { if (target) {
var hadTabFocus = _hasClass(trigger, config.classes.tabFocus); var hadTabFocus = _hasClass(trigger, config.classes.tabFocus);
setTimeout(function() { setTimeout(function() {
target.focus(); target.focus();
if(hadTabFocus) { if (hadTabFocus) {
_toggleClass(trigger, config.classes.tabFocus, false); _toggleClass(trigger, config.classes.tabFocus, false);
_toggleClass(target, config.classes.tabFocus, true); _toggleClass(target, config.classes.tabFocus, true);
} }
@ -2575,6 +2764,15 @@
// Reset UI // Reset UI
_checkPlaying(); _checkPlaying();
// Show poster on end
if(config.showPosterOnEnd) {
// Seek to 0
_seek(0);
// Re-load media
plyr.media.load();
}
}); });
// Check for buffer progress // Check for buffer progress
@ -2595,7 +2793,7 @@
var wrapper = _getElement('.' + config.classes.videoWrapper); var wrapper = _getElement('.' + config.classes.videoWrapper);
// Bail if there's no wrapper (this should never happen) // Bail if there's no wrapper (this should never happen)
if(!wrapper) { if (!wrapper) {
return; return;
} }
@ -2619,26 +2817,29 @@
// Proxy events to container // Proxy events to container
_on(plyr.media, config.events.join(' '), function(event) { _on(plyr.media, config.events.join(' '), function(event) {
_triggerEvent(plyr.container, event.type); _triggerEvent(plyr.container, event.type, true);
}); });
} }
// Cancel current network requests // Cancel current network requests
// See https://github.com/Selz/plyr/issues/174 // See https://github.com/Selz/plyr/issues/174
function _cancelRequests() { function _cancelRequests() {
if(!_inArray(config.types.html5, plyr.type)) { if (!_inArray(config.types.html5, plyr.type)) {
return; return;
} }
// Set empty src attribute
plyr.media.setAttribute('src', '');
// Remove child sources // Remove child sources
var sources = plyr.media.querySelectorAll('source'); var sources = plyr.media.querySelectorAll('source');
for (var i = 0; i < sources.length; i++) { for (var i = 0; i < sources.length; i++) {
_remove(sources[i]); _remove(sources[i]);
} }
// Set blank video src attribute
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
// Small mp4: https://github.com/mathiasbynens/small/blob/master/mp4.mp4
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
plyr.media.setAttribute('src', 'data:video/mp4;base64,AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAGm1kYXQAAAGzABAHAAABthBgUYI9t+8AAAMNbW9vdgAAAGxtdmhkAAAAAMXMvvrFzL76AAAD6AAAACoAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAABhpb2RzAAAAABCAgIAHAE/////+/wAAAiF0cmFrAAAAXHRraGQAAAAPxcy++sXMvvoAAAABAAAAAAAAACoAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAgAAAAIAAAAAAG9bWRpYQAAACBtZGhkAAAAAMXMvvrFzL76AAAAGAAAAAEVxwAAAAAALWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAABaG1pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAShzdGJsAAAAxHN0c2QAAAAAAAAAAQAAALRtcDR2AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAgACABIAAAASAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGP//AAAAXmVzZHMAAAAAA4CAgE0AAQAEgICAPyARAAAAAAMNQAAAAAAFgICALQAAAbABAAABtYkTAAABAAAAASAAxI2IAMUARAEUQwAAAbJMYXZjNTMuMzUuMAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAAABAAAAAQAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAASAAAAAQAAABRzdGNvAAAAAAAAAAEAAAAsAAAAYHVkdGEAAABYbWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcmFwcGwAAAAAAAAAAAAAAAAraWxzdAAAACOpdG9vAAAAG2RhdGEAAAABAAAAAExhdmY1My4yMS4x');
// Load the new empty source // Load the new empty source
// This will cancel existing requests // This will cancel existing requests
// See https://github.com/Selz/plyr/issues/174 // See https://github.com/Selz/plyr/issues/174
@ -2707,12 +2908,12 @@
plyr.media = plyr.container.querySelectorAll('audio, video')[0]; plyr.media = plyr.container.querySelectorAll('audio, video')[0];
// Get the div placeholder for YouTube and Vimeo // Get the div placeholder for YouTube and Vimeo
if(!plyr.media) { if (!plyr.media) {
plyr.media = plyr.container.querySelectorAll('div')[0]; plyr.media = plyr.container.querySelectorAll('div')[0];
} }
// Bail if nothing to setup // Bail if nothing to setup
if(!plyr.media) { if (!plyr.media) {
return; return;
} }
@ -2897,6 +3098,7 @@
case 'vimeo': case 'vimeo':
case 'youtube': case 'youtube':
case 'soundcloud':
basic = true; basic = true;
full = (!oldIE && !iPhone); full = (!oldIE && !iPhone);
break; break;
@ -2954,7 +3156,7 @@
var config = _extend(defaults, options, JSON.parse(element.getAttribute("data-plyr"))); var config = _extend(defaults, options, JSON.parse(element.getAttribute("data-plyr")));
// Bail if not enabled // Bail if not enabled
if(!config.enabled) { if (!config.enabled) {
return; return;
} }

View File

@ -201,12 +201,13 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
padding: (@plyr-control-spacing * 2) (@plyr-control-spacing * 2) (@plyr-control-spacing * 8); padding: (@plyr-control-spacing * 2);
transform: translateY(-(@plyr-control-spacing * 6));
transition: transform .3s ease;
color: #fff; color: #fff;
font-size: @plyr-font-size-captions-base; font-size: @plyr-font-size-captions-base;
text-align: center; text-align: center;
font-weight: 400; font-weight: 400;
-webkit-font-smoothing: subpixel-antialiased;
span { span {
border-radius: 2px; border-radius: 2px;
@ -227,6 +228,9 @@
.plyr--fullscreen-active .plyr__captions { .plyr--fullscreen-active .plyr__captions {
font-size: @plyr-font-size-captions-large; font-size: @plyr-font-size-captions-large;
} }
.plyr--hide-controls .plyr__captions {
transform: translateY(-(@plyr-control-spacing * 2));
}
// Controls // Controls
// -------------------------------------------------------------- // --------------------------------------------------------------
@ -436,7 +440,6 @@
color: @plyr-tooltip-color; color: @plyr-tooltip-color;
font-size: @plyr-font-size-small; font-size: @plyr-font-size-small;
line-height: 1.3; line-height: 1.3;
-webkit-font-smoothing: subpixel-antialiased;
transform: translate(-50%, 10px) scale(.8); transform: translate(-50%, 10px) scale(.8);
transform-origin: 50% 100%; transform-origin: 50% 100%;
@ -498,9 +501,9 @@
} }
} }
.plyr__progress--buffer[value], .plyr__progress--buffer,
.plyr__progress--played[value], .plyr__progress--played,
.plyr__volume--display[value] { .plyr__volume--display {
position: absolute; position: absolute;
left: 0; left: 0;
top: 50%; top: 50%;
@ -530,8 +533,8 @@
border-radius: 100px; border-radius: 100px;
} }
} }
.plyr__progress--played[value], .plyr__progress--played,
.plyr__volume--display[value] { .plyr__volume--display {
z-index: 1; z-index: 1;
color: @plyr-range-selected-bg; color: @plyr-range-selected-bg;
background: transparent; background: transparent;
@ -553,7 +556,7 @@
display: none; display: none;
} }
} }
.plyr__progress--buffer[value] { .plyr__progress--buffer {
&::-webkit-progress-value { &::-webkit-progress-value {
transition: width .2s ease; transition: width .2s ease;
} }
@ -564,18 +567,18 @@
transition: width .2s ease; transition: width .2s ease;
} }
} }
.plyr--video .plyr__progress--buffer[value], .plyr--video .plyr__progress--buffer,
.plyr--video .plyr__volume--display[value] { .plyr--video .plyr__volume--display {
background: @plyr-video-range-track-bg; background: @plyr-video-range-track-bg;
} }
.plyr--video .plyr__progress--buffer[value] { .plyr--video .plyr__progress--buffer {
color: @plyr-video-progress-buffered-bg; color: @plyr-video-progress-buffered-bg;
} }
.plyr--audio .plyr__progress--buffer[value], .plyr--audio .plyr__progress--buffer,
.plyr--audio .plyr__volume--display[value] { .plyr--audio .plyr__volume--display {
background: @plyr-audio-range-track-bg; background: @plyr-audio-range-track-bg;
} }
.plyr--audio .plyr__progress--buffer[value] { .plyr--audio .plyr__progress--buffer {
color: @plyr-audio-progress-buffered-bg; color: @plyr-audio-progress-buffered-bg;
} }
@ -609,7 +612,6 @@
vertical-align: middle; vertical-align: middle;
font-size: @plyr-font-size-small; font-size: @plyr-font-size-small;
line-height: .95; line-height: .95;
-webkit-font-smoothing: subpixel-antialiased;
} }
// Media duration hidden on small screens // Media duration hidden on small screens
.plyr__time + .plyr__time { .plyr__time + .plyr__time {

View File

@ -201,12 +201,13 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
padding: ($plyr-control-spacing * 2) ($plyr-control-spacing * 2) ($plyr-control-spacing * 8); padding: ($plyr-control-spacing * 2);
transform: translateY(-($plyr-control-spacing * 6));
transition: transform .3s ease;
color: #fff; color: #fff;
font-size: $plyr-font-size-captions-base; font-size: $plyr-font-size-captions-base;
text-align: center; text-align: center;
font-weight: 400; font-weight: 400;
-webkit-font-smoothing: subpixel-antialiased;
span { span {
border-radius: 2px; border-radius: 2px;
@ -227,6 +228,9 @@
.plyr--fullscreen-active .plyr__captions { .plyr--fullscreen-active .plyr__captions {
font-size: $plyr-font-size-captions-large; font-size: $plyr-font-size-captions-large;
} }
.plyr--hide-controls .plyr__captions {
transform: translateY(-($plyr-control-spacing * 2));
}
// Controls // Controls
// -------------------------------------------------------------- // --------------------------------------------------------------
@ -436,7 +440,6 @@
color: $plyr-tooltip-color; color: $plyr-tooltip-color;
font-size: $plyr-font-size-small; font-size: $plyr-font-size-small;
line-height: 1.3; line-height: 1.3;
-webkit-font-smoothing: subpixel-antialiased;
transform: translate(-50%, 10px) scale(.8); transform: translate(-50%, 10px) scale(.8);
transform-origin: 50% 100%; transform-origin: 50% 100%;
@ -498,9 +501,9 @@
} }
} }
.plyr__progress--buffer[value], .plyr__progress--buffer,
.plyr__progress--played[value], .plyr__progress--played,
.plyr__volume--display[value] { .plyr__volume--display {
position: absolute; position: absolute;
left: 0; left: 0;
top: 50%; top: 50%;
@ -530,8 +533,8 @@
border-radius: 100px; border-radius: 100px;
} }
} }
.plyr__progress--played[value], .plyr__progress--played,
.plyr__volume--display[value] { .plyr__volume--display {
z-index: 1; z-index: 1;
color: $plyr-range-selected-bg; color: $plyr-range-selected-bg;
background: transparent; background: transparent;
@ -553,7 +556,7 @@
display: none; display: none;
} }
} }
.plyr__progress--buffer[value] { .plyr__progress--buffer {
&::-webkit-progress-value { &::-webkit-progress-value {
transition: width .2s ease; transition: width .2s ease;
} }
@ -564,18 +567,18 @@
transition: width .2s ease; transition: width .2s ease;
} }
} }
.plyr--video .plyr__progress--buffer[value], .plyr--video .plyr__progress--buffer,
.plyr--video .plyr__volume--display[value] { .plyr--video .plyr__volume--display {
background: $plyr-video-range-track-bg; background: $plyr-video-range-track-bg;
} }
.plyr--video .plyr__progress--buffer[value] { .plyr--video .plyr__progress--buffer {
color: $plyr-video-progress-buffered-bg; color: $plyr-video-progress-buffered-bg;
} }
.plyr--audio .plyr__progress--buffer[value], .plyr--audio .plyr__progress--buffer,
.plyr--audio .plyr__volume--display[value] { .plyr--audio .plyr__volume--display {
background: $plyr-audio-range-track-bg; background: $plyr-audio-range-track-bg;
} }
.plyr--audio .plyr__progress--buffer[value] { .plyr--audio .plyr__progress--buffer {
color: $plyr-audio-progress-buffered-bg; color: $plyr-audio-progress-buffered-bg;
} }
@ -609,7 +612,6 @@
vertical-align: middle; vertical-align: middle;
font-size: $plyr-font-size-small; font-size: $plyr-font-size-small;
line-height: .95; line-height: .95;
-webkit-font-smoothing: subpixel-antialiased;
} }
// Media duration hidden on small screens // Media duration hidden on small screens
.plyr__time + .plyr__time { .plyr__time + .plyr__time {