@mottosports/motto-video-player 1.0.1-rc.8 → 1.0.1-rc.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31,14 +31,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var index_exports = {};
33
33
  __export(index_exports, {
34
+ BigPlayIcon: () => BigPlayIcon,
34
35
  CreativeWork: () => CreativeWork,
35
36
  Event: () => Event,
36
37
  Player: () => Player,
37
38
  QueryProvider: () => QueryProvider,
39
+ SkipBackIcon: () => SkipBackIcon,
40
+ SkipForwardIcon: () => SkipForwardIcon,
38
41
  Video: () => Video,
39
42
  queryClient: () => queryClient
40
43
  });
41
44
  module.exports = __toCommonJS(index_exports);
45
+ var import_controls = require("shaka-player/dist/controls.css");
42
46
 
43
47
  // #style-inject:#style-inject
44
48
  function styleInject(css, { insertAt } = {}) {
@@ -62,73 +66,1031 @@ function styleInject(css, { insertAt } = {}) {
62
66
  }
63
67
  }
64
68
 
65
- // src/index.css
66
- 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');
69
+ // src/styles.css
70
+ styleInject(`@layer components {
71
+ video::-webkit-media-controls {
72
+ display: none !important;
73
+ }
74
+ video::-webkit-media-controls-panel {
75
+ display: none !important;
76
+ }
77
+ video::-webkit-media-controls-play-button {
78
+ display: none !important;
79
+ }
80
+ video::-webkit-media-controls-timeline {
81
+ display: none !important;
82
+ }
83
+ video::-webkit-media-controls-current-time-display {
84
+ display: none !important;
85
+ }
86
+ video::-webkit-media-controls-time-remaining-display {
87
+ display: none !important;
88
+ }
89
+ video::-webkit-media-controls-mute-button {
90
+ display: none !important;
91
+ }
92
+ video::-webkit-media-controls-volume-slider {
93
+ display: none !important;
94
+ }
95
+ video::-webkit-media-controls-fullscreen-button {
96
+ display: none !important;
97
+ }
98
+ video::-webkit-media-controls-overlay-play-button {
99
+ display: none !important;
100
+ }
101
+ video::-moz-media-controls {
102
+ display: none !important;
103
+ }
104
+ video {
105
+ outline: none !important;
106
+ }
107
+ video[controls] {
108
+ -webkit-appearance: none !important;
109
+ appearance: none !important;
110
+ }
111
+ video::-webkit-media-controls-enclosure {
112
+ display: none !important;
113
+ }
114
+ video::-webkit-media-controls-start-playback-button {
115
+ display: none !important;
116
+ }
117
+ video[controls]::-webkit-media-controls,
118
+ video[controls]::-webkit-media-controls-panel,
119
+ video[controls]::-webkit-media-controls-play-button,
120
+ video[controls]::-webkit-media-controls-timeline,
121
+ video[controls]::-webkit-media-controls-current-time-display,
122
+ video[controls]::-webkit-media-controls-time-remaining-display,
123
+ video[controls]::-webkit-media-controls-mute-button,
124
+ video[controls]::-webkit-media-controls-volume-slider,
125
+ video[controls]::-webkit-media-controls-fullscreen-button,
126
+ video[controls]::-webkit-media-controls-overlay-play-button,
127
+ video[controls]::-webkit-media-controls-enclosure,
128
+ video[controls]::-webkit-media-controls-start-playback-button {
129
+ display: none !important;
130
+ visibility: hidden !important;
131
+ opacity: 0 !important;
132
+ pointer-events: none !important;
133
+ }
134
+ video[controls]::-moz-media-controls {
135
+ display: none !important;
136
+ visibility: hidden !important;
137
+ opacity: 0 !important;
138
+ }
139
+ .motto-video-container {
140
+ @apply relative w-full;
141
+ min-height: 300px;
142
+ }
143
+ @supports (aspect-ratio: 16/9) {
144
+ .motto-video-container {
145
+ min-height: auto;
146
+ }
147
+ }
148
+ .motto-video-responsive {
149
+ @apply absolute top-0 left-0 w-full h-full;
150
+ }
151
+ .motto-skip-button {
152
+ @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;
153
+ }
154
+ .motto-skip-button-back {
155
+ @apply left-5;
156
+ }
157
+ .motto-skip-button-forward {
158
+ @apply right-5;
159
+ }
160
+ }
161
+ .shaka-seek-bar-container {
162
+ height: 6px !important;
163
+ width: 100% !important;
164
+ margin: 8px 0 !important;
165
+ border-radius: 4px !important;
166
+ position: relative !important;
167
+ border-top: none !important;
168
+ border-bottom: none !important;
169
+ box-shadow: none !important;
170
+ }
171
+ .shaka-seek-bar {
172
+ height: 6px !important;
173
+ width: 100% !important;
174
+ -webkit-appearance: none !important;
175
+ appearance: none !important;
176
+ background: transparent !important;
177
+ cursor: pointer !important;
178
+ border: none !important;
179
+ outline: none !important;
180
+ position: absolute !important;
181
+ top: 0 !important;
182
+ left: 0 !important;
183
+ border-radius: 4px !important;
184
+ }
185
+ .shaka-seek-bar::-webkit-slider-runnable-track {
186
+ height: 6px !important;
187
+ background: transparent !important;
188
+ border-radius: 4px !important;
189
+ border: none !important;
190
+ }
191
+ .shaka-seek-bar::-moz-range-track {
192
+ height: 6px !important;
193
+ background: transparent !important;
194
+ border-radius: 4px !important;
195
+ border: none !important;
196
+ }
197
+ .shaka-seek-bar::-webkit-slider-thumb {
198
+ -webkit-appearance: none !important;
199
+ appearance: none !important;
200
+ width: 16px !important;
201
+ height: 16px !important;
202
+ border-radius: 50% !important;
203
+ background: #ffffff !important;
204
+ cursor: pointer !important;
205
+ border: 2px solid #ffffff !important;
206
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;
207
+ margin-top: -4px !important;
208
+ }
209
+ .shaka-seek-bar::-moz-range-thumb {
210
+ width: 16px !important;
211
+ height: 16px !important;
212
+ border-radius: 50% !important;
213
+ background: #ffffff !important;
214
+ cursor: pointer !important;
215
+ border: 2px solid #ffffff !important;
216
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;
217
+ margin-top: -4px !important;
218
+ }
219
+ .motto-skip-back-button,
220
+ .motto-skip-forward-button,
221
+ .motto-native-skip-button {
222
+ background: transparent !important;
223
+ border: none !important;
224
+ padding: 4px !important;
225
+ margin: 0px !important;
226
+ cursor: pointer !important;
227
+ color: #ffffff !important;
228
+ transition: all 0.2s ease !important;
229
+ min-width: 32px !important;
230
+ height: 32px !important;
231
+ display: flex !important;
232
+ align-items: center !important;
233
+ justify-content: center !important;
234
+ border-radius: 4px !important;
235
+ width: 25px;
236
+ }
237
+ .motto-skip-back-button:hover,
238
+ .motto-skip-forward-button:hover,
239
+ .motto-native-skip-button:hover {
240
+ opacity: 0.8 !important;
241
+ background: transparent !important;
242
+ transform: scale(1.05) !important;
243
+ }
244
+ .motto-skip-back-button:active,
245
+ .motto-skip-forward-button:active,
246
+ .motto-native-skip-button:active {
247
+ transform: scale(0.95) !important;
248
+ }
249
+ .motto-skip-back-button svg,
250
+ .motto-skip-forward-button svg,
251
+ .motto-native-skip-button svg {
252
+ width: 24px !important;
253
+ height: 24px !important;
254
+ }
255
+ .shaka-spinner-svg {
256
+ color: white !important;
257
+ fill: white !important;
258
+ }
259
+ .shaka-spinner-path {
260
+ stroke: white !important;
261
+ fill: none !important;
262
+ }
263
+ .shaka-spinner-container {
264
+ color: white !important;
265
+ }
266
+ .shaka-buffering-spinner {
267
+ color: white !important;
268
+ fill: white !important;
269
+ }
270
+ .shaka-buffering-spinner svg {
271
+ color: white !important;
272
+ fill: white !important;
273
+ }
274
+ .shaka-buffering-spinner path {
275
+ stroke: white !important;
276
+ fill: none !important;
277
+ }
278
+ [data-shaka-player-container] .shaka-spinner,
279
+ [data-shaka-player-container] .spinner {
280
+ color: white !important;
281
+ border-color: white !important;
282
+ }
283
+ .material-icons.shaka-spinner {
284
+ color: white !important;
285
+ }
286
+ .shaka-controls-container .shaka-spinner,
287
+ .shaka-video-container .shaka-spinner {
288
+ color: white !important;
289
+ fill: white !important;
290
+ }
291
+ .shaka-controls-container .shaka-spinner svg,
292
+ .shaka-video-container .shaka-spinner svg {
293
+ color: white !important;
294
+ fill: white !important;
295
+ }
296
+ .shaka-controls-container .shaka-spinner path,
297
+ .shaka-video-container .shaka-spinner path {
298
+ stroke: white !important;
299
+ }
300
+ .motto-video-loading-overlay {
301
+ position: absolute;
302
+ top: 0;
303
+ left: 0;
304
+ width: 100%;
305
+ height: 100%;
306
+ background:
307
+ linear-gradient(
308
+ 135deg,
309
+ #1a1a1a 0%,
310
+ #2d2d2d 100%);
311
+ display: flex;
312
+ flex-direction: column;
313
+ align-items: center;
314
+ justify-content: center;
315
+ z-index: 10;
316
+ transition: opacity 0.3s ease;
317
+ }
318
+ .motto-video-loading-overlay.hidden {
319
+ opacity: 0;
320
+ pointer-events: none;
321
+ }
322
+ .motto-video-loading-content {
323
+ text-align: center;
324
+ color: white;
325
+ }
326
+ .motto-video-loading-icon {
327
+ width: 64px;
328
+ height: 64px;
329
+ margin-bottom: 16px;
330
+ opacity: 0.7;
331
+ }
332
+ .motto-video-loading-text {
333
+ font-size: 16px;
334
+ font-weight: 500;
335
+ margin-bottom: 8px;
336
+ }
337
+ .motto-video-loading-subtext {
338
+ font-size: 14px;
339
+ opacity: 0.7;
340
+ }
341
+ @keyframes pulse-live {
342
+ 0% {
343
+ opacity: 1;
344
+ transform: scale(1);
345
+ }
346
+ 50% {
347
+ opacity: 0.7;
348
+ transform: scale(1.1);
349
+ }
350
+ 100% {
351
+ opacity: 1;
352
+ transform: scale(1);
353
+ }
354
+ }
355
+ .shaka-play-button {
356
+ background: rgba(255, 255, 255, 0.1) !important;
357
+ border: none !important;
358
+ color: white !important;
359
+ padding: 10px !important;
360
+ border-radius: 100% !important;
361
+ transition: all 0.2s ease !important;
362
+ display: flex !important;
363
+ align-items: center !important;
364
+ justify-content: center !important;
365
+ min-width: 55px !important;
366
+ height: 55px !important;
367
+ }
368
+ .shaka-play-button-container {
369
+ background: transparent;
370
+ transition: all 0.2s ease !important;
371
+ }
372
+ .motto-video-container:not(.no-cursor) .shaka-play-button-container {
373
+ background: rgba(0, 0, 0, 0.3);
374
+ transition: all 0.s ease !important;
375
+ }
376
+ .shaka-play-button:hover {
377
+ background: rgba(255, 255, 255, 0.2) !important;
378
+ transform: scale(1.05) !important;
379
+ }
380
+ .shaka-play-button:active {
381
+ transform: scale(0.95) !important;
382
+ }
383
+ .shaka-play-button > * {
384
+ display: none !important;
385
+ }
386
+ .shaka-play-button::after {
387
+ content: "" !important;
388
+ width: 35px !important;
389
+ height: 35px !important;
390
+ 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;
391
+ background-repeat: no-repeat !important;
392
+ background-size: contain !important;
393
+ background-position: center !important;
394
+ display: block !important;
395
+ }
396
+ .shaka-play-button[aria-label*=Play]::after {
397
+ 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;
398
+ }
399
+ .shaka-play-button[aria-label*=Pause]::after {
400
+ 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;
401
+ }
402
+ .motto-video-container {
403
+ background: #111111;
404
+ }
405
+ .motto-video-container video {
406
+ width: 100% !important;
407
+ height: 100% !important;
408
+ margin-left: auto !important;
409
+ margin-right: auto !important;
410
+ }
411
+ html[dir=rtl] .shaka-controls-container,
412
+ html[dir=rtl] .shaka-bottom-controls,
413
+ html[dir=rtl] .shaka-controls-button-panel {
414
+ direction: ltr !important;
415
+ }
416
+ html[dir=rtl] .shaka-overflow-menu,
417
+ html[dir=rtl] .shaka-settings-menu {
418
+ direction: rtl !important;
419
+ text-align: right !important;
420
+ }
421
+ html[dir=rtl] .shaka-overflow-menu .shaka-overflow-button .material-svg-icon:not(:first-child) {
422
+ margin-right: 12px !important;
423
+ margin-left: 0 !important;
424
+ }
425
+ html[dir=rtl] .shaka-overflow-menu .shaka-overflow-button .material-svg-icon:first-child {
426
+ margin-right: 0 !important;
427
+ margin-left: 12px !important;
428
+ }
429
+ .shaka-hidden-fast-forward-container,
430
+ .shaka-hidden-rewind-container {
431
+ pointer-events: none !important;
432
+ display: none !important;
433
+ }
434
+ `);
67
435
 
68
436
  // src/Player.tsx
69
- var import_react10 = require("react");
437
+ var import_react12 = require("react");
70
438
  var import_shaka_player4 = __toESM(require("shaka-player/dist/shaka-player.ui"));
71
439
 
72
- // src/hooks/useShakePlayer.ts
440
+ // src/hooks/useShakaPlayer.ts
73
441
  var import_react = require("react");
