@livepeer-frameworks/player-core 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 (294) hide show
  1. package/README.md +11 -9
  2. package/dist/cjs/core/ABRController.js +456 -0
  3. package/dist/cjs/core/ABRController.js.map +1 -0
  4. package/dist/cjs/core/CodecUtils.js +195 -0
  5. package/dist/cjs/core/CodecUtils.js.map +1 -0
  6. package/dist/cjs/core/ErrorClassifier.js +410 -0
  7. package/dist/cjs/core/ErrorClassifier.js.map +1 -0
  8. package/dist/cjs/core/EventEmitter.js +108 -0
  9. package/dist/cjs/core/EventEmitter.js.map +1 -0
  10. package/dist/cjs/core/GatewayClient.js +342 -0
  11. package/dist/cjs/core/GatewayClient.js.map +1 -0
  12. package/dist/cjs/core/InteractionController.js +606 -0
  13. package/dist/cjs/core/InteractionController.js.map +1 -0
  14. package/dist/cjs/core/LiveDurationProxy.js +186 -0
  15. package/dist/cjs/core/LiveDurationProxy.js.map +1 -0
  16. package/dist/cjs/core/MetaTrackManager.js +624 -0
  17. package/dist/cjs/core/MetaTrackManager.js.map +1 -0
  18. package/dist/cjs/core/MistReporter.js +449 -0
  19. package/dist/cjs/core/MistReporter.js.map +1 -0
  20. package/dist/cjs/core/MistSignaling.js +264 -0
  21. package/dist/cjs/core/MistSignaling.js.map +1 -0
  22. package/dist/cjs/core/PlayerController.js +2658 -0
  23. package/dist/cjs/core/PlayerController.js.map +1 -0
  24. package/dist/cjs/core/PlayerInterface.js +269 -0
  25. package/dist/cjs/core/PlayerInterface.js.map +1 -0
  26. package/dist/cjs/core/PlayerManager.js +806 -0
  27. package/dist/cjs/core/PlayerManager.js.map +1 -0
  28. package/dist/cjs/core/PlayerRegistry.js +270 -0
  29. package/dist/cjs/core/PlayerRegistry.js.map +1 -0
  30. package/dist/cjs/core/QualityMonitor.js +474 -0
  31. package/dist/cjs/core/QualityMonitor.js.map +1 -0
  32. package/dist/cjs/core/SeekingUtils.js +292 -0
  33. package/dist/cjs/core/SeekingUtils.js.map +1 -0
  34. package/dist/cjs/core/StreamStateClient.js +381 -0
  35. package/dist/cjs/core/StreamStateClient.js.map +1 -0
  36. package/dist/cjs/core/SubtitleManager.js +227 -0
  37. package/dist/cjs/core/SubtitleManager.js.map +1 -0
  38. package/dist/cjs/core/TelemetryReporter.js +258 -0
  39. package/dist/cjs/core/TelemetryReporter.js.map +1 -0
  40. package/dist/cjs/core/TimeFormat.js +176 -0
  41. package/dist/cjs/core/TimeFormat.js.map +1 -0
  42. package/dist/cjs/core/TimerManager.js +176 -0
  43. package/dist/cjs/core/TimerManager.js.map +1 -0
  44. package/dist/cjs/core/UrlUtils.js +160 -0
  45. package/dist/cjs/core/UrlUtils.js.map +1 -0
  46. package/dist/cjs/core/detector.js +293 -0
  47. package/dist/cjs/core/detector.js.map +1 -0
  48. package/dist/cjs/core/scorer.js +443 -0
  49. package/dist/cjs/core/scorer.js.map +1 -0
  50. package/dist/cjs/index.js +121 -20134
  51. package/dist/cjs/index.js.map +1 -1
  52. package/dist/cjs/lib/utils.js +11 -0
  53. package/dist/cjs/lib/utils.js.map +1 -0
  54. package/dist/cjs/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js +6 -0
  55. package/dist/cjs/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js.map +1 -0
  56. package/dist/cjs/node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.js +3042 -0
  57. package/dist/cjs/node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  58. package/dist/cjs/players/DashJsPlayer.js +638 -0
  59. package/dist/cjs/players/DashJsPlayer.js.map +1 -0
  60. package/dist/cjs/players/HlsJsPlayer.js +482 -0
  61. package/dist/cjs/players/HlsJsPlayer.js.map +1 -0
  62. package/dist/cjs/players/MewsWsPlayer/SourceBufferManager.js +522 -0
  63. package/dist/cjs/players/MewsWsPlayer/SourceBufferManager.js.map +1 -0
  64. package/dist/cjs/players/MewsWsPlayer/WebSocketManager.js +215 -0
  65. package/dist/cjs/players/MewsWsPlayer/WebSocketManager.js.map +1 -0
  66. package/dist/cjs/players/MewsWsPlayer/index.js +987 -0
  67. package/dist/cjs/players/MewsWsPlayer/index.js.map +1 -0
  68. package/dist/cjs/players/MistPlayer.js +185 -0
  69. package/dist/cjs/players/MistPlayer.js.map +1 -0
  70. package/dist/cjs/players/MistWebRTCPlayer/index.js +635 -0
  71. package/dist/cjs/players/MistWebRTCPlayer/index.js.map +1 -0
  72. package/dist/cjs/players/NativePlayer.js +762 -0
  73. package/dist/cjs/players/NativePlayer.js.map +1 -0
  74. package/dist/cjs/players/VideoJsPlayer.js +585 -0
  75. package/dist/cjs/players/VideoJsPlayer.js.map +1 -0
  76. package/dist/cjs/players/WebCodecsPlayer/JitterBuffer.js +236 -0
  77. package/dist/cjs/players/WebCodecsPlayer/JitterBuffer.js.map +1 -0
  78. package/dist/cjs/players/WebCodecsPlayer/LatencyProfiles.js +143 -0
  79. package/dist/cjs/players/WebCodecsPlayer/LatencyProfiles.js.map +1 -0
  80. package/dist/cjs/players/WebCodecsPlayer/RawChunkParser.js +96 -0
  81. package/dist/cjs/players/WebCodecsPlayer/RawChunkParser.js.map +1 -0
  82. package/dist/cjs/players/WebCodecsPlayer/SyncController.js +359 -0
  83. package/dist/cjs/players/WebCodecsPlayer/SyncController.js.map +1 -0
  84. package/dist/cjs/players/WebCodecsPlayer/WebSocketController.js +460 -0
  85. package/dist/cjs/players/WebCodecsPlayer/WebSocketController.js.map +1 -0
  86. package/dist/cjs/players/WebCodecsPlayer/index.js +1467 -0
  87. package/dist/cjs/players/WebCodecsPlayer/index.js.map +1 -0
  88. package/dist/cjs/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.js +320 -0
  89. package/dist/cjs/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.js.map +1 -0
  90. package/dist/cjs/styles/index.js +57 -0
  91. package/dist/cjs/styles/index.js.map +1 -0
  92. package/dist/cjs/vanilla/FrameWorksPlayer.js +269 -0
  93. package/dist/cjs/vanilla/FrameWorksPlayer.js.map +1 -0
  94. package/dist/cjs/vanilla.js +11 -0
  95. package/dist/cjs/vanilla.js.map +1 -0
  96. package/dist/esm/core/ABRController.js +454 -0
  97. package/dist/esm/core/ABRController.js.map +1 -0
  98. package/dist/esm/core/CodecUtils.js +193 -0
  99. package/dist/esm/core/CodecUtils.js.map +1 -0
  100. package/dist/esm/core/ErrorClassifier.js +408 -0
  101. package/dist/esm/core/ErrorClassifier.js.map +1 -0
  102. package/dist/esm/core/EventEmitter.js +106 -0
  103. package/dist/esm/core/EventEmitter.js.map +1 -0
  104. package/dist/esm/core/GatewayClient.js +340 -0
  105. package/dist/esm/core/GatewayClient.js.map +1 -0
  106. package/dist/esm/core/InteractionController.js +604 -0
  107. package/dist/esm/core/InteractionController.js.map +1 -0
  108. package/dist/esm/core/LiveDurationProxy.js +184 -0
  109. package/dist/esm/core/LiveDurationProxy.js.map +1 -0
  110. package/dist/esm/core/MetaTrackManager.js +622 -0
  111. package/dist/esm/core/MetaTrackManager.js.map +1 -0
  112. package/dist/esm/core/MistReporter.js +447 -0
  113. package/dist/esm/core/MistReporter.js.map +1 -0
  114. package/dist/esm/core/MistSignaling.js +262 -0
  115. package/dist/esm/core/MistSignaling.js.map +1 -0
  116. package/dist/esm/core/PlayerController.js +2651 -0
  117. package/dist/esm/core/PlayerController.js.map +1 -0
  118. package/dist/esm/core/PlayerInterface.js +267 -0
  119. package/dist/esm/core/PlayerInterface.js.map +1 -0
  120. package/dist/esm/core/PlayerManager.js +804 -0
  121. package/dist/esm/core/PlayerManager.js.map +1 -0
  122. package/dist/esm/core/PlayerRegistry.js +264 -0
  123. package/dist/esm/core/PlayerRegistry.js.map +1 -0
  124. package/dist/esm/core/QualityMonitor.js +471 -0
  125. package/dist/esm/core/QualityMonitor.js.map +1 -0
  126. package/dist/esm/core/SeekingUtils.js +280 -0
  127. package/dist/esm/core/SeekingUtils.js.map +1 -0
  128. package/dist/esm/core/StreamStateClient.js +379 -0
  129. package/dist/esm/core/StreamStateClient.js.map +1 -0
  130. package/dist/esm/core/SubtitleManager.js +225 -0
  131. package/dist/esm/core/SubtitleManager.js.map +1 -0
  132. package/dist/esm/core/TelemetryReporter.js +256 -0
  133. package/dist/esm/core/TelemetryReporter.js.map +1 -0
  134. package/dist/esm/core/TimeFormat.js +169 -0
  135. package/dist/esm/core/TimeFormat.js.map +1 -0
  136. package/dist/esm/core/TimerManager.js +174 -0
  137. package/dist/esm/core/TimerManager.js.map +1 -0
  138. package/dist/esm/core/UrlUtils.js +151 -0
  139. package/dist/esm/core/UrlUtils.js.map +1 -0
  140. package/dist/esm/core/detector.js +279 -0
  141. package/dist/esm/core/detector.js.map +1 -0
  142. package/dist/esm/core/scorer.js +422 -0
  143. package/dist/esm/core/scorer.js.map +1 -0
  144. package/dist/esm/index.js +26 -20043
  145. package/dist/esm/index.js.map +1 -1
  146. package/dist/esm/lib/utils.js +9 -0
  147. package/dist/esm/lib/utils.js.map +1 -0
  148. package/dist/esm/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js +4 -0
  149. package/dist/esm/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js.map +1 -0
  150. package/dist/esm/node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.js +3036 -0
  151. package/dist/esm/node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  152. package/dist/esm/players/DashJsPlayer.js +636 -0
  153. package/dist/esm/players/DashJsPlayer.js.map +1 -0
  154. package/dist/esm/players/HlsJsPlayer.js +480 -0
  155. package/dist/esm/players/HlsJsPlayer.js.map +1 -0
  156. package/dist/esm/players/MewsWsPlayer/SourceBufferManager.js +520 -0
  157. package/dist/esm/players/MewsWsPlayer/SourceBufferManager.js.map +1 -0
  158. package/dist/esm/players/MewsWsPlayer/WebSocketManager.js +213 -0
  159. package/dist/esm/players/MewsWsPlayer/WebSocketManager.js.map +1 -0
  160. package/dist/esm/players/MewsWsPlayer/index.js +985 -0
  161. package/dist/esm/players/MewsWsPlayer/index.js.map +1 -0
  162. package/dist/esm/players/MistPlayer.js +183 -0
  163. package/dist/esm/players/MistPlayer.js.map +1 -0
  164. package/dist/esm/players/MistWebRTCPlayer/index.js +633 -0
  165. package/dist/esm/players/MistWebRTCPlayer/index.js.map +1 -0
  166. package/dist/esm/players/NativePlayer.js +759 -0
  167. package/dist/esm/players/NativePlayer.js.map +1 -0
  168. package/dist/esm/players/VideoJsPlayer.js +583 -0
  169. package/dist/esm/players/VideoJsPlayer.js.map +1 -0
  170. package/dist/esm/players/WebCodecsPlayer/JitterBuffer.js +233 -0
  171. package/dist/esm/players/WebCodecsPlayer/JitterBuffer.js.map +1 -0
  172. package/dist/esm/players/WebCodecsPlayer/LatencyProfiles.js +134 -0
  173. package/dist/esm/players/WebCodecsPlayer/LatencyProfiles.js.map +1 -0
  174. package/dist/esm/players/WebCodecsPlayer/RawChunkParser.js +91 -0
  175. package/dist/esm/players/WebCodecsPlayer/RawChunkParser.js.map +1 -0
  176. package/dist/esm/players/WebCodecsPlayer/SyncController.js +357 -0
  177. package/dist/esm/players/WebCodecsPlayer/SyncController.js.map +1 -0
  178. package/dist/esm/players/WebCodecsPlayer/WebSocketController.js +458 -0
  179. package/dist/esm/players/WebCodecsPlayer/WebSocketController.js.map +1 -0
  180. package/dist/esm/players/WebCodecsPlayer/index.js +1458 -0
  181. package/dist/esm/players/WebCodecsPlayer/index.js.map +1 -0
  182. package/dist/esm/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.js +315 -0
  183. package/dist/esm/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.js.map +1 -0
  184. package/dist/esm/styles/index.js +54 -0
  185. package/dist/esm/styles/index.js.map +1 -0
  186. package/dist/esm/vanilla/FrameWorksPlayer.js +264 -0
  187. package/dist/esm/vanilla/FrameWorksPlayer.js.map +1 -0
  188. package/dist/esm/vanilla.js +2 -0
  189. package/dist/esm/vanilla.js.map +1 -0
  190. package/dist/player.css +185 -42
  191. package/dist/types/core/ABRController.d.ts +4 -4
  192. package/dist/types/core/CodecUtils.d.ts +1 -1
  193. package/dist/types/core/ErrorClassifier.d.ts +77 -0
  194. package/dist/types/core/GatewayClient.d.ts +4 -4
  195. package/dist/types/core/MetaTrackManager.d.ts +2 -2
  196. package/dist/types/core/MistReporter.d.ts +3 -3
  197. package/dist/types/core/MistSignaling.d.ts +12 -12
  198. package/dist/types/core/PlayerController.d.ts +19 -14
  199. package/dist/types/core/PlayerInterface.d.ts +100 -2
  200. package/dist/types/core/PlayerManager.d.ts +36 -9
  201. package/dist/types/core/PlayerRegistry.d.ts +11 -11
  202. package/dist/types/core/QualityMonitor.d.ts +2 -2
  203. package/dist/types/core/SeekingUtils.d.ts +2 -2
  204. package/dist/types/core/StreamStateClient.d.ts +2 -2
  205. package/dist/types/core/TelemetryReporter.d.ts +1 -1
  206. package/dist/types/core/TimerManager.d.ts +1 -1
  207. package/dist/types/core/detector.d.ts +1 -1
  208. package/dist/types/core/index.d.ts +44 -44
  209. package/dist/types/core/scorer.d.ts +1 -1
  210. package/dist/types/core/selector.d.ts +2 -2
  211. package/dist/types/index.d.ts +35 -34
  212. package/dist/types/players/DashJsPlayer.d.ts +3 -3
  213. package/dist/types/players/HlsJsPlayer.d.ts +3 -3
  214. package/dist/types/players/MewsWsPlayer/SourceBufferManager.d.ts +1 -1
  215. package/dist/types/players/MewsWsPlayer/WebSocketManager.d.ts +1 -1
  216. package/dist/types/players/MewsWsPlayer/index.d.ts +2 -2
  217. package/dist/types/players/MewsWsPlayer/types.d.ts +15 -15
  218. package/dist/types/players/MistPlayer.d.ts +2 -2
  219. package/dist/types/players/MistWebRTCPlayer/index.d.ts +3 -3
  220. package/dist/types/players/NativePlayer.d.ts +3 -3
  221. package/dist/types/players/VideoJsPlayer.d.ts +3 -3
  222. package/dist/types/players/WebCodecsPlayer/JitterBuffer.d.ts +3 -3
  223. package/dist/types/players/WebCodecsPlayer/LatencyProfiles.d.ts +1 -1
  224. package/dist/types/players/WebCodecsPlayer/RawChunkParser.d.ts +2 -2
  225. package/dist/types/players/WebCodecsPlayer/SyncController.d.ts +2 -2
  226. package/dist/types/players/WebCodecsPlayer/WebSocketController.d.ts +3 -3
  227. package/dist/types/players/WebCodecsPlayer/index.d.ts +9 -9
  228. package/dist/types/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.d.ts +1 -1
  229. package/dist/types/players/WebCodecsPlayer/types.d.ts +49 -49
  230. package/dist/types/players/WebCodecsPlayer/worker/types.d.ts +31 -31
  231. package/dist/types/players/index.d.ts +5 -8
  232. package/dist/types/types.d.ts +15 -15
  233. package/dist/types/vanilla/FrameWorksPlayer.d.ts +2 -2
  234. package/dist/types/vanilla/index.d.ts +4 -4
  235. package/dist/workers/decoder.worker.js +129 -122
  236. package/dist/workers/decoder.worker.js.map +1 -1
  237. package/package.json +31 -15
  238. package/src/core/ABRController.ts +38 -36
  239. package/src/core/CodecUtils.ts +49 -46
  240. package/src/core/Disposable.ts +4 -4
  241. package/src/core/ErrorClassifier.ts +499 -0
  242. package/src/core/EventEmitter.ts +1 -1
  243. package/src/core/GatewayClient.ts +41 -39
  244. package/src/core/InteractionController.ts +89 -82
  245. package/src/core/LiveDurationProxy.ts +14 -15
  246. package/src/core/MetaTrackManager.ts +73 -65
  247. package/src/core/MistReporter.ts +72 -45
  248. package/src/core/MistSignaling.ts +59 -56
  249. package/src/core/PlayerController.ts +542 -384
  250. package/src/core/PlayerInterface.ts +192 -59
  251. package/src/core/PlayerManager.ts +354 -164
  252. package/src/core/PlayerRegistry.ts +238 -87
  253. package/src/core/QualityMonitor.ts +38 -31
  254. package/src/core/ScreenWakeLockManager.ts +8 -9
  255. package/src/core/SeekingUtils.ts +31 -22
  256. package/src/core/StreamStateClient.ts +74 -68
  257. package/src/core/SubtitleManager.ts +24 -22
  258. package/src/core/TelemetryReporter.ts +38 -32
  259. package/src/core/TimeFormat.ts +13 -17
  260. package/src/core/TimerManager.ts +24 -8
  261. package/src/core/UrlUtils.ts +20 -17
  262. package/src/core/detector.ts +44 -44
  263. package/src/core/index.ts +57 -48
  264. package/src/core/scorer.ts +136 -141
  265. package/src/core/selector.ts +2 -6
  266. package/src/global.d.ts +1 -1
  267. package/src/index.ts +56 -36
  268. package/src/players/DashJsPlayer.ts +164 -115
  269. package/src/players/HlsJsPlayer.ts +132 -78
  270. package/src/players/MewsWsPlayer/SourceBufferManager.ts +41 -36
  271. package/src/players/MewsWsPlayer/WebSocketManager.ts +9 -9
  272. package/src/players/MewsWsPlayer/index.ts +192 -152
  273. package/src/players/MewsWsPlayer/types.ts +21 -21
  274. package/src/players/MistPlayer.ts +45 -26
  275. package/src/players/MistWebRTCPlayer/index.ts +175 -129
  276. package/src/players/NativePlayer.ts +203 -143
  277. package/src/players/VideoJsPlayer.ts +170 -118
  278. package/src/players/WebCodecsPlayer/JitterBuffer.ts +6 -7
  279. package/src/players/WebCodecsPlayer/LatencyProfiles.ts +43 -43
  280. package/src/players/WebCodecsPlayer/RawChunkParser.ts +10 -10
  281. package/src/players/WebCodecsPlayer/SyncController.ts +45 -53
  282. package/src/players/WebCodecsPlayer/WebSocketController.ts +66 -68
  283. package/src/players/WebCodecsPlayer/index.ts +265 -223
  284. package/src/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.ts +12 -17
  285. package/src/players/WebCodecsPlayer/types.ts +56 -56
  286. package/src/players/WebCodecsPlayer/worker/decoder.worker.ts +238 -182
  287. package/src/players/WebCodecsPlayer/worker/types.ts +31 -31
  288. package/src/players/index.ts +5 -16
  289. package/src/styles/animations.css +2 -1
  290. package/src/styles/player.css +185 -42
  291. package/src/styles/tailwind.css +473 -159
  292. package/src/types.ts +43 -43
  293. package/src/vanilla/FrameWorksPlayer.ts +26 -14
  294. package/src/vanilla/index.ts +4 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetaTrackManager.js","sources":["../../../../src/core/MetaTrackManager.ts"],"sourcesContent":["import type { MetaTrackEvent, MetaTrackEventType } from \"../types\";\nimport { TimerManager } from \"./TimerManager\";\n\nexport interface MetaTrackSubscription {\n trackId: string;\n callback: (event: MetaTrackEvent) => void;\n}\n\nexport interface MetaTrackManagerConfig {\n /** MistServer base URL */\n mistBaseUrl: string;\n /** Stream name */\n streamName: string;\n /** Initial subscriptions */\n subscriptions?: MetaTrackSubscription[];\n /** Debug logging */\n debug?: boolean;\n /** Buffer ahead duration in seconds (default: 5) */\n bufferAhead?: number;\n /** Max age for messages in seconds before filtering (default: 5) */\n maxMessageAge?: number;\n /** Fast-forward interval in seconds for catching up (default: 5) */\n fastForwardInterval?: number;\n}\n\ntype ConnectionState = \"disconnected\" | \"connecting\" | \"connected\" | \"reconnecting\";\n\n/**\n * MetaTrackManager - Handles real-time metadata subscriptions via MistServer WebSocket\n *\n * Uses native MistServer WebSocket protocol (from embed/player.js):\n * - Connect: ws://{baseUrl}/json_{streamName}.js?rate=1\n * - Set tracks: {type:\"tracks\", meta:\"1,2,3\"} (comma-separated indices)\n * - Seek: {type:\"seek\", seek_time:<ms>, ff_to:<ms>}\n * - Receive: {time:<ms>, track:<index>, data:{...}}\n * - Control: {type:\"hold\"}, {type:\"play\"}, {type:\"fast_forward\", ff_to:<ms>}\n *\n * Features:\n * - Automatic reconnection with exponential backoff\n * - Message buffering during reconnection\n * - Type detection for subtitle/score/event/chapter data\n * - Stay-ahead buffering for smooth playback\n *\n * @example\n * ```ts\n * const manager = new MetaTrackManager({\n * mistBaseUrl: 'https://mist.example.com',\n * streamName: 'pk_...', // playbackId (view key)\n * });\n *\n * manager.subscribe('1', (event) => {\n * if (event.type === 'subtitle') {\n * console.log('Subtitle:', event.data);\n * }\n * });\n *\n * manager.connect();\n * ```\n */\nexport class MetaTrackManager {\n private config: MetaTrackManagerConfig;\n private ws: WebSocket | null = null;\n private state: ConnectionState = \"disconnected\";\n private subscriptions: Map<string, Set<(event: MetaTrackEvent) => void>> = new Map();\n private pendingSubscriptions: Set<string> = new Set();\n private reconnectAttempt = 0;\n private timers = new TimerManager();\n private messageBuffer: MetaTrackEvent[] = [];\n private debug: boolean;\n private connectionId: number = 0; // Track connection attempts to prevent stale callbacks\n\n // Debounce time for rapid mount/unmount cycles (ms)\n private static readonly CONNECTION_DEBOUNCE_MS = 100;\n\n // Reconnection settings\n private static readonly MAX_RECONNECT_ATTEMPTS = 5;\n private static readonly INITIAL_RECONNECT_DELAY = 1000;\n private static readonly MAX_RECONNECT_DELAY = 30000;\n private static readonly MESSAGE_BUFFER_SIZE = 100;\n\n // Buffer management (MistMetaPlayer feature backport)\n private currentPlaybackTime = 0;\n private bufferAhead: number;\n private maxMessageAge: number;\n private fastForwardInterval: number;\n private lastFastForwardTime = 0;\n private timedEventBuffer: Map<string, MetaTrackEvent[]> = new Map(); // trackId -> events sorted by time\n\n constructor(config: MetaTrackManagerConfig) {\n this.config = config;\n this.debug = config.debug ?? false;\n\n // Buffer management settings (MistMetaPlayer defaults)\n this.bufferAhead = config.bufferAhead ?? 5;\n this.maxMessageAge = config.maxMessageAge ?? 5;\n this.fastForwardInterval = config.fastForwardInterval ?? 5;\n\n // Add initial subscriptions\n if (config.subscriptions) {\n for (const sub of config.subscriptions) {\n this.subscribe(sub.trackId, sub.callback);\n }\n }\n }\n\n /**\n * Connect to MistServer WebSocket\n * Debounced to prevent orphaned connections during rapid mount/unmount cycles.\n */\n connect(): void {\n if (this.state === \"connecting\" || this.state === \"connected\") {\n return;\n }\n\n this.state = \"connecting\";\n this.log(\"Connecting...\");\n\n // Increment connection ID to invalidate any pending callbacks\n const currentConnectionId = ++this.connectionId;\n\n // Debounce connection\n this.timers.start(\n () => {\n // Check if this connection attempt is still valid\n if (this.state !== \"connecting\" || this.connectionId !== currentConnectionId) {\n return;\n }\n\n this.createWebSocket(currentConnectionId);\n },\n MetaTrackManager.CONNECTION_DEBOUNCE_MS,\n \"connect\"\n );\n }\n\n /**\n * Internal method to create WebSocket after debounce\n */\n private createWebSocket(connectionId: number): void {\n try {\n const wsUrl = this.buildWsUrl();\n this.ws = new WebSocket(wsUrl);\n\n this.ws.onopen = () => {\n // Verify still valid\n if (this.connectionId !== connectionId) {\n this.ws?.close();\n return;\n }\n\n this.log(\"Connected\");\n this.state = \"connected\";\n this.reconnectAttempt = 0;\n\n // Merge pending subscriptions into existing\n for (const trackId of this.pendingSubscriptions) {\n if (!this.subscriptions.has(trackId)) {\n this.subscriptions.set(trackId, new Set());\n }\n }\n this.pendingSubscriptions.clear();\n\n // Send all subscribed tracks at once (MistServer protocol)\n this.sendTracksUpdate();\n\n // Send initial seek to current playback position\n this.sendSeek(this.currentPlaybackTime);\n\n // Flush message buffer\n this.flushMessageBuffer();\n };\n\n this.ws.onmessage = (event) => {\n this.handleMessage(event.data);\n };\n\n this.ws.onerror = (event) => {\n this.log(\"WebSocket error\");\n console.warn(\"[MetaTrackManager] WebSocket error:\", event);\n };\n\n this.ws.onclose = () => {\n this.log(\"Disconnected\");\n this.ws = null;\n\n if (this.state !== \"disconnected\") {\n this.scheduleReconnect();\n }\n };\n } catch (error) {\n this.log(`Connection error: ${error}`);\n this.scheduleReconnect();\n }\n }\n\n /**\n * Disconnect from MistServer\n */\n disconnect(): void {\n this.state = \"disconnected\";\n\n // Clear all timers\n this.timers.destroy();\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n }\n\n /**\n * Subscribe to a meta track\n * @param trackId Track index (number as string) or \"all\" for all meta tracks\n */\n subscribe(trackId: string, callback: (event: MetaTrackEvent) => void): () => void {\n const isNewTrack = !this.subscriptions.has(trackId);\n\n if (isNewTrack) {\n this.subscriptions.set(trackId, new Set());\n }\n\n this.subscriptions.get(trackId)!.add(callback);\n\n // Send updated track list if connected and this is a new track\n if (this.state === \"connected\" && this.ws && isNewTrack) {\n this.sendTracksUpdate();\n } else if (isNewTrack) {\n this.pendingSubscriptions.add(trackId);\n }\n\n // Return unsubscribe function\n return () => this.unsubscribe(trackId, callback);\n }\n\n /**\n * Unsubscribe from a meta track\n */\n unsubscribe(trackId: string, callback: (event: MetaTrackEvent) => void): void {\n const callbacks = this.subscriptions.get(trackId);\n if (callbacks) {\n callbacks.delete(callback);\n\n // If no more callbacks, remove subscription and update MistServer\n if (callbacks.size === 0) {\n this.subscriptions.delete(trackId);\n // Send updated track list (MistServer doesn't have explicit unsubscribe)\n if (this.state === \"connected\" && this.ws) {\n this.sendTracksUpdate();\n }\n }\n }\n }\n\n /**\n * Get list of subscribed track IDs\n */\n getSubscribedTracks(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n\n /**\n * Get connection state\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.state === \"connected\";\n }\n\n // ========================================\n // Buffer Management (MistMetaPlayer backport)\n // ========================================\n\n /**\n * Update current playback time\n * Call this on video timeupdate events to keep buffer in sync\n */\n setPlaybackTime(timeInSeconds: number): void {\n this.currentPlaybackTime = timeInSeconds;\n\n // Process any buffered events that are now due\n this.processTimedEvents();\n }\n\n /**\n * Get current playback time\n */\n getPlaybackTime(): number {\n return this.currentPlaybackTime;\n }\n\n /**\n * Handle seek event - clears buffer and sends seek command to MistServer\n * Call this when video seeks to a new position\n */\n onSeek(newTimeInSeconds: number): void {\n this.log(`Seek to ${newTimeInSeconds}s - clearing buffer and notifying server`);\n this.currentPlaybackTime = newTimeInSeconds;\n\n // Clear all timed event buffers\n this.timedEventBuffer.clear();\n\n // Reset fast-forward tracking\n this.lastFastForwardTime = 0;\n\n // Tell MistServer to seek its metadata stream\n this.sendSeek(newTimeInSeconds);\n }\n\n /**\n * Process buffered events up to current playback time\n * Dispatches events that are ready to be shown\n */\n private processTimedEvents(): void {\n const now = this.currentPlaybackTime * 1000; // Convert to ms\n\n for (const [trackId, events] of this.timedEventBuffer) {\n // Find events that should be dispatched\n const dueEvents: MetaTrackEvent[] = [];\n const remainingEvents: MetaTrackEvent[] = [];\n\n for (const event of events) {\n if (event.timestamp <= now) {\n // Check if event is too old (filter stale events)\n const ageSeconds = (now - event.timestamp) / 1000;\n if (ageSeconds <= this.maxMessageAge) {\n dueEvents.push(event);\n } else {\n this.log(`Filtering stale event (${ageSeconds.toFixed(1)}s old)`);\n }\n } else {\n remainingEvents.push(event);\n }\n }\n\n // Dispatch due events\n for (const event of dueEvents) {\n this.dispatchEvent(event);\n }\n\n // Update buffer with remaining events\n if (remainingEvents.length > 0) {\n this.timedEventBuffer.set(trackId, remainingEvents);\n } else {\n this.timedEventBuffer.delete(trackId);\n }\n }\n }\n\n /**\n * Add event to timed buffer (sorted by timestamp)\n * Used for events that should be dispatched at specific playback times\n */\n private addToTimedBuffer(event: MetaTrackEvent): void {\n const trackId = event.trackId;\n\n if (!this.timedEventBuffer.has(trackId)) {\n this.timedEventBuffer.set(trackId, []);\n }\n\n const buffer = this.timedEventBuffer.get(trackId)!;\n\n // Insert in sorted order by timestamp\n let insertIndex = buffer.length;\n for (let i = 0; i < buffer.length; i++) {\n if (buffer[i].timestamp > event.timestamp) {\n insertIndex = i;\n break;\n }\n }\n buffer.splice(insertIndex, 0, event);\n\n // Limit buffer size per track\n while (buffer.length > MetaTrackManager.MESSAGE_BUFFER_SIZE) {\n buffer.shift();\n }\n }\n\n /**\n * Check if we need to request more data (stay bufferAhead seconds ahead)\n * Returns true if buffer is running low\n */\n needsMoreData(trackId: string): boolean {\n const buffer = this.timedEventBuffer.get(trackId);\n if (!buffer || buffer.length === 0) return true;\n\n const lastEventTime = buffer[buffer.length - 1].timestamp / 1000;\n const currentTime = this.currentPlaybackTime;\n const bufferedAhead = lastEventTime - currentTime;\n\n return bufferedAhead < this.bufferAhead;\n }\n\n /**\n * Fast-forward through buffered events (rate-limited)\n * Used when playback jumps ahead and needs to catch up\n * Also notifies MistServer to fast-forward its metadata stream\n */\n fastForward(): void {\n const now = Date.now();\n\n // Rate limit fast-forward (once per fastForwardInterval seconds)\n if (now - this.lastFastForwardTime < this.fastForwardInterval * 1000) {\n return;\n }\n\n this.lastFastForwardTime = now;\n this.log(\"Fast-forwarding through buffered events\");\n\n // Process all events up to current time + bufferAhead\n const targetTime = (this.currentPlaybackTime + this.bufferAhead) * 1000;\n\n for (const [trackId, events] of this.timedEventBuffer) {\n const processEvents: MetaTrackEvent[] = [];\n const remainingEvents: MetaTrackEvent[] = [];\n\n for (const event of events) {\n if (event.timestamp <= targetTime) {\n // Only dispatch if not too old\n const ageSeconds = (this.currentPlaybackTime * 1000 - event.timestamp) / 1000;\n if (ageSeconds <= this.maxMessageAge) {\n processEvents.push(event);\n }\n } else {\n remainingEvents.push(event);\n }\n }\n\n // Dispatch events\n for (const event of processEvents) {\n this.dispatchEvent(event);\n }\n\n // Update buffer\n if (remainingEvents.length > 0) {\n this.timedEventBuffer.set(trackId, remainingEvents);\n } else {\n this.timedEventBuffer.delete(trackId);\n }\n }\n\n // Tell MistServer to fast-forward as well\n this.sendFastForward(this.currentPlaybackTime + this.bufferAhead);\n }\n\n /**\n * Get buffer status for debugging\n */\n getBufferStatus(): Record<string, { count: number; oldestMs: number; newestMs: number }> {\n const status: Record<string, { count: number; oldestMs: number; newestMs: number }> = {};\n\n for (const [trackId, events] of this.timedEventBuffer) {\n if (events.length > 0) {\n status[trackId] = {\n count: events.length,\n oldestMs: events[0].timestamp,\n newestMs: events[events.length - 1].timestamp,\n };\n }\n }\n\n return status;\n }\n\n /**\n * Build WebSocket URL for MistServer meta track subscription\n * Uses the same endpoint as JSON info polling, just over WebSocket\n */\n private buildWsUrl(): string {\n const baseUrl = this.config.mistBaseUrl\n .replace(/^http:/, \"ws:\")\n .replace(/^https:/, \"wss:\")\n .replace(/\\/$/, \"\");\n\n // MistServer meta track WebSocket uses /json_<streamname>.js endpoint\n // The rate=1 param tells MistServer to stream metadata in real-time\n return `${baseUrl}/json_${this.config.streamName}.js?rate=1`;\n }\n\n /**\n * Send tracks update to MistServer\n * MistServer protocol: {type:\"tracks\", meta:\"1,2,3\"} (comma-separated track indices)\n */\n private sendTracksUpdate(): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n const trackIds = Array.from(this.subscriptions.keys());\n // Support \"all\" as special track ID to subscribe to all meta tracks\n const metaValue = trackIds.includes(\"all\") ? \"all\" : trackIds.join(\",\");\n\n const message = JSON.stringify({\n type: \"tracks\",\n meta: metaValue,\n });\n this.ws.send(message);\n this.log(`Set tracks: ${metaValue}`);\n }\n }\n\n /**\n * Send seek command to MistServer\n * MistServer protocol: {type:\"seek\", seek_time:<ms>, ff_to:<ms>}\n */\n private sendSeek(timeInSeconds: number): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n const seekTimeMs = Math.round(timeInSeconds * 1000);\n const ffToMs = Math.round((timeInSeconds + this.bufferAhead) * 1000);\n\n const message = JSON.stringify({\n type: \"seek\",\n seek_time: seekTimeMs,\n ff_to: ffToMs,\n });\n this.ws.send(message);\n this.log(`Seek to ${timeInSeconds}s, buffer ahead to ${timeInSeconds + this.bufferAhead}s`);\n }\n }\n\n /**\n * Send hold command (pause metadata delivery)\n */\n private sendHold(): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify({ type: \"hold\" }));\n this.log(\"Sent hold\");\n }\n }\n\n /**\n * Send play command (resume metadata delivery)\n */\n private sendPlay(): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify({ type: \"play\" }));\n this.log(\"Sent play\");\n }\n }\n\n /**\n * Send fast-forward command\n */\n private sendFastForward(targetTimeSeconds: number): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n const message = JSON.stringify({\n type: \"fast_forward\",\n ff_to: Math.round(targetTimeSeconds * 1000),\n });\n this.ws.send(message);\n this.log(`Fast-forward to ${targetTimeSeconds}s`);\n }\n }\n\n /**\n * Handle incoming WebSocket message\n * MistServer format:\n * - Metadata: {time:<ms>, track:<index>, data:{...}}\n * - Status: {type:\"on_time\", data:{current:<ms>}}\n * - Seek complete: {type:\"seek\", ...}\n */\n private handleMessage(data: string): void {\n try {\n const parsed = JSON.parse(data);\n\n // Handle metadata event: {time, track, data}\n if (\"time\" in parsed && \"track\" in parsed && \"data\" in parsed) {\n const event = this.parseMetaTrackEvent(parsed);\n\n // Check if we're subscribed to this track (or \"all\")\n const trackId = String(parsed.track);\n if (this.subscriptions.has(trackId) || this.subscriptions.has(\"all\")) {\n // Subtitles and chapters should be buffered for timed playback\n // Other events (scores, generic events) dispatch immediately\n if (event.type === \"subtitle\" || event.type === \"chapter\") {\n this.addToTimedBuffer(event);\n // Also process immediately in case we're already past this time\n this.processTimedEvents();\n } else {\n // Dispatch immediately for non-timed events\n this.dispatchEvent(event);\n }\n }\n return;\n }\n\n // Handle server status messages: {type:..., ...}\n if (\"type\" in parsed) {\n switch (parsed.type) {\n case \"on_time\":\n // Server time update - can be used for buffer management\n if (parsed.data?.current) {\n const serverTimeMs = parsed.data.current;\n const playerTimeMs = this.currentPlaybackTime * 1000;\n const aheadMs = serverTimeMs - playerTimeMs;\n\n // If server is too far ahead, pause and wait\n if (aheadMs > this.bufferAhead * 6 * 1000) {\n this.log(`Server ${aheadMs}ms ahead, sending hold`);\n this.sendHold();\n }\n }\n break;\n\n case \"seek\":\n // Seek completed - clear buffers\n this.log(\"Server confirmed seek, clearing buffers\");\n this.timedEventBuffer.clear();\n break;\n\n default:\n this.log(`Unknown message type: ${parsed.type}`);\n }\n }\n } catch (error) {\n this.log(`Failed to parse message: ${error}`);\n }\n }\n\n /**\n * Parse meta track event from MistServer message\n * MistServer format: {time:<ms>, track:<index>, data:{...}}\n */\n private parseMetaTrackEvent(message: {\n track: string | number;\n time: number;\n data?: unknown;\n [key: string]: unknown;\n }): MetaTrackEvent {\n const trackId = String(message.track);\n const timestamp = Number(message.time);\n const data = message.data ?? message;\n\n // Detect event type from data shape\n const type = this.detectEventType(data);\n\n return {\n type,\n timestamp,\n trackId,\n data,\n };\n }\n\n /**\n * Detect event type from data shape\n */\n private detectEventType(data: unknown): MetaTrackEventType {\n if (typeof data !== \"object\" || data === null) {\n return \"unknown\";\n }\n\n const obj = data as Record<string, unknown>;\n\n // Subtitle: has text, startTime/endTime\n if (\"text\" in obj && (\"startTime\" in obj || \"start\" in obj)) {\n return \"subtitle\";\n }\n\n // Score: has key and value\n if (\"key\" in obj && \"value\" in obj) {\n return \"score\";\n }\n\n // Chapter: has title and startTime\n if (\"title\" in obj && \"startTime\" in obj) {\n return \"chapter\";\n }\n\n // Event: has name\n if (\"name\" in obj) {\n return \"event\";\n }\n\n return \"unknown\";\n }\n\n /**\n * Dispatch event to subscribers\n */\n private dispatchEvent(event: MetaTrackEvent): void {\n const callbacks = this.subscriptions.get(event.trackId);\n if (callbacks) {\n for (const callback of callbacks) {\n try {\n callback(event);\n } catch (error) {\n console.error(\"[MetaTrackManager] Callback error:\", error);\n }\n }\n }\n }\n\n /**\n * Schedule reconnection attempt\n */\n private scheduleReconnect(): void {\n if (this.state === \"disconnected\") return;\n\n if (this.reconnectAttempt >= MetaTrackManager.MAX_RECONNECT_ATTEMPTS) {\n this.log(\"Max reconnect attempts reached\");\n this.state = \"disconnected\";\n return;\n }\n\n this.state = \"reconnecting\";\n this.reconnectAttempt++;\n\n const delay = Math.min(\n MetaTrackManager.INITIAL_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempt - 1),\n MetaTrackManager.MAX_RECONNECT_DELAY\n );\n\n this.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt})`);\n\n this.timers.start(\n () => {\n this.connect();\n },\n delay,\n \"reconnect\"\n );\n }\n\n /**\n * Buffer message for later delivery\n */\n private bufferMessage(event: MetaTrackEvent): void {\n this.messageBuffer.push(event);\n\n // Limit buffer size\n while (this.messageBuffer.length > MetaTrackManager.MESSAGE_BUFFER_SIZE) {\n this.messageBuffer.shift();\n }\n }\n\n /**\n * Flush buffered messages to subscribers\n */\n private flushMessageBuffer(): void {\n const buffered = [...this.messageBuffer];\n this.messageBuffer = [];\n\n for (const event of buffered) {\n this.dispatchEvent(event);\n }\n }\n\n /**\n * Debug logging\n */\n private log(message: string): void {\n if (this.debug) {\n console.debug(`[MetaTrackManager] ${message}`);\n }\n }\n}\n\nexport default MetaTrackManager;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,447 @@
