@livepeer-frameworks/player-react 0.1.0 → 0.1.2

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.
Files changed (187) hide show
  1. package/README.md +7 -9
  2. package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +359 -0
  3. package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  4. package/dist/cjs/assets/logomark.svg.js +8 -0
  5. package/dist/cjs/assets/logomark.svg.js.map +1 -0
  6. package/dist/cjs/components/DevModePanel.js +826 -0
  7. package/dist/cjs/components/DevModePanel.js.map +1 -0
  8. package/dist/cjs/components/DvdLogo.js +200 -0
  9. package/dist/cjs/components/DvdLogo.js.map +1 -0
  10. package/dist/cjs/components/Icons.js +439 -0
  11. package/dist/cjs/components/Icons.js.map +1 -0
  12. package/dist/cjs/components/IdleScreen.js +587 -0
  13. package/dist/cjs/components/IdleScreen.js.map +1 -0
  14. package/dist/cjs/components/LoadingScreen.js +523 -0
  15. package/dist/cjs/components/LoadingScreen.js.map +1 -0
  16. package/dist/cjs/components/Player.js +420 -0
  17. package/dist/cjs/components/Player.js.map +1 -0
  18. package/dist/cjs/components/PlayerControls.js +798 -0
  19. package/dist/cjs/components/PlayerControls.js.map +1 -0
  20. package/dist/cjs/components/PlayerErrorBoundary.js +80 -0
  21. package/dist/cjs/components/PlayerErrorBoundary.js.map +1 -0
  22. package/dist/cjs/components/SeekBar.js +253 -0
  23. package/dist/cjs/components/SeekBar.js.map +1 -0
  24. package/dist/cjs/components/SkipIndicator.js +92 -0
  25. package/dist/cjs/components/SkipIndicator.js.map +1 -0
  26. package/dist/cjs/components/SpeedIndicator.js +43 -0
  27. package/dist/cjs/components/SpeedIndicator.js.map +1 -0
  28. package/dist/cjs/components/StatsPanel.js +202 -0
  29. package/dist/cjs/components/StatsPanel.js.map +1 -0
  30. package/dist/cjs/components/StreamStateOverlay.js +229 -0
  31. package/dist/cjs/components/StreamStateOverlay.js.map +1 -0
  32. package/dist/cjs/components/ThumbnailOverlay.js +86 -0
  33. package/dist/cjs/components/ThumbnailOverlay.js.map +1 -0
  34. package/dist/cjs/components/TitleOverlay.js +32 -0
  35. package/dist/cjs/components/TitleOverlay.js.map +1 -0
  36. package/dist/cjs/context/PlayerContext.js +46 -0
  37. package/dist/cjs/context/PlayerContext.js.map +1 -0
  38. package/dist/cjs/hooks/useMetaTrack.js +165 -0
  39. package/dist/cjs/hooks/useMetaTrack.js.map +1 -0
  40. package/dist/cjs/hooks/usePlaybackQuality.js +131 -0
  41. package/dist/cjs/hooks/usePlaybackQuality.js.map +1 -0
  42. package/dist/cjs/hooks/usePlayerController.js +518 -0
  43. package/dist/cjs/hooks/usePlayerController.js.map +1 -0
  44. package/dist/cjs/hooks/usePlayerSelection.js +90 -0
  45. package/dist/cjs/hooks/usePlayerSelection.js.map +1 -0
  46. package/dist/cjs/hooks/useStreamState.js +360 -0
  47. package/dist/cjs/hooks/useStreamState.js.map +1 -0
  48. package/dist/cjs/hooks/useTelemetry.js +120 -0
  49. package/dist/cjs/hooks/useTelemetry.js.map +1 -0
  50. package/dist/cjs/hooks/useViewerEndpoints.js +222 -0
  51. package/dist/cjs/hooks/useViewerEndpoints.js.map +1 -0
  52. package/dist/cjs/index.js +97 -1
  53. package/dist/cjs/index.js.map +1 -1
  54. package/dist/cjs/ui/badge.js +34 -0
  55. package/dist/cjs/ui/badge.js.map +1 -0
  56. package/dist/cjs/ui/button.js +74 -0
  57. package/dist/cjs/ui/button.js.map +1 -0
  58. package/dist/cjs/ui/context-menu.js +163 -0
  59. package/dist/cjs/ui/context-menu.js.map +1 -0
  60. package/dist/cjs/ui/slider.js +60 -0
  61. package/dist/cjs/ui/slider.js.map +1 -0
  62. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
  63. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  64. package/dist/esm/assets/logomark.svg.js +4 -0
  65. package/dist/esm/assets/logomark.svg.js.map +1 -0
  66. package/dist/esm/components/DevModePanel.js +822 -0
  67. package/dist/esm/components/DevModePanel.js.map +1 -0
  68. package/dist/esm/components/DvdLogo.js +196 -0
  69. package/dist/esm/components/DvdLogo.js.map +1 -0
  70. package/dist/esm/components/Icons.js +421 -0
  71. package/dist/esm/components/Icons.js.map +1 -0
  72. package/dist/esm/components/IdleScreen.js +582 -0
  73. package/dist/esm/components/IdleScreen.js.map +1 -0
  74. package/dist/esm/components/LoadingScreen.js +519 -0
  75. package/dist/esm/components/LoadingScreen.js.map +1 -0
  76. package/dist/esm/components/Player.js +416 -0
  77. package/dist/esm/components/Player.js.map +1 -0
  78. package/dist/esm/components/PlayerControls.js +794 -0
  79. package/dist/esm/components/PlayerControls.js.map +1 -0
  80. package/dist/esm/components/PlayerErrorBoundary.js +76 -0
  81. package/dist/esm/components/PlayerErrorBoundary.js.map +1 -0
  82. package/dist/esm/components/SeekBar.js +249 -0
  83. package/dist/esm/components/SeekBar.js.map +1 -0
  84. package/dist/esm/components/SkipIndicator.js +88 -0
  85. package/dist/esm/components/SkipIndicator.js.map +1 -0
  86. package/dist/esm/components/SpeedIndicator.js +39 -0
  87. package/dist/esm/components/SpeedIndicator.js.map +1 -0
  88. package/dist/esm/components/StatsPanel.js +198 -0
  89. package/dist/esm/components/StatsPanel.js.map +1 -0
  90. package/dist/esm/components/StreamStateOverlay.js +224 -0
  91. package/dist/esm/components/StreamStateOverlay.js.map +1 -0
  92. package/dist/esm/components/ThumbnailOverlay.js +82 -0
  93. package/dist/esm/components/ThumbnailOverlay.js.map +1 -0
  94. package/dist/esm/components/TitleOverlay.js +28 -0
  95. package/dist/esm/components/TitleOverlay.js.map +1 -0
  96. package/dist/esm/context/PlayerContext.js +41 -0
  97. package/dist/esm/context/PlayerContext.js.map +1 -0
  98. package/dist/esm/hooks/useMetaTrack.js +163 -0
  99. package/dist/esm/hooks/useMetaTrack.js.map +1 -0
  100. package/dist/esm/hooks/usePlaybackQuality.js +129 -0
  101. package/dist/esm/hooks/usePlaybackQuality.js.map +1 -0
  102. package/dist/esm/hooks/usePlayerController.js +516 -0
  103. package/dist/esm/hooks/usePlayerController.js.map +1 -0
  104. package/dist/esm/hooks/usePlayerSelection.js +88 -0
  105. package/dist/esm/hooks/usePlayerSelection.js.map +1 -0
  106. package/dist/esm/hooks/useStreamState.js +358 -0
  107. package/dist/esm/hooks/useStreamState.js.map +1 -0
  108. package/dist/esm/hooks/useTelemetry.js +118 -0
  109. package/dist/esm/hooks/useTelemetry.js.map +1 -0
  110. package/dist/esm/hooks/useViewerEndpoints.js +220 -0
  111. package/dist/esm/hooks/useViewerEndpoints.js.map +1 -0
  112. package/dist/esm/index.js +23 -1
  113. package/dist/esm/index.js.map +1 -1
  114. package/dist/esm/ui/badge.js +31 -0
  115. package/dist/esm/ui/badge.js.map +1 -0
  116. package/dist/esm/ui/button.js +52 -0
  117. package/dist/esm/ui/button.js.map +1 -0
  118. package/dist/esm/ui/context-menu.js +132 -0
  119. package/dist/esm/ui/context-menu.js.map +1 -0
  120. package/dist/esm/ui/slider.js +38 -0
  121. package/dist/esm/ui/slider.js.map +1 -0
  122. package/dist/types/components/DvdLogo.d.ts +1 -1
  123. package/dist/types/components/Icons.d.ts +1 -1
  124. package/dist/types/components/Player.d.ts +1 -1
  125. package/dist/types/components/PlayerErrorBoundary.d.ts +2 -1
  126. package/dist/types/components/StreamStateOverlay.d.ts +2 -2
  127. package/dist/types/components/SubtitleRenderer.d.ts +2 -2
  128. package/dist/types/context/PlayerContext.d.ts +2 -2
  129. package/dist/types/context/index.d.ts +2 -2
  130. package/dist/types/hooks/useMetaTrack.d.ts +3 -3
  131. package/dist/types/hooks/usePlaybackQuality.d.ts +2 -2
  132. package/dist/types/hooks/usePlayerController.d.ts +26 -3
  133. package/dist/types/hooks/usePlayerSelection.d.ts +1 -1
  134. package/dist/types/hooks/useStreamState.d.ts +1 -1
  135. package/dist/types/hooks/useTelemetry.d.ts +1 -1
  136. package/dist/types/hooks/useViewerEndpoints.d.ts +3 -3
  137. package/dist/types/index.d.ts +28 -28
  138. package/dist/types/types.d.ts +3 -3
  139. package/dist/types/ui/select.d.ts +1 -1
  140. package/package.json +22 -14
  141. package/src/components/DevModePanel.tsx +244 -143
  142. package/src/components/DvdLogo.tsx +1 -1
  143. package/src/components/Icons.tsx +105 -25
  144. package/src/components/IdleScreen.tsx +262 -128
  145. package/src/components/LoadingScreen.tsx +169 -151
  146. package/src/components/LogoOverlay.tsx +3 -6
  147. package/src/components/Player.tsx +126 -59
  148. package/src/components/PlayerControls.tsx +384 -272
  149. package/src/components/PlayerErrorBoundary.tsx +7 -13
  150. package/src/components/SeekBar.tsx +96 -88
  151. package/src/components/SkipIndicator.tsx +2 -12
  152. package/src/components/SpeedIndicator.tsx +2 -11
  153. package/src/components/StatsPanel.tsx +31 -22
  154. package/src/components/StreamStateOverlay.tsx +105 -49
  155. package/src/components/SubtitleRenderer.tsx +29 -29
  156. package/src/components/ThumbnailOverlay.tsx +5 -6
  157. package/src/components/TitleOverlay.tsx +2 -8
  158. package/src/context/PlayerContext.tsx +4 -8
  159. package/src/context/index.ts +3 -3
  160. package/src/hooks/useMetaTrack.ts +27 -27
  161. package/src/hooks/usePlaybackQuality.ts +3 -3
  162. package/src/hooks/usePlayerController.ts +246 -138
  163. package/src/hooks/usePlayerSelection.ts +6 -6
  164. package/src/hooks/useStreamState.ts +51 -56
  165. package/src/hooks/useTelemetry.ts +18 -3
  166. package/src/hooks/useViewerEndpoints.ts +34 -23
  167. package/src/index.tsx +36 -28
  168. package/src/types.ts +8 -8
  169. package/src/ui/badge.tsx +6 -5
  170. package/src/ui/button.tsx +9 -8
  171. package/src/ui/context-menu.tsx +42 -61
  172. package/src/ui/select.tsx +13 -7
  173. package/src/ui/slider.tsx +18 -29
  174. package/dist/types/components/players/DashJsPlayer.d.ts +0 -18
  175. package/dist/types/components/players/HlsJsPlayer.d.ts +0 -18
  176. package/dist/types/components/players/MewsWsPlayer/index.d.ts +0 -18
  177. package/dist/types/components/players/MistPlayer.d.ts +0 -20
  178. package/dist/types/components/players/MistWebRTCPlayer/index.d.ts +0 -20
  179. package/dist/types/components/players/NativePlayer.d.ts +0 -19
  180. package/dist/types/components/players/VideoJsPlayer.d.ts +0 -18
  181. package/src/components/players/DashJsPlayer.tsx +0 -56
  182. package/src/components/players/HlsJsPlayer.tsx +0 -56
  183. package/src/components/players/MewsWsPlayer/index.tsx +0 -56
  184. package/src/components/players/MistPlayer.tsx +0 -60
  185. package/src/components/players/MistWebRTCPlayer/index.tsx +0 -59
  186. package/src/components/players/NativePlayer.tsx +0 -58
  187. package/src/components/players/VideoJsPlayer.tsx +0 -56
