From 59c988f8197af8edca26e2665f4c90ec6326a62f Mon Sep 17 00:00:00 2001 From: Astound Date: Sun, 28 Jan 2024 00:31:30 +0800 Subject: Revert update plyr --- youtube/static/modules/plyr/plyr.css | 2 +- youtube/static/modules/plyr/plyr.js | 10121 ++++++++++++++------------ youtube/static/modules/plyr/plyr.min.js | 4 +- youtube/static/modules/plyr/plyr.min.js.map | 2 +- 4 files changed, 5316 insertions(+), 4813 deletions(-) (limited to 'youtube/static/modules') diff --git a/youtube/static/modules/plyr/plyr.css b/youtube/static/modules/plyr/plyr.css index fdc1e26..7d98f20 100644 --- a/youtube/static/modules/plyr/plyr.css +++ b/youtube/static/modules/plyr/plyr.css @@ -1 +1 @@ -@charset "UTF-8";@keyframes plyr-progress{to{background-position:25px 0;background-position:var(--plyr-progress-loading-size,25px) 0}}@keyframes plyr-popup{0%{opacity:.5;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes plyr-fade-in{0%{opacity:0}to{opacity:1}}.plyr{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;align-items:center;direction:ltr;display:flex;flex-direction:column;font-family:inherit;font-family:var(--plyr-font-family,inherit);font-variant-numeric:tabular-nums;font-weight:400;font-weight:var(--plyr-font-weight-regular,400);line-height:1.7;line-height:var(--plyr-line-height,1.7);max-width:100%;min-width:200px;position:relative;text-shadow:none;transition:box-shadow .3s ease;z-index:0}.plyr audio,.plyr iframe,.plyr video{display:block;height:100%;width:100%}.plyr button{font:inherit;line-height:inherit;width:auto}.plyr:focus{outline:0}.plyr--full-ui{box-sizing:border-box}.plyr--full-ui *,.plyr--full-ui :after,.plyr--full-ui :before{box-sizing:inherit}.plyr--full-ui a,.plyr--full-ui button,.plyr--full-ui input,.plyr--full-ui label{touch-action:manipulation}.plyr__badge{background:#4a5464;background:var(--plyr-badge-background,#4a5464);border-radius:2px;border-radius:var(--plyr-badge-border-radius,2px);color:#fff;color:var(--plyr-badge-text-color,#fff);font-size:9px;font-size:var(--plyr-font-size-badge,9px);line-height:1;padding:3px 4px}.plyr--full-ui ::-webkit-media-text-track-container{display:none}.plyr__captions{animation:plyr-fade-in .3s ease;bottom:0;display:none;font-size:13px;font-size:var(--plyr-font-size-small,13px);left:0;padding:10px;padding:var(--plyr-control-spacing,10px);position:absolute;text-align:center;transition:transform .4s ease-in-out;width:100%}.plyr__captions span:empty{display:none}@media (min-width:480px){.plyr__captions{font-size:15px;font-size:var(--plyr-font-size-base,15px);padding:20px;padding:calc(var(--plyr-control-spacing, 10px)*2)}}@media (min-width:768px){.plyr__captions{font-size:18px;font-size:var(--plyr-font-size-large,18px)}}.plyr--captions-active .plyr__captions{display:block}.plyr:not(.plyr--hide-controls) .plyr__controls:not(:empty)~.plyr__captions{transform:translateY(-40px);transform:translateY(calc(var(--plyr-control-spacing, 10px)*-4))}.plyr__caption{background:#000c;background:var(--plyr-captions-background,#000c);border-radius:2px;-webkit-box-decoration-break:clone;box-decoration-break:clone;color:#fff;color:var(--plyr-captions-text-color,#fff);line-height:185%;padding:.2em .5em;white-space:pre-wrap}.plyr__caption div{display:inline}.plyr__control{background:#0000;border:0;border-radius:4px;border-radius:var(--plyr-control-radius,4px);color:inherit;cursor:pointer;flex-shrink:0;overflow:visible;padding:7px;padding:calc(var(--plyr-control-spacing, 10px)*.7);position:relative;transition:all .3s ease}.plyr__control svg{fill:currentColor;display:block;height:18px;height:var(--plyr-control-icon-size,18px);pointer-events:none;width:18px;width:var(--plyr-control-icon-size,18px)}.plyr__control:focus{outline:0}.plyr__control:focus-visible{outline:2px dashed #00b2ff;outline:2px dashed var(--plyr-focus-visible-color,var(--plyr-color-main,var(--plyr-color-main,#00b2ff)));outline-offset:2px}a.plyr__control{text-decoration:none}.plyr__control.plyr__control--pressed .icon--not-pressed,.plyr__control.plyr__control--pressed .label--not-pressed,.plyr__control:not(.plyr__control--pressed) .icon--pressed,.plyr__control:not(.plyr__control--pressed) .label--pressed,a.plyr__control:after,a.plyr__control:before{display:none}.plyr--full-ui ::-webkit-media-controls{display:none}.plyr__controls{align-items:center;display:flex;justify-content:flex-end;text-align:center}.plyr__controls .plyr__progress__container{flex:1;min-width:0}.plyr__controls .plyr__controls__item{margin-left:2.5px;margin-left:calc(var(--plyr-control-spacing, 10px)/4)}.plyr__controls .plyr__controls__item:first-child{margin-left:0;margin-right:auto}.plyr__controls .plyr__controls__item.plyr__progress__container{padding-left:2.5px;padding-left:calc(var(--plyr-control-spacing, 10px)/4)}.plyr__controls .plyr__controls__item.plyr__time{padding:0 5px;padding:0 calc(var(--plyr-control-spacing, 10px)/2)}.plyr__controls .plyr__controls__item.plyr__progress__container:first-child,.plyr__controls .plyr__controls__item.plyr__time+.plyr__time,.plyr__controls .plyr__controls__item.plyr__time:first-child{padding-left:0}.plyr [data-plyr=airplay],.plyr [data-plyr=captions],.plyr [data-plyr=fullscreen],.plyr [data-plyr=pip],.plyr__controls:empty{display:none}.plyr--airplay-supported [data-plyr=airplay],.plyr--captions-enabled [data-plyr=captions],.plyr--fullscreen-enabled [data-plyr=fullscreen],.plyr--pip-supported [data-plyr=pip]{display:inline-block}.plyr__menu{display:flex;position:relative}.plyr__menu .plyr__control svg{transition:transform .3s ease}.plyr__menu .plyr__control[aria-expanded=true] svg{transform:rotate(90deg)}.plyr__menu .plyr__control[aria-expanded=true] .plyr__tooltip{display:none}.plyr__menu__container{animation:plyr-popup .2s ease;background:#ffffffe6;background:var(--plyr-menu-background,#ffffffe6);border-radius:8px;border-radius:var(--plyr-menu-radius,8px);bottom:100%;box-shadow:0 1px 2px #00000026;box-shadow:var(--plyr-menu-shadow,0 1px 2px #00000026);color:#4a5464;color:var(--plyr-menu-color,#4a5464);font-size:15px;font-size:var(--plyr-font-size-base,15px);margin-bottom:10px;position:absolute;right:-3px;text-align:left;white-space:nowrap;z-index:3}.plyr__menu__container>div{overflow:hidden;transition:height .35s cubic-bezier(.4,0,.2,1),width .35s cubic-bezier(.4,0,.2,1)}.plyr__menu__container:after{border:4px solid #0000;border-top-color:#ffffffe6;border:var(--plyr-menu-arrow-size,4px) solid #0000;border-top-color:var(--plyr-menu-background,#ffffffe6);content:"";height:0;position:absolute;right:14px;right:calc(var(--plyr-control-icon-size, 18px)/2 + var(--plyr-control-spacing, 10px)*.7 - var(--plyr-menu-arrow-size, 4px)/2);top:100%;width:0}.plyr__menu__container [role=menu]{max-height:320px;overflow-y:auto;padding:7px;padding:calc(var(--plyr-control-spacing, 10px)*.7)}.plyr__menu__container [role=menuitem],.plyr__menu__container [role=menuitemradio]{margin-top:2px}.plyr__menu__container [role=menuitem]:first-child,.plyr__menu__container [role=menuitemradio]:first-child{margin-top:0}.plyr__menu__container .plyr__control{align-items:center;color:#4a5464;color:var(--plyr-menu-color,#4a5464);display:flex;font-size:13px;font-size:var(--plyr-font-size-menu,var(--plyr-font-size-small,13px));padding:4.66667px 10.5px;padding:calc(var(--plyr-control-spacing, 10px)*.7/1.5) calc(var(--plyr-control-spacing, 10px)*.7*1.5);-webkit-user-select:none;user-select:none;width:100%}.plyr__menu__container .plyr__control>span{align-items:inherit;display:flex;width:100%}.plyr__menu__container .plyr__control:after{border:4px solid #0000;border:var(--plyr-menu-item-arrow-size,4px) solid #0000;content:"";position:absolute;top:50%;transform:translateY(-50%)}.plyr__menu__container .plyr__control--forward{padding-right:28px;padding-right:calc(var(--plyr-control-spacing, 10px)*.7*4)}.plyr__menu__container .plyr__control--forward:after{border-left-color:#728197;border-left-color:var(--plyr-menu-arrow-color,#728197);right:6.5px;right:calc(var(--plyr-control-spacing, 10px)*.7*1.5 - var(--plyr-menu-item-arrow-size, 4px))}.plyr__menu__container .plyr__control--forward:focus-visible:after,.plyr__menu__container .plyr__control--forward:hover:after{border-left-color:initial}.plyr__menu__container .plyr__control--back{font-weight:400;font-weight:var(--plyr-font-weight-regular,400);margin:7px;margin:calc(var(--plyr-control-spacing, 10px)*.7);margin-bottom:3.5px;margin-bottom:calc(var(--plyr-control-spacing, 10px)*.7/2);padding-left:28px;padding-left:calc(var(--plyr-control-spacing, 10px)*.7*4);position:relative;width:calc(100% - 14px);width:calc(100% - var(--plyr-control-spacing, 10px)*.7*2)}.plyr__menu__container .plyr__control--back:after{border-right-color:#728197;border-right-color:var(--plyr-menu-arrow-color,#728197);left:6.5px;left:calc(var(--plyr-control-spacing, 10px)*.7*1.5 - var(--plyr-menu-item-arrow-size, 4px))}.plyr__menu__container .plyr__control--back:before{background:#dcdfe5;background:var(--plyr-menu-back-border-color,#dcdfe5);box-shadow:0 1px 0 #fff;box-shadow:0 1px 0 var(--plyr-menu-back-border-shadow-color,#fff);content:"";height:1px;left:0;margin-top:3.5px;margin-top:calc(var(--plyr-control-spacing, 10px)*.7/2);overflow:hidden;position:absolute;right:0;top:100%}.plyr__menu__container .plyr__control--back:focus-visible:after,.plyr__menu__container .plyr__control--back:hover:after{border-right-color:initial}.plyr__menu__container .plyr__control[role=menuitemradio]{padding-left:7px;padding-left:calc(var(--plyr-control-spacing, 10px)*.7)}.plyr__menu__container .plyr__control[role=menuitemradio]:after,.plyr__menu__container .plyr__control[role=menuitemradio]:before{border-radius:100%}.plyr__menu__container .plyr__control[role=menuitemradio]:before{background:#0000001a;content:"";display:block;flex-shrink:0;height:16px;margin-right:10px;margin-right:var(--plyr-control-spacing,10px);transition:all .3s ease;width:16px}.plyr__menu__container .plyr__control[role=menuitemradio]:after{background:#fff;border:0;height:6px;left:12px;opacity:0;top:50%;transform:translateY(-50%) scale(0);transition:transform .3s ease,opacity .3s ease;width:6px}.plyr__menu__container .plyr__control[role=menuitemradio][aria-checked=true]:before{background:#00b2ff;background:var(--plyr-control-toggle-checked-background,var(--plyr-color-main,var(--plyr-color-main,#00b2ff)))}.plyr__menu__container .plyr__control[role=menuitemradio][aria-checked=true]:after{opacity:1;transform:translateY(-50%) scale(1)}.plyr__menu__container .plyr__control[role=menuitemradio]:focus-visible:before,.plyr__menu__container .plyr__control[role=menuitemradio]:hover:before{background:#23282f1a}.plyr__menu__container .plyr__menu__value{align-items:center;display:flex;margin-left:auto;margin-right:-5px;margin-right:calc(var(--plyr-control-spacing, 10px)*.7*-1 - -2px);overflow:hidden;padding-left:24.5px;padding-left:calc(var(--plyr-control-spacing, 10px)*.7*3.5);pointer-events:none}.plyr--full-ui input[type=range]{-webkit-appearance:none;appearance:none;background:#0000;border:0;border-radius:26px;border-radius:calc(var(--plyr-range-thumb-height, 13px)*2);color:#00b2ff;color:var(--plyr-range-fill-background,var(--plyr-color-main,var(--plyr-color-main,#00b2ff)));display:block;height:19px;height:calc(var(--plyr-range-thumb-active-shadow-width, 3px)*2 + var(--plyr-range-thumb-height, 13px));margin:0;min-width:0;padding:0;transition:box-shadow .3s ease;width:100%}.plyr--full-ui input[type=range]::-webkit-slider-runnable-track{background:#0000;background-image:linear-gradient(90deg,currentColor 0,#0000 0);background-image:linear-gradient(to right,currentColor var(--value,0),#0000 var(--value,0));border:0;border-radius:2.5px;border-radius:calc(var(--plyr-range-track-height, 5px)/2);height:5px;height:var(--plyr-range-track-height,5px);-webkit-transition:box-shadow .3s ease;transition:box-shadow .3s ease;-webkit-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background:#fff;background:var(--plyr-range-thumb-background,#fff);border:0;border-radius:100%;box-shadow:0 1px 1px #23282f26,0 0 0 1px #23282f33;box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px #23282f26,0 0 0 1px #23282f33);height:13px;height:var(--plyr-range-thumb-height,13px);margin-top:-4px;margin-top:calc((var(--plyr-range-thumb-height, 13px) - var(--plyr-range-track-height, 5px))/2*-1);position:relative;-webkit-transition:all .2s ease;transition:all .2s ease;width:13px;width:var(--plyr-range-thumb-height,13px)}.plyr--full-ui input[type=range]::-moz-range-track{background:#0000;border:0;border-radius:2.5px;border-radius:calc(var(--plyr-range-track-height, 5px)/2);height:5px;height:var(--plyr-range-track-height,5px);-moz-transition:box-shadow .3s ease;transition:box-shadow .3s ease;user-select:none}.plyr--full-ui input[type=range]::-moz-range-thumb{background:#fff;background:var(--plyr-range-thumb-background,#fff);border:0;border-radius:100%;box-shadow:0 1px 1px #23282f26,0 0 0 1px #23282f33;box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px #23282f26,0 0 0 1px #23282f33);height:13px;height:var(--plyr-range-thumb-height,13px);position:relative;-moz-transition:all .2s ease;transition:all .2s ease;width:13px;width:var(--plyr-range-thumb-height,13px)}.plyr--full-ui input[type=range]::-moz-range-progress{background:currentColor;border-radius:2.5px;border-radius:calc(var(--plyr-range-track-height, 5px)/2);height:5px;height:var(--plyr-range-track-height,5px)}.plyr--full-ui input[type=range]::-ms-track{color:#0000}.plyr--full-ui input[type=range]::-ms-fill-upper,.plyr--full-ui input[type=range]::-ms-track{background:#0000;border:0;border-radius:2.5px;border-radius:calc(var(--plyr-range-track-height, 5px)/2);height:5px;height:var(--plyr-range-track-height,5px);-ms-transition:box-shadow .3s ease;transition:box-shadow .3s ease;user-select:none}.plyr--full-ui input[type=range]::-ms-fill-lower{background:#0000;background:currentColor;border:0;border-radius:2.5px;border-radius:calc(var(--plyr-range-track-height, 5px)/2);height:5px;height:var(--plyr-range-track-height,5px);-ms-transition:box-shadow .3s ease;transition:box-shadow .3s ease;user-select:none}.plyr--full-ui input[type=range]::-ms-thumb{background:#fff;background:var(--plyr-range-thumb-background,#fff);border:0;border-radius:100%;box-shadow:0 1px 1px #23282f26,0 0 0 1px #23282f33;box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px #23282f26,0 0 0 1px #23282f33);height:13px;height:var(--plyr-range-thumb-height,13px);margin-top:0;position:relative;-ms-transition:all .2s ease;transition:all .2s ease;width:13px;width:var(--plyr-range-thumb-height,13px)}.plyr--full-ui input[type=range]::-ms-tooltip{display:none}.plyr--full-ui input[type=range]::-moz-focus-outer{border:0}.plyr--full-ui input[type=range]:focus{outline:0}.plyr--full-ui input[type=range]:focus-visible::-webkit-slider-runnable-track{outline:2px dashed #00b2ff;outline:2px dashed var(--plyr-focus-visible-color,var(--plyr-color-main,var(--plyr-color-main,#00b2ff)));outline-offset:2px}.plyr--full-ui input[type=range]:focus-visible::-moz-range-track{outline:2px dashed #00b2ff;outline:2px dashed var(--plyr-focus-visible-color,var(--plyr-color-main,var(--plyr-color-main,#00b2ff)));outline-offset:2px}.plyr--full-ui input[type=range]:focus-visible::-ms-track{outline:2px dashed #00b2ff;outline:2px dashed var(--plyr-focus-visible-color,var(--plyr-color-main,var(--plyr-color-main,#00b2ff)));outline-offset:2px}.plyr__poster{background-color:#000;background-color:var(--plyr-video-background,var(--plyr-video-background,#000));background-position:50% 50%;background-repeat:no-repeat;background-size:contain;height:100%;left:0;opacity:0;position:absolute;top:0;transition:opacity .2s ease;width:100%;z-index:1}.plyr--stopped.plyr__poster-enabled .plyr__poster{opacity:1}.plyr--youtube.plyr--paused.plyr__poster-enabled:not(.plyr--stopped) .plyr__poster{display:none}.plyr__time{font-size:13px;font-size:var(--plyr-font-size-time,var(--plyr-font-size-small,13px))}.plyr__time+.plyr__time:before{content:"⁄";margin-right:10px;margin-right:var(--plyr-control-spacing,10px)}@media (max-width:767px){.plyr__time+.plyr__time{display:none}}.plyr__tooltip{background:#fff;background:var(--plyr-tooltip-background,#fff);border-radius:5px;border-radius:var(--plyr-tooltip-radius,5px);bottom:100%;box-shadow:0 1px 2px #00000026;box-shadow:var(--plyr-tooltip-shadow,0 1px 2px #00000026);color:#4a5464;color:var(--plyr-tooltip-color,#4a5464);font-size:13px;font-size:var(--plyr-font-size-small,13px);font-weight:400;font-weight:var(--plyr-font-weight-regular,400);left:50%;line-height:1.3;margin-bottom:10px;margin-bottom:calc(var(--plyr-control-spacing, 10px)/2*2);opacity:0;padding:5px 7.5px;padding:calc(var(--plyr-control-spacing, 10px)/2) calc(var(--plyr-control-spacing, 10px)/2*1.5);pointer-events:none;position:absolute;transform:translate(-50%,10px) scale(.8);transform-origin:50% 100%;transition:transform .2s ease .1s,opacity .2s ease .1s;white-space:nowrap;z-index:2}.plyr__tooltip:before{border-left:4px solid #0000;border-left:var(--plyr-tooltip-arrow-size,4px) solid #0000;border-right:4px solid #0000;border-right:var(--plyr-tooltip-arrow-size,4px) solid #0000;border-top:4px solid #fff;border-top:var(--plyr-tooltip-arrow-size,4px) solid var(--plyr-tooltip-background,#fff);bottom:-4px;bottom:calc(var(--plyr-tooltip-arrow-size, 4px)*-1);content:"";height:0;left:50%;position:absolute;transform:translateX(-50%);width:0;z-index:2}.plyr .plyr__control:focus-visible .plyr__tooltip,.plyr .plyr__control:hover .plyr__tooltip,.plyr__tooltip--visible{opacity:1;transform:translate(-50%) scale(1)}.plyr .plyr__control:hover .plyr__tooltip{z-index:3}.plyr__controls>.plyr__control:first-child .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip{left:0;transform:translateY(10px) scale(.8);transform-origin:0 100%}.plyr__controls>.plyr__control:first-child .plyr__tooltip:before,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip:before{left:16px;left:calc(var(--plyr-control-icon-size, 18px)/2 + var(--plyr-control-spacing, 10px)*.7)}.plyr__controls>.plyr__control:last-child .plyr__tooltip{left:auto;right:0;transform:translateY(10px) scale(.8);transform-origin:100% 100%}.plyr__controls>.plyr__control:last-child .plyr__tooltip:before{left:auto;right:16px;right:calc(var(--plyr-control-icon-size, 18px)/2 + var(--plyr-control-spacing, 10px)*.7);transform:translateX(50%)}.plyr__controls>.plyr__control:first-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control:focus-visible .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control:hover .plyr__tooltip,.plyr__controls>.plyr__control:first-child:focus-visible .plyr__tooltip,.plyr__controls>.plyr__control:first-child:hover .plyr__tooltip,.plyr__controls>.plyr__control:last-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:last-child:focus-visible .plyr__tooltip,.plyr__controls>.plyr__control:last-child:hover .plyr__tooltip{transform:translate(0) scale(1)}.plyr__progress{left:6.5px;left:calc(var(--plyr-range-thumb-height, 13px)*.5);margin-right:13px;margin-right:var(--plyr-range-thumb-height,13px);position:relative}.plyr__progress input[type=range],.plyr__progress__buffer{margin-left:-6.5px;margin-left:calc(var(--plyr-range-thumb-height, 13px)*-.5);margin-right:-6.5px;margin-right:calc(var(--plyr-range-thumb-height, 13px)*-.5);width:calc(100% + 13px);width:calc(100% + var(--plyr-range-thumb-height, 13px))}.plyr__progress input[type=range]{position:relative;z-index:2}.plyr__progress .plyr__tooltip{left:0;max-width:120px;overflow-wrap:break-word}.plyr__progress__buffer{-webkit-appearance:none;background:#0000;border:0;border-radius:100px;height:5px;height:var(--plyr-range-track-height,5px);left:0;margin-top:-2.5px;margin-top:calc(var(--plyr-range-track-height, 5px)/2*-1);padding:0;position:absolute;top:50%}.plyr__progress__buffer::-webkit-progress-bar{background:#0000}.plyr__progress__buffer::-webkit-progress-value{background:currentColor;border-radius:100px;min-width:5px;min-width:var(--plyr-range-track-height,5px);-webkit-transition:width .2s ease;transition:width .2s ease}.plyr__progress__buffer::-moz-progress-bar{background:currentColor;border-radius:100px;min-width:5px;min-width:var(--plyr-range-track-height,5px);-moz-transition:width .2s ease;transition:width .2s ease}.plyr__progress__buffer::-ms-fill{border-radius:100px;-ms-transition:width .2s ease;transition:width .2s ease}.plyr--loading .plyr__progress__buffer{animation:plyr-progress 1s linear infinite;background-image:linear-gradient(-45deg,#23282f99 25%,#0000 0,#0000 50%,#23282f99 0,#23282f99 75%,#0000 0,#0000);background-image:linear-gradient(-45deg,var(--plyr-progress-loading-background,#23282f99) 25%,#0000 25%,#0000 50%,var(--plyr-progress-loading-background,#23282f99) 50%,var(--plyr-progress-loading-background,#23282f99) 75%,#0000 75%,#0000);background-repeat:repeat-x;background-size:25px 25px;background-size:var(--plyr-progress-loading-size,25px) var(--plyr-progress-loading-size,25px);color:#0000}.plyr--video.plyr--loading .plyr__progress__buffer{background-color:#ffffff40;background-color:var(--plyr-video-progress-buffered-background,#ffffff40)}.plyr--audio.plyr--loading .plyr__progress__buffer{background-color:#c1c8d199;background-color:var(--plyr-audio-progress-buffered-background,#c1c8d199)}.plyr__progress__marker{background-color:#fff;background-color:var(--plyr-progress-marker-background,#fff);border-radius:1px;height:5px;height:var(--plyr-range-track-height,5px);position:absolute;top:50%;transform:translate(-50%,-50%);width:3px;width:var(--plyr-progress-marker-width,3px);z-index:3}.plyr__volume{align-items:center;display:flex;position:relative}.plyr__volume input[type=range]{margin-left:5px;margin-left:calc(var(--plyr-control-spacing, 10px)/2);margin-right:5px;margin-right:calc(var(--plyr-control-spacing, 10px)/2);max-width:90px;min-width:60px;position:relative;z-index:2}.plyr--audio{display:block}.plyr--audio .plyr__controls{background:#fff;background:var(--plyr-audio-controls-background,#fff);border-radius:inherit;color:#4a5464;color:var(--plyr-audio-control-color,#4a5464);padding:10px;padding:var(--plyr-control-spacing,10px)}.plyr--audio .plyr__control:focus-visible,.plyr--audio .plyr__control:hover,.plyr--audio .plyr__control[aria-expanded=true]{background:#00b2ff;background:var(--plyr-audio-control-background-hover,var(--plyr-color-main,var(--plyr-color-main,#00b2ff)));color:#fff;color:var(--plyr-audio-control-color-hover,#fff)}.plyr--full-ui.plyr--audio input[type=range]::-webkit-slider-runnable-track{background-color:#c1c8d199;background-color:var(--plyr-audio-range-track-background,var(--plyr-audio-progress-buffered-background,#c1c8d199))}.plyr--full-ui.plyr--audio input[type=range]::-moz-range-track{background-color:#c1c8d199;background-color:var(--plyr-audio-range-track-background,var(--plyr-audio-progress-buffered-background,#c1c8d199))}.plyr--full-ui.plyr--audio input[type=range]::-ms-track{background-color:#c1c8d199;background-color:var(--plyr-audio-range-track-background,var(--plyr-audio-progress-buffered-background,#c1c8d199))}.plyr--full-ui.plyr--audio input[type=range]:active::-webkit-slider-thumb{box-shadow:0 1px 1px #23282f26,0 0 0 1px #23282f33,0 0 0 3px #23282f1a;box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px #23282f26,0 0 0 1px #23282f33),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,#23282f1a)}.plyr--full-ui.plyr--audio input[type=range]:active::-moz-range-thumb{box-shadow:0 1px 1px #23282f26,0 0 0 1px #23282f33,0 0 0 3px #23282f1a;box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px #23282f26,0 0 0 1px #23282f33),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,#23282f1a)}.plyr--full-ui.plyr--audio input[type=range]:active::-ms-thumb{box-shadow:0 1px 1px #23282f26,0 0 0 1px #23282f33,0 0 0 3px #23282f1a;box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px #23282f26,0 0 0 1px #23282f33),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,#23282f1a)}.plyr--audio .plyr__progress__buffer{color:#c1c8d199;color:var(--plyr-audio-progress-buffered-background,#c1c8d199)}.plyr--video{overflow:hidden}.plyr--video.plyr--menu-open{overflow:visible}.plyr__video-wrapper{background:#000;background:var(--plyr-video-background,var(--plyr-video-background,#000));border-radius:inherit;height:100%;margin:auto;overflow:hidden;position:relative;width:100%}.plyr__video-embed,.plyr__video-wrapper--fixed-ratio{aspect-ratio:16/9}@supports not (aspect-ratio:16/9){.plyr__video-embed,.plyr__video-wrapper--fixed-ratio{height:0;padding-bottom:56.25%;position:relative}}.plyr__video-embed iframe,.plyr__video-wrapper--fixed-ratio video{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.plyr--full-ui .plyr__video-embed>.plyr__video-embed__container{padding-bottom:240%;position:relative;transform:translateY(-38.28125%)}.plyr--video .plyr__controls{background:linear-gradient(#0000,#000c);background:var(--plyr-video-controls-background,linear-gradient(#0000,#000c));border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;bottom:0;color:#fff;color:var(--plyr-video-control-color,#fff);left:0;padding:5px;padding:calc(var(--plyr-control-spacing, 10px)/2);padding-top:20px;padding-top:calc(var(--plyr-control-spacing, 10px)*2);position:absolute;right:0;transition:opacity .4s ease-in-out,transform .4s ease-in-out;z-index:3}@media (min-width:480px){.plyr--video .plyr__controls{padding:10px;padding:var(--plyr-control-spacing,10px);padding-top:35px;padding-top:calc(var(--plyr-control-spacing, 10px)*3.5)}}.plyr--video.plyr--hide-controls .plyr__controls{opacity:0;pointer-events:none;transform:translateY(100%)}.plyr--video .plyr__control:focus-visible,.plyr--video .plyr__control:hover,.plyr--video .plyr__control[aria-expanded=true]{background:#00b2ff;background:var(--plyr-video-control-background-hover,var(--plyr-color-main,var(--plyr-color-main,#00b2ff)));color:#fff;color:var(--plyr-video-control-color-hover,#fff)}.plyr__control--overlaid{background:#00b2ff;background:var(--plyr-video-control-background-hover,var(--plyr-color-main,var(--plyr-color-main,#00b2ff)));border:0;border-radius:100%;color:#fff;color:var(--plyr-video-control-color,#fff);display:none;left:50%;opacity:.9;padding:15px;padding:calc(var(--plyr-control-spacing, 10px)*1.5);position:absolute;top:50%;transform:translate(-50%,-50%);transition:.3s;z-index:2}.plyr__control--overlaid svg{left:2px;position:relative}.plyr__control--overlaid:focus,.plyr__control--overlaid:hover{opacity:1}.plyr--playing .plyr__control--overlaid{opacity:0;visibility:hidden}.plyr--full-ui.plyr--video .plyr__control--overlaid{display:block}.plyr--full-ui.plyr--video input[type=range]::-webkit-slider-runnable-track{background-color:#ffffff40;background-color:var(--plyr-video-range-track-background,var(--plyr-video-progress-buffered-background,#ffffff40))}.plyr--full-ui.plyr--video input[type=range]::-moz-range-track{background-color:#ffffff40;background-color:var(--plyr-video-range-track-background,var(--plyr-video-progress-buffered-background,#ffffff40))}.plyr--full-ui.plyr--video input[type=range]::-ms-track{background-color:#ffffff40;background-color:var(--plyr-video-range-track-background,var(--plyr-video-progress-buffered-background,#ffffff40))}.plyr--full-ui.plyr--video input[type=range]:active::-webkit-slider-thumb{box-shadow:0 1px 1px #23282f26,0 0 0 1px #23282f33,0 0 0 3px #ffffff80;box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px #23282f26,0 0 0 1px #23282f33),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,#ffffff80)}.plyr--full-ui.plyr--video input[type=range]:active::-moz-range-thumb{box-shadow:0 1px 1px #23282f26,0 0 0 1px #23282f33,0 0 0 3px #ffffff80;box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px #23282f26,0 0 0 1px #23282f33),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,#ffffff80)}.plyr--full-ui.plyr--video input[type=range]:active::-ms-thumb{box-shadow:0 1px 1px #23282f26,0 0 0 1px #23282f33,0 0 0 3px #ffffff80;box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px #23282f26,0 0 0 1px #23282f33),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,#ffffff80)}.plyr--video .plyr__progress__buffer{color:#ffffff40;color:var(--plyr-video-progress-buffered-background,#ffffff40)}.plyr:fullscreen{background:#000;border-radius:0!important;height:100%;margin:0;width:100%}.plyr:fullscreen video{height:100%}.plyr:fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:fullscreen.plyr--hide-controls{cursor:none}@media (min-width:1024px){.plyr:fullscreen .plyr__captions{font-size:21px;font-size:var(--plyr-font-size-xlarge,21px)}}.plyr--fullscreen-fallback{background:#000;border-radius:0!important;bottom:0;height:100%;left:0;margin:0;position:fixed;right:0;top:0;width:100%;z-index:10000000}.plyr--fullscreen-fallback video{height:100%}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen{display:block}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr--fullscreen-fallback.plyr--hide-controls{cursor:none}@media (min-width:1024px){.plyr--fullscreen-fallback .plyr__captions{font-size:21px;font-size:var(--plyr-font-size-xlarge,21px)}}.plyr__ads{border-radius:inherit;bottom:0;cursor:pointer;left:0;overflow:hidden;position:absolute;right:0;top:0;z-index:-1}.plyr__ads>div,.plyr__ads>div iframe{height:100%;position:absolute;width:100%}.plyr__ads:after{background:#23282f;border-radius:2px;bottom:10px;bottom:var(--plyr-control-spacing,10px);color:#fff;content:attr(data-badge-text);font-size:11px;padding:2px 6px;pointer-events:none;position:absolute;right:10px;right:var(--plyr-control-spacing,10px);z-index:3}.plyr__ads:empty:after{display:none}.plyr__cues{background:currentColor;display:block;height:5px;height:var(--plyr-range-track-height,5px);left:0;opacity:.8;position:absolute;top:50%;transform:translateY(-50%);width:3px;z-index:3}.plyr__preview-thumb{background-color:#fff;background-color:var(--plyr-tooltip-background,#fff);border-radius:8px;border-radius:var(--plyr-menu-radius,8px);bottom:100%;box-shadow:0 1px 2px #00000026;box-shadow:var(--plyr-tooltip-shadow,0 1px 2px #00000026);margin-bottom:10px;margin-bottom:calc(var(--plyr-control-spacing, 10px)/2*2);opacity:0;padding:3px;pointer-events:none;position:absolute;transform:translateY(10px) scale(.8);transform-origin:50% 100%;transition:transform .2s ease .1s,opacity .2s ease .1s;z-index:2}.plyr__preview-thumb--is-shown{opacity:1;transform:translate(0) scale(1)}.plyr__preview-thumb:before{border-left:4px solid #0000;border-left:var(--plyr-tooltip-arrow-size,4px) solid #0000;border-right:4px solid #0000;border-right:var(--plyr-tooltip-arrow-size,4px) solid #0000;border-top:4px solid #fff;border-top:var(--plyr-tooltip-arrow-size,4px) solid var(--plyr-tooltip-background,#fff);bottom:-4px;bottom:calc(var(--plyr-tooltip-arrow-size, 4px)*-1);content:"";height:0;left:calc(50% + var(--preview-arrow-offset));position:absolute;transform:translateX(-50%);width:0;z-index:2}.plyr__preview-thumb__image-container{background:#c1c8d1;border-radius:7px;border-radius:calc(var(--plyr-menu-radius, 8px) - 1px);overflow:hidden;position:relative;z-index:0}.plyr__preview-thumb__image-container img,.plyr__preview-thumb__image-container:after{height:100%;left:0;position:absolute;top:0;width:100%}.plyr__preview-thumb__image-container:after{border-radius:inherit;box-shadow:inset 0 0 0 1px #00000026;content:"";pointer-events:none}.plyr__preview-thumb__image-container img{max-height:none;max-width:none}.plyr__preview-thumb__time-container{background:linear-gradient(#0000,#000000bf);background:var(--plyr-video-controls-background,linear-gradient(#0000,#000000bf));border-bottom-left-radius:7px;border-bottom-left-radius:calc(var(--plyr-menu-radius, 8px) - 1px);border-bottom-right-radius:7px;border-bottom-right-radius:calc(var(--plyr-menu-radius, 8px) - 1px);bottom:0;left:0;line-height:1.1;padding:20px 6px 6px;position:absolute;right:0;z-index:3}.plyr__preview-thumb__time-container span{color:#fff;font-size:13px;font-size:var(--plyr-font-size-time,var(--plyr-font-size-small,13px))}.plyr__preview-scrubbing{bottom:0;filter:blur(1px);height:100%;left:0;margin:auto;opacity:0;overflow:hidden;pointer-events:none;position:absolute;right:0;top:0;transition:opacity .3s ease;width:100%;z-index:1}.plyr__preview-scrubbing--is-shown{opacity:1}.plyr__preview-scrubbing img{height:100%;left:0;max-height:none;max-width:none;object-fit:contain;position:absolute;top:0;width:100%}.plyr--no-transition{transition:none!important}.plyr__sr-only{clip:rect(1px,1px,1px,1px);border:0!important;height:1px!important;overflow:hidden;padding:0!important;position:absolute!important;width:1px!important}.plyr [hidden]{display:none!important} \ No newline at end of file +@keyframes plyr-progress{to{background-position:25px 0;background-position:var(--plyr-progress-loading-size,25px) 0}}@keyframes plyr-popup{0%{opacity:.5;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes plyr-fade-in{from{opacity:0}to{opacity:1}}.plyr{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;align-items:center;direction:ltr;display:flex;flex-direction:column;font-family:inherit;font-family:var(--plyr-font-family,inherit);font-variant-numeric:tabular-nums;font-weight:400;font-weight:var(--plyr-font-weight-regular,400);height:100%;line-height:1.7;line-height:var(--plyr-line-height,1.7);max-width:100%;min-width:200px;position:relative;text-shadow:none;transition:box-shadow .3s ease;z-index:0}.plyr audio,.plyr iframe,.plyr video{display:block;height:100%;width:100%}.plyr button{font:inherit;line-height:inherit;width:auto}.plyr:focus{outline:0}.plyr--full-ui{box-sizing:border-box}.plyr--full-ui *,.plyr--full-ui ::after,.plyr--full-ui ::before{box-sizing:inherit}.plyr--full-ui a,.plyr--full-ui button,.plyr--full-ui input,.plyr--full-ui label{touch-action:manipulation}.plyr__badge{background:#4a5464;background:var(--plyr-badge-background,#4a5464);border-radius:2px;border-radius:var(--plyr-badge-border-radius,2px);color:#fff;color:var(--plyr-badge-text-color,#fff);font-size:9px;font-size:var(--plyr-font-size-badge,9px);line-height:1;padding:3px 4px}.plyr--full-ui ::-webkit-media-text-track-container{display:none}.plyr__captions{animation:plyr-fade-in .3s ease;bottom:0;display:none;font-size:13px;font-size:var(--plyr-font-size-small,13px);left:0;padding:10px;padding:var(--plyr-control-spacing,10px);position:absolute;text-align:center;transition:transform .4s ease-in-out;width:100%}.plyr__captions span:empty{display:none}@media (min-width:480px){.plyr__captions{font-size:15px;font-size:var(--plyr-font-size-base,15px);padding:calc(10px * 2);padding:calc(var(--plyr-control-spacing,10px) * 2)}}@media (min-width:768px){.plyr__captions{font-size:18px;font-size:var(--plyr-font-size-large,18px)}}.plyr--captions-active .plyr__captions{display:block}.plyr:not(.plyr--hide-controls) .plyr__controls:not(:empty)~.plyr__captions{transform:translateY(calc(10px * -4));transform:translateY(calc(var(--plyr-control-spacing,10px) * -4))}.plyr__caption{background:rgba(0,0,0,.8);background:var(--plyr-captions-background,rgba(0,0,0,.8));border-radius:2px;-webkit-box-decoration-break:clone;box-decoration-break:clone;color:#fff;color:var(--plyr-captions-text-color,#fff);line-height:185%;padding:.2em .5em;white-space:pre-wrap}.plyr__caption div{display:inline}.plyr__control{background:0 0;border:0;border-radius:3px;border-radius:var(--plyr-control-radius,3px);color:inherit;cursor:pointer;flex-shrink:0;overflow:visible;padding:calc(10px * .7);padding:calc(var(--plyr-control-spacing,10px) * .7);position:relative;transition:all .3s ease}.plyr__control svg{display:block;fill:currentColor;height:18px;height:var(--plyr-control-icon-size,18px);pointer-events:none;width:18px;width:var(--plyr-control-icon-size,18px)}.plyr__control:focus{outline:0}.plyr__control.plyr__tab-focus{outline-color:#00b3ff;outline-color:var(--plyr-tab-focus-color,var(--plyr-color-main,var(--plyr-color-main,#00b3ff)));outline-offset:2px;outline-style:dotted;outline-width:3px}a.plyr__control{text-decoration:none}a.plyr__control::after,a.plyr__control::before{display:none}.plyr__control.plyr__control--pressed .icon--not-pressed,.plyr__control.plyr__control--pressed .label--not-pressed,.plyr__control:not(.plyr__control--pressed) .icon--pressed,.plyr__control:not(.plyr__control--pressed) .label--pressed{display:none}.plyr--full-ui ::-webkit-media-controls{display:none}.plyr__controls{align-items:center;display:flex;justify-content:flex-end;text-align:center}.plyr__controls .plyr__progress__container{flex:1;min-width:0}.plyr__controls .plyr__controls__item{margin-left:calc(10px / 4);margin-left:calc(var(--plyr-control-spacing,10px)/ 4)}.plyr__controls .plyr__controls__item:first-child{margin-left:0;margin-right:auto}.plyr__controls .plyr__controls__item.plyr__progress__container{padding-left:calc(10px / 4);padding-left:calc(var(--plyr-control-spacing,10px)/ 4)}.plyr__controls .plyr__controls__item.plyr__time{padding:0 calc(10px / 2);padding:0 calc(var(--plyr-control-spacing,10px)/ 2)}.plyr__controls .plyr__controls__item.plyr__progress__container:first-child,.plyr__controls .plyr__controls__item.plyr__time+.plyr__time,.plyr__controls .plyr__controls__item.plyr__time:first-child{padding-left:0}.plyr__controls:empty{display:none}.plyr [data-plyr=airplay],.plyr [data-plyr=captions],.plyr [data-plyr=fullscreen],.plyr [data-plyr=pip]{display:none}.plyr--airplay-supported [data-plyr=airplay],.plyr--captions-enabled [data-plyr=captions],.plyr--fullscreen-enabled [data-plyr=fullscreen],.plyr--pip-supported [data-plyr=pip]{display:inline-block}.plyr__menu{display:flex;position:relative}.plyr__menu .plyr__control svg{transition:transform .3s ease}.plyr__menu .plyr__control[aria-expanded=true] svg{transform:rotate(90deg)}.plyr__menu .plyr__control[aria-expanded=true] .plyr__tooltip{display:none}.plyr__menu__container{animation:plyr-popup .2s ease;background:rgba(255,255,255,.9);background:var(--plyr-menu-background,rgba(255,255,255,.9));border-radius:4px;bottom:100%;box-shadow:0 1px 2px rgba(0,0,0,.15);box-shadow:var(--plyr-menu-shadow,0 1px 2px rgba(0,0,0,.15));color:#4a5464;color:var(--plyr-menu-color,#4a5464);font-size:15px;font-size:var(--plyr-font-size-base,15px);margin-bottom:10px;position:absolute;right:-3px;text-align:left;white-space:nowrap;z-index:3}.plyr__menu__container>div{overflow:hidden;transition:height .35s cubic-bezier(.4,0,.2,1),width .35s cubic-bezier(.4,0,.2,1)}.plyr__menu__container::after{border:4px solid transparent;border:var(--plyr-menu-arrow-size,4px) solid transparent;border-top-color:rgba(255,255,255,.9);border-top-color:var(--plyr-menu-background,rgba(255,255,255,.9));content:'';height:0;position:absolute;right:calc(((18px / 2) + calc(10px * .7)) - (4px / 2));right:calc(((var(--plyr-control-icon-size,18px)/ 2) + calc(var(--plyr-control-spacing,10px) * .7)) - (var(--plyr-menu-arrow-size,4px)/ 2));top:100%;width:0}.plyr__menu__container [role=menu]{padding:calc(10px * .7);padding:calc(var(--plyr-control-spacing,10px) * .7)}.plyr__menu__container [role=menucaptions]{padding:calc(10px * .7);padding:calc(var(--plyr-control-spacing,10px) * .7);max-height:320px;overflow-y:auto}.plyr__menu__container [role=menuitem],.plyr__menu__container [role=menuitemradio]{margin-top:2px}.plyr__menu__container [role=menuitem]:first-child,.plyr__menu__container [role=menuitemradio]:first-child{margin-top:0}.plyr__menu__container .plyr__control{align-items:center;color:#4a5464;color:var(--plyr-menu-color,#4a5464);display:flex;font-size:13px;font-size:var(--plyr-font-size-menu,var(--plyr-font-size-small,13px));padding-bottom:calc(calc(10px * .7)/ 1.5);padding-bottom:calc(calc(var(--plyr-control-spacing,10px) * .7)/ 1.5);padding-left:calc(calc(10px * .7) * 1.5);padding-left:calc(calc(var(--plyr-control-spacing,10px) * .7) * 1.5);padding-right:calc(calc(10px * .7) * 1.5);padding-right:calc(calc(var(--plyr-control-spacing,10px) * .7) * 1.5);padding-top:calc(calc(10px * .7)/ 1.5);padding-top:calc(calc(var(--plyr-control-spacing,10px) * .7)/ 1.5);-webkit-user-select:none;-ms-user-select:none;user-select:none;width:100%}.plyr__menu__container .plyr__control>span{align-items:inherit;display:flex;width:100%}.plyr__menu__container .plyr__control::after{border:4px solid transparent;border:var(--plyr-menu-item-arrow-size,4px) solid transparent;content:'';position:absolute;top:50%;transform:translateY(-50%)}.plyr__menu__container .plyr__control--forward{padding-right:calc(calc(10px * .7) * 4);padding-right:calc(calc(var(--plyr-control-spacing,10px) * .7) * 4)}.plyr__menu__container .plyr__control--forward::after{border-left-color:#728197;border-left-color:var(--plyr-menu-arrow-color,#728197);right:calc((calc(10px * .7) * 1.5) - 4px);right:calc((calc(var(--plyr-control-spacing,10px) * .7) * 1.5) - var(--plyr-menu-item-arrow-size,4px))}.plyr__menu__container .plyr__control--forward.plyr__tab-focus::after,.plyr__menu__container .plyr__control--forward:hover::after{border-left-color:currentColor}.plyr__menu__container .plyr__control--back{font-weight:400;font-weight:var(--plyr-font-weight-regular,400);margin:calc(10px * .7);margin:calc(var(--plyr-control-spacing,10px) * .7);margin-bottom:calc(calc(10px * .7)/ 2);margin-bottom:calc(calc(var(--plyr-control-spacing,10px) * .7)/ 2);padding-left:calc(calc(10px * .7) * 4);padding-left:calc(calc(var(--plyr-control-spacing,10px) * .7) * 4);position:relative;width:calc(100% - (calc(10px * .7) * 2));width:calc(100% - (calc(var(--plyr-control-spacing,10px) * .7) * 2))}.plyr__menu__container .plyr__control--back::after{border-right-color:#728197;border-right-color:var(--plyr-menu-arrow-color,#728197);left:calc((calc(10px * .7) * 1.5) - 4px);left:calc((calc(var(--plyr-control-spacing,10px) * .7) * 1.5) - var(--plyr-menu-item-arrow-size,4px))}.plyr__menu__container .plyr__control--back::before{background:#dcdfe5;background:var(--plyr-menu-back-border-color,#dcdfe5);box-shadow:0 1px 0 #fff;box-shadow:0 1px 0 var(--plyr-menu-back-border-shadow-color,#fff);content:'';height:1px;left:0;margin-top:calc(calc(10px * .7)/ 2);margin-top:calc(calc(var(--plyr-control-spacing,10px) * .7)/ 2);overflow:hidden;position:absolute;right:0;top:100%}.plyr__menu__container .plyr__control--back.plyr__tab-focus::after,.plyr__menu__container .plyr__control--back:hover::after{border-right-color:currentColor}.plyr__menu__container .plyr__control[role=menuitemradio]{padding-left:calc(10px * .7);padding-left:calc(var(--plyr-control-spacing,10px) * .7)}.plyr__menu__container .plyr__control[role=menuitemradio]::after,.plyr__menu__container .plyr__control[role=menuitemradio]::before{border-radius:100%}.plyr__menu__container .plyr__control[role=menuitemradio]::before{background:rgba(0,0,0,.1);content:'';display:block;flex-shrink:0;height:16px;margin-right:10px;margin-right:var(--plyr-control-spacing,10px);transition:all .3s ease;width:16px}.plyr__menu__container .plyr__control[role=menuitemradio]::after{background:#fff;border:0;height:6px;left:12px;opacity:0;top:50%;transform:translateY(-50%) scale(0);transition:transform .3s ease,opacity .3s ease;width:6px}.plyr__menu__container .plyr__control[role=menuitemradio][aria-checked=true]::before{background:#00b3ff;background:var(--plyr-control-toggle-checked-background,var(--plyr-color-main,var(--plyr-color-main,#00b3ff)))}.plyr__menu__container .plyr__control[role=menuitemradio][aria-checked=true]::after{opacity:1;transform:translateY(-50%) scale(1)}.plyr__menu__container .plyr__control[role=menuitemradio].plyr__tab-focus::before,.plyr__menu__container .plyr__control[role=menuitemradio]:hover::before{background:rgba(35,40,47,.1)}.plyr__menu__container .plyr__menu__value{align-items:center;display:flex;margin-left:auto;margin-right:calc((calc(10px * .7) - 2) * -1);margin-right:calc((calc(var(--plyr-control-spacing,10px) * .7) - 2) * -1);overflow:hidden;padding-left:calc(calc(10px * .7) * 3.5);padding-left:calc(calc(var(--plyr-control-spacing,10px) * .7) * 3.5);pointer-events:none}.plyr--full-ui input[type=range]{-webkit-appearance:none;background:0 0;border:0;border-radius:calc(13px * 2);border-radius:calc(var(--plyr-range-thumb-height,13px) * 2);color:#00b3ff;color:var(--plyr-range-fill-background,var(--plyr-color-main,var(--plyr-color-main,#00b3ff)));display:block;height:calc((3px * 2) + 13px);height:calc((var(--plyr-range-thumb-active-shadow-width,3px) * 2) + var(--plyr-range-thumb-height,13px));margin:0;padding:0;transition:box-shadow .3s ease;width:100%}.plyr--full-ui input[type=range]::-webkit-slider-runnable-track{background:0 0;border:0;border-radius:calc(5px / 2);border-radius:calc(var(--plyr-range-track-height,5px)/ 2);height:5px;height:var(--plyr-range-track-height,5px);-webkit-transition:box-shadow .3s ease;transition:box-shadow .3s ease;-webkit-user-select:none;user-select:none;background-image:linear-gradient(to right,currentColor 0,transparent 0);background-image:linear-gradient(to right,currentColor var(--value,0),transparent var(--value,0))}.plyr--full-ui input[type=range]::-webkit-slider-thumb{background:#fff;background:var(--plyr-range-thumb-background,#fff);border:0;border-radius:100%;box-shadow:0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2);box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2));height:13px;height:var(--plyr-range-thumb-height,13px);position:relative;-webkit-transition:all .2s ease;transition:all .2s ease;width:13px;width:var(--plyr-range-thumb-height,13px);-webkit-appearance:none;margin-top:calc(((13px - 5px)/ 2) * -1);margin-top:calc(((var(--plyr-range-thumb-height,13px) - var(--plyr-range-track-height,5px))/ 2) * -1)}.plyr--full-ui input[type=range]::-moz-range-track{background:0 0;border:0;border-radius:calc(5px / 2);border-radius:calc(var(--plyr-range-track-height,5px)/ 2);height:5px;height:var(--plyr-range-track-height,5px);-moz-transition:box-shadow .3s ease;transition:box-shadow .3s ease;user-select:none}.plyr--full-ui input[type=range]::-moz-range-thumb{background:#fff;background:var(--plyr-range-thumb-background,#fff);border:0;border-radius:100%;box-shadow:0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2);box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2));height:13px;height:var(--plyr-range-thumb-height,13px);position:relative;-moz-transition:all .2s ease;transition:all .2s ease;width:13px;width:var(--plyr-range-thumb-height,13px)}.plyr--full-ui input[type=range]::-moz-range-progress{background:currentColor;border-radius:calc(5px / 2);border-radius:calc(var(--plyr-range-track-height,5px)/ 2);height:5px;height:var(--plyr-range-track-height,5px)}.plyr--full-ui input[type=range]::-ms-track{background:0 0;border:0;border-radius:calc(5px / 2);border-radius:calc(var(--plyr-range-track-height,5px)/ 2);height:5px;height:var(--plyr-range-track-height,5px);-ms-transition:box-shadow .3s ease;transition:box-shadow .3s ease;-ms-user-select:none;user-select:none;color:transparent}.plyr--full-ui input[type=range]::-ms-fill-upper{background:0 0;border:0;border-radius:calc(5px / 2);border-radius:calc(var(--plyr-range-track-height,5px)/ 2);height:5px;height:var(--plyr-range-track-height,5px);-ms-transition:box-shadow .3s ease;transition:box-shadow .3s ease;-ms-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-ms-fill-lower{background:0 0;border:0;border-radius:calc(5px / 2);border-radius:calc(var(--plyr-range-track-height,5px)/ 2);height:5px;height:var(--plyr-range-track-height,5px);-ms-transition:box-shadow .3s ease;transition:box-shadow .3s ease;-ms-user-select:none;user-select:none;background:currentColor}.plyr--full-ui input[type=range]::-ms-thumb{background:#fff;background:var(--plyr-range-thumb-background,#fff);border:0;border-radius:100%;box-shadow:0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2);box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2));height:13px;height:var(--plyr-range-thumb-height,13px);position:relative;-ms-transition:all .2s ease;transition:all .2s ease;width:13px;width:var(--plyr-range-thumb-height,13px);margin-top:0}.plyr--full-ui input[type=range]::-ms-tooltip{display:none}.plyr--full-ui input[type=range]:focus{outline:0}.plyr--full-ui input[type=range]::-moz-focus-outer{border:0}.plyr--full-ui input[type=range].plyr__tab-focus::-webkit-slider-runnable-track{outline-color:#00b3ff;outline-color:var(--plyr-tab-focus-color,var(--plyr-color-main,var(--plyr-color-main,#00b3ff)));outline-offset:2px;outline-style:dotted;outline-width:3px}.plyr--full-ui input[type=range].plyr__tab-focus::-moz-range-track{outline-color:#00b3ff;outline-color:var(--plyr-tab-focus-color,var(--plyr-color-main,var(--plyr-color-main,#00b3ff)));outline-offset:2px;outline-style:dotted;outline-width:3px}.plyr--full-ui input[type=range].plyr__tab-focus::-ms-track{outline-color:#00b3ff;outline-color:var(--plyr-tab-focus-color,var(--plyr-color-main,var(--plyr-color-main,#00b3ff)));outline-offset:2px;outline-style:dotted;outline-width:3px}.plyr__poster{background-color:#000;background-position:50% 50%;background-repeat:no-repeat;background-size:contain;height:100%;left:0;opacity:0;position:absolute;top:0;transition:opacity .2s ease;width:100%;z-index:1}.plyr--stopped.plyr__poster-enabled .plyr__poster{opacity:1}.plyr__time{font-size:13px;font-size:var(--plyr-font-size-time,var(--plyr-font-size-small,13px))}.plyr__time+.plyr__time::before{content:'\2044';margin-right:10px;margin-right:var(--plyr-control-spacing,10px)}@media (max-width:calc(768px - 1)){.plyr__time+.plyr__time{display:none}}.plyr__tooltip{background:rgba(255,255,255,.9);background:var(--plyr-tooltip-background,rgba(255,255,255,.9));border-radius:3px;border-radius:var(--plyr-tooltip-radius,3px);bottom:100%;box-shadow:0 1px 2px rgba(0,0,0,.15);box-shadow:var(--plyr-tooltip-shadow,0 1px 2px rgba(0,0,0,.15));color:#4a5464;color:var(--plyr-tooltip-color,#4a5464);font-size:13px;font-size:var(--plyr-font-size-small,13px);font-weight:400;font-weight:var(--plyr-font-weight-regular,400);left:50%;line-height:1.3;margin-bottom:calc(calc(10px / 2) * 2);margin-bottom:calc(calc(var(--plyr-control-spacing,10px)/ 2) * 2);opacity:0;padding:calc(10px / 2) calc(calc(10px / 2) * 1.5);padding:calc(var(--plyr-control-spacing,10px)/ 2) calc(calc(var(--plyr-control-spacing,10px)/ 2) * 1.5);pointer-events:none;position:absolute;transform:translate(-50%,10px) scale(.8);transform-origin:50% 100%;transition:transform .2s .1s ease,opacity .2s .1s ease;white-space:nowrap;z-index:2}.plyr__tooltip::before{border-left:4px solid transparent;border-left:var(--plyr-tooltip-arrow-size,4px) solid transparent;border-right:4px solid transparent;border-right:var(--plyr-tooltip-arrow-size,4px) solid transparent;border-top:4px solid rgba(255,255,255,.9);border-top:var(--plyr-tooltip-arrow-size,4px) solid var(--plyr-tooltip-background,rgba(255,255,255,.9));bottom:calc(4px * -1);bottom:calc(var(--plyr-tooltip-arrow-size,4px) * -1);content:'';height:0;left:50%;position:absolute;transform:translateX(-50%);width:0;z-index:2}.plyr .plyr__control.plyr__tab-focus .plyr__tooltip,.plyr .plyr__control:hover .plyr__tooltip,.plyr__tooltip--visible{opacity:1;transform:translate(-50%,0) scale(1)}.plyr .plyr__control:hover .plyr__tooltip{z-index:3}.plyr__controls>.plyr__control:first-child .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip{left:0;transform:translate(0,10px) scale(.8);transform-origin:0 100%}.plyr__controls>.plyr__control:first-child .plyr__tooltip::before,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip::before{left:calc((18px / 2) + calc(10px * .7));left:calc((var(--plyr-control-icon-size,18px)/ 2) + calc(var(--plyr-control-spacing,10px) * .7))}.plyr__controls>.plyr__control:last-child .plyr__tooltip{left:auto;right:0;transform:translate(0,10px) scale(.8);transform-origin:100% 100%}.plyr__controls>.plyr__control:last-child .plyr__tooltip::before{left:auto;right:calc((18px / 2) + calc(10px * .7));right:calc((var(--plyr-control-icon-size,18px)/ 2) + calc(var(--plyr-control-spacing,10px) * .7));transform:translateX(50%)}.plyr__controls>.plyr__control:first-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control.plyr__tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control:hover .plyr__tooltip,.plyr__controls>.plyr__control:first-child.plyr__tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child:hover .plyr__tooltip,.plyr__controls>.plyr__control:last-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:last-child.plyr__tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:last-child:hover .plyr__tooltip{transform:translate(0,0) scale(1)}.plyr__progress{left:calc(13px * .5);left:calc(var(--plyr-range-thumb-height,13px) * .5);margin-right:13px;margin-right:var(--plyr-range-thumb-height,13px);position:relative}.plyr__progress input[type=range],.plyr__progress__buffer{margin-left:calc(13px * -.5);margin-left:calc(var(--plyr-range-thumb-height,13px) * -.5);margin-right:calc(13px * -.5);margin-right:calc(var(--plyr-range-thumb-height,13px) * -.5);width:calc(100% + 13px);width:calc(100% + var(--plyr-range-thumb-height,13px))}.plyr__progress input[type=range]{position:relative;z-index:2}.plyr__progress .plyr__tooltip{font-size:13px;font-size:var(--plyr-font-size-time,var(--plyr-font-size-small,13px));left:0}.plyr__progress__buffer{-webkit-appearance:none;background:0 0;border:0;border-radius:100px;height:5px;height:var(--plyr-range-track-height,5px);left:0;margin-top:calc((5px / 2) * -1);margin-top:calc((var(--plyr-range-track-height,5px)/ 2) * -1);padding:0;position:absolute;top:50%}.plyr__progress__buffer::-webkit-progress-bar{background:0 0}.plyr__progress__buffer::-webkit-progress-value{background:currentColor;border-radius:100px;min-width:5px;min-width:var(--plyr-range-track-height,5px);-webkit-transition:width .2s ease;transition:width .2s ease}.plyr__progress__buffer::-moz-progress-bar{background:currentColor;border-radius:100px;min-width:5px;min-width:var(--plyr-range-track-height,5px);-moz-transition:width .2s ease;transition:width .2s ease}.plyr__progress__buffer::-ms-fill{border-radius:100px;-ms-transition:width .2s ease;transition:width .2s ease}.plyr--loading .plyr__progress__buffer{animation:plyr-progress 1s linear infinite;background-image:linear-gradient(-45deg,rgba(35,40,47,.6) 25%,transparent 25%,transparent 50%,rgba(35,40,47,.6) 50%,rgba(35,40,47,.6) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,var(--plyr-progress-loading-background,rgba(35,40,47,.6)) 25%,transparent 25%,transparent 50%,var(--plyr-progress-loading-background,rgba(35,40,47,.6)) 50%,var(--plyr-progress-loading-background,rgba(35,40,47,.6)) 75%,transparent 75%,transparent);background-repeat:repeat-x;background-size:25px 25px;background-size:var(--plyr-progress-loading-size,25px) var(--plyr-progress-loading-size,25px);color:transparent}.plyr--video.plyr--loading .plyr__progress__buffer{background-color:rgba(255,255,255,.25);background-color:var(--plyr-video-progress-buffered-background,rgba(255,255,255,.25))}.plyr--audio.plyr--loading .plyr__progress__buffer{background-color:rgba(193,200,209,.6);background-color:var(--plyr-audio-progress-buffered-background,rgba(193,200,209,.6))}.plyr__volume{align-items:center;display:flex;max-width:110px;min-width:80px;position:relative;width:20%}.plyr__volume input[type=range]{margin-left:calc(10px / 2);margin-left:calc(var(--plyr-control-spacing,10px)/ 2);margin-right:calc(10px / 2);margin-right:calc(var(--plyr-control-spacing,10px)/ 2);position:relative;z-index:2}.plyr--is-ios .plyr__volume{min-width:0;width:auto}.plyr--audio{display:block}.plyr--audio .plyr__controls{background:#fff;background:var(--plyr-audio-controls-background,#fff);border-radius:inherit;color:#4a5464;color:var(--plyr-audio-control-color,#4a5464);padding:10px;padding:var(--plyr-control-spacing,10px)}.plyr--audio .plyr__control.plyr__tab-focus,.plyr--audio .plyr__control:hover,.plyr--audio .plyr__control[aria-expanded=true]{background:#00b3ff;background:var(--plyr-audio-control-background-hover,var(--plyr-color-main,var(--plyr-color-main,#00b3ff)));color:#fff;color:var(--plyr-audio-control-color-hover,#fff)}.plyr--full-ui.plyr--audio input[type=range]::-webkit-slider-runnable-track{background-color:rgba(193,200,209,.6);background-color:var(--plyr-audio-range-track-background,var(--plyr-audio-progress-buffered-background,rgba(193,200,209,.6)))}.plyr--full-ui.plyr--audio input[type=range]::-moz-range-track{background-color:rgba(193,200,209,.6);background-color:var(--plyr-audio-range-track-background,var(--plyr-audio-progress-buffered-background,rgba(193,200,209,.6)))}.plyr--full-ui.plyr--audio input[type=range]::-ms-track{background-color:rgba(193,200,209,.6);background-color:var(--plyr-audio-range-track-background,var(--plyr-audio-progress-buffered-background,rgba(193,200,209,.6)))}.plyr--full-ui.plyr--audio input[type=range]:active::-webkit-slider-thumb{box-shadow:0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2),0 0 0 3px rgba(35,40,47,.1);box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2)),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,rgba(35,40,47,.1))}.plyr--full-ui.plyr--audio input[type=range]:active::-moz-range-thumb{box-shadow:0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2),0 0 0 3px rgba(35,40,47,.1);box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2)),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,rgba(35,40,47,.1))}.plyr--full-ui.plyr--audio input[type=range]:active::-ms-thumb{box-shadow:0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2),0 0 0 3px rgba(35,40,47,.1);box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2)),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,rgba(35,40,47,.1))}.plyr--audio .plyr__progress__buffer{color:rgba(193,200,209,.6);color:var(--plyr-audio-progress-buffered-background,rgba(193,200,209,.6))}.plyr--video{background:#000;overflow:hidden}.plyr--video.plyr--menu-open{overflow:visible}.plyr__video-wrapper{background:#000;height:100%;margin:auto;overflow:hidden;position:relative;width:100%}.plyr__video-embed,.plyr__video-wrapper--fixed-ratio{height:0;padding-bottom:56.25%}.plyr__video-embed iframe,.plyr__video-wrapper--fixed-ratio video{border:0;left:0;position:absolute;top:0}.plyr--full-ui .plyr__video-embed>.plyr__video-embed__container{padding-bottom:240%;position:relative;transform:translateY(-38.28125%)}.plyr--video .plyr__controls{background:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.75));background:var(--plyr-video-controls-background,linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.75)));border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;bottom:0;color:#fff;color:var(--plyr-video-control-color,#fff);left:0;padding:calc(10px / 2);padding:calc(var(--plyr-control-spacing,10px)/ 2);padding-top:calc(10px * 2);padding-top:calc(var(--plyr-control-spacing,10px) * 2);position:absolute;right:0;transition:opacity .4s ease-in-out,transform .4s ease-in-out;z-index:3}@media (min-width:480px){.plyr--video .plyr__controls{padding:10px;padding:var(--plyr-control-spacing,10px);padding-top:calc(10px * 3.5);padding-top:calc(var(--plyr-control-spacing,10px) * 3.5)}}.plyr--video.plyr--hide-controls .plyr__controls{opacity:0;pointer-events:none;transform:translateY(100%)}.plyr--video .plyr__control.plyr__tab-focus,.plyr--video .plyr__control:hover,.plyr--video .plyr__control[aria-expanded=true]{background:#00b3ff;background:var(--plyr-video-control-background-hover,var(--plyr-color-main,var(--plyr-color-main,#00b3ff)));color:#fff;color:var(--plyr-video-control-color-hover,#fff)}.plyr__control--overlaid{background:#00b3ff;background:var(--plyr-video-control-background-hover,var(--plyr-color-main,var(--plyr-color-main,#00b3ff)));border:0;border-radius:100%;color:#fff;color:var(--plyr-video-control-color,#fff);display:none;left:50%;opacity:.9;padding:calc(10px * 1.5);padding:calc(var(--plyr-control-spacing,10px) * 1.5);position:absolute;top:50%;transform:translate(-50%,-50%);transition:.3s;z-index:2}.plyr__control--overlaid svg{left:2px;position:relative}.plyr__control--overlaid:focus,.plyr__control--overlaid:hover{opacity:1}.plyr--playing .plyr__control--overlaid{opacity:0;visibility:hidden}.plyr--full-ui.plyr--video .plyr__control--overlaid{display:block}.plyr--full-ui.plyr--video input[type=range]::-webkit-slider-runnable-track{background-color:rgba(255,255,255,.25);background-color:var(--plyr-video-range-track-background,var(--plyr-video-progress-buffered-background,rgba(255,255,255,.25)))}.plyr--full-ui.plyr--video input[type=range]::-moz-range-track{background-color:rgba(255,255,255,.25);background-color:var(--plyr-video-range-track-background,var(--plyr-video-progress-buffered-background,rgba(255,255,255,.25)))}.plyr--full-ui.plyr--video input[type=range]::-ms-track{background-color:rgba(255,255,255,.25);background-color:var(--plyr-video-range-track-background,var(--plyr-video-progress-buffered-background,rgba(255,255,255,.25)))}.plyr--full-ui.plyr--video input[type=range]:active::-webkit-slider-thumb{box-shadow:0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2),0 0 0 3px rgba(255,255,255,.5);box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2)),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,rgba(255,255,255,.5))}.plyr--full-ui.plyr--video input[type=range]:active::-moz-range-thumb{box-shadow:0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2),0 0 0 3px rgba(255,255,255,.5);box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2)),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,rgba(255,255,255,.5))}.plyr--full-ui.plyr--video input[type=range]:active::-ms-thumb{box-shadow:0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2),0 0 0 3px rgba(255,255,255,.5);box-shadow:var(--plyr-range-thumb-shadow,0 1px 1px rgba(35,40,47,.15),0 0 0 1px rgba(35,40,47,.2)),0 0 0 var(--plyr-range-thumb-active-shadow-width,3px) var(--plyr-audio-range-thumb-active-shadow-color,rgba(255,255,255,.5))}.plyr--video .plyr__progress__buffer{color:rgba(255,255,255,.25);color:var(--plyr-video-progress-buffered-background,rgba(255,255,255,.25))}.plyr:-webkit-full-screen{background:#000;border-radius:0!important;height:100%;margin:0;width:100%}.plyr:-ms-fullscreen{background:#000;border-radius:0!important;height:100%;margin:0;width:100%}.plyr:fullscreen{background:#000;border-radius:0!important;height:100%;margin:0;width:100%}.plyr:-webkit-full-screen video{height:100%}.plyr:-ms-fullscreen video{height:100%}.plyr:fullscreen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;position:static}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;position:static}.plyr:fullscreen .plyr__video-wrapper{height:100%;position:static}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;position:relative}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;position:relative}.plyr:fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;position:relative}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-webkit-full-screen.plyr--hide-controls{cursor:none}.plyr:-ms-fullscreen.plyr--hide-controls{cursor:none}.plyr:fullscreen.plyr--hide-controls{cursor:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:21px;font-size:var(--plyr-font-size-xlarge,21px)}.plyr:-ms-fullscreen .plyr__captions{font-size:21px;font-size:var(--plyr-font-size-xlarge,21px)}.plyr:fullscreen .plyr__captions{font-size:21px;font-size:var(--plyr-font-size-xlarge,21px)}}.plyr:-webkit-full-screen{background:#000;border-radius:0!important;height:100%;margin:0;width:100%}.plyr:-webkit-full-screen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;position:static}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;position:relative}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-webkit-full-screen.plyr--hide-controls{cursor:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:21px;font-size:var(--plyr-font-size-xlarge,21px)}}.plyr:-moz-full-screen{background:#000;border-radius:0!important;height:100%;margin:0;width:100%}.plyr:-moz-full-screen video{height:100%}.plyr:-moz-full-screen .plyr__video-wrapper{height:100%;position:static}.plyr:-moz-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;position:relative}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-moz-full-screen.plyr--hide-controls{cursor:none}@media (min-width:1024px){.plyr:-moz-full-screen .plyr__captions{font-size:21px;font-size:var(--plyr-font-size-xlarge,21px)}}.plyr:-ms-fullscreen{background:#000;border-radius:0!important;height:100%;margin:0;width:100%}.plyr:-ms-fullscreen video{height:100%}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;position:static}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;position:relative}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-ms-fullscreen.plyr--hide-controls{cursor:none}@media (min-width:1024px){.plyr:-ms-fullscreen .plyr__captions{font-size:21px;font-size:var(--plyr-font-size-xlarge,21px)}}.plyr--fullscreen-fallback{background:#000;border-radius:0!important;height:100%;margin:0;width:100%;bottom:0;display:block;left:0;position:fixed;right:0;top:0;z-index:10000000}.plyr--fullscreen-fallback video{height:100%}.plyr--fullscreen-fallback .plyr__video-wrapper{height:100%;position:static}.plyr--fullscreen-fallback.plyr--vimeo .plyr__video-wrapper{height:0;position:relative}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen{display:block}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr--fullscreen-fallback.plyr--hide-controls{cursor:none}@media (min-width:1024px){.plyr--fullscreen-fallback .plyr__captions{font-size:21px;font-size:var(--plyr-font-size-xlarge,21px)}}.plyr__ads{border-radius:inherit;bottom:0;cursor:pointer;left:0;overflow:hidden;position:absolute;right:0;top:0;z-index:-1}.plyr__ads>div,.plyr__ads>div iframe{height:100%;position:absolute;width:100%}.plyr__ads::after{background:#23282f;border-radius:2px;bottom:10px;bottom:var(--plyr-control-spacing,10px);color:#fff;content:attr(data-badge-text);font-size:11px;padding:2px 6px;pointer-events:none;position:absolute;right:10px;right:var(--plyr-control-spacing,10px);z-index:3}.plyr__ads::after:empty{display:none}.plyr__cues{background:currentColor;display:block;height:5px;height:var(--plyr-range-track-height,5px);left:0;margin:-var(--plyr-range-track-height,5px)/2 0 0;opacity:.8;position:absolute;top:50%;width:3px;z-index:3}.plyr__preview-thumb{background-color:rgba(255,255,255,.9);background-color:var(--plyr-tooltip-background,rgba(255,255,255,.9));border-radius:3px;bottom:100%;box-shadow:0 1px 2px rgba(0,0,0,.15);box-shadow:var(--plyr-tooltip-shadow,0 1px 2px rgba(0,0,0,.15));margin-bottom:calc(calc(10px / 2) * 2);margin-bottom:calc(calc(var(--plyr-control-spacing,10px)/ 2) * 2);opacity:0;padding:3px;padding:var(--plyr-tooltip-radius,3px);pointer-events:none;position:absolute;transform:translate(0,10px) scale(.8);transform-origin:50% 100%;transition:transform .2s .1s ease,opacity .2s .1s ease;z-index:2}.plyr__preview-thumb--is-shown{opacity:1;transform:translate(0,0) scale(1)}.plyr__preview-thumb::before{border-left:4px solid transparent;border-left:var(--plyr-tooltip-arrow-size,4px) solid transparent;border-right:4px solid transparent;border-right:var(--plyr-tooltip-arrow-size,4px) solid transparent;border-top:4px solid rgba(255,255,255,.9);border-top:var(--plyr-tooltip-arrow-size,4px) solid var(--plyr-tooltip-background,rgba(255,255,255,.9));bottom:calc(4px * -1);bottom:calc(var(--plyr-tooltip-arrow-size,4px) * -1);content:'';height:0;left:50%;position:absolute;transform:translateX(-50%);width:0;z-index:2}.plyr__preview-thumb__image-container{background:#c1c8d1;border-radius:calc(3px - 1px);border-radius:calc(var(--plyr-tooltip-radius,3px) - 1px);overflow:hidden;position:relative;z-index:0}.plyr__preview-thumb__image-container img{height:100%;left:0;max-height:none;max-width:none;position:absolute;top:0;width:100%}.plyr__preview-thumb__time-container{bottom:6px;left:0;position:absolute;right:0;white-space:nowrap;z-index:3}.plyr__preview-thumb__time-container span{background-color:rgba(0,0,0,.55);border-radius:calc(3px - 1px);border-radius:calc(var(--plyr-tooltip-radius,3px) - 1px);color:#fff;font-size:13px;font-size:var(--plyr-font-size-time,var(--plyr-font-size-small,13px));padding:3px 6px}.plyr__preview-scrubbing{bottom:0;filter:blur(1px);height:100%;left:0;margin:auto;opacity:0;overflow:hidden;pointer-events:none;position:absolute;right:0;top:0;transition:opacity .3s ease;width:100%;z-index:1}.plyr__preview-scrubbing--is-shown{opacity:1}.plyr__preview-scrubbing img{height:100%;left:0;max-height:none;max-width:none;object-fit:contain;position:absolute;top:0;width:100%}.plyr--no-transition{transition:none!important}.plyr__sr-only{clip:rect(1px,1px,1px,1px);overflow:hidden;border:0!important;height:1px!important;padding:0!important;position:absolute!important;width:1px!important}.plyr [hidden]{display:none!important} \ No newline at end of file diff --git a/youtube/static/modules/plyr/plyr.js b/youtube/static/modules/plyr/plyr.js index 7d571e5..d5cc84e 100644 --- a/youtube/static/modules/plyr/plyr.js +++ b/youtube/static/modules/plyr/plyr.js @@ -1,25 +1,32 @@ typeof navigator === "object" && (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define('Plyr', factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Plyr = factory()); -})(this, (function () { 'use strict'; - - function _toPrimitive(t, r) { - if ("object" != typeof t || !t) return t; - var e = t[Symbol.toPrimitive]; - if (void 0 !== e) { - var i = e.call(t, r || "default"); - if ("object" != typeof i) return i; - throw new TypeError("@@toPrimitive must return a primitive value."); + (global = global || self, global.Plyr = factory()); +}(this, (function () { 'use strict'; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); } - return ("string" === r ? String : Number)(t); } - function _toPropertyKey(t) { - var i = _toPrimitive(t, "string"); - return "symbol" == typeof i ? i : String(i); + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; } - function _defineProperty$1(obj, key, value) { - key = _toPropertyKey(key); + + function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, @@ -30,22 +37,168 @@ typeof navigator === "object" && (function (global, factory) { } else { obj[key] = value; } + return obj; } - function _classCallCheck(e, t) { + function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + if (enumerableOnly) symbols = symbols.filter(function (sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + }); + keys.push.apply(keys, symbols); + } + + return keys; + } + + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + + if (i % 2) { + ownKeys(Object(source), true).forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } else if (Object.getOwnPropertyDescriptors) { + Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); + } else { + ownKeys(Object(source)).forEach(function (key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + } + + return target; + } + + function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + + return target; + } + + function _objectWithoutProperties(source, excluded) { + if (source == null) return {}; + + var target = _objectWithoutPropertiesLoose(source, excluded); + + var key, i; + + if (Object.getOwnPropertySymbols) { + var sourceSymbolKeys = Object.getOwnPropertySymbols(source); + + for (i = 0; i < sourceSymbolKeys.length; i++) { + key = sourceSymbolKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } + } + + return target; + } + + function _slicedToArray(arr, i) { + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); + } + + function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); + } + + function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) return _arrayLikeToArray(arr); + } + + function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; + } + + function _iterableToArray(iter) { + if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); + } + + function _iterableToArrayLimit(arr, i) { + if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; + } + } + + return _arr; + } + + function _unsupportedIterableToArray(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); + } + + function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) len = arr.length; + + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + + return arr2; + } + + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + + function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + + function _classCallCheck$1(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function"); } - function _defineProperties(e, t) { + + function _defineProperties$1(e, t) { for (var n = 0; n < t.length; n++) { var r = t[n]; r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), Object.defineProperty(e, r.key, r); } } - function _createClass(e, t, n) { - return t && _defineProperties(e.prototype, t), n && _defineProperties(e, n), e; + + function _createClass$1(e, t, n) { + return t && _defineProperties$1(e.prototype, t), n && _defineProperties$1(e, n), e; } - function _defineProperty(e, t, n) { + + function _defineProperty$1(e, t, n) { return t in e ? Object.defineProperty(e, t, { value: n, enumerable: !0, @@ -53,37 +206,45 @@ typeof navigator === "object" && (function (global, factory) { writable: !0 }) : e[t] = n, e; } - function ownKeys(e, t) { + + function ownKeys$1(e, t) { var n = Object.keys(e); + if (Object.getOwnPropertySymbols) { var r = Object.getOwnPropertySymbols(e); t && (r = r.filter(function (t) { return Object.getOwnPropertyDescriptor(e, t).enumerable; })), n.push.apply(n, r); } + return n; } - function _objectSpread2(e) { + + function _objectSpread2$1(e) { for (var t = 1; t < arguments.length; t++) { var n = null != arguments[t] ? arguments[t] : {}; - t % 2 ? ownKeys(Object(n), !0).forEach(function (t) { - _defineProperty(e, t, n[t]); - }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : ownKeys(Object(n)).forEach(function (t) { + t % 2 ? ownKeys$1(Object(n), !0).forEach(function (t) { + _defineProperty$1(e, t, n[t]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : ownKeys$1(Object(n)).forEach(function (t) { Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(n, t)); }); } + return e; } - var defaults$1 = { + + var defaults = { addCSS: !0, thumbWidth: 15, watch: !0 }; - function matches$1(e, t) { + + function matches(e, t) { return function () { return Array.from(document.querySelectorAll(t)).includes(this); }.call(e, t); } + function trigger(e, t) { if (e && t) { var n = new Event(t, { @@ -92,88 +253,94 @@ typeof navigator === "object" && (function (global, factory) { e.dispatchEvent(n); } } - var getConstructor$1 = function (e) { - return null != e ? e.constructor : null; - }, - instanceOf$1 = function (e, t) { - return !!(e && t && e instanceof t); - }, - isNullOrUndefined$1 = function (e) { - return null == e; - }, - isObject$1 = function (e) { - return getConstructor$1(e) === Object; - }, - isNumber$1 = function (e) { - return getConstructor$1(e) === Number && !Number.isNaN(e); - }, - isString$1 = function (e) { - return getConstructor$1(e) === String; - }, - isBoolean$1 = function (e) { - return getConstructor$1(e) === Boolean; - }, - isFunction$1 = function (e) { - return getConstructor$1(e) === Function; - }, - isArray$1 = function (e) { - return Array.isArray(e); - }, - isNodeList$1 = function (e) { - return instanceOf$1(e, NodeList); - }, - isElement$1 = function (e) { - return instanceOf$1(e, Element); - }, - isEvent$1 = function (e) { - return instanceOf$1(e, Event); - }, - isEmpty$1 = function (e) { - return isNullOrUndefined$1(e) || (isString$1(e) || isArray$1(e) || isNodeList$1(e)) && !e.length || isObject$1(e) && !Object.keys(e).length; - }, - is$1 = { - nullOrUndefined: isNullOrUndefined$1, - object: isObject$1, - number: isNumber$1, - string: isString$1, - boolean: isBoolean$1, - function: isFunction$1, - array: isArray$1, - nodeList: isNodeList$1, - element: isElement$1, - event: isEvent$1, - empty: isEmpty$1 - }; + + var getConstructor = function getConstructor(e) { + return null != e ? e.constructor : null; + }, + instanceOf = function instanceOf(e, t) { + return !!(e && t && e instanceof t); + }, + isNullOrUndefined = function isNullOrUndefined(e) { + return null == e; + }, + isObject = function isObject(e) { + return getConstructor(e) === Object; + }, + isNumber = function isNumber(e) { + return getConstructor(e) === Number && !Number.isNaN(e); + }, + isString = function isString(e) { + return getConstructor(e) === String; + }, + isBoolean = function isBoolean(e) { + return getConstructor(e) === Boolean; + }, + isFunction = function isFunction(e) { + return getConstructor(e) === Function; + }, + isArray = function isArray(e) { + return Array.isArray(e); + }, + isNodeList = function isNodeList(e) { + return instanceOf(e, NodeList); + }, + isElement = function isElement(e) { + return instanceOf(e, Element); + }, + isEvent = function isEvent(e) { + return instanceOf(e, Event); + }, + isEmpty = function isEmpty(e) { + return isNullOrUndefined(e) || (isString(e) || isArray(e) || isNodeList(e)) && !e.length || isObject(e) && !Object.keys(e).length; + }, + is = { + nullOrUndefined: isNullOrUndefined, + object: isObject, + number: isNumber, + string: isString, + boolean: isBoolean, + function: isFunction, + array: isArray, + nodeList: isNodeList, + element: isElement, + event: isEvent, + empty: isEmpty + }; + function getDecimalPlaces(e) { var t = "".concat(e).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); return t ? Math.max(0, (t[1] ? t[1].length : 0) - (t[2] ? +t[2] : 0)) : 0; } + function round(e, t) { if (1 > t) { var n = getDecimalPlaces(t); return parseFloat(e.toFixed(n)); } + return Math.round(e / t) * t; } + var RangeTouch = function () { function e(t, n) { - _classCallCheck(this, e), is$1.element(t) ? this.element = t : is$1.string(t) && (this.element = document.querySelector(t)), is$1.element(this.element) && is$1.empty(this.element.rangeTouch) && (this.config = _objectSpread2({}, defaults$1, {}, n), this.init()); + _classCallCheck$1(this, e), is.element(t) ? this.element = t : is.string(t) && (this.element = document.querySelector(t)), is.element(this.element) && is.empty(this.element.rangeTouch) && (this.config = _objectSpread2$1({}, defaults, {}, n), this.init()); } - return _createClass(e, [{ + + return _createClass$1(e, [{ key: "init", - value: function () { + value: function value() { e.enabled && (this.config.addCSS && (this.element.style.userSelect = "none", this.element.style.webKitUserSelect = "none", this.element.style.touchAction = "manipulation"), this.listeners(!0), this.element.rangeTouch = this); } }, { key: "destroy", - value: function () { + value: function value() { e.enabled && (this.config.addCSS && (this.element.style.userSelect = "", this.element.style.webKitUserSelect = "", this.element.style.touchAction = ""), this.listeners(!1), this.element.rangeTouch = null); } }, { key: "listeners", - value: function (e) { + value: function value(e) { var t = this, - n = e ? "addEventListener" : "removeEventListener"; + n = e ? "addEventListener" : "removeEventListener"; ["touchstart", "touchmove", "touchend"].forEach(function (e) { t.element[n](e, function (e) { return t.set(e); @@ -182,35 +349,37 @@ typeof navigator === "object" && (function (global, factory) { } }, { key: "get", - value: function (t) { - if (!e.enabled || !is$1.event(t)) return null; + value: function value(t) { + if (!e.enabled || !is.event(t)) return null; var n, - r = t.target, - i = t.changedTouches[0], - o = parseFloat(r.getAttribute("min")) || 0, - s = parseFloat(r.getAttribute("max")) || 100, - u = parseFloat(r.getAttribute("step")) || 1, - c = r.getBoundingClientRect(), - a = 100 / c.width * (this.config.thumbWidth / 2) / 100; + r = t.target, + i = t.changedTouches[0], + o = parseFloat(r.getAttribute("min")) || 0, + s = parseFloat(r.getAttribute("max")) || 100, + u = parseFloat(r.getAttribute("step")) || 1, + c = r.getBoundingClientRect(), + a = 100 / c.width * (this.config.thumbWidth / 2) / 100; return 0 > (n = 100 / c.width * (i.clientX - c.left)) ? n = 0 : 100 < n && (n = 100), 50 > n ? n -= (100 - 2 * n) * a : 50 < n && (n += 2 * (n - 50) * a), o + round(n / 100 * (s - o), u); } }, { key: "set", - value: function (t) { - e.enabled && is$1.event(t) && !t.target.disabled && (t.preventDefault(), t.target.value = this.get(t), trigger(t.target, "touchend" === t.type ? "change" : "input")); + value: function value(t) { + e.enabled && is.event(t) && !t.target.disabled && (t.preventDefault(), t.target.value = this.get(t), trigger(t.target, "touchend" === t.type ? "change" : "input")); } }], [{ key: "setup", - value: function (t) { + value: function value(t) { var n = 1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : {}, - r = null; - if (is$1.empty(t) || is$1.string(t) ? r = Array.from(document.querySelectorAll(is$1.string(t) ? t : 'input[type="range"]')) : is$1.element(t) ? r = [t] : is$1.nodeList(t) ? r = Array.from(t) : is$1.array(t) && (r = t.filter(is$1.element)), is$1.empty(r)) return null; - var i = _objectSpread2({}, defaults$1, {}, n); - if (is$1.string(t) && i.watch) { + r = null; + if (is.empty(t) || is.string(t) ? r = Array.from(document.querySelectorAll(is.string(t) ? t : 'input[type="range"]')) : is.element(t) ? r = [t] : is.nodeList(t) ? r = Array.from(t) : is.array(t) && (r = t.filter(is.element)), is.empty(r)) return null; + + var i = _objectSpread2$1({}, defaults, {}, n); + + if (is.string(t) && i.watch) { var o = new MutationObserver(function (n) { Array.from(n).forEach(function (n) { Array.from(n.addedNodes).forEach(function (n) { - is$1.element(n) && matches$1(n, t) && new e(n, i); + is.element(n) && matches(n, t) && new e(n, i); }); }); }); @@ -219,13 +388,14 @@ typeof navigator === "object" && (function (global, factory) { subtree: !0 }); } + return r.map(function (t) { return new e(t, n); }); } }, { key: "enabled", - get: function () { + get: function get() { return "ontouchstart" in document.documentElement; } }]), e; @@ -234,99 +404,153 @@ typeof navigator === "object" && (function (global, factory) { // ========================================================================== // Type checking utils // ========================================================================== + var getConstructor$1 = function getConstructor(input) { + return input !== null && typeof input !== 'undefined' ? input.constructor : null; + }; + + var instanceOf$1 = function instanceOf(input, constructor) { + return Boolean(input && constructor && input instanceof constructor); + }; + + var isNullOrUndefined$1 = function isNullOrUndefined(input) { + return input === null || typeof input === 'undefined'; + }; + + var isObject$1 = function isObject(input) { + return getConstructor$1(input) === Object; + }; + + var isNumber$1 = function isNumber(input) { + return getConstructor$1(input) === Number && !Number.isNaN(input); + }; + + var isString$1 = function isString(input) { + return getConstructor$1(input) === String; + }; + + var isBoolean$1 = function isBoolean(input) { + return getConstructor$1(input) === Boolean; + }; - const getConstructor = input => input !== null && typeof input !== 'undefined' ? input.constructor : null; - const instanceOf = (input, constructor) => Boolean(input && constructor && input instanceof constructor); - const isNullOrUndefined = input => input === null || typeof input === 'undefined'; - const isObject = input => getConstructor(input) === Object; - const isNumber = input => getConstructor(input) === Number && !Number.isNaN(input); - const isString = input => getConstructor(input) === String; - const isBoolean = input => getConstructor(input) === Boolean; - const isFunction = input => typeof input === 'function'; - const isArray = input => Array.isArray(input); - const isWeakMap = input => instanceOf(input, WeakMap); - const isNodeList = input => instanceOf(input, NodeList); - const isTextNode = input => getConstructor(input) === Text; - const isEvent = input => instanceOf(input, Event); - const isKeyboardEvent = input => instanceOf(input, KeyboardEvent); - const isCue = input => instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue); - const isTrack = input => instanceOf(input, TextTrack) || !isNullOrUndefined(input) && isString(input.kind); - const isPromise = input => instanceOf(input, Promise) && isFunction(input.then); - const isElement = input => input !== null && typeof input === 'object' && input.nodeType === 1 && typeof input.style === 'object' && typeof input.ownerDocument === 'object'; - const isEmpty = input => isNullOrUndefined(input) || (isString(input) || isArray(input) || isNodeList(input)) && !input.length || isObject(input) && !Object.keys(input).length; - const isUrl = input => { + var isFunction$1 = function isFunction(input) { + return getConstructor$1(input) === Function; + }; + + var isArray$1 = function isArray(input) { + return Array.isArray(input); + }; + + var isWeakMap = function isWeakMap(input) { + return instanceOf$1(input, WeakMap); + }; + + var isNodeList$1 = function isNodeList(input) { + return instanceOf$1(input, NodeList); + }; + + var isElement$1 = function isElement(input) { + return instanceOf$1(input, Element); + }; + + var isTextNode = function isTextNode(input) { + return getConstructor$1(input) === Text; + }; + + var isEvent$1 = function isEvent(input) { + return instanceOf$1(input, Event); + }; + + var isKeyboardEvent = function isKeyboardEvent(input) { + return instanceOf$1(input, KeyboardEvent); + }; + + var isCue = function isCue(input) { + return instanceOf$1(input, window.TextTrackCue) || instanceOf$1(input, window.VTTCue); + }; + + var isTrack = function isTrack(input) { + return instanceOf$1(input, TextTrack) || !isNullOrUndefined$1(input) && isString$1(input.kind); + }; + + var isPromise = function isPromise(input) { + return instanceOf$1(input, Promise) && isFunction$1(input.then); + }; + + var isEmpty$1 = function isEmpty(input) { + return isNullOrUndefined$1(input) || (isString$1(input) || isArray$1(input) || isNodeList$1(input)) && !input.length || isObject$1(input) && !Object.keys(input).length; + }; + + var isUrl = function isUrl(input) { // Accept a URL object - if (instanceOf(input, window.URL)) { + if (instanceOf$1(input, window.URL)) { return true; - } + } // Must be string from here + - // Must be string from here - if (!isString(input)) { + if (!isString$1(input)) { return false; - } + } // Add the protocol if required + + + var string = input; - // Add the protocol if required - let string = input; if (!input.startsWith('http://') || !input.startsWith('https://')) { - string = `http://${input}`; + string = "http://".concat(input); } + try { - return !isEmpty(new URL(string).hostname); - } catch (_) { + return !isEmpty$1(new URL(string).hostname); + } catch (e) { return false; } }; - var is = { - nullOrUndefined: isNullOrUndefined, - object: isObject, - number: isNumber, - string: isString, - boolean: isBoolean, - function: isFunction, - array: isArray, + + var is$1 = { + nullOrUndefined: isNullOrUndefined$1, + object: isObject$1, + number: isNumber$1, + string: isString$1, + boolean: isBoolean$1, + function: isFunction$1, + array: isArray$1, weakMap: isWeakMap, - nodeList: isNodeList, - element: isElement, + nodeList: isNodeList$1, + element: isElement$1, textNode: isTextNode, - event: isEvent, + event: isEvent$1, keyboardEvent: isKeyboardEvent, cue: isCue, track: isTrack, promise: isPromise, url: isUrl, - empty: isEmpty + empty: isEmpty$1 }; // ========================================================================== - // Animation utils - // ========================================================================== - - const transitionEndEvent = (() => { - const element = document.createElement('span'); - const events = { + var transitionEndEvent = function () { + var element = document.createElement('span'); + var events = { WebkitTransition: 'webkitTransitionEnd', MozTransition: 'transitionend', OTransition: 'oTransitionEnd otransitionend', transition: 'transitionend' }; - const type = Object.keys(events).find(event => element.style[event] !== undefined); - return is.string(type) ? events[type] : false; - })(); + var type = Object.keys(events).find(function (event) { + return element.style[event] !== undefined; + }); + return is$1.string(type) ? events[type] : false; + }(); // Force repaint of element - // Force repaint of element function repaint(element, delay) { - setTimeout(() => { + setTimeout(function () { try { // eslint-disable-next-line no-param-reassign - element.hidden = true; + element.hidden = true; // eslint-disable-next-line no-unused-expressions - // eslint-disable-next-line no-unused-expressions - element.offsetHeight; + element.offsetHeight; // eslint-disable-next-line no-param-reassign - // eslint-disable-next-line no-param-reassign element.hidden = false; - } catch (_) { - // Do nothing + } catch (e) {// Do nothing } }, delay); } @@ -335,202 +559,212 @@ typeof navigator === "object" && (function (global, factory) { // Browser sniffing // Unfortunately, due to mixed support, UA sniffing is required // ========================================================================== - - const isIE = Boolean(window.document.documentMode); - const isEdge = /Edge/g.test(navigator.userAgent); - const isWebKit = 'WebkitAppearance' in document.documentElement.style && !/Edge/g.test(navigator.userAgent); - const isIPhone = /iPhone|iPod/gi.test(navigator.userAgent) && navigator.maxTouchPoints > 1; - // navigator.platform may be deprecated but this check is still required - const isIPadOS = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1; - const isIos = /iPad|iPhone|iPod/gi.test(navigator.userAgent) && navigator.maxTouchPoints > 1; var browser = { - isIE, - isEdge, - isWebKit, - isIPhone, - isIPadOS, - isIos + isIE: + /* @cc_on!@ */ + !!document.documentMode, + isEdge: window.navigator.userAgent.includes('Edge'), + isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent), + isIPhone: /(iPhone|iPod)/gi.test(navigator.platform), + isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform) }; - // ========================================================================== - // Object utils - // ========================================================================== - - - // Clone nested objects function cloneDeep(object) { return JSON.parse(JSON.stringify(object)); - } + } // Get a nested value in an object - // Get a nested value in an object function getDeep(object, path) { - return path.split('.').reduce((obj, key) => obj && obj[key], object); - } + return path.split('.').reduce(function (obj, key) { + return obj && obj[key]; + }, object); + } // Deep extend destination object with N more objects + + function extend() { + var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } - // Deep extend destination object with N more objects - function extend(target = {}, ...sources) { if (!sources.length) { return target; } - const source = sources.shift(); - if (!is.object(source)) { + + var source = sources.shift(); + + if (!is$1.object(source)) { return target; } - Object.keys(source).forEach(key => { - if (is.object(source[key])) { + + Object.keys(source).forEach(function (key) { + if (is$1.object(source[key])) { if (!Object.keys(target).includes(key)) { - Object.assign(target, { - [key]: {} - }); + Object.assign(target, _defineProperty({}, key, {})); } + extend(target[key], source[key]); } else { - Object.assign(target, { - [key]: source[key] - }); + Object.assign(target, _defineProperty({}, key, source[key])); } }); - return extend(target, ...sources); + return extend.apply(void 0, [target].concat(sources)); } - // ========================================================================== - // Element utils - // ========================================================================== - - - // Wrap an element function wrap(elements, wrapper) { // Convert `elements` to an array, if necessary. - const targets = elements.length ? elements : [elements]; - - // Loops backwards to prevent having to clone the wrapper on the + var targets = elements.length ? elements : [elements]; // Loops backwards to prevent having to clone the wrapper on the // first element (see `child` below). - Array.from(targets).reverse().forEach((element, index) => { - const child = index > 0 ? wrapper.cloneNode(true) : wrapper; - // Cache the current parent and sibling. - const parent = element.parentNode; - const sibling = element.nextSibling; - // Wrap the element (is automatically removed from its current + Array.from(targets).reverse().forEach(function (element, index) { + var child = index > 0 ? wrapper.cloneNode(true) : wrapper; // Cache the current parent and sibling. + + var parent = element.parentNode; + var sibling = element.nextSibling; // Wrap the element (is automatically removed from its current // parent). - child.appendChild(element); - // If the element had a sibling, insert the wrapper before + child.appendChild(element); // If the element had a sibling, insert the wrapper before // the sibling to maintain the HTML structure; otherwise, just // append it to the parent. + if (sibling) { parent.insertBefore(child, sibling); } else { parent.appendChild(child); } }); - } + } // Set attributes - // Set attributes function setAttributes(element, attributes) { - if (!is.element(element) || is.empty(attributes)) return; - - // Assume null and undefined attributes should be left out, + if (!is$1.element(element) || is$1.empty(attributes)) { + return; + } // Assume null and undefined attributes should be left out, // Setting them would otherwise convert them to "null" and "undefined" - Object.entries(attributes).filter(([, value]) => !is.nullOrUndefined(value)).forEach(([key, value]) => element.setAttribute(key, value)); - } - // Create a DocumentFragment + + Object.entries(attributes).filter(function (_ref) { + var _ref2 = _slicedToArray(_ref, 2), + value = _ref2[1]; + + return !is$1.nullOrUndefined(value); + }).forEach(function (_ref3) { + var _ref4 = _slicedToArray(_ref3, 2), + key = _ref4[0], + value = _ref4[1]; + + return element.setAttribute(key, value); + }); + } // Create a DocumentFragment + function createElement(type, attributes, text) { // Create a new - const element = document.createElement(type); + var element = document.createElement(type); // Set all passed attributes - // Set all passed attributes - if (is.object(attributes)) { + if (is$1.object(attributes)) { setAttributes(element, attributes); - } + } // Add text node - // Add text node - if (is.string(text)) { + + if (is$1.string(text)) { element.innerText = text; - } + } // Return built element + - // Return built element return element; - } + } // Inaert an element after another - // Insert an element after another function insertAfter(element, target) { - if (!is.element(element) || !is.element(target)) return; + if (!is$1.element(element) || !is$1.element(target)) { + return; + } + target.parentNode.insertBefore(element, target.nextSibling); - } + } // Insert a DocumentFragment - // Insert a DocumentFragment function insertElement(type, parent, attributes, text) { - if (!is.element(parent)) return; + if (!is$1.element(parent)) { + return; + } + parent.appendChild(createElement(type, attributes, text)); - } + } // Remove element(s) - // Remove element(s) function removeElement(element) { - if (is.nodeList(element) || is.array(element)) { + if (is$1.nodeList(element) || is$1.array(element)) { Array.from(element).forEach(removeElement); return; } - if (!is.element(element) || !is.element(element.parentNode)) { + + if (!is$1.element(element) || !is$1.element(element.parentNode)) { return; } + element.parentNode.removeChild(element); - } + } // Remove all child elements - // Remove all child elements function emptyElement(element) { - if (!is.element(element)) return; - let { - length - } = element.childNodes; + if (!is$1.element(element)) { + return; + } + + var length = element.childNodes.length; + while (length > 0) { element.removeChild(element.lastChild); length -= 1; } - } + } // Replace element - // Replace element function replaceElement(newChild, oldChild) { - if (!is.element(oldChild) || !is.element(oldChild.parentNode) || !is.element(newChild)) return null; + if (!is$1.element(oldChild) || !is$1.element(oldChild.parentNode) || !is$1.element(newChild)) { + return null; + } + oldChild.parentNode.replaceChild(newChild, oldChild); return newChild; - } + } // Get an attribute object from a string selector - // Get an attribute object from a string selector function getAttributesFromSelector(sel, existingAttributes) { // For example: // '.test' to { class: 'test' } // '#test' to { id: 'test' } // '[data-test="test"]' to { 'data-test': 'test' } + if (!is$1.string(sel) || is$1.empty(sel)) { + return {}; + } - if (!is.string(sel) || is.empty(sel)) return {}; - const attributes = {}; - const existing = extend({}, existingAttributes); - sel.split(',').forEach(s => { + var attributes = {}; + var existing = extend({}, existingAttributes); + sel.split(',').forEach(function (s) { // Remove whitespace - const selector = s.trim(); - const className = selector.replace('.', ''); - const stripped = selector.replace(/[[\]]/g, ''); - // Get the parts and value - const parts = stripped.split('='); - const [key] = parts; - const value = parts.length > 1 ? parts[1].replace(/["']/g, '') : ''; - // Get the first character - const start = selector.charAt(0); + var selector = s.trim(); + var className = selector.replace('.', ''); + var stripped = selector.replace(/[[\]]/g, ''); // Get the parts and value + + var parts = stripped.split('='); + + var _parts = _slicedToArray(parts, 1), + key = _parts[0]; + + var value = parts.length > 1 ? parts[1].replace(/["']/g, '') : ''; // Get the first character + + var start = selector.charAt(0); + switch (start) { case '.': // Add to existing classname - if (is.string(existing.class)) { - attributes.class = `${existing.class} ${className}`; + if (is$1.string(existing.class)) { + attributes.class = "".concat(existing.class, " ").concat(className); } else { attributes.class = className; } + break; + case '#': // ID selector attributes.id = selector.replace('#', ''); break; + case '[': // Attribute selector attributes[key] = value; @@ -538,184 +772,192 @@ typeof navigator === "object" && (function (global, factory) { } }); return extend(existing, attributes); - } + } // Toggle hidden - // Toggle hidden function toggleHidden(element, hidden) { - if (!is.element(element)) return; - let hide = hidden; - if (!is.boolean(hide)) { - hide = !element.hidden; + if (!is$1.element(element)) { + return; } - // eslint-disable-next-line no-param-reassign + var hide = hidden; + + if (!is$1.boolean(hide)) { + hide = !element.hidden; + } // eslint-disable-next-line no-param-reassign + + element.hidden = hide; - } + } // Mirror Element.classList.toggle, with IE compatibility for "force" argument - // Mirror Element.classList.toggle, with IE compatibility for "force" argument function toggleClass(element, className, force) { - if (is.nodeList(element)) { - return Array.from(element).map(e => toggleClass(e, className, force)); + if (is$1.nodeList(element)) { + return Array.from(element).map(function (e) { + return toggleClass(e, className, force); + }); } - if (is.element(element)) { - let method = 'toggle'; + + if (is$1.element(element)) { + var method = 'toggle'; + if (typeof force !== 'undefined') { method = force ? 'add' : 'remove'; } + element.classList[method](className); return element.classList.contains(className); } + return false; - } + } // Has class name - // Has class name function hasClass(element, className) { - return is.element(element) && element.classList.contains(className); - } + return is$1.element(element) && element.classList.contains(className); + } // Element matches selector + + function matches$1(element, selector) { + var _Element = Element, + prototype = _Element.prototype; - // Element matches selector - function matches(element, selector) { - const { - prototype - } = Element; function match() { return Array.from(document.querySelectorAll(selector)).includes(this); } - const method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match; + + var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match; return method.call(element, selector); - } + } // Closest ancestor element matching selector (also tests element itself) - // Closest ancestor element matching selector (also tests element itself) - function closest$1(element, selector) { - const { - prototype - } = Element; + function closest(element, selector) { + var _Element2 = Element, + prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill - // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill function closestElement() { - let el = this; + var el = this; + do { - if (matches.matches(el, selector)) return el; + if (matches$1.matches(el, selector)) return el; el = el.parentElement || el.parentNode; } while (el !== null && el.nodeType === 1); + return null; } - const method = prototype.closest || closestElement; + + var method = prototype.closest || closestElement; return method.call(element, selector); - } + } // Find all elements - // Find all elements function getElements(selector) { return this.elements.container.querySelectorAll(selector); - } + } // Find a single element - // Find a single element function getElement(selector) { return this.elements.container.querySelector(selector); - } + } // Set focus and tab focus class - // Set focus and tab focus class - function setFocus(element = null, focusVisible = false) { - if (!is.element(element)) return; + function setFocus() { + var element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var tabFocus = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - // Set regular focus - element.focus({ - preventScroll: true, - focusVisible - }); - } + if (!is$1.element(element)) { + return; + } // Set regular focus - // ========================================================================== - // Plyr support checks - // ========================================================================== + element.focus({ + preventScroll: true + }); // If we want to mimic keyboard focus via tab + + if (tabFocus) { + toggleClass(element, this.config.classNames.tabFocus); + } + } - // Default codecs for checking mimetype support - const defaultCodecs = { + var defaultCodecs = { 'audio/ogg': 'vorbis', 'audio/wav': '1', 'video/webm': 'vp8, vorbis', 'video/mp4': 'avc1.42E01E, mp4a.40.2', 'video/ogg': 'theora' - }; + }; // Check for feature support - // Check for feature support - const support = { + var support = { // Basic support audio: 'canPlayType' in document.createElement('audio'), video: 'canPlayType' in document.createElement('video'), // Check for support // Basic functionality vs full UI - check(type, provider) { - const api = support[type] || provider !== 'html5'; - const ui = api && support.rangeInput; + check: function check(type, provider, playsinline) { + var canPlayInline = browser.isIPhone && playsinline && support.playsinline; + var api = support[type] || provider !== 'html5'; + var ui = api && support.rangeInput && (type !== 'video' || !browser.isIPhone || canPlayInline); return { - api, - ui + api: api, + ui: ui }; }, // Picture-in-picture support // Safari & Chrome only currently - pip: (() => { - // While iPhone's support picture-in-picture for some apps, seemingly Safari isn't one of them - // It will throw the following error when trying to enter picture-in-picture - // `NotSupportedError: The Picture-in-Picture mode is not supported.` + pip: function () { if (browser.isIPhone) { return false; - } - - // Safari + } // Safari // https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls - if (is.function(createElement('video').webkitSetPresentationMode)) { - return true; - } - // Chrome + + if (is$1.function(createElement('video').webkitSetPresentationMode)) { + return true; + } // Chrome // https://developers.google.com/web/updates/2018/10/watch-video-using-picture-in-picture + + if (document.pictureInPictureEnabled && !createElement('video').disablePictureInPicture) { return true; } + return false; - })(), + }(), // Airplay support // Safari only currently - airplay: is.function(window.WebKitPlaybackTargetAvailabilityEvent), + airplay: is$1.function(window.WebKitPlaybackTargetAvailabilityEvent), // Inline playback support // https://webkit.org/blog/6784/new-video-policies-for-ios/ playsinline: 'playsInline' in document.createElement('video'), // Check for mime type support against a player instance // Credits: http://diveintohtml5.info/everything.html // Related: http://www.leanbackplayer.com/test/h5mt.html - mime(input) { - if (is.empty(input)) { + mime: function mime(input) { + if (is$1.empty(input)) { return false; } - const [mediaType] = input.split('/'); - let type = input; - // Verify we're using HTML5 and there's no media type mismatch + var _input$split = input.split('/'), + _input$split2 = _slicedToArray(_input$split, 1), + mediaType = _input$split2[0]; + + var type = input; // Verify we're using HTML5 and there's no media type mismatch + if (!this.isHTML5 || mediaType !== this.type) { return false; - } + } // Add codec if required + - // Add codec if required if (Object.keys(defaultCodecs).includes(type)) { - type += `; codecs="${defaultCodecs[input]}"`; + type += "; codecs=\"".concat(defaultCodecs[input], "\""); } + try { return Boolean(type && this.media.canPlayType(type).replace(/no/, '')); - } catch (_) { + } catch (e) { return false; } }, // Check for textTracks support textTracks: 'textTracks' in document.createElement('video'), // Sliders - rangeInput: (() => { - const range = document.createElement('input'); + rangeInput: function () { + var range = document.createElement('input'); range.type = 'range'; return range.type === 'range'; - })(), + }(), // Touch // NOTE: Remember a device can be mouse + touch enabled so we check on first touch event touch: 'ontouchstart' in document.documentElement, @@ -726,128 +968,149 @@ typeof navigator === "object" && (function (global, factory) { reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches }; - // ========================================================================== - // Event utils - // ========================================================================== - - - // Check for passive event listener support // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md // https://www.youtube.com/watch?v=NPM6172J22g - const supportsPassiveListeners = (() => { + + var supportsPassiveListeners = function () { // Test via a getter in the options object to see if the passive property is accessed - let supported = false; + var supported = false; + try { - const options = Object.defineProperty({}, 'passive', { - get() { + var options = Object.defineProperty({}, 'passive', { + get: function get() { supported = true; return null; } }); window.addEventListener('test', null, options); window.removeEventListener('test', null, options); - } catch (_) { - // Do nothing + } catch (e) {// Do nothing } + return supported; - })(); + }(); // Toggle event listener + + + function toggleListener(element, event, callback) { + var _this = this; + + var toggle = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + var passive = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; + var capture = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; - // Toggle event listener - function toggleListener(element, event, callback, toggle = false, passive = true, capture = false) { // Bail if no element, event, or callback - if (!element || !('addEventListener' in element) || is.empty(event) || !is.function(callback)) { + if (!element || !('addEventListener' in element) || is$1.empty(event) || !is$1.function(callback)) { return; - } + } // Allow multiple events - // Allow multiple events - const events = event.split(' '); - // Build options + + var events = event.split(' '); // Build options // Default to just the capture boolean for browsers with no passive listener support - let options = capture; - // If passive events listeners are supported + var options = capture; // If passive events listeners are supported + if (supportsPassiveListeners) { options = { // Whether the listener can be passive (i.e. default never prevented) - passive, + passive: passive, // Whether the listener is a capturing listener or not - capture + capture: capture }; - } + } // If a single node is passed, bind the event listener + - // If a single node is passed, bind the event listener - events.forEach(type => { - if (this && this.eventListeners && toggle) { + events.forEach(function (type) { + if (_this && _this.eventListeners && toggle) { // Cache event listener - this.eventListeners.push({ - element, - type, - callback, - options + _this.eventListeners.push({ + element: element, + type: type, + callback: callback, + options: options }); } + element[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options); }); - } + } // Bind event handler - // Bind event handler - function on(element, events = '', callback, passive = true, capture = false) { + function on(element) { + var events = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; + var callback = arguments.length > 2 ? arguments[2] : undefined; + var passive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; + var capture = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; toggleListener.call(this, element, events, callback, true, passive, capture); - } + } // Unbind event handler - // Unbind event handler - function off(element, events = '', callback, passive = true, capture = false) { + function off(element) { + var events = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; + var callback = arguments.length > 2 ? arguments[2] : undefined; + var passive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; + var capture = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; toggleListener.call(this, element, events, callback, false, passive, capture); - } + } // Bind once-only event handler + + function once(element) { + var _this2 = this; + + var events = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; + var callback = arguments.length > 2 ? arguments[2] : undefined; + var passive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; + var capture = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; - // Bind once-only event handler - function once(element, events = '', callback, passive = true, capture = false) { - const onceCallback = (...args) => { + var onceCallback = function onceCallback() { off(element, events, onceCallback, passive, capture); - callback.apply(this, args); + + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + callback.apply(_this2, args); }; + toggleListener.call(this, element, events, onceCallback, true, passive, capture); - } + } // Trigger event + + function triggerEvent(element) { + var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; + var bubbles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + var detail = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; - // Trigger event - function triggerEvent(element, type = '', bubbles = false, detail = {}) { // Bail if no element - if (!is.element(element) || is.empty(type)) { + if (!is$1.element(element) || is$1.empty(type)) { return; - } + } // Create and dispatch the event + - // Create and dispatch the event - const event = new CustomEvent(type, { - bubbles, - detail: { - ...detail, + var event = new CustomEvent(type, { + bubbles: bubbles, + detail: _objectSpread2(_objectSpread2({}, detail), {}, { plyr: this - } - }); + }) + }); // Dispatch the event - // Dispatch the event element.dispatchEvent(event); - } + } // Unbind all cached event listeners - // Unbind all cached event listeners function unbindListeners() { if (this && this.eventListeners) { - this.eventListeners.forEach(item => { - const { - element, - type, - callback, - options - } = item; + this.eventListeners.forEach(function (item) { + var element = item.element, + type = item.type, + callback = item.callback, + options = item.options; element.removeEventListener(type, callback, options); }); this.eventListeners = []; } - } + } // Run method when / if player is ready - // Run method when / if player is ready function ready() { - return new Promise(resolve => this.ready ? setTimeout(resolve, 0) : on.call(this, this.elements.container, 'ready', resolve)).then(() => {}); + var _this3 = this; + + return new Promise(function (resolve) { + return _this3.ready ? setTimeout(resolve, 0) : on.call(_this3, _this3.elements.container, 'ready', resolve); + }).then(function () {}); } /** @@ -856,266 +1119,198 @@ typeof navigator === "object" && (function (global, factory) { * play promise" rejection error messages. * @param {Object} value An object that may or may not be `Promise`-like. */ - function silencePromise(value) { - if (is.promise(value)) { - value.then(null, () => {}); - } - } - - // ========================================================================== - // Array utils - // ========================================================================== - - - // Remove duplicates in an array - function dedupe(array) { - if (!is.array(array)) { - return array; - } - return array.filter((item, index) => array.indexOf(item) === index); - } - // Get the closest value in an array - function closest(array, value) { - if (!is.array(array) || !array.length) { - return null; + function silencePromise(value) { + if (is$1.promise(value)) { + value.then(null, function () {}); } - return array.reduce((prev, curr) => Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev); } - // ========================================================================== - // Style utils - // ========================================================================== - - - // Check support for a CSS declaration - function supportsCSS(declaration) { - if (!window || !window.CSS) { + function validateRatio(input) { + if (!is$1.array(input) && (!is$1.string(input) || !input.includes(':'))) { return false; } - return window.CSS.supports(declaration); - } - - // Standard/common aspect ratios - const standardRatios = [[1, 1], [4, 3], [3, 4], [5, 4], [4, 5], [3, 2], [2, 3], [16, 10], [10, 16], [16, 9], [9, 16], [21, 9], [9, 21], [32, 9], [9, 32]].reduce((out, [x, y]) => ({ - ...out, - [x / y]: [x, y] - }), {}); - // Validate an aspect ratio - function validateAspectRatio(input) { - if (!is.array(input) && (!is.string(input) || !input.includes(':'))) { - return false; - } - const ratio = is.array(input) ? input : input.split(':'); - return ratio.map(Number).every(is.number); + var ratio = is$1.array(input) ? input : input.split(':'); + return ratio.map(Number).every(is$1.number); } - - // Reduce an aspect ratio to it's lowest form function reduceAspectRatio(ratio) { - if (!is.array(ratio) || !ratio.every(is.number)) { + if (!is$1.array(ratio) || !ratio.every(is$1.number)) { return null; } - const [width, height] = ratio; - const getDivider = (w, h) => h === 0 ? w : getDivider(h, w % h); - const divider = getDivider(width, height); + + var _ratio = _slicedToArray(ratio, 2), + width = _ratio[0], + height = _ratio[1]; + + var getDivider = function getDivider(w, h) { + return h === 0 ? w : getDivider(h, w % h); + }; + + var divider = getDivider(width, height); return [width / divider, height / divider]; } - - // Calculate an aspect ratio function getAspectRatio(input) { - const parse = ratio => validateAspectRatio(ratio) ? ratio.split(':').map(Number) : null; - // Try provided ratio - let ratio = parse(input); + var parse = function parse(ratio) { + return validateRatio(ratio) ? ratio.split(':').map(Number) : null; + }; // Try provided ratio + + + var ratio = parse(input); // Get from config - // Get from config if (ratio === null) { ratio = parse(this.config.ratio); - } + } // Get from embed + + + if (ratio === null && !is$1.empty(this.embed) && is$1.array(this.embed.ratio)) { + ratio = this.embed.ratio; + } // Get from HTML5 video - // Get from embed - if (ratio === null && !is.empty(this.embed) && is.array(this.embed.ratio)) { - ({ - ratio - } = this.embed); - } - // Get from HTML5 video if (ratio === null && this.isHTML5) { - const { - videoWidth, - videoHeight - } = this.media; - ratio = [videoWidth, videoHeight]; + var _this$media = this.media, + videoWidth = _this$media.videoWidth, + videoHeight = _this$media.videoHeight; + ratio = reduceAspectRatio([videoWidth, videoHeight]); } - return reduceAspectRatio(ratio); - } - // Set aspect ratio for responsive container + return ratio; + } // Set aspect ratio for responsive container + function setAspectRatio(input) { if (!this.isVideo) { return {}; } - const { - wrapper - } = this.elements; - const ratio = getAspectRatio.call(this, input); - if (!is.array(ratio)) { - return {}; - } - const [x, y] = reduceAspectRatio(ratio); - const useNative = supportsCSS(`aspect-ratio: ${x}/${y}`); - const padding = 100 / x * y; - if (useNative) { - wrapper.style.aspectRatio = `${x}/${y}`; - } else { - wrapper.style.paddingBottom = `${padding}%`; - } - // For Vimeo we have an extra
to hide the standard controls and UI + var wrapper = this.elements.wrapper; + var ratio = getAspectRatio.call(this, input); + + var _ref = is$1.array(ratio) ? ratio : [0, 0], + _ref2 = _slicedToArray(_ref, 2), + w = _ref2[0], + h = _ref2[1]; + + var padding = 100 / w * h; + wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra
to hide the standard controls and UI + if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) { - const height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10); - const offset = (height - padding) / (height / 50); - if (this.fullscreen.active) { - wrapper.style.paddingBottom = null; - } else { - this.media.style.transform = `translateY(-${offset}%)`; - } + var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10); + var offset = (height - padding) / (height / 50); + this.media.style.transform = "translateY(-".concat(offset, "%)"); } else if (this.isHTML5) { - wrapper.classList.add(this.config.classNames.videoFixedRatio); + wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null); } + return { - padding, - ratio + padding: padding, + ratio: ratio }; } - // Round an aspect ratio to closest standard ratio - function roundAspectRatio(x, y, tolerance = 0.05) { - const ratio = x / y; - const closestRatio = closest(Object.keys(standardRatios), ratio); - - // Check match is within tolerance - if (Math.abs(closestRatio - ratio) <= tolerance) { - return standardRatios[closestRatio]; - } - - // No match - return [x, y]; - } - - // Get the size of the viewport - // https://stackoverflow.com/questions/1248081/how-to-get-the-browser-viewport-dimensions - function getViewportSize() { - const width = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0); - const height = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0); - return [width, height]; - } - - // ========================================================================== - // Plyr HTML5 helpers // ========================================================================== + var html5 = { + getSources: function getSources() { + var _this = this; - const html5 = { - getSources() { if (!this.isHTML5) { return []; } - const sources = Array.from(this.media.querySelectorAll('source')); - // Filter out unsupported sources (if type is specified) - return sources.filter(source => { - const type = source.getAttribute('type'); - if (is.empty(type)) { + var sources = Array.from(this.media.querySelectorAll('source')); // Filter out unsupported sources (if type is specified) + + return sources.filter(function (source) { + var type = source.getAttribute('type'); + + if (is$1.empty(type)) { return true; } - return support.mime.call(this, type); + + return support.mime.call(_this, type); }); }, // Get quality levels - getQualityOptions() { + getQualityOptions: function getQualityOptions() { // Whether we're forcing all options (e.g. for streaming) if (this.config.quality.forced) { return this.config.quality.options; - } + } // Get sizes from elements + - // Get sizes from elements - return html5.getSources.call(this).map(source => Number(source.getAttribute('data-res'))).filter(Boolean); + return html5.getSources.call(this).map(function (source) { + return Number(source.getAttribute('data-res')); + }).filter(Boolean); }, - setup() { + setup: function setup() { if (!this.isHTML5) { return; } - const player = this; - // Set speed options from config - player.options.speed = player.config.speed.options; + var player = this; // Set speed options from config - // Set aspect ratio if fixed - if (!is.empty(this.config.ratio)) { + player.options.speed = player.config.speed.options; // Set aspect ratio if fixed + + if (!is$1.empty(this.config.ratio)) { setAspectRatio.call(player); - } + } // Quality + - // Quality Object.defineProperty(player.media, 'quality', { - get() { + get: function get() { // Get sources - const sources = html5.getSources.call(player); - const source = sources.find(s => s.getAttribute('src') === player.source); + var sources = html5.getSources.call(player); + var source = sources.find(function (s) { + return s.getAttribute('src') === player.source; + }); // Return size, if match is found - // Return size, if match is found return source && Number(source.getAttribute('data-res')); }, - set(input) { + set: function set(input) { if (player.quality === input) { return; - } + } // If we're using an an external handler... - // If we're using an external handler... - if (player.config.quality.forced && is.function(player.config.quality.onChange)) { + + if (player.config.quality.forced && is$1.function(player.config.quality.onChange)) { player.config.quality.onChange(input); } else { // Get sources - const sources = html5.getSources.call(player); - // Get first match for requested size - const source = sources.find(s => Number(s.getAttribute('data-res')) === input); + var sources = html5.getSources.call(player); // Get first match for requested size + + var source = sources.find(function (s) { + return Number(s.getAttribute('data-res')) === input; + }); // No matching source found - // No matching source found if (!source) { return; - } + } // Get current state + - // Get current state - const { - currentTime, - paused, - preload, - readyState, - playbackRate - } = player.media; + var _player$media = player.media, + currentTime = _player$media.currentTime, + paused = _player$media.paused, + preload = _player$media.preload, + readyState = _player$media.readyState, + playbackRate = _player$media.playbackRate; // Set new source - // Set new source - player.media.src = source.getAttribute('src'); + player.media.src = source.getAttribute('src'); // Prevent loading if preload="none" and the current source isn't loaded (#1044) - // Prevent loading if preload="none" and the current source isn't loaded (#1044) if (preload !== 'none' || readyState) { // Restore time - player.once('loadedmetadata', () => { + player.once('loadedmetadata', function () { player.speed = playbackRate; - player.currentTime = currentTime; + player.currentTime = currentTime; // Resume playing - // Resume playing if (!paused) { silencePromise(player.play()); } - }); + }); // Load new source - // Load new source player.media.load(); } - } + } // Trigger change event + - // Trigger change event triggerEvent.call(player, player.media, 'qualitychange', false, { quality: input }); @@ -1124,368 +1319,401 @@ typeof navigator === "object" && (function (global, factory) { }, // Cancel current network requests // See https://github.com/sampotts/plyr/issues/174 - cancelRequests() { + cancelRequests: function cancelRequests() { if (!this.isHTML5) { return; - } + } // Remove child sources - // Remove child sources - removeElement(html5.getSources.call(this)); - // Set blank video src attribute + removeElement(html5.getSources.call(this)); // Set blank video src attribute // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection - this.media.setAttribute('src', this.config.blankVideo); - // Load the new empty source + this.media.setAttribute('src', this.config.blankVideo); // Load the new empty source // This will cancel existing requests // See https://github.com/sampotts/plyr/issues/174 - this.media.load(); - // Debugging + this.media.load(); // Debugging + this.debug.log('Cancelled network requests'); } }; // ========================================================================== - // String utils - // ========================================================================== + function dedupe(array) { + if (!is$1.array(array)) { + return array; + } - // Generate a random ID - function generateId(prefix) { - return `${prefix}-${Math.floor(Math.random() * 10000)}`; - } + return array.filter(function (item, index) { + return array.indexOf(item) === index; + }); + } // Get the closest value in an array + + function closest$1(array, value) { + if (!is$1.array(array) || !array.length) { + return null; + } - // Format string - function format(input, ...args) { - if (is.empty(input)) return input; - return input.toString().replace(/{(\d+)}/g, (_, i) => args[i].toString()); + return array.reduce(function (prev, curr) { + return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev; + }); } - // Get percentage + // ========================================================================== + + function generateId(prefix) { + return "".concat(prefix, "-").concat(Math.floor(Math.random() * 10000)); + } // Format string + + function format(input) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (is$1.empty(input)) { + return input; + } + + return input.toString().replace(/{(\d+)}/g, function (match, i) { + return args[i].toString(); + }); + } // Get percentage + function getPercentage(current, max) { if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) { return 0; } - return (current / max * 100).toFixed(2); - } - - // Replace all occurrences of a string in a string - const replaceAll = (input = '', find = '', replace = '') => input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'), 'g'), replace.toString()); - // Convert to title case - const toTitleCase = (input = '') => input.toString().replace(/\w\S*/g, text => text.charAt(0).toUpperCase() + text.slice(1).toLowerCase()); + return (current / max * 100).toFixed(2); + } // Replace all occurances of a string in a string + + var replaceAll = function replaceAll() { + var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + var find = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; + var replace = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; + return input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'), 'g'), replace.toString()); + }; // Convert to title case + + var toTitleCase = function toTitleCase() { + var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + return input.toString().replace(/\w\S*/g, function (text) { + return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase(); + }); + }; // Convert string to pascalCase - // Convert string to pascalCase - function toPascalCase(input = '') { - let string = input.toString(); + function toPascalCase() { + var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + var string = input.toString(); // Convert kebab case - // Convert kebab case - string = replaceAll(string, '-', ' '); + string = replaceAll(string, '-', ' '); // Convert snake case - // Convert snake case - string = replaceAll(string, '_', ' '); + string = replaceAll(string, '_', ' '); // Convert to title case - // Convert to title case - string = toTitleCase(string); + string = toTitleCase(string); // Convert to pascal case - // Convert to pascal case return replaceAll(string, ' ', ''); - } + } // Convert string to pascalCase - // Convert string to pascalCase - function toCamelCase(input = '') { - let string = input.toString(); + function toCamelCase() { + var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + var string = input.toString(); // Convert to pascal case - // Convert to pascal case - string = toPascalCase(string); + string = toPascalCase(string); // Convert first character to lowercase - // Convert first character to lowercase return string.charAt(0).toLowerCase() + string.slice(1); - } + } // Remove HTML from a string - // Remove HTML from a string function stripHTML(source) { - const fragment = document.createDocumentFragment(); - const element = document.createElement('div'); + var fragment = document.createDocumentFragment(); + var element = document.createElement('div'); fragment.appendChild(element); element.innerHTML = source; return fragment.firstChild.innerText; - } + } // Like outerHTML, but also works for DocumentFragment - // Like outerHTML, but also works for DocumentFragment function getHTML(element) { - const wrapper = document.createElement('div'); + var wrapper = document.createElement('div'); wrapper.appendChild(element); return wrapper.innerHTML; } - // ========================================================================== - // Plyr internationalization - // ========================================================================== - - - // Skip i18n for abbreviations and brand names - const resources = { + var resources = { pip: 'PIP', airplay: 'AirPlay', html5: 'HTML5', vimeo: 'Vimeo', youtube: 'YouTube' }; - const i18n = { - get(key = '', config = {}) { - if (is.empty(key) || is.empty(config)) { + var i18n = { + get: function get() { + var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + if (is$1.empty(key) || is$1.empty(config)) { return ''; } - let string = getDeep(config.i18n, key); - if (is.empty(string)) { + + var string = getDeep(config.i18n, key); + + if (is$1.empty(string)) { if (Object.keys(resources).includes(key)) { return resources[key]; } + return ''; } - const replace = { + + var replace = { '{seektime}': config.seekTime, '{title}': config.title }; - Object.entries(replace).forEach(([k, v]) => { + Object.entries(replace).forEach(function (_ref) { + var _ref2 = _slicedToArray(_ref, 2), + k = _ref2[0], + v = _ref2[1]; + string = replaceAll(string, k, v); }); return string; } }; - class Storage { - constructor(player) { - _defineProperty$1(this, "get", key => { + var Storage = /*#__PURE__*/function () { + function Storage(player) { + _classCallCheck(this, Storage); + + this.enabled = player.config.storage.enabled; + this.key = player.config.storage.key; + } // Check for actual support (see if we can use it) + + + _createClass(Storage, [{ + key: "get", + value: function get(key) { if (!Storage.supported || !this.enabled) { return null; } - const store = window.localStorage.getItem(this.key); - if (is.empty(store)) { + + var store = window.localStorage.getItem(this.key); + + if (is$1.empty(store)) { return null; } - const json = JSON.parse(store); - return is.string(key) && key.length ? json[key] : json; - }); - _defineProperty$1(this, "set", object => { + + var json = JSON.parse(store); + return is$1.string(key) && key.length ? json[key] : json; + } + }, { + key: "set", + value: function set(object) { // Bail if we don't have localStorage support or it's disabled if (!Storage.supported || !this.enabled) { return; - } + } // Can only store objectst + - // Can only store objectst - if (!is.object(object)) { + if (!is$1.object(object)) { return; - } + } // Get current storage + - // Get current storage - let storage = this.get(); + var storage = this.get(); // Default to empty object - // Default to empty object - if (is.empty(storage)) { + if (is$1.empty(storage)) { storage = {}; - } + } // Update the working copy of the values + - // Update the working copy of the values - extend(storage, object); + extend(storage, object); // Update storage - // Update storage + window.localStorage.setItem(this.key, JSON.stringify(storage)); + } + }], [{ + key: "supported", + get: function get() { try { - window.localStorage.setItem(this.key, JSON.stringify(storage)); - } catch (_) { - // Do nothing - } - }); - this.enabled = player.config.storage.enabled; - this.key = player.config.storage.key; - } + if (!('localStorage' in window)) { + return false; + } - // Check for actual support (see if we can use it) - static get supported() { - try { - if (!('localStorage' in window)) { + var test = '___test'; // Try to use it (it might be disabled, e.g. user is in private mode) + // see: https://github.com/sampotts/plyr/issues/131 + + window.localStorage.setItem(test, test); + window.localStorage.removeItem(test); + return true; + } catch (e) { return false; } - const test = '___test'; - - // Try to use it (it might be disabled, e.g. user is in private mode) - // see: https://github.com/sampotts/plyr/issues/131 - window.localStorage.setItem(test, test); - window.localStorage.removeItem(test); - return true; - } catch (_) { - return false; } - } - } + }]); + + return Storage; + }(); // ========================================================================== // Fetch wrapper // Using XHR to avoid issues with older browsers // ========================================================================== - - function fetch(url, responseType = 'text') { - return new Promise((resolve, reject) => { + function fetch(url) { + var responseType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text'; + return new Promise(function (resolve, reject) { try { - const request = new XMLHttpRequest(); + var request = new XMLHttpRequest(); // Check for CORS support - // Check for CORS support if (!('withCredentials' in request)) { return; } - request.addEventListener('load', () => { + + request.addEventListener('load', function () { if (responseType === 'text') { try { resolve(JSON.parse(request.responseText)); - } catch (_) { + } catch (e) { resolve(request.responseText); } } else { resolve(request.response); } }); - request.addEventListener('error', () => { + request.addEventListener('error', function () { throw new Error(request.status); }); - request.open('GET', url, true); + request.open('GET', url, true); // Set the required response type - // Set the required response type request.responseType = responseType; request.send(); - } catch (error) { - reject(error); + } catch (e) { + reject(e); } }); } // ========================================================================== - // Sprite loader - // ========================================================================== - - // Load an external SVG sprite function loadSprite(url, id) { - if (!is.string(url)) { + if (!is$1.string(url)) { return; } - const prefix = 'cache'; - const hasId = is.string(id); - let isCached = false; - const exists = () => document.getElementById(id) !== null; - const update = (container, data) => { + + var prefix = 'cache'; + var hasId = is$1.string(id); + var isCached = false; + + var exists = function exists() { + return document.getElementById(id) !== null; + }; + + var update = function update(container, data) { // eslint-disable-next-line no-param-reassign - container.innerHTML = data; + container.innerHTML = data; // Check again incase of race condition - // Check again incase of race condition if (hasId && exists()) { return; - } + } // Inject the SVG to the body + - // Inject the SVG to the body document.body.insertAdjacentElement('afterbegin', container); - }; + }; // Only load once if ID set + - // Only load once if ID set if (!hasId || !exists()) { - const useStorage = Storage.supported; - // Create container - const container = document.createElement('div'); + var useStorage = Storage.supported; // Create container + + var container = document.createElement('div'); container.setAttribute('hidden', ''); + if (hasId) { container.setAttribute('id', id); - } + } // Check in cache + - // Check in cache if (useStorage) { - const cached = window.localStorage.getItem(`${prefix}-${id}`); + var cached = window.localStorage.getItem("".concat(prefix, "-").concat(id)); isCached = cached !== null; + if (isCached) { - const data = JSON.parse(cached); + var data = JSON.parse(cached); update(container, data.content); } - } + } // Get the sprite + - // Get the sprite - fetch(url).then(result => { - if (is.empty(result)) { + fetch(url).then(function (result) { + if (is$1.empty(result)) { return; } + if (useStorage) { - try { - window.localStorage.setItem(`${prefix}-${id}`, JSON.stringify({ - content: result - })); - } catch (_) { - // Do nothing - } + window.localStorage.setItem("".concat(prefix, "-").concat(id), JSON.stringify({ + content: result + })); } + update(container, result); - }).catch(() => {}); + }).catch(function () {}); } } // ========================================================================== - // Time utils - // ========================================================================== + var getHours = function getHours(value) { + return Math.trunc(value / 60 / 60 % 60, 10); + }; + var getMinutes = function getMinutes(value) { + return Math.trunc(value / 60 % 60, 10); + }; + var getSeconds = function getSeconds(value) { + return Math.trunc(value % 60, 10); + }; // Format time to UI friendly string - // Time helpers - const getHours = value => Math.trunc(value / 60 / 60 % 60, 10); - const getMinutes = value => Math.trunc(value / 60 % 60, 10); - const getSeconds = value => Math.trunc(value % 60, 10); + function formatTime() { + var time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var displayHours = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + var inverted = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; - // Format time to UI friendly string - function formatTime(time = 0, displayHours = false, inverted = false) { // Bail if the value isn't a number - if (!is.number(time)) { + if (!is$1.number(time)) { return formatTime(undefined, displayHours, inverted); - } + } // Format time component to add leading zero + + + var format = function format(value) { + return "0".concat(value).slice(-2); + }; // Breakdown to hours, mins, secs - // Format time component to add leading zero - const format = value => `0${value}`.slice(-2); - // Breakdown to hours, mins, secs - let hours = getHours(time); - const mins = getMinutes(time); - const secs = getSeconds(time); - // Do we need to display hours? + var hours = getHours(time); + var mins = getMinutes(time); + var secs = getSeconds(time); // Do we need to display hours? + if (displayHours || hours > 0) { - hours = `${hours}:`; + hours = "".concat(hours, ":"); } else { hours = ''; - } + } // Render - // Render - return `${inverted && time > 0 ? '-' : ''}${hours}${format(mins)}:${format(secs)}`; + + return "".concat(inverted && time > 0 ? '-' : '').concat(hours).concat(format(mins), ":").concat(format(secs)); } - // ========================================================================== - // Plyr controls - // TODO: This needs to be split into smaller files and cleaned up - // ========================================================================== - - - // TODO: Don't export a massive object - break down and create class - const controls = { + var controls = { // Get icon URL - getIconUrl() { - const url = new URL(this.config.iconUrl, window.location); - const host = window.location.host ? window.location.host : window.top.location.host; - const cors = url.host !== host || browser.isIE && !window.svg4everybody; + getIconUrl: function getIconUrl() { + var url = new URL(this.config.iconUrl, window.location); + var cors = url.host !== window.location.host || browser.isIE && !window.svg4everybody; return { url: this.config.iconUrl, - cors + cors: cors }; }, // Find the UI controls - findElements() { + findElements: function findElements() { try { - this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper); + this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper); // Buttons - // Buttons this.elements.buttons = { play: getElements.call(this, this.config.selectors.buttons.play), pause: getElement.call(this, this.config.selectors.buttons.pause), @@ -1498,83 +1726,79 @@ typeof navigator === "object" && (function (global, factory) { settings: getElement.call(this, this.config.selectors.buttons.settings), captions: getElement.call(this, this.config.selectors.buttons.captions), fullscreen: getElement.call(this, this.config.selectors.buttons.fullscreen) - }; + }; // Progress - // Progress - this.elements.progress = getElement.call(this, this.config.selectors.progress); + this.elements.progress = getElement.call(this, this.config.selectors.progress); // Inputs - // Inputs this.elements.inputs = { seek: getElement.call(this, this.config.selectors.inputs.seek), volume: getElement.call(this, this.config.selectors.inputs.volume) - }; + }; // Display - // Display this.elements.display = { buffer: getElement.call(this, this.config.selectors.display.buffer), currentTime: getElement.call(this, this.config.selectors.display.currentTime), duration: getElement.call(this, this.config.selectors.display.duration) - }; + }; // Seek tooltip - // Seek tooltip - if (is.element(this.elements.progress)) { - this.elements.display.seekTooltip = this.elements.progress.querySelector(`.${this.config.classNames.tooltip}`); + if (is$1.element(this.elements.progress)) { + this.elements.display.seekTooltip = this.elements.progress.querySelector(".".concat(this.config.classNames.tooltip)); } + return true; } catch (error) { // Log it - this.debug.warn('It looks like there is a problem with your custom controls HTML', error); + this.debug.warn('It looks like there is a problem with your custom controls HTML', error); // Restore native video controls - // Restore native video controls this.toggleNativeControls(true); return false; } }, // Create icon - createIcon(type, attributes) { - const namespace = 'http://www.w3.org/2000/svg'; - const iconUrl = controls.getIconUrl.call(this); - const iconPath = `${!iconUrl.cors ? iconUrl.url : ''}#${this.config.iconPrefix}`; - // Create - const icon = document.createElementNS(namespace, 'svg'); + createIcon: function createIcon(type, attributes) { + var namespace = 'http://www.w3.org/2000/svg'; + var iconUrl = controls.getIconUrl.call(this); + var iconPath = "".concat(!iconUrl.cors ? iconUrl.url : '', "#").concat(this.config.iconPrefix); // Create + + var icon = document.createElementNS(namespace, 'svg'); setAttributes(icon, extend(attributes, { 'aria-hidden': 'true', focusable: 'false' - })); - - // Create the to reference sprite - const use = document.createElementNS(namespace, 'use'); - const path = `${iconPath}-${type}`; + })); // Create the to reference sprite - // Set `href` attributes + var use = document.createElementNS(namespace, 'use'); + var path = "".concat(iconPath, "-").concat(type); // Set `href` attributes // https://github.com/sampotts/plyr/issues/460 // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href + if ('href' in use) { use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path); - } + } // Always set the older attribute even though it's "deprecated" (it'll be around for ages) - // Always set the older attribute even though it's "deprecated" (it'll be around for ages) - use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path); - // Add to + use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path); // Add to + icon.appendChild(use); return icon; }, // Create hidden text label - createLabel(key, attr = {}) { - const text = i18n.get(key, this.config); - const attributes = { - ...attr, + createLabel: function createLabel(key) { + var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var text = i18n.get(key, this.config); + + var attributes = _objectSpread2(_objectSpread2({}, attr), {}, { class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ') - }; + }); + return createElement('span', attributes, text); }, // Create a badge - createBadge(text) { - if (is.empty(text)) { + createBadge: function createBadge(text) { + if (is$1.empty(text)) { return null; } - const badge = createElement('span', { + + var badge = createElement('span', { class: this.config.classNames.menu.value }); badge.appendChild(createElement('span', { @@ -1583,10 +1807,12 @@ typeof navigator === "object" && (function (global, factory) { return badge; }, // Create a
`); - } - // Set position - tipElement.style.left = `${percent}%`; + controls.updateTimeDisplay.call(this, this.elements.display.seekTooltip, this.duration / 100 * percent); // Set position - // Show/hide the tooltip + this.elements.display.seekTooltip.style.left = "".concat(percent, "%"); // Show/hide the tooltip // If the event is a moues in/out and percentage is inside bounds - if (is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) { + + if (is$1.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) { toggle(event.type === 'mouseenter'); } }, // Handle time change event - timeUpdate(event) { + timeUpdate: function timeUpdate(event) { // Only invert if only one time element is displayed and used for both duration and currentTime - const invert = !is.element(this.elements.display.duration) && this.config.invertTime; + var invert = !is$1.element(this.elements.display.duration) && this.config.invertTime; // Duration - // Duration - controls.updateTimeDisplay.call(this, this.elements.display.currentTime, invert ? this.duration - this.currentTime : this.currentTime, invert); + controls.updateTimeDisplay.call(this, this.elements.display.currentTime, invert ? this.duration - this.currentTime : this.currentTime, invert); // Ignore updates while seeking - // Ignore updates while seeking if (event && event.type === 'timeupdate' && this.media.seeking) { return; - } + } // Playing progress + - // Playing progress controls.updateProgress.call(this, event); }, // Show the duration on metadataloaded or durationchange events - durationUpdate() { + durationUpdate: function durationUpdate() { // Bail if no UI or durationchange event triggered after playing/seek when invertTime is false if (!this.supported.ui || !this.config.invertTime && this.currentTime) { return; - } - - // If duration is the 2**32 (shaka), Infinity (HLS), DASH-IF (Number.MAX_SAFE_INTEGER || Number.MAX_VALUE) indicating live we hide the currentTime and progressbar. + } // If duration is the 2**32 (shaka), Infinity (HLS), DASH-IF (Number.MAX_SAFE_INTEGER || Number.MAX_VALUE) indicating live we hide the currentTime and progressbar. // https://github.com/video-dev/hls.js/blob/5820d29d3c4c8a46e8b75f1e3afa3e68c1a9a2db/src/controller/buffer-controller.js#L415 // https://github.com/google/shaka-player/blob/4d889054631f4e1cf0fbd80ddd2b71887c02e232/lib/media/streaming_engine.js#L1062 // https://github.com/Dash-Industry-Forum/dash.js/blob/69859f51b969645b234666800d4cb596d89c602d/src/dash/models/DashManifestModel.js#L338 - if (this.duration >= 2 ** 32) { + + + if (this.duration >= Math.pow(2, 32)) { toggleHidden(this.elements.display.currentTime, true); toggleHidden(this.elements.progress, true); return; - } + } // Update ARIA values + - // Update ARIA values - if (is.element(this.elements.inputs.seek)) { + if (is$1.element(this.elements.inputs.seek)) { this.elements.inputs.seek.setAttribute('aria-valuemax', this.duration); - } + } // If there's a spot to display duration + - // If there's a spot to display duration - const hasDuration = is.element(this.elements.display.duration); + var hasDuration = is$1.element(this.elements.display.duration); // If there's only one time display, display duration there - // If there's only one time display, display duration there if (!hasDuration && this.config.displayDuration && this.paused) { controls.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration); - } + } // If there's a duration element, update content + - // If there's a duration element, update content if (hasDuration) { controls.updateTimeDisplay.call(this, this.elements.display.duration, this.duration); - } - if (this.config.markers.enabled) { - controls.setMarkers.call(this); - } + } // Update the tooltip (if visible) + - // Update the tooltip (if visible) controls.updateSeekTooltip.call(this); }, // Hide/show a tab - toggleMenuButton(setting, toggle) { + toggleMenuButton: function toggleMenuButton(setting, toggle) { toggleHidden(this.elements.settings.buttons[setting], !toggle); }, // Update the selected setting - updateSetting(setting, container, input) { - const pane = this.elements.settings.panels[setting]; - let value = null; - let list = container; + updateSetting: function updateSetting(setting, container, input) { + var pane = this.elements.settings.panels[setting]; + var value = null; + var list = container; + if (setting === 'captions') { value = this.currentTrack; } else { - value = !is.empty(input) ? input : this[setting]; + value = !is$1.empty(input) ? input : this[setting]; // Get default - // Get default - if (is.empty(value)) { + if (is$1.empty(value)) { value = this.config[setting].default; - } + } // Unsupported value + - // Unsupported value - if (!is.empty(this.options[setting]) && !this.options[setting].includes(value)) { - this.debug.warn(`Unsupported value of '${value}' for ${setting}`); + if (!is$1.empty(this.options[setting]) && !this.options[setting].includes(value)) { + this.debug.warn("Unsupported value of '".concat(value, "' for ").concat(setting)); return; - } + } // Disabled value + - // Disabled value if (!this.config[setting].options.includes(value)) { - this.debug.warn(`Disabled value of '${value}' for ${setting}`); + this.debug.warn("Disabled value of '".concat(value, "' for ").concat(setting)); return; } - } + } // Get the list if we need to + - // Get the list if we need to - if (!is.element(list)) { + if (!is$1.element(list)) { list = pane && pane.querySelector('[role="menu"]'); - } + } // If there's no list it means it's not been rendered... + - // If there's no list it means it's not been rendered... - if (!is.element(list)) { + if (!is$1.element(list)) { return; - } + } // Update the label + - // Update the label - const label = this.elements.settings.buttons[setting].querySelector(`.${this.config.classNames.menu.value}`); - label.innerHTML = controls.getLabel.call(this, setting, value); + var label = this.elements.settings.buttons[setting].querySelector(".".concat(this.config.classNames.menu.value)); + label.innerHTML = controls.getLabel.call(this, setting, value); // Find the radio option and check it - // Find the radio option and check it - const target = list && list.querySelector(`[value="${value}"]`); - if (is.element(target)) { + var target = list && list.querySelector("[value=\"".concat(value, "\"]")); + + if (is$1.element(target)) { target.checked = true; } }, // Translate a value into a nice label - getLabel(setting, value) { + getLabel: function getLabel(setting, value) { switch (setting) { case 'speed': - return value === 1 ? i18n.get('normal', this.config) : `${value}×`; + return value === 1 ? i18n.get('normal', this.config) : "".concat(value, "×"); + case 'quality': - if (is.number(value)) { - const label = i18n.get(`qualityLabel.${value}`, this.config); + if (is$1.number(value)) { + var label = i18n.get("qualityLabel.".concat(value), this.config); + if (!label.length) { - return `${value}p`; + return "".concat(value, "p"); } + return label; } + return toTitleCase(value); + case 'captions': return captions.getLabel.call(this); + default: return null; } }, // Set the quality menu - setQualityMenu(options) { + setQualityMenu: function setQualityMenu(options) { + var _this6 = this; + // Menu required - if (!is.element(this.elements.settings.panels.quality)) { + if (!is$1.element(this.elements.settings.panels.quality)) { return; } - const type = 'quality'; - const list = this.elements.settings.panels.quality.querySelector('[role="menu"]'); - // Set options if passed and filter based on uniqueness and config - if (is.array(options)) { - this.options.quality = dedupe(options).filter(quality => this.config.quality.options.includes(quality)); - } + var type = 'quality'; + var list = this.elements.settings.panels.quality.querySelector('[role="menu"]'); // Set options if passed and filter based on uniqueness and config + + if (is$1.array(options)) { + this.options.quality = dedupe(options).filter(function (quality) { + return _this6.config.quality.options.includes(quality); + }); + } // Toggle the pane and tab + - // Toggle the pane and tab - const toggle = !is.empty(this.options.quality) && this.options.quality.length > 1; - controls.toggleMenuButton.call(this, type, toggle); + var toggle = !is$1.empty(this.options.quality) && this.options.quality.length > 1; + controls.toggleMenuButton.call(this, type, toggle); // Empty the menu - // Empty the menu - emptyElement(list); + emptyElement(list); // Check if we need to toggle the parent - // Check if we need to toggle the parent - controls.checkMenu.call(this); + controls.checkMenu.call(this); // If we're hiding, nothing more to do - // If we're hiding, nothing more to do if (!toggle) { return; - } + } // Get the badge HTML for HD, 4K etc + + + var getBadge = function getBadge(quality) { + var label = i18n.get("qualityBadge.".concat(quality), _this6.config); - // Get the badge HTML for HD, 4K etc - const getBadge = quality => { - const label = i18n.get(`qualityBadge.${quality}`, this.config); if (!label.length) { return null; } - return controls.createBadge.call(this, label); - }; - // Sort options by the config and then render options - this.options.quality.sort((a, b) => { - const sorting = this.config.quality.options; + return controls.createBadge.call(_this6, label); + }; // Sort options by the config and then render options + + + this.options.quality.sort(function (a, b) { + var sorting = _this6.config.quality.options; return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1; - }).forEach(quality => { - controls.createMenuItem.call(this, { + }).forEach(function (quality) { + controls.createMenuItem.call(_this6, { value: quality, - list, - type, - title: controls.getLabel.call(this, 'quality', quality), + list: list, + type: type, + title: controls.getLabel.call(_this6, 'quality', quality), badge: getBadge(quality) }); }); controls.updateSetting.call(this, type, list); }, // Set the looping options + /* setLoopMenu() { // Menu required if (!is.element(this.elements.settings.panels.loop)) { @@ -2275,589 +2532,562 @@ typeof navigator === "object" && (function (global, factory) { list.appendChild(item); }); }, */ - // Get current selected caption language // TODO: rework this to user the getter in the API? - // Set a list of available captions languages - setCaptionsMenu() { + setCaptionsMenu: function setCaptionsMenu() { + var _this7 = this; + // Menu required - if (!is.element(this.elements.settings.panels.captions)) { + if (!is$1.element(this.elements.settings.panels.captions)) { return; - } + } // TODO: Captions or language? Currently it's mixed + - // TODO: Captions or language? Currently it's mixed - const type = 'captions'; - const list = this.elements.settings.panels.captions.querySelector('[role="menu"]'); - const tracks = captions.getTracks.call(this); - const toggle = Boolean(tracks.length); + var type = 'captions'; + var list = this.elements.settings.panels.captions.querySelector('[role="menucaptions"]'); + var tracks = captions.getTracks.call(this); + var toggle = Boolean(tracks.length); // Toggle the pane and tab - // Toggle the pane and tab - controls.toggleMenuButton.call(this, type, toggle); + controls.toggleMenuButton.call(this, type, toggle); // Empty the menu - // Empty the menu - emptyElement(list); + emptyElement(list); // Check if we need to toggle the parent - // Check if we need to toggle the parent - controls.checkMenu.call(this); + controls.checkMenu.call(this); // If there's no captions, bail - // If there's no captions, bail if (!toggle) { return; - } + } // Generate options data - // Generate options data - const options = tracks.map((track, value) => ({ - value, - checked: this.captions.toggled && this.currentTrack === value, - title: captions.getLabel.call(this, track), - badge: track.language && controls.createBadge.call(this, track.language.toUpperCase()), - list, - type: 'language' - })); - // Add the "Disabled" option to turn off captions + var options = tracks.map(function (track, value) { + return { + value: value, + checked: _this7.captions.toggled && _this7.currentTrack === value, + title: captions.getLabel.call(_this7, track), + badge: track.language && controls.createBadge.call(_this7, track.language.toUpperCase()), + list: list, + type: 'language' + }; + }); // Add the "Disabled" option to turn off captions + options.unshift({ value: -1, checked: !this.captions.toggled, title: i18n.get('disabled', this.config), - list, + list: list, type: 'language' - }); + }); // Generate options - // Generate options options.forEach(controls.createMenuItem.bind(this)); controls.updateSetting.call(this, type, list); }, // Set a list of available captions languages - setSpeedMenu() { + setSpeedMenu: function setSpeedMenu() { + var _this8 = this; + // Menu required - if (!is.element(this.elements.settings.panels.speed)) { + if (!is$1.element(this.elements.settings.panels.speed)) { return; } - const type = 'speed'; - const list = this.elements.settings.panels.speed.querySelector('[role="menu"]'); - // Filter out invalid speeds - this.options.speed = this.options.speed.filter(o => o >= this.minimumSpeed && o <= this.maximumSpeed); + var type = 'speed'; + var list = this.elements.settings.panels.speed.querySelector('[role="menu"]'); // Filter out invalid speeds + + this.options.speed = this.options.speed.filter(function (o) { + return o >= _this8.minimumSpeed && o <= _this8.maximumSpeed; + }); // Toggle the pane and tab - // Toggle the pane and tab - const toggle = !is.empty(this.options.speed) && this.options.speed.length > 1; - controls.toggleMenuButton.call(this, type, toggle); + var toggle = !is$1.empty(this.options.speed) && this.options.speed.length > 1; + controls.toggleMenuButton.call(this, type, toggle); // Empty the menu - // Empty the menu - emptyElement(list); + emptyElement(list); // Check if we need to toggle the parent - // Check if we need to toggle the parent - controls.checkMenu.call(this); + controls.checkMenu.call(this); // If we're hiding, nothing more to do - // If we're hiding, nothing more to do if (!toggle) { return; - } + } // Create items + - // Create items - this.options.speed.forEach(speed => { - controls.createMenuItem.call(this, { + this.options.speed.forEach(function (speed) { + controls.createMenuItem.call(_this8, { value: speed, - list, - type, - title: controls.getLabel.call(this, 'speed', speed) + list: list, + type: type, + title: controls.getLabel.call(_this8, 'speed', speed) }); }); controls.updateSetting.call(this, type, list); }, // Check if we need to hide/show the settings menu - checkMenu() { - const { - buttons - } = this.elements.settings; - const visible = !is.empty(buttons) && Object.values(buttons).some(button => !button.hidden); + checkMenu: function checkMenu() { + var buttons = this.elements.settings.buttons; + var visible = !is$1.empty(buttons) && Object.values(buttons).some(function (button) { + return !button.hidden; + }); toggleHidden(this.elements.settings.menu, !visible); }, // Focus the first menu item in a given (or visible) menu - focusFirstMenuItem(pane, focusVisible = false) { + focusFirstMenuItem: function focusFirstMenuItem(pane) { + var tabFocus = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + if (this.elements.settings.popup.hidden) { return; } - let target = pane; - if (!is.element(target)) { - target = Object.values(this.elements.settings.panels).find(p => !p.hidden); + + var target = pane; + + if (!is$1.element(target)) { + target = Object.values(this.elements.settings.panels).find(function (p) { + return !p.hidden; + }); } - const firstItem = target.querySelector('[role^="menuitem"]'); - setFocus.call(this, firstItem, focusVisible); + + var firstItem = target.querySelector('[role^="menuitem"]'); + setFocus.call(this, firstItem, tabFocus); }, // Show/hide menu - toggleMenu(input) { - const { - popup - } = this.elements.settings; - const button = this.elements.buttons.settings; - - // Menu and button are required - if (!is.element(popup) || !is.element(button)) { + toggleMenu: function toggleMenu(input) { + var popup = this.elements.settings.popup; + var button = this.elements.buttons.settings; // Menu and button are required + + if (!is$1.element(popup) || !is$1.element(button)) { return; - } + } // True toggle by default + + + var hidden = popup.hidden; + var show = hidden; - // True toggle by default - const { - hidden - } = popup; - let show = hidden; - if (is.boolean(input)) { + if (is$1.boolean(input)) { show = input; - } else if (is.keyboardEvent(input) && input.key === 'Escape') { + } else if (is$1.keyboardEvent(input) && input.which === 27) { show = false; - } else if (is.event(input)) { + } else if (is$1.event(input)) { // If Plyr is in a shadowDOM, the event target is set to the component, instead of the // Element in the shadowDOM. The path, if available, is complete. - const target = is.function(input.composedPath) ? input.composedPath()[0] : input.target; - const isMenuItem = popup.contains(target); - - // If the click was inside the menu or if the click + var target = is$1.function(input.composedPath) ? input.composedPath()[0] : input.target; + var isMenuItem = popup.contains(target); // If the click was inside the menu or if the click // wasn't the button or menu item and we're trying to // show the menu (a doc click shouldn't show the menu) + if (isMenuItem || !isMenuItem && input.target !== button && show) { return; } - } + } // Set button attributes + - // Set button attributes - button.setAttribute('aria-expanded', show); + button.setAttribute('aria-expanded', show); // Show the actual popup - // Show the actual popup - toggleHidden(popup, !show); + toggleHidden(popup, !show); // Add class hook - // Add class hook - toggleClass(this.elements.container, this.config.classNames.menu.open, show); + toggleClass(this.elements.container, this.config.classNames.menu.open, show); // Focus the first item if key interaction - // Focus the first item if key interaction - if (show && is.keyboardEvent(input)) { + if (show && is$1.keyboardEvent(input)) { controls.focusFirstMenuItem.call(this, null, true); } else if (!show && !hidden) { // If closing, re-focus the button - setFocus.call(this, button, is.keyboardEvent(input)); + setFocus.call(this, button, is$1.keyboardEvent(input)); } }, // Get the natural size of a menu panel - getMenuSize(tab) { - const clone = tab.cloneNode(true); + getMenuSize: function getMenuSize(tab) { + var clone = tab.cloneNode(true); clone.style.position = 'absolute'; clone.style.opacity = 0; - clone.removeAttribute('hidden'); + clone.removeAttribute('hidden'); // Append to parent so we get the "real" size - // Append to parent so we get the "real" size - tab.parentNode.appendChild(clone); + tab.parentNode.appendChild(clone); // Get the sizes before we remove - // Get the sizes before we remove - const width = clone.scrollWidth; - const height = clone.scrollHeight; + var width = clone.scrollWidth; + var height = clone.scrollHeight; // Remove from the DOM - // Remove from the DOM removeElement(clone); return { - width, - height + width: width, + height: height }; }, // Show a panel in the menu - showMenuPanel(type = '', focusVisible = false) { - const target = this.elements.container.querySelector(`#plyr-settings-${this.id}-${type}`); + showMenuPanel: function showMenuPanel() { + var _this9 = this; - // Nothing to show, bail - if (!is.element(target)) { + var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + var tabFocus = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + var target = this.elements.container.querySelector("#plyr-settings-".concat(this.id, "-").concat(type)); // Nothing to show, bail + + if (!is$1.element(target)) { return; - } + } // Hide all other panels - // Hide all other panels - const container = target.parentNode; - const current = Array.from(container.children).find(node => !node.hidden); - // If we can do fancy animations, we'll animate the height/width + var container = target.parentNode; + var current = Array.from(container.children).find(function (node) { + return !node.hidden; + }); // If we can do fancy animations, we'll animate the height/width + if (support.transitions && !support.reducedMotion) { // Set the current width as a base - container.style.width = `${current.scrollWidth}px`; - container.style.height = `${current.scrollHeight}px`; + container.style.width = "".concat(current.scrollWidth, "px"); + container.style.height = "".concat(current.scrollHeight, "px"); // Get potential sizes - // Get potential sizes - const size = controls.getMenuSize.call(this, target); + var size = controls.getMenuSize.call(this, target); // Restore auto height/width - // Restore auto height/width - const restore = event => { + var restore = function restore(event) { // We're only bothered about height and width on the container if (event.target !== container || !['width', 'height'].includes(event.propertyName)) { return; - } + } // Revert back to auto + - // Revert back to auto container.style.width = ''; - container.style.height = ''; + container.style.height = ''; // Only listen once - // Only listen once - off.call(this, container, transitionEndEvent, restore); - }; + off.call(_this9, container, transitionEndEvent, restore); + }; // Listen for the transition finishing and restore auto height/width - // Listen for the transition finishing and restore auto height/width - on.call(this, container, transitionEndEvent, restore); - // Set dimensions to target - container.style.width = `${size.width}px`; - container.style.height = `${size.height}px`; - } + on.call(this, container, transitionEndEvent, restore); // Set dimensions to target + + container.style.width = "".concat(size.width, "px"); + container.style.height = "".concat(size.height, "px"); + } // Set attributes on current tab - // Set attributes on current tab - toggleHidden(current, true); - // Set attributes on target - toggleHidden(target, false); + toggleHidden(current, true); // Set attributes on target - // Focus the first item - controls.focusFirstMenuItem.call(this, target, focusVisible); + toggleHidden(target, false); // Focus the first item + + controls.focusFirstMenuItem.call(this, target, tabFocus); }, // Set the download URL - setDownloadUrl() { - const button = this.elements.buttons.download; + setDownloadUrl: function setDownloadUrl() { + var button = this.elements.buttons.download; // Bail if no button - // Bail if no button - if (!is.element(button)) { + if (!is$1.element(button)) { return; - } + } // Set attribute + - // Set attribute button.setAttribute('href', this.download); }, // Build the default HTML - create(data) { - const { - bindMenuItemShortcuts, - createButton, - createProgress, - createRange, - createTime, - setQualityMenu, - setSpeedMenu, - showMenuPanel - } = controls; - this.elements.controls = null; - - // Larger overlaid play button - if (is.array(this.config.controls) && this.config.controls.includes('play-large')) { + create: function create(data) { + var _this10 = this; + + var bindMenuItemShortcuts = controls.bindMenuItemShortcuts, + createButton = controls.createButton, + createProgress = controls.createProgress, + createRange = controls.createRange, + createTime = controls.createTime, + setQualityMenu = controls.setQualityMenu, + setSpeedMenu = controls.setSpeedMenu, + showMenuPanel = controls.showMenuPanel; + this.elements.controls = null; // Larger overlaid play button + + if (is$1.array(this.config.controls) && this.config.controls.includes('play-large')) { this.elements.container.appendChild(createButton.call(this, 'play-large')); - } + } // Create the container - // Create the container - const container = createElement('div', getAttributesFromSelector(this.config.selectors.controls.wrapper)); - this.elements.controls = container; - // Default item attributes - const defaultAttributes = { + var container = createElement('div', getAttributesFromSelector(this.config.selectors.controls.wrapper)); + this.elements.controls = container; // Default item attributes + + var defaultAttributes = { class: 'plyr__controls__item' - }; + }; // Loop through controls in order - // Loop through controls in order - dedupe(is.array(this.config.controls) ? this.config.controls : []).forEach(control => { + dedupe(is$1.array(this.config.controls) ? this.config.controls : []).forEach(function (control) { // Restart button if (control === 'restart') { - container.appendChild(createButton.call(this, 'restart', defaultAttributes)); - } + container.appendChild(createButton.call(_this10, 'restart', defaultAttributes)); + } // Rewind button + - // Rewind button if (control === 'rewind') { - container.appendChild(createButton.call(this, 'rewind', defaultAttributes)); - } + container.appendChild(createButton.call(_this10, 'rewind', defaultAttributes)); + } // Play/Pause button + - // Play/Pause button if (control === 'play') { - container.appendChild(createButton.call(this, 'play', defaultAttributes)); - } + container.appendChild(createButton.call(_this10, 'play', defaultAttributes)); + } // Fast forward button + - // Fast forward button if (control === 'fast-forward') { - container.appendChild(createButton.call(this, 'fast-forward', defaultAttributes)); - } + container.appendChild(createButton.call(_this10, 'fast-forward', defaultAttributes)); + } // Progress + - // Progress if (control === 'progress') { - const progressContainer = createElement('div', { - class: `${defaultAttributes.class} plyr__progress__container` + var progressContainer = createElement('div', { + class: "".concat(defaultAttributes.class, " plyr__progress__container") }); - const progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress)); - - // Seek range slider - progress.appendChild(createRange.call(this, 'seek', { - id: `plyr-seek-${data.id}` - })); + var progress = createElement('div', getAttributesFromSelector(_this10.config.selectors.progress)); // Seek range slider - // Buffer progress - progress.appendChild(createProgress.call(this, 'buffer')); - - // TODO: Add loop display indicator + progress.appendChild(createRange.call(_this10, 'seek', { + id: "plyr-seek-".concat(data.id) + })); // Buffer progress + progress.appendChild(createProgress.call(_this10, 'buffer')); // TODO: Add loop display indicator // Seek tooltip - if (this.config.tooltips.seek) { - const tooltip = createElement('span', { - class: this.config.classNames.tooltip + + if (_this10.config.tooltips.seek) { + var tooltip = createElement('span', { + class: _this10.config.classNames.tooltip }, '00:00'); progress.appendChild(tooltip); - this.elements.display.seekTooltip = tooltip; + _this10.elements.display.seekTooltip = tooltip; } - this.elements.progress = progress; - progressContainer.appendChild(this.elements.progress); + + _this10.elements.progress = progress; + progressContainer.appendChild(_this10.elements.progress); container.appendChild(progressContainer); - } + } // Media current time display + - // Media current time display if (control === 'current-time') { - container.appendChild(createTime.call(this, 'currentTime', defaultAttributes)); - } + container.appendChild(createTime.call(_this10, 'currentTime', defaultAttributes)); + } // Media duration display + - // Media duration display if (control === 'duration') { - container.appendChild(createTime.call(this, 'duration', defaultAttributes)); - } + container.appendChild(createTime.call(_this10, 'duration', defaultAttributes)); + } // Volume controls + - // Volume controls if (control === 'mute' || control === 'volume') { - let { - volume - } = this.elements; + var volume = _this10.elements.volume; // Create the volume container if needed - // Create the volume container if needed - if (!is.element(volume) || !container.contains(volume)) { + if (!is$1.element(volume) || !container.contains(volume)) { volume = createElement('div', extend({}, defaultAttributes, { - class: `${defaultAttributes.class} plyr__volume`.trim() + class: "".concat(defaultAttributes.class, " plyr__volume").trim() })); - this.elements.volume = volume; + _this10.elements.volume = volume; container.appendChild(volume); - } + } // Toggle mute button - // Toggle mute button - if (control === 'mute') { - volume.appendChild(createButton.call(this, 'mute')); - } - // Volume range control + if (control === 'mute') { + volume.appendChild(createButton.call(_this10, 'mute')); + } // Volume range control // Ignored on iOS as it's handled globally // https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html - if (control === 'volume' && !browser.isIos && !browser.isIPadOS) { + + + if (control === 'volume' && !browser.isIos) { // Set the attributes - const attributes = { + var attributes = { max: 1, step: 0.05, - value: this.config.volume - }; + value: _this10.config.volume + }; // Create the volume range slider - // Create the volume range slider - volume.appendChild(createRange.call(this, 'volume', extend(attributes, { - id: `plyr-volume-${data.id}` + volume.appendChild(createRange.call(_this10, 'volume', extend(attributes, { + id: "plyr-volume-".concat(data.id) }))); } - } + } // Toggle captions button + - // Toggle captions button if (control === 'captions') { - container.appendChild(createButton.call(this, 'captions', defaultAttributes)); - } + container.appendChild(createButton.call(_this10, 'captions', defaultAttributes)); + } // Settings button / menu + - // Settings button / menu - if (control === 'settings' && !is.empty(this.config.settings)) { - const wrapper = createElement('div', extend({}, defaultAttributes, { - class: `${defaultAttributes.class} plyr__menu`.trim(), + if (control === 'settings' && !is$1.empty(_this10.config.settings)) { + var wrapper = createElement('div', extend({}, defaultAttributes, { + class: "".concat(defaultAttributes.class, " plyr__menu").trim(), hidden: '' })); - wrapper.appendChild(createButton.call(this, 'settings', { + wrapper.appendChild(createButton.call(_this10, 'settings', { 'aria-haspopup': true, - 'aria-controls': `plyr-settings-${data.id}`, + 'aria-controls': "plyr-settings-".concat(data.id), 'aria-expanded': false })); - const popup = createElement('div', { + var popup = createElement('div', { class: 'plyr__menu__container', - id: `plyr-settings-${data.id}`, + id: "plyr-settings-".concat(data.id), hidden: '' }); - const inner = createElement('div'); - const home = createElement('div', { - id: `plyr-settings-${data.id}-home` - }); + var inner = createElement('div'); + var home = createElement('div', { + id: "plyr-settings-".concat(data.id, "-home") + }); // Create the menu - // Create the menu - const menu = createElement('div', { + var menu = createElement('div', { role: 'menu' }); home.appendChild(menu); inner.appendChild(home); - this.elements.settings.panels.home = home; + _this10.elements.settings.panels.home = home; // Build the menu items - // Build the menu items - this.config.settings.forEach(type => { + _this10.config.settings.forEach(function (type) { // TODO: bundle this with the createMenuItem helper and bindings - const menuItem = createElement('button', extend(getAttributesFromSelector(this.config.selectors.buttons.settings), { + var menuItem = createElement('button', extend(getAttributesFromSelector(_this10.config.selectors.buttons.settings), { type: 'button', - class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`, + class: "".concat(_this10.config.classNames.control, " ").concat(_this10.config.classNames.control, "--forward"), role: 'menuitem', 'aria-haspopup': true, hidden: '' - })); + })); // Bind menu shortcuts for keyboard users - // Bind menu shortcuts for keyboard users - bindMenuItemShortcuts.call(this, menuItem, type); + bindMenuItemShortcuts.call(_this10, menuItem, type); // Show menu on click - // Show menu on click - on.call(this, menuItem, 'click', () => { - showMenuPanel.call(this, type, false); - }); - const flex = createElement('span', null, i18n.get(type, this.config)); - const value = createElement('span', { - class: this.config.classNames.menu.value + on.call(_this10, menuItem, 'click', function () { + showMenuPanel.call(_this10, type, false); }); + var flex = createElement('span', null, i18n.get(type, _this10.config)); + var value = createElement('span', { + class: _this10.config.classNames.menu.value + }); // Speed contains HTML entities - // Speed contains HTML entities value.innerHTML = data[type]; flex.appendChild(value); menuItem.appendChild(flex); - menu.appendChild(menuItem); + menu.appendChild(menuItem); // Build the panes - // Build the panes - const pane = createElement('div', { - id: `plyr-settings-${data.id}-${type}`, + var pane = createElement('div', { + id: "plyr-settings-".concat(data.id, "-").concat(type), hidden: '' - }); + }); // Back button - // Back button - const backButton = createElement('button', { + var backButton = createElement('button', { type: 'button', - class: `${this.config.classNames.control} ${this.config.classNames.control}--back` - }); + class: "".concat(_this10.config.classNames.control, " ").concat(_this10.config.classNames.control, "--back") + }); // Visible label - // Visible label backButton.appendChild(createElement('span', { 'aria-hidden': true - }, i18n.get(type, this.config))); + }, i18n.get(type, _this10.config))); // Screen reader label - // Screen reader label backButton.appendChild(createElement('span', { - class: this.config.classNames.hidden - }, i18n.get('menuBack', this.config))); + class: _this10.config.classNames.hidden + }, i18n.get('menuBack', _this10.config))); // Go back via keyboard + + on.call(_this10, pane, 'keydown', function (event) { + // We only care about <- + if (event.which !== 37) { + return; + } // Prevent seek - // Go back via keyboard - on.call(this, pane, 'keydown', event => { - if (event.key !== 'ArrowLeft') return; - // Prevent seek event.preventDefault(); - event.stopPropagation(); + event.stopPropagation(); // Show the respective menu - // Show the respective menu - showMenuPanel.call(this, 'home', true); - }, false); + showMenuPanel.call(_this10, 'home', true); + }, false); // Go back via button click - // Go back via button click - on.call(this, backButton, 'click', () => { - showMenuPanel.call(this, 'home', false); - }); + on.call(_this10, backButton, 'click', function () { + showMenuPanel.call(_this10, 'home', false); + }); // Add to pane - // Add to pane - pane.appendChild(backButton); + pane.appendChild(backButton); // Menu - // Menu pane.appendChild(createElement('div', { role: 'menu' + })); // Menu Captions + + pane.appendChild(createElement('div', { + role: 'menucaptions' })); inner.appendChild(pane); - this.elements.settings.buttons[type] = menuItem; - this.elements.settings.panels[type] = pane; + _this10.elements.settings.buttons[type] = menuItem; + _this10.elements.settings.panels[type] = pane; }); + popup.appendChild(inner); wrapper.appendChild(popup); container.appendChild(wrapper); - this.elements.settings.popup = popup; - this.elements.settings.menu = wrapper; - } + _this10.elements.settings.popup = popup; + _this10.elements.settings.menu = wrapper; + } // Picture in picture button + - // Picture in picture button if (control === 'pip' && support.pip) { - container.appendChild(createButton.call(this, 'pip', defaultAttributes)); - } + container.appendChild(createButton.call(_this10, 'pip', defaultAttributes)); + } // Airplay button + - // Airplay button if (control === 'airplay' && support.airplay) { - container.appendChild(createButton.call(this, 'airplay', defaultAttributes)); - } + container.appendChild(createButton.call(_this10, 'airplay', defaultAttributes)); + } // Download button + - // Download button if (control === 'download') { - const attributes = extend({}, defaultAttributes, { + var _attributes = extend({}, defaultAttributes, { element: 'a', - href: this.download, + href: _this10.download, target: '_blank' - }); + }); // Set download attribute for HTML5 only + - // Set download attribute for HTML5 only - if (this.isHTML5) { - attributes.download = ''; + if (_this10.isHTML5) { + _attributes.download = ''; } - const { - download - } = this.config.urls; - if (!is.url(download) && this.isEmbed) { - extend(attributes, { - icon: `logo-${this.provider}`, - label: this.provider + + var download = _this10.config.urls.download; + + if (!is$1.url(download) && _this10.isEmbed) { + extend(_attributes, { + icon: "logo-".concat(_this10.provider), + label: _this10.provider }); } - container.appendChild(createButton.call(this, 'download', attributes)); - } - // Toggle fullscreen button + container.appendChild(createButton.call(_this10, 'download', _attributes)); + } // Toggle fullscreen button + + if (control === 'fullscreen') { - container.appendChild(createButton.call(this, 'fullscreen', defaultAttributes)); + container.appendChild(createButton.call(_this10, 'fullscreen', defaultAttributes)); } - }); + }); // Set available quality levels - // Set available quality levels if (this.isHTML5) { setQualityMenu.call(this, html5.getQualityOptions.call(this)); } + setSpeedMenu.call(this); return container; }, // Insert controls - inject() { + inject: function inject() { + var _this11 = this; + // Sprite if (this.config.loadSprite) { - const icon = controls.getIconUrl.call(this); + var icon = controls.getIconUrl.call(this); // Only load external sprite using AJAX - // Only load external sprite using AJAX if (icon.cors) { loadSprite(icon.url, 'sprite-plyr'); } - } + } // Create a unique ID + - // Create a unique ID - this.id = Math.floor(Math.random() * 10000); + this.id = Math.floor(Math.random() * 10000); // Null by default - // Null by default - let container = null; - this.elements.controls = null; + var container = null; + this.elements.controls = null; // Set template properties - // Set template properties - const props = { + var props = { id: this.id, seektime: this.config.seekTime, title: this.config.title }; - let update = true; + var update = true; // If function, run it and use output - // If function, run it and use output - if (is.function(this.config.controls)) { + if (is$1.function(this.config.controls)) { this.config.controls = this.config.controls.call(this, props); - } + } // Convert falsy controls to empty array (primarily for empty strings) + - // Convert falsy controls to empty array (primarily for empty strings) if (!this.config.controls) { this.config.controls = []; } - if (is.element(this.config.controls) || is.string(this.config.controls)) { + + if (is$1.element(this.config.controls) || is$1.string(this.config.controls)) { // HTMLElement or Non-empty string passed as the option container = this.config.controls; } else { @@ -2867,358 +3097,292 @@ typeof navigator === "object" && (function (global, factory) { seektime: this.config.seekTime, speed: this.speed, quality: this.quality, - captions: captions.getLabel.call(this) - // TODO: Looping + captions: captions.getLabel.call(this) // TODO: Looping // loop: 'None', + }); update = false; - } + } // Replace props with their value + - // Replace props with their value - const replace = input => { - let result = input; - Object.entries(props).forEach(([key, value]) => { - result = replaceAll(result, `{${key}}`, value); + var replace = function replace(input) { + var result = input; + Object.entries(props).forEach(function (_ref2) { + var _ref3 = _slicedToArray(_ref2, 2), + key = _ref3[0], + value = _ref3[1]; + + result = replaceAll(result, "{".concat(key, "}"), value); }); return result; - }; + }; // Update markup + - // Update markup if (update) { - if (is.string(this.config.controls)) { + if (is$1.string(this.config.controls)) { container = replace(container); } - } + } // Controls container - // Controls container - let target; - // Inject to custom location - if (is.string(this.config.selectors.controls.container)) { + var target; // Inject to custom location + + if (is$1.string(this.config.selectors.controls.container)) { target = document.querySelector(this.config.selectors.controls.container); - } + } // Inject into the container by default - // Inject into the container by default - if (!is.element(target)) { + + if (!is$1.element(target)) { target = this.elements.container; - } + } // Inject controls HTML (needs to be before captions, hence "afterbegin") - // Inject controls HTML (needs to be before captions, hence "afterbegin") - const insertMethod = is.element(container) ? 'insertAdjacentElement' : 'insertAdjacentHTML'; - target[insertMethod]('afterbegin', container); - // Find the elements if need be - if (!is.element(this.elements.controls)) { + var insertMethod = is$1.element(container) ? 'insertAdjacentElement' : 'insertAdjacentHTML'; + target[insertMethod]('afterbegin', container); // Find the elements if need be + + if (!is$1.element(this.elements.controls)) { controls.findElements.call(this); - } + } // Add pressed property to buttons - // Add pressed property to buttons - if (!is.empty(this.elements.buttons)) { - const addProperty = button => { - const className = this.config.classNames.controlPressed; - button.setAttribute('aria-pressed', 'false'); + + if (!is$1.empty(this.elements.buttons)) { + var addProperty = function addProperty(button) { + var className = _this11.config.classNames.controlPressed; Object.defineProperty(button, 'pressed', { - configurable: true, enumerable: true, - get() { + get: function get() { return hasClass(button, className); }, - set(pressed = false) { + set: function set() { + var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; toggleClass(button, className, pressed); - button.setAttribute('aria-pressed', pressed ? 'true' : 'false'); } }); - }; + }; // Toggle classname when pressed property is set - // Toggle classname when pressed property is set - Object.values(this.elements.buttons).filter(Boolean).forEach(button => { - if (is.array(button) || is.nodeList(button)) { + + Object.values(this.elements.buttons).filter(Boolean).forEach(function (button) { + if (is$1.array(button) || is$1.nodeList(button)) { Array.from(button).filter(Boolean).forEach(addProperty); } else { addProperty(button); } }); - } + } // Edge sometimes doesn't finish the paint so force a repaint + - // Edge sometimes doesn't finish the paint so force a repaint if (browser.isEdge) { repaint(target); - } + } // Setup tooltips + - // Setup tooltips if (this.config.tooltips.controls) { - const { - classNames, - selectors - } = this.config; - const selector = `${selectors.controls.wrapper} ${selectors.labels} .${classNames.hidden}`; - const labels = getElements.call(this, selector); - Array.from(labels).forEach(label => { - toggleClass(label, this.config.classNames.hidden, false); - toggleClass(label, this.config.classNames.tooltip, true); + var _this$config = this.config, + classNames = _this$config.classNames, + selectors = _this$config.selectors; + var selector = "".concat(selectors.controls.wrapper, " ").concat(selectors.labels, " .").concat(classNames.hidden); + var labels = getElements.call(this, selector); + Array.from(labels).forEach(function (label) { + toggleClass(label, _this11.config.classNames.hidden, false); + toggleClass(label, _this11.config.classNames.tooltip, true); }); } - }, - // Set media metadata - setMediaMetadata() { - try { - if ('mediaSession' in navigator) { - navigator.mediaSession.metadata = new window.MediaMetadata({ - title: this.config.mediaMetadata.title, - artist: this.config.mediaMetadata.artist, - album: this.config.mediaMetadata.album, - artwork: this.config.mediaMetadata.artwork - }); - } - } catch (_) { - // Do nothing - } - }, - // Add markers - setMarkers() { - var _this$config$markers2, _this$config$markers3; - if (!this.duration || this.elements.markers) return; - - // Get valid points - const points = (_this$config$markers2 = this.config.markers) === null || _this$config$markers2 === void 0 ? void 0 : (_this$config$markers3 = _this$config$markers2.points) === null || _this$config$markers3 === void 0 ? void 0 : _this$config$markers3.filter(({ - time - }) => time > 0 && time < this.duration); - if (!(points !== null && points !== void 0 && points.length)) return; - const containerFragment = document.createDocumentFragment(); - const pointsFragment = document.createDocumentFragment(); - let tipElement = null; - const tipVisible = `${this.config.classNames.tooltip}--visible`; - const toggleTip = show => toggleClass(tipElement, tipVisible, show); - - // Inject markers to progress container - points.forEach(point => { - const markerElement = createElement('span', { - class: this.config.classNames.marker - }, ''); - const left = `${point.time / this.duration * 100}%`; - if (tipElement) { - // Show on hover - markerElement.addEventListener('mouseenter', () => { - if (point.label) return; - tipElement.style.left = left; - tipElement.innerHTML = point.label; - toggleTip(true); - }); - - // Hide on leave - markerElement.addEventListener('mouseleave', () => { - toggleTip(false); - }); - } - markerElement.addEventListener('click', () => { - this.currentTime = point.time; - }); - markerElement.style.left = left; - pointsFragment.appendChild(markerElement); - }); - containerFragment.appendChild(pointsFragment); - - // Inject a tooltip if needed - if (!this.config.tooltips.seek) { - tipElement = createElement('span', { - class: this.config.classNames.tooltip - }, ''); - containerFragment.appendChild(tipElement); - } - this.elements.markers = { - points: pointsFragment, - tip: tipElement - }; - this.elements.progress.appendChild(containerFragment); } }; - // ========================================================================== - // URL utils - // ========================================================================== - - /** * Parse a string to a URL object * @param {String} input - the URL to be parsed * @param {Boolean} safe - failsafe parsing */ - function parseUrl(input, safe = true) { - let url = input; + + function parseUrl(input) { + var safe = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + var url = input; + if (safe) { - const parser = document.createElement('a'); + var parser = document.createElement('a'); parser.href = url; url = parser.href; } + try { return new URL(url); - } catch (_) { + } catch (e) { return null; } - } + } // Convert object to URLSearchParams - // Convert object to URLSearchParams function buildUrlParams(input) { - const params = new URLSearchParams(); - if (is.object(input)) { - Object.entries(input).forEach(([key, value]) => { + var params = new URLSearchParams(); + + if (is$1.object(input)) { + Object.entries(input).forEach(function (_ref) { + var _ref2 = _slicedToArray(_ref, 2), + key = _ref2[0], + value = _ref2[1]; + params.set(key, value); }); } + return params; } - // ========================================================================== - // Plyr Captions - // TODO: Create as class - // ========================================================================== - - const captions = { + var captions = { // Setup captions - setup() { + setup: function setup() { // Requires UI support if (!this.supported.ui) { return; - } + } // Only Vimeo and HTML5 video supported at this point + - // Only Vimeo and HTML5 video supported at this point if (!this.isVideo || this.isYouTube || this.isHTML5 && !support.textTracks) { // Clear menu and hide - if (is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) { + if (is$1.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) { controls.setCaptionsMenu.call(this); } + return; - } + } // Inject the container - // Inject the container - if (!is.element(this.elements.captions)) { + + if (!is$1.element(this.elements.captions)) { this.elements.captions = createElement('div', getAttributesFromSelector(this.config.selectors.captions)); - this.elements.captions.setAttribute('dir', 'auto'); insertAfter(this.elements.captions, this.elements.wrapper); - } - - // Fix IE captions if CORS is used + } // Fix IE captions if CORS is used // Fetch captions and inject as blobs instead (data URIs not supported!) + + if (browser.isIE && window.URL) { - const elements = this.media.querySelectorAll('track'); - Array.from(elements).forEach(track => { - const src = track.getAttribute('src'); - const url = parseUrl(src); + var elements = this.media.querySelectorAll('track'); + Array.from(elements).forEach(function (track) { + var src = track.getAttribute('src'); + var url = parseUrl(src); + if (url !== null && url.hostname !== window.location.href.hostname && ['http:', 'https:'].includes(url.protocol)) { - fetch(src, 'blob').then(blob => { + fetch(src, 'blob').then(function (blob) { track.setAttribute('src', window.URL.createObjectURL(blob)); - }).catch(() => { + }).catch(function () { removeElement(track); }); } }); - } - - // Get and set initial data + } // Get and set initial data // The "preferred" options are not realized unless / until the wanted language has a match // * languages: Array of user's browser languages. // * language: The language preferred by user settings or config // * active: The state preferred by user settings or config // * toggled: The real captions state - const browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en']; - const languages = dedupe(browserLanguages.map(language => language.split('-')[0])); - let language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase(); - // Use first browser language when language is 'auto' + var browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en']; + var languages = dedupe(browserLanguages.map(function (language) { + return language.split('-')[0]; + })); + var language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase(); // Use first browser language when language is 'auto' + if (language === 'auto') { - [language] = languages; + var _languages = _slicedToArray(languages, 1); + + language = _languages[0]; } - let active = this.storage.get('captions'); - if (!is.boolean(active)) { - ({ - active - } = this.config.captions); + + var active = this.storage.get('captions'); + + if (!is$1.boolean(active)) { + active = this.config.captions.active; } + Object.assign(this.captions, { toggled: false, - active, - language, - languages - }); + active: active, + language: language, + languages: languages + }); // Watch changes to textTracks and update captions menu - // Watch changes to textTracks and update captions menu if (this.isHTML5) { - const trackEvents = this.config.captions.update ? 'addtrack removetrack' : 'removetrack'; + var trackEvents = this.config.captions.update ? 'addtrack removetrack' : 'removetrack'; on.call(this, this.media.textTracks, trackEvents, captions.update.bind(this)); - } + } // Update available languages in list next tick (the event must not be triggered before the listeners) + - // Update available languages in list next tick (the event must not be triggered before the listeners) setTimeout(captions.update.bind(this), 0); }, // Update available language options in settings based on tracks - update() { - const tracks = captions.getTracks.call(this, true); - // Get the wanted language - const { - active, - language, - meta, - currentTrackNode - } = this.captions; - const languageExists = Boolean(tracks.find(track => track.language === language)); - - // Handle tracks (add event listener and "pseudo"-default) + update: function update() { + var _this = this; + + var tracks = captions.getTracks.call(this, true); // Get the wanted language + + var _this$captions = this.captions, + active = _this$captions.active, + language = _this$captions.language, + meta = _this$captions.meta, + currentTrackNode = _this$captions.currentTrackNode; + var languageExists = Boolean(tracks.find(function (track) { + return track.language === language; + })); // Handle tracks (add event listener and "pseudo"-default) + if (this.isHTML5 && this.isVideo) { - tracks.filter(track => !meta.get(track)).forEach(track => { - this.debug.log('Track added', track); + tracks.filter(function (track) { + return !meta.get(track); + }).forEach(function (track) { + _this.debug.log('Track added', track); // Attempt to store if the original dom element was "default" + - // Attempt to store if the original dom element was "default" meta.set(track, { default: track.mode === 'showing' - }); - - // Turn off native caption rendering to avoid double captions + }); // Turn off native caption rendering to avoid double captions // Note: mode='hidden' forces a track to download. To ensure every track // isn't downloaded at once, only 'showing' tracks should be reassigned // eslint-disable-next-line no-param-reassign + if (track.mode === 'showing') { // eslint-disable-next-line no-param-reassign track.mode = 'hidden'; - } + } // Add event listener for cue changes + - // Add event listener for cue changes - on.call(this, track, 'cuechange', () => captions.updateCues.call(this)); + on.call(_this, track, 'cuechange', function () { + return captions.updateCues.call(_this); + }); }); - } + } // Update language first time it matches, or if the previous matching track was removed + - // Update language first time it matches, or if the previous matching track was removed if (languageExists && this.language !== language || !tracks.includes(currentTrackNode)) { captions.setLanguage.call(this, language); captions.toggle.call(this, active && languageExists); - } + } // Enable or disable captions based on track length - // Enable or disable captions based on track length - if (this.elements) { - toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is.empty(tracks)); - } - // Update available languages in list - if (is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) { + toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is$1.empty(tracks)); // Update available languages in list + + if (is$1.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) { controls.setCaptionsMenu.call(this); } }, // Toggle captions display // Used internally for the toggleCaptions method, with the passive option forced to false - toggle(input, passive = true) { + toggle: function toggle(input) { + var _this2 = this; + + var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + // If there's no full support if (!this.supported.ui) { return; } - const { - toggled - } = this.captions; // Current state - const activeClass = this.config.classNames.captions.active; - // Get the next state + + var toggled = this.captions.toggled; // Current state + + var activeClass = this.config.classNames.captions.active; // Get the next state // If the method is called without parameter, toggle based on current value - const active = is.nullOrUndefined(input) ? !toggled : input; - // Update state and trigger event + var active = is$1.nullOrUndefined(input) ? !toggled : input; // Update state and trigger event + if (active !== toggled) { // When passive, don't override user preferences if (!passive) { @@ -3226,95 +3390,93 @@ typeof navigator === "object" && (function (global, factory) { this.storage.set({ captions: active }); - } + } // Force language if the call isn't passive and there is no matching language to toggle to + - // Force language if the call isn't passive and there is no matching language to toggle to if (!this.language && active && !passive) { - const tracks = captions.getTracks.call(this); - const track = captions.findTrack.call(this, [this.captions.language, ...this.captions.languages], true); + var tracks = captions.getTracks.call(this); + var track = captions.findTrack.call(this, [this.captions.language].concat(_toConsumableArray(this.captions.languages)), true); // Override user preferences to avoid switching languages if a matching track is added - // Override user preferences to avoid switching languages if a matching track is added - this.captions.language = track.language; + this.captions.language = track.language; // Set caption, but don't store in localStorage as user preference - // Set caption, but don't store in localStorage as user preference captions.set.call(this, tracks.indexOf(track)); return; - } + } // Toggle button if it's enabled + - // Toggle button if it's enabled if (this.elements.buttons.captions) { this.elements.buttons.captions.pressed = active; - } + } // Add class hook + - // Add class hook toggleClass(this.elements.container, activeClass, active); - this.captions.toggled = active; + this.captions.toggled = active; // Update settings menu - // Update settings menu - controls.updateSetting.call(this, 'captions'); + controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally) - // Trigger event (not used internally) triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled'); - } - - // Wait for the call stack to clear before setting mode='hidden' + } // Wait for the call stack to clear before setting mode='hidden' // on the active track - forcing the browser to download it - setTimeout(() => { - if (active && this.captions.toggled) { - this.captions.currentTrackNode.mode = 'hidden'; + + + setTimeout(function () { + if (active && _this2.captions.toggled) { + _this2.captions.currentTrackNode.mode = 'hidden'; } }); }, // Set captions by track index // Used internally for the currentTrack setter with the passive option forced to false - set(index, passive = true) { - const tracks = captions.getTracks.call(this); + set: function set(index) { + var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + var tracks = captions.getTracks.call(this); // Disable captions if setting to -1 - // Disable captions if setting to -1 if (index === -1) { captions.toggle.call(this, false, passive); return; } - if (!is.number(index)) { + + if (!is$1.number(index)) { this.debug.warn('Invalid caption argument', index); return; } + if (!(index in tracks)) { this.debug.warn('Track not found', index); return; } + if (this.captions.currentTrack !== index) { this.captions.currentTrack = index; - const track = tracks[index]; - const { - language - } = track || {}; + var track = tracks[index]; - // Store reference to node for invalidation on remove - this.captions.currentTrackNode = track; + var _ref = track || {}, + language = _ref.language; // Store reference to node for invalidation on remove - // Update settings menu - controls.updateSetting.call(this, 'captions'); - // When passive, don't override user preferences + this.captions.currentTrackNode = track; // Update settings menu + + controls.updateSetting.call(this, 'captions'); // When passive, don't override user preferences + if (!passive) { this.captions.language = language; this.storage.set({ - language + language: language }); - } + } // Handle Vimeo captions + - // Handle Vimeo captions if (this.isVimeo) { this.embed.enableTextTrack(language); - } + } // Trigger event + - // Trigger event triggerEvent.call(this, this.media, 'languagechange'); - } + } // Show captions + - // Show captions captions.toggle.call(this, true, passive); + if (this.isHTML5 && this.isVideo) { // If we change the active track while a cue is already displayed we need to update it captions.updateCues.call(this); @@ -3322,101 +3484,130 @@ typeof navigator === "object" && (function (global, factory) { }, // Set captions by language // Used internally for the language setter with the passive option forced to false - setLanguage(input, passive = true) { - if (!is.string(input)) { + setLanguage: function setLanguage(input) { + var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + + if (!is$1.string(input)) { this.debug.warn('Invalid language argument', input); return; - } - // Normalize - const language = input.toLowerCase(); - this.captions.language = language; + } // Normalize - // Set currentTrack - const tracks = captions.getTracks.call(this); - const track = captions.findTrack.call(this, [language]); + + var language = input.toLowerCase(); + this.captions.language = language; // Set currentTrack + + var tracks = captions.getTracks.call(this); + var track = captions.findTrack.call(this, [language]); captions.set.call(this, tracks.indexOf(track), passive); }, // Get current valid caption tracks // If update is false it will also ignore tracks without metadata // This is used to "freeze" the language options when captions.update is false - getTracks(update = false) { + getTracks: function getTracks() { + var _this3 = this; + + var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; // Handle media or textTracks missing or null - const tracks = Array.from((this.media || {}).textTracks || []); - // For HTML5, use cache instead of current tracks when it exists (if captions.update is false) + var tracks = Array.from((this.media || {}).textTracks || []); // For HTML5, use cache instead of current tracks when it exists (if captions.update is false) // Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata) - return tracks.filter(track => !this.isHTML5 || update || this.captions.meta.has(track)).filter(track => ['captions', 'subtitles'].includes(track.kind)); + + return tracks.filter(function (track) { + return !_this3.isHTML5 || update || _this3.captions.meta.has(track); + }).filter(function (track) { + return ['captions', 'subtitles'].includes(track.kind); + }); }, // Match tracks based on languages and get the first - findTrack(languages, force = false) { - const tracks = captions.getTracks.call(this); - const sortIsDefault = track => Number((this.captions.meta.get(track) || {}).default); - const sorted = Array.from(tracks).sort((a, b) => sortIsDefault(b) - sortIsDefault(a)); - let track; - languages.every(language => { - track = sorted.find(t => t.language === language); - return !track; // Break iteration if there is a match + findTrack: function findTrack(languages) { + var _this4 = this; + + var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + var tracks = captions.getTracks.call(this); + + var sortIsDefault = function sortIsDefault(track) { + return Number((_this4.captions.meta.get(track) || {}).default); + }; + + var sorted = Array.from(tracks).sort(function (a, b) { + return sortIsDefault(b) - sortIsDefault(a); }); + var track; + languages.every(function (language) { + track = sorted.find(function (t) { + return t.language === language; + }); + return !track; // Break iteration if there is a match + }); // If no match is found but is required, get first - // If no match is found but is required, get first return track || (force ? sorted[0] : undefined); }, // Get the current track - getCurrentTrack() { + getCurrentTrack: function getCurrentTrack() { return captions.getTracks.call(this)[this.currentTrack]; }, // Get UI label for track - getLabel(track) { - let currentTrack = track; - if (!is.track(currentTrack) && support.textTracks && this.captions.toggled) { + getLabel: function getLabel(track) { + var currentTrack = track; + + if (!is$1.track(currentTrack) && support.textTracks && this.captions.toggled) { currentTrack = captions.getCurrentTrack.call(this); } - if (is.track(currentTrack)) { - if (!is.empty(currentTrack.label)) { + + if (is$1.track(currentTrack)) { + if (!is$1.empty(currentTrack.label)) { return currentTrack.label; } - if (!is.empty(currentTrack.language)) { + + if (!is$1.empty(currentTrack.language)) { return track.language.toUpperCase(); } + return i18n.get('enabled', this.config); } + return i18n.get('disabled', this.config); }, // Update captions using current track's active cues // Also optional array argument in case there isn't any track (ex: vimeo) - updateCues(input) { + updateCues: function updateCues(input) { // Requires UI if (!this.supported.ui) { return; } - if (!is.element(this.elements.captions)) { + + if (!is$1.element(this.elements.captions)) { this.debug.warn('No captions element to render to'); return; - } + } // Only accept array or empty input + - // Only accept array or empty input - if (!is.nullOrUndefined(input) && !Array.isArray(input)) { + if (!is$1.nullOrUndefined(input) && !Array.isArray(input)) { this.debug.warn('updateCues: Invalid input', input); return; } - let cues = input; - // Get cues from track + var cues = input; // Get cues from track + if (!cues) { - const track = captions.getCurrentTrack.call(this); - cues = Array.from((track || {}).activeCues || []).map(cue => cue.getCueAsHTML()).map(getHTML); - } + var track = captions.getCurrentTrack.call(this); + cues = Array.from((track || {}).activeCues || []).map(function (cue) { + return cue.getCueAsHTML(); + }).map(getHTML); + } // Set new caption text + + + var content = cues.map(function (cueText) { + return cueText.trim(); + }).join('\n'); + var changed = content !== this.elements.captions.innerHTML; - // Set new caption text - const content = cues.map(cueText => cueText.trim()).join('\n'); - const changed = content !== this.elements.captions.innerHTML; if (changed) { // Empty the container and create a new child element emptyElement(this.elements.captions); - const caption = createElement('span', getAttributesFromSelector(this.config.selectors.caption)); + var caption = createElement('span', getAttributesFromSelector(this.config.selectors.caption)); caption.innerHTML = content; - this.elements.captions.appendChild(caption); + this.elements.captions.appendChild(caption); // Trigger event - // Trigger event triggerEvent.call(this, this.media, 'cuechange'); } } @@ -3425,8 +3616,7 @@ typeof navigator === "object" && (function (global, factory) { // ========================================================================== // Plyr default config // ========================================================================== - - const defaults = { + var defaults$1 = { // Disable enabled: true, // Custom media title @@ -3437,7 +3627,8 @@ typeof navigator === "object" && (function (global, factory) { autoplay: false, // Only allow one media playing at once (vimeo only) autopause: true, - // Allow inline playback on iOS + // Allow inline playback on iOS (this effects YouTube/Vimeo - HTML5 requires the attribute present) + // TODO: Remove iosNative fullscreen option in favour of this (logic needs work) playsinline: true, // Default time to skip when rewind/fast forward seekTime: 10, @@ -3467,9 +3658,9 @@ typeof navigator === "object" && (function (global, factory) { // Sprite (for icons) loadSprite: true, iconPrefix: 'plyr', - iconUrl: 'https://cdn.plyr.io/3.7.8/plyr.svg', + iconUrl: '/theme/modules/plyr/plyr.svg', // Blank video (used to prevent errors on source change) - blankVideo: 'https://cdn.plyr.io/static/blank.mp4', + blankVideo: '/theme/modules/plyr/blank.webm', // Quality default quality: { default: 576, @@ -3480,9 +3671,9 @@ typeof navigator === "object" && (function (global, factory) { }, // Set loops loop: { - active: false - // start: null, + active: false // start: null, // end: null, + }, // Speed default and options to display speed: { @@ -3518,6 +3709,7 @@ typeof navigator === "object" && (function (global, factory) { // Selector for the fullscreen container so contextual / non-player content can remain visible in fullscreen mode // Non-ancestors of the player element will be ignored // container: null, // defaults to the player element + }, // Local storage storage: { @@ -3525,15 +3717,11 @@ typeof navigator === "object" && (function (global, factory) { key: 'plyr' }, // Default controls - controls: ['play-large', - // 'restart', + controls: ['play-large', // 'restart', // 'rewind', - 'play', - // 'fast-forward', - 'progress', 'current-time', - // 'duration', - 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', - // 'download', + 'play', // 'fast-forward', + 'progress', 'current-time', // 'duration', + 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', // 'download', 'fullscreen'], settings: ['captions', 'quality', 'speed'], // Localisation @@ -3588,7 +3776,7 @@ typeof navigator === "object" && (function (global, factory) { vimeo: { sdk: 'https://player.vimeo.com/api/player.js', iframe: 'https://player.vimeo.com/video/{0}?{1}', - api: 'https://vimeo.com/api/oembed.json?url={0}' + api: 'https://vimeo.com/api/v2/video/{0}.json' }, youtube: { sdk: 'https://www.youtube.com/iframe_api', @@ -3619,17 +3807,12 @@ typeof navigator === "object" && (function (global, factory) { language: null }, // Events to watch and bubble - events: [ - // Events to watch on HTML5 media elements and bubble + events: [// Events to watch on HTML5 media elements and bubble // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events - 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied', 'ratechange', 'cuechange', - // Custom events - 'download', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready', - // YouTube - 'statechange', - // Quality - 'qualitychange', - // Ads + 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied', 'ratechange', 'cuechange', // Custom events + 'download', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready', // YouTube + 'statechange', // Quality + 'qualitychange', // Ads 'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'], // Selectors // Change these to match your template if using custom HTML @@ -3695,9 +3878,9 @@ typeof navigator === "object" && (function (global, factory) { hover: 'plyr--hover', tooltip: 'plyr__tooltip', cues: 'plyr__cues', - marker: 'plyr__progress__marker', hidden: 'plyr__sr-only', hideControls: 'plyr--hide-controls', + isIos: 'plyr--is-ios', isTouch: 'plyr--is-touch', uiSupported: 'plyr--full-ui', noTransition: 'plyr--no-transition', @@ -3725,6 +3908,7 @@ typeof navigator === "object" && (function (global, factory) { supported: 'plyr--airplay-supported', active: 'plyr--airplay-active' }, + tabFocus: 'plyr__tab-focus', previewThumbnails: { // Tooltip thumbs thumbContainer: 'plyr__preview-thumb', @@ -3740,8 +3924,7 @@ typeof navigator === "object" && (function (global, factory) { attributes: { embed: { provider: 'data-plyr-provider', - id: 'data-plyr-embed-id', - hash: 'data-plyr-embed-hash' + id: 'data-plyr-embed-id' } }, // Advertisements plugin @@ -3763,47 +3946,32 @@ typeof navigator === "object" && (function (global, factory) { title: false, speed: true, transparent: false, - // Custom settings from Plyr - customControls: true, - referrerPolicy: null, - // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy // Whether the owner of the video has a Pro or Business account // (which allows us to properly hide controls without CSS hacks, etc) - premium: false + premium: false, + // Custom settings from Plyr + referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy + }, // YouTube plugin youtube: { + noCookie: true, + // Whether to use an alternative version of YouTube without cookies rel: 0, // No related vids showinfo: 0, // Hide info iv_load_policy: 3, // Hide annotations - modestbranding: 1, - // Hide logos as much as possible (they still show one in the corner when paused) - // Custom settings from Plyr - customControls: true, - noCookie: false // Whether to use an alternative version of YouTube without cookies - }, - // Media Metadata - mediaMetadata: { - title: '', - artist: '', - album: '', - artwork: [] - }, - // Markers - markers: { - enabled: false, - points: [] + modestbranding: 1 // Hide logos as much as possible (they still show one in the corner when paused) + } }; // ========================================================================== // Plyr states // ========================================================================== - - const pip = { + var pip = { active: 'picture-in-picture', inactive: 'inline' }; @@ -3811,127 +3979,203 @@ typeof navigator === "object" && (function (global, factory) { // ========================================================================== // Plyr supported types and providers // ========================================================================== - - const providers = { + var providers = { html5: 'html5', youtube: 'youtube', vimeo: 'vimeo' }; - const types = { + var types = { audio: 'audio', video: 'video' }; - /** * Get provider by URL * @param {String} url */ + function getProviderByUrl(url) { // YouTube if (/^(https?:\/\/)?(www\.)?(youtube\.com|youtube-nocookie\.com|youtu\.?be)\/.+$/.test(url)) { return providers.youtube; - } + } // Vimeo + - // Vimeo if (/^https?:\/\/player.vimeo.com\/video\/\d{0,9}(?=\b|\/)/.test(url)) { return providers.vimeo; } + return null; } // ========================================================================== // Console wrapper // ========================================================================== + var noop = function noop() {}; + + var Console = /*#__PURE__*/function () { + function Console() { + var enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + _classCallCheck(this, Console); - const noop = () => {}; - class Console { - constructor(enabled = false) { this.enabled = window.console && enabled; + if (this.enabled) { this.log('Debugging enabled'); } } - get log() { - // eslint-disable-next-line no-console - return this.enabled ? Function.prototype.bind.call(console.log, console) : noop; - } - get warn() { - // eslint-disable-next-line no-console - return this.enabled ? Function.prototype.bind.call(console.warn, console) : noop; - } - get error() { - // eslint-disable-next-line no-console - return this.enabled ? Function.prototype.bind.call(console.error, console) : noop; - } - } - class Fullscreen { - constructor(player) { - _defineProperty$1(this, "onChange", () => { - if (!this.supported) return; + _createClass(Console, [{ + key: "log", + get: function get() { + // eslint-disable-next-line no-console + return this.enabled ? Function.prototype.bind.call(console.log, console) : noop; + } + }, { + key: "warn", + get: function get() { + // eslint-disable-next-line no-console + return this.enabled ? Function.prototype.bind.call(console.warn, console) : noop; + } + }, { + key: "error", + get: function get() { + // eslint-disable-next-line no-console + return this.enabled ? Function.prototype.bind.call(console.error, console) : noop; + } + }]); + + return Console; + }(); + + var Fullscreen = /*#__PURE__*/function () { + function Fullscreen(player) { + var _this = this; - // Update toggle button - const button = this.player.elements.buttons.fullscreen; - if (is.element(button)) { - button.pressed = this.active; + _classCallCheck(this, Fullscreen); + + // Keep reference to parent + this.player = player; // Get prefix + + this.prefix = Fullscreen.prefix; + this.property = Fullscreen.property; // Scroll position + + this.scrollPosition = { + x: 0, + y: 0 + }; // Force the use of 'full window/browser' rather than fullscreen + + this.forceFallback = player.config.fullscreen.fallback === 'force'; // Get the fullscreen element + // Checks container is an ancestor, defaults to null + + this.player.elements.fullscreen = player.config.fullscreen.container && closest(this.player.elements.container, player.config.fullscreen.container); // Register event listeners + // Handle event (incase user presses escape etc) + + on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () { + // TODO: Filter for target?? + _this.onChange(); + }); // Fullscreen toggle on double click + + on.call(this.player, this.player.elements.container, 'dblclick', function (event) { + // Ignore double click in controls + if (is$1.element(_this.player.elements.controls) && _this.player.elements.controls.contains(event.target)) { + return; } - // Always trigger events on the plyr / media element (not a fullscreen container) and let them bubble up - const target = this.target === this.player.media ? this.target : this.player.elements.container; - // Trigger an event - triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true); - }); - _defineProperty$1(this, "toggleFallback", (toggle = false) => { + _this.toggle(); + }); // Tap focus when in fullscreen + + on.call(this, this.player.elements.container, 'keydown', function (event) { + return _this.trapFocus(event); + }); // Update the UI + + this.update(); + } // Determine if native supported + + + _createClass(Fullscreen, [{ + key: "onChange", + value: function onChange() { + if (!this.enabled) { + return; + } // Update toggle button + + + var button = this.player.elements.buttons.fullscreen; + + if (is$1.element(button)) { + button.pressed = this.active; + } // Trigger an event + + + triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true); + } + }, { + key: "toggleFallback", + value: function toggleFallback() { + var toggle = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + // Store or restore scroll position if (toggle) { this.scrollPosition = { - x: window.scrollX ?? 0, - y: window.scrollY ?? 0 + x: window.scrollX || 0, + y: window.scrollY || 0 }; } else { window.scrollTo(this.scrollPosition.x, this.scrollPosition.y); - } + } // Toggle scroll + - // Toggle scroll - document.body.style.overflow = toggle ? 'hidden' : ''; + document.body.style.overflow = toggle ? 'hidden' : ''; // Toggle class hook - // Toggle class hook - toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle); + toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle); // Force full viewport on iPhone X+ - // Force full viewport on iPhone X+ if (browser.isIos) { - let viewport = document.head.querySelector('meta[name="viewport"]'); - const property = 'viewport-fit=cover'; + var viewport = document.head.querySelector('meta[name="viewport"]'); + var property = 'viewport-fit=cover'; // Inject the viewport meta if required - // Inject the viewport meta if required if (!viewport) { viewport = document.createElement('meta'); viewport.setAttribute('name', 'viewport'); - } + } // Check if the property already exists + + + var hasProperty = is$1.string(viewport.content) && viewport.content.includes(property); - // Check if the property already exists - const hasProperty = is.string(viewport.content) && viewport.content.includes(property); if (toggle) { this.cleanupViewport = !hasProperty; - if (!hasProperty) viewport.content += `,${property}`; + + if (!hasProperty) { + viewport.content += ",".concat(property); + } } else if (this.cleanupViewport) { - viewport.content = viewport.content.split(',').filter(part => part.trim() !== property).join(','); + viewport.content = viewport.content.split(',').filter(function (part) { + return part.trim() !== property; + }).join(','); } - } + } // Toggle button and fire events + - // Toggle button and fire events this.onChange(); - }); - // Trap focus inside container - _defineProperty$1(this, "trapFocus", event => { - // Bail if iOS/iPadOS, not active, not the tab key - if (browser.isIos || browser.isIPadOS || !this.active || event.key !== 'Tab') return; - - // Get the current focused element - const focused = document.activeElement; - const focusable = getElements.call(this.player, 'a[href], button:not(:disabled), input:not(:disabled), [tabindex]'); - const [first] = focusable; - const last = focusable[focusable.length - 1]; + } // Trap focus inside container + + }, { + key: "trapFocus", + value: function trapFocus(event) { + // Bail if iOS, not active, not the tab key + if (browser.isIos || !this.active || event.key !== 'Tab' || event.keyCode !== 9) { + return; + } // Get the current focused element + + + var focused = document.activeElement; + var focusable = getElements.call(this.player, 'a[href], button:not(:disabled), input:not(:disabled), [tabindex]'); + + var _focusable = _slicedToArray(focusable, 1), + first = _focusable[0]; + + var last = focusable[focusable.length - 1]; + if (focused === last && !event.shiftKey) { // Move focus to first element that can be tabbed if Shift isn't used first.focus(); @@ -3941,205 +4185,186 @@ typeof navigator === "object" && (function (global, factory) { last.focus(); event.preventDefault(); } - }); - // Update UI - _defineProperty$1(this, "update", () => { - if (this.supported) { - let mode; - if (this.forceFallback) mode = 'Fallback (forced)';else if (Fullscreen.nativeSupported) mode = 'Native';else mode = 'Fallback'; - this.player.debug.log(`${mode} fullscreen enabled`); + } // Update UI + + }, { + key: "update", + value: function update() { + if (this.enabled) { + var mode; + + if (this.forceFallback) { + mode = 'Fallback (forced)'; + } else if (Fullscreen.native) { + mode = 'Native'; + } else { + mode = 'Fallback'; + } + + this.player.debug.log("".concat(mode, " fullscreen enabled")); } else { this.player.debug.log('Fullscreen not supported and fallback disabled'); - } + } // Add styling hook to show button + + + toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.enabled); + } // Make an element fullscreen + + }, { + key: "enter", + value: function enter() { + if (!this.enabled) { + return; + } // iOS native fullscreen doesn't need the request step - // Add styling hook to show button - toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.supported); - }); - // Make an element fullscreen - _defineProperty$1(this, "enter", () => { - if (!this.supported) return; - // iOS native fullscreen doesn't need the request step if (browser.isIos && this.player.config.fullscreen.iosNative) { - if (this.player.isVimeo) { - this.player.embed.requestFullscreen(); - } else { - this.target.webkitEnterFullscreen(); - } - } else if (!Fullscreen.nativeSupported || this.forceFallback) { + this.target.webkitEnterFullscreen(); + } else if (!Fullscreen.native || this.forceFallback) { this.toggleFallback(true); } else if (!this.prefix) { this.target.requestFullscreen({ navigationUI: 'hide' }); - } else if (!is.empty(this.prefix)) { - this.target[`${this.prefix}Request${this.property}`](); + } else if (!is$1.empty(this.prefix)) { + this.target["".concat(this.prefix, "Request").concat(this.property)](); } - }); - // Bail from fullscreen - _defineProperty$1(this, "exit", () => { - if (!this.supported) return; + } // Bail from fullscreen + + }, { + key: "exit", + value: function exit() { + if (!this.enabled) { + return; + } // iOS native fullscreen + - // iOS native fullscreen if (browser.isIos && this.player.config.fullscreen.iosNative) { - if (this.player.isVimeo) { - this.player.embed.exitFullscreen(); - } else { - this.target.webkitEnterFullscreen(); - } + this.target.webkitExitFullscreen(); silencePromise(this.player.play()); - } else if (!Fullscreen.nativeSupported || this.forceFallback) { + } else if (!Fullscreen.native || this.forceFallback) { this.toggleFallback(false); } else if (!this.prefix) { (document.cancelFullScreen || document.exitFullscreen).call(document); - } else if (!is.empty(this.prefix)) { - const action = this.prefix === 'moz' ? 'Cancel' : 'Exit'; - document[`${this.prefix}${action}${this.property}`](); + } else if (!is$1.empty(this.prefix)) { + var action = this.prefix === 'moz' ? 'Cancel' : 'Exit'; + document["".concat(this.prefix).concat(action).concat(this.property)](); } - }); - // Toggle state - _defineProperty$1(this, "toggle", () => { - if (!this.active) this.enter();else this.exit(); - }); - // Keep reference to parent - this.player = player; + } // Toggle state - // Get prefix - this.prefix = Fullscreen.prefix; - this.property = Fullscreen.property; - - // Scroll position - this.scrollPosition = { - x: 0, - y: 0 - }; - - // Force the use of 'full window/browser' rather than fullscreen - this.forceFallback = player.config.fullscreen.fallback === 'force'; - - // Get the fullscreen element - // Checks container is an ancestor, defaults to null - this.player.elements.fullscreen = player.config.fullscreen.container && closest$1(this.player.elements.container, player.config.fullscreen.container); - - // Register event listeners - // Handle event (incase user presses escape etc) - on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`, () => { - // TODO: Filter for target?? - this.onChange(); - }); - - // Fullscreen toggle on double click - on.call(this.player, this.player.elements.container, 'dblclick', event => { - // Ignore double click in controls - if (is.element(this.player.elements.controls) && this.player.elements.controls.contains(event.target)) { - return; + }, { + key: "toggle", + value: function toggle() { + if (!this.active) { + this.enter(); + } else { + this.exit(); } - this.player.listeners.proxy(event, this.toggle, 'fullscreen'); - }); - - // Tap focus when in fullscreen - on.call(this, this.player.elements.container, 'keydown', event => this.trapFocus(event)); + } + }, { + key: "usingNative", + // If we're actually using native + get: function get() { + return Fullscreen.native && !this.forceFallback; + } // Get the prefix for handlers - // Update the UI - this.update(); - } + }, { + key: "enabled", + // Determine if fullscreen is enabled + get: function get() { + return (Fullscreen.native || this.player.config.fullscreen.fallback) && this.player.config.fullscreen.enabled && this.player.supported.ui && this.player.isVideo; + } // Get active state - // Determine if native supported - static get nativeSupported() { - return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled); - } + }, { + key: "active", + get: function get() { + if (!this.enabled) { + return false; + } // Fallback using classname - // If we're actually using native - get useNative() { - return Fullscreen.nativeSupported && !this.forceFallback; - } - // Get the prefix for handlers - static get prefix() { - // No prefix - if (is.function(document.exitFullscreen)) return ''; - - // Check for fullscreen support by vendor prefix - let value = ''; - const prefixes = ['webkit', 'moz', 'ms']; - prefixes.some(pre => { - if (is.function(document[`${pre}ExitFullscreen`]) || is.function(document[`${pre}CancelFullScreen`])) { - value = pre; - return true; + if (!Fullscreen.native || this.forceFallback) { + return hasClass(this.target, this.player.config.classNames.fullscreen.fallback); } - return false; - }); - return value; - } - static get property() { - return this.prefix === 'moz' ? 'FullScreen' : 'Fullscreen'; - } - // Determine if fullscreen is supported - get supported() { - return [ - // Fullscreen is enabled in config - this.player.config.fullscreen.enabled, - // Must be a video - this.player.isVideo, - // Either native is supported or fallback enabled - Fullscreen.nativeSupported || this.player.config.fullscreen.fallback, - // YouTube has no way to trigger fullscreen, so on devices with no native support, playsinline - // must be enabled and iosNative fullscreen must be disabled to offer the fullscreen fallback - !this.player.isYouTube || Fullscreen.nativeSupported || !browser.isIos || this.player.config.playsinline && !this.player.config.fullscreen.iosNative].every(Boolean); - } + var element = !this.prefix ? document.fullscreenElement : document["".concat(this.prefix).concat(this.property, "Element")]; + return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target; + } // Get target element - // Get active state - get active() { - if (!this.supported) return false; + }, { + key: "target", + get: function get() { + return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container; + } + }], [{ + key: "native", + get: function get() { + return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled); + } + }, { + key: "prefix", + get: function get() { + // No prefix + if (is$1.function(document.exitFullscreen)) { + return ''; + } // Check for fullscreen support by vendor prefix + + + var value = ''; + var prefixes = ['webkit', 'moz', 'ms']; + prefixes.some(function (pre) { + if (is$1.function(document["".concat(pre, "ExitFullscreen")]) || is$1.function(document["".concat(pre, "CancelFullScreen")])) { + value = pre; + return true; + } - // Fallback using classname - if (!Fullscreen.nativeSupported || this.forceFallback) { - return hasClass(this.target, this.player.config.classNames.fullscreen.fallback); + return false; + }); + return value; } - const element = !this.prefix ? this.target.getRootNode().fullscreenElement : this.target.getRootNode()[`${this.prefix}${this.property}Element`]; - return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target; - } + }, { + key: "property", + get: function get() { + return this.prefix === 'moz' ? 'FullScreen' : 'Fullscreen'; + } + }]); - // Get target element - get target() { - return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen ?? this.player.elements.container; - } - } + return Fullscreen; + }(); // ========================================================================== // Load image avoiding xhr/fetch CORS issues // Server status can't be obtained this way unfortunately, so this uses "naturalWidth" to determine if the image has loaded // By default it checks if it is at least 1px, but you can add a second argument to change this // ========================================================================== + function loadImage(src) { + var minWidth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + return new Promise(function (resolve, reject) { + var image = new Image(); - function loadImage(src, minWidth = 1) { - return new Promise((resolve, reject) => { - const image = new Image(); - const handler = () => { + var handler = function handler() { delete image.onload; delete image.onerror; (image.naturalWidth >= minWidth ? resolve : reject)(image); }; + Object.assign(image, { onload: handler, onerror: handler, - src + src: src }); }); } - // ========================================================================== - // Plyr UI - // ========================================================================== - - const ui = { - addStyleHook() { + var ui = { + addStyleHook: function addStyleHook() { toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true); toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui); }, // Toggle native HTML5 media controls - toggleNativeControls(toggle = false) { + toggleNativeControls: function toggleNativeControls() { + var toggle = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + if (toggle && this.isHTML5) { this.media.setAttribute('controls', ''); } else { @@ -4147,671 +4372,835 @@ typeof navigator === "object" && (function (global, factory) { } }, // Setup the UI - build() { + build: function build() { + var _this = this; + // Re-attach media element listeners // TODO: Use event bubbling? - this.listeners.media(); + this.listeners.media(); // Don't setup interface if no support - // Don't setup interface if no support if (!this.supported.ui) { - this.debug.warn(`Basic support only for ${this.provider} ${this.type}`); + this.debug.warn("Basic support only for ".concat(this.provider, " ").concat(this.type)); // Restore native controls - // Restore native controls - ui.toggleNativeControls.call(this, true); + ui.toggleNativeControls.call(this, true); // Bail - // Bail return; - } + } // Inject custom controls if not present + - // Inject custom controls if not present - if (!is.element(this.elements.controls)) { + if (!is$1.element(this.elements.controls)) { // Inject custom controls - controls.inject.call(this); + controls.inject.call(this); // Re-attach control listeners - // Re-attach control listeners this.listeners.controls(); - } + } // Remove native controls + - // Remove native controls - ui.toggleNativeControls.call(this); + ui.toggleNativeControls.call(this); // Setup captions for HTML5 - // Setup captions for HTML5 if (this.isHTML5) { captions.setup.call(this); - } + } // Reset volume - // Reset volume - this.volume = null; - // Reset mute state - this.muted = null; + this.volume = null; // Reset mute state - // Reset loop state - this.loop = null; + this.muted = null; // Reset loop state - // Reset quality setting - this.quality = null; + this.loop = null; // Reset quality setting - // Reset speed - this.speed = null; + this.quality = null; // Reset speed - // Reset volume display - controls.updateVolume.call(this); + this.speed = null; // Reset volume display - // Reset time display - controls.timeUpdate.call(this); + controls.updateVolume.call(this); // Reset time display - // Reset duration display - controls.durationUpdate.call(this); + controls.timeUpdate.call(this); // Update the UI - // Update the UI - ui.checkPlaying.call(this); + ui.checkPlaying.call(this); // Check for picture-in-picture support - // Check for picture-in-picture support - toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo); + toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo); // Check for airplay support - // Check for airplay support - toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5); + toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5); // Add iOS class - // Add touch class - toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch); + toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos); // Add touch class - // Ready for API calls - this.ready = true; + toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch); // Ready for API calls - // Ready event at end of execution stack - setTimeout(() => { - triggerEvent.call(this, this.media, 'ready'); - }, 0); + this.ready = true; // Ready event at end of execution stack - // Set the title - ui.setTitle.call(this); + setTimeout(function () { + triggerEvent.call(_this, _this.media, 'ready'); + }, 0); // Set the title - // Assure the poster image is set, if the property was added before the element was created - if (this.poster) { - ui.setPoster.call(this, this.poster, false).catch(() => {}); - } + ui.setTitle.call(this); // Assure the poster image is set, if the property was added before the element was created - // Manually set the duration if user has overridden it. + if (this.poster) { + ui.setPoster.call(this, this.poster, false).catch(function () {}); + } // Manually set the duration if user has overridden it. // The event listeners for it doesn't get called if preload is disabled (#701) + + if (this.config.duration) { controls.durationUpdate.call(this); } - - // Media metadata - if (this.config.mediaMetadata) { - controls.setMediaMetadata.call(this); - } }, // Setup aria attribute for play and iframe title - setTitle() { + setTitle: function setTitle() { // Find the current text - let label = i18n.get('play', this.config); + var label = i18n.get('play', this.config); // If there's a media title set, use that for the label - // If there's a media title set, use that for the label - if (is.string(this.config.title) && !is.empty(this.config.title)) { - label += `, ${this.config.title}`; - } + if (is$1.string(this.config.title) && !is$1.empty(this.config.title)) { + label += ", ".concat(this.config.title); + } // If there's a play button, set label - // If there's a play button, set label - Array.from(this.elements.buttons.play || []).forEach(button => { - button.setAttribute('aria-label', label); - }); - // Set iframe title + Array.from(this.elements.buttons.play || []).forEach(function (button) { + button.setAttribute('aria-label', label); + }); // Set iframe title // https://github.com/sampotts/plyr/issues/124 + if (this.isEmbed) { - const iframe = getElement.call(this, 'iframe'); - if (!is.element(iframe)) { + var iframe = getElement.call(this, 'iframe'); + + if (!is$1.element(iframe)) { return; - } + } // Default to media type - // Default to media type - const title = !is.empty(this.config.title) ? this.config.title : 'video'; - const format = i18n.get('frameTitle', this.config); + + var title = !is$1.empty(this.config.title) ? this.config.title : 'video'; + var format = i18n.get('frameTitle', this.config); iframe.setAttribute('title', format.replace('{title}', title)); } }, // Toggle poster - togglePoster(enable) { + togglePoster: function togglePoster(enable) { toggleClass(this.elements.container, this.config.classNames.posterEnabled, enable); }, // Set the poster image (async) // Used internally for the poster setter, with the passive option forced to false - setPoster(poster, passive = true) { + setPoster: function setPoster(poster) { + var _this2 = this; + + var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + // Don't override if call is passive if (passive && this.poster) { return Promise.reject(new Error('Poster already set')); - } + } // Set property synchronously to respect the call order - // Set property synchronously to respect the call order - this.media.setAttribute('data-poster', poster); - // Show the poster - this.elements.poster.removeAttribute('hidden'); + this.media.setAttribute('data-poster', poster); // Wait until ui is ready - // Wait until ui is ready - return ready.call(this) - // Load image - .then(() => loadImage(poster)).catch(error => { + return ready.call(this) // Load image + .then(function () { + return loadImage(poster); + }).catch(function (err) { // Hide poster on error unless it's been set by another call - if (poster === this.poster) { - ui.togglePoster.call(this, false); - } - // Rethrow - throw error; - }).then(() => { + if (poster === _this2.poster) { + ui.togglePoster.call(_this2, false); + } // Rethrow + + + throw err; + }).then(function () { // Prevent race conditions - if (poster !== this.poster) { + if (poster !== _this2.poster) { throw new Error('setPoster cancelled by later call to setPoster'); } - }).then(() => { - Object.assign(this.elements.poster.style, { - backgroundImage: `url('${poster}')`, + }).then(function () { + Object.assign(_this2.elements.poster.style, { + backgroundImage: "url('".concat(poster, "')"), // Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube) backgroundSize: '' }); - ui.togglePoster.call(this, true); + ui.togglePoster.call(_this2, true); return poster; }); }, // Check playing state - checkPlaying(event) { + checkPlaying: function checkPlaying(event) { + var _this3 = this; + // Class hooks toggleClass(this.elements.container, this.config.classNames.playing, this.playing); toggleClass(this.elements.container, this.config.classNames.paused, this.paused); - toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); + toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); // Set state - // Set state - Array.from(this.elements.buttons.play || []).forEach(target => { + Array.from(this.elements.buttons.play || []).forEach(function (target) { Object.assign(target, { - pressed: this.playing + pressed: _this3.playing }); - target.setAttribute('aria-label', i18n.get(this.playing ? 'pause' : 'play', this.config)); - }); + target.setAttribute('aria-label', i18n.get(_this3.playing ? 'pause' : 'play', _this3.config)); + }); // Only update controls on non timeupdate events - // Only update controls on non timeupdate events - if (is.event(event) && event.type === 'timeupdate') { + if (is$1.event(event) && event.type === 'timeupdate') { return; - } + } // Toggle controls + - // Toggle controls ui.toggleControls.call(this); }, // Check if media is loading - checkLoading(event) { - this.loading = ['stalled', 'waiting'].includes(event.type); + checkLoading: function checkLoading(event) { + var _this4 = this; + + this.loading = ['stalled', 'waiting'].includes(event.type); // Clear timer - // Clear timer - clearTimeout(this.timers.loading); + clearTimeout(this.timers.loading); // Timer to prevent flicker when seeking - // Timer to prevent flicker when seeking - this.timers.loading = setTimeout(() => { + this.timers.loading = setTimeout(function () { // Update progress bar loading class state - toggleClass(this.elements.container, this.config.classNames.loading, this.loading); + toggleClass(_this4.elements.container, _this4.config.classNames.loading, _this4.loading); // Update controls visibility - // Update controls visibility - ui.toggleControls.call(this); + ui.toggleControls.call(_this4); }, this.loading ? 250 : 0); }, // Toggle controls based on state and `force` argument - toggleControls(force) { - const { - controls: controlsElement - } = this.elements; + toggleControls: function toggleControls(force) { + var controlsElement = this.elements.controls; + if (controlsElement && this.config.hideControls) { // Don't hide controls if a touch-device user recently seeked. (Must be limited to touch devices, or it occasionally prevents desktop controls from hiding.) - const recentTouchSeek = this.touch && this.lastSeekTime + 2000 > Date.now(); + var recentTouchSeek = this.touch && this.lastSeekTime + 2000 > Date.now(); // Show controls if force, loading, paused, button interaction, or recent seek, otherwise hide - // Show controls if force, loading, paused, button interaction, or recent seek, otherwise hide this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek)); } }, // Migrate any custom properties from the media to the parent - migrateStyles() { + migrateStyles: function migrateStyles() { + var _this5 = this; + // Loop through values (as they are the keys when the object is spread 🤔) - Object.values({ - ...this.media.style - }) - // We're only fussed about Plyr specific properties - .filter(key => !is.empty(key) && is.string(key) && key.startsWith('--plyr')).forEach(key => { + Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties + .filter(function (key) { + return !is$1.empty(key) && key.startsWith('--plyr'); + }).forEach(function (key) { // Set on the container - this.elements.container.style.setProperty(key, this.media.style.getPropertyValue(key)); + _this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element - // Clean up from media element - this.media.style.removeProperty(key); - }); - // Remove attribute if empty - if (is.empty(this.media.style)) { + _this5.media.style.removeProperty(key); + }); // Remove attribute if empty + + if (is$1.empty(this.media.style)) { this.media.removeAttribute('style'); } } }; - class Listeners { - constructor(_player) { - // Device is touch enabled - _defineProperty$1(this, "firstTouch", () => { - const { - player - } = this; - const { - elements - } = player; - player.touch = true; - - // Add touch class + var Listeners = /*#__PURE__*/function () { + function Listeners(player) { + _classCallCheck(this, Listeners); + + this.player = player; + this.lastKey = null; + this.focusTimer = null; + this.lastKeyDown = null; + this.handleKey = this.handleKey.bind(this); + this.toggleMenu = this.toggleMenu.bind(this); + this.setTabFocus = this.setTabFocus.bind(this); + this.firstTouch = this.firstTouch.bind(this); + } // Handle key presses + + + _createClass(Listeners, [{ + key: "handleKey", + value: function handleKey(event) { + var player = this.player; + var elements = player.elements; + var code = event.keyCode ? event.keyCode : event.which; + var pressed = event.type === 'keydown'; + var repeat = pressed && code === this.lastKey; // Bail if a modifier key is set + + if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) { + return; + } // If the event is bubbled from the media element + // Firefox doesn't get the keycode for whatever reason + + + if (!is$1.number(code)) { + return; + } // Seek by the number keys + + + var seekByKey = function seekByKey() { + // Divide the max duration into 10th's and times by the number value + player.currentTime = player.duration / 10 * (code - 48); + }; // Handle the key on keydown + // Reset on keyup + + + if (pressed) { + // Check focused element + // and if the focused element is not editable (e.g. text input) + // and any that accept key input http://webaim.org/techniques/keyboard/ + var focused = document.activeElement; + + if (is$1.element(focused)) { + var editable = player.config.selectors.editable; + var seek = elements.inputs.seek; + + if (focused !== seek && matches$1(focused, editable)) { + return; + } + + if (event.which === 32 && matches$1(focused, 'button, [role^="menuitem"]')) { + return; + } + } // Which keycodes should we prevent default + + + var preventDefault = [32, 37, 38, 39, 40, 48, 49, 50, 51, 52, 53, 54, 56, 57, 67, 70, 73, 75, 76, 77, 79]; // If the code is found prevent default (e.g. prevent scrolling for arrows) + + if (preventDefault.includes(code)) { + event.preventDefault(); + event.stopPropagation(); + } + + switch (code) { + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + // 0-9 + if (!repeat) { + seekByKey(); + } + + break; + + case 32: + case 75: + // Space and K key + if (!repeat) { + silencePromise(player.togglePlay()); + } + + break; + + case 38: + // Arrow up + player.increaseVolume(0.1); + break; + + case 40: + // Arrow down + player.decreaseVolume(0.1); + break; + + case 77: + // M key + if (!repeat) { + player.muted = !player.muted; + } + + break; + + case 39: + // Arrow forward + player.forward(); + break; + + case 37: + // Arrow back + player.rewind(); + break; + + case 70: + // F key + player.fullscreen.toggle(); + break; + + case 67: + // C key + if (!repeat) { + player.toggleCaptions(); + } + + break; + + case 76: + // L key + player.loop = !player.loop; + break; + } // Escape is handle natively when in full screen + // So we only need to worry about non native + + + if (code === 27 && !player.fullscreen.usingNative && player.fullscreen.active) { + player.fullscreen.toggle(); + } // Store last code for next cycle + + + this.lastKey = code; + } else { + this.lastKey = null; + } + } // Toggle menu + + }, { + key: "toggleMenu", + value: function toggleMenu(event) { + controls.toggleMenu.call(this.player, event); + } // Device is touch enabled + + }, { + key: "firstTouch", + value: function firstTouch() { + var player = this.player; + var elements = player.elements; + player.touch = true; // Add touch class + toggleClass(elements.container, player.config.classNames.isTouch, true); - }); - // Global window & document listeners - _defineProperty$1(this, "global", (toggle = true) => { - const { - player - } = this; + } + }, { + key: "setTabFocus", + value: function setTabFocus(event) { + var player = this.player; + var elements = player.elements; + clearTimeout(this.focusTimer); // Ignore any key other than tab + + if (event.type === 'keydown' && event.which !== 9) { + return; + } // Store reference to event timeStamp + + + if (event.type === 'keydown') { + this.lastKeyDown = event.timeStamp; + } // Remove current classes + + + var removeCurrent = function removeCurrent() { + var className = player.config.classNames.tabFocus; + var current = getElements.call(player, ".".concat(className)); + toggleClass(current, className, false); + }; // Determine if a key was pressed to trigger this event + + + var wasKeyDown = event.timeStamp - this.lastKeyDown <= 20; // Ignore focus events if a key was pressed prior + + if (event.type === 'focus' && !wasKeyDown) { + return; + } // Remove all current + + + removeCurrent(); // Delay the adding of classname until the focus has changed + // This event fires before the focusin event + + if (event.type !== 'focusout') { + this.focusTimer = setTimeout(function () { + var focused = document.activeElement; // Ignore if current focus element isn't inside the player + + if (!elements.container.contains(focused)) { + return; + } + + toggleClass(document.activeElement, player.config.classNames.tabFocus, true); + }, 10); + } + } // Global window & document listeners + + }, { + key: "global", + value: function global() { + var toggle = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + var player = this.player; // Keyboard shortcuts - // Keyboard shortcuts if (player.config.keyboard.global) { toggleListener.call(player, window, 'keydown keyup', this.handleKey, toggle, false); - } + } // Click anywhere closes menu - // Click anywhere closes menu - toggleListener.call(player, document.body, 'click', this.toggleMenu, toggle); - // Detect touch by events - once.call(player, document.body, 'touchstart', this.firstTouch); - }); - // Container listeners - _defineProperty$1(this, "container", () => { - const { - player - } = this; - const { - config, - elements, - timers - } = player; - - // Keyboard shortcuts + toggleListener.call(player, document.body, 'click', this.toggleMenu, toggle); // Detect touch by events + + once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection + + toggleListener.call(player, document.body, 'keydown focus blur focusout', this.setTabFocus, toggle, false, true); + } // Container listeners + + }, { + key: "container", + value: function container() { + var player = this.player; + var config = player.config, + elements = player.elements, + timers = player.timers; // Keyboard shortcuts + if (!config.keyboard.global && config.keyboard.focused) { on.call(player, elements.container, 'keydown keyup', this.handleKey, false); - } + } // Toggle controls on mouse events and entering fullscreen + - // Toggle controls on mouse events and entering fullscreen - on.call(player, elements.container, 'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen', event => { - const { - controls: controlsElement - } = elements; + on.call(player, elements.container, 'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen', function (event) { + var controlsElement = elements.controls; // Remove button states for fullscreen - // Remove button states for fullscreen if (controlsElement && event.type === 'enterfullscreen') { controlsElement.pressed = false; controlsElement.hover = false; - } + } // Show, then hide after a timeout unless another control event occurs + + + var show = ['touchstart', 'touchmove', 'mousemove'].includes(event.type); + var delay = 0; - // Show, then hide after a timeout unless another control event occurs - const show = ['touchstart', 'touchmove', 'mousemove'].includes(event.type); - let delay = 0; if (show) { - ui.toggleControls.call(player, true); - // Use longer timeout for touch devices + ui.toggleControls.call(player, true); // Use longer timeout for touch devices + delay = player.touch ? 3000 : 2000; - } + } // Clear timer - // Clear timer - clearTimeout(timers.controls); - // Set new timer to prevent flicker when seeking - timers.controls = setTimeout(() => ui.toggleControls.call(player, false), delay); - }); + clearTimeout(timers.controls); // Set new timer to prevent flicker when seeking - // Set a gutter for Vimeo - const setGutter = () => { + timers.controls = setTimeout(function () { + return ui.toggleControls.call(player, false); + }, delay); + }); // Set a gutter for Vimeo + + var setGutter = function setGutter(ratio, padding, toggle) { if (!player.isVimeo || player.config.vimeo.premium) { return; } - const target = elements.wrapper; - const { - active - } = player.fullscreen; - const [videoWidth, videoHeight] = getAspectRatio.call(player); - const useNativeAspectRatio = supportsCSS(`aspect-ratio: ${videoWidth} / ${videoHeight}`); - - // If not active, remove styles - if (!active) { - if (useNativeAspectRatio) { - target.style.width = null; - target.style.height = null; - } else { - target.style.maxWidth = null; - target.style.margin = null; - } - return; - } - // Determine which dimension will overflow and constrain view - const [viewportWidth, viewportHeight] = getViewportSize(); - const overflow = viewportWidth / viewportHeight > videoWidth / videoHeight; - if (useNativeAspectRatio) { - target.style.width = overflow ? 'auto' : '100%'; - target.style.height = overflow ? '100%' : 'auto'; - } else { - target.style.maxWidth = overflow ? `${viewportHeight / videoHeight * videoWidth}px` : null; - target.style.margin = overflow ? '0 auto' : null; + var target = player.elements.wrapper.firstChild; + + var _ratio = _slicedToArray(ratio, 2), + y = _ratio[1]; + + var _getAspectRatio$call = getAspectRatio.call(player), + _getAspectRatio$call2 = _slicedToArray(_getAspectRatio$call, 2), + videoX = _getAspectRatio$call2[0], + videoY = _getAspectRatio$call2[1]; + + target.style.maxWidth = toggle ? "".concat(y / videoY * videoX, "px") : null; + target.style.margin = toggle ? '0 auto' : null; + }; // Resize on fullscreen change + + + var setPlayerSize = function setPlayerSize(measure) { + // If we don't need to measure the viewport + if (!measure) { + return setAspectRatio.call(player); } + + var rect = elements.container.getBoundingClientRect(); + var width = rect.width, + height = rect.height; + return setAspectRatio.call(player, "".concat(width, ":").concat(height)); }; - // Handle resizing - const resized = () => { + var resized = function resized() { clearTimeout(timers.resized); - timers.resized = setTimeout(setGutter, 50); + timers.resized = setTimeout(setPlayerSize, 50); }; - on.call(player, elements.container, 'enterfullscreen exitfullscreen', event => { - const { - target - } = player.fullscreen; - // Ignore events not from target + on.call(player, elements.container, 'enterfullscreen exitfullscreen', function (event) { + var _player$fullscreen = player.fullscreen, + target = _player$fullscreen.target, + usingNative = _player$fullscreen.usingNative; // Ignore events not from target + if (target !== elements.container) { return; - } + } // If it's not an embed and no ratio specified - // If it's not an embed and no ratio specified - if (!player.isEmbed && is.empty(player.config.ratio)) { + + if (!player.isEmbed && is$1.empty(player.config.ratio)) { return; } - // Set Vimeo gutter - setGutter(); + var isEnter = event.type === 'enterfullscreen'; // Set the player size when entering fullscreen to viewport size + + var _setPlayerSize = setPlayerSize(isEnter), + padding = _setPlayerSize.padding, + ratio = _setPlayerSize.ratio; // Set Vimeo gutter - // Watch for resizes - const method = event.type === 'enterfullscreen' ? on : off; - method.call(player, window, 'resize', resized); + + setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport + + if (!usingNative) { + if (isEnter) { + on.call(player, window, 'resize', resized); + } else { + off.call(player, window, 'resize', resized); + } + } }); - }); - // Listen for media events - _defineProperty$1(this, "media", () => { - const { - player - } = this; - const { - elements - } = player; - - // Time change on media - on.call(player, player.media, 'timeupdate seeking seeked', event => controls.timeUpdate.call(player, event)); - - // Display duration - on.call(player, player.media, 'durationchange loadeddata loadedmetadata', event => controls.durationUpdate.call(player, event)); - - // Handle the media finishing - on.call(player, player.media, 'ended', () => { + } // Listen for media events + + }, { + key: "media", + value: function media() { + var _this = this; + + var player = this.player; + var elements = player.elements; // Time change on media + + on.call(player, player.media, 'timeupdate seeking seeked', function (event) { + return controls.timeUpdate.call(player, event); + }); // Display duration + + on.call(player, player.media, 'durationchange loadeddata loadedmetadata', function (event) { + return controls.durationUpdate.call(player, event); + }); // Handle the media finishing + + on.call(player, player.media, 'ended', function () { // Show poster on end if (player.isHTML5 && player.isVideo && player.config.resetOnEnd) { // Restart - player.restart(); + player.restart(); // Call pause otherwise IE11 will start playing the video again - // Call pause otherwise IE11 will start playing the video again player.pause(); } - }); + }); // Check for buffer progress - // Check for buffer progress - on.call(player, player.media, 'progress playing seeking seeked', event => controls.updateProgress.call(player, event)); + on.call(player, player.media, 'progress playing seeking seeked', function (event) { + return controls.updateProgress.call(player, event); + }); // Handle volume changes - // Handle volume changes - on.call(player, player.media, 'volumechange', event => controls.updateVolume.call(player, event)); + on.call(player, player.media, 'volumechange', function (event) { + return controls.updateVolume.call(player, event); + }); // Handle play/pause - // Handle play/pause - on.call(player, player.media, 'playing play pause ended emptied timeupdate', event => ui.checkPlaying.call(player, event)); + on.call(player, player.media, 'playing play pause ended emptied timeupdate', function (event) { + return ui.checkPlaying.call(player, event); + }); // Loading state - // Loading state - on.call(player, player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(player, event)); + on.call(player, player.media, 'waiting canplay seeked playing', function (event) { + return ui.checkLoading.call(player, event); + }); // Click video - // Click video if (player.supported.ui && player.config.clickToPlay && !player.isAudio) { // Re-fetch the wrapper - const wrapper = getElement.call(player, `.${player.config.classNames.video}`); + var wrapper = getElement.call(player, ".".concat(player.config.classNames.video)); // Bail if there's no wrapper (this should never happen) - // Bail if there's no wrapper (this should never happen) - if (!is.element(wrapper)) { + if (!is$1.element(wrapper)) { return; - } + } // On click play, pause or restart - // On click play, pause or restart - on.call(player, elements.container, 'click', event => { - const targets = [elements.container, wrapper]; - // Ignore if click if not container or in video wrapper + on.call(player, elements.container, 'click', function (event) { + var targets = [elements.container, wrapper]; // Ignore if click if not container or in video wrapper + if (!targets.includes(event.target) && !wrapper.contains(event.target)) { return; - } + } // Touch devices will just show controls (if hidden) + - // Touch devices will just show controls (if hidden) if (player.touch && player.config.hideControls) { return; } + if (player.ended) { - this.proxy(event, player.restart, 'restart'); - this.proxy(event, () => { + _this.proxy(event, player.restart, 'restart'); + + _this.proxy(event, function () { silencePromise(player.play()); }, 'play'); } else { - this.proxy(event, () => { + _this.proxy(event, function () { silencePromise(player.togglePlay()); }, 'play'); } }); - } + } // Disable right click + - // Disable right click if (player.supported.ui && player.config.disableContextMenu) { - on.call(player, elements.wrapper, 'contextmenu', event => { + on.call(player, elements.wrapper, 'contextmenu', function (event) { event.preventDefault(); }, false); - } + } // Volume change - // Volume change - on.call(player, player.media, 'volumechange', () => { + + on.call(player, player.media, 'volumechange', function () { // Save to storage player.storage.set({ volume: player.volume, muted: player.muted }); - }); + }); // Speed change - // Speed change - on.call(player, player.media, 'ratechange', () => { + on.call(player, player.media, 'ratechange', function () { // Update UI - controls.updateSetting.call(player, 'speed'); + controls.updateSetting.call(player, 'speed'); // Save to storage + - // Save to storage player.storage.set({ speed: player.speed }); - }); + }); // Quality change - // Quality change - on.call(player, player.media, 'qualitychange', event => { + on.call(player, player.media, 'qualitychange', function (event) { // Update UI controls.updateSetting.call(player, 'quality', null, event.detail.quality); - }); + }); // Update download link when ready and if quality changes - // Update download link when ready and if quality changes - on.call(player, player.media, 'ready qualitychange', () => { + on.call(player, player.media, 'ready qualitychange', function () { controls.setDownloadUrl.call(player); - }); - - // Proxy events to container + }); // Proxy events to container // Bubble up key events for Edge - const proxyEvents = player.config.events.concat(['keyup', 'keydown']).join(' '); - on.call(player, player.media, proxyEvents, event => { - let { - detail = {} - } = event; - // Get error details from media + var proxyEvents = player.config.events.concat(['keyup', 'keydown']).join(' '); + on.call(player, player.media, proxyEvents, function (event) { + var _event$detail = event.detail, + detail = _event$detail === void 0 ? {} : _event$detail; // Get error details from media + if (event.type === 'error') { detail = player.media.error; } + triggerEvent.call(player, elements.container, event.type, true, detail); }); - }); - // Run default and custom handlers - _defineProperty$1(this, "proxy", (event, defaultHandler, customHandlerKey) => { - const { - player - } = this; - const customHandler = player.config.listeners[customHandlerKey]; - const hasCustomHandler = is.function(customHandler); - let returned = true; - - // Execute custom handler + } // Run default and custom handlers + + }, { + key: "proxy", + value: function proxy(event, defaultHandler, customHandlerKey) { + var player = this.player; + var customHandler = player.config.listeners[customHandlerKey]; + var hasCustomHandler = is$1.function(customHandler); + var returned = true; // Execute custom handler + if (hasCustomHandler) { returned = customHandler.call(player, event); - } + } // Only call default handler if not prevented in custom handler + - // Only call default handler if not prevented in custom handler - if (returned !== false && is.function(defaultHandler)) { + if (returned !== false && is$1.function(defaultHandler)) { defaultHandler.call(player, event); } - }); - // Trigger custom and default handlers - _defineProperty$1(this, "bind", (element, type, defaultHandler, customHandlerKey, passive = true) => { - const { - player - } = this; - const customHandler = player.config.listeners[customHandlerKey]; - const hasCustomHandler = is.function(customHandler); - on.call(player, element, type, event => this.proxy(event, defaultHandler, customHandlerKey), passive && !hasCustomHandler); - }); - // Listen for control events - _defineProperty$1(this, "controls", () => { - const { - player - } = this; - const { - elements - } = player; - // IE doesn't support input event, so we fallback to change - const inputEvent = browser.isIE ? 'change' : 'input'; - - // Play/pause toggle + } // Trigger custom and default handlers + + }, { + key: "bind", + value: function bind(element, type, defaultHandler, customHandlerKey) { + var _this2 = this; + + var passive = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; + var player = this.player; + var customHandler = player.config.listeners[customHandlerKey]; + var hasCustomHandler = is$1.function(customHandler); + on.call(player, element, type, function (event) { + return _this2.proxy(event, defaultHandler, customHandlerKey); + }, passive && !hasCustomHandler); + } // Listen for control events + + }, { + key: "controls", + value: function controls$1() { + var _this3 = this; + + var player = this.player; + var elements = player.elements; // IE doesn't support input event, so we fallback to change + + var inputEvent = browser.isIE ? 'change' : 'input'; // Play/pause toggle + if (elements.buttons.play) { - Array.from(elements.buttons.play).forEach(button => { - this.bind(button, 'click', () => { + Array.from(elements.buttons.play).forEach(function (button) { + _this3.bind(button, 'click', function () { silencePromise(player.togglePlay()); }, 'play'); }); - } + } // Pause - // Pause - this.bind(elements.buttons.restart, 'click', player.restart, 'restart'); - - // Rewind - this.bind(elements.buttons.rewind, 'click', () => { - // Record seek time so we can prevent hiding controls for a few seconds after rewind - player.lastSeekTime = Date.now(); - player.rewind(); - }, 'rewind'); - - // Rewind - this.bind(elements.buttons.fastForward, 'click', () => { - // Record seek time so we can prevent hiding controls for a few seconds after fast forward - player.lastSeekTime = Date.now(); - player.forward(); - }, 'fastForward'); - - // Mute toggle - this.bind(elements.buttons.mute, 'click', () => { + + this.bind(elements.buttons.restart, 'click', player.restart, 'restart'); // Rewind + + this.bind(elements.buttons.rewind, 'click', player.rewind, 'rewind'); // Rewind + + this.bind(elements.buttons.fastForward, 'click', player.forward, 'fastForward'); // Mute toggle + + this.bind(elements.buttons.mute, 'click', function () { player.muted = !player.muted; - }, 'mute'); + }, 'mute'); // Captions toggle - // Captions toggle - this.bind(elements.buttons.captions, 'click', () => player.toggleCaptions()); + this.bind(elements.buttons.captions, 'click', function () { + return player.toggleCaptions(); + }); // Download - // Download - this.bind(elements.buttons.download, 'click', () => { + this.bind(elements.buttons.download, 'click', function () { triggerEvent.call(player, player.media, 'download'); - }, 'download'); + }, 'download'); // Fullscreen toggle - // Fullscreen toggle - this.bind(elements.buttons.fullscreen, 'click', () => { + this.bind(elements.buttons.fullscreen, 'click', function () { player.fullscreen.toggle(); - }, 'fullscreen'); + }, 'fullscreen'); // Picture-in-Picture - // Picture-in-Picture - this.bind(elements.buttons.pip, 'click', () => { + this.bind(elements.buttons.pip, 'click', function () { player.pip = 'toggle'; - }, 'pip'); + }, 'pip'); // Airplay - // Airplay - this.bind(elements.buttons.airplay, 'click', player.airplay, 'airplay'); + this.bind(elements.buttons.airplay, 'click', player.airplay, 'airplay'); // Settings menu - click toggle - // Settings menu - click toggle - this.bind(elements.buttons.settings, 'click', event => { + this.bind(elements.buttons.settings, 'click', function (event) { // Prevent the document click listener closing the menu event.stopPropagation(); event.preventDefault(); + controls.toggleMenu.call(player, event); }, null, false); // Can't be passive as we're preventing default - // Settings menu - keyboard toggle // We have to bind to keyup otherwise Firefox triggers a click when a keydown event handler shifts focus // https://bugzilla.mozilla.org/show_bug.cgi?id=1220143 - this.bind(elements.buttons.settings, 'keyup', event => { - if (![' ', 'Enter'].includes(event.key)) { + + this.bind(elements.buttons.settings, 'keyup', function (event) { + var code = event.which; // We only care about space and return + + if (![13, 32].includes(code)) { return; - } + } // Because return triggers a click anyway, all we need to do is set focus + - // Because return triggers a click anyway, all we need to do is set focus - if (event.key === 'Enter') { + if (code === 13) { controls.focusFirstMenuItem.call(player, null, true); + return; - } + } // Prevent scroll - // Prevent scroll - event.preventDefault(); - // Prevent playing video (Firefox) - event.stopPropagation(); + event.preventDefault(); // Prevent playing video (Firefox) + + event.stopPropagation(); // Toggle menu - // Toggle menu controls.toggleMenu.call(player, event); }, null, false // Can't be passive as we're preventing default - ); + ); // Escape closes menu - // Escape closes menu - this.bind(elements.settings.menu, 'keydown', event => { - if (event.key === 'Escape') { + this.bind(elements.settings.menu, 'keydown', function (event) { + if (event.which === 27) { controls.toggleMenu.call(player, event); } - }); + }); // Set range input alternative "value", which matches the tooltip time (#954) - // Set range input alternative "value", which matches the tooltip time (#954) - this.bind(elements.inputs.seek, 'mousedown mousemove', event => { - const rect = elements.progress.getBoundingClientRect(); - const percent = 100 / rect.width * (event.pageX - rect.left); + this.bind(elements.inputs.seek, 'mousedown mousemove', function (event) { + var rect = elements.progress.getBoundingClientRect(); + var percent = 100 / rect.width * (event.pageX - rect.left); event.currentTarget.setAttribute('seek-value', percent); - }); + }); // Pause while seeking + + this.bind(elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', function (event) { + var seek = event.currentTarget; + var code = event.keyCode ? event.keyCode : event.which; + var attribute = 'play-on-seeked'; - // Pause while seeking - this.bind(elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', event => { - const seek = event.currentTarget; - const attribute = 'play-on-seeked'; - if (is.keyboardEvent(event) && !['ArrowLeft', 'ArrowRight'].includes(event.key)) { + if (is$1.keyboardEvent(event) && code !== 39 && code !== 37) { return; - } + } // Record seek time so we can prevent hiding controls for a few seconds after seek + - // Record seek time so we can prevent hiding controls for a few seconds after seek - player.lastSeekTime = Date.now(); + player.lastSeekTime = Date.now(); // Was playing before? - // Was playing before? - const play = seek.hasAttribute(attribute); - // Done seeking - const done = ['mouseup', 'touchend', 'keyup'].includes(event.type); + var play = seek.hasAttribute(attribute); // Done seeking + + var done = ['mouseup', 'touchend', 'keyup'].includes(event.type); // If we're done seeking and it was playing, resume playback - // If we're done seeking and it was playing, resume playback if (play && done) { seek.removeAttribute(attribute); silencePromise(player.play()); @@ -4819,310 +5208,165 @@ typeof navigator === "object" && (function (global, factory) { seek.setAttribute(attribute, ''); player.pause(); } - }); - - // Fix range inputs on iOS + }); // Fix range inputs on iOS // Super weird iOS bug where after you interact with an , // it takes over further interactions on the page. This is a hack + if (browser.isIos) { - const inputs = getElements.call(player, 'input[type="range"]'); - Array.from(inputs).forEach(input => this.bind(input, inputEvent, event => repaint(event.target))); - } + var inputs = getElements.call(player, 'input[type="range"]'); + Array.from(inputs).forEach(function (input) { + return _this3.bind(input, inputEvent, function (event) { + return repaint(event.target); + }); + }); + } // Seek + - // Seek - this.bind(elements.inputs.seek, inputEvent, event => { - const seek = event.currentTarget; - // If it exists, use seek-value instead of "value" for consistency with tooltip time (#954) - let seekTo = seek.getAttribute('seek-value'); - if (is.empty(seekTo)) { + this.bind(elements.inputs.seek, inputEvent, function (event) { + var seek = event.currentTarget; // If it exists, use seek-value instead of "value" for consistency with tooltip time (#954) + + var seekTo = seek.getAttribute('seek-value'); + + if (is$1.empty(seekTo)) { seekTo = seek.value; } + seek.removeAttribute('seek-value'); player.currentTime = seekTo / seek.max * player.duration; - }, 'seek'); - - // Seek tooltip - this.bind(elements.progress, 'mouseenter mouseleave mousemove', event => controls.updateSeekTooltip.call(player, event)); + }, 'seek'); // Seek tooltip - // Preview thumbnails plugin + this.bind(elements.progress, 'mouseenter mouseleave mousemove', function (event) { + return controls.updateSeekTooltip.call(player, event); + }); // Preview thumbnails plugin // TODO: Really need to work on some sort of plug-in wide event bus or pub-sub for this - this.bind(elements.progress, 'mousemove touchmove', event => { - const { - previewThumbnails - } = player; + + this.bind(elements.progress, 'mousemove touchmove', function (event) { + var previewThumbnails = player.previewThumbnails; + if (previewThumbnails && previewThumbnails.loaded) { previewThumbnails.startMove(event); } - }); + }); // Hide thumbnail preview - on mouse click, mouse leave, and video play/seek. All four are required, e.g., for buffering + + this.bind(elements.progress, 'mouseleave touchend click', function () { + var previewThumbnails = player.previewThumbnails; - // Hide thumbnail preview - on mouse click, mouse leave, and video play/seek. All four are required, e.g., for buffering - this.bind(elements.progress, 'mouseleave touchend click', () => { - const { - previewThumbnails - } = player; if (previewThumbnails && previewThumbnails.loaded) { previewThumbnails.endMove(false, true); } - }); + }); // Show scrubbing preview + + this.bind(elements.progress, 'mousedown touchstart', function (event) { + var previewThumbnails = player.previewThumbnails; - // Show scrubbing preview - this.bind(elements.progress, 'mousedown touchstart', event => { - const { - previewThumbnails - } = player; if (previewThumbnails && previewThumbnails.loaded) { previewThumbnails.startScrubbing(event); } }); - this.bind(elements.progress, 'mouseup touchend', event => { - const { - previewThumbnails - } = player; + this.bind(elements.progress, 'mouseup touchend', function (event) { + var previewThumbnails = player.previewThumbnails; + if (previewThumbnails && previewThumbnails.loaded) { previewThumbnails.endScrubbing(event); } - }); + }); // Polyfill for lower fill in for webkit - // Polyfill for lower fill in for webkit - if (browser.isWebKit) { - Array.from(getElements.call(player, 'input[type="range"]')).forEach(element => { - this.bind(element, 'input', event => controls.updateRangeFill.call(player, event.target)); + if (browser.isWebkit) { + Array.from(getElements.call(player, 'input[type="range"]')).forEach(function (element) { + _this3.bind(element, 'input', function (event) { + return controls.updateRangeFill.call(player, event.target); + }); }); - } - - // Current time invert + } // Current time invert // Only if one time element is used for both currentTime and duration - if (player.config.toggleInvert && !is.element(elements.display.duration)) { - this.bind(elements.display.currentTime, 'click', () => { + + + if (player.config.toggleInvert && !is$1.element(elements.display.duration)) { + this.bind(elements.display.currentTime, 'click', function () { // Do nothing if we're at the start if (player.currentTime === 0) { return; } + player.config.invertTime = !player.config.invertTime; + controls.timeUpdate.call(player); }); - } + } // Volume - // Volume - this.bind(elements.inputs.volume, inputEvent, event => { + + this.bind(elements.inputs.volume, inputEvent, function (event) { player.volume = event.target.value; - }, 'volume'); + }, 'volume'); // Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting) - // Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting) - this.bind(elements.controls, 'mouseenter mouseleave', event => { + this.bind(elements.controls, 'mouseenter mouseleave', function (event) { elements.controls.hover = !player.touch && event.type === 'mouseenter'; - }); + }); // Also update controls.hover state for any non-player children of fullscreen element (as above) - // Also update controls.hover state for any non-player children of fullscreen element (as above) if (elements.fullscreen) { - Array.from(elements.fullscreen.children).filter(c => !c.contains(elements.container)).forEach(child => { - this.bind(child, 'mouseenter mouseleave', event => { - if (elements.controls) { - elements.controls.hover = !player.touch && event.type === 'mouseenter'; - } + Array.from(elements.fullscreen.children).filter(function (c) { + return !c.contains(elements.container); + }).forEach(function (child) { + _this3.bind(child, 'mouseenter mouseleave', function (event) { + elements.controls.hover = !player.touch && event.type === 'mouseenter'; }); }); - } + } // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting) - // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting) - this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => { + + this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) { elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); - }); + }); // Show controls when they receive focus (e.g., when using keyboard tab key) - // Show controls when they receive focus (e.g., when using keyboard tab key) - this.bind(elements.controls, 'focusin', () => { - const { - config, - timers - } = player; + this.bind(elements.controls, 'focusin', function () { + var config = player.config, + timers = player.timers; // Skip transition to prevent focus from scrolling the parent element - // Skip transition to prevent focus from scrolling the parent element - toggleClass(elements.controls, config.classNames.noTransition, true); + toggleClass(elements.controls, config.classNames.noTransition, true); // Toggle - // Toggle - ui.toggleControls.call(player, true); + ui.toggleControls.call(player, true); // Restore transition - // Restore transition - setTimeout(() => { + setTimeout(function () { toggleClass(elements.controls, config.classNames.noTransition, false); - }, 0); + }, 0); // Delay a little more for mouse users - // Delay a little more for mouse users - const delay = this.touch ? 3000 : 4000; + var delay = _this3.touch ? 3000 : 4000; // Clear timer - // Clear timer - clearTimeout(timers.controls); + clearTimeout(timers.controls); // Hide again after delay - // Hide again after delay - timers.controls = setTimeout(() => ui.toggleControls.call(player, false), delay); - }); + timers.controls = setTimeout(function () { + return ui.toggleControls.call(player, false); + }, delay); + }); // Mouse wheel for volume - // Mouse wheel for volume - this.bind(elements.inputs.volume, 'wheel', event => { - // Detect "natural" scroll - supported on OS X Safari only + this.bind(elements.inputs.volume, 'wheel', function (event) { + // Detect "natural" scroll - suppored on OS X Safari only // Other browsers on OS X will be inverted until support improves - const inverted = event.webkitDirectionInvertedFromDevice; - // Get delta from event. Invert if `inverted` is true - const [x, y] = [event.deltaX, -event.deltaY].map(value => inverted ? -value : value); - // Using the biggest delta, normalize to 1 or -1 (or 0 if no delta) - const direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y); - - // Change the volume by 2% - player.increaseVolume(direction / 50); - - // Don't break page scrolling at max and min - const { - volume - } = player.media; - if (direction === 1 && volume < 1 || direction === -1 && volume > 0) { - event.preventDefault(); - } - }, 'volume', false); - }); - this.player = _player; - this.lastKey = null; - this.focusTimer = null; - this.lastKeyDown = null; - this.handleKey = this.handleKey.bind(this); - this.toggleMenu = this.toggleMenu.bind(this); - this.firstTouch = this.firstTouch.bind(this); - } - - // Handle key presses - handleKey(event) { - const { - player - } = this; - const { - elements - } = player; - const { - key, - type, - altKey, - ctrlKey, - metaKey, - shiftKey - } = event; - const pressed = type === 'keydown'; - const repeat = pressed && key === this.lastKey; - - // Bail if a modifier key is set - if (altKey || ctrlKey || metaKey || shiftKey) { - return; - } - - // If the event is bubbled from the media element - // Firefox doesn't get the key for whatever reason - if (!key) { - return; - } + var inverted = event.webkitDirectionInvertedFromDevice; // Get delta from event. Invert if `inverted` is true - // Seek by increment - const seekByIncrement = increment => { - // Divide the max duration into 10th's and times by the number value - player.currentTime = player.duration / 10 * increment; - }; + var _map = [event.deltaX, -event.deltaY].map(function (value) { + return inverted ? -value : value; + }), + _map2 = _slicedToArray(_map, 2), + x = _map2[0], + y = _map2[1]; // Using the biggest delta, normalize to 1 or -1 (or 0 if no delta) - // Handle the key on keydown - // Reset on keyup - if (pressed) { - // Check focused element - // and if the focused element is not editable (e.g. text input) - // and any that accept key input http://webaim.org/techniques/keyboard/ - const focused = document.activeElement; - if (is.element(focused)) { - const { - editable - } = player.config.selectors; - const { - seek - } = elements.inputs; - if (focused !== seek && matches(focused, editable)) { - return; - } - if (event.key === ' ' && matches(focused, 'button, [role^="menuitem"]')) { - return; - } - } - // Which keys should we prevent default - const preventDefault = [' ', 'ArrowLeft', 'ArrowUp', 'ArrowRight', 'ArrowDown', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'c', 'f', 'k', 'l', 'm']; + var direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y); // Change the volume by 2% - // If the key is found prevent default (e.g. prevent scrolling for arrows) - if (preventDefault.includes(key)) { - event.preventDefault(); - event.stopPropagation(); - } - switch (key) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (!repeat) { - seekByIncrement(parseInt(key, 10)); - } - break; - case ' ': - case 'k': - if (!repeat) { - silencePromise(player.togglePlay()); - } - break; - case 'ArrowUp': - player.increaseVolume(0.1); - break; - case 'ArrowDown': - player.decreaseVolume(0.1); - break; - case 'm': - if (!repeat) { - player.muted = !player.muted; - } - break; - case 'ArrowRight': - player.forward(); - break; - case 'ArrowLeft': - player.rewind(); - break; - case 'f': - player.fullscreen.toggle(); - break; - case 'c': - if (!repeat) { - player.toggleCaptions(); - } - break; - case 'l': - player.loop = !player.loop; - break; - } + player.increaseVolume(direction / 50); // Don't break page scrolling at max and min - // Escape is handle natively when in full screen - // So we only need to worry about non native - if (key === 'Escape' && !player.fullscreen.usingNative && player.fullscreen.active) { - player.fullscreen.toggle(); - } + var volume = player.media.volume; - // Store last key for next cycle - this.lastKey = key; - } else { - this.lastKey = null; + if (direction === 1 && volume < 1 || direction === -1 && volume > 0) { + event.preventDefault(); + } + }, 'volume', false); } - } + }]); - // Toggle menu - toggleMenu(event) { - controls.toggleMenu.call(this.player, event); - } - } + return Listeners; + }(); var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; @@ -5140,115 +5384,112 @@ typeof navigator === "object" && (function (global, factory) { * Global dependencies. * @global {Object} document - DOM */ - - var devnull = function () {}, - bundleIdCache = {}, - bundleResultCache = {}, - bundleCallbackQueue = {}; - + var devnull = function devnull() {}, + bundleIdCache = {}, + bundleResultCache = {}, + bundleCallbackQueue = {}; /** * Subscribe to bundle load event. * @param {string[]} bundleIds - Bundle ids * @param {Function} callbackFn - The callback function */ + + function subscribe(bundleIds, callbackFn) { // listify bundleIds = bundleIds.push ? bundleIds : [bundleIds]; var depsNotFound = [], - i = bundleIds.length, - numWaiting = i, - fn, - bundleId, - r, - q; - - // define callback function - fn = function (bundleId, pathsNotFound) { + i = bundleIds.length, + numWaiting = i, + fn, + bundleId, + r, + q; // define callback function + + fn = function fn(bundleId, pathsNotFound) { if (pathsNotFound.length) depsNotFound.push(bundleId); numWaiting--; if (!numWaiting) callbackFn(depsNotFound); - }; + }; // register callback + - // register callback while (i--) { - bundleId = bundleIds[i]; + bundleId = bundleIds[i]; // execute callback if in result cache - // execute callback if in result cache r = bundleResultCache[bundleId]; + if (r) { fn(bundleId, r); continue; - } + } // add to callback queue + - // add to callback queue q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || []; q.push(fn); } } - /** * Publish bundle load event. * @param {string} bundleId - Bundle id * @param {string[]} pathsNotFound - List of files not found */ + + function publish(bundleId, pathsNotFound) { // exit if id isn't defined if (!bundleId) return; - var q = bundleCallbackQueue[bundleId]; + var q = bundleCallbackQueue[bundleId]; // cache result - // cache result - bundleResultCache[bundleId] = pathsNotFound; + bundleResultCache[bundleId] = pathsNotFound; // exit if queue is empty - // exit if queue is empty - if (!q) return; + if (!q) return; // empty callback queue - // empty callback queue while (q.length) { q[0](bundleId, pathsNotFound); q.splice(0, 1); } } - /** * Execute callbacks. * @param {Object or Function} args - The callback args * @param {string[]} depsNotFound - List of dependencies not found */ + + function executeCallbacks(args, depsNotFound) { // accept function as argument if (args.call) args = { success: args - }; + }; // success and error callbacks - // success and error callbacks if (depsNotFound.length) (args.error || devnull)(depsNotFound);else (args.success || devnull)(args); } - /** * Load individual file. * @param {string} path - The file path * @param {Function} callbackFn - The callback function */ + + function loadFile(path, callbackFn, args, numTries) { var doc = document, - async = args.async, - maxTries = (args.numRetries || 0) + 1, - beforeCallbackFn = args.before || devnull, - pathname = path.replace(/[\?|#].*$/, ''), - pathStripped = path.replace(/^(css|img)!/, ''), - isLegacyIECss, - e; + async = args.async, + maxTries = (args.numRetries || 0) + 1, + beforeCallbackFn = args.before || devnull, + pathname = path.replace(/[\?|#].*$/, ''), + pathStripped = path.replace(/^(css|img)!/, ''), + isLegacyIECss, + e; numTries = numTries || 0; + if (/(^css!|\.css$)/.test(pathname)) { // css e = doc.createElement('link'); e.rel = 'stylesheet'; - e.href = pathStripped; + e.href = pathStripped; // tag IE9+ - // tag IE9+ - isLegacyIECss = 'hideFocus' in e; + isLegacyIECss = 'hideFocus' in e; // use preload in IE Edge (to detect load errors) - // use preload in IE Edge (to detect load errors) if (isLegacyIECss && e.relList) { isLegacyIECss = 0; e.rel = 'preload'; @@ -5264,11 +5505,11 @@ typeof navigator === "object" && (function (global, factory) { e.src = path; e.async = async === undefined ? true : async; } - e.onload = e.onerror = e.onbeforeload = function (ev) { - var result = ev.type[0]; - // treat empty stylesheets as failures to get around lack of onerror + e.onload = e.onerror = e.onbeforeload = function (ev) { + var result = ev.type[0]; // treat empty stylesheets as failures to get around lack of onerror // support in IE9-11 + if (isLegacyIECss) { try { if (!e.sheet.cssText.length) result = 'e'; @@ -5277,62 +5518,62 @@ typeof navigator === "object" && (function (global, factory) { // `cssText` (unless error is Code:18 SecurityError) if (x.code != 18) result = 'e'; } - } + } // handle retries in case of load failure + - // handle retries in case of load failure if (result == 'e') { // increment counter - numTries += 1; + numTries += 1; // exit function and try again - // exit function and try again if (numTries < maxTries) { return loadFile(path, callbackFn, args, numTries); } } else if (e.rel == 'preload' && e.as == 'style') { // activate preloaded stylesheets return e.rel = 'stylesheet'; // jshint ignore:line - } + } // execute callback + - // execute callback callbackFn(path, result, ev.defaultPrevented); - }; + }; // add to document (unless callback returns `false`) + - // add to document (unless callback returns `false`) if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e); } - /** * Load multiple files. * @param {string[]} paths - The file paths * @param {Function} callbackFn - The callback function */ + + function loadFiles(paths, callbackFn, args) { // listify paths paths = paths.push ? paths : [paths]; var numWaiting = paths.length, - x = numWaiting, - pathsNotFound = [], - fn, - i; + x = numWaiting, + pathsNotFound = [], + fn, + i; // define callback function - // define callback function - fn = function (path, result, defaultPrevented) { + fn = function fn(path, result, defaultPrevented) { // handle error - if (result == 'e') pathsNotFound.push(path); - - // handle beforeload event. If defaultPrevented then that means the load + if (result == 'e') pathsNotFound.push(path); // handle beforeload event. If defaultPrevented then that means the load // will be blocked (ex. Ghostery/ABP on Safari) + if (result == 'b') { if (defaultPrevented) pathsNotFound.push(path);else return; } + numWaiting--; if (!numWaiting) callbackFn(pathsNotFound); - }; + }; // load scripts - // load scripts - for (i = 0; i < x; i++) loadFile(paths[i], fn, args); - } + for (i = 0; i < x; i++) { + loadFile(paths[i], fn, args); + } + } /** * Initiate script load and register bundle. * @param {(string|string[])} paths - The file paths @@ -5342,16 +5583,15 @@ typeof navigator === "object" && (function (global, factory) { * @param {(Function|Object)} [arg2] - The (1) success callback or (2) object * literal with success/error arguments, numRetries, etc. */ + + function loadjs(paths, arg1, arg2) { - var bundleId, args; + var bundleId, args; // bundleId (if string) - // bundleId (if string) - if (arg1 && arg1.trim) bundleId = arg1; + if (arg1 && arg1.trim) bundleId = arg1; // args (default is {}) - // args (default is {}) - args = (bundleId ? arg2 : arg1) || {}; + args = (bundleId ? arg2 : arg1) || {}; // throw error if bundle is already defined - // throw error if bundle is already defined if (bundleId) { if (bundleId in bundleIdCache) { throw "LoadJS"; @@ -5359,31 +5599,33 @@ typeof navigator === "object" && (function (global, factory) { bundleIdCache[bundleId] = true; } } + function loadFn(resolve, reject) { loadFiles(paths, function (pathsNotFound) { // execute callbacks - executeCallbacks(args, pathsNotFound); + executeCallbacks(args, pathsNotFound); // resolve Promise - // resolve Promise if (resolve) { executeCallbacks({ success: resolve, error: reject }, pathsNotFound); - } + } // publish bundle load event + - // publish bundle load event publish(bundleId, pathsNotFound); }, args); } + if (args.returnPromise) return new Promise(loadFn);else loadFn(); } - /** * Execute callbacks when dependencies have been satisfied. * @param {(string|string[])} deps - List of bundle ids * @param {Object} args - success/error arguments */ + + loadjs.ready = function ready(deps, args) { // subscribe to bundle load event subscribe(deps, function (depsNotFound) { @@ -5392,43 +5634,43 @@ typeof navigator === "object" && (function (global, factory) { }); return loadjs; }; - /** * Manually satisfy bundle dependencies. * @param {string} bundleId - The bundle id */ + + loadjs.done = function done(bundleId) { publish(bundleId, []); }; - /** * Reset loadjs dependencies statuses */ + + loadjs.reset = function reset() { bundleIdCache = {}; bundleResultCache = {}; bundleCallbackQueue = {}; }; - /** * Determine if bundle has already been defined * @param String} bundleId - The bundle id */ + + loadjs.isDefined = function isDefined(bundleId) { return bundleId in bundleIdCache; - }; + }; // export + - // export return loadjs; }); }); // ========================================================================== - // Load an external script - // ========================================================================== - function loadScript(url) { - return new Promise((resolve, reject) => { + return new Promise(function (resolve, reject) { loadjs_umd(url, { success: resolve, error: reject @@ -5436,65 +5678,45 @@ typeof navigator === "object" && (function (global, factory) { }); } - // ========================================================================== - // Vimeo plugin - // ========================================================================== - - - // Parse Vimeo ID from URL - function parseId$1(url) { - if (is.empty(url)) { + function parseId(url) { + if (is$1.empty(url)) { return null; } - if (is.number(Number(url))) { + + if (is$1.number(Number(url))) { return url; } - const regex = /^.*(vimeo.com\/|video\/)(\d+).*/; + + var regex = /^.*(vimeo.com\/|video\/)(\d+).*/; return url.match(regex) ? RegExp.$2 : url; - } + } // Set playback state and trigger change (only on actual change) - // Try to extract a hash for private videos from the URL - function parseHash(url) { - /* This regex matches a hexadecimal hash if given in any of these forms: - * - [https://player.]vimeo.com/video/{id}/{hash}[?params] - * - [https://player.]vimeo.com/video/{id}?h={hash}[¶ms] - * - [https://player.]vimeo.com/video/{id}?[params]&h={hash} - * - video/{id}/{hash} - * If matched, the hash is available in capture group 4 - */ - const regex = /^.*(vimeo.com\/|video\/)(\d+)(\?.*&*h=|\/)+([\d,a-f]+)/; - const found = url.match(regex); - return found && found.length === 5 ? found[4] : null; - } - // Set playback state and trigger change (only on actual change) - function assurePlaybackState$1(play) { + function assurePlaybackState(play) { if (play && !this.embed.hasPlayed) { this.embed.hasPlayed = true; } + if (this.media.paused === play) { this.media.paused = !play; triggerEvent.call(this, this.media, play ? 'play' : 'pause'); } } - const vimeo = { - setup() { - const player = this; - // Add embed class for responsive - toggleClass(player.elements.wrapper, player.config.classNames.embed, true); + var vimeo = { + setup: function setup() { + var player = this; // Add embed class for responsive + + toggleClass(player.elements.wrapper, player.config.classNames.embed, true); // Set speed options from config - // Set speed options from config - player.options.speed = player.config.speed.options; + player.options.speed = player.config.speed.options; // Set intial ratio - // Set intial ratio - setAspectRatio.call(player); + setAspectRatio.call(player); // Load the SDK if not already - // Load the SDK if not already - if (!is.object(window.Vimeo)) { - loadScript(player.config.urls.vimeo.sdk).then(() => { + if (!is$1.object(window.Vimeo)) { + loadScript(player.config.urls.vimeo.sdk).then(function () { vimeo.ready.call(player); - }).catch(error => { + }).catch(function (error) { player.debug.warn('Vimeo SDK (player.js) failed to load', error); }); } else { @@ -5502,497 +5724,479 @@ typeof navigator === "object" && (function (global, factory) { } }, // API Ready - ready() { - const player = this; - const config = player.config.vimeo; - const { - premium, - referrerPolicy, - ...frameParams - } = config; - // Get the source URL or ID - let source = player.media.getAttribute('src'); - let hash = ''; - // Get from
if needed - if (is.empty(source)) { - source = player.media.getAttribute(player.config.attributes.embed.id); - // hash can also be set as attribute on the
- hash = player.media.getAttribute(player.config.attributes.embed.hash); - } else { - hash = parseHash(source); - } - const hashParam = hash ? { - h: hash - } : {}; + ready: function ready() { + var _this = this; + + var player = this; + var config = player.config.vimeo; + + var premium = config.premium, + referrerPolicy = config.referrerPolicy, + frameParams = _objectWithoutProperties(config, ["premium", "referrerPolicy"]); // If the owner has a pro or premium account then we can hide controls etc + - // If the owner has a pro or premium account then we can hide controls etc if (premium) { Object.assign(frameParams, { controls: false, sidedock: false }); - } + } // Get Vimeo params for the iframe + - // Get Vimeo params for the iframe - const params = buildUrlParams({ + var params = buildUrlParams(_objectSpread2({ loop: player.config.loop.active, autoplay: player.autoplay, muted: player.muted, gesture: 'media', - playsinline: player.config.playsinline, - // hash has to be added to iframe-URL - ...hashParam, - ...frameParams - }); - const id = parseId$1(source); - // Build an iframe - const iframe = createElement('iframe'); - const src = format(player.config.urls.vimeo.iframe, id, params); + playsinline: !this.config.fullscreen.iosNative + }, frameParams)); // Get the source URL or ID + + var source = player.media.getAttribute('src'); // Get from
if needed + + if (is$1.empty(source)) { + source = player.media.getAttribute(player.config.attributes.embed.id); + } + + var id = parseId(source); // Build an iframe + + var iframe = createElement('iframe'); + var src = format(player.config.urls.vimeo.iframe, id, params); iframe.setAttribute('src', src); iframe.setAttribute('allowfullscreen', ''); - iframe.setAttribute('allow', ['autoplay', 'fullscreen', 'picture-in-picture', 'encrypted-media', 'accelerometer', 'gyroscope'].join('; ')); + iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required - // Set the referrer policy if required - if (!is.empty(referrerPolicy)) { + if (!is$1.empty(referrerPolicy)) { iframe.setAttribute('referrerPolicy', referrerPolicy); - } + } // Inject the package - // Inject the package - if (premium || !config.customControls) { - iframe.setAttribute('data-poster', player.poster); + + var poster = player.poster; + + if (premium) { + iframe.setAttribute('data-poster', poster); player.media = replaceElement(iframe, player.media); } else { - const wrapper = createElement('div', { + var wrapper = createElement('div', { class: player.config.classNames.embedContainer, - 'data-poster': player.poster + 'data-poster': poster }); wrapper.appendChild(iframe); player.media = replaceElement(wrapper, player.media); - } + } // Get poster image - // Get poster image - if (!config.customControls) { - fetch(format(player.config.urls.vimeo.api, src)).then(response => { - if (is.empty(response) || !response.thumbnail_url) { - return; - } - // Set and show poster - ui.setPoster.call(player, response.thumbnail_url).catch(() => {}); - }); - } + fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) { + if (is$1.empty(response)) { + return; + } // Get the URL for thumbnail + + + var url = new URL(response[0].thumbnail_large); // Get original image + + url.pathname = "".concat(url.pathname.split('_')[0], ".jpg"); // Set and show poster - // Setup instance + ui.setPoster.call(player, url.href).catch(function () {}); + }); // Setup instance // https://github.com/vimeo/player.js + player.embed = new window.Vimeo.Player(iframe, { autopause: player.config.autopause, muted: player.muted }); player.media.paused = true; - player.media.currentTime = 0; + player.media.currentTime = 0; // Disable native text track rendering - // Disable native text track rendering if (player.supported.ui) { player.embed.disableTextTrack(); - } + } // Create a faux HTML5 API using the Vimeo API - // Create a faux HTML5 API using the Vimeo API - player.media.play = () => { - assurePlaybackState$1.call(player, true); + + player.media.play = function () { + assurePlaybackState.call(player, true); return player.embed.play(); }; - player.media.pause = () => { - assurePlaybackState$1.call(player, false); + + player.media.pause = function () { + assurePlaybackState.call(player, false); return player.embed.pause(); }; - player.media.stop = () => { + + player.media.stop = function () { player.pause(); player.currentTime = 0; - }; + }; // Seeking - // Seeking - let { - currentTime - } = player.media; + + var currentTime = player.media.currentTime; Object.defineProperty(player.media, 'currentTime', { - get() { + get: function get() { return currentTime; }, - set(time) { + set: function set(time) { // Vimeo will automatically play on seek if the video hasn't been played before - // Get current paused state and volume etc - const { - embed, - media, - paused, - volume - } = player; - const restorePause = paused && !embed.hasPlayed; - - // Set seeking state and trigger event + var embed = player.embed, + media = player.media, + paused = player.paused, + volume = player.volume; + var restorePause = paused && !embed.hasPlayed; // Set seeking state and trigger event + media.seeking = true; - triggerEvent.call(player, media, 'seeking'); - - // If paused, mute until seek is complete - Promise.resolve(restorePause && embed.setVolume(0)) - // Seek - .then(() => embed.setCurrentTime(time)) - // Restore paused - .then(() => restorePause && embed.pause()) - // Restore volume - .then(() => restorePause && embed.setVolume(volume)).catch(() => { - // Do nothing + triggerEvent.call(player, media, 'seeking'); // If paused, mute until seek is complete + + Promise.resolve(restorePause && embed.setVolume(0)) // Seek + .then(function () { + return embed.setCurrentTime(time); + }) // Restore paused + .then(function () { + return restorePause && embed.pause(); + }) // Restore volume + .then(function () { + return restorePause && embed.setVolume(volume); + }).catch(function () {// Do nothing }); } - }); + }); // Playback speed - // Playback speed - let speed = player.config.speed.selected; + var speed = player.config.speed.selected; Object.defineProperty(player.media, 'playbackRate', { - get() { + get: function get() { return speed; }, - set(input) { - player.embed.setPlaybackRate(input).then(() => { + set: function set(input) { + player.embed.setPlaybackRate(input).then(function () { speed = input; triggerEvent.call(player, player.media, 'ratechange'); - }).catch(() => { + }).catch(function () { // Cannot set Playback Rate, Video is probably not on Pro account player.options.speed = [1]; }); } - }); + }); // Volume - // Volume - let { - volume - } = player.config; + var volume = player.config.volume; Object.defineProperty(player.media, 'volume', { - get() { + get: function get() { return volume; }, - set(input) { - player.embed.setVolume(input).then(() => { + set: function set(input) { + player.embed.setVolume(input).then(function () { volume = input; triggerEvent.call(player, player.media, 'volumechange'); }); } - }); + }); // Muted - // Muted - let { - muted - } = player.config; + var muted = player.config.muted; Object.defineProperty(player.media, 'muted', { - get() { + get: function get() { return muted; }, - set(input) { - const toggle = is.boolean(input) ? input : false; - player.embed.setMuted(toggle ? true : player.config.muted).then(() => { + set: function set(input) { + var toggle = is$1.boolean(input) ? input : false; + player.embed.setVolume(toggle ? 0 : player.config.volume).then(function () { muted = toggle; triggerEvent.call(player, player.media, 'volumechange'); }); } - }); + }); // Loop - // Loop - let { - loop - } = player.config; + var loop = player.config.loop; Object.defineProperty(player.media, 'loop', { - get() { + get: function get() { return loop; }, - set(input) { - const toggle = is.boolean(input) ? input : player.config.loop.active; - player.embed.setLoop(toggle).then(() => { + set: function set(input) { + var toggle = is$1.boolean(input) ? input : player.config.loop.active; + player.embed.setLoop(toggle).then(function () { loop = toggle; }); } - }); + }); // Source - // Source - let currentSrc; - player.embed.getVideoUrl().then(value => { + var currentSrc; + player.embed.getVideoUrl().then(function (value) { currentSrc = value; controls.setDownloadUrl.call(player); - }).catch(error => { - this.debug.warn(error); + }).catch(function (error) { + _this.debug.warn(error); }); Object.defineProperty(player.media, 'currentSrc', { - get() { + get: function get() { return currentSrc; } - }); + }); // Ended - // Ended Object.defineProperty(player.media, 'ended', { - get() { + get: function get() { return player.currentTime === player.duration; } - }); + }); // Set aspect ratio based on video size - // Set aspect ratio based on video size - Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(dimensions => { - const [width, height] = dimensions; - player.embed.ratio = roundAspectRatio(width, height); - setAspectRatio.call(this); - }); + Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(function (dimensions) { + var _dimensions = _slicedToArray(dimensions, 2), + width = _dimensions[0], + height = _dimensions[1]; - // Set autopause - player.embed.setAutopause(player.config.autopause).then(state => { + player.embed.ratio = [width, height]; + setAspectRatio.call(_this); + }); // Set autopause + + player.embed.setAutopause(player.config.autopause).then(function (state) { player.config.autopause = state; - }); + }); // Get title - // Get title - player.embed.getVideoTitle().then(title => { + player.embed.getVideoTitle().then(function (title) { player.config.title = title; - ui.setTitle.call(this); - }); + ui.setTitle.call(_this); + }); // Get current time - // Get current time - player.embed.getCurrentTime().then(value => { + player.embed.getCurrentTime().then(function (value) { currentTime = value; triggerEvent.call(player, player.media, 'timeupdate'); - }); + }); // Get duration - // Get duration - player.embed.getDuration().then(value => { + player.embed.getDuration().then(function (value) { player.media.duration = value; triggerEvent.call(player, player.media, 'durationchange'); - }); + }); // Get captions - // Get captions - player.embed.getTextTracks().then(tracks => { + player.embed.getTextTracks().then(function (tracks) { player.media.textTracks = tracks; captions.setup.call(player); }); - player.embed.on('cuechange', ({ - cues = [] - }) => { - const strippedCues = cues.map(cue => stripHTML(cue.text)); + player.embed.on('cuechange', function (_ref) { + var _ref$cues = _ref.cues, + cues = _ref$cues === void 0 ? [] : _ref$cues; + var strippedCues = cues.map(function (cue) { + return stripHTML(cue.text); + }); captions.updateCues.call(player, strippedCues); }); - player.embed.on('loaded', () => { + player.embed.on('loaded', function () { // Assure state and events are updated on autoplay - player.embed.getPaused().then(paused => { - assurePlaybackState$1.call(player, !paused); + player.embed.getPaused().then(function (paused) { + assurePlaybackState.call(player, !paused); + if (!paused) { triggerEvent.call(player, player.media, 'playing'); } }); - if (is.element(player.embed.element) && player.supported.ui) { - const frame = player.embed.element; - // Fix keyboard focus issues + if (is$1.element(player.embed.element) && player.supported.ui) { + var frame = player.embed.element; // Fix keyboard focus issues // https://github.com/sampotts/plyr/issues/317 + frame.setAttribute('tabindex', -1); } }); - player.embed.on('bufferstart', () => { + player.embed.on('bufferstart', function () { triggerEvent.call(player, player.media, 'waiting'); }); - player.embed.on('bufferend', () => { + player.embed.on('bufferend', function () { triggerEvent.call(player, player.media, 'playing'); }); - player.embed.on('play', () => { - assurePlaybackState$1.call(player, true); + player.embed.on('play', function () { + assurePlaybackState.call(player, true); triggerEvent.call(player, player.media, 'playing'); }); - player.embed.on('pause', () => { - assurePlaybackState$1.call(player, false); + player.embed.on('pause', function () { + assurePlaybackState.call(player, false); }); - player.embed.on('timeupdate', data => { + player.embed.on('timeupdate', function (data) { player.media.seeking = false; currentTime = data.seconds; triggerEvent.call(player, player.media, 'timeupdate'); }); - player.embed.on('progress', data => { + player.embed.on('progress', function (data) { player.media.buffered = data.percent; - triggerEvent.call(player, player.media, 'progress'); + triggerEvent.call(player, player.media, 'progress'); // Check all loaded - // Check all loaded if (parseInt(data.percent, 10) === 1) { triggerEvent.call(player, player.media, 'canplaythrough'); - } - - // Get duration as if we do it before load, it gives an incorrect value + } // Get duration as if we do it before load, it gives an incorrect value // https://github.com/sampotts/plyr/issues/891 - player.embed.getDuration().then(value => { + + + player.embed.getDuration().then(function (value) { if (value !== player.media.duration) { player.media.duration = value; triggerEvent.call(player, player.media, 'durationchange'); } }); }); - player.embed.on('seeked', () => { + player.embed.on('seeked', function () { player.media.seeking = false; triggerEvent.call(player, player.media, 'seeked'); }); - player.embed.on('ended', () => { + player.embed.on('ended', function () { player.media.paused = true; triggerEvent.call(player, player.media, 'ended'); }); - player.embed.on('error', detail => { + player.embed.on('error', function (detail) { player.media.error = detail; triggerEvent.call(player, player.media, 'error'); - }); + }); // Rebuild UI - // Rebuild UI - if (config.customControls) { - setTimeout(() => ui.build.call(player), 0); - } + setTimeout(function () { + return ui.build.call(player); + }, 0); } }; // ========================================================================== - // YouTube plugin - // ========================================================================== - - // Parse YouTube ID from URL - function parseId(url) { - if (is.empty(url)) { + function parseId$1(url) { + if (is$1.empty(url)) { return null; } - const regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/; + + var regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/; return url.match(regex) ? RegExp.$2 : url; - } + } // Set playback state and trigger change (only on actual change) - // Set playback state and trigger change (only on actual change) - function assurePlaybackState(play) { + + function assurePlaybackState$1(play) { if (play && !this.embed.hasPlayed) { this.embed.hasPlayed = true; } + if (this.media.paused === play) { this.media.paused = !play; triggerEvent.call(this, this.media, play ? 'play' : 'pause'); } } + function getHost(config) { if (config.noCookie) { return 'https://www.youtube-nocookie.com'; } + if (window.location.protocol === 'http:') { return 'http://www.youtube.com'; - } + } // Use YouTube's default + - // Use YouTube's default return undefined; } - const youtube = { - setup() { + + var youtube = { + setup: function setup() { + var _this = this; + // Add embed class for responsive - toggleClass(this.elements.wrapper, this.config.classNames.embed, true); + toggleClass(this.elements.wrapper, this.config.classNames.embed, true); // Setup API - // Setup API - if (is.object(window.YT) && is.function(window.YT.Player)) { + if (is$1.object(window.YT) && is$1.function(window.YT.Player)) { youtube.ready.call(this); } else { // Reference current global callback - const callback = window.onYouTubeIframeAPIReady; + var callback = window.onYouTubeIframeAPIReady; // Set callback to process queue - // Set callback to process queue - window.onYouTubeIframeAPIReady = () => { + window.onYouTubeIframeAPIReady = function () { // Call global callback if set - if (is.function(callback)) { + if (is$1.function(callback)) { callback(); } - youtube.ready.call(this); - }; - // Load the SDK - loadScript(this.config.urls.youtube.sdk).catch(error => { - this.debug.warn('YouTube API failed to load', error); + youtube.ready.call(_this); + }; // Load the SDK + + + loadScript(this.config.urls.youtube.sdk).catch(function (error) { + _this.debug.warn('YouTube API failed to load', error); }); } }, // Get the media title - getTitle(videoId) { - const url = format(this.config.urls.youtube.api, videoId); - fetch(url).then(data => { - if (is.object(data)) { - const { - title, - height, - width - } = data; - - // Set title - this.config.title = title; - ui.setTitle.call(this); - - // Set aspect ratio - this.embed.ratio = roundAspectRatio(width, height); + getTitle: function getTitle(videoId) { + var _this2 = this; + + var url = format(this.config.urls.youtube.api, videoId); + fetch(url).then(function (data) { + if (is$1.object(data)) { + var title = data.title, + height = data.height, + width = data.width; // Set title + + _this2.config.title = title; + ui.setTitle.call(_this2); // Set aspect ratio + + _this2.embed.ratio = [width, height]; } - setAspectRatio.call(this); - }).catch(() => { + + setAspectRatio.call(_this2); + }).catch(function () { // Set aspect ratio - setAspectRatio.call(this); + setAspectRatio.call(_this2); }); }, // API ready - ready() { - const player = this; - const config = player.config.youtube; - // Ignore already setup (race condition) - const currentId = player.media && player.media.getAttribute('id'); - if (!is.empty(currentId) && currentId.startsWith('youtube-')) { + ready: function ready() { + var player = this; // Ignore already setup (race condition) + + var currentId = player.media && player.media.getAttribute('id'); + + if (!is$1.empty(currentId) && currentId.startsWith('youtube-')) { return; - } + } // Get the source URL or ID + - // Get the source URL or ID - let source = player.media.getAttribute('src'); + var source = player.media.getAttribute('src'); // Get from
if needed - // Get from
if needed - if (is.empty(source)) { + if (is$1.empty(source)) { source = player.media.getAttribute(this.config.attributes.embed.id); - } + } // Replace the