rvms-vue 0.1.13 → 0.1.15

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