@vivix-ai/ivi-frontend-sdk 0.3.0 → 0.3.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/README.md +21 -7
- package/dist/index.cjs +152 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +153 -11
- package/dist/index.js.map +1 -1
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -45,12 +45,6 @@ pnpm update @vivix-ai/ivi-frontend-sdk
|
|
|
45
45
|
yarn up @vivix-ai/ivi-frontend-sdk
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
### `dist` 与 npm 发布
|
|
49
|
-
|
|
50
|
-
`package.json` 的 `main` / `module` / `types` / `exports` 均指向 `dist/`,且 npm 包通过 `"files": ["dist"]` 发布到 npm 官方仓库。因此发布前必须先完成构建,确保 npm 包包含可运行、可解析类型的产物。
|
|
51
|
-
|
|
52
|
-
**协作约定**:修改 `src/` 后必须在本地执行 `npm run build`(或 `pnpm run build`),并将**与本次源码变更对应的一次完整 `dist/` 输出**一并提交:可与功能改动放在**同一提交**,或在必要时单独提交,提交信息示例:`chore: 重新构建 dist`。禁止只改源码而不更新 `dist/`,避免仓库内源码与产物不一致。
|
|
53
|
-
|
|
54
48
|
### Peer Dependencies
|
|
55
49
|
|
|
56
50
|
React 为可选 peer dependency,仅使用 React 组件时需要:
|
|
@@ -514,7 +508,27 @@ HLS 流播放器(基于 `hls.js`),由 `IVITrackSlot` 内部用于 `.m3u8`
|
|
|
514
508
|
>
|
|
515
509
|
> 若需“保留播放/音量,仅隐藏进度条”,请在上层自行渲染自定义控制栏。
|
|
516
510
|
|
|
517
|
-
### `
|
|
511
|
+
### `IVIFlvVideo`
|
|
512
|
+
|
|
513
|
+
FLV 流播放器(基于 `xgplayer` + `xgplayer-flv`),用于 `.flv` 地址播放。`IVITrackSlot` 会按 URL 后缀自动选用。辅助函数 `isFlvUrl(url)` 可判断 URL 是否为 flv。
|
|
514
|
+
|
|
515
|
+
使用前需安装 peer 依赖:
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
npm install xgplayer xgplayer-flv
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
| Prop | 类型 | 说明 |
|
|
522
|
+
|------|------|------|
|
|
523
|
+
| `url` | `string` | FLV 播放地址 |
|
|
524
|
+
| `videoProps` | — | 透传 muted / controls / onEnded 等语义 |
|
|
525
|
+
| `style` | — | 容器样式 |
|
|
526
|
+
| `isLive` | `boolean` | 是否直播,默认 `true` |
|
|
527
|
+
| `paused` | `boolean` | 是否暂停(standby 预加载) |
|
|
528
|
+
|
|
529
|
+
> 直播 FLV 通常不会触发 `ended`,切换 source 时请使用定时模式而非「播放完毕」。
|
|
530
|
+
|
|
531
|
+
### `IVIVolumeControl`
|
|
518
532
|
|
|
519
533
|
音量控制浮层组件,由 `IVITrackSlot` 在 `showVolumeControl` 开启时内部使用;当前不从包根公开导出。
|
|
520
534
|
|
package/dist/index.cjs
CHANGED
|
@@ -3292,6 +3292,132 @@ function IVILivekitPlayer(props) {
|
|
|
3292
3292
|
}
|
|
3293
3293
|
);
|
|
3294
3294
|
}
|
|
3295
|
+
var loadModulesPromise = null;
|
|
3296
|
+
async function loadXgplayerModules() {
|
|
3297
|
+
if (!loadModulesPromise) {
|
|
3298
|
+
loadModulesPromise = (async () => {
|
|
3299
|
+
try {
|
|
3300
|
+
await import('xgplayer/dist/index.min.css');
|
|
3301
|
+
} catch (err) {
|
|
3302
|
+
console.warn("[IVIFlvVideo] \u52A0\u8F7D xgplayer \u6837\u5F0F\u5931\u8D25\uFF0C\u64AD\u653E\u5668\u63A7\u4EF6\u53EF\u80FD\u663E\u793A\u5F02\u5E38", err);
|
|
3303
|
+
}
|
|
3304
|
+
const [playerMod, flvMod] = await Promise.all([import('xgplayer'), import('xgplayer-flv')]);
|
|
3305
|
+
const playerModule = playerMod;
|
|
3306
|
+
const flvModule = flvMod;
|
|
3307
|
+
const Player = playerModule.default ?? playerModule.Player;
|
|
3308
|
+
const FlvPlugin = flvModule.default ?? flvModule.FlvPlugin;
|
|
3309
|
+
if (!Player || !FlvPlugin) {
|
|
3310
|
+
throw new Error("xgplayer \u6216 xgplayer-flv \u6A21\u5757\u5BFC\u51FA\u65E0\u6548");
|
|
3311
|
+
}
|
|
3312
|
+
return { Player, FlvPlugin };
|
|
3313
|
+
})().catch((err) => {
|
|
3314
|
+
loadModulesPromise = null;
|
|
3315
|
+
throw err;
|
|
3316
|
+
});
|
|
3317
|
+
}
|
|
3318
|
+
return loadModulesPromise;
|
|
3319
|
+
}
|
|
3320
|
+
function IVIFlvVideo(props) {
|
|
3321
|
+
const { url, videoProps, style, isLive = true, paused = false } = props;
|
|
3322
|
+
const containerRef = react.useRef(null);
|
|
3323
|
+
const playerRef = react.useRef(null);
|
|
3324
|
+
const pausedRef = react.useRef(paused);
|
|
3325
|
+
const videoPropsRef = react.useRef(videoProps);
|
|
3326
|
+
videoPropsRef.current = videoProps;
|
|
3327
|
+
const reactId = react.useId();
|
|
3328
|
+
const containerId = `ivi-flv-${reactId.replace(/:/g, "")}`;
|
|
3329
|
+
react.useEffect(() => {
|
|
3330
|
+
pausedRef.current = paused;
|
|
3331
|
+
const player = playerRef.current;
|
|
3332
|
+
if (!player) return;
|
|
3333
|
+
if (paused) {
|
|
3334
|
+
player.pause();
|
|
3335
|
+
} else {
|
|
3336
|
+
Promise.resolve(player.play()).catch((err) => {
|
|
3337
|
+
console.warn(
|
|
3338
|
+
"[IVIFlvVideo] paused\u2192active \u5207\u6362\u65F6 play() \u88AB\u6D4F\u89C8\u5668\u62D2\u7EDD\uFF08\u591A\u534A\u53D7\u81EA\u52A8\u64AD\u653E\u7B56\u7565\u9650\u5236\uFF09",
|
|
3339
|
+
err
|
|
3340
|
+
);
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
}, [paused]);
|
|
3344
|
+
react.useEffect(() => {
|
|
3345
|
+
const container = containerRef.current;
|
|
3346
|
+
if (!container) return;
|
|
3347
|
+
let disposed = false;
|
|
3348
|
+
let endedHandler = null;
|
|
3349
|
+
let errorHandler = null;
|
|
3350
|
+
const setup = async () => {
|
|
3351
|
+
try {
|
|
3352
|
+
const { Player, FlvPlugin } = await loadXgplayerModules();
|
|
3353
|
+
if (disposed || !containerRef.current) return;
|
|
3354
|
+
playerRef.current?.destroy();
|
|
3355
|
+
playerRef.current = null;
|
|
3356
|
+
container.innerHTML = "";
|
|
3357
|
+
const shouldAutoplay = !pausedRef.current;
|
|
3358
|
+
const currentVideoProps = videoPropsRef.current;
|
|
3359
|
+
const muted = Boolean(currentVideoProps?.muted);
|
|
3360
|
+
const player = new Player({
|
|
3361
|
+
id: containerId,
|
|
3362
|
+
el: containerRef.current,
|
|
3363
|
+
url,
|
|
3364
|
+
plugins: [FlvPlugin],
|
|
3365
|
+
isLive,
|
|
3366
|
+
autoplay: shouldAutoplay,
|
|
3367
|
+
autoplayMuted: muted,
|
|
3368
|
+
muted,
|
|
3369
|
+
controls: currentVideoProps?.controls ?? true,
|
|
3370
|
+
width: "100%",
|
|
3371
|
+
height: "100%",
|
|
3372
|
+
fluid: true,
|
|
3373
|
+
videoFillMode: "contain",
|
|
3374
|
+
flv: {
|
|
3375
|
+
retryCount: Number.MAX_SAFE_INTEGER,
|
|
3376
|
+
retryDelay: 500,
|
|
3377
|
+
loadTimeout: 1e4
|
|
3378
|
+
}
|
|
3379
|
+
});
|
|
3380
|
+
playerRef.current = player;
|
|
3381
|
+
errorHandler = (...args) => {
|
|
3382
|
+
console.warn("[IVIFlvVideo] \u64AD\u653E\u5668 error \u4E8B\u4EF6", { url, args });
|
|
3383
|
+
};
|
|
3384
|
+
player.on("error", errorHandler);
|
|
3385
|
+
const onEnded = currentVideoProps?.onEnded;
|
|
3386
|
+
if (onEnded) {
|
|
3387
|
+
endedHandler = () => {
|
|
3388
|
+
videoPropsRef.current?.onEnded?.({});
|
|
3389
|
+
};
|
|
3390
|
+
player.on("ended", endedHandler);
|
|
3391
|
+
}
|
|
3392
|
+
if (!pausedRef.current) {
|
|
3393
|
+
Promise.resolve(player.play()).catch((err) => {
|
|
3394
|
+
console.warn("[IVIFlvVideo] \u521D\u59CB play() \u88AB\u6D4F\u89C8\u5668\u62D2\u7EDD", err);
|
|
3395
|
+
});
|
|
3396
|
+
}
|
|
3397
|
+
} catch (err) {
|
|
3398
|
+
console.warn("[IVIFlvVideo] \u521D\u59CB\u5316 xgplayer-flv \u5931\u8D25", err);
|
|
3399
|
+
}
|
|
3400
|
+
};
|
|
3401
|
+
void setup();
|
|
3402
|
+
return () => {
|
|
3403
|
+
disposed = true;
|
|
3404
|
+
const player = playerRef.current;
|
|
3405
|
+
if (player) {
|
|
3406
|
+
if (endedHandler) player.off("ended", endedHandler);
|
|
3407
|
+
if (errorHandler) player.off("error", errorHandler);
|
|
3408
|
+
player.destroy();
|
|
3409
|
+
}
|
|
3410
|
+
playerRef.current = null;
|
|
3411
|
+
if (containerRef.current) {
|
|
3412
|
+
containerRef.current.innerHTML = "";
|
|
3413
|
+
}
|
|
3414
|
+
};
|
|
3415
|
+
}, [url, isLive, containerId]);
|
|
3416
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { id: containerId, ref: containerRef, style: { width: "100%", height: "100%", ...style } });
|
|
3417
|
+
}
|
|
3418
|
+
function isFlvUrl(url) {
|
|
3419
|
+
return /\.flv(?:$|[?#])/i.test(url);
|
|
3420
|
+
}
|
|
3295
3421
|
var RETRY_DELAY_MS = 500;
|
|
3296
3422
|
var UNLIMITED_RETRIES = Number.MAX_SAFE_INTEGER;
|
|
3297
3423
|
var HLS_LOG_TAG = "[IVI-HLS]";
|
|
@@ -3648,16 +3774,32 @@ function TrackSlotMediaContent(props) {
|
|
|
3648
3774
|
) : void 0
|
|
3649
3775
|
};
|
|
3650
3776
|
const shouldPause = !isActive;
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3777
|
+
if (isM3u8Url(playbackUrl)) {
|
|
3778
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3779
|
+
IVIHlsVideo,
|
|
3780
|
+
{
|
|
3781
|
+
url: playbackUrl,
|
|
3782
|
+
videoProps: mergedVideoProps,
|
|
3783
|
+
style: videoStyle,
|
|
3784
|
+
paused: shouldPause
|
|
3785
|
+
}
|
|
3786
|
+
);
|
|
3787
|
+
}
|
|
3788
|
+
if (isFlvUrl(playbackUrl)) {
|
|
3789
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3790
|
+
IVIFlvVideo,
|
|
3791
|
+
{
|
|
3792
|
+
url: playbackUrl,
|
|
3793
|
+
videoProps: {
|
|
3794
|
+
...mergedVideoProps,
|
|
3795
|
+
controls: isActive ? videoProps?.controls ?? true : false
|
|
3796
|
+
},
|
|
3797
|
+
style: videoStyle,
|
|
3798
|
+
paused: shouldPause
|
|
3799
|
+
}
|
|
3800
|
+
);
|
|
3801
|
+
}
|
|
3802
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3661
3803
|
SlotVideo,
|
|
3662
3804
|
{
|
|
3663
3805
|
src: playbackUrl,
|