@livepeer-frameworks/player-svelte 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.
- package/README.md +4 -6
- package/dist/DevModePanel.svelte +266 -127
- package/dist/DevModePanel.svelte.d.ts +1 -1
- package/dist/DvdLogo.svelte +17 -21
- package/dist/Icons.svelte +5 -3
- package/dist/Icons.svelte.d.ts +6 -19
- package/dist/IdleScreen.svelte +277 -186
- package/dist/IdleScreen.svelte.d.ts +1 -1
- package/dist/LoadingScreen.svelte +190 -162
- package/dist/Player.svelte +244 -111
- package/dist/Player.svelte.d.ts +1 -1
- package/dist/PlayerControls.svelte +263 -168
- package/dist/PlayerControls.svelte.d.ts +1 -1
- package/dist/SeekBar.svelte +61 -35
- package/dist/SkipIndicator.svelte +4 -4
- package/dist/SkipIndicator.svelte.d.ts +1 -1
- package/dist/SpeedIndicator.svelte +1 -1
- package/dist/StatsPanel.svelte +76 -57
- package/dist/StatsPanel.svelte.d.ts +1 -1
- package/dist/StreamStateOverlay.svelte +143 -107
- package/dist/StreamStateOverlay.svelte.d.ts +1 -1
- package/dist/SubtitleRenderer.svelte +46 -43
- package/dist/ThumbnailOverlay.svelte +22 -19
- package/dist/TitleOverlay.svelte +6 -11
- package/dist/components/VolumeIcons.svelte +12 -6
- package/dist/global.d.ts +3 -3
- package/dist/icons/FullscreenExitIcon.svelte +1 -5
- package/dist/icons/FullscreenIcon.svelte +1 -5
- package/dist/icons/PauseIcon.svelte +1 -5
- package/dist/icons/PictureInPictureIcon.svelte +12 -6
- package/dist/icons/PlayIcon.svelte +1 -5
- package/dist/icons/SeekToLiveIcon.svelte +1 -5
- package/dist/icons/SettingsIcon.svelte +1 -5
- package/dist/icons/SkipBackIcon.svelte +1 -5
- package/dist/icons/SkipForwardIcon.svelte +1 -5
- package/dist/icons/StatsIcon.svelte +1 -5
- package/dist/icons/VolumeOffIcon.svelte +1 -5
- package/dist/icons/VolumeUpIcon.svelte +1 -5
- package/dist/icons/index.d.ts +12 -12
- package/dist/icons/index.js +12 -12
- package/dist/index.d.ts +24 -24
- package/dist/index.js +21 -21
- package/dist/stores/index.d.ts +6 -6
- package/dist/stores/index.js +6 -6
- package/dist/stores/playbackQuality.d.ts +2 -2
- package/dist/stores/playbackQuality.js +7 -7
- package/dist/stores/playerContext.d.ts +2 -2
- package/dist/stores/playerContext.js +17 -17
- package/dist/stores/playerController.d.ts +13 -4
- package/dist/stores/playerController.js +80 -56
- package/dist/stores/playerSelection.d.ts +2 -2
- package/dist/stores/playerSelection.js +7 -7
- package/dist/stores/streamState.d.ts +2 -2
- package/dist/stores/streamState.js +56 -56
- package/dist/stores/viewerEndpoints.d.ts +3 -3
- package/dist/stores/viewerEndpoints.js +21 -21
- package/dist/types.d.ts +1 -1
- package/dist/ui/Badge.svelte +9 -10
- package/dist/ui/Badge.svelte.d.ts +8 -29
- package/dist/ui/Button.svelte +16 -16
- package/dist/ui/Button.svelte.d.ts +8 -29
- package/dist/ui/Slider.svelte +21 -55
- package/dist/ui/badge.js +1 -1
- package/dist/ui/button.js +2 -2
- package/dist/ui/context-menu/ContextMenuCheckboxItem.svelte +5 -7
- package/dist/ui/context-menu/ContextMenuCheckboxItem.svelte.d.ts +6 -27
- package/dist/ui/context-menu/ContextMenuContent.svelte +2 -9
- package/dist/ui/context-menu/ContextMenuItem.svelte +1 -5
- package/dist/ui/context-menu/ContextMenuLabel.svelte +1 -5
- package/dist/ui/context-menu/ContextMenuRadioItem.svelte +5 -7
- package/dist/ui/context-menu/ContextMenuRadioItem.svelte.d.ts +6 -27
- package/dist/ui/context-menu/ContextMenuSeparator.svelte +2 -8
- package/dist/ui/context-menu/ContextMenuShortcut.svelte +2 -12
- package/dist/ui/context-menu/ContextMenuSubContent.svelte +1 -5
- package/package.json +15 -7
- package/src/DevModePanel.svelte +266 -127
- package/src/DvdLogo.svelte +17 -21
- package/src/Icons.svelte +5 -3
- package/src/IdleScreen.svelte +277 -186
- package/src/LoadingScreen.svelte +190 -162
- package/src/Player.svelte +244 -111
- package/src/PlayerControls.svelte +263 -168
- package/src/SeekBar.svelte +61 -35
- package/src/SkipIndicator.svelte +4 -4
- package/src/SpeedIndicator.svelte +1 -1
- package/src/StatsPanel.svelte +76 -57
- package/src/StreamStateOverlay.svelte +143 -107
- package/src/SubtitleRenderer.svelte +46 -43
- package/src/ThumbnailOverlay.svelte +22 -19
- package/src/TitleOverlay.svelte +6 -11
- package/src/components/VolumeIcons.svelte +12 -6
- package/src/global.d.ts +3 -3
- package/src/icons/FullscreenExitIcon.svelte +1 -5
- package/src/icons/FullscreenIcon.svelte +1 -5
- package/src/icons/PauseIcon.svelte +1 -5
- package/src/icons/PictureInPictureIcon.svelte +12 -6
- package/src/icons/PlayIcon.svelte +1 -5
- package/src/icons/SeekToLiveIcon.svelte +1 -5
- package/src/icons/SettingsIcon.svelte +1 -5
- package/src/icons/SkipBackIcon.svelte +1 -5
- package/src/icons/SkipForwardIcon.svelte +1 -5
- package/src/icons/StatsIcon.svelte +1 -5
- package/src/icons/VolumeOffIcon.svelte +1 -5
- package/src/icons/VolumeUpIcon.svelte +1 -5
- package/src/icons/index.ts +12 -12
- package/src/index.ts +31 -24
- package/src/stores/index.ts +6 -6
- package/src/stores/playbackQuality.ts +10 -8
- package/src/stores/playerContext.ts +21 -17
- package/src/stores/playerController.ts +196 -126
- package/src/stores/playerSelection.ts +23 -13
- package/src/stores/streamState.ts +51 -51
- package/src/stores/viewerEndpoints.ts +30 -26
- package/src/types.ts +1 -1
- package/src/ui/Badge.svelte +9 -10
- package/src/ui/Button.svelte +16 -16
- package/src/ui/Slider.svelte +21 -55
- package/src/ui/badge.ts +3 -2
- package/src/ui/button.ts +17 -5
- package/src/ui/context-menu/ContextMenuCheckboxItem.svelte +5 -7
- package/src/ui/context-menu/ContextMenuContent.svelte +2 -9
- package/src/ui/context-menu/ContextMenuItem.svelte +1 -5
- package/src/ui/context-menu/ContextMenuLabel.svelte +1 -5
- package/src/ui/context-menu/ContextMenuRadioItem.svelte +5 -7
- package/src/ui/context-menu/ContextMenuSeparator.svelte +2 -8
- package/src/ui/context-menu/ContextMenuShortcut.svelte +2 -12
- package/src/ui/context-menu/ContextMenuSubContent.svelte +1 -5
package/dist/DevModePanel.svelte
CHANGED
|
@@ -10,23 +10,27 @@
|
|
|
10
10
|
type StreamInfo,
|
|
11
11
|
type MistStreamInfo,
|
|
12
12
|
type PlaybackMode,
|
|
13
|
-
} from
|
|
13
|
+
} from "@livepeer-frameworks/player-core";
|
|
14
14
|
|
|
15
15
|
/** Short labels for source types */
|
|
16
16
|
const SOURCE_TYPE_LABELS: Record<string, string> = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
"html5/application/vnd.apple.mpegurl": "HLS",
|
|
18
|
+
"dash/video/mp4": "DASH",
|
|
19
|
+
"html5/video/mp4": "MP4",
|
|
20
|
+
"html5/video/webm": "WebM",
|
|
21
|
+
whep: "WHEP",
|
|
22
|
+
"mist/html": "Mist",
|
|
23
|
+
"mist/legacy": "Auto",
|
|
24
|
+
"ws/video/mp4": "MEWS",
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
interface Props {
|
|
28
28
|
/** Callback when user selects a combo (one-shot selection) */
|
|
29
|
-
onSettingsChange: (settings: {
|
|
29
|
+
onSettingsChange: (settings: {
|
|
30
|
+
forcePlayer?: string;
|
|
31
|
+
forceType?: string;
|
|
32
|
+
forceSource?: number;
|
|
33
|
+
}) => void;
|
|
30
34
|
playbackMode?: PlaybackMode;
|
|
31
35
|
onModeChange?: (mode: PlaybackMode) => void;
|
|
32
36
|
onReload?: () => void;
|
|
@@ -44,7 +48,7 @@
|
|
|
44
48
|
|
|
45
49
|
let {
|
|
46
50
|
onSettingsChange,
|
|
47
|
-
playbackMode =
|
|
51
|
+
playbackMode = "auto",
|
|
48
52
|
onModeChange = undefined,
|
|
49
53
|
onReload = undefined,
|
|
50
54
|
streamInfo = null,
|
|
@@ -61,7 +65,7 @@
|
|
|
61
65
|
|
|
62
66
|
// Internal state
|
|
63
67
|
let internalIsOpen = $state(false);
|
|
64
|
-
let activeTab = $state<
|
|
68
|
+
let activeTab = $state<"config" | "stats">("config");
|
|
65
69
|
let hoveredComboIndex = $state<number | null>(null);
|
|
66
70
|
let tooltipAbove = $state(false);
|
|
67
71
|
let showDisabledPlayers = $state(false);
|
|
@@ -112,20 +116,20 @@
|
|
|
112
116
|
}
|
|
113
117
|
});
|
|
114
118
|
|
|
115
|
-
let combinations = $derived(allCombinations.filter(c => c.compatible));
|
|
119
|
+
let combinations = $derived(allCombinations.filter((c) => c.compatible));
|
|
116
120
|
|
|
117
121
|
// Find active combo index
|
|
118
122
|
let activeComboIndex = $derived.by(() => {
|
|
119
123
|
if (!currentPlayer || !currentSource || allCombinations.length === 0) return -1;
|
|
120
124
|
return allCombinations.findIndex(
|
|
121
|
-
c => c.player === currentPlayer.shortname && c.sourceType === currentSource.type
|
|
125
|
+
(c) => c.player === currentPlayer.shortname && c.sourceType === currentSource.type
|
|
122
126
|
);
|
|
123
127
|
});
|
|
124
128
|
|
|
125
129
|
let activeCompatibleIndex = $derived.by(() => {
|
|
126
130
|
if (!currentPlayer || !currentSource || combinations.length === 0) return -1;
|
|
127
131
|
return combinations.findIndex(
|
|
128
|
-
c => c.player === currentPlayer.shortname && c.sourceType === currentSource.type
|
|
132
|
+
(c) => c.player === currentPlayer.shortname && c.sourceType === currentSource.type
|
|
129
133
|
);
|
|
130
134
|
});
|
|
131
135
|
|
|
@@ -195,7 +199,7 @@
|
|
|
195
199
|
|
|
196
200
|
// Video stats polling
|
|
197
201
|
$effect(() => {
|
|
198
|
-
if (!isOpen || activeTab !==
|
|
202
|
+
if (!isOpen || activeTab !== "stats") return;
|
|
199
203
|
|
|
200
204
|
function updateStats() {
|
|
201
205
|
const player = globalPlayerManager.getCurrentPlayer();
|
|
@@ -206,12 +210,13 @@
|
|
|
206
210
|
}
|
|
207
211
|
stats = {
|
|
208
212
|
resolution: `${v.videoWidth}x${v.videoHeight}`,
|
|
209
|
-
buffered:
|
|
210
|
-
|
|
211
|
-
|
|
213
|
+
buffered:
|
|
214
|
+
v.buffered.length > 0
|
|
215
|
+
? (v.buffered.end(v.buffered.length - 1) - v.currentTime).toFixed(1)
|
|
216
|
+
: "0",
|
|
212
217
|
playbackRate: v.playbackRate.toFixed(2),
|
|
213
218
|
currentTime: v.currentTime.toFixed(1),
|
|
214
|
-
duration: isFinite(v.duration) ? v.duration.toFixed(1) :
|
|
219
|
+
duration: isFinite(v.duration) ? v.duration.toFixed(1) : "live",
|
|
215
220
|
readyState: v.readyState,
|
|
216
221
|
networkState: v.networkState,
|
|
217
222
|
};
|
|
@@ -224,7 +229,7 @@
|
|
|
224
229
|
|
|
225
230
|
// Poll player-specific stats when stats tab is open
|
|
226
231
|
$effect(() => {
|
|
227
|
-
if (!isOpen || activeTab !==
|
|
232
|
+
if (!isOpen || activeTab !== "stats") {
|
|
228
233
|
playerStats = null;
|
|
229
234
|
return;
|
|
230
235
|
}
|
|
@@ -232,7 +237,7 @@
|
|
|
232
237
|
async function pollStats() {
|
|
233
238
|
try {
|
|
234
239
|
const player = globalPlayerManager.getCurrentPlayer();
|
|
235
|
-
if (player && typeof player.getStats ===
|
|
240
|
+
if (player && typeof player.getStats === "function") {
|
|
236
241
|
const stats = await player.getStats();
|
|
237
242
|
if (stats) {
|
|
238
243
|
playerStats = stats;
|
|
@@ -262,15 +267,15 @@
|
|
|
262
267
|
<div class="fw-dev-header">
|
|
263
268
|
<button
|
|
264
269
|
type="button"
|
|
265
|
-
onclick={() => activeTab =
|
|
266
|
-
class={cn(
|
|
270
|
+
onclick={() => (activeTab = "config")}
|
|
271
|
+
class={cn("fw-dev-tab", activeTab === "config" && "fw-dev-tab--active")}
|
|
267
272
|
>
|
|
268
273
|
Config
|
|
269
274
|
</button>
|
|
270
275
|
<button
|
|
271
276
|
type="button"
|
|
272
|
-
onclick={() => activeTab =
|
|
273
|
-
class={cn(
|
|
277
|
+
onclick={() => (activeTab = "stats")}
|
|
278
|
+
class={cn("fw-dev-tab", activeTab === "stats" && "fw-dev-tab--active")}
|
|
274
279
|
>
|
|
275
280
|
Stats
|
|
276
281
|
</button>
|
|
@@ -281,21 +286,28 @@
|
|
|
281
286
|
class="fw-dev-close"
|
|
282
287
|
aria-label="Close dev mode panel"
|
|
283
288
|
>
|
|
284
|
-
<svg
|
|
289
|
+
<svg
|
|
290
|
+
width="12"
|
|
291
|
+
height="12"
|
|
292
|
+
viewBox="0 0 12 12"
|
|
293
|
+
fill="none"
|
|
294
|
+
stroke="currentColor"
|
|
295
|
+
stroke-width="1.5"
|
|
296
|
+
>
|
|
285
297
|
<path d="M2 2l8 8M10 2l-8 8" />
|
|
286
298
|
</svg>
|
|
287
299
|
</button>
|
|
288
300
|
</div>
|
|
289
301
|
|
|
290
|
-
{#if activeTab ===
|
|
302
|
+
{#if activeTab === "config"}
|
|
291
303
|
<div bind:this={comboListRef} class="fw-dev-body">
|
|
292
304
|
<!-- Current State -->
|
|
293
305
|
<div class="fw-dev-section">
|
|
294
306
|
<div class="fw-dev-label">Active</div>
|
|
295
307
|
<div class="fw-dev-value">
|
|
296
|
-
{currentPlayer?.name ||
|
|
297
|
-
<span class="fw-dev-value-arrow">→</span>{
|
|
298
|
-
{SOURCE_TYPE_LABELS[currentSource?.type ||
|
|
308
|
+
{currentPlayer?.name || "None"}{" "}
|
|
309
|
+
<span class="fw-dev-value-arrow">→</span>{" "}
|
|
310
|
+
{SOURCE_TYPE_LABELS[currentSource?.type || ""] || currentSource?.type || "—"}
|
|
299
311
|
</div>
|
|
300
312
|
{#if nodeId}
|
|
301
313
|
<div class="fw-dev-value-muted">Node: {nodeId}</div>
|
|
@@ -306,28 +318,26 @@
|
|
|
306
318
|
<div class="fw-dev-section">
|
|
307
319
|
<div class="fw-dev-label">Playback Mode</div>
|
|
308
320
|
<div class="fw-dev-mode-group">
|
|
309
|
-
{#each [
|
|
321
|
+
{#each ["auto", "low-latency", "quality"] as mode}
|
|
310
322
|
<button
|
|
311
323
|
type="button"
|
|
312
324
|
onclick={() => onModeChange?.(mode as PlaybackMode)}
|
|
313
|
-
class={cn(
|
|
325
|
+
class={cn("fw-dev-mode-btn", playbackMode === mode && "fw-dev-mode-btn--active")}
|
|
314
326
|
>
|
|
315
|
-
{mode ===
|
|
327
|
+
{mode === "low-latency" ? "Low Lat" : mode.charAt(0).toUpperCase() + mode.slice(1)}
|
|
316
328
|
</button>
|
|
317
329
|
{/each}
|
|
318
330
|
</div>
|
|
319
331
|
<div class="fw-dev-mode-desc">
|
|
320
|
-
{#if playbackMode ===
|
|
321
|
-
{#if playbackMode ===
|
|
322
|
-
{#if playbackMode ===
|
|
332
|
+
{#if playbackMode === "auto"}Balanced: MP4/WS → WHEP → HLS{/if}
|
|
333
|
+
{#if playbackMode === "low-latency"}WHEP/WebRTC first (sub-1s delay){/if}
|
|
334
|
+
{#if playbackMode === "quality"}MP4/WS first, HLS fallback{/if}
|
|
323
335
|
</div>
|
|
324
336
|
</div>
|
|
325
337
|
|
|
326
338
|
<!-- Action buttons -->
|
|
327
339
|
<div class="fw-dev-actions">
|
|
328
|
-
<button type="button" onclick={handleReload} class="fw-dev-action-btn">
|
|
329
|
-
Reload
|
|
330
|
-
</button>
|
|
340
|
+
<button type="button" onclick={handleReload} class="fw-dev-action-btn"> Reload </button>
|
|
331
341
|
<button type="button" onclick={handleNextCombo} class="fw-dev-action-btn">
|
|
332
342
|
Next Option
|
|
333
343
|
</button>
|
|
@@ -342,7 +352,7 @@
|
|
|
342
352
|
{#if allCombinations.length > combinations.length}
|
|
343
353
|
<button
|
|
344
354
|
type="button"
|
|
345
|
-
onclick={() => showDisabledPlayers = !showDisabledPlayers}
|
|
355
|
+
onclick={() => (showDisabledPlayers = !showDisabledPlayers)}
|
|
346
356
|
class="fw-dev-list-toggle"
|
|
347
357
|
>
|
|
348
358
|
<svg
|
|
@@ -352,11 +362,12 @@
|
|
|
352
362
|
fill="none"
|
|
353
363
|
stroke="currentColor"
|
|
354
364
|
stroke-width="2"
|
|
355
|
-
class={cn(
|
|
365
|
+
class={cn("fw-dev-chevron", showDisabledPlayers && "fw-dev-chevron--open")}
|
|
356
366
|
>
|
|
357
367
|
<path d="M6 9l6 6 6-6" />
|
|
358
368
|
</svg>
|
|
359
|
-
{showDisabledPlayers ?
|
|
369
|
+
{showDisabledPlayers ? "Hide" : "Show"} disabled ({allCombinations.length -
|
|
370
|
+
combinations.length})
|
|
360
371
|
</button>
|
|
361
372
|
{/if}
|
|
362
373
|
</div>
|
|
@@ -368,78 +379,121 @@
|
|
|
368
379
|
{@const isCodecIncompat = (combo as any).codecIncompatible === true}
|
|
369
380
|
{@const shouldShow = combo.compatible || isCodecIncompat || showDisabledPlayers}
|
|
370
381
|
{@const isActive = activeComboIndex === index}
|
|
371
|
-
{@const typeLabel =
|
|
382
|
+
{@const typeLabel =
|
|
383
|
+
SOURCE_TYPE_LABELS[combo.sourceType] || combo.sourceType.split("/").pop()}
|
|
372
384
|
|
|
373
385
|
{#if shouldShow}
|
|
374
386
|
<div
|
|
375
387
|
class="fw-dev-combo"
|
|
388
|
+
role="listitem"
|
|
376
389
|
onmouseenter={(e) => handleComboHover(index, e)}
|
|
377
|
-
onmouseleave={() => hoveredComboIndex = null}
|
|
390
|
+
onmouseleave={() => (hoveredComboIndex = null)}
|
|
378
391
|
>
|
|
379
392
|
<button
|
|
380
393
|
type="button"
|
|
381
394
|
onclick={() => handleSelectCombo(index)}
|
|
382
395
|
class={cn(
|
|
383
|
-
|
|
384
|
-
isActive &&
|
|
385
|
-
!combo.compatible && !isCodecIncompat &&
|
|
386
|
-
isCodecIncompat &&
|
|
396
|
+
"fw-dev-combo-btn",
|
|
397
|
+
isActive && "fw-dev-combo-btn--active",
|
|
398
|
+
!combo.compatible && !isCodecIncompat && "fw-dev-combo-btn--disabled",
|
|
399
|
+
isCodecIncompat && "fw-dev-combo-btn--codec-warn"
|
|
387
400
|
)}
|
|
388
401
|
>
|
|
389
402
|
<!-- Rank -->
|
|
390
|
-
<span
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
403
|
+
<span
|
|
404
|
+
class={cn(
|
|
405
|
+
"fw-dev-combo-rank",
|
|
406
|
+
isActive
|
|
407
|
+
? "fw-dev-combo-rank--active"
|
|
408
|
+
: !combo.compatible && !isCodecIncompat
|
|
409
|
+
? "fw-dev-combo-rank--disabled"
|
|
410
|
+
: isCodecIncompat
|
|
411
|
+
? "fw-dev-combo-rank--warn"
|
|
412
|
+
: ""
|
|
413
|
+
)}
|
|
414
|
+
>
|
|
415
|
+
{combo.compatible ? index + 1 : isCodecIncompat ? "⚠" : "—"}
|
|
397
416
|
</span>
|
|
398
417
|
<!-- Player + Protocol -->
|
|
399
418
|
<span class="fw-dev-combo-name">
|
|
400
|
-
{combo.playerName}{
|
|
401
|
-
<span class="fw-dev-combo-arrow">→</span>{
|
|
402
|
-
<span
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
419
|
+
{combo.playerName}{" "}
|
|
420
|
+
<span class="fw-dev-combo-arrow">→</span>{" "}
|
|
421
|
+
<span
|
|
422
|
+
class={cn(
|
|
423
|
+
"fw-dev-combo-type",
|
|
424
|
+
isCodecIncompat && "fw-dev-combo-type--warn",
|
|
425
|
+
!combo.compatible && !isCodecIncompat && "fw-dev-combo-type--disabled"
|
|
426
|
+
)}>{typeLabel}</span
|
|
427
|
+
>
|
|
407
428
|
</span>
|
|
408
429
|
<!-- Score -->
|
|
409
|
-
<span
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
430
|
+
<span
|
|
431
|
+
class={cn(
|
|
432
|
+
"fw-dev-combo-score",
|
|
433
|
+
!combo.compatible && !isCodecIncompat
|
|
434
|
+
? "fw-dev-combo-score--disabled"
|
|
435
|
+
: isCodecIncompat
|
|
436
|
+
? "fw-dev-combo-score--low"
|
|
437
|
+
: combo.score >= 2
|
|
438
|
+
? "fw-dev-combo-score--high"
|
|
439
|
+
: combo.score >= 1.5
|
|
440
|
+
? "fw-dev-combo-score--mid"
|
|
441
|
+
: "fw-dev-combo-score--low"
|
|
442
|
+
)}
|
|
443
|
+
>
|
|
417
444
|
{combo.score.toFixed(2)}
|
|
418
445
|
</span>
|
|
419
446
|
</button>
|
|
420
447
|
|
|
421
448
|
<!-- Tooltip -->
|
|
422
449
|
{#if hoveredComboIndex === index}
|
|
423
|
-
<div
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
450
|
+
<div
|
|
451
|
+
class={cn(
|
|
452
|
+
"fw-dev-tooltip",
|
|
453
|
+
tooltipAbove ? "fw-dev-tooltip--above" : "fw-dev-tooltip--below"
|
|
454
|
+
)}
|
|
455
|
+
>
|
|
427
456
|
<div class="fw-dev-tooltip-header">
|
|
428
457
|
<div class="fw-dev-tooltip-title">{combo.playerName}</div>
|
|
429
458
|
<div class="fw-dev-tooltip-subtitle">{combo.sourceType}</div>
|
|
430
459
|
{#if combo.scoreBreakdown?.trackTypes?.length}
|
|
431
460
|
<div class="fw-dev-tooltip-tracks">
|
|
432
|
-
Tracks: <span class="fw-dev-tooltip-value"
|
|
461
|
+
Tracks: <span class="fw-dev-tooltip-value"
|
|
462
|
+
>{combo.scoreBreakdown.trackTypes.join(", ")}</span
|
|
463
|
+
>
|
|
433
464
|
</div>
|
|
434
465
|
{/if}
|
|
435
466
|
</div>
|
|
436
467
|
{#if combo.compatible && combo.scoreBreakdown}
|
|
437
468
|
<div class="fw-dev-tooltip-score">Score: {combo.score.toFixed(2)}</div>
|
|
438
|
-
<div class="fw-dev-tooltip-row">
|
|
439
|
-
|
|
440
|
-
|
|
469
|
+
<div class="fw-dev-tooltip-row">
|
|
470
|
+
Tracks: <span class="fw-dev-tooltip-value"
|
|
471
|
+
>{combo.scoreBreakdown.trackScore.toFixed(2)}</span
|
|
472
|
+
>
|
|
473
|
+
<span class="fw-dev-tooltip-weight"
|
|
474
|
+
>x{combo.scoreBreakdown.weights.tracks}</span
|
|
475
|
+
>
|
|
476
|
+
</div>
|
|
477
|
+
<div class="fw-dev-tooltip-row">
|
|
478
|
+
Priority: <span class="fw-dev-tooltip-value"
|
|
479
|
+
>{combo.scoreBreakdown.priorityScore.toFixed(2)}</span
|
|
480
|
+
>
|
|
481
|
+
<span class="fw-dev-tooltip-weight"
|
|
482
|
+
>x{combo.scoreBreakdown.weights.priority}</span
|
|
483
|
+
>
|
|
484
|
+
</div>
|
|
485
|
+
<div class="fw-dev-tooltip-row">
|
|
486
|
+
Source: <span class="fw-dev-tooltip-value"
|
|
487
|
+
>{combo.scoreBreakdown.sourceScore.toFixed(2)}</span
|
|
488
|
+
>
|
|
489
|
+
<span class="fw-dev-tooltip-weight"
|
|
490
|
+
>x{combo.scoreBreakdown.weights.source}</span
|
|
491
|
+
>
|
|
492
|
+
</div>
|
|
441
493
|
{:else}
|
|
442
|
-
<div class="fw-dev-tooltip-error">
|
|
494
|
+
<div class="fw-dev-tooltip-error">
|
|
495
|
+
{combo.incompatibleReason || "Incompatible"}
|
|
496
|
+
</div>
|
|
443
497
|
{/if}
|
|
444
498
|
</div>
|
|
445
499
|
{/if}
|
|
@@ -449,47 +503,94 @@
|
|
|
449
503
|
{/if}
|
|
450
504
|
</div>
|
|
451
505
|
</div>
|
|
452
|
-
{:else if activeTab ===
|
|
506
|
+
{:else if activeTab === "stats"}
|
|
453
507
|
<div class="fw-dev-body">
|
|
454
508
|
<!-- Playback Rate -->
|
|
455
509
|
<div class="fw-dev-section">
|
|
456
510
|
<div class="fw-dev-label">Playback Rate</div>
|
|
457
511
|
<div class="fw-dev-rate">
|
|
458
|
-
<div
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
512
|
+
<div
|
|
513
|
+
class={cn(
|
|
514
|
+
"fw-dev-rate-value",
|
|
515
|
+
playbackScore >= 0.95 && playbackScore <= 1.05
|
|
516
|
+
? "fw-dev-stat-value--good"
|
|
517
|
+
: playbackScore > 1.05
|
|
518
|
+
? "fw-dev-stat-value--accent"
|
|
519
|
+
: playbackScore >= 0.75
|
|
520
|
+
? "fw-dev-stat-value--warn"
|
|
521
|
+
: "fw-dev-stat-value--bad"
|
|
522
|
+
)}
|
|
523
|
+
>
|
|
465
524
|
{playbackScore.toFixed(2)}×
|
|
466
525
|
</div>
|
|
467
526
|
<div class="fw-dev-rate-status">
|
|
468
|
-
{playbackScore >= 0.95 && playbackScore <= 1.05
|
|
469
|
-
|
|
470
|
-
|
|
527
|
+
{playbackScore >= 0.95 && playbackScore <= 1.05
|
|
528
|
+
? "realtime"
|
|
529
|
+
: playbackScore > 1.05
|
|
530
|
+
? "catching up"
|
|
531
|
+
: playbackScore >= 0.75
|
|
532
|
+
? "slightly slow"
|
|
533
|
+
: "stalling"}
|
|
471
534
|
</div>
|
|
472
535
|
</div>
|
|
473
536
|
<div class="fw-dev-rate-stats">
|
|
474
|
-
<span class={qualityScore >= 75 ?
|
|
475
|
-
|
|
476
|
-
|
|
537
|
+
<span class={qualityScore >= 75 ? "fw-dev-stat-value--good" : "fw-dev-stat-value--bad"}
|
|
538
|
+
>Quality: {qualityScore}/100</span
|
|
539
|
+
>
|
|
540
|
+
<span class={stallCount === 0 ? "fw-dev-stat-value--good" : "fw-dev-stat-value--warn"}
|
|
541
|
+
>Stalls: {stallCount}</span
|
|
542
|
+
>
|
|
543
|
+
<span class={frameDropRate < 1 ? "fw-dev-stat-value--good" : "fw-dev-stat-value--bad"}
|
|
544
|
+
>Drops: {frameDropRate.toFixed(1)}%</span
|
|
545
|
+
>
|
|
477
546
|
</div>
|
|
478
547
|
</div>
|
|
479
548
|
|
|
480
549
|
<!-- Video Stats -->
|
|
481
550
|
{#if stats}
|
|
482
|
-
<div class="fw-dev-stat"
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
<div class="fw-dev-stat"
|
|
551
|
+
<div class="fw-dev-stat">
|
|
552
|
+
<span class="fw-dev-stat-label">Resolution</span><span class="fw-dev-stat-value"
|
|
553
|
+
>{stats.resolution}</span
|
|
554
|
+
>
|
|
555
|
+
</div>
|
|
556
|
+
<div class="fw-dev-stat">
|
|
557
|
+
<span class="fw-dev-stat-label">Buffer</span><span class="fw-dev-stat-value"
|
|
558
|
+
>{stats.buffered}s</span
|
|
559
|
+
>
|
|
560
|
+
</div>
|
|
561
|
+
<div class="fw-dev-stat">
|
|
562
|
+
<span class="fw-dev-stat-label">Playback Rate</span><span class="fw-dev-stat-value"
|
|
563
|
+
>{stats.playbackRate}x</span
|
|
564
|
+
>
|
|
565
|
+
</div>
|
|
566
|
+
<div class="fw-dev-stat">
|
|
567
|
+
<span class="fw-dev-stat-label">Time</span><span class="fw-dev-stat-value"
|
|
568
|
+
>{stats.currentTime} / {stats.duration}</span
|
|
569
|
+
>
|
|
570
|
+
</div>
|
|
571
|
+
<div class="fw-dev-stat">
|
|
572
|
+
<span class="fw-dev-stat-label">Ready State</span><span class="fw-dev-stat-value"
|
|
573
|
+
>{stats.readyState}</span
|
|
574
|
+
>
|
|
575
|
+
</div>
|
|
576
|
+
<div class="fw-dev-stat">
|
|
577
|
+
<span class="fw-dev-stat-label">Network State</span><span class="fw-dev-stat-value"
|
|
578
|
+
>{stats.networkState}</span
|
|
579
|
+
>
|
|
580
|
+
</div>
|
|
488
581
|
{#if protocol}
|
|
489
|
-
<div class="fw-dev-stat"
|
|
582
|
+
<div class="fw-dev-stat">
|
|
583
|
+
<span class="fw-dev-stat-label">Protocol</span><span class="fw-dev-stat-value"
|
|
584
|
+
>{protocol}</span
|
|
585
|
+
>
|
|
586
|
+
</div>
|
|
490
587
|
{/if}
|
|
491
588
|
{#if nodeId}
|
|
492
|
-
<div class="fw-dev-stat"
|
|
589
|
+
<div class="fw-dev-stat">
|
|
590
|
+
<span class="fw-dev-stat-label">Node ID</span><span class="fw-dev-stat-value"
|
|
591
|
+
>{nodeId}</span
|
|
592
|
+
>
|
|
593
|
+
</div>
|
|
493
594
|
{/if}
|
|
494
595
|
{:else}
|
|
495
596
|
<div class="fw-dev-list-empty">No video element available</div>
|
|
@@ -499,34 +600,46 @@
|
|
|
499
600
|
{#if playerStats}
|
|
500
601
|
<div class="fw-dev-section fw-dev-section-header">
|
|
501
602
|
<div class="fw-dev-label">
|
|
502
|
-
{playerStats.type ===
|
|
503
|
-
|
|
603
|
+
{playerStats.type === "hls"
|
|
604
|
+
? "HLS.js Stats"
|
|
605
|
+
: playerStats.type === "webrtc"
|
|
606
|
+
? "WebRTC Stats"
|
|
607
|
+
: "Player Stats"}
|
|
504
608
|
</div>
|
|
505
609
|
</div>
|
|
506
610
|
<!-- HLS-specific stats -->
|
|
507
|
-
{#if playerStats.type ===
|
|
611
|
+
{#if playerStats.type === "hls"}
|
|
508
612
|
<div class="fw-dev-stat">
|
|
509
613
|
<span class="fw-dev-stat-label">Bitrate</span>
|
|
510
614
|
<span class="fw-dev-stat-value fw-dev-stat-value--accent">
|
|
511
|
-
{playerStats.currentBitrate > 0
|
|
615
|
+
{playerStats.currentBitrate > 0
|
|
616
|
+
? `${Math.round(playerStats.currentBitrate / 1000)} kbps`
|
|
617
|
+
: "N/A"}
|
|
512
618
|
</span>
|
|
513
619
|
</div>
|
|
514
620
|
<div class="fw-dev-stat">
|
|
515
621
|
<span class="fw-dev-stat-label">Bandwidth Est.</span>
|
|
516
622
|
<span class="fw-dev-stat-value">
|
|
517
|
-
{playerStats.bandwidthEstimate > 0
|
|
623
|
+
{playerStats.bandwidthEstimate > 0
|
|
624
|
+
? `${Math.round(playerStats.bandwidthEstimate / 1000)} kbps`
|
|
625
|
+
: "N/A"}
|
|
518
626
|
</span>
|
|
519
627
|
</div>
|
|
520
628
|
<div class="fw-dev-stat">
|
|
521
629
|
<span class="fw-dev-stat-label">Level</span>
|
|
522
630
|
<span class="fw-dev-stat-value">
|
|
523
|
-
{playerStats.currentLevel >= 0 ? playerStats.currentLevel :
|
|
631
|
+
{playerStats.currentLevel >= 0 ? playerStats.currentLevel : "Auto"} / {playerStats
|
|
632
|
+
.levels?.length || 0}
|
|
524
633
|
</span>
|
|
525
634
|
</div>
|
|
526
635
|
{#if playerStats.latency !== undefined}
|
|
527
636
|
<div class="fw-dev-stat">
|
|
528
637
|
<span class="fw-dev-stat-label">Latency</span>
|
|
529
|
-
<span
|
|
638
|
+
<span
|
|
639
|
+
class={playerStats.latency > 5000
|
|
640
|
+
? "fw-dev-stat-value fw-dev-stat-value--warn"
|
|
641
|
+
: "fw-dev-stat-value"}
|
|
642
|
+
>
|
|
530
643
|
{Math.round(playerStats.latency)} ms
|
|
531
644
|
</span>
|
|
532
645
|
</div>
|
|
@@ -534,48 +647,70 @@
|
|
|
534
647
|
{/if}
|
|
535
648
|
|
|
536
649
|
<!-- WebRTC-specific stats -->
|
|
537
|
-
{#if playerStats.type ===
|
|
650
|
+
{#if playerStats.type === "webrtc"}
|
|
538
651
|
{#if playerStats.video}
|
|
539
652
|
<div class="fw-dev-stat">
|
|
540
653
|
<span class="fw-dev-stat-label">Video Bitrate</span>
|
|
541
654
|
<span class="fw-dev-stat-value fw-dev-stat-value--accent">
|
|
542
|
-
{playerStats.video.bitrate > 0
|
|
655
|
+
{playerStats.video.bitrate > 0
|
|
656
|
+
? `${Math.round(playerStats.video.bitrate / 1000)} kbps`
|
|
657
|
+
: "N/A"}
|
|
543
658
|
</span>
|
|
544
659
|
</div>
|
|
545
660
|
<div class="fw-dev-stat">
|
|
546
661
|
<span class="fw-dev-stat-label">FPS</span>
|
|
547
|
-
<span class="fw-dev-stat-value"
|
|
662
|
+
<span class="fw-dev-stat-value"
|
|
663
|
+
>{Math.round(playerStats.video.framesPerSecond || 0)}</span
|
|
664
|
+
>
|
|
548
665
|
</div>
|
|
549
666
|
<div class="fw-dev-stat">
|
|
550
667
|
<span class="fw-dev-stat-label">Frames</span>
|
|
551
668
|
<span class="fw-dev-stat-value">
|
|
552
|
-
{playerStats.video.framesDecoded} decoded,{
|
|
553
|
-
<span
|
|
669
|
+
{playerStats.video.framesDecoded} decoded,{" "}
|
|
670
|
+
<span
|
|
671
|
+
class={playerStats.video.frameDropRate > 1
|
|
672
|
+
? "fw-dev-stat-value--bad"
|
|
673
|
+
: "fw-dev-stat-value--good"}
|
|
674
|
+
>
|
|
554
675
|
{playerStats.video.framesDropped} dropped
|
|
555
676
|
</span>
|
|
556
677
|
</span>
|
|
557
678
|
</div>
|
|
558
679
|
<div class="fw-dev-stat">
|
|
559
680
|
<span class="fw-dev-stat-label">Packet Loss</span>
|
|
560
|
-
<span
|
|
681
|
+
<span
|
|
682
|
+
class={playerStats.video.packetLossRate > 1
|
|
683
|
+
? "fw-dev-stat-value fw-dev-stat-value--bad"
|
|
684
|
+
: "fw-dev-stat-value fw-dev-stat-value--good"}
|
|
685
|
+
>
|
|
561
686
|
{playerStats.video.packetLossRate?.toFixed(2) || 0}%
|
|
562
687
|
</span>
|
|
563
688
|
</div>
|
|
564
689
|
<div class="fw-dev-stat">
|
|
565
690
|
<span class="fw-dev-stat-label">Jitter</span>
|
|
566
|
-
<span
|
|
691
|
+
<span
|
|
692
|
+
class={playerStats.video.jitter > 30
|
|
693
|
+
? "fw-dev-stat-value fw-dev-stat-value--warn"
|
|
694
|
+
: "fw-dev-stat-value"}
|
|
695
|
+
>
|
|
567
696
|
{playerStats.video.jitter?.toFixed(1) || 0} ms
|
|
568
697
|
</span>
|
|
569
698
|
</div>
|
|
570
699
|
<div class="fw-dev-stat">
|
|
571
700
|
<span class="fw-dev-stat-label">Jitter Buffer</span>
|
|
572
|
-
<span class="fw-dev-stat-value"
|
|
701
|
+
<span class="fw-dev-stat-value"
|
|
702
|
+
>{playerStats.video.jitterBufferDelay?.toFixed(1) || 0} ms</span
|
|
703
|
+
>
|
|
573
704
|
</div>
|
|
574
705
|
{/if}
|
|
575
706
|
{#if playerStats.network}
|
|
576
707
|
<div class="fw-dev-stat">
|
|
577
708
|
<span class="fw-dev-stat-label">RTT</span>
|
|
578
|
-
<span
|
|
709
|
+
<span
|
|
710
|
+
class={playerStats.network.rtt > 200
|
|
711
|
+
? "fw-dev-stat-value fw-dev-stat-value--warn"
|
|
712
|
+
: "fw-dev-stat-value"}
|
|
713
|
+
>
|
|
579
714
|
{Math.round(playerStats.network.rtt || 0)} ms
|
|
580
715
|
</span>
|
|
581
716
|
</div>
|
|
@@ -593,19 +728,23 @@
|
|
|
593
728
|
{#each Object.entries(mistStreamInfo.meta.tracks) as [id, track]}
|
|
594
729
|
<div class="fw-dev-track">
|
|
595
730
|
<div class="fw-dev-track-header">
|
|
596
|
-
<span
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
731
|
+
<span
|
|
732
|
+
class={cn(
|
|
733
|
+
"fw-dev-track-badge",
|
|
734
|
+
track.type === "video"
|
|
735
|
+
? "fw-dev-track-badge--video"
|
|
736
|
+
: track.type === "audio"
|
|
737
|
+
? "fw-dev-track-badge--audio"
|
|
738
|
+
: "fw-dev-track-badge--other"
|
|
739
|
+
)}
|
|
740
|
+
>
|
|
602
741
|
{track.type}
|
|
603
742
|
</span>
|
|
604
743
|
<span class="fw-dev-track-codec">{track.codec}</span>
|
|
605
744
|
<span class="fw-dev-track-id">#{id}</span>
|
|
606
745
|
</div>
|
|
607
746
|
<div class="fw-dev-track-meta">
|
|
608
|
-
{#if track.type ===
|
|
747
|
+
{#if track.type === "video" && track.width && track.height}
|
|
609
748
|
<span>{track.width}×{track.height}</span>
|
|
610
749
|
{/if}
|
|
611
750
|
{#if track.bps}
|
|
@@ -614,10 +753,10 @@
|
|
|
614
753
|
{#if track.fpks}
|
|
615
754
|
<span>{Math.round(track.fpks / 1000)} fps</span>
|
|
616
755
|
{/if}
|
|
617
|
-
{#if track.type ===
|
|
756
|
+
{#if track.type === "audio" && track.channels}
|
|
618
757
|
<span>{track.channels}ch</span>
|
|
619
758
|
{/if}
|
|
620
|
-
{#if track.type ===
|
|
759
|
+
{#if track.type === "audio" && track.rate}
|
|
621
760
|
<span>{track.rate} Hz</span>
|
|
622
761
|
{/if}
|
|
623
762
|
{#if track.lang}
|