@video-lab/vue-frame 2.0.0 → 3.0.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 CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("vue"),t=require("@video-lab/frame-core");function n(n,r,i){let a=(0,e.shallowRef)(null),o=(0,e.ref)(!1),s=(0,e.ref)(!0);function c(){let e={};return r.preset!==void 0&&(e.preset=r.preset),r.autoplay!==void 0&&(e.autoplay=r.autoplay),r.muted!==void 0&&(e.muted=r.muted),r.loop!==void 0&&(e.loop=r.loop),r.playsinline!==void 0&&(e.playsinline=r.playsinline),r.playbackRate!==void 0&&(e.playbackRate=r.playbackRate),r.volume!==void 0&&(e.volume=r.volume),r.startTime!==void 0&&(e.startTime=r.startTime),r.preload!==void 0&&(e.preload=r.preload),r.controls!==void 0&&(e.controls=r.controls),r.interactive!==void 0&&(e.interactive=r.interactive),r.poster!==void 0&&(e.poster=r.poster),r.pauseImage!==void 0&&(e.pauseImage=r.pauseImage),r.locale!==void 0&&(e.locale=r.locale),r.danmaku!==void 0&&(e.danmaku=r.danmaku),r.debug!==void 0&&(e.debug=r.debug),e}function l(e){(e.event===`play`||e.event===`error`)&&(s.value=!1);try{i(`playerEvent`,e)}catch{}switch(e.event){case`ready`:i(`ready`,e.payload);break;case`play`:i(`play`);break;case`pause`:i(`pause`);break;case`ended`:i(`ended`);break;case`timeupdate`:i(`timeUpdate`,e.payload);break;case`volumechange`:i(`volumeChange`,e.payload);break;case`seeking`:i(`seeking`,e.payload);break;case`seeked`:i(`seeked`,e.payload);break;case`waiting`:i(`waiting`);break;case`playing`:i(`playing`);break;case`qualitychange`:i(`qualityChange`,e.payload);break;case`subtitlechange`:i(`subtitleChange`,e.payload);break;case`error`:i(`error`,e.payload);break;case`autoplayblocked`:i(`autoplayBlocked`);break;case`reconnectstart`:i(`reconnectStart`,{attempt:e.payload.attempt,maxAttempts:e.payload.maxAttempts});break;case`reconnectsuccess`:i(`reconnectSuccess`);break;case`reconnectfailed`:i(`reconnectFailed`);break;case`compatwarning`:i(`compatWarning`,e.payload);break;case`stalled`:i(`stalled`,e.payload);break;case`playablechange`:i(`playableChange`,e.payload);break;case`bufferhealth`:i(`bufferHealth`,e.payload);break;case`contextchange`:i(`contextChange`,e.payload);break;case`sourceroute`:i(`sourceRoute`,e.payload);break;case`firstframe`:i(`firstFrame`,e.payload);break;case`framefreeze`:i(`frameFreeze`,e.payload);break;case`useraction`:i(`userAction`,e.payload);break;case`kernelhealth`:i(`kernelHealth`,e.payload);break;case`audiohealth`:i(`audioHealth`,e.payload);break;case`recovery`:break;default:break}}let u=!1;return(0,e.onMounted)(async()=>{o.value=!0;let e=n.value;if(!e)return;let i=await(0,t.createPlayerFrame)({container:e,source:r.source,config:c(),...r.origin===void 0?{}:{origin:r.origin},...r.version===void 0?{}:{version:r.version},onEvent:l,debug:r.debug??!1});if(u){i.destroy();return}a.value=i}),(0,e.watch)(()=>JSON.stringify(r.source),async()=>{s.value=!0;try{await a.value?.load(r.source)}catch(e){l({event:`error`,payload:(0,t.toPlayerError)(e)})}}),(0,e.watch)(()=>r.muted,async e=>{if(e!==void 0)try{await a.value?.setMuted(e)}catch(e){l({event:`error`,payload:(0,t.toPlayerError)(e)})}}),(0,e.watch)(()=>r.locale,async e=>{if(e!==void 0)try{await a.value?.setLocale(e)}catch(e){l({event:`error`,payload:(0,t.toPlayerError)(e)})}},{deep:!0}),(0,e.onBeforeUnmount)(async()=>{u=!0,await a.value?.destroy(),a.value=null}),{handle:a,isMounted:o,hostPosterVisible:s}}var r=(0,e.createElementVNode)(`div`,{class:`sentinel-video-frame__placeholder`,style:{width:`100%`,height:`100%`,background:`#000`}},null,-1),i=[`src`,`loading`],a=(0,e.defineComponent)({__name:`VideoPlayerFrame`,props:{source:{},autoplay:{type:Boolean,default:void 0},muted:{type:Boolean,default:void 0},loop:{type:Boolean,default:void 0},controls:{type:Boolean,default:void 0},interactive:{type:Boolean,default:void 0},playsinline:{type:Boolean,default:void 0},playbackRate:{},volume:{},startTime:{},preload:{},poster:{},pauseImage:{},preset:{},origin:{},version:{},locale:{},danmaku:{},debug:{type:Boolean,default:void 0}},emits:`playerEvent.ready.play.pause.ended.timeUpdate.volumeChange.seeking.seeked.waiting.playing.qualityChange.subtitleChange.error.autoplayBlocked.reconnectStart.reconnectSuccess.reconnectFailed.compatWarning.stalled.playableChange.kernelHealth.audioHealth.bufferHealth.contextChange.sourceRoute.firstFrame.frameFreeze.userAction`.split(`.`),setup(t,{expose:a,emit:o}){let s=t,c=o,l=(0,e.shallowRef)(null),{handle:u,isMounted:d,hostPosterVisible:f}=n(l,s,c),p=(0,e.computed)(()=>typeof s.poster==`string`?s.poster:s.poster?.url??``),m=(0,e.computed)(()=>typeof s.poster==`string`?`cover`:s.poster?.fit??`cover`),h=(0,e.computed)(()=>typeof s.poster!=`string`&&s.poster?.loading===`eager`?`eager`:`lazy`);return a({play:()=>u.value?.play()??Promise.resolve(),pause:()=>u.value?.pause()??Promise.resolve(),seek:e=>u.value?.seek(e)??Promise.resolve(),setMuted:e=>u.value?.setMuted(e)??Promise.resolve(),setVolume:e=>u.value?.setVolume(e)??Promise.resolve(),setPlaybackRate:e=>u.value?.setPlaybackRate(e)??Promise.resolve(),enterFullscreen:()=>u.value?.enterFullscreen()??Promise.resolve(),exitFullscreen:()=>u.value?.exitFullscreen()??Promise.resolve(),setQuality:e=>u.value?.setQuality(e)??Promise.resolve(),setSubtitle:e=>u.value?.setSubtitle(e)??Promise.resolve(),setLocale:e=>u.value?.setLocale(e)??Promise.resolve(),pushDanmaku:e=>u.value?.pushDanmaku(e)??Promise.resolve(),setDanmakuEnabled:e=>u.value?.setDanmakuEnabled(e)??Promise.resolve(),clearDanmaku:()=>u.value?.clearDanmaku()??Promise.resolve(),reconnect:e=>u.value?.reconnect(e)??Promise.resolve(),destroy:()=>u.value?.destroy()??Promise.resolve(),getCurrentTime:()=>u.value?.getCurrentTime()??0,getPlaybackContext:()=>u.value?.getPlaybackContext()??null,getDuration:()=>u.value?.getDuration()??0,getPlayerHandle:()=>u.value}),(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{ref_key:`containerRef`,ref:l,class:`sentinel-video-frame`,style:(0,e.normalizeStyle)({position:`relative`,width:`100%`,height:`100%`,pointerEvents:s.interactive===!1?`none`:void 0})},[(0,e.unref)(d)?(0,e.createCommentVNode)(``,!0):(0,e.renderSlot)(t.$slots,`ssr-placeholder`,{key:0},()=>[r]),(0,e.unref)(f)&&p.value?((0,e.openBlock)(),(0,e.createElementBlock)(`img`,{key:1,class:`sentinel-video-frame__poster`,src:p.value,alt:``,loading:h.value,style:(0,e.normalizeStyle)({position:`absolute`,inset:0,width:`100%`,height:`100%`,display:`block`,objectFit:m.value,zIndex:10})},null,12,i)):(0,e.createCommentVNode)(``,!0)],4))}});exports.VideoPlayerFrame=a;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("vue"),t=require("@video-lab/frame-core");function n(n,r,i){let a=(0,e.shallowRef)(null),o=(0,e.ref)(!1),s=(0,e.ref)(!0);function c(){let e={};return r.preset!==void 0&&(e.preset=r.preset),r.autoplay!==void 0&&(e.autoplay=r.autoplay),r.muted!==void 0&&(e.muted=r.muted),r.loop!==void 0&&(e.loop=r.loop),r.playsinline!==void 0&&(e.playsinline=r.playsinline),r.playbackRate!==void 0&&(e.playbackRate=r.playbackRate),r.volume!==void 0&&(e.volume=r.volume),r.startTime!==void 0&&(e.startTime=r.startTime),r.preload!==void 0&&(e.preload=r.preload),r.controls!==void 0&&(e.controls=r.controls),r.showErrorOverlay!==void 0&&(e.showErrorOverlay=r.showErrorOverlay),r.showLoadingOverlay!==void 0&&(e.showLoadingOverlay=r.showLoadingOverlay),r.controlVisibility!==void 0&&(e.controlVisibility=r.controlVisibility),r.interactive!==void 0&&(e.interactive=r.interactive),r.poster!==void 0&&(e.poster=r.poster),r.pauseImage!==void 0&&(e.pauseImage=r.pauseImage),r.locale!==void 0&&(e.locale=r.locale),r.danmaku!==void 0&&(e.danmaku=r.danmaku),r.debug!==void 0&&(e.debug=r.debug),e}function l(e){(e.event===`play`||e.event===`error`)&&(s.value=!1);try{i(`playerEvent`,e)}catch{}switch(e.event){case`ready`:i(`ready`,e.payload);break;case`play`:i(`play`);break;case`pause`:i(`pause`);break;case`ended`:i(`ended`);break;case`timeupdate`:i(`timeUpdate`,e.payload);break;case`volumechange`:i(`volumeChange`,e.payload);break;case`seeking`:i(`seeking`,e.payload);break;case`seeked`:i(`seeked`,e.payload);break;case`waiting`:i(`waiting`);break;case`playing`:i(`playing`);break;case`qualitychange`:i(`qualityChange`,e.payload);break;case`subtitlechange`:i(`subtitleChange`,e.payload);break;case`error`:i(`error`,e.payload);break;case`autoplayblocked`:i(`autoplayBlocked`);break;case`compatwarning`:i(`compatWarning`,e.payload);break;case`stalled`:i(`stalled`,e.payload);break;case`playablechange`:i(`playableChange`,e.payload);break;case`bufferhealth`:i(`bufferHealth`,e.payload);break;case`contextchange`:i(`contextChange`,e.payload);break;case`sourceroute`:i(`sourceRoute`,e.payload);break;case`firstframe`:i(`firstFrame`,e.payload);break;case`framefreeze`:i(`frameFreeze`,e.payload);break;case`pagefullscreenchange`:i(`pageFullscreenChange`,e.payload);break;case`useraction`:i(`userAction`,e.payload);break;case`kernelhealth`:i(`kernelHealth`,e.payload);break;case`audiohealth`:i(`audioHealth`,e.payload);break;case`recovery`:break;default:break}}let u=!1;return(0,e.onMounted)(async()=>{o.value=!0;let e=n.value;if(!e)return;let s=await(0,t.createPlayerFrame)({container:e,source:r.source,config:c(),pageFullscreen:r.pageFullscreen,...r.origin===void 0?{}:{origin:r.origin},...r.version===void 0?{}:{version:r.version},onEvent:l,onDeliveredEvent:e=>{try{i(`deliveredPlayerEvent`,e)}catch{}},debug:r.debug??!1});if(u){s.destroy();return}a.value=s}),(0,e.watch)(()=>JSON.stringify(r.source),async()=>{s.value=!0;try{await a.value?.load(r.source)}catch(e){l({event:`error`,payload:(0,t.toPlayerError)(e)})}}),(0,e.watch)(()=>r.muted,async e=>{if(e!==void 0)try{await a.value?.setMuted(e)}catch(e){l({event:`error`,payload:(0,t.toPlayerError)(e)})}}),(0,e.watch)(()=>r.locale,async e=>{if(e!==void 0)try{await a.value?.setLocale(e)}catch(e){l({event:`error`,payload:(0,t.toPlayerError)(e)})}},{deep:!0}),(0,e.onBeforeUnmount)(async()=>{u=!0,await a.value?.destroy(),a.value=null}),{handle:a,isMounted:o,hostPosterVisible:s}}var r=(0,e.createElementVNode)(`div`,{class:`sentinel-video-frame__placeholder`,style:{width:`100%`,height:`100%`,background:`#000`}},null,-1),i=[`src`,`loading`],a=(0,e.defineComponent)({__name:`VideoPlayerFrame`,props:{pageFullscreen:{},source:{},autoplay:{type:Boolean,default:void 0},muted:{type:Boolean,default:void 0},loop:{type:Boolean,default:void 0},controls:{type:Boolean,default:void 0},showErrorOverlay:{type:Boolean,default:void 0},showLoadingOverlay:{type:Boolean,default:void 0},controlVisibility:{},interactive:{type:Boolean,default:void 0},playsinline:{type:Boolean,default:void 0},playbackRate:{},volume:{},startTime:{},preload:{},poster:{},pauseImage:{},preset:{},origin:{},version:{},locale:{},danmaku:{},debug:{type:Boolean,default:void 0}},emits:`playerEvent.deliveredPlayerEvent.ready.play.pause.ended.timeUpdate.volumeChange.seeking.seeked.waiting.playing.qualityChange.subtitleChange.error.autoplayBlocked.compatWarning.stalled.playableChange.kernelHealth.audioHealth.bufferHealth.contextChange.sourceRoute.firstFrame.frameFreeze.pageFullscreenChange.userAction`.split(`.`),setup(t,{expose:a,emit:o}){let s=t,c=o,l=(0,e.shallowRef)(null),{handle:u,isMounted:d,hostPosterVisible:f}=n(l,s,c),p=(0,e.computed)(()=>typeof s.poster==`string`?s.poster:s.poster?.url??``),m=(0,e.computed)(()=>typeof s.poster==`string`?`cover`:s.poster?.fit??`cover`),h=(0,e.computed)(()=>typeof s.poster!=`string`&&s.poster?.loading===`eager`?`eager`:`lazy`);return a({play:()=>u.value?.play()??Promise.resolve(),pause:()=>u.value?.pause()??Promise.resolve(),seek:e=>u.value?.seek(e)??Promise.resolve(),setMuted:e=>u.value?.setMuted(e)??Promise.resolve(),setVolume:e=>u.value?.setVolume(e)??Promise.resolve(),setPlaybackRate:e=>u.value?.setPlaybackRate(e)??Promise.resolve(),setPageFullscreen:e=>u.value?.setPageFullscreen(e)??Promise.reject(Error(`播放器未就绪`)),enterFullscreen:()=>u.value?.enterFullscreen()??Promise.resolve(),exitFullscreen:()=>u.value?.exitFullscreen()??Promise.resolve(),setQuality:e=>u.value?.setQuality(e)??Promise.resolve(),setSubtitle:e=>u.value?.setSubtitle(e)??Promise.resolve(),setLocale:e=>u.value?.setLocale(e)??Promise.resolve(),pushDanmaku:e=>u.value?.pushDanmaku(e)??Promise.resolve(),setDanmakuEnabled:e=>u.value?.setDanmakuEnabled(e)??Promise.resolve(),clearDanmaku:()=>u.value?.clearDanmaku()??Promise.resolve(),retry:()=>u.value?.retry()??Promise.resolve(),destroy:()=>u.value?.destroy()??Promise.resolve(),getCurrentTime:()=>u.value?.getCurrentTime()??0,getPlaybackContext:()=>u.value?.getPlaybackContext()??null,getDuration:()=>u.value?.getDuration()??0,getPlayerHandle:()=>u.value}),(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{ref_key:`containerRef`,ref:l,class:`sentinel-video-frame`,style:(0,e.normalizeStyle)({position:`relative`,width:`100%`,height:`100%`,pointerEvents:s.interactive===!1?`none`:void 0})},[(0,e.unref)(d)?(0,e.createCommentVNode)(``,!0):(0,e.renderSlot)(t.$slots,`ssr-placeholder`,{key:0},()=>[r]),(0,e.unref)(f)&&p.value?((0,e.openBlock)(),(0,e.createElementBlock)(`img`,{key:1,class:`sentinel-video-frame__poster`,src:p.value,alt:``,loading:h.value,style:(0,e.normalizeStyle)({position:`absolute`,inset:0,width:`100%`,height:`100%`,display:`block`,objectFit:m.value,zIndex:10})},null,12,i)):(0,e.createCommentVNode)(``,!0)],4))}});exports.VideoPlayerFrame=a;
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * 消费面唯一入口 `<VideoPlayerFrame />`。业务代码不应直接 import 本包,
5
5
  * 应通过团队封装层(examples/team-video-vue)接入——见 CLAUDE.md § 和 examples 的关系。
