aboutsummaryrefslogtreecommitdiffstats
path: root/src/js/plugins/youtube.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/plugins/youtube.js')
-rw-r--r--src/js/plugins/youtube.js104
1 files changed, 60 insertions, 44 deletions
diff --git a/src/js/plugins/youtube.js b/src/js/plugins/youtube.js
index 9b067c8a..e486aa43 100644
--- a/src/js/plugins/youtube.js
+++ b/src/js/plugins/youtube.js
@@ -4,7 +4,24 @@
import controls from './../controls';
import ui from './../ui';
-import utils from './../utils';
+import { dedupe } from './../utils/arrays';
+import { createElement, replaceElement, toggleClass } from './../utils/elements';
+import { trigger } from './../utils/events';
+import fetch from './../utils/fetch';
+import is from './../utils/is';
+import loadImage from './../utils/loadImage';
+import loadScript from './../utils/loadScript';
+import { format, generateId } from './../utils/strings';
+
+// Parse YouTube ID from URL
+function parseId(url) {
+ if (is.empty(url)) {
+ return null;
+ }
+
+ const regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
+ return url.match(regex) ? RegExp.$2 : url;
+}
// Standardise YouTube quality unit
function mapQualityUnit(input) {
@@ -57,11 +74,11 @@ function mapQualityUnit(input) {
}
function mapQualityUnits(levels) {
- if (utils.is.empty(levels)) {
+ if (is.empty(levels)) {
return levels;
}
- return utils.dedupe(levels.map(level => mapQualityUnit(level)));
+ return dedupe(levels.map(level => mapQualityUnit(level)));
}
// Set playback state and trigger change (only on actual change)
@@ -71,24 +88,24 @@ function assurePlaybackState(play) {
}
if (this.media.paused === play) {
this.media.paused = !play;
- utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause');
+ trigger.call(this, this.media, play ? 'play' : 'pause');
}
}
const youtube = {
setup() {
// Add embed class for responsive
- utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);
+ toggleClass(this.elements.wrapper, this.config.classNames.embed, true);
// Set aspect ratio
youtube.setAspectRatio.call(this);
// Setup API
- if (utils.is.object(window.YT) && utils.is.function(window.YT.Player)) {
+ if (is.object(window.YT) && is.function(window.YT.Player)) {
youtube.ready.call(this);
} else {
// Load the API
- utils.loadScript(this.config.urls.youtube.sdk).catch(error => {
+ loadScript(this.config.urls.youtube.sdk).catch(error => {
this.debug.warn('YouTube API failed to load', error);
});
@@ -115,10 +132,10 @@ const youtube = {
// Try via undocumented API method first
// This method disappears now and then though...
// https://github.com/sampotts/plyr/issues/709
- if (utils.is.function(this.embed.getVideoData)) {
+ if (is.function(this.embed.getVideoData)) {
const { title } = this.embed.getVideoData();
- if (utils.is.empty(title)) {
+ if (is.empty(title)) {
this.config.title = title;
ui.setTitle.call(this);
return;
@@ -127,13 +144,12 @@ const youtube = {
// Or via Google API
const key = this.config.keys.google;
- if (utils.is.string(key) && !utils.is.empty(key)) {
- const url = utils.format(this.config.urls.youtube.api, videoId, key);
+ if (is.string(key) && !is.empty(key)) {
+ const url = format(this.config.urls.youtube.api, videoId, key);
- utils
- .fetch(url)
+ fetch(url)
.then(result => {
- if (utils.is.object(result)) {
+ if (is.object(result)) {
this.config.title = result.items[0].snippet.title;
ui.setTitle.call(this);
}
@@ -154,7 +170,7 @@ const youtube = {
// Ignore already setup (race condition)
const currentId = player.media.getAttribute('id');
- if (!utils.is.empty(currentId) && currentId.startsWith('youtube-')) {
+ if (!is.empty(currentId) && currentId.startsWith('youtube-')) {
return;
}
@@ -162,23 +178,23 @@ const youtube = {
let source = player.media.getAttribute('src');
// Get from <div> if needed
- if (utils.is.empty(source)) {
+ if (is.empty(source)) {
source = player.media.getAttribute(this.config.attributes.embed.id);
}
// Replace the <iframe> with a <div> due to YouTube API issues
- const videoId = utils.parseYouTubeId(source);
- const id = utils.generateId(player.provider);
- const container = utils.createElement('div', { id });
- player.media = utils.replaceElement(container, player.media);
+ const videoId = parseId(source);
+ const id = generateId(player.provider);
+ const container = createElement('div', { id });
+ player.media = replaceElement(container, player.media);
// Set poster image
const posterSrc = format => `https://img.youtube.com/vi/${videoId}/${format}default.jpg`;
// Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
- utils.loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
- .catch(() => utils.loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
- .catch(() => utils.loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
+ loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
+ .catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
+ .catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
.then(image => ui.setPoster.call(player, image.src))
.then(posterSrc => {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
@@ -213,7 +229,7 @@ const youtube = {
onError(event) {
// If we've already fired an error, don't do it again
// YouTube fires onError twice
- if (utils.is.object(player.media.error)) {
+ if (is.object(player.media.error)) {
return;
}
@@ -250,10 +266,10 @@ const youtube = {
player.media.error = detail;
- utils.dispatchEvent.call(player, player.media, 'error');
+ trigger.call(player, player.media, 'error');
},
onPlaybackQualityChange() {
- utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
+ trigger.call(player, player.media, 'qualitychange', false, {
quality: player.media.quality,
});
},
@@ -264,7 +280,7 @@ const youtube = {
// Get current speed
player.media.playbackRate = instance.getPlaybackRate();
- utils.dispatchEvent.call(player, player.media, 'ratechange');
+ trigger.call(player, player.media, 'ratechange');
},
onReady(event) {
// Get the instance
@@ -305,7 +321,7 @@ const youtube = {
// Set seeking state and trigger event
player.media.seeking = true;
- utils.dispatchEvent.call(player, player.media, 'seeking');
+ trigger.call(player, player.media, 'seeking');
// Seek after events sent
instance.seekTo(time);
@@ -334,7 +350,7 @@ const youtube = {
instance.setPlaybackQuality(mapQualityUnit(quality));
// Trigger request event
- utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
+ trigger.call(player, player.media, 'qualityrequested', false, {
quality,
});
},
@@ -349,7 +365,7 @@ const youtube = {
set(input) {
volume = input;
instance.setVolume(volume * 100);
- utils.dispatchEvent.call(player, player.media, 'volumechange');
+ trigger.call(player, player.media, 'volumechange');
},
});
@@ -360,10 +376,10 @@ const youtube = {
return muted;
},
set(input) {
- const toggle = utils.is.boolean(input) ? input : muted;
+ const toggle = is.boolean(input) ? input : muted;
muted = toggle;
instance[toggle ? 'mute' : 'unMute']();
- utils.dispatchEvent.call(player, player.media, 'volumechange');
+ trigger.call(player, player.media, 'volumechange');
},
});
@@ -389,8 +405,8 @@ const youtube = {
player.media.setAttribute('tabindex', -1);
}
- utils.dispatchEvent.call(player, player.media, 'timeupdate');
- utils.dispatchEvent.call(player, player.media, 'durationchange');
+ trigger.call(player, player.media, 'timeupdate');
+ trigger.call(player, player.media, 'durationchange');
// Reset timer
clearInterval(player.timers.buffering);
@@ -402,7 +418,7 @@ const youtube = {
// Trigger progress only when we actually buffer something
if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {
- utils.dispatchEvent.call(player, player.media, 'progress');
+ trigger.call(player, player.media, 'progress');
}
// Set last buffer point
@@ -413,7 +429,7 @@ const youtube = {
clearInterval(player.timers.buffering);
// Trigger event
- utils.dispatchEvent.call(player, player.media, 'canplaythrough');
+ trigger.call(player, player.media, 'canplaythrough');
}
}, 200);
@@ -435,7 +451,7 @@ const youtube = {
if (seeked) {
// Unset seeking and fire seeked event
player.media.seeking = false;
- utils.dispatchEvent.call(player, player.media, 'seeked');
+ trigger.call(player, player.media, 'seeked');
}
// Handle events
@@ -448,11 +464,11 @@ const youtube = {
switch (event.data) {
case -1:
// Update scrubber
- utils.dispatchEvent.call(player, player.media, 'timeupdate');
+ trigger.call(player, player.media, 'timeupdate');
// Get loaded % from YouTube
player.media.buffered = instance.getVideoLoadedFraction();
- utils.dispatchEvent.call(player, player.media, 'progress');
+ trigger.call(player, player.media, 'progress');
break;
@@ -465,7 +481,7 @@ const youtube = {
instance.stopVideo();
instance.playVideo();
} else {
- utils.dispatchEvent.call(player, player.media, 'ended');
+ trigger.call(player, player.media, 'ended');
}
break;
@@ -477,11 +493,11 @@ const youtube = {
} else {
assurePlaybackState.call(player, true);
- utils.dispatchEvent.call(player, player.media, 'playing');
+ trigger.call(player, player.media, 'playing');
// Poll to get playback progress
player.timers.playing = setInterval(() => {
- utils.dispatchEvent.call(player, player.media, 'timeupdate');
+ trigger.call(player, player.media, 'timeupdate');
}, 50);
// Check duration again due to YouTube bug
@@ -489,7 +505,7 @@ const youtube = {
// https://code.google.com/p/gdata-issues/issues/detail?id=8690
if (player.media.duration !== instance.getDuration()) {
player.media.duration = instance.getDuration();
- utils.dispatchEvent.call(player, player.media, 'durationchange');
+ trigger.call(player, player.media, 'durationchange');
}
// Get quality
@@ -511,7 +527,7 @@ const youtube = {
break;
}
- utils.dispatchEvent.call(player, player.elements.container, 'statechange', false, {
+ trigger.call(player, player.elements.container, 'statechange', false, {
code: event.data,
});
},