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 +203 -199
- package/dist/lib/style.css +1 -1
- package/package.json +1 -1
- package/src/components/RvmsVideo.vue +4 -0
- package/src/components/RvmsVideoPlayer.vue +4 -0
package/dist/lib/index.js
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
const
|
|
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
|
-
},
|
|
8
|
+
}, ee = {
|
|
9
9
|
key: 1,
|
|
10
10
|
class: "rvms-overlay"
|
|
11
|
-
},
|
|
11
|
+
}, te = {
|
|
12
12
|
key: 2,
|
|
13
13
|
class: "rvms-overlay"
|
|
14
|
-
},
|
|
14
|
+
}, ne = {
|
|
15
15
|
key: 3,
|
|
16
16
|
class: "rvms-overlay"
|
|
17
|
-
},
|
|
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
|
-
},
|
|
20
|
+
}, oe = {
|
|
21
21
|
key: 4,
|
|
22
22
|
class: "rvms-overlay"
|
|
23
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
29
|
+
}, ie = {
|
|
30
30
|
key: 5,
|
|
31
31
|
style: { position: "absolute", bottom: "12px", right: "12px", display: "flex", gap: "6px" }
|
|
32
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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),
|
|
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",
|
|
56
|
+
C.value = C.value === "main" ? "sub" : "main", b.value && m();
|
|
57
57
|
}
|
|
58
|
-
const E = k(null),
|
|
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
|
|
63
|
-
|
|
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 && (
|
|
70
|
+
r.events && (O.value = r.events, r.events.forEach((d) => v("alarm", d)));
|
|
71
71
|
break;
|
|
72
72
|
case "alarm":
|
|
73
|
-
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(
|
|
81
|
+
E.value = null, setTimeout(j, 3e3);
|
|
82
82
|
}, e.onerror = () => {
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
|
-
function
|
|
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
|
-
|
|
101
|
+
O.value = r;
|
|
102
102
|
}
|
|
103
103
|
} catch {
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
let H = null;
|
|
107
|
-
function
|
|
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
|
|
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 =
|
|
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
|
|
162
|
-
t.cancelled || t.mediaSource !== r || (a.value = "buffering", v("stream-status", "buffering"),
|
|
161
|
+
const d = () => {
|
|
162
|
+
t.cancelled || t.mediaSource !== r || (a.value = "buffering", v("stream-status", "buffering"), M(t));
|
|
163
163
|
};
|
|
164
|
-
t.sourceOpenHandler =
|
|
165
|
-
const
|
|
166
|
-
|
|
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
|
|
168
|
+
if (typeof h.data == "string") {
|
|
169
169
|
try {
|
|
170
|
-
const
|
|
171
|
-
|
|
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(
|
|
176
|
+
const _ = new Uint8Array(h.data);
|
|
177
177
|
if (!t.sourceBuffer) {
|
|
178
|
-
t.preBuffer.push(_),
|
|
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
|
-
},
|
|
184
|
+
}, c.onerror = () => {
|
|
185
185
|
t.cancelled || a.value !== "error" && (g.value = "WebSocket error", a.value = "error", v("stream-status", "error"));
|
|
186
|
-
},
|
|
187
|
-
t.cancelled || (a.value === "connecting" || a.value === "buffering" ? (g.value =
|
|
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 = (
|
|
192
|
-
let r = null,
|
|
193
|
-
for (let
|
|
194
|
-
const
|
|
195
|
-
if (
|
|
196
|
-
const _ = e[
|
|
197
|
-
_ !== void 0 &&
|
|
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
|
-
|
|
199
|
+
h === "hvcC" && (r = "hev1.1.6.L93.B0"), h === "mp4a" && (d = "mp4a.40.2");
|
|
200
200
|
}
|
|
201
|
-
return r ?
|
|
201
|
+
return r ? d ? `${r}, ${d}` : r : null;
|
|
202
202
|
}
|
|
203
|
-
function
|
|
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
|
|
209
|
-
if (!MediaSource.isTypeSupported(
|
|
210
|
-
g.value = `Codec not supported: ${
|
|
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
|
|
213
|
+
let c;
|
|
214
214
|
try {
|
|
215
|
-
|
|
215
|
+
c = e.mediaSource.addSourceBuffer(d);
|
|
216
216
|
} catch (_) {
|
|
217
|
-
g.value = `addSourceBuffer failed: ${_.message}`, a.value = "error",
|
|
217
|
+
g.value = `addSourceBuffer failed: ${_.message}`, a.value = "error", R();
|
|
218
218
|
return;
|
|
219
219
|
}
|
|
220
|
-
|
|
221
|
-
const
|
|
220
|
+
c.mode = "segments";
|
|
221
|
+
const h = () => {
|
|
222
222
|
e.cancelled || o(e);
|
|
223
223
|
};
|
|
224
|
-
e.updateEndHandler =
|
|
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 =
|
|
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((
|
|
230
|
-
let
|
|
231
|
-
for (const
|
|
232
|
-
r.set(
|
|
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
|
|
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
|
|
241
|
-
if (
|
|
240
|
+
const d = e.appendQueue.shift();
|
|
241
|
+
if (d)
|
|
242
242
|
try {
|
|
243
|
-
t.appendBuffer(
|
|
244
|
-
} catch (
|
|
245
|
-
const
|
|
246
|
-
if (
|
|
247
|
-
|
|
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) <
|
|
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(
|
|
254
|
+
e.appendQueue.unshift(d);
|
|
253
255
|
} else
|
|
254
|
-
g.value = `appendBuffer failed: ${
|
|
256
|
+
g.value = `appendBuffer failed: ${L.message}`, a.value = "error", R();
|
|
255
257
|
}
|
|
256
258
|
}
|
|
257
259
|
async function m() {
|
|
258
|
-
if (
|
|
259
|
-
g.value = "nvrId and deviceId are required", a.value = "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",
|
|
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
|
-
|
|
282
|
+
b.value = !1, R(), a.value = "idle", g.value = null, v("stream-status", "idle");
|
|
281
283
|
}
|
|
282
|
-
function
|
|
284
|
+
function u(e) {
|
|
283
285
|
return e || "";
|
|
284
286
|
}
|
|
285
|
-
return
|
|
286
|
-
|
|
287
|
-
}),
|
|
288
|
-
|
|
289
|
-
}),
|
|
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
|
-
|
|
294
|
+
b.value && s.nvrId && s.deviceId && m();
|
|
293
295
|
}
|
|
294
|
-
), P({ start: m, stop: y }), (e, t) => (
|
|
296
|
+
), P({ start: m, stop: y }), (e, t) => (f(), p("div", {
|
|
295
297
|
class: "rvms-player-wrapper",
|
|
296
|
-
style:
|
|
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" ? (
|
|
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
|
-
(
|
|
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" ? (
|
|
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" ? (
|
|
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" ? (
|
|
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 ? (
|
|
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" ? (
|
|
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",
|
|
346
|
-
a.value !== "idle" ? (
|
|
347
|
+
i("div", ae, [
|
|
348
|
+
a.value !== "idle" ? (f(), p("span", {
|
|
347
349
|
key: 0,
|
|
348
|
-
style:
|
|
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 ? (
|
|
360
|
-
E.value ? (
|
|
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
|
-
|
|
364
|
+
Y(" Alarms ", -1)
|
|
363
365
|
])])) : S("", !0)
|
|
364
366
|
]),
|
|
365
|
-
a.value !== "idle" ? (
|
|
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,
|
|
377
|
+
}, B(C.value === "main" ? "HD" : "SD"), 9, ue)
|
|
376
378
|
])) : S("", !0),
|
|
377
|
-
$.showAlarms &&
|
|
378
|
-
(
|
|
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: (
|
|
383
|
-
onMouseenter: t[0] || (t[0] = (
|
|
384
|
-
onMouseleave: t[1] || (t[1] = (
|
|
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 ? (
|
|
388
|
+
r.snapshotUrl ? (f(), p("img", {
|
|
387
389
|
key: 0,
|
|
388
|
-
src:
|
|
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,
|
|
393
|
-
i("div",
|
|
394
|
-
i("div",
|
|
395
|
-
i("span",
|
|
396
|
-
r.channel ? (
|
|
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",
|
|
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,
|
|
403
|
+
], 40, de))), 128))
|
|
402
404
|
])) : S("", !0)
|
|
403
405
|
], 4));
|
|
404
406
|
}
|
|
405
|
-
}),
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
427
|
+
}, Le = {
|
|
426
428
|
key: 5,
|
|
427
429
|
style: { position: "absolute", bottom: "8px", right: "8px", display: "flex", gap: "6px", "z-index": "11" }
|
|
428
|
-
},
|
|
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),
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
501
|
-
|
|
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
|
-
},
|
|
521
|
+
}, u.onerror = () => {
|
|
520
522
|
o.cancelled || l.value !== "error" && (a.value = "WebSocket error", l.value = "error", s("status-change", "error"));
|
|
521
|
-
},
|
|
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
|
|
526
|
-
const o = (
|
|
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
|
|
529
|
-
const e = String.fromCharCode(n[
|
|
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[
|
|
532
|
-
t !== void 0 && r !== void 0 &&
|
|
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
|
|
543
|
-
const e =
|
|
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
|
|
554
|
+
for (const u of o)
|
|
553
555
|
try {
|
|
554
|
-
n.sourceBuffer = n.mediaSource.addSourceBuffer(`video/mp4; codecs="${
|
|
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
|
|
565
|
+
for (const u of n.preBuffer)
|
|
564
566
|
try {
|
|
565
|
-
n.sourceBuffer.appendBuffer(
|
|
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 (
|
|
582
|
-
const
|
|
583
|
-
if (
|
|
584
|
-
|
|
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) <
|
|
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: ${
|
|
595
|
+
a.value = `appendBuffer failed: ${t.message}`, l.value = "error", U();
|
|
592
596
|
}
|
|
593
597
|
}
|
|
594
|
-
async function
|
|
595
|
-
if (
|
|
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:
|
|
608
|
+
mode: b.value,
|
|
605
609
|
profile: C.value
|
|
606
610
|
});
|
|
607
|
-
if (
|
|
611
|
+
if (b.value === "playback") {
|
|
608
612
|
let y = I.value;
|
|
609
613
|
y || (y = (/* @__PURE__ */ new Date()).toISOString(), I.value = y);
|
|
610
|
-
const
|
|
611
|
-
n.set("from", new Date(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 &&
|
|
632
|
+
C.value = C.value === "main" ? "sub" : "main", w.value && z();
|
|
629
633
|
}
|
|
630
|
-
function
|
|
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
|
|
635
|
-
|
|
636
|
-
}),
|
|
638
|
+
return J(() => {
|
|
639
|
+
R();
|
|
640
|
+
}), q(
|
|
637
641
|
() => [x.nvrId, x.channelId].join("|"),
|
|
638
642
|
() => {
|
|
639
|
-
w.value && x.nvrId && x.channelId &&
|
|
643
|
+
w.value && x.nvrId && x.channelId && z();
|
|
640
644
|
}
|
|
641
|
-
), (n, o) => (
|
|
645
|
+
), (n, o) => (f(), p("div", {
|
|
642
646
|
class: "rvms-video",
|
|
643
|
-
style:
|
|
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" ? (
|
|
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:
|
|
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" ? (
|
|
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",
|
|
687
|
-
])) : l.value === "error" ? (
|
|
688
|
-
i("span",
|
|
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:
|
|
695
|
+
onClick: z
|
|
692
696
|
}, " Retry ")
|
|
693
|
-
])) : l.value === "ended" ? (
|
|
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:
|
|
701
|
+
onClick: z
|
|
698
702
|
}, "Reconnect")
|
|
699
703
|
])) : S("", !0),
|
|
700
|
-
i("div",
|
|
704
|
+
i("div", we, [
|
|
701
705
|
i("button", {
|
|
702
706
|
class: "rvms-chip",
|
|
703
|
-
title: `Switch to ${
|
|
707
|
+
title: `Switch to ${b.value === "live" ? "playback" : "live"} mode`,
|
|
704
708
|
onClick: W,
|
|
705
|
-
style:
|
|
706
|
-
background:
|
|
709
|
+
style: Q({
|
|
710
|
+
background: b.value === "live" ? "#dc2626" : "#2563eb",
|
|
707
711
|
pointerEvents: "auto"
|
|
708
712
|
})
|
|
709
|
-
}, B(
|
|
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,
|
|
716
|
-
g.value ? (
|
|
717
|
-
|
|
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:
|
|
725
|
+
onInput: M,
|
|
722
726
|
class: "rvms-datetime",
|
|
723
727
|
title: "Playback timestamp",
|
|
724
728
|
style: { "pointer-events": "auto" }
|
|
725
|
-
}, null, 40,
|
|
726
|
-
|
|
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" ? (
|
|
732
|
+
l.value !== "idle" ? (f(), p("div", Ee, [
|
|
729
733
|
i("span", {
|
|
730
|
-
style:
|
|
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" ? (
|
|
742
|
-
w.value ? (
|
|
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:
|
|
747
|
-
}, " ⏹ Stop ")) : (
|
|
750
|
+
onClick: R
|
|
751
|
+
}, " ⏹ Stop ")) : (f(), p("button", {
|
|
748
752
|
key: 1,
|
|
749
753
|
class: "rvms-btn",
|
|
750
754
|
title: "Start stream",
|
|
751
|
-
onClick:
|
|
755
|
+
onClick: z
|
|
752
756
|
}, " ▶ Play "))
|
|
753
757
|
])) : S("", !0)
|
|
754
758
|
], 4));
|
|
755
759
|
}
|
|
756
|
-
}),
|
|
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
|
-
},
|
|
765
|
+
}, He = /* @__PURE__ */ ze(Oe, [["__scopeId", "data-v-650bbebf"]]);
|
|
762
766
|
export {
|
|
763
|
-
|
|
764
|
-
|
|
767
|
+
He as RvmsVideo,
|
|
768
|
+
Ue as RvmsVideoPlayer
|
|
765
769
|
};
|
package/dist/lib/style.css
CHANGED
|
@@ -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-
|
|
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
|
@@ -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);
|