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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.81";
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 {
98
750
  }
99
- if (drmConfig.servers) {
100
- player.configure({ "drm.servers": drmConfig.servers });
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
+ });
885
+ }
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) {
375
- this.onSkipForward = onSkipForward;
376
- }
377
- 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
- });
454
- }
455
- };
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;
1493
+ constructor(onSkipForward, iconSize) {
556
1494
  this.onSkipForward = onSkipForward;
1495
+ this.iconSize = iconSize;
557
1496
  }
558
1497
  create(rootElement, controls) {
559
- return new MobileControlsContainer(rootElement, controls, this.onSkipBack, this.onSkipForward);
1498
+ return new SkipForwardButton(rootElement, controls, this.onSkipForward, this.iconSize);
560
1499
  }
561
1500
  };
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,100 +1610,31 @@ 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;
658
1619
  if (onPlay) video.addEventListener("play", onPlay);
659
1620
  if (onPause) video.addEventListener("pause", onPause);
660
- if (onEnded) video.addEventListener("ended", onEnded);
661
- if (onLoadStart) video.addEventListener("loadstart", onLoadStart);
662
- if (onCanPlay) video.addEventListener("canplay", onCanPlay);
663
- }, [videoRef, handlers]);
664
- const cleanupEventListeners = (0, import_react6.useCallback)(() => {
665
- 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);
1621
+ if (onEnded) video.addEventListener("ended", onEnded);
1622
+ if (onLoadStart) video.addEventListener("loadstart", onLoadStart);
1623
+ if (onCanPlay) video.addEventListener("canplay", onCanPlay);
1624
+ }, [videoRef, handlers]);
1625
+ const cleanupEventListeners = (0, import_react7.useCallback)(() => {
1626
+ const video = videoRef.current;
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,144 @@ 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 (typeof player.isLive !== "function") {
1664
+ return { isLive: false, isNearEdge: false };
1665
+ }
1666
+ const isLiveStream = player.isLive();
1667
+ if (!isLiveStream) return { isLive: false, isNearEdge: false };
1668
+ const videoElement = player.getMediaElement?.();
1669
+ if (!videoElement) return { isLive: true, isNearEdge: false };
1670
+ if (typeof player.seekRange !== "function") {
1671
+ return { isLive: true, isNearEdge: false };
1672
+ }
1673
+ const seekRange = player.seekRange();
1674
+ if (!seekRange || seekRange.end === void 0) {
1675
+ return { isLive: true, isNearEdge: false };
1676
+ }
1677
+ const liveEdge = seekRange.end;
1678
+ const currentTime = videoElement.currentTime;
1679
+ const timeBehindLive = liveEdge - currentTime;
1680
+ return {
1681
+ isLive: true,
1682
+ isNearEdge: timeBehindLive <= liveThresholdSeconds,
1683
+ liveEdge
1684
+ };
1685
+ } catch (error) {
1686
+ console.error("Error checking live status:", error);
1687
+ return { isLive: false, isNearEdge: false };
1688
+ }
1689
+ };
1690
+ const seekToLiveEdge = () => {
1691
+ const player = playerRef.current;
1692
+ if (!player) return;
1693
+ try {
1694
+ if (typeof player.seekRange !== "function") return;
1695
+ const seekRange = player.seekRange();
1696
+ if (!seekRange || seekRange.end === void 0) return;
1697
+ const liveEdge = seekRange.end;
1698
+ const videoElement = player.getMediaElement?.();
1699
+ if (videoElement) {
1700
+ videoElement.currentTime = liveEdge;
1701
+ }
1702
+ } catch (error) {
1703
+ console.error("Error seeking to live edge:", error);
1704
+ }
1705
+ };
762
1706
  (0, import_react9.useEffect)(() => {
763
1707
  if (!containerRef.current || !enabled) {
764
1708
  return;
765
1709
  }
766
- const addLiveIndicator = (currentTimeElement) => {
767
- if (currentTimeElement.querySelector(".live-indicator-dot")) {
1710
+ const updateLiveIndicator = (currentTimeElement, status) => {
1711
+ const parent = currentTimeElement.parentElement;
1712
+ if (!parent) return;
1713
+ const existingContainer = parent.querySelector(".live-indicator-container");
1714
+ const isCurrentlyNearEdge = existingContainer?.getAttribute("data-near-edge") === "true";
1715
+ if (existingContainer && status.isNearEdge === isCurrentlyNearEdge) {
768
1716
  return;
769
1717
  }
1718
+ if (existingContainer) {
1719
+ existingContainer.remove();
1720
+ }
1721
+ const container = document.createElement("span");
1722
+ container.className = "live-indicator-container";
1723
+ container.setAttribute("data-near-edge", status.isNearEdge.toString());
1724
+ container.style.cssText = `
1725
+ display: inline-flex;
1726
+ align-items: center;
1727
+ width: 80px;
1728
+ ${!status.isNearEdge ? "cursor: pointer;" : ""}
1729
+ `;
770
1730
  const indicator = document.createElement("span");
771
1731
  indicator.className = "live-indicator-dot";
772
1732
  indicator.style.cssText = `
773
1733
  display: inline-block;
774
1734
  width: ${indicatorSize}px;
775
1735
  height: ${indicatorSize}px;
776
- background-color: ${indicatorColor};
1736
+ background-color: ${status.isNearEdge ? indicatorColor : "#888888"};
777
1737
  border-radius: 50%;
778
1738
  margin-right: 6px;
779
- vertical-align: middle;
780
- ${showPulseAnimation ? "animation: pulse-live 2s infinite;" : ""}
1739
+ ${status.isNearEdge && showPulseAnimation ? "animation: pulse-live 2s infinite;" : ""}
781
1740
  `;
782
- currentTimeElement.insertBefore(indicator, currentTimeElement.firstChild);
1741
+ const liveText = document.createElement("span");
1742
+ liveText.className = "live-indicator-text";
1743
+ liveText.textContent = status.isNearEdge ? "LIVE" : "GO TO LIVE";
1744
+ container.appendChild(indicator);
1745
+ container.appendChild(liveText);
1746
+ if (!status.isNearEdge) {
1747
+ container.addEventListener("click", seekToLiveEdge);
1748
+ }
1749
+ if (status.isNearEdge) {
1750
+ parent.insertBefore(container, currentTimeElement);
1751
+ currentTimeElement.style.display = "none";
1752
+ } else {
1753
+ currentTimeElement.insertAdjacentElement("afterend", container);
1754
+ currentTimeElement.style.display = "";
1755
+ }
783
1756
  };
784
1757
  const removeLiveIndicator = (currentTimeElement) => {
785
- const indicator = currentTimeElement.querySelector(".live-indicator-dot");
786
- if (indicator) {
787
- indicator.remove();
1758
+ const parent = currentTimeElement.parentElement;
1759
+ if (!parent) return;
1760
+ const container = parent.querySelector(".live-indicator-container");
1761
+ if (container) {
1762
+ container.remove();
1763
+ currentTimeElement.style.display = "";
788
1764
  }
789
1765
  };
790
1766
  const checkForLiveContent = () => {
791
1767
  const currentTimeElements = containerRef.current?.querySelectorAll(".shaka-current-time");
1768
+ const status = getLiveStatus(playerRef.current);
1769
+ const lastStatus = lastStatusRef.current;
1770
+ if (onLiveStatusChange && (!lastStatus || lastStatus.isLive !== status.isLive || lastStatus.isNearEdge !== status.isNearEdge)) {
1771
+ onLiveStatusChange(status);
1772
+ lastStatusRef.current = { isLive: status.isLive, isNearEdge: status.isNearEdge };
1773
+ }
792
1774
  currentTimeElements?.forEach((element) => {
793
- const textContent = element.textContent?.trim() || "";
794
- if (textContent.toLowerCase().includes("live")) {
795
- addLiveIndicator(element);
1775
+ if (status.isLive) {
1776
+ updateLiveIndicator(element, status);
796
1777
  } else {
797
1778
  removeLiveIndicator(element);
798
1779
  }
799
1780
  });
800
1781
  };
801
1782
  checkForLiveContent();
1783
+ intervalRef.current = setInterval(checkForLiveContent, 1e3);
802
1784
  observerRef.current = new MutationObserver((mutations) => {
803
1785
  let shouldCheck = false;
804
1786
  mutations.forEach((mutation) => {
@@ -824,31 +1806,289 @@ var useLiveIndicator = (containerRef, options = {}) => {
824
1806
  characterData: true,
825
1807
  characterDataOldValue: true
826
1808
  });
827
- const intervalId = setInterval(checkForLiveContent, 1e3);
828
1809
  return () => {
829
1810
  if (observerRef.current) {
830
1811
  observerRef.current.disconnect();
831
1812
  }
832
- clearInterval(intervalId);
1813
+ if (intervalRef.current) {
1814
+ clearInterval(intervalRef.current);
1815
+ }
833
1816
  };
834
- }, [containerRef, enabled, indicatorColor, indicatorSize, showPulseAnimation]);
1817
+ }, [containerRef, enabled, indicatorColor, indicatorSize, showPulseAnimation, liveThresholdSeconds]);
835
1818
  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")) {
1819
+ seekToLiveEdge,
1820
+ getLiveStatus: () => getLiveStatus(playerRef.current)
1821
+ };
1822
+ };
1823
+
1824
+ // src/hooks/useKeyboardControls.ts
1825
+ var import_react10 = require("react");
1826
+ var useKeyboardControls = (videoRef, options = {}) => {
1827
+ const { skipBack, skipForward, enabled = true } = options;
1828
+ const isDesktop = (0, import_react10.useCallback)(() => {
1829
+ return window.innerWidth > 767 && !/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
1830
+ }, []);
1831
+ const handleKeydown = (0, import_react10.useCallback)((event) => {
1832
+ if (!enabled || !isDesktop() || !videoRef.current) return;
1833
+ const activeElement = document.activeElement;
1834
+ if (activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.isContentEditable)) {
1835
+ return;
1836
+ }
1837
+ switch (event.key) {
1838
+ case "ArrowLeft":
1839
+ event.preventDefault();
1840
+ skipBack?.();
1841
+ break;
1842
+ case "ArrowRight":
1843
+ event.preventDefault();
1844
+ skipForward?.();
1845
+ break;
1846
+ case " ":
1847
+ case "Space":
1848
+ event.preventDefault();
1849
+ if (videoRef.current.paused) {
1850
+ videoRef.current.play();
1851
+ } else {
1852
+ videoRef.current.pause();
1853
+ }
1854
+ break;
1855
+ }
1856
+ }, [enabled, videoRef, skipBack, skipForward, isDesktop]);
1857
+ (0, import_react10.useEffect)(() => {
1858
+ if (!enabled || !isDesktop()) return;
1859
+ document.addEventListener("keydown", handleKeydown);
1860
+ return () => {
1861
+ document.removeEventListener("keydown", handleKeydown);
1862
+ };
1863
+ }, [handleKeydown, enabled, isDesktop]);
1864
+ return {
1865
+ isDesktop: isDesktop()
1866
+ };
1867
+ };
1868
+
1869
+ // src/hooks/useAdEvents.ts
1870
+ var import_react11 = require("react");
1871
+ var useAdEvents = (playerRef, handlers) => {
1872
+ const listenersRef = (0, import_react11.useRef)([]);
1873
+ const setupAdEventListeners = (0, import_react11.useCallback)(() => {
1874
+ const player = playerRef.current;
1875
+ if (!player) return;
1876
+ const adManager = player.getAdManager();
1877
+ if (!adManager) return;
1878
+ const onAdsManagerLoaded = (event) => {
1879
+ const adsManager = event.getAdsManager();
1880
+ const onAdStarted = () => {
1881
+ console.log("Ad started");
1882
+ handlers.onAdStart?.();
1883
+ };
1884
+ const onAdComplete = () => {
1885
+ console.log("Ad completed");
1886
+ handlers.onAdComplete?.();
1887
+ };
1888
+ const onAdError = (adErrorEvent) => {
1889
+ console.error("Ad error:", adErrorEvent.getError());
1890
+ handlers.onAdError?.(adErrorEvent.getError());
1891
+ };
1892
+ const onAdSkipped = () => {
1893
+ console.log("Ad skipped");
1894
+ handlers.onAdSkipped?.();
1895
+ };
1896
+ const onAdPaused = () => {
1897
+ console.log("Ad paused");
1898
+ handlers.onAdPaused?.();
1899
+ };
1900
+ const onAdResumed = () => {
1901
+ console.log("Ad resumed");
1902
+ handlers.onAdResumed?.();
1903
+ };
1904
+ const onAdProgress = (adProgressData) => {
1905
+ handlers.onAdProgress?.(adProgressData);
1906
+ };
1907
+ const onAllAdsCompleted = () => {
1908
+ console.log("All ads completed");
1909
+ handlers.onAllAdsCompleted?.();
1910
+ };
1911
+ const adEventListeners = [];
1912
+ if (window.google?.ima) {
1913
+ const AdEvent = window.google.ima.AdEvent.Type;
1914
+ const AdErrorEvent = window.google.ima.AdErrorEvent.Type;
1915
+ if (handlers.onAdStart) {
1916
+ adsManager.addEventListener(AdEvent.STARTED, onAdStarted);
1917
+ adEventListeners.push({ event: AdEvent.STARTED, listener: onAdStarted });
1918
+ }
1919
+ if (handlers.onAdComplete) {
1920
+ adsManager.addEventListener(AdEvent.COMPLETE, onAdComplete);
1921
+ adEventListeners.push({ event: AdEvent.COMPLETE, listener: onAdComplete });
1922
+ }
1923
+ if (handlers.onAdError) {
1924
+ adsManager.addEventListener(AdErrorEvent.AD_ERROR, onAdError);
1925
+ adEventListeners.push({ event: AdErrorEvent.AD_ERROR, listener: onAdError });
1926
+ }
1927
+ if (handlers.onAdSkipped) {
1928
+ adsManager.addEventListener(AdEvent.SKIPPED, onAdSkipped);
1929
+ adEventListeners.push({ event: AdEvent.SKIPPED, listener: onAdSkipped });
1930
+ }
1931
+ if (handlers.onAdPaused) {
1932
+ adsManager.addEventListener(AdEvent.PAUSED, onAdPaused);
1933
+ adEventListeners.push({ event: AdEvent.PAUSED, listener: onAdPaused });
1934
+ }
1935
+ if (handlers.onAdResumed) {
1936
+ adsManager.addEventListener(AdEvent.RESUMED, onAdResumed);
1937
+ adEventListeners.push({ event: AdEvent.RESUMED, listener: onAdResumed });
1938
+ }
1939
+ if (handlers.onAdProgress) {
1940
+ adsManager.addEventListener(AdEvent.AD_PROGRESS, onAdProgress);
1941
+ adEventListeners.push({ event: AdEvent.AD_PROGRESS, listener: onAdProgress });
1942
+ }
1943
+ if (handlers.onAllAdsCompleted) {
1944
+ adsManager.addEventListener(AdEvent.ALL_ADS_COMPLETED, onAllAdsCompleted);
1945
+ adEventListeners.push({ event: AdEvent.ALL_ADS_COMPLETED, listener: onAllAdsCompleted });
1946
+ }
1947
+ listenersRef.current.push({
1948
+ adsManager,
1949
+ listeners: adEventListeners
1950
+ });
1951
+ }
1952
+ };
1953
+ try {
1954
+ player.addEventListener("ad-started", () => {
1955
+ console.log("Shaka ad-started event");
1956
+ handlers.onAdStart?.();
1957
+ });
1958
+ player.addEventListener("ad-complete", () => {
1959
+ console.log("Shaka ad-complete event");
1960
+ handlers.onAdComplete?.();
1961
+ });
1962
+ player.addEventListener("ad-skipped", () => {
1963
+ console.log("Shaka ad-skipped event");
1964
+ handlers.onAdSkipped?.();
1965
+ });
1966
+ player.addEventListener("ad-error", (event) => {
1967
+ console.error("Shaka ad-error event:", event);
1968
+ handlers.onAdError?.(event);
1969
+ });
1970
+ listenersRef.current.push({
1971
+ type: "shaka",
1972
+ player,
1973
+ events: ["ad-started", "ad-complete", "ad-skipped", "ad-error"]
1974
+ });
1975
+ } catch (error) {
1976
+ console.warn("Error setting up ad event listeners:", error);
1977
+ }
1978
+ }, [playerRef, handlers]);
1979
+ const cleanupAdEventListeners = (0, import_react11.useCallback)(() => {
1980
+ try {
1981
+ listenersRef.current.forEach((listenerGroup) => {
1982
+ if (listenerGroup.type === "shaka" && listenerGroup.player) {
1983
+ listenerGroup.events.forEach((eventName) => {
1984
+ try {
1985
+ listenerGroup.player.removeEventListener(eventName, () => {
1986
+ });
1987
+ } catch (e) {
1988
+ console.warn(`Error removing ${eventName} listener:`, e);
1989
+ }
1990
+ });
1991
+ } else if (listenerGroup.adsManager && listenerGroup.listeners) {
1992
+ listenerGroup.listeners.forEach(({ event, listener }) => {
1993
+ try {
1994
+ listenerGroup.adsManager.removeEventListener(event, listener);
1995
+ } catch (e) {
1996
+ console.warn("Error removing ad listener:", e);
1997
+ }
1998
+ });
842
1999
  }
843
2000
  });
2001
+ listenersRef.current = [];
2002
+ } catch (error) {
2003
+ console.warn("Error cleaning up ad event listeners:", error);
844
2004
  }
2005
+ }, []);
2006
+ return {
2007
+ setupAdEventListeners,
2008
+ cleanupAdEventListeners
845
2009
  };
846
2010
  };
847
2011
 
2012
+ // src/Player.tsx
2013
+ var import_tailwind_merge2 = require("tailwind-merge");
2014
+
2015
+ // src/utils/scriptLoader.ts
2016
+ var SCRIPT_CONFIGS = {
2017
+ ima: {
2018
+ src: "https://imasdk.googleapis.com/js/sdkloader/ima3.js",
2019
+ id: "ima-sdk",
2020
+ type: "text/javascript"
2021
+ },
2022
+ system73: {
2023
+ src: "//cdn.s73cloud.com/4/s73-sdk-shakaplayer.js",
2024
+ id: "system73-sdk",
2025
+ type: "application/javascript"
2026
+ }
2027
+ };
2028
+ function loadScript(config) {
2029
+ return new Promise((resolve, reject) => {
2030
+ if (document.getElementById(config.id)) {
2031
+ resolve();
2032
+ return;
2033
+ }
2034
+ const script = document.createElement("script");
2035
+ script.id = config.id;
2036
+ script.src = config.src;
2037
+ script.type = config.type || "text/javascript";
2038
+ script.async = true;
2039
+ script.onload = () => resolve();
2040
+ script.onerror = () => reject(new Error(`Failed to load script: ${config.src}`));
2041
+ document.head.appendChild(script);
2042
+ });
2043
+ }
2044
+ function getRequiredScriptLoaders(needsIma, needsSystem73) {
2045
+ const loaders = [];
2046
+ if (needsIma) {
2047
+ loaders.push(loadScript(SCRIPT_CONFIGS.ima));
2048
+ }
2049
+ if (needsSystem73) {
2050
+ loaders.push(loadScript(SCRIPT_CONFIGS.system73));
2051
+ }
2052
+ return loaders;
2053
+ }
2054
+ async function loadScripts(scriptLoaders) {
2055
+ if (scriptLoaders.length === 0) {
2056
+ return;
2057
+ }
2058
+ try {
2059
+ await Promise.all(scriptLoaders);
2060
+ } catch (error) {
2061
+ console.error("Error loading scripts:", error);
2062
+ throw error;
2063
+ }
2064
+ }
2065
+ function waitForGlobal(globalName, timeout = 5e3) {
2066
+ return new Promise((resolve, reject) => {
2067
+ const startTime = Date.now();
2068
+ function checkGlobal() {
2069
+ const global = window[globalName];
2070
+ if (global) {
2071
+ resolve(global);
2072
+ return;
2073
+ }
2074
+ if (Date.now() - startTime > timeout) {
2075
+ reject(new Error(`Timeout waiting for global: ${globalName}`));
2076
+ return;
2077
+ }
2078
+ setTimeout(checkGlobal, 100);
2079
+ }
2080
+ checkGlobal();
2081
+ });
2082
+ }
2083
+ async function waitForGlobals(globalNames, timeout = 5e3) {
2084
+ const promises = globalNames.map((name) => waitForGlobal(name, timeout));
2085
+ await Promise.all(promises);
2086
+ }
2087
+
848
2088
  // src/components/Loading.tsx
849
2089
  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)(
2090
+ var import_jsx_runtime4 = require("react/jsx-runtime");
2091
+ var Loading = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
852
2092
  "div",
853
2093
  {
854
2094
  className: (0, import_tailwind_merge.twMerge)(
@@ -856,17 +2096,36 @@ var Loading = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
856
2096
  className
857
2097
  ),
858
2098
  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
- ]
2099
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: " flex justify-center items-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2100
+ "svg",
2101
+ {
2102
+ className: "shaka-spinner-svg animate-spin h-12 w-12",
2103
+ viewBox: "0 0 64 64",
2104
+ xmlns: "http://www.w3.org/2000/svg",
2105
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2106
+ "circle",
2107
+ {
2108
+ className: "shaka-spinner-path",
2109
+ cx: "32",
2110
+ cy: "32",
2111
+ r: "28",
2112
+ strokeWidth: "4",
2113
+ strokeLinecap: "round",
2114
+ stroke: "currentColor",
2115
+ fill: "none",
2116
+ strokeDasharray: "176",
2117
+ strokeDashoffset: "120"
2118
+ }
2119
+ )
2120
+ }
2121
+ ) })
863
2122
  }
