@scarlett-player/native 1.6.0 → 1.8.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/README.md CHANGED
@@ -11,16 +11,14 @@ npm install @scarlett-player/core @scarlett-player/native
11
11
  ## Usage
12
12
 
13
13
  ```typescript
14
- import { ScarlettPlayer } from '@scarlett-player/core';
14
+ import { createPlayer } from '@scarlett-player/core';
15
15
  import { createNativePlugin } from '@scarlett-player/native';
16
16
 
17
- const player = new ScarlettPlayer({
17
+ const player = await createPlayer({
18
18
  container: document.getElementById('player'),
19
+ src: 'https://example.com/video.mp4',
19
20
  plugins: [createNativePlugin()],
20
21
  });
21
-
22
- await player.init();
23
- await player.load('https://example.com/video.mp4');
24
22
  ```
25
23
 
26
24
  ## Supported Formats
package/dist/index.cjs CHANGED
@@ -25,6 +25,11 @@ __export(index_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(index_exports);
27
27
  var import_core = require("@scarlett-player/core");
28
+
29
+ // src/version.ts
30
+ var PKG_VERSION = true ? "1.7.1" : "0.0.0-dev";
31
+
32
+ // src/index.ts
28
33
  var VIDEO_EXTENSIONS = ["mp4", "webm", "mov", "mkv", "ogv", "m4v"];
29
34
  var AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "flac", "aac", "m4a", "opus", "weba"];
30
35
  var SUPPORTED_EXTENSIONS = [...VIDEO_EXTENSIONS, ...AUDIO_EXTENSIONS];
