diff options
Diffstat (limited to 'dist/plyr.min.js.map')
-rw-r--r-- | dist/plyr.min.js.map | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/dist/plyr.min.js.map b/dist/plyr.min.js.map index d5425a75..1e1e4287 100644 --- a/dist/plyr.min.js.map +++ b/dist/plyr.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["src/js/utils/is.js","src/js/utils/events.js","src/js/utils/elements.js","src/js/utils/animation.js","src/js/utils/browser.js","src/js/support.js","src/js/html5.js","src/js/utils/arrays.js","src/js/utils/objects.js","src/js/utils/strings.js","src/js/utils/i18n.js","src/js/storage.js","src/js/utils/fetch.js","src/js/utils/loadSprite.js","src/js/utils/time.js","src/js/controls.js","src/js/utils/urls.js","src/js/captions.js","src/js/config/defaults.js","src/js/config/types.js","src/js/console.js","src/js/fullscreen.js","src/js/utils/loadImage.js","src/js/ui.js","src/js/listeners.js","node_modules/loadjs/dist/loadjs.umd.js","src/js/utils/loadScript.js","src/js/plugins/vimeo.js","src/js/plugins/youtube.js","src/js/media.js","src/js/plugins/ads.js","src/js/source.js","src/js/plyr.js"],"names":["getConstructor","input","constructor","instanceOf","Boolean","isNullOrUndefined","isObject","Object","isString","String","isArray","Array","isNodeList","NodeList","isEmpty","length","keys","is","nullOrUndefined","object","number","Number","isNaN","string","boolean","function","Function","array","weakMap","WeakMap","nodeList","element","Element","textNode","Text","event","Event","keyboardEvent","KeyboardEvent","cue","window","TextTrackCue","VTTCue","track","TextTrack","kind","url","URL","startsWith","concat","hostname","e","empty","supportsPassiveListeners","supported","options","defineProperty","get","addEventListener","removeEventListener","toggleListener","callback","_this","this","toggle","arguments","undefined","passive","capture","events","split","forEach","type","eventListeners","push","on","call","off","once","onceCallback","_len","args","_key","apply","triggerEvent","bubbles","detail","CustomEvent","assign","plyr","dispatchEvent","wrap","elements","wrapper","targets","from","reverse","index","child","cloneNode","parent","parentNode","sibling","nextSibling","appendChild","insertBefore","setAttributes","attributes","entries","filter","_ref","value","_slicedToArray","_ref3","_ref4","key","setAttribute","createElement","text","document","innerText","insertElement","removeElement","removeChild","emptyElement","childNodes","lastChild","replaceElement","newChild","oldChild","replaceChild","getAttributesFromSelector","sel","existingAttributes","existing","s","selector","trim","className","replace","parts","charAt","class","id","toggleHidden","hidden","hide","removeAttribute","toggleClass","force","map","method","classList","contains","hasClass","matches","prototype","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","querySelectorAll","includes","getElements","container","getElement","querySelector","setFocus","tabFocus","focus","config","classNames","transitionEndEvent","WebkitTransition","MozTransition","OTransition","transition","find","style","repaint","setTimeout","offsetHeight","range","browser","isIE","documentMode","isWebkit","documentElement","test","navigator","userAgent","isIPhone","platform","isIos","defaultCodecs","audio/ogg","audio/wav","video/webm","video/mp4","video/ogg","support","audio","video","check","provider","playsinline","canPlayInline","api","ui","rangeInput","pip","webkitSetPresentationMode","airplay","WebKitPlaybackTargetAvailabilityEvent","mime","inputType","mediaType","isHTML5","media","canPlayType","err","textTracks","touch","transitions","reducedMotion","matchMedia","html5","getSources","source","getAttribute","getQualityOptions","extend","player","set","_player$media","currentTime","paused","preload","readyState","src","play","load","quality","storage","cancelRequests","blankVideo","debug","log","dedupe","item","indexOf","getDeep","path","reduce","obj","target","sources","shift","_defineProperty","format","toString","match","i","replaceAll","RegExp","toTitleCase","toUpperCase","substr","toLowerCase","toCamelCase","toPascalCase","slice","getHTML","innerHTML","i18n","{seektime}","seekTime","{title}","title","_ref2","Storage","_classCallCheck","enabled","store","localStorage","getItem","json","JSON","parse","setItem","stringify","removeItem","fetch","responseType","Promise","resolve","reject","request","XMLHttpRequest","responseText","response","Error","status","open","send","loadSprite","hasId","exists","getElementById","update","data","body","insertAdjacentElement","useStorage","cached","content","then","result","catch","getHours","parseInt","getMinutes","getSeconds","formatTime","time","displayHours","inverted","hours","mins","secs","controls","getIconUrl","cors","iconUrl","location","host","svg4everybody","findElements","selectors","buttons","pause","restart","rewind","fastForward","mute","settings","captions","fullscreen","progress","inputs","seek","volume","display","buffer","duration","seekTooltip","tooltip","error","warn","toggleNativeControls","createIcon","iconPath","iconPrefix","icon","createElementNS","role","focusable","use","setAttributeNS","createLabel","attr","join","createBadge","badge","menu","createButton","buttonType","label","labelPressed","iconPressed","button","control","createRange","min","max","step","autocomplete","aria-label","aria-valuemin","aria-valuemax","aria-valuenow","updateRangeFill","createProgress","aria-hidden","suffixKey","played","suffix","createTime","bindMenuItemShortcuts","menuItem","which","preventDefault","stopPropagation","isRadioButton","showMenuPanel","nextElementSibling","firstElementChild","previousElementSibling","lastElementChild","focusFirstMenuItem","createMenuItem","_this2","list","_ref$badge","_ref$checked","checked","aria-checked","flex","enumerable","children","node","listeners","bind","currentTrack","speed","parseFloat","updateTimeDisplay","updateVolume","setRange","muted","pressed","updateProgress","_this3","current","toFixed","getElementsByTagName","nodeValue","setProgress","buffered","percent","setProperty","updateSeekTooltip","_this4","tooltips","clientRect","getBoundingClientRect","visible","width","pageX","left","timeUpdate","invert","invertTime","seeking","durationUpdate","Math","pow","hasDuration","displayDuration","toggleMenuButton","setting","updateSetting","pane","panels","default","getLabel","setQualityMenu","_this5","checkMenu","sort","a","b","sorting","getBadge","setCaptionsMenu","_this6","tracks","getTracks","toggled","language","unshift","setSpeedMenu","_this7","isVimeo","values","some","popup","firstItem","toggleMenu","show","isMenuItem","getMenuSize","tab","clone","position","opacity","scrollWidth","height","scrollHeight","_this8","size","restore","propertyName","create","_this9","aria-haspopup","aria-controls","aria-expanded","inner","home","backButton","inject","_this10","floor","random","props","seektime","addProperty","controlPressed","_this$config","labels","parseUrl","parser","href","buildUrlParams","params","URLSearchParams","setup","isVideo","isYouTube","protocol","blob","createObjectURL","languages","userLanguage","active","trackEvents","_this$captions","meta","currentTrackNode","languageExists","mode","updateCues","setLanguage","activeClass","findTrack","_toConsumableArray","embed","enableTextTrack","has","sortIsDefault","sorted","every","getCurrentTrack","cues","activeCues","getCueAsHTML","cueText","caption","defaults","autoplay","autopause","toggleInvert","ratio","clickToPlay","hideControls","resetOnEnd","disableContextMenu","loop","selected","keyboard","focused","global","fallback","iosNative","seekLabel","unmute","enableCaptions","disableCaptions","enterFullscreen","exitFullscreen","frameTitle","menuBack","normal","start","end","all","reset","disabled","advertisement","qualityBadge","2160","1440","1080","720","576","480","urls","vimeo","sdk","iframe","youtube","googleIMA","editable","embedContainer","poster","posterEnabled","ads","playing","stopped","loading","hover","isTouch","uiSupported","noTransition","google","publisherId","providers","types","noop","Console","console","onChange","first","last","keyCode","activeElement","shiftKey","toggleFallback","scrollPosition","x","scrollX","y","scrollY","scrollTo","overflow","viewport","head","property","hasProperty","cleanupViewport","part","Fullscreen","prefix","native","webkitEnterFullscreen","requestFullscreen","webkitExitFullscreen","action","cancelFullScreen","exit","enter","fullscreenElement","fullscreenEnabled","webkitFullscreenEnabled","mozFullScreenEnabled","msFullscreenEnabled","pre","loadImage","minWidth","image","Image","handler","onload","onerror","naturalWidth","addStyleHook","build","checkPlaying","ready","setTitle","setPoster","isEmbed","togglePoster","enable","backgroundImage","backgroundSize","toggleControls","checkLoading","clearTimeout","timers","Listeners","lastKey","focusTimer","lastKeyDown","handleKey","setTabFocus","firstTouch","code","repeat","altKey","ctrlKey","metaKey","togglePlay","increaseVolume","decreaseVolume","forward","toggleCaptions","timeStamp","wasKeyDown","delay","hasAudio","initialized","managerPromise","isAudio","ended","proxyEvents","_event$detail","defaultHandler","customHandlerKey","customHandler","returned","hasCustomHandler","proxy","inputEvent","rect","currentTarget","hasAttribute","done","seekTo","isFocusIn","webkitDirectionInvertedFromDevice","_map2","deltaX","deltaY","direction","sign","abs","factory","devnull","bundleIdCache","bundleResultCache","bundleCallbackQueue","publish","bundleId","pathsNotFound","q","splice","executeCallbacks","depsNotFound","success","loadFile","callbackFn","numTries","isCss","doc","async","maxTries","numRetries","beforeCallbackFn","before","pathStripped","rel","onbeforeload","ev","sheet","cssText","defaultPrevented","loadjs","paths","arg1","arg2","fn","numWaiting","loadFiles","deps","bundleIds","r","subscribe","isDefined","module","exports","loadScript","assurePlaybackState","hasPlayed","setAspectRatio","Vimeo","_split2","padding","paddingBottom","offset","transform","byline","portrait","transparent","gesture","$2","thumbnail_large","pathname","Player","disableTextTrack","stop","restorePause","setVolume","setCurrentTime","setPlaybackRate","name","currentSrc","setLoop","getVideoUrl","getVideoWidth","getVideoHeight","dimensions","getRatio","w","h","getAspectRatio","setAutopause","state","getVideoTitle","getCurrentTime","getDuration","getTextTracks","_ref$cues","strippedCues","fragment","createDocumentFragment","firstChild","getPaused","seconds","YT","onYouTubeReadyCallbacks","onYouTubeIframeAPIReady","getTitle","videoId","getVideoData","items","snippet","currentId","posterSrc","playerVars","hl","showinfo","iv_load_policy","modestbranding","disablekb","widget_referrer","cc_load_policy","cc_lang_pref","onError","message","2","5","100","101","150","onPlaybackRateChange","instance","playbackRate","getPlaybackRate","onReady","playVideo","pauseVideo","stopVideo","getAvailablePlaybackRates","clearInterval","buffering","setInterval","getVideoLoadedFraction","lastBuffered","onStateChange","unMute","Ads","displayContainer","manager","loader","cuePoints","safetyTimer","countdownTimer","ima","trigger","startSafetyTimer","clearSafetyTimer","setupIMA","setVpaidMode","ImaSdkSettings","VpaidMode","ENABLED","setLocale","AdDisplayContainer","requestAds","AdsLoader","AdsManagerLoadedEvent","Type","ADS_MANAGER_LOADED","onAdsManagerLoaded","AdErrorEvent","AD_ERROR","onAdError","AdsRequest","adTagUrl","tagUrl","linearAdSlotWidth","offsetWidth","linearAdSlotHeight","nonLinearAdSlotWidth","nonLinearAdSlotHeight","forceNonLinearFullSlot","setAdWillPlayMuted","getRemainingTime","AdsRenderingSettings","restoreCustomPlaybackStateOnAdBreakComplete","enablePreloading","getAdsManager","getCuePoints","cuePoint","seekElement","cuePercentage","AdEvent","onAdEvent","ad","getAd","LOADED","pollCountdown","isLinear","ALL_ADS_COMPLETED","loadAds","CONTENT_PAUSE_REQUESTED","pauseContent","CONTENT_RESUME_REQUESTED","resumeContent","STARTED","MIDPOINT","COMPLETE","IMPRESSION","CLICK","cancel","contentComplete","seekedTime","discardAdBreak","resize","ViewMode","NORMAL","initialize","init","adError","zIndex","destroy","_this11","handlers","_this12","AV_PUBLISHERID","AV_CHANNELID","AV_URL","cb","Date","now","AV_WIDTH","AV_HEIGHT","AV_CDIM2","insertElements","attribute","change","_sources$","_sources$$provider","tagName","crossorigin","Plyr","failed","jQuery","original","getProviderByUrl","search","truthy","searchParams","webkitShowPlaybackTargetPicker","isHidden","hiding","eventName","soft","unload","inputIsValid","fauxDuration","realDuration","Infinity","mozHasAudio","webkitAudioDecodedByteCount","audioTracks","prev","curr","closest","states","webkitPresentationMode","inline","t"],"mappings":"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","file":"plyr.min.js","sourcesContent":["// ==========================================================================\n// Type checking utils\n// ==========================================================================\n\nconst getConstructor = input => (input !== null && typeof input !== 'undefined' ? input.constructor : null);\nconst instanceOf = (input, constructor) => Boolean(input && constructor && input instanceof constructor);\nconst isNullOrUndefined = input => input === null || typeof input === 'undefined';\nconst isObject = input => getConstructor(input) === Object;\nconst isNumber = input => getConstructor(input) === Number && !Number.isNaN(input);\nconst isString = input => getConstructor(input) === String;\nconst isBoolean = input => getConstructor(input) === Boolean;\nconst isFunction = input => getConstructor(input) === Function;\nconst isArray = input => Array.isArray(input);\nconst isWeakMap = input => instanceOf(input, WeakMap);\nconst isNodeList = input => instanceOf(input, NodeList);\nconst isElement = input => instanceOf(input, Element);\nconst isTextNode = input => getConstructor(input) === Text;\nconst isEvent = input => instanceOf(input, Event);\nconst isKeyboardEvent = input => instanceOf(input, KeyboardEvent);\nconst isCue = input => instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);\nconst isTrack = input => instanceOf(input, TextTrack) || (!isNullOrUndefined(input) && isString(input.kind));\n\nconst isEmpty = input =>\n isNullOrUndefined(input) ||\n ((isString(input) || isArray(input) || isNodeList(input)) && !input.length) ||\n (isObject(input) && !Object.keys(input).length);\n\nconst isUrl = input => {\n // Accept a URL object\n if (instanceOf(input, window.URL)) {\n return true;\n }\n\n // Add the protocol if required\n let string = input;\n if (!input.startsWith('http://') || !input.startsWith('https://')) {\n string = `http://${input}`;\n }\n\n try {\n return !isEmpty(new URL(string).hostname);\n } catch (e) {\n return false;\n }\n};\n\nexport default {\n nullOrUndefined: isNullOrUndefined,\n object: isObject,\n number: isNumber,\n string: isString,\n boolean: isBoolean,\n function: isFunction,\n array: isArray,\n weakMap: isWeakMap,\n nodeList: isNodeList,\n element: isElement,\n textNode: isTextNode,\n event: isEvent,\n keyboardEvent: isKeyboardEvent,\n cue: isCue,\n track: isTrack,\n url: isUrl,\n empty: isEmpty,\n};\n","// ==========================================================================\n// Event utils\n// ==========================================================================\n\nimport is from './is';\n\n// Check for passive event listener support\n// https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n// https://www.youtube.com/watch?v=NPM6172J22g\nconst supportsPassiveListeners = (() => {\n // Test via a getter in the options object to see if the passive property is accessed\n let supported = false;\n try {\n const options = Object.defineProperty({}, 'passive', {\n get() {\n supported = true;\n return null;\n },\n });\n window.addEventListener('test', null, options);\n window.removeEventListener('test', null, options);\n } catch (e) {\n // Do nothing\n }\n\n return supported;\n})();\n\n// Toggle event listener\nexport function toggleListener(element, event, callback, toggle = false, passive = true, capture = false) {\n // Bail if no element, event, or callback\n if (!element || !('addEventListener' in element) || is.empty(event) || !is.function(callback)) {\n return;\n }\n\n // Allow multiple events\n const events = event.split(' ');\n\n // Build options\n // Default to just the capture boolean for browsers with no passive listener support\n let options = capture;\n\n // If passive events listeners are supported\n if (supportsPassiveListeners) {\n options = {\n // Whether the listener can be passive (i.e. default never prevented)\n passive,\n // Whether the listener is a capturing listener or not\n capture,\n };\n }\n\n // If a single node is passed, bind the event listener\n events.forEach(type => {\n if (this && this.eventListeners && toggle) {\n // Cache event listener\n this.eventListeners.push({ element, type, callback, options });\n }\n\n element[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);\n });\n}\n\n// Bind event handler\nexport function on(element, events = '', callback, passive = true, capture = false) {\n toggleListener.call(this, element, events, callback, true, passive, capture);\n}\n\n// Unbind event handler\nexport function off(element, events = '', callback, passive = true, capture = false) {\n toggleListener.call(this, element, events, callback, false, passive, capture);\n}\n\n// Bind once-only event handler\nexport function once(element, events = '', callback, passive = true, capture = false) {\n function onceCallback(...args) {\n off(element, events, onceCallback, passive, capture);\n callback.apply(this, args);\n }\n\n toggleListener.call(this, element, events, onceCallback, true, passive, capture);\n}\n\n// Trigger event\nexport function triggerEvent(element, type = '', bubbles = false, detail = {}) {\n // Bail if no element\n if (!is.element(element) || is.empty(type)) {\n return;\n }\n\n // Create and dispatch the event\n const event = new CustomEvent(type, {\n bubbles,\n detail: Object.assign({}, detail, {\n plyr: this,\n }),\n });\n\n // Dispatch the event\n element.dispatchEvent(event);\n}\n\n// Unbind all cached event listeners\nexport function unbindListeners() {\n if (this && this.eventListeners) {\n this.eventListeners.forEach(item => {\n const { element, type, callback, options } = item;\n element.removeEventListener(type, callback, options);\n });\n\n this.eventListeners = [];\n }\n}\n\n// Run method when / if player is ready\nexport function ready() {\n return new Promise(\n resolve => (this.ready ? setTimeout(resolve, 0) : on.call(this, this.elements.container, 'ready', resolve)),\n ).then(() => {});\n}\n","// ==========================================================================\n// Element utils\n// ==========================================================================\n\nimport { toggleListener } from './events';\nimport is from './is';\n\n// Wrap an element\nexport function wrap(elements, wrapper) {\n // Convert `elements` to an array, if necessary.\n const targets = elements.length ? elements : [elements];\n\n // Loops backwards to prevent having to clone the wrapper on the\n // first element (see `child` below).\n Array.from(targets)\n .reverse()\n .forEach((element, index) => {\n const child = index > 0 ? wrapper.cloneNode(true) : wrapper;\n\n // Cache the current parent and sibling.\n const parent = element.parentNode;\n const sibling = element.nextSibling;\n\n // Wrap the element (is automatically removed from its current\n // parent).\n child.appendChild(element);\n\n // If the element had a sibling, insert the wrapper before\n // the sibling to maintain the HTML structure; otherwise, just\n // append it to the parent.\n if (sibling) {\n parent.insertBefore(child, sibling);\n } else {\n parent.appendChild(child);\n }\n });\n}\n\n// Set attributes\nexport function setAttributes(element, attributes) {\n if (!is.element(element) || is.empty(attributes)) {\n return;\n }\n\n // Assume null and undefined attributes should be left out,\n // Setting them would otherwise convert them to \"null\" and \"undefined\"\n Object.entries(attributes)\n .filter(([, value]) => !is.nullOrUndefined(value))\n .forEach(([key, value]) => element.setAttribute(key, value));\n}\n\n// Create a DocumentFragment\nexport function createElement(type, attributes, text) {\n // Create a new <element>\n const element = document.createElement(type);\n\n // Set all passed attributes\n if (is.object(attributes)) {\n setAttributes(element, attributes);\n }\n\n // Add text node\n if (is.string(text)) {\n element.innerText = text;\n }\n\n // Return built element\n return element;\n}\n\n// Inaert an element after another\nexport function insertAfter(element, target) {\n if (!is.element(element) || !is.element(target)) {\n return;\n }\n\n target.parentNode.insertBefore(element, target.nextSibling);\n}\n\n// Insert a DocumentFragment\nexport function insertElement(type, parent, attributes, text) {\n if (!is.element(parent)) {\n return;\n }\n\n parent.appendChild(createElement(type, attributes, text));\n}\n\n// Remove element(s)\nexport function removeElement(element) {\n if (is.nodeList(element) || is.array(element)) {\n Array.from(element).forEach(removeElement);\n return;\n }\n\n if (!is.element(element) || !is.element(element.parentNode)) {\n return;\n }\n\n element.parentNode.removeChild(element);\n}\n\n// Remove all child elements\nexport function emptyElement(element) {\n if (!is.element(element)) {\n return;\n }\n\n let { length } = element.childNodes;\n\n while (length > 0) {\n element.removeChild(element.lastChild);\n length -= 1;\n }\n}\n\n// Replace element\nexport function replaceElement(newChild, oldChild) {\n if (!is.element(oldChild) || !is.element(oldChild.parentNode) || !is.element(newChild)) {\n return null;\n }\n\n oldChild.parentNode.replaceChild(newChild, oldChild);\n\n return newChild;\n}\n\n// Get an attribute object from a string selector\nexport function getAttributesFromSelector(sel, existingAttributes) {\n // For example:\n // '.test' to { class: 'test' }\n // '#test' to { id: 'test' }\n // '[data-test=\"test\"]' to { 'data-test': 'test' }\n\n if (!is.string(sel) || is.empty(sel)) {\n return {};\n }\n\n const attributes = {};\n const existing = existingAttributes;\n\n sel.split(',').forEach(s => {\n // Remove whitespace\n const selector = s.trim();\n const className = selector.replace('.', '');\n const stripped = selector.replace(/[[\\]]/g, '');\n\n // Get the parts and value\n const parts = stripped.split('=');\n const key = parts[0];\n const value = parts.length > 1 ? parts[1].replace(/[\"']/g, '') : '';\n\n // Get the first character\n const start = selector.charAt(0);\n\n switch (start) {\n case '.':\n // Add to existing classname\n if (is.object(existing) && is.string(existing.class)) {\n existing.class += ` ${className}`;\n }\n\n attributes.class = className;\n break;\n\n case '#':\n // ID selector\n attributes.id = selector.replace('#', '');\n break;\n\n case '[':\n // Attribute selector\n attributes[key] = value;\n\n break;\n\n default:\n break;\n }\n });\n\n return attributes;\n}\n\n// Toggle hidden\nexport function toggleHidden(element, hidden) {\n if (!is.element(element)) {\n return;\n }\n\n let hide = hidden;\n\n if (!is.boolean(hide)) {\n hide = !element.hidden;\n }\n\n if (hide) {\n element.setAttribute('hidden', '');\n } else {\n element.removeAttribute('hidden');\n }\n}\n\n// Mirror Element.classList.toggle, with IE compatibility for \"force\" argument\nexport function toggleClass(element, className, force) {\n if (is.nodeList(element)) {\n return Array.from(element).map(e => toggleClass(e, className, force));\n }\n\n if (is.element(element)) {\n let method = 'toggle';\n if (typeof force !== 'undefined') {\n method = force ? 'add' : 'remove';\n }\n\n element.classList[method](className);\n return element.classList.contains(className);\n }\n\n return false;\n}\n\n// Has class name\nexport function hasClass(element, className) {\n return is.element(element) && element.classList.contains(className);\n}\n\n// Element matches selector\nexport function matches(element, selector) {\n const prototype = { Element };\n\n function match() {\n return Array.from(document.querySelectorAll(selector)).includes(this);\n }\n\n const matches =\n prototype.matches ||\n prototype.webkitMatchesSelector ||\n prototype.mozMatchesSelector ||\n prototype.msMatchesSelector ||\n match;\n\n return matches.call(element, selector);\n}\n\n// Find all elements\nexport function getElements(selector) {\n return this.elements.container.querySelectorAll(selector);\n}\n\n// Find a single element\nexport function getElement(selector) {\n return this.elements.container.querySelector(selector);\n}\n\n// Trap focus inside container\nexport function trapFocus(element = null, toggle = false) {\n if (!is.element(element)) {\n return;\n }\n\n const focusable = getElements.call(this, 'button:not(:disabled), input:not(:disabled), [tabindex]');\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n const trap = event => {\n // Bail if not tab key or not fullscreen\n if (event.key !== 'Tab' || event.keyCode !== 9) {\n return;\n }\n\n // Get the current focused element\n const focused = document.activeElement;\n\n if (focused === last && !event.shiftKey) {\n // Move focus to first element that can be tabbed if Shift isn't used\n first.focus();\n event.preventDefault();\n } else if (focused === first && event.shiftKey) {\n // Move focus to last element that can be tabbed if Shift is used\n last.focus();\n event.preventDefault();\n }\n };\n\n toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false);\n}\n\n// Set focus and tab focus class\nexport function setFocus(element = null, tabFocus = false) {\n if (!is.element(element)) {\n return;\n }\n\n // Set regular focus\n element.focus();\n\n // If we want to mimic keyboard focus via tab\n if (tabFocus) {\n toggleClass(element, this.config.classNames.tabFocus);\n }\n}\n","// ==========================================================================\n// Animation utils\n// ==========================================================================\n\nimport { toggleHidden } from './elements';\nimport is from './is';\n\nexport const transitionEndEvent = (() => {\n const element = document.createElement('span');\n\n const events = {\n WebkitTransition: 'webkitTransitionEnd',\n MozTransition: 'transitionend',\n OTransition: 'oTransitionEnd otransitionend',\n transition: 'transitionend',\n };\n\n const type = Object.keys(events).find(event => element.style[event] !== undefined);\n\n return is.string(type) ? events[type] : false;\n})();\n\n// Force repaint of element\nexport function repaint(element) {\n setTimeout(() => {\n try {\n toggleHidden(element, true);\n element.offsetHeight; // eslint-disable-line\n toggleHidden(element, false);\n } catch (e) {\n // Do nothing\n }\n }, 0);\n}\n","// ==========================================================================\n// Browser sniffing\n// Unfortunately, due to mixed support, UA sniffing is required\n// ==========================================================================\n\nconst browser = {\n isIE: /* @cc_on!@ */ false || !!document.documentMode,\n isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),\n isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),\n isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform),\n};\n\nexport default browser;\n","// ==========================================================================\n// Plyr support checks\n// ==========================================================================\n\nimport { transitionEndEvent } from './utils/animation';\nimport browser from './utils/browser';\nimport { createElement } from './utils/elements';\nimport is from './utils/is';\n\n// Default codecs for checking mimetype support\nconst defaultCodecs = {\n 'audio/ogg': 'vorbis',\n 'audio/wav': '1',\n 'video/webm': 'vp8, vorbis',\n 'video/mp4': 'avc1.42E01E, mp4a.40.2',\n 'video/ogg': 'theora',\n};\n\n// Check for feature support\nconst support = {\n // Basic support\n audio: 'canPlayType' in document.createElement('audio'),\n video: 'canPlayType' in document.createElement('video'),\n\n // Check for support\n // Basic functionality vs full UI\n check(type, provider, playsinline) {\n const canPlayInline = browser.isIPhone && playsinline && support.playsinline;\n const api = support[type] || provider !== 'html5';\n const ui = api && support.rangeInput && (type !== 'video' || !browser.isIPhone || canPlayInline);\n\n return {\n api,\n ui,\n };\n },\n\n // Picture-in-picture support\n // Safari only currently\n pip: (() => !browser.isIPhone && is.function(createElement('video').webkitSetPresentationMode))(),\n\n // Airplay support\n // Safari only currently\n airplay: is.function(window.WebKitPlaybackTargetAvailabilityEvent),\n\n // Inline playback support\n // https://webkit.org/blog/6784/new-video-policies-for-ios/\n playsinline: 'playsInline' in document.createElement('video'),\n\n // Check for mime type support against a player instance\n // Credits: http://diveintohtml5.info/everything.html\n // Related: http://www.leanbackplayer.com/test/h5mt.html\n mime(inputType) {\n const [mediaType] = inputType.split('/');\n if (!this.isHTML5 || mediaType !== this.type) {\n return false;\n }\n\n let type;\n if (inputType && inputType.includes('codecs=')) {\n // Use input directly\n type = inputType;\n } else if (inputType === 'audio/mpeg') {\n // Skip codec\n type = 'audio/mpeg;';\n } else if (inputType in defaultCodecs) {\n // Use codec\n type = `${inputType}; codecs=\"${defaultCodecs[inputType]}\"`;\n }\n\n try {\n return Boolean(type && this.media.canPlayType(type).replace(/no/, ''));\n } catch (err) {\n return false;\n }\n },\n\n // Check for textTracks support\n textTracks: 'textTracks' in document.createElement('video'),\n\n // <input type=\"range\"> Sliders\n rangeInput: (() => {\n const range = document.createElement('input');\n range.type = 'range';\n return range.type === 'range';\n })(),\n\n // Touch\n // NOTE: Remember a device can be mouse + touch enabled so we check on first touch event\n touch: 'ontouchstart' in document.documentElement,\n\n // Detect transitions support\n transitions: transitionEndEvent !== false,\n\n // Reduced motion iOS & MacOS setting\n // https://webkit.org/blog/7551/responsive-design-for-motion/\n reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches,\n};\n\nexport default support;\n","// ==========================================================================\n// Plyr HTML5 helpers\n// ==========================================================================\n\nimport support from './support';\nimport { removeElement } from './utils/elements';\nimport { triggerEvent } from './utils/events';\n\nconst html5 = {\n getSources() {\n if (!this.isHTML5) {\n return [];\n }\n\n const sources = Array.from(this.media.querySelectorAll('source'));\n\n // Filter out unsupported sources\n return sources.filter(source => support.mime.call(this, source.getAttribute('type')));\n },\n\n // Get quality levels\n getQualityOptions() {\n // Get sizes from <source> elements\n return html5.getSources\n .call(this)\n .map(source => Number(source.getAttribute('size')))\n .filter(Boolean);\n },\n\n extend() {\n if (!this.isHTML5) {\n return;\n }\n\n const player = this;\n\n // Quality\n Object.defineProperty(player.media, 'quality', {\n get() {\n // Get sources\n const sources = html5.getSources.call(player);\n const source = sources.find(source => source.getAttribute('src') === player.source);\n\n // Return size, if match is found\n return source && Number(source.getAttribute('size'));\n },\n set(input) {\n // Get sources\n const sources = html5.getSources.call(player);\n\n // Get first match for requested size\n const source = sources.find(source => Number(source.getAttribute('size')) === input);\n\n // No matching source found\n if (!source) {\n return;\n }\n\n // Get current state\n const { currentTime, paused, preload, readyState } = player.media;\n\n // Set new source\n player.media.src = source.getAttribute('src');\n\n // Prevent loading if preload=\"none\" and the current source isn't loaded (#1044)\n if (preload !== 'none' || readyState) {\n // Restore time\n player.once('loadedmetadata', () => {\n player.currentTime = currentTime;\n\n // Resume playing\n if (!paused) {\n player.play();\n }\n });\n\n // Load new source\n player.media.load();\n }\n\n // Trigger change event\n triggerEvent.call(player, player.media, 'qualitychange', false, {\n quality: input,\n });\n\n // Save to storage\n player.storage.set({ quality: input });\n },\n });\n },\n\n // Cancel current network requests\n // See https://github.com/sampotts/plyr/issues/174\n cancelRequests() {\n if (!this.isHTML5) {\n return;\n }\n\n // Remove child sources\n removeElement(html5.getSources.call(this));\n\n // Set blank video src attribute\n // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error\n // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection\n this.media.setAttribute('src', this.config.blankVideo);\n\n // Load the new empty source\n // This will cancel existing requests\n // See https://github.com/sampotts/plyr/issues/174\n this.media.load();\n\n // Debugging\n this.debug.log('Cancelled network requests');\n },\n};\n\nexport default html5;\n","// ==========================================================================\n// Array utils\n// ==========================================================================\n\nimport is from './is';\n\n// Remove duplicates in an array\nexport function dedupe(array) {\n if (!is.array(array)) {\n return array;\n }\n\n return array.filter((item, index) => array.indexOf(item) === index);\n}\n\n// Get the closest value in an array\nexport function closest(array, value) {\n if (!is.array(array) || !array.length) {\n return null;\n }\n\n return array.reduce((prev, curr) => (Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev));\n}\n","// ==========================================================================\n// Object utils\n// ==========================================================================\n\nimport is from './is';\n\n// Clone nested objects\nexport function cloneDeep(object) {\n return JSON.parse(JSON.stringify(object));\n}\n\n// Get a nested value in an object\nexport function getDeep(object, path) {\n return path.split('.').reduce((obj, key) => obj && obj[key], object);\n}\n\n// Deep extend destination object with N more objects\nexport function extend(target = {}, ...sources) {\n if (!sources.length) {\n return target;\n }\n\n const source = sources.shift();\n\n if (!is.object(source)) {\n return target;\n }\n\n Object.keys(source).forEach(key => {\n if (is.object(source[key])) {\n if (!Object.keys(target).includes(key)) {\n Object.assign(target, { [key]: {} });\n }\n\n extend(target[key], source[key]);\n } else {\n Object.assign(target, { [key]: source[key] });\n }\n });\n\n return extend(target, ...sources);\n}\n","// ==========================================================================\n// String utils\n// ==========================================================================\n\nimport is from './is';\n\n// Generate a random ID\nexport function generateId(prefix) {\n return `${prefix}-${Math.floor(Math.random() * 10000)}`;\n}\n\n// Format string\nexport function format(input, ...args) {\n if (is.empty(input)) {\n return input;\n }\n\n return input.toString().replace(/{(\\d+)}/g, (match, i) => args[i].toString());\n}\n\n// Get percentage\nexport function getPercentage(current, max) {\n if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {\n return 0;\n }\n\n return ((current / max) * 100).toFixed(2);\n}\n\n// Replace all occurances of a string in a string\nexport function replaceAll(input = '', find = '', replace = '') {\n return input.replace(\n new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\\]/\\\\])/g, '\\\\$1'), 'g'),\n replace.toString(),\n );\n}\n\n// Convert to title case\nexport function toTitleCase(input = '') {\n return input.toString().replace(/\\w\\S*/g, text => text.charAt(0).toUpperCase() + text.substr(1).toLowerCase());\n}\n\n// Convert string to pascalCase\nexport function toPascalCase(input = '') {\n let string = input.toString();\n\n // Convert kebab case\n string = replaceAll(string, '-', ' ');\n\n // Convert snake case\n string = replaceAll(string, '_', ' ');\n\n // Convert to title case\n string = toTitleCase(string);\n\n // Convert to pascal case\n return replaceAll(string, ' ', '');\n}\n\n// Convert string to pascalCase\nexport function toCamelCase(input = '') {\n let string = input.toString();\n\n // Convert to pascal case\n string = toPascalCase(string);\n\n // Convert first character to lowercase\n return string.charAt(0).toLowerCase() + string.slice(1);\n}\n\n// Remove HTML from a string\nexport function stripHTML(source) {\n const fragment = document.createDocumentFragment();\n const element = document.createElement('div');\n fragment.appendChild(element);\n element.innerHTML = source;\n return fragment.firstChild.innerText;\n}\n\n// Like outerHTML, but also works for DocumentFragment\nexport function getHTML(element) {\n const wrapper = document.createElement('div');\n wrapper.appendChild(element);\n return wrapper.innerHTML;\n}\n","// ==========================================================================\n// Plyr internationalization\n// ==========================================================================\n\nimport is from './is';\nimport { getDeep } from './objects';\nimport { replaceAll } from './strings';\n\nconst i18n = {\n get(key = '', config = {}) {\n if (is.empty(key) || is.empty(config)) {\n return '';\n }\n\n let string = getDeep(config.i18n, key);\n\n if (is.empty(string)) {\n return '';\n }\n\n const replace = {\n '{seektime}': config.seekTime,\n '{title}': config.title,\n };\n\n Object.entries(replace).forEach(([key, value]) => {\n string = replaceAll(string, key, value);\n });\n\n return string;\n },\n};\n\nexport default i18n;\n","// ==========================================================================\n// Plyr storage\n// ==========================================================================\n\nimport is from './utils/is';\nimport { extend } from './utils/objects';\n\nclass Storage {\n constructor(player) {\n this.enabled = player.config.storage.enabled;\n this.key = player.config.storage.key;\n }\n\n // Check for actual support (see if we can use it)\n static get supported() {\n try {\n if (!('localStorage' in window)) {\n return false;\n }\n\n const test = '___test';\n\n // Try to use it (it might be disabled, e.g. user is in private mode)\n // see: https://github.com/sampotts/plyr/issues/131\n window.localStorage.setItem(test, test);\n window.localStorage.removeItem(test);\n\n return true;\n } catch (e) {\n return false;\n }\n }\n\n get(key) {\n if (!Storage.supported || !this.enabled) {\n return null;\n }\n\n const store = window.localStorage.getItem(this.key);\n\n if (is.empty(store)) {\n return null;\n }\n\n const json = JSON.parse(store);\n\n return is.string(key) && key.length ? json[key] : json;\n }\n\n set(object) {\n // Bail if we don't have localStorage support or it's disabled\n if (!Storage.supported || !this.enabled) {\n return;\n }\n\n // Can only store objectst\n if (!is.object(object)) {\n return;\n }\n\n // Get current storage\n let storage = this.get();\n\n // Default to empty object\n if (is.empty(storage)) {\n storage = {};\n }\n\n // Update the working copy of the values\n extend(storage, object);\n\n // Update storage\n window.localStorage.setItem(this.key, JSON.stringify(storage));\n }\n}\n\nexport default Storage;\n","// ==========================================================================\n// Fetch wrapper\n// Using XHR to avoid issues with older browsers\n// ==========================================================================\n\nexport default function fetch(url, responseType = 'text') {\n return new Promise((resolve, reject) => {\n try {\n const request = new XMLHttpRequest();\n\n // Check for CORS support\n if (!('withCredentials' in request)) {\n return;\n }\n\n request.addEventListener('load', () => {\n if (responseType === 'text') {\n try {\n resolve(JSON.parse(request.responseText));\n } catch (e) {\n resolve(request.responseText);\n }\n } else {\n resolve(request.response);\n }\n });\n\n request.addEventListener('error', () => {\n throw new Error(request.status);\n });\n\n request.open('GET', url, true);\n\n // Set the required response type\n request.responseType = responseType;\n\n request.send();\n } catch (e) {\n reject(e);\n }\n });\n}\n","// ==========================================================================\n// Sprite loader\n// ==========================================================================\n\nimport Storage from '../storage';\nimport fetch from './fetch';\nimport is from './is';\n\n// Load an external SVG sprite\nexport default function loadSprite(url, id) {\n if (!is.string(url)) {\n return;\n }\n\n const prefix = 'cache';\n const hasId = is.string(id);\n let isCached = false;\n\n const exists = () => document.getElementById(id) !== null;\n\n const update = (container, data) => {\n container.innerHTML = data;\n\n // Check again incase of race condition\n if (hasId && exists()) {\n return;\n }\n\n // Inject the SVG to the body\n document.body.insertAdjacentElement('afterbegin', container);\n };\n\n // Only load once if ID set\n if (!hasId || !exists()) {\n const useStorage = Storage.supported;\n\n // Create container\n const container = document.createElement('div');\n container.setAttribute('hidden', '');\n\n if (hasId) {\n container.setAttribute('id', id);\n }\n\n // Check in cache\n if (useStorage) {\n const cached = window.localStorage.getItem(`${prefix}-${id}`);\n isCached = cached !== null;\n\n if (isCached) {\n const data = JSON.parse(cached);\n update(container, data.content);\n }\n }\n\n // Get the sprite\n fetch(url)\n .then(result => {\n if (is.empty(result)) {\n return;\n }\n\n if (useStorage) {\n window.localStorage.setItem(\n `${prefix}-${id}`,\n JSON.stringify({\n content: result,\n }),\n );\n }\n\n update(container, result);\n })\n .catch(() => {});\n }\n}\n","// ==========================================================================\n// Time utils\n// ==========================================================================\n\nimport is from './is';\n\n// Time helpers\nexport const getHours = value => parseInt((value / 60 / 60) % 60, 10);\nexport const getMinutes = value => parseInt((value / 60) % 60, 10);\nexport const getSeconds = value => parseInt(value % 60, 10);\n\n// Format time to UI friendly string\nexport function formatTime(time = 0, displayHours = false, inverted = false) {\n // Bail if the value isn't a number\n if (!is.number(time)) {\n return formatTime(null, displayHours, inverted);\n }\n\n // Format time component to add leading zero\n const format = value => `0${value}`.slice(-2);\n\n // Breakdown to hours, mins, secs\n let hours = getHours(time);\n const mins = getMinutes(time);\n const secs = getSeconds(time);\n\n // Do we need to display hours?\n if (displayHours || hours > 0) {\n hours = `${hours}:`;\n } else {\n hours = '';\n }\n\n // Render\n return `${inverted && time > 0 ? '-' : ''}${hours}${format(mins)}:${format(secs)}`;\n}\n","// ==========================================================================\n// Plyr controls\n// TODO: This needs to be split into smaller files and cleaned up\n// ==========================================================================\n\nimport captions from './captions';\nimport html5 from './html5';\nimport support from './support';\nimport { repaint, transitionEndEvent } from './utils/animation';\nimport { dedupe } from './utils/arrays';\nimport browser from './utils/browser';\nimport { createElement, emptyElement, getAttributesFromSelector, getElement, getElements, hasClass, matches, removeElement, setAttributes, setFocus, toggleClass, toggleHidden } from './utils/elements';\nimport { off, on } from './utils/events';\nimport i18n from './utils/i18n';\nimport is from './utils/is';\nimport loadSprite from './utils/loadSprite';\nimport { extend } from './utils/objects';\nimport { getPercentage, replaceAll, toCamelCase, toTitleCase } from './utils/strings';\nimport { formatTime, getHours } from './utils/time';\n\n// TODO: Don't export a massive object - break down and create class\nconst controls = {\n // Get icon URL\n getIconUrl() {\n const url = new URL(this.config.iconUrl, window.location);\n const cors = url.host !== window.location.host || (browser.isIE && !window.svg4everybody);\n\n return {\n url: this.config.iconUrl,\n cors,\n };\n },\n\n // Find the UI controls\n findElements() {\n try {\n this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper);\n\n // Buttons\n this.elements.buttons = {\n play: getElements.call(this, this.config.selectors.buttons.play),\n pause: getElement.call(this, this.config.selectors.buttons.pause),\n restart: getElement.call(this, this.config.selectors.buttons.restart),\n rewind: getElement.call(this, this.config.selectors.buttons.rewind),\n fastForward: getElement.call(this, this.config.selectors.buttons.fastForward),\n mute: getElement.call(this, this.config.selectors.buttons.mute),\n pip: getElement.call(this, this.config.selectors.buttons.pip),\n airplay: getElement.call(this, this.config.selectors.buttons.airplay),\n settings: getElement.call(this, this.config.selectors.buttons.settings),\n captions: getElement.call(this, this.config.selectors.buttons.captions),\n fullscreen: getElement.call(this, this.config.selectors.buttons.fullscreen),\n };\n\n // Progress\n this.elements.progress = getElement.call(this, this.config.selectors.progress);\n\n // Inputs\n this.elements.inputs = {\n seek: getElement.call(this, this.config.selectors.inputs.seek),\n volume: getElement.call(this, this.config.selectors.inputs.volume),\n };\n\n // Display\n this.elements.display = {\n buffer: getElement.call(this, this.config.selectors.display.buffer),\n currentTime: getElement.call(this, this.config.selectors.display.currentTime),\n duration: getElement.call(this, this.config.selectors.display.duration),\n };\n\n // Seek tooltip\n if (is.element(this.elements.progress)) {\n this.elements.display.seekTooltip = this.elements.progress.querySelector(\n `.${this.config.classNames.tooltip}`,\n );\n }\n\n return true;\n } catch (error) {\n // Log it\n this.debug.warn('It looks like there is a problem with your custom controls HTML', error);\n\n // Restore native video controls\n this.toggleNativeControls(true);\n\n return false;\n }\n },\n\n // Create <svg> icon\n createIcon(type, attributes) {\n const namespace = 'http://www.w3.org/2000/svg';\n const iconUrl = controls.getIconUrl.call(this);\n const iconPath = `${!iconUrl.cors ? iconUrl.url : ''}#${this.config.iconPrefix}`;\n\n // Create <svg>\n const icon = document.createElementNS(namespace, 'svg');\n setAttributes(\n icon,\n extend(attributes, {\n role: 'presentation',\n focusable: 'false',\n }),\n );\n\n // Create the <use> to reference sprite\n const use = document.createElementNS(namespace, 'use');\n const path = `${iconPath}-${type}`;\n\n // Set `href` attributes\n // https://github.com/sampotts/plyr/issues/460\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href\n if ('href' in use) {\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);\n } else {\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path);\n }\n\n // Add <use> to <svg>\n icon.appendChild(use);\n\n return icon;\n },\n\n // Create hidden text label\n createLabel(type, attr = {}) {\n // Skip i18n for abbreviations and brand names\n const universals = {\n pip: 'PIP',\n airplay: 'AirPlay',\n };\n const text = universals[type] || i18n.get(type, this.config);\n\n const attributes = Object.assign({}, attr, {\n class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' '),\n });\n return createElement('span', attributes, text);\n },\n\n // Create a badge\n createBadge(text) {\n if (is.empty(text)) {\n return null;\n }\n\n const badge = createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n badge.appendChild(\n createElement(\n 'span',\n {\n class: this.config.classNames.menu.badge,\n },\n text,\n ),\n );\n\n return badge;\n },\n\n // Create a <button>\n createButton(buttonType, attr) {\n const button = createElement('button');\n const attributes = Object.assign({}, attr);\n let type = toCamelCase(buttonType);\n\n let toggle = false;\n let label;\n let icon;\n let labelPressed;\n let iconPressed;\n\n if (!('type' in attributes)) {\n attributes.type = 'button';\n }\n\n if ('class' in attributes) {\n if (!attributes.class.includes(this.config.classNames.control)) {\n attributes.class += ` ${this.config.classNames.control}`;\n }\n } else {\n attributes.class = this.config.classNames.control;\n }\n\n // Large play button\n switch (buttonType) {\n case 'play':\n toggle = true;\n label = 'play';\n labelPressed = 'pause';\n icon = 'play';\n iconPressed = 'pause';\n break;\n\n case 'mute':\n toggle = true;\n label = 'mute';\n labelPressed = 'unmute';\n icon = 'volume';\n iconPressed = 'muted';\n break;\n\n case 'captions':\n toggle = true;\n label = 'enableCaptions';\n labelPressed = 'disableCaptions';\n icon = 'captions-off';\n iconPressed = 'captions-on';\n break;\n\n case 'fullscreen':\n toggle = true;\n label = 'enterFullscreen';\n labelPressed = 'exitFullscreen';\n icon = 'enter-fullscreen';\n iconPressed = 'exit-fullscreen';\n break;\n\n case 'play-large':\n attributes.class += ` ${this.config.classNames.control}--overlaid`;\n type = 'play';\n label = 'play';\n icon = 'play';\n break;\n\n default:\n label = type;\n icon = buttonType;\n }\n\n // Setup toggle icon and labels\n if (toggle) {\n // Icon\n button.appendChild(\n controls.createIcon.call(this, iconPressed, {\n class: 'icon--pressed',\n }),\n );\n button.appendChild(\n controls.createIcon.call(this, icon, {\n class: 'icon--not-pressed',\n }),\n );\n\n // Label/Tooltip\n button.appendChild(\n controls.createLabel.call(this, labelPressed, {\n class: 'label--pressed',\n }),\n );\n button.appendChild(\n controls.createLabel.call(this, label, {\n class: 'label--not-pressed',\n }),\n );\n } else {\n button.appendChild(controls.createIcon.call(this, icon));\n button.appendChild(controls.createLabel.call(this, label));\n }\n\n // Merge attributes\n extend(attributes, getAttributesFromSelector(this.config.selectors.buttons[type], attributes));\n\n setAttributes(button, attributes);\n\n // We have multiple play buttons\n if (type === 'play') {\n if (!is.array(this.elements.buttons[type])) {\n this.elements.buttons[type] = [];\n }\n\n this.elements.buttons[type].push(button);\n } else {\n this.elements.buttons[type] = button;\n }\n\n return button;\n },\n\n // Create an <input type='range'>\n createRange(type, attributes) {\n // Seek input\n const input = createElement(\n 'input',\n extend(\n getAttributesFromSelector(this.config.selectors.inputs[type]),\n {\n type: 'range',\n min: 0,\n max: 100,\n step: 0.01,\n value: 0,\n autocomplete: 'off',\n // A11y fixes for https://github.com/sampotts/plyr/issues/905\n role: 'slider',\n 'aria-label': i18n.get(type, this.config),\n 'aria-valuemin': 0,\n 'aria-valuemax': 100,\n 'aria-valuenow': 0,\n },\n attributes,\n ),\n );\n\n this.elements.inputs[type] = input;\n\n // Set the fill for webkit now\n controls.updateRangeFill.call(this, input);\n\n return input;\n },\n\n // Create a <progress>\n createProgress(type, attributes) {\n const progress = createElement(\n 'progress',\n extend(\n getAttributesFromSelector(this.config.selectors.display[type]),\n {\n min: 0,\n max: 100,\n value: 0,\n role: 'presentation',\n 'aria-hidden': true,\n },\n attributes,\n ),\n );\n\n // Create the label inside\n if (type !== 'volume') {\n progress.appendChild(createElement('span', null, '0'));\n\n const suffixKey = {\n played: 'played',\n buffer: 'buffered',\n }[type];\n const suffix = suffixKey ? i18n.get(suffixKey, this.config) : '';\n\n progress.innerText = `% ${suffix.toLowerCase()}`;\n }\n\n this.elements.display[type] = progress;\n\n return progress;\n },\n\n // Create time display\n createTime(type) {\n const attributes = getAttributesFromSelector(this.config.selectors.display[type]);\n\n const container = createElement(\n 'div',\n extend(attributes, {\n class: `${this.config.classNames.display.time} ${attributes.class ? attributes.class : ''}`.trim(),\n 'aria-label': i18n.get(type, this.config),\n }),\n '00:00',\n );\n\n // Reference for updates\n this.elements.display[type] = container;\n\n return container;\n },\n\n // Bind keyboard shortcuts for a menu item\n // We have to bind to keyup otherwise Firefox triggers a click when a keydown event handler shifts focus\n // https://bugzilla.mozilla.org/show_bug.cgi?id=1220143\n bindMenuItemShortcuts(menuItem, type) {\n // Navigate through menus via arrow keys and space\n on(\n menuItem,\n 'keydown keyup',\n event => {\n // We only care about space and ⬆️ ⬇️️ ➡️\n if (![32, 38, 39, 40].includes(event.which)) {\n return;\n }\n\n // Prevent play / seek\n event.preventDefault();\n event.stopPropagation();\n\n // We're just here to prevent the keydown bubbling\n if (event.type === 'keydown') {\n return;\n }\n\n const isRadioButton = matches(menuItem, '[role=\"menuitemradio\"]');\n\n // Show the respective menu\n if (!isRadioButton && [32, 39].includes(event.which)) {\n controls.showMenuPanel.call(this, type, true);\n } else {\n let target;\n\n if (event.which !== 32) {\n if (event.which === 40 || (isRadioButton && event.which === 39)) {\n target = menuItem.nextElementSibling;\n\n if (!is.element(target)) {\n target = menuItem.parentNode.firstElementChild;\n }\n } else {\n target = menuItem.previousElementSibling;\n\n if (!is.element(target)) {\n target = menuItem.parentNode.lastElementChild;\n }\n }\n\n setFocus.call(this, target, true);\n }\n }\n },\n false,\n );\n\n // Enter will fire a `click` event but we still need to manage focus\n // So we bind to keyup which fires after and set focus here\n on(menuItem, 'keyup', event => {\n if (event.which !== 13) {\n return;\n }\n\n controls.focusFirstMenuItem.call(this, null, true);\n });\n },\n\n // Create a settings menu item\n createMenuItem({ value, list, type, title, badge = null, checked = false }) {\n const attributes = getAttributesFromSelector(this.config.selectors.inputs[type]);\n\n const menuItem = createElement(\n 'button',\n extend(attributes, {\n type: 'button',\n role: 'menuitemradio',\n class: `${this.config.classNames.control} ${attributes.class ? attributes.class : ''}`.trim(),\n 'aria-checked': checked,\n value,\n }),\n );\n\n const flex = createElement('span');\n\n // We have to set as HTML incase of special characters\n flex.innerHTML = title;\n\n if (is.element(badge)) {\n flex.appendChild(badge);\n }\n\n menuItem.appendChild(flex);\n\n // Replicate radio button behaviour\n Object.defineProperty(menuItem, 'checked', {\n enumerable: true,\n get() {\n return menuItem.getAttribute('aria-checked') === 'true';\n },\n set(checked) {\n // Ensure exclusivity\n if (checked) {\n Array.from(menuItem.parentNode.children)\n .filter(node => matches(node, '[role=\"menuitemradio\"]'))\n .forEach(node => node.setAttribute('aria-checked', 'false'));\n }\n\n menuItem.setAttribute('aria-checked', checked ? 'true' : 'false');\n },\n });\n\n this.listeners.bind(\n menuItem,\n 'click keyup',\n event => {\n if (is.keyboardEvent(event) && event.which !== 32) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n menuItem.checked = true;\n\n switch (type) {\n case 'language':\n this.currentTrack = Number(value);\n break;\n\n case 'quality':\n this.quality = value;\n break;\n\n case 'speed':\n this.speed = parseFloat(value);\n break;\n\n default:\n break;\n }\n\n controls.showMenuPanel.call(this, 'home', is.keyboardEvent(event));\n },\n type,\n false,\n );\n\n controls.bindMenuItemShortcuts.call(this, menuItem, type);\n\n list.appendChild(menuItem);\n },\n\n // Format a time for display\n formatTime(time = 0, inverted = false) {\n // Bail if the value isn't a number\n if (!is.number(time)) {\n return time;\n }\n\n // Always display hours if duration is over an hour\n const forceHours = getHours(this.duration) > 0;\n\n return formatTime(time, forceHours, inverted);\n },\n\n // Update the displayed time\n updateTimeDisplay(target = null, time = 0, inverted = false) {\n // Bail if there's no element to display or the value isn't a number\n if (!is.element(target) || !is.number(time)) {\n return;\n }\n\n // eslint-disable-next-line no-param-reassign\n target.innerText = controls.formatTime(time, inverted);\n },\n\n // Update volume UI and storage\n updateVolume() {\n if (!this.supported.ui) {\n return;\n }\n\n // Update range\n if (is.element(this.elements.inputs.volume)) {\n controls.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume);\n }\n\n // Update mute state\n if (is.element(this.elements.buttons.mute)) {\n this.elements.buttons.mute.pressed = this.muted || this.volume === 0;\n }\n },\n\n // Update seek value and lower fill\n setRange(target, value = 0) {\n if (!is.element(target)) {\n return;\n }\n\n // eslint-disable-next-line\n target.value = value;\n\n // Webkit range fill\n controls.updateRangeFill.call(this, target);\n },\n\n // Update <progress> elements\n updateProgress(event) {\n if (!this.supported.ui || !is.event(event)) {\n return;\n }\n\n let value = 0;\n\n const setProgress = (target, input) => {\n const value = is.number(input) ? input : 0;\n const progress = is.element(target) ? target : this.elements.display.buffer;\n\n // Update value and label\n if (is.element(progress)) {\n progress.value = value;\n\n // Update text label inside\n const label = progress.getElementsByTagName('span')[0];\n if (is.element(label)) {\n label.childNodes[0].nodeValue = value;\n }\n }\n };\n\n if (event) {\n switch (event.type) {\n // Video playing\n case 'timeupdate':\n case 'seeking':\n case 'seeked':\n value = getPercentage(this.currentTime, this.duration);\n\n // Set seek range value only if it's a 'natural' time event\n if (event.type === 'timeupdate') {\n controls.setRange.call(this, this.elements.inputs.seek, value);\n }\n\n break;\n\n // Check buffer status\n case 'playing':\n case 'progress':\n setProgress(this.elements.display.buffer, this.buffered * 100);\n\n break;\n\n default:\n break;\n }\n }\n },\n\n // Webkit polyfill for lower fill range\n updateRangeFill(target) {\n // Get range from event if event passed\n const range = is.event(target) ? target.target : target;\n\n // Needs to be a valid <input type='range'>\n if (!is.element(range) || range.getAttribute('type') !== 'range') {\n return;\n }\n\n // Set aria values for https://github.com/sampotts/plyr/issues/905\n if (matches(range, this.config.selectors.inputs.seek)) {\n range.setAttribute('aria-valuenow', this.currentTime);\n const currentTime = controls.formatTime(this.currentTime);\n const duration = controls.formatTime(this.duration);\n const format = i18n.get('seekLabel', this.config);\n range.setAttribute(\n 'aria-valuetext',\n format.replace('{currentTime}', currentTime).replace('{duration}', duration),\n );\n } else if (matches(range, this.config.selectors.inputs.volume)) {\n const percent = range.value * 100;\n range.setAttribute('aria-valuenow', percent);\n range.setAttribute('aria-valuetext', `${percent.toFixed(1)}%`);\n } else {\n range.setAttribute('aria-valuenow', range.value);\n }\n\n // WebKit only\n if (!browser.isWebkit) {\n return;\n }\n\n // Set CSS custom property\n range.style.setProperty('--value', `${range.value / range.max * 100}%`);\n },\n\n // Update hover tooltip for seeking\n updateSeekTooltip(event) {\n // Bail if setting not true\n if (\n !this.config.tooltips.seek ||\n !is.element(this.elements.inputs.seek) ||\n !is.element(this.elements.display.seekTooltip) ||\n this.duration === 0\n ) {\n return;\n }\n\n // Calculate percentage\n let percent = 0;\n const clientRect = this.elements.progress.getBoundingClientRect();\n const visible = `${this.config.classNames.tooltip}--visible`;\n\n const toggle = toggle => {\n toggleClass(this.elements.display.seekTooltip, visible, toggle);\n };\n\n // Hide on touch\n if (this.touch) {\n toggle(false);\n return;\n }\n\n // Determine percentage, if already visible\n if (is.event(event)) {\n percent = 100 / clientRect.width * (event.pageX - clientRect.left);\n } else if (hasClass(this.elements.display.seekTooltip, visible)) {\n percent = parseFloat(this.elements.display.seekTooltip.style.left, 10);\n } else {\n return;\n }\n\n // Set bounds\n if (percent < 0) {\n percent = 0;\n } else if (percent > 100) {\n percent = 100;\n }\n\n // Display the time a click would seek to\n controls.updateTimeDisplay.call(this, this.elements.display.seekTooltip, this.duration / 100 * percent);\n\n // Set position\n this.elements.display.seekTooltip.style.left = `${percent}%`;\n\n // Show/hide the tooltip\n // If the event is a moues in/out and percentage is inside bounds\n if (is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {\n toggle(event.type === 'mouseenter');\n }\n },\n\n // Handle time change event\n timeUpdate(event) {\n // Only invert if only one time element is displayed and used for both duration and currentTime\n const invert = !is.element(this.elements.display.duration) && this.config.invertTime;\n\n // Duration\n controls.updateTimeDisplay.call(\n this,\n this.elements.display.currentTime,\n invert ? this.duration - this.currentTime : this.currentTime,\n invert,\n );\n\n // Ignore updates while seeking\n if (event && event.type === 'timeupdate' && this.media.seeking) {\n return;\n }\n\n // Playing progress\n controls.updateProgress.call(this, event);\n },\n\n // Show the duration on metadataloaded or durationchange events\n durationUpdate() {\n // Bail if no UI or durationchange event triggered after playing/seek when invertTime is false\n if (!this.supported.ui || (!this.config.invertTime && this.currentTime)) {\n return;\n }\n\n // If duration is the 2**32 (shaka), Infinity (HLS), DASH-IF (Number.MAX_SAFE_INTEGER || Number.MAX_VALUE) indicating live we hide the currentTime and progressbar.\n // https://github.com/video-dev/hls.js/blob/5820d29d3c4c8a46e8b75f1e3afa3e68c1a9a2db/src/controller/buffer-controller.js#L415\n // https://github.com/google/shaka-player/blob/4d889054631f4e1cf0fbd80ddd2b71887c02e232/lib/media/streaming_engine.js#L1062\n // https://github.com/Dash-Industry-Forum/dash.js/blob/69859f51b969645b234666800d4cb596d89c602d/src/dash/models/DashManifestModel.js#L338\n if (this.duration >= 2 ** 32) {\n toggleHidden(this.elements.display.currentTime, true);\n toggleHidden(this.elements.progress, true);\n return;\n }\n\n // Update ARIA values\n if (is.element(this.elements.inputs.seek)) {\n this.elements.inputs.seek.setAttribute('aria-valuemax', this.duration);\n }\n\n // If there's a spot to display duration\n const hasDuration = is.element(this.elements.display.duration);\n\n // If there's only one time display, display duration there\n if (!hasDuration && this.config.displayDuration && this.paused) {\n controls.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration);\n }\n\n // If there's a duration element, update content\n if (hasDuration) {\n controls.updateTimeDisplay.call(this, this.elements.display.duration, this.duration);\n }\n\n // Update the tooltip (if visible)\n controls.updateSeekTooltip.call(this);\n },\n\n // Hide/show a tab\n toggleMenuButton(setting, toggle) {\n toggleHidden(this.elements.settings.buttons[setting], !toggle);\n },\n\n // Update the selected setting\n updateSetting(setting, container, input) {\n const pane = this.elements.settings.panels[setting];\n let value = null;\n let list = container;\n\n if (setting === 'captions') {\n value = this.currentTrack;\n } else {\n value = !is.empty(input) ? input : this[setting];\n\n // Get default\n if (is.empty(value)) {\n value = this.config[setting].default;\n }\n\n // Unsupported value\n if (!is.empty(this.options[setting]) && !this.options[setting].includes(value)) {\n this.debug.warn(`Unsupported value of '${value}' for ${setting}`);\n return;\n }\n\n // Disabled value\n if (!this.config[setting].options.includes(value)) {\n this.debug.warn(`Disabled value of '${value}' for ${setting}`);\n return;\n }\n }\n\n // Get the list if we need to\n if (!is.element(list)) {\n list = pane && pane.querySelector('[role=\"menu\"]');\n }\n\n // If there's no list it means it's not been rendered...\n if (!is.element(list)) {\n return;\n }\n\n // Update the label\n const label = this.elements.settings.buttons[setting].querySelector(`.${this.config.classNames.menu.value}`);\n label.innerHTML = controls.getLabel.call(this, setting, value);\n\n // Find the radio option and check it\n const target = list && list.querySelector(`[value=\"${value}\"]`);\n\n if (is.element(target)) {\n target.checked = true;\n }\n },\n\n // Translate a value into a nice label\n getLabel(setting, value) {\n switch (setting) {\n case 'speed':\n return value === 1 ? i18n.get('normal', this.config) : `${value}×`;\n\n case 'quality':\n if (is.number(value)) {\n const label = i18n.get(`qualityLabel.${value}`, this.config);\n\n if (!label.length) {\n return `${value}p`;\n }\n\n return label;\n }\n\n return toTitleCase(value);\n\n case 'captions':\n return captions.getLabel.call(this);\n\n default:\n return null;\n }\n },\n\n // Set the quality menu\n setQualityMenu(options) {\n // Menu required\n if (!is.element(this.elements.settings.panels.quality)) {\n return;\n }\n\n const type = 'quality';\n const list = this.elements.settings.panels.quality.querySelector('[role=\"menu\"]');\n\n // Set options if passed and filter based on uniqueness and config\n if (is.array(options)) {\n this.options.quality = dedupe(options).filter(quality => this.config.quality.options.includes(quality));\n }\n\n // Toggle the pane and tab\n const toggle = !is.empty(this.options.quality) && this.options.quality.length > 1;\n controls.toggleMenuButton.call(this, type, toggle);\n\n // Empty the menu\n emptyElement(list);\n\n // Check if we need to toggle the parent\n controls.checkMenu.call(this);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Get the badge HTML for HD, 4K etc\n const getBadge = quality => {\n const label = i18n.get(`qualityBadge.${quality}`, this.config);\n\n if (!label.length) {\n return null;\n }\n\n return controls.createBadge.call(this, label);\n };\n\n // Sort options by the config and then render options\n this.options.quality\n .sort((a, b) => {\n const sorting = this.config.quality.options;\n return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;\n })\n .forEach(quality => {\n controls.createMenuItem.call(this, {\n value: quality,\n list,\n type,\n title: controls.getLabel.call(this, 'quality', quality),\n badge: getBadge(quality),\n });\n });\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Set the looping options\n /* setLoopMenu() {\n // Menu required\n if (!is.element(this.elements.settings.panels.loop)) {\n return;\n }\n\n const options = ['start', 'end', 'all', 'reset'];\n const list = this.elements.settings.panels.loop.querySelector('[role=\"menu\"]');\n\n // Show the pane and tab\n toggleHidden(this.elements.settings.buttons.loop, false);\n toggleHidden(this.elements.settings.panels.loop, false);\n\n // Toggle the pane and tab\n const toggle = !is.empty(this.loop.options);\n controls.toggleMenuButton.call(this, 'loop', toggle);\n\n // Empty the menu\n emptyElement(list);\n\n options.forEach(option => {\n const item = createElement('li');\n\n const button = createElement(\n 'button',\n extend(getAttributesFromSelector(this.config.selectors.buttons.loop), {\n type: 'button',\n class: this.config.classNames.control,\n 'data-plyr-loop-action': option,\n }),\n i18n.get(option, this.config)\n );\n\n if (['start', 'end'].includes(option)) {\n const badge = controls.createBadge.call(this, '00:00');\n button.appendChild(badge);\n }\n\n item.appendChild(button);\n list.appendChild(item);\n });\n }, */\n\n // Get current selected caption language\n // TODO: rework this to user the getter in the API?\n\n // Set a list of available captions languages\n setCaptionsMenu() {\n // Menu required\n if (!is.element(this.elements.settings.panels.captions)) {\n return;\n }\n\n // TODO: Captions or language? Currently it's mixed\n const type = 'captions';\n const list = this.elements.settings.panels.captions.querySelector('[role=\"menu\"]');\n const tracks = captions.getTracks.call(this);\n const toggle = Boolean(tracks.length);\n\n // Toggle the pane and tab\n controls.toggleMenuButton.call(this, type, toggle);\n\n // Empty the menu\n emptyElement(list);\n\n // Check if we need to toggle the parent\n controls.checkMenu.call(this);\n\n // If there's no captions, bail\n if (!toggle) {\n return;\n }\n\n // Generate options data\n const options = tracks.map((track, value) => ({\n value,\n checked: this.captions.toggled && this.currentTrack === value,\n title: captions.getLabel.call(this, track),\n badge: track.language && controls.createBadge.call(this, track.language.toUpperCase()),\n list,\n type: 'language',\n }));\n\n // Add the \"Disabled\" option to turn off captions\n options.unshift({\n value: -1,\n checked: !this.captions.toggled,\n title: i18n.get('disabled', this.config),\n list,\n type: 'language',\n });\n\n // Generate options\n options.forEach(controls.createMenuItem.bind(this));\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Set a list of available captions languages\n setSpeedMenu(options) {\n // Menu required\n if (!is.element(this.elements.settings.panels.speed)) {\n return;\n }\n\n const type = 'speed';\n const list = this.elements.settings.panels.speed.querySelector('[role=\"menu\"]');\n\n // Set the speed options\n if (is.array(options)) {\n this.options.speed = options;\n } else if (this.isHTML5 || this.isVimeo) {\n this.options.speed = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n }\n\n // Set options if passed and filter based on config\n this.options.speed = this.options.speed.filter(speed => this.config.speed.options.includes(speed));\n\n // Toggle the pane and tab\n const toggle = !is.empty(this.options.speed) && this.options.speed.length > 1;\n controls.toggleMenuButton.call(this, type, toggle);\n\n // Empty the menu\n emptyElement(list);\n\n // Check if we need to toggle the parent\n controls.checkMenu.call(this);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Create items\n this.options.speed.forEach(speed => {\n controls.createMenuItem.call(this, {\n value: speed,\n list,\n type,\n title: controls.getLabel.call(this, 'speed', speed),\n });\n });\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Check if we need to hide/show the settings menu\n checkMenu() {\n const { buttons } = this.elements.settings;\n const visible = !is.empty(buttons) && Object.values(buttons).some(button => !button.hidden);\n\n toggleHidden(this.elements.settings.menu, !visible);\n },\n\n // Focus the first menu item in a given (or visible) menu\n focusFirstMenuItem(pane, tabFocus = false) {\n if (this.elements.settings.popup.hidden) {\n return;\n }\n\n let target = pane;\n\n if (!is.element(target)) {\n target = Object.values(this.elements.settings.panels).find(pane => !pane.hidden);\n }\n\n const firstItem = target.querySelector('[role^=\"menuitem\"]');\n\n setFocus.call(this, firstItem, tabFocus);\n },\n\n // Show/hide menu\n toggleMenu(input) {\n const { popup } = this.elements.settings;\n const button = this.elements.buttons.settings;\n\n // Menu and button are required\n if (!is.element(popup) || !is.element(button)) {\n return;\n }\n\n // True toggle by default\n const { hidden } = popup;\n let show = hidden;\n\n if (is.boolean(input)) {\n show = input;\n } else if (is.keyboardEvent(input) && input.which === 27) {\n show = false;\n } else if (is.event(input)) {\n const isMenuItem = popup.contains(input.target);\n\n // If the click was inside the menu or if the click\n // wasn't the button or menu item and we're trying to\n // show the menu (a doc click shouldn't show the menu)\n if (isMenuItem || (!isMenuItem && input.target !== button && show)) {\n return;\n }\n }\n\n // Set button attributes\n button.setAttribute('aria-expanded', show);\n\n // Show the actual popup\n toggleHidden(popup, !show);\n\n // Add class hook\n toggleClass(this.elements.container, this.config.classNames.menu.open, show);\n\n // Focus the first item if key interaction\n if (show && is.keyboardEvent(input)) {\n controls.focusFirstMenuItem.call(this, null, true);\n } else if (!show && !hidden) {\n // If closing, re-focus the button\n setFocus.call(this, button, is.keyboardEvent(input));\n }\n },\n\n // Get the natural size of a menu panel\n getMenuSize(tab) {\n const clone = tab.cloneNode(true);\n clone.style.position = 'absolute';\n clone.style.opacity = 0;\n clone.removeAttribute('hidden');\n\n // Append to parent so we get the \"real\" size\n tab.parentNode.appendChild(clone);\n\n // Get the sizes before we remove\n const width = clone.scrollWidth;\n const height = clone.scrollHeight;\n\n // Remove from the DOM\n removeElement(clone);\n\n return {\n width,\n height,\n };\n },\n\n // Show a panel in the menu\n showMenuPanel(type = '', tabFocus = false) {\n const target = document.getElementById(`plyr-settings-${this.id}-${type}`);\n\n // Nothing to show, bail\n if (!is.element(target)) {\n return;\n }\n\n // Hide all other panels\n const container = target.parentNode;\n const current = Array.from(container.children).find(node => !node.hidden);\n\n // If we can do fancy animations, we'll animate the height/width\n if (support.transitions && !support.reducedMotion) {\n // Set the current width as a base\n container.style.width = `${current.scrollWidth}px`;\n container.style.height = `${current.scrollHeight}px`;\n\n // Get potential sizes\n const size = controls.getMenuSize.call(this, target);\n\n // Restore auto height/width\n const restore = event => {\n // We're only bothered about height and width on the container\n if (event.target !== container || !['width', 'height'].includes(event.propertyName)) {\n return;\n }\n\n // Revert back to auto\n container.style.width = '';\n container.style.height = '';\n\n // Only listen once\n off.call(this, container, transitionEndEvent, restore);\n };\n\n // Listen for the transition finishing and restore auto height/width\n on.call(this, container, transitionEndEvent, restore);\n\n // Set dimensions to target\n container.style.width = `${size.width}px`;\n container.style.height = `${size.height}px`;\n }\n\n // Set attributes on current tab\n toggleHidden(current, true);\n\n // Set attributes on target\n toggleHidden(target, false);\n\n // Focus the first item\n controls.focusFirstMenuItem.call(this, target, tabFocus);\n },\n\n // Build the default HTML\n // TODO: Set order based on order in the config.controls array?\n create(data) {\n // Create the container\n const container = createElement('div', getAttributesFromSelector(this.config.selectors.controls.wrapper));\n\n // Restart button\n if (this.config.controls.includes('restart')) {\n container.appendChild(controls.createButton.call(this, 'restart'));\n }\n\n // Rewind button\n if (this.config.controls.includes('rewind')) {\n container.appendChild(controls.createButton.call(this, 'rewind'));\n }\n\n // Play/Pause button\n if (this.config.controls.includes('play')) {\n container.appendChild(controls.createButton.call(this, 'play'));\n }\n\n // Fast forward button\n if (this.config.controls.includes('fast-forward')) {\n container.appendChild(controls.createButton.call(this, 'fast-forward'));\n }\n\n // Progress\n if (this.config.controls.includes('progress')) {\n const progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress));\n\n // Seek range slider\n progress.appendChild(\n controls.createRange.call(this, 'seek', {\n id: `plyr-seek-${data.id}`,\n }),\n );\n\n // Buffer progress\n progress.appendChild(controls.createProgress.call(this, 'buffer'));\n\n // TODO: Add loop display indicator\n\n // Seek tooltip\n if (this.config.tooltips.seek) {\n const tooltip = createElement(\n 'span',\n {\n class: this.config.classNames.tooltip,\n },\n '00:00',\n );\n\n progress.appendChild(tooltip);\n this.elements.display.seekTooltip = tooltip;\n }\n\n this.elements.progress = progress;\n container.appendChild(this.elements.progress);\n }\n\n // Media current time display\n if (this.config.controls.includes('current-time')) {\n container.appendChild(controls.createTime.call(this, 'currentTime'));\n }\n\n // Media duration display\n if (this.config.controls.includes('duration')) {\n container.appendChild(controls.createTime.call(this, 'duration'));\n }\n\n // Volume controls\n if (this.config.controls.includes('mute') || this.config.controls.includes('volume')) {\n const volume = createElement('div', {\n class: 'plyr__volume',\n });\n\n // Toggle mute button\n if (this.config.controls.includes('mute')) {\n volume.appendChild(controls.createButton.call(this, 'mute'));\n }\n\n // Volume range control\n if (this.config.controls.includes('volume')) {\n // Set the attributes\n const attributes = {\n max: 1,\n step: 0.05,\n value: this.config.volume,\n };\n\n // Create the volume range slider\n volume.appendChild(\n controls.createRange.call(\n this,\n 'volume',\n extend(attributes, {\n id: `plyr-volume-${data.id}`,\n }),\n ),\n );\n\n this.elements.volume = volume;\n }\n\n container.appendChild(volume);\n }\n\n // Toggle captions button\n if (this.config.controls.includes('captions')) {\n container.appendChild(controls.createButton.call(this, 'captions'));\n }\n\n // Settings button / menu\n if (this.config.controls.includes('settings') && !is.empty(this.config.settings)) {\n const control = createElement('div', {\n class: 'plyr__menu',\n hidden: '',\n });\n\n control.appendChild(\n controls.createButton.call(this, 'settings', {\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}`,\n 'aria-expanded': false,\n }),\n );\n\n const popup = createElement('div', {\n class: 'plyr__menu__container',\n id: `plyr-settings-${data.id}`,\n hidden: '',\n });\n\n const inner = createElement('div');\n\n const home = createElement('div', {\n id: `plyr-settings-${data.id}-home`,\n });\n\n // Create the menu\n const menu = createElement('div', {\n role: 'menu',\n });\n\n home.appendChild(menu);\n inner.appendChild(home);\n this.elements.settings.panels.home = home;\n\n // Build the menu items\n this.config.settings.forEach(type => {\n // TODO: bundle this with the createMenuItem helper and bindings\n const menuItem = createElement(\n 'button',\n extend(getAttributesFromSelector(this.config.selectors.buttons.settings), {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`,\n role: 'menuitem',\n 'aria-haspopup': true,\n hidden: '',\n }),\n );\n\n // Bind menu shortcuts for keyboard users\n controls.bindMenuItemShortcuts.call(this, menuItem, type);\n\n // Show menu on click\n on(menuItem, 'click', () => {\n controls.showMenuPanel.call(this, type, false);\n });\n\n const flex = createElement('span', null, i18n.get(type, this.config));\n\n const value = createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n // Speed contains HTML entities\n value.innerHTML = data[type];\n\n flex.appendChild(value);\n menuItem.appendChild(flex);\n menu.appendChild(menuItem);\n\n // Build the panes\n const pane = createElement('div', {\n id: `plyr-settings-${data.id}-${type}`,\n hidden: '',\n });\n\n // Back button\n const backButton = createElement('button', {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--back`,\n });\n\n // Visible label\n backButton.appendChild(\n createElement(\n 'span',\n {\n 'aria-hidden': true,\n },\n i18n.get(type, this.config),\n ),\n );\n\n // Screen reader label\n backButton.appendChild(\n createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n i18n.get('menuBack', this.config),\n ),\n );\n\n // Go back via keyboard\n on(\n pane,\n 'keydown',\n event => {\n // We only care about <-\n if (event.which !== 37) {\n return;\n }\n\n // Prevent seek\n event.preventDefault();\n event.stopPropagation();\n\n // Show the respective menu\n controls.showMenuPanel.call(this, 'home', true);\n },\n false,\n );\n\n // Go back via button click\n on(backButton, 'click', () => {\n controls.showMenuPanel.call(this, 'home', false);\n });\n\n // Add to pane\n pane.appendChild(backButton);\n\n // Menu\n pane.appendChild(\n createElement('div', {\n role: 'menu',\n }),\n );\n\n inner.appendChild(pane);\n\n this.elements.settings.buttons[type] = menuItem;\n this.elements.settings.panels[type] = pane;\n });\n\n popup.appendChild(inner);\n control.appendChild(popup);\n container.appendChild(control);\n\n this.elements.settings.popup = popup;\n this.elements.settings.menu = control;\n }\n\n // Picture in picture button\n if (this.config.controls.includes('pip') && support.pip) {\n container.appendChild(controls.createButton.call(this, 'pip'));\n }\n\n // Airplay button\n if (this.config.controls.includes('airplay') && support.airplay) {\n container.appendChild(controls.createButton.call(this, 'airplay'));\n }\n\n // Toggle fullscreen button\n if (this.config.controls.includes('fullscreen')) {\n container.appendChild(controls.createButton.call(this, 'fullscreen'));\n }\n\n // Larger overlaid play button\n if (this.config.controls.includes('play-large')) {\n this.elements.container.appendChild(controls.createButton.call(this, 'play-large'));\n }\n\n this.elements.controls = container;\n\n // Set available quality levels\n if (this.isHTML5) {\n controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));\n }\n\n controls.setSpeedMenu.call(this);\n\n return container;\n },\n\n // Insert controls\n inject() {\n // Sprite\n if (this.config.loadSprite) {\n const icon = controls.getIconUrl.call(this);\n\n // Only load external sprite using AJAX\n if (icon.cors) {\n loadSprite(icon.url, 'sprite-plyr');\n }\n }\n\n // Create a unique ID\n this.id = Math.floor(Math.random() * 10000);\n\n // Null by default\n let container = null;\n this.elements.controls = null;\n\n // Set template properties\n const props = {\n id: this.id,\n seektime: this.config.seekTime,\n title: this.config.title,\n };\n let update = true;\n\n // If function, run it and use output\n if (is.function(this.config.controls)) {\n this.config.controls = this.config.controls.call(this.props);\n }\n\n // Convert falsy controls to empty array (primarily for empty strings)\n if (!this.config.controls) {\n this.config.controls = [];\n }\n\n if (is.element(this.config.controls) || is.string(this.config.controls)) {\n // HTMLElement or Non-empty string passed as the option\n container = this.config.controls;\n } else {\n // Create controls\n container = controls.create.call(this, {\n id: this.id,\n seektime: this.config.seekTime,\n speed: this.speed,\n quality: this.quality,\n captions: captions.getLabel.call(this),\n // TODO: Looping\n // loop: 'None',\n });\n update = false;\n }\n\n // Replace props with their value\n const replace = input => {\n let result = input;\n\n Object.entries(props).forEach(([key, value]) => {\n result = replaceAll(result, `{${key}}`, value);\n });\n\n return result;\n };\n\n // Update markup\n if (update) {\n if (is.string(this.config.controls)) {\n container = replace(container);\n } else if (is.element(container)) {\n container.innerHTML = replace(container.innerHTML);\n }\n }\n\n // Controls container\n let target;\n\n // Inject to custom location\n if (is.string(this.config.selectors.controls.container)) {\n target = document.querySelector(this.config.selectors.controls.container);\n }\n\n // Inject into the container by default\n if (!is.element(target)) {\n target = this.elements.container;\n }\n\n // Inject controls HTML (needs to be before captions, hence \"afterbegin\")\n const insertMethod = is.element(container) ? 'insertAdjacentElement' : 'insertAdjacentHTML';\n target[insertMethod]('afterbegin', container);\n\n // Find the elements if need be\n if (!is.element(this.elements.controls)) {\n controls.findElements.call(this);\n }\n\n // Add pressed property to buttons\n if (!is.empty(this.elements.buttons)) {\n const addProperty = button => {\n const className = this.config.classNames.controlPressed;\n Object.defineProperty(button, 'pressed', {\n enumerable: true,\n get() {\n return hasClass(button, className);\n },\n set(pressed = false) {\n toggleClass(button, className, pressed);\n },\n });\n };\n\n // Toggle classname when pressed property is set\n Object.values(this.elements.buttons)\n .filter(Boolean)\n .forEach(button => {\n if (is.array(button) || is.nodeList(button)) {\n Array.from(button).filter(Boolean).forEach(addProperty);\n } else {\n addProperty(button);\n }\n });\n }\n\n // Edge sometimes doesn't finish the paint so force a redraw\n if (window.navigator.userAgent.includes('Edge')) {\n repaint(target);\n }\n\n // Setup tooltips\n if (this.config.tooltips.controls) {\n const { classNames, selectors } = this.config;\n const selector = `${selectors.controls.wrapper} ${selectors.labels} .${classNames.hidden}`;\n const labels = getElements.call(this, selector);\n\n Array.from(labels).forEach(label => {\n toggleClass(label, this.config.classNames.hidden, false);\n toggleClass(label, this.config.classNames.tooltip, true);\n });\n }\n },\n};\n\nexport default controls;\n","// ==========================================================================\n// URL utils\n// ==========================================================================\n\nimport is from './is';\n\n/**\n * Parse a string to a URL object\n * @param {string} input - the URL to be parsed\n * @param {boolean} safe - failsafe parsing\n */\nexport function parseUrl(input, safe = true) {\n let url = input;\n\n if (safe) {\n const parser = document.createElement('a');\n parser.href = url;\n url = parser.href;\n }\n\n try {\n return new URL(url);\n } catch (e) {\n return null;\n }\n}\n\n// Convert object to URLSearchParams\nexport function buildUrlParams(input) {\n const params = new URLSearchParams();\n\n if (is.object(input)) {\n Object.entries(input).forEach(([key, value]) => {\n params.set(key, value);\n });\n }\n\n return params;\n}\n","// ==========================================================================\n// Plyr Captions\n// TODO: Create as class\n// ==========================================================================\n\nimport controls from './controls';\nimport support from './support';\nimport { dedupe } from './utils/arrays';\nimport browser from './utils/browser';\nimport {\n createElement,\n emptyElement,\n getAttributesFromSelector,\n insertAfter,\n removeElement,\n toggleClass,\n} from './utils/elements';\nimport { on, triggerEvent } from './utils/events';\nimport fetch from './utils/fetch';\nimport i18n from './utils/i18n';\nimport is from './utils/is';\nimport { getHTML } from './utils/strings';\nimport { parseUrl } from './utils/urls';\n\nconst captions = {\n // Setup captions\n setup() {\n // Requires UI support\n if (!this.supported.ui) {\n return;\n }\n\n // Only Vimeo and HTML5 video supported at this point\n if (!this.isVideo || this.isYouTube || (this.isHTML5 && !support.textTracks)) {\n // Clear menu and hide\n if (\n is.array(this.config.controls) &&\n this.config.controls.includes('settings') &&\n this.config.settings.includes('captions')\n ) {\n controls.setCaptionsMenu.call(this);\n }\n\n return;\n }\n\n // Inject the container\n if (!is.element(this.elements.captions)) {\n this.elements.captions = createElement('div', getAttributesFromSelector(this.config.selectors.captions));\n\n insertAfter(this.elements.captions, this.elements.wrapper);\n }\n\n // Fix IE captions if CORS is used\n // Fetch captions and inject as blobs instead (data URIs not supported!)\n if (browser.isIE && window.URL) {\n const elements = this.media.querySelectorAll('track');\n\n Array.from(elements).forEach(track => {\n const src = track.getAttribute('src');\n const url = parseUrl(src);\n\n if (\n url !== null &&\n url.hostname !== window.location.href.hostname &&\n ['http:', 'https:'].includes(url.protocol)\n ) {\n fetch(src, 'blob')\n .then(blob => {\n track.setAttribute('src', window.URL.createObjectURL(blob));\n })\n .catch(() => {\n removeElement(track);\n });\n }\n });\n }\n\n // Get and set initial data\n // The \"preferred\" options are not realized unless / until the wanted language has a match\n // * languages: Array of user's browser languages.\n // * language: The language preferred by user settings or config\n // * active: The state preferred by user settings or config\n // * toggled: The real captions state\n\n const browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];\n const languages = dedupe(browserLanguages.map(language => language.split('-')[0]));\n\n let language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase();\n\n // Use first browser language when language is 'auto'\n if (language === 'auto') {\n [language] = languages;\n }\n\n let active = this.storage.get('captions');\n if (!is.boolean(active)) {\n ({ active } = this.config.captions);\n }\n\n Object.assign(this.captions, {\n toggled: false,\n active,\n language,\n languages,\n });\n\n // Watch changes to textTracks and update captions menu\n if (this.isHTML5) {\n const trackEvents = this.config.captions.update ? 'addtrack removetrack' : 'removetrack';\n on.call(this, this.media.textTracks, trackEvents, captions.update.bind(this));\n }\n\n // Update available languages in list next tick (the event must not be triggered before the listeners)\n setTimeout(captions.update.bind(this), 0);\n },\n\n // Update available language options in settings based on tracks\n update() {\n const tracks = captions.getTracks.call(this, true);\n // Get the wanted language\n const { active, language, meta, currentTrackNode } = this.captions;\n const languageExists = Boolean(tracks.find(track => track.language === language));\n\n // Handle tracks (add event listener and \"pseudo\"-default)\n if (this.isHTML5 && this.isVideo) {\n tracks.filter(track => !meta.get(track)).forEach(track => {\n this.debug.log('Track added', track);\n // Attempt to store if the original dom element was \"default\"\n meta.set(track, {\n default: track.mode === 'showing',\n });\n\n // Turn off native caption rendering to avoid double captions\n track.mode = 'hidden';\n\n // Add event listener for cue changes\n on.call(this, track, 'cuechange', () => captions.updateCues.call(this));\n });\n }\n\n // Update language first time it matches, or if the previous matching track was removed\n if ((languageExists && this.language !== language) || !tracks.includes(currentTrackNode)) {\n captions.setLanguage.call(this, language);\n captions.toggle.call(this, active && languageExists);\n }\n\n // Enable or disable captions based on track length\n toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is.empty(tracks));\n\n // Update available languages in list\n if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n },\n\n // Toggle captions display\n // Used internally for the toggleCaptions method, with the passive option forced to false\n toggle(input, passive = true) {\n // If there's no full support\n if (!this.supported.ui) {\n return;\n }\n\n const { toggled } = this.captions; // Current state\n const activeClass = this.config.classNames.captions.active;\n\n // Get the next state\n // If the method is called without parameter, toggle based on current value\n const active = is.nullOrUndefined(input) ? !toggled : input;\n\n // Update state and trigger event\n if (active !== toggled) {\n // When passive, don't override user preferences\n if (!passive) {\n this.captions.active = active;\n this.storage.set({ captions: active });\n }\n\n // Force language if the call isn't passive and there is no matching language to toggle to\n if (!this.language && active && !passive) {\n const tracks = captions.getTracks.call(this);\n const track = captions.findTrack.call(this, [this.captions.language, ...this.captions.languages], true);\n\n // Override user preferences to avoid switching languages if a matching track is added\n this.captions.language = track.language;\n\n // Set caption, but don't store in localStorage as user preference\n captions.set.call(this, tracks.indexOf(track));\n return;\n }\n\n // Toggle button if it's enabled\n if (this.elements.buttons.captions) {\n this.elements.buttons.captions.pressed = active;\n }\n\n // Add class hook\n toggleClass(this.elements.container, activeClass, active);\n\n this.captions.toggled = active;\n\n // Update settings menu\n controls.updateSetting.call(this, 'captions');\n\n // Trigger event (not used internally)\n triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled');\n }\n },\n\n // Set captions by track index\n // Used internally for the currentTrack setter with the passive option forced to false\n set(index, passive = true) {\n const tracks = captions.getTracks.call(this);\n\n // Disable captions if setting to -1\n if (index === -1) {\n captions.toggle.call(this, false, passive);\n return;\n }\n\n if (!is.number(index)) {\n this.debug.warn('Invalid caption argument', index);\n return;\n }\n\n if (!(index in tracks)) {\n this.debug.warn('Track not found', index);\n return;\n }\n\n if (this.captions.currentTrack !== index) {\n this.captions.currentTrack = index;\n const track = tracks[index];\n const { language } = track || {};\n\n // Store reference to node for invalidation on remove\n this.captions.currentTrackNode = track;\n\n // Update settings menu\n controls.updateSetting.call(this, 'captions');\n\n // When passive, don't override user preferences\n if (!passive) {\n this.captions.language = language;\n this.storage.set({ language });\n }\n\n // Handle Vimeo captions\n if (this.isVimeo) {\n this.embed.enableTextTrack(language);\n }\n\n // Trigger event\n triggerEvent.call(this, this.media, 'languagechange');\n }\n\n // Show captions\n captions.toggle.call(this, true, passive);\n\n if (this.isHTML5 && this.isVideo) {\n // If we change the active track while a cue is already displayed we need to update it\n captions.updateCues.call(this);\n }\n },\n\n // Set captions by language\n // Used internally for the language setter with the passive option forced to false\n setLanguage(input, passive = true) {\n if (!is.string(input)) {\n this.debug.warn('Invalid language argument', input);\n return;\n }\n // Normalize\n const language = input.toLowerCase();\n this.captions.language = language;\n\n // Set currentTrack\n const tracks = captions.getTracks.call(this);\n const track = captions.findTrack.call(this, [language]);\n captions.set.call(this, tracks.indexOf(track), passive);\n },\n\n // Get current valid caption tracks\n // If update is false it will also ignore tracks without metadata\n // This is used to \"freeze\" the language options when captions.update is false\n getTracks(update = false) {\n // Handle media or textTracks missing or null\n const tracks = Array.from((this.media || {}).textTracks || []);\n // For HTML5, use cache instead of current tracks when it exists (if captions.update is false)\n // Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)\n return tracks\n .filter(track => !this.isHTML5 || update || this.captions.meta.has(track))\n .filter(track => ['captions', 'subtitles'].includes(track.kind));\n },\n\n // Match tracks based on languages and get the first\n findTrack(languages, force = false) {\n const tracks = captions.getTracks.call(this);\n const sortIsDefault = track => Number((this.captions.meta.get(track) || {}).default);\n const sorted = Array.from(tracks).sort((a, b) => sortIsDefault(b) - sortIsDefault(a));\n let track;\n languages.every(language => {\n track = sorted.find(track => track.language === language);\n return !track; // Break iteration if there is a match\n });\n // If no match is found but is required, get first\n return track || (force ? sorted[0] : undefined);\n },\n\n // Get the current track\n getCurrentTrack() {\n return captions.getTracks.call(this)[this.currentTrack];\n },\n\n // Get UI label for track\n getLabel(track) {\n let currentTrack = track;\n\n if (!is.track(currentTrack) && support.textTracks && this.captions.toggled) {\n currentTrack = captions.getCurrentTrack.call(this);\n }\n\n if (is.track(currentTrack)) {\n if (!is.empty(currentTrack.label)) {\n return currentTrack.label;\n }\n\n if (!is.empty(currentTrack.language)) {\n return track.language.toUpperCase();\n }\n\n return i18n.get('enabled', this.config);\n }\n\n return i18n.get('disabled', this.config);\n },\n\n // Update captions using current track's active cues\n // Also optional array argument in case there isn't any track (ex: vimeo)\n updateCues(input) {\n // Requires UI\n if (!this.supported.ui) {\n return;\n }\n\n if (!is.element(this.elements.captions)) {\n this.debug.warn('No captions element to render to');\n return;\n }\n\n // Only accept array or empty input\n if (!is.nullOrUndefined(input) && !Array.isArray(input)) {\n this.debug.warn('updateCues: Invalid input', input);\n return;\n }\n\n let cues = input;\n\n // Get cues from track\n if (!cues) {\n const track = captions.getCurrentTrack.call(this);\n cues = Array.from((track || {}).activeCues || [])\n .map(cue => cue.getCueAsHTML())\n .map(getHTML);\n }\n\n // Set new caption text\n const content = cues.map(cueText => cueText.trim()).join('\\n');\n const changed = content !== this.elements.captions.innerHTML;\n\n if (changed) {\n // Empty the container and create a new child element\n emptyElement(this.elements.captions);\n const caption = createElement('span', getAttributesFromSelector(this.config.selectors.caption));\n caption.innerHTML = content;\n this.elements.captions.appendChild(caption);\n\n // Trigger event\n triggerEvent.call(this, this.media, 'cuechange');\n }\n },\n};\n\nexport default captions;\n","// ==========================================================================\n// Plyr default config\n// ==========================================================================\n\nconst defaults = {\n // Disable\n enabled: true,\n\n // Custom media title\n title: '',\n\n // Logging to console\n debug: false,\n\n // Auto play (if supported)\n autoplay: false,\n\n // Only allow one media playing at once (vimeo only)\n autopause: true,\n\n // Allow inline playback on iOS (this effects YouTube/Vimeo - HTML5 requires the attribute present)\n // TODO: Remove iosNative fullscreen option in favour of this (logic needs work)\n playsinline: true,\n\n // Default time to skip when rewind/fast forward\n seekTime: 10,\n\n // Default volume\n volume: 1,\n muted: false,\n\n // Pass a custom duration\n duration: null,\n\n // Display the media duration on load in the current time position\n // If you have opted to display both duration and currentTime, this is ignored\n displayDuration: true,\n\n // Invert the current time to be a countdown\n invertTime: true,\n\n // Clicking the currentTime inverts it's value to show time left rather than elapsed\n toggleInvert: true,\n\n // Aspect ratio (for embeds)\n ratio: '16:9',\n\n // Click video container to play/pause\n clickToPlay: true,\n\n // Auto hide the controls\n hideControls: true,\n\n // Reset to start when playback ended\n resetOnEnd: false,\n\n // Disable the standard context menu\n disableContextMenu: true,\n\n // Sprite (for icons)\n loadSprite: true,\n iconPrefix: 'plyr',\n iconUrl: 'https://cdn.plyr.io/3.3.12/plyr.svg',\n\n // Blank video (used to prevent errors on source change)\n blankVideo: 'https://cdn.plyr.io/static/blank.mp4',\n\n // Quality default\n quality: {\n default: 576,\n options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240],\n },\n\n // Set loops\n loop: {\n active: false,\n // start: null,\n // end: null,\n },\n\n // Speed default and options to display\n speed: {\n selected: 1,\n options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],\n },\n\n // Keyboard shortcut settings\n keyboard: {\n focused: true,\n global: false,\n },\n\n // Display tooltips\n tooltips: {\n controls: false,\n seek: true,\n },\n\n // Captions settings\n captions: {\n active: false,\n language: 'auto',\n // Listen to new tracks added after Plyr is initialized.\n // This is needed for streaming captions, but may result in unselectable options\n update: false,\n },\n\n // Fullscreen settings\n fullscreen: {\n enabled: true, // Allow fullscreen?\n fallback: true, // Fallback for vintage browsers\n iosNative: false, // Use the native fullscreen in iOS (disables custom controls)\n },\n\n // Local storage\n storage: {\n enabled: true,\n key: 'plyr',\n },\n\n // Default controls\n controls: [\n 'play-large',\n // 'restart',\n // 'rewind',\n 'play',\n // 'fast-forward',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'pip',\n 'airplay',\n 'fullscreen',\n ],\n settings: ['captions', 'quality', 'speed'],\n\n // Localisation\n i18n: {\n restart: 'Restart',\n rewind: 'Rewind {seektime}s',\n play: 'Play',\n pause: 'Pause',\n fastForward: 'Forward {seektime}s',\n seek: 'Seek',\n seekLabel: '{currentTime} of {duration}',\n played: 'Played',\n buffered: 'Buffered',\n currentTime: 'Current time',\n duration: 'Duration',\n volume: 'Volume',\n mute: 'Mute',\n unmute: 'Unmute',\n enableCaptions: 'Enable captions',\n disableCaptions: 'Disable captions',\n enterFullscreen: 'Enter fullscreen',\n exitFullscreen: 'Exit fullscreen',\n frameTitle: 'Player for {title}',\n captions: 'Captions',\n settings: 'Settings',\n menuBack: 'Go back to previous menu',\n speed: 'Speed',\n normal: 'Normal',\n quality: 'Quality',\n loop: 'Loop',\n start: 'Start',\n end: 'End',\n all: 'All',\n reset: 'Reset',\n disabled: 'Disabled',\n enabled: 'Enabled',\n advertisement: 'Ad',\n qualityBadge: {\n 2160: '4K',\n 1440: 'HD',\n 1080: 'HD',\n 720: 'HD',\n 576: 'SD',\n 480: 'SD',\n },\n },\n\n // URLs\n urls: {\n vimeo: {\n sdk: 'https://player.vimeo.com/api/player.js',\n iframe: 'https://player.vimeo.com/video/{0}?{1}',\n api: 'https://vimeo.com/api/v2/video/{0}.json',\n },\n youtube: {\n sdk: 'https://www.youtube.com/iframe_api',\n api:\n 'https://www.googleapis.com/youtube/v3/videos?id={0}&key={1}&fields=items(snippet(title))&part=snippet',\n },\n googleIMA: {\n sdk: 'https://imasdk.googleapis.com/js/sdkloader/ima3.js',\n },\n },\n\n // Custom control listeners\n listeners: {\n seek: null,\n play: null,\n pause: null,\n restart: null,\n rewind: null,\n fastForward: null,\n mute: null,\n volume: null,\n captions: null,\n fullscreen: null,\n pip: null,\n airplay: null,\n speed: null,\n quality: null,\n loop: null,\n language: null,\n },\n\n // Events to watch and bubble\n events: [\n // Events to watch on HTML5 media elements and bubble\n // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events\n 'ended',\n 'progress',\n 'stalled',\n 'playing',\n 'waiting',\n 'canplay',\n 'canplaythrough',\n 'loadstart',\n 'loadeddata',\n 'loadedmetadata',\n 'timeupdate',\n 'volumechange',\n 'play',\n 'pause',\n 'error',\n 'seeking',\n 'seeked',\n 'emptied',\n 'ratechange',\n 'cuechange',\n\n // Custom events\n 'enterfullscreen',\n 'exitfullscreen',\n 'captionsenabled',\n 'captionsdisabled',\n 'languagechange',\n 'controlshidden',\n 'controlsshown',\n 'ready',\n\n // YouTube\n 'statechange',\n\n // Quality\n 'qualitychange',\n\n // Ads\n 'adsloaded',\n 'adscontentpause',\n 'adscontentresume',\n 'adstarted',\n 'adsmidpoint',\n 'adscomplete',\n 'adsallcomplete',\n 'adsimpression',\n 'adsclick',\n ],\n\n // Selectors\n // Change these to match your template if using custom HTML\n selectors: {\n editable: 'input, textarea, select, [contenteditable]',\n container: '.plyr',\n controls: {\n container: null,\n wrapper: '.plyr__controls',\n },\n labels: '[data-plyr]',\n buttons: {\n play: '[data-plyr=\"play\"]',\n pause: '[data-plyr=\"pause\"]',\n restart: '[data-plyr=\"restart\"]',\n rewind: '[data-plyr=\"rewind\"]',\n fastForward: '[data-plyr=\"fast-forward\"]',\n mute: '[data-plyr=\"mute\"]',\n captions: '[data-plyr=\"captions\"]',\n fullscreen: '[data-plyr=\"fullscreen\"]',\n pip: '[data-plyr=\"pip\"]',\n airplay: '[data-plyr=\"airplay\"]',\n settings: '[data-plyr=\"settings\"]',\n loop: '[data-plyr=\"loop\"]',\n },\n inputs: {\n seek: '[data-plyr=\"seek\"]',\n volume: '[data-plyr=\"volume\"]',\n speed: '[data-plyr=\"speed\"]',\n language: '[data-plyr=\"language\"]',\n quality: '[data-plyr=\"quality\"]',\n },\n display: {\n currentTime: '.plyr__time--current',\n duration: '.plyr__time--duration',\n buffer: '.plyr__progress__buffer',\n loop: '.plyr__progress__loop', // Used later\n volume: '.plyr__volume--display',\n },\n progress: '.plyr__progress',\n captions: '.plyr__captions',\n caption: '.plyr__caption',\n menu: {\n quality: '.js-plyr__menu__list--quality',\n },\n },\n\n // Class hooks added to the player in different states\n classNames: {\n type: 'plyr--{0}',\n provider: 'plyr--{0}',\n video: 'plyr__video-wrapper',\n embed: 'plyr__video-embed',\n embedContainer: 'plyr__video-embed__container',\n poster: 'plyr__poster',\n posterEnabled: 'plyr__poster-enabled',\n ads: 'plyr__ads',\n control: 'plyr__control',\n controlPressed: 'plyr__control--pressed',\n playing: 'plyr--playing',\n paused: 'plyr--paused',\n stopped: 'plyr--stopped',\n loading: 'plyr--loading',\n hover: 'plyr--hover',\n tooltip: 'plyr__tooltip',\n cues: 'plyr__cues',\n hidden: 'plyr__sr-only',\n hideControls: 'plyr--hide-controls',\n isIos: 'plyr--is-ios',\n isTouch: 'plyr--is-touch',\n uiSupported: 'plyr--full-ui',\n noTransition: 'plyr--no-transition',\n display: {\n time: 'plyr__time',\n },\n menu: {\n value: 'plyr__menu__value',\n badge: 'plyr__badge',\n open: 'plyr--menu-open',\n },\n captions: {\n enabled: 'plyr--captions-enabled',\n active: 'plyr--captions-active',\n },\n fullscreen: {\n enabled: 'plyr--fullscreen-enabled',\n fallback: 'plyr--fullscreen-fallback',\n },\n pip: {\n supported: 'plyr--pip-supported',\n active: 'plyr--pip-active',\n },\n airplay: {\n supported: 'plyr--airplay-supported',\n active: 'plyr--airplay-active',\n },\n tabFocus: 'plyr__tab-focus',\n },\n\n // Embed attributes\n attributes: {\n embed: {\n provider: 'data-plyr-provider',\n id: 'data-plyr-embed-id',\n },\n },\n\n // API keys\n keys: {\n google: null,\n },\n\n // Advertisements plugin\n // Register for an account here: http://vi.ai/publisher-video-monetization/?aid=plyrio\n ads: {\n enabled: false,\n publisherId: '',\n },\n};\n\nexport default defaults;\n","// ==========================================================================\n// Plyr supported types and providers\n// ==========================================================================\n\nexport const providers = {\n html5: 'html5',\n youtube: 'youtube',\n vimeo: 'vimeo',\n};\n\nexport const types = {\n audio: 'audio',\n video: 'video',\n};\n\n/**\n * Get provider by URL\n * @param {string} url\n */\nexport function getProviderByUrl(url) {\n // YouTube\n if (/^(https?:\\/\\/)?(www\\.)?(youtube\\.com|youtu\\.?be)\\/.+$/.test(url)) {\n return providers.youtube;\n }\n\n // Vimeo\n if (/^https?:\\/\\/player.vimeo.com\\/video\\/\\d{0,9}(?=\\b|\\/)/.test(url)) {\n return providers.vimeo;\n }\n\n return null;\n}\n\nexport default { providers, types };\n","// ==========================================================================\n// Console wrapper\n// ==========================================================================\n\nconst noop = () => {};\n\nexport default class Console {\n constructor(enabled = false) {\n this.enabled = window.console && enabled;\n\n if (this.enabled) {\n this.log('Debugging enabled');\n }\n }\n\n get log() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.log, console) : noop;\n }\n\n get warn() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.warn, console) : noop;\n }\n\n get error() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.error, console) : noop;\n }\n}\n","// ==========================================================================\n// Fullscreen wrapper\n// https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API#prefixing\n// https://webkit.org/blog/7929/designing-websites-for-iphone-x/\n// ==========================================================================\n\nimport { repaint } from './utils/animation';\nimport browser from './utils/browser';\nimport { hasClass, toggleClass, trapFocus } from './utils/elements';\nimport { on, triggerEvent } from './utils/events';\nimport is from './utils/is';\n\nfunction onChange() {\n if (!this.enabled) {\n return;\n }\n\n // Update toggle button\n const button = this.player.elements.buttons.fullscreen;\n if (is.element(button)) {\n button.pressed = this.active;\n }\n\n // Trigger an event\n triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);\n\n // Trap focus in container\n if (!browser.isIos) {\n trapFocus.call(this.player, this.target, this.active);\n }\n}\n\nfunction toggleFallback(toggle = false) {\n // Store or restore scroll position\n if (toggle) {\n this.scrollPosition = {\n x: window.scrollX || 0,\n y: window.scrollY || 0,\n };\n } else {\n window.scrollTo(this.scrollPosition.x, this.scrollPosition.y);\n }\n\n // Toggle scroll\n document.body.style.overflow = toggle ? 'hidden' : '';\n\n // Toggle class hook\n toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle);\n\n // Force full viewport on iPhone X+\n if (browser.isIos) {\n let viewport = document.head.querySelector('meta[name=\"viewport\"]');\n const property = 'viewport-fit=cover';\n\n // Inject the viewport meta if required\n if (!viewport) {\n viewport = document.createElement('meta');\n viewport.setAttribute('name', 'viewport');\n }\n\n // Check if the property already exists\n const hasProperty = is.string(viewport.content) && viewport.content.includes(property);\n\n if (toggle) {\n this.cleanupViewport = !hasProperty;\n\n if (!hasProperty) {\n viewport.content += `,${property}`;\n }\n } else if (this.cleanupViewport) {\n viewport.content = viewport.content\n .split(',')\n .filter(part => part.trim() !== property)\n .join(',');\n }\n\n // Force a repaint as sometimes Safari doesn't want to fill the screen\n setTimeout(() => repaint(this.target), 100);\n }\n\n // Toggle button and fire events\n onChange.call(this);\n}\n\nclass Fullscreen {\n constructor(player) {\n // Keep reference to parent\n this.player = player;\n\n // Get prefix\n this.prefix = Fullscreen.prefix;\n this.property = Fullscreen.property;\n\n // Scroll position\n this.scrollPosition = { x: 0, y: 0 };\n\n // Register event listeners\n // Handle event (incase user presses escape etc)\n on.call(\n this.player,\n document,\n this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`,\n () => {\n // TODO: Filter for target??\n onChange.call(this);\n },\n );\n\n // Fullscreen toggle on double click\n on.call(this.player, this.player.elements.container, 'dblclick', event => {\n // Ignore double click in controls\n if (is.element(this.player.elements.controls) && this.player.elements.controls.contains(event.target)) {\n return;\n }\n\n this.toggle();\n });\n\n // Update the UI\n this.update();\n }\n\n // Determine if native supported\n static get native() {\n return !!(\n document.fullscreenEnabled ||\n document.webkitFullscreenEnabled ||\n document.mozFullScreenEnabled ||\n document.msFullscreenEnabled\n );\n }\n\n // Get the prefix for handlers\n static get prefix() {\n // No prefix\n if (is.function(document.exitFullscreen)) {\n return '';\n }\n\n // Check for fullscreen support by vendor prefix\n let value = '';\n const prefixes = ['webkit', 'moz', 'ms'];\n\n prefixes.some(pre => {\n if (is.function(document[`${pre}ExitFullscreen`]) || is.function(document[`${pre}CancelFullScreen`])) {\n value = pre;\n return true;\n }\n\n return false;\n });\n\n return value;\n }\n\n static get property() {\n return this.prefix === 'moz' ? 'FullScreen' : 'Fullscreen';\n }\n\n // Determine if fullscreen is enabled\n get enabled() {\n return (\n (Fullscreen.native || this.player.config.fullscreen.fallback) &&\n this.player.config.fullscreen.enabled &&\n this.player.supported.ui &&\n this.player.isVideo\n );\n }\n\n // Get active state\n get active() {\n if (!this.enabled) {\n return false;\n }\n\n // Fallback using classname\n if (!Fullscreen.native) {\n return hasClass(this.target, this.player.config.classNames.fullscreen.fallback);\n }\n\n const element = !this.prefix ? document.fullscreenElement : document[`${this.prefix}${this.property}Element`];\n\n return element === this.target;\n }\n\n // Get target element\n get target() {\n return browser.isIos && this.player.config.fullscreen.iosNative\n ? this.player.media\n : this.player.elements.container;\n }\n\n // Update UI\n update() {\n if (this.enabled) {\n this.player.debug.log(`${Fullscreen.native ? 'Native' : 'Fallback'} fullscreen enabled`);\n } else {\n this.player.debug.log('Fullscreen not supported and fallback disabled');\n }\n\n // Add styling hook to show button\n toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.enabled);\n }\n\n // Make an element fullscreen\n enter() {\n if (!this.enabled) {\n return;\n }\n\n // iOS native fullscreen doesn't need the request step\n if (browser.isIos && this.player.config.fullscreen.iosNative) {\n this.target.webkitEnterFullscreen();\n } else if (!Fullscreen.native) {\n toggleFallback.call(this, true);\n } else if (!this.prefix) {\n this.target.requestFullscreen();\n } else if (!is.empty(this.prefix)) {\n this.target[`${this.prefix}Request${this.property}`]();\n }\n }\n\n // Bail from fullscreen\n exit() {\n if (!this.enabled) {\n return;\n }\n\n // iOS native fullscreen\n if (browser.isIos && this.player.config.fullscreen.iosNative) {\n this.target.webkitExitFullscreen();\n this.player.play();\n } else if (!Fullscreen.native) {\n toggleFallback.call(this, false);\n } else if (!this.prefix) {\n (document.cancelFullScreen || document.exitFullscreen).call(document);\n } else if (!is.empty(this.prefix)) {\n const action = this.prefix === 'moz' ? 'Cancel' : 'Exit';\n document[`${this.prefix}${action}${this.property}`]();\n }\n }\n\n // Toggle state\n toggle() {\n if (!this.active) {\n this.enter();\n } else {\n this.exit();\n }\n }\n}\n\nexport default Fullscreen;\n","// ==========================================================================\n// Load image avoiding xhr/fetch CORS issues\n// Server status can't be obtained this way unfortunately, so this uses \"naturalWidth\" to determine if the image has loaded\n// By default it checks if it is at least 1px, but you can add a second argument to change this\n// ==========================================================================\n\nexport default function loadImage(src, minWidth = 1) {\n return new Promise((resolve, reject) => {\n const image = new Image();\n\n const handler = () => {\n delete image.onload;\n delete image.onerror;\n (image.naturalWidth >= minWidth ? resolve : reject)(image);\n };\n\n Object.assign(image, { onload: handler, onerror: handler, src });\n });\n}\n","// ==========================================================================\n// Plyr UI\n// ==========================================================================\n\nimport captions from './captions';\nimport controls from './controls';\nimport support from './support';\nimport browser from './utils/browser';\nimport { getElement, toggleClass } from './utils/elements';\nimport { ready, triggerEvent } from './utils/events';\nimport i18n from './utils/i18n';\nimport is from './utils/is';\nimport loadImage from './utils/loadImage';\n\nconst ui = {\n addStyleHook() {\n toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);\n toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui);\n },\n\n // Toggle native HTML5 media controls\n toggleNativeControls(toggle = false) {\n if (toggle && this.isHTML5) {\n this.media.setAttribute('controls', '');\n } else {\n this.media.removeAttribute('controls');\n }\n },\n\n // Setup the UI\n build() {\n // Re-attach media element listeners\n // TODO: Use event bubbling?\n this.listeners.media();\n\n // Don't setup interface if no support\n if (!this.supported.ui) {\n this.debug.warn(`Basic support only for ${this.provider} ${this.type}`);\n\n // Restore native controls\n ui.toggleNativeControls.call(this, true);\n\n // Bail\n return;\n }\n\n // Inject custom controls if not present\n if (!is.element(this.elements.controls)) {\n // Inject custom controls\n controls.inject.call(this);\n\n // Re-attach control listeners\n this.listeners.controls();\n }\n\n // Remove native controls\n ui.toggleNativeControls.call(this);\n\n // Setup captions for HTML5\n if (this.isHTML5) {\n captions.setup.call(this);\n }\n\n // Reset volume\n this.volume = null;\n\n // Reset mute state\n this.muted = null;\n\n // Reset speed\n this.speed = null;\n\n // Reset loop state\n this.loop = null;\n\n // Reset quality setting\n this.quality = null;\n\n // Reset volume display\n controls.updateVolume.call(this);\n\n // Reset time display\n controls.timeUpdate.call(this);\n\n // Update the UI\n ui.checkPlaying.call(this);\n\n // Check for picture-in-picture support\n toggleClass(\n this.elements.container,\n this.config.classNames.pip.supported,\n support.pip && this.isHTML5 && this.isVideo,\n );\n\n // Check for airplay support\n toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5);\n\n // Add iOS class\n toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);\n\n // Add touch class\n toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch);\n\n // Ready for API calls\n this.ready = true;\n\n // Ready event at end of execution stack\n setTimeout(() => {\n triggerEvent.call(this, this.media, 'ready');\n }, 0);\n\n // Set the title\n ui.setTitle.call(this);\n\n // Assure the poster image is set, if the property was added before the element was created\n if (this.poster) {\n ui.setPoster.call(this, this.poster, false).catch(() => {});\n }\n\n // Manually set the duration if user has overridden it.\n // The event listeners for it doesn't get called if preload is disabled (#701)\n if (this.config.duration) {\n controls.durationUpdate.call(this);\n }\n },\n\n // Setup aria attribute for play and iframe title\n setTitle() {\n // Find the current text\n let label = i18n.get('play', this.config);\n\n // If there's a media title set, use that for the label\n if (is.string(this.config.title) && !is.empty(this.config.title)) {\n label += `, ${this.config.title}`;\n }\n\n // If there's a play button, set label\n Array.from(this.elements.buttons.play || []).forEach(button => {\n button.setAttribute('aria-label', label);\n });\n\n // Set iframe title\n // https://github.com/sampotts/plyr/issues/124\n if (this.isEmbed) {\n const iframe = getElement.call(this, 'iframe');\n\n if (!is.element(iframe)) {\n return;\n }\n\n // Default to media type\n const title = !is.empty(this.config.title) ? this.config.title : 'video';\n const format = i18n.get('frameTitle', this.config);\n\n iframe.setAttribute('title', format.replace('{title}', title));\n }\n },\n\n // Toggle poster\n togglePoster(enable) {\n toggleClass(this.elements.container, this.config.classNames.posterEnabled, enable);\n },\n\n // Set the poster image (async)\n // Used internally for the poster setter, with the passive option forced to false\n setPoster(poster, passive = true) {\n // Don't override if call is passive\n if (passive && this.poster) {\n return Promise.reject(new Error('Poster already set'));\n }\n\n // Set property synchronously to respect the call order\n this.media.setAttribute('poster', poster);\n\n // Wait until ui is ready\n return (\n ready\n .call(this)\n // Load image\n .then(() => loadImage(poster))\n .catch(err => {\n // Hide poster on error unless it's been set by another call\n if (poster === this.poster) {\n ui.togglePoster.call(this, false);\n }\n // Rethrow\n throw err;\n })\n .then(() => {\n // Prevent race conditions\n if (poster !== this.poster) {\n throw new Error('setPoster cancelled by later call to setPoster');\n }\n })\n .then(() => {\n Object.assign(this.elements.poster.style, {\n backgroundImage: `url('${poster}')`,\n // Reset backgroundSize as well (since it can be set to \"cover\" for padded thumbnails for youtube)\n backgroundSize: '',\n });\n ui.togglePoster.call(this, true);\n return poster;\n })\n );\n },\n\n // Check playing state\n checkPlaying(event) {\n // Class hooks\n toggleClass(this.elements.container, this.config.classNames.playing, this.playing);\n toggleClass(this.elements.container, this.config.classNames.paused, this.paused);\n toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);\n\n // Set state\n Array.from(this.elements.buttons.play || []).forEach(target => {\n target.pressed = this.playing;\n });\n\n // Only update controls on non timeupdate events\n if (is.event(event) && event.type === 'timeupdate') {\n return;\n }\n\n // Toggle controls\n ui.toggleControls.call(this);\n },\n\n // Check if media is loading\n checkLoading(event) {\n this.loading = ['stalled', 'waiting'].includes(event.type);\n\n // Clear timer\n clearTimeout(this.timers.loading);\n\n // Timer to prevent flicker when seeking\n this.timers.loading = setTimeout(() => {\n // Update progress bar loading class state\n toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Update controls visibility\n ui.toggleControls.call(this);\n }, this.loading ? 250 : 0);\n },\n\n // Toggle controls based on state and `force` argument\n toggleControls(force) {\n const { controls } = this.elements;\n\n if (controls && this.config.hideControls) {\n // Show controls if force, loading, paused, or button interaction, otherwise hide\n this.toggleControls(Boolean(force || this.loading || this.paused || controls.pressed || controls.hover));\n }\n },\n};\n\nexport default ui;\n","// ==========================================================================\n// Plyr Event Listeners\n// ==========================================================================\n\nimport controls from './controls';\nimport ui from './ui';\nimport { repaint } from './utils/animation';\nimport browser from './utils/browser';\nimport { getElement, getElements, matches, toggleClass, toggleHidden } from './utils/elements';\nimport { on, once, toggleListener, triggerEvent } from './utils/events';\nimport is from './utils/is';\n\nclass Listeners {\n constructor(player) {\n this.player = player;\n this.lastKey = null;\n this.focusTimer = null;\n this.lastKeyDown = null;\n\n this.handleKey = this.handleKey.bind(this);\n this.toggleMenu = this.toggleMenu.bind(this);\n this.setTabFocus = this.setTabFocus.bind(this);\n this.firstTouch = this.firstTouch.bind(this);\n }\n\n // Handle key presses\n handleKey(event) {\n const { player } = this;\n const { elements } = player;\n const code = event.keyCode ? event.keyCode : event.which;\n const pressed = event.type === 'keydown';\n const repeat = pressed && code === this.lastKey;\n\n // Bail if a modifier key is set\n if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {\n return;\n }\n\n // If the event is bubbled from the media element\n // Firefox doesn't get the keycode for whatever reason\n if (!is.number(code)) {\n return;\n }\n\n // Seek by the number keys\n const seekByKey = () => {\n // Divide the max duration into 10th's and times by the number value\n player.currentTime = (player.duration / 10) * (code - 48);\n };\n\n // Handle the key on keydown\n // Reset on keyup\n if (pressed) {\n // Check focused element\n // and if the focused element is not editable (e.g. text input)\n // and any that accept key input http://webaim.org/techniques/keyboard/\n const focused = document.activeElement;\n if (is.element(focused)) {\n const { editable } = player.config.selectors;\n const { seek } = elements.inputs;\n\n if (focused !== seek && matches(focused, editable)) {\n return;\n }\n\n if (event.which === 32 && matches(focused, 'button, [role^=\"menuitem\"]')) {\n return;\n }\n }\n\n // Which keycodes should we prevent default\n const preventDefault = [32, 37, 38, 39, 40, 48, 49, 50, 51, 52, 53, 54, 56, 57, 67, 70, 73, 75, 76, 77, 79];\n\n // If the code is found prevent default (e.g. prevent scrolling for arrows)\n if (preventDefault.includes(code)) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n switch (code) {\n case 48:\n case 49:\n case 50:\n case 51:\n case 52:\n case 53:\n case 54:\n case 55:\n case 56:\n case 57:\n // 0-9\n if (!repeat) {\n seekByKey();\n }\n break;\n\n case 32:\n case 75:\n // Space and K key\n if (!repeat) {\n player.togglePlay();\n }\n break;\n\n case 38:\n // Arrow up\n player.increaseVolume(0.1);\n break;\n\n case 40:\n // Arrow down\n player.decreaseVolume(0.1);\n break;\n\n case 77:\n // M key\n if (!repeat) {\n player.muted = !player.muted;\n }\n break;\n\n case 39:\n // Arrow forward\n player.forward();\n break;\n\n case 37:\n // Arrow back\n player.rewind();\n break;\n\n case 70:\n // F key\n player.fullscreen.toggle();\n break;\n\n case 67:\n // C key\n if (!repeat) {\n player.toggleCaptions();\n }\n break;\n\n case 76:\n // L key\n player.loop = !player.loop;\n break;\n\n /* case 73:\n this.setLoop('start');\n break;\n\n case 76:\n this.setLoop();\n break;\n\n case 79:\n this.setLoop('end');\n break; */\n\n default:\n break;\n }\n\n // Escape is handle natively when in full screen\n // So we only need to worry about non native\n if (!player.fullscreen.enabled && player.fullscreen.active && code === 27) {\n player.fullscreen.toggle();\n }\n\n // Store last code for next cycle\n this.lastKey = code;\n } else {\n this.lastKey = null;\n }\n }\n\n // Toggle menu\n toggleMenu(event) {\n controls.toggleMenu.call(this.player, event);\n }\n\n // Device is touch enabled\n firstTouch() {\n const { player } = this;\n const { elements } = player;\n\n player.touch = true;\n\n // Add touch class\n toggleClass(elements.container, player.config.classNames.isTouch, true);\n }\n\n setTabFocus(event) {\n const { player } = this;\n const { elements } = player;\n\n clearTimeout(this.focusTimer);\n\n // Ignore any key other than tab\n if (event.type === 'keydown' && event.which !== 9) {\n return;\n }\n\n // Store reference to event timeStamp\n if (event.type === 'keydown') {\n this.lastKeyDown = event.timeStamp;\n }\n\n // Remove current classes\n const removeCurrent = () => {\n const className = player.config.classNames.tabFocus;\n const current = getElements.call(player, `.${className}`);\n toggleClass(current, className, false);\n };\n\n // Determine if a key was pressed to trigger this event\n const wasKeyDown = event.timeStamp - this.lastKeyDown <= 20;\n\n // Ignore focus events if a key was pressed prior\n if (event.type === 'focus' && !wasKeyDown) {\n return;\n }\n\n // Remove all current\n removeCurrent();\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n this.focusTimer = setTimeout(() => {\n const focused = document.activeElement;\n\n // Ignore if current focus element isn't inside the player\n if (!elements.container.contains(focused)) {\n return;\n }\n\n toggleClass(document.activeElement, player.config.classNames.tabFocus, true);\n }, 10);\n }\n\n // Global window & document listeners\n global(toggle = true) {\n const { player } = this;\n\n // Keyboard shortcuts\n if (player.config.keyboard.global) {\n toggleListener.call(player, window, 'keydown keyup', this.handleKey, toggle, false);\n }\n\n // Click anywhere closes menu\n toggleListener.call(player, document.body, 'click', this.toggleMenu, toggle);\n\n // Detect touch by events\n once.call(player, document.body, 'touchstart', this.firstTouch);\n\n // Tab focus detection\n toggleListener.call(player, document.body, 'keydown focus blur', this.setTabFocus, toggle, false, true);\n }\n\n // Container listeners\n container() {\n const { player } = this;\n const { elements } = player;\n\n // Keyboard shortcuts\n if (!player.config.keyboard.global && player.config.keyboard.focused) {\n on.call(player, elements.container, 'keydown keyup', this.handleKey, false);\n }\n\n // Toggle controls on mouse events and entering fullscreen\n on.call(\n player,\n elements.container,\n 'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen',\n event => {\n const { controls } = elements;\n\n // Remove button states for fullscreen\n if (controls && event.type === 'enterfullscreen') {\n controls.pressed = false;\n controls.hover = false;\n }\n\n // Show, then hide after a timeout unless another control event occurs\n const show = ['touchstart', 'touchmove', 'mousemove'].includes(event.type);\n\n let delay = 0;\n\n if (show) {\n ui.toggleControls.call(player, true);\n // Use longer timeout for touch devices\n delay = player.touch ? 3000 : 2000;\n }\n\n // Clear timer\n clearTimeout(player.timers.controls);\n\n // Set new timer to prevent flicker when seeking\n player.timers.controls = setTimeout(() => ui.toggleControls.call(player, false), delay);\n },\n );\n }\n\n // Listen for media events\n media() {\n const { player } = this;\n const { elements } = player;\n\n // Time change on media\n on.call(player, player.media, 'timeupdate seeking seeked', event => controls.timeUpdate.call(player, event));\n\n // Display duration\n on.call(player, player.media, 'durationchange loadeddata loadedmetadata', event =>\n controls.durationUpdate.call(player, event),\n );\n\n // Check for audio tracks on load\n // We can't use `loadedmetadata` as it doesn't seem to have audio tracks at that point\n on.call(player, player.media, 'canplay', () => {\n toggleHidden(elements.volume, !player.hasAudio);\n toggleHidden(elements.buttons.mute, !player.hasAudio);\n });\n\n // Handle the media finishing\n on.call(player, player.media, 'ended', () => {\n // Show poster on end\n if (player.isHTML5 && player.isVideo && player.config.resetOnEnd) {\n // Restart\n player.restart();\n }\n });\n\n // Check for buffer progress\n on.call(player, player.media, 'progress playing seeking seeked', event =>\n controls.updateProgress.call(player, event),\n );\n\n // Handle volume changes\n on.call(player, player.media, 'volumechange', event => controls.updateVolume.call(player, event));\n\n // Handle play/pause\n on.call(player, player.media, 'playing play pause ended emptied timeupdate', event =>\n ui.checkPlaying.call(player, event),\n );\n\n // Loading state\n on.call(player, player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(player, event));\n\n // If autoplay, then load advertisement if required\n // TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows\n on.call(player, player.media, 'playing', () => {\n if (!player.ads) {\n return;\n }\n\n // If ads are enabled, wait for them first\n if (player.ads.enabled && !player.ads.initialized) {\n // Wait for manager response\n player.ads.managerPromise.then(() => player.ads.play()).catch(() => player.play());\n }\n });\n\n // Click video\n if (player.supported.ui && player.config.clickToPlay && !player.isAudio) {\n // Re-fetch the wrapper\n const wrapper = getElement.call(player, `.${player.config.classNames.video}`);\n\n // Bail if there's no wrapper (this should never happen)\n if (!is.element(wrapper)) {\n return;\n }\n\n // On click play, pause ore restart\n on.call(player, elements.container, 'click', event => {\n const targets = [elements.container, wrapper];\n\n // Ignore if click if not container or in video wrapper\n if (!targets.includes(event.target) && !wrapper.contains(event.target)) {\n return;\n }\n\n // Touch devices will just show controls (if hidden)\n if (player.touch && player.config.hideControls) {\n return;\n }\n\n if (player.ended) {\n player.restart();\n player.play();\n } else {\n player.togglePlay();\n }\n });\n }\n\n // Disable right click\n if (player.supported.ui && player.config.disableContextMenu) {\n on.call(\n player,\n elements.wrapper,\n 'contextmenu',\n event => {\n event.preventDefault();\n },\n false,\n );\n }\n\n // Volume change\n on.call(player, player.media, 'volumechange', () => {\n // Save to storage\n player.storage.set({\n volume: player.volume,\n muted: player.muted,\n });\n });\n\n // Speed change\n on.call(player, player.media, 'ratechange', () => {\n // Update UI\n controls.updateSetting.call(player, 'speed');\n\n // Save to storage\n player.storage.set({ speed: player.speed });\n });\n\n // Quality change\n on.call(player, player.media, 'qualitychange', event => {\n // Update UI\n controls.updateSetting.call(player, 'quality', null, event.detail.quality);\n });\n\n // Proxy events to container\n // Bubble up key events for Edge\n const proxyEvents = player.config.events.concat(['keyup', 'keydown']).join(' ');\n\n on.call(player, player.media, proxyEvents, event => {\n let { detail = {} } = event;\n\n // Get error details from media\n if (event.type === 'error') {\n detail = player.media.error;\n }\n\n triggerEvent.call(player, elements.container, event.type, true, detail);\n });\n }\n\n // Run default and custom handlers\n proxy(event, defaultHandler, customHandlerKey) {\n const { player } = this;\n const customHandler = player.config.listeners[customHandlerKey];\n const hasCustomHandler = is.function(customHandler);\n let returned = true;\n\n // Execute custom handler\n if (hasCustomHandler) {\n returned = customHandler.call(player, event);\n }\n\n // Only call default handler if not prevented in custom handler\n if (returned && is.function(defaultHandler)) {\n defaultHandler.call(player, event);\n }\n }\n\n // Trigger custom and default handlers\n bind(element, type, defaultHandler, customHandlerKey, passive = true) {\n const { player } = this;\n const customHandler = player.config.listeners[customHandlerKey];\n const hasCustomHandler = is.function(customHandler);\n\n on.call(\n player,\n element,\n type,\n event => this.proxy(event, defaultHandler, customHandlerKey),\n passive && !hasCustomHandler,\n );\n }\n\n // Listen for control events\n controls() {\n const { player } = this;\n const { elements } = player;\n\n // IE doesn't support input event, so we fallback to change\n const inputEvent = browser.isIE ? 'change' : 'input';\n\n // Play/pause toggle\n if (elements.buttons.play) {\n Array.from(elements.buttons.play).forEach(button => {\n this.bind(button, 'click', player.togglePlay, 'play');\n });\n }\n\n // Pause\n this.bind(elements.buttons.restart, 'click', player.restart, 'restart');\n\n // Rewind\n this.bind(elements.buttons.rewind, 'click', player.rewind, 'rewind');\n\n // Rewind\n this.bind(elements.buttons.fastForward, 'click', player.forward, 'fastForward');\n\n // Mute toggle\n this.bind(\n elements.buttons.mute,\n 'click',\n () => {\n player.muted = !player.muted;\n },\n 'mute',\n );\n\n // Captions toggle\n this.bind(elements.buttons.captions, 'click', () => player.toggleCaptions());\n\n // Fullscreen toggle\n this.bind(\n elements.buttons.fullscreen,\n 'click',\n () => {\n player.fullscreen.toggle();\n },\n 'fullscreen',\n );\n\n // Picture-in-Picture\n this.bind(\n elements.buttons.pip,\n 'click',\n () => {\n player.pip = 'toggle';\n },\n 'pip',\n );\n\n // Airplay\n this.bind(elements.buttons.airplay, 'click', player.airplay, 'airplay');\n\n // Settings menu - click toggle\n this.bind(elements.buttons.settings, 'click', event => {\n // Prevent the document click listener closing the menu\n event.stopPropagation();\n\n controls.toggleMenu.call(player, event);\n });\n\n // Settings menu - keyboard toggle\n // We have to bind to keyup otherwise Firefox triggers a click when a keydown event handler shifts focus\n // https://bugzilla.mozilla.org/show_bug.cgi?id=1220143\n this.bind(\n elements.buttons.settings,\n 'keyup',\n event => {\n const code = event.which;\n\n // We only care about space and return\n if (![13, 32].includes(code)) {\n return;\n }\n\n // Because return triggers a click anyway, all we need to do is set focus\n if (code === 13) {\n controls.focusFirstMenuItem.call(player, null, true);\n return;\n }\n\n // Prevent scroll\n event.preventDefault();\n\n // Prevent playing video (Firefox)\n event.stopPropagation();\n\n // Toggle menu\n controls.toggleMenu.call(player, event);\n },\n null,\n false, // Can't be passive as we're preventing default\n );\n\n // Escape closes menu\n this.bind(elements.settings.menu, 'keydown', event => {\n if (event.which === 27) {\n controls.toggleMenu.call(player, event);\n }\n });\n\n // Set range input alternative \"value\", which matches the tooltip time (#954)\n this.bind(elements.inputs.seek, 'mousedown mousemove', event => {\n const rect = elements.progress.getBoundingClientRect();\n const percent = (100 / rect.width) * (event.pageX - rect.left);\n event.currentTarget.setAttribute('seek-value', percent);\n });\n\n // Pause while seeking\n this.bind(elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', event => {\n const seek = event.currentTarget;\n const code = event.keyCode ? event.keyCode : event.which;\n const attribute = 'play-on-seeked';\n\n if (is.keyboardEvent(event) && (code !== 39 && code !== 37)) {\n return;\n }\n\n // Was playing before?\n const play = seek.hasAttribute(attribute);\n\n // Done seeking\n const done = ['mouseup', 'touchend', 'keyup'].includes(event.type);\n\n // If we're done seeking and it was playing, resume playback\n if (play && done) {\n seek.removeAttribute(attribute);\n player.play();\n } else if (!done && player.playing) {\n seek.setAttribute(attribute, '');\n player.pause();\n }\n });\n\n // Fix range inputs on iOS\n // Super weird iOS bug where after you interact with an <input type=\"range\">,\n // it takes over further interactions on the page. This is a hack\n if (browser.isIos) {\n const inputs = getElements.call(player, 'input[type=\"range\"]');\n Array.from(inputs).forEach(input => this.bind(input, inputEvent, event => repaint(event.target)));\n }\n\n // Seek\n this.bind(\n elements.inputs.seek,\n inputEvent,\n event => {\n const seek = event.currentTarget;\n\n // If it exists, use seek-value instead of \"value\" for consistency with tooltip time (#954)\n let seekTo = seek.getAttribute('seek-value');\n\n if (is.empty(seekTo)) {\n seekTo = seek.value;\n }\n\n seek.removeAttribute('seek-value');\n\n player.currentTime = (seekTo / seek.max) * player.duration;\n },\n 'seek',\n );\n\n // Seek tooltip\n this.bind(elements.progress, 'mouseenter mouseleave mousemove', event =>\n controls.updateSeekTooltip.call(player, event),\n );\n\n // Polyfill for lower fill in <input type=\"range\"> for webkit\n if (browser.isWebkit) {\n Array.from(getElements.call(player, 'input[type=\"range\"]')).forEach(element => {\n this.bind(element, 'input', event => controls.updateRangeFill.call(player, event.target));\n });\n }\n\n // Current time invert\n // Only if one time element is used for both currentTime and duration\n if (player.config.toggleInvert && !is.element(elements.display.duration)) {\n this.bind(elements.display.currentTime, 'click', () => {\n // Do nothing if we're at the start\n if (player.currentTime === 0) {\n return;\n }\n\n player.config.invertTime = !player.config.invertTime;\n\n controls.timeUpdate.call(player);\n });\n }\n\n // Volume\n this.bind(\n elements.inputs.volume,\n inputEvent,\n event => {\n player.volume = event.target.value;\n },\n 'volume',\n );\n\n // Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)\n this.bind(elements.controls, 'mouseenter mouseleave', event => {\n elements.controls.hover = !player.touch && event.type === 'mouseenter';\n });\n\n // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)\n this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {\n elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);\n });\n\n // Focus in/out on controls\n this.bind(elements.controls, 'focusin focusout', event => {\n const { config, elements, timers } = player;\n const isFocusIn = event.type === 'focusin';\n\n // Skip transition to prevent focus from scrolling the parent element\n toggleClass(elements.controls, config.classNames.noTransition, isFocusIn);\n\n // Toggle\n ui.toggleControls.call(player, isFocusIn);\n\n // If focusin, hide again after delay\n if (isFocusIn) {\n // Restore transition\n setTimeout(() => {\n toggleClass(elements.controls, config.classNames.noTransition, false);\n }, 0);\n\n // Delay a little more for keyboard users\n const delay = this.touch ? 3000 : 4000;\n\n // Clear timer\n clearTimeout(timers.controls);\n\n // Hide\n timers.controls = setTimeout(() => ui.toggleControls.call(player, false), delay);\n }\n });\n\n // Mouse wheel for volume\n this.bind(\n elements.inputs.volume,\n 'wheel',\n event => {\n // Detect \"natural\" scroll - suppored on OS X Safari only\n // Other browsers on OS X will be inverted until support improves\n const inverted = event.webkitDirectionInvertedFromDevice;\n\n // Get delta from event. Invert if `inverted` is true\n const [x, y] = [event.deltaX, -event.deltaY].map(value => (inverted ? -value : value));\n\n // Using the biggest delta, normalize to 1 or -1 (or 0 if no delta)\n const direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y);\n\n // Change the volume by 2%\n player.increaseVolume(direction / 50);\n\n // Don't break page scrolling at max and min\n const { volume } = player.media;\n if ((direction === 1 && volume < 1) || (direction === -1 && volume > 0)) {\n event.preventDefault();\n }\n },\n 'volume',\n false,\n );\n }\n}\n\nexport default Listeners;\n","(function(root, factory) {\n if (typeof define === 'function' && define.amd) {\n define([], factory);\n } else if (typeof exports === 'object') {\n module.exports = factory();\n } else {\n root.loadjs = factory();\n }\n}(this, function() {\n/**\n * Global dependencies.\n * @global {Object} document - DOM\n */\n\nvar devnull = function() {},\n bundleIdCache = {},\n bundleResultCache = {},\n bundleCallbackQueue = {};\n\n\n/**\n * Subscribe to bundle load event.\n * @param {string[]} bundleIds - Bundle ids\n * @param {Function} callbackFn - The callback function\n */\nfunction subscribe(bundleIds, callbackFn) {\n // listify\n bundleIds = bundleIds.push ? bundleIds : [bundleIds];\n\n var depsNotFound = [],\n i = bundleIds.length,\n numWaiting = i,\n fn,\n bundleId,\n r,\n q;\n\n // define callback function\n fn = function (bundleId, pathsNotFound) {\n if (pathsNotFound.length) depsNotFound.push(bundleId);\n\n numWaiting--;\n if (!numWaiting) callbackFn(depsNotFound);\n };\n\n // register callback\n while (i--) {\n bundleId = bundleIds[i];\n\n // execute callback if in result cache\n r = bundleResultCache[bundleId];\n if (r) {\n fn(bundleId, r);\n continue;\n }\n\n // add to callback queue\n q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || [];\n q.push(fn);\n }\n}\n\n\n/**\n * Publish bundle load event.\n * @param {string} bundleId - Bundle id\n * @param {string[]} pathsNotFound - List of files not found\n */\nfunction publish(bundleId, pathsNotFound) {\n // exit if id isn't defined\n if (!bundleId) return;\n\n var q = bundleCallbackQueue[bundleId];\n\n // cache result\n bundleResultCache[bundleId] = pathsNotFound;\n\n // exit if queue is empty\n if (!q) return;\n\n // empty callback queue\n while (q.length) {\n q[0](bundleId, pathsNotFound);\n q.splice(0, 1);\n }\n}\n\n\n/**\n * Execute callbacks.\n * @param {Object or Function} args - The callback args\n * @param {string[]} depsNotFound - List of dependencies not found\n */\nfunction executeCallbacks(args, depsNotFound) {\n // accept function as argument\n if (args.call) args = {success: args};\n\n // success and error callbacks\n if (depsNotFound.length) (args.error || devnull)(depsNotFound);\n else (args.success || devnull)(args);\n}\n\n\n/**\n * Load individual file.\n * @param {string} path - The file path\n * @param {Function} callbackFn - The callback function\n */\nfunction loadFile(path, callbackFn, args, numTries) {\n var doc = document,\n async = args.async,\n maxTries = (args.numRetries || 0) + 1,\n beforeCallbackFn = args.before || devnull,\n pathStripped = path.replace(/^(css|img)!/, ''),\n isCss,\n e;\n\n numTries = numTries || 0;\n\n if (/(^css!|\\.css$)/.test(path)) {\n isCss = true;\n\n // css\n e = doc.createElement('link');\n e.rel = 'stylesheet';\n e.href = pathStripped; //.replace(/^css!/, ''); // remove \"css!\" prefix\n } else if (/(^img!|\\.(png|gif|jpg|svg)$)/.test(path)) {\n // image\n e = doc.createElement('img');\n e.src = pathStripped; \n } else {\n // javascript\n e = doc.createElement('script');\n e.src = path;\n e.async = async === undefined ? true : async;\n }\n\n e.onload = e.onerror = e.onbeforeload = function (ev) {\n var result = ev.type[0];\n\n // Note: The following code isolates IE using `hideFocus` and treats empty\n // stylesheets as failures to get around lack of onerror support\n if (isCss && 'hideFocus' in e) {\n try {\n if (!e.sheet.cssText.length) result = 'e';\n } catch (x) {\n // sheets objects created from load errors don't allow access to\n // `cssText`\n result = 'e';\n }\n }\n\n // handle retries in case of load failure\n if (result == 'e') {\n // increment counter\n numTries += 1;\n\n // exit function and try again\n if (numTries < maxTries) {\n return loadFile(path, callbackFn, args, numTries);\n }\n }\n\n // execute callback\n callbackFn(path, result, ev.defaultPrevented);\n };\n\n // add to document (unless callback returns `false`)\n if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e);\n}\n\n\n/**\n * Load multiple files.\n * @param {string[]} paths - The file paths\n * @param {Function} callbackFn - The callback function\n */\nfunction loadFiles(paths, callbackFn, args) {\n // listify paths\n paths = paths.push ? paths : [paths];\n\n var numWaiting = paths.length,\n x = numWaiting,\n pathsNotFound = [],\n fn,\n i;\n\n // define callback function\n fn = function(path, result, defaultPrevented) {\n // handle error\n if (result == 'e') pathsNotFound.push(path);\n\n // handle beforeload event. If defaultPrevented then that means the load\n // will be blocked (ex. Ghostery/ABP on Safari)\n if (result == 'b') {\n if (defaultPrevented) pathsNotFound.push(path);\n else return;\n }\n\n numWaiting--;\n if (!numWaiting) callbackFn(pathsNotFound);\n };\n\n // load scripts\n for (i=0; i < x; i++) loadFile(paths[i], fn, args);\n}\n\n\n/**\n * Initiate script load and register bundle.\n * @param {(string|string[])} paths - The file paths\n * @param {(string|Function)} [arg1] - The bundleId or success callback\n * @param {Function} [arg2] - The success or error callback\n * @param {Function} [arg3] - The error callback\n */\nfunction loadjs(paths, arg1, arg2) {\n var bundleId,\n args;\n\n // bundleId (if string)\n if (arg1 && arg1.trim) bundleId = arg1;\n\n // args (default is {})\n args = (bundleId ? arg2 : arg1) || {};\n\n // throw error if bundle is already defined\n if (bundleId) {\n if (bundleId in bundleIdCache) {\n throw \"LoadJS\";\n } else {\n bundleIdCache[bundleId] = true;\n }\n }\n\n // load scripts\n loadFiles(paths, function (pathsNotFound) {\n // execute callbacks\n executeCallbacks(args, pathsNotFound);\n\n // publish bundle load event\n publish(bundleId, pathsNotFound);\n }, args);\n}\n\n\n/**\n * Execute callbacks when dependencies have been satisfied.\n * @param {(string|string[])} deps - List of bundle ids\n * @param {Object} args - success/error arguments\n */\nloadjs.ready = function ready(deps, args) {\n // subscribe to bundle load event\n subscribe(deps, function (depsNotFound) {\n // execute callbacks\n executeCallbacks(args, depsNotFound);\n });\n\n return loadjs;\n};\n\n\n/**\n * Manually satisfy bundle dependencies.\n * @param {string} bundleId - The bundle id\n */\nloadjs.done = function done(bundleId) {\n publish(bundleId, []);\n};\n\n\n/**\n * Reset loadjs dependencies statuses\n */\nloadjs.reset = function reset() {\n bundleIdCache = {};\n bundleResultCache = {};\n bundleCallbackQueue = {};\n};\n\n\n/**\n * Determine if bundle has already been defined\n * @param String} bundleId - The bundle id\n */\nloadjs.isDefined = function isDefined(bundleId) {\n return bundleId in bundleIdCache;\n};\n\n\n// export\nreturn loadjs;\n\n}));\n","// ==========================================================================\n// Load an external script\n// ==========================================================================\n\nimport loadjs from 'loadjs';\n\nexport default function loadScript(url) {\n return new Promise((resolve, reject) => {\n loadjs(url, {\n success: resolve,\n error: reject,\n });\n });\n}\n","// ==========================================================================\n// Vimeo plugin\n// ==========================================================================\n\nimport captions from '../captions';\nimport controls from '../controls';\nimport ui from '../ui';\nimport { createElement, replaceElement, toggleClass } from '../utils/elements';\nimport { triggerEvent } from '../utils/events';\nimport fetch from '../utils/fetch';\nimport is from '../utils/is';\nimport loadScript from '../utils/loadScript';\nimport { format, stripHTML } from '../utils/strings';\nimport { buildUrlParams } from '../utils/urls';\n\n// Parse Vimeo ID from URL\nfunction parseId(url) {\n if (is.empty(url)) {\n return null;\n }\n\n if (is.number(Number(url))) {\n return url;\n }\n\n const regex = /^.*(vimeo.com\\/|video\\/)(\\d+).*/;\n return url.match(regex) ? RegExp.$2 : url;\n}\n\n// Get aspect ratio for dimensions\nfunction getAspectRatio(width, height) {\n const getRatio = (w, h) => (h === 0 ? w : getRatio(h, w % h));\n const ratio = getRatio(width, height);\n return `${width / ratio}:${height / ratio}`;\n}\n\n// Set playback state and trigger change (only on actual change)\nfunction assurePlaybackState(play) {\n if (play && !this.embed.hasPlayed) {\n this.embed.hasPlayed = true;\n }\n if (this.media.paused === play) {\n this.media.paused = !play;\n triggerEvent.call(this, this.media, play ? 'play' : 'pause');\n }\n}\n\nconst vimeo = {\n setup() {\n // Add embed class for responsive\n toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set intial ratio\n vimeo.setAspectRatio.call(this);\n\n // Load the API if not already\n if (!is.object(window.Vimeo)) {\n loadScript(this.config.urls.vimeo.sdk)\n .then(() => {\n vimeo.ready.call(this);\n })\n .catch(error => {\n this.debug.warn('Vimeo API failed to load', error);\n });\n } else {\n vimeo.ready.call(this);\n }\n },\n\n // Set aspect ratio\n // For Vimeo we have an extra 300% height <div> to hide the standard controls and UI\n setAspectRatio(input) {\n const [x, y] = (is.string(input) ? input : this.config.ratio).split(':');\n const padding = 100 / x * y;\n this.elements.wrapper.style.paddingBottom = `${padding}%`;\n\n if (this.supported.ui) {\n const height = 240;\n const offset = (height - padding) / (height / 50);\n\n this.media.style.transform = `translateY(-${offset}%)`;\n }\n },\n\n // API Ready\n ready() {\n const player = this;\n\n // Get Vimeo params for the iframe\n const options = {\n loop: player.config.loop.active,\n autoplay: player.autoplay,\n // muted: player.muted,\n byline: false,\n portrait: false,\n title: false,\n speed: true,\n transparent: 0,\n gesture: 'media',\n playsinline: !this.config.fullscreen.iosNative,\n };\n const params = buildUrlParams(options);\n\n // Get the source URL or ID\n let source = player.media.getAttribute('src');\n\n // Get from <div> if needed\n if (is.empty(source)) {\n source = player.media.getAttribute(player.config.attributes.embed.id);\n }\n\n const id = parseId(source);\n\n // Build an iframe\n const iframe = createElement('iframe');\n const src = format(player.config.urls.vimeo.iframe, id, params);\n iframe.setAttribute('src', src);\n iframe.setAttribute('allowfullscreen', '');\n iframe.setAttribute('allowtransparency', '');\n iframe.setAttribute('allow', 'autoplay');\n\n // Get poster, if already set\n const { poster } = player;\n\n // Inject the package\n const wrapper = createElement('div', { poster, class: player.config.classNames.embedContainer });\n wrapper.appendChild(iframe);\n player.media = replaceElement(wrapper, player.media);\n\n // Get poster image\n fetch(format(player.config.urls.vimeo.api, id), 'json').then(response => {\n if (is.empty(response)) {\n return;\n }\n\n // Get the URL for thumbnail\n const url = new URL(response[0].thumbnail_large);\n\n // Get original image\n url.pathname = `${url.pathname.split('_')[0]}.jpg`;\n\n // Set and show poster\n ui.setPoster.call(player, url.href).catch(() => {});\n });\n\n // Setup instance\n // https://github.com/vimeo/player.js\n player.embed = new window.Vimeo.Player(iframe, {\n autopause: player.config.autopause,\n muted: player.muted,\n });\n\n player.media.paused = true;\n player.media.currentTime = 0;\n\n // Disable native text track rendering\n if (player.supported.ui) {\n player.embed.disableTextTrack();\n }\n\n // Create a faux HTML5 API using the Vimeo API\n player.media.play = () => {\n assurePlaybackState.call(player, true);\n return player.embed.play();\n };\n\n player.media.pause = () => {\n assurePlaybackState.call(player, false);\n return player.embed.pause();\n };\n\n player.media.stop = () => {\n player.pause();\n player.currentTime = 0;\n };\n\n // Seeking\n let { currentTime } = player.media;\n Object.defineProperty(player.media, 'currentTime', {\n get() {\n return currentTime;\n },\n set(time) {\n // Vimeo will automatically play on seek if the video hasn't been played before\n\n // Get current paused state and volume etc\n const { embed, media, paused, volume } = player;\n const restorePause = paused && !embed.hasPlayed;\n\n // Set seeking state and trigger event\n media.seeking = true;\n triggerEvent.call(player, media, 'seeking');\n\n // If paused, mute until seek is complete\n Promise.resolve(restorePause && embed.setVolume(0))\n // Seek\n .then(() => embed.setCurrentTime(time))\n // Restore paused\n .then(() => restorePause && embed.pause())\n // Restore volume\n .then(() => restorePause && embed.setVolume(volume))\n .catch(() => {\n // Do nothing\n });\n },\n });\n\n // Playback speed\n let speed = player.config.speed.selected;\n Object.defineProperty(player.media, 'playbackRate', {\n get() {\n return speed;\n },\n set(input) {\n player.embed\n .setPlaybackRate(input)\n .then(() => {\n speed = input;\n triggerEvent.call(player, player.media, 'ratechange');\n })\n .catch(error => {\n // Hide menu item (and menu if empty)\n if (error.name === 'Error') {\n controls.setSpeedMenu.call(player, []);\n }\n });\n },\n });\n\n // Volume\n let { volume } = player.config;\n Object.defineProperty(player.media, 'volume', {\n get() {\n return volume;\n },\n set(input) {\n player.embed.setVolume(input).then(() => {\n volume = input;\n triggerEvent.call(player, player.media, 'volumechange');\n });\n },\n });\n\n // Muted\n let { muted } = player.config;\n Object.defineProperty(player.media, 'muted', {\n get() {\n return muted;\n },\n set(input) {\n const toggle = is.boolean(input) ? input : false;\n\n player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => {\n muted = toggle;\n triggerEvent.call(player, player.media, 'volumechange');\n });\n },\n });\n\n // Loop\n let { loop } = player.config;\n Object.defineProperty(player.media, 'loop', {\n get() {\n return loop;\n },\n set(input) {\n const toggle = is.boolean(input) ? input : player.config.loop.active;\n\n player.embed.setLoop(toggle).then(() => {\n loop = toggle;\n });\n },\n });\n\n // Source\n let currentSrc;\n player.embed\n .getVideoUrl()\n .then(value => {\n currentSrc = value;\n })\n .catch(error => {\n this.debug.warn(error);\n });\n\n Object.defineProperty(player.media, 'currentSrc', {\n get() {\n return currentSrc;\n },\n });\n\n // Ended\n Object.defineProperty(player.media, 'ended', {\n get() {\n return player.currentTime === player.duration;\n },\n });\n\n // Set aspect ratio based on video size\n Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(dimensions => {\n const ratio = getAspectRatio(dimensions[0], dimensions[1]);\n vimeo.setAspectRatio.call(this, ratio);\n });\n\n // Set autopause\n player.embed.setAutopause(player.config.autopause).then(state => {\n player.config.autopause = state;\n });\n\n // Get title\n player.embed.getVideoTitle().then(title => {\n player.config.title = title;\n ui.setTitle.call(this);\n });\n\n // Get current time\n player.embed.getCurrentTime().then(value => {\n currentTime = value;\n triggerEvent.call(player, player.media, 'timeupdate');\n });\n\n // Get duration\n player.embed.getDuration().then(value => {\n player.media.duration = value;\n triggerEvent.call(player, player.media, 'durationchange');\n });\n\n // Get captions\n player.embed.getTextTracks().then(tracks => {\n player.media.textTracks = tracks;\n captions.setup.call(player);\n });\n\n player.embed.on('cuechange', ({ cues = [] }) => {\n const strippedCues = cues.map(cue => stripHTML(cue.text));\n captions.updateCues.call(player, strippedCues);\n });\n\n player.embed.on('loaded', () => {\n // Assure state and events are updated on autoplay\n player.embed.getPaused().then(paused => {\n assurePlaybackState.call(player, !paused);\n if (!paused) {\n triggerEvent.call(player, player.media, 'playing');\n }\n });\n\n if (is.element(player.embed.element) && player.supported.ui) {\n const frame = player.embed.element;\n\n // Fix keyboard focus issues\n // https://github.com/sampotts/plyr/issues/317\n frame.setAttribute('tabindex', -1);\n }\n });\n\n player.embed.on('play', () => {\n assurePlaybackState.call(player, true);\n triggerEvent.call(player, player.media, 'playing');\n });\n\n player.embed.on('pause', () => {\n assurePlaybackState.call(player, false);\n });\n\n player.embed.on('timeupdate', data => {\n player.media.seeking = false;\n currentTime = data.seconds;\n triggerEvent.call(player, player.media, 'timeupdate');\n });\n\n player.embed.on('progress', data => {\n player.media.buffered = data.percent;\n triggerEvent.call(player, player.media, 'progress');\n\n // Check all loaded\n if (parseInt(data.percent, 10) === 1) {\n triggerEvent.call(player, player.media, 'canplaythrough');\n }\n\n // Get duration as if we do it before load, it gives an incorrect value\n // https://github.com/sampotts/plyr/issues/891\n player.embed.getDuration().then(value => {\n if (value !== player.media.duration) {\n player.media.duration = value;\n triggerEvent.call(player, player.media, 'durationchange');\n }\n });\n });\n\n player.embed.on('seeked', () => {\n player.media.seeking = false;\n triggerEvent.call(player, player.media, 'seeked');\n });\n\n player.embed.on('ended', () => {\n player.media.paused = true;\n triggerEvent.call(player, player.media, 'ended');\n });\n\n player.embed.on('error', detail => {\n player.media.error = detail;\n triggerEvent.call(player, player.media, 'error');\n });\n\n // Rebuild UI\n setTimeout(() => ui.build.call(player), 0);\n },\n};\n\nexport default vimeo;\n","// ==========================================================================\n// YouTube plugin\n// ==========================================================================\n\nimport ui from '../ui';\nimport { createElement, replaceElement, toggleClass } from '../utils/elements';\nimport { triggerEvent } from '../utils/events';\nimport fetch from '../utils/fetch';\nimport is from '../utils/is';\nimport loadImage from '../utils/loadImage';\nimport loadScript from '../utils/loadScript';\nimport { format, generateId } from '../utils/strings';\n\n// Parse YouTube ID from URL\nfunction parseId(url) {\n if (is.empty(url)) {\n return null;\n }\n\n const regex = /^.*(youtu.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|&v=)([^#&?]*).*/;\n return url.match(regex) ? RegExp.$2 : url;\n}\n\n// Set playback state and trigger change (only on actual change)\nfunction assurePlaybackState(play) {\n if (play && !this.embed.hasPlayed) {\n this.embed.hasPlayed = true;\n }\n if (this.media.paused === play) {\n this.media.paused = !play;\n triggerEvent.call(this, this.media, play ? 'play' : 'pause');\n }\n}\n\nconst youtube = {\n setup() {\n // Add embed class for responsive\n toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set aspect ratio\n youtube.setAspectRatio.call(this);\n\n // Setup API\n if (is.object(window.YT) && is.function(window.YT.Player)) {\n youtube.ready.call(this);\n } else {\n // Load the API\n loadScript(this.config.urls.youtube.sdk).catch(error => {\n this.debug.warn('YouTube API failed to load', error);\n });\n\n // Setup callback for the API\n // YouTube has it's own system of course...\n window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];\n\n // Add to queue\n window.onYouTubeReadyCallbacks.push(() => {\n youtube.ready.call(this);\n });\n\n // Set callback to process queue\n window.onYouTubeIframeAPIReady = () => {\n window.onYouTubeReadyCallbacks.forEach(callback => {\n callback();\n });\n };\n }\n },\n\n // Get the media title\n getTitle(videoId) {\n // Try via undocumented API method first\n // This method disappears now and then though...\n // https://github.com/sampotts/plyr/issues/709\n if (is.function(this.embed.getVideoData)) {\n const { title } = this.embed.getVideoData();\n\n if (is.empty(title)) {\n this.config.title = title;\n ui.setTitle.call(this);\n return;\n }\n }\n\n // Or via Google API\n const key = this.config.keys.google;\n if (is.string(key) && !is.empty(key)) {\n const url = format(this.config.urls.youtube.api, videoId, key);\n\n fetch(url)\n .then(result => {\n if (is.object(result)) {\n this.config.title = result.items[0].snippet.title;\n ui.setTitle.call(this);\n }\n })\n .catch(() => {});\n }\n },\n\n // Set aspect ratio\n setAspectRatio() {\n const ratio = this.config.ratio.split(':');\n this.elements.wrapper.style.paddingBottom = `${100 / ratio[0] * ratio[1]}%`;\n },\n\n // API ready\n ready() {\n const player = this;\n\n // Ignore already setup (race condition)\n const currentId = player.media.getAttribute('id');\n if (!is.empty(currentId) && currentId.startsWith('youtube-')) {\n return;\n }\n\n // Get the source URL or ID\n let source = player.media.getAttribute('src');\n\n // Get from <div> if needed\n if (is.empty(source)) {\n source = player.media.getAttribute(this.config.attributes.embed.id);\n }\n\n // Replace the <iframe> with a <div> due to YouTube API issues\n const videoId = parseId(source);\n const id = generateId(player.provider);\n\n // Get poster, if already set\n const { poster } = player;\n\n // Replace media element\n const container = createElement('div', { id, poster });\n player.media = replaceElement(container, player.media);\n\n // Id to poster wrapper\n const posterSrc = format => `https://img.youtube.com/vi/${videoId}/${format}default.jpg`;\n\n // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)\n loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded\n .catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3\n .catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists\n .then(image => ui.setPoster.call(player, image.src))\n .then(posterSrc => {\n // If the image is padded, use background-size \"cover\" instead (like youtube does too with their posters)\n if (!posterSrc.includes('maxres')) {\n player.elements.poster.style.backgroundSize = 'cover';\n }\n })\n .catch(() => {});\n\n // Setup instance\n // https://developers.google.com/youtube/iframe_api_reference\n player.embed = new window.YT.Player(id, {\n videoId,\n playerVars: {\n autoplay: player.config.autoplay ? 1 : 0, // Autoplay\n hl: player.config.hl, // iframe interface language\n controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported\n rel: 0, // No related vids\n showinfo: 0, // Hide info\n iv_load_policy: 3, // Hide annotations\n modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused)\n disablekb: 1, // Disable keyboard as we handle it\n playsinline: 1, // Allow iOS inline playback\n\n // Tracking for stats\n // origin: window ? `${window.location.protocol}//${window.location.host}` : null,\n widget_referrer: window ? window.location.href : null,\n\n // Captions are flaky on YouTube\n cc_load_policy: player.captions.active ? 1 : 0,\n cc_lang_pref: player.config.captions.language,\n },\n events: {\n onError(event) {\n // YouTube may fire onError twice, so only handle it once\n if (!player.media.error) {\n const code = event.data;\n // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError\n const message =\n {\n 2: 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.',\n 5: 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.',\n 100: 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.',\n 101: 'The owner of the requested video does not allow it to be played in embedded players.',\n 150: 'The owner of the requested video does not allow it to be played in embedded players.',\n }[code] || 'An unknown error occured';\n\n player.media.error = { code, message };\n\n triggerEvent.call(player, player.media, 'error');\n }\n },\n onPlaybackRateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current speed\n player.media.playbackRate = instance.getPlaybackRate();\n\n triggerEvent.call(player, player.media, 'ratechange');\n },\n onReady(event) {\n // Bail if onReady has already been called. See issue #1108\n if (is.function(player.media.play)) {\n return;\n }\n // Get the instance\n const instance = event.target;\n\n // Get the title\n youtube.getTitle.call(player, videoId);\n\n // Create a faux HTML5 API using the YouTube API\n player.media.play = () => {\n assurePlaybackState.call(player, true);\n instance.playVideo();\n };\n\n player.media.pause = () => {\n assurePlaybackState.call(player, false);\n instance.pauseVideo();\n };\n\n player.media.stop = () => {\n instance.stopVideo();\n };\n\n player.media.duration = instance.getDuration();\n player.media.paused = true;\n\n // Seeking\n player.media.currentTime = 0;\n Object.defineProperty(player.media, 'currentTime', {\n get() {\n return Number(instance.getCurrentTime());\n },\n set(time) {\n // If paused and never played, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).\n if (player.paused && !player.embed.hasPlayed) {\n player.embed.mute();\n }\n\n // Set seeking state and trigger event\n player.media.seeking = true;\n triggerEvent.call(player, player.media, 'seeking');\n\n // Seek after events sent\n instance.seekTo(time);\n },\n });\n\n // Playback speed\n Object.defineProperty(player.media, 'playbackRate', {\n get() {\n return instance.getPlaybackRate();\n },\n set(input) {\n instance.setPlaybackRate(input);\n },\n });\n\n // Volume\n let { volume } = player.config;\n Object.defineProperty(player.media, 'volume', {\n get() {\n return volume;\n },\n set(input) {\n volume = input;\n instance.setVolume(volume * 100);\n triggerEvent.call(player, player.media, 'volumechange');\n },\n });\n\n // Muted\n let { muted } = player.config;\n Object.defineProperty(player.media, 'muted', {\n get() {\n return muted;\n },\n set(input) {\n const toggle = is.boolean(input) ? input : muted;\n muted = toggle;\n instance[toggle ? 'mute' : 'unMute']();\n triggerEvent.call(player, player.media, 'volumechange');\n },\n });\n\n // Source\n Object.defineProperty(player.media, 'currentSrc', {\n get() {\n return instance.getVideoUrl();\n },\n });\n\n // Ended\n Object.defineProperty(player.media, 'ended', {\n get() {\n return player.currentTime === player.duration;\n },\n });\n\n // Get available speeds\n player.options.speed = instance.getAvailablePlaybackRates();\n\n // Set the tabindex to avoid focus entering iframe\n if (player.supported.ui) {\n player.media.setAttribute('tabindex', -1);\n }\n\n triggerEvent.call(player, player.media, 'timeupdate');\n triggerEvent.call(player, player.media, 'durationchange');\n\n // Reset timer\n clearInterval(player.timers.buffering);\n\n // Setup buffering\n player.timers.buffering = setInterval(() => {\n // Get loaded % from YouTube\n player.media.buffered = instance.getVideoLoadedFraction();\n\n // Trigger progress only when we actually buffer something\n if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {\n triggerEvent.call(player, player.media, 'progress');\n }\n\n // Set last buffer point\n player.media.lastBuffered = player.media.buffered;\n\n // Bail if we're at 100%\n if (player.media.buffered === 1) {\n clearInterval(player.timers.buffering);\n\n // Trigger event\n triggerEvent.call(player, player.media, 'canplaythrough');\n }\n }, 200);\n\n // Rebuild UI\n setTimeout(() => ui.build.call(player), 50);\n },\n onStateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Reset timer\n clearInterval(player.timers.playing);\n\n const seeked = player.media.seeking && [1, 2].includes(event.data);\n\n if (seeked) {\n // Unset seeking and fire seeked event\n player.media.seeking = false;\n triggerEvent.call(player, player.media, 'seeked');\n }\n\n // Handle events\n // -1 Unstarted\n // 0 Ended\n // 1 Playing\n // 2 Paused\n // 3 Buffering\n // 5 Video cued\n switch (event.data) {\n case -1:\n // Update scrubber\n triggerEvent.call(player, player.media, 'timeupdate');\n\n // Get loaded % from YouTube\n player.media.buffered = instance.getVideoLoadedFraction();\n triggerEvent.call(player, player.media, 'progress');\n\n break;\n\n case 0:\n assurePlaybackState.call(player, false);\n\n // YouTube doesn't support loop for a single video, so mimick it.\n if (player.media.loop) {\n // YouTube needs a call to `stopVideo` before playing again\n instance.stopVideo();\n instance.playVideo();\n } else {\n triggerEvent.call(player, player.media, 'ended');\n }\n\n break;\n\n case 1:\n // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)\n if (player.media.paused && !player.embed.hasPlayed) {\n player.media.pause();\n } else {\n assurePlaybackState.call(player, true);\n\n triggerEvent.call(player, player.media, 'playing');\n\n // Poll to get playback progress\n player.timers.playing = setInterval(() => {\n triggerEvent.call(player, player.media, 'timeupdate');\n }, 50);\n\n // Check duration again due to YouTube bug\n // https://github.com/sampotts/plyr/issues/374\n // https://code.google.com/p/gdata-issues/issues/detail?id=8690\n if (player.media.duration !== instance.getDuration()) {\n player.media.duration = instance.getDuration();\n triggerEvent.call(player, player.media, 'durationchange');\n }\n }\n\n break;\n\n case 2:\n // Restore audio (YouTube starts playing on seek if the video hasn't been played yet)\n if (!player.muted) {\n player.embed.unMute();\n }\n assurePlaybackState.call(player, false);\n\n break;\n\n default:\n break;\n }\n\n triggerEvent.call(player, player.elements.container, 'statechange', false, {\n code: event.data,\n });\n },\n },\n });\n },\n};\n\nexport default youtube;\n","// ==========================================================================\n// Plyr Media\n// ==========================================================================\n\nimport html5 from './html5';\nimport vimeo from './plugins/vimeo';\nimport youtube from './plugins/youtube';\nimport { createElement, toggleClass, wrap } from './utils/elements';\n\nconst media = {\n // Setup media\n setup() {\n // If there's no media, bail\n if (!this.media) {\n this.debug.warn('No media element found!');\n return;\n }\n\n // Add type class\n toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', this.type), true);\n\n // Add provider class\n toggleClass(this.elements.container, this.config.classNames.provider.replace('{0}', this.provider), true);\n\n // Add video class for embeds\n // This will require changes if audio embeds are added\n if (this.isEmbed) {\n toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true);\n }\n\n // Inject the player wrapper\n if (this.isVideo) {\n // Create the wrapper div\n this.elements.wrapper = createElement('div', {\n class: this.config.classNames.video,\n });\n\n // Wrap the video in a container\n wrap(this.media, this.elements.wrapper);\n\n // Faux poster container\n this.elements.poster = createElement('div', {\n class: this.config.classNames.poster,\n });\n\n this.elements.wrapper.appendChild(this.elements.poster);\n }\n\n if (this.isHTML5) {\n html5.extend.call(this);\n } else if (this.isYouTube) {\n youtube.setup.call(this);\n } else if (this.isVimeo) {\n vimeo.setup.call(this);\n }\n },\n};\n\nexport default media;\n","// ==========================================================================\n// Advertisement plugin using Google IMA HTML5 SDK\n// Create an account with our ad partner, vi here:\n// https://www.vi.ai/publisher-video-monetization/\n// ==========================================================================\n\n/* global google */\n\nimport { createElement } from '../utils/elements';\nimport { triggerEvent } from '../utils/events';\nimport i18n from '../utils/i18n';\nimport is from '../utils/is';\nimport loadScript from '../utils/loadScript';\nimport { formatTime } from '../utils/time';\nimport { buildUrlParams } from '../utils/urls';\n\nclass Ads {\n /**\n * Ads constructor.\n * @param {object} player\n * @return {Ads}\n */\n constructor(player) {\n this.player = player;\n this.publisherId = player.config.ads.publisherId;\n this.playing = false;\n this.initialized = false;\n this.elements = {\n container: null,\n displayContainer: null,\n };\n this.manager = null;\n this.loader = null;\n this.cuePoints = null;\n this.events = {};\n this.safetyTimer = null;\n this.countdownTimer = null;\n\n // Setup a promise to resolve when the IMA manager is ready\n this.managerPromise = new Promise((resolve, reject) => {\n // The ad is loaded and ready\n this.on('loaded', resolve);\n\n // Ads failed\n this.on('error', reject);\n });\n\n this.load();\n }\n\n get enabled() {\n return (\n this.player.isHTML5 && this.player.isVideo && this.player.config.ads.enabled && !is.empty(this.publisherId)\n );\n }\n\n /**\n * Load the IMA SDK\n */\n load() {\n if (this.enabled) {\n // Check if the Google IMA3 SDK is loaded or load it ourselves\n if (!is.object(window.google) || !is.object(window.google.ima)) {\n loadScript(this.player.config.urls.googleIMA.sdk)\n .then(() => {\n this.ready();\n })\n .catch(() => {\n // Script failed to load or is blocked\n this.trigger('error', new Error('Google IMA SDK failed to load'));\n });\n } else {\n this.ready();\n }\n }\n }\n\n /**\n * Get the ads instance ready\n */\n ready() {\n // Start ticking our safety timer. If the whole advertisement\n // thing doesn't resolve within our set time; we bail\n this.startSafetyTimer(12000, 'ready()');\n\n // Clear the safety timer\n this.managerPromise.then(() => {\n this.clearSafetyTimer('onAdsManagerLoaded()');\n });\n\n // Set listeners on the Plyr instance\n this.listeners();\n\n // Setup the IMA SDK\n this.setupIMA();\n }\n\n // Build the default tag URL\n get tagUrl() {\n const params = {\n AV_PUBLISHERID: '58c25bb0073ef448b1087ad6',\n AV_CHANNELID: '5a0458dc28a06145e4519d21',\n AV_URL: window.location.hostname,\n cb: Date.now(),\n AV_WIDTH: 640,\n AV_HEIGHT: 480,\n AV_CDIM2: this.publisherId,\n };\n\n const base = 'https://go.aniview.com/api/adserver6/vast/';\n\n return `${base}?${buildUrlParams(params)}`;\n }\n\n /**\n * In order for the SDK to display ads for our video, we need to tell it where to put them,\n * so here we define our ad container. This div is set up to render on top of the video player.\n * Using the code below, we tell the SDK to render ads within that div. We also provide a\n * handle to the content video player - the SDK will poll the current time of our player to\n * properly place mid-rolls. After we create the ad display container, we initialize it. On\n * mobile devices, this initialization is done as the result of a user action.\n */\n setupIMA() {\n // Create the container for our advertisements\n this.elements.container = createElement('div', {\n class: this.player.config.classNames.ads,\n });\n this.player.elements.container.appendChild(this.elements.container);\n\n // So we can run VPAID2\n google.ima.settings.setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);\n\n // Set language\n google.ima.settings.setLocale(this.player.config.ads.language);\n\n // We assume the adContainer is the video container of the plyr element\n // that will house the ads\n this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container);\n\n // Request video ads to be pre-loaded\n this.requestAds();\n }\n\n /**\n * Request advertisements\n */\n requestAds() {\n const { container } = this.player.elements;\n\n try {\n // Create ads loader\n this.loader = new google.ima.AdsLoader(this.elements.displayContainer);\n\n // Listen and respond to ads loaded and error events\n this.loader.addEventListener(\n google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,\n event => this.onAdsManagerLoaded(event),\n false,\n );\n this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, error => this.onAdError(error), false);\n\n // Request video ads\n const request = new google.ima.AdsRequest();\n request.adTagUrl = this.tagUrl;\n\n // Specify the linear and nonlinear slot sizes. This helps the SDK\n // to select the correct creative if multiple are returned\n request.linearAdSlotWidth = container.offsetWidth;\n request.linearAdSlotHeight = container.offsetHeight;\n request.nonLinearAdSlotWidth = container.offsetWidth;\n request.nonLinearAdSlotHeight = container.offsetHeight;\n\n // We only overlay ads as we only support video.\n request.forceNonLinearFullSlot = false;\n\n // Mute based on current state\n request.setAdWillPlayMuted(!this.player.muted);\n\n this.loader.requestAds(request);\n } catch (e) {\n this.onAdError(e);\n }\n }\n\n /**\n * Update the ad countdown\n * @param {boolean} start\n */\n pollCountdown(start = false) {\n if (!start) {\n clearInterval(this.countdownTimer);\n this.elements.container.removeAttribute('data-badge-text');\n return;\n }\n\n const update = () => {\n const time = formatTime(Math.max(this.manager.getRemainingTime(), 0));\n const label = `${i18n.get('advertisement', this.player.config)} - ${time}`;\n this.elements.container.setAttribute('data-badge-text', label);\n };\n\n this.countdownTimer = setInterval(update, 100);\n }\n\n /**\n * This method is called whenever the ads are ready inside the AdDisplayContainer\n * @param {Event} adsManagerLoadedEvent\n */\n onAdsManagerLoaded(event) {\n // Load could occur after a source change (race condition)\n if (!this.enabled) {\n return;\n }\n\n // Get the ads manager\n const settings = new google.ima.AdsRenderingSettings();\n\n // Tell the SDK to save and restore content video state on our behalf\n settings.restoreCustomPlaybackStateOnAdBreakComplete = true;\n settings.enablePreloading = true;\n\n // The SDK is polling currentTime on the contentPlayback. And needs a duration\n // so it can determine when to start the mid- and post-roll\n this.manager = event.getAdsManager(this.player, settings);\n\n // Get the cue points for any mid-rolls by filtering out the pre- and post-roll\n this.cuePoints = this.manager.getCuePoints();\n\n // Add advertisement cue's within the time line if available\n if (!is.empty(this.cuePoints)) {\n this.cuePoints.forEach(cuePoint => {\n if (cuePoint !== 0 && cuePoint !== -1 && cuePoint < this.player.duration) {\n const seekElement = this.player.elements.progress;\n\n if (is.element(seekElement)) {\n const cuePercentage = 100 / this.player.duration * cuePoint;\n const cue = createElement('span', {\n class: this.player.config.classNames.cues,\n });\n\n cue.style.left = `${cuePercentage.toString()}%`;\n seekElement.appendChild(cue);\n }\n }\n });\n }\n\n // Set volume to match player\n this.manager.setVolume(this.player.volume);\n\n // Add listeners to the required events\n // Advertisement error events\n this.manager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, error => this.onAdError(error));\n\n // Advertisement regular events\n Object.keys(google.ima.AdEvent.Type).forEach(type => {\n this.manager.addEventListener(google.ima.AdEvent.Type[type], event => this.onAdEvent(event));\n });\n\n // Resolve our adsManager\n this.trigger('loaded');\n }\n\n /**\n * This is where all the event handling takes place. Retrieve the ad from the event. Some\n * events (e.g. ALL_ADS_COMPLETED) don't have the ad object associated\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type\n * @param {Event} event\n */\n onAdEvent(event) {\n const { container } = this.player.elements;\n\n // Retrieve the ad from the event. Some events (e.g. ALL_ADS_COMPLETED)\n // don't have ad object associated\n const ad = event.getAd();\n\n // Proxy event\n const dispatchEvent = type => {\n const event = `ads${type.replace(/_/g, '').toLowerCase()}`;\n triggerEvent.call(this.player, this.player.media, event);\n };\n\n switch (event.type) {\n case google.ima.AdEvent.Type.LOADED:\n // This is the first event sent for an ad - it is possible to determine whether the\n // ad is a video ad or an overlay\n this.trigger('loaded');\n\n // Bubble event\n dispatchEvent(event.type);\n\n // Start countdown\n this.pollCountdown(true);\n\n if (!ad.isLinear()) {\n // Position AdDisplayContainer correctly for overlay\n ad.width = container.offsetWidth;\n ad.height = container.offsetHeight;\n }\n\n // console.info('Ad type: ' + event.getAd().getAdPodInfo().getPodIndex());\n // console.info('Ad time: ' + event.getAd().getAdPodInfo().getTimeOffset());\n break;\n\n case google.ima.AdEvent.Type.ALL_ADS_COMPLETED:\n // All ads for the current videos are done. We can now request new advertisements\n // in case the video is re-played\n\n // Fire event\n dispatchEvent(event.type);\n\n // TODO: Example for what happens when a next video in a playlist would be loaded.\n // So here we load a new video when all ads are done.\n // Then we load new ads within a new adsManager. When the video\n // Is started - after - the ads are loaded, then we get ads.\n // You can also easily test cancelling and reloading by running\n // player.ads.cancel() and player.ads.play from the console I guess.\n // this.player.source = {\n // type: 'video',\n // title: 'View From A Blue Moon',\n // sources: [{\n // src:\n // 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4', type:\n // 'video/mp4', }], poster:\n // 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg', tracks:\n // [ { kind: 'captions', label: 'English', srclang: 'en', src:\n // 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt',\n // default: true, }, { kind: 'captions', label: 'French', srclang: 'fr', src:\n // 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt', }, ],\n // };\n\n // TODO: So there is still this thing where a video should only be allowed to start\n // playing when the IMA SDK is ready or has failed\n\n this.loadAds();\n break;\n\n case google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED:\n // This event indicates the ad has started - the video player can adjust the UI,\n // for example display a pause button and remaining time. Fired when content should\n // be paused. This usually happens right before an ad is about to cover the content\n\n dispatchEvent(event.type);\n\n this.pauseContent();\n\n break;\n\n case google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED:\n // This event indicates the ad has finished - the video player can perform\n // appropriate UI actions, such as removing the timer for remaining time detection.\n // Fired when content should be resumed. This usually happens when an ad finishes\n // or collapses\n\n dispatchEvent(event.type);\n\n this.pollCountdown();\n\n this.resumeContent();\n\n break;\n\n case google.ima.AdEvent.Type.STARTED:\n case google.ima.AdEvent.Type.MIDPOINT:\n case google.ima.AdEvent.Type.COMPLETE:\n case google.ima.AdEvent.Type.IMPRESSION:\n case google.ima.AdEvent.Type.CLICK:\n dispatchEvent(event.type);\n break;\n\n default:\n break;\n }\n }\n\n /**\n * Any ad error handling comes through here\n * @param {Event} event\n */\n onAdError(event) {\n this.cancel();\n this.player.debug.warn('Ads error', event);\n }\n\n /**\n * Setup hooks for Plyr and window events. This ensures\n * the mid- and post-roll launch at the correct time. And\n * resize the advertisement when the player resizes\n */\n listeners() {\n const { container } = this.player.elements;\n let time;\n\n // Add listeners to the required events\n this.player.on('ended', () => {\n this.loader.contentComplete();\n });\n\n this.player.on('seeking', () => {\n time = this.player.currentTime;\n return time;\n });\n\n this.player.on('seeked', () => {\n const seekedTime = this.player.currentTime;\n\n if (is.empty(this.cuePoints)) {\n return;\n }\n\n this.cuePoints.forEach((cuePoint, index) => {\n if (time < cuePoint && cuePoint < seekedTime) {\n this.manager.discardAdBreak();\n this.cuePoints.splice(index, 1);\n }\n });\n });\n\n // Listen to the resizing of the window. And resize ad accordingly\n // TODO: eventually implement ResizeObserver\n window.addEventListener('resize', () => {\n if (this.manager) {\n this.manager.resize(container.offsetWidth, container.offsetHeight, google.ima.ViewMode.NORMAL);\n }\n });\n }\n\n /**\n * Initialize the adsManager and start playing advertisements\n */\n play() {\n const { container } = this.player.elements;\n\n if (!this.managerPromise) {\n this.resumeContent();\n }\n\n // Play the requested advertisement whenever the adsManager is ready\n this.managerPromise\n .then(() => {\n // Initialize the container. Must be done via a user action on mobile devices\n this.elements.displayContainer.initialize();\n\n try {\n if (!this.initialized) {\n // Initialize the ads manager. Ad rules playlist will start at this time\n this.manager.init(container.offsetWidth, container.offsetHeight, google.ima.ViewMode.NORMAL);\n\n // Call play to start showing the ad. Single video and overlay ads will\n // start at this time; the call will be ignored for ad rules\n this.manager.start();\n }\n\n this.initialized = true;\n } catch (adError) {\n // An error may be thrown if there was a problem with the\n // VAST response\n this.onAdError(adError);\n }\n })\n .catch(() => {});\n }\n\n /**\n * Resume our video\n */\n resumeContent() {\n // Hide the advertisement container\n this.elements.container.style.zIndex = '';\n\n // Ad is stopped\n this.playing = false;\n\n // Play our video\n if (this.player.currentTime < this.player.duration) {\n this.player.play();\n }\n }\n\n /**\n * Pause our video\n */\n pauseContent() {\n // Show the advertisement container\n this.elements.container.style.zIndex = 3;\n\n // Ad is playing.\n this.playing = true;\n\n // Pause our video.\n this.player.pause();\n }\n\n /**\n * Destroy the adsManager so we can grab new ads after this. If we don't then we're not\n * allowed to call new ads based on google policies, as they interpret this as an accidental\n * video requests. https://developers.google.com/interactive-\n * media-ads/docs/sdks/android/faq#8\n */\n cancel() {\n // Pause our video\n if (this.initialized) {\n this.resumeContent();\n }\n\n // Tell our instance that we're done for now\n this.trigger('error');\n\n // Re-create our adsManager\n this.loadAds();\n }\n\n /**\n * Re-create our adsManager\n */\n loadAds() {\n // Tell our adsManager to go bye bye\n this.managerPromise\n .then(() => {\n // Destroy our adsManager\n if (this.manager) {\n this.manager.destroy();\n }\n\n // Re-set our adsManager promises\n this.managerPromise = new Promise(resolve => {\n this.on('loaded', resolve);\n this.player.debug.log(this.manager);\n });\n\n // Now request some new advertisements\n this.requestAds();\n })\n .catch(() => {});\n }\n\n /**\n * Handles callbacks after an ad event was invoked\n * @param {string} event - Event type\n */\n trigger(event, ...args) {\n const handlers = this.events[event];\n\n if (is.array(handlers)) {\n handlers.forEach(handler => {\n if (is.function(handler)) {\n handler.apply(this, args);\n }\n });\n }\n }\n\n /**\n * Add event listeners\n * @param {string} event - Event type\n * @param {function} callback - Callback for when event occurs\n * @return {Ads}\n */\n on(event, callback) {\n if (!is.array(this.events[event])) {\n this.events[event] = [];\n }\n\n this.events[event].push(callback);\n\n return this;\n }\n\n /**\n * Setup a safety timer for when the ad network doesn't respond for whatever reason.\n * The advertisement has 12 seconds to get its things together. We stop this timer when the\n * advertisement is playing, or when a user action is required to start, then we clear the\n * timer on ad ready\n * @param {number} time\n * @param {string} from\n */\n startSafetyTimer(time, from) {\n this.player.debug.log(`Safety timer invoked from: ${from}`);\n\n this.safetyTimer = setTimeout(() => {\n this.cancel();\n this.clearSafetyTimer('startSafetyTimer()');\n }, time);\n }\n\n /**\n * Clear our safety timer(s)\n * @param {string} from\n */\n clearSafetyTimer(from) {\n if (!is.nullOrUndefined(this.safetyTimer)) {\n this.player.debug.log(`Safety timer cleared from: ${from}`);\n\n clearTimeout(this.safetyTimer);\n this.safetyTimer = null;\n }\n }\n}\n\nexport default Ads;\n","// ==========================================================================\n// Plyr source update\n// ==========================================================================\n\nimport { providers } from './config/types';\nimport html5 from './html5';\nimport media from './media';\nimport support from './support';\nimport ui from './ui';\nimport { createElement, insertElement, removeElement } from './utils/elements';\nimport is from './utils/is';\nimport { getDeep } from './utils/objects';\n\nconst source = {\n // Add elements to HTML5 media (source, tracks, etc)\n insertElements(type, attributes) {\n if (is.string(attributes)) {\n insertElement(type, this.media, {\n src: attributes,\n });\n } else if (is.array(attributes)) {\n attributes.forEach(attribute => {\n insertElement(type, this.media, attribute);\n });\n }\n },\n\n // Update source\n // Sources are not checked for support so be careful\n change(input) {\n if (!getDeep(input, 'sources.length')) {\n this.debug.warn('Invalid source format');\n return;\n }\n\n // Cancel current network requests\n html5.cancelRequests.call(this);\n\n // Destroy instance and re-setup\n this.destroy.call(\n this,\n () => {\n // Reset quality options\n this.options.quality = [];\n\n // Remove elements\n removeElement(this.media);\n this.media = null;\n\n // Reset class name\n if (is.element(this.elements.container)) {\n this.elements.container.removeAttribute('class');\n }\n\n // Set the type and provider\n const { sources, type } = input;\n const [{ provider = providers.html5, src }] = sources;\n const tagName = provider === 'html5' ? type : 'div';\n const attributes = provider === 'html5' ? {} : { src };\n\n Object.assign(this, {\n provider,\n type,\n // Check for support\n supported: support.check(type, provider, this.config.playsinline),\n // Create new element\n media: createElement(tagName, attributes),\n });\n\n // Inject the new element\n this.elements.container.appendChild(this.media);\n\n // Autoplay the new source?\n if (is.boolean(input.autoplay)) {\n this.config.autoplay = input.autoplay;\n }\n\n // Set attributes for audio and video\n if (this.isHTML5) {\n if (this.config.crossorigin) {\n this.media.setAttribute('crossorigin', '');\n }\n if (this.config.autoplay) {\n this.media.setAttribute('autoplay', '');\n }\n if (!is.empty(input.poster)) {\n this.poster = input.poster;\n }\n if (this.config.loop.active) {\n this.media.setAttribute('loop', '');\n }\n if (this.config.muted) {\n this.media.setAttribute('muted', '');\n }\n if (this.config.playsinline) {\n this.media.setAttribute('playsinline', '');\n }\n }\n\n // Restore class hook\n ui.addStyleHook.call(this);\n\n // Set new sources for html5\n if (this.isHTML5) {\n source.insertElements.call(this, 'source', sources);\n }\n\n // Set video title\n this.config.title = input.title;\n\n // Set up from scratch\n media.setup.call(this);\n\n // HTML5 stuff\n if (this.isHTML5) {\n // Setup captions\n if ('tracks' in input) {\n source.insertElements.call(this, 'track', input.tracks);\n }\n\n // Load HTML5 sources\n this.media.load();\n }\n\n // If HTML5 or embed but not fully supported, setupInterface and call ready now\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n // Setup interface\n ui.build.call(this);\n }\n\n // Update the fullscreen support\n this.fullscreen.update();\n },\n true,\n );\n },\n};\n\nexport default source;\n","// ==========================================================================\n// Plyr\n// plyr.js v3.4.4\n// https://github.com/sampotts/plyr\n// License: The MIT License (MIT)\n// ==========================================================================\n\nimport captions from './captions';\nimport defaults from './config/defaults';\nimport { getProviderByUrl, providers, types } from './config/types';\nimport Console from './console';\nimport controls from './controls';\nimport Fullscreen from './fullscreen';\nimport Listeners from './listeners';\nimport media from './media';\nimport Ads from './plugins/ads';\nimport source from './source';\nimport Storage from './storage';\nimport support from './support';\nimport ui from './ui';\nimport { closest } from './utils/arrays';\nimport { createElement, hasClass, removeElement, replaceElement, toggleClass, wrap } from './utils/elements';\nimport { off, on, once, triggerEvent, unbindListeners } from './utils/events';\nimport is from './utils/is';\nimport loadSprite from './utils/loadSprite';\nimport { cloneDeep, extend } from './utils/objects';\nimport { parseUrl } from './utils/urls';\n\n// Private properties\n// TODO: Use a WeakMap for private globals\n// const globals = new WeakMap();\n\n// Plyr instance\nclass Plyr {\n constructor(target, options) {\n this.timers = {};\n\n // State\n this.ready = false;\n this.loading = false;\n this.failed = false;\n\n // Touch device\n this.touch = support.touch;\n\n // Set the media element\n this.media = target;\n\n // String selector passed\n if (is.string(this.media)) {\n this.media = document.querySelectorAll(this.media);\n }\n\n // jQuery, NodeList or Array passed, use first element\n if ((window.jQuery && this.media instanceof jQuery) || is.nodeList(this.media) || is.array(this.media)) {\n // eslint-disable-next-line\n this.media = this.media[0];\n }\n\n // Set config\n this.config = extend(\n {},\n defaults,\n Plyr.defaults,\n options || {},\n (() => {\n try {\n return JSON.parse(this.media.getAttribute('data-plyr-config'));\n } catch (e) {\n return {};\n }\n })(),\n );\n\n // Elements cache\n this.elements = {\n container: null,\n captions: null,\n buttons: {},\n display: {},\n progress: {},\n inputs: {},\n settings: {\n popup: null,\n menu: null,\n panels: {},\n buttons: {},\n },\n };\n\n // Captions\n this.captions = {\n active: null,\n currentTrack: -1,\n meta: new WeakMap(),\n };\n\n // Fullscreen\n this.fullscreen = {\n active: false,\n };\n\n // Options\n this.options = {\n speed: [],\n quality: [],\n };\n\n // Debugging\n // TODO: move to globals\n this.debug = new Console(this.config.debug);\n\n // Log config options and support\n this.debug.log('Config', this.config);\n this.debug.log('Support', support);\n\n // We need an element to setup\n if (is.nullOrUndefined(this.media) || !is.element(this.media)) {\n this.debug.error('Setup failed: no suitable element passed');\n return;\n }\n\n // Bail if the element is initialized\n if (this.media.plyr) {\n this.debug.warn('Target already setup');\n return;\n }\n\n // Bail if not enabled\n if (!this.config.enabled) {\n this.debug.error('Setup failed: disabled by config');\n return;\n }\n\n // Bail if disabled or no basic support\n // You may want to disable certain UAs etc\n if (!support.check().api) {\n this.debug.error('Setup failed: no support');\n return;\n }\n\n // Cache original element state for .destroy()\n const clone = this.media.cloneNode(true);\n clone.autoplay = false;\n this.elements.original = clone;\n\n // Set media type based on tag or data attribute\n // Supported: video, audio, vimeo, youtube\n const type = this.media.tagName.toLowerCase();\n\n // Embed properties\n let iframe = null;\n let url = null;\n\n // Different setup based on type\n switch (type) {\n case 'div':\n // Find the frame\n iframe = this.media.querySelector('iframe');\n\n // <iframe> type\n if (is.element(iframe)) {\n // Detect provider\n url = parseUrl(iframe.getAttribute('src'));\n this.provider = getProviderByUrl(url.toString());\n\n // Rework elements\n this.elements.container = this.media;\n this.media = iframe;\n\n // Reset classname\n this.elements.container.className = '';\n\n // Get attributes from URL and set config\n if (url.search.length) {\n const truthy = ['1', 'true'];\n\n if (truthy.includes(url.searchParams.get('autoplay'))) {\n this.config.autoplay = true;\n }\n if (truthy.includes(url.searchParams.get('loop'))) {\n this.config.loop.active = true;\n }\n\n // TODO: replace fullscreen.iosNative with this playsinline config option\n // YouTube requires the playsinline in the URL\n if (this.isYouTube) {\n this.config.playsinline = truthy.includes(url.searchParams.get('playsinline'));\n this.config.hl = url.searchParams.get('hl'); // TODO: Should this be setting language?\n } else {\n this.config.playsinline = true;\n }\n }\n } else {\n // <div> with attributes\n this.provider = this.media.getAttribute(this.config.attributes.embed.provider);\n\n // Remove attribute\n this.media.removeAttribute(this.config.attributes.embed.provider);\n }\n\n // Unsupported or missing provider\n if (is.empty(this.provider) || !Object.keys(providers).includes(this.provider)) {\n this.debug.error('Setup failed: Invalid provider');\n return;\n }\n\n // Audio will come later for external providers\n this.type = types.video;\n\n break;\n\n case 'video':\n case 'audio':\n this.type = type;\n this.provider = providers.html5;\n\n // Get config from attributes\n if (this.media.hasAttribute('crossorigin')) {\n this.config.crossorigin = true;\n }\n if (this.media.hasAttribute('autoplay')) {\n this.config.autoplay = true;\n }\n if (this.media.hasAttribute('playsinline') || this.media.hasAttribute('webkit-playsinline')) {\n this.config.playsinline = true;\n }\n if (this.media.hasAttribute('muted')) {\n this.config.muted = true;\n }\n if (this.media.hasAttribute('loop')) {\n this.config.loop.active = true;\n }\n\n break;\n\n default:\n this.debug.error('Setup failed: unsupported type');\n return;\n }\n\n // Check for support again but with type\n this.supported = support.check(this.type, this.provider, this.config.playsinline);\n\n // If no support for even API, bail\n if (!this.supported.api) {\n this.debug.error('Setup failed: no support');\n return;\n }\n\n this.eventListeners = [];\n\n // Create listeners\n this.listeners = new Listeners(this);\n\n // Setup local storage for user settings\n this.storage = new Storage(this);\n\n // Store reference\n this.media.plyr = this;\n\n // Wrap media\n if (!is.element(this.elements.container)) {\n this.elements.container = createElement('div');\n wrap(this.media, this.elements.container);\n }\n\n // Add style hook\n ui.addStyleHook.call(this);\n\n // Setup media\n media.setup.call(this);\n\n // Listen for events if debugging\n if (this.config.debug) {\n on.call(this, this.elements.container, this.config.events.join(' '), event => {\n this.debug.log(`event: ${event.type}`);\n });\n }\n\n // Setup interface\n // If embed but not fully supported, build interface now to avoid flash of controls\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n ui.build.call(this);\n }\n\n // Container listeners\n this.listeners.container();\n\n // Global listeners\n this.listeners.global();\n\n // Setup fullscreen\n this.fullscreen = new Fullscreen(this);\n\n // Setup ads if provided\n if (this.config.ads.enabled) {\n this.ads = new Ads(this);\n }\n\n // Autoplay if required\n if (this.config.autoplay) {\n this.play();\n }\n }\n\n // ---------------------------------------\n // API\n // ---------------------------------------\n\n /**\n * Types and provider helpers\n */\n get isHTML5() {\n return Boolean(this.provider === providers.html5);\n }\n\n get isEmbed() {\n return Boolean(this.isYouTube || this.isVimeo);\n }\n\n get isYouTube() {\n return Boolean(this.provider === providers.youtube);\n }\n\n get isVimeo() {\n return Boolean(this.provider === providers.vimeo);\n }\n\n get isVideo() {\n return Boolean(this.type === types.video);\n }\n\n get isAudio() {\n return Boolean(this.type === types.audio);\n }\n\n /**\n * Play the media, or play the advertisement (if they are not blocked)\n */\n play() {\n if (!is.function(this.media.play)) {\n return null;\n }\n\n // Return the promise (for HTML5)\n return this.media.play();\n }\n\n /**\n * Pause the media\n */\n pause() {\n if (!this.playing || !is.function(this.media.pause)) {\n return;\n }\n\n this.media.pause();\n }\n\n /**\n * Get playing state\n */\n get playing() {\n return Boolean(this.ready && !this.paused && !this.ended);\n }\n\n /**\n * Get paused state\n */\n get paused() {\n return Boolean(this.media.paused);\n }\n\n /**\n * Get stopped state\n */\n get stopped() {\n return Boolean(this.paused && this.currentTime === 0);\n }\n\n /**\n * Get ended state\n */\n get ended() {\n return Boolean(this.media.ended);\n }\n\n /**\n * Toggle playback based on current status\n * @param {boolean} input\n */\n togglePlay(input) {\n // Toggle based on current state if nothing passed\n const toggle = is.boolean(input) ? input : !this.playing;\n\n if (toggle) {\n this.play();\n } else {\n this.pause();\n }\n }\n\n /**\n * Stop playback\n */\n stop() {\n if (this.isHTML5) {\n this.pause();\n this.restart();\n } else if (is.function(this.media.stop)) {\n this.media.stop();\n }\n }\n\n /**\n * Restart playback\n */\n restart() {\n this.currentTime = 0;\n }\n\n /**\n * Rewind\n * @param {number} seekTime - how far to rewind in seconds. Defaults to the config.seekTime\n */\n rewind(seekTime) {\n this.currentTime = this.currentTime - (is.number(seekTime) ? seekTime : this.config.seekTime);\n }\n\n /**\n * Fast forward\n * @param {number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime\n */\n forward(seekTime) {\n this.currentTime = this.currentTime + (is.number(seekTime) ? seekTime : this.config.seekTime);\n }\n\n /**\n * Seek to a time\n * @param {number} input - where to seek to in seconds. Defaults to 0 (the start)\n */\n set currentTime(input) {\n // Bail if media duration isn't available yet\n if (!this.duration) {\n return;\n }\n\n // Validate input\n const inputIsValid = is.number(input) && input > 0;\n\n // Set\n this.media.currentTime = inputIsValid ? Math.min(input, this.duration) : 0;\n\n // Logging\n this.debug.log(`Seeking to ${this.currentTime} seconds`);\n }\n\n /**\n * Get current time\n */\n get currentTime() {\n return Number(this.media.currentTime);\n }\n\n /**\n * Get buffered\n */\n get buffered() {\n const { buffered } = this.media;\n\n // YouTube / Vimeo return a float between 0-1\n if (is.number(buffered)) {\n return buffered;\n }\n\n // HTML5\n // TODO: Handle buffered chunks of the media\n // (i.e. seek to another section buffers only that section)\n if (buffered && buffered.length && this.duration > 0) {\n return buffered.end(0) / this.duration;\n }\n\n return 0;\n }\n\n /**\n * Get seeking status\n */\n get seeking() {\n return Boolean(this.media.seeking);\n }\n\n /**\n * Get the duration of the current media\n */\n get duration() {\n // Faux duration set via config\n const fauxDuration = parseFloat(this.config.duration);\n\n // Media duration can be NaN or Infinity before the media has loaded\n const realDuration = (this.media || {}).duration;\n const duration = !is.number(realDuration) || realDuration === Infinity ? 0 : realDuration;\n\n // If config duration is funky, use regular duration\n return fauxDuration || duration;\n }\n\n /**\n * Set the player volume\n * @param {number} value - must be between 0 and 1. Defaults to the value from local storage and config.volume if not set in storage\n */\n set volume(value) {\n let volume = value;\n const max = 1;\n const min = 0;\n\n if (is.string(volume)) {\n volume = Number(volume);\n }\n\n // Load volume from storage if no value specified\n if (!is.number(volume)) {\n volume = this.storage.get('volume');\n }\n\n // Use config if all else fails\n if (!is.number(volume)) {\n ({ volume } = this.config);\n }\n\n // Maximum is volumeMax\n if (volume > max) {\n volume = max;\n }\n // Minimum is volumeMin\n if (volume < min) {\n volume = min;\n }\n\n // Update config\n this.config.volume = volume;\n\n // Set the player volume\n this.media.volume = volume;\n\n // If muted, and we're increasing volume manually, reset muted state\n if (!is.empty(value) && this.muted && volume > 0) {\n this.muted = false;\n }\n }\n\n /**\n * Get the current player volume\n */\n get volume() {\n return Number(this.media.volume);\n }\n\n /**\n * Increase volume\n * @param {boolean} step - How much to decrease by (between 0 and 1)\n */\n increaseVolume(step) {\n const volume = this.media.muted ? 0 : this.volume;\n this.volume = volume + (is.number(step) ? step : 0);\n }\n\n /**\n * Decrease volume\n * @param {boolean} step - How much to decrease by (between 0 and 1)\n */\n decreaseVolume(step) {\n this.increaseVolume(-step);\n }\n\n /**\n * Set muted state\n * @param {boolean} mute\n */\n set muted(mute) {\n let toggle = mute;\n\n // Load muted state from storage\n if (!is.boolean(toggle)) {\n toggle = this.storage.get('muted');\n }\n\n // Use config if all else fails\n if (!is.boolean(toggle)) {\n toggle = this.config.muted;\n }\n\n // Update config\n this.config.muted = toggle;\n\n // Set mute on the player\n this.media.muted = toggle;\n }\n\n /**\n * Get current muted state\n */\n get muted() {\n return Boolean(this.media.muted);\n }\n\n /**\n * Check if the media has audio\n */\n get hasAudio() {\n // Assume yes for all non HTML5 (as we can't tell...)\n if (!this.isHTML5) {\n return true;\n }\n\n if (this.isAudio) {\n return true;\n }\n\n // Get audio tracks\n return (\n Boolean(this.media.mozHasAudio) ||\n Boolean(this.media.webkitAudioDecodedByteCount) ||\n Boolean(this.media.audioTracks && this.media.audioTracks.length)\n );\n }\n\n /**\n * Set playback speed\n * @param {number} speed - the speed of playback (0.5-2.0)\n */\n set speed(input) {\n let speed = null;\n\n if (is.number(input)) {\n speed = input;\n }\n\n if (!is.number(speed)) {\n speed = this.storage.get('speed');\n }\n\n if (!is.number(speed)) {\n speed = this.config.speed.selected;\n }\n\n // Set min/max\n if (speed < 0.1) {\n speed = 0.1;\n }\n if (speed > 2.0) {\n speed = 2.0;\n }\n\n if (!this.config.speed.options.includes(speed)) {\n this.debug.warn(`Unsupported speed (${speed})`);\n return;\n }\n\n // Update config\n this.config.speed.selected = speed;\n\n // Set media speed\n this.media.playbackRate = speed;\n }\n\n /**\n * Get current playback speed\n */\n get speed() {\n return Number(this.media.playbackRate);\n }\n\n /**\n * Set playback quality\n * Currently HTML5 & YouTube only\n * @param {number} input - Quality level\n */\n set quality(input) {\n const config = this.config.quality;\n const options = this.options.quality;\n\n if (!options.length) {\n return;\n }\n\n let quality = [\n !is.empty(input) && Number(input),\n this.storage.get('quality'),\n config.selected,\n config.default,\n ].find(is.number);\n\n if (!options.includes(quality)) {\n const value = closest(options, quality);\n this.debug.warn(`Unsupported quality option: ${quality}, using ${value} instead`);\n quality = value;\n }\n\n // Update config\n config.selected = quality;\n\n // Set quality\n this.media.quality = quality;\n }\n\n /**\n * Get current quality level\n */\n get quality() {\n return this.media.quality;\n }\n\n /**\n * Toggle loop\n * TODO: Finish fancy new logic. Set the indicator on load as user may pass loop as config\n * @param {boolean} input - Whether to loop or not\n */\n set loop(input) {\n const toggle = is.boolean(input) ? input : this.config.loop.active;\n this.config.loop.active = toggle;\n this.media.loop = toggle;\n\n // Set default to be a true toggle\n /* const type = ['start', 'end', 'all', 'none', 'toggle'].includes(input) ? input : 'toggle';\n\n switch (type) {\n case 'start':\n if (this.config.loop.end && this.config.loop.end <= this.currentTime) {\n this.config.loop.end = null;\n }\n this.config.loop.start = this.currentTime;\n // this.config.loop.indicator.start = this.elements.display.played.value;\n break;\n\n case 'end':\n if (this.config.loop.start >= this.currentTime) {\n return this;\n }\n this.config.loop.end = this.currentTime;\n // this.config.loop.indicator.end = this.elements.display.played.value;\n break;\n\n case 'all':\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n this.config.loop.indicator.start = 0;\n this.config.loop.indicator.end = 100;\n break;\n\n case 'toggle':\n if (this.config.loop.active) {\n this.config.loop.start = 0;\n this.config.loop.end = null;\n } else {\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n }\n break;\n\n default:\n this.config.loop.start = 0;\n this.config.loop.end = null;\n break;\n } */\n }\n\n /**\n * Get current loop state\n */\n get loop() {\n return Boolean(this.media.loop);\n }\n\n /**\n * Set new media source\n * @param {object} input - The new source object (see docs)\n */\n set source(input) {\n source.change.call(this, input);\n }\n\n /**\n * Get current source\n */\n get source() {\n return this.media.currentSrc;\n }\n\n /**\n * Set the poster image for a video\n * @param {input} - the URL for the new poster image\n */\n set poster(input) {\n if (!this.isVideo) {\n this.debug.warn('Poster can only be set for video');\n return;\n }\n\n ui.setPoster.call(this, input, false).catch(() => {});\n }\n\n /**\n * Get the current poster image\n */\n get poster() {\n if (!this.isVideo) {\n return null;\n }\n\n return this.media.getAttribute('poster');\n }\n\n /**\n * Set the autoplay state\n * @param {boolean} input - Whether to autoplay or not\n */\n set autoplay(input) {\n const toggle = is.boolean(input) ? input : this.config.autoplay;\n this.config.autoplay = toggle;\n }\n\n /**\n * Get the current autoplay state\n */\n get autoplay() {\n return Boolean(this.config.autoplay);\n }\n\n /**\n * Toggle captions\n * @param {boolean} input - Whether to enable captions\n */\n toggleCaptions(input) {\n captions.toggle.call(this, input, false);\n }\n\n /**\n * Set the caption track by index\n * @param {number} - Caption index\n */\n set currentTrack(input) {\n captions.set.call(this, input, false);\n }\n\n /**\n * Get the current caption track index (-1 if disabled)\n */\n get currentTrack() {\n const { toggled, currentTrack } = this.captions;\n return toggled ? currentTrack : -1;\n }\n\n /**\n * Set the wanted language for captions\n * Since tracks can be added later it won't update the actual caption track until there is a matching track\n * @param {string} - Two character ISO language code (e.g. EN, FR, PT, etc)\n */\n set language(input) {\n captions.setLanguage.call(this, input, false);\n }\n\n /**\n * Get the current track's language\n */\n get language() {\n return (captions.getCurrentTrack.call(this) || {}).language;\n }\n\n /**\n * Toggle picture-in-picture playback on WebKit/MacOS\n * TODO: update player with state, support, enabled\n * TODO: detect outside changes\n */\n set pip(input) {\n const states = {\n pip: 'picture-in-picture',\n inline: 'inline',\n };\n\n // Bail if no support\n if (!support.pip) {\n return;\n }\n\n // Toggle based on current state if not passed\n const toggle = is.boolean(input) ? input : this.pip === states.inline;\n\n // Toggle based on current state\n this.media.webkitSetPresentationMode(toggle ? states.pip : states.inline);\n }\n\n /**\n * Get the current picture-in-picture state\n */\n get pip() {\n if (!support.pip) {\n return null;\n }\n\n return this.media.webkitPresentationMode;\n }\n\n /**\n * Trigger the airplay dialog\n * TODO: update player with state, support, enabled\n */\n airplay() {\n // Show dialog if supported\n if (support.airplay) {\n this.media.webkitShowPlaybackTargetPicker();\n }\n }\n\n /**\n * Toggle the player controls\n * @param {boolean} [toggle] - Whether to show the controls\n */\n toggleControls(toggle) {\n // Don't toggle if missing UI support or if it's audio\n if (this.supported.ui && !this.isAudio) {\n // Get state before change\n const isHidden = hasClass(this.elements.container, this.config.classNames.hideControls);\n\n // Negate the argument if not undefined since adding the class to hides the controls\n const force = typeof toggle === 'undefined' ? undefined : !toggle;\n\n // Apply and get updated state\n const hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force);\n\n // Close menu\n if (hiding && this.config.controls.includes('settings') && !is.empty(this.config.settings)) {\n controls.toggleMenu.call(this, false);\n }\n\n // Trigger event on change\n if (hiding !== isHidden) {\n const eventName = hiding ? 'controlshidden' : 'controlsshown';\n triggerEvent.call(this, this.media, eventName);\n }\n\n return !hiding;\n }\n\n return false;\n }\n\n /**\n * Add event listeners\n * @param {string} event - Event type\n * @param {function} callback - Callback for when event occurs\n */\n on(event, callback) {\n on.call(this, this.elements.container, event, callback);\n }\n\n /**\n * Add event listeners once\n * @param {string} event - Event type\n * @param {function} callback - Callback for when event occurs\n */\n once(event, callback) {\n once.call(this, this.elements.container, event, callback);\n }\n\n /**\n * Remove event listeners\n * @param {string} event - Event type\n * @param {function} callback - Callback for when event occurs\n */\n off(event, callback) {\n off(this.elements.container, event, callback);\n }\n\n /**\n * Destroy an instance\n * Event listeners are removed when elements are removed\n * http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory\n * @param {function} callback - Callback for when destroy is complete\n * @param {boolean} soft - Whether it's a soft destroy (for source changes etc)\n */\n destroy(callback, soft = false) {\n if (!this.ready) {\n return;\n }\n\n const done = () => {\n // Reset overflow (incase destroyed while in fullscreen)\n document.body.style.overflow = '';\n\n // GC for embed\n this.embed = null;\n\n // If it's a soft destroy, make minimal changes\n if (soft) {\n if (Object.keys(this.elements).length) {\n // Remove elements\n removeElement(this.elements.buttons.play);\n removeElement(this.elements.captions);\n removeElement(this.elements.controls);\n removeElement(this.elements.wrapper);\n\n // Clear for GC\n this.elements.buttons.play = null;\n this.elements.captions = null;\n this.elements.controls = null;\n this.elements.wrapper = null;\n }\n\n // Callback\n if (is.function(callback)) {\n callback();\n }\n } else {\n // Unbind listeners\n unbindListeners.call(this);\n\n // Replace the container with the original element provided\n replaceElement(this.elements.original, this.elements.container);\n\n // Event\n triggerEvent.call(this, this.elements.original, 'destroyed', true);\n\n // Callback\n if (is.function(callback)) {\n callback.call(this.elements.original);\n }\n\n // Reset state\n this.ready = false;\n\n // Clear for garbage collection\n setTimeout(() => {\n this.elements = null;\n this.media = null;\n }, 200);\n }\n };\n\n // Stop playback\n this.stop();\n\n // Provider specific stuff\n if (this.isHTML5) {\n // Clear timeout\n clearTimeout(this.timers.loading);\n\n // Restore native video controls\n ui.toggleNativeControls.call(this, true);\n\n // Clean up\n done();\n } else if (this.isYouTube) {\n // Clear timers\n clearInterval(this.timers.buffering);\n clearInterval(this.timers.playing);\n\n // Destroy YouTube API\n if (this.embed !== null && is.function(this.embed.destroy)) {\n this.embed.destroy();\n }\n\n // Clean up\n done();\n } else if (this.isVimeo) {\n // Destroy Vimeo API\n // then clean up (wait, to prevent postmessage errors)\n if (this.embed !== null) {\n this.embed.unload().then(done);\n }\n\n // Vimeo does not always return\n setTimeout(done, 200);\n }\n }\n\n /**\n * Check for support for a mime type (HTML5 only)\n * @param {string} type - Mime type\n */\n supports(type) {\n return support.mime.call(this, type);\n }\n\n /**\n * Check for support\n * @param {string} type - Player type (audio/video)\n * @param {string} provider - Provider (html5/youtube/vimeo)\n * @param {bool} inline - Where player has `playsinline` sttribute\n */\n static supported(type, provider, inline) {\n return support.check(type, provider, inline);\n }\n\n /**\n * Load an SVG sprite into the page\n * @param {string} url - URL for the SVG sprite\n * @param {string} [id] - Unique ID\n */\n static loadSprite(url, id) {\n return loadSprite(url, id);\n }\n\n /**\n * Setup multiple instances\n * @param {*} selector\n * @param {object} options\n */\n static setup(selector, options = {}) {\n let targets = null;\n\n if (is.string(selector)) {\n targets = Array.from(document.querySelectorAll(selector));\n } else if (is.nodeList(selector)) {\n targets = Array.from(selector);\n } else if (is.array(selector)) {\n targets = selector.filter(is.element);\n }\n\n if (is.empty(targets)) {\n return null;\n }\n\n return targets.map(t => new Plyr(t, options));\n }\n}\n\nPlyr.defaults = cloneDeep(defaults);\n\nexport default Plyr;\n"]}
\ No newline at end of file +{"version":3,"sources":["src/js/utils/is.js","src/js/utils/events.js","src/js/utils/elements.js","src/js/utils/animation.js","src/js/utils/browser.js","src/js/support.js","src/js/html5.js","src/js/utils/arrays.js","src/js/utils/objects.js","src/js/utils/strings.js","src/js/utils/i18n.js","src/js/storage.js","src/js/utils/fetch.js","src/js/utils/loadSprite.js","src/js/utils/time.js","src/js/controls.js","src/js/utils/urls.js","src/js/captions.js","src/js/config/defaults.js","src/js/config/types.js","src/js/console.js","src/js/fullscreen.js","src/js/utils/loadImage.js","src/js/ui.js","src/js/listeners.js","node_modules/loadjs/dist/loadjs.umd.js","src/js/utils/loadScript.js","src/js/plugins/vimeo.js","src/js/plugins/youtube.js","src/js/media.js","src/js/plugins/ads.js","src/js/source.js","src/js/plyr.js"],"names":["getConstructor","input","constructor","instanceOf","Boolean","isNullOrUndefined","isObject","Object","isString","String","isArray","Array","isNodeList","NodeList","isEmpty","length","keys","is","nullOrUndefined","object","number","Number","isNaN","string","boolean","function","Function","array","weakMap","WeakMap","nodeList","element","Element","textNode","Text","event","Event","keyboardEvent","KeyboardEvent","cue","window","TextTrackCue","VTTCue","track","TextTrack","kind","url","URL","startsWith","concat","hostname","e","empty","supportsPassiveListeners","supported","options","defineProperty","get","addEventListener","removeEventListener","toggleListener","callback","_this","this","toggle","arguments","undefined","passive","capture","events","split","forEach","type","eventListeners","push","on","call","off","once","onceCallback","_len","args","_key","apply","triggerEvent","bubbles","detail","CustomEvent","assign","plyr","dispatchEvent","wrap","elements","wrapper","targets","from","reverse","index","child","cloneNode","parent","parentNode","sibling","nextSibling","appendChild","insertBefore","setAttributes","attributes","entries","filter","_ref","value","_slicedToArray","_ref3","_ref4","key","setAttribute","createElement","text","document","innerText","insertElement","removeElement","removeChild","emptyElement","childNodes","lastChild","replaceElement","newChild","oldChild","replaceChild","getAttributesFromSelector","sel","existingAttributes","existing","s","selector","trim","className","replace","parts","charAt","class","id","toggleHidden","hidden","hide","removeAttribute","toggleClass","force","map","method","classList","contains","hasClass","matches","prototype","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","querySelectorAll","includes","getElements","container","getElement","querySelector","setFocus","tabFocus","focus","config","classNames","transitionEndEvent","WebkitTransition","MozTransition","OTransition","transition","find","style","repaint","setTimeout","offsetHeight","range","browser","isIE","documentMode","isWebkit","documentElement","test","navigator","userAgent","isIPhone","platform","isIos","defaultCodecs","audio/ogg","audio/wav","video/webm","video/mp4","video/ogg","support","audio","video","check","provider","playsinline","canPlayInline","api","ui","rangeInput","pip","webkitSetPresentationMode","airplay","WebKitPlaybackTargetAvailabilityEvent","mime","inputType","mediaType","isHTML5","media","canPlayType","err","textTracks","touch","transitions","reducedMotion","matchMedia","html5","getSources","source","getAttribute","getQualityOptions","extend","player","set","_player$media","currentTime","paused","preload","readyState","src","play","load","quality","storage","cancelRequests","blankVideo","debug","log","dedupe","item","indexOf","getDeep","path","reduce","obj","target","sources","shift","_defineProperty","format","toString","match","i","replaceAll","RegExp","toTitleCase","toUpperCase","substr","toLowerCase","toCamelCase","toPascalCase","slice","getHTML","innerHTML","resources","vimeo","youtube","i18n","{seektime}","seekTime","{title}","title","_ref2","Storage","_classCallCheck","enabled","store","localStorage","getItem","json","JSON","parse","setItem","stringify","removeItem","fetch","responseType","Promise","resolve","reject","request","XMLHttpRequest","responseText","response","Error","status","open","send","loadSprite","hasId","exists","getElementById","update","data","body","insertAdjacentElement","useStorage","cached","content","then","result","catch","getHours","parseInt","getMinutes","getSeconds","formatTime","time","displayHours","inverted","hours","mins","secs","controls","getIconUrl","cors","iconUrl","location","host","svg4everybody","findElements","selectors","buttons","pause","restart","rewind","fastForward","mute","settings","captions","fullscreen","progress","inputs","seek","volume","display","buffer","duration","seekTooltip","tooltip","error","warn","toggleNativeControls","createIcon","iconPath","iconPrefix","icon","createElementNS","role","focusable","use","setAttributeNS","createLabel","attr","join","createBadge","badge","menu","createButton","buttonType","props","label","labelPressed","iconPressed","control","button","createRange","min","max","step","autocomplete","aria-label","aria-valuemin","aria-valuemax","aria-valuenow","updateRangeFill","createProgress","aria-hidden","suffixKey","played","suffix","createTime","bindMenuItemShortcuts","menuItem","which","preventDefault","stopPropagation","isRadioButton","showMenuPanel","nextElementSibling","firstElementChild","previousElementSibling","lastElementChild","focusFirstMenuItem","createMenuItem","_this2","list","_ref$badge","_ref$checked","checked","aria-checked","flex","enumerable","children","node","listeners","bind","currentTrack","speed","parseFloat","updateTimeDisplay","updateVolume","setRange","muted","pressed","updateProgress","_this3","current","toFixed","getElementsByTagName","nodeValue","setProgress","buffered","percent","setProperty","updateSeekTooltip","_this4","tooltips","clientRect","getBoundingClientRect","visible","width","pageX","left","timeUpdate","invert","invertTime","seeking","durationUpdate","Math","pow","hasDuration","displayDuration","toggleMenuButton","setting","updateSetting","pane","panels","default","getLabel","setQualityMenu","_this5","checkMenu","sort","a","b","sorting","getBadge","setCaptionsMenu","_this6","tracks","getTracks","toggled","language","unshift","setSpeedMenu","_this7","isVimeo","values","some","popup","firstItem","toggleMenu","show","isMenuItem","getMenuSize","tab","clone","position","opacity","scrollWidth","height","scrollHeight","_this8","size","restore","propertyName","setDownloadLink","download","create","_this9","aria-haspopup","aria-controls","aria-expanded","inner","home","backButton","href","urls","isEmbed","inject","_this10","floor","random","seektime","addProperty","controlPressed","_this$config","labels","parseUrl","parser","buildUrlParams","params","URLSearchParams","setup","isVideo","isYouTube","protocol","blob","createObjectURL","languages","userLanguage","active","trackEvents","_this$captions","meta","currentTrackNode","languageExists","mode","updateCues","setLanguage","activeClass","findTrack","_toConsumableArray","embed","enableTextTrack","has","sortIsDefault","sorted","every","getCurrentTrack","cues","activeCues","getCueAsHTML","cueText","caption","defaults","autoplay","autopause","toggleInvert","ratio","clickToPlay","hideControls","resetOnEnd","disableContextMenu","loop","selected","keyboard","focused","global","fallback","iosNative","seekLabel","unmute","enableCaptions","disableCaptions","enterFullscreen","exitFullscreen","frameTitle","menuBack","normal","start","end","all","reset","disabled","advertisement","qualityBadge","2160","1440","1080","720","576","480","sdk","iframe","googleIMA","editable","embedContainer","poster","posterEnabled","ads","playing","stopped","loading","hover","isTouch","uiSupported","noTransition","google","publisherId","providers","types","noop","Console","console","onChange","first","last","keyCode","activeElement","shiftKey","toggleFallback","scrollPosition","x","scrollX","y","scrollY","scrollTo","overflow","viewport","head","property","hasProperty","cleanupViewport","part","Fullscreen","prefix","native","webkitEnterFullscreen","requestFullscreen","webkitExitFullscreen","action","cancelFullScreen","exit","enter","fullscreenElement","fullscreenEnabled","webkitFullscreenEnabled","mozFullScreenEnabled","msFullscreenEnabled","pre","loadImage","minWidth","image","Image","handler","onload","onerror","naturalWidth","addStyleHook","build","checkPlaying","ready","setTitle","setPoster","togglePoster","enable","backgroundImage","backgroundSize","toggleControls","checkLoading","clearTimeout","timers","recentTouchSeek","lastSeekTime","Date","now","Listeners","lastKey","focusTimer","lastKeyDown","handleKey","setTabFocus","firstTouch","code","repeat","altKey","ctrlKey","metaKey","togglePlay","increaseVolume","decreaseVolume","forward","toggleCaptions","timeStamp","wasKeyDown","delay","hasAudio","initialized","managerPromise","isAudio","ended","proxyEvents","_event$detail","defaultHandler","customHandlerKey","customHandler","returned","hasCustomHandler","proxy","inputEvent","rect","currentTarget","hasAttribute","done","seekTo","webkitDirectionInvertedFromDevice","_map2","deltaX","deltaY","direction","sign","abs","factory","devnull","bundleIdCache","bundleResultCache","bundleCallbackQueue","publish","bundleId","pathsNotFound","q","splice","executeCallbacks","depsNotFound","success","loadFile","callbackFn","numTries","isCss","doc","async","maxTries","numRetries","beforeCallbackFn","before","pathStripped","rel","onbeforeload","ev","sheet","cssText","defaultPrevented","loadjs","paths","arg1","arg2","fn","numWaiting","loadFiles","deps","bundleIds","r","subscribe","isDefined","module","exports","loadScript","assurePlaybackState","hasPlayed","setAspectRatio","Vimeo","_split2","padding","paddingBottom","offset","transform","byline","portrait","transparent","gesture","$2","thumbnail_large","pathname","Player","disableTextTrack","stop","restorePause","setVolume","setCurrentTime","setPlaybackRate","name","currentSrc","setLoop","getVideoUrl","getVideoWidth","getVideoHeight","dimensions","getRatio","w","h","getAspectRatio","setAutopause","state","getVideoTitle","getCurrentTime","getDuration","getTextTracks","_ref$cues","strippedCues","fragment","createDocumentFragment","firstChild","getPaused","seconds","YT","onYouTubeReadyCallbacks","onYouTubeIframeAPIReady","getTitle","videoId","getVideoData","items","snippet","currentId","posterSrc","playerVars","hl","showinfo","iv_load_policy","modestbranding","disablekb","widget_referrer","cc_load_policy","cc_lang_pref","onError","message","2","5","100","101","150","onPlaybackRateChange","instance","playbackRate","getPlaybackRate","onReady","playVideo","pauseVideo","stopVideo","getAvailablePlaybackRates","clearInterval","buffering","setInterval","getVideoLoadedFraction","lastBuffered","onStateChange","unMute","Ads","displayContainer","manager","loader","cuePoints","safetyTimer","countdownTimer","ima","trigger","startSafetyTimer","clearSafetyTimer","setupIMA","setVpaidMode","ImaSdkSettings","VpaidMode","ENABLED","setLocale","AdDisplayContainer","requestAds","AdsLoader","AdsManagerLoadedEvent","Type","ADS_MANAGER_LOADED","onAdsManagerLoaded","AdErrorEvent","AD_ERROR","onAdError","AdsRequest","adTagUrl","tagUrl","linearAdSlotWidth","offsetWidth","linearAdSlotHeight","nonLinearAdSlotWidth","nonLinearAdSlotHeight","forceNonLinearFullSlot","setAdWillPlayMuted","getRemainingTime","AdsRenderingSettings","restoreCustomPlaybackStateOnAdBreakComplete","enablePreloading","getAdsManager","getCuePoints","cuePoint","seekElement","cuePercentage","AdEvent","onAdEvent","ad","getAd","LOADED","pollCountdown","isLinear","ALL_ADS_COMPLETED","loadAds","CONTENT_PAUSE_REQUESTED","pauseContent","CONTENT_RESUME_REQUESTED","resumeContent","STARTED","MIDPOINT","COMPLETE","IMPRESSION","CLICK","cancel","contentComplete","seekedTime","discardAdBreak","resize","ViewMode","NORMAL","initialize","init","adError","zIndex","destroy","_this11","handlers","_this12","AV_PUBLISHERID","AV_CHANNELID","AV_URL","cb","AV_WIDTH","AV_HEIGHT","AV_CDIM2","insertElements","attribute","change","_sources$","_sources$$provider","tagName","crossorigin","Plyr","failed","jQuery","original","getProviderByUrl","search","truthy","searchParams","webkitShowPlaybackTargetPicker","isHidden","hiding","eventName","soft","unload","inputIsValid","fauxDuration","realDuration","Infinity","mozHasAudio","webkitAudioDecodedByteCount","audioTracks","prev","curr","closest","states","webkitPresentationMode","inline","t"],"mappings":"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","file":"plyr.min.js","sourcesContent":["// ==========================================================================\n// Type checking utils\n// ==========================================================================\n\nconst getConstructor = input => (input !== null && typeof input !== 'undefined' ? input.constructor : null);\nconst instanceOf = (input, constructor) => Boolean(input && constructor && input instanceof constructor);\nconst isNullOrUndefined = input => input === null || typeof input === 'undefined';\nconst isObject = input => getConstructor(input) === Object;\nconst isNumber = input => getConstructor(input) === Number && !Number.isNaN(input);\nconst isString = input => getConstructor(input) === String;\nconst isBoolean = input => getConstructor(input) === Boolean;\nconst isFunction = input => getConstructor(input) === Function;\nconst isArray = input => Array.isArray(input);\nconst isWeakMap = input => instanceOf(input, WeakMap);\nconst isNodeList = input => instanceOf(input, NodeList);\nconst isElement = input => instanceOf(input, Element);\nconst isTextNode = input => getConstructor(input) === Text;\nconst isEvent = input => instanceOf(input, Event);\nconst isKeyboardEvent = input => instanceOf(input, KeyboardEvent);\nconst isCue = input => instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);\nconst isTrack = input => instanceOf(input, TextTrack) || (!isNullOrUndefined(input) && isString(input.kind));\n\nconst isEmpty = input =>\n isNullOrUndefined(input) ||\n ((isString(input) || isArray(input) || isNodeList(input)) && !input.length) ||\n (isObject(input) && !Object.keys(input).length);\n\nconst isUrl = input => {\n // Accept a URL object\n if (instanceOf(input, window.URL)) {\n return true;\n }\n\n // Must be string from here\n if (!isString(input)) {\n return false;\n }\n\n // Add the protocol if required\n let string = input;\n if (!input.startsWith('http://') || !input.startsWith('https://')) {\n string = `http://${input}`;\n }\n\n try {\n return !isEmpty(new URL(string).hostname);\n } catch (e) {\n return false;\n }\n};\n\nexport default {\n nullOrUndefined: isNullOrUndefined,\n object: isObject,\n number: isNumber,\n string: isString,\n boolean: isBoolean,\n function: isFunction,\n array: isArray,\n weakMap: isWeakMap,\n nodeList: isNodeList,\n element: isElement,\n textNode: isTextNode,\n event: isEvent,\n keyboardEvent: isKeyboardEvent,\n cue: isCue,\n track: isTrack,\n url: isUrl,\n empty: isEmpty,\n};\n","// ==========================================================================\n// Event utils\n// ==========================================================================\n\nimport is from './is';\n\n// Check for passive event listener support\n// https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n// https://www.youtube.com/watch?v=NPM6172J22g\nconst supportsPassiveListeners = (() => {\n // Test via a getter in the options object to see if the passive property is accessed\n let supported = false;\n try {\n const options = Object.defineProperty({}, 'passive', {\n get() {\n supported = true;\n return null;\n },\n });\n window.addEventListener('test', null, options);\n window.removeEventListener('test', null, options);\n } catch (e) {\n // Do nothing\n }\n\n return supported;\n})();\n\n// Toggle event listener\nexport function toggleListener(element, event, callback, toggle = false, passive = true, capture = false) {\n // Bail if no element, event, or callback\n if (!element || !('addEventListener' in element) || is.empty(event) || !is.function(callback)) {\n return;\n }\n\n // Allow multiple events\n const events = event.split(' ');\n\n // Build options\n // Default to just the capture boolean for browsers with no passive listener support\n let options = capture;\n\n // If passive events listeners are supported\n if (supportsPassiveListeners) {\n options = {\n // Whether the listener can be passive (i.e. default never prevented)\n passive,\n // Whether the listener is a capturing listener or not\n capture,\n };\n }\n\n // If a single node is passed, bind the event listener\n events.forEach(type => {\n if (this && this.eventListeners && toggle) {\n // Cache event listener\n this.eventListeners.push({ element, type, callback, options });\n }\n\n element[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);\n });\n}\n\n// Bind event handler\nexport function on(element, events = '', callback, passive = true, capture = false) {\n toggleListener.call(this, element, events, callback, true, passive, capture);\n}\n\n// Unbind event handler\nexport function off(element, events = '', callback, passive = true, capture = false) {\n toggleListener.call(this, element, events, callback, false, passive, capture);\n}\n\n// Bind once-only event handler\nexport function once(element, events = '', callback, passive = true, capture = false) {\n function onceCallback(...args) {\n off(element, events, onceCallback, passive, capture);\n callback.apply(this, args);\n }\n\n toggleListener.call(this, element, events, onceCallback, true, passive, capture);\n}\n\n// Trigger event\nexport function triggerEvent(element, type = '', bubbles = false, detail = {}) {\n // Bail if no element\n if (!is.element(element) || is.empty(type)) {\n return;\n }\n\n // Create and dispatch the event\n const event = new CustomEvent(type, {\n bubbles,\n detail: Object.assign({}, detail, {\n plyr: this,\n }),\n });\n\n // Dispatch the event\n element.dispatchEvent(event);\n}\n\n// Unbind all cached event listeners\nexport function unbindListeners() {\n if (this && this.eventListeners) {\n this.eventListeners.forEach(item => {\n const { element, type, callback, options } = item;\n element.removeEventListener(type, callback, options);\n });\n\n this.eventListeners = [];\n }\n}\n\n// Run method when / if player is ready\nexport function ready() {\n return new Promise(\n resolve => (this.ready ? setTimeout(resolve, 0) : on.call(this, this.elements.container, 'ready', resolve)),\n ).then(() => {});\n}\n","// ==========================================================================\n// Element utils\n// ==========================================================================\n\nimport { toggleListener } from './events';\nimport is from './is';\n\n// Wrap an element\nexport function wrap(elements, wrapper) {\n // Convert `elements` to an array, if necessary.\n const targets = elements.length ? elements : [elements];\n\n // Loops backwards to prevent having to clone the wrapper on the\n // first element (see `child` below).\n Array.from(targets)\n .reverse()\n .forEach((element, index) => {\n const child = index > 0 ? wrapper.cloneNode(true) : wrapper;\n\n // Cache the current parent and sibling.\n const parent = element.parentNode;\n const sibling = element.nextSibling;\n\n // Wrap the element (is automatically removed from its current\n // parent).\n child.appendChild(element);\n\n // If the element had a sibling, insert the wrapper before\n // the sibling to maintain the HTML structure; otherwise, just\n // append it to the parent.\n if (sibling) {\n parent.insertBefore(child, sibling);\n } else {\n parent.appendChild(child);\n }\n });\n}\n\n// Set attributes\nexport function setAttributes(element, attributes) {\n if (!is.element(element) || is.empty(attributes)) {\n return;\n }\n\n // Assume null and undefined attributes should be left out,\n // Setting them would otherwise convert them to \"null\" and \"undefined\"\n Object.entries(attributes)\n .filter(([, value]) => !is.nullOrUndefined(value))\n .forEach(([key, value]) => element.setAttribute(key, value));\n}\n\n// Create a DocumentFragment\nexport function createElement(type, attributes, text) {\n // Create a new <element>\n const element = document.createElement(type);\n\n // Set all passed attributes\n if (is.object(attributes)) {\n setAttributes(element, attributes);\n }\n\n // Add text node\n if (is.string(text)) {\n element.innerText = text;\n }\n\n // Return built element\n return element;\n}\n\n// Inaert an element after another\nexport function insertAfter(element, target) {\n if (!is.element(element) || !is.element(target)) {\n return;\n }\n\n target.parentNode.insertBefore(element, target.nextSibling);\n}\n\n// Insert a DocumentFragment\nexport function insertElement(type, parent, attributes, text) {\n if (!is.element(parent)) {\n return;\n }\n\n parent.appendChild(createElement(type, attributes, text));\n}\n\n// Remove element(s)\nexport function removeElement(element) {\n if (is.nodeList(element) || is.array(element)) {\n Array.from(element).forEach(removeElement);\n return;\n }\n\n if (!is.element(element) || !is.element(element.parentNode)) {\n return;\n }\n\n element.parentNode.removeChild(element);\n}\n\n// Remove all child elements\nexport function emptyElement(element) {\n if (!is.element(element)) {\n return;\n }\n\n let { length } = element.childNodes;\n\n while (length > 0) {\n element.removeChild(element.lastChild);\n length -= 1;\n }\n}\n\n// Replace element\nexport function replaceElement(newChild, oldChild) {\n if (!is.element(oldChild) || !is.element(oldChild.parentNode) || !is.element(newChild)) {\n return null;\n }\n\n oldChild.parentNode.replaceChild(newChild, oldChild);\n\n return newChild;\n}\n\n// Get an attribute object from a string selector\nexport function getAttributesFromSelector(sel, existingAttributes) {\n // For example:\n // '.test' to { class: 'test' }\n // '#test' to { id: 'test' }\n // '[data-test=\"test\"]' to { 'data-test': 'test' }\n\n if (!is.string(sel) || is.empty(sel)) {\n return {};\n }\n\n const attributes = {};\n const existing = existingAttributes;\n\n sel.split(',').forEach(s => {\n // Remove whitespace\n const selector = s.trim();\n const className = selector.replace('.', '');\n const stripped = selector.replace(/[[\\]]/g, '');\n\n // Get the parts and value\n const parts = stripped.split('=');\n const key = parts[0];\n const value = parts.length > 1 ? parts[1].replace(/[\"']/g, '') : '';\n\n // Get the first character\n const start = selector.charAt(0);\n\n switch (start) {\n case '.':\n // Add to existing classname\n if (is.object(existing) && is.string(existing.class)) {\n existing.class += ` ${className}`;\n }\n\n attributes.class = className;\n break;\n\n case '#':\n // ID selector\n attributes.id = selector.replace('#', '');\n break;\n\n case '[':\n // Attribute selector\n attributes[key] = value;\n\n break;\n\n default:\n break;\n }\n });\n\n return attributes;\n}\n\n// Toggle hidden\nexport function toggleHidden(element, hidden) {\n if (!is.element(element)) {\n return;\n }\n\n let hide = hidden;\n\n if (!is.boolean(hide)) {\n hide = !element.hidden;\n }\n\n if (hide) {\n element.setAttribute('hidden', '');\n } else {\n element.removeAttribute('hidden');\n }\n}\n\n// Mirror Element.classList.toggle, with IE compatibility for \"force\" argument\nexport function toggleClass(element, className, force) {\n if (is.nodeList(element)) {\n return Array.from(element).map(e => toggleClass(e, className, force));\n }\n\n if (is.element(element)) {\n let method = 'toggle';\n if (typeof force !== 'undefined') {\n method = force ? 'add' : 'remove';\n }\n\n element.classList[method](className);\n return element.classList.contains(className);\n }\n\n return false;\n}\n\n// Has class name\nexport function hasClass(element, className) {\n return is.element(element) && element.classList.contains(className);\n}\n\n// Element matches selector\nexport function matches(element, selector) {\n const prototype = { Element };\n\n function match() {\n return Array.from(document.querySelectorAll(selector)).includes(this);\n }\n\n const matches =\n prototype.matches ||\n prototype.webkitMatchesSelector ||\n prototype.mozMatchesSelector ||\n prototype.msMatchesSelector ||\n match;\n\n return matches.call(element, selector);\n}\n\n// Find all elements\nexport function getElements(selector) {\n return this.elements.container.querySelectorAll(selector);\n}\n\n// Find a single element\nexport function getElement(selector) {\n return this.elements.container.querySelector(selector);\n}\n\n// Trap focus inside container\nexport function trapFocus(element = null, toggle = false) {\n if (!is.element(element)) {\n return;\n }\n\n const focusable = getElements.call(this, 'button:not(:disabled), input:not(:disabled), [tabindex]');\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n const trap = event => {\n // Bail if not tab key or not fullscreen\n if (event.key !== 'Tab' || event.keyCode !== 9) {\n return;\n }\n\n // Get the current focused element\n const focused = document.activeElement;\n\n if (focused === last && !event.shiftKey) {\n // Move focus to first element that can be tabbed if Shift isn't used\n first.focus();\n event.preventDefault();\n } else if (focused === first && event.shiftKey) {\n // Move focus to last element that can be tabbed if Shift is used\n last.focus();\n event.preventDefault();\n }\n };\n\n toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false);\n}\n\n// Set focus and tab focus class\nexport function setFocus(element = null, tabFocus = false) {\n if (!is.element(element)) {\n return;\n }\n\n // Set regular focus\n element.focus();\n\n // If we want to mimic keyboard focus via tab\n if (tabFocus) {\n toggleClass(element, this.config.classNames.tabFocus);\n }\n}\n","// ==========================================================================\n// Animation utils\n// ==========================================================================\n\nimport { toggleHidden } from './elements';\nimport is from './is';\n\nexport const transitionEndEvent = (() => {\n const element = document.createElement('span');\n\n const events = {\n WebkitTransition: 'webkitTransitionEnd',\n MozTransition: 'transitionend',\n OTransition: 'oTransitionEnd otransitionend',\n transition: 'transitionend',\n };\n\n const type = Object.keys(events).find(event => element.style[event] !== undefined);\n\n return is.string(type) ? events[type] : false;\n})();\n\n// Force repaint of element\nexport function repaint(element) {\n setTimeout(() => {\n try {\n toggleHidden(element, true);\n element.offsetHeight; // eslint-disable-line\n toggleHidden(element, false);\n } catch (e) {\n // Do nothing\n }\n }, 0);\n}\n","// ==========================================================================\n// Browser sniffing\n// Unfortunately, due to mixed support, UA sniffing is required\n// ==========================================================================\n\nconst browser = {\n isIE: /* @cc_on!@ */ false || !!document.documentMode,\n isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),\n isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),\n isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform),\n};\n\nexport default browser;\n","// ==========================================================================\n// Plyr support checks\n// ==========================================================================\n\nimport { transitionEndEvent } from './utils/animation';\nimport browser from './utils/browser';\nimport { createElement } from './utils/elements';\nimport is from './utils/is';\n\n// Default codecs for checking mimetype support\nconst defaultCodecs = {\n 'audio/ogg': 'vorbis',\n 'audio/wav': '1',\n 'video/webm': 'vp8, vorbis',\n 'video/mp4': 'avc1.42E01E, mp4a.40.2',\n 'video/ogg': 'theora',\n};\n\n// Check for feature support\nconst support = {\n // Basic support\n audio: 'canPlayType' in document.createElement('audio'),\n video: 'canPlayType' in document.createElement('video'),\n\n // Check for support\n // Basic functionality vs full UI\n check(type, provider, playsinline) {\n const canPlayInline = browser.isIPhone && playsinline && support.playsinline;\n const api = support[type] || provider !== 'html5';\n const ui = api && support.rangeInput && (type !== 'video' || !browser.isIPhone || canPlayInline);\n\n return {\n api,\n ui,\n };\n },\n\n // Picture-in-picture support\n // Safari only currently\n pip: (() => !browser.isIPhone && is.function(createElement('video').webkitSetPresentationMode))(),\n\n // Airplay support\n // Safari only currently\n airplay: is.function(window.WebKitPlaybackTargetAvailabilityEvent),\n\n // Inline playback support\n // https://webkit.org/blog/6784/new-video-policies-for-ios/\n playsinline: 'playsInline' in document.createElement('video'),\n\n // Check for mime type support against a player instance\n // Credits: http://diveintohtml5.info/everything.html\n // Related: http://www.leanbackplayer.com/test/h5mt.html\n mime(inputType) {\n const [mediaType] = inputType.split('/');\n if (!this.isHTML5 || mediaType !== this.type) {\n return false;\n }\n\n let type;\n if (inputType && inputType.includes('codecs=')) {\n // Use input directly\n type = inputType;\n } else if (inputType === 'audio/mpeg') {\n // Skip codec\n type = 'audio/mpeg;';\n } else if (inputType in defaultCodecs) {\n // Use codec\n type = `${inputType}; codecs=\"${defaultCodecs[inputType]}\"`;\n }\n\n try {\n return Boolean(type && this.media.canPlayType(type).replace(/no/, ''));\n } catch (err) {\n return false;\n }\n },\n\n // Check for textTracks support\n textTracks: 'textTracks' in document.createElement('video'),\n\n // <input type=\"range\"> Sliders\n rangeInput: (() => {\n const range = document.createElement('input');\n range.type = 'range';\n return range.type === 'range';\n })(),\n\n // Touch\n // NOTE: Remember a device can be mouse + touch enabled so we check on first touch event\n touch: 'ontouchstart' in document.documentElement,\n\n // Detect transitions support\n transitions: transitionEndEvent !== false,\n\n // Reduced motion iOS & MacOS setting\n // https://webkit.org/blog/7551/responsive-design-for-motion/\n reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches,\n};\n\nexport default support;\n","// ==========================================================================\n// Plyr HTML5 helpers\n// ==========================================================================\n\nimport support from './support';\nimport { removeElement } from './utils/elements';\nimport { triggerEvent } from './utils/events';\n\nconst html5 = {\n getSources() {\n if (!this.isHTML5) {\n return [];\n }\n\n const sources = Array.from(this.media.querySelectorAll('source'));\n\n // Filter out unsupported sources\n return sources.filter(source => support.mime.call(this, source.getAttribute('type')));\n },\n\n // Get quality levels\n getQualityOptions() {\n // Get sizes from <source> elements\n return html5.getSources\n .call(this)\n .map(source => Number(source.getAttribute('size')))\n .filter(Boolean);\n },\n\n extend() {\n if (!this.isHTML5) {\n return;\n }\n\n const player = this;\n\n // Quality\n Object.defineProperty(player.media, 'quality', {\n get() {\n // Get sources\n const sources = html5.getSources.call(player);\n const source = sources.find(source => source.getAttribute('src') === player.source);\n\n // Return size, if match is found\n return source && Number(source.getAttribute('size'));\n },\n set(input) {\n // Get sources\n const sources = html5.getSources.call(player);\n\n // Get first match for requested size\n const source = sources.find(source => Number(source.getAttribute('size')) === input);\n\n // No matching source found\n if (!source) {\n return;\n }\n\n // Get current state\n const { currentTime, paused, preload, readyState } = player.media;\n\n // Set new source\n player.media.src = source.getAttribute('src');\n\n // Prevent loading if preload=\"none\" and the current source isn't loaded (#1044)\n if (preload !== 'none' || readyState) {\n // Restore time\n player.once('loadedmetadata', () => {\n player.currentTime = currentTime;\n\n // Resume playing\n if (!paused) {\n player.play();\n }\n });\n\n // Load new source\n player.media.load();\n }\n\n // Trigger change event\n triggerEvent.call(player, player.media, 'qualitychange', false, {\n quality: input,\n });\n\n // Save to storage\n player.storage.set({ quality: input });\n },\n });\n },\n\n // Cancel current network requests\n // See https://github.com/sampotts/plyr/issues/174\n cancelRequests() {\n if (!this.isHTML5) {\n return;\n }\n\n // Remove child sources\n removeElement(html5.getSources.call(this));\n\n // Set blank video src attribute\n // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error\n // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection\n this.media.setAttribute('src', this.config.blankVideo);\n\n // Load the new empty source\n // This will cancel existing requests\n // See https://github.com/sampotts/plyr/issues/174\n this.media.load();\n\n // Debugging\n this.debug.log('Cancelled network requests');\n },\n};\n\nexport default html5;\n","// ==========================================================================\n// Array utils\n// ==========================================================================\n\nimport is from './is';\n\n// Remove duplicates in an array\nexport function dedupe(array) {\n if (!is.array(array)) {\n return array;\n }\n\n return array.filter((item, index) => array.indexOf(item) === index);\n}\n\n// Get the closest value in an array\nexport function closest(array, value) {\n if (!is.array(array) || !array.length) {\n return null;\n }\n\n return array.reduce((prev, curr) => (Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev));\n}\n","// ==========================================================================\n// Object utils\n// ==========================================================================\n\nimport is from './is';\n\n// Clone nested objects\nexport function cloneDeep(object) {\n return JSON.parse(JSON.stringify(object));\n}\n\n// Get a nested value in an object\nexport function getDeep(object, path) {\n return path.split('.').reduce((obj, key) => obj && obj[key], object);\n}\n\n// Deep extend destination object with N more objects\nexport function extend(target = {}, ...sources) {\n if (!sources.length) {\n return target;\n }\n\n const source = sources.shift();\n\n if (!is.object(source)) {\n return target;\n }\n\n Object.keys(source).forEach(key => {\n if (is.object(source[key])) {\n if (!Object.keys(target).includes(key)) {\n Object.assign(target, { [key]: {} });\n }\n\n extend(target[key], source[key]);\n } else {\n Object.assign(target, { [key]: source[key] });\n }\n });\n\n return extend(target, ...sources);\n}\n","// ==========================================================================\n// String utils\n// ==========================================================================\n\nimport is from './is';\n\n// Generate a random ID\nexport function generateId(prefix) {\n return `${prefix}-${Math.floor(Math.random() * 10000)}`;\n}\n\n// Format string\nexport function format(input, ...args) {\n if (is.empty(input)) {\n return input;\n }\n\n return input.toString().replace(/{(\\d+)}/g, (match, i) => args[i].toString());\n}\n\n// Get percentage\nexport function getPercentage(current, max) {\n if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {\n return 0;\n }\n\n return ((current / max) * 100).toFixed(2);\n}\n\n// Replace all occurances of a string in a string\nexport function replaceAll(input = '', find = '', replace = '') {\n return input.replace(\n new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\\]/\\\\])/g, '\\\\$1'), 'g'),\n replace.toString(),\n );\n}\n\n// Convert to title case\nexport function toTitleCase(input = '') {\n return input.toString().replace(/\\w\\S*/g, text => text.charAt(0).toUpperCase() + text.substr(1).toLowerCase());\n}\n\n// Convert string to pascalCase\nexport function toPascalCase(input = '') {\n let string = input.toString();\n\n // Convert kebab case\n string = replaceAll(string, '-', ' ');\n\n // Convert snake case\n string = replaceAll(string, '_', ' ');\n\n // Convert to title case\n string = toTitleCase(string);\n\n // Convert to pascal case\n return replaceAll(string, ' ', '');\n}\n\n// Convert string to pascalCase\nexport function toCamelCase(input = '') {\n let string = input.toString();\n\n // Convert to pascal case\n string = toPascalCase(string);\n\n // Convert first character to lowercase\n return string.charAt(0).toLowerCase() + string.slice(1);\n}\n\n// Remove HTML from a string\nexport function stripHTML(source) {\n const fragment = document.createDocumentFragment();\n const element = document.createElement('div');\n fragment.appendChild(element);\n element.innerHTML = source;\n return fragment.firstChild.innerText;\n}\n\n// Like outerHTML, but also works for DocumentFragment\nexport function getHTML(element) {\n const wrapper = document.createElement('div');\n wrapper.appendChild(element);\n return wrapper.innerHTML;\n}\n","// ==========================================================================\n// Plyr internationalization\n// ==========================================================================\n\nimport is from './is';\nimport { getDeep } from './objects';\nimport { replaceAll } from './strings';\n\n// Skip i18n for abbreviations and brand names\nconst resources = {\n pip: 'PIP',\n airplay: 'AirPlay',\n html5: 'HTML5',\n vimeo: 'Vimeo',\n youtube: 'YouTube',\n};\n\nconst i18n = {\n get(key = '', config = {}) {\n if (is.empty(key) || is.empty(config)) {\n return '';\n }\n\n let string = getDeep(config.i18n, key);\n\n if (is.empty(string)) {\n if (Object.keys(resources).includes(key)) {\n return resources[key];\n }\n\n return '';\n }\n\n const replace = {\n '{seektime}': config.seekTime,\n '{title}': config.title,\n };\n\n Object.entries(replace).forEach(([key, value]) => {\n string = replaceAll(string, key, value);\n });\n\n return string;\n },\n};\n\nexport default i18n;\n","// ==========================================================================\n// Plyr storage\n// ==========================================================================\n\nimport is from './utils/is';\nimport { extend } from './utils/objects';\n\nclass Storage {\n constructor(player) {\n this.enabled = player.config.storage.enabled;\n this.key = player.config.storage.key;\n }\n\n // Check for actual support (see if we can use it)\n static get supported() {\n try {\n if (!('localStorage' in window)) {\n return false;\n }\n\n const test = '___test';\n\n // Try to use it (it might be disabled, e.g. user is in private mode)\n // see: https://github.com/sampotts/plyr/issues/131\n window.localStorage.setItem(test, test);\n window.localStorage.removeItem(test);\n\n return true;\n } catch (e) {\n return false;\n }\n }\n\n get(key) {\n if (!Storage.supported || !this.enabled) {\n return null;\n }\n\n const store = window.localStorage.getItem(this.key);\n\n if (is.empty(store)) {\n return null;\n }\n\n const json = JSON.parse(store);\n\n return is.string(key) && key.length ? json[key] : json;\n }\n\n set(object) {\n // Bail if we don't have localStorage support or it's disabled\n if (!Storage.supported || !this.enabled) {\n return;\n }\n\n // Can only store objectst\n if (!is.object(object)) {\n return;\n }\n\n // Get current storage\n let storage = this.get();\n\n // Default to empty object\n if (is.empty(storage)) {\n storage = {};\n }\n\n // Update the working copy of the values\n extend(storage, object);\n\n // Update storage\n window.localStorage.setItem(this.key, JSON.stringify(storage));\n }\n}\n\nexport default Storage;\n","// ==========================================================================\n// Fetch wrapper\n// Using XHR to avoid issues with older browsers\n// ==========================================================================\n\nexport default function fetch(url, responseType = 'text') {\n return new Promise((resolve, reject) => {\n try {\n const request = new XMLHttpRequest();\n\n // Check for CORS support\n if (!('withCredentials' in request)) {\n return;\n }\n\n request.addEventListener('load', () => {\n if (responseType === 'text') {\n try {\n resolve(JSON.parse(request.responseText));\n } catch (e) {\n resolve(request.responseText);\n }\n } else {\n resolve(request.response);\n }\n });\n\n request.addEventListener('error', () => {\n throw new Error(request.status);\n });\n\n request.open('GET', url, true);\n\n // Set the required response type\n request.responseType = responseType;\n\n request.send();\n } catch (e) {\n reject(e);\n }\n });\n}\n","// ==========================================================================\n// Sprite loader\n// ==========================================================================\n\nimport Storage from '../storage';\nimport fetch from './fetch';\nimport is from './is';\n\n// Load an external SVG sprite\nexport default function loadSprite(url, id) {\n if (!is.string(url)) {\n return;\n }\n\n const prefix = 'cache';\n const hasId = is.string(id);\n let isCached = false;\n\n const exists = () => document.getElementById(id) !== null;\n\n const update = (container, data) => {\n container.innerHTML = data;\n\n // Check again incase of race condition\n if (hasId && exists()) {\n return;\n }\n\n // Inject the SVG to the body\n document.body.insertAdjacentElement('afterbegin', container);\n };\n\n // Only load once if ID set\n if (!hasId || !exists()) {\n const useStorage = Storage.supported;\n\n // Create container\n const container = document.createElement('div');\n container.setAttribute('hidden', '');\n\n if (hasId) {\n container.setAttribute('id', id);\n }\n\n // Check in cache\n if (useStorage) {\n const cached = window.localStorage.getItem(`${prefix}-${id}`);\n isCached = cached !== null;\n\n if (isCached) {\n const data = JSON.parse(cached);\n update(container, data.content);\n }\n }\n\n // Get the sprite\n fetch(url)\n .then(result => {\n if (is.empty(result)) {\n return;\n }\n\n if (useStorage) {\n window.localStorage.setItem(\n `${prefix}-${id}`,\n JSON.stringify({\n content: result,\n }),\n );\n }\n\n update(container, result);\n })\n .catch(() => {});\n }\n}\n","// ==========================================================================\n// Time utils\n// ==========================================================================\n\nimport is from './is';\n\n// Time helpers\nexport const getHours = value => parseInt((value / 60 / 60) % 60, 10);\nexport const getMinutes = value => parseInt((value / 60) % 60, 10);\nexport const getSeconds = value => parseInt(value % 60, 10);\n\n// Format time to UI friendly string\nexport function formatTime(time = 0, displayHours = false, inverted = false) {\n // Bail if the value isn't a number\n if (!is.number(time)) {\n return formatTime(null, displayHours, inverted);\n }\n\n // Format time component to add leading zero\n const format = value => `0${value}`.slice(-2);\n\n // Breakdown to hours, mins, secs\n let hours = getHours(time);\n const mins = getMinutes(time);\n const secs = getSeconds(time);\n\n // Do we need to display hours?\n if (displayHours || hours > 0) {\n hours = `${hours}:`;\n } else {\n hours = '';\n }\n\n // Render\n return `${inverted && time > 0 ? '-' : ''}${hours}${format(mins)}:${format(secs)}`;\n}\n","// ==========================================================================\n// Plyr controls\n// TODO: This needs to be split into smaller files and cleaned up\n// ==========================================================================\n\nimport captions from './captions';\nimport html5 from './html5';\nimport support from './support';\nimport { repaint, transitionEndEvent } from './utils/animation';\nimport { dedupe } from './utils/arrays';\nimport browser from './utils/browser';\nimport { createElement, emptyElement, getAttributesFromSelector, getElement, getElements, hasClass, matches, removeElement, setAttributes, setFocus, toggleClass, toggleHidden } from './utils/elements';\nimport { off, on } from './utils/events';\nimport i18n from './utils/i18n';\nimport is from './utils/is';\nimport loadSprite from './utils/loadSprite';\nimport { extend } from './utils/objects';\nimport { getPercentage, replaceAll, toCamelCase, toTitleCase } from './utils/strings';\nimport { formatTime, getHours } from './utils/time';\n\n// TODO: Don't export a massive object - break down and create class\nconst controls = {\n // Get icon URL\n getIconUrl() {\n const url = new URL(this.config.iconUrl, window.location);\n const cors = url.host !== window.location.host || (browser.isIE && !window.svg4everybody);\n\n return {\n url: this.config.iconUrl,\n cors,\n };\n },\n\n // Find the UI controls\n findElements() {\n try {\n this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper);\n\n // Buttons\n this.elements.buttons = {\n play: getElements.call(this, this.config.selectors.buttons.play),\n pause: getElement.call(this, this.config.selectors.buttons.pause),\n restart: getElement.call(this, this.config.selectors.buttons.restart),\n rewind: getElement.call(this, this.config.selectors.buttons.rewind),\n fastForward: getElement.call(this, this.config.selectors.buttons.fastForward),\n mute: getElement.call(this, this.config.selectors.buttons.mute),\n pip: getElement.call(this, this.config.selectors.buttons.pip),\n airplay: getElement.call(this, this.config.selectors.buttons.airplay),\n settings: getElement.call(this, this.config.selectors.buttons.settings),\n captions: getElement.call(this, this.config.selectors.buttons.captions),\n fullscreen: getElement.call(this, this.config.selectors.buttons.fullscreen),\n };\n\n // Progress\n this.elements.progress = getElement.call(this, this.config.selectors.progress);\n\n // Inputs\n this.elements.inputs = {\n seek: getElement.call(this, this.config.selectors.inputs.seek),\n volume: getElement.call(this, this.config.selectors.inputs.volume),\n };\n\n // Display\n this.elements.display = {\n buffer: getElement.call(this, this.config.selectors.display.buffer),\n currentTime: getElement.call(this, this.config.selectors.display.currentTime),\n duration: getElement.call(this, this.config.selectors.display.duration),\n };\n\n // Seek tooltip\n if (is.element(this.elements.progress)) {\n this.elements.display.seekTooltip = this.elements.progress.querySelector(\n `.${this.config.classNames.tooltip}`,\n );\n }\n\n return true;\n } catch (error) {\n // Log it\n this.debug.warn('It looks like there is a problem with your custom controls HTML', error);\n\n // Restore native video controls\n this.toggleNativeControls(true);\n\n return false;\n }\n },\n\n // Create <svg> icon\n createIcon(type, attributes) {\n const namespace = 'http://www.w3.org/2000/svg';\n const iconUrl = controls.getIconUrl.call(this);\n const iconPath = `${!iconUrl.cors ? iconUrl.url : ''}#${this.config.iconPrefix}`;\n\n // Create <svg>\n const icon = document.createElementNS(namespace, 'svg');\n setAttributes(\n icon,\n extend(attributes, {\n role: 'presentation',\n focusable: 'false',\n }),\n );\n\n // Create the <use> to reference sprite\n const use = document.createElementNS(namespace, 'use');\n const path = `${iconPath}-${type}`;\n\n // Set `href` attributes\n // https://github.com/sampotts/plyr/issues/460\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href\n if ('href' in use) {\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);\n }\n\n // Always set the older attribute even though it's \"deprecated\" (it'll be around for ages)\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path);\n\n // Add <use> to <svg>\n icon.appendChild(use);\n\n return icon;\n },\n\n // Create hidden text label\n createLabel(key, attr = {}) {\n const text = i18n.get(key, this.config);\n\n const attributes = Object.assign({}, attr, {\n class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' '),\n });\n\n return createElement('span', attributes, text);\n },\n\n // Create a badge\n createBadge(text) {\n if (is.empty(text)) {\n return null;\n }\n\n const badge = createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n badge.appendChild(\n createElement(\n 'span',\n {\n class: this.config.classNames.menu.badge,\n },\n text,\n ),\n );\n\n return badge;\n },\n\n // Create a <button>\n createButton(buttonType, attr) {\n const attributes = Object.assign({}, attr);\n let type = toCamelCase(buttonType);\n\n const props = {\n element: 'button',\n toggle: false,\n label: null,\n icon: null,\n labelPressed: null,\n iconPressed: null,\n };\n\n ['element', 'icon', 'label'].forEach(key => {\n if (Object.keys(attributes).includes(key)) {\n props[key] = attributes[key];\n delete attributes[key];\n }\n });\n\n // Default to 'button' type to prevent form submission\n if (props.element === 'button' && !Object.keys(attributes).includes('type')) {\n attributes.type = 'button';\n }\n\n // Set class name\n if (Object.keys(attributes).includes('class')) {\n if (!attributes.class.includes(this.config.classNames.control)) {\n attributes.class += ` ${this.config.classNames.control}`;\n }\n } else {\n attributes.class = this.config.classNames.control;\n }\n\n // Large play button\n switch (buttonType) {\n case 'play':\n props.toggle = true;\n props.label = 'play';\n props.labelPressed = 'pause';\n props.icon = 'play';\n props.iconPressed = 'pause';\n break;\n\n case 'mute':\n props.toggle = true;\n props.label = 'mute';\n props.labelPressed = 'unmute';\n props.icon = 'volume';\n props.iconPressed = 'muted';\n break;\n\n case 'captions':\n props.toggle = true;\n props.label = 'enableCaptions';\n props.labelPressed = 'disableCaptions';\n props.icon = 'captions-off';\n props.iconPressed = 'captions-on';\n break;\n\n case 'fullscreen':\n props.toggle = true;\n props.label = 'enterFullscreen';\n props.labelPressed = 'exitFullscreen';\n props.icon = 'enter-fullscreen';\n props.iconPressed = 'exit-fullscreen';\n break;\n\n case 'play-large':\n attributes.class += ` ${this.config.classNames.control}--overlaid`;\n type = 'play';\n props.label = 'play';\n props.icon = 'play';\n break;\n\n default:\n if (is.empty(props.label)) {\n props.label = type;\n }\n if (is.empty(props.icon)) {\n props.icon = buttonType;\n }\n }\n\n const button = createElement(props.element);\n\n // Setup toggle icon and labels\n if (props.toggle) {\n // Icon\n button.appendChild(\n controls.createIcon.call(this, props.iconPressed, {\n class: 'icon--pressed',\n }),\n );\n button.appendChild(\n controls.createIcon.call(this, props.icon, {\n class: 'icon--not-pressed',\n }),\n );\n\n // Label/Tooltip\n button.appendChild(\n controls.createLabel.call(this, props.labelPressed, {\n class: 'label--pressed',\n }),\n );\n button.appendChild(\n controls.createLabel.call(this, props.label, {\n class: 'label--not-pressed',\n }),\n );\n } else {\n button.appendChild(controls.createIcon.call(this, props.icon));\n button.appendChild(controls.createLabel.call(this, props.label));\n }\n\n // Merge and set attributes\n extend(attributes, getAttributesFromSelector(this.config.selectors.buttons[type], attributes));\n setAttributes(button, attributes);\n\n // We have multiple play buttons\n if (type === 'play') {\n if (!is.array(this.elements.buttons[type])) {\n this.elements.buttons[type] = [];\n }\n\n this.elements.buttons[type].push(button);\n } else {\n this.elements.buttons[type] = button;\n }\n\n return button;\n },\n\n // Create an <input type='range'>\n createRange(type, attributes) {\n // Seek input\n const input = createElement(\n 'input',\n extend(\n getAttributesFromSelector(this.config.selectors.inputs[type]),\n {\n type: 'range',\n min: 0,\n max: 100,\n step: 0.01,\n value: 0,\n autocomplete: 'off',\n // A11y fixes for https://github.com/sampotts/plyr/issues/905\n role: 'slider',\n 'aria-label': i18n.get(type, this.config),\n 'aria-valuemin': 0,\n 'aria-valuemax': 100,\n 'aria-valuenow': 0,\n },\n attributes,\n ),\n );\n\n this.elements.inputs[type] = input;\n\n // Set the fill for webkit now\n controls.updateRangeFill.call(this, input);\n\n return input;\n },\n\n // Create a <progress>\n createProgress(type, attributes) {\n const progress = createElement(\n 'progress',\n extend(\n getAttributesFromSelector(this.config.selectors.display[type]),\n {\n min: 0,\n max: 100,\n value: 0,\n role: 'presentation',\n 'aria-hidden': true,\n },\n attributes,\n ),\n );\n\n // Create the label inside\n if (type !== 'volume') {\n progress.appendChild(createElement('span', null, '0'));\n\n const suffixKey = {\n played: 'played',\n buffer: 'buffered',\n }[type];\n const suffix = suffixKey ? i18n.get(suffixKey, this.config) : '';\n\n progress.innerText = `% ${suffix.toLowerCase()}`;\n }\n\n this.elements.display[type] = progress;\n\n return progress;\n },\n\n // Create time display\n createTime(type) {\n const attributes = getAttributesFromSelector(this.config.selectors.display[type]);\n\n const container = createElement(\n 'div',\n extend(attributes, {\n class: `${this.config.classNames.display.time} ${attributes.class ? attributes.class : ''}`.trim(),\n 'aria-label': i18n.get(type, this.config),\n }),\n '00:00',\n );\n\n // Reference for updates\n this.elements.display[type] = container;\n\n return container;\n },\n\n // Bind keyboard shortcuts for a menu item\n // We have to bind to keyup otherwise Firefox triggers a click when a keydown event handler shifts focus\n // https://bugzilla.mozilla.org/show_bug.cgi?id=1220143\n bindMenuItemShortcuts(menuItem, type) {\n // Navigate through menus via arrow keys and space\n on(\n menuItem,\n 'keydown keyup',\n event => {\n // We only care about space and ⬆️ ⬇️️ ➡️\n if (![32, 38, 39, 40].includes(event.which)) {\n return;\n }\n\n // Prevent play / seek\n event.preventDefault();\n event.stopPropagation();\n\n // We're just here to prevent the keydown bubbling\n if (event.type === 'keydown') {\n return;\n }\n\n const isRadioButton = matches(menuItem, '[role=\"menuitemradio\"]');\n\n // Show the respective menu\n if (!isRadioButton && [32, 39].includes(event.which)) {\n controls.showMenuPanel.call(this, type, true);\n } else {\n let target;\n\n if (event.which !== 32) {\n if (event.which === 40 || (isRadioButton && event.which === 39)) {\n target = menuItem.nextElementSibling;\n\n if (!is.element(target)) {\n target = menuItem.parentNode.firstElementChild;\n }\n } else {\n target = menuItem.previousElementSibling;\n\n if (!is.element(target)) {\n target = menuItem.parentNode.lastElementChild;\n }\n }\n\n setFocus.call(this, target, true);\n }\n }\n },\n false,\n );\n\n // Enter will fire a `click` event but we still need to manage focus\n // So we bind to keyup which fires after and set focus here\n on(menuItem, 'keyup', event => {\n if (event.which !== 13) {\n return;\n }\n\n controls.focusFirstMenuItem.call(this, null, true);\n });\n },\n\n // Create a settings menu item\n createMenuItem({ value, list, type, title, badge = null, checked = false }) {\n const attributes = getAttributesFromSelector(this.config.selectors.inputs[type]);\n\n const menuItem = createElement(\n 'button',\n extend(attributes, {\n type: 'button',\n role: 'menuitemradio',\n class: `${this.config.classNames.control} ${attributes.class ? attributes.class : ''}`.trim(),\n 'aria-checked': checked,\n value,\n }),\n );\n\n const flex = createElement('span');\n\n // We have to set as HTML incase of special characters\n flex.innerHTML = title;\n\n if (is.element(badge)) {\n flex.appendChild(badge);\n }\n\n menuItem.appendChild(flex);\n\n // Replicate radio button behaviour\n Object.defineProperty(menuItem, 'checked', {\n enumerable: true,\n get() {\n return menuItem.getAttribute('aria-checked') === 'true';\n },\n set(checked) {\n // Ensure exclusivity\n if (checked) {\n Array.from(menuItem.parentNode.children)\n .filter(node => matches(node, '[role=\"menuitemradio\"]'))\n .forEach(node => node.setAttribute('aria-checked', 'false'));\n }\n\n menuItem.setAttribute('aria-checked', checked ? 'true' : 'false');\n },\n });\n\n this.listeners.bind(\n menuItem,\n 'click keyup',\n event => {\n if (is.keyboardEvent(event) && event.which !== 32) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n menuItem.checked = true;\n\n switch (type) {\n case 'language':\n this.currentTrack = Number(value);\n break;\n\n case 'quality':\n this.quality = value;\n break;\n\n case 'speed':\n this.speed = parseFloat(value);\n break;\n\n default:\n break;\n }\n\n controls.showMenuPanel.call(this, 'home', is.keyboardEvent(event));\n },\n type,\n false,\n );\n\n controls.bindMenuItemShortcuts.call(this, menuItem, type);\n\n list.appendChild(menuItem);\n },\n\n // Format a time for display\n formatTime(time = 0, inverted = false) {\n // Bail if the value isn't a number\n if (!is.number(time)) {\n return time;\n }\n\n // Always display hours if duration is over an hour\n const forceHours = getHours(this.duration) > 0;\n\n return formatTime(time, forceHours, inverted);\n },\n\n // Update the displayed time\n updateTimeDisplay(target = null, time = 0, inverted = false) {\n // Bail if there's no element to display or the value isn't a number\n if (!is.element(target) || !is.number(time)) {\n return;\n }\n\n // eslint-disable-next-line no-param-reassign\n target.innerText = controls.formatTime(time, inverted);\n },\n\n // Update volume UI and storage\n updateVolume() {\n if (!this.supported.ui) {\n return;\n }\n\n // Update range\n if (is.element(this.elements.inputs.volume)) {\n controls.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume);\n }\n\n // Update mute state\n if (is.element(this.elements.buttons.mute)) {\n this.elements.buttons.mute.pressed = this.muted || this.volume === 0;\n }\n },\n\n // Update seek value and lower fill\n setRange(target, value = 0) {\n if (!is.element(target)) {\n return;\n }\n\n // eslint-disable-next-line\n target.value = value;\n\n // Webkit range fill\n controls.updateRangeFill.call(this, target);\n },\n\n // Update <progress> elements\n updateProgress(event) {\n if (!this.supported.ui || !is.event(event)) {\n return;\n }\n\n let value = 0;\n\n const setProgress = (target, input) => {\n const value = is.number(input) ? input : 0;\n const progress = is.element(target) ? target : this.elements.display.buffer;\n\n // Update value and label\n if (is.element(progress)) {\n progress.value = value;\n\n // Update text label inside\n const label = progress.getElementsByTagName('span')[0];\n if (is.element(label)) {\n label.childNodes[0].nodeValue = value;\n }\n }\n };\n\n if (event) {\n switch (event.type) {\n // Video playing\n case 'timeupdate':\n case 'seeking':\n case 'seeked':\n value = getPercentage(this.currentTime, this.duration);\n\n // Set seek range value only if it's a 'natural' time event\n if (event.type === 'timeupdate') {\n controls.setRange.call(this, this.elements.inputs.seek, value);\n }\n\n break;\n\n // Check buffer status\n case 'playing':\n case 'progress':\n setProgress(this.elements.display.buffer, this.buffered * 100);\n\n break;\n\n default:\n break;\n }\n }\n },\n\n // Webkit polyfill for lower fill range\n updateRangeFill(target) {\n // Get range from event if event passed\n const range = is.event(target) ? target.target : target;\n\n // Needs to be a valid <input type='range'>\n if (!is.element(range) || range.getAttribute('type') !== 'range') {\n return;\n }\n\n // Set aria values for https://github.com/sampotts/plyr/issues/905\n if (matches(range, this.config.selectors.inputs.seek)) {\n range.setAttribute('aria-valuenow', this.currentTime);\n const currentTime = controls.formatTime(this.currentTime);\n const duration = controls.formatTime(this.duration);\n const format = i18n.get('seekLabel', this.config);\n range.setAttribute(\n 'aria-valuetext',\n format.replace('{currentTime}', currentTime).replace('{duration}', duration),\n );\n } else if (matches(range, this.config.selectors.inputs.volume)) {\n const percent = range.value * 100;\n range.setAttribute('aria-valuenow', percent);\n range.setAttribute('aria-valuetext', `${percent.toFixed(1)}%`);\n } else {\n range.setAttribute('aria-valuenow', range.value);\n }\n\n // WebKit only\n if (!browser.isWebkit) {\n return;\n }\n\n // Set CSS custom property\n range.style.setProperty('--value', `${range.value / range.max * 100}%`);\n },\n\n // Update hover tooltip for seeking\n updateSeekTooltip(event) {\n // Bail if setting not true\n if (\n !this.config.tooltips.seek ||\n !is.element(this.elements.inputs.seek) ||\n !is.element(this.elements.display.seekTooltip) ||\n this.duration === 0\n ) {\n return;\n }\n\n // Calculate percentage\n let percent = 0;\n const clientRect = this.elements.progress.getBoundingClientRect();\n const visible = `${this.config.classNames.tooltip}--visible`;\n\n const toggle = toggle => {\n toggleClass(this.elements.display.seekTooltip, visible, toggle);\n };\n\n // Hide on touch\n if (this.touch) {\n toggle(false);\n return;\n }\n\n // Determine percentage, if already visible\n if (is.event(event)) {\n percent = 100 / clientRect.width * (event.pageX - clientRect.left);\n } else if (hasClass(this.elements.display.seekTooltip, visible)) {\n percent = parseFloat(this.elements.display.seekTooltip.style.left, 10);\n } else {\n return;\n }\n\n // Set bounds\n if (percent < 0) {\n percent = 0;\n } else if (percent > 100) {\n percent = 100;\n }\n\n // Display the time a click would seek to\n controls.updateTimeDisplay.call(this, this.elements.display.seekTooltip, this.duration / 100 * percent);\n\n // Set position\n this.elements.display.seekTooltip.style.left = `${percent}%`;\n\n // Show/hide the tooltip\n // If the event is a moues in/out and percentage is inside bounds\n if (is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {\n toggle(event.type === 'mouseenter');\n }\n },\n\n // Handle time change event\n timeUpdate(event) {\n // Only invert if only one time element is displayed and used for both duration and currentTime\n const invert = !is.element(this.elements.display.duration) && this.config.invertTime;\n\n // Duration\n controls.updateTimeDisplay.call(\n this,\n this.elements.display.currentTime,\n invert ? this.duration - this.currentTime : this.currentTime,\n invert,\n );\n\n // Ignore updates while seeking\n if (event && event.type === 'timeupdate' && this.media.seeking) {\n return;\n }\n\n // Playing progress\n controls.updateProgress.call(this, event);\n },\n\n // Show the duration on metadataloaded or durationchange events\n durationUpdate() {\n // Bail if no UI or durationchange event triggered after playing/seek when invertTime is false\n if (!this.supported.ui || (!this.config.invertTime && this.currentTime)) {\n return;\n }\n\n // If duration is the 2**32 (shaka), Infinity (HLS), DASH-IF (Number.MAX_SAFE_INTEGER || Number.MAX_VALUE) indicating live we hide the currentTime and progressbar.\n // https://github.com/video-dev/hls.js/blob/5820d29d3c4c8a46e8b75f1e3afa3e68c1a9a2db/src/controller/buffer-controller.js#L415\n // https://github.com/google/shaka-player/blob/4d889054631f4e1cf0fbd80ddd2b71887c02e232/lib/media/streaming_engine.js#L1062\n // https://github.com/Dash-Industry-Forum/dash.js/blob/69859f51b969645b234666800d4cb596d89c602d/src/dash/models/DashManifestModel.js#L338\n if (this.duration >= 2 ** 32) {\n toggleHidden(this.elements.display.currentTime, true);\n toggleHidden(this.elements.progress, true);\n return;\n }\n\n // Update ARIA values\n if (is.element(this.elements.inputs.seek)) {\n this.elements.inputs.seek.setAttribute('aria-valuemax', this.duration);\n }\n\n // If there's a spot to display duration\n const hasDuration = is.element(this.elements.display.duration);\n\n // If there's only one time display, display duration there\n if (!hasDuration && this.config.displayDuration && this.paused) {\n controls.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration);\n }\n\n // If there's a duration element, update content\n if (hasDuration) {\n controls.updateTimeDisplay.call(this, this.elements.display.duration, this.duration);\n }\n\n // Update the tooltip (if visible)\n controls.updateSeekTooltip.call(this);\n },\n\n // Hide/show a tab\n toggleMenuButton(setting, toggle) {\n toggleHidden(this.elements.settings.buttons[setting], !toggle);\n },\n\n // Update the selected setting\n updateSetting(setting, container, input) {\n const pane = this.elements.settings.panels[setting];\n let value = null;\n let list = container;\n\n if (setting === 'captions') {\n value = this.currentTrack;\n } else {\n value = !is.empty(input) ? input : this[setting];\n\n // Get default\n if (is.empty(value)) {\n value = this.config[setting].default;\n }\n\n // Unsupported value\n if (!is.empty(this.options[setting]) && !this.options[setting].includes(value)) {\n this.debug.warn(`Unsupported value of '${value}' for ${setting}`);\n return;\n }\n\n // Disabled value\n if (!this.config[setting].options.includes(value)) {\n this.debug.warn(`Disabled value of '${value}' for ${setting}`);\n return;\n }\n }\n\n // Get the list if we need to\n if (!is.element(list)) {\n list = pane && pane.querySelector('[role=\"menu\"]');\n }\n\n // If there's no list it means it's not been rendered...\n if (!is.element(list)) {\n return;\n }\n\n // Update the label\n const label = this.elements.settings.buttons[setting].querySelector(`.${this.config.classNames.menu.value}`);\n label.innerHTML = controls.getLabel.call(this, setting, value);\n\n // Find the radio option and check it\n const target = list && list.querySelector(`[value=\"${value}\"]`);\n\n if (is.element(target)) {\n target.checked = true;\n }\n },\n\n // Translate a value into a nice label\n getLabel(setting, value) {\n switch (setting) {\n case 'speed':\n return value === 1 ? i18n.get('normal', this.config) : `${value}×`;\n\n case 'quality':\n if (is.number(value)) {\n const label = i18n.get(`qualityLabel.${value}`, this.config);\n\n if (!label.length) {\n return `${value}p`;\n }\n\n return label;\n }\n\n return toTitleCase(value);\n\n case 'captions':\n return captions.getLabel.call(this);\n\n default:\n return null;\n }\n },\n\n // Set the quality menu\n setQualityMenu(options) {\n // Menu required\n if (!is.element(this.elements.settings.panels.quality)) {\n return;\n }\n\n const type = 'quality';\n const list = this.elements.settings.panels.quality.querySelector('[role=\"menu\"]');\n\n // Set options if passed and filter based on uniqueness and config\n if (is.array(options)) {\n this.options.quality = dedupe(options).filter(quality => this.config.quality.options.includes(quality));\n }\n\n // Toggle the pane and tab\n const toggle = !is.empty(this.options.quality) && this.options.quality.length > 1;\n controls.toggleMenuButton.call(this, type, toggle);\n\n // Empty the menu\n emptyElement(list);\n\n // Check if we need to toggle the parent\n controls.checkMenu.call(this);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Get the badge HTML for HD, 4K etc\n const getBadge = quality => {\n const label = i18n.get(`qualityBadge.${quality}`, this.config);\n\n if (!label.length) {\n return null;\n }\n\n return controls.createBadge.call(this, label);\n };\n\n // Sort options by the config and then render options\n this.options.quality\n .sort((a, b) => {\n const sorting = this.config.quality.options;\n return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;\n })\n .forEach(quality => {\n controls.createMenuItem.call(this, {\n value: quality,\n list,\n type,\n title: controls.getLabel.call(this, 'quality', quality),\n badge: getBadge(quality),\n });\n });\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Set the looping options\n /* setLoopMenu() {\n // Menu required\n if (!is.element(this.elements.settings.panels.loop)) {\n return;\n }\n\n const options = ['start', 'end', 'all', 'reset'];\n const list = this.elements.settings.panels.loop.querySelector('[role=\"menu\"]');\n\n // Show the pane and tab\n toggleHidden(this.elements.settings.buttons.loop, false);\n toggleHidden(this.elements.settings.panels.loop, false);\n\n // Toggle the pane and tab\n const toggle = !is.empty(this.loop.options);\n controls.toggleMenuButton.call(this, 'loop', toggle);\n\n // Empty the menu\n emptyElement(list);\n\n options.forEach(option => {\n const item = createElement('li');\n\n const button = createElement(\n 'button',\n extend(getAttributesFromSelector(this.config.selectors.buttons.loop), {\n type: 'button',\n class: this.config.classNames.control,\n 'data-plyr-loop-action': option,\n }),\n i18n.get(option, this.config)\n );\n\n if (['start', 'end'].includes(option)) {\n const badge = controls.createBadge.call(this, '00:00');\n button.appendChild(badge);\n }\n\n item.appendChild(button);\n list.appendChild(item);\n });\n }, */\n\n // Get current selected caption language\n // TODO: rework this to user the getter in the API?\n\n // Set a list of available captions languages\n setCaptionsMenu() {\n // Menu required\n if (!is.element(this.elements.settings.panels.captions)) {\n return;\n }\n\n // TODO: Captions or language? Currently it's mixed\n const type = 'captions';\n const list = this.elements.settings.panels.captions.querySelector('[role=\"menu\"]');\n const tracks = captions.getTracks.call(this);\n const toggle = Boolean(tracks.length);\n\n // Toggle the pane and tab\n controls.toggleMenuButton.call(this, type, toggle);\n\n // Empty the menu\n emptyElement(list);\n\n // Check if we need to toggle the parent\n controls.checkMenu.call(this);\n\n // If there's no captions, bail\n if (!toggle) {\n return;\n }\n\n // Generate options data\n const options = tracks.map((track, value) => ({\n value,\n checked: this.captions.toggled && this.currentTrack === value,\n title: captions.getLabel.call(this, track),\n badge: track.language && controls.createBadge.call(this, track.language.toUpperCase()),\n list,\n type: 'language',\n }));\n\n // Add the \"Disabled\" option to turn off captions\n options.unshift({\n value: -1,\n checked: !this.captions.toggled,\n title: i18n.get('disabled', this.config),\n list,\n type: 'language',\n });\n\n // Generate options\n options.forEach(controls.createMenuItem.bind(this));\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Set a list of available captions languages\n setSpeedMenu(options) {\n // Menu required\n if (!is.element(this.elements.settings.panels.speed)) {\n return;\n }\n\n const type = 'speed';\n const list = this.elements.settings.panels.speed.querySelector('[role=\"menu\"]');\n\n // Set the speed options\n if (is.array(options)) {\n this.options.speed = options;\n } else if (this.isHTML5 || this.isVimeo) {\n this.options.speed = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n }\n\n // Set options if passed and filter based on config\n this.options.speed = this.options.speed.filter(speed => this.config.speed.options.includes(speed));\n\n // Toggle the pane and tab\n const toggle = !is.empty(this.options.speed) && this.options.speed.length > 1;\n controls.toggleMenuButton.call(this, type, toggle);\n\n // Empty the menu\n emptyElement(list);\n\n // Check if we need to toggle the parent\n controls.checkMenu.call(this);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Create items\n this.options.speed.forEach(speed => {\n controls.createMenuItem.call(this, {\n value: speed,\n list,\n type,\n title: controls.getLabel.call(this, 'speed', speed),\n });\n });\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Check if we need to hide/show the settings menu\n checkMenu() {\n const { buttons } = this.elements.settings;\n const visible = !is.empty(buttons) && Object.values(buttons).some(button => !button.hidden);\n\n toggleHidden(this.elements.settings.menu, !visible);\n },\n\n // Focus the first menu item in a given (or visible) menu\n focusFirstMenuItem(pane, tabFocus = false) {\n if (this.elements.settings.popup.hidden) {\n return;\n }\n\n let target = pane;\n\n if (!is.element(target)) {\n target = Object.values(this.elements.settings.panels).find(pane => !pane.hidden);\n }\n\n const firstItem = target.querySelector('[role^=\"menuitem\"]');\n\n setFocus.call(this, firstItem, tabFocus);\n },\n\n // Show/hide menu\n toggleMenu(input) {\n const { popup } = this.elements.settings;\n const button = this.elements.buttons.settings;\n\n // Menu and button are required\n if (!is.element(popup) || !is.element(button)) {\n return;\n }\n\n // True toggle by default\n const { hidden } = popup;\n let show = hidden;\n\n if (is.boolean(input)) {\n show = input;\n } else if (is.keyboardEvent(input) && input.which === 27) {\n show = false;\n } else if (is.event(input)) {\n const isMenuItem = popup.contains(input.target);\n\n // If the click was inside the menu or if the click\n // wasn't the button or menu item and we're trying to\n // show the menu (a doc click shouldn't show the menu)\n if (isMenuItem || (!isMenuItem && input.target !== button && show)) {\n return;\n }\n }\n\n // Set button attributes\n button.setAttribute('aria-expanded', show);\n\n // Show the actual popup\n toggleHidden(popup, !show);\n\n // Add class hook\n toggleClass(this.elements.container, this.config.classNames.menu.open, show);\n\n // Focus the first item if key interaction\n if (show && is.keyboardEvent(input)) {\n controls.focusFirstMenuItem.call(this, null, true);\n } else if (!show && !hidden) {\n // If closing, re-focus the button\n setFocus.call(this, button, is.keyboardEvent(input));\n }\n },\n\n // Get the natural size of a menu panel\n getMenuSize(tab) {\n const clone = tab.cloneNode(true);\n clone.style.position = 'absolute';\n clone.style.opacity = 0;\n clone.removeAttribute('hidden');\n\n // Append to parent so we get the \"real\" size\n tab.parentNode.appendChild(clone);\n\n // Get the sizes before we remove\n const width = clone.scrollWidth;\n const height = clone.scrollHeight;\n\n // Remove from the DOM\n removeElement(clone);\n\n return {\n width,\n height,\n };\n },\n\n // Show a panel in the menu\n showMenuPanel(type = '', tabFocus = false) {\n const target = document.getElementById(`plyr-settings-${this.id}-${type}`);\n\n // Nothing to show, bail\n if (!is.element(target)) {\n return;\n }\n\n // Hide all other panels\n const container = target.parentNode;\n const current = Array.from(container.children).find(node => !node.hidden);\n\n // If we can do fancy animations, we'll animate the height/width\n if (support.transitions && !support.reducedMotion) {\n // Set the current width as a base\n container.style.width = `${current.scrollWidth}px`;\n container.style.height = `${current.scrollHeight}px`;\n\n // Get potential sizes\n const size = controls.getMenuSize.call(this, target);\n\n // Restore auto height/width\n const restore = event => {\n // We're only bothered about height and width on the container\n if (event.target !== container || !['width', 'height'].includes(event.propertyName)) {\n return;\n }\n\n // Revert back to auto\n container.style.width = '';\n container.style.height = '';\n\n // Only listen once\n off.call(this, container, transitionEndEvent, restore);\n };\n\n // Listen for the transition finishing and restore auto height/width\n on.call(this, container, transitionEndEvent, restore);\n\n // Set dimensions to target\n container.style.width = `${size.width}px`;\n container.style.height = `${size.height}px`;\n }\n\n // Set attributes on current tab\n toggleHidden(current, true);\n\n // Set attributes on target\n toggleHidden(target, false);\n\n // Focus the first item\n controls.focusFirstMenuItem.call(this, target, tabFocus);\n },\n\n // Set the download link\n setDownloadLink() {\n const button = this.elements.buttons.download;\n\n // Bail if no button\n if (!is.element(button)) {\n return;\n }\n\n // Set download link\n button.setAttribute('href', this.download);\n },\n\n // Build the default HTML\n // TODO: Set order based on order in the config.controls array?\n create(data) {\n // Create the container\n const container = createElement('div', getAttributesFromSelector(this.config.selectors.controls.wrapper));\n\n // Restart button\n if (this.config.controls.includes('restart')) {\n container.appendChild(controls.createButton.call(this, 'restart'));\n }\n\n // Rewind button\n if (this.config.controls.includes('rewind')) {\n container.appendChild(controls.createButton.call(this, 'rewind'));\n }\n\n // Play/Pause button\n if (this.config.controls.includes('play')) {\n container.appendChild(controls.createButton.call(this, 'play'));\n }\n\n // Fast forward button\n if (this.config.controls.includes('fast-forward')) {\n container.appendChild(controls.createButton.call(this, 'fast-forward'));\n }\n\n // Progress\n if (this.config.controls.includes('progress')) {\n const progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress));\n\n // Seek range slider\n progress.appendChild(\n controls.createRange.call(this, 'seek', {\n id: `plyr-seek-${data.id}`,\n }),\n );\n\n // Buffer progress\n progress.appendChild(controls.createProgress.call(this, 'buffer'));\n\n // TODO: Add loop display indicator\n\n // Seek tooltip\n if (this.config.tooltips.seek) {\n const tooltip = createElement(\n 'span',\n {\n class: this.config.classNames.tooltip,\n },\n '00:00',\n );\n\n progress.appendChild(tooltip);\n this.elements.display.seekTooltip = tooltip;\n }\n\n this.elements.progress = progress;\n container.appendChild(this.elements.progress);\n }\n\n // Media current time display\n if (this.config.controls.includes('current-time')) {\n container.appendChild(controls.createTime.call(this, 'currentTime'));\n }\n\n // Media duration display\n if (this.config.controls.includes('duration')) {\n container.appendChild(controls.createTime.call(this, 'duration'));\n }\n\n // Volume controls\n if (this.config.controls.includes('mute') || this.config.controls.includes('volume')) {\n const volume = createElement('div', {\n class: 'plyr__volume',\n });\n\n // Toggle mute button\n if (this.config.controls.includes('mute')) {\n volume.appendChild(controls.createButton.call(this, 'mute'));\n }\n\n // Volume range control\n if (this.config.controls.includes('volume')) {\n // Set the attributes\n const attributes = {\n max: 1,\n step: 0.05,\n value: this.config.volume,\n };\n\n // Create the volume range slider\n volume.appendChild(\n controls.createRange.call(\n this,\n 'volume',\n extend(attributes, {\n id: `plyr-volume-${data.id}`,\n }),\n ),\n );\n\n this.elements.volume = volume;\n }\n\n container.appendChild(volume);\n }\n\n // Toggle captions button\n if (this.config.controls.includes('captions')) {\n container.appendChild(controls.createButton.call(this, 'captions'));\n }\n\n // Settings button / menu\n if (this.config.controls.includes('settings') && !is.empty(this.config.settings)) {\n const control = createElement('div', {\n class: 'plyr__menu',\n hidden: '',\n });\n\n control.appendChild(\n controls.createButton.call(this, 'settings', {\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}`,\n 'aria-expanded': false,\n }),\n );\n\n const popup = createElement('div', {\n class: 'plyr__menu__container',\n id: `plyr-settings-${data.id}`,\n hidden: '',\n });\n\n const inner = createElement('div');\n\n const home = createElement('div', {\n id: `plyr-settings-${data.id}-home`,\n });\n\n // Create the menu\n const menu = createElement('div', {\n role: 'menu',\n });\n\n home.appendChild(menu);\n inner.appendChild(home);\n this.elements.settings.panels.home = home;\n\n // Build the menu items\n this.config.settings.forEach(type => {\n // TODO: bundle this with the createMenuItem helper and bindings\n const menuItem = createElement(\n 'button',\n extend(getAttributesFromSelector(this.config.selectors.buttons.settings), {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`,\n role: 'menuitem',\n 'aria-haspopup': true,\n hidden: '',\n }),\n );\n\n // Bind menu shortcuts for keyboard users\n controls.bindMenuItemShortcuts.call(this, menuItem, type);\n\n // Show menu on click\n on(menuItem, 'click', () => {\n controls.showMenuPanel.call(this, type, false);\n });\n\n const flex = createElement('span', null, i18n.get(type, this.config));\n\n const value = createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n // Speed contains HTML entities\n value.innerHTML = data[type];\n\n flex.appendChild(value);\n menuItem.appendChild(flex);\n menu.appendChild(menuItem);\n\n // Build the panes\n const pane = createElement('div', {\n id: `plyr-settings-${data.id}-${type}`,\n hidden: '',\n });\n\n // Back button\n const backButton = createElement('button', {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--back`,\n });\n\n // Visible label\n backButton.appendChild(\n createElement(\n 'span',\n {\n 'aria-hidden': true,\n },\n i18n.get(type, this.config),\n ),\n );\n\n // Screen reader label\n backButton.appendChild(\n createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n i18n.get('menuBack', this.config),\n ),\n );\n\n // Go back via keyboard\n on(\n pane,\n 'keydown',\n event => {\n // We only care about <-\n if (event.which !== 37) {\n return;\n }\n\n // Prevent seek\n event.preventDefault();\n event.stopPropagation();\n\n // Show the respective menu\n controls.showMenuPanel.call(this, 'home', true);\n },\n false,\n );\n\n // Go back via button click\n on(backButton, 'click', () => {\n controls.showMenuPanel.call(this, 'home', false);\n });\n\n // Add to pane\n pane.appendChild(backButton);\n\n // Menu\n pane.appendChild(\n createElement('div', {\n role: 'menu',\n }),\n );\n\n inner.appendChild(pane);\n\n this.elements.settings.buttons[type] = menuItem;\n this.elements.settings.panels[type] = pane;\n });\n\n popup.appendChild(inner);\n control.appendChild(popup);\n container.appendChild(control);\n\n this.elements.settings.popup = popup;\n this.elements.settings.menu = control;\n }\n\n // Picture in picture button\n if (this.config.controls.includes('pip') && support.pip) {\n container.appendChild(controls.createButton.call(this, 'pip'));\n }\n\n // Airplay button\n if (this.config.controls.includes('airplay') && support.airplay) {\n container.appendChild(controls.createButton.call(this, 'airplay'));\n }\n\n // Download button\n if (this.config.controls.includes('download')) {\n const attributes = {\n element: 'a',\n href: this.download,\n target: '_blank',\n };\n\n const { download } = this.config.urls;\n\n if (!is.url(download) && this.isEmbed) {\n extend(attributes, {\n icon: `logo-${this.provider}`,\n label: this.provider,\n });\n }\n\n container.appendChild(controls.createButton.call(this, 'download', attributes));\n }\n\n // Toggle fullscreen button\n if (this.config.controls.includes('fullscreen')) {\n container.appendChild(controls.createButton.call(this, 'fullscreen'));\n }\n\n // Larger overlaid play button\n if (this.config.controls.includes('play-large')) {\n this.elements.container.appendChild(controls.createButton.call(this, 'play-large'));\n }\n\n this.elements.controls = container;\n\n // Set available quality levels\n if (this.isHTML5) {\n controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));\n }\n\n controls.setSpeedMenu.call(this);\n\n return container;\n },\n\n // Insert controls\n inject() {\n // Sprite\n if (this.config.loadSprite) {\n const icon = controls.getIconUrl.call(this);\n\n // Only load external sprite using AJAX\n if (icon.cors) {\n loadSprite(icon.url, 'sprite-plyr');\n }\n }\n\n // Create a unique ID\n this.id = Math.floor(Math.random() * 10000);\n\n // Null by default\n let container = null;\n this.elements.controls = null;\n\n // Set template properties\n const props = {\n id: this.id,\n seektime: this.config.seekTime,\n title: this.config.title,\n };\n let update = true;\n\n // If function, run it and use output\n if (is.function(this.config.controls)) {\n this.config.controls = this.config.controls.call(this.props);\n }\n\n // Convert falsy controls to empty array (primarily for empty strings)\n if (!this.config.controls) {\n this.config.controls = [];\n }\n\n if (is.element(this.config.controls) || is.string(this.config.controls)) {\n // HTMLElement or Non-empty string passed as the option\n container = this.config.controls;\n } else {\n // Create controls\n container = controls.create.call(this, {\n id: this.id,\n seektime: this.config.seekTime,\n speed: this.speed,\n quality: this.quality,\n captions: captions.getLabel.call(this),\n // TODO: Looping\n // loop: 'None',\n });\n update = false;\n }\n\n // Replace props with their value\n const replace = input => {\n let result = input;\n\n Object.entries(props).forEach(([key, value]) => {\n result = replaceAll(result, `{${key}}`, value);\n });\n\n return result;\n };\n\n // Update markup\n if (update) {\n if (is.string(this.config.controls)) {\n container = replace(container);\n } else if (is.element(container)) {\n container.innerHTML = replace(container.innerHTML);\n }\n }\n\n // Controls container\n let target;\n\n // Inject to custom location\n if (is.string(this.config.selectors.controls.container)) {\n target = document.querySelector(this.config.selectors.controls.container);\n }\n\n // Inject into the container by default\n if (!is.element(target)) {\n target = this.elements.container;\n }\n\n // Inject controls HTML (needs to be before captions, hence \"afterbegin\")\n const insertMethod = is.element(container) ? 'insertAdjacentElement' : 'insertAdjacentHTML';\n target[insertMethod]('afterbegin', container);\n\n // Find the elements if need be\n if (!is.element(this.elements.controls)) {\n controls.findElements.call(this);\n }\n\n // Add pressed property to buttons\n if (!is.empty(this.elements.buttons)) {\n const addProperty = button => {\n const className = this.config.classNames.controlPressed;\n Object.defineProperty(button, 'pressed', {\n enumerable: true,\n get() {\n return hasClass(button, className);\n },\n set(pressed = false) {\n toggleClass(button, className, pressed);\n },\n });\n };\n\n // Toggle classname when pressed property is set\n Object.values(this.elements.buttons)\n .filter(Boolean)\n .forEach(button => {\n if (is.array(button) || is.nodeList(button)) {\n Array.from(button).filter(Boolean).forEach(addProperty);\n } else {\n addProperty(button);\n }\n });\n }\n\n // Edge sometimes doesn't finish the paint so force a redraw\n if (window.navigator.userAgent.includes('Edge')) {\n repaint(target);\n }\n\n // Setup tooltips\n if (this.config.tooltips.controls) {\n const { classNames, selectors } = this.config;\n const selector = `${selectors.controls.wrapper} ${selectors.labels} .${classNames.hidden}`;\n const labels = getElements.call(this, selector);\n\n Array.from(labels).forEach(label => {\n toggleClass(label, this.config.classNames.hidden, false);\n toggleClass(label, this.config.classNames.tooltip, true);\n });\n }\n },\n};\n\nexport default controls;\n","// ==========================================================================\n// URL utils\n// ==========================================================================\n\nimport is from './is';\n\n/**\n * Parse a string to a URL object\n * @param {string} input - the URL to be parsed\n * @param {boolean} safe - failsafe parsing\n */\nexport function parseUrl(input, safe = true) {\n let url = input;\n\n if (safe) {\n const parser = document.createElement('a');\n parser.href = url;\n url = parser.href;\n }\n\n try {\n return new URL(url);\n } catch (e) {\n return null;\n }\n}\n\n// Convert object to URLSearchParams\nexport function buildUrlParams(input) {\n const params = new URLSearchParams();\n\n if (is.object(input)) {\n Object.entries(input).forEach(([key, value]) => {\n params.set(key, value);\n });\n }\n\n return params;\n}\n","// ==========================================================================\n// Plyr Captions\n// TODO: Create as class\n// ==========================================================================\n\nimport controls from './controls';\nimport support from './support';\nimport { dedupe } from './utils/arrays';\nimport browser from './utils/browser';\nimport {\n createElement,\n emptyElement,\n getAttributesFromSelector,\n insertAfter,\n removeElement,\n toggleClass,\n} from './utils/elements';\nimport { on, triggerEvent } from './utils/events';\nimport fetch from './utils/fetch';\nimport i18n from './utils/i18n';\nimport is from './utils/is';\nimport { getHTML } from './utils/strings';\nimport { parseUrl } from './utils/urls';\n\nconst captions = {\n // Setup captions\n setup() {\n // Requires UI support\n if (!this.supported.ui) {\n return;\n }\n\n // Only Vimeo and HTML5 video supported at this point\n if (!this.isVideo || this.isYouTube || (this.isHTML5 && !support.textTracks)) {\n // Clear menu and hide\n if (\n is.array(this.config.controls) &&\n this.config.controls.includes('settings') &&\n this.config.settings.includes('captions')\n ) {\n controls.setCaptionsMenu.call(this);\n }\n\n return;\n }\n\n // Inject the container\n if (!is.element(this.elements.captions)) {\n this.elements.captions = createElement('div', getAttributesFromSelector(this.config.selectors.captions));\n\n insertAfter(this.elements.captions, this.elements.wrapper);\n }\n\n // Fix IE captions if CORS is used\n // Fetch captions and inject as blobs instead (data URIs not supported!)\n if (browser.isIE && window.URL) {\n const elements = this.media.querySelectorAll('track');\n\n Array.from(elements).forEach(track => {\n const src = track.getAttribute('src');\n const url = parseUrl(src);\n\n if (\n url !== null &&\n url.hostname !== window.location.href.hostname &&\n ['http:', 'https:'].includes(url.protocol)\n ) {\n fetch(src, 'blob')\n .then(blob => {\n track.setAttribute('src', window.URL.createObjectURL(blob));\n })\n .catch(() => {\n removeElement(track);\n });\n }\n });\n }\n\n // Get and set initial data\n // The \"preferred\" options are not realized unless / until the wanted language has a match\n // * languages: Array of user's browser languages.\n // * language: The language preferred by user settings or config\n // * active: The state preferred by user settings or config\n // * toggled: The real captions state\n\n const browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];\n const languages = dedupe(browserLanguages.map(language => language.split('-')[0]));\n\n let language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase();\n\n // Use first browser language when language is 'auto'\n if (language === 'auto') {\n [language] = languages;\n }\n\n let active = this.storage.get('captions');\n if (!is.boolean(active)) {\n ({ active } = this.config.captions);\n }\n\n Object.assign(this.captions, {\n toggled: false,\n active,\n language,\n languages,\n });\n\n // Watch changes to textTracks and update captions menu\n if (this.isHTML5) {\n const trackEvents = this.config.captions.update ? 'addtrack removetrack' : 'removetrack';\n on.call(this, this.media.textTracks, trackEvents, captions.update.bind(this));\n }\n\n // Update available languages in list next tick (the event must not be triggered before the listeners)\n setTimeout(captions.update.bind(this), 0);\n },\n\n // Update available language options in settings based on tracks\n update() {\n const tracks = captions.getTracks.call(this, true);\n // Get the wanted language\n const { active, language, meta, currentTrackNode } = this.captions;\n const languageExists = Boolean(tracks.find(track => track.language === language));\n\n // Handle tracks (add event listener and \"pseudo\"-default)\n if (this.isHTML5 && this.isVideo) {\n tracks.filter(track => !meta.get(track)).forEach(track => {\n this.debug.log('Track added', track);\n // Attempt to store if the original dom element was \"default\"\n meta.set(track, {\n default: track.mode === 'showing',\n });\n\n // Turn off native caption rendering to avoid double captions\n track.mode = 'hidden';\n\n // Add event listener for cue changes\n on.call(this, track, 'cuechange', () => captions.updateCues.call(this));\n });\n }\n\n // Update language first time it matches, or if the previous matching track was removed\n if ((languageExists && this.language !== language) || !tracks.includes(currentTrackNode)) {\n captions.setLanguage.call(this, language);\n captions.toggle.call(this, active && languageExists);\n }\n\n // Enable or disable captions based on track length\n toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is.empty(tracks));\n\n // Update available languages in list\n if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n },\n\n // Toggle captions display\n // Used internally for the toggleCaptions method, with the passive option forced to false\n toggle(input, passive = true) {\n // If there's no full support\n if (!this.supported.ui) {\n return;\n }\n\n const { toggled } = this.captions; // Current state\n const activeClass = this.config.classNames.captions.active;\n\n // Get the next state\n // If the method is called without parameter, toggle based on current value\n const active = is.nullOrUndefined(input) ? !toggled : input;\n\n // Update state and trigger event\n if (active !== toggled) {\n // When passive, don't override user preferences\n if (!passive) {\n this.captions.active = active;\n this.storage.set({ captions: active });\n }\n\n // Force language if the call isn't passive and there is no matching language to toggle to\n if (!this.language && active && !passive) {\n const tracks = captions.getTracks.call(this);\n const track = captions.findTrack.call(this, [this.captions.language, ...this.captions.languages], true);\n\n // Override user preferences to avoid switching languages if a matching track is added\n this.captions.language = track.language;\n\n // Set caption, but don't store in localStorage as user preference\n captions.set.call(this, tracks.indexOf(track));\n return;\n }\n\n // Toggle button if it's enabled\n if (this.elements.buttons.captions) {\n this.elements.buttons.captions.pressed = active;\n }\n\n // Add class hook\n toggleClass(this.elements.container, activeClass, active);\n\n this.captions.toggled = active;\n\n // Update settings menu\n controls.updateSetting.call(this, 'captions');\n\n // Trigger event (not used internally)\n triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled');\n }\n },\n\n // Set captions by track index\n // Used internally for the currentTrack setter with the passive option forced to false\n set(index, passive = true) {\n const tracks = captions.getTracks.call(this);\n\n // Disable captions if setting to -1\n if (index === -1) {\n captions.toggle.call(this, false, passive);\n return;\n }\n\n if (!is.number(index)) {\n this.debug.warn('Invalid caption argument', index);\n return;\n }\n\n if (!(index in tracks)) {\n this.debug.warn('Track not found', index);\n return;\n }\n\n if (this.captions.currentTrack !== index) {\n this.captions.currentTrack = index;\n const track = tracks[index];\n const { language } = track || {};\n\n // Store reference to node for invalidation on remove\n this.captions.currentTrackNode = track;\n\n // Update settings menu\n controls.updateSetting.call(this, 'captions');\n\n // When passive, don't override user preferences\n if (!passive) {\n this.captions.language = language;\n this.storage.set({ language });\n }\n\n // Handle Vimeo captions\n if (this.isVimeo) {\n this.embed.enableTextTrack(language);\n }\n\n // Trigger event\n triggerEvent.call(this, this.media, 'languagechange');\n }\n\n // Show captions\n captions.toggle.call(this, true, passive);\n\n if (this.isHTML5 && this.isVideo) {\n // If we change the active track while a cue is already displayed we need to update it\n captions.updateCues.call(this);\n }\n },\n\n // Set captions by language\n // Used internally for the language setter with the passive option forced to false\n setLanguage(input, passive = true) {\n if (!is.string(input)) {\n this.debug.warn('Invalid language argument', input);\n return;\n }\n // Normalize\n const language = input.toLowerCase();\n this.captions.language = language;\n\n // Set currentTrack\n const tracks = captions.getTracks.call(this);\n const track = captions.findTrack.call(this, [language]);\n captions.set.call(this, tracks.indexOf(track), passive);\n },\n\n // Get current valid caption tracks\n // If update is false it will also ignore tracks without metadata\n // This is used to \"freeze\" the language options when captions.update is false\n getTracks(update = false) {\n // Handle media or textTracks missing or null\n const tracks = Array.from((this.media || {}).textTracks || []);\n // For HTML5, use cache instead of current tracks when it exists (if captions.update is false)\n // Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)\n return tracks\n .filter(track => !this.isHTML5 || update || this.captions.meta.has(track))\n .filter(track => ['captions', 'subtitles'].includes(track.kind));\n },\n\n // Match tracks based on languages and get the first\n findTrack(languages, force = false) {\n const tracks = captions.getTracks.call(this);\n const sortIsDefault = track => Number((this.captions.meta.get(track) || {}).default);\n const sorted = Array.from(tracks).sort((a, b) => sortIsDefault(b) - sortIsDefault(a));\n let track;\n languages.every(language => {\n track = sorted.find(track => track.language === language);\n return !track; // Break iteration if there is a match\n });\n // If no match is found but is required, get first\n return track || (force ? sorted[0] : undefined);\n },\n\n // Get the current track\n getCurrentTrack() {\n return captions.getTracks.call(this)[this.currentTrack];\n },\n\n // Get UI label for track\n getLabel(track) {\n let currentTrack = track;\n\n if (!is.track(currentTrack) && support.textTracks && this.captions.toggled) {\n currentTrack = captions.getCurrentTrack.call(this);\n }\n\n if (is.track(currentTrack)) {\n if (!is.empty(currentTrack.label)) {\n return currentTrack.label;\n }\n\n if (!is.empty(currentTrack.language)) {\n return track.language.toUpperCase();\n }\n\n return i18n.get('enabled', this.config);\n }\n\n return i18n.get('disabled', this.config);\n },\n\n // Update captions using current track's active cues\n // Also optional array argument in case there isn't any track (ex: vimeo)\n updateCues(input) {\n // Requires UI\n if (!this.supported.ui) {\n return;\n }\n\n if (!is.element(this.elements.captions)) {\n this.debug.warn('No captions element to render to');\n return;\n }\n\n // Only accept array or empty input\n if (!is.nullOrUndefined(input) && !Array.isArray(input)) {\n this.debug.warn('updateCues: Invalid input', input);\n return;\n }\n\n let cues = input;\n\n // Get cues from track\n if (!cues) {\n const track = captions.getCurrentTrack.call(this);\n cues = Array.from((track || {}).activeCues || [])\n .map(cue => cue.getCueAsHTML())\n .map(getHTML);\n }\n\n // Set new caption text\n const content = cues.map(cueText => cueText.trim()).join('\\n');\n const changed = content !== this.elements.captions.innerHTML;\n\n if (changed) {\n // Empty the container and create a new child element\n emptyElement(this.elements.captions);\n const caption = createElement('span', getAttributesFromSelector(this.config.selectors.caption));\n caption.innerHTML = content;\n this.elements.captions.appendChild(caption);\n\n // Trigger event\n triggerEvent.call(this, this.media, 'cuechange');\n }\n },\n};\n\nexport default captions;\n","// ==========================================================================\n// Plyr default config\n// ==========================================================================\n\nconst defaults = {\n // Disable\n enabled: true,\n\n // Custom media title\n title: '',\n\n // Logging to console\n debug: false,\n\n // Auto play (if supported)\n autoplay: false,\n\n // Only allow one media playing at once (vimeo only)\n autopause: true,\n\n // Allow inline playback on iOS (this effects YouTube/Vimeo - HTML5 requires the attribute present)\n // TODO: Remove iosNative fullscreen option in favour of this (logic needs work)\n playsinline: true,\n\n // Default time to skip when rewind/fast forward\n seekTime: 10,\n\n // Default volume\n volume: 1,\n muted: false,\n\n // Pass a custom duration\n duration: null,\n\n // Display the media duration on load in the current time position\n // If you have opted to display both duration and currentTime, this is ignored\n displayDuration: true,\n\n // Invert the current time to be a countdown\n invertTime: true,\n\n // Clicking the currentTime inverts it's value to show time left rather than elapsed\n toggleInvert: true,\n\n // Aspect ratio (for embeds)\n ratio: '16:9',\n\n // Click video container to play/pause\n clickToPlay: true,\n\n // Auto hide the controls\n hideControls: true,\n\n // Reset to start when playback ended\n resetOnEnd: false,\n\n // Disable the standard context menu\n disableContextMenu: true,\n\n // Sprite (for icons)\n loadSprite: true,\n iconPrefix: 'plyr',\n iconUrl: 'https://cdn.plyr.io/3.3.12/plyr.svg',\n\n // Blank video (used to prevent errors on source change)\n blankVideo: 'https://cdn.plyr.io/static/blank.mp4',\n\n // Quality default\n quality: {\n default: 576,\n options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240],\n },\n\n // Set loops\n loop: {\n active: false,\n // start: null,\n // end: null,\n },\n\n // Speed default and options to display\n speed: {\n selected: 1,\n options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],\n },\n\n // Keyboard shortcut settings\n keyboard: {\n focused: true,\n global: false,\n },\n\n // Display tooltips\n tooltips: {\n controls: false,\n seek: true,\n },\n\n // Captions settings\n captions: {\n active: false,\n language: 'auto',\n // Listen to new tracks added after Plyr is initialized.\n // This is needed for streaming captions, but may result in unselectable options\n update: false,\n },\n\n // Fullscreen settings\n fullscreen: {\n enabled: true, // Allow fullscreen?\n fallback: true, // Fallback for vintage browsers\n iosNative: false, // Use the native fullscreen in iOS (disables custom controls)\n },\n\n // Local storage\n storage: {\n enabled: true,\n key: 'plyr',\n },\n\n // Default controls\n controls: [\n 'play-large',\n // 'restart',\n // 'rewind',\n 'play',\n // 'fast-forward',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'pip',\n 'airplay',\n // 'download',\n 'fullscreen',\n ],\n settings: ['captions', 'quality', 'speed'],\n\n // Localisation\n i18n: {\n restart: 'Restart',\n rewind: 'Rewind {seektime}s',\n play: 'Play',\n pause: 'Pause',\n fastForward: 'Forward {seektime}s',\n seek: 'Seek',\n seekLabel: '{currentTime} of {duration}',\n played: 'Played',\n buffered: 'Buffered',\n currentTime: 'Current time',\n duration: 'Duration',\n volume: 'Volume',\n mute: 'Mute',\n unmute: 'Unmute',\n enableCaptions: 'Enable captions',\n disableCaptions: 'Disable captions',\n download: 'Download',\n enterFullscreen: 'Enter fullscreen',\n exitFullscreen: 'Exit fullscreen',\n frameTitle: 'Player for {title}',\n captions: 'Captions',\n settings: 'Settings',\n menuBack: 'Go back to previous menu',\n speed: 'Speed',\n normal: 'Normal',\n quality: 'Quality',\n loop: 'Loop',\n start: 'Start',\n end: 'End',\n all: 'All',\n reset: 'Reset',\n disabled: 'Disabled',\n enabled: 'Enabled',\n advertisement: 'Ad',\n qualityBadge: {\n 2160: '4K',\n 1440: 'HD',\n 1080: 'HD',\n 720: 'HD',\n 576: 'SD',\n 480: 'SD',\n },\n },\n\n // URLs\n urls: {\n download: null,\n vimeo: {\n sdk: 'https://player.vimeo.com/api/player.js',\n iframe: 'https://player.vimeo.com/video/{0}?{1}',\n api: 'https://vimeo.com/api/v2/video/{0}.json',\n },\n youtube: {\n sdk: 'https://www.youtube.com/iframe_api',\n api:\n 'https://www.googleapis.com/youtube/v3/videos?id={0}&key={1}&fields=items(snippet(title))&part=snippet',\n },\n googleIMA: {\n sdk: 'https://imasdk.googleapis.com/js/sdkloader/ima3.js',\n },\n },\n\n // Custom control listeners\n listeners: {\n seek: null,\n play: null,\n pause: null,\n restart: null,\n rewind: null,\n fastForward: null,\n mute: null,\n volume: null,\n captions: null,\n download: null,\n fullscreen: null,\n pip: null,\n airplay: null,\n speed: null,\n quality: null,\n loop: null,\n language: null,\n },\n\n // Events to watch and bubble\n events: [\n // Events to watch on HTML5 media elements and bubble\n // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events\n 'ended',\n 'progress',\n 'stalled',\n 'playing',\n 'waiting',\n 'canplay',\n 'canplaythrough',\n 'loadstart',\n 'loadeddata',\n 'loadedmetadata',\n 'timeupdate',\n 'volumechange',\n 'play',\n 'pause',\n 'error',\n 'seeking',\n 'seeked',\n 'emptied',\n 'ratechange',\n 'cuechange',\n\n // Custom events\n 'download',\n 'enterfullscreen',\n 'exitfullscreen',\n 'captionsenabled',\n 'captionsdisabled',\n 'languagechange',\n 'controlshidden',\n 'controlsshown',\n 'ready',\n\n // YouTube\n 'statechange',\n\n // Quality\n 'qualitychange',\n\n // Ads\n 'adsloaded',\n 'adscontentpause',\n 'adscontentresume',\n 'adstarted',\n 'adsmidpoint',\n 'adscomplete',\n 'adsallcomplete',\n 'adsimpression',\n 'adsclick',\n ],\n\n // Selectors\n // Change these to match your template if using custom HTML\n selectors: {\n editable: 'input, textarea, select, [contenteditable]',\n container: '.plyr',\n controls: {\n container: null,\n wrapper: '.plyr__controls',\n },\n labels: '[data-plyr]',\n buttons: {\n play: '[data-plyr=\"play\"]',\n pause: '[data-plyr=\"pause\"]',\n restart: '[data-plyr=\"restart\"]',\n rewind: '[data-plyr=\"rewind\"]',\n fastForward: '[data-plyr=\"fast-forward\"]',\n mute: '[data-plyr=\"mute\"]',\n captions: '[data-plyr=\"captions\"]',\n download: '[data-plyr=\"download\"]',\n fullscreen: '[data-plyr=\"fullscreen\"]',\n pip: '[data-plyr=\"pip\"]',\n airplay: '[data-plyr=\"airplay\"]',\n settings: '[data-plyr=\"settings\"]',\n loop: '[data-plyr=\"loop\"]',\n },\n inputs: {\n seek: '[data-plyr=\"seek\"]',\n volume: '[data-plyr=\"volume\"]',\n speed: '[data-plyr=\"speed\"]',\n language: '[data-plyr=\"language\"]',\n quality: '[data-plyr=\"quality\"]',\n },\n display: {\n currentTime: '.plyr__time--current',\n duration: '.plyr__time--duration',\n buffer: '.plyr__progress__buffer',\n loop: '.plyr__progress__loop', // Used later\n volume: '.plyr__volume--display',\n },\n progress: '.plyr__progress',\n captions: '.plyr__captions',\n caption: '.plyr__caption',\n menu: {\n quality: '.js-plyr__menu__list--quality',\n },\n },\n\n // Class hooks added to the player in different states\n classNames: {\n type: 'plyr--{0}',\n provider: 'plyr--{0}',\n video: 'plyr__video-wrapper',\n embed: 'plyr__video-embed',\n embedContainer: 'plyr__video-embed__container',\n poster: 'plyr__poster',\n posterEnabled: 'plyr__poster-enabled',\n ads: 'plyr__ads',\n control: 'plyr__control',\n controlPressed: 'plyr__control--pressed',\n playing: 'plyr--playing',\n paused: 'plyr--paused',\n stopped: 'plyr--stopped',\n loading: 'plyr--loading',\n hover: 'plyr--hover',\n tooltip: 'plyr__tooltip',\n cues: 'plyr__cues',\n hidden: 'plyr__sr-only',\n hideControls: 'plyr--hide-controls',\n isIos: 'plyr--is-ios',\n isTouch: 'plyr--is-touch',\n uiSupported: 'plyr--full-ui',\n noTransition: 'plyr--no-transition',\n display: {\n time: 'plyr__time',\n },\n menu: {\n value: 'plyr__menu__value',\n badge: 'plyr__badge',\n open: 'plyr--menu-open',\n },\n captions: {\n enabled: 'plyr--captions-enabled',\n active: 'plyr--captions-active',\n },\n fullscreen: {\n enabled: 'plyr--fullscreen-enabled',\n fallback: 'plyr--fullscreen-fallback',\n },\n pip: {\n supported: 'plyr--pip-supported',\n active: 'plyr--pip-active',\n },\n airplay: {\n supported: 'plyr--airplay-supported',\n active: 'plyr--airplay-active',\n },\n tabFocus: 'plyr__tab-focus',\n },\n\n // Embed attributes\n attributes: {\n embed: {\n provider: 'data-plyr-provider',\n id: 'data-plyr-embed-id',\n },\n },\n\n // API keys\n keys: {\n google: null,\n },\n\n // Advertisements plugin\n // Register for an account here: http://vi.ai/publisher-video-monetization/?aid=plyrio\n ads: {\n enabled: false,\n publisherId: '',\n },\n};\n\nexport default defaults;\n","// ==========================================================================\n// Plyr supported types and providers\n// ==========================================================================\n\nexport const providers = {\n html5: 'html5',\n youtube: 'youtube',\n vimeo: 'vimeo',\n};\n\nexport const types = {\n audio: 'audio',\n video: 'video',\n};\n\n/**\n * Get provider by URL\n * @param {String} url\n */\nexport function getProviderByUrl(url) {\n // YouTube\n if (/^(https?:\\/\\/)?(www\\.)?(youtube\\.com|youtu\\.?be)\\/.+$/.test(url)) {\n return providers.youtube;\n }\n\n // Vimeo\n if (/^https?:\\/\\/player.vimeo.com\\/video\\/\\d{0,9}(?=\\b|\\/)/.test(url)) {\n return providers.vimeo;\n }\n\n return null;\n}\n\nexport default { providers, types };\n","// ==========================================================================\n// Console wrapper\n// ==========================================================================\n\nconst noop = () => {};\n\nexport default class Console {\n constructor(enabled = false) {\n this.enabled = window.console && enabled;\n\n if (this.enabled) {\n this.log('Debugging enabled');\n }\n }\n\n get log() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.log, console) : noop;\n }\n\n get warn() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.warn, console) : noop;\n }\n\n get error() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.error, console) : noop;\n }\n}\n","// ==========================================================================\n// Fullscreen wrapper\n// https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API#prefixing\n// https://webkit.org/blog/7929/designing-websites-for-iphone-x/\n// ==========================================================================\n\nimport { repaint } from './utils/animation';\nimport browser from './utils/browser';\nimport { hasClass, toggleClass, trapFocus } from './utils/elements';\nimport { on, triggerEvent } from './utils/events';\nimport is from './utils/is';\n\nfunction onChange() {\n if (!this.enabled) {\n return;\n }\n\n // Update toggle button\n const button = this.player.elements.buttons.fullscreen;\n if (is.element(button)) {\n button.pressed = this.active;\n }\n\n // Trigger an event\n triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);\n\n // Trap focus in container\n if (!browser.isIos) {\n trapFocus.call(this.player, this.target, this.active);\n }\n}\n\nfunction toggleFallback(toggle = false) {\n // Store or restore scroll position\n if (toggle) {\n this.scrollPosition = {\n x: window.scrollX || 0,\n y: window.scrollY || 0,\n };\n } else {\n window.scrollTo(this.scrollPosition.x, this.scrollPosition.y);\n }\n\n // Toggle scroll\n document.body.style.overflow = toggle ? 'hidden' : '';\n\n // Toggle class hook\n toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle);\n\n // Force full viewport on iPhone X+\n if (browser.isIos) {\n let viewport = document.head.querySelector('meta[name=\"viewport\"]');\n const property = 'viewport-fit=cover';\n\n // Inject the viewport meta if required\n if (!viewport) {\n viewport = document.createElement('meta');\n viewport.setAttribute('name', 'viewport');\n }\n\n // Check if the property already exists\n const hasProperty = is.string(viewport.content) && viewport.content.includes(property);\n\n if (toggle) {\n this.cleanupViewport = !hasProperty;\n\n if (!hasProperty) {\n viewport.content += `,${property}`;\n }\n } else if (this.cleanupViewport) {\n viewport.content = viewport.content\n .split(',')\n .filter(part => part.trim() !== property)\n .join(',');\n }\n\n // Force a repaint as sometimes Safari doesn't want to fill the screen\n setTimeout(() => repaint(this.target), 100);\n }\n\n // Toggle button and fire events\n onChange.call(this);\n}\n\nclass Fullscreen {\n constructor(player) {\n // Keep reference to parent\n this.player = player;\n\n // Get prefix\n this.prefix = Fullscreen.prefix;\n this.property = Fullscreen.property;\n\n // Scroll position\n this.scrollPosition = { x: 0, y: 0 };\n\n // Register event listeners\n // Handle event (incase user presses escape etc)\n on.call(\n this.player,\n document,\n this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`,\n () => {\n // TODO: Filter for target??\n onChange.call(this);\n },\n );\n\n // Fullscreen toggle on double click\n on.call(this.player, this.player.elements.container, 'dblclick', event => {\n // Ignore double click in controls\n if (is.element(this.player.elements.controls) && this.player.elements.controls.contains(event.target)) {\n return;\n }\n\n this.toggle();\n });\n\n // Update the UI\n this.update();\n }\n\n // Determine if native supported\n static get native() {\n return !!(\n document.fullscreenEnabled ||\n document.webkitFullscreenEnabled ||\n document.mozFullScreenEnabled ||\n document.msFullscreenEnabled\n );\n }\n\n // Get the prefix for handlers\n static get prefix() {\n // No prefix\n if (is.function(document.exitFullscreen)) {\n return '';\n }\n\n // Check for fullscreen support by vendor prefix\n let value = '';\n const prefixes = ['webkit', 'moz', 'ms'];\n\n prefixes.some(pre => {\n if (is.function(document[`${pre}ExitFullscreen`]) || is.function(document[`${pre}CancelFullScreen`])) {\n value = pre;\n return true;\n }\n\n return false;\n });\n\n return value;\n }\n\n static get property() {\n return this.prefix === 'moz' ? 'FullScreen' : 'Fullscreen';\n }\n\n // Determine if fullscreen is enabled\n get enabled() {\n return (\n (Fullscreen.native || this.player.config.fullscreen.fallback) &&\n this.player.config.fullscreen.enabled &&\n this.player.supported.ui &&\n this.player.isVideo\n );\n }\n\n // Get active state\n get active() {\n if (!this.enabled) {\n return false;\n }\n\n // Fallback using classname\n if (!Fullscreen.native) {\n return hasClass(this.target, this.player.config.classNames.fullscreen.fallback);\n }\n\n const element = !this.prefix ? document.fullscreenElement : document[`${this.prefix}${this.property}Element`];\n\n return element === this.target;\n }\n\n // Get target element\n get target() {\n return browser.isIos && this.player.config.fullscreen.iosNative\n ? this.player.media\n : this.player.elements.container;\n }\n\n // Update UI\n update() {\n if (this.enabled) {\n this.player.debug.log(`${Fullscreen.native ? 'Native' : 'Fallback'} fullscreen enabled`);\n } else {\n this.player.debug.log('Fullscreen not supported and fallback disabled');\n }\n\n // Add styling hook to show button\n toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.enabled);\n }\n\n // Make an element fullscreen\n enter() {\n if (!this.enabled) {\n return;\n }\n\n // iOS native fullscreen doesn't need the request step\n if (browser.isIos && this.player.config.fullscreen.iosNative) {\n this.target.webkitEnterFullscreen();\n } else if (!Fullscreen.native) {\n toggleFallback.call(this, true);\n } else if (!this.prefix) {\n this.target.requestFullscreen();\n } else if (!is.empty(this.prefix)) {\n this.target[`${this.prefix}Request${this.property}`]();\n }\n }\n\n // Bail from fullscreen\n exit() {\n if (!this.enabled) {\n return;\n }\n\n // iOS native fullscreen\n if (browser.isIos && this.player.config.fullscreen.iosNative) {\n this.target.webkitExitFullscreen();\n this.player.play();\n } else if (!Fullscreen.native) {\n toggleFallback.call(this, false);\n } else if (!this.prefix) {\n (document.cancelFullScreen || document.exitFullscreen).call(document);\n } else if (!is.empty(this.prefix)) {\n const action = this.prefix === 'moz' ? 'Cancel' : 'Exit';\n document[`${this.prefix}${action}${this.property}`]();\n }\n }\n\n // Toggle state\n toggle() {\n if (!this.active) {\n this.enter();\n } else {\n this.exit();\n }\n }\n}\n\nexport default Fullscreen;\n","// ==========================================================================\n// Load image avoiding xhr/fetch CORS issues\n// Server status can't be obtained this way unfortunately, so this uses \"naturalWidth\" to determine if the image has loaded\n// By default it checks if it is at least 1px, but you can add a second argument to change this\n// ==========================================================================\n\nexport default function loadImage(src, minWidth = 1) {\n return new Promise((resolve, reject) => {\n const image = new Image();\n\n const handler = () => {\n delete image.onload;\n delete image.onerror;\n (image.naturalWidth >= minWidth ? resolve : reject)(image);\n };\n\n Object.assign(image, { onload: handler, onerror: handler, src });\n });\n}\n","// ==========================================================================\n// Plyr UI\n// ==========================================================================\n\nimport captions from './captions';\nimport controls from './controls';\nimport support from './support';\nimport browser from './utils/browser';\nimport { getElement, toggleClass } from './utils/elements';\nimport { ready, triggerEvent } from './utils/events';\nimport i18n from './utils/i18n';\nimport is from './utils/is';\nimport loadImage from './utils/loadImage';\n\nconst ui = {\n addStyleHook() {\n toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);\n toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui);\n },\n\n // Toggle native HTML5 media controls\n toggleNativeControls(toggle = false) {\n if (toggle && this.isHTML5) {\n this.media.setAttribute('controls', '');\n } else {\n this.media.removeAttribute('controls');\n }\n },\n\n // Setup the UI\n build() {\n // Re-attach media element listeners\n // TODO: Use event bubbling?\n this.listeners.media();\n\n // Don't setup interface if no support\n if (!this.supported.ui) {\n this.debug.warn(`Basic support only for ${this.provider} ${this.type}`);\n\n // Restore native controls\n ui.toggleNativeControls.call(this, true);\n\n // Bail\n return;\n }\n\n // Inject custom controls if not present\n if (!is.element(this.elements.controls)) {\n // Inject custom controls\n controls.inject.call(this);\n\n // Re-attach control listeners\n this.listeners.controls();\n }\n\n // Remove native controls\n ui.toggleNativeControls.call(this);\n\n // Setup captions for HTML5\n if (this.isHTML5) {\n captions.setup.call(this);\n }\n\n // Reset volume\n this.volume = null;\n\n // Reset mute state\n this.muted = null;\n\n // Reset speed\n this.speed = null;\n\n // Reset loop state\n this.loop = null;\n\n // Reset quality setting\n this.quality = null;\n\n // Reset volume display\n controls.updateVolume.call(this);\n\n // Reset time display\n controls.timeUpdate.call(this);\n\n // Update the UI\n ui.checkPlaying.call(this);\n\n // Check for picture-in-picture support\n toggleClass(\n this.elements.container,\n this.config.classNames.pip.supported,\n support.pip && this.isHTML5 && this.isVideo,\n );\n\n // Check for airplay support\n toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5);\n\n // Add iOS class\n toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);\n\n // Add touch class\n toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch);\n\n // Ready for API calls\n this.ready = true;\n\n // Ready event at end of execution stack\n setTimeout(() => {\n triggerEvent.call(this, this.media, 'ready');\n }, 0);\n\n // Set the title\n ui.setTitle.call(this);\n\n // Assure the poster image is set, if the property was added before the element was created\n if (this.poster) {\n ui.setPoster.call(this, this.poster, false).catch(() => {});\n }\n\n // Manually set the duration if user has overridden it.\n // The event listeners for it doesn't get called if preload is disabled (#701)\n if (this.config.duration) {\n controls.durationUpdate.call(this);\n }\n },\n\n // Setup aria attribute for play and iframe title\n setTitle() {\n // Find the current text\n let label = i18n.get('play', this.config);\n\n // If there's a media title set, use that for the label\n if (is.string(this.config.title) && !is.empty(this.config.title)) {\n label += `, ${this.config.title}`;\n }\n\n // If there's a play button, set label\n Array.from(this.elements.buttons.play || []).forEach(button => {\n button.setAttribute('aria-label', label);\n });\n\n // Set iframe title\n // https://github.com/sampotts/plyr/issues/124\n if (this.isEmbed) {\n const iframe = getElement.call(this, 'iframe');\n\n if (!is.element(iframe)) {\n return;\n }\n\n // Default to media type\n const title = !is.empty(this.config.title) ? this.config.title : 'video';\n const format = i18n.get('frameTitle', this.config);\n\n iframe.setAttribute('title', format.replace('{title}', title));\n }\n },\n\n // Toggle poster\n togglePoster(enable) {\n toggleClass(this.elements.container, this.config.classNames.posterEnabled, enable);\n },\n\n // Set the poster image (async)\n // Used internally for the poster setter, with the passive option forced to false\n setPoster(poster, passive = true) {\n // Don't override if call is passive\n if (passive && this.poster) {\n return Promise.reject(new Error('Poster already set'));\n }\n\n // Set property synchronously to respect the call order\n this.media.setAttribute('poster', poster);\n\n // Wait until ui is ready\n return (\n ready\n .call(this)\n // Load image\n .then(() => loadImage(poster))\n .catch(err => {\n // Hide poster on error unless it's been set by another call\n if (poster === this.poster) {\n ui.togglePoster.call(this, false);\n }\n // Rethrow\n throw err;\n })\n .then(() => {\n // Prevent race conditions\n if (poster !== this.poster) {\n throw new Error('setPoster cancelled by later call to setPoster');\n }\n })\n .then(() => {\n Object.assign(this.elements.poster.style, {\n backgroundImage: `url('${poster}')`,\n // Reset backgroundSize as well (since it can be set to \"cover\" for padded thumbnails for youtube)\n backgroundSize: '',\n });\n ui.togglePoster.call(this, true);\n return poster;\n })\n );\n },\n\n // Check playing state\n checkPlaying(event) {\n // Class hooks\n toggleClass(this.elements.container, this.config.classNames.playing, this.playing);\n toggleClass(this.elements.container, this.config.classNames.paused, this.paused);\n toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);\n\n // Set state\n Array.from(this.elements.buttons.play || []).forEach(target => {\n target.pressed = this.playing;\n });\n\n // Only update controls on non timeupdate events\n if (is.event(event) && event.type === 'timeupdate') {\n return;\n }\n\n // Toggle controls\n ui.toggleControls.call(this);\n },\n\n // Check if media is loading\n checkLoading(event) {\n this.loading = ['stalled', 'waiting'].includes(event.type);\n\n // Clear timer\n clearTimeout(this.timers.loading);\n\n // Timer to prevent flicker when seeking\n this.timers.loading = setTimeout(() => {\n // Update progress bar loading class state\n toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Update controls visibility\n ui.toggleControls.call(this);\n }, this.loading ? 250 : 0);\n },\n\n // Toggle controls based on state and `force` argument\n toggleControls(force) {\n const { controls } = this.elements;\n\n if (controls && this.config.hideControls) {\n // 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.)\n const recentTouchSeek = (this.touch && this.lastSeekTime + 2000 > Date.now());\n\n // Show controls if force, loading, paused, button interaction, or recent seek, otherwise hide\n this.toggleControls(Boolean(force || this.loading || this.paused || controls.pressed || controls.hover || recentTouchSeek));\n }\n },\n};\n\nexport default ui;\n","// ==========================================================================\n// Plyr Event Listeners\n// ==========================================================================\n\nimport controls from './controls';\nimport ui from './ui';\nimport { repaint } from './utils/animation';\nimport browser from './utils/browser';\nimport { getElement, getElements, matches, toggleClass, toggleHidden } from './utils/elements';\nimport { on, once, toggleListener, triggerEvent } from './utils/events';\nimport is from './utils/is';\n\nclass Listeners {\n constructor(player) {\n this.player = player;\n this.lastKey = null;\n this.focusTimer = null;\n this.lastKeyDown = null;\n\n this.handleKey = this.handleKey.bind(this);\n this.toggleMenu = this.toggleMenu.bind(this);\n this.setTabFocus = this.setTabFocus.bind(this);\n this.firstTouch = this.firstTouch.bind(this);\n }\n\n // Handle key presses\n handleKey(event) {\n const { player } = this;\n const { elements } = player;\n const code = event.keyCode ? event.keyCode : event.which;\n const pressed = event.type === 'keydown';\n const repeat = pressed && code === this.lastKey;\n\n // Bail if a modifier key is set\n if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {\n return;\n }\n\n // If the event is bubbled from the media element\n // Firefox doesn't get the keycode for whatever reason\n if (!is.number(code)) {\n return;\n }\n\n // Seek by the number keys\n const seekByKey = () => {\n // Divide the max duration into 10th's and times by the number value\n player.currentTime = (player.duration / 10) * (code - 48);\n };\n\n // Handle the key on keydown\n // Reset on keyup\n if (pressed) {\n // Check focused element\n // and if the focused element is not editable (e.g. text input)\n // and any that accept key input http://webaim.org/techniques/keyboard/\n const focused = document.activeElement;\n if (is.element(focused)) {\n const { editable } = player.config.selectors;\n const { seek } = elements.inputs;\n\n if (focused !== seek && matches(focused, editable)) {\n return;\n }\n\n if (event.which === 32 && matches(focused, 'button, [role^=\"menuitem\"]')) {\n return;\n }\n }\n\n // Which keycodes should we prevent default\n const preventDefault = [32, 37, 38, 39, 40, 48, 49, 50, 51, 52, 53, 54, 56, 57, 67, 70, 73, 75, 76, 77, 79];\n\n // If the code is found prevent default (e.g. prevent scrolling for arrows)\n if (preventDefault.includes(code)) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n switch (code) {\n case 48:\n case 49:\n case 50:\n case 51:\n case 52:\n case 53:\n case 54:\n case 55:\n case 56:\n case 57:\n // 0-9\n if (!repeat) {\n seekByKey();\n }\n break;\n\n case 32:\n case 75:\n // Space and K key\n if (!repeat) {\n player.togglePlay();\n }\n break;\n\n case 38:\n // Arrow up\n player.increaseVolume(0.1);\n break;\n\n case 40:\n // Arrow down\n player.decreaseVolume(0.1);\n break;\n\n case 77:\n // M key\n if (!repeat) {\n player.muted = !player.muted;\n }\n break;\n\n case 39:\n // Arrow forward\n player.forward();\n break;\n\n case 37:\n // Arrow back\n player.rewind();\n break;\n\n case 70:\n // F key\n player.fullscreen.toggle();\n break;\n\n case 67:\n // C key\n if (!repeat) {\n player.toggleCaptions();\n }\n break;\n\n case 76:\n // L key\n player.loop = !player.loop;\n break;\n\n /* case 73:\n this.setLoop('start');\n break;\n\n case 76:\n this.setLoop();\n break;\n\n case 79:\n this.setLoop('end');\n break; */\n\n default:\n break;\n }\n\n // Escape is handle natively when in full screen\n // So we only need to worry about non native\n if (!player.fullscreen.enabled && player.fullscreen.active && code === 27) {\n player.fullscreen.toggle();\n }\n\n // Store last code for next cycle\n this.lastKey = code;\n } else {\n this.lastKey = null;\n }\n }\n\n // Toggle menu\n toggleMenu(event) {\n controls.toggleMenu.call(this.player, event);\n }\n\n // Device is touch enabled\n firstTouch() {\n const { player } = this;\n const { elements } = player;\n\n player.touch = true;\n\n // Add touch class\n toggleClass(elements.container, player.config.classNames.isTouch, true);\n }\n\n setTabFocus(event) {\n const { player } = this;\n const { elements } = player;\n\n clearTimeout(this.focusTimer);\n\n // Ignore any key other than tab\n if (event.type === 'keydown' && event.which !== 9) {\n return;\n }\n\n // Store reference to event timeStamp\n if (event.type === 'keydown') {\n this.lastKeyDown = event.timeStamp;\n }\n\n // Remove current classes\n const removeCurrent = () => {\n const className = player.config.classNames.tabFocus;\n const current = getElements.call(player, `.${className}`);\n toggleClass(current, className, false);\n };\n\n // Determine if a key was pressed to trigger this event\n const wasKeyDown = event.timeStamp - this.lastKeyDown <= 20;\n\n // Ignore focus events if a key was pressed prior\n if (event.type === 'focus' && !wasKeyDown) {\n return;\n }\n\n // Remove all current\n removeCurrent();\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n this.focusTimer = setTimeout(() => {\n const focused = document.activeElement;\n\n // Ignore if current focus element isn't inside the player\n if (!elements.container.contains(focused)) {\n return;\n }\n\n toggleClass(document.activeElement, player.config.classNames.tabFocus, true);\n }, 10);\n }\n\n // Global window & document listeners\n global(toggle = true) {\n const { player } = this;\n\n // Keyboard shortcuts\n if (player.config.keyboard.global) {\n toggleListener.call(player, window, 'keydown keyup', this.handleKey, toggle, false);\n }\n\n // Click anywhere closes menu\n toggleListener.call(player, document.body, 'click', this.toggleMenu, toggle);\n\n // Detect touch by events\n once.call(player, document.body, 'touchstart', this.firstTouch);\n\n // Tab focus detection\n toggleListener.call(player, document.body, 'keydown focus blur', this.setTabFocus, toggle, false, true);\n }\n\n // Container listeners\n container() {\n const { player } = this;\n const { elements } = player;\n\n // Keyboard shortcuts\n if (!player.config.keyboard.global && player.config.keyboard.focused) {\n on.call(player, elements.container, 'keydown keyup', this.handleKey, false);\n }\n\n // Toggle controls on mouse events and entering fullscreen\n on.call(\n player,\n elements.container,\n 'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen',\n event => {\n const { controls } = elements;\n\n // Remove button states for fullscreen\n if (controls && event.type === 'enterfullscreen') {\n controls.pressed = false;\n controls.hover = false;\n }\n\n // Show, then hide after a timeout unless another control event occurs\n const show = ['touchstart', 'touchmove', 'mousemove'].includes(event.type);\n\n let delay = 0;\n\n if (show) {\n ui.toggleControls.call(player, true);\n // Use longer timeout for touch devices\n delay = player.touch ? 3000 : 2000;\n }\n\n // Clear timer\n clearTimeout(player.timers.controls);\n\n // Set new timer to prevent flicker when seeking\n player.timers.controls = setTimeout(() => ui.toggleControls.call(player, false), delay);\n },\n );\n }\n\n // Listen for media events\n media() {\n const { player } = this;\n const { elements } = player;\n\n // Time change on media\n on.call(player, player.media, 'timeupdate seeking seeked', event => controls.timeUpdate.call(player, event));\n\n // Display duration\n on.call(player, player.media, 'durationchange loadeddata loadedmetadata', event =>\n controls.durationUpdate.call(player, event),\n );\n\n // Check for audio tracks on load\n // We can't use `loadedmetadata` as it doesn't seem to have audio tracks at that point\n on.call(player, player.media, 'canplay', () => {\n toggleHidden(elements.volume, !player.hasAudio);\n toggleHidden(elements.buttons.mute, !player.hasAudio);\n });\n\n // Handle the media finishing\n on.call(player, player.media, 'ended', () => {\n // Show poster on end\n if (player.isHTML5 && player.isVideo && player.config.resetOnEnd) {\n // Restart\n player.restart();\n }\n });\n\n // Check for buffer progress\n on.call(player, player.media, 'progress playing seeking seeked', event =>\n controls.updateProgress.call(player, event),\n );\n\n // Handle volume changes\n on.call(player, player.media, 'volumechange', event => controls.updateVolume.call(player, event));\n\n // Handle play/pause\n on.call(player, player.media, 'playing play pause ended emptied timeupdate', event =>\n ui.checkPlaying.call(player, event),\n );\n\n // Loading state\n on.call(player, player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(player, event));\n\n // If autoplay, then load advertisement if required\n // TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows\n on.call(player, player.media, 'playing', () => {\n if (!player.ads) {\n return;\n }\n\n // If ads are enabled, wait for them first\n if (player.ads.enabled && !player.ads.initialized) {\n // Wait for manager response\n player.ads.managerPromise.then(() => player.ads.play()).catch(() => player.play());\n }\n });\n\n // Click video\n if (player.supported.ui && player.config.clickToPlay && !player.isAudio) {\n // Re-fetch the wrapper\n const wrapper = getElement.call(player, `.${player.config.classNames.video}`);\n\n // Bail if there's no wrapper (this should never happen)\n if (!is.element(wrapper)) {\n return;\n }\n\n // On click play, pause or restart\n on.call(player, elements.container, 'click', event => {\n const targets = [elements.container, wrapper];\n\n // Ignore if click if not container or in video wrapper\n if (!targets.includes(event.target) && !wrapper.contains(event.target)) {\n return;\n }\n\n // Touch devices will just show controls (if hidden)\n if (player.touch && player.config.hideControls) {\n return;\n }\n\n if (player.ended) {\n player.restart();\n player.play();\n } else {\n player.togglePlay();\n }\n });\n }\n\n // Disable right click\n if (player.supported.ui && player.config.disableContextMenu) {\n on.call(\n player,\n elements.wrapper,\n 'contextmenu',\n event => {\n event.preventDefault();\n },\n false,\n );\n }\n\n // Volume change\n on.call(player, player.media, 'volumechange', () => {\n // Save to storage\n player.storage.set({\n volume: player.volume,\n muted: player.muted,\n });\n });\n\n // Speed change\n on.call(player, player.media, 'ratechange', () => {\n // Update UI\n controls.updateSetting.call(player, 'speed');\n\n // Save to storage\n player.storage.set({ speed: player.speed });\n });\n\n // Quality change\n on.call(player, player.media, 'qualitychange', event => {\n // Update UI\n controls.updateSetting.call(player, 'quality', null, event.detail.quality);\n });\n\n // Update download link when ready and if quality changes\n on.call(player, player.media, 'ready qualitychange', () => {\n controls.setDownloadLink.call(player);\n });\n\n // Proxy events to container\n // Bubble up key events for Edge\n const proxyEvents = player.config.events.concat(['keyup', 'keydown']).join(' ');\n\n on.call(player, player.media, proxyEvents, event => {\n let { detail = {} } = event;\n\n // Get error details from media\n if (event.type === 'error') {\n detail = player.media.error;\n }\n\n triggerEvent.call(player, elements.container, event.type, true, detail);\n });\n }\n\n // Run default and custom handlers\n proxy(event, defaultHandler, customHandlerKey) {\n const { player } = this;\n const customHandler = player.config.listeners[customHandlerKey];\n const hasCustomHandler = is.function(customHandler);\n let returned = true;\n\n // Execute custom handler\n if (hasCustomHandler) {\n returned = customHandler.call(player, event);\n }\n\n // Only call default handler if not prevented in custom handler\n if (returned && is.function(defaultHandler)) {\n defaultHandler.call(player, event);\n }\n }\n\n // Trigger custom and default handlers\n bind(element, type, defaultHandler, customHandlerKey, passive = true) {\n const { player } = this;\n const customHandler = player.config.listeners[customHandlerKey];\n const hasCustomHandler = is.function(customHandler);\n\n on.call(\n player,\n element,\n type,\n event => this.proxy(event, defaultHandler, customHandlerKey),\n passive && !hasCustomHandler,\n );\n }\n\n // Listen for control events\n controls() {\n const { player } = this;\n const { elements } = player;\n\n // IE doesn't support input event, so we fallback to change\n const inputEvent = browser.isIE ? 'change' : 'input';\n\n // Play/pause toggle\n if (elements.buttons.play) {\n Array.from(elements.buttons.play).forEach(button => {\n this.bind(button, 'click', player.togglePlay, 'play');\n });\n }\n\n // Pause\n this.bind(elements.buttons.restart, 'click', player.restart, 'restart');\n\n // Rewind\n this.bind(elements.buttons.rewind, 'click', player.rewind, 'rewind');\n\n // Rewind\n this.bind(elements.buttons.fastForward, 'click', player.forward, 'fastForward');\n\n // Mute toggle\n this.bind(\n elements.buttons.mute,\n 'click',\n () => {\n player.muted = !player.muted;\n },\n 'mute',\n );\n\n // Captions toggle\n this.bind(elements.buttons.captions, 'click', () => player.toggleCaptions());\n\n // Download\n this.bind(\n elements.buttons.download,\n 'click',\n () => {\n triggerEvent.call(player, player.media, 'download');\n },\n 'download',\n );\n\n // Fullscreen toggle\n this.bind(\n elements.buttons.fullscreen,\n 'click',\n () => {\n player.fullscreen.toggle();\n },\n 'fullscreen',\n );\n\n // Picture-in-Picture\n this.bind(\n elements.buttons.pip,\n 'click',\n () => {\n player.pip = 'toggle';\n },\n 'pip',\n );\n\n // Airplay\n this.bind(elements.buttons.airplay, 'click', player.airplay, 'airplay');\n\n // Settings menu - click toggle\n this.bind(elements.buttons.settings, 'click', event => {\n // Prevent the document click listener closing the menu\n event.stopPropagation();\n\n controls.toggleMenu.call(player, event);\n });\n\n // Settings menu - keyboard toggle\n // We have to bind to keyup otherwise Firefox triggers a click when a keydown event handler shifts focus\n // https://bugzilla.mozilla.org/show_bug.cgi?id=1220143\n this.bind(\n elements.buttons.settings,\n 'keyup',\n event => {\n const code = event.which;\n\n // We only care about space and return\n if (![13, 32].includes(code)) {\n return;\n }\n\n // Because return triggers a click anyway, all we need to do is set focus\n if (code === 13) {\n controls.focusFirstMenuItem.call(player, null, true);\n return;\n }\n\n // Prevent scroll\n event.preventDefault();\n\n // Prevent playing video (Firefox)\n event.stopPropagation();\n\n // Toggle menu\n controls.toggleMenu.call(player, event);\n },\n null,\n false, // Can't be passive as we're preventing default\n );\n\n // Escape closes menu\n this.bind(elements.settings.menu, 'keydown', event => {\n if (event.which === 27) {\n controls.toggleMenu.call(player, event);\n }\n });\n\n // Set range input alternative \"value\", which matches the tooltip time (#954)\n this.bind(elements.inputs.seek, 'mousedown mousemove', event => {\n const rect = elements.progress.getBoundingClientRect();\n const percent = (100 / rect.width) * (event.pageX - rect.left);\n event.currentTarget.setAttribute('seek-value', percent);\n });\n\n // Pause while seeking\n this.bind(elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', event => {\n const seek = event.currentTarget;\n const code = event.keyCode ? event.keyCode : event.which;\n const attribute = 'play-on-seeked';\n\n if (is.keyboardEvent(event) && (code !== 39 && code !== 37)) {\n return;\n }\n\n // Record seek time so we can prevent hiding controls for a few seconds after seek\n player.lastSeekTime = Date.now();\n\n // Was playing before?\n const play = seek.hasAttribute(attribute);\n\n // Done seeking\n const done = ['mouseup', 'touchend', 'keyup'].includes(event.type);\n\n // If we're done seeking and it was playing, resume playback\n if (play && done) {\n seek.removeAttribute(attribute);\n player.play();\n } else if (!done && player.playing) {\n seek.setAttribute(attribute, '');\n player.pause();\n }\n });\n\n // Fix range inputs on iOS\n // Super weird iOS bug where after you interact with an <input type=\"range\">,\n // it takes over further interactions on the page. This is a hack\n if (browser.isIos) {\n const inputs = getElements.call(player, 'input[type=\"range\"]');\n Array.from(inputs).forEach(input => this.bind(input, inputEvent, event => repaint(event.target)));\n }\n\n // Seek\n this.bind(\n elements.inputs.seek,\n inputEvent,\n event => {\n const seek = event.currentTarget;\n\n // If it exists, use seek-value instead of \"value\" for consistency with tooltip time (#954)\n let seekTo = seek.getAttribute('seek-value');\n\n if (is.empty(seekTo)) {\n seekTo = seek.value;\n }\n\n seek.removeAttribute('seek-value');\n\n player.currentTime = (seekTo / seek.max) * player.duration;\n },\n 'seek',\n );\n\n // Seek tooltip\n this.bind(elements.progress, 'mouseenter mouseleave mousemove', event =>\n controls.updateSeekTooltip.call(player, event),\n );\n\n // Polyfill for lower fill in <input type=\"range\"> for webkit\n if (browser.isWebkit) {\n Array.from(getElements.call(player, 'input[type=\"range\"]')).forEach(element => {\n this.bind(element, 'input', event => controls.updateRangeFill.call(player, event.target));\n });\n }\n\n // Current time invert\n // Only if one time element is used for both currentTime and duration\n if (player.config.toggleInvert && !is.element(elements.display.duration)) {\n this.bind(elements.display.currentTime, 'click', () => {\n // Do nothing if we're at the start\n if (player.currentTime === 0) {\n return;\n }\n\n player.config.invertTime = !player.config.invertTime;\n\n controls.timeUpdate.call(player);\n });\n }\n\n // Volume\n this.bind(\n elements.inputs.volume,\n inputEvent,\n event => {\n player.volume = event.target.value;\n },\n 'volume',\n );\n\n // Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)\n this.bind(elements.controls, 'mouseenter mouseleave', event => {\n elements.controls.hover = !player.touch && event.type === 'mouseenter';\n });\n\n // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)\n this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {\n elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);\n });\n\n // Show controls when they receive focus (e.g., when using keyboard tab key)\n this.bind(elements.controls, 'focusin', () => {\n const { config, elements, timers } = player;\n\n // Skip transition to prevent focus from scrolling the parent element\n toggleClass(elements.controls, config.classNames.noTransition, true);\n\n // Toggle\n ui.toggleControls.call(player, true);\n\n // Restore transition\n setTimeout(() => {\n toggleClass(elements.controls, config.classNames.noTransition, false);\n }, 0);\n\n // Delay a little more for mouse users\n const delay = this.touch ? 3000 : 4000;\n\n // Clear timer\n clearTimeout(timers.controls);\n\n // Hide again after delay\n timers.controls = setTimeout(() => ui.toggleControls.call(player, false), delay);\n });\n\n // Mouse wheel for volume\n this.bind(\n elements.inputs.volume,\n 'wheel',\n event => {\n // Detect \"natural\" scroll - suppored on OS X Safari only\n // Other browsers on OS X will be inverted until support improves\n const inverted = event.webkitDirectionInvertedFromDevice;\n\n // Get delta from event. Invert if `inverted` is true\n const [x, y] = [event.deltaX, -event.deltaY].map(value => (inverted ? -value : value));\n\n // Using the biggest delta, normalize to 1 or -1 (or 0 if no delta)\n const direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y);\n\n // Change the volume by 2%\n player.increaseVolume(direction / 50);\n\n // Don't break page scrolling at max and min\n const { volume } = player.media;\n if ((direction === 1 && volume < 1) || (direction === -1 && volume > 0)) {\n event.preventDefault();\n }\n },\n 'volume',\n false,\n );\n }\n}\n\nexport default Listeners;\n","(function(root, factory) {\n if (typeof define === 'function' && define.amd) {\n define([], factory);\n } else if (typeof exports === 'object') {\n module.exports = factory();\n } else {\n root.loadjs = factory();\n }\n}(this, function() {\n/**\n * Global dependencies.\n * @global {Object} document - DOM\n */\n\nvar devnull = function() {},\n bundleIdCache = {},\n bundleResultCache = {},\n bundleCallbackQueue = {};\n\n\n/**\n * Subscribe to bundle load event.\n * @param {string[]} bundleIds - Bundle ids\n * @param {Function} callbackFn - The callback function\n */\nfunction subscribe(bundleIds, callbackFn) {\n // listify\n bundleIds = bundleIds.push ? bundleIds : [bundleIds];\n\n var depsNotFound = [],\n i = bundleIds.length,\n numWaiting = i,\n fn,\n bundleId,\n r,\n q;\n\n // define callback function\n fn = function (bundleId, pathsNotFound) {\n if (pathsNotFound.length) depsNotFound.push(bundleId);\n\n numWaiting--;\n if (!numWaiting) callbackFn(depsNotFound);\n };\n\n // register callback\n while (i--) {\n bundleId = bundleIds[i];\n\n // execute callback if in result cache\n r = bundleResultCache[bundleId];\n if (r) {\n fn(bundleId, r);\n continue;\n }\n\n // add to callback queue\n q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || [];\n q.push(fn);\n }\n}\n\n\n/**\n * Publish bundle load event.\n * @param {string} bundleId - Bundle id\n * @param {string[]} pathsNotFound - List of files not found\n */\nfunction publish(bundleId, pathsNotFound) {\n // exit if id isn't defined\n if (!bundleId) return;\n\n var q = bundleCallbackQueue[bundleId];\n\n // cache result\n bundleResultCache[bundleId] = pathsNotFound;\n\n // exit if queue is empty\n if (!q) return;\n\n // empty callback queue\n while (q.length) {\n q[0](bundleId, pathsNotFound);\n q.splice(0, 1);\n }\n}\n\n\n/**\n * Execute callbacks.\n * @param {Object or Function} args - The callback args\n * @param {string[]} depsNotFound - List of dependencies not found\n */\nfunction executeCallbacks(args, depsNotFound) {\n // accept function as argument\n if (args.call) args = {success: args};\n\n // success and error callbacks\n if (depsNotFound.length) (args.error || devnull)(depsNotFound);\n else (args.success || devnull)(args);\n}\n\n\n/**\n * Load individual file.\n * @param {string} path - The file path\n * @param {Function} callbackFn - The callback function\n */\nfunction loadFile(path, callbackFn, args, numTries) {\n var doc = document,\n async = args.async,\n maxTries = (args.numRetries || 0) + 1,\n beforeCallbackFn = args.before || devnull,\n pathStripped = path.replace(/^(css|img)!/, ''),\n isCss,\n e;\n\n numTries = numTries || 0;\n\n if (/(^css!|\\.css$)/.test(path)) {\n isCss = true;\n\n // css\n e = doc.createElement('link');\n e.rel = 'stylesheet';\n e.href = pathStripped; //.replace(/^css!/, ''); // remove \"css!\" prefix\n } else if (/(^img!|\\.(png|gif|jpg|svg)$)/.test(path)) {\n // image\n e = doc.createElement('img');\n e.src = pathStripped; \n } else {\n // javascript\n e = doc.createElement('script');\n e.src = path;\n e.async = async === undefined ? true : async;\n }\n\n e.onload = e.onerror = e.onbeforeload = function (ev) {\n var result = ev.type[0];\n\n // Note: The following code isolates IE using `hideFocus` and treats empty\n // stylesheets as failures to get around lack of onerror support\n if (isCss && 'hideFocus' in e) {\n try {\n if (!e.sheet.cssText.length) result = 'e';\n } catch (x) {\n // sheets objects created from load errors don't allow access to\n // `cssText`\n result = 'e';\n }\n }\n\n // handle retries in case of load failure\n if (result == 'e') {\n // increment counter\n numTries += 1;\n\n // exit function and try again\n if (numTries < maxTries) {\n return loadFile(path, callbackFn, args, numTries);\n }\n }\n\n // execute callback\n callbackFn(path, result, ev.defaultPrevented);\n };\n\n // add to document (unless callback returns `false`)\n if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e);\n}\n\n\n/**\n * Load multiple files.\n * @param {string[]} paths - The file paths\n * @param {Function} callbackFn - The callback function\n */\nfunction loadFiles(paths, callbackFn, args) {\n // listify paths\n paths = paths.push ? paths : [paths];\n\n var numWaiting = paths.length,\n x = numWaiting,\n pathsNotFound = [],\n fn,\n i;\n\n // define callback function\n fn = function(path, result, defaultPrevented) {\n // handle error\n if (result == 'e') pathsNotFound.push(path);\n\n // handle beforeload event. If defaultPrevented then that means the load\n // will be blocked (ex. Ghostery/ABP on Safari)\n if (result == 'b') {\n if (defaultPrevented) pathsNotFound.push(path);\n else return;\n }\n\n numWaiting--;\n if (!numWaiting) callbackFn(pathsNotFound);\n };\n\n // load scripts\n for (i=0; i < x; i++) loadFile(paths[i], fn, args);\n}\n\n\n/**\n * Initiate script load and register bundle.\n * @param {(string|string[])} paths - The file paths\n * @param {(string|Function)} [arg1] - The bundleId or success callback\n * @param {Function} [arg2] - The success or error callback\n * @param {Function} [arg3] - The error callback\n */\nfunction loadjs(paths, arg1, arg2) {\n var bundleId,\n args;\n\n // bundleId (if string)\n if (arg1 && arg1.trim) bundleId = arg1;\n\n // args (default is {})\n args = (bundleId ? arg2 : arg1) || {};\n\n // throw error if bundle is already defined\n if (bundleId) {\n if (bundleId in bundleIdCache) {\n throw \"LoadJS\";\n } else {\n bundleIdCache[bundleId] = true;\n }\n }\n\n // load scripts\n loadFiles(paths, function (pathsNotFound) {\n // execute callbacks\n executeCallbacks(args, pathsNotFound);\n\n // publish bundle load event\n publish(bundleId, pathsNotFound);\n }, args);\n}\n\n\n/**\n * Execute callbacks when dependencies have been satisfied.\n * @param {(string|string[])} deps - List of bundle ids\n * @param {Object} args - success/error arguments\n */\nloadjs.ready = function ready(deps, args) {\n // subscribe to bundle load event\n subscribe(deps, function (depsNotFound) {\n // execute callbacks\n executeCallbacks(args, depsNotFound);\n });\n\n return loadjs;\n};\n\n\n/**\n * Manually satisfy bundle dependencies.\n * @param {string} bundleId - The bundle id\n */\nloadjs.done = function done(bundleId) {\n publish(bundleId, []);\n};\n\n\n/**\n * Reset loadjs dependencies statuses\n */\nloadjs.reset = function reset() {\n bundleIdCache = {};\n bundleResultCache = {};\n bundleCallbackQueue = {};\n};\n\n\n/**\n * Determine if bundle has already been defined\n * @param String} bundleId - The bundle id\n */\nloadjs.isDefined = function isDefined(bundleId) {\n return bundleId in bundleIdCache;\n};\n\n\n// export\nreturn loadjs;\n\n}));\n","// ==========================================================================\n// Load an external script\n// ==========================================================================\n\nimport loadjs from 'loadjs';\n\nexport default function loadScript(url) {\n return new Promise((resolve, reject) => {\n loadjs(url, {\n success: resolve,\n error: reject,\n });\n });\n}\n","// ==========================================================================\n// Vimeo plugin\n// ==========================================================================\n\nimport captions from '../captions';\nimport controls from '../controls';\nimport ui from '../ui';\nimport { createElement, replaceElement, toggleClass } from '../utils/elements';\nimport { triggerEvent } from '../utils/events';\nimport fetch from '../utils/fetch';\nimport is from '../utils/is';\nimport loadScript from '../utils/loadScript';\nimport { format, stripHTML } from '../utils/strings';\nimport { buildUrlParams } from '../utils/urls';\n\n// Parse Vimeo ID from URL\nfunction parseId(url) {\n if (is.empty(url)) {\n return null;\n }\n\n if (is.number(Number(url))) {\n return url;\n }\n\n const regex = /^.*(vimeo.com\\/|video\\/)(\\d+).*/;\n return url.match(regex) ? RegExp.$2 : url;\n}\n\n// Get aspect ratio for dimensions\nfunction getAspectRatio(width, height) {\n const getRatio = (w, h) => (h === 0 ? w : getRatio(h, w % h));\n const ratio = getRatio(width, height);\n return `${width / ratio}:${height / ratio}`;\n}\n\n// Set playback state and trigger change (only on actual change)\nfunction assurePlaybackState(play) {\n if (play && !this.embed.hasPlayed) {\n this.embed.hasPlayed = true;\n }\n if (this.media.paused === play) {\n this.media.paused = !play;\n triggerEvent.call(this, this.media, play ? 'play' : 'pause');\n }\n}\n\nconst vimeo = {\n setup() {\n // Add embed class for responsive\n toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set intial ratio\n vimeo.setAspectRatio.call(this);\n\n // Load the API if not already\n if (!is.object(window.Vimeo)) {\n loadScript(this.config.urls.vimeo.sdk)\n .then(() => {\n vimeo.ready.call(this);\n })\n .catch(error => {\n this.debug.warn('Vimeo API failed to load', error);\n });\n } else {\n vimeo.ready.call(this);\n }\n },\n\n // Set aspect ratio\n // For Vimeo we have an extra 300% height <div> to hide the standard controls and UI\n setAspectRatio(input) {\n const [x, y] = (is.string(input) ? input : this.config.ratio).split(':');\n const padding = (100 / x) * y;\n this.elements.wrapper.style.paddingBottom = `${padding}%`;\n\n if (this.supported.ui) {\n const height = 240;\n const offset = (height - padding) / (height / 50);\n\n this.media.style.transform = `translateY(-${offset}%)`;\n }\n },\n\n // API Ready\n ready() {\n const player = this;\n\n // Get Vimeo params for the iframe\n const options = {\n loop: player.config.loop.active,\n autoplay: player.autoplay,\n // muted: player.muted,\n byline: false,\n portrait: false,\n title: false,\n speed: true,\n transparent: 0,\n gesture: 'media',\n playsinline: !this.config.fullscreen.iosNative,\n };\n const params = buildUrlParams(options);\n\n // Get the source URL or ID\n let source = player.media.getAttribute('src');\n\n // Get from <div> if needed\n if (is.empty(source)) {\n source = player.media.getAttribute(player.config.attributes.embed.id);\n }\n\n const id = parseId(source);\n\n // Build an iframe\n const iframe = createElement('iframe');\n const src = format(player.config.urls.vimeo.iframe, id, params);\n iframe.setAttribute('src', src);\n iframe.setAttribute('allowfullscreen', '');\n iframe.setAttribute('allowtransparency', '');\n iframe.setAttribute('allow', 'autoplay');\n\n // Get poster, if already set\n const { poster } = player;\n\n // Inject the package\n const wrapper = createElement('div', { poster, class: player.config.classNames.embedContainer });\n wrapper.appendChild(iframe);\n player.media = replaceElement(wrapper, player.media);\n\n // Get poster image\n fetch(format(player.config.urls.vimeo.api, id), 'json').then(response => {\n if (is.empty(response)) {\n return;\n }\n\n // Get the URL for thumbnail\n const url = new URL(response[0].thumbnail_large);\n\n // Get original image\n url.pathname = `${url.pathname.split('_')[0]}.jpg`;\n\n // Set and show poster\n ui.setPoster.call(player, url.href).catch(() => {});\n });\n\n // Setup instance\n // https://github.com/vimeo/player.js\n player.embed = new window.Vimeo.Player(iframe, {\n autopause: player.config.autopause,\n muted: player.muted,\n });\n\n player.media.paused = true;\n player.media.currentTime = 0;\n\n // Disable native text track rendering\n if (player.supported.ui) {\n player.embed.disableTextTrack();\n }\n\n // Create a faux HTML5 API using the Vimeo API\n player.media.play = () => {\n assurePlaybackState.call(player, true);\n return player.embed.play();\n };\n\n player.media.pause = () => {\n assurePlaybackState.call(player, false);\n return player.embed.pause();\n };\n\n player.media.stop = () => {\n player.pause();\n player.currentTime = 0;\n };\n\n // Seeking\n let { currentTime } = player.media;\n Object.defineProperty(player.media, 'currentTime', {\n get() {\n return currentTime;\n },\n set(time) {\n // Vimeo will automatically play on seek if the video hasn't been played before\n\n // Get current paused state and volume etc\n const { embed, media, paused, volume } = player;\n const restorePause = paused && !embed.hasPlayed;\n\n // Set seeking state and trigger event\n media.seeking = true;\n triggerEvent.call(player, media, 'seeking');\n\n // If paused, mute until seek is complete\n Promise.resolve(restorePause && embed.setVolume(0))\n // Seek\n .then(() => embed.setCurrentTime(time))\n // Restore paused\n .then(() => restorePause && embed.pause())\n // Restore volume\n .then(() => restorePause && embed.setVolume(volume))\n .catch(() => {\n // Do nothing\n });\n },\n });\n\n // Playback speed\n let speed = player.config.speed.selected;\n Object.defineProperty(player.media, 'playbackRate', {\n get() {\n return speed;\n },\n set(input) {\n player.embed\n .setPlaybackRate(input)\n .then(() => {\n speed = input;\n triggerEvent.call(player, player.media, 'ratechange');\n })\n .catch(error => {\n // Hide menu item (and menu if empty)\n if (error.name === 'Error') {\n controls.setSpeedMenu.call(player, []);\n }\n });\n },\n });\n\n // Volume\n let { volume } = player.config;\n Object.defineProperty(player.media, 'volume', {\n get() {\n return volume;\n },\n set(input) {\n player.embed.setVolume(input).then(() => {\n volume = input;\n triggerEvent.call(player, player.media, 'volumechange');\n });\n },\n });\n\n // Muted\n let { muted } = player.config;\n Object.defineProperty(player.media, 'muted', {\n get() {\n return muted;\n },\n set(input) {\n const toggle = is.boolean(input) ? input : false;\n\n player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => {\n muted = toggle;\n triggerEvent.call(player, player.media, 'volumechange');\n });\n },\n });\n\n // Loop\n let { loop } = player.config;\n Object.defineProperty(player.media, 'loop', {\n get() {\n return loop;\n },\n set(input) {\n const toggle = is.boolean(input) ? input : player.config.loop.active;\n\n player.embed.setLoop(toggle).then(() => {\n loop = toggle;\n });\n },\n });\n\n // Source\n let currentSrc;\n player.embed\n .getVideoUrl()\n .then(value => {\n currentSrc = value;\n controls.setDownloadLink.call(player);\n })\n .catch(error => {\n this.debug.warn(error);\n });\n\n Object.defineProperty(player.media, 'currentSrc', {\n get() {\n return currentSrc;\n },\n });\n\n // Ended\n Object.defineProperty(player.media, 'ended', {\n get() {\n return player.currentTime === player.duration;\n },\n });\n\n // Set aspect ratio based on video size\n Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(dimensions => {\n const ratio = getAspectRatio(dimensions[0], dimensions[1]);\n vimeo.setAspectRatio.call(this, ratio);\n });\n\n // Set autopause\n player.embed.setAutopause(player.config.autopause).then(state => {\n player.config.autopause = state;\n });\n\n // Get title\n player.embed.getVideoTitle().then(title => {\n player.config.title = title;\n ui.setTitle.call(this);\n });\n\n // Get current time\n player.embed.getCurrentTime().then(value => {\n currentTime = value;\n triggerEvent.call(player, player.media, 'timeupdate');\n });\n\n // Get duration\n player.embed.getDuration().then(value => {\n player.media.duration = value;\n triggerEvent.call(player, player.media, 'durationchange');\n });\n\n // Get captions\n player.embed.getTextTracks().then(tracks => {\n player.media.textTracks = tracks;\n captions.setup.call(player);\n });\n\n player.embed.on('cuechange', ({ cues = [] }) => {\n const strippedCues = cues.map(cue => stripHTML(cue.text));\n captions.updateCues.call(player, strippedCues);\n });\n\n player.embed.on('loaded', () => {\n // Assure state and events are updated on autoplay\n player.embed.getPaused().then(paused => {\n assurePlaybackState.call(player, !paused);\n if (!paused) {\n triggerEvent.call(player, player.media, 'playing');\n }\n });\n\n if (is.element(player.embed.element) && player.supported.ui) {\n const frame = player.embed.element;\n\n // Fix keyboard focus issues\n // https://github.com/sampotts/plyr/issues/317\n frame.setAttribute('tabindex', -1);\n }\n });\n\n player.embed.on('play', () => {\n assurePlaybackState.call(player, true);\n triggerEvent.call(player, player.media, 'playing');\n });\n\n player.embed.on('pause', () => {\n assurePlaybackState.call(player, false);\n });\n\n player.embed.on('timeupdate', data => {\n player.media.seeking = false;\n currentTime = data.seconds;\n triggerEvent.call(player, player.media, 'timeupdate');\n });\n\n player.embed.on('progress', data => {\n player.media.buffered = data.percent;\n triggerEvent.call(player, player.media, 'progress');\n\n // Check all loaded\n if (parseInt(data.percent, 10) === 1) {\n triggerEvent.call(player, player.media, 'canplaythrough');\n }\n\n // Get duration as if we do it before load, it gives an incorrect value\n // https://github.com/sampotts/plyr/issues/891\n player.embed.getDuration().then(value => {\n if (value !== player.media.duration) {\n player.media.duration = value;\n triggerEvent.call(player, player.media, 'durationchange');\n }\n });\n });\n\n player.embed.on('seeked', () => {\n player.media.seeking = false;\n triggerEvent.call(player, player.media, 'seeked');\n });\n\n player.embed.on('ended', () => {\n player.media.paused = true;\n triggerEvent.call(player, player.media, 'ended');\n });\n\n player.embed.on('error', detail => {\n player.media.error = detail;\n triggerEvent.call(player, player.media, 'error');\n });\n\n // Rebuild UI\n setTimeout(() => ui.build.call(player), 0);\n },\n};\n\nexport default vimeo;\n","// ==========================================================================\n// YouTube plugin\n// ==========================================================================\n\nimport ui from '../ui';\nimport { createElement, replaceElement, toggleClass } from '../utils/elements';\nimport { triggerEvent } from '../utils/events';\nimport fetch from '../utils/fetch';\nimport is from '../utils/is';\nimport loadImage from '../utils/loadImage';\nimport loadScript from '../utils/loadScript';\nimport { format, generateId } from '../utils/strings';\n\n// Parse YouTube ID from URL\nfunction parseId(url) {\n if (is.empty(url)) {\n return null;\n }\n\n const regex = /^.*(youtu.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|&v=)([^#&?]*).*/;\n return url.match(regex) ? RegExp.$2 : url;\n}\n\n// Set playback state and trigger change (only on actual change)\nfunction assurePlaybackState(play) {\n if (play && !this.embed.hasPlayed) {\n this.embed.hasPlayed = true;\n }\n if (this.media.paused === play) {\n this.media.paused = !play;\n triggerEvent.call(this, this.media, play ? 'play' : 'pause');\n }\n}\n\nconst youtube = {\n setup() {\n // Add embed class for responsive\n toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set aspect ratio\n youtube.setAspectRatio.call(this);\n\n // Setup API\n if (is.object(window.YT) && is.function(window.YT.Player)) {\n youtube.ready.call(this);\n } else {\n // Load the API\n loadScript(this.config.urls.youtube.sdk).catch(error => {\n this.debug.warn('YouTube API failed to load', error);\n });\n\n // Setup callback for the API\n // YouTube has it's own system of course...\n window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];\n\n // Add to queue\n window.onYouTubeReadyCallbacks.push(() => {\n youtube.ready.call(this);\n });\n\n // Set callback to process queue\n window.onYouTubeIframeAPIReady = () => {\n window.onYouTubeReadyCallbacks.forEach(callback => {\n callback();\n });\n };\n }\n },\n\n // Get the media title\n getTitle(videoId) {\n // Try via undocumented API method first\n // This method disappears now and then though...\n // https://github.com/sampotts/plyr/issues/709\n if (is.function(this.embed.getVideoData)) {\n const { title } = this.embed.getVideoData();\n\n if (is.empty(title)) {\n this.config.title = title;\n ui.setTitle.call(this);\n return;\n }\n }\n\n // Or via Google API\n const key = this.config.keys.google;\n if (is.string(key) && !is.empty(key)) {\n const url = format(this.config.urls.youtube.api, videoId, key);\n\n fetch(url)\n .then(result => {\n if (is.object(result)) {\n this.config.title = result.items[0].snippet.title;\n ui.setTitle.call(this);\n }\n })\n .catch(() => {});\n }\n },\n\n // Set aspect ratio\n setAspectRatio() {\n const ratio = this.config.ratio.split(':');\n this.elements.wrapper.style.paddingBottom = `${100 / ratio[0] * ratio[1]}%`;\n },\n\n // API ready\n ready() {\n const player = this;\n\n // Ignore already setup (race condition)\n const currentId = player.media.getAttribute('id');\n if (!is.empty(currentId) && currentId.startsWith('youtube-')) {\n return;\n }\n\n // Get the source URL or ID\n let source = player.media.getAttribute('src');\n\n // Get from <div> if needed\n if (is.empty(source)) {\n source = player.media.getAttribute(this.config.attributes.embed.id);\n }\n\n // Replace the <iframe> with a <div> due to YouTube API issues\n const videoId = parseId(source);\n const id = generateId(player.provider);\n\n // Get poster, if already set\n const { poster } = player;\n\n // Replace media element\n const container = createElement('div', { id, poster });\n player.media = replaceElement(container, player.media);\n\n // Id to poster wrapper\n const posterSrc = format => `https://img.youtube.com/vi/${videoId}/${format}default.jpg`;\n\n // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)\n loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded\n .catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3\n .catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists\n .then(image => ui.setPoster.call(player, image.src))\n .then(posterSrc => {\n // If the image is padded, use background-size \"cover\" instead (like youtube does too with their posters)\n if (!posterSrc.includes('maxres')) {\n player.elements.poster.style.backgroundSize = 'cover';\n }\n })\n .catch(() => {});\n\n // Setup instance\n // https://developers.google.com/youtube/iframe_api_reference\n player.embed = new window.YT.Player(id, {\n videoId,\n playerVars: {\n autoplay: player.config.autoplay ? 1 : 0, // Autoplay\n hl: player.config.hl, // iframe interface language\n controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported\n rel: 0, // No related vids\n showinfo: 0, // Hide info\n iv_load_policy: 3, // Hide annotations\n modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused)\n disablekb: 1, // Disable keyboard as we handle it\n playsinline: 1, // Allow iOS inline playback\n\n // Tracking for stats\n // origin: window ? `${window.location.protocol}//${window.location.host}` : null,\n widget_referrer: window ? window.location.href : null,\n\n // Captions are flaky on YouTube\n cc_load_policy: player.captions.active ? 1 : 0,\n cc_lang_pref: player.config.captions.language,\n },\n events: {\n onError(event) {\n // YouTube may fire onError twice, so only handle it once\n if (!player.media.error) {\n const code = event.data;\n // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError\n const message =\n {\n 2: 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.',\n 5: 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.',\n 100: 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.',\n 101: 'The owner of the requested video does not allow it to be played in embedded players.',\n 150: 'The owner of the requested video does not allow it to be played in embedded players.',\n }[code] || 'An unknown error occured';\n\n player.media.error = { code, message };\n\n triggerEvent.call(player, player.media, 'error');\n }\n },\n onPlaybackRateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current speed\n player.media.playbackRate = instance.getPlaybackRate();\n\n triggerEvent.call(player, player.media, 'ratechange');\n },\n onReady(event) {\n // Bail if onReady has already been called. See issue #1108\n if (is.function(player.media.play)) {\n return;\n }\n // Get the instance\n const instance = event.target;\n\n // Get the title\n youtube.getTitle.call(player, videoId);\n\n // Create a faux HTML5 API using the YouTube API\n player.media.play = () => {\n assurePlaybackState.call(player, true);\n instance.playVideo();\n };\n\n player.media.pause = () => {\n assurePlaybackState.call(player, false);\n instance.pauseVideo();\n };\n\n player.media.stop = () => {\n instance.stopVideo();\n };\n\n player.media.duration = instance.getDuration();\n player.media.paused = true;\n\n // Seeking\n player.media.currentTime = 0;\n Object.defineProperty(player.media, 'currentTime', {\n get() {\n return Number(instance.getCurrentTime());\n },\n set(time) {\n // If paused and never played, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).\n if (player.paused && !player.embed.hasPlayed) {\n player.embed.mute();\n }\n\n // Set seeking state and trigger event\n player.media.seeking = true;\n triggerEvent.call(player, player.media, 'seeking');\n\n // Seek after events sent\n instance.seekTo(time);\n },\n });\n\n // Playback speed\n Object.defineProperty(player.media, 'playbackRate', {\n get() {\n return instance.getPlaybackRate();\n },\n set(input) {\n instance.setPlaybackRate(input);\n },\n });\n\n // Volume\n let { volume } = player.config;\n Object.defineProperty(player.media, 'volume', {\n get() {\n return volume;\n },\n set(input) {\n volume = input;\n instance.setVolume(volume * 100);\n triggerEvent.call(player, player.media, 'volumechange');\n },\n });\n\n // Muted\n let { muted } = player.config;\n Object.defineProperty(player.media, 'muted', {\n get() {\n return muted;\n },\n set(input) {\n const toggle = is.boolean(input) ? input : muted;\n muted = toggle;\n instance[toggle ? 'mute' : 'unMute']();\n triggerEvent.call(player, player.media, 'volumechange');\n },\n });\n\n // Source\n Object.defineProperty(player.media, 'currentSrc', {\n get() {\n return instance.getVideoUrl();\n },\n });\n\n // Ended\n Object.defineProperty(player.media, 'ended', {\n get() {\n return player.currentTime === player.duration;\n },\n });\n\n // Get available speeds\n player.options.speed = instance.getAvailablePlaybackRates();\n\n // Set the tabindex to avoid focus entering iframe\n if (player.supported.ui) {\n player.media.setAttribute('tabindex', -1);\n }\n\n triggerEvent.call(player, player.media, 'timeupdate');\n triggerEvent.call(player, player.media, 'durationchange');\n\n // Reset timer\n clearInterval(player.timers.buffering);\n\n // Setup buffering\n player.timers.buffering = setInterval(() => {\n // Get loaded % from YouTube\n player.media.buffered = instance.getVideoLoadedFraction();\n\n // Trigger progress only when we actually buffer something\n if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {\n triggerEvent.call(player, player.media, 'progress');\n }\n\n // Set last buffer point\n player.media.lastBuffered = player.media.buffered;\n\n // Bail if we're at 100%\n if (player.media.buffered === 1) {\n clearInterval(player.timers.buffering);\n\n // Trigger event\n triggerEvent.call(player, player.media, 'canplaythrough');\n }\n }, 200);\n\n // Rebuild UI\n setTimeout(() => ui.build.call(player), 50);\n },\n onStateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Reset timer\n clearInterval(player.timers.playing);\n\n const seeked = player.media.seeking && [1, 2].includes(event.data);\n\n if (seeked) {\n // Unset seeking and fire seeked event\n player.media.seeking = false;\n triggerEvent.call(player, player.media, 'seeked');\n }\n\n // Handle events\n // -1 Unstarted\n // 0 Ended\n // 1 Playing\n // 2 Paused\n // 3 Buffering\n // 5 Video cued\n switch (event.data) {\n case -1:\n // Update scrubber\n triggerEvent.call(player, player.media, 'timeupdate');\n\n // Get loaded % from YouTube\n player.media.buffered = instance.getVideoLoadedFraction();\n triggerEvent.call(player, player.media, 'progress');\n\n break;\n\n case 0:\n assurePlaybackState.call(player, false);\n\n // YouTube doesn't support loop for a single video, so mimick it.\n if (player.media.loop) {\n // YouTube needs a call to `stopVideo` before playing again\n instance.stopVideo();\n instance.playVideo();\n } else {\n triggerEvent.call(player, player.media, 'ended');\n }\n\n break;\n\n case 1:\n // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)\n if (player.media.paused && !player.embed.hasPlayed) {\n player.media.pause();\n } else {\n assurePlaybackState.call(player, true);\n\n triggerEvent.call(player, player.media, 'playing');\n\n // Poll to get playback progress\n player.timers.playing = setInterval(() => {\n triggerEvent.call(player, player.media, 'timeupdate');\n }, 50);\n\n // Check duration again due to YouTube bug\n // https://github.com/sampotts/plyr/issues/374\n // https://code.google.com/p/gdata-issues/issues/detail?id=8690\n if (player.media.duration !== instance.getDuration()) {\n player.media.duration = instance.getDuration();\n triggerEvent.call(player, player.media, 'durationchange');\n }\n }\n\n break;\n\n case 2:\n // Restore audio (YouTube starts playing on seek if the video hasn't been played yet)\n if (!player.muted) {\n player.embed.unMute();\n }\n assurePlaybackState.call(player, false);\n\n break;\n\n default:\n break;\n }\n\n triggerEvent.call(player, player.elements.container, 'statechange', false, {\n code: event.data,\n });\n },\n },\n });\n },\n};\n\nexport default youtube;\n","// ==========================================================================\n// Plyr Media\n// ==========================================================================\n\nimport html5 from './html5';\nimport vimeo from './plugins/vimeo';\nimport youtube from './plugins/youtube';\nimport { createElement, toggleClass, wrap } from './utils/elements';\n\nconst media = {\n // Setup media\n setup() {\n // If there's no media, bail\n if (!this.media) {\n this.debug.warn('No media element found!');\n return;\n }\n\n // Add type class\n toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', this.type), true);\n\n // Add provider class\n toggleClass(this.elements.container, this.config.classNames.provider.replace('{0}', this.provider), true);\n\n // Add video class for embeds\n // This will require changes if audio embeds are added\n if (this.isEmbed) {\n toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true);\n }\n\n // Inject the player wrapper\n if (this.isVideo) {\n // Create the wrapper div\n this.elements.wrapper = createElement('div', {\n class: this.config.classNames.video,\n });\n\n // Wrap the video in a container\n wrap(this.media, this.elements.wrapper);\n\n // Faux poster container\n this.elements.poster = createElement('div', {\n class: this.config.classNames.poster,\n });\n\n this.elements.wrapper.appendChild(this.elements.poster);\n }\n\n if (this.isHTML5) {\n html5.extend.call(this);\n } else if (this.isYouTube) {\n youtube.setup.call(this);\n } else if (this.isVimeo) {\n vimeo.setup.call(this);\n }\n },\n};\n\nexport default media;\n","// ==========================================================================\n// Advertisement plugin using Google IMA HTML5 SDK\n// Create an account with our ad partner, vi here:\n// https://www.vi.ai/publisher-video-monetization/\n// ==========================================================================\n\n/* global google */\n\nimport { createElement } from '../utils/elements';\nimport { triggerEvent } from '../utils/events';\nimport i18n from '../utils/i18n';\nimport is from '../utils/is';\nimport loadScript from '../utils/loadScript';\nimport { formatTime } from '../utils/time';\nimport { buildUrlParams } from '../utils/urls';\n\nclass Ads {\n /**\n * Ads constructor.\n * @param {object} player\n * @return {Ads}\n */\n constructor(player) {\n this.player = player;\n this.publisherId = player.config.ads.publisherId;\n this.playing = false;\n this.initialized = false;\n this.elements = {\n container: null,\n displayContainer: null,\n };\n this.manager = null;\n this.loader = null;\n this.cuePoints = null;\n this.events = {};\n this.safetyTimer = null;\n this.countdownTimer = null;\n\n // Setup a promise to resolve when the IMA manager is ready\n this.managerPromise = new Promise((resolve, reject) => {\n // The ad is loaded and ready\n this.on('loaded', resolve);\n\n // Ads failed\n this.on('error', reject);\n });\n\n this.load();\n }\n\n get enabled() {\n return (\n this.player.isHTML5 && this.player.isVideo && this.player.config.ads.enabled && !is.empty(this.publisherId)\n );\n }\n\n /**\n * Load the IMA SDK\n */\n load() {\n if (this.enabled) {\n // Check if the Google IMA3 SDK is loaded or load it ourselves\n if (!is.object(window.google) || !is.object(window.google.ima)) {\n loadScript(this.player.config.urls.googleIMA.sdk)\n .then(() => {\n this.ready();\n })\n .catch(() => {\n // Script failed to load or is blocked\n this.trigger('error', new Error('Google IMA SDK failed to load'));\n });\n } else {\n this.ready();\n }\n }\n }\n\n /**\n * Get the ads instance ready\n */\n ready() {\n // Start ticking our safety timer. If the whole advertisement\n // thing doesn't resolve within our set time; we bail\n this.startSafetyTimer(12000, 'ready()');\n\n // Clear the safety timer\n this.managerPromise.then(() => {\n this.clearSafetyTimer('onAdsManagerLoaded()');\n });\n\n // Set listeners on the Plyr instance\n this.listeners();\n\n // Setup the IMA SDK\n this.setupIMA();\n }\n\n // Build the default tag URL\n get tagUrl() {\n const params = {\n AV_PUBLISHERID: '58c25bb0073ef448b1087ad6',\n AV_CHANNELID: '5a0458dc28a06145e4519d21',\n AV_URL: window.location.hostname,\n cb: Date.now(),\n AV_WIDTH: 640,\n AV_HEIGHT: 480,\n AV_CDIM2: this.publisherId,\n };\n\n const base = 'https://go.aniview.com/api/adserver6/vast/';\n\n return `${base}?${buildUrlParams(params)}`;\n }\n\n /**\n * In order for the SDK to display ads for our video, we need to tell it where to put them,\n * so here we define our ad container. This div is set up to render on top of the video player.\n * Using the code below, we tell the SDK to render ads within that div. We also provide a\n * handle to the content video player - the SDK will poll the current time of our player to\n * properly place mid-rolls. After we create the ad display container, we initialize it. On\n * mobile devices, this initialization is done as the result of a user action.\n */\n setupIMA() {\n // Create the container for our advertisements\n this.elements.container = createElement('div', {\n class: this.player.config.classNames.ads,\n });\n this.player.elements.container.appendChild(this.elements.container);\n\n // So we can run VPAID2\n google.ima.settings.setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);\n\n // Set language\n google.ima.settings.setLocale(this.player.config.ads.language);\n\n // We assume the adContainer is the video container of the plyr element\n // that will house the ads\n this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container);\n\n // Request video ads to be pre-loaded\n this.requestAds();\n }\n\n /**\n * Request advertisements\n */\n requestAds() {\n const { container } = this.player.elements;\n\n try {\n // Create ads loader\n this.loader = new google.ima.AdsLoader(this.elements.displayContainer);\n\n // Listen and respond to ads loaded and error events\n this.loader.addEventListener(\n google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,\n event => this.onAdsManagerLoaded(event),\n false,\n );\n this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, error => this.onAdError(error), false);\n\n // Request video ads\n const request = new google.ima.AdsRequest();\n request.adTagUrl = this.tagUrl;\n\n // Specify the linear and nonlinear slot sizes. This helps the SDK\n // to select the correct creative if multiple are returned\n request.linearAdSlotWidth = container.offsetWidth;\n request.linearAdSlotHeight = container.offsetHeight;\n request.nonLinearAdSlotWidth = container.offsetWidth;\n request.nonLinearAdSlotHeight = container.offsetHeight;\n\n // We only overlay ads as we only support video.\n request.forceNonLinearFullSlot = false;\n\n // Mute based on current state\n request.setAdWillPlayMuted(!this.player.muted);\n\n this.loader.requestAds(request);\n } catch (e) {\n this.onAdError(e);\n }\n }\n\n /**\n * Update the ad countdown\n * @param {boolean} start\n */\n pollCountdown(start = false) {\n if (!start) {\n clearInterval(this.countdownTimer);\n this.elements.container.removeAttribute('data-badge-text');\n return;\n }\n\n const update = () => {\n const time = formatTime(Math.max(this.manager.getRemainingTime(), 0));\n const label = `${i18n.get('advertisement', this.player.config)} - ${time}`;\n this.elements.container.setAttribute('data-badge-text', label);\n };\n\n this.countdownTimer = setInterval(update, 100);\n }\n\n /**\n * This method is called whenever the ads are ready inside the AdDisplayContainer\n * @param {Event} adsManagerLoadedEvent\n */\n onAdsManagerLoaded(event) {\n // Load could occur after a source change (race condition)\n if (!this.enabled) {\n return;\n }\n\n // Get the ads manager\n const settings = new google.ima.AdsRenderingSettings();\n\n // Tell the SDK to save and restore content video state on our behalf\n settings.restoreCustomPlaybackStateOnAdBreakComplete = true;\n settings.enablePreloading = true;\n\n // The SDK is polling currentTime on the contentPlayback. And needs a duration\n // so it can determine when to start the mid- and post-roll\n this.manager = event.getAdsManager(this.player, settings);\n\n // Get the cue points for any mid-rolls by filtering out the pre- and post-roll\n this.cuePoints = this.manager.getCuePoints();\n\n // Add advertisement cue's within the time line if available\n if (!is.empty(this.cuePoints)) {\n this.cuePoints.forEach(cuePoint => {\n if (cuePoint !== 0 && cuePoint !== -1 && cuePoint < this.player.duration) {\n const seekElement = this.player.elements.progress;\n\n if (is.element(seekElement)) {\n const cuePercentage = 100 / this.player.duration * cuePoint;\n const cue = createElement('span', {\n class: this.player.config.classNames.cues,\n });\n\n cue.style.left = `${cuePercentage.toString()}%`;\n seekElement.appendChild(cue);\n }\n }\n });\n }\n\n // Set volume to match player\n this.manager.setVolume(this.player.volume);\n\n // Add listeners to the required events\n // Advertisement error events\n this.manager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, error => this.onAdError(error));\n\n // Advertisement regular events\n Object.keys(google.ima.AdEvent.Type).forEach(type => {\n this.manager.addEventListener(google.ima.AdEvent.Type[type], event => this.onAdEvent(event));\n });\n\n // Resolve our adsManager\n this.trigger('loaded');\n }\n\n /**\n * This is where all the event handling takes place. Retrieve the ad from the event. Some\n * events (e.g. ALL_ADS_COMPLETED) don't have the ad object associated\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type\n * @param {Event} event\n */\n onAdEvent(event) {\n const { container } = this.player.elements;\n\n // Retrieve the ad from the event. Some events (e.g. ALL_ADS_COMPLETED)\n // don't have ad object associated\n const ad = event.getAd();\n\n // Proxy event\n const dispatchEvent = type => {\n const event = `ads${type.replace(/_/g, '').toLowerCase()}`;\n triggerEvent.call(this.player, this.player.media, event);\n };\n\n switch (event.type) {\n case google.ima.AdEvent.Type.LOADED:\n // This is the first event sent for an ad - it is possible to determine whether the\n // ad is a video ad or an overlay\n this.trigger('loaded');\n\n // Bubble event\n dispatchEvent(event.type);\n\n // Start countdown\n this.pollCountdown(true);\n\n if (!ad.isLinear()) {\n // Position AdDisplayContainer correctly for overlay\n ad.width = container.offsetWidth;\n ad.height = container.offsetHeight;\n }\n\n // console.info('Ad type: ' + event.getAd().getAdPodInfo().getPodIndex());\n // console.info('Ad time: ' + event.getAd().getAdPodInfo().getTimeOffset());\n break;\n\n case google.ima.AdEvent.Type.ALL_ADS_COMPLETED:\n // All ads for the current videos are done. We can now request new advertisements\n // in case the video is re-played\n\n // Fire event\n dispatchEvent(event.type);\n\n // TODO: Example for what happens when a next video in a playlist would be loaded.\n // So here we load a new video when all ads are done.\n // Then we load new ads within a new adsManager. When the video\n // Is started - after - the ads are loaded, then we get ads.\n // You can also easily test cancelling and reloading by running\n // player.ads.cancel() and player.ads.play from the console I guess.\n // this.player.source = {\n // type: 'video',\n // title: 'View From A Blue Moon',\n // sources: [{\n // src:\n // 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4', type:\n // 'video/mp4', }], poster:\n // 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg', tracks:\n // [ { kind: 'captions', label: 'English', srclang: 'en', src:\n // 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt',\n // default: true, }, { kind: 'captions', label: 'French', srclang: 'fr', src:\n // 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt', }, ],\n // };\n\n // TODO: So there is still this thing where a video should only be allowed to start\n // playing when the IMA SDK is ready or has failed\n\n this.loadAds();\n break;\n\n case google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED:\n // This event indicates the ad has started - the video player can adjust the UI,\n // for example display a pause button and remaining time. Fired when content should\n // be paused. This usually happens right before an ad is about to cover the content\n\n dispatchEvent(event.type);\n\n this.pauseContent();\n\n break;\n\n case google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED:\n // This event indicates the ad has finished - the video player can perform\n // appropriate UI actions, such as removing the timer for remaining time detection.\n // Fired when content should be resumed. This usually happens when an ad finishes\n // or collapses\n\n dispatchEvent(event.type);\n\n this.pollCountdown();\n\n this.resumeContent();\n\n break;\n\n case google.ima.AdEvent.Type.STARTED:\n case google.ima.AdEvent.Type.MIDPOINT:\n case google.ima.AdEvent.Type.COMPLETE:\n case google.ima.AdEvent.Type.IMPRESSION:\n case google.ima.AdEvent.Type.CLICK:\n dispatchEvent(event.type);\n break;\n\n default:\n break;\n }\n }\n\n /**\n * Any ad error handling comes through here\n * @param {Event} event\n */\n onAdError(event) {\n this.cancel();\n this.player.debug.warn('Ads error', event);\n }\n\n /**\n * Setup hooks for Plyr and window events. This ensures\n * the mid- and post-roll launch at the correct time. And\n * resize the advertisement when the player resizes\n */\n listeners() {\n const { container } = this.player.elements;\n let time;\n\n // Add listeners to the required events\n this.player.on('ended', () => {\n this.loader.contentComplete();\n });\n\n this.player.on('seeking', () => {\n time = this.player.currentTime;\n return time;\n });\n\n this.player.on('seeked', () => {\n const seekedTime = this.player.currentTime;\n\n if (is.empty(this.cuePoints)) {\n return;\n }\n\n this.cuePoints.forEach((cuePoint, index) => {\n if (time < cuePoint && cuePoint < seekedTime) {\n this.manager.discardAdBreak();\n this.cuePoints.splice(index, 1);\n }\n });\n });\n\n // Listen to the resizing of the window. And resize ad accordingly\n // TODO: eventually implement ResizeObserver\n window.addEventListener('resize', () => {\n if (this.manager) {\n this.manager.resize(container.offsetWidth, container.offsetHeight, google.ima.ViewMode.NORMAL);\n }\n });\n }\n\n /**\n * Initialize the adsManager and start playing advertisements\n */\n play() {\n const { container } = this.player.elements;\n\n if (!this.managerPromise) {\n this.resumeContent();\n }\n\n // Play the requested advertisement whenever the adsManager is ready\n this.managerPromise\n .then(() => {\n // Initialize the container. Must be done via a user action on mobile devices\n this.elements.displayContainer.initialize();\n\n try {\n if (!this.initialized) {\n // Initialize the ads manager. Ad rules playlist will start at this time\n this.manager.init(container.offsetWidth, container.offsetHeight, google.ima.ViewMode.NORMAL);\n\n // Call play to start showing the ad. Single video and overlay ads will\n // start at this time; the call will be ignored for ad rules\n this.manager.start();\n }\n\n this.initialized = true;\n } catch (adError) {\n // An error may be thrown if there was a problem with the\n // VAST response\n this.onAdError(adError);\n }\n })\n .catch(() => {});\n }\n\n /**\n * Resume our video\n */\n resumeContent() {\n // Hide the advertisement container\n this.elements.container.style.zIndex = '';\n\n // Ad is stopped\n this.playing = false;\n\n // Play our video\n if (this.player.currentTime < this.player.duration) {\n this.player.play();\n }\n }\n\n /**\n * Pause our video\n */\n pauseContent() {\n // Show the advertisement container\n this.elements.container.style.zIndex = 3;\n\n // Ad is playing.\n this.playing = true;\n\n // Pause our video.\n this.player.pause();\n }\n\n /**\n * Destroy the adsManager so we can grab new ads after this. If we don't then we're not\n * allowed to call new ads based on google policies, as they interpret this as an accidental\n * video requests. https://developers.google.com/interactive-\n * media-ads/docs/sdks/android/faq#8\n */\n cancel() {\n // Pause our video\n if (this.initialized) {\n this.resumeContent();\n }\n\n // Tell our instance that we're done for now\n this.trigger('error');\n\n // Re-create our adsManager\n this.loadAds();\n }\n\n /**\n * Re-create our adsManager\n */\n loadAds() {\n // Tell our adsManager to go bye bye\n this.managerPromise\n .then(() => {\n // Destroy our adsManager\n if (this.manager) {\n this.manager.destroy();\n }\n\n // Re-set our adsManager promises\n this.managerPromise = new Promise(resolve => {\n this.on('loaded', resolve);\n this.player.debug.log(this.manager);\n });\n\n // Now request some new advertisements\n this.requestAds();\n })\n .catch(() => {});\n }\n\n /**\n * Handles callbacks after an ad event was invoked\n * @param {string} event - Event type\n */\n trigger(event, ...args) {\n const handlers = this.events[event];\n\n if (is.array(handlers)) {\n handlers.forEach(handler => {\n if (is.function(handler)) {\n handler.apply(this, args);\n }\n });\n }\n }\n\n /**\n * Add event listeners\n * @param {string} event - Event type\n * @param {function} callback - Callback for when event occurs\n * @return {Ads}\n */\n on(event, callback) {\n if (!is.array(this.events[event])) {\n this.events[event] = [];\n }\n\n this.events[event].push(callback);\n\n return this;\n }\n\n /**\n * Setup a safety timer for when the ad network doesn't respond for whatever reason.\n * The advertisement has 12 seconds to get its things together. We stop this timer when the\n * advertisement is playing, or when a user action is required to start, then we clear the\n * timer on ad ready\n * @param {number} time\n * @param {string} from\n */\n startSafetyTimer(time, from) {\n this.player.debug.log(`Safety timer invoked from: ${from}`);\n\n this.safetyTimer = setTimeout(() => {\n this.cancel();\n this.clearSafetyTimer('startSafetyTimer()');\n }, time);\n }\n\n /**\n * Clear our safety timer(s)\n * @param {string} from\n */\n clearSafetyTimer(from) {\n if (!is.nullOrUndefined(this.safetyTimer)) {\n this.player.debug.log(`Safety timer cleared from: ${from}`);\n\n clearTimeout(this.safetyTimer);\n this.safetyTimer = null;\n }\n }\n}\n\nexport default Ads;\n","// ==========================================================================\n// Plyr source update\n// ==========================================================================\n\nimport { providers } from './config/types';\nimport html5 from './html5';\nimport media from './media';\nimport support from './support';\nimport ui from './ui';\nimport { createElement, insertElement, removeElement } from './utils/elements';\nimport is from './utils/is';\nimport { getDeep } from './utils/objects';\n\nconst source = {\n // Add elements to HTML5 media (source, tracks, etc)\n insertElements(type, attributes) {\n if (is.string(attributes)) {\n insertElement(type, this.media, {\n src: attributes,\n });\n } else if (is.array(attributes)) {\n attributes.forEach(attribute => {\n insertElement(type, this.media, attribute);\n });\n }\n },\n\n // Update source\n // Sources are not checked for support so be careful\n change(input) {\n if (!getDeep(input, 'sources.length')) {\n this.debug.warn('Invalid source format');\n return;\n }\n\n // Cancel current network requests\n html5.cancelRequests.call(this);\n\n // Destroy instance and re-setup\n this.destroy.call(\n this,\n () => {\n // Reset quality options\n this.options.quality = [];\n\n // Remove elements\n removeElement(this.media);\n this.media = null;\n\n // Reset class name\n if (is.element(this.elements.container)) {\n this.elements.container.removeAttribute('class');\n }\n\n // Set the type and provider\n const { sources, type } = input;\n const [{ provider = providers.html5, src }] = sources;\n const tagName = provider === 'html5' ? type : 'div';\n const attributes = provider === 'html5' ? {} : { src };\n\n Object.assign(this, {\n provider,\n type,\n // Check for support\n supported: support.check(type, provider, this.config.playsinline),\n // Create new element\n media: createElement(tagName, attributes),\n });\n\n // Inject the new element\n this.elements.container.appendChild(this.media);\n\n // Autoplay the new source?\n if (is.boolean(input.autoplay)) {\n this.config.autoplay = input.autoplay;\n }\n\n // Set attributes for audio and video\n if (this.isHTML5) {\n if (this.config.crossorigin) {\n this.media.setAttribute('crossorigin', '');\n }\n if (this.config.autoplay) {\n this.media.setAttribute('autoplay', '');\n }\n if (!is.empty(input.poster)) {\n this.poster = input.poster;\n }\n if (this.config.loop.active) {\n this.media.setAttribute('loop', '');\n }\n if (this.config.muted) {\n this.media.setAttribute('muted', '');\n }\n if (this.config.playsinline) {\n this.media.setAttribute('playsinline', '');\n }\n }\n\n // Restore class hook\n ui.addStyleHook.call(this);\n\n // Set new sources for html5\n if (this.isHTML5) {\n source.insertElements.call(this, 'source', sources);\n }\n\n // Set video title\n this.config.title = input.title;\n\n // Set up from scratch\n media.setup.call(this);\n\n // HTML5 stuff\n if (this.isHTML5) {\n // Setup captions\n if ('tracks' in input) {\n source.insertElements.call(this, 'track', input.tracks);\n }\n\n // Load HTML5 sources\n this.media.load();\n }\n\n // If HTML5 or embed but not fully supported, setupInterface and call ready now\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n // Setup interface\n ui.build.call(this);\n }\n\n // Update the fullscreen support\n this.fullscreen.update();\n },\n true,\n );\n },\n};\n\nexport default source;\n","// ==========================================================================\n// Plyr\n// plyr.js v3.4.5\n// https://github.com/sampotts/plyr\n// License: The MIT License (MIT)\n// ==========================================================================\n\nimport captions from './captions';\nimport defaults from './config/defaults';\nimport { getProviderByUrl, providers, types } from './config/types';\nimport Console from './console';\nimport controls from './controls';\nimport Fullscreen from './fullscreen';\nimport Listeners from './listeners';\nimport media from './media';\nimport Ads from './plugins/ads';\nimport source from './source';\nimport Storage from './storage';\nimport support from './support';\nimport ui from './ui';\nimport { closest } from './utils/arrays';\nimport { createElement, hasClass, removeElement, replaceElement, toggleClass, wrap } from './utils/elements';\nimport { off, on, once, triggerEvent, unbindListeners } from './utils/events';\nimport is from './utils/is';\nimport loadSprite from './utils/loadSprite';\nimport { cloneDeep, extend } from './utils/objects';\nimport { parseUrl } from './utils/urls';\n\n// Private properties\n// TODO: Use a WeakMap for private globals\n// const globals = new WeakMap();\n\n// Plyr instance\nclass Plyr {\n constructor(target, options) {\n this.timers = {};\n\n // State\n this.ready = false;\n this.loading = false;\n this.failed = false;\n\n // Touch device\n this.touch = support.touch;\n\n // Set the media element\n this.media = target;\n\n // String selector passed\n if (is.string(this.media)) {\n this.media = document.querySelectorAll(this.media);\n }\n\n // jQuery, NodeList or Array passed, use first element\n if ((window.jQuery && this.media instanceof jQuery) || is.nodeList(this.media) || is.array(this.media)) {\n // eslint-disable-next-line\n this.media = this.media[0];\n }\n\n // Set config\n this.config = extend(\n {},\n defaults,\n Plyr.defaults,\n options || {},\n (() => {\n try {\n return JSON.parse(this.media.getAttribute('data-plyr-config'));\n } catch (e) {\n return {};\n }\n })(),\n );\n\n // Elements cache\n this.elements = {\n container: null,\n captions: null,\n buttons: {},\n display: {},\n progress: {},\n inputs: {},\n settings: {\n popup: null,\n menu: null,\n panels: {},\n buttons: {},\n },\n };\n\n // Captions\n this.captions = {\n active: null,\n currentTrack: -1,\n meta: new WeakMap(),\n };\n\n // Fullscreen\n this.fullscreen = {\n active: false,\n };\n\n // Options\n this.options = {\n speed: [],\n quality: [],\n };\n\n // Debugging\n // TODO: move to globals\n this.debug = new Console(this.config.debug);\n\n // Log config options and support\n this.debug.log('Config', this.config);\n this.debug.log('Support', support);\n\n // We need an element to setup\n if (is.nullOrUndefined(this.media) || !is.element(this.media)) {\n this.debug.error('Setup failed: no suitable element passed');\n return;\n }\n\n // Bail if the element is initialized\n if (this.media.plyr) {\n this.debug.warn('Target already setup');\n return;\n }\n\n // Bail if not enabled\n if (!this.config.enabled) {\n this.debug.error('Setup failed: disabled by config');\n return;\n }\n\n // Bail if disabled or no basic support\n // You may want to disable certain UAs etc\n if (!support.check().api) {\n this.debug.error('Setup failed: no support');\n return;\n }\n\n // Cache original element state for .destroy()\n const clone = this.media.cloneNode(true);\n clone.autoplay = false;\n this.elements.original = clone;\n\n // Set media type based on tag or data attribute\n // Supported: video, audio, vimeo, youtube\n const type = this.media.tagName.toLowerCase();\n\n // Embed properties\n let iframe = null;\n let url = null;\n\n // Different setup based on type\n switch (type) {\n case 'div':\n // Find the frame\n iframe = this.media.querySelector('iframe');\n\n // <iframe> type\n if (is.element(iframe)) {\n // Detect provider\n url = parseUrl(iframe.getAttribute('src'));\n this.provider = getProviderByUrl(url.toString());\n\n // Rework elements\n this.elements.container = this.media;\n this.media = iframe;\n\n // Reset classname\n this.elements.container.className = '';\n\n // Get attributes from URL and set config\n if (url.search.length) {\n const truthy = ['1', 'true'];\n\n if (truthy.includes(url.searchParams.get('autoplay'))) {\n this.config.autoplay = true;\n }\n if (truthy.includes(url.searchParams.get('loop'))) {\n this.config.loop.active = true;\n }\n\n // TODO: replace fullscreen.iosNative with this playsinline config option\n // YouTube requires the playsinline in the URL\n if (this.isYouTube) {\n this.config.playsinline = truthy.includes(url.searchParams.get('playsinline'));\n this.config.hl = url.searchParams.get('hl'); // TODO: Should this be setting language?\n } else {\n this.config.playsinline = true;\n }\n }\n } else {\n // <div> with attributes\n this.provider = this.media.getAttribute(this.config.attributes.embed.provider);\n\n // Remove attribute\n this.media.removeAttribute(this.config.attributes.embed.provider);\n }\n\n // Unsupported or missing provider\n if (is.empty(this.provider) || !Object.keys(providers).includes(this.provider)) {\n this.debug.error('Setup failed: Invalid provider');\n return;\n }\n\n // Audio will come later for external providers\n this.type = types.video;\n\n break;\n\n case 'video':\n case 'audio':\n this.type = type;\n this.provider = providers.html5;\n\n // Get config from attributes\n if (this.media.hasAttribute('crossorigin')) {\n this.config.crossorigin = true;\n }\n if (this.media.hasAttribute('autoplay')) {\n this.config.autoplay = true;\n }\n if (this.media.hasAttribute('playsinline') || this.media.hasAttribute('webkit-playsinline')) {\n this.config.playsinline = true;\n }\n if (this.media.hasAttribute('muted')) {\n this.config.muted = true;\n }\n if (this.media.hasAttribute('loop')) {\n this.config.loop.active = true;\n }\n\n break;\n\n default:\n this.debug.error('Setup failed: unsupported type');\n return;\n }\n\n // Check for support again but with type\n this.supported = support.check(this.type, this.provider, this.config.playsinline);\n\n // If no support for even API, bail\n if (!this.supported.api) {\n this.debug.error('Setup failed: no support');\n return;\n }\n\n this.eventListeners = [];\n\n // Create listeners\n this.listeners = new Listeners(this);\n\n // Setup local storage for user settings\n this.storage = new Storage(this);\n\n // Store reference\n this.media.plyr = this;\n\n // Wrap media\n if (!is.element(this.elements.container)) {\n this.elements.container = createElement('div');\n wrap(this.media, this.elements.container);\n }\n\n // Add style hook\n ui.addStyleHook.call(this);\n\n // Setup media\n media.setup.call(this);\n\n // Listen for events if debugging\n if (this.config.debug) {\n on.call(this, this.elements.container, this.config.events.join(' '), event => {\n this.debug.log(`event: ${event.type}`);\n });\n }\n\n // Setup interface\n // If embed but not fully supported, build interface now to avoid flash of controls\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n ui.build.call(this);\n }\n\n // Container listeners\n this.listeners.container();\n\n // Global listeners\n this.listeners.global();\n\n // Setup fullscreen\n this.fullscreen = new Fullscreen(this);\n\n // Setup ads if provided\n if (this.config.ads.enabled) {\n this.ads = new Ads(this);\n }\n\n // Autoplay if required\n if (this.config.autoplay) {\n this.play();\n }\n\n // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek\n this.lastSeekTime = 0;\n }\n\n // ---------------------------------------\n // API\n // ---------------------------------------\n\n /**\n * Types and provider helpers\n */\n get isHTML5() {\n return Boolean(this.provider === providers.html5);\n }\n\n get isEmbed() {\n return Boolean(this.isYouTube || this.isVimeo);\n }\n\n get isYouTube() {\n return Boolean(this.provider === providers.youtube);\n }\n\n get isVimeo() {\n return Boolean(this.provider === providers.vimeo);\n }\n\n get isVideo() {\n return Boolean(this.type === types.video);\n }\n\n get isAudio() {\n return Boolean(this.type === types.audio);\n }\n\n /**\n * Play the media, or play the advertisement (if they are not blocked)\n */\n play() {\n if (!is.function(this.media.play)) {\n return null;\n }\n\n // Return the promise (for HTML5)\n return this.media.play();\n }\n\n /**\n * Pause the media\n */\n pause() {\n if (!this.playing || !is.function(this.media.pause)) {\n return;\n }\n\n this.media.pause();\n }\n\n /**\n * Get playing state\n */\n get playing() {\n return Boolean(this.ready && !this.paused && !this.ended);\n }\n\n /**\n * Get paused state\n */\n get paused() {\n return Boolean(this.media.paused);\n }\n\n /**\n * Get stopped state\n */\n get stopped() {\n return Boolean(this.paused && this.currentTime === 0);\n }\n\n /**\n * Get ended state\n */\n get ended() {\n return Boolean(this.media.ended);\n }\n\n /**\n * Toggle playback based on current status\n * @param {boolean} input\n */\n togglePlay(input) {\n // Toggle based on current state if nothing passed\n const toggle = is.boolean(input) ? input : !this.playing;\n\n if (toggle) {\n this.play();\n } else {\n this.pause();\n }\n }\n\n /**\n * Stop playback\n */\n stop() {\n if (this.isHTML5) {\n this.pause();\n this.restart();\n } else if (is.function(this.media.stop)) {\n this.media.stop();\n }\n }\n\n /**\n * Restart playback\n */\n restart() {\n this.currentTime = 0;\n }\n\n /**\n * Rewind\n * @param {number} seekTime - how far to rewind in seconds. Defaults to the config.seekTime\n */\n rewind(seekTime) {\n this.currentTime = this.currentTime - (is.number(seekTime) ? seekTime : this.config.seekTime);\n }\n\n /**\n * Fast forward\n * @param {number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime\n */\n forward(seekTime) {\n this.currentTime = this.currentTime + (is.number(seekTime) ? seekTime : this.config.seekTime);\n }\n\n /**\n * Seek to a time\n * @param {number} input - where to seek to in seconds. Defaults to 0 (the start)\n */\n set currentTime(input) {\n // Bail if media duration isn't available yet\n if (!this.duration) {\n return;\n }\n\n // Validate input\n const inputIsValid = is.number(input) && input > 0;\n\n // Set\n this.media.currentTime = inputIsValid ? Math.min(input, this.duration) : 0;\n\n // Logging\n this.debug.log(`Seeking to ${this.currentTime} seconds`);\n }\n\n /**\n * Get current time\n */\n get currentTime() {\n return Number(this.media.currentTime);\n }\n\n /**\n * Get buffered\n */\n get buffered() {\n const { buffered } = this.media;\n\n // YouTube / Vimeo return a float between 0-1\n if (is.number(buffered)) {\n return buffered;\n }\n\n // HTML5\n // TODO: Handle buffered chunks of the media\n // (i.e. seek to another section buffers only that section)\n if (buffered && buffered.length && this.duration > 0) {\n return buffered.end(0) / this.duration;\n }\n\n return 0;\n }\n\n /**\n * Get seeking status\n */\n get seeking() {\n return Boolean(this.media.seeking);\n }\n\n /**\n * Get the duration of the current media\n */\n get duration() {\n // Faux duration set via config\n const fauxDuration = parseFloat(this.config.duration);\n\n // Media duration can be NaN or Infinity before the media has loaded\n const realDuration = (this.media || {}).duration;\n const duration = !is.number(realDuration) || realDuration === Infinity ? 0 : realDuration;\n\n // If config duration is funky, use regular duration\n return fauxDuration || duration;\n }\n\n /**\n * Set the player volume\n * @param {number} value - must be between 0 and 1. Defaults to the value from local storage and config.volume if not set in storage\n */\n set volume(value) {\n let volume = value;\n const max = 1;\n const min = 0;\n\n if (is.string(volume)) {\n volume = Number(volume);\n }\n\n // Load volume from storage if no value specified\n if (!is.number(volume)) {\n volume = this.storage.get('volume');\n }\n\n // Use config if all else fails\n if (!is.number(volume)) {\n ({ volume } = this.config);\n }\n\n // Maximum is volumeMax\n if (volume > max) {\n volume = max;\n }\n // Minimum is volumeMin\n if (volume < min) {\n volume = min;\n }\n\n // Update config\n this.config.volume = volume;\n\n // Set the player volume\n this.media.volume = volume;\n\n // If muted, and we're increasing volume manually, reset muted state\n if (!is.empty(value) && this.muted && volume > 0) {\n this.muted = false;\n }\n }\n\n /**\n * Get the current player volume\n */\n get volume() {\n return Number(this.media.volume);\n }\n\n /**\n * Increase volume\n * @param {boolean} step - How much to decrease by (between 0 and 1)\n */\n increaseVolume(step) {\n const volume = this.media.muted ? 0 : this.volume;\n this.volume = volume + (is.number(step) ? step : 0);\n }\n\n /**\n * Decrease volume\n * @param {boolean} step - How much to decrease by (between 0 and 1)\n */\n decreaseVolume(step) {\n this.increaseVolume(-step);\n }\n\n /**\n * Set muted state\n * @param {boolean} mute\n */\n set muted(mute) {\n let toggle = mute;\n\n // Load muted state from storage\n if (!is.boolean(toggle)) {\n toggle = this.storage.get('muted');\n }\n\n // Use config if all else fails\n if (!is.boolean(toggle)) {\n toggle = this.config.muted;\n }\n\n // Update config\n this.config.muted = toggle;\n\n // Set mute on the player\n this.media.muted = toggle;\n }\n\n /**\n * Get current muted state\n */\n get muted() {\n return Boolean(this.media.muted);\n }\n\n /**\n * Check if the media has audio\n */\n get hasAudio() {\n // Assume yes for all non HTML5 (as we can't tell...)\n if (!this.isHTML5) {\n return true;\n }\n\n if (this.isAudio) {\n return true;\n }\n\n // Get audio tracks\n return (\n Boolean(this.media.mozHasAudio) ||\n Boolean(this.media.webkitAudioDecodedByteCount) ||\n Boolean(this.media.audioTracks && this.media.audioTracks.length)\n );\n }\n\n /**\n * Set playback speed\n * @param {number} speed - the speed of playback (0.5-2.0)\n */\n set speed(input) {\n let speed = null;\n\n if (is.number(input)) {\n speed = input;\n }\n\n if (!is.number(speed)) {\n speed = this.storage.get('speed');\n }\n\n if (!is.number(speed)) {\n speed = this.config.speed.selected;\n }\n\n // Set min/max\n if (speed < 0.1) {\n speed = 0.1;\n }\n if (speed > 2.0) {\n speed = 2.0;\n }\n\n if (!this.config.speed.options.includes(speed)) {\n this.debug.warn(`Unsupported speed (${speed})`);\n return;\n }\n\n // Update config\n this.config.speed.selected = speed;\n\n // Set media speed\n this.media.playbackRate = speed;\n }\n\n /**\n * Get current playback speed\n */\n get speed() {\n return Number(this.media.playbackRate);\n }\n\n /**\n * Set playback quality\n * Currently HTML5 & YouTube only\n * @param {number} input - Quality level\n */\n set quality(input) {\n const config = this.config.quality;\n const options = this.options.quality;\n\n if (!options.length) {\n return;\n }\n\n let quality = [\n !is.empty(input) && Number(input),\n this.storage.get('quality'),\n config.selected,\n config.default,\n ].find(is.number);\n\n if (!options.includes(quality)) {\n const value = closest(options, quality);\n this.debug.warn(`Unsupported quality option: ${quality}, using ${value} instead`);\n quality = value;\n }\n\n // Update config\n config.selected = quality;\n\n // Set quality\n this.media.quality = quality;\n }\n\n /**\n * Get current quality level\n */\n get quality() {\n return this.media.quality;\n }\n\n /**\n * Toggle loop\n * TODO: Finish fancy new logic. Set the indicator on load as user may pass loop as config\n * @param {boolean} input - Whether to loop or not\n */\n set loop(input) {\n const toggle = is.boolean(input) ? input : this.config.loop.active;\n this.config.loop.active = toggle;\n this.media.loop = toggle;\n\n // Set default to be a true toggle\n /* const type = ['start', 'end', 'all', 'none', 'toggle'].includes(input) ? input : 'toggle';\n\n switch (type) {\n case 'start':\n if (this.config.loop.end && this.config.loop.end <= this.currentTime) {\n this.config.loop.end = null;\n }\n this.config.loop.start = this.currentTime;\n // this.config.loop.indicator.start = this.elements.display.played.value;\n break;\n\n case 'end':\n if (this.config.loop.start >= this.currentTime) {\n return this;\n }\n this.config.loop.end = this.currentTime;\n // this.config.loop.indicator.end = this.elements.display.played.value;\n break;\n\n case 'all':\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n this.config.loop.indicator.start = 0;\n this.config.loop.indicator.end = 100;\n break;\n\n case 'toggle':\n if (this.config.loop.active) {\n this.config.loop.start = 0;\n this.config.loop.end = null;\n } else {\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n }\n break;\n\n default:\n this.config.loop.start = 0;\n this.config.loop.end = null;\n break;\n } */\n }\n\n /**\n * Get current loop state\n */\n get loop() {\n return Boolean(this.media.loop);\n }\n\n /**\n * Set new media source\n * @param {object} input - The new source object (see docs)\n */\n set source(input) {\n source.change.call(this, input);\n }\n\n /**\n * Get current source\n */\n get source() {\n return this.media.currentSrc;\n }\n\n /**\n * Get a download URL (either source or custom)\n */\n get download() {\n const { download } = this.config.urls;\n\n return is.url(download) ? download : this.source;\n }\n\n /**\n * Set the poster image for a video\n * @param {input} - the URL for the new poster image\n */\n set poster(input) {\n if (!this.isVideo) {\n this.debug.warn('Poster can only be set for video');\n return;\n }\n\n ui.setPoster.call(this, input, false).catch(() => {});\n }\n\n /**\n * Get the current poster image\n */\n get poster() {\n if (!this.isVideo) {\n return null;\n }\n\n return this.media.getAttribute('poster');\n }\n\n /**\n * Set the autoplay state\n * @param {boolean} input - Whether to autoplay or not\n */\n set autoplay(input) {\n const toggle = is.boolean(input) ? input : this.config.autoplay;\n this.config.autoplay = toggle;\n }\n\n /**\n * Get the current autoplay state\n */\n get autoplay() {\n return Boolean(this.config.autoplay);\n }\n\n /**\n * Toggle captions\n * @param {boolean} input - Whether to enable captions\n */\n toggleCaptions(input) {\n captions.toggle.call(this, input, false);\n }\n\n /**\n * Set the caption track by index\n * @param {number} - Caption index\n */\n set currentTrack(input) {\n captions.set.call(this, input, false);\n }\n\n /**\n * Get the current caption track index (-1 if disabled)\n */\n get currentTrack() {\n const { toggled, currentTrack } = this.captions;\n return toggled ? currentTrack : -1;\n }\n\n /**\n * Set the wanted language for captions\n * Since tracks can be added later it won't update the actual caption track until there is a matching track\n * @param {string} - Two character ISO language code (e.g. EN, FR, PT, etc)\n */\n set language(input) {\n captions.setLanguage.call(this, input, false);\n }\n\n /**\n * Get the current track's language\n */\n get language() {\n return (captions.getCurrentTrack.call(this) || {}).language;\n }\n\n /**\n * Toggle picture-in-picture playback on WebKit/MacOS\n * TODO: update player with state, support, enabled\n * TODO: detect outside changes\n */\n set pip(input) {\n const states = {\n pip: 'picture-in-picture',\n inline: 'inline',\n };\n\n // Bail if no support\n if (!support.pip) {\n return;\n }\n\n // Toggle based on current state if not passed\n const toggle = is.boolean(input) ? input : this.pip === states.inline;\n\n // Toggle based on current state\n this.media.webkitSetPresentationMode(toggle ? states.pip : states.inline);\n }\n\n /**\n * Get the current picture-in-picture state\n */\n get pip() {\n if (!support.pip) {\n return null;\n }\n\n return this.media.webkitPresentationMode;\n }\n\n /**\n * Trigger the airplay dialog\n * TODO: update player with state, support, enabled\n */\n airplay() {\n // Show dialog if supported\n if (support.airplay) {\n this.media.webkitShowPlaybackTargetPicker();\n }\n }\n\n /**\n * Toggle the player controls\n * @param {boolean} [toggle] - Whether to show the controls\n */\n toggleControls(toggle) {\n // Don't toggle if missing UI support or if it's audio\n if (this.supported.ui && !this.isAudio) {\n // Get state before change\n const isHidden = hasClass(this.elements.container, this.config.classNames.hideControls);\n\n // Negate the argument if not undefined since adding the class to hides the controls\n const force = typeof toggle === 'undefined' ? undefined : !toggle;\n\n // Apply and get updated state\n const hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force);\n\n // Close menu\n if (hiding && this.config.controls.includes('settings') && !is.empty(this.config.settings)) {\n controls.toggleMenu.call(this, false);\n }\n\n // Trigger event on change\n if (hiding !== isHidden) {\n const eventName = hiding ? 'controlshidden' : 'controlsshown';\n triggerEvent.call(this, this.media, eventName);\n }\n\n return !hiding;\n }\n\n return false;\n }\n\n /**\n * Add event listeners\n * @param {string} event - Event type\n * @param {function} callback - Callback for when event occurs\n */\n on(event, callback) {\n on.call(this, this.elements.container, event, callback);\n }\n\n /**\n * Add event listeners once\n * @param {string} event - Event type\n * @param {function} callback - Callback for when event occurs\n */\n once(event, callback) {\n once.call(this, this.elements.container, event, callback);\n }\n\n /**\n * Remove event listeners\n * @param {string} event - Event type\n * @param {function} callback - Callback for when event occurs\n */\n off(event, callback) {\n off(this.elements.container, event, callback);\n }\n\n /**\n * Destroy an instance\n * Event listeners are removed when elements are removed\n * http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory\n * @param {function} callback - Callback for when destroy is complete\n * @param {boolean} soft - Whether it's a soft destroy (for source changes etc)\n */\n destroy(callback, soft = false) {\n if (!this.ready) {\n return;\n }\n\n const done = () => {\n // Reset overflow (incase destroyed while in fullscreen)\n document.body.style.overflow = '';\n\n // GC for embed\n this.embed = null;\n\n // If it's a soft destroy, make minimal changes\n if (soft) {\n if (Object.keys(this.elements).length) {\n // Remove elements\n removeElement(this.elements.buttons.play);\n removeElement(this.elements.captions);\n removeElement(this.elements.controls);\n removeElement(this.elements.wrapper);\n\n // Clear for GC\n this.elements.buttons.play = null;\n this.elements.captions = null;\n this.elements.controls = null;\n this.elements.wrapper = null;\n }\n\n // Callback\n if (is.function(callback)) {\n callback();\n }\n } else {\n // Unbind listeners\n unbindListeners.call(this);\n\n // Replace the container with the original element provided\n replaceElement(this.elements.original, this.elements.container);\n\n // Event\n triggerEvent.call(this, this.elements.original, 'destroyed', true);\n\n // Callback\n if (is.function(callback)) {\n callback.call(this.elements.original);\n }\n\n // Reset state\n this.ready = false;\n\n // Clear for garbage collection\n setTimeout(() => {\n this.elements = null;\n this.media = null;\n }, 200);\n }\n };\n\n // Stop playback\n this.stop();\n\n // Provider specific stuff\n if (this.isHTML5) {\n // Clear timeout\n clearTimeout(this.timers.loading);\n\n // Restore native video controls\n ui.toggleNativeControls.call(this, true);\n\n // Clean up\n done();\n } else if (this.isYouTube) {\n // Clear timers\n clearInterval(this.timers.buffering);\n clearInterval(this.timers.playing);\n\n // Destroy YouTube API\n if (this.embed !== null && is.function(this.embed.destroy)) {\n this.embed.destroy();\n }\n\n // Clean up\n done();\n } else if (this.isVimeo) {\n // Destroy Vimeo API\n // then clean up (wait, to prevent postmessage errors)\n if (this.embed !== null) {\n this.embed.unload().then(done);\n }\n\n // Vimeo does not always return\n setTimeout(done, 200);\n }\n }\n\n /**\n * Check for support for a mime type (HTML5 only)\n * @param {string} type - Mime type\n */\n supports(type) {\n return support.mime.call(this, type);\n }\n\n /**\n * Check for support\n * @param {string} type - Player type (audio/video)\n * @param {string} provider - Provider (html5/youtube/vimeo)\n * @param {bool} inline - Where player has `playsinline` sttribute\n */\n static supported(type, provider, inline) {\n return support.check(type, provider, inline);\n }\n\n /**\n * Load an SVG sprite into the page\n * @param {string} url - URL for the SVG sprite\n * @param {string} [id] - Unique ID\n */\n static loadSprite(url, id) {\n return loadSprite(url, id);\n }\n\n /**\n * Setup multiple instances\n * @param {*} selector\n * @param {object} options\n */\n static setup(selector, options = {}) {\n let targets = null;\n\n if (is.string(selector)) {\n targets = Array.from(document.querySelectorAll(selector));\n } else if (is.nodeList(selector)) {\n targets = Array.from(selector);\n } else if (is.array(selector)) {\n targets = selector.filter(is.element);\n }\n\n if (is.empty(targets)) {\n return null;\n }\n\n return targets.map(t => new Plyr(t, options));\n }\n}\n\nPlyr.defaults = cloneDeep(defaults);\n\nexport default Plyr;\n"]}
\ No newline at end of file |