1
+ import { TimerManager } from './TimerManager.js';
2
+
3
+ /**
4
+ * MistReporter - Reports playback stats to MistServer
5
+ *
6
+ * Implements the same reporting protocol as MistPlayer reference:
7
+ * - Sends initial report on player selection (player, sourceType, sourceUrl, pageUrl)
8
+ * - Reports deltas every 5 seconds
9
+ * - Tracks waiting/stalled events and durations
10
+ * - Integrates with QualityMonitor for playbackScore
11
+ * - Sends final report on unload
12
+ *
13
+ * Reports are sent over the same WebSocket used for stream state.
14
+ */
15
+ /**
16
+ * MistReporter - Playback telemetry to MistServer
17
+ */
18
+ class MistReporter {
19
+ constructor(options = {}) {
20
+ this.socket = null;
21
+ this.videoElement = null;
22
+ this.containerElement = null;
23
+ this.logs = [];
24
+ // Time tracking state
25
+ this.waitingSince = 0;
26
+ this.stalledSince = 0;
27
+ this.unpausedSince = 0;
28
+ this.timeWaitingAccum = 0;
29
+ this.timeStalledAccum = 0;
30
+ this.timeUnpausedAccum = 0;
31
+ // Last reported values for delta detection
32
+ this.lastReported = {};
33
+ // Timer manager for periodic reporting
34
+ this.timers = new TimerManager();
35
+ // Event listener cleanup functions
36
+ this.listeners = [];
37
+ // Track if first playback has been recorded
38
+ this.firstPlaybackRecorded = false;
39
+ // E2: Batch reporting state
40
+ this.pendingBatch = {};
41
+ this.hasPendingBatch = false;
42
+ this.lastFlushTime = 0;
43
+ this.batchFlushTimerId = null;
44
+ // E3: Offline queue for telemetry
45
+ this.offlineQueue = [];
46
+ this.socket = options.socket ?? null;
47
+ this.reportInterval = options.reportInterval ?? 5000;
48
+ this.batchFlushInterval = options.batchFlushInterval ?? 1000;
49
+ this.bootMs = options.bootMs ?? Date.now();
50
+ this.logs = options.logs ?? [];
51
+ // Initialize stats
52
+ this._stats = {
53
+ _nWaiting: 0,
54
+ _nStalled: 0,
55
+ _nError: 0,
56
+ lastError: null,
57
+ firstPlayback: null,
58
+ playbackScore: 1.0,
59
+ autoplay: null,
60
+ tracks: null,
61
+ };
62
+ // Initialize lastReported to empty
63
+ this.lastReported = {
64
+ nWaiting: 0,
65
+ timeWaiting: 0,
66
+ nStalled: 0,
67
+ timeStalled: 0,
68
+ timeUnpaused: 0,
69
+ nError: 0,
70
+ lastError: null,
71
+ firstPlayback: null,
72
+ playbackScore: 1,
73
+ autoplay: null,
74
+ videoHeight: null,
75
+ videoWidth: null,
76
+ playerHeight: null,
77
+ playerWidth: null,
78
+ tracks: null,
79
+ nLog: 0,
80
+ };
81
+ }
82
+ /**
83
+ * Set the WebSocket to use for reporting
84
+ * E3: Flushes offline queue when socket becomes available
85
+ */
86
+ setSocket(socket) {
87
+ const wasDisconnected = !this.socket || this.socket.readyState !== WebSocket.OPEN;
88
+ this.socket = socket;
89
+ // E3: Flush offline queue when reconnecting
90
+ if (wasDisconnected && socket?.readyState === WebSocket.OPEN) {
91
+ this.flushOfflineQueue();
92
+ }
93
+ }
94
+ /**
95
+ * E3: Flush queued reports that were collected while offline
96
+ */
97
+ flushOfflineQueue() {
98
+ if (this.offlineQueue.length === 0) {
99
+ return;
100
+ }
101
+ // Send all queued reports
102
+ for (const report of this.offlineQueue) {
103
+ this.sendReport(report);
104
+ }
105
+ this.offlineQueue = [];
106
+ }
107
+ /**
108
+ * Get current stats object with computed getters
109
+ * E1: Uses performance.now() for sub-millisecond precision in duration tracking
110
+ */
111
+ getStats() {
112
+ const now = performance.now();
113
+ return {
114
+ nWaiting: this._stats._nWaiting,
115
+ timeWaiting: Math.round(this.timeWaitingAccum + (this.waitingSince > 0 ? now - this.waitingSince : 0)),
116
+ nStalled: this._stats._nStalled,
117
+ timeStalled: Math.round(this.timeStalledAccum + (this.stalledSince > 0 ? now - this.stalledSince : 0)),
118
+ timeUnpaused: Math.round(this.timeUnpausedAccum + (this.unpausedSince > 0 ? now - this.unpausedSince : 0)),
119
+ nError: this._stats._nError,
120
+ lastError: this._stats.lastError,
121
+ firstPlayback: this._stats.firstPlayback,
122
+ playbackScore: Math.round(this._stats.playbackScore * 10) / 10,
123
+ autoplay: this._stats.autoplay,
124
+ videoHeight: this.videoElement?.videoHeight ?? null,
125
+ videoWidth: this.videoElement?.videoWidth ?? null,
126
+ playerHeight: this.containerElement?.clientHeight ?? null,
127
+ playerWidth: this.containerElement?.clientWidth ?? null,
128
+ tracks: this._stats.tracks,
129
+ nLog: this.logs.length,
130
+ };
131
+ }
132
+ /**
133
+ * Set a stat value
134
+ */
135
+ set(key, value) {
136
+ if (key === "nWaiting") {
137
+ this._stats._nWaiting = value;
138
+ }
139
+ else if (key === "nStalled") {
140
+ this._stats._nStalled = value;
141
+ }
142
+ else if (key === "nError") {
143
+ this._stats._nError = value;
144
+ }
145
+ else if (key === "lastError") {
146
+ this._stats.lastError = value;
147
+ }
148
+ else if (key === "firstPlayback") {
149
+ this._stats.firstPlayback = value;
150
+ }
151
+ else if (key === "playbackScore") {
152
+ this._stats.playbackScore = value;
153
+ }
154
+ else if (key === "autoplay") {
155
+ this._stats.autoplay = value;
156
+ }
157
+ else if (key === "tracks") {
158
+ this._stats.tracks = value;
159
+ }
160
+ // Other keys (computed) are read-only
161
+ }
162
+ /**
163
+ * Increment a counter stat
164
+ */
165
+ add(key, amount = 1) {
166
+ if (key === "nWaiting") {
167
+ this._stats._nWaiting += amount;
168
+ }
169
+ else if (key === "nStalled") {
170
+ this._stats._nStalled += amount;
171
+ }
172
+ else if (key === "nError") {
173
+ this._stats._nError += amount;
174
+ }
175
+ }
176
+ /**
177
+ * Initialize reporting for a video element
178
+ */
179
+ init(videoElement, containerElement) {
180
+ this.videoElement = videoElement;
181
+ this.containerElement = containerElement ?? videoElement.parentElement ?? null;
182
+ this.firstPlaybackRecorded = false;
183
+ // Set up event listeners like MistPlayer reference
184
+ // E1: Use performance.now() for sub-millisecond precision in duration tracking
185
+ const onPlaying = () => {
186
+ const now = performance.now();
187
+ const isFirstPlay = !this.firstPlaybackRecorded;
188
+ // Record first playback time (still uses Date.now for absolute timestamp)
189
+ if (isFirstPlay) {
190
+ this._stats.firstPlayback = Date.now() - this.bootMs;
191
+ this.firstPlaybackRecorded = true;
192
+ }
193
+ // End waiting state if active
194
+ if (this.waitingSince > 0) {
195
+ this.timeWaitingAccum += now - this.waitingSince;
196
+ this.waitingSince = 0;
197
+ }
198
+ // End stalled state if active
199
+ if (this.stalledSince > 0) {
200
+ this.timeStalledAccum += now - this.stalledSince;
201
+ this.stalledSince = 0;
202
+ }
203
+ // Start unpaused timer
204
+ if (this.unpausedSince === 0) {
205
+ this.unpausedSince = now;
206
+ }
207
+ // E2: Flush immediately on first playback
208
+ if (isFirstPlay) {
209
+ this.reportStats();
210
+ this.flushBatch();
211
+ }
212
+ };
213
+ const onWaiting = () => {
214
+ this._stats._nWaiting++;
215
+ if (this.waitingSince === 0) {
216
+ this.waitingSince = performance.now();
217
+ }
218
+ };
219
+ const onStalled = () => {
220
+ this._stats._nStalled++;
221
+ if (this.stalledSince === 0) {
222
+ this.stalledSince = performance.now();
223
+ }
224
+ };
225
+ const onPause = () => {
226
+ // End unpaused timer
227
+ if (this.unpausedSince > 0) {
228
+ this.timeUnpausedAccum += performance.now() - this.unpausedSince;
229
+ this.unpausedSince = 0;
230
+ }
231
+ };
232
+ const onError = (e) => {
233
+ this._stats._nError++;
234
+ const error = e.message || "Unknown error";
235
+ this._stats.lastError = error;
236
+ // E2: Flush immediately on error
237
+ this.reportStats();
238
+ this.flushBatch();
239
+ };
240
+ const onCanPlay = () => {
241
+ // End waiting state if active
242
+ if (this.waitingSince > 0) {
243
+ this.timeWaitingAccum += performance.now() - this.waitingSince;
244
+ this.waitingSince = 0;
245
+ }
246
+ };
247
+ videoElement.addEventListener("playing", onPlaying);
248
+ videoElement.addEventListener("waiting", onWaiting);
249
+ videoElement.addEventListener("stalled", onStalled);
250
+ videoElement.addEventListener("pause", onPause);
251
+ videoElement.addEventListener("error", onError);
252
+ videoElement.addEventListener("canplay", onCanPlay);
253
+ this.listeners = [
254
+ () => videoElement.removeEventListener("playing", onPlaying),
255
+ () => videoElement.removeEventListener("waiting", onWaiting),
256
+ () => videoElement.removeEventListener("stalled", onStalled),
257
+ () => videoElement.removeEventListener("pause", onPause),
258
+ () => videoElement.removeEventListener("error", onError),
259
+ () => videoElement.removeEventListener("canplay", onCanPlay),
260
+ ];
261
+ // Start periodic reporting
262
+ this.startReporting();
263
+ }
264
+ /**
265
+ * Send initial report when player is selected
266
+ */
267
+ sendInitialReport(info) {
268
+ this.report(info);
269
+ }
270
+ /**
271
+ * Update playback score (call from QualityMonitor)
272
+ */
273
+ setPlaybackScore(score) {
274
+ this._stats.playbackScore = score;
275
+ }
276
+ /**
277
+ * Update autoplay status
278
+ */
279
+ setAutoplayStatus(status) {
280
+ this._stats.autoplay = status;
281
+ }
282
+ /**
283
+ * Update current tracks
284
+ */
285
+ setTracks(tracks) {
286
+ this._stats.tracks = tracks.join(",");
287
+ }
288
+ /**
289
+ * Send a report over WebSocket immediately
290
+ * E3: Queues reports when socket is unavailable (up to MAX_OFFLINE_QUEUE_SIZE)
291
+ */
292
+ sendReport(data) {
293
+ // If socket not available, queue for later
294
+ if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
295
+ // E3: Queue report for when socket reconnects
296
+ if (this.offlineQueue.length < MistReporter.MAX_OFFLINE_QUEUE_SIZE) {
297
+ this.offlineQueue.push(data);
298
+ }
299
+ // If queue is full, oldest reports are lost (FIFO overflow)
300
+ return;
301
+ }
302
+ try {
303
+ this.socket.send(JSON.stringify(data));
304
+ }
305
+ catch {
306
+ // E3: Queue on send failure too
307
+ if (this.offlineQueue.length < MistReporter.MAX_OFFLINE_QUEUE_SIZE) {
308
+ this.offlineQueue.push(data);
309
+ }
310
+ }
311
+ }
312
+ /**
313
+ * E2: Queue data for batched reporting
314
+ * Merges with pending batch, schedules flush if not already pending
315
+ */
316
+ report(data) {
317
+ // Merge into pending batch
318
+ Object.assign(this.pendingBatch, data);
319
+ this.hasPendingBatch = true;
320
+ // Schedule flush if not already scheduled
321
+ if (this.batchFlushTimerId === null) {
322
+ const now = performance.now();
323
+ const timeSinceLastFlush = now - this.lastFlushTime;
324
+ const delay = Math.max(0, this.batchFlushInterval - timeSinceLastFlush);
325
+ this.batchFlushTimerId = this.timers.start(() => {
326
+ this.batchFlushTimerId = null;
327
+ this.flushBatch();
328
+ }, delay, "batchFlush");
329
+ }
330
+ }
331
+ /**
332
+ * E2: Flush pending batch immediately
333
+ * Used for critical events (error, first play, unload)
334
+ */
335
+ flushBatch() {
336
+ if (this.batchFlushTimerId !== null) {
337
+ this.timers.stop(this.batchFlushTimerId);
338
+ this.batchFlushTimerId = null;
339
+ }
340
+ if (!this.hasPendingBatch) {
341
+ return;
342
+ }
343
+ this.sendReport(this.pendingBatch);
344
+ this.pendingBatch = {};
345
+ this.hasPendingBatch = false;
346
+ this.lastFlushTime = performance.now();
347
+ }
348
+ /**
349
+ * Report stats delta (only changed values)
350
+ * E2: Now queues to batch instead of sending immediately
351
+ */
352
+ reportStats() {
353
+ const current = this.getStats();
354
+ const delta = {};
355
+ let hasChanges = false;
356
+ // Compare each stat and include only changed values
357
+ const keys = [
358
+ "nWaiting",
359
+ "timeWaiting",
360
+ "nStalled",
361
+ "timeStalled",
362
+ "timeUnpaused",
363
+ "nError",
364
+ "lastError",
365
+ "firstPlayback",
366
+ "playbackScore",
367
+ "autoplay",
368
+ "videoHeight",
369
+ "videoWidth",
370
+ "playerHeight",
371
+ "playerWidth",
372
+ "tracks",
373
+ "nLog",
374
+ ];
375
+ for (const key of keys) {
376
+ const currentValue = current[key];
377
+ const lastValue = this.lastReported[key];
378
+ if (currentValue !== lastValue) {
379
+ delta[key] = currentValue;
380
+ this.lastReported[key] = currentValue;
381
+ hasChanges = true;
382
+ }
383
+ }
384
+ // Include logs if there are new ones
385
+ const lastLogCount = this.lastReported.nLog ?? 0;
386
+ if (this.logs.length > lastLogCount) {
387
+ const newLogs = this.logs.slice(lastLogCount);
388
+ if (newLogs.length > 0) {
389
+ delta.logs = newLogs;
390
+ hasChanges = true;
391
+ }
392
+ }
393
+ if (hasChanges) {
394
+ this.report(delta);
395
+ }
396
+ // Schedule next report
397
+ this.scheduleNextReport();
398
+ }
399
+ /**
400
+ * Start periodic reporting
401
+ */
402
+ startReporting() {
403
+ this.scheduleNextReport();
404
+ }
405
+ /**
406
+ * Schedule the next report
407
+ */
408
+ scheduleNextReport() {
409
+ this.timers.start(() => {
410
+ this.reportStats();
411
+ }, this.reportInterval, "report");
412
+ }
413
+ /**
414
+ * Send final report and cleanup
415
+ * E2: Flushes immediately since this is a critical event
416
+ */
417
+ sendFinalReport(reason) {
418
+ // Report final stats
419
+ this.reportStats();
420
+ // Queue unload report
421
+ this.report({ unload: reason ?? null });
422
+ // E2: Flush immediately - don't wait for batch interval
423
+ this.flushBatch();
424
+ }
425
+ /**
426
+ * Stop reporting and cleanup
427
+ */
428
+ destroy() {
429
+ // Stop all timers
430
+ this.timers.destroy();
431
+ // Remove event listeners
432
+ this.listeners.forEach((cleanup) => cleanup());
433
+ this.listeners = [];
434
+ this.videoElement = null;
435
+ this.containerElement = null;
436
+ }
437
+ /**
438
+ * Add a log entry
439
+ */
440
+ log(message) {
441
+ this.logs.push(message);
442
+ }
443
+ }
444
+ MistReporter.MAX_OFFLINE_QUEUE_SIZE = 100;
445
+
446
+ export { MistReporter };
447
+ //# sourceMappingURL=MistReporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MistReporter.js","sources":["../../../../src/core/MistReporter.ts"],"sourcesContent":["/**\n * MistReporter - Reports playback stats to MistServer\n *\n * Implements the same reporting protocol as MistPlayer reference:\n * - Sends initial report on player selection (player, sourceType, sourceUrl, pageUrl)\n * - Reports deltas every 5 seconds\n * - Tracks waiting/stalled events and durations\n * - Integrates with QualityMonitor for playbackScore\n * - Sends final report on unload\n *\n * Reports are sent over the same WebSocket used for stream state.\n */\n\nimport { TimerManager } from \"./TimerManager\";\n\nexport interface MistReporterStats {\n nWaiting: number;\n timeWaiting: number;\n nStalled: number;\n timeStalled: number;\n timeUnpaused: number;\n nError: number;\n lastError: string | null;\n firstPlayback: number | null;\n playbackScore: number;\n autoplay: \"success\" | \"muted\" | \"failed\" | null;\n videoHeight: number | null;\n videoWidth: number | null;\n playerHeight: number | null;\n playerWidth: number | null;\n tracks: string | null;\n nLog: number;\n}\n\nexport interface MistReporterInitialReport {\n player: string;\n sourceType: string;\n sourceUrl: string;\n pageUrl: string;\n}\n\nexport interface MistReporterOptions {\n /** WebSocket to send reports through (shared with stream state) */\n socket?: WebSocket | null;\n /** Report interval in ms (default: 5000) */\n reportInterval?: number;\n /** E2: Batch flush interval in ms (default: 1000) - max rate for non-critical reports */\n batchFlushInterval?: number;\n /** Boot timestamp for firstPlayback calculation */\n bootMs?: number;\n /** Log array reference for including logs in reports */\n logs?: string[];\n}\n\ntype StatsKey = keyof MistReporterStats;\n\n/**\n * MistReporter - Playback telemetry to MistServer\n */\nexport class MistReporter {\n private socket: WebSocket | null = null;\n private videoElement: HTMLVideoElement | null = null;\n private containerElement: HTMLElement | null = null;\n private reportInterval: number;\n private batchFlushInterval: number;\n private bootMs: number;\n private logs: string[] = [];\n\n // Internal stats storage (different structure for time tracking)\n private _stats: {\n _nWaiting: number;\n _nStalled: number;\n _nError: number;\n lastError: string | null;\n firstPlayback: number | null;\n playbackScore: number;\n autoplay: \"success\" | \"muted\" | \"failed\" | null;\n tracks: string | null;\n };\n\n // Time tracking state\n private waitingSince: number = 0;\n private stalledSince: number = 0;\n private unpausedSince: number = 0;\n private timeWaitingAccum: number = 0;\n private timeStalledAccum: number = 0;\n private timeUnpausedAccum: number = 0;\n\n // Last reported values for delta detection\n private lastReported: Partial<MistReporterStats> = {};\n\n // Timer manager for periodic reporting\n private timers = new TimerManager();\n\n // Event listener cleanup functions\n private listeners: Array<() => void> = [];\n\n // Track if first playback has been recorded\n private firstPlaybackRecorded = false;\n\n // E2: Batch reporting state\n private pendingBatch: Record<string, unknown> = {};\n private hasPendingBatch = false;\n private lastFlushTime = 0;\n private batchFlushTimerId: number | null = null;\n\n // E3: Offline queue for telemetry\n private offlineQueue: Record<string, unknown>[] = [];\n private static readonly MAX_OFFLINE_QUEUE_SIZE = 100;\n\n constructor(options: MistReporterOptions = {}) {\n this.socket = options.socket ?? null;\n this.reportInterval = options.reportInterval ?? 5000;\n this.batchFlushInterval = options.batchFlushInterval ?? 1000;\n this.bootMs = options.bootMs ?? Date.now();\n this.logs = options.logs ?? [];\n\n // Initialize stats\n this._stats = {\n _nWaiting: 0,\n _nStalled: 0,\n _nError: 0,\n lastError: null,\n firstPlayback: null,\n playbackScore: 1.0,\n autoplay: null,\n tracks: null,\n };\n\n // Initialize lastReported to empty\n this.lastReported = {\n nWaiting: 0,\n timeWaiting: 0,\n nStalled: 0,\n timeStalled: 0,\n timeUnpaused: 0,\n nError: 0,\n lastError: null,\n firstPlayback: null,\n playbackScore: 1,\n autoplay: null,\n videoHeight: null,\n videoWidth: null,\n playerHeight: null,\n playerWidth: null,\n tracks: null,\n nLog: 0,\n };\n }\n\n /**\n * Set the WebSocket to use for reporting\n * E3: Flushes offline queue when socket becomes available\n */\n setSocket(socket: WebSocket | null): void {\n const wasDisconnected = !this.socket || this.socket.readyState !== WebSocket.OPEN;\n this.socket = socket;\n\n // E3: Flush offline queue when reconnecting\n if (wasDisconnected && socket?.readyState === WebSocket.OPEN) {\n this.flushOfflineQueue();\n }\n }\n\n /**\n * E3: Flush queued reports that were collected while offline\n */\n private flushOfflineQueue(): void {\n if (this.offlineQueue.length === 0) {\n return;\n }\n\n // Send all queued reports\n for (const report of this.offlineQueue) {\n this.sendReport(report);\n }\n\n this.offlineQueue = [];\n }\n\n /**\n * Get current stats object with computed getters\n * E1: Uses performance.now() for sub-millisecond precision in duration tracking\n */\n getStats(): MistReporterStats {\n const now = performance.now();\n\n return {\n nWaiting: this._stats._nWaiting,\n timeWaiting: Math.round(\n this.timeWaitingAccum + (this.waitingSince > 0 ? now - this.waitingSince : 0)\n ),\n nStalled: this._stats._nStalled,\n timeStalled: Math.round(\n this.timeStalledAccum + (this.stalledSince > 0 ? now - this.stalledSince : 0)\n ),\n timeUnpaused: Math.round(\n this.timeUnpausedAccum + (this.unpausedSince > 0 ? now - this.unpausedSince : 0)\n ),\n nError: this._stats._nError,\n lastError: this._stats.lastError,\n firstPlayback: this._stats.firstPlayback,\n playbackScore: Math.round(this._stats.playbackScore * 10) / 10,\n autoplay: this._stats.autoplay,\n videoHeight: this.videoElement?.videoHeight ?? null,\n videoWidth: this.videoElement?.videoWidth ?? null,\n playerHeight: this.containerElement?.clientHeight ?? null,\n playerWidth: this.containerElement?.clientWidth ?? null,\n tracks: this._stats.tracks,\n nLog: this.logs.length,\n };\n }\n\n /**\n * Set a stat value\n */\n set<K extends StatsKey>(key: K, value: MistReporterStats[K]): void {\n if (key === \"nWaiting\") {\n this._stats._nWaiting = value as number;\n } else if (key === \"nStalled\") {\n this._stats._nStalled = value as number;\n } else if (key === \"nError\") {\n this._stats._nError = value as number;\n } else if (key === \"lastError\") {\n this._stats.lastError = value as string | null;\n } else if (key === \"firstPlayback\") {\n this._stats.firstPlayback = value as number | null;\n } else if (key === \"playbackScore\") {\n this._stats.playbackScore = value as number;\n } else if (key === \"autoplay\") {\n this._stats.autoplay = value as \"success\" | \"muted\" | \"failed\" | null;\n } else if (key === \"tracks\") {\n this._stats.tracks = value as string | null;\n }\n // Other keys (computed) are read-only\n }\n\n /**\n * Increment a counter stat\n */\n add(key: \"nWaiting\" | \"nStalled\" | \"nError\", amount = 1): void {\n if (key === \"nWaiting\") {\n this._stats._nWaiting += amount;\n } else if (key === \"nStalled\") {\n this._stats._nStalled += amount;\n } else if (key === \"nError\") {\n this._stats._nError += amount;\n }\n }\n\n /**\n * Initialize reporting for a video element\n */\n init(videoElement: HTMLVideoElement, containerElement?: HTMLElement): void {\n this.videoElement = videoElement;\n this.containerElement = containerElement ?? videoElement.parentElement ?? null;\n this.firstPlaybackRecorded = false;\n\n // Set up event listeners like MistPlayer reference\n // E1: Use performance.now() for sub-millisecond precision in duration tracking\n const onPlaying = () => {\n const now = performance.now();\n const isFirstPlay = !this.firstPlaybackRecorded;\n\n // Record first playback time (still uses Date.now for absolute timestamp)\n if (isFirstPlay) {\n this._stats.firstPlayback = Date.now() - this.bootMs;\n this.firstPlaybackRecorded = true;\n }\n\n // End waiting state if active\n if (this.waitingSince > 0) {\n this.timeWaitingAccum += now - this.waitingSince;\n this.waitingSince = 0;\n }\n\n // End stalled state if active\n if (this.stalledSince > 0) {\n this.timeStalledAccum += now - this.stalledSince;\n this.stalledSince = 0;\n }\n\n // Start unpaused timer\n if (this.unpausedSince === 0) {\n this.unpausedSince = now;\n }\n\n // E2: Flush immediately on first playback\n if (isFirstPlay) {\n this.reportStats();\n this.flushBatch();\n }\n };\n\n const onWaiting = () => {\n this._stats._nWaiting++;\n if (this.waitingSince === 0) {\n this.waitingSince = performance.now();\n }\n };\n\n const onStalled = () => {\n this._stats._nStalled++;\n if (this.stalledSince === 0) {\n this.stalledSince = performance.now();\n }\n };\n\n const onPause = () => {\n // End unpaused timer\n if (this.unpausedSince > 0) {\n this.timeUnpausedAccum += performance.now() - this.unpausedSince;\n this.unpausedSince = 0;\n }\n };\n\n const onError = (e: Event) => {\n this._stats._nError++;\n const error = (e as ErrorEvent).message || \"Unknown error\";\n this._stats.lastError = error;\n\n // E2: Flush immediately on error\n this.reportStats();\n this.flushBatch();\n };\n\n const onCanPlay = () => {\n // End waiting state if active\n if (this.waitingSince > 0) {\n this.timeWaitingAccum += performance.now() - this.waitingSince;\n this.waitingSince = 0;\n }\n };\n\n videoElement.addEventListener(\"playing\", onPlaying);\n videoElement.addEventListener(\"waiting\", onWaiting);\n videoElement.addEventListener(\"stalled\", onStalled);\n videoElement.addEventListener(\"pause\", onPause);\n videoElement.addEventListener(\"error\", onError);\n videoElement.addEventListener(\"canplay\", onCanPlay);\n\n this.listeners = [\n () => videoElement.removeEventListener(\"playing\", onPlaying),\n () => videoElement.removeEventListener(\"waiting\", onWaiting),\n () => videoElement.removeEventListener(\"stalled\", onStalled),\n () => videoElement.removeEventListener(\"pause\", onPause),\n () => videoElement.removeEventListener(\"error\", onError),\n () => videoElement.removeEventListener(\"canplay\", onCanPlay),\n ];\n\n // Start periodic reporting\n this.startReporting();\n }\n\n /**\n * Send initial report when player is selected\n */\n sendInitialReport(info: MistReporterInitialReport): void {\n this.report(info as unknown as Record<string, unknown>);\n }\n\n /**\n * Update playback score (call from QualityMonitor)\n */\n setPlaybackScore(score: number): void {\n this._stats.playbackScore = score;\n }\n\n /**\n * Update autoplay status\n */\n setAutoplayStatus(status: \"success\" | \"muted\" | \"failed\"): void {\n this._stats.autoplay = status;\n }\n\n /**\n * Update current tracks\n */\n setTracks(tracks: string[]): void {\n this._stats.tracks = tracks.join(\",\");\n }\n\n /**\n * Send a report over WebSocket immediately\n * E3: Queues reports when socket is unavailable (up to MAX_OFFLINE_QUEUE_SIZE)\n */\n private sendReport(data: Record<string, unknown>): void {\n // If socket not available, queue for later\n if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {\n // E3: Queue report for when socket reconnects\n if (this.offlineQueue.length < MistReporter.MAX_OFFLINE_QUEUE_SIZE) {\n this.offlineQueue.push(data);\n }\n // If queue is full, oldest reports are lost (FIFO overflow)\n return;\n }\n\n try {\n this.socket.send(JSON.stringify(data));\n } catch {\n // E3: Queue on send failure too\n if (this.offlineQueue.length < MistReporter.MAX_OFFLINE_QUEUE_SIZE) {\n this.offlineQueue.push(data);\n }\n }\n }\n\n /**\n * E2: Queue data for batched reporting\n * Merges with pending batch, schedules flush if not already pending\n */\n private report(data: Record<string, unknown>): void {\n // Merge into pending batch\n Object.assign(this.pendingBatch, data);\n this.hasPendingBatch = true;\n\n // Schedule flush if not already scheduled\n if (this.batchFlushTimerId === null) {\n const now = performance.now();\n const timeSinceLastFlush = now - this.lastFlushTime;\n const delay = Math.max(0, this.batchFlushInterval - timeSinceLastFlush);\n\n this.batchFlushTimerId = this.timers.start(\n () => {\n this.batchFlushTimerId = null;\n this.flushBatch();\n },\n delay,\n \"batchFlush\"\n );\n }\n }\n\n /**\n * E2: Flush pending batch immediately\n * Used for critical events (error, first play, unload)\n */\n flushBatch(): void {\n if (this.batchFlushTimerId !== null) {\n this.timers.stop(this.batchFlushTimerId);\n this.batchFlushTimerId = null;\n }\n\n if (!this.hasPendingBatch) {\n return;\n }\n\n this.sendReport(this.pendingBatch);\n this.pendingBatch = {};\n this.hasPendingBatch = false;\n this.lastFlushTime = performance.now();\n }\n\n /**\n * Report stats delta (only changed values)\n * E2: Now queues to batch instead of sending immediately\n */\n reportStats(): void {\n const current = this.getStats();\n const delta: Record<string, unknown> = {};\n let hasChanges = false;\n\n // Compare each stat and include only changed values\n const keys: StatsKey[] = [\n \"nWaiting\",\n \"timeWaiting\",\n \"nStalled\",\n \"timeStalled\",\n \"timeUnpaused\",\n \"nError\",\n \"lastError\",\n \"firstPlayback\",\n \"playbackScore\",\n \"autoplay\",\n \"videoHeight\",\n \"videoWidth\",\n \"playerHeight\",\n \"playerWidth\",\n \"tracks\",\n \"nLog\",\n ];\n\n for (const key of keys) {\n const currentValue = current[key];\n const lastValue = this.lastReported[key];\n\n if (currentValue !== lastValue) {\n delta[key] = currentValue;\n (this.lastReported as Record<string, unknown>)[key] = currentValue;\n hasChanges = true;\n }\n }\n\n // Include logs if there are new ones\n const lastLogCount = this.lastReported.nLog ?? 0;\n if (this.logs.length > lastLogCount) {\n const newLogs = this.logs.slice(lastLogCount);\n if (newLogs.length > 0) {\n delta.logs = newLogs;\n hasChanges = true;\n }\n }\n\n if (hasChanges) {\n this.report(delta);\n }\n\n // Schedule next report\n this.scheduleNextReport();\n }\n\n /**\n * Start periodic reporting\n */\n private startReporting(): void {\n this.scheduleNextReport();\n }\n\n /**\n * Schedule the next report\n */\n private scheduleNextReport(): void {\n this.timers.start(\n () => {\n this.reportStats();\n },\n this.reportInterval,\n \"report\"\n );\n }\n\n /**\n * Send final report and cleanup\n * E2: Flushes immediately since this is a critical event\n */\n sendFinalReport(reason?: string): void {\n // Report final stats\n this.reportStats();\n\n // Queue unload report\n this.report({ unload: reason ?? null });\n\n // E2: Flush immediately - don't wait for batch interval\n this.flushBatch();\n }\n\n /**\n * Stop reporting and cleanup\n */\n destroy(): void {\n // Stop all timers\n this.timers.destroy();\n\n // Remove event listeners\n this.listeners.forEach((cleanup) => cleanup());\n this.listeners = [];\n\n this.videoElement = null;\n this.containerElement = null;\n }\n\n /**\n * Add a log entry\n */\n log(message: string): void {\n this.logs.push(message);\n }\n}\n\nexport default MistReporter;\n"],"names":[],"mappings":"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"}