@@ -53,6 +58,7 @@ function createNativePlugin(config) {
53
58
  let video = null;
54
59
  let cleanupEvents = null;
55
60
  let derived_title = null;
61
+ let is_audio_source = false;
56
62
  const getExtension = (src) => {
57
63
  try {
58
64
  const url = new URL(src, window.location.href);
@@ -76,6 +82,14 @@ function createNativePlugin(config) {
76
82
  const canPlay = testElement.canPlayType(mimeType);
77
83
  return canPlay === "probably" || canPlay === "maybe";
78
84
  };
85
+ const applyPoster = () => {
86
+ if (!video) return;
87
+ if (is_audio_source) {
88
+ video.poster = "";
89
+ return;
90
+ }
91
+ video.poster = api?.getState("poster") || "";
92
+ };
79
93
  const getOrCreateVideo = () => {
80
94
  if (video) return video;
81
95
  const existing = api?.container.querySelector("video");
@@ -88,10 +102,7 @@ function createNativePlugin(config) {
88
102
  video.preload = preload;
89
103
  video.controls = false;
90
104
  video.playsInline = true;
91
- const poster = api?.getState("poster");
92
- if (poster) {
93
- video.poster = poster;
94
- }
105
+ applyPoster();
95
106
  api?.container.appendChild(video);
96
107
  return video;
97
108
  };
@@ -101,22 +112,32 @@ function createNativePlugin(config) {
101
112
  videoEl.addEventListener(event, handler);
102
113
  handlers.push([event, handler]);
103
114
  };
115
+ const syncEndedFromElement = () => {
116
+ if (videoEl.ended || !api?.getState("ended")) return;
117
+ api?.setState("ended", false);
118
+ api?.setState("playbackState", videoEl.paused ? "paused" : "playing");
119
+ };
104
120
  on("play", () => {
105
121
  api?.setState("paused", false);
122
+ syncEndedFromElement();
106
123
  });
107
124
  on("playing", () => {
108
125
  api?.setState("playing", true);
109
126
  api?.setState("paused", false);
127
+ api?.setState("playbackState", "playing");
110
128
  api?.emit("playback:play", void 0);
129
+ syncEndedFromElement();
111
130
  });
112
131
  on("pause", () => {
113
132
  api?.setState("playing", false);
114
133
  api?.setState("paused", true);
134
+ api?.setState("playbackState", "paused");
115
135
  api?.emit("playback:pause", void 0);
116
136
  });
117
137
  on("ended", () => {
118
138
  api?.setState("playing", false);
119
139
  api?.setState("ended", true);
140
+ api?.setState("playbackState", "ended");
120
141
  api?.emit("playback:ended", void 0);
121
142
  });
122
143
  on("timeupdate", () => {
@@ -152,6 +173,7 @@ function createNativePlugin(config) {
152
173
  });
153
174
  on("seeking", () => {
154
175
  api?.setState("seeking", true);
176
+ syncEndedFromElement();
155
177
  });
156
178
  on("seeked", () => {
157
179
  api?.setState("seeking", false);
@@ -246,7 +268,7 @@ function createNativePlugin(config) {
246
268
  const plugin = {
247
269
  id: "native-provider",
248
270
  name: "Native Media Provider",
249
- version: "1.0.0",
271
+ version: PKG_VERSION,
250
272
  type: "provider",
251
273
  description: "Native HTML5 playback for video (MP4, WebM, MOV) and audio (MP3, WAV, FLAC, AAC)",
252
274
  canPlay(src) {
@@ -288,6 +310,9 @@ function createNativePlugin(config) {
288
310
  const unsubRate = api.on("playback:ratechange", ({ rate }) => {
289
311
  if (video) video.playbackRate = rate;
290
312
  });
313
+ const unsubPoster = api.subscribeToState((event) => {
314
+ if (event.key === "poster") applyPoster();
315
+ });
291
316
  api.onDestroy(() => {
292
317
  unsubPlay();
293
318
  unsubPause();
@@ -295,6 +320,7 @@ function createNativePlugin(config) {
295
320
  unsubVolume();
296
321
  unsubMute();
297
322
  unsubRate();
323
+ unsubPoster();
298
324
  });
299
325
  },
300
326
  async destroy() {
@@ -306,12 +332,14 @@ function createNativePlugin(config) {
306
332
  video = null;
307
333
  api = null;
308
334
  derived_title = null;
335
+ is_audio_source = false;
309
336
  },
310
337
  async loadSource(src) {
311
338
  if (!api) throw new Error("Plugin not initialized");
312
339
  const ext = getExtension(src);
313
340
  const mimeType = getMimeType(ext);
314
341
  const isAudio = isAudioExtension(ext);
342
+ is_audio_source = isAudio;
315
343
  api.logger.info("Loading native media source", { src, mimeType, isAudio });
316
344
  cleanup();
317
345
  api.setState("playbackState", "loading");
@@ -335,16 +363,8 @@ function createNativePlugin(config) {
335
363
  api.setState("qualities", []);
336
364
  api.setState("currentQuality", null);
337
365
  const videoEl = getOrCreateVideo();
338
- if (isAudio) {
339
- videoEl.style.display = "none";
340
- videoEl.poster = "";
341
- } else {
342
- videoEl.style.display = "block";
343
- const poster = api.getState("poster");
344
- if (poster) {
345
- videoEl.poster = poster;
346
- }
347
- }
366
+ videoEl.style.display = isAudio ? "none" : "block";
367
+ applyPoster();
348
368
  cleanupEvents = setupEventListeners(videoEl);
349
369
  return new Promise((resolve, reject) => {
350
370
  let watchdog = null;
package/dist/index.d.cts CHANGED
@@ -50,9 +50,10 @@ interface INativePlugin {
50
50
  *
51
51
  * @example
52
52
  * ```ts
53
+ * import { createPlayer } from '@scarlett-player/core';
53
54
  * import { createNativePlugin } from '@scarlett-player/native';
54
55
  *
55
- * const player = new ScarlettPlayer({
56
+ * const player = await createPlayer({
56
57
  * container: document.getElementById('player'),
57
58
  * plugins: [createNativePlugin()],
58
59
  * });
package/dist/index.d.ts CHANGED
@@ -50,9 +50,10 @@ interface INativePlugin {
50
50
  *
51
51
  * @example
52
52
  * ```ts
53
+ * import { createPlayer } from '@scarlett-player/core';
53
54
  * import { createNativePlugin } from '@scarlett-player/native';
54
55
  *
55
- * const player = new ScarlettPlayer({
56
+ * const player = await createPlayer({
56
57
  * container: document.getElementById('player'),
57
58
  * plugins: [createNativePlugin()],
58
59
  * });
package/dist/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  // src/index.ts
2
2
  import { ErrorCode } from "@scarlett-player/core";
3
+
4
+ // src/version.ts
5
+ var PKG_VERSION = true ? "1.7.1" : "0.0.0-dev";
6
+
7
+ // src/index.ts
3
8
  var VIDEO_EXTENSIONS = ["mp4", "webm", "mov", "mkv", "ogv", "m4v"];
4
9
  var AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "flac", "aac", "m4a", "opus", "weba"];
5
10
  var SUPPORTED_EXTENSIONS = [...VIDEO_EXTENSIONS, ...AUDIO_EXTENSIONS];
@@ -28,6 +33,7 @@ function createNativePlugin(config) {
28
33
  let video = null;
29
34
  let cleanupEvents = null;
30
35
  let derived_title = null;
36
+ let is_audio_source = false;
31
37
  const getExtension = (src) => {
32
38
  try {
33
39
  const url = new URL(src, window.location.href);
@@ -51,6 +57,14 @@ function createNativePlugin(config) {
51
57
  const canPlay = testElement.canPlayType(mimeType);
52
58
  return canPlay === "probably" || canPlay === "maybe";
53
59
  };
60
+ const applyPoster = () => {
61
+ if (!video) return;
62
+ if (is_audio_source) {
63
+ video.poster = "";
64
+ return;
65
+ }
66
+ video.poster = api?.getState("poster") || "";
67
+ };
54
68
  const getOrCreateVideo = () => {
55
69
  if (video) return video;
56
70
  const existing = api?.container.querySelector("video");
@@ -63,10 +77,7 @@ function createNativePlugin(config) {
63
77
  video.preload = preload;
64
78
  video.controls = false;
65
79
  video.playsInline = true;
66
- const poster = api?.getState("poster");
67
- if (poster) {
68
- video.poster = poster;
69
- }
80
+ applyPoster();
70
81
  api?.container.appendChild(video);
71
82
  return video;
72
83
  };
@@ -76,22 +87,32 @@ function createNativePlugin(config) {
76
87
  videoEl.addEventListener(event, handler);
77
88
  handlers.push([event, handler]);
78
89
  };
90
+ const syncEndedFromElement = () => {
91
+ if (videoEl.ended || !api?.getState("ended")) return;
92
+ api?.setState("ended", false);
93
+ api?.setState("playbackState", videoEl.paused ? "paused" : "playing");
94
+ };
79
95
  on("play", () => {
80
96
  api?.setState("paused", false);
97
+ syncEndedFromElement();
81
98
  });
82
99
  on("playing", () => {
83
100
  api?.setState("playing", true);
84
101
  api?.setState("paused", false);
102
+ api?.setState("playbackState", "playing");
85
103
  api?.emit("playback:play", void 0);
104
+ syncEndedFromElement();
86
105
  });
87
106
  on("pause", () => {
88
107
  api?.setState("playing", false);
89
108
  api?.setState("paused", true);
109
+ api?.setState("playbackState", "paused");
90
110
  api?.emit("playback:pause", void 0);
91
111
  });
92
112
  on("ended", () => {
93
113
  api?.setState("playing", false);
94
114
  api?.setState("ended", true);
115
+ api?.setState("playbackState", "ended");
95
116
  api?.emit("playback:ended", void 0);
96
117
  });
97
118
  on("timeupdate", () => {
@@ -127,6 +148,7 @@ function createNativePlugin(config) {
127
148
  });
128
149
  on("seeking", () => {
129
150
  api?.setState("seeking", true);
151
+ syncEndedFromElement();
130
152
  });
131
153
  on("seeked", () => {
132
154
  api?.setState("seeking", false);
@@ -221,7 +243,7 @@ function createNativePlugin(config) {
221
243
  const plugin = {
222
244
  id: "native-provider",
223
245
  name: "Native Media Provider",
224
- version: "1.0.0",
246
+ version: PKG_VERSION,
225
247
  type: "provider",
226
248
  description: "Native HTML5 playback for video (MP4, WebM, MOV) and audio (MP3, WAV, FLAC, AAC)",
227
249
  canPlay(src) {
@@ -263,6 +285,9 @@ function createNativePlugin(config) {
263
285
  const unsubRate = api.on("playback:ratechange", ({ rate }) => {
264
286
  if (video) video.playbackRate = rate;
265
287
  });
288
+ const unsubPoster = api.subscribeToState((event) => {
289
+ if (event.key === "poster") applyPoster();
290
+ });
266
291
  api.onDestroy(() => {
267
292
  unsubPlay();
268
293
  unsubPause();
@@ -270,6 +295,7 @@ function createNativePlugin(config) {
270
295
  unsubVolume();
271
296
  unsubMute();
272
297
  unsubRate();
298
+ unsubPoster();
273
299
  });
274
300
  },
275
301
  async destroy() {
@@ -281,12 +307,14 @@ function createNativePlugin(config) {
281
307
  video = null;
282
308
  api = null;
283
309
  derived_title = null;
310
+ is_audio_source = false;
284
311
  },
285
312
  async loadSource(src) {
286
313
  if (!api) throw new Error("Plugin not initialized");
287
314
  const ext = getExtension(src);
288
315
  const mimeType = getMimeType(ext);
289
316
  const isAudio = isAudioExtension(ext);
317
+ is_audio_source = isAudio;
290
318
  api.logger.info("Loading native media source", { src, mimeType, isAudio });
291
319
  cleanup();
292
320
  api.setState("playbackState", "loading");
@@ -310,16 +338,8 @@ function createNativePlugin(config) {
310
338
  api.setState("qualities", []);
311
339
  api.setState("currentQuality", null);
312
340
  const videoEl = getOrCreateVideo();
313
- if (isAudio) {
314
- videoEl.style.display = "none";
315
- videoEl.poster = "";
316
- } else {
317
- videoEl.style.display = "block";
318
- const poster = api.getState("poster");
319
- if (poster) {
320
- videoEl.poster = poster;
321
- }
322
- }
341
+ videoEl.style.display = isAudio ? "none" : "block";
342
+ applyPoster();
323
343
  cleanupEvents = setupEventListeners(videoEl);
324
344
  return new Promise((resolve, reject) => {
325
345
  let watchdog = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scarlett-player/native",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Native Video Provider Plugin for Scarlett Player (MP4, WebM, MOV, MKV)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -17,13 +17,13 @@
17
17
  "dist"
18
18
  ],
19
19
  "peerDependencies": {
20
- "@scarlett-player/core": "^1.0.3"
20
+ "@scarlett-player/core": "^1.7.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "typescript": "^5.3.0",
24
24
  "tsup": "^8.0.0",
25
25
  "vitest": "^1.6.0",
26
- "@scarlett-player/core": "1.6.0"
26
+ "@scarlett-player/core": "1.8.0"
27
27
  },
28
28
  "keywords": [
29
29
  "video",
@@ -45,9 +45,10 @@
45
45
  },
46
46
  "homepage": "https://scarlettplayer.com",
47
47
  "scripts": {
48
- "build": "tsup src/index.ts --format esm,cjs --dts",
49
- "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
48
+ "build": "tsup",
49
+ "dev": "tsup --watch",
50
50
  "test": "vitest --run",
51
- "test:watch": "vitest"
51
+ "test:watch": "vitest",
52
+ "typecheck": "tsc --noEmit -p tsconfig.typecheck.json"
52
53
  }
53
54
  }