@livepeer-frameworks/player-svelte 0.1.1 → 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 (88) hide show
  1. package/dist/DevModePanel.svelte +266 -127
  2. package/dist/DevModePanel.svelte.d.ts +1 -1
  3. package/dist/DvdLogo.svelte +17 -21
  4. package/dist/Icons.svelte +5 -3
  5. package/dist/Icons.svelte.d.ts +6 -19
  6. package/dist/IdleScreen.svelte +277 -186
  7. package/dist/IdleScreen.svelte.d.ts +1 -1
  8. package/dist/LoadingScreen.svelte +190 -162
  9. package/dist/Player.svelte +244 -111
  10. package/dist/Player.svelte.d.ts +1 -1
  11. package/dist/PlayerControls.svelte +263 -168
  12. package/dist/PlayerControls.svelte.d.ts +1 -1
  13. package/dist/SeekBar.svelte +61 -35
  14. package/dist/SkipIndicator.svelte +4 -4
  15. package/dist/SkipIndicator.svelte.d.ts +1 -1
  16. package/dist/SpeedIndicator.svelte +1 -1
  17. package/dist/StatsPanel.svelte +76 -57
  18. package/dist/StatsPanel.svelte.d.ts +1 -1
  19. package/dist/StreamStateOverlay.svelte +143 -107
  20. package/dist/StreamStateOverlay.svelte.d.ts +1 -1
  21. package/dist/SubtitleRenderer.svelte +46 -43
  22. package/dist/ThumbnailOverlay.svelte +22 -19
  23. package/dist/TitleOverlay.svelte +6 -11
  24. package/dist/components/VolumeIcons.svelte +12 -6
  25. package/dist/global.d.ts +3 -3
  26. package/dist/icons/FullscreenExitIcon.svelte +1 -5
  27. package/dist/icons/FullscreenIcon.svelte +1 -5
  28. package/dist/icons/PauseIcon.svelte +1 -5
  29. package/dist/icons/PictureInPictureIcon.svelte +12 -6
  30. package/dist/icons/PlayIcon.svelte +1 -5
  31. package/dist/icons/SeekToLiveIcon.svelte +1 -5
  32. package/dist/icons/SettingsIcon.svelte +1 -5
  33. package/dist/icons/SkipBackIcon.svelte +1 -5
  34. package/dist/icons/SkipForwardIcon.svelte +1 -5
  35. package/dist/icons/StatsIcon.svelte +1 -5
  36. package/dist/icons/VolumeOffIcon.svelte +1 -5
  37. package/dist/icons/VolumeUpIcon.svelte +1 -5
  38. package/dist/icons/index.d.ts +12 -12
  39. package/dist/icons/index.js +12 -12
  40. package/dist/index.d.ts +24 -24
  41. package/dist/index.js +21 -21
  42. package/dist/stores/index.d.ts +6 -6
  43. package/dist/stores/index.js +6 -6
  44. package/dist/stores/playbackQuality.d.ts +2 -2
  45. package/dist/stores/playbackQuality.js +7 -7
  46. package/dist/stores/playerContext.d.ts +2 -2
  47. package/dist/stores/playerContext.js +17 -17
  48. package/dist/stores/playerController.d.ts +13 -4
  49. package/dist/stores/playerController.js +80 -56
  50. package/dist/stores/playerSelection.d.ts +2 -2
  51. package/dist/stores/playerSelection.js +7 -7
  52. package/dist/stores/streamState.d.ts +2 -2
  53. package/dist/stores/streamState.js +56 -56
  54. package/dist/stores/viewerEndpoints.d.ts +3 -3
  55. package/dist/stores/viewerEndpoints.js +21 -21
  56. package/dist/types.d.ts +1 -1
  57. package/dist/ui/Badge.svelte +9 -10
  58. package/dist/ui/Badge.svelte.d.ts +8 -29
  59. package/dist/ui/Button.svelte +16 -16
  60. package/dist/ui/Button.svelte.d.ts +8 -29
  61. package/dist/ui/Slider.svelte +21 -55
  62. package/dist/ui/badge.js +1 -1
  63. package/dist/ui/button.js +2 -2
  64. package/dist/ui/context-menu/ContextMenuCheckboxItem.svelte +5 -7
  65. package/dist/ui/context-menu/ContextMenuCheckboxItem.svelte.d.ts +6 -27
  66. package/dist/ui/context-menu/ContextMenuContent.svelte +2 -9
  67. package/dist/ui/context-menu/ContextMenuItem.svelte +1 -5
  68. package/dist/ui/context-menu/ContextMenuLabel.svelte +1 -5
  69. package/dist/ui/context-menu/ContextMenuRadioItem.svelte +5 -7
  70. package/dist/ui/context-menu/ContextMenuRadioItem.svelte.d.ts +6 -27
  71. package/dist/ui/context-menu/ContextMenuSeparator.svelte +2 -8
  72. package/dist/ui/context-menu/ContextMenuShortcut.svelte +2 -12
  73. package/dist/ui/context-menu/ContextMenuSubContent.svelte +1 -5
  74. package/package.json +15 -7
  75. package/src/DevModePanel.svelte +1 -0
  76. package/src/Icons.svelte +5 -3
  77. package/src/IdleScreen.svelte +21 -14
  78. package/src/LoadingScreen.svelte +20 -13
  79. package/src/Player.svelte +48 -2
  80. package/src/PlayerControls.svelte +36 -17
  81. package/src/SeekBar.svelte +33 -0
  82. package/src/StreamStateOverlay.svelte +2 -2
  83. package/src/stores/playerController.ts +39 -1
  84. package/src/stores/viewerEndpoints.ts +1 -1
  85. package/src/ui/Badge.svelte +7 -4
  86. package/src/ui/Button.svelte +13 -13
  87. package/src/ui/context-menu/ContextMenuCheckboxItem.svelte +4 -2
  88. package/src/ui/context-menu/ContextMenuRadioItem.svelte +4 -2