74
- var import_shaka_player = require("shaka-player/dist/shaka-player.ui");
75
- var useShakePlayer = ({
442
+ var import_shaka_player = __toESM(require("shaka-player/dist/shaka-player.ui"));
443
+
444
+ // src/utils/devices.ts
445
+ var isAppleDevice = () => {
446
+ if (typeof navigator === "undefined") return false;
447
+ const ua = navigator.userAgent || "";
448
+ const isIOS = /iPad|iPhone|iPod/.test(ua) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
449
+ const isSafari = /Safari/.test(ua) && !/Chrome|CriOS|FxiOS|Edg/.test(ua);
450
+ const isMacSafari = /Macintosh/.test(ua) && isSafari;
451
+ return isIOS || isMacSafari;
452
+ };
453
+ var isPlayReadySupported = () => {
454
+ if (typeof navigator === "undefined" || typeof window === "undefined") {
455
+ return false;
456
+ }
457
+ if (!navigator.requestMediaKeySystemAccess) {
458
+ return false;
459
+ }
460
+ const userAgent = navigator.userAgent || "";
461
+ const isXbox = /Xbox/.test(userAgent);
462
+ const isEdge = /Edg/.test(userAgent);
463
+ const isIE = /Trident|MSIE/.test(userAgent);
464
+ const isWindows = /Windows/.test(userAgent);
465
+ return isXbox || (isEdge || isIE) && isWindows;
466
+ };
467
+ var supportsWidevinePersistentLicenses = () => {
468
+ return false;
469
+ if (typeof navigator === "undefined") {
470
+ return false;
471
+ }
472
+ const userAgent = navigator.userAgent || "";
473
+ const isChromeMatch = userAgent.match(/Chrome\/(\d+)/);
474
+ if (!isChromeMatch) {
475
+ return false;
476
+ }
477
+ if (/Edg|OPR|Opera/.test(userAgent)) {
478
+ return false;
479
+ }
480
+ const chromeVersion = parseInt(isChromeMatch[1], 10);
481
+ if (chromeVersion < 64) {
482
+ return false;
483
+ }
484
+ const isMacOS = /Mac OS X|Macintosh/.test(userAgent);
485
+ const isWindows = /Windows/.test(userAgent);
486
+ return isMacOS || isWindows;
487
+ };
488
+
489
+ // src/hooks/useShakaPlayer.ts
490
+ var import_mux_data_shakaplayer = __toESM(require("@mux/mux-data-shakaplayer"));
491
+
492
+ // package.json
493
+ var version = "1.0.1-rc.80";
494
+
495
+ // src/utils/licenseCache.ts
496
+ var PERSISTENT_LICENSE_PREFIX = "motto_lic_";
497
+ var LICENSE_EXPIRY_MS = 2 * 60 * 60 * 1e3;
498
+ var LICENSE_MAX_RETRY_ATTEMPTS = 10;
499
+ var getAllLicenseCacheKeys = () => {
500
+ const keys = [];
501
+ for (let i = 0; i < localStorage.length; i++) {
502
+ const key = localStorage.key(i);
503
+ if (key?.startsWith(PERSISTENT_LICENSE_PREFIX)) {
504
+ keys.push(key);
505
+ }
506
+ }
507
+ return keys;
508
+ };
509
+ var getAllLicenseCacheEntries = () => {
510
+ const keys = getAllLicenseCacheKeys();
511
+ const entries = [];
512
+ for (const key of keys) {
513
+ try {
514
+ const stored = localStorage.getItem(key);
515
+ if (stored) {
516
+ const data = JSON.parse(stored);
517
+ entries.push({ key, data });
518
+ }
519
+ } catch (error) {
520
+ console.warn(`Failed to parse license cache entry for key ${key}:`, error);
521
+ localStorage.removeItem(key);
522
+ }
523
+ }
524
+ return entries;
525
+ };
526
+ var evictLRUEntry = () => {
527
+ const entries = getAllLicenseCacheEntries();
528
+ if (entries.length === 0) {
529
+ return false;
530
+ }
531
+ entries.sort((a, b) => {
532
+ const oldestA = Math.min(...a.data.map((session) => session.timestamp));
533
+ const oldestB = Math.min(...b.data.map((session) => session.timestamp));
534
+ return oldestA - oldestB;
535
+ });
536
+ const lruEntry = entries[0];
537
+ localStorage.removeItem(lruEntry.key);
538
+ console.log(`Evicted LRU license cache entry: ${lruEntry.key}`);
539
+ return true;
540
+ };
541
+ var storeWithQuotaHandling = (key, data) => {
542
+ let attempts = 0;
543
+ while (attempts < LICENSE_MAX_RETRY_ATTEMPTS) {
544
+ try {
545
+ localStorage.setItem(key, data);
546
+ return true;
547
+ } catch (error) {
548
+ if (error instanceof DOMException && (error.code === 22 || // QUOTA_EXCEEDED_ERR
549
+ error.name === "QuotaExceededError" || error.name === "NS_ERROR_DOM_QUOTA_REACHED")) {
550
+ console.warn(`QuotaExceededError on attempt ${attempts + 1}, attempting LRU eviction...`);
551
+ if (!evictLRUEntry()) {
552
+ console.error("No more entries to evict, storage operation failed");
553
+ return false;
554
+ }
555
+ attempts++;
556
+ } else {
557
+ console.error("Failed to store license cache data:", error);
558
+ return false;
559
+ }
560
+ }
561
+ }
562
+ console.error(`Failed to store license cache data after ${LICENSE_MAX_RETRY_ATTEMPTS} eviction attempts`);
563
+ return false;
564
+ };
565
+ var managePersistentLicenseStorage = (playlistId, licenseCacheKey, newSessionMetadata) => {
566
+ try {
567
+ const storageKey = `${PERSISTENT_LICENSE_PREFIX}${playlistId}_${licenseCacheKey}`;
568
+ const stored = localStorage.getItem(storageKey);
569
+ let existingSessions = [];
570
+ if (stored) {
571
+ try {
572
+ existingSessions = JSON.parse(stored);
573
+ } catch (parseError) {
574
+ console.warn("Failed to parse existing persistent license data:", parseError);
575
+ existingSessions = [];
576
+ }
577
+ }
578
+ const now = Date.now();
579
+ let validSessions = existingSessions.filter(
580
+ (session) => now - session.timestamp < LICENSE_EXPIRY_MS
581
+ );
582
+ if (newSessionMetadata && newSessionMetadata.length > 0) {
583
+ const newSessions = newSessionMetadata.map((session) => {
584
+ const uint8Array = new Uint8Array(session.initData);
585
+ const binaryString = Array.from(uint8Array).map((byte) => String.fromCharCode(byte)).join("");
586
+ return {
587
+ sessionId: session.sessionId,
588
+ initData: btoa(binaryString),
589
+ initDataType: session.initDataType,
590
+ keySystem: session.keySystem,
591
+ timestamp: now
592
+ };
593
+ });
594
+ const newSessionIds = new Set(newSessions.map((s) => s.sessionId));
595
+ validSessions = validSessions.filter((session) => !newSessionIds.has(session.sessionId));
596
+ validSessions = [...validSessions, ...newSessions];
597
+ }
598
+ if (validSessions.length === 0) {
599
+ localStorage.removeItem(storageKey);
600
+ } else {
601
+ const dataToStore = JSON.stringify(validSessions);
602
+ const success = storeWithQuotaHandling(storageKey, dataToStore);
603
+ if (!success) {
604
+ console.error(`Failed to store license cache for ${storageKey} after quota handling`);
605
+ return validSessions;
606
+ }
607
+ }
608
+ return validSessions;
609
+ } catch (error) {
610
+ console.warn("Failed to manage persistent license storage:", error);
611
+ return [];
612
+ }
613
+ };
614
+ var storePersistentLicense = (playlistId, licenseCacheKey, sessionMetadata) => {
615
+ managePersistentLicenseStorage(playlistId, licenseCacheKey, sessionMetadata);
616
+ };
617
+ var retrievePersistentLicense = (playlistId, licenseCacheKey) => {
618
+ try {
619
+ const validSessions = managePersistentLicenseStorage(playlistId, licenseCacheKey);
620
+ return validSessions.map((session) => ({
621
+ sessionId: session.sessionId,
622
+ initData: Uint8Array.from(atob(session.initData), (c) => c.charCodeAt(0)).buffer,
623
+ initDataType: session.initDataType,
624
+ keySystem: session.keySystem
625
+ }));
626
+ } catch (error) {
627
+ console.warn("Failed to retrieve persistent license:", error);
628
+ return [];
629
+ }
630
+ };
631
+ var clearAllPersistentLicenses = () => {
632
+ try {
633
+ const keys = getAllLicenseCacheKeys();
634
+ for (const key of keys) {
635
+ localStorage.removeItem(key);
636
+ }
637
+ console.log(`Cleared ${keys.length} persistent license cache entries`);
638
+ return keys.length;
639
+ } catch (error) {
640
+ console.error("Failed to clear persistent licenses:", error);
641
+ return 0;
642
+ }
643
+ };
644
+
645
+ // src/hooks/useShakaPlayer.ts
646
+ var normalizeSource = (src) => {
647
+ if (typeof src === "string") {
648
+ return {
649
+ id: "",
650
+ url: src,
651
+ format: "auto",
652
+ drm: {}
653
+ };
654
+ }
655
+ return src;
656
+ };
657
+ var useShakaPlayer = ({
76
658
  src,
77
659
  shakaConfig,
78
660
  drmConfig,
79
661
  onError,
80
- onPlayerReady
662
+ onPlayerReady,
663
+ muxConfig,
664
+ onMuxReady,
665
+ onMuxDataUpdate,
666
+ publicKey,
667
+ mottoToken,
668
+ hasAds = false,
669
+ hasSystem73 = false,
670
+ apiToken
81
671
  }) => {
82
672
  const playerRef = (0, import_react.useRef)(null);
83
- const initializePlayer = (0, import_react.useCallback)(async (video) => {
673
+ const [isRetrying, setIsRetrying] = (0, import_react.useState)(false);
674
+ const videoElementRef = (0, import_react.useRef)(null);
675
+ const destroyInProgressRef = (0, import_react.useRef)(null);
676
+ const isDestroyingRef = (0, import_react.useRef)(false);
677
+ const initSequenceRef = (0, import_react.useRef)(0);
678
+ const activeInitIdRef = (0, import_react.useRef)(null);
679
+ const waitingForKeyTimerRef = (0, import_react.useRef)(null);
680
+ const waitingForKeyHandlerRef = (0, import_react.useRef)(null);
681
+ const playbackResumedHandlerRef = (0, import_react.useRef)(null);
682
+ const usingPersistentLicenseRef = (0, import_react.useRef)(false);
683
+ const storedPersistentThisLoadRef = (0, import_react.useRef)(false);
684
+ const drmExpirationHandlerRef = (0, import_react.useRef)(null);
685
+ const getManifestUrl = (0, import_react.useCallback)(() => {
686
+ const playlistSrc = normalizeSource(src);
687
+ let manifestUrl = playlistSrc.url;
688
+ const isDRM = Boolean(playlistSrc.drm?.widevine || playlistSrc.drm?.fairplay || playlistSrc.drm?.playready);
689
+ if (isDRM) {
690
+ const isPlayReady = isPlayReadySupported();
691
+ if (isAppleDevice() && playlistSrc.drm?.fairplay?.certificateUrl) {
692
+ manifestUrl = playlistSrc.drm.fairplay.playlistUrl;
693
+ } else if (isPlayReady && playlistSrc.drm?.playready?.licenseUrl) {
694
+ manifestUrl = playlistSrc.drm.playready.playlistUrl;
695
+ } else {
696
+ manifestUrl = playlistSrc.drm?.widevine?.playlistUrl || "";
697
+ }
698
+ }
699
+ return manifestUrl;
700
+ }, [src]);
701
+ const initializePlayerInternal = (0, import_react.useCallback)(async (video) => {
84
702
  try {
85
- import_shaka_player.polyfill.installAll();
86
- if (!import_shaka_player.Player.isBrowserSupported()) {
703
+ if (destroyInProgressRef.current) {
704
+ try {
705
+ await destroyInProgressRef.current;
706
+ } catch {
707
+ }
708
+ }
709
+ const myInitId = ++initSequenceRef.current;
710
+ activeInitIdRef.current = myInitId;
711
+ videoElementRef.current = video;
712
+ import_shaka_player.default.polyfill.installAll();
713
+ if (!import_shaka_player.default.Player.isBrowserSupported()) {
87
714
  throw new Error("Browser not supported by Shaka Player");
88
715
  }
89
- const player = new import_shaka_player.Player(video);
716
+ if (isDestroyingRef.current) {
717
+ return;
718
+ }
719
+ const player = new import_shaka_player.default.Player();
90
720
  playerRef.current = player;
91
721
  await player.attach(video);
722
+ const defaultConfig = {
723
+ manifest: {
724
+ // Override availability window to allow DVR window to grow from start
725
+ // Set to a very large value (24 hours in seconds) to effectively allow unlimited growth
726
+ availabilityWindowOverride: 86400
727
+ // 24 hours in seconds
728
+ },
729
+ streaming: {
730
+ // Allow seeking to any point within the availability window
731
+ safeSeekOffset: 5,
732
+ // 5 seconds from live edge to prevent buffering
733
+ // Increase tolerance for manifest timing inaccuracies in live streams
734
+ inaccurateManifestTolerance: 2
735
+ }
736
+ };
737
+ player.configure(defaultConfig);
92
738
  if (shakaConfig) {
93
739
  player.configure(shakaConfig);
94
740
  }
95
- if (drmConfig) {
96
- if (drmConfig.clearKeys) {
97
- player.configure({ "drm.clearKeys": drmConfig.clearKeys });
741
+ const playlistSrc = normalizeSource(src);
742
+ const manifestUrl = getManifestUrl();
743
+ let playlistId = playlistSrc.id;
744
+ const isDRM = Boolean(playlistSrc.drm?.widevine || playlistSrc.drm?.fairplay || playlistSrc.drm?.playready);
745
+ storedPersistentThisLoadRef.current = false;
746
+ if (activeInitIdRef.current !== myInitId || isDestroyingRef.current) {
747
+ try {
748
+ await player.destroy();
749
+ } catch {
750
+ }
751
+ if (playerRef.current === player) playerRef.current = null;
752
+ return;
753
+ }
754
+ let storedSessionsMetadata = [];
755
+ if (isDRM && playlistId) {
756
+ storedSessionsMetadata = retrievePersistentLicense(playlistId, playlistSrc.drm?.licenseCacheKey ?? "");
757
+ }
758
+ if (isDRM) {
759
+ const drmConfig2 = {
760
+ servers: {
761
+ "com.widevine.alpha": playlistSrc.drm?.widevine?.licenseUrl,
762
+ "com.microsoft.playready": playlistSrc.drm?.playready?.licenseUrl,
763
+ "com.apple.fps": playlistSrc.drm?.fairplay?.licenseUrl
764
+ },
765
+ keySystemsMapping: {
766
+ // Fall back or reroute to the platform's recommended PlayReady CDM if needed
767
+ "com.microsoft.playready": "com.microsoft.playready.recommendation"
768
+ },
769
+ ...playlistSrc.drm?.fairplay && {
770
+ advanced: {
771
+ "com.apple.fps": {
772
+ serverCertificateUri: playlistSrc.drm.fairplay.certificateUrl
773
+ }
774
+ }
775
+ }
776
+ };
777
+ drmConfig2.advanced = {
778
+ ...drmConfig2.advanced,
779
+ "com.widevine.alpha": {
780
+ ...drmConfig2.advanced?.["com.widevine.alpha"],
781
+ sessionType: supportsWidevinePersistentLicenses() ? "persistent-license" : "temporary"
782
+ },
783
+ "com.microsoft.playready": {
784
+ ...drmConfig2.advanced?.["com.microsoft.playready"],
785
+ sessionType: "persistent-license"
786
+ // PlayReady seems to always require persistent-license (temporary won't work, not compatible with license server response)
787
+ },
788
+ "com.apple.fps": {
789
+ ...drmConfig2.advanced?.["com.apple.fps"],
790
+ sessionType: "temporary"
791
+ // FairPlay always uses temporary sessions - Safari won't play with persistent-license
792
+ }
793
+ };
794
+ if (storedSessionsMetadata.length > 0) {
795
+ drmConfig2.persistentSessionOnlinePlayback = true;
796
+ drmConfig2.persistentSessionsMetadata = storedSessionsMetadata.map((session) => ({
797
+ sessionId: session.sessionId,
798
+ initData: new Uint8Array(session.initData),
799
+ initDataType: session.initDataType
800
+ }));
801
+ }
802
+ usingPersistentLicenseRef.current = storedSessionsMetadata.length > 0;
803
+ player.configure({ drm: drmConfig2 });
804
+ const clearWaitingForKeyTimer = () => {
805
+ if (waitingForKeyTimerRef.current !== null) {
806
+ window.clearTimeout(waitingForKeyTimerRef.current);
807
+ waitingForKeyTimerRef.current = null;
808
+ }
809
+ };
810
+ const onPlaybackResumed = () => {
811
+ clearWaitingForKeyTimer();
812
+ };
813
+ const onWaitingForKey = () => {
814
+ if (!usingPersistentLicenseRef.current) return;
815
+ if (isRetrying) return;
816
+ clearWaitingForKeyTimer();
817
+ waitingForKeyTimerRef.current = window.setTimeout(async () => {
818
+ try {
819
+ if (isRetrying) return;
820
+ console.warn("Stuck waiting for decryption key; attempting license cache reset and reload...");
821
+ const clearedCount = clearAllPersistentLicenses();
822
+ if (clearedCount > 0 && playerRef.current) {
823
+ setIsRetrying(true);
824
+ await playerRef.current.load(getManifestUrl());
825
+ console.log("Reloaded manifest after clearing cached licenses");
826
+ } else {
827
+ console.warn("No cached licenses found to clear, skipping reload");
828
+ }
829
+ } catch (e) {
830
+ console.error("Failed during recovery from waitingforkey state:", e);
831
+ onError?.(e);
832
+ } finally {
833
+ setIsRetrying(false);
834
+ clearWaitingForKeyTimer();
835
+ }
836
+ }, 3e3);
837
+ };
838
+ try {
839
+ video.addEventListener("waitingforkey", onWaitingForKey);
840
+ video.addEventListener("playing", onPlaybackResumed);
841
+ video.addEventListener("ended", onPlaybackResumed);
842
+ video.addEventListener("pause", onPlaybackResumed);
843
+ waitingForKeyHandlerRef.current = onWaitingForKey;
844
+ playbackResumedHandlerRef.current = onPlaybackResumed;
845
+ } catch (e) {
846
+ console.warn("Failed to attach waitingforkey/playback listeners:", e);
847
+ }
848
+ const netEngine = player.getNetworkingEngine();
849
+ if (netEngine) {
850
+ netEngine.registerRequestFilter((type, request) => {
851
+ switch (type) {
852
+ case import_shaka_player.default.net.NetworkingEngine.RequestType.LICENSE:
853
+ if (publicKey) {
854
+ request.headers["authorization"] = `Bearer ${publicKey}`;
855
+ }
856
+ if (mottoToken) {
857
+ request.headers["x-motto-token"] = mottoToken;
858
+ }
859
+ break;
860
+ case import_shaka_player.default.net.NetworkingEngine.RequestType.MANIFEST:
861
+ case import_shaka_player.default.net.NetworkingEngine.RequestType.SEGMENT:
862
+ request.allowCrossSiteCredentials = true;
863
+ break;
864
+ }
865
+ });
866
+ netEngine.registerResponseFilter((type, response) => {
867
+ if (type === import_shaka_player.default.net.NetworkingEngine.RequestType.LICENSE) {
868
+ const ks = player.keySystem && player.keySystem();
869
+ if (ks === "com.apple.fps") {
870
+ const responseText = import_shaka_player.default.util.StringUtils.fromUTF8(response.data);
871
+ response.data = import_shaka_player.default.util.Uint8ArrayUtils.fromBase64(responseText).buffer;
872
+ }
873
+ }
874
+ });
875
+ }
876
+ }
877
+ if (apiToken) {
878
+ const netEngine = player.getNetworkingEngine();
879
+ if (netEngine) {
880
+ netEngine.registerRequestFilter((type, request) => {
881
+ if (type === import_shaka_player.default.net.NetworkingEngine.RequestType.MANIFEST) {
882
+ request.headers["authorization"] = `Bearer ${apiToken}`;
883
+ }
884
+ });
98
885
  }
99
- if (drmConfig.servers) {
100
- player.configure({ "drm.servers": drmConfig.servers });
886
+ }
887
+ if (isDRM && playlistId) {
888
+ const onDRMSessionUpdate = () => {
889
+ try {
890
+ if (storedPersistentThisLoadRef.current) return;
891
+ const activeDrmSessions = player.getActiveSessionsMetadata?.();
892
+ if (!activeDrmSessions) return;
893
+ const persistentSessions = activeDrmSessions.filter(
894
+ (session) => session.sessionType === "persistent-license"
895
+ );
896
+ if (persistentSessions.length > 0) {
897
+ const sessionsToStore = persistentSessions.map((session) => ({
898
+ sessionId: session.sessionId,
899
+ initData: session.initData,
900
+ initDataType: session.initDataType,
901
+ keySystem: session.keySystem || "com.widevine.alpha"
902
+ }));
903
+ storePersistentLicense(playlistId, playlistSrc.drm?.licenseCacheKey ?? "", sessionsToStore);
904
+ storedPersistentThisLoadRef.current = true;
905
+ }
906
+ } catch (e) {
907
+ console.warn("Failed to persist licenses on expiration update:", e);
908
+ }
909
+ };
910
+ try {
911
+ player.addEventListener("drmsessionupdate", onDRMSessionUpdate);
912
+ drmExpirationHandlerRef.current = onDRMSessionUpdate;
913
+ } catch (e) {
914
+ console.warn("Failed to attach drmsessionupdate listener:", e);
101
915
  }
102
916
  }
103
- player.addEventListener("error", (event) => {
917
+ player?.addEventListener("error", (event) => {
104
918
  const error = event.detail;
919
+ if (error?.code === 7e3) {
920
+ return;
921
+ }
922
+ if (error?.code >= 6e3 && error?.code < 7e3 && !isRetrying && videoElementRef.current) {
923
+ console.warn(`DRM error detected (code: ${error.code}), checking for cached licenses...`);
924
+ const clearedCount = clearAllPersistentLicenses();
925
+ if (clearedCount > 0) {
926
+ console.warn(`Cleared ${clearedCount} cached licenses, retrying...`);
927
+ setIsRetrying(true);
928
+ setTimeout(async () => {
929
+ try {
930
+ const video2 = videoElementRef.current;
931
+ const currentPlayer = playerRef.current;
932
+ if (video2 && currentPlayer) {
933
+ console.log("Reloading manifest after license cache clear...");
934
+ await currentPlayer.load(getManifestUrl());
935
+ console.log("Manifest reloaded successfully");
936
+ }
937
+ } catch (retryError) {
938
+ console.error("Failed to retry after license clear:", retryError);
939
+ onError?.(retryError);
940
+ } finally {
941
+ setIsRetrying(false);
942
+ }
943
+ }, 500);
944
+ return;
945
+ } else {
946
+ console.warn(`No cached licenses found to clear for error code ${error.code}, not retrying to avoid infinite loop`);
947
+ }
948
+ }
105
949
  console.error("Shaka Player Error:", error);
106
950
  onError?.(new Error(`Shaka Player Error: ${error.message || "Unknown error"}`));
107
951
  });
108
- await player.load(src);
952
+ if (muxConfig) {
953
+ try {
954
+ const playerInitTime = import_mux_data_shakaplayer.default.utils.now();
955
+ const muxOptions = {
956
+ debug: muxConfig.debug || false,
957
+ disableCookies: muxConfig.disableCookies || false,
958
+ respectDoNotTrack: muxConfig.respectDoNotTrack || false,
959
+ automaticErrorTracking: muxConfig.automaticErrorTracking !== false,
960
+ ...muxConfig.beaconCollectionDomain && { beaconCollectionDomain: muxConfig.beaconCollectionDomain },
961
+ ...muxConfig.errorTranslator && { errorTranslator: muxConfig.errorTranslator },
962
+ data: {
963
+ env_key: muxConfig.envKey,
964
+ player_name: muxConfig?.metadata?.player_name,
965
+ player_version: version,
966
+ player_init_time: playerInitTime,
967
+ video_title: muxConfig?.metadata?.video_title ?? "",
968
+ video_id: muxConfig?.metadata?.video_id ?? "",
969
+ viewer_user_id: muxConfig?.metadata?.viewer_user_id ?? "",
970
+ ...muxConfig.metadata
971
+ }
972
+ };
973
+ (0, import_mux_data_shakaplayer.default)(player, muxOptions, import_shaka_player.default);
974
+ onMuxReady?.();
975
+ } catch (error) {
976
+ console.error("Failed to initialize Mux Analytics:", error);
977
+ }
978
+ }
979
+ if (activeInitIdRef.current !== myInitId || isDestroyingRef.current) {
980
+ try {
981
+ await player.destroy();
982
+ } catch {
983
+ }
984
+ if (playerRef.current === player) playerRef.current = null;
985
+ return;
986
+ }
987
+ if (!hasAds && !hasSystem73) {
988
+ console.log("\u{1F4FA} [Shaka] Auto-loading manifest:", manifestUrl);
989
+ await player.load(manifestUrl);
990
+ console.log("\u2705 [Shaka] Manifest auto-loaded successfully");
991
+ } else {
992
+ console.log("\u23ED\uFE0F [Shaka] Skipping auto-load (hasAds:", hasAds, ", hasSystem73:", hasSystem73, ")");
993
+ }
109
994
  onPlayerReady?.(player);
110
995
  return player;
111
996
  } catch (error) {
997
+ if (error?.code === 7e3) {
998
+ return;
999
+ }
112
1000
  console.error("Error initializing Shaka Player:", error);
113
1001
  onError?.(error);
114
1002
  throw error;
115
1003
  }
116
- }, [shakaConfig, drmConfig, src, onError, onPlayerReady]);
1004
+ }, [shakaConfig, drmConfig, src, onError, onPlayerReady, muxConfig, onMuxReady, isRetrying, getManifestUrl, apiToken]);
1005
+ const initializePlayer = (0, import_react.useCallback)(async (video) => {
1006
+ return initializePlayerInternal(video);
1007
+ }, [initializePlayerInternal]);
1008
+ const loadManifest = (0, import_react.useCallback)(async () => {
1009
+ const player = playerRef.current;
1010
+ if (!player) {
1011
+ console.warn("\u26A0\uFE0F [Shaka] Cannot load manifest: player not initialized");
1012
+ return;
1013
+ }
1014
+ try {
1015
+ const manifestUrl = getManifestUrl();
1016
+ console.log("\u{1F4FA} [Shaka] Loading manifest:", manifestUrl);
1017
+ await player.load(manifestUrl);
1018
+ console.log("\u2705 [Shaka] Manifest loaded successfully");
1019
+ } catch (error) {
1020
+ if (error?.code === 7e3) {
1021
+ return;
1022
+ }
1023
+ console.error("\u274C [Shaka] Error loading manifest:", error);
1024
+ onError?.(error);
1025
+ throw error;
1026
+ }
1027
+ }, [getManifestUrl, onError]);
117
1028
  const destroyPlayer = (0, import_react.useCallback)(async () => {
118
- if (playerRef.current) {
1029
+ const playerInstance = playerRef.current;
1030
+ if (playerInstance) {
119
1031
  try {
120
- await playerRef.current.destroy();
1032
+ isDestroyingRef.current = true;
1033
+ activeInitIdRef.current = null;
1034
+ if (videoElementRef.current) {
1035
+ try {
1036
+ if (waitingForKeyHandlerRef.current) {
1037
+ videoElementRef.current.removeEventListener("waitingforkey", waitingForKeyHandlerRef.current);
1038
+ }
1039
+ if (playbackResumedHandlerRef.current) {
1040
+ videoElementRef.current.removeEventListener("playing", playbackResumedHandlerRef.current);
1041
+ videoElementRef.current.removeEventListener("ended", playbackResumedHandlerRef.current);
1042
+ videoElementRef.current.removeEventListener("pause", playbackResumedHandlerRef.current);
1043
+ }
1044
+ } catch (e) {
1045
+ console.warn("Error removing media event listeners:", e);
1046
+ }
1047
+ }
1048
+ if (waitingForKeyTimerRef.current !== null) {
1049
+ window.clearTimeout(waitingForKeyTimerRef.current);
1050
+ waitingForKeyTimerRef.current = null;
1051
+ }
1052
+ try {
1053
+ if (drmExpirationHandlerRef.current && playerInstance.removeEventListener) {
1054
+ playerInstance.removeEventListener("drmsessionupdate", drmExpirationHandlerRef.current);
1055
+ }
1056
+ } catch (e) {
1057
+ console.warn("Error removing DRM expiration listener:", e);
1058
+ } finally {
1059
+ drmExpirationHandlerRef.current = null;
1060
+ }
1061
+ const performDestroy = async () => {
1062
+ try {
1063
+ await playerInstance.destroy();
1064
+ } finally {
1065
+ try {
1066
+ if (videoElementRef.current) {
1067
+ videoElementRef.current.removeAttribute("src");
1068
+ videoElementRef.current.load();
1069
+ }
1070
+ } catch {
1071
+ }
1072
+ }
1073
+ };
1074
+ destroyInProgressRef.current = performDestroy();
1075
+ await destroyInProgressRef.current;
121
1076
  } catch (error) {
122
1077
  console.warn("Error destroying Shaka Player:", error);
123
1078
  } finally {
124
- playerRef.current = null;
1079
+ if (playerRef.current === playerInstance) {
1080
+ playerRef.current = null;
1081
+ }
1082
+ storedPersistentThisLoadRef.current = false;
1083
+ isDestroyingRef.current = false;
1084
+ destroyInProgressRef.current = null;
125
1085
  }
126
1086
  }
127
- }, []);
1087
+ }, [playerRef]);
128
1088
  return {
129
1089
  playerRef,
130
1090
  initializePlayer,
131
- destroyPlayer
1091
+ loadManifest,
1092
+ destroyPlayer,
1093
+ isRetrying
132
1094
  };
133
1095
  };
134
1096
 
@@ -151,11 +1113,25 @@ var useQualityControl = (playerRef, qualityConfig, onQualityChange) => {
151
1113
  if (!playerRef.current) return;
152
1114
  if (height === 0) {
153
1115
  playerRef.current.configure({
154
- abr: { enabled: true }
1116
+ abr: {
1117
+ enabled: true,
1118
+ switchInterval: 2,
1119
+ // quicker re-checks
1120
+ clearBufferSwitch: true,
1121
+ safeMarginSwitch: 10
1122
+ // leave ~10 s in front of the playhead }
1123
+ }
155
1124
  });
156
1125
  } else {
157
1126
  playerRef.current.configure({
158
- abr: { enabled: false }
1127
+ abr: {
1128
+ enabled: false,
1129
+ switchInterval: 2,
1130
+ // quicker re-checks
1131
+ clearBufferSwitch: true,
1132
+ safeMarginSwitch: 10
1133
+ // leave ~10 s in front of the playhead }
1134
+ }
159
1135
  });
160
1136
  const tracks = playerRef.current.getVariantTracks();
161
1137
  const targetTrack = tracks.find((track) => track.height === height);
@@ -234,14 +1210,14 @@ var useSkipControls = (videoRef, onSkipBack, onSkipForward) => {
234
1210
 
235
1211
  // src/hooks/useMuxAnalytics.ts
236
1212
  var import_react4 = require("react");
237
- var import_mux_data_shakaplayer = __toESM(require("@mux/mux-data-shakaplayer"));
1213
+ var import_mux_data_shakaplayer2 = __toESM(require("@mux/mux-data-shakaplayer"));
238
1214
  var import_shaka_player2 = __toESM(require("shaka-player/dist/shaka-player.ui"));
239
1215
  var useMuxAnalytics = (playerRef, muxConfig, onMuxReady, onMuxDataUpdate) => {
240
1216
  const shakaPlayerMuxRef = (0, import_react4.useRef)(null);
241
1217
  const initializeMux = (0, import_react4.useCallback)(() => {
242
1218
  if (!muxConfig || !playerRef.current) return;
243
1219
  try {
244
- const playerInitTime = import_mux_data_shakaplayer.default.utils.now();
1220
+ const playerInitTime = import_mux_data_shakaplayer2.default.utils.now();
245
1221
  const muxOptions = {
246
1222
  debug: muxConfig.debug || false,
247
1223
  disableCookies: muxConfig.disableCookies || false,
@@ -251,13 +1227,16 @@ var useMuxAnalytics = (playerRef, muxConfig, onMuxReady, onMuxDataUpdate) => {
251
1227
  ...muxConfig.errorTranslator && { errorTranslator: muxConfig.errorTranslator },
252
1228
  data: {
253
1229
  env_key: muxConfig.envKey,
254
- player_name: "Motto Video Player",
255
- player_version: "1.0.0",
1230
+ player_name: muxConfig?.metadata?.player_name,
1231
+ player_version: version,
256
1232
  player_init_time: playerInitTime,
1233
+ video_title: muxConfig?.metadata?.video_title ?? "",
1234
+ video_id: muxConfig?.metadata?.video_id ?? "",
1235
+ viewer_user_id: muxConfig?.metadata?.viewer_user_id ?? "",
257
1236
  ...muxConfig.metadata
258
1237
  }
259
1238
  };
260
- shakaPlayerMuxRef.current = (0, import_mux_data_shakaplayer.default)(playerRef.current, muxOptions, import_shaka_player2.default);
1239
+ shakaPlayerMuxRef.current = (0, import_mux_data_shakaplayer2.default)(playerRef.current, muxOptions, import_shaka_player2.default);
261
1240
  onMuxReady?.();
262
1241
  } catch (error) {
263
1242
  console.error("Failed to initialize Mux Analytics:", error);
@@ -300,10 +1279,157 @@ var useMuxAnalytics = (playerRef, muxConfig, onMuxReady, onMuxDataUpdate) => {
300
1279
  };
301
1280
 
302
1281
  // src/hooks/useShakaUI.ts
303
- var import_react5 = require("react");
1282
+ var import_react6 = require("react");
304
1283
  var import_shaka_player3 = require("shaka-player/dist/shaka-player.ui");
1284
+
1285
+ // src/icons/SkipBackIcon.tsx
1286
+ var import_jsx_runtime = require("react/jsx-runtime");
1287
+ var SkipBackIcon = ({ size = 24, className = "" }) => {
1288
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1289
+ "svg",
1290
+ {
1291
+ width: size,
1292
+ height: size,
1293
+ strokeWidth: "2",
1294
+ viewBox: "0 0 24 24",
1295
+ fill: "none",
1296
+ xmlns: "http://www.w3.org/2000/svg",
1297
+ className,
1298
+ children: [
1299
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1300
+ "path",
1301
+ {
1302
+ d: "M3 13C3 17.9706 7.02944 22 12 22C16.9706 22 21 17.9706 21 13C21 8.02944 16.9706 4 12 4",
1303
+ stroke: "currentColor",
1304
+ strokeWidth: "2",
1305
+ strokeLinecap: "round",
1306
+ strokeLinejoin: "round"
1307
+ }
1308
+ ),
1309
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1310
+ "path",
1311
+ {
1312
+ d: "M9 9L9 16",
1313
+ stroke: "currentColor",
1314
+ strokeWidth: "2",
1315
+ strokeLinecap: "round",
1316
+ strokeLinejoin: "round"
1317
+ }
1318
+ ),
1319
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1320
+ "path",
1321
+ {
1322
+ 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",
1323
+ stroke: "currentColor",
1324
+ strokeWidth: "2",
1325
+ strokeLinecap: "round",
1326
+ strokeLinejoin: "round"
1327
+ }
1328
+ ),
1329
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1330
+ "path",
1331
+ {
1332
+ d: "M12 4L4.5 4M4.5 4L6.5 2M4.5 4L6.5 6",
1333
+ stroke: "currentColor",
1334
+ strokeWidth: "2",
1335
+ strokeLinecap: "round",
1336
+ strokeLinejoin: "round"
1337
+ }
1338
+ )
1339
+ ]
1340
+ }
1341
+ );
1342
+ };
1343
+
1344
+ // src/icons/SkipForwardIcon.tsx
1345
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1346
+ var SkipForwardIcon = ({ size = 24, className = "" }) => {
1347
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1348
+ "svg",
1349
+ {
1350
+ width: size,
1351
+ height: size,
1352
+ strokeWidth: "2",
1353
+ viewBox: "0 0 24 24",
1354
+ fill: "none",
1355
+ xmlns: "http://www.w3.org/2000/svg",
1356
+ className,
1357
+ children: [
1358
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1359
+ "path",
1360
+ {
1361
+ d: "M21 13C21 17.9706 16.9706 22 12 22C7.02944 22 3 17.9706 3 13C3 8.02944 7.02944 4 12 4",
1362
+ stroke: "currentColor",
1363
+ strokeLinecap: "round",
1364
+ strokeLinejoin: "round"
1365
+ }
1366
+ ),
1367
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1368
+ "path",
1369
+ {
1370
+ d: "M12 4H19.5M19.5 4L17.5 2M19.5 4L17.5 6",
1371
+ stroke: "currentColor",
1372
+ strokeLinecap: "round",
1373
+ strokeLinejoin: "round"
1374
+ }
1375
+ ),
1376
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1377
+ "path",
1378
+ {
1379
+ d: "M9 9L9 16",
1380
+ stroke: "currentColor",
1381
+ strokeLinecap: "round",
1382
+ strokeLinejoin: "round"
1383
+ }
1384
+ ),
1385
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1386
+ "path",
1387
+ {
1388
+ 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",
1389
+ stroke: "currentColor",
1390
+ strokeLinecap: "round",
1391
+ strokeLinejoin: "round"
1392
+ }
1393
+ )
1394
+ ]
1395
+ }
1396
+ );
1397
+ };
1398
+
1399
+ // src/icons/BigPlayIcon.tsx
1400
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1401
+ var BigPlayIcon = ({ size = 40, className = "" }) => {
1402
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1403
+ "svg",
1404
+ {
1405
+ width: size,
1406
+ height: size,
1407
+ viewBox: "0 0 24 24",
1408
+ fill: "currentColor",
1409
+ xmlns: "http://www.w3.org/2000/svg",
1410
+ className,
1411
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1412
+ "path",
1413
+ {
1414
+ fillRule: "evenodd",
1415
+ 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",
1416
+ clipRule: "evenodd"
1417
+ }
1418
+ )
1419
+ }
1420
+ );
1421
+ };
1422
+
1423
+ // src/utils/renderIcon.ts
1424
+ var import_server = require("react-dom/server");
1425
+ var import_react5 = require("react");
1426
+ var renderIcon = (Component, props = {}) => {
1427
+ return (0, import_server.renderToStaticMarkup)((0, import_react5.createElement)(Component, props));
1428
+ };
1429
+
1430
+ // src/hooks/useShakaUI.ts
305
1431
  var SkipBackButton = class {
306
- constructor(parent, controls, onSkipBack) {
1432
+ constructor(parent, controls, onSkipBack, iconSize = 24) {
307
1433
  this.parent = parent;
308
1434
  this.controls = controls;
309
1435
  this.eventManager = { listen: (element, event, handler) => {
@@ -311,14 +1437,7 @@ var SkipBackButton = class {
311
1437
  } };
312
1438
  this.button_ = document.createElement("button");
313
1439
  this.button_.className = "shaka-button motto-native-skip-button";
314
- this.button_.innerHTML = `
315
- <svg width="24px" stroke-width="2" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
316
- <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>
317
- <path d="M9 9L9 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
318
- <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>
319
- <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>
320
- </svg>
321
- `;
1440
+ this.button_.innerHTML = renderIcon(SkipBackIcon, { size: iconSize });
322
1441
  this.button_.title = "Skip back 15 seconds";
323
1442
  this.button_.setAttribute("aria-label", "Skip back 15 seconds");
324
1443
  this.parent.appendChild(this.button_);
@@ -331,9 +1450,13 @@ var SkipBackButton = class {
331
1450
  }
332
1451
  });
333
1452
  }
1453
+ // Shaka UI will call `release` when the controls are destroyed.
1454
+ // Provide a no-op implementation to avoid TypeErrors.
1455
+ release() {
1456
+ }
334
1457
  };
335
1458
  var SkipForwardButton = class {
336
- constructor(parent, controls, onSkipForward) {
1459
+ constructor(parent, controls, onSkipForward, iconSize = 24) {
337
1460
  this.parent = parent;
338
1461
  this.controls = controls;
339
1462
  this.eventManager = { listen: (element, event, handler) => {
@@ -341,14 +1464,7 @@ var SkipForwardButton = class {
341
1464
  } };
342
1465
  this.button_ = document.createElement("button");
343
1466
  this.button_.className = "shaka-button motto-native-skip-button";
344
- this.button_.innerHTML = `
345
- <svg fill="none" height="24" stroke-width="2" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
346
- <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"/>
347
- <path d="M12 4H19.5M19.5 4L17.5 2M19.5 4L17.5 6" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
348
- <path d="M9 9L9 16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
349
- <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"/>
350
- </svg>
351
- `;
1467
+ this.button_.innerHTML = renderIcon(SkipForwardIcon, { size: iconSize });
352
1468
  this.button_.title = "Skip forward 15 seconds";
353
1469
  this.button_.setAttribute("aria-label", "Skip forward 15 seconds");
354
1470
  this.parent.appendChild(this.button_);
@@ -361,243 +1477,65 @@ var SkipForwardButton = class {
361
1477
  }
362
1478
  });
363
1479
  }
1480
+ release() {
1481
+ }
364
1482
  };
365
1483
  var SkipBackButtonFactory = class {
366
- constructor(onSkipBack) {
1484
+ constructor(onSkipBack, iconSize) {
367
1485
  this.onSkipBack = onSkipBack;
1486
+ this.iconSize = iconSize;
368
1487
  }
369
1488
  create(rootElement, controls) {
370
- return new SkipBackButton(rootElement, controls, this.onSkipBack);
1489
+ return new SkipBackButton(rootElement, controls, this.onSkipBack, this.iconSize);
371
1490
  }
372
1491
  };
373
1492
  var SkipForwardButtonFactory = class {
374
- constructor(onSkipForward) {
1493
+ constructor(onSkipForward, iconSize) {
375
1494
  this.onSkipForward = onSkipForward;
1495
+ this.iconSize = iconSize;
376
1496
  }
377
1497
  create(rootElement, controls) {
378
- return new SkipForwardButton(rootElement, controls, this.onSkipForward);
379
- }
380
- };
381
- var MobilePlayButton = class {
382
- constructor(parent, controls) {
383
- this.parent = parent;
384
- this.controls = controls;
385
- this.video = controls?.getVideo?.() || parent.querySelector("video") || document.querySelector("video");
386
- if (!this.video) {
387
- console.error("MobilePlayButton: No video element found");
388
- return;
389
- }
390
- this.eventManager = { listen: (element, event, handler) => {
391
- element.addEventListener(event, handler);
392
- } };
393
- this.button_ = document.createElement("button");
394
- this.button_.className = "motto-mobile-play-button";
395
- this.updateIcon();
396
- this.parent.appendChild(this.button_);
397
- this.eventManager.listen(this.button_, "click", () => {
398
- if (this.video.paused) {
399
- this.video.play();
400
- } else {
401
- this.video.pause();
402
- }
403
- });
404
- this.eventManager.listen(this.video, "play", () => this.updateIcon());
405
- this.eventManager.listen(this.video, "pause", () => this.updateIcon());
406
- }
407
- updateIcon() {
408
- if (this.video.paused) {
409
- this.button_.innerHTML = `
410
- <svg xmlns="http://www.w3.org/2000/svg" stroke-width="2" viewBox="0 0 24 24" fill="currentColor">
411
- <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" />
412
- </svg>
413
- `;
414
- this.button_.setAttribute("aria-label", "Play");
415
- } else {
416
- this.button_.innerHTML = `
417
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
418
- <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" />
419
- </svg>
420
- `;
421
- this.button_.setAttribute("aria-label", "Pause");
422
- }
423
- }
424
- };
425
- var MobileSkipBackButton = class {
426
- constructor(parent, controls, onSkipBack) {
427
- this.parent = parent;
428
- this.controls = controls;
429
- this.video = controls?.getVideo?.() || parent.querySelector("video") || document.querySelector("video");
430
- if (!this.video) {
431
- console.error("MobileSkipBackButton: No video element found");
432
- return;
433
- }
434
- this.eventManager = { listen: (element, event, handler) => {
435
- element.addEventListener(event, handler);
436
- } };
437
- this.button_ = document.createElement("button");
438
- this.button_.className = "motto-mobile-skip-button";
439
- this.button_.innerHTML = `
440
- <svg width="20px" stroke-width="2" height="20px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
441
- <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>
442
- <path d="M9 9L9 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
443
- <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>
444
- <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>
445
- </svg>
446
- `;
447
- this.button_.setAttribute("aria-label", "Skip back 15 seconds");
448
- this.parent.appendChild(this.button_);
449
- this.eventManager.listen(this.button_, "click", () => {
450
- const newTime = Math.max(0, this.video.currentTime - 15);
451
- this.video.currentTime = newTime;
452
- onSkipBack?.(newTime);
453
- });
1498
+ return new SkipForwardButton(rootElement, controls, this.onSkipForward, this.iconSize);
454
1499
  }
455
1500
  };
456
- var MobileSkipForwardButton = class {
457
- constructor(parent, controls, onSkipForward) {
458
- this.parent = parent;
459
- this.controls = controls;
460
- this.video = controls?.getVideo?.() || parent.querySelector("video") || document.querySelector("video");
461
- if (!this.video) {
462
- console.error("MobileSkipForwardButton: No video element found");
463
- return;
464
- }
465
- this.eventManager = { listen: (element, event, handler) => {
466
- element.addEventListener(event, handler);
467
- } };
468
- this.button_ = document.createElement("button");
469
- this.button_.className = "motto-mobile-skip-button";
470
- this.button_.innerHTML = `
471
- <svg fill="none" height="20" stroke-width="2" viewBox="0 0 24 24" width="20" xmlns="http://www.w3.org/2000/svg">
472
- <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"/>
473
- <path d="M12 4H19.5M19.5 4L17.5 2M19.5 4L17.5 6" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
474
- <path d="M9 9L9 16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
475
- <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"/>
476
- </svg>
477
- `;
478
- this.button_.setAttribute("aria-label", "Skip forward 15 seconds");
479
- this.parent.appendChild(this.button_);
480
- this.eventManager.listen(this.button_, "click", () => {
481
- const newTime = Math.min(this.video.duration || 0, this.video.currentTime + 15);
482
- this.video.currentTime = newTime;
483
- onSkipForward?.(newTime);
484
- });
485
- }
486
- };
487
- var MobileControlsContainer = class {
488
- constructor(parent, controls, onSkipBack, onSkipForward) {
489
- this.parent = parent;
490
- this.controls = controls;
491
- if (!parent) {
492
- console.error("MobileControlsContainer: No parent element provided");
493
- return;
494
- }
495
- this.container_ = document.createElement("div");
496
- this.container_.className = "motto-mobile-controls-overlay";
497
- const controlsGroup = document.createElement("div");
498
- controlsGroup.className = "motto-mobile-controls-group";
499
- new MobileSkipBackButton(controlsGroup, controls, onSkipBack);
500
- new MobilePlayButton(controlsGroup, controls);
501
- new MobileSkipForwardButton(controlsGroup, controls, onSkipForward);
502
- this.container_.appendChild(controlsGroup);
503
- this.parent.appendChild(this.container_);
504
- this.setupVisibilitySync();
505
- }
506
- setupVisibilitySync() {
507
- setTimeout(() => {
508
- this.syncVisibility();
509
- this.observer = new MutationObserver((mutations) => {
510
- mutations.forEach((mutation) => {
511
- if (mutation.type === "attributes" && mutation.attributeName === "class") {
512
- this.syncVisibility();
513
- }
514
- });
515
- });
516
- this.observer.observe(this.parent, {
517
- attributes: true,
518
- attributeFilter: ["class"]
519
- });
520
- const video = this.controls?.getVideo?.() || this.parent.querySelector("video");
521
- if (video) {
522
- video.addEventListener("play", () => {
523
- setTimeout(() => this.syncVisibility(), 50);
524
- });
525
- video.addEventListener("pause", () => {
526
- setTimeout(() => this.syncVisibility(), 50);
527
- });
528
- }
529
- }, 1e3);
530
- }
531
- syncVisibility() {
532
- const mainContainer = this.parent;
533
- const hasNoCursor = mainContainer.classList.contains("no-cursor");
534
- const video = this.controls?.getVideo?.() || this.parent.querySelector("video");
535
- const isVideoPaused = video ? video.paused : false;
536
- const isControlsVisible = !hasNoCursor || isVideoPaused;
537
- if (this.container_) {
538
- if (isControlsVisible) {
539
- this.container_.style.opacity = "1";
540
- this.container_.style.pointerEvents = "none";
541
- } else {
542
- this.container_.style.opacity = "0";
543
- this.container_.style.pointerEvents = "none";
544
- }
545
- }
546
- }
547
- isElementVisible(element) {
548
- const style = window.getComputedStyle(element);
549
- const hasHiddenClass = element.classList.contains("shaka-hidden") || element.classList.contains("hidden") || element.classList.contains("shaka-fade-out");
550
- return style.display !== "none" && style.visibility !== "hidden" && style.opacity !== "0" && !element.hidden && !hasHiddenClass;
551
- }
552
- };
553
- var MobileControlsContainerFactory = class {
554
- constructor(onSkipBack, onSkipForward) {
555
- this.onSkipBack = onSkipBack;
556
- this.onSkipForward = onSkipForward;
557
- }
558
- create(rootElement, controls) {
559
- return new MobileControlsContainer(rootElement, controls, this.onSkipBack, this.onSkipForward);
560
- }
561
- };
562
- var useShakaUI = (playerRef, containerRef, videoRef, controls, chromecastConfig, seekbarColors, onSkipBack, onSkipForward) => {
563
- const uiRef = (0, import_react5.useRef)(null);
564
- const registeredElements = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
565
- const initializeUI = (0, import_react5.useCallback)(async () => {
1501
+ var useShakaUI = (playerRef, containerRef, videoRef, controls, chromecastConfig, seekbarColors, onSkipBack, onSkipForward, iconSizes, locale = "en") => {
1502
+ const uiRef = (0, import_react6.useRef)(null);
1503
+ const registeredElements = (0, import_react6.useRef)(/* @__PURE__ */ new Set());
1504
+ const initializeUI = (0, import_react6.useCallback)(async () => {
566
1505
  if (!controls || !containerRef.current || !playerRef.current || !videoRef.current) {
567
1506
  return null;
568
1507
  }
569
- const isMobile = window.innerWidth <= 767 || /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
570
1508
  if (!registeredElements.current.has("skip_back_button")) {
571
- import_shaka_player3.ui.Controls.registerElement("skip_back_button", new SkipBackButtonFactory(onSkipBack));
1509
+ import_shaka_player3.ui.Controls.registerElement("skip_back_button", new SkipBackButtonFactory(onSkipBack, iconSizes?.skipButtons));
572
1510
  registeredElements.current.add("skip_back_button");
573
1511
  }
574
1512
  if (!registeredElements.current.has("skip_forward_button")) {
575
- import_shaka_player3.ui.Controls.registerElement("skip_forward_button", new SkipForwardButtonFactory(onSkipForward));
1513
+ import_shaka_player3.ui.Controls.registerElement("skip_forward_button", new SkipForwardButtonFactory(onSkipForward, iconSizes?.skipButtons));
576
1514
  registeredElements.current.add("skip_forward_button");
577
1515
  }
578
- if (isMobile) {
579
- if (!registeredElements.current.has("mobile_controls_container")) {
580
- import_shaka_player3.ui.Controls.registerElement("mobile_controls_container", new MobileControlsContainerFactory(onSkipBack, onSkipForward));
581
- registeredElements.current.add("mobile_controls_container");
582
- }
583
- }
584
1516
  const ui = new import_shaka_player3.ui.Overlay(playerRef.current, containerRef.current, videoRef.current);
585
1517
  uiRef.current = ui;
586
- const controlPanelElements = isMobile ? [
587
- "mute",
588
- "time_and_duration",
589
- "spacer",
590
- "fullscreen",
591
- "overflow_menu"
592
- ] : [
593
- "skip_back_button",
594
- "play_pause",
595
- "skip_forward_button",
1518
+ if (locale !== "en") {
1519
+ try {
1520
+ ui.getControls().getLocalization().changeLocale([locale]);
1521
+ console.log(`Set locale to '${locale}'`);
1522
+ } catch (error) {
1523
+ console.warn(`Failed to set locale to '${locale}', falling back to 'en':`, error);
1524
+ }
1525
+ }
1526
+ const isMobile = window.innerWidth <= 767;
1527
+ const controlPanelElements = [
1528
+ ...isMobile ? [] : ["skip_back_button"],
1529
+ ...isMobile ? [] : ["play_pause"],
1530
+ ...isMobile ? [] : ["skip_forward_button"],
596
1531
  "mute",
597
- "volume",
1532
+ ...isMobile ? [] : ["volume"],
1533
+ // Only include volume on desktop
598
1534
  "time_and_duration",
599
1535
  "spacer",
600
1536
  "fullscreen",
1537
+ "cast",
1538
+ // Always show cast button
601
1539
  "overflow_menu"
602
1540
  ];
603
1541
  const uiConfig = {
@@ -610,35 +1548,58 @@ var useShakaUI = (playerRef, containerRef, videoRef, controls, chromecastConfig,
610
1548
  // Progress/played portion (white)
611
1549
  },
612
1550
  controlPanelElements,
613
- ...chromecastConfig?.receiverApplicationId && {
614
- "castReceiverAppId": chromecastConfig.receiverApplicationId,
615
- "castAndroidReceiverCompatible": false
616
- }
1551
+ addBigPlayButton: isMobile,
1552
+ // For now, Chromecast via Shaka must use the Motto receiver that runs on the legacy cast SDK (2.0), because
1553
+ // Shaka does not support the newer Cast SDK (3.0+) in its native integration.
1554
+ castReceiverAppId: "EC900D4D",
1555
+ castAndroidReceiverCompatible: true,
1556
+ // Enable Android TV compatibility
1557
+ overflowMenuButtons: [
1558
+ "quality",
1559
+ "picture_in_picture",
1560
+ "playback_rate"
1561
+ ]
617
1562
  };
618
- if (chromecastConfig?.receiverApplicationId) {
619
- uiConfig.castReceiverAppId = chromecastConfig.receiverApplicationId;
620
- uiConfig.castAndroidReceiverCompatible = false;
621
- }
622
1563
  ui.configure(uiConfig);
623
1564
  if (isMobile) {
624
- setTimeout(() => {
625
- const container = containerRef.current;
626
- const video = videoRef.current;
627
- if (container && video) {
628
- new MobileControlsContainer(container, { getVideo: () => video }, onSkipBack, onSkipForward);
1565
+ const customizeBigPlayButton = () => {
1566
+ const bigPlayButton = containerRef.current?.querySelector(".shaka-big-play-button");
1567
+ if (bigPlayButton && !bigPlayButton.hasAttribute("data-customized")) {
1568
+ const buttonSize = iconSizes?.bigPlayButton || 40;
1569
+ bigPlayButton.innerHTML = renderIcon(BigPlayIcon, { size: buttonSize });
1570
+ bigPlayButton.setAttribute("data-customized", "true");
1571
+ const buttonElement = bigPlayButton;
1572
+ buttonElement.style.display = "flex";
1573
+ buttonElement.style.alignItems = "center";
1574
+ buttonElement.style.justifyContent = "center";
629
1575
  }
630
- }, 500);
1576
+ };
1577
+ setTimeout(customizeBigPlayButton, 100);
1578
+ const observer = new MutationObserver(() => {
1579
+ customizeBigPlayButton();
1580
+ });
1581
+ if (containerRef.current) {
1582
+ observer.observe(containerRef.current, {
1583
+ childList: true,
1584
+ subtree: true,
1585
+ attributes: false
1586
+ });
1587
+ }
631
1588
  }
632
1589
  return ui;
633
- }, [controls, containerRef, playerRef, videoRef, chromecastConfig, seekbarColors, onSkipBack, onSkipForward]);
634
- const destroyUI = (0, import_react5.useCallback)(() => {
635
- if (uiRef.current) {
1590
+ }, [controls, containerRef, playerRef, videoRef, chromecastConfig, seekbarColors, onSkipBack, onSkipForward, iconSizes, locale]);
1591
+ const destroyUI = (0, import_react6.useCallback)(async () => {
1592
+ const uiInstance = uiRef.current;
1593
+ if (uiInstance) {
636
1594
  try {
637
- uiRef.current.destroy();
1595
+ await uiInstance.destroy();
638
1596
  } catch (error) {
639
1597
  console.error("Error destroying UI:", error);
1598
+ } finally {
1599
+ if (uiRef.current === uiInstance) {
1600
+ uiRef.current = null;
1601
+ }
640
1602
  }
641
- uiRef.current = null;
642
1603
  }
643
1604
  }, []);
644
1605
  return {
@@ -649,9 +1610,9 @@ var useShakaUI = (playerRef, containerRef, videoRef, controls, chromecastConfig,
649
1610
  };
650
1611
 
651
1612
  // src/hooks/useEventHandlers.ts
652
- var import_react6 = require("react");
1613
+ var import_react7 = require("react");
653
1614
  var useEventHandlers = (videoRef, handlers) => {
654
- const setupEventListeners = (0, import_react6.useCallback)(() => {
1615
+ const setupEventListeners = (0, import_react7.useCallback)(() => {
655
1616
  const video = videoRef.current;
656
1617
  if (!video) return;
657
1618
  const { onPlay, onPause, onEnded, onLoadStart, onCanPlay } = handlers;
@@ -661,88 +1622,19 @@ var useEventHandlers = (videoRef, handlers) => {
661
1622
  if (onLoadStart) video.addEventListener("loadstart", onLoadStart);
662
1623
  if (onCanPlay) video.addEventListener("canplay", onCanPlay);
663
1624
  }, [videoRef, handlers]);
664
- const cleanupEventListeners = (0, import_react6.useCallback)(() => {
1625
+ const cleanupEventListeners = (0, import_react7.useCallback)(() => {
665
1626
  const video = videoRef.current;
666
- if (!video) return;
667
- const { onPlay, onPause, onEnded, onLoadStart, onCanPlay } = handlers;
668
- if (onPlay) video.removeEventListener("play", onPlay);
669
- if (onPause) video.removeEventListener("pause", onPause);
670
- if (onEnded) video.removeEventListener("ended", onEnded);
671
- if (onLoadStart) video.removeEventListener("loadstart", onLoadStart);
672
- if (onCanPlay) video.removeEventListener("canplay", onCanPlay);
673
- }, [videoRef, handlers]);
674
- return {
675
- setupEventListeners,
676
- cleanupEventListeners
677
- };
678
- };
679
-
680
- // src/hooks/useLiveBadge.ts
681
- var import_react7 = require("react");
682
- var useLiveBadge = (playerRef, options = {}) => {
683
- const [isLive, setIsLive] = (0, import_react7.useState)(false);
684
- const [isVisible, setIsVisible] = (0, import_react7.useState)(false);
685
- const intervalRef = (0, import_react7.useRef)(null);
686
- const { enabled = true, onLiveStateChange } = options;
687
- const checkLiveStatus = () => {
688
- if (!playerRef.current || !enabled) {
689
- return;
690
- }
691
- try {
692
- const player = playerRef.current;
693
- if (!player.getManifest || !player.getPresentationTimeline || typeof player.getPresentationTimeline !== "function") {
694
- return;
695
- }
696
- const manifest = player.getManifest();
697
- if (!manifest) {
698
- return;
699
- }
700
- const timeline = player.getPresentationTimeline();
701
- if (!timeline || typeof timeline.isLive !== "function") {
702
- return;
703
- }
704
- const liveStatus = timeline.isLive();
705
- if (liveStatus !== isLive) {
706
- setIsLive(liveStatus);
707
- setIsVisible(liveStatus);
708
- onLiveStateChange?.(liveStatus);
709
- }
710
- } catch (error) {
711
- if (error instanceof Error && !error.message.includes("not a function")) {
712
- console.error("Error checking live status:", error);
713
- }
714
- }
715
- };
716
- (0, import_react7.useEffect)(() => {
717
- if (!enabled) {
718
- setIsLive(false);
719
- setIsVisible(false);
720
- return;
721
- }
722
- checkLiveStatus();
723
- intervalRef.current = setInterval(checkLiveStatus, 2e3);
724
- return () => {
725
- if (intervalRef.current) {
726
- clearInterval(intervalRef.current);
727
- intervalRef.current = null;
728
- }
729
- };
730
- }, [enabled, playerRef.current]);
731
- (0, import_react7.useEffect)(() => {
732
- return () => {
733
- if (intervalRef.current) {
734
- clearInterval(intervalRef.current);
735
- }
736
- };
737
- }, []);
738
- const hideBadge = () => setIsVisible(false);
739
- const showBadge = () => setIsVisible(true);
1627
+ if (!video) return;
1628
+ const { onPlay, onPause, onEnded, onLoadStart, onCanPlay } = handlers;
1629
+ if (onPlay) video.removeEventListener("play", onPlay);
1630
+ if (onPause) video.removeEventListener("pause", onPause);
1631
+ if (onEnded) video.removeEventListener("ended", onEnded);
1632
+ if (onLoadStart) video.removeEventListener("loadstart", onLoadStart);
1633
+ if (onCanPlay) video.removeEventListener("canplay", onCanPlay);
1634
+ }, [videoRef, handlers]);
740
1635
  return {
741
- isLive,
742
- isVisible,
743
- hideBadge,
744
- showBadge,
745
- checkLiveStatus
1636
+ setupEventListeners,
1637
+ cleanupEventListeners
746
1638
  };
747
1639
  };
748
1640
 
@@ -751,54 +1643,148 @@ var import_react8 = require("react");
751
1643
 
752
1644
  // src/hooks/useLiveIndicator.ts
753
1645
  var import_react9 = require("react");
754
- var useLiveIndicator = (containerRef, options = {}) => {
1646
+ var useLiveIndicator = (containerRef, playerRef, options = {}) => {
755
1647
  const observerRef = (0, import_react9.useRef)(null);
1648
+ const intervalRef = (0, import_react9.useRef)(null);
1649
+ const lastStatusRef = (0, import_react9.useRef)(null);
756
1650
  const {
757
1651
  enabled = true,
758
1652
  indicatorColor = "#ff0000",
759
1653
  indicatorSize = 8,
760
- showPulseAnimation = true
1654
+ showPulseAnimation = true,
1655
+ liveThresholdSeconds = 15,
1656
+ onLiveStatusChange
761
1657
  } = options;
1658
+ const getLiveStatus = (player) => {
1659
+ if (!player) {
1660
+ return { isLive: false, isNearEdge: false };
1661
+ }
1662
+ try {
1663
+ if (!player.getManifest || typeof player.getManifest !== "function") {
1664
+ return { isLive: false, isNearEdge: false };
1665
+ }
1666
+ const manifest = player.getManifest();
1667
+ if (!manifest) {
1668
+ return { isLive: false, isNearEdge: false };
1669
+ }
1670
+ const timeline = manifest.presentationTimeline;
1671
+ if (!timeline || typeof timeline.isLive !== "function") {
1672
+ return { isLive: false, isNearEdge: false };
1673
+ }
1674
+ const isLiveStream = timeline.isLive();
1675
+ if (!isLiveStream) return { isLive: false, isNearEdge: false };
1676
+ const videoElement = player.getMediaElement?.();
1677
+ if (!videoElement) return { isLive: true, isNearEdge: false };
1678
+ const liveEdge = timeline.getSeekRangeEnd?.() ?? timeline.getSegmentAvailabilityEnd?.();
1679
+ if (liveEdge === void 0) return { isLive: true, isNearEdge: false };
1680
+ const currentTime = videoElement.currentTime;
1681
+ const timeBehindLive = liveEdge - currentTime;
1682
+ return {
1683
+ isLive: true,
1684
+ isNearEdge: timeBehindLive <= liveThresholdSeconds,
1685
+ liveEdge
1686
+ };
1687
+ } catch (error) {
1688
+ console.error("Error checking live status:", error);
1689
+ return { isLive: false, isNearEdge: false };
1690
+ }
1691
+ };
1692
+ const seekToLiveEdge = () => {
1693
+ const player = playerRef.current;
1694
+ if (!player) return;
1695
+ try {
1696
+ const manifest = player.getManifest();
1697
+ if (!manifest) return;
1698
+ const timeline = manifest.presentationTimeline;
1699
+ const liveEdge = timeline?.getSeekRangeEnd?.() ?? timeline?.getSegmentAvailabilityEnd?.();
1700
+ if (liveEdge !== void 0) {
1701
+ const videoElement = player.getMediaElement?.();
1702
+ if (videoElement) {
1703
+ videoElement.currentTime = liveEdge;
1704
+ }
1705
+ }
1706
+ } catch (error) {
1707
+ console.error("Error seeking to live edge:", error);
1708
+ }
1709
+ };
762
1710
  (0, import_react9.useEffect)(() => {
763
1711
  if (!containerRef.current || !enabled) {
764
1712
  return;
765
1713
  }
766
- const addLiveIndicator = (currentTimeElement) => {
767
- if (currentTimeElement.querySelector(".live-indicator-dot")) {
1714
+ const updateLiveIndicator = (currentTimeElement, status) => {
1715
+ const parent = currentTimeElement.parentElement;
1716
+ if (!parent) return;
1717
+ const existingContainer = parent.querySelector(".live-indicator-container");
1718
+ const isCurrentlyNearEdge = existingContainer?.getAttribute("data-near-edge") === "true";
1719
+ if (existingContainer && status.isNearEdge === isCurrentlyNearEdge) {
768
1720
  return;
769
1721
  }
1722
+ if (existingContainer) {
1723
+ existingContainer.remove();
1724
+ }
1725
+ const container = document.createElement("span");
1726
+ container.className = "live-indicator-container";
1727
+ container.setAttribute("data-near-edge", status.isNearEdge.toString());
1728
+ container.style.cssText = `
1729
+ display: inline-flex;
1730
+ align-items: center;
1731
+ width: 80px;
1732
+ ${!status.isNearEdge ? "cursor: pointer;" : ""}
1733
+ `;
770
1734
  const indicator = document.createElement("span");
771
1735
  indicator.className = "live-indicator-dot";
772
1736
  indicator.style.cssText = `
773
1737
  display: inline-block;
774
1738
  width: ${indicatorSize}px;
775
1739
  height: ${indicatorSize}px;
776
- background-color: ${indicatorColor};
1740
+ background-color: ${status.isNearEdge ? indicatorColor : "#888888"};
777
1741
  border-radius: 50%;
778
1742
  margin-right: 6px;
779
- vertical-align: middle;
780
- ${showPulseAnimation ? "animation: pulse-live 2s infinite;" : ""}
1743
+ ${status.isNearEdge && showPulseAnimation ? "animation: pulse-live 2s infinite;" : ""}
781
1744
  `;
782
- currentTimeElement.insertBefore(indicator, currentTimeElement.firstChild);
1745
+ const liveText = document.createElement("span");
1746
+ liveText.className = "live-indicator-text";
1747
+ liveText.textContent = status.isNearEdge ? "LIVE" : "GO TO LIVE";
1748
+ container.appendChild(indicator);
1749
+ container.appendChild(liveText);
1750
+ if (!status.isNearEdge) {
1751
+ container.addEventListener("click", seekToLiveEdge);
1752
+ }
1753
+ if (status.isNearEdge) {
1754
+ parent.insertBefore(container, currentTimeElement);
1755
+ currentTimeElement.style.display = "none";
1756
+ } else {
1757
+ currentTimeElement.insertAdjacentElement("afterend", container);
1758
+ currentTimeElement.style.display = "";
1759
+ }
783
1760
  };
784
1761
  const removeLiveIndicator = (currentTimeElement) => {
785
- const indicator = currentTimeElement.querySelector(".live-indicator-dot");
786
- if (indicator) {
787
- indicator.remove();
1762
+ const parent = currentTimeElement.parentElement;
1763
+ if (!parent) return;
1764
+ const container = parent.querySelector(".live-indicator-container");
1765
+ if (container) {
1766
+ container.remove();
1767
+ currentTimeElement.style.display = "";
788
1768
  }
789
1769
  };
790
1770
  const checkForLiveContent = () => {
791
1771
  const currentTimeElements = containerRef.current?.querySelectorAll(".shaka-current-time");
1772
+ const status = getLiveStatus(playerRef.current);
1773
+ const lastStatus = lastStatusRef.current;
1774
+ if (onLiveStatusChange && (!lastStatus || lastStatus.isLive !== status.isLive || lastStatus.isNearEdge !== status.isNearEdge)) {
1775
+ onLiveStatusChange(status);
1776
+ lastStatusRef.current = { isLive: status.isLive, isNearEdge: status.isNearEdge };
1777
+ }
792
1778
  currentTimeElements?.forEach((element) => {
793
- const textContent = element.textContent?.trim() || "";
794
- if (textContent.toLowerCase().includes("live")) {
795
- addLiveIndicator(element);
1779
+ if (status.isLive) {
1780
+ updateLiveIndicator(element, status);
796
1781
  } else {
797
1782
  removeLiveIndicator(element);
798
1783
  }
799
1784
  });
800
1785
  };
801
1786
  checkForLiveContent();
1787
+ intervalRef.current = setInterval(checkForLiveContent, 1e3);
802
1788
  observerRef.current = new MutationObserver((mutations) => {
803
1789
  let shouldCheck = false;
804
1790
  mutations.forEach((mutation) => {
@@ -824,31 +1810,289 @@ var useLiveIndicator = (containerRef, options = {}) => {
824
1810
  characterData: true,
825
1811
  characterDataOldValue: true
826
1812
  });
827
- const intervalId = setInterval(checkForLiveContent, 1e3);
828
1813
  return () => {
829
1814
  if (observerRef.current) {
830
1815
  observerRef.current.disconnect();
831
1816
  }
832
- clearInterval(intervalId);
1817
+ if (intervalRef.current) {
1818
+ clearInterval(intervalRef.current);
1819
+ }
833
1820
  };
834
- }, [containerRef, enabled, indicatorColor, indicatorSize, showPulseAnimation]);
1821
+ }, [containerRef, enabled, indicatorColor, indicatorSize, showPulseAnimation, liveThresholdSeconds]);
835
1822
  return {
836
- // Expose method to manually trigger check if needed
837
- checkForLiveContent: () => {
838
- const currentTimeElements = containerRef.current?.querySelectorAll(".shaka-current-time");
839
- currentTimeElements?.forEach((element) => {
840
- const textContent = element.textContent?.trim() || "";
841
- if (textContent.toLowerCase().includes("live")) {
1823
+ seekToLiveEdge,
1824
+ getLiveStatus: () => getLiveStatus(playerRef.current)
1825
+ };
1826
+ };
1827
+
1828
+ // src/hooks/useKeyboardControls.ts
1829
+ var import_react10 = require("react");
1830
+ var useKeyboardControls = (videoRef, options = {}) => {
1831
+ const { skipBack, skipForward, enabled = true } = options;
1832
+ const isDesktop = (0, import_react10.useCallback)(() => {
1833
+ return window.innerWidth > 767 && !/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
1834
+ }, []);
1835
+ const handleKeydown = (0, import_react10.useCallback)((event) => {
1836
+ if (!enabled || !isDesktop() || !videoRef.current) return;
1837
+ const activeElement = document.activeElement;
1838
+ if (activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.isContentEditable)) {
1839
+ return;
1840
+ }
1841
+ switch (event.key) {
1842
+ case "ArrowLeft":
1843
+ event.preventDefault();
1844
+ skipBack?.();
1845
+ break;
1846
+ case "ArrowRight":
1847
+ event.preventDefault();
1848
+ skipForward?.();
1849
+ break;
1850
+ case " ":
1851
+ case "Space":
1852
+ event.preventDefault();
1853
+ if (videoRef.current.paused) {
1854
+ videoRef.current.play();
1855
+ } else {
1856
+ videoRef.current.pause();
1857
+ }
1858
+ break;
1859
+ }
1860
+ }, [enabled, videoRef, skipBack, skipForward, isDesktop]);
1861
+ (0, import_react10.useEffect)(() => {
1862
+ if (!enabled || !isDesktop()) return;
1863
+ document.addEventListener("keydown", handleKeydown);
1864
+ return () => {
1865
+ document.removeEventListener("keydown", handleKeydown);
1866
+ };
1867
+ }, [handleKeydown, enabled, isDesktop]);
1868
+ return {
1869
+ isDesktop: isDesktop()
1870
+ };
1871
+ };
1872
+
1873
+ // src/hooks/useAdEvents.ts
1874
+ var import_react11 = require("react");
1875
+ var useAdEvents = (playerRef, handlers) => {
1876
+ const listenersRef = (0, import_react11.useRef)([]);
1877
+ const setupAdEventListeners = (0, import_react11.useCallback)(() => {
1878
+ const player = playerRef.current;
1879
+ if (!player) return;
1880
+ const adManager = player.getAdManager();
1881
+ if (!adManager) return;
1882
+ const onAdsManagerLoaded = (event) => {
1883
+ const adsManager = event.getAdsManager();
1884
+ const onAdStarted = () => {
1885
+ console.log("Ad started");
1886
+ handlers.onAdStart?.();
1887
+ };
1888
+ const onAdComplete = () => {
1889
+ console.log("Ad completed");
1890
+ handlers.onAdComplete?.();
1891
+ };
1892
+ const onAdError = (adErrorEvent) => {
1893
+ console.error("Ad error:", adErrorEvent.getError());
1894
+ handlers.onAdError?.(adErrorEvent.getError());
1895
+ };
1896
+ const onAdSkipped = () => {
1897
+ console.log("Ad skipped");
1898
+ handlers.onAdSkipped?.();
1899
+ };
1900
+ const onAdPaused = () => {
1901
+ console.log("Ad paused");
1902
+ handlers.onAdPaused?.();
1903
+ };
1904
+ const onAdResumed = () => {
1905
+ console.log("Ad resumed");
1906
+ handlers.onAdResumed?.();
1907
+ };
1908
+ const onAdProgress = (adProgressData) => {
1909
+ handlers.onAdProgress?.(adProgressData);
1910
+ };
1911
+ const onAllAdsCompleted = () => {
1912
+ console.log("All ads completed");
1913
+ handlers.onAllAdsCompleted?.();
1914
+ };
1915
+ const adEventListeners = [];
1916
+ if (window.google?.ima) {
1917
+ const AdEvent = window.google.ima.AdEvent.Type;
1918
+ const AdErrorEvent = window.google.ima.AdErrorEvent.Type;
1919
+ if (handlers.onAdStart) {
1920
+ adsManager.addEventListener(AdEvent.STARTED, onAdStarted);
1921
+ adEventListeners.push({ event: AdEvent.STARTED, listener: onAdStarted });
1922
+ }
1923
+ if (handlers.onAdComplete) {
1924
+ adsManager.addEventListener(AdEvent.COMPLETE, onAdComplete);
1925
+ adEventListeners.push({ event: AdEvent.COMPLETE, listener: onAdComplete });
1926
+ }
1927
+ if (handlers.onAdError) {
1928
+ adsManager.addEventListener(AdErrorEvent.AD_ERROR, onAdError);
1929
+ adEventListeners.push({ event: AdErrorEvent.AD_ERROR, listener: onAdError });
1930
+ }
1931
+ if (handlers.onAdSkipped) {
1932
+ adsManager.addEventListener(AdEvent.SKIPPED, onAdSkipped);
1933
+ adEventListeners.push({ event: AdEvent.SKIPPED, listener: onAdSkipped });
1934
+ }
1935
+ if (handlers.onAdPaused) {
1936
+ adsManager.addEventListener(AdEvent.PAUSED, onAdPaused);
1937
+ adEventListeners.push({ event: AdEvent.PAUSED, listener: onAdPaused });
1938
+ }
1939
+ if (handlers.onAdResumed) {
1940
+ adsManager.addEventListener(AdEvent.RESUMED, onAdResumed);
1941
+ adEventListeners.push({ event: AdEvent.RESUMED, listener: onAdResumed });
1942
+ }
1943
+ if (handlers.onAdProgress) {
1944
+ adsManager.addEventListener(AdEvent.AD_PROGRESS, onAdProgress);
1945
+ adEventListeners.push({ event: AdEvent.AD_PROGRESS, listener: onAdProgress });
1946
+ }
1947
+ if (handlers.onAllAdsCompleted) {
1948
+ adsManager.addEventListener(AdEvent.ALL_ADS_COMPLETED, onAllAdsCompleted);
1949
+ adEventListeners.push({ event: AdEvent.ALL_ADS_COMPLETED, listener: onAllAdsCompleted });
1950
+ }
1951
+ listenersRef.current.push({
1952
+ adsManager,
1953
+ listeners: adEventListeners
1954
+ });
1955
+ }
1956
+ };
1957
+ try {
1958
+ player.addEventListener("ad-started", () => {
1959
+ console.log("Shaka ad-started event");
1960
+ handlers.onAdStart?.();
1961
+ });
1962
+ player.addEventListener("ad-complete", () => {
1963
+ console.log("Shaka ad-complete event");
1964
+ handlers.onAdComplete?.();
1965
+ });
1966
+ player.addEventListener("ad-skipped", () => {
1967
+ console.log("Shaka ad-skipped event");
1968
+ handlers.onAdSkipped?.();
1969
+ });
1970
+ player.addEventListener("ad-error", (event) => {
1971
+ console.error("Shaka ad-error event:", event);
1972
+ handlers.onAdError?.(event);
1973
+ });
1974
+ listenersRef.current.push({
1975
+ type: "shaka",
1976
+ player,
1977
+ events: ["ad-started", "ad-complete", "ad-skipped", "ad-error"]
1978
+ });
1979
+ } catch (error) {
1980
+ console.warn("Error setting up ad event listeners:", error);
1981
+ }
1982
+ }, [playerRef, handlers]);
1983
+ const cleanupAdEventListeners = (0, import_react11.useCallback)(() => {
1984
+ try {
1985
+ listenersRef.current.forEach((listenerGroup) => {
1986
+ if (listenerGroup.type === "shaka" && listenerGroup.player) {
1987
+ listenerGroup.events.forEach((eventName) => {
1988
+ try {
1989
+ listenerGroup.player.removeEventListener(eventName, () => {
1990
+ });
1991
+ } catch (e) {
1992
+ console.warn(`Error removing ${eventName} listener:`, e);
1993
+ }
1994
+ });
1995
+ } else if (listenerGroup.adsManager && listenerGroup.listeners) {
1996
+ listenerGroup.listeners.forEach(({ event, listener }) => {
1997
+ try {
1998
+ listenerGroup.adsManager.removeEventListener(event, listener);
1999
+ } catch (e) {
2000
+ console.warn("Error removing ad listener:", e);
2001
+ }
2002
+ });
842
2003
  }
843
2004
  });
2005
+ listenersRef.current = [];
2006
+ } catch (error) {
2007
+ console.warn("Error cleaning up ad event listeners:", error);
844
2008
  }
2009
+ }, []);
2010
+ return {
2011
+ setupAdEventListeners,
2012
+ cleanupAdEventListeners
845
2013
  };
846
2014
  };
847
2015
 
2016
+ // src/Player.tsx
2017
+ var import_tailwind_merge2 = require("tailwind-merge");
2018
+
2019
+ // src/utils/scriptLoader.ts
2020
+ var SCRIPT_CONFIGS = {
2021
+ ima: {
2022
+ src: "https://imasdk.googleapis.com/js/sdkloader/ima3.js",
2023
+ id: "ima-sdk",
2024
+ type: "text/javascript"
2025
+ },
2026
+ system73: {
2027
+ src: "//cdn.s73cloud.com/4/s73-sdk-shakaplayer.js",
2028
+ id: "system73-sdk",
2029
+ type: "application/javascript"
2030
+ }
2031
+ };
2032
+ function loadScript(config) {
2033
+ return new Promise((resolve, reject) => {
2034
+ if (document.getElementById(config.id)) {
2035
+ resolve();
2036
+ return;
2037
+ }
2038
+ const script = document.createElement("script");
2039
+ script.id = config.id;
2040
+ script.src = config.src;
2041
+ script.type = config.type || "text/javascript";
2042
+ script.async = true;
2043
+ script.onload = () => resolve();
2044
+ script.onerror = () => reject(new Error(`Failed to load script: ${config.src}`));
2045
+ document.head.appendChild(script);
2046
+ });
2047
+ }
2048
+ function getRequiredScriptLoaders(needsIma, needsSystem73) {
2049
+ const loaders = [];
2050
+ if (needsIma) {
2051
+ loaders.push(loadScript(SCRIPT_CONFIGS.ima));
2052
+ }
2053
+ if (needsSystem73) {
2054
+ loaders.push(loadScript(SCRIPT_CONFIGS.system73));
2055
+ }
2056
+ return loaders;
2057
+ }
2058
+ async function loadScripts(scriptLoaders) {
2059
+ if (scriptLoaders.length === 0) {
2060
+ return;
2061
+ }
2062
+ try {
2063
+ await Promise.all(scriptLoaders);
2064
+ } catch (error) {
2065
+ console.error("Error loading scripts:", error);
2066
+ throw error;
2067
+ }
2068
+ }
2069
+ function waitForGlobal(globalName, timeout = 5e3) {
2070
+ return new Promise((resolve, reject) => {
2071
+ const startTime = Date.now();
2072
+ function checkGlobal() {
2073
+ const global = window[globalName];
2074
+ if (global) {
2075
+ resolve(global);
2076
+ return;
2077
+ }
2078
+ if (Date.now() - startTime > timeout) {
2079
+ reject(new Error(`Timeout waiting for global: ${globalName}`));
2080
+ return;
2081
+ }
2082
+ setTimeout(checkGlobal, 100);
2083
+ }
2084
+ checkGlobal();
2085
+ });
2086
+ }
2087
+ async function waitForGlobals(globalNames, timeout = 5e3) {
2088
+ const promises = globalNames.map((name) => waitForGlobal(name, timeout));
2089
+ await Promise.all(promises);
2090
+ }
2091
+
848
2092
  // src/components/Loading.tsx
849
2093
  var import_tailwind_merge = require("tailwind-merge");
850
- var import_jsx_runtime = require("react/jsx-runtime");
851
- var Loading = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2094
+ var import_jsx_runtime4 = require("react/jsx-runtime");
2095
+ var Loading = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
852
2096
  "div",
853
2097
  {
854
2098
  className: (0, import_tailwind_merge.twMerge)(
@@ -856,17 +2100,36 @@ var Loading = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
856
2100
  className
857
2101
  ),
858
2102
  role: "status",
859
- children: [
860
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-white" }),
861
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only", children: "Loading..." })
862
- ]
2103
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: " flex justify-center items-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2104
+ "svg",
2105
+ {
2106
+ className: "shaka-spinner-svg animate-spin h-12 w-12",
2107
+ viewBox: "0 0 64 64",
2108
+ xmlns: "http://www.w3.org/2000/svg",
2109
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2110
+ "circle",
2111
+ {
2112
+ className: "shaka-spinner-path",
2113
+ cx: "32",
2114
+ cy: "32",
2115
+ r: "28",
2116
+ strokeWidth: "4",
2117
+ strokeLinecap: "round",
2118
+ stroke: "currentColor",
2119
+ fill: "none",
2120
+ strokeDasharray: "176",
2121
+ strokeDashoffset: "120"
2122
+ }
2123
+ )
2124
+ }
2125
+ ) })
863
2126
  }
864
2127
  );
865
2128
 
866
2129
  // src/components/ErrorScreen.tsx
867
- var import_jsx_runtime2 = require("react/jsx-runtime");
868
- var ErrorScreen = ({ title, description }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-full h-full md:rounded-2xl! aspect-video bg-black", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-[#151515] text-white w-full h-full flex justify-stretch items-center", children: [
869
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2130
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2131
+ var ErrorScreen = ({ title, description }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-full h-full md:rounded-2xl! aspect-video bg-black flex", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "bg-[#151515] text-white w-full h-full flex justify-center items-center", children: [
2132
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
870
2133
  "svg",
871
2134
  {
872
2135
  className: "w-24 h-24 m-6",
@@ -876,7 +2139,7 @@ var ErrorScreen = ({ title, description }) => /* @__PURE__ */ (0, import_jsx_run
876
2139
  style: { width: 96 },
877
2140
  viewBox: "0 0 24 24",
878
2141
  xmlns: "http://www.w3.org/2000/svg",
879
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2142
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
880
2143
  "path",
881
2144
  {
882
2145
  d: "M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z",
@@ -886,66 +2149,22 @@ var ErrorScreen = ({ title, description }) => /* @__PURE__ */ (0, import_jsx_run
886
2149
  )
887
2150
  }
888
2151
  ),
889
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
890
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "text-2xl mb-2", children: title || "Playback Error" }),
891
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-lg", children: description || "Unable to play the video. Please try again later." })
2152
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2153
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "text-2xl mb-2", children: title || "Playback Error" }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-lg", children: description || "Unable to play the video. Please try again later." })
892
2155
  ] })
893
2156
  ] }) });
894
2157
 
895
2158
  // src/components/Title.tsx
896
- var import_jsx_runtime3 = require("react/jsx-runtime");
897
- var Title = ({ title }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: "text-white text-xl font-semibold", children: title }) });
898
-
899
- // src/components/LiveBadge.tsx
900
- var import_jsx_runtime4 = require("react/jsx-runtime");
901
- var LiveBadge = ({
902
- isVisible,
903
- position = "top-right",
904
- className = "",
905
- style = {},
906
- text = "LIVE"
907
- }) => {
908
- if (!isVisible) return null;
909
- const positionClasses = {
910
- "top-left": "top-4 left-4",
911
- "top-right": "top-4 right-4",
912
- "bottom-left": "bottom-4 left-4",
913
- "bottom-right": "bottom-4 right-4"
914
- };
915
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
916
- "div",
917
- {
918
- className: `
919
- absolute z-50
920
- ${positionClasses[position]}
921
- bg-red-600 text-white
922
- px-2 py-1
923
- rounded-md
924
- text-xs font-bold
925
- uppercase tracking-wide
926
- shadow-lg
927
- animate-pulse
928
- pointer-events-none
929
- ${className}
930
- `,
931
- style,
932
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "flex items-center gap-1", children: [
933
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-2 h-2 bg-white rounded-full animate-pulse" }),
934
- text
935
- ] })
936
- }
937
- );
938
- };
939
-
940
- // src/styles.css
941
- 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');
2159
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2160
+ var Title = ({ title }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "text-white text-xl font-semibold", children: title }) });
942
2161
 
943
2162
  // src/Player.tsx
944
- var import_tailwind_merge2 = require("tailwind-merge");
945
- var import_jsx_runtime5 = require("react/jsx-runtime");
946
- var Player = (0, import_react10.forwardRef)(
2163
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2164
+ var Player = (0, import_react12.forwardRef)(
947
2165
  ({
948
2166
  src,
2167
+ managedMode = false,
949
2168
  autoPlay = false,
950
2169
  loop = false,
951
2170
  muted = false,
@@ -957,25 +2176,48 @@ var Player = (0, import_react10.forwardRef)(
957
2176
  shakaConfig,
958
2177
  drmConfig,
959
2178
  muxConfig,
2179
+ system73Config,
960
2180
  imaConfig,
961
2181
  chromecastConfig,
962
2182
  qualityConfig,
963
2183
  seekbarConfig,
2184
+ iconSizes,
964
2185
  events,
2186
+ locale = "en",
965
2187
  containerClassName,
966
- ...props
2188
+ liveThresholdSeconds = 15,
2189
+ publicKey,
2190
+ auth,
2191
+ ...videoProps
967
2192
  }, ref) => {
968
- const videoRef = (0, import_react10.useRef)(null);
969
- const containerRef = (0, import_react10.useRef)(null);
970
- const adContainerRef = (0, import_react10.useRef)(null);
971
- (0, import_react10.useImperativeHandle)(ref, () => videoRef.current, []);
972
- const { playerRef, initializePlayer, destroyPlayer } = useShakePlayer({
2193
+ const videoRef = (0, import_react12.useRef)(null);
2194
+ const containerRef = (0, import_react12.useRef)(null);
2195
+ const [isScriptsLoaded, setIsScriptsLoaded] = (0, import_react12.useState)(false);
2196
+ const [isInitialLoading, setIsInitialLoading] = (0, import_react12.useState)(true);
2197
+ const [bfResetKey, setBfResetKey] = (0, import_react12.useState)(0);
2198
+ const hasPlaylist = !!src && (typeof src === "string" || !!(src.url || src.drm?.widevine?.playlistUrl || src.drm?.playready?.playlistUrl || src.drm?.fairplay?.playlistUrl));
2199
+ (0, import_react12.useImperativeHandle)(ref, () => videoRef.current, []);
2200
+ const { playerRef, initializePlayer, loadManifest, destroyPlayer, isRetrying } = useShakaPlayer({
973
2201
  src,
974
2202
  shakaConfig,
975
2203
  drmConfig,
976
2204
  onError: events?.onError,
977
- onPlayerReady: events?.onPlayerReady
2205
+ onPlayerReady: events?.onPlayerReady,
2206
+ muxConfig,
2207
+ onMuxReady: events?.onMuxReady,
2208
+ onMuxDataUpdate: events?.onMuxDataUpdate,
2209
+ publicKey,
2210
+ mottoToken: auth?.mottoToken,
2211
+ hasAds: !!imaConfig?.adTagUrl,
2212
+ hasSystem73: !!system73Config?.apiKey,
2213
+ apiToken: auth?.apiToken
978
2214
  });
2215
+ const {
2216
+ initializeMux,
2217
+ updateMuxData,
2218
+ handleMuxError,
2219
+ destroyMux
2220
+ } = useMuxAnalytics(playerRef, muxConfig, events?.onMuxReady, events?.onMuxDataUpdate);
979
2221
  const {
980
2222
  getAvailableQualities,
981
2223
  setQuality,
@@ -988,12 +2230,11 @@ var Player = (0, import_react10.forwardRef)(
988
2230
  skipDuration,
989
2231
  shouldShowSkipControls
990
2232
  } = useSkipControls(videoRef, events?.onSkipBack, events?.onSkipForward);
991
- const {
992
- initializeMux,
993
- updateMuxData,
994
- handleMuxError,
995
- destroyMux
996
- } = useMuxAnalytics(playerRef, muxConfig, events?.onMuxReady, events?.onMuxDataUpdate);
2233
+ useKeyboardControls(videoRef, {
2234
+ skipBack,
2235
+ skipForward,
2236
+ enabled: true
2237
+ });
997
2238
  const { setupEventListeners, cleanupEventListeners } = useEventHandlers(videoRef, {
998
2239
  onPlay: events?.onPlay,
999
2240
  onPause: events?.onPause,
@@ -1009,110 +2250,231 @@ var Player = (0, import_react10.forwardRef)(
1009
2250
  chromecastConfig,
1010
2251
  seekbarConfig,
1011
2252
  events?.onSkipBack,
1012
- events?.onSkipForward
2253
+ events?.onSkipForward,
2254
+ iconSizes,
2255
+ locale
1013
2256
  );
1014
- const { isLive, isVisible: isLiveBadgeVisible } = useLiveBadge(playerRef, {
1015
- enabled: true,
1016
- onLiveStateChange: (isLive2) => {
1017
- events?.onLiveStateChange?.(isLive2);
1018
- }
1019
- });
1020
- useLiveIndicator(containerRef, {
2257
+ const { getLiveStatus, seekToLiveEdge } = useLiveIndicator(containerRef, playerRef, {
1021
2258
  enabled: true,
1022
2259
  indicatorColor: "#ff0000",
1023
2260
  indicatorSize: 8,
1024
- showPulseAnimation: true
2261
+ showPulseAnimation: true,
2262
+ liveThresholdSeconds,
2263
+ onLiveStatusChange: events?.onLiveStatusChange
1025
2264
  });
1026
- const initializeAds = () => {
1027
- if (!imaConfig || !playerRef.current || !videoRef.current) return;
1028
- const adManager = playerRef.current.getAdManager();
1029
- if (!adManager) return;
1030
- adManager.addEventListener(import_shaka_player4.default.ads?.Utils?.AD_STARTED, () => {
1031
- events?.onAdStart?.();
1032
- });
1033
- adManager.addEventListener(import_shaka_player4.default.ads?.Utils?.AD_COMPLETE, () => {
1034
- events?.onAdComplete?.();
1035
- });
1036
- adManager.addEventListener(import_shaka_player4.default.ads?.Utils?.AD_ERROR, (event) => {
1037
- events?.onAdError?.(event.detail);
1038
- });
1039
- if (imaConfig.adTagUrl) {
1040
- const adContainer = adContainerRef.current;
1041
- if (adContainer) {
1042
- adManager.initClientSide(adContainer, videoRef.current, imaConfig.adsRenderingSettings);
1043
- const adsRequest = {
1044
- adTagUrl: imaConfig.adTagUrl,
1045
- linearAdSlotWidth: imaConfig.linearAdSlotWidth || width || 640,
1046
- linearAdSlotHeight: imaConfig.linearAdSlotHeight || height || 360,
1047
- nonLinearAdSlotWidth: imaConfig.nonLinearAdSlotWidth || width || 640,
1048
- nonLinearAdSlotHeight: imaConfig.nonLinearAdSlotHeight || 150
1049
- };
1050
- adManager.requestClientSideAds(adsRequest);
1051
- }
2265
+ const { setupAdEventListeners, cleanupAdEventListeners } = useAdEvents(playerRef, {
2266
+ onAdStart: events?.onAdStart,
2267
+ onAdComplete: events?.onAdComplete,
2268
+ onAdError: events?.onAdError,
2269
+ onAdSkipped: events?.onAdSkipped,
2270
+ onAdPaused: events?.onAdPaused,
2271
+ onAdResumed: events?.onAdResumed,
2272
+ onAdProgress: events?.onAdProgress,
2273
+ onAllAdsCompleted: events?.onAllAdsCompleted
2274
+ });
2275
+ const initializeSystem73 = (0, import_react12.useCallback)((playerConfig) => {
2276
+ if (!system73Config?.apiKey || !window.S73ShakaPlayerWrapper) {
2277
+ return null;
1052
2278
  }
1053
- };
1054
- const initializeChromecast = () => {
1055
- if (!chromecastConfig?.enabled) {
2279
+ console.log("Initializing System73 SDK...");
2280
+ try {
2281
+ const s73Config = {
2282
+ apiKey: system73Config.apiKey,
2283
+ contentSteeringEndpoint: system73Config.contentSteeringEndpoint,
2284
+ channelId: system73Config.channelId
2285
+ };
2286
+ const wrapper = window.S73ShakaPlayerWrapper(s73Config, { shaka: import_shaka_player4.default });
2287
+ wrapper.wrapPlayerConfig(playerConfig);
2288
+ console.log("System73 SDK initialized with config:", s73Config);
2289
+ return wrapper;
2290
+ } catch (error) {
2291
+ console.error("Error initializing System73 SDK:", error);
2292
+ return null;
2293
+ }
2294
+ }, [system73Config]);
2295
+ const initializeAds = (0, import_react12.useCallback)(async () => {
2296
+ if (!imaConfig?.adTagUrl || !playerRef.current || !videoRef.current || !uiRef.current) {
2297
+ return;
2298
+ }
2299
+ if (!window.google?.ima) {
2300
+ console.error("Google IMA SDK not available when trying to initialize ads");
1056
2301
  return;
1057
2302
  }
1058
2303
  try {
1059
- if (events?.onCastStateChange) {
1060
- setTimeout(() => events.onCastStateChange(false), 100);
2304
+ const player = playerRef.current;
2305
+ const video = videoRef.current;
2306
+ const ui = uiRef.current;
2307
+ const controls2 = ui.getControls();
2308
+ const container = controls2.getClientSideAdContainer();
2309
+ const adManager = player.getAdManager();
2310
+ if (!adManager) {
2311
+ console.error("Ad manager not available");
2312
+ return;
1061
2313
  }
2314
+ const google = window.google;
2315
+ let adsRenderingSettings = null;
2316
+ if (imaConfig.adsRenderingSettings) {
2317
+ adsRenderingSettings = imaConfig.adsRenderingSettings;
2318
+ } else if (autoPlay) {
2319
+ adsRenderingSettings = new google.ima.AdsRenderingSettings();
2320
+ adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
2321
+ }
2322
+ adManager.initClientSide(container, video, adsRenderingSettings);
2323
+ const adsRequest = new google.ima.AdsRequest();
2324
+ adsRequest.adTagUrl = imaConfig.adTagUrl;
2325
+ adManager.requestClientSideAds(adsRequest);
2326
+ setupAdEventListeners();
2327
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
2328
+ await loadManifest();
1062
2329
  } catch (error) {
1063
- console.warn("Chromecast initialization failed:", error);
2330
+ console.error("Error initializing ads:", error);
1064
2331
  }
1065
- };
1066
- (0, import_react10.useEffect)(() => {
2332
+ }, [imaConfig, autoPlay, setupAdEventListeners, loadManifest]);
2333
+ (0, import_react12.useEffect)(() => {
2334
+ const loadRequiredScripts = async () => {
2335
+ try {
2336
+ const scriptLoaders = getRequiredScriptLoaders(!!imaConfig?.adTagUrl, !!system73Config?.apiKey);
2337
+ await loadScripts(scriptLoaders);
2338
+ const globalsToWait = [];
2339
+ if (imaConfig?.adTagUrl) {
2340
+ globalsToWait.push("google");
2341
+ }
2342
+ if (system73Config?.apiKey) {
2343
+ globalsToWait.push("S73ShakaPlayerWrapper");
2344
+ }
2345
+ if (globalsToWait.length > 0) {
2346
+ await waitForGlobals(globalsToWait);
2347
+ }
2348
+ setIsScriptsLoaded(true);
2349
+ } catch (error) {
2350
+ console.error("Error loading required scripts:", error);
2351
+ setIsScriptsLoaded(true);
2352
+ }
2353
+ };
2354
+ loadRequiredScripts();
2355
+ }, [imaConfig?.adTagUrl, system73Config?.apiKey]);
2356
+ (0, import_react12.useEffect)(() => {
2357
+ const onPageShow = (e) => {
2358
+ if (e && e.persisted) {
2359
+ setBfResetKey((k) => k + 1);
2360
+ }
2361
+ };
2362
+ window.addEventListener("pageshow", onPageShow);
2363
+ return () => window.removeEventListener("pageshow", onPageShow);
2364
+ }, []);
2365
+ (0, import_react12.useEffect)(() => {
1067
2366
  const video = videoRef.current;
1068
- if (!video) return;
2367
+ if (!video || !isScriptsLoaded) return;
1069
2368
  const initialize = async () => {
1070
2369
  try {
2370
+ console.log("\u{1F680} [Player] Starting initialization...");
2371
+ setIsInitialLoading(true);
2372
+ let system73Wrapper = null;
2373
+ if (system73Config?.apiKey && window.S73ShakaPlayerWrapper) {
2374
+ console.log("\u{1F4E6} [System73] Step 1: Initializing System73 wrapper with config");
2375
+ const playerConfig = { ...shakaConfig };
2376
+ system73Wrapper = initializeSystem73(playerConfig);
2377
+ if (system73Wrapper) {
2378
+ shakaConfig = playerConfig;
2379
+ console.log("\u2705 [System73] Step 1 complete: Wrapper created and config modified");
2380
+ }
2381
+ }
2382
+ console.log("\u{1F3AC} [Shaka] Step 2: Initializing Shaka Player (auto-load:", !system73Config?.apiKey && !imaConfig?.adTagUrl, ")");
1071
2383
  await initializePlayer(video);
2384
+ console.log("\u2705 [Shaka] Step 2 complete: Player initialized");
2385
+ if (system73Wrapper && playerRef.current) {
2386
+ console.log("\u{1F517} [System73] Step 3: Wrapping Shaka player with System73");
2387
+ system73Wrapper.wrapPlayer(playerRef.current);
2388
+ console.log("\u2705 [System73] Step 3 complete: Player wrapped");
2389
+ if (!imaConfig?.adTagUrl) {
2390
+ console.log("\u{1F4FA} [System73] Step 4: Loading manifest");
2391
+ await loadManifest();
2392
+ console.log("\u2705 [System73] Step 4 complete: Manifest loaded");
2393
+ } else {
2394
+ console.log("\u23ED\uFE0F [System73] Skipping manifest load - ads will handle it");
2395
+ }
2396
+ }
2397
+ console.log("\u{1F4CB} [Player] Setting up event listeners and quality tracking");
1072
2398
  setupEventListeners();
1073
2399
  const cleanupQuality = setupQualityTracking();
1074
2400
  configureQuality();
2401
+ console.log("\u{1F3A8} [UI] Initializing Shaka UI");
1075
2402
  await initializeUI();
1076
- initializeMux();
1077
- initializeAds();
1078
- initializeChromecast();
2403
+ console.log("\u2705 [UI] UI initialized");
2404
+ if (imaConfig?.adTagUrl && window.google?.ima) {
2405
+ console.log("\u{1F4E2} [Ads] Initializing ads (will load manifest after VAST fetch)");
2406
+ await initializeAds();
2407
+ console.log("\u2705 [Ads] Ads initialized and manifest loaded");
2408
+ }
2409
+ console.log("\u2728 [Player] Initialization complete!");
1079
2410
  } catch (error) {
1080
- console.error("Error during player initialization:", error);
2411
+ console.error("\u274C [Player] Error during initialization:", error);
1081
2412
  handleMuxError(error);
1082
2413
  }
1083
2414
  };
1084
2415
  initialize();
1085
2416
  return () => {
1086
2417
  cleanupEventListeners();
2418
+ cleanupAdEventListeners();
1087
2419
  destroyUI();
1088
2420
  destroyMux();
1089
2421
  destroyPlayer();
1090
2422
  };
1091
- }, [
1092
- src,
1093
- initializePlayer,
1094
- setupEventListeners,
1095
- setupQualityTracking,
1096
- configureQuality,
1097
- initializeUI,
1098
- initializeMux,
1099
- cleanupEventListeners,
1100
- destroyUI,
1101
- destroyMux,
1102
- destroyPlayer,
1103
- handleMuxError,
1104
- playerRef
1105
- ]);
1106
- (0, import_react10.useEffect)(() => {
2423
+ }, [managedMode ? hasPlaylist : src, isScriptsLoaded, bfResetKey, managedMode]);
2424
+ (0, import_react12.useEffect)(() => {
2425
+ const video = videoRef.current;
2426
+ if (!video) return;
2427
+ const onLoadStart = () => {
2428
+ setIsInitialLoading(true);
2429
+ };
2430
+ const onCanPlay = () => {
2431
+ setIsInitialLoading(false);
2432
+ };
2433
+ const onPlaying = () => {
2434
+ setIsInitialLoading(false);
2435
+ };
2436
+ video.addEventListener("loadstart", onLoadStart);
2437
+ video.addEventListener("canplay", onCanPlay);
2438
+ video.addEventListener("playing", onPlaying);
2439
+ return () => {
2440
+ video.removeEventListener("loadstart", onLoadStart);
2441
+ video.removeEventListener("canplay", onCanPlay);
2442
+ video.removeEventListener("playing", onPlaying);
2443
+ };
2444
+ }, []);
2445
+ (0, import_react12.useEffect)(() => {
1107
2446
  const video = videoRef.current;
1108
2447
  if (!video) return;
1109
2448
  video.autoplay = autoPlay;
1110
2449
  video.loop = loop;
1111
- video.muted = muted;
1112
2450
  video.controls = false;
1113
2451
  if (poster) video.poster = poster;
1114
- }, [autoPlay, loop, muted, poster]);
1115
- (0, import_react10.useImperativeHandle)(ref, () => ({
2452
+ }, [autoPlay, loop, muted, poster, imaConfig?.adTagUrl]);
2453
+ (0, import_react12.useEffect)(() => {
2454
+ const video = videoRef.current;
2455
+ if (!video) return;
2456
+ video.controls = false;
2457
+ video.setAttribute("controls", "false");
2458
+ video.removeAttribute("controls");
2459
+ const observer = new MutationObserver((mutations) => {
2460
+ mutations.forEach((mutation) => {
2461
+ if (mutation.type === "attributes" && mutation.attributeName === "controls") {
2462
+ if (video.hasAttribute("controls")) {
2463
+ video.removeAttribute("controls");
2464
+ video.controls = false;
2465
+ }
2466
+ }
2467
+ });
2468
+ });
2469
+ observer.observe(video, {
2470
+ attributes: true,
2471
+ attributeFilter: ["controls"]
2472
+ });
2473
+ return () => {
2474
+ observer.disconnect();
2475
+ };
2476
+ }, []);
2477
+ (0, import_react12.useImperativeHandle)(ref, () => ({
1116
2478
  ...videoRef.current,
1117
2479
  // Custom methods for quality control
1118
2480
  getAvailableQualities,
@@ -1122,27 +2484,30 @@ var Player = (0, import_react10.forwardRef)(
1122
2484
  skipForward,
1123
2485
  // Mux methods
1124
2486
  updateMuxData,
2487
+ // Live status methods
2488
+ getLiveStatus,
2489
+ seekToLiveEdge,
1125
2490
  // Access to underlying instances
1126
2491
  getPlayer: () => playerRef.current,
1127
2492
  getMuxMonitor: () => null
1128
- }), [getAvailableQualities, setQuality, skipBack, skipForward, updateMuxData]);
2493
+ }), [getAvailableQualities, setQuality, skipBack, skipForward, updateMuxData, getLiveStatus, seekToLiveEdge]);
1129
2494
  const isResponsive = !width && !height;
1130
- const containerClasses = (0, import_tailwind_merge2.twMerge)(containerClassName, "motto-video-container");
2495
+ const containerClasses = (0, import_tailwind_merge2.twMerge)(containerClassName, "motto-video-container relative bg-[#111111] ");
1131
2496
  const containerStyle = isResponsive ? {
1132
2497
  aspectRatio: aspectRatio.toString()
1133
2498
  } : { width, height };
1134
- const videoClasses = isResponsive ? "motto-video-responsive" : "w-full h-full ";
2499
+ const videoClasses = isResponsive ? "motto-video-responsive w-full" : "w-full h-full ";
1135
2500
  const videoStyle = isResponsive ? {} : { width, height };
1136
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2501
+ const filteredVideoProps = { ...videoProps };
2502
+ delete filteredVideoProps.controls;
2503
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1137
2504
  "div",
1138
2505
  {
1139
2506
  ref: containerRef,
1140
2507
  className: containerClasses,
1141
2508
  style: containerStyle,
1142
- "data-shaka-player-container": true,
1143
- "data-shaka-player-cast-receiver-id": chromecastConfig?.receiverApplicationId,
1144
2509
  children: [
1145
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2510
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1146
2511
  "video",
1147
2512
  {
1148
2513
  ref: videoRef,
@@ -1151,17 +2516,11 @@ var Player = (0, import_react10.forwardRef)(
1151
2516
  height: isResponsive ? void 0 : height,
1152
2517
  style: videoStyle,
1153
2518
  controls: false,
1154
- ...props
2519
+ playsInline: true,
2520
+ ...filteredVideoProps
1155
2521
  }
1156
2522
  ),
1157
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LiveBadge, { isVisible: isLiveBadgeVisible }),
1158
- imaConfig && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1159
- "div",
1160
- {
1161
- ref: adContainerRef,
1162
- className: "absolute top-0 left-0 w-full h-full pointer-events-auto"
1163
- }
1164
- )
2523
+ isInitialLoading && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "absolute inset-0 flex items-center justify-center z-20 pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Loading, { className: "bg-transparent" }) })
1165
2524
  ]
1166
2525
  }
1167
2526
  );
@@ -1170,16 +2529,16 @@ var Player = (0, import_react10.forwardRef)(
1170
2529
  Player.displayName = "Player";
1171
2530
 
1172
2531
  // src/Video.tsx
1173
- var import_react12 = require("react");
2532
+ var import_react14 = require("react");
1174
2533
  var import_tailwind_merge3 = require("tailwind-merge");
1175
2534
  var import_react_query = require("@tanstack/react-query");
1176
2535
 
1177
2536
  // src/api/video.ts
1178
- var fetchVideoData = async (videoId, publicKey, mottoToken) => {
2537
+ var fetchVideoData = async (videoId, publicKey, mottoToken, adsEnabled = false, locale = "en") => {
1179
2538
  const endpoint = "https://cda.mottostreaming.com/motto.cda.streaming.video.v1.VideoService/GetVideo";
1180
2539
  const url = new URL(endpoint);
1181
2540
  url.searchParams.set("encoding", "json");
1182
- url.searchParams.set("message", JSON.stringify({ videoId }));
2541
+ url.searchParams.set("message", JSON.stringify({ videoId, enable_ads: adsEnabled, locale }));
1183
2542
  const response = await fetch(url, {
1184
2543
  method: "GET",
1185
2544
  headers: {
@@ -1193,14 +2552,14 @@ var fetchVideoData = async (videoId, publicKey, mottoToken) => {
1193
2552
  const data = await response.json();
1194
2553
  return data.video;
1195
2554
  };
1196
- async function fetchVideosList(publicKey, videoIds, mottoToken, skip = 0, limit = 0) {
2555
+ async function fetchVideosList(publicKey, videoIds, mottoToken, skip = 0, limit = 0, adsEnabled = true, locale = "en") {
1197
2556
  if (!videoIds || videoIds.length === 0) {
1198
2557
  return [];
1199
2558
  }
1200
2559
  const endpoint = "https://cda.mottostreaming.com/motto.cda.streaming.video.v1.VideoService/BatchGetVideos";
1201
2560
  const url = new URL(endpoint);
1202
2561
  url.searchParams.set("encoding", "json");
1203
- url.searchParams.set("message", JSON.stringify({ videoIds }));
2562
+ url.searchParams.set("message", JSON.stringify({ videoIds, enable_ads: adsEnabled, locale }));
1204
2563
  const response = await fetch(url.toString(), {
1205
2564
  method: "GET",
1206
2565
  headers: {
@@ -1311,7 +2670,7 @@ var getErrorType = (error, video) => {
1311
2670
  };
1312
2671
 
1313
2672
  // src/messages/useMessages.tsx
1314
- var import_react11 = require("react");
2673
+ var import_react13 = require("react");
1315
2674
 
1316
2675
  // src/messages/en.json
1317
2676
  var en_default = {
@@ -1613,9 +2972,9 @@ var getBrowserLanguage = () => {
1613
2972
  return availableLanguages[language] ? language : "en";
1614
2973
  };
1615
2974
  var useMessages = (locale) => {
1616
- const [language, setLanguage] = (0, import_react11.useState)("en");
1617
- const [translations, setTranslations] = (0, import_react11.useState)(availableLanguages.en);
1618
- (0, import_react11.useEffect)(() => {
2975
+ const [language, setLanguage] = (0, import_react13.useState)("en");
2976
+ const [translations, setTranslations] = (0, import_react13.useState)(availableLanguages.en);
2977
+ (0, import_react13.useEffect)(() => {
1619
2978
  const lang = !!availableLanguages?.[locale] ? locale : getBrowserLanguage();
1620
2979
  ;
1621
2980
  setLanguage(lang);
@@ -1641,11 +3000,10 @@ var useMessages = (locale) => {
1641
3000
  var useMessages_default = useMessages;
1642
3001
 
1643
3002
  // src/Video.tsx
1644
- var import_jsx_runtime6 = require("react/jsx-runtime");
3003
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1645
3004
  var Video = ({
1646
3005
  videoId,
1647
3006
  publicKey,
1648
- mottoToken,
1649
3007
  videoData: providedVideoData,
1650
3008
  refetchInterval = 0,
1651
3009
  playerName,
@@ -1653,7 +3011,10 @@ var Video = ({
1653
3011
  events,
1654
3012
  children,
1655
3013
  className,
3014
+ auth,
3015
+ settings,
1656
3016
  queryOptions = {},
3017
+ adsEnabled = false,
1657
3018
  ...props
1658
3019
  }) => {
1659
3020
  const {
@@ -1662,8 +3023,8 @@ var Video = ({
1662
3023
  error,
1663
3024
  refetch
1664
3025
  } = (0, import_react_query.useQuery)({
1665
- queryKey: ["video", videoId, publicKey, mottoToken],
1666
- queryFn: () => fetchVideoData(videoId, publicKey, mottoToken),
3026
+ queryKey: ["video", videoId, publicKey, auth?.mottoToken, adsEnabled, locale],
3027
+ queryFn: () => fetchVideoData(videoId, publicKey, auth?.mottoToken, adsEnabled, locale),
1667
3028
  enabled: !!videoId && !!publicKey && !providedVideoData,
1668
3029
  refetchInterval: refetchInterval > 0 ? refetchInterval : false,
1669
3030
  staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
@@ -1676,16 +3037,17 @@ var Video = ({
1676
3037
  const video = providedVideoData || data;
1677
3038
  const { t } = useMessages_default(locale);
1678
3039
  const activePlaylist = findHLSPlaylist(video);
1679
- const hlsUrl = activePlaylist?.url;
1680
- (0, import_react12.useEffect)(() => {
3040
+ const activePlaylistUrl = activePlaylist?.url ?? activePlaylist?.drm?.widevine?.playlistUrl ?? activePlaylist?.drm?.playready?.playlistUrl ?? activePlaylist?.drm?.fairplay?.playlistUrl;
3041
+ const activePlaylistHasUrl = !!activePlaylistUrl;
3042
+ (0, import_react14.useEffect)(() => {
1681
3043
  if (events?.onVideoData && video) {
1682
3044
  events.onVideoData(video);
1683
3045
  }
1684
3046
  }, [video, events]);
1685
3047
  if (isLoading || !providedVideoData && !video) {
1686
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: (0, import_tailwind_merge3.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "relative w-full h-full bg-[#151515]", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Loading, {}) }) });
3048
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: (0, import_tailwind_merge3.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative w-full h-full bg-[#151515]", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Loading, {}) }) });
1687
3049
  }
1688
- if (!isLoading && video && !hlsUrl && events?.onEmptyPlaylists) {
3050
+ if (!isLoading && video && !activePlaylistHasUrl && events?.onEmptyPlaylists) {
1689
3051
  events.onEmptyPlaylists();
1690
3052
  }
1691
3053
  if (error || video?.error) {
@@ -1696,8 +3058,8 @@ var Video = ({
1696
3058
  }
1697
3059
  const title = t(errorKey) || t("DEFAULT_ERROR");
1698
3060
  const description = t(`${errorKey}_DESCRIPTION`) || t("DEFAULT_ERROR_DESCRIPTION");
1699
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: (0, import_tailwind_merge3.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative w-full h-full", children: [
1700
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3061
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: (0, import_tailwind_merge3.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative w-full h-full", children: [
3062
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1701
3063
  ErrorScreen,
1702
3064
  {
1703
3065
  title,
@@ -1707,31 +3069,35 @@ var Video = ({
1707
3069
  children
1708
3070
  ] }) });
1709
3071
  }
1710
- if (!hlsUrl) {
1711
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: (0, import_tailwind_merge3.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative w-full h-full bg-[#151515]", children: [
1712
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Title, { title: video?.name || "" }),
3072
+ if (!activePlaylist || !activePlaylistHasUrl) {
3073
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: (0, import_tailwind_merge3.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative w-full h-full bg-[#151515]", children: [
3074
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Title, { title: video?.name || "" }),
1713
3075
  children
1714
3076
  ] }) });
1715
3077
  }
1716
- console.log("hlsUrl", hlsUrl);
1717
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: (0, import_tailwind_merge3.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3078
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: (0, import_tailwind_merge3.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1718
3079
  Player,
1719
3080
  {
1720
3081
  ...props,
1721
- src: hlsUrl,
3082
+ src: activePlaylist,
3083
+ managedMode: true,
1722
3084
  className: (0, import_tailwind_merge3.twMerge)("video-player-container", className),
1723
3085
  events,
3086
+ locale,
1724
3087
  containerClassName: "w-full h-full",
3088
+ publicKey,
3089
+ auth,
3090
+ ...adsEnabled && video?.ad?.adTagUrl ? { imaConfig: { adTagUrl: video?.ad?.adTagUrl } } : {},
1725
3091
  children
1726
3092
  }
1727
3093
  ) }) });
1728
3094
  };
1729
3095
 
1730
3096
  // src/Event.tsx
1731
- var import_react13 = require("react");
3097
+ var import_react15 = require("react");
1732
3098
  var import_tailwind_merge4 = require("tailwind-merge");
1733
3099
  var import_react_query2 = require("@tanstack/react-query");
1734
- var import_jsx_runtime7 = require("react/jsx-runtime");
3100
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1735
3101
  var Event = ({
1736
3102
  publicKey,
1737
3103
  eventId,
@@ -1744,6 +3110,7 @@ var Event = ({
1744
3110
  settings,
1745
3111
  auth,
1746
3112
  queryOptions = {},
3113
+ adsEnabled = false,
1747
3114
  ...props
1748
3115
  }) => {
1749
3116
  const {
@@ -1761,16 +3128,16 @@ var Event = ({
1761
3128
  retry: queryOptions.retry ?? 3,
1762
3129
  retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
1763
3130
  });
1764
- const [activePlaylist, setActivePlaylist] = (0, import_react13.useState)();
1765
- const [activeVideoId, setActiveVideoId] = (0, import_react13.useState)();
3131
+ const [activePlaylist, setActivePlaylist] = (0, import_react15.useState)();
3132
+ const [activeVideoId, setActiveVideoId] = (0, import_react15.useState)();
1766
3133
  const videoIds = eventData?.videoIds ?? [];
1767
3134
  const {
1768
3135
  data: videosData,
1769
3136
  isLoading: videosIsLoading,
1770
3137
  error: videosError
1771
3138
  } = (0, import_react_query2.useQuery)({
1772
- queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken],
1773
- queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0),
3139
+ queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken, adsEnabled, locale],
3140
+ queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0, adsEnabled, locale),
1774
3141
  enabled: !!publicKey && videoIds.length > 0,
1775
3142
  refetchInterval: activePlaylist === null ? 3e4 : false,
1776
3143
  staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
@@ -1778,8 +3145,8 @@ var Event = ({
1778
3145
  retry: queryOptions.retry ?? 3,
1779
3146
  retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
1780
3147
  });
1781
- const [loadingApisState, setLoadingApisState] = (0, import_react13.useState)(true);
1782
- (0, import_react13.useEffect)(() => {
3148
+ const [loadingApisState, setLoadingApisState] = (0, import_react15.useState)(true);
3149
+ (0, import_react15.useEffect)(() => {
1783
3150
  if (videosData !== void 0) {
1784
3151
  setLoadingApisState(false);
1785
3152
  const videosWithPlaylists = videosData.filter(
@@ -1788,9 +3155,11 @@ var Event = ({
1788
3155
  if (videosWithPlaylists.length > 0) {
1789
3156
  let hlsPlaylistFound = false;
1790
3157
  for (const video of videosWithPlaylists) {
1791
- const hlsPlaylist = findHLSPlaylist(video);
1792
- if (hlsPlaylist?.url) {
1793
- setActivePlaylist(hlsPlaylist.url);
3158
+ const activePlaylist2 = findHLSPlaylist(video);
3159
+ const activePlaylistUrl = activePlaylist2?.url ?? activePlaylist2?.drm?.widevine?.playlistUrl ?? activePlaylist2?.drm?.playready?.playlistUrl ?? activePlaylist2?.drm?.fairplay?.playlistUrl;
3160
+ const activePlaylistHasUrl = !!activePlaylistUrl;
3161
+ if (activePlaylist2 && activePlaylistHasUrl) {
3162
+ setActivePlaylist(activePlaylist2);
1794
3163
  setActiveVideoId(video.id);
1795
3164
  hlsPlaylistFound = true;
1796
3165
  break;
@@ -1811,12 +3180,12 @@ var Event = ({
1811
3180
  }
1812
3181
  }, [videosData, eventData]);
1813
3182
  const { t } = useMessages_default(locale);
1814
- (0, import_react13.useEffect)(() => {
3183
+ (0, import_react15.useEffect)(() => {
1815
3184
  if (events?.onEventData && eventData) {
1816
3185
  events.onEventData(eventData);
1817
3186
  }
1818
3187
  }, [eventData, events]);
1819
- (0, import_react13.useEffect)(() => {
3188
+ (0, import_react15.useEffect)(() => {
1820
3189
  if (events?.onVideoData && activeVideoId && videosData) {
1821
3190
  const activeVideo = videosData.find((video) => video.id === activeVideoId);
1822
3191
  if (activeVideo) {
@@ -1824,12 +3193,17 @@ var Event = ({
1824
3193
  }
1825
3194
  }
1826
3195
  }, [activeVideoId, videosData, events]);
1827
- const [error, setError] = (0, import_react13.useState)(null);
1828
- const [loadingPlaylist, setLoadingPlaylist] = (0, import_react13.useState)(true);
3196
+ const [error, setError] = (0, import_react15.useState)(null);
3197
+ const [loadingPlaylist, setLoadingPlaylist] = (0, import_react15.useState)(true);
1829
3198
  const videosDataError = videosData?.some((video) => !!video.error);
1830
- (0, import_react13.useEffect)(() => {
1831
- if (eventError || videosError || videosDataError) {
1832
- const errorObj = eventError || videosError || videosData?.find((video) => !!video.error)?.error && new Error(videosData?.find((video) => !!video.error)?.error) || new Error("default");
3199
+ (0, import_react15.useEffect)(() => {
3200
+ if (isEventLoading || videosIsLoading || loadingApisState) {
3201
+ return;
3202
+ }
3203
+ const hasPlayablePlaylist = Boolean(activePlaylist);
3204
+ if (eventError || videosError || videosDataError && !hasPlayablePlaylist) {
3205
+ const firstVideoError = videosData?.find((video) => !!video.error)?.error;
3206
+ const errorObj = eventError || videosError || firstVideoError && new Error(firstVideoError) || new Error("default");
1833
3207
  setError(errorObj);
1834
3208
  if (events?.onError) {
1835
3209
  events.onError(errorObj);
@@ -1837,8 +3211,18 @@ var Event = ({
1837
3211
  } else {
1838
3212
  setError(null);
1839
3213
  }
1840
- }, [eventError, videosError, videosDataError, videosData, events]);
1841
- (0, import_react13.useEffect)(() => {
3214
+ }, [
3215
+ eventError,
3216
+ videosError,
3217
+ videosDataError,
3218
+ videosData,
3219
+ events,
3220
+ activePlaylist,
3221
+ isEventLoading,
3222
+ videosIsLoading,
3223
+ loadingApisState
3224
+ ]);
3225
+ (0, import_react15.useEffect)(() => {
1842
3226
  const eventLoadedWithNoVideos = !isEventLoading && eventData && eventData.videoIds && (!eventData.videoIds || eventData?.videoIds?.length === 0) && !loadingApisState;
1843
3227
  const allApisLoadedWithPotentialVideos = !isEventLoading && !videosIsLoading && eventData && !loadingApisState;
1844
3228
  if (eventLoadedWithNoVideos || allApisLoadedWithPotentialVideos) {
@@ -1848,7 +3232,7 @@ var Event = ({
1848
3232
  if (error) {
1849
3233
  const title = t(error.message)?.length ? t(error.message) : t("DEFAULT_ERROR");
1850
3234
  const description = t(`${error.message}_DESCRIPTION`)?.length ? t(`${error.message}_DESCRIPTION`) : t("DEFAULT_ERROR_DESCRIPTION");
1851
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: (0, import_tailwind_merge4.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3235
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: (0, import_tailwind_merge4.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1852
3236
  ErrorScreen,
1853
3237
  {
1854
3238
  title,
@@ -1860,22 +3244,28 @@ var Event = ({
1860
3244
  events.onEmptyPlaylists();
1861
3245
  }
1862
3246
  if (loadingPlaylist) {
1863
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: (0, import_tailwind_merge4.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative w-full h-full bg-[#151515]", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Loading, {}) }) });
3247
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: (0, import_tailwind_merge4.twMerge)("", className), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative w-full aspect-video bg-[#151515]", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Loading, {}) }) });
1864
3248
  }
1865
3249
  if (activePlaylist && activeVideoId && videosData) {
1866
3250
  const activeVideo = videosData.find((video) => video.id === activeVideoId);
1867
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: (0, import_tailwind_merge4.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative w-full h-full", children: [
1868
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3251
+ console.log("activeVideo?.ad?.adTagUrl", activeVideo?.ad?.adTagUrl);
3252
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: (0, import_tailwind_merge4.twMerge)("", className), children: [
3253
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1869
3254
  Player,
1870
3255
  {
1871
3256
  ...props,
1872
3257
  src: activePlaylist,
1873
- className: (0, import_tailwind_merge4.twMerge)(className, "peer"),
3258
+ managedMode: true,
3259
+ className: (0, import_tailwind_merge4.twMerge)(className, "peer aspect-video"),
1874
3260
  events,
1875
- containerClassName: "w-full h-full"
3261
+ locale,
3262
+ containerClassName: "w-full h-full",
3263
+ publicKey,
3264
+ auth,
3265
+ ...adsEnabled && activeVideo ? { imaConfig: { adTagUrl: activeVideo?.ad?.adTagUrl } } : {}
1876
3266
  }
1877
- ),
1878
- !hideTitle && eventData && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3267
+ ) }),
3268
+ !hideTitle && eventData && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1879
3269
  TitleAndDescription,
1880
3270
  {
1881
3271
  title: eventData.title,
@@ -1884,10 +3274,10 @@ var Event = ({
1884
3274
  locale
1885
3275
  }
1886
3276
  )
1887
- ] }) });
3277
+ ] });
1888
3278
  }
1889
3279
  if (eventData) {
1890
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: (0, import_tailwind_merge4.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3280
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: (0, import_tailwind_merge4.twMerge)("", className), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1891
3281
  PreEvent,
1892
3282
  {
1893
3283
  event: eventData,
@@ -1909,12 +3299,12 @@ function PreEvent({
1909
3299
  }) {
1910
3300
  const date = new Date(event.startTime);
1911
3301
  const now = /* @__PURE__ */ new Date();
1912
- const [remainingTime, setRemainingTime] = (0, import_react13.useState)(
3302
+ const [remainingTime, setRemainingTime] = (0, import_react15.useState)(
1913
3303
  date.getTime() - now.getTime()
1914
3304
  );
1915
3305
  const shouldBeStarted = remainingTime < 0;
1916
3306
  const { t } = useMessages_default(locale);
1917
- (0, import_react13.useEffect)(() => {
3307
+ (0, import_react15.useEffect)(() => {
1918
3308
  const interval = setInterval(() => {
1919
3309
  if (remainingTime < 0) {
1920
3310
  clearInterval(interval);
@@ -1924,29 +3314,28 @@ function PreEvent({
1924
3314
  }, 1e3);
1925
3315
  return () => clearInterval(interval);
1926
3316
  }, [date, remainingTime]);
1927
- const renderCountdown = (0, import_react13.useCallback)(() => {
3317
+ const renderCountdown = (0, import_react15.useCallback)(() => {
1928
3318
  if (shouldBeStarted) {
1929
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
3319
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
1930
3320
  }
1931
3321
  const seconds = Math.floor(remainingTime / 1e3) % 60;
1932
3322
  const minutes = Math.floor(remainingTime / 1e3 / 60) % 60;
1933
3323
  const hours = Math.floor(remainingTime / 1e3 / 60 / 60) % 24;
1934
3324
  const days = Math.floor(remainingTime / 1e3 / 60 / 60 / 24);
1935
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid grid-flow-col gap-5 text-center auto-cols-max", children: [
1936
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
1937
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "countdown font-mono text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3325
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-flow-col gap-1 md:gap-5 text-center auto-cols-max", children: [
3326
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3327
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1938
3328
  "span",
1939
3329
  {
1940
- style: { "--value": days },
1941
3330
  "aria-live": "polite",
1942
3331
  "aria-label": days.toString(),
1943
- children: days?.toString()?.padStart(2, "0")
3332
+ children: days.toString()
1944
3333
  }
1945
3334
  ) }),
1946
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("DAYS") })
3335
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("DAYS") })
1947
3336
  ] }),
1948
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
1949
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "countdown font-mono text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3337
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3338
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1950
3339
  "span",
1951
3340
  {
1952
3341
  style: { "--value": hours },
@@ -1955,10 +3344,10 @@ function PreEvent({
1955
3344
  children: hours?.toString()?.padStart(2, "0")
1956
3345
  }
1957
3346
  ) }),
1958
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("HOURS") })
3347
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("HOURS") })
1959
3348
  ] }),
1960
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
1961
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "countdown font-mono text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3349
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3350
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1962
3351
  "span",
1963
3352
  {
1964
3353
  style: { "--value": minutes },
@@ -1967,10 +3356,10 @@ function PreEvent({
1967
3356
  children: minutes?.toString()?.padStart(2, "0")
1968
3357
  }
1969
3358
  ) }),
1970
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("MINUTES") })
3359
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("MINUTES") })
1971
3360
  ] }),
1972
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
1973
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "countdown font-mono text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3361
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3362
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1974
3363
  "span",
1975
3364
  {
1976
3365
  style: { "--value": seconds },
@@ -1979,12 +3368,12 @@ function PreEvent({
1979
3368
  children: seconds?.toString()?.padStart(2, "0")
1980
3369
  }
1981
3370
  ) }),
1982
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("SECONDS") })
3371
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("SECONDS") })
1983
3372
  ] })
1984
3373
  ] });
1985
3374
  }, [remainingTime, shouldBeStarted, t]);
1986
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: event?.posterUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1987
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3375
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: event?.posterUrl ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
3376
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1988
3377
  "div",
1989
3378
  {
1990
3379
  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",
@@ -1993,10 +3382,10 @@ function PreEvent({
1993
3382
  backgroundRepeat: "no-repeat",
1994
3383
  backgroundSize: "cover"
1995
3384
  },
1996
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative z-10", children: renderCountdown() })
3385
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative z-10", children: renderCountdown() })
1997
3386
  }
1998
3387
  ),
1999
- !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3388
+ !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2000
3389
  TitleAndDescription,
2001
3390
  {
2002
3391
  title: event.title,
@@ -2005,18 +3394,18 @@ function PreEvent({
2005
3394
  locale
2006
3395
  }
2007
3396
  )
2008
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2009
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3397
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
3398
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2010
3399
  "div",
2011
3400
  {
2012
3401
  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",
2013
3402
  style: {
2014
3403
  backgroundImage: backgroundImageUrl ? `url(${backgroundImageUrl})` : ""
2015
3404
  },
2016
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative z-10", children: renderCountdown() })
3405
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative z-10", children: renderCountdown() })
2017
3406
  }
2018
3407
  ),
2019
- !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3408
+ !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2020
3409
  TitleAndDescription,
2021
3410
  {
2022
3411
  title: event.title,
@@ -2034,9 +3423,9 @@ var TitleAndDescription = ({
2034
3423
  locale = "en",
2035
3424
  className
2036
3425
  }) => {
2037
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: (0, import_tailwind_merge4.twMerge)("mt-3 mb-6 m-event-details-ctn px-4 text-left w-full", className), children: [
2038
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
2039
- startTime ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "text-sm md:text-base text-base-content/70 m-event-start-time", children: [
3426
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: (0, import_tailwind_merge4.twMerge)("mt-3 mb-6 m-event-details-ctn px-4 text-left w-full", className), children: [
3427
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
3428
+ startTime ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-xs md:text-base text-base-content/70 m-event-start-time", children: [
2040
3429
  new Date(startTime || "").toLocaleDateString(locale || "default", {
2041
3430
  month: "long",
2042
3431
  year: "numeric",
@@ -2049,15 +3438,15 @@ var TitleAndDescription = ({
2049
3438
  minute: "2-digit"
2050
3439
  })
2051
3440
  ] }) : null,
2052
- description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs md:text-sm text-base-content/60 uppercase", children: description })
3441
+ description && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs md:text-xs text-base-content/60 uppercase", children: description })
2053
3442
  ] });
2054
3443
  };
2055
3444
 
2056
3445
  // src/CreativeWork.tsx
2057
- var import_react14 = require("react");
3446
+ var import_react16 = require("react");
2058
3447
  var import_tailwind_merge5 = require("tailwind-merge");
2059
3448
  var import_react_query3 = require("@tanstack/react-query");
2060
- var import_jsx_runtime8 = require("react/jsx-runtime");
3449
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2061
3450
  var CreativeWork = ({
2062
3451
  publicKey,
2063
3452
  creativeWorkId,
@@ -2070,6 +3459,7 @@ var CreativeWork = ({
2070
3459
  settings,
2071
3460
  auth,
2072
3461
  queryOptions = {},
3462
+ adsEnabled = false,
2073
3463
  ...props
2074
3464
  }) => {
2075
3465
  const {
@@ -2087,17 +3477,17 @@ var CreativeWork = ({
2087
3477
  retry: queryOptions.retry ?? 3,
2088
3478
  retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
2089
3479
  });
2090
- const [activePlaylist, setActivePlaylist] = (0, import_react14.useState)();
2091
- const [activeVideoId, setActiveVideoId] = (0, import_react14.useState)();
2092
- const [showCountDown, setShowCountDown] = (0, import_react14.useState)(false);
3480
+ const [activePlaylist, setActivePlaylist] = (0, import_react16.useState)();
3481
+ const [activeVideoId, setActiveVideoId] = (0, import_react16.useState)();
3482
+ const [showCountDown, setShowCountDown] = (0, import_react16.useState)(false);
2093
3483
  const videoIds = creativeWorkData?.videoIds ?? [];
2094
3484
  const {
2095
3485
  data: videosData,
2096
3486
  isLoading: videosIsLoading,
2097
3487
  error: videosError
2098
3488
  } = (0, import_react_query3.useQuery)({
2099
- queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken],
2100
- queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0),
3489
+ queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken, adsEnabled, locale],
3490
+ queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0, adsEnabled, locale),
2101
3491
  enabled: !!publicKey && videoIds.length > 0,
2102
3492
  refetchInterval: activePlaylist === null ? 3e4 : false,
2103
3493
  staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
@@ -2105,8 +3495,8 @@ var CreativeWork = ({
2105
3495
  retry: queryOptions.retry ?? 3,
2106
3496
  retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
2107
3497
  });
2108
- const [loadingApisState, setLoadingApisState] = (0, import_react14.useState)(true);
2109
- (0, import_react14.useEffect)(() => {
3498
+ const [loadingApisState, setLoadingApisState] = (0, import_react16.useState)(true);
3499
+ (0, import_react16.useEffect)(() => {
2110
3500
  if (videosData !== void 0) {
2111
3501
  setLoadingApisState(false);
2112
3502
  const videosWithPlaylists = videosData.filter(
@@ -2115,9 +3505,11 @@ var CreativeWork = ({
2115
3505
  if (videosWithPlaylists.length > 0) {
2116
3506
  let hlsPlaylistFound = false;
2117
3507
  for (const video of videosWithPlaylists) {
2118
- const hlsPlaylist = findHLSPlaylist(video);
2119
- if (hlsPlaylist?.url) {
2120
- setActivePlaylist(hlsPlaylist.url);
3508
+ const activePlaylist2 = findHLSPlaylist(video);
3509
+ const activePlaylistUrl = activePlaylist2?.url ?? activePlaylist2?.drm?.widevine?.playlistUrl ?? activePlaylist2?.drm?.playready?.playlistUrl ?? activePlaylist2?.drm?.fairplay?.playlistUrl;
3510
+ const activePlaylistHasUrl = !!activePlaylistUrl;
3511
+ if (activePlaylist2 && activePlaylistHasUrl) {
3512
+ setActivePlaylist(activePlaylist2);
2121
3513
  setActiveVideoId(video.id);
2122
3514
  hlsPlaylistFound = true;
2123
3515
  break;
@@ -2138,7 +3530,7 @@ var CreativeWork = ({
2138
3530
  }
2139
3531
  }, [videosData, creativeWorkData]);
2140
3532
  const { t } = useMessages_default(locale);
2141
- (0, import_react14.useEffect)(() => {
3533
+ (0, import_react16.useEffect)(() => {
2142
3534
  if (events?.onCreativeWorkData && creativeWorkData) {
2143
3535
  events.onCreativeWorkData(creativeWorkData);
2144
3536
  }
@@ -2146,7 +3538,7 @@ var CreativeWork = ({
2146
3538
  setShowCountDown(true);
2147
3539
  }
2148
3540
  }, [creativeWorkData, events]);
2149
- (0, import_react14.useEffect)(() => {
3541
+ (0, import_react16.useEffect)(() => {
2150
3542
  if (events?.onVideoData && activeVideoId && videosData) {
2151
3543
  const activeVideo = videosData.find((video) => video.id === activeVideoId);
2152
3544
  if (activeVideo) {
@@ -2154,9 +3546,9 @@ var CreativeWork = ({
2154
3546
  }
2155
3547
  }
2156
3548
  }, [activeVideoId, videosData, events]);
2157
- const [error, setError] = (0, import_react14.useState)(null);
3549
+ const [error, setError] = (0, import_react16.useState)(null);
2158
3550
  const videosDataError = videosData?.some((video) => !!video.error);
2159
- (0, import_react14.useEffect)(() => {
3551
+ (0, import_react16.useEffect)(() => {
2160
3552
  if (creativeWorkError || videosError || videosDataError) {
2161
3553
  const errorObj = creativeWorkError || videosError || videosData?.find((video) => !!video.error)?.error && new Error(videosData?.find((video) => !!video.error)?.error) || new Error("default");
2162
3554
  setError(errorObj);
@@ -2170,7 +3562,7 @@ var CreativeWork = ({
2170
3562
  if (error) {
2171
3563
  const title = t(error.message)?.length ? t(error.message) : t("DEFAULT_ERROR");
2172
3564
  const description = t(`${error.message}_DESCRIPTION`)?.length ? t(`${error.message}_DESCRIPTION`) : t("DEFAULT_ERROR_DESCRIPTION");
2173
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: (0, import_tailwind_merge5.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3565
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: (0, import_tailwind_merge5.twMerge)("", className), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2174
3566
  ErrorScreen,
2175
3567
  {
2176
3568
  title,
@@ -2178,8 +3570,8 @@ var CreativeWork = ({
2178
3570
  }
2179
3571
  ) }) });
2180
3572
  }
2181
- const [loadingPlaylist, setLoadingPlaylist] = (0, import_react14.useState)(true);
2182
- (0, import_react14.useEffect)(() => {
3573
+ const [loadingPlaylist, setLoadingPlaylist] = (0, import_react16.useState)(true);
3574
+ (0, import_react16.useEffect)(() => {
2183
3575
  const creativeWorkLoadedWithNoVideos = !isCreativeWorkLoading && creativeWorkData && creativeWorkData.videoIds && creativeWorkData.videoIds.length === 0;
2184
3576
  const creativeWorkLoadedWithNoData = !isCreativeWorkLoading && creativeWorkData && !creativeWorkData.videoIds;
2185
3577
  const isEventsFinished = !videosIsLoading && videosData && videosData.length > 0 && videosData.every((video) => video.playlists && video.playlists.length === 0);
@@ -2200,10 +3592,10 @@ var CreativeWork = ({
2200
3592
  events
2201
3593
  ]);
2202
3594
  if (isCreativeWorkLoading || videosIsLoading || loadingApisState) {
2203
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: (0, import_tailwind_merge5.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Loading, {}) }) });
3595
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: (0, import_tailwind_merge5.twMerge)("", className), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "relative w-full aspect-video bg-[#151515]", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Loading, {}) }) });
2204
3596
  }
2205
3597
  if (showCountDown && creativeWorkData) {
2206
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: (0, import_tailwind_merge5.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative w-full h-full bg-base-200 text-base-content flex justify-center items-center flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3598
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: (0, import_tailwind_merge5.twMerge)("", className), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "relative w-full h-full bg-base-200 text-base-content flex justify-center items-center flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2207
3599
  PreCreativeWork,
2208
3600
  {
2209
3601
  creativeWork: creativeWorkData,
@@ -2216,20 +3608,25 @@ var CreativeWork = ({
2216
3608
  }
2217
3609
  if (activeVideoId && activePlaylist && !loadingPlaylist) {
2218
3610
  const activeVideo = videosData?.find((video) => video.id === activeVideoId);
2219
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: (0, import_tailwind_merge5.twMerge)("md:rounded-2xl overflow-hidden aspect-video", className), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative w-full h-full", children: [
2220
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3611
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: (0, import_tailwind_merge5.twMerge)("", className), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative w-full h-full", children: [
3612
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2221
3613
  Player,
2222
3614
  {
2223
3615
  ...props,
2224
- className: (0, import_tailwind_merge5.twMerge)(className, "peer"),
3616
+ className: (0, import_tailwind_merge5.twMerge)(className, "peer aspect-video"),
3617
+ managedMode: true,
2225
3618
  events: {
2226
3619
  ...events
2227
3620
  },
2228
3621
  src: activePlaylist,
2229
- containerClassName: "w-full h-full"
3622
+ locale,
3623
+ containerClassName: "w-full h-full",
3624
+ publicKey,
3625
+ auth,
3626
+ ...adsEnabled && activeVideo?.ad?.adTagUrl ? { imaConfig: { adTagUrl: activeVideo?.ad?.adTagUrl } } : {}
2230
3627
  }
2231
3628
  ),
2232
- !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3629
+ !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2233
3630
  TitleAndDescription2,
2234
3631
  {
2235
3632
  title: creativeWorkData?.title || "",
@@ -2242,7 +3639,7 @@ var CreativeWork = ({
2242
3639
  ] }) });
2243
3640
  }
2244
3641
  if (loadingPlaylist) {
2245
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Loading, {});
3642
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: (0, import_tailwind_merge5.twMerge)("", className), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "relative w-full aspect-video bg-[#151515]", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Loading, {}) }) });
2246
3643
  }
2247
3644
  return null;
2248
3645
  };
@@ -2255,12 +3652,12 @@ function PreCreativeWork({
2255
3652
  }) {
2256
3653
  const date = new Date(creativeWork.releaseTime);
2257
3654
  const now = /* @__PURE__ */ new Date();
2258
- const [remainingTime, setRemainingTime] = (0, import_react14.useState)(
3655
+ const [remainingTime, setRemainingTime] = (0, import_react16.useState)(
2259
3656
  date.getTime() - now.getTime()
2260
3657
  );
2261
3658
  const shouldBeStarted = remainingTime < 0;
2262
3659
  const { t } = useMessages_default(locale);
2263
- (0, import_react14.useEffect)(() => {
3660
+ (0, import_react16.useEffect)(() => {
2264
3661
  const interval = setInterval(() => {
2265
3662
  if (remainingTime < 0) {
2266
3663
  clearInterval(interval);
@@ -2274,27 +3671,26 @@ function PreCreativeWork({
2274
3671
  }, [date, remainingTime]);
2275
3672
  const renderCountdown = () => {
2276
3673
  if (shouldBeStarted) {
2277
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
3674
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
2278
3675
  }
2279
3676
  const seconds = Math.floor(remainingTime / 1e3) % 60;
2280
3677
  const minutes = Math.floor(remainingTime / 1e3 / 60) % 60;
2281
3678
  const hours = Math.floor(remainingTime / 1e3 / 60 / 60) % 24;
2282
3679
  const days = Math.floor(remainingTime / 1e3 / 60 / 60 / 24);
2283
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "grid grid-flow-col gap-5 text-center auto-cols-max", children: [
2284
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
2285
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "countdown font-mono text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3680
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid grid-flow-col md:gap-5 gap-1 text-center auto-cols-max", children: [
3681
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3682
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2286
3683
  "span",
2287
3684
  {
2288
- style: { "--value": days },
2289
3685
  "aria-live": "polite",
2290
3686
  "aria-label": days.toString(),
2291
- children: days?.toString()?.padStart(2, "0")
3687
+ children: days.toString()
2292
3688
  }
2293
3689
  ) }),
2294
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("DAYS") })
3690
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("DAYS") })
2295
3691
  ] }),
2296
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
2297
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "countdown font-mono text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3692
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3693
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2298
3694
  "span",
2299
3695
  {
2300
3696
  style: { "--value": hours },
@@ -2303,10 +3699,10 @@ function PreCreativeWork({
2303
3699
  children: hours?.toString()?.padStart(2, "0")
2304
3700
  }
2305
3701
  ) }),
2306
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("HOURS") })
3702
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("HOURS") })
2307
3703
  ] }),
2308
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
2309
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "countdown font-mono text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3704
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3705
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2310
3706
  "span",
2311
3707
  {
2312
3708
  style: { "--value": minutes },
@@ -2315,10 +3711,10 @@ function PreCreativeWork({
2315
3711
  children: minutes?.toString()?.padStart(2, "0")
2316
3712
  }
2317
3713
  ) }),
2318
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("MINUTES") })
3714
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("MINUTES") })
2319
3715
  ] }),
2320
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
2321
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "countdown font-mono text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3716
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3717
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2322
3718
  "span",
2323
3719
  {
2324
3720
  style: { "--value": seconds },
@@ -2327,12 +3723,12 @@ function PreCreativeWork({
2327
3723
  children: seconds?.toString()?.padStart(2, "0")
2328
3724
  }
2329
3725
  ) }),
2330
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("SECONDS") })
3726
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("SECONDS") })
2331
3727
  ] })
2332
3728
  ] });
2333
3729
  };
2334
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2335
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3730
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3731
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2336
3732
  "div",
2337
3733
  {
2338
3734
  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",
@@ -2340,12 +3736,12 @@ function PreCreativeWork({
2340
3736
  backgroundImage: backgroundImageUrl ? `url(${backgroundImageUrl})` : ""
2341
3737
  },
2342
3738
  children: [
2343
- backgroundImageUrl && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "absolute inset-0 bg-black bg-opacity-40" }),
2344
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative z-10", children: renderCountdown() })
3739
+ backgroundImageUrl && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "absolute inset-0 bg-black bg-opacity-40" }),
3740
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "relative z-10", children: renderCountdown() })
2345
3741
  ]
2346
3742
  }
2347
3743
  ),
2348
- !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3744
+ !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2349
3745
  TitleAndDescription2,
2350
3746
  {
2351
3747
  title: creativeWork.title,
@@ -2363,9 +3759,9 @@ var TitleAndDescription2 = ({
2363
3759
  locale = "en",
2364
3760
  className
2365
3761
  }) => {
2366
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: (0, import_tailwind_merge5.twMerge)("mt-3 mb-6 m-event-details-ctn px-4 text-left w-full", className), children: [
2367
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
2368
- releaseTime ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "text-sm md:text-base text-base-content/70 m-event-start-time", children: [
3762
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: (0, import_tailwind_merge5.twMerge)("mt-3 mb-6 m-event-details-ctn px-4 text-left w-full", className), children: [
3763
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
3764
+ releaseTime ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "text-sm md:text-base text-base-content/70 m-event-start-time", children: [
2369
3765
  new Date(releaseTime || "").toLocaleDateString(locale || "default", {
2370
3766
  month: "long",
2371
3767
  year: "numeric",
@@ -2378,13 +3774,13 @@ var TitleAndDescription2 = ({
2378
3774
  minute: "2-digit"
2379
3775
  })
2380
3776
  ] }) : null,
2381
- description && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-xs md:text-sm text-base-content/60 uppercase", children: description })
3777
+ description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-xs md:text-sm text-base-content/60 uppercase", children: description })
2382
3778
  ] });
2383
3779
  };
2384
3780
 
2385
3781
  // src/QueryProvider.tsx
2386
3782
  var import_react_query4 = require("@tanstack/react-query");
2387
- var import_jsx_runtime9 = require("react/jsx-runtime");
3783
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2388
3784
  var queryClient = new import_react_query4.QueryClient({
2389
3785
  defaultOptions: {
2390
3786
  queries: {
@@ -2398,14 +3794,17 @@ var queryClient = new import_react_query4.QueryClient({
2398
3794
  }
2399
3795
  });
2400
3796
  var QueryProvider = ({ children }) => {
2401
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_query4.QueryClientProvider, { client: queryClient, children });
3797
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_query4.QueryClientProvider, { client: queryClient, children });
2402
3798
  };
2403
3799
  // Annotate the CommonJS export names for ESM import in node:
2404
3800
  0 && (module.exports = {
3801
+ BigPlayIcon,
2405
3802
  CreativeWork,
2406
3803
  Event,
2407
3804
  Player,
2408
3805
  QueryProvider,
3806
+ SkipBackIcon,
3807
+ SkipForwardIcon,
2409
3808
  Video,
2410
3809
  queryClient
2411
3810
  });