864
2123
  );
865
2124
 
866
2125
  // 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)(
2126
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2127
+ 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: [
2128
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
870
2129
  "svg",
871
2130
  {
872
2131
  className: "w-24 h-24 m-6",
@@ -876,7 +2135,7 @@ var ErrorScreen = ({ title, description }) => /* @__PURE__ */ (0, import_jsx_run
876
2135
  style: { width: 96 },
877
2136
  viewBox: "0 0 24 24",
878
2137
  xmlns: "http://www.w3.org/2000/svg",
879
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2138
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
880
2139
  "path",
881
2140
  {
882
2141
  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 +2145,22 @@ var ErrorScreen = ({ title, description }) => /* @__PURE__ */ (0, import_jsx_run
886
2145
  )
887
2146
  }
888
2147
  ),
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." })
2148
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2149
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "text-2xl mb-2", children: title || "Playback Error" }),
2150
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-lg", children: description || "Unable to play the video. Please try again later." })
892
2151
  ] })
893
2152
  ] }) });
894
2153
 
895
2154
  // 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');
2155
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2156
+ 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
2157
 
943
2158
  // 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)(
2159
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2160
+ var Player = (0, import_react12.forwardRef)(
947
2161
  ({
948
2162
  src,
2163
+ managedMode = false,
949
2164
  autoPlay = false,
950
2165
  loop = false,
951
2166
  muted = false,
@@ -957,25 +2172,48 @@ var Player = (0, import_react10.forwardRef)(
957
2172
  shakaConfig,
958
2173
  drmConfig,
959
2174
  muxConfig,
2175
+ system73Config,
960
2176
  imaConfig,
961
2177
  chromecastConfig,
962
2178
  qualityConfig,
963
2179
  seekbarConfig,
2180
+ iconSizes,
964
2181
  events,
2182
+ locale = "en",
965
2183
  containerClassName,
966
- ...props
2184
+ liveThresholdSeconds = 15,
2185
+ publicKey,
2186
+ auth,
2187
+ ...videoProps
967
2188
  }, 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({
2189
+ const videoRef = (0, import_react12.useRef)(null);
2190
+ const containerRef = (0, import_react12.useRef)(null);
2191
+ const [isScriptsLoaded, setIsScriptsLoaded] = (0, import_react12.useState)(false);
2192
+ const [isInitialLoading, setIsInitialLoading] = (0, import_react12.useState)(true);
2193
+ const [bfResetKey, setBfResetKey] = (0, import_react12.useState)(0);
2194
+ const hasPlaylist = !!src && (typeof src === "string" || !!(src.url || src.drm?.widevine?.playlistUrl || src.drm?.playready?.playlistUrl || src.drm?.fairplay?.playlistUrl));
2195
+ (0, import_react12.useImperativeHandle)(ref, () => videoRef.current, []);
2196
+ const { playerRef, initializePlayer, loadManifest, destroyPlayer, isRetrying } = useShakaPlayer({
973
2197
  src,
974
2198
  shakaConfig,
975
2199
  drmConfig,
976
2200
  onError: events?.onError,
977
- onPlayerReady: events?.onPlayerReady
2201
+ onPlayerReady: events?.onPlayerReady,
2202
+ muxConfig,
2203
+ onMuxReady: events?.onMuxReady,
2204
+ onMuxDataUpdate: events?.onMuxDataUpdate,
2205
+ publicKey,
2206
+ mottoToken: auth?.mottoToken,
2207
+ hasAds: !!imaConfig?.adTagUrl,
2208
+ hasSystem73: !!system73Config?.apiKey,
2209
+ apiToken: auth?.apiToken
978
2210
  });
2211
+ const {
2212
+ initializeMux,
2213
+ updateMuxData,
2214
+ handleMuxError,
2215
+ destroyMux
2216
+ } = useMuxAnalytics(playerRef, muxConfig, events?.onMuxReady, events?.onMuxDataUpdate);
979
2217
  const {
980
2218
  getAvailableQualities,
981
2219
  setQuality,
@@ -988,12 +2226,11 @@ var Player = (0, import_react10.forwardRef)(
988
2226
  skipDuration,
989
2227
  shouldShowSkipControls
990
2228
  } = useSkipControls(videoRef, events?.onSkipBack, events?.onSkipForward);
991
- const {
992
- initializeMux,
993
- updateMuxData,
994
- handleMuxError,
995
- destroyMux
996
- } = useMuxAnalytics(playerRef, muxConfig, events?.onMuxReady, events?.onMuxDataUpdate);
2229
+ useKeyboardControls(videoRef, {
2230
+ skipBack,
2231
+ skipForward,
2232
+ enabled: true
2233
+ });
997
2234
  const { setupEventListeners, cleanupEventListeners } = useEventHandlers(videoRef, {
998
2235
  onPlay: events?.onPlay,
999
2236
  onPause: events?.onPause,
@@ -1009,110 +2246,231 @@ var Player = (0, import_react10.forwardRef)(
1009
2246
  chromecastConfig,
1010
2247
  seekbarConfig,
1011
2248
  events?.onSkipBack,
1012
- events?.onSkipForward
2249
+ events?.onSkipForward,
2250
+ iconSizes,
2251
+ locale
1013
2252
  );
1014
- const { isLive, isVisible: isLiveBadgeVisible } = useLiveBadge(playerRef, {
1015
- enabled: true,
1016
- onLiveStateChange: (isLive2) => {
1017
- events?.onLiveStateChange?.(isLive2);
1018
- }
1019
- });
1020
- useLiveIndicator(containerRef, {
2253
+ const { getLiveStatus, seekToLiveEdge } = useLiveIndicator(containerRef, playerRef, {
1021
2254
  enabled: true,
1022
2255
  indicatorColor: "#ff0000",
1023
2256
  indicatorSize: 8,
1024
- showPulseAnimation: true
2257
+ showPulseAnimation: true,
2258
+ liveThresholdSeconds,
2259
+ onLiveStatusChange: events?.onLiveStatusChange
1025
2260
  });
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
- }
2261
+ const { setupAdEventListeners, cleanupAdEventListeners } = useAdEvents(playerRef, {
2262
+ onAdStart: events?.onAdStart,
2263
+ onAdComplete: events?.onAdComplete,
2264
+ onAdError: events?.onAdError,
2265
+ onAdSkipped: events?.onAdSkipped,
2266
+ onAdPaused: events?.onAdPaused,
2267
+ onAdResumed: events?.onAdResumed,
2268
+ onAdProgress: events?.onAdProgress,
2269
+ onAllAdsCompleted: events?.onAllAdsCompleted
2270
+ });
2271
+ const initializeSystem73 = (0, import_react12.useCallback)((playerConfig) => {
2272
+ if (!system73Config?.apiKey || !window.S73ShakaPlayerWrapper) {
2273
+ return null;
1052
2274
  }
1053
- };
1054
- const initializeChromecast = () => {
1055
- if (!chromecastConfig?.enabled) {
2275
+ console.log("Initializing System73 SDK...");
2276
+ try {
2277
+ const s73Config = {
2278
+ apiKey: system73Config.apiKey,
2279
+ contentSteeringEndpoint: system73Config.contentSteeringEndpoint,
2280
+ channelId: system73Config.channelId
2281
+ };
2282
+ const wrapper = window.S73ShakaPlayerWrapper(s73Config, { shaka: import_shaka_player4.default });
2283
+ wrapper.wrapPlayerConfig(playerConfig);
2284
+ console.log("System73 SDK initialized with config:", s73Config);
2285
+ return wrapper;
2286
+ } catch (error) {
2287
+ console.error("Error initializing System73 SDK:", error);
2288
+ return null;
2289
+ }
2290
+ }, [system73Config]);
2291
+ const initializeAds = (0, import_react12.useCallback)(async () => {
2292
+ if (!imaConfig?.adTagUrl || !playerRef.current || !videoRef.current || !uiRef.current) {
2293
+ return;
2294
+ }
2295
+ if (!window.google?.ima) {
2296
+ console.error("Google IMA SDK not available when trying to initialize ads");
1056
2297
  return;
1057
2298
  }
1058
2299
  try {
1059
- if (events?.onCastStateChange) {
1060
- setTimeout(() => events.onCastStateChange(false), 100);
2300
+ const player = playerRef.current;
2301
+ const video = videoRef.current;
2302
+ const ui = uiRef.current;
2303
+ const controls2 = ui.getControls();
2304
+ const container = controls2.getClientSideAdContainer();
2305
+ const adManager = player.getAdManager();
2306
+ if (!adManager) {
2307
+ console.error("Ad manager not available");
2308
+ return;
1061
2309
  }
2310
+ const google = window.google;
2311
+ let adsRenderingSettings = null;
2312
+ if (imaConfig.adsRenderingSettings) {
2313
+ adsRenderingSettings = imaConfig.adsRenderingSettings;
2314
+ } else if (autoPlay) {
2315
+ adsRenderingSettings = new google.ima.AdsRenderingSettings();
2316
+ adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
2317
+ }
2318
+ adManager.initClientSide(container, video, adsRenderingSettings);
2319
+ const adsRequest = new google.ima.AdsRequest();
2320
+ adsRequest.adTagUrl = imaConfig.adTagUrl;
2321
+ adManager.requestClientSideAds(adsRequest);
2322
+ setupAdEventListeners();
2323
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
2324
+ await loadManifest();
1062
2325
  } catch (error) {
1063
- console.warn("Chromecast initialization failed:", error);
2326
+ console.error("Error initializing ads:", error);
1064
2327
  }
1065
- };
1066
- (0, import_react10.useEffect)(() => {
2328
+ }, [imaConfig, autoPlay, setupAdEventListeners, loadManifest]);
2329
+ (0, import_react12.useEffect)(() => {
2330
+ const loadRequiredScripts = async () => {
2331
+ try {
2332
+ const scriptLoaders = getRequiredScriptLoaders(!!imaConfig?.adTagUrl, !!system73Config?.apiKey);
2333
+ await loadScripts(scriptLoaders);
2334
+ const globalsToWait = [];
2335
+ if (imaConfig?.adTagUrl) {
2336
+ globalsToWait.push("google");
2337
+ }
2338
+ if (system73Config?.apiKey) {
2339
+ globalsToWait.push("S73ShakaPlayerWrapper");
2340
+ }
2341
+ if (globalsToWait.length > 0) {
2342
+ await waitForGlobals(globalsToWait);
2343
+ }
2344
+ setIsScriptsLoaded(true);
2345
+ } catch (error) {
2346
+ console.error("Error loading required scripts:", error);
2347
+ setIsScriptsLoaded(true);
2348
+ }
2349
+ };
2350
+ loadRequiredScripts();
2351
+ }, [imaConfig?.adTagUrl, system73Config?.apiKey]);
2352
+ (0, import_react12.useEffect)(() => {
2353
+ const onPageShow = (e) => {
2354
+ if (e && e.persisted) {
2355
+ setBfResetKey((k) => k + 1);
2356
+ }
2357
+ };
2358
+ window.addEventListener("pageshow", onPageShow);
2359
+ return () => window.removeEventListener("pageshow", onPageShow);
2360
+ }, []);
2361
+ (0, import_react12.useEffect)(() => {
1067
2362
  const video = videoRef.current;
1068
- if (!video) return;
2363
+ if (!video || !isScriptsLoaded) return;
1069
2364
  const initialize = async () => {
1070
2365
  try {
2366
+ console.log("\u{1F680} [Player] Starting initialization...");
2367
+ setIsInitialLoading(true);
2368
+ let system73Wrapper = null;
2369
+ if (system73Config?.apiKey && window.S73ShakaPlayerWrapper) {
2370
+ console.log("\u{1F4E6} [System73] Step 1: Initializing System73 wrapper with config");
2371
+ const playerConfig = { ...shakaConfig };
2372
+ system73Wrapper = initializeSystem73(playerConfig);
2373
+ if (system73Wrapper) {
2374
+ shakaConfig = playerConfig;
2375
+ console.log("\u2705 [System73] Step 1 complete: Wrapper created and config modified");
2376
+ }
2377
+ }
2378
+ console.log("\u{1F3AC} [Shaka] Step 2: Initializing Shaka Player (auto-load:", !system73Config?.apiKey && !imaConfig?.adTagUrl, ")");
1071
2379
  await initializePlayer(video);
2380
+ console.log("\u2705 [Shaka] Step 2 complete: Player initialized");
2381
+ if (system73Wrapper && playerRef.current) {
2382
+ console.log("\u{1F517} [System73] Step 3: Wrapping Shaka player with System73");
2383
+ system73Wrapper.wrapPlayer(playerRef.current);
2384
+ console.log("\u2705 [System73] Step 3 complete: Player wrapped");
2385
+ if (!imaConfig?.adTagUrl) {
2386
+ console.log("\u{1F4FA} [System73] Step 4: Loading manifest");
2387
+ await loadManifest();
2388
+ console.log("\u2705 [System73] Step 4 complete: Manifest loaded");
2389
+ } else {
2390
+ console.log("\u23ED\uFE0F [System73] Skipping manifest load - ads will handle it");
2391
+ }
2392
+ }
2393
+ console.log("\u{1F4CB} [Player] Setting up event listeners and quality tracking");
1072
2394
  setupEventListeners();
1073
2395
  const cleanupQuality = setupQualityTracking();
1074
2396
  configureQuality();
2397
+ console.log("\u{1F3A8} [UI] Initializing Shaka UI");
1075
2398
  await initializeUI();
1076
- initializeMux();
1077
- initializeAds();
1078
- initializeChromecast();
2399
+ console.log("\u2705 [UI] UI initialized");
2400
+ if (imaConfig?.adTagUrl && window.google?.ima) {
2401
+ console.log("\u{1F4E2} [Ads] Initializing ads (will load manifest after VAST fetch)");
2402
+ await initializeAds();
2403
+ console.log("\u2705 [Ads] Ads initialized and manifest loaded");
2404
+ }
2405
+ console.log("\u2728 [Player] Initialization complete!");
1079
2406
  } catch (error) {
1080
- console.error("Error during player initialization:", error);
2407
+ console.error("\u274C [Player] Error during initialization:", error);
1081
2408
  handleMuxError(error);
1082
2409
  }
1083
2410
  };
1084
2411
  initialize();
1085
2412
  return () => {
1086
2413
  cleanupEventListeners();
2414
+ cleanupAdEventListeners();
1087
2415
  destroyUI();
1088
2416
  destroyMux();
1089
2417
  destroyPlayer();
1090
2418
  };
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)(() => {
2419
+ }, [managedMode ? hasPlaylist : src, isScriptsLoaded, bfResetKey, managedMode]);
2420
+ (0, import_react12.useEffect)(() => {
2421
+ const video = videoRef.current;
2422
+ if (!video) return;
2423
+ const onLoadStart = () => {
2424
+ setIsInitialLoading(true);
2425
+ };
2426
+ const onCanPlay = () => {
2427
+ setIsInitialLoading(false);
2428
+ };
2429
+ const onPlaying = () => {
2430
+ setIsInitialLoading(false);
2431
+ };
2432
+ video.addEventListener("loadstart", onLoadStart);
2433
+ video.addEventListener("canplay", onCanPlay);
2434
+ video.addEventListener("playing", onPlaying);
2435
+ return () => {
2436
+ video.removeEventListener("loadstart", onLoadStart);
2437
+ video.removeEventListener("canplay", onCanPlay);
2438
+ video.removeEventListener("playing", onPlaying);
2439
+ };
2440
+ }, []);
2441
+ (0, import_react12.useEffect)(() => {
1107
2442
  const video = videoRef.current;
1108
2443
  if (!video) return;
1109
2444
  video.autoplay = autoPlay;
1110
2445
  video.loop = loop;
1111
- video.muted = muted;
1112
2446
  video.controls = false;
1113
2447
  if (poster) video.poster = poster;
1114
- }, [autoPlay, loop, muted, poster]);
1115
- (0, import_react10.useImperativeHandle)(ref, () => ({
2448
+ }, [autoPlay, loop, muted, poster, imaConfig?.adTagUrl]);
2449
+ (0, import_react12.useEffect)(() => {
2450
+ const video = videoRef.current;
2451
+ if (!video) return;
2452
+ video.controls = false;
2453
+ video.setAttribute("controls", "false");
2454
+ video.removeAttribute("controls");
2455
+ const observer = new MutationObserver((mutations) => {
2456
+ mutations.forEach((mutation) => {
2457
+ if (mutation.type === "attributes" && mutation.attributeName === "controls") {
2458
+ if (video.hasAttribute("controls")) {
2459
+ video.removeAttribute("controls");
2460
+ video.controls = false;
2461
+ }
2462
+ }
2463
+ });
2464
+ });
2465
+ observer.observe(video, {
2466
+ attributes: true,
2467
+ attributeFilter: ["controls"]
2468
+ });
2469
+ return () => {
2470
+ observer.disconnect();
2471
+ };
2472
+ }, []);
2473
+ (0, import_react12.useImperativeHandle)(ref, () => ({
1116
2474
  ...videoRef.current,
1117
2475
  // Custom methods for quality control
1118
2476
  getAvailableQualities,
@@ -1122,27 +2480,30 @@ var Player = (0, import_react10.forwardRef)(
1122
2480
  skipForward,
1123
2481
  // Mux methods
1124
2482
  updateMuxData,
2483
+ // Live status methods
2484
+ getLiveStatus,
2485
+ seekToLiveEdge,
1125
2486
  // Access to underlying instances
1126
2487
  getPlayer: () => playerRef.current,
1127
2488
  getMuxMonitor: () => null
1128
- }), [getAvailableQualities, setQuality, skipBack, skipForward, updateMuxData]);
2489
+ }), [getAvailableQualities, setQuality, skipBack, skipForward, updateMuxData, getLiveStatus, seekToLiveEdge]);
1129
2490
  const isResponsive = !width && !height;
1130
- const containerClasses = (0, import_tailwind_merge2.twMerge)(containerClassName, "motto-video-container");
2491
+ const containerClasses = (0, import_tailwind_merge2.twMerge)(containerClassName, "motto-video-container relative bg-[#111111] ");
1131
2492
  const containerStyle = isResponsive ? {
1132
2493
  aspectRatio: aspectRatio.toString()
1133
2494
  } : { width, height };
1134
- const videoClasses = isResponsive ? "motto-video-responsive" : "w-full h-full ";
2495
+ const videoClasses = isResponsive ? "motto-video-responsive w-full" : "w-full h-full ";
1135
2496
  const videoStyle = isResponsive ? {} : { width, height };
1136
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2497
+ const filteredVideoProps = { ...videoProps };
2498
+ delete filteredVideoProps.controls;
2499
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1137
2500
  "div",
1138
2501
  {
1139
2502
  ref: containerRef,
1140
2503
  className: containerClasses,
1141
2504
  style: containerStyle,
1142
- "data-shaka-player-container": true,
1143
- "data-shaka-player-cast-receiver-id": chromecastConfig?.receiverApplicationId,
1144
2505
  children: [
1145
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2506
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1146
2507
  "video",
1147
2508
  {
1148
2509
  ref: videoRef,
@@ -1151,17 +2512,11 @@ var Player = (0, import_react10.forwardRef)(
1151
2512
  height: isResponsive ? void 0 : height,
1152
2513
  style: videoStyle,
1153
2514
  controls: false,
1154
- ...props
2515
+ playsInline: true,
2516
+ ...filteredVideoProps
1155
2517
  }
1156
2518
  ),
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
- )
2519
+ 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
2520
  ]
1166
2521
  }
1167
2522
  );
@@ -1170,16 +2525,16 @@ var Player = (0, import_react10.forwardRef)(
1170
2525
  Player.displayName = "Player";
1171
2526
 
1172
2527
  // src/Video.tsx
1173
- var import_react12 = require("react");
2528
+ var import_react14 = require("react");
1174
2529
  var import_tailwind_merge3 = require("tailwind-merge");
1175
2530
  var import_react_query = require("@tanstack/react-query");
1176
2531
 
1177
2532
  // src/api/video.ts
1178
- var fetchVideoData = async (videoId, publicKey, mottoToken) => {
2533
+ var fetchVideoData = async (videoId, publicKey, mottoToken, adsEnabled = false, locale = "en") => {
1179
2534
  const endpoint = "https://cda.mottostreaming.com/motto.cda.streaming.video.v1.VideoService/GetVideo";
1180
2535
  const url = new URL(endpoint);
1181
2536
  url.searchParams.set("encoding", "json");
1182
- url.searchParams.set("message", JSON.stringify({ videoId }));
2537
+ url.searchParams.set("message", JSON.stringify({ videoId, enable_ads: adsEnabled, locale }));
1183
2538
  const response = await fetch(url, {
1184
2539
  method: "GET",
1185
2540
  headers: {
@@ -1193,14 +2548,14 @@ var fetchVideoData = async (videoId, publicKey, mottoToken) => {
1193
2548
  const data = await response.json();
1194
2549
  return data.video;
1195
2550
  };
1196
- async function fetchVideosList(publicKey, videoIds, mottoToken, skip = 0, limit = 0) {
2551
+ async function fetchVideosList(publicKey, videoIds, mottoToken, skip = 0, limit = 0, adsEnabled = true, locale = "en") {
1197
2552
  if (!videoIds || videoIds.length === 0) {
1198
2553
  return [];
1199
2554
  }
1200
2555
  const endpoint = "https://cda.mottostreaming.com/motto.cda.streaming.video.v1.VideoService/BatchGetVideos";
1201
2556
  const url = new URL(endpoint);
1202
2557
  url.searchParams.set("encoding", "json");
1203
- url.searchParams.set("message", JSON.stringify({ videoIds }));
2558
+ url.searchParams.set("message", JSON.stringify({ videoIds, enable_ads: adsEnabled, locale }));
1204
2559
  const response = await fetch(url.toString(), {
1205
2560
  method: "GET",
1206
2561
  headers: {
@@ -1311,7 +2666,7 @@ var getErrorType = (error, video) => {
1311
2666
  };
1312
2667
 
1313
2668
  // src/messages/useMessages.tsx
1314
- var import_react11 = require("react");
2669
+ var import_react13 = require("react");
1315
2670
 
1316
2671
  // src/messages/en.json
1317
2672
  var en_default = {
@@ -1613,9 +2968,9 @@ var getBrowserLanguage = () => {
1613
2968
  return availableLanguages[language] ? language : "en";
1614
2969
  };
1615
2970
  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)(() => {
2971
+ const [language, setLanguage] = (0, import_react13.useState)("en");
2972
+ const [translations, setTranslations] = (0, import_react13.useState)(availableLanguages.en);
2973
+ (0, import_react13.useEffect)(() => {
1619
2974
  const lang = !!availableLanguages?.[locale] ? locale : getBrowserLanguage();
1620
2975
  ;
1621
2976
  setLanguage(lang);
@@ -1641,11 +2996,10 @@ var useMessages = (locale) => {
1641
2996
  var useMessages_default = useMessages;
1642
2997
 
1643
2998
  // src/Video.tsx
1644
- var import_jsx_runtime6 = require("react/jsx-runtime");
2999
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1645
3000
  var Video = ({
1646
3001
  videoId,
1647
3002
  publicKey,
1648
- mottoToken,
1649
3003
  videoData: providedVideoData,
1650
3004
  refetchInterval = 0,
1651
3005
  playerName,
@@ -1653,7 +3007,10 @@ var Video = ({
1653
3007
  events,
1654
3008
  children,
1655
3009
  className,
3010
+ auth,
3011
+ settings,
1656
3012
  queryOptions = {},
3013
+ adsEnabled = false,
1657
3014
  ...props
1658
3015
  }) => {
1659
3016
  const {
@@ -1662,8 +3019,8 @@ var Video = ({
1662
3019
  error,
1663
3020
  refetch
1664
3021
  } = (0, import_react_query.useQuery)({
1665
- queryKey: ["video", videoId, publicKey, mottoToken],
1666
- queryFn: () => fetchVideoData(videoId, publicKey, mottoToken),
3022
+ queryKey: ["video", videoId, publicKey, auth?.mottoToken, adsEnabled, locale],
3023
+ queryFn: () => fetchVideoData(videoId, publicKey, auth?.mottoToken, adsEnabled, locale),
1667
3024
  enabled: !!videoId && !!publicKey && !providedVideoData,
1668
3025
  refetchInterval: refetchInterval > 0 ? refetchInterval : false,
1669
3026
  staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
@@ -1676,16 +3033,17 @@ var Video = ({
1676
3033
  const video = providedVideoData || data;
1677
3034
  const { t } = useMessages_default(locale);
1678
3035
  const activePlaylist = findHLSPlaylist(video);
1679
- const hlsUrl = activePlaylist?.url;
1680
- (0, import_react12.useEffect)(() => {
3036
+ const activePlaylistUrl = activePlaylist?.url ?? activePlaylist?.drm?.widevine?.playlistUrl ?? activePlaylist?.drm?.playready?.playlistUrl ?? activePlaylist?.drm?.fairplay?.playlistUrl;
3037
+ const activePlaylistHasUrl = !!activePlaylistUrl;
3038
+ (0, import_react14.useEffect)(() => {
1681
3039
  if (events?.onVideoData && video) {
1682
3040
  events.onVideoData(video);
1683
3041
  }
1684
3042
  }, [video, events]);
1685
3043
  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, {}) }) });
3044
+ 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
3045
  }
1688
- if (!isLoading && video && !hlsUrl && events?.onEmptyPlaylists) {
3046
+ if (!isLoading && video && !activePlaylistHasUrl && events?.onEmptyPlaylists) {
1689
3047
  events.onEmptyPlaylists();
1690
3048
  }
1691
3049
  if (error || video?.error) {
@@ -1696,8 +3054,8 @@ var Video = ({
1696
3054
  }
1697
3055
  const title = t(errorKey) || t("DEFAULT_ERROR");
1698
3056
  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)(
3057
+ 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: [
3058
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1701
3059
  ErrorScreen,
1702
3060
  {
1703
3061
  title,
@@ -1707,31 +3065,35 @@ var Video = ({
1707
3065
  children
1708
3066
  ] }) });
1709
3067
  }
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 || "" }),
3068
+ if (!activePlaylist || !activePlaylistHasUrl) {
3069
+ 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: [
3070
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Title, { title: video?.name || "" }),
1713
3071
  children
1714
3072
  ] }) });
1715
3073
  }
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)(
3074
+ 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
3075
  Player,
1719
3076
  {
1720
3077
  ...props,
1721
- src: hlsUrl,
3078
+ src: activePlaylist,
3079
+ managedMode: true,
1722
3080
  className: (0, import_tailwind_merge3.twMerge)("video-player-container", className),
1723
3081
  events,
3082
+ locale,
1724
3083
  containerClassName: "w-full h-full",
3084
+ publicKey,
3085
+ auth,
3086
+ ...adsEnabled && video?.ad?.adTagUrl ? { imaConfig: { adTagUrl: video?.ad?.adTagUrl } } : {},
1725
3087
  children
1726
3088
  }
1727
3089
  ) }) });
1728
3090
  };
1729
3091
 
1730
3092
  // src/Event.tsx
1731
- var import_react13 = require("react");
3093
+ var import_react15 = require("react");
1732
3094
  var import_tailwind_merge4 = require("tailwind-merge");
1733
3095
  var import_react_query2 = require("@tanstack/react-query");
1734
- var import_jsx_runtime7 = require("react/jsx-runtime");
3096
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1735
3097
  var Event = ({
1736
3098
  publicKey,
1737
3099
  eventId,
@@ -1744,6 +3106,7 @@ var Event = ({
1744
3106
  settings,
1745
3107
  auth,
1746
3108
  queryOptions = {},
3109
+ adsEnabled = false,
1747
3110
  ...props
1748
3111
  }) => {
1749
3112
  const {
@@ -1761,16 +3124,16 @@ var Event = ({
1761
3124
  retry: queryOptions.retry ?? 3,
1762
3125
  retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
1763
3126
  });
1764
- const [activePlaylist, setActivePlaylist] = (0, import_react13.useState)();
1765
- const [activeVideoId, setActiveVideoId] = (0, import_react13.useState)();
3127
+ const [activePlaylist, setActivePlaylist] = (0, import_react15.useState)();
3128
+ const [activeVideoId, setActiveVideoId] = (0, import_react15.useState)();
1766
3129
  const videoIds = eventData?.videoIds ?? [];
1767
3130
  const {
1768
3131
  data: videosData,
1769
3132
  isLoading: videosIsLoading,
1770
3133
  error: videosError
1771
3134
  } = (0, import_react_query2.useQuery)({
1772
- queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken],
1773
- queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0),
3135
+ queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken, adsEnabled, locale],
3136
+ queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0, adsEnabled, locale),
1774
3137
  enabled: !!publicKey && videoIds.length > 0,
1775
3138
  refetchInterval: activePlaylist === null ? 3e4 : false,
1776
3139
  staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
@@ -1778,8 +3141,8 @@ var Event = ({
1778
3141
  retry: queryOptions.retry ?? 3,
1779
3142
  retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
1780
3143
  });
1781
- const [loadingApisState, setLoadingApisState] = (0, import_react13.useState)(true);
1782
- (0, import_react13.useEffect)(() => {
3144
+ const [loadingApisState, setLoadingApisState] = (0, import_react15.useState)(true);
3145
+ (0, import_react15.useEffect)(() => {
1783
3146
  if (videosData !== void 0) {
1784
3147
  setLoadingApisState(false);
1785
3148
  const videosWithPlaylists = videosData.filter(
@@ -1788,9 +3151,11 @@ var Event = ({
1788
3151
  if (videosWithPlaylists.length > 0) {
1789
3152
  let hlsPlaylistFound = false;
1790
3153
  for (const video of videosWithPlaylists) {
1791
- const hlsPlaylist = findHLSPlaylist(video);
1792
- if (hlsPlaylist?.url) {
1793
- setActivePlaylist(hlsPlaylist.url);
3154
+ const activePlaylist2 = findHLSPlaylist(video);
3155
+ const activePlaylistUrl = activePlaylist2?.url ?? activePlaylist2?.drm?.widevine?.playlistUrl ?? activePlaylist2?.drm?.playready?.playlistUrl ?? activePlaylist2?.drm?.fairplay?.playlistUrl;
3156
+ const activePlaylistHasUrl = !!activePlaylistUrl;
3157
+ if (activePlaylist2 && activePlaylistHasUrl) {
3158
+ setActivePlaylist(activePlaylist2);
1794
3159
  setActiveVideoId(video.id);
1795
3160
  hlsPlaylistFound = true;
1796
3161
  break;
@@ -1811,12 +3176,12 @@ var Event = ({
1811
3176
  }
1812
3177
  }, [videosData, eventData]);
1813
3178
  const { t } = useMessages_default(locale);
1814
- (0, import_react13.useEffect)(() => {
3179
+ (0, import_react15.useEffect)(() => {
1815
3180
  if (events?.onEventData && eventData) {
1816
3181
  events.onEventData(eventData);
1817
3182
  }
1818
3183
  }, [eventData, events]);
1819
- (0, import_react13.useEffect)(() => {
3184
+ (0, import_react15.useEffect)(() => {
1820
3185
  if (events?.onVideoData && activeVideoId && videosData) {
1821
3186
  const activeVideo = videosData.find((video) => video.id === activeVideoId);
1822
3187
  if (activeVideo) {
@@ -1824,12 +3189,17 @@ var Event = ({
1824
3189
  }
1825
3190
  }
1826
3191
  }, [activeVideoId, videosData, events]);
1827
- const [error, setError] = (0, import_react13.useState)(null);
1828
- const [loadingPlaylist, setLoadingPlaylist] = (0, import_react13.useState)(true);
3192
+ const [error, setError] = (0, import_react15.useState)(null);
3193
+ const [loadingPlaylist, setLoadingPlaylist] = (0, import_react15.useState)(true);
1829
3194
  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");
3195
+ (0, import_react15.useEffect)(() => {
3196
+ if (isEventLoading || videosIsLoading || loadingApisState) {
3197
+ return;
3198
+ }
3199
+ const hasPlayablePlaylist = Boolean(activePlaylist);
3200
+ if (eventError || videosError || videosDataError && !hasPlayablePlaylist) {
3201
+ const firstVideoError = videosData?.find((video) => !!video.error)?.error;
3202
+ const errorObj = eventError || videosError || firstVideoError && new Error(firstVideoError) || new Error("default");
1833
3203
  setError(errorObj);
1834
3204
  if (events?.onError) {
1835
3205
  events.onError(errorObj);
@@ -1837,8 +3207,18 @@ var Event = ({
1837
3207
  } else {
1838
3208
  setError(null);
1839
3209
  }
1840
- }, [eventError, videosError, videosDataError, videosData, events]);
1841
- (0, import_react13.useEffect)(() => {
3210
+ }, [
3211
+ eventError,
3212
+ videosError,
3213
+ videosDataError,
3214
+ videosData,
3215
+ events,
3216
+ activePlaylist,
3217
+ isEventLoading,
3218
+ videosIsLoading,
3219
+ loadingApisState
3220
+ ]);
3221
+ (0, import_react15.useEffect)(() => {
1842
3222
  const eventLoadedWithNoVideos = !isEventLoading && eventData && eventData.videoIds && (!eventData.videoIds || eventData?.videoIds?.length === 0) && !loadingApisState;
1843
3223
  const allApisLoadedWithPotentialVideos = !isEventLoading && !videosIsLoading && eventData && !loadingApisState;
1844
3224
  if (eventLoadedWithNoVideos || allApisLoadedWithPotentialVideos) {
@@ -1848,7 +3228,7 @@ var Event = ({
1848
3228
  if (error) {
1849
3229
  const title = t(error.message)?.length ? t(error.message) : t("DEFAULT_ERROR");
1850
3230
  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)(
3231
+ 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
3232
  ErrorScreen,
1853
3233
  {
1854
3234
  title,
@@ -1860,22 +3240,28 @@ var Event = ({
1860
3240
  events.onEmptyPlaylists();
1861
3241
  }
1862
3242
  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, {}) }) });
3243
+ 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
3244
  }
1865
3245
  if (activePlaylist && activeVideoId && videosData) {
1866
3246
  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)(
3247
+ console.log("activeVideo?.ad?.adTagUrl", activeVideo?.ad?.adTagUrl);
3248
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: (0, import_tailwind_merge4.twMerge)("", className), children: [
3249
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1869
3250
  Player,
1870
3251
  {
1871
3252
  ...props,
1872
3253
  src: activePlaylist,
1873
- className: (0, import_tailwind_merge4.twMerge)(className, "peer"),
3254
+ managedMode: true,
3255
+ className: (0, import_tailwind_merge4.twMerge)(className, "peer aspect-video"),
1874
3256
  events,
1875
- containerClassName: "w-full h-full"
3257
+ locale,
3258
+ containerClassName: "w-full h-full",
3259
+ publicKey,
3260
+ auth,
3261
+ ...adsEnabled && activeVideo ? { imaConfig: { adTagUrl: activeVideo?.ad?.adTagUrl } } : {}
1876
3262
  }
1877
- ),
1878
- !hideTitle && eventData && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3263
+ ) }),
3264
+ !hideTitle && eventData && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1879
3265
  TitleAndDescription,
1880
3266
  {
1881
3267
  title: eventData.title,
@@ -1884,10 +3270,10 @@ var Event = ({
1884
3270
  locale
1885
3271
  }
1886
3272
  )
1887
- ] }) });
3273
+ ] });
1888
3274
  }
1889
3275
  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)(
3276
+ 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
3277
  PreEvent,
1892
3278
  {
1893
3279
  event: eventData,
@@ -1909,12 +3295,12 @@ function PreEvent({
1909
3295
  }) {
1910
3296
  const date = new Date(event.startTime);
1911
3297
  const now = /* @__PURE__ */ new Date();
1912
- const [remainingTime, setRemainingTime] = (0, import_react13.useState)(
3298
+ const [remainingTime, setRemainingTime] = (0, import_react15.useState)(
1913
3299
  date.getTime() - now.getTime()
1914
3300
  );
1915
3301
  const shouldBeStarted = remainingTime < 0;
1916
3302
  const { t } = useMessages_default(locale);
1917
- (0, import_react13.useEffect)(() => {
3303
+ (0, import_react15.useEffect)(() => {
1918
3304
  const interval = setInterval(() => {
1919
3305
  if (remainingTime < 0) {
1920
3306
  clearInterval(interval);
@@ -1924,29 +3310,28 @@ function PreEvent({
1924
3310
  }, 1e3);
1925
3311
  return () => clearInterval(interval);
1926
3312
  }, [date, remainingTime]);
1927
- const renderCountdown = (0, import_react13.useCallback)(() => {
3313
+ const renderCountdown = (0, import_react15.useCallback)(() => {
1928
3314
  if (shouldBeStarted) {
1929
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
3315
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
1930
3316
  }
1931
3317
  const seconds = Math.floor(remainingTime / 1e3) % 60;
1932
3318
  const minutes = Math.floor(remainingTime / 1e3 / 60) % 60;
1933
3319
  const hours = Math.floor(remainingTime / 1e3 / 60 / 60) % 24;
1934
3320
  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)(
3321
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-flow-col gap-1 md:gap-5 text-center auto-cols-max", children: [
3322
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3323
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1938
3324
  "span",
1939
3325
  {
1940
- style: { "--value": days },
1941
3326
  "aria-live": "polite",
1942
3327
  "aria-label": days.toString(),
1943
- children: days?.toString()?.padStart(2, "0")
3328
+ children: days.toString()
1944
3329
  }
1945
3330
  ) }),
1946
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("DAYS") })
3331
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("DAYS") })
1947
3332
  ] }),
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)(
3333
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3334
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1950
3335
  "span",
1951
3336
  {
1952
3337
  style: { "--value": hours },
@@ -1955,10 +3340,10 @@ function PreEvent({
1955
3340
  children: hours?.toString()?.padStart(2, "0")
1956
3341
  }
1957
3342
  ) }),
1958
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("HOURS") })
3343
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("HOURS") })
1959
3344
  ] }),
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)(
3345
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3346
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1962
3347
  "span",
1963
3348
  {
1964
3349
  style: { "--value": minutes },
@@ -1967,10 +3352,10 @@ function PreEvent({
1967
3352
  children: minutes?.toString()?.padStart(2, "0")
1968
3353
  }
1969
3354
  ) }),
1970
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("MINUTES") })
3355
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("MINUTES") })
1971
3356
  ] }),
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)(
3357
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3358
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1974
3359
  "span",
1975
3360
  {
1976
3361
  style: { "--value": seconds },
@@ -1979,12 +3364,12 @@ function PreEvent({
1979
3364
  children: seconds?.toString()?.padStart(2, "0")
1980
3365
  }
1981
3366
  ) }),
1982
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("SECONDS") })
3367
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("SECONDS") })
1983
3368
  ] })
1984
3369
  ] });
1985
3370
  }, [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)(
3371
+ 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: [
3372
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1988
3373
  "div",
1989
3374
  {
1990
3375
  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 +3378,10 @@ function PreEvent({
1993
3378
  backgroundRepeat: "no-repeat",
1994
3379
  backgroundSize: "cover"
1995
3380
  },
1996
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative z-10", children: renderCountdown() })
3381
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative z-10", children: renderCountdown() })
1997
3382
  }
1998
3383
  ),
1999
- !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3384
+ !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2000
3385
  TitleAndDescription,
2001
3386
  {
2002
3387
  title: event.title,
@@ -2005,18 +3390,18 @@ function PreEvent({
2005
3390
  locale
2006
3391
  }
2007
3392
  )
2008
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2009
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3393
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
3394
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2010
3395
  "div",
2011
3396
  {
2012
3397
  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
3398
  style: {
2014
3399
  backgroundImage: backgroundImageUrl ? `url(${backgroundImageUrl})` : ""
2015
3400
  },
2016
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative z-10", children: renderCountdown() })
3401
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative z-10", children: renderCountdown() })
2017
3402
  }
2018
3403
  ),
2019
- !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3404
+ !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2020
3405
  TitleAndDescription,
2021
3406
  {
2022
3407
  title: event.title,
@@ -2034,9 +3419,9 @@ var TitleAndDescription = ({
2034
3419
  locale = "en",
2035
3420
  className
2036
3421
  }) => {
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: [
3422
+ 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: [
3423
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
3424
+ startTime ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-xs md:text-base text-base-content/70 m-event-start-time", children: [
2040
3425
  new Date(startTime || "").toLocaleDateString(locale || "default", {
2041
3426
  month: "long",
2042
3427
  year: "numeric",
@@ -2049,15 +3434,15 @@ var TitleAndDescription = ({
2049
3434
  minute: "2-digit"
2050
3435
  })
2051
3436
  ] }) : null,
2052
- description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs md:text-sm text-base-content/60 uppercase", children: description })
3437
+ description && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs md:text-xs text-base-content/60 uppercase", children: description })
2053
3438
  ] });
2054
3439
  };
2055
3440
 
2056
3441
  // src/CreativeWork.tsx
2057
- var import_react14 = require("react");
3442
+ var import_react16 = require("react");
2058
3443
  var import_tailwind_merge5 = require("tailwind-merge");
2059
3444
  var import_react_query3 = require("@tanstack/react-query");
2060
- var import_jsx_runtime8 = require("react/jsx-runtime");
3445
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2061
3446
  var CreativeWork = ({
2062
3447
  publicKey,
2063
3448
  creativeWorkId,
@@ -2070,6 +3455,7 @@ var CreativeWork = ({
2070
3455
  settings,
2071
3456
  auth,
2072
3457
  queryOptions = {},
3458
+ adsEnabled = false,
2073
3459
  ...props
2074
3460
  }) => {
2075
3461
  const {
@@ -2087,17 +3473,17 @@ var CreativeWork = ({
2087
3473
  retry: queryOptions.retry ?? 3,
2088
3474
  retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
2089
3475
  });
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);
3476
+ const [activePlaylist, setActivePlaylist] = (0, import_react16.useState)();
3477
+ const [activeVideoId, setActiveVideoId] = (0, import_react16.useState)();
3478
+ const [showCountDown, setShowCountDown] = (0, import_react16.useState)(false);
2093
3479
  const videoIds = creativeWorkData?.videoIds ?? [];
2094
3480
  const {
2095
3481
  data: videosData,
2096
3482
  isLoading: videosIsLoading,
2097
3483
  error: videosError
2098
3484
  } = (0, import_react_query3.useQuery)({
2099
- queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken],
2100
- queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0),
3485
+ queryKey: ["videos-list", publicKey, videoIds, auth?.mottoToken, adsEnabled, locale],
3486
+ queryFn: () => fetchVideosList(publicKey, videoIds, auth?.mottoToken, 0, 0, adsEnabled, locale),
2101
3487
  enabled: !!publicKey && videoIds.length > 0,
2102
3488
  refetchInterval: activePlaylist === null ? 3e4 : false,
2103
3489
  staleTime: queryOptions.staleTime ?? 5 * 60 * 1e3,
@@ -2105,8 +3491,8 @@ var CreativeWork = ({
2105
3491
  retry: queryOptions.retry ?? 3,
2106
3492
  retryDelay: queryOptions.retryDelay ?? ((attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4))
2107
3493
  });
2108
- const [loadingApisState, setLoadingApisState] = (0, import_react14.useState)(true);
2109
- (0, import_react14.useEffect)(() => {
3494
+ const [loadingApisState, setLoadingApisState] = (0, import_react16.useState)(true);
3495
+ (0, import_react16.useEffect)(() => {
2110
3496
  if (videosData !== void 0) {
2111
3497
  setLoadingApisState(false);
2112
3498
  const videosWithPlaylists = videosData.filter(
@@ -2115,9 +3501,11 @@ var CreativeWork = ({
2115
3501
  if (videosWithPlaylists.length > 0) {
2116
3502
  let hlsPlaylistFound = false;
2117
3503
  for (const video of videosWithPlaylists) {
2118
- const hlsPlaylist = findHLSPlaylist(video);
2119
- if (hlsPlaylist?.url) {
2120
- setActivePlaylist(hlsPlaylist.url);
3504
+ const activePlaylist2 = findHLSPlaylist(video);
3505
+ const activePlaylistUrl = activePlaylist2?.url ?? activePlaylist2?.drm?.widevine?.playlistUrl ?? activePlaylist2?.drm?.playready?.playlistUrl ?? activePlaylist2?.drm?.fairplay?.playlistUrl;
3506
+ const activePlaylistHasUrl = !!activePlaylistUrl;
3507
+ if (activePlaylist2 && activePlaylistHasUrl) {
3508
+ setActivePlaylist(activePlaylist2);
2121
3509
  setActiveVideoId(video.id);
2122
3510
  hlsPlaylistFound = true;
2123
3511
  break;
@@ -2138,7 +3526,7 @@ var CreativeWork = ({
2138
3526
  }
2139
3527
  }, [videosData, creativeWorkData]);
2140
3528
  const { t } = useMessages_default(locale);
2141
- (0, import_react14.useEffect)(() => {
3529
+ (0, import_react16.useEffect)(() => {
2142
3530
  if (events?.onCreativeWorkData && creativeWorkData) {
2143
3531
  events.onCreativeWorkData(creativeWorkData);
2144
3532
  }
@@ -2146,7 +3534,7 @@ var CreativeWork = ({
2146
3534
  setShowCountDown(true);
2147
3535
  }
2148
3536
  }, [creativeWorkData, events]);
2149
- (0, import_react14.useEffect)(() => {
3537
+ (0, import_react16.useEffect)(() => {
2150
3538
  if (events?.onVideoData && activeVideoId && videosData) {
2151
3539
  const activeVideo = videosData.find((video) => video.id === activeVideoId);
2152
3540
  if (activeVideo) {
@@ -2154,9 +3542,9 @@ var CreativeWork = ({
2154
3542
  }
2155
3543
  }
2156
3544
  }, [activeVideoId, videosData, events]);
2157
- const [error, setError] = (0, import_react14.useState)(null);
3545
+ const [error, setError] = (0, import_react16.useState)(null);
2158
3546
  const videosDataError = videosData?.some((video) => !!video.error);
2159
- (0, import_react14.useEffect)(() => {
3547
+ (0, import_react16.useEffect)(() => {
2160
3548
  if (creativeWorkError || videosError || videosDataError) {
2161
3549
  const errorObj = creativeWorkError || videosError || videosData?.find((video) => !!video.error)?.error && new Error(videosData?.find((video) => !!video.error)?.error) || new Error("default");
2162
3550
  setError(errorObj);
@@ -2170,7 +3558,7 @@ var CreativeWork = ({
2170
3558
  if (error) {
2171
3559
  const title = t(error.message)?.length ? t(error.message) : t("DEFAULT_ERROR");
2172
3560
  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)(
3561
+ 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
3562
  ErrorScreen,
2175
3563
  {
2176
3564
  title,
@@ -2178,8 +3566,8 @@ var CreativeWork = ({
2178
3566
  }
2179
3567
  ) }) });
2180
3568
  }
2181
- const [loadingPlaylist, setLoadingPlaylist] = (0, import_react14.useState)(true);
2182
- (0, import_react14.useEffect)(() => {
3569
+ const [loadingPlaylist, setLoadingPlaylist] = (0, import_react16.useState)(true);
3570
+ (0, import_react16.useEffect)(() => {
2183
3571
  const creativeWorkLoadedWithNoVideos = !isCreativeWorkLoading && creativeWorkData && creativeWorkData.videoIds && creativeWorkData.videoIds.length === 0;
2184
3572
  const creativeWorkLoadedWithNoData = !isCreativeWorkLoading && creativeWorkData && !creativeWorkData.videoIds;
2185
3573
  const isEventsFinished = !videosIsLoading && videosData && videosData.length > 0 && videosData.every((video) => video.playlists && video.playlists.length === 0);
@@ -2200,10 +3588,10 @@ var CreativeWork = ({
2200
3588
  events
2201
3589
  ]);
2202
3590
  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, {}) }) });
3591
+ 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
3592
  }
2205
3593
  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)(
3594
+ 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
3595
  PreCreativeWork,
2208
3596
  {
2209
3597
  creativeWork: creativeWorkData,
@@ -2216,20 +3604,25 @@ var CreativeWork = ({
2216
3604
  }
2217
3605
  if (activeVideoId && activePlaylist && !loadingPlaylist) {
2218
3606
  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)(
3607
+ 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: [
3608
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2221
3609
  Player,
2222
3610
  {
2223
3611
  ...props,
2224
- className: (0, import_tailwind_merge5.twMerge)(className, "peer"),
3612
+ className: (0, import_tailwind_merge5.twMerge)(className, "peer aspect-video"),
3613
+ managedMode: true,
2225
3614
  events: {
2226
3615
  ...events
2227
3616
  },
2228
3617
  src: activePlaylist,
2229
- containerClassName: "w-full h-full"
3618
+ locale,
3619
+ containerClassName: "w-full h-full",
3620
+ publicKey,
3621
+ auth,
3622
+ ...adsEnabled && activeVideo?.ad?.adTagUrl ? { imaConfig: { adTagUrl: activeVideo?.ad?.adTagUrl } } : {}
2230
3623
  }
2231
3624
  ),
2232
- !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3625
+ !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2233
3626
  TitleAndDescription2,
2234
3627
  {
2235
3628
  title: creativeWorkData?.title || "",
@@ -2242,7 +3635,7 @@ var CreativeWork = ({
2242
3635
  ] }) });
2243
3636
  }
2244
3637
  if (loadingPlaylist) {
2245
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Loading, {});
3638
+ 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
3639
  }
2247
3640
  return null;
2248
3641
  };
@@ -2255,12 +3648,12 @@ function PreCreativeWork({
2255
3648
  }) {
2256
3649
  const date = new Date(creativeWork.releaseTime);
2257
3650
  const now = /* @__PURE__ */ new Date();
2258
- const [remainingTime, setRemainingTime] = (0, import_react14.useState)(
3651
+ const [remainingTime, setRemainingTime] = (0, import_react16.useState)(
2259
3652
  date.getTime() - now.getTime()
2260
3653
  );
2261
3654
  const shouldBeStarted = remainingTime < 0;
2262
3655
  const { t } = useMessages_default(locale);
2263
- (0, import_react14.useEffect)(() => {
3656
+ (0, import_react16.useEffect)(() => {
2264
3657
  const interval = setInterval(() => {
2265
3658
  if (remainingTime < 0) {
2266
3659
  clearInterval(interval);
@@ -2274,27 +3667,26 @@ function PreCreativeWork({
2274
3667
  }, [date, remainingTime]);
2275
3668
  const renderCountdown = () => {
2276
3669
  if (shouldBeStarted) {
2277
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
3670
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-base-content text-xl", children: t("EVENT_NOT_STARTED") });
2278
3671
  }
2279
3672
  const seconds = Math.floor(remainingTime / 1e3) % 60;
2280
3673
  const minutes = Math.floor(remainingTime / 1e3 / 60) % 60;
2281
3674
  const hours = Math.floor(remainingTime / 1e3 / 60 / 60) % 24;
2282
3675
  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)(
3676
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid grid-flow-col md:gap-5 gap-1 text-center auto-cols-max", children: [
3677
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3678
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2286
3679
  "span",
2287
3680
  {
2288
- style: { "--value": days },
2289
3681
  "aria-live": "polite",
2290
3682
  "aria-label": days.toString(),
2291
- children: days?.toString()?.padStart(2, "0")
3683
+ children: days.toString()
2292
3684
  }
2293
3685
  ) }),
2294
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("DAYS") })
3686
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("DAYS") })
2295
3687
  ] }),
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)(
3688
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3689
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2298
3690
  "span",
2299
3691
  {
2300
3692
  style: { "--value": hours },
@@ -2303,10 +3695,10 @@ function PreCreativeWork({
2303
3695
  children: hours?.toString()?.padStart(2, "0")
2304
3696
  }
2305
3697
  ) }),
2306
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("HOURS") })
3698
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("HOURS") })
2307
3699
  ] }),
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)(
3700
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3701
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2310
3702
  "span",
2311
3703
  {
2312
3704
  style: { "--value": minutes },
@@ -2315,10 +3707,10 @@ function PreCreativeWork({
2315
3707
  children: minutes?.toString()?.padStart(2, "0")
2316
3708
  }
2317
3709
  ) }),
2318
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("MINUTES") })
3710
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("MINUTES") })
2319
3711
  ] }),
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)(
3712
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col p-2 bg-neutral rounded-box text-neutral-content", children: [
3713
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "countdown font-mono text-lg md:text-5xl", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2322
3714
  "span",
2323
3715
  {
2324
3716
  style: { "--value": seconds },
@@ -2327,12 +3719,12 @@ function PreCreativeWork({
2327
3719
  children: seconds?.toString()?.padStart(2, "0")
2328
3720
  }
2329
3721
  ) }),
2330
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm uppercase tracking-widest mt-1", children: t("SECONDS") })
3722
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs uppercase tracking-widest mt-1", children: t("SECONDS") })
2331
3723
  ] })
2332
3724
  ] });
2333
3725
  };
2334
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2335
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3726
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3727
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2336
3728
  "div",
2337
3729
  {
2338
3730
  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 +3732,12 @@ function PreCreativeWork({
2340
3732
  backgroundImage: backgroundImageUrl ? `url(${backgroundImageUrl})` : ""
2341
3733
  },
2342
3734
  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() })
3735
+ backgroundImageUrl && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "absolute inset-0 bg-black bg-opacity-40" }),
3736
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "relative z-10", children: renderCountdown() })
2345
3737
  ]
