@lumra/core 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.
- package/README.md +115 -0
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @lumra/core
|
|
2
|
+
|
|
3
|
+
Headless media player engine for Lumra. Wraps the native `<video>` element with HLS adaptive streaming, a plugin system, quality switching, and a typed event emitter.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @lumra/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createPlayer } from '@lumra/core'
|
|
15
|
+
|
|
16
|
+
const player = createPlayer({
|
|
17
|
+
target: '#my-video', // CSS selector or HTMLVideoElement
|
|
18
|
+
src: 'https://example.com/stream.m3u8',
|
|
19
|
+
autoplay: false,
|
|
20
|
+
muted: false,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
player.on('play', () => console.log('playing'))
|
|
24
|
+
player.on('pause', () => console.log('paused'))
|
|
25
|
+
player.on('timeupdate', ({ currentTime, duration }) => console.log(currentTime, duration))
|
|
26
|
+
player.on('ended', () => console.log('ended'))
|
|
27
|
+
player.on('error', ({ code, message }) => console.error(code, message))
|
|
28
|
+
|
|
29
|
+
// Playback control
|
|
30
|
+
await player.play()
|
|
31
|
+
player.pause()
|
|
32
|
+
player.seek(30) // seek to 30 seconds
|
|
33
|
+
player.setVolume(0.8) // 0–1
|
|
34
|
+
player.mute()
|
|
35
|
+
player.unmute()
|
|
36
|
+
|
|
37
|
+
// Source switching
|
|
38
|
+
player.setSrc('https://example.com/other.m3u8')
|
|
39
|
+
|
|
40
|
+
// Cleanup
|
|
41
|
+
player.destroy()
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## HLS & adaptive streaming
|
|
45
|
+
|
|
46
|
+
HLS streams (`.m3u8`) are detected automatically and loaded via hls.js. Safari uses native HLS.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const player = createPlayer({
|
|
50
|
+
target: '#video',
|
|
51
|
+
src: 'https://example.com/stream.m3u8',
|
|
52
|
+
hlsConfig: { maxBufferLength: 30 }, // pass any hls.js config here
|
|
53
|
+
})
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quality switching
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// Get available quality levels (populated after the HLS manifest loads)
|
|
60
|
+
const levels = player.getQualityLevels()
|
|
61
|
+
// [{ index: -1, label: 'Auto' }, { index: 0, label: '1080p', bitrate: 5000000 }, ...]
|
|
62
|
+
|
|
63
|
+
// Set quality — index -1 = ABR auto
|
|
64
|
+
player.setQuality(0) // lock to first level
|
|
65
|
+
player.setQuality(-1) // back to auto
|
|
66
|
+
|
|
67
|
+
player.on('qualitychange', ({ level, auto }) => console.log(level, auto))
|
|
68
|
+
player.on('levelchange', ({ level }) => console.log(level))
|
|
69
|
+
|
|
70
|
+
// Live stream detection
|
|
71
|
+
console.log(player.isLive) // true for live HLS
|
|
72
|
+
console.log(player.isHls) // true when hls.js is active
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Plugin system
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { createPlayer } from '@lumra/core'
|
|
79
|
+
import type { Plugin, PlayerInstance } from '@lumra/core'
|
|
80
|
+
|
|
81
|
+
const myPlugin: Plugin = {
|
|
82
|
+
name: 'my-plugin',
|
|
83
|
+
init(player: PlayerInstance) {
|
|
84
|
+
player.on('play', () => console.log('plugin saw play'))
|
|
85
|
+
},
|
|
86
|
+
destroy() {
|
|
87
|
+
// cleanup — called when player.destroy() is called
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
player.use(myPlugin)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Events reference
|
|
95
|
+
|
|
96
|
+
| Event | Payload |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `play` | — |
|
|
99
|
+
| `pause` | — |
|
|
100
|
+
| `ended` | — |
|
|
101
|
+
| `timeupdate` | `{ currentTime, duration }` |
|
|
102
|
+
| `volumechange` | `{ volume, muted }` |
|
|
103
|
+
| `seeking` | `{ time }` |
|
|
104
|
+
| `seeked` | `{ time }` |
|
|
105
|
+
| `buffering` | — |
|
|
106
|
+
| `ready` | — |
|
|
107
|
+
| `error` | `{ code, message }` |
|
|
108
|
+
| `qualitychange` | `{ level, auto }` |
|
|
109
|
+
| `levelchange` | `{ level }` |
|
|
110
|
+
| `destroy` | — |
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
© 2026 Reel Foundry AU. All rights reserved.
|
|
115
|
+
MIT License — see [LICENSE](../../LICENSE)
|
package/dist/index.cjs
CHANGED
|
@@ -150,6 +150,7 @@ var Player = class extends EventEmitter {
|
|
|
150
150
|
{ index: -1, height: 0, bitrate: 0, label: "Auto" },
|
|
151
151
|
...levels
|
|
152
152
|
];
|
|
153
|
+
this.emit("manifest", void 0);
|
|
153
154
|
});
|
|
154
155
|
hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {
|
|
155
156
|
this.emit("levelchange", { level: data.level });
|
|
@@ -164,6 +165,7 @@ var Player = class extends EventEmitter {
|
|
|
164
165
|
}
|
|
165
166
|
if (this.video.canPlayType("application/vnd.apple.mpegurl")) {
|
|
166
167
|
this.video.src = src;
|
|
168
|
+
void Promise.resolve().then(() => this.emit("manifest", void 0));
|
|
167
169
|
return;
|
|
168
170
|
}
|
|
169
171
|
this.emit("error", { code: -1, message: "HLS is not supported in this browser" });
|
|
@@ -171,6 +173,7 @@ var Player = class extends EventEmitter {
|
|
|
171
173
|
}
|
|
172
174
|
this.destroyHls();
|
|
173
175
|
this.video.src = src;
|
|
176
|
+
void Promise.resolve().then(() => this.emit("manifest", void 0));
|
|
174
177
|
}
|
|
175
178
|
destroyHls() {
|
|
176
179
|
if (this.hls) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/events.ts","../src/hls.ts","../src/player.ts","../src/index.ts"],"names":[],"mappings":";;;AAMO,IAAM,eAAN,MAAmB;AAAA,EAAnB,WAAA,GAAA;AACL,IAAA,IAAA,CAAQ,YAAyB,EAAC;AAAA,EAAA;AAAA,EAElC,EAAA,CAA0B,OAAU,QAAA,EAAwC;AAC1E,IAAA,IAAI,CAAC,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG;AAC1B,MAAA,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,mBAAI,IAAI,GAAA,EAAI;AAAA,IAClC;AACC,IAAC,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,CAAkC,IAAI,QAAQ,CAAA;AAAA,EACtE;AAAA,EAEA,GAAA,CAA2B,OAAU,QAAA,EAAwC;AAC3E,IAAC,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAA+C,OAAO,QAAQ,CAAA;AAAA,EACrF;AAAA,EAEA,IAAA,CAA4B,OAAU,QAAA,EAAwC;AAC5E,IAAA,MAAM,OAAA,GAAkC,CAAC,IAAA,KAAS;AAChD,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,IAAA,CAAK,GAAA,CAAI,OAAO,OAAO,CAAA;AAAA,IACzB,CAAA;AACA,IAAA,IAAA,CAAK,EAAA,CAAG,OAAO,OAAO,CAAA;AAAA,EACxB;AAAA,EAEA,IAAA,CAA4B,OAAU,IAAA,EAA+B;AACnE,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AAChC,IAAA,IAAI,CAAC,GAAA,EAAK;AACV,IAAA,KAAA,MAAW,YAAY,GAAA,EAAK;AAC1B,MAAA,IAAI;AACF,QAAA,QAAA,CAAS,IAAI,CAAA;AAAA,MACf,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,kBAAA,EAAqB,KAAK,CAAA,WAAA,CAAA,EAAe,GAAG,CAAA;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAAA,EAEA,kBAAA,GAA2B;AACzB,IAAA,IAAA,CAAK,YAAY,EAAC;AAAA,EACpB;AACF;;;ACzCA,IAAI,SAAA,GAA+B,IAAA;AAEnC,eAAsB,OAAA,GAAsC;AAC1D,EAAA,IAAI,WAAW,OAAO,SAAA;AACtB,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,OAAO,QAAQ,CAAA;AACjC,IAAA,SAAA,GAAY,GAAA,CAAI,OAAA;AAChB,IAAA,OAAO,SAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAWO,SAAS,YAAY,GAAA,EAAsB;AAChD,EAAA,OAAO,IAAI,QAAA,CAAS,OAAO,CAAA,IAAK,GAAA,CAAI,SAAS,uBAAuB,CAAA;AACtE;;;ACrBA,SAAS,WAAW,MAAA,EAAwB;AAC1C,EAAA,IAAI,MAAA,IAAU,MAAM,OAAO,IAAA;AAC3B,EAAA,IAAI,MAAA,IAAU,MAAM,OAAO,OAAA;AAC3B,EAAA,IAAI,MAAA,IAAU,KAAM,OAAO,MAAA;AAC3B,EAAA,IAAI,MAAA,IAAU,KAAM,OAAO,MAAA;AAC3B,EAAA,IAAI,MAAA,IAAU,KAAM,OAAO,MAAA;AAC3B,EAAA,OAAO,GAAG,MAAM,CAAA,CAAA,CAAA;AAClB;AAEO,IAAM,MAAA,GAAN,cAAqB,YAAA,CAAuC;AAAA,EAUjE,YAA6B,OAAA,EAAwB;AACnD,IAAA,KAAA,EAAM;AADqB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAR7B,IAAA,IAAA,CAAQ,GAAA,GAAkB,IAAA;AAC1B,IAAA,IAAA,CAAQ,OAAA,uBAAmC,GAAA,EAAI;AAC/C,IAAA,IAAA,CAAQ,IAAA,GAAO,EAAA;AACf,IAAA,IAAA,CAAQ,UAAA,GAAa,KAAA;AACrB,IAAA,IAAA,CAAQ,OAAA,GAAU,KAAA;AAClB,IAAA,IAAA,CAAQ,YAAA,GAAe,IAAA;AACvB,IAAA,IAAA,CAAQ,aAA6B,EAAC;AAIpC,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,aAAA,CAAc,OAAA,CAAQ,MAAM,CAAA;AAC9C,IAAA,IAAA,CAAK,YAAA,EAAa;AAClB,IAAA,IAAA,CAAK,gBAAA,EAAiB;AACtB,IAAA,IAAI,QAAQ,GAAA,EAAK;AACf,MAAA,KAAK,IAAA,CAAK,WAAA,CAAY,OAAA,CAAQ,GAAG,CAAA;AAAA,IACnC;AAAA,EACF;AAAA,EAEQ,cAAc,MAAA,EAAqD;AACzE,IAAA,IAAI,MAAA,YAAkB,kBAAkB,OAAO,MAAA;AAC/C,IAAA,MAAM,EAAA,GAAK,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AACxC,IAAA,IAAI,EAAE,cAAc,gBAAA,CAAA,EAAmB;AACrC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,MAAM,CAAA,0BAAA,CAA4B,CAAA;AAAA,IACvE;AACA,IAAA,OAAO,EAAA;AAAA,EACT;AAAA,EAEQ,YAAA,GAAqB;AAC3B,IAAA,MAAM,EAAE,KAAA,GAAQ,KAAA,EAAO,MAAA,GAAS,CAAA,EAAG,OAAO,KAAA,EAAO,QAAA,GAAW,KAAA,EAAM,GAAI,IAAA,CAAK,OAAA;AAC3E,IAAA,IAAA,CAAK,MAAM,KAAA,GAAQ,KAAA;AACnB,IAAA,IAAA,CAAK,MAAM,MAAA,GAAS,MAAA;AACpB,IAAA,IAAA,CAAK,MAAM,IAAA,GAAO,IAAA;AAClB,IAAA,IAAA,CAAK,MAAM,QAAA,GAAW,QAAA;AAAA,EACxB;AAAA,EAEQ,gBAAA,GAAyB;AAC/B,IAAA,IAAA,CAAK,KAAA,CAAM,iBAAiB,MAAA,EAAQ,MAAM,KAAK,IAAA,CAAK,MAAA,EAAQ,MAAiB,CAAC,CAAA;AAC9E,IAAA,IAAA,CAAK,KAAA,CAAM,iBAAiB,OAAA,EAAS,MAAM,KAAK,IAAA,CAAK,OAAA,EAAS,MAAiB,CAAC,CAAA;AAChF,IAAA,IAAA,CAAK,KAAA,CAAM,iBAAiB,OAAA,EAAS,MAAM,KAAK,IAAA,CAAK,OAAA,EAAS,MAAiB,CAAC,CAAA;AAChF,IAAA,IAAA,CAAK,KAAA,CAAM,iBAAiB,SAAA,EAAW,MAAM,KAAK,IAAA,CAAK,WAAA,EAAa,MAAiB,CAAC,CAAA;AACtF,IAAA,IAAA,CAAK,KAAA,CAAM,iBAAiB,SAAA,EAAW,MAAM,KAAK,IAAA,CAAK,OAAA,EAAS,MAAiB,CAAC,CAAA;AAClF,IAAA,IAAA,CAAK,KAAA,CAAM,gBAAA;AAAA,MAAiB,cAAA;AAAA,MAAgB,MAC1C,IAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,EAAE,MAAA,EAAQ,IAAA,CAAK,KAAA,CAAM,MAAA,EAAQ,KAAA,EAAO,IAAA,CAAK,KAAA,CAAM,OAAO;AAAA,KAClF;AACA,IAAA,IAAA,CAAK,KAAA,CAAM,gBAAA;AAAA,MAAiB,YAAA;AAAA,MAAc,MACxC,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc;AAAA,QACtB,WAAA,EAAa,KAAK,KAAA,CAAM,WAAA;AAAA,QACxB,QAAA,EAAU,IAAA,CAAK,KAAA,CAAM,QAAA,IAAY;AAAA,OAClC;AAAA,KACH;AACA,IAAA,IAAA,CAAK,KAAA,CAAM,gBAAA;AAAA,MAAiB,SAAA;AAAA,MAAW,MACrC,KAAK,IAAA,CAAK,SAAA,EAAW,EAAE,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,WAAA,EAAa;AAAA,KACvD;AACA,IAAA,IAAA,CAAK,KAAA,CAAM,gBAAA;AAAA,MAAiB,QAAA;AAAA,MAAU,MACpC,KAAK,IAAA,CAAK,QAAA,EAAU,EAAE,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,WAAA,EAAa;AAAA,KACtD;AACA,IAAA,IAAA,CAAK,KAAA,CAAM,gBAAA,CAAiB,OAAA,EAAS,MAAM;AACzC,MAAA,MAAM,GAAA,GAAM,KAAK,KAAA,CAAM,KAAA;AACvB,MAAA,IAAA,CAAK,KAAK,OAAA,EAAS;AAAA,QACjB,IAAA,EAAM,KAAK,IAAA,IAAQ,EAAA;AAAA,QACnB,OAAA,EAAS,KAAK,OAAA,IAAW;AAAA,OAC1B,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAc,YAAY,GAAA,EAA4B;AACpD,IAAA,IAAA,CAAK,IAAA,GAAO,GAAA;AAEZ,IAAA,IAAI,WAAA,CAAY,GAAG,CAAA,EAAG;AACpB,MAAA,MAAM,GAAA,GAAM,MAAM,OAAA,EAAQ;AAC1B,MAAA,IAAI,GAAA,IAAO,GAAA,CAAI,WAAA,EAAY,EAAG;AAC5B,QAAA,IAAA,CAAK,UAAA,EAAW;AAChB,QAAA,MAAM,MAAM,IAAI,GAAA,CAAI,KAAK,OAAA,CAAQ,SAAA,IAAa,EAAE,CAAA;AAChD,QAAA,IAAA,CAAK,GAAA,GAAM,GAAA;AACX,QAAA,GAAA,CAAI,WAAW,GAAG,CAAA;AAClB,QAAA,GAAA,CAAI,WAAA,CAAY,KAAK,KAAK,CAAA;AAE1B,QAAA,GAAA,CAAI,GAAG,GAAA,CAAI,MAAA,CAAO,eAAA,EAAiB,CAAC,QAAQ,IAAA,KAAS;AACnD,UAAA,IAAA,CAAK,OAAA,GAAW,KAA4B,IAAA,KAAS,IAAA;AACrD,UAAA,MAAM,SAAyB,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,CAAC,GAAG,CAAA,MAAO;AAAA,YACvD,KAAA,EAAO,CAAA;AAAA,YACP,QAAQ,CAAA,CAAE,MAAA;AAAA,YACV,SAAS,CAAA,CAAE,OAAA;AAAA,YACX,KAAA,EAAO,UAAA,CAAW,CAAA,CAAE,MAAM;AAAA,WAC5B,CAAE,CAAA;AACF,UAAA,IAAA,CAAK,UAAA,GAAa;AAAA,YAChB,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,GAAG,OAAA,EAAS,CAAA,EAAG,OAAO,MAAA,EAAO;AAAA,YAClD,GAAG;AAAA,WACL;AAAA,QACF,CAAC,CAAA;AAED,QAAA,GAAA,CAAI,GAAG,GAAA,CAAI,MAAA,CAAO,cAAA,EAAgB,CAAC,QAAQ,IAAA,KAAS;AAClD,UAAA,IAAA,CAAK,KAAK,aAAA,EAAe,EAAE,KAAA,EAAO,IAAA,CAAK,OAAO,CAAA;AAC9C,UAAA,IAAA,CAAK,IAAA,CAAK,iBAAiB,EAAE,KAAA,EAAO,KAAK,KAAA,EAAO,IAAA,EAAM,IAAA,CAAK,YAAA,EAAc,CAAA;AAAA,QAC3E,CAAC,CAAA;AAED,QAAA,GAAA,CAAI,GAAG,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,CAAC,QAAQ,IAAA,KAAS;AACzC,UAAA,IAAI,KAAK,KAAA,EAAO;AACd,YAAA,IAAA,CAAK,IAAA,CAAK,SAAS,EAAE,IAAA,EAAM,IAAI,OAAA,EAAS,IAAA,CAAK,OAAA,IAAW,iBAAA,EAAmB,CAAA;AAAA,UAC7E;AAAA,QACF,CAAC,CAAA;AAED,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,+BAA+B,CAAA,EAAG;AAC3D,QAAA,IAAA,CAAK,MAAM,GAAA,GAAM,GAAA;AACjB,QAAA;AAAA,MACF;AACA,MAAA,IAAA,CAAK,KAAK,OAAA,EAAS,EAAE,MAAM,EAAA,EAAI,OAAA,EAAS,wCAAwC,CAAA;AAChF,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,UAAA,EAAW;AAChB,IAAA,IAAA,CAAK,MAAM,GAAA,GAAM,GAAA;AAAA,EACnB;AAAA,EAEQ,UAAA,GAAmB;AACzB,IAAA,IAAI,KAAK,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,IAAI,OAAA,EAAQ;AACjB,MAAA,IAAA,CAAK,GAAA,GAAM,IAAA;AAAA,IACb;AAAA,EACF;AAAA,EAEA,MAAM,IAAA,GAAsB;AAC1B,IAAA,MAAM,IAAA,CAAK,MAAM,IAAA,EAAK;AAAA,EACxB;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AAAA,EAEA,KAAK,IAAA,EAAoB;AACvB,IAAA,IAAA,CAAK,MAAM,WAAA,GAAc,IAAA;AAAA,EAC3B;AAAA,EAEA,UAAU,MAAA,EAAsB;AAC9B,IAAA,IAAA,CAAK,KAAA,CAAM,SAAS,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAM,CAAC,CAAA;AAAA,EACrD;AAAA,EAEA,IAAA,GAAa;AACX,IAAA,IAAA,CAAK,MAAM,KAAA,GAAQ,IAAA;AAAA,EACrB;AAAA,EAEA,MAAA,GAAe;AACb,IAAA,IAAA,CAAK,MAAM,KAAA,GAAQ,KAAA;AAAA,EACrB;AAAA,EAEA,OAAO,GAAA,EAAmB;AACxB,IAAA,KAAK,IAAA,CAAK,YAAY,GAAG,CAAA;AAAA,EAC3B;AAAA,EAEA,IAAI,MAAA,EAAsB;AACxB,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,EAAG;AACjC,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,gBAAA,EAAmB,MAAA,CAAO,IAAI,CAAA,uBAAA,CAAyB,CAAA;AACpE,MAAA;AAAA,IACF;AACA,IAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAChB,IAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,MAAM,CAAA;AACpC,IAAA,IAAA,CAAK,KAAK,iBAAA,EAAmB,EAAE,IAAA,EAAM,MAAA,CAAO,MAAM,CAAA;AAAA,EACpD;AAAA,EAEA,OAAA,GAAgB;AACd,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AAC1C,MAAA,MAAA,CAAO,OAAA,EAAQ;AAAA,IACjB;AACA,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AACnB,IAAA,IAAA,CAAK,UAAA,EAAW;AAChB,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AACjB,IAAA,IAAA,CAAK,KAAA,CAAM,gBAAgB,KAAK,CAAA;AAChC,IAAA,IAAA,CAAK,MAAM,IAAA,EAAK;AAChB,IAAA,IAAA,CAAK,IAAA,CAAK,WAAW,MAAiB,CAAA;AACtC,IAAA,IAAA,CAAK,kBAAA,EAAmB;AAAA,EAC1B;AAAA,EAEA,gBAAA,GAAmC;AACjC,IAAA,OAAO,IAAA,CAAK,UAAA;AAAA,EACd;AAAA,EAEA,WAAW,UAAA,EAA0B;AACnC,IAAA,IAAI,CAAC,KAAK,GAAA,EAAK;AACf,IAAA,IAAA,CAAK,eAAe,UAAA,KAAe,EAAA;AACnC,IAAA,IAAA,CAAK,IAAI,YAAA,GAAe,UAAA;AACxB,IAAA,IAAA,CAAK,IAAA,CAAK,iBAAiB,EAAE,KAAA,EAAO,YAAY,IAAA,EAAM,IAAA,CAAK,cAAc,CAAA;AAAA,EAC3E;AAAA,EAEA,IAAI,WAAA,GAAsB;AAAE,IAAA,OAAO,KAAK,KAAA,CAAM,WAAA;AAAA,EAAY;AAAA,EAC1D,IAAI,QAAA,GAAmB;AAAE,IAAA,OAAO,IAAA,CAAK,MAAM,QAAA,IAAY,CAAA;AAAA,EAAE;AAAA,EACzD,IAAI,MAAA,GAAkB;AAAE,IAAA,OAAO,KAAK,KAAA,CAAM,MAAA;AAAA,EAAO;AAAA,EACjD,IAAI,MAAA,GAAiB;AAAE,IAAA,OAAO,KAAK,KAAA,CAAM,MAAA;AAAA,EAAO;AAAA,EAChD,IAAI,KAAA,GAAiB;AAAE,IAAA,OAAO,KAAK,KAAA,CAAM,KAAA;AAAA,EAAM;AAAA,EAC/C,IAAI,GAAA,GAAc;AAAE,IAAA,OAAO,IAAA,CAAK,IAAA;AAAA,EAAK;AAAA,EACrC,IAAI,MAAA,GAAkB;AAAE,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EAAQ;AAAA,EAC5C,IAAI,KAAA,GAAiB;AAAE,IAAA,OAAO,KAAK,GAAA,KAAQ,IAAA;AAAA,EAAK;AAAA,EAChD,IAAI,WAAA,GAA8B;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA;AAAA,EAAI;AACtD,CAAA;;;AClNO,SAAS,aAAa,OAAA,EAAwC;AACnE,EAAA,OAAO,IAAI,OAAO,OAAO,CAAA;AAC3B","file":"index.cjs","sourcesContent":["import type { PlayerEvent, PlayerEventListener, PlayerEventMap } from './types'\n\ntype ListenerMap = {\n [E in PlayerEvent]?: Set<PlayerEventListener<E>>\n}\n\nexport class EventEmitter {\n private listeners: ListenerMap = {}\n\n on<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n if (!this.listeners[event]) {\n this.listeners[event] = new Set() as ListenerMap[E]\n }\n ;(this.listeners[event] as Set<PlayerEventListener<E>>).add(listener)\n }\n\n off<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n (this.listeners[event] as Set<PlayerEventListener<E>> | undefined)?.delete(listener)\n }\n\n once<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n const wrapper: PlayerEventListener<E> = (data) => {\n listener(data)\n this.off(event, wrapper)\n }\n this.on(event, wrapper)\n }\n\n emit<E extends PlayerEvent>(event: E, data: PlayerEventMap[E]): void {\n const set = this.listeners[event] as Set<PlayerEventListener<E>> | undefined\n if (!set) return\n for (const listener of set) {\n try {\n listener(data)\n } catch (err) {\n console.error(`[lumra] Error in \"${event}\" listener:`, err)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners = {}\n }\n}\n","import type Hls from 'hls.js'\n\nlet HlsModule: typeof Hls | null = null\n\nexport async function loadHls(): Promise<typeof Hls | null> {\n if (HlsModule) return HlsModule\n try {\n const mod = await import('hls.js')\n HlsModule = mod.default\n return HlsModule\n } catch {\n return null\n }\n}\n\nexport function isHlsSupported(): boolean {\n try {\n // Synchronous check using the cached module\n return HlsModule ? HlsModule.isSupported() : false\n } catch {\n return false\n }\n}\n\nexport function isHlsSource(src: string): boolean {\n return src.includes('.m3u8') || src.includes('application/x-mpegURL')\n}\n","import type Hls from 'hls.js'\nimport { EventEmitter } from './events'\nimport { isHlsSource, loadHls } from './hls'\nimport type { Plugin, PlayerInstance, PlayerOptions, QualityLevel } from './types'\n\nfunction levelLabel(height: number): string {\n if (height >= 2160) return '4K'\n if (height >= 1080) return '1080p'\n if (height >= 720) return '720p'\n if (height >= 480) return '480p'\n if (height >= 360) return '360p'\n return `${height}p`\n}\n\nexport class Player extends EventEmitter implements PlayerInstance {\n private video: HTMLVideoElement\n private hls: Hls | null = null\n private plugins: Map<string, Plugin> = new Map()\n private _src = ''\n private _destroyed = false\n private _isLive = false\n private _qualityAuto = true\n private _hlsLevels: QualityLevel[] = []\n\n constructor(private readonly options: PlayerOptions) {\n super()\n this.video = this.resolveTarget(options.target)\n this.applyOptions()\n this.bindNativeEvents()\n if (options.src) {\n void this.setSrcAsync(options.src)\n }\n }\n\n private resolveTarget(target: string | HTMLVideoElement): HTMLVideoElement {\n if (target instanceof HTMLVideoElement) return target\n const el = document.querySelector(target)\n if (!(el instanceof HTMLVideoElement)) {\n throw new Error(`[lumra] Target \"${target}\" is not a <video> element`)\n }\n return el\n }\n\n private applyOptions(): void {\n const { muted = false, volume = 1, loop = false, autoplay = false } = this.options\n this.video.muted = muted\n this.video.volume = volume\n this.video.loop = loop\n this.video.autoplay = autoplay\n }\n\n private bindNativeEvents(): void {\n this.video.addEventListener('play', () => this.emit('play', undefined as void))\n this.video.addEventListener('pause', () => this.emit('pause', undefined as void))\n this.video.addEventListener('ended', () => this.emit('ended', undefined as void))\n this.video.addEventListener('waiting', () => this.emit('buffering', undefined as void))\n this.video.addEventListener('canplay', () => this.emit('ready', undefined as void))\n this.video.addEventListener('volumechange', () =>\n this.emit('volumechange', { volume: this.video.volume, muted: this.video.muted })\n )\n this.video.addEventListener('timeupdate', () =>\n this.emit('timeupdate', {\n currentTime: this.video.currentTime,\n duration: this.video.duration || 0,\n })\n )\n this.video.addEventListener('seeking', () =>\n this.emit('seeking', { time: this.video.currentTime })\n )\n this.video.addEventListener('seeked', () =>\n this.emit('seeked', { time: this.video.currentTime })\n )\n this.video.addEventListener('error', () => {\n const err = this.video.error\n this.emit('error', {\n code: err?.code ?? -1,\n message: err?.message ?? 'Unknown media error',\n })\n })\n }\n\n private async setSrcAsync(src: string): Promise<void> {\n this._src = src\n\n if (isHlsSource(src)) {\n const Hls = await loadHls()\n if (Hls && Hls.isSupported()) {\n this.destroyHls()\n const hls = new Hls(this.options.hlsConfig ?? {})\n this.hls = hls\n hls.loadSource(src)\n hls.attachMedia(this.video)\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n this._isLive = (data as { live?: boolean }).live === true\n const levels: QualityLevel[] = hls.levels.map((l, i) => ({\n index: i,\n height: l.height,\n bitrate: l.bitrate,\n label: levelLabel(l.height),\n }))\n this._hlsLevels = [\n { index: -1, height: 0, bitrate: 0, label: 'Auto' },\n ...levels,\n ]\n })\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {\n this.emit('levelchange', { level: data.level })\n this.emit('qualitychange', { level: data.level, auto: this._qualityAuto })\n })\n\n hls.on(Hls.Events.ERROR, (_event, data) => {\n if (data.fatal) {\n this.emit('error', { code: -2, message: data.details ?? 'HLS fatal error' })\n }\n })\n\n return\n }\n // Fallback: native HLS (Safari)\n if (this.video.canPlayType('application/vnd.apple.mpegurl')) {\n this.video.src = src\n return\n }\n this.emit('error', { code: -1, message: 'HLS is not supported in this browser' })\n return\n }\n\n this.destroyHls()\n this.video.src = src\n }\n\n private destroyHls(): void {\n if (this.hls) {\n this.hls.destroy()\n this.hls = null\n }\n }\n\n async play(): Promise<void> {\n await this.video.play()\n }\n\n pause(): void {\n this.video.pause()\n }\n\n seek(time: number): void {\n this.video.currentTime = time\n }\n\n setVolume(volume: number): void {\n this.video.volume = Math.max(0, Math.min(1, volume))\n }\n\n mute(): void {\n this.video.muted = true\n }\n\n unmute(): void {\n this.video.muted = false\n }\n\n setSrc(src: string): void {\n void this.setSrcAsync(src)\n }\n\n use(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n console.warn(`[lumra] Plugin \"${plugin.name}\" is already registered`)\n return\n }\n plugin.init(this)\n this.plugins.set(plugin.name, plugin)\n this.emit('plugin:register', { name: plugin.name })\n }\n\n destroy(): void {\n if (this._destroyed) return\n this._destroyed = true\n for (const plugin of this.plugins.values()) {\n plugin.destroy()\n }\n this.plugins.clear()\n this.destroyHls()\n this.video.pause()\n this.video.removeAttribute('src')\n this.video.load()\n this.emit('destroy', undefined as void)\n this.removeAllListeners()\n }\n\n getQualityLevels(): QualityLevel[] {\n return this._hlsLevels\n }\n\n setQuality(levelIndex: number): void {\n if (!this.hls) return\n this._qualityAuto = levelIndex === -1\n this.hls.currentLevel = levelIndex\n this.emit('qualitychange', { level: levelIndex, auto: this._qualityAuto })\n }\n\n get currentTime(): number { return this.video.currentTime }\n get duration(): number { return this.video.duration || 0 }\n get paused(): boolean { return this.video.paused }\n get volume(): number { return this.video.volume }\n get muted(): boolean { return this.video.muted }\n get src(): string { return this._src }\n get isLive(): boolean { return this._isLive }\n get isHls(): boolean { return this.hls !== null }\n get hlsInstance(): unknown | null { return this.hls }\n}\n","import { Player } from './player'\nimport type { PlayerOptions, PlayerInstance } from './types'\n\nexport function createPlayer(options: PlayerOptions): PlayerInstance {\n return new Player(options)\n}\n\nexport type { PlayerOptions, PlayerInstance, Plugin, PlayerEvent, PlayerEventMap, PlayerEventListener, QualityLevel } from './types'\nexport { EventEmitter } from './events'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/events.ts","../src/hls.ts","../src/player.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { PlayerEvent, PlayerEventListener, PlayerEventMap } from './types'\n\ntype ListenerMap = {\n [E in PlayerEvent]?: Set<PlayerEventListener<E>>\n}\n\nexport class EventEmitter {\n private listeners: ListenerMap = {}\n\n on<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n if (!this.listeners[event]) {\n this.listeners[event] = new Set() as ListenerMap[E]\n }\n ;(this.listeners[event] as Set<PlayerEventListener<E>>).add(listener)\n }\n\n off<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n (this.listeners[event] as Set<PlayerEventListener<E>> | undefined)?.delete(listener)\n }\n\n once<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n const wrapper: PlayerEventListener<E> = (data) => {\n listener(data)\n this.off(event, wrapper)\n }\n this.on(event, wrapper)\n }\n\n emit<E extends PlayerEvent>(event: E, data: PlayerEventMap[E]): void {\n const set = this.listeners[event] as Set<PlayerEventListener<E>> | undefined\n if (!set) return\n for (const listener of set) {\n try {\n listener(data)\n } catch (err) {\n console.error(`[lumra] Error in \"${event}\" listener:`, err)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners = {}\n }\n}\n","import type Hls from 'hls.js'\n\nlet HlsModule: typeof Hls | null = null\n\nexport async function loadHls(): Promise<typeof Hls | null> {\n if (HlsModule) return HlsModule\n try {\n const mod = await import('hls.js')\n HlsModule = mod.default\n return HlsModule\n } catch {\n return null\n }\n}\n\nexport function isHlsSupported(): boolean {\n try {\n // Synchronous check using the cached module\n return HlsModule ? HlsModule.isSupported() : false\n } catch {\n return false\n }\n}\n\nexport function isHlsSource(src: string): boolean {\n return src.includes('.m3u8') || src.includes('application/x-mpegURL')\n}\n","import type Hls from 'hls.js'\nimport { EventEmitter } from './events'\nimport { isHlsSource, loadHls } from './hls'\nimport type { Plugin, PlayerInstance, PlayerOptions, QualityLevel } from './types'\n\nfunction levelLabel(height: number): string {\n if (height >= 2160) return '4K'\n if (height >= 1080) return '1080p'\n if (height >= 720) return '720p'\n if (height >= 480) return '480p'\n if (height >= 360) return '360p'\n return `${height}p`\n}\n\nexport class Player extends EventEmitter implements PlayerInstance {\n private video: HTMLVideoElement\n private hls: Hls | null = null\n private plugins: Map<string, Plugin> = new Map()\n private _src = ''\n private _destroyed = false\n private _isLive = false\n private _qualityAuto = true\n private _hlsLevels: QualityLevel[] = []\n\n constructor(private readonly options: PlayerOptions) {\n super()\n this.video = this.resolveTarget(options.target)\n this.applyOptions()\n this.bindNativeEvents()\n if (options.src) {\n void this.setSrcAsync(options.src)\n }\n }\n\n private resolveTarget(target: string | HTMLVideoElement): HTMLVideoElement {\n if (target instanceof HTMLVideoElement) return target\n const el = document.querySelector(target)\n if (!(el instanceof HTMLVideoElement)) {\n throw new Error(`[lumra] Target \"${target}\" is not a <video> element`)\n }\n return el\n }\n\n private applyOptions(): void {\n const { muted = false, volume = 1, loop = false, autoplay = false } = this.options\n this.video.muted = muted\n this.video.volume = volume\n this.video.loop = loop\n this.video.autoplay = autoplay\n }\n\n private bindNativeEvents(): void {\n this.video.addEventListener('play', () => this.emit('play', undefined as void))\n this.video.addEventListener('pause', () => this.emit('pause', undefined as void))\n this.video.addEventListener('ended', () => this.emit('ended', undefined as void))\n this.video.addEventListener('waiting', () => this.emit('buffering', undefined as void))\n this.video.addEventListener('canplay', () => this.emit('ready', undefined as void))\n this.video.addEventListener('volumechange', () =>\n this.emit('volumechange', { volume: this.video.volume, muted: this.video.muted })\n )\n this.video.addEventListener('timeupdate', () =>\n this.emit('timeupdate', {\n currentTime: this.video.currentTime,\n duration: this.video.duration || 0,\n })\n )\n this.video.addEventListener('seeking', () =>\n this.emit('seeking', { time: this.video.currentTime })\n )\n this.video.addEventListener('seeked', () =>\n this.emit('seeked', { time: this.video.currentTime })\n )\n this.video.addEventListener('error', () => {\n const err = this.video.error\n this.emit('error', {\n code: err?.code ?? -1,\n message: err?.message ?? 'Unknown media error',\n })\n })\n }\n\n private async setSrcAsync(src: string): Promise<void> {\n this._src = src\n\n if (isHlsSource(src)) {\n const Hls = await loadHls()\n if (Hls && Hls.isSupported()) {\n this.destroyHls()\n const hls = new Hls(this.options.hlsConfig ?? {})\n this.hls = hls\n hls.loadSource(src)\n hls.attachMedia(this.video)\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n this._isLive = (data as { live?: boolean }).live === true\n const levels: QualityLevel[] = hls.levels.map((l, i) => ({\n index: i,\n height: l.height,\n bitrate: l.bitrate,\n label: levelLabel(l.height),\n }))\n this._hlsLevels = [\n { index: -1, height: 0, bitrate: 0, label: 'Auto' },\n ...levels,\n ]\n // Signal that the source is ready for play() — fires before segment\n // buffering so callers can call play() within the user-gesture window.\n this.emit('manifest', undefined as void)\n })\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {\n this.emit('levelchange', { level: data.level })\n this.emit('qualitychange', { level: data.level, auto: this._qualityAuto })\n })\n\n hls.on(Hls.Events.ERROR, (_event, data) => {\n if (data.fatal) {\n this.emit('error', { code: -2, message: data.details ?? 'HLS fatal error' })\n }\n })\n\n return\n }\n // Fallback: native HLS (Safari)\n if (this.video.canPlayType('application/vnd.apple.mpegurl')) {\n this.video.src = src\n void Promise.resolve().then(() => this.emit('manifest', undefined as void))\n return\n }\n this.emit('error', { code: -1, message: 'HLS is not supported in this browser' })\n return\n }\n\n this.destroyHls()\n this.video.src = src\n void Promise.resolve().then(() => this.emit('manifest', undefined as void))\n }\n\n private destroyHls(): void {\n if (this.hls) {\n this.hls.destroy()\n this.hls = null\n }\n }\n\n async play(): Promise<void> {\n await this.video.play()\n }\n\n pause(): void {\n this.video.pause()\n }\n\n seek(time: number): void {\n this.video.currentTime = time\n }\n\n setVolume(volume: number): void {\n this.video.volume = Math.max(0, Math.min(1, volume))\n }\n\n mute(): void {\n this.video.muted = true\n }\n\n unmute(): void {\n this.video.muted = false\n }\n\n setSrc(src: string): void {\n void this.setSrcAsync(src)\n }\n\n use(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n console.warn(`[lumra] Plugin \"${plugin.name}\" is already registered`)\n return\n }\n plugin.init(this)\n this.plugins.set(plugin.name, plugin)\n this.emit('plugin:register', { name: plugin.name })\n }\n\n destroy(): void {\n if (this._destroyed) return\n this._destroyed = true\n for (const plugin of this.plugins.values()) {\n plugin.destroy()\n }\n this.plugins.clear()\n this.destroyHls()\n this.video.pause()\n this.video.removeAttribute('src')\n this.video.load()\n this.emit('destroy', undefined as void)\n this.removeAllListeners()\n }\n\n getQualityLevels(): QualityLevel[] {\n return this._hlsLevels\n }\n\n setQuality(levelIndex: number): void {\n if (!this.hls) return\n this._qualityAuto = levelIndex === -1\n this.hls.currentLevel = levelIndex\n this.emit('qualitychange', { level: levelIndex, auto: this._qualityAuto })\n }\n\n get currentTime(): number { return this.video.currentTime }\n get duration(): number { return this.video.duration || 0 }\n get paused(): boolean { return this.video.paused }\n get volume(): number { return this.video.volume }\n get muted(): boolean { return this.video.muted }\n get src(): string { return this._src }\n get isLive(): boolean { return this._isLive }\n get isHls(): boolean { return this.hls !== null }\n get hlsInstance(): unknown | null { return this.hls }\n}\n","import { Player } from './player'\nimport type { PlayerOptions, PlayerInstance } from './types'\n\nexport function createPlayer(options: PlayerOptions): PlayerInstance {\n return new Player(options)\n}\n\nexport type { PlayerOptions, PlayerInstance, Plugin, PlayerEvent, PlayerEventMap, PlayerEventListener, QualityLevel } from './types'\nexport { EventEmitter } from './events'\n"]}
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -148,6 +148,7 @@ var Player = class extends EventEmitter {
|
|
|
148
148
|
{ index: -1, height: 0, bitrate: 0, label: "Auto" },
|
|
149
149
|
...levels
|
|
150
150
|
];
|
|
151
|
+
this.emit("manifest", void 0);
|
|
151
152
|
});
|
|
152
153
|
hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {
|
|
153
154
|
this.emit("levelchange", { level: data.level });
|
|
@@ -162,6 +163,7 @@ var Player = class extends EventEmitter {
|
|
|
162
163
|
}
|
|
163
164
|
if (this.video.canPlayType("application/vnd.apple.mpegurl")) {
|
|
164
165
|
this.video.src = src;
|
|
166
|
+
void Promise.resolve().then(() => this.emit("manifest", void 0));
|
|
165
167
|
return;
|
|
166
168
|
}
|
|
167
169
|
this.emit("error", { code: -1, message: "HLS is not supported in this browser" });
|
|
@@ -169,6 +171,7 @@ var Player = class extends EventEmitter {
|
|
|
169
171
|
}
|
|
170
172
|
this.destroyHls();
|
|
171
173
|
this.video.src = src;
|
|
174
|
+
void Promise.resolve().then(() => this.emit("manifest", void 0));
|
|
172
175
|
}
|
|
173
176
|
destroyHls() {
|
|
174
177
|
if (this.hls) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/events.ts","../src/hls.ts","../src/player.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PlayerEvent, PlayerEventListener, PlayerEventMap } from './types'\n\ntype ListenerMap = {\n [E in PlayerEvent]?: Set<PlayerEventListener<E>>\n}\n\nexport class EventEmitter {\n private listeners: ListenerMap = {}\n\n on<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n if (!this.listeners[event]) {\n this.listeners[event] = new Set() as ListenerMap[E]\n }\n ;(this.listeners[event] as Set<PlayerEventListener<E>>).add(listener)\n }\n\n off<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n (this.listeners[event] as Set<PlayerEventListener<E>> | undefined)?.delete(listener)\n }\n\n once<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n const wrapper: PlayerEventListener<E> = (data) => {\n listener(data)\n this.off(event, wrapper)\n }\n this.on(event, wrapper)\n }\n\n emit<E extends PlayerEvent>(event: E, data: PlayerEventMap[E]): void {\n const set = this.listeners[event] as Set<PlayerEventListener<E>> | undefined\n if (!set) return\n for (const listener of set) {\n try {\n listener(data)\n } catch (err) {\n console.error(`[lumra] Error in \"${event}\" listener:`, err)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners = {}\n }\n}\n","import type Hls from 'hls.js'\n\nlet HlsModule: typeof Hls | null = null\n\nexport async function loadHls(): Promise<typeof Hls | null> {\n if (HlsModule) return HlsModule\n try {\n const mod = await import('hls.js')\n HlsModule = mod.default\n return HlsModule\n } catch {\n return null\n }\n}\n\nexport function isHlsSupported(): boolean {\n try {\n // Synchronous check using the cached module\n return HlsModule ? HlsModule.isSupported() : false\n } catch {\n return false\n }\n}\n\nexport function isHlsSource(src: string): boolean {\n return src.includes('.m3u8') || src.includes('application/x-mpegURL')\n}\n","import type Hls from 'hls.js'\nimport { EventEmitter } from './events'\nimport { isHlsSource, loadHls } from './hls'\nimport type { Plugin, PlayerInstance, PlayerOptions, QualityLevel } from './types'\n\nfunction levelLabel(height: number): string {\n if (height >= 2160) return '4K'\n if (height >= 1080) return '1080p'\n if (height >= 720) return '720p'\n if (height >= 480) return '480p'\n if (height >= 360) return '360p'\n return `${height}p`\n}\n\nexport class Player extends EventEmitter implements PlayerInstance {\n private video: HTMLVideoElement\n private hls: Hls | null = null\n private plugins: Map<string, Plugin> = new Map()\n private _src = ''\n private _destroyed = false\n private _isLive = false\n private _qualityAuto = true\n private _hlsLevels: QualityLevel[] = []\n\n constructor(private readonly options: PlayerOptions) {\n super()\n this.video = this.resolveTarget(options.target)\n this.applyOptions()\n this.bindNativeEvents()\n if (options.src) {\n void this.setSrcAsync(options.src)\n }\n }\n\n private resolveTarget(target: string | HTMLVideoElement): HTMLVideoElement {\n if (target instanceof HTMLVideoElement) return target\n const el = document.querySelector(target)\n if (!(el instanceof HTMLVideoElement)) {\n throw new Error(`[lumra] Target \"${target}\" is not a <video> element`)\n }\n return el\n }\n\n private applyOptions(): void {\n const { muted = false, volume = 1, loop = false, autoplay = false } = this.options\n this.video.muted = muted\n this.video.volume = volume\n this.video.loop = loop\n this.video.autoplay = autoplay\n }\n\n private bindNativeEvents(): void {\n this.video.addEventListener('play', () => this.emit('play', undefined as void))\n this.video.addEventListener('pause', () => this.emit('pause', undefined as void))\n this.video.addEventListener('ended', () => this.emit('ended', undefined as void))\n this.video.addEventListener('waiting', () => this.emit('buffering', undefined as void))\n this.video.addEventListener('canplay', () => this.emit('ready', undefined as void))\n this.video.addEventListener('volumechange', () =>\n this.emit('volumechange', { volume: this.video.volume, muted: this.video.muted })\n )\n this.video.addEventListener('timeupdate', () =>\n this.emit('timeupdate', {\n currentTime: this.video.currentTime,\n duration: this.video.duration || 0,\n })\n )\n this.video.addEventListener('seeking', () =>\n this.emit('seeking', { time: this.video.currentTime })\n )\n this.video.addEventListener('seeked', () =>\n this.emit('seeked', { time: this.video.currentTime })\n )\n this.video.addEventListener('error', () => {\n const err = this.video.error\n this.emit('error', {\n code: err?.code ?? -1,\n message: err?.message ?? 'Unknown media error',\n })\n })\n }\n\n private async setSrcAsync(src: string): Promise<void> {\n this._src = src\n\n if (isHlsSource(src)) {\n const Hls = await loadHls()\n if (Hls && Hls.isSupported()) {\n this.destroyHls()\n const hls = new Hls(this.options.hlsConfig ?? {})\n this.hls = hls\n hls.loadSource(src)\n hls.attachMedia(this.video)\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n this._isLive = (data as { live?: boolean }).live === true\n const levels: QualityLevel[] = hls.levels.map((l, i) => ({\n index: i,\n height: l.height,\n bitrate: l.bitrate,\n label: levelLabel(l.height),\n }))\n this._hlsLevels = [\n { index: -1, height: 0, bitrate: 0, label: 'Auto' },\n ...levels,\n ]\n })\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {\n this.emit('levelchange', { level: data.level })\n this.emit('qualitychange', { level: data.level, auto: this._qualityAuto })\n })\n\n hls.on(Hls.Events.ERROR, (_event, data) => {\n if (data.fatal) {\n this.emit('error', { code: -2, message: data.details ?? 'HLS fatal error' })\n }\n })\n\n return\n }\n // Fallback: native HLS (Safari)\n if (this.video.canPlayType('application/vnd.apple.mpegurl')) {\n this.video.src = src\n return\n }\n this.emit('error', { code: -1, message: 'HLS is not supported in this browser' })\n return\n }\n\n this.destroyHls()\n this.video.src = src\n }\n\n private destroyHls(): void {\n if (this.hls) {\n this.hls.destroy()\n this.hls = null\n }\n }\n\n async play(): Promise<void> {\n await this.video.play()\n }\n\n pause(): void {\n this.video.pause()\n }\n\n seek(time: number): void {\n this.video.currentTime = time\n }\n\n setVolume(volume: number): void {\n this.video.volume = Math.max(0, Math.min(1, volume))\n }\n\n mute(): void {\n this.video.muted = true\n }\n\n unmute(): void {\n this.video.muted = false\n }\n\n setSrc(src: string): void {\n void this.setSrcAsync(src)\n }\n\n use(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n console.warn(`[lumra] Plugin \"${plugin.name}\" is already registered`)\n return\n }\n plugin.init(this)\n this.plugins.set(plugin.name, plugin)\n this.emit('plugin:register', { name: plugin.name })\n }\n\n destroy(): void {\n if (this._destroyed) return\n this._destroyed = true\n for (const plugin of this.plugins.values()) {\n plugin.destroy()\n }\n this.plugins.clear()\n this.destroyHls()\n this.video.pause()\n this.video.removeAttribute('src')\n this.video.load()\n this.emit('destroy', undefined as void)\n this.removeAllListeners()\n }\n\n getQualityLevels(): QualityLevel[] {\n return this._hlsLevels\n }\n\n setQuality(levelIndex: number): void {\n if (!this.hls) return\n this._qualityAuto = levelIndex === -1\n this.hls.currentLevel = levelIndex\n this.emit('qualitychange', { level: levelIndex, auto: this._qualityAuto })\n }\n\n get currentTime(): number { return this.video.currentTime }\n get duration(): number { return this.video.duration || 0 }\n get paused(): boolean { return this.video.paused }\n get volume(): number { return this.video.volume }\n get muted(): boolean { return this.video.muted }\n get src(): string { return this._src }\n get isLive(): boolean { return this._isLive }\n get isHls(): boolean { return this.hls !== null }\n get hlsInstance(): unknown | null { return this.hls }\n}\n","import { Player } from './player'\nimport type { PlayerOptions, PlayerInstance } from './types'\n\nexport function createPlayer(options: PlayerOptions): PlayerInstance {\n return new Player(options)\n}\n\nexport type { PlayerOptions, PlayerInstance, Plugin, PlayerEvent, PlayerEventMap, PlayerEventListener, QualityLevel } from './types'\nexport { EventEmitter } from './events'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/events.ts","../src/hls.ts","../src/player.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PlayerEvent, PlayerEventListener, PlayerEventMap } from './types'\n\ntype ListenerMap = {\n [E in PlayerEvent]?: Set<PlayerEventListener<E>>\n}\n\nexport class EventEmitter {\n private listeners: ListenerMap = {}\n\n on<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n if (!this.listeners[event]) {\n this.listeners[event] = new Set() as ListenerMap[E]\n }\n ;(this.listeners[event] as Set<PlayerEventListener<E>>).add(listener)\n }\n\n off<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n (this.listeners[event] as Set<PlayerEventListener<E>> | undefined)?.delete(listener)\n }\n\n once<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n const wrapper: PlayerEventListener<E> = (data) => {\n listener(data)\n this.off(event, wrapper)\n }\n this.on(event, wrapper)\n }\n\n emit<E extends PlayerEvent>(event: E, data: PlayerEventMap[E]): void {\n const set = this.listeners[event] as Set<PlayerEventListener<E>> | undefined\n if (!set) return\n for (const listener of set) {\n try {\n listener(data)\n } catch (err) {\n console.error(`[lumra] Error in \"${event}\" listener:`, err)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners = {}\n }\n}\n","import type Hls from 'hls.js'\n\nlet HlsModule: typeof Hls | null = null\n\nexport async function loadHls(): Promise<typeof Hls | null> {\n if (HlsModule) return HlsModule\n try {\n const mod = await import('hls.js')\n HlsModule = mod.default\n return HlsModule\n } catch {\n return null\n }\n}\n\nexport function isHlsSupported(): boolean {\n try {\n // Synchronous check using the cached module\n return HlsModule ? HlsModule.isSupported() : false\n } catch {\n return false\n }\n}\n\nexport function isHlsSource(src: string): boolean {\n return src.includes('.m3u8') || src.includes('application/x-mpegURL')\n}\n","import type Hls from 'hls.js'\nimport { EventEmitter } from './events'\nimport { isHlsSource, loadHls } from './hls'\nimport type { Plugin, PlayerInstance, PlayerOptions, QualityLevel } from './types'\n\nfunction levelLabel(height: number): string {\n if (height >= 2160) return '4K'\n if (height >= 1080) return '1080p'\n if (height >= 720) return '720p'\n if (height >= 480) return '480p'\n if (height >= 360) return '360p'\n return `${height}p`\n}\n\nexport class Player extends EventEmitter implements PlayerInstance {\n private video: HTMLVideoElement\n private hls: Hls | null = null\n private plugins: Map<string, Plugin> = new Map()\n private _src = ''\n private _destroyed = false\n private _isLive = false\n private _qualityAuto = true\n private _hlsLevels: QualityLevel[] = []\n\n constructor(private readonly options: PlayerOptions) {\n super()\n this.video = this.resolveTarget(options.target)\n this.applyOptions()\n this.bindNativeEvents()\n if (options.src) {\n void this.setSrcAsync(options.src)\n }\n }\n\n private resolveTarget(target: string | HTMLVideoElement): HTMLVideoElement {\n if (target instanceof HTMLVideoElement) return target\n const el = document.querySelector(target)\n if (!(el instanceof HTMLVideoElement)) {\n throw new Error(`[lumra] Target \"${target}\" is not a <video> element`)\n }\n return el\n }\n\n private applyOptions(): void {\n const { muted = false, volume = 1, loop = false, autoplay = false } = this.options\n this.video.muted = muted\n this.video.volume = volume\n this.video.loop = loop\n this.video.autoplay = autoplay\n }\n\n private bindNativeEvents(): void {\n this.video.addEventListener('play', () => this.emit('play', undefined as void))\n this.video.addEventListener('pause', () => this.emit('pause', undefined as void))\n this.video.addEventListener('ended', () => this.emit('ended', undefined as void))\n this.video.addEventListener('waiting', () => this.emit('buffering', undefined as void))\n this.video.addEventListener('canplay', () => this.emit('ready', undefined as void))\n this.video.addEventListener('volumechange', () =>\n this.emit('volumechange', { volume: this.video.volume, muted: this.video.muted })\n )\n this.video.addEventListener('timeupdate', () =>\n this.emit('timeupdate', {\n currentTime: this.video.currentTime,\n duration: this.video.duration || 0,\n })\n )\n this.video.addEventListener('seeking', () =>\n this.emit('seeking', { time: this.video.currentTime })\n )\n this.video.addEventListener('seeked', () =>\n this.emit('seeked', { time: this.video.currentTime })\n )\n this.video.addEventListener('error', () => {\n const err = this.video.error\n this.emit('error', {\n code: err?.code ?? -1,\n message: err?.message ?? 'Unknown media error',\n })\n })\n }\n\n private async setSrcAsync(src: string): Promise<void> {\n this._src = src\n\n if (isHlsSource(src)) {\n const Hls = await loadHls()\n if (Hls && Hls.isSupported()) {\n this.destroyHls()\n const hls = new Hls(this.options.hlsConfig ?? {})\n this.hls = hls\n hls.loadSource(src)\n hls.attachMedia(this.video)\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n this._isLive = (data as { live?: boolean }).live === true\n const levels: QualityLevel[] = hls.levels.map((l, i) => ({\n index: i,\n height: l.height,\n bitrate: l.bitrate,\n label: levelLabel(l.height),\n }))\n this._hlsLevels = [\n { index: -1, height: 0, bitrate: 0, label: 'Auto' },\n ...levels,\n ]\n // Signal that the source is ready for play() — fires before segment\n // buffering so callers can call play() within the user-gesture window.\n this.emit('manifest', undefined as void)\n })\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {\n this.emit('levelchange', { level: data.level })\n this.emit('qualitychange', { level: data.level, auto: this._qualityAuto })\n })\n\n hls.on(Hls.Events.ERROR, (_event, data) => {\n if (data.fatal) {\n this.emit('error', { code: -2, message: data.details ?? 'HLS fatal error' })\n }\n })\n\n return\n }\n // Fallback: native HLS (Safari)\n if (this.video.canPlayType('application/vnd.apple.mpegurl')) {\n this.video.src = src\n void Promise.resolve().then(() => this.emit('manifest', undefined as void))\n return\n }\n this.emit('error', { code: -1, message: 'HLS is not supported in this browser' })\n return\n }\n\n this.destroyHls()\n this.video.src = src\n void Promise.resolve().then(() => this.emit('manifest', undefined as void))\n }\n\n private destroyHls(): void {\n if (this.hls) {\n this.hls.destroy()\n this.hls = null\n }\n }\n\n async play(): Promise<void> {\n await this.video.play()\n }\n\n pause(): void {\n this.video.pause()\n }\n\n seek(time: number): void {\n this.video.currentTime = time\n }\n\n setVolume(volume: number): void {\n this.video.volume = Math.max(0, Math.min(1, volume))\n }\n\n mute(): void {\n this.video.muted = true\n }\n\n unmute(): void {\n this.video.muted = false\n }\n\n setSrc(src: string): void {\n void this.setSrcAsync(src)\n }\n\n use(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n console.warn(`[lumra] Plugin \"${plugin.name}\" is already registered`)\n return\n }\n plugin.init(this)\n this.plugins.set(plugin.name, plugin)\n this.emit('plugin:register', { name: plugin.name })\n }\n\n destroy(): void {\n if (this._destroyed) return\n this._destroyed = true\n for (const plugin of this.plugins.values()) {\n plugin.destroy()\n }\n this.plugins.clear()\n this.destroyHls()\n this.video.pause()\n this.video.removeAttribute('src')\n this.video.load()\n this.emit('destroy', undefined as void)\n this.removeAllListeners()\n }\n\n getQualityLevels(): QualityLevel[] {\n return this._hlsLevels\n }\n\n setQuality(levelIndex: number): void {\n if (!this.hls) return\n this._qualityAuto = levelIndex === -1\n this.hls.currentLevel = levelIndex\n this.emit('qualitychange', { level: levelIndex, auto: this._qualityAuto })\n }\n\n get currentTime(): number { return this.video.currentTime }\n get duration(): number { return this.video.duration || 0 }\n get paused(): boolean { return this.video.paused }\n get volume(): number { return this.video.volume }\n get muted(): boolean { return this.video.muted }\n get src(): string { return this._src }\n get isLive(): boolean { return this._isLive }\n get isHls(): boolean { return this.hls !== null }\n get hlsInstance(): unknown | null { return this.hls }\n}\n","import { Player } from './player'\nimport type { PlayerOptions, PlayerInstance } from './types'\n\nexport function createPlayer(options: PlayerOptions): PlayerInstance {\n return new Player(options)\n}\n\nexport type { PlayerOptions, PlayerInstance, Plugin, PlayerEvent, PlayerEventMap, PlayerEventListener, QualityLevel } from './types'\nexport { EventEmitter } from './events'\n"]}
|