6
6
  */
7
+ export type { PageFullscreenAdapter, PageFullscreenState } from '@video-lab/protocol';
7
8
  export type { DanmakuConfig, DanmakuItem, MediaSource, PlayerError, PlayerHandle, QualityLevel, SubtitleTrackInfo, VideoPlayerFrameEmits, VideoPlayerFrameExpose, VideoPlayerFrameProps, } from './types';
8
9
  export { default as VideoPlayerFrame } from './VideoPlayerFrame.vue';
9
10
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ function g(e, t, n) {
5
5
  let r = d(null), i = l(!1), a = l(!0);
6
6
  function c() {
7
7
  let e = {};
8
- return t.preset !== void 0 && (e.preset = t.preset), t.autoplay !== void 0 && (e.autoplay = t.autoplay), t.muted !== void 0 && (e.muted = t.muted), t.loop !== void 0 && (e.loop = t.loop), t.playsinline !== void 0 && (e.playsinline = t.playsinline), t.playbackRate !== void 0 && (e.playbackRate = t.playbackRate), t.volume !== void 0 && (e.volume = t.volume), t.startTime !== void 0 && (e.startTime = t.startTime), t.preload !== void 0 && (e.preload = t.preload), t.controls !== void 0 && (e.controls = t.controls), t.interactive !== void 0 && (e.interactive = t.interactive), t.poster !== void 0 && (e.poster = t.poster), t.pauseImage !== void 0 && (e.pauseImage = t.pauseImage), t.locale !== void 0 && (e.locale = t.locale), t.danmaku !== void 0 && (e.danmaku = t.danmaku), t.debug !== void 0 && (e.debug = t.debug), e;
8
+ return t.preset !== void 0 && (e.preset = t.preset), t.autoplay !== void 0 && (e.autoplay = t.autoplay), t.muted !== void 0 && (e.muted = t.muted), t.loop !== void 0 && (e.loop = t.loop), t.playsinline !== void 0 && (e.playsinline = t.playsinline), t.playbackRate !== void 0 && (e.playbackRate = t.playbackRate), t.volume !== void 0 && (e.volume = t.volume), t.startTime !== void 0 && (e.startTime = t.startTime), t.preload !== void 0 && (e.preload = t.preload), t.controls !== void 0 && (e.controls = t.controls), t.showErrorOverlay !== void 0 && (e.showErrorOverlay = t.showErrorOverlay), t.showLoadingOverlay !== void 0 && (e.showLoadingOverlay = t.showLoadingOverlay), t.controlVisibility !== void 0 && (e.controlVisibility = t.controlVisibility), t.interactive !== void 0 && (e.interactive = t.interactive), t.poster !== void 0 && (e.poster = t.poster), t.pauseImage !== void 0 && (e.pauseImage = t.pauseImage), t.locale !== void 0 && (e.locale = t.locale), t.danmaku !== void 0 && (e.danmaku = t.danmaku), t.debug !== void 0 && (e.debug = t.debug), e;
9
9
  }
10
10
  function u(e) {
11
11
  (e.event === "play" || e.event === "error") && (a.value = !1);
@@ -55,18 +55,6 @@ function g(e, t, n) {
55
55
  case "autoplayblocked":
56
56
  n("autoplayBlocked");
57
57
  break;
58
- case "reconnectstart":
59
- n("reconnectStart", {
60
- attempt: e.payload.attempt,
61
- maxAttempts: e.payload.maxAttempts
62
- });
63
- break;
64
- case "reconnectsuccess":
65
- n("reconnectSuccess");
66
- break;
67
- case "reconnectfailed":
68
- n("reconnectFailed");
69
- break;
70
58
  case "compatwarning":
71
59
  n("compatWarning", e.payload);
72
60
  break;
@@ -91,6 +79,9 @@ function g(e, t, n) {
91
79
  case "framefreeze":
92
80
  n("frameFreeze", e.payload);
93
81
  break;
82
+ case "pagefullscreenchange":
83
+ n("pageFullscreenChange", e.payload);
84
+ break;
94
85
  case "useraction":
95
86
  n("userAction", e.payload);
96
87
  break;
@@ -107,22 +98,28 @@ function g(e, t, n) {
107
98
  let f = !1;
108
99
  return s(async () => {
109
100
  i.value = !0;
110
- let n = e.value;
111
- if (!n) return;
112
- let a = await m({
113
- container: n,
101
+ let a = e.value;
102
+ if (!a) return;
103
+ let o = await m({
104
+ container: a,
114
105
  source: t.source,
115
106
  config: c(),
107
+ pageFullscreen: t.pageFullscreen,
116
108
  ...t.origin === void 0 ? {} : { origin: t.origin },
117
109
  ...t.version === void 0 ? {} : { version: t.version },
118
110
  onEvent: u,
111
+ onDeliveredEvent: (e) => {
112
+ try {
113
+ n("deliveredPlayerEvent", e);
114
+ } catch {}
115
+ },
119
116
  debug: t.debug ?? !1
120
117
  });
121
118
  if (f) {
122
- a.destroy();
119
+ o.destroy();
123
120
  return;
124
121
  }
125
- r.value = a;
122
+ r.value = o;
126
123
  }), p(() => JSON.stringify(t.source), async () => {
127
124
  a.value = !0;
128
125
  try {
@@ -171,6 +168,7 @@ var _ = /*#__PURE__*/ r("div", {
171
168
  }, null, -1), v = ["src", "loading"], y = /* @__PURE__ */ i({
172
169
  __name: "VideoPlayerFrame",
173
170
  props: {
171
+ pageFullscreen: {},
174
172
  source: {},
175
173
  autoplay: {
176
174
  type: Boolean,
@@ -188,6 +186,15 @@ var _ = /*#__PURE__*/ r("div", {
188
186
  type: Boolean,
189
187
  default: void 0
190
188
  },
189
+ showErrorOverlay: {
190
+ type: Boolean,
191
+ default: void 0
192
+ },
193
+ showLoadingOverlay: {
194
+ type: Boolean,
195
+ default: void 0
196
+ },
197
+ controlVisibility: {},
191
198
  interactive: {
192
199
  type: Boolean,
193
200
  default: void 0
@@ -212,7 +219,7 @@ var _ = /*#__PURE__*/ r("div", {
212
219
  default: void 0
213
220
  }
214
221
  },
215
- emits: /* @__PURE__ */ "playerEvent.ready.play.pause.ended.timeUpdate.volumeChange.seeking.seeked.waiting.playing.qualityChange.subtitleChange.error.autoplayBlocked.reconnectStart.reconnectSuccess.reconnectFailed.compatWarning.stalled.playableChange.kernelHealth.audioHealth.bufferHealth.contextChange.sourceRoute.firstFrame.frameFreeze.userAction".split("."),
222
+ emits: /* @__PURE__ */ "playerEvent.deliveredPlayerEvent.ready.play.pause.ended.timeUpdate.volumeChange.seeking.seeked.waiting.playing.qualityChange.subtitleChange.error.autoplayBlocked.compatWarning.stalled.playableChange.kernelHealth.audioHealth.bufferHealth.contextChange.sourceRoute.firstFrame.frameFreeze.pageFullscreenChange.userAction".split("."),
216
223
  setup(r, { expose: i, emit: o }) {
217
224
  let s = r, l = o, p = d(null), { handle: m, isMounted: h, hostPosterVisible: y } = g(p, s, l), b = e(() => typeof s.poster == "string" ? s.poster : s.poster?.url ?? ""), x = e(() => typeof s.poster == "string" ? "cover" : s.poster?.fit ?? "cover"), S = e(() => typeof s.poster != "string" && s.poster?.loading === "eager" ? "eager" : "lazy");
218
225
  return i({
@@ -222,6 +229,7 @@ var _ = /*#__PURE__*/ r("div", {
222
229
  setMuted: (e) => m.value?.setMuted(e) ?? Promise.resolve(),
223
230
  setVolume: (e) => m.value?.setVolume(e) ?? Promise.resolve(),
224
231
  setPlaybackRate: (e) => m.value?.setPlaybackRate(e) ?? Promise.resolve(),
232
+ setPageFullscreen: (e) => m.value?.setPageFullscreen(e) ?? Promise.reject(/* @__PURE__ */ Error("播放器未就绪")),
225
233
  enterFullscreen: () => m.value?.enterFullscreen() ?? Promise.resolve(),
226
234
  exitFullscreen: () => m.value?.exitFullscreen() ?? Promise.resolve(),
227
235
  setQuality: (e) => m.value?.setQuality(e) ?? Promise.resolve(),
@@ -230,7 +238,7 @@ var _ = /*#__PURE__*/ r("div", {
230
238
  pushDanmaku: (e) => m.value?.pushDanmaku(e) ?? Promise.resolve(),
231
239
  setDanmakuEnabled: (e) => m.value?.setDanmakuEnabled(e) ?? Promise.resolve(),
232
240
  clearDanmaku: () => m.value?.clearDanmaku() ?? Promise.resolve(),
233
- reconnect: (e) => m.value?.reconnect(e) ?? Promise.resolve(),
241
+ retry: () => m.value?.retry() ?? Promise.resolve(),
234
242
  destroy: () => m.value?.destroy() ?? Promise.resolve(),
235
243
  getCurrentTime: () => m.value?.getCurrentTime() ?? 0,
236
244
  getPlaybackContext: () => m.value?.getPlaybackContext() ?? null,
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PlayerFrameHandle } from '@video-lab/frame-core';
2
- import { AudioHealthPayload, BufferHealthPayload, DanmakuConfig, DanmakuItem, FirstFramePayload, FrameFreezePayload, KernelHealthPayload, LocaleConfig, MediaSource, PauseImageConfig, PlayableReason, PlaybackContext, PlaybackContextPayload, PlayerError, PlayerEvent, PosterConfig, PresetName, QualityLevel, SourceRouteEventPayload, SubtitleTrackInfo, UserActionPayload } from '@video-lab/protocol';
2
+ import { AudioHealthPayload, BufferHealthPayload, ControlVisibilityConfig, DanmakuConfig, DanmakuItem, DeliveredPlayerEvent, FirstFramePayload, FrameFreezePayload, KernelHealthPayload, LocaleConfig, MediaSource, PageFullscreenAdapter, PageFullscreenState, PauseImageConfig, PlaybackContext, PlaybackContextPayload, PlayerError, PlayerEvent, PosterConfig, PresetName, QualityLevel, SourceRouteEventPayload, SubtitleTrackInfo, UserActionPayload } from '@video-lab/protocol';
3
3
  /**
4
4
  * 消费方拿到的播放器句柄(逃生舱)。
5
5
  *
@@ -15,12 +15,20 @@ export type { DanmakuConfig, DanmakuItem, MediaSource, PlayerError, QualityLevel
15
15
  * `config` 下发给 iframe;origin / version 走 ADR-023 的 URL 覆盖。
16
16
  */
17
17
  export interface VideoPlayerFrameProps {
18
+ /** 挂载期间保持稳定的宿主网页全屏布局适配器。 */
19
+ pageFullscreen?: PageFullscreenAdapter;
18
20
  /** 视频源。字符串按 URL 处理,对象可带 type / live / hls 等 */
19
21
  source: MediaSource | string;
20
22
  autoplay?: boolean;
21
23
  muted?: boolean;
22
24
  loop?: boolean;
23
25
  controls?: boolean;
26
+ /** 默认错误覆盖层,省略时开启。仅初始化读取;变更须重新挂载,不影响错误事件。 */
27
+ showErrorOverlay?: boolean;
28
+ /** 是否显示 SDK 运行时 Loading;构造期读取,默认 true。 */
29
+ showLoadingOverlay?: boolean;
30
+ /** 内置控件初始化显示策略;修改后须由宿主显式重建播放器。 */
31
+ controlVisibility?: ControlVisibilityConfig;
24
32
  /** false 时播放器不接收指针事件(点击穿透到下层) */
25
33
  interactive?: boolean;
26
34
  playsinline?: boolean;
@@ -77,6 +85,7 @@ export interface VideoPlayerFrameProps {
77
85
  export interface VideoPlayerFrameEmits {
78
86
  /** 完整的契约事件流,供遥测适配器使用;不裁剪 iframe 转发的 payload。 */
79
87
  (e: 'playerEvent', payload: PlayerEvent): void;
88
+ (e: 'deliveredPlayerEvent', payload: DeliveredPlayerEvent): void;
80
89
  /**
81
90
  * metadata 就绪。`quality` 是可切档位清单(单码率源为空数组),团队层据此渲染清晰度菜单;
82
91
  * `subtitles` 是可切字幕轨清单(无字幕源为空/缺省,契约 1.2.0 起可选,ADR-027),团队层据此渲染字幕菜单。
@@ -126,12 +135,6 @@ export interface VideoPlayerFrameEmits {
126
135
  }): void;
127
136
  (e: 'error', payload: PlayerError): void;
128
137
  (e: 'autoplayBlocked'): void;
129
- (e: 'reconnectStart', payload: {
130
- attempt: number;
131
- maxAttempts: number;
132
- }): void;
133
- (e: 'reconnectSuccess'): void;
134
- (e: 'reconnectFailed'): void;
135
138
  (e: 'compatWarning', payload: {
136
139
  code: string;
137
140
  message: string;
@@ -155,11 +158,9 @@ export interface VideoPlayerFrameEmits {
155
158
  * `recoverable` 决定盖 loading(等)还是露重试入口(不等);`reason='degraded'`
156
159
  * 是唯一 `playable` 仍为 `true` 的值(掉帧严重但画面还在动,可以忽略)。
157
160
  */
158
- (e: 'playableChange', payload: {
159
- playable: boolean;
160
- reason: PlayableReason;
161
- recoverable: boolean;
162
- }): void;
161
+ (e: 'playableChange', payload: Extract<PlayerEvent, {
162
+ event: 'playablechange';
163
+ }>['payload']): void;
163
164
  /**
164
165
  * 内核健康 —— **非致命内核诊断的聚合**(契约 4.1.0 / ADR-062 / issue #391)。
165
166
  *
@@ -202,6 +203,8 @@ export interface VideoPlayerFrameEmits {
202
203
  * ⚠️ 它不是掉帧率,也不与 `stalled` 重复(后者是缓冲驱动的等待)。
203
204
  */
204
205
  (e: 'frameFreeze', payload: FrameFreezePayload): void;
206
+ /** 实际网页全屏状态变化。 */
207
+ (e: 'pageFullscreenChange', payload: PageFullscreenState): void;
205
208
  /**
206
209
  * 用户动作(ADR-075),经白名单过滤,只含**发生在 SDK 内部**的那些。
207
210
  *
@@ -224,6 +227,8 @@ export interface VideoPlayerFrameExpose {
224
227
  setMuted(muted: boolean): Promise<void>;
225
228
  setVolume(volume: number): Promise<void>;
226
229
  setPlaybackRate(rate: number): Promise<void>;
230
+ /** 设置网页全屏;必须等宿主布局与 iframe 状态确认。 */
231
+ setPageFullscreen(active: boolean): Promise<void>;
227
232
  /** 进入全屏(容器托管,不碰 video 原生入口,iOS 微信崩溃入口由 FullscreenGuard 中和) */
228
233
  enterFullscreen(): Promise<void>;
229
234
  /** 退出全屏 */
@@ -239,9 +244,7 @@ export interface VideoPlayerFrameExpose {
239
244
  setDanmakuEnabled(enabled: boolean): Promise<void>;
240
245
  /** 清空屏上弹幕(ADR-028) */
241
246
  clearDanmaku(): Promise<void>;
242
- reconnect(options?: {
243
- resetCounter?: boolean;
244
- }): Promise<void>;
247
+ retry(): Promise<void>;
245
248
  destroy(): Promise<void>;
246
249
  getCurrentTime(): number;
247
250
  getDuration(): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@video-lab/vue-frame",
3
- "version": "2.0.0",
3
+ "version": "3.0.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -20,15 +20,16 @@
20
20
  "dist/**/*.d.ts",
21
21
  "dist/**/*.d.cts",
22
22
  "dist/**/*.d.mts",
23
- "dist/**/*.css"
23
+ "dist/**/*.css",
24
+ "skills/**"
24
25
  ],
25
26
  "sideEffects": false,
26
27
  "peerDependencies": {
27
28
  "vue": "^3.4.0"
28
29
  },
29
30
  "dependencies": {
30
- "@video-lab/protocol": "2.0.0",
31
- "@video-lab/frame-core": "2.0.0"
31
+ "@video-lab/protocol": "3.0.1",
32
+ "@video-lab/frame-core": "3.0.1"
32
33
  },
33
34
  "devDependencies": {
34
35
  "@vitejs/plugin-vue": "^6.0.8",
@@ -47,7 +48,7 @@
47
48
  "access": "public"
48
49
  },
49
50
  "scripts": {
50
- "build": "vite build",
51
+ "build": "node ../../scripts/sync-public-host-skill.mjs vue-frame && vite build",
51
52
  "dev": "vite build --watch --emptyOutDir false",
52
53
  "test": "vitest run",
53
54
  "typecheck": "vue-tsc --noEmit && vue-tsc -p tsconfig.test.json --noEmit"
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: video-lab-host-integration
3
+ skillVersion: 1
4
+ sdkMajor: 2
5
+ supportedPackages:
6
+ - '@video-lab/react-frame@2.0.0'
7
+ - '@video-lab/vue-frame@2.0.0'
8
+ description: >-
9
+ 在业务宿主项目中接入 Video Lab Player 时使用。选择五种接入面之一,完成可验证 demo,
10
+ 并交接 SDK、宿主与服务端责任;不用于修改 SDK 契约或设计品牌 UI。
11
+ ---
12
+
13
+ # Video Lab Player · 宿主接入
14
+
15
+ ## 取得与版本绑定
16
+
17
+ 在已安装的 `@video-lab/react-frame` 或 `@video-lab/vue-frame` 中读取
18
+ `skills/host-integration/SKILL.md`,再将该目录复制到宿主项目的 AI Skill 目录。先核对
19
+ front matter 的 `supportedPackages` 与安装版本;它是**宿主 AI 的公开接入资料**,不是 npm
20
+ 运行时文件,也不是 iframe 部署目录的一部分。
21
+
22
+ API 以已安装包的类型定义和对应 README 为准;本 Skill 只负责选择接入面与交接流程,不能替代类型。
23
+
24
+ ## 先选接入面
25
+
26
+ | 宿主条件 | 选择 | 不能承诺 |
27
+ | --- | --- | --- |
28
+ | React/Vue 页面,追求性能与深度组合 | `@video-lab/react` / `@video-lab/vue` | 直接操作 xgplayer 私有实例。 |
29
+ | 需要样式、脚本或故障隔离,仍要命令和事件 | `@video-lab/react-frame` / `@video-lab/vue-frame` | 同步读取 iframe DOM 或媒体元素。 |
30
+ | CMS、Markdown、无构建工具,只需嵌入与事件订阅 | 静态 iframe URL,可选 `@video-lab/embed-helper` | 播放命令、换源、字幕、弹幕和实例级握手。 |
31
+
32
+ 若静态 iframe 的能力不够,升级到 React/Vue inline 或 iframe。不要私发 `postMessage`、把 JSON 塞进 query,或猜测未在类型中出现的 SDK API。
33
+
34
+ ## 实施顺序
35
+
36
+ 1. 在宿主项目建立独立 demo 页面,使用服务端提供的完整、已授权 `MediaSource`。不要传 headers、token 刷新回调或业务 ID 给 SDK。
37
+ 2. 以公开 `ready`、`PlayerEvent`、错误码和 `playablechange` 驱动业务状态。runtime Loading 只从 `!playable && recoverable` 派生。跨重连 telemetry、排序、去重和迟到事件识别使用 delivered outlet:React iframe 是 `onDeliveredPlayerEvent`,Vue iframe 是 `@delivered-player-event`;旧 iframe 只能提供 raw `PlayerEvent`。
38
+ 3. 业务服务负责签名 URL、CORS、权益、字幕资源、弹幕审核与限流;品牌 UI、CTA、菜单和无障碍交互留在宿主。
39
+ 4. 业务 telemetry 只记录允许的播放器事实:不要发送完整媒体 URL、query、签名、token、cookie、身份或弹幕正文。
40
+ 5. 用真实或受控媒体覆盖首次加载、自动播放拒绝、可恢复/不可恢复错误、签名换源、字幕失败与卸载清理;恢复必须有时间或画面推进证据。
41
+ 6. 所有可失败命令都 `await` 并 `catch`;命令 rejection 不保证触发 `error`,播放期 `error` 也不保证对应某个命令 rejection。
42
+
43
+ ## 交接模板
44
+
45
+ ```md
46
+ ### Video Lab 宿主接入结论
47
+
48
+ - 接入面:<React inline / Vue inline / React iframe / Vue iframe / 静态 iframe>
49
+ - 选择原因:<隔离、性能或无构建工具约束>
50
+ - 已验证:<源、事件、Loading、恢复、销毁>
51
+ - SDK 已完成:<实际使用的公开能力>
52
+ - 宿主待完成:<UI、状态、telemetry、无障碍、验收>
53
+ - 服务端/CDN 待完成:<签名 URL、CORS、内容、互动治理>
54
+ - 不支持/风险:<模式限制与明确的产品决定>
55
+ ```
56
+
57
+ ## 使用资料的优先级
58
+
59
+ 1. 已安装 `@video-lab/*` 包的 README 和类型定义是 API 的最终事实。
60
+ 2. 接入交接单提供当前的 iframe origin、版本路径、媒体源和部署边界;不得猜测或硬编码内部地址。
61
+ 3. 宿主项目的安全、品牌 UI、业务 telemetry 与服务端约束优先于本 Skill 的通用示例。
62
+
63
+ ## 宿主要求隐藏单个内置控件
64
+
65
+ 使用初始化 `controlVisibility`,例如 `{ cssFullscreen: false }`;静态 iframe 使用 `controlCssFullscreen=0`。
66
+ 保留 `controls` 布尔总开关,不覆盖内部 CSS、不访问私有插件。八字段与重建语义见
67
+ [控件显示指南](../../guides/PLAYER-CONTROL-VISIBILITY.md)。先确认安装版本实际包含该字段,
68
+ iframe 同时核实支持此功能的精确应用版本已部署;旧 iframe 可能忽略新字段。
69
+
70
+ ## 网页全屏交接
71
+
72
+ iframe CSS 全屏必须由宿主布局。四个框架组件传稳定的 `pageFullscreen` 适配器(`setActive`、`dispose`),静态 URL 用 `createPageFullscreenController` 绑定精确 origin 与 iframe。确认、Esc 和销毁清理由 SDK 编排;宿主负责层级、滚动、焦点恢复,不移动 iframe。未接适配器的新 iframe 隐藏入口。旧 iframe 需配套升级,浏览器原生全屏仍独立。以对应包 README 和 `docs/guides/PAGE-FULLSCREEN.md` 为准。