@@ -0,0 +1,82 @@
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { cn } from '@livepeer-frameworks/player-core';
3
+ import { Button } from '../ui/button.js';
4
+
5
+ var ThumbnailOverlay = function ThumbnailOverlay(_ref) {
6
+ var thumbnailUrl = _ref.thumbnailUrl,
7
+ onPlay = _ref.onPlay,
8
+ message = _ref.message,
9
+ _ref$showUnmuteMessag = _ref.showUnmuteMessage,
10
+ showUnmuteMessage = _ref$showUnmuteMessag === void 0 ? false : _ref$showUnmuteMessag,
11
+ style = _ref.style,
12
+ className = _ref.className;
13
+ var handleClick = function handleClick(e) {
14
+ e.stopPropagation();
15
+ onPlay === null || onPlay === void 0 || onPlay();
16
+ };
17
+ return jsxs("div", {
18
+ role: "button",
19
+ tabIndex: 0,
20
+ onClick: handleClick,
21
+ onKeyDown: function onKeyDown(event) {
22
+ if (event.key === "Enter" || event.key === " ") {
23
+ event.preventDefault();
24
+ handleClick(event);
25
+ }
26
+ },
27
+ style: style,
28
+ className: cn("fw-player-thumbnail relative flex h-full min-h-[280px] w-full cursor-pointer items-center justify-center overflow-hidden rounded-xl bg-slate-950 text-foreground outline-none transition focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background", className),
29
+ children: [thumbnailUrl && jsx("div", {
30
+ className: "absolute inset-0 bg-cover bg-center",
31
+ style: {
32
+ backgroundImage: "url(".concat(thumbnailUrl, ")")
33
+ }
34
+ }), jsx("div", {
35
+ className: cn("absolute inset-0 bg-slate-950/70", !thumbnailUrl && "bg-gradient-to-br from-slate-900 via-slate-950 to-slate-900")
36
+ }), jsx("div", {
37
+ className: "relative z-10 flex max-w-[320px] flex-col items-center gap-4 px-6 text-center text-sm sm:gap-6",
38
+ children: showUnmuteMessage ? jsxs("div", {
39
+ className: "w-full rounded-lg border border-white/15 bg-black/80 p-4 text-sm text-white shadow-lg backdrop-blur",
40
+ children: [jsxs("div", {
41
+ className: "mb-1 flex items-center justify-center gap-2 text-base font-semibold text-primary",
42
+ children: [jsx("span", {
43
+ "aria-hidden": "true",
44
+ children: "\uD83D\uDD07"
45
+ }), " Click to unmute"]
46
+ }), jsx("p", {
47
+ className: "text-xs text-white/80",
48
+ children: "Stream is playing muted \u2014 tap to enable sound."
49
+ })]
50
+ }) : jsxs(Fragment, {
51
+ children: [jsx(Button, {
52
+ type: "button",
53
+ size: "icon",
54
+ variant: "secondary",
55
+ className: "h-20 w-20 rounded-full bg-primary/90 text-primary-foreground shadow-lg shadow-primary/40 transition hover:bg-primary focus-visible:bg-primary",
56
+ "aria-label": "Play stream",
57
+ children: jsx("svg", {
58
+ viewBox: "0 0 24 24",
59
+ fill: "currentColor",
60
+ className: "ml-0.5 h-8 w-8",
61
+ "aria-hidden": "true",
62
+ children: jsx("path", {
63
+ d: "M8 5v14l11-7z"
64
+ })
65
+ })
66
+ }), jsxs("div", {
67
+ className: "w-full rounded-lg border border-white/10 bg-black/70 p-5 text-white shadow-inner backdrop-blur",
68
+ children: [jsx("p", {
69
+ className: "text-base font-semibold text-primary",
70
+ children: message !== null && message !== void 0 ? message : "Click to play"
71
+ }), jsx("p", {
72
+ className: "mt-1 text-xs text-white/70",
73
+ children: message ? "Start streaming instantly" : "Jump into the live feed"
74
+ })]
75
+ })]
76
+ })
77
+ })]
78
+ });
79
+ };
80
+
81
+ export { ThumbnailOverlay as default };
82
+ //# sourceMappingURL=ThumbnailOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThumbnailOverlay.js","sources":["../../../../src/components/ThumbnailOverlay.tsx"],"sourcesContent":["import React from \"react\";\nimport { cn } from \"@livepeer-frameworks/player-core\";\nimport { Button } from \"../ui/button\";\nimport type { ThumbnailOverlayProps } from \"../types\";\n\nconst ThumbnailOverlay: React.FC<ThumbnailOverlayProps> = ({\n thumbnailUrl,\n onPlay,\n message,\n showUnmuteMessage = false,\n style,\n className,\n}) => {\n const handleClick = (e: React.MouseEvent | React.KeyboardEvent) => {\n e.stopPropagation();\n onPlay?.();\n };\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleClick}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n handleClick(event);\n }\n }}\n style={style}\n className={cn(\n \"fw-player-thumbnail relative flex h-full min-h-[280px] w-full cursor-pointer items-center justify-center overflow-hidden rounded-xl bg-slate-950 text-foreground outline-none transition focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n className\n )}\n >\n {thumbnailUrl && (\n <div\n className=\"absolute inset-0 bg-cover bg-center\"\n style={{ backgroundImage: `url(${thumbnailUrl})` }}\n />\n )}\n\n <div\n className={cn(\n \"absolute inset-0 bg-slate-950/70\",\n !thumbnailUrl && \"bg-gradient-to-br from-slate-900 via-slate-950 to-slate-900\"\n )}\n />\n\n <div className=\"relative z-10 flex max-w-[320px] flex-col items-center gap-4 px-6 text-center text-sm sm:gap-6\">\n {showUnmuteMessage ? (\n <div className=\"w-full rounded-lg border border-white/15 bg-black/80 p-4 text-sm text-white shadow-lg backdrop-blur\">\n <div className=\"mb-1 flex items-center justify-center gap-2 text-base font-semibold text-primary\">\n <span aria-hidden=\"true\">🔇</span> Click to unmute\n </div>\n <p className=\"text-xs text-white/80\">Stream is playing muted — tap to enable sound.</p>\n </div>\n ) : (\n <>\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"secondary\"\n className=\"h-20 w-20 rounded-full bg-primary/90 text-primary-foreground shadow-lg shadow-primary/40 transition hover:bg-primary focus-visible:bg-primary\"\n aria-label=\"Play stream\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n className=\"ml-0.5 h-8 w-8\"\n aria-hidden=\"true\"\n >\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </Button>\n <div className=\"w-full rounded-lg border border-white/10 bg-black/70 p-5 text-white shadow-inner backdrop-blur\">\n <p className=\"text-base font-semibold text-primary\">{message ?? \"Click to play\"}</p>\n <p className=\"mt-1 text-xs text-white/70\">\n {message ? \"Start streaming instantly\" : \"Jump into the live feed\"}\n </p>\n </div>\n </>\n )}\n </div>\n </div>\n );\n};\n\nexport default ThumbnailOverlay;\n"],"names":["ThumbnailOverlay","_ref","thumbnailUrl","onPlay","message","_ref$showUnmuteMessag","showUnmuteMessage","style","className","handleClick","e","stopPropagation","_jsxs","role","tabIndex","onClick","onKeyDown","event","key","preventDefault","cn","_jsx","backgroundImage","concat","children","Button","type","size","variant","viewBox","fill","d"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { cn } from '@livepeer-frameworks/player-core';
3
+
4
+ /**
5
+ * Title/description overlay that appears at the top of the player.
6
+ * Visible on hover or when paused - controlled by parent via isVisible prop.
7
+ */
8
+ var TitleOverlay = function TitleOverlay(_ref) {
9
+ var title = _ref.title,
10
+ description = _ref.description,
11
+ isVisible = _ref.isVisible,
12
+ className = _ref.className;
13
+ // Don't render if no content
14
+ if (!title && !description) return null;
15
+ return jsxs("div", {
16
+ className: cn("fw-title-overlay absolute inset-x-0 top-0 z-20 pointer-events-none", "bg-gradient-to-b from-black/70 via-black/40 to-transparent", "px-4 py-3 transition-opacity duration-300", isVisible ? "opacity-100" : "opacity-0", className),
17
+ children: [title && jsx("h2", {
18
+ className: "text-white text-sm font-medium truncate max-w-[80%]",
19
+ children: title
20
+ }), description && jsx("p", {
21
+ className: "text-white/70 text-xs mt-0.5 line-clamp-2 max-w-[70%]",
22
+ children: description
23
+ })]
24
+ });
25
+ };
26
+
27
+ export { TitleOverlay as default };
28
+ //# sourceMappingURL=TitleOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TitleOverlay.js","sources":["../../../../src/components/TitleOverlay.tsx"],"sourcesContent":["import React from \"react\";\nimport { cn } from \"@livepeer-frameworks/player-core\";\n\ninterface TitleOverlayProps {\n title?: string | null;\n description?: string | null;\n isVisible: boolean;\n className?: string;\n}\n\n/**\n * Title/description overlay that appears at the top of the player.\n * Visible on hover or when paused - controlled by parent via isVisible prop.\n */\nconst TitleOverlay: React.FC<TitleOverlayProps> = ({\n title,\n description,\n isVisible,\n className,\n}) => {\n // Don't render if no content\n if (!title && !description) return null;\n\n return (\n <div\n className={cn(\n \"fw-title-overlay absolute inset-x-0 top-0 z-20 pointer-events-none\",\n \"bg-gradient-to-b from-black/70 via-black/40 to-transparent\",\n \"px-4 py-3 transition-opacity duration-300\",\n isVisible ? \"opacity-100\" : \"opacity-0\",\n className\n )}\n >\n {title && <h2 className=\"text-white text-sm font-medium truncate max-w-[80%]\">{title}</h2>}\n {description && (\n <p className=\"text-white/70 text-xs mt-0.5 line-clamp-2 max-w-[70%]\">{description}</p>\n )}\n </div>\n );\n};\n\nexport default TitleOverlay;\n"],"names":["TitleOverlay","_ref","title","description","isVisible","className","_jsxs","cn","_jsx","children"],"mappings":";;;AAUA;;;AAGG;AACH,IAAMA,YAAY,GAAgC,SAA5CA,YAAYA,CAAAC,IAAA,EAKb;AAAA,EAAA,IAJHC,KAAK,GAAAD,IAAA,CAALC,KAAK;IACLC,WAAW,GAAAF,IAAA,CAAXE,WAAW;IACXC,SAAS,GAAAH,IAAA,CAATG,SAAS;IACTC,SAAS,GAAAJ,IAAA,CAATI,SAAS;AAET;AACA,EAAA,IAAI,CAACH,KAAK,IAAI,CAACC,WAAW,EAAE,OAAO,IAAI;EAEvC,OACEG;AACED,IAAAA,SAAS,EAAEE,EAAE,CACX,oEAAoE,EACpE,4DAA4D,EAC5D,2CAA2C,EAC3CH,SAAS,GAAG,aAAa,GAAG,WAAW,EACvCC,SAAS,CACV;eAEAH,KAAK,IAAIM;AAAIH,MAAAA,SAAS,EAAC,qDAAqD;AAAAI,MAAAA,QAAA,EAAEP;AAAK,KAAA,CAAM,EACzFC,WAAW,IACVK,GAAA,CAAA,GAAA,EAAA;AAAGH,MAAAA,SAAS,EAAC,uDAAuD;AAAAI,MAAAA,QAAA,EAAEN;AAAW,KAAA,CAClF;AAAA,GAAA,CACG;AAEV;;;;"}
@@ -0,0 +1,41 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { createContext, useContext } from 'react';
3
+ import { usePlayerController } from '../hooks/usePlayerController.js';
4
+
5
+ // Context holds the full hook return value
6
+ var PlayerContext = /*#__PURE__*/createContext(null);
7
+ /**
8
+ * Provider component that wraps Player and its controls.
9
+ * Calls usePlayerController internally and shares state via context.
10
+ */
11
+ function PlayerProvider(_ref) {
12
+ var children = _ref.children,
13
+ config = _ref.config;
14
+ var playerController = usePlayerController(config);
15
+ return jsx(PlayerContext.Provider, {
16
+ value: playerController,
17
+ children: children
18
+ });
19
+ }
20
+ /**
21
+ * Hook to access player context.
22
+ * Must be used within a PlayerProvider.
23
+ */
24
+ function usePlayerContext() {
25
+ var context = useContext(PlayerContext);
26
+ if (!context) {
27
+ throw new Error("usePlayerContext must be used within a PlayerProvider");
28
+ }
29
+ return context;
30
+ }
31
+ /**
32
+ * Hook to optionally access player context.
33
+ * Returns null if not within a PlayerProvider (no error thrown).
34
+ * Use this when component may or may not be within a PlayerProvider.
35
+ */
36
+ function usePlayerContextOptional() {
37
+ return useContext(PlayerContext);
38
+ }
39
+
40
+ export { PlayerContext, PlayerProvider, usePlayerContext, usePlayerContextOptional };
41
+ //# sourceMappingURL=PlayerContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlayerContext.js","sources":["../../../../src/context/PlayerContext.tsx"],"sourcesContent":["/**\n * PlayerContext\n *\n * React context for sharing PlayerController state across components.\n * Follows the \"context wraps hook\" pattern (same as npm_studio).\n *\n * Usage:\n * ```tsx\n * <PlayerProvider config={{ contentId: 'stream-1', contentType: 'live' }}>\n * <PlayerControls />\n * </PlayerProvider>\n * ```\n */\n\nimport React, { createContext, useContext, type ReactNode } from \"react\";\nimport {\n usePlayerController,\n type UsePlayerControllerConfig,\n type UsePlayerControllerReturn,\n} from \"../hooks/usePlayerController\";\n\n// Context holds the full hook return value\nconst PlayerContext = createContext<UsePlayerControllerReturn | null>(null);\n\nexport interface PlayerProviderProps {\n children: ReactNode;\n /** Configuration for the player controller */\n config: UsePlayerControllerConfig;\n}\n\n/**\n * Provider component that wraps Player and its controls.\n * Calls usePlayerController internally and shares state via context.\n */\nexport function PlayerProvider({ children, config }: PlayerProviderProps) {\n const playerController = usePlayerController(config);\n\n return <PlayerContext.Provider value={playerController}>{children}</PlayerContext.Provider>;\n}\n\n/**\n * Hook to access player context.\n * Must be used within a PlayerProvider.\n */\nexport function usePlayerContext(): UsePlayerControllerReturn {\n const context = useContext(PlayerContext);\n if (!context) {\n throw new Error(\"usePlayerContext must be used within a PlayerProvider\");\n }\n return context;\n}\n\n/**\n * Hook to optionally access player context.\n * Returns null if not within a PlayerProvider (no error thrown).\n * Use this when component may or may not be within a PlayerProvider.\n */\nexport function usePlayerContextOptional(): UsePlayerControllerReturn | null {\n return useContext(PlayerContext);\n}\n\n// Export context for advanced use cases\nexport { PlayerContext };\n\n// Type exports\nexport type { UsePlayerControllerReturn as PlayerContextValue };\nexport type { UsePlayerControllerConfig };\n"],"names":["PlayerContext","createContext","PlayerProvider","_ref","children","config","playerController","usePlayerController","_jsx","Provider","value","usePlayerContext","context","useContext","Error","usePlayerContextOptional"],"mappings":";;;;AAqBA;AACA,IAAMA,aAAa,gBAAGC,aAAa,CAAmC,IAAI;AAQ1E;;;AAGG;SACaC,cAAcA,CAAAC,IAAA,EAA0C;AAAA,EAAA,IAAvCC,QAAQ,GAAAD,IAAA,CAARC,QAAQ;IAAEC,MAAM,GAAAF,IAAA,CAANE,MAAM;AAC/C,EAAA,IAAMC,gBAAgB,GAAGC,mBAAmB,CAACF,MAAM,CAAC;AAEpD,EAAA,OAAOG,GAAA,CAACR,aAAa,CAACS,QAAQ,EAAA;AAACC,IAAAA,KAAK,EAAEJ,gBAAgB;AAAAF,IAAAA,QAAA,EAAGA;AAAQ,GAAA,CAA0B;AAC7F;AAEA;;;AAGG;SACaO,gBAAgBA,GAAA;AAC9B,EAAA,IAAMC,OAAO,GAAGC,UAAU,CAACb,aAAa,CAAC;EACzC,IAAI,CAACY,OAAO,EAAE;AACZ,IAAA,MAAM,IAAIE,KAAK,CAAC,uDAAuD,CAAC;AAC1E,EAAA;AACA,EAAA,OAAOF,OAAO;AAChB;AAEA;;;;AAIG;SACaG,wBAAwBA,GAAA;EACtC,OAAOF,UAAU,CAACb,aAAa,CAAC;AAClC;;;;"}
@@ -0,0 +1,163 @@
1
+ import { slicedToArray as _slicedToArray } from '../_virtual/_rollupPluginBabelHelpers.js';
2
+ import { useState, useRef, useEffect, useCallback } from 'react';
3
+ import { MetaTrackManager } from '@livepeer-frameworks/player-core';
4
+
5
+ /**
6
+ * Hook for subscribing to real-time metadata from MistServer
7
+ *
8
+ * Uses native MistServer WebSocket protocol for low-latency metadata delivery:
9
+ * - Subtitles/captions
10
+ * - Live scores
11
+ * - Timed events
12
+ * - Chapter markers
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * const { isConnected, subscribe } = useMetaTrack({
17
+ * mistBaseUrl: 'https://mist.example.com',
18
+ * streamName: 'pk_...', // playbackId (view key)
19
+ * enabled: true,
20
+ * });
21
+ *
22
+ * useEffect(() => {
23
+ * if (!isConnected) return;
24
+ *
25
+ * const unsubscribe = subscribe('1', (event) => {
26
+ * if (event.type === 'subtitle') {
27
+ * setSubtitle(event.data as SubtitleCue);
28
+ * }
29
+ * });
30
+ *
31
+ * return unsubscribe;
32
+ * }, [isConnected, subscribe]);
33
+ * ```
34
+ */
35
+ function useMetaTrack(options) {
36
+ var mistBaseUrl = options.mistBaseUrl,
37
+ streamName = options.streamName,
38
+ initialSubscriptions = options.subscriptions,
39
+ _options$enabled = options.enabled,
40
+ enabled = _options$enabled === void 0 ? true : _options$enabled;
41
+ var _useState = useState(false),
42
+ _useState2 = _slicedToArray(_useState, 2),
43
+ isConnected = _useState2[0],
44
+ setIsConnected = _useState2[1];
45
+ var _useState3 = useState("disconnected"),
46
+ _useState4 = _slicedToArray(_useState3, 2),
47
+ connectionState = _useState4[0],
48
+ setConnectionState = _useState4[1];
49
+ var _useState5 = useState([]),
50
+ _useState6 = _slicedToArray(_useState5, 2),
51
+ subscribedTracks = _useState6[0],
52
+ setSubscribedTracks = _useState6[1];
53
+ var managerRef = useRef(null);
54
+ // Create manager instance
55
+ useEffect(function () {
56
+ if (!enabled || !mistBaseUrl || !streamName) {
57
+ if (managerRef.current) {
58
+ managerRef.current.disconnect();
59
+ managerRef.current = null;
60
+ }
61
+ setIsConnected(false);
62
+ setConnectionState("disconnected");
63
+ return;
64
+ }
65
+ managerRef.current = new MetaTrackManager({
66
+ mistBaseUrl: mistBaseUrl,
67
+ streamName: streamName,
68
+ subscriptions: initialSubscriptions,
69
+ debug: false
70
+ });
71
+ // Start polling connection state
72
+ var pollState = function pollState() {
73
+ if (managerRef.current) {
74
+ var state = managerRef.current.getState();
75
+ setConnectionState(state);
76
+ setIsConnected(state === "connected");
77
+ setSubscribedTracks(managerRef.current.getSubscribedTracks());
78
+ }
79
+ };
80
+ var pollInterval = setInterval(pollState, 500);
81
+ // Connect
82
+ managerRef.current.connect();
83
+ pollState();
84
+ return function () {
85
+ clearInterval(pollInterval);
86
+ if (managerRef.current) {
87
+ managerRef.current.disconnect();
88
+ managerRef.current = null;
89
+ }
90
+ setIsConnected(false);
91
+ setConnectionState("disconnected");
92
+ };
93
+ }, [enabled, mistBaseUrl, streamName, initialSubscriptions]);
94
+ /**
95
+ * Subscribe to a meta track
96
+ */
97
+ var subscribe = useCallback(function (trackId, callback) {
98
+ if (!managerRef.current) {
99
+ return function () {};
100
+ }
101
+ var unsubscribe = managerRef.current.subscribe(trackId, callback);
102
+ setSubscribedTracks(managerRef.current.getSubscribedTracks());
103
+ return function () {
104
+ unsubscribe();
105
+ if (managerRef.current) {
106
+ setSubscribedTracks(managerRef.current.getSubscribedTracks());
107
+ }
108
+ };
109
+ }, []);
110
+ /**
111
+ * Unsubscribe from a meta track
112
+ */
113
+ var unsubscribe = useCallback(function (trackId, callback) {
114
+ if (managerRef.current) {
115
+ managerRef.current.unsubscribe(trackId, callback);
116
+ setSubscribedTracks(managerRef.current.getSubscribedTracks());
117
+ }
118
+ }, []);
119
+ /**
120
+ * Manually connect
121
+ */
122
+ var connect = useCallback(function () {
123
+ var _managerRef$current;
124
+ (_managerRef$current = managerRef.current) === null || _managerRef$current === void 0 || _managerRef$current.connect();
125
+ }, []);
126
+ /**
127
+ * Manually disconnect
128
+ */
129
+ var disconnect = useCallback(function () {
130
+ var _managerRef$current2;
131
+ (_managerRef$current2 = managerRef.current) === null || _managerRef$current2 === void 0 || _managerRef$current2.disconnect();
132
+ }, []);
133
+ /**
134
+ * Update playback time for timed event dispatch
135
+ * Call this on video timeupdate events to keep subtitle/chapter timing in sync
136
+ */
137
+ var setPlaybackTime = useCallback(function (timeInSeconds) {
138
+ var _managerRef$current3;
139
+ (_managerRef$current3 = managerRef.current) === null || _managerRef$current3 === void 0 || _managerRef$current3.setPlaybackTime(timeInSeconds);
140
+ }, []);
141
+ /**
142
+ * Handle seek event - clears buffered events and resets state
143
+ * Call this on video seeking/seeked events
144
+ */
145
+ var onSeek = useCallback(function (newTimeInSeconds) {
146
+ var _managerRef$current4;
147
+ (_managerRef$current4 = managerRef.current) === null || _managerRef$current4 === void 0 || _managerRef$current4.onSeek(newTimeInSeconds);
148
+ }, []);
149
+ return {
150
+ isConnected: isConnected,
151
+ connectionState: connectionState,
152
+ subscribedTracks: subscribedTracks,
153
+ subscribe: subscribe,
154
+ unsubscribe: unsubscribe,
155
+ connect: connect,
156
+ disconnect: disconnect,
157
+ setPlaybackTime: setPlaybackTime,
158
+ onSeek: onSeek
159
+ };
160
+ }
161
+
162
+ export { useMetaTrack };
163
+ //# sourceMappingURL=useMetaTrack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMetaTrack.js","sources":["../../../../src/hooks/useMetaTrack.ts"],"sourcesContent":["import { useEffect, useState, useRef, useCallback } from \"react\";\nimport { MetaTrackManager, type MetaTrackEvent } from \"@livepeer-frameworks/player-core\";\nimport type { UseMetaTrackOptions } from \"../types\";\n\nexport interface UseMetaTrackReturn {\n /** Whether connected to MistServer WebSocket */\n isConnected: boolean;\n /** Connection state */\n connectionState: \"disconnected\" | \"connecting\" | \"connected\" | \"reconnecting\";\n /** List of subscribed track IDs */\n subscribedTracks: string[];\n /** Subscribe to a meta track */\n subscribe: (trackId: string, callback: (event: MetaTrackEvent) => void) => () => void;\n /** Unsubscribe from a meta track */\n unsubscribe: (trackId: string, callback: (event: MetaTrackEvent) => void) => void;\n /** Manually connect */\n connect: () => void;\n /** Manually disconnect */\n disconnect: () => void;\n /** Update playback time for timed event dispatch (call on video timeupdate) */\n setPlaybackTime: (timeInSeconds: number) => void;\n /** Handle seek event (call on video seeking/seeked) */\n onSeek: (newTimeInSeconds: number) => void;\n}\n\n/**\n * Hook for subscribing to real-time metadata from MistServer\n *\n * Uses native MistServer WebSocket protocol for low-latency metadata delivery:\n * - Subtitles/captions\n * - Live scores\n * - Timed events\n * - Chapter markers\n *\n * @example\n * ```tsx\n * const { isConnected, subscribe } = useMetaTrack({\n * mistBaseUrl: 'https://mist.example.com',\n * streamName: 'pk_...', // playbackId (view key)\n * enabled: true,\n * });\n *\n * useEffect(() => {\n * if (!isConnected) return;\n *\n * const unsubscribe = subscribe('1', (event) => {\n * if (event.type === 'subtitle') {\n * setSubtitle(event.data as SubtitleCue);\n * }\n * });\n *\n * return unsubscribe;\n * }, [isConnected, subscribe]);\n * ```\n */\nexport function useMetaTrack(options: UseMetaTrackOptions): UseMetaTrackReturn {\n const { mistBaseUrl, streamName, subscriptions: initialSubscriptions, enabled = true } = options;\n\n const [isConnected, setIsConnected] = useState(false);\n const [connectionState, setConnectionState] = useState<\n \"disconnected\" | \"connecting\" | \"connected\" | \"reconnecting\"\n >(\"disconnected\");\n const [subscribedTracks, setSubscribedTracks] = useState<string[]>([]);\n const managerRef = useRef<MetaTrackManager | null>(null);\n\n // Create manager instance\n useEffect(() => {\n if (!enabled || !mistBaseUrl || !streamName) {\n if (managerRef.current) {\n managerRef.current.disconnect();\n managerRef.current = null;\n }\n setIsConnected(false);\n setConnectionState(\"disconnected\");\n return;\n }\n\n managerRef.current = new MetaTrackManager({\n mistBaseUrl,\n streamName,\n subscriptions: initialSubscriptions,\n debug: false,\n });\n\n // Start polling connection state\n const pollState = () => {\n if (managerRef.current) {\n const state = managerRef.current.getState();\n setConnectionState(state);\n setIsConnected(state === \"connected\");\n setSubscribedTracks(managerRef.current.getSubscribedTracks());\n }\n };\n\n const pollInterval = setInterval(pollState, 500);\n\n // Connect\n managerRef.current.connect();\n pollState();\n\n return () => {\n clearInterval(pollInterval);\n if (managerRef.current) {\n managerRef.current.disconnect();\n managerRef.current = null;\n }\n setIsConnected(false);\n setConnectionState(\"disconnected\");\n };\n }, [enabled, mistBaseUrl, streamName, initialSubscriptions]);\n\n /**\n * Subscribe to a meta track\n */\n const subscribe = useCallback(\n (trackId: string, callback: (event: MetaTrackEvent) => void): (() => void) => {\n if (!managerRef.current) {\n return () => {};\n }\n\n const unsubscribe = managerRef.current.subscribe(trackId, callback);\n setSubscribedTracks(managerRef.current.getSubscribedTracks());\n\n return () => {\n unsubscribe();\n if (managerRef.current) {\n setSubscribedTracks(managerRef.current.getSubscribedTracks());\n }\n };\n },\n []\n );\n\n /**\n * Unsubscribe from a meta track\n */\n const unsubscribe = useCallback((trackId: string, callback: (event: MetaTrackEvent) => void) => {\n if (managerRef.current) {\n managerRef.current.unsubscribe(trackId, callback);\n setSubscribedTracks(managerRef.current.getSubscribedTracks());\n }\n }, []);\n\n /**\n * Manually connect\n */\n const connect = useCallback(() => {\n managerRef.current?.connect();\n }, []);\n\n /**\n * Manually disconnect\n */\n const disconnect = useCallback(() => {\n managerRef.current?.disconnect();\n }, []);\n\n /**\n * Update playback time for timed event dispatch\n * Call this on video timeupdate events to keep subtitle/chapter timing in sync\n */\n const setPlaybackTime = useCallback((timeInSeconds: number) => {\n managerRef.current?.setPlaybackTime(timeInSeconds);\n }, []);\n\n /**\n * Handle seek event - clears buffered events and resets state\n * Call this on video seeking/seeked events\n */\n const onSeek = useCallback((newTimeInSeconds: number) => {\n managerRef.current?.onSeek(newTimeInSeconds);\n }, []);\n\n return {\n isConnected,\n connectionState,\n subscribedTracks,\n subscribe,\n unsubscribe,\n connect,\n disconnect,\n setPlaybackTime,\n onSeek,\n };\n}\n\nexport default useMetaTrack;\n"],"names":["useMetaTrack","options","mistBaseUrl","streamName","initialSubscriptions","subscriptions","_options$enabled","enabled","_useState","useState","_useState2","_slicedToArray","isConnected","setIsConnected","_useState3","_useState4","connectionState","setConnectionState","_useState5","_useState6","subscribedTracks","setSubscribedTracks","managerRef","useRef","useEffect","current","disconnect","MetaTrackManager","debug","pollState","state","getState","getSubscribedTracks","pollInterval","setInterval","connect","clearInterval","subscribe","useCallback","trackId","callback","unsubscribe","_managerRef$current","_managerRef$current2","setPlaybackTime","timeInSeconds","_managerRef$current3","onSeek","newTimeInSeconds","_managerRef$current4"],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import { slicedToArray as _slicedToArray } from '../_virtual/_rollupPluginBabelHelpers.js';
2
+ import { useState, useRef, useEffect, useCallback } from 'react';
3
+ import { QualityMonitor } from '@livepeer-frameworks/player-core';
4
+
5
+ /**
6
+ * Hook to monitor video playback quality
7
+ *
8
+ * Tracks:
9
+ * - Buffer health (seconds ahead)
10
+ * - Stall count
11
+ * - Frame drop rate
12
+ * - Estimated bitrate
13
+ * - Latency (live streams)
14
+ * - Composite quality score (0-100)
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * const { quality, isMonitoring } = usePlaybackQuality({
19
+ * videoElement,
20
+ * enabled: true,
21
+ * thresholds: { minScore: 60 },
22
+ * onQualityDegraded: (q) => console.log('Quality dropped:', q.score),
23
+ * });
24
+ *
25
+ * return <div>Quality: {quality?.score ?? '--'}</div>;
26
+ * ```
27
+ */
28
+ function usePlaybackQuality(options) {
29
+ var videoElement = options.videoElement,
30
+ _options$enabled = options.enabled,
31
+ enabled = _options$enabled === void 0 ? true : _options$enabled,
32
+ _options$sampleInterv = options.sampleInterval,
33
+ sampleInterval = _options$sampleInterv === void 0 ? 500 : _options$sampleInterv,
34
+ thresholds = options.thresholds,
35
+ onQualityDegraded = options.onQualityDegraded;
36
+ var _useState = useState(null),
37
+ _useState2 = _slicedToArray(_useState, 2),
38
+ quality = _useState2[0],
39
+ setQuality = _useState2[1];
40
+ var _useState3 = useState(false),
41
+ _useState4 = _slicedToArray(_useState3, 2),
42
+ isMonitoring = _useState4[0],
43
+ setIsMonitoring = _useState4[1];
44
+ var monitorRef = useRef(null);
45
+ // Create/update monitor instance
46
+ useEffect(function () {
47
+ monitorRef.current = new QualityMonitor({
48
+ sampleInterval: sampleInterval,
49
+ thresholds: thresholds,
50
+ onQualityDegraded: onQualityDegraded,
51
+ onSample: setQuality
52
+ });
53
+ return function () {
54
+ var _monitorRef$current;
55
+ (_monitorRef$current = monitorRef.current) === null || _monitorRef$current === void 0 || _monitorRef$current.stop();
56
+ monitorRef.current = null;
57
+ };
58
+ }, [sampleInterval, thresholds, onQualityDegraded]);
59
+ // Start/stop monitoring based on videoElement and enabled state
60
+ useEffect(function () {
61
+ if (!enabled || !videoElement || !monitorRef.current) {
62
+ var _monitorRef$current2;
63
+ (_monitorRef$current2 = monitorRef.current) === null || _monitorRef$current2 === void 0 || _monitorRef$current2.stop();
64
+ setIsMonitoring(false);
65
+ return;
66
+ }
67
+ monitorRef.current.start(videoElement);
68
+ setIsMonitoring(true);
69
+ return function () {
70
+ var _monitorRef$current3;
71
+ (_monitorRef$current3 = monitorRef.current) === null || _monitorRef$current3 === void 0 || _monitorRef$current3.stop();
72
+ setIsMonitoring(false);
73
+ };
74
+ }, [videoElement, enabled]);
75
+ /**
76
+ * Get current quality snapshot
77
+ */
78
+ var getCurrentQuality = useCallback(function () {
79
+ var _monitorRef$current$g, _monitorRef$current4;
80
+ return (_monitorRef$current$g = (_monitorRef$current4 = monitorRef.current) === null || _monitorRef$current4 === void 0 ? void 0 : _monitorRef$current4.getCurrentQuality()) !== null && _monitorRef$current$g !== void 0 ? _monitorRef$current$g : null;
81
+ }, []);
82
+ /**
83
+ * Get rolling average quality
84
+ */
85
+ var getAverageQuality = useCallback(function () {
86
+ var _monitorRef$current$g2, _monitorRef$current5;
87
+ return (_monitorRef$current$g2 = (_monitorRef$current5 = monitorRef.current) === null || _monitorRef$current5 === void 0 ? void 0 : _monitorRef$current5.getAverageQuality()) !== null && _monitorRef$current$g2 !== void 0 ? _monitorRef$current$g2 : null;
88
+ }, []);
89
+ /**
90
+ * Get quality history
91
+ */
92
+ var getHistory = useCallback(function () {
93
+ var _monitorRef$current$g3, _monitorRef$current6;
94
+ return (_monitorRef$current$g3 = (_monitorRef$current6 = monitorRef.current) === null || _monitorRef$current6 === void 0 ? void 0 : _monitorRef$current6.getHistory()) !== null && _monitorRef$current$g3 !== void 0 ? _monitorRef$current$g3 : [];
95
+ }, []);
96
+ /**
97
+ * Reset stall counters
98
+ */
99
+ var resetStallCounters = useCallback(function () {
100
+ var _monitorRef$current7;
101
+ (_monitorRef$current7 = monitorRef.current) === null || _monitorRef$current7 === void 0 || _monitorRef$current7.resetStallCounters();
102
+ }, []);
103
+ /**
104
+ * Get total stall time
105
+ */
106
+ var getTotalStallMs = useCallback(function () {
107
+ var _monitorRef$current$g4, _monitorRef$current8;
108
+ return (_monitorRef$current$g4 = (_monitorRef$current8 = monitorRef.current) === null || _monitorRef$current8 === void 0 ? void 0 : _monitorRef$current8.getTotalStallMs()) !== null && _monitorRef$current$g4 !== void 0 ? _monitorRef$current$g4 : 0;
109
+ }, []);
110
+ return {
111
+ /** Current quality metrics */
112
+ quality: quality,
113
+ /** Whether monitoring is active */
114
+ isMonitoring: isMonitoring,
115
+ /** Get current quality snapshot */
116
+ getCurrentQuality: getCurrentQuality,
117
+ /** Get rolling average quality */
118
+ getAverageQuality: getAverageQuality,
119
+ /** Get quality history */
120
+ getHistory: getHistory,
121
+ /** Reset stall counters */
122
+ resetStallCounters: resetStallCounters,
123
+ /** Get total stall time in ms */
124
+ getTotalStallMs: getTotalStallMs
125
+ };
126
+ }
127
+
128
+ export { usePlaybackQuality };
129
+ //# sourceMappingURL=usePlaybackQuality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePlaybackQuality.js","sources":["../../../../src/hooks/usePlaybackQuality.ts"],"sourcesContent":["import { useEffect, useState, useRef, useCallback } from \"react\";\nimport { QualityMonitor, type PlaybackQuality } from \"@livepeer-frameworks/player-core\";\nimport type { UsePlaybackQualityOptions } from \"../types\";\n\n/**\n * Hook to monitor video playback quality\n *\n * Tracks:\n * - Buffer health (seconds ahead)\n * - Stall count\n * - Frame drop rate\n * - Estimated bitrate\n * - Latency (live streams)\n * - Composite quality score (0-100)\n *\n * @example\n * ```tsx\n * const { quality, isMonitoring } = usePlaybackQuality({\n * videoElement,\n * enabled: true,\n * thresholds: { minScore: 60 },\n * onQualityDegraded: (q) => console.log('Quality dropped:', q.score),\n * });\n *\n * return <div>Quality: {quality?.score ?? '--'}</div>;\n * ```\n */\nexport function usePlaybackQuality(options: UsePlaybackQualityOptions) {\n const {\n videoElement,\n enabled = true,\n sampleInterval = 500,\n thresholds,\n onQualityDegraded,\n } = options;\n\n const [quality, setQuality] = useState<PlaybackQuality | null>(null);\n const [isMonitoring, setIsMonitoring] = useState(false);\n const monitorRef = useRef<QualityMonitor | null>(null);\n\n // Create/update monitor instance\n useEffect(() => {\n monitorRef.current = new QualityMonitor({\n sampleInterval,\n thresholds,\n onQualityDegraded,\n onSample: setQuality,\n });\n\n return () => {\n monitorRef.current?.stop();\n monitorRef.current = null;\n };\n }, [sampleInterval, thresholds, onQualityDegraded]);\n\n // Start/stop monitoring based on videoElement and enabled state\n useEffect(() => {\n if (!enabled || !videoElement || !monitorRef.current) {\n monitorRef.current?.stop();\n setIsMonitoring(false);\n return;\n }\n\n monitorRef.current.start(videoElement);\n setIsMonitoring(true);\n\n return () => {\n monitorRef.current?.stop();\n setIsMonitoring(false);\n };\n }, [videoElement, enabled]);\n\n /**\n * Get current quality snapshot\n */\n const getCurrentQuality = useCallback((): PlaybackQuality | null => {\n return monitorRef.current?.getCurrentQuality() ?? null;\n }, []);\n\n /**\n * Get rolling average quality\n */\n const getAverageQuality = useCallback((): PlaybackQuality | null => {\n return monitorRef.current?.getAverageQuality() ?? null;\n }, []);\n\n /**\n * Get quality history\n */\n const getHistory = useCallback((): PlaybackQuality[] => {\n return monitorRef.current?.getHistory() ?? [];\n }, []);\n\n /**\n * Reset stall counters\n */\n const resetStallCounters = useCallback(() => {\n monitorRef.current?.resetStallCounters();\n }, []);\n\n /**\n * Get total stall time\n */\n const getTotalStallMs = useCallback((): number => {\n return monitorRef.current?.getTotalStallMs() ?? 0;\n }, []);\n\n return {\n /** Current quality metrics */\n quality,\n /** Whether monitoring is active */\n isMonitoring,\n /** Get current quality snapshot */\n getCurrentQuality,\n /** Get rolling average quality */\n getAverageQuality,\n /** Get quality history */\n getHistory,\n /** Reset stall counters */\n resetStallCounters,\n /** Get total stall time in ms */\n getTotalStallMs,\n };\n}\n\nexport default usePlaybackQuality;\n"],"names":["usePlaybackQuality","options","videoElement","_options$enabled","enabled","_options$sampleInterv","sampleInterval","thresholds","onQualityDegraded","_useState","useState","_useState2","_slicedToArray","quality","setQuality","_useState3","_useState4","isMonitoring","setIsMonitoring","monitorRef","useRef","useEffect","current","QualityMonitor","onSample","_monitorRef$current","stop","_monitorRef$current2","start","_monitorRef$current3","getCurrentQuality","useCallback","_monitorRef$current$g","_monitorRef$current4","getAverageQuality","_monitorRef$current$g2","_monitorRef$current5","getHistory","_monitorRef$current$g3","_monitorRef$current6","resetStallCounters","_monitorRef$current7","getTotalStallMs","_monitorRef$current$g4","_monitorRef$current8"],"mappings":";;;;AAIA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACG,SAAUA,kBAAkBA,CAACC,OAAkC,EAAA;AACnE,EAAA,IACEC,YAAY,GAKVD,OAAO,CALTC,YAAY;IAAAC,gBAAA,GAKVF,OAAO,CAJTG,OAAO;AAAPA,IAAAA,OAAO,GAAAD,gBAAA,KAAA,MAAA,GAAG,IAAI,GAAAA,gBAAA;IAAAE,qBAAA,GAIZJ,OAAO,CAHTK,cAAc;AAAdA,IAAAA,cAAc,GAAAD,qBAAA,KAAA,MAAA,GAAG,GAAG,GAAAA,qBAAA;IACpBE,UAAU,GAERN,OAAO,CAFTM,UAAU;IACVC,iBAAiB,GACfP,OAAO,CADTO,iBAAiB;AAGnB,EAAA,IAAAC,SAAA,GAA8BC,QAAQ,CAAyB,IAAI,CAAC;IAAAC,UAAA,GAAAC,cAAA,CAAAH,SAAA,EAAA,CAAA,CAAA;AAA7DI,IAAAA,OAAO,GAAAF,UAAA,CAAA,CAAA,CAAA;AAAEG,IAAAA,UAAU,GAAAH,UAAA,CAAA,CAAA,CAAA;AAC1B,EAAA,IAAAI,UAAA,GAAwCL,QAAQ,CAAC,KAAK,CAAC;IAAAM,UAAA,GAAAJ,cAAA,CAAAG,UAAA,EAAA,CAAA,CAAA;AAAhDE,IAAAA,YAAY,GAAAD,UAAA,CAAA,CAAA,CAAA;AAAEE,IAAAA,eAAe,GAAAF,UAAA,CAAA,CAAA,CAAA;AACpC,EAAA,IAAMG,UAAU,GAAGC,MAAM,CAAwB,IAAI,CAAC;AAEtD;AACAC,EAAAA,SAAS,CAAC,YAAK;AACbF,IAAAA,UAAU,CAACG,OAAO,GAAG,IAAIC,cAAc,CAAC;AACtCjB,MAAAA,cAAc,EAAdA,cAAc;AACdC,MAAAA,UAAU,EAAVA,UAAU;AACVC,MAAAA,iBAAiB,EAAjBA,iBAAiB;AACjBgB,MAAAA,QAAQ,EAAEV;AACX,KAAA,CAAC;AAEF,IAAA,OAAO,YAAK;AAAA,MAAA,IAAAW,mBAAA;AACV,MAAA,CAAAA,mBAAA,GAAAN,UAAU,CAACG,OAAO,MAAA,IAAA,IAAAG,mBAAA,KAAA,MAAA,IAAlBA,mBAAA,CAAoBC,IAAI,EAAE;MAC1BP,UAAU,CAACG,OAAO,GAAG,IAAI;IAC3B,CAAC;EACH,CAAC,EAAE,CAAChB,cAAc,EAAEC,UAAU,EAAEC,iBAAiB,CAAC,CAAC;AAEnD;AACAa,EAAAA,SAAS,CAAC,YAAK;IACb,IAAI,CAACjB,OAAO,IAAI,CAACF,YAAY,IAAI,CAACiB,UAAU,CAACG,OAAO,EAAE;AAAA,MAAA,IAAAK,oBAAA;AACpD,MAAA,CAAAA,oBAAA,GAAAR,UAAU,CAACG,OAAO,MAAA,IAAA,IAAAK,oBAAA,KAAA,MAAA,IAAlBA,oBAAA,CAAoBD,IAAI,EAAE;MAC1BR,eAAe,CAAC,KAAK,CAAC;AACtB,MAAA;AACF,IAAA;AAEAC,IAAAA,UAAU,CAACG,OAAO,CAACM,KAAK,CAAC1B,YAAY,CAAC;IACtCgB,eAAe,CAAC,IAAI,CAAC;AAErB,IAAA,OAAO,YAAK;AAAA,MAAA,IAAAW,oBAAA;AACV,MAAA,CAAAA,oBAAA,GAAAV,UAAU,CAACG,OAAO,MAAA,IAAA,IAAAO,oBAAA,KAAA,MAAA,IAAlBA,oBAAA,CAAoBH,IAAI,EAAE;MAC1BR,eAAe,CAAC,KAAK,CAAC;IACxB,CAAC;AACH,EAAA,CAAC,EAAE,CAAChB,YAAY,EAAEE,OAAO,CAAC,CAAC;AAE3B;;AAEG;AACH,EAAA,IAAM0B,iBAAiB,GAAGC,WAAW,CAAC,YAA6B;IAAA,IAAAC,qBAAA,EAAAC,oBAAA;IACjE,OAAA,CAAAD,qBAAA,IAAAC,oBAAA,GAAOd,UAAU,CAACG,OAAO,cAAAW,oBAAA,KAAA,MAAA,GAAA,MAAA,GAAlBA,oBAAA,CAAoBH,iBAAiB,EAAE,MAAA,IAAA,IAAAE,qBAAA,KAAA,MAAA,GAAAA,qBAAA,GAAI,IAAI;EACxD,CAAC,EAAE,EAAE,CAAC;AAEN;;AAEG;AACH,EAAA,IAAME,iBAAiB,GAAGH,WAAW,CAAC,YAA6B;IAAA,IAAAI,sBAAA,EAAAC,oBAAA;IACjE,OAAA,CAAAD,sBAAA,IAAAC,oBAAA,GAAOjB,UAAU,CAACG,OAAO,cAAAc,oBAAA,KAAA,MAAA,GAAA,MAAA,GAAlBA,oBAAA,CAAoBF,iBAAiB,EAAE,MAAA,IAAA,IAAAC,sBAAA,KAAA,MAAA,GAAAA,sBAAA,GAAI,IAAI;EACxD,CAAC,EAAE,EAAE,CAAC;AAEN;;AAEG;AACH,EAAA,IAAME,UAAU,GAAGN,WAAW,CAAC,YAAwB;IAAA,IAAAO,sBAAA,EAAAC,oBAAA;IACrD,OAAA,CAAAD,sBAAA,IAAAC,oBAAA,GAAOpB,UAAU,CAACG,OAAO,cAAAiB,oBAAA,KAAA,MAAA,GAAA,MAAA,GAAlBA,oBAAA,CAAoBF,UAAU,EAAE,MAAA,IAAA,IAAAC,sBAAA,KAAA,MAAA,GAAAA,sBAAA,GAAI,EAAE;EAC/C,CAAC,EAAE,EAAE,CAAC;AAEN;;AAEG;AACH,EAAA,IAAME,kBAAkB,GAAGT,WAAW,CAAC,YAAK;AAAA,IAAA,IAAAU,oBAAA;AAC1C,IAAA,CAAAA,oBAAA,GAAAtB,UAAU,CAACG,OAAO,MAAA,IAAA,IAAAmB,oBAAA,KAAA,MAAA,IAAlBA,oBAAA,CAAoBD,kBAAkB,EAAE;EAC1C,CAAC,EAAE,EAAE,CAAC;AAEN;;AAEG;AACH,EAAA,IAAME,eAAe,GAAGX,WAAW,CAAC,YAAa;IAAA,IAAAY,sBAAA,EAAAC,oBAAA;IAC/C,OAAA,CAAAD,sBAAA,IAAAC,oBAAA,GAAOzB,UAAU,CAACG,OAAO,cAAAsB,oBAAA,KAAA,MAAA,GAAA,MAAA,GAAlBA,oBAAA,CAAoBF,eAAe,EAAE,MAAA,IAAA,IAAAC,sBAAA,KAAA,MAAA,GAAAA,sBAAA,GAAI,CAAC;EACnD,CAAC,EAAE,EAAE,CAAC;EAEN,OAAO;AACL;AACA9B,IAAAA,OAAO,EAAPA,OAAO;AACP;AACAI,IAAAA,YAAY,EAAZA,YAAY;AACZ;AACAa,IAAAA,iBAAiB,EAAjBA,iBAAiB;AACjB;AACAI,IAAAA,iBAAiB,EAAjBA,iBAAiB;AACjB;AACAG,IAAAA,UAAU,EAAVA,UAAU;AACV;AACAG,IAAAA,kBAAkB,EAAlBA,kBAAkB;AAClB;AACAE,IAAAA,eAAe,EAAfA;GACD;AACH;;;;"}