@mottosports/motto-video-player 1.0.1-rc.8 → 1.0.1-rc.81
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 +2083 -688
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2028 -634
- 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";
|
|
402
|
+
|
|
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.81";
|
|
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
|
+
};
|
|
31
603
|
|
|
32
|
-
// src/hooks/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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) {
|
|
1452
|
+
constructor(onSkipForward, iconSize) {
|
|
335
1453
|
this.onSkipForward = onSkipForward;
|
|
1454
|
+
this.iconSize = iconSize;
|
|
336
1455
|
}
|
|
337
1456
|
create(rootElement, controls) {
|
|
338
|
-
return new SkipForwardButton(rootElement, controls, this.onSkipForward);
|
|
1457
|
+
return new SkipForwardButton(rootElement, controls, this.onSkipForward, this.iconSize);
|
|
339
1458
|
}
|
|
340
1459
|
};
|
|
341
|
-
var
|
|
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;
|
|
516
|
-
this.onSkipForward = onSkipForward;
|
|
517
|
-
}
|
|
518
|
-
create(rootElement, controls) {
|
|
519
|
-
return new MobileControlsContainer(rootElement, controls, this.onSkipBack, this.onSkipForward);
|
|
520
|
-
}
|
|
521
|
-
};
|
|
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,149 @@ 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;
|
|
655
|
-
}
|
|
656
|
-
const manifest = player.getManifest();
|
|
657
|
-
if (!manifest) {
|
|
658
|
-
return;
|
|
1622
|
+
if (typeof player.isLive !== "function") {
|
|
1623
|
+
return { isLive: false, isNearEdge: false };
|
|
659
1624
|
}
|
|
660
|
-
const
|
|
661
|
-
if (!
|
|
662
|
-
|
|
1625
|
+
const isLiveStream = player.isLive();
|
|
1626
|
+
if (!isLiveStream) return { isLive: false, isNearEdge: false };
|
|
1627
|
+
const videoElement = player.getMediaElement?.();
|
|
1628
|
+
if (!videoElement) return { isLive: true, isNearEdge: false };
|
|
1629
|
+
if (typeof player.seekRange !== "function") {
|
|
1630
|
+
return { isLive: true, isNearEdge: false };
|
|
663
1631
|
}
|
|
664
|
-
const
|
|
665
|
-
if (
|
|
666
|
-
|
|
667
|
-
setIsVisible(liveStatus);
|
|
668
|
-
onLiveStateChange?.(liveStatus);
|
|
1632
|
+
const seekRange = player.seekRange();
|
|
1633
|
+
if (!seekRange || seekRange.end === void 0) {
|
|
1634
|
+
return { isLive: true, isNearEdge: false };
|
|
669
1635
|
}
|
|
1636
|
+
const liveEdge = seekRange.end;
|
|
1637
|
+
const currentTime = videoElement.currentTime;
|
|
1638
|
+
const timeBehindLive = liveEdge - currentTime;
|
|
1639
|
+
return {
|
|
1640
|
+
isLive: true,
|
|
1641
|
+
isNearEdge: timeBehindLive <= liveThresholdSeconds,
|
|
1642
|
+
liveEdge
|
|
1643
|
+
};
|
|
670
1644
|
} catch (error) {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
1645
|
+
console.error("Error checking live status:", error);
|
|
1646
|
+
return { isLive: false, isNearEdge: false };
|
|
674
1647
|
}
|
|
675
1648
|
};
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
return;
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
if (
|
|
686
|
-
|
|
687
|
-
intervalRef.current = null;
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
}, [enabled, playerRef.current]);
|
|
691
|
-
useEffect(() => {
|
|
692
|
-
return () => {
|
|
693
|
-
if (intervalRef.current) {
|
|
694
|
-
clearInterval(intervalRef.current);
|
|
1649
|
+
const seekToLiveEdge = () => {
|
|
1650
|
+
const player = playerRef.current;
|
|
1651
|
+
if (!player) return;
|
|
1652
|
+
try {
|
|
1653
|
+
if (typeof player.seekRange !== "function") return;
|
|
1654
|
+
const seekRange = player.seekRange();
|
|
1655
|
+
if (!seekRange || seekRange.end === void 0) return;
|
|
1656
|
+
const liveEdge = seekRange.end;
|
|
1657
|
+
const videoElement = player.getMediaElement?.();
|
|
1658
|
+
if (videoElement) {
|
|
1659
|
+
videoElement.currentTime = liveEdge;
|
|
695
1660
|
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
const showBadge = () => setIsVisible(true);
|
|
700
|
-
return {
|
|
701
|
-
isLive,
|
|
702
|
-
isVisible,
|
|
703
|
-
hideBadge,
|
|
704
|
-
showBadge,
|
|
705
|
-
checkLiveStatus
|
|
1661
|
+
} catch (error) {
|
|
1662
|
+
console.error("Error seeking to live edge:", error);
|
|
1663
|
+
}
|
|
706
1664
|
};
|
|
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(() => {
|
|
1665
|
+
useEffect2(() => {
|
|
723
1666
|
if (!containerRef.current || !enabled) {
|
|
724
1667
|
return;
|
|
725
1668
|
}
|
|
726
|
-
const
|
|
727
|
-
|
|
1669
|
+
const updateLiveIndicator = (currentTimeElement, status) => {
|
|
1670
|
+
const parent = currentTimeElement.parentElement;
|
|
1671
|
+
if (!parent) return;
|
|
1672
|
+
const existingContainer = parent.querySelector(".live-indicator-container");
|
|
1673
|
+
const isCurrentlyNearEdge = existingContainer?.getAttribute("data-near-edge") === "true";
|
|
1674
|
+
if (existingContainer && status.isNearEdge === isCurrentlyNearEdge) {
|
|
728
1675
|
return;
|
|
729
1676
|
}
|
|
1677
|
+
if (existingContainer) {
|
|
1678
|
+
existingContainer.remove();
|
|
1679
|
+
}
|
|
1680
|
+
const container = document.createElement("span");
|
|
1681
|
+
container.className = "live-indicator-container";
|
|
1682
|
+
container.setAttribute("data-near-edge", status.isNearEdge.toString());
|
|
1683
|
+
container.style.cssText = `
|
|
1684
|
+
display: inline-flex;
|
|
1685
|
+
align-items: center;
|
|
1686
|
+
width: 80px;
|
|
1687
|
+
${!status.isNearEdge ? "cursor: pointer;" : ""}
|
|
1688
|
+
`;
|
|
730
1689
|
const indicator = document.createElement("span");
|
|
731
1690
|
indicator.className = "live-indicator-dot";
|
|
732
1691
|
indicator.style.cssText = `
|
|
733
1692
|
display: inline-block;
|
|
734
1693
|
width: ${indicatorSize}px;
|
|
735
1694
|
height: ${indicatorSize}px;
|
|
736
|
-
background-color: ${indicatorColor};
|
|
1695
|
+
background-color: ${status.isNearEdge ? indicatorColor : "#888888"};
|
|
737
1696
|
border-radius: 50%;
|
|
738
1697
|
margin-right: 6px;
|
|
739
|
-
|
|
740
|
-
${showPulseAnimation ? "animation: pulse-live 2s infinite;" : ""}
|
|
1698
|
+
${status.isNearEdge && showPulseAnimation ? "animation: pulse-live 2s infinite;" : ""}
|
|
741
1699
|
`;
|
|
742
|
-
|
|
1700
|
+
const liveText = document.createElement("span");
|
|
1701
|
+
liveText.className = "live-indicator-text";
|
|
1702
|
+
liveText.textContent = status.isNearEdge ? "LIVE" : "GO TO LIVE";
|
|
1703
|
+
container.appendChild(indicator);
|
|
1704
|
+
container.appendChild(liveText);
|
|
1705
|
+
if (!status.isNearEdge) {
|
|
1706
|
+
container.addEventListener("click", seekToLiveEdge);
|
|
1707
|
+
}
|
|
1708
|
+
if (status.isNearEdge) {
|
|
1709
|
+
parent.insertBefore(container, currentTimeElement);
|
|
1710
|
+
currentTimeElement.style.display = "none";
|
|
1711
|
+
} else {
|
|
1712
|
+
currentTimeElement.insertAdjacentElement("afterend", container);
|
|
1713
|
+
currentTimeElement.style.display = "";
|
|
1714
|
+
}
|
|
743
1715
|
};
|
|
744
1716
|
const removeLiveIndicator = (currentTimeElement) => {
|
|
745
|
-
const
|
|
746
|
-
if (
|
|
747
|
-
|
|
1717
|
+
const parent = currentTimeElement.parentElement;
|
|
1718
|
+
if (!parent) return;
|
|
1719
|
+
const container = parent.querySelector(".live-indicator-container");
|
|
1720
|
+
if (container) {
|
|
1721
|
+
container.remove();
|
|
1722
|
+
currentTimeElement.style.display = "";
|
|
748
1723
|
}
|
|
749
1724
|
};
|
|
750
1725
|
const checkForLiveContent = () => {
|
|
751
1726
|
const currentTimeElements = containerRef.current?.querySelectorAll(".shaka-current-time");
|
|
1727
|
+
const status = getLiveStatus(playerRef.current);
|
|
1728
|
+
const lastStatus = lastStatusRef.current;
|
|
1729
|
+
if (onLiveStatusChange && (!lastStatus || lastStatus.isLive !== status.isLive || lastStatus.isNearEdge !== status.isNearEdge)) {
|
|
1730
|
+
onLiveStatusChange(status);
|
|
1731
|
+
lastStatusRef.current = { isLive: status.isLive, isNearEdge: status.isNearEdge };
|
|
1732
|
+
}
|
|
752
1733
|
currentTimeElements?.forEach((element) => {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
addLiveIndicator(element);
|
|
1734
|
+
if (status.isLive) {
|
|
1735
|
+
updateLiveIndicator(element, status);
|
|
756
1736
|
} else {
|
|
757
1737
|
removeLiveIndicator(element);
|
|
758
1738
|
}
|
|
759
1739
|
});
|
|
760
1740
|
};
|
|
761
1741
|
checkForLiveContent();
|
|
1742
|
+
intervalRef.current = setInterval(checkForLiveContent, 1e3);
|
|
762
1743
|
observerRef.current = new MutationObserver((mutations) => {
|
|
763
1744
|
let shouldCheck = false;
|
|
764
1745
|
mutations.forEach((mutation) => {
|
|
@@ -784,31 +1765,289 @@ var useLiveIndicator = (containerRef, options = {}) => {
|
|
|
784
1765
|
characterData: true,
|
|
785
1766
|
characterDataOldValue: true
|
|
786
1767
|
});
|
|
787
|
-
const intervalId = setInterval(checkForLiveContent, 1e3);
|
|
788
1768
|
return () => {
|
|
789
1769
|
if (observerRef.current) {
|
|
790
1770
|
observerRef.current.disconnect();
|
|
791
1771
|
}
|
|
792
|
-
|
|
1772
|
+
if (intervalRef.current) {
|
|
1773
|
+
clearInterval(intervalRef.current);
|
|
1774
|
+
}
|
|
793
1775
|
};
|
|
794
|
-
}, [containerRef, enabled, indicatorColor, indicatorSize, showPulseAnimation]);
|
|
1776
|
+
}, [containerRef, enabled, indicatorColor, indicatorSize, showPulseAnimation, liveThresholdSeconds]);
|
|
795
1777
|
return {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1778
|
+
seekToLiveEdge,
|
|
1779
|
+
getLiveStatus: () => getLiveStatus(playerRef.current)
|
|
1780
|
+
};
|
|
1781
|
+
};
|
|
1782
|
+
|
|
1783
|
+
// src/hooks/useKeyboardControls.ts
|
|
1784
|
+
import { useCallback as useCallback7, useEffect as useEffect3 } from "react";
|
|
1785
|
+
var useKeyboardControls = (videoRef, options = {}) => {
|
|
1786
|
+
const { skipBack, skipForward, enabled = true } = options;
|
|
1787
|
+
const isDesktop = useCallback7(() => {
|
|
1788
|
+
return window.innerWidth > 767 && !/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
1789
|
+
}, []);
|
|
1790
|
+
const handleKeydown = useCallback7((event) => {
|
|
1791
|
+
if (!enabled || !isDesktop() || !videoRef.current) return;
|
|
1792
|
+
const activeElement = document.activeElement;
|
|
1793
|
+
if (activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.isContentEditable)) {
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
switch (event.key) {
|
|
1797
|
+
case "ArrowLeft":
|
|
1798
|
+
event.preventDefault();
|
|
1799
|
+
skipBack?.();
|
|
1800
|
+
break;
|
|
1801
|
+
case "ArrowRight":
|
|
1802
|
+
event.preventDefault();
|
|
1803
|
+
skipForward?.();
|
|
1804
|
+
break;
|
|
1805
|
+
case " ":
|
|
1806
|
+
case "Space":
|
|
1807
|
+
event.preventDefault();
|
|
1808
|
+
if (videoRef.current.paused) {
|
|
1809
|
+
videoRef.current.play();
|
|
1810
|
+
} else {
|
|
1811
|
+
videoRef.current.pause();
|
|
802
1812
|
}
|
|
1813
|
+
break;
|
|
1814
|
+
}
|
|
1815
|
+
}, [enabled, videoRef, skipBack, skipForward, isDesktop]);
|
|
1816
|
+
useEffect3(() => {
|
|
1817
|
+
if (!enabled || !isDesktop()) return;
|
|
1818
|
+
document.addEventListener("keydown", handleKeydown);
|
|
1819
|
+
return () => {
|
|
1820
|
+
document.removeEventListener("keydown", handleKeydown);
|
|
1821
|
+
};
|
|
1822
|
+
}, [handleKeydown, enabled, isDesktop]);
|
|
1823
|
+
return {
|
|
1824
|
+
isDesktop: isDesktop()
|
|
1825
|
+
};
|
|
1826
|
+
};
|
|
1827
|
+
|
|
1828
|
+
// src/hooks/useAdEvents.ts
|
|
1829
|
+
import { useCallback as useCallback8, useRef as useRef7 } from "react";
|
|
1830
|
+
var useAdEvents = (playerRef, handlers) => {
|
|
1831
|
+
const listenersRef = useRef7([]);
|
|
1832
|
+
const setupAdEventListeners = useCallback8(() => {
|
|
1833
|
+
const player = playerRef.current;
|
|
1834
|
+
if (!player) return;
|
|
1835
|
+
const adManager = player.getAdManager();
|
|
1836
|
+
if (!adManager) return;
|
|
1837
|
+
const onAdsManagerLoaded = (event) => {
|
|
1838
|
+
const adsManager = event.getAdsManager();
|
|
1839
|
+
const onAdStarted = () => {
|
|
1840
|
+
console.log("Ad started");
|
|
1841
|
+
handlers.onAdStart?.();
|
|
1842
|
+
};
|
|
1843
|
+
const onAdComplete = () => {
|
|
1844
|
+
console.log("Ad completed");
|
|
1845
|
+
handlers.onAdComplete?.();
|
|
1846
|
+
};
|
|
1847
|
+
const onAdError = (adErrorEvent) => {
|
|
1848
|
+
console.error("Ad error:", adErrorEvent.getError());
|
|
1849
|
+
handlers.onAdError?.(adErrorEvent.getError());
|
|
1850
|
+
};
|
|
1851
|
+
const onAdSkipped = () => {
|
|
1852
|
+
console.log("Ad skipped");
|
|
1853
|
+
handlers.onAdSkipped?.();
|
|
1854
|
+
};
|
|
1855
|
+
const onAdPaused = () => {
|
|
1856
|
+
console.log("Ad paused");
|
|
1857
|
+
handlers.onAdPaused?.();
|
|
1858
|
+
};
|
|
1859
|
+
const onAdResumed = () => {
|
|
1860
|
+
console.log("Ad resumed");
|
|
1861
|
+
handlers.onAdResumed?.();
|
|
1862
|
+
};
|
|
1863
|
+
const onAdProgress = (adProgressData) => {
|
|
1864
|
+
handlers.onAdProgress?.(adProgressData);
|
|
1865
|
+
};
|
|
1866
|
+
const onAllAdsCompleted = () => {
|
|
1867
|
+
console.log("All ads completed");
|
|
1868
|
+
handlers.onAllAdsCompleted?.();
|
|
1869
|
+
};
|
|
1870
|
+
const adEventListeners = [];
|
|
1871
|
+
if (window.google?.ima) {
|
|
1872
|
+
const AdEvent = window.google.ima.AdEvent.Type;
|
|
1873
|
+
const AdErrorEvent = window.google.ima.AdErrorEvent.Type;
|
|
1874
|
+
if (handlers.onAdStart) {
|
|
1875
|
+
adsManager.addEventListener(AdEvent.STARTED, onAdStarted);
|
|
1876
|
+
adEventListeners.push({ event: AdEvent.STARTED, listener: onAdStarted });
|
|
1877
|
+
}
|
|
1878
|
+
if (handlers.onAdComplete) {
|
|
1879
|
+
adsManager.addEventListener(AdEvent.COMPLETE, onAdComplete);
|
|
1880
|
+
adEventListeners.push({ event: AdEvent.COMPLETE, listener: onAdComplete });
|
|
1881
|
+
}
|
|
1882
|
+
if (handlers.onAdError) {
|
|
1883
|
+
adsManager.addEventListener(AdErrorEvent.AD_ERROR, onAdError);
|
|
1884
|
+
adEventListeners.push({ event: AdErrorEvent.AD_ERROR, listener: onAdError });
|
|
1885
|
+
}
|
|
1886
|
+
if (handlers.onAdSkipped) {
|
|
1887
|
+
adsManager.addEventListener(AdEvent.SKIPPED, onAdSkipped);
|
|
1888
|
+
adEventListeners.push({ event: AdEvent.SKIPPED, listener: onAdSkipped });
|
|
1889
|
+
}
|
|
1890
|
+
if (handlers.onAdPaused) {
|
|
1891
|
+
adsManager.addEventListener(AdEvent.PAUSED, onAdPaused);
|
|
1892
|
+
adEventListeners.push({ event: AdEvent.PAUSED, listener: onAdPaused });
|
|
1893
|
+
}
|
|
1894
|
+
if (handlers.onAdResumed) {
|
|
1895
|
+
adsManager.addEventListener(AdEvent.RESUMED, onAdResumed);
|
|
1896
|
+
adEventListeners.push({ event: AdEvent.RESUMED, listener: onAdResumed });
|
|
1897
|
+
}
|
|
1898
|
+
if (handlers.onAdProgress) {
|
|
1899
|
+
adsManager.addEventListener(AdEvent.AD_PROGRESS, onAdProgress);
|
|
1900
|
+
adEventListeners.push({ event: AdEvent.AD_PROGRESS, listener: onAdProgress });
|
|
1901
|
+
}
|
|
1902
|
+
if (handlers.onAllAdsCompleted) {
|
|
1903
|
+
adsManager.addEventListener(AdEvent.ALL_ADS_COMPLETED, onAllAdsCompleted);
|
|
1904
|
+
adEventListeners.push({ event: AdEvent.ALL_ADS_COMPLETED, listener: onAllAdsCompleted });
|
|
1905
|
+
}
|
|
1906
|
+
listenersRef.current.push({
|
|
1907
|
+
adsManager,
|
|
1908
|
+
listeners: adEventListeners
|
|
1909
|
+
});
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
try {
|
|
1913
|
+
player.addEventListener("ad-started", () => {
|
|
1914
|
+
console.log("Shaka ad-started event");
|
|
1915
|
+
handlers.onAdStart?.();
|
|
1916
|
+
});
|
|
1917
|
+
player.addEventListener("ad-complete", () => {
|
|
1918
|
+
console.log("Shaka ad-complete event");
|
|
1919
|
+
handlers.onAdComplete?.();
|
|
1920
|
+
});
|
|
1921
|
+
player.addEventListener("ad-skipped", () => {
|
|
1922
|
+
console.log("Shaka ad-skipped event");
|
|
1923
|
+
handlers.onAdSkipped?.();
|
|
1924
|
+
});
|
|
1925
|
+
player.addEventListener("ad-error", (event) => {
|
|
1926
|
+
console.error("Shaka ad-error event:", event);
|
|
1927
|
+
handlers.onAdError?.(event);
|
|
1928
|
+
});
|
|
1929
|
+
listenersRef.current.push({
|
|
1930
|
+
type: "shaka",
|
|
1931
|
+
player,
|
|
1932
|
+
events: ["ad-started", "ad-complete", "ad-skipped", "ad-error"]
|
|
803
1933
|
});
|
|
1934
|
+
} catch (error) {
|
|
1935
|
+
console.warn("Error setting up ad event listeners:", error);
|
|
1936
|
+
}
|
|
1937
|
+
}, [playerRef, handlers]);
|
|
1938
|
+
const cleanupAdEventListeners = useCallback8(() => {
|
|
1939
|
+
try {
|
|
1940
|
+
listenersRef.current.forEach((listenerGroup) => {
|
|
1941
|
+
if (listenerGroup.type === "shaka" && listenerGroup.player) {
|
|
1942
|
+
listenerGroup.events.forEach((eventName) => {
|
|
1943
|
+
try {
|
|
1944
|
+
listenerGroup.player.removeEventListener(eventName, () => {
|
|
1945
|
+
});
|
|
1946
|
+
} catch (e) {
|
|
1947
|
+
console.warn(`Error removing ${eventName} listener:`, e);
|
|
1948
|
+
}
|
|
1949
|
+
});
|
|
1950
|
+
} else if (listenerGroup.adsManager && listenerGroup.listeners) {
|
|
1951
|
+
listenerGroup.listeners.forEach(({ event, listener }) => {
|
|
1952
|
+
try {
|
|
1953
|
+
listenerGroup.adsManager.removeEventListener(event, listener);
|
|
1954
|
+
} catch (e) {
|
|
1955
|
+
console.warn("Error removing ad listener:", e);
|
|
1956
|
+
}
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
});
|
|
1960
|
+
listenersRef.current = [];
|
|
1961
|
+
} catch (error) {
|
|
1962
|
+
console.warn("Error cleaning up ad event listeners:", error);
|
|
804
1963
|
}
|
|
1964
|
+
}, []);
|
|
1965
|
+
return {
|
|
1966
|
+
setupAdEventListeners,
|
|
1967
|
+
cleanupAdEventListeners
|
|
805
1968
|
};
|
|
806
1969
|
};
|
|
807
1970
|
|
|
1971
|
+
// src/Player.tsx
|
|
1972
|
+
import { twMerge as twMerge2 } from "tailwind-merge";
|
|
1973
|
+
|
|
1974
|
+
// src/utils/scriptLoader.ts
|
|
1975
|
+
var SCRIPT_CONFIGS = {
|
|
1976
|
+
ima: {
|
|
1977
|
+
src: "https://imasdk.googleapis.com/js/sdkloader/ima3.js",
|
|
1978
|
+
id: "ima-sdk",
|
|
1979
|
+
type: "text/javascript"
|
|
1980
|
+
},
|
|
1981
|
+
system73: {
|
|
1982
|
+
src: "//cdn.s73cloud.com/4/s73-sdk-shakaplayer.js",
|
|
1983
|
+
id: "system73-sdk",
|
|
1984
|
+
type: "application/javascript"
|
|
1985
|
+
}
|
|
1986
|
+
};
|
|
1987
|
+
function loadScript(config) {
|
|
1988
|
+
return new Promise((resolve, reject) => {
|
|
1989
|
+
if (document.getElementById(config.id)) {
|
|
1990
|
+
resolve();
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1993
|
+
const script = document.createElement("script");
|
|
1994
|
+
script.id = config.id;
|
|
1995
|
+
script.src = config.src;
|
|
1996
|
+
script.type = config.type || "text/javascript";
|
|
1997
|
+
script.async = true;
|
|
1998
|
+
script.onload = () => resolve();
|
|
1999
|
+
script.onerror = () => reject(new Error(`Failed to load script: ${config.src}`));
|
|
2000
|
+
document.head.appendChild(script);
|
|
2001
|
+
});
|
|
2002
|
+
}
|
|
2003
|
+
function getRequiredScriptLoaders(needsIma, needsSystem73) {
|
|
2004
|
+
const loaders = [];
|
|
2005
|
+
if (needsIma) {
|
|
2006
|
+
loaders.push(loadScript(SCRIPT_CONFIGS.ima));
|
|
2007
|
+
}
|
|
2008
|
+
if (needsSystem73) {
|
|
2009
|
+
loaders.push(loadScript(SCRIPT_CONFIGS.system73));
|
|
2010
|
+
}
|
|
2011
|
+
return loaders;
|
|
2012
|
+
}
|
|
2013
|
+
async function loadScripts(scriptLoaders) {
|
|
2014
|
+
if (scriptLoaders.length === 0) {
|
|
2015
|
+
return;
|
|
2016
|
+
}
|
|
2017
|
+
try {
|
|
2018
|
+
await Promise.all(scriptLoaders);
|
|
2019
|
+
} catch (error) {
|
|
2020
|
+
console.error("Error loading scripts:", error);
|
|
2021
|
+
throw error;
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
function waitForGlobal(globalName, timeout = 5e3) {
|
|
2025
|
+
return new Promise((resolve, reject) => {
|
|
2026
|
+
const startTime = Date.now();
|
|
2027
|
+
function checkGlobal() {
|
|
2028
|
+
const global = window[globalName];
|
|
2029
|
+
if (global) {
|
|
2030
|
+
resolve(global);
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
if (Date.now() - startTime > timeout) {
|
|
2034
|
+
reject(new Error(`Timeout waiting for global: ${globalName}`));
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
setTimeout(checkGlobal, 100);
|
|
2038
|
+
}
|
|
2039
|
+
checkGlobal();
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2042
|
+
async function waitForGlobals(globalNames, timeout = 5e3) {
|
|
2043
|
+
const promises = globalNames.map((name) => waitForGlobal(name, timeout));
|
|
2044
|
+
await Promise.all(promises);
|
|
2045
|
+
}
|
|
2046
|
+
|
|
808
2047
|
// src/components/Loading.tsx
|
|
809
2048
|
import { twMerge } from "tailwind-merge";
|
|
810
|
-
import { jsx
|
|
811
|
-
var Loading = ({ className }) => /* @__PURE__ */
|
|
2049
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
2050
|
+
var Loading = ({ className }) => /* @__PURE__ */ jsx4(
|
|
812
2051
|
"div",
|
|
813
2052
|
{
|
|
814
2053
|
className: twMerge(
|
|
@@ -816,17 +2055,36 @@ var Loading = ({ className }) => /* @__PURE__ */ jsxs(
|
|
|
816
2055
|
className
|
|
817
2056
|
),
|
|
818
2057
|
role: "status",
|
|
819
|
-
children:
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
2058
|
+
children: /* @__PURE__ */ jsx4("div", { className: " flex justify-center items-center", children: /* @__PURE__ */ jsx4(
|
|
2059
|
+
"svg",
|
|
2060
|
+
{
|
|
2061
|
+
className: "shaka-spinner-svg animate-spin h-12 w-12",
|
|
2062
|
+
viewBox: "0 0 64 64",
|
|
2063
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2064
|
+
children: /* @__PURE__ */ jsx4(
|
|
2065
|
+
"circle",
|
|
2066
|
+
{
|
|
2067
|
+
className: "shaka-spinner-path",
|
|
2068
|
+
cx: "32",
|
|
2069
|
+
cy: "32",
|
|
2070
|
+
r: "28",
|
|
2071
|
+
strokeWidth: "4",
|
|
2072
|
+
strokeLinecap: "round",
|
|
2073
|
+
stroke: "currentColor",
|
|
2074
|
+
fill: "none",
|
|
2075
|
+
strokeDasharray: "176",
|
|
2076
|
+
strokeDashoffset: "120"
|
|
2077
|
+
}
|
|
2078
|
+
)
|
|
2079
|
+
}
|
|
2080
|
+
) })
|
|
823
2081
|
}
|
|
824
2082
|
);
|
|
825
2083
|
|
|
826
2084
|
// src/components/ErrorScreen.tsx
|
|
827
|
-
import { jsx as
|
|
828
|
-
var ErrorScreen = ({ title, description }) => /* @__PURE__ */
|
|
829
|
-
/* @__PURE__ */
|
|
2085
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2086
|
+
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: [
|
|
2087
|
+
/* @__PURE__ */ jsx5(
|
|
830
2088
|
"svg",
|
|
831
2089
|
{
|
|
832
2090
|
className: "w-24 h-24 m-6",
|
|
@@ -836,7 +2094,7 @@ var ErrorScreen = ({ title, description }) => /* @__PURE__ */ jsx2("div", { clas
|
|
|
836
2094
|
style: { width: 96 },
|
|
837
2095
|
viewBox: "0 0 24 24",
|
|
838
2096
|
xmlns: "http://www.w3.org/2000/svg",
|
|
839
|
-
children: /* @__PURE__ */
|
|
2097
|
+
children: /* @__PURE__ */ jsx5(
|
|
840
2098
|
"path",
|
|
841
2099
|
{
|
|
842
2100
|
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 +2104,22 @@ var ErrorScreen = ({ title, description }) => /* @__PURE__ */ jsx2("div", { clas
|
|
|
846
2104
|
)
|
|
847
2105
|
}
|
|
848
2106
|
),
|
|
849
|
-
/* @__PURE__ */
|
|
850
|
-
/* @__PURE__ */
|
|
851
|
-
/* @__PURE__ */
|
|
2107
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
2108
|
+
/* @__PURE__ */ jsx5("h3", { className: "text-2xl mb-2", children: title || "Playback Error" }),
|
|
2109
|
+
/* @__PURE__ */ jsx5("div", { className: "text-lg", children: description || "Unable to play the video. Please try again later." })
|
|
852
2110
|
] })
|
|
853
2111
|
] }) });
|
|
854
2112
|
|
|
855
2113
|
// 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');
|
|
2114
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2115
|
+
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
2116
|
|
|
903
2117
|
// src/Player.tsx
|
|
904
|
-
import {
|
|
905
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2118
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
906
2119
|
var Player = forwardRef(
|
|
907
2120
|
({
|
|
908
2121
|
src,
|
|
2122
|
+
managedMode = false,
|
|
909
2123
|
autoPlay = false,
|
|
910
2124
|
loop = false,
|
|
911
2125
|
muted = false,
|
|
@@ -917,25 +2131,48 @@ var Player = forwardRef(
|
|
|
917
2131
|
shakaConfig,
|
|
918
2132
|
drmConfig,
|
|
919
2133
|
muxConfig,
|
|
2134
|
+
system73Config,
|
|
920
2135
|
imaConfig,
|
|
921
2136
|
chromecastConfig,
|
|
922
2137
|
qualityConfig,
|
|
923
2138
|
seekbarConfig,
|
|
2139
|
+
iconSizes,
|
|
924
2140
|
events,
|
|
2141
|
+
locale = "en",
|
|
925
2142
|
containerClassName,
|
|
926
|
-
|
|
2143
|
+
liveThresholdSeconds = 15,
|
|
2144
|
+
publicKey,
|
|
2145
|
+
auth,
|
|
2146
|
+
...videoProps
|
|
927
2147
|
}, ref) => {
|
|
928
2148
|
const videoRef = useRef8(null);
|
|
929
2149
|
const containerRef = useRef8(null);
|
|
930
|
-
const
|
|
2150
|
+
const [isScriptsLoaded, setIsScriptsLoaded] = useState3(false);
|
|
2151
|
+
const [isInitialLoading, setIsInitialLoading] = useState3(true);
|
|
2152
|
+
const [bfResetKey, setBfResetKey] = useState3(0);
|
|
2153
|
+
const hasPlaylist = !!src && (typeof src === "string" || !!(src.url || src.drm?.widevine?.playlistUrl || src.drm?.playready?.playlistUrl || src.drm?.fairplay?.playlistUrl));
|
|
931
2154
|
useImperativeHandle(ref, () => videoRef.current, []);
|
|
932
|
-
const { playerRef, initializePlayer, destroyPlayer } =
|
|
2155
|
+
const { playerRef, initializePlayer, loadManifest, destroyPlayer, isRetrying } = useShakaPlayer({
|
|
933
2156
|
src,
|
|
934
2157
|
shakaConfig,
|
|
935
2158
|
drmConfig,
|
|
936
2159
|
onError: events?.onError,
|
|
937
|
-
onPlayerReady: events?.onPlayerReady
|
|
2160
|
+
onPlayerReady: events?.onPlayerReady,
|
|
2161
|
+
muxConfig,
|
|
2162
|
+
onMuxReady: events?.onMuxReady,
|
|
2163
|
+
onMuxDataUpdate: events?.onMuxDataUpdate,
|
|
2164
|
+
publicKey,
|
|
2165
|
+
mottoToken: auth?.mottoToken,
|
|
2166
|
+
hasAds: !!imaConfig?.adTagUrl,
|
|
2167
|
+
hasSystem73: !!system73Config?.apiKey,
|
|
2168
|
+
apiToken: auth?.apiToken
|
|
938
2169
|
});
|
|
2170
|
+
const {
|
|
2171
|
+
initializeMux,
|
|
2172
|
+
updateMuxData,
|
|
2173
|
+
handleMuxError,
|
|
2174
|
+
destroyMux
|
|
2175
|
+
} = useMuxAnalytics(playerRef, muxConfig, events?.onMuxReady, events?.onMuxDataUpdate);
|
|
939
2176
|
const {
|
|
940
2177
|
getAvailableQualities,
|
|
941
2178
|
setQuality,
|
|
@@ -948,12 +2185,11 @@ var Player = forwardRef(
|
|
|
948
2185
|
skipDuration,
|
|
949
2186
|
shouldShowSkipControls
|
|
950
2187
|
} = useSkipControls(videoRef, events?.onSkipBack, events?.onSkipForward);
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
} = useMuxAnalytics(playerRef, muxConfig, events?.onMuxReady, events?.onMuxDataUpdate);
|
|
2188
|
+
useKeyboardControls(videoRef, {
|
|
2189
|
+
skipBack,
|
|
2190
|
+
skipForward,
|
|
2191
|
+
enabled: true
|
|
2192
|
+
});
|
|
957
2193
|
const { setupEventListeners, cleanupEventListeners } = useEventHandlers(videoRef, {
|
|
958
2194
|
onPlay: events?.onPlay,
|
|
959
2195
|
onPause: events?.onPause,
|
|
@@ -969,109 +2205,230 @@ var Player = forwardRef(
|
|
|
969
2205
|
chromecastConfig,
|
|
970
2206
|
seekbarConfig,
|
|
971
2207
|
events?.onSkipBack,
|
|
972
|
-
events?.onSkipForward
|
|
2208
|
+
events?.onSkipForward,
|
|
2209
|
+
iconSizes,
|
|
2210
|
+
locale
|
|
973
2211
|
);
|
|
974
|
-
const {
|
|
975
|
-
enabled: true,
|
|
976
|
-
onLiveStateChange: (isLive2) => {
|
|
977
|
-
events?.onLiveStateChange?.(isLive2);
|
|
978
|
-
}
|
|
979
|
-
});
|
|
980
|
-
useLiveIndicator(containerRef, {
|
|
2212
|
+
const { getLiveStatus, seekToLiveEdge } = useLiveIndicator(containerRef, playerRef, {
|
|
981
2213
|
enabled: true,
|
|
982
2214
|
indicatorColor: "#ff0000",
|
|
983
2215
|
indicatorSize: 8,
|
|
984
|
-
showPulseAnimation: true
|
|
2216
|
+
showPulseAnimation: true,
|
|
2217
|
+
liveThresholdSeconds,
|
|
2218
|
+
onLiveStatusChange: events?.onLiveStatusChange
|
|
985
2219
|
});
|
|
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
|
-
}
|
|
2220
|
+
const { setupAdEventListeners, cleanupAdEventListeners } = useAdEvents(playerRef, {
|
|
2221
|
+
onAdStart: events?.onAdStart,
|
|
2222
|
+
onAdComplete: events?.onAdComplete,
|
|
2223
|
+
onAdError: events?.onAdError,
|
|
2224
|
+
onAdSkipped: events?.onAdSkipped,
|
|
2225
|
+
onAdPaused: events?.onAdPaused,
|
|
2226
|
+
onAdResumed: events?.onAdResumed,
|
|
2227
|
+
onAdProgress: events?.onAdProgress,
|
|
2228
|
+
onAllAdsCompleted: events?.onAllAdsCompleted
|
|
2229
|
+
});
|
|
2230
|
+
const initializeSystem73 = useCallback9((playerConfig) => {
|
|
2231
|
+
if (!system73Config?.apiKey || !window.S73ShakaPlayerWrapper) {
|
|
2232
|
+
return null;
|
|
1012
2233
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
2234
|
+
console.log("Initializing System73 SDK...");
|
|
2235
|
+
try {
|
|
2236
|
+
const s73Config = {
|
|
2237
|
+
apiKey: system73Config.apiKey,
|
|
2238
|
+
contentSteeringEndpoint: system73Config.contentSteeringEndpoint,
|
|
2239
|
+
channelId: system73Config.channelId
|
|
2240
|
+
};
|
|
2241
|
+
const wrapper = window.S73ShakaPlayerWrapper(s73Config, { shaka: shaka3 });
|
|
2242
|
+
wrapper.wrapPlayerConfig(playerConfig);
|
|
2243
|
+
console.log("System73 SDK initialized with config:", s73Config);
|
|
2244
|
+
return wrapper;
|
|
2245
|
+
} catch (error) {
|
|
2246
|
+
console.error("Error initializing System73 SDK:", error);
|
|
2247
|
+
return null;
|
|
2248
|
+
}
|
|
2249
|
+
}, [system73Config]);
|
|
2250
|
+
const initializeAds = useCallback9(async () => {
|
|
2251
|
+
if (!imaConfig?.adTagUrl || !playerRef.current || !videoRef.current || !uiRef.current) {
|
|
2252
|
+
return;
|
|
2253
|
+
}
|
|
2254
|
+
if (!window.google?.ima) {
|
|
2255
|
+
console.error("Google IMA SDK not available when trying to initialize ads");
|
|
1016
2256
|
return;
|
|
1017
2257
|
}
|
|
1018
2258
|
try {
|
|
1019
|
-
|
|
1020
|
-
|
|
2259
|
+
const player = playerRef.current;
|
|
2260
|
+
const video = videoRef.current;
|
|
2261
|
+
const ui = uiRef.current;
|
|
2262
|
+
const controls2 = ui.getControls();
|
|
2263
|
+
const container = controls2.getClientSideAdContainer();
|
|
2264
|
+
const adManager = player.getAdManager();
|
|
2265
|
+
if (!adManager) {
|
|
2266
|
+
console.error("Ad manager not available");
|
|
2267
|
+
return;
|
|
1021
2268
|
}
|
|
2269
|
+
const google = window.google;
|
|
2270
|
+
let adsRenderingSettings = null;
|
|
2271
|
+
if (imaConfig.adsRenderingSettings) {
|
|
2272
|
+
adsRenderingSettings = imaConfig.adsRenderingSettings;
|
|
2273
|
+
} else if (autoPlay) {
|
|
2274
|
+
adsRenderingSettings = new google.ima.AdsRenderingSettings();
|
|
2275
|
+
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
|
|
2276
|
+
}
|
|
2277
|
+
adManager.initClientSide(container, video, adsRenderingSettings);
|
|
2278
|
+
const adsRequest = new google.ima.AdsRequest();
|
|
2279
|
+
adsRequest.adTagUrl = imaConfig.adTagUrl;
|
|
2280
|
+
adManager.requestClientSideAds(adsRequest);
|
|
2281
|
+
setupAdEventListeners();
|
|
2282
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
2283
|
+
await loadManifest();
|
|
1022
2284
|
} catch (error) {
|
|
1023
|
-
console.
|
|
2285
|
+
console.error("Error initializing ads:", error);
|
|
1024
2286
|
}
|
|
1025
|
-
};
|
|
2287
|
+
}, [imaConfig, autoPlay, setupAdEventListeners, loadManifest]);
|
|
2288
|
+
useEffect4(() => {
|
|
2289
|
+
const loadRequiredScripts = async () => {
|
|
2290
|
+
try {
|
|
2291
|
+
const scriptLoaders = getRequiredScriptLoaders(!!imaConfig?.adTagUrl, !!system73Config?.apiKey);
|
|
2292
|
+
await loadScripts(scriptLoaders);
|
|
2293
|
+
const globalsToWait = [];
|
|
2294
|
+
if (imaConfig?.adTagUrl) {
|
|
2295
|
+
globalsToWait.push("google");
|
|
2296
|
+
}
|
|
2297
|
+
if (system73Config?.apiKey) {
|
|
2298
|
+
globalsToWait.push("S73ShakaPlayerWrapper");
|
|
2299
|
+
}
|
|
2300
|
+
if (globalsToWait.length > 0) {
|
|
2301
|
+
await waitForGlobals(globalsToWait);
|
|
2302
|
+
}
|
|
2303
|
+
setIsScriptsLoaded(true);
|
|
2304
|
+
} catch (error) {
|
|
2305
|
+
console.error("Error loading required scripts:", error);
|
|
2306
|
+
setIsScriptsLoaded(true);
|
|
2307
|
+
}
|
|
2308
|
+
};
|
|
2309
|
+
loadRequiredScripts();
|
|
2310
|
+
}, [imaConfig?.adTagUrl, system73Config?.apiKey]);
|
|
2311
|
+
useEffect4(() => {
|
|
2312
|
+
const onPageShow = (e) => {
|
|
2313
|
+
if (e && e.persisted) {
|
|
2314
|
+
setBfResetKey((k) => k + 1);
|
|
2315
|
+
}
|
|
2316
|
+
};
|
|
2317
|
+
window.addEventListener("pageshow", onPageShow);
|
|
2318
|
+
return () => window.removeEventListener("pageshow", onPageShow);
|
|
2319
|
+
}, []);
|
|
1026
2320
|
useEffect4(() => {
|
|
1027
2321
|
const video = videoRef.current;
|
|
1028
|
-
if (!video) return;
|
|
2322
|
+
if (!video || !isScriptsLoaded) return;
|
|
1029
2323
|
const initialize = async () => {
|
|
1030
2324
|
try {
|
|
2325
|
+
console.log("\u{1F680} [Player] Starting initialization...");
|
|
2326
|
+
setIsInitialLoading(true);
|
|
2327
|
+
let system73Wrapper = null;
|
|
2328
|
+
if (system73Config?.apiKey && window.S73ShakaPlayerWrapper) {
|
|
2329
|
+
console.log("\u{1F4E6} [System73] Step 1: Initializing System73 wrapper with config");
|
|
2330
|
+
const playerConfig = { ...shakaConfig };
|
|
2331
|
+
system73Wrapper = initializeSystem73(playerConfig);
|
|
2332
|
+
if (system73Wrapper) {
|
|
2333
|
+
shakaConfig = playerConfig;
|
|
2334
|
+
console.log("\u2705 [System73] Step 1 complete: Wrapper created and config modified");
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
console.log("\u{1F3AC} [Shaka] Step 2: Initializing Shaka Player (auto-load:", !system73Config?.apiKey && !imaConfig?.adTagUrl, ")");
|
|
1031
2338
|
await initializePlayer(video);
|
|
2339
|
+
console.log("\u2705 [Shaka] Step 2 complete: Player initialized");
|
|
2340
|
+
if (system73Wrapper && playerRef.current) {
|
|
2341
|
+
console.log("\u{1F517} [System73] Step 3: Wrapping Shaka player with System73");
|
|
2342
|
+
system73Wrapper.wrapPlayer(playerRef.current);
|
|
2343
|
+
console.log("\u2705 [System73] Step 3 complete: Player wrapped");
|
|
2344
|
+
if (!imaConfig?.adTagUrl) {
|
|
2345
|
+
console.log("\u{1F4FA} [System73] Step 4: Loading manifest");
|
|
2346
|
+
await loadManifest();
|
|
2347
|
+
console.log("\u2705 [System73] Step 4 complete: Manifest loaded");
|
|
2348
|
+
} else {
|
|
2349
|
+
console.log("\u23ED\uFE0F [System73] Skipping manifest load - ads will handle it");
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
console.log("\u{1F4CB} [Player] Setting up event listeners and quality tracking");
|
|
1032
2353
|
setupEventListeners();
|
|
1033
2354
|
const cleanupQuality = setupQualityTracking();
|
|
1034
2355
|
configureQuality();
|
|
2356
|
+
console.log("\u{1F3A8} [UI] Initializing Shaka UI");
|
|
1035
2357
|
await initializeUI();
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
2358
|
+
console.log("\u2705 [UI] UI initialized");
|
|
2359
|
+
if (imaConfig?.adTagUrl && window.google?.ima) {
|
|
2360
|
+
console.log("\u{1F4E2} [Ads] Initializing ads (will load manifest after VAST fetch)");
|
|
2361
|
+
await initializeAds();
|
|
2362
|
+
console.log("\u2705 [Ads] Ads initialized and manifest loaded");
|
|
2363
|
+
}
|
|
2364
|
+
console.log("\u2728 [Player] Initialization complete!");
|
|
1039
2365
|
} catch (error) {
|
|
1040
|
-
console.error("Error during
|
|
2366
|
+
console.error("\u274C [Player] Error during initialization:", error);
|
|
1041
2367
|
handleMuxError(error);
|
|
1042
2368
|
}
|
|
1043
2369
|
};
|
|
1044
2370
|
initialize();
|
|
1045
2371
|
return () => {
|
|
1046
2372
|
cleanupEventListeners();
|
|
2373
|
+
cleanupAdEventListeners();
|
|
1047
2374
|
destroyUI();
|
|
1048
2375
|
destroyMux();
|
|
1049
2376
|
destroyPlayer();
|
|
1050
2377
|
};
|
|
1051
|
-
}, [
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
2378
|
+
}, [managedMode ? hasPlaylist : src, isScriptsLoaded, bfResetKey, managedMode]);
|
|
2379
|
+
useEffect4(() => {
|
|
2380
|
+
const video = videoRef.current;
|
|
2381
|
+
if (!video) return;
|
|
2382
|
+
const onLoadStart = () => {
|
|
2383
|
+
setIsInitialLoading(true);
|
|
2384
|
+
};
|
|
2385
|
+
const onCanPlay = () => {
|
|
2386
|
+
setIsInitialLoading(false);
|
|
2387
|
+
};
|
|
2388
|
+
const onPlaying = () => {
|
|
2389
|
+
setIsInitialLoading(false);
|
|
2390
|
+
};
|
|
2391
|
+
video.addEventListener("loadstart", onLoadStart);
|
|
2392
|
+
video.addEventListener("canplay", onCanPlay);
|
|
2393
|
+
video.addEventListener("playing", onPlaying);
|
|
2394
|
+
return () => {
|
|
2395
|
+
video.removeEventListener("loadstart", onLoadStart);
|
|
2396
|
+
video.removeEventListener("canplay", onCanPlay);
|
|
2397
|
+
video.removeEventListener("playing", onPlaying);
|
|
2398
|
+
};
|
|
2399
|
+
}, []);
|
|
1066
2400
|
useEffect4(() => {
|
|
1067
2401
|
const video = videoRef.current;
|
|
1068
2402
|
if (!video) return;
|
|
1069
2403
|
video.autoplay = autoPlay;
|
|
1070
2404
|
video.loop = loop;
|
|
1071
|
-
video.muted = muted;
|
|
1072
2405
|
video.controls = false;
|
|
1073
2406
|
if (poster) video.poster = poster;
|
|
1074
|
-
}, [autoPlay, loop, muted, poster]);
|
|
2407
|
+
}, [autoPlay, loop, muted, poster, imaConfig?.adTagUrl]);
|
|
2408
|
+
useEffect4(() => {
|
|
2409
|
+
const video = videoRef.current;
|
|
2410
|
+
if (!video) return;
|
|
2411
|
+
video.controls = false;
|
|
2412
|
+
video.setAttribute("controls", "false");
|
|
2413
|
+
video.removeAttribute("controls");
|
|
2414
|
+
const observer = new MutationObserver((mutations) => {
|
|
2415
|
+
mutations.forEach((mutation) => {
|
|
2416
|
+
if (mutation.type === "attributes" && mutation.attributeName === "controls") {
|
|
2417
|
+
if (video.hasAttribute("controls")) {
|
|
2418
|
+
video.removeAttribute("controls");
|
|
2419
|
+
video.controls = false;
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
});
|
|
2423
|
+
});
|
|
2424
|
+
observer.observe(video, {
|
|
2425
|
+
attributes: true,
|
|
2426
|
+
attributeFilter: ["controls"]
|
|
2427
|
+
});
|
|
2428
|
+
return () => {
|
|
2429
|
+
observer.disconnect();
|
|
2430
|
+
};
|
|
2431
|
+
}, []);
|
|
1075
2432
|
useImperativeHandle(ref, () => ({
|
|
1076
2433
|
...videoRef.current,
|
|
1077
2434
|
// Custom methods for quality control
|
|
@@ -1082,27 +2439,30 @@ var Player = forwardRef(
|
|
|
1082
2439
|
skipForward,
|
|
1083
2440
|
// Mux methods
|
|
1084
2441
|
updateMuxData,
|
|
2442
|
+
// Live status methods
|
|
2443
|
+
getLiveStatus,
|
|
2444
|
+
seekToLiveEdge,
|
|
1085
2445
|
// Access to underlying instances
|
|
1086
2446
|
getPlayer: () => playerRef.current,
|
|
1087
2447
|
getMuxMonitor: () => null
|
|
1088
|
-
}), [getAvailableQualities, setQuality, skipBack, skipForward, updateMuxData]);
|
|
2448
|
+
}), [getAvailableQualities, setQuality, skipBack, skipForward, updateMuxData, getLiveStatus, seekToLiveEdge]);
|
|
1089
2449
|
const isResponsive = !width && !height;
|
|
1090
|
-
const containerClasses = twMerge2(containerClassName, "motto-video-container");
|
|
2450
|
+
const containerClasses = twMerge2(containerClassName, "motto-video-container relative bg-[#111111] ");
|
|
1091
2451
|
const containerStyle = isResponsive ? {
|
|
1092
2452
|
aspectRatio: aspectRatio.toString()
|
|
1093
2453
|
} : { width, height };
|
|
1094
|
-
const videoClasses = isResponsive ? "motto-video-responsive" : "w-full h-full ";
|
|
2454
|
+
const videoClasses = isResponsive ? "motto-video-responsive w-full" : "w-full h-full ";
|
|
1095
2455
|
const videoStyle = isResponsive ? {} : { width, height };
|
|
2456
|
+
const filteredVideoProps = { ...videoProps };
|
|
2457
|
+
delete filteredVideoProps.controls;
|
|
1096
2458
|
return /* @__PURE__ */ jsxs4(
|
|
1097
2459
|
"div",
|
|
1098
2460
|
{
|
|
1099
2461
|
ref: containerRef,
|
|
1100
2462
|
className: containerClasses,
|
|
1101
2463
|
style: containerStyle,
|
|
1102
|
-
"data-shaka-player-container": true,
|
|
1103
|
-
"data-shaka-player-cast-receiver-id": chromecastConfig?.receiverApplicationId,
|
|
1104
2464
|
children: [
|
|
1105
|
-
/* @__PURE__ */
|
|
2465
|
+
/* @__PURE__ */ jsx7(
|
|
1106
2466
|
"video",
|
|
1107
2467
|
{
|
|
1108
2468
|
ref: videoRef,
|
|
@@ -1111,17 +2471,11 @@ var Player = forwardRef(
|
|
|
1111
2471
|
height: isResponsive ? void 0 : height,
|
|
1112
2472
|
style: videoStyle,
|
|
1113
2473
|
controls: false,
|
|
1114
|
-
|
|
2474
|
+
playsInline: true,
|
|
2475
|
+
...filteredVideoProps
|
|
1115
2476
|
}
|
|
1116
2477
|
),
|
|
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
|
-
)
|
|
2478
|
+
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
2479
|
]
|
|
1126
2480
|
}
|
|
1127
2481
|
);
|
|
@@ -1135,11 +2489,11 @@ import { twMerge as twMerge3 } from "tailwind-merge";
|
|
|
1135
2489
|
import { useQuery } from "@tanstack/react-query";
|
|
1136
2490
|
|
|
1137
2491
|
// src/api/video.ts
|
|
1138
|
-
var fetchVideoData = async (videoId, publicKey, mottoToken) => {
|
|
2492
|
+
var fetchVideoData = async (videoId, publicKey, mottoToken, adsEnabled = false, locale = "en") => {
|
|
1139
2493
|
const endpoint = "https://cda.mottostreaming.com/motto.cda.streaming.video.v1.VideoService/GetVideo";
|
|
1140
2494
|
const url = new URL(endpoint);
|
|
1141
2495
|
url.searchParams.set("encoding", "json");
|
|
1142
|
-
url.searchParams.set("message", JSON.stringify({ videoId }));
|
|
2496
|
+
url.searchParams.set("message", JSON.stringify({ videoId, enable_ads: adsEnabled, locale }));
|
|
1143
2497
|
const response = await fetch(url, {
|
|
1144
2498
|
method: "GET",
|
|
1145
2499
|
headers: {
|
|
@@ -1153,14 +2507,14 @@ var fetchVideoData = async (videoId, publicKey, mottoToken) => {
|
|
|
1153
2507
|
const data = await response.json();
|
|
1154
2508
|
return data.video;
|
|
1155
2509
|
};
|
|
1156
|
-
async function fetchVideosList(publicKey, videoIds, mottoToken, skip = 0, limit = 0) {
|
|
2510
|
+
async function fetchVideosList(publicKey, videoIds, mottoToken, skip = 0, limit = 0, adsEnabled = true, locale = "en") {
|
|
1157
2511
|
if (!videoIds || videoIds.length === 0) {
|
|
1158
2512
|
return [];
|
|
1159
2513
|
}
|
|
1160
2514
|
const endpoint = "https://cda.mottostreaming.com/motto.cda.streaming.video.v1.VideoService/BatchGetVideos";
|
|
1161
2515
|
const url = new URL(endpoint);
|
|
1162
2516
|
url.searchParams.set("encoding", "json");
|
|
1163
|
-
url.searchParams.set("message", JSON.stringify({ videoIds }));
|
|
2517
|
+
url.searchParams.set("message", JSON.stringify({ videoIds, enable_ads: adsEnabled, locale }));
|
|
1164
2518
|
const response = await fetch(url.toString(), {
|
|
1165
2519
|
method: "GET",
|
|
1166
2520
|
headers: {
|
|
@@ -1271,7 +2625,7 @@ var getErrorType = (error, video) => {
|
|
|
1271
2625
|
};
|
|
1272
2626
|
|
|
1273
2627
|
// src/messages/useMessages.tsx
|
|
1274
|
-
import { useState as
|
|
2628
|
+
import { useState as useState4, useEffect as useEffect5 } from "react";
|
|
1275
2629
|
|
|
1276
2630
|
// src/messages/en.json
|
|
1277
2631
|
var en_default = {
|
|
@@ -1573,8 +2927,8 @@ var getBrowserLanguage = () => {
|
|
|
1573
2927
|
return availableLanguages[language] ? language : "en";
|
|
1574
2928
|
};
|
|
1575
2929
|
var useMessages = (locale) => {
|
|
1576
|
-
const [language, setLanguage] =
|
|
1577
|
-
const [translations, setTranslations] =
|
|
2930
|
+
const [language, setLanguage] = useState4("en");
|
|
2931
|
+
const [translations, setTranslations] = useState4(availableLanguages.en);
|
|
1578
2932
|
useEffect5(() => {
|
|
1579
2933
|
const lang = !!availableLanguages?.[locale] ? locale : getBrowserLanguage();
|
|
1580
2934
|
;
|
|
@@ -1601,11 +2955,10 @@ var useMessages = (locale) => {
|
|
|
1601
2955
|
var useMessages_default = useMessages;
|
|
1602
2956
|
|
|
1603
2957
|
// src/Video.tsx
|
|
1604
|
-
import { jsx as
|
|
2958
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1605
2959
|
var Video = ({
|
|
1606
2960
|
videoId,
|
|
1607
2961
|
publicKey,
|
|
1608
|
-
mottoToken,
|
|
1609
2962
|
videoData: providedVideoData,
|
|
1610
2963
|
refetchInterval = 0,
|
|
1611
2964
|
playerName,
|
|
@@ -1613,7 +2966,10 @@ var Video = ({
|
|
|
1613
2966
|
events,
|
|
1614
2967
|
children,
|
|
1615
2968
|
className,
|
|
2969
|
+
auth,
|
|
2970
|
+
settings,
|
|
1616
2971
|
queryOptions = {},
|
|
2972
|
+
adsEnabled = false,
|
|
1617
2973
|
...props
|
|
1618
2974
|
}) => {
|
|
1619
2975
|
const {
|
|
@@ -1622,8 +2978,8 @@ var Video = ({
|
|
|
1622
2978
|
error,
|
|
1623
2979
|
refetch
|
|
1624
2980
|
} = useQuery({
|
|
1625
|
-
queryKey: ["video", videoId, publicKey, mottoToken],
|
|
1626
|
-
queryFn: () => fetchVideoData(videoId, publicKey, mottoToken),
|
|
2981
|
+
queryKey: ["video", videoId, publicKey, auth?.mottoToken, adsEnabled, locale],
|
|
2982
|
+
queryFn: () => fetchVideoData(videoId, publicKey, auth?.mottoToken, adsEnabled, locale),
|
|
1627
2983
|
enabled: !!videoId && !!publicKey && !providedVideoData,
|
|
1628
2984
|
refetchInterval: refetchInterval > 0 ? refetchInterval : false,
|
|
1629
2985
|
staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
|
|
@@ -1636,16 +2992,17 @@ var Video = ({
|
|
|
1636
2992
|
const video = providedVideoData || data;
|
|
1637
2993
|
const { t } = useMessages_default(locale);
|
|
1638
2994
|
const activePlaylist = findHLSPlaylist(video);
|
|
1639
|
-
const
|
|
2995
|
+
const activePlaylistUrl = activePlaylist?.url ?? activePlaylist?.drm?.widevine?.playlistUrl ?? activePlaylist?.drm?.playready?.playlistUrl ?? activePlaylist?.drm?.fairplay?.playlistUrl;
|
|
2996
|
+
const activePlaylistHasUrl = !!activePlaylistUrl;
|
|
1640
2997
|
useEffect6(() => {
|
|
1641
2998
|
if (events?.onVideoData && video) {
|
|
1642
2999
|
events.onVideoData(video);
|
|
1643
3000
|
}
|
|
1644
3001
|
}, [video, events]);
|
|
1645
3002
|
if (isLoading || !providedVideoData && !video) {
|
|
1646
|
-
return /* @__PURE__ */
|
|
3003
|
+
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
3004
|
}
|
|
1648
|
-
if (!isLoading && video && !
|
|
3005
|
+
if (!isLoading && video && !activePlaylistHasUrl && events?.onEmptyPlaylists) {
|
|
1649
3006
|
events.onEmptyPlaylists();
|
|
1650
3007
|
}
|
|
1651
3008
|
if (error || video?.error) {
|
|
@@ -1656,8 +3013,8 @@ var Video = ({
|
|
|
1656
3013
|
}
|
|
1657
3014
|
const title = t(errorKey) || t("DEFAULT_ERROR");
|
|
1658
3015
|
const description = t(`${errorKey}_DESCRIPTION`) || t("DEFAULT_ERROR_DESCRIPTION");
|
|
1659
|
-
return /* @__PURE__ */
|
|
1660
|
-
/* @__PURE__ */
|
|
3016
|
+
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: [
|
|
3017
|
+
/* @__PURE__ */ jsx8(
|
|
1661
3018
|
ErrorScreen,
|
|
1662
3019
|
{
|
|
1663
3020
|
title,
|
|
@@ -1667,31 +3024,35 @@ var Video = ({
|
|
|
1667
3024
|
children
|
|
1668
3025
|
] }) });
|
|
1669
3026
|
}
|
|
1670
|
-
if (!
|
|
1671
|
-
return /* @__PURE__ */
|
|
1672
|
-
/* @__PURE__ */
|
|
3027
|
+
if (!activePlaylist || !activePlaylistHasUrl) {
|
|
3028
|
+
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: [
|
|
3029
|
+
/* @__PURE__ */ jsx8(Title, { title: video?.name || "" }),
|
|
1673
3030
|
children
|
|
1674
3031
|
] }) });
|
|
1675
3032
|
}
|
|
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(
|
|
3033
|
+
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
3034
|
Player,
|
|
1679
3035
|
{
|
|
1680
3036
|
...props,
|
|
1681
|
-
src:
|
|
3037
|
+
src: activePlaylist,
|
|
3038
|
+
managedMode: true,
|
|
1682
3039
|
className: twMerge3("video-player-container", className),
|
|
1683
3040
|
events,
|
|
3041
|
+
locale,
|
|
1684
3042
|
containerClassName: "w-full h-full",
|
|
3043
|
+
publicKey,
|
|
3044
|
+
auth,
|
|
3045
|
+
...adsEnabled && video?.ad?.adTagUrl ? { imaConfig: { adTagUrl: video?.ad?.adTagUrl } } : {},
|
|
1685
3046
|
children
|
|
1686
3047
|
}
|
|
1687
3048
|
) }) });
|
|
1688
3049
|
};
|
|
1689
3050
|
|
|
1690
3051
|
// src/Event.tsx
|
|
1691
|
-
import { useCallback as
|
|
3052
|
+
import { useCallback as useCallback10, useEffect as useEffect7, useState as useState5 } from "react";
|
|
1692
3053
|
import { twMerge as twMerge4 } from "tailwind-merge";
|
|
1693
3054
|
import { useQuery as useQuery2 } from "@tanstack/react-query";
|
|
1694
|
-
import { Fragment, jsx as
|
|
3055
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1695
3056
|
var Event = ({
|
|
1696
3057
|
publicKey,
|
|
1697
3058
|
eventId,
|
|
@@ -1704,6 +3065,7 @@ var Event = ({
|
|
|
1704
3065
|
settings,
|
|
1705
3066
|
auth,
|
|
1706
3067
|
queryOptions = {},
|
|
3068
|
+
adsEnabled = false,
|
|
1707
3069
|
...props
|
|
1708
3070
|
}) => {
|
|
1709
3071
|
const {
|
|
@@ -1721,16 +3083,16 @@ var Event = ({
|
|
|
1721
3083
|
retry: queryOptions.retry ?? 3,
|
|
1722
3084
|
retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
|
|
1723
3085
|
});
|
|
1724
|
-
const [activePlaylist, setActivePlaylist] =
|
|
1725
|
-
const [activeVideoId, setActiveVideoId] =
|
|
3086
|
+
const [activePlaylist, setActivePlaylist] = useState5();
|
|
3087
|
+
const [activeVideoId, setActiveVideoId] = useState5();
|
|
1726
3088
|
const videoIds = eventData?.videoIds ?? [];
|
|
1727
3089
|
const {
|
|
1728
3090
|
data: videosData,
|
|
1729
3091
|
isLoading: videosIsLoading,
|
|
1730
3092
|
error: videosError
|
|
1731
3093
|
} = useQuery2({
|
|
1732
|
-
queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken],
|
|
1733
|
-
queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0),
|
|
3094
|
+
queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken, adsEnabled, locale],
|
|
3095
|
+
queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0, adsEnabled, locale),
|
|
1734
3096
|
enabled: !!publicKey && videoIds.length > 0,
|
|
1735
3097
|
refetchInterval: activePlaylist === null ? 3e4 : false,
|
|
1736
3098
|
staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
|
|
@@ -1738,7 +3100,7 @@ var Event = ({
|
|
|
1738
3100
|
retry: queryOptions.retry ?? 3,
|
|
1739
3101
|
retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
|
|
1740
3102
|
});
|
|
1741
|
-
const [loadingApisState, setLoadingApisState] =
|
|
3103
|
+
const [loadingApisState, setLoadingApisState] = useState5(true);
|
|
1742
3104
|
useEffect7(() => {
|
|
1743
3105
|
if (videosData !== void 0) {
|
|
1744
3106
|
setLoadingApisState(false);
|
|
@@ -1748,9 +3110,11 @@ var Event = ({
|
|
|
1748
3110
|
if (videosWithPlaylists.length > 0) {
|
|
1749
3111
|
let hlsPlaylistFound = false;
|
|
1750
3112
|
for (const video of videosWithPlaylists) {
|
|
1751
|
-
const
|
|
1752
|
-
|
|
1753
|
-
|
|
3113
|
+
const activePlaylist2 = findHLSPlaylist(video);
|
|
3114
|
+
const activePlaylistUrl = activePlaylist2?.url ?? activePlaylist2?.drm?.widevine?.playlistUrl ?? activePlaylist2?.drm?.playready?.playlistUrl ?? activePlaylist2?.drm?.fairplay?.playlistUrl;
|
|
3115
|
+
const activePlaylistHasUrl = !!activePlaylistUrl;
|
|
3116
|
+
if (activePlaylist2 && activePlaylistHasUrl) {
|
|
3117
|
+
setActivePlaylist(activePlaylist2);
|
|
1754
3118
|
setActiveVideoId(video.id);
|
|
1755
3119
|
hlsPlaylistFound = true;
|
|
1756
3120
|
break;
|
|
@@ -1784,12 +3148,17 @@ var Event = ({
|
|
|
1784
3148
|
}
|
|
1785
3149
|
}
|
|
1786
3150
|
}, [activeVideoId, videosData, events]);
|
|
1787
|
-
const [error, setError] =
|
|
1788
|
-
const [loadingPlaylist, setLoadingPlaylist] =
|
|
3151
|
+
const [error, setError] = useState5(null);
|
|
3152
|
+
const [loadingPlaylist, setLoadingPlaylist] = useState5(true);
|
|
1789
3153
|
const videosDataError = videosData?.some((video) => !!video.error);
|
|
1790
3154
|
useEffect7(() => {
|
|
1791
|
-
if (
|
|
1792
|
-
|
|
3155
|
+
if (isEventLoading || videosIsLoading || loadingApisState) {
|
|
3156
|
+
return;
|
|
3157
|
+
}
|
|
3158
|
+
const hasPlayablePlaylist = Boolean(activePlaylist);
|
|
3159
|
+
if (eventError || videosError || videosDataError && !hasPlayablePlaylist) {
|
|
3160
|
+
const firstVideoError = videosData?.find((video) => !!video.error)?.error;
|
|
3161
|
+
const errorObj = eventError || videosError || firstVideoError && new Error(firstVideoError) || new Error("default");
|
|
1793
3162
|
setError(errorObj);
|
|
1794
3163
|
if (events?.onError) {
|
|
1795
3164
|
events.onError(errorObj);
|
|
@@ -1797,7 +3166,17 @@ var Event = ({
|
|
|
1797
3166
|
} else {
|
|
1798
3167
|
setError(null);
|
|
1799
3168
|
}
|
|
1800
|
-
}, [
|
|
3169
|
+
}, [
|
|
3170
|
+
eventError,
|
|
3171
|
+
videosError,
|
|
3172
|
+
videosDataError,
|
|
3173
|
+
videosData,
|
|
3174
|
+
events,
|
|
3175
|
+
activePlaylist,
|
|
3176
|
+
isEventLoading,
|
|
3177
|
+
videosIsLoading,
|
|
3178
|
+
loadingApisState
|
|
3179
|
+
]);
|
|
1801
3180
|
useEffect7(() => {
|
|
1802
3181
|
const eventLoadedWithNoVideos = !isEventLoading && eventData && eventData.videoIds && (!eventData.videoIds || eventData?.videoIds?.length === 0) && !loadingApisState;
|
|
1803
3182
|
const allApisLoadedWithPotentialVideos = !isEventLoading && !videosIsLoading && eventData && !loadingApisState;
|
|
@@ -1808,7 +3187,7 @@ var Event = ({
|
|
|
1808
3187
|
if (error) {
|
|
1809
3188
|
const title = t(error.message)?.length ? t(error.message) : t("DEFAULT_ERROR");
|
|
1810
3189
|
const description = t(`${error.message}_DESCRIPTION`)?.length ? t(`${error.message}_DESCRIPTION`) : t("DEFAULT_ERROR_DESCRIPTION");
|
|
1811
|
-
return /* @__PURE__ */
|
|
3190
|
+
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
3191
|
ErrorScreen,
|
|
1813
3192
|
{
|
|
1814
3193
|
title,
|
|
@@ -1820,22 +3199,28 @@ var Event = ({
|
|
|
1820
3199
|
events.onEmptyPlaylists();
|
|
1821
3200
|
}
|
|
1822
3201
|
if (loadingPlaylist) {
|
|
1823
|
-
return /* @__PURE__ */
|
|
3202
|
+
return /* @__PURE__ */ jsx9("div", { className: twMerge4("", className), children: /* @__PURE__ */ jsx9("div", { className: "relative w-full aspect-video bg-[#151515]", children: /* @__PURE__ */ jsx9(Loading, {}) }) });
|
|
1824
3203
|
}
|
|
1825
3204
|
if (activePlaylist && activeVideoId && videosData) {
|
|
1826
3205
|
const activeVideo = videosData.find((video) => video.id === activeVideoId);
|
|
1827
|
-
|
|
1828
|
-
|
|
3206
|
+
console.log("activeVideo?.ad?.adTagUrl", activeVideo?.ad?.adTagUrl);
|
|
3207
|
+
return /* @__PURE__ */ jsxs6("div", { className: twMerge4("", className), children: [
|
|
3208
|
+
/* @__PURE__ */ jsx9("div", { className: "relative w-full h-full", children: /* @__PURE__ */ jsx9(
|
|
1829
3209
|
Player,
|
|
1830
3210
|
{
|
|
1831
3211
|
...props,
|
|
1832
3212
|
src: activePlaylist,
|
|
1833
|
-
|
|
3213
|
+
managedMode: true,
|
|
3214
|
+
className: twMerge4(className, "peer aspect-video"),
|
|
1834
3215
|
events,
|
|
1835
|
-
|
|
3216
|
+
locale,
|
|
3217
|
+
containerClassName: "w-full h-full",
|
|
3218
|
+
publicKey,
|
|
3219
|
+
auth,
|
|
3220
|
+
...adsEnabled && activeVideo ? { imaConfig: { adTagUrl: activeVideo?.ad?.adTagUrl } } : {}
|
|
1836
3221
|
}
|
|
1837
|
-
),
|
|
1838
|
-
!hideTitle && eventData && /* @__PURE__ */
|
|
3222
|
+
) }),
|
|
3223
|
+
!hideTitle && eventData && /* @__PURE__ */ jsx9(
|
|
1839
3224
|
TitleAndDescription,
|
|
1840
3225
|
{
|
|
1841
3226
|
title: eventData.title,
|
|
@@ -1844,10 +3229,10 @@ var Event = ({
|
|
|
1844
3229
|
locale
|
|
1845
3230
|
}
|
|
1846
3231
|
)
|
|
1847
|
-
] })
|
|
3232
|
+
] });
|
|
1848
3233
|
}
|
|
1849
3234
|
if (eventData) {
|
|
1850
|
-
return /* @__PURE__ */
|
|
3235
|
+
return /* @__PURE__ */ jsx9("div", { className: twMerge4("", className), children: /* @__PURE__ */ jsx9("div", { className: "relative w-full h-full", children: /* @__PURE__ */ jsx9(
|
|
1851
3236
|
PreEvent,
|
|
1852
3237
|
{
|
|
1853
3238
|
event: eventData,
|
|
@@ -1869,7 +3254,7 @@ function PreEvent({
|
|
|
1869
3254
|
}) {
|
|
1870
3255
|
const date = new Date(event.startTime);
|
|
1871
3256
|
const now = /* @__PURE__ */ new Date();
|
|
1872
|
-
const [remainingTime, setRemainingTime] =
|
|
3257
|
+
const [remainingTime, setRemainingTime] = useState5(
|
|
1873
3258
|
date.getTime() - now.getTime()
|
|
1874
3259
|
);
|
|
1875
3260
|
const shouldBeStarted = remainingTime < 0;
|
|
@@ -1884,29 +3269,28 @@ function PreEvent({
|
|
|
1884
3269
|
}, 1e3);
|
|
1885
3270
|
return () => clearInterval(interval);
|
|
1886
3271
|
}, [date, remainingTime]);
|
|
1887
|
-
const renderCountdown =
|
|
3272
|
+
const renderCountdown = useCallback10(() => {
|
|
1888
3273
|
if (shouldBeStarted) {
|
|
1889
|
-
return /* @__PURE__ */
|
|
3274
|
+
return /* @__PURE__ */ jsx9("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
|
|
1890
3275
|
}
|
|
1891
3276
|
const seconds = Math.floor(remainingTime / 1e3) % 60;
|
|
1892
3277
|
const minutes = Math.floor(remainingTime / 1e3 / 60) % 60;
|
|
1893
3278
|
const hours = Math.floor(remainingTime / 1e3 / 60 / 60) % 24;
|
|
1894
3279
|
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: [
|
|
3280
|
+
return /* @__PURE__ */ jsxs6("div", { className: "grid grid-flow-col gap-1 md:gap-5 text-center auto-cols-max", children: [
|
|
1896
3281
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
1897
|
-
/* @__PURE__ */
|
|
3282
|
+
/* @__PURE__ */ jsx9("span", { className: "font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx9(
|
|
1898
3283
|
"span",
|
|
1899
3284
|
{
|
|
1900
|
-
style: { "--value": days },
|
|
1901
3285
|
"aria-live": "polite",
|
|
1902
3286
|
"aria-label": days.toString(),
|
|
1903
|
-
children: days
|
|
3287
|
+
children: days.toString()
|
|
1904
3288
|
}
|
|
1905
3289
|
) }),
|
|
1906
|
-
/* @__PURE__ */
|
|
3290
|
+
/* @__PURE__ */ jsx9("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("DAYS") })
|
|
1907
3291
|
] }),
|
|
1908
3292
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
1909
|
-
/* @__PURE__ */
|
|
3293
|
+
/* @__PURE__ */ jsx9("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx9(
|
|
1910
3294
|
"span",
|
|
1911
3295
|
{
|
|
1912
3296
|
style: { "--value": hours },
|
|
@@ -1915,10 +3299,10 @@ function PreEvent({
|
|
|
1915
3299
|
children: hours?.toString()?.padStart(2, "0")
|
|
1916
3300
|
}
|
|
1917
3301
|
) }),
|
|
1918
|
-
/* @__PURE__ */
|
|
3302
|
+
/* @__PURE__ */ jsx9("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("HOURS") })
|
|
1919
3303
|
] }),
|
|
1920
3304
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
1921
|
-
/* @__PURE__ */
|
|
3305
|
+
/* @__PURE__ */ jsx9("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx9(
|
|
1922
3306
|
"span",
|
|
1923
3307
|
{
|
|
1924
3308
|
style: { "--value": minutes },
|
|
@@ -1927,10 +3311,10 @@ function PreEvent({
|
|
|
1927
3311
|
children: minutes?.toString()?.padStart(2, "0")
|
|
1928
3312
|
}
|
|
1929
3313
|
) }),
|
|
1930
|
-
/* @__PURE__ */
|
|
3314
|
+
/* @__PURE__ */ jsx9("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("MINUTES") })
|
|
1931
3315
|
] }),
|
|
1932
3316
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
1933
|
-
/* @__PURE__ */
|
|
3317
|
+
/* @__PURE__ */ jsx9("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx9(
|
|
1934
3318
|
"span",
|
|
1935
3319
|
{
|
|
1936
3320
|
style: { "--value": seconds },
|
|
@@ -1939,12 +3323,12 @@ function PreEvent({
|
|
|
1939
3323
|
children: seconds?.toString()?.padStart(2, "0")
|
|
1940
3324
|
}
|
|
1941
3325
|
) }),
|
|
1942
|
-
/* @__PURE__ */
|
|
3326
|
+
/* @__PURE__ */ jsx9("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("SECONDS") })
|
|
1943
3327
|
] })
|
|
1944
3328
|
] });
|
|
1945
3329
|
}, [remainingTime, shouldBeStarted, t]);
|
|
1946
|
-
return /* @__PURE__ */
|
|
1947
|
-
/* @__PURE__ */
|
|
3330
|
+
return /* @__PURE__ */ jsx9(Fragment, { children: event?.posterUrl ? /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
3331
|
+
/* @__PURE__ */ jsx9(
|
|
1948
3332
|
"div",
|
|
1949
3333
|
{
|
|
1950
3334
|
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 +3337,10 @@ function PreEvent({
|
|
|
1953
3337
|
backgroundRepeat: "no-repeat",
|
|
1954
3338
|
backgroundSize: "cover"
|
|
1955
3339
|
},
|
|
1956
|
-
children: /* @__PURE__ */
|
|
3340
|
+
children: /* @__PURE__ */ jsx9("div", { className: "relative z-10", children: renderCountdown() })
|
|
1957
3341
|
}
|
|
1958
3342
|
),
|
|
1959
|
-
!hideTitle && /* @__PURE__ */
|
|
3343
|
+
!hideTitle && /* @__PURE__ */ jsx9(
|
|
1960
3344
|
TitleAndDescription,
|
|
1961
3345
|
{
|
|
1962
3346
|
title: event.title,
|
|
@@ -1966,17 +3350,17 @@ function PreEvent({
|
|
|
1966
3350
|
}
|
|
1967
3351
|
)
|
|
1968
3352
|
] }) : /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
1969
|
-
/* @__PURE__ */
|
|
3353
|
+
/* @__PURE__ */ jsx9(
|
|
1970
3354
|
"div",
|
|
1971
3355
|
{
|
|
1972
3356
|
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
3357
|
style: {
|
|
1974
3358
|
backgroundImage: backgroundImageUrl ? `url(${backgroundImageUrl})` : ""
|
|
1975
3359
|
},
|
|
1976
|
-
children: /* @__PURE__ */
|
|
3360
|
+
children: /* @__PURE__ */ jsx9("div", { className: "relative z-10", children: renderCountdown() })
|
|
1977
3361
|
}
|
|
1978
3362
|
),
|
|
1979
|
-
!hideTitle && /* @__PURE__ */
|
|
3363
|
+
!hideTitle && /* @__PURE__ */ jsx9(
|
|
1980
3364
|
TitleAndDescription,
|
|
1981
3365
|
{
|
|
1982
3366
|
title: event.title,
|
|
@@ -1995,8 +3379,8 @@ var TitleAndDescription = ({
|
|
|
1995
3379
|
className
|
|
1996
3380
|
}) => {
|
|
1997
3381
|
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-
|
|
3382
|
+
/* @__PURE__ */ jsx9("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
|
|
3383
|
+
startTime ? /* @__PURE__ */ jsxs6("div", { className: "text-xs md:text-base text-base-content/70 m-event-start-time", children: [
|
|
2000
3384
|
new Date(startTime || "").toLocaleDateString(locale || "default", {
|
|
2001
3385
|
month: "long",
|
|
2002
3386
|
year: "numeric",
|
|
@@ -2009,15 +3393,15 @@ var TitleAndDescription = ({
|
|
|
2009
3393
|
minute: "2-digit"
|
|
2010
3394
|
})
|
|
2011
3395
|
] }) : null,
|
|
2012
|
-
description && /* @__PURE__ */
|
|
3396
|
+
description && /* @__PURE__ */ jsx9("div", { className: "text-xs md:text-xs text-base-content/60 uppercase", children: description })
|
|
2013
3397
|
] });
|
|
2014
3398
|
};
|
|
2015
3399
|
|
|
2016
3400
|
// src/CreativeWork.tsx
|
|
2017
|
-
import { useEffect as useEffect8, useState as
|
|
3401
|
+
import { useEffect as useEffect8, useState as useState6 } from "react";
|
|
2018
3402
|
import { twMerge as twMerge5 } from "tailwind-merge";
|
|
2019
3403
|
import { useQuery as useQuery3 } from "@tanstack/react-query";
|
|
2020
|
-
import { Fragment as Fragment2, jsx as
|
|
3404
|
+
import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2021
3405
|
var CreativeWork = ({
|
|
2022
3406
|
publicKey,
|
|
2023
3407
|
creativeWorkId,
|
|
@@ -2030,6 +3414,7 @@ var CreativeWork = ({
|
|
|
2030
3414
|
settings,
|
|
2031
3415
|
auth,
|
|
2032
3416
|
queryOptions = {},
|
|
3417
|
+
adsEnabled = false,
|
|
2033
3418
|
...props
|
|
2034
3419
|
}) => {
|
|
2035
3420
|
const {
|
|
@@ -2047,17 +3432,17 @@ var CreativeWork = ({
|
|
|
2047
3432
|
retry: queryOptions.retry ?? 3,
|
|
2048
3433
|
retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
|
|
2049
3434
|
});
|
|
2050
|
-
const [activePlaylist, setActivePlaylist] =
|
|
2051
|
-
const [activeVideoId, setActiveVideoId] =
|
|
2052
|
-
const [showCountDown, setShowCountDown] =
|
|
3435
|
+
const [activePlaylist, setActivePlaylist] = useState6();
|
|
3436
|
+
const [activeVideoId, setActiveVideoId] = useState6();
|
|
3437
|
+
const [showCountDown, setShowCountDown] = useState6(false);
|
|
2053
3438
|
const videoIds = creativeWorkData?.videoIds ?? [];
|
|
2054
3439
|
const {
|
|
2055
3440
|
data: videosData,
|
|
2056
3441
|
isLoading: videosIsLoading,
|
|
2057
3442
|
error: videosError
|
|
2058
3443
|
} = useQuery3({
|
|
2059
|
-
queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken],
|
|
2060
|
-
queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0),
|
|
3444
|
+
queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken, adsEnabled, locale],
|
|
3445
|
+
queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0, adsEnabled, locale),
|
|
2061
3446
|
enabled: !!publicKey && videoIds.length > 0,
|
|
2062
3447
|
refetchInterval: activePlaylist === null ? 3e4 : false,
|
|
2063
3448
|
staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
|
|
@@ -2065,7 +3450,7 @@ var CreativeWork = ({
|
|
|
2065
3450
|
retry: queryOptions.retry ?? 3,
|
|
2066
3451
|
retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
|
|
2067
3452
|
});
|
|
2068
|
-
const [loadingApisState, setLoadingApisState] =
|
|
3453
|
+
const [loadingApisState, setLoadingApisState] = useState6(true);
|
|
2069
3454
|
useEffect8(() => {
|
|
2070
3455
|
if (videosData !== void 0) {
|
|
2071
3456
|
setLoadingApisState(false);
|
|
@@ -2075,9 +3460,11 @@ var CreativeWork = ({
|
|
|
2075
3460
|
if (videosWithPlaylists.length > 0) {
|
|
2076
3461
|
let hlsPlaylistFound = false;
|
|
2077
3462
|
for (const video of videosWithPlaylists) {
|
|
2078
|
-
const
|
|
2079
|
-
|
|
2080
|
-
|
|
3463
|
+
const activePlaylist2 = findHLSPlaylist(video);
|
|
3464
|
+
const activePlaylistUrl = activePlaylist2?.url ?? activePlaylist2?.drm?.widevine?.playlistUrl ?? activePlaylist2?.drm?.playready?.playlistUrl ?? activePlaylist2?.drm?.fairplay?.playlistUrl;
|
|
3465
|
+
const activePlaylistHasUrl = !!activePlaylistUrl;
|
|
3466
|
+
if (activePlaylist2 && activePlaylistHasUrl) {
|
|
3467
|
+
setActivePlaylist(activePlaylist2);
|
|
2081
3468
|
setActiveVideoId(video.id);
|
|
2082
3469
|
hlsPlaylistFound = true;
|
|
2083
3470
|
break;
|
|
@@ -2114,7 +3501,7 @@ var CreativeWork = ({
|
|
|
2114
3501
|
}
|
|
2115
3502
|
}
|
|
2116
3503
|
}, [activeVideoId, videosData, events]);
|
|
2117
|
-
const [error, setError] =
|
|
3504
|
+
const [error, setError] = useState6(null);
|
|
2118
3505
|
const videosDataError = videosData?.some((video) => !!video.error);
|
|
2119
3506
|
useEffect8(() => {
|
|
2120
3507
|
if (creativeWorkError || videosError || videosDataError) {
|
|
@@ -2130,7 +3517,7 @@ var CreativeWork = ({
|
|
|
2130
3517
|
if (error) {
|
|
2131
3518
|
const title = t(error.message)?.length ? t(error.message) : t("DEFAULT_ERROR");
|
|
2132
3519
|
const description = t(`${error.message}_DESCRIPTION`)?.length ? t(`${error.message}_DESCRIPTION`) : t("DEFAULT_ERROR_DESCRIPTION");
|
|
2133
|
-
return /* @__PURE__ */
|
|
3520
|
+
return /* @__PURE__ */ jsx10("div", { className: twMerge5("", className), children: /* @__PURE__ */ jsx10("div", { className: "relative w-full h-full", children: /* @__PURE__ */ jsx10(
|
|
2134
3521
|
ErrorScreen,
|
|
2135
3522
|
{
|
|
2136
3523
|
title,
|
|
@@ -2138,7 +3525,7 @@ var CreativeWork = ({
|
|
|
2138
3525
|
}
|
|
2139
3526
|
) }) });
|
|
2140
3527
|
}
|
|
2141
|
-
const [loadingPlaylist, setLoadingPlaylist] =
|
|
3528
|
+
const [loadingPlaylist, setLoadingPlaylist] = useState6(true);
|
|
2142
3529
|
useEffect8(() => {
|
|
2143
3530
|
const creativeWorkLoadedWithNoVideos = !isCreativeWorkLoading && creativeWorkData && creativeWorkData.videoIds && creativeWorkData.videoIds.length === 0;
|
|
2144
3531
|
const creativeWorkLoadedWithNoData = !isCreativeWorkLoading && creativeWorkData && !creativeWorkData.videoIds;
|
|
@@ -2160,10 +3547,10 @@ var CreativeWork = ({
|
|
|
2160
3547
|
events
|
|
2161
3548
|
]);
|
|
2162
3549
|
if (isCreativeWorkLoading || videosIsLoading || loadingApisState) {
|
|
2163
|
-
return /* @__PURE__ */
|
|
3550
|
+
return /* @__PURE__ */ jsx10("div", { className: twMerge5("", className), children: /* @__PURE__ */ jsx10("div", { className: "relative w-full aspect-video bg-[#151515]", children: /* @__PURE__ */ jsx10(Loading, {}) }) });
|
|
2164
3551
|
}
|
|
2165
3552
|
if (showCountDown && creativeWorkData) {
|
|
2166
|
-
return /* @__PURE__ */
|
|
3553
|
+
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
3554
|
PreCreativeWork,
|
|
2168
3555
|
{
|
|
2169
3556
|
creativeWork: creativeWorkData,
|
|
@@ -2176,20 +3563,25 @@ var CreativeWork = ({
|
|
|
2176
3563
|
}
|
|
2177
3564
|
if (activeVideoId && activePlaylist && !loadingPlaylist) {
|
|
2178
3565
|
const activeVideo = videosData?.find((video) => video.id === activeVideoId);
|
|
2179
|
-
return /* @__PURE__ */
|
|
2180
|
-
/* @__PURE__ */
|
|
3566
|
+
return /* @__PURE__ */ jsx10("div", { className: twMerge5("", className), children: /* @__PURE__ */ jsxs7("div", { className: "relative w-full h-full", children: [
|
|
3567
|
+
/* @__PURE__ */ jsx10(
|
|
2181
3568
|
Player,
|
|
2182
3569
|
{
|
|
2183
3570
|
...props,
|
|
2184
|
-
className: twMerge5(className, "peer"),
|
|
3571
|
+
className: twMerge5(className, "peer aspect-video"),
|
|
3572
|
+
managedMode: true,
|
|
2185
3573
|
events: {
|
|
2186
3574
|
...events
|
|
2187
3575
|
},
|
|
2188
3576
|
src: activePlaylist,
|
|
2189
|
-
|
|
3577
|
+
locale,
|
|
3578
|
+
containerClassName: "w-full h-full",
|
|
3579
|
+
publicKey,
|
|
3580
|
+
auth,
|
|
3581
|
+
...adsEnabled && activeVideo?.ad?.adTagUrl ? { imaConfig: { adTagUrl: activeVideo?.ad?.adTagUrl } } : {}
|
|
2190
3582
|
}
|
|
2191
3583
|
),
|
|
2192
|
-
!hideTitle && /* @__PURE__ */
|
|
3584
|
+
!hideTitle && /* @__PURE__ */ jsx10(
|
|
2193
3585
|
TitleAndDescription2,
|
|
2194
3586
|
{
|
|
2195
3587
|
title: creativeWorkData?.title || "",
|
|
@@ -2202,7 +3594,7 @@ var CreativeWork = ({
|
|
|
2202
3594
|
] }) });
|
|
2203
3595
|
}
|
|
2204
3596
|
if (loadingPlaylist) {
|
|
2205
|
-
return /* @__PURE__ */
|
|
3597
|
+
return /* @__PURE__ */ jsx10("div", { className: twMerge5("", className), children: /* @__PURE__ */ jsx10("div", { className: "relative w-full aspect-video bg-[#151515]", children: /* @__PURE__ */ jsx10(Loading, {}) }) });
|
|
2206
3598
|
}
|
|
2207
3599
|
return null;
|
|
2208
3600
|
};
|
|
@@ -2215,7 +3607,7 @@ function PreCreativeWork({
|
|
|
2215
3607
|
}) {
|
|
2216
3608
|
const date = new Date(creativeWork.releaseTime);
|
|
2217
3609
|
const now = /* @__PURE__ */ new Date();
|
|
2218
|
-
const [remainingTime, setRemainingTime] =
|
|
3610
|
+
const [remainingTime, setRemainingTime] = useState6(
|
|
2219
3611
|
date.getTime() - now.getTime()
|
|
2220
3612
|
);
|
|
2221
3613
|
const shouldBeStarted = remainingTime < 0;
|
|
@@ -2234,27 +3626,26 @@ function PreCreativeWork({
|
|
|
2234
3626
|
}, [date, remainingTime]);
|
|
2235
3627
|
const renderCountdown = () => {
|
|
2236
3628
|
if (shouldBeStarted) {
|
|
2237
|
-
return /* @__PURE__ */
|
|
3629
|
+
return /* @__PURE__ */ jsx10("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
|
|
2238
3630
|
}
|
|
2239
3631
|
const seconds = Math.floor(remainingTime / 1e3) % 60;
|
|
2240
3632
|
const minutes = Math.floor(remainingTime / 1e3 / 60) % 60;
|
|
2241
3633
|
const hours = Math.floor(remainingTime / 1e3 / 60 / 60) % 24;
|
|
2242
3634
|
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: [
|
|
3635
|
+
return /* @__PURE__ */ jsxs7("div", { className: "grid grid-flow-col md:gap-5 gap-1 text-center auto-cols-max", children: [
|
|
2244
3636
|
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
2245
|
-
/* @__PURE__ */
|
|
3637
|
+
/* @__PURE__ */ jsx10("span", { className: "font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx10(
|
|
2246
3638
|
"span",
|
|
2247
3639
|
{
|
|
2248
|
-
style: { "--value": days },
|
|
2249
3640
|
"aria-live": "polite",
|
|
2250
3641
|
"aria-label": days.toString(),
|
|
2251
|
-
children: days
|
|
3642
|
+
children: days.toString()
|
|
2252
3643
|
}
|
|
2253
3644
|
) }),
|
|
2254
|
-
/* @__PURE__ */
|
|
3645
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("DAYS") })
|
|
2255
3646
|
] }),
|
|
2256
3647
|
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
2257
|
-
/* @__PURE__ */
|
|
3648
|
+
/* @__PURE__ */ jsx10("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx10(
|
|
2258
3649
|
"span",
|
|
2259
3650
|
{
|
|
2260
3651
|
style: { "--value": hours },
|
|
@@ -2263,10 +3654,10 @@ function PreCreativeWork({
|
|
|
2263
3654
|
children: hours?.toString()?.padStart(2, "0")
|
|
2264
3655
|
}
|
|
2265
3656
|
) }),
|
|
2266
|
-
/* @__PURE__ */
|
|
3657
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("HOURS") })
|
|
2267
3658
|
] }),
|
|
2268
3659
|
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
2269
|
-
/* @__PURE__ */
|
|
3660
|
+
/* @__PURE__ */ jsx10("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx10(
|
|
2270
3661
|
"span",
|
|
2271
3662
|
{
|
|
2272
3663
|
style: { "--value": minutes },
|
|
@@ -2275,10 +3666,10 @@ function PreCreativeWork({
|
|
|
2275
3666
|
children: minutes?.toString()?.padStart(2, "0")
|
|
2276
3667
|
}
|
|
2277
3668
|
) }),
|
|
2278
|
-
/* @__PURE__ */
|
|
3669
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("MINUTES") })
|
|
2279
3670
|
] }),
|
|
2280
3671
|
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
|
|
2281
|
-
/* @__PURE__ */
|
|
3672
|
+
/* @__PURE__ */ jsx10("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ jsx10(
|
|
2282
3673
|
"span",
|
|
2283
3674
|
{
|
|
2284
3675
|
style: { "--value": seconds },
|
|
@@ -2287,7 +3678,7 @@ function PreCreativeWork({
|
|
|
2287
3678
|
children: seconds?.toString()?.padStart(2, "0")
|
|
2288
3679
|
}
|
|
2289
3680
|
) }),
|
|
2290
|
-
/* @__PURE__ */
|
|
3681
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("SECONDS") })
|
|
2291
3682
|
] })
|
|
2292
3683
|
] });
|
|
2293
3684
|
};
|
|
@@ -2300,12 +3691,12 @@ function PreCreativeWork({
|
|
|
2300
3691
|
backgroundImage: backgroundImageUrl ? `url(${backgroundImageUrl})` : ""
|
|
2301
3692
|
},
|
|
2302
3693
|
children: [
|
|
2303
|
-
backgroundImageUrl && /* @__PURE__ */
|
|
2304
|
-
/* @__PURE__ */
|
|
3694
|
+
backgroundImageUrl && /* @__PURE__ */ jsx10("div", { className: "absolute inset-0 bg-black bg-opacity-40" }),
|
|
3695
|
+
/* @__PURE__ */ jsx10("div", { className: "relative z-10", children: renderCountdown() })
|
|
2305
3696
|
]
|
|
2306
3697
|
}
|
|
2307
3698
|
),
|
|
2308
|
-
!hideTitle && /* @__PURE__ */
|
|
3699
|
+
!hideTitle && /* @__PURE__ */ jsx10(
|
|
2309
3700
|
TitleAndDescription2,
|
|
2310
3701
|
{
|
|
2311
3702
|
title: creativeWork.title,
|
|
@@ -2324,7 +3715,7 @@ var TitleAndDescription2 = ({
|
|
|
2324
3715
|
className
|
|
2325
3716
|
}) => {
|
|
2326
3717
|
return /* @__PURE__ */ jsxs7("div", { className: twMerge5("mt-3 mb-6 m-event-details-ctn px-4 text-left w-full", className), children: [
|
|
2327
|
-
/* @__PURE__ */
|
|
3718
|
+
/* @__PURE__ */ jsx10("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
|
|
2328
3719
|
releaseTime ? /* @__PURE__ */ jsxs7("div", { className: "text-sm md:text-base text-base-content/70 m-event-start-time", children: [
|
|
2329
3720
|
new Date(releaseTime || "").toLocaleDateString(locale || "default", {
|
|
2330
3721
|
month: "long",
|
|
@@ -2338,13 +3729,13 @@ var TitleAndDescription2 = ({
|
|
|
2338
3729
|
minute: "2-digit"
|
|
2339
3730
|
})
|
|
2340
3731
|
] }) : null,
|
|
2341
|
-
description && /* @__PURE__ */
|
|
3732
|
+
description && /* @__PURE__ */ jsx10("div", { className: "text-xs md:text-sm text-base-content/60 uppercase", children: description })
|
|
2342
3733
|
] });
|
|
2343
3734
|
};
|
|
2344
3735
|
|
|
2345
3736
|
// src/QueryProvider.tsx
|
|
2346
3737
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
2347
|
-
import { jsx as
|
|
3738
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
2348
3739
|
var queryClient = new QueryClient({
|
|
2349
3740
|
defaultOptions: {
|
|
2350
3741
|
queries: {
|
|
@@ -2358,13 +3749,16 @@ var queryClient = new QueryClient({
|
|
|
2358
3749
|
}
|
|
2359
3750
|
});
|
|
2360
3751
|
var QueryProvider = ({ children }) => {
|
|
2361
|
-
return /* @__PURE__ */
|
|
3752
|
+
return /* @__PURE__ */ jsx11(QueryClientProvider, { client: queryClient, children });
|
|
2362
3753
|
};
|
|
2363
3754
|
export {
|
|
3755
|
+
BigPlayIcon,
|
|
2364
3756
|
CreativeWork,
|
|
2365
3757
|
Event,
|
|
2366
3758
|
Player,
|
|
2367
3759
|
QueryProvider,
|
|
3760
|
+
SkipBackIcon,
|
|
3761
|
+
SkipForwardIcon,
|
|
2368
3762
|
Video,
|
|
2369
3763
|
queryClient
|
|
2370
3764
|
};
|