@scarlett-player/native 1.0.1 → 1.1.1
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.cjs +31 -10
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +31 -10
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -48,9 +48,11 @@ var MIME_TYPES = {
|
|
|
48
48
|
};
|
|
49
49
|
function createNativePlugin(config) {
|
|
50
50
|
const preload = config?.preload ?? "metadata";
|
|
51
|
+
const load_timeout_ms = config?.loadTimeoutMs ?? 3e4;
|
|
51
52
|
let api = null;
|
|
52
53
|
let video = null;
|
|
53
54
|
let cleanupEvents = null;
|
|
55
|
+
let derived_title = null;
|
|
54
56
|
const getExtension = (src) => {
|
|
55
57
|
try {
|
|
56
58
|
const url = new URL(src, window.location.href);
|
|
@@ -279,6 +281,7 @@ function createNativePlugin(config) {
|
|
|
279
281
|
}
|
|
280
282
|
video = null;
|
|
281
283
|
api = null;
|
|
284
|
+
derived_title = null;
|
|
282
285
|
},
|
|
283
286
|
async loadSource(src) {
|
|
284
287
|
if (!api) throw new Error("Plugin not initialized");
|
|
@@ -291,13 +294,18 @@ function createNativePlugin(config) {
|
|
|
291
294
|
api.setState("buffering", true);
|
|
292
295
|
api.setState("mediaType", isAudio ? "audio" : "video");
|
|
293
296
|
if (isAudio) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
297
|
+
const current_title = api.getState("title");
|
|
298
|
+
if (!current_title || current_title === derived_title) {
|
|
299
|
+
try {
|
|
300
|
+
const url = new URL(src, window.location.href);
|
|
301
|
+
const filename = url.pathname.split("/").pop() || "Audio";
|
|
302
|
+
const title = decodeURIComponent(filename.replace(/\.[^.]+$/, "").replace(/[-_]/g, " "));
|
|
303
|
+
derived_title = title;
|
|
304
|
+
api.setState("title", title);
|
|
305
|
+
} catch {
|
|
306
|
+
derived_title = "Audio";
|
|
307
|
+
api.setState("title", "Audio");
|
|
308
|
+
}
|
|
301
309
|
}
|
|
302
310
|
}
|
|
303
311
|
api.setState("qualities", []);
|
|
@@ -315,9 +323,17 @@ function createNativePlugin(config) {
|
|
|
315
323
|
}
|
|
316
324
|
cleanupEvents = setupEventListeners(videoEl);
|
|
317
325
|
return new Promise((resolve, reject) => {
|
|
318
|
-
|
|
326
|
+
let watchdog = null;
|
|
327
|
+
const settle = () => {
|
|
319
328
|
videoEl.removeEventListener("loadedmetadata", onLoaded);
|
|
320
329
|
videoEl.removeEventListener("error", onError);
|
|
330
|
+
if (watchdog !== null) {
|
|
331
|
+
clearTimeout(watchdog);
|
|
332
|
+
watchdog = null;
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
const onLoaded = () => {
|
|
336
|
+
settle();
|
|
321
337
|
const muted = api?.getState("muted");
|
|
322
338
|
const volume = api?.getState("volume");
|
|
323
339
|
if (muted !== void 0) videoEl.muted = muted;
|
|
@@ -329,11 +345,16 @@ function createNativePlugin(config) {
|
|
|
329
345
|
resolve();
|
|
330
346
|
};
|
|
331
347
|
const onError = () => {
|
|
332
|
-
|
|
333
|
-
videoEl.removeEventListener("error", onError);
|
|
348
|
+
settle();
|
|
334
349
|
const error = videoEl.error;
|
|
335
350
|
reject(new Error(error?.message || "Failed to load video source"));
|
|
336
351
|
};
|
|
352
|
+
if (load_timeout_ms > 0) {
|
|
353
|
+
watchdog = setTimeout(() => {
|
|
354
|
+
settle();
|
|
355
|
+
reject(new Error("Video took too long to load (network timeout)"));
|
|
356
|
+
}, load_timeout_ms);
|
|
357
|
+
}
|
|
337
358
|
videoEl.addEventListener("loadedmetadata", onLoaded);
|
|
338
359
|
videoEl.addEventListener("error", onError);
|
|
339
360
|
videoEl.src = src;
|
package/dist/index.d.cts
CHANGED
|
@@ -24,6 +24,12 @@ import { PluginType, IPluginAPI } from '@scarlett-player/core';
|
|
|
24
24
|
interface NativePluginConfig {
|
|
25
25
|
/** Preload behavior: 'none' | 'metadata' | 'auto' */
|
|
26
26
|
preload?: 'none' | 'metadata' | 'auto';
|
|
27
|
+
/**
|
|
28
|
+
* Watchdog for source loading in milliseconds (default: 30000, 0 disables).
|
|
29
|
+
* Guarantees a load attempt terminates with an error instead of leaving
|
|
30
|
+
* the viewer on a spinner when the network stalls without erroring.
|
|
31
|
+
*/
|
|
32
|
+
loadTimeoutMs?: number;
|
|
27
33
|
}
|
|
28
34
|
interface INativePlugin {
|
|
29
35
|
id: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,12 @@ import { PluginType, IPluginAPI } from '@scarlett-player/core';
|
|
|
24
24
|
interface NativePluginConfig {
|
|
25
25
|
/** Preload behavior: 'none' | 'metadata' | 'auto' */
|
|
26
26
|
preload?: 'none' | 'metadata' | 'auto';
|
|
27
|
+
/**
|
|
28
|
+
* Watchdog for source loading in milliseconds (default: 30000, 0 disables).
|
|
29
|
+
* Guarantees a load attempt terminates with an error instead of leaving
|
|
30
|
+
* the viewer on a spinner when the network stalls without erroring.
|
|
31
|
+
*/
|
|
32
|
+
loadTimeoutMs?: number;
|
|
27
33
|
}
|
|
28
34
|
interface INativePlugin {
|
|
29
35
|
id: string;
|
package/dist/index.js
CHANGED
|
@@ -23,9 +23,11 @@ var MIME_TYPES = {
|
|
|
23
23
|
};
|
|
24
24
|
function createNativePlugin(config) {
|
|
25
25
|
const preload = config?.preload ?? "metadata";
|
|
26
|
+
const load_timeout_ms = config?.loadTimeoutMs ?? 3e4;
|
|
26
27
|
let api = null;
|
|
27
28
|
let video = null;
|
|
28
29
|
let cleanupEvents = null;
|
|
30
|
+
let derived_title = null;
|
|
29
31
|
const getExtension = (src) => {
|
|
30
32
|
try {
|
|
31
33
|
const url = new URL(src, window.location.href);
|
|
@@ -254,6 +256,7 @@ function createNativePlugin(config) {
|
|
|
254
256
|
}
|
|
255
257
|
video = null;
|
|
256
258
|
api = null;
|
|
259
|
+
derived_title = null;
|
|
257
260
|
},
|
|
258
261
|
async loadSource(src) {
|
|
259
262
|
if (!api) throw new Error("Plugin not initialized");
|
|
@@ -266,13 +269,18 @@ function createNativePlugin(config) {
|
|
|
266
269
|
api.setState("buffering", true);
|
|
267
270
|
api.setState("mediaType", isAudio ? "audio" : "video");
|
|
268
271
|
if (isAudio) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
272
|
+
const current_title = api.getState("title");
|
|
273
|
+
if (!current_title || current_title === derived_title) {
|
|
274
|
+
try {
|
|
275
|
+
const url = new URL(src, window.location.href);
|
|
276
|
+
const filename = url.pathname.split("/").pop() || "Audio";
|
|
277
|
+
const title = decodeURIComponent(filename.replace(/\.[^.]+$/, "").replace(/[-_]/g, " "));
|
|
278
|
+
derived_title = title;
|
|
279
|
+
api.setState("title", title);
|
|
280
|
+
} catch {
|
|
281
|
+
derived_title = "Audio";
|
|
282
|
+
api.setState("title", "Audio");
|
|
283
|
+
}
|
|
276
284
|
}
|
|
277
285
|
}
|
|
278
286
|
api.setState("qualities", []);
|
|
@@ -290,9 +298,17 @@ function createNativePlugin(config) {
|
|
|
290
298
|
}
|
|
291
299
|
cleanupEvents = setupEventListeners(videoEl);
|
|
292
300
|
return new Promise((resolve, reject) => {
|
|
293
|
-
|
|
301
|
+
let watchdog = null;
|
|
302
|
+
const settle = () => {
|
|
294
303
|
videoEl.removeEventListener("loadedmetadata", onLoaded);
|
|
295
304
|
videoEl.removeEventListener("error", onError);
|
|
305
|
+
if (watchdog !== null) {
|
|
306
|
+
clearTimeout(watchdog);
|
|
307
|
+
watchdog = null;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
const onLoaded = () => {
|
|
311
|
+
settle();
|
|
296
312
|
const muted = api?.getState("muted");
|
|
297
313
|
const volume = api?.getState("volume");
|
|
298
314
|
if (muted !== void 0) videoEl.muted = muted;
|
|
@@ -304,11 +320,16 @@ function createNativePlugin(config) {
|
|
|
304
320
|
resolve();
|
|
305
321
|
};
|
|
306
322
|
const onError = () => {
|
|
307
|
-
|
|
308
|
-
videoEl.removeEventListener("error", onError);
|
|
323
|
+
settle();
|
|
309
324
|
const error = videoEl.error;
|
|
310
325
|
reject(new Error(error?.message || "Failed to load video source"));
|
|
311
326
|
};
|
|
327
|
+
if (load_timeout_ms > 0) {
|
|
328
|
+
watchdog = setTimeout(() => {
|
|
329
|
+
settle();
|
|
330
|
+
reject(new Error("Video took too long to load (network timeout)"));
|
|
331
|
+
}, load_timeout_ms);
|
|
332
|
+
}
|
|
312
333
|
videoEl.addEventListener("loadedmetadata", onLoaded);
|
|
313
334
|
videoEl.addEventListener("error", onError);
|
|
314
335
|
videoEl.src = src;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scarlett-player/native",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
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.
|
|
20
|
+
"@scarlett-player/core": "^1.0.3"
|
|
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.
|
|
26
|
+
"@scarlett-player/core": "1.1.1"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
|
29
29
|
"video",
|