seamless-vid-player 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.inset-1\/2{inset:50%}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-6{bottom:1.5rem}.bottom-full{bottom:100%}.left-0{left:0}.left-1\/2{left:50%}.left-3{left:.75rem}.right-0{right:0}.top-1\/2{top:50%}.top-3{top:.75rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.m-0{margin:0}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-10{margin-bottom:2.5rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.mt-5{margin-top:1.25rem}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-9{height:2.25rem}.h-\[3px\]{height:3px}.h-full{height:100%}.max-h-\[82vh\]{max-height:82vh}.max-h-\[min\(28rem\2c calc\(100vh-10rem\)\)\]{max-height:min(28rem,calc(100vh - 10rem))}.max-h-screen{max-height:100vh}.min-h-\[56\.25vw\]{min-height:56.25vw}.min-h-screen{min-height:100vh}.w-1\.5{width:.375rem}.w-16{width:4rem}.w-2{width:.5rem}.w-3\.5{width:.875rem}.w-56{width:14rem}.w-9{width:2.25rem}.w-\[min\(92vw\2c 360px\)\]{width:min(92vw,360px)}.w-full{width:100%}.w-screen{width:100vw}.min-w-0{min-width:0}.min-w-16{min-width:4rem}.max-w-2xl{max-width:42rem}.max-w-\[1180px\]{max-width:1180px}.max-w-\[1280px\]{max-width:1280px}.max-w-none{max-width:none}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.translate-y-0{--tw-translate-y:0px}.translate-y-0,.translate-y-2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-2{--tw-translate-y:0.5rem}.rotate-\[22deg\]{--tw-rotate:22deg}.rotate-\[22deg\],.scale-100{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1}.scale-110,.scale-75{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-75{--tw-scale-x:.75;--tw-scale-y:.75}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-none{cursor:none}.cursor-pointer{cursor:pointer}.list-none{list-style-type:none}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.whitespace-nowrap{white-space:nowrap}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-l{border-left-width:1px}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity,1))}.border-white\/10{border-color:hsla(0,0%,100%,.1)}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-black\/40{background-color:rgba(0,0,0,.4)}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-black\/75{background-color:rgba(0,0,0,.75)}.bg-black\/80{background-color:rgba(0,0,0,.8)}.bg-black\/85{background-color:rgba(0,0,0,.85)}.bg-white\/10{background-color:hsla(0,0%,100%,.1)}.bg-white\/25{background-color:hsla(0,0%,100%,.25)}.bg-white\/40{background-color:hsla(0,0%,100%,.4)}.bg-white\/5{background-color:hsla(0,0%,100%,.05)}.bg-youtube-accent{--tw-bg-opacity:1;background-color:rgb(255 0 0/var(--tw-bg-opacity,1))}.bg-youtube-panel{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-youtube-track{background-color:hsla(0,0%,100%,.2)}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-black\/90{--tw-gradient-from:rgba(0,0,0,.9) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.p-0{padding:0}.p-1{padding:.25rem}.p-2\.5{padding:.625rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.text-center{text-align:center}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-4{line-height:1rem}.leading-relaxed{line-height:1.625}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/50{color:hsla(0,0%,100%,.5)}.text-white\/55{color:hsla(0,0%,100%,.55)}.text-white\/80{color:hsla(0,0%,100%,.8)}.text-white\/90{color:hsla(0,0%,100%,.9)}.text-youtube-accent{--tw-text-opacity:1;color:rgb(255 0 0/var(--tw-text-opacity,1))}.text-youtube-muted{--tw-text-opacity:1;color:rgb(170 170 170/var(--tw-text-opacity,1))}.text-youtube-text{--tw-text-opacity:1;color:rgb(241 241 241/var(--tw-text-opacity,1))}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-2xl,.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-white\/5{--tw-ring-color:hsla(0,0%,100%,.05)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.backdrop-blur-md,.backdrop-blur-sm{backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px)}.transition-\[height\]{transition-property:height;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[max-height\]{transition-property:max-height;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[width\2c transform\2c border-radius\]{transition-property:width,transform,border-radius;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-150,.transition-transform{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.last\:mb-0:last-child{margin-bottom:0}.hover\:bg-youtube-accent:hover{--tw-bg-opacity:1;background-color:rgb(255 0 0/var(--tw-bg-opacity,1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}@media (min-width:640px){.sm\:flex{display:flex}.sm\:gap-2{gap:.5rem}.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}}@media (min-width:768px){.md\:h-20{height:5rem}.md\:w-20{width:5rem}.md\:rounded-2xl{border-radius:1rem}.md\:text-5xl{font-size:3rem;line-height:1}}
|
|
1
|
+
.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.svp-root .pointer-events-none{pointer-events:none}.svp-root .absolute{position:absolute}.svp-root .relative{position:relative}.svp-root .inset-1\/2{inset:50%}.svp-root .inset-x-0{left:0;right:0}.svp-root .inset-y-0{top:0;bottom:0}.svp-root .bottom-0{bottom:0}.svp-root .bottom-6{bottom:1.5rem}.svp-root .bottom-full{bottom:100%}.svp-root .left-0{left:0}.svp-root .left-1\/2{left:50%}.svp-root .left-3{left:.75rem}.svp-root .right-0{right:0}.svp-root .top-1\/2{top:50%}.svp-root .top-3{top:.75rem}.svp-root .z-10{z-index:10}.svp-root .z-20{z-index:20}.svp-root .z-30{z-index:30}.svp-root .z-50{z-index:50}.svp-root .m-0{margin:0}.svp-root .mx-1{margin-left:.25rem;margin-right:.25rem}.svp-root .mx-auto{margin-left:auto;margin-right:auto}.svp-root .mb-2{margin-bottom:.5rem}.svp-root .mb-4{margin-bottom:1rem}.svp-root .mb-6{margin-bottom:1.5rem}.svp-root .ml-1{margin-left:.25rem}.svp-root .mt-5{margin-top:1.25rem}.svp-root .block{display:block}.svp-root .flex{display:flex}.svp-root .grid{display:grid}.svp-root .hidden{display:none}.svp-root .h-1{height:.25rem}.svp-root .h-1\.5{height:.375rem}.svp-root .h-14{height:3.5rem}.svp-root .h-16{height:4rem}.svp-root .h-2{height:.5rem}.svp-root .h-3\.5{height:.875rem}.svp-root .h-4{height:1rem}.svp-root .h-9{height:2.25rem}.svp-root .h-\[3px\]{height:3px}.svp-root .h-full{height:100%}.svp-root .max-h-\[82vh\]{max-height:82vh}.svp-root .max-h-\[min\(28rem\2c calc\(100vh-10rem\)\)\]{max-height:min(28rem,calc(100vh - 10rem))}.svp-root .max-h-screen{max-height:100vh}.svp-root .min-h-\[56\.25vw\]{min-height:56.25vw}.svp-root .w-1\.5{width:.375rem}.svp-root .w-16{width:4rem}.svp-root .w-2{width:.5rem}.svp-root .w-3\.5{width:.875rem}.svp-root .w-56{width:14rem}.svp-root .w-9{width:2.25rem}.svp-root .w-\[min\(92vw\2c 360px\)\]{width:min(92vw,360px)}.svp-root .w-full{width:100%}.svp-root .w-screen{width:100vw}.svp-root .min-w-0{min-width:0}.svp-root .min-w-16{min-width:4rem}.svp-root .max-w-2xl{max-width:42rem}.svp-root .max-w-\[1180px\]{max-width:1180px}.svp-root .max-w-none{max-width:none}.svp-root .-translate-x-1\/2{--tw-translate-x:-50%}.svp-root .-translate-x-1\/2,.svp-root .-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.svp-root .-translate-y-1\/2{--tw-translate-y:-50%}.svp-root .translate-y-0{--tw-translate-y:0px}.svp-root .translate-y-0,.svp-root .translate-y-2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.svp-root .translate-y-2{--tw-translate-y:0.5rem}.svp-root .rotate-\[22deg\]{--tw-rotate:22deg}.svp-root .rotate-\[22deg\],.svp-root .scale-100{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.svp-root .scale-100{--tw-scale-x:1;--tw-scale-y:1}.svp-root .scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1}.svp-root .scale-110,.svp-root .scale-75{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.svp-root .scale-75{--tw-scale-x:.75;--tw-scale-y:.75}.svp-root .transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.svp-root .cursor-none{cursor:none}.svp-root .cursor-pointer{cursor:pointer}.svp-root .list-none{list-style-type:none}.svp-root .flex-wrap{flex-wrap:wrap}.svp-root .place-items-center{place-items:center}.svp-root .items-center{align-items:center}.svp-root .justify-center{justify-content:center}.svp-root .justify-between{justify-content:space-between}.svp-root .gap-1{gap:.25rem}.svp-root .gap-2{gap:.5rem}.svp-root .gap-3{gap:.75rem}.svp-root :is(.space-y-1\.5>:not([hidden])~:not([hidden])){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.svp-root .overflow-hidden{overflow:hidden}.svp-root .whitespace-nowrap{white-space:nowrap}.svp-root .rounded-full{border-radius:9999px}.svp-root .rounded-lg{border-radius:.5rem}.svp-root .rounded-md{border-radius:.375rem}.svp-root .rounded-none{border-radius:0}.svp-root .rounded-xl{border-radius:.75rem}.svp-root .border{border-width:1px}.svp-root .border-2{border-width:2px}.svp-root .border-l{border-left-width:1px}.svp-root .border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity,1))}.svp-root .border-white\/10{border-color:hsla(0,0%,100%,.1)}.svp-root .bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.svp-root .bg-black\/40{background-color:rgba(0,0,0,.4)}.svp-root .bg-black\/50{background-color:rgba(0,0,0,.5)}.svp-root .bg-black\/75{background-color:rgba(0,0,0,.75)}.svp-root .bg-black\/80{background-color:rgba(0,0,0,.8)}.svp-root .bg-black\/85{background-color:rgba(0,0,0,.85)}.svp-root .bg-white\/10{background-color:hsla(0,0%,100%,.1)}.svp-root .bg-white\/25{background-color:hsla(0,0%,100%,.25)}.svp-root .bg-white\/40{background-color:hsla(0,0%,100%,.4)}.svp-root .bg-white\/5{background-color:hsla(0,0%,100%,.05)}.svp-root .bg-youtube-accent{--tw-bg-opacity:1;background-color:rgb(255 0 0/var(--tw-bg-opacity,1))}.svp-root .bg-youtube-panel{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.svp-root .bg-youtube-track{background-color:hsla(0,0%,100%,.2)}.svp-root .bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.svp-root .from-black\/90{--tw-gradient-from:rgba(0,0,0,.9) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.svp-root .to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.svp-root .p-0{padding:0}.svp-root .p-1{padding:.25rem}.svp-root .p-2\.5{padding:.625rem}.svp-root .px-1{padding-left:.25rem;padding-right:.25rem}.svp-root .px-2{padding-left:.5rem;padding-right:.5rem}.svp-root .px-3{padding-left:.75rem;padding-right:.75rem}.svp-root .px-4{padding-left:1rem;padding-right:1rem}.svp-root .py-1{padding-top:.25rem;padding-bottom:.25rem}.svp-root .py-3{padding-top:.75rem;padding-bottom:.75rem}.svp-root .py-8{padding-top:2rem;padding-bottom:2rem}.svp-root .pb-2{padding-bottom:.5rem}.svp-root .pt-16{padding-top:4rem}.svp-root .pt-2{padding-top:.5rem}.svp-root .text-center{text-align:center}.svp-root .font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.svp-root .text-3xl{font-size:1.875rem;line-height:2.25rem}.svp-root .text-\[10px\]{font-size:10px}.svp-root .text-\[11px\]{font-size:11px}.svp-root .text-\[13px\]{font-size:13px}.svp-root .text-base{font-size:1rem;line-height:1.5rem}.svp-root .text-sm{font-size:.875rem;line-height:1.25rem}.svp-root .text-xs{font-size:.75rem;line-height:1rem}.svp-root .font-bold{font-weight:700}.svp-root .font-medium{font-weight:500}.svp-root .font-semibold{font-weight:600}.svp-root .uppercase{text-transform:uppercase}.svp-root .tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.svp-root .leading-4{line-height:1rem}.svp-root .leading-relaxed{line-height:1.625}.svp-root .tracking-\[0\.2em\]{letter-spacing:.2em}.svp-root .tracking-tight{letter-spacing:-.025em}.svp-root .tracking-wider{letter-spacing:.05em}.svp-root .text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.svp-root .text-white\/50{color:hsla(0,0%,100%,.5)}.svp-root .text-white\/55{color:hsla(0,0%,100%,.55)}.svp-root .text-white\/80{color:hsla(0,0%,100%,.8)}.svp-root .text-white\/90{color:hsla(0,0%,100%,.9)}.svp-root .text-youtube-accent{--tw-text-opacity:1;color:rgb(255 0 0/var(--tw-text-opacity,1))}.svp-root .text-youtube-muted{--tw-text-opacity:1;color:rgb(170 170 170/var(--tw-text-opacity,1))}.svp-root .text-youtube-text{--tw-text-opacity:1;color:rgb(241 241 241/var(--tw-text-opacity,1))}.svp-root .opacity-0{opacity:0}.svp-root .opacity-100{opacity:1}.svp-root .shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.svp-root .shadow-2xl,.svp-root .shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.svp-root .shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.svp-root .ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.svp-root .ring-white\/5{--tw-ring-color:hsla(0,0%,100%,.05)}.svp-root .filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.svp-root .backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.svp-root .backdrop-blur-md,.svp-root .backdrop-blur-sm{backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.svp-root .backdrop-blur-sm{--tw-backdrop-blur:blur(4px)}.svp-root .transition-\[height\]{transition-property:height;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.svp-root .transition-\[max-height\]{transition-property:max-height;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.svp-root .transition-\[width\2c transform\2c border-radius\]{transition-property:width,transform,border-radius;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.svp-root .transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.svp-root .transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.svp-root .transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.svp-root .duration-150{transition-duration:.15s}.svp-root .duration-200{transition-duration:.2s}.svp-root .duration-300{transition-duration:.3s}.svp-root .duration-500{transition-duration:.5s}.svp-root .ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.svp-root .hover\:bg-youtube-accent:hover{--tw-bg-opacity:1;background-color:rgb(255 0 0/var(--tw-bg-opacity,1))}.svp-root .disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.svp-root .disabled\:opacity-40:disabled{opacity:.4}@media (min-width:640px){.svp-root .sm\:flex{display:flex}.svp-root .sm\:gap-2{gap:.5rem}.svp-root .sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}}@media (min-width:768px){.svp-root .md\:h-20{height:5rem}.svp-root .md\:w-20{width:5rem}.svp-root .md\:rounded-2xl{border-radius:1rem}.svp-root .md\:text-5xl{font-size:3rem;line-height:1}}
|
package/dist/index.js
CHANGED
|
@@ -628,7 +628,7 @@ function YouTubePlayer({
|
|
|
628
628
|
if (volume < 0.5) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Volume1, { size: 18, className: "control-icon" });
|
|
629
629
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Volume2, { size: 18, className: "control-icon" });
|
|
630
630
|
};
|
|
631
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { className: "w-full max-w-[1180px] mx-auto py-8 px-4", children: [
|
|
631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { className: "svp-root w-full max-w-[1180px] mx-auto py-8 px-4", children: [
|
|
632
632
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "mb-6", children: [
|
|
633
633
|
eyebrow ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "m-0 mb-2 text-youtube-muted uppercase tracking-wider text-xs font-medium", children: eyebrow }) : null,
|
|
634
634
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "m-0 text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight mb-4", children: title }),
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../components/YouTubePlayer.tsx"],"sourcesContent":["\"use client\";\n\nexport { default as YouTubePlayer } from \"../components/YouTubePlayer\";\n","\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport {\n Captions,\n ChevronLeft,\n ChevronRight,\n Maximize,\n Minimize,\n Pause,\n PictureInPicture,\n Play,\n RectangleHorizontal,\n Settings,\n Tv,\n Volume1,\n Volume2,\n VolumeX,\n} from \"lucide-react\";\nimport Hls from \"hls.js\";\n\nexport interface PlayerProps {\n src: string;\n title: string;\n description?: string;\n eyebrow?: string;\n badges?: string[];\n captionsSrc?: string;\n thumbnailTrackSrc?: string;\n theaterMode?: boolean;\n defaultTheaterMode?: boolean;\n onTheaterModeChange?: (isTheaterMode: boolean) => void;\n}\n\ninterface ThumbnailCue {\n startTime: number;\n endTime: number;\n url: string;\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\ninterface QualityOption {\n height: number;\n index: number;\n}\n\ninterface PlaybackStats {\n source: string;\n resolution: string;\n quality: string;\n bitrate: string;\n codec: string;\n mimeType: string;\n audio: string;\n bufferHealth: string;\n droppedFrames: string;\n fps: string;\n playbackRate: string;\n state: string;\n}\n\nconst PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n\nexport default function YouTubePlayer({\n src,\n title,\n description,\n eyebrow,\n badges = [],\n captionsSrc,\n thumbnailTrackSrc,\n theaterMode,\n defaultTheaterMode = false,\n onTheaterModeChange,\n}: PlayerProps) {\n const videoRef = useRef<HTMLVideoElement>(null);\n const timelineRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const settingsRef = useRef<HTMLDivElement>(null);\n\n const [isPlaying, setIsPlaying] = useState(false);\n const [isMuted, setIsMuted] = useState(false);\n const [volume, setVolume] = useState(1);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [isScrubbing, setIsScrubbing] = useState(false);\n const [isHoveringTimeline, setIsHoveringTimeline] = useState(false);\n const [timelineProgress, setTimelineProgress] = useState(0);\n const [previewPosition, setPreviewPosition] = useState(0);\n const [previewTime, setPreviewTime] = useState(0);\n const [activeThumbnail, setActiveThumbnail] = useState<ThumbnailCue | null>(null);\n const [thumbnails, setThumbnails] = useState<ThumbnailCue[]>([]);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const [internalTheaterMode, setInternalTheaterMode] = useState(defaultTheaterMode);\n const [isUserInactive, setIsUserInactive] = useState(false);\n const [playbackRate, setPlaybackRate] = useState(1);\n const [captionsEnabled, setCaptionsEnabled] = useState(false);\n const [qualities, setQualities] = useState<QualityOption[]>([]);\n const [currentQuality, setCurrentQuality] = useState<number | \"auto\">(\"auto\");\n const [showSettings, setShowSettings] = useState(false);\n const [settingsView, setSettingsView] = useState<\"root\" | \"quality\" | \"speed\">(\"root\");\n const [showStatsForNerds, setShowStatsForNerds] = useState(false);\n const [pipSupported, setPipSupported] = useState(false);\n const [playbackStats, setPlaybackStats] = useState<PlaybackStats>({\n source: \"MP4\",\n resolution: \"0x0\",\n quality: \"Auto\",\n bitrate: \"N/A\",\n codec: \"N/A\",\n mimeType: \"video/mp4\",\n audio: \"N/A\",\n bufferHealth: \"0.0s\",\n droppedFrames: \"0\",\n fps: \"N/A\",\n playbackRate: \"1x\",\n state: \"Idle\",\n });\n const [bitrateHistory, setBitrateHistory] = useState<number[]>([]);\n const [bufferHistory, setBufferHistory] = useState<number[]>([]);\n\n const idleTimer = useRef<NodeJS.Timeout | null>(null);\n const hlsRef = useRef<Hls | null>(null);\n const dashRef = useRef<any>(null);\n const wasPlayingBeforeScrub = useRef(false);\n const scrubStartThumbnail = useRef<ThumbnailCue | null>(null);\n const isTheaterControlled = theaterMode !== undefined;\n const isTheater = isTheaterControlled ? theaterMode : internalTheaterMode;\n\n const setTheaterMode = (nextValue: boolean | ((prev: boolean) => boolean)) => {\n const resolvedValue =\n typeof nextValue === \"function\" ? nextValue(isTheater) : nextValue;\n\n if (!isTheaterControlled) {\n setInternalTheaterMode(resolvedValue);\n }\n\n onTheaterModeChange?.(resolvedValue);\n };\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n\n let hls: Hls | null = null;\n let dash: any = null;\n let isMounted = true;\n\n if (src.includes(\".m3u8\")) {\n if (Hls.isSupported()) {\n hls = new Hls();\n hlsRef.current = hls;\n hls.loadSource(src);\n hls.attachMedia(video);\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_, data) => {\n const availableQualities: QualityOption[] = data.levels.map((level, index) => ({\n height: level.height,\n index,\n }));\n const uniqueQualities = Array.from(\n new Map(availableQualities.map((q) => [q.height, q])).values(),\n ).sort((a, b) => b.height - a.height);\n setQualities(uniqueQualities);\n });\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_, data) => {\n if (hls?.autoLevelEnabled) {\n setCurrentQuality(\"auto\");\n } else {\n setCurrentQuality(data.level);\n }\n });\n } else if (video.canPlayType(\"application/vnd.apple.mpegurl\")) {\n video.src = src;\n }\n } else if (src.includes(\".mpd\")) {\n import(\"dashjs\").then((dashjs) => {\n if (!isMounted) return;\n\n dash = dashjs.MediaPlayer().create();\n dashRef.current = dash;\n dash.initialize(video, src, false);\n\n dash.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED, () => {\n const representations = dash.getRepresentationsByType?.(\"video\");\n if (representations?.length) {\n const availableQualities: QualityOption[] = representations.map(\n (representation: any, index: number) => ({\n height: representation.height,\n index,\n }),\n );\n const uniqueQualities = Array.from(\n new Map(availableQualities.map((q) => [q.height, q])).values(),\n ).sort((a, b) => b.height - a.height);\n setQualities(uniqueQualities);\n } else {\n setQualities([]);\n }\n });\n\n dash.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_RENDERED, (event: any) => {\n if (event.mediaType !== \"video\") return;\n\n const settings = dash.getSettings();\n if (settings.streaming?.abr?.autoSwitchBitrate?.video) {\n setCurrentQuality(\"auto\");\n } else {\n setCurrentQuality(event.newQuality);\n }\n });\n\n dash.on(dashjs.MediaPlayer.events.ERROR, () => {\n setQualities([]);\n setCurrentQuality(\"auto\");\n });\n });\n } else {\n video.src = src;\n }\n\n return () => {\n isMounted = false;\n if (hls) {\n hls.destroy();\n hlsRef.current = null;\n }\n if (dash) {\n dash.reset();\n dashRef.current = null;\n }\n };\n }, [src]);\n\n useEffect(() => {\n if (videoRef.current && videoRef.current.readyState >= 1) {\n setDuration(videoRef.current.duration || 0);\n }\n }, []);\n\n const parseVttTime = (timeStr: string) => {\n const parts = timeStr.split(\":\");\n if (parts.length === 3) {\n return Number(parts[0]) * 3600 + Number(parts[1]) * 60 + Number(parts[2]);\n }\n if (parts.length === 2) {\n return Number(parts[0]) * 60 + Number(parts[1]);\n }\n return Number(parts[0]) || 0;\n };\n\n useEffect(() => {\n if (!thumbnailTrackSrc) return;\n\n let isMounted = true;\n fetch(thumbnailTrackSrc)\n .then((response) => response.text())\n .then((text) => {\n if (!isMounted) return;\n const lines = text.split(\"\\n\");\n const cues: ThumbnailCue[] = [];\n let currentCue: Partial<ThumbnailCue> = {};\n\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i].trim();\n if (line.includes(\"-->\")) {\n const parts = line.split(\"-->\");\n currentCue.startTime = parseVttTime(parts[0].trim());\n currentCue.endTime = parseVttTime(parts[1].trim());\n } else if (line.includes(\"#xywh=\")) {\n const [url, coords] = line.split(\"#xywh=\");\n const [x, y, w, h] = coords.split(\",\").map(Number);\n\n try {\n currentCue.url = new URL(url, new URL(thumbnailTrackSrc, window.location.href)).href;\n } catch {\n currentCue.url = url;\n }\n\n currentCue.x = x;\n currentCue.y = y;\n currentCue.w = w;\n currentCue.h = h;\n cues.push(currentCue as ThumbnailCue);\n currentCue = {};\n }\n }\n setThumbnails(cues);\n })\n .catch(console.error);\n\n return () => {\n isMounted = false;\n };\n }, [thumbnailTrackSrc]);\n\n const formatDuration = (time: number) => {\n if (!Number.isFinite(time)) return \"0:00\";\n const seconds = Math.floor(time % 60);\n const minutes = Math.floor(time / 60) % 60;\n const hours = Math.floor(time / 3600);\n\n const leadingZeroFormatter = new Intl.NumberFormat(undefined, {\n minimumIntegerDigits: 2,\n });\n\n if (hours === 0) {\n return `${minutes}:${leadingZeroFormatter.format(seconds)}`;\n }\n return `${hours}:${leadingZeroFormatter.format(minutes)}:${leadingZeroFormatter.format(seconds)}`;\n };\n\n const queueIdleFade = () => {\n if (idleTimer.current) clearTimeout(idleTimer.current);\n setIsUserInactive(false);\n\n if (videoRef.current?.paused || isScrubbing) return;\n\n idleTimer.current = setTimeout(() => {\n if (!videoRef.current?.paused && !isScrubbing) {\n setIsUserInactive(true);\n }\n }, 2200);\n };\n\n useEffect(() => {\n const events = [\"pointermove\", \"pointerdown\", \"focusin\", \"mouseenter\"];\n const container = containerRef.current;\n if (!container) return;\n\n const handler = () => queueIdleFade();\n events.forEach((eventName) => container.addEventListener(eventName, handler));\n\n const handleLeave = () => {\n if (!videoRef.current?.paused && !isScrubbing) {\n setIsUserInactive(true);\n }\n };\n container.addEventListener(\"pointerleave\", handleLeave);\n\n return () => {\n events.forEach((eventName) => container.removeEventListener(eventName, handler));\n container.removeEventListener(\"pointerleave\", handleLeave);\n if (idleTimer.current) clearTimeout(idleTimer.current);\n };\n }, [isScrubbing]);\n\n useEffect(() => {\n const handleFullscreenChange = () => {\n setIsFullscreen(document.fullscreenElement === containerRef.current);\n };\n document.addEventListener(\"fullscreenchange\", handleFullscreenChange);\n return () => document.removeEventListener(\"fullscreenchange\", handleFullscreenChange);\n }, []);\n\n useEffect(() => {\n const handleClickOutside = (event: PointerEvent) => {\n if (!showSettings || !settingsRef.current) return;\n if (!settingsRef.current.contains(event.target as Node)) {\n setShowSettings(false);\n setSettingsView(\"root\");\n }\n };\n document.addEventListener(\"pointerdown\", handleClickOutside);\n return () => document.removeEventListener(\"pointerdown\", handleClickOutside);\n }, [showSettings]);\n\n useEffect(() => {\n const video = videoRef.current;\n const supported =\n typeof document !== \"undefined\" &&\n \"pictureInPictureEnabled\" in document &&\n document.pictureInPictureEnabled &&\n !!video &&\n typeof (video as HTMLVideoElement & { requestPictureInPicture?: () => Promise<PictureInPictureWindow> })\n .requestPictureInPicture === \"function\";\n\n setPipSupported(Boolean(supported));\n }, [src]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n const tagName = document.activeElement?.tagName?.toLowerCase();\n if (tagName === \"input\") return;\n\n switch (event.key.toLowerCase()) {\n case \" \":\n case \"k\":\n if (tagName === \"button\") return;\n event.preventDefault();\n togglePlay();\n break;\n case \"f\":\n event.preventDefault();\n toggleFullscreen();\n break;\n case \"t\":\n event.preventDefault();\n setTheaterMode((prev) => !prev);\n break;\n case \"m\":\n event.preventDefault();\n toggleMute();\n break;\n case \"arrowleft\":\n case \"j\":\n event.preventDefault();\n skipBy(-5);\n break;\n case \"arrowright\":\n case \"l\":\n event.preventDefault();\n skipBy(5);\n break;\n case \"c\":\n event.preventDefault();\n toggleCaptions();\n break;\n case \"i\":\n event.preventDefault();\n void togglePictureInPicture();\n break;\n default:\n break;\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [isScrubbing, playbackRate]);\n\n const togglePlay = () => {\n if (videoRef.current?.paused) {\n videoRef.current.play().catch(console.error);\n } else {\n videoRef.current?.pause();\n }\n };\n\n const toggleMute = () => {\n if (videoRef.current) {\n videoRef.current.muted = !videoRef.current.muted;\n setIsMuted(videoRef.current.muted);\n if (videoRef.current.muted) {\n setVolume(0);\n } else {\n setVolume(videoRef.current.volume || 1);\n }\n }\n };\n\n const handleVolumeChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const val = Number(event.target.value);\n setVolume(val);\n if (videoRef.current) {\n videoRef.current.volume = val;\n videoRef.current.muted = val === 0;\n setIsMuted(val === 0);\n }\n };\n\n const toggleFullscreen = async () => {\n if (!document.fullscreenElement) {\n await containerRef.current?.requestFullscreen();\n } else {\n await document.exitFullscreen();\n }\n };\n\n const skipBy = (seconds: number) => {\n if (videoRef.current) {\n const nextTime = Math.min(\n Math.max(videoRef.current.currentTime + seconds, 0),\n videoRef.current.duration || 0,\n );\n videoRef.current.currentTime = nextTime;\n setCurrentTime(nextTime);\n }\n };\n\n const toggleCaptions = () => {\n const video = videoRef.current;\n if (video && video.textTracks[0]) {\n const enabled = video.textTracks[0].mode === \"showing\";\n video.textTracks[0].mode = enabled ? \"hidden\" : \"showing\";\n setCaptionsEnabled(!enabled);\n }\n };\n\n const changePlaybackRate = (rate: number) => {\n if (!videoRef.current) return;\n videoRef.current.playbackRate = rate;\n setPlaybackRate(rate);\n setShowSettings(false);\n setSettingsView(\"root\");\n };\n\n const changeQuality = (index: number | \"auto\") => {\n setCurrentQuality(index);\n setShowSettings(false);\n setSettingsView(\"root\");\n\n if (hlsRef.current) {\n if (index === \"auto\") {\n hlsRef.current.currentLevel = -1;\n } else {\n hlsRef.current.currentLevel = index;\n }\n } else if (dashRef.current) {\n if (index === \"auto\") {\n dashRef.current.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: true } } },\n });\n } else {\n dashRef.current.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: false } } },\n });\n dashRef.current.setRepresentationForTypeByIndex(\"video\", index, true);\n }\n }\n };\n\n const togglePictureInPicture = async () => {\n try {\n if (document.pictureInPictureElement) {\n await document.exitPictureInPicture();\n return;\n }\n\n const video = videoRef.current as\n | (HTMLVideoElement & { requestPictureInPicture?: () => Promise<PictureInPictureWindow> })\n | null;\n\n if (!video || typeof video.requestPictureInPicture !== \"function\") {\n return;\n }\n\n await video.requestPictureInPicture();\n } catch (error) {\n console.error(error);\n }\n };\n\n const getQualityLabel = () => {\n if (currentQuality === \"auto\") {\n return \"Auto\";\n }\n\n return `${qualities.find((quality) => quality.index === currentQuality)?.height ?? currentQuality}p`;\n };\n\n const renderSparkline = (values: number[], colorClassName: string) => {\n if (values.length < 2) {\n return <div className=\"h-14 rounded-lg bg-white/5\" />;\n }\n\n const max = Math.max(...values, 1);\n const points = values\n .map((value, index) => {\n const x = (index / (values.length - 1)) * 100;\n const y = 100 - (value / max) * 100;\n return `${x},${y}`;\n })\n .join(\" \");\n\n return (\n <div className=\"h-14 rounded-lg bg-white/5 p-1\">\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" className=\"h-full w-full\">\n <polyline\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"3\"\n points={points}\n className={colorClassName}\n />\n </svg>\n </div>\n );\n };\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n\n const formatBitrate = (bitrate?: number | null) => {\n if (!bitrate || !Number.isFinite(bitrate) || bitrate <= 0) {\n return \"N/A\";\n }\n\n return bitrate >= 1_000_000\n ? `${(bitrate / 1_000_000).toFixed(2)} Mbps`\n : `${Math.round(bitrate / 1000)} kbps`;\n };\n\n const updateStats = () => {\n const bufferedAhead = (() => {\n for (let i = 0; i < video.buffered.length; i += 1) {\n const start = video.buffered.start(i);\n const end = video.buffered.end(i);\n if (video.currentTime >= start && video.currentTime <= end) {\n return Math.max(end - video.currentTime, 0);\n }\n }\n return 0;\n })();\n\n const playbackQuality =\n typeof video.getVideoPlaybackQuality === \"function\"\n ? video.getVideoPlaybackQuality()\n : null;\n\n let source = \"MP4\";\n let bitrate = \"N/A\";\n let quality = getQualityLabel();\n let codec = \"N/A\";\n let mimeType = video.currentSrc.includes(\".mpd\")\n ? \"application/dash+xml\"\n : video.currentSrc.includes(\".m3u8\")\n ? \"application/vnd.apple.mpegurl\"\n : \"video/mp4\";\n let audio = \"N/A\";\n let bitrateValue = 0;\n\n if (hlsRef.current) {\n source = \"HLS\";\n const hls = hlsRef.current;\n const levelIndex =\n hls.currentLevel >= 0\n ? hls.currentLevel\n : hls.loadLevel >= 0\n ? hls.loadLevel\n : hls.nextAutoLevel >= 0\n ? hls.nextAutoLevel\n : -1;\n const level = levelIndex >= 0 ? hls.levels[levelIndex] : null;\n bitrateValue = level?.bitrate ?? 0;\n bitrate = formatBitrate(bitrateValue);\n quality = level?.height ? `${level.height}p` : getQualityLabel();\n codec =\n level?.codecSet ||\n [level?.videoCodec, level?.audioCodec].filter(Boolean).join(\" / \") ||\n \"N/A\";\n mimeType = \"application/vnd.apple.mpegurl\";\n audio = level?.audioCodec || \"AAC/Unknown\";\n } else if (dashRef.current) {\n source = \"DASH\";\n const representation = dashRef.current.getCurrentRepresentationForType?.(\"video\");\n const audioTrack = dashRef.current.getCurrentTrackFor?.(\"audio\");\n const throughput = dashRef.current.getSafeAverageThroughput?.(\"video\");\n bitrateValue = representation?.bandwidth ?? throughput ?? 0;\n bitrate = formatBitrate(bitrateValue);\n quality = representation?.height ? `${representation.height}p` : getQualityLabel();\n codec = representation?.codecs || audioTrack?.codec || \"N/A\";\n mimeType = representation?.mimeType || audioTrack?.mimeType || \"application/dash+xml\";\n audio = [audioTrack?.codec, audioTrack?.lang].filter(Boolean).join(\" / \") || \"N/A\";\n }\n\n setBitrateHistory((previous) => [...previous.slice(-39), bitrateValue / 1_000_000]);\n setBufferHistory((previous) => [...previous.slice(-39), bufferedAhead]);\n\n setPlaybackStats({\n source,\n resolution:\n video.videoWidth && video.videoHeight ? `${video.videoWidth}x${video.videoHeight}` : \"0x0\",\n quality,\n bitrate,\n codec,\n mimeType,\n audio,\n bufferHealth: `${bufferedAhead.toFixed(1)}s`,\n droppedFrames: String(playbackQuality?.droppedVideoFrames ?? 0),\n fps:\n video.currentTime > 0 && playbackQuality?.totalVideoFrames\n ? `${Math.round(\n ((playbackQuality.totalVideoFrames ?? 0) - (playbackQuality.droppedVideoFrames ?? 0)) /\n Math.max(video.currentTime, 1),\n )}`\n : \"N/A\",\n playbackRate: `${video.playbackRate}x`,\n state: video.paused ? \"Paused\" : video.readyState < 3 ? \"Buffering\" : \"Playing\",\n });\n };\n\n updateStats();\n const intervalId = window.setInterval(updateStats, 500);\n return () => window.clearInterval(intervalId);\n }, [src, playbackRate, currentQuality, qualities]);\n\n const hasCaptions = Boolean(captionsSrc);\n const hasQualityOptions = qualities.length > 0;\n\n const getTimelinePercent = (clientX: number) => {\n const rect = timelineRef.current?.getBoundingClientRect();\n if (!rect || rect.width === 0) return 0;\n const rawPosition = clientX - rect.left;\n return Math.min(Math.max(rawPosition / rect.width, 0), 1);\n };\n\n const getThumbnailForTime = (time: number) => {\n if (thumbnails.length === 0) return null;\n\n return (\n thumbnails.find((thumbnail) => time >= thumbnail.startTime && time <= thumbnail.endTime) ||\n null\n );\n };\n\n const updateTimelinePreview = (event: React.PointerEvent | PointerEvent) => {\n const percent = getTimelinePercent(event.clientX);\n const time = percent * duration;\n\n setPreviewPosition(percent);\n setPreviewTime(time);\n\n if (duration > 0) {\n const thumbnail = getThumbnailForTime(time);\n if (thumbnail) {\n setActiveThumbnail(thumbnail);\n } else if (isScrubbing && scrubStartThumbnail.current) {\n setActiveThumbnail(scrubStartThumbnail.current);\n } else if (!isScrubbing) {\n setActiveThumbnail(null);\n }\n }\n\n if (isScrubbing) {\n event.preventDefault();\n setTimelineProgress(percent);\n }\n };\n\n const beginScrubbing = (event: React.PointerEvent) => {\n if (event.pointerType === \"mouse\" && event.button !== 0) return;\n wasPlayingBeforeScrub.current = !videoRef.current?.paused;\n scrubStartThumbnail.current = getThumbnailForTime(videoRef.current?.currentTime ?? 0);\n setIsScrubbing(true);\n videoRef.current?.pause();\n updateTimelinePreview(event);\n };\n\n const endScrubbing = (event: PointerEvent) => {\n if (!isScrubbing) return;\n setIsScrubbing(false);\n const percent = getTimelinePercent(event.clientX);\n if (videoRef.current) {\n const nextTime = percent * (videoRef.current.duration || 0);\n videoRef.current.currentTime = nextTime;\n setCurrentTime(nextTime);\n setPreviewTime(nextTime);\n if (wasPlayingBeforeScrub.current) {\n videoRef.current.play().catch(console.error);\n }\n }\n scrubStartThumbnail.current = null;\n };\n\n useEffect(() => {\n if (isScrubbing) {\n const onPointerMove = (event: PointerEvent) => updateTimelinePreview(event);\n document.addEventListener(\"pointermove\", onPointerMove);\n document.addEventListener(\"pointerup\", endScrubbing);\n return () => {\n document.removeEventListener(\"pointermove\", onPointerMove);\n document.removeEventListener(\"pointerup\", endScrubbing);\n };\n }\n return undefined;\n }, [isScrubbing, duration, thumbnails]);\n\n const VolumeIcon = () => {\n if (isMuted || volume === 0) return <VolumeX size={18} className=\"control-icon\" />;\n if (volume < 0.5) return <Volume1 size={18} className=\"control-icon\" />;\n return <Volume2 size={18} className=\"control-icon\" />;\n };\n\n return (\n <main className=\"w-full max-w-[1180px] mx-auto py-8 px-4\">\n <section className=\"mb-6\">\n {eyebrow ? (\n <p className=\"m-0 mb-2 text-youtube-muted uppercase tracking-wider text-xs font-medium\">\n {eyebrow}\n </p>\n ) : null}\n <h1 className=\"m-0 text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight mb-4\">{title}</h1>\n {description ? (\n <p className=\"max-w-2xl m-0 text-youtube-muted text-base leading-relaxed\">{description}</p>\n ) : null}\n {badges.length > 0 ? (\n <ul className=\"list-none flex flex-wrap gap-2 p-0 mt-5\">\n {badges.map((badge) => (\n <li\n key={badge}\n className=\"px-3 py-1 bg-white/10 rounded-full text-youtube-text text-sm font-medium\"\n >\n {badge}\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n\n <section\n className={`bg-youtube-panel shadow-2xl ring-1 ring-white/5 transition-[width,transform,border-radius] duration-300 ease-out ${\n isTheater\n ? \"relative left-1/2 w-screen max-w-none -translate-x-1/2 rounded-none md:rounded-2xl\"\n : \"rounded-xl overflow-hidden\"\n }`}\n >\n <div\n ref={containerRef}\n className={`relative flex justify-center bg-black group transition-[max-height] duration-300 ease-out ${\n isTheater ? \"min-h-[56.25vw] max-h-[82vh] w-full\" : \"\"\n } ${isFullscreen ? \"max-h-screen w-full\" : \"\"} ${isUserInactive ? \"user-inactive\" : \"\"}`}\n >\n {showStatsForNerds ? (\n <div className=\"stats-panel absolute left-3 top-3 z-30 w-[min(92vw,360px)] rounded-lg border border-white/10 bg-black/75 p-2.5 text-[10px] leading-4 text-white backdrop-blur-sm\">\n <div className=\"mb-2 text-[10px] font-semibold uppercase tracking-[0.2em] text-white/55\">\n Stats for nerds\n </div>\n <div className=\"space-y-1.5\">\n <div className=\"stats-row\">\n <span className=\"stats-key\">Buffer</span>\n <div className=\"stats-value-wrap\">\n <span>{playbackStats.bufferHealth}</span>\n <div className=\"stats-graph\">{renderSparkline(bufferHistory, \"text-white/80\")}</div>\n </div>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Bitrate</span>\n <div className=\"stats-value-wrap\">\n <span>{playbackStats.bitrate}</span>\n <div className=\"stats-graph\">{renderSparkline(bitrateHistory, \"text-youtube-accent\")}</div>\n </div>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Quality</span>\n <span className=\"stats-value-wrap\">{playbackStats.quality}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Codecs</span>\n <span className=\"stats-value-wrap\">{playbackStats.codec}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Audio</span>\n <span className=\"stats-value-wrap\">{playbackStats.audio}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Viewport</span>\n <span className=\"stats-value-wrap\">{playbackStats.resolution}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Mime</span>\n <span className=\"stats-value-wrap\">{playbackStats.mimeType}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Frames</span>\n <span className=\"stats-value-wrap\">\n {playbackStats.fps} fps / {playbackStats.droppedFrames} dropped\n </span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">State</span>\n <span className=\"stats-value-wrap\">\n {playbackStats.state} / {playbackStats.playbackRate}\n </span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Source</span>\n <span className=\"stats-value-wrap\">{playbackStats.source}</span>\n </div>\n </div>\n </div>\n ) : null}\n\n <button\n onClick={togglePlay}\n aria-label=\"Play video\"\n className={`absolute inset-1/2 -translate-x-1/2 -translate-y-1/2 grid place-items-center w-16 h-16 md:w-20 md:h-20 rounded-full bg-black/50 backdrop-blur-md text-white z-10 shadow-lg transition-all duration-200 hover:bg-youtube-accent ${isPlaying ? \"opacity-0 scale-75 pointer-events-none\" : \"opacity-100 scale-100\"}`}\n >\n <Play size={32} className=\"ml-1 control-icon\" fill=\"currentColor\" />\n </button>\n\n <div\n className={`video-controls-container absolute bottom-0 left-0 right-0 px-3 pb-2 pt-16 bg-gradient-to-t from-black/90 to-transparent text-white z-20 transition-all duration-500 ease-out ${isUserInactive && isPlaying ? \"opacity-0 pointer-events-none cursor-none translate-y-2\" : \"opacity-100 translate-y-0\"}`}\n >\n <div\n ref={timelineRef}\n className=\"timeline-container h-4 mx-1 cursor-pointer flex items-center relative group/timeline\"\n onPointerDown={beginScrubbing}\n onPointerMove={(event) => {\n if (!isScrubbing) updateTimelinePreview(event);\n }}\n onPointerEnter={() => setIsHoveringTimeline(true)}\n onPointerLeave={() => setIsHoveringTimeline(false)}\n >\n <div className=\"timeline-progress w-full h-[3px] bg-youtube-track relative transition-[height] duration-150\">\n <div\n className=\"absolute inset-y-0 left-0 bg-white/40\"\n style={{\n width: `${previewPosition * 100}%`,\n display: isHoveringTimeline || isScrubbing ? \"block\" : \"none\",\n }}\n />\n <div\n className=\"absolute inset-y-0 left-0 bg-youtube-accent transition-all duration-200 ease-out\"\n style={{\n width: `${(isScrubbing ? timelineProgress : duration ? currentTime / duration : 0) * 100}%`,\n }}\n />\n <div\n className=\"timeline-thumb absolute top-1/2 w-3.5 h-3.5 rounded-full bg-youtube-accent transition-all duration-200 ease-out\"\n style={{\n left: `${(isScrubbing ? timelineProgress : duration ? currentTime / duration : 0) * 100}%`,\n transform: `translate(-50%, -50%) scale(${isHoveringTimeline || isScrubbing ? 1 : 0})`,\n }}\n />\n\n {activeThumbnail ? (\n <div\n className={`pointer-events-none absolute bottom-6 border-2 border-white rounded-lg shadow-lg overflow-hidden bg-black -translate-x-1/2 transition-opacity duration-200 ${isScrubbing || isHoveringTimeline ? \"opacity-100\" : \"opacity-0\"}`}\n style={{ left: `${previewPosition * 100}%`, width: \"160px\", height: \"110px\" }}\n >\n <div\n style={{\n backgroundImage: `url(${activeThumbnail.url})`,\n backgroundPosition: `-${activeThumbnail.x}px -${activeThumbnail.y}px`,\n width: `${activeThumbnail.w}px`,\n height: `${activeThumbnail.h}px`,\n transform: `scale(${160 / activeThumbnail.w})`,\n transformOrigin: \"top left\",\n }}\n />\n <div className=\"absolute inset-x-0 bottom-0 bg-black/80 px-2 py-1 text-center text-[11px] text-white\">\n {formatDuration(previewTime)}\n </div>\n </div>\n ) : isScrubbing || isHoveringTimeline ? (\n <div\n className=\"pointer-events-none absolute bottom-6 min-w-16 rounded-md bg-black/85 px-2 py-1 text-center text-[11px] text-white shadow-lg -translate-x-1/2 transition-opacity duration-200\"\n style={{ left: `${previewPosition * 100}%` }}\n >\n {formatDuration(previewTime)}\n </div>\n ) : null}\n </div>\n </div>\n\n <div className=\"flex items-center justify-between gap-3 pt-2 px-1\">\n <div className=\"flex min-w-0 items-center gap-1 sm:gap-2\">\n <button\n onClick={togglePlay}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n >\n {isPlaying ? (\n <Pause size={18} fill=\"currentColor\" className=\"control-icon\" />\n ) : (\n <Play size={18} fill=\"currentColor\" className=\"control-icon\" />\n )}\n </button>\n\n <div className=\"volume-container flex items-center gap-1\">\n <button\n onClick={toggleMute}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n >\n <VolumeIcon />\n </button>\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"any\"\n value={volume}\n onChange={handleVolumeChange}\n className=\"volume-slider h-1\"\n style={{ \"--volume-percent\": `${volume * 100}%` } as React.CSSProperties}\n />\n </div>\n\n <div className=\"flex min-w-0 items-center gap-1 text-[13px] font-sans text-white/90 tabular-nums whitespace-nowrap\">\n <span>{formatDuration(currentTime)}</span>\n <span className=\"text-white/50\">/</span>\n <span>{formatDuration(duration)}</span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-1 sm:gap-2\">\n <button\n onClick={toggleCaptions}\n disabled={!hasCaptions}\n className={`control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all disabled:opacity-40 disabled:cursor-not-allowed ${captionsEnabled ? \"text-youtube-accent\" : \"\"}`}\n title=\"Subtitles/closed captions (c)\"\n >\n <Captions size={18} className=\"control-icon\" />\n </button>\n\n <div ref={settingsRef} className=\"relative\">\n <button\n onClick={() => {\n setShowSettings((prev) => !prev);\n setSettingsView(\"root\");\n }}\n className={`control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all ${showSettings ? \"bg-white/10 text-youtube-accent\" : \"\"}`}\n title=\"Settings\"\n >\n <Settings\n size={18}\n className={`control-icon ${showSettings ? \"rotate-[22deg] scale-110\" : \"\"} transition-transform duration-300`}\n />\n </button>\n\n {showSettings ? (\n <div\n className={`settings-panel absolute bottom-full right-0 mb-4 w-56 bg-black/40 backdrop-blur-sm rounded-xl overflow-hidden shadow-2xl z-50 border border-white/10 ${\n settingsView === \"root\" ? \"settings-panel-root\" : \"max-h-[min(28rem,calc(100vh-10rem))]\"\n }`}\n >\n <div\n className=\"settings-slider\"\n style={{\n width: \"300%\",\n transform: `translateX(${\n settingsView === \"root\"\n ? \"0%\"\n : settingsView === \"quality\"\n ? \"-33.3333%\"\n : \"-66.6667%\"\n })`,\n }}\n >\n <div className=\"settings-view settings-scroll\">\n <button\n onClick={() => setSettingsView(\"quality\")}\n disabled={!hasQualityOptions}\n className=\"settings-item disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n <div>\n <div className=\"settings-label\">Quality</div>\n <div className=\"settings-value\">\n {hasQualityOptions ? getQualityLabel() : \"Unavailable\"}\n </div>\n </div>\n <ChevronRight size={16} className=\"text-white/55\" />\n </button>\n\n <button\n onClick={() => setSettingsView(\"speed\")}\n className=\"settings-item\"\n >\n <div>\n <div className=\"settings-label\">Playback speed</div>\n <div className=\"settings-value\">{playbackRate}x</div>\n </div>\n <ChevronRight size={16} className=\"text-white/55\" />\n </button>\n\n <button\n onClick={() => {\n setShowStatsForNerds((prev) => !prev);\n setShowSettings(false);\n setSettingsView(\"root\");\n }}\n className=\"settings-item\"\n >\n <div>\n <div className=\"settings-label\">Stats for nerds</div>\n <div className=\"settings-value\">\n {showStatsForNerds ? \"On\" : \"Off\"}\n </div>\n </div>\n <span\n className={`h-2 w-2 rounded-full ${\n showStatsForNerds ? \"bg-youtube-accent\" : \"bg-white/25\"\n }`}\n />\n </button>\n </div>\n\n <div className=\"settings-view settings-scroll border-l border-white/10\">\n <button\n onClick={() => setSettingsView(\"root\")}\n className=\"settings-back\"\n >\n <ChevronLeft size={16} />\n <span>Quality</span>\n </button>\n <button\n onClick={() => changeQuality(\"auto\")}\n className={`settings-option ${currentQuality === \"auto\" ? \"settings-option-active\" : \"\"}`}\n >\n <span>Auto</span>\n {currentQuality === \"auto\" ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n {qualities.length > 0 ? (\n qualities.map((quality) => (\n <button\n key={quality.height}\n onClick={() => changeQuality(quality.index)}\n className={`settings-option ${currentQuality === quality.index ? \"settings-option-active\" : \"\"}`}\n >\n <span>{quality.height}p</span>\n {currentQuality === quality.index ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n ))\n ) : (\n <div className=\"px-4 py-3 text-[13px] text-white/55\">No quality options</div>\n )}\n </div>\n\n <div className=\"settings-view settings-scroll border-l border-white/10\">\n <button\n onClick={() => setSettingsView(\"root\")}\n className=\"settings-back\"\n >\n <ChevronLeft size={16} />\n <span>Playback speed</span>\n </button>\n {PLAYBACK_RATES.map((rate) => (\n <button\n key={rate}\n onClick={() => changePlaybackRate(rate)}\n className={`settings-option ${playbackRate === rate ? \"settings-option-active\" : \"\"}`}\n >\n <span>{rate}x</span>\n {playbackRate === rate ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n ))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n\n <button\n onClick={togglePictureInPicture}\n disabled={!pipSupported}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all disabled:opacity-40 disabled:cursor-not-allowed\"\n title={pipSupported ? \"Miniplayer (i)\" : \"Picture-in-picture not supported\"}\n >\n <PictureInPicture size={18} className=\"control-icon\" />\n </button>\n\n <button\n onClick={() => setTheaterMode((prev) => !prev)}\n className=\"control-btn h-9 w-9 items-center justify-center rounded-md transition-all hidden sm:flex\"\n title=\"Theater mode (t)\"\n >\n {isTheater ? (\n <Tv size={18} className=\"control-icon\" />\n ) : (\n <RectangleHorizontal size={18} className=\"control-icon\" />\n )}\n </button>\n\n <button\n onClick={toggleFullscreen}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n title=\"Fullscreen (f)\"\n >\n {isFullscreen ? (\n <Minimize size={18} className=\"control-icon\" />\n ) : (\n <Maximize size={18} className=\"control-icon\" />\n )}\n </button>\n </div>\n </div>\n </div>\n\n <video\n ref={videoRef}\n preload=\"metadata\"\n className=\"w-full bg-black block\"\n onClick={togglePlay}\n onDoubleClick={toggleFullscreen}\n onPlay={() => {\n setIsPlaying(true);\n queueIdleFade();\n }}\n onPause={() => {\n setIsPlaying(false);\n setIsUserInactive(false);\n }}\n onTimeUpdate={(event) => {\n const time = event.currentTarget.currentTime;\n if (time === 0 && currentTime > 1 && !isScrubbing) return;\n setCurrentTime(time);\n }}\n onDurationChange={(event) => setDuration(event.currentTarget.duration)}\n onLoadedMetadata={(event) => {\n setDuration(event.currentTarget.duration);\n }}\n onVolumeChange={(event) => {\n setIsMuted(event.currentTarget.muted);\n setVolume(event.currentTarget.muted ? 0 : event.currentTarget.volume);\n }}\n >\n {captionsSrc ? (\n <track kind=\"captions\" src={captionsSrc} srcLang=\"en\" label=\"English\" default={false} />\n ) : null}\n </video>\n </div>\n </section>\n </main>\n );\n}\n"],"mappings":"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","names":["Hls"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../components/YouTubePlayer.tsx"],"sourcesContent":["\"use client\";\n\nexport { default as YouTubePlayer } from \"../components/YouTubePlayer\";\n","\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport {\n Captions,\n ChevronLeft,\n ChevronRight,\n Maximize,\n Minimize,\n Pause,\n PictureInPicture,\n Play,\n RectangleHorizontal,\n Settings,\n Tv,\n Volume1,\n Volume2,\n VolumeX,\n} from \"lucide-react\";\nimport Hls from \"hls.js\";\n\nexport interface PlayerProps {\n src: string;\n title: string;\n description?: string;\n eyebrow?: string;\n badges?: string[];\n captionsSrc?: string;\n thumbnailTrackSrc?: string;\n theaterMode?: boolean;\n defaultTheaterMode?: boolean;\n onTheaterModeChange?: (isTheaterMode: boolean) => void;\n}\n\ninterface ThumbnailCue {\n startTime: number;\n endTime: number;\n url: string;\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\ninterface QualityOption {\n height: number;\n index: number;\n}\n\ninterface PlaybackStats {\n source: string;\n resolution: string;\n quality: string;\n bitrate: string;\n codec: string;\n mimeType: string;\n audio: string;\n bufferHealth: string;\n droppedFrames: string;\n fps: string;\n playbackRate: string;\n state: string;\n}\n\nconst PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n\nexport default function YouTubePlayer({\n src,\n title,\n description,\n eyebrow,\n badges = [],\n captionsSrc,\n thumbnailTrackSrc,\n theaterMode,\n defaultTheaterMode = false,\n onTheaterModeChange,\n}: PlayerProps) {\n const videoRef = useRef<HTMLVideoElement>(null);\n const timelineRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const settingsRef = useRef<HTMLDivElement>(null);\n\n const [isPlaying, setIsPlaying] = useState(false);\n const [isMuted, setIsMuted] = useState(false);\n const [volume, setVolume] = useState(1);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [isScrubbing, setIsScrubbing] = useState(false);\n const [isHoveringTimeline, setIsHoveringTimeline] = useState(false);\n const [timelineProgress, setTimelineProgress] = useState(0);\n const [previewPosition, setPreviewPosition] = useState(0);\n const [previewTime, setPreviewTime] = useState(0);\n const [activeThumbnail, setActiveThumbnail] = useState<ThumbnailCue | null>(null);\n const [thumbnails, setThumbnails] = useState<ThumbnailCue[]>([]);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const [internalTheaterMode, setInternalTheaterMode] = useState(defaultTheaterMode);\n const [isUserInactive, setIsUserInactive] = useState(false);\n const [playbackRate, setPlaybackRate] = useState(1);\n const [captionsEnabled, setCaptionsEnabled] = useState(false);\n const [qualities, setQualities] = useState<QualityOption[]>([]);\n const [currentQuality, setCurrentQuality] = useState<number | \"auto\">(\"auto\");\n const [showSettings, setShowSettings] = useState(false);\n const [settingsView, setSettingsView] = useState<\"root\" | \"quality\" | \"speed\">(\"root\");\n const [showStatsForNerds, setShowStatsForNerds] = useState(false);\n const [pipSupported, setPipSupported] = useState(false);\n const [playbackStats, setPlaybackStats] = useState<PlaybackStats>({\n source: \"MP4\",\n resolution: \"0x0\",\n quality: \"Auto\",\n bitrate: \"N/A\",\n codec: \"N/A\",\n mimeType: \"video/mp4\",\n audio: \"N/A\",\n bufferHealth: \"0.0s\",\n droppedFrames: \"0\",\n fps: \"N/A\",\n playbackRate: \"1x\",\n state: \"Idle\",\n });\n const [bitrateHistory, setBitrateHistory] = useState<number[]>([]);\n const [bufferHistory, setBufferHistory] = useState<number[]>([]);\n\n const idleTimer = useRef<NodeJS.Timeout | null>(null);\n const hlsRef = useRef<Hls | null>(null);\n const dashRef = useRef<any>(null);\n const wasPlayingBeforeScrub = useRef(false);\n const scrubStartThumbnail = useRef<ThumbnailCue | null>(null);\n const isTheaterControlled = theaterMode !== undefined;\n const isTheater = isTheaterControlled ? theaterMode : internalTheaterMode;\n\n const setTheaterMode = (nextValue: boolean | ((prev: boolean) => boolean)) => {\n const resolvedValue =\n typeof nextValue === \"function\" ? nextValue(isTheater) : nextValue;\n\n if (!isTheaterControlled) {\n setInternalTheaterMode(resolvedValue);\n }\n\n onTheaterModeChange?.(resolvedValue);\n };\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n\n let hls: Hls | null = null;\n let dash: any = null;\n let isMounted = true;\n\n if (src.includes(\".m3u8\")) {\n if (Hls.isSupported()) {\n hls = new Hls();\n hlsRef.current = hls;\n hls.loadSource(src);\n hls.attachMedia(video);\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_, data) => {\n const availableQualities: QualityOption[] = data.levels.map((level, index) => ({\n height: level.height,\n index,\n }));\n const uniqueQualities = Array.from(\n new Map(availableQualities.map((q) => [q.height, q])).values(),\n ).sort((a, b) => b.height - a.height);\n setQualities(uniqueQualities);\n });\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_, data) => {\n if (hls?.autoLevelEnabled) {\n setCurrentQuality(\"auto\");\n } else {\n setCurrentQuality(data.level);\n }\n });\n } else if (video.canPlayType(\"application/vnd.apple.mpegurl\")) {\n video.src = src;\n }\n } else if (src.includes(\".mpd\")) {\n import(\"dashjs\").then((dashjs) => {\n if (!isMounted) return;\n\n dash = dashjs.MediaPlayer().create();\n dashRef.current = dash;\n dash.initialize(video, src, false);\n\n dash.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED, () => {\n const representations = dash.getRepresentationsByType?.(\"video\");\n if (representations?.length) {\n const availableQualities: QualityOption[] = representations.map(\n (representation: any, index: number) => ({\n height: representation.height,\n index,\n }),\n );\n const uniqueQualities = Array.from(\n new Map(availableQualities.map((q) => [q.height, q])).values(),\n ).sort((a, b) => b.height - a.height);\n setQualities(uniqueQualities);\n } else {\n setQualities([]);\n }\n });\n\n dash.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_RENDERED, (event: any) => {\n if (event.mediaType !== \"video\") return;\n\n const settings = dash.getSettings();\n if (settings.streaming?.abr?.autoSwitchBitrate?.video) {\n setCurrentQuality(\"auto\");\n } else {\n setCurrentQuality(event.newQuality);\n }\n });\n\n dash.on(dashjs.MediaPlayer.events.ERROR, () => {\n setQualities([]);\n setCurrentQuality(\"auto\");\n });\n });\n } else {\n video.src = src;\n }\n\n return () => {\n isMounted = false;\n if (hls) {\n hls.destroy();\n hlsRef.current = null;\n }\n if (dash) {\n dash.reset();\n dashRef.current = null;\n }\n };\n }, [src]);\n\n useEffect(() => {\n if (videoRef.current && videoRef.current.readyState >= 1) {\n setDuration(videoRef.current.duration || 0);\n }\n }, []);\n\n const parseVttTime = (timeStr: string) => {\n const parts = timeStr.split(\":\");\n if (parts.length === 3) {\n return Number(parts[0]) * 3600 + Number(parts[1]) * 60 + Number(parts[2]);\n }\n if (parts.length === 2) {\n return Number(parts[0]) * 60 + Number(parts[1]);\n }\n return Number(parts[0]) || 0;\n };\n\n useEffect(() => {\n if (!thumbnailTrackSrc) return;\n\n let isMounted = true;\n fetch(thumbnailTrackSrc)\n .then((response) => response.text())\n .then((text) => {\n if (!isMounted) return;\n const lines = text.split(\"\\n\");\n const cues: ThumbnailCue[] = [];\n let currentCue: Partial<ThumbnailCue> = {};\n\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i].trim();\n if (line.includes(\"-->\")) {\n const parts = line.split(\"-->\");\n currentCue.startTime = parseVttTime(parts[0].trim());\n currentCue.endTime = parseVttTime(parts[1].trim());\n } else if (line.includes(\"#xywh=\")) {\n const [url, coords] = line.split(\"#xywh=\");\n const [x, y, w, h] = coords.split(\",\").map(Number);\n\n try {\n currentCue.url = new URL(url, new URL(thumbnailTrackSrc, window.location.href)).href;\n } catch {\n currentCue.url = url;\n }\n\n currentCue.x = x;\n currentCue.y = y;\n currentCue.w = w;\n currentCue.h = h;\n cues.push(currentCue as ThumbnailCue);\n currentCue = {};\n }\n }\n setThumbnails(cues);\n })\n .catch(console.error);\n\n return () => {\n isMounted = false;\n };\n }, [thumbnailTrackSrc]);\n\n const formatDuration = (time: number) => {\n if (!Number.isFinite(time)) return \"0:00\";\n const seconds = Math.floor(time % 60);\n const minutes = Math.floor(time / 60) % 60;\n const hours = Math.floor(time / 3600);\n\n const leadingZeroFormatter = new Intl.NumberFormat(undefined, {\n minimumIntegerDigits: 2,\n });\n\n if (hours === 0) {\n return `${minutes}:${leadingZeroFormatter.format(seconds)}`;\n }\n return `${hours}:${leadingZeroFormatter.format(minutes)}:${leadingZeroFormatter.format(seconds)}`;\n };\n\n const queueIdleFade = () => {\n if (idleTimer.current) clearTimeout(idleTimer.current);\n setIsUserInactive(false);\n\n if (videoRef.current?.paused || isScrubbing) return;\n\n idleTimer.current = setTimeout(() => {\n if (!videoRef.current?.paused && !isScrubbing) {\n setIsUserInactive(true);\n }\n }, 2200);\n };\n\n useEffect(() => {\n const events = [\"pointermove\", \"pointerdown\", \"focusin\", \"mouseenter\"];\n const container = containerRef.current;\n if (!container) return;\n\n const handler = () => queueIdleFade();\n events.forEach((eventName) => container.addEventListener(eventName, handler));\n\n const handleLeave = () => {\n if (!videoRef.current?.paused && !isScrubbing) {\n setIsUserInactive(true);\n }\n };\n container.addEventListener(\"pointerleave\", handleLeave);\n\n return () => {\n events.forEach((eventName) => container.removeEventListener(eventName, handler));\n container.removeEventListener(\"pointerleave\", handleLeave);\n if (idleTimer.current) clearTimeout(idleTimer.current);\n };\n }, [isScrubbing]);\n\n useEffect(() => {\n const handleFullscreenChange = () => {\n setIsFullscreen(document.fullscreenElement === containerRef.current);\n };\n document.addEventListener(\"fullscreenchange\", handleFullscreenChange);\n return () => document.removeEventListener(\"fullscreenchange\", handleFullscreenChange);\n }, []);\n\n useEffect(() => {\n const handleClickOutside = (event: PointerEvent) => {\n if (!showSettings || !settingsRef.current) return;\n if (!settingsRef.current.contains(event.target as Node)) {\n setShowSettings(false);\n setSettingsView(\"root\");\n }\n };\n document.addEventListener(\"pointerdown\", handleClickOutside);\n return () => document.removeEventListener(\"pointerdown\", handleClickOutside);\n }, [showSettings]);\n\n useEffect(() => {\n const video = videoRef.current;\n const supported =\n typeof document !== \"undefined\" &&\n \"pictureInPictureEnabled\" in document &&\n document.pictureInPictureEnabled &&\n !!video &&\n typeof (video as HTMLVideoElement & { requestPictureInPicture?: () => Promise<PictureInPictureWindow> })\n .requestPictureInPicture === \"function\";\n\n setPipSupported(Boolean(supported));\n }, [src]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n const tagName = document.activeElement?.tagName?.toLowerCase();\n if (tagName === \"input\") return;\n\n switch (event.key.toLowerCase()) {\n case \" \":\n case \"k\":\n if (tagName === \"button\") return;\n event.preventDefault();\n togglePlay();\n break;\n case \"f\":\n event.preventDefault();\n toggleFullscreen();\n break;\n case \"t\":\n event.preventDefault();\n setTheaterMode((prev) => !prev);\n break;\n case \"m\":\n event.preventDefault();\n toggleMute();\n break;\n case \"arrowleft\":\n case \"j\":\n event.preventDefault();\n skipBy(-5);\n break;\n case \"arrowright\":\n case \"l\":\n event.preventDefault();\n skipBy(5);\n break;\n case \"c\":\n event.preventDefault();\n toggleCaptions();\n break;\n case \"i\":\n event.preventDefault();\n void togglePictureInPicture();\n break;\n default:\n break;\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [isScrubbing, playbackRate]);\n\n const togglePlay = () => {\n if (videoRef.current?.paused) {\n videoRef.current.play().catch(console.error);\n } else {\n videoRef.current?.pause();\n }\n };\n\n const toggleMute = () => {\n if (videoRef.current) {\n videoRef.current.muted = !videoRef.current.muted;\n setIsMuted(videoRef.current.muted);\n if (videoRef.current.muted) {\n setVolume(0);\n } else {\n setVolume(videoRef.current.volume || 1);\n }\n }\n };\n\n const handleVolumeChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const val = Number(event.target.value);\n setVolume(val);\n if (videoRef.current) {\n videoRef.current.volume = val;\n videoRef.current.muted = val === 0;\n setIsMuted(val === 0);\n }\n };\n\n const toggleFullscreen = async () => {\n if (!document.fullscreenElement) {\n await containerRef.current?.requestFullscreen();\n } else {\n await document.exitFullscreen();\n }\n };\n\n const skipBy = (seconds: number) => {\n if (videoRef.current) {\n const nextTime = Math.min(\n Math.max(videoRef.current.currentTime + seconds, 0),\n videoRef.current.duration || 0,\n );\n videoRef.current.currentTime = nextTime;\n setCurrentTime(nextTime);\n }\n };\n\n const toggleCaptions = () => {\n const video = videoRef.current;\n if (video && video.textTracks[0]) {\n const enabled = video.textTracks[0].mode === \"showing\";\n video.textTracks[0].mode = enabled ? \"hidden\" : \"showing\";\n setCaptionsEnabled(!enabled);\n }\n };\n\n const changePlaybackRate = (rate: number) => {\n if (!videoRef.current) return;\n videoRef.current.playbackRate = rate;\n setPlaybackRate(rate);\n setShowSettings(false);\n setSettingsView(\"root\");\n };\n\n const changeQuality = (index: number | \"auto\") => {\n setCurrentQuality(index);\n setShowSettings(false);\n setSettingsView(\"root\");\n\n if (hlsRef.current) {\n if (index === \"auto\") {\n hlsRef.current.currentLevel = -1;\n } else {\n hlsRef.current.currentLevel = index;\n }\n } else if (dashRef.current) {\n if (index === \"auto\") {\n dashRef.current.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: true } } },\n });\n } else {\n dashRef.current.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: false } } },\n });\n dashRef.current.setRepresentationForTypeByIndex(\"video\", index, true);\n }\n }\n };\n\n const togglePictureInPicture = async () => {\n try {\n if (document.pictureInPictureElement) {\n await document.exitPictureInPicture();\n return;\n }\n\n const video = videoRef.current as\n | (HTMLVideoElement & { requestPictureInPicture?: () => Promise<PictureInPictureWindow> })\n | null;\n\n if (!video || typeof video.requestPictureInPicture !== \"function\") {\n return;\n }\n\n await video.requestPictureInPicture();\n } catch (error) {\n console.error(error);\n }\n };\n\n const getQualityLabel = () => {\n if (currentQuality === \"auto\") {\n return \"Auto\";\n }\n\n return `${qualities.find((quality) => quality.index === currentQuality)?.height ?? currentQuality}p`;\n };\n\n const renderSparkline = (values: number[], colorClassName: string) => {\n if (values.length < 2) {\n return <div className=\"h-14 rounded-lg bg-white/5\" />;\n }\n\n const max = Math.max(...values, 1);\n const points = values\n .map((value, index) => {\n const x = (index / (values.length - 1)) * 100;\n const y = 100 - (value / max) * 100;\n return `${x},${y}`;\n })\n .join(\" \");\n\n return (\n <div className=\"h-14 rounded-lg bg-white/5 p-1\">\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" className=\"h-full w-full\">\n <polyline\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"3\"\n points={points}\n className={colorClassName}\n />\n </svg>\n </div>\n );\n };\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n\n const formatBitrate = (bitrate?: number | null) => {\n if (!bitrate || !Number.isFinite(bitrate) || bitrate <= 0) {\n return \"N/A\";\n }\n\n return bitrate >= 1_000_000\n ? `${(bitrate / 1_000_000).toFixed(2)} Mbps`\n : `${Math.round(bitrate / 1000)} kbps`;\n };\n\n const updateStats = () => {\n const bufferedAhead = (() => {\n for (let i = 0; i < video.buffered.length; i += 1) {\n const start = video.buffered.start(i);\n const end = video.buffered.end(i);\n if (video.currentTime >= start && video.currentTime <= end) {\n return Math.max(end - video.currentTime, 0);\n }\n }\n return 0;\n })();\n\n const playbackQuality =\n typeof video.getVideoPlaybackQuality === \"function\"\n ? video.getVideoPlaybackQuality()\n : null;\n\n let source = \"MP4\";\n let bitrate = \"N/A\";\n let quality = getQualityLabel();\n let codec = \"N/A\";\n let mimeType = video.currentSrc.includes(\".mpd\")\n ? \"application/dash+xml\"\n : video.currentSrc.includes(\".m3u8\")\n ? \"application/vnd.apple.mpegurl\"\n : \"video/mp4\";\n let audio = \"N/A\";\n let bitrateValue = 0;\n\n if (hlsRef.current) {\n source = \"HLS\";\n const hls = hlsRef.current;\n const levelIndex =\n hls.currentLevel >= 0\n ? hls.currentLevel\n : hls.loadLevel >= 0\n ? hls.loadLevel\n : hls.nextAutoLevel >= 0\n ? hls.nextAutoLevel\n : -1;\n const level = levelIndex >= 0 ? hls.levels[levelIndex] : null;\n bitrateValue = level?.bitrate ?? 0;\n bitrate = formatBitrate(bitrateValue);\n quality = level?.height ? `${level.height}p` : getQualityLabel();\n codec =\n level?.codecSet ||\n [level?.videoCodec, level?.audioCodec].filter(Boolean).join(\" / \") ||\n \"N/A\";\n mimeType = \"application/vnd.apple.mpegurl\";\n audio = level?.audioCodec || \"AAC/Unknown\";\n } else if (dashRef.current) {\n source = \"DASH\";\n const representation = dashRef.current.getCurrentRepresentationForType?.(\"video\");\n const audioTrack = dashRef.current.getCurrentTrackFor?.(\"audio\");\n const throughput = dashRef.current.getSafeAverageThroughput?.(\"video\");\n bitrateValue = representation?.bandwidth ?? throughput ?? 0;\n bitrate = formatBitrate(bitrateValue);\n quality = representation?.height ? `${representation.height}p` : getQualityLabel();\n codec = representation?.codecs || audioTrack?.codec || \"N/A\";\n mimeType = representation?.mimeType || audioTrack?.mimeType || \"application/dash+xml\";\n audio = [audioTrack?.codec, audioTrack?.lang].filter(Boolean).join(\" / \") || \"N/A\";\n }\n\n setBitrateHistory((previous) => [...previous.slice(-39), bitrateValue / 1_000_000]);\n setBufferHistory((previous) => [...previous.slice(-39), bufferedAhead]);\n\n setPlaybackStats({\n source,\n resolution:\n video.videoWidth && video.videoHeight ? `${video.videoWidth}x${video.videoHeight}` : \"0x0\",\n quality,\n bitrate,\n codec,\n mimeType,\n audio,\n bufferHealth: `${bufferedAhead.toFixed(1)}s`,\n droppedFrames: String(playbackQuality?.droppedVideoFrames ?? 0),\n fps:\n video.currentTime > 0 && playbackQuality?.totalVideoFrames\n ? `${Math.round(\n ((playbackQuality.totalVideoFrames ?? 0) - (playbackQuality.droppedVideoFrames ?? 0)) /\n Math.max(video.currentTime, 1),\n )}`\n : \"N/A\",\n playbackRate: `${video.playbackRate}x`,\n state: video.paused ? \"Paused\" : video.readyState < 3 ? \"Buffering\" : \"Playing\",\n });\n };\n\n updateStats();\n const intervalId = window.setInterval(updateStats, 500);\n return () => window.clearInterval(intervalId);\n }, [src, playbackRate, currentQuality, qualities]);\n\n const hasCaptions = Boolean(captionsSrc);\n const hasQualityOptions = qualities.length > 0;\n\n const getTimelinePercent = (clientX: number) => {\n const rect = timelineRef.current?.getBoundingClientRect();\n if (!rect || rect.width === 0) return 0;\n const rawPosition = clientX - rect.left;\n return Math.min(Math.max(rawPosition / rect.width, 0), 1);\n };\n\n const getThumbnailForTime = (time: number) => {\n if (thumbnails.length === 0) return null;\n\n return (\n thumbnails.find((thumbnail) => time >= thumbnail.startTime && time <= thumbnail.endTime) ||\n null\n );\n };\n\n const updateTimelinePreview = (event: React.PointerEvent | PointerEvent) => {\n const percent = getTimelinePercent(event.clientX);\n const time = percent * duration;\n\n setPreviewPosition(percent);\n setPreviewTime(time);\n\n if (duration > 0) {\n const thumbnail = getThumbnailForTime(time);\n if (thumbnail) {\n setActiveThumbnail(thumbnail);\n } else if (isScrubbing && scrubStartThumbnail.current) {\n setActiveThumbnail(scrubStartThumbnail.current);\n } else if (!isScrubbing) {\n setActiveThumbnail(null);\n }\n }\n\n if (isScrubbing) {\n event.preventDefault();\n setTimelineProgress(percent);\n }\n };\n\n const beginScrubbing = (event: React.PointerEvent) => {\n if (event.pointerType === \"mouse\" && event.button !== 0) return;\n wasPlayingBeforeScrub.current = !videoRef.current?.paused;\n scrubStartThumbnail.current = getThumbnailForTime(videoRef.current?.currentTime ?? 0);\n setIsScrubbing(true);\n videoRef.current?.pause();\n updateTimelinePreview(event);\n };\n\n const endScrubbing = (event: PointerEvent) => {\n if (!isScrubbing) return;\n setIsScrubbing(false);\n const percent = getTimelinePercent(event.clientX);\n if (videoRef.current) {\n const nextTime = percent * (videoRef.current.duration || 0);\n videoRef.current.currentTime = nextTime;\n setCurrentTime(nextTime);\n setPreviewTime(nextTime);\n if (wasPlayingBeforeScrub.current) {\n videoRef.current.play().catch(console.error);\n }\n }\n scrubStartThumbnail.current = null;\n };\n\n useEffect(() => {\n if (isScrubbing) {\n const onPointerMove = (event: PointerEvent) => updateTimelinePreview(event);\n document.addEventListener(\"pointermove\", onPointerMove);\n document.addEventListener(\"pointerup\", endScrubbing);\n return () => {\n document.removeEventListener(\"pointermove\", onPointerMove);\n document.removeEventListener(\"pointerup\", endScrubbing);\n };\n }\n return undefined;\n }, [isScrubbing, duration, thumbnails]);\n\n const VolumeIcon = () => {\n if (isMuted || volume === 0) return <VolumeX size={18} className=\"control-icon\" />;\n if (volume < 0.5) return <Volume1 size={18} className=\"control-icon\" />;\n return <Volume2 size={18} className=\"control-icon\" />;\n };\n\n return (\n <main className=\"svp-root w-full max-w-[1180px] mx-auto py-8 px-4\">\n <section className=\"mb-6\">\n {eyebrow ? (\n <p className=\"m-0 mb-2 text-youtube-muted uppercase tracking-wider text-xs font-medium\">\n {eyebrow}\n </p>\n ) : null}\n <h1 className=\"m-0 text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight mb-4\">{title}</h1>\n {description ? (\n <p className=\"max-w-2xl m-0 text-youtube-muted text-base leading-relaxed\">{description}</p>\n ) : null}\n {badges.length > 0 ? (\n <ul className=\"list-none flex flex-wrap gap-2 p-0 mt-5\">\n {badges.map((badge) => (\n <li\n key={badge}\n className=\"px-3 py-1 bg-white/10 rounded-full text-youtube-text text-sm font-medium\"\n >\n {badge}\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n\n <section\n className={`bg-youtube-panel shadow-2xl ring-1 ring-white/5 transition-[width,transform,border-radius] duration-300 ease-out ${\n isTheater\n ? \"relative left-1/2 w-screen max-w-none -translate-x-1/2 rounded-none md:rounded-2xl\"\n : \"rounded-xl overflow-hidden\"\n }`}\n >\n <div\n ref={containerRef}\n className={`relative flex justify-center bg-black group transition-[max-height] duration-300 ease-out ${\n isTheater ? \"min-h-[56.25vw] max-h-[82vh] w-full\" : \"\"\n } ${isFullscreen ? \"max-h-screen w-full\" : \"\"} ${isUserInactive ? \"user-inactive\" : \"\"}`}\n >\n {showStatsForNerds ? (\n <div className=\"stats-panel absolute left-3 top-3 z-30 w-[min(92vw,360px)] rounded-lg border border-white/10 bg-black/75 p-2.5 text-[10px] leading-4 text-white backdrop-blur-sm\">\n <div className=\"mb-2 text-[10px] font-semibold uppercase tracking-[0.2em] text-white/55\">\n Stats for nerds\n </div>\n <div className=\"space-y-1.5\">\n <div className=\"stats-row\">\n <span className=\"stats-key\">Buffer</span>\n <div className=\"stats-value-wrap\">\n <span>{playbackStats.bufferHealth}</span>\n <div className=\"stats-graph\">{renderSparkline(bufferHistory, \"text-white/80\")}</div>\n </div>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Bitrate</span>\n <div className=\"stats-value-wrap\">\n <span>{playbackStats.bitrate}</span>\n <div className=\"stats-graph\">{renderSparkline(bitrateHistory, \"text-youtube-accent\")}</div>\n </div>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Quality</span>\n <span className=\"stats-value-wrap\">{playbackStats.quality}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Codecs</span>\n <span className=\"stats-value-wrap\">{playbackStats.codec}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Audio</span>\n <span className=\"stats-value-wrap\">{playbackStats.audio}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Viewport</span>\n <span className=\"stats-value-wrap\">{playbackStats.resolution}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Mime</span>\n <span className=\"stats-value-wrap\">{playbackStats.mimeType}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Frames</span>\n <span className=\"stats-value-wrap\">\n {playbackStats.fps} fps / {playbackStats.droppedFrames} dropped\n </span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">State</span>\n <span className=\"stats-value-wrap\">\n {playbackStats.state} / {playbackStats.playbackRate}\n </span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Source</span>\n <span className=\"stats-value-wrap\">{playbackStats.source}</span>\n </div>\n </div>\n </div>\n ) : null}\n\n <button\n onClick={togglePlay}\n aria-label=\"Play video\"\n className={`absolute inset-1/2 -translate-x-1/2 -translate-y-1/2 grid place-items-center w-16 h-16 md:w-20 md:h-20 rounded-full bg-black/50 backdrop-blur-md text-white z-10 shadow-lg transition-all duration-200 hover:bg-youtube-accent ${isPlaying ? \"opacity-0 scale-75 pointer-events-none\" : \"opacity-100 scale-100\"}`}\n >\n <Play size={32} className=\"ml-1 control-icon\" fill=\"currentColor\" />\n </button>\n\n <div\n className={`video-controls-container absolute bottom-0 left-0 right-0 px-3 pb-2 pt-16 bg-gradient-to-t from-black/90 to-transparent text-white z-20 transition-all duration-500 ease-out ${isUserInactive && isPlaying ? \"opacity-0 pointer-events-none cursor-none translate-y-2\" : \"opacity-100 translate-y-0\"}`}\n >\n <div\n ref={timelineRef}\n className=\"timeline-container h-4 mx-1 cursor-pointer flex items-center relative group/timeline\"\n onPointerDown={beginScrubbing}\n onPointerMove={(event) => {\n if (!isScrubbing) updateTimelinePreview(event);\n }}\n onPointerEnter={() => setIsHoveringTimeline(true)}\n onPointerLeave={() => setIsHoveringTimeline(false)}\n >\n <div className=\"timeline-progress w-full h-[3px] bg-youtube-track relative transition-[height] duration-150\">\n <div\n className=\"absolute inset-y-0 left-0 bg-white/40\"\n style={{\n width: `${previewPosition * 100}%`,\n display: isHoveringTimeline || isScrubbing ? \"block\" : \"none\",\n }}\n />\n <div\n className=\"absolute inset-y-0 left-0 bg-youtube-accent transition-all duration-200 ease-out\"\n style={{\n width: `${(isScrubbing ? timelineProgress : duration ? currentTime / duration : 0) * 100}%`,\n }}\n />\n <div\n className=\"timeline-thumb absolute top-1/2 w-3.5 h-3.5 rounded-full bg-youtube-accent transition-all duration-200 ease-out\"\n style={{\n left: `${(isScrubbing ? timelineProgress : duration ? currentTime / duration : 0) * 100}%`,\n transform: `translate(-50%, -50%) scale(${isHoveringTimeline || isScrubbing ? 1 : 0})`,\n }}\n />\n\n {activeThumbnail ? (\n <div\n className={`pointer-events-none absolute bottom-6 border-2 border-white rounded-lg shadow-lg overflow-hidden bg-black -translate-x-1/2 transition-opacity duration-200 ${isScrubbing || isHoveringTimeline ? \"opacity-100\" : \"opacity-0\"}`}\n style={{ left: `${previewPosition * 100}%`, width: \"160px\", height: \"110px\" }}\n >\n <div\n style={{\n backgroundImage: `url(${activeThumbnail.url})`,\n backgroundPosition: `-${activeThumbnail.x}px -${activeThumbnail.y}px`,\n width: `${activeThumbnail.w}px`,\n height: `${activeThumbnail.h}px`,\n transform: `scale(${160 / activeThumbnail.w})`,\n transformOrigin: \"top left\",\n }}\n />\n <div className=\"absolute inset-x-0 bottom-0 bg-black/80 px-2 py-1 text-center text-[11px] text-white\">\n {formatDuration(previewTime)}\n </div>\n </div>\n ) : isScrubbing || isHoveringTimeline ? (\n <div\n className=\"pointer-events-none absolute bottom-6 min-w-16 rounded-md bg-black/85 px-2 py-1 text-center text-[11px] text-white shadow-lg -translate-x-1/2 transition-opacity duration-200\"\n style={{ left: `${previewPosition * 100}%` }}\n >\n {formatDuration(previewTime)}\n </div>\n ) : null}\n </div>\n </div>\n\n <div className=\"flex items-center justify-between gap-3 pt-2 px-1\">\n <div className=\"flex min-w-0 items-center gap-1 sm:gap-2\">\n <button\n onClick={togglePlay}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n >\n {isPlaying ? (\n <Pause size={18} fill=\"currentColor\" className=\"control-icon\" />\n ) : (\n <Play size={18} fill=\"currentColor\" className=\"control-icon\" />\n )}\n </button>\n\n <div className=\"volume-container flex items-center gap-1\">\n <button\n onClick={toggleMute}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n >\n <VolumeIcon />\n </button>\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"any\"\n value={volume}\n onChange={handleVolumeChange}\n className=\"volume-slider h-1\"\n style={{ \"--volume-percent\": `${volume * 100}%` } as React.CSSProperties}\n />\n </div>\n\n <div className=\"flex min-w-0 items-center gap-1 text-[13px] font-sans text-white/90 tabular-nums whitespace-nowrap\">\n <span>{formatDuration(currentTime)}</span>\n <span className=\"text-white/50\">/</span>\n <span>{formatDuration(duration)}</span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-1 sm:gap-2\">\n <button\n onClick={toggleCaptions}\n disabled={!hasCaptions}\n className={`control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all disabled:opacity-40 disabled:cursor-not-allowed ${captionsEnabled ? \"text-youtube-accent\" : \"\"}`}\n title=\"Subtitles/closed captions (c)\"\n >\n <Captions size={18} className=\"control-icon\" />\n </button>\n\n <div ref={settingsRef} className=\"relative\">\n <button\n onClick={() => {\n setShowSettings((prev) => !prev);\n setSettingsView(\"root\");\n }}\n className={`control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all ${showSettings ? \"bg-white/10 text-youtube-accent\" : \"\"}`}\n title=\"Settings\"\n >\n <Settings\n size={18}\n className={`control-icon ${showSettings ? \"rotate-[22deg] scale-110\" : \"\"} transition-transform duration-300`}\n />\n </button>\n\n {showSettings ? (\n <div\n className={`settings-panel absolute bottom-full right-0 mb-4 w-56 bg-black/40 backdrop-blur-sm rounded-xl overflow-hidden shadow-2xl z-50 border border-white/10 ${\n settingsView === \"root\" ? \"settings-panel-root\" : \"max-h-[min(28rem,calc(100vh-10rem))]\"\n }`}\n >\n <div\n className=\"settings-slider\"\n style={{\n width: \"300%\",\n transform: `translateX(${\n settingsView === \"root\"\n ? \"0%\"\n : settingsView === \"quality\"\n ? \"-33.3333%\"\n : \"-66.6667%\"\n })`,\n }}\n >\n <div className=\"settings-view settings-scroll\">\n <button\n onClick={() => setSettingsView(\"quality\")}\n disabled={!hasQualityOptions}\n className=\"settings-item disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n <div>\n <div className=\"settings-label\">Quality</div>\n <div className=\"settings-value\">\n {hasQualityOptions ? getQualityLabel() : \"Unavailable\"}\n </div>\n </div>\n <ChevronRight size={16} className=\"text-white/55\" />\n </button>\n\n <button\n onClick={() => setSettingsView(\"speed\")}\n className=\"settings-item\"\n >\n <div>\n <div className=\"settings-label\">Playback speed</div>\n <div className=\"settings-value\">{playbackRate}x</div>\n </div>\n <ChevronRight size={16} className=\"text-white/55\" />\n </button>\n\n <button\n onClick={() => {\n setShowStatsForNerds((prev) => !prev);\n setShowSettings(false);\n setSettingsView(\"root\");\n }}\n className=\"settings-item\"\n >\n <div>\n <div className=\"settings-label\">Stats for nerds</div>\n <div className=\"settings-value\">\n {showStatsForNerds ? \"On\" : \"Off\"}\n </div>\n </div>\n <span\n className={`h-2 w-2 rounded-full ${\n showStatsForNerds ? \"bg-youtube-accent\" : \"bg-white/25\"\n }`}\n />\n </button>\n </div>\n\n <div className=\"settings-view settings-scroll border-l border-white/10\">\n <button\n onClick={() => setSettingsView(\"root\")}\n className=\"settings-back\"\n >\n <ChevronLeft size={16} />\n <span>Quality</span>\n </button>\n <button\n onClick={() => changeQuality(\"auto\")}\n className={`settings-option ${currentQuality === \"auto\" ? \"settings-option-active\" : \"\"}`}\n >\n <span>Auto</span>\n {currentQuality === \"auto\" ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n {qualities.length > 0 ? (\n qualities.map((quality) => (\n <button\n key={quality.height}\n onClick={() => changeQuality(quality.index)}\n className={`settings-option ${currentQuality === quality.index ? \"settings-option-active\" : \"\"}`}\n >\n <span>{quality.height}p</span>\n {currentQuality === quality.index ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n ))\n ) : (\n <div className=\"px-4 py-3 text-[13px] text-white/55\">No quality options</div>\n )}\n </div>\n\n <div className=\"settings-view settings-scroll border-l border-white/10\">\n <button\n onClick={() => setSettingsView(\"root\")}\n className=\"settings-back\"\n >\n <ChevronLeft size={16} />\n <span>Playback speed</span>\n </button>\n {PLAYBACK_RATES.map((rate) => (\n <button\n key={rate}\n onClick={() => changePlaybackRate(rate)}\n className={`settings-option ${playbackRate === rate ? \"settings-option-active\" : \"\"}`}\n >\n <span>{rate}x</span>\n {playbackRate === rate ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n ))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n\n <button\n onClick={togglePictureInPicture}\n disabled={!pipSupported}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all disabled:opacity-40 disabled:cursor-not-allowed\"\n title={pipSupported ? \"Miniplayer (i)\" : \"Picture-in-picture not supported\"}\n >\n <PictureInPicture size={18} className=\"control-icon\" />\n </button>\n\n <button\n onClick={() => setTheaterMode((prev) => !prev)}\n className=\"control-btn h-9 w-9 items-center justify-center rounded-md transition-all hidden sm:flex\"\n title=\"Theater mode (t)\"\n >\n {isTheater ? (\n <Tv size={18} className=\"control-icon\" />\n ) : (\n <RectangleHorizontal size={18} className=\"control-icon\" />\n )}\n </button>\n\n <button\n onClick={toggleFullscreen}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n title=\"Fullscreen (f)\"\n >\n {isFullscreen ? (\n <Minimize size={18} className=\"control-icon\" />\n ) : (\n <Maximize size={18} className=\"control-icon\" />\n )}\n </button>\n </div>\n </div>\n </div>\n\n <video\n ref={videoRef}\n preload=\"metadata\"\n className=\"w-full bg-black block\"\n onClick={togglePlay}\n onDoubleClick={toggleFullscreen}\n onPlay={() => {\n setIsPlaying(true);\n queueIdleFade();\n }}\n onPause={() => {\n setIsPlaying(false);\n setIsUserInactive(false);\n }}\n onTimeUpdate={(event) => {\n const time = event.currentTarget.currentTime;\n if (time === 0 && currentTime > 1 && !isScrubbing) return;\n setCurrentTime(time);\n }}\n onDurationChange={(event) => setDuration(event.currentTarget.duration)}\n onLoadedMetadata={(event) => {\n setDuration(event.currentTarget.duration);\n }}\n onVolumeChange={(event) => {\n setIsMuted(event.currentTarget.muted);\n setVolume(event.currentTarget.muted ? 0 : event.currentTarget.volume);\n }}\n >\n {captionsSrc ? (\n <track kind=\"captions\" src={captionsSrc} srcLang=\"en\" label=\"English\" default={false} />\n ) : null}\n </video>\n </div>\n </section>\n </main>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAAmD;AACnD,0BAeO;AACP,iBAAgB;AAwhBH;AA3eb,IAAM,iBAAiB,CAAC,MAAM,KAAK,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC;AAE/C,SAAR,cAA+B;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB;AACF,GAAgB;AACd,QAAM,eAAW,qBAAyB,IAAI;AAC9C,QAAM,kBAAc,qBAAuB,IAAI;AAC/C,QAAM,mBAAe,qBAAuB,IAAI;AAChD,QAAM,kBAAc,qBAAuB,IAAI;AAE/C,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAChD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,CAAC;AACtC,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,CAAC;AAChD,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,CAAC;AAC1C,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AACpD,QAAM,CAAC,oBAAoB,qBAAqB,QAAI,uBAAS,KAAK;AAClE,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,uBAAS,CAAC;AAC1D,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,uBAAS,CAAC;AACxD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,CAAC;AAChD,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,uBAA8B,IAAI;AAChF,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAyB,CAAC,CAAC;AAC/D,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,KAAK;AACtD,QAAM,CAAC,qBAAqB,sBAAsB,QAAI,uBAAS,kBAAkB;AACjF,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAAS,KAAK;AAC1D,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,CAAC;AAClD,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,uBAAS,KAAK;AAC5D,QAAM,CAAC,WAAW,YAAY,QAAI,uBAA0B,CAAC,CAAC;AAC9D,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAA0B,MAAM;AAC5E,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,KAAK;AACtD,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAuC,MAAM;AACrF,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,uBAAS,KAAK;AAChE,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,KAAK;AACtD,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAwB;AAAA,IAChE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,cAAc;AAAA,IACd,eAAe;AAAA,IACf,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,EACT,CAAC;AACD,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAAmB,CAAC,CAAC;AACjE,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAmB,CAAC,CAAC;AAE/D,QAAM,gBAAY,qBAA8B,IAAI;AACpD,QAAM,aAAS,qBAAmB,IAAI;AACtC,QAAM,cAAU,qBAAY,IAAI;AAChC,QAAM,4BAAwB,qBAAO,KAAK;AAC1C,QAAM,0BAAsB,qBAA4B,IAAI;AAC5D,QAAM,sBAAsB,gBAAgB;AAC5C,QAAM,YAAY,sBAAsB,cAAc;AAEtD,QAAM,iBAAiB,CAAC,cAAsD;AAC5E,UAAM,gBACJ,OAAO,cAAc,aAAa,UAAU,SAAS,IAAI;AAE3D,QAAI,CAAC,qBAAqB;AACxB,6BAAuB,aAAa;AAAA,IACtC;AAEA,0BAAsB,aAAa;AAAA,EACrC;AAEA,8BAAU,MAAM;AACd,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,MAAO;AAEZ,QAAI,MAAkB;AACtB,QAAI,OAAY;AAChB,QAAI,YAAY;AAEhB,QAAI,IAAI,SAAS,OAAO,GAAG;AACzB,UAAI,WAAAA,QAAI,YAAY,GAAG;AACrB,cAAM,IAAI,WAAAA,QAAI;AACd,eAAO,UAAU;AACjB,YAAI,WAAW,GAAG;AAClB,YAAI,YAAY,KAAK;AAErB,YAAI,GAAG,WAAAA,QAAI,OAAO,iBAAiB,CAAC,GAAG,SAAS;AAC9C,gBAAM,qBAAsC,KAAK,OAAO,IAAI,CAAC,OAAO,WAAW;AAAA,YAC7E,QAAQ,MAAM;AAAA,YACd;AAAA,UACF,EAAE;AACF,gBAAM,kBAAkB,MAAM;AAAA,YAC5B,IAAI,IAAI,mBAAmB,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO;AAAA,UAC/D,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AACpC,uBAAa,eAAe;AAAA,QAC9B,CAAC;AAED,YAAI,GAAG,WAAAA,QAAI,OAAO,gBAAgB,CAAC,GAAG,SAAS;AAC7C,cAAI,KAAK,kBAAkB;AACzB,8BAAkB,MAAM;AAAA,UAC1B,OAAO;AACL,8BAAkB,KAAK,KAAK;AAAA,UAC9B;AAAA,QACF,CAAC;AAAA,MACH,WAAW,MAAM,YAAY,+BAA+B,GAAG;AAC7D,cAAM,MAAM;AAAA,MACd;AAAA,IACF,WAAW,IAAI,SAAS,MAAM,GAAG;AAC/B,aAAO,QAAQ,EAAE,KAAK,CAAC,WAAW;AAChC,YAAI,CAAC,UAAW;AAEhB,eAAO,OAAO,YAAY,EAAE,OAAO;AACnC,gBAAQ,UAAU;AAClB,aAAK,WAAW,OAAO,KAAK,KAAK;AAEjC,aAAK,GAAG,OAAO,YAAY,OAAO,oBAAoB,MAAM;AAC1D,gBAAM,kBAAkB,KAAK,2BAA2B,OAAO;AAC/D,cAAI,iBAAiB,QAAQ;AAC3B,kBAAM,qBAAsC,gBAAgB;AAAA,cAC1D,CAAC,gBAAqB,WAAmB;AAAA,gBACvC,QAAQ,eAAe;AAAA,gBACvB;AAAA,cACF;AAAA,YACF;AACA,kBAAM,kBAAkB,MAAM;AAAA,cAC5B,IAAI,IAAI,mBAAmB,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO;AAAA,YAC/D,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AACpC,yBAAa,eAAe;AAAA,UAC9B,OAAO;AACL,yBAAa,CAAC,CAAC;AAAA,UACjB;AAAA,QACF,CAAC;AAED,aAAK,GAAG,OAAO,YAAY,OAAO,yBAAyB,CAAC,UAAe;AACzE,cAAI,MAAM,cAAc,QAAS;AAEjC,gBAAM,WAAW,KAAK,YAAY;AAClC,cAAI,SAAS,WAAW,KAAK,mBAAmB,OAAO;AACrD,8BAAkB,MAAM;AAAA,UAC1B,OAAO;AACL,8BAAkB,MAAM,UAAU;AAAA,UACpC;AAAA,QACF,CAAC;AAED,aAAK,GAAG,OAAO,YAAY,OAAO,OAAO,MAAM;AAC7C,uBAAa,CAAC,CAAC;AACf,4BAAkB,MAAM;AAAA,QAC1B,CAAC;AAAA,MACH,CAAC;AAAA,IACH,OAAO;AACL,YAAM,MAAM;AAAA,IACd;AAEA,WAAO,MAAM;AACX,kBAAY;AACZ,UAAI,KAAK;AACP,YAAI,QAAQ;AACZ,eAAO,UAAU;AAAA,MACnB;AACA,UAAI,MAAM;AACR,aAAK,MAAM;AACX,gBAAQ,UAAU;AAAA,MACpB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,8BAAU,MAAM;AACd,QAAI,SAAS,WAAW,SAAS,QAAQ,cAAc,GAAG;AACxD,kBAAY,SAAS,QAAQ,YAAY,CAAC;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,CAAC,YAAoB;AACxC,UAAM,QAAQ,QAAQ,MAAM,GAAG;AAC/B,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO,OAAO,MAAM,CAAC,CAAC,IAAI,OAAO,OAAO,MAAM,CAAC,CAAC,IAAI,KAAK,OAAO,MAAM,CAAC,CAAC;AAAA,IAC1E;AACA,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO,OAAO,MAAM,CAAC,CAAC,IAAI,KAAK,OAAO,MAAM,CAAC,CAAC;AAAA,IAChD;AACA,WAAO,OAAO,MAAM,CAAC,CAAC,KAAK;AAAA,EAC7B;AAEA,8BAAU,MAAM;AACd,QAAI,CAAC,kBAAmB;AAExB,QAAI,YAAY;AAChB,UAAM,iBAAiB,EACpB,KAAK,CAAC,aAAa,SAAS,KAAK,CAAC,EAClC,KAAK,CAAC,SAAS;AACd,UAAI,CAAC,UAAW;AAChB,YAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,YAAM,OAAuB,CAAC;AAC9B,UAAI,aAAoC,CAAC;AAEzC,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;AACxC,cAAM,OAAO,MAAM,CAAC,EAAE,KAAK;AAC3B,YAAI,KAAK,SAAS,KAAK,GAAG;AACxB,gBAAM,QAAQ,KAAK,MAAM,KAAK;AAC9B,qBAAW,YAAY,aAAa,MAAM,CAAC,EAAE,KAAK,CAAC;AACnD,qBAAW,UAAU,aAAa,MAAM,CAAC,EAAE,KAAK,CAAC;AAAA,QACnD,WAAW,KAAK,SAAS,QAAQ,GAAG;AAClC,gBAAM,CAAC,KAAK,MAAM,IAAI,KAAK,MAAM,QAAQ;AACzC,gBAAM,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI,MAAM;AAEjD,cAAI;AACF,uBAAW,MAAM,IAAI,IAAI,KAAK,IAAI,IAAI,mBAAmB,OAAO,SAAS,IAAI,CAAC,EAAE;AAAA,UAClF,QAAQ;AACN,uBAAW,MAAM;AAAA,UACnB;AAEA,qBAAW,IAAI;AACf,qBAAW,IAAI;AACf,qBAAW,IAAI;AACf,qBAAW,IAAI;AACf,eAAK,KAAK,UAA0B;AACpC,uBAAa,CAAC;AAAA,QAChB;AAAA,MACF;AACA,oBAAc,IAAI;AAAA,IACpB,CAAC,EACA,MAAM,QAAQ,KAAK;AAEtB,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,iBAAiB,CAAC;AAEtB,QAAM,iBAAiB,CAAC,SAAiB;AACvC,QAAI,CAAC,OAAO,SAAS,IAAI,EAAG,QAAO;AACnC,UAAM,UAAU,KAAK,MAAM,OAAO,EAAE;AACpC,UAAM,UAAU,KAAK,MAAM,OAAO,EAAE,IAAI;AACxC,UAAM,QAAQ,KAAK,MAAM,OAAO,IAAI;AAEpC,UAAM,uBAAuB,IAAI,KAAK,aAAa,QAAW;AAAA,MAC5D,sBAAsB;AAAA,IACxB,CAAC;AAED,QAAI,UAAU,GAAG;AACf,aAAO,GAAG,OAAO,IAAI,qBAAqB,OAAO,OAAO,CAAC;AAAA,IAC3D;AACA,WAAO,GAAG,KAAK,IAAI,qBAAqB,OAAO,OAAO,CAAC,IAAI,qBAAqB,OAAO,OAAO,CAAC;AAAA,EACjG;AAEA,QAAM,gBAAgB,MAAM;AAC1B,QAAI,UAAU,QAAS,cAAa,UAAU,OAAO;AACrD,sBAAkB,KAAK;AAEvB,QAAI,SAAS,SAAS,UAAU,YAAa;AAE7C,cAAU,UAAU,WAAW,MAAM;AACnC,UAAI,CAAC,SAAS,SAAS,UAAU,CAAC,aAAa;AAC7C,0BAAkB,IAAI;AAAA,MACxB;AAAA,IACF,GAAG,IAAI;AAAA,EACT;AAEA,8BAAU,MAAM;AACd,UAAM,SAAS,CAAC,eAAe,eAAe,WAAW,YAAY;AACrE,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,UAAW;AAEhB,UAAM,UAAU,MAAM,cAAc;AACpC,WAAO,QAAQ,CAAC,cAAc,UAAU,iBAAiB,WAAW,OAAO,CAAC;AAE5E,UAAM,cAAc,MAAM;AACxB,UAAI,CAAC,SAAS,SAAS,UAAU,CAAC,aAAa;AAC7C,0BAAkB,IAAI;AAAA,MACxB;AAAA,IACF;AACA,cAAU,iBAAiB,gBAAgB,WAAW;AAEtD,WAAO,MAAM;AACX,aAAO,QAAQ,CAAC,cAAc,UAAU,oBAAoB,WAAW,OAAO,CAAC;AAC/E,gBAAU,oBAAoB,gBAAgB,WAAW;AACzD,UAAI,UAAU,QAAS,cAAa,UAAU,OAAO;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,8BAAU,MAAM;AACd,UAAM,yBAAyB,MAAM;AACnC,sBAAgB,SAAS,sBAAsB,aAAa,OAAO;AAAA,IACrE;AACA,aAAS,iBAAiB,oBAAoB,sBAAsB;AACpE,WAAO,MAAM,SAAS,oBAAoB,oBAAoB,sBAAsB;AAAA,EACtF,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,UAAM,qBAAqB,CAAC,UAAwB;AAClD,UAAI,CAAC,gBAAgB,CAAC,YAAY,QAAS;AAC3C,UAAI,CAAC,YAAY,QAAQ,SAAS,MAAM,MAAc,GAAG;AACvD,wBAAgB,KAAK;AACrB,wBAAgB,MAAM;AAAA,MACxB;AAAA,IACF;AACA,aAAS,iBAAiB,eAAe,kBAAkB;AAC3D,WAAO,MAAM,SAAS,oBAAoB,eAAe,kBAAkB;AAAA,EAC7E,GAAG,CAAC,YAAY,CAAC;AAEjB,8BAAU,MAAM;AACd,UAAM,QAAQ,SAAS;AACvB,UAAM,YACJ,OAAO,aAAa,eACpB,6BAA6B,YAC7B,SAAS,2BACT,CAAC,CAAC,SACF,OAAQ,MACL,4BAA4B;AAEjC,oBAAgB,QAAQ,SAAS,CAAC;AAAA,EACpC,GAAG,CAAC,GAAG,CAAC;AAER,8BAAU,MAAM;AACd,UAAM,gBAAgB,CAAC,UAAyB;AAC9C,YAAM,UAAU,SAAS,eAAe,SAAS,YAAY;AAC7D,UAAI,YAAY,QAAS;AAEzB,cAAQ,MAAM,IAAI,YAAY,GAAG;AAAA,QAC/B,KAAK;AAAA,QACL,KAAK;AACH,cAAI,YAAY,SAAU;AAC1B,gBAAM,eAAe;AACrB,qBAAW;AACX;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,2BAAiB;AACjB;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,yBAAe,CAAC,SAAS,CAAC,IAAI;AAC9B;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,qBAAW;AACX;AAAA,QACF,KAAK;AAAA,QACL,KAAK;AACH,gBAAM,eAAe;AACrB,iBAAO,EAAE;AACT;AAAA,QACF,KAAK;AAAA,QACL,KAAK;AACH,gBAAM,eAAe;AACrB,iBAAO,CAAC;AACR;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,yBAAe;AACf;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,eAAK,uBAAuB;AAC5B;AAAA,QACF;AACE;AAAA,MACJ;AAAA,IACF;AACA,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,aAAa,YAAY,CAAC;AAE9B,QAAM,aAAa,MAAM;AACvB,QAAI,SAAS,SAAS,QAAQ;AAC5B,eAAS,QAAQ,KAAK,EAAE,MAAM,QAAQ,KAAK;AAAA,IAC7C,OAAO;AACL,eAAS,SAAS,MAAM;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,aAAa,MAAM;AACvB,QAAI,SAAS,SAAS;AACpB,eAAS,QAAQ,QAAQ,CAAC,SAAS,QAAQ;AAC3C,iBAAW,SAAS,QAAQ,KAAK;AACjC,UAAI,SAAS,QAAQ,OAAO;AAC1B,kBAAU,CAAC;AAAA,MACb,OAAO;AACL,kBAAU,SAAS,QAAQ,UAAU,CAAC;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,qBAAqB,CAAC,UAA+C;AACzE,UAAM,MAAM,OAAO,MAAM,OAAO,KAAK;AACrC,cAAU,GAAG;AACb,QAAI,SAAS,SAAS;AACpB,eAAS,QAAQ,SAAS;AAC1B,eAAS,QAAQ,QAAQ,QAAQ;AACjC,iBAAW,QAAQ,CAAC;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,mBAAmB,YAAY;AACnC,QAAI,CAAC,SAAS,mBAAmB;AAC/B,YAAM,aAAa,SAAS,kBAAkB;AAAA,IAChD,OAAO;AACL,YAAM,SAAS,eAAe;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,SAAS,CAAC,YAAoB;AAClC,QAAI,SAAS,SAAS;AACpB,YAAM,WAAW,KAAK;AAAA,QACpB,KAAK,IAAI,SAAS,QAAQ,cAAc,SAAS,CAAC;AAAA,QAClD,SAAS,QAAQ,YAAY;AAAA,MAC/B;AACA,eAAS,QAAQ,cAAc;AAC/B,qBAAe,QAAQ;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,iBAAiB,MAAM;AAC3B,UAAM,QAAQ,SAAS;AACvB,QAAI,SAAS,MAAM,WAAW,CAAC,GAAG;AAChC,YAAM,UAAU,MAAM,WAAW,CAAC,EAAE,SAAS;AAC7C,YAAM,WAAW,CAAC,EAAE,OAAO,UAAU,WAAW;AAChD,yBAAmB,CAAC,OAAO;AAAA,IAC7B;AAAA,EACF;AAEA,QAAM,qBAAqB,CAAC,SAAiB;AAC3C,QAAI,CAAC,SAAS,QAAS;AACvB,aAAS,QAAQ,eAAe;AAChC,oBAAgB,IAAI;AACpB,oBAAgB,KAAK;AACrB,oBAAgB,MAAM;AAAA,EACxB;AAEA,QAAM,gBAAgB,CAAC,UAA2B;AAChD,sBAAkB,KAAK;AACvB,oBAAgB,KAAK;AACrB,oBAAgB,MAAM;AAEtB,QAAI,OAAO,SAAS;AAClB,UAAI,UAAU,QAAQ;AACpB,eAAO,QAAQ,eAAe;AAAA,MAChC,OAAO;AACL,eAAO,QAAQ,eAAe;AAAA,MAChC;AAAA,IACF,WAAW,QAAQ,SAAS;AAC1B,UAAI,UAAU,QAAQ;AACpB,gBAAQ,QAAQ,eAAe;AAAA,UAC7B,WAAW,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,KAAK,EAAE,EAAE;AAAA,QAC3D,CAAC;AAAA,MACH,OAAO;AACL,gBAAQ,QAAQ,eAAe;AAAA,UAC7B,WAAW,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,MAAM,EAAE,EAAE;AAAA,QAC5D,CAAC;AACD,gBAAQ,QAAQ,gCAAgC,SAAS,OAAO,IAAI;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,yBAAyB,YAAY;AACzC,QAAI;AACF,UAAI,SAAS,yBAAyB;AACpC,cAAM,SAAS,qBAAqB;AACpC;AAAA,MACF;AAEA,YAAM,QAAQ,SAAS;AAIvB,UAAI,CAAC,SAAS,OAAO,MAAM,4BAA4B,YAAY;AACjE;AAAA,MACF;AAEA,YAAM,MAAM,wBAAwB;AAAA,IACtC,SAAS,OAAO;AACd,cAAQ,MAAM,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,kBAAkB,MAAM;AAC5B,QAAI,mBAAmB,QAAQ;AAC7B,aAAO;AAAA,IACT;AAEA,WAAO,GAAG,UAAU,KAAK,CAAC,YAAY,QAAQ,UAAU,cAAc,GAAG,UAAU,cAAc;AAAA,EACnG;AAEA,QAAM,kBAAkB,CAAC,QAAkB,mBAA2B;AACpE,QAAI,OAAO,SAAS,GAAG;AACrB,aAAO,4CAAC,SAAI,WAAU,8BAA6B;AAAA,IACrD;AAEA,UAAM,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC;AACjC,UAAM,SAAS,OACZ,IAAI,CAAC,OAAO,UAAU;AACrB,YAAM,IAAK,SAAS,OAAO,SAAS,KAAM;AAC1C,YAAM,IAAI,MAAO,QAAQ,MAAO;AAChC,aAAO,GAAG,CAAC,IAAI,CAAC;AAAA,IAClB,CAAC,EACA,KAAK,GAAG;AAEX,WACE,4CAAC,SAAI,WAAU,kCACb,sDAAC,SAAI,SAAQ,eAAc,qBAAoB,QAAO,WAAU,iBAC9D;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,QAAO;AAAA,QACP,aAAY;AAAA,QACZ;AAAA,QACA,WAAW;AAAA;AAAA,IACb,GACF,GACF;AAAA,EAEJ;AAEA,8BAAU,MAAM;AACd,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,MAAO;AAEZ,UAAM,gBAAgB,CAAC,YAA4B;AACjD,UAAI,CAAC,WAAW,CAAC,OAAO,SAAS,OAAO,KAAK,WAAW,GAAG;AACzD,eAAO;AAAA,MACT;AAEA,aAAO,WAAW,MACd,IAAI,UAAU,KAAW,QAAQ,CAAC,CAAC,UACnC,GAAG,KAAK,MAAM,UAAU,GAAI,CAAC;AAAA,IACnC;AAEA,UAAM,cAAc,MAAM;AACxB,YAAM,iBAAiB,MAAM;AAC3B,iBAAS,IAAI,GAAG,IAAI,MAAM,SAAS,QAAQ,KAAK,GAAG;AACjD,gBAAM,QAAQ,MAAM,SAAS,MAAM,CAAC;AACpC,gBAAM,MAAM,MAAM,SAAS,IAAI,CAAC;AAChC,cAAI,MAAM,eAAe,SAAS,MAAM,eAAe,KAAK;AAC1D,mBAAO,KAAK,IAAI,MAAM,MAAM,aAAa,CAAC;AAAA,UAC5C;AAAA,QACF;AACA,eAAO;AAAA,MACT,GAAG;AAEH,YAAM,kBACJ,OAAO,MAAM,4BAA4B,aACrC,MAAM,wBAAwB,IAC9B;AAEN,UAAI,SAAS;AACb,UAAI,UAAU;AACd,UAAI,UAAU,gBAAgB;AAC9B,UAAI,QAAQ;AACZ,UAAI,WAAW,MAAM,WAAW,SAAS,MAAM,IAC3C,yBACA,MAAM,WAAW,SAAS,OAAO,IAC/B,kCACA;AACN,UAAI,QAAQ;AACZ,UAAI,eAAe;AAEnB,UAAI,OAAO,SAAS;AAClB,iBAAS;AACT,cAAM,MAAM,OAAO;AACnB,cAAM,aACJ,IAAI,gBAAgB,IAChB,IAAI,eACJ,IAAI,aAAa,IACf,IAAI,YACJ,IAAI,iBAAiB,IACnB,IAAI,gBACJ;AACV,cAAM,QAAQ,cAAc,IAAI,IAAI,OAAO,UAAU,IAAI;AACzD,uBAAe,OAAO,WAAW;AACjC,kBAAU,cAAc,YAAY;AACpC,kBAAU,OAAO,SAAS,GAAG,MAAM,MAAM,MAAM,gBAAgB;AAC/D,gBACE,OAAO,YACP,CAAC,OAAO,YAAY,OAAO,UAAU,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK,KACjE;AACF,mBAAW;AACX,gBAAQ,OAAO,cAAc;AAAA,MAC/B,WAAW,QAAQ,SAAS;AAC1B,iBAAS;AACT,cAAM,iBAAiB,QAAQ,QAAQ,kCAAkC,OAAO;AAChF,cAAM,aAAa,QAAQ,QAAQ,qBAAqB,OAAO;AAC/D,cAAM,aAAa,QAAQ,QAAQ,2BAA2B,OAAO;AACrE,uBAAe,gBAAgB,aAAa,cAAc;AAC1D,kBAAU,cAAc,YAAY;AACpC,kBAAU,gBAAgB,SAAS,GAAG,eAAe,MAAM,MAAM,gBAAgB;AACjF,gBAAQ,gBAAgB,UAAU,YAAY,SAAS;AACvD,mBAAW,gBAAgB,YAAY,YAAY,YAAY;AAC/D,gBAAQ,CAAC,YAAY,OAAO,YAAY,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK,KAAK;AAAA,MAC/E;AAEA,wBAAkB,CAAC,aAAa,CAAC,GAAG,SAAS,MAAM,GAAG,GAAG,eAAe,GAAS,CAAC;AAClF,uBAAiB,CAAC,aAAa,CAAC,GAAG,SAAS,MAAM,GAAG,GAAG,aAAa,CAAC;AAEtE,uBAAiB;AAAA,QACf;AAAA,QACA,YACE,MAAM,cAAc,MAAM,cAAc,GAAG,MAAM,UAAU,IAAI,MAAM,WAAW,KAAK;AAAA,QACvF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,cAAc,GAAG,cAAc,QAAQ,CAAC,CAAC;AAAA,QACzC,eAAe,OAAO,iBAAiB,sBAAsB,CAAC;AAAA,QAC9D,KACE,MAAM,cAAc,KAAK,iBAAiB,mBACtC,GAAG,KAAK;AAAA,YACJ,gBAAgB,oBAAoB,MAAM,gBAAgB,sBAAsB,MAChF,KAAK,IAAI,MAAM,aAAa,CAAC;AAAA,QACjC,CAAC,KACD;AAAA,QACN,cAAc,GAAG,MAAM,YAAY;AAAA,QACnC,OAAO,MAAM,SAAS,WAAW,MAAM,aAAa,IAAI,cAAc;AAAA,MACxE,CAAC;AAAA,IACH;AAEA,gBAAY;AACZ,UAAM,aAAa,OAAO,YAAY,aAAa,GAAG;AACtD,WAAO,MAAM,OAAO,cAAc,UAAU;AAAA,EAC9C,GAAG,CAAC,KAAK,cAAc,gBAAgB,SAAS,CAAC;AAEjD,QAAM,cAAc,QAAQ,WAAW;AACvC,QAAM,oBAAoB,UAAU,SAAS;AAE7C,QAAM,qBAAqB,CAAC,YAAoB;AAC9C,UAAM,OAAO,YAAY,SAAS,sBAAsB;AACxD,QAAI,CAAC,QAAQ,KAAK,UAAU,EAAG,QAAO;AACtC,UAAM,cAAc,UAAU,KAAK;AACnC,WAAO,KAAK,IAAI,KAAK,IAAI,cAAc,KAAK,OAAO,CAAC,GAAG,CAAC;AAAA,EAC1D;AAEA,QAAM,sBAAsB,CAAC,SAAiB;AAC5C,QAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,WACE,WAAW,KAAK,CAAC,cAAc,QAAQ,UAAU,aAAa,QAAQ,UAAU,OAAO,KACvF;AAAA,EAEJ;AAEA,QAAM,wBAAwB,CAAC,UAA6C;AAC1E,UAAM,UAAU,mBAAmB,MAAM,OAAO;AAChD,UAAM,OAAO,UAAU;AAEvB,uBAAmB,OAAO;AAC1B,mBAAe,IAAI;AAEnB,QAAI,WAAW,GAAG;AAChB,YAAM,YAAY,oBAAoB,IAAI;AAC1C,UAAI,WAAW;AACb,2BAAmB,SAAS;AAAA,MAC9B,WAAW,eAAe,oBAAoB,SAAS;AACrD,2BAAmB,oBAAoB,OAAO;AAAA,MAChD,WAAW,CAAC,aAAa;AACvB,2BAAmB,IAAI;AAAA,MACzB;AAAA,IACF;AAEA,QAAI,aAAa;AACf,YAAM,eAAe;AACrB,0BAAoB,OAAO;AAAA,IAC7B;AAAA,EACF;AAEA,QAAM,iBAAiB,CAAC,UAA8B;AACpD,QAAI,MAAM,gBAAgB,WAAW,MAAM,WAAW,EAAG;AACzD,0BAAsB,UAAU,CAAC,SAAS,SAAS;AACnD,wBAAoB,UAAU,oBAAoB,SAAS,SAAS,eAAe,CAAC;AACpF,mBAAe,IAAI;AACnB,aAAS,SAAS,MAAM;AACxB,0BAAsB,KAAK;AAAA,EAC7B;AAEA,QAAM,eAAe,CAAC,UAAwB;AAC5C,QAAI,CAAC,YAAa;AAClB,mBAAe,KAAK;AACpB,UAAM,UAAU,mBAAmB,MAAM,OAAO;AAChD,QAAI,SAAS,SAAS;AACpB,YAAM,WAAW,WAAW,SAAS,QAAQ,YAAY;AACzD,eAAS,QAAQ,cAAc;AAC/B,qBAAe,QAAQ;AACvB,qBAAe,QAAQ;AACvB,UAAI,sBAAsB,SAAS;AACjC,iBAAS,QAAQ,KAAK,EAAE,MAAM,QAAQ,KAAK;AAAA,MAC7C;AAAA,IACF;AACA,wBAAoB,UAAU;AAAA,EAChC;AAEA,8BAAU,MAAM;AACd,QAAI,aAAa;AACf,YAAM,gBAAgB,CAAC,UAAwB,sBAAsB,KAAK;AAC1E,eAAS,iBAAiB,eAAe,aAAa;AACtD,eAAS,iBAAiB,aAAa,YAAY;AACnD,aAAO,MAAM;AACX,iBAAS,oBAAoB,eAAe,aAAa;AACzD,iBAAS,oBAAoB,aAAa,YAAY;AAAA,MACxD;AAAA,IACF;AACA,WAAO;AAAA,EACT,GAAG,CAAC,aAAa,UAAU,UAAU,CAAC;AAEtC,QAAM,aAAa,MAAM;AACvB,QAAI,WAAW,WAAW,EAAG,QAAO,4CAAC,+BAAQ,MAAM,IAAI,WAAU,gBAAe;AAChF,QAAI,SAAS,IAAK,QAAO,4CAAC,+BAAQ,MAAM,IAAI,WAAU,gBAAe;AACrE,WAAO,4CAAC,+BAAQ,MAAM,IAAI,WAAU,gBAAe;AAAA,EACrD;AAEA,SACE,6CAAC,UAAK,WAAU,oDACd;AAAA,iDAAC,aAAQ,WAAU,QAChB;AAAA,gBACC,4CAAC,OAAE,WAAU,4EACV,mBACH,IACE;AAAA,MACJ,4CAAC,QAAG,WAAU,sEAAsE,iBAAM;AAAA,MACzF,cACC,4CAAC,OAAE,WAAU,8DAA8D,uBAAY,IACrF;AAAA,MACH,OAAO,SAAS,IACf,4CAAC,QAAG,WAAU,2CACX,iBAAO,IAAI,CAAC,UACX;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAET;AAAA;AAAA,QAHI;AAAA,MAIP,CACD,GACH,IACE;AAAA,OACN;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,oHACT,YACI,uFACA,4BACN;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,WAAW,6FACT,YAAY,wCAAwC,EACtD,IAAI,eAAe,wBAAwB,EAAE,IAAI,iBAAiB,kBAAkB,EAAE;AAAA,YAErF;AAAA,kCACC,6CAAC,SAAI,WAAU,oKACb;AAAA,4DAAC,SAAI,WAAU,2EAA0E,6BAEzF;AAAA,gBACA,6CAAC,SAAI,WAAU,eACb;AAAA,+DAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,oBAAM;AAAA,oBAClC,6CAAC,SAAI,WAAU,oBACb;AAAA,kEAAC,UAAM,wBAAc,cAAa;AAAA,sBAClC,4CAAC,SAAI,WAAU,eAAe,0BAAgB,eAAe,eAAe,GAAE;AAAA,uBAChF;AAAA,qBACF;AAAA,kBACA,6CAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,qBAAO;AAAA,oBACnC,6CAAC,SAAI,WAAU,oBACb;AAAA,kEAAC,UAAM,wBAAc,SAAQ;AAAA,sBAC7B,4CAAC,SAAI,WAAU,eAAe,0BAAgB,gBAAgB,qBAAqB,GAAE;AAAA,uBACvF;AAAA,qBACF;AAAA,kBACA,6CAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,qBAAO;AAAA,oBACnC,4CAAC,UAAK,WAAU,oBAAoB,wBAAc,SAAQ;AAAA,qBAC5D;AAAA,kBACA,6CAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,oBAAM;AAAA,oBAClC,4CAAC,UAAK,WAAU,oBAAoB,wBAAc,OAAM;AAAA,qBAC1D;AAAA,kBACA,6CAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,mBAAK;AAAA,oBACjC,4CAAC,UAAK,WAAU,oBAAoB,wBAAc,OAAM;AAAA,qBAC1D;AAAA,kBACA,6CAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,sBAAQ;AAAA,oBACpC,4CAAC,UAAK,WAAU,oBAAoB,wBAAc,YAAW;AAAA,qBAC/D;AAAA,kBACA,6CAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,kBAAI;AAAA,oBAChC,4CAAC,UAAK,WAAU,oBAAoB,wBAAc,UAAS;AAAA,qBAC7D;AAAA,kBACA,6CAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,oBAAM;AAAA,oBAClC,6CAAC,UAAK,WAAU,oBACb;AAAA,oCAAc;AAAA,sBAAI;AAAA,sBAAQ,cAAc;AAAA,sBAAc;AAAA,uBACzD;AAAA,qBACF;AAAA,kBACA,6CAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,mBAAK;AAAA,oBACjC,6CAAC,UAAK,WAAU,oBACb;AAAA,oCAAc;AAAA,sBAAM;AAAA,sBAAI,cAAc;AAAA,uBACzC;AAAA,qBACF;AAAA,kBACA,6CAAC,SAAI,WAAU,aACb;AAAA,gEAAC,UAAK,WAAU,aAAY,oBAAM;AAAA,oBAClC,4CAAC,UAAK,WAAU,oBAAoB,wBAAc,QAAO;AAAA,qBAC3D;AAAA,mBACF;AAAA,iBACF,IACE;AAAA,cAEJ;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS;AAAA,kBACT,cAAW;AAAA,kBACX,WAAW,kOAAkO,YAAY,2CAA2C,uBAAuB;AAAA,kBAE3T,sDAAC,4BAAK,MAAM,IAAI,WAAU,qBAAoB,MAAK,gBAAe;AAAA;AAAA,cACpE;AAAA,cAEA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW,gLAAgL,kBAAkB,YAAY,4DAA4D,2BAA2B;AAAA,kBAEhT;AAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,KAAK;AAAA,wBACL,WAAU;AAAA,wBACV,eAAe;AAAA,wBACf,eAAe,CAAC,UAAU;AACxB,8BAAI,CAAC,YAAa,uBAAsB,KAAK;AAAA,wBAC/C;AAAA,wBACA,gBAAgB,MAAM,sBAAsB,IAAI;AAAA,wBAChD,gBAAgB,MAAM,sBAAsB,KAAK;AAAA,wBAEjD,uDAAC,SAAI,WAAU,+FACb;AAAA;AAAA,4BAAC;AAAA;AAAA,8BACC,WAAU;AAAA,8BACV,OAAO;AAAA,gCACL,OAAO,GAAG,kBAAkB,GAAG;AAAA,gCAC/B,SAAS,sBAAsB,cAAc,UAAU;AAAA,8BACzD;AAAA;AAAA,0BACF;AAAA,0BACA;AAAA,4BAAC;AAAA;AAAA,8BACC,WAAU;AAAA,8BACV,OAAO;AAAA,gCACL,OAAO,IAAI,cAAc,mBAAmB,WAAW,cAAc,WAAW,KAAK,GAAG;AAAA,8BAC1F;AAAA;AAAA,0BACF;AAAA,0BACA;AAAA,4BAAC;AAAA;AAAA,8BACC,WAAU;AAAA,8BACV,OAAO;AAAA,gCACL,MAAM,IAAI,cAAc,mBAAmB,WAAW,cAAc,WAAW,KAAK,GAAG;AAAA,gCACvF,WAAW,+BAA+B,sBAAsB,cAAc,IAAI,CAAC;AAAA,8BACrF;AAAA;AAAA,0BACF;AAAA,0BAEC,kBACC;AAAA,4BAAC;AAAA;AAAA,8BACC,WAAW,8JAA8J,eAAe,qBAAqB,gBAAgB,WAAW;AAAA,8BACxO,OAAO,EAAE,MAAM,GAAG,kBAAkB,GAAG,KAAK,OAAO,SAAS,QAAQ,QAAQ;AAAA,8BAE5E;AAAA;AAAA,kCAAC;AAAA;AAAA,oCACC,OAAO;AAAA,sCACL,iBAAiB,OAAO,gBAAgB,GAAG;AAAA,sCAC3C,oBAAoB,IAAI,gBAAgB,CAAC,OAAO,gBAAgB,CAAC;AAAA,sCACjE,OAAO,GAAG,gBAAgB,CAAC;AAAA,sCAC3B,QAAQ,GAAG,gBAAgB,CAAC;AAAA,sCAC5B,WAAW,SAAS,MAAM,gBAAgB,CAAC;AAAA,sCAC3C,iBAAiB;AAAA,oCACnB;AAAA;AAAA,gCACF;AAAA,gCACA,4CAAC,SAAI,WAAU,wFACZ,yBAAe,WAAW,GAC7B;AAAA;AAAA;AAAA,0BACF,IACE,eAAe,qBACjB;AAAA,4BAAC;AAAA;AAAA,8BACC,WAAU;AAAA,8BACV,OAAO,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;AAAA,8BAE1C,yBAAe,WAAW;AAAA;AAAA,0BAC7B,IACE;AAAA,2BACN;AAAA;AAAA,oBACF;AAAA,oBAEA,6CAAC,SAAI,WAAU,qDACb;AAAA,mEAAC,SAAI,WAAU,4CACb;AAAA;AAAA,0BAAC;AAAA;AAAA,4BACC,SAAS;AAAA,4BACT,WAAU;AAAA,4BAET,sBACC,4CAAC,6BAAM,MAAM,IAAI,MAAK,gBAAe,WAAU,gBAAe,IAE9D,4CAAC,4BAAK,MAAM,IAAI,MAAK,gBAAe,WAAU,gBAAe;AAAA;AAAA,wBAEjE;AAAA,wBAEA,6CAAC,SAAI,WAAU,4CACb;AAAA;AAAA,4BAAC;AAAA;AAAA,8BACC,SAAS;AAAA,8BACT,WAAU;AAAA,8BAEV,sDAAC,cAAW;AAAA;AAAA,0BACd;AAAA,0BACA;AAAA,4BAAC;AAAA;AAAA,8BACC,MAAK;AAAA,8BACL,KAAI;AAAA,8BACJ,KAAI;AAAA,8BACJ,MAAK;AAAA,8BACL,OAAO;AAAA,8BACP,UAAU;AAAA,8BACV,WAAU;AAAA,8BACV,OAAO,EAAE,oBAAoB,GAAG,SAAS,GAAG,IAAI;AAAA;AAAA,0BAClD;AAAA,2BACF;AAAA,wBAEA,6CAAC,SAAI,WAAU,sGACb;AAAA,sEAAC,UAAM,yBAAe,WAAW,GAAE;AAAA,0BACnC,4CAAC,UAAK,WAAU,iBAAgB,eAAC;AAAA,0BACjC,4CAAC,UAAM,yBAAe,QAAQ,GAAE;AAAA,2BAClC;AAAA,yBACF;AAAA,sBAEA,6CAAC,SAAI,WAAU,oCACb;AAAA;AAAA,0BAAC;AAAA;AAAA,4BACC,SAAS;AAAA,4BACT,UAAU,CAAC;AAAA,4BACX,WAAW,kIAAkI,kBAAkB,wBAAwB,EAAE;AAAA,4BACzL,OAAM;AAAA,4BAEN,sDAAC,gCAAS,MAAM,IAAI,WAAU,gBAAe;AAAA;AAAA,wBAC/C;AAAA,wBAEA,6CAAC,SAAI,KAAK,aAAa,WAAU,YAC/B;AAAA;AAAA,4BAAC;AAAA;AAAA,8BACC,SAAS,MAAM;AACb,gDAAgB,CAAC,SAAS,CAAC,IAAI;AAC/B,gDAAgB,MAAM;AAAA,8BACxB;AAAA,8BACA,WAAW,kFAAkF,eAAe,oCAAoC,EAAE;AAAA,8BAClJ,OAAM;AAAA,8BAEN;AAAA,gCAAC;AAAA;AAAA,kCACC,MAAM;AAAA,kCACN,WAAW,gBAAgB,eAAe,6BAA6B,EAAE;AAAA;AAAA,8BAC3E;AAAA;AAAA,0BACF;AAAA,0BAEC,eACC;AAAA,4BAAC;AAAA;AAAA,8BACC,WAAW,wJACT,iBAAiB,SAAS,wBAAwB,sCACpD;AAAA,8BAEA;AAAA,gCAAC;AAAA;AAAA,kCACC,WAAU;AAAA,kCACV,OAAO;AAAA,oCACL,OAAO;AAAA,oCACP,WAAW,cACT,iBAAiB,SACb,OACA,iBAAiB,YACf,cACA,WACR;AAAA,kCACF;AAAA,kCAEA;AAAA,iFAAC,SAAI,WAAU,iCACb;AAAA;AAAA,wCAAC;AAAA;AAAA,0CACC,SAAS,MAAM,gBAAgB,SAAS;AAAA,0CACxC,UAAU,CAAC;AAAA,0CACX,WAAU;AAAA,0CAEV;AAAA,yFAAC,SACC;AAAA,0FAAC,SAAI,WAAU,kBAAiB,qBAAO;AAAA,8CACvC,4CAAC,SAAI,WAAU,kBACZ,8BAAoB,gBAAgB,IAAI,eAC3C;AAAA,+CACF;AAAA,4CACA,4CAAC,oCAAa,MAAM,IAAI,WAAU,iBAAgB;AAAA;AAAA;AAAA,sCACpD;AAAA,sCAEA;AAAA,wCAAC;AAAA;AAAA,0CACC,SAAS,MAAM,gBAAgB,OAAO;AAAA,0CACtC,WAAU;AAAA,0CAEV;AAAA,yFAAC,SACC;AAAA,0FAAC,SAAI,WAAU,kBAAiB,4BAAc;AAAA,8CAC9C,6CAAC,SAAI,WAAU,kBAAkB;AAAA;AAAA,gDAAa;AAAA,iDAAC;AAAA,+CACjD;AAAA,4CACA,4CAAC,oCAAa,MAAM,IAAI,WAAU,iBAAgB;AAAA;AAAA;AAAA,sCACpD;AAAA,sCAEA;AAAA,wCAAC;AAAA;AAAA,0CACC,SAAS,MAAM;AACb,iEAAqB,CAAC,SAAS,CAAC,IAAI;AACpC,4DAAgB,KAAK;AACrB,4DAAgB,MAAM;AAAA,0CACxB;AAAA,0CACA,WAAU;AAAA,0CAEV;AAAA,yFAAC,SACC;AAAA,0FAAC,SAAI,WAAU,kBAAiB,6BAAe;AAAA,8CAC/C,4CAAC,SAAI,WAAU,kBACZ,8BAAoB,OAAO,OAC9B;AAAA,+CACF;AAAA,4CACA;AAAA,8CAAC;AAAA;AAAA,gDACC,WAAW,wBACT,oBAAoB,sBAAsB,aAC5C;AAAA;AAAA,4CACF;AAAA;AAAA;AAAA,sCACF;AAAA,uCACF;AAAA,oCAEA,6CAAC,SAAI,WAAU,0DACb;AAAA;AAAA,wCAAC;AAAA;AAAA,0CACC,SAAS,MAAM,gBAAgB,MAAM;AAAA,0CACrC,WAAU;AAAA,0CAEV;AAAA,wFAAC,mCAAY,MAAM,IAAI;AAAA,4CACvB,4CAAC,UAAK,qBAAO;AAAA;AAAA;AAAA,sCACf;AAAA,sCACA;AAAA,wCAAC;AAAA;AAAA,0CACC,SAAS,MAAM,cAAc,MAAM;AAAA,0CACnC,WAAW,mBAAmB,mBAAmB,SAAS,2BAA2B,EAAE;AAAA,0CAEvF;AAAA,wFAAC,UAAK,kBAAI;AAAA,4CACT,mBAAmB,SAClB,4CAAC,UAAK,WAAU,8CAA6C,IAC3D;AAAA;AAAA;AAAA,sCACN;AAAA,sCACC,UAAU,SAAS,IAClB,UAAU,IAAI,CAAC,YACb;AAAA,wCAAC;AAAA;AAAA,0CAEC,SAAS,MAAM,cAAc,QAAQ,KAAK;AAAA,0CAC1C,WAAW,mBAAmB,mBAAmB,QAAQ,QAAQ,2BAA2B,EAAE;AAAA,0CAE9F;AAAA,yFAAC,UAAM;AAAA,sDAAQ;AAAA,8CAAO;AAAA,+CAAC;AAAA,4CACtB,mBAAmB,QAAQ,QAC1B,4CAAC,UAAK,WAAU,8CAA6C,IAC3D;AAAA;AAAA;AAAA,wCAPC,QAAQ;AAAA,sCAQf,CACD,IAED,4CAAC,SAAI,WAAU,uCAAsC,gCAAkB;AAAA,uCAE3E;AAAA,oCAEA,6CAAC,SAAI,WAAU,0DACb;AAAA;AAAA,wCAAC;AAAA;AAAA,0CACC,SAAS,MAAM,gBAAgB,MAAM;AAAA,0CACrC,WAAU;AAAA,0CAEV;AAAA,wFAAC,mCAAY,MAAM,IAAI;AAAA,4CACvB,4CAAC,UAAK,4BAAc;AAAA;AAAA;AAAA,sCACtB;AAAA,sCACC,eAAe,IAAI,CAAC,SACnB;AAAA,wCAAC;AAAA;AAAA,0CAEC,SAAS,MAAM,mBAAmB,IAAI;AAAA,0CACtC,WAAW,mBAAmB,iBAAiB,OAAO,2BAA2B,EAAE;AAAA,0CAEnF;AAAA,yFAAC,UAAM;AAAA;AAAA,8CAAK;AAAA,+CAAC;AAAA,4CACZ,iBAAiB,OAChB,4CAAC,UAAK,WAAU,8CAA6C,IAC3D;AAAA;AAAA;AAAA,wCAPC;AAAA,sCAQP,CACD;AAAA,uCACH;AAAA;AAAA;AAAA,8BACF;AAAA;AAAA,0BACF,IACE;AAAA,2BACN;AAAA,wBAEA;AAAA,0BAAC;AAAA;AAAA,4BACC,SAAS;AAAA,4BACT,UAAU,CAAC;AAAA,4BACX,WAAU;AAAA,4BACV,OAAO,eAAe,mBAAmB;AAAA,4BAEzC,sDAAC,wCAAiB,MAAM,IAAI,WAAU,gBAAe;AAAA;AAAA,wBACvD;AAAA,wBAEA;AAAA,0BAAC;AAAA;AAAA,4BACC,SAAS,MAAM,eAAe,CAAC,SAAS,CAAC,IAAI;AAAA,4BAC7C,WAAU;AAAA,4BACV,OAAM;AAAA,4BAEL,sBACC,4CAAC,0BAAG,MAAM,IAAI,WAAU,gBAAe,IAEvC,4CAAC,2CAAoB,MAAM,IAAI,WAAU,gBAAe;AAAA;AAAA,wBAE5D;AAAA,wBAEA;AAAA,0BAAC;AAAA;AAAA,4BACC,SAAS;AAAA,4BACT,WAAU;AAAA,4BACV,OAAM;AAAA,4BAEL,yBACC,4CAAC,gCAAS,MAAM,IAAI,WAAU,gBAAe,IAE7C,4CAAC,gCAAS,MAAM,IAAI,WAAU,gBAAe;AAAA;AAAA,wBAEjD;AAAA,yBACF;AAAA,uBACF;AAAA;AAAA;AAAA,cACF;AAAA,cAEA;AAAA,gBAAC;AAAA;AAAA,kBACC,KAAK;AAAA,kBACL,SAAQ;AAAA,kBACR,WAAU;AAAA,kBACV,SAAS;AAAA,kBACT,eAAe;AAAA,kBACf,QAAQ,MAAM;AACZ,iCAAa,IAAI;AACjB,kCAAc;AAAA,kBAChB;AAAA,kBACA,SAAS,MAAM;AACb,iCAAa,KAAK;AAClB,sCAAkB,KAAK;AAAA,kBACzB;AAAA,kBACA,cAAc,CAAC,UAAU;AACvB,0BAAM,OAAO,MAAM,cAAc;AACjC,wBAAI,SAAS,KAAK,cAAc,KAAK,CAAC,YAAa;AACnD,mCAAe,IAAI;AAAA,kBACrB;AAAA,kBACA,kBAAkB,CAAC,UAAU,YAAY,MAAM,cAAc,QAAQ;AAAA,kBACrE,kBAAkB,CAAC,UAAU;AAC3B,gCAAY,MAAM,cAAc,QAAQ;AAAA,kBAC1C;AAAA,kBACA,gBAAgB,CAAC,UAAU;AACzB,+BAAW,MAAM,cAAc,KAAK;AACpC,8BAAU,MAAM,cAAc,QAAQ,IAAI,MAAM,cAAc,MAAM;AAAA,kBACtE;AAAA,kBAEC,wBACC,4CAAC,WAAM,MAAK,YAAW,KAAK,aAAa,SAAQ,MAAK,OAAM,WAAU,SAAS,OAAO,IACpF;AAAA;AAAA,cACN;AAAA;AAAA;AAAA,QACF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":["Hls"]}
|
package/dist/index.mjs
CHANGED
|
@@ -608,7 +608,7 @@ function YouTubePlayer({
|
|
|
608
608
|
if (volume < 0.5) return /* @__PURE__ */ jsx(Volume1, { size: 18, className: "control-icon" });
|
|
609
609
|
return /* @__PURE__ */ jsx(Volume2, { size: 18, className: "control-icon" });
|
|
610
610
|
};
|
|
611
|
-
return /* @__PURE__ */ jsxs("main", { className: "w-full max-w-[1180px] mx-auto py-8 px-4", children: [
|
|
611
|
+
return /* @__PURE__ */ jsxs("main", { className: "svp-root w-full max-w-[1180px] mx-auto py-8 px-4", children: [
|
|
612
612
|
/* @__PURE__ */ jsxs("section", { className: "mb-6", children: [
|
|
613
613
|
eyebrow ? /* @__PURE__ */ jsx("p", { className: "m-0 mb-2 text-youtube-muted uppercase tracking-wider text-xs font-medium", children: eyebrow }) : null,
|
|
614
614
|
/* @__PURE__ */ jsx("h1", { className: "m-0 text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight mb-4", children: title }),
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../components/YouTubePlayer.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport {\n Captions,\n ChevronLeft,\n ChevronRight,\n Maximize,\n Minimize,\n Pause,\n PictureInPicture,\n Play,\n RectangleHorizontal,\n Settings,\n Tv,\n Volume1,\n Volume2,\n VolumeX,\n} from \"lucide-react\";\nimport Hls from \"hls.js\";\n\nexport interface PlayerProps {\n src: string;\n title: string;\n description?: string;\n eyebrow?: string;\n badges?: string[];\n captionsSrc?: string;\n thumbnailTrackSrc?: string;\n theaterMode?: boolean;\n defaultTheaterMode?: boolean;\n onTheaterModeChange?: (isTheaterMode: boolean) => void;\n}\n\ninterface ThumbnailCue {\n startTime: number;\n endTime: number;\n url: string;\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\ninterface QualityOption {\n height: number;\n index: number;\n}\n\ninterface PlaybackStats {\n source: string;\n resolution: string;\n quality: string;\n bitrate: string;\n codec: string;\n mimeType: string;\n audio: string;\n bufferHealth: string;\n droppedFrames: string;\n fps: string;\n playbackRate: string;\n state: string;\n}\n\nconst PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n\nexport default function YouTubePlayer({\n src,\n title,\n description,\n eyebrow,\n badges = [],\n captionsSrc,\n thumbnailTrackSrc,\n theaterMode,\n defaultTheaterMode = false,\n onTheaterModeChange,\n}: PlayerProps) {\n const videoRef = useRef<HTMLVideoElement>(null);\n const timelineRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const settingsRef = useRef<HTMLDivElement>(null);\n\n const [isPlaying, setIsPlaying] = useState(false);\n const [isMuted, setIsMuted] = useState(false);\n const [volume, setVolume] = useState(1);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [isScrubbing, setIsScrubbing] = useState(false);\n const [isHoveringTimeline, setIsHoveringTimeline] = useState(false);\n const [timelineProgress, setTimelineProgress] = useState(0);\n const [previewPosition, setPreviewPosition] = useState(0);\n const [previewTime, setPreviewTime] = useState(0);\n const [activeThumbnail, setActiveThumbnail] = useState<ThumbnailCue | null>(null);\n const [thumbnails, setThumbnails] = useState<ThumbnailCue[]>([]);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const [internalTheaterMode, setInternalTheaterMode] = useState(defaultTheaterMode);\n const [isUserInactive, setIsUserInactive] = useState(false);\n const [playbackRate, setPlaybackRate] = useState(1);\n const [captionsEnabled, setCaptionsEnabled] = useState(false);\n const [qualities, setQualities] = useState<QualityOption[]>([]);\n const [currentQuality, setCurrentQuality] = useState<number | \"auto\">(\"auto\");\n const [showSettings, setShowSettings] = useState(false);\n const [settingsView, setSettingsView] = useState<\"root\" | \"quality\" | \"speed\">(\"root\");\n const [showStatsForNerds, setShowStatsForNerds] = useState(false);\n const [pipSupported, setPipSupported] = useState(false);\n const [playbackStats, setPlaybackStats] = useState<PlaybackStats>({\n source: \"MP4\",\n resolution: \"0x0\",\n quality: \"Auto\",\n bitrate: \"N/A\",\n codec: \"N/A\",\n mimeType: \"video/mp4\",\n audio: \"N/A\",\n bufferHealth: \"0.0s\",\n droppedFrames: \"0\",\n fps: \"N/A\",\n playbackRate: \"1x\",\n state: \"Idle\",\n });\n const [bitrateHistory, setBitrateHistory] = useState<number[]>([]);\n const [bufferHistory, setBufferHistory] = useState<number[]>([]);\n\n const idleTimer = useRef<NodeJS.Timeout | null>(null);\n const hlsRef = useRef<Hls | null>(null);\n const dashRef = useRef<any>(null);\n const wasPlayingBeforeScrub = useRef(false);\n const scrubStartThumbnail = useRef<ThumbnailCue | null>(null);\n const isTheaterControlled = theaterMode !== undefined;\n const isTheater = isTheaterControlled ? theaterMode : internalTheaterMode;\n\n const setTheaterMode = (nextValue: boolean | ((prev: boolean) => boolean)) => {\n const resolvedValue =\n typeof nextValue === \"function\" ? nextValue(isTheater) : nextValue;\n\n if (!isTheaterControlled) {\n setInternalTheaterMode(resolvedValue);\n }\n\n onTheaterModeChange?.(resolvedValue);\n };\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n\n let hls: Hls | null = null;\n let dash: any = null;\n let isMounted = true;\n\n if (src.includes(\".m3u8\")) {\n if (Hls.isSupported()) {\n hls = new Hls();\n hlsRef.current = hls;\n hls.loadSource(src);\n hls.attachMedia(video);\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_, data) => {\n const availableQualities: QualityOption[] = data.levels.map((level, index) => ({\n height: level.height,\n index,\n }));\n const uniqueQualities = Array.from(\n new Map(availableQualities.map((q) => [q.height, q])).values(),\n ).sort((a, b) => b.height - a.height);\n setQualities(uniqueQualities);\n });\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_, data) => {\n if (hls?.autoLevelEnabled) {\n setCurrentQuality(\"auto\");\n } else {\n setCurrentQuality(data.level);\n }\n });\n } else if (video.canPlayType(\"application/vnd.apple.mpegurl\")) {\n video.src = src;\n }\n } else if (src.includes(\".mpd\")) {\n import(\"dashjs\").then((dashjs) => {\n if (!isMounted) return;\n\n dash = dashjs.MediaPlayer().create();\n dashRef.current = dash;\n dash.initialize(video, src, false);\n\n dash.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED, () => {\n const representations = dash.getRepresentationsByType?.(\"video\");\n if (representations?.length) {\n const availableQualities: QualityOption[] = representations.map(\n (representation: any, index: number) => ({\n height: representation.height,\n index,\n }),\n );\n const uniqueQualities = Array.from(\n new Map(availableQualities.map((q) => [q.height, q])).values(),\n ).sort((a, b) => b.height - a.height);\n setQualities(uniqueQualities);\n } else {\n setQualities([]);\n }\n });\n\n dash.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_RENDERED, (event: any) => {\n if (event.mediaType !== \"video\") return;\n\n const settings = dash.getSettings();\n if (settings.streaming?.abr?.autoSwitchBitrate?.video) {\n setCurrentQuality(\"auto\");\n } else {\n setCurrentQuality(event.newQuality);\n }\n });\n\n dash.on(dashjs.MediaPlayer.events.ERROR, () => {\n setQualities([]);\n setCurrentQuality(\"auto\");\n });\n });\n } else {\n video.src = src;\n }\n\n return () => {\n isMounted = false;\n if (hls) {\n hls.destroy();\n hlsRef.current = null;\n }\n if (dash) {\n dash.reset();\n dashRef.current = null;\n }\n };\n }, [src]);\n\n useEffect(() => {\n if (videoRef.current && videoRef.current.readyState >= 1) {\n setDuration(videoRef.current.duration || 0);\n }\n }, []);\n\n const parseVttTime = (timeStr: string) => {\n const parts = timeStr.split(\":\");\n if (parts.length === 3) {\n return Number(parts[0]) * 3600 + Number(parts[1]) * 60 + Number(parts[2]);\n }\n if (parts.length === 2) {\n return Number(parts[0]) * 60 + Number(parts[1]);\n }\n return Number(parts[0]) || 0;\n };\n\n useEffect(() => {\n if (!thumbnailTrackSrc) return;\n\n let isMounted = true;\n fetch(thumbnailTrackSrc)\n .then((response) => response.text())\n .then((text) => {\n if (!isMounted) return;\n const lines = text.split(\"\\n\");\n const cues: ThumbnailCue[] = [];\n let currentCue: Partial<ThumbnailCue> = {};\n\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i].trim();\n if (line.includes(\"-->\")) {\n const parts = line.split(\"-->\");\n currentCue.startTime = parseVttTime(parts[0].trim());\n currentCue.endTime = parseVttTime(parts[1].trim());\n } else if (line.includes(\"#xywh=\")) {\n const [url, coords] = line.split(\"#xywh=\");\n const [x, y, w, h] = coords.split(\",\").map(Number);\n\n try {\n currentCue.url = new URL(url, new URL(thumbnailTrackSrc, window.location.href)).href;\n } catch {\n currentCue.url = url;\n }\n\n currentCue.x = x;\n currentCue.y = y;\n currentCue.w = w;\n currentCue.h = h;\n cues.push(currentCue as ThumbnailCue);\n currentCue = {};\n }\n }\n setThumbnails(cues);\n })\n .catch(console.error);\n\n return () => {\n isMounted = false;\n };\n }, [thumbnailTrackSrc]);\n\n const formatDuration = (time: number) => {\n if (!Number.isFinite(time)) return \"0:00\";\n const seconds = Math.floor(time % 60);\n const minutes = Math.floor(time / 60) % 60;\n const hours = Math.floor(time / 3600);\n\n const leadingZeroFormatter = new Intl.NumberFormat(undefined, {\n minimumIntegerDigits: 2,\n });\n\n if (hours === 0) {\n return `${minutes}:${leadingZeroFormatter.format(seconds)}`;\n }\n return `${hours}:${leadingZeroFormatter.format(minutes)}:${leadingZeroFormatter.format(seconds)}`;\n };\n\n const queueIdleFade = () => {\n if (idleTimer.current) clearTimeout(idleTimer.current);\n setIsUserInactive(false);\n\n if (videoRef.current?.paused || isScrubbing) return;\n\n idleTimer.current = setTimeout(() => {\n if (!videoRef.current?.paused && !isScrubbing) {\n setIsUserInactive(true);\n }\n }, 2200);\n };\n\n useEffect(() => {\n const events = [\"pointermove\", \"pointerdown\", \"focusin\", \"mouseenter\"];\n const container = containerRef.current;\n if (!container) return;\n\n const handler = () => queueIdleFade();\n events.forEach((eventName) => container.addEventListener(eventName, handler));\n\n const handleLeave = () => {\n if (!videoRef.current?.paused && !isScrubbing) {\n setIsUserInactive(true);\n }\n };\n container.addEventListener(\"pointerleave\", handleLeave);\n\n return () => {\n events.forEach((eventName) => container.removeEventListener(eventName, handler));\n container.removeEventListener(\"pointerleave\", handleLeave);\n if (idleTimer.current) clearTimeout(idleTimer.current);\n };\n }, [isScrubbing]);\n\n useEffect(() => {\n const handleFullscreenChange = () => {\n setIsFullscreen(document.fullscreenElement === containerRef.current);\n };\n document.addEventListener(\"fullscreenchange\", handleFullscreenChange);\n return () => document.removeEventListener(\"fullscreenchange\", handleFullscreenChange);\n }, []);\n\n useEffect(() => {\n const handleClickOutside = (event: PointerEvent) => {\n if (!showSettings || !settingsRef.current) return;\n if (!settingsRef.current.contains(event.target as Node)) {\n setShowSettings(false);\n setSettingsView(\"root\");\n }\n };\n document.addEventListener(\"pointerdown\", handleClickOutside);\n return () => document.removeEventListener(\"pointerdown\", handleClickOutside);\n }, [showSettings]);\n\n useEffect(() => {\n const video = videoRef.current;\n const supported =\n typeof document !== \"undefined\" &&\n \"pictureInPictureEnabled\" in document &&\n document.pictureInPictureEnabled &&\n !!video &&\n typeof (video as HTMLVideoElement & { requestPictureInPicture?: () => Promise<PictureInPictureWindow> })\n .requestPictureInPicture === \"function\";\n\n setPipSupported(Boolean(supported));\n }, [src]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n const tagName = document.activeElement?.tagName?.toLowerCase();\n if (tagName === \"input\") return;\n\n switch (event.key.toLowerCase()) {\n case \" \":\n case \"k\":\n if (tagName === \"button\") return;\n event.preventDefault();\n togglePlay();\n break;\n case \"f\":\n event.preventDefault();\n toggleFullscreen();\n break;\n case \"t\":\n event.preventDefault();\n setTheaterMode((prev) => !prev);\n break;\n case \"m\":\n event.preventDefault();\n toggleMute();\n break;\n case \"arrowleft\":\n case \"j\":\n event.preventDefault();\n skipBy(-5);\n break;\n case \"arrowright\":\n case \"l\":\n event.preventDefault();\n skipBy(5);\n break;\n case \"c\":\n event.preventDefault();\n toggleCaptions();\n break;\n case \"i\":\n event.preventDefault();\n void togglePictureInPicture();\n break;\n default:\n break;\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [isScrubbing, playbackRate]);\n\n const togglePlay = () => {\n if (videoRef.current?.paused) {\n videoRef.current.play().catch(console.error);\n } else {\n videoRef.current?.pause();\n }\n };\n\n const toggleMute = () => {\n if (videoRef.current) {\n videoRef.current.muted = !videoRef.current.muted;\n setIsMuted(videoRef.current.muted);\n if (videoRef.current.muted) {\n setVolume(0);\n } else {\n setVolume(videoRef.current.volume || 1);\n }\n }\n };\n\n const handleVolumeChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const val = Number(event.target.value);\n setVolume(val);\n if (videoRef.current) {\n videoRef.current.volume = val;\n videoRef.current.muted = val === 0;\n setIsMuted(val === 0);\n }\n };\n\n const toggleFullscreen = async () => {\n if (!document.fullscreenElement) {\n await containerRef.current?.requestFullscreen();\n } else {\n await document.exitFullscreen();\n }\n };\n\n const skipBy = (seconds: number) => {\n if (videoRef.current) {\n const nextTime = Math.min(\n Math.max(videoRef.current.currentTime + seconds, 0),\n videoRef.current.duration || 0,\n );\n videoRef.current.currentTime = nextTime;\n setCurrentTime(nextTime);\n }\n };\n\n const toggleCaptions = () => {\n const video = videoRef.current;\n if (video && video.textTracks[0]) {\n const enabled = video.textTracks[0].mode === \"showing\";\n video.textTracks[0].mode = enabled ? \"hidden\" : \"showing\";\n setCaptionsEnabled(!enabled);\n }\n };\n\n const changePlaybackRate = (rate: number) => {\n if (!videoRef.current) return;\n videoRef.current.playbackRate = rate;\n setPlaybackRate(rate);\n setShowSettings(false);\n setSettingsView(\"root\");\n };\n\n const changeQuality = (index: number | \"auto\") => {\n setCurrentQuality(index);\n setShowSettings(false);\n setSettingsView(\"root\");\n\n if (hlsRef.current) {\n if (index === \"auto\") {\n hlsRef.current.currentLevel = -1;\n } else {\n hlsRef.current.currentLevel = index;\n }\n } else if (dashRef.current) {\n if (index === \"auto\") {\n dashRef.current.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: true } } },\n });\n } else {\n dashRef.current.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: false } } },\n });\n dashRef.current.setRepresentationForTypeByIndex(\"video\", index, true);\n }\n }\n };\n\n const togglePictureInPicture = async () => {\n try {\n if (document.pictureInPictureElement) {\n await document.exitPictureInPicture();\n return;\n }\n\n const video = videoRef.current as\n | (HTMLVideoElement & { requestPictureInPicture?: () => Promise<PictureInPictureWindow> })\n | null;\n\n if (!video || typeof video.requestPictureInPicture !== \"function\") {\n return;\n }\n\n await video.requestPictureInPicture();\n } catch (error) {\n console.error(error);\n }\n };\n\n const getQualityLabel = () => {\n if (currentQuality === \"auto\") {\n return \"Auto\";\n }\n\n return `${qualities.find((quality) => quality.index === currentQuality)?.height ?? currentQuality}p`;\n };\n\n const renderSparkline = (values: number[], colorClassName: string) => {\n if (values.length < 2) {\n return <div className=\"h-14 rounded-lg bg-white/5\" />;\n }\n\n const max = Math.max(...values, 1);\n const points = values\n .map((value, index) => {\n const x = (index / (values.length - 1)) * 100;\n const y = 100 - (value / max) * 100;\n return `${x},${y}`;\n })\n .join(\" \");\n\n return (\n <div className=\"h-14 rounded-lg bg-white/5 p-1\">\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" className=\"h-full w-full\">\n <polyline\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"3\"\n points={points}\n className={colorClassName}\n />\n </svg>\n </div>\n );\n };\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n\n const formatBitrate = (bitrate?: number | null) => {\n if (!bitrate || !Number.isFinite(bitrate) || bitrate <= 0) {\n return \"N/A\";\n }\n\n return bitrate >= 1_000_000\n ? `${(bitrate / 1_000_000).toFixed(2)} Mbps`\n : `${Math.round(bitrate / 1000)} kbps`;\n };\n\n const updateStats = () => {\n const bufferedAhead = (() => {\n for (let i = 0; i < video.buffered.length; i += 1) {\n const start = video.buffered.start(i);\n const end = video.buffered.end(i);\n if (video.currentTime >= start && video.currentTime <= end) {\n return Math.max(end - video.currentTime, 0);\n }\n }\n return 0;\n })();\n\n const playbackQuality =\n typeof video.getVideoPlaybackQuality === \"function\"\n ? video.getVideoPlaybackQuality()\n : null;\n\n let source = \"MP4\";\n let bitrate = \"N/A\";\n let quality = getQualityLabel();\n let codec = \"N/A\";\n let mimeType = video.currentSrc.includes(\".mpd\")\n ? \"application/dash+xml\"\n : video.currentSrc.includes(\".m3u8\")\n ? \"application/vnd.apple.mpegurl\"\n : \"video/mp4\";\n let audio = \"N/A\";\n let bitrateValue = 0;\n\n if (hlsRef.current) {\n source = \"HLS\";\n const hls = hlsRef.current;\n const levelIndex =\n hls.currentLevel >= 0\n ? hls.currentLevel\n : hls.loadLevel >= 0\n ? hls.loadLevel\n : hls.nextAutoLevel >= 0\n ? hls.nextAutoLevel\n : -1;\n const level = levelIndex >= 0 ? hls.levels[levelIndex] : null;\n bitrateValue = level?.bitrate ?? 0;\n bitrate = formatBitrate(bitrateValue);\n quality = level?.height ? `${level.height}p` : getQualityLabel();\n codec =\n level?.codecSet ||\n [level?.videoCodec, level?.audioCodec].filter(Boolean).join(\" / \") ||\n \"N/A\";\n mimeType = \"application/vnd.apple.mpegurl\";\n audio = level?.audioCodec || \"AAC/Unknown\";\n } else if (dashRef.current) {\n source = \"DASH\";\n const representation = dashRef.current.getCurrentRepresentationForType?.(\"video\");\n const audioTrack = dashRef.current.getCurrentTrackFor?.(\"audio\");\n const throughput = dashRef.current.getSafeAverageThroughput?.(\"video\");\n bitrateValue = representation?.bandwidth ?? throughput ?? 0;\n bitrate = formatBitrate(bitrateValue);\n quality = representation?.height ? `${representation.height}p` : getQualityLabel();\n codec = representation?.codecs || audioTrack?.codec || \"N/A\";\n mimeType = representation?.mimeType || audioTrack?.mimeType || \"application/dash+xml\";\n audio = [audioTrack?.codec, audioTrack?.lang].filter(Boolean).join(\" / \") || \"N/A\";\n }\n\n setBitrateHistory((previous) => [...previous.slice(-39), bitrateValue / 1_000_000]);\n setBufferHistory((previous) => [...previous.slice(-39), bufferedAhead]);\n\n setPlaybackStats({\n source,\n resolution:\n video.videoWidth && video.videoHeight ? `${video.videoWidth}x${video.videoHeight}` : \"0x0\",\n quality,\n bitrate,\n codec,\n mimeType,\n audio,\n bufferHealth: `${bufferedAhead.toFixed(1)}s`,\n droppedFrames: String(playbackQuality?.droppedVideoFrames ?? 0),\n fps:\n video.currentTime > 0 && playbackQuality?.totalVideoFrames\n ? `${Math.round(\n ((playbackQuality.totalVideoFrames ?? 0) - (playbackQuality.droppedVideoFrames ?? 0)) /\n Math.max(video.currentTime, 1),\n )}`\n : \"N/A\",\n playbackRate: `${video.playbackRate}x`,\n state: video.paused ? \"Paused\" : video.readyState < 3 ? \"Buffering\" : \"Playing\",\n });\n };\n\n updateStats();\n const intervalId = window.setInterval(updateStats, 500);\n return () => window.clearInterval(intervalId);\n }, [src, playbackRate, currentQuality, qualities]);\n\n const hasCaptions = Boolean(captionsSrc);\n const hasQualityOptions = qualities.length > 0;\n\n const getTimelinePercent = (clientX: number) => {\n const rect = timelineRef.current?.getBoundingClientRect();\n if (!rect || rect.width === 0) return 0;\n const rawPosition = clientX - rect.left;\n return Math.min(Math.max(rawPosition / rect.width, 0), 1);\n };\n\n const getThumbnailForTime = (time: number) => {\n if (thumbnails.length === 0) return null;\n\n return (\n thumbnails.find((thumbnail) => time >= thumbnail.startTime && time <= thumbnail.endTime) ||\n null\n );\n };\n\n const updateTimelinePreview = (event: React.PointerEvent | PointerEvent) => {\n const percent = getTimelinePercent(event.clientX);\n const time = percent * duration;\n\n setPreviewPosition(percent);\n setPreviewTime(time);\n\n if (duration > 0) {\n const thumbnail = getThumbnailForTime(time);\n if (thumbnail) {\n setActiveThumbnail(thumbnail);\n } else if (isScrubbing && scrubStartThumbnail.current) {\n setActiveThumbnail(scrubStartThumbnail.current);\n } else if (!isScrubbing) {\n setActiveThumbnail(null);\n }\n }\n\n if (isScrubbing) {\n event.preventDefault();\n setTimelineProgress(percent);\n }\n };\n\n const beginScrubbing = (event: React.PointerEvent) => {\n if (event.pointerType === \"mouse\" && event.button !== 0) return;\n wasPlayingBeforeScrub.current = !videoRef.current?.paused;\n scrubStartThumbnail.current = getThumbnailForTime(videoRef.current?.currentTime ?? 0);\n setIsScrubbing(true);\n videoRef.current?.pause();\n updateTimelinePreview(event);\n };\n\n const endScrubbing = (event: PointerEvent) => {\n if (!isScrubbing) return;\n setIsScrubbing(false);\n const percent = getTimelinePercent(event.clientX);\n if (videoRef.current) {\n const nextTime = percent * (videoRef.current.duration || 0);\n videoRef.current.currentTime = nextTime;\n setCurrentTime(nextTime);\n setPreviewTime(nextTime);\n if (wasPlayingBeforeScrub.current) {\n videoRef.current.play().catch(console.error);\n }\n }\n scrubStartThumbnail.current = null;\n };\n\n useEffect(() => {\n if (isScrubbing) {\n const onPointerMove = (event: PointerEvent) => updateTimelinePreview(event);\n document.addEventListener(\"pointermove\", onPointerMove);\n document.addEventListener(\"pointerup\", endScrubbing);\n return () => {\n document.removeEventListener(\"pointermove\", onPointerMove);\n document.removeEventListener(\"pointerup\", endScrubbing);\n };\n }\n return undefined;\n }, [isScrubbing, duration, thumbnails]);\n\n const VolumeIcon = () => {\n if (isMuted || volume === 0) return <VolumeX size={18} className=\"control-icon\" />;\n if (volume < 0.5) return <Volume1 size={18} className=\"control-icon\" />;\n return <Volume2 size={18} className=\"control-icon\" />;\n };\n\n return (\n <main className=\"w-full max-w-[1180px] mx-auto py-8 px-4\">\n <section className=\"mb-6\">\n {eyebrow ? (\n <p className=\"m-0 mb-2 text-youtube-muted uppercase tracking-wider text-xs font-medium\">\n {eyebrow}\n </p>\n ) : null}\n <h1 className=\"m-0 text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight mb-4\">{title}</h1>\n {description ? (\n <p className=\"max-w-2xl m-0 text-youtube-muted text-base leading-relaxed\">{description}</p>\n ) : null}\n {badges.length > 0 ? (\n <ul className=\"list-none flex flex-wrap gap-2 p-0 mt-5\">\n {badges.map((badge) => (\n <li\n key={badge}\n className=\"px-3 py-1 bg-white/10 rounded-full text-youtube-text text-sm font-medium\"\n >\n {badge}\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n\n <section\n className={`bg-youtube-panel shadow-2xl ring-1 ring-white/5 transition-[width,transform,border-radius] duration-300 ease-out ${\n isTheater\n ? \"relative left-1/2 w-screen max-w-none -translate-x-1/2 rounded-none md:rounded-2xl\"\n : \"rounded-xl overflow-hidden\"\n }`}\n >\n <div\n ref={containerRef}\n className={`relative flex justify-center bg-black group transition-[max-height] duration-300 ease-out ${\n isTheater ? \"min-h-[56.25vw] max-h-[82vh] w-full\" : \"\"\n } ${isFullscreen ? \"max-h-screen w-full\" : \"\"} ${isUserInactive ? \"user-inactive\" : \"\"}`}\n >\n {showStatsForNerds ? (\n <div className=\"stats-panel absolute left-3 top-3 z-30 w-[min(92vw,360px)] rounded-lg border border-white/10 bg-black/75 p-2.5 text-[10px] leading-4 text-white backdrop-blur-sm\">\n <div className=\"mb-2 text-[10px] font-semibold uppercase tracking-[0.2em] text-white/55\">\n Stats for nerds\n </div>\n <div className=\"space-y-1.5\">\n <div className=\"stats-row\">\n <span className=\"stats-key\">Buffer</span>\n <div className=\"stats-value-wrap\">\n <span>{playbackStats.bufferHealth}</span>\n <div className=\"stats-graph\">{renderSparkline(bufferHistory, \"text-white/80\")}</div>\n </div>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Bitrate</span>\n <div className=\"stats-value-wrap\">\n <span>{playbackStats.bitrate}</span>\n <div className=\"stats-graph\">{renderSparkline(bitrateHistory, \"text-youtube-accent\")}</div>\n </div>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Quality</span>\n <span className=\"stats-value-wrap\">{playbackStats.quality}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Codecs</span>\n <span className=\"stats-value-wrap\">{playbackStats.codec}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Audio</span>\n <span className=\"stats-value-wrap\">{playbackStats.audio}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Viewport</span>\n <span className=\"stats-value-wrap\">{playbackStats.resolution}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Mime</span>\n <span className=\"stats-value-wrap\">{playbackStats.mimeType}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Frames</span>\n <span className=\"stats-value-wrap\">\n {playbackStats.fps} fps / {playbackStats.droppedFrames} dropped\n </span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">State</span>\n <span className=\"stats-value-wrap\">\n {playbackStats.state} / {playbackStats.playbackRate}\n </span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Source</span>\n <span className=\"stats-value-wrap\">{playbackStats.source}</span>\n </div>\n </div>\n </div>\n ) : null}\n\n <button\n onClick={togglePlay}\n aria-label=\"Play video\"\n className={`absolute inset-1/2 -translate-x-1/2 -translate-y-1/2 grid place-items-center w-16 h-16 md:w-20 md:h-20 rounded-full bg-black/50 backdrop-blur-md text-white z-10 shadow-lg transition-all duration-200 hover:bg-youtube-accent ${isPlaying ? \"opacity-0 scale-75 pointer-events-none\" : \"opacity-100 scale-100\"}`}\n >\n <Play size={32} className=\"ml-1 control-icon\" fill=\"currentColor\" />\n </button>\n\n <div\n className={`video-controls-container absolute bottom-0 left-0 right-0 px-3 pb-2 pt-16 bg-gradient-to-t from-black/90 to-transparent text-white z-20 transition-all duration-500 ease-out ${isUserInactive && isPlaying ? \"opacity-0 pointer-events-none cursor-none translate-y-2\" : \"opacity-100 translate-y-0\"}`}\n >\n <div\n ref={timelineRef}\n className=\"timeline-container h-4 mx-1 cursor-pointer flex items-center relative group/timeline\"\n onPointerDown={beginScrubbing}\n onPointerMove={(event) => {\n if (!isScrubbing) updateTimelinePreview(event);\n }}\n onPointerEnter={() => setIsHoveringTimeline(true)}\n onPointerLeave={() => setIsHoveringTimeline(false)}\n >\n <div className=\"timeline-progress w-full h-[3px] bg-youtube-track relative transition-[height] duration-150\">\n <div\n className=\"absolute inset-y-0 left-0 bg-white/40\"\n style={{\n width: `${previewPosition * 100}%`,\n display: isHoveringTimeline || isScrubbing ? \"block\" : \"none\",\n }}\n />\n <div\n className=\"absolute inset-y-0 left-0 bg-youtube-accent transition-all duration-200 ease-out\"\n style={{\n width: `${(isScrubbing ? timelineProgress : duration ? currentTime / duration : 0) * 100}%`,\n }}\n />\n <div\n className=\"timeline-thumb absolute top-1/2 w-3.5 h-3.5 rounded-full bg-youtube-accent transition-all duration-200 ease-out\"\n style={{\n left: `${(isScrubbing ? timelineProgress : duration ? currentTime / duration : 0) * 100}%`,\n transform: `translate(-50%, -50%) scale(${isHoveringTimeline || isScrubbing ? 1 : 0})`,\n }}\n />\n\n {activeThumbnail ? (\n <div\n className={`pointer-events-none absolute bottom-6 border-2 border-white rounded-lg shadow-lg overflow-hidden bg-black -translate-x-1/2 transition-opacity duration-200 ${isScrubbing || isHoveringTimeline ? \"opacity-100\" : \"opacity-0\"}`}\n style={{ left: `${previewPosition * 100}%`, width: \"160px\", height: \"110px\" }}\n >\n <div\n style={{\n backgroundImage: `url(${activeThumbnail.url})`,\n backgroundPosition: `-${activeThumbnail.x}px -${activeThumbnail.y}px`,\n width: `${activeThumbnail.w}px`,\n height: `${activeThumbnail.h}px`,\n transform: `scale(${160 / activeThumbnail.w})`,\n transformOrigin: \"top left\",\n }}\n />\n <div className=\"absolute inset-x-0 bottom-0 bg-black/80 px-2 py-1 text-center text-[11px] text-white\">\n {formatDuration(previewTime)}\n </div>\n </div>\n ) : isScrubbing || isHoveringTimeline ? (\n <div\n className=\"pointer-events-none absolute bottom-6 min-w-16 rounded-md bg-black/85 px-2 py-1 text-center text-[11px] text-white shadow-lg -translate-x-1/2 transition-opacity duration-200\"\n style={{ left: `${previewPosition * 100}%` }}\n >\n {formatDuration(previewTime)}\n </div>\n ) : null}\n </div>\n </div>\n\n <div className=\"flex items-center justify-between gap-3 pt-2 px-1\">\n <div className=\"flex min-w-0 items-center gap-1 sm:gap-2\">\n <button\n onClick={togglePlay}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n >\n {isPlaying ? (\n <Pause size={18} fill=\"currentColor\" className=\"control-icon\" />\n ) : (\n <Play size={18} fill=\"currentColor\" className=\"control-icon\" />\n )}\n </button>\n\n <div className=\"volume-container flex items-center gap-1\">\n <button\n onClick={toggleMute}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n >\n <VolumeIcon />\n </button>\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"any\"\n value={volume}\n onChange={handleVolumeChange}\n className=\"volume-slider h-1\"\n style={{ \"--volume-percent\": `${volume * 100}%` } as React.CSSProperties}\n />\n </div>\n\n <div className=\"flex min-w-0 items-center gap-1 text-[13px] font-sans text-white/90 tabular-nums whitespace-nowrap\">\n <span>{formatDuration(currentTime)}</span>\n <span className=\"text-white/50\">/</span>\n <span>{formatDuration(duration)}</span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-1 sm:gap-2\">\n <button\n onClick={toggleCaptions}\n disabled={!hasCaptions}\n className={`control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all disabled:opacity-40 disabled:cursor-not-allowed ${captionsEnabled ? \"text-youtube-accent\" : \"\"}`}\n title=\"Subtitles/closed captions (c)\"\n >\n <Captions size={18} className=\"control-icon\" />\n </button>\n\n <div ref={settingsRef} className=\"relative\">\n <button\n onClick={() => {\n setShowSettings((prev) => !prev);\n setSettingsView(\"root\");\n }}\n className={`control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all ${showSettings ? \"bg-white/10 text-youtube-accent\" : \"\"}`}\n title=\"Settings\"\n >\n <Settings\n size={18}\n className={`control-icon ${showSettings ? \"rotate-[22deg] scale-110\" : \"\"} transition-transform duration-300`}\n />\n </button>\n\n {showSettings ? (\n <div\n className={`settings-panel absolute bottom-full right-0 mb-4 w-56 bg-black/40 backdrop-blur-sm rounded-xl overflow-hidden shadow-2xl z-50 border border-white/10 ${\n settingsView === \"root\" ? \"settings-panel-root\" : \"max-h-[min(28rem,calc(100vh-10rem))]\"\n }`}\n >\n <div\n className=\"settings-slider\"\n style={{\n width: \"300%\",\n transform: `translateX(${\n settingsView === \"root\"\n ? \"0%\"\n : settingsView === \"quality\"\n ? \"-33.3333%\"\n : \"-66.6667%\"\n })`,\n }}\n >\n <div className=\"settings-view settings-scroll\">\n <button\n onClick={() => setSettingsView(\"quality\")}\n disabled={!hasQualityOptions}\n className=\"settings-item disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n <div>\n <div className=\"settings-label\">Quality</div>\n <div className=\"settings-value\">\n {hasQualityOptions ? getQualityLabel() : \"Unavailable\"}\n </div>\n </div>\n <ChevronRight size={16} className=\"text-white/55\" />\n </button>\n\n <button\n onClick={() => setSettingsView(\"speed\")}\n className=\"settings-item\"\n >\n <div>\n <div className=\"settings-label\">Playback speed</div>\n <div className=\"settings-value\">{playbackRate}x</div>\n </div>\n <ChevronRight size={16} className=\"text-white/55\" />\n </button>\n\n <button\n onClick={() => {\n setShowStatsForNerds((prev) => !prev);\n setShowSettings(false);\n setSettingsView(\"root\");\n }}\n className=\"settings-item\"\n >\n <div>\n <div className=\"settings-label\">Stats for nerds</div>\n <div className=\"settings-value\">\n {showStatsForNerds ? \"On\" : \"Off\"}\n </div>\n </div>\n <span\n className={`h-2 w-2 rounded-full ${\n showStatsForNerds ? \"bg-youtube-accent\" : \"bg-white/25\"\n }`}\n />\n </button>\n </div>\n\n <div className=\"settings-view settings-scroll border-l border-white/10\">\n <button\n onClick={() => setSettingsView(\"root\")}\n className=\"settings-back\"\n >\n <ChevronLeft size={16} />\n <span>Quality</span>\n </button>\n <button\n onClick={() => changeQuality(\"auto\")}\n className={`settings-option ${currentQuality === \"auto\" ? \"settings-option-active\" : \"\"}`}\n >\n <span>Auto</span>\n {currentQuality === \"auto\" ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n {qualities.length > 0 ? (\n qualities.map((quality) => (\n <button\n key={quality.height}\n onClick={() => changeQuality(quality.index)}\n className={`settings-option ${currentQuality === quality.index ? \"settings-option-active\" : \"\"}`}\n >\n <span>{quality.height}p</span>\n {currentQuality === quality.index ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n ))\n ) : (\n <div className=\"px-4 py-3 text-[13px] text-white/55\">No quality options</div>\n )}\n </div>\n\n <div className=\"settings-view settings-scroll border-l border-white/10\">\n <button\n onClick={() => setSettingsView(\"root\")}\n className=\"settings-back\"\n >\n <ChevronLeft size={16} />\n <span>Playback speed</span>\n </button>\n {PLAYBACK_RATES.map((rate) => (\n <button\n key={rate}\n onClick={() => changePlaybackRate(rate)}\n className={`settings-option ${playbackRate === rate ? \"settings-option-active\" : \"\"}`}\n >\n <span>{rate}x</span>\n {playbackRate === rate ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n ))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n\n <button\n onClick={togglePictureInPicture}\n disabled={!pipSupported}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all disabled:opacity-40 disabled:cursor-not-allowed\"\n title={pipSupported ? \"Miniplayer (i)\" : \"Picture-in-picture not supported\"}\n >\n <PictureInPicture size={18} className=\"control-icon\" />\n </button>\n\n <button\n onClick={() => setTheaterMode((prev) => !prev)}\n className=\"control-btn h-9 w-9 items-center justify-center rounded-md transition-all hidden sm:flex\"\n title=\"Theater mode (t)\"\n >\n {isTheater ? (\n <Tv size={18} className=\"control-icon\" />\n ) : (\n <RectangleHorizontal size={18} className=\"control-icon\" />\n )}\n </button>\n\n <button\n onClick={toggleFullscreen}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n title=\"Fullscreen (f)\"\n >\n {isFullscreen ? (\n <Minimize size={18} className=\"control-icon\" />\n ) : (\n <Maximize size={18} className=\"control-icon\" />\n )}\n </button>\n </div>\n </div>\n </div>\n\n <video\n ref={videoRef}\n preload=\"metadata\"\n className=\"w-full bg-black block\"\n onClick={togglePlay}\n onDoubleClick={toggleFullscreen}\n onPlay={() => {\n setIsPlaying(true);\n queueIdleFade();\n }}\n onPause={() => {\n setIsPlaying(false);\n setIsUserInactive(false);\n }}\n onTimeUpdate={(event) => {\n const time = event.currentTarget.currentTime;\n if (time === 0 && currentTime > 1 && !isScrubbing) return;\n setCurrentTime(time);\n }}\n onDurationChange={(event) => setDuration(event.currentTarget.duration)}\n onLoadedMetadata={(event) => {\n setDuration(event.currentTarget.duration);\n }}\n onVolumeChange={(event) => {\n setIsMuted(event.currentTarget.muted);\n setVolume(event.currentTarget.muted ? 0 : event.currentTarget.volume);\n }}\n >\n {captionsSrc ? (\n <track kind=\"captions\" src={captionsSrc} srcLang=\"en\" label=\"English\" default={false} />\n ) : null}\n </video>\n </div>\n </section>\n </main>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../components/YouTubePlayer.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport {\n Captions,\n ChevronLeft,\n ChevronRight,\n Maximize,\n Minimize,\n Pause,\n PictureInPicture,\n Play,\n RectangleHorizontal,\n Settings,\n Tv,\n Volume1,\n Volume2,\n VolumeX,\n} from \"lucide-react\";\nimport Hls from \"hls.js\";\n\nexport interface PlayerProps {\n src: string;\n title: string;\n description?: string;\n eyebrow?: string;\n badges?: string[];\n captionsSrc?: string;\n thumbnailTrackSrc?: string;\n theaterMode?: boolean;\n defaultTheaterMode?: boolean;\n onTheaterModeChange?: (isTheaterMode: boolean) => void;\n}\n\ninterface ThumbnailCue {\n startTime: number;\n endTime: number;\n url: string;\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\ninterface QualityOption {\n height: number;\n index: number;\n}\n\ninterface PlaybackStats {\n source: string;\n resolution: string;\n quality: string;\n bitrate: string;\n codec: string;\n mimeType: string;\n audio: string;\n bufferHealth: string;\n droppedFrames: string;\n fps: string;\n playbackRate: string;\n state: string;\n}\n\nconst PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n\nexport default function YouTubePlayer({\n src,\n title,\n description,\n eyebrow,\n badges = [],\n captionsSrc,\n thumbnailTrackSrc,\n theaterMode,\n defaultTheaterMode = false,\n onTheaterModeChange,\n}: PlayerProps) {\n const videoRef = useRef<HTMLVideoElement>(null);\n const timelineRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const settingsRef = useRef<HTMLDivElement>(null);\n\n const [isPlaying, setIsPlaying] = useState(false);\n const [isMuted, setIsMuted] = useState(false);\n const [volume, setVolume] = useState(1);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [isScrubbing, setIsScrubbing] = useState(false);\n const [isHoveringTimeline, setIsHoveringTimeline] = useState(false);\n const [timelineProgress, setTimelineProgress] = useState(0);\n const [previewPosition, setPreviewPosition] = useState(0);\n const [previewTime, setPreviewTime] = useState(0);\n const [activeThumbnail, setActiveThumbnail] = useState<ThumbnailCue | null>(null);\n const [thumbnails, setThumbnails] = useState<ThumbnailCue[]>([]);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const [internalTheaterMode, setInternalTheaterMode] = useState(defaultTheaterMode);\n const [isUserInactive, setIsUserInactive] = useState(false);\n const [playbackRate, setPlaybackRate] = useState(1);\n const [captionsEnabled, setCaptionsEnabled] = useState(false);\n const [qualities, setQualities] = useState<QualityOption[]>([]);\n const [currentQuality, setCurrentQuality] = useState<number | \"auto\">(\"auto\");\n const [showSettings, setShowSettings] = useState(false);\n const [settingsView, setSettingsView] = useState<\"root\" | \"quality\" | \"speed\">(\"root\");\n const [showStatsForNerds, setShowStatsForNerds] = useState(false);\n const [pipSupported, setPipSupported] = useState(false);\n const [playbackStats, setPlaybackStats] = useState<PlaybackStats>({\n source: \"MP4\",\n resolution: \"0x0\",\n quality: \"Auto\",\n bitrate: \"N/A\",\n codec: \"N/A\",\n mimeType: \"video/mp4\",\n audio: \"N/A\",\n bufferHealth: \"0.0s\",\n droppedFrames: \"0\",\n fps: \"N/A\",\n playbackRate: \"1x\",\n state: \"Idle\",\n });\n const [bitrateHistory, setBitrateHistory] = useState<number[]>([]);\n const [bufferHistory, setBufferHistory] = useState<number[]>([]);\n\n const idleTimer = useRef<NodeJS.Timeout | null>(null);\n const hlsRef = useRef<Hls | null>(null);\n const dashRef = useRef<any>(null);\n const wasPlayingBeforeScrub = useRef(false);\n const scrubStartThumbnail = useRef<ThumbnailCue | null>(null);\n const isTheaterControlled = theaterMode !== undefined;\n const isTheater = isTheaterControlled ? theaterMode : internalTheaterMode;\n\n const setTheaterMode = (nextValue: boolean | ((prev: boolean) => boolean)) => {\n const resolvedValue =\n typeof nextValue === \"function\" ? nextValue(isTheater) : nextValue;\n\n if (!isTheaterControlled) {\n setInternalTheaterMode(resolvedValue);\n }\n\n onTheaterModeChange?.(resolvedValue);\n };\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n\n let hls: Hls | null = null;\n let dash: any = null;\n let isMounted = true;\n\n if (src.includes(\".m3u8\")) {\n if (Hls.isSupported()) {\n hls = new Hls();\n hlsRef.current = hls;\n hls.loadSource(src);\n hls.attachMedia(video);\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_, data) => {\n const availableQualities: QualityOption[] = data.levels.map((level, index) => ({\n height: level.height,\n index,\n }));\n const uniqueQualities = Array.from(\n new Map(availableQualities.map((q) => [q.height, q])).values(),\n ).sort((a, b) => b.height - a.height);\n setQualities(uniqueQualities);\n });\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_, data) => {\n if (hls?.autoLevelEnabled) {\n setCurrentQuality(\"auto\");\n } else {\n setCurrentQuality(data.level);\n }\n });\n } else if (video.canPlayType(\"application/vnd.apple.mpegurl\")) {\n video.src = src;\n }\n } else if (src.includes(\".mpd\")) {\n import(\"dashjs\").then((dashjs) => {\n if (!isMounted) return;\n\n dash = dashjs.MediaPlayer().create();\n dashRef.current = dash;\n dash.initialize(video, src, false);\n\n dash.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED, () => {\n const representations = dash.getRepresentationsByType?.(\"video\");\n if (representations?.length) {\n const availableQualities: QualityOption[] = representations.map(\n (representation: any, index: number) => ({\n height: representation.height,\n index,\n }),\n );\n const uniqueQualities = Array.from(\n new Map(availableQualities.map((q) => [q.height, q])).values(),\n ).sort((a, b) => b.height - a.height);\n setQualities(uniqueQualities);\n } else {\n setQualities([]);\n }\n });\n\n dash.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_RENDERED, (event: any) => {\n if (event.mediaType !== \"video\") return;\n\n const settings = dash.getSettings();\n if (settings.streaming?.abr?.autoSwitchBitrate?.video) {\n setCurrentQuality(\"auto\");\n } else {\n setCurrentQuality(event.newQuality);\n }\n });\n\n dash.on(dashjs.MediaPlayer.events.ERROR, () => {\n setQualities([]);\n setCurrentQuality(\"auto\");\n });\n });\n } else {\n video.src = src;\n }\n\n return () => {\n isMounted = false;\n if (hls) {\n hls.destroy();\n hlsRef.current = null;\n }\n if (dash) {\n dash.reset();\n dashRef.current = null;\n }\n };\n }, [src]);\n\n useEffect(() => {\n if (videoRef.current && videoRef.current.readyState >= 1) {\n setDuration(videoRef.current.duration || 0);\n }\n }, []);\n\n const parseVttTime = (timeStr: string) => {\n const parts = timeStr.split(\":\");\n if (parts.length === 3) {\n return Number(parts[0]) * 3600 + Number(parts[1]) * 60 + Number(parts[2]);\n }\n if (parts.length === 2) {\n return Number(parts[0]) * 60 + Number(parts[1]);\n }\n return Number(parts[0]) || 0;\n };\n\n useEffect(() => {\n if (!thumbnailTrackSrc) return;\n\n let isMounted = true;\n fetch(thumbnailTrackSrc)\n .then((response) => response.text())\n .then((text) => {\n if (!isMounted) return;\n const lines = text.split(\"\\n\");\n const cues: ThumbnailCue[] = [];\n let currentCue: Partial<ThumbnailCue> = {};\n\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i].trim();\n if (line.includes(\"-->\")) {\n const parts = line.split(\"-->\");\n currentCue.startTime = parseVttTime(parts[0].trim());\n currentCue.endTime = parseVttTime(parts[1].trim());\n } else if (line.includes(\"#xywh=\")) {\n const [url, coords] = line.split(\"#xywh=\");\n const [x, y, w, h] = coords.split(\",\").map(Number);\n\n try {\n currentCue.url = new URL(url, new URL(thumbnailTrackSrc, window.location.href)).href;\n } catch {\n currentCue.url = url;\n }\n\n currentCue.x = x;\n currentCue.y = y;\n currentCue.w = w;\n currentCue.h = h;\n cues.push(currentCue as ThumbnailCue);\n currentCue = {};\n }\n }\n setThumbnails(cues);\n })\n .catch(console.error);\n\n return () => {\n isMounted = false;\n };\n }, [thumbnailTrackSrc]);\n\n const formatDuration = (time: number) => {\n if (!Number.isFinite(time)) return \"0:00\";\n const seconds = Math.floor(time % 60);\n const minutes = Math.floor(time / 60) % 60;\n const hours = Math.floor(time / 3600);\n\n const leadingZeroFormatter = new Intl.NumberFormat(undefined, {\n minimumIntegerDigits: 2,\n });\n\n if (hours === 0) {\n return `${minutes}:${leadingZeroFormatter.format(seconds)}`;\n }\n return `${hours}:${leadingZeroFormatter.format(minutes)}:${leadingZeroFormatter.format(seconds)}`;\n };\n\n const queueIdleFade = () => {\n if (idleTimer.current) clearTimeout(idleTimer.current);\n setIsUserInactive(false);\n\n if (videoRef.current?.paused || isScrubbing) return;\n\n idleTimer.current = setTimeout(() => {\n if (!videoRef.current?.paused && !isScrubbing) {\n setIsUserInactive(true);\n }\n }, 2200);\n };\n\n useEffect(() => {\n const events = [\"pointermove\", \"pointerdown\", \"focusin\", \"mouseenter\"];\n const container = containerRef.current;\n if (!container) return;\n\n const handler = () => queueIdleFade();\n events.forEach((eventName) => container.addEventListener(eventName, handler));\n\n const handleLeave = () => {\n if (!videoRef.current?.paused && !isScrubbing) {\n setIsUserInactive(true);\n }\n };\n container.addEventListener(\"pointerleave\", handleLeave);\n\n return () => {\n events.forEach((eventName) => container.removeEventListener(eventName, handler));\n container.removeEventListener(\"pointerleave\", handleLeave);\n if (idleTimer.current) clearTimeout(idleTimer.current);\n };\n }, [isScrubbing]);\n\n useEffect(() => {\n const handleFullscreenChange = () => {\n setIsFullscreen(document.fullscreenElement === containerRef.current);\n };\n document.addEventListener(\"fullscreenchange\", handleFullscreenChange);\n return () => document.removeEventListener(\"fullscreenchange\", handleFullscreenChange);\n }, []);\n\n useEffect(() => {\n const handleClickOutside = (event: PointerEvent) => {\n if (!showSettings || !settingsRef.current) return;\n if (!settingsRef.current.contains(event.target as Node)) {\n setShowSettings(false);\n setSettingsView(\"root\");\n }\n };\n document.addEventListener(\"pointerdown\", handleClickOutside);\n return () => document.removeEventListener(\"pointerdown\", handleClickOutside);\n }, [showSettings]);\n\n useEffect(() => {\n const video = videoRef.current;\n const supported =\n typeof document !== \"undefined\" &&\n \"pictureInPictureEnabled\" in document &&\n document.pictureInPictureEnabled &&\n !!video &&\n typeof (video as HTMLVideoElement & { requestPictureInPicture?: () => Promise<PictureInPictureWindow> })\n .requestPictureInPicture === \"function\";\n\n setPipSupported(Boolean(supported));\n }, [src]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n const tagName = document.activeElement?.tagName?.toLowerCase();\n if (tagName === \"input\") return;\n\n switch (event.key.toLowerCase()) {\n case \" \":\n case \"k\":\n if (tagName === \"button\") return;\n event.preventDefault();\n togglePlay();\n break;\n case \"f\":\n event.preventDefault();\n toggleFullscreen();\n break;\n case \"t\":\n event.preventDefault();\n setTheaterMode((prev) => !prev);\n break;\n case \"m\":\n event.preventDefault();\n toggleMute();\n break;\n case \"arrowleft\":\n case \"j\":\n event.preventDefault();\n skipBy(-5);\n break;\n case \"arrowright\":\n case \"l\":\n event.preventDefault();\n skipBy(5);\n break;\n case \"c\":\n event.preventDefault();\n toggleCaptions();\n break;\n case \"i\":\n event.preventDefault();\n void togglePictureInPicture();\n break;\n default:\n break;\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [isScrubbing, playbackRate]);\n\n const togglePlay = () => {\n if (videoRef.current?.paused) {\n videoRef.current.play().catch(console.error);\n } else {\n videoRef.current?.pause();\n }\n };\n\n const toggleMute = () => {\n if (videoRef.current) {\n videoRef.current.muted = !videoRef.current.muted;\n setIsMuted(videoRef.current.muted);\n if (videoRef.current.muted) {\n setVolume(0);\n } else {\n setVolume(videoRef.current.volume || 1);\n }\n }\n };\n\n const handleVolumeChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const val = Number(event.target.value);\n setVolume(val);\n if (videoRef.current) {\n videoRef.current.volume = val;\n videoRef.current.muted = val === 0;\n setIsMuted(val === 0);\n }\n };\n\n const toggleFullscreen = async () => {\n if (!document.fullscreenElement) {\n await containerRef.current?.requestFullscreen();\n } else {\n await document.exitFullscreen();\n }\n };\n\n const skipBy = (seconds: number) => {\n if (videoRef.current) {\n const nextTime = Math.min(\n Math.max(videoRef.current.currentTime + seconds, 0),\n videoRef.current.duration || 0,\n );\n videoRef.current.currentTime = nextTime;\n setCurrentTime(nextTime);\n }\n };\n\n const toggleCaptions = () => {\n const video = videoRef.current;\n if (video && video.textTracks[0]) {\n const enabled = video.textTracks[0].mode === \"showing\";\n video.textTracks[0].mode = enabled ? \"hidden\" : \"showing\";\n setCaptionsEnabled(!enabled);\n }\n };\n\n const changePlaybackRate = (rate: number) => {\n if (!videoRef.current) return;\n videoRef.current.playbackRate = rate;\n setPlaybackRate(rate);\n setShowSettings(false);\n setSettingsView(\"root\");\n };\n\n const changeQuality = (index: number | \"auto\") => {\n setCurrentQuality(index);\n setShowSettings(false);\n setSettingsView(\"root\");\n\n if (hlsRef.current) {\n if (index === \"auto\") {\n hlsRef.current.currentLevel = -1;\n } else {\n hlsRef.current.currentLevel = index;\n }\n } else if (dashRef.current) {\n if (index === \"auto\") {\n dashRef.current.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: true } } },\n });\n } else {\n dashRef.current.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: false } } },\n });\n dashRef.current.setRepresentationForTypeByIndex(\"video\", index, true);\n }\n }\n };\n\n const togglePictureInPicture = async () => {\n try {\n if (document.pictureInPictureElement) {\n await document.exitPictureInPicture();\n return;\n }\n\n const video = videoRef.current as\n | (HTMLVideoElement & { requestPictureInPicture?: () => Promise<PictureInPictureWindow> })\n | null;\n\n if (!video || typeof video.requestPictureInPicture !== \"function\") {\n return;\n }\n\n await video.requestPictureInPicture();\n } catch (error) {\n console.error(error);\n }\n };\n\n const getQualityLabel = () => {\n if (currentQuality === \"auto\") {\n return \"Auto\";\n }\n\n return `${qualities.find((quality) => quality.index === currentQuality)?.height ?? currentQuality}p`;\n };\n\n const renderSparkline = (values: number[], colorClassName: string) => {\n if (values.length < 2) {\n return <div className=\"h-14 rounded-lg bg-white/5\" />;\n }\n\n const max = Math.max(...values, 1);\n const points = values\n .map((value, index) => {\n const x = (index / (values.length - 1)) * 100;\n const y = 100 - (value / max) * 100;\n return `${x},${y}`;\n })\n .join(\" \");\n\n return (\n <div className=\"h-14 rounded-lg bg-white/5 p-1\">\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" className=\"h-full w-full\">\n <polyline\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"3\"\n points={points}\n className={colorClassName}\n />\n </svg>\n </div>\n );\n };\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n\n const formatBitrate = (bitrate?: number | null) => {\n if (!bitrate || !Number.isFinite(bitrate) || bitrate <= 0) {\n return \"N/A\";\n }\n\n return bitrate >= 1_000_000\n ? `${(bitrate / 1_000_000).toFixed(2)} Mbps`\n : `${Math.round(bitrate / 1000)} kbps`;\n };\n\n const updateStats = () => {\n const bufferedAhead = (() => {\n for (let i = 0; i < video.buffered.length; i += 1) {\n const start = video.buffered.start(i);\n const end = video.buffered.end(i);\n if (video.currentTime >= start && video.currentTime <= end) {\n return Math.max(end - video.currentTime, 0);\n }\n }\n return 0;\n })();\n\n const playbackQuality =\n typeof video.getVideoPlaybackQuality === \"function\"\n ? video.getVideoPlaybackQuality()\n : null;\n\n let source = \"MP4\";\n let bitrate = \"N/A\";\n let quality = getQualityLabel();\n let codec = \"N/A\";\n let mimeType = video.currentSrc.includes(\".mpd\")\n ? \"application/dash+xml\"\n : video.currentSrc.includes(\".m3u8\")\n ? \"application/vnd.apple.mpegurl\"\n : \"video/mp4\";\n let audio = \"N/A\";\n let bitrateValue = 0;\n\n if (hlsRef.current) {\n source = \"HLS\";\n const hls = hlsRef.current;\n const levelIndex =\n hls.currentLevel >= 0\n ? hls.currentLevel\n : hls.loadLevel >= 0\n ? hls.loadLevel\n : hls.nextAutoLevel >= 0\n ? hls.nextAutoLevel\n : -1;\n const level = levelIndex >= 0 ? hls.levels[levelIndex] : null;\n bitrateValue = level?.bitrate ?? 0;\n bitrate = formatBitrate(bitrateValue);\n quality = level?.height ? `${level.height}p` : getQualityLabel();\n codec =\n level?.codecSet ||\n [level?.videoCodec, level?.audioCodec].filter(Boolean).join(\" / \") ||\n \"N/A\";\n mimeType = \"application/vnd.apple.mpegurl\";\n audio = level?.audioCodec || \"AAC/Unknown\";\n } else if (dashRef.current) {\n source = \"DASH\";\n const representation = dashRef.current.getCurrentRepresentationForType?.(\"video\");\n const audioTrack = dashRef.current.getCurrentTrackFor?.(\"audio\");\n const throughput = dashRef.current.getSafeAverageThroughput?.(\"video\");\n bitrateValue = representation?.bandwidth ?? throughput ?? 0;\n bitrate = formatBitrate(bitrateValue);\n quality = representation?.height ? `${representation.height}p` : getQualityLabel();\n codec = representation?.codecs || audioTrack?.codec || \"N/A\";\n mimeType = representation?.mimeType || audioTrack?.mimeType || \"application/dash+xml\";\n audio = [audioTrack?.codec, audioTrack?.lang].filter(Boolean).join(\" / \") || \"N/A\";\n }\n\n setBitrateHistory((previous) => [...previous.slice(-39), bitrateValue / 1_000_000]);\n setBufferHistory((previous) => [...previous.slice(-39), bufferedAhead]);\n\n setPlaybackStats({\n source,\n resolution:\n video.videoWidth && video.videoHeight ? `${video.videoWidth}x${video.videoHeight}` : \"0x0\",\n quality,\n bitrate,\n codec,\n mimeType,\n audio,\n bufferHealth: `${bufferedAhead.toFixed(1)}s`,\n droppedFrames: String(playbackQuality?.droppedVideoFrames ?? 0),\n fps:\n video.currentTime > 0 && playbackQuality?.totalVideoFrames\n ? `${Math.round(\n ((playbackQuality.totalVideoFrames ?? 0) - (playbackQuality.droppedVideoFrames ?? 0)) /\n Math.max(video.currentTime, 1),\n )}`\n : \"N/A\",\n playbackRate: `${video.playbackRate}x`,\n state: video.paused ? \"Paused\" : video.readyState < 3 ? \"Buffering\" : \"Playing\",\n });\n };\n\n updateStats();\n const intervalId = window.setInterval(updateStats, 500);\n return () => window.clearInterval(intervalId);\n }, [src, playbackRate, currentQuality, qualities]);\n\n const hasCaptions = Boolean(captionsSrc);\n const hasQualityOptions = qualities.length > 0;\n\n const getTimelinePercent = (clientX: number) => {\n const rect = timelineRef.current?.getBoundingClientRect();\n if (!rect || rect.width === 0) return 0;\n const rawPosition = clientX - rect.left;\n return Math.min(Math.max(rawPosition / rect.width, 0), 1);\n };\n\n const getThumbnailForTime = (time: number) => {\n if (thumbnails.length === 0) return null;\n\n return (\n thumbnails.find((thumbnail) => time >= thumbnail.startTime && time <= thumbnail.endTime) ||\n null\n );\n };\n\n const updateTimelinePreview = (event: React.PointerEvent | PointerEvent) => {\n const percent = getTimelinePercent(event.clientX);\n const time = percent * duration;\n\n setPreviewPosition(percent);\n setPreviewTime(time);\n\n if (duration > 0) {\n const thumbnail = getThumbnailForTime(time);\n if (thumbnail) {\n setActiveThumbnail(thumbnail);\n } else if (isScrubbing && scrubStartThumbnail.current) {\n setActiveThumbnail(scrubStartThumbnail.current);\n } else if (!isScrubbing) {\n setActiveThumbnail(null);\n }\n }\n\n if (isScrubbing) {\n event.preventDefault();\n setTimelineProgress(percent);\n }\n };\n\n const beginScrubbing = (event: React.PointerEvent) => {\n if (event.pointerType === \"mouse\" && event.button !== 0) return;\n wasPlayingBeforeScrub.current = !videoRef.current?.paused;\n scrubStartThumbnail.current = getThumbnailForTime(videoRef.current?.currentTime ?? 0);\n setIsScrubbing(true);\n videoRef.current?.pause();\n updateTimelinePreview(event);\n };\n\n const endScrubbing = (event: PointerEvent) => {\n if (!isScrubbing) return;\n setIsScrubbing(false);\n const percent = getTimelinePercent(event.clientX);\n if (videoRef.current) {\n const nextTime = percent * (videoRef.current.duration || 0);\n videoRef.current.currentTime = nextTime;\n setCurrentTime(nextTime);\n setPreviewTime(nextTime);\n if (wasPlayingBeforeScrub.current) {\n videoRef.current.play().catch(console.error);\n }\n }\n scrubStartThumbnail.current = null;\n };\n\n useEffect(() => {\n if (isScrubbing) {\n const onPointerMove = (event: PointerEvent) => updateTimelinePreview(event);\n document.addEventListener(\"pointermove\", onPointerMove);\n document.addEventListener(\"pointerup\", endScrubbing);\n return () => {\n document.removeEventListener(\"pointermove\", onPointerMove);\n document.removeEventListener(\"pointerup\", endScrubbing);\n };\n }\n return undefined;\n }, [isScrubbing, duration, thumbnails]);\n\n const VolumeIcon = () => {\n if (isMuted || volume === 0) return <VolumeX size={18} className=\"control-icon\" />;\n if (volume < 0.5) return <Volume1 size={18} className=\"control-icon\" />;\n return <Volume2 size={18} className=\"control-icon\" />;\n };\n\n return (\n <main className=\"svp-root w-full max-w-[1180px] mx-auto py-8 px-4\">\n <section className=\"mb-6\">\n {eyebrow ? (\n <p className=\"m-0 mb-2 text-youtube-muted uppercase tracking-wider text-xs font-medium\">\n {eyebrow}\n </p>\n ) : null}\n <h1 className=\"m-0 text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight mb-4\">{title}</h1>\n {description ? (\n <p className=\"max-w-2xl m-0 text-youtube-muted text-base leading-relaxed\">{description}</p>\n ) : null}\n {badges.length > 0 ? (\n <ul className=\"list-none flex flex-wrap gap-2 p-0 mt-5\">\n {badges.map((badge) => (\n <li\n key={badge}\n className=\"px-3 py-1 bg-white/10 rounded-full text-youtube-text text-sm font-medium\"\n >\n {badge}\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n\n <section\n className={`bg-youtube-panel shadow-2xl ring-1 ring-white/5 transition-[width,transform,border-radius] duration-300 ease-out ${\n isTheater\n ? \"relative left-1/2 w-screen max-w-none -translate-x-1/2 rounded-none md:rounded-2xl\"\n : \"rounded-xl overflow-hidden\"\n }`}\n >\n <div\n ref={containerRef}\n className={`relative flex justify-center bg-black group transition-[max-height] duration-300 ease-out ${\n isTheater ? \"min-h-[56.25vw] max-h-[82vh] w-full\" : \"\"\n } ${isFullscreen ? \"max-h-screen w-full\" : \"\"} ${isUserInactive ? \"user-inactive\" : \"\"}`}\n >\n {showStatsForNerds ? (\n <div className=\"stats-panel absolute left-3 top-3 z-30 w-[min(92vw,360px)] rounded-lg border border-white/10 bg-black/75 p-2.5 text-[10px] leading-4 text-white backdrop-blur-sm\">\n <div className=\"mb-2 text-[10px] font-semibold uppercase tracking-[0.2em] text-white/55\">\n Stats for nerds\n </div>\n <div className=\"space-y-1.5\">\n <div className=\"stats-row\">\n <span className=\"stats-key\">Buffer</span>\n <div className=\"stats-value-wrap\">\n <span>{playbackStats.bufferHealth}</span>\n <div className=\"stats-graph\">{renderSparkline(bufferHistory, \"text-white/80\")}</div>\n </div>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Bitrate</span>\n <div className=\"stats-value-wrap\">\n <span>{playbackStats.bitrate}</span>\n <div className=\"stats-graph\">{renderSparkline(bitrateHistory, \"text-youtube-accent\")}</div>\n </div>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Quality</span>\n <span className=\"stats-value-wrap\">{playbackStats.quality}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Codecs</span>\n <span className=\"stats-value-wrap\">{playbackStats.codec}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Audio</span>\n <span className=\"stats-value-wrap\">{playbackStats.audio}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Viewport</span>\n <span className=\"stats-value-wrap\">{playbackStats.resolution}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Mime</span>\n <span className=\"stats-value-wrap\">{playbackStats.mimeType}</span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Frames</span>\n <span className=\"stats-value-wrap\">\n {playbackStats.fps} fps / {playbackStats.droppedFrames} dropped\n </span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">State</span>\n <span className=\"stats-value-wrap\">\n {playbackStats.state} / {playbackStats.playbackRate}\n </span>\n </div>\n <div className=\"stats-row\">\n <span className=\"stats-key\">Source</span>\n <span className=\"stats-value-wrap\">{playbackStats.source}</span>\n </div>\n </div>\n </div>\n ) : null}\n\n <button\n onClick={togglePlay}\n aria-label=\"Play video\"\n className={`absolute inset-1/2 -translate-x-1/2 -translate-y-1/2 grid place-items-center w-16 h-16 md:w-20 md:h-20 rounded-full bg-black/50 backdrop-blur-md text-white z-10 shadow-lg transition-all duration-200 hover:bg-youtube-accent ${isPlaying ? \"opacity-0 scale-75 pointer-events-none\" : \"opacity-100 scale-100\"}`}\n >\n <Play size={32} className=\"ml-1 control-icon\" fill=\"currentColor\" />\n </button>\n\n <div\n className={`video-controls-container absolute bottom-0 left-0 right-0 px-3 pb-2 pt-16 bg-gradient-to-t from-black/90 to-transparent text-white z-20 transition-all duration-500 ease-out ${isUserInactive && isPlaying ? \"opacity-0 pointer-events-none cursor-none translate-y-2\" : \"opacity-100 translate-y-0\"}`}\n >\n <div\n ref={timelineRef}\n className=\"timeline-container h-4 mx-1 cursor-pointer flex items-center relative group/timeline\"\n onPointerDown={beginScrubbing}\n onPointerMove={(event) => {\n if (!isScrubbing) updateTimelinePreview(event);\n }}\n onPointerEnter={() => setIsHoveringTimeline(true)}\n onPointerLeave={() => setIsHoveringTimeline(false)}\n >\n <div className=\"timeline-progress w-full h-[3px] bg-youtube-track relative transition-[height] duration-150\">\n <div\n className=\"absolute inset-y-0 left-0 bg-white/40\"\n style={{\n width: `${previewPosition * 100}%`,\n display: isHoveringTimeline || isScrubbing ? \"block\" : \"none\",\n }}\n />\n <div\n className=\"absolute inset-y-0 left-0 bg-youtube-accent transition-all duration-200 ease-out\"\n style={{\n width: `${(isScrubbing ? timelineProgress : duration ? currentTime / duration : 0) * 100}%`,\n }}\n />\n <div\n className=\"timeline-thumb absolute top-1/2 w-3.5 h-3.5 rounded-full bg-youtube-accent transition-all duration-200 ease-out\"\n style={{\n left: `${(isScrubbing ? timelineProgress : duration ? currentTime / duration : 0) * 100}%`,\n transform: `translate(-50%, -50%) scale(${isHoveringTimeline || isScrubbing ? 1 : 0})`,\n }}\n />\n\n {activeThumbnail ? (\n <div\n className={`pointer-events-none absolute bottom-6 border-2 border-white rounded-lg shadow-lg overflow-hidden bg-black -translate-x-1/2 transition-opacity duration-200 ${isScrubbing || isHoveringTimeline ? \"opacity-100\" : \"opacity-0\"}`}\n style={{ left: `${previewPosition * 100}%`, width: \"160px\", height: \"110px\" }}\n >\n <div\n style={{\n backgroundImage: `url(${activeThumbnail.url})`,\n backgroundPosition: `-${activeThumbnail.x}px -${activeThumbnail.y}px`,\n width: `${activeThumbnail.w}px`,\n height: `${activeThumbnail.h}px`,\n transform: `scale(${160 / activeThumbnail.w})`,\n transformOrigin: \"top left\",\n }}\n />\n <div className=\"absolute inset-x-0 bottom-0 bg-black/80 px-2 py-1 text-center text-[11px] text-white\">\n {formatDuration(previewTime)}\n </div>\n </div>\n ) : isScrubbing || isHoveringTimeline ? (\n <div\n className=\"pointer-events-none absolute bottom-6 min-w-16 rounded-md bg-black/85 px-2 py-1 text-center text-[11px] text-white shadow-lg -translate-x-1/2 transition-opacity duration-200\"\n style={{ left: `${previewPosition * 100}%` }}\n >\n {formatDuration(previewTime)}\n </div>\n ) : null}\n </div>\n </div>\n\n <div className=\"flex items-center justify-between gap-3 pt-2 px-1\">\n <div className=\"flex min-w-0 items-center gap-1 sm:gap-2\">\n <button\n onClick={togglePlay}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n >\n {isPlaying ? (\n <Pause size={18} fill=\"currentColor\" className=\"control-icon\" />\n ) : (\n <Play size={18} fill=\"currentColor\" className=\"control-icon\" />\n )}\n </button>\n\n <div className=\"volume-container flex items-center gap-1\">\n <button\n onClick={toggleMute}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n >\n <VolumeIcon />\n </button>\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"any\"\n value={volume}\n onChange={handleVolumeChange}\n className=\"volume-slider h-1\"\n style={{ \"--volume-percent\": `${volume * 100}%` } as React.CSSProperties}\n />\n </div>\n\n <div className=\"flex min-w-0 items-center gap-1 text-[13px] font-sans text-white/90 tabular-nums whitespace-nowrap\">\n <span>{formatDuration(currentTime)}</span>\n <span className=\"text-white/50\">/</span>\n <span>{formatDuration(duration)}</span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-1 sm:gap-2\">\n <button\n onClick={toggleCaptions}\n disabled={!hasCaptions}\n className={`control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all disabled:opacity-40 disabled:cursor-not-allowed ${captionsEnabled ? \"text-youtube-accent\" : \"\"}`}\n title=\"Subtitles/closed captions (c)\"\n >\n <Captions size={18} className=\"control-icon\" />\n </button>\n\n <div ref={settingsRef} className=\"relative\">\n <button\n onClick={() => {\n setShowSettings((prev) => !prev);\n setSettingsView(\"root\");\n }}\n className={`control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all ${showSettings ? \"bg-white/10 text-youtube-accent\" : \"\"}`}\n title=\"Settings\"\n >\n <Settings\n size={18}\n className={`control-icon ${showSettings ? \"rotate-[22deg] scale-110\" : \"\"} transition-transform duration-300`}\n />\n </button>\n\n {showSettings ? (\n <div\n className={`settings-panel absolute bottom-full right-0 mb-4 w-56 bg-black/40 backdrop-blur-sm rounded-xl overflow-hidden shadow-2xl z-50 border border-white/10 ${\n settingsView === \"root\" ? \"settings-panel-root\" : \"max-h-[min(28rem,calc(100vh-10rem))]\"\n }`}\n >\n <div\n className=\"settings-slider\"\n style={{\n width: \"300%\",\n transform: `translateX(${\n settingsView === \"root\"\n ? \"0%\"\n : settingsView === \"quality\"\n ? \"-33.3333%\"\n : \"-66.6667%\"\n })`,\n }}\n >\n <div className=\"settings-view settings-scroll\">\n <button\n onClick={() => setSettingsView(\"quality\")}\n disabled={!hasQualityOptions}\n className=\"settings-item disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n <div>\n <div className=\"settings-label\">Quality</div>\n <div className=\"settings-value\">\n {hasQualityOptions ? getQualityLabel() : \"Unavailable\"}\n </div>\n </div>\n <ChevronRight size={16} className=\"text-white/55\" />\n </button>\n\n <button\n onClick={() => setSettingsView(\"speed\")}\n className=\"settings-item\"\n >\n <div>\n <div className=\"settings-label\">Playback speed</div>\n <div className=\"settings-value\">{playbackRate}x</div>\n </div>\n <ChevronRight size={16} className=\"text-white/55\" />\n </button>\n\n <button\n onClick={() => {\n setShowStatsForNerds((prev) => !prev);\n setShowSettings(false);\n setSettingsView(\"root\");\n }}\n className=\"settings-item\"\n >\n <div>\n <div className=\"settings-label\">Stats for nerds</div>\n <div className=\"settings-value\">\n {showStatsForNerds ? \"On\" : \"Off\"}\n </div>\n </div>\n <span\n className={`h-2 w-2 rounded-full ${\n showStatsForNerds ? \"bg-youtube-accent\" : \"bg-white/25\"\n }`}\n />\n </button>\n </div>\n\n <div className=\"settings-view settings-scroll border-l border-white/10\">\n <button\n onClick={() => setSettingsView(\"root\")}\n className=\"settings-back\"\n >\n <ChevronLeft size={16} />\n <span>Quality</span>\n </button>\n <button\n onClick={() => changeQuality(\"auto\")}\n className={`settings-option ${currentQuality === \"auto\" ? \"settings-option-active\" : \"\"}`}\n >\n <span>Auto</span>\n {currentQuality === \"auto\" ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n {qualities.length > 0 ? (\n qualities.map((quality) => (\n <button\n key={quality.height}\n onClick={() => changeQuality(quality.index)}\n className={`settings-option ${currentQuality === quality.index ? \"settings-option-active\" : \"\"}`}\n >\n <span>{quality.height}p</span>\n {currentQuality === quality.index ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n ))\n ) : (\n <div className=\"px-4 py-3 text-[13px] text-white/55\">No quality options</div>\n )}\n </div>\n\n <div className=\"settings-view settings-scroll border-l border-white/10\">\n <button\n onClick={() => setSettingsView(\"root\")}\n className=\"settings-back\"\n >\n <ChevronLeft size={16} />\n <span>Playback speed</span>\n </button>\n {PLAYBACK_RATES.map((rate) => (\n <button\n key={rate}\n onClick={() => changePlaybackRate(rate)}\n className={`settings-option ${playbackRate === rate ? \"settings-option-active\" : \"\"}`}\n >\n <span>{rate}x</span>\n {playbackRate === rate ? (\n <span className=\"w-1.5 h-1.5 rounded-full bg-youtube-accent\" />\n ) : null}\n </button>\n ))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n\n <button\n onClick={togglePictureInPicture}\n disabled={!pipSupported}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all disabled:opacity-40 disabled:cursor-not-allowed\"\n title={pipSupported ? \"Miniplayer (i)\" : \"Picture-in-picture not supported\"}\n >\n <PictureInPicture size={18} className=\"control-icon\" />\n </button>\n\n <button\n onClick={() => setTheaterMode((prev) => !prev)}\n className=\"control-btn h-9 w-9 items-center justify-center rounded-md transition-all hidden sm:flex\"\n title=\"Theater mode (t)\"\n >\n {isTheater ? (\n <Tv size={18} className=\"control-icon\" />\n ) : (\n <RectangleHorizontal size={18} className=\"control-icon\" />\n )}\n </button>\n\n <button\n onClick={toggleFullscreen}\n className=\"control-btn h-9 w-9 flex items-center justify-center rounded-md transition-all\"\n title=\"Fullscreen (f)\"\n >\n {isFullscreen ? (\n <Minimize size={18} className=\"control-icon\" />\n ) : (\n <Maximize size={18} className=\"control-icon\" />\n )}\n </button>\n </div>\n </div>\n </div>\n\n <video\n ref={videoRef}\n preload=\"metadata\"\n className=\"w-full bg-black block\"\n onClick={togglePlay}\n onDoubleClick={toggleFullscreen}\n onPlay={() => {\n setIsPlaying(true);\n queueIdleFade();\n }}\n onPause={() => {\n setIsPlaying(false);\n setIsUserInactive(false);\n }}\n onTimeUpdate={(event) => {\n const time = event.currentTarget.currentTime;\n if (time === 0 && currentTime > 1 && !isScrubbing) return;\n setCurrentTime(time);\n }}\n onDurationChange={(event) => setDuration(event.currentTarget.duration)}\n onLoadedMetadata={(event) => {\n setDuration(event.currentTarget.duration);\n }}\n onVolumeChange={(event) => {\n setIsMuted(event.currentTarget.muted);\n setVolume(event.currentTarget.muted ? 0 : event.currentTarget.volume);\n }}\n >\n {captionsSrc ? (\n <track kind=\"captions\" src={captionsSrc} srcLang=\"en\" label=\"English\" default={false} />\n ) : null}\n </video>\n </div>\n </section>\n </main>\n );\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "seamless-vid-player",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "YouTube-style React video player with HLS, DASH, scrubbing previews, theater mode, and a polished settings UI.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"dev": "next dev",
|
|
24
24
|
"build:app": "next build",
|
|
25
|
-
"build:styles": "tailwindcss -i ./src/index.css -o ./dist/index.css --minify",
|
|
25
|
+
"build:styles": "tailwindcss -c ./tailwind.package.config.js -i ./src/index.css -o ./dist/index.css --minify",
|
|
26
26
|
"build": "tsup && npm run build:styles",
|
|
27
27
|
"prepublishOnly": "npm run build",
|
|
28
28
|
"start": "next start",
|