Merge branch 'master' into develop
This commit is contained in:
		@ -1,3 +1,10 @@
 | 
				
			|||||||
 | 
					# v3.4.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-   Added download button option to download either current source or a custom URL you specify in options
 | 
				
			||||||
 | 
					-   Prevent immediate hiding of controls on mobile (thanks @jamesoflol)
 | 
				
			||||||
 | 
					-   Don't hide controls on focusout event (fixes #1122) (thanks @jamesoflol)
 | 
				
			||||||
 | 
					-   Fix HTML5 quality settings being incorrectly set in local storage (thanks @TechGuard)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# v3.4.4
 | 
					# v3.4.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-   Fixed issue with double binding for `click` and `touchstart` for `clickToPlay` option
 | 
					-   Fixed issue with double binding for `click` and `touchstart` for `clickToPlay` option
 | 
				
			||||||
 | 
				
			|||||||
@ -28,6 +28,7 @@ controls: [
 | 
				
			|||||||
    'settings', // Settings menu
 | 
					    'settings', // Settings menu
 | 
				
			||||||
    'pip', // Picture-in-picture (currently Safari only)
 | 
					    'pip', // Picture-in-picture (currently Safari only)
 | 
				
			||||||
    'airplay', // Airplay (currently Safari only)
 | 
					    'airplay', // Airplay (currently Safari only)
 | 
				
			||||||
 | 
					    'download', // Show a download button with a link to either the current source or a custom URL you specify in your options
 | 
				
			||||||
    'fullscreen', // Toggle fullscreen
 | 
					    'fullscreen', // Toggle fullscreen
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								demo/dist/demo.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								demo/dist/demo.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										240
									
								
								dist/plyr.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										240
									
								
								dist/plyr.js
									
									
									
									
										vendored
									
									
								
							@ -178,6 +178,11 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    // Accept a URL object
 | 
					    // Accept a URL object
 | 
				
			||||||
    if (instanceOf(input, window.URL)) {
 | 
					    if (instanceOf(input, window.URL)) {
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
 | 
					    } // Must be string from here
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!isString(input)) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
    } // Add the protocol if required
 | 
					    } // Add the protocol if required
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1006,6 +1011,13 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    return wrapper.innerHTML;
 | 
					    return wrapper.innerHTML;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var resources = {
 | 
				
			||||||
 | 
					    pip: 'PIP',
 | 
				
			||||||
 | 
					    airplay: 'AirPlay',
 | 
				
			||||||
 | 
					    html5: 'HTML5',
 | 
				
			||||||
 | 
					    vimeo: 'Vimeo',
 | 
				
			||||||
 | 
					    youtube: 'YouTube'
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  var i18n = {
 | 
					  var i18n = {
 | 
				
			||||||
    get: function get() {
 | 
					    get: function get() {
 | 
				
			||||||
      var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
 | 
					      var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
 | 
				
			||||||
@ -1018,6 +1030,10 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      var string = getDeep(config.i18n, key);
 | 
					      var string = getDeep(config.i18n, key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (is.empty(string)) {
 | 
					      if (is.empty(string)) {
 | 
				
			||||||
 | 
					        if (Object.keys(resources).includes(key)) {
 | 
				
			||||||
 | 
					          return resources[key];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return '';
 | 
					        return '';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1330,23 +1346,18 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if ('href' in use) {
 | 
					      if ('href' in use) {
 | 
				
			||||||
        use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);
 | 
					        use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);
 | 
				
			||||||
      } else {
 | 
					      } // Always set the older attribute even though it's "deprecated" (it'll be around for ages)
 | 
				
			||||||
        use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path);
 | 
					 | 
				
			||||||
      } // Add <use> to <svg>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path); // Add <use> to <svg>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      icon.appendChild(use);
 | 
					      icon.appendChild(use);
 | 
				
			||||||
      return icon;
 | 
					      return icon;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    // Create hidden text label
 | 
					    // Create hidden text label
 | 
				
			||||||
    createLabel: function createLabel(type) {
 | 
					    createLabel: function createLabel(key) {
 | 
				
			||||||
      var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 | 
					      var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 | 
				
			||||||
      // Skip i18n for abbreviations and brand names
 | 
					      var text = i18n.get(key, this.config);
 | 
				
			||||||
      var universals = {
 | 
					 | 
				
			||||||
        pip: 'PIP',
 | 
					 | 
				
			||||||
        airplay: 'AirPlay'
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
      var text = universals[type] || i18n.get(type, this.config);
 | 
					 | 
				
			||||||
      var attributes = Object.assign({}, attr, {
 | 
					      var attributes = Object.assign({}, attr, {
 | 
				
			||||||
        class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')
 | 
					        class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
@ -1368,20 +1379,29 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    // Create a <button>
 | 
					    // Create a <button>
 | 
				
			||||||
    createButton: function createButton(buttonType, attr) {
 | 
					    createButton: function createButton(buttonType, attr) {
 | 
				
			||||||
      var button = createElement('button');
 | 
					 | 
				
			||||||
      var attributes = Object.assign({}, attr);
 | 
					      var attributes = Object.assign({}, attr);
 | 
				
			||||||
      var type = toCamelCase(buttonType);
 | 
					      var type = toCamelCase(buttonType);
 | 
				
			||||||
      var toggle = false;
 | 
					      var props = {
 | 
				
			||||||
      var label;
 | 
					        element: 'button',
 | 
				
			||||||
      var icon;
 | 
					        toggle: false,
 | 
				
			||||||
      var labelPressed;
 | 
					        label: null,
 | 
				
			||||||
      var iconPressed;
 | 
					        icon: null,
 | 
				
			||||||
 | 
					        labelPressed: null,
 | 
				
			||||||
 | 
					        iconPressed: null
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      ['element', 'icon', 'label'].forEach(function (key) {
 | 
				
			||||||
 | 
					        if (Object.keys(attributes).includes(key)) {
 | 
				
			||||||
 | 
					          props[key] = attributes[key];
 | 
				
			||||||
 | 
					          delete attributes[key];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }); // Default to 'button' type to prevent form submission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!('type' in attributes)) {
 | 
					      if (props.element === 'button' && !Object.keys(attributes).includes('type')) {
 | 
				
			||||||
        attributes.type = 'button';
 | 
					        attributes.type = 'button';
 | 
				
			||||||
      }
 | 
					      } // Set class name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if ('class' in attributes) {
 | 
					
 | 
				
			||||||
 | 
					      if (Object.keys(attributes).includes('class')) {
 | 
				
			||||||
        if (!attributes.class.includes(this.config.classNames.control)) {
 | 
					        if (!attributes.class.includes(this.config.classNames.control)) {
 | 
				
			||||||
          attributes.class += " ".concat(this.config.classNames.control);
 | 
					          attributes.class += " ".concat(this.config.classNames.control);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -1392,69 +1412,76 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      switch (buttonType) {
 | 
					      switch (buttonType) {
 | 
				
			||||||
        case 'play':
 | 
					        case 'play':
 | 
				
			||||||
          toggle = true;
 | 
					          props.toggle = true;
 | 
				
			||||||
          label = 'play';
 | 
					          props.label = 'play';
 | 
				
			||||||
          labelPressed = 'pause';
 | 
					          props.labelPressed = 'pause';
 | 
				
			||||||
          icon = 'play';
 | 
					          props.icon = 'play';
 | 
				
			||||||
          iconPressed = 'pause';
 | 
					          props.iconPressed = 'pause';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case 'mute':
 | 
					        case 'mute':
 | 
				
			||||||
          toggle = true;
 | 
					          props.toggle = true;
 | 
				
			||||||
          label = 'mute';
 | 
					          props.label = 'mute';
 | 
				
			||||||
          labelPressed = 'unmute';
 | 
					          props.labelPressed = 'unmute';
 | 
				
			||||||
          icon = 'volume';
 | 
					          props.icon = 'volume';
 | 
				
			||||||
          iconPressed = 'muted';
 | 
					          props.iconPressed = 'muted';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case 'captions':
 | 
					        case 'captions':
 | 
				
			||||||
          toggle = true;
 | 
					          props.toggle = true;
 | 
				
			||||||
          label = 'enableCaptions';
 | 
					          props.label = 'enableCaptions';
 | 
				
			||||||
          labelPressed = 'disableCaptions';
 | 
					          props.labelPressed = 'disableCaptions';
 | 
				
			||||||
          icon = 'captions-off';
 | 
					          props.icon = 'captions-off';
 | 
				
			||||||
          iconPressed = 'captions-on';
 | 
					          props.iconPressed = 'captions-on';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case 'fullscreen':
 | 
					        case 'fullscreen':
 | 
				
			||||||
          toggle = true;
 | 
					          props.toggle = true;
 | 
				
			||||||
          label = 'enterFullscreen';
 | 
					          props.label = 'enterFullscreen';
 | 
				
			||||||
          labelPressed = 'exitFullscreen';
 | 
					          props.labelPressed = 'exitFullscreen';
 | 
				
			||||||
          icon = 'enter-fullscreen';
 | 
					          props.icon = 'enter-fullscreen';
 | 
				
			||||||
          iconPressed = 'exit-fullscreen';
 | 
					          props.iconPressed = 'exit-fullscreen';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case 'play-large':
 | 
					        case 'play-large':
 | 
				
			||||||
          attributes.class += " ".concat(this.config.classNames.control, "--overlaid");
 | 
					          attributes.class += " ".concat(this.config.classNames.control, "--overlaid");
 | 
				
			||||||
          type = 'play';
 | 
					          type = 'play';
 | 
				
			||||||
          label = 'play';
 | 
					          props.label = 'play';
 | 
				
			||||||
          icon = 'play';
 | 
					          props.icon = 'play';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
          label = type;
 | 
					          if (is.empty(props.label)) {
 | 
				
			||||||
          icon = buttonType;
 | 
					            props.label = type;
 | 
				
			||||||
      } // Setup toggle icon and labels
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (is.empty(props.icon)) {
 | 
				
			||||||
 | 
					            props.icon = buttonType;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (toggle) {
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      var button = createElement(props.element); // Setup toggle icon and labels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (props.toggle) {
 | 
				
			||||||
        // Icon
 | 
					        // Icon
 | 
				
			||||||
        button.appendChild(controls.createIcon.call(this, iconPressed, {
 | 
					        button.appendChild(controls.createIcon.call(this, props.iconPressed, {
 | 
				
			||||||
          class: 'icon--pressed'
 | 
					          class: 'icon--pressed'
 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
        button.appendChild(controls.createIcon.call(this, icon, {
 | 
					        button.appendChild(controls.createIcon.call(this, props.icon, {
 | 
				
			||||||
          class: 'icon--not-pressed'
 | 
					          class: 'icon--not-pressed'
 | 
				
			||||||
        })); // Label/Tooltip
 | 
					        })); // Label/Tooltip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        button.appendChild(controls.createLabel.call(this, labelPressed, {
 | 
					        button.appendChild(controls.createLabel.call(this, props.labelPressed, {
 | 
				
			||||||
          class: 'label--pressed'
 | 
					          class: 'label--pressed'
 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
        button.appendChild(controls.createLabel.call(this, label, {
 | 
					        button.appendChild(controls.createLabel.call(this, props.label, {
 | 
				
			||||||
          class: 'label--not-pressed'
 | 
					          class: 'label--not-pressed'
 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        button.appendChild(controls.createIcon.call(this, icon));
 | 
					        button.appendChild(controls.createIcon.call(this, props.icon));
 | 
				
			||||||
        button.appendChild(controls.createLabel.call(this, label));
 | 
					        button.appendChild(controls.createLabel.call(this, props.label));
 | 
				
			||||||
      } // Merge attributes
 | 
					      } // Merge and set attributes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      extend(attributes, getAttributesFromSelector(this.config.selectors.buttons[type], attributes));
 | 
					      extend(attributes, getAttributesFromSelector(this.config.selectors.buttons[type], attributes));
 | 
				
			||||||
@ -2307,6 +2334,17 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      controls.focusFirstMenuItem.call(this, target, tabFocus);
 | 
					      controls.focusFirstMenuItem.call(this, target, tabFocus);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    // Set the download link
 | 
				
			||||||
 | 
					    setDownloadLink: function setDownloadLink() {
 | 
				
			||||||
 | 
					      var button = this.elements.buttons.download; // Bail if no button
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!is.element(button)) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      } // Set download link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      button.setAttribute('href', this.download);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    // Build the default HTML
 | 
					    // Build the default HTML
 | 
				
			||||||
    // TODO: Set order based on order in the config.controls array?
 | 
					    // TODO: Set order based on order in the config.controls array?
 | 
				
			||||||
    create: function create(data) {
 | 
					    create: function create(data) {
 | 
				
			||||||
@ -2512,6 +2550,25 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (this.config.controls.includes('airplay') && support.airplay) {
 | 
					      if (this.config.controls.includes('airplay') && support.airplay) {
 | 
				
			||||||
        container.appendChild(controls.createButton.call(this, 'airplay'));
 | 
					        container.appendChild(controls.createButton.call(this, 'airplay'));
 | 
				
			||||||
 | 
					      } // Download button
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (this.config.controls.includes('download')) {
 | 
				
			||||||
 | 
					        var _attributes = {
 | 
				
			||||||
 | 
					          element: 'a',
 | 
				
			||||||
 | 
					          href: this.download,
 | 
				
			||||||
 | 
					          target: '_blank'
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        var download = this.config.urls.download;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!is.url(download) && this.isEmbed) {
 | 
				
			||||||
 | 
					          extend(_attributes, {
 | 
				
			||||||
 | 
					            icon: "logo-".concat(this.provider),
 | 
				
			||||||
 | 
					            label: this.provider
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container.appendChild(controls.createButton.call(this, 'download', _attributes));
 | 
				
			||||||
      } // Toggle fullscreen button
 | 
					      } // Toggle fullscreen button
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3178,7 +3235,8 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    controls: ['play-large', // 'restart',
 | 
					    controls: ['play-large', // 'restart',
 | 
				
			||||||
    // 'rewind',
 | 
					    // 'rewind',
 | 
				
			||||||
    'play', // 'fast-forward',
 | 
					    'play', // 'fast-forward',
 | 
				
			||||||
    'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', 'fullscreen'],
 | 
					    'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', // 'download',
 | 
				
			||||||
 | 
					    'fullscreen'],
 | 
				
			||||||
    settings: ['captions', 'quality', 'speed'],
 | 
					    settings: ['captions', 'quality', 'speed'],
 | 
				
			||||||
    // Localisation
 | 
					    // Localisation
 | 
				
			||||||
    i18n: {
 | 
					    i18n: {
 | 
				
			||||||
@ -3198,6 +3256,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      unmute: 'Unmute',
 | 
					      unmute: 'Unmute',
 | 
				
			||||||
      enableCaptions: 'Enable captions',
 | 
					      enableCaptions: 'Enable captions',
 | 
				
			||||||
      disableCaptions: 'Disable captions',
 | 
					      disableCaptions: 'Disable captions',
 | 
				
			||||||
 | 
					      download: 'Download',
 | 
				
			||||||
      enterFullscreen: 'Enter fullscreen',
 | 
					      enterFullscreen: 'Enter fullscreen',
 | 
				
			||||||
      exitFullscreen: 'Exit fullscreen',
 | 
					      exitFullscreen: 'Exit fullscreen',
 | 
				
			||||||
      frameTitle: 'Player for {title}',
 | 
					      frameTitle: 'Player for {title}',
 | 
				
			||||||
@ -3226,6 +3285,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    // URLs
 | 
					    // URLs
 | 
				
			||||||
    urls: {
 | 
					    urls: {
 | 
				
			||||||
 | 
					      download: null,
 | 
				
			||||||
      vimeo: {
 | 
					      vimeo: {
 | 
				
			||||||
        sdk: 'https://player.vimeo.com/api/player.js',
 | 
					        sdk: 'https://player.vimeo.com/api/player.js',
 | 
				
			||||||
        iframe: 'https://player.vimeo.com/video/{0}?{1}',
 | 
					        iframe: 'https://player.vimeo.com/video/{0}?{1}',
 | 
				
			||||||
@ -3250,6 +3310,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      mute: null,
 | 
					      mute: null,
 | 
				
			||||||
      volume: null,
 | 
					      volume: null,
 | 
				
			||||||
      captions: null,
 | 
					      captions: null,
 | 
				
			||||||
 | 
					      download: null,
 | 
				
			||||||
      fullscreen: null,
 | 
					      fullscreen: null,
 | 
				
			||||||
      pip: null,
 | 
					      pip: null,
 | 
				
			||||||
      airplay: null,
 | 
					      airplay: null,
 | 
				
			||||||
@ -3262,7 +3323,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    events: [// Events to watch on HTML5 media elements and bubble
 | 
					    events: [// Events to watch on HTML5 media elements and bubble
 | 
				
			||||||
    // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events
 | 
					    // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events
 | 
				
			||||||
    'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied', 'ratechange', 'cuechange', // Custom events
 | 
					    'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied', 'ratechange', 'cuechange', // Custom events
 | 
				
			||||||
    'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready', // YouTube
 | 
					    'download', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready', // YouTube
 | 
				
			||||||
    'statechange', // Quality
 | 
					    'statechange', // Quality
 | 
				
			||||||
    'qualitychange', // Ads
 | 
					    'qualitychange', // Ads
 | 
				
			||||||
    'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
 | 
					    'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
 | 
				
			||||||
@ -3284,6 +3345,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
        fastForward: '[data-plyr="fast-forward"]',
 | 
					        fastForward: '[data-plyr="fast-forward"]',
 | 
				
			||||||
        mute: '[data-plyr="mute"]',
 | 
					        mute: '[data-plyr="mute"]',
 | 
				
			||||||
        captions: '[data-plyr="captions"]',
 | 
					        captions: '[data-plyr="captions"]',
 | 
				
			||||||
 | 
					        download: '[data-plyr="download"]',
 | 
				
			||||||
        fullscreen: '[data-plyr="fullscreen"]',
 | 
					        fullscreen: '[data-plyr="fullscreen"]',
 | 
				
			||||||
        pip: '[data-plyr="pip"]',
 | 
					        pip: '[data-plyr="pip"]',
 | 
				
			||||||
        airplay: '[data-plyr="airplay"]',
 | 
					        airplay: '[data-plyr="airplay"]',
 | 
				
			||||||
@ -3396,7 +3458,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Get provider by URL
 | 
					   * Get provider by URL
 | 
				
			||||||
   * @param {string} url
 | 
					   * @param {String} url
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function getProviderByUrl(url) {
 | 
					  function getProviderByUrl(url) {
 | 
				
			||||||
@ -3923,8 +3985,10 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      var controls$$1 = this.elements.controls;
 | 
					      var controls$$1 = this.elements.controls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (controls$$1 && this.config.hideControls) {
 | 
					      if (controls$$1 && this.config.hideControls) {
 | 
				
			||||||
        // Show controls if force, loading, paused, or button interaction, otherwise hide
 | 
					        // Don't hide controls if a touch-device user recently seeked. (Must be limited to touch devices, or it occasionally prevents desktop controls from hiding.)
 | 
				
			||||||
        this.toggleControls(Boolean(force || this.loading || this.paused || controls$$1.pressed || controls$$1.hover));
 | 
					        var recentTouchSeek = this.touch && this.lastSeekTime + 2000 > Date.now(); // Show controls if force, loading, paused, button interaction, or recent seek, otherwise hide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.toggleControls(Boolean(force || this.loading || this.paused || controls$$1.pressed || controls$$1.hover || recentTouchSeek));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@ -4283,7 +4347,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          if (!is.element(wrapper)) {
 | 
					          if (!is.element(wrapper)) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
          } // On click play, pause ore restart
 | 
					          } // On click play, pause or restart
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          on.call(player, elements.container, 'click', function (event) {
 | 
					          on.call(player, elements.container, 'click', function (event) {
 | 
				
			||||||
@ -4336,6 +4400,10 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
        on.call(player, player.media, 'qualitychange', function (event) {
 | 
					        on.call(player, player.media, 'qualitychange', function (event) {
 | 
				
			||||||
          // Update UI
 | 
					          // Update UI
 | 
				
			||||||
          controls.updateSetting.call(player, 'quality', null, event.detail.quality);
 | 
					          controls.updateSetting.call(player, 'quality', null, event.detail.quality);
 | 
				
			||||||
 | 
					        }); // Update download link when ready and if quality changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        on.call(player, player.media, 'ready qualitychange', function () {
 | 
				
			||||||
 | 
					          controls.setDownloadLink.call(player);
 | 
				
			||||||
        }); // Proxy events to container
 | 
					        }); // Proxy events to container
 | 
				
			||||||
        // Bubble up key events for Edge
 | 
					        // Bubble up key events for Edge
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -4413,7 +4481,11 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.buttons.captions, 'click', function () {
 | 
					        this.bind(elements.buttons.captions, 'click', function () {
 | 
				
			||||||
          return player.toggleCaptions();
 | 
					          return player.toggleCaptions();
 | 
				
			||||||
        }); // Fullscreen toggle
 | 
					        }); // Download
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.bind(elements.buttons.download, 'click', function () {
 | 
				
			||||||
 | 
					          triggerEvent.call(player, player.media, 'download');
 | 
				
			||||||
 | 
					        }, 'download'); // Fullscreen toggle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.buttons.fullscreen, 'click', function () {
 | 
					        this.bind(elements.buttons.fullscreen, 'click', function () {
 | 
				
			||||||
          player.fullscreen.toggle();
 | 
					          player.fullscreen.toggle();
 | 
				
			||||||
@ -4476,9 +4548,11 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          if (is.keyboardEvent(event) && code !== 39 && code !== 37) {
 | 
					          if (is.keyboardEvent(event) && code !== 39 && code !== 37) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
          } // Was playing before?
 | 
					          } // Record seek time so we can prevent hiding controls for a few seconds after seek
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          player.lastSeekTime = Date.now(); // Was playing before?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          var play = seek.hasAttribute(attribute); // Done seeking
 | 
					          var play = seek.hasAttribute(attribute); // Done seeking
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          var done = ['mouseup', 'touchend', 'keyup'].includes(event.type); // If we're done seeking and it was playing, resume playback
 | 
					          var done = ['mouseup', 'touchend', 'keyup'].includes(event.type); // If we're done seeking and it was playing, resume playback
 | 
				
			||||||
@ -4555,32 +4629,28 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
 | 
					        this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
 | 
				
			||||||
          elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
 | 
					          elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
 | 
				
			||||||
        }); // Focus in/out on controls
 | 
					        }); // Show controls when they receive focus (e.g., when using keyboard tab key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.controls, 'focusin focusout', function (event) {
 | 
					        this.bind(elements.controls, 'focusin', function () {
 | 
				
			||||||
          var config = player.config,
 | 
					          var config = player.config,
 | 
				
			||||||
              elements = player.elements,
 | 
					              elements = player.elements,
 | 
				
			||||||
              timers = player.timers;
 | 
					              timers = player.timers; // Skip transition to prevent focus from scrolling the parent element
 | 
				
			||||||
          var isFocusIn = event.type === 'focusin'; // Skip transition to prevent focus from scrolling the parent element
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          toggleClass(elements.controls, config.classNames.noTransition, isFocusIn); // Toggle
 | 
					          toggleClass(elements.controls, config.classNames.noTransition, true); // Toggle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          ui.toggleControls.call(player, isFocusIn); // If focusin, hide again after delay
 | 
					          ui.toggleControls.call(player, true); // Restore transition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (isFocusIn) {
 | 
					          setTimeout(function () {
 | 
				
			||||||
            // Restore transition
 | 
					            toggleClass(elements.controls, config.classNames.noTransition, false);
 | 
				
			||||||
            setTimeout(function () {
 | 
					          }, 0); // Delay a little more for mouse users
 | 
				
			||||||
              toggleClass(elements.controls, config.classNames.noTransition, false);
 | 
					 | 
				
			||||||
            }, 0); // Delay a little more for keyboard users
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var delay = _this2.touch ? 3000 : 4000; // Clear timer
 | 
					          var delay = _this2.touch ? 3000 : 4000; // Clear timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            clearTimeout(timers.controls); // Hide
 | 
					          clearTimeout(timers.controls); // Hide again after delay
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            timers.controls = setTimeout(function () {
 | 
					          timers.controls = setTimeout(function () {
 | 
				
			||||||
              return ui.toggleControls.call(player, false);
 | 
					            return ui.toggleControls.call(player, false);
 | 
				
			||||||
            }, delay);
 | 
					          }, delay);
 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }); // Mouse wheel for volume
 | 
					        }); // Mouse wheel for volume
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.inputs.volume, 'wheel', function (event) {
 | 
					        this.bind(elements.inputs.volume, 'wheel', function (event) {
 | 
				
			||||||
@ -5171,6 +5241,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      var currentSrc;
 | 
					      var currentSrc;
 | 
				
			||||||
      player.embed.getVideoUrl().then(function (value) {
 | 
					      player.embed.getVideoUrl().then(function (value) {
 | 
				
			||||||
        currentSrc = value;
 | 
					        currentSrc = value;
 | 
				
			||||||
 | 
					        controls.setDownloadLink.call(player);
 | 
				
			||||||
      }).catch(function (error) {
 | 
					      }).catch(function (error) {
 | 
				
			||||||
        _this2.debug.warn(error);
 | 
					        _this2.debug.warn(error);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
@ -6724,7 +6795,10 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (this.config.autoplay) {
 | 
					      if (this.config.autoplay) {
 | 
				
			||||||
        this.play();
 | 
					        this.play();
 | 
				
			||||||
      }
 | 
					      } // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.lastSeekTime = 0;
 | 
				
			||||||
    } // ---------------------------------------
 | 
					    } // ---------------------------------------
 | 
				
			||||||
    // API
 | 
					    // API
 | 
				
			||||||
    // ---------------------------------------
 | 
					    // ---------------------------------------
 | 
				
			||||||
@ -7448,6 +7522,16 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      get: function get() {
 | 
					      get: function get() {
 | 
				
			||||||
        return this.media.currentSrc;
 | 
					        return this.media.currentSrc;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * Get a download URL (either source or custom)
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }, {
 | 
				
			||||||
 | 
					      key: "download",
 | 
				
			||||||
 | 
					      get: function get() {
 | 
				
			||||||
 | 
					        var download = this.config.urls.download;
 | 
				
			||||||
 | 
					        return is.url(download) ? download : this.source;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      /**
 | 
					      /**
 | 
				
			||||||
       * Set the poster image for a video
 | 
					       * Set the poster image for a video
 | 
				
			||||||
       * @param {input} - the URL for the new poster image
 | 
					       * @param {input} - the URL for the new poster image
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								dist/plyr.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.min.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.min.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										240
									
								
								dist/plyr.polyfilled.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										240
									
								
								dist/plyr.polyfilled.js
									
									
									
									
										vendored
									
									
								
							@ -2804,6 +2804,11 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    // Accept a URL object
 | 
					    // Accept a URL object
 | 
				
			||||||
    if (instanceOf(input, window.URL)) {
 | 
					    if (instanceOf(input, window.URL)) {
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
 | 
					    } // Must be string from here
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!isString(input)) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
    } // Add the protocol if required
 | 
					    } // Add the protocol if required
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3669,6 +3674,13 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    return wrapper.innerHTML;
 | 
					    return wrapper.innerHTML;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var resources = {
 | 
				
			||||||
 | 
					    pip: 'PIP',
 | 
				
			||||||
 | 
					    airplay: 'AirPlay',
 | 
				
			||||||
 | 
					    html5: 'HTML5',
 | 
				
			||||||
 | 
					    vimeo: 'Vimeo',
 | 
				
			||||||
 | 
					    youtube: 'YouTube'
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  var i18n = {
 | 
					  var i18n = {
 | 
				
			||||||
    get: function get() {
 | 
					    get: function get() {
 | 
				
			||||||
      var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
 | 
					      var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
 | 
				
			||||||
@ -3681,6 +3693,10 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      var string = getDeep(config.i18n, key);
 | 
					      var string = getDeep(config.i18n, key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (is$1.empty(string)) {
 | 
					      if (is$1.empty(string)) {
 | 
				
			||||||
 | 
					        if (Object.keys(resources).includes(key)) {
 | 
				
			||||||
 | 
					          return resources[key];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return '';
 | 
					        return '';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3993,23 +4009,18 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if ('href' in use) {
 | 
					      if ('href' in use) {
 | 
				
			||||||
        use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);
 | 
					        use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);
 | 
				
			||||||
      } else {
 | 
					      } // Always set the older attribute even though it's "deprecated" (it'll be around for ages)
 | 
				
			||||||
        use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path);
 | 
					 | 
				
			||||||
      } // Add <use> to <svg>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path); // Add <use> to <svg>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      icon.appendChild(use);
 | 
					      icon.appendChild(use);
 | 
				
			||||||
      return icon;
 | 
					      return icon;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    // Create hidden text label
 | 
					    // Create hidden text label
 | 
				
			||||||
    createLabel: function createLabel(type) {
 | 
					    createLabel: function createLabel(key) {
 | 
				
			||||||
      var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 | 
					      var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 | 
				
			||||||
      // Skip i18n for abbreviations and brand names
 | 
					      var text = i18n.get(key, this.config);
 | 
				
			||||||
      var universals = {
 | 
					 | 
				
			||||||
        pip: 'PIP',
 | 
					 | 
				
			||||||
        airplay: 'AirPlay'
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
      var text = universals[type] || i18n.get(type, this.config);
 | 
					 | 
				
			||||||
      var attributes = Object.assign({}, attr, {
 | 
					      var attributes = Object.assign({}, attr, {
 | 
				
			||||||
        class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')
 | 
					        class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
@ -4031,20 +4042,29 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    // Create a <button>
 | 
					    // Create a <button>
 | 
				
			||||||
    createButton: function createButton(buttonType, attr) {
 | 
					    createButton: function createButton(buttonType, attr) {
 | 
				
			||||||
      var button = createElement('button');
 | 
					 | 
				
			||||||
      var attributes = Object.assign({}, attr);
 | 
					      var attributes = Object.assign({}, attr);
 | 
				
			||||||
      var type = toCamelCase(buttonType);
 | 
					      var type = toCamelCase(buttonType);
 | 
				
			||||||
      var toggle = false;
 | 
					      var props = {
 | 
				
			||||||
      var label;
 | 
					        element: 'button',
 | 
				
			||||||
      var icon;
 | 
					        toggle: false,
 | 
				
			||||||
      var labelPressed;
 | 
					        label: null,
 | 
				
			||||||
      var iconPressed;
 | 
					        icon: null,
 | 
				
			||||||
 | 
					        labelPressed: null,
 | 
				
			||||||
 | 
					        iconPressed: null
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      ['element', 'icon', 'label'].forEach(function (key) {
 | 
				
			||||||
 | 
					        if (Object.keys(attributes).includes(key)) {
 | 
				
			||||||
 | 
					          props[key] = attributes[key];
 | 
				
			||||||
 | 
					          delete attributes[key];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }); // Default to 'button' type to prevent form submission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!('type' in attributes)) {
 | 
					      if (props.element === 'button' && !Object.keys(attributes).includes('type')) {
 | 
				
			||||||
        attributes.type = 'button';
 | 
					        attributes.type = 'button';
 | 
				
			||||||
      }
 | 
					      } // Set class name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if ('class' in attributes) {
 | 
					
 | 
				
			||||||
 | 
					      if (Object.keys(attributes).includes('class')) {
 | 
				
			||||||
        if (!attributes.class.includes(this.config.classNames.control)) {
 | 
					        if (!attributes.class.includes(this.config.classNames.control)) {
 | 
				
			||||||
          attributes.class += " ".concat(this.config.classNames.control);
 | 
					          attributes.class += " ".concat(this.config.classNames.control);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -4055,69 +4075,76 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      switch (buttonType) {
 | 
					      switch (buttonType) {
 | 
				
			||||||
        case 'play':
 | 
					        case 'play':
 | 
				
			||||||
          toggle = true;
 | 
					          props.toggle = true;
 | 
				
			||||||
          label = 'play';
 | 
					          props.label = 'play';
 | 
				
			||||||
          labelPressed = 'pause';
 | 
					          props.labelPressed = 'pause';
 | 
				
			||||||
          icon = 'play';
 | 
					          props.icon = 'play';
 | 
				
			||||||
          iconPressed = 'pause';
 | 
					          props.iconPressed = 'pause';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case 'mute':
 | 
					        case 'mute':
 | 
				
			||||||
          toggle = true;
 | 
					          props.toggle = true;
 | 
				
			||||||
          label = 'mute';
 | 
					          props.label = 'mute';
 | 
				
			||||||
          labelPressed = 'unmute';
 | 
					          props.labelPressed = 'unmute';
 | 
				
			||||||
          icon = 'volume';
 | 
					          props.icon = 'volume';
 | 
				
			||||||
          iconPressed = 'muted';
 | 
					          props.iconPressed = 'muted';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case 'captions':
 | 
					        case 'captions':
 | 
				
			||||||
          toggle = true;
 | 
					          props.toggle = true;
 | 
				
			||||||
          label = 'enableCaptions';
 | 
					          props.label = 'enableCaptions';
 | 
				
			||||||
          labelPressed = 'disableCaptions';
 | 
					          props.labelPressed = 'disableCaptions';
 | 
				
			||||||
          icon = 'captions-off';
 | 
					          props.icon = 'captions-off';
 | 
				
			||||||
          iconPressed = 'captions-on';
 | 
					          props.iconPressed = 'captions-on';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case 'fullscreen':
 | 
					        case 'fullscreen':
 | 
				
			||||||
          toggle = true;
 | 
					          props.toggle = true;
 | 
				
			||||||
          label = 'enterFullscreen';
 | 
					          props.label = 'enterFullscreen';
 | 
				
			||||||
          labelPressed = 'exitFullscreen';
 | 
					          props.labelPressed = 'exitFullscreen';
 | 
				
			||||||
          icon = 'enter-fullscreen';
 | 
					          props.icon = 'enter-fullscreen';
 | 
				
			||||||
          iconPressed = 'exit-fullscreen';
 | 
					          props.iconPressed = 'exit-fullscreen';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case 'play-large':
 | 
					        case 'play-large':
 | 
				
			||||||
          attributes.class += " ".concat(this.config.classNames.control, "--overlaid");
 | 
					          attributes.class += " ".concat(this.config.classNames.control, "--overlaid");
 | 
				
			||||||
          type = 'play';
 | 
					          type = 'play';
 | 
				
			||||||
          label = 'play';
 | 
					          props.label = 'play';
 | 
				
			||||||
          icon = 'play';
 | 
					          props.icon = 'play';
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
          label = type;
 | 
					          if (is$1.empty(props.label)) {
 | 
				
			||||||
          icon = buttonType;
 | 
					            props.label = type;
 | 
				
			||||||
      } // Setup toggle icon and labels
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (is$1.empty(props.icon)) {
 | 
				
			||||||
 | 
					            props.icon = buttonType;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (toggle) {
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      var button = createElement(props.element); // Setup toggle icon and labels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (props.toggle) {
 | 
				
			||||||
        // Icon
 | 
					        // Icon
 | 
				
			||||||
        button.appendChild(controls.createIcon.call(this, iconPressed, {
 | 
					        button.appendChild(controls.createIcon.call(this, props.iconPressed, {
 | 
				
			||||||
          class: 'icon--pressed'
 | 
					          class: 'icon--pressed'
 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
        button.appendChild(controls.createIcon.call(this, icon, {
 | 
					        button.appendChild(controls.createIcon.call(this, props.icon, {
 | 
				
			||||||
          class: 'icon--not-pressed'
 | 
					          class: 'icon--not-pressed'
 | 
				
			||||||
        })); // Label/Tooltip
 | 
					        })); // Label/Tooltip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        button.appendChild(controls.createLabel.call(this, labelPressed, {
 | 
					        button.appendChild(controls.createLabel.call(this, props.labelPressed, {
 | 
				
			||||||
          class: 'label--pressed'
 | 
					          class: 'label--pressed'
 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
        button.appendChild(controls.createLabel.call(this, label, {
 | 
					        button.appendChild(controls.createLabel.call(this, props.label, {
 | 
				
			||||||
          class: 'label--not-pressed'
 | 
					          class: 'label--not-pressed'
 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        button.appendChild(controls.createIcon.call(this, icon));
 | 
					        button.appendChild(controls.createIcon.call(this, props.icon));
 | 
				
			||||||
        button.appendChild(controls.createLabel.call(this, label));
 | 
					        button.appendChild(controls.createLabel.call(this, props.label));
 | 
				
			||||||
      } // Merge attributes
 | 
					      } // Merge and set attributes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      extend(attributes, getAttributesFromSelector(this.config.selectors.buttons[type], attributes));
 | 
					      extend(attributes, getAttributesFromSelector(this.config.selectors.buttons[type], attributes));
 | 
				
			||||||
@ -4970,6 +4997,17 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      controls.focusFirstMenuItem.call(this, target, tabFocus);
 | 
					      controls.focusFirstMenuItem.call(this, target, tabFocus);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    // Set the download link
 | 
				
			||||||
 | 
					    setDownloadLink: function setDownloadLink() {
 | 
				
			||||||
 | 
					      var button = this.elements.buttons.download; // Bail if no button
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!is$1.element(button)) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      } // Set download link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      button.setAttribute('href', this.download);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    // Build the default HTML
 | 
					    // Build the default HTML
 | 
				
			||||||
    // TODO: Set order based on order in the config.controls array?
 | 
					    // TODO: Set order based on order in the config.controls array?
 | 
				
			||||||
    create: function create(data) {
 | 
					    create: function create(data) {
 | 
				
			||||||
@ -5175,6 +5213,25 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (this.config.controls.includes('airplay') && support.airplay) {
 | 
					      if (this.config.controls.includes('airplay') && support.airplay) {
 | 
				
			||||||
        container.appendChild(controls.createButton.call(this, 'airplay'));
 | 
					        container.appendChild(controls.createButton.call(this, 'airplay'));
 | 
				
			||||||
 | 
					      } // Download button
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (this.config.controls.includes('download')) {
 | 
				
			||||||
 | 
					        var _attributes = {
 | 
				
			||||||
 | 
					          element: 'a',
 | 
				
			||||||
 | 
					          href: this.download,
 | 
				
			||||||
 | 
					          target: '_blank'
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        var download = this.config.urls.download;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!is$1.url(download) && this.isEmbed) {
 | 
				
			||||||
 | 
					          extend(_attributes, {
 | 
				
			||||||
 | 
					            icon: "logo-".concat(this.provider),
 | 
				
			||||||
 | 
					            label: this.provider
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container.appendChild(controls.createButton.call(this, 'download', _attributes));
 | 
				
			||||||
      } // Toggle fullscreen button
 | 
					      } // Toggle fullscreen button
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -5841,7 +5898,8 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    controls: ['play-large', // 'restart',
 | 
					    controls: ['play-large', // 'restart',
 | 
				
			||||||
    // 'rewind',
 | 
					    // 'rewind',
 | 
				
			||||||
    'play', // 'fast-forward',
 | 
					    'play', // 'fast-forward',
 | 
				
			||||||
    'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', 'fullscreen'],
 | 
					    'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', // 'download',
 | 
				
			||||||
 | 
					    'fullscreen'],
 | 
				
			||||||
    settings: ['captions', 'quality', 'speed'],
 | 
					    settings: ['captions', 'quality', 'speed'],
 | 
				
			||||||
    // Localisation
 | 
					    // Localisation
 | 
				
			||||||
    i18n: {
 | 
					    i18n: {
 | 
				
			||||||
@ -5861,6 +5919,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      unmute: 'Unmute',
 | 
					      unmute: 'Unmute',
 | 
				
			||||||
      enableCaptions: 'Enable captions',
 | 
					      enableCaptions: 'Enable captions',
 | 
				
			||||||
      disableCaptions: 'Disable captions',
 | 
					      disableCaptions: 'Disable captions',
 | 
				
			||||||
 | 
					      download: 'Download',
 | 
				
			||||||
      enterFullscreen: 'Enter fullscreen',
 | 
					      enterFullscreen: 'Enter fullscreen',
 | 
				
			||||||
      exitFullscreen: 'Exit fullscreen',
 | 
					      exitFullscreen: 'Exit fullscreen',
 | 
				
			||||||
      frameTitle: 'Player for {title}',
 | 
					      frameTitle: 'Player for {title}',
 | 
				
			||||||
@ -5889,6 +5948,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    // URLs
 | 
					    // URLs
 | 
				
			||||||
    urls: {
 | 
					    urls: {
 | 
				
			||||||
 | 
					      download: null,
 | 
				
			||||||
      vimeo: {
 | 
					      vimeo: {
 | 
				
			||||||
        sdk: 'https://player.vimeo.com/api/player.js',
 | 
					        sdk: 'https://player.vimeo.com/api/player.js',
 | 
				
			||||||
        iframe: 'https://player.vimeo.com/video/{0}?{1}',
 | 
					        iframe: 'https://player.vimeo.com/video/{0}?{1}',
 | 
				
			||||||
@ -5913,6 +5973,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      mute: null,
 | 
					      mute: null,
 | 
				
			||||||
      volume: null,
 | 
					      volume: null,
 | 
				
			||||||
      captions: null,
 | 
					      captions: null,
 | 
				
			||||||
 | 
					      download: null,
 | 
				
			||||||
      fullscreen: null,
 | 
					      fullscreen: null,
 | 
				
			||||||
      pip: null,
 | 
					      pip: null,
 | 
				
			||||||
      airplay: null,
 | 
					      airplay: null,
 | 
				
			||||||
@ -5925,7 +5986,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
    events: [// Events to watch on HTML5 media elements and bubble
 | 
					    events: [// Events to watch on HTML5 media elements and bubble
 | 
				
			||||||
    // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events
 | 
					    // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events
 | 
				
			||||||
    'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied', 'ratechange', 'cuechange', // Custom events
 | 
					    'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied', 'ratechange', 'cuechange', // Custom events
 | 
				
			||||||
    'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready', // YouTube
 | 
					    'download', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready', // YouTube
 | 
				
			||||||
    'statechange', // Quality
 | 
					    'statechange', // Quality
 | 
				
			||||||
    'qualitychange', // Ads
 | 
					    'qualitychange', // Ads
 | 
				
			||||||
    'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
 | 
					    'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
 | 
				
			||||||
@ -5947,6 +6008,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
        fastForward: '[data-plyr="fast-forward"]',
 | 
					        fastForward: '[data-plyr="fast-forward"]',
 | 
				
			||||||
        mute: '[data-plyr="mute"]',
 | 
					        mute: '[data-plyr="mute"]',
 | 
				
			||||||
        captions: '[data-plyr="captions"]',
 | 
					        captions: '[data-plyr="captions"]',
 | 
				
			||||||
 | 
					        download: '[data-plyr="download"]',
 | 
				
			||||||
        fullscreen: '[data-plyr="fullscreen"]',
 | 
					        fullscreen: '[data-plyr="fullscreen"]',
 | 
				
			||||||
        pip: '[data-plyr="pip"]',
 | 
					        pip: '[data-plyr="pip"]',
 | 
				
			||||||
        airplay: '[data-plyr="airplay"]',
 | 
					        airplay: '[data-plyr="airplay"]',
 | 
				
			||||||
@ -6059,7 +6121,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Get provider by URL
 | 
					   * Get provider by URL
 | 
				
			||||||
   * @param {string} url
 | 
					   * @param {String} url
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function getProviderByUrl(url) {
 | 
					  function getProviderByUrl(url) {
 | 
				
			||||||
@ -6596,8 +6658,10 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      var controls$$1 = this.elements.controls;
 | 
					      var controls$$1 = this.elements.controls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (controls$$1 && this.config.hideControls) {
 | 
					      if (controls$$1 && this.config.hideControls) {
 | 
				
			||||||
        // Show controls if force, loading, paused, or button interaction, otherwise hide
 | 
					        // Don't hide controls if a touch-device user recently seeked. (Must be limited to touch devices, or it occasionally prevents desktop controls from hiding.)
 | 
				
			||||||
        this.toggleControls(Boolean(force || this.loading || this.paused || controls$$1.pressed || controls$$1.hover));
 | 
					        var recentTouchSeek = this.touch && this.lastSeekTime + 2000 > Date.now(); // Show controls if force, loading, paused, button interaction, or recent seek, otherwise hide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.toggleControls(Boolean(force || this.loading || this.paused || controls$$1.pressed || controls$$1.hover || recentTouchSeek));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@ -6956,7 +7020,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          if (!is$1.element(wrapper)) {
 | 
					          if (!is$1.element(wrapper)) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
          } // On click play, pause ore restart
 | 
					          } // On click play, pause or restart
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          on.call(player, elements.container, 'click', function (event) {
 | 
					          on.call(player, elements.container, 'click', function (event) {
 | 
				
			||||||
@ -7009,6 +7073,10 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
        on.call(player, player.media, 'qualitychange', function (event) {
 | 
					        on.call(player, player.media, 'qualitychange', function (event) {
 | 
				
			||||||
          // Update UI
 | 
					          // Update UI
 | 
				
			||||||
          controls.updateSetting.call(player, 'quality', null, event.detail.quality);
 | 
					          controls.updateSetting.call(player, 'quality', null, event.detail.quality);
 | 
				
			||||||
 | 
					        }); // Update download link when ready and if quality changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        on.call(player, player.media, 'ready qualitychange', function () {
 | 
				
			||||||
 | 
					          controls.setDownloadLink.call(player);
 | 
				
			||||||
        }); // Proxy events to container
 | 
					        }); // Proxy events to container
 | 
				
			||||||
        // Bubble up key events for Edge
 | 
					        // Bubble up key events for Edge
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -7086,7 +7154,11 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.buttons.captions, 'click', function () {
 | 
					        this.bind(elements.buttons.captions, 'click', function () {
 | 
				
			||||||
          return player.toggleCaptions();
 | 
					          return player.toggleCaptions();
 | 
				
			||||||
        }); // Fullscreen toggle
 | 
					        }); // Download
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.bind(elements.buttons.download, 'click', function () {
 | 
				
			||||||
 | 
					          triggerEvent.call(player, player.media, 'download');
 | 
				
			||||||
 | 
					        }, 'download'); // Fullscreen toggle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.buttons.fullscreen, 'click', function () {
 | 
					        this.bind(elements.buttons.fullscreen, 'click', function () {
 | 
				
			||||||
          player.fullscreen.toggle();
 | 
					          player.fullscreen.toggle();
 | 
				
			||||||
@ -7149,9 +7221,11 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          if (is$1.keyboardEvent(event) && code !== 39 && code !== 37) {
 | 
					          if (is$1.keyboardEvent(event) && code !== 39 && code !== 37) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
          } // Was playing before?
 | 
					          } // Record seek time so we can prevent hiding controls for a few seconds after seek
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          player.lastSeekTime = Date.now(); // Was playing before?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          var play = seek.hasAttribute(attribute); // Done seeking
 | 
					          var play = seek.hasAttribute(attribute); // Done seeking
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          var done = ['mouseup', 'touchend', 'keyup'].includes(event.type); // If we're done seeking and it was playing, resume playback
 | 
					          var done = ['mouseup', 'touchend', 'keyup'].includes(event.type); // If we're done seeking and it was playing, resume playback
 | 
				
			||||||
@ -7228,32 +7302,28 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
 | 
					        this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
 | 
				
			||||||
          elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
 | 
					          elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
 | 
				
			||||||
        }); // Focus in/out on controls
 | 
					        }); // Show controls when they receive focus (e.g., when using keyboard tab key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.controls, 'focusin focusout', function (event) {
 | 
					        this.bind(elements.controls, 'focusin', function () {
 | 
				
			||||||
          var config = player.config,
 | 
					          var config = player.config,
 | 
				
			||||||
              elements = player.elements,
 | 
					              elements = player.elements,
 | 
				
			||||||
              timers = player.timers;
 | 
					              timers = player.timers; // Skip transition to prevent focus from scrolling the parent element
 | 
				
			||||||
          var isFocusIn = event.type === 'focusin'; // Skip transition to prevent focus from scrolling the parent element
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          toggleClass(elements.controls, config.classNames.noTransition, isFocusIn); // Toggle
 | 
					          toggleClass(elements.controls, config.classNames.noTransition, true); // Toggle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          ui.toggleControls.call(player, isFocusIn); // If focusin, hide again after delay
 | 
					          ui.toggleControls.call(player, true); // Restore transition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (isFocusIn) {
 | 
					          setTimeout(function () {
 | 
				
			||||||
            // Restore transition
 | 
					            toggleClass(elements.controls, config.classNames.noTransition, false);
 | 
				
			||||||
            setTimeout(function () {
 | 
					          }, 0); // Delay a little more for mouse users
 | 
				
			||||||
              toggleClass(elements.controls, config.classNames.noTransition, false);
 | 
					 | 
				
			||||||
            }, 0); // Delay a little more for keyboard users
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var delay = _this2.touch ? 3000 : 4000; // Clear timer
 | 
					          var delay = _this2.touch ? 3000 : 4000; // Clear timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            clearTimeout(timers.controls); // Hide
 | 
					          clearTimeout(timers.controls); // Hide again after delay
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            timers.controls = setTimeout(function () {
 | 
					          timers.controls = setTimeout(function () {
 | 
				
			||||||
              return ui.toggleControls.call(player, false);
 | 
					            return ui.toggleControls.call(player, false);
 | 
				
			||||||
            }, delay);
 | 
					          }, delay);
 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }); // Mouse wheel for volume
 | 
					        }); // Mouse wheel for volume
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.bind(elements.inputs.volume, 'wheel', function (event) {
 | 
					        this.bind(elements.inputs.volume, 'wheel', function (event) {
 | 
				
			||||||
@ -7864,6 +7934,7 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      var currentSrc;
 | 
					      var currentSrc;
 | 
				
			||||||
      player.embed.getVideoUrl().then(function (value) {
 | 
					      player.embed.getVideoUrl().then(function (value) {
 | 
				
			||||||
        currentSrc = value;
 | 
					        currentSrc = value;
 | 
				
			||||||
 | 
					        controls.setDownloadLink.call(player);
 | 
				
			||||||
      }).catch(function (error) {
 | 
					      }).catch(function (error) {
 | 
				
			||||||
        _this2.debug.warn(error);
 | 
					        _this2.debug.warn(error);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
@ -9414,7 +9485,10 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (this.config.autoplay) {
 | 
					      if (this.config.autoplay) {
 | 
				
			||||||
        this.play();
 | 
					        this.play();
 | 
				
			||||||
      }
 | 
					      } // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.lastSeekTime = 0;
 | 
				
			||||||
    } // ---------------------------------------
 | 
					    } // ---------------------------------------
 | 
				
			||||||
    // API
 | 
					    // API
 | 
				
			||||||
    // ---------------------------------------
 | 
					    // ---------------------------------------
 | 
				
			||||||
@ -10138,6 +10212,16 @@ typeof navigator === "object" && (function (global, factory) {
 | 
				
			|||||||
      get: function get() {
 | 
					      get: function get() {
 | 
				
			||||||
        return this.media.currentSrc;
 | 
					        return this.media.currentSrc;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * Get a download URL (either source or custom)
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }, {
 | 
				
			||||||
 | 
					      key: "download",
 | 
				
			||||||
 | 
					      get: function get() {
 | 
				
			||||||
 | 
					        var download = this.config.urls.download;
 | 
				
			||||||
 | 
					        return is$1.url(download) ? download : this.source;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      /**
 | 
					      /**
 | 
				
			||||||
       * Set the poster image for a video
 | 
					       * Set the poster image for a video
 | 
				
			||||||
       * @param {input} - the URL for the new poster image
 | 
					       * @param {input} - the URL for the new poster image
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								dist/plyr.polyfilled.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.polyfilled.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.polyfilled.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.polyfilled.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.polyfilled.min.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.polyfilled.min.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.svg
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.svg
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
		 Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 5.3 KiB  | 
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "name": "plyr",
 | 
					    "name": "plyr",
 | 
				
			||||||
    "version": "3.4.4",
 | 
					    "version": "3.4.5",
 | 
				
			||||||
    "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": "https://plyr.io",
 | 
					    "homepage": "https://plyr.io",
 | 
				
			||||||
    "author": "Sam Potts <sam@potts.es>",
 | 
					    "author": "Sam Potts <sam@potts.es>",
 | 
				
			||||||
 | 
				
			|||||||
@ -132,13 +132,13 @@ See [initialising](#initialising) for more information on advanced setups.
 | 
				
			|||||||
You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build.
 | 
					You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```html
 | 
					```html
 | 
				
			||||||
<script src="https://cdn.plyr.io/3.4.4/plyr.js"></script>
 | 
					<script src="https://cdn.plyr.io/3.4.5/plyr.js"></script>
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
...or...
 | 
					...or...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```html
 | 
					```html
 | 
				
			||||||
<script src="https://cdn.plyr.io/3.4.4/plyr.polyfilled.js"></script>
 | 
					<script src="https://cdn.plyr.io/3.4.5/plyr.polyfilled.js"></script>
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### CSS
 | 
					### CSS
 | 
				
			||||||
@ -152,13 +152,13 @@ Include the `plyr.css` stylsheet into your `<head>`
 | 
				
			|||||||
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
 | 
					If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```html
 | 
					```html
 | 
				
			||||||
<link rel="stylesheet" href="https://cdn.plyr.io/3.4.4/plyr.css">
 | 
					<link rel="stylesheet" href="https://cdn.plyr.io/3.4.5/plyr.css">
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### SVG Sprite
 | 
					### SVG Sprite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
 | 
					The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
 | 
				
			||||||
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.4.4/plyr.svg`.
 | 
					reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.4.5/plyr.svg`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Ads
 | 
					## Ads
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -315,6 +315,7 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
 | 
				
			|||||||
| `quality`            | Object                     | `{ default: 'default', options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default'] }`      | Currently only supported by YouTube. `default` is the default quality level, determined by YouTube. `options` are the options to display.                                                                                                                                                                                                                              |
 | 
					| `quality`            | Object                     | `{ default: 'default', options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default'] }`      | Currently only supported by YouTube. `default` is the default quality level, determined by YouTube. `options` are the options to display.                                                                                                                                                                                                                              |
 | 
				
			||||||
| `loop`               | Object                     | `{ active: false }`                                                                                                            | `active`: Whether to loop the current video. If the `loop` attribute is present on a `<video>` or `<audio>` element, this will be automatically set to true This is an object to support future functionality.                                                                                                                                                         |
 | 
					| `loop`               | Object                     | `{ active: false }`                                                                                                            | `active`: Whether to loop the current video. If the `loop` attribute is present on a `<video>` or `<audio>` element, this will be automatically set to true This is an object to support future functionality.                                                                                                                                                         |
 | 
				
			||||||
| `ads`                | Object                     | `{ enabled: false, publisherId: '' }`                                                                                          | `enabled`: Whether to enable vi.ai ads. `publisherId`: Your unique vi.ai publisher ID.                                                                                                                                                                                                                                                                                 |
 | 
					| `ads`                | Object                     | `{ enabled: false, publisherId: '' }`                                                                                          | `enabled`: Whether to enable vi.ai ads. `publisherId`: Your unique vi.ai publisher ID.                                                                                                                                                                                                                                                                                 |
 | 
				
			||||||
 | 
					| `urls`               | Object                     | See source.                                                                                                                    | If you wish to override any API URLs then you can do so here. You can also set a custom download URL for the download button.                                                                                                                                                                                                                                          |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1.  Vimeo only
 | 
					1.  Vimeo only
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
// ==========================================================================
 | 
					// ==========================================================================
 | 
				
			||||||
// Plyr
 | 
					// Plyr
 | 
				
			||||||
// plyr.js v3.4.4
 | 
					// plyr.js v3.4.5
 | 
				
			||||||
// https://github.com/sampotts/plyr
 | 
					// https://github.com/sampotts/plyr
 | 
				
			||||||
// License: The MIT License (MIT)
 | 
					// License: The MIT License (MIT)
 | 
				
			||||||
// ==========================================================================
 | 
					// ==========================================================================
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
// ==========================================================================
 | 
					// ==========================================================================
 | 
				
			||||||
// Plyr Polyfilled Build
 | 
					// Plyr Polyfilled Build
 | 
				
			||||||
// plyr.js v3.4.4
 | 
					// plyr.js v3.4.5
 | 
				
			||||||
// https://github.com/sampotts/plyr
 | 
					// https://github.com/sampotts/plyr
 | 
				
			||||||
// License: The MIT License (MIT)
 | 
					// License: The MIT License (MIT)
 | 
				
			||||||
// ==========================================================================
 | 
					// ==========================================================================
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user