@livepeer-frameworks/player-svelte 0.0.3
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/dist/DevModePanel.svelte +650 -0
- package/dist/DevModePanel.svelte.d.ts +31 -0
- package/dist/DvdLogo.svelte +213 -0
- package/dist/DvdLogo.svelte.d.ts +7 -0
- package/dist/Icons.svelte +27 -0
- package/dist/Icons.svelte.d.ts +25 -0
- package/dist/IdleScreen.svelte +752 -0
- package/dist/IdleScreen.svelte.d.ts +11 -0
- package/dist/LoadingScreen.svelte +689 -0
- package/dist/LoadingScreen.svelte.d.ts +7 -0
- package/dist/Player.svelte +482 -0
- package/dist/Player.svelte.d.ts +26 -0
- package/dist/PlayerControls.svelte +739 -0
- package/dist/PlayerControls.svelte.d.ts +20 -0
- package/dist/SeekBar.svelte +274 -0
- package/dist/SeekBar.svelte.d.ts +25 -0
- package/dist/SkipIndicator.svelte +95 -0
- package/dist/SkipIndicator.svelte.d.ts +14 -0
- package/dist/SpeedIndicator.svelte +38 -0
- package/dist/SpeedIndicator.svelte.d.ts +8 -0
- package/dist/StatsPanel.svelte +155 -0
- package/dist/StatsPanel.svelte.d.ts +27 -0
- package/dist/StreamStateOverlay.svelte +266 -0
- package/dist/StreamStateOverlay.svelte.d.ts +18 -0
- package/dist/SubtitleRenderer.svelte +234 -0
- package/dist/SubtitleRenderer.svelte.d.ts +41 -0
- package/dist/ThumbnailOverlay.svelte +96 -0
- package/dist/ThumbnailOverlay.svelte.d.ts +11 -0
- package/dist/TitleOverlay.svelte +47 -0
- package/dist/TitleOverlay.svelte.d.ts +9 -0
- package/dist/assets/logomark.svg +56 -0
- package/dist/components/VolumeIcons.svelte +53 -0
- package/dist/components/VolumeIcons.svelte.d.ts +10 -0
- package/dist/global.d.ts +15 -0
- package/dist/icons/FullscreenExitIcon.svelte +33 -0
- package/dist/icons/FullscreenExitIcon.svelte.d.ts +8 -0
- package/dist/icons/FullscreenIcon.svelte +33 -0
- package/dist/icons/FullscreenIcon.svelte.d.ts +8 -0
- package/dist/icons/PauseIcon.svelte +28 -0
- package/dist/icons/PauseIcon.svelte.d.ts +8 -0
- package/dist/icons/PictureInPictureIcon.svelte +28 -0
- package/dist/icons/PictureInPictureIcon.svelte.d.ts +8 -0
- package/dist/icons/PlayIcon.svelte +27 -0
- package/dist/icons/PlayIcon.svelte.d.ts +8 -0
- package/dist/icons/SeekToLiveIcon.svelte +30 -0
- package/dist/icons/SeekToLiveIcon.svelte.d.ts +8 -0
- package/dist/icons/SettingsIcon.svelte +40 -0
- package/dist/icons/SettingsIcon.svelte.d.ts +8 -0
- package/dist/icons/SkipBackIcon.svelte +32 -0
- package/dist/icons/SkipBackIcon.svelte.d.ts +8 -0
- package/dist/icons/SkipForwardIcon.svelte +32 -0
- package/dist/icons/SkipForwardIcon.svelte.d.ts +8 -0
- package/dist/icons/StatsIcon.svelte +29 -0
- package/dist/icons/StatsIcon.svelte.d.ts +8 -0
- package/dist/icons/VolumeOffIcon.svelte +29 -0
- package/dist/icons/VolumeOffIcon.svelte.d.ts +8 -0
- package/dist/icons/VolumeUpIcon.svelte +34 -0
- package/dist/icons/VolumeUpIcon.svelte.d.ts +8 -0
- package/dist/icons/index.d.ts +17 -0
- package/dist/icons/index.js +17 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +54 -0
- package/dist/player.css +2 -0
- package/dist/stores/index.d.ts +15 -0
- package/dist/stores/index.js +21 -0
- package/dist/stores/playbackQuality.d.ts +43 -0
- package/dist/stores/playbackQuality.js +107 -0
- package/dist/stores/playerContext.d.ts +73 -0
- package/dist/stores/playerContext.js +166 -0
- package/dist/stores/playerController.d.ts +178 -0
- package/dist/stores/playerController.js +358 -0
- package/dist/stores/playerSelection.d.ts +84 -0
- package/dist/stores/playerSelection.js +159 -0
- package/dist/stores/streamState.d.ts +44 -0
- package/dist/stores/streamState.js +314 -0
- package/dist/stores/viewerEndpoints.d.ts +48 -0
- package/dist/stores/viewerEndpoints.js +178 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.js +4 -0
- package/dist/ui/Badge.svelte +21 -0
- package/dist/ui/Badge.svelte.d.ts +32 -0
- package/dist/ui/Button.svelte +42 -0
- package/dist/ui/Button.svelte.d.ts +35 -0
- package/dist/ui/Slider.svelte +100 -0
- package/dist/ui/Slider.svelte.d.ts +17 -0
- package/dist/ui/badge.d.ts +6 -0
- package/dist/ui/badge.js +10 -0
- package/dist/ui/button.d.ts +8 -0
- package/dist/ui/button.js +21 -0
- package/dist/ui/context-menu/ContextMenuCheckboxItem.svelte +34 -0
- package/dist/ui/context-menu/ContextMenuCheckboxItem.svelte.d.ts +31 -0
- package/dist/ui/context-menu/ContextMenuContent.svelte +17 -0
- package/dist/ui/context-menu/ContextMenuContent.svelte.d.ts +7 -0
- package/dist/ui/context-menu/ContextMenuItem.svelte +22 -0
- package/dist/ui/context-menu/ContextMenuItem.svelte.d.ts +8 -0
- package/dist/ui/context-menu/ContextMenuLabel.svelte +22 -0
- package/dist/ui/context-menu/ContextMenuLabel.svelte.d.ts +8 -0
- package/dist/ui/context-menu/ContextMenuPortal.svelte +11 -0
- package/dist/ui/context-menu/ContextMenuPortal.svelte.d.ts +6 -0
- package/dist/ui/context-menu/ContextMenuRadioItem.svelte +21 -0
- package/dist/ui/context-menu/ContextMenuRadioItem.svelte.d.ts +31 -0
- package/dist/ui/context-menu/ContextMenuSeparator.svelte +14 -0
- package/dist/ui/context-menu/ContextMenuSeparator.svelte.d.ts +6 -0
- package/dist/ui/context-menu/ContextMenuShortcut.svelte +19 -0
- package/dist/ui/context-menu/ContextMenuShortcut.svelte.d.ts +7 -0
- package/dist/ui/context-menu/ContextMenuSubContent.svelte +20 -0
- package/dist/ui/context-menu/ContextMenuSubContent.svelte.d.ts +7 -0
- package/dist/ui/context-menu/ContextMenuSubTrigger.svelte +34 -0
- package/dist/ui/context-menu/ContextMenuSubTrigger.svelte.d.ts +8 -0
- package/dist/ui/context-menu/index.d.ts +17 -0
- package/dist/ui/context-menu/index.js +17 -0
- package/package.json +51 -0
- package/src/DevModePanel.svelte +650 -0
- package/src/DvdLogo.svelte +213 -0
- package/src/Icons.svelte +27 -0
- package/src/IdleScreen.svelte +739 -0
- package/src/LoadingScreen.svelte +674 -0
- package/src/Player.svelte +483 -0
- package/src/PlayerControls.svelte +752 -0
- package/src/SeekBar.svelte +274 -0
- package/src/SkipIndicator.svelte +95 -0
- package/src/SpeedIndicator.svelte +37 -0
- package/src/StatsPanel.svelte +155 -0
- package/src/StreamStateOverlay.svelte +266 -0
- package/src/SubtitleRenderer.svelte +234 -0
- package/src/ThumbnailOverlay.svelte +96 -0
- package/src/TitleOverlay.svelte +47 -0
- package/src/assets/logomark.svg +56 -0
- package/src/components/VolumeIcons.svelte +53 -0
- package/src/global.d.ts +15 -0
- package/src/icons/FullscreenExitIcon.svelte +33 -0
- package/src/icons/FullscreenIcon.svelte +33 -0
- package/src/icons/PauseIcon.svelte +28 -0
- package/src/icons/PictureInPictureIcon.svelte +28 -0
- package/src/icons/PlayIcon.svelte +27 -0
- package/src/icons/SeekToLiveIcon.svelte +30 -0
- package/src/icons/SettingsIcon.svelte +40 -0
- package/src/icons/SkipBackIcon.svelte +32 -0
- package/src/icons/SkipForwardIcon.svelte +32 -0
- package/src/icons/StatsIcon.svelte +29 -0
- package/src/icons/VolumeOffIcon.svelte +29 -0
- package/src/icons/VolumeUpIcon.svelte +34 -0
- package/src/icons/index.ts +18 -0
- package/src/index.ts +84 -0
- package/src/player.css +2 -0
- package/src/stores/index.ts +88 -0
- package/src/stores/playbackQuality.ts +137 -0
- package/src/stores/playerContext.ts +221 -0
- package/src/stores/playerController.ts +568 -0
- package/src/stores/playerSelection.ts +216 -0
- package/src/stores/streamState.ts +367 -0
- package/src/stores/viewerEndpoints.ts +224 -0
- package/src/types.ts +6 -0
- package/src/ui/Badge.svelte +21 -0
- package/src/ui/Button.svelte +42 -0
- package/src/ui/Slider.svelte +100 -0
- package/src/ui/badge.ts +20 -0
- package/src/ui/button.ts +35 -0
- package/src/ui/context-menu/ContextMenuCheckboxItem.svelte +34 -0
- package/src/ui/context-menu/ContextMenuContent.svelte +17 -0
- package/src/ui/context-menu/ContextMenuItem.svelte +22 -0
- package/src/ui/context-menu/ContextMenuLabel.svelte +22 -0
- package/src/ui/context-menu/ContextMenuPortal.svelte +11 -0
- package/src/ui/context-menu/ContextMenuRadioItem.svelte +21 -0
- package/src/ui/context-menu/ContextMenuSeparator.svelte +14 -0
- package/src/ui/context-menu/ContextMenuShortcut.svelte +19 -0
- package/src/ui/context-menu/ContextMenuSubContent.svelte +20 -0
- package/src/ui/context-menu/ContextMenuSubTrigger.svelte +34 -0
- package/src/ui/context-menu/index.ts +36 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelte stores for player state management.
|
|
3
|
+
*
|
|
4
|
+
* These stores provide reactive state management for:
|
|
5
|
+
* - MistServer stream state polling (WebSocket/HTTP)
|
|
6
|
+
* - Gateway endpoint resolution (GraphQL)
|
|
7
|
+
* - Player instance context sharing
|
|
8
|
+
* - Playback quality monitoring
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Stream state (MistServer polling)
|
|
12
|
+
export {
|
|
13
|
+
createStreamStateManager,
|
|
14
|
+
createDerivedStreamStatus,
|
|
15
|
+
createDerivedIsOnline,
|
|
16
|
+
createDerivedStreamInfo,
|
|
17
|
+
type StreamStateOptions,
|
|
18
|
+
type StreamStateStore,
|
|
19
|
+
} from './streamState';
|
|
20
|
+
|
|
21
|
+
// Viewer endpoints (Gateway resolution)
|
|
22
|
+
export {
|
|
23
|
+
createEndpointResolver,
|
|
24
|
+
createDerivedEndpoints,
|
|
25
|
+
createDerivedPrimaryEndpoint,
|
|
26
|
+
createDerivedMetadata,
|
|
27
|
+
createDerivedStatus,
|
|
28
|
+
type ViewerEndpointsOptions,
|
|
29
|
+
type ViewerEndpointsStore,
|
|
30
|
+
type ViewerEndpointsState,
|
|
31
|
+
type EndpointStatus,
|
|
32
|
+
} from './viewerEndpoints';
|
|
33
|
+
|
|
34
|
+
// Player context (instance sharing)
|
|
35
|
+
export {
|
|
36
|
+
createPlayerContext,
|
|
37
|
+
setPlayerContextInComponent,
|
|
38
|
+
getPlayerContextFromComponent,
|
|
39
|
+
getPlayerContextOrFallback,
|
|
40
|
+
createDerivedVideoElement,
|
|
41
|
+
createDerivedIsReady,
|
|
42
|
+
createDerivedPlayerInfo,
|
|
43
|
+
type PlayerContextState,
|
|
44
|
+
type PlayerContextStore,
|
|
45
|
+
} from './playerContext';
|
|
46
|
+
|
|
47
|
+
// Playback quality monitoring
|
|
48
|
+
export {
|
|
49
|
+
createPlaybackQualityMonitor,
|
|
50
|
+
createDerivedQualityScore,
|
|
51
|
+
createDerivedStallCount,
|
|
52
|
+
createDerivedFrameDropRate,
|
|
53
|
+
createDerivedBitrate,
|
|
54
|
+
createDerivedLatency,
|
|
55
|
+
type PlaybackQualityOptions,
|
|
56
|
+
type PlaybackQualityStore,
|
|
57
|
+
} from './playbackQuality';
|
|
58
|
+
|
|
59
|
+
// Player selection (event-driven, cached)
|
|
60
|
+
export {
|
|
61
|
+
createPlayerSelectionStore,
|
|
62
|
+
createDerivedSelection,
|
|
63
|
+
createDerivedCombinations,
|
|
64
|
+
createDerivedReady,
|
|
65
|
+
createDerivedSelectedPlayer,
|
|
66
|
+
createDerivedSelectedSourceType,
|
|
67
|
+
createDerivedCompatibleCombinations,
|
|
68
|
+
createDerivedIncompatibleCombinations,
|
|
69
|
+
type PlayerSelectionOptions,
|
|
70
|
+
type PlayerSelectionState,
|
|
71
|
+
type PlayerSelectionStore,
|
|
72
|
+
} from './playerSelection';
|
|
73
|
+
|
|
74
|
+
// PlayerController store (central orchestrator)
|
|
75
|
+
export {
|
|
76
|
+
createPlayerControllerStore,
|
|
77
|
+
createDerivedState,
|
|
78
|
+
createDerivedIsPlaying,
|
|
79
|
+
createDerivedCurrentTime,
|
|
80
|
+
createDerivedDuration,
|
|
81
|
+
createDerivedError,
|
|
82
|
+
createDerivedVideoElement as createDerivedControllerVideoElement,
|
|
83
|
+
createDerivedShouldShowControls,
|
|
84
|
+
createDerivedShouldShowIdleScreen,
|
|
85
|
+
type PlayerControllerStoreConfig,
|
|
86
|
+
type PlayerControllerState,
|
|
87
|
+
type PlayerControllerStore,
|
|
88
|
+
} from './playerController';
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelte store for playback quality monitoring.
|
|
3
|
+
*
|
|
4
|
+
* Wraps QualityMonitor for reactive quality metrics.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { writable, derived, type Readable } from 'svelte/store';
|
|
8
|
+
import { QualityMonitor, type PlaybackQuality } from '@livepeer-frameworks/player-core';
|
|
9
|
+
|
|
10
|
+
export interface PlaybackQualityOptions {
|
|
11
|
+
sampleInterval?: number;
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface PlaybackQualityStore extends Readable<PlaybackQuality | null> {
|
|
16
|
+
start: (videoElement: HTMLVideoElement) => void;
|
|
17
|
+
stop: () => void;
|
|
18
|
+
getPlaybackScore: () => number;
|
|
19
|
+
destroy: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const initialQuality: PlaybackQuality = {
|
|
23
|
+
score: 100,
|
|
24
|
+
bitrate: 0,
|
|
25
|
+
bufferedAhead: 0,
|
|
26
|
+
frameDropRate: 0,
|
|
27
|
+
stallCount: 0,
|
|
28
|
+
latency: 0,
|
|
29
|
+
timestamp: Date.now(),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create a playback quality monitoring store.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```svelte
|
|
37
|
+
* <script>
|
|
38
|
+
* import { createPlaybackQualityMonitor } from './stores/playbackQuality';
|
|
39
|
+
*
|
|
40
|
+
* const quality = createPlaybackQualityMonitor();
|
|
41
|
+
*
|
|
42
|
+
* // Start monitoring when video element is available
|
|
43
|
+
* $: if (videoElement) quality.start(videoElement);
|
|
44
|
+
*
|
|
45
|
+
* // Access quality metrics
|
|
46
|
+
* $: score = $quality?.score ?? 100;
|
|
47
|
+
* $: stallCount = $quality?.stallCount ?? 0;
|
|
48
|
+
* </script>
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function createPlaybackQualityMonitor(options: PlaybackQualityOptions = {}): PlaybackQualityStore {
|
|
52
|
+
const { sampleInterval = 500, enabled = true } = options;
|
|
53
|
+
|
|
54
|
+
const store = writable<PlaybackQuality | null>(null);
|
|
55
|
+
let monitor: QualityMonitor | null = null;
|
|
56
|
+
let currentVideoElement: HTMLVideoElement | null = null;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Start monitoring a video element
|
|
60
|
+
*/
|
|
61
|
+
function start(videoElement: HTMLVideoElement) {
|
|
62
|
+
if (!enabled) return;
|
|
63
|
+
|
|
64
|
+
// Stop existing monitor if different element
|
|
65
|
+
if (currentVideoElement && currentVideoElement !== videoElement) {
|
|
66
|
+
stop();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
currentVideoElement = videoElement;
|
|
70
|
+
|
|
71
|
+
if (!monitor) {
|
|
72
|
+
monitor = new QualityMonitor({
|
|
73
|
+
sampleInterval,
|
|
74
|
+
onSample: (quality) => {
|
|
75
|
+
store.set(quality);
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
monitor.start(videoElement);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Stop monitoring
|
|
85
|
+
*/
|
|
86
|
+
function stop() {
|
|
87
|
+
monitor?.stop();
|
|
88
|
+
currentVideoElement = null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get current playback score
|
|
93
|
+
*/
|
|
94
|
+
function getPlaybackScore(): number {
|
|
95
|
+
return monitor?.getPlaybackScore() ?? 1.0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Cleanup
|
|
100
|
+
*/
|
|
101
|
+
function destroy() {
|
|
102
|
+
stop();
|
|
103
|
+
monitor = null;
|
|
104
|
+
store.set(null);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
subscribe: store.subscribe,
|
|
109
|
+
start,
|
|
110
|
+
stop,
|
|
111
|
+
getPlaybackScore,
|
|
112
|
+
destroy,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Convenience derived stores
|
|
117
|
+
export function createDerivedQualityScore(store: PlaybackQualityStore) {
|
|
118
|
+
return derived(store, $quality => $quality?.score ?? 100);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function createDerivedStallCount(store: PlaybackQualityStore) {
|
|
122
|
+
return derived(store, $quality => $quality?.stallCount ?? 0);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function createDerivedFrameDropRate(store: PlaybackQualityStore) {
|
|
126
|
+
return derived(store, $quality => $quality?.frameDropRate ?? 0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function createDerivedBitrate(store: PlaybackQualityStore) {
|
|
130
|
+
return derived(store, $quality => $quality?.bitrate ?? 0);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function createDerivedLatency(store: PlaybackQualityStore) {
|
|
134
|
+
return derived(store, $quality => $quality?.latency);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export default createPlaybackQualityMonitor;
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelte store for player instance context sharing.
|
|
3
|
+
*
|
|
4
|
+
* Port of PlayerContext.tsx React context to Svelte 5 stores.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { writable, derived, type Readable, type Writable } from 'svelte/store';
|
|
8
|
+
import { getContext, setContext } from 'svelte';
|
|
9
|
+
import { globalPlayerManager, type StreamInfo, type IPlayer } from '@livepeer-frameworks/player-core';
|
|
10
|
+
|
|
11
|
+
// Context key
|
|
12
|
+
const PLAYER_CONTEXT_KEY = Symbol('player-context');
|
|
13
|
+
|
|
14
|
+
export interface PlayerContextState {
|
|
15
|
+
/** Current video element (if available) */
|
|
16
|
+
videoElement: HTMLVideoElement | null;
|
|
17
|
+
/** Current player instance */
|
|
18
|
+
player: IPlayer | null;
|
|
19
|
+
/** Player name */
|
|
20
|
+
playerName: string | null;
|
|
21
|
+
/** Player shortname */
|
|
22
|
+
playerShortname: string | null;
|
|
23
|
+
/** Current source type */
|
|
24
|
+
sourceType: string | null;
|
|
25
|
+
/** Current source URL */
|
|
26
|
+
sourceUrl: string | null;
|
|
27
|
+
/** Whether player is ready */
|
|
28
|
+
isReady: boolean;
|
|
29
|
+
/** Current stream info */
|
|
30
|
+
streamInfo: StreamInfo | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface PlayerContextStore extends Readable<PlayerContextState> {
|
|
34
|
+
setVideoElement: (el: HTMLVideoElement | null) => void;
|
|
35
|
+
setPlayer: (player: IPlayer | null) => void;
|
|
36
|
+
setSource: (type: string | null, url: string | null) => void;
|
|
37
|
+
setStreamInfo: (info: StreamInfo | null) => void;
|
|
38
|
+
setReady: (ready: boolean) => void;
|
|
39
|
+
reset: () => void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const initialState: PlayerContextState = {
|
|
43
|
+
videoElement: null,
|
|
44
|
+
player: null,
|
|
45
|
+
playerName: null,
|
|
46
|
+
playerShortname: null,
|
|
47
|
+
sourceType: null,
|
|
48
|
+
sourceUrl: null,
|
|
49
|
+
isReady: false,
|
|
50
|
+
streamInfo: null,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create a player context store for sharing player state across components.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```svelte
|
|
58
|
+
* <!-- Parent component -->
|
|
59
|
+
* <script>
|
|
60
|
+
* import { createPlayerContext, setPlayerContext } from './stores/playerContext';
|
|
61
|
+
* const playerContext = createPlayerContext();
|
|
62
|
+
* setPlayerContext(playerContext);
|
|
63
|
+
* </script>
|
|
64
|
+
*
|
|
65
|
+
* <!-- Child component -->
|
|
66
|
+
* <script>
|
|
67
|
+
* import { getPlayerContext } from './stores/playerContext';
|
|
68
|
+
* const playerContext = getPlayerContext();
|
|
69
|
+
* $: videoEl = $playerContext.videoElement;
|
|
70
|
+
* </script>
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export function createPlayerContext(): PlayerContextStore {
|
|
74
|
+
const store = writable<PlayerContextState>(initialState);
|
|
75
|
+
|
|
76
|
+
function setVideoElement(el: HTMLVideoElement | null) {
|
|
77
|
+
store.update(s => ({ ...s, videoElement: el }));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function setPlayer(player: IPlayer | null) {
|
|
81
|
+
store.update(s => ({
|
|
82
|
+
...s,
|
|
83
|
+
player,
|
|
84
|
+
playerName: player?.capability.name ?? null,
|
|
85
|
+
playerShortname: player?.capability.shortname ?? null,
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function setSource(type: string | null, url: string | null) {
|
|
90
|
+
store.update(s => ({ ...s, sourceType: type, sourceUrl: url }));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function setStreamInfo(info: StreamInfo | null) {
|
|
94
|
+
store.update(s => ({ ...s, streamInfo: info }));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function setReady(ready: boolean) {
|
|
98
|
+
store.update(s => ({ ...s, isReady: ready }));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function reset() {
|
|
102
|
+
store.set(initialState);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
subscribe: store.subscribe,
|
|
107
|
+
setVideoElement,
|
|
108
|
+
setPlayer,
|
|
109
|
+
setSource,
|
|
110
|
+
setStreamInfo,
|
|
111
|
+
setReady,
|
|
112
|
+
reset,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Set player context in Svelte context (call in parent component)
|
|
118
|
+
*/
|
|
119
|
+
export function setPlayerContextInComponent(context: PlayerContextStore) {
|
|
120
|
+
setContext(PLAYER_CONTEXT_KEY, context);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get player context from Svelte context (call in child components)
|
|
125
|
+
*/
|
|
126
|
+
export function getPlayerContextFromComponent(): PlayerContextStore | undefined {
|
|
127
|
+
return getContext<PlayerContextStore>(PLAYER_CONTEXT_KEY);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get player context or create a fallback that uses globalPlayerManager
|
|
132
|
+
*/
|
|
133
|
+
export function getPlayerContextOrFallback(): PlayerContextStore {
|
|
134
|
+
const context = getContext<PlayerContextStore>(PLAYER_CONTEXT_KEY);
|
|
135
|
+
if (context) return context;
|
|
136
|
+
|
|
137
|
+
// Fallback: create a derived context from globalPlayerManager
|
|
138
|
+
return createFallbackContext();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Create a fallback context that reads from globalPlayerManager
|
|
143
|
+
* Uses event-driven updates instead of polling
|
|
144
|
+
*/
|
|
145
|
+
function createFallbackContext(): PlayerContextStore {
|
|
146
|
+
const store = writable<PlayerContextState>(initialState);
|
|
147
|
+
|
|
148
|
+
// Sync state from globalPlayerManager
|
|
149
|
+
function syncState() {
|
|
150
|
+
const player = globalPlayerManager.getCurrentPlayer();
|
|
151
|
+
const videoEl = player?.getVideoElement() ?? null;
|
|
152
|
+
|
|
153
|
+
store.update(s => ({
|
|
154
|
+
...s,
|
|
155
|
+
videoElement: videoEl,
|
|
156
|
+
player: player ?? null,
|
|
157
|
+
playerName: player?.capability.name ?? null,
|
|
158
|
+
playerShortname: player?.capability.shortname ?? null,
|
|
159
|
+
isReady: !!videoEl,
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Event handlers
|
|
164
|
+
const handleInitialized = () => syncState();
|
|
165
|
+
const handleSelectionChanged = () => syncState();
|
|
166
|
+
|
|
167
|
+
// Start/stop event listeners based on subscriber count
|
|
168
|
+
const originalSubscribe = store.subscribe;
|
|
169
|
+
let subscribers = 0;
|
|
170
|
+
|
|
171
|
+
const subscribe: typeof originalSubscribe = (run, invalidate) => {
|
|
172
|
+
subscribers++;
|
|
173
|
+
if (subscribers === 1) {
|
|
174
|
+
// Initial sync
|
|
175
|
+
syncState();
|
|
176
|
+
// Subscribe to events
|
|
177
|
+
globalPlayerManager.on('playerInitialized', handleInitialized);
|
|
178
|
+
globalPlayerManager.on('selection-changed', handleSelectionChanged);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const unsubscribe = originalSubscribe(run, invalidate);
|
|
182
|
+
|
|
183
|
+
return () => {
|
|
184
|
+
unsubscribe();
|
|
185
|
+
subscribers--;
|
|
186
|
+
if (subscribers === 0) {
|
|
187
|
+
// Unsubscribe from events
|
|
188
|
+
globalPlayerManager.off('playerInitialized', handleInitialized);
|
|
189
|
+
globalPlayerManager.off('selection-changed', handleSelectionChanged);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
subscribe,
|
|
196
|
+
setVideoElement: () => {},
|
|
197
|
+
setPlayer: () => {},
|
|
198
|
+
setSource: () => {},
|
|
199
|
+
setStreamInfo: () => {},
|
|
200
|
+
setReady: () => {},
|
|
201
|
+
reset: () => {},
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Convenience derived stores
|
|
206
|
+
export function createDerivedVideoElement(store: PlayerContextStore) {
|
|
207
|
+
return derived(store, $state => $state.videoElement);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function createDerivedIsReady(store: PlayerContextStore) {
|
|
211
|
+
return derived(store, $state => $state.isReady);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function createDerivedPlayerInfo(store: PlayerContextStore) {
|
|
215
|
+
return derived(store, $state => ({
|
|
216
|
+
name: $state.playerName,
|
|
217
|
+
shortname: $state.playerShortname,
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export default createPlayerContext;
|