@viostream/viostream-player-svelte 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 ADDED
@@ -0,0 +1,456 @@
1
+ # viostream-player-svelte
2
+
3
+ Svelte 5 SDK for the [Viostream](https://www.viostream.com) video player. Embed, control, and listen to player events with full TypeScript support.
4
+
5
+ ## Requirements
6
+
7
+ - Svelte 5
8
+ - A Viostream account key (found on the **Settings > General** page in Viostream)
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install viostream-player-svelte
14
+ ```
15
+
16
+ ## Quick Start
17
+
18
+ ### Component
19
+
20
+ Drop a `<ViostreamPlayer>` into any Svelte component. The SDK loads the Viostream script automatically.
21
+
22
+ ```svelte
23
+ <script lang="ts">
24
+ import { ViostreamPlayer } from 'viostream-player-svelte';
25
+ </script>
26
+
27
+ <ViostreamPlayer
28
+ accountKey="vc-100100100"
29
+ publicKey="nhedxonrxsyfee"
30
+ displayTitle={true}
31
+ sharing={true}
32
+ onplay={() => console.log('playing')}
33
+ />
34
+ ```
35
+
36
+ ### Headless / Programmatic
37
+
38
+ Use `createViostreamPlayer` when you need full control without a component:
39
+
40
+ ```ts
41
+ import { createViostreamPlayer } from 'viostream-player-svelte';
42
+
43
+ const player = await createViostreamPlayer({
44
+ accountKey: 'vc-100100100',
45
+ publicKey: 'nhedxonrxsyfee',
46
+ target: 'my-video-div', // element id or HTMLElement
47
+ options: { displayTitle: true }
48
+ });
49
+
50
+ player.play();
51
+ ```
52
+
53
+ ---
54
+
55
+ ## `<ViostreamPlayer>` Component
56
+
57
+ ### Props
58
+
59
+ #### Required
60
+
61
+ | Prop | Type | Description |
62
+ |---|---|---|
63
+ | `accountKey` | `string` | Your Viostream account key (e.g. `'vc-100100100'`). |
64
+ | `publicKey` | `string` | The public key of the media asset to embed. |
65
+
66
+ #### Embed Options
67
+
68
+ All embed options are optional and passed directly to the Viostream embed API.
69
+
70
+ | Prop | Type | Description |
71
+ |---|---|---|
72
+ | `chapters` | `boolean` | Display chapter markers. |
73
+ | `chapterDisplayType` | `'dropdown' \| 'progressbar' \| 'horizontal'` | Chapter display style. |
74
+ | `chapterSlug` | `string` | Seek to a named chapter before playback. |
75
+ | `displayTitle` | `boolean` | Show the video title overlay. |
76
+ | `hlsQualitySelector` | `boolean` | Show the HLS quality selector. |
77
+ | `playerKey` | `string` | Override the player theme to use. |
78
+ | `sharing` | `boolean` | Show sharing controls. |
79
+ | `speedSelector` | `boolean` | Show playback speed selector. |
80
+ | `startEndTimespan` | `string` | Play a specific section (e.g. `'10,30'`). |
81
+ | `startTime` | `string` | Seek to a time (seconds) before playback. |
82
+ | `transcriptDownload` | `boolean` | Allow transcript download. |
83
+
84
+ #### Event Callbacks
85
+
86
+ | Prop | Signature | Fires when |
87
+ |---|---|---|
88
+ | `onplay` | `() => void` | Playback starts or resumes. |
89
+ | `onpause` | `() => void` | Playback is paused. |
90
+ | `onended` | `() => void` | Media finishes playing. |
91
+ | `ontimeupdate` | `(data: ViostreamTimeUpdateData) => void` | Current time changes. `data.seconds`, `data.duration`. |
92
+ | `onvolumechange` | `(data: ViostreamVolumeChangeData) => void` | Volume changes. `data.volume`. |
93
+ | `onerror` | `(data: ViostreamErrorData) => void` | An error occurs. `data.code`, `data.message`. |
94
+ | `onprogress` | `(data: ViostreamProgressData) => void` | Buffering progress. `data.percent`. |
95
+ | `onready` | `() => void` | Player is ready. |
96
+ | `onseeked` | `() => void` | Seek operation completes. |
97
+ | `onloaded` | `() => void` | Metadata has loaded. |
98
+
99
+ #### Other Props
100
+
101
+ | Prop | Type | Description |
102
+ |---|---|---|
103
+ | `class` | `string` | CSS class applied to the outer wrapper `<div>`. |
104
+ | `onplayerready` | `(player: ViostreamPlayerInstance) => void` | Callback providing the player instance for programmatic control. |
105
+ | `loading` | `Snippet` | Optional Svelte 5 snippet rendered while the player is loading. |
106
+ | `error` | `Snippet<[string]>` | Optional snippet rendered on error. Receives the error message as an argument. |
107
+
108
+ ### Getting the Player Instance
109
+
110
+ Use `onplayerready` to get a reference to the player for programmatic control:
111
+
112
+ ```svelte
113
+ <script lang="ts">
114
+ import { ViostreamPlayer } from 'viostream-player-svelte';
115
+ import type { ViostreamPlayerInstance } from 'viostream-player-svelte';
116
+
117
+ let player: ViostreamPlayerInstance | undefined = $state();
118
+ </script>
119
+
120
+ <ViostreamPlayer
121
+ accountKey="vc-100100100"
122
+ publicKey="nhedxonrxsyfee"
123
+ onplayerready={(p) => (player = p)}
124
+ />
125
+
126
+ <button onclick={() => player?.play()}>Play</button>
127
+ <button onclick={() => player?.pause()}>Pause</button>
128
+ ```
129
+
130
+ ### Custom Loading and Error States
131
+
132
+ Use Svelte 5 snippets to replace the default loading/error UI:
133
+
134
+ ```svelte
135
+ <ViostreamPlayer
136
+ accountKey="vc-100100100"
137
+ publicKey="nhedxonrxsyfee"
138
+ >
139
+ {#snippet loading()}
140
+ <p>Loading video...</p>
141
+ {/snippet}
142
+
143
+ {#snippet error(message)}
144
+ <div class="my-error">Something went wrong: {message}</div>
145
+ {/snippet}
146
+ </ViostreamPlayer>
147
+ ```
148
+
149
+ ### Cleanup
150
+
151
+ The player is destroyed automatically when the component unmounts. All event listeners are cleaned up and the player iframe is removed from the DOM.
152
+
153
+ ---
154
+
155
+ ## `createViostreamPlayer()`
156
+
157
+ For use outside of Svelte components or when you need full lifecycle control.
158
+
159
+ ```ts
160
+ import { createViostreamPlayer } from 'viostream-player-svelte';
161
+ import type { CreateViostreamPlayerOptions } from 'viostream-player-svelte';
162
+
163
+ const player = await createViostreamPlayer({
164
+ accountKey: 'vc-100100100',
165
+ publicKey: 'nhedxonrxsyfee',
166
+ target: 'my-video-div', // element id (string) or HTMLElement
167
+ options: {
168
+ displayTitle: true,
169
+ sharing: true,
170
+ speedSelector: true
171
+ }
172
+ });
173
+ ```
174
+
175
+ ### Options
176
+
177
+ | Property | Type | Description |
178
+ |---|---|---|
179
+ | `accountKey` | `string` | Your Viostream account key. |
180
+ | `publicKey` | `string` | Public key of the media asset. |
181
+ | `target` | `string \| HTMLElement` | Container element id or direct DOM reference. |
182
+ | `options` | `ViostreamEmbedOptions` | Embed options (same as component props above). |
183
+
184
+ ---
185
+
186
+ ## Player Instance API
187
+
188
+ Both the component (via `onplayerready`) and `createViostreamPlayer()` provide a `ViostreamPlayerInstance` with the following methods.
189
+
190
+ ### Playback Controls
191
+
192
+ ```ts
193
+ player.play();
194
+ player.pause();
195
+ player.mute();
196
+ player.unmute();
197
+ player.setVolume(0.5); // 0 to 1
198
+ player.setLoop(true);
199
+ player.setCurrentTime(30); // seek to 30 seconds
200
+ player.setCurrentTime(30, true); // seek and auto-play
201
+ player.reload(); // reload the player
202
+ player.reload({ key: 'value' }); // reload with new settings
203
+ ```
204
+
205
+ ### Getters (Promise-based)
206
+
207
+ All getters return promises. The SDK converts the underlying callback-based API to `async`/`await`.
208
+
209
+ ```ts
210
+ const volume = await player.getVolume(); // number (0–1)
211
+ const loop = await player.getLoop(); // boolean
212
+ const time = await player.getCurrentTime(); // number (seconds)
213
+ const paused = await player.getPaused(); // boolean
214
+ const duration = await player.getDuration(); // number (seconds)
215
+ const muted = await player.getMuted(); // boolean
216
+ const ratio = await player.getAspectRatio(); // number
217
+ const liveTime = await player.getLiveCurrentTime(); // number (seconds)
218
+ const height = await player.getHeight(); // number (pixels)
219
+ const tracks = await player.getTracks(); // ViostreamTrack[]
220
+ ```
221
+
222
+ ### Track Management
223
+
224
+ ```ts
225
+ const tracks = await player.getTracks();
226
+ player.setTrack(tracks[0]); // pass a ViostreamTrack object
227
+ player.setTrack('en'); // or a track id string
228
+ ```
229
+
230
+ ### Cue Management
231
+
232
+ ```ts
233
+ player.cueAdd({ startTime: 10, text: 'Introduction' });
234
+
235
+ player.cueUpdate(
236
+ { startTime: 10, text: 'Introduction' },
237
+ { text: 'Updated Introduction' }
238
+ );
239
+
240
+ player.cueDelete('cue-id');
241
+ ```
242
+
243
+ ### Automatic Speech Recognition (ASR)
244
+
245
+ ```ts
246
+ player.asrAdd(cueArray, 'asr-track-id');
247
+ ```
248
+
249
+ ### Events
250
+
251
+ Subscribe to player events with `on()`. It returns an unsubscribe function.
252
+
253
+ ```ts
254
+ // Subscribe
255
+ const unsubscribe = player.on('timeupdate', (data) => {
256
+ console.log(`${data.seconds}s / ${data.duration}s`);
257
+ });
258
+
259
+ // Unsubscribe later
260
+ unsubscribe();
261
+
262
+ // Or use off() directly
263
+ const handler = () => console.log('paused');
264
+ player.on('pause', handler);
265
+ player.off('pause', handler);
266
+ ```
267
+
268
+ #### Available Events
269
+
270
+ | Event | Callback Data | Description |
271
+ |---|---|---|
272
+ | `play` | `void` | Playback started or resumed. |
273
+ | `pause` | `void` | Playback paused. |
274
+ | `ended` | `void` | Media finished playing. |
275
+ | `timeupdate` | `{ seconds: number, duration: number }` | Playback time changed. |
276
+ | `volumechange` | `{ volume: number }` | Volume changed. |
277
+ | `error` | `{ code?: number, message?: string }` | Error occurred. |
278
+ | `progress` | `{ percent: number }` | Buffering progress. |
279
+ | `ready` | `void` | Player is ready. |
280
+ | `seeked` | `void` | Seek completed. |
281
+ | `loaded` | `void` | Metadata loaded. |
282
+
283
+ Custom event names are also accepted via the string index signature:
284
+
285
+ ```ts
286
+ player.on('my-custom-event', (data) => {
287
+ console.log(data);
288
+ });
289
+ ```
290
+
291
+ ### Destroy
292
+
293
+ When using `createViostreamPlayer()`, you are responsible for cleanup:
294
+
295
+ ```ts
296
+ player.destroy();
297
+ ```
298
+
299
+ After calling `destroy()`:
300
+ - All event listeners are removed.
301
+ - The player iframe is removed from the DOM.
302
+ - Getter calls will reject with `"Player has been destroyed"`.
303
+ - `player.raw` returns `undefined`.
304
+
305
+ ### Raw Escape Hatch
306
+
307
+ If you need direct access to the underlying Viostream player instance:
308
+
309
+ ```ts
310
+ const raw = player.raw; // RawViostreamPlayerInstance | undefined
311
+ if (raw) {
312
+ raw.getVolume((vol) => console.log(vol)); // callback-based original API
313
+ }
314
+ ```
315
+
316
+ ---
317
+
318
+ ## Script Loader
319
+
320
+ The SDK loads the Viostream API script automatically. If you need manual control over loading (e.g. preloading), you can use `loadViostream` directly:
321
+
322
+ ```ts
323
+ import { loadViostream } from 'viostream-player-svelte';
324
+
325
+ const api = await loadViostream('vc-100100100');
326
+ // api.embed(...) is now available
327
+ ```
328
+
329
+ The loader:
330
+ - Injects `<script src="https://play.viostream.com/api/{accountKey}">` into `<head>`.
331
+ - Deduplicates requests -- calling it multiple times with the same key returns the same promise.
332
+ - Times out after 15 seconds if the script fails to load.
333
+ - Detects if the script tag already exists in the DOM (e.g. added manually) and waits for it.
334
+
335
+ ---
336
+
337
+ ## TypeScript
338
+
339
+ Every export is fully typed. Import types alongside runtime exports:
340
+
341
+ ```ts
342
+ import { ViostreamPlayer, createViostreamPlayer } from 'viostream-player-svelte';
343
+ import type {
344
+ ViostreamPlayerInstance,
345
+ ViostreamPlayerProps,
346
+ ViostreamEmbedOptions,
347
+ ViostreamTimeUpdateData,
348
+ ViostreamVolumeChangeData,
349
+ ViostreamErrorData,
350
+ ViostreamProgressData,
351
+ ViostreamPlayerEventMap,
352
+ ViostreamEventHandler,
353
+ ViostreamCue,
354
+ ViostreamCueFieldUpdate,
355
+ ViostreamTrack,
356
+ CreateViostreamPlayerOptions,
357
+ RawViostreamPlayerInstance,
358
+ ViostreamGlobal
359
+ } from 'viostream-player-svelte';
360
+ ```
361
+
362
+ ---
363
+
364
+ ## Full Example
365
+
366
+ A complete example showing the component with custom controls, event logging, and async getters:
367
+
368
+ ```svelte
369
+ <script lang="ts">
370
+ import { ViostreamPlayer } from 'viostream-player-svelte';
371
+ import type { ViostreamPlayerInstance, ViostreamTimeUpdateData } from 'viostream-player-svelte';
372
+
373
+ let player: ViostreamPlayerInstance | undefined = $state();
374
+ let currentTime = $state(0);
375
+ let duration = $state(0);
376
+ let paused = $state(true);
377
+ let log: string[] = $state([]);
378
+
379
+ function handleReady(p: ViostreamPlayerInstance) {
380
+ player = p;
381
+ p.getDuration().then((d) => (duration = d));
382
+ }
383
+
384
+ function handleTimeUpdate(data: ViostreamTimeUpdateData) {
385
+ currentTime = data.seconds;
386
+ duration = data.duration;
387
+ }
388
+
389
+ function format(s: number): string {
390
+ return `${Math.floor(s / 60)}:${Math.floor(s % 60).toString().padStart(2, '0')}`;
391
+ }
392
+ </script>
393
+
394
+ <ViostreamPlayer
395
+ accountKey="vc-100100100"
396
+ publicKey="nhedxonrxsyfee"
397
+ displayTitle={true}
398
+ sharing={true}
399
+ speedSelector={true}
400
+ hlsQualitySelector={true}
401
+ onplay={() => { paused = false; log = ['play', ...log]; }}
402
+ onpause={() => { paused = true; log = ['pause', ...log]; }}
403
+ onended={() => { log = ['ended', ...log]; }}
404
+ ontimeupdate={handleTimeUpdate}
405
+ onplayerready={handleReady}
406
+ />
407
+
408
+ <div>
409
+ <button onclick={() => paused ? player?.play() : player?.pause()}>
410
+ {paused ? 'Play' : 'Pause'}
411
+ </button>
412
+ <button onclick={() => player?.setCurrentTime(0)}>Restart</button>
413
+ <span>{format(currentTime)} / {format(duration)}</span>
414
+ </div>
415
+
416
+ <div>
417
+ <button onclick={async () => {
418
+ const vol = await player?.getVolume();
419
+ log = [`volume: ${vol}`, ...log];
420
+ }}>Get Volume</button>
421
+ <button onclick={async () => {
422
+ const tracks = await player?.getTracks();
423
+ log = [`tracks: ${JSON.stringify(tracks)}`, ...log];
424
+ }}>Get Tracks</button>
425
+ </div>
426
+
427
+ <pre>{log.join('\n')}</pre>
428
+ ```
429
+
430
+ ---
431
+
432
+ ## Development
433
+
434
+ ```bash
435
+ # Install dependencies
436
+ npm install
437
+
438
+ # Start the dev server (serves the demo page)
439
+ npm run dev
440
+
441
+ # Type-check
442
+ npm run check
443
+
444
+ # Run tests
445
+ npm run test
446
+
447
+ # Run tests in watch mode
448
+ npm run test:watch
449
+
450
+ # Build the library for publishing
451
+ npm run package
452
+ ```
453
+
454
+ ## License
455
+
456
+ MIT
@@ -0,0 +1,222 @@
1
+ <!--
2
+ @component ViostreamPlayer
3
+
4
+ Svelte 5 component that embeds a Viostream video player.
5
+
6
+ Usage:
7
+ ```svelte
8
+ <script lang="ts">
9
+ import { ViostreamPlayer } from '@viostream/viostream-player-svelte';
10
+ import type { ViostreamPlayer as ViostreamPlayerType } from '@viostream/viostream-player-svelte';
11
+
12
+ let player: ViostreamPlayerType | undefined = $state();
13
+ </script>
14
+
15
+ <ViostreamPlayer
16
+ accountKey="vc-100100100"
17
+ publicKey="nhedxonrxsyfee"
18
+ displayTitle={true}
19
+ sharing={true}
20
+ onplay={() => console.log('playing!')}
21
+ ontimeupdate={(d) => console.log('time:', d.seconds)}
22
+ onplayerready={(p) => (player = p)}
23
+ />
24
+ ```
25
+ -->
26
+ <script lang="ts">
27
+ import { onMount, type Snippet } from 'svelte';
28
+ import { loadViostream, wrapRawPlayer } from '@viostream/viostream-player-core';
29
+ import type {
30
+ ViostreamEmbedOptions,
31
+ ViostreamPlayer,
32
+ RawViostreamPlayerInstance,
33
+ ViostreamEventHandler,
34
+ } from '@viostream/viostream-player-core';
35
+ import type { ViostreamPlayerProps } from './types.js';
36
+
37
+ let {
38
+ // Required props
39
+ accountKey,
40
+ publicKey,
41
+
42
+ // Embed options
43
+ chapters,
44
+ chapterDisplayType,
45
+ chapterSlug,
46
+ displayTitle,
47
+ hlsQualitySelector,
48
+ playerKey,
49
+ sharing,
50
+ speedSelector,
51
+ startEndTimespan,
52
+ startTime,
53
+ transcriptDownload,
54
+
55
+ // Event callbacks
56
+ onplay,
57
+ onpause,
58
+ onended,
59
+ ontimeupdate,
60
+ onvolumechange,
61
+ onerror,
62
+ onprogress,
63
+ onready,
64
+ onseeked,
65
+ onloaded,
66
+
67
+ // Component callbacks
68
+ onplayerready,
69
+
70
+ // Snippet overrides
71
+ loading: loadingSnippet,
72
+ error: errorSnippet,
73
+
74
+ // Styling
75
+ class: className,
76
+
77
+ // Spread rest for future-proofing
78
+ ...restProps
79
+ }: ViostreamPlayerProps & {
80
+ loading?: Snippet;
81
+ error?: Snippet<[string]>;
82
+ } = $props();
83
+
84
+ // Internal state
85
+ let containerEl: HTMLDivElement | undefined = $state();
86
+ let player: ViostreamPlayer | undefined = $state();
87
+ let errorMsg: string | undefined = $state();
88
+ let isLoading = $state(true);
89
+
90
+ // Unique ID for the container
91
+ const containerId = `viostream-player-${Math.random().toString(36).slice(2, 10)}`;
92
+
93
+ // Build the embed options object from props
94
+ function buildEmbedOptions(): ViostreamEmbedOptions {
95
+ const opts: ViostreamEmbedOptions = {};
96
+ if (chapters !== undefined) opts.chapters = chapters;
97
+ if (chapterDisplayType !== undefined) opts.chapterDisplayType = chapterDisplayType;
98
+ if (chapterSlug !== undefined) opts.chapterSlug = chapterSlug;
99
+ if (displayTitle !== undefined) opts.displayTitle = displayTitle;
100
+ if (hlsQualitySelector !== undefined) opts.hlsQualitySelector = hlsQualitySelector;
101
+ if (playerKey !== undefined) opts.playerKey = playerKey;
102
+ if (sharing !== undefined) opts.sharing = sharing;
103
+ if (speedSelector !== undefined) opts.speedSelector = speedSelector;
104
+ if (startEndTimespan !== undefined) opts.startEndTimespan = startEndTimespan;
105
+ if (startTime !== undefined) opts.startTime = startTime;
106
+ if (transcriptDownload !== undefined) opts.transcriptDownload = transcriptDownload;
107
+ return opts;
108
+ }
109
+
110
+ // Event wiring: maps event names to their prop callbacks
111
+ const EVENT_MAP: Array<[string, (() => ViostreamEventHandler | undefined)]> = [
112
+ ['play', () => onplay as ViostreamEventHandler | undefined],
113
+ ['pause', () => onpause as ViostreamEventHandler | undefined],
114
+ ['ended', () => onended as ViostreamEventHandler | undefined],
115
+ ['timeupdate', () => ontimeupdate as ViostreamEventHandler | undefined],
116
+ ['volumechange', () => onvolumechange as ViostreamEventHandler | undefined],
117
+ ['error', () => onerror as ViostreamEventHandler | undefined],
118
+ ['progress', () => onprogress as ViostreamEventHandler | undefined],
119
+ ['ready', () => onready as ViostreamEventHandler | undefined],
120
+ ['seeked', () => onseeked as ViostreamEventHandler | undefined],
121
+ ['loaded', () => onloaded as ViostreamEventHandler | undefined]
122
+ ];
123
+
124
+ onMount(() => {
125
+ let destroyed = false;
126
+ const unsubscribers: Array<() => void> = [];
127
+
128
+ async function init() {
129
+ try {
130
+ const api = await loadViostream(accountKey);
131
+
132
+ if (destroyed) return;
133
+
134
+ const embedOpts = buildEmbedOptions();
135
+ const raw: RawViostreamPlayerInstance = api.embed(publicKey, containerId, embedOpts);
136
+ const wrappedPlayer = wrapRawPlayer(raw, containerId);
137
+
138
+ if (destroyed) {
139
+ wrappedPlayer.destroy();
140
+ return;
141
+ }
142
+
143
+ player = wrappedPlayer;
144
+ isLoading = false;
145
+
146
+ // Wire up event callbacks from props
147
+ for (const [eventName, getHandler] of EVENT_MAP) {
148
+ const handler = getHandler();
149
+ if (handler) {
150
+ const unsub = wrappedPlayer.on(eventName, handler);
151
+ unsubscribers.push(unsub);
152
+ }
153
+ }
154
+
155
+ // Notify consumer that the player is ready
156
+ onplayerready?.(wrappedPlayer);
157
+ } catch (err) {
158
+ if (!destroyed) {
159
+ errorMsg = err instanceof Error ? err.message : String(err);
160
+ isLoading = false;
161
+ }
162
+ }
163
+ }
164
+
165
+ init();
166
+
167
+ return () => {
168
+ destroyed = true;
169
+ for (const unsub of unsubscribers) {
170
+ unsub();
171
+ }
172
+ player?.destroy();
173
+ player = undefined;
174
+ };
175
+ });
176
+
177
+ // Re-wire event handlers reactively when callback props change
178
+ // This handles the case where a consumer conditionally provides callbacks
179
+ $effect(() => {
180
+ if (!player) return;
181
+
182
+ const currentUnsubscribers: Array<() => void> = [];
183
+
184
+ for (const [eventName, getHandler] of EVENT_MAP) {
185
+ const handler = getHandler();
186
+ if (handler) {
187
+ const unsub = player.on(eventName, handler);
188
+ currentUnsubscribers.push(unsub);
189
+ }
190
+ }
191
+
192
+ return () => {
193
+ for (const unsub of currentUnsubscribers) {
194
+ unsub();
195
+ }
196
+ };
197
+ });
198
+ </script>
199
+
200
+ <div
201
+ id={containerId}
202
+ class={className}
203
+ bind:this={containerEl}
204
+ data-viostream-player
205
+ data-viostream-public-key={publicKey}
206
+ >
207
+ {#if isLoading}
208
+ {#if loadingSnippet}
209
+ {@render loadingSnippet()}
210
+ {/if}
211
+ {/if}
212
+
213
+ {#if errorMsg}
214
+ {#if errorSnippet}
215
+ {@render errorSnippet(errorMsg)}
216
+ {:else}
217
+ <div data-viostream-error style="color: red; padding: 1em;">
218
+ Failed to load Viostream player: {errorMsg}
219
+ </div>
220
+ {/if}
221
+ {/if}
222
+ </div>
@@ -0,0 +1,35 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { ViostreamPlayer } from '@viostream/viostream-player-core';
3
+ import type { ViostreamPlayerProps } from './types.js';
4
+ type $$ComponentProps = ViostreamPlayerProps & {
5
+ loading?: Snippet;
6
+ error?: Snippet<[string]>;
7
+ };
8
+ /**
9
+ * ViostreamPlayer
10
+ *
11
+ * Svelte 5 component that embeds a Viostream video player.
12
+ *
13
+ * Usage:
14
+ * ```svelte
15
+ * <script lang="ts">
16
+ * import { ViostreamPlayer } from '@viostream/viostream-player-svelte';
17
+ * import type { ViostreamPlayer as ViostreamPlayerType } from '@viostream/viostream-player-svelte';
18
+ *
19
+ * let player: ViostreamPlayerType | undefined = $state();
20
+ * </script>
21
+ *
22
+ * <ViostreamPlayer
23
+ * accountKey="vc-100100100"
24
+ * publicKey="nhedxonrxsyfee"
25
+ * displayTitle={true}
26
+ * sharing={true}
27
+ * onplay={() => console.log('playing!')}
28
+ * ontimeupdate={(d) => console.log('time:', d.seconds)}
29
+ * onplayerready={(p) => (player = p)}
30
+ * />
31
+ * ```
32
+ */
33
+ declare const ViostreamPlayer: import("svelte").Component<$$ComponentProps, {}, "">;
34
+ type ViostreamPlayer = ReturnType<typeof ViostreamPlayer>;
35
+ export default ViostreamPlayer;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @viostream/viostream-player-svelte
3
+ *
4
+ * Svelte 5 SDK for the Viostream video player.
5
+ *
6
+ * @example Component usage
7
+ * ```svelte
8
+ * <script lang="ts">
9
+ * import { ViostreamPlayer } from '@viostream/viostream-player-svelte';
10
+ * </script>
11
+ *
12
+ * <ViostreamPlayer
13
+ * accountKey="vc-100100100"
14
+ * publicKey="nhedxonrxsyfee"
15
+ * displayTitle={true}
16
+ * onplay={() => console.log('playing')}
17
+ * />
18
+ * ```
19
+ *
20
+ * @example Headless / programmatic usage
21
+ * ```ts
22
+ * import { createViostreamPlayer } from '@viostream/viostream-player-svelte';
23
+ *
24
+ * const player = await createViostreamPlayer({
25
+ * accountKey: 'vc-100100100',
26
+ * publicKey: 'nhedxonrxsyfee',
27
+ * target: 'my-video-div'
28
+ * });
29
+ *
30
+ * player.play();
31
+ * const time = await player.getCurrentTime();
32
+ * player.on('ended', () => console.log('done'));
33
+ * ```
34
+ */
35
+ export { default as ViostreamPlayer } from './ViostreamPlayer.svelte';
36
+ export { createViostreamPlayer, wrapRawPlayer, loadViostream, } from '@viostream/viostream-player-core';
37
+ export type { CreateViostreamPlayerOptions, ViostreamEmbedOptions, ViostreamTimeUpdateData, ViostreamVolumeChangeData, ViostreamErrorData, ViostreamProgressData, ViostreamPlayerEventMap, ViostreamEventHandler, ViostreamCue, ViostreamCueFieldUpdate, ViostreamTrack, ViostreamPlayer as ViostreamPlayerInstance, RawViostreamPlayerInstance, ViostreamGlobal, } from '@viostream/viostream-player-core';
38
+ export type { ViostreamPlayerProps, ViostreamPlayerEventProps, } from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @viostream/viostream-player-svelte
3
+ *
4
+ * Svelte 5 SDK for the Viostream video player.
5
+ *
6
+ * @example Component usage
7
+ * ```svelte
8
+ * <script lang="ts">
9
+ * import { ViostreamPlayer } from '@viostream/viostream-player-svelte';
10
+ * </script>
11
+ *
12
+ * <ViostreamPlayer
13
+ * accountKey="vc-100100100"
14
+ * publicKey="nhedxonrxsyfee"
15
+ * displayTitle={true}
16
+ * onplay={() => console.log('playing')}
17
+ * />
18
+ * ```
19
+ *
20
+ * @example Headless / programmatic usage
21
+ * ```ts
22
+ * import { createViostreamPlayer } from '@viostream/viostream-player-svelte';
23
+ *
24
+ * const player = await createViostreamPlayer({
25
+ * accountKey: 'vc-100100100',
26
+ * publicKey: 'nhedxonrxsyfee',
27
+ * target: 'my-video-div'
28
+ * });
29
+ *
30
+ * player.play();
31
+ * const time = await player.getCurrentTime();
32
+ * player.on('ended', () => console.log('done'));
33
+ * ```
34
+ */
35
+ // Component
36
+ export { default as ViostreamPlayer } from './ViostreamPlayer.svelte';
37
+ // Re-export everything from core so consumers can import from this package
38
+ export { createViostreamPlayer, wrapRawPlayer, loadViostream, } from '@viostream/viostream-player-core';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Viostream Player SDK — Svelte-specific type definitions
3
+ *
4
+ * Core types (ViostreamPlayer, ViostreamEmbedOptions, etc.) are re-exported from
5
+ * `@viostream/viostream-player-core`. This file defines only the Svelte component props.
6
+ */
7
+ import type { ViostreamEmbedOptions, ViostreamPlayer, ViostreamTimeUpdateData, ViostreamVolumeChangeData, ViostreamErrorData, ViostreamProgressData } from '@viostream/viostream-player-core';
8
+ /** Callback props for player events on the `<ViostreamPlayer>` component. */
9
+ export interface ViostreamPlayerEventProps {
10
+ onplay?: () => void;
11
+ onpause?: () => void;
12
+ onended?: () => void;
13
+ ontimeupdate?: (data: ViostreamTimeUpdateData) => void;
14
+ onvolumechange?: (data: ViostreamVolumeChangeData) => void;
15
+ onerror?: (data: ViostreamErrorData) => void;
16
+ onprogress?: (data: ViostreamProgressData) => void;
17
+ onready?: () => void;
18
+ onseeked?: () => void;
19
+ onloaded?: () => void;
20
+ }
21
+ /** Props accepted by the `<ViostreamPlayer>` component. */
22
+ export interface ViostreamPlayerProps extends ViostreamEmbedOptions, ViostreamPlayerEventProps {
23
+ /** Your Viostream account key (e.g. `'vc-100100100'`). */
24
+ accountKey: string;
25
+ /** The public key of the media asset to embed. */
26
+ publicKey: string;
27
+ /**
28
+ * Optional CSS class applied to the outer wrapper `<div>`.
29
+ */
30
+ class?: string;
31
+ /**
32
+ * Callback fired once the player is ready, providing the `ViostreamPlayer` instance.
33
+ */
34
+ onplayerready?: (player: ViostreamPlayer) => void;
35
+ }
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Viostream Player SDK — Svelte-specific type definitions
3
+ *
4
+ * Core types (ViostreamPlayer, ViostreamEmbedOptions, etc.) are re-exported from
5
+ * `@viostream/viostream-player-core`. This file defines only the Svelte component props.
6
+ */
7
+ export {};
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@viostream/viostream-player-svelte",
3
+ "version": "0.1.2",
4
+ "description": "Svelte 5 SDK for the Viostream video player — embed, control, and listen to player events",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "type": "module",
10
+ "scripts": {
11
+ "package": "svelte-kit sync && svelte-package && publint",
12
+ "build": "npm run package",
13
+ "prepublishOnly": "npm run package",
14
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
15
+ "test": "vitest run",
16
+ "test:watch": "vitest"
17
+ },
18
+ "svelte": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "svelte": "./dist/index.js",
24
+ "default": "./dist/index.js"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "!dist/**/*.test.*",
30
+ "!dist/**/*.spec.*"
31
+ ],
32
+ "dependencies": {
33
+ "@viostream/viostream-player-core": "^0.1.1"
34
+ },
35
+ "peerDependencies": {
36
+ "svelte": "^5.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@sveltejs/kit": "^2.16.0",
40
+ "@sveltejs/package": "^2.3.0",
41
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
42
+ "@testing-library/jest-dom": "^6.9.1",
43
+ "@testing-library/svelte": "^5.3.1",
44
+ "jsdom": "^28.1.0",
45
+ "publint": "^0.3.0",
46
+ "svelte": "^5.0.0",
47
+ "svelte-check": "^4.0.0",
48
+ "typescript": "^5.7.0",
49
+ "vite": "^6.0.0",
50
+ "vitest": "^4.0.18"
51
+ },
52
+ "keywords": [
53
+ "svelte",
54
+ "svelte5",
55
+ "viostream",
56
+ "video",
57
+ "player",
58
+ "embed",
59
+ "sdk"
60
+ ]
61
+ }