rvms-vue 0.1.11 → 0.1.12

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/lib/index.js CHANGED
@@ -1,41 +1,41 @@
1
- import { defineComponent as N, ref as k, onMounted as q, onBeforeUnmount as F, watch as J, openBlock as d, createElementBlock as f, normalizeStyle as j, createElementVNode as i, toDisplayString as B, createCommentVNode as S, createTextVNode as K, Fragment as Y, renderList as G } from "vue";
2
- const X = {
1
+ import { defineComponent as F, ref as k, onMounted as K, onBeforeUnmount as J, watch as q, openBlock as f, createElementBlock as p, normalizeStyle as Q, createElementVNode as i, toDisplayString as B, createCommentVNode as S, createTextVNode as Y, Fragment as G, renderList as X } from "vue";
2
+ const Z = {
3
3
  width: "64",
4
4
  height: "64",
5
5
  viewBox: "0 0 64 64",
6
6
  fill: "none",
7
7
  style: { opacity: "0.8" }
8
- }, Z = {
8
+ }, ee = {
9
9
  key: 1,
10
10
  class: "rvms-overlay"
11
- }, ee = {
11
+ }, te = {
12
12
  key: 2,
13
13
  class: "rvms-overlay"
14
- }, te = {
14
+ }, ne = {
15
15
  key: 3,
16
16
  class: "rvms-overlay"
17
- }, ne = {
17
+ }, re = {
18
18
  key: 0,
19
19
  style: { color: "#fca5a5", "font-size": "0.8em", "text-align": "center", padding: "0 1em", "max-width": "80%" }
20
- }, re = {
20
+ }, oe = {
21
21
  key: 4,
22
22
  class: "rvms-overlay"
23
- }, oe = { style: { position: "absolute", top: "8px", left: "8px", display: "flex", gap: "6px", "align-items": "center", "pointer-events": "none" } }, ae = {
23
+ }, ae = { style: { position: "absolute", top: "8px", left: "8px", display: "flex", gap: "6px", "align-items": "center", "pointer-events": "none" } }, le = {
24
24
  key: 1,
25
25
  style: { padding: "2px 6px", "border-radius": "4px", "font-size": "10px", "font-family": "monospace", background: "rgba(51, 65, 85, 0.8)", color: "#cbd5e1" }
26
- }, le = {
26
+ }, se = {
27
27
  key: 2,
28
28
  style: { display: "inline-flex", "align-items": "center", gap: "4px", padding: "2px 8px", "border-radius": "4px", "font-size": "10px", background: "#065f46", color: "#6ee7b7" }
29
- }, se = {
29
+ }, ie = {
30
30
  key: 5,
31
31
  style: { position: "absolute", bottom: "12px", right: "12px", display: "flex", gap: "6px" }
32
- }, ie = ["title"], ue = {
32
+ }, ue = ["title"], ce = {
33
33
  key: 6,
34
34
  style: { position: "absolute", bottom: "48px", left: "8px", right: "8px", "max-height": "140px", "overflow-y": "auto", display: "flex", "flex-direction": "column", gap: "4px" }
35
- }, ce = ["title", "onClick"], de = ["src"], fe = { style: { flex: "1", "min-width": "0" } }, pe = { style: { display: "flex", gap: "6px", "align-items": "baseline" } }, ve = { style: { color: "#fbbf24", "font-weight": "600", "text-transform": "uppercase", "font-size": "10px" } }, me = {
35
+ }, de = ["title", "onClick"], fe = ["src"], pe = { style: { flex: "1", "min-width": "0" } }, ve = { style: { display: "flex", gap: "6px", "align-items": "baseline" } }, me = { style: { color: "#fbbf24", "font-weight": "600", "text-transform": "uppercase", "font-size": "10px" } }, ge = {
36
36
  key: 0,
37
37
  style: { color: "#94a3b8" }
38
- }, ge = { style: { color: "#94a3b8", "font-size": "10px", "white-space": "nowrap", overflow: "hidden", "text-overflow": "ellipsis" } }, Re = /* @__PURE__ */ N({
38
+ }, ye = { style: { color: "#94a3b8", "font-size": "10px", "white-space": "nowrap", overflow: "hidden", "text-overflow": "ellipsis" } }, Ue = /* @__PURE__ */ F({
39
39
  __name: "RvmsVideoPlayer",
40
40
  props: {
41
41
  nvrId: {},
@@ -51,26 +51,26 @@ const X = {
51
51
  },
52
52
  emits: ["alarm", "stream-status", "alarm-click"],
53
53
  setup($, { expose: P, emit: x }) {
54
- const s = $, v = x, l = k(null), a = k("idle"), g = k(null), w = k(null), h = k(!1), C = k(s.initialProfile);
54
+ const s = $, v = x, l = k(null), a = k("idle"), g = k(null), w = k(null), b = k(!1), C = k(s.initialProfile);
55
55
  function I() {
56
- C.value = C.value === "main" ? "sub" : "main", h.value && m();
56
+ C.value = C.value === "main" ? "sub" : "main", b.value && m();
57
57
  }
58
- const E = k(null), L = k([]);
58
+ const E = k(null), O = k([]);
59
59
  function U(e) {
60
60
  return `${location.protocol === "https:" ? "wss:" : "ws:"}//${location.host}${e}`;
61
61
  }
62
- function D() {
63
- M();
62
+ function j() {
63
+ D();
64
64
  const e = new WebSocket(s.token ? `/ws/alarms?token=${encodeURIComponent(s.token)}` : U("/ws/alarms"));
65
65
  E.value = e, e.onmessage = (t) => {
66
66
  try {
67
67
  const r = JSON.parse(t.data);
68
68
  switch (r.type) {
69
69
  case "snapshot":
70
- r.events && (L.value = r.events, r.events.forEach((p) => v("alarm", p)));
70
+ r.events && (O.value = r.events, r.events.forEach((d) => v("alarm", d)));
71
71
  break;
72
72
  case "alarm":
73
- r.event && (L.value.unshift(r.event), L.value.length > 50 && (L.value.length = 50), v("alarm", r.event));
73
+ r.event && (O.value.unshift(r.event), O.value.length > 50 && (O.value.length = 50), v("alarm", r.event));
74
74
  break;
75
75
  default:
76
76
  break;
@@ -78,11 +78,11 @@ const X = {
78
78
  } catch {
79
79
  }
80
80
  }, e.onclose = () => {
81
- E.value = null, setTimeout(D, 3e3);
81
+ E.value = null, setTimeout(j, 3e3);
82
82
  }, e.onerror = () => {
83
83
  };
84
84
  }
85
- function M() {
85
+ function D() {
86
86
  if (E.value) {
87
87
  try {
88
88
  E.value.onclose = null, E.value.close();
@@ -98,13 +98,13 @@ const X = {
98
98
  const t = await fetch("/api/alarms/recent", { headers: e });
99
99
  if (t.ok) {
100
100
  const r = await t.json();
101
- L.value = r;
101
+ O.value = r;
102
102
  }
103
103
  } catch {
104
104
  }
105
105
  }
106
106
  let H = null;
107
- function O() {
107
+ function z() {
108
108
  return {
109
109
  cancelled: !1,
110
110
  ws: null,
@@ -116,7 +116,7 @@ const X = {
116
116
  sourceOpenHandler: null
117
117
  };
118
118
  }
119
- function z() {
119
+ function R() {
120
120
  var t;
121
121
  const e = H;
122
122
  if (e) {
@@ -154,109 +154,111 @@ const X = {
154
154
  return;
155
155
  }
156
156
  a.value = "connecting", g.value = null, w.value = null, v("stream-status", "connecting");
157
- const t = O();
157
+ const t = z();
158
158
  H = t;
159
159
  const r = new MediaSource();
160
160
  t.mediaSource = r, l.value.src = URL.createObjectURL(r);
161
- const p = () => {
162
- t.cancelled || t.mediaSource !== r || (a.value = "buffering", v("stream-status", "buffering"), T(t));
161
+ const d = () => {
162
+ t.cancelled || t.mediaSource !== r || (a.value = "buffering", v("stream-status", "buffering"), M(t));
163
163
  };
164
- t.sourceOpenHandler = p, r.addEventListener("sourceopen", p);
165
- const u = new WebSocket(e);
166
- u.binaryType = "arraybuffer", t.ws = u, u.onmessage = (b) => {
164
+ t.sourceOpenHandler = d, r.addEventListener("sourceopen", d);
165
+ const c = new WebSocket(e);
166
+ c.binaryType = "arraybuffer", t.ws = c, c.onmessage = (h) => {
167
167
  if (t.cancelled) return;
168
- if (typeof b.data == "string") {
168
+ if (typeof h.data == "string") {
169
169
  try {
170
- const R = JSON.parse(b.data);
171
- R.type === "error" && R.message && (g.value = R.message, a.value = "error", v("stream-status", "error"), z());
170
+ const L = JSON.parse(h.data);
171
+ L.type === "error" && L.message && (g.value = L.message, a.value = "error", v("stream-status", "error"), R());
172
172
  } catch {
173
173
  }
174
174
  return;
175
175
  }
176
- const _ = new Uint8Array(b.data);
176
+ const _ = new Uint8Array(h.data);
177
177
  if (!t.sourceBuffer) {
178
- t.preBuffer.push(_), T(t);
178
+ t.preBuffer.push(_), M(t);
179
179
  return;
180
180
  }
181
181
  t.appendQueue.push(
182
182
  _.buffer.slice(_.byteOffset, _.byteOffset + _.byteLength)
183
183
  ), o(t);
184
- }, u.onerror = () => {
184
+ }, c.onerror = () => {
185
185
  t.cancelled || a.value !== "error" && (g.value = "WebSocket error", a.value = "error", v("stream-status", "error"));
186
- }, u.onclose = (b) => {
187
- t.cancelled || (a.value === "connecting" || a.value === "buffering" ? (g.value = b.reason || `Stream closed (code ${b.code})`, a.value = "error", v("stream-status", "error")) : a.value === "playing" && (a.value = "ended", v("stream-status", "ended")));
186
+ }, c.onclose = (h) => {
187
+ t.cancelled || (a.value === "connecting" || a.value === "buffering" ? (g.value = h.reason || `Stream closed (code ${h.code})`, a.value = "error", v("stream-status", "error")) : a.value === "playing" && (a.value = "ended", v("stream-status", "ended")));
188
188
  };
189
189
  }
190
190
  function V(e) {
191
- const t = (u) => u.toString(16).padStart(2, "0").toUpperCase();
192
- let r = null, p = null;
193
- for (let u = 0; u + 7 < e.length; u++) {
194
- const b = String.fromCharCode(e[u], e[u + 1], e[u + 2], e[u + 3]);
195
- if (b === "avcC") {
196
- const _ = e[u + 5], R = e[u + 6], Q = e[u + 7];
197
- _ !== void 0 && R !== void 0 && Q !== void 0 && (r = `avc1.${t(_)}${t(R)}${t(Q)}`);
191
+ const t = (c) => c.toString(16).padStart(2, "0").toUpperCase();
192
+ let r = null, d = null;
193
+ for (let c = 0; c + 7 < e.length; c++) {
194
+ const h = String.fromCharCode(e[c], e[c + 1], e[c + 2], e[c + 3]);
195
+ if (h === "avcC") {
196
+ const _ = e[c + 5], L = e[c + 6], T = e[c + 7];
197
+ _ !== void 0 && L !== void 0 && T !== void 0 && (r = `avc1.${t(_)}${t(L)}${t(T)}`);
198
198
  }
199
- b === "hvcC" && (r = "hev1.1.6.L93.B0"), b === "mp4a" && (p = "mp4a.40.2");
199
+ h === "hvcC" && (r = "hev1.1.6.L93.B0"), h === "mp4a" && (d = "mp4a.40.2");
200
200
  }
201
- return r ? p ? `${r}, ${p}` : r : null;
201
+ return r ? d ? `${r}, ${d}` : r : null;
202
202
  }
203
- function T(e) {
203
+ function M(e) {
204
204
  if (e.cancelled || e.sourceBuffer || !e.mediaSource || e.mediaSource.readyState !== "open") return;
205
205
  const t = n(e.preBuffer), r = V(t);
206
206
  if (!r) return;
207
207
  w.value = r;
208
- const p = `video/mp4; codecs="${r}"`;
209
- if (!MediaSource.isTypeSupported(p)) {
210
- g.value = `Codec not supported: ${p}`, a.value = "error", z();
208
+ const d = `video/mp4; codecs="${r}"`;
209
+ if (!MediaSource.isTypeSupported(d)) {
210
+ g.value = `Codec not supported: ${d}`, a.value = "error", R();
211
211
  return;
212
212
  }
213
- let u;
213
+ let c;
214
214
  try {
215
- u = e.mediaSource.addSourceBuffer(p);
215
+ c = e.mediaSource.addSourceBuffer(d);
216
216
  } catch (_) {
217
- g.value = `addSourceBuffer failed: ${_.message}`, a.value = "error", z();
217
+ g.value = `addSourceBuffer failed: ${_.message}`, a.value = "error", R();
218
218
  return;
219
219
  }
220
- u.mode = "segments";
221
- const b = () => {
220
+ c.mode = "segments";
221
+ const h = () => {
222
222
  e.cancelled || o(e);
223
223
  };
224
- e.updateEndHandler = b, u.addEventListener("updateend", b), u.addEventListener("error", () => {
224
+ e.updateEndHandler = h, c.addEventListener("updateend", h), c.addEventListener("error", () => {
225
225
  e.cancelled || (g.value = "SourceBuffer error", a.value = "error");
226
- }), e.sourceBuffer = u, e.appendQueue.unshift(t.buffer.slice(t.byteOffset, t.byteOffset + t.byteLength)), e.preBuffer.length = 0, o(e);
226
+ }), e.sourceBuffer = c, e.appendQueue.unshift(t.buffer.slice(t.byteOffset, t.byteOffset + t.byteLength)), e.preBuffer.length = 0, o(e);
227
227
  }
228
228
  function n(e) {
229
- const t = e.reduce((u, b) => u + b.byteLength, 0), r = new Uint8Array(t);
230
- let p = 0;
231
- for (const u of e)
232
- r.set(u, p), p += u.byteLength;
229
+ const t = e.reduce((c, h) => c + h.byteLength, 0), r = new Uint8Array(t);
230
+ let d = 0;
231
+ for (const c of e)
232
+ r.set(c, d), d += c.byteLength;
233
233
  return r;
234
234
  }
235
235
  function o(e) {
236
- var u;
236
+ var c, h;
237
237
  if (e.cancelled) return;
238
238
  const t = e.sourceBuffer, r = e.mediaSource;
239
239
  if (!t || !r || r.readyState !== "open" || t.updating) return;
240
- const p = e.appendQueue.shift();
241
- if (p)
240
+ const d = e.appendQueue.shift();
241
+ if (d)
242
242
  try {
243
- t.appendBuffer(p), a.value !== "playing" && (a.value = "playing", v("stream-status", "playing"));
244
- } catch (b) {
245
- const _ = b;
246
- if (_.name === "QuotaExceededError") {
247
- const R = ((u = l.value) == null ? void 0 : u.currentTime) ?? 0, Q = Math.max(0, R - 5);
243
+ t.appendBuffer(d), a.value !== "playing" && (a.value = "playing", v("stream-status", "playing"));
244
+ } catch (_) {
245
+ const L = _;
246
+ if (e.cancelled || (c = L.message) != null && c.includes("removed from the parent"))
247
+ return;
248
+ if (L.name === "QuotaExceededError") {
249
+ const T = ((h = l.value) == null ? void 0 : h.currentTime) ?? 0, N = Math.max(0, T - 5);
248
250
  try {
249
- t.buffered.length > 0 && t.buffered.start(0) < Q && t.remove(t.buffered.start(0), Q);
251
+ t.buffered.length > 0 && t.buffered.start(0) < N && t.remove(t.buffered.start(0), N);
250
252
  } catch {
251
253
  }
252
- e.appendQueue.unshift(p);
254
+ e.appendQueue.unshift(d);
253
255
  } else
254
- g.value = `appendBuffer failed: ${_.message}`, a.value = "error", z();
256
+ g.value = `appendBuffer failed: ${L.message}`, a.value = "error", R();
255
257
  }
256
258
  }
257
259
  async function m() {
258
- if (z(), h.value = !0, !s.nvrId || !s.deviceId) {
259
- g.value = "nvrId and deviceId are required", a.value = "error", h.value = !1, v("stream-status", "error");
260
+ if (R(), b.value = !0, !s.nvrId || !s.deviceId) {
261
+ g.value = "nvrId and deviceId are required", a.value = "error", b.value = !1, v("stream-status", "error");
260
262
  return;
261
263
  }
262
264
  a.value = "connecting", g.value = null, w.value = null, v("stream-status", "connecting");
@@ -273,27 +275,27 @@ const X = {
273
275
  const r = `${t}//${location.host}/ws/stream?${e.toString()}`;
274
276
  W(r), A();
275
277
  } catch (e) {
276
- g.value = e.message, a.value = "error", h.value = !1, v("stream-status", "error"), console.error("[RvmsVideoPlayer] start failed:", e.message);
278
+ g.value = e.message, a.value = "error", b.value = !1, v("stream-status", "error"), console.error("[RvmsVideoPlayer] start failed:", e.message);
277
279
  }
278
280
  }
279
281
  function y() {
280
- h.value = !1, z(), a.value = "idle", g.value = null, v("stream-status", "idle");
282
+ b.value = !1, R(), a.value = "idle", g.value = null, v("stream-status", "idle");
281
283
  }
282
- function c(e) {
284
+ function u(e) {
283
285
  return e || "";
284
286
  }
285
- return q(() => {
286
- D(), A();
287
- }), F(() => {
288
- M(), y();
289
- }), J(
287
+ return K(() => {
288
+ j(), A();
289
+ }), J(() => {
290
+ D(), y();
291
+ }), q(
290
292
  () => [s.nvrId, s.deviceId, s.mode].join("|"),
291
293
  () => {
292
- h.value && s.nvrId && s.deviceId && m();
294
+ b.value && s.nvrId && s.deviceId && m();
293
295
  }
294
- ), P({ start: m, stop: y }), (e, t) => (d(), f("div", {
296
+ ), P({ start: m, stop: y }), (e, t) => (f(), p("div", {
295
297
  class: "rvms-player-wrapper",
296
- style: j({ width: $.width, height: $.height, position: "relative", background: "#000", overflow: "hidden", borderRadius: "8px" })
298
+ style: Q({ width: $.width, height: $.height, position: "relative", background: "#000", overflow: "hidden", borderRadius: "8px" })
297
299
  }, [
298
300
  i("video", {
299
301
  ref_key: "videoEl",
@@ -303,13 +305,13 @@ const X = {
303
305
  controls: "",
304
306
  style: { width: "100%", height: "100%", "object-fit": "contain", display: "block" }
305
307
  }, null, 512),
306
- a.value === "idle" ? (d(), f("div", {
308
+ a.value === "idle" ? (f(), p("div", {
307
309
  key: 0,
308
310
  class: "rvms-overlay",
309
311
  style: { cursor: "pointer" },
310
312
  onClick: m
311
313
  }, [
312
- (d(), f("svg", X, [...t[2] || (t[2] = [
314
+ (f(), p("svg", Z, [...t[2] || (t[2] = [
313
315
  i("circle", {
314
316
  cx: "32",
315
317
  cy: "32",
@@ -324,28 +326,28 @@ const X = {
324
326
  }, null, -1)
325
327
  ])])),
326
328
  t[3] || (t[3] = i("span", { style: { color: "#94a3b8", "font-size": "0.85rem" } }, "Click to play", -1))
327
- ])) : a.value === "connecting" ? (d(), f("div", Z, [...t[4] || (t[4] = [
329
+ ])) : a.value === "connecting" ? (f(), p("div", ee, [...t[4] || (t[4] = [
328
330
  i("span", { style: { color: "#93c5fd", animation: "rvms-pulse 1.5s infinite" } }, "Connecting…", -1)
329
- ])])) : a.value === "buffering" ? (d(), f("div", ee, [...t[5] || (t[5] = [
331
+ ])])) : a.value === "buffering" ? (f(), p("div", te, [...t[5] || (t[5] = [
330
332
  i("span", { style: { color: "#93c5fd", animation: "rvms-pulse 1.5s infinite" } }, "Buffering…", -1)
331
- ])])) : a.value === "error" ? (d(), f("div", te, [
333
+ ])])) : a.value === "error" ? (f(), p("div", ne, [
332
334
  t[6] || (t[6] = i("span", { style: { color: "#f87171", "font-weight": "600" } }, "Stream error", -1)),
333
- g.value ? (d(), f("span", ne, B(g.value), 1)) : S("", !0),
335
+ g.value ? (f(), p("span", re, B(g.value), 1)) : S("", !0),
334
336
  i("button", {
335
337
  class: "rvms-btn",
336
338
  onClick: m
337
339
  }, " Retry ")
338
- ])) : a.value === "ended" ? (d(), f("div", re, [
340
+ ])) : a.value === "ended" ? (f(), p("div", oe, [
339
341
  t[7] || (t[7] = i("span", { style: { color: "#94a3b8" } }, "Stream ended", -1)),
340
342
  i("button", {
341
343
  class: "rvms-btn",
342
344
  onClick: m
343
345
  }, " Reconnect ")
344
346
  ])) : S("", !0),
345
- i("div", oe, [
346
- a.value !== "idle" ? (d(), f("span", {
347
+ i("div", ae, [
348
+ a.value !== "idle" ? (f(), p("span", {
347
349
  key: 0,
348
- style: j({
350
+ style: Q({
349
351
  padding: "2px 8px",
350
352
  borderRadius: "4px",
351
353
  fontSize: "10px",
@@ -356,13 +358,13 @@ const X = {
356
358
  color: "#fff"
357
359
  })
358
360
  }, B($.mode === "live" ? "LIVE" : "PLAYBACK"), 5)) : S("", !0),
359
- w.value ? (d(), f("span", ae, B(w.value), 1)) : S("", !0),
360
- E.value ? (d(), f("span", le, [...t[8] || (t[8] = [
361
+ w.value ? (f(), p("span", le, B(w.value), 1)) : S("", !0),
362
+ E.value ? (f(), p("span", se, [...t[8] || (t[8] = [
361
363
  i("span", { style: { width: "6px", height: "6px", "border-radius": "50%", background: "#22c55e", display: "inline-block" } }, null, -1),
362
- K(" Alarms ", -1)
364
+ Y(" Alarms ", -1)
363
365
  ])])) : S("", !0)
364
366
  ]),
365
- a.value !== "idle" ? (d(), f("div", se, [
367
+ a.value !== "idle" ? (f(), p("div", ie, [
366
368
  i("button", {
367
369
  class: "rvms-btn",
368
370
  title: "Stop stream",
@@ -372,60 +374,60 @@ const X = {
372
374
  class: "rvms-btn",
373
375
  title: `Switch to ${C.value === "main" ? "sub" : "main"} stream`,
374
376
  onClick: I
375
- }, B(C.value === "main" ? "HD" : "SD"), 9, ie)
377
+ }, B(C.value === "main" ? "HD" : "SD"), 9, ue)
376
378
  ])) : S("", !0),
377
- $.showAlarms && L.value.length > 0 ? (d(), f("div", ue, [
378
- (d(!0), f(Y, null, G(L.value.slice(0, 5), (r) => (d(), f("div", {
379
+ $.showAlarms && O.value.length > 0 ? (f(), p("div", ce, [
380
+ (f(!0), p(G, null, X(O.value.slice(0, 5), (r) => (f(), p("div", {
379
381
  key: r.id,
380
382
  title: (r.description || r.type) + " — click to view playback",
381
383
  style: { display: "flex", "align-items": "center", gap: "8px", padding: "4px 8px", "border-radius": "4px", background: "rgba(0, 0, 0, 0.65)", "font-size": "11px", "backdrop-filter": "blur(4px)", cursor: "pointer", transition: "background 0.15s" },
382
- onClick: (p) => v("alarm-click", r),
383
- onMouseenter: t[0] || (t[0] = (p) => p.target.style.background = "rgba(51, 65, 85, 0.8)"),
384
- onMouseleave: t[1] || (t[1] = (p) => p.target.style.background = "rgba(0, 0, 0, 0.65)")
384
+ onClick: (d) => v("alarm-click", r),
385
+ onMouseenter: t[0] || (t[0] = (d) => d.target.style.background = "rgba(51, 65, 85, 0.8)"),
386
+ onMouseleave: t[1] || (t[1] = (d) => d.target.style.background = "rgba(0, 0, 0, 0.65)")
385
387
  }, [
386
- r.snapshotUrl ? (d(), f("img", {
388
+ r.snapshotUrl ? (f(), p("img", {
387
389
  key: 0,
388
- src: c(r.snapshotUrl),
390
+ src: u(r.snapshotUrl),
389
391
  alt: "snapshot",
390
392
  style: { width: "32px", height: "24px", "border-radius": "2px", "object-fit": "cover", background: "#1e293b" },
391
393
  loading: "lazy"
392
- }, null, 8, de)) : S("", !0),
393
- i("div", fe, [
394
- i("div", pe, [
395
- i("span", ve, B(r.type), 1),
396
- r.channel ? (d(), f("span", me, " ch" + B(r.channel), 1)) : S("", !0)
394
+ }, null, 8, fe)) : S("", !0),
395
+ i("div", pe, [
396
+ i("div", ve, [
397
+ i("span", me, B(r.type), 1),
398
+ r.channel ? (f(), p("span", ge, " ch" + B(r.channel), 1)) : S("", !0)
397
399
  ]),
398
- i("div", ge, B(new Date(r.timestamp).toLocaleString()), 1),
400
+ i("div", ye, B(new Date(r.timestamp).toLocaleString()), 1),
399
401
  t[9] || (t[9] = i("div", { style: { color: "#60a5fa", "font-size": "9px", "margin-top": "1px" } }, " Click to view playback ", -1))
400
402
  ])
401
- ], 40, ce))), 128))
403
+ ], 40, de))), 128))
402
404
  ])) : S("", !0)
403
405
  ], 4));
404
406
  }
405
- }), ye = {
407
+ }), he = {
406
408
  key: 1,
407
409
  style: { position: "absolute", inset: "0", display: "flex", "flex-direction": "column", "align-items": "center", "justify-content": "center", gap: "8px", background: "rgba(0, 0, 0, 0.4)", "z-index": "10" }
408
- }, he = { style: { color: "#e2e8f0", "font-size": "0.85rem" } }, be = {
410
+ }, be = { style: { color: "#e2e8f0", "font-size": "0.85rem" } }, xe = {
409
411
  key: 2,
410
412
  style: { position: "absolute", inset: "0", display: "flex", "flex-direction": "column", "align-items": "center", "justify-content": "center", gap: "12px", background: "rgba(0, 0, 0, 0.5)", "z-index": "10" }
411
- }, xe = { style: { color: "#ef4444", "font-size": "0.85rem", "text-align": "center", padding: "0 16px" } }, ke = {
413
+ }, ke = { style: { color: "#ef4444", "font-size": "0.85rem", "text-align": "center", padding: "0 16px" } }, Se = {
412
414
  key: 3,
413
415
  style: { position: "absolute", inset: "0", display: "flex", "flex-direction": "column", "align-items": "center", "justify-content": "center", gap: "12px", background: "rgba(0, 0, 0, 0.4)", "z-index": "10" }
414
- }, Se = { style: { position: "absolute", top: "8px", left: "8px", right: "8px", display: "flex", gap: "6px", "align-items": "center", "flex-wrap": "wrap", "z-index": "11", "pointer-events": "none" } }, we = ["title"], Be = ["title"], $e = {
416
+ }, we = { style: { position: "absolute", top: "8px", left: "8px", right: "8px", display: "flex", gap: "6px", "align-items": "center", "flex-wrap": "wrap", "z-index": "11", "pointer-events": "none" } }, Be = ["title"], $e = ["title"], _e = {
415
417
  key: 0,
416
418
  class: "rvms-chip",
417
419
  style: { background: "rgba(51, 65, 85, 0.8)", color: "#cbd5e1", "font-family": "monospace" }
418
- }, _e = ["value"], Ce = {
420
+ }, Ce = ["value"], Ie = {
419
421
  key: 2,
420
422
  class: "rvms-chip",
421
423
  style: { background: "rgba(15, 23, 42, 0.85)", color: "#94a3b8", cursor: "default", "pointer-events": "auto" }
422
- }, Ie = {
424
+ }, Ee = {
423
425
  key: 4,
424
426
  style: { position: "absolute", bottom: "44px", left: "8px", display: "flex", gap: "6px", "align-items": "center", "z-index": "11", "pointer-events": "none" }
425
- }, Ee = {
427
+ }, Le = {
426
428
  key: 5,
427
429
  style: { position: "absolute", bottom: "8px", right: "8px", display: "flex", gap: "6px", "z-index": "11" }
428
- }, Le = /* @__PURE__ */ N({
430
+ }, Oe = /* @__PURE__ */ F({
429
431
  __name: "RvmsVideo",
430
432
  props: {
431
433
  nvrId: {},
@@ -437,9 +439,9 @@ const X = {
437
439
  },
438
440
  emits: ["status-change"],
439
441
  setup($, { emit: P }) {
440
- const x = $, s = P, v = k(null), l = k("idle"), a = k(null), g = k(null), w = k(!1), h = k("live"), C = k(x.initialProfile), I = k("");
442
+ const x = $, s = P, v = k(null), l = k("idle"), a = k(null), g = k(null), w = k(!1), b = k("live"), C = k(x.initialProfile), I = k("");
441
443
  let E = null;
442
- function L() {
444
+ function O() {
443
445
  return {
444
446
  cancelled: !1,
445
447
  ws: null,
@@ -482,14 +484,14 @@ const X = {
482
484
  }
483
485
  }
484
486
  }
485
- function D(n) {
487
+ function j(n) {
486
488
  if (!v.value) return;
487
489
  if (!("MediaSource" in window)) {
488
490
  a.value = "MediaSource Extensions not supported", l.value = "error", s("status-change", "error");
489
491
  return;
490
492
  }
491
493
  l.value = "connecting", a.value = null, g.value = null, s("status-change", "connecting");
492
- const o = L();
494
+ const o = O();
493
495
  E = o;
494
496
  const m = new MediaSource();
495
497
  o.mediaSource = m, v.value.src = URL.createObjectURL(m);
@@ -497,8 +499,8 @@ const X = {
497
499
  o.cancelled || o.mediaSource !== m || (l.value = "buffering", s("status-change", "buffering"), A(o));
498
500
  };
499
501
  o.sourceOpenHandler = y, m.addEventListener("sourceopen", y);
500
- const c = new WebSocket(n);
501
- c.binaryType = "arraybuffer", o.ws = c, c.onmessage = (e) => {
502
+ const u = new WebSocket(n);
503
+ u.binaryType = "arraybuffer", o.ws = u, u.onmessage = (e) => {
502
504
  if (o.cancelled) return;
503
505
  if (typeof e.data == "string") {
504
506
  try {
@@ -516,20 +518,20 @@ const X = {
516
518
  o.appendQueue.push(
517
519
  t.buffer.slice(t.byteOffset, t.byteOffset + t.byteLength)
518
520
  ), H(o);
519
- }, c.onerror = () => {
521
+ }, u.onerror = () => {
520
522
  o.cancelled || l.value !== "error" && (a.value = "WebSocket error", l.value = "error", s("status-change", "error"));
521
- }, c.onclose = (e) => {
523
+ }, u.onclose = (e) => {
522
524
  o.cancelled || (l.value === "connecting" || l.value === "buffering" ? (a.value = e.reason || `Stream closed (code ${e.code})`, l.value = "error", s("status-change", "error")) : l.value === "playing" && (l.value = "ended", s("status-change", "ended")));
523
525
  };
524
526
  }
525
- function M(n) {
526
- const o = (c) => c.toString(16).padStart(2, "0").toUpperCase();
527
+ function D(n) {
528
+ const o = (u) => u.toString(16).padStart(2, "0").toUpperCase();
527
529
  let m = null, y = null;
528
- for (let c = 0; c + 7 < n.length; c++) {
529
- const e = String.fromCharCode(n[c], n[c + 1], n[c + 2], n[c + 3]);
530
+ for (let u = 0; u + 7 < n.length; u++) {
531
+ const e = String.fromCharCode(n[u], n[u + 1], n[u + 2], n[u + 3]);
530
532
  if (e === "avcC") {
531
- const t = n[c + 5], r = n[c + 6], p = n[c + 7];
532
- t !== void 0 && r !== void 0 && p !== void 0 && (m = `avc1.${o(t)}${o(r)}${o(p)}`);
533
+ const t = n[u + 5], r = n[u + 6], d = n[u + 7];
534
+ t !== void 0 && r !== void 0 && d !== void 0 && (m = `avc1.${o(t)}${o(r)}${o(d)}`);
533
535
  }
534
536
  e === "hvcC" && (m = "hev1.1.6.L93.B0"), e === "mp4a" && (y = "mp4a.40.2");
535
537
  }
@@ -539,8 +541,8 @@ const X = {
539
541
  if (n.sourceBuffer || !n.mediaSource || n.mediaSource.readyState !== "open") return;
540
542
  const o = ["avc1.64001F", "avc1.4D0028", "avc1.42001E", "hev1.1.6.L93.B0"];
541
543
  let m = 'video/mp4; codecs="avc1.64001F"';
542
- for (const c of n.preBuffer) {
543
- const e = M(c);
544
+ for (const u of n.preBuffer) {
545
+ const e = D(u);
544
546
  if (e) {
545
547
  g.value = e, m = `video/mp4; codecs="${e}"`;
546
548
  break;
@@ -549,9 +551,9 @@ const X = {
549
551
  try {
550
552
  n.sourceBuffer = n.mediaSource.addSourceBuffer(m);
551
553
  } catch {
552
- for (const c of o)
554
+ for (const u of o)
553
555
  try {
554
- n.sourceBuffer = n.mediaSource.addSourceBuffer(`video/mp4; codecs="${c}"`);
556
+ n.sourceBuffer = n.mediaSource.addSourceBuffer(`video/mp4; codecs="${u}"`);
555
557
  break;
556
558
  } catch {
557
559
  }
@@ -560,9 +562,9 @@ const X = {
560
562
  a.value = "No compatible video codec", l.value = "error";
561
563
  return;
562
564
  }
563
- for (const c of n.preBuffer)
565
+ for (const u of n.preBuffer)
564
566
  try {
565
- n.sourceBuffer.appendBuffer(c);
567
+ n.sourceBuffer.appendBuffer(u);
566
568
  } catch {
567
569
  }
568
570
  n.preBuffer.length = 0;
@@ -572,27 +574,29 @@ const X = {
572
574
  n.updateEndHandler = y, n.sourceBuffer.addEventListener("updateend", y);
573
575
  }
574
576
  function H(n) {
575
- var y;
577
+ var y, u;
576
578
  const o = n.sourceBuffer;
577
579
  if (!o || o.updating || n.appendQueue.length === 0) return;
578
580
  const m = n.appendQueue.shift();
579
581
  try {
580
582
  o.appendBuffer(m), l.value !== "playing" && (l.value = "playing", s("status-change", "playing"));
581
- } catch (c) {
582
- const e = c;
583
- if (e.name === "QuotaExceededError") {
584
- const t = ((y = v.value) == null ? void 0 : y.currentTime) ?? 0, r = Math.max(0, t - 5);
583
+ } catch (e) {
584
+ const t = e;
585
+ if (n.cancelled || (y = t.message) != null && y.includes("removed from the parent"))
586
+ return;
587
+ if (t.name === "QuotaExceededError") {
588
+ const r = ((u = v.value) == null ? void 0 : u.currentTime) ?? 0, d = Math.max(0, r - 5);
585
589
  try {
586
- o.buffered.length > 0 && o.buffered.start(0) < r && o.remove(o.buffered.start(0), r);
590
+ o.buffered.length > 0 && o.buffered.start(0) < d && o.remove(o.buffered.start(0), d);
587
591
  } catch {
588
592
  }
589
593
  n.appendQueue.unshift(m);
590
594
  } else
591
- a.value = `appendBuffer failed: ${e.message}`, l.value = "error", U();
595
+ a.value = `appendBuffer failed: ${t.message}`, l.value = "error", U();
592
596
  }
593
597
  }
594
- async function O() {
595
- if (h.value === "playback" && !I.value && (I.value = (/* @__PURE__ */ new Date()).toISOString()), U(), w.value = !0, !x.nvrId || !x.channelId) {
598
+ async function z() {
599
+ if (b.value === "playback" && !I.value && (I.value = (/* @__PURE__ */ new Date()).toISOString()), U(), w.value = !0, !x.nvrId || !x.channelId) {
596
600
  a.value = "nvrId and channelId are required", l.value = "error", w.value = !1, s("status-change", "error");
597
601
  return;
598
602
  }
@@ -601,46 +605,46 @@ const X = {
601
605
  const n = new URLSearchParams({
602
606
  nvrId: x.nvrId,
603
607
  deviceId: x.channelId,
604
- mode: h.value,
608
+ mode: b.value,
605
609
  profile: C.value
606
610
  });
607
- if (h.value === "playback") {
611
+ if (b.value === "playback") {
608
612
  let y = I.value;
609
613
  y || (y = (/* @__PURE__ */ new Date()).toISOString(), I.value = y);
610
- const c = new Date(y).getTime();
611
- n.set("from", new Date(c - 3e4).toISOString()), n.set("to", new Date(c + 3e4).toISOString());
614
+ const u = new Date(y).getTime();
615
+ n.set("from", new Date(u - 3e4).toISOString()), n.set("to", new Date(u + 3e4).toISOString());
612
616
  }
613
617
  const o = location.protocol === "https:" ? "wss:" : "ws:";
614
618
  x.token && n.set("token", x.token);
615
619
  const m = `${o}//${location.host}/ws/stream?${n.toString()}`;
616
- D(m);
620
+ j(m);
617
621
  } catch (n) {
618
622
  a.value = n.message, l.value = "error", w.value = !1, s("status-change", "error");
619
623
  }
620
624
  }
621
- function z() {
625
+ function R() {
622
626
  w.value = !1, U(), l.value = "idle", a.value = null, s("status-change", "idle");
623
627
  }
624
628
  function W() {
625
- h.value = h.value === "live" ? "playback" : "live", w.value && O();
629
+ b.value = b.value === "live" ? "playback" : "live", w.value && z();
626
630
  }
627
631
  function V() {
628
- C.value = C.value === "main" ? "sub" : "main", w.value && O();
632
+ C.value = C.value === "main" ? "sub" : "main", w.value && z();
629
633
  }
630
- function T(n) {
634
+ function M(n) {
631
635
  const o = n.target;
632
636
  o.value && (I.value = new Date(o.value).toISOString());
633
637
  }
634
- return F(() => {
635
- z();
636
- }), J(
638
+ return J(() => {
639
+ R();
640
+ }), q(
637
641
  () => [x.nvrId, x.channelId].join("|"),
638
642
  () => {
639
- w.value && x.nvrId && x.channelId && O();
643
+ w.value && x.nvrId && x.channelId && z();
640
644
  }
641
- ), (n, o) => (d(), f("div", {
645
+ ), (n, o) => (f(), p("div", {
642
646
  class: "rvms-video",
643
- style: j({
647
+ style: Q({
644
648
  width: $.width,
645
649
  height: $.height,
646
650
  position: "relative",
@@ -656,10 +660,10 @@ const X = {
656
660
  playsinline: "",
657
661
  style: { width: "100%", height: "100%", display: "block", "object-fit": "contain" }
658
662
  }, null, 512),
659
- l.value === "idle" ? (d(), f("div", {
663
+ l.value === "idle" ? (f(), p("div", {
660
664
  key: 0,
661
665
  style: { position: "absolute", inset: "0", display: "flex", "flex-direction": "column", "align-items": "center", "justify-content": "center", gap: "12px", background: "rgba(0, 0, 0, 0.5)", cursor: "pointer", "z-index": "10" },
662
- onClick: O
666
+ onClick: z
663
667
  }, [...o[0] || (o[0] = [
664
668
  i("svg", {
665
669
  width: "64",
@@ -681,53 +685,53 @@ const X = {
681
685
  })
682
686
  ], -1),
683
687
  i("span", { style: { color: "#e2e8f0", "font-size": "0.9rem", "font-weight": "600" } }, "Click to play", -1)
684
- ])])) : l.value === "connecting" || l.value === "buffering" ? (d(), f("div", ye, [
688
+ ])])) : l.value === "connecting" || l.value === "buffering" ? (f(), p("div", he, [
685
689
  o[1] || (o[1] = i("div", { class: "rvms-spinner" }, null, -1)),
686
- i("span", he, B(l.value === "connecting" ? "Connecting…" : "Buffering…"), 1)
687
- ])) : l.value === "error" ? (d(), f("div", be, [
688
- i("span", xe, B(a.value || "Stream error"), 1),
690
+ i("span", be, B(l.value === "connecting" ? "Connecting…" : "Buffering…"), 1)
691
+ ])) : l.value === "error" ? (f(), p("div", xe, [
692
+ i("span", ke, B(a.value || "Stream error"), 1),
689
693
  i("button", {
690
694
  class: "rvms-btn",
691
- onClick: O
695
+ onClick: z
692
696
  }, " Retry ")
693
- ])) : l.value === "ended" ? (d(), f("div", ke, [
697
+ ])) : l.value === "ended" ? (f(), p("div", Se, [
694
698
  o[2] || (o[2] = i("span", { style: { color: "#94a3b8" } }, "Stream ended", -1)),
695
699
  i("button", {
696
700
  class: "rvms-btn",
697
- onClick: O
701
+ onClick: z
698
702
  }, "Reconnect")
699
703
  ])) : S("", !0),
700
- i("div", Se, [
704
+ i("div", we, [
701
705
  i("button", {
702
706
  class: "rvms-chip",
703
- title: `Switch to ${h.value === "live" ? "playback" : "live"} mode`,
707
+ title: `Switch to ${b.value === "live" ? "playback" : "live"} mode`,
704
708
  onClick: W,
705
- style: j({
706
- background: h.value === "live" ? "#dc2626" : "#2563eb",
709
+ style: Q({
710
+ background: b.value === "live" ? "#dc2626" : "#2563eb",
707
711
  pointerEvents: "auto"
708
712
  })
709
- }, B(h.value === "live" ? "🔴 LIVE" : "🔵 PLAYBACK"), 13, we),
713
+ }, B(b.value === "live" ? "🔴 LIVE" : "🔵 PLAYBACK"), 13, Be),
710
714
  i("button", {
711
715
  class: "rvms-chip",
712
716
  title: `Switch to ${C.value === "main" ? "sub" : "main"} stream`,
713
717
  onClick: V,
714
718
  style: { pointerEvents: "auto" }
715
- }, B(C.value === "main" ? "HD" : "SD"), 9, Be),
716
- g.value ? (d(), f("span", $e, B(g.value), 1)) : S("", !0),
717
- h.value === "playback" ? (d(), f("input", {
719
+ }, B(C.value === "main" ? "HD" : "SD"), 9, $e),
720
+ g.value ? (f(), p("span", _e, B(g.value), 1)) : S("", !0),
721
+ b.value === "playback" ? (f(), p("input", {
718
722
  key: 1,
719
723
  type: "datetime-local",
720
724
  value: I.value ? I.value.slice(0, 16) : "",
721
- onInput: T,
725
+ onInput: M,
722
726
  class: "rvms-datetime",
723
727
  title: "Playback timestamp",
724
728
  style: { "pointer-events": "auto" }
725
- }, null, 40, _e)) : S("", !0),
726
- h.value === "playback" && I.value ? (d(), f("span", Ce, B(new Date(I.value).toLocaleString()), 1)) : S("", !0)
729
+ }, null, 40, Ce)) : S("", !0),
730
+ b.value === "playback" && I.value ? (f(), p("span", Ie, B(new Date(I.value).toLocaleString()), 1)) : S("", !0)
727
731
  ]),
728
- l.value !== "idle" ? (d(), f("div", Ie, [
732
+ l.value !== "idle" ? (f(), p("div", Ee, [
729
733
  i("span", {
730
- style: j({
734
+ style: Q({
731
735
  padding: "2px 8px",
732
736
  borderRadius: "4px",
733
737
  fontSize: "10px",
@@ -738,28 +742,28 @@ const X = {
738
742
  })
739
743
  }, B(l.value), 5)
740
744
  ])) : S("", !0),
741
- l.value !== "idle" ? (d(), f("div", Ee, [
742
- w.value ? (d(), f("button", {
745
+ l.value !== "idle" ? (f(), p("div", Le, [
746
+ w.value ? (f(), p("button", {
743
747
  key: 0,
744
748
  class: "rvms-btn",
745
749
  title: "Stop stream",
746
- onClick: z
747
- }, " ⏹ Stop ")) : (d(), f("button", {
750
+ onClick: R
751
+ }, " ⏹ Stop ")) : (f(), p("button", {
748
752
  key: 1,
749
753
  class: "rvms-btn",
750
754
  title: "Start stream",
751
- onClick: O
755
+ onClick: z
752
756
  }, " ▶ Play "))
753
757
  ])) : S("", !0)
754
758
  ], 4));
755
759
  }
756
- }), Oe = ($, P) => {
760
+ }), ze = ($, P) => {
757
761
  const x = $.__vccOpts || $;
758
762
  for (const [s, v] of P)
759
763
  x[s] = v;
760
764
  return x;
761
- }, Ue = /* @__PURE__ */ Oe(Le, [["__scopeId", "data-v-bfc7094e"]]);
765
+ }, He = /* @__PURE__ */ ze(Oe, [["__scopeId", "data-v-650bbebf"]]);
762
766
  export {
763
- Ue as RvmsVideo,
764
- Re as RvmsVideoPlayer
767
+ He as RvmsVideo,
768
+ Ue as RvmsVideoPlayer
765
769
  };
@@ -1 +1 @@
1
- @keyframes rvms-pulse{0%,to{opacity:1}50%{opacity:.4}}.rvms-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:#00000080;font-size:14px}.rvms-btn{padding:4px 12px;border:1px solid rgba(255,255,255,.2);border-radius:4px;background:#1e293bcc;color:#e2e8f0;font-size:11px;font-weight:600;cursor:pointer;pointer-events:auto;transition:background .15s}.rvms-btn:hover{background:#334155e6}@keyframes rvms-spin-bfc7094e{to{transform:rotate(360deg)}}.rvms-spinner[data-v-bfc7094e]{width:32px;height:32px;border:3px solid rgba(255,255,255,.2);border-top-color:#60a5fa;border-radius:50%;animation:rvms-spin-bfc7094e .8s linear infinite}.rvms-btn[data-v-bfc7094e]{padding:6px 14px;border:none;border-radius:6px;background:#0f172ad9;color:#e2e8f0;font-size:.8rem;font-weight:700;cursor:pointer;transition:background .15s;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.rvms-btn[data-v-bfc7094e]:hover{background:#1e293bf2}.rvms-chip[data-v-bfc7094e]{padding:2px 8px;border:none;border-radius:4px;font-size:10px;font-weight:700;color:#fff;cursor:pointer;transition:opacity .15s;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);text-transform:uppercase;letter-spacing:.05em}.rvms-chip[data-v-bfc7094e]:hover{opacity:.85}.rvms-datetime[data-v-bfc7094e]{padding:2px 6px;border:1px solid rgba(255,255,255,.2);border-radius:4px;background:#0f172ad9;color:#e2e8f0;font-size:11px;cursor:pointer;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.rvms-datetime[data-v-bfc7094e]:focus{outline:none;border-color:#60a5fa}
1
+ @keyframes rvms-pulse{0%,to{opacity:1}50%{opacity:.4}}.rvms-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:#00000080;font-size:14px}.rvms-btn{padding:4px 12px;border:1px solid rgba(255,255,255,.2);border-radius:4px;background:#1e293bcc;color:#e2e8f0;font-size:11px;font-weight:600;cursor:pointer;pointer-events:auto;transition:background .15s}.rvms-btn:hover{background:#334155e6}@keyframes rvms-spin-650bbebf{to{transform:rotate(360deg)}}.rvms-spinner[data-v-650bbebf]{width:32px;height:32px;border:3px solid rgba(255,255,255,.2);border-top-color:#60a5fa;border-radius:50%;animation:rvms-spin-650bbebf .8s linear infinite}.rvms-btn[data-v-650bbebf]{padding:6px 14px;border:none;border-radius:6px;background:#0f172ad9;color:#e2e8f0;font-size:.8rem;font-weight:700;cursor:pointer;transition:background .15s;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.rvms-btn[data-v-650bbebf]:hover{background:#1e293bf2}.rvms-chip[data-v-650bbebf]{padding:2px 8px;border:none;border-radius:4px;font-size:10px;font-weight:700;color:#fff;cursor:pointer;transition:opacity .15s;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);text-transform:uppercase;letter-spacing:.05em}.rvms-chip[data-v-650bbebf]:hover{opacity:.85}.rvms-datetime[data-v-650bbebf]{padding:2px 6px;border:1px solid rgba(255,255,255,.2);border-radius:4px;background:#0f172ad9;color:#e2e8f0;font-size:11px;cursor:pointer;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.rvms-datetime[data-v-650bbebf]:focus{outline:none;border-color:#60a5fa}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rvms-vue",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "type": "module",
5
5
  "description": "RVMS (Video-MS) Vue 3 components — RvmsVideoPlayer, RvmsVideo",
6
6
  "main": "./dist/lib/index.js",
@@ -312,6 +312,10 @@ function flushQueue(s: Session): void {
312
312
  }
313
313
  } catch (err) {
314
314
  const e = err as DOMException;
315
+ // SourceBuffer was removed during teardown — stream already ended, ignore.
316
+ if (s.cancelled || e.message?.includes('removed from the parent')) {
317
+ return;
318
+ }
315
319
  if (e.name === 'QuotaExceededError') {
316
320
  const ct = videoEl.value?.currentTime ?? 0;
317
321
  const cutoff = Math.max(0, ct - 5);
@@ -456,6 +456,10 @@ function flushQueue(session: Session): void {
456
456
  }
457
457
  } catch (err) {
458
458
  const e = err as DOMException;
459
+ // SourceBuffer was removed during teardown — stream already ended, ignore.
460
+ if (session.cancelled || e.message?.includes('removed from the parent')) {
461
+ return;
462
+ }
459
463
  if (e.name === 'QuotaExceededError') {
460
464
  const ct = videoEl.value?.currentTime ?? 0;
461
465
  const cutoff = Math.max(0, ct - 5);