@livepeer-frameworks/player-core 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/cjs/index.js +792 -146
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +792 -146
- package/dist/esm/index.js.map +1 -1
- package/dist/player.css +3 -331
- package/dist/types/core/GatewayClient.d.ts +3 -4
- package/dist/types/core/InteractionController.d.ts +12 -0
- package/dist/types/core/MetaTrackManager.d.ts +1 -1
- package/dist/types/core/PlayerController.d.ts +18 -2
- package/dist/types/core/PlayerInterface.d.ts +10 -0
- package/dist/types/core/SeekingUtils.d.ts +3 -1
- package/dist/types/core/StreamStateClient.d.ts +1 -1
- package/dist/types/players/HlsJsPlayer.d.ts +8 -0
- package/dist/types/players/MewsWsPlayer/index.d.ts +1 -1
- package/dist/types/players/VideoJsPlayer.d.ts +12 -4
- package/dist/types/players/WebCodecsPlayer/SyncController.d.ts +1 -1
- package/dist/types/players/WebCodecsPlayer/index.d.ts +11 -0
- package/dist/types/players/WebCodecsPlayer/types.d.ts +25 -3
- package/dist/types/players/WebCodecsPlayer/worker/types.d.ts +20 -2
- package/dist/types/types.d.ts +32 -1
- package/dist/types/vanilla/FrameWorksPlayer.d.ts +5 -5
- package/dist/types/vanilla/index.d.ts +3 -3
- package/dist/workers/decoder.worker.js +183 -6
- package/dist/workers/decoder.worker.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ABRController.ts +1 -1
- package/src/core/CodecUtils.ts +1 -1
- package/src/core/GatewayClient.ts +8 -10
- package/src/core/LiveDurationProxy.ts +0 -1
- package/src/core/MetaTrackManager.ts +1 -1
- package/src/core/PlayerController.ts +232 -26
- package/src/core/PlayerInterface.ts +6 -0
- package/src/core/PlayerManager.ts +49 -0
- package/src/core/StreamStateClient.ts +3 -3
- package/src/core/SubtitleManager.ts +1 -1
- package/src/core/TelemetryReporter.ts +1 -1
- package/src/core/TimerManager.ts +1 -1
- package/src/core/scorer.ts +8 -4
- package/src/players/DashJsPlayer.ts +23 -11
- package/src/players/HlsJsPlayer.ts +29 -5
- package/src/players/MewsWsPlayer/SourceBufferManager.ts +3 -3
- package/src/players/MewsWsPlayer/WebSocketManager.ts +0 -1
- package/src/players/MewsWsPlayer/index.ts +7 -5
- package/src/players/MistPlayer.ts +1 -1
- package/src/players/MistWebRTCPlayer/index.ts +1 -1
- package/src/players/NativePlayer.ts +2 -2
- package/src/players/VideoJsPlayer.ts +33 -31
- package/src/players/WebCodecsPlayer/SyncController.ts +1 -2
- package/src/players/WebCodecsPlayer/WebSocketController.ts +1 -1
- package/src/players/WebCodecsPlayer/index.ts +25 -7
- package/src/players/WebCodecsPlayer/types.ts +31 -3
- package/src/players/WebCodecsPlayer/worker/decoder.worker.ts +20 -13
- package/src/players/WebCodecsPlayer/worker/types.ts +4 -0
- package/src/styles/player.css +0 -314
- package/src/types.ts +43 -1
- package/src/vanilla/FrameWorksPlayer.ts +5 -5
- package/src/vanilla/index.ts +3 -3
package/dist/player.css
CHANGED
|
@@ -252,284 +252,6 @@
|
|
|
252
252
|
-webkit-user-select: none;
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
/* =====================================================
|
|
256
|
-
UTILITY CLASSES - All utilities needed by components
|
|
257
|
-
===================================================== */
|
|
258
|
-
|
|
259
|
-
/* Layout */
|
|
260
|
-
.flex { display: flex; }
|
|
261
|
-
.inline-flex { display: inline-flex; }
|
|
262
|
-
.hidden { display: none; }
|
|
263
|
-
.block { display: block; }
|
|
264
|
-
.relative { position: relative; }
|
|
265
|
-
.absolute { position: absolute; }
|
|
266
|
-
.fixed { position: fixed; }
|
|
267
|
-
|
|
268
|
-
/* Flex utilities */
|
|
269
|
-
.flex-col { flex-direction: column; }
|
|
270
|
-
.flex-row { flex-direction: row; }
|
|
271
|
-
.flex-wrap { flex-wrap: wrap; }
|
|
272
|
-
.flex-1 { flex: 1 1 0%; }
|
|
273
|
-
.flex-shrink { flex-shrink: 1; }
|
|
274
|
-
.flex-shrink-0 { flex-shrink: 0; }
|
|
275
|
-
.items-center { align-items: center; }
|
|
276
|
-
.items-start { align-items: flex-start; }
|
|
277
|
-
.items-end { align-items: flex-end; }
|
|
278
|
-
.justify-center { justify-content: center; }
|
|
279
|
-
.justify-between { justify-content: space-between; }
|
|
280
|
-
.justify-end { justify-content: flex-end; }
|
|
281
|
-
|
|
282
|
-
/* Positioning */
|
|
283
|
-
.inset-0 { inset: 0; }
|
|
284
|
-
.inset-x-0 { left: 0; right: 0; }
|
|
285
|
-
.inset-y-0 { top: 0; bottom: 0; }
|
|
286
|
-
.top-0 { top: 0; }
|
|
287
|
-
.top-2 { top: 0.5rem; }
|
|
288
|
-
.top-3 { top: 0.75rem; }
|
|
289
|
-
.right-0 { right: 0; }
|
|
290
|
-
.right-2 { right: 0.5rem; }
|
|
291
|
-
.right-3 { right: 0.75rem; }
|
|
292
|
-
.bottom-0 { bottom: 0; }
|
|
293
|
-
.bottom-2 { bottom: 0.5rem; }
|
|
294
|
-
.left-0 { left: 0; }
|
|
295
|
-
.left-2 { left: 0.5rem; }
|
|
296
|
-
.left-3 { left: 0.75rem; }
|
|
297
|
-
|
|
298
|
-
/* Z-index */
|
|
299
|
-
.z-10 { z-index: 10; }
|
|
300
|
-
.z-20 { z-index: 20; }
|
|
301
|
-
.z-30 { z-index: 30; }
|
|
302
|
-
.z-50 { z-index: 50; }
|
|
303
|
-
|
|
304
|
-
/* Sizing */
|
|
305
|
-
.w-0 { width: 0; }
|
|
306
|
-
.w-2 { width: 0.5rem; }
|
|
307
|
-
.w-2\.5 { width: 0.625rem; }
|
|
308
|
-
.w-4 { width: 1rem; }
|
|
309
|
-
.w-5 { width: 1.25rem; }
|
|
310
|
-
.w-6 { width: 1.5rem; }
|
|
311
|
-
.w-8 { width: 2rem; }
|
|
312
|
-
.w-10 { width: 2.5rem; }
|
|
313
|
-
.w-12 { width: 3rem; }
|
|
314
|
-
.w-24 { width: 6rem; }
|
|
315
|
-
.w-28 { width: 7rem; }
|
|
316
|
-
.w-48 { width: 12rem; }
|
|
317
|
-
.w-full { width: 100%; }
|
|
318
|
-
.h-1 { height: 0.25rem; }
|
|
319
|
-
.h-1\.5 { height: 0.375rem; }
|
|
320
|
-
.h-2 { height: 0.5rem; }
|
|
321
|
-
.h-2\.5 { height: 0.625rem; }
|
|
322
|
-
.h-4 { height: 1rem; }
|
|
323
|
-
.h-5 { height: 1.25rem; }
|
|
324
|
-
.h-6 { height: 1.5rem; }
|
|
325
|
-
.h-8 { height: 2rem; }
|
|
326
|
-
.h-10 { height: 2.5rem; }
|
|
327
|
-
.h-12 { height: 3rem; }
|
|
328
|
-
.h-full { height: 100%; }
|
|
329
|
-
.min-w-0 { min-width: 0; }
|
|
330
|
-
.min-w-\[280px\] { min-width: 280px; }
|
|
331
|
-
.max-w-xs { max-width: 20rem; }
|
|
332
|
-
.max-w-sm { max-width: 24rem; }
|
|
333
|
-
.max-w-md { max-width: 28rem; }
|
|
334
|
-
.max-h-32 { max-height: 8rem; }
|
|
335
|
-
.max-h-\[80\%\] { max-height: 80%; }
|
|
336
|
-
.max-w-\[320px\] { max-width: 320px; }
|
|
337
|
-
|
|
338
|
-
/* Spacing */
|
|
339
|
-
.gap-0\.5 { gap: 0.125rem; }
|
|
340
|
-
.gap-1 { gap: 0.25rem; }
|
|
341
|
-
.gap-2 { gap: 0.5rem; }
|
|
342
|
-
.gap-3 { gap: 0.75rem; }
|
|
343
|
-
.gap-4 { gap: 1rem; }
|
|
344
|
-
.space-x-1 > * + * { margin-left: 0.25rem; }
|
|
345
|
-
.space-x-2 > * + * { margin-left: 0.5rem; }
|
|
346
|
-
.space-y-1 > * + * { margin-top: 0.25rem; }
|
|
347
|
-
.p-1 { padding: 0.25rem; }
|
|
348
|
-
.p-2 { padding: 0.5rem; }
|
|
349
|
-
.p-3 { padding: 0.75rem; }
|
|
350
|
-
.p-4 { padding: 1rem; }
|
|
351
|
-
.px-1 { padding-left: 0.25rem; padding-right: 0.25rem; }
|
|
352
|
-
.px-1\.5 { padding-left: 0.375rem; padding-right: 0.375rem; }
|
|
353
|
-
.px-2 { padding-left: 0.5rem; padding-right: 0.5rem; }
|
|
354
|
-
.px-3 { padding-left: 0.75rem; padding-right: 0.75rem; }
|
|
355
|
-
.px-4 { padding-left: 1rem; padding-right: 1rem; }
|
|
356
|
-
.py-0\.5 { padding-top: 0.125rem; padding-bottom: 0.125rem; }
|
|
357
|
-
.py-1 { padding-top: 0.25rem; padding-bottom: 0.25rem; }
|
|
358
|
-
.py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
|
|
359
|
-
.py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; }
|
|
360
|
-
.pr-2 { padding-right: 0.5rem; }
|
|
361
|
-
.pr-5 { padding-right: 1.25rem; }
|
|
362
|
-
.m-0 { margin: 0; }
|
|
363
|
-
.mx-auto { margin-left: auto; margin-right: auto; }
|
|
364
|
-
.mt-1 { margin-top: 0.25rem; }
|
|
365
|
-
.mt-2 { margin-top: 0.5rem; }
|
|
366
|
-
.mb-1 { margin-bottom: 0.25rem; }
|
|
367
|
-
.mb-2 { margin-bottom: 0.5rem; }
|
|
368
|
-
.-mb-1 { margin-bottom: -0.25rem; }
|
|
369
|
-
.-ml-4 { margin-left: -1rem; }
|
|
370
|
-
.ml-0\.5 { margin-left: 0.125rem; }
|
|
371
|
-
|
|
372
|
-
/* Typography */
|
|
373
|
-
.text-\[10px\] { font-size: 10px; }
|
|
374
|
-
.text-\[11px\] { font-size: 11px; }
|
|
375
|
-
.text-xs { font-size: 0.75rem; line-height: 1rem; }
|
|
376
|
-
.text-sm { font-size: 0.875rem; line-height: 1.25rem; }
|
|
377
|
-
.text-base { font-size: 1rem; line-height: 1.5rem; }
|
|
378
|
-
.text-center { text-align: center; }
|
|
379
|
-
.text-left { text-align: left; }
|
|
380
|
-
.text-right { text-align: right; }
|
|
381
|
-
.font-medium { font-weight: 500; }
|
|
382
|
-
.font-semibold { font-weight: 600; }
|
|
383
|
-
.font-bold { font-weight: 700; }
|
|
384
|
-
.font-mono { font-family: ui-monospace, monospace; }
|
|
385
|
-
.uppercase { text-transform: uppercase; }
|
|
386
|
-
.leading-none { line-height: 1; }
|
|
387
|
-
.tracking-wide { letter-spacing: 0.025em; }
|
|
388
|
-
.tracking-wider { letter-spacing: 0.05em; }
|
|
389
|
-
.whitespace-nowrap { white-space: nowrap; }
|
|
390
|
-
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
391
|
-
|
|
392
|
-
/* Colors - Generic */
|
|
393
|
-
.text-white { color: white; }
|
|
394
|
-
.text-white\/50 { color: rgb(255 255 255 / 0.5); }
|
|
395
|
-
.text-white\/60 { color: rgb(255 255 255 / 0.6); }
|
|
396
|
-
.text-white\/70 { color: rgb(255 255 255 / 0.7); }
|
|
397
|
-
.text-white\/80 { color: rgb(255 255 255 / 0.8); }
|
|
398
|
-
.text-white\/90 { color: rgb(255 255 255 / 0.9); }
|
|
399
|
-
.bg-transparent { background-color: transparent; }
|
|
400
|
-
.bg-black { background-color: black; }
|
|
401
|
-
.bg-black\/40 { background-color: rgb(0 0 0 / 0.4); }
|
|
402
|
-
.bg-black\/50 { background-color: rgb(0 0 0 / 0.5); }
|
|
403
|
-
.bg-black\/60 { background-color: rgb(0 0 0 / 0.6); }
|
|
404
|
-
.bg-black\/70 { background-color: rgb(0 0 0 / 0.7); }
|
|
405
|
-
.bg-black\/80 { background-color: rgb(0 0 0 / 0.8); }
|
|
406
|
-
.bg-black\/90 { background-color: rgb(0 0 0 / 0.9); }
|
|
407
|
-
.bg-white { background-color: white; }
|
|
408
|
-
.bg-white\/5 { background-color: rgb(255 255 255 / 0.05); }
|
|
409
|
-
.bg-white\/10 { background-color: rgb(255 255 255 / 0.1); }
|
|
410
|
-
.bg-white\/20 { background-color: rgb(255 255 255 / 0.2); }
|
|
411
|
-
.bg-white\/30 { background-color: rgb(255 255 255 / 0.3); }
|
|
412
|
-
.bg-white\/50 { background-color: rgb(255 255 255 / 0.5); }
|
|
413
|
-
.border-white\/10 { border-color: rgb(255 255 255 / 0.1); }
|
|
414
|
-
|
|
415
|
-
/* Colors - Tokyo Night */
|
|
416
|
-
.bg-tn-bg-dark { background-color: hsl(var(--tn-bg-dark)); }
|
|
417
|
-
.bg-tn-bg { background-color: hsl(var(--tn-bg)); }
|
|
418
|
-
.bg-tn-bg-highlight { background-color: hsl(var(--tn-bg-highlight)); }
|
|
419
|
-
.bg-tn-bg-visual { background-color: hsl(var(--tn-bg-visual)); }
|
|
420
|
-
.text-tn-fg { color: hsl(var(--tn-fg)); }
|
|
421
|
-
.text-tn-fg-dark { color: hsl(var(--tn-fg-dark)); }
|
|
422
|
-
.text-tn-blue { color: hsl(var(--tn-blue)); }
|
|
423
|
-
.text-tn-bg-dark { color: hsl(var(--tn-bg-dark)); }
|
|
424
|
-
.text-tn-accent { color: hsl(var(--tn-bg-visual)); }
|
|
425
|
-
.bg-tn-blue { background-color: hsl(var(--tn-blue)); }
|
|
426
|
-
.bg-tn-blue\/20 { background-color: hsl(var(--tn-blue) / 0.2); }
|
|
427
|
-
.bg-tn-accent { background-color: hsl(var(--tn-bg-visual)); }
|
|
428
|
-
.border-tn-seam { border-color: hsl(var(--tn-fg-gutter) / 0.3); }
|
|
429
|
-
.bg-tn-seam { background-color: hsl(var(--tn-fg-gutter) / 0.3); }
|
|
430
|
-
|
|
431
|
-
/* Colors - Semantic */
|
|
432
|
-
.bg-red-500\/10 { background-color: rgb(239 68 68 / 0.1); }
|
|
433
|
-
.bg-red-600 { background-color: rgb(220 38 38); }
|
|
434
|
-
.bg-yellow-500\/10 { background-color: rgb(234 179 8 / 0.1); }
|
|
435
|
-
.text-red-400 { color: rgb(248 113 113); }
|
|
436
|
-
.text-yellow-400 { color: rgb(250 204 21); }
|
|
437
|
-
|
|
438
|
-
/* Special button colors from component */
|
|
439
|
-
.bg-\[\#414868\] { background-color: #414868; }
|
|
440
|
-
.text-\[\#a9b1d6\] { color: #a9b1d6; }
|
|
441
|
-
.bg-\[hsl\(var\(--tn-fg-dark\)\)\] { background-color: hsl(var(--tn-fg-dark)); }
|
|
442
|
-
.text-\[hsl\(var\(--tn-fg-dark\)\)\] { color: hsl(var(--tn-fg-dark)); }
|
|
443
|
-
.bg-\[hsl\(var\(--tn-accent\)\)\] { color: hsl(var(--tn-accent)); }
|
|
444
|
-
.text-\[hsl\(var\(--tn-accent\)\)\] { color: hsl(var(--tn-accent)); }
|
|
445
|
-
|
|
446
|
-
/* Borders & Rounded */
|
|
447
|
-
.border { border-width: 1px; }
|
|
448
|
-
.border-b { border-bottom-width: 1px; }
|
|
449
|
-
.border-t { border-top-width: 1px; }
|
|
450
|
-
.border-l { border-left-width: 1px; }
|
|
451
|
-
.rounded { border-radius: 0.25rem; }
|
|
452
|
-
.rounded-md { border-radius: 0.375rem; }
|
|
453
|
-
.rounded-lg { border-radius: 0.5rem; }
|
|
454
|
-
.rounded-full { border-radius: 9999px; }
|
|
455
|
-
|
|
456
|
-
/* Effects */
|
|
457
|
-
.shadow-lg { box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); }
|
|
458
|
-
.backdrop-blur-sm { backdrop-filter: blur(4px); }
|
|
459
|
-
|
|
460
|
-
/* Opacity */
|
|
461
|
-
.opacity-0 { opacity: 0; }
|
|
462
|
-
.opacity-40 { opacity: 0.4; }
|
|
463
|
-
.opacity-50 { opacity: 0.5; }
|
|
464
|
-
.opacity-70 { opacity: 0.7; }
|
|
465
|
-
.opacity-100 { opacity: 1; }
|
|
466
|
-
|
|
467
|
-
/* Transitions */
|
|
468
|
-
.transition {
|
|
469
|
-
transition-property: color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, width;
|
|
470
|
-
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
471
|
-
transition-duration: 150ms;
|
|
472
|
-
}
|
|
473
|
-
.transition-all {
|
|
474
|
-
transition-property: all;
|
|
475
|
-
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
476
|
-
transition-duration: 150ms;
|
|
477
|
-
}
|
|
478
|
-
.transition-opacity {
|
|
479
|
-
transition-property: opacity;
|
|
480
|
-
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
481
|
-
transition-duration: 150ms;
|
|
482
|
-
}
|
|
483
|
-
.transition-colors {
|
|
484
|
-
transition-property: color, background-color, border-color, fill, stroke;
|
|
485
|
-
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
486
|
-
transition-duration: 150ms;
|
|
487
|
-
}
|
|
488
|
-
.transition-transform {
|
|
489
|
-
transition-property: transform;
|
|
490
|
-
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
491
|
-
transition-duration: 150ms;
|
|
492
|
-
}
|
|
493
|
-
.duration-200 { transition-duration: 200ms; }
|
|
494
|
-
.ease-out { transition-timing-function: cubic-bezier(0, 0, 0.2, 1); }
|
|
495
|
-
|
|
496
|
-
/* Interactive */
|
|
497
|
-
.cursor-pointer { cursor: pointer; }
|
|
498
|
-
.cursor-default { cursor: default; }
|
|
499
|
-
.cursor-not-allowed { cursor: not-allowed; }
|
|
500
|
-
.select-none { user-select: none; }
|
|
501
|
-
.touch-none { touch-action: none; }
|
|
502
|
-
.pointer-events-none { pointer-events: none; }
|
|
503
|
-
.pointer-events-auto { pointer-events: auto; }
|
|
504
|
-
|
|
505
|
-
/* Overflow */
|
|
506
|
-
.overflow-hidden { overflow: hidden; }
|
|
507
|
-
.overflow-auto { overflow: auto; }
|
|
508
|
-
.overflow-y-auto { overflow-y: auto; }
|
|
509
|
-
|
|
510
|
-
/* =====================================================
|
|
511
|
-
HOVER & FOCUS STATES
|
|
512
|
-
===================================================== */
|
|
513
|
-
.hover\:text-white:hover { color: white; }
|
|
514
|
-
.hover\:bg-white\/5:hover { background-color: rgb(255 255 255 / 0.05); }
|
|
515
|
-
.hover\:bg-white\/10:hover { background-color: rgb(255 255 255 / 0.1); }
|
|
516
|
-
.hover\:bg-tn-bg-highlight:hover { background-color: hsl(var(--tn-bg-highlight)); }
|
|
517
|
-
.hover\:bg-tn-bg-visual:hover { background-color: hsl(var(--tn-bg-visual)); }
|
|
518
|
-
.hover\:bg-red-600:hover { background-color: rgb(220 38 38); }
|
|
519
|
-
.focus\:bg-tn-bg-visual:focus { background-color: hsl(var(--tn-bg-visual)); }
|
|
520
|
-
.focus\:text-white:focus { color: white; }
|
|
521
|
-
|
|
522
|
-
/* Group hover states */
|
|
523
|
-
.group:hover .group-hover\:rotate-90 { transform: rotate(90deg); }
|
|
524
|
-
.group:hover .group-hover\:h-1\.5 { height: 0.375rem; }
|
|
525
|
-
|
|
526
|
-
/* =====================================================
|
|
527
|
-
RESPONSIVE - sm: breakpoint (640px)
|
|
528
|
-
===================================================== */
|
|
529
|
-
@media (min-width: 640px) {
|
|
530
|
-
.sm\:flex { display: flex; }
|
|
531
|
-
}
|
|
532
|
-
|
|
533
255
|
/* =====================================================
|
|
534
256
|
VIDEO.JS CONTAINER CONSTRAINTS
|
|
535
257
|
===================================================== */
|
|
@@ -795,18 +517,6 @@
|
|
|
795
517
|
color: white;
|
|
796
518
|
}
|
|
797
519
|
|
|
798
|
-
.fw-live-badge--nodvr {
|
|
799
|
-
background: #2c2f45;
|
|
800
|
-
color: #c0c7e6;
|
|
801
|
-
cursor: default;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
.fw-live-badge__nodvr {
|
|
805
|
-
font-size: 9px;
|
|
806
|
-
font-weight: 600;
|
|
807
|
-
letter-spacing: 0.04em;
|
|
808
|
-
opacity: 0.85;
|
|
809
|
-
}
|
|
810
520
|
|
|
811
521
|
/* --- Volume Control --- */
|
|
812
522
|
.fw-volume-group {
|
|
@@ -1134,11 +844,9 @@
|
|
|
1134
844
|
|
|
1135
845
|
/* --- Speed Indicator --- */
|
|
1136
846
|
.fw-speed-indicator {
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
background: hsl(var(--tn-bg-dark) / 0.6);
|
|
1141
|
-
backdrop-filter: blur(4px);
|
|
847
|
+
pointer-events: none;
|
|
848
|
+
background: none;
|
|
849
|
+
backdrop-filter: none;
|
|
1142
850
|
}
|
|
1143
851
|
|
|
1144
852
|
/* --- Skip Indicator --- */
|
|
@@ -1332,42 +1040,6 @@
|
|
|
1332
1040
|
DEV MODE PANEL (Advanced settings sidebar)
|
|
1333
1041
|
===================================================== */
|
|
1334
1042
|
|
|
1335
|
-
/* Toggle button - small icon button in corner */
|
|
1336
|
-
.fw-dev-toggle {
|
|
1337
|
-
position: absolute;
|
|
1338
|
-
bottom: 3.5rem;
|
|
1339
|
-
right: 0.5rem;
|
|
1340
|
-
z-index: 40;
|
|
1341
|
-
width: 2rem;
|
|
1342
|
-
height: 2rem;
|
|
1343
|
-
display: flex;
|
|
1344
|
-
align-items: center;
|
|
1345
|
-
justify-content: center;
|
|
1346
|
-
padding: 0;
|
|
1347
|
-
border-radius: 0.375rem;
|
|
1348
|
-
background: hsl(var(--tn-bg-dark));
|
|
1349
|
-
border: 1px solid hsl(var(--tn-fg-gutter) / 0.5);
|
|
1350
|
-
color: hsl(var(--tn-fg-dark));
|
|
1351
|
-
cursor: pointer;
|
|
1352
|
-
transition: background-color 0.15s, color 0.15s, border-color 0.15s, opacity 0.2s;
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
.fw-dev-toggle:hover {
|
|
1356
|
-
background: hsl(var(--tn-bg-highlight));
|
|
1357
|
-
border-color: hsl(var(--tn-fg-gutter));
|
|
1358
|
-
color: hsl(var(--tn-fg));
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
.fw-dev-toggle--visible {
|
|
1362
|
-
opacity: 1;
|
|
1363
|
-
pointer-events: auto;
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
.fw-dev-toggle--hidden {
|
|
1367
|
-
opacity: 0;
|
|
1368
|
-
pointer-events: none;
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
1043
|
/* Main panel - side panel container */
|
|
1372
1044
|
.fw-dev-panel {
|
|
1373
1045
|
z-index: 40;
|
|
@@ -10,10 +10,10 @@ export type GatewayStatus = 'idle' | 'loading' | 'ready' | 'error';
|
|
|
10
10
|
export interface GatewayClientConfig {
|
|
11
11
|
/** Gateway GraphQL endpoint URL */
|
|
12
12
|
gatewayUrl: string;
|
|
13
|
-
/** Content type to resolve */
|
|
14
|
-
contentType: ContentType;
|
|
15
13
|
/** Content identifier (stream name) */
|
|
16
14
|
contentId: string;
|
|
15
|
+
/** Optional content type (no longer required for resolution) */
|
|
16
|
+
contentType?: ContentType;
|
|
17
17
|
/** Optional auth token for private streams */
|
|
18
18
|
authToken?: string;
|
|
19
19
|
/** Maximum retry attempts (default: 3) */
|
|
@@ -40,8 +40,7 @@ type CircuitBreakerState = 'closed' | 'open' | 'half-open';
|
|
|
40
40
|
* ```typescript
|
|
41
41
|
* const client = new GatewayClient({
|
|
42
42
|
* gatewayUrl: 'https://gateway.example.com/graphql',
|
|
43
|
-
*
|
|
44
|
-
* contentId: 'my-stream',
|
|
43
|
+
* contentId: 'pk_...', // playbackId (view key)
|
|
45
44
|
* });
|
|
46
45
|
*
|
|
47
46
|
* client.on('statusChange', ({ status }) => console.log('Status:', status));
|
|
@@ -12,6 +12,7 @@ export interface InteractionControllerConfig {
|
|
|
12
12
|
container: HTMLElement;
|
|
13
13
|
videoElement: HTMLVideoElement;
|
|
14
14
|
isLive: boolean;
|
|
15
|
+
isPaused?: () => boolean;
|
|
15
16
|
onPlayPause: () => void;
|
|
16
17
|
onSeek: (delta: number) => void;
|
|
17
18
|
onVolumeChange: (delta: number) => void;
|
|
@@ -21,7 +22,11 @@ export interface InteractionControllerConfig {
|
|
|
21
22
|
onLoopToggle?: () => void;
|
|
22
23
|
onSpeedChange: (speed: number, isHolding: boolean) => void;
|
|
23
24
|
onSeekPercent?: (percent: number) => void;
|
|
25
|
+
/** Optional: player-specific frame stepping (return true if handled) */
|
|
26
|
+
onFrameStep?: (direction: -1 | 1, seconds: number) => boolean | void;
|
|
24
27
|
speedHoldValue?: number;
|
|
28
|
+
/** Frame step duration in seconds (for prev/next frame shortcuts) */
|
|
29
|
+
frameStepSeconds?: number;
|
|
25
30
|
/** Idle timeout in ms (default 5000). Set to 0 to disable. */
|
|
26
31
|
idleTimeout?: number;
|
|
27
32
|
/** Callback fired when user becomes idle */
|
|
@@ -58,6 +63,9 @@ export declare class InteractionController {
|
|
|
58
63
|
private boundPointerCancel;
|
|
59
64
|
private boundContextMenu;
|
|
60
65
|
private boundMouseMove;
|
|
66
|
+
private boundDoubleClick;
|
|
67
|
+
private boundDocumentKeyDown;
|
|
68
|
+
private boundDocumentKeyUp;
|
|
61
69
|
constructor(config: InteractionControllerConfig);
|
|
62
70
|
/**
|
|
63
71
|
* Attach event listeners to container
|
|
@@ -85,8 +93,11 @@ export declare class InteractionController {
|
|
|
85
93
|
updateConfig(updates: Partial<InteractionControllerConfig>): void;
|
|
86
94
|
private handleKeyDown;
|
|
87
95
|
private handleKeyUp;
|
|
96
|
+
private shouldHandleKeyboard;
|
|
88
97
|
private handleSpaceDown;
|
|
89
98
|
private handleSpaceUp;
|
|
99
|
+
private handleDoubleClick;
|
|
100
|
+
private stepFrame;
|
|
90
101
|
private handlePointerDown;
|
|
91
102
|
private handlePointerUp;
|
|
92
103
|
private handlePointerCancel;
|
|
@@ -118,4 +129,5 @@ export declare class InteractionController {
|
|
|
118
129
|
resumeIdleTracking(): void;
|
|
119
130
|
private isInputElement;
|
|
120
131
|
private isControlElement;
|
|
132
|
+
private getFrameStepSeconds;
|
|
121
133
|
}
|
|
@@ -40,7 +40,7 @@ type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecti
|
|
|
40
40
|
* ```ts
|
|
41
41
|
* const manager = new MetaTrackManager({
|
|
42
42
|
* mistBaseUrl: 'https://mist.example.com',
|
|
43
|
-
* streamName: '
|
|
43
|
+
* streamName: 'pk_...', // playbackId (view key)
|
|
44
44
|
* });
|
|
45
45
|
*
|
|
46
46
|
* manager.subscribe('1', (event) => {
|
|
@@ -17,7 +17,7 @@ export interface PlayerControllerConfig {
|
|
|
17
17
|
/** Content identifier (stream name) */
|
|
18
18
|
contentId: string;
|
|
19
19
|
/** Content type */
|
|
20
|
-
contentType
|
|
20
|
+
contentType?: ContentType;
|
|
21
21
|
/** Pre-resolved endpoints (skip gateway) */
|
|
22
22
|
endpoints?: ContentEndpoints;
|
|
23
23
|
/** Gateway URL (for FrameWorks Gateway resolution) */
|
|
@@ -219,7 +219,7 @@ export declare function buildStreamInfoFromEndpoints(endpoints: ContentEndpoints
|
|
|
219
219
|
* @example
|
|
220
220
|
* ```typescript
|
|
221
221
|
* const controller = new PlayerController({
|
|
222
|
-
* contentId: '
|
|
222
|
+
* contentId: 'pk_...', // playbackId (view key)
|
|
223
223
|
* contentType: 'live',
|
|
224
224
|
* gatewayUrl: 'https://gateway.example.com/graphql',
|
|
225
225
|
* });
|
|
@@ -238,6 +238,7 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
|
|
|
238
238
|
private config;
|
|
239
239
|
private state;
|
|
240
240
|
private lastEmittedState;
|
|
241
|
+
private suppressPlayPauseEventsUntil;
|
|
241
242
|
private gatewayClient;
|
|
242
243
|
private streamStateClient;
|
|
243
244
|
private playerManager;
|
|
@@ -249,6 +250,10 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
|
|
|
249
250
|
private streamState;
|
|
250
251
|
/** Tracks parsed from MistServer JSON response (used for direct MistServer mode) */
|
|
251
252
|
private mistTracks;
|
|
253
|
+
/** Gateway-seeded metadata (used as base for Mist enrichment) */
|
|
254
|
+
private metadataSeed;
|
|
255
|
+
/** Merged metadata (gateway seed + Mist enrichment) */
|
|
256
|
+
private metadata;
|
|
252
257
|
private cleanupFns;
|
|
253
258
|
private isDestroyed;
|
|
254
259
|
private isAttached;
|
|
@@ -319,6 +324,10 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
|
|
|
319
324
|
getEndpoints(): ContentEndpoints | null;
|
|
320
325
|
/** Get content metadata (title, description, duration, etc.) */
|
|
321
326
|
getMetadata(): ContentMetadata | null;
|
|
327
|
+
private setMetadataSeed;
|
|
328
|
+
private refreshMergedMetadata;
|
|
329
|
+
private buildMetadataTracks;
|
|
330
|
+
private sanitizeMistInfo;
|
|
322
331
|
/** Get stream info (sources + tracks for player selection) */
|
|
323
332
|
getStreamInfo(): StreamInfo | null;
|
|
324
333
|
/** Get video element (null if not ready) */
|
|
@@ -381,6 +390,8 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
|
|
|
381
390
|
hasAudioTrack(): boolean;
|
|
382
391
|
/** Check if playback rate adjustment is supported */
|
|
383
392
|
canAdjustPlaybackRate(): boolean;
|
|
393
|
+
/** Resolve content type from config override or Gateway metadata */
|
|
394
|
+
private getResolvedContentType;
|
|
384
395
|
/** Check if source is WebRTC/MediaStream */
|
|
385
396
|
isWebRTCSource(): boolean;
|
|
386
397
|
/** Check if currently in fullscreen mode */
|
|
@@ -494,6 +505,7 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
|
|
|
494
505
|
private getEffectiveCurrentTime;
|
|
495
506
|
private getEffectiveDuration;
|
|
496
507
|
private getPlayerSeekableRange;
|
|
508
|
+
private getFrameStepSecondsFromTracks;
|
|
497
509
|
private deriveBufferWindowMsFromTracks;
|
|
498
510
|
/** Get current time */
|
|
499
511
|
getCurrentTime(): number;
|
|
@@ -501,6 +513,10 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
|
|
|
501
513
|
getDuration(): number;
|
|
502
514
|
/** Check if paused */
|
|
503
515
|
isPaused(): boolean;
|
|
516
|
+
/** Suppress play/pause-driven UI updates for a short window */
|
|
517
|
+
suppressPlayPauseEvents(ms?: number): void;
|
|
518
|
+
/** Check if play/pause UI updates should be suppressed */
|
|
519
|
+
shouldSuppressVideoEvents(): boolean;
|
|
504
520
|
/** Check if muted */
|
|
505
521
|
isMuted(): boolean;
|
|
506
522
|
/** Skip backward by specified seconds (default 10) */
|
|
@@ -42,6 +42,8 @@ export interface PlayerOptions {
|
|
|
42
42
|
height?: number;
|
|
43
43
|
/** Enable dev mode - for Legacy player, uses MistServer's dev skin with source selection */
|
|
44
44
|
devMode?: boolean;
|
|
45
|
+
/** Enable debug logging in player implementations */
|
|
46
|
+
debug?: boolean;
|
|
45
47
|
onReady?: (element: HTMLVideoElement) => void;
|
|
46
48
|
onError?: (error: string | Error) => void;
|
|
47
49
|
onPlay?: () => void;
|
|
@@ -52,6 +54,12 @@ export interface PlayerOptions {
|
|
|
52
54
|
onPlaying?: () => void;
|
|
53
55
|
onCanPlay?: () => void;
|
|
54
56
|
onDurationChange?: (duration: number) => void;
|
|
57
|
+
/** HLS.js configuration override (merged with defaults) */
|
|
58
|
+
hlsConfig?: Record<string, unknown>;
|
|
59
|
+
/** DASH.js configuration override (merged with defaults) */
|
|
60
|
+
dashConfig?: Record<string, unknown>;
|
|
61
|
+
/** Video.js VHS configuration override (merged with defaults) */
|
|
62
|
+
vhsConfig?: Record<string, unknown>;
|
|
55
63
|
}
|
|
56
64
|
export interface PlayerCapability {
|
|
57
65
|
/** Player name for display */
|
|
@@ -173,6 +181,8 @@ export interface IPlayer {
|
|
|
173
181
|
getCurrentQuality?(): string | null;
|
|
174
182
|
isLive?(): boolean;
|
|
175
183
|
jumpToLive?(): void;
|
|
184
|
+
/** Optional: frame step (direction -1/1, optional step seconds) */
|
|
185
|
+
frameStep?(direction: -1 | 1, seconds?: number): void;
|
|
176
186
|
requestPiP?(): Promise<void>;
|
|
177
187
|
/**
|
|
178
188
|
* Optional: Retrieve player-specific stats (e.g., WebRTC inbound-rtp)
|
|
@@ -30,6 +30,8 @@ export interface SeekableRangeParams {
|
|
|
30
30
|
mistStreamInfo?: MistStreamInfo;
|
|
31
31
|
currentTime: number;
|
|
32
32
|
duration: number;
|
|
33
|
+
/** Allow Mist track metadata for MediaStream sources (e.g., WebCodecs DVR) */
|
|
34
|
+
allowMediaStreamDvr?: boolean;
|
|
33
35
|
}
|
|
34
36
|
export interface CanSeekParams {
|
|
35
37
|
video: HTMLVideoElement | null;
|
|
@@ -87,7 +89,7 @@ export declare function supportsPlaybackRate(video: HTMLVideoElement | null): bo
|
|
|
87
89
|
* 1. Browser's video.seekable ranges (most accurate for MSE-based players)
|
|
88
90
|
* 2. Track firstms/lastms from MistServer metadata
|
|
89
91
|
* 3. buffer_window from MistServer signaling
|
|
90
|
-
* 4.
|
|
92
|
+
* 4. No fallback (treat as live-only when no reliable data)
|
|
91
93
|
*
|
|
92
94
|
* @param params - Calculation parameters
|
|
93
95
|
* @returns Seekable range with start and live edge
|
|
@@ -37,7 +37,7 @@ export interface StreamStateClientEvents {
|
|
|
37
37
|
* ```typescript
|
|
38
38
|
* const client = new StreamStateClient({
|
|
39
39
|
* mistBaseUrl: 'https://mist.example.com',
|
|
40
|
-
* streamName: '
|
|
40
|
+
* streamName: 'pk_...', // playbackId (view key)
|
|
41
41
|
* });
|
|
42
42
|
*
|
|
43
43
|
* client.on('stateChange', ({ state }) => console.log('State:', state));
|
|
@@ -29,6 +29,14 @@ export declare class HlsJsPlayerImpl extends BasePlayer {
|
|
|
29
29
|
* Uses HLS.js liveSyncPosition when available (more accurate)
|
|
30
30
|
*/
|
|
31
31
|
jumpToLive(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Provide a seekable range override for live streams.
|
|
34
|
+
* Uses liveSyncPosition as the live edge to avoid waiting for the absolute end.
|
|
35
|
+
*/
|
|
36
|
+
getSeekableRange(): {
|
|
37
|
+
start: number;
|
|
38
|
+
end: number;
|
|
39
|
+
} | null;
|
|
32
40
|
/**
|
|
33
41
|
* Get latency from live edge (for live streams)
|
|
34
42
|
*/
|
|
@@ -37,7 +37,7 @@ export declare class MewsWsPlayerImpl extends BasePlayer {
|
|
|
37
37
|
private analyticsTimer;
|
|
38
38
|
isMimeSupported(mimetype: string): boolean;
|
|
39
39
|
isBrowserSupported(mimetype: string, source: StreamSource, streamInfo: StreamInfo): boolean | string[];
|
|
40
|
-
initialize(container: HTMLElement, source: StreamSource, options: PlayerOptions): Promise<HTMLVideoElement>;
|
|
40
|
+
initialize(container: HTMLElement, source: StreamSource, options: PlayerOptions, streamInfo?: StreamInfo): Promise<HTMLVideoElement>;
|
|
41
41
|
/**
|
|
42
42
|
* Handle MediaSource sourceopen event.
|
|
43
43
|
* Ported from mews.js:143-148, 198-204, 885-902
|
|
@@ -21,10 +21,6 @@ export declare class VideoJsPlayerImpl extends BasePlayer {
|
|
|
21
21
|
private getVideoJsType;
|
|
22
22
|
setPlaybackRate(rate: number): void;
|
|
23
23
|
getCurrentTime(): number;
|
|
24
|
-
getSeekableRange(): {
|
|
25
|
-
start: number;
|
|
26
|
-
end: number;
|
|
27
|
-
} | null;
|
|
28
24
|
/**
|
|
29
25
|
* Seek to time using VideoJS API (fixes backwards seeking in HLS).
|
|
30
26
|
* Time should be in the corrected coordinate space (with firstms offset applied).
|
|
@@ -46,11 +42,23 @@ export declare class VideoJsPlayerImpl extends BasePlayer {
|
|
|
46
42
|
* Check if the stream is live
|
|
47
43
|
*/
|
|
48
44
|
isLiveStream(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Get the calculated duration for live streams
|
|
47
|
+
*/
|
|
48
|
+
getDuration(): number;
|
|
49
49
|
/**
|
|
50
50
|
* Jump to live edge
|
|
51
51
|
* Uses VideoJS liveTracker when available, otherwise LiveDurationProxy
|
|
52
52
|
*/
|
|
53
53
|
jumpToLive(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Provide a seekable range override for live streams.
|
|
56
|
+
* Uses VideoJS liveTracker seekableEnd as the live edge when available.
|
|
57
|
+
*/
|
|
58
|
+
getSeekableRange(): {
|
|
59
|
+
start: number;
|
|
60
|
+
end: number;
|
|
61
|
+
} | null;
|
|
54
62
|
/**
|
|
55
63
|
* Get latency from live edge (for live streams)
|
|
56
64
|
*/
|
|
@@ -35,6 +35,8 @@ export declare class WebCodecsPlayerImpl extends BasePlayer {
|
|
|
35
35
|
private debugging;
|
|
36
36
|
private verboseDebugging;
|
|
37
37
|
private streamType;
|
|
38
|
+
/** Payload format: 'avcc' for ws/video/raw, 'annexb' for ws/video/h264 */
|
|
39
|
+
private payloadFormat;
|
|
38
40
|
private workerUidCounter;
|
|
39
41
|
private workerListeners;
|
|
40
42
|
private _duration;
|
|
@@ -47,6 +49,12 @@ export declare class WebCodecsPlayerImpl extends BasePlayer {
|
|
|
47
49
|
private _framesDecoded;
|
|
48
50
|
private _bytesReceived;
|
|
49
51
|
private _messagesReceived;
|
|
52
|
+
private _isPaused;
|
|
53
|
+
private _suppressPlayPauseSync;
|
|
54
|
+
private _onVideoPlay?;
|
|
55
|
+
private _onVideoPause?;
|
|
56
|
+
private _pendingStepPause;
|
|
57
|
+
private _stepPauseTimeout;
|
|
50
58
|
private static codecCache;
|
|
51
59
|
/**
|
|
52
60
|
* Get cache key for a track's codec configuration
|
|
@@ -95,8 +103,11 @@ export declare class WebCodecsPlayerImpl extends BasePlayer {
|
|
|
95
103
|
private closePipeline;
|
|
96
104
|
play(): Promise<void>;
|
|
97
105
|
pause(): void;
|
|
106
|
+
private finishStepPause;
|
|
107
|
+
frameStep(direction: -1 | 1, _seconds?: number): void;
|
|
98
108
|
seek(time: number): void;
|
|
99
109
|
setPlaybackRate(rate: number): void;
|
|
110
|
+
isPaused(): boolean;
|
|
100
111
|
isLive(): boolean;
|
|
101
112
|
jumpToLive(): void;
|
|
102
113
|
/**
|