2346
3738
  }
2347
3739
  ),
2348
- !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3740
+ !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2349
3741
  TitleAndDescription2,
2350
3742
  {
2351
3743
  title: creativeWork.title,
@@ -2363,9 +3755,9 @@ var TitleAndDescription2 = ({
2363
3755
  locale = "en",
2364
3756
  className
2365
3757
  }) => {
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: [
3758
+ 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: [
3759
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-base md:text-xl m-event-title text-base-content font-medium", children: title }),
3760
+ releaseTime ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "text-sm md:text-base text-base-content/70 m-event-start-time", children: [
2369
3761
  new Date(releaseTime || "").toLocaleDateString(locale || "default", {
2370
3762
  month: "long",
2371
3763
  year: "numeric",
@@ -2378,13 +3770,13 @@ var TitleAndDescription2 = ({
2378
3770
  minute: "2-digit"
2379
3771
  })
2380
3772
  ] }) : null,
2381
- description && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-xs md:text-sm text-base-content/60 uppercase", children: description })
3773
+ description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-xs md:text-sm text-base-content/60 uppercase", children: description })
2382
3774
  ] });
2383
3775
  };
2384
3776
 
2385
3777
  // src/QueryProvider.tsx
2386
3778
  var import_react_query4 = require("@tanstack/react-query");
2387
- var import_jsx_runtime9 = require("react/jsx-runtime");
3779
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2388
3780
  var queryClient = new import_react_query4.QueryClient({
2389
3781
  defaultOptions: {
2390
3782
  queries: {
@@ -2398,14 +3790,17 @@ var queryClient = new import_react_query4.QueryClient({
2398
3790
  }
2399
3791
  });
2400
3792
  var QueryProvider = ({ children }) => {
2401
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_query4.QueryClientProvider, { client: queryClient, children });
3793
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_query4.QueryClientProvider, { client: queryClient, children });
2402
3794
  };
2403
3795
  // Annotate the CommonJS export names for ESM import in node:
2404
3796
  0 && (module.exports = {
3797
+ BigPlayIcon,
2405
3798
  CreativeWork,
2406
3799
  Event,
2407
3800
  Player,
2408
3801
  QueryProvider,
3802
+ SkipBackIcon,
3803
+ SkipForwardIcon,
2409
3804
  Video,
2410
3805
  queryClient
2411
3806
  });