rvms-vue 0.1.13 → 0.1.14

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