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 1e1e4287..d7fcf076 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","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 +{"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/states.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","pictureInPictureEnabled","disablePictureInPicture","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","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","storage","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","updateStorage","prev","curr","closest","requestPictureInPicture","exitPictureInPicture","webkitPresentationMode","pictureInPictureElement","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 & Chrome only currently\n pip: (() => {\n if (browser.isIPhone) {\n return false;\n }\n\n // Safari\n // https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls\n if (is.function(createElement('video').webkitSetPresentationMode)) {\n return true;\n }\n\n // Chrome\n // https://developers.google.com/web/updates/2018/10/watch-video-using-picture-in-picture\n if (document.pictureInPictureEnabled && !createElement('video').disablePictureInPicture) {\n return true;\n }\n\n return false;\n })(),\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 });\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.4.6/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 states\n// ==========================================================================\n\nexport const pip = {\n active: 'picture-in-picture',\n inactive: 'inline',\n};\n\nexport default { pip };\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.6\n// https://github.com/sampotts/plyr\n// License: The MIT License (MIT)\n// ==========================================================================\n\nimport captions from './captions';\nimport defaults from './config/defaults';\nimport { pip } from './config/states';\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 let updateStorage = true;\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 // Don't update storage if quality is not supported\n updateStorage = false;\n }\n\n // Update config\n config.selected = quality;\n\n // Set quality\n this.media.quality = quality;\n\n // Save to storage\n if (updateStorage) {\n this.storage.set({ quality });\n }\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 // 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;\n\n // Toggle based on current state\n // Safari\n if (is.function(this.media.webkitSetPresentationMode)) {\n this.media.webkitSetPresentationMode(toggle ? pip.active : pip.inactive);\n }\n\n // Chrome\n if (is.function(this.media.requestPictureInPicture)) {\n if (!this.pip && toggle) {\n this.media.requestPictureInPicture();\n } else if (this.pip && !toggle) {\n document.exitPictureInPicture();\n }\n }\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 // Safari\n if (!is.empty(this.media.webkitPresentationMode)) {\n return this.media.webkitPresentationMode === pip.active;\n }\n\n // Chrome\n return this.media === document.pictureInPictureElement;\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 |