node-red-contrib-hik-media-buffer 1.1.139 → 1.1.141

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.
@@ -126,8 +126,8 @@ module.exports = function(RED) {
126
126
  if (nowTime - lastTriggerTime[channelID] < 5000) return;
127
127
  lastTriggerTime[channelID] = nowTime;
128
128
 
129
- node.status({fill:"yellow", shape:"dot", text:`Attesa (6s)...`});
130
- await new Promise(resolve => setTimeout(resolve, 6000));
129
+ node.status({fill:"yellow", shape:"dot", text:`Attesa (10s)...`});
130
+ await new Promise(resolve => setTimeout(resolve, 10000));
131
131
 
132
132
  const nvrAuth = new AxiosDigestAuth({ username: node.user, password: node.pass });
133
133
  const referenceTime = new Date();
@@ -216,7 +216,6 @@ module.exports = function(RED) {
216
216
  }
217
217
 
218
218
  // 3. 💾 EFFETTUIAMO LA GET DI DOWNLOAD SE ABBIAMO GENERATO L'URI
219
- // 3. 💾 EFFETTUIAMO LA GET DI DOWNLOAD CON VALUTAZIONE STREAM (Evita i Parse Error)
220
219
  if (playbackURIGrezzo) {
221
220
  const playbackURIXml = playbackURIGrezzo.replace(/&/g, '&amp;');
222
221
 
@@ -241,23 +240,39 @@ module.exports = function(RED) {
241
240
  const rawPath = path.join(baseStorage, `raw_${timestamp}_ch${channelID}.mp4`);
242
241
  const fixedPath = path.join(baseStorage, `hik_v_${channelID}_${timestamp}.mp4`);
243
242
 
244
- // Usiamo un WriteStream per salvare i byte man mano che arrivano dalla rete
245
243
  const writer = fs.createWriteStream(rawPath);
244
+
246
245
  resDownVideo.data.pipe(writer);
247
246
 
247
+ // 🌟 BLOCCO DI SICUREZZA: Aspettiamo la reale chiusura del flusso di rete dell'NVR
248
248
  await new Promise((resolve, reject) => {
249
- writer.on('finish', resolve);
250
- writer.on('error', reject);
249
+ resDownVideo.data.on('end', () => {
250
+ setTimeout(() => {
251
+ writer.end();
252
+ resolve();
253
+ }, 500);
254
+ });
255
+
256
+ resDownVideo.data.on('error', (err) => {
257
+ writer.end();
258
+ reject(err);
259
+ });
260
+
261
+ writer.on('error', (err) => {
262
+ reject(err);
263
+ });
251
264
  });
252
265
 
253
- // Una volta finito di scrivere il file grezzo, controlliamo la testata IMKH e passiamo a FFMPEG
266
+ // Leggiamo il file finale completo per controllare la testata IMKH
254
267
  let videoBuffer = fs.readFileSync(rawPath);
255
268
  if (videoBuffer.slice(0, 4).toString() === 'IMKH') {
256
- // Rimuoviamo i 40 byte di intestazione proprietaria Hikvision se presenti
257
269
  videoBuffer = videoBuffer.slice(40);
258
270
  fs.writeFileSync(rawPath, videoBuffer);
259
271
  }
260
272
 
273
+ const stats = fs.statSync(rawPath);
274
+ node.warn(`[HIK DOWNLOAD OK] File scaricato. Dimensione: ${(stats.size / 1024).toFixed(1)} KB`);
275
+
261
276
  await new Promise((resolve) => {
262
277
  exec(`ffmpeg -y -i "${rawPath}" -c copy -movflags +faststart "${fixedPath}"`, (err) => {
263
278
  if (!err && fs.existsSync(fixedPath)) {
@@ -271,7 +286,7 @@ module.exports = function(RED) {
271
286
  });
272
287
  });
273
288
  }
274
-
289
+
275
290
  if (output.foto_base64 || output.video_base64) {
276
291
  node.send({ payload: output });
277
292
  setTimeout(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-hik-media-buffer",
3
- "version": "1.1.139",
3
+ "version": "1.1.141",
4
4
  "description": "Ottiene buffer video e immagine da camere Hikvision via ISAPI",
5
5
  "keywords": [
6
6
  "node-red",