ts-video-player 0.1.1 → 0.1.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/cdn.min.js +76 -76
- package/dist/{chunk-z1ehbz9f.js → chunk-ds1nj487.js} +35 -35
- package/dist/{chunk-36x4yhjn.js → chunk-rhykj0qy.js} +58 -58
- package/dist/{chunk-eajts2jv.js → chunk-yfrrczn9.js} +221 -194
- package/dist/elements/index.js +49 -50
- package/dist/features/index.js +25 -26
- package/dist/index.js +368 -368
- package/dist/plugins/index.js +2143 -15
- package/dist/providers/html5.d.ts +4 -0
- package/dist/providers/youtube.d.ts +4 -0
- package/dist/stx/index.js +4 -4
- package/dist/ui/index.js +730 -11
- package/package.json +3 -5
- package/src/providers/html5.ts +1 -1
- package/src/providers/index.ts +36 -2
- package/src/providers/youtube.ts +18 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-video-player",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A modern, framework-agnostic video player with deep stx integration",
|
|
5
5
|
"author": "Chris Breuer <chris@stacksjs.org>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
9
|
"module": "./dist/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
|
-
"sideEffects":
|
|
12
|
-
"./dist/cdn.min.js"
|
|
13
|
-
],
|
|
11
|
+
"sideEffects": true,
|
|
14
12
|
"exports": {
|
|
15
13
|
".": {
|
|
16
14
|
"types": "./dist/index.d.ts",
|
|
@@ -62,7 +60,7 @@
|
|
|
62
60
|
},
|
|
63
61
|
"devDependencies": {
|
|
64
62
|
"@types/bun": "latest",
|
|
65
|
-
"typescript": "^
|
|
63
|
+
"typescript": "^7.0.2"
|
|
66
64
|
},
|
|
67
65
|
"peerDependencies": {
|
|
68
66
|
"stx": ">=0.65.0"
|
package/src/providers/html5.ts
CHANGED
|
@@ -65,7 +65,7 @@ function getExtension(src: string): string {
|
|
|
65
65
|
/**
|
|
66
66
|
* Get MIME type for a source
|
|
67
67
|
*/
|
|
68
|
-
function getMimeType(src: string): string {
|
|
68
|
+
export function getMimeType(src: string): string {
|
|
69
69
|
const ext = getExtension(src)
|
|
70
70
|
const mimeTypes: Record<string, string> = {
|
|
71
71
|
mp4: 'video/mp4',
|
package/src/providers/index.ts
CHANGED
|
@@ -35,7 +35,7 @@ export type { Provider, ProviderLoader, ProviderType } from '../types'
|
|
|
35
35
|
// =============================================================================
|
|
36
36
|
|
|
37
37
|
import type { ProviderLoader, Src } from '../types'
|
|
38
|
-
import { html5Loader } from './html5'
|
|
38
|
+
import { getMimeType, html5Loader } from './html5'
|
|
39
39
|
import { youtubeLoader } from './youtube'
|
|
40
40
|
import { vimeoLoader } from './vimeo'
|
|
41
41
|
import { hlsLoader } from './hls'
|
|
@@ -52,6 +52,32 @@ export const defaultLoaders: ProviderLoader[] = [
|
|
|
52
52
|
html5Loader, // HTML5 as fallback
|
|
53
53
|
]
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* The URL of a source object that says nothing about its kind: `{ src }`,
|
|
57
|
+
* perhaps with a quality or size, but no `type`. Only its URL can tell a
|
|
58
|
+
* YouTube link from an MP4, so that is what the loaders are asked about.
|
|
59
|
+
*/
|
|
60
|
+
function untypedUrl(src: Src): string | null {
|
|
61
|
+
if (!src || typeof src !== 'object' || typeof src.src !== 'string')
|
|
62
|
+
return null
|
|
63
|
+
return 'type' in src && src.type ? null : src.src
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** What a loader's source type is written as, for a source it matched by URL alone. */
|
|
67
|
+
const TYPE_FOR_LOADER: Record<string, (url: string) => string> = {
|
|
68
|
+
youtube: () => 'youtube',
|
|
69
|
+
vimeo: () => 'vimeo',
|
|
70
|
+
hls: () => 'application/x-mpegurl',
|
|
71
|
+
dash: () => 'dash',
|
|
72
|
+
video: url => getMimeType(url),
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function withType(src: Src, loader: ProviderLoader): Src {
|
|
76
|
+
const url = untypedUrl(src)
|
|
77
|
+
const type = url && TYPE_FOR_LOADER[loader.type]
|
|
78
|
+
return url && type ? { ...(src as object), type: type(url) } as Src : src
|
|
79
|
+
}
|
|
80
|
+
|
|
55
81
|
/**
|
|
56
82
|
* Find the appropriate provider loader for a source
|
|
57
83
|
*/
|
|
@@ -61,6 +87,13 @@ export function findLoader(src: Src, loaders: ProviderLoader[] = defaultLoaders)
|
|
|
61
87
|
return loader
|
|
62
88
|
}
|
|
63
89
|
}
|
|
90
|
+
const url = untypedUrl(src)
|
|
91
|
+
if (url) {
|
|
92
|
+
for (const loader of loaders) {
|
|
93
|
+
if (loader.canPlay(url))
|
|
94
|
+
return loader
|
|
95
|
+
}
|
|
96
|
+
}
|
|
64
97
|
return null
|
|
65
98
|
}
|
|
66
99
|
|
|
@@ -75,7 +108,8 @@ export function findSourceCandidates(sources: readonly Src[], loaders: ProviderL
|
|
|
75
108
|
const candidates: SourceCandidate[] = []
|
|
76
109
|
sources.forEach((src, index) => {
|
|
77
110
|
const loader = findLoader(src, loaders)
|
|
78
|
-
|
|
111
|
+
// Typed for the provider that claimed it, which reads `type` to know how.
|
|
112
|
+
if (loader) candidates.push({ src: withType(src, loader), index, loader })
|
|
79
113
|
})
|
|
80
114
|
return candidates
|
|
81
115
|
}
|
package/src/providers/youtube.ts
CHANGED
|
@@ -145,6 +145,8 @@ declare global {
|
|
|
145
145
|
elementId: string | HTMLElement,
|
|
146
146
|
options: {
|
|
147
147
|
videoId?: string
|
|
148
|
+
/** Where the iframe is served from, e.g. https://www.youtube-nocookie.com. */
|
|
149
|
+
host?: string
|
|
148
150
|
width?: number | string
|
|
149
151
|
height?: number | string
|
|
150
152
|
playerVars?: Record<string, string | number>
|
|
@@ -184,6 +186,8 @@ export class YouTubeProvider extends BaseProvider {
|
|
|
184
186
|
private player: YTPlayer | null = null
|
|
185
187
|
private iframe: HTMLIFrameElement | null = null
|
|
186
188
|
private pendingVideoId: string | null = null
|
|
189
|
+
/** YouTube's own ready event: the player's methods exist only after it. */
|
|
190
|
+
private playerReady = false
|
|
187
191
|
private startTime?: number
|
|
188
192
|
private endTime?: number
|
|
189
193
|
private timeUpdateInterval: ReturnType<typeof setInterval> | null = null
|
|
@@ -227,11 +231,14 @@ export class YouTubeProvider extends BaseProvider {
|
|
|
227
231
|
Object.assign(playerVars, this.options.youtubeParams)
|
|
228
232
|
}
|
|
229
233
|
|
|
230
|
-
// Use privacy-enhanced mode
|
|
231
|
-
playerVars.host = 'https://www.youtube-nocookie.com'
|
|
232
234
|
|
|
233
|
-
// Create player
|
|
234
|
-
|
|
235
|
+
// Create player. The element, not its id: the API looks an id up with
|
|
236
|
+
// document.getElementById, which cannot see into the shadow root the
|
|
237
|
+
// <video-player> element renders into, so an id found nothing there.
|
|
238
|
+
this.player = new window.YT!.Player(playerDiv, {
|
|
239
|
+
// Privacy-enhanced mode. A top-level option: set among playerVars, the
|
|
240
|
+
// API ignored it and embedded from youtube.com.
|
|
241
|
+
host: 'https://www.youtube-nocookie.com',
|
|
235
242
|
width: '100%',
|
|
236
243
|
height: '100%',
|
|
237
244
|
playerVars,
|
|
@@ -287,12 +294,15 @@ export class YouTubeProvider extends BaseProvider {
|
|
|
287
294
|
|
|
288
295
|
this.player?.destroy()
|
|
289
296
|
this.player = null
|
|
297
|
+
this.playerReady = false
|
|
290
298
|
this.iframe = null
|
|
291
299
|
}
|
|
292
300
|
|
|
293
301
|
// === Event Handlers ===
|
|
294
302
|
|
|
295
303
|
private onReady(): void {
|
|
304
|
+
this.playerReady = true
|
|
305
|
+
|
|
296
306
|
// Start time update polling
|
|
297
307
|
this.timeUpdateInterval = setInterval(() => {
|
|
298
308
|
if (this.player && this.lastState === 1) {
|
|
@@ -383,7 +393,10 @@ export class YouTubeProvider extends BaseProvider {
|
|
|
383
393
|
this.startTime = parsed.startTime
|
|
384
394
|
this.endTime = parsed.endTime
|
|
385
395
|
|
|
386
|
-
|
|
396
|
+
// `_ready` means setup finished, which is before YouTube has attached
|
|
397
|
+
// cueVideoById and friends to the player: calling one then threw, and the
|
|
398
|
+
// source was reported as unplayable. onReady loads the pending video.
|
|
399
|
+
if (!this.player || !this._ready || !this.playerReady) {
|
|
387
400
|
this.pendingVideoId = parsed.videoId
|
|
388
401
|
return
|
|
389
402
|
}
|