Use Old ONVIF Scanner
parent
384752a422
commit
0c5485409d
|
@ -6625,75 +6625,79 @@ module.exports = function(s,config,lang){
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ONVIF Scanner": {
|
"ONVIF Scanner": {
|
||||||
"section": "ONVIF Scanner",
|
"section": "ONVIF Scanner",
|
||||||
"blocks": {
|
"blocks": {
|
||||||
"Search Settings": {
|
"Search Settings": {
|
||||||
"name": lang["Scan Settings"],
|
"name": lang["Scan Settings"],
|
||||||
"color": "navy",
|
"color": "navy",
|
||||||
"blockquote": lang.ONVIFnote,
|
"blockquote": lang.ONVIFnote,
|
||||||
"section-pre-class": "col-md-4",
|
"section-pre-class": "col-md-4",
|
||||||
"info": [
|
"info": [
|
||||||
{
|
{
|
||||||
"name": "ip",
|
"name": "ip",
|
||||||
"field": lang['IP Address'],
|
"field": lang['IP Address'],
|
||||||
"description": lang.fieldTextIp,
|
"description": lang[lang["fieldTextIp"]],
|
||||||
"example": "10.1.100.1-10.1.100.254",
|
"example": "10.1.100.1-10.1.100.254",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "port",
|
"name": "port",
|
||||||
"field": lang['Port'],
|
"field": lang['Port'],
|
||||||
"description": lang.separateByCommasOrRange,
|
"description": lang.separateByCommasOrRange,
|
||||||
"example": "80,7575,8000,8080,8081",
|
"example": "80,7575,8000,8080,8081",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "user",
|
"name": "user",
|
||||||
"field": lang['Camera Username'],
|
"field": lang['Camera Username'],
|
||||||
"description": lang.fieldTextOnvifScanCameraUsername,
|
"placeholder": "Can be left blank.",
|
||||||
"placeholder": "Can be left blank.",
|
},
|
||||||
},
|
{
|
||||||
{
|
"name": "pass",
|
||||||
"name": "pass",
|
"field": lang['Camera Password'],
|
||||||
"field": lang['Camera Password'],
|
"fieldType": "password",
|
||||||
"description": lang.fieldTextOnvifScanCameraPassword,
|
},
|
||||||
"fieldType": "password",
|
{
|
||||||
},
|
"fieldType": "btn-group",
|
||||||
{
|
"btns": [
|
||||||
"fieldType": "btn-group",
|
{
|
||||||
"btns": [
|
"fieldType": "btn",
|
||||||
{
|
"forForm": true,
|
||||||
"fieldType": "btn",
|
"class": `btn-block btn-success`,
|
||||||
"forForm": true,
|
"btnContent": `${lang['Search']}<span class="_loading" style="display:none"> <i class="fa fa-pulse fa-spinner"></i></span>`,
|
||||||
"class": `btn-success start-scan`,
|
},
|
||||||
"btnContent": `${lang['Search']}`,
|
{
|
||||||
},
|
"fieldType": "btn",
|
||||||
{
|
"class": `btn-default add-all`,
|
||||||
"fieldType": "btn",
|
"btnContent": `${lang['Add All']}`,
|
||||||
"class": `btn-danger stop-scan d-none`,
|
},
|
||||||
"btnContent": `${lang['Stop']}`,
|
],
|
||||||
},
|
},
|
||||||
{
|
]
|
||||||
"fieldType": "btn",
|
},
|
||||||
"class": `btn-default add-all`,
|
"Found Devices": {
|
||||||
"btnContent": `${lang['Add All']}`,
|
"name": lang['Found Devices'],
|
||||||
},
|
"color": "blue",
|
||||||
],
|
"section-pre-class": "col-md-8",
|
||||||
},
|
"info": [
|
||||||
|
{
|
||||||
|
"fieldType": "div",
|
||||||
|
"class": "onvif_result row",
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"Found Devices": {
|
"Other Devices": {
|
||||||
"name": lang['Found Devices'],
|
"name": lang['Other Devices'],
|
||||||
"color": "blue",
|
"color": "danger",
|
||||||
"section-pre-class": "col-md-8",
|
"section-pre-class": "col-md-12",
|
||||||
"info": [
|
"info": [
|
||||||
{
|
{
|
||||||
"fieldType": "div",
|
"fieldType": "div",
|
||||||
"class": "onvif_result row",
|
"class": "onvif_result_error row",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Camera Probe": {
|
"Camera Probe": {
|
||||||
"section": "Camera Probe",
|
"section": "Camera Probe",
|
||||||
"blocks": {
|
"blocks": {
|
||||||
|
|
|
@ -1,34 +1,16 @@
|
||||||
module.exports = function(s,config,lang,app,io){
|
module.exports = function(s,config,lang,app,io){
|
||||||
const {
|
|
||||||
scanStatus,
|
|
||||||
runOnvifScanner,
|
|
||||||
stopOnvifScanner,
|
|
||||||
} = require('./scanners/utils.js')(s,config,lang)
|
|
||||||
const {
|
const {
|
||||||
ffprobe,
|
ffprobe,
|
||||||
} = require('./ffmpeg/utils.js')(s,config,lang)
|
} = require('./ffmpeg/utils.js')(s,config,lang)
|
||||||
|
const {
|
||||||
|
runOnvifScanner,
|
||||||
|
} = require('./scanners/utils.js')(s,config,lang)
|
||||||
const onWebSocketConnection = async (cn) => {
|
const onWebSocketConnection = async (cn) => {
|
||||||
const tx = function(z){if(!z.ke){z.ke=cn.ke;};cn.emit('f',z);}
|
const tx = function(z){if(!z.ke){z.ke=cn.ke;};cn.emit('f',z);}
|
||||||
cn.on('f',(d) => {
|
cn.on('f',(d) => {
|
||||||
switch(d.f){
|
switch(d.f){
|
||||||
case'onvif_scan_reconnect':
|
|
||||||
tx({f: 'onvif_scan_current', devices: Object.values(scanStatus.allSuccessful), isScanning: scanStatus.isActive})
|
|
||||||
break;
|
|
||||||
case'onvif_stop':
|
|
||||||
stopOnvifScanner()
|
|
||||||
tx({f: 'onvif_scan_stopped'})
|
|
||||||
break;
|
|
||||||
case'onvif':
|
case'onvif':
|
||||||
const groupKey = `${cn.ke}`
|
runOnvifScanner(d,tx)
|
||||||
runOnvifScanner(d, (data) => {
|
|
||||||
const response = { f: 'onvif', ...data }
|
|
||||||
s.tx(response, 'GRP_' + cn.ke)
|
|
||||||
}, (data) => {
|
|
||||||
const response = { f: 'onvif', ff: 'failed_capture', ...data }
|
|
||||||
s.tx(response, 'GRP_' + cn.ke)
|
|
||||||
}).then((responseList) => {
|
|
||||||
s.tx({ f: 'onvif_scan_complete' }, 'GRP_' + cn.ke)
|
|
||||||
})
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -58,60 +40,4 @@ module.exports = function(s,config,lang,app,io){
|
||||||
})
|
})
|
||||||
},res,req);
|
},res,req);
|
||||||
})
|
})
|
||||||
/**
|
|
||||||
* API : ONVIF Scanner RUN
|
|
||||||
*/
|
|
||||||
app.get(config.webPaths.apiPrefix+':auth/onvifScanner/:ke/scan',function (req,res){
|
|
||||||
s.auth(req.params,function(user){
|
|
||||||
const {
|
|
||||||
isRestricted,
|
|
||||||
isRestrictedApiKey,
|
|
||||||
apiKeyPermissions,
|
|
||||||
} = s.checkPermission(user);
|
|
||||||
if(
|
|
||||||
isRestrictedApiKey && apiKeyPermissions.control_monitors_disallowed
|
|
||||||
){
|
|
||||||
s.closeJsonResponse(res,{
|
|
||||||
ok: false,
|
|
||||||
msg: lang['Not Authorized']
|
|
||||||
});
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const groupKey = req.params.ke;
|
|
||||||
stopOnvifScanner()
|
|
||||||
s.closeJsonResponse(res, { ok: true });
|
|
||||||
},res,req);
|
|
||||||
})
|
|
||||||
/**
|
|
||||||
* API : ONVIF Scanner STOP
|
|
||||||
*/
|
|
||||||
app.get(config.webPaths.apiPrefix+':auth/onvifScanner/:ke/scan/stop',function (req,res){
|
|
||||||
s.auth(req.params,function(user){
|
|
||||||
const {
|
|
||||||
isRestricted,
|
|
||||||
isRestrictedApiKey,
|
|
||||||
apiKeyPermissions,
|
|
||||||
} = s.checkPermission(user);
|
|
||||||
if(
|
|
||||||
isRestrictedApiKey && apiKeyPermissions.control_monitors_disallowed
|
|
||||||
){
|
|
||||||
s.closeJsonResponse(res,{
|
|
||||||
ok: false,
|
|
||||||
msg: lang['Not Authorized']
|
|
||||||
});
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const groupKey = req.params.ke;
|
|
||||||
runOnvifScanner(d, (data) => {
|
|
||||||
const response = { f: 'onvif', ...data }
|
|
||||||
s.tx(response, 'GRP_' + groupKey)
|
|
||||||
}, (data) => {
|
|
||||||
const response = { f: 'onvif', ff: 'failed_capture', ...data }
|
|
||||||
s.tx(response, 'GRP_' + groupKey)
|
|
||||||
}).then((responseList) => {
|
|
||||||
s.tx({ f: 'onvif_scan_complete' }, 'GRP_' + groupKey)
|
|
||||||
s.closeJsonResponse(res, responseList)
|
|
||||||
})
|
|
||||||
},res,req);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,381 +1,202 @@
|
||||||
var os = require('os');
|
var os = require('os');
|
||||||
const async = require('async');
|
|
||||||
const onvif = require("shinobi-onvif");
|
const onvif = require("shinobi-onvif");
|
||||||
const {
|
const {
|
||||||
addCredentialsToUrl,
|
addCredentialsToUrl,
|
||||||
stringContains,
|
stringContains,
|
||||||
getBuffer,
|
getBuffer,
|
||||||
} = require('../common.js')
|
} = require('../common.js')
|
||||||
const scanStatus = {
|
|
||||||
current: [],
|
|
||||||
allSuccessful: {},
|
|
||||||
cancelPromises: null,
|
|
||||||
abortController: null
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = (s,config,lang) => {
|
module.exports = (s,config,lang) => {
|
||||||
const ipRange = (start_ip, end_ip) => {
|
const ipRange = (start_ip, end_ip) => {
|
||||||
const startLong = toLong(start_ip);
|
var startLong = toLong(start_ip);
|
||||||
const endLong = toLong(end_ip);
|
var endLong = toLong(end_ip);
|
||||||
if (startLong > endLong) {
|
if (startLong > endLong) {
|
||||||
const tmp = startLong;
|
var tmp = startLong;
|
||||||
startLong = endLong;
|
startLong = endLong
|
||||||
endLong = tmp;
|
endLong = tmp;
|
||||||
}
|
}
|
||||||
const rangeArray = [];
|
var rangeArray = [];
|
||||||
for (let i = startLong; i <= endLong; i++) {
|
var i;
|
||||||
rangeArray.push(fromLong(i));
|
for (i = startLong; i <= endLong; i++) {
|
||||||
}
|
rangeArray.push(fromLong(i));
|
||||||
return rangeArray;
|
}
|
||||||
};
|
return rangeArray;
|
||||||
|
}
|
||||||
const portRange = (lowEnd, highEnd) => {
|
const portRange = (lowEnd,highEnd) => {
|
||||||
const list = [];
|
var list = [];
|
||||||
for (let i = lowEnd; i <= highEnd; i++) {
|
for (var i = lowEnd; i <= highEnd; i++) {
|
||||||
list.push(i);
|
list.push(i);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
};
|
}
|
||||||
|
//toLong taken from NPM package 'ip'
|
||||||
const toLong = (ip) => {
|
const toLong = (ip) => {
|
||||||
let ipl = 0;
|
var ipl = 0;
|
||||||
ip.split('.').forEach(function(octet) {
|
ip.split('.').forEach(function(octet) {
|
||||||
ipl <<= 8;
|
ipl <<= 8;
|
||||||
ipl += parseInt(octet);
|
ipl += parseInt(octet);
|
||||||
});
|
});
|
||||||
return (ipl >>> 0);
|
return(ipl >>> 0);
|
||||||
};
|
}
|
||||||
|
//fromLong taken from NPM package 'ip'
|
||||||
const fromLong = (ipl) => {
|
const fromLong = (ipl) => {
|
||||||
return ((ipl >>> 24) + '.' +
|
return ((ipl >>> 24) + '.' +
|
||||||
(ipl >> 16 & 255) + '.' +
|
(ipl >> 16 & 255) + '.' +
|
||||||
(ipl >> 8 & 255) + '.' +
|
(ipl >> 8 & 255) + '.' +
|
||||||
(ipl & 255));
|
(ipl & 255) );
|
||||||
};
|
|
||||||
|
|
||||||
const getNetworkAddresses = () => {
|
|
||||||
const interfaces = os.networkInterfaces();
|
|
||||||
const addresses = [];
|
|
||||||
for (const k in interfaces) {
|
|
||||||
for (const k2 in interfaces[k]) {
|
|
||||||
const address = interfaces[k][k2];
|
|
||||||
if (address.family === 'IPv4' && !address.internal) {
|
|
||||||
addresses.push(address.address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return addresses;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAddressRange = (addresses) => {
|
|
||||||
const addressRange = [];
|
|
||||||
addresses.forEach((address) => {
|
|
||||||
if (address.indexOf('0.0.0') > -1) return;
|
|
||||||
const addressPrefix = address.split('.').slice(0, 3).join('.');
|
|
||||||
addressRange.push(`${addressPrefix}.1-${addressPrefix}.254`);
|
|
||||||
});
|
|
||||||
return addressRange.join(',');
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPorts = (ports) => {
|
|
||||||
if (ports === '') {
|
|
||||||
return '80,8080,8000,7575,8081,9080,8090,8999,8899'.split(',');
|
|
||||||
}
|
|
||||||
if (ports.indexOf('-') > -1) {
|
|
||||||
const [start, end] = ports.split('-');
|
|
||||||
return portRange(start, end);
|
|
||||||
}
|
|
||||||
return ports.split(',');
|
|
||||||
};
|
|
||||||
|
|
||||||
const getIpList = (ip) => {
|
|
||||||
const ipList = [];
|
|
||||||
ip.split(',').forEach((range) => {
|
|
||||||
const [start, end] = range.indexOf('-') > -1 ? range.split('-') : [range, range];
|
|
||||||
ipList.push(...ipRange(start, end));
|
|
||||||
});
|
|
||||||
return ipList;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createHitList = (ipList, ports, onvifUsername = '', onvifPassword = '') => {
|
|
||||||
const hitList = [];
|
|
||||||
const usernameVariants = onvifUsername.split(',');
|
|
||||||
const passwordVariants = onvifPassword.split(',');
|
|
||||||
for (const username of usernameVariants) {
|
|
||||||
for (const password of passwordVariants) {
|
|
||||||
hitList.push(...ipList.flatMap((ipEntry) =>
|
|
||||||
ports.map((portEntry) => ({
|
|
||||||
xaddr: `http://${ipEntry}:${portEntry}/onvif/device_service`,
|
|
||||||
user: username,
|
|
||||||
pass: password,
|
|
||||||
ip: ipEntry,
|
|
||||||
port: portEntry,
|
|
||||||
}))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hitList;
|
|
||||||
};
|
|
||||||
|
|
||||||
const takeSnapshot = async (cameraResponse, device) => {
|
|
||||||
try {
|
|
||||||
const snapUri = addCredentialsToUrl({
|
|
||||||
username: cameraResponse.user,
|
|
||||||
password: cameraResponse.pass,
|
|
||||||
url: (await device.services.media.getSnapshotUri({ ProfileToken: device.current_profile.token })).data.GetSnapshotUriResponse.MediaUri.Uri,
|
|
||||||
});
|
|
||||||
const imgBuffer = await getBuffer(snapUri);
|
|
||||||
cameraResponse.snapShot = imgBuffer.toString('base64');
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to get snapshot via ONVIF:', err);
|
|
||||||
}
|
|
||||||
return cameraResponse;
|
|
||||||
}
|
}
|
||||||
|
const runOnvifScanner = (options,foundCameraCallback) => {
|
||||||
const fetchCameraDetails = async (camera, onvifUsername, onvifPassword, foundCameraCallback, failedCameraCallback) => {
|
var ip = options.ip.replace(/ /g,'')
|
||||||
// const previousSuccess = scanStatus.allSuccessful[camera.ip];
|
var ports = options.port.replace(/ /g,'')
|
||||||
// if (previousSuccess) {
|
if(options.ip === ''){
|
||||||
// // console.log('FOUND PREVIOUS', camera.ip);
|
var interfaces = os.networkInterfaces()
|
||||||
// foundCameraCallback(previousSuccess);
|
var addresses = []
|
||||||
// return;
|
for (var k in interfaces) {
|
||||||
// }
|
for (var k2 in interfaces[k]) {
|
||||||
try {
|
var address = interfaces[k][k2]
|
||||||
const device = new onvif.OnvifDevice(camera);
|
if (address.family === 'IPv4' && !address.internal) {
|
||||||
const info = await device.init();
|
addresses.push(address.address)
|
||||||
const stream = await device.services.media.getStreamUri({
|
|
||||||
ProfileToken: device.current_profile.token,
|
|
||||||
Protocol: 'RTSP'
|
|
||||||
});
|
|
||||||
|
|
||||||
const cameraResponse = {
|
|
||||||
ip: camera.ip,
|
|
||||||
port: camera.port,
|
|
||||||
user: camera.user,
|
|
||||||
pass: camera.pass,
|
|
||||||
info: info,
|
|
||||||
uri: stream.data.GetStreamUriResponse.MediaUri.Uri
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const camPtzConfigs = (await device.services.ptz.getConfigurations()).data.GetConfigurationsResponse;
|
|
||||||
if (camPtzConfigs.PTZConfiguration && (camPtzConfigs.PTZConfiguration.PanTiltLimits || camPtzConfigs.PTZConfiguration.ZoomLimits)) {
|
|
||||||
cameraResponse.isPTZ = true;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(er)
|
|
||||||
// s.debugLog(err);
|
|
||||||
}
|
|
||||||
await takeSnapshot(cameraResponse, device)
|
|
||||||
scanStatus.allSuccessful[camera.ip] = cameraResponse;
|
|
||||||
foundCameraCallback(cameraResponse);
|
|
||||||
|
|
||||||
return cameraResponse;
|
|
||||||
} catch (err) {
|
|
||||||
return handleCameraError(camera, err, failedCameraCallback);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCameraError = (camera, err, failedCameraCallback) => {
|
|
||||||
// const previousSuccess = scanStatus.allSuccessful[camera.ip];
|
|
||||||
// if (previousSuccess) {
|
|
||||||
// // console.log('FOUND PREVIOUS AFTER ERROR', camera.ip);
|
|
||||||
// return previousSuccess;
|
|
||||||
// }
|
|
||||||
const searchError = (find) => stringContains(find, err.message, true);
|
|
||||||
const commonIgnoredErrors = ['ECONNREFUSED', 'socket hang up'];
|
|
||||||
let foundDevice = false;
|
|
||||||
let errorMessage = '';
|
|
||||||
|
|
||||||
switch (true) {
|
|
||||||
case searchError('ECONNREFUSED'):
|
|
||||||
errorMessage = `ECONNREFUSED`;
|
|
||||||
return {refused: true}
|
|
||||||
break;
|
|
||||||
case searchError('TIMEDOUT'):
|
|
||||||
foundDevice = true;
|
|
||||||
errorMessage = lang.ONVIFErr401;
|
|
||||||
break;
|
|
||||||
case searchError('401'):
|
|
||||||
foundDevice = true;
|
|
||||||
errorMessage = lang.ONVIFErr401;
|
|
||||||
break;
|
|
||||||
case searchError('400'):
|
|
||||||
foundDevice = true;
|
|
||||||
errorMessage = lang.ONVIFErr400;
|
|
||||||
break;
|
|
||||||
case searchError('405'):
|
|
||||||
foundDevice = true;
|
|
||||||
errorMessage = lang.ONVIFErr405;
|
|
||||||
break;
|
|
||||||
case searchError('404'):
|
|
||||||
foundDevice = true;
|
|
||||||
errorMessage = lang.ONVIFErr404;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foundDevice) {
|
|
||||||
const cameraResponse = {
|
|
||||||
ip: camera.ip,
|
|
||||||
port: camera.port,
|
|
||||||
error: errorMessage,
|
|
||||||
failedConnection: true,
|
|
||||||
};
|
|
||||||
failedCameraCallback(cameraResponse);
|
|
||||||
return cameraResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
function isValidOnvifResult(result) {
|
|
||||||
return result.info || result.uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
function detectAndReplaceReolinkRTSP(camera, url){
|
|
||||||
const possibilities = [`/h264Preview_01_main`, `/h265Preview_01_main`]
|
|
||||||
for(possible of possibilities){
|
|
||||||
// console.log(url, possible, url.indexOf(possible) > -1)
|
|
||||||
if(url.indexOf(possible) > -1){
|
|
||||||
return `rtmp://${camera.user}:${camera.pass}@${camera.ip}:1935/bcs/channel0_main.bcs?token=sdasdasd&channel=0&stream=0&user=${camera.user}&password=${camera.pass}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
const runOnvifScanner = async (options, foundCameraCallback, failedCameraCallback) => {
|
|
||||||
if (scanStatus.isActive) return scanStatus.current;
|
|
||||||
|
|
||||||
scanStatus.isActive = true;
|
|
||||||
scanStatus.abortController = new AbortController();
|
|
||||||
const { signal } = scanStatus.abortController;
|
|
||||||
const cancelPromises = [];
|
|
||||||
scanStatus.cancelPromises = cancelPromises;
|
|
||||||
let ip = options.ip.replace(/ /g, '');
|
|
||||||
let ports = options.port.replace(/ /g, '');
|
|
||||||
const onvifUsername = options.user || 'admin';
|
|
||||||
const onvifPassword = options.pass || '';
|
|
||||||
|
|
||||||
if (ip === '') {
|
|
||||||
const addresses = getNetworkAddresses();
|
|
||||||
ip = getAddressRange(addresses);
|
|
||||||
}
|
|
||||||
|
|
||||||
ports = getPorts(ports);
|
|
||||||
|
|
||||||
const ipList = getIpList(ip);
|
|
||||||
const hitList = createHitList(ipList, ports, onvifUsername, onvifPassword);
|
|
||||||
|
|
||||||
const ipQueues = {};
|
|
||||||
const responseList = [];
|
|
||||||
const allPingSuccess = {};
|
|
||||||
|
|
||||||
const fetchWithTimeout = async (camera, onvifUsername, onvifPassword, foundCameraCallback, failedCameraCallback, signal) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const timeout = setTimeout(() => reject(new Error('Timeout')), 2500); // Adjust the timeout as needed
|
|
||||||
fetchCameraDetails(camera, onvifUsername, onvifPassword, foundCameraCallback, failedCameraCallback, signal)
|
|
||||||
.then(result => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
resolve(result);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (const camera of hitList) {
|
|
||||||
if (!ipQueues[camera.ip]) {
|
|
||||||
ipQueues[camera.ip] = async.queue(async (task) => {
|
|
||||||
if (signal.aborted) {
|
|
||||||
throw new Error('Aborted');
|
|
||||||
}
|
|
||||||
// if(!scanStatus.allSuccessful[camera.ip]){
|
|
||||||
const cameraIp = task.camera.ip;
|
|
||||||
const hasPingSuccess = allPingSuccess[cameraIp];
|
|
||||||
if (hasPingSuccess !== false) {
|
|
||||||
const fetchPromise = fetchWithTimeout(task.camera, task.onvifUsername, task.onvifPassword, task.foundCameraCallback, task.failedCameraCallback, signal);
|
|
||||||
cancelPromises.push(fetchPromise);
|
|
||||||
const result = await fetchPromise;
|
|
||||||
if (result.refused) allPingSuccess[cameraIp] = !result.refused;
|
|
||||||
if (result.uri){
|
|
||||||
try{
|
|
||||||
result.uri = detectAndReplaceReolinkRTSP(task.camera, addCredentialsToUrl({ url: result.uri, username: task.camera.user, password: task.camera.pass }));
|
|
||||||
}catch(err){
|
|
||||||
console.error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
responseList.push({...result});
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
}, 1);
|
|
||||||
}
|
|
||||||
ipQueues[camera.ip].push({
|
|
||||||
camera,
|
|
||||||
onvifUsername: camera.user,
|
|
||||||
onvifPassword: camera.pass,
|
|
||||||
foundCameraCallback,
|
|
||||||
failedCameraCallback
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await Promise.all(Object.values(ipQueues).map(queue => new Promise((resolve) => queue.drain(resolve))));
|
|
||||||
} catch (err) {
|
|
||||||
if (err.message === 'Aborted') {
|
|
||||||
console.log('Scan aborted');
|
|
||||||
} else {
|
|
||||||
console.error('big error', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scanStatus.isActive = false;
|
|
||||||
scanStatus.abortController = null;
|
|
||||||
scanStatus.cancelPromises = null;
|
|
||||||
s.debugLog('Done Scan');
|
|
||||||
return responseList;
|
|
||||||
};
|
|
||||||
|
|
||||||
const stopOnvifScanner = () => {
|
|
||||||
if (scanStatus.isActive && scanStatus.abortController) {
|
|
||||||
scanStatus.abortController.abort();
|
|
||||||
scanStatus.cancelPromises.forEach(promise => promise.catch(() => {}));
|
|
||||||
scanStatus.isActive = false;
|
|
||||||
s.debugLog('Scan stopped');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function expandIPRange(rangeStr) {
|
|
||||||
const ipRangeToArray = (start, end) => {
|
|
||||||
const startParts = start.split('.').map(Number);
|
|
||||||
const endParts = end.split('.').map(Number);
|
|
||||||
const ips = [];
|
|
||||||
for (let a = startParts[0]; a <= endParts[0]; a++) {
|
|
||||||
for (let b = startParts[1]; b <= endParts[1]; b++) {
|
|
||||||
for (let c = startParts[2]; c <= endParts[2]; c++) {
|
|
||||||
for (let d = startParts[3]; d <= endParts[3]; d++) {
|
|
||||||
ips.push([a, b, c, d].join('.'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ips;
|
const addressRange = []
|
||||||
};
|
addresses.forEach(function(address){
|
||||||
|
if(address.indexOf('0.0.0')>-1){return false}
|
||||||
|
var addressPrefix = address.split('.')
|
||||||
|
delete(addressPrefix[3]);
|
||||||
|
addressPrefix = addressPrefix.join('.')
|
||||||
|
addressRange.push(`${addressPrefix}1-${addressPrefix}254`)
|
||||||
|
})
|
||||||
|
ip = addressRange.join(',')
|
||||||
|
}
|
||||||
|
if(ports === ''){
|
||||||
|
ports = '80,8080,8000,7575,8081,9080,8090,8999,8899'
|
||||||
|
}
|
||||||
|
if(ports.indexOf('-') > -1){
|
||||||
|
ports = ports.split('-')
|
||||||
|
var portRangeStart = ports[0]
|
||||||
|
var portRangeEnd = ports[1]
|
||||||
|
ports = portRange(portRangeStart,portRangeEnd);
|
||||||
|
}else{
|
||||||
|
ports = ports.split(',')
|
||||||
|
}
|
||||||
|
var ipList = options.ipList
|
||||||
|
var onvifUsername = options.user || ''
|
||||||
|
var onvifPassword = options.pass || ''
|
||||||
|
ip.split(',').forEach(function(addressRange){
|
||||||
|
var ipRangeStart = addressRange[0]
|
||||||
|
var ipRangeEnd = addressRange[1]
|
||||||
|
if(addressRange.indexOf('-')>-1){
|
||||||
|
addressRange = addressRange.split('-');
|
||||||
|
ipRangeStart = addressRange[0]
|
||||||
|
ipRangeEnd = addressRange[1]
|
||||||
|
}else{
|
||||||
|
ipRangeStart = addressRange
|
||||||
|
ipRangeEnd = addressRange
|
||||||
|
}
|
||||||
|
if(!ipList){
|
||||||
|
ipList = ipRange(ipRangeStart,ipRangeEnd);
|
||||||
|
}else{
|
||||||
|
ipList = ipList.concat(ipRange(ipRangeStart,ipRangeEnd))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
var hitList = []
|
||||||
|
ipList.forEach((ipEntry,n) => {
|
||||||
|
ports.forEach((portEntry,nn) => {
|
||||||
|
hitList.push({
|
||||||
|
xaddr : 'http://' + ipEntry + ':' + portEntry + '/onvif/device_service',
|
||||||
|
user : onvifUsername,
|
||||||
|
pass : onvifPassword,
|
||||||
|
ip: ipEntry,
|
||||||
|
port: portEntry,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
var responseList = []
|
||||||
|
hitList.forEach(async (camera) => {
|
||||||
|
try{
|
||||||
|
var device = new onvif.OnvifDevice(camera)
|
||||||
|
var info = await device.init()
|
||||||
|
var date = await device.services.device.getSystemDateAndTime()
|
||||||
|
var stream = await device.services.media.getStreamUri({
|
||||||
|
ProfileToken : device.current_profile.token,
|
||||||
|
Protocol : 'RTSP'
|
||||||
|
})
|
||||||
|
|
||||||
return rangeStr.split(',')
|
var cameraResponse = {
|
||||||
.flatMap(range => {
|
ip: camera.ip,
|
||||||
const [start, end] = range.split('-');
|
port: camera.port,
|
||||||
return ipRangeToArray(start.trim(), end.trim());
|
info: info,
|
||||||
});
|
date: date,
|
||||||
|
uri: stream.data.GetStreamUriResponse.MediaUri.Uri
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
const camPtzConfigs = (await device.services.ptz.getConfigurations()).data.GetConfigurationsResponse
|
||||||
|
if(
|
||||||
|
camPtzConfigs.PTZConfiguration &&
|
||||||
|
(
|
||||||
|
camPtzConfigs.PTZConfiguration.PanTiltLimits ||
|
||||||
|
camPtzConfigs.PTZConfiguration.ZoomLimits
|
||||||
|
)
|
||||||
|
){
|
||||||
|
cameraResponse.isPTZ = true
|
||||||
|
}
|
||||||
|
}catch(err){
|
||||||
|
s.debugLog(err)
|
||||||
|
}
|
||||||
|
responseList.push(cameraResponse)
|
||||||
|
var imageSnap
|
||||||
|
try{
|
||||||
|
const snapUri = addCredentialsToUrl({
|
||||||
|
username: onvifUsername,
|
||||||
|
password: onvifPassword,
|
||||||
|
url: (await device.services.media.getSnapshotUri({
|
||||||
|
ProfileToken : device.current_profile.token,
|
||||||
|
})).data.GetSnapshotUriResponse.MediaUri.Uri,
|
||||||
|
});
|
||||||
|
imageSnap = (await getBuffer(snapUri)).toString('base64');
|
||||||
|
}catch(err){
|
||||||
|
s.debugLog(err)
|
||||||
|
}
|
||||||
|
if(foundCameraCallback)foundCameraCallback(Object.assign(cameraResponse,{f: 'onvif', snapShot: imageSnap}))
|
||||||
|
}catch(err){
|
||||||
|
const searchError = (find) => {
|
||||||
|
return stringContains(find,err.message,true)
|
||||||
|
}
|
||||||
|
var foundDevice = false
|
||||||
|
var errorMessage = ''
|
||||||
|
switch(true){
|
||||||
|
//ONVIF camera found but denied access
|
||||||
|
case searchError('400'): //Bad Request - Sender not Authorized
|
||||||
|
foundDevice = true
|
||||||
|
errorMessage = lang.ONVIFErr400
|
||||||
|
break;
|
||||||
|
case searchError('405'): //Method Not Allowed
|
||||||
|
foundDevice = true
|
||||||
|
errorMessage = lang.ONVIFErr405
|
||||||
|
break;
|
||||||
|
//Webserver exists but undetermined if IP Camera
|
||||||
|
case searchError('404'): //Not Found
|
||||||
|
foundDevice = true
|
||||||
|
errorMessage = lang.ONVIFErr404
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(foundDevice && foundCameraCallback){
|
||||||
|
foundCameraCallback({
|
||||||
|
f: 'onvif',
|
||||||
|
ff: 'failed_capture',
|
||||||
|
ip: camera.ip,
|
||||||
|
port: camera.port,
|
||||||
|
error: errorMessage
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(config.debugLogVerbose)s.debugLog(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return responseList
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
expandIPRange,
|
ipRange: ipRange,
|
||||||
ipRange,
|
portRange: portRange,
|
||||||
portRange,
|
runOnvifScanner: runOnvifScanner,
|
||||||
scanStatus,
|
}
|
||||||
runOnvifScanner,
|
|
||||||
stopOnvifScanner,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ $(document).ready(function(e){
|
||||||
var loadedResultsByIp = {}
|
var loadedResultsByIp = {}
|
||||||
var monitorEditorWindow = $('#tab-monitorSettings')
|
var monitorEditorWindow = $('#tab-monitorSettings')
|
||||||
var onvifScannerWindow = $('#tab-onvifScanner')
|
var onvifScannerWindow = $('#tab-onvifScanner')
|
||||||
var onvifScannerStartButton = onvifScannerWindow.find('.start-scan')
|
|
||||||
var onvifScannerStopButton = onvifScannerWindow.find('.stop-scan')
|
|
||||||
var onvifScannerResultPane = onvifScannerWindow.find('.onvif_result')
|
var onvifScannerResultPane = onvifScannerWindow.find('.onvif_result')
|
||||||
var onvifScannerErrorResultPane = onvifScannerWindow.find('.onvif_result_error')
|
var onvifScannerErrorResultPane = onvifScannerWindow.find('.onvif_result_error')
|
||||||
var scanForm = onvifScannerWindow.find('form');
|
var scanForm = onvifScannerWindow.find('form');
|
||||||
|
@ -32,97 +30,86 @@ $(document).ready(function(e){
|
||||||
var html = buildSubMenuItems(allFound)
|
var html = buildSubMenuItems(allFound)
|
||||||
sideMenuList.html(html)
|
sideMenuList.html(html)
|
||||||
}
|
}
|
||||||
var showStopButton = function(appearance){
|
var setAsLoading = function(appearance){
|
||||||
if(appearance){
|
if(appearance){
|
||||||
onvifScannerStartButton.addClass('d-none')
|
onvifScannerWindow.find('._loading').show()
|
||||||
onvifScannerStopButton.removeClass('d-none')
|
onvifScannerWindow.find('[type="submit"]').prop('disabled',true)
|
||||||
}else{
|
}else{
|
||||||
onvifScannerStartButton.removeClass('d-none')
|
onvifScannerWindow.find('._loading').hide()
|
||||||
onvifScannerStopButton.addClass('d-none')
|
onvifScannerWindow.find('[type="submit"]').prop('disabled',false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function drawProbeResult(options){
|
||||||
function drawDeviceTableRow(device, gotAccess){
|
if(!options.error){
|
||||||
var ip = device.ip;
|
var currentUsername = onvifScannerWindow.find('[name="user"]').val()
|
||||||
var el = onvifScannerResultPane.find(`[scan-item="${ip}"]`)
|
var currentPassword = onvifScannerWindow.find('[name="pass"]').val()
|
||||||
var hasError = !!device.error;
|
var tempID = generateId()
|
||||||
var uriText = !hasError ? device.uri ? device.uri.split('?')[0] : '' : device.error;
|
var info = options.info ? jsonToHtmlBlock(options.info) : ''
|
||||||
var statusColor = hasError ? 'red' : 'green';
|
var streamUrl = ''
|
||||||
var snapShot = device.snapShot;
|
var launchWebPage = `target="_blank" href="http${options.port == 443 ? 's' : ''}://${options.ip}:${options.port}"`
|
||||||
// console.log(ip, device.error, hasError)
|
if(options.uri){
|
||||||
if(gotAccess)loadMonitorConfigFromResult(device)
|
streamUrl = options.uri
|
||||||
if(el.length === 0){
|
}
|
||||||
var html = `<div scan-item="${ip}" class="col-md-6">
|
var theLocation = getLocationFromUri(options.uri)
|
||||||
<div class="card btn-default d-flex flex-row align-items-center p-2 mb-3 mx-2" style="border:none;border-left: 3px solid;border-color: ${statusColor}">
|
var pathLocation = theLocation.location
|
||||||
<div class="pr-2"><i class="fa fa-square" style="color:${statusColor}"></i></div>
|
var monitorConfigPartial = {
|
||||||
<div class="pr-2"><div class="scan-item-img copy ${snapShot ? `cursor-pointer` : ''}" style="${snapShot ? `background-image:url(data:image/jpeg;base64,${snapShot})` : 'background-color:${statusColor};'}"></div></div>
|
name: pathLocation.hostname,
|
||||||
<div class="pr-2 flex-grow-1">${ip}<br><small class="uri">${uriText}</small></div>
|
mid: tempID + `${options.port}`,
|
||||||
<div class="text-center copy-button pr-2">${!hasError ? makeButton({text: lang.Copy, class:'copy', color: 'primary'}) : ''}</div>
|
host: pathLocation.hostname,
|
||||||
</div>
|
port: pathLocation.port,
|
||||||
</div>`
|
path: pathLocation.pathname + (pathLocation.search && pathLocation.search !== '?' ? pathLocation.search : ''),
|
||||||
onvifScannerResultPane.append(html)
|
protocol: theLocation.protocol,
|
||||||
|
details: {
|
||||||
|
auto_host: addCredentialsToUri(streamUrl,currentUsername,currentPassword),
|
||||||
|
muser: currentUsername,
|
||||||
|
mpass: currentPassword,
|
||||||
|
is_onvif: '1',
|
||||||
|
onvif_port: options.port,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if(options.isPTZ){
|
||||||
|
monitorConfigPartial.details = Object.assign(monitorConfigPartial.details,{
|
||||||
|
control: '1',
|
||||||
|
control_url_method: 'ONVIF',
|
||||||
|
control_stop: '1',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
var monitorAlreadyAdded = isOnvifRowAlreadyALoadedMonitor(monitorConfigPartial)
|
||||||
|
if(monitorAlreadyAdded){
|
||||||
|
monitorConfigPartial.mid = monitorAlreadyAdded.mid;
|
||||||
|
}
|
||||||
|
var monitorId = monitorConfigPartial.mid
|
||||||
|
loadedResults[monitorId] = monitorConfigPartial;
|
||||||
|
loadedResultsByIp[monitorConfigPartial.host] = monitorConfigPartial;
|
||||||
|
onvifScannerResultPane.append(`
|
||||||
|
<div class="col-md-4 mb-3" onvif_row="${monitorId}" id="onvif-result-${monitorId}">
|
||||||
|
<div style="display:block" class="card shadow btn-default copy">
|
||||||
|
<div class="preview-image card-header" style="background-image:url(${options.snapShot ? 'data:image/png;base64,' + options.snapShot : placeholder.getData(placeholder.plcimg({text: ' ', fsize: 25, bgcolor:'#1f80f9'}))})"></div>
|
||||||
|
<div class="card-body" style="min-height:190px">
|
||||||
|
<div>${info}</div>
|
||||||
|
<div class="url">${streamUrl}</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">${options.ip}:${options.port}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
|
onvifScannerWindow.find('._notfound').remove()
|
||||||
|
setAsLoading(false)
|
||||||
|
drawFoundCamerasSubMenu()
|
||||||
}else{
|
}else{
|
||||||
var copyButton = el.find('.copy-button');
|
if(!loadedResultsByIp[options.ip]){
|
||||||
var imgEl = el.find('.scan-item-img');
|
onvifScannerErrorResultPane.append(`
|
||||||
if(hasError){
|
<div onvif_error_row="${options.ip}" class="d-flex flex-row">
|
||||||
copyButton.empty()
|
<div class="py-2 px-1" style="min-width:170px"><b>${options.ip}:${options.port}</b></div>
|
||||||
imgEl.removeClass('copy cursor-pointer')
|
<div class="py-2 px-1 flex-grow-1">${options.error}</div>
|
||||||
}else{
|
<div class="py-2 px-1 text-right">
|
||||||
copyButton.html(makeButton({text: lang.Copy, class:'copy', color: 'primary'}))
|
<a target="_blank" class="btn btn-sm btn-secondary" href="http://${options.ip}:${options.port}"><i class="fa fa-external-link"></i></a>
|
||||||
imgEl.addClass('copy cursor-pointer')
|
</div>
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
}
|
}
|
||||||
if(snapShot){
|
|
||||||
imgEl.css('background-image', `url("data:image/jpeg;base64,${snapShot}")`)
|
|
||||||
}else{
|
|
||||||
imgEl.css('background-image', '')
|
|
||||||
}
|
|
||||||
imgEl.css('background-color', statusColor)
|
|
||||||
el.find('.uri').text(uriText)
|
|
||||||
el.find('.card').css('border-color', statusColor)
|
|
||||||
el.find('.fa-circle').css('color', statusColor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function loadMonitorConfigFromResult(options){
|
|
||||||
var monitorId = removeSpecialCharacters(options.ip)
|
|
||||||
var currentUsername = options.user
|
|
||||||
var currentPassword = options.pass
|
|
||||||
var streamUrl = ''
|
|
||||||
var launchWebPage = `target="_blank" href="http${options.port == 443 ? 's' : ''}://${options.ip}:${options.port}"`
|
|
||||||
if(options.uri){
|
|
||||||
streamUrl = options.uri
|
|
||||||
}
|
|
||||||
var theLocation = getLocationFromUri(options.uri)
|
|
||||||
var pathLocation = theLocation.location
|
|
||||||
var monitorConfigPartial = {
|
|
||||||
name: pathLocation.hostname,
|
|
||||||
mid: monitorId,
|
|
||||||
host: pathLocation.hostname,
|
|
||||||
port: pathLocation.port,
|
|
||||||
path: pathLocation.pathname + (pathLocation.search && pathLocation.search !== '?' ? pathLocation.search : ''),
|
|
||||||
protocol: theLocation.protocol,
|
|
||||||
details: {
|
|
||||||
auto_host: addCredentialsToUri(streamUrl,currentUsername,currentPassword),
|
|
||||||
muser: currentUsername,
|
|
||||||
mpass: currentPassword,
|
|
||||||
is_onvif: '1',
|
|
||||||
onvif_port: options.port,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if(options.isPTZ){
|
|
||||||
monitorConfigPartial.details = Object.assign(monitorConfigPartial.details,{
|
|
||||||
control: '1',
|
|
||||||
control_url_method: 'ONVIF',
|
|
||||||
control_stop: '1',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
var monitorAlreadyAdded = isOnvifRowAlreadyALoadedMonitor(monitorConfigPartial)
|
|
||||||
if(monitorAlreadyAdded){
|
|
||||||
monitorConfigPartial.mid = monitorAlreadyAdded.mid;
|
|
||||||
}
|
|
||||||
loadedResults[monitorId] = monitorConfigPartial;
|
|
||||||
loadedResultsByIp[monitorConfigPartial.host] = monitorConfigPartial;
|
|
||||||
return monitorConfigPartial
|
|
||||||
}
|
|
||||||
function isOnvifRowAlreadyALoadedMonitor(onvifRow){
|
function isOnvifRowAlreadyALoadedMonitor(onvifRow){
|
||||||
var matches = null;
|
var matches = null;
|
||||||
$.each(loadedMonitors,function(n,monitor){
|
$.each(loadedMonitors,function(n,monitor){
|
||||||
|
@ -187,7 +174,7 @@ $(document).ready(function(e){
|
||||||
var form = el.serializeObject();
|
var form = el.serializeObject();
|
||||||
onvifScannerResultPane.empty();
|
onvifScannerResultPane.empty();
|
||||||
onvifScannerErrorResultPane.empty();
|
onvifScannerErrorResultPane.empty();
|
||||||
showStopButton(true)
|
setAsLoading(true)
|
||||||
mainSocket.f({
|
mainSocket.f({
|
||||||
f: 'onvif',
|
f: 'onvif',
|
||||||
ip: form.ip,
|
ip: form.ip,
|
||||||
|
@ -197,80 +184,34 @@ $(document).ready(function(e){
|
||||||
});
|
});
|
||||||
clearTimeout(checkTimeout)
|
clearTimeout(checkTimeout)
|
||||||
checkTimeout = setTimeout(function(){
|
checkTimeout = setTimeout(function(){
|
||||||
if(onvifScannerResultPane.find('[scan-item]').length === 0){
|
if(onvifScannerResultPane.find('.card').length === 0){
|
||||||
showStopButton(false)
|
setAsLoading(false)
|
||||||
onvifScannerResultPane.append(`<div class="p-2 text-center ${definitions.Theme.isDark ? 'text-white' : ''} _notfound text-white epic-text">${lang.sorryNothingWasFound}</div>`)
|
onvifScannerResultPane.append(`<div class="p-2 text-center ${definitions.Theme.isDark ? 'text-white' : ''} _notfound text-white epic-text">${lang.sorryNothingWasFound}</div>`)
|
||||||
}
|
}
|
||||||
},5000)
|
},5000)
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
onvifScannerWindow.on('click','.copy',function(e){
|
onvifScannerWindow.on('click','.copy',function(){
|
||||||
e.preventDefault()
|
|
||||||
openMonitorEditorPage()
|
openMonitorEditorPage()
|
||||||
var el = $(this).parents('[scan-item]');
|
var el = $(this).parents('[onvif_row]');
|
||||||
var id = el.attr('scan-item');
|
var id = el.attr('onvif_row');
|
||||||
var onvifRecord = loadedResultsByIp[id];
|
var onvifRecord = loadedResults[id];
|
||||||
var streamURL = onvifRecord.details.auto_host
|
var streamURL = onvifRecord.details.auto_host
|
||||||
writeToMonitorSettingsWindow(onvifRecord)
|
writeToMonitorSettingsWindow(onvifRecord)
|
||||||
})
|
})
|
||||||
onvifScannerWindow.on('click','.add-all',function(){
|
onvifScannerWindow.on('click','.add-all',function(){
|
||||||
filterOutMonitorsThatAreAlreadyAdded(loadedResults,function(importableCameras){
|
filterOutMonitorsThatAreAlreadyAdded(loadedResults,function(importableCameras){
|
||||||
const numberOfCameras = importableCameras.length
|
$.each(importableCameras,function(n,camera){
|
||||||
if(numberOfCameras === 0){
|
// console.log(camera)
|
||||||
new PNotify({
|
postMonitor(camera)
|
||||||
title: lang["ONVIF Scanner"],
|
})
|
||||||
text: lang.sorryNothingWasFound,
|
|
||||||
type: 'danger',
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
$.confirm.create({
|
|
||||||
title: lang['Add Cameras'],
|
|
||||||
body: `<p>${lang.addAllCamerasText.replace('9001', numberOfCameras)}</p><ul>${importableCameras.map(item => `<li>${item.host}</li>`).join('')}</ul>`,
|
|
||||||
clickOptions: {
|
|
||||||
class: 'btn-success',
|
|
||||||
title: lang.Add,
|
|
||||||
},
|
|
||||||
clickCallback: function(){
|
|
||||||
$.each(importableCameras,function(n,camera){
|
|
||||||
// console.log(camera)
|
|
||||||
postMonitor(camera)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
onvifScannerWindow.on('click','.stop-scan',function(){
|
|
||||||
mainSocket.f({ f: 'onvif_stop' });
|
|
||||||
})
|
|
||||||
|
|
||||||
loadLocalOptions()
|
loadLocalOptions()
|
||||||
onInitWebsocket(function (){
|
|
||||||
mainSocket.f({ f: 'onvif_scan_reconnect' });
|
|
||||||
})
|
|
||||||
onWebSocketEvent(function (d){
|
onWebSocketEvent(function (d){
|
||||||
switch(d.f){
|
switch(d.f){
|
||||||
case'onvif':
|
case'onvif':
|
||||||
try{
|
drawProbeResult(d)
|
||||||
drawDeviceTableRow(d, d.ff !== 'failed_capture' && !d.failedConnection);
|
|
||||||
}catch(err){
|
|
||||||
console.error(err)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case'onvif_scan_current':
|
|
||||||
console.log(d)
|
|
||||||
if(d.isScanning){
|
|
||||||
showStopButton(true)
|
|
||||||
}else{
|
|
||||||
showStopButton(false)
|
|
||||||
}
|
|
||||||
d.devices.forEach(device => {
|
|
||||||
console.log('onvif_scan_current', device)
|
|
||||||
drawDeviceTableRow(device, !device.error && !d.failedConnection)
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case'onvif_scan_complete':
|
|
||||||
showStopButton(false)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue