@scarlett-player/hls 0.1.2 → 0.2.0

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/index.js CHANGED
@@ -1,3 +1,9 @@
1
+ import {
2
+ mapLevels,
3
+ setupHlsEventHandlers,
4
+ setupVideoEventHandlers
5
+ } from "./chunk-CBBDW7UR.js";
6
+
1
7
  // src/hls-loader.ts
2
8
  var hlsConstructor = null;
3
9
  var loadingPromise = null;
@@ -50,264 +56,6 @@ function getHlsConstructor() {
50
56
  return hlsConstructor;
51
57
  }
52
58
 
53
- // src/quality.ts
54
- function formatLevel(level) {
55
- if (level.name) {
56
- return level.name;
57
- }
58
- if (level.height) {
59
- const standardLabels = {
60
- 2160: "4K",
61
- 1440: "1440p",
62
- 1080: "1080p",
63
- 720: "720p",
64
- 480: "480p",
65
- 360: "360p",
66
- 240: "240p",
67
- 144: "144p"
68
- };
69
- const closest = Object.keys(standardLabels).map(Number).sort((a, b) => Math.abs(a - level.height) - Math.abs(b - level.height))[0];
70
- if (Math.abs(closest - level.height) <= 20) {
71
- return standardLabels[closest];
72
- }
73
- return `${level.height}p`;
74
- }
75
- if (level.bitrate) {
76
- return formatBitrate(level.bitrate);
77
- }
78
- return "Unknown";
79
- }
80
- function formatBitrate(bitrate) {
81
- if (bitrate >= 1e6) {
82
- return `${(bitrate / 1e6).toFixed(1)} Mbps`;
83
- }
84
- if (bitrate >= 1e3) {
85
- return `${Math.round(bitrate / 1e3)} Kbps`;
86
- }
87
- return `${bitrate} bps`;
88
- }
89
- function mapLevels(levels, currentLevel) {
90
- return levels.map((level, index) => ({
91
- index,
92
- width: level.width || 0,
93
- height: level.height || 0,
94
- bitrate: level.bitrate || 0,
95
- label: formatLevel(level),
96
- codec: level.codecSet
97
- }));
98
- }
99
-
100
- // src/event-map.ts
101
- var HLS_ERROR_TYPES = {
102
- NETWORK_ERROR: "networkError",
103
- MEDIA_ERROR: "mediaError",
104
- KEY_SYSTEM_ERROR: "keySystemError",
105
- MUX_ERROR: "muxError",
106
- OTHER_ERROR: "otherError"
107
- };
108
- function mapErrorType(hlsType) {
109
- switch (hlsType) {
110
- case HLS_ERROR_TYPES.NETWORK_ERROR:
111
- return "network";
112
- case HLS_ERROR_TYPES.MEDIA_ERROR:
113
- return "media";
114
- case HLS_ERROR_TYPES.MUX_ERROR:
115
- return "mux";
116
- default:
117
- return "other";
118
- }
119
- }
120
- function parseHlsError(data) {
121
- return {
122
- type: mapErrorType(data.type),
123
- details: data.details || "Unknown error",
124
- fatal: data.fatal || false,
125
- url: data.url,
126
- reason: data.reason,
127
- response: data.response
128
- };
129
- }
130
- function setupHlsEventHandlers(hls, api, callbacks) {
131
- const handlers = [];
132
- const addHandler = (event, handler) => {
133
- hls.on(event, handler);
134
- handlers.push({ event, handler });
135
- };
136
- addHandler("hlsManifestParsed", (_event, data) => {
137
- api.logger.debug("HLS manifest parsed", { levels: data.levels.length });
138
- const levels = data.levels.map((level, index) => ({
139
- id: `level-${index}`,
140
- label: formatLevel(level),
141
- width: level.width,
142
- height: level.height,
143
- bitrate: level.bitrate,
144
- active: index === hls.currentLevel
145
- }));
146
- api.setState("qualities", levels);
147
- api.emit("quality:levels", {
148
- levels: levels.map((l) => ({ id: l.id, label: l.label }))
149
- });
150
- callbacks.onManifestParsed?.(data.levels);
151
- });
152
- addHandler("hlsLevelSwitched", (_event, data) => {
153
- const level = hls.levels[data.level];
154
- const isAuto = callbacks.getIsAutoQuality?.() ?? hls.autoLevelEnabled;
155
- api.logger.debug("HLS level switched", { level: data.level, height: level?.height, auto: isAuto });
156
- if (level) {
157
- const label = isAuto ? `Auto (${formatLevel(level)})` : formatLevel(level);
158
- api.setState("currentQuality", {
159
- id: isAuto ? "auto" : `level-${data.level}`,
160
- label,
161
- width: level.width,
162
- height: level.height,
163
- bitrate: level.bitrate,
164
- active: true
165
- });
166
- }
167
- api.emit("quality:change", {
168
- quality: level ? formatLevel(level) : "auto",
169
- auto: isAuto
170
- });
171
- callbacks.onLevelSwitched?.(data.level);
172
- });
173
- addHandler("hlsFragBuffered", () => {
174
- api.setState("buffering", false);
175
- callbacks.onBufferUpdate?.();
176
- });
177
- addHandler("hlsFragLoading", () => {
178
- api.setState("buffering", true);
179
- });
180
- addHandler("hlsLevelLoaded", (_event, data) => {
181
- if (data.details?.live !== void 0) {
182
- api.setState("live", data.details.live);
183
- callbacks.onLiveUpdate?.();
184
- }
185
- });
186
- addHandler("hlsError", (_event, data) => {
187
- const error = parseHlsError(data);
188
- api.logger.warn("HLS error", { error });
189
- callbacks.onError?.(error);
190
- });
191
- return () => {
192
- for (const { event, handler } of handlers) {
193
- hls.off(event, handler);
194
- }
195
- handlers.length = 0;
196
- };
197
- }
198
- function setupVideoEventHandlers(video, api) {
199
- const handlers = [];
200
- const addHandler = (event, handler) => {
201
- video.addEventListener(event, handler);
202
- handlers.push({ event, handler });
203
- };
204
- addHandler("playing", () => {
205
- api.setState("playing", true);
206
- api.setState("paused", false);
207
- api.setState("playbackState", "playing");
208
- });
209
- addHandler("pause", () => {
210
- api.setState("playing", false);
211
- api.setState("paused", true);
212
- api.setState("playbackState", "paused");
213
- });
214
- addHandler("ended", () => {
215
- api.setState("playing", false);
216
- api.setState("ended", true);
217
- api.setState("playbackState", "ended");
218
- api.emit("playback:ended", void 0);
219
- });
220
- addHandler("timeupdate", () => {
221
- api.setState("currentTime", video.currentTime);
222
- api.emit("playback:timeupdate", { currentTime: video.currentTime });
223
- });
224
- addHandler("durationchange", () => {
225
- api.setState("duration", video.duration || 0);
226
- api.emit("media:loadedmetadata", { duration: video.duration || 0 });
227
- });
228
- addHandler("waiting", () => {
229
- api.setState("waiting", true);
230
- api.setState("buffering", true);
231
- api.emit("media:waiting", void 0);
232
- });
233
- addHandler("canplay", () => {
234
- api.setState("waiting", false);
235
- api.setState("playbackState", "ready");
236
- api.emit("media:canplay", void 0);
237
- });
238
- addHandler("canplaythrough", () => {
239
- api.setState("buffering", false);
240
- api.emit("media:canplaythrough", void 0);
241
- });
242
- addHandler("progress", () => {
243
- if (video.buffered.length > 0) {
244
- const bufferedEnd = video.buffered.end(video.buffered.length - 1);
245
- const bufferedAmount = video.duration > 0 ? bufferedEnd / video.duration : 0;
246
- api.setState("bufferedAmount", bufferedAmount);
247
- api.setState("buffered", video.buffered);
248
- api.emit("media:progress", { buffered: bufferedAmount });
249
- }
250
- });
251
- addHandler("seeking", () => {
252
- api.setState("seeking", true);
253
- });
254
- addHandler("seeked", () => {
255
- api.setState("seeking", false);
256
- api.emit("playback:seeked", { time: video.currentTime });
257
- });
258
- addHandler("volumechange", () => {
259
- api.setState("volume", video.volume);
260
- api.setState("muted", video.muted);
261
- api.emit("volume:change", { volume: video.volume, muted: video.muted });
262
- });
263
- addHandler("ratechange", () => {
264
- api.setState("playbackRate", video.playbackRate);
265
- api.emit("playback:ratechange", { rate: video.playbackRate });
266
- });
267
- addHandler("loadedmetadata", () => {
268
- api.setState("duration", video.duration);
269
- api.setState("mediaType", video.videoWidth > 0 ? "video" : "audio");
270
- });
271
- addHandler("error", () => {
272
- const error = video.error;
273
- if (error) {
274
- api.logger.error("Video element error", { code: error.code, message: error.message });
275
- api.emit("media:error", { error: new Error(error.message || "Video playback error") });
276
- }
277
- });
278
- addHandler("enterpictureinpicture", () => {
279
- api.setState("pip", true);
280
- api.logger.debug("PiP: entered (standard)");
281
- });
282
- addHandler("leavepictureinpicture", () => {
283
- api.setState("pip", false);
284
- api.logger.debug("PiP: exited (standard)");
285
- if (!video.paused || api.getState("playing")) {
286
- video.play().catch(() => {
287
- });
288
- }
289
- });
290
- const webkitVideo = video;
291
- if ("webkitPresentationMode" in video) {
292
- addHandler("webkitpresentationmodechanged", () => {
293
- const mode = webkitVideo.webkitPresentationMode;
294
- const isInPip = mode === "picture-in-picture";
295
- api.setState("pip", isInPip);
296
- api.logger.debug(`PiP: mode changed to ${mode} (webkit)`);
297
- if (mode === "inline" && video.paused) {
298
- video.play().catch(() => {
299
- });
300
- }
301
- });
302
- }
303
- return () => {
304
- for (const { event, handler } of handlers) {
305
- video.removeEventListener(event, handler);
306
- }
307
- handlers.length = 0;
308
- };
309
- }
310
-
311
59
  // src/index.ts
312
60
  var DEFAULT_CONFIG = {
313
61
  debug: false,
@@ -353,6 +101,10 @@ function createHLSPlugin(config) {
353
101
  video.preload = "metadata";
354
102
  video.controls = false;
355
103
  video.playsInline = true;
104
+ const poster = api?.getState("poster");
105
+ if (poster) {
106
+ video.poster = poster;
107
+ }
356
108
  api?.container.appendChild(video);
357
109
  return video;
358
110
  };