@mottosports/motto-video-player 1.0.1-rc.8 → 1.0.1-rc.80
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/README.md +39 -0
- package/dist/index.d.mts +246 -66
- package/dist/index.d.ts +246 -66
- package/dist/index.js +2082 -683
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2029 -631
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -6
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import "shaka-player/dist/controls.css";
|
|
5
|
+
|
|
3
6
|
// #style-inject:#style-inject
|
|
4
7
|
function styleInject(css, { insertAt } = {}) {
|
|
5
8
|
if (!css || typeof document === "undefined") return;
|
|
@@ -22,73 +25,1031 @@ function styleInject(css, { insertAt } = {}) {
|
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
// src/
|
|
26
|
-
styleInject('/*! tailwindcss v4.1.8 | MIT License | https://tailwindcss.com */\n@layer properties;\n@layer theme, base, components, utilities;\n@layer theme {\n :root,\n :host {\n --font-sans:\n ui-sans-serif,\n system-ui,\n sans-serif,\n "Apple Color Emoji",\n "Segoe UI Emoji",\n "Segoe UI Symbol",\n "Noto Color Emoji";\n --font-mono:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Monaco,\n Consolas,\n "Liberation Mono",\n "Courier New",\n monospace;\n --color-red-600: oklch(57.7% 0.245 27.325);\n --color-black: #000;\n --color-white: #fff;\n --spacing: 0.25rem;\n --text-xs: 0.75rem;\n --text-xs--line-height: calc(1 / 0.75);\n --text-sm: 0.875rem;\n --text-sm--line-height: calc(1.25 / 0.875);\n --text-base: 1rem;\n --text-base--line-height: calc(1.5 / 1);\n --text-lg: 1.125rem;\n --text-lg--line-height: calc(1.75 / 1.125);\n --text-xl: 1.25rem;\n --text-xl--line-height: calc(1.75 / 1.25);\n --text-2xl: 1.5rem;\n --text-2xl--line-height: calc(2 / 1.5);\n --text-5xl: 3rem;\n --text-5xl--line-height: 1;\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --tracking-wide: 0.025em;\n --tracking-widest: 0.1em;\n --radius-md: 0.375rem;\n --radius-2xl: 1rem;\n --animate-spin: spin 1s linear infinite;\n --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n --aspect-video: 16 / 9;\n --default-transition-duration: 150ms;\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n --default-font-family: var(--font-sans);\n --default-mono-font-family: var(--font-mono);\n }\n}\n@layer base {\n *,\n ::after,\n ::before,\n ::backdrop,\n ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n }\n html,\n :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n tab-size: 4;\n font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");\n font-feature-settings: var(--default-font-feature-settings, normal);\n font-variation-settings: var(--default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n }\n hr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n }\n abbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n }\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n font-size: inherit;\n font-weight: inherit;\n }\n a {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n }\n b,\n strong {\n font-weight: bolder;\n }\n code,\n kbd,\n samp,\n pre {\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\n font-size: 1em;\n }\n small {\n font-size: 80%;\n }\n sub,\n sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n sub {\n bottom: -0.25em;\n }\n sup {\n top: -0.5em;\n }\n table {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n }\n :-moz-focusring {\n outline: auto;\n }\n progress {\n vertical-align: baseline;\n }\n summary {\n display: list-item;\n }\n ol,\n ul,\n menu {\n list-style: none;\n }\n img,\n svg,\n video,\n canvas,\n audio,\n iframe,\n embed,\n object {\n display: block;\n vertical-align: middle;\n }\n img,\n video {\n max-width: 100%;\n height: auto;\n }\n button,\n input,\n select,\n optgroup,\n textarea,\n ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n }\n :where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n }\n :where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n }\n ::file-selector-button {\n margin-inline-end: 4px;\n }\n ::placeholder {\n opacity: 1;\n }\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n }\n textarea {\n resize: vertical;\n }\n ::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n ::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n }\n ::-webkit-datetime-edit {\n display: inline-flex;\n }\n ::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n }\n ::-webkit-datetime-edit,\n ::-webkit-datetime-edit-year-field,\n ::-webkit-datetime-edit-month-field,\n ::-webkit-datetime-edit-day-field,\n ::-webkit-datetime-edit-hour-field,\n ::-webkit-datetime-edit-minute-field,\n ::-webkit-datetime-edit-second-field,\n ::-webkit-datetime-edit-millisecond-field,\n ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n }\n :-moz-ui-invalid {\n box-shadow: none;\n }\n button,\n input:where([type=button], [type=reset], [type=submit]),\n ::file-selector-button {\n appearance: button;\n }\n ::-webkit-inner-spin-button,\n ::-webkit-outer-spin-button {\n height: auto;\n }\n [hidden]:where(:not([hidden=until-found])) {\n display: none !important;\n }\n}\n@layer utilities {\n .pointer-events-auto {\n pointer-events: auto;\n }\n .pointer-events-none {\n pointer-events: none;\n }\n .visible {\n visibility: visible;\n }\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n }\n .absolute {\n position: absolute;\n }\n .fixed {\n position: fixed;\n }\n .relative {\n position: relative;\n }\n .static {\n position: static;\n }\n .inset-0 {\n inset: calc(var(--spacing) * 0);\n }\n .top-0 {\n top: calc(var(--spacing) * 0);\n }\n .top-4 {\n top: calc(var(--spacing) * 4);\n }\n .right-0 {\n right: calc(var(--spacing) * 0);\n }\n .right-4 {\n right: calc(var(--spacing) * 4);\n }\n .bottom-0 {\n bottom: calc(var(--spacing) * 0);\n }\n .bottom-4 {\n bottom: calc(var(--spacing) * 4);\n }\n .left-0 {\n left: calc(var(--spacing) * 0);\n }\n .left-4 {\n left: calc(var(--spacing) * 4);\n }\n .z-10 {\n z-index: 10;\n }\n .z-50 {\n z-index: 50;\n }\n .container {\n width: 100%;\n @media (width >= 40rem) {\n max-width: 40rem;\n }\n @media (width >= 48rem) {\n max-width: 48rem;\n }\n @media (width >= 64rem) {\n max-width: 64rem;\n }\n @media (width >= 80rem) {\n max-width: 80rem;\n }\n @media (width >= 96rem) {\n max-width: 96rem;\n }\n }\n .m-6 {\n margin: calc(var(--spacing) * 6);\n }\n .mt-1 {\n margin-top: calc(var(--spacing) * 1);\n }\n .mt-3 {\n margin-top: calc(var(--spacing) * 3);\n }\n .mb-2 {\n margin-bottom: calc(var(--spacing) * 2);\n }\n .mb-6 {\n margin-bottom: calc(var(--spacing) * 6);\n }\n .flex {\n display: flex;\n }\n .grid {\n display: grid;\n }\n .hidden {\n display: none;\n }\n .aspect-video {\n aspect-ratio: var(--aspect-video);\n }\n .h-2 {\n height: calc(var(--spacing) * 2);\n }\n .h-8 {\n height: calc(var(--spacing) * 8);\n }\n .h-24 {\n height: calc(var(--spacing) * 24);\n }\n .h-full {\n height: 100%;\n }\n .w-2 {\n width: calc(var(--spacing) * 2);\n }\n .w-8 {\n width: calc(var(--spacing) * 8);\n }\n .w-24 {\n width: calc(var(--spacing) * 24);\n }\n .w-full {\n width: 100%;\n }\n .animate-pulse {\n animation: var(--animate-pulse);\n }\n .animate-spin {\n animation: var(--animate-spin);\n }\n .auto-cols-max {\n grid-auto-columns: max-content;\n }\n .grid-flow-col {\n grid-auto-flow: column;\n }\n .flex-col {\n flex-direction: column;\n }\n .items-center {\n align-items: center;\n }\n .justify-center {\n justify-content: center;\n }\n .justify-stretch {\n justify-content: stretch;\n }\n .gap-1 {\n gap: calc(var(--spacing) * 1);\n }\n .gap-5 {\n gap: calc(var(--spacing) * 5);\n }\n .overflow-hidden {\n overflow: hidden;\n }\n .rounded-full {\n border-radius: calc(infinity * 1px);\n }\n .rounded-md {\n border-radius: var(--radius-md);\n }\n .border-b-2 {\n border-bottom-style: var(--tw-border-style);\n border-bottom-width: 2px;\n }\n .border-white {\n border-color: var(--color-white);\n }\n .bg-\\[\\#151515\\] {\n background-color: #151515;\n }\n .bg-black {\n background-color: var(--color-black);\n }\n .bg-red-600 {\n background-color: var(--color-red-600);\n }\n .bg-white {\n background-color: var(--color-white);\n }\n .bg-gradient-to-t {\n --tw-gradient-position: to top in oklab;\n background-image: linear-gradient(var(--tw-gradient-stops));\n }\n .from-black\\/70 {\n --tw-gradient-from: color-mix(in srgb, #000 70%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n --tw-gradient-from: color-mix(in oklab, var(--color-black) 70%, transparent);\n }\n --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));\n }\n .to-transparent {\n --tw-gradient-to: transparent;\n --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));\n }\n .bg-cover {\n background-size: cover;\n }\n .bg-center {\n background-position: center;\n }\n .bg-no-repeat {\n background-repeat: no-repeat;\n }\n .p-2 {\n padding: calc(var(--spacing) * 2);\n }\n .p-4 {\n padding: calc(var(--spacing) * 4);\n }\n .px-2 {\n padding-inline: calc(var(--spacing) * 2);\n }\n .px-4 {\n padding-inline: calc(var(--spacing) * 4);\n }\n .py-1 {\n padding-block: calc(var(--spacing) * 1);\n }\n .text-center {\n text-align: center;\n }\n .text-left {\n text-align: left;\n }\n .font-mono {\n font-family: var(--font-mono);\n }\n .text-2xl {\n font-size: var(--text-2xl);\n line-height: var(--tw-leading, var(--text-2xl--line-height));\n }\n .text-5xl {\n font-size: var(--text-5xl);\n line-height: var(--tw-leading, var(--text-5xl--line-height));\n }\n .text-base {\n font-size: var(--text-base);\n line-height: var(--tw-leading, var(--text-base--line-height));\n }\n .text-lg {\n font-size: var(--text-lg);\n line-height: var(--tw-leading, var(--text-lg--line-height));\n }\n .text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n .text-xl {\n font-size: var(--text-xl);\n line-height: var(--tw-leading, var(--text-xl--line-height));\n }\n .text-xs {\n font-size: var(--text-xs);\n line-height: var(--tw-leading, var(--text-xs--line-height));\n }\n .text-\\[10px\\] {\n font-size: 10px;\n }\n .font-bold {\n --tw-font-weight: var(--font-weight-bold);\n font-weight: var(--font-weight-bold);\n }\n .font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n }\n .font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n }\n .tracking-wide {\n --tw-tracking: var(--tracking-wide);\n letter-spacing: var(--tracking-wide);\n }\n .tracking-widest {\n --tw-tracking: var(--tracking-widest);\n letter-spacing: var(--tracking-widest);\n }\n .text-white {\n color: var(--color-white);\n }\n .uppercase {\n text-transform: uppercase;\n }\n .shadow-lg {\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow:\n var(--tw-inset-shadow),\n var(--tw-inset-ring-shadow),\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow);\n }\n .filter {\n 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,);\n }\n .md\\:rounded-2xl {\n @media (width >= 48rem) {\n border-radius: var(--radius-2xl);\n }\n }\n .md\\:rounded-2xl\\! {\n @media (width >= 48rem) {\n border-radius: var(--radius-2xl) !important;\n }\n }\n .md\\:text-base {\n @media (width >= 48rem) {\n font-size: var(--text-base);\n line-height: var(--tw-leading, var(--text-base--line-height));\n }\n }\n .md\\:text-sm {\n @media (width >= 48rem) {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n }\n .md\\:text-xl {\n @media (width >= 48rem) {\n font-size: var(--text-xl);\n line-height: var(--tw-leading, var(--text-xl--line-height));\n }\n }\n}\n@layer components {\n .motto-video-container {\n position: relative;\n width: 100%;\n min-height: 300px;\n }\n @supports (aspect-ratio: 16/9) {\n .motto-video-container {\n min-height: auto;\n }\n }\n .motto-video-responsive {\n position: absolute;\n top: calc(var(--spacing) * 0);\n left: calc(var(--spacing) * 0);\n height: 100%;\n width: 100%;\n }\n .motto-skip-button {\n position: absolute;\n top: calc(1/2 * 100%);\n z-index: 10;\n display: flex;\n height: calc(var(--spacing) * 16);\n width: calc(var(--spacing) * 16);\n --tw-translate-y: calc(calc(1/2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n cursor: pointer;\n align-items: center;\n justify-content: center;\n border-radius: calc(infinity * 1px);\n border-style: var(--tw-border-style);\n border-width: 0px;\n background-color: color-mix(in srgb, #000 70%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 70%, transparent);\n }\n font-size: var(--text-2xl);\n line-height: var(--tw-leading, var(--text-2xl--line-height));\n color: var(--color-white);\n opacity: 80%;\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 200ms;\n transition-duration: 200ms;\n &:hover {\n @media (hover: hover) {\n --tw-scale-x: 110%;\n --tw-scale-y: 110%;\n --tw-scale-z: 110%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n }\n &:hover {\n @media (hover: hover) {\n opacity: 100%;\n }\n }\n &:active {\n --tw-scale-x: 95%;\n --tw-scale-y: 95%;\n --tw-scale-z: 95%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n }\n .motto-skip-button-back {\n left: calc(var(--spacing) * 5);\n }\n .motto-skip-button-forward {\n right: calc(var(--spacing) * 5);\n }\n .motto-mobile-controls-overlay {\n position: absolute;\n inset: calc(var(--spacing) * 0);\n z-index: 20;\n display: flex;\n align-items: center;\n justify-content: center;\n transition-property: opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 300ms;\n transition-duration: 300ms;\n pointer-events: none;\n }\n .motto-mobile-controls-group {\n display: flex;\n align-items: center;\n gap: calc(var(--spacing) * 8);\n opacity: 100%;\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 200ms;\n transition-duration: 200ms;\n pointer-events: none;\n }\n .motto-mobile-play-button {\n display: flex;\n height: calc(var(--spacing) * 14);\n width: calc(var(--spacing) * 14);\n cursor: pointer;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n border-radius: calc(infinity * 1px);\n border-style: var(--tw-border-style);\n border-width: 0px;\n background-color: color-mix(in srgb, #000 30%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 30%, transparent);\n }\n color: var(--color-white);\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow:\n var(--tw-inset-shadow),\n var(--tw-inset-ring-shadow),\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow);\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 200ms;\n transition-duration: 200ms;\n pointer-events: auto;\n }\n .motto-mobile-play-button:active {\n --tw-scale-x: 95%;\n --tw-scale-y: 95%;\n --tw-scale-z: 95%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n .motto-mobile-play-button svg {\n height: calc(var(--spacing) * 7);\n width: calc(var(--spacing) * 7);\n }\n .motto-mobile-skip-button {\n display: flex;\n height: calc(var(--spacing) * 10);\n width: calc(var(--spacing) * 10);\n cursor: pointer;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n border-radius: calc(infinity * 1px);\n border-style: var(--tw-border-style);\n border-width: 0px;\n background-color: color-mix(in srgb, #000 30%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 30%, transparent);\n }\n color: var(--color-white);\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow:\n var(--tw-inset-shadow),\n var(--tw-inset-ring-shadow),\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow);\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 200ms;\n transition-duration: 200ms;\n pointer-events: auto;\n }\n .motto-mobile-skip-button:active {\n --tw-scale-x: 95%;\n --tw-scale-y: 95%;\n --tw-scale-z: 95%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n .motto-mobile-skip-button svg {\n height: calc(var(--spacing) * 6);\n width: calc(var(--spacing) * 6);\n }\n}\n@media (min-width: 768px) {\n .motto-mobile-controls-overlay {\n display: none !important;\n }\n}\n@media (max-width: 767px) {\n .shaka-controls-container .motto-native-skip-button,\n .shaka-controls-container .motto-skip-back-button,\n .shaka-controls-container .motto-skip-forward-button,\n .shaka-controls-container .shaka-button[title*="Skip back"],\n .shaka-controls-container .shaka-button[title*="Skip forward"],\n .shaka-controls-container .shaka-button[aria-label*="Skip back"],\n .shaka-controls-container .shaka-button[aria-label*="Skip forward"],\n .shaka-controls-container button[title*="Skip back"],\n .shaka-controls-container button[title*="Skip forward"],\n .shaka-controls-container button[aria-label*="Skip back"],\n .shaka-controls-container button[aria-label*="Skip forward"],\n .motto-native-skip-button:not(.motto-mobile-skip-button),\n .motto-skip-back-button:not(.motto-mobile-skip-button),\n .motto-skip-forward-button:not(.motto-mobile-skip-button),\n .shaka-button[title*="Skip back"]:not(.motto-mobile-skip-button),\n .shaka-button[title*="Skip forward"]:not(.motto-mobile-skip-button),\n .shaka-button[aria-label*="Skip back"]:not(.motto-mobile-skip-button),\n .shaka-button[aria-label*="Skip forward"]:not(.motto-mobile-skip-button),\n button[title*="Skip back"]:not(.motto-mobile-skip-button),\n button[title*="Skip forward"]:not(.motto-mobile-skip-button),\n button[aria-label*="Skip back"]:not(.motto-mobile-skip-button),\n button[aria-label*="Skip forward"]:not(.motto-mobile-skip-button) {\n display: none !important;\n visibility: hidden !important;\n opacity: 0 !important;\n width: 0 !important;\n height: 0 !important;\n padding: 0 !important;\n margin: 0 !important;\n }\n .motto-mobile-skip-button {\n display: flex !important;\n visibility: visible !important;\n opacity: 1 !important;\n }\n}\n.shaka-seek-bar-container {\n height: 6px !important;\n width: 100% !important;\n margin: 8px 0 !important;\n border-radius: 4px !important;\n position: relative !important;\n border-top: none !important;\n border-bottom: none !important;\n box-shadow: none !important;\n}\n.shaka-seek-bar {\n height: 6px !important;\n width: 100% !important;\n -webkit-appearance: none !important;\n appearance: none !important;\n background: transparent !important;\n cursor: pointer !important;\n border: none !important;\n outline: none !important;\n position: absolute !important;\n top: 0 !important;\n left: 0 !important;\n border-radius: 4px !important;\n}\n.shaka-seek-bar::-webkit-slider-runnable-track {\n height: 6px !important;\n background: transparent !important;\n border-radius: 4px !important;\n border: none !important;\n}\n.shaka-seek-bar::-moz-range-track {\n height: 6px !important;\n background: transparent !important;\n border-radius: 4px !important;\n border: none !important;\n}\n.shaka-seek-bar::-webkit-slider-thumb {\n -webkit-appearance: none !important;\n appearance: none !important;\n width: 16px !important;\n height: 16px !important;\n border-radius: 50% !important;\n background: #ffffff !important;\n cursor: pointer !important;\n border: 2px solid #ffffff !important;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;\n margin-top: -4px !important;\n}\n.shaka-seek-bar::-moz-range-thumb {\n width: 16px !important;\n height: 16px !important;\n border-radius: 50% !important;\n background: #ffffff !important;\n cursor: pointer !important;\n border: 2px solid #ffffff !important;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;\n margin-top: -4px !important;\n}\n.motto-skip-back-button,\n.motto-skip-forward-button,\n.motto-native-skip-button {\n background: transparent !important;\n border: none !important;\n padding: 4px !important;\n margin: 0px !important;\n cursor: pointer !important;\n color: #ffffff !important;\n transition: all 0.2s ease !important;\n min-width: 32px !important;\n height: 32px !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n border-radius: 4px !important;\n width: 25px;\n}\n.motto-skip-back-button:hover,\n.motto-skip-forward-button:hover,\n.motto-native-skip-button:hover {\n opacity: 0.8 !important;\n background: transparent !important;\n transform: scale(1.05) !important;\n}\n.motto-skip-back-button:active,\n.motto-skip-forward-button:active,\n.motto-native-skip-button:active {\n transform: scale(0.95) !important;\n}\n.motto-skip-back-button svg,\n.motto-skip-forward-button svg,\n.motto-native-skip-button svg {\n width: 24px !important;\n height: 24px !important;\n}\n@media (max-width: 767px) {\n .shaka-controls-container .motto-native-skip-button,\n .shaka-controls-container .motto-skip-back-button,\n .shaka-controls-container .motto-skip-forward-button,\n .shaka-controls-container .shaka-play-button,\n .shaka-controls-container .shaka-pause-button {\n display: none !important;\n }\n}\n.shaka-spinner-svg {\n color: white !important;\n fill: white !important;\n}\n.shaka-spinner-path {\n stroke: white !important;\n fill: none !important;\n}\n.shaka-spinner-container {\n color: white !important;\n}\n.shaka-buffering-spinner {\n color: white !important;\n fill: white !important;\n}\n.shaka-buffering-spinner svg {\n color: white !important;\n fill: white !important;\n}\n.shaka-buffering-spinner path {\n stroke: white !important;\n fill: none !important;\n}\n[data-shaka-player-container] .shaka-spinner,\n[data-shaka-player-container] .spinner {\n color: white !important;\n border-color: white !important;\n}\n.material-icons.shaka-spinner {\n color: white !important;\n}\n.shaka-controls-container .shaka-spinner,\n.shaka-video-container .shaka-spinner {\n color: white !important;\n fill: white !important;\n}\n.shaka-controls-container .shaka-spinner svg,\n.shaka-video-container .shaka-spinner svg {\n color: white !important;\n fill: white !important;\n}\n.shaka-controls-container .shaka-spinner path,\n.shaka-video-container .shaka-spinner path {\n stroke: white !important;\n}\n.motto-video-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background:\n linear-gradient(\n 135deg,\n #1a1a1a 0%,\n #2d2d2d 100%);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n z-index: 10;\n transition: opacity 0.3s ease;\n}\n.motto-video-loading-overlay.hidden {\n opacity: 0;\n pointer-events: none;\n}\n.motto-video-loading-content {\n text-align: center;\n color: white;\n}\n.motto-video-loading-icon {\n width: 64px;\n height: 64px;\n margin-bottom: 16px;\n opacity: 0.7;\n}\n.motto-video-loading-text {\n font-size: 16px;\n font-weight: 500;\n margin-bottom: 8px;\n}\n.motto-video-loading-subtext {\n font-size: 14px;\n opacity: 0.7;\n}\n@keyframes pulse-live {\n 0% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.7;\n transform: scale(1.1);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n}\n.shaka-play-button-container {\n display: none !important;\n}\n@media (max-width: 767px) {\n .shaka-controls-container {\n z-index: 90 !important;\n height: 100px !important;\n bottom: 0 !important;\n top: unset !important;\n }\n}\n@property --tw-border-style { syntax: "*"; inherits: false; initial-value: solid; }\n@property --tw-gradient-position { syntax: "*"; inherits: false; }\n@property --tw-gradient-from { syntax: "<color>"; inherits: false; initial-value: #0000; }\n@property --tw-gradient-via { syntax: "<color>"; inherits: false; initial-value: #0000; }\n@property --tw-gradient-to { syntax: "<color>"; inherits: false; initial-value: #0000; }\n@property --tw-gradient-stops { syntax: "*"; inherits: false; }\n@property --tw-gradient-via-stops { syntax: "*"; inherits: false; }\n@property --tw-gradient-from-position { syntax: "<length-percentage>"; inherits: false; initial-value: 0%; }\n@property --tw-gradient-via-position { syntax: "<length-percentage>"; inherits: false; initial-value: 50%; }\n@property --tw-gradient-to-position { syntax: "<length-percentage>"; inherits: false; initial-value: 100%; }\n@property --tw-font-weight { syntax: "*"; inherits: false; }\n@property --tw-tracking { syntax: "*"; inherits: false; }\n@property --tw-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-shadow-color { syntax: "*"; inherits: false; }\n@property --tw-shadow-alpha { syntax: "<percentage>"; inherits: false; initial-value: 100%; }\n@property --tw-inset-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-inset-shadow-color { syntax: "*"; inherits: false; }\n@property --tw-inset-shadow-alpha { syntax: "<percentage>"; inherits: false; initial-value: 100%; }\n@property --tw-ring-color { syntax: "*"; inherits: false; }\n@property --tw-ring-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-inset-ring-color { syntax: "*"; inherits: false; }\n@property --tw-inset-ring-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-ring-inset { syntax: "*"; inherits: false; }\n@property --tw-ring-offset-width { syntax: "<length>"; inherits: false; initial-value: 0px; }\n@property --tw-ring-offset-color { syntax: "*"; inherits: false; initial-value: #fff; }\n@property --tw-ring-offset-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-blur { syntax: "*"; inherits: false; }\n@property --tw-brightness { syntax: "*"; inherits: false; }\n@property --tw-contrast { syntax: "*"; inherits: false; }\n@property --tw-grayscale { syntax: "*"; inherits: false; }\n@property --tw-hue-rotate { syntax: "*"; inherits: false; }\n@property --tw-invert { syntax: "*"; inherits: false; }\n@property --tw-opacity { syntax: "*"; inherits: false; }\n@property --tw-saturate { syntax: "*"; inherits: false; }\n@property --tw-sepia { syntax: "*"; inherits: false; }\n@property --tw-drop-shadow { syntax: "*"; inherits: false; }\n@property --tw-drop-shadow-color { syntax: "*"; inherits: false; }\n@property --tw-drop-shadow-alpha { syntax: "<percentage>"; inherits: false; initial-value: 100%; }\n@property --tw-drop-shadow-size { syntax: "*"; inherits: false; }\n@property --tw-translate-x { syntax: "*"; inherits: false; initial-value: 0; }\n@property --tw-translate-y { syntax: "*"; inherits: false; initial-value: 0; }\n@property --tw-translate-z { syntax: "*"; inherits: false; initial-value: 0; }\n@property --tw-duration { syntax: "*"; inherits: false; }\n@property --tw-scale-x { syntax: "*"; inherits: false; initial-value: 1; }\n@property --tw-scale-y { syntax: "*"; inherits: false; initial-value: 1; }\n@property --tw-scale-z { syntax: "*"; inherits: false; initial-value: 1; }\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n@keyframes pulse {\n 50% {\n opacity: 0.5;\n }\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *,\n ::before,\n ::after,\n ::backdrop {\n --tw-border-style: solid;\n --tw-gradient-position: initial;\n --tw-gradient-from: #0000;\n --tw-gradient-via: #0000;\n --tw-gradient-to: #0000;\n --tw-gradient-stops: initial;\n --tw-gradient-via-stops: initial;\n --tw-gradient-from-position: 0%;\n --tw-gradient-via-position: 50%;\n --tw-gradient-to-position: 100%;\n --tw-font-weight: initial;\n --tw-tracking: initial;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-color: initial;\n --tw-shadow-alpha: 100%;\n --tw-inset-shadow: 0 0 #0000;\n --tw-inset-shadow-color: initial;\n --tw-inset-shadow-alpha: 100%;\n --tw-ring-color: initial;\n --tw-ring-shadow: 0 0 #0000;\n --tw-inset-ring-color: initial;\n --tw-inset-ring-shadow: 0 0 #0000;\n --tw-ring-inset: initial;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-blur: initial;\n --tw-brightness: initial;\n --tw-contrast: initial;\n --tw-grayscale: initial;\n --tw-hue-rotate: initial;\n --tw-invert: initial;\n --tw-opacity: initial;\n --tw-saturate: initial;\n --tw-sepia: initial;\n --tw-drop-shadow: initial;\n --tw-drop-shadow-color: initial;\n --tw-drop-shadow-alpha: 100%;\n --tw-drop-shadow-size: initial;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-duration: initial;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-scale-z: 1;\n }\n }\n}\n');
|
|
28
|
+
// src/styles.css
|
|
29
|
+
styleInject(`@layer components {
|
|
30
|
+
video::-webkit-media-controls {
|
|
31
|
+
display: none !important;
|
|
32
|
+
}
|
|
33
|
+
video::-webkit-media-controls-panel {
|
|
34
|
+
display: none !important;
|
|
35
|
+
}
|
|
36
|
+
video::-webkit-media-controls-play-button {
|
|
37
|
+
display: none !important;
|
|
38
|
+
}
|
|
39
|
+
video::-webkit-media-controls-timeline {
|
|
40
|
+
display: none !important;
|
|
41
|
+
}
|
|
42
|
+
video::-webkit-media-controls-current-time-display {
|
|
43
|
+
display: none !important;
|
|
44
|
+
}
|
|
45
|
+
video::-webkit-media-controls-time-remaining-display {
|
|
46
|
+
display: none !important;
|
|
47
|
+
}
|
|
48
|
+
video::-webkit-media-controls-mute-button {
|
|
49
|
+
display: none !important;
|
|
50
|
+
}
|
|
51
|
+
video::-webkit-media-controls-volume-slider {
|
|
52
|
+
display: none !important;
|
|
53
|
+
}
|
|
54
|
+
video::-webkit-media-controls-fullscreen-button {
|
|
55
|
+
display: none !important;
|
|
56
|
+
}
|
|
57
|
+
video::-webkit-media-controls-overlay-play-button {
|
|
58
|
+
display: none !important;
|
|
59
|
+
}
|
|
60
|
+
video::-moz-media-controls {
|
|
61
|
+
display: none !important;
|
|
62
|
+
}
|
|
63
|
+
video {
|
|
64
|
+
outline: none !important;
|
|
65
|
+
}
|
|
66
|
+
video[controls] {
|
|
67
|
+
-webkit-appearance: none !important;
|
|
68
|
+
appearance: none !important;
|
|
69
|
+
}
|
|
70
|
+
video::-webkit-media-controls-enclosure {
|
|
71
|
+
display: none !important;
|
|
72
|
+
}
|
|
73
|
+
video::-webkit-media-controls-start-playback-button {
|
|
74
|
+
display: none !important;
|
|
75
|
+
}
|
|
76
|
+
video[controls]::-webkit-media-controls,
|
|
77
|
+
video[controls]::-webkit-media-controls-panel,
|
|
78
|
+
video[controls]::-webkit-media-controls-play-button,
|
|
79
|
+
video[controls]::-webkit-media-controls-timeline,
|
|
80
|
+
video[controls]::-webkit-media-controls-current-time-display,
|
|
81
|
+
video[controls]::-webkit-media-controls-time-remaining-display,
|
|
82
|
+
video[controls]::-webkit-media-controls-mute-button,
|
|
83
|
+
video[controls]::-webkit-media-controls-volume-slider,
|
|
84
|
+
video[controls]::-webkit-media-controls-fullscreen-button,
|
|
85
|
+
video[controls]::-webkit-media-controls-overlay-play-button,
|
|
86
|
+
video[controls]::-webkit-media-controls-enclosure,
|
|
87
|
+
video[controls]::-webkit-media-controls-start-playback-button {
|
|
88
|
+
display: none !important;
|
|
89
|
+
visibility: hidden !important;
|
|
90
|
+
opacity: 0 !important;
|
|
91
|
+
pointer-events: none !important;
|
|
92
|
+
}
|
|
93
|
+
video[controls]::-moz-media-controls {
|
|
94
|
+
display: none !important;
|
|
95
|
+
visibility: hidden !important;
|
|
96
|
+
opacity: 0 !important;
|
|
97
|
+
}
|
|
98
|
+
.motto-video-container {
|
|
99
|
+
@apply relative w-full;
|
|
100
|
+
min-height: 300px;
|
|
101
|
+
}
|
|
102
|
+
@supports (aspect-ratio: 16/9) {
|
|
103
|
+
.motto-video-container {
|
|
104
|
+
min-height: auto;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
.motto-video-responsive {
|
|
108
|
+
@apply absolute top-0 left-0 w-full h-full;
|
|
109
|
+
}
|
|
110
|
+
.motto-skip-button {
|
|
111
|
+
@apply absolute top-1/2 -translate-y-1/2 bg-black/70 text-white border-0 rounded-full w-16 h-16 text-2xl cursor-pointer flex items-center justify-center transition-all duration-200 z-10 opacity-80 hover:opacity-100 hover:scale-110 active:scale-95;
|
|
112
|
+
}
|
|
113
|
+
.motto-skip-button-back {
|
|
114
|
+
@apply left-5;
|
|
115
|
+
}
|
|
116
|
+
.motto-skip-button-forward {
|
|
117
|
+
@apply right-5;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
.shaka-seek-bar-container {
|
|
121
|
+
height: 6px !important;
|
|
122
|
+
width: 100% !important;
|
|
123
|
+
margin: 8px 0 !important;
|
|
124
|
+
border-radius: 4px !important;
|
|
125
|
+
position: relative !important;
|
|
126
|
+
border-top: none !important;
|
|
127
|
+
border-bottom: none !important;
|
|
128
|
+
box-shadow: none !important;
|
|
129
|
+
}
|
|
130
|
+
.shaka-seek-bar {
|
|
131
|
+
height: 6px !important;
|
|
132
|
+
width: 100% !important;
|
|
133
|
+
-webkit-appearance: none !important;
|
|
134
|
+
appearance: none !important;
|
|
135
|
+
background: transparent !important;
|
|
136
|
+
cursor: pointer !important;
|
|
137
|
+
border: none !important;
|
|
138
|
+
outline: none !important;
|
|
139
|
+
position: absolute !important;
|
|
140
|
+
top: 0 !important;
|
|
141
|
+
left: 0 !important;
|
|
142
|
+
border-radius: 4px !important;
|
|
143
|
+
}
|
|
144
|
+
.shaka-seek-bar::-webkit-slider-runnable-track {
|
|
145
|
+
height: 6px !important;
|
|
146
|
+
background: transparent !important;
|
|
147
|
+
border-radius: 4px !important;
|
|
148
|
+
border: none !important;
|
|
149
|
+
}
|
|
150
|
+
.shaka-seek-bar::-moz-range-track {
|
|
151
|
+
height: 6px !important;
|
|
152
|
+
background: transparent !important;
|
|
153
|
+
border-radius: 4px !important;
|
|
154
|
+
border: none !important;
|
|
155
|
+
}
|
|
156
|
+
.shaka-seek-bar::-webkit-slider-thumb {
|
|
157
|
+
-webkit-appearance: none !important;
|
|
158
|
+
appearance: none !important;
|
|
159
|
+
width: 16px !important;
|
|
160
|
+
height: 16px !important;
|
|
161
|
+
border-radius: 50% !important;
|
|
162
|
+
background: #ffffff !important;
|
|
163
|
+
cursor: pointer !important;
|
|
164
|
+
border: 2px solid #ffffff !important;
|
|
165
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;
|
|
166
|
+
margin-top: -4px !important;
|
|
167
|
+
}
|
|
168
|
+
.shaka-seek-bar::-moz-range-thumb {
|
|
169
|
+
width: 16px !important;
|
|
170
|
+
height: 16px !important;
|
|
171
|
+
border-radius: 50% !important;
|
|
172
|
+
background: #ffffff !important;
|
|
173
|
+
cursor: pointer !important;
|
|
174
|
+
border: 2px solid #ffffff !important;
|
|
175
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;
|
|
176
|
+
margin-top: -4px !important;
|
|
177
|
+
}
|
|
178
|
+
.motto-skip-back-button,
|
|
179
|
+
.motto-skip-forward-button,
|
|
180
|
+
.motto-native-skip-button {
|
|
181
|
+
background: transparent !important;
|
|
182
|
+
border: none !important;
|
|
183
|
+
padding: 4px !important;
|
|
184
|
+
margin: 0px !important;
|
|
185
|
+
cursor: pointer !important;
|
|
186
|
+
color: #ffffff !important;
|
|
187
|
+
transition: all 0.2s ease !important;
|
|
188
|
+
min-width: 32px !important;
|
|
189
|
+
height: 32px !important;
|
|
190
|
+
display: flex !important;
|
|
191
|
+
align-items: center !important;
|
|
192
|
+
justify-content: center !important;
|
|
193
|
+
border-radius: 4px !important;
|
|
194
|
+
width: 25px;
|
|
195
|
+
}
|
|
196
|
+
.motto-skip-back-button:hover,
|
|
197
|
+
.motto-skip-forward-button:hover,
|
|
198
|
+
.motto-native-skip-button:hover {
|
|
199
|
+
opacity: 0.8 !important;
|
|
200
|
+
background: transparent !important;
|
|
201
|
+
transform: scale(1.05) !important;
|
|
202
|
+
}
|
|
203
|
+
.motto-skip-back-button:active,
|
|
204
|
+
.motto-skip-forward-button:active,
|
|
205
|
+
.motto-native-skip-button:active {
|
|
206
|
+
transform: scale(0.95) !important;
|
|
207
|
+
}
|
|
208
|
+
.motto-skip-back-button svg,
|
|
209
|
+
.motto-skip-forward-button svg,
|
|
210
|
+
.motto-native-skip-button svg {
|
|
211
|
+
width: 24px !important;
|
|
212
|
+
height: 24px !important;
|
|
213
|
+
}
|
|
214
|
+
.shaka-spinner-svg {
|
|
215
|
+
color: white !important;
|
|
216
|
+
fill: white !important;
|
|
217
|
+
}
|
|
218
|
+
.shaka-spinner-path {
|
|
219
|
+
stroke: white !important;
|
|
220
|
+
fill: none !important;
|
|
221
|
+
}
|
|
222
|
+
.shaka-spinner-container {
|
|
223
|
+
color: white !important;
|
|
224
|
+
}
|
|
225
|
+
.shaka-buffering-spinner {
|
|
226
|
+
color: white !important;
|
|
227
|
+
fill: white !important;
|
|
228
|
+
}
|
|
229
|
+
.shaka-buffering-spinner svg {
|
|
230
|
+
color: white !important;
|
|
231
|
+
fill: white !important;
|
|
232
|
+
}
|
|
233
|
+
.shaka-buffering-spinner path {
|
|
234
|
+
stroke: white !important;
|
|
235
|
+
fill: none !important;
|
|
236
|
+
}
|
|
237
|
+
[data-shaka-player-container] .shaka-spinner,
|
|
238
|
+
[data-shaka-player-container] .spinner {
|
|
239
|
+
color: white !important;
|
|
240
|
+
border-color: white !important;
|
|
241
|
+
}
|
|
242
|
+
.material-icons.shaka-spinner {
|
|
243
|
+
color: white !important;
|
|
244
|
+
}
|
|
245
|
+
.shaka-controls-container .shaka-spinner,
|
|
246
|
+
.shaka-video-container .shaka-spinner {
|
|
247
|
+
color: white !important;
|
|
248
|
+
fill: white !important;
|
|
249
|
+
}
|
|
250
|
+
.shaka-controls-container .shaka-spinner svg,
|
|
251
|
+
.shaka-video-container .shaka-spinner svg {
|
|
252
|
+
color: white !important;
|
|
253
|
+
fill: white !important;
|
|
254
|
+
}
|
|
255
|
+
.shaka-controls-container .shaka-spinner path,
|
|
256
|
+
.shaka-video-container .shaka-spinner path {
|
|
257
|
+
stroke: white !important;
|
|
258
|
+
}
|
|
259
|
+
.motto-video-loading-overlay {
|
|
260
|
+
position: absolute;
|
|
261
|
+
top: 0;
|
|
262
|
+
left: 0;
|
|
263
|
+
width: 100%;
|
|
264
|
+
height: 100%;
|
|
265
|
+
background:
|
|
266
|
+
linear-gradient(
|
|
267
|
+
135deg,
|
|
268
|
+
#1a1a1a 0%,
|
|
269
|
+
#2d2d2d 100%);
|
|
270
|
+
display: flex;
|
|
271
|
+
flex-direction: column;
|
|
272
|
+
align-items: center;
|
|
273
|
+
justify-content: center;
|
|
274
|
+
z-index: 10;
|
|
275
|
+
transition: opacity 0.3s ease;
|
|
276
|
+
}
|
|
277
|
+
.motto-video-loading-overlay.hidden {
|
|
278
|
+
opacity: 0;
|
|
279
|
+
pointer-events: none;
|
|
280
|
+
}
|
|
281
|
+
.motto-video-loading-content {
|
|
282
|
+
text-align: center;
|
|
283
|
+
color: white;
|
|
284
|
+
}
|
|
285
|
+
.motto-video-loading-icon {
|
|
286
|
+
width: 64px;
|
|
287
|
+
height: 64px;
|
|
288
|
+
margin-bottom: 16px;
|
|
289
|
+
opacity: 0.7;
|
|
290
|
+
}
|
|
291
|
+
.motto-video-loading-text {
|
|
292
|
+
font-size: 16px;
|
|
293
|
+
font-weight: 500;
|
|
294
|
+
margin-bottom: 8px;
|
|
295
|
+
}
|
|
296
|
+
.motto-video-loading-subtext {
|
|
297
|
+
font-size: 14px;
|
|
298
|
+
opacity: 0.7;
|
|
299
|
+
}
|
|
300
|
+
@keyframes pulse-live {
|
|
301
|
+
0% {
|
|
302
|
+
opacity: 1;
|
|
303
|
+
transform: scale(1);
|
|
304
|
+
}
|
|
305
|
+
50% {
|
|
306
|
+
opacity: 0.7;
|
|
307
|
+
transform: scale(1.1);
|
|
308
|
+
}
|
|
309
|
+
100% {
|
|
310
|
+
opacity: 1;
|
|
311
|
+
transform: scale(1);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
.shaka-play-button {
|
|
315
|
+
background: rgba(255, 255, 255, 0.1) !important;
|
|
316
|
+
border: none !important;
|
|
317
|
+
color: white !important;
|
|
318
|
+
padding: 10px !important;
|
|
319
|
+
border-radius: 100% !important;
|
|
320
|
+
transition: all 0.2s ease !important;
|
|
321
|
+
display: flex !important;
|
|
322
|
+
align-items: center !important;
|
|
323
|
+
justify-content: center !important;
|
|
324
|
+
min-width: 55px !important;
|
|
325
|
+
height: 55px !important;
|
|
326
|
+
}
|
|
327
|
+
.shaka-play-button-container {
|
|
328
|
+
background: transparent;
|
|
329
|
+
transition: all 0.2s ease !important;
|
|
330
|
+
}
|
|
331
|
+
.motto-video-container:not(.no-cursor) .shaka-play-button-container {
|
|
332
|
+
background: rgba(0, 0, 0, 0.3);
|
|
333
|
+
transition: all 0.s ease !important;
|
|
334
|
+
}
|
|
335
|
+
.shaka-play-button:hover {
|
|
336
|
+
background: rgba(255, 255, 255, 0.2) !important;
|
|
337
|
+
transform: scale(1.05) !important;
|
|
338
|
+
}
|
|
339
|
+
.shaka-play-button:active {
|
|
340
|
+
transform: scale(0.95) !important;
|
|
341
|
+
}
|
|
342
|
+
.shaka-play-button > * {
|
|
343
|
+
display: none !important;
|
|
344
|
+
}
|
|
345
|
+
.shaka-play-button::after {
|
|
346
|
+
content: "" !important;
|
|
347
|
+
width: 35px !important;
|
|
348
|
+
height: 35px !important;
|
|
349
|
+
background-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path fill-rule="evenodd" d="M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z" clip-rule="evenodd" /></svg>') !important;
|
|
350
|
+
background-repeat: no-repeat !important;
|
|
351
|
+
background-size: contain !important;
|
|
352
|
+
background-position: center !important;
|
|
353
|
+
display: block !important;
|
|
354
|
+
}
|
|
355
|
+
.shaka-play-button[aria-label*=Play]::after {
|
|
356
|
+
background-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path fill-rule="evenodd" d="M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z" clip-rule="evenodd" /></svg>') !important;
|
|
357
|
+
}
|
|
358
|
+
.shaka-play-button[aria-label*=Pause]::after {
|
|
359
|
+
background-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path fill-rule="evenodd" d="M6.75 5.25a.75.75 0 0 1 .75-.75H9a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H7.5a.75.75 0 0 1-.75-.75V5.25Zm7.5 0A.75.75 0 0 1 15 4.5h1.5a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H15a.75.75 0 0 1-.75-.75V5.25Z" clip-rule="evenodd" /></svg>') !important;
|
|
360
|
+
}
|
|
361
|
+
.motto-video-container {
|
|
362
|
+
background: #111111;
|
|
363
|
+
}
|
|
364
|
+
.motto-video-container video {
|
|
365
|
+
width: 100% !important;
|
|
366
|
+
height: 100% !important;
|
|
367
|
+
margin-left: auto !important;
|
|
368
|
+
margin-right: auto !important;
|
|
369
|
+
}
|
|
370
|
+
html[dir=rtl] .shaka-controls-container,
|
|
371
|
+
html[dir=rtl] .shaka-bottom-controls,
|
|
372
|
+
html[dir=rtl] .shaka-controls-button-panel {
|
|
373
|
+
direction: ltr !important;
|
|
374
|
+
}
|
|
375
|
+
html[dir=rtl] .shaka-overflow-menu,
|
|
376
|
+
html[dir=rtl] .shaka-settings-menu {
|
|
377
|
+
direction: rtl !important;
|
|
378
|
+
text-align: right !important;
|
|
379
|
+
}
|
|
380
|
+
html[dir=rtl] .shaka-overflow-menu .shaka-overflow-button .material-svg-icon:not(:first-child) {
|
|
381
|
+
margin-right: 12px !important;
|
|
382
|
+
margin-left: 0 !important;
|
|
383
|
+
}
|
|
384
|
+
html[dir=rtl] .shaka-overflow-menu .shaka-overflow-button .material-svg-icon:first-child {
|
|
385
|
+
margin-right: 0 !important;
|
|
386
|
+
margin-left: 12px !important;
|
|
387
|
+
}
|
|
388
|
+
.shaka-hidden-fast-forward-container,
|
|
389
|
+
.shaka-hidden-rewind-container {
|
|
390
|
+
pointer-events: none !important;
|
|
391
|
+
display: none !important;
|
|
392
|
+
}
|
|
393
|
+
`);
|
|
27
394
|
|
|
28
395
|
// src/Player.tsx
|
|
29
|
-
import { forwardRef, useEffect as useEffect4, useRef as useRef8, useImperativeHandle } from "react";
|
|
30
|
-
import
|
|
396
|
+
import { forwardRef, useEffect as useEffect4, useRef as useRef8, useImperativeHandle, useCallback as useCallback9, useState as useState3 } from "react";
|
|
397
|
+
import shaka3 from "shaka-player/dist/shaka-player.ui";
|
|
398
|
+
|
|
399
|
+
// src/hooks/useShakaPlayer.ts
|
|
400
|
+
import { useRef, useCallback, useState } from "react";
|
|
401
|
+
import shaka from "shaka-player/dist/shaka-player.ui";
|
|
31
402
|
|
|
32
|
-
// src/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
403
|
+
// src/utils/devices.ts
|
|
404
|
+
var isAppleDevice = () => {
|
|
405
|
+
if (typeof navigator === "undefined") return false;
|
|
406
|
+
const ua = navigator.userAgent || "";
|
|
407
|
+
const isIOS = /iPad|iPhone|iPod/.test(ua) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
|
|
408
|
+
const isSafari = /Safari/.test(ua) && !/Chrome|CriOS|FxiOS|Edg/.test(ua);
|
|
409
|
+
const isMacSafari = /Macintosh/.test(ua) && isSafari;
|
|
410
|
+
return isIOS || isMacSafari;
|
|
411
|
+
};
|
|
412
|
+
var isPlayReadySupported = () => {
|
|
413
|
+
if (typeof navigator === "undefined" || typeof window === "undefined") {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
if (!navigator.requestMediaKeySystemAccess) {
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
const userAgent = navigator.userAgent || "";
|
|
420
|
+
const isXbox = /Xbox/.test(userAgent);
|
|
421
|
+
const isEdge = /Edg/.test(userAgent);
|
|
422
|
+
const isIE = /Trident|MSIE/.test(userAgent);
|
|
423
|
+
const isWindows = /Windows/.test(userAgent);
|
|
424
|
+
return isXbox || (isEdge || isIE) && isWindows;
|
|
425
|
+
};
|
|
426
|
+
var supportsWidevinePersistentLicenses = () => {
|
|
427
|
+
return false;
|
|
428
|
+
if (typeof navigator === "undefined") {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
const userAgent = navigator.userAgent || "";
|
|
432
|
+
const isChromeMatch = userAgent.match(/Chrome\/(\d+)/);
|
|
433
|
+
if (!isChromeMatch) {
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
if (/Edg|OPR|Opera/.test(userAgent)) {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
const chromeVersion = parseInt(isChromeMatch[1], 10);
|
|
440
|
+
if (chromeVersion < 64) {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
const isMacOS = /Mac OS X|Macintosh/.test(userAgent);
|
|
444
|
+
const isWindows = /Windows/.test(userAgent);
|
|
445
|
+
return isMacOS || isWindows;
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// src/hooks/useShakaPlayer.ts
|
|
449
|
+
import initShakaPlayerMux from "@mux/mux-data-shakaplayer";
|
|
450
|
+
|
|
451
|
+
// package.json
|
|
452
|
+
var version = "1.0.1-rc.80";
|
|
453
|
+
|
|
454
|
+
// src/utils/licenseCache.ts
|
|
455
|
+
var PERSISTENT_LICENSE_PREFIX = "motto_lic_";
|
|
456
|
+
var LICENSE_EXPIRY_MS = 2 * 60 * 60 * 1e3;
|
|
457
|
+
var LICENSE_MAX_RETRY_ATTEMPTS = 10;
|
|
458
|
+
var getAllLicenseCacheKeys = () => {
|
|
459
|
+
const keys = [];
|
|
460
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
461
|
+
const key = localStorage.key(i);
|
|
462
|
+
if (key?.startsWith(PERSISTENT_LICENSE_PREFIX)) {
|
|
463
|
+
keys.push(key);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return keys;
|
|
467
|
+
};
|
|
468
|
+
var getAllLicenseCacheEntries = () => {
|
|
469
|
+
const keys = getAllLicenseCacheKeys();
|
|
470
|
+
const entries = [];
|
|
471
|
+
for (const key of keys) {
|
|
472
|
+
try {
|
|
473
|
+
const stored = localStorage.getItem(key);
|
|
474
|
+
if (stored) {
|
|
475
|
+
const data = JSON.parse(stored);
|
|
476
|
+
entries.push({ key, data });
|
|
477
|
+
}
|
|
478
|
+
} catch (error) {
|
|
479
|
+
console.warn(`Failed to parse license cache entry for key ${key}:`, error);
|
|
480
|
+
localStorage.removeItem(key);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return entries;
|
|
484
|
+
};
|
|
485
|
+
var evictLRUEntry = () => {
|
|
486
|
+
const entries = getAllLicenseCacheEntries();
|
|
487
|
+
if (entries.length === 0) {
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
entries.sort((a, b) => {
|
|
491
|
+
const oldestA = Math.min(...a.data.map((session) => session.timestamp));
|
|
492
|
+
const oldestB = Math.min(...b.data.map((session) => session.timestamp));
|
|
493
|
+
return oldestA - oldestB;
|
|
494
|
+
});
|
|
495
|
+
const lruEntry = entries[0];
|
|
496
|
+
localStorage.removeItem(lruEntry.key);
|
|
497
|
+
console.log(`Evicted LRU license cache entry: ${lruEntry.key}`);
|
|
498
|
+
return true;
|
|
499
|
+
};
|
|
500
|
+
var storeWithQuotaHandling = (key, data) => {
|
|
501
|
+
let attempts = 0;
|
|
502
|
+
while (attempts < LICENSE_MAX_RETRY_ATTEMPTS) {
|
|
503
|
+
try {
|
|
504
|
+
localStorage.setItem(key, data);
|
|
505
|
+
return true;
|
|
506
|
+
} catch (error) {
|
|
507
|
+
if (error instanceof DOMException && (error.code === 22 || // QUOTA_EXCEEDED_ERR
|
|
508
|
+
error.name === "QuotaExceededError" || error.name === "NS_ERROR_DOM_QUOTA_REACHED")) {
|
|
509
|
+
console.warn(`QuotaExceededError on attempt ${attempts + 1}, attempting LRU eviction...`);
|
|
510
|
+
if (!evictLRUEntry()) {
|
|
511
|
+
console.error("No more entries to evict, storage operation failed");
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
attempts++;
|
|
515
|
+
} else {
|
|
516
|
+
console.error("Failed to store license cache data:", error);
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
console.error(`Failed to store license cache data after ${LICENSE_MAX_RETRY_ATTEMPTS} eviction attempts`);
|
|
522
|
+
return false;
|
|
523
|
+
};
|
|
524
|
+
var managePersistentLicenseStorage = (playlistId, licenseCacheKey, newSessionMetadata) => {
|
|
525
|
+
try {
|
|
526
|
+
const storageKey = `${PERSISTENT_LICENSE_PREFIX}${playlistId}_${licenseCacheKey}`;
|
|
527
|
+
const stored = localStorage.getItem(storageKey);
|
|
528
|
+
let existingSessions = [];
|
|
529
|
+
if (stored) {
|
|
530
|
+
try {
|
|
531
|
+
existingSessions = JSON.parse(stored);
|
|
532
|
+
} catch (parseError) {
|
|
533
|
+
console.warn("Failed to parse existing persistent license data:", parseError);
|
|
534
|
+
existingSessions = [];
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
const now = Date.now();
|
|
538
|
+
let validSessions = existingSessions.filter(
|
|
539
|
+
(session) => now - session.timestamp < LICENSE_EXPIRY_MS
|
|
540
|
+
);
|
|
541
|
+
if (newSessionMetadata && newSessionMetadata.length > 0) {
|
|
542
|
+
const newSessions = newSessionMetadata.map((session) => {
|
|
543
|
+
const uint8Array = new Uint8Array(session.initData);
|
|
544
|
+
const binaryString = Array.from(uint8Array).map((byte) => String.fromCharCode(byte)).join("");
|
|
545
|
+
return {
|
|
546
|
+
sessionId: session.sessionId,
|
|
547
|
+
initData: btoa(binaryString),
|
|
548
|
+
initDataType: session.initDataType,
|
|
549
|
+
keySystem: session.keySystem,
|
|
550
|
+
timestamp: now
|
|
551
|
+
};
|
|
552
|
+
});
|
|
553
|
+
const newSessionIds = new Set(newSessions.map((s) => s.sessionId));
|
|
554
|
+
validSessions = validSessions.filter((session) => !newSessionIds.has(session.sessionId));
|
|
555
|
+
validSessions = [...validSessions, ...newSessions];
|
|
556
|
+
}
|
|
557
|
+
if (validSessions.length === 0) {
|
|
558
|
+
localStorage.removeItem(storageKey);
|
|
559
|
+
} else {
|
|
560
|
+
const dataToStore = JSON.stringify(validSessions);
|
|
561
|
+
const success = storeWithQuotaHandling(storageKey, dataToStore);
|
|
562
|
+
if (!success) {
|
|
563
|
+
console.error(`Failed to store license cache for ${storageKey} after quota handling`);
|
|
564
|
+
return validSessions;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return validSessions;
|
|
568
|
+
} catch (error) {
|
|
569
|
+
console.warn("Failed to manage persistent license storage:", error);
|
|
570
|
+
return [];
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
var storePersistentLicense = (playlistId, licenseCacheKey, sessionMetadata) => {
|
|
574
|
+
managePersistentLicenseStorage(playlistId, licenseCacheKey, sessionMetadata);
|
|
575
|
+
};
|
|
576
|
+
var retrievePersistentLicense = (playlistId, licenseCacheKey) => {
|
|
577
|
+
try {
|
|
578
|
+
const validSessions = managePersistentLicenseStorage(playlistId, licenseCacheKey);
|
|
579
|
+
return validSessions.map((session) => ({
|
|
580
|
+
sessionId: session.sessionId,
|
|
581
|
+
initData: Uint8Array.from(atob(session.initData), (c) => c.charCodeAt(0)).buffer,
|
|
582
|
+
initDataType: session.initDataType,
|
|
583
|
+
keySystem: session.keySystem
|
|
584
|
+
}));
|
|
585
|
+
} catch (error) {
|
|
586
|
+
console.warn("Failed to retrieve persistent license:", error);
|
|
587
|
+
return [];
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
var clearAllPersistentLicenses = () => {
|
|
591
|
+
try {
|
|
592
|
+
const keys = getAllLicenseCacheKeys();
|
|
593
|
+
for (const key of keys) {
|
|
594
|
+
localStorage.removeItem(key);
|
|
595
|
+
}
|
|
596
|
+
console.log(`Cleared ${keys.length} persistent license cache entries`);
|
|
597
|
+
return keys.length;
|
|
598
|
+
} catch (error) {
|
|
599
|
+
console.error("Failed to clear persistent licenses:", error);
|
|
600
|
+
return 0;
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
// src/hooks/useShakaPlayer.ts
|
|
605
|
+
var normalizeSource = (src) => {
|
|
606
|
+
if (typeof src === "string") {
|
|
607
|
+
return {
|
|
608
|
+
id: "",
|
|
609
|
+
url: src,
|
|
610
|
+
format: "auto",
|
|
611
|
+
drm: {}
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
return src;
|
|
615
|
+
};
|
|
616
|
+
var useShakaPlayer = ({
|
|
36
617
|
src,
|
|
37
618
|
shakaConfig,
|
|
38
619
|
drmConfig,
|
|
39
620
|
onError,
|
|
40
|
-
onPlayerReady
|
|
621
|
+
onPlayerReady,
|
|
622
|
+
muxConfig,
|
|
623
|
+
onMuxReady,
|
|
624
|
+
onMuxDataUpdate,
|
|
625
|
+
publicKey,
|
|
626
|
+
mottoToken,
|
|
627
|
+
hasAds = false,
|
|
628
|
+
hasSystem73 = false,
|
|
629
|
+
apiToken
|
|
41
630
|
}) => {
|
|
42
631
|
const playerRef = useRef(null);
|
|
43
|
-
const
|
|
632
|
+
const [isRetrying, setIsRetrying] = useState(false);
|
|
633
|
+
const videoElementRef = useRef(null);
|
|
634
|
+
const destroyInProgressRef = useRef(null);
|
|
635
|
+
const isDestroyingRef = useRef(false);
|
|
636
|
+
const initSequenceRef = useRef(0);
|
|
637
|
+
const activeInitIdRef = useRef(null);
|
|
638
|
+
const waitingForKeyTimerRef = useRef(null);
|
|
639
|
+
const waitingForKeyHandlerRef = useRef(null);
|
|
640
|
+
const playbackResumedHandlerRef = useRef(null);
|
|
641
|
+
const usingPersistentLicenseRef = useRef(false);
|
|
642
|
+
const storedPersistentThisLoadRef = useRef(false);
|
|
643
|
+
const drmExpirationHandlerRef = useRef(null);
|
|
644
|
+
const getManifestUrl = useCallback(() => {
|
|
645
|
+
const playlistSrc = normalizeSource(src);
|
|
646
|
+
let manifestUrl = playlistSrc.url;
|
|
647
|
+
const isDRM = Boolean(playlistSrc.drm?.widevine || playlistSrc.drm?.fairplay || playlistSrc.drm?.playready);
|
|
648
|
+
if (isDRM) {
|
|
649
|
+
const isPlayReady = isPlayReadySupported();
|
|
650
|
+
if (isAppleDevice() && playlistSrc.drm?.fairplay?.certificateUrl) {
|
|
651
|
+
manifestUrl = playlistSrc.drm.fairplay.playlistUrl;
|
|
652
|
+
} else if (isPlayReady && playlistSrc.drm?.playready?.licenseUrl) {
|
|
653
|
+
manifestUrl = playlistSrc.drm.playready.playlistUrl;
|
|
654
|
+
} else {
|
|
655
|
+
manifestUrl = playlistSrc.drm?.widevine?.playlistUrl || "";
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return manifestUrl;
|
|
659
|
+
}, [src]);
|
|
660
|
+
const initializePlayerInternal = useCallback(async (video) => {
|
|
44
661
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
662
|
+
if (destroyInProgressRef.current) {
|
|
663
|
+
try {
|
|
664
|
+
await destroyInProgressRef.current;
|
|
665
|
+
} catch {
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
const myInitId = ++initSequenceRef.current;
|
|
669
|
+
activeInitIdRef.current = myInitId;
|
|
670
|
+
videoElementRef.current = video;
|
|
671
|
+
shaka.polyfill.installAll();
|
|
672
|
+
if (!shaka.Player.isBrowserSupported()) {
|
|
47
673
|
throw new Error("Browser not supported by Shaka Player");
|
|
48
674
|
}
|
|
49
|
-
|
|
675
|
+
if (isDestroyingRef.current) {
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
const player = new shaka.Player();
|
|
50
679
|
playerRef.current = player;
|
|
51
680
|
await player.attach(video);
|
|
681
|
+
const defaultConfig = {
|
|
682
|
+
manifest: {
|
|
683
|
+
// Override availability window to allow DVR window to grow from start
|
|
684
|
+
// Set to a very large value (24 hours in seconds) to effectively allow unlimited growth
|
|
685
|
+
availabilityWindowOverride: 86400
|
|
686
|
+
// 24 hours in seconds
|
|
687
|
+
},
|
|
688
|
+
streaming: {
|
|
689
|
+
// Allow seeking to any point within the availability window
|
|
690
|
+
safeSeekOffset: 5,
|
|
691
|
+
// 5 seconds from live edge to prevent buffering
|
|
692
|
+
// Increase tolerance for manifest timing inaccuracies in live streams
|
|
693
|
+
inaccurateManifestTolerance: 2
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
player.configure(defaultConfig);
|
|
52
697
|
if (shakaConfig) {
|
|
53
698
|
player.configure(shakaConfig);
|
|
54
699
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
700
|
+
const playlistSrc = normalizeSource(src);
|
|
701
|
+
const manifestUrl = getManifestUrl();
|
|
702
|
+
let playlistId = playlistSrc.id;
|
|
703
|
+
const isDRM = Boolean(playlistSrc.drm?.widevine || playlistSrc.drm?.fairplay || playlistSrc.drm?.playready);
|
|
704
|
+
storedPersistentThisLoadRef.current = false;
|
|
705
|
+
if (activeInitIdRef.current !== myInitId || isDestroyingRef.current) {
|
|
706
|
+
try {
|
|
707
|
+
await player.destroy();
|
|
708
|
+
} catch {
|
|
709
|
+
}
|
|
710
|
+
if (playerRef.current === player) playerRef.current = null;
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
let storedSessionsMetadata = [];
|
|
714
|
+
if (isDRM && playlistId) {
|
|
715
|
+
storedSessionsMetadata = retrievePersistentLicense(playlistId, playlistSrc.drm?.licenseCacheKey ?? "");
|
|
716
|
+
}
|
|
717
|
+
if (isDRM) {
|
|
718
|
+
const drmConfig2 = {
|
|
719
|
+
servers: {
|
|
720
|
+
"com.widevine.alpha": playlistSrc.drm?.widevine?.licenseUrl,
|
|
721
|
+
"com.microsoft.playready": playlistSrc.drm?.playready?.licenseUrl,
|
|
722
|
+
"com.apple.fps": playlistSrc.drm?.fairplay?.licenseUrl
|
|
723
|
+
},
|
|
724
|
+
keySystemsMapping: {
|
|
725
|
+
// Fall back or reroute to the platform's recommended PlayReady CDM if needed
|
|
726
|
+
"com.microsoft.playready": "com.microsoft.playready.recommendation"
|
|
727
|
+
},
|
|
728
|
+
...playlistSrc.drm?.fairplay && {
|
|
729
|
+
advanced: {
|
|
730
|
+
"com.apple.fps": {
|
|
731
|
+
serverCertificateUri: playlistSrc.drm.fairplay.certificateUrl
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
drmConfig2.advanced = {
|
|
737
|
+
...drmConfig2.advanced,
|
|
738
|
+
"com.widevine.alpha": {
|
|
739
|
+
...drmConfig2.advanced?.["com.widevine.alpha"],
|
|
740
|
+
sessionType: supportsWidevinePersistentLicenses() ? "persistent-license" : "temporary"
|
|
741
|
+
},
|
|
742
|
+
"com.microsoft.playready": {
|
|
743
|
+
...drmConfig2.advanced?.["com.microsoft.playready"],
|
|
744
|
+
sessionType: "persistent-license"
|
|
745
|
+
// PlayReady seems to always require persistent-license (temporary won't work, not compatible with license server response)
|
|
746
|
+
},
|
|
747
|
+
"com.apple.fps": {
|
|
748
|
+
...drmConfig2.advanced?.["com.apple.fps"],
|
|
749
|
+
sessionType: "temporary"
|
|
750
|
+
// FairPlay always uses temporary sessions - Safari won't play with persistent-license
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
if (storedSessionsMetadata.length > 0) {
|
|
754
|
+
drmConfig2.persistentSessionOnlinePlayback = true;
|
|
755
|
+
drmConfig2.persistentSessionsMetadata = storedSessionsMetadata.map((session) => ({
|
|
756
|
+
sessionId: session.sessionId,
|
|
757
|
+
initData: new Uint8Array(session.initData),
|
|
758
|
+
initDataType: session.initDataType
|
|
759
|
+
}));
|
|
760
|
+
}
|
|
761
|
+
usingPersistentLicenseRef.current = storedSessionsMetadata.length > 0;
|
|
762
|
+
player.configure({ drm: drmConfig2 });
|
|
763
|
+
const clearWaitingForKeyTimer = () => {
|
|
764
|
+
if (waitingForKeyTimerRef.current !== null) {
|
|
765
|
+
window.clearTimeout(waitingForKeyTimerRef.current);
|
|
766
|
+
waitingForKeyTimerRef.current = null;
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
const onPlaybackResumed = () => {
|
|
770
|
+
clearWaitingForKeyTimer();
|
|
771
|
+
};
|
|
772
|
+
const onWaitingForKey = () => {
|
|
773
|
+
if (!usingPersistentLicenseRef.current) return;
|
|
774
|
+
if (isRetrying) return;
|
|
775
|
+
clearWaitingForKeyTimer();
|
|
776
|
+
waitingForKeyTimerRef.current = window.setTimeout(async () => {
|
|
777
|
+
try {
|
|
778
|
+
if (isRetrying) return;
|
|
779
|
+
console.warn("Stuck waiting for decryption key; attempting license cache reset and reload...");
|
|
780
|
+
const clearedCount = clearAllPersistentLicenses();
|
|
781
|
+
if (clearedCount > 0 && playerRef.current) {
|
|
782
|
+
setIsRetrying(true);
|
|
783
|
+
await playerRef.current.load(getManifestUrl());
|
|
784
|
+
console.log("Reloaded manifest after clearing cached licenses");
|
|
785
|
+
} else {
|
|
786
|
+
console.warn("No cached licenses found to clear, skipping reload");
|
|
787
|
+
}
|
|
788
|
+
} catch (e) {
|
|
789
|
+
console.error("Failed during recovery from waitingforkey state:", e);
|
|
790
|
+
onError?.(e);
|
|
791
|
+
} finally {
|
|
792
|
+
setIsRetrying(false);
|
|
793
|
+
clearWaitingForKeyTimer();
|
|
794
|
+
}
|
|
795
|
+
}, 3e3);
|
|
796
|
+
};
|
|
797
|
+
try {
|
|
798
|
+
video.addEventListener("waitingforkey", onWaitingForKey);
|
|
799
|
+
video.addEventListener("playing", onPlaybackResumed);
|
|
800
|
+
video.addEventListener("ended", onPlaybackResumed);
|
|
801
|
+
video.addEventListener("pause", onPlaybackResumed);
|
|
802
|
+
waitingForKeyHandlerRef.current = onWaitingForKey;
|
|
803
|
+
playbackResumedHandlerRef.current = onPlaybackResumed;
|
|
804
|
+
} catch (e) {
|
|
805
|
+
console.warn("Failed to attach waitingforkey/playback listeners:", e);
|
|
806
|
+
}
|
|
807
|
+
const netEngine = player.getNetworkingEngine();
|
|
808
|
+
if (netEngine) {
|
|
809
|
+
netEngine.registerRequestFilter((type, request) => {
|
|
810
|
+
switch (type) {
|
|
811
|
+
case shaka.net.NetworkingEngine.RequestType.LICENSE:
|
|
812
|
+
if (publicKey) {
|
|
813
|
+
request.headers["authorization"] = `Bearer ${publicKey}`;
|
|
814
|
+
}
|
|
815
|
+
if (mottoToken) {
|
|
816
|
+
request.headers["x-motto-token"] = mottoToken;
|
|
817
|
+
}
|
|
818
|
+
break;
|
|
819
|
+
case shaka.net.NetworkingEngine.RequestType.MANIFEST:
|
|
820
|
+
case shaka.net.NetworkingEngine.RequestType.SEGMENT:
|
|
821
|
+
request.allowCrossSiteCredentials = true;
|
|
822
|
+
break;
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
netEngine.registerResponseFilter((type, response) => {
|
|
826
|
+
if (type === shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
827
|
+
const ks = player.keySystem && player.keySystem();
|
|
828
|
+
if (ks === "com.apple.fps") {
|
|
829
|
+
const responseText = shaka.util.StringUtils.fromUTF8(response.data);
|
|
830
|
+
response.data = shaka.util.Uint8ArrayUtils.fromBase64(responseText).buffer;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
if (apiToken) {
|
|
837
|
+
const netEngine = player.getNetworkingEngine();
|
|
838
|
+
if (netEngine) {
|
|
839
|
+
netEngine.registerRequestFilter((type, request) => {
|
|
840
|
+
if (type === shaka.net.NetworkingEngine.RequestType.MANIFEST) {
|
|
841
|
+
request.headers["authorization"] = `Bearer ${apiToken}`;
|
|
842
|
+
}
|
|
843
|
+
});
|
|
58
844
|
}
|
|
59
|
-
|
|
60
|
-
|
|
845
|
+
}
|
|
846
|
+
if (isDRM && playlistId) {
|
|
847
|
+
const onDRMSessionUpdate = () => {
|
|
848
|
+
try {
|
|
849
|
+
if (storedPersistentThisLoadRef.current) return;
|
|
850
|
+
const activeDrmSessions = player.getActiveSessionsMetadata?.();
|
|
851
|
+
if (!activeDrmSessions) return;
|
|
852
|
+
const persistentSessions = activeDrmSessions.filter(
|
|
853
|
+
(session) => session.sessionType === "persistent-license"
|
|
854
|
+
);
|
|
855
|
+
if (persistentSessions.length > 0) {
|
|
856
|
+
const sessionsToStore = persistentSessions.map((session) => ({
|
|
857
|
+
sessionId: session.sessionId,
|
|
858
|
+
initData: session.initData,
|
|
859
|
+
initDataType: session.initDataType,
|
|
860
|
+
keySystem: session.keySystem || "com.widevine.alpha"
|
|
861
|
+
}));
|
|
862
|
+
storePersistentLicense(playlistId, playlistSrc.drm?.licenseCacheKey ?? "", sessionsToStore);
|
|
863
|
+
storedPersistentThisLoadRef.current = true;
|
|
864
|
+
}
|
|
865
|
+
} catch (e) {
|
|
866
|
+
console.warn("Failed to persist licenses on expiration update:", e);
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
try {
|
|
870
|
+
player.addEventListener("drmsessionupdate", onDRMSessionUpdate);
|
|
871
|
+
drmExpirationHandlerRef.current = onDRMSessionUpdate;
|
|
872
|
+
} catch (e) {
|
|
873
|
+
console.warn("Failed to attach drmsessionupdate listener:", e);
|
|
61
874
|
}
|
|
62
875
|
}
|
|
63
|
-
player
|
|
876
|
+
player?.addEventListener("error", (event) => {
|
|
64
877
|
const error = event.detail;
|
|
878
|
+
if (error?.code === 7e3) {
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (error?.code >= 6e3 && error?.code < 7e3 && !isRetrying && videoElementRef.current) {
|
|
882
|
+
console.warn(`DRM error detected (code: ${error.code}), checking for cached licenses...`);
|
|
883
|
+
const clearedCount = clearAllPersistentLicenses();
|
|
884
|
+
if (clearedCount > 0) {
|
|
885
|
+
console.warn(`Cleared ${clearedCount} cached licenses, retrying...`);
|
|
886
|
+
setIsRetrying(true);
|
|
887
|
+
setTimeout(async () => {
|
|
888
|
+
try {
|
|
889
|
+
const video2 = videoElementRef.current;
|
|
890
|
+
const currentPlayer = playerRef.current;
|
|
891
|
+
if (video2 && currentPlayer) {
|
|
892
|
+
console.log("Reloading manifest after license cache clear...");
|
|
893
|
+
await currentPlayer.load(getManifestUrl());
|
|
894
|
+
console.log("Manifest reloaded successfully");
|
|
895
|
+
}
|
|
896
|
+
} catch (retryError) {
|
|
897
|
+
console.error("Failed to retry after license clear:", retryError);
|
|
898
|
+
onError?.(retryError);
|
|
899
|
+
} finally {
|
|
900
|
+
setIsRetrying(false);
|
|
901
|
+
}
|
|
902
|
+
}, 500);
|
|
903
|
+
return;
|
|
904
|
+
} else {
|
|
905
|
+
console.warn(`No cached licenses found to clear for error code ${error.code}, not retrying to avoid infinite loop`);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
65
908
|
console.error("Shaka Player Error:", error);
|
|
66
909
|
onError?.(new Error(`Shaka Player Error: ${error.message || "Unknown error"}`));
|
|
67
910
|
});
|
|
68
|
-
|
|
911
|
+
if (muxConfig) {
|
|
912
|
+
try {
|
|
913
|
+
const playerInitTime = initShakaPlayerMux.utils.now();
|
|
914
|
+
const muxOptions = {
|
|
915
|
+
debug: muxConfig.debug || false,
|
|
916
|
+
disableCookies: muxConfig.disableCookies || false,
|
|
917
|
+
respectDoNotTrack: muxConfig.respectDoNotTrack || false,
|
|
918
|
+
automaticErrorTracking: muxConfig.automaticErrorTracking !== false,
|
|
919
|
+
...muxConfig.beaconCollectionDomain && { beaconCollectionDomain: muxConfig.beaconCollectionDomain },
|
|
920
|
+
...muxConfig.errorTranslator && { errorTranslator: muxConfig.errorTranslator },
|
|
921
|
+
data: {
|
|
922
|
+
env_key: muxConfig.envKey,
|
|
923
|
+
player_name: muxConfig?.metadata?.player_name,
|
|
924
|
+
player_version: version,
|
|
925
|
+
player_init_time: playerInitTime,
|
|
926
|
+
video_title: muxConfig?.metadata?.video_title ?? "",
|
|
927
|
+
video_id: muxConfig?.metadata?.video_id ?? "",
|
|
928
|
+
viewer_user_id: muxConfig?.metadata?.viewer_user_id ?? "",
|
|
929
|
+
...muxConfig.metadata
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
initShakaPlayerMux(player, muxOptions, shaka);
|
|
933
|
+
onMuxReady?.();
|
|
934
|
+
} catch (error) {
|
|
935
|
+
console.error("Failed to initialize Mux Analytics:", error);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
if (activeInitIdRef.current !== myInitId || isDestroyingRef.current) {
|
|
939
|
+
try {
|
|
940
|
+
await player.destroy();
|
|
941
|
+
} catch {
|
|
942
|
+
}
|
|
943
|
+
if (playerRef.current === player) playerRef.current = null;
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
if (!hasAds && !hasSystem73) {
|
|
947
|
+
console.log("\u{1F4FA} [Shaka] Auto-loading manifest:", manifestUrl);
|
|
948
|
+
await player.load(manifestUrl);
|
|
949
|
+
console.log("\u2705 [Shaka] Manifest auto-loaded successfully");
|
|
950
|
+
} else {
|
|
951
|
+
console.log("\u23ED\uFE0F [Shaka] Skipping auto-load (hasAds:", hasAds, ", hasSystem73:", hasSystem73, ")");
|
|
952
|
+
}
|
|
69
953
|
onPlayerReady?.(player);
|
|
70
954
|
return player;
|
|
71
955
|
} catch (error) {
|
|
956
|
+
if (error?.code === 7e3) {
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
72
959
|
console.error("Error initializing Shaka Player:", error);
|
|
73
960
|
onError?.(error);
|
|
74
961
|
throw error;
|
|
75
962
|
}
|
|
76
|
-
}, [shakaConfig, drmConfig, src, onError, onPlayerReady]);
|
|
963
|
+
}, [shakaConfig, drmConfig, src, onError, onPlayerReady, muxConfig, onMuxReady, isRetrying, getManifestUrl, apiToken]);
|
|
964
|
+
const initializePlayer = useCallback(async (video) => {
|
|
965
|
+
return initializePlayerInternal(video);
|
|
966
|
+
}, [initializePlayerInternal]);
|
|
967
|
+
const loadManifest = useCallback(async () => {
|
|
968
|
+
const player = playerRef.current;
|
|
969
|
+
if (!player) {
|
|
970
|
+
console.warn("\u26A0\uFE0F [Shaka] Cannot load manifest: player not initialized");
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
try {
|
|
974
|
+
const manifestUrl = getManifestUrl();
|
|
975
|
+
console.log("\u{1F4FA} [Shaka] Loading manifest:", manifestUrl);
|
|
976
|
+
await player.load(manifestUrl);
|
|
977
|
+
console.log("\u2705 [Shaka] Manifest loaded successfully");
|
|
978
|
+
} catch (error) {
|
|
979
|
+
if (error?.code === 7e3) {
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
console.error("\u274C [Shaka] Error loading manifest:", error);
|
|
983
|
+
onError?.(error);
|
|
984
|
+
throw error;
|
|
985
|
+
}
|
|
986
|
+
}, [getManifestUrl, onError]);
|
|
77
987
|
const destroyPlayer = useCallback(async () => {
|
|
78
|
-
|
|
988
|
+
const playerInstance = playerRef.current;
|
|
989
|
+
if (playerInstance) {
|
|
79
990
|
try {
|
|
80
|
-
|
|
991
|
+
isDestroyingRef.current = true;
|
|
992
|
+
activeInitIdRef.current = null;
|
|
993
|
+
if (videoElementRef.current) {
|
|
994
|
+
try {
|
|
995
|
+
if (waitingForKeyHandlerRef.current) {
|
|
996
|
+
videoElementRef.current.removeEventListener("waitingforkey", waitingForKeyHandlerRef.current);
|
|
997
|
+
}
|
|
998
|
+
if (playbackResumedHandlerRef.current) {
|
|
999
|
+
videoElementRef.current.removeEventListener("playing", playbackResumedHandlerRef.current);
|
|
1000
|
+
videoElementRef.current.removeEventListener("ended", playbackResumedHandlerRef.current);
|
|
1001
|
+
videoElementRef.current.removeEventListener("pause", playbackResumedHandlerRef.current);
|
|
1002
|
+
}
|
|
1003
|
+
} catch (e) {
|
|
1004
|
+
console.warn("Error removing media event listeners:", e);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
if (waitingForKeyTimerRef.current !== null) {
|
|
1008
|
+
window.clearTimeout(waitingForKeyTimerRef.current);
|
|
1009
|
+
waitingForKeyTimerRef.current = null;
|
|
1010
|
+
}
|
|
1011
|
+
try {
|
|
1012
|
+
if (drmExpirationHandlerRef.current && playerInstance.removeEventListener) {
|
|
1013
|
+
playerInstance.removeEventListener("drmsessionupdate", drmExpirationHandlerRef.current);
|
|
1014
|
+
}
|
|
1015
|
+
} catch (e) {
|
|
1016
|
+
console.warn("Error removing DRM expiration listener:", e);
|
|
1017
|
+
} finally {
|
|
1018
|
+
drmExpirationHandlerRef.current = null;
|
|
1019
|
+
}
|
|
1020
|
+
const performDestroy = async () => {
|
|
1021
|
+
try {
|
|
1022
|
+
await playerInstance.destroy();
|
|
1023
|
+
} finally {
|
|
1024
|
+
try {
|
|
1025
|
+
if (videoElementRef.current) {
|
|
1026
|
+
videoElementRef.current.removeAttribute("src");
|
|
1027
|
+
videoElementRef.current.load();
|
|
1028
|
+
}
|
|
1029
|
+
} catch {
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
destroyInProgressRef.current = performDestroy();
|
|
1034
|
+
await destroyInProgressRef.current;
|
|
81
1035
|
} catch (error) {
|
|
82
1036
|
console.warn("Error destroying Shaka Player:", error);
|
|
83
1037
|
} finally {
|
|
84
|
-
playerRef.current
|
|
1038
|
+
if (playerRef.current === playerInstance) {
|
|
1039
|
+
playerRef.current = null;
|
|
1040
|
+
}
|
|
1041
|
+
storedPersistentThisLoadRef.current = false;
|
|
1042
|
+
isDestroyingRef.current = false;
|
|
1043
|
+
destroyInProgressRef.current = null;
|
|
85
1044
|
}
|
|
86
1045
|
}
|
|
87
|
-
}, []);
|
|
1046
|
+
}, [playerRef]);
|
|
88
1047
|
return {
|
|
89
1048
|
playerRef,
|
|
90
1049
|
initializePlayer,
|
|
91
|
-
|
|
1050
|
+
loadManifest,
|
|
1051
|
+
destroyPlayer,
|
|
1052
|
+
isRetrying
|
|
92
1053
|
};
|
|
93
1054
|
};
|
|
94
1055
|
|
|
@@ -111,11 +1072,25 @@ var useQualityControl = (playerRef, qualityConfig, onQualityChange) => {
|
|
|
111
1072
|
if (!playerRef.current) return;
|
|
112
1073
|
if (height === 0) {
|
|
113
1074
|
playerRef.current.configure({
|
|
114
|
-
abr: {
|
|
1075
|
+
abr: {
|
|
1076
|
+
enabled: true,
|
|
1077
|
+
switchInterval: 2,
|
|
1078
|
+
// quicker re-checks
|
|
1079
|
+
clearBufferSwitch: true,
|
|
1080
|
+
safeMarginSwitch: 10
|
|
1081
|
+
// leave ~10 s in front of the playhead }
|
|
1082
|
+
}
|
|
115
1083
|
});
|
|
116
1084
|
} else {
|
|
117
1085
|
playerRef.current.configure({
|
|
118
|
-
abr: {
|
|
1086
|
+
abr: {
|
|
1087
|
+
enabled: false,
|
|
1088
|
+
switchInterval: 2,
|
|
1089
|
+
// quicker re-checks
|
|
1090
|
+
clearBufferSwitch: true,
|
|
1091
|
+
safeMarginSwitch: 10
|
|
1092
|
+
// leave ~10 s in front of the playhead }
|
|
1093
|
+
}
|
|
119
1094
|
});
|
|
120
1095
|
const tracks = playerRef.current.getVariantTracks();
|
|
121
1096
|
const targetTrack = tracks.find((track) => track.height === height);
|
|
@@ -194,14 +1169,14 @@ var useSkipControls = (videoRef, onSkipBack, onSkipForward) => {
|
|
|
194
1169
|
|
|
195
1170
|
// src/hooks/useMuxAnalytics.ts
|
|
196
1171
|
import { useCallback as useCallback4, useRef as useRef3 } from "react";
|
|
197
|
-
import
|
|
198
|
-
import
|
|
1172
|
+
import initShakaPlayerMux2 from "@mux/mux-data-shakaplayer";
|
|
1173
|
+
import shaka2 from "shaka-player/dist/shaka-player.ui";
|
|
199
1174
|
var useMuxAnalytics = (playerRef, muxConfig, onMuxReady, onMuxDataUpdate) => {
|
|
200
1175
|
const shakaPlayerMuxRef = useRef3(null);
|
|
201
1176
|
const initializeMux = useCallback4(() => {
|
|
202
1177
|
if (!muxConfig || !playerRef.current) return;
|
|
203
1178
|
try {
|
|
204
|
-
const playerInitTime =
|
|
1179
|
+
const playerInitTime = initShakaPlayerMux2.utils.now();
|
|
205
1180
|
const muxOptions = {
|
|
206
1181
|
debug: muxConfig.debug || false,
|
|
207
1182
|
disableCookies: muxConfig.disableCookies || false,
|
|
@@ -211,13 +1186,16 @@ var useMuxAnalytics = (playerRef, muxConfig, onMuxReady, onMuxDataUpdate) => {
|
|
|
211
1186
|
...muxConfig.errorTranslator && { errorTranslator: muxConfig.errorTranslator },
|
|
212
1187
|
data: {
|
|
213
1188
|
env_key: muxConfig.envKey,
|
|
214
|
-
player_name:
|
|
215
|
-
player_version:
|
|
1189
|
+
player_name: muxConfig?.metadata?.player_name,
|
|
1190
|
+
player_version: version,
|
|
216
1191
|
player_init_time: playerInitTime,
|
|
1192
|
+
video_title: muxConfig?.metadata?.video_title ?? "",
|
|
1193
|
+
video_id: muxConfig?.metadata?.video_id ?? "",
|
|
1194
|
+
viewer_user_id: muxConfig?.metadata?.viewer_user_id ?? "",
|
|
217
1195
|
...muxConfig.metadata
|
|
218
1196
|
}
|
|
219
1197
|
};
|
|
220
|
-
shakaPlayerMuxRef.current =
|
|
1198
|
+
shakaPlayerMuxRef.current = initShakaPlayerMux2(playerRef.current, muxOptions, shaka2);
|
|
221
1199
|
onMuxReady?.();
|
|
222
1200
|
} catch (error) {
|
|
223
1201
|
console.error("Failed to initialize Mux Analytics:", error);
|
|
@@ -262,8 +1240,155 @@ var useMuxAnalytics = (playerRef, muxConfig, onMuxReady, onMuxDataUpdate) => {
|
|
|
262
1240
|
// src/hooks/useShakaUI.ts
|
|
263
1241
|
import { useCallback as useCallback5, useRef as useRef4 } from "react";
|
|
264
1242
|
import { ui as ShakaUI } from "shaka-player/dist/shaka-player.ui";
|
|
1243
|
+
|
|
1244
|
+
// src/icons/SkipBackIcon.tsx
|
|
1245
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1246
|
+
var SkipBackIcon = ({ size = 24, className = "" }) => {
|
|
1247
|
+
return /* @__PURE__ */ jsxs(
|
|
1248
|
+
"svg",
|
|
1249
|
+
{
|
|
1250
|
+
width: size,
|
|
1251
|
+
height: size,
|
|
1252
|
+
strokeWidth: "2",
|
|
1253
|
+
viewBox: "0 0 24 24",
|
|
1254
|
+
fill: "none",
|
|
1255
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1256
|
+
className,
|
|
1257
|
+
children: [
|
|
1258
|
+
/* @__PURE__ */ jsx(
|
|
1259
|
+
"path",
|
|
1260
|
+
{
|
|
1261
|
+
d: "M3 13C3 17.9706 7.02944 22 12 22C16.9706 22 21 17.9706 21 13C21 8.02944 16.9706 4 12 4",
|
|
1262
|
+
stroke: "currentColor",
|
|
1263
|
+
strokeWidth: "2",
|
|
1264
|
+
strokeLinecap: "round",
|
|
1265
|
+
strokeLinejoin: "round"
|
|
1266
|
+
}
|
|
1267
|
+
),
|
|
1268
|
+
/* @__PURE__ */ jsx(
|
|
1269
|
+
"path",
|
|
1270
|
+
{
|
|
1271
|
+
d: "M9 9L9 16",
|
|
1272
|
+
stroke: "currentColor",
|
|
1273
|
+
strokeWidth: "2",
|
|
1274
|
+
strokeLinecap: "round",
|
|
1275
|
+
strokeLinejoin: "round"
|
|
1276
|
+
}
|
|
1277
|
+
),
|
|
1278
|
+
/* @__PURE__ */ jsx(
|
|
1279
|
+
"path",
|
|
1280
|
+
{
|
|
1281
|
+
d: "M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16",
|
|
1282
|
+
stroke: "currentColor",
|
|
1283
|
+
strokeWidth: "2",
|
|
1284
|
+
strokeLinecap: "round",
|
|
1285
|
+
strokeLinejoin: "round"
|
|
1286
|
+
}
|
|
1287
|
+
),
|
|
1288
|
+
/* @__PURE__ */ jsx(
|
|
1289
|
+
"path",
|
|
1290
|
+
{
|
|
1291
|
+
d: "M12 4L4.5 4M4.5 4L6.5 2M4.5 4L6.5 6",
|
|
1292
|
+
stroke: "currentColor",
|
|
1293
|
+
strokeWidth: "2",
|
|
1294
|
+
strokeLinecap: "round",
|
|
1295
|
+
strokeLinejoin: "round"
|
|
1296
|
+
}
|
|
1297
|
+
)
|
|
1298
|
+
]
|
|
1299
|
+
}
|
|
1300
|
+
);
|
|
1301
|
+
};
|
|
1302
|
+
|
|
1303
|
+
// src/icons/SkipForwardIcon.tsx
|
|
1304
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1305
|
+
var SkipForwardIcon = ({ size = 24, className = "" }) => {
|
|
1306
|
+
return /* @__PURE__ */ jsxs2(
|
|
1307
|
+
"svg",
|
|
1308
|
+
{
|
|
1309
|
+
width: size,
|
|
1310
|
+
height: size,
|
|
1311
|
+
strokeWidth: "2",
|
|
1312
|
+
viewBox: "0 0 24 24",
|
|
1313
|
+
fill: "none",
|
|
1314
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1315
|
+
className,
|
|
1316
|
+
children: [
|
|
1317
|
+
/* @__PURE__ */ jsx2(
|
|
1318
|
+
"path",
|
|
1319
|
+
{
|
|
1320
|
+
d: "M21 13C21 17.9706 16.9706 22 12 22C7.02944 22 3 17.9706 3 13C3 8.02944 7.02944 4 12 4",
|
|
1321
|
+
stroke: "currentColor",
|
|
1322
|
+
strokeLinecap: "round",
|
|
1323
|
+
strokeLinejoin: "round"
|
|
1324
|
+
}
|
|
1325
|
+
),
|
|
1326
|
+
/* @__PURE__ */ jsx2(
|
|
1327
|
+
"path",
|
|
1328
|
+
{
|
|
1329
|
+
d: "M12 4H19.5M19.5 4L17.5 2M19.5 4L17.5 6",
|
|
1330
|
+
stroke: "currentColor",
|
|
1331
|
+
strokeLinecap: "round",
|
|
1332
|
+
strokeLinejoin: "round"
|
|
1333
|
+
}
|
|
1334
|
+
),
|
|
1335
|
+
/* @__PURE__ */ jsx2(
|
|
1336
|
+
"path",
|
|
1337
|
+
{
|
|
1338
|
+
d: "M9 9L9 16",
|
|
1339
|
+
stroke: "currentColor",
|
|
1340
|
+
strokeLinecap: "round",
|
|
1341
|
+
strokeLinejoin: "round"
|
|
1342
|
+
}
|
|
1343
|
+
),
|
|
1344
|
+
/* @__PURE__ */ jsx2(
|
|
1345
|
+
"path",
|
|
1346
|
+
{
|
|
1347
|
+
d: "M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16",
|
|
1348
|
+
stroke: "currentColor",
|
|
1349
|
+
strokeLinecap: "round",
|
|
1350
|
+
strokeLinejoin: "round"
|
|
1351
|
+
}
|
|
1352
|
+
)
|
|
1353
|
+
]
|
|
1354
|
+
}
|
|
1355
|
+
);
|
|
1356
|
+
};
|
|
1357
|
+
|
|
1358
|
+
// src/icons/BigPlayIcon.tsx
|
|
1359
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1360
|
+
var BigPlayIcon = ({ size = 40, className = "" }) => {
|
|
1361
|
+
return /* @__PURE__ */ jsx3(
|
|
1362
|
+
"svg",
|
|
1363
|
+
{
|
|
1364
|
+
width: size,
|
|
1365
|
+
height: size,
|
|
1366
|
+
viewBox: "0 0 24 24",
|
|
1367
|
+
fill: "currentColor",
|
|
1368
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1369
|
+
className,
|
|
1370
|
+
children: /* @__PURE__ */ jsx3(
|
|
1371
|
+
"path",
|
|
1372
|
+
{
|
|
1373
|
+
fillRule: "evenodd",
|
|
1374
|
+
d: "M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z",
|
|
1375
|
+
clipRule: "evenodd"
|
|
1376
|
+
}
|
|
1377
|
+
)
|
|
1378
|
+
}
|
|
1379
|
+
);
|
|
1380
|
+
};
|
|
1381
|
+
|
|
1382
|
+
// src/utils/renderIcon.ts
|
|
1383
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
1384
|
+
import { createElement } from "react";
|
|
1385
|
+
var renderIcon = (Component, props = {}) => {
|
|
1386
|
+
return renderToStaticMarkup(createElement(Component, props));
|
|
1387
|
+
};
|
|
1388
|
+
|
|
1389
|
+
// src/hooks/useShakaUI.ts
|
|
265
1390
|
var SkipBackButton = class {
|
|
266
|
-
constructor(parent, controls, onSkipBack) {
|
|
1391
|
+
constructor(parent, controls, onSkipBack, iconSize = 24) {
|
|
267
1392
|
this.parent = parent;
|
|
268
1393
|
this.controls = controls;
|
|
269
1394
|
this.eventManager = { listen: (element, event, handler) => {
|
|
@@ -271,14 +1396,7 @@ var SkipBackButton = class {
|
|
|
271
1396
|
} };
|
|
272
1397
|
this.button_ = document.createElement("button");
|
|
273
1398
|
this.button_.className = "shaka-button motto-native-skip-button";
|
|
274
|
-
this.button_.innerHTML =
|
|
275
|
-
<svg width="24px" stroke-width="2" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
276
|
-
<path d="M3 13C3 17.9706 7.02944 22 12 22C16.9706 22 21 17.9706 21 13C21 8.02944 16.9706 4 12 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
277
|
-
<path d="M9 9L9 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
278
|
-
<path d="M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
279
|
-
<path d="M12 4L4.5 4M4.5 4L6.5 2M4.5 4L6.5 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
280
|
-
</svg>
|
|
281
|
-
`;
|
|
1399
|
+
this.button_.innerHTML = renderIcon(SkipBackIcon, { size: iconSize });
|
|
282
1400
|
this.button_.title = "Skip back 15 seconds";
|
|
283
1401
|
this.button_.setAttribute("aria-label", "Skip back 15 seconds");
|
|
284
1402
|
this.parent.appendChild(this.button_);
|
|
@@ -291,9 +1409,13 @@ var SkipBackButton = class {
|
|
|
291
1409
|
}
|
|
292
1410
|
});
|
|
293
1411
|
}
|
|
1412
|
+
// Shaka UI will call `release` when the controls are destroyed.
|
|
1413
|
+
// Provide a no-op implementation to avoid TypeErrors.
|
|
1414
|
+
release() {
|
|
1415
|
+
}
|
|
294
1416
|
};
|
|
295
1417
|
var SkipForwardButton = class {
|
|
296
|
-
constructor(parent, controls, onSkipForward) {
|
|
1418
|
+
constructor(parent, controls, onSkipForward, iconSize = 24) {
|
|
297
1419
|
this.parent = parent;
|
|
298
1420
|
this.controls = controls;
|
|
299
1421
|
this.eventManager = { listen: (element, event, handler) => {
|
|
@@ -301,14 +1423,7 @@ var SkipForwardButton = class {
|
|
|
301
1423
|
} };
|
|
302
1424
|
this.button_ = document.createElement("button");
|
|
303
1425
|
this.button_.className = "shaka-button motto-native-skip-button";
|
|
304
|
-
this.button_.innerHTML =
|
|
305
|
-
<svg fill="none" height="24" stroke-width="2" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
|
306
|
-
<path d="M21 13C21 17.9706 16.9706 22 12 22C7.02944 22 3 17.9706 3 13C3 8.02944 7.02944 4 12 4" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
307
|
-
<path d="M12 4H19.5M19.5 4L17.5 2M19.5 4L17.5 6" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
308
|
-
<path d="M9 9L9 16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
309
|
-
<path d="M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
310
|
-
</svg>
|
|
311
|
-
`;
|
|
1426
|
+
this.button_.innerHTML = renderIcon(SkipForwardIcon, { size: iconSize });
|
|
312
1427
|
this.button_.title = "Skip forward 15 seconds";
|
|
313
1428
|
this.button_.setAttribute("aria-label", "Skip forward 15 seconds");
|
|
314
1429
|
this.parent.appendChild(this.button_);
|
|
@@ -321,243 +1436,65 @@ var SkipForwardButton = class {
|
|
|
321
1436
|
}
|
|
322
1437
|
});
|
|
323
1438
|
}
|
|
1439
|
+
release() {
|
|
1440
|
+
}
|
|
324
1441
|
};
|
|
325
1442
|
var SkipBackButtonFactory = class {
|
|
326
|
-
constructor(onSkipBack) {
|
|
1443
|
+
constructor(onSkipBack, iconSize) {
|
|
327
1444
|
this.onSkipBack = onSkipBack;
|
|
1445
|
+
this.iconSize = iconSize;
|
|
328
1446
|
}
|
|
329
1447
|
create(rootElement, controls) {
|
|
330
|
-
return new SkipBackButton(rootElement, controls, this.onSkipBack);
|
|
1448
|
+
return new SkipBackButton(rootElement, controls, this.onSkipBack, this.iconSize);
|
|
331
1449
|
}
|
|
332
1450
|
};
|
|
333
1451
|
var SkipForwardButtonFactory = class {
|
|
334
|
-
constructor(onSkipForward) {
|
|
335
|
-
this.onSkipForward = onSkipForward;
|
|
336
|
-
}
|
|
337
|
-
create(rootElement, controls) {
|
|
338
|
-
return new SkipForwardButton(rootElement, controls, this.onSkipForward);
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
var MobilePlayButton = class {
|
|
342
|
-
constructor(parent, controls) {
|
|
343
|
-
this.parent = parent;
|
|
344
|
-
this.controls = controls;
|
|
345
|
-
this.video = controls?.getVideo?.() || parent.querySelector("video") || document.querySelector("video");
|
|
346
|
-
if (!this.video) {
|
|
347
|
-
console.error("MobilePlayButton: No video element found");
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
this.eventManager = { listen: (element, event, handler) => {
|
|
351
|
-
element.addEventListener(event, handler);
|
|
352
|
-
} };
|
|
353
|
-
this.button_ = document.createElement("button");
|
|
354
|
-
this.button_.className = "motto-mobile-play-button";
|
|
355
|
-
this.updateIcon();
|
|
356
|
-
this.parent.appendChild(this.button_);
|
|
357
|
-
this.eventManager.listen(this.button_, "click", () => {
|
|
358
|
-
if (this.video.paused) {
|
|
359
|
-
this.video.play();
|
|
360
|
-
} else {
|
|
361
|
-
this.video.pause();
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
this.eventManager.listen(this.video, "play", () => this.updateIcon());
|
|
365
|
-
this.eventManager.listen(this.video, "pause", () => this.updateIcon());
|
|
366
|
-
}
|
|
367
|
-
updateIcon() {
|
|
368
|
-
if (this.video.paused) {
|
|
369
|
-
this.button_.innerHTML = `
|
|
370
|
-
<svg xmlns="http://www.w3.org/2000/svg" stroke-width="2" viewBox="0 0 24 24" fill="currentColor">
|
|
371
|
-
<path stroke-width="2" fill-rule="evenodd" d="M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z" clip-rule="evenodd" />
|
|
372
|
-
</svg>
|
|
373
|
-
`;
|
|
374
|
-
this.button_.setAttribute("aria-label", "Play");
|
|
375
|
-
} else {
|
|
376
|
-
this.button_.innerHTML = `
|
|
377
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
|
378
|
-
<path fill-rule="evenodd" d="M6.75 5.25a.75.75 0 0 1 .75-.75H9a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H7.5a.75.75 0 0 1-.75-.75V5.25Zm7.5 0A.75.75 0 0 1 15 4.5h1.5a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H15a.75.75 0 0 1-.75-.75V5.25Z" clip-rule="evenodd" />
|
|
379
|
-
</svg>
|
|
380
|
-
`;
|
|
381
|
-
this.button_.setAttribute("aria-label", "Pause");
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
};
|
|
385
|
-
var MobileSkipBackButton = class {
|
|
386
|
-
constructor(parent, controls, onSkipBack) {
|
|
387
|
-
this.parent = parent;
|
|
388
|
-
this.controls = controls;
|
|
389
|
-
this.video = controls?.getVideo?.() || parent.querySelector("video") || document.querySelector("video");
|
|
390
|
-
if (!this.video) {
|
|
391
|
-
console.error("MobileSkipBackButton: No video element found");
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
this.eventManager = { listen: (element, event, handler) => {
|
|
395
|
-
element.addEventListener(event, handler);
|
|
396
|
-
} };
|
|
397
|
-
this.button_ = document.createElement("button");
|
|
398
|
-
this.button_.className = "motto-mobile-skip-button";
|
|
399
|
-
this.button_.innerHTML = `
|
|
400
|
-
<svg width="20px" stroke-width="2" height="20px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
401
|
-
<path d="M3 13C3 17.9706 7.02944 22 12 22C16.9706 22 21 17.9706 21 13C21 8.02944 16.9706 4 12 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
402
|
-
<path d="M9 9L9 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
403
|
-
<path d="M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
404
|
-
<path d="M12 4L4.5 4M4.5 4L6.5 2M4.5 4L6.5 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
405
|
-
</svg>
|
|
406
|
-
`;
|
|
407
|
-
this.button_.setAttribute("aria-label", "Skip back 15 seconds");
|
|
408
|
-
this.parent.appendChild(this.button_);
|
|
409
|
-
this.eventManager.listen(this.button_, "click", () => {
|
|
410
|
-
const newTime = Math.max(0, this.video.currentTime - 15);
|
|
411
|
-
this.video.currentTime = newTime;
|
|
412
|
-
onSkipBack?.(newTime);
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
};
|
|
416
|
-
var MobileSkipForwardButton = class {
|
|
417
|
-
constructor(parent, controls, onSkipForward) {
|
|
418
|
-
this.parent = parent;
|
|
419
|
-
this.controls = controls;
|
|
420
|
-
this.video = controls?.getVideo?.() || parent.querySelector("video") || document.querySelector("video");
|
|
421
|
-
if (!this.video) {
|
|
422
|
-
console.error("MobileSkipForwardButton: No video element found");
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
this.eventManager = { listen: (element, event, handler) => {
|
|
426
|
-
element.addEventListener(event, handler);
|
|
427
|
-
} };
|
|
428
|
-
this.button_ = document.createElement("button");
|
|
429
|
-
this.button_.className = "motto-mobile-skip-button";
|
|
430
|
-
this.button_.innerHTML = `
|
|
431
|
-
<svg fill="none" height="20" stroke-width="2" viewBox="0 0 24 24" width="20" xmlns="http://www.w3.org/2000/svg">
|
|
432
|
-
<path d="M21 13C21 17.9706 16.9706 22 12 22C7.02944 22 3 17.9706 3 13C3 8.02944 7.02944 4 12 4" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
433
|
-
<path d="M12 4H19.5M19.5 4L17.5 2M19.5 4L17.5 6" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
434
|
-
<path d="M9 9L9 16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
435
|
-
<path d="M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
436
|
-
</svg>
|
|
437
|
-
`;
|
|
438
|
-
this.button_.setAttribute("aria-label", "Skip forward 15 seconds");
|
|
439
|
-
this.parent.appendChild(this.button_);
|
|
440
|
-
this.eventManager.listen(this.button_, "click", () => {
|
|
441
|
-
const newTime = Math.min(this.video.duration || 0, this.video.currentTime + 15);
|
|
442
|
-
this.video.currentTime = newTime;
|
|
443
|
-
onSkipForward?.(newTime);
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
};
|
|
447
|
-
var MobileControlsContainer = class {
|
|
448
|
-
constructor(parent, controls, onSkipBack, onSkipForward) {
|
|
449
|
-
this.parent = parent;
|
|
450
|
-
this.controls = controls;
|
|
451
|
-
if (!parent) {
|
|
452
|
-
console.error("MobileControlsContainer: No parent element provided");
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
this.container_ = document.createElement("div");
|
|
456
|
-
this.container_.className = "motto-mobile-controls-overlay";
|
|
457
|
-
const controlsGroup = document.createElement("div");
|
|
458
|
-
controlsGroup.className = "motto-mobile-controls-group";
|
|
459
|
-
new MobileSkipBackButton(controlsGroup, controls, onSkipBack);
|
|
460
|
-
new MobilePlayButton(controlsGroup, controls);
|
|
461
|
-
new MobileSkipForwardButton(controlsGroup, controls, onSkipForward);
|
|
462
|
-
this.container_.appendChild(controlsGroup);
|
|
463
|
-
this.parent.appendChild(this.container_);
|
|
464
|
-
this.setupVisibilitySync();
|
|
465
|
-
}
|
|
466
|
-
setupVisibilitySync() {
|
|
467
|
-
setTimeout(() => {
|
|
468
|
-
this.syncVisibility();
|
|
469
|
-
this.observer = new MutationObserver((mutations) => {
|
|
470
|
-
mutations.forEach((mutation) => {
|
|
471
|
-
if (mutation.type === "attributes" && mutation.attributeName === "class") {
|
|
472
|
-
this.syncVisibility();
|
|
473
|
-
}
|
|
474
|
-
});
|
|
475
|
-
});
|
|
476
|
-
this.observer.observe(this.parent, {
|
|
477
|
-
attributes: true,
|
|
478
|
-
attributeFilter: ["class"]
|
|
479
|
-
});
|
|
480
|
-
const video = this.controls?.getVideo?.() || this.parent.querySelector("video");
|
|
481
|
-
if (video) {
|
|
482
|
-
video.addEventListener("play", () => {
|
|
483
|
-
setTimeout(() => this.syncVisibility(), 50);
|
|
484
|
-
});
|
|
485
|
-
video.addEventListener("pause", () => {
|
|
486
|
-
setTimeout(() => this.syncVisibility(), 50);
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
}, 1e3);
|
|
490
|
-
}
|
|
491
|
-
syncVisibility() {
|
|
492
|
-
const mainContainer = this.parent;
|
|
493
|
-
const hasNoCursor = mainContainer.classList.contains("no-cursor");
|
|
494
|
-
const video = this.controls?.getVideo?.() || this.parent.querySelector("video");
|
|
495
|
-
const isVideoPaused = video ? video.paused : false;
|
|
496
|
-
const isControlsVisible = !hasNoCursor || isVideoPaused;
|
|
497
|
-
if (this.container_) {
|
|
498
|
-
if (isControlsVisible) {
|
|
499
|
-
this.container_.style.opacity = "1";
|
|
500
|
-
this.container_.style.pointerEvents = "none";
|
|
501
|
-
} else {
|
|
502
|
-
this.container_.style.opacity = "0";
|
|
503
|
-
this.container_.style.pointerEvents = "none";
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
isElementVisible(element) {
|
|
508
|
-
const style = window.getComputedStyle(element);
|
|
509
|
-
const hasHiddenClass = element.classList.contains("shaka-hidden") || element.classList.contains("hidden") || element.classList.contains("shaka-fade-out");
|
|
510
|
-
return style.display !== "none" && style.visibility !== "hidden" && style.opacity !== "0" && !element.hidden && !hasHiddenClass;
|
|
511
|
-
}
|
|
512
|
-
};
|
|
513
|
-
var MobileControlsContainerFactory = class {
|
|
514
|
-
constructor(onSkipBack, onSkipForward) {
|
|
515
|
-
this.onSkipBack = onSkipBack;
|
|
1452
|
+
constructor(onSkipForward, iconSize) {
|
|
516
1453
|
this.onSkipForward = onSkipForward;
|
|
1454
|
+
this.iconSize = iconSize;
|
|
517
1455
|
}
|
|
518
1456
|
create(rootElement, controls) {
|
|
519
|
-
return new
|
|
1457
|
+
return new SkipForwardButton(rootElement, controls, this.onSkipForward, this.iconSize);
|
|
520
1458
|
}
|
|
521
1459
|
};
|
|
522
|
-
var useShakaUI = (playerRef, containerRef, videoRef, controls, chromecastConfig, seekbarColors, onSkipBack, onSkipForward) => {
|
|
1460
|
+
var useShakaUI = (playerRef, containerRef, videoRef, controls, chromecastConfig, seekbarColors, onSkipBack, onSkipForward, iconSizes, locale = "en") => {
|
|
523
1461
|
const uiRef = useRef4(null);
|
|
524
1462
|
const registeredElements = useRef4(/* @__PURE__ */ new Set());
|
|
525
1463
|
const initializeUI = useCallback5(async () => {
|
|
526
1464
|
if (!controls || !containerRef.current || !playerRef.current || !videoRef.current) {
|
|
527
1465
|
return null;
|
|
528
1466
|
}
|
|
529
|
-
const isMobile = window.innerWidth <= 767 || /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
530
1467
|
if (!registeredElements.current.has("skip_back_button")) {
|
|
531
|
-
ShakaUI.Controls.registerElement("skip_back_button", new SkipBackButtonFactory(onSkipBack));
|
|
1468
|
+
ShakaUI.Controls.registerElement("skip_back_button", new SkipBackButtonFactory(onSkipBack, iconSizes?.skipButtons));
|
|
532
1469
|
registeredElements.current.add("skip_back_button");
|
|
533
1470
|
}
|
|
534
1471
|
if (!registeredElements.current.has("skip_forward_button")) {
|
|
535
|
-
ShakaUI.Controls.registerElement("skip_forward_button", new SkipForwardButtonFactory(onSkipForward));
|
|
1472
|
+
ShakaUI.Controls.registerElement("skip_forward_button", new SkipForwardButtonFactory(onSkipForward, iconSizes?.skipButtons));
|
|
536
1473
|
registeredElements.current.add("skip_forward_button");
|
|
537
1474
|
}
|
|
538
|
-
if (isMobile) {
|
|
539
|
-
if (!registeredElements.current.has("mobile_controls_container")) {
|
|
540
|
-
ShakaUI.Controls.registerElement("mobile_controls_container", new MobileControlsContainerFactory(onSkipBack, onSkipForward));
|
|
541
|
-
registeredElements.current.add("mobile_controls_container");
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
1475
|
const ui = new ShakaUI.Overlay(playerRef.current, containerRef.current, videoRef.current);
|
|
545
1476
|
uiRef.current = ui;
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
1477
|
+
if (locale !== "en") {
|
|
1478
|
+
try {
|
|
1479
|
+
ui.getControls().getLocalization().changeLocale([locale]);
|
|
1480
|
+
console.log(`Set locale to '${locale}'`);
|
|
1481
|
+
} catch (error) {
|
|
1482
|
+
console.warn(`Failed to set locale to '${locale}', falling back to 'en':`, error);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
const isMobile = window.innerWidth <= 767;
|
|
1486
|
+
const controlPanelElements = [
|
|
1487
|
+
...isMobile ? [] : ["skip_back_button"],
|
|
1488
|
+
...isMobile ? [] : ["play_pause"],
|
|
1489
|
+
...isMobile ? [] : ["skip_forward_button"],
|
|
556
1490
|
"mute",
|
|
557
|
-
"volume",
|
|
1491
|
+
...isMobile ? [] : ["volume"],
|
|
1492
|
+
// Only include volume on desktop
|
|
558
1493
|
"time_and_duration",
|
|
559
1494
|
"spacer",
|
|
560
1495
|
"fullscreen",
|
|
1496
|
+
"cast",
|
|
1497
|
+
// Always show cast button
|
|
561
1498
|
"overflow_menu"
|
|
562
1499
|
];
|
|
563
1500
|
const uiConfig = {
|
|
@@ -570,35 +1507,58 @@ var useShakaUI = (playerRef, containerRef, videoRef, controls, chromecastConfig,
|
|
|
570
1507
|
// Progress/played portion (white)
|
|
571
1508
|
},
|
|
572
1509
|
controlPanelElements,
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
1510
|
+
addBigPlayButton: isMobile,
|
|
1511
|
+
// For now, Chromecast via Shaka must use the Motto receiver that runs on the legacy cast SDK (2.0), because
|
|
1512
|
+
// Shaka does not support the newer Cast SDK (3.0+) in its native integration.
|
|
1513
|
+
castReceiverAppId: "EC900D4D",
|
|
1514
|
+
castAndroidReceiverCompatible: true,
|
|
1515
|
+
// Enable Android TV compatibility
|
|
1516
|
+
overflowMenuButtons: [
|
|
1517
|
+
"quality",
|
|
1518
|
+
"picture_in_picture",
|
|
1519
|
+
"playback_rate"
|
|
1520
|
+
]
|
|
577
1521
|
};
|
|
578
|
-
if (chromecastConfig?.receiverApplicationId) {
|
|
579
|
-
uiConfig.castReceiverAppId = chromecastConfig.receiverApplicationId;
|
|
580
|
-
uiConfig.castAndroidReceiverCompatible = false;
|
|
581
|
-
}
|
|
582
1522
|
ui.configure(uiConfig);
|
|
583
1523
|
if (isMobile) {
|
|
584
|
-
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
1524
|
+
const customizeBigPlayButton = () => {
|
|
1525
|
+
const bigPlayButton = containerRef.current?.querySelector(".shaka-big-play-button");
|
|
1526
|
+
if (bigPlayButton && !bigPlayButton.hasAttribute("data-customized")) {
|
|
1527
|
+
const buttonSize = iconSizes?.bigPlayButton || 40;
|
|
1528
|
+
bigPlayButton.innerHTML = renderIcon(BigPlayIcon, { size: buttonSize });
|
|
1529
|
+
bigPlayButton.setAttribute("data-customized", "true");
|
|
1530
|
+
const buttonElement = bigPlayButton;
|
|
1531
|
+
buttonElement.style.display = "flex";
|
|
1532
|
+
buttonElement.style.alignItems = "center";
|
|
1533
|
+
buttonElement.style.justifyContent = "center";
|
|
589
1534
|
}
|
|
590
|
-
}
|
|
1535
|
+
};
|
|
1536
|
+
setTimeout(customizeBigPlayButton, 100);
|
|
1537
|
+
const observer = new MutationObserver(() => {
|
|
1538
|
+
customizeBigPlayButton();
|
|
1539
|
+
});
|
|
1540
|
+
if (containerRef.current) {
|
|
1541
|
+
observer.observe(containerRef.current, {
|
|
1542
|
+
childList: true,
|
|
1543
|
+
subtree: true,
|
|
1544
|
+
attributes: false
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
591
1547
|
}
|
|
592
1548
|
return ui;
|
|
593
|
-
}, [controls, containerRef, playerRef, videoRef, chromecastConfig, seekbarColors, onSkipBack, onSkipForward]);
|
|
594
|
-
const destroyUI = useCallback5(() => {
|
|
595
|
-
|
|
1549
|
+
}, [controls, containerRef, playerRef, videoRef, chromecastConfig, seekbarColors, onSkipBack, onSkipForward, iconSizes, locale]);
|
|
1550
|
+
const destroyUI = useCallback5(async () => {
|
|
1551
|
+
const uiInstance = uiRef.current;
|
|
1552
|
+
if (uiInstance) {
|
|
596
1553
|
try {
|
|
597
|
-
|
|
1554
|
+
await uiInstance.destroy();
|
|
598
1555
|
} catch (error) {
|
|
599
1556
|
console.error("Error destroying UI:", error);
|
|
1557
|
+
} finally {
|
|
1558
|
+
if (uiRef.current === uiInstance) {
|
|
1559
|
+
uiRef.current = null;
|
|
1560
|
+
}
|
|
600
1561
|
}
|
|
601
|
-
uiRef.current = null;
|
|
602
1562
|
}
|
|
603
1563
|
}, []);
|
|
604
1564
|
return {
|
|
@@ -637,128 +1597,153 @@ var useEventHandlers = (videoRef, handlers) => {
|
|
|
637
1597
|
};
|
|
638
1598
|
};
|
|
639
1599
|
|
|
640
|
-
// src/hooks/
|
|
641
|
-
import { useEffect, useState
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
const
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
1600
|
+
// src/hooks/usePosterFallback.ts
|
|
1601
|
+
import { useEffect, useState as useState2 } from "react";
|
|
1602
|
+
|
|
1603
|
+
// src/hooks/useLiveIndicator.ts
|
|
1604
|
+
import { useEffect as useEffect2, useRef as useRef6 } from "react";
|
|
1605
|
+
var useLiveIndicator = (containerRef, playerRef, options = {}) => {
|
|
1606
|
+
const observerRef = useRef6(null);
|
|
1607
|
+
const intervalRef = useRef6(null);
|
|
1608
|
+
const lastStatusRef = useRef6(null);
|
|
1609
|
+
const {
|
|
1610
|
+
enabled = true,
|
|
1611
|
+
indicatorColor = "#ff0000",
|
|
1612
|
+
indicatorSize = 8,
|
|
1613
|
+
showPulseAnimation = true,
|
|
1614
|
+
liveThresholdSeconds = 15,
|
|
1615
|
+
onLiveStatusChange
|
|
1616
|
+
} = options;
|
|
1617
|
+
const getLiveStatus = (player) => {
|
|
1618
|
+
if (!player) {
|
|
1619
|
+
return { isLive: false, isNearEdge: false };
|
|
650
1620
|
}
|
|
651
1621
|
try {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
return;
|
|
1622
|
+
if (!player.getManifest || typeof player.getManifest !== "function") {
|
|
1623
|
+
return { isLive: false, isNearEdge: false };
|
|
655
1624
|
}
|
|
656
1625
|
const manifest = player.getManifest();
|
|
657
1626
|
if (!manifest) {
|
|
658
|
-
return;
|
|
1627
|
+
return { isLive: false, isNearEdge: false };
|
|
659
1628
|
}
|
|
660
|
-
const timeline =
|
|
1629
|
+
const timeline = manifest.presentationTimeline;
|
|
661
1630
|
if (!timeline || typeof timeline.isLive !== "function") {
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
const liveStatus = timeline.isLive();
|
|
665
|
-
if (liveStatus !== isLive) {
|
|
666
|
-
setIsLive(liveStatus);
|
|
667
|
-
setIsVisible(liveStatus);
|
|
668
|
-
onLiveStateChange?.(liveStatus);
|
|
1631
|
+
return { isLive: false, isNearEdge: false };
|
|
669
1632
|
}
|
|
1633
|
+
const isLiveStream = timeline.isLive();
|
|
1634
|
+
if (!isLiveStream) return { isLive: false, isNearEdge: false };
|
|
1635
|
+
const videoElement = player.getMediaElement?.();
|
|
1636
|
+
if (!videoElement) return { isLive: true, isNearEdge: false };
|
|
1637
|
+
const liveEdge = timeline.getSeekRangeEnd?.() ?? timeline.getSegmentAvailabilityEnd?.();
|
|
1638
|
+
if (liveEdge === void 0) return { isLive: true, isNearEdge: false };
|
|
1639
|
+
const currentTime = videoElement.currentTime;
|
|
1640
|
+
const timeBehindLive = liveEdge - currentTime;
|
|
1641
|
+
return {
|
|
1642
|
+
isLive: true,
|
|
1643
|
+
isNearEdge: timeBehindLive <= liveThresholdSeconds,
|
|
1644
|
+
liveEdge
|
|
1645
|
+
};
|
|
670
1646
|
} catch (error) {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
1647
|
+
console.error("Error checking live status:", error);
|
|
1648
|
+
return { isLive: false, isNearEdge: false };
|
|
674
1649
|
}
|
|
675
1650
|
};
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
};
|
|
690
|
-
}, [enabled, playerRef.current]);
|
|
691
|
-
useEffect(() => {
|
|
692
|
-
return () => {
|
|
693
|
-
if (intervalRef.current) {
|
|
694
|
-
clearInterval(intervalRef.current);
|
|
1651
|
+
const seekToLiveEdge = () => {
|
|
1652
|
+
const player = playerRef.current;
|
|
1653
|
+
if (!player) return;
|
|
1654
|
+
try {
|
|
1655
|
+
const manifest = player.getManifest();
|
|
1656
|
+
if (!manifest) return;
|
|
1657
|
+
const timeline = manifest.presentationTimeline;
|
|
1658
|
+
const liveEdge = timeline?.getSeekRangeEnd?.() ?? timeline?.getSegmentAvailabilityEnd?.();
|
|
1659
|
+
if (liveEdge !== void 0) {
|
|
1660
|
+
const videoElement = player.getMediaElement?.();
|
|
1661
|
+
if (videoElement) {
|
|
1662
|
+
videoElement.currentTime = liveEdge;
|
|
1663
|
+
}
|
|
695
1664
|
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
const showBadge = () => setIsVisible(true);
|
|
700
|
-
return {
|
|
701
|
-
isLive,
|
|
702
|
-
isVisible,
|
|
703
|
-
hideBadge,
|
|
704
|
-
showBadge,
|
|
705
|
-
checkLiveStatus
|
|
1665
|
+
} catch (error) {
|
|
1666
|
+
console.error("Error seeking to live edge:", error);
|
|
1667
|
+
}
|
|
706
1668
|
};
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
// src/hooks/usePosterFallback.ts
|
|
710
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
711
|
-
|
|
712
|
-
// src/hooks/useLiveIndicator.ts
|
|
713
|
-
import { useEffect as useEffect3, useRef as useRef7 } from "react";
|
|
714
|
-
var useLiveIndicator = (containerRef, options = {}) => {
|
|
715
|
-
const observerRef = useRef7(null);
|
|
716
|
-
const {
|
|
717
|
-
enabled = true,
|
|
718
|
-
indicatorColor = "#ff0000",
|
|
719
|
-
indicatorSize = 8,
|
|
720
|
-
showPulseAnimation = true
|
|
721
|
-
} = options;
|
|
722
|
-
useEffect3(() => {
|
|
1669
|
+
useEffect2(() => {
|
|
723
1670
|
if (!containerRef.current || !enabled) {
|
|
724
1671
|
return;
|
|
725
1672
|
}
|
|
726
|
-
const
|
|
727
|
-
|
|
1673
|
+
const updateLiveIndicator = (currentTimeElement, status) => {
|
|
1674
|
+
const parent = currentTimeElement.parentElement;
|
|
1675
|
+
if (!parent) return;
|
|
1676
|
+
const existingContainer = parent.querySelector(".live-indicator-container");
|
|
1677
|
+
const isCurrentlyNearEdge = existingContainer?.getAttribute("data-near-edge") === "true";
|
|
1678
|
+
if (existingContainer && status.isNearEdge === isCurrentlyNearEdge) {
|
|
728
1679
|
return;
|
|
729
1680
|
}
|
|
1681
|
+
if (existingContainer) {
|
|
1682
|
+
existingContainer.remove();
|
|
1683
|
+
}
|
|
1684
|
+
const container = document.createElement("span");
|
|
1685
|
+
container.className = "live-indicator-container";
|
|
1686
|
+
container.setAttribute("data-near-edge", status.isNearEdge.toString());
|
|
1687
|
+
container.style.cssText = `
|
|
1688
|
+
display: inline-flex;
|
|
1689
|
+
align-items: center;
|
|
1690
|
+
width: 80px;
|
|
1691
|
+
${!status.isNearEdge ? "cursor: pointer;" : ""}
|
|
1692
|
+
`;
|
|
730
1693
|
const indicator = document.createElement("span");
|
|
731
1694
|
indicator.className = "live-indicator-dot";
|
|
732
1695
|
indicator.style.cssText = `
|
|
733
1696
|
display: inline-block;
|
|
734
1697
|
width: ${indicatorSize}px;
|
|
735
1698
|
height: ${indicatorSize}px;
|
|
736
|
-
background-color: ${indicatorColor};
|
|
1699
|
+
background-color: ${status.isNearEdge ? indicatorColor : "#888888"};
|
|
737
1700
|
border-radius: 50%;
|
|
738
1701
|
margin-right: 6px;
|
|
739
|
-
|
|
740
|
-
${showPulseAnimation ? "animation: pulse-live 2s infinite;" : ""}
|
|
1702
|
+
${status.isNearEdge && showPulseAnimation ? "animation: pulse-live 2s infinite;" : ""}
|
|
741
1703
|
`;
|
|
742
|
-
|
|
1704
|
+
const liveText = document.createElement("span");
|
|
1705
|
+
liveText.className = "live-indicator-text";
|
|
1706
|
+
liveText.textContent = status.isNearEdge ? "LIVE" : "GO TO LIVE";
|
|
1707
|
+
container.appendChild(indicator);
|
|
1708
|
+
container.appendChild(liveText);
|
|
1709
|
+
if (!status.isNearEdge) {
|
|
1710
|
+
container.addEventListener("click", seekToLiveEdge);
|
|
1711
|
+
}
|
|
1712
|
+
if (status.isNearEdge) {
|
|
1713
|
+
parent.insertBefore(container, currentTimeElement);
|
|
1714
|
+
currentTimeElement.style.display = "none";
|
|
1715
|
+
} else {
|
|
1716
|
+
currentTimeElement.insertAdjacentElement("afterend", container);
|
|
1717
|
+
currentTimeElement.style.display = "";
|
|
1718
|
+
}
|
|
743
1719
|
};
|
|
744
1720
|
const removeLiveIndicator = (currentTimeElement) => {
|
|
745
|
-
const
|
|
746
|
-
if (
|
|
747
|
-
|
|
1721
|
+
const parent = currentTimeElement.parentElement;
|
|
1722
|
+
if (!parent) return;
|
|
1723
|
+
const container = parent.querySelector(".live-indicator-container");
|
|
1724
|
+
if (container) {
|
|
1725
|
+
container.remove();
|
|
1726
|
+
currentTimeElement.style.display = "";
|
|
748
1727
|
}
|
|
749
1728
|
};
|
|
750
1729
|
const checkForLiveContent = () => {
|
|
751
1730
|
const currentTimeElements = containerRef.current?.querySelectorAll(".shaka-current-time");
|
|
1731
|
+
const status = getLiveStatus(playerRef.current);
|
|
1732
|
+
const lastStatus = lastStatusRef.current;
|
|
1733
|
+
if (onLiveStatusChange && (!lastStatus || lastStatus.isLive !== status.isLive || lastStatus.isNearEdge !== status.isNearEdge)) {
|
|
1734
|
+
onLiveStatusChange(status);
|
|
1735
|
+
lastStatusRef.current = { isLive: status.isLive, isNearEdge: status.isNearEdge };
|
|
1736
|
+
}
|
|
752
1737
|
currentTimeElements?.forEach((element) => {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
addLiveIndicator(element);
|
|
1738
|
+
if (status.isLive) {
|
|
1739
|
+
updateLiveIndicator(element, status);
|
|
756
1740
|
} else {
|
|
757
1741
|
removeLiveIndicator(element);
|
|
758
1742
|
}
|
|
759
1743
|
});
|
|
760
1744
|
};
|
|
761
1745
|
checkForLiveContent();
|
|
1746
|
+
intervalRef.current = setInterval(checkForLiveContent, 1e3);
|
|
762
1747
|
observerRef.current = new MutationObserver((mutations) => {
|
|
763
1748
|
let shouldCheck = false;
|
|
764
1749
|
mutations.forEach((mutation) => {
|
|
@@ -784,31 +1769,289 @@ var useLiveIndicator = (containerRef, options = {}) => {
|
|
|
784
1769
|
characterData: true,
|
|
785
1770
|
characterDataOldValue: true
|
|
786
1771
|
});
|
|
787
|
-
const intervalId = setInterval(checkForLiveContent, 1e3);
|
|
788
1772
|
return () => {
|
|
789
1773
|
if (observerRef.current) {
|
|
790
1774
|
observerRef.current.disconnect();
|
|
791
1775
|
}
|
|
792
|
-
|
|
1776
|
+
if (intervalRef.current) {
|
|
1777
|
+
clearInterval(intervalRef.current);
|
|
1778
|
+
}
|
|
793
1779
|
};
|
|
794
|
-
}, [containerRef, enabled, indicatorColor, indicatorSize, showPulseAnimation]);
|
|
1780
|
+
}, [containerRef, enabled, indicatorColor, indicatorSize, showPulseAnimation, liveThresholdSeconds]);
|
|
795
1781
|
return {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1782
|
+
seekToLiveEdge,
|
|
1783
|
+
getLiveStatus: () => getLiveStatus(playerRef.current)
|
|
1784
|
+
};
|
|
1785
|
+
};
|
|
1786
|
+
|
|
1787
|
+
// src/hooks/useKeyboardControls.ts
|
|
1788
|
+
import { useCallback as useCallback7, useEffect as useEffect3 } from "react";
|
|
1789
|
+
var useKeyboardControls = (videoRef, options = {}) => {
|
|
1790
|
+
const { skipBack, skipForward, enabled = true } = options;
|
|
1791
|
+
const isDesktop = useCallback7(() => {
|
|
1792
|
+
return window.innerWidth > 767 && !/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
1793
|
+
}, []);
|
|
1794
|
+
const handleKeydown = useCallback7((event) => {
|
|
1795
|
+
if (!enabled || !isDesktop() || !videoRef.current) return;
|
|
1796
|
+
const activeElement = document.activeElement;
|
|
1797
|
+
if (activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.isContentEditable)) {
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
switch (event.key) {
|
|
1801
|
+
case "ArrowLeft":
|
|
1802
|
+
event.preventDefault();
|
|
1803
|
+
skipBack?.();
|
|
1804
|
+
break;
|
|
1805
|
+
case "ArrowRight":
|
|
1806
|
+
event.preventDefault();
|
|
1807
|
+
skipForward?.();
|
|
1808
|
+
break;
|
|
1809
|
+
case " ":
|
|
1810
|
+
case "Space":
|
|
1811
|
+
event.preventDefault();
|
|
1812
|
+
if (videoRef.current.paused) {
|
|
1813
|
+
videoRef.current.play();
|
|
1814
|
+
} else {
|
|
1815
|
+
videoRef.current.pause();
|
|
802
1816
|
}
|
|
1817
|
+
break;
|
|
1818
|
+
}
|
|
1819
|
+
}, [enabled, videoRef, skipBack, skipForward, isDesktop]);
|
|
1820
|
+
useEffect3(() => {
|
|
1821
|
+
if (!enabled || !isDesktop()) return;
|
|
1822
|
+
document.addEventListener("keydown", handleKeydown);
|
|
1823
|
+
return () => {
|
|
1824
|
+
document.removeEventListener("keydown", handleKeydown);
|
|
1825
|
+
};
|
|
1826
|
+
}, [handleKeydown, enabled, isDesktop]);
|
|
1827
|
+
return {
|
|
1828
|
+
isDesktop: isDesktop()
|
|
1829
|
+
};
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1832
|
+
// src/hooks/useAdEvents.ts
|
|
1833
|
+
import { useCallback as useCallback8, useRef as useRef7 } from "react";
|
|
1834
|
+
var useAdEvents = (playerRef, handlers) => {
|
|
1835
|
+
const listenersRef = useRef7([]);
|
|
1836
|
+
const setupAdEventListeners = useCallback8(() => {
|
|
1837
|
+
const player = playerRef.current;
|
|
1838
|
+
if (!player) return;
|
|
1839
|
+
const adManager = player.getAdManager();
|
|
1840
|
+
if (!adManager) return;
|
|
1841
|
+
const onAdsManagerLoaded = (event) => {
|
|
1842
|
+
const adsManager = event.getAdsManager();
|
|
1843
|
+
const onAdStarted = () => {
|
|
1844
|
+
console.log("Ad started");
|
|
1845
|
+
handlers.onAdStart?.();
|
|
1846
|
+
};
|
|
1847
|
+
const onAdComplete = () => {
|
|
1848
|
+
console.log("Ad completed");
|
|
1849
|
+
handlers.onAdComplete?.();
|
|
1850
|
+
};
|
|
1851
|
+
const onAdError = (adErrorEvent) => {
|
|
1852
|
+
console.error("Ad error:", adErrorEvent.getError());
|
|
1853
|
+
handlers.onAdError?.(adErrorEvent.getError());
|
|
1854
|
+
};
|
|
1855
|
+
const onAdSkipped = () => {
|
|
1856
|
+
console.log("Ad skipped");
|
|
1857
|
+
handlers.onAdSkipped?.();
|
|
1858
|
+
};
|
|
1859
|
+
const onAdPaused = () => {
|
|
1860
|
+
console.log("Ad paused");
|
|
1861
|
+
handlers.onAdPaused?.();
|
|
1862
|
+
};
|
|
1863
|
+
const onAdResumed = () => {
|
|
1864
|
+
console.log("Ad resumed");
|
|
1865
|
+
handlers.onAdResumed?.();
|
|
1866
|
+
};
|
|
1867
|
+
const onAdProgress = (adProgressData) => {
|
|
1868
|
+
handlers.onAdProgress?.(adProgressData);
|
|
1869
|
+
};
|
|
1870
|
+
const onAllAdsCompleted = () => {
|
|
1871
|
+
console.log("All ads completed");
|
|
1872
|
+
handlers.onAllAdsCompleted?.();
|
|
1873
|
+
};
|
|
1874
|
+
const adEventListeners = [];
|
|
1875
|
+
if (window.google?.ima) {
|
|
1876
|
+
const AdEvent = window.google.ima.AdEvent.Type;
|
|
1877
|
+
const AdErrorEvent = window.google.ima.AdErrorEvent.Type;
|
|
1878
|
+
if (handlers.onAdStart) {
|
|
1879
|
+
adsManager.addEventListener(AdEvent.STARTED, onAdStarted);
|
|
1880
|
+
adEventListeners.push({ event: AdEvent.STARTED, listener: onAdStarted });
|
|
1881
|
+
}
|
|
1882
|
+
if (handlers.onAdComplete) {
|
|
1883
|
+
adsManager.addEventListener(AdEvent.COMPLETE, onAdComplete);
|
|
1884
|
+
adEventListeners.push({ event: AdEvent.COMPLETE, listener: onAdComplete });
|
|
1885
|
+
}
|
|
1886
|
+
if (handlers.onAdError) {
|
|
1887
|
+
adsManager.addEventListener(AdErrorEvent.AD_ERROR, onAdError);
|
|
1888
|
+
adEventListeners.push({ event: AdErrorEvent.AD_ERROR, listener: onAdError });
|
|
1889
|
+
}
|
|
1890
|
+
if (handlers.onAdSkipped) {
|
|
1891
|
+
adsManager.addEventListener(AdEvent.SKIPPED, onAdSkipped);
|
|
1892
|
+
adEventListeners.push({ event: AdEvent.SKIPPED, listener: onAdSkipped });
|
|
1893
|
+
}
|
|
1894
|
+
if (handlers.onAdPaused) {
|
|
1895
|
+
adsManager.addEventListener(AdEvent.PAUSED, onAdPaused);
|
|
1896
|
+
adEventListeners.push({ event: AdEvent.PAUSED, listener: onAdPaused });
|
|
1897
|
+
}
|
|
1898
|
+
if (handlers.onAdResumed) {
|
|
1899
|
+
adsManager.addEventListener(AdEvent.RESUMED, onAdResumed);
|
|
1900
|
+
adEventListeners.push({ event: AdEvent.RESUMED, listener: onAdResumed });
|
|
1901
|
+
}
|
|
1902
|
+
if (handlers.onAdProgress) {
|
|
1903
|
+
adsManager.addEventListener(AdEvent.AD_PROGRESS, onAdProgress);
|
|
1904
|
+
adEventListeners.push({ event: AdEvent.AD_PROGRESS, listener: onAdProgress });
|
|
1905
|
+
}
|
|
1906
|
+
if (handlers.onAllAdsCompleted) {
|
|
1907
|
+
adsManager.addEventListener(AdEvent.ALL_ADS_COMPLETED, onAllAdsCompleted);
|
|
1908
|
+
adEventListeners.push({ event: AdEvent.ALL_ADS_COMPLETED, listener: onAllAdsCompleted });
|
|
1909
|
+
}
|
|
1910
|
+
listenersRef.current.push({
|
|
1911
|
+
adsManager,
|
|
1912
|
+
listeners: adEventListeners
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1916
|
+
try {
|
|
1917
|
+
player.addEventListener("ad-started", () => {
|
|
1918
|
+
console.log("Shaka ad-started event");
|
|
1919
|
+
handlers.onAdStart?.();
|
|
1920
|
+
});
|
|
1921
|
+
player.addEventListener("ad-complete", () => {
|
|
1922
|
+
console.log("Shaka ad-complete event");
|
|
1923
|
+
handlers.onAdComplete?.();
|
|
1924
|
+
});
|
|
1925
|
+
player.addEventListener("ad-skipped", () => {
|
|
1926
|
+
console.log("Shaka ad-skipped event");
|
|
1927
|
+
handlers.onAdSkipped?.();
|
|
1928
|
+
});
|
|
1929
|
+
player.addEventListener("ad-error", (event) => {
|
|
1930
|
+
console.error("Shaka ad-error event:", event);
|
|
1931
|
+
handlers.onAdError?.(event);
|
|
1932
|
+
});
|
|
1933
|
+
listenersRef.current.push({
|
|
1934
|
+
type: "shaka",
|
|
1935
|
+
player,
|
|
1936
|
+
events: ["ad-started", "ad-complete", "ad-skipped", "ad-error"]
|
|
803
1937
|
});
|
|
1938
|
+
} catch (error) {
|
|
1939
|
+
console.warn("Error setting up ad event listeners:", error);
|
|
1940
|
+
}
|
|
1941
|
+
}, [playerRef, handlers]);
|
|
1942
|
+
const cleanupAdEventListeners = useCallback8(() => {
|
|
1943
|
+
try {
|
|
1944
|
+
listenersRef.current.forEach((listenerGroup) => {
|
|
1945
|
+
if (listenerGroup.type === "shaka" && listenerGroup.player) {
|
|
1946
|
+
listenerGroup.events.forEach((eventName) => {
|
|
1947
|
+
try {
|
|
1948
|
+
listenerGroup.player.removeEventListener(eventName, () => {
|
|
1949
|
+
});
|
|
1950
|
+
} catch (e) {
|
|
1951
|
+
console.warn(`Error removing ${eventName} listener:`, e);
|
|
1952
|
+
}
|
|
1953
|
+
});
|
|
1954
|
+
} else if (listenerGroup.adsManager && listenerGroup.listeners) {
|
|
1955
|
+
listenerGroup.listeners.forEach(({ event, listener }) => {
|
|
1956
|
+
try {
|
|
1957
|
+
listenerGroup.adsManager.removeEventListener(event, listener);
|
|
1958
|
+
} catch (e) {
|
|
1959
|
+
console.warn("Error removing ad listener:", e);
|
|
1960
|
+
}
|
|
1961
|
+
});
|
|
1962
|
+
}
|
|
1963
|
+
});
|
|
1964
|
+
listenersRef.current = [];
|
|
1965
|
+
} catch (error) {
|
|
1966
|
+
console.warn("Error cleaning up ad event listeners:", error);
|
|
804
1967
|
}
|
|
1968
|
+
}, []);
|
|
1969
|
+
return {
|
|
1970
|
+
setupAdEventListeners,
|
|
1971
|
+
cleanupAdEventListeners
|
|
805
1972
|
};
|
|
806
1973
|
};
|
|
807
1974
|
|
|
1975
|
+
// src/Player.tsx
|
|
1976
|
+
import { twMerge as twMerge2 } from "tailwind-merge";
|
|
1977
|
+
|
|
1978
|
+
// src/utils/scriptLoader.ts
|
|
1979
|
+
var SCRIPT_CONFIGS = {
|
|
1980
|
+
ima: {
|
|
1981
|
+
src: "https://imasdk.googleapis.com/js/sdkloader/ima3.js",
|
|
1982
|
+
id: "ima-sdk",
|
|
1983
|
+
type: "text/javascript"
|
|
1984
|
+
},
|
|
1985
|
+
system73: {
|
|
1986
|
+
src: "//cdn.s73cloud.com/4/s73-sdk-shakaplayer.js",
|
|
1987
|
+
id: "system73-sdk",
|
|
1988
|
+
type: "application/javascript"
|
|
1989
|
+
}
|
|
1990
|
+
};
|
|
1991
|
+
function loadScript(config) {
|
|
1992
|
+
return new Promise((resolve, reject) => {
|
|
1993
|
+
if (document.getElementById(config.id)) {
|
|
1994
|
+
resolve();
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
const script = document.createElement("script");
|
|
1998
|
+
script.id = config.id;
|
|
1999
|
+
script.src = config.src;
|
|
2000
|
+
script.type = config.type || "text/javascript";
|
|
2001
|
+
script.async = true;
|
|
2002
|
+
script.onload = () => resolve();
|
|
2003
|
+
script.onerror = () => reject(new Error(`Failed to load script: ${config.src}`));
|
|
2004
|
+
document.head.appendChild(script);
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
function getRequiredScriptLoaders(needsIma, needsSystem73) {
|
|
2008
|
+
const loaders = [];
|
|
2009
|
+
if (needsIma) {
|
|
2010
|
+
loaders.push(loadScript(SCRIPT_CONFIGS.ima));
|
|
2011
|
+
}
|
|
2012
|
+
if (needsSystem73) {
|
|
2013
|
+
loaders.push(loadScript(SCRIPT_CONFIGS.system73));
|
|
2014
|
+
}
|
|
2015
|
+
return loaders;
|
|
2016
|
+
}
|
|
2017
|
+
async function loadScripts(scriptLoaders) {
|
|
2018
|
+
if (scriptLoaders.length === 0) {
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
try {
|
|
2022
|
+
await Promise.all(scriptLoaders);
|
|
2023
|
+
} catch (error) {
|
|
2024
|
+
console.error("Error loading scripts:", error);
|
|
2025
|
+
throw error;
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
function waitForGlobal(globalName, timeout = 5e3) {
|
|
2029
|
+
return new Promise((resolve, reject) => {
|
|
2030
|
+
const startTime = Date.now();
|
|
2031
|
+
function checkGlobal() {
|
|
2032
|
+
const global = window[globalName];
|
|
2033
|
+
if (global) {
|
|
2034
|
+
resolve(global);
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
if (Date.now() - startTime > timeout) {
|
|
2038
|
+
reject(new Error(`Timeout waiting for global: ${globalName}`));
|
|
2039
|
+
return;
|
|
2040
|
+
}
|
|
2041
|
+
setTimeout(checkGlobal, 100);
|
|
2042
|
+
}
|
|
2043
|
+
checkGlobal();
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2046
|
+
async function waitForGlobals(globalNames, timeout = 5e3) {
|
|
2047
|
+
const promises = globalNames.map((name) => waitForGlobal(name, timeout));
|
|
2048
|
+
await Promise.all(promises);
|
|
2049
|
+
}
|
|
2050
|
+
|
|
808
2051
|
// src/components/Loading.tsx
|
|
809
2052
|
import { twMerge } from "tailwind-merge";
|
|
810
|
-
import { jsx
|
|
811
|
-
var Loading = ({ className }) => /* @__PURE__ */
|
|
2053
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
2054
|
+
var Loading = ({ className }) => /* @__PURE__ */ jsx4(
|
|
812
2055
|
"div",
|
|
813
2056
|
{
|
|
814
2057
|
className: twMerge(
|
|
@@ -816,17 +2059,36 @@ var Loading = ({ className }) => /* @__PURE__ */ jsxs(
|
|
|
816
2059
|
className
|
|
817
2060
|
),
|
|
818
2061
|
role: "status",
|
|
819
|
-
children:
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
2062
|
+
children: /* @__PURE__ */ jsx4("div", { className: " flex justify-center items-center", children: /* @__PURE__ */ jsx4(
|
|
2063
|
+
"svg",
|
|
2064
|
+
{
|
|
2065
|
+
className: "shaka-spinner-svg animate-spin h-12 w-12",
|
|
2066
|
+
viewBox: "0 0 64 64",
|
|
2067
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2068
|
+
children: /* @__PURE__ */ jsx4(
|
|
2069
|
+
"circle",
|
|
2070
|
+
{
|
|
2071
|
+
className: "shaka-spinner-path",
|
|
2072
|
+
cx: "32",
|
|
2073
|
+
cy: "32",
|
|
2074
|
+
r: "28",
|
|
2075
|
+
strokeWidth: "4",
|
|
2076
|
+
strokeLinecap: "round",
|
|
2077
|
+
stroke: "currentColor",
|
|
2078
|
+
fill: "none",
|
|
2079
|
+
strokeDasharray: "176",
|
|
2080
|
+
strokeDashoffset: "120"
|
|
2081
|
+
}
|
|
2082
|
+
)
|
|
2083
|
+
}
|
|
2084
|
+
) })
|
|
823
2085
|
}
|
|
824
2086
|
);
|
|
825
2087
|
|
|
826
2088
|
// src/components/ErrorScreen.tsx
|
|
827
|
-
import { jsx as
|
|
828
|
-
var ErrorScreen = ({ title, description }) => /* @__PURE__ */
|
|
829
|
-
/* @__PURE__ */
|
|
2089
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2090
|
+
var ErrorScreen = ({ title, description }) => /* @__PURE__ */ jsx5("div", { className: "w-full h-full md:rounded-2xl! aspect-video bg-black flex", children: /* @__PURE__ */ jsxs3("div", { className: "bg-[#151515] text-white w-full h-full flex justify-center items-center", children: [
|
|
2091
|
+
/* @__PURE__ */ jsx5(
|
|
830
2092
|
"svg",
|
|
831
2093
|
{
|
|
832
2094
|
className: "w-24 h-24 m-6",
|
|
@@ -836,7 +2098,7 @@ var ErrorScreen = ({ title, description }) => /* @__PURE__ */ jsx2("div", { clas
|
|
|
836
2098
|
style: { width: 96 },
|
|
837
2099
|
viewBox: "0 0 24 24",
|
|
838
2100
|
xmlns: "http://www.w3.org/2000/svg",
|
|
839
|
-
children: /* @__PURE__ */
|
|
2101
|
+
children: /* @__PURE__ */ jsx5(
|
|
840
2102
|
"path",
|
|
841
2103
|
{
|
|
842
2104
|
d: "M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z",
|
|
@@ -846,66 +2108,22 @@ var ErrorScreen = ({ title, description }) => /* @__PURE__ */ jsx2("div", { clas
|
|
|
846
2108
|
)
|
|
847
2109
|
}
|
|
848
2110
|
),
|
|
849
|
-
/* @__PURE__ */
|
|
850
|
-
/* @__PURE__ */
|
|
851
|
-
/* @__PURE__ */
|
|
2111
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
2112
|
+
/* @__PURE__ */ jsx5("h3", { className: "text-2xl mb-2", children: title || "Playback Error" }),
|
|
2113
|
+
/* @__PURE__ */ jsx5("div", { className: "text-lg", children: description || "Unable to play the video. Please try again later." })
|
|
852
2114
|
] })
|
|
853
2115
|
] }) });
|
|
854
2116
|
|
|
855
2117
|
// src/components/Title.tsx
|
|
856
|
-
import { jsx as
|
|
857
|
-
var Title = ({ title }) => /* @__PURE__ */
|
|
858
|
-
|
|
859
|
-
// src/components/LiveBadge.tsx
|
|
860
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
861
|
-
var LiveBadge = ({
|
|
862
|
-
isVisible,
|
|
863
|
-
position = "top-right",
|
|
864
|
-
className = "",
|
|
865
|
-
style = {},
|
|
866
|
-
text = "LIVE"
|
|
867
|
-
}) => {
|
|
868
|
-
if (!isVisible) return null;
|
|
869
|
-
const positionClasses = {
|
|
870
|
-
"top-left": "top-4 left-4",
|
|
871
|
-
"top-right": "top-4 right-4",
|
|
872
|
-
"bottom-left": "bottom-4 left-4",
|
|
873
|
-
"bottom-right": "bottom-4 right-4"
|
|
874
|
-
};
|
|
875
|
-
return /* @__PURE__ */ jsx4(
|
|
876
|
-
"div",
|
|
877
|
-
{
|
|
878
|
-
className: `
|
|
879
|
-
absolute z-50
|
|
880
|
-
${positionClasses[position]}
|
|
881
|
-
bg-red-600 text-white
|
|
882
|
-
px-2 py-1
|
|
883
|
-
rounded-md
|
|
884
|
-
text-xs font-bold
|
|
885
|
-
uppercase tracking-wide
|
|
886
|
-
shadow-lg
|
|
887
|
-
animate-pulse
|
|
888
|
-
pointer-events-none
|
|
889
|
-
${className}
|
|
890
|
-
`,
|
|
891
|
-
style,
|
|
892
|
-
children: /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-1", children: [
|
|
893
|
-
/* @__PURE__ */ jsx4("span", { className: "w-2 h-2 bg-white rounded-full animate-pulse" }),
|
|
894
|
-
text
|
|
895
|
-
] })
|
|
896
|
-
}
|
|
897
|
-
);
|
|
898
|
-
};
|
|
899
|
-
|
|
900
|
-
// src/styles.css
|
|
901
|
-
styleInject('/*! tailwindcss v4.1.8 | MIT License | https://tailwindcss.com */\n@layer properties;\n@layer theme, base, components, utilities;\n@layer theme {\n :root,\n :host {\n --font-sans:\n ui-sans-serif,\n system-ui,\n sans-serif,\n "Apple Color Emoji",\n "Segoe UI Emoji",\n "Segoe UI Symbol",\n "Noto Color Emoji";\n --font-mono:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Monaco,\n Consolas,\n "Liberation Mono",\n "Courier New",\n monospace;\n --color-red-600: oklch(57.7% 0.245 27.325);\n --color-black: #000;\n --color-white: #fff;\n --spacing: 0.25rem;\n --text-xs: 0.75rem;\n --text-xs--line-height: calc(1 / 0.75);\n --text-sm: 0.875rem;\n --text-sm--line-height: calc(1.25 / 0.875);\n --text-base: 1rem;\n --text-base--line-height: calc(1.5 / 1);\n --text-lg: 1.125rem;\n --text-lg--line-height: calc(1.75 / 1.125);\n --text-xl: 1.25rem;\n --text-xl--line-height: calc(1.75 / 1.25);\n --text-2xl: 1.5rem;\n --text-2xl--line-height: calc(2 / 1.5);\n --text-5xl: 3rem;\n --text-5xl--line-height: 1;\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --tracking-wide: 0.025em;\n --tracking-widest: 0.1em;\n --radius-md: 0.375rem;\n --radius-2xl: 1rem;\n --animate-spin: spin 1s linear infinite;\n --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n --aspect-video: 16 / 9;\n --default-transition-duration: 150ms;\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n --default-font-family: var(--font-sans);\n --default-mono-font-family: var(--font-mono);\n }\n}\n@layer base {\n *,\n ::after,\n ::before,\n ::backdrop,\n ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n }\n html,\n :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n tab-size: 4;\n font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");\n font-feature-settings: var(--default-font-feature-settings, normal);\n font-variation-settings: var(--default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n }\n hr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n }\n abbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n }\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n font-size: inherit;\n font-weight: inherit;\n }\n a {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n }\n b,\n strong {\n font-weight: bolder;\n }\n code,\n kbd,\n samp,\n pre {\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\n font-size: 1em;\n }\n small {\n font-size: 80%;\n }\n sub,\n sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n sub {\n bottom: -0.25em;\n }\n sup {\n top: -0.5em;\n }\n table {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n }\n :-moz-focusring {\n outline: auto;\n }\n progress {\n vertical-align: baseline;\n }\n summary {\n display: list-item;\n }\n ol,\n ul,\n menu {\n list-style: none;\n }\n img,\n svg,\n video,\n canvas,\n audio,\n iframe,\n embed,\n object {\n display: block;\n vertical-align: middle;\n }\n img,\n video {\n max-width: 100%;\n height: auto;\n }\n button,\n input,\n select,\n optgroup,\n textarea,\n ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n }\n :where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n }\n :where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n }\n ::file-selector-button {\n margin-inline-end: 4px;\n }\n ::placeholder {\n opacity: 1;\n }\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n }\n textarea {\n resize: vertical;\n }\n ::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n ::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n }\n ::-webkit-datetime-edit {\n display: inline-flex;\n }\n ::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n }\n ::-webkit-datetime-edit,\n ::-webkit-datetime-edit-year-field,\n ::-webkit-datetime-edit-month-field,\n ::-webkit-datetime-edit-day-field,\n ::-webkit-datetime-edit-hour-field,\n ::-webkit-datetime-edit-minute-field,\n ::-webkit-datetime-edit-second-field,\n ::-webkit-datetime-edit-millisecond-field,\n ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n }\n :-moz-ui-invalid {\n box-shadow: none;\n }\n button,\n input:where([type=button], [type=reset], [type=submit]),\n ::file-selector-button {\n appearance: button;\n }\n ::-webkit-inner-spin-button,\n ::-webkit-outer-spin-button {\n height: auto;\n }\n [hidden]:where(:not([hidden=until-found])) {\n display: none !important;\n }\n}\n@layer utilities {\n .pointer-events-auto {\n pointer-events: auto;\n }\n .pointer-events-none {\n pointer-events: none;\n }\n .visible {\n visibility: visible;\n }\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n }\n .absolute {\n position: absolute;\n }\n .fixed {\n position: fixed;\n }\n .relative {\n position: relative;\n }\n .static {\n position: static;\n }\n .inset-0 {\n inset: calc(var(--spacing) * 0);\n }\n .top-0 {\n top: calc(var(--spacing) * 0);\n }\n .top-4 {\n top: calc(var(--spacing) * 4);\n }\n .right-0 {\n right: calc(var(--spacing) * 0);\n }\n .right-4 {\n right: calc(var(--spacing) * 4);\n }\n .bottom-0 {\n bottom: calc(var(--spacing) * 0);\n }\n .bottom-4 {\n bottom: calc(var(--spacing) * 4);\n }\n .left-0 {\n left: calc(var(--spacing) * 0);\n }\n .left-4 {\n left: calc(var(--spacing) * 4);\n }\n .z-10 {\n z-index: 10;\n }\n .z-50 {\n z-index: 50;\n }\n .container {\n width: 100%;\n @media (width >= 40rem) {\n max-width: 40rem;\n }\n @media (width >= 48rem) {\n max-width: 48rem;\n }\n @media (width >= 64rem) {\n max-width: 64rem;\n }\n @media (width >= 80rem) {\n max-width: 80rem;\n }\n @media (width >= 96rem) {\n max-width: 96rem;\n }\n }\n .m-6 {\n margin: calc(var(--spacing) * 6);\n }\n .mt-1 {\n margin-top: calc(var(--spacing) * 1);\n }\n .mt-3 {\n margin-top: calc(var(--spacing) * 3);\n }\n .mb-2 {\n margin-bottom: calc(var(--spacing) * 2);\n }\n .mb-6 {\n margin-bottom: calc(var(--spacing) * 6);\n }\n .flex {\n display: flex;\n }\n .grid {\n display: grid;\n }\n .hidden {\n display: none;\n }\n .aspect-video {\n aspect-ratio: var(--aspect-video);\n }\n .h-2 {\n height: calc(var(--spacing) * 2);\n }\n .h-8 {\n height: calc(var(--spacing) * 8);\n }\n .h-24 {\n height: calc(var(--spacing) * 24);\n }\n .h-full {\n height: 100%;\n }\n .w-2 {\n width: calc(var(--spacing) * 2);\n }\n .w-8 {\n width: calc(var(--spacing) * 8);\n }\n .w-24 {\n width: calc(var(--spacing) * 24);\n }\n .w-full {\n width: 100%;\n }\n .animate-pulse {\n animation: var(--animate-pulse);\n }\n .animate-spin {\n animation: var(--animate-spin);\n }\n .auto-cols-max {\n grid-auto-columns: max-content;\n }\n .grid-flow-col {\n grid-auto-flow: column;\n }\n .flex-col {\n flex-direction: column;\n }\n .items-center {\n align-items: center;\n }\n .justify-center {\n justify-content: center;\n }\n .justify-stretch {\n justify-content: stretch;\n }\n .gap-1 {\n gap: calc(var(--spacing) * 1);\n }\n .gap-5 {\n gap: calc(var(--spacing) * 5);\n }\n .overflow-hidden {\n overflow: hidden;\n }\n .rounded-full {\n border-radius: calc(infinity * 1px);\n }\n .rounded-md {\n border-radius: var(--radius-md);\n }\n .border-b-2 {\n border-bottom-style: var(--tw-border-style);\n border-bottom-width: 2px;\n }\n .border-white {\n border-color: var(--color-white);\n }\n .bg-\\[\\#151515\\] {\n background-color: #151515;\n }\n .bg-black {\n background-color: var(--color-black);\n }\n .bg-red-600 {\n background-color: var(--color-red-600);\n }\n .bg-white {\n background-color: var(--color-white);\n }\n .bg-gradient-to-t {\n --tw-gradient-position: to top in oklab;\n background-image: linear-gradient(var(--tw-gradient-stops));\n }\n .from-black\\/70 {\n --tw-gradient-from: color-mix(in srgb, #000 70%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n --tw-gradient-from: color-mix(in oklab, var(--color-black) 70%, transparent);\n }\n --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));\n }\n .to-transparent {\n --tw-gradient-to: transparent;\n --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));\n }\n .bg-cover {\n background-size: cover;\n }\n .bg-center {\n background-position: center;\n }\n .bg-no-repeat {\n background-repeat: no-repeat;\n }\n .p-2 {\n padding: calc(var(--spacing) * 2);\n }\n .p-4 {\n padding: calc(var(--spacing) * 4);\n }\n .px-2 {\n padding-inline: calc(var(--spacing) * 2);\n }\n .px-4 {\n padding-inline: calc(var(--spacing) * 4);\n }\n .py-1 {\n padding-block: calc(var(--spacing) * 1);\n }\n .text-center {\n text-align: center;\n }\n .text-left {\n text-align: left;\n }\n .font-mono {\n font-family: var(--font-mono);\n }\n .text-2xl {\n font-size: var(--text-2xl);\n line-height: var(--tw-leading, var(--text-2xl--line-height));\n }\n .text-5xl {\n font-size: var(--text-5xl);\n line-height: var(--tw-leading, var(--text-5xl--line-height));\n }\n .text-base {\n font-size: var(--text-base);\n line-height: var(--tw-leading, var(--text-base--line-height));\n }\n .text-lg {\n font-size: var(--text-lg);\n line-height: var(--tw-leading, var(--text-lg--line-height));\n }\n .text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n .text-xl {\n font-size: var(--text-xl);\n line-height: var(--tw-leading, var(--text-xl--line-height));\n }\n .text-xs {\n font-size: var(--text-xs);\n line-height: var(--tw-leading, var(--text-xs--line-height));\n }\n .text-\\[10px\\] {\n font-size: 10px;\n }\n .font-bold {\n --tw-font-weight: var(--font-weight-bold);\n font-weight: var(--font-weight-bold);\n }\n .font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n }\n .font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n }\n .tracking-wide {\n --tw-tracking: var(--tracking-wide);\n letter-spacing: var(--tracking-wide);\n }\n .tracking-widest {\n --tw-tracking: var(--tracking-widest);\n letter-spacing: var(--tracking-widest);\n }\n .text-white {\n color: var(--color-white);\n }\n .uppercase {\n text-transform: uppercase;\n }\n .shadow-lg {\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow:\n var(--tw-inset-shadow),\n var(--tw-inset-ring-shadow),\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow);\n }\n .filter {\n 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,);\n }\n .md\\:rounded-2xl {\n @media (width >= 48rem) {\n border-radius: var(--radius-2xl);\n }\n }\n .md\\:rounded-2xl\\! {\n @media (width >= 48rem) {\n border-radius: var(--radius-2xl) !important;\n }\n }\n .md\\:text-base {\n @media (width >= 48rem) {\n font-size: var(--text-base);\n line-height: var(--tw-leading, var(--text-base--line-height));\n }\n }\n .md\\:text-sm {\n @media (width >= 48rem) {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n }\n .md\\:text-xl {\n @media (width >= 48rem) {\n font-size: var(--text-xl);\n line-height: var(--tw-leading, var(--text-xl--line-height));\n }\n }\n}\n@layer components {\n .motto-video-container {\n position: relative;\n width: 100%;\n min-height: 300px;\n }\n @supports (aspect-ratio: 16/9) {\n .motto-video-container {\n min-height: auto;\n }\n }\n .motto-video-responsive {\n position: absolute;\n top: calc(var(--spacing) * 0);\n left: calc(var(--spacing) * 0);\n height: 100%;\n width: 100%;\n }\n .motto-skip-button {\n position: absolute;\n top: calc(1/2 * 100%);\n z-index: 10;\n display: flex;\n height: calc(var(--spacing) * 16);\n width: calc(var(--spacing) * 16);\n --tw-translate-y: calc(calc(1/2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n cursor: pointer;\n align-items: center;\n justify-content: center;\n border-radius: calc(infinity * 1px);\n border-style: var(--tw-border-style);\n border-width: 0px;\n background-color: color-mix(in srgb, #000 70%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 70%, transparent);\n }\n font-size: var(--text-2xl);\n line-height: var(--tw-leading, var(--text-2xl--line-height));\n color: var(--color-white);\n opacity: 80%;\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 200ms;\n transition-duration: 200ms;\n &:hover {\n @media (hover: hover) {\n --tw-scale-x: 110%;\n --tw-scale-y: 110%;\n --tw-scale-z: 110%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n }\n &:hover {\n @media (hover: hover) {\n opacity: 100%;\n }\n }\n &:active {\n --tw-scale-x: 95%;\n --tw-scale-y: 95%;\n --tw-scale-z: 95%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n }\n .motto-skip-button-back {\n left: calc(var(--spacing) * 5);\n }\n .motto-skip-button-forward {\n right: calc(var(--spacing) * 5);\n }\n .motto-mobile-controls-overlay {\n position: absolute;\n inset: calc(var(--spacing) * 0);\n z-index: 20;\n display: flex;\n align-items: center;\n justify-content: center;\n transition-property: opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 300ms;\n transition-duration: 300ms;\n pointer-events: none;\n }\n .motto-mobile-controls-group {\n display: flex;\n align-items: center;\n gap: calc(var(--spacing) * 8);\n opacity: 100%;\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 200ms;\n transition-duration: 200ms;\n pointer-events: none;\n }\n .motto-mobile-play-button {\n display: flex;\n height: calc(var(--spacing) * 14);\n width: calc(var(--spacing) * 14);\n cursor: pointer;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n border-radius: calc(infinity * 1px);\n border-style: var(--tw-border-style);\n border-width: 0px;\n background-color: color-mix(in srgb, #000 30%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 30%, transparent);\n }\n color: var(--color-white);\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow:\n var(--tw-inset-shadow),\n var(--tw-inset-ring-shadow),\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow);\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 200ms;\n transition-duration: 200ms;\n pointer-events: auto;\n }\n .motto-mobile-play-button:active {\n --tw-scale-x: 95%;\n --tw-scale-y: 95%;\n --tw-scale-z: 95%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n .motto-mobile-play-button svg {\n height: calc(var(--spacing) * 7);\n width: calc(var(--spacing) * 7);\n }\n .motto-mobile-skip-button {\n display: flex;\n height: calc(var(--spacing) * 10);\n width: calc(var(--spacing) * 10);\n cursor: pointer;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n border-radius: calc(infinity * 1px);\n border-style: var(--tw-border-style);\n border-width: 0px;\n background-color: color-mix(in srgb, #000 30%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 30%, transparent);\n }\n color: var(--color-white);\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow:\n var(--tw-inset-shadow),\n var(--tw-inset-ring-shadow),\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow);\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n --tw-duration: 200ms;\n transition-duration: 200ms;\n pointer-events: auto;\n }\n .motto-mobile-skip-button:active {\n --tw-scale-x: 95%;\n --tw-scale-y: 95%;\n --tw-scale-z: 95%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n .motto-mobile-skip-button svg {\n height: calc(var(--spacing) * 6);\n width: calc(var(--spacing) * 6);\n }\n}\n@media (min-width: 768px) {\n .motto-mobile-controls-overlay {\n display: none !important;\n }\n}\n@media (max-width: 767px) {\n .shaka-controls-container .motto-native-skip-button,\n .shaka-controls-container .motto-skip-back-button,\n .shaka-controls-container .motto-skip-forward-button,\n .shaka-controls-container .shaka-button[title*="Skip back"],\n .shaka-controls-container .shaka-button[title*="Skip forward"],\n .shaka-controls-container .shaka-button[aria-label*="Skip back"],\n .shaka-controls-container .shaka-button[aria-label*="Skip forward"],\n .shaka-controls-container button[title*="Skip back"],\n .shaka-controls-container button[title*="Skip forward"],\n .shaka-controls-container button[aria-label*="Skip back"],\n .shaka-controls-container button[aria-label*="Skip forward"],\n .motto-native-skip-button:not(.motto-mobile-skip-button),\n .motto-skip-back-button:not(.motto-mobile-skip-button),\n .motto-skip-forward-button:not(.motto-mobile-skip-button),\n .shaka-button[title*="Skip back"]:not(.motto-mobile-skip-button),\n .shaka-button[title*="Skip forward"]:not(.motto-mobile-skip-button),\n .shaka-button[aria-label*="Skip back"]:not(.motto-mobile-skip-button),\n .shaka-button[aria-label*="Skip forward"]:not(.motto-mobile-skip-button),\n button[title*="Skip back"]:not(.motto-mobile-skip-button),\n button[title*="Skip forward"]:not(.motto-mobile-skip-button),\n button[aria-label*="Skip back"]:not(.motto-mobile-skip-button),\n button[aria-label*="Skip forward"]:not(.motto-mobile-skip-button) {\n display: none !important;\n visibility: hidden !important;\n opacity: 0 !important;\n width: 0 !important;\n height: 0 !important;\n padding: 0 !important;\n margin: 0 !important;\n }\n .motto-mobile-skip-button {\n display: flex !important;\n visibility: visible !important;\n opacity: 1 !important;\n }\n}\n.shaka-seek-bar-container {\n height: 6px !important;\n width: 100% !important;\n margin: 8px 0 !important;\n border-radius: 4px !important;\n position: relative !important;\n border-top: none !important;\n border-bottom: none !important;\n box-shadow: none !important;\n}\n.shaka-seek-bar {\n height: 6px !important;\n width: 100% !important;\n -webkit-appearance: none !important;\n appearance: none !important;\n background: transparent !important;\n cursor: pointer !important;\n border: none !important;\n outline: none !important;\n position: absolute !important;\n top: 0 !important;\n left: 0 !important;\n border-radius: 4px !important;\n}\n.shaka-seek-bar::-webkit-slider-runnable-track {\n height: 6px !important;\n background: transparent !important;\n border-radius: 4px !important;\n border: none !important;\n}\n.shaka-seek-bar::-moz-range-track {\n height: 6px !important;\n background: transparent !important;\n border-radius: 4px !important;\n border: none !important;\n}\n.shaka-seek-bar::-webkit-slider-thumb {\n -webkit-appearance: none !important;\n appearance: none !important;\n width: 16px !important;\n height: 16px !important;\n border-radius: 50% !important;\n background: #ffffff !important;\n cursor: pointer !important;\n border: 2px solid #ffffff !important;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;\n margin-top: -4px !important;\n}\n.shaka-seek-bar::-moz-range-thumb {\n width: 16px !important;\n height: 16px !important;\n border-radius: 50% !important;\n background: #ffffff !important;\n cursor: pointer !important;\n border: 2px solid #ffffff !important;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;\n margin-top: -4px !important;\n}\n.motto-skip-back-button,\n.motto-skip-forward-button,\n.motto-native-skip-button {\n background: transparent !important;\n border: none !important;\n padding: 4px !important;\n margin: 0px !important;\n cursor: pointer !important;\n color: #ffffff !important;\n transition: all 0.2s ease !important;\n min-width: 32px !important;\n height: 32px !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n border-radius: 4px !important;\n width: 25px;\n}\n.motto-skip-back-button:hover,\n.motto-skip-forward-button:hover,\n.motto-native-skip-button:hover {\n opacity: 0.8 !important;\n background: transparent !important;\n transform: scale(1.05) !important;\n}\n.motto-skip-back-button:active,\n.motto-skip-forward-button:active,\n.motto-native-skip-button:active {\n transform: scale(0.95) !important;\n}\n.motto-skip-back-button svg,\n.motto-skip-forward-button svg,\n.motto-native-skip-button svg {\n width: 24px !important;\n height: 24px !important;\n}\n@media (max-width: 767px) {\n .shaka-controls-container .motto-native-skip-button,\n .shaka-controls-container .motto-skip-back-button,\n .shaka-controls-container .motto-skip-forward-button,\n .shaka-controls-container .shaka-play-button,\n .shaka-controls-container .shaka-pause-button {\n display: none !important;\n }\n}\n.shaka-spinner-svg {\n color: white !important;\n fill: white !important;\n}\n.shaka-spinner-path {\n stroke: white !important;\n fill: none !important;\n}\n.shaka-spinner-container {\n color: white !important;\n}\n.shaka-buffering-spinner {\n color: white !important;\n fill: white !important;\n}\n.shaka-buffering-spinner svg {\n color: white !important;\n fill: white !important;\n}\n.shaka-buffering-spinner path {\n stroke: white !important;\n fill: none !important;\n}\n[data-shaka-player-container] .shaka-spinner,\n[data-shaka-player-container] .spinner {\n color: white !important;\n border-color: white !important;\n}\n.material-icons.shaka-spinner {\n color: white !important;\n}\n.shaka-controls-container .shaka-spinner,\n.shaka-video-container .shaka-spinner {\n color: white !important;\n fill: white !important;\n}\n.shaka-controls-container .shaka-spinner svg,\n.shaka-video-container .shaka-spinner svg {\n color: white !important;\n fill: white !important;\n}\n.shaka-controls-container .shaka-spinner path,\n.shaka-video-container .shaka-spinner path {\n stroke: white !important;\n}\n.motto-video-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background:\n linear-gradient(\n 135deg,\n #1a1a1a 0%,\n #2d2d2d 100%);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n z-index: 10;\n transition: opacity 0.3s ease;\n}\n.motto-video-loading-overlay.hidden {\n opacity: 0;\n pointer-events: none;\n}\n.motto-video-loading-content {\n text-align: center;\n color: white;\n}\n.motto-video-loading-icon {\n width: 64px;\n height: 64px;\n margin-bottom: 16px;\n opacity: 0.7;\n}\n.motto-video-loading-text {\n font-size: 16px;\n font-weight: 500;\n margin-bottom: 8px;\n}\n.motto-video-loading-subtext {\n font-size: 14px;\n opacity: 0.7;\n}\n@keyframes pulse-live {\n 0% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.7;\n transform: scale(1.1);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n}\n@property --tw-border-style { syntax: "*"; inherits: false; initial-value: solid; }\n@property --tw-gradient-position { syntax: "*"; inherits: false; }\n@property --tw-gradient-from { syntax: "<color>"; inherits: false; initial-value: #0000; }\n@property --tw-gradient-via { syntax: "<color>"; inherits: false; initial-value: #0000; }\n@property --tw-gradient-to { syntax: "<color>"; inherits: false; initial-value: #0000; }\n@property --tw-gradient-stops { syntax: "*"; inherits: false; }\n@property --tw-gradient-via-stops { syntax: "*"; inherits: false; }\n@property --tw-gradient-from-position { syntax: "<length-percentage>"; inherits: false; initial-value: 0%; }\n@property --tw-gradient-via-position { syntax: "<length-percentage>"; inherits: false; initial-value: 50%; }\n@property --tw-gradient-to-position { syntax: "<length-percentage>"; inherits: false; initial-value: 100%; }\n@property --tw-font-weight { syntax: "*"; inherits: false; }\n@property --tw-tracking { syntax: "*"; inherits: false; }\n@property --tw-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-shadow-color { syntax: "*"; inherits: false; }\n@property --tw-shadow-alpha { syntax: "<percentage>"; inherits: false; initial-value: 100%; }\n@property --tw-inset-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-inset-shadow-color { syntax: "*"; inherits: false; }\n@property --tw-inset-shadow-alpha { syntax: "<percentage>"; inherits: false; initial-value: 100%; }\n@property --tw-ring-color { syntax: "*"; inherits: false; }\n@property --tw-ring-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-inset-ring-color { syntax: "*"; inherits: false; }\n@property --tw-inset-ring-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-ring-inset { syntax: "*"; inherits: false; }\n@property --tw-ring-offset-width { syntax: "<length>"; inherits: false; initial-value: 0px; }\n@property --tw-ring-offset-color { syntax: "*"; inherits: false; initial-value: #fff; }\n@property --tw-ring-offset-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }\n@property --tw-blur { syntax: "*"; inherits: false; }\n@property --tw-brightness { syntax: "*"; inherits: false; }\n@property --tw-contrast { syntax: "*"; inherits: false; }\n@property --tw-grayscale { syntax: "*"; inherits: false; }\n@property --tw-hue-rotate { syntax: "*"; inherits: false; }\n@property --tw-invert { syntax: "*"; inherits: false; }\n@property --tw-opacity { syntax: "*"; inherits: false; }\n@property --tw-saturate { syntax: "*"; inherits: false; }\n@property --tw-sepia { syntax: "*"; inherits: false; }\n@property --tw-drop-shadow { syntax: "*"; inherits: false; }\n@property --tw-drop-shadow-color { syntax: "*"; inherits: false; }\n@property --tw-drop-shadow-alpha { syntax: "<percentage>"; inherits: false; initial-value: 100%; }\n@property --tw-drop-shadow-size { syntax: "*"; inherits: false; }\n@property --tw-translate-x { syntax: "*"; inherits: false; initial-value: 0; }\n@property --tw-translate-y { syntax: "*"; inherits: false; initial-value: 0; }\n@property --tw-translate-z { syntax: "*"; inherits: false; initial-value: 0; }\n@property --tw-duration { syntax: "*"; inherits: false; }\n@property --tw-scale-x { syntax: "*"; inherits: false; initial-value: 1; }\n@property --tw-scale-y { syntax: "*"; inherits: false; initial-value: 1; }\n@property --tw-scale-z { syntax: "*"; inherits: false; initial-value: 1; }\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n@keyframes pulse {\n 50% {\n opacity: 0.5;\n }\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *,\n ::before,\n ::after,\n ::backdrop {\n --tw-border-style: solid;\n --tw-gradient-position: initial;\n --tw-gradient-from: #0000;\n --tw-gradient-via: #0000;\n --tw-gradient-to: #0000;\n --tw-gradient-stops: initial;\n --tw-gradient-via-stops: initial;\n --tw-gradient-from-position: 0%;\n --tw-gradient-via-position: 50%;\n --tw-gradient-to-position: 100%;\n --tw-font-weight: initial;\n --tw-tracking: initial;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-color: initial;\n --tw-shadow-alpha: 100%;\n --tw-inset-shadow: 0 0 #0000;\n --tw-inset-shadow-color: initial;\n --tw-inset-shadow-alpha: 100%;\n --tw-ring-color: initial;\n --tw-ring-shadow: 0 0 #0000;\n --tw-inset-ring-color: initial;\n --tw-inset-ring-shadow: 0 0 #0000;\n --tw-ring-inset: initial;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-blur: initial;\n --tw-brightness: initial;\n --tw-contrast: initial;\n --tw-grayscale: initial;\n --tw-hue-rotate: initial;\n --tw-invert: initial;\n --tw-opacity: initial;\n --tw-saturate: initial;\n --tw-sepia: initial;\n --tw-drop-shadow: initial;\n --tw-drop-shadow-color: initial;\n --tw-drop-shadow-alpha: 100%;\n --tw-drop-shadow-size: initial;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-duration: initial;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-scale-z: 1;\n }\n }\n}\n');
|
|
2118
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2119
|
+
var Title = ({ title }) => /* @__PURE__ */ jsx6("div", { className: "absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4", children: /* @__PURE__ */ jsx6("h2", { className: "text-white text-xl font-semibold", children: title }) });
|
|
902
2120
|
|
|
903
2121
|
// src/Player.tsx
|
|
904
|
-
import {
|
|
905
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2122
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
906
2123
|
var Player = forwardRef(
|
|
907
2124
|
({
|
|
908
2125
|
src,
|
|
2126
|
+
managedMode = false,
|
|
909
2127
|
autoPlay = false,
|
|
910
2128
|
loop = false,
|
|
911
2129
|
muted = false,
|
|
@@ -917,25 +2135,48 @@ var Player = forwardRef(
|
|
|
917
2135
|
shakaConfig,
|
|
918
2136
|
drmConfig,
|
|
919
2137
|
muxConfig,
|
|
2138
|
+
system73Config,
|
|
920
2139
|
imaConfig,
|
|
921
2140
|
chromecastConfig,
|
|
922
2141
|
qualityConfig,
|
|
923
2142
|
seekbarConfig,
|
|
2143
|
+
iconSizes,
|
|
924
2144
|
events,
|
|
2145
|
+
locale = "en",
|
|
925
2146
|
containerClassName,
|
|
926
|
-
|
|
2147
|
+
liveThresholdSeconds = 15,
|
|
2148
|
+
publicKey,
|
|
2149
|
+
auth,
|
|
2150
|
+
...videoProps
|
|
927
2151
|
}, ref) => {
|
|
928
2152
|
const videoRef = useRef8(null);
|
|
929
2153
|
const containerRef = useRef8(null);
|
|
930
|
-
const
|
|
2154
|
+
const [isScriptsLoaded, setIsScriptsLoaded] = useState3(false);
|
|
2155
|
+
const [isInitialLoading, setIsInitialLoading] = useState3(true);
|
|
2156
|
+
const [bfResetKey, setBfResetKey] = useState3(0);
|
|
2157
|
+
const hasPlaylist = !!src && (typeof src === "string" || !!(src.url || src.drm?.widevine?.playlistUrl || src.drm?.playready?.playlistUrl || src.drm?.fairplay?.playlistUrl));
|
|
931
2158
|
useImperativeHandle(ref, () => videoRef.current, []);
|
|
932
|
-
const { playerRef, initializePlayer, destroyPlayer } =
|
|
2159
|
+
const { playerRef, initializePlayer, loadManifest, destroyPlayer, isRetrying } = useShakaPlayer({
|
|
933
2160
|
src,
|
|
934
2161
|
shakaConfig,
|
|
935
2162
|
drmConfig,
|
|
936
2163
|
onError: events?.onError,
|
|
937
|
-
onPlayerReady: events?.onPlayerReady
|
|
2164
|
+
onPlayerReady: events?.onPlayerReady,
|
|
2165
|
+
muxConfig,
|
|
2166
|
+
onMuxReady: events?.onMuxReady,
|
|
2167
|
+
onMuxDataUpdate: events?.onMuxDataUpdate,
|
|
2168
|
+
publicKey,
|
|
2169
|
+
mottoToken: auth?.mottoToken,
|
|
2170
|
+
hasAds: !!imaConfig?.adTagUrl,
|
|
2171
|
+
hasSystem73: !!system73Config?.apiKey,
|
|
2172
|
+
apiToken: auth?.apiToken
|
|
938
2173
|
});
|
|
2174
|
+
const {
|
|
2175
|
+
initializeMux,
|
|
2176
|
+
updateMuxData,
|
|
2177
|
+
handleMuxError,
|
|
2178
|
+
destroyMux
|
|
2179
|
+
} = useMuxAnalytics(playerRef, muxConfig, events?.onMuxReady, events?.onMuxDataUpdate);
|
|
939
2180
|
const {
|
|
940
2181
|
getAvailableQualities,
|
|
941
2182
|
setQuality,
|
|
@@ -948,12 +2189,11 @@ var Player = forwardRef(
|
|
|
948
2189
|
skipDuration,
|
|
949
2190
|
shouldShowSkipControls
|
|
950
2191
|
} = useSkipControls(videoRef, events?.onSkipBack, events?.onSkipForward);
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
} = useMuxAnalytics(playerRef, muxConfig, events?.onMuxReady, events?.onMuxDataUpdate);
|
|
2192
|
+
useKeyboardControls(videoRef, {
|
|
2193
|
+
skipBack,
|
|
2194
|
+
skipForward,
|
|
2195
|
+
enabled: true
|
|
2196
|
+
});
|
|
957
2197
|
const { setupEventListeners, cleanupEventListeners } = useEventHandlers(videoRef, {
|
|
958
2198
|
onPlay: events?.onPlay,
|
|
959
2199
|
onPause: events?.onPause,
|
|
@@ -969,109 +2209,230 @@ var Player = forwardRef(
|
|
|
969
2209
|
chromecastConfig,
|
|
970
2210
|
seekbarConfig,
|
|
971
2211
|
events?.onSkipBack,
|
|
972
|
-
events?.onSkipForward
|
|
2212
|
+
events?.onSkipForward,
|
|
2213
|
+
iconSizes,
|
|
2214
|
+
locale
|
|
973
2215
|
);
|
|
974
|
-
const {
|
|
975
|
-
enabled: true,
|
|
976
|
-
onLiveStateChange: (isLive2) => {
|
|
977
|
-
events?.onLiveStateChange?.(isLive2);
|
|
978
|
-
}
|
|
979
|
-
});
|
|
980
|
-
useLiveIndicator(containerRef, {
|
|
2216
|
+
const { getLiveStatus, seekToLiveEdge } = useLiveIndicator(containerRef, playerRef, {
|
|
981
2217
|
enabled: true,
|
|
982
2218
|
indicatorColor: "#ff0000",
|
|
983
2219
|
indicatorSize: 8,
|
|
984
|
-
showPulseAnimation: true
|
|
2220
|
+
showPulseAnimation: true,
|
|
2221
|
+
liveThresholdSeconds,
|
|
2222
|
+
onLiveStatusChange: events?.onLiveStatusChange
|
|
985
2223
|
});
|
|
986
|
-
const
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
if (imaConfig.adTagUrl) {
|
|
1000
|
-
const adContainer = adContainerRef.current;
|
|
1001
|
-
if (adContainer) {
|
|
1002
|
-
adManager.initClientSide(adContainer, videoRef.current, imaConfig.adsRenderingSettings);
|
|
1003
|
-
const adsRequest = {
|
|
1004
|
-
adTagUrl: imaConfig.adTagUrl,
|
|
1005
|
-
linearAdSlotWidth: imaConfig.linearAdSlotWidth || width || 640,
|
|
1006
|
-
linearAdSlotHeight: imaConfig.linearAdSlotHeight || height || 360,
|
|
1007
|
-
nonLinearAdSlotWidth: imaConfig.nonLinearAdSlotWidth || width || 640,
|
|
1008
|
-
nonLinearAdSlotHeight: imaConfig.nonLinearAdSlotHeight || 150
|
|
1009
|
-
};
|
|
1010
|
-
adManager.requestClientSideAds(adsRequest);
|
|
1011
|
-
}
|
|
2224
|
+
const { setupAdEventListeners, cleanupAdEventListeners } = useAdEvents(playerRef, {
|
|
2225
|
+
onAdStart: events?.onAdStart,
|
|
2226
|
+
onAdComplete: events?.onAdComplete,
|
|
2227
|
+
onAdError: events?.onAdError,
|
|
2228
|
+
onAdSkipped: events?.onAdSkipped,
|
|
2229
|
+
onAdPaused: events?.onAdPaused,
|
|
2230
|
+
onAdResumed: events?.onAdResumed,
|
|
2231
|
+
onAdProgress: events?.onAdProgress,
|
|
2232
|
+
onAllAdsCompleted: events?.onAllAdsCompleted
|
|
2233
|
+
});
|
|
2234
|
+
const initializeSystem73 = useCallback9((playerConfig) => {
|
|
2235
|
+
if (!system73Config?.apiKey || !window.S73ShakaPlayerWrapper) {
|
|
2236
|
+
return null;
|
|
1012
2237
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
2238
|
+
console.log("Initializing System73 SDK...");
|
|
2239
|
+
try {
|
|
2240
|
+
const s73Config = {
|
|
2241
|
+
apiKey: system73Config.apiKey,
|
|
2242
|
+
contentSteeringEndpoint: system73Config.contentSteeringEndpoint,
|
|
2243
|
+
channelId: system73Config.channelId
|
|
2244
|
+
};
|
|
2245
|
+
const wrapper = window.S73ShakaPlayerWrapper(s73Config, { shaka: shaka3 });
|
|
2246
|
+
wrapper.wrapPlayerConfig(playerConfig);
|
|
2247
|
+
console.log("System73 SDK initialized with config:", s73Config);
|
|
2248
|
+
return wrapper;
|
|
2249
|
+
} catch (error) {
|
|
2250
|
+
console.error("Error initializing System73 SDK:", error);
|
|
2251
|
+
return null;
|
|
2252
|
+
}
|
|
2253
|
+
}, [system73Config]);
|
|
2254
|
+
const initializeAds = useCallback9(async () => {
|
|
2255
|
+
if (!imaConfig?.adTagUrl || !playerRef.current || !videoRef.current || !uiRef.current) {
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
if (!window.google?.ima) {
|
|
2259
|
+
console.error("Google IMA SDK not available when trying to initialize ads");
|
|
1016
2260
|
return;
|
|
1017
2261
|
}
|
|
1018
2262
|
try {
|
|
1019
|
-
|
|
1020
|
-
|
|
2263
|
+
const player = playerRef.current;
|
|
2264
|
+
const video = videoRef.current;
|
|
2265
|
+
const ui = uiRef.current;
|
|
2266
|
+
const controls2 = ui.getControls();
|
|
2267
|
+
const container = controls2.getClientSideAdContainer();
|
|
2268
|
+
const adManager = player.getAdManager();
|
|
2269
|
+
if (!adManager) {
|
|
2270
|
+
console.error("Ad manager not available");
|
|
2271
|
+
return;
|
|
1021
2272
|
}
|
|
2273
|
+
const google = window.google;
|
|
2274
|
+
let adsRenderingSettings = null;
|
|
2275
|
+
if (imaConfig.adsRenderingSettings) {
|
|
2276
|
+
adsRenderingSettings = imaConfig.adsRenderingSettings;
|
|
2277
|
+
} else if (autoPlay) {
|
|
2278
|
+
adsRenderingSettings = new google.ima.AdsRenderingSettings();
|
|
2279
|
+
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
|
|
2280
|
+
}
|
|
2281
|
+
adManager.initClientSide(container, video, adsRenderingSettings);
|
|
2282
|
+
const adsRequest = new google.ima.AdsRequest();
|
|
2283
|
+
adsRequest.adTagUrl = imaConfig.adTagUrl;
|
|
2284
|
+
adManager.requestClientSideAds(adsRequest);
|
|
2285
|
+
setupAdEventListeners();
|
|
2286
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
2287
|
+
await loadManifest();
|
|
1022
2288
|
} catch (error) {
|
|
1023
|
-
console.
|
|
2289
|
+
console.error("Error initializing ads:", error);
|
|
1024
2290
|
}
|
|
1025
|
-
};
|
|
2291
|
+
}, [imaConfig, autoPlay, setupAdEventListeners, loadManifest]);
|
|
2292
|
+
useEffect4(() => {
|
|
2293
|
+
const loadRequiredScripts = async () => {
|
|
2294
|
+
try {
|
|
2295
|
+
const scriptLoaders = getRequiredScriptLoaders(!!imaConfig?.adTagUrl, !!system73Config?.apiKey);
|
|
2296
|
+
await loadScripts(scriptLoaders);
|
|
2297
|
+
const globalsToWait = [];
|
|
2298
|
+
if (imaConfig?.adTagUrl) {
|
|
2299
|
+
globalsToWait.push("google");
|
|
2300
|
+
}
|
|
2301
|
+
if (system73Config?.apiKey) {
|
|
2302
|
+
globalsToWait.push("S73ShakaPlayerWrapper");
|
|
2303
|
+
}
|
|
2304
|
+
if (globalsToWait.length > 0) {
|
|
2305
|
+
await waitForGlobals(globalsToWait);
|
|
2306
|
+
}
|
|
2307
|
+
setIsScriptsLoaded(true);
|
|
2308
|
+
} catch (error) {
|
|
2309
|
+
console.error("Error loading required scripts:", error);
|
|
2310
|
+
setIsScriptsLoaded(true);
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
loadRequiredScripts();
|
|
2314
|
+
}, [imaConfig?.adTagUrl, system73Config?.apiKey]);
|
|
2315
|
+
useEffect4(() => {
|
|
2316
|
+
const onPageShow = (e) => {
|
|
2317
|
+
if (e && e.persisted) {
|
|
2318
|
+
setBfResetKey((k) => k + 1);
|
|
2319
|
+
}
|
|
2320
|
+
};
|
|
2321
|
+
window.addEventListener("pageshow", onPageShow);
|
|
2322
|
+
return () => window.removeEventListener("pageshow", onPageShow);
|
|
2323
|
+
}, []);
|
|
1026
2324
|
useEffect4(() => {
|
|
1027
2325
|
const video = videoRef.current;
|
|
1028
|
-
if (!video) return;
|
|
2326
|
+
if (!video || !isScriptsLoaded) return;
|
|
1029
2327
|
const initialize = async () => {
|
|
1030
2328
|
try {
|
|
2329
|
+
console.log("\u{1F680} [Player] Starting initialization...");
|
|
2330
|
+
setIsInitialLoading(true);
|
|
2331
|
+
let system73Wrapper = null;
|
|
2332
|
+
if (system73Config?.apiKey && window.S73ShakaPlayerWrapper) {
|
|
2333
|
+
console.log("\u{1F4E6} [System73] Step 1: Initializing System73 wrapper with config");
|
|
2334
|
+
const playerConfig = { ...shakaConfig };
|
|
2335
|
+
system73Wrapper = initializeSystem73(playerConfig);
|
|
2336
|
+
if (system73Wrapper) {
|
|
2337
|
+
shakaConfig = playerConfig;
|
|
2338
|
+
console.log("\u2705 [System73] Step 1 complete: Wrapper created and config modified");
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
console.log("\u{1F3AC} [Shaka] Step 2: Initializing Shaka Player (auto-load:", !system73Config?.apiKey && !imaConfig?.adTagUrl, ")");
|
|
1031
2342
|
await initializePlayer(video);
|
|
2343
|
+
console.log("\u2705 [Shaka] Step 2 complete: Player initialized");
|
|
2344
|
+
if (system73Wrapper && playerRef.current) {
|
|
2345
|
+
console.log("\u{1F517} [System73] Step 3: Wrapping Shaka player with System73");
|
|
2346
|
+
system73Wrapper.wrapPlayer(playerRef.current);
|
|
2347
|
+
console.log("\u2705 [System73] Step 3 complete: Player wrapped");
|
|
2348
|
+
if (!imaConfig?.adTagUrl) {
|
|
2349
|
+
console.log("\u{1F4FA} [System73] Step 4: Loading manifest");
|
|
2350
|
+
await loadManifest();
|
|
2351
|
+
console.log("\u2705 [System73] Step 4 complete: Manifest loaded");
|
|
2352
|
+
} else {
|
|
2353
|
+
console.log("\u23ED\uFE0F [System73] Skipping manifest load - ads will handle it");
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
console.log("\u{1F4CB} [Player] Setting up event listeners and quality tracking");
|
|
1032
2357
|
setupEventListeners();
|
|
1033
2358
|
const cleanupQuality = setupQualityTracking();
|
|
1034
2359
|
configureQuality();
|
|
2360
|
+
console.log("\u{1F3A8} [UI] Initializing Shaka UI");
|
|
1035
2361
|
await initializeUI();
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
2362
|
+
console.log("\u2705 [UI] UI initialized");
|
|
2363
|
+
if (imaConfig?.adTagUrl && window.google?.ima) {
|
|
2364
|
+
console.log("\u{1F4E2} [Ads] Initializing ads (will load manifest after VAST fetch)");
|
|
2365
|
+
await initializeAds();
|
|
2366
|
+
console.log("\u2705 [Ads] Ads initialized and manifest loaded");
|
|
2367
|
+
}
|
|
2368
|
+
console.log("\u2728 [Player] Initialization complete!");
|
|
1039
2369
|
} catch (error) {
|
|
1040
|
-
console.error("Error during
|
|
2370
|
+
console.error("\u274C [Player] Error during initialization:", error);
|
|
1041
2371
|
handleMuxError(error);
|
|
1042
2372
|
}
|
|
1043
2373
|
};
|
|
1044
2374
|
initialize();
|
|
1045
2375
|
return () => {
|
|
1046
2376
|
cleanupEventListeners();
|
|
2377
|
+
cleanupAdEventListeners();
|
|
1047
2378
|
destroyUI();
|
|
1048
2379
|
destroyMux();
|
|
1049
2380
|
destroyPlayer();
|
|
1050
2381
|
};
|
|
1051
|
-
}, [
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
2382
|
+
}, [managedMode ? hasPlaylist : src, isScriptsLoaded, bfResetKey, managedMode]);
|
|
2383
|
+
useEffect4(() => {
|
|
2384
|
+
const video = videoRef.current;
|
|
2385
|
+
if (!video) return;
|
|
2386
|
+
const onLoadStart = () => {
|
|
2387
|
+
setIsInitialLoading(true);
|
|
2388
|
+
};
|
|
2389
|
+
const onCanPlay = () => {
|
|
2390
|
+
setIsInitialLoading(false);
|
|
2391
|
+
};
|
|
2392
|
+
const onPlaying = () => {
|
|
2393
|
+
setIsInitialLoading(false);
|
|
2394
|
+
};
|
|
2395
|
+
video.addEventListener("loadstart", onLoadStart);
|
|
2396
|
+
video.addEventListener("canplay", onCanPlay);
|
|
2397
|
+
video.addEventListener("playing", onPlaying);
|
|
2398
|
+
return () => {
|
|
2399
|
+
video.removeEventListener("loadstart", onLoadStart);
|
|
2400
|
+
video.removeEventListener("canplay", onCanPlay);
|
|
2401
|
+
video.removeEventListener("playing", onPlaying);
|
|
2402
|
+
};
|
|
2403
|
+
}, []);
|
|
1066
2404
|
useEffect4(() => {
|
|
1067
2405
|
const video = videoRef.current;
|
|
1068
2406
|
if (!video) return;
|
|
1069
2407
|
video.autoplay = autoPlay;
|
|
1070
2408
|
video.loop = loop;
|
|
1071
|
-
video.muted = muted;
|
|
1072
2409
|
video.controls = false;
|
|
1073
2410
|
if (poster) video.poster = poster;
|
|
1074
|
-
}, [autoPlay, loop, muted, poster]);
|
|
2411
|
+
}, [autoPlay, loop, muted, poster, imaConfig?.adTagUrl]);
|
|
2412
|
+
useEffect4(() => {
|
|
2413
|
+
const video = videoRef.current;
|
|
2414
|
+
if (!video) return;
|
|
2415
|
+
video.controls = false;
|
|
2416
|
+
video.setAttribute("controls", "false");
|
|
2417
|
+
video.removeAttribute("controls");
|
|
2418
|
+
const observer = new MutationObserver((mutations) => {
|
|
2419
|
+
mutations.forEach((mutation) => {
|
|
2420
|
+
if (mutation.type === "attributes" && mutation.attributeName === "controls") {
|
|
2421
|
+
if (video.hasAttribute("controls")) {
|
|
2422
|
+
video.removeAttribute("controls");
|
|
2423
|
+
video.controls = false;
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
});
|
|
2427
|
+
});
|
|
2428
|
+
observer.observe(video, {
|
|
2429
|
+
attributes: true,
|
|
2430
|
+
attributeFilter: ["controls"]
|
|
2431
|
+
});
|
|
2432
|
+
return () => {
|
|
2433
|
+
observer.disconnect();
|
|
2434
|
+
};
|
|
2435
|
+
}, []);
|
|
1075
2436
|
useImperativeHandle(ref, () => ({
|
|
1076
2437
|
...videoRef.current,
|
|
1077
2438
|
// Custom methods for quality control
|
|
@@ -1082,27 +2443,30 @@ var Player = forwardRef(
|
|
|
1082
2443
|
skipForward,
|
|
1083
2444
|
// Mux methods
|
|
1084
2445
|
updateMuxData,
|
|
2446
|
+
// Live status methods
|
|
2447
|
+
getLiveStatus,
|
|
2448
|
+
seekToLiveEdge,
|
|
1085
2449
|
// Access to underlying instances
|
|
1086
2450
|
getPlayer: () => playerRef.current,
|
|
1087
2451
|
getMuxMonitor: () => null
|
|
1088
|
-
}), [getAvailableQualities, setQuality, skipBack, skipForward, updateMuxData]);
|
|
2452
|
+
}), [getAvailableQualities, setQuality, skipBack, skipForward, updateMuxData, getLiveStatus, seekToLiveEdge]);
|
|
1089
2453
|
const isResponsive = !width && !height;
|
|
1090
|
-
const containerClasses = twMerge2(containerClassName, "motto-video-container");
|
|
2454
|
+
const containerClasses = twMerge2(containerClassName, "motto-video-container relative bg-[#111111] ");
|
|
1091
2455
|
const containerStyle = isResponsive ? {
|
|
1092
2456
|
aspectRatio: aspectRatio.toString()
|
|
1093
2457
|
} : { width, height };
|
|
1094
|
-
const videoClasses = isResponsive ? "motto-video-responsive" : "w-full h-full ";
|
|
2458
|
+
const videoClasses = isResponsive ? "motto-video-responsive w-full" : "w-full h-full ";
|
|
1095
2459
|
const videoStyle = isResponsive ? {} : { width, height };
|
|
2460
|
+
const filteredVideoProps = { ...videoProps };
|
|
2461
|
+
delete filteredVideoProps.controls;
|
|
1096
2462
|
return /* @__PURE__ */ jsxs4(
|
|
1097
2463
|
"div",
|
|
1098
2464
|
{
|
|
1099
2465
|
ref: containerRef,
|
|
1100
2466
|
className: containerClasses,
|
|
1101
2467
|
style: containerStyle,
|
|
1102
|
-
"data-shaka-player-container": true,
|
|
1103
|
-
"data-shaka-player-cast-receiver-id": chromecastConfig?.receiverApplicationId,
|
|
1104
2468
|
children: [
|
|
1105
|
-
/* @__PURE__ */
|
|
2469
|
+
/* @__PURE__ */ jsx7(
|
|
1106
2470
|
"video",
|
|
1107
2471
|
{
|
|
1108
2472
|
ref: videoRef,
|
|
@@ -1111,17 +2475,11 @@ var Player = forwardRef(
|
|
|
1111
2475
|
height: isResponsive ? void 0 : height,
|
|
1112
2476
|
style: videoStyle,
|
|
1113
2477
|
controls: false,
|
|
1114
|
-
|
|
2478
|
+
playsInline: true,
|
|
2479
|
+
...filteredVideoProps
|
|
1115
2480
|
}
|
|
1116
2481
|
),
|
|
1117
|
-
/* @__PURE__ */
|
|
1118
|
-
imaConfig && /* @__PURE__ */ jsx5(
|
|
1119
|
-
"div",
|
|
1120
|
-
{
|
|
1121
|
-
ref: adContainerRef,
|
|
1122
|
-
className: "absolute top-0 left-0 w-full h-full pointer-events-auto"
|
|
1123
|
-
}
|
|
1124
|
-
)
|
|
2482
|
+
isInitialLoading && /* @__PURE__ */ jsx7("div", { className: "absolute inset-0 flex items-center justify-center z-20 pointer-events-none", children: /* @__PURE__ */ jsx7(Loading, { className: "bg-transparent" }) })
|
|
1125
2483
|
]
|
|
1126
2484
|
}
|
|
1127
2485
|
);
|
|
@@ -1135,11 +2493,11 @@ import { twMerge as twMerge3 } from "tailwind-merge";
|
|
|
1135
2493
|
import { useQuery } from "@tanstack/react-query";
|
|
1136
2494
|
|
|
1137
2495
|
// src/api/video.ts
|
|
1138
|
-
var fetchVideoData = async (videoId, publicKey, mottoToken) => {
|
|
2496
|
+
var fetchVideoData = async (videoId, publicKey, mottoToken, adsEnabled = false, locale = "en") => {
|
|
1139
2497
|
const endpoint = "https://cda.mottostreaming.com/motto.cda.streaming.video.v1.VideoService/GetVideo";
|
|
1140
2498
|
const url = new URL(endpoint);
|
|
1141
2499
|
url.searchParams.set("encoding", "json");
|
|
1142
|
-
url.searchParams.set("message", JSON.stringify({ videoId }));
|
|
2500
|
+
url.searchParams.set("message", JSON.stringify({ videoId, enable_ads: adsEnabled, locale }));
|
|
1143
2501
|
const response = await fetch(url, {
|
|
1144
2502
|
method: "GET",
|
|
1145
2503
|
headers: {
|
|
@@ -1153,14 +2511,14 @@ var fetchVideoData = async (videoId, publicKey, mottoToken) => {
|
|
|
1153
2511
|
const data = await response.json();
|
|
1154
2512
|
return data.video;
|
|
1155
2513
|
};
|
|
1156
|
-
async function fetchVideosList(publicKey, videoIds, mottoToken, skip = 0, limit = 0) {
|
|
2514
|
+
async function fetchVideosList(publicKey, videoIds, mottoToken, skip = 0, limit = 0, adsEnabled = true, locale = "en") {
|
|
1157
2515
|
if (!videoIds || videoIds.length === 0) {
|
|
1158
2516
|
return [];
|
|
1159
2517
|
}
|
|
1160
2518
|
const endpoint = "https://cda.mottostreaming.com/motto.cda.streaming.video.v1.VideoService/BatchGetVideos";
|
|
1161
2519
|
const url = new URL(endpoint);
|
|
1162
2520
|
url.searchParams.set("encoding", "json");
|
|
1163
|
-
url.searchParams.set("message", JSON.stringify({ videoIds }));
|
|
2521
|
+
url.searchParams.set("message", JSON.stringify({ videoIds, enable_ads: adsEnabled, locale }));
|
|
1164
2522
|
const response = await fetch(url.toString(), {
|
|
1165
2523
|
method: "GET",
|
|
1166
2524
|
headers: {
|
|
@@ -1271,7 +2629,7 @@ var getErrorType = (error, video) => {
|
|
|
1271
2629
|
};
|
|
1272
2630
|
|
|
1273
2631
|
// src/messages/useMessages.tsx
|
|
1274
|
-
import { useState as
|
|
2632
|
+
import { useState as useState4, useEffect as useEffect5 } from "react";
|
|
1275
2633
|
|
|
1276
2634
|
// src/messages/en.json
|
|
1277
2635
|
var en_default = {
|
|
@@ -1573,8 +2931,8 @@ var getBrowserLanguage = () => {
|
|
|
1573
2931
|
return availableLanguages[language] ? language : "en";
|
|
1574
2932
|
};
|
|
1575
2933
|
var useMessages = (locale) => {
|
|
1576
|
-
const [language, setLanguage] =
|
|
1577
|
-
const [translations, setTranslations] =
|
|
2934
|
+
const [language, setLanguage] = useState4("en");
|
|
2935
|
+
const [translations, setTranslations] = useState4(availableLanguages.en);
|
|
1578
2936
|
useEffect5(() => {
|
|
1579
2937
|
const lang = !!availableLanguages?.[locale] ? locale : getBrowserLanguage();
|
|
1580
2938
|
;
|
|
@@ -1601,11 +2959,10 @@ var useMessages = (locale) => {
|
|
|
1601
2959
|
var useMessages_default = useMessages;
|
|
1602
2960
|
|
|
1603
2961
|
// src/Video.tsx
|
|
1604
|
-
import { jsx as
|
|
2962
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1605
2963
|
var Video = ({
|
|
1606
2964
|
videoId,
|
|
1607
2965
|
publicKey,
|
|
1608
|
-
mottoToken,
|
|
1609
2966
|
videoData: providedVideoData,
|
|
1610
2967
|
refetchInterval = 0,
|
|
1611
2968
|
playerName,
|
|
@@ -1613,7 +2970,10 @@ var Video = ({
|
|
|
1613
2970
|
events,
|
|
1614
2971
|
children,
|
|
1615
2972
|
className,
|
|
2973
|
+
auth,
|
|
2974
|
+
settings,
|
|
1616
2975
|
queryOptions = {},
|
|
2976
|
+
adsEnabled = false,
|
|
1617
2977
|
...props
|
|
1618
2978
|
}) => {
|
|
1619
2979
|
const {
|
|
@@ -1622,8 +2982,8 @@ var Video = ({
|
|
|
1622
2982
|
error,
|
|
1623
2983
|
refetch
|
|
1624
2984
|
} = useQuery({
|
|
1625
|
-
queryKey: ["video", videoId, publicKey, mottoToken],
|
|
1626
|
-
queryFn: () => fetchVideoData(videoId, publicKey, mottoToken),
|
|
2985
|
+
queryKey: ["video", videoId, publicKey, auth?.mottoToken, adsEnabled, locale],
|
|
2986
|
+
queryFn: () => fetchVideoData(videoId, publicKey, auth?.mottoToken, adsEnabled, locale),
|
|
1627
2987
|
enabled: !!videoId && !!publicKey && !providedVideoData,
|
|
1628
2988
|
refetchInterval: refetchInterval > 0 ? refetchInterval : false,
|
|
1629
2989
|
staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
|
|
@@ -1636,16 +2996,17 @@ var Video = ({
|
|
|
1636
2996
|
const video = providedVideoData || data;
|
|
1637
2997
|
const { t } = useMessages_default(locale);
|
|
1638
2998
|
const activePlaylist = findHLSPlaylist(video);
|
|
1639
|
-
const
|
|
2999
|
+
const activePlaylistUrl = activePlaylist?.url ?? activePlaylist?.drm?.widevine?.playlistUrl ?? activePlaylist?.drm?.playready?.playlistUrl ?? activePlaylist?.drm?.fairplay?.playlistUrl;
|
|
3000
|
+
const activePlaylistHasUrl = !!activePlaylistUrl;
|
|
1640
3001
|
useEffect6(() => {
|
|
1641
3002
|
if (events?.onVideoData && video) {
|
|
1642
3003
|
events.onVideoData(video);
|
|
1643
3004
|
}
|
|
1644
3005
|
}, [video, events]);
|
|
1645
3006
|
if (isLoading || !providedVideoData && !video) {
|
|
1646
|
-
return /* @__PURE__ */
|
|
3007
|
+
return /* @__PURE__ */ jsx8("div", { className: twMerge3("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ jsx8("div", { className: "relative w-full h-full bg-[#151515]", children: /* @__PURE__ */ jsx8(Loading, {}) }) });
|
|
1647
3008
|
}
|
|
1648
|
-
if (!isLoading && video && !
|
|
3009
|
+
if (!isLoading && video && !activePlaylistHasUrl && events?.onEmptyPlaylists) {
|
|
1649
3010
|
events.onEmptyPlaylists();
|
|
1650
3011
|
}
|
|
1651
3012
|
if (error || video?.error) {
|
|
@@ -1656,8 +3017,8 @@ var Video = ({
|
|
|
1656
3017
|
}
|
|
1657
3018
|
const title = t(errorKey) || t("DEFAULT_ERROR");
|
|
1658
3019
|
const description = t(`${errorKey}_DESCRIPTION`) || t("DEFAULT_ERROR_DESCRIPTION");
|
|
1659
|
-
return /* @__PURE__ */
|
|
1660
|
-
/* @__PURE__ */
|
|
3020
|
+
return /* @__PURE__ */ jsx8("div", { className: twMerge3("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ jsxs5("div", { className: "relative w-full h-full", children: [
|
|
3021
|
+
/* @__PURE__ */ jsx8(
|
|
1661
3022
|
ErrorScreen,
|
|
1662
3023
|
{
|
|
1663
3024
|
title,
|
|
@@ -1667,31 +3028,35 @@ var Video = ({
|
|
|
1667
3028
|
children
|
|
1668
3029
|
] }) });
|
|
1669
3030
|
}
|
|
1670
|
-
if (!
|
|
1671
|
-
return /* @__PURE__ */
|
|
1672
|
-
/* @__PURE__ */
|
|
3031
|
+
if (!activePlaylist || !activePlaylistHasUrl) {
|
|
3032
|
+
return /* @__PURE__ */ jsx8("div", { className: twMerge3("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ jsxs5("div", { className: "relative w-full h-full bg-[#151515]", children: [
|
|
3033
|
+
/* @__PURE__ */ jsx8(Title, { title: video?.name || "" }),
|
|
1673
3034
|
children
|
|
1674
3035
|
] }) });
|
|
1675
3036
|
}
|
|
1676
|
-
|
|
1677
|
-
return /* @__PURE__ */ jsx6("div", { className: twMerge3("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ jsx6("div", { className: "relative w-full h-full", children: /* @__PURE__ */ jsx6(
|
|
3037
|
+
return /* @__PURE__ */ jsx8("div", { className: twMerge3("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ jsx8("div", { className: "relative w-full h-full", children: /* @__PURE__ */ jsx8(
|
|
1678
3038
|
Player,
|
|
1679
3039
|
{
|
|
1680
3040
|
...props,
|
|
1681
|
-
src:
|
|
3041
|
+
src: activePlaylist,
|
|
3042
|
+
managedMode: true,
|
|
1682
3043
|
className: twMerge3("video-player-container", className),
|
|
1683
3044
|
events,
|
|
3045
|
+
locale,
|
|
1684
3046
|
containerClassName: "w-full h-full",
|
|
3047
|
+
publicKey,
|
|
3048
|
+
auth,
|
|
3049
|
+
...adsEnabled && video?.ad?.adTagUrl ? { imaConfig: { adTagUrl: video?.ad?.adTagUrl } } : {},
|
|
1685
3050
|
children
|
|
1686
3051
|
}
|
|
1687
3052
|
) }) });
|
|
1688
3053
|
};
|
|
1689
3054
|
|
|
1690
3055
|
// src/Event.tsx
|
|
1691
|
-
import { useCallback as
|
|
3056
|
+
import { useCallback as useCallback10, useEffect as useEffect7, useState as useState5 } from "react";
|
|
1692
3057
|
import { twMerge as twMerge4 } from "tailwind-merge";
|
|
1693
3058
|
import { useQuery as useQuery2 } from "@tanstack/react-query";
|
|
1694
|
-
import { Fragment, jsx as
|
|
3059
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1695
3060
|
var Event = ({
|
|
1696
3061
|
publicKey,
|
|
1697
3062
|
eventId,
|
|
@@ -1704,6 +3069,7 @@ var Event = ({
|
|
|
1704
3069
|
settings,
|
|
1705
3070
|
auth,
|
|
1706
3071
|
queryOptions = {},
|
|
3072
|
+
adsEnabled = false,
|
|
1707
3073
|
...props
|
|
1708
3074
|
}) => {
|
|
1709
3075
|
const {
|
|
@@ -1721,16 +3087,16 @@ var Event = ({
|
|
|
1721
3087
|
retry: queryOptions.retry ?? 3,
|
|
1722
3088
|
retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
|
|
1723
3089
|
});
|
|
1724
|
-
const [activePlaylist, setActivePlaylist] =
|
|
1725
|
-
const [activeVideoId, setActiveVideoId] =
|
|
3090
|
+
const [activePlaylist, setActivePlaylist] = useState5();
|
|
3091
|
+
const [activeVideoId, setActiveVideoId] = useState5();
|
|
1726
3092
|
const videoIds = eventData?.videoIds ?? [];
|
|
1727
3093
|
const {
|
|
1728
3094
|
data: videosData,
|
|
1729
3095
|
isLoading: videosIsLoading,
|
|
1730
3096
|
error: videosError
|
|
1731
3097
|
} = useQuery2({
|
|
1732
|
-
queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken],
|
|
1733
|
-
queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0),
|
|
3098
|
+
queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken, adsEnabled, locale],
|
|
3099
|
+
queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0, adsEnabled, locale),
|
|
1734
3100
|
enabled: !!publicKey && videoIds.length > 0,
|
|
1735
3101
|
refetchInterval: activePlaylist === null ? 3e4 : false,
|
|
1736
3102
|
staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
|
|
@@ -1738,7 +3104,7 @@ var Event = ({
|
|
|
1738
3104
|
retry: queryOptions.retry ?? 3,
|
|
1739
3105
|
retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
|
|
1740
3106
|
});
|
|
1741
|
-
const [loadingApisState, setLoadingApisState] =
|
|
3107
|
+
const [loadingApisState, setLoadingApisState] = useState5(true);
|
|
1742
3108
|
useEffect7(() => {
|
|
1743
3109
|
if (videosData !== void 0) {
|
|
1744
3110
|
setLoadingApisState(false);
|
|
@@ -1748,9 +3114,11 @@ var Event = ({
|
|
|
1748
3114
|
if (videosWithPlaylists.length > 0) {
|
|
1749
3115
|
let hlsPlaylistFound = false;
|
|
1750
3116
|
for (const video of videosWithPlaylists) {
|
|
1751
|
-
const
|
|
1752
|
-
|
|
1753
|
-
|
|
3117
|
+
const activePlaylist2 = findHLSPlaylist(video);
|
|
3118
|
+
const activePlaylistUrl = activePlaylist2?.url ?? activePlaylist2?.drm?.widevine?.playlistUrl ?? activePlaylist2?.drm?.playready?.playlistUrl ?? activePlaylist2?.drm?.fairplay?.playlistUrl;
|
|
3119
|
+
const activePlaylistHasUrl = !!activePlaylistUrl;
|
|
3120
|
+
if (activePlaylist2 && activePlaylistHasUrl) {
|
|
3121
|
+
setActivePlaylist(activePlaylist2);
|
|
1754
3122
|
setActiveVideoId(video.id);
|
|
1755
3123
|
hlsPlaylistFound = true;
|
|
1756
3124
|
break;
|
|
@@ -1784,12 +3152,17 @@ var Event = ({
|
|
|
1784
3152
|
}
|
|
1785
3153
|
}
|
|
1786
3154
|
}, [activeVideoId, videosData, events]);
|
|
1787
|
-
const [error, setError] =
|
|
1788
|
-
const [loadingPlaylist, setLoadingPlaylist] =
|
|
3155
|
+
const [error, setError] = useState5(null);
|
|
3156
|
+
const [loadingPlaylist, setLoadingPlaylist] = useState5(true);
|
|
1789
3157
|
const videosDataError = videosData?.some((video) => !!video.error);
|
|
1790
3158
|
useEffect7(() => {
|
|
1791
|
-
if (
|
|
1792
|
-
|
|
3159
|
+
if (isEventLoading || videosIsLoading || loadingApisState) {
|
|
3160
|
+
return;
|
|
3161
|
+
}
|
|
3162
|
+
const hasPlayablePlaylist = Boolean(activePlaylist);
|
|
3163
|
+
if (eventError || videosError || videosDataError && !hasPlayablePlaylist) {
|
|
3164
|
+
const firstVideoError = videosData?.find((video) => !!video.error)?.error;
|
|
3165
|
+
const errorObj = eventError || videosError || firstVideoError && new Error(firstVideoError) || new Error("default");
|
|
1793
3166
|
setError(errorObj);
|
|
1794
3167
|
if (events?.onError) {
|
|
1795
3168
|
events.onError(errorObj);
|
|
@@ -1797,7 +3170,17 @@ var Event = ({
|
|
|
1797
3170
|
} else {
|
|
1798
3171
|
setError(null);
|
|
1799
3172
|
}
|
|
1800
|
-
}, [
|
|
3173
|
+
}, [
|
|
3174
|
+
eventError,
|
|
3175
|
+
videosError,
|
|
3176
|
+
videosDataError,
|
|
3177
|
+
videosData,
|
|
3178
|
+
events,
|
|
3179
|
+
activePlaylist,
|
|
3180
|
+
isEventLoading,
|
|
3181
|
+
videosIsLoading,
|
|
3182
|
+
loadingApisState
|
|
3183
|
+
]);
|
|
1801
3184
|
useEffect7(() => {
|
|
1802
3185
|
const eventLoadedWithNoVideos = !isEventLoading && eventData && eventData.videoIds && (!eventData.videoIds || eventData?.videoIds?.length === 0) && !loadingApisState;
|
|
1803
3186
|
const allApisLoadedWithPotentialVideos = !isEventLoading && !videosIsLoading && eventData && !loadingApisState;
|
|
@@ -1808,7 +3191,7 @@ var Event = ({
|
|
|
1808
3191
|
if (error) {
|
|
1809
3192
|
const title = t(error.message)?.length ? t(error.message) : t("DEFAULT_ERROR");
|
|
1810
3193
|
const description = t(`${error.message}_DESCRIPTION`)?.length ? t(`${error.message}_DESCRIPTION`) : t("DEFAULT_ERROR_DESCRIPTION");
|
|
1811
|
-
return /* @__PURE__ */
|
|
3194
|
+
return /* @__PURE__ */ jsx9("div", { className: twMerge4("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ jsx9("div", { className: "relative w-full h-full", children: /* @__PURE__ */ jsx9(
|
|
1812
3195
|
ErrorScreen,
|
|
1813
3196
|
{
|
|
1814
3197
|
title,
|
|
@@ -1820,22 +3203,28 @@ var Event = ({
|
|
|
1820
3203
|
events.onEmptyPlaylists();
|
|
1821
3204
|
}
|
|
1822
3205
|
if (loadingPlaylist) {
|
|
1823
|
-
return /* @__PURE__ */
|
|
3206
|
+
return /* @__PURE__ */ jsx9("div", { className: twMerge4("", className), children: /* @__PURE__ */ jsx9("div", { className: "relative w-full aspect-video bg-[#151515]", children: /* @__PURE__ */ jsx9(Loading, {}) }) });
|
|
1824
3207
|
}
|
|
1825
3208
|
if (activePlaylist && activeVideoId && videosData) {
|
|
1826
3209
|
const activeVideo = videosData.find((video) => video.id === activeVideoId);
|
|
1827
|
-
|
|
1828
|
-
|
|
3210
|
+
console.log("activeVideo?.ad?.adTagUrl", activeVideo?.ad?.adTagUrl);
|
|
3211
|
+
return /* @__PURE__ */ jsxs6("div", { className: twMerge4("", className), children: [
|
|
3212
|
+
/* @__PURE__ */ jsx9("div", { className: "relative w-full h-full", children: /* @__PURE__ */ jsx9(
|
|
1829
3213
|
Player,
|
|
1830
3214
|
{
|
|
1831
3215
|
...props,
|
|
1832
3216
|
src: activePlaylist,
|
|
1833
|
-
|
|
3217
|
+
managedMode: true,
|
|
3218
|
+
className: twMerge4(className, "peer aspect-video"),
|
|
1834
3219
|
events,
|
|
1835
|
-
|
|
3220
|
+
locale,
|
|
3221
|
+
containerClassName: "w-full h-full",
|
|
3222
|
+
publicKey,
|
|
3223
|
+
auth,
|
|
3224
|
+
...adsEnabled && activeVideo ? { imaConfig: { adTagUrl: activeVideo?.ad?.adTagUrl } } : {}
|
|
1836
3225
|
}
|
|
1837
|
-
),
|
|
1838
|
-
!hideTitle && eventData && /* @__PURE__ */
|
|
3226
|
+
) }),
|
|
3227
|
+
!hideTitle && eventData && /* @__PURE__ */ jsx9(
|
|
1839
3228
|
TitleAndDescription,
|
|
1840
3229
|
{
|
|
1841
3230
|
title: eventData.title,
|
|
@@ -1844,10 +3233,10 @@ var Event = ({
|
|
|
1844
3233
|
locale
|
|
1845
3234
|
}
|
|
1846
3235
|
)
|
|
1847
|
-
] })
|
|
3236
|
+
] });
|
|
1848
3237
|
}
|
|
1849
3238
|
if (eventData) {
|
|
1850
|
-
return /* @__PURE__ */
|
|
3239
|
+
return /* @__PURE__ */ jsx9("div", { className: twMerge4("", className), children: /* @__PURE__ */ jsx9("div", { className: "relative w-full h-full", children: /* @__PURE__ */ jsx9(
|
|
1851
3240
|
PreEvent,
|
|
1852
3241
|
{
|
|
1853
3242
|
event: eventData,
|
|
@@ -1869,7 +3258,7 @@ function PreEvent({
|
|
|
1869
3258
|
}) {
|
|
1870
3259
|
const date = new Date(event.startTime);
|
|
1871
3260
|
const now = /* @__PURE__ */ new Date();
|
|
1872
|
-
const [remainingTime, setRemainingTime] =
|
|
3261
|
+
const [remainingTime, setRemainingTime] = useState5(
|
|
1873
3262
|
date.getTime() - now.getTime()
|
|
1874
3263
|
);
|
|
1875
3264
|
const shouldBeStarted = remainingTime < 0;
|
|
@@ -1884,29 +3273,28 @@ function PreEvent({
|
|
|
1884
3273
|
}, 1e3);
|
|
1885
3274
|
return () => clearInterval(interval);
|
|
1886
3275
|
}, [date, remainingTime]);
|
|
1887
|
-
const renderCountdown =
|
|
3276
|
+
const renderCountdown = useCallback10(() => {
|
|
1888
3277
|
if (shouldBeStarted) {
|
|
1889
|
-
return /* @__PURE__ */
|
|
3278
|
+
return /* @__PURE__ */ jsx9("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
|
|
1890
3279
|
}
|
|
1891
3280
|
const seconds = Math.floor(remainingTime / 1e3) % 60;
|
|
1892
3281
|
const minutes = Math.floor(remainingTime / 1e3 / 60) % 60;
|
|
1893
3282
|
const hours = Math.floor(remainingTime / 1e3 / 60 / 60) % 24;
|
|
1894
3283
|
const days = Math.floor(remainingTime / 1e3 / 60 / 60 / 24);
|
|
1895
|
-
return /* @__PURE__ */ jsxs6("div", { className: "grid grid-flow-col gap-5 text-center auto-cols-max", children: [
|
|
3284
|
+
return /* @__PURE__ */ jsxs6("div", { className: "grid grid-flow-col gap-1 md:gap-5 text-center auto-cols-max", children: [
|
|
1896
3285
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
1897
|
-
/* @__PURE__ */
|
|
3286
|
+
/* @__PURE__ */ jsx9("span", { className: "font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx9(
|
|
1898
3287
|
"span",
|
|
1899
3288
|
{
|
|
1900
|
-
style: { "--value": days },
|
|
1901
3289
|
"aria-live": "polite",
|
|
1902
3290
|
"aria-label": days.toString(),
|
|
1903
|
-
children: days
|
|
3291
|
+
children: days.toString()
|
|
1904
3292
|
}
|
|
1905
3293
|
) }),
|
|
1906
|
-
/* @__PURE__ */
|
|
3294
|
+
/* @__PURE__ */ jsx9("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("DAYS") })
|
|
1907
3295
|
] }),
|
|
1908
3296
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
1909
|
-
/* @__PURE__ */
|
|
3297
|
+
/* @__PURE__ */ jsx9("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx9(
|
|
1910
3298
|
"span",
|
|
1911
3299
|
{
|
|
1912
3300
|
style: { "--value": hours },
|
|
@@ -1915,10 +3303,10 @@ function PreEvent({
|
|
|
1915
3303
|
children: hours?.toString()?.padStart(2, "0")
|
|
1916
3304
|
}
|
|
1917
3305
|
) }),
|
|
1918
|
-
/* @__PURE__ */
|
|
3306
|
+
/* @__PURE__ */ jsx9("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("HOURS") })
|
|
1919
3307
|
] }),
|
|
1920
3308
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
1921
|
-
/* @__PURE__ */
|
|
3309
|
+
/* @__PURE__ */ jsx9("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx9(
|
|
1922
3310
|
"span",
|
|
1923
3311
|
{
|
|
1924
3312
|
style: { "--value": minutes },
|
|
@@ -1927,10 +3315,10 @@ function PreEvent({
|
|
|
1927
3315
|
children: minutes?.toString()?.padStart(2, "0")
|
|
1928
3316
|
}
|
|
1929
3317
|
) }),
|
|
1930
|
-
/* @__PURE__ */
|
|
3318
|
+
/* @__PURE__ */ jsx9("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("MINUTES") })
|
|
1931
3319
|
] }),
|
|
1932
3320
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
1933
|
-
/* @__PURE__ */
|
|
3321
|
+
/* @__PURE__ */ jsx9("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx9(
|
|
1934
3322
|
"span",
|
|
1935
3323
|
{
|
|
1936
3324
|
style: { "--value": seconds },
|
|
@@ -1939,12 +3327,12 @@ function PreEvent({
|
|
|
1939
3327
|
children: seconds?.toString()?.padStart(2, "0")
|
|
1940
3328
|
}
|
|
1941
3329
|
) }),
|
|
1942
|
-
/* @__PURE__ */
|
|
3330
|
+
/* @__PURE__ */ jsx9("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("SECONDS") })
|
|
1943
3331
|
] })
|
|
1944
3332
|
] });
|
|
1945
3333
|
}, [remainingTime, shouldBeStarted, t]);
|
|
1946
|
-
return /* @__PURE__ */
|
|
1947
|
-
/* @__PURE__ */
|
|
3334
|
+
return /* @__PURE__ */ jsx9(Fragment, { children: event?.posterUrl ? /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
3335
|
+
/* @__PURE__ */ jsx9(
|
|
1948
3336
|
"div",
|
|
1949
3337
|
{
|
|
1950
3338
|
className: "relative overflow-hidden bg-base-200 aspect-video text-base-content w-full h-full flex justify-center items-center flex-col bg-no-repeat bg-cover md:rounded-2xl",
|
|
@@ -1953,10 +3341,10 @@ function PreEvent({
|
|
|
1953
3341
|
backgroundRepeat: "no-repeat",
|
|
1954
3342
|
backgroundSize: "cover"
|
|
1955
3343
|
},
|
|
1956
|
-
children: /* @__PURE__ */
|
|
3344
|
+
children: /* @__PURE__ */ jsx9("div", { className: "relative z-10", children: renderCountdown() })
|
|
1957
3345
|
}
|
|
1958
3346
|
),
|
|
1959
|
-
!hideTitle && /* @__PURE__ */
|
|
3347
|
+
!hideTitle && /* @__PURE__ */ jsx9(
|
|
1960
3348
|
TitleAndDescription,
|
|
1961
3349
|
{
|
|
1962
3350
|
title: event.title,
|
|
@@ -1966,17 +3354,17 @@ function PreEvent({
|
|
|
1966
3354
|
}
|
|
1967
3355
|
)
|
|
1968
3356
|
] }) : /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
1969
|
-
/* @__PURE__ */
|
|
3357
|
+
/* @__PURE__ */ jsx9(
|
|
1970
3358
|
"div",
|
|
1971
3359
|
{
|
|
1972
3360
|
className: "relative overflow-hidden md:rounded-2xl bg-base-200 aspect-video text-base-content flex flex-col justify-center items-center w-full h-full bg-cover bg-center bg-no-repeat",
|
|
1973
3361
|
style: {
|
|
1974
3362
|
backgroundImage: backgroundImageUrl ? `url(${backgroundImageUrl})` : ""
|
|
1975
3363
|
},
|
|
1976
|
-
children: /* @__PURE__ */
|
|
3364
|
+
children: /* @__PURE__ */ jsx9("div", { className: "relative z-10", children: renderCountdown() })
|
|
1977
3365
|
}
|
|
1978
3366
|
),
|
|
1979
|
-
!hideTitle && /* @__PURE__ */
|
|
3367
|
+
!hideTitle && /* @__PURE__ */ jsx9(
|
|
1980
3368
|
TitleAndDescription,
|
|
1981
3369
|
{
|
|
1982
3370
|
title: event.title,
|
|
@@ -1995,8 +3383,8 @@ var TitleAndDescription = ({
|
|
|
1995
3383
|
className
|
|
1996
3384
|
}) => {
|
|
1997
3385
|
return /* @__PURE__ */ jsxs6("div", { className: twMerge4("mt-3 mb-6 m-event-details-ctn px-4 text-left w-full", className), children: [
|
|
1998
|
-
/* @__PURE__ */
|
|
1999
|
-
startTime ? /* @__PURE__ */ jsxs6("div", { className: "text-
|
|
3386
|
+
/* @__PURE__ */ jsx9("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
|
|
3387
|
+
startTime ? /* @__PURE__ */ jsxs6("div", { className: "text-xs md:text-base text-base-content/70 m-event-start-time", children: [
|
|
2000
3388
|
new Date(startTime || "").toLocaleDateString(locale || "default", {
|
|
2001
3389
|
month: "long",
|
|
2002
3390
|
year: "numeric",
|
|
@@ -2009,15 +3397,15 @@ var TitleAndDescription = ({
|
|
|
2009
3397
|
minute: "2-digit"
|
|
2010
3398
|
})
|
|
2011
3399
|
] }) : null,
|
|
2012
|
-
description && /* @__PURE__ */
|
|
3400
|
+
description && /* @__PURE__ */ jsx9("div", { className: "text-xs md:text-xs text-base-content/60 uppercase", children: description })
|
|
2013
3401
|
] });
|
|
2014
3402
|
};
|
|
2015
3403
|
|
|
2016
3404
|
// src/CreativeWork.tsx
|
|
2017
|
-
import { useEffect as useEffect8, useState as
|
|
3405
|
+
import { useEffect as useEffect8, useState as useState6 } from "react";
|
|
2018
3406
|
import { twMerge as twMerge5 } from "tailwind-merge";
|
|
2019
3407
|
import { useQuery as useQuery3 } from "@tanstack/react-query";
|
|
2020
|
-
import { Fragment as Fragment2, jsx as
|
|
3408
|
+
import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2021
3409
|
var CreativeWork = ({
|
|
2022
3410
|
publicKey,
|
|
2023
3411
|
creativeWorkId,
|
|
@@ -2030,6 +3418,7 @@ var CreativeWork = ({
|
|
|
2030
3418
|
settings,
|
|
2031
3419
|
auth,
|
|
2032
3420
|
queryOptions = {},
|
|
3421
|
+
adsEnabled = false,
|
|
2033
3422
|
...props
|
|
2034
3423
|
}) => {
|
|
2035
3424
|
const {
|
|
@@ -2047,17 +3436,17 @@ var CreativeWork = ({
|
|
|
2047
3436
|
retry: queryOptions.retry ?? 3,
|
|
2048
3437
|
retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
|
|
2049
3438
|
});
|
|
2050
|
-
const [activePlaylist, setActivePlaylist] =
|
|
2051
|
-
const [activeVideoId, setActiveVideoId] =
|
|
2052
|
-
const [showCountDown, setShowCountDown] =
|
|
3439
|
+
const [activePlaylist, setActivePlaylist] = useState6();
|
|
3440
|
+
const [activeVideoId, setActiveVideoId] = useState6();
|
|
3441
|
+
const [showCountDown, setShowCountDown] = useState6(false);
|
|
2053
3442
|
const videoIds = creativeWorkData?.videoIds ?? [];
|
|
2054
3443
|
const {
|
|
2055
3444
|
data: videosData,
|
|
2056
3445
|
isLoading: videosIsLoading,
|
|
2057
3446
|
error: videosError
|
|
2058
3447
|
} = useQuery3({
|
|
2059
|
-
queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken],
|
|
2060
|
-
queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0),
|
|
3448
|
+
queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken, adsEnabled, locale],
|
|
3449
|
+
queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0, adsEnabled, locale),
|
|
2061
3450
|
enabled: !!publicKey && videoIds.length > 0,
|
|
2062
3451
|
refetchInterval: activePlaylist === null ? 3e4 : false,
|
|
2063
3452
|
staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
|
|
@@ -2065,7 +3454,7 @@ var CreativeWork = ({
|
|
|
2065
3454
|
retry: queryOptions.retry ?? 3,
|
|
2066
3455
|
retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
|
|
2067
3456
|
});
|
|
2068
|
-
const [loadingApisState, setLoadingApisState] =
|
|
3457
|
+
const [loadingApisState, setLoadingApisState] = useState6(true);
|
|
2069
3458
|
useEffect8(() => {
|
|
2070
3459
|
if (videosData !== void 0) {
|
|
2071
3460
|
setLoadingApisState(false);
|
|
@@ -2075,9 +3464,11 @@ var CreativeWork = ({
|
|
|
2075
3464
|
if (videosWithPlaylists.length > 0) {
|
|
2076
3465
|
let hlsPlaylistFound = false;
|
|
2077
3466
|
for (const video of videosWithPlaylists) {
|
|
2078
|
-
const
|
|
2079
|
-
|
|
2080
|
-
|
|
3467
|
+
const activePlaylist2 = findHLSPlaylist(video);
|
|
3468
|
+
const activePlaylistUrl = activePlaylist2?.url ?? activePlaylist2?.drm?.widevine?.playlistUrl ?? activePlaylist2?.drm?.playready?.playlistUrl ?? activePlaylist2?.drm?.fairplay?.playlistUrl;
|
|
3469
|
+
const activePlaylistHasUrl = !!activePlaylistUrl;
|
|
3470
|
+
if (activePlaylist2 && activePlaylistHasUrl) {
|
|
3471
|
+
setActivePlaylist(activePlaylist2);
|
|
2081
3472
|
setActiveVideoId(video.id);
|
|
2082
3473
|
hlsPlaylistFound = true;
|
|
2083
3474
|
break;
|
|
@@ -2114,7 +3505,7 @@ var CreativeWork = ({
|
|
|
2114
3505
|
}
|
|
2115
3506
|
}
|
|
2116
3507
|
}, [activeVideoId, videosData, events]);
|
|
2117
|
-
const [error, setError] =
|
|
3508
|
+
const [error, setError] = useState6(null);
|
|
2118
3509
|
const videosDataError = videosData?.some((video) => !!video.error);
|
|
2119
3510
|
useEffect8(() => {
|
|
2120
3511
|
if (creativeWorkError || videosError || videosDataError) {
|
|
@@ -2130,7 +3521,7 @@ var CreativeWork = ({
|
|
|
2130
3521
|
if (error) {
|
|
2131
3522
|
const title = t(error.message)?.length ? t(error.message) : t("DEFAULT_ERROR");
|
|
2132
3523
|
const description = t(`${error.message}_DESCRIPTION`)?.length ? t(`${error.message}_DESCRIPTION`) : t("DEFAULT_ERROR_DESCRIPTION");
|
|
2133
|
-
return /* @__PURE__ */
|
|
3524
|
+
return /* @__PURE__ */ jsx10("div", { className: twMerge5("", className), children: /* @__PURE__ */ jsx10("div", { className: "relative w-full h-full", children: /* @__PURE__ */ jsx10(
|
|
2134
3525
|
ErrorScreen,
|
|
2135
3526
|
{
|
|
2136
3527
|
title,
|
|
@@ -2138,7 +3529,7 @@ var CreativeWork = ({
|
|
|
2138
3529
|
}
|
|
2139
3530
|
) }) });
|
|
2140
3531
|
}
|
|
2141
|
-
const [loadingPlaylist, setLoadingPlaylist] =
|
|
3532
|
+
const [loadingPlaylist, setLoadingPlaylist] = useState6(true);
|
|
2142
3533
|
useEffect8(() => {
|
|
2143
3534
|
const creativeWorkLoadedWithNoVideos = !isCreativeWorkLoading && creativeWorkData && creativeWorkData.videoIds && creativeWorkData.videoIds.length === 0;
|
|
2144
3535
|
const creativeWorkLoadedWithNoData = !isCreativeWorkLoading && creativeWorkData && !creativeWorkData.videoIds;
|
|
@@ -2160,10 +3551,10 @@ var CreativeWork = ({
|
|
|
2160
3551
|
events
|
|
2161
3552
|
]);
|
|
2162
3553
|
if (isCreativeWorkLoading || videosIsLoading || loadingApisState) {
|
|
2163
|
-
return /* @__PURE__ */
|
|
3554
|
+
return /* @__PURE__ */ jsx10("div", { className: twMerge5("", className), children: /* @__PURE__ */ jsx10("div", { className: "relative w-full aspect-video bg-[#151515]", children: /* @__PURE__ */ jsx10(Loading, {}) }) });
|
|
2164
3555
|
}
|
|
2165
3556
|
if (showCountDown && creativeWorkData) {
|
|
2166
|
-
return /* @__PURE__ */
|
|
3557
|
+
return /* @__PURE__ */ jsx10("div", { className: twMerge5("", className), children: /* @__PURE__ */ jsx10("div", { className: "relative w-full h-full bg-base-200 text-base-content flex justify-center items-center flex-col", children: /* @__PURE__ */ jsx10(
|
|
2167
3558
|
PreCreativeWork,
|
|
2168
3559
|
{
|
|
2169
3560
|
creativeWork: creativeWorkData,
|
|
@@ -2176,20 +3567,25 @@ var CreativeWork = ({
|
|
|
2176
3567
|
}
|
|
2177
3568
|
if (activeVideoId && activePlaylist && !loadingPlaylist) {
|
|
2178
3569
|
const activeVideo = videosData?.find((video) => video.id === activeVideoId);
|
|
2179
|
-
return /* @__PURE__ */
|
|
2180
|
-
/* @__PURE__ */
|
|
3570
|
+
return /* @__PURE__ */ jsx10("div", { className: twMerge5("", className), children: /* @__PURE__ */ jsxs7("div", { className: "relative w-full h-full", children: [
|
|
3571
|
+
/* @__PURE__ */ jsx10(
|
|
2181
3572
|
Player,
|
|
2182
3573
|
{
|
|
2183
3574
|
...props,
|
|
2184
|
-
className: twMerge5(className, "peer"),
|
|
3575
|
+
className: twMerge5(className, "peer aspect-video"),
|
|
3576
|
+
managedMode: true,
|
|
2185
3577
|
events: {
|
|
2186
3578
|
...events
|
|
2187
3579
|
},
|
|
2188
3580
|
src: activePlaylist,
|
|
2189
|
-
|
|
3581
|
+
locale,
|
|
3582
|
+
containerClassName: "w-full h-full",
|
|
3583
|
+
publicKey,
|
|
3584
|
+
auth,
|
|
3585
|
+
...adsEnabled && activeVideo?.ad?.adTagUrl ? { imaConfig: { adTagUrl: activeVideo?.ad?.adTagUrl } } : {}
|
|
2190
3586
|
}
|
|
2191
3587
|
),
|
|
2192
|
-
!hideTitle && /* @__PURE__ */
|
|
3588
|
+
!hideTitle && /* @__PURE__ */ jsx10(
|
|
2193
3589
|
TitleAndDescription2,
|
|
2194
3590
|
{
|
|
2195
3591
|
title: creativeWorkData?.title || "",
|
|
@@ -2202,7 +3598,7 @@ var CreativeWork = ({
|
|
|
2202
3598
|
] }) });
|
|
2203
3599
|
}
|
|
2204
3600
|
if (loadingPlaylist) {
|
|
2205
|
-
return /* @__PURE__ */
|
|
3601
|
+
return /* @__PURE__ */ jsx10("div", { className: twMerge5("", className), children: /* @__PURE__ */ jsx10("div", { className: "relative w-full aspect-video bg-[#151515]", children: /* @__PURE__ */ jsx10(Loading, {}) }) });
|
|
2206
3602
|
}
|
|
2207
3603
|
return null;
|
|
2208
3604
|
};
|
|
@@ -2215,7 +3611,7 @@ function PreCreativeWork({
|
|
|
2215
3611
|
}) {
|
|
2216
3612
|
const date = new Date(creativeWork.releaseTime);
|
|
2217
3613
|
const now = /* @__PURE__ */ new Date();
|
|
2218
|
-
const [remainingTime, setRemainingTime] =
|
|
3614
|
+
const [remainingTime, setRemainingTime] = useState6(
|
|
2219
3615
|
date.getTime() - now.getTime()
|
|
2220
3616
|
);
|
|
2221
3617
|
const shouldBeStarted = remainingTime < 0;
|
|
@@ -2234,27 +3630,26 @@ function PreCreativeWork({
|
|
|
2234
3630
|
}, [date, remainingTime]);
|
|
2235
3631
|
const renderCountdown = () => {
|
|
2236
3632
|
if (shouldBeStarted) {
|
|
2237
|
-
return /* @__PURE__ */
|
|
3633
|
+
return /* @__PURE__ */ jsx10("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
|
|
2238
3634
|
}
|
|
2239
3635
|
const seconds = Math.floor(remainingTime / 1e3) % 60;
|
|
2240
3636
|
const minutes = Math.floor(remainingTime / 1e3 / 60) % 60;
|
|
2241
3637
|
const hours = Math.floor(remainingTime / 1e3 / 60 / 60) % 24;
|
|
2242
3638
|
const days = Math.floor(remainingTime / 1e3 / 60 / 60 / 24);
|
|
2243
|
-
return /* @__PURE__ */ jsxs7("div", { className: "grid grid-flow-col gap-5 text-center auto-cols-max", children: [
|
|
3639
|
+
return /* @__PURE__ */ jsxs7("div", { className: "grid grid-flow-col md:gap-5 gap-1 text-center auto-cols-max", children: [
|
|
2244
3640
|
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
2245
|
-
/* @__PURE__ */
|
|
3641
|
+
/* @__PURE__ */ jsx10("span", { className: "font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx10(
|
|
2246
3642
|
"span",
|
|
2247
3643
|
{
|
|
2248
|
-
style: { "--value": days },
|
|
2249
3644
|
"aria-live": "polite",
|
|
2250
3645
|
"aria-label": days.toString(),
|
|
2251
|
-
children: days
|
|
3646
|
+
children: days.toString()
|
|
2252
3647
|
}
|
|
2253
3648
|
) }),
|
|
2254
|
-
/* @__PURE__ */
|
|
3649
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("DAYS") })
|
|
2255
3650
|
] }),
|
|
2256
3651
|
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
2257
|
-
/* @__PURE__ */
|
|
3652
|
+
/* @__PURE__ */ jsx10("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx10(
|
|
2258
3653
|
"span",
|
|
2259
3654
|
{
|
|
2260
3655
|
style: { "--value": hours },
|
|
@@ -2263,10 +3658,10 @@ function PreCreativeWork({
|
|
|
2263
3658
|
children: hours?.toString()?.padStart(2, "0")
|
|
2264
3659
|
}
|
|
2265
3660
|
) }),
|
|
2266
|
-
/* @__PURE__ */
|
|
3661
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("HOURS") })
|
|
2267
3662
|
] }),
|
|
2268
3663
|
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
2269
|
-
/* @__PURE__ */
|
|
3664
|
+
/* @__PURE__ */ jsx10("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx10(
|
|
2270
3665
|
"span",
|
|
2271
3666
|
{
|
|
2272
3667
|
style: { "--value": minutes },
|
|
@@ -2275,10 +3670,10 @@ function PreCreativeWork({
|
|
|
2275
3670
|
children: minutes?.toString()?.padStart(2, "0")
|
|
2276
3671
|
}
|
|
2277
3672
|
) }),
|
|
2278
|
-
/* @__PURE__ */
|
|
3673
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("MINUTES") })
|
|
2279
3674
|
] }),
|
|
2280
3675
|
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
2281
|
-
/* @__PURE__ */
|
|
3676
|
+
/* @__PURE__ */ jsx10("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx10(
|
|
2282
3677
|
"span",
|
|
2283
3678
|
{
|
|
2284
3679
|
style: { "--value": seconds },
|
|
@@ -2287,7 +3682,7 @@ function PreCreativeWork({
|
|
|
2287
3682
|
children: seconds?.toString()?.padStart(2, "0")
|
|
2288
3683
|
}
|
|
2289
3684
|
) }),
|
|
2290
|
-
/* @__PURE__ */
|
|
3685
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("SECONDS") })
|
|
2291
3686
|
] })
|
|
2292
3687
|
] });
|
|
2293
3688
|
};
|
|
@@ -2300,12 +3695,12 @@ function PreCreativeWork({
|
|
|
2300
3695
|
backgroundImage: backgroundImageUrl ? `url(${backgroundImageUrl})` : ""
|
|
2301
3696
|
},
|
|
2302
3697
|
children: [
|
|
2303
|
-
backgroundImageUrl && /* @__PURE__ */
|
|
2304
|
-
/* @__PURE__ */
|
|
3698
|
+
backgroundImageUrl && /* @__PURE__ */ jsx10("div", { className: "absolute inset-0 bg-black bg-opacity-40" }),
|
|
3699
|
+
/* @__PURE__ */ jsx10("div", { className: "relative z-10", children: renderCountdown() })
|
|
2305
3700
|
]
|
|
2306
3701
|
}
|
|
2307
3702
|
),
|
|
2308
|
-
!hideTitle && /* @__PURE__ */
|
|
3703
|
+
!hideTitle && /* @__PURE__ */ jsx10(
|
|
2309
3704
|
TitleAndDescription2,
|
|
2310
3705
|
{
|
|
2311
3706
|
title: creativeWork.title,
|
|
@@ -2324,7 +3719,7 @@ var TitleAndDescription2 = ({
|
|
|
2324
3719
|
className
|
|
2325
3720
|
}) => {
|
|
2326
3721
|
return /* @__PURE__ */ jsxs7("div", { className: twMerge5("mt-3 mb-6 m-event-details-ctn px-4 text-left w-full", className), children: [
|
|
2327
|
-
/* @__PURE__ */
|
|
3722
|
+
/* @__PURE__ */ jsx10("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
|
|
2328
3723
|
releaseTime ? /* @__PURE__ */ jsxs7("div", { className: "text-sm md:text-base text-base-content/70 m-event-start-time", children: [
|
|
2329
3724
|
new Date(releaseTime || "").toLocaleDateString(locale || "default", {
|
|
2330
3725
|
month: "long",
|
|
@@ -2338,13 +3733,13 @@ var TitleAndDescription2 = ({
|
|
|
2338
3733
|
minute: "2-digit"
|
|
2339
3734
|
})
|
|
2340
3735
|
] }) : null,
|
|
2341
|
-
description && /* @__PURE__ */
|
|
3736
|
+
description && /* @__PURE__ */ jsx10("div", { className: "text-xs md:text-sm text-base-content/60 uppercase", children: description })
|
|
2342
3737
|
] });
|
|
2343
3738
|
};
|
|
2344
3739
|
|
|
2345
3740
|
// src/QueryProvider.tsx
|
|
2346
3741
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
2347
|
-
import { jsx as
|
|
3742
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
2348
3743
|
var queryClient = new QueryClient({
|
|
2349
3744
|
defaultOptions: {
|
|
2350
3745
|
queries: {
|
|
@@ -2358,13 +3753,16 @@ var queryClient = new QueryClient({
|
|
|
2358
3753
|
}
|
|
2359
3754
|
});
|
|
2360
3755
|
var QueryProvider = ({ children }) => {
|
|
2361
|
-
return /* @__PURE__ */
|
|
3756
|
+
return /* @__PURE__ */ jsx11(QueryClientProvider, { client: queryClient, children });
|
|
2362
3757
|
};
|
|
2363
3758
|
export {
|
|
3759
|
+
BigPlayIcon,
|
|
2364
3760
|
CreativeWork,
|
|
2365
3761
|
Event,
|
|
2366
3762
|
Player,
|
|
2367
3763
|
QueryProvider,
|
|
3764
|
+
SkipBackIcon,
|
|
3765
|
+
SkipForwardIcon,
|
|
2368
3766
|
Video,
|
|
2369
3767
|
queryClient
|
|
2370
3768
|
};
|