node-red-contrib-hik-media-buffer 1.2.6 → 1.2.8
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-download.js +64 -27
- package/hik-media-buffer.js +1 -1
- package/package.json +1 -1
package/hik-download.js
CHANGED
|
@@ -62,25 +62,45 @@ module.exports = function(RED) {
|
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
d
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
// 🌟 1. FORMATTAZIONE DELLE DATE IN BASE ALLA PORTA (Bivio Logico)
|
|
66
|
+
let startTimeNVR, endTimeNVR, playbackURIGrezzo, payloadDownload;
|
|
67
|
+
|
|
68
|
+
const isPort85 = (port.toString() === "85");
|
|
69
|
+
|
|
70
|
+
if (isPort85) {
|
|
71
|
+
// Formato specifico DVR Porta 85: AAAA-MM-GGTHH:MM:SS (Senza Z, con trattini e due punti)
|
|
72
|
+
const formattaDataDVR = (dataStr) => {
|
|
73
|
+
let d = dataStr.replace(' ', 'T').split('.')[0].replace('Z', '');
|
|
74
|
+
if (d.includes('T') && d.split('T')[1].length === 5) {
|
|
75
|
+
d += ':00';
|
|
76
|
+
}
|
|
77
|
+
return d;
|
|
78
|
+
};
|
|
79
|
+
startTimeNVR = formattaDataDVR(startTimeRaw);
|
|
80
|
+
endTimeNVR = formattaDataDVR(endTimeRaw);
|
|
81
|
+
|
|
82
|
+
// RTSP con porta e XML senza namespace
|
|
83
|
+
const trackId = targetChannels[0] + "01"; // Default temporaneo per comporre l'URI prima del ciclo
|
|
84
|
+
playbackURIGrezzo = `rtsp://${host}:${port}/Streaming/tracks/TRACK_PLACEHOLDER/?starttime=${startTimeNVR}&endtime=${endTimeNVR}`;
|
|
85
|
+
} else {
|
|
86
|
+
// Formato classico NVR (Senza trattini e senza due punti)
|
|
87
|
+
const pulisciDataNVR = (dataStr) => {
|
|
88
|
+
let d = dataStr.replace(' ', 'T').replace(/[-:]/g, '').split('.')[0].replace('Z', '');
|
|
89
|
+
if (d.includes('T') && d.split('T')[1].length === 4) {
|
|
90
|
+
d += '00';
|
|
91
|
+
}
|
|
92
|
+
return d;
|
|
93
|
+
};
|
|
94
|
+
startTimeNVR = pulisciDataNVR(startTimeRaw);
|
|
95
|
+
endTimeNVR = pulisciDataNVR(endTimeRaw);
|
|
77
96
|
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
// RTSP senza porta
|
|
98
|
+
playbackURIGrezzo = `rtsp://${host}/Streaming/tracks/TRACK_PLACEHOLDER/?starttime=${startTimeNVR}&endtime=${endTimeNVR}`;
|
|
99
|
+
}
|
|
80
100
|
|
|
81
|
-
// Creazione cartella C:\download\YYYY-MM-DD
|
|
101
|
+
// Creazione cartella di salvataggio C:\download\YYYY-MM-DD
|
|
82
102
|
const dataGiorno = startTimeRaw.substring(0, 10).replace(/\//g, '-');
|
|
83
|
-
const baseDir = "C:\\download";
|
|
103
|
+
const baseDir = process.platform === "win32" ? "C:\\download" : "/home/allsystem/download";
|
|
84
104
|
const targetDir = path.join(baseDir, dataGiorno);
|
|
85
105
|
|
|
86
106
|
try {
|
|
@@ -95,6 +115,7 @@ module.exports = function(RED) {
|
|
|
95
115
|
|
|
96
116
|
const digest = new DigestAuthClass({ username: user, password: pass });
|
|
97
117
|
|
|
118
|
+
// 🌟 2. CICLO DI DOWNLOAD
|
|
98
119
|
for (let index = 0; index < targetChannels.length; index++) {
|
|
99
120
|
const ch = targetChannels[index];
|
|
100
121
|
const trackId = ch + "01";
|
|
@@ -105,17 +126,24 @@ module.exports = function(RED) {
|
|
|
105
126
|
text: `Download Ch ${ch} (${index + 1}/${targetChannels.length})...`
|
|
106
127
|
});
|
|
107
128
|
|
|
108
|
-
//
|
|
109
|
-
const
|
|
110
|
-
const playbackURIXml =
|
|
129
|
+
// Sostituiamo il placeholder con la traccia corrente del ciclo
|
|
130
|
+
const uriCorrente = playbackURIGrezzo.replace('TRACK_PLACEHOLDER', trackId);
|
|
131
|
+
const playbackURIXml = uriCorrente.replace(/&/g, '&');
|
|
111
132
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
133
|
+
// Costruiamo l'XML a seconda del tipo di macchina
|
|
134
|
+
if (isPort85) {
|
|
135
|
+
payloadDownload = `<?xml version="1.0" encoding="UTF-8"?>
|
|
136
|
+
<downloadRequest>
|
|
137
|
+
<playbackURI>${playbackURIXml}</playbackURI>
|
|
138
|
+
</downloadRequest>`;
|
|
139
|
+
} else {
|
|
140
|
+
payloadDownload = `<?xml version="1.0" encoding="UTF-8"?>
|
|
141
|
+
<downloadRequest version="1.0" xmlns="http://www.isapi.org/ver20/XMLSchema">
|
|
142
|
+
<playbackURI>${playbackURIXml}</playbackURI>
|
|
143
|
+
</downloadRequest>`;
|
|
144
|
+
}
|
|
116
145
|
|
|
117
146
|
try {
|
|
118
|
-
// 🌟 2. GET DI DOWNLOAD CON PAYLOAD XML E RESPONSE 'STREAM'
|
|
119
147
|
const response = await digest.request({
|
|
120
148
|
method: 'GET',
|
|
121
149
|
url: `${protocol}://${host}:${port}/ISAPI/ContentMgmt/download`,
|
|
@@ -130,11 +158,17 @@ module.exports = function(RED) {
|
|
|
130
158
|
if (response.status === 200 || response.status === 206) {
|
|
131
159
|
const nomeCondominio = (msg.nvr_name || node.name || 'NVR').replace(/[^a-zA-Z0-9]/g, '_');
|
|
132
160
|
const oraInizio = startTimeNVR.split('T')[1] || startTimeNVR;
|
|
133
|
-
const finalFileName = `${nomeCondominio}_Cam${ch}_${oraInizio}.mp4`;
|
|
161
|
+
const finalFileName = `${nomeCondominio}_Cam${ch}_${oraInizio.replace(/:/g, '')}.mp4`;
|
|
134
162
|
const finalFilePath = path.join(targetDir, finalFileName);
|
|
135
163
|
|
|
136
|
-
// 🌟 3. SALVATAGGIO TRAMITE STREAM (Ottimizzato per file grandi)
|
|
137
164
|
const writer = fs.createWriteStream(finalFilePath);
|
|
165
|
+
const videoChunks = [];
|
|
166
|
+
|
|
167
|
+
// Ascoltiamo i dati in arrivo dallo stream per salvarli anche in memoria
|
|
168
|
+
response.data.on('data', (chunk) => {
|
|
169
|
+
videoChunks.push(chunk);
|
|
170
|
+
});
|
|
171
|
+
|
|
138
172
|
response.data.pipe(writer);
|
|
139
173
|
|
|
140
174
|
await new Promise((resolve, reject) => {
|
|
@@ -147,8 +181,11 @@ module.exports = function(RED) {
|
|
|
147
181
|
|
|
148
182
|
node.log(`File salvato in: ${finalFilePath}`);
|
|
149
183
|
|
|
184
|
+
const videoBuffer = Buffer.concat(videoChunks);
|
|
185
|
+
|
|
150
186
|
let outMsg = RED.util.cloneMessage(msg);
|
|
151
|
-
outMsg.payload =
|
|
187
|
+
outMsg.payload = videoBuffer;
|
|
188
|
+
outMsg.localFilePath = finalFilePath;
|
|
152
189
|
outMsg.channel = ch;
|
|
153
190
|
outMsg.filename = finalFileName;
|
|
154
191
|
node.send(outMsg);
|
package/hik-media-buffer.js
CHANGED
|
@@ -213,7 +213,7 @@ module.exports = function(RED) {
|
|
|
213
213
|
|
|
214
214
|
playbackURIGrezzo = `rtsp://${node.host}:${node.port}/Streaming/tracks/${videoTrackID}/?starttime=${startClip}&endtime=${endClip}`;
|
|
215
215
|
}
|
|
216
|
-
}
|
|
216
|
+
}hik
|
|
217
217
|
|
|
218
218
|
// 3. 💾 EFFETTUIAMO LA GET DI DOWNLOAD SE ABBIAMO GENERATO L'URI
|
|
219
219
|
if (playbackURIGrezzo) {
|