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.js256
1 files changed, 256 insertions, 0 deletions
diff --git a/src/js/plugins/youtube.js b/src/js/plugins/youtube.js
new file mode 100644
index 00000000..61e7adce
--- /dev/null
+++ b/src/js/plugins/youtube.js
@@ -0,0 +1,256 @@
+// ==========================================================================
+// YouTube plugin
+// ==========================================================================
+
+import utils from './../utils';
+import controls from './../controls';
+import ui from './../ui';
+
+/* Object.defineProperty(input, "value", {
+ get: function() {return this._value;},
+ set: function(v) {
+ // Do your stuff
+ this._value = v;
+ }
+}); */
+
+const youtube = {
+ // Setup YouTube
+ setup() {
+ const videoId = utils.parseYouTubeId(this.embedId);
+
+ // Remove old containers
+ const containers = utils.getElements.call(this, `[id^="${this.type}-"]`);
+ Array.from(containers).forEach(utils.removeElement);
+
+ // Add embed class for responsive
+ utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);
+
+ // Set ID
+ this.media.setAttribute('id', utils.generateId(this.type));
+
+ // Setup API
+ if (utils.is.object(window.YT)) {
+ youtube.ready.call(this, videoId);
+ } else {
+ // Load the API
+ utils.loadScript(this.config.urls.youtube.api);
+
+ // Setup callback for the API
+ window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];
+
+ // Add to queue
+ window.onYouTubeReadyCallbacks.push(() => {
+ youtube.ready.call(this, videoId);
+ });
+
+ // Set callback to process queue
+ window.onYouTubeIframeAPIReady = () => {
+ window.onYouTubeReadyCallbacks.forEach(callback => {
+ callback();
+ });
+ };
+ }
+ },
+
+ // Handle YouTube API ready
+ ready(videoId) {
+ const player = this;
+
+ // Setup instance
+ // https://developers.google.com/youtube/iframe_api_reference
+ player.embed = new window.YT.Player(player.media.id, {
+ videoId,
+ playerVars: {
+ autoplay: player.config.autoplay ? 1 : 0, // Autoplay
+ controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported
+ rel: 0, // No related vids
+ showinfo: 0, // Hide info
+ iv_load_policy: 3, // Hide annotations
+ modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused)
+ disablekb: 1, // Disable keyboard as we handle it
+ playsinline: 1, // Allow iOS inline playback
+
+ // Tracking for stats
+ origin: window && window.location.hostname,
+ widget_referrer: window && window.location.href,
+
+ // Captions is flaky on YouTube
+ // cc_load_policy: (this.captions.active ? 1 : 0),
+ // cc_lang_pref: 'en',
+ },
+ events: {
+ onError(event) {
+ utils.dispatchEvent.call(player, player.media, 'error', true, {
+ code: event.data,
+ embed: event.target,
+ });
+ },
+ onPlaybackQualityChange(event) {
+ // Get the instance
+ const instance = event.target;
+
+ // Get current quality
+ player.media.quality = instance.getPlaybackQuality();
+
+ utils.dispatchEvent.call(player, player.media, 'qualitychange');
+ },
+ onPlaybackRateChange(event) {
+ // Get the instance
+ const instance = event.target;
+
+ // Get current speed
+ player.media.playbackRate = instance.getPlaybackRate();
+
+ utils.dispatchEvent.call(player, player.media, 'ratechange');
+ },
+ onReady(event) {
+ // Get the instance
+ const instance = event.target;
+
+ // Create a faux HTML5 API using the YouTube API
+ player.media.play = () => {
+ instance.playVideo();
+ player.media.paused = false;
+ };
+ player.media.pause = () => {
+ instance.pauseVideo();
+ player.media.paused = true;
+ };
+ player.media.stop = () => {
+ instance.stopVideo();
+ player.media.paused = true;
+ };
+ player.media.duration = instance.getDuration();
+ player.media.paused = true;
+ player.media.muted = instance.isMuted();
+ player.media.currentTime = 0;
+
+ // Get available speeds
+ if (player.config.controls.includes('settings') && player.config.settings.includes('speed')) {
+ controls.setSpeedMenu.call(player, instance.getAvailablePlaybackRates());
+ }
+
+ // Set title
+ player.config.title = instance.getVideoData().title;
+
+ // Set the tabindex to avoid focus entering iframe
+ if (player.supported.ui) {
+ player.media.setAttribute('tabindex', -1);
+ }
+
+ // Rebuild UI
+ ui.build.call(player);
+
+ utils.dispatchEvent.call(player, player.media, 'timeupdate');
+ utils.dispatchEvent.call(player, player.media, 'durationchange');
+
+ // Reset timer
+ window.clearInterval(player.timers.buffering);
+
+ // Setup buffering
+ player.timers.buffering = window.setInterval(() => {
+ // Get loaded % from YouTube
+ player.media.buffered = instance.getVideoLoadedFraction();
+
+ // 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');
+ }
+
+ // Set last buffer point
+ player.media.lastBuffered = player.media.buffered;
+
+ // Bail if we're at 100%
+ if (player.media.buffered === 1) {
+ window.clearInterval(player.timers.buffering);
+
+ // Trigger event
+ utils.dispatchEvent.call(player, player.media, 'canplaythrough');
+ }
+ }, 200);
+ },
+ onStateChange(event) {
+ // Get the instance
+ const instance = event.target;
+
+ // Reset timer
+ window.clearInterval(player.timers.playing);
+
+ // Handle events
+ // -1 Unstarted
+ // 0 Ended
+ // 1 Playing
+ // 2 Paused
+ // 3 Buffering
+ // 5 Video cued
+ switch (event.data) {
+ case 0:
+ // YouTube doesn't support loop for a single video, so mimick it.
+ if (player.config.loop.active) {
+ // YouTube needs a call to `stopVideo` before playing again
+ instance.stopVideo();
+ instance.playVideo();
+
+ break;
+ }
+
+ player.media.paused = true;
+
+ utils.dispatchEvent.call(player, player.media, 'ended');
+
+ break;
+
+ case 1:
+ player.media.paused = false;
+
+ // If we were seeking, fire seeked event
+ if (player.media.seeking) {
+ utils.dispatchEvent.call(player, player.media, 'seeked');
+ }
+
+ player.media.seeking = false;
+
+ utils.dispatchEvent.call(player, player.media, 'play');
+ utils.dispatchEvent.call(player, player.media, 'playing');
+
+ // Poll to get playback progress
+ player.timers.playing = window.setInterval(() => {
+ player.media.currentTime = instance.getCurrentTime();
+ utils.dispatchEvent.call(player, player.media, 'timeupdate');
+ }, 100);
+
+ // Check duration again due to YouTube bug
+ // https://github.com/sampotts/plyr/issues/374
+ // 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');
+ }
+
+ // Get quality
+ controls.setQualityMenu.call(player, instance.getAvailableQualityLevels());
+
+ break;
+
+ case 2:
+ player.media.paused = true;
+
+ utils.dispatchEvent.call(player, player.media, 'pause');
+
+ break;
+
+ default:
+ break;
+ }
+
+ utils.dispatchEvent.call(player, player.elements.container, 'statechange', false, {
+ code: event.data,
+ });
+ },
+ },
+ });
+ },
+};
+
+export default youtube;