node-red-contrib-hik-media-buffer 1.1.116 → 1.1.117
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/hik-media-buffer.js +22 -22
- package/package.json +1 -1
package/hik-media-buffer.js
CHANGED
|
@@ -112,7 +112,12 @@ module.exports = function(RED) {
|
|
|
112
112
|
|
|
113
113
|
const heartbeatInterval = setInterval(checkCameras, 30000);
|
|
114
114
|
|
|
115
|
-
// ---
|
|
115
|
+
// --- FORMATTATORE PER IL BODY DI RICERCA (Con i trattini: 2026-07-07T17:24:00Z) ---
|
|
116
|
+
function toHikSearchDate(d) {
|
|
117
|
+
return d.toISOString().split('.')[0] + "Z";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// --- DOWNLOAD CON ORARIO DINAMICO STRETTO SULL'ULTIMO EVENTO ---
|
|
116
121
|
async function downloadMedia(evento, channelID) {
|
|
117
122
|
const nowTime = Date.now();
|
|
118
123
|
if (!lastTriggerTime[channelID]) lastTriggerTime[channelID] = 0;
|
|
@@ -124,13 +129,15 @@ module.exports = function(RED) {
|
|
|
124
129
|
const timestamp = Math.floor(referenceTime.getTime() / 1000);
|
|
125
130
|
|
|
126
131
|
const videoTrackID = (parseInt(channelID) * 100) + 1;
|
|
127
|
-
|
|
128
|
-
// Recupera il nome reale prima di inviare l'allarme
|
|
129
132
|
const nomeCamera = await getCameraNameFromNVR(channelID);
|
|
130
133
|
node.status({fill:"yellow", shape:"dot", text:`Download Cam ${channelID}...`});
|
|
131
134
|
|
|
132
|
-
|
|
133
|
-
const
|
|
135
|
+
// FINESTRA TEMPORALE REALE: Cerchiamo l'evento da 2 minuti fa a 1 minuto nel futuro
|
|
136
|
+
const inizioFinestra = new Date(referenceTime.getTime() - (2 * 60 * 1000));
|
|
137
|
+
const fineFinestra = new Date(referenceTime.getTime() + (1 * 60 * 1000));
|
|
138
|
+
|
|
139
|
+
const startSearchStr = toHikSearchDate(inizioFinestra);
|
|
140
|
+
const endSearchStr = toHikSearchDate(fineFinestra);
|
|
134
141
|
|
|
135
142
|
let output = {
|
|
136
143
|
tipo_messaggio: "evento",
|
|
@@ -148,16 +155,13 @@ module.exports = function(RED) {
|
|
|
148
155
|
let fileDaCancellare = [];
|
|
149
156
|
|
|
150
157
|
try {
|
|
151
|
-
// 1. SCARICAMENTO IMMAGINE
|
|
158
|
+
// 1. 📸 RICERCA E SCARICAMENTO IMMAGINE (Formato con i trattini nel body)
|
|
152
159
|
const payloadFoto = {
|
|
153
160
|
"EventSearchDescription": {
|
|
154
161
|
"searchID": "C5AFEE35-B1E0-4C01-83F8-47FD77892E4A",
|
|
155
162
|
"searchResultPosition": 0,
|
|
156
|
-
"maxResults":
|
|
157
|
-
"timeSpanList": [{
|
|
158
|
-
"startTime": startSearchStr,
|
|
159
|
-
"endTime": endSearchStr
|
|
160
|
-
}],
|
|
163
|
+
"maxResults": 1, // Prendiamo solo il più vicino all'evento attuale
|
|
164
|
+
"timeSpanList": [{ "startTime": startSearchStr, "endTime": endSearchStr }],
|
|
161
165
|
"type": "all",
|
|
162
166
|
"channels": [parseInt(channelID)],
|
|
163
167
|
"eventType": "behavior",
|
|
@@ -189,21 +193,18 @@ module.exports = function(RED) {
|
|
|
189
193
|
fileDaCancellare.push(fullImgPath);
|
|
190
194
|
}
|
|
191
195
|
|
|
192
|
-
// 2. SCARICAMENTO VIDEO
|
|
193
|
-
const startVideoSearch = referenceTime.toISOString().split('T')[0] + "T00:00:00Z";
|
|
194
|
-
const endVideoSearch = referenceTime.toISOString().split('T')[0] + "T23:59:59Z";
|
|
195
|
-
|
|
196
|
+
// 2. 🎥 RICERCA E SCARICAMENTO VIDEO (Formato con i trattini nel body)
|
|
196
197
|
const payloadVideoSearch = `<?xml version="1.0" encoding="utf-8"?>
|
|
197
198
|
<CMSearchDescription>
|
|
198
199
|
<searchID>CEC13F0F-1AEA-4474-A2DA-CFFF332C7C5B</searchID>
|
|
199
200
|
<trackList><trackID>${videoTrackID}</trackID></trackList>
|
|
200
201
|
<timeSpanList>
|
|
201
202
|
<timeSpan>
|
|
202
|
-
<startTime>${
|
|
203
|
-
<endTime>${
|
|
203
|
+
<startTime>${startSearchStr}</startTime>
|
|
204
|
+
<endTime>${endSearchStr}</endTime>
|
|
204
205
|
</timeSpan>
|
|
205
206
|
</timeSpanList>
|
|
206
|
-
<maxResults>
|
|
207
|
+
<maxResults>1</maxResults>
|
|
207
208
|
<searchResultPostion>0</searchResultPostion>
|
|
208
209
|
<metadataList><metadataDescriptor>//recordType.meta.std-cgi.com</metadataDescriptor></metadataList>
|
|
209
210
|
</CMSearchDescription>`;
|
|
@@ -220,8 +221,10 @@ module.exports = function(RED) {
|
|
|
220
221
|
const uriMatch = xmlString.match(/<playbackURI>([\s\S]*?)<\/playbackURI>/i);
|
|
221
222
|
|
|
222
223
|
if (uriMatch && uriMatch[1]) {
|
|
224
|
+
// Estrae il playbackURI grezzo che contiene GIÀ la data compressa senza trattini generata dall'NVR
|
|
223
225
|
const playbackURIGrezzo = uriMatch[1].trim();
|
|
224
226
|
|
|
227
|
+
// Inviamo il downloadRequest passando l'URI nativo fornito dall'NVR (che rispetta il formato compresso)
|
|
225
228
|
const payloadDownload = `<?xml version="1.0" encoding="UTF-8"?>
|
|
226
229
|
<downloadRequest>
|
|
227
230
|
<playbackURI>${playbackURIGrezzo}</playbackURI>
|
|
@@ -259,12 +262,9 @@ module.exports = function(RED) {
|
|
|
259
262
|
|
|
260
263
|
if (output.foto_base64 || output.video_base64) {
|
|
261
264
|
node.send({ payload: output });
|
|
262
|
-
|
|
263
265
|
setTimeout(() => {
|
|
264
266
|
for (let file of fileDaCancellare) {
|
|
265
|
-
try {
|
|
266
|
-
if (fs.existsSync(file)) fs.unlinkSync(file);
|
|
267
|
-
} catch (err) {}
|
|
267
|
+
try { if (fs.existsSync(file)) fs.unlinkSync(file); } catch (err) {}
|
|
268
268
|
}
|
|
269
269
|
}, 120000);
|
|
270
270
|
}
|