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 e2ee9097..f149f6eb 100644 --- a/dist/plyr.min.js.map +++ b/dist/plyr.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["src/js/types.js","src/js/support.js","src/js/defaults.js","src/js/utils.js","src/js/console.js","src/js/fullscreen.js","src/js/storage.js","src/js/plugins/ads.js","src/js/listeners.js","src/js/ui.js","src/js/controls.js","src/js/captions.js","src/js/plugins/youtube.js","src/js/plugins/vimeo.js","src/js/media.js","src/js/source.js","src/js/plyr.js"],"names":["range","providers","types","defaults","window","navigator","language","split","utils","input","this","instanceof","Plyr","getConstructor","Object","Number","isNaN","String","Boolean","Function","nullOrUndefined","Array","isArray","WeakMap","NodeList","Element","Text","Event","TextTrackCue","VTTCue","TextTrack","string","kind","test","array","nodeList","length","object","keys","constructor","document","documentMode","documentElement","style","userAgent","platform","url","Promise","resolve","reject","request","XMLHttpRequest","addEventListener","JSON","parse","responseText","e","Error","statusText","open","send","callback","error","current","querySelector","callbacks","push","element","createElement","errors","is","function","event","forEach","cb","call","err","src","first","getElementsByTagName","parentNode","insertBefore","id","hasId","querySelectorAll","container","toggleHidden","setAttribute","support","storage","cached","localStorage","getItem","data","content","fetch","then","result","empty","setItem","stringify","catch","updateSprite","innerHTML","body","childNodes","prefix","Math","floor","random","self","top","elements","wrapper","targets","from","reverse","index","child","cloneNode","parent","sibling","nextSibling","appendChild","type","attributes","text","setAttributes","textContent","target","removeElement","removeChild","lastChild","newChild","oldChild","replaceChild","key","sel","existingAttributes","existing","s","selector","trim","className","replace","parts","value","charAt","class","toggle","contains","classList","removeAttribute","prototype","matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","includes","controls","getElement","config","selectors","buttons","getElements","play","pause","restart","rewind","forward","mute","pip","airplay","settings","captions","fullscreen","progress","inputs","seek","volume","display","buffer","duration","currentTime","seekTooltip","classNames","tooltip","debug","warn","toggleNativeControls","focused","activeElement","arguments","undefined","focusable","last","trap","keyCode","getFocusElement","shiftKey","focus","preventDefault","on","off","passive","capture","Node","toggleListener","events","options","boolean","passiveListeners","bubbles","detail","CustomEvent","assign","plyr","dispatchEvent","toggleState","pressed","getAttribute","state","max","toFixed","parseInt","time","displayHours","inverted","number","formatTime","format","slice","hours","getHours","mins","getMinutes","secs","getSeconds","sources","_len","_key","source","shift","defineProperty","extend","apply","concat","toConsumableArray","youtube","vimeo","match","RegExp","$2","parser","href","search","startsWith","parseUrl","indexOf","reduce","params","hash","_hash$split2","val","decodeURIComponent","map","encodeURIComponent","join","fragment","createDocumentFragment","firstChild","innerText","width","height","ratio","getRatio","w","h","find","setTimeout","offsetHeight","provider","inline","api","ui","browser","getBrowser","playsInline","isIPhone","video","rangeInput","audio","webkitSetPresentationMode","WebKitPlaybackTargetAvailabilityEvent","media","isHTML5","canPlayType","isVideo","isAudio","supported","transitionEndEvent","matchMedia","noop","Console","enabled","console","log","bind","onChange","button","player","active","isIos","trapFocus","toggleFallback","scrollPosition","scrollX","scrollY","scrollTo","x","y","overflow","toggleClass","fallback","Fullscreen","_this","stopPropagation","update","native","iosNative","playing","webkitEnterFullscreen","requestFullScreen","webkitExitFullscreen","cancelFullScreen","exit","enter","inFrame","fullscreenElement","hasClass","fullscreenEnabled","webkitFullscreenEnabled","mozFullScreenEnabled","msFullscreenEnabled","some","pre","msExitFullscreen","Storage","store","json","get","removeItem","Ads","ads","initialized","blocked","tag","google","ready","loadScript","urls","googleIMA","manager","loader","cuePoints","safetyTimer","countdownTimer","listeners","startSafetyTimer","loaderPromise","managerPromise","clearSafetyTimer","setupIMA","ima","setVpaidMode","ImaSdkSettings","VpaidMode","ENABLED","setLocale","displayContainer","AdDisplayContainer","requestAds","AdsLoader","AdsManagerLoadedEvent","Type","ADS_MANAGER_LOADED","_this3","onAdsManagerLoaded","AdErrorEvent","AD_ERROR","onAdError","AdsRequest","adTagUrl","base","buildUrlParams","linearAdSlotWidth","offsetWidth","linearAdSlotHeight","nonLinearAdSlotWidth","nonLinearAdSlotHeight","forceNonLinearFullSlot","handleEventListeners","clearInterval","setInterval","_this4","getRemainingTime","label","i18n","advertisment","adsManagerLoadedEvent","AdsRenderingSettings","restoreCustomPlaybackStateOnAdBreakComplete","enablePreloading","getAdsManager","getCuePoints","cuePoint","seekElement","_this5","cuePercentage","cue","cues","left","toString","setVolume","AdEvent","onAdEvent","ad","getAd","_this6","LOADED","pollCountdown","isLinear","ALL_ADS_COMPLETED","loadAds","CONTENT_PAUSE_REQUESTED","pauseContent","CONTENT_RESUME_REQUESTED","resumeContent","STARTED","MIDPOINT","COMPLETE","IMPRESSION","CLICK","cancel","contentComplete","_this7","seekedTime","discardAdBreak","splice","resize","ViewMode","NORMAL","initialize","_this8","init","start","adError","_this9","destroy","handleKey","code","which","getKeyCode","repeat","altKey","ctrlKey","metaKey","editable","togglePlay","increaseVolume","decreaseVolume","muted","toggleCaptions","loop","keyboard","global","tabFocus","hideControls","toggleControls","timeUpdate","_this2","durationUpdate","hasAudio","showPosterOnEnd","load","updateProgress","updateVolume","checkPlaying","checkLoading","clickToPlay","touch","paused","ended","disableContextMenu","set","updateSetting","speed","quality","inputEvent","isIE","proxy","handlerKey","defaultHandler","customHandler","defaultPrevented","toggleMenu","form","parseFloat","showTab","toggleInvert","invertTime","isWebkit","updateRangeFill","updateSeekTooltip","hover","webkitDirectionInvertedFromDevice","direction","deltaY","deltaX","uiSupported","inject","setup","setTitle","title","isEmbed","iframe","frameTitle","stopped","loading","timers","failed","networkState","setRange","nodeValue","buffered","getPercentage","end","setProgress","invert","updateTimeDisplay","seeking","hasDuration","displayDuration","setProperty","iconUrl","svg4everybody","getIconUrl","iconPath","absolute","iconPrefix","icon","createElementNS","use","path","setAttributeNS","attr","hidden","badge","menu","buttonType","labelPressed","iconPressed","control","createIcon","createLabel","getAttributesFromSelector","suffix","played","toLowerCase","list","checked","item","radio","faux","aria-hidden","insertAdjacentHTML","tooltips","percent","clientRect","getBoundingClientRect","visible","pageX","setting","tab","tabs","pane","panes","filter","isYouTube","toggleTab","emptyElement","createMenuItem","getLabel","createBadge","getBadge","getLanguage","default","textTracks","getTracks","none","currentTrack","getCurrentTrack","track","disabled","hasTracks","tracks","toUpperCase","unshift","show","isMenuItem","isButton","clone","position","opacity","name","scrollWidth","scrollHeight","getElementById","transitions","reducedMotion","size","getTabSize","restore","propertyName","createButton","createRange","createProgress","createTime","inner","home","back","setSpeedMenu","loadSprite","seekTime","create","findElements","repaint","labels","stored","setCaptionsMenu","insertAfter","setLanguage","setCue","mode","activeCues","isVimeo","embed","enableTextTrack","setText","getCueAsHTML","caption","setAspectRatio","YT","Player","onYouTubeReadyCallbacks","onYouTubeIframeAPIReady","videoId","getVideoData","items","snippet","paddingBottom","currentId","parseYouTubeId","generateId","replaceElement","autoplay","location","message","instance","getPlaybackQuality","playbackRate","getPlaybackRate","getTitle","playVideo","pauseVideo","stop","stopVideo","getDuration","getCurrentTime","seekTo","setPlaybackRate","setPlaybackQuality","getVideoUrl","getAvailablePlaybackRates","buffering","getVideoLoadedFraction","lastBuffered","build","setQualityMenu","getAvailableQualityLevels","Vimeo","padding","offset","transform","parseVimeoId","setCurrentTime","selected","setLoop","currentSrc","all","getVideoWidth","getVideoHeight","dimensions","getAspectRatio","setAutopause","autopause","getVideoTitle","getTextTracks","stripHTML","seconds","isTouch","wrap","blankVideo","insertElement","attribute","cancelRequests","html5","check","crossorigin","poster","addStyleHook","insertElements","jQuery","original","tagName","getProviderByUrl","getUrlParams","truthy","playsinline","hasAttribute","step","webkitShowPlaybackTargetPicker","delay","isEnterFullscreen","noTransition","clearTimeout","soft","done","unload","mime","readyState","targetTime","fauxDuration","realDuration","mozHasAudio","webkitAudioDecodedByteCount","audioTracks","change","states","webkitPresentationMode"],"mappings":"uLAIA,IC2IcA,ED3IDC,SACF,gBACE,gBACF,SAGEC,SACF,cACA,SERLC,YAEO,QAGF,UAGA,YAGG,aAGC,WAGD,UAGF,SACD,WAGG,sBAIO,cAGL,gBAGE,QAGP,oBAGM,gBAGC,mBAGG,sBAGG,cAGR,aACA,eACH,wDAGG,wDAIC,mBAEL,SACA,SACA,SACA,QACA,QACA,SACA,QACA,OACA,0BAMI,mBAOE,WAEN,GACA,IACA,EACA,KACA,IACA,KACA,uBAMK,UACD,uBAKE,QACJ,qBAKE,WACEC,OAAOC,UAAUC,SAASC,MAAM,KAAK,yBAKtC,YACC,aACC,qBAKF,MACJ,kBAKL,aACA,OACA,WACA,eACA,OACA,SACA,WACA,WACA,MACA,UACA,wBAGA,WACA,UACA,uBAKS,iBACD,8BACF,aACC,gBACE,+BACH,cACE,kBACE,uBACG,wBACH,kBACF,cACF,cACE,wBACQ,kCACC,mCACA,kCACD,6BACJ,8BACF,oBACA,iBACH,gBACE,eACH,aACC,YACF,UACA,YACE,aACD,gBACI,wBACI,uBAML,uDAGA,qDAGA,uEAMH,UACA,WACC,aACE,YACD,aACC,UACH,YACE,cACE,gBACE,SACP,aACI,WACF,aACE,UACH,cACI,sBAQV,WACA,UACA,UACA,UACA,UACA,iBACA,YACA,aACA,iBACA,aACA,eACA,OACA,QACA,QACA,UACA,SACA,UACA,aACA,8BAIA,iBACA,kBACA,mBACA,iBACA,iBACA,gBACA,sBAIA,gBACA,+BAIA,kBACA,kBACA,YACA,cACA,cACA,iBACA,gBACA,gCAMU,uDACC,4BAEI,aACF,0BAEL,4BAEE,2BACC,8BACE,+BACD,+BACC,kCACH,8BACI,oCACE,+BACP,4BACI,iCACC,8BACJ,mCAGA,4BACE,6BACD,+BACG,iCACD,8CAGI,gCACH,+BACF,iCACA,+BACF,+BACE,mCAEF,2BACA,gCAEG,oDAMN,4BACA,wBACF,oBACI,qBACH,qBACI,oBACD,wBACA,wBACA,sBACF,wBACA,sBACE,qBACH,oBACE,6BACM,4BACP,uBACE,6BACI,6BACC,kC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","file":"plyr.min.js","sourcesContent":["// ==========================================================================\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\nexport default { providers, types };\n","// ==========================================================================\n// Plyr support checks\n// ==========================================================================\n\nimport utils from './utils';\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, inline) {\n let api = false;\n let ui = false;\n const browser = utils.getBrowser();\n const playsInline = browser.isIPhone && inline && support.inline;\n\n switch (`${provider}:${type}`) {\n case 'html5:video':\n api = support.video;\n ui = api && support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'html5:audio':\n api = support.audio;\n ui = api && support.rangeInput;\n break;\n\n case 'youtube:video':\n api = true;\n ui = support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'vimeo:video':\n api = true;\n ui = support.rangeInput && !browser.isIPhone;\n break;\n\n default:\n api = support.audio && support.video;\n ui = api && support.rangeInput;\n }\n\n return {\n api,\n ui,\n };\n },\n\n // Picture-in-picture support\n // Safari only currently\n pip: (() => {\n const browser = utils.getBrowser();\n return !browser.isIPhone && utils.is.function(utils.createElement('video').webkitSetPresentationMode);\n })(),\n\n // Airplay support\n // Safari only currently\n airplay: utils.is.function(window.WebKitPlaybackTargetAvailabilityEvent),\n\n // Inline playback support\n // https://webkit.org/blog/6784/new-video-policies-for-ios/\n inline: '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(type) {\n const { media } = this;\n\n try {\n // Bail if no checking function\n if (!this.isHTML5 || !utils.is.function(media.canPlayType)) {\n return false;\n }\n\n // Type specific checks\n if (this.isVideo) {\n switch (type) {\n case 'video/webm':\n return media.canPlayType('video/webm; codecs=\"vp8, vorbis\"').replace(/no/, '');\n\n case 'video/mp4':\n return media.canPlayType('video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"').replace(/no/, '');\n\n case 'video/ogg':\n return media.canPlayType('video/ogg; codecs=\"theora\"').replace(/no/, '');\n\n default:\n return false;\n }\n } else if (this.isAudio) {\n switch (type) {\n case 'audio/mpeg':\n return media.canPlayType('audio/mpeg;').replace(/no/, '');\n\n case 'audio/ogg':\n return media.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/no/, '');\n\n case 'audio/wav':\n return media.canPlayType('audio/wav; codecs=\"1\"').replace(/no/, '');\n\n default:\n return false;\n }\n }\n } catch (e) {\n return false;\n }\n\n // If we got this far, we're stuffed\n return false;\n },\n\n // Check for textTracks support\n textTracks: 'textTracks' in document.createElement('video'),\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\n passiveListeners: (() => {\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 } catch (e) {\n // Do nothing\n }\n\n return supported;\n })(),\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 // Remember a device can be moust + touch enabled\n touch: 'ontouchstart' in document.documentElement,\n\n // Detect transitions support\n transitions: utils.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 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 // 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 // Revert to poster on finish (HTML5 - will cause reload)\n showPosterOnEnd: 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.0.0-beta.14/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: 'default',\n options: [\n 'hd2160',\n 'hd1440',\n 'hd1080',\n 'hd720',\n 'large',\n 'medium',\n 'small',\n 'tiny',\n 'default',\n ],\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: [\n 0.5,\n 0.75,\n 1,\n 1.25,\n 1.5,\n 1.75,\n 2,\n ],\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: window.navigator.language.split('-')[0],\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 'play',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'pip',\n 'airplay',\n 'fullscreen',\n ],\n settings: [\n 'captions',\n 'quality',\n 'speed',\n ],\n\n // Localisation\n i18n: {\n restart: 'Restart',\n rewind: 'Rewind {seektime} secs',\n play: 'Play',\n pause: 'Pause',\n forward: 'Forward {seektime} secs',\n seek: 'Seek',\n played: 'Played',\n buffered: 'Buffered',\n currentTime: 'Current time',\n duration: 'Duration',\n volume: 'Volume',\n mute: 'Mute',\n unmute: 'Unmute',\n enableCaptions: 'Enable captions',\n disableCaptions: 'Disable captions',\n enterFullscreen: 'Enter fullscreen',\n exitFullscreen: 'Exit fullscreen',\n frameTitle: 'Player for {title}',\n captions: 'Captions',\n settings: 'Settings',\n speed: 'Speed',\n quality: 'Quality',\n loop: 'Loop',\n start: 'Start',\n end: 'End',\n all: 'All',\n reset: 'Reset',\n none: 'None',\n disabled: 'Disabled',\n advertisment: 'Ad',\n },\n\n // URLs\n urls: {\n vimeo: {\n api: 'https://player.vimeo.com/api/player.js',\n },\n youtube: {\n api: 'https://www.youtube.com/iframe_api',\n },\n googleIMA: {\n api: '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 forward: null,\n mute: null,\n volume: null,\n captions: null,\n fullscreen: null,\n pip: null,\n airplay: null,\n speed: null,\n quality: null,\n loop: null,\n language: null,\n },\n\n // Events to watch and bubble\n events: [\n // Events to watch on HTML5 media elements and bubble\n // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events\n 'ended',\n 'progress',\n 'stalled',\n 'playing',\n 'waiting',\n 'canplay',\n 'canplaythrough',\n 'loadstart',\n 'loadeddata',\n 'loadedmetadata',\n 'timeupdate',\n 'volumechange',\n 'play',\n 'pause',\n 'error',\n 'seeking',\n 'seeked',\n 'emptied',\n 'ratechange',\n 'cuechange',\n\n // Custom events\n 'enterfullscreen',\n 'exitfullscreen',\n 'captionsenabled',\n 'captionsdisabled',\n 'languagechange',\n 'controlshidden',\n 'controlsshown',\n 'ready',\n\n // YouTube\n 'statechange',\n 'qualitychange',\n 'qualityrequested',\n\n // Ads\n 'adsloaded',\n 'adscontentpause',\n 'adsconentresume',\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 forward: '[data-plyr=\"fast-forward\"]',\n mute: '[data-plyr=\"mute\"]',\n captions: '[data-plyr=\"captions\"]',\n fullscreen: '[data-plyr=\"fullscreen\"]',\n pip: '[data-plyr=\"pip\"]',\n airplay: '[data-plyr=\"airplay\"]',\n settings: '[data-plyr=\"settings\"]',\n loop: '[data-plyr=\"loop\"]',\n },\n inputs: {\n seek: '[data-plyr=\"seek\"]',\n volume: '[data-plyr=\"volume\"]',\n speed: '[data-plyr=\"speed\"]',\n language: '[data-plyr=\"language\"]',\n quality: '[data-plyr=\"quality\"]',\n },\n display: {\n currentTime: '.plyr__time--current',\n duration: '.plyr__time--duration',\n buffer: '.plyr__progress--buffer',\n played: '.plyr__progress--played',\n loop: '.plyr__progress--loop',\n volume: '.plyr__volume--display',\n },\n progress: '.plyr__progress',\n captions: '.plyr__captions',\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 video: 'plyr__video-wrapper',\n embed: 'plyr__video-embed',\n ads: 'plyr__ads',\n control: 'plyr__control',\n type: 'plyr--{0}',\n provider: 'plyr--{0}',\n stopped: 'plyr--stopped',\n playing: 'plyr--playing',\n loading: 'plyr--loading',\n error: 'plyr--has-error',\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 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 // Tag is not required as publisher is determined by vi.ai using the domain\n ads: {\n enabled: false,\n },\n};\n\nexport default defaults;\n","// ==========================================================================\n// Plyr utils\n// ==========================================================================\n\nimport support from './support';\nimport { providers } from './types';\n\nconst utils = {\n // Check variable types\n is: {\n plyr(input) {\n return this.instanceof(input, window.Plyr);\n },\n object(input) {\n return this.getConstructor(input) === Object;\n },\n number(input) {\n return this.getConstructor(input) === Number && !Number.isNaN(input);\n },\n string(input) {\n return this.getConstructor(input) === String;\n },\n boolean(input) {\n return this.getConstructor(input) === Boolean;\n },\n function(input) {\n return this.getConstructor(input) === Function;\n },\n array(input) {\n return !this.nullOrUndefined(input) && Array.isArray(input);\n },\n weakMap(input) {\n return this.instanceof(input, window.WeakMap);\n },\n nodeList(input) {\n return this.instanceof(input, window.NodeList);\n },\n element(input) {\n return this.instanceof(input, window.Element);\n },\n textNode(input) {\n return this.getConstructor(input) === Text;\n },\n event(input) {\n return this.instanceof(input, window.Event);\n },\n cue(input) {\n return this.instanceof(input, window.TextTrackCue) || this.instanceof(input, window.VTTCue);\n },\n track(input) {\n return this.instanceof(input, TextTrack) || (!this.nullOrUndefined(input) && this.string(input.kind));\n },\n url(input) {\n return !this.nullOrUndefined(input) && /(ftp|http|https):\\/\\/(\\w+:{0,1}\\w*@)?(\\S+)(:[0-9]+)?(\\/|\\/([\\w#!:.?+=&%@!\\-/]))?/.test(input);\n },\n nullOrUndefined(input) {\n return input === null || typeof input === 'undefined';\n },\n empty(input) {\n return (\n this.nullOrUndefined(input) ||\n ((this.string(input) || this.array(input) || this.nodeList(input)) && !input.length) ||\n (this.object(input) && !Object.keys(input).length)\n );\n },\n instanceof(input, constructor) {\n return Boolean(input && constructor && input instanceof constructor);\n },\n getConstructor(input) {\n return !this.nullOrUndefined(input) ? input.constructor : null;\n },\n },\n\n // Unfortunately, due to mixed support, UA sniffing is required\n getBrowser() {\n return {\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 },\n\n // Fetch wrapper\n // Using XHR to avoid issues with older browsers\n fetch(url) {\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 try {\n resolve(JSON.parse(request.responseText));\n } catch(e) {\n resolve(request.responseText);\n }\n });\n\n request.addEventListener('error', () => {\n throw new Error(request.statusText);\n });\n\n request.open('GET', url, true);\n request.send();\n } catch (e) {\n reject(e);\n }\n });\n },\n\n // Load an external script\n loadScript(url, callback, error) {\n const current = document.querySelector(`script[src=\"${url}\"]`);\n\n // Check script is not already referenced, if so wait for load\n if (current !== null) {\n current.callbacks = current.callbacks || [];\n current.callbacks.push(callback);\n return;\n }\n\n // Build the element\n const element = document.createElement('script');\n\n // Callback queue\n element.callbacks = element.callbacks || [];\n element.callbacks.push(callback);\n\n // Error queue\n element.errors = element.errors || [];\n element.errors.push(error);\n\n // Bind callback\n if (utils.is.function(callback)) {\n element.addEventListener(\n 'load',\n event => {\n element.callbacks.forEach(cb => cb.call(null, event));\n element.callbacks = null;\n },\n false,\n );\n }\n\n // Bind error handling\n element.addEventListener(\n 'error',\n event => {\n element.errors.forEach(err => err.call(null, event));\n element.errors = null;\n },\n false,\n );\n\n // Set the URL after binding callback\n element.src = url;\n\n // Inject\n const first = document.getElementsByTagName('script')[0];\n first.parentNode.insertBefore(element, first);\n },\n\n // Load an external SVG sprite\n loadSprite(url, id) {\n if (!utils.is.string(url)) {\n return;\n }\n\n const prefix = 'cache-';\n const hasId = utils.is.string(id);\n let isCached = false;\n\n function updateSprite(data) {\n // Inject content\n this.innerHTML = data;\n\n // Inject the SVG to the body\n document.body.insertBefore(this, document.body.childNodes[0]);\n }\n\n // Only load once\n if (!hasId || !document.querySelectorAll(`#${id}`).length) {\n // Create container\n const container = document.createElement('div');\n utils.toggleHidden(container, true);\n\n if (hasId) {\n container.setAttribute('id', id);\n }\n\n // Check in cache\n if (support.storage) {\n const cached = window.localStorage.getItem(prefix + id);\n isCached = cached !== null;\n\n if (isCached) {\n const data = JSON.parse(cached);\n updateSprite.call(container, data.content);\n return;\n }\n }\n\n // Get the sprite\n utils\n .fetch(url)\n .then(result => {\n if (utils.is.empty(result)) {\n return;\n }\n\n if (support.storage) {\n window.localStorage.setItem(\n prefix + id,\n JSON.stringify({\n content: result,\n }),\n );\n }\n\n updateSprite.call(container, result);\n })\n .catch(() => {});\n }\n },\n\n // Generate a random ID\n generateId(prefix) {\n return `${prefix}-${Math.floor(Math.random() * 10000)}`;\n },\n\n // Determine if we're in an iframe\n inFrame() {\n try {\n return window.self !== window.top;\n } catch (e) {\n return true;\n }\n },\n\n // Wrap an element\n 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 // Create a DocumentFragment\n createElement(type, attributes, text) {\n // Create a new <element>\n const element = document.createElement(type);\n\n // Set all passed attributes\n if (utils.is.object(attributes)) {\n utils.setAttributes(element, attributes);\n }\n\n // Add text node\n if (utils.is.string(text)) {\n element.textContent = text;\n }\n\n // Return built element\n return element;\n },\n\n // Inaert an element after another\n insertAfter(element, target) {\n target.parentNode.insertBefore(element, target.nextSibling);\n },\n\n // Insert a DocumentFragment\n insertElement(type, parent, attributes, text) {\n // Inject the new <element>\n parent.appendChild(utils.createElement(type, attributes, text));\n },\n\n // Remove an element\n removeElement(element) {\n if (!utils.is.element(element) || !utils.is.element(element.parentNode)) {\n return;\n }\n\n if (utils.is.nodeList(element) || utils.is.array(element)) {\n Array.from(element).forEach(utils.removeElement);\n return;\n }\n\n element.parentNode.removeChild(element);\n },\n\n // Remove all child elements\n emptyElement(element) {\n let { length } = element.childNodes;\n\n while (length > 0) {\n element.removeChild(element.lastChild);\n length -= 1;\n }\n },\n\n // Replace element\n replaceElement(newChild, oldChild) {\n if (!utils.is.element(oldChild) || !utils.is.element(oldChild.parentNode) || !utils.is.element(newChild)) {\n return null;\n }\n\n oldChild.parentNode.replaceChild(newChild, oldChild);\n\n return newChild;\n },\n\n // Set attributes\n setAttributes(element, attributes) {\n if (!utils.is.element(element) || utils.is.empty(attributes)) {\n return;\n }\n\n Object.keys(attributes).forEach(key => {\n element.setAttribute(key, attributes[key]);\n });\n },\n\n // Get an attribute object from a string selector\n 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 (!utils.is.string(sel) || utils.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 (utils.is.object(existing) && utils.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 class on an element\n toggleClass(element, className, toggle) {\n if (utils.is.element(element)) {\n const contains = element.classList.contains(className);\n\n element.classList[toggle ? 'add' : 'remove'](className);\n\n return (toggle && !contains) || (!toggle && contains);\n }\n\n return null;\n },\n\n // Has class name\n hasClass(element, className) {\n return utils.is.element(element) && element.classList.contains(className);\n },\n\n // Toggle hidden attribute on an element\n toggleHidden(element, toggle) {\n if (!utils.is.element(element)) {\n return;\n }\n\n if (toggle) {\n element.setAttribute('hidden', '');\n } else {\n element.removeAttribute('hidden');\n }\n },\n\n // Element matches selector\n 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 = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;\n\n return matches.call(element, selector);\n },\n\n // Find all elements\n getElements(selector) {\n return this.elements.container.querySelectorAll(selector);\n },\n\n // Find a single element\n getElement(selector) {\n return this.elements.container.querySelector(selector);\n },\n\n // Find the UI controls and store references in custom controls\n // TODO: Allow settings menus with custom controls\n findElements() {\n try {\n this.elements.controls = utils.getElement.call(this, this.config.selectors.controls.wrapper);\n\n // Buttons\n this.elements.buttons = {\n play: utils.getElements.call(this, this.config.selectors.buttons.play),\n pause: utils.getElement.call(this, this.config.selectors.buttons.pause),\n restart: utils.getElement.call(this, this.config.selectors.buttons.restart),\n rewind: utils.getElement.call(this, this.config.selectors.buttons.rewind),\n forward: utils.getElement.call(this, this.config.selectors.buttons.forward),\n mute: utils.getElement.call(this, this.config.selectors.buttons.mute),\n pip: utils.getElement.call(this, this.config.selectors.buttons.pip),\n airplay: utils.getElement.call(this, this.config.selectors.buttons.airplay),\n settings: utils.getElement.call(this, this.config.selectors.buttons.settings),\n captions: utils.getElement.call(this, this.config.selectors.buttons.captions),\n fullscreen: utils.getElement.call(this, this.config.selectors.buttons.fullscreen),\n };\n\n // Progress\n this.elements.progress = utils.getElement.call(this, this.config.selectors.progress);\n\n // Inputs\n this.elements.inputs = {\n seek: utils.getElement.call(this, this.config.selectors.inputs.seek),\n volume: utils.getElement.call(this, this.config.selectors.inputs.volume),\n };\n\n // Display\n this.elements.display = {\n buffer: utils.getElement.call(this, this.config.selectors.display.buffer),\n duration: utils.getElement.call(this, this.config.selectors.display.duration),\n currentTime: utils.getElement.call(this, this.config.selectors.display.currentTime),\n };\n\n // Seek tooltip\n if (utils.is.element(this.elements.progress)) {\n this.elements.display.seekTooltip = this.elements.progress.querySelector(`.${this.config.classNames.tooltip}`);\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 // Get the focused element\n getFocusElement() {\n let focused = document.activeElement;\n\n if (!focused || focused === document.body) {\n focused = null;\n } else {\n focused = document.querySelector(':focus');\n }\n\n return focused;\n },\n\n // Trap focus inside container\n trapFocus(element = null, toggle = false) {\n if (!utils.is.element(element)) {\n return;\n }\n\n const focusable = utils.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 = utils.getFocusElement();\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 if (toggle) {\n utils.on(this.elements.container, 'keydown', trap, false);\n } else {\n utils.off(this.elements.container, 'keydown', trap, false);\n }\n },\n\n // Toggle event listener\n toggleListener(elements, event, callback, toggle, passive, capture) {\n // Bail if no elemetns, event, or callback\n if (utils.is.empty(elements) || utils.is.empty(event) || !utils.is.function(callback)) {\n return;\n }\n\n // If a nodelist is passed, call itself on each node\n if (utils.is.nodeList(elements) || utils.is.array(elements)) {\n // Create listener for each node\n Array.from(elements).forEach(element => {\n if (element instanceof Node) {\n utils.toggleListener.call(null, element, event, callback, toggle, passive, capture);\n }\n });\n\n return;\n }\n\n // Allow multiple events\n const events = event.split(' ');\n\n // Build options\n // Default to just capture boolean\n let options = utils.is.boolean(capture) ? capture : false;\n\n // If passive events listeners are supported\n if (support.passiveListeners) {\n options = {\n // Whether the listener can be passive (i.e. default never prevented)\n passive: utils.is.boolean(passive) ? passive : true,\n // Whether the listener is a capturing listener or not\n capture: utils.is.boolean(capture) ? capture : false,\n };\n }\n\n // If a single node is passed, bind the event listener\n events.forEach(type => {\n elements[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);\n });\n },\n\n // Bind event handler\n on(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, true, passive, capture);\n },\n\n // Unbind event handler\n off(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, false, passive, capture);\n },\n\n // Trigger event\n dispatchEvent(element, type, bubbles, detail) {\n // Bail if no element\n if (!utils.is.element(element) || !utils.is.string(type)) {\n return;\n }\n\n // Create and dispatch the event\n const event = new CustomEvent(type, {\n bubbles: utils.is.boolean(bubbles) ? bubbles : false,\n detail: Object.assign({}, detail, {\n plyr: utils.is.plyr(this) ? this : null,\n }),\n });\n\n // Dispatch the event\n element.dispatchEvent(event);\n },\n\n // Toggle aria-pressed state on a toggle button\n // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles\n toggleState(element, input) {\n // If multiple elements passed\n if (utils.is.array(element) || utils.is.nodeList(element)) {\n Array.from(element).forEach(target => utils.toggleState(target, input));\n return;\n }\n\n // Bail if no target\n if (!utils.is.element(element)) {\n return;\n }\n\n // Get state\n const pressed = element.getAttribute('aria-pressed') === 'true';\n const state = utils.is.boolean(input) ? input : !pressed;\n\n // Set the attribute on target\n element.setAttribute('aria-pressed', state);\n },\n\n // Get percentage\n getPercentage(current, max) {\n if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {\n return 0;\n }\n return (current / max * 100).toFixed(2);\n },\n\n // Time helpers\n getHours(value) {\n return parseInt((value / 60 / 60) % 60, 10);\n },\n getMinutes(value) {\n return parseInt((value / 60) % 60, 10);\n },\n getSeconds(value) {\n return parseInt(value % 60, 10);\n },\n\n // Format time to UI friendly string\n formatTime(time = 0, displayHours = false, inverted = false) {\n // Bail if the value isn't a number\n if (!utils.is.number(time)) {\n return this.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 = this.getHours(time);\n const mins = this.getMinutes(time);\n const secs = this.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 ? '-' : ''}${hours}${format(mins)}:${format(secs)}`;\n },\n\n // Deep extend destination object with N more objects\n extend(target = {}, ...sources) {\n if (!sources.length) {\n return target;\n }\n\n const source = sources.shift();\n\n if (!utils.is.object(source)) {\n return target;\n }\n\n Object.keys(source).forEach(key => {\n if (utils.is.object(source[key])) {\n if (!Object.keys(target).includes(key)) {\n Object.assign(target, { [key]: {} });\n }\n\n utils.extend(target[key], source[key]);\n } else {\n Object.assign(target, { [key]: source[key] });\n }\n });\n\n return utils.extend(target, ...sources);\n },\n\n // Get the provider for a given URL\n 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{8,}(?=\\b|\\/)/.test(url)) {\n return providers.vimeo;\n }\n\n return null;\n },\n\n // Parse YouTube ID from URL\n parseYouTubeId(url) {\n if (utils.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 // Parse Vimeo ID from URL\n parseVimeoId(url) {\n if (utils.is.empty(url)) {\n return null;\n }\n\n if (utils.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 // Convert a URL to a location object\n parseUrl(url) {\n const parser = document.createElement('a');\n parser.href = url;\n return parser;\n },\n\n // Get URL query parameters\n getUrlParams(input) {\n let search = input;\n\n // Parse URL if needed\n if (input.startsWith('http://') || input.startsWith('https://')) {\n ({ search } = this.parseUrl(input));\n }\n\n if (this.is.empty(search)) {\n return null;\n }\n\n const hashes = search.slice(search.indexOf('?') + 1).split('&');\n\n return hashes.reduce((params, hash) => {\n const [\n key,\n val,\n ] = hash.split('=');\n\n return Object.assign(params, { [key]: decodeURIComponent(val) });\n }, {});\n },\n\n // Convert object to URL parameters\n buildUrlParams(input) {\n if (!utils.is.object(input)) {\n return '';\n }\n\n return Object.keys(input)\n .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(input[key])}`)\n .join('&');\n },\n\n // Remove HTML from a string\n 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 // Get aspect ratio for dimensions\n 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 // Get the transition end event\n get 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 utils.is.string(type) ? events[type] : false;\n },\n\n // Force repaint of element\n repaint(element) {\n window.setTimeout(() => {\n utils.toggleHidden(element, true);\n element.offsetHeight; // eslint-disable-line\n utils.toggleHidden(element, false);\n }, 0);\n },\n};\n\nexport default utils;\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 get warn() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.warn, console) : noop;\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// ==========================================================================\n\nimport utils from './utils';\n\nconst browser = utils.getBrowser();\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 (utils.is.element(button)) {\n utils.toggleState(button, this.active);\n }\n\n // Trigger an event\n utils.dispatchEvent(this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);\n\n // Trap focus in container\n if (!browser.isIos) {\n utils.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 utils.toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle);\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\n // Scroll position\n this.scrollPosition = { x: 0, y: 0 };\n\n // Register event listeners\n // Handle event (incase user presses escape etc)\n utils.on(document, this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`, () => {\n // TODO: Filter for target??\n onChange.call(this);\n });\n\n // Fullscreen toggle on double click\n utils.on(this.player.elements.container, 'dblclick', () => {\n this.toggle();\n });\n\n // Prevent double click on controls bubbling up\n utils.on(this.player.elements.controls, 'dblclick', event => event.stopPropagation());\n\n // Update the UI\n this.update();\n }\n\n // Determine if native supported\n static get native() {\n return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled);\n }\n\n // Get the prefix for handlers\n static get prefix() {\n // No prefix\n if (utils.is.function(document.cancelFullScreen)) {\n return false;\n }\n\n // Check for fullscreen support by vendor prefix\n let value = '';\n const prefixes = [\n 'webkit',\n 'moz',\n 'ms',\n ];\n\n prefixes.some(pre => {\n if (utils.is.function(document[`${pre}CancelFullScreen`])) {\n value = pre;\n return true;\n } else if (utils.is.function(document.msExitFullscreen)) {\n value = 'ms';\n return true;\n }\n\n return false;\n });\n\n return value;\n }\n\n // Determine if fullscreen is enabled\n get enabled() {\n const fallback = this.player.config.fullscreen.fallback && !utils.inFrame();\n\n return (Fullscreen.native || fallback) && this.player.config.fullscreen.enabled && this.player.supported.ui && this.player.isVideo;\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 utils.hasClass(this.target, this.player.config.classNames.fullscreen.fallback);\n }\n\n const element = !this.prefix ? document.fullscreenElement : document[`${this.prefix}FullscreenElement`];\n\n return element === this.target;\n }\n\n // Get target element\n get target() {\n return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : 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 utils.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 if (this.player.playing) {\n this.target.webkitEnterFullscreen();\n }\n } else if (!Fullscreen.native) {\n toggleFallback.call(this, true);\n } else if (!this.prefix) {\n this.target.requestFullScreen();\n } else if (!utils.is.empty(this.prefix)) {\n this.target[`${this.prefix}${this.prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen'}`]();\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();\n } else if (!utils.is.empty(this.prefix)) {\n document[`${this.prefix}${this.prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen'}`]();\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// Plyr storage\n// ==========================================================================\n\nimport utils from './utils';\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 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 try {\n window.localStorage.setItem(test, test);\n window.localStorage.removeItem(test);\n return true;\n } catch (e) {\n return false;\n }\n }\n\n get(key) {\n const store = window.localStorage.getItem(this.key);\n\n if (!Storage.supported || utils.is.empty(store)) {\n return null;\n }\n\n const json = JSON.parse(store);\n\n return utils.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 (!utils.is.object(object)) {\n return;\n }\n\n // Get current storage\n let storage = this.get();\n\n // Default to empty object\n if (utils.is.empty(storage)) {\n storage = {};\n }\n\n // Update the working copy of the values\n utils.extend(storage, object);\n\n // Update storage\n window.localStorage.setItem(this.key, JSON.stringify(storage));\n }\n}\n\nexport default Storage;\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 utils from '../utils';\n\n// Build the default tag URL\nconst getTagUrl = () => {\n const params = {\n AV_PUBLISHERID: '58c25bb0073ef448b1087ad6',\n AV_CHANNELID: '5a0458dc28a06145e4519d21',\n AV_URL: '127.0.0.1:3000',\n cb: 1,\n AV_WIDTH: 640,\n AV_HEIGHT: 480,\n };\n\n const base = 'https://go.aniview.com/api/adserver6/vast/';\n\n return `${base}?${utils.buildUrlParams(params)}`;\n};\n\nclass Ads {\n /**\n * Ads constructor.\n * @param {object} player\n * @return {Ads}\n */\n constructor(player) {\n this.player = player;\n this.enabled = player.config.ads.enabled;\n this.playing = false;\n this.initialized = false;\n this.blocked = false;\n this.enabled = utils.is.url(player.config.ads.tag);\n\n // Check if a tag URL is provided.\n if (!this.enabled) {\n return;\n }\n\n // Check if the Google IMA3 SDK is loaded or load it ourselves\n if (!utils.is.object(window.google)) {\n utils.loadScript(\n player.config.urls.googleIMA.api,\n () => {\n this.ready();\n },\n () => {\n // Script failed to load or is blocked\n this.blocked = true;\n this.player.debug.log('Ads error: Google IMA SDK failed to load');\n },\n );\n } else {\n this.ready();\n }\n }\n\n /**\n * Get the ads instance ready.\n */\n ready() {\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 // Set listeners on the Plyr instance\n this.listeners();\n\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 // Setup a simple promise to resolve if the IMA loader is ready\n this.loaderPromise = new Promise(resolve => {\n this.on('ADS_LOADER_LOADED', () => resolve());\n });\n\n // Setup a promise to resolve if the IMA manager is ready\n this.managerPromise = new Promise(resolve => {\n this.on('ADS_MANAGER_LOADED', () => resolve());\n });\n\n // Clear the safety timer\n this.managerPromise.then(() => {\n this.clearSafetyTimer('onAdsManagerLoaded()');\n });\n\n // Setup the IMA SDK\n this.setupIMA();\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 = utils.createElement('div', {\n class: this.player.config.classNames.ads,\n hidden: '',\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(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, event => this.onAdsManagerLoaded(event), false);\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 = getTagUrl();\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 this.loader.requestAds(request);\n\n this.handleEventListeners('ADS_LOADER_LOADED');\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 window.clearInterval(this.countdownTimer);\n this.elements.container.removeAttribute('data-badge-text');\n return;\n }\n\n const update = () => {\n const time = utils.formatTime(this.manager.getRemainingTime());\n const label = `${this.player.config.i18n.advertisment} - ${time}`;\n this.elements.container.setAttribute('data-badge-text', label);\n };\n\n this.countdownTimer = window.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(adsManagerLoadedEvent) {\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 = adsManagerLoadedEvent.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 this.cuePoints.forEach(cuePoint => {\n if (cuePoint !== 0 && cuePoint !== -1) {\n const seekElement = this.player.elements.progress;\n\n if (seekElement) {\n const cuePercentage = 100 / this.player.duration * cuePoint;\n const cue = utils.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 // Get skippable state\n // TODO: Skip button\n // this.manager.getAdSkippableState();\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.handleEventListeners('ADS_MANAGER_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 utils.dispatchEvent.call(this.player, this.player.media, `ads${type}`);\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.handleEventListeners('LOADED');\n\n // Bubble event\n dispatchEvent('loaded');\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 this.handleEventListeners('ALL_ADS_COMPLETED');\n\n // Fire event\n dispatchEvent('allcomplete');\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 this.handleEventListeners('CONTENT_PAUSE_REQUESTED');\n\n dispatchEvent('contentpause');\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 this.handleEventListeners('CONTENT_RESUME_REQUESTED');\n\n dispatchEvent('contentresume');\n\n this.pollCountdown();\n\n this.resumeContent();\n\n break;\n\n case google.ima.AdEvent.Type.STARTED:\n dispatchEvent('started');\n break;\n\n case google.ima.AdEvent.Type.MIDPOINT:\n dispatchEvent('midpoint');\n break;\n\n case google.ima.AdEvent.Type.COMPLETE:\n dispatchEvent('complete');\n break;\n\n case google.ima.AdEvent.Type.IMPRESSION:\n dispatchEvent('impression');\n break;\n\n case google.ima.AdEvent.Type.CLICK:\n dispatchEvent('click');\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.log('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 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 this.manager.resize(container.offsetWidth, container.offsetHeight, google.ima.ViewMode.NORMAL);\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 return;\n }\n\n // Play the requested advertisement whenever the adsManager is ready\n this.managerPromise.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 }\n\n /**\n * Resume our video.\n */\n resumeContent() {\n // Hide our ad container\n utils.toggleHidden(this.elements.container, true);\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 our ad container.\n utils.toggleHidden(this.elements.container, false);\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.handleEventListeners('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.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('ADS_MANAGER_LOADED', () => resolve());\n this.player.debug.log(this.manager);\n });\n\n // Now request some new advertisements\n this.requestAds();\n });\n }\n\n /**\n * Handles callbacks after an ad event was invoked\n * @param {string} event - Event type\n */\n handleEventListeners(event) {\n if (utils.is.function(this.events[event])) {\n this.events[event].call(this);\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 this.events[event] = callback;\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 = window.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 (!utils.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 Event Listeners\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst listeners = {\n // Global listeners\n global() {\n let last = null;\n\n // Get the key code for an event\n const getKeyCode = event => (event.keyCode ? event.keyCode : event.which);\n\n // Handle key press\n const handleKey = event => {\n const code = getKeyCode(event);\n const pressed = event.type === 'keydown';\n const repeat = pressed && code === last;\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 (!utils.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 this.currentTime = this.duration / 10 * (code - 48);\n };\n\n // Handle the key on keydown\n // Reset on keyup\n if (pressed) {\n // Which keycodes should we prevent default\n const preventDefault = [\n 48,\n 49,\n 50,\n 51,\n 52,\n 53,\n 54,\n 56,\n 57,\n 32,\n 75,\n 38,\n 40,\n 77,\n 39,\n 37,\n 70,\n 67,\n 73,\n 76,\n 79,\n ];\n\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 = utils.getFocusElement();\n if (utils.is.element(focused) && utils.matches(focused, this.config.selectors.editable)) {\n return;\n }\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 this.togglePlay();\n }\n break;\n\n case 38:\n // Arrow up\n this.increaseVolume(0.1);\n break;\n\n case 40:\n // Arrow down\n this.decreaseVolume(0.1);\n break;\n\n case 77:\n // M key\n if (!repeat) {\n this.muted = !this.muted;\n }\n break;\n\n case 39:\n // Arrow forward\n this.forward();\n break;\n\n case 37:\n // Arrow back\n this.rewind();\n break;\n\n case 70:\n // F key\n this.fullscreen.toggle();\n break;\n\n case 67:\n // C key\n if (!repeat) {\n this.toggleCaptions();\n }\n break;\n\n case 76:\n // L key\n this.loop = !this.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 (!this.fullscreen.enabled && this.fullscreen.active && code === 27) {\n this.fullscreen.toggle();\n }\n\n // Store last code for next cycle\n last = code;\n } else {\n last = null;\n }\n };\n\n // Keyboard shortcuts\n if (this.config.keyboard.global) {\n utils.on(window, 'keydown keyup', handleKey, false);\n } else if (this.config.keyboard.focused) {\n utils.on(this.elements.container, 'keydown keyup', handleKey, false);\n }\n\n // Detect tab focus\n // Remove class on blur/focusout\n utils.on(this.elements.container, 'focusout', event => {\n utils.toggleClass(event.target, this.config.classNames.tabFocus, false);\n });\n\n // Add classname to tabbed elements\n utils.on(this.elements.container, 'keydown', event => {\n if (event.keyCode !== 9) {\n return;\n }\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n window.setTimeout(() => {\n utils.toggleClass(utils.getFocusElement(), this.config.classNames.tabFocus, true);\n }, 0);\n });\n\n // Toggle controls visibility based on mouse movement\n if (this.config.hideControls) {\n // Toggle controls on mouse events and entering fullscreen\n utils.on(this.elements.container, 'mouseenter mouseleave mousemove touchstart touchend touchmove enterfullscreen exitfullscreen', event => {\n this.toggleControls(event);\n });\n }\n },\n\n // Listen for media events\n media() {\n // Time change on media\n utils.on(this.media, 'timeupdate seeking', event => ui.timeUpdate.call(this, event));\n\n // Display duration\n utils.on(this.media, 'durationchange loadedmetadata', event => ui.durationUpdate.call(this, event));\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 utils.on(this.media, 'loadeddata', () => {\n utils.toggleHidden(this.elements.volume, !this.hasAudio);\n utils.toggleHidden(this.elements.buttons.mute, !this.hasAudio);\n });\n\n // Handle the media finishing\n utils.on(this.media, 'ended', () => {\n // Show poster on end\n if (this.isHTML5 && this.isVideo && this.config.showPosterOnEnd) {\n // Restart\n this.restart();\n\n // Re-load media\n this.media.load();\n }\n });\n\n // Check for buffer progress\n utils.on(this.media, 'progress playing', event => ui.updateProgress.call(this, event));\n\n // Handle native mute\n utils.on(this.media, 'volumechange', event => ui.updateVolume.call(this, event));\n\n // Handle native play/pause\n utils.on(this.media, 'playing play pause ended', event => ui.checkPlaying.call(this, event));\n\n // Loading\n utils.on(this.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(this, event));\n\n // Check if media failed to load\n // utils.on(this.media, 'play', event => ui.checkFailed.call(this, event));\n\n // Click video\n if (this.supported.ui && this.config.clickToPlay && !this.isAudio) {\n // Re-fetch the wrapper\n const wrapper = utils.getElement.call(this, `.${this.config.classNames.video}`);\n\n // Bail if there's no wrapper (this should never happen)\n if (!utils.is.element(wrapper)) {\n return;\n }\n\n // On click play, pause ore restart\n utils.on(wrapper, 'click', () => {\n // Touch devices will just show controls (if we're hiding controls)\n if (this.config.hideControls && support.touch && !this.paused) {\n return;\n }\n\n if (this.paused) {\n this.play();\n } else if (this.ended) {\n this.restart();\n this.play();\n } else {\n this.pause();\n }\n });\n }\n\n // Disable right click\n if (this.supported.ui && this.config.disableContextMenu) {\n utils.on(\n this.media,\n 'contextmenu',\n event => {\n event.preventDefault();\n },\n false,\n );\n }\n\n // Volume change\n utils.on(this.media, 'volumechange', () => {\n // Save to storage\n this.storage.set({ volume: this.volume, muted: this.muted });\n });\n\n // Speed change\n utils.on(this.media, 'ratechange', () => {\n // Update UI\n controls.updateSetting.call(this, 'speed');\n\n // Save to storage\n this.storage.set({ speed: this.speed });\n });\n\n // Quality change\n utils.on(this.media, 'qualitychange', () => {\n // Update UI\n controls.updateSetting.call(this, 'quality');\n\n // Save to storage\n this.storage.set({ quality: this.quality });\n });\n\n // Caption language change\n utils.on(this.media, 'languagechange', () => {\n // Update UI\n controls.updateSetting.call(this, 'captions');\n\n // Save to storage\n this.storage.set({ language: this.language });\n });\n\n // Captions toggle\n utils.on(this.media, 'captionsenabled captionsdisabled', () => {\n // Update UI\n controls.updateSetting.call(this, 'captions');\n\n // Save to storage\n this.storage.set({ captions: this.captions.active });\n });\n\n // Proxy events to container\n // Bubble up key events for Edge\n utils.on(this.media, this.config.events.concat([\n 'keyup',\n 'keydown',\n ]).join(' '), event => {\n let detail = {};\n\n // Get error details from media\n if (event.type === 'error') {\n detail = this.media.error;\n }\n\n utils.dispatchEvent.call(this, this.elements.container, event.type, true, detail);\n });\n },\n\n // Listen for control events\n controls() {\n // IE doesn't support input event, so we fallback to change\n const inputEvent = browser.isIE ? 'change' : 'input';\n\n // Trigger custom and default handlers\n const proxy = (event, handlerKey, defaultHandler) => {\n const customHandler = this.config.listeners[handlerKey];\n\n // Execute custom handler\n if (utils.is.function(customHandler)) {\n customHandler.call(this, event);\n }\n\n // Only call default handler if not prevented in custom handler\n if (!event.defaultPrevented && utils.is.function(defaultHandler)) {\n defaultHandler.call(this, event);\n }\n };\n\n // Play/pause toggle\n utils.on(this.elements.buttons.play, 'click', event =>\n proxy(event, 'play', () => {\n this.togglePlay();\n }),\n );\n\n // Pause\n utils.on(this.elements.buttons.restart, 'click', event =>\n proxy(event, 'restart', () => {\n this.restart();\n }),\n );\n\n // Rewind\n utils.on(this.elements.buttons.rewind, 'click', event =>\n proxy(event, 'rewind', () => {\n this.rewind();\n }),\n );\n\n // Rewind\n utils.on(this.elements.buttons.forward, 'click', event =>\n proxy(event, 'forward', () => {\n this.forward();\n }),\n );\n\n // Mute toggle\n utils.on(this.elements.buttons.mute, 'click', event =>\n proxy(event, 'mute', () => {\n this.muted = !this.muted;\n }),\n );\n\n // Captions toggle\n utils.on(this.elements.buttons.captions, 'click', event =>\n proxy(event, 'captions', () => {\n this.toggleCaptions();\n }),\n );\n\n // Fullscreen toggle\n utils.on(this.elements.buttons.fullscreen, 'click', event =>\n proxy(event, 'fullscreen', () => {\n this.fullscreen.toggle();\n }),\n );\n\n // Picture-in-Picture\n utils.on(this.elements.buttons.pip, 'click', event =>\n proxy(event, 'pip', () => {\n this.pip = 'toggle';\n }),\n );\n\n // Airplay\n utils.on(this.elements.buttons.airplay, 'click', event =>\n proxy(event, 'airplay', () => {\n this.airplay();\n }),\n );\n\n // Settings menu\n utils.on(this.elements.buttons.settings, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Click anywhere closes menu\n utils.on(document.documentElement, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Settings menu\n utils.on(this.elements.settings.form, 'click', event => {\n event.stopPropagation();\n\n // Settings menu items - use event delegation as items are added/removed\n if (utils.matches(event.target, this.config.selectors.inputs.language)) {\n proxy(event, 'language', () => {\n this.language = event.target.value;\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.quality)) {\n proxy(event, 'quality', () => {\n this.quality = event.target.value;\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.speed)) {\n proxy(event, 'speed', () => {\n this.speed = parseFloat(event.target.value);\n });\n } else {\n controls.showTab.call(this, event);\n }\n });\n\n // Seek\n utils.on(this.elements.inputs.seek, inputEvent, event =>\n proxy(event, 'seek', () => {\n this.currentTime = event.target.value / event.target.max * this.duration;\n }),\n );\n\n // Current time invert\n // Only if one time element is used for both currentTime and duration\n if (this.config.toggleInvert && !utils.is.element(this.elements.display.duration)) {\n utils.on(this.elements.display.currentTime, 'click', () => {\n // Do nothing if we're at the start\n if (this.currentTime === 0) {\n return;\n }\n\n this.config.invertTime = !this.config.invertTime;\n ui.timeUpdate.call(this);\n });\n }\n\n // Volume\n utils.on(this.elements.inputs.volume, inputEvent, event =>\n proxy(event, 'volume', () => {\n this.volume = event.target.value;\n }),\n );\n\n // Polyfill for lower fill in <input type=\"range\"> for webkit\n if (browser.isWebkit) {\n utils.on(utils.getElements.call(this, 'input[type=\"range\"]'), 'input', event => {\n controls.updateRangeFill.call(this, event.target);\n });\n }\n\n // Seek tooltip\n utils.on(this.elements.progress, 'mouseenter mouseleave mousemove', event => controls.updateSeekTooltip.call(this, event));\n\n // Toggle controls visibility based on mouse movement\n if (this.config.hideControls) {\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mouseenter mouseleave', event => {\n this.elements.controls.hover = event.type === 'mouseenter';\n });\n\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {\n this.elements.controls.pressed = [\n 'mousedown',\n 'touchstart',\n ].includes(event.type);\n });\n\n // Focus in/out on controls\n utils.on(this.elements.controls, 'focusin focusout', event => {\n this.toggleControls(event);\n });\n }\n\n // Mouse wheel for volume\n utils.on(\n this.elements.inputs.volume,\n 'wheel',\n event =>\n proxy(event, 'volume', () => {\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 const step = 1 / 50;\n let direction = 0;\n\n // Scroll down (or up on natural) to decrease\n if (event.deltaY < 0 || event.deltaX > 0) {\n if (inverted) {\n this.decreaseVolume(step);\n direction = -1;\n } else {\n this.increaseVolume(step);\n direction = 1;\n }\n }\n\n // Scroll up (or down on natural) to increase\n if (event.deltaY > 0 || event.deltaX < 0) {\n if (inverted) {\n this.increaseVolume(step);\n direction = 1;\n } else {\n this.decreaseVolume(step);\n direction = -1;\n }\n }\n\n // Don't break page scrolling at max and min\n if ((direction === 1 && this.media.volume < 1) || (direction === -1 && this.media.volume > 0)) {\n event.preventDefault();\n }\n }),\n false,\n );\n },\n};\n\nexport default listeners;\n","// ==========================================================================\n// Plyr UI\n// ==========================================================================\n\nimport utils from './utils';\nimport captions from './captions';\nimport controls from './controls';\nimport listeners from './listeners';\n\nconst ui = {\n addStyleHook() {\n utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);\n utils.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 listeners.media.call(this);\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 (!utils.is.element(this.elements.controls)) {\n // Inject custom controls\n controls.inject.call(this);\n\n // Re-attach control listeners\n listeners.controls.call(this);\n }\n\n // If there's no controls, bail\n if (!utils.is.element(this.elements.controls)) {\n return;\n }\n\n // Remove native controls\n ui.toggleNativeControls.call(this);\n\n // Captions\n captions.setup.call(this);\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 options\n this.options.quality = [];\n\n // Reset time display\n ui.timeUpdate.call(this);\n\n // Update the UI\n ui.checkPlaying.call(this);\n\n // Ready for API calls\n this.ready = true;\n\n // Ready event at end of execution stack\n utils.dispatchEvent.call(this, this.media, 'ready');\n\n // Set the title\n ui.setTitle.call(this);\n },\n\n // Setup aria attribute for play and iframe title\n setTitle() {\n // Find the current text\n let label = this.config.i18n.play;\n\n // If there's a media title set, use that for the label\n if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) {\n label += `, ${this.config.title}`;\n\n // Set container label\n this.elements.container.setAttribute('aria-label', this.config.title);\n }\n\n // If there's a play button, set label\n if (utils.is.nodeList(this.elements.buttons.play)) {\n Array.from(this.elements.buttons.play).forEach(button => {\n button.setAttribute('aria-label', label);\n });\n }\n\n // Set iframe title\n // https://github.com/sampotts/plyr/issues/124\n if (this.isEmbed) {\n const iframe = utils.getElement.call(this, 'iframe');\n\n if (!utils.is.element(iframe)) {\n return;\n }\n\n // Default to media type\n const title = !utils.is.empty(this.config.title) ? this.config.title : 'video';\n\n iframe.setAttribute('title', this.config.i18n.frameTitle.replace('{title}', title));\n }\n },\n\n // Check playing state\n checkPlaying() {\n // Class hooks\n utils.toggleClass(this.elements.container, this.config.classNames.playing, this.playing);\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.paused);\n\n // Set ARIA state\n utils.toggleState(this.elements.buttons.play, this.playing);\n\n // Toggle controls\n this.toggleControls(!this.playing);\n },\n\n // Check if media is loading\n checkLoading(event) {\n this.loading = [\n 'stalled',\n 'waiting',\n ].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 // Toggle container class hook\n utils.toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Show controls if loading, hide if done\n this.toggleControls(this.loading);\n }, this.loading ? 250 : 0);\n },\n\n // Check if media failed to load\n checkFailed() {\n // https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/networkState\n this.failed = this.media.networkState === 3;\n\n if (this.failed) {\n utils.toggleClass(this.elements.container, this.config.classNames.loading, false);\n utils.toggleClass(this.elements.container, this.config.classNames.error, true);\n }\n\n // Clear timer\n clearTimeout(this.timers.failed);\n\n // Timer to prevent flicker when seeking\n this.timers.loading = setTimeout(() => {\n // Toggle container class hook\n utils.toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Show controls if loading, hide if done\n this.toggleControls(this.loading);\n }, this.loading ? 250 : 0);\n },\n\n // Update volume UI and storage\n updateVolume() {\n if (!this.supported.ui) {\n return;\n }\n\n // Update range\n if (utils.is.element(this.elements.inputs.volume)) {\n ui.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume);\n }\n\n // Update mute state\n if (utils.is.element(this.elements.buttons.mute)) {\n utils.toggleState(this.elements.buttons.mute, this.muted || this.volume === 0);\n }\n },\n\n // Update seek value and lower fill\n setRange(target, value = 0) {\n if (!utils.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 // Set <progress> value\n setProgress(target, input) {\n const value = utils.is.number(input) ? input : 0;\n const progress = utils.is.element(target) ? target : this.elements.display.buffer;\n\n // Update value and label\n if (utils.is.element(progress)) {\n progress.value = value;\n\n // Update text label inside\n const label = progress.getElementsByTagName('span')[0];\n if (utils.is.element(label)) {\n label.childNodes[0].nodeValue = value;\n }\n }\n },\n\n // Update <progress> elements\n updateProgress(event) {\n if (!this.supported.ui || !utils.is.event(event)) {\n return;\n }\n\n let value = 0;\n\n if (event) {\n switch (event.type) {\n // Video playing\n case 'timeupdate':\n case 'seeking':\n value = utils.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 ui.setRange.call(this, this.elements.inputs.seek, value);\n }\n\n break;\n\n // Check buffer status\n case 'playing':\n case 'progress':\n value = (() => {\n const { buffered } = this.media;\n\n if (buffered && buffered.length) {\n // HTML5\n return utils.getPercentage(buffered.end(0), this.duration);\n } else if (utils.is.number(buffered)) {\n // YouTube returns between 0 and 1\n return buffered * 100;\n }\n\n return 0;\n })();\n\n ui.setProgress.call(this, this.elements.display.buffer, value);\n\n break;\n\n default:\n break;\n }\n }\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 (!utils.is.element(target) || !utils.is.number(time)) {\n return;\n }\n\n // Always display hours if duration is over an hour\n const displayHours = utils.getHours(this.duration) > 0;\n\n // eslint-disable-next-line no-param-reassign\n target.textContent = utils.formatTime(time, displayHours, inverted);\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 = !utils.is.element(this.elements.display.duration) && this.config.invertTime;\n\n // Duration\n ui.updateTimeDisplay.call(this, this.elements.display.currentTime, invert ? this.duration - this.currentTime : this.currentTime, invert);\n\n // Ignore updates while seeking\n if (event && event.type === 'timeupdate' && this.media.seeking) {\n return;\n }\n\n // Playing progress\n ui.updateProgress.call(this, event);\n },\n\n // Show the duration on metadataloaded\n durationUpdate() {\n if (!this.supported.ui) {\n return;\n }\n\n // If there's a spot to display duration\n const hasDuration = utils.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 ui.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration);\n }\n\n // If there's a duration element, update content\n if (hasDuration) {\n ui.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\nexport default ui;\n","// ==========================================================================\n// Plyr controls\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport ui from './ui';\nimport captions from './captions';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst controls = {\n // Webkit polyfill for lower fill range\n updateRangeFill(target) {\n // WebKit only\n if (!browser.isWebkit) {\n return;\n }\n\n // Get range from event if event passed\n const range = utils.is.event(target) ? target.target : target;\n\n // Needs to be a valid <input type='range'>\n if (!utils.is.element(range) || range.getAttribute('type') !== 'range') {\n return;\n }\n\n // Set CSS custom property\n range.style.setProperty('--value', `${range.value / range.max * 100}%`);\n },\n\n // Get icon URL\n getIconUrl() {\n return {\n url: this.config.iconUrl,\n absolute: this.config.iconUrl.indexOf('http') === 0 || (browser.isIE && !window.svg4everybody),\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.absolute ? iconUrl.url : ''}#${this.config.iconPrefix}`;\n\n // Create <svg>\n const icon = document.createElementNS(namespace, 'svg');\n utils.setAttributes(\n icon,\n utils.extend(attributes, {\n role: 'presentation',\n })\n );\n\n // Create the <use> to reference sprite\n const use = document.createElementNS(namespace, 'use');\n const path = `${iconPath}-${type}`;\n\n // Set `href` attributes\n // https://github.com/sampotts/plyr/issues/460\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href\n if ('href' in use) {\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);\n } else {\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path);\n }\n\n // Add <use> to <svg>\n icon.appendChild(use);\n\n return icon;\n },\n\n // Create hidden text label\n createLabel(type, attr) {\n let text = this.config.i18n[type];\n const attributes = Object.assign({}, attr);\n\n switch (type) {\n case 'pip':\n text = 'PIP';\n break;\n\n case 'airplay':\n text = 'AirPlay';\n break;\n\n default:\n break;\n }\n\n if ('class' in attributes) {\n attributes.class += ` ${this.config.classNames.hidden}`;\n } else {\n attributes.class = this.config.classNames.hidden;\n }\n\n return utils.createElement('span', attributes, text);\n },\n\n // Create a badge\n createBadge(text) {\n if (utils.is.empty(text)) {\n return null;\n }\n\n const badge = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n badge.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.menu.badge,\n },\n text\n )\n );\n\n return badge;\n },\n\n // Create a <button>\n createButton(buttonType, attr) {\n const button = utils.createElement('button');\n const attributes = Object.assign({}, attr);\n let type = buttonType;\n\n let toggle = false;\n let label;\n let icon;\n let labelPressed;\n let iconPressed;\n\n if (!('type' in attributes)) {\n attributes.type = 'button';\n }\n\n if ('class' in attributes) {\n if (attributes.class.includes(this.config.classNames.control)) {\n attributes.class += ` ${this.config.classNames.control}`;\n }\n } else {\n attributes.class = this.config.classNames.control;\n }\n\n // Large play button\n switch (type) {\n case 'play':\n toggle = true;\n label = 'play';\n labelPressed = 'pause';\n icon = 'play';\n iconPressed = 'pause';\n break;\n\n case 'mute':\n toggle = true;\n label = 'mute';\n labelPressed = 'unmute';\n icon = 'volume';\n iconPressed = 'muted';\n break;\n\n case 'captions':\n toggle = true;\n label = 'enableCaptions';\n labelPressed = 'disableCaptions';\n icon = 'captions-off';\n iconPressed = 'captions-on';\n break;\n\n case 'fullscreen':\n toggle = true;\n label = 'enterFullscreen';\n labelPressed = 'exitFullscreen';\n icon = 'enter-fullscreen';\n iconPressed = 'exit-fullscreen';\n break;\n\n case 'play-large':\n attributes.class += ` ${this.config.classNames.control}--overlaid`;\n type = 'play';\n label = 'play';\n icon = 'play';\n break;\n\n default:\n label = type;\n icon = type;\n }\n\n // Setup toggle icon and labels\n if (toggle) {\n // Icon\n button.appendChild(controls.createIcon.call(this, iconPressed, { class: 'icon--pressed' }));\n button.appendChild(controls.createIcon.call(this, icon, { class: 'icon--not-pressed' }));\n\n // Label/Tooltip\n button.appendChild(controls.createLabel.call(this, labelPressed, { class: 'label--pressed' }));\n button.appendChild(controls.createLabel.call(this, label, { class: 'label--not-pressed' }));\n\n // Add aria attributes\n attributes['aria-pressed'] = false;\n attributes['aria-label'] = this.config.i18n[label];\n } else {\n button.appendChild(controls.createIcon.call(this, icon));\n button.appendChild(controls.createLabel.call(this, label));\n }\n\n // Merge attributes\n utils.extend(attributes, utils.getAttributesFromSelector(this.config.selectors.buttons[type], attributes));\n\n utils.setAttributes(button, attributes);\n\n // We have multiple play buttons\n if (type === 'play') {\n if (!utils.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 label\n const label = utils.createElement(\n 'label',\n {\n for: attributes.id,\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n );\n\n // Seek input\n const input = utils.createElement(\n 'input',\n utils.extend(\n utils.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 },\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 {\n label,\n input,\n };\n },\n\n // Create a <progress>\n createProgress(type, attributes) {\n const progress = utils.createElement(\n 'progress',\n utils.extend(\n utils.getAttributesFromSelector(this.config.selectors.display[type]),\n {\n min: 0,\n max: 100,\n value: 0,\n },\n attributes\n )\n );\n\n // Create the label inside\n if (type !== 'volume') {\n progress.appendChild(utils.createElement('span', null, '0'));\n\n let suffix = '';\n switch (type) {\n case 'played':\n suffix = this.config.i18n.played;\n break;\n\n case 'buffer':\n suffix = this.config.i18n.buffered;\n break;\n\n default:\n break;\n }\n\n progress.textContent = `% ${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 container = utils.createElement('div', {\n class: 'plyr__time',\n });\n\n container.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n )\n );\n\n container.appendChild(utils.createElement('span', utils.getAttributesFromSelector(this.config.selectors.display[type]), '00:00'));\n\n this.elements.display[type] = container;\n\n return container;\n },\n\n // Create a settings menu item\n createMenuItem(value, list, type, title, badge = null, checked = false) {\n const item = utils.createElement('li');\n\n const label = utils.createElement('label', {\n class: this.config.classNames.control,\n });\n\n const radio = utils.createElement(\n 'input',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs[type]), {\n type: 'radio',\n name: `plyr-${type}`,\n value,\n checked,\n class: 'plyr__sr-only',\n })\n );\n\n const faux = utils.createElement('span', { 'aria-hidden': true });\n\n label.appendChild(radio);\n label.appendChild(faux);\n label.insertAdjacentHTML('beforeend', title);\n\n if (utils.is.element(badge)) {\n label.appendChild(badge);\n }\n\n item.appendChild(label);\n list.appendChild(item);\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 !utils.is.element(this.elements.inputs.seek) ||\n !utils.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.inputs.seek.getBoundingClientRect();\n const visible = `${this.config.classNames.tooltip}--visible`;\n\n // Determine percentage, if already visible\n if (utils.is.event(event)) {\n percent = 100 / clientRect.width * (event.pageX - clientRect.left);\n } else if (utils.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 ui.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 (utils.is.event(event) && [\n 'mouseenter',\n 'mouseleave',\n ].includes(event.type)) {\n utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter');\n }\n },\n\n // Hide/show a tab\n toggleTab(setting, toggle) {\n const tab = this.elements.settings.tabs[setting];\n const pane = this.elements.settings.panes[setting];\n\n utils.toggleHidden(tab, !toggle);\n utils.toggleHidden(pane, !toggle);\n },\n\n // Set the YouTube quality menu\n // TODO: Support for HTML5\n setQualityMenu(options) {\n const type = 'quality';\n const list = this.elements.settings.panes.quality.querySelector('ul');\n\n // Set options if passed and filter based on config\n if (utils.is.array(options)) {\n this.options.quality = options.filter(quality => this.config.quality.options.includes(quality));\n } else {\n this.options.quality = this.config.quality.options;\n }\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.options.quality) && this.isYouTube;\n controls.toggleTab.call(this, type, toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Get the badge HTML for HD, 4K etc\n const getBadge = quality => {\n let label = '';\n\n switch (quality) {\n case 'hd2160':\n label = '4K';\n break;\n\n case 'hd1440':\n label = 'WQHD';\n break;\n\n case 'hd1080':\n label = 'HD';\n break;\n\n case 'hd720':\n label = 'HD';\n break;\n\n default:\n break;\n }\n\n if (!label.length) {\n return null;\n }\n\n return controls.createBadge.call(this, label);\n };\n\n this.options.quality.forEach(quality =>\n controls.createMenuItem.call(this, quality, list, type, controls.getLabel.call(this, 'quality', quality), getBadge(quality))\n );\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Translate a value into a nice label\n // TODO: Localisation\n getLabel(setting, value) {\n switch (setting) {\n case 'speed':\n return value === 1 ? 'Normal' : `${value}×`;\n\n case 'quality':\n switch (value) {\n case 'hd2160':\n return '2160P';\n case 'hd1440':\n return '1440P';\n case 'hd1080':\n return '1080P';\n case 'hd720':\n return '720P';\n case 'large':\n return '480P';\n case 'medium':\n return '360P';\n case 'small':\n return '240P';\n case 'tiny':\n return 'Tiny';\n case 'default':\n return 'Auto';\n default:\n return value;\n }\n\n case 'captions':\n return controls.getLanguage.call(this);\n\n default:\n return null;\n }\n },\n\n // Update the selected setting\n updateSetting(setting, container) {\n const pane = this.elements.settings.panes[setting];\n let value = null;\n let list = container;\n\n switch (setting) {\n case 'captions':\n value = this.captions.active ? this.captions.language : '';\n break;\n\n default:\n value = this[setting];\n\n // Get default\n if (utils.is.empty(value)) {\n value = this.config[setting].default;\n }\n\n // Unsupported value\n if (!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 break;\n }\n\n // Get the list if we need to\n if (!utils.is.element(list)) {\n list = pane && pane.querySelector('ul');\n }\n\n // Update the label\n if (!utils.is.empty(value)) {\n const label = this.elements.settings.tabs[setting].querySelector(`.${this.config.classNames.menu.value}`);\n label.innerHTML = controls.getLabel.call(this, setting, value);\n }\n\n // Find the radio option\n const target = list && list.querySelector(`input[value=\"${value}\"]`);\n\n if (utils.is.element(target)) {\n // Check it\n target.checked = true;\n }\n },\n\n // Set the looping options\n /* setLoopMenu() {\n const options = ['start', 'end', 'all', 'reset'];\n const list = this.elements.settings.panes.loop.querySelector('ul');\n\n // Show the pane and tab\n utils.toggleHidden(this.elements.settings.tabs.loop, false);\n utils.toggleHidden(this.elements.settings.panes.loop, false);\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.loop.options);\n controls.toggleTab.call(this, 'loop', toggle);\n\n // Empty the menu\n utils.emptyElement(list);\n\n options.forEach(option => {\n const item = utils.createElement('li');\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.loop), {\n type: 'button',\n class: this.config.classNames.control,\n 'data-plyr-loop-action': option,\n }),\n this.config.i18n[option]\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 getLanguage() {\n if (!this.supported.ui) {\n return null;\n }\n\n if (!support.textTracks || !captions.getTracks.call(this).length) {\n return this.config.i18n.none;\n }\n\n if (this.captions.active) {\n const currentTrack = captions.getCurrentTrack.call(this);\n\n if (utils.is.track(currentTrack)) {\n return currentTrack.label;\n }\n }\n\n return this.config.i18n.disabled;\n },\n\n // Set a list of available captions languages\n setCaptionsMenu() {\n // TODO: Captions or language? Currently it's mixed\n const type = 'captions';\n const list = this.elements.settings.panes.captions.querySelector('ul');\n\n // Toggle the pane and tab\n const hasTracks = captions.getTracks.call(this).length;\n controls.toggleTab.call(this, type, hasTracks);\n\n // Empty the menu\n utils.emptyElement(list);\n\n // If there's no captions, bail\n if (!hasTracks) {\n return;\n }\n\n // Re-map the tracks into just the data we need\n const tracks = captions.getTracks.call(this).map(track => ({\n language: track.language,\n label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(),\n }));\n\n // Add the \"None\" option to turn off captions\n tracks.unshift({\n language: '',\n label: this.config.i18n.none,\n });\n\n // Generate options\n tracks.forEach(track => {\n controls.createMenuItem.call(\n this,\n track.language,\n list,\n 'language',\n track.label || track.language,\n controls.createBadge.call(this, track.language.toUpperCase()),\n track.language.toLowerCase() === this.captions.language.toLowerCase()\n );\n });\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Set a list of available captions languages\n setSpeedMenu() {\n const type = 'speed';\n\n // Set the default speeds\n if (!utils.is.object(this.options.speed) || !Object.keys(this.options.speed).length) {\n this.options.speed = [\n 0.5,\n 0.75,\n 1,\n 1.25,\n 1.5,\n 1.75,\n 2,\n ];\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 = !utils.is.empty(this.options.speed);\n controls.toggleTab.call(this, type, toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Get the list to populate\n const list = this.elements.settings.panes.speed.querySelector('ul');\n\n // Show the pane and tab\n utils.toggleHidden(this.elements.settings.tabs.speed, false);\n utils.toggleHidden(this.elements.settings.panes.speed, false);\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Create items\n this.options.speed.forEach(speed => controls.createMenuItem.call(this, speed, list, type, controls.getLabel.call(this, 'speed', speed)));\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Show/hide menu\n toggleMenu(event) {\n const { form } = this.elements.settings;\n const button = this.elements.buttons.settings;\n const show = utils.is.boolean(event) ? event : utils.is.element(form) && form.getAttribute('aria-hidden') === 'true';\n\n if (utils.is.event(event)) {\n const isMenuItem = utils.is.element(form) && form.contains(event.target);\n const isButton = event.target === this.elements.buttons.settings;\n\n // If the click was inside the form 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 && !isButton && show)) {\n return;\n }\n\n // Prevent the toggle being caught by the doc listener\n if (isButton) {\n event.stopPropagation();\n }\n }\n\n // Set form and button attributes\n if (utils.is.element(button)) {\n button.setAttribute('aria-expanded', show);\n }\n\n if (utils.is.element(form)) {\n form.setAttribute('aria-hidden', !show);\n utils.toggleClass(this.elements.container, this.config.classNames.menu.open, show);\n\n if (show) {\n form.removeAttribute('tabindex');\n } else {\n form.setAttribute('tabindex', -1);\n }\n }\n },\n\n // Get the natural size of a tab\n getTabSize(tab) {\n const clone = tab.cloneNode(true);\n clone.style.position = 'absolute';\n clone.style.opacity = 0;\n clone.setAttribute('aria-hidden', false);\n\n // Prevent input's being unchecked due to the name being identical\n Array.from(clone.querySelectorAll('input[name]')).forEach(input => {\n const name = input.getAttribute('name');\n input.setAttribute('name', `${name}-clone`);\n });\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 utils.removeElement(clone);\n\n return {\n width,\n height,\n };\n },\n\n // Toggle Menu\n showTab(event) {\n const { menu } = this.elements.settings;\n const tab = event.target;\n const show = tab.getAttribute('aria-expanded') === 'false';\n const pane = document.getElementById(tab.getAttribute('aria-controls'));\n\n // Nothing to show, bail\n if (!utils.is.element(pane)) {\n return;\n }\n\n // Are we targetting a tab? If not, bail\n const isTab = pane.getAttribute('role') === 'tabpanel';\n if (!isTab) {\n return;\n }\n\n // Hide all other tabs\n // Get other tabs\n const current = menu.querySelector('[role=\"tabpanel\"][aria-hidden=\"false\"]');\n const container = current.parentNode;\n\n // Set other toggles to be expanded false\n Array.from(menu.querySelectorAll(`[aria-controls=\"${current.getAttribute('id')}\"]`)).forEach(toggle => {\n toggle.setAttribute('aria-expanded', false);\n });\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.getTabSize.call(this, pane);\n\n // Restore auto height/width\n const restore = e => {\n // We're only bothered about height and width on the container\n if (e.target !== container || ![\n 'width',\n 'height',\n ].includes(e.propertyName)) {\n return;\n }\n\n // Revert back to auto\n container.style.width = '';\n container.style.height = '';\n\n // Only listen once\n utils.off(container, utils.transitionEndEvent, restore);\n };\n\n // Listen for the transition finishing and restore auto height/width\n utils.on(container, utils.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 current.setAttribute('aria-hidden', true);\n current.setAttribute('tabindex', -1);\n\n // Set attributes on target\n pane.setAttribute('aria-hidden', !show);\n tab.setAttribute('aria-expanded', show);\n pane.removeAttribute('tabindex');\n\n // Focus the first item\n pane.querySelectorAll('button:not(:disabled), input:not(:disabled), [tabindex]')[0].focus();\n },\n\n // Build the default HTML\n // TODO: Set order based on order in the config.controls array?\n create(data) {\n // Do nothing if we want no controls\n if (utils.is.empty(this.config.controls)) {\n return null;\n }\n\n // Create the container\n const container = utils.createElement('div', utils.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 = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.progress));\n\n // Seek range slider\n const seek = controls.createRange.call(this, 'seek', {\n id: `plyr-seek-${data.id}`,\n });\n progress.appendChild(seek.label);\n progress.appendChild(seek.input);\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 = utils.createElement(\n 'span',\n {\n role: 'tooltip',\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 // Toggle mute button\n if (this.config.controls.includes('mute')) {\n container.appendChild(controls.createButton.call(this, 'mute'));\n }\n\n // Volume range control\n if (this.config.controls.includes('volume')) {\n const volume = utils.createElement('div', {\n class: 'plyr__volume',\n });\n\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 const range = controls.createRange.call(\n this,\n 'volume',\n utils.extend(attributes, {\n id: `plyr-volume-${data.id}`,\n })\n );\n volume.appendChild(range.label);\n volume.appendChild(range.input);\n\n this.elements.volume = volume;\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') && !utils.is.empty(this.config.settings)) {\n const menu = utils.createElement('div', {\n class: 'plyr__menu',\n });\n\n menu.appendChild(\n controls.createButton.call(this, 'settings', {\n id: `plyr-settings-toggle-${data.id}`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}`,\n 'aria-expanded': false,\n })\n );\n\n const form = utils.createElement('form', {\n class: 'plyr__menu__container',\n id: `plyr-settings-${data.id}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tablist',\n tabindex: -1,\n });\n\n const inner = utils.createElement('div');\n\n const home = utils.createElement('div', {\n id: `plyr-settings-${data.id}-home`,\n 'aria-hidden': false,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tabpanel',\n });\n\n // Create the tab list\n const tabs = utils.createElement('ul', {\n role: 'tablist',\n });\n\n // Build the tabs\n this.config.settings.forEach(type => {\n const tab = utils.createElement('li', {\n role: 'tab',\n hidden: '',\n });\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.settings), {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`,\n id: `plyr-settings-${data.id}-${type}-tab`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-${type}`,\n 'aria-expanded': false,\n }),\n this.config.i18n[type]\n );\n\n const value = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n // Speed contains HTML entities\n value.innerHTML = data[type];\n\n button.appendChild(value);\n tab.appendChild(button);\n tabs.appendChild(tab);\n\n this.elements.settings.tabs[type] = tab;\n });\n\n home.appendChild(tabs);\n inner.appendChild(home);\n\n // Build the panes\n this.config.settings.forEach(type => {\n const pane = utils.createElement('div', {\n id: `plyr-settings-${data.id}-${type}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-${data.id}-${type}-tab`,\n role: 'tabpanel',\n tabindex: -1,\n hidden: '',\n });\n\n const back = utils.createElement(\n 'button',\n {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--back`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-home`,\n 'aria-expanded': false,\n },\n this.config.i18n[type]\n );\n\n pane.appendChild(back);\n\n const options = utils.createElement('ul');\n\n pane.appendChild(options);\n inner.appendChild(pane);\n\n this.elements.settings.panes[type] = pane;\n });\n\n form.appendChild(inner);\n menu.appendChild(form);\n container.appendChild(menu);\n\n this.elements.settings.form = form;\n this.elements.settings.menu = menu;\n }\n\n // Picture in picture button\n if (this.config.controls.includes('pip') && support.pip) {\n container.appendChild(controls.createButton.call(this, 'pip'));\n }\n\n // Airplay button\n if (this.config.controls.includes('airplay') && support.airplay) {\n container.appendChild(controls.createButton.call(this, 'airplay'));\n }\n\n // Toggle fullscreen button\n if (this.config.controls.includes('fullscreen')) {\n container.appendChild(controls.createButton.call(this, 'fullscreen'));\n }\n\n // Larger overlaid play button\n if (this.config.controls.includes('play-large')) {\n this.elements.container.appendChild(controls.createButton.call(this, 'play-large'));\n }\n\n this.elements.controls = container;\n\n if (this.config.controls.includes('settings') && this.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(this);\n }\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.absolute) {\n utils.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 // HTML or Element passed as the option\n if (utils.is.string(this.config.controls) || utils.is.element(this.config.controls)) {\n container = this.config.controls;\n } else if (utils.is.function(this.config.controls)) {\n // A custom function to build controls\n // The function can return a HTMLElement or String\n container = this.config.controls({\n id: this.id,\n seektime: this.config.seekTime,\n title: this.config.title,\n });\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: controls.getLanguage.call(this),\n // TODO: Looping\n // loop: 'None',\n });\n }\n\n // Controls container\n let target;\n\n // Inject to custom location\n if (utils.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 (!utils.is.element(target)) {\n target = this.elements.container;\n }\n\n // Inject controls HTML\n if (utils.is.element(container)) {\n target.appendChild(container);\n } else {\n target.insertAdjacentHTML('beforeend', container);\n }\n\n // Find the elements if need be\n if (!utils.is.element(this.elements.controls)) {\n utils.findElements.call(this);\n }\n\n // Edge sometimes doesn't finish the paint so force a redraw\n if (window.navigator.userAgent.includes('Edge')) {\n utils.repaint(target);\n }\n\n // Setup tooltips\n if (this.config.tooltips.controls) {\n const labels = utils.getElements.call(\n this,\n [\n this.config.selectors.controls.wrapper,\n ' ',\n this.config.selectors.labels,\n ' .',\n this.config.classNames.hidden,\n ].join('')\n );\n\n Array.from(labels).forEach(label => {\n utils.toggleClass(label, this.config.classNames.hidden, false);\n utils.toggleClass(label, this.config.classNames.tooltip, true);\n label.setAttribute('role', 'tooltip');\n });\n }\n },\n};\n\nexport default controls;\n","// ==========================================================================\n// Plyr Captions\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\n\nconst captions = {\n // Setup captions\n setup() {\n // Requires UI support\n if (!this.supported.ui) {\n return;\n }\n\n // Set default language if not set\n const stored = this.storage.get('language');\n\n if (!utils.is.empty(stored)) {\n this.captions.language = stored;\n }\n\n if (utils.is.empty(this.captions.language)) {\n this.captions.language = this.config.captions.language.toLowerCase();\n }\n\n // Set captions enabled state if not set\n if (!utils.is.boolean(this.captions.active)) {\n const active = this.storage.get('captions');\n\n if (utils.is.boolean(active)) {\n this.captions.active = active;\n } else {\n this.captions.active = this.config.captions.active;\n }\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 (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n\n return;\n }\n\n // Inject the container\n if (!utils.is.element(this.elements.captions)) {\n this.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.captions));\n\n utils.insertAfter(this.elements.captions, this.elements.wrapper);\n }\n\n // Set the class hook\n utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this)));\n\n // If no caption file exists, hide container for caption text\n if (utils.is.empty(captions.getTracks.call(this))) {\n return;\n }\n\n // Set language\n captions.setLanguage.call(this);\n\n // Enable UI\n captions.show.call(this);\n\n // Set available languages in list\n if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n },\n\n // Set the captions language\n setLanguage() {\n // Setup HTML5 track rendering\n if (this.isHTML5 && this.isVideo) {\n captions.getTracks.call(this).forEach(track => {\n // Show track\n utils.on(track, 'cuechange', event => captions.setCue.call(this, event));\n\n // Turn off native caption rendering to avoid double captions\n // eslint-disable-next-line\n track.mode = 'hidden';\n });\n\n // Get current track\n const currentTrack = captions.getCurrentTrack.call(this);\n\n // Check if suported kind\n if (utils.is.track(currentTrack)) {\n // If we change the active track while a cue is already displayed we need to update it\n if (Array.from(currentTrack.activeCues || []).length) {\n captions.setCue.call(this, currentTrack);\n }\n }\n } else if (this.isVimeo && this.captions.active) {\n this.embed.enableTextTrack(this.language);\n }\n },\n\n // Get the tracks\n getTracks() {\n // Return empty array at least\n if (utils.is.nullOrUndefined(this.media)) {\n return [];\n }\n\n // Only get accepted kinds\n return Array.from(this.media.textTracks || []).filter(track => [\n 'captions',\n 'subtitles',\n ].includes(track.kind));\n },\n\n // Get the current track for the current language\n getCurrentTrack() {\n return captions.getTracks.call(this).find(track => track.language.toLowerCase() === this.language);\n },\n\n // Display active caption if it contains text\n setCue(input) {\n // Get the track from the event if needed\n const track = utils.is.event(input) ? input.target : input;\n const { activeCues } = track;\n const active = activeCues.length && activeCues[0];\n const currentTrack = captions.getCurrentTrack.call(this);\n\n // Only display current track\n if (track !== currentTrack) {\n return;\n }\n\n // Display a cue, if there is one\n if (utils.is.cue(active)) {\n captions.setText.call(this, active.getCueAsHTML());\n } else {\n captions.setText.call(this, null);\n }\n\n utils.dispatchEvent.call(this, this.media, 'cuechange');\n },\n\n // Set the current caption\n setText(input) {\n // Requires UI\n if (!this.supported.ui) {\n return;\n }\n\n if (utils.is.element(this.elements.captions)) {\n const content = utils.createElement('span');\n\n // Empty the container\n utils.emptyElement(this.elements.captions);\n\n // Default to empty\n const caption = !utils.is.nullOrUndefined(input) ? input : '';\n\n // Set the span content\n if (utils.is.string(caption)) {\n content.textContent = caption.trim();\n } else {\n content.appendChild(caption);\n }\n\n // Set new caption text\n this.elements.captions.appendChild(content);\n } else {\n this.debug.warn('No captions element to render to');\n }\n },\n\n // Display captions container and button (for initialization)\n show() {\n // If there's no caption toggle, bail\n if (!utils.is.element(this.elements.buttons.captions)) {\n return;\n }\n\n // Try to load the value from storage\n let active = this.storage.get('captions');\n\n // Otherwise fall back to the default config\n if (!utils.is.boolean(active)) {\n ({ active } = this.config.captions);\n } else {\n this.captions.active = active;\n }\n\n if (active) {\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true);\n utils.toggleState(this.elements.buttons.captions, true);\n }\n },\n};\n\nexport default captions;\n","// ==========================================================================\n// YouTube plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport controls from './../controls';\nimport ui from './../ui';\n\nconst youtube = {\n setup() {\n // Add embed class for responsive\n utils.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 (utils.is.object(window.YT) && utils.is.function(window.YT.Player)) {\n youtube.ready.call(this);\n } else {\n // Load the API\n utils.loadScript(this.config.urls.youtube.api);\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 (utils.is.function(this.embed.getVideoData)) {\n const { title } = this.embed.getVideoData();\n\n if (utils.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 (utils.is.string(key) && !utils.is.empty(key)) {\n const url = `https://www.googleapis.com/youtube/v3/videos?id=${videoId}&key=${key}&fields=items(snippet(title))&part=snippet`;\n\n utils\n .fetch(url)\n .then(result => {\n if (utils.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 (!utils.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 (utils.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 = utils.parseYouTubeId(source);\n const id = utils.generateId(player.provider);\n const container = utils.createElement('div', { id });\n player.media = utils.replaceElement(container, player.media);\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 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 // If we've already fired an error, don't do it again\n // YouTube fires onError twice\n if (utils.is.object(player.media.error)) {\n return;\n }\n\n const detail = {\n code: event.data,\n };\n\n // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError\n switch (event.data) {\n case 2:\n detail.message =\n '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 break;\n\n case 5:\n detail.message =\n 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.';\n break;\n\n case 100:\n detail.message =\n '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 break;\n\n case 101:\n case 150:\n detail.message = 'The owner of the requested video does not allow it to be played in embedded players.';\n break;\n\n default:\n detail.message = 'An unknown error occured';\n break;\n }\n\n player.media.error = detail;\n\n utils.dispatchEvent.call(player, player.media, 'error');\n },\n onPlaybackQualityChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current quality\n player.media.quality = instance.getPlaybackQuality();\n\n utils.dispatchEvent.call(player, player.media, 'qualitychange');\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 utils.dispatchEvent.call(player, player.media, 'ratechange');\n },\n onReady(event) {\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 instance.playVideo();\n player.media.paused = false;\n };\n\n player.media.pause = () => {\n instance.pauseVideo();\n player.media.paused = true;\n };\n\n player.media.stop = () => {\n instance.stopVideo();\n player.media.paused = true;\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 // Set seeking flag\n player.media.seeking = true;\n\n // Trigger seeking\n utils.dispatchEvent.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 // Quality\n Object.defineProperty(player.media, 'quality', {\n get() {\n return instance.getPlaybackQuality();\n },\n set(input) {\n // Trigger request event\n utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {\n quality: input,\n });\n\n instance.setPlaybackQuality(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 utils.dispatchEvent.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 = utils.is.boolean(input) ? input : muted;\n muted = toggle;\n instance[toggle ? 'mute' : 'unMute']();\n utils.dispatchEvent.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 utils.dispatchEvent.call(player, player.media, 'timeupdate');\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n\n // Reset timer\n window.clearInterval(player.timers.buffering);\n\n // Setup buffering\n player.timers.buffering = window.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 utils.dispatchEvent.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 window.clearInterval(player.timers.buffering);\n\n // Trigger event\n utils.dispatchEvent.call(player, player.media, 'canplaythrough');\n }\n }, 200);\n\n // Rebuild UI\n window.setTimeout(() => ui.build.call(player), 50);\n },\n onStateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Reset timer\n window.clearInterval(player.timers.playing);\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 0:\n player.media.paused = true;\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 utils.dispatchEvent.call(player, player.media, 'ended');\n }\n\n break;\n\n case 1:\n // If we were seeking, fire seeked event\n if (player.media.seeking) {\n utils.dispatchEvent.call(player, player.media, 'seeked');\n }\n player.media.seeking = false;\n\n // Only fire play if paused before\n if (player.media.paused) {\n utils.dispatchEvent.call(player, player.media, 'play');\n }\n player.media.paused = false;\n\n utils.dispatchEvent.call(player, player.media, 'playing');\n\n // Poll to get playback progress\n player.timers.playing = window.setInterval(() => {\n utils.dispatchEvent.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 utils.dispatchEvent.call(player, player.media, 'durationchange');\n }\n\n // Get quality\n controls.setQualityMenu.call(player, instance.getAvailableQualityLevels());\n\n break;\n\n case 2:\n player.media.paused = true;\n\n utils.dispatchEvent.call(player, player.media, 'pause');\n\n break;\n\n default:\n break;\n }\n\n utils.dispatchEvent.call(player, player.elements.container, 'statechange', false, {\n code: event.data,\n });\n },\n },\n });\n },\n};\n\nexport default youtube;\n","// ==========================================================================\n// Vimeo plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport captions from './../captions';\nimport ui from './../ui';\n\nconst vimeo = {\n setup() {\n // Add embed class for responsive\n utils.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 (!utils.is.object(window.Vimeo)) {\n utils.loadScript(this.config.urls.vimeo.api, () => {\n vimeo.ready.call(this);\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 ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');\n const padding = 100 / ratio[0] * ratio[1];\n const height = 200;\n const offset = (height - padding) / (height / 50);\n this.elements.wrapper.style.paddingBottom = `${padding}%`;\n this.media.style.transform = `translateY(-${offset}%)`;\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 byline: false,\n portrait: false,\n title: false,\n speed: true,\n transparent: 0,\n gesture: 'media',\n };\n const params = utils.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 (utils.is.empty(source)) {\n source = player.media.getAttribute(this.config.attributes.embed.id);\n }\n\n const id = utils.parseVimeoId(source);\n\n // Build an iframe\n const iframe = utils.createElement('iframe');\n const src = `https://player.vimeo.com/video/${id}?${params}`;\n iframe.setAttribute('src', src);\n iframe.setAttribute('allowfullscreen', '');\n iframe.setAttribute('allowtransparency', '');\n iframe.setAttribute('allow', 'autoplay');\n\n // Inject the package\n const wrapper = utils.createElement('div');\n wrapper.appendChild(iframe);\n player.media = utils.replaceElement(wrapper, player.media);\n\n // Setup instance\n // https://github.com/vimeo/player.js\n player.embed = new window.Vimeo.Player(iframe);\n\n player.media.paused = true;\n player.media.currentTime = 0;\n\n // Create a faux HTML5 API using the Vimeo API\n player.media.play = () => {\n player.embed.play().then(() => {\n player.media.paused = false;\n });\n };\n\n player.media.pause = () => {\n player.embed.pause().then(() => {\n player.media.paused = true;\n });\n };\n\n player.media.stop = () => {\n player.embed.stop().then(() => {\n player.media.paused = true;\n player.currentTime = 0;\n });\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 // Get current paused state\n // Vimeo will automatically play on seek\n const { paused } = player.media;\n\n // Set seeking flag\n player.media.seeking = true;\n\n // Trigger seeking\n utils.dispatchEvent.call(player, player.media, 'seeking');\n\n // Seek after events\n player.embed.setCurrentTime(time);\n\n // Restore pause state\n if (paused) {\n player.pause();\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.setPlaybackRate(input).then(() => {\n speed = input;\n utils.dispatchEvent.call(player, player.media, 'ratechange');\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 utils.dispatchEvent.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 = utils.is.boolean(input) ? input : false;\n\n player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => {\n muted = toggle;\n utils.dispatchEvent.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 = utils.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.getVideoUrl().then(value => {\n currentSrc = value;\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([\n player.embed.getVideoWidth(),\n player.embed.getVideoHeight(),\n ]).then(dimensions => {\n const ratio = utils.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 utils.dispatchEvent.call(player, player.media, 'timeupdate');\n });\n\n // Get duration\n player.embed.getDuration().then(value => {\n player.media.duration = value;\n utils.dispatchEvent.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', data => {\n let cue = null;\n\n if (data.cues.length) {\n cue = utils.stripHTML(data.cues[0].text);\n }\n\n captions.setText.call(player, cue);\n });\n\n player.embed.on('loaded', () => {\n if (utils.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 // Only fire play if paused before\n if (player.media.paused) {\n utils.dispatchEvent.call(player, player.media, 'play');\n }\n player.media.paused = false;\n utils.dispatchEvent.call(player, player.media, 'playing');\n });\n\n player.embed.on('pause', () => {\n player.media.paused = true;\n utils.dispatchEvent.call(player, player.media, 'pause');\n });\n\n player.embed.on('timeupdate', data => {\n player.media.seeking = false;\n currentTime = data.seconds;\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n });\n\n player.embed.on('progress', data => {\n player.media.buffered = data.percent;\n utils.dispatchEvent.call(player, player.media, 'progress');\n\n // Check all loaded\n if (parseInt(data.percent, 10) === 1) {\n utils.dispatchEvent.call(player, player.media, 'canplaythrough');\n }\n });\n\n player.embed.on('seeked', () => {\n player.media.seeking = false;\n utils.dispatchEvent.call(player, player.media, 'seeked');\n utils.dispatchEvent.call(player, player.media, 'play');\n });\n\n player.embed.on('ended', () => {\n player.media.paused = true;\n utils.dispatchEvent.call(player, player.media, 'ended');\n });\n\n player.embed.on('error', detail => {\n player.media.error = detail;\n utils.dispatchEvent.call(player, player.media, 'error');\n });\n\n // Rebuild UI\n window.setTimeout(() => ui.build.call(player), 0);\n },\n};\n\nexport default vimeo;\n","// ==========================================================================\n// Plyr Media\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport youtube from './plugins/youtube';\nimport vimeo from './plugins/vimeo';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\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 utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', this.type), true);\n\n // Add provider class\n utils.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 utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true);\n }\n\n if (this.supported.ui) {\n // Check for picture-in-picture support\n utils.toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo);\n\n // Check for airplay support\n utils.toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5);\n\n // If there's no autoplay attribute, assume the video is stopped and add state class\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.config.autoplay);\n\n // Add iOS class\n utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);\n\n // Add touch class\n utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch);\n }\n\n // Inject the player wrapper\n if (this.isVideo) {\n // Create the wrapper div\n this.elements.wrapper = utils.createElement('div', {\n class: this.config.classNames.video,\n });\n\n // Wrap the video in a container\n utils.wrap(this.media, this.elements.wrapper);\n }\n\n if (this.isEmbed) {\n switch (this.provider) {\n case 'youtube':\n youtube.setup.call(this);\n break;\n\n case 'vimeo':\n vimeo.setup.call(this);\n break;\n\n default:\n break;\n }\n } else if (this.isHTML5) {\n ui.setTitle.call(this);\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 utils.removeElement(this.media.querySelectorAll('source'));\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 media;\n","// ==========================================================================\n// Plyr source update\n// ==========================================================================\n\nimport { providers } from './types';\nimport utils from './utils';\nimport media from './media';\nimport ui from './ui';\nimport support from './support';\n\nconst source = {\n // Add elements to HTML5 media (source, tracks, etc)\n insertElements(type, attributes) {\n if (utils.is.string(attributes)) {\n utils.insertElement(type, this.media, {\n src: attributes,\n });\n } else if (utils.is.array(attributes)) {\n attributes.forEach(attribute => {\n utils.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 (!utils.is.object(input) || !('sources' in input) || !input.sources.length) {\n this.debug.warn('Invalid source format');\n return;\n }\n\n // Cancel current network requests\n media.cancelRequests.call(this);\n\n // Destroy instance and re-setup\n this.destroy.call(\n this,\n () => {\n // TODO: Reset menus here\n\n // Remove elements\n utils.removeElement(this.media);\n this.media = null;\n\n // Reset class name\n if (utils.is.element(this.elements.container)) {\n this.elements.container.removeAttribute('class');\n }\n\n // Set the type and provider\n this.type = input.type;\n this.provider = !utils.is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5;\n\n // Check for support\n this.supported = support.check(this.type, this.provider, this.config.inline);\n\n // Create new markup\n switch (`${this.provider}:${this.type}`) {\n case 'html5:video':\n this.media = utils.createElement('video');\n break;\n\n case 'html5:audio':\n this.media = utils.createElement('audio');\n break;\n\n case 'youtube:video':\n case 'vimeo:video':\n this.media = utils.createElement('div', {\n src: input.sources[0].src,\n });\n break;\n\n default:\n break;\n }\n\n // Inject the new element\n this.elements.container.appendChild(this.media);\n\n // Autoplay the new source?\n if (utils.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 ('poster' in input) {\n this.media.setAttribute('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.inline) {\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', input.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.0.0-beta.14\n// https://github.com/sampotts/plyr\n// License: The MIT License (MIT)\n// ==========================================================================\n\nimport { providers, types } from './types';\nimport defaults from './defaults';\nimport support from './support';\nimport utils from './utils';\n\nimport Console from './console';\nimport Fullscreen from './fullscreen';\nimport Storage from './storage';\nimport Ads from './plugins/ads';\n\nimport captions from './captions';\nimport controls from './controls';\nimport listeners from './listeners';\nimport media from './media';\nimport source from './source';\nimport ui from './ui';\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 // Set the media element\n this.media = target;\n\n // String selector passed\n if (utils.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) || utils.is.nodeList(this.media) || utils.is.array(this.media)) {\n // eslint-disable-next-line\n this.media = this.media[0];\n }\n\n // Set config\n this.config = utils.extend(\n {},\n 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 buttons: {},\n display: {},\n progress: {},\n inputs: {},\n settings: {\n menu: null,\n panes: {},\n tabs: {},\n },\n captions: null,\n };\n\n // Captions\n this.captions = {\n active: null,\n currentTrack: null,\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 (utils.is.nullOrUndefined(this.media) || !utils.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 this.elements.original = this.media.cloneNode(true);\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 let params = 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 (utils.is.element(iframe)) {\n // Detect provider\n url = iframe.getAttribute('src');\n this.provider = utils.getProviderByUrl(url);\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 params = utils.getUrlParams(url);\n if (!utils.is.empty(params)) {\n const truthy = [\n '1',\n 'true',\n ];\n\n if (truthy.includes(params.autoplay)) {\n this.config.autoplay = true;\n }\n if (truthy.includes(params.playsinline)) {\n this.config.inline = true;\n }\n if (truthy.includes(params.loop)) {\n this.config.loop.active = 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 (utils.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')) {\n this.config.inline = 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.inline);\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 // 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 (!utils.is.element(this.elements.container)) {\n this.elements.container = utils.createElement('div');\n utils.wrap(this.media, this.elements.container);\n }\n\n // Allow focus to be captured\n this.elements.container.setAttribute('tabindex', 0);\n\n // Global listeners\n listeners.global.call(this);\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 utils.on(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 // Setup fullscreen\n this.fullscreen = new Fullscreen(this);\n\n // Setup ads if provided\n this.ads = new Ads(this);\n }\n\n // ---------------------------------------\n // API\n // ---------------------------------------\n\n /**\n * Types and provider helpers\n */\n get isHTML5() {\n return this.provider === providers.html5;\n }\n get isEmbed() {\n return this.isYouTube || this.isVimeo;\n }\n get isYouTube() {\n return this.provider === providers.youtube;\n }\n get isVimeo() {\n return this.provider === providers.vimeo;\n }\n get isVideo() {\n return this.type === types.video;\n }\n get isAudio() {\n return this.type === types.audio;\n }\n\n /**\n * Play the media, or play the advertisement (if they are not blocked)\n */\n play() {\n // TODO: Always return a promise?\n if (this.ads.enabled && !this.ads.initialized && !this.ads.blocked) {\n this.ads.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) {\n return;\n }\n\n this.media.pause();\n }\n\n /**\n * Get paused state\n */\n get paused() {\n return this.media.paused;\n }\n\n /**\n * Get playing state\n */\n get playing() {\n return !this.paused && !this.ended && (this.isHTML5 ? this.media.readyState > 2 : true);\n }\n\n /**\n * Get ended state\n */\n get ended() {\n return 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 = utils.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 this.restart();\n this.pause();\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 - (utils.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 + (utils.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 let targetTime = 0;\n\n if (utils.is.number(input)) {\n targetTime = input;\n }\n\n // Normalise targetTime\n if (targetTime < 0) {\n targetTime = 0;\n } else if (targetTime > this.duration) {\n targetTime = this.duration;\n }\n\n // Set\n this.media.currentTime = targetTime.toFixed(4);\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 seeking status\n */\n get seeking() {\n return 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 = parseInt(this.config.duration, 10);\n\n // True duration\n const realDuration = Number(this.media.duration);\n\n // If custom duration is funky, use regular duration\n return !Number.isNaN(fauxDuration) ? fauxDuration : realDuration;\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 (utils.is.string(volume)) {\n volume = Number(volume);\n }\n\n // Load volume from storage if no value specified\n if (!utils.is.number(volume)) {\n volume = this.storage.get('volume');\n }\n\n // Use config if all else fails\n if (!utils.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, reset muted state\n if (this.muted && volume > 0) {\n this.muted = false;\n }\n }\n\n /**\n * Get the current player volume\n */\n get volume() {\n return 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 + (utils.is.number(step) ? step : 1);\n }\n\n /**\n * Decrease volume\n * @param {boolean} step - How much to decrease by (between 0 and 1)\n */\n decreaseVolume(step) {\n const volume = this.media.muted ? 0 : this.volume;\n this.volume = volume - (utils.is.number(step) ? step : 1);\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 (!utils.is.boolean(toggle)) {\n toggle = this.storage.get('muted');\n }\n\n // Use config if all else fails\n if (!utils.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 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 this.media.mozHasAudio || Boolean(this.media.webkitAudioDecodedByteCount) || Boolean(this.media.audioTracks && this.media.audioTracks.length);\n }\n\n /**\n * Set playback speed\n * @param {decimal} speed - the speed of playback (0.5-2.0)\n */\n set speed(input) {\n let speed = null;\n\n if (utils.is.number(input)) {\n speed = input;\n }\n\n if (!utils.is.number(speed)) {\n speed = this.storage.get('speed');\n }\n\n if (!utils.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 this.media.playbackRate;\n }\n\n /**\n * Set playback quality\n * Currently YouTube only\n * @param {string} input - Quality level\n */\n set quality(input) {\n let quality = null;\n\n if (utils.is.string(input)) {\n quality = input;\n }\n\n if (!utils.is.string(quality)) {\n quality = this.storage.get('quality');\n }\n\n if (!utils.is.string(quality)) {\n quality = this.config.quality.selected;\n }\n\n if (!this.options.quality.includes(quality)) {\n this.debug.warn(`Unsupported quality option (${quality})`);\n return;\n }\n\n // Update config\n this.config.quality.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 = utils.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 this.media.loop;\n }\n\n /**\n * Set new media source\n * @param {object} input - The new source object (see docs)\n */\n set source(input) {\n source.change.call(this, input);\n }\n\n /**\n * Get current source\n */\n get source() {\n return this.media.currentSrc;\n }\n\n /**\n * Set the poster image for a HTML5 video\n * @param {input} - the URL for the new poster image\n */\n set poster(input) {\n if (!this.isHTML5 || !this.isVideo) {\n this.debug.warn('Poster can only be set on HTML5 video');\n return;\n }\n\n if (utils.is.string(input)) {\n this.media.setAttribute('poster', input);\n }\n }\n\n /**\n * Get the current poster image\n */\n get poster() {\n if (!this.isHTML5 || !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 = utils.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 this.config.autoplay;\n }\n\n /**\n * Toggle captions\n * @param {boolean} input - Whether to enable captions\n */\n toggleCaptions(input) {\n // If there's no full support, or there's no caption toggle\n if (!this.supported.ui || !utils.is.element(this.elements.buttons.captions)) {\n return;\n }\n\n // If the method is called without parameter, toggle based on current value\n const show = utils.is.boolean(input) ? input : this.elements.container.className.indexOf(this.config.classNames.captions.active) === -1;\n\n // Nothing to change...\n if (this.captions.active === show) {\n return;\n }\n\n // Set global\n this.captions.active = show;\n\n // Toggle state\n utils.toggleState(this.elements.buttons.captions, this.captions.active);\n\n // Add class hook\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.active);\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled');\n }\n\n /**\n * Set the captions language\n * @param {string} - Two character ISO language code (e.g. EN, FR, PT, etc)\n */\n set language(input) {\n // Nothing specified\n if (!utils.is.string(input)) {\n return;\n }\n\n // Toggle captions based on input\n this.toggleCaptions(!utils.is.empty(input));\n\n // If empty string is passed, assume disable captions\n if (utils.is.empty(input)) {\n return;\n }\n\n // Normalize\n const language = input.toLowerCase();\n\n // If nothing to change, bail\n if (this.language === language) {\n return;\n }\n\n // Update config\n this.captions.language = language;\n\n // Clear caption\n captions.setText.call(this, null);\n\n // Update captions\n captions.setLanguage.call(this);\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, 'languagechange');\n }\n\n /**\n * Get the current captions language\n */\n get language() {\n return this.captions.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 = utils.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 // We need controls of course...\n if (!utils.is.element(this.elements.controls)) {\n return;\n }\n\n // Don't hide if no UI support or it's audio\n if (!this.supported.ui || this.isAudio) {\n return;\n }\n\n let delay = 0;\n let show = toggle;\n let isEnterFullscreen = false;\n\n // Get toggle state if not set\n if (!utils.is.boolean(toggle)) {\n if (utils.is.event(toggle)) {\n // Is the enter fullscreen event\n isEnterFullscreen = toggle.type === 'enterfullscreen';\n\n // Whether to show controls\n show = [\n 'mouseenter',\n 'mousemove',\n 'touchstart',\n 'touchmove',\n 'focusin',\n ].includes(toggle.type);\n\n // Delay hiding on move events\n if ([\n 'mousemove',\n 'touchmove',\n 'touchend',\n ].includes(toggle.type)) {\n delay = 2000;\n }\n\n // Delay a little more for keyboard users\n if (toggle.type === 'focusin') {\n delay = 3000;\n utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true);\n }\n } else {\n show = utils.hasClass(this.elements.container, this.config.classNames.hideControls);\n }\n }\n\n // Clear timer on every call\n window.clearTimeout(this.timers.controls);\n\n // If the mouse is not over the controls, set a timeout to hide them\n if (show || this.paused || this.loading) {\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, false);\n\n // Trigger event\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlsshown');\n }\n\n // Always show controls when paused or if touch\n if (this.paused || this.loading) {\n return;\n }\n\n // Delay for hiding on touch\n if (support.touch) {\n delay = 3000;\n }\n }\n\n // If toggle is false or if we're playing (regardless of toggle),\n // then set the timer to hide the controls\n if (!show || this.playing) {\n this.timers.controls = window.setTimeout(() => {\n /* this.debug.warn({\n pressed: this.elements.controls.pressed,\n hover: this.elements.controls.pressed,\n playing: this.playing,\n paused: this.paused,\n loading: this.loading,\n }); */\n\n // If the mouse is over the controls (and not entering fullscreen), bail\n if ((this.elements.controls.pressed || this.elements.controls.hover) && !isEnterFullscreen) {\n return;\n }\n\n // Restore transition behaviour\n if (!utils.hasClass(this.elements.container, this.config.classNames.hideControls)) {\n utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, false);\n }\n\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, true);\n\n // Trigger event and close menu\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlshidden');\n\n if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) {\n controls.toggleMenu.call(this, false);\n }\n }\n }, delay);\n }\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 utils.on(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 utils.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 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 utils.removeElement(this.elements.buttons.play);\n utils.removeElement(this.elements.captions);\n utils.removeElement(this.elements.controls);\n utils.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 (utils.is.function(callback)) {\n callback();\n }\n } else {\n // Replace the container with the original element provided\n utils.replaceElement(this.elements.original, this.elements.container);\n\n // Event\n utils.dispatchEvent.call(this, this.elements.original, 'destroyed', true);\n\n // Callback\n if (utils.is.function(callback)) {\n callback.call(this.elements.original);\n }\n\n // Clear for GC\n this.elements = null;\n }\n };\n\n // Type specific stuff\n switch (`${this.provider}:${this.type}`) {\n case 'html5:video':\n case 'html5:audio':\n // Restore native video controls\n ui.toggleNativeControls.call(this, true);\n\n // Clean up\n done();\n\n break;\n\n case 'youtube:video':\n // Clear timers\n window.clearInterval(this.timers.buffering);\n window.clearInterval(this.timers.playing);\n\n // Destroy YouTube API\n if (this.embed !== null) {\n this.embed.destroy();\n }\n\n // Clean up\n done();\n\n break;\n\n case 'vimeo:video':\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 window.setTimeout(done, 200);\n\n break;\n\n default:\n break;\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 utils.loadSprite(url, id);\n }\n}\n\nexport default Plyr;\n"]}
\ No newline at end of file +{"version":3,"sources":["src/js/types.js","src/js/support.js","src/js/defaults.js","src/js/utils.js","src/js/console.js","src/js/fullscreen.js","src/js/storage.js","src/js/plugins/ads.js","src/js/listeners.js","src/js/ui.js","src/js/controls.js","src/js/captions.js","src/js/plugins/youtube.js","src/js/plugins/vimeo.js","src/js/media.js","src/js/source.js","src/js/plyr.js"],"names":["range","providers","types","defaults","window","navigator","language","split","utils","input","this","instanceof","Plyr","getConstructor","Object","Number","isNaN","String","Boolean","Function","nullOrUndefined","Array","isArray","WeakMap","NodeList","Element","Text","Event","TextTrackCue","VTTCue","TextTrack","string","kind","test","array","nodeList","length","object","keys","constructor","document","documentMode","documentElement","style","userAgent","platform","url","responseType","arguments","undefined","Promise","resolve","reject","request","XMLHttpRequest","addEventListener","JSON","parse","responseText","e","response","Error","statusText","open","send","callback","error","current","querySelector","callbacks","push","element","createElement","errors","is","function","event","forEach","cb","call","err","src","first","getElementsByTagName","parentNode","insertBefore","id","hasId","querySelectorAll","container","toggleHidden","setAttribute","support","storage","cached","localStorage","getItem","data","content","fetch","then","result","empty","setItem","stringify","catch","updateSprite","innerHTML","body","childNodes","prefix","Math","floor","random","self","top","elements","wrapper","targets","from","reverse","index","child","cloneNode","parent","sibling","nextSibling","appendChild","type","attributes","text","setAttributes","textContent","target","removeElement","removeChild","lastChild","newChild","oldChild","replaceChild","key","sel","existingAttributes","existing","s","selector","trim","className","replace","parts","value","charAt","class","toggle","contains","classList","removeAttribute","prototype","matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","includes","controls","getElement","config","selectors","buttons","getElements","play","pause","restart","rewind","forward","mute","pip","airplay","settings","captions","fullscreen","progress","inputs","seek","volume","display","buffer","duration","currentTime","seekTooltip","classNames","tooltip","debug","warn","toggleNativeControls","focused","activeElement","focusable","last","trap","keyCode","getFocusElement","shiftKey","focus","preventDefault","on","off","passive","capture","Node","toggleListener","events","options","boolean","passiveListeners","bubbles","detail","CustomEvent","assign","plyr","dispatchEvent","toggleState","pressed","getAttribute","state","max","toFixed","parseInt","time","displayHours","inverted","number","formatTime","format","slice","hours","getHours","mins","getMinutes","secs","getSeconds","sources","_len","_key","source","shift","defineProperty","extend","apply","concat","toConsumableArray","youtube","vimeo","match","RegExp","$2","parser","href","search","startsWith","parseUrl","indexOf","reduce","params","hash","_hash$split2","val","decodeURIComponent","map","encodeURIComponent","join","fragment","createDocumentFragment","firstChild","innerText","width","height","ratio","getRatio","w","h","find","setTimeout","offsetHeight","provider","inline","api","ui","browser","getBrowser","playsInline","isIPhone","video","rangeInput","audio","webkitSetPresentationMode","WebKitPlaybackTargetAvailabilityEvent","media","isHTML5","canPlayType","isVideo","isAudio","supported","transitionEndEvent","matchMedia","noop","Console","enabled","console","log","bind","onChange","button","player","active","isIos","trapFocus","toggleFallback","scrollPosition","scrollX","scrollY","scrollTo","x","y","overflow","toggleClass","fallback","Fullscreen","_this","stopPropagation","update","native","iosNative","playing","webkitEnterFullscreen","requestFullScreen","webkitExitFullscreen","cancelFullScreen","exit","enter","inFrame","fullscreenElement","hasClass","fullscreenEnabled","webkitFullscreenEnabled","mozFullScreenEnabled","msFullscreenEnabled","some","pre","msExitFullscreen","Storage","store","json","get","removeItem","Ads","ads","initialized","blocked","tag","google","ready","loadScript","urls","googleIMA","manager","loader","cuePoints","safetyTimer","countdownTimer","listeners","startSafetyTimer","loaderPromise","managerPromise","clearSafetyTimer","setupIMA","ima","setVpaidMode","ImaSdkSettings","VpaidMode","ENABLED","setLocale","displayContainer","AdDisplayContainer","requestAds","AdsLoader","AdsManagerLoadedEvent","Type","ADS_MANAGER_LOADED","_this3","onAdsManagerLoaded","AdErrorEvent","AD_ERROR","onAdError","AdsRequest","adTagUrl","base","buildUrlParams","linearAdSlotWidth","offsetWidth","linearAdSlotHeight","nonLinearAdSlotWidth","nonLinearAdSlotHeight","forceNonLinearFullSlot","handleEventListeners","clearInterval","setInterval","_this4","getRemainingTime","label","i18n","advertisment","adsManagerLoadedEvent","AdsRenderingSettings","restoreCustomPlaybackStateOnAdBreakComplete","enablePreloading","getAdsManager","getCuePoints","cuePoint","seekElement","_this5","cuePercentage","cue","cues","left","toString","setVolume","AdEvent","onAdEvent","ad","getAd","_this6","LOADED","pollCountdown","isLinear","ALL_ADS_COMPLETED","loadAds","CONTENT_PAUSE_REQUESTED","pauseContent","CONTENT_RESUME_REQUESTED","resumeContent","STARTED","MIDPOINT","COMPLETE","IMPRESSION","CLICK","cancel","contentComplete","_this7","seekedTime","discardAdBreak","splice","resize","ViewMode","NORMAL","initialize","_this8","init","start","adError","_this9","destroy","handleKey","code","which","getKeyCode","repeat","altKey","ctrlKey","metaKey","editable","togglePlay","increaseVolume","decreaseVolume","muted","toggleCaptions","loop","keyboard","global","tabFocus","hideControls","toggleControls","timeUpdate","_this2","durationUpdate","hasAudio","showPosterOnEnd","load","updateProgress","updateVolume","checkPlaying","checkLoading","clickToPlay","touch","paused","ended","disableContextMenu","set","updateSetting","speed","quality","inputEvent","isIE","proxy","handlerKey","defaultHandler","customHandler","defaultPrevented","toggleMenu","form","parseFloat","showTab","toggleInvert","invertTime","isWebkit","updateRangeFill","updateSeekTooltip","hover","webkitDirectionInvertedFromDevice","direction","deltaY","deltaX","uiSupported","inject","setup","setTitle","title","isEmbed","iframe","frameTitle","stopped","loading","timers","failed","networkState","setRange","nodeValue","buffered","getPercentage","end","setProgress","invert","updateTimeDisplay","seeking","hasDuration","displayDuration","setProperty","iconUrl","svg4everybody","getIconUrl","iconPath","absolute","iconPrefix","icon","createElementNS","use","path","setAttributeNS","attr","hidden","badge","menu","buttonType","labelPressed","iconPressed","control","createIcon","createLabel","getAttributesFromSelector","suffix","played","toLowerCase","list","checked","item","radio","faux","aria-hidden","insertAdjacentHTML","tooltips","percent","clientRect","getBoundingClientRect","visible","pageX","setting","tab","tabs","pane","panes","filter","isYouTube","toggleTab","emptyElement","createMenuItem","getLabel","createBadge","getBadge","getLanguage","default","textTracks","getTracks","none","currentTrack","getCurrentTrack","track","disabled","hasTracks","tracks","toUpperCase","unshift","show","isMenuItem","isButton","clone","position","opacity","name","scrollWidth","scrollHeight","getElementById","transitions","reducedMotion","size","getTabSize","restore","propertyName","createButton","createRange","createProgress","createTime","inner","home","back","setSpeedMenu","loadSprite","seekTime","create","findElements","repaint","labels","stored","setCaptionsMenu","insertAfter","URL","hostname","location","protocol","blob","createObjectURL","setLanguage","setCue","mode","activeCues","isVimeo","embed","enableTextTrack","setText","getCueAsHTML","caption","setAspectRatio","YT","Player","onYouTubeReadyCallbacks","onYouTubeIframeAPIReady","videoId","getVideoData","items","snippet","paddingBottom","currentId","parseYouTubeId","generateId","replaceElement","autoplay","message","instance","getPlaybackQuality","playbackRate","getPlaybackRate","getTitle","playVideo","pauseVideo","stop","stopVideo","getDuration","getCurrentTime","seekTo","setPlaybackRate","setPlaybackQuality","getVideoUrl","getAvailablePlaybackRates","buffering","getVideoLoadedFraction","lastBuffered","build","setQualityMenu","getAvailableQualityLevels","Vimeo","padding","offset","transform","parseVimeoId","setCurrentTime","selected","setLoop","currentSrc","all","getVideoWidth","getVideoHeight","dimensions","getAspectRatio","setAutopause","autopause","getVideoTitle","getTextTracks","stripHTML","seconds","isTouch","wrap","blankVideo","insertElement","attribute","cancelRequests","html5","check","crossorigin","poster","addStyleHook","insertElements","jQuery","original","tagName","getProviderByUrl","getUrlParams","truthy","playsinline","hasAttribute","step","webkitShowPlaybackTargetPicker","delay","isEnterFullscreen","noTransition","clearTimeout","soft","done","unload","mime","readyState","targetTime","fauxDuration","realDuration","mozHasAudio","webkitAudioDecodedByteCount","audioTracks","change","states","webkitPresentationMode"],"mappings":"uLAIA,IC2IcA,ED3IDC,SACF,gBACE,gBACF,SAGEC,SACF,cACA,SERLC,YAEO,QAGF,UAGA,YAGG,aAGC,WAGD,UAGF,SACD,WAGG,sBAIO,cAGL,gBAGE,QAGP,oBAGM,gBAGC,mBAGG,sBAGG,cAGR,aACA,eACH,wDAGG,wDAIC,mBAEL,SACA,SACA,SACA,QACA,QACA,SACA,QACA,OACA,0BAMI,mBAOE,WAEN,GACA,IACA,EACA,KACA,IACA,KACA,uBAMK,UACD,uBAKE,QACJ,qBAKE,WACEC,OAAOC,UAAUC,SAASC,MAAM,KAAK,yBAKtC,YACC,aACC,qBAKF,MACJ,kBAKL,aACA,OACA,WACA,eACA,OACA,SACA,WACA,WACA,MACA,UACA,wBAGA,WACA,UACA,uBAKS,iBACD,8BACF,aACC,gBACE,+BACH,cACE,kBACE,uBACG,wBACH,kBACF,cACF,cACE,wBACQ,kCACC,mCACA,kCACD,6BACJ,8BACF,oBACA,iBACH,gBACE,eACH,aACC,YACF,UACA,YACE,aACD,gBACI,wBACI,uBAML,uDAGA,qDAGA,uEAMH,UACA,WACC,aACE,YACD,aACC,UACH,YACE,cACE,gBACE,SACP,aACI,WACF,aACE,UACH,cACI,sBAQV,WACA,UACA,UACA,UACA,UACA,iBACA,YACA,aACA,iBACA,aACA,eACA,OACA,QACA,QACA,UACA,SACA,UACA,aACA,8BAIA,iBACA,kBACA,mBACA,iBACA,iBACA,gBACA,sBAIA,gBACA,+BAIA,kBACA,kBACA,YACA,cACA,cACA,iBACA,gBACA,gCAMU,uDACC,4BAEI,aACF,0BAEL,4BAEE,2BACC,8BACE,+BACD,+BACC,kCACH,8BACI,oCACE,+BACP,4BACI,iCACC,8BACJ,mCAGA,4BACE,6BACD,+BACG,iCACD,8CAGI,gCACH,+BACF,iCACA,+BACF,+BACE,mCAEF,2BACA,gCAEG,oDAMN,4BACA,wBACF,oBACI,qBACH,qBACI,oBACD,wBACA,wBACA,sBACF,wBACA,sBACE,qBACH,oBACE,6BACM,4BACP,uBACE,6BACI,6BACC,kC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","file":"plyr.min.js","sourcesContent":["// ==========================================================================\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\nexport default { providers, types };\n","// ==========================================================================\n// Plyr support checks\n// ==========================================================================\n\nimport utils from './utils';\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, inline) {\n let api = false;\n let ui = false;\n const browser = utils.getBrowser();\n const playsInline = browser.isIPhone && inline && support.inline;\n\n switch (`${provider}:${type}`) {\n case 'html5:video':\n api = support.video;\n ui = api && support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'html5:audio':\n api = support.audio;\n ui = api && support.rangeInput;\n break;\n\n case 'youtube:video':\n api = true;\n ui = support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'vimeo:video':\n api = true;\n ui = support.rangeInput && !browser.isIPhone;\n break;\n\n default:\n api = support.audio && support.video;\n ui = api && support.rangeInput;\n }\n\n return {\n api,\n ui,\n };\n },\n\n // Picture-in-picture support\n // Safari only currently\n pip: (() => {\n const browser = utils.getBrowser();\n return !browser.isIPhone && utils.is.function(utils.createElement('video').webkitSetPresentationMode);\n })(),\n\n // Airplay support\n // Safari only currently\n airplay: utils.is.function(window.WebKitPlaybackTargetAvailabilityEvent),\n\n // Inline playback support\n // https://webkit.org/blog/6784/new-video-policies-for-ios/\n inline: '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(type) {\n const { media } = this;\n\n try {\n // Bail if no checking function\n if (!this.isHTML5 || !utils.is.function(media.canPlayType)) {\n return false;\n }\n\n // Type specific checks\n if (this.isVideo) {\n switch (type) {\n case 'video/webm':\n return media.canPlayType('video/webm; codecs=\"vp8, vorbis\"').replace(/no/, '');\n\n case 'video/mp4':\n return media.canPlayType('video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"').replace(/no/, '');\n\n case 'video/ogg':\n return media.canPlayType('video/ogg; codecs=\"theora\"').replace(/no/, '');\n\n default:\n return false;\n }\n } else if (this.isAudio) {\n switch (type) {\n case 'audio/mpeg':\n return media.canPlayType('audio/mpeg;').replace(/no/, '');\n\n case 'audio/ogg':\n return media.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/no/, '');\n\n case 'audio/wav':\n return media.canPlayType('audio/wav; codecs=\"1\"').replace(/no/, '');\n\n default:\n return false;\n }\n }\n } catch (e) {\n return false;\n }\n\n // If we got this far, we're stuffed\n return false;\n },\n\n // Check for textTracks support\n textTracks: 'textTracks' in document.createElement('video'),\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\n passiveListeners: (() => {\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 } catch (e) {\n // Do nothing\n }\n\n return supported;\n })(),\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 // Remember a device can be moust + touch enabled\n touch: 'ontouchstart' in document.documentElement,\n\n // Detect transitions support\n transitions: utils.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 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 // 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 // Revert to poster on finish (HTML5 - will cause reload)\n showPosterOnEnd: 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.0.0-beta.14/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: 'default',\n options: [\n 'hd2160',\n 'hd1440',\n 'hd1080',\n 'hd720',\n 'large',\n 'medium',\n 'small',\n 'tiny',\n 'default',\n ],\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: [\n 0.5,\n 0.75,\n 1,\n 1.25,\n 1.5,\n 1.75,\n 2,\n ],\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: window.navigator.language.split('-')[0],\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 'play',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'pip',\n 'airplay',\n 'fullscreen',\n ],\n settings: [\n 'captions',\n 'quality',\n 'speed',\n ],\n\n // Localisation\n i18n: {\n restart: 'Restart',\n rewind: 'Rewind {seektime} secs',\n play: 'Play',\n pause: 'Pause',\n forward: 'Forward {seektime} secs',\n seek: 'Seek',\n played: 'Played',\n buffered: 'Buffered',\n currentTime: 'Current time',\n duration: 'Duration',\n volume: 'Volume',\n mute: 'Mute',\n unmute: 'Unmute',\n enableCaptions: 'Enable captions',\n disableCaptions: 'Disable captions',\n enterFullscreen: 'Enter fullscreen',\n exitFullscreen: 'Exit fullscreen',\n frameTitle: 'Player for {title}',\n captions: 'Captions',\n settings: 'Settings',\n speed: 'Speed',\n quality: 'Quality',\n loop: 'Loop',\n start: 'Start',\n end: 'End',\n all: 'All',\n reset: 'Reset',\n none: 'None',\n disabled: 'Disabled',\n advertisment: 'Ad',\n },\n\n // URLs\n urls: {\n vimeo: {\n api: 'https://player.vimeo.com/api/player.js',\n },\n youtube: {\n api: 'https://www.youtube.com/iframe_api',\n },\n googleIMA: {\n api: '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 forward: null,\n mute: null,\n volume: null,\n captions: null,\n fullscreen: null,\n pip: null,\n airplay: null,\n speed: null,\n quality: null,\n loop: null,\n language: null,\n },\n\n // Events to watch and bubble\n events: [\n // Events to watch on HTML5 media elements and bubble\n // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events\n 'ended',\n 'progress',\n 'stalled',\n 'playing',\n 'waiting',\n 'canplay',\n 'canplaythrough',\n 'loadstart',\n 'loadeddata',\n 'loadedmetadata',\n 'timeupdate',\n 'volumechange',\n 'play',\n 'pause',\n 'error',\n 'seeking',\n 'seeked',\n 'emptied',\n 'ratechange',\n 'cuechange',\n\n // Custom events\n 'enterfullscreen',\n 'exitfullscreen',\n 'captionsenabled',\n 'captionsdisabled',\n 'languagechange',\n 'controlshidden',\n 'controlsshown',\n 'ready',\n\n // YouTube\n 'statechange',\n 'qualitychange',\n 'qualityrequested',\n\n // Ads\n 'adsloaded',\n 'adscontentpause',\n 'adsconentresume',\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 forward: '[data-plyr=\"fast-forward\"]',\n mute: '[data-plyr=\"mute\"]',\n captions: '[data-plyr=\"captions\"]',\n fullscreen: '[data-plyr=\"fullscreen\"]',\n pip: '[data-plyr=\"pip\"]',\n airplay: '[data-plyr=\"airplay\"]',\n settings: '[data-plyr=\"settings\"]',\n loop: '[data-plyr=\"loop\"]',\n },\n inputs: {\n seek: '[data-plyr=\"seek\"]',\n volume: '[data-plyr=\"volume\"]',\n speed: '[data-plyr=\"speed\"]',\n language: '[data-plyr=\"language\"]',\n quality: '[data-plyr=\"quality\"]',\n },\n display: {\n currentTime: '.plyr__time--current',\n duration: '.plyr__time--duration',\n buffer: '.plyr__progress--buffer',\n played: '.plyr__progress--played',\n loop: '.plyr__progress--loop',\n volume: '.plyr__volume--display',\n },\n progress: '.plyr__progress',\n captions: '.plyr__captions',\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 video: 'plyr__video-wrapper',\n embed: 'plyr__video-embed',\n ads: 'plyr__ads',\n control: 'plyr__control',\n type: 'plyr--{0}',\n provider: 'plyr--{0}',\n stopped: 'plyr--stopped',\n playing: 'plyr--playing',\n loading: 'plyr--loading',\n error: 'plyr--has-error',\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 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 // Tag is not required as publisher is determined by vi.ai using the domain\n ads: {\n enabled: false,\n },\n};\n\nexport default defaults;\n","// ==========================================================================\n// Plyr utils\n// ==========================================================================\n\nimport support from './support';\nimport { providers } from './types';\n\nconst utils = {\n // Check variable types\n is: {\n plyr(input) {\n return this.instanceof(input, window.Plyr);\n },\n object(input) {\n return this.getConstructor(input) === Object;\n },\n number(input) {\n return this.getConstructor(input) === Number && !Number.isNaN(input);\n },\n string(input) {\n return this.getConstructor(input) === String;\n },\n boolean(input) {\n return this.getConstructor(input) === Boolean;\n },\n function(input) {\n return this.getConstructor(input) === Function;\n },\n array(input) {\n return !this.nullOrUndefined(input) && Array.isArray(input);\n },\n weakMap(input) {\n return this.instanceof(input, window.WeakMap);\n },\n nodeList(input) {\n return this.instanceof(input, window.NodeList);\n },\n element(input) {\n return this.instanceof(input, window.Element);\n },\n textNode(input) {\n return this.getConstructor(input) === Text;\n },\n event(input) {\n return this.instanceof(input, window.Event);\n },\n cue(input) {\n return this.instanceof(input, window.TextTrackCue) || this.instanceof(input, window.VTTCue);\n },\n track(input) {\n return this.instanceof(input, TextTrack) || (!this.nullOrUndefined(input) && this.string(input.kind));\n },\n url(input) {\n return !this.nullOrUndefined(input) && /(ftp|http|https):\\/\\/(\\w+:{0,1}\\w*@)?(\\S+)(:[0-9]+)?(\\/|\\/([\\w#!:.?+=&%@!\\-/]))?/.test(input);\n },\n nullOrUndefined(input) {\n return input === null || typeof input === 'undefined';\n },\n empty(input) {\n return (\n this.nullOrUndefined(input) ||\n ((this.string(input) || this.array(input) || this.nodeList(input)) && !input.length) ||\n (this.object(input) && !Object.keys(input).length)\n );\n },\n instanceof(input, constructor) {\n return Boolean(input && constructor && input instanceof constructor);\n },\n getConstructor(input) {\n return !this.nullOrUndefined(input) ? input.constructor : null;\n },\n },\n\n // Unfortunately, due to mixed support, UA sniffing is required\n getBrowser() {\n return {\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 },\n\n // Fetch wrapper\n // Using XHR to avoid issues with older browsers\n 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 }\n else {\n resolve(request.response);\n }\n });\n\n request.addEventListener('error', () => {\n throw new Error(request.statusText);\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 // Load an external script\n loadScript(url, callback, error) {\n const current = document.querySelector(`script[src=\"${url}\"]`);\n\n // Check script is not already referenced, if so wait for load\n if (current !== null) {\n current.callbacks = current.callbacks || [];\n current.callbacks.push(callback);\n return;\n }\n\n // Build the element\n const element = document.createElement('script');\n\n // Callback queue\n element.callbacks = element.callbacks || [];\n element.callbacks.push(callback);\n\n // Error queue\n element.errors = element.errors || [];\n element.errors.push(error);\n\n // Bind callback\n if (utils.is.function(callback)) {\n element.addEventListener(\n 'load',\n event => {\n element.callbacks.forEach(cb => cb.call(null, event));\n element.callbacks = null;\n },\n false,\n );\n }\n\n // Bind error handling\n element.addEventListener(\n 'error',\n event => {\n element.errors.forEach(err => err.call(null, event));\n element.errors = null;\n },\n false,\n );\n\n // Set the URL after binding callback\n element.src = url;\n\n // Inject\n const first = document.getElementsByTagName('script')[0];\n first.parentNode.insertBefore(element, first);\n },\n\n // Load an external SVG sprite\n loadSprite(url, id) {\n if (!utils.is.string(url)) {\n return;\n }\n\n const prefix = 'cache-';\n const hasId = utils.is.string(id);\n let isCached = false;\n\n function updateSprite(data) {\n // Inject content\n this.innerHTML = data;\n\n // Inject the SVG to the body\n document.body.insertBefore(this, document.body.childNodes[0]);\n }\n\n // Only load once\n if (!hasId || !document.querySelectorAll(`#${id}`).length) {\n // Create container\n const container = document.createElement('div');\n utils.toggleHidden(container, true);\n\n if (hasId) {\n container.setAttribute('id', id);\n }\n\n // Check in cache\n if (support.storage) {\n const cached = window.localStorage.getItem(prefix + id);\n isCached = cached !== null;\n\n if (isCached) {\n const data = JSON.parse(cached);\n updateSprite.call(container, data.content);\n return;\n }\n }\n\n // Get the sprite\n utils\n .fetch(url)\n .then(result => {\n if (utils.is.empty(result)) {\n return;\n }\n\n if (support.storage) {\n window.localStorage.setItem(\n prefix + id,\n JSON.stringify({\n content: result,\n }),\n );\n }\n\n updateSprite.call(container, result);\n })\n .catch(() => {});\n }\n },\n\n // Generate a random ID\n generateId(prefix) {\n return `${prefix}-${Math.floor(Math.random() * 10000)}`;\n },\n\n // Determine if we're in an iframe\n inFrame() {\n try {\n return window.self !== window.top;\n } catch (e) {\n return true;\n }\n },\n\n // Wrap an element\n 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 // Create a DocumentFragment\n createElement(type, attributes, text) {\n // Create a new <element>\n const element = document.createElement(type);\n\n // Set all passed attributes\n if (utils.is.object(attributes)) {\n utils.setAttributes(element, attributes);\n }\n\n // Add text node\n if (utils.is.string(text)) {\n element.textContent = text;\n }\n\n // Return built element\n return element;\n },\n\n // Inaert an element after another\n insertAfter(element, target) {\n target.parentNode.insertBefore(element, target.nextSibling);\n },\n\n // Insert a DocumentFragment\n insertElement(type, parent, attributes, text) {\n // Inject the new <element>\n parent.appendChild(utils.createElement(type, attributes, text));\n },\n\n // Remove an element\n removeElement(element) {\n if (!utils.is.element(element) || !utils.is.element(element.parentNode)) {\n return;\n }\n\n if (utils.is.nodeList(element) || utils.is.array(element)) {\n Array.from(element).forEach(utils.removeElement);\n return;\n }\n\n element.parentNode.removeChild(element);\n },\n\n // Remove all child elements\n emptyElement(element) {\n let { length } = element.childNodes;\n\n while (length > 0) {\n element.removeChild(element.lastChild);\n length -= 1;\n }\n },\n\n // Replace element\n replaceElement(newChild, oldChild) {\n if (!utils.is.element(oldChild) || !utils.is.element(oldChild.parentNode) || !utils.is.element(newChild)) {\n return null;\n }\n\n oldChild.parentNode.replaceChild(newChild, oldChild);\n\n return newChild;\n },\n\n // Set attributes\n setAttributes(element, attributes) {\n if (!utils.is.element(element) || utils.is.empty(attributes)) {\n return;\n }\n\n Object.keys(attributes).forEach(key => {\n element.setAttribute(key, attributes[key]);\n });\n },\n\n // Get an attribute object from a string selector\n 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 (!utils.is.string(sel) || utils.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 (utils.is.object(existing) && utils.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 class on an element\n toggleClass(element, className, toggle) {\n if (utils.is.element(element)) {\n const contains = element.classList.contains(className);\n\n element.classList[toggle ? 'add' : 'remove'](className);\n\n return (toggle && !contains) || (!toggle && contains);\n }\n\n return null;\n },\n\n // Has class name\n hasClass(element, className) {\n return utils.is.element(element) && element.classList.contains(className);\n },\n\n // Toggle hidden attribute on an element\n toggleHidden(element, toggle) {\n if (!utils.is.element(element)) {\n return;\n }\n\n if (toggle) {\n element.setAttribute('hidden', '');\n } else {\n element.removeAttribute('hidden');\n }\n },\n\n // Element matches selector\n 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 = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;\n\n return matches.call(element, selector);\n },\n\n // Find all elements\n getElements(selector) {\n return this.elements.container.querySelectorAll(selector);\n },\n\n // Find a single element\n getElement(selector) {\n return this.elements.container.querySelector(selector);\n },\n\n // Find the UI controls and store references in custom controls\n // TODO: Allow settings menus with custom controls\n findElements() {\n try {\n this.elements.controls = utils.getElement.call(this, this.config.selectors.controls.wrapper);\n\n // Buttons\n this.elements.buttons = {\n play: utils.getElements.call(this, this.config.selectors.buttons.play),\n pause: utils.getElement.call(this, this.config.selectors.buttons.pause),\n restart: utils.getElement.call(this, this.config.selectors.buttons.restart),\n rewind: utils.getElement.call(this, this.config.selectors.buttons.rewind),\n forward: utils.getElement.call(this, this.config.selectors.buttons.forward),\n mute: utils.getElement.call(this, this.config.selectors.buttons.mute),\n pip: utils.getElement.call(this, this.config.selectors.buttons.pip),\n airplay: utils.getElement.call(this, this.config.selectors.buttons.airplay),\n settings: utils.getElement.call(this, this.config.selectors.buttons.settings),\n captions: utils.getElement.call(this, this.config.selectors.buttons.captions),\n fullscreen: utils.getElement.call(this, this.config.selectors.buttons.fullscreen),\n };\n\n // Progress\n this.elements.progress = utils.getElement.call(this, this.config.selectors.progress);\n\n // Inputs\n this.elements.inputs = {\n seek: utils.getElement.call(this, this.config.selectors.inputs.seek),\n volume: utils.getElement.call(this, this.config.selectors.inputs.volume),\n };\n\n // Display\n this.elements.display = {\n buffer: utils.getElement.call(this, this.config.selectors.display.buffer),\n duration: utils.getElement.call(this, this.config.selectors.display.duration),\n currentTime: utils.getElement.call(this, this.config.selectors.display.currentTime),\n };\n\n // Seek tooltip\n if (utils.is.element(this.elements.progress)) {\n this.elements.display.seekTooltip = this.elements.progress.querySelector(`.${this.config.classNames.tooltip}`);\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 // Get the focused element\n getFocusElement() {\n let focused = document.activeElement;\n\n if (!focused || focused === document.body) {\n focused = null;\n } else {\n focused = document.querySelector(':focus');\n }\n\n return focused;\n },\n\n // Trap focus inside container\n trapFocus(element = null, toggle = false) {\n if (!utils.is.element(element)) {\n return;\n }\n\n const focusable = utils.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 = utils.getFocusElement();\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 if (toggle) {\n utils.on(this.elements.container, 'keydown', trap, false);\n } else {\n utils.off(this.elements.container, 'keydown', trap, false);\n }\n },\n\n // Toggle event listener\n toggleListener(elements, event, callback, toggle, passive, capture) {\n // Bail if no elemetns, event, or callback\n if (utils.is.empty(elements) || utils.is.empty(event) || !utils.is.function(callback)) {\n return;\n }\n\n // If a nodelist is passed, call itself on each node\n if (utils.is.nodeList(elements) || utils.is.array(elements)) {\n // Create listener for each node\n Array.from(elements).forEach(element => {\n if (element instanceof Node) {\n utils.toggleListener.call(null, element, event, callback, toggle, passive, capture);\n }\n });\n\n return;\n }\n\n // Allow multiple events\n const events = event.split(' ');\n\n // Build options\n // Default to just capture boolean\n let options = utils.is.boolean(capture) ? capture : false;\n\n // If passive events listeners are supported\n if (support.passiveListeners) {\n options = {\n // Whether the listener can be passive (i.e. default never prevented)\n passive: utils.is.boolean(passive) ? passive : true,\n // Whether the listener is a capturing listener or not\n capture: utils.is.boolean(capture) ? capture : false,\n };\n }\n\n // If a single node is passed, bind the event listener\n events.forEach(type => {\n elements[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);\n });\n },\n\n // Bind event handler\n on(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, true, passive, capture);\n },\n\n // Unbind event handler\n off(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, false, passive, capture);\n },\n\n // Trigger event\n dispatchEvent(element, type, bubbles, detail) {\n // Bail if no element\n if (!utils.is.element(element) || !utils.is.string(type)) {\n return;\n }\n\n // Create and dispatch the event\n const event = new CustomEvent(type, {\n bubbles: utils.is.boolean(bubbles) ? bubbles : false,\n detail: Object.assign({}, detail, {\n plyr: utils.is.plyr(this) ? this : null,\n }),\n });\n\n // Dispatch the event\n element.dispatchEvent(event);\n },\n\n // Toggle aria-pressed state on a toggle button\n // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles\n toggleState(element, input) {\n // If multiple elements passed\n if (utils.is.array(element) || utils.is.nodeList(element)) {\n Array.from(element).forEach(target => utils.toggleState(target, input));\n return;\n }\n\n // Bail if no target\n if (!utils.is.element(element)) {\n return;\n }\n\n // Get state\n const pressed = element.getAttribute('aria-pressed') === 'true';\n const state = utils.is.boolean(input) ? input : !pressed;\n\n // Set the attribute on target\n element.setAttribute('aria-pressed', state);\n },\n\n // Get percentage\n getPercentage(current, max) {\n if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {\n return 0;\n }\n return (current / max * 100).toFixed(2);\n },\n\n // Time helpers\n getHours(value) {\n return parseInt((value / 60 / 60) % 60, 10);\n },\n getMinutes(value) {\n return parseInt((value / 60) % 60, 10);\n },\n getSeconds(value) {\n return parseInt(value % 60, 10);\n },\n\n // Format time to UI friendly string\n formatTime(time = 0, displayHours = false, inverted = false) {\n // Bail if the value isn't a number\n if (!utils.is.number(time)) {\n return this.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 = this.getHours(time);\n const mins = this.getMinutes(time);\n const secs = this.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 ? '-' : ''}${hours}${format(mins)}:${format(secs)}`;\n },\n\n // Deep extend destination object with N more objects\n extend(target = {}, ...sources) {\n if (!sources.length) {\n return target;\n }\n\n const source = sources.shift();\n\n if (!utils.is.object(source)) {\n return target;\n }\n\n Object.keys(source).forEach(key => {\n if (utils.is.object(source[key])) {\n if (!Object.keys(target).includes(key)) {\n Object.assign(target, { [key]: {} });\n }\n\n utils.extend(target[key], source[key]);\n } else {\n Object.assign(target, { [key]: source[key] });\n }\n });\n\n return utils.extend(target, ...sources);\n },\n\n // Get the provider for a given URL\n 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{8,}(?=\\b|\\/)/.test(url)) {\n return providers.vimeo;\n }\n\n return null;\n },\n\n // Parse YouTube ID from URL\n parseYouTubeId(url) {\n if (utils.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 // Parse Vimeo ID from URL\n parseVimeoId(url) {\n if (utils.is.empty(url)) {\n return null;\n }\n\n if (utils.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 // Convert a URL to a location object\n parseUrl(url) {\n const parser = document.createElement('a');\n parser.href = url;\n return parser;\n },\n\n // Get URL query parameters\n getUrlParams(input) {\n let search = input;\n\n // Parse URL if needed\n if (input.startsWith('http://') || input.startsWith('https://')) {\n ({ search } = this.parseUrl(input));\n }\n\n if (this.is.empty(search)) {\n return null;\n }\n\n const hashes = search.slice(search.indexOf('?') + 1).split('&');\n\n return hashes.reduce((params, hash) => {\n const [\n key,\n val,\n ] = hash.split('=');\n\n return Object.assign(params, { [key]: decodeURIComponent(val) });\n }, {});\n },\n\n // Convert object to URL parameters\n buildUrlParams(input) {\n if (!utils.is.object(input)) {\n return '';\n }\n\n return Object.keys(input)\n .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(input[key])}`)\n .join('&');\n },\n\n // Remove HTML from a string\n 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 // Get aspect ratio for dimensions\n 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 // Get the transition end event\n get 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 utils.is.string(type) ? events[type] : false;\n },\n\n // Force repaint of element\n repaint(element) {\n window.setTimeout(() => {\n utils.toggleHidden(element, true);\n element.offsetHeight; // eslint-disable-line\n utils.toggleHidden(element, false);\n }, 0);\n },\n};\n\nexport default utils;\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 get warn() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.warn, console) : noop;\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// ==========================================================================\n\nimport utils from './utils';\n\nconst browser = utils.getBrowser();\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 (utils.is.element(button)) {\n utils.toggleState(button, this.active);\n }\n\n // Trigger an event\n utils.dispatchEvent(this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);\n\n // Trap focus in container\n if (!browser.isIos) {\n utils.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 utils.toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle);\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\n // Scroll position\n this.scrollPosition = { x: 0, y: 0 };\n\n // Register event listeners\n // Handle event (incase user presses escape etc)\n utils.on(document, this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`, () => {\n // TODO: Filter for target??\n onChange.call(this);\n });\n\n // Fullscreen toggle on double click\n utils.on(this.player.elements.container, 'dblclick', () => {\n this.toggle();\n });\n\n // Prevent double click on controls bubbling up\n utils.on(this.player.elements.controls, 'dblclick', event => event.stopPropagation());\n\n // Update the UI\n this.update();\n }\n\n // Determine if native supported\n static get native() {\n return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled);\n }\n\n // Get the prefix for handlers\n static get prefix() {\n // No prefix\n if (utils.is.function(document.cancelFullScreen)) {\n return false;\n }\n\n // Check for fullscreen support by vendor prefix\n let value = '';\n const prefixes = [\n 'webkit',\n 'moz',\n 'ms',\n ];\n\n prefixes.some(pre => {\n if (utils.is.function(document[`${pre}CancelFullScreen`])) {\n value = pre;\n return true;\n } else if (utils.is.function(document.msExitFullscreen)) {\n value = 'ms';\n return true;\n }\n\n return false;\n });\n\n return value;\n }\n\n // Determine if fullscreen is enabled\n get enabled() {\n const fallback = this.player.config.fullscreen.fallback && !utils.inFrame();\n\n return (Fullscreen.native || fallback) && this.player.config.fullscreen.enabled && this.player.supported.ui && this.player.isVideo;\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 utils.hasClass(this.target, this.player.config.classNames.fullscreen.fallback);\n }\n\n const element = !this.prefix ? document.fullscreenElement : document[`${this.prefix}FullscreenElement`];\n\n return element === this.target;\n }\n\n // Get target element\n get target() {\n return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : 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 utils.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 if (this.player.playing) {\n this.target.webkitEnterFullscreen();\n }\n } else if (!Fullscreen.native) {\n toggleFallback.call(this, true);\n } else if (!this.prefix) {\n this.target.requestFullScreen();\n } else if (!utils.is.empty(this.prefix)) {\n this.target[`${this.prefix}${this.prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen'}`]();\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();\n } else if (!utils.is.empty(this.prefix)) {\n document[`${this.prefix}${this.prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen'}`]();\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// Plyr storage\n// ==========================================================================\n\nimport utils from './utils';\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 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 try {\n window.localStorage.setItem(test, test);\n window.localStorage.removeItem(test);\n return true;\n } catch (e) {\n return false;\n }\n }\n\n get(key) {\n const store = window.localStorage.getItem(this.key);\n\n if (!Storage.supported || utils.is.empty(store)) {\n return null;\n }\n\n const json = JSON.parse(store);\n\n return utils.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 (!utils.is.object(object)) {\n return;\n }\n\n // Get current storage\n let storage = this.get();\n\n // Default to empty object\n if (utils.is.empty(storage)) {\n storage = {};\n }\n\n // Update the working copy of the values\n utils.extend(storage, object);\n\n // Update storage\n window.localStorage.setItem(this.key, JSON.stringify(storage));\n }\n}\n\nexport default Storage;\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 utils from '../utils';\n\n// Build the default tag URL\nconst getTagUrl = () => {\n const params = {\n AV_PUBLISHERID: '58c25bb0073ef448b1087ad6',\n AV_CHANNELID: '5a0458dc28a06145e4519d21',\n AV_URL: '127.0.0.1:3000',\n cb: 1,\n AV_WIDTH: 640,\n AV_HEIGHT: 480,\n };\n\n const base = 'https://go.aniview.com/api/adserver6/vast/';\n\n return `${base}?${utils.buildUrlParams(params)}`;\n};\n\nclass Ads {\n /**\n * Ads constructor.\n * @param {object} player\n * @return {Ads}\n */\n constructor(player) {\n this.player = player;\n this.enabled = player.config.ads.enabled;\n this.playing = false;\n this.initialized = false;\n this.blocked = false;\n this.enabled = utils.is.url(player.config.ads.tag);\n\n // Check if a tag URL is provided.\n if (!this.enabled) {\n return;\n }\n\n // Check if the Google IMA3 SDK is loaded or load it ourselves\n if (!utils.is.object(window.google)) {\n utils.loadScript(\n player.config.urls.googleIMA.api,\n () => {\n this.ready();\n },\n () => {\n // Script failed to load or is blocked\n this.blocked = true;\n this.player.debug.log('Ads error: Google IMA SDK failed to load');\n },\n );\n } else {\n this.ready();\n }\n }\n\n /**\n * Get the ads instance ready.\n */\n ready() {\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 // Set listeners on the Plyr instance\n this.listeners();\n\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 // Setup a simple promise to resolve if the IMA loader is ready\n this.loaderPromise = new Promise(resolve => {\n this.on('ADS_LOADER_LOADED', () => resolve());\n });\n\n // Setup a promise to resolve if the IMA manager is ready\n this.managerPromise = new Promise(resolve => {\n this.on('ADS_MANAGER_LOADED', () => resolve());\n });\n\n // Clear the safety timer\n this.managerPromise.then(() => {\n this.clearSafetyTimer('onAdsManagerLoaded()');\n });\n\n // Setup the IMA SDK\n this.setupIMA();\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 = utils.createElement('div', {\n class: this.player.config.classNames.ads,\n hidden: '',\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(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, event => this.onAdsManagerLoaded(event), false);\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 = getTagUrl();\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 this.loader.requestAds(request);\n\n this.handleEventListeners('ADS_LOADER_LOADED');\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 window.clearInterval(this.countdownTimer);\n this.elements.container.removeAttribute('data-badge-text');\n return;\n }\n\n const update = () => {\n const time = utils.formatTime(this.manager.getRemainingTime());\n const label = `${this.player.config.i18n.advertisment} - ${time}`;\n this.elements.container.setAttribute('data-badge-text', label);\n };\n\n this.countdownTimer = window.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(adsManagerLoadedEvent) {\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 = adsManagerLoadedEvent.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 this.cuePoints.forEach(cuePoint => {\n if (cuePoint !== 0 && cuePoint !== -1) {\n const seekElement = this.player.elements.progress;\n\n if (seekElement) {\n const cuePercentage = 100 / this.player.duration * cuePoint;\n const cue = utils.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 // Get skippable state\n // TODO: Skip button\n // this.manager.getAdSkippableState();\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.handleEventListeners('ADS_MANAGER_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 utils.dispatchEvent.call(this.player, this.player.media, `ads${type}`);\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.handleEventListeners('LOADED');\n\n // Bubble event\n dispatchEvent('loaded');\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 this.handleEventListeners('ALL_ADS_COMPLETED');\n\n // Fire event\n dispatchEvent('allcomplete');\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 this.handleEventListeners('CONTENT_PAUSE_REQUESTED');\n\n dispatchEvent('contentpause');\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 this.handleEventListeners('CONTENT_RESUME_REQUESTED');\n\n dispatchEvent('contentresume');\n\n this.pollCountdown();\n\n this.resumeContent();\n\n break;\n\n case google.ima.AdEvent.Type.STARTED:\n dispatchEvent('started');\n break;\n\n case google.ima.AdEvent.Type.MIDPOINT:\n dispatchEvent('midpoint');\n break;\n\n case google.ima.AdEvent.Type.COMPLETE:\n dispatchEvent('complete');\n break;\n\n case google.ima.AdEvent.Type.IMPRESSION:\n dispatchEvent('impression');\n break;\n\n case google.ima.AdEvent.Type.CLICK:\n dispatchEvent('click');\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.log('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 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 this.manager.resize(container.offsetWidth, container.offsetHeight, google.ima.ViewMode.NORMAL);\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 return;\n }\n\n // Play the requested advertisement whenever the adsManager is ready\n this.managerPromise.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 }\n\n /**\n * Resume our video.\n */\n resumeContent() {\n // Hide our ad container\n utils.toggleHidden(this.elements.container, true);\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 our ad container.\n utils.toggleHidden(this.elements.container, false);\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.handleEventListeners('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.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('ADS_MANAGER_LOADED', () => resolve());\n this.player.debug.log(this.manager);\n });\n\n // Now request some new advertisements\n this.requestAds();\n });\n }\n\n /**\n * Handles callbacks after an ad event was invoked\n * @param {string} event - Event type\n */\n handleEventListeners(event) {\n if (utils.is.function(this.events[event])) {\n this.events[event].call(this);\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 this.events[event] = callback;\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 = window.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 (!utils.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 Event Listeners\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst listeners = {\n // Global listeners\n global() {\n let last = null;\n\n // Get the key code for an event\n const getKeyCode = event => (event.keyCode ? event.keyCode : event.which);\n\n // Handle key press\n const handleKey = event => {\n const code = getKeyCode(event);\n const pressed = event.type === 'keydown';\n const repeat = pressed && code === last;\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 (!utils.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 this.currentTime = this.duration / 10 * (code - 48);\n };\n\n // Handle the key on keydown\n // Reset on keyup\n if (pressed) {\n // Which keycodes should we prevent default\n const preventDefault = [\n 48,\n 49,\n 50,\n 51,\n 52,\n 53,\n 54,\n 56,\n 57,\n 32,\n 75,\n 38,\n 40,\n 77,\n 39,\n 37,\n 70,\n 67,\n 73,\n 76,\n 79,\n ];\n\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 = utils.getFocusElement();\n if (utils.is.element(focused) && utils.matches(focused, this.config.selectors.editable)) {\n return;\n }\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 this.togglePlay();\n }\n break;\n\n case 38:\n // Arrow up\n this.increaseVolume(0.1);\n break;\n\n case 40:\n // Arrow down\n this.decreaseVolume(0.1);\n break;\n\n case 77:\n // M key\n if (!repeat) {\n this.muted = !this.muted;\n }\n break;\n\n case 39:\n // Arrow forward\n this.forward();\n break;\n\n case 37:\n // Arrow back\n this.rewind();\n break;\n\n case 70:\n // F key\n this.fullscreen.toggle();\n break;\n\n case 67:\n // C key\n if (!repeat) {\n this.toggleCaptions();\n }\n break;\n\n case 76:\n // L key\n this.loop = !this.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 (!this.fullscreen.enabled && this.fullscreen.active && code === 27) {\n this.fullscreen.toggle();\n }\n\n // Store last code for next cycle\n last = code;\n } else {\n last = null;\n }\n };\n\n // Keyboard shortcuts\n if (this.config.keyboard.global) {\n utils.on(window, 'keydown keyup', handleKey, false);\n } else if (this.config.keyboard.focused) {\n utils.on(this.elements.container, 'keydown keyup', handleKey, false);\n }\n\n // Detect tab focus\n // Remove class on blur/focusout\n utils.on(this.elements.container, 'focusout', event => {\n utils.toggleClass(event.target, this.config.classNames.tabFocus, false);\n });\n\n // Add classname to tabbed elements\n utils.on(this.elements.container, 'keydown', event => {\n if (event.keyCode !== 9) {\n return;\n }\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n window.setTimeout(() => {\n utils.toggleClass(utils.getFocusElement(), this.config.classNames.tabFocus, true);\n }, 0);\n });\n\n // Toggle controls visibility based on mouse movement\n if (this.config.hideControls) {\n // Toggle controls on mouse events and entering fullscreen\n utils.on(this.elements.container, 'mouseenter mouseleave mousemove touchstart touchend touchmove enterfullscreen exitfullscreen', event => {\n this.toggleControls(event);\n });\n }\n },\n\n // Listen for media events\n media() {\n // Time change on media\n utils.on(this.media, 'timeupdate seeking', event => ui.timeUpdate.call(this, event));\n\n // Display duration\n utils.on(this.media, 'durationchange loadedmetadata', event => ui.durationUpdate.call(this, event));\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 utils.on(this.media, 'loadeddata', () => {\n utils.toggleHidden(this.elements.volume, !this.hasAudio);\n utils.toggleHidden(this.elements.buttons.mute, !this.hasAudio);\n });\n\n // Handle the media finishing\n utils.on(this.media, 'ended', () => {\n // Show poster on end\n if (this.isHTML5 && this.isVideo && this.config.showPosterOnEnd) {\n // Restart\n this.restart();\n\n // Re-load media\n this.media.load();\n }\n });\n\n // Check for buffer progress\n utils.on(this.media, 'progress playing', event => ui.updateProgress.call(this, event));\n\n // Handle native mute\n utils.on(this.media, 'volumechange', event => ui.updateVolume.call(this, event));\n\n // Handle native play/pause\n utils.on(this.media, 'playing play pause ended', event => ui.checkPlaying.call(this, event));\n\n // Loading\n utils.on(this.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(this, event));\n\n // Check if media failed to load\n // utils.on(this.media, 'play', event => ui.checkFailed.call(this, event));\n\n // Click video\n if (this.supported.ui && this.config.clickToPlay && !this.isAudio) {\n // Re-fetch the wrapper\n const wrapper = utils.getElement.call(this, `.${this.config.classNames.video}`);\n\n // Bail if there's no wrapper (this should never happen)\n if (!utils.is.element(wrapper)) {\n return;\n }\n\n // On click play, pause ore restart\n utils.on(wrapper, 'click', () => {\n // Touch devices will just show controls (if we're hiding controls)\n if (this.config.hideControls && support.touch && !this.paused) {\n return;\n }\n\n if (this.paused) {\n this.play();\n } else if (this.ended) {\n this.restart();\n this.play();\n } else {\n this.pause();\n }\n });\n }\n\n // Disable right click\n if (this.supported.ui && this.config.disableContextMenu) {\n utils.on(\n this.media,\n 'contextmenu',\n event => {\n event.preventDefault();\n },\n false,\n );\n }\n\n // Volume change\n utils.on(this.media, 'volumechange', () => {\n // Save to storage\n this.storage.set({ volume: this.volume, muted: this.muted });\n });\n\n // Speed change\n utils.on(this.media, 'ratechange', () => {\n // Update UI\n controls.updateSetting.call(this, 'speed');\n\n // Save to storage\n this.storage.set({ speed: this.speed });\n });\n\n // Quality change\n utils.on(this.media, 'qualitychange', () => {\n // Update UI\n controls.updateSetting.call(this, 'quality');\n\n // Save to storage\n this.storage.set({ quality: this.quality });\n });\n\n // Caption language change\n utils.on(this.media, 'languagechange', () => {\n // Update UI\n controls.updateSetting.call(this, 'captions');\n\n // Save to storage\n this.storage.set({ language: this.language });\n });\n\n // Captions toggle\n utils.on(this.media, 'captionsenabled captionsdisabled', () => {\n // Update UI\n controls.updateSetting.call(this, 'captions');\n\n // Save to storage\n this.storage.set({ captions: this.captions.active });\n });\n\n // Proxy events to container\n // Bubble up key events for Edge\n utils.on(this.media, this.config.events.concat([\n 'keyup',\n 'keydown',\n ]).join(' '), event => {\n let detail = {};\n\n // Get error details from media\n if (event.type === 'error') {\n detail = this.media.error;\n }\n\n utils.dispatchEvent.call(this, this.elements.container, event.type, true, detail);\n });\n },\n\n // Listen for control events\n controls() {\n // IE doesn't support input event, so we fallback to change\n const inputEvent = browser.isIE ? 'change' : 'input';\n\n // Trigger custom and default handlers\n const proxy = (event, handlerKey, defaultHandler) => {\n const customHandler = this.config.listeners[handlerKey];\n\n // Execute custom handler\n if (utils.is.function(customHandler)) {\n customHandler.call(this, event);\n }\n\n // Only call default handler if not prevented in custom handler\n if (!event.defaultPrevented && utils.is.function(defaultHandler)) {\n defaultHandler.call(this, event);\n }\n };\n\n // Play/pause toggle\n utils.on(this.elements.buttons.play, 'click', event =>\n proxy(event, 'play', () => {\n this.togglePlay();\n }),\n );\n\n // Pause\n utils.on(this.elements.buttons.restart, 'click', event =>\n proxy(event, 'restart', () => {\n this.restart();\n }),\n );\n\n // Rewind\n utils.on(this.elements.buttons.rewind, 'click', event =>\n proxy(event, 'rewind', () => {\n this.rewind();\n }),\n );\n\n // Rewind\n utils.on(this.elements.buttons.forward, 'click', event =>\n proxy(event, 'forward', () => {\n this.forward();\n }),\n );\n\n // Mute toggle\n utils.on(this.elements.buttons.mute, 'click', event =>\n proxy(event, 'mute', () => {\n this.muted = !this.muted;\n }),\n );\n\n // Captions toggle\n utils.on(this.elements.buttons.captions, 'click', event =>\n proxy(event, 'captions', () => {\n this.toggleCaptions();\n }),\n );\n\n // Fullscreen toggle\n utils.on(this.elements.buttons.fullscreen, 'click', event =>\n proxy(event, 'fullscreen', () => {\n this.fullscreen.toggle();\n }),\n );\n\n // Picture-in-Picture\n utils.on(this.elements.buttons.pip, 'click', event =>\n proxy(event, 'pip', () => {\n this.pip = 'toggle';\n }),\n );\n\n // Airplay\n utils.on(this.elements.buttons.airplay, 'click', event =>\n proxy(event, 'airplay', () => {\n this.airplay();\n }),\n );\n\n // Settings menu\n utils.on(this.elements.buttons.settings, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Click anywhere closes menu\n utils.on(document.documentElement, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Settings menu\n utils.on(this.elements.settings.form, 'click', event => {\n event.stopPropagation();\n\n // Settings menu items - use event delegation as items are added/removed\n if (utils.matches(event.target, this.config.selectors.inputs.language)) {\n proxy(event, 'language', () => {\n this.language = event.target.value;\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.quality)) {\n proxy(event, 'quality', () => {\n this.quality = event.target.value;\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.speed)) {\n proxy(event, 'speed', () => {\n this.speed = parseFloat(event.target.value);\n });\n } else {\n controls.showTab.call(this, event);\n }\n });\n\n // Seek\n utils.on(this.elements.inputs.seek, inputEvent, event =>\n proxy(event, 'seek', () => {\n this.currentTime = event.target.value / event.target.max * this.duration;\n }),\n );\n\n // Current time invert\n // Only if one time element is used for both currentTime and duration\n if (this.config.toggleInvert && !utils.is.element(this.elements.display.duration)) {\n utils.on(this.elements.display.currentTime, 'click', () => {\n // Do nothing if we're at the start\n if (this.currentTime === 0) {\n return;\n }\n\n this.config.invertTime = !this.config.invertTime;\n ui.timeUpdate.call(this);\n });\n }\n\n // Volume\n utils.on(this.elements.inputs.volume, inputEvent, event =>\n proxy(event, 'volume', () => {\n this.volume = event.target.value;\n }),\n );\n\n // Polyfill for lower fill in <input type=\"range\"> for webkit\n if (browser.isWebkit) {\n utils.on(utils.getElements.call(this, 'input[type=\"range\"]'), 'input', event => {\n controls.updateRangeFill.call(this, event.target);\n });\n }\n\n // Seek tooltip\n utils.on(this.elements.progress, 'mouseenter mouseleave mousemove', event => controls.updateSeekTooltip.call(this, event));\n\n // Toggle controls visibility based on mouse movement\n if (this.config.hideControls) {\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mouseenter mouseleave', event => {\n this.elements.controls.hover = event.type === 'mouseenter';\n });\n\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {\n this.elements.controls.pressed = [\n 'mousedown',\n 'touchstart',\n ].includes(event.type);\n });\n\n // Focus in/out on controls\n utils.on(this.elements.controls, 'focusin focusout', event => {\n this.toggleControls(event);\n });\n }\n\n // Mouse wheel for volume\n utils.on(\n this.elements.inputs.volume,\n 'wheel',\n event =>\n proxy(event, 'volume', () => {\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 const step = 1 / 50;\n let direction = 0;\n\n // Scroll down (or up on natural) to decrease\n if (event.deltaY < 0 || event.deltaX > 0) {\n if (inverted) {\n this.decreaseVolume(step);\n direction = -1;\n } else {\n this.increaseVolume(step);\n direction = 1;\n }\n }\n\n // Scroll up (or down on natural) to increase\n if (event.deltaY > 0 || event.deltaX < 0) {\n if (inverted) {\n this.increaseVolume(step);\n direction = 1;\n } else {\n this.decreaseVolume(step);\n direction = -1;\n }\n }\n\n // Don't break page scrolling at max and min\n if ((direction === 1 && this.media.volume < 1) || (direction === -1 && this.media.volume > 0)) {\n event.preventDefault();\n }\n }),\n false,\n );\n },\n};\n\nexport default listeners;\n","// ==========================================================================\n// Plyr UI\n// ==========================================================================\n\nimport utils from './utils';\nimport captions from './captions';\nimport controls from './controls';\nimport listeners from './listeners';\n\nconst ui = {\n addStyleHook() {\n utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);\n utils.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 listeners.media.call(this);\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 (!utils.is.element(this.elements.controls)) {\n // Inject custom controls\n controls.inject.call(this);\n\n // Re-attach control listeners\n listeners.controls.call(this);\n }\n\n // If there's no controls, bail\n if (!utils.is.element(this.elements.controls)) {\n return;\n }\n\n // Remove native controls\n ui.toggleNativeControls.call(this);\n\n // Captions\n captions.setup.call(this);\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 options\n this.options.quality = [];\n\n // Reset time display\n ui.timeUpdate.call(this);\n\n // Update the UI\n ui.checkPlaying.call(this);\n\n // Ready for API calls\n this.ready = true;\n\n // Ready event at end of execution stack\n utils.dispatchEvent.call(this, this.media, 'ready');\n\n // Set the title\n ui.setTitle.call(this);\n },\n\n // Setup aria attribute for play and iframe title\n setTitle() {\n // Find the current text\n let label = this.config.i18n.play;\n\n // If there's a media title set, use that for the label\n if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) {\n label += `, ${this.config.title}`;\n\n // Set container label\n this.elements.container.setAttribute('aria-label', this.config.title);\n }\n\n // If there's a play button, set label\n if (utils.is.nodeList(this.elements.buttons.play)) {\n Array.from(this.elements.buttons.play).forEach(button => {\n button.setAttribute('aria-label', label);\n });\n }\n\n // Set iframe title\n // https://github.com/sampotts/plyr/issues/124\n if (this.isEmbed) {\n const iframe = utils.getElement.call(this, 'iframe');\n\n if (!utils.is.element(iframe)) {\n return;\n }\n\n // Default to media type\n const title = !utils.is.empty(this.config.title) ? this.config.title : 'video';\n\n iframe.setAttribute('title', this.config.i18n.frameTitle.replace('{title}', title));\n }\n },\n\n // Check playing state\n checkPlaying() {\n // Class hooks\n utils.toggleClass(this.elements.container, this.config.classNames.playing, this.playing);\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.paused);\n\n // Set ARIA state\n utils.toggleState(this.elements.buttons.play, this.playing);\n\n // Toggle controls\n this.toggleControls(!this.playing);\n },\n\n // Check if media is loading\n checkLoading(event) {\n this.loading = [\n 'stalled',\n 'waiting',\n ].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 // Toggle container class hook\n utils.toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Show controls if loading, hide if done\n this.toggleControls(this.loading);\n }, this.loading ? 250 : 0);\n },\n\n // Check if media failed to load\n checkFailed() {\n // https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/networkState\n this.failed = this.media.networkState === 3;\n\n if (this.failed) {\n utils.toggleClass(this.elements.container, this.config.classNames.loading, false);\n utils.toggleClass(this.elements.container, this.config.classNames.error, true);\n }\n\n // Clear timer\n clearTimeout(this.timers.failed);\n\n // Timer to prevent flicker when seeking\n this.timers.loading = setTimeout(() => {\n // Toggle container class hook\n utils.toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Show controls if loading, hide if done\n this.toggleControls(this.loading);\n }, this.loading ? 250 : 0);\n },\n\n // Update volume UI and storage\n updateVolume() {\n if (!this.supported.ui) {\n return;\n }\n\n // Update range\n if (utils.is.element(this.elements.inputs.volume)) {\n ui.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume);\n }\n\n // Update mute state\n if (utils.is.element(this.elements.buttons.mute)) {\n utils.toggleState(this.elements.buttons.mute, this.muted || this.volume === 0);\n }\n },\n\n // Update seek value and lower fill\n setRange(target, value = 0) {\n if (!utils.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 // Set <progress> value\n setProgress(target, input) {\n const value = utils.is.number(input) ? input : 0;\n const progress = utils.is.element(target) ? target : this.elements.display.buffer;\n\n // Update value and label\n if (utils.is.element(progress)) {\n progress.value = value;\n\n // Update text label inside\n const label = progress.getElementsByTagName('span')[0];\n if (utils.is.element(label)) {\n label.childNodes[0].nodeValue = value;\n }\n }\n },\n\n // Update <progress> elements\n updateProgress(event) {\n if (!this.supported.ui || !utils.is.event(event)) {\n return;\n }\n\n let value = 0;\n\n if (event) {\n switch (event.type) {\n // Video playing\n case 'timeupdate':\n case 'seeking':\n value = utils.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 ui.setRange.call(this, this.elements.inputs.seek, value);\n }\n\n break;\n\n // Check buffer status\n case 'playing':\n case 'progress':\n value = (() => {\n const { buffered } = this.media;\n\n if (buffered && buffered.length) {\n // HTML5\n return utils.getPercentage(buffered.end(0), this.duration);\n } else if (utils.is.number(buffered)) {\n // YouTube returns between 0 and 1\n return buffered * 100;\n }\n\n return 0;\n })();\n\n ui.setProgress.call(this, this.elements.display.buffer, value);\n\n break;\n\n default:\n break;\n }\n }\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 (!utils.is.element(target) || !utils.is.number(time)) {\n return;\n }\n\n // Always display hours if duration is over an hour\n const displayHours = utils.getHours(this.duration) > 0;\n\n // eslint-disable-next-line no-param-reassign\n target.textContent = utils.formatTime(time, displayHours, inverted);\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 = !utils.is.element(this.elements.display.duration) && this.config.invertTime;\n\n // Duration\n ui.updateTimeDisplay.call(this, this.elements.display.currentTime, invert ? this.duration - this.currentTime : this.currentTime, invert);\n\n // Ignore updates while seeking\n if (event && event.type === 'timeupdate' && this.media.seeking) {\n return;\n }\n\n // Playing progress\n ui.updateProgress.call(this, event);\n },\n\n // Show the duration on metadataloaded\n durationUpdate() {\n if (!this.supported.ui) {\n return;\n }\n\n // If there's a spot to display duration\n const hasDuration = utils.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 ui.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration);\n }\n\n // If there's a duration element, update content\n if (hasDuration) {\n ui.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\nexport default ui;\n","// ==========================================================================\n// Plyr controls\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport ui from './ui';\nimport captions from './captions';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst controls = {\n // Webkit polyfill for lower fill range\n updateRangeFill(target) {\n // WebKit only\n if (!browser.isWebkit) {\n return;\n }\n\n // Get range from event if event passed\n const range = utils.is.event(target) ? target.target : target;\n\n // Needs to be a valid <input type='range'>\n if (!utils.is.element(range) || range.getAttribute('type') !== 'range') {\n return;\n }\n\n // Set CSS custom property\n range.style.setProperty('--value', `${range.value / range.max * 100}%`);\n },\n\n // Get icon URL\n getIconUrl() {\n return {\n url: this.config.iconUrl,\n absolute: this.config.iconUrl.indexOf('http') === 0 || (browser.isIE && !window.svg4everybody),\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.absolute ? iconUrl.url : ''}#${this.config.iconPrefix}`;\n\n // Create <svg>\n const icon = document.createElementNS(namespace, 'svg');\n utils.setAttributes(\n icon,\n utils.extend(attributes, {\n role: 'presentation',\n })\n );\n\n // Create the <use> to reference sprite\n const use = document.createElementNS(namespace, 'use');\n const path = `${iconPath}-${type}`;\n\n // Set `href` attributes\n // https://github.com/sampotts/plyr/issues/460\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href\n if ('href' in use) {\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);\n } else {\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path);\n }\n\n // Add <use> to <svg>\n icon.appendChild(use);\n\n return icon;\n },\n\n // Create hidden text label\n createLabel(type, attr) {\n let text = this.config.i18n[type];\n const attributes = Object.assign({}, attr);\n\n switch (type) {\n case 'pip':\n text = 'PIP';\n break;\n\n case 'airplay':\n text = 'AirPlay';\n break;\n\n default:\n break;\n }\n\n if ('class' in attributes) {\n attributes.class += ` ${this.config.classNames.hidden}`;\n } else {\n attributes.class = this.config.classNames.hidden;\n }\n\n return utils.createElement('span', attributes, text);\n },\n\n // Create a badge\n createBadge(text) {\n if (utils.is.empty(text)) {\n return null;\n }\n\n const badge = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n badge.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.menu.badge,\n },\n text\n )\n );\n\n return badge;\n },\n\n // Create a <button>\n createButton(buttonType, attr) {\n const button = utils.createElement('button');\n const attributes = Object.assign({}, attr);\n let type = buttonType;\n\n let toggle = false;\n let label;\n let icon;\n let labelPressed;\n let iconPressed;\n\n if (!('type' in attributes)) {\n attributes.type = 'button';\n }\n\n if ('class' in attributes) {\n if (attributes.class.includes(this.config.classNames.control)) {\n attributes.class += ` ${this.config.classNames.control}`;\n }\n } else {\n attributes.class = this.config.classNames.control;\n }\n\n // Large play button\n switch (type) {\n case 'play':\n toggle = true;\n label = 'play';\n labelPressed = 'pause';\n icon = 'play';\n iconPressed = 'pause';\n break;\n\n case 'mute':\n toggle = true;\n label = 'mute';\n labelPressed = 'unmute';\n icon = 'volume';\n iconPressed = 'muted';\n break;\n\n case 'captions':\n toggle = true;\n label = 'enableCaptions';\n labelPressed = 'disableCaptions';\n icon = 'captions-off';\n iconPressed = 'captions-on';\n break;\n\n case 'fullscreen':\n toggle = true;\n label = 'enterFullscreen';\n labelPressed = 'exitFullscreen';\n icon = 'enter-fullscreen';\n iconPressed = 'exit-fullscreen';\n break;\n\n case 'play-large':\n attributes.class += ` ${this.config.classNames.control}--overlaid`;\n type = 'play';\n label = 'play';\n icon = 'play';\n break;\n\n default:\n label = type;\n icon = type;\n }\n\n // Setup toggle icon and labels\n if (toggle) {\n // Icon\n button.appendChild(controls.createIcon.call(this, iconPressed, { class: 'icon--pressed' }));\n button.appendChild(controls.createIcon.call(this, icon, { class: 'icon--not-pressed' }));\n\n // Label/Tooltip\n button.appendChild(controls.createLabel.call(this, labelPressed, { class: 'label--pressed' }));\n button.appendChild(controls.createLabel.call(this, label, { class: 'label--not-pressed' }));\n\n // Add aria attributes\n attributes['aria-pressed'] = false;\n attributes['aria-label'] = this.config.i18n[label];\n } else {\n button.appendChild(controls.createIcon.call(this, icon));\n button.appendChild(controls.createLabel.call(this, label));\n }\n\n // Merge attributes\n utils.extend(attributes, utils.getAttributesFromSelector(this.config.selectors.buttons[type], attributes));\n\n utils.setAttributes(button, attributes);\n\n // We have multiple play buttons\n if (type === 'play') {\n if (!utils.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 label\n const label = utils.createElement(\n 'label',\n {\n for: attributes.id,\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n );\n\n // Seek input\n const input = utils.createElement(\n 'input',\n utils.extend(\n utils.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 },\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 {\n label,\n input,\n };\n },\n\n // Create a <progress>\n createProgress(type, attributes) {\n const progress = utils.createElement(\n 'progress',\n utils.extend(\n utils.getAttributesFromSelector(this.config.selectors.display[type]),\n {\n min: 0,\n max: 100,\n value: 0,\n },\n attributes\n )\n );\n\n // Create the label inside\n if (type !== 'volume') {\n progress.appendChild(utils.createElement('span', null, '0'));\n\n let suffix = '';\n switch (type) {\n case 'played':\n suffix = this.config.i18n.played;\n break;\n\n case 'buffer':\n suffix = this.config.i18n.buffered;\n break;\n\n default:\n break;\n }\n\n progress.textContent = `% ${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 container = utils.createElement('div', {\n class: 'plyr__time',\n });\n\n container.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n )\n );\n\n container.appendChild(utils.createElement('span', utils.getAttributesFromSelector(this.config.selectors.display[type]), '00:00'));\n\n this.elements.display[type] = container;\n\n return container;\n },\n\n // Create a settings menu item\n createMenuItem(value, list, type, title, badge = null, checked = false) {\n const item = utils.createElement('li');\n\n const label = utils.createElement('label', {\n class: this.config.classNames.control,\n });\n\n const radio = utils.createElement(\n 'input',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs[type]), {\n type: 'radio',\n name: `plyr-${type}`,\n value,\n checked,\n class: 'plyr__sr-only',\n })\n );\n\n const faux = utils.createElement('span', { 'aria-hidden': true });\n\n label.appendChild(radio);\n label.appendChild(faux);\n label.insertAdjacentHTML('beforeend', title);\n\n if (utils.is.element(badge)) {\n label.appendChild(badge);\n }\n\n item.appendChild(label);\n list.appendChild(item);\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 !utils.is.element(this.elements.inputs.seek) ||\n !utils.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.inputs.seek.getBoundingClientRect();\n const visible = `${this.config.classNames.tooltip}--visible`;\n\n // Determine percentage, if already visible\n if (utils.is.event(event)) {\n percent = 100 / clientRect.width * (event.pageX - clientRect.left);\n } else if (utils.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 ui.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 (utils.is.event(event) && [\n 'mouseenter',\n 'mouseleave',\n ].includes(event.type)) {\n utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter');\n }\n },\n\n // Hide/show a tab\n toggleTab(setting, toggle) {\n const tab = this.elements.settings.tabs[setting];\n const pane = this.elements.settings.panes[setting];\n\n utils.toggleHidden(tab, !toggle);\n utils.toggleHidden(pane, !toggle);\n },\n\n // Set the YouTube quality menu\n // TODO: Support for HTML5\n setQualityMenu(options) {\n const type = 'quality';\n const list = this.elements.settings.panes.quality.querySelector('ul');\n\n // Set options if passed and filter based on config\n if (utils.is.array(options)) {\n this.options.quality = options.filter(quality => this.config.quality.options.includes(quality));\n } else {\n this.options.quality = this.config.quality.options;\n }\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.options.quality) && this.isYouTube;\n controls.toggleTab.call(this, type, toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Get the badge HTML for HD, 4K etc\n const getBadge = quality => {\n let label = '';\n\n switch (quality) {\n case 'hd2160':\n label = '4K';\n break;\n\n case 'hd1440':\n label = 'WQHD';\n break;\n\n case 'hd1080':\n label = 'HD';\n break;\n\n case 'hd720':\n label = 'HD';\n break;\n\n default:\n break;\n }\n\n if (!label.length) {\n return null;\n }\n\n return controls.createBadge.call(this, label);\n };\n\n this.options.quality.forEach(quality =>\n controls.createMenuItem.call(this, quality, list, type, controls.getLabel.call(this, 'quality', quality), getBadge(quality))\n );\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Translate a value into a nice label\n // TODO: Localisation\n getLabel(setting, value) {\n switch (setting) {\n case 'speed':\n return value === 1 ? 'Normal' : `${value}×`;\n\n case 'quality':\n switch (value) {\n case 'hd2160':\n return '2160P';\n case 'hd1440':\n return '1440P';\n case 'hd1080':\n return '1080P';\n case 'hd720':\n return '720P';\n case 'large':\n return '480P';\n case 'medium':\n return '360P';\n case 'small':\n return '240P';\n case 'tiny':\n return 'Tiny';\n case 'default':\n return 'Auto';\n default:\n return value;\n }\n\n case 'captions':\n return controls.getLanguage.call(this);\n\n default:\n return null;\n }\n },\n\n // Update the selected setting\n updateSetting(setting, container) {\n const pane = this.elements.settings.panes[setting];\n let value = null;\n let list = container;\n\n switch (setting) {\n case 'captions':\n value = this.captions.active ? this.captions.language : '';\n break;\n\n default:\n value = this[setting];\n\n // Get default\n if (utils.is.empty(value)) {\n value = this.config[setting].default;\n }\n\n // Unsupported value\n if (!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 break;\n }\n\n // Get the list if we need to\n if (!utils.is.element(list)) {\n list = pane && pane.querySelector('ul');\n }\n\n // Update the label\n if (!utils.is.empty(value)) {\n const label = this.elements.settings.tabs[setting].querySelector(`.${this.config.classNames.menu.value}`);\n label.innerHTML = controls.getLabel.call(this, setting, value);\n }\n\n // Find the radio option\n const target = list && list.querySelector(`input[value=\"${value}\"]`);\n\n if (utils.is.element(target)) {\n // Check it\n target.checked = true;\n }\n },\n\n // Set the looping options\n /* setLoopMenu() {\n const options = ['start', 'end', 'all', 'reset'];\n const list = this.elements.settings.panes.loop.querySelector('ul');\n\n // Show the pane and tab\n utils.toggleHidden(this.elements.settings.tabs.loop, false);\n utils.toggleHidden(this.elements.settings.panes.loop, false);\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.loop.options);\n controls.toggleTab.call(this, 'loop', toggle);\n\n // Empty the menu\n utils.emptyElement(list);\n\n options.forEach(option => {\n const item = utils.createElement('li');\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.loop), {\n type: 'button',\n class: this.config.classNames.control,\n 'data-plyr-loop-action': option,\n }),\n this.config.i18n[option]\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 getLanguage() {\n if (!this.supported.ui) {\n return null;\n }\n\n if (!support.textTracks || !captions.getTracks.call(this).length) {\n return this.config.i18n.none;\n }\n\n if (this.captions.active) {\n const currentTrack = captions.getCurrentTrack.call(this);\n\n if (utils.is.track(currentTrack)) {\n return currentTrack.label;\n }\n }\n\n return this.config.i18n.disabled;\n },\n\n // Set a list of available captions languages\n setCaptionsMenu() {\n // TODO: Captions or language? Currently it's mixed\n const type = 'captions';\n const list = this.elements.settings.panes.captions.querySelector('ul');\n\n // Toggle the pane and tab\n const hasTracks = captions.getTracks.call(this).length;\n controls.toggleTab.call(this, type, hasTracks);\n\n // Empty the menu\n utils.emptyElement(list);\n\n // If there's no captions, bail\n if (!hasTracks) {\n return;\n }\n\n // Re-map the tracks into just the data we need\n const tracks = captions.getTracks.call(this).map(track => ({\n language: track.language,\n label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(),\n }));\n\n // Add the \"None\" option to turn off captions\n tracks.unshift({\n language: '',\n label: this.config.i18n.none,\n });\n\n // Generate options\n tracks.forEach(track => {\n controls.createMenuItem.call(\n this,\n track.language,\n list,\n 'language',\n track.label || track.language,\n controls.createBadge.call(this, track.language.toUpperCase()),\n track.language.toLowerCase() === this.captions.language.toLowerCase()\n );\n });\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Set a list of available captions languages\n setSpeedMenu() {\n const type = 'speed';\n\n // Set the default speeds\n if (!utils.is.object(this.options.speed) || !Object.keys(this.options.speed).length) {\n this.options.speed = [\n 0.5,\n 0.75,\n 1,\n 1.25,\n 1.5,\n 1.75,\n 2,\n ];\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 = !utils.is.empty(this.options.speed);\n controls.toggleTab.call(this, type, toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Get the list to populate\n const list = this.elements.settings.panes.speed.querySelector('ul');\n\n // Show the pane and tab\n utils.toggleHidden(this.elements.settings.tabs.speed, false);\n utils.toggleHidden(this.elements.settings.panes.speed, false);\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Create items\n this.options.speed.forEach(speed => controls.createMenuItem.call(this, speed, list, type, controls.getLabel.call(this, 'speed', speed)));\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Show/hide menu\n toggleMenu(event) {\n const { form } = this.elements.settings;\n const button = this.elements.buttons.settings;\n const show = utils.is.boolean(event) ? event : utils.is.element(form) && form.getAttribute('aria-hidden') === 'true';\n\n if (utils.is.event(event)) {\n const isMenuItem = utils.is.element(form) && form.contains(event.target);\n const isButton = event.target === this.elements.buttons.settings;\n\n // If the click was inside the form 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 && !isButton && show)) {\n return;\n }\n\n // Prevent the toggle being caught by the doc listener\n if (isButton) {\n event.stopPropagation();\n }\n }\n\n // Set form and button attributes\n if (utils.is.element(button)) {\n button.setAttribute('aria-expanded', show);\n }\n\n if (utils.is.element(form)) {\n form.setAttribute('aria-hidden', !show);\n utils.toggleClass(this.elements.container, this.config.classNames.menu.open, show);\n\n if (show) {\n form.removeAttribute('tabindex');\n } else {\n form.setAttribute('tabindex', -1);\n }\n }\n },\n\n // Get the natural size of a tab\n getTabSize(tab) {\n const clone = tab.cloneNode(true);\n clone.style.position = 'absolute';\n clone.style.opacity = 0;\n clone.setAttribute('aria-hidden', false);\n\n // Prevent input's being unchecked due to the name being identical\n Array.from(clone.querySelectorAll('input[name]')).forEach(input => {\n const name = input.getAttribute('name');\n input.setAttribute('name', `${name}-clone`);\n });\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 utils.removeElement(clone);\n\n return {\n width,\n height,\n };\n },\n\n // Toggle Menu\n showTab(event) {\n const { menu } = this.elements.settings;\n const tab = event.target;\n const show = tab.getAttribute('aria-expanded') === 'false';\n const pane = document.getElementById(tab.getAttribute('aria-controls'));\n\n // Nothing to show, bail\n if (!utils.is.element(pane)) {\n return;\n }\n\n // Are we targetting a tab? If not, bail\n const isTab = pane.getAttribute('role') === 'tabpanel';\n if (!isTab) {\n return;\n }\n\n // Hide all other tabs\n // Get other tabs\n const current = menu.querySelector('[role=\"tabpanel\"][aria-hidden=\"false\"]');\n const container = current.parentNode;\n\n // Set other toggles to be expanded false\n Array.from(menu.querySelectorAll(`[aria-controls=\"${current.getAttribute('id')}\"]`)).forEach(toggle => {\n toggle.setAttribute('aria-expanded', false);\n });\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.getTabSize.call(this, pane);\n\n // Restore auto height/width\n const restore = e => {\n // We're only bothered about height and width on the container\n if (e.target !== container || ![\n 'width',\n 'height',\n ].includes(e.propertyName)) {\n return;\n }\n\n // Revert back to auto\n container.style.width = '';\n container.style.height = '';\n\n // Only listen once\n utils.off(container, utils.transitionEndEvent, restore);\n };\n\n // Listen for the transition finishing and restore auto height/width\n utils.on(container, utils.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 current.setAttribute('aria-hidden', true);\n current.setAttribute('tabindex', -1);\n\n // Set attributes on target\n pane.setAttribute('aria-hidden', !show);\n tab.setAttribute('aria-expanded', show);\n pane.removeAttribute('tabindex');\n\n // Focus the first item\n pane.querySelectorAll('button:not(:disabled), input:not(:disabled), [tabindex]')[0].focus();\n },\n\n // Build the default HTML\n // TODO: Set order based on order in the config.controls array?\n create(data) {\n // Do nothing if we want no controls\n if (utils.is.empty(this.config.controls)) {\n return null;\n }\n\n // Create the container\n const container = utils.createElement('div', utils.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 = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.progress));\n\n // Seek range slider\n const seek = controls.createRange.call(this, 'seek', {\n id: `plyr-seek-${data.id}`,\n });\n progress.appendChild(seek.label);\n progress.appendChild(seek.input);\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 = utils.createElement(\n 'span',\n {\n role: 'tooltip',\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 // Toggle mute button\n if (this.config.controls.includes('mute')) {\n container.appendChild(controls.createButton.call(this, 'mute'));\n }\n\n // Volume range control\n if (this.config.controls.includes('volume')) {\n const volume = utils.createElement('div', {\n class: 'plyr__volume',\n });\n\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 const range = controls.createRange.call(\n this,\n 'volume',\n utils.extend(attributes, {\n id: `plyr-volume-${data.id}`,\n })\n );\n volume.appendChild(range.label);\n volume.appendChild(range.input);\n\n this.elements.volume = volume;\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') && !utils.is.empty(this.config.settings)) {\n const menu = utils.createElement('div', {\n class: 'plyr__menu',\n });\n\n menu.appendChild(\n controls.createButton.call(this, 'settings', {\n id: `plyr-settings-toggle-${data.id}`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}`,\n 'aria-expanded': false,\n })\n );\n\n const form = utils.createElement('form', {\n class: 'plyr__menu__container',\n id: `plyr-settings-${data.id}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tablist',\n tabindex: -1,\n });\n\n const inner = utils.createElement('div');\n\n const home = utils.createElement('div', {\n id: `plyr-settings-${data.id}-home`,\n 'aria-hidden': false,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tabpanel',\n });\n\n // Create the tab list\n const tabs = utils.createElement('ul', {\n role: 'tablist',\n });\n\n // Build the tabs\n this.config.settings.forEach(type => {\n const tab = utils.createElement('li', {\n role: 'tab',\n hidden: '',\n });\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.settings), {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`,\n id: `plyr-settings-${data.id}-${type}-tab`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-${type}`,\n 'aria-expanded': false,\n }),\n this.config.i18n[type]\n );\n\n const value = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n // Speed contains HTML entities\n value.innerHTML = data[type];\n\n button.appendChild(value);\n tab.appendChild(button);\n tabs.appendChild(tab);\n\n this.elements.settings.tabs[type] = tab;\n });\n\n home.appendChild(tabs);\n inner.appendChild(home);\n\n // Build the panes\n this.config.settings.forEach(type => {\n const pane = utils.createElement('div', {\n id: `plyr-settings-${data.id}-${type}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-${data.id}-${type}-tab`,\n role: 'tabpanel',\n tabindex: -1,\n hidden: '',\n });\n\n const back = utils.createElement(\n 'button',\n {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--back`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-home`,\n 'aria-expanded': false,\n },\n this.config.i18n[type]\n );\n\n pane.appendChild(back);\n\n const options = utils.createElement('ul');\n\n pane.appendChild(options);\n inner.appendChild(pane);\n\n this.elements.settings.panes[type] = pane;\n });\n\n form.appendChild(inner);\n menu.appendChild(form);\n container.appendChild(menu);\n\n this.elements.settings.form = form;\n this.elements.settings.menu = menu;\n }\n\n // Picture in picture button\n if (this.config.controls.includes('pip') && support.pip) {\n container.appendChild(controls.createButton.call(this, 'pip'));\n }\n\n // Airplay button\n if (this.config.controls.includes('airplay') && support.airplay) {\n container.appendChild(controls.createButton.call(this, 'airplay'));\n }\n\n // Toggle fullscreen button\n if (this.config.controls.includes('fullscreen')) {\n container.appendChild(controls.createButton.call(this, 'fullscreen'));\n }\n\n // Larger overlaid play button\n if (this.config.controls.includes('play-large')) {\n this.elements.container.appendChild(controls.createButton.call(this, 'play-large'));\n }\n\n this.elements.controls = container;\n\n if (this.config.controls.includes('settings') && this.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(this);\n }\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.absolute) {\n utils.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 // HTML or Element passed as the option\n if (utils.is.string(this.config.controls) || utils.is.element(this.config.controls)) {\n container = this.config.controls;\n } else if (utils.is.function(this.config.controls)) {\n // A custom function to build controls\n // The function can return a HTMLElement or String\n container = this.config.controls({\n id: this.id,\n seektime: this.config.seekTime,\n title: this.config.title,\n });\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: controls.getLanguage.call(this),\n // TODO: Looping\n // loop: 'None',\n });\n }\n\n // Controls container\n let target;\n\n // Inject to custom location\n if (utils.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 (!utils.is.element(target)) {\n target = this.elements.container;\n }\n\n // Inject controls HTML\n if (utils.is.element(container)) {\n target.appendChild(container);\n } else {\n target.insertAdjacentHTML('beforeend', container);\n }\n\n // Find the elements if need be\n if (!utils.is.element(this.elements.controls)) {\n utils.findElements.call(this);\n }\n\n // Edge sometimes doesn't finish the paint so force a redraw\n if (window.navigator.userAgent.includes('Edge')) {\n utils.repaint(target);\n }\n\n // Setup tooltips\n if (this.config.tooltips.controls) {\n const labels = utils.getElements.call(\n this,\n [\n this.config.selectors.controls.wrapper,\n ' ',\n this.config.selectors.labels,\n ' .',\n this.config.classNames.hidden,\n ].join('')\n );\n\n Array.from(labels).forEach(label => {\n utils.toggleClass(label, this.config.classNames.hidden, false);\n utils.toggleClass(label, this.config.classNames.tooltip, true);\n label.setAttribute('role', 'tooltip');\n });\n }\n },\n};\n\nexport default controls;\n","// ==========================================================================\n// Plyr Captions\n// TODO: Create as class\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\n\nconst captions = {\n // Setup captions\n setup() {\n // Requires UI support\n if (!this.supported.ui) {\n return;\n }\n\n // Set default language if not set\n const stored = this.storage.get('language');\n\n if (!utils.is.empty(stored)) {\n this.captions.language = stored;\n }\n\n if (utils.is.empty(this.captions.language)) {\n this.captions.language = this.config.captions.language.toLowerCase();\n }\n\n // Set captions enabled state if not set\n if (!utils.is.boolean(this.captions.active)) {\n const active = this.storage.get('captions');\n\n if (utils.is.boolean(active)) {\n this.captions.active = active;\n } else {\n this.captions.active = this.config.captions.active;\n }\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 (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n\n return;\n }\n // Inject the container\n if (!utils.is.element(this.elements.captions)) {\n this.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.captions));\n\n utils.insertAfter(this.elements.captions, this.elements.wrapper);\n }\n\n // Set the class hook\n utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this)));\n\n // Get tracks\n const tracks = captions.getTracks.call(this);\n\n // If no caption file exists, hide container for caption text\n if (utils.is.empty(tracks)) {\n return;\n }\n\n // Get browser info\n const browser = utils.getBrowser();\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 href = utils.parseUrl(src);\n\n if (href.hostname !== window.location.href.hostname && [\n 'http:',\n 'https:',\n ].includes(href.protocol)) {\n utils\n .fetch(src, 'blob')\n .then(blob => {\n track.setAttribute('src', window.URL.createObjectURL(blob));\n })\n .catch(() => {\n utils.removeElement(track);\n });\n }\n });\n }\n\n // Set language\n captions.setLanguage.call(this);\n\n // Enable UI\n captions.show.call(this);\n\n // Set available languages in list\n if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n },\n\n // Set the captions language\n setLanguage() {\n // Setup HTML5 track rendering\n if (this.isHTML5 && this.isVideo) {\n captions.getTracks.call(this).forEach(track => {\n // Show track\n utils.on(track, 'cuechange', event => captions.setCue.call(this, event));\n\n // Turn off native caption rendering to avoid double captions\n // eslint-disable-next-line\n track.mode = 'hidden';\n });\n\n // Get current track\n const currentTrack = captions.getCurrentTrack.call(this);\n\n // Check if suported kind\n if (utils.is.track(currentTrack)) {\n // If we change the active track while a cue is already displayed we need to update it\n if (Array.from(currentTrack.activeCues || []).length) {\n captions.setCue.call(this, currentTrack);\n }\n }\n } else if (this.isVimeo && this.captions.active) {\n this.embed.enableTextTrack(this.language);\n }\n },\n\n // Get the tracks\n getTracks() {\n // Return empty array at least\n if (utils.is.nullOrUndefined(this.media)) {\n return [];\n }\n\n // Only get accepted kinds\n return Array.from(this.media.textTracks || []).filter(track => [\n 'captions',\n 'subtitles',\n ].includes(track.kind));\n },\n\n // Get the current track for the current language\n getCurrentTrack() {\n return captions.getTracks.call(this).find(track => track.language.toLowerCase() === this.language);\n },\n\n // Display active caption if it contains text\n setCue(input) {\n // Get the track from the event if needed\n const track = utils.is.event(input) ? input.target : input;\n const { activeCues } = track;\n const active = activeCues.length && activeCues[0];\n const currentTrack = captions.getCurrentTrack.call(this);\n\n // Only display current track\n if (track !== currentTrack) {\n return;\n }\n\n // Display a cue, if there is one\n if (utils.is.cue(active)) {\n captions.setText.call(this, active.getCueAsHTML());\n } else {\n captions.setText.call(this, null);\n }\n\n utils.dispatchEvent.call(this, this.media, 'cuechange');\n },\n\n // Set the current caption\n setText(input) {\n // Requires UI\n if (!this.supported.ui) {\n return;\n }\n\n if (utils.is.element(this.elements.captions)) {\n const content = utils.createElement('span');\n\n // Empty the container\n utils.emptyElement(this.elements.captions);\n\n // Default to empty\n const caption = !utils.is.nullOrUndefined(input) ? input : '';\n\n // Set the span content\n if (utils.is.string(caption)) {\n content.textContent = caption.trim();\n } else {\n content.appendChild(caption);\n }\n\n // Set new caption text\n this.elements.captions.appendChild(content);\n } else {\n this.debug.warn('No captions element to render to');\n }\n },\n\n // Display captions container and button (for initialization)\n show() {\n // If there's no caption toggle, bail\n if (!utils.is.element(this.elements.buttons.captions)) {\n return;\n }\n\n // Try to load the value from storage\n let active = this.storage.get('captions');\n\n // Otherwise fall back to the default config\n if (!utils.is.boolean(active)) {\n ({ active } = this.config.captions);\n } else {\n this.captions.active = active;\n }\n\n if (active) {\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true);\n utils.toggleState(this.elements.buttons.captions, true);\n }\n },\n};\n\nexport default captions;\n","// ==========================================================================\n// YouTube plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport controls from './../controls';\nimport ui from './../ui';\n\nconst youtube = {\n setup() {\n // Add embed class for responsive\n utils.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 (utils.is.object(window.YT) && utils.is.function(window.YT.Player)) {\n youtube.ready.call(this);\n } else {\n // Load the API\n utils.loadScript(this.config.urls.youtube.api);\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 (utils.is.function(this.embed.getVideoData)) {\n const { title } = this.embed.getVideoData();\n\n if (utils.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 (utils.is.string(key) && !utils.is.empty(key)) {\n const url = `https://www.googleapis.com/youtube/v3/videos?id=${videoId}&key=${key}&fields=items(snippet(title))&part=snippet`;\n\n utils\n .fetch(url)\n .then(result => {\n if (utils.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 (!utils.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 (utils.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 = utils.parseYouTubeId(source);\n const id = utils.generateId(player.provider);\n const container = utils.createElement('div', { id });\n player.media = utils.replaceElement(container, player.media);\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 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 // If we've already fired an error, don't do it again\n // YouTube fires onError twice\n if (utils.is.object(player.media.error)) {\n return;\n }\n\n const detail = {\n code: event.data,\n };\n\n // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError\n switch (event.data) {\n case 2:\n detail.message =\n '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 break;\n\n case 5:\n detail.message =\n 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.';\n break;\n\n case 100:\n detail.message =\n '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 break;\n\n case 101:\n case 150:\n detail.message = 'The owner of the requested video does not allow it to be played in embedded players.';\n break;\n\n default:\n detail.message = 'An unknown error occured';\n break;\n }\n\n player.media.error = detail;\n\n utils.dispatchEvent.call(player, player.media, 'error');\n },\n onPlaybackQualityChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current quality\n player.media.quality = instance.getPlaybackQuality();\n\n utils.dispatchEvent.call(player, player.media, 'qualitychange');\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 utils.dispatchEvent.call(player, player.media, 'ratechange');\n },\n onReady(event) {\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 instance.playVideo();\n player.media.paused = false;\n };\n\n player.media.pause = () => {\n instance.pauseVideo();\n player.media.paused = true;\n };\n\n player.media.stop = () => {\n instance.stopVideo();\n player.media.paused = true;\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 // Set seeking flag\n player.media.seeking = true;\n\n // Trigger seeking\n utils.dispatchEvent.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 // Quality\n Object.defineProperty(player.media, 'quality', {\n get() {\n return instance.getPlaybackQuality();\n },\n set(input) {\n // Trigger request event\n utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {\n quality: input,\n });\n\n instance.setPlaybackQuality(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 utils.dispatchEvent.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 = utils.is.boolean(input) ? input : muted;\n muted = toggle;\n instance[toggle ? 'mute' : 'unMute']();\n utils.dispatchEvent.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 utils.dispatchEvent.call(player, player.media, 'timeupdate');\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n\n // Reset timer\n window.clearInterval(player.timers.buffering);\n\n // Setup buffering\n player.timers.buffering = window.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 utils.dispatchEvent.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 window.clearInterval(player.timers.buffering);\n\n // Trigger event\n utils.dispatchEvent.call(player, player.media, 'canplaythrough');\n }\n }, 200);\n\n // Rebuild UI\n window.setTimeout(() => ui.build.call(player), 50);\n },\n onStateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Reset timer\n window.clearInterval(player.timers.playing);\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 0:\n player.media.paused = true;\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 utils.dispatchEvent.call(player, player.media, 'ended');\n }\n\n break;\n\n case 1:\n // If we were seeking, fire seeked event\n if (player.media.seeking) {\n utils.dispatchEvent.call(player, player.media, 'seeked');\n }\n player.media.seeking = false;\n\n // Only fire play if paused before\n if (player.media.paused) {\n utils.dispatchEvent.call(player, player.media, 'play');\n }\n player.media.paused = false;\n\n utils.dispatchEvent.call(player, player.media, 'playing');\n\n // Poll to get playback progress\n player.timers.playing = window.setInterval(() => {\n utils.dispatchEvent.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 utils.dispatchEvent.call(player, player.media, 'durationchange');\n }\n\n // Get quality\n controls.setQualityMenu.call(player, instance.getAvailableQualityLevels());\n\n break;\n\n case 2:\n player.media.paused = true;\n\n utils.dispatchEvent.call(player, player.media, 'pause');\n\n break;\n\n default:\n break;\n }\n\n utils.dispatchEvent.call(player, player.elements.container, 'statechange', false, {\n code: event.data,\n });\n },\n },\n });\n },\n};\n\nexport default youtube;\n","// ==========================================================================\n// Vimeo plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport captions from './../captions';\nimport ui from './../ui';\n\nconst vimeo = {\n setup() {\n // Add embed class for responsive\n utils.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 (!utils.is.object(window.Vimeo)) {\n utils.loadScript(this.config.urls.vimeo.api, () => {\n vimeo.ready.call(this);\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 ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');\n const padding = 100 / ratio[0] * ratio[1];\n const height = 200;\n const offset = (height - padding) / (height / 50);\n this.elements.wrapper.style.paddingBottom = `${padding}%`;\n this.media.style.transform = `translateY(-${offset}%)`;\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 byline: false,\n portrait: false,\n title: false,\n speed: true,\n transparent: 0,\n gesture: 'media',\n };\n const params = utils.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 (utils.is.empty(source)) {\n source = player.media.getAttribute(this.config.attributes.embed.id);\n }\n\n const id = utils.parseVimeoId(source);\n\n // Build an iframe\n const iframe = utils.createElement('iframe');\n const src = `https://player.vimeo.com/video/${id}?${params}`;\n iframe.setAttribute('src', src);\n iframe.setAttribute('allowfullscreen', '');\n iframe.setAttribute('allowtransparency', '');\n iframe.setAttribute('allow', 'autoplay');\n\n // Inject the package\n const wrapper = utils.createElement('div');\n wrapper.appendChild(iframe);\n player.media = utils.replaceElement(wrapper, player.media);\n\n // Setup instance\n // https://github.com/vimeo/player.js\n player.embed = new window.Vimeo.Player(iframe);\n\n player.media.paused = true;\n player.media.currentTime = 0;\n\n // Create a faux HTML5 API using the Vimeo API\n player.media.play = () => {\n player.embed.play().then(() => {\n player.media.paused = false;\n });\n };\n\n player.media.pause = () => {\n player.embed.pause().then(() => {\n player.media.paused = true;\n });\n };\n\n player.media.stop = () => {\n player.embed.stop().then(() => {\n player.media.paused = true;\n player.currentTime = 0;\n });\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 // Get current paused state\n // Vimeo will automatically play on seek\n const { paused } = player.media;\n\n // Set seeking flag\n player.media.seeking = true;\n\n // Trigger seeking\n utils.dispatchEvent.call(player, player.media, 'seeking');\n\n // Seek after events\n player.embed.setCurrentTime(time);\n\n // Restore pause state\n if (paused) {\n player.pause();\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.setPlaybackRate(input).then(() => {\n speed = input;\n utils.dispatchEvent.call(player, player.media, 'ratechange');\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 utils.dispatchEvent.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 = utils.is.boolean(input) ? input : false;\n\n player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => {\n muted = toggle;\n utils.dispatchEvent.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 = utils.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.getVideoUrl().then(value => {\n currentSrc = value;\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([\n player.embed.getVideoWidth(),\n player.embed.getVideoHeight(),\n ]).then(dimensions => {\n const ratio = utils.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 utils.dispatchEvent.call(player, player.media, 'timeupdate');\n });\n\n // Get duration\n player.embed.getDuration().then(value => {\n player.media.duration = value;\n utils.dispatchEvent.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', data => {\n let cue = null;\n\n if (data.cues.length) {\n cue = utils.stripHTML(data.cues[0].text);\n }\n\n captions.setText.call(player, cue);\n });\n\n player.embed.on('loaded', () => {\n if (utils.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 // Only fire play if paused before\n if (player.media.paused) {\n utils.dispatchEvent.call(player, player.media, 'play');\n }\n player.media.paused = false;\n utils.dispatchEvent.call(player, player.media, 'playing');\n });\n\n player.embed.on('pause', () => {\n player.media.paused = true;\n utils.dispatchEvent.call(player, player.media, 'pause');\n });\n\n player.embed.on('timeupdate', data => {\n player.media.seeking = false;\n currentTime = data.seconds;\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n });\n\n player.embed.on('progress', data => {\n player.media.buffered = data.percent;\n utils.dispatchEvent.call(player, player.media, 'progress');\n\n // Check all loaded\n if (parseInt(data.percent, 10) === 1) {\n utils.dispatchEvent.call(player, player.media, 'canplaythrough');\n }\n });\n\n player.embed.on('seeked', () => {\n player.media.seeking = false;\n utils.dispatchEvent.call(player, player.media, 'seeked');\n utils.dispatchEvent.call(player, player.media, 'play');\n });\n\n player.embed.on('ended', () => {\n player.media.paused = true;\n utils.dispatchEvent.call(player, player.media, 'ended');\n });\n\n player.embed.on('error', detail => {\n player.media.error = detail;\n utils.dispatchEvent.call(player, player.media, 'error');\n });\n\n // Rebuild UI\n window.setTimeout(() => ui.build.call(player), 0);\n },\n};\n\nexport default vimeo;\n","// ==========================================================================\n// Plyr Media\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport youtube from './plugins/youtube';\nimport vimeo from './plugins/vimeo';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\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 utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', this.type), true);\n\n // Add provider class\n utils.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 utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true);\n }\n\n if (this.supported.ui) {\n // Check for picture-in-picture support\n utils.toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo);\n\n // Check for airplay support\n utils.toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5);\n\n // If there's no autoplay attribute, assume the video is stopped and add state class\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.config.autoplay);\n\n // Add iOS class\n utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);\n\n // Add touch class\n utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch);\n }\n\n // Inject the player wrapper\n if (this.isVideo) {\n // Create the wrapper div\n this.elements.wrapper = utils.createElement('div', {\n class: this.config.classNames.video,\n });\n\n // Wrap the video in a container\n utils.wrap(this.media, this.elements.wrapper);\n }\n\n if (this.isEmbed) {\n switch (this.provider) {\n case 'youtube':\n youtube.setup.call(this);\n break;\n\n case 'vimeo':\n vimeo.setup.call(this);\n break;\n\n default:\n break;\n }\n } else if (this.isHTML5) {\n ui.setTitle.call(this);\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 utils.removeElement(this.media.querySelectorAll('source'));\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 media;\n","// ==========================================================================\n// Plyr source update\n// ==========================================================================\n\nimport { providers } from './types';\nimport utils from './utils';\nimport media from './media';\nimport ui from './ui';\nimport support from './support';\n\nconst source = {\n // Add elements to HTML5 media (source, tracks, etc)\n insertElements(type, attributes) {\n if (utils.is.string(attributes)) {\n utils.insertElement(type, this.media, {\n src: attributes,\n });\n } else if (utils.is.array(attributes)) {\n attributes.forEach(attribute => {\n utils.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 (!utils.is.object(input) || !('sources' in input) || !input.sources.length) {\n this.debug.warn('Invalid source format');\n return;\n }\n\n // Cancel current network requests\n media.cancelRequests.call(this);\n\n // Destroy instance and re-setup\n this.destroy.call(\n this,\n () => {\n // TODO: Reset menus here\n\n // Remove elements\n utils.removeElement(this.media);\n this.media = null;\n\n // Reset class name\n if (utils.is.element(this.elements.container)) {\n this.elements.container.removeAttribute('class');\n }\n\n // Set the type and provider\n this.type = input.type;\n this.provider = !utils.is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5;\n\n // Check for support\n this.supported = support.check(this.type, this.provider, this.config.inline);\n\n // Create new markup\n switch (`${this.provider}:${this.type}`) {\n case 'html5:video':\n this.media = utils.createElement('video');\n break;\n\n case 'html5:audio':\n this.media = utils.createElement('audio');\n break;\n\n case 'youtube:video':\n case 'vimeo:video':\n this.media = utils.createElement('div', {\n src: input.sources[0].src,\n });\n break;\n\n default:\n break;\n }\n\n // Inject the new element\n this.elements.container.appendChild(this.media);\n\n // Autoplay the new source?\n if (utils.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 ('poster' in input) {\n this.media.setAttribute('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.inline) {\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', input.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.0.0-beta.14\n// https://github.com/sampotts/plyr\n// License: The MIT License (MIT)\n// ==========================================================================\n\nimport { providers, types } from './types';\nimport defaults from './defaults';\nimport support from './support';\nimport utils from './utils';\n\nimport Console from './console';\nimport Fullscreen from './fullscreen';\nimport Storage from './storage';\nimport Ads from './plugins/ads';\n\nimport captions from './captions';\nimport controls from './controls';\nimport listeners from './listeners';\nimport media from './media';\nimport source from './source';\nimport ui from './ui';\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 // Set the media element\n this.media = target;\n\n // String selector passed\n if (utils.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) || utils.is.nodeList(this.media) || utils.is.array(this.media)) {\n // eslint-disable-next-line\n this.media = this.media[0];\n }\n\n // Set config\n this.config = utils.extend(\n {},\n 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 buttons: {},\n display: {},\n progress: {},\n inputs: {},\n settings: {\n menu: null,\n panes: {},\n tabs: {},\n },\n captions: null,\n };\n\n // Captions\n this.captions = {\n active: null,\n currentTrack: null,\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 (utils.is.nullOrUndefined(this.media) || !utils.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 this.elements.original = this.media.cloneNode(true);\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 let params = 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 (utils.is.element(iframe)) {\n // Detect provider\n url = iframe.getAttribute('src');\n this.provider = utils.getProviderByUrl(url);\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 params = utils.getUrlParams(url);\n if (!utils.is.empty(params)) {\n const truthy = [\n '1',\n 'true',\n ];\n\n if (truthy.includes(params.autoplay)) {\n this.config.autoplay = true;\n }\n if (truthy.includes(params.playsinline)) {\n this.config.inline = true;\n }\n if (truthy.includes(params.loop)) {\n this.config.loop.active = 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 (utils.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')) {\n this.config.inline = 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.inline);\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 // 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 (!utils.is.element(this.elements.container)) {\n this.elements.container = utils.createElement('div');\n utils.wrap(this.media, this.elements.container);\n }\n\n // Allow focus to be captured\n this.elements.container.setAttribute('tabindex', 0);\n\n // Global listeners\n listeners.global.call(this);\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 utils.on(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 // Setup fullscreen\n this.fullscreen = new Fullscreen(this);\n\n // Setup ads if provided\n this.ads = new Ads(this);\n }\n\n // ---------------------------------------\n // API\n // ---------------------------------------\n\n /**\n * Types and provider helpers\n */\n get isHTML5() {\n return this.provider === providers.html5;\n }\n get isEmbed() {\n return this.isYouTube || this.isVimeo;\n }\n get isYouTube() {\n return this.provider === providers.youtube;\n }\n get isVimeo() {\n return this.provider === providers.vimeo;\n }\n get isVideo() {\n return this.type === types.video;\n }\n get isAudio() {\n return this.type === types.audio;\n }\n\n /**\n * Play the media, or play the advertisement (if they are not blocked)\n */\n play() {\n // TODO: Always return a promise?\n if (this.ads.enabled && !this.ads.initialized && !this.ads.blocked) {\n this.ads.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) {\n return;\n }\n\n this.media.pause();\n }\n\n /**\n * Get paused state\n */\n get paused() {\n return this.media.paused;\n }\n\n /**\n * Get playing state\n */\n get playing() {\n return !this.paused && !this.ended && (this.isHTML5 ? this.media.readyState > 2 : true);\n }\n\n /**\n * Get ended state\n */\n get ended() {\n return 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 = utils.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 this.restart();\n this.pause();\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 - (utils.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 + (utils.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 let targetTime = 0;\n\n if (utils.is.number(input)) {\n targetTime = input;\n }\n\n // Normalise targetTime\n if (targetTime < 0) {\n targetTime = 0;\n } else if (targetTime > this.duration) {\n targetTime = this.duration;\n }\n\n // Set\n this.media.currentTime = targetTime.toFixed(4);\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 seeking status\n */\n get seeking() {\n return 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 = parseInt(this.config.duration, 10);\n\n // True duration\n const realDuration = Number(this.media.duration);\n\n // If custom duration is funky, use regular duration\n return !Number.isNaN(fauxDuration) ? fauxDuration : realDuration;\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 (utils.is.string(volume)) {\n volume = Number(volume);\n }\n\n // Load volume from storage if no value specified\n if (!utils.is.number(volume)) {\n volume = this.storage.get('volume');\n }\n\n // Use config if all else fails\n if (!utils.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, reset muted state\n if (this.muted && volume > 0) {\n this.muted = false;\n }\n }\n\n /**\n * Get the current player volume\n */\n get volume() {\n return 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 + (utils.is.number(step) ? step : 1);\n }\n\n /**\n * Decrease volume\n * @param {boolean} step - How much to decrease by (between 0 and 1)\n */\n decreaseVolume(step) {\n const volume = this.media.muted ? 0 : this.volume;\n this.volume = volume - (utils.is.number(step) ? step : 1);\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 (!utils.is.boolean(toggle)) {\n toggle = this.storage.get('muted');\n }\n\n // Use config if all else fails\n if (!utils.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 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 this.media.mozHasAudio || Boolean(this.media.webkitAudioDecodedByteCount) || Boolean(this.media.audioTracks && this.media.audioTracks.length);\n }\n\n /**\n * Set playback speed\n * @param {decimal} speed - the speed of playback (0.5-2.0)\n */\n set speed(input) {\n let speed = null;\n\n if (utils.is.number(input)) {\n speed = input;\n }\n\n if (!utils.is.number(speed)) {\n speed = this.storage.get('speed');\n }\n\n if (!utils.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 this.media.playbackRate;\n }\n\n /**\n * Set playback quality\n * Currently YouTube only\n * @param {string} input - Quality level\n */\n set quality(input) {\n let quality = null;\n\n if (utils.is.string(input)) {\n quality = input;\n }\n\n if (!utils.is.string(quality)) {\n quality = this.storage.get('quality');\n }\n\n if (!utils.is.string(quality)) {\n quality = this.config.quality.selected;\n }\n\n if (!this.options.quality.includes(quality)) {\n this.debug.warn(`Unsupported quality option (${quality})`);\n return;\n }\n\n // Update config\n this.config.quality.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 = utils.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 this.media.loop;\n }\n\n /**\n * Set new media source\n * @param {object} input - The new source object (see docs)\n */\n set source(input) {\n source.change.call(this, input);\n }\n\n /**\n * Get current source\n */\n get source() {\n return this.media.currentSrc;\n }\n\n /**\n * Set the poster image for a HTML5 video\n * @param {input} - the URL for the new poster image\n */\n set poster(input) {\n if (!this.isHTML5 || !this.isVideo) {\n this.debug.warn('Poster can only be set on HTML5 video');\n return;\n }\n\n if (utils.is.string(input)) {\n this.media.setAttribute('poster', input);\n }\n }\n\n /**\n * Get the current poster image\n */\n get poster() {\n if (!this.isHTML5 || !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 = utils.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 this.config.autoplay;\n }\n\n /**\n * Toggle captions\n * @param {boolean} input - Whether to enable captions\n */\n toggleCaptions(input) {\n // If there's no full support, or there's no caption toggle\n if (!this.supported.ui || !utils.is.element(this.elements.buttons.captions)) {\n return;\n }\n\n // If the method is called without parameter, toggle based on current value\n const show = utils.is.boolean(input) ? input : this.elements.container.className.indexOf(this.config.classNames.captions.active) === -1;\n\n // Nothing to change...\n if (this.captions.active === show) {\n return;\n }\n\n // Set global\n this.captions.active = show;\n\n // Toggle state\n utils.toggleState(this.elements.buttons.captions, this.captions.active);\n\n // Add class hook\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.active);\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled');\n }\n\n /**\n * Set the captions language\n * @param {string} - Two character ISO language code (e.g. EN, FR, PT, etc)\n */\n set language(input) {\n // Nothing specified\n if (!utils.is.string(input)) {\n return;\n }\n\n // Toggle captions based on input\n this.toggleCaptions(!utils.is.empty(input));\n\n // If empty string is passed, assume disable captions\n if (utils.is.empty(input)) {\n return;\n }\n\n // Normalize\n const language = input.toLowerCase();\n\n // If nothing to change, bail\n if (this.language === language) {\n return;\n }\n\n // Update config\n this.captions.language = language;\n\n // Clear caption\n captions.setText.call(this, null);\n\n // Update captions\n captions.setLanguage.call(this);\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, 'languagechange');\n }\n\n /**\n * Get the current captions language\n */\n get language() {\n return this.captions.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 = utils.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 // We need controls of course...\n if (!utils.is.element(this.elements.controls)) {\n return;\n }\n\n // Don't hide if no UI support or it's audio\n if (!this.supported.ui || this.isAudio) {\n return;\n }\n\n let delay = 0;\n let show = toggle;\n let isEnterFullscreen = false;\n\n // Get toggle state if not set\n if (!utils.is.boolean(toggle)) {\n if (utils.is.event(toggle)) {\n // Is the enter fullscreen event\n isEnterFullscreen = toggle.type === 'enterfullscreen';\n\n // Whether to show controls\n show = [\n 'mouseenter',\n 'mousemove',\n 'touchstart',\n 'touchmove',\n 'focusin',\n ].includes(toggle.type);\n\n // Delay hiding on move events\n if ([\n 'mousemove',\n 'touchmove',\n 'touchend',\n ].includes(toggle.type)) {\n delay = 2000;\n }\n\n // Delay a little more for keyboard users\n if (toggle.type === 'focusin') {\n delay = 3000;\n utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true);\n }\n } else {\n show = utils.hasClass(this.elements.container, this.config.classNames.hideControls);\n }\n }\n\n // Clear timer on every call\n window.clearTimeout(this.timers.controls);\n\n // If the mouse is not over the controls, set a timeout to hide them\n if (show || this.paused || this.loading) {\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, false);\n\n // Trigger event\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlsshown');\n }\n\n // Always show controls when paused or if touch\n if (this.paused || this.loading) {\n return;\n }\n\n // Delay for hiding on touch\n if (support.touch) {\n delay = 3000;\n }\n }\n\n // If toggle is false or if we're playing (regardless of toggle),\n // then set the timer to hide the controls\n if (!show || this.playing) {\n this.timers.controls = window.setTimeout(() => {\n /* this.debug.warn({\n pressed: this.elements.controls.pressed,\n hover: this.elements.controls.pressed,\n playing: this.playing,\n paused: this.paused,\n loading: this.loading,\n }); */\n\n // If the mouse is over the controls (and not entering fullscreen), bail\n if ((this.elements.controls.pressed || this.elements.controls.hover) && !isEnterFullscreen) {\n return;\n }\n\n // Restore transition behaviour\n if (!utils.hasClass(this.elements.container, this.config.classNames.hideControls)) {\n utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, false);\n }\n\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, true);\n\n // Trigger event and close menu\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlshidden');\n\n if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) {\n controls.toggleMenu.call(this, false);\n }\n }\n }, delay);\n }\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 utils.on(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 utils.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 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 utils.removeElement(this.elements.buttons.play);\n utils.removeElement(this.elements.captions);\n utils.removeElement(this.elements.controls);\n utils.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 (utils.is.function(callback)) {\n callback();\n }\n } else {\n // Replace the container with the original element provided\n utils.replaceElement(this.elements.original, this.elements.container);\n\n // Event\n utils.dispatchEvent.call(this, this.elements.original, 'destroyed', true);\n\n // Callback\n if (utils.is.function(callback)) {\n callback.call(this.elements.original);\n }\n\n // Clear for GC\n this.elements = null;\n }\n };\n\n // Type specific stuff\n switch (`${this.provider}:${this.type}`) {\n case 'html5:video':\n case 'html5:audio':\n // Restore native video controls\n ui.toggleNativeControls.call(this, true);\n\n // Clean up\n done();\n\n break;\n\n case 'youtube:video':\n // Clear timers\n window.clearInterval(this.timers.buffering);\n window.clearInterval(this.timers.playing);\n\n // Destroy YouTube API\n if (this.embed !== null) {\n this.embed.destroy();\n }\n\n // Clean up\n done();\n\n break;\n\n case 'vimeo:video':\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 window.setTimeout(done, 200);\n\n break;\n\n default:\n break;\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 utils.loadSprite(url, id);\n }\n}\n\nexport default Plyr;\n"]}
\ No newline at end of file |