@@ -2,13 +2,13 @@
2
2
  * Svelte store for PlayerController - wraps the core PlayerController
3
3
  * for declarative usage in Svelte 5 components.
4
4
  */
5
- import { writable, derived } from 'svelte/store';
6
- import { PlayerController, } from '@livepeer-frameworks/player-core';
5
+ import { writable, derived } from "svelte/store";
6
+ import { PlayerController, } from "@livepeer-frameworks/player-core";
7
7
  // ============================================================================
8
8
  // Initial State
9
9
  // ============================================================================
10
10
  const initialState = {
11
- state: 'booting',
11
+ state: "booting",
12
12
  streamState: null,
13
13
  endpoints: null,
14
14
  metadata: null,
@@ -21,6 +21,7 @@ const initialState = {
21
21
  isMuted: true,
22
22
  volume: 1,
23
23
  error: null,
24
+ errorDetails: null,
24
25
  isPassiveError: false,
25
26
  hasPlaybackStarted: false,
26
27
  isHoldingSpeed: false,
@@ -36,6 +37,7 @@ const initialState = {
36
37
  currentSourceInfo: null,
37
38
  playbackQuality: null,
38
39
  subtitlesEnabled: false,
40
+ toast: null,
39
41
  };
40
42
  // ============================================================================
41
43
  // Store Factory
@@ -85,7 +87,7 @@ export function createPlayerControllerStore(config) {
85
87
  function syncState() {
86
88
  if (!controller)
87
89
  return;
88
- store.update(prev => ({
90
+ store.update((prev) => ({
89
91
  ...prev,
90
92
  isPlaying: controller.isPlaying(),
91
93
  isPaused: controller.isPaused(),
@@ -108,18 +110,18 @@ export function createPlayerControllerStore(config) {
108
110
  return;
109
111
  // Clean up existing controller
110
112
  if (controller) {
111
- unsubscribers.forEach(fn => fn());
113
+ unsubscribers.forEach((fn) => fn());
112
114
  unsubscribers = [];
113
115
  controller.destroy();
114
116
  }
115
117
  // Create new controller
116
118
  controller = new PlayerController(controllerConfig);
117
119
  // Subscribe to events
118
- unsubscribers.push(controller.on('stateChange', ({ state }) => {
119
- store.update(prev => ({ ...prev, state }));
120
+ unsubscribers.push(controller.on("stateChange", ({ state }) => {
121
+ store.update((prev) => ({ ...prev, state }));
120
122
  }));
121
- unsubscribers.push(controller.on('streamStateChange', ({ state: streamState }) => {
122
- store.update(prev => ({
123
+ unsubscribers.push(controller.on("streamStateChange", ({ state: streamState }) => {
124
+ store.update((prev) => ({
123
125
  ...prev,
124
126
  streamState,
125
127
  metadata: controller.getMetadata(),
@@ -127,21 +129,21 @@ export function createPlayerControllerStore(config) {
127
129
  shouldShowIdleScreen: controller.shouldShowIdleScreen(),
128
130
  }));
129
131
  }));
130
- unsubscribers.push(controller.on('timeUpdate', ({ currentTime, duration }) => {
131
- store.update(prev => ({ ...prev, currentTime, duration }));
132
+ unsubscribers.push(controller.on("timeUpdate", ({ currentTime, duration }) => {
133
+ store.update((prev) => ({ ...prev, currentTime, duration }));
132
134
  }));
133
- unsubscribers.push(controller.on('error', ({ error }) => {
134
- store.update(prev => ({
135
+ unsubscribers.push(controller.on("error", ({ error }) => {
136
+ store.update((prev) => ({
135
137
  ...prev,
136
138
  error,
137
139
  isPassiveError: controller.isPassiveError(),
138
140
  }));
139
141
  }));
140
- unsubscribers.push(controller.on('errorCleared', () => {
141
- store.update(prev => ({ ...prev, error: null, isPassiveError: false }));
142
+ unsubscribers.push(controller.on("errorCleared", () => {
143
+ store.update((prev) => ({ ...prev, error: null, isPassiveError: false }));
142
144
  }));
143
- unsubscribers.push(controller.on('ready', ({ videoElement }) => {
144
- store.update(prev => ({
145
+ unsubscribers.push(controller.on("ready", ({ videoElement }) => {
146
+ store.update((prev) => ({
145
147
  ...prev,
146
148
  videoElement,
147
149
  endpoints: controller.getEndpoints(),
@@ -158,57 +160,70 @@ export function createPlayerControllerStore(config) {
158
160
  return;
159
161
  syncState();
160
162
  };
161
- video.addEventListener('play', handleVideoEvent);
162
- video.addEventListener('pause', handleVideoEvent);
163
- video.addEventListener('waiting', handleVideoEvent);
164
- video.addEventListener('playing', handleVideoEvent);
163
+ video.addEventListener("play", handleVideoEvent);
164
+ video.addEventListener("pause", handleVideoEvent);
165
+ video.addEventListener("waiting", handleVideoEvent);
166
+ video.addEventListener("playing", handleVideoEvent);
165
167
  unsubscribers.push(() => {
166
- video.removeEventListener('play', handleVideoEvent);
167
- video.removeEventListener('pause', handleVideoEvent);
168
- video.removeEventListener('waiting', handleVideoEvent);
169
- video.removeEventListener('playing', handleVideoEvent);
168
+ video.removeEventListener("play", handleVideoEvent);
169
+ video.removeEventListener("pause", handleVideoEvent);
170
+ video.removeEventListener("waiting", handleVideoEvent);
171
+ video.removeEventListener("playing", handleVideoEvent);
170
172
  });
171
173
  }));
172
- unsubscribers.push(controller.on('playerSelected', ({ player: _player, source }) => {
173
- store.update(prev => ({
174
+ unsubscribers.push(controller.on("playerSelected", ({ player: _player, source }) => {
175
+ store.update((prev) => ({
174
176
  ...prev,
175
177
  currentPlayerInfo: controller.getCurrentPlayerInfo(),
176
178
  currentSourceInfo: { url: source.url, type: source.type },
177
179
  }));
178
180
  }));
179
- unsubscribers.push(controller.on('volumeChange', ({ volume, muted }) => {
180
- store.update(prev => ({ ...prev, volume, isMuted: muted }));
181
+ unsubscribers.push(controller.on("volumeChange", ({ volume, muted }) => {
182
+ store.update((prev) => ({ ...prev, volume, isMuted: muted }));
181
183
  }));
182
- unsubscribers.push(controller.on('loopChange', ({ isLoopEnabled }) => {
183
- store.update(prev => ({ ...prev, isLoopEnabled }));
184
+ unsubscribers.push(controller.on("loopChange", ({ isLoopEnabled }) => {
185
+ store.update((prev) => ({ ...prev, isLoopEnabled }));
184
186
  }));
185
- unsubscribers.push(controller.on('fullscreenChange', ({ isFullscreen }) => {
186
- store.update(prev => ({ ...prev, isFullscreen }));
187
+ unsubscribers.push(controller.on("fullscreenChange", ({ isFullscreen }) => {
188
+ store.update((prev) => ({ ...prev, isFullscreen }));
187
189
  }));
188
- unsubscribers.push(controller.on('pipChange', ({ isPiP }) => {
189
- store.update(prev => ({ ...prev, isPiPActive: isPiP }));
190
+ unsubscribers.push(controller.on("pipChange", ({ isPiP }) => {
191
+ store.update((prev) => ({ ...prev, isPiPActive: isPiP }));
190
192
  }));
191
- unsubscribers.push(controller.on('holdSpeedStart', ({ speed }) => {
192
- store.update(prev => ({ ...prev, isHoldingSpeed: true, holdSpeed: speed }));
193
+ unsubscribers.push(controller.on("holdSpeedStart", ({ speed }) => {
194
+ store.update((prev) => ({ ...prev, isHoldingSpeed: true, holdSpeed: speed }));
193
195
  }));
194
- unsubscribers.push(controller.on('holdSpeedEnd', () => {
195
- store.update(prev => ({ ...prev, isHoldingSpeed: false }));
196
+ unsubscribers.push(controller.on("holdSpeedEnd", () => {
197
+ store.update((prev) => ({ ...prev, isHoldingSpeed: false }));
196
198
  }));
197
- unsubscribers.push(controller.on('hoverStart', () => {
198
- store.update(prev => ({ ...prev, isHovering: true, shouldShowControls: true }));
199
+ unsubscribers.push(controller.on("hoverStart", () => {
200
+ store.update((prev) => ({ ...prev, isHovering: true, shouldShowControls: true }));
199
201
  }));
200
- unsubscribers.push(controller.on('hoverEnd', () => {
201
- store.update(prev => ({
202
+ unsubscribers.push(controller.on("hoverEnd", () => {
203
+ store.update((prev) => ({
202
204
  ...prev,
203
205
  isHovering: false,
204
206
  shouldShowControls: controller.shouldShowControls(),
205
207
  }));
206
208
  }));
207
- unsubscribers.push(controller.on('captionsChange', ({ enabled }) => {
208
- store.update(prev => ({ ...prev, subtitlesEnabled: enabled }));
209
+ unsubscribers.push(controller.on("captionsChange", ({ enabled }) => {
210
+ store.update((prev) => ({ ...prev, subtitlesEnabled: enabled }));
211
+ }));
212
+ // Error handling events - show toasts/modals
213
+ unsubscribers.push(controller.on("protocolSwapped", (data) => {
214
+ const message = `Switched to ${data.toProtocol}`;
215
+ store.update((prev) => ({ ...prev, toast: { message, timestamp: Date.now() } }));
216
+ }));
217
+ unsubscribers.push(controller.on("playbackFailed", (data) => {
218
+ store.update((prev) => ({
219
+ ...prev,
220
+ error: data.message,
221
+ errorDetails: data.details ?? null,
222
+ isPassiveError: false,
223
+ }));
209
224
  }));
210
225
  // Set initial loop state
211
- store.update(prev => ({
226
+ store.update((prev) => ({
212
227
  ...prev,
213
228
  isLoopEnabled: controller.isLoopEnabled(),
214
229
  }));
@@ -228,7 +243,7 @@ export function createPlayerControllerStore(config) {
228
243
  * Destroy the store and controller
229
244
  */
230
245
  function destroy() {
231
- unsubscribers.forEach(fn => fn());
246
+ unsubscribers.forEach((fn) => fn());
232
247
  unsubscribers = [];
233
248
  if (controller) {
234
249
  controller.destroy();
@@ -272,7 +287,15 @@ export function createPlayerControllerStore(config) {
272
287
  }
273
288
  function clearError() {
274
289
  controller?.clearError();
275
- store.update(prev => ({ ...prev, error: null, isPassiveError: false }));
290
+ store.update((prev) => ({
291
+ ...prev,
292
+ error: null,
293
+ errorDetails: null,
294
+ isPassiveError: false,
295
+ }));
296
+ }
297
+ function dismissToast() {
298
+ store.update((prev) => ({ ...prev, toast: null }));
276
299
  }
277
300
  async function retry() {
278
301
  await controller?.retry();
@@ -322,6 +345,7 @@ export function createPlayerControllerStore(config) {
322
345
  togglePiP,
323
346
  toggleSubtitles,
324
347
  clearError,
348
+ dismissToast,
325
349
  retry,
326
350
  reload,
327
351
  getQualities,
@@ -337,27 +361,27 @@ export function createPlayerControllerStore(config) {
337
361
  // Derived Stores (convenience)
338
362
  // ============================================================================
339
363
  export function createDerivedState(store) {
340
- return derived(store, $state => $state.state);
364
+ return derived(store, ($state) => $state.state);
341
365
  }
342
366
  export function createDerivedIsPlaying(store) {
343
- return derived(store, $state => $state.isPlaying);
367
+ return derived(store, ($state) => $state.isPlaying);
344
368
  }
345
369
  export function createDerivedCurrentTime(store) {
346
- return derived(store, $state => $state.currentTime);
370
+ return derived(store, ($state) => $state.currentTime);
347
371
  }
348
372
  export function createDerivedDuration(store) {
349
- return derived(store, $state => $state.duration);
373
+ return derived(store, ($state) => $state.duration);
350
374
  }
351
375
  export function createDerivedError(store) {
352
- return derived(store, $state => $state.error);
376
+ return derived(store, ($state) => $state.error);
353
377
  }
354
378
  export function createDerivedVideoElement(store) {
355
- return derived(store, $state => $state.videoElement);
379
+ return derived(store, ($state) => $state.videoElement);
356
380
  }
357
381
  export function createDerivedShouldShowControls(store) {
358
- return derived(store, $state => $state.shouldShowControls);
382
+ return derived(store, ($state) => $state.shouldShowControls);
359
383
  }
360
384
  export function createDerivedShouldShowIdleScreen(store) {
361
- return derived(store, $state => $state.shouldShowIdleScreen);
385
+ return derived(store, ($state) => $state.shouldShowIdleScreen);
362
386
  }
363
387
  export default createPlayerControllerStore;
@@ -4,8 +4,8 @@
4
4
  * Subscribes to PlayerManager events for reactive selection updates.
5
5
  * Uses event-driven updates instead of polling - no render spam.
6
6
  */
7
- import { type Readable } from 'svelte/store';
8
- import { type PlayerManager, type PlayerSelection, type PlayerCombination, type StreamInfo, type PlaybackMode } from '@livepeer-frameworks/player-core';
7
+ import { type Readable } from "svelte/store";
8
+ import { type PlayerManager, type PlayerSelection, type PlayerCombination, type StreamInfo, type PlaybackMode } from "@livepeer-frameworks/player-core";
9
9
  export interface PlayerSelectionOptions {
10
10
  /** Enable debug logging */
11
11
  debug?: boolean;
@@ -4,7 +4,7 @@
4
4
  * Subscribes to PlayerManager events for reactive selection updates.
5
5
  * Uses event-driven updates instead of polling - no render spam.
6
6
  */
7
- import { writable, derived } from 'svelte/store';
7
+ import { writable, derived } from "svelte/store";
8
8
  const initialState = {
9
9
  selection: null,
10
10
  combinations: [],
@@ -40,25 +40,25 @@ export function createPlayerSelectionStore(manager, options = {}) {
40
40
  const { debug = false } = options;
41
41
  const store = writable({ ...initialState });
42
42
  let currentStreamInfo = null;
43
- let currentPlaybackMode = 'auto';
43
+ let currentPlaybackMode = "auto";
44
44
  let unsubSelection = null;
45
45
  let unsubCombos = null;
46
46
  // Subscribe to PlayerManager events
47
47
  function subscribe() {
48
48
  // Clean up existing subscriptions
49
49
  unsubscribe();
50
- unsubSelection = manager.on('selection-changed', (sel) => {
50
+ unsubSelection = manager.on("selection-changed", (sel) => {
51
51
  if (debug) {
52
- console.log('[playerSelection store] Selection changed:', sel?.player, sel?.source?.type);
52
+ console.log("[playerSelection store] Selection changed:", sel?.player, sel?.source?.type);
53
53
  }
54
54
  store.update((state) => ({
55
55
  ...state,
56
56
  selection: sel,
57
57
  }));
58
58
  });
59
- unsubCombos = manager.on('combinations-updated', (combos) => {
59
+ unsubCombos = manager.on("combinations-updated", (combos) => {
60
60
  if (debug) {
61
- console.log('[playerSelection store] Combinations updated:', combos.length);
61
+ console.log("[playerSelection store] Combinations updated:", combos.length);
62
62
  }
63
63
  store.update((state) => ({
64
64
  ...state,
@@ -81,7 +81,7 @@ export function createPlayerSelectionStore(manager, options = {}) {
81
81
  */
82
82
  function setStreamInfo(streamInfo, playbackMode) {
83
83
  currentStreamInfo = streamInfo;
84
- currentPlaybackMode = playbackMode ?? 'auto';
84
+ currentPlaybackMode = playbackMode ?? "auto";
85
85
  if (!streamInfo) {
86
86
  store.set({ ...initialState });
87
87
  return;
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Port of useStreamState.ts React hook to Svelte 5 stores.
5
5
  */
6
- import { type Readable } from 'svelte/store';
7
- import type { StreamStatus, MistStreamInfo, StreamState } from '@livepeer-frameworks/player-core';
6
+ import { type Readable } from "svelte/store";
7
+ import type { StreamStatus, MistStreamInfo, StreamState } from "@livepeer-frameworks/player-core";
8
8
  export interface StreamStateOptions {
9
9
  mistBaseUrl: string;
10
10
  streamName: string;
@@ -3,56 +3,56 @@
3
3
  *
4
4
  * Port of useStreamState.ts React hook to Svelte 5 stores.
5
5
  */
6
- import { writable, derived } from 'svelte/store';
6
+ import { writable, derived } from "svelte/store";
7
7
  /**
8
8
  * Parse MistServer error string into StreamStatus enum
9
9
  */
10
10
  function parseErrorToStatus(error) {
11
11
  const lowerError = error.toLowerCase();
12
- if (lowerError.includes('offline'))
13
- return 'OFFLINE';
14
- if (lowerError.includes('initializing'))
15
- return 'INITIALIZING';
16
- if (lowerError.includes('booting'))
17
- return 'BOOTING';
18
- if (lowerError.includes('waiting for data'))
19
- return 'WAITING_FOR_DATA';
20
- if (lowerError.includes('shutting down'))
21
- return 'SHUTTING_DOWN';
22
- if (lowerError.includes('invalid'))
23
- return 'INVALID';
24
- return 'ERROR';
12
+ if (lowerError.includes("offline"))
13
+ return "OFFLINE";
14
+ if (lowerError.includes("initializing"))
15
+ return "INITIALIZING";
16
+ if (lowerError.includes("booting"))
17
+ return "BOOTING";
18
+ if (lowerError.includes("waiting for data"))
19
+ return "WAITING_FOR_DATA";
20
+ if (lowerError.includes("shutting down"))
21
+ return "SHUTTING_DOWN";
22
+ if (lowerError.includes("invalid"))
23
+ return "INVALID";
24
+ return "ERROR";
25
25
  }
26
26
  /**
27
27
  * Get human-readable message for stream status
28
28
  */
29
29
  function getStatusMessage(status, percentage) {
30
30
  switch (status) {
31
- case 'ONLINE':
32
- return 'Stream is online';
33
- case 'OFFLINE':
34
- return 'Stream is offline';
35
- case 'INITIALIZING':
31
+ case "ONLINE":
32
+ return "Stream is online";
33
+ case "OFFLINE":
34
+ return "Stream is offline";
35
+ case "INITIALIZING":
36
36
  return percentage !== undefined
37
37
  ? `Initializing... ${Math.round(percentage * 10) / 10}%`
38
- : 'Stream is initializing';
39
- case 'BOOTING':
40
- return 'Stream is starting up';
41
- case 'WAITING_FOR_DATA':
42
- return 'Waiting for stream data';
43
- case 'SHUTTING_DOWN':
44
- return 'Stream is shutting down';
45
- case 'INVALID':
46
- return 'Stream status is invalid';
47
- case 'ERROR':
38
+ : "Stream is initializing";
39
+ case "BOOTING":
40
+ return "Stream is starting up";
41
+ case "WAITING_FOR_DATA":
42
+ return "Waiting for stream data";
43
+ case "SHUTTING_DOWN":
44
+ return "Stream is shutting down";
45
+ case "INVALID":
46
+ return "Stream status is invalid";
47
+ case "ERROR":
48
48
  default:
49
- return 'Stream error';
49
+ return "Stream error";
50
50
  }
51
51
  }
52
52
  const initialState = {
53
- status: 'OFFLINE',
53
+ status: "OFFLINE",
54
54
  isOnline: false,
55
- message: 'Connecting...',
55
+ message: "Connecting...",
56
56
  lastUpdate: 0,
57
57
  };
58
58
  /**
@@ -93,7 +93,7 @@ export function createStreamStateManager(options) {
93
93
  if (data.error) {
94
94
  const status = parseErrorToStatus(data.error);
95
95
  const message = data.on_error || getStatusMessage(status, data.perc);
96
- store.update(prev => ({
96
+ store.update((prev) => ({
97
97
  status,
98
98
  isOnline: false,
99
99
  message,
@@ -105,7 +105,7 @@ export function createStreamStateManager(options) {
105
105
  }
106
106
  else {
107
107
  // Stream is online with valid metadata
108
- store.update(prev => {
108
+ store.update((prev) => {
109
109
  const mergedStreamInfo = {
110
110
  ...prev.streamInfo,
111
111
  ...data,
@@ -117,9 +117,9 @@ export function createStreamStateManager(options) {
117
117
  },
118
118
  };
119
119
  return {
120
- status: 'ONLINE',
120
+ status: "ONLINE",
121
121
  isOnline: true,
122
- message: 'Stream is online',
122
+ message: "Stream is online",
123
123
  lastUpdate: Date.now(),
124
124
  streamInfo: mergedStreamInfo,
125
125
  };
@@ -133,11 +133,11 @@ export function createStreamStateManager(options) {
133
133
  if (!mounted || !enabled)
134
134
  return;
135
135
  try {
136
- const baseUrl = `${mistBaseUrl.replace(/\/$/, '')}/json_${encodeURIComponent(streamName)}.js`;
136
+ const baseUrl = `${mistBaseUrl.replace(/\/$/, "")}/json_${encodeURIComponent(streamName)}.js`;
137
137
  const url = `${baseUrl}?metaeverywhere=1&inclzero=1`;
138
138
  const response = await fetch(url, {
139
- method: 'GET',
140
- headers: { 'Accept': 'application/json' },
139
+ method: "GET",
140
+ headers: { Accept: "application/json" },
141
141
  });
142
142
  if (!response.ok) {
143
143
  throw new Error(`HTTP ${response.status}`);
@@ -154,13 +154,13 @@ export function createStreamStateManager(options) {
154
154
  catch (error) {
155
155
  if (!mounted)
156
156
  return;
157
- store.update(prev => ({
157
+ store.update((prev) => ({
158
158
  ...prev,
159
- status: 'ERROR',
159
+ status: "ERROR",
160
160
  isOnline: false,
161
- message: error instanceof Error ? error.message : 'Connection failed',
161
+ message: error instanceof Error ? error.message : "Connection failed",
162
162
  lastUpdate: Date.now(),
163
- error: error instanceof Error ? error.message : 'Unknown error',
163
+ error: error instanceof Error ? error.message : "Unknown error",
164
164
  }));
165
165
  }
166
166
  // Schedule next poll
@@ -185,22 +185,22 @@ export function createStreamStateManager(options) {
185
185
  }
186
186
  try {
187
187
  const wsUrl = mistBaseUrl
188
- .replace(/^http:/, 'ws:')
189
- .replace(/^https:/, 'wss:')
190
- .replace(/\/$/, '');
188
+ .replace(/^http:/, "ws:")
189
+ .replace(/^https:/, "wss:")
190
+ .replace(/\/$/, "");
191
191
  const url = `${wsUrl}/json_${encodeURIComponent(streamName)}.js?metaeverywhere=1&inclzero=1`;
192
192
  const socket = new WebSocket(url);
193
193
  ws = socket;
194
194
  // Timeout: if no message within 5 seconds, fall back to HTTP
195
195
  wsTimeout = setTimeout(() => {
196
196
  if (socket.readyState <= WebSocket.OPEN) {
197
- console.debug('[streamState] WebSocket timeout (5s), falling back to HTTP');
197
+ console.debug("[streamState] WebSocket timeout (5s), falling back to HTTP");
198
198
  socket.close();
199
199
  pollHttp();
200
200
  }
201
201
  }, WS_TIMEOUT_MS);
202
202
  socket.onopen = () => {
203
- console.debug('[streamState] WebSocket connected');
203
+ console.debug("[streamState] WebSocket connected");
204
204
  socketReady.set(true);
205
205
  };
206
206
  socket.onmessage = (event) => {
@@ -213,11 +213,11 @@ export function createStreamStateManager(options) {
213
213
  processStreamInfo(data);
214
214
  }
215
215
  catch (e) {
216
- console.warn('[streamState] Failed to parse WebSocket message:', e);
216
+ console.warn("[streamState] Failed to parse WebSocket message:", e);
217
217
  }
218
218
  };
219
219
  socket.onerror = () => {
220
- console.warn('[streamState] WebSocket error, falling back to HTTP');
220
+ console.warn("[streamState] WebSocket error, falling back to HTTP");
221
221
  if (wsTimeout) {
222
222
  clearTimeout(wsTimeout);
223
223
  wsTimeout = null;
@@ -229,12 +229,12 @@ export function createStreamStateManager(options) {
229
229
  socketReady.set(false);
230
230
  if (!mounted || !enabled)
231
231
  return;
232
- console.debug('[streamState] WebSocket closed, starting HTTP polling');
232
+ console.debug("[streamState] WebSocket closed, starting HTTP polling");
233
233
  pollHttp();
234
234
  };
235
235
  }
236
236
  catch (error) {
237
- console.warn('[streamState] WebSocket connection failed:', error);
237
+ console.warn("[streamState] WebSocket connection failed:", error);
238
238
  pollHttp();
239
239
  }
240
240
  }
@@ -281,7 +281,7 @@ export function createStreamStateManager(options) {
281
281
  if (enabled && mistBaseUrl && streamName) {
282
282
  store.set({
283
283
  ...initialState,
284
- message: 'Connecting...',
284
+ message: "Connecting...",
285
285
  lastUpdate: Date.now(),
286
286
  });
287
287
  // Initial HTTP poll then WebSocket
@@ -303,12 +303,12 @@ export function createStreamStateManager(options) {
303
303
  }
304
304
  // Convenience derived stores for common values
305
305
  export function createDerivedStreamStatus(store) {
306
- return derived(store, $state => $state.status);
306
+ return derived(store, ($state) => $state.status);
307
307
  }
308
308
  export function createDerivedIsOnline(store) {
309
- return derived(store, $state => $state.isOnline);
309
+ return derived(store, ($state) => $state.isOnline);
310
310
  }
311
311
  export function createDerivedStreamInfo(store) {
312
- return derived(store, $state => $state.streamInfo);
312
+ return derived(store, ($state) => $state.streamInfo);
313
313
  }
314
314
  export default createStreamStateManager;
@@ -3,15 +3,15 @@
3
3
  *
4
4
  * Port of useViewerEndpoints.ts React hook to Svelte 5 stores.
5
5
  */
6
- import { type Readable } from 'svelte/store';
7
- import type { ContentEndpoints, ContentType } from '@livepeer-frameworks/player-core';
6
+ import { type Readable } from "svelte/store";
7
+ import type { ContentEndpoints, ContentType } from "@livepeer-frameworks/player-core";
8
8
  export interface ViewerEndpointsOptions {
9
9
  gatewayUrl: string;
10
10
  contentId: string;
11
11
  contentType?: ContentType;
12
12
  authToken?: string;
13
13
  }
14
- export type EndpointStatus = 'idle' | 'loading' | 'ready' | 'error';
14
+ export type EndpointStatus = "idle" | "loading" | "ready" | "error";
15
15
  export interface ViewerEndpointsState {
16
16
  endpoints: ContentEndpoints | null;
17
17
  status: EndpointStatus;