mirror of
https://gitlab.com/Shinobi-Systems/ShinobiCE.git
synced 2025-03-09 15:40:15 +00:00
Kicking Kangaroo
This commit is contained in:
parent
bc01b19714
commit
e0f7c135af
37 changed files with 1642 additions and 518 deletions
|
@ -34,13 +34,13 @@ loadLib('ffmpeg')(s,config,function(){
|
||||||
//express web server with ejs
|
//express web server with ejs
|
||||||
var app = loadLib('webServer')(s,config,lang,io)
|
var app = loadLib('webServer')(s,config,lang,io)
|
||||||
//web server routes : page handling..
|
//web server routes : page handling..
|
||||||
loadLib('webServerPaths')(s,config,lang,app)
|
loadLib('webServerPaths')(s,config,lang,app,io)
|
||||||
//web server routes for streams : streams..
|
//web server routes for streams : streams..
|
||||||
loadLib('webServerStreamPaths')(s,config,lang,app)
|
loadLib('webServerStreamPaths')(s,config,lang,app,io)
|
||||||
//web server admin routes : create sub accounts, share monitors, share videos
|
//web server admin routes : create sub accounts, share monitors, share videos
|
||||||
loadLib('webServerAdminPaths')(s,config,lang,app)
|
loadLib('webServerAdminPaths')(s,config,lang,app,io)
|
||||||
//web server superuser routes : create admin accounts and manage system functions
|
//web server superuser routes : create admin accounts and manage system functions
|
||||||
loadLib('webServerSuperPaths')(s,config,lang,app)
|
loadLib('webServerSuperPaths')(s,config,lang,app,io)
|
||||||
//websocket connection handlers : login and streams..
|
//websocket connection handlers : login and streams..
|
||||||
loadLib('socketio')(s,config,lang,io)
|
loadLib('socketio')(s,config,lang,io)
|
||||||
//user and group functions
|
//user and group functions
|
||||||
|
|
61
cron.js
61
cron.js
|
@ -46,22 +46,35 @@ if(databaseOptions.client === 'sqlite3' && databaseOptions.connection.filename =
|
||||||
databaseOptions.connection.filename = __dirname+"/shinobi.sqlite"
|
databaseOptions.connection.filename = __dirname+"/shinobi.sqlite"
|
||||||
}
|
}
|
||||||
s.databaseEngine = knex(databaseOptions)
|
s.databaseEngine = knex(databaseOptions)
|
||||||
|
s.dateSubtract = function(date, interval, units){
|
||||||
|
var ret = date
|
||||||
|
var checkRollover = function() { if(ret.getDate() != date.getDate()) ret.setDate(0);};
|
||||||
|
switch(interval.toLowerCase()) {
|
||||||
|
case 'year' : ret.setFullYear(ret.getFullYear() - units); checkRollover(); break;
|
||||||
|
case 'quarter': ret.setMonth(ret.getMonth() - 3*units); checkRollover(); break;
|
||||||
|
case 'month' : ret.setMonth(ret.getMonth() - units); checkRollover(); break;
|
||||||
|
case 'week' : ret.setDate(ret.getDate() - 7*units); break;
|
||||||
|
case 'day' : ret.setDate(ret.getDate() - units); break;
|
||||||
|
case 'hour' : ret.setTime(ret.getTime() - units*3600000); break;
|
||||||
|
case 'minute' : ret.setTime(ret.getTime() - units*60000); break;
|
||||||
|
case 'second' :default: ret.setTime(ret.getTime() - units*1000); break;
|
||||||
|
}
|
||||||
|
return (new Date(ret))
|
||||||
|
}
|
||||||
s.sqlDate = function(value){
|
s.sqlDate = function(value){
|
||||||
var dateQueryFunction = ''
|
var value = value.toLowerCase()
|
||||||
if(databaseOptions.client === 'sqlite3'){
|
var splitValue = value.split(' ')
|
||||||
value = value.toLowerCase()
|
var amount = parseFloat(splitValue[0])
|
||||||
if (value.slice(-1) !== 's') {
|
var today = new Date()
|
||||||
value = value+'s'
|
var query
|
||||||
}
|
if(value.indexOf('min') > -1){
|
||||||
dateQueryFunction = "datetime('now', '-"+value+"')"
|
query = s.dateSubtract(today,'minute',amount)
|
||||||
}else{
|
}else if(value.indexOf('day') > -1){
|
||||||
value = value.toUpperCase()
|
query = s.dateSubtract(today,'day',amount)
|
||||||
if (value.slice(-1) === 'S') {
|
}else if(value.indexOf('hour') > -1){
|
||||||
value = value.slice(0, -1);
|
query = s.dateSubtract(today,'hour',amount)
|
||||||
}
|
|
||||||
dateQueryFunction = "DATE_SUB(NOW(), INTERVAL "+value+")"
|
|
||||||
}
|
}
|
||||||
return dateQueryFunction
|
return query
|
||||||
}
|
}
|
||||||
s.mergeQueryValues = function(query,values){
|
s.mergeQueryValues = function(query,values){
|
||||||
if(!values){values=[]}
|
if(!values){values=[]}
|
||||||
|
@ -187,12 +200,11 @@ s.checkFilterRules = function(v,callback){
|
||||||
v.d.filters={};
|
v.d.filters={};
|
||||||
}
|
}
|
||||||
//delete old videos with filter
|
//delete old videos with filter
|
||||||
if(config.cron.deleteOld===true){
|
if(config.cron.deleteOld === true){
|
||||||
var where = [{
|
var where = [{
|
||||||
"p1":"end",
|
"p1":"end",
|
||||||
"p2":"<",
|
"p2":"<=",
|
||||||
"p3":s.sqlDate(v.d.days+" DAYS"),
|
"p3":s.sqlDate(v.d.days+" DAY")
|
||||||
"p3_type":"function",
|
|
||||||
}]
|
}]
|
||||||
//exclude monitors with their own max days
|
//exclude monitors with their own max days
|
||||||
v.monitorsWithMaxKeepDays.forEach(function(mid){
|
v.monitorsWithMaxKeepDays.forEach(function(mid){
|
||||||
|
@ -298,7 +310,7 @@ s.deleteRowsWithNoVideo = function(v,callback){
|
||||||
){
|
){
|
||||||
s.alreadyDeletedRowsWithNoVideosOnStart[v.ke]=true;
|
s.alreadyDeletedRowsWithNoVideosOnStart[v.ke]=true;
|
||||||
es={};
|
es={};
|
||||||
s.sqlQuery('SELECT * FROM Videos WHERE ke=? AND status!=0 AND details NOT LIKE \'%"archived":"1"%\' AND time < '+s.sqlDate('10 MINUTE'),[v.ke],function(err,evs){
|
s.sqlQuery('SELECT * FROM Videos WHERE ke=? AND status!=0 AND details NOT LIKE \'%"archived":"1"%\' AND time < ?',[v.ke,s.sqlDate('10 MINUTE')],function(err,evs){
|
||||||
if(evs&&evs[0]){
|
if(evs&&evs[0]){
|
||||||
es.del=[];es.ar=[v.ke];
|
es.del=[];es.ar=[v.ke];
|
||||||
evs.forEach(function(ev){
|
evs.forEach(function(ev){
|
||||||
|
@ -341,7 +353,7 @@ s.deleteRowsWithNoVideo = function(v,callback){
|
||||||
s.deleteOldLogs = function(v,callback){
|
s.deleteOldLogs = function(v,callback){
|
||||||
if(!v.d.log_days||v.d.log_days==''){v.d.log_days=10}else{v.d.log_days=parseFloat(v.d.log_days)};
|
if(!v.d.log_days||v.d.log_days==''){v.d.log_days=10}else{v.d.log_days=parseFloat(v.d.log_days)};
|
||||||
if(config.cron.deleteLogs===true&&v.d.log_days!==0){
|
if(config.cron.deleteLogs===true&&v.d.log_days!==0){
|
||||||
s.sqlQuery("DELETE FROM Logs WHERE ke=? AND `time` < "+s.sqlDate('? DAYS'),[v.ke,v.d.log_days],function(err,rrr){
|
s.sqlQuery("DELETE FROM Logs WHERE ke=? AND `time` < ?",[v.ke,s.sqlDate(v.d.log_days+' DAY')],function(err,rrr){
|
||||||
callback()
|
callback()
|
||||||
if(err)return console.error(err);
|
if(err)return console.error(err);
|
||||||
if(rrr.affectedRows && rrr.affectedRows.length>0 || config.debugLog === true){
|
if(rrr.affectedRows && rrr.affectedRows.length>0 || config.debugLog === true){
|
||||||
|
@ -356,7 +368,7 @@ s.deleteOldLogs = function(v,callback){
|
||||||
s.deleteOldEvents = function(v,callback){
|
s.deleteOldEvents = function(v,callback){
|
||||||
if(!v.d.event_days||v.d.event_days==''){v.d.event_days=10}else{v.d.event_days=parseFloat(v.d.event_days)};
|
if(!v.d.event_days||v.d.event_days==''){v.d.event_days=10}else{v.d.event_days=parseFloat(v.d.event_days)};
|
||||||
if(config.cron.deleteEvents===true&&v.d.event_days!==0){
|
if(config.cron.deleteEvents===true&&v.d.event_days!==0){
|
||||||
s.sqlQuery("DELETE FROM Events WHERE ke=? AND `time` < "+s.sqlDate('? DAYS'),[v.ke,v.d.event_days],function(err,rrr){
|
s.sqlQuery("DELETE FROM Events WHERE ke=? AND `time` < ?",[v.ke,s.sqlDate(v.d.event_days+' DAY')],function(err,rrr){
|
||||||
callback()
|
callback()
|
||||||
if(err)return console.error(err);
|
if(err)return console.error(err);
|
||||||
if(rrr.affectedRows && rrr.affectedRows.length>0 || config.debugLog === true){
|
if(rrr.affectedRows && rrr.affectedRows.length>0 || config.debugLog === true){
|
||||||
|
@ -371,8 +383,8 @@ s.deleteOldEvents = function(v,callback){
|
||||||
s.deleteOldFileBins = function(v,callback){
|
s.deleteOldFileBins = function(v,callback){
|
||||||
if(!v.d.fileBin_days||v.d.fileBin_days==''){v.d.fileBin_days=10}else{v.d.fileBin_days=parseFloat(v.d.fileBin_days)};
|
if(!v.d.fileBin_days||v.d.fileBin_days==''){v.d.fileBin_days=10}else{v.d.fileBin_days=parseFloat(v.d.fileBin_days)};
|
||||||
if(config.cron.deleteFileBins===true&&v.d.fileBin_days!==0){
|
if(config.cron.deleteFileBins===true&&v.d.fileBin_days!==0){
|
||||||
var fileBinQuery = " FROM Files WHERE ke=? AND `time` < "+s.sqlDate('? DAYS');
|
var fileBinQuery = " FROM Files WHERE ke=? AND `time` < ?";
|
||||||
s.sqlQuery("SELECT *"+fileBinQuery,[v.ke,v.d.fileBin_days],function(err,files){
|
s.sqlQuery("SELECT *"+fileBinQuery,[v.ke,s.sqlDate(v.d.fileBin_days+' DAY')],function(err,files){
|
||||||
if(files&&files[0]){
|
if(files&&files[0]){
|
||||||
//delete the files
|
//delete the files
|
||||||
files.forEach(function(file){
|
files.forEach(function(file){
|
||||||
|
@ -451,8 +463,7 @@ s.processUser = function(number,rows){
|
||||||
},{
|
},{
|
||||||
"p1":"end",
|
"p1":"end",
|
||||||
"p2":"<",
|
"p2":"<",
|
||||||
"p3":s.sqlDate(b.details.max_keep_days+" DAYS"),
|
"p3":s.sqlDate(b.details.max_keep_days+" DAY")
|
||||||
"p3_type":"function",
|
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,6 +206,9 @@
|
||||||
"Save Links to Database": "Save Links to Database",
|
"Save Links to Database": "Save Links to Database",
|
||||||
"Bucket": "Bucket",
|
"Bucket": "Bucket",
|
||||||
"Region": "Region",
|
"Region": "Region",
|
||||||
|
"Use Global Amazon S3 Video Storage": "Use Global Amazon S3 Video Storage",
|
||||||
|
"Use Global Backblaze B2 Video Storage": "Use Global Backblaze B2 Video Storage",
|
||||||
|
"Use Global WebDAV Video Storage": "Use Global WebDAV Video Storage",
|
||||||
"Amazon S3 Upload Error": "Amazon S3 Upload Error",
|
"Amazon S3 Upload Error": "Amazon S3 Upload Error",
|
||||||
"accountId": "Account ID",
|
"accountId": "Account ID",
|
||||||
"applicationKey": "Application Key",
|
"applicationKey": "Application Key",
|
||||||
|
@ -574,6 +577,8 @@
|
||||||
"Monitor is now Disabled": "Monitor is now Disabled",
|
"Monitor is now Disabled": "Monitor is now Disabled",
|
||||||
"Monitor is now Watching": "Monitor is now Watching",
|
"Monitor is now Watching": "Monitor is now Watching",
|
||||||
"Monitor is now Recording": "Monitor is now Recording",
|
"Monitor is now Recording": "Monitor is now Recording",
|
||||||
|
"Space Used": "Space Used",
|
||||||
|
"Processor": "Processor",
|
||||||
"coProcessor": "coProcessor",
|
"coProcessor": "coProcessor",
|
||||||
"coProcessor Stopped": "coProcessor Stopped",
|
"coProcessor Stopped": "coProcessor Stopped",
|
||||||
"coProcessor Started": "coProcessor Started",
|
"coProcessor Started": "coProcessor Started",
|
||||||
|
@ -606,6 +611,7 @@
|
||||||
"Control Error": "Control Error",
|
"Control Error": "Control Error",
|
||||||
"Database row does not exist": "Database row does not exist",
|
"Database row does not exist": "Database row does not exist",
|
||||||
"File Delete Error": "File Delete Error",
|
"File Delete Error": "File Delete Error",
|
||||||
|
"List of Videos Delete Error": "List of Videos Delete Error",
|
||||||
"postDataBroken": "Check the format of the JSON. Ensure it is stringified and defined under 'data'",
|
"postDataBroken": "Check the format of the JSON. Ensure it is stringified and defined under 'data'",
|
||||||
"ControlErrorText1": "Control is not enabled",
|
"ControlErrorText1": "Control is not enabled",
|
||||||
"ControlErrorText2": "Check your connection details. You may need to point the Base URL at port 8000 or 80. Check your authentication info.",
|
"ControlErrorText2": "Check your connection details. You may need to point the Base URL at port 8000 or 80. Check your authentication info.",
|
||||||
|
@ -643,7 +649,14 @@
|
||||||
"Thumbnail": "Thumbnail",
|
"Thumbnail": "Thumbnail",
|
||||||
"Host Type": "Host Type",
|
"Host Type": "Host Type",
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
|
"No Monitor ID Present in Form": "No Monitor ID Present in Form",
|
||||||
|
"State Configuration has no monitors associated": "State Configuration has no monitors associated",
|
||||||
|
"State Configuration Not Found": "State Configuration Not Found",
|
||||||
|
"Inserted State Configuration": "Inserted State Configuration",
|
||||||
|
"Edited State Configuration": "Edited State Configuration",
|
||||||
|
"Deleted State Configuration": "Deleted State Configuration",
|
||||||
"Dashboard Language": "Dashboard Language",
|
"Dashboard Language": "Dashboard Language",
|
||||||
|
"Form Data Not Found": "Form Data Not Found",
|
||||||
"File Not Found": "File Not Found",
|
"File Not Found": "File Not Found",
|
||||||
"File Not Found in Filesystem": "File Not Found in Filesystem",
|
"File Not Found in Filesystem": "File Not Found in Filesystem",
|
||||||
"File Not Found in Database": "File Not Found in Database",
|
"File Not Found in Database": "File Not Found in Database",
|
||||||
|
|
|
@ -6,6 +6,7 @@ module.exports = function(s,config,lang){
|
||||||
// WebDAV
|
// WebDAV
|
||||||
var beforeAccountSaveForWebDav = function(d){
|
var beforeAccountSaveForWebDav = function(d){
|
||||||
//d = save event
|
//d = save event
|
||||||
|
d.form.details.webdav_use_global=d.d.webdav_use_global
|
||||||
d.form.details.use_webdav=d.d.use_webdav
|
d.form.details.use_webdav=d.d.use_webdav
|
||||||
}
|
}
|
||||||
var cloudDiskUseStartupForWebDav = function(group,userDetails){
|
var cloudDiskUseStartupForWebDav = function(group,userDetails){
|
||||||
|
@ -20,6 +21,15 @@ module.exports = function(s,config,lang){
|
||||||
var loadWebDavForUser = function(e){
|
var loadWebDavForUser = function(e){
|
||||||
// e = user
|
// e = user
|
||||||
var ar = JSON.parse(e.details);
|
var ar = JSON.parse(e.details);
|
||||||
|
if(ar.webdav_use_global === '1' && config.cloudUploaders && config.cloudUploaders.WebDAV){
|
||||||
|
// {
|
||||||
|
// webdav_user: "",
|
||||||
|
// webdav_pass: "",
|
||||||
|
// webdav_url: "",
|
||||||
|
// webdav_dir: "",
|
||||||
|
// }
|
||||||
|
ar = Object.assign(ar,config.cloudUploaders.WebDAV)
|
||||||
|
}
|
||||||
//owncloud/webdav
|
//owncloud/webdav
|
||||||
if(!s.group[e.ke].webdav &&
|
if(!s.group[e.ke].webdav &&
|
||||||
ar.webdav_user&&
|
ar.webdav_user&&
|
||||||
|
@ -150,6 +160,7 @@ module.exports = function(s,config,lang){
|
||||||
//Amazon S3
|
//Amazon S3
|
||||||
var beforeAccountSaveForAmazonS3 = function(d){
|
var beforeAccountSaveForAmazonS3 = function(d){
|
||||||
//d = save event
|
//d = save event
|
||||||
|
d.form.details.aws_use_global=d.d.aws_use_global
|
||||||
d.form.details.use_aws_s3=d.d.use_aws_s3
|
d.form.details.use_aws_s3=d.d.use_aws_s3
|
||||||
}
|
}
|
||||||
var cloudDiskUseStartupForAmazonS3 = function(group,userDetails){
|
var cloudDiskUseStartupForAmazonS3 = function(group,userDetails){
|
||||||
|
@ -163,7 +174,17 @@ module.exports = function(s,config,lang){
|
||||||
}
|
}
|
||||||
var loadAmazonS3ForUser = function(e){
|
var loadAmazonS3ForUser = function(e){
|
||||||
// e = user
|
// e = user
|
||||||
var ar = JSON.parse(e.details);
|
var ar = JSON.parse(e.details)
|
||||||
|
if(ar.aws_use_global === '1' && config.cloudUploaders && config.cloudUploaders.AmazonS3){
|
||||||
|
// {
|
||||||
|
// aws_accessKeyId: "",
|
||||||
|
// aws_secretAccessKey: "",
|
||||||
|
// aws_region: "",
|
||||||
|
// aws_s3_bucket: "",
|
||||||
|
// aws_s3_dir: "",
|
||||||
|
// }
|
||||||
|
ar = Object.assign(ar,config.cloudUploaders.AmazonS3)
|
||||||
|
}
|
||||||
//Amazon S3
|
//Amazon S3
|
||||||
if(!s.group[e.ke].aws &&
|
if(!s.group[e.ke].aws &&
|
||||||
!s.group[e.ke].aws_s3 &&
|
!s.group[e.ke].aws_s3 &&
|
||||||
|
@ -262,7 +283,8 @@ module.exports = function(s,config,lang){
|
||||||
//Backblaze B2
|
//Backblaze B2
|
||||||
var beforeAccountSaveForBackblazeB2 = function(d){
|
var beforeAccountSaveForBackblazeB2 = function(d){
|
||||||
//d = save event
|
//d = save event
|
||||||
d.form.details.use_aws_s3=d.d.use_bb_b2
|
d.form.details.b2_use_global=d.d.b2_use_global
|
||||||
|
d.form.details.use_bb_b2=d.d.use_bb_b2
|
||||||
}
|
}
|
||||||
var cloudDiskUseStartupForBackblazeB2 = function(group,userDetails){
|
var cloudDiskUseStartupForBackblazeB2 = function(group,userDetails){
|
||||||
group.cloudDiskUse['b2'].name = 'Backblaze B2'
|
group.cloudDiskUse['b2'].name = 'Backblaze B2'
|
||||||
|
@ -276,6 +298,15 @@ module.exports = function(s,config,lang){
|
||||||
var loadBackblazeB2ForUser = function(e){
|
var loadBackblazeB2ForUser = function(e){
|
||||||
var ar = JSON.parse(e.details);
|
var ar = JSON.parse(e.details);
|
||||||
try{
|
try{
|
||||||
|
if(ar.b2_use_global === '1' && config.cloudUploaders && config.cloudUploaders.BackblazeB2){
|
||||||
|
// {
|
||||||
|
// bb_b2_accountId: "",
|
||||||
|
// bb_b2_applicationKey: "",
|
||||||
|
// bb_b2_bucket: "",
|
||||||
|
// bb_b2_dir: "",
|
||||||
|
// }
|
||||||
|
ar = Object.assign(ar,config.cloudUploaders.BackblazeB2)
|
||||||
|
}
|
||||||
if(!s.group[e.ke].bb_b2 &&
|
if(!s.group[e.ke].bb_b2 &&
|
||||||
ar.bb_b2_accountId &&
|
ar.bb_b2_accountId &&
|
||||||
ar.bb_b2_accountId !=='' &&
|
ar.bb_b2_accountId !=='' &&
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
var P2P = require('pipe2pam');
|
var P2P = require('pipe2pam');
|
||||||
var PamDiff = require('pam-diff');
|
// pamDiff is based on https://www.npmjs.com/package/pam-diff
|
||||||
|
var PamDiff = require('./detectorPamDiff.js');
|
||||||
module.exports = function(s,config){
|
module.exports = function(s,config){
|
||||||
s.createPamDiffEngine = function(e){
|
s.createPamDiffEngine = function(e){
|
||||||
var width,
|
var width,
|
||||||
|
@ -64,12 +65,13 @@ module.exports = function(s,config){
|
||||||
plug:'built-in',
|
plug:'built-in',
|
||||||
name:trigger.name,
|
name:trigger.name,
|
||||||
reason:'motion',
|
reason:'motion',
|
||||||
confidence:trigger.percent,
|
confidence:trigger.percent
|
||||||
},
|
},
|
||||||
plates:[],
|
plates:[],
|
||||||
imgHeight:height,
|
imgHeight:e.details.detector_scale_y,
|
||||||
imgWidth:width
|
imgWidth:e.details.detector_scale_x
|
||||||
}
|
}
|
||||||
|
if(trigger.matrix)detectorObject.details.matrices = [trigger.matrix]
|
||||||
var region = Object.values(regionJson).find(x => x.name == detectorObject.name)
|
var region = Object.values(regionJson).find(x => x.name == detectorObject.name)
|
||||||
s.checkMaximumSensitivity(e, region, detectorObject, function() {
|
s.checkMaximumSensitivity(e, region, detectorObject, function() {
|
||||||
s.checkTriggerThreshold(e, region, detectorObject, function() {
|
s.checkTriggerThreshold(e, region, detectorObject, function() {
|
||||||
|
|
622
libs/detectorPamDiff.js
Normal file
622
libs/detectorPamDiff.js
Normal file
|
@ -0,0 +1,622 @@
|
||||||
|
//
|
||||||
|
// Shinobi - fork of pam-diff
|
||||||
|
// Copyright (C) 2018 Kevin Godell
|
||||||
|
// Author : Kevin Godell, https://github.com/kevinGodell
|
||||||
|
// npmjs : https://www.npmjs.com/package/pam-diff
|
||||||
|
// Github : https://github.com/kevinGodell/pam-diff
|
||||||
|
//
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Transform } = require('stream');
|
||||||
|
|
||||||
|
const PP = require('polygon-points');
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param chunk
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var _getMatrixFromPoints = function(thisRegion) {
|
||||||
|
var coordinates = [
|
||||||
|
thisRegion.topLeft,
|
||||||
|
{"x" : thisRegion.bottomRight.x, "y" : thisRegion.topLeft.y},
|
||||||
|
thisRegion.bottomRight
|
||||||
|
]
|
||||||
|
var width = Math.sqrt( Math.pow(coordinates[1].x - coordinates[0].x, 2) + Math.pow(coordinates[1].y - coordinates[0].y, 2));
|
||||||
|
var height = Math.sqrt( Math.pow(coordinates[2].x - coordinates[1].x, 2) + Math.pow(coordinates[2].y - coordinates[1].y, 2))
|
||||||
|
return {
|
||||||
|
x: coordinates[0].x,
|
||||||
|
y: coordinates[0].y,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
tag: thisRegion.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class PamDiff extends Transform {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param [options] {Object}
|
||||||
|
* @param [callback] {Function}
|
||||||
|
*/
|
||||||
|
constructor(options, callback) {
|
||||||
|
super(options);
|
||||||
|
Transform.call(this, {objectMode: true});
|
||||||
|
this.difference = PamDiff._parseOptions('difference', options);//global option, can be overridden per region
|
||||||
|
this.percent = PamDiff._parseOptions('percent', options);//global option, can be overridden per region
|
||||||
|
this.regions = PamDiff._parseOptions('regions', options);//can be no regions or a single region or multiple regions. if no regions, all pixels will be compared.
|
||||||
|
this.callback = callback;//callback function to be called when pixel difference is detected
|
||||||
|
this._parseChunk = this._parseFirstChunk;//first parsing will be reading settings and configuring internal pixel reading
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param option {String}
|
||||||
|
* @param options {Object}
|
||||||
|
* @return {*}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _parseOptions(option, options) {
|
||||||
|
if (options && options.hasOwnProperty(option)) {
|
||||||
|
return options[option];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param number {Number}
|
||||||
|
* @param def {Number}
|
||||||
|
* @param low {Number}
|
||||||
|
* @param high {Number}
|
||||||
|
* @return {Number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _validateNumber(number, def, low, high) {
|
||||||
|
if (isNaN(number)) {
|
||||||
|
return def;
|
||||||
|
} else if (number < low) {
|
||||||
|
return low;
|
||||||
|
} else if (number > high) {
|
||||||
|
return high;
|
||||||
|
} else {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
* @param string {String}
|
||||||
|
*/
|
||||||
|
setGrayscale(string) {
|
||||||
|
console.warn('grayscale option has been removed, "average" has proven to most accurate and is the default');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param number {Number}
|
||||||
|
*/
|
||||||
|
set difference(number) {
|
||||||
|
this._difference = PamDiff._validateNumber(parseInt(number), 5, 1, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return {Number}
|
||||||
|
*/
|
||||||
|
get difference() {
|
||||||
|
return this._difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param number {Number}
|
||||||
|
* @return {PamDiff}
|
||||||
|
*/
|
||||||
|
setDifference(number) {
|
||||||
|
this.difference = number;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param number {Number}
|
||||||
|
*/
|
||||||
|
set percent(number) {
|
||||||
|
this._percent = PamDiff._validateNumber(parseInt(number), 5, 1, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return {Number}
|
||||||
|
*/
|
||||||
|
get percent() {
|
||||||
|
return this._percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param number {Number}
|
||||||
|
* @return {PamDiff}
|
||||||
|
*/
|
||||||
|
setPercent(number) {
|
||||||
|
this.percent = number;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param array {Array}
|
||||||
|
*/
|
||||||
|
set regions(array) {
|
||||||
|
if (!array) {
|
||||||
|
if (this._regions) {
|
||||||
|
delete this._regions;
|
||||||
|
delete this._regionsLength;
|
||||||
|
delete this._minDiff;
|
||||||
|
}
|
||||||
|
this._diffs = 0;
|
||||||
|
} else if (!Array.isArray(array) || array.length < 1) {
|
||||||
|
throw new Error(`Regions must be an array of at least 1 region object {name: 'region1', difference: 10, percent: 10, polygon: [[0, 0], [0, 50], [50, 50], [50, 0]]}`);
|
||||||
|
} else {
|
||||||
|
this._regions = [];
|
||||||
|
this._minDiff = 255;
|
||||||
|
for (const region of array) {
|
||||||
|
if (!region.hasOwnProperty('name') || !region.hasOwnProperty('polygon')) {
|
||||||
|
throw new Error('Region must include a name and a polygon property');
|
||||||
|
}
|
||||||
|
const polygonPoints = new PP(region.polygon);
|
||||||
|
const difference = PamDiff._validateNumber(parseInt(region.difference), this._difference, 1, 255);
|
||||||
|
const percent = PamDiff._validateNumber(parseInt(region.percent), this._percent, 1, 100);
|
||||||
|
this._minDiff = Math.min(this._minDiff, difference);
|
||||||
|
this._regions.push(
|
||||||
|
{
|
||||||
|
name: region.name,
|
||||||
|
polygon: polygonPoints,
|
||||||
|
difference: difference,
|
||||||
|
percent: percent,
|
||||||
|
diffs: 0
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this._regionsLength = this._regions.length;
|
||||||
|
this._createPointsInPolygons(this._regions, this._width, this._height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
get regions() {
|
||||||
|
return this._regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param array {Array}
|
||||||
|
* @return {PamDiff}
|
||||||
|
*/
|
||||||
|
setRegions(array) {
|
||||||
|
this.regions = array;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param func {Function}
|
||||||
|
*/
|
||||||
|
set callback(func) {
|
||||||
|
if (!func) {
|
||||||
|
delete this._callback;
|
||||||
|
} else if (typeof func === 'function' && func.length === 1) {
|
||||||
|
this._callback = func;
|
||||||
|
} else {
|
||||||
|
throw new Error('Callback must be a function that accepts 1 argument.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return {Function}
|
||||||
|
*/
|
||||||
|
get callback() {
|
||||||
|
return this._callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param func {Function}
|
||||||
|
* @return {PamDiff}
|
||||||
|
*/
|
||||||
|
setCallback(func) {
|
||||||
|
this.callback = func;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return {PamDiff}
|
||||||
|
*/
|
||||||
|
resetCache() {
|
||||||
|
//delete this._oldPix;
|
||||||
|
//delete this._newPix;
|
||||||
|
//delete this._width;
|
||||||
|
//delete this._length;
|
||||||
|
this._parseChunk = this._parseFirstChunk;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param regions {Array}
|
||||||
|
* @param width {Number}
|
||||||
|
* @param height {Number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_createPointsInPolygons(regions, width, height) {
|
||||||
|
if (regions && width && height) {
|
||||||
|
this._pointsInPolygons = [];
|
||||||
|
for (const region of regions) {
|
||||||
|
const bitset = region.polygon.getBitset(this._width, this._height);
|
||||||
|
region.pointsLength = bitset.count;
|
||||||
|
this._pointsInPolygons.push(bitset.buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param chunk
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_blackAndWhitePixelDiff(chunk) {
|
||||||
|
this._newPix = chunk.pixels;
|
||||||
|
for (let y = 0, i = 0; y < this._height; y++) {
|
||||||
|
for (let x = 0; x < this._width; x++, i++) {
|
||||||
|
const diff = this._oldPix[i] !== this._newPix[i];
|
||||||
|
if (this._regions && diff === true) {
|
||||||
|
for (let j = 0; j < this._regionsLength; j++) {
|
||||||
|
if (this._pointsInPolygons[j][i]) {
|
||||||
|
this._regions[j].diffs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (diff === true) {
|
||||||
|
this._diffs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this._regions) {
|
||||||
|
const regionDiffArray = [];
|
||||||
|
for (let i = 0; i < this._regionsLength; i++) {
|
||||||
|
const percent = Math.floor(100 * this._regions[i].diffs / this._regions[i].pointsLength);
|
||||||
|
if (percent >= this._regions[i].percent) {
|
||||||
|
regionDiffArray.push({name: this._regions[i].name, percent: percent});
|
||||||
|
}
|
||||||
|
this._regions[i].diffs = 0;
|
||||||
|
}
|
||||||
|
if (regionDiffArray.length > 0) {
|
||||||
|
const data = {trigger: regionDiffArray, pam: chunk.pam};
|
||||||
|
if (this._callback) {
|
||||||
|
this._callback(data);
|
||||||
|
}
|
||||||
|
if (this._readableState.pipesCount > 0) {
|
||||||
|
this.push(data);
|
||||||
|
}
|
||||||
|
if (this.listenerCount('diff') > 0) {
|
||||||
|
this.emit('diff', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const percent = Math.floor(100 * this._diffs / this._length);
|
||||||
|
if (percent >= this._percent) {
|
||||||
|
const data = {trigger: [{name: 'percent', percent: percent}], pam: chunk.pam};
|
||||||
|
if (this._callback) {
|
||||||
|
this._callback(data);
|
||||||
|
}
|
||||||
|
if (this._readableState.pipesCount > 0) {
|
||||||
|
this.push(data);
|
||||||
|
}
|
||||||
|
if (this.listenerCount('diff') > 0) {
|
||||||
|
this.emit('diff', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._diffs = 0;
|
||||||
|
}
|
||||||
|
this._oldPix = this._newPix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param chunk
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_grayScalePixelDiff(chunk) {
|
||||||
|
this._newPix = chunk.pixels;
|
||||||
|
for (let j = 0; j < this._regionsLength; j++) {
|
||||||
|
this._regions[j].topLeft = {
|
||||||
|
x: this._width,
|
||||||
|
y: this._height
|
||||||
|
}
|
||||||
|
this._regions[j].bottomRight = {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.topLeft = {
|
||||||
|
x: this._width,
|
||||||
|
y: this._height
|
||||||
|
}
|
||||||
|
this.bottomRight = {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
}
|
||||||
|
for (let y = 0, i = 0; y < this._height; y++) {
|
||||||
|
for (let x = 0; x < this._width; x++, i++) {
|
||||||
|
if (this._oldPix[i] !== this._newPix[i]) {
|
||||||
|
const diff = Math.abs(this._oldPix[i] - this._newPix[i]);
|
||||||
|
if (this._regions && diff >= this._minDiff) {
|
||||||
|
for (let j = 0; j < this._regionsLength; j++) {
|
||||||
|
if (this._pointsInPolygons[j][i] && diff >= this._regions[j].difference) {
|
||||||
|
var theRegion = this._regions[j]
|
||||||
|
theRegion.diffs++;
|
||||||
|
if(theRegion.topLeft.x > x && theRegion.topLeft.y > y){
|
||||||
|
theRegion.topLeft.x = x
|
||||||
|
theRegion.topLeft.y = y
|
||||||
|
}
|
||||||
|
if(theRegion.bottomRight.x < x && theRegion.bottomRight.y < y){
|
||||||
|
theRegion.bottomRight.x = x
|
||||||
|
theRegion.bottomRight.y = y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (diff >= this._difference) {
|
||||||
|
this._diffs++;
|
||||||
|
if(this.topLeft.x > x && this.topLeft.y > y){
|
||||||
|
this.topLeft.x = x
|
||||||
|
this.topLeft.y = y
|
||||||
|
}
|
||||||
|
if(this.bottomRight.x < x && this.bottomRight.y < y){
|
||||||
|
this.bottomRight.x = x
|
||||||
|
this.bottomRight.y = y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this._regions) {
|
||||||
|
const regionDiffArray = [];
|
||||||
|
for (let i = 0; i < this._regionsLength; i++) {
|
||||||
|
var thisRegion = this._regions[i]
|
||||||
|
const percent = Math.floor(100 * thisRegion.diffs / thisRegion.pointsLength);
|
||||||
|
if (percent >= thisRegion.percent) {
|
||||||
|
// create matrix from points >>
|
||||||
|
thisRegion._matrix = _getMatrixFromPoints(thisRegion)
|
||||||
|
// create matrix from points />>
|
||||||
|
regionDiffArray.push({name: thisRegion.name, percent: percent, matrix: thisRegion._matrix});
|
||||||
|
}
|
||||||
|
thisRegion.diffs = 0;
|
||||||
|
}
|
||||||
|
if (regionDiffArray.length > 0) {
|
||||||
|
this._matrix = _getMatrixFromPoints(this)
|
||||||
|
const data = {trigger: regionDiffArray, pam: chunk.pam, matrix: this._matrix};
|
||||||
|
if (this._callback) {
|
||||||
|
this._callback(data);
|
||||||
|
}
|
||||||
|
if (this._readableState.pipesCount > 0) {
|
||||||
|
this.push(data);
|
||||||
|
}
|
||||||
|
if (this.listenerCount('diff') > 0) {
|
||||||
|
this.emit('diff', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const percent = Math.floor(100 * this._diffs / this._length);
|
||||||
|
if (percent >= this._percent) {
|
||||||
|
this._matrix = _getMatrixFromPoints(this)
|
||||||
|
const data = {trigger: [{name: 'percent', percent: percent, matrix: this._matrix}], pam: chunk.pam};
|
||||||
|
if (this._callback) {
|
||||||
|
this._callback(data);
|
||||||
|
}
|
||||||
|
if (this._readableState.pipesCount > 0) {
|
||||||
|
this.push(data);
|
||||||
|
}
|
||||||
|
if (this.listenerCount('diff') > 0) {
|
||||||
|
this.emit('diff', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._diffs = 0;
|
||||||
|
}
|
||||||
|
this._oldPix = this._newPix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param chunk
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_rgbPixelDiff(chunk) {
|
||||||
|
this._newPix = chunk.pixels;
|
||||||
|
for (let y = 0, i = 0, p = 0; y < this._height; y++) {
|
||||||
|
for (let x = 0; x < this._width; x++, i += 3, p++) {
|
||||||
|
if (this._oldPix[i] !== this._newPix[i] || this._oldPix[i + 1] !== this._newPix[i + 1] || this._oldPix[i + 2] !== this._newPix[i + 2]) {
|
||||||
|
const diff = Math.abs(this._oldPix[i] + this._oldPix[i + 1] + this._oldPix[i + 2] - this._newPix[i] - this._newPix[i + 1] - this._newPix[i + 2])/3;
|
||||||
|
if (this._regions && diff >= this._minDiff) {
|
||||||
|
for (let j = 0; j < this._regionsLength; j++) {
|
||||||
|
if (this._pointsInPolygons[j][p] && diff >= this._regions[j].difference) {
|
||||||
|
this._regions[j].diffs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (diff >= this._difference) {
|
||||||
|
this._diffs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this._regions) {
|
||||||
|
const regionDiffArray = [];
|
||||||
|
for (let i = 0; i < this._regionsLength; i++) {
|
||||||
|
const percent = Math.floor(100 * this._regions[i].diffs / this._regions[i].pointsLength);
|
||||||
|
if (percent >= this._regions[i].percent) {
|
||||||
|
regionDiffArray.push({name: this._regions[i].name, percent: percent});
|
||||||
|
}
|
||||||
|
this._regions[i].diffs = 0;
|
||||||
|
}
|
||||||
|
if (regionDiffArray.length > 0) {
|
||||||
|
const data = {trigger: regionDiffArray, pam: chunk.pam};
|
||||||
|
if (this._callback) {
|
||||||
|
this._callback(data);
|
||||||
|
}
|
||||||
|
if (this._readableState.pipesCount > 0) {
|
||||||
|
this.push(data);
|
||||||
|
}
|
||||||
|
if (this.listenerCount('diff') > 0) {
|
||||||
|
this.emit('diff', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const percent = Math.floor(100 * this._diffs / this._length);
|
||||||
|
if (percent >= this._percent) {
|
||||||
|
const data = {trigger: [{name: 'percent', percent: percent}], pam: chunk.pam};
|
||||||
|
if (this._callback) {
|
||||||
|
this._callback(data);
|
||||||
|
}
|
||||||
|
if (this._readableState.pipesCount > 0) {
|
||||||
|
this.push(data);
|
||||||
|
}
|
||||||
|
if (this.listenerCount('diff') > 0) {
|
||||||
|
this.emit('diff', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._diffs = 0;
|
||||||
|
}
|
||||||
|
this._oldPix = this._newPix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param chunk
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_rgbAlphaPixelDiff(chunk) {
|
||||||
|
this._newPix = chunk.pixels;
|
||||||
|
for (let y = 0, i = 0, p = 0; y < this._height; y++) {
|
||||||
|
for (let x = 0; x < this._width; x++, i += 4, p++) {
|
||||||
|
if (this._oldPix[i] !== this._newPix[i] || this._oldPix[i + 1] !== this._newPix[i + 1] || this._oldPix[i + 2] !== this._newPix[i + 2]) {
|
||||||
|
const diff = Math.abs(this._oldPix[i] + this._oldPix[i + 1] + this._oldPix[i + 2] - this._newPix[i] - this._newPix[i + 1] - this._newPix[i + 2])/3;
|
||||||
|
if (this._regions && diff >= this._minDiff) {
|
||||||
|
for (let j = 0; j < this._regionsLength; j++) {
|
||||||
|
if (this._pointsInPolygons[j][p] && diff >= this._regions[j].difference) {
|
||||||
|
this._regions[j].diffs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (diff >= this._difference) {
|
||||||
|
this._diffs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this._regions) {
|
||||||
|
const regionDiffArray = [];
|
||||||
|
for (let i = 0; i < this._regionsLength; i++) {
|
||||||
|
const percent = Math.floor(100 * this._regions[i].diffs / this._regions[i].pointsLength);
|
||||||
|
if (percent >= this._regions[i].percent) {
|
||||||
|
regionDiffArray.push({name: this._regions[i].name, percent: percent});
|
||||||
|
}
|
||||||
|
this._regions[i].diffs = 0;
|
||||||
|
}
|
||||||
|
if (regionDiffArray.length > 0) {
|
||||||
|
const data = {trigger: regionDiffArray, pam: chunk.pam};
|
||||||
|
if (this._callback) {
|
||||||
|
this._callback(data);
|
||||||
|
}
|
||||||
|
if (this._readableState.pipesCount > 0) {
|
||||||
|
this.push(data);
|
||||||
|
}
|
||||||
|
if (this.listenerCount('diff') > 0) {
|
||||||
|
this.emit('diff', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const percent = Math.floor(100 * this._diffs / this._length);
|
||||||
|
if (percent >= this._percent) {
|
||||||
|
const data = {trigger: [{name: 'percent', percent: percent}], pam: chunk.pam};
|
||||||
|
if (this._callback) {
|
||||||
|
this._callback(data);
|
||||||
|
}
|
||||||
|
if (this._readableState.pipesCount > 0) {
|
||||||
|
this.push(data);
|
||||||
|
}
|
||||||
|
if (this.listenerCount('diff') > 0) {
|
||||||
|
this.emit('diff', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._diffs = 0;
|
||||||
|
}
|
||||||
|
this._oldPix = this._newPix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param chunk
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_parseFirstChunk(chunk) {
|
||||||
|
this._width = parseInt(chunk.width);
|
||||||
|
this._height = parseInt(chunk.height);
|
||||||
|
this._oldPix = chunk.pixels;
|
||||||
|
this._length = this._width * this._height;
|
||||||
|
this._createPointsInPolygons(this._regions, this._width, this._height);
|
||||||
|
switch (chunk.tupltype) {
|
||||||
|
case 'blackandwhite' :
|
||||||
|
this._parseChunk = this._blackAndWhitePixelDiff;
|
||||||
|
break;
|
||||||
|
case 'grayscale' :
|
||||||
|
this._parseChunk = this._grayScalePixelDiff;
|
||||||
|
break;
|
||||||
|
case 'rgb' :
|
||||||
|
this._parseChunk = this._rgbPixelDiff;
|
||||||
|
//this._increment = 3;//future use
|
||||||
|
break;
|
||||||
|
case 'rgb_alpha' :
|
||||||
|
this._parseChunk = this._rgbAlphaPixelDiff;
|
||||||
|
//this._increment = 4;//future use
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw Error(`Unsupported tupltype: ${chunk.tupltype}. Supported tupltypes include grayscale(gray), blackandwhite(monob), rgb(rgb24), and rgb_alpha(rgba).`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param chunk
|
||||||
|
* @param encoding
|
||||||
|
* @param callback
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_transform(chunk, encoding, callback) {
|
||||||
|
this._parseChunk(chunk);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param callback
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_flush(callback) {
|
||||||
|
this.resetCache();
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {PamDiff}
|
||||||
|
*/
|
||||||
|
module.exports = PamDiff;
|
||||||
|
//todo get bounding box of all regions combined to exclude some pixels before checking if they exist inside specific regions
|
|
@ -12,9 +12,7 @@ module.exports = function(s,config,lang){
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
case'delete':
|
case'delete':
|
||||||
d.videos.forEach(function(v,n){
|
s.deleteListOfVideos(d.videos)
|
||||||
s.deleteVideo(v)
|
|
||||||
})
|
|
||||||
break;
|
break;
|
||||||
case'execute':
|
case'execute':
|
||||||
exec(d.execute,{detached: true})
|
exec(d.execute,{detached: true})
|
||||||
|
@ -373,6 +371,7 @@ module.exports = function(s,config,lang){
|
||||||
delete(s.api[d.auth])
|
delete(s.api[d.auth])
|
||||||
s.userLog(d,{type:"Traditional Recording",msg:'Clear Recorder Process'})
|
s.userLog(d,{type:"Traditional Recording",msg:'Clear Recorder Process'})
|
||||||
delete(s.group[d.ke].mon[d.id].eventBasedRecording.process)
|
delete(s.group[d.ke].mon[d.id].eventBasedRecording.process)
|
||||||
|
clearTimeout(s.group[d.ke].mon[d.id].eventBasedRecording.timeout)
|
||||||
delete(s.group[d.ke].mon[d.id].eventBasedRecording.timeout)
|
delete(s.group[d.ke].mon[d.id].eventBasedRecording.timeout)
|
||||||
clearTimeout(s.group[d.ke].mon[d.id].recordingChecker)
|
clearTimeout(s.group[d.ke].mon[d.id].recordingChecker)
|
||||||
})
|
})
|
||||||
|
|
|
@ -526,12 +526,9 @@ module.exports = function(s,config,onFinish){
|
||||||
//add input feed map
|
//add input feed map
|
||||||
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.stream)
|
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.stream)
|
||||||
}
|
}
|
||||||
console.log('x.cust_stream',x.cust_stream)
|
|
||||||
|
|
||||||
if(x.stream_fps && (e.details.stream_vcodec !== 'copy' || e.details.stream_type === 'mjpeg' || e.details.stream_type === 'b64')){
|
if(x.stream_fps && (e.details.stream_vcodec !== 'copy' || e.details.stream_type === 'mjpeg' || e.details.stream_type === 'b64')){
|
||||||
x.cust_stream += x.stream_fps
|
x.cust_stream += x.stream_fps
|
||||||
}
|
}
|
||||||
console.log('x.cust_stream',x.cust_stream)
|
|
||||||
switch(e.details.stream_type){
|
switch(e.details.stream_type){
|
||||||
case'mp4':
|
case'mp4':
|
||||||
x.cust_stream+=' -movflags +frag_keyframe+empty_moov+default_base_moof -metadata title="Poseidon Stream" -reset_timestamps 1'
|
x.cust_stream+=' -movflags +frag_keyframe+empty_moov+default_base_moof -metadata title="Poseidon Stream" -reset_timestamps 1'
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
module.exports = function(s,config){
|
module.exports = function(s,config){
|
||||||
//directories
|
//directories
|
||||||
s.group={};
|
s.group = {}
|
||||||
if(!config.windowsTempDir&&s.isWin===true){config.windowsTempDir='C:/Windows/Temp'}
|
if(!config.windowsTempDir&&s.isWin===true){config.windowsTempDir='C:/Windows/Temp'}
|
||||||
if(!config.defaultMjpeg){config.defaultMjpeg=s.mainDirectory+'/web/libs/img/bg.jpg'}
|
if(!config.defaultMjpeg){config.defaultMjpeg=s.mainDirectory+'/web/libs/img/bg.jpg'}
|
||||||
//default stream folder check
|
//default stream folder check
|
||||||
if(!config.streamDir){
|
if(!config.streamDir){
|
||||||
if(s.isWin===false){
|
if(s.isWin === false){
|
||||||
config.streamDir='/dev/shm'
|
config.streamDir = '/dev/shm'
|
||||||
}else{
|
}else{
|
||||||
config.streamDir=config.windowsTempDir
|
config.streamDir = config.windowsTempDir
|
||||||
}
|
}
|
||||||
if(!fs.existsSync(config.streamDir)){
|
if(!fs.existsSync(config.streamDir)){
|
||||||
config.streamDir=s.mainDirectory+'/streams/'
|
config.streamDir = s.mainDirectory+'/streams/'
|
||||||
}else{
|
}else{
|
||||||
config.streamDir+='/streams/'
|
config.streamDir += '/streams/'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!config.videosDir){config.videosDir=s.mainDirectory+'/videos/'}
|
if(!config.videosDir){config.videosDir=s.mainDirectory+'/videos/'}
|
||||||
if(!config.binDir){config.binDir=s.mainDirectory+'/fileBin/'}
|
if(!config.binDir){config.binDir=s.mainDirectory+'/fileBin/'}
|
||||||
if(!config.addStorage){config.addStorage=[]}
|
if(!config.addStorage){config.addStorage=[]}
|
||||||
s.dir={
|
s.dir={
|
||||||
videos:s.checkCorrectPathEnding(config.videosDir),
|
videos: s.checkCorrectPathEnding(config.videosDir),
|
||||||
streams:s.checkCorrectPathEnding(config.streamDir),
|
streams: s.checkCorrectPathEnding(config.streamDir),
|
||||||
fileBin:s.checkCorrectPathEnding(config.binDir),
|
fileBin: s.checkCorrectPathEnding(config.binDir),
|
||||||
addStorage:config.addStorage,
|
addStorage: config.addStorage,
|
||||||
languages:s.location.languages+'/'
|
languages: s.location.languages+'/'
|
||||||
};
|
};
|
||||||
//streams dir
|
//streams dir
|
||||||
if(!fs.existsSync(s.dir.streams)){
|
if(!fs.existsSync(s.dir.streams)){
|
||||||
|
@ -41,7 +41,7 @@ module.exports = function(s,config){
|
||||||
}
|
}
|
||||||
//additional storage areas
|
//additional storage areas
|
||||||
s.dir.addStorage.forEach(function(v,n){
|
s.dir.addStorage.forEach(function(v,n){
|
||||||
v.path=s.checkCorrectPathEnding(v.path)
|
v.path = s.checkCorrectPathEnding(v.path)
|
||||||
if(!fs.existsSync(v.path)){
|
if(!fs.existsSync(v.path)){
|
||||||
fs.mkdirSync(v.path);
|
fs.mkdirSync(v.path);
|
||||||
}
|
}
|
||||||
|
|
215
libs/monitor.js
215
libs/monitor.js
|
@ -73,6 +73,16 @@ module.exports = function(s,config,lang){
|
||||||
if(noPath !== true)url += e.path
|
if(noPath !== true)url += e.path
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
s.cleanMonitorObjectForDatabase = function(dirtyMonitor){
|
||||||
|
var cleanMonitor = {}
|
||||||
|
var acceptedFields = ['mid','ke','name','shto','shfr','details','type','ext','protocol','host','path','port','fps','mode','width','height']
|
||||||
|
Object.keys(dirtyMonitor).forEach(function(key){
|
||||||
|
if(acceptedFields.indexOf(key) > -1){
|
||||||
|
cleanMonitor[key] = dirtyMonitor[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return cleanMonitor
|
||||||
|
}
|
||||||
s.cleanMonitorObject = function(e){
|
s.cleanMonitorObject = function(e){
|
||||||
x={keys:Object.keys(e),ar:{}};
|
x={keys:Object.keys(e),ar:{}};
|
||||||
x.keys.forEach(function(v){
|
x.keys.forEach(function(v){
|
||||||
|
@ -89,18 +99,28 @@ module.exports = function(s,config,lang){
|
||||||
}
|
}
|
||||||
var url
|
var url
|
||||||
var runExtraction = function(){
|
var runExtraction = function(){
|
||||||
var snapBuffer = []
|
try{
|
||||||
var snapProcess = spawn(config.ffmpegDir,('-loglevel quiet -re -i '+url+options+' -frames:v 1 -f mjpeg pipe:1').split(' '),{detached: true})
|
var snapBuffer = []
|
||||||
snapProcess.stdout.on('data',function(data){
|
var snapProcess = spawn(config.ffmpegDir,('-loglevel quiet -re -i '+url+options+' -frames:v 1 -f image2pipe pipe:1').split(' '),{detached: true})
|
||||||
snapBuffer.push(data)
|
snapProcess.stdout.on('data',function(data){
|
||||||
});
|
snapBuffer.push(data)
|
||||||
snapProcess.stderr.on('data',function(data){
|
})
|
||||||
console.log(data.toString())
|
snapProcess.stderr.on('data',function(data){
|
||||||
});
|
console.log(data.toString())
|
||||||
snapProcess.on('close',function(data){
|
})
|
||||||
snapBuffer = Buffer.concat(snapBuffer)
|
snapProcess.on('exit',function(data){
|
||||||
callback(snapBuffer,false)
|
clearTimeout(snapProcessTimeout)
|
||||||
})
|
snapBuffer = Buffer.concat(snapBuffer)
|
||||||
|
callback(snapBuffer,false)
|
||||||
|
})
|
||||||
|
var snapProcessTimeout = setTimeout(function(){
|
||||||
|
snapProcess.stdin.setEncoding('utf8')
|
||||||
|
snapProcess.stdin.write('q')
|
||||||
|
delete(snapProcessTimeout)
|
||||||
|
},5000)
|
||||||
|
}catch(err){
|
||||||
|
callback(fs.readFileSync(config.defaultMjpeg,'binary'),false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var checkExists = function(localStream,callback){
|
var checkExists = function(localStream,callback){
|
||||||
fs.stat(localStream,function(err){
|
fs.stat(localStream,function(err){
|
||||||
|
@ -230,6 +250,7 @@ module.exports = function(s,config,lang){
|
||||||
clearTimeout(s.group[e.ke].mon[e.id].watchdog_stop);
|
clearTimeout(s.group[e.ke].mon[e.id].watchdog_stop);
|
||||||
delete(s.group[e.ke].mon[e.id].watchdog_stop);
|
delete(s.group[e.ke].mon[e.id].watchdog_stop);
|
||||||
delete(s.group[e.ke].mon[e.id].lastJpegDetectorFrame);
|
delete(s.group[e.ke].mon[e.id].lastJpegDetectorFrame);
|
||||||
|
delete(s.group[e.ke].mon[e.id].detectorFrameSaveBuffer);
|
||||||
clearTimeout(s.group[e.ke].mon[e.id].recordingSnapper);
|
clearTimeout(s.group[e.ke].mon[e.id].recordingSnapper);
|
||||||
clearInterval(s.group[e.ke].mon[e.id].getMonitorCpuUsage);
|
clearInterval(s.group[e.ke].mon[e.id].getMonitorCpuUsage);
|
||||||
if(s.group[e.ke].mon[e.id].onChildNodeExit){
|
if(s.group[e.ke].mon[e.id].onChildNodeExit){
|
||||||
|
@ -377,7 +398,7 @@ module.exports = function(s,config,lang){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//create onvif connection
|
//create onvif connection
|
||||||
if(!s.group[e.ke].mon[e.id].onvifConnection){
|
if(!s.group[e.ke].mon[e.id].onvifConnection || !s.group[e.ke].mon[e.id].onvifConnection.current_profile || !s.group[e.ke].mon[e.id].onvifConnection.current_profile.token){
|
||||||
s.group[e.ke].mon[e.id].onvifConnection = new onvif.OnvifDevice({
|
s.group[e.ke].mon[e.id].onvifConnection = new onvif.OnvifDevice({
|
||||||
xaddr : 'http://' + controlURLOptions.host + ':' + controlURLOptions.port + '/onvif/device_service',
|
xaddr : 'http://' + controlURLOptions.host + ':' + controlURLOptions.port + '/onvif/device_service',
|
||||||
user : controlURLOptions.username,
|
user : controlURLOptions.username,
|
||||||
|
@ -494,8 +515,8 @@ module.exports = function(s,config,lang){
|
||||||
}
|
}
|
||||||
s.cameraSendSnapshot = function(e){
|
s.cameraSendSnapshot = function(e){
|
||||||
s.checkDetails(e)
|
s.checkDetails(e)
|
||||||
if(config.doSnapshot===true){
|
if(config.doSnapshot === true){
|
||||||
if(e.mon.mode!=='stop'){
|
if(e.mon.mode !== 'stop'){
|
||||||
var pathDir = s.dir.streams+e.ke+'/'+e.mid+'/'
|
var pathDir = s.dir.streams+e.ke+'/'+e.mid+'/'
|
||||||
fs.stat(pathDir+'icon.jpg',function(err){
|
fs.stat(pathDir+'icon.jpg',function(err){
|
||||||
if(!err){
|
if(!err){
|
||||||
|
@ -505,36 +526,22 @@ module.exports = function(s,config,lang){
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
e.url = s.buildMonitorUrl(e.mon)
|
e.url = s.buildMonitorUrl(e.mon)
|
||||||
switch(e.mon.type){
|
s.getRawSnapshotFromMonitor(e.mon,'-s 200x200',function(data,isStaticFile){
|
||||||
case'mjpeg':case'h264':case'local':
|
if((data[data.length-2] === 0xFF && data[data.length-1] === 0xD9)){
|
||||||
if(e.mon.type==='local'){e.url=e.mon.path;}
|
if(!isStaticFile){
|
||||||
s.getRawSnapshotFromMonitor(e.mon,'-s 200x200',function(data,isStaticFile){
|
fs.writeFile(s.dir.streams+e.ke+'/'+e.mid+'/icon.jpg',data,function(){})
|
||||||
if((data[data.length-2] === 0xFF && data[data.length-1] === 0xD9)){
|
}
|
||||||
if(!isStaticFile){
|
s.tx({
|
||||||
fs.writeFile(s.dir.streams+e.ke+'/'+e.mid+'/icon.jpg',data,function(){})
|
f: 'monitor_snapshot',
|
||||||
}
|
snapshot: data.toString('base64'),
|
||||||
s.tx({
|
snapshot_format: 'b64',
|
||||||
f:'monitor_snapshot',
|
mid: e.mid,
|
||||||
snapshot:data.toString('base64'),
|
ke: e.ke
|
||||||
snapshot_format:'b64',
|
},'GRP_'+e.ke)
|
||||||
mid:e.mid,
|
}else{
|
||||||
ke:e.ke
|
s.tx({f:'monitor_snapshot',snapshot:e.mon.name,snapshot_format:'plc',mid:e.mid,ke:e.ke},'GRP_'+e.ke)
|
||||||
},'GRP_'+e.ke)
|
}
|
||||||
}else{
|
})
|
||||||
s.tx({f:'monitor_snapshot',snapshot:e.mon.name,snapshot_format:'plc',mid:e.mid,ke:e.ke},'GRP_'+e.ke)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break;
|
|
||||||
case'jpeg':
|
|
||||||
request({url:e.url,method:'GET',encoding:null},function(err,data){
|
|
||||||
if(err){s.tx({f:'monitor_snapshot',snapshot:e.mon.name,snapshot_format:'plc',mid:e.mid,ke:e.ke},'GRP_'+e.ke);return};
|
|
||||||
s.tx({f:'monitor_snapshot',snapshot:data.body,snapshot_format:'ab',mid:e.mid,ke:e.ke},'GRP_'+e.ke)
|
|
||||||
})
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
s.tx({f:'monitor_snapshot',snapshot:'...',snapshot_format:'plc',mid:e.mid,ke:e.ke},'GRP_'+e.ke)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
|
@ -777,10 +784,34 @@ module.exports = function(s,config,lang){
|
||||||
s.group[e.ke].mon[e.id].lastJpegDetectorFrame = d
|
s.group[e.ke].mon[e.id].lastJpegDetectorFrame = d
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}else{
|
}else if(s.ocv){
|
||||||
s.group[e.ke].mon[e.id].spawn.stdio[3].on('data',function(d){
|
if(s.ocv.connectionType !== 'ram'){
|
||||||
s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d});
|
s.group[e.ke].mon[e.id].spawn.stdio[3].on('data',function(d){
|
||||||
})
|
s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d});
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
s.group[e.ke].mon[e.id].spawn.stdio[3].on('data',function(d){
|
||||||
|
if(!s.group[e.ke].mon[e.id].detectorFrameSaveBuffer){
|
||||||
|
s.group[e.ke].mon[e.id].detectorFrameSaveBuffer=[d]
|
||||||
|
}else{
|
||||||
|
s.group[e.ke].mon[e.id].detectorFrameSaveBuffer.push(d)
|
||||||
|
}
|
||||||
|
if(d[d.length-2] === 0xFF && d[d.length-1] === 0xD9){
|
||||||
|
var buffer = Buffer.concat(s.group[e.ke].mon[e.id].detectorFrameSaveBuffer);
|
||||||
|
var frameLocation = s.dir.streams + e.ke + '/' + e.id + '/' + s.gid(5) + '.jpg'
|
||||||
|
if(s.ocv){
|
||||||
|
fs.writeFile(frameLocation,buffer,function(err){
|
||||||
|
if(err){
|
||||||
|
s.debugLog(err)
|
||||||
|
}else{
|
||||||
|
s.ocvTx({f:'frameFromRam',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frameLocation:frameLocation})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
s.group[e.ke].mon[e.id].detectorFrameSaveBuffer = null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//frames to stream
|
//frames to stream
|
||||||
|
@ -1192,6 +1223,92 @@ module.exports = function(s,config,lang){
|
||||||
}catch(err){}
|
}catch(err){}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
s.addOrEditMonitor = function(form,callback,user){
|
||||||
|
var endData = {
|
||||||
|
ok: false
|
||||||
|
}
|
||||||
|
if(!form.mid){
|
||||||
|
endData.msg = lang['No Monitor ID Present in Form']
|
||||||
|
callback(endData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
form.mid = form.mid.replace(/[^\w\s]/gi,'').replace(/ /g,'')
|
||||||
|
form = s.cleanMonitorObjectForDatabase(form)
|
||||||
|
s.sqlQuery('SELECT * FROM Monitors WHERE ke=? AND mid=?',[form.ke,form.mid],function(er,r){
|
||||||
|
var affectMonitor = false
|
||||||
|
var monitorQuery = []
|
||||||
|
var monitorQueryValues = []
|
||||||
|
var txData = {
|
||||||
|
f: 'monitor_edit',
|
||||||
|
mid: form.mid,
|
||||||
|
ke: form.ke,
|
||||||
|
mon: form
|
||||||
|
}
|
||||||
|
if(r&&r[0]){
|
||||||
|
txData.new = false
|
||||||
|
Object.keys(form).forEach(function(v){
|
||||||
|
if(form[v]&&form[v]!==''){
|
||||||
|
monitorQuery.push(v+'=?')
|
||||||
|
if(form[v] instanceof Object){
|
||||||
|
form[v] = s.s(form[v])
|
||||||
|
}
|
||||||
|
monitorQueryValues.push(form[v])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
monitorQuery = monitorQuery.join(',')
|
||||||
|
monitorQueryValues.push(form.ke)
|
||||||
|
monitorQueryValues.push(form.mid)
|
||||||
|
s.userLog(form,{type:'Monitor Updated',msg:'by user : '+user.uid})
|
||||||
|
endData.msg = user.lang['Monitor Updated by user']+' : '+user.uid
|
||||||
|
s.sqlQuery('UPDATE Monitors SET '+monitorQuery+' WHERE ke=? AND mid=?',monitorQueryValues)
|
||||||
|
affectMonitor = true
|
||||||
|
}else if(
|
||||||
|
!s.group[form.ke].init.max_camera ||
|
||||||
|
s.group[form.ke].init.max_camera === '' ||
|
||||||
|
Object.keys(s.group[form.ke].mon).length <= parseInt(s.group[form.ke].init.max_camera)
|
||||||
|
){
|
||||||
|
txData.new = true
|
||||||
|
monitorQueryInsertValues = []
|
||||||
|
Object.keys(form).forEach(function(v){
|
||||||
|
if(form[v] && form[v] !== ''){
|
||||||
|
monitorQuery.push(v)
|
||||||
|
monitorQueryInsertValues.push('?')
|
||||||
|
if(form[v] instanceof Object){
|
||||||
|
form[v] = s.s(form[v])
|
||||||
|
}
|
||||||
|
monitorQueryValues.push(form[v])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
monitorQuery = monitorQuery.join(',')
|
||||||
|
monitorQueryInsertValues = monitorQueryInsertValues.join(',')
|
||||||
|
s.userLog(form,{type:'Monitor Added',msg:'by user : '+user.uid})
|
||||||
|
endData.msg = user.lang['Monitor Added by user']+' : '+user.uid
|
||||||
|
s.sqlQuery('INSERT INTO Monitors ('+monitorQuery+') VALUES ('+monitorQueryInsertValues+')',monitorQueryValues)
|
||||||
|
affectMonitor = true
|
||||||
|
}else{
|
||||||
|
txData.f = 'monitor_edit_failed'
|
||||||
|
txData.ff = 'max_reached'
|
||||||
|
endData.msg = user.lang.monitorEditFailedMaxReached
|
||||||
|
}
|
||||||
|
if(affectMonitor === true){
|
||||||
|
form.details = JSON.parse(form.details)
|
||||||
|
endData.ok = true
|
||||||
|
s.initiateMonitorObject({mid:form.mid,ke:form.ke})
|
||||||
|
s.group[form.ke].mon_conf[form.mid] = s.cleanMonitorObject(form)
|
||||||
|
if(form.mode === 'stop'){
|
||||||
|
s.camera('stop',form)
|
||||||
|
}else{
|
||||||
|
s.camera('stop',form)
|
||||||
|
setTimeout(function(){
|
||||||
|
s.camera(form.mode,form)
|
||||||
|
},5000)
|
||||||
|
}
|
||||||
|
s.tx(txData,'STR_'+form.ke)
|
||||||
|
}
|
||||||
|
s.tx(txData,'GRP_'+form.ke)
|
||||||
|
callback(!endData.ok,endData)
|
||||||
|
})
|
||||||
|
}
|
||||||
s.camera = function(x,e,cn){
|
s.camera = function(x,e,cn){
|
||||||
// x = function or mode
|
// x = function or mode
|
||||||
// e = monitor object
|
// e = monitor object
|
||||||
|
|
|
@ -30,8 +30,15 @@ module.exports = function(s,config,lang){
|
||||||
s.systemLog('Connected to plugin : Detector - '+d.plug+' - '+d.type)
|
s.systemLog('Connected to plugin : Detector - '+d.plug+' - '+d.type)
|
||||||
switch(d.type){
|
switch(d.type){
|
||||||
default:case'detector':
|
default:case'detector':
|
||||||
s.ocv={started:s.timeObject(),id:cn.id,plug:d.plug,notice:d.notice,isClientPlugin:true};
|
s.ocv = {
|
||||||
cn.ocv=1;
|
started: s.timeObject(),
|
||||||
|
id: cn.id,
|
||||||
|
plug: d.plug,
|
||||||
|
notice: d.notice,
|
||||||
|
isClientPlugin: true,
|
||||||
|
connectionType: d.connectionType
|
||||||
|
};
|
||||||
|
cn.ocv = 1;
|
||||||
s.tx({f:'detector_plugged',plug:d.plug,notice:d.notice},'CPU')
|
s.tx({f:'detector_plugged',plug:d.plug,notice:d.notice},'CPU')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +46,14 @@ module.exports = function(s,config,lang){
|
||||||
//is in host mode (camera.js is client)
|
//is in host mode (camera.js is client)
|
||||||
switch(d.type){
|
switch(d.type){
|
||||||
default:case'detector':
|
default:case'detector':
|
||||||
s.ocv={started:s.timeObject(),id:"host",plug:d.plug,notice:d.notice,isHostPlugin:true};
|
s.ocv = {
|
||||||
|
started:s.timeObject(),
|
||||||
|
id:"host",
|
||||||
|
plug:d.plug,
|
||||||
|
notice:d.notice,
|
||||||
|
isHostPlugin:true,
|
||||||
|
connectionType: d.connectionType
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ var spawn = require('child_process').spawn;
|
||||||
var jsonfile = require("jsonfile");
|
var jsonfile = require("jsonfile");
|
||||||
var onvif = require("node-onvif");
|
var onvif = require("node-onvif");
|
||||||
module.exports = function(s,config,lang,io){
|
module.exports = function(s,config,lang,io){
|
||||||
|
s.clientSocketConnection = {}
|
||||||
//send data to detector plugin
|
//send data to detector plugin
|
||||||
s.ocvTx=function(data){
|
s.ocvTx=function(data){
|
||||||
if(!s.ocv){return}
|
if(!s.ocv){return}
|
||||||
|
@ -426,7 +427,15 @@ module.exports = function(s,config,lang,io){
|
||||||
// if(!s.group[d.ke].vid)s.group[d.ke].vid={};
|
// if(!s.group[d.ke].vid)s.group[d.ke].vid={};
|
||||||
if(!s.group[d.ke].users)s.group[d.ke].users={};
|
if(!s.group[d.ke].users)s.group[d.ke].users={};
|
||||||
// s.group[d.ke].vid[cn.id]={uid:d.uid};
|
// s.group[d.ke].vid[cn.id]={uid:d.uid};
|
||||||
s.group[d.ke].users[d.auth]={cnid:cn.id,uid:r.uid,mail:r.mail,details:JSON.parse(r.details),logged_in_at:s.timeObject(new Date).format(),login_type:'Dashboard'}
|
s.group[d.ke].users[d.auth] = {
|
||||||
|
cnid: cn.id,
|
||||||
|
uid: r.uid,
|
||||||
|
mail: r.mail,
|
||||||
|
details: JSON.parse(r.details),
|
||||||
|
logged_in_at: s.timeObject(new Date).format(),
|
||||||
|
login_type: 'Dashboard'
|
||||||
|
}
|
||||||
|
s.clientSocketConnection[cn.id] = cn
|
||||||
try{s.group[d.ke].users[d.auth].details=JSON.parse(r.details)}catch(er){}
|
try{s.group[d.ke].users[d.auth].details=JSON.parse(r.details)}catch(er){}
|
||||||
if(s.group[d.ke].users[d.auth].details.get_server_log!=='0'){
|
if(s.group[d.ke].users[d.auth].details.get_server_log!=='0'){
|
||||||
cn.join('GRPLOG_'+d.ke)
|
cn.join('GRPLOG_'+d.ke)
|
||||||
|
@ -588,75 +597,8 @@ module.exports = function(s,config,lang,io){
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case'edit':
|
case'edit':
|
||||||
s.sqlQuery('SELECT details FROM Users WHERE ke=? AND uid=?',[d.ke,d.uid],function(err,r){
|
d.cnid = cn.id
|
||||||
if(r&&r[0]){
|
s.accountSettingsEdit(d)
|
||||||
r=r[0];
|
|
||||||
d.d=JSON.parse(r.details);
|
|
||||||
if(!d.d.sub || d.d.user_change === "1"){
|
|
||||||
if(d.d.get_server_log==='1'){
|
|
||||||
cn.join('GRPLOG_'+d.ke)
|
|
||||||
}else{
|
|
||||||
cn.leave('GRPLOG_'+d.ke)
|
|
||||||
}
|
|
||||||
///unchangeable from client side, so reset them in case they did.
|
|
||||||
d.form.details=JSON.parse(d.form.details)
|
|
||||||
s.beforeAccountSaveExtensions.forEach(function(extender){
|
|
||||||
extender(d)
|
|
||||||
})
|
|
||||||
//admin permissions
|
|
||||||
d.form.details.permissions=d.d.permissions
|
|
||||||
d.form.details.edit_size=d.d.edit_size
|
|
||||||
d.form.details.edit_days=d.d.edit_days
|
|
||||||
d.form.details.use_admin=d.d.use_admin
|
|
||||||
d.form.details.use_ldap=d.d.use_ldap
|
|
||||||
//check
|
|
||||||
if(d.d.edit_days=="0"){
|
|
||||||
d.form.details.days=d.d.days;
|
|
||||||
}
|
|
||||||
if(d.d.edit_size=="0"){
|
|
||||||
d.form.details.size=d.d.size;
|
|
||||||
}
|
|
||||||
if(d.d.sub){
|
|
||||||
d.form.details.sub=d.d.sub;
|
|
||||||
if(d.d.monitors){d.form.details.monitors=d.d.monitors;}
|
|
||||||
if(d.d.allmonitors){d.form.details.allmonitors=d.d.allmonitors;}
|
|
||||||
if(d.d.monitor_create){d.form.details.monitor_create=d.d.monitor_create;}
|
|
||||||
if(d.d.video_delete){d.form.details.video_delete=d.d.video_delete;}
|
|
||||||
if(d.d.video_view){d.form.details.video_view=d.d.video_view;}
|
|
||||||
if(d.d.monitor_edit){d.form.details.monitor_edit=d.d.monitor_edit;}
|
|
||||||
if(d.d.size){d.form.details.size=d.d.size;}
|
|
||||||
if(d.d.days){d.form.details.days=d.d.days;}
|
|
||||||
delete(d.form.details.mon_groups)
|
|
||||||
}
|
|
||||||
var newSize = d.form.details.size || 10000
|
|
||||||
d.form.details=JSON.stringify(d.form.details)
|
|
||||||
///
|
|
||||||
d.set=[],d.ar=[];
|
|
||||||
if(d.form.pass&&d.form.pass!==''){d.form.pass=s.createHash(d.form.pass);}else{delete(d.form.pass)};
|
|
||||||
delete(d.form.password_again);
|
|
||||||
d.for=Object.keys(d.form);
|
|
||||||
d.for.forEach(function(v){
|
|
||||||
d.set.push(v+'=?'),d.ar.push(d.form[v]);
|
|
||||||
});
|
|
||||||
d.ar.push(d.ke),d.ar.push(d.uid);
|
|
||||||
s.sqlQuery('UPDATE Users SET '+d.set.join(',')+' WHERE ke=? AND uid=?',d.ar,function(err,r){
|
|
||||||
if(!d.d.sub){
|
|
||||||
var user = Object.assign(d.form,{ke : d.ke})
|
|
||||||
var userDetails = JSON.parse(d.form.details)
|
|
||||||
s.group[d.ke].sizeLimit = parseFloat(newSize)
|
|
||||||
s.onAccountSaveExtensions.forEach(function(extender){
|
|
||||||
extender(s.group[d.ke],userDetails)
|
|
||||||
})
|
|
||||||
s.unloadGroupAppExtensions.forEach(function(extender){
|
|
||||||
extender(user)
|
|
||||||
})
|
|
||||||
s.loadGroupApps(d)
|
|
||||||
}
|
|
||||||
tx({f:'user_settings_change',uid:d.uid,ke:d.ke,form:d.form});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1428,6 +1370,7 @@ module.exports = function(s,config,lang,io){
|
||||||
if(cn.superSessionKey){
|
if(cn.superSessionKey){
|
||||||
delete(s.superUsersApi[cn.superSessionKey])
|
delete(s.superUsersApi[cn.superSessionKey])
|
||||||
}
|
}
|
||||||
|
delete(s.clientSocketConnection[cn.id])
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
10
libs/sql.js
10
libs/sql.js
|
@ -50,6 +50,9 @@ module.exports = function(s,config){
|
||||||
if(!onMoveOn){onMoveOn=function(){}}
|
if(!onMoveOn){onMoveOn=function(){}}
|
||||||
var mergedQuery = s.mergeQueryValues(query,values)
|
var mergedQuery = s.mergeQueryValues(query,values)
|
||||||
s.debugLog('s.sqlQuery QUERY',mergedQuery)
|
s.debugLog('s.sqlQuery QUERY',mergedQuery)
|
||||||
|
if(!s.databaseEngine || !s.databaseEngine.raw){
|
||||||
|
s.connectDatabase()
|
||||||
|
}
|
||||||
return s.databaseEngine
|
return s.databaseEngine
|
||||||
.raw(query,values)
|
.raw(query,values)
|
||||||
.asCallback(function(err,r){
|
.asCallback(function(err,r){
|
||||||
|
@ -70,11 +73,18 @@ module.exports = function(s,config){
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
s.connectDatabase = function(){
|
||||||
|
s.databaseEngine = require('knex')(s.databaseOptions)
|
||||||
|
}
|
||||||
s.preQueries = function(){
|
s.preQueries = function(){
|
||||||
//add Cloud Videos table, will remove in future
|
//add Cloud Videos table, will remove in future
|
||||||
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Cloud Videos` (`mid` varchar(50) NOT NULL,`ke` varchar(50) DEFAULT NULL,`href` text NOT NULL,`size` float DEFAULT NULL,`time` timestamp NULL DEFAULT NULL,`end` timestamp NULL DEFAULT NULL,`status` int(1) DEFAULT \'0\' COMMENT \'0:Complete,1:Read,2:Archive\',`details` text) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;',[],function(err){
|
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Cloud Videos` (`mid` varchar(50) NOT NULL,`ke` varchar(50) DEFAULT NULL,`href` text NOT NULL,`size` float DEFAULT NULL,`time` timestamp NULL DEFAULT NULL,`end` timestamp NULL DEFAULT NULL,`status` int(1) DEFAULT \'0\' COMMENT \'0:Complete,1:Read,2:Archive\',`details` text) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;',[],function(err){
|
||||||
// if(err)console.log(err)
|
// if(err)console.log(err)
|
||||||
},true)
|
},true)
|
||||||
|
//add monitorStates to Preset ENUM
|
||||||
|
s.sqlQuery('ALTER TABLE `Presets` CHANGE COLUMN `type` `type` VARCHAR(50) NULL DEFAULT NULL AFTER `details`;',[],function(err){
|
||||||
|
// if(err)console.log(err)
|
||||||
|
},true)
|
||||||
//create Files table
|
//create Files table
|
||||||
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Files` (`ke` varchar(50) NOT NULL,`mid` varchar(50) NOT NULL,`name` tinytext NOT NULL,`size` float NOT NULL DEFAULT \'0\',`details` text NOT NULL,`status` int(1) NOT NULL DEFAULT \'0\') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;',[],function(err){
|
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Files` (`ke` varchar(50) NOT NULL,`mid` varchar(50) NOT NULL,`name` tinytext NOT NULL,`size` float NOT NULL DEFAULT \'0\',`details` text NOT NULL,`status` int(1) NOT NULL DEFAULT \'0\') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;',[],function(err){
|
||||||
// if(err)console.log(err)
|
// if(err)console.log(err)
|
||||||
|
|
|
@ -29,6 +29,7 @@ module.exports = function(s,config,lang,io){
|
||||||
orphanedVideosForMonitors[monitor.ke][monitor.mid] += orphanedFilesCount
|
orphanedVideosForMonitors[monitor.ke][monitor.mid] += orphanedFilesCount
|
||||||
}
|
}
|
||||||
s.group[monitor.ke].mon_conf[monitor.mid] = monitor
|
s.group[monitor.ke].mon_conf[monitor.mid] = monitor
|
||||||
|
s.sendMonitorStatus({id:monitor.mid,ke:monitor.ke,status:'Stopped'});
|
||||||
var monObj = Object.assign(monitor,{id : monitor.mid})
|
var monObj = Object.assign(monitor,{id : monitor.mid})
|
||||||
s.camera(monitor.mode,monObj)
|
s.camera(monitor.mode,monObj)
|
||||||
++loadCompleted
|
++loadCompleted
|
||||||
|
|
75
libs/user.js
75
libs/user.js
|
@ -230,6 +230,79 @@ module.exports = function(s,config){
|
||||||
s.group[e.ke].init[v]=ar[v]
|
s.group[e.ke].init[v]=ar[v]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
}
|
||||||
|
s.accountSettingsEdit = function(d){
|
||||||
|
s.sqlQuery('SELECT details FROM Users WHERE ke=? AND uid=?',[d.ke,d.uid],function(err,r){
|
||||||
|
if(r&&r[0]){
|
||||||
|
r=r[0];
|
||||||
|
d.d=JSON.parse(r.details);
|
||||||
|
if(!d.d.sub || d.d.user_change !== "0"){
|
||||||
|
if(d.cnid){
|
||||||
|
if(d.d.get_server_log==='1'){
|
||||||
|
s.clientSocketConnection[d.cnid].join('GRPLOG_'+d.ke)
|
||||||
|
}else{
|
||||||
|
s.clientSocketConnection[d.cnid].leave('GRPLOG_'+d.ke)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///unchangeable from client side, so reset them in case they did.
|
||||||
|
d.form.details=JSON.parse(d.form.details)
|
||||||
|
s.beforeAccountSaveExtensions.forEach(function(extender){
|
||||||
|
extender(d)
|
||||||
|
})
|
||||||
|
//admin permissions
|
||||||
|
d.form.details.permissions=d.d.permissions
|
||||||
|
d.form.details.edit_size=d.d.edit_size
|
||||||
|
d.form.details.edit_days=d.d.edit_days
|
||||||
|
d.form.details.use_admin=d.d.use_admin
|
||||||
|
d.form.details.use_ldap=d.d.use_ldap
|
||||||
|
//check
|
||||||
|
if(d.d.edit_days=="0"){
|
||||||
|
d.form.details.days=d.d.days;
|
||||||
|
}
|
||||||
|
if(d.d.edit_size=="0"){
|
||||||
|
d.form.details.size=d.d.size;
|
||||||
|
}
|
||||||
|
if(d.d.sub){
|
||||||
|
d.form.details.sub=d.d.sub;
|
||||||
|
if(d.d.monitors){d.form.details.monitors=d.d.monitors;}
|
||||||
|
if(d.d.allmonitors){d.form.details.allmonitors=d.d.allmonitors;}
|
||||||
|
if(d.d.monitor_create){d.form.details.monitor_create=d.d.monitor_create;}
|
||||||
|
if(d.d.video_delete){d.form.details.video_delete=d.d.video_delete;}
|
||||||
|
if(d.d.video_view){d.form.details.video_view=d.d.video_view;}
|
||||||
|
if(d.d.monitor_edit){d.form.details.monitor_edit=d.d.monitor_edit;}
|
||||||
|
if(d.d.size){d.form.details.size=d.d.size;}
|
||||||
|
if(d.d.days){d.form.details.days=d.d.days;}
|
||||||
|
delete(d.form.details.mon_groups)
|
||||||
|
}
|
||||||
|
var newSize = d.form.details.size || 10000
|
||||||
|
d.form.details=JSON.stringify(d.form.details)
|
||||||
|
///
|
||||||
|
d.set=[],d.ar=[];
|
||||||
|
if(d.form.pass&&d.form.pass!==''){d.form.pass=s.createHash(d.form.pass);}else{delete(d.form.pass)};
|
||||||
|
delete(d.form.password_again);
|
||||||
|
d.for=Object.keys(d.form);
|
||||||
|
d.for.forEach(function(v){
|
||||||
|
d.set.push(v+'=?'),d.ar.push(d.form[v]);
|
||||||
|
});
|
||||||
|
d.ar.push(d.ke),d.ar.push(d.uid);
|
||||||
|
s.sqlQuery('UPDATE Users SET '+d.set.join(',')+' WHERE ke=? AND uid=?',d.ar,function(err,r){
|
||||||
|
if(!d.d.sub){
|
||||||
|
var user = Object.assign(d.form,{ke : d.ke})
|
||||||
|
var userDetails = JSON.parse(d.form.details)
|
||||||
|
s.group[d.ke].sizeLimit = parseFloat(newSize)
|
||||||
|
s.onAccountSaveExtensions.forEach(function(extender){
|
||||||
|
extender(s.group[d.ke],userDetails)
|
||||||
|
})
|
||||||
|
s.unloadGroupAppExtensions.forEach(function(extender){
|
||||||
|
extender(user)
|
||||||
|
})
|
||||||
|
s.loadGroupApps(d)
|
||||||
|
}
|
||||||
|
if(d.cnid)s.tx({f:'user_settings_change',uid:d.uid,ke:d.ke,form:d.form},d.cnid)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,17 +230,69 @@ module.exports = function(s,config,lang){
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
var videoSnap = s.dir.videoSnaps + e.ke + '/' + e.mid + '/' + filename.split('.')[0] + '.jpg'
|
|
||||||
fs.chmod(videoSnap,0o777,function(err){
|
fs.chmod(videoSnap,0o777,function(err){
|
||||||
if(!err){
|
if(!err){
|
||||||
fs.unlink(videoSnap,function(err){})
|
fs.unlink(videoSnap,function(err){})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
|
console.log(new Error())
|
||||||
console.log(lang['Database row does not exist'],queryValues)
|
console.log(lang['Database row does not exist'],queryValues)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
s.deleteListOfVideos = function(videos){
|
||||||
|
var query = 'DELETE FROM Videos WHERE '
|
||||||
|
var videoQuery = []
|
||||||
|
var queryValues = []
|
||||||
|
videos.forEach(function(video){
|
||||||
|
s.checkDetails(video)
|
||||||
|
//e = video object
|
||||||
|
video.dir = s.getVideoDirectory(video)
|
||||||
|
if(!video.filename && video.time){
|
||||||
|
video.filename = s.formattedTime(video.time)
|
||||||
|
}
|
||||||
|
var filename,
|
||||||
|
time
|
||||||
|
if(video.filename.indexOf('.')>-1){
|
||||||
|
filename = video.filename
|
||||||
|
}else{
|
||||||
|
filename = video.filename+'.'+video.ext
|
||||||
|
}
|
||||||
|
if(video.filename && !video.time){
|
||||||
|
time = s.nameToTime(filename)
|
||||||
|
}else{
|
||||||
|
time = video.time
|
||||||
|
}
|
||||||
|
time = new Date(time)
|
||||||
|
fs.chmod(video.dir+filename,0o777,function(err){
|
||||||
|
s.tx({
|
||||||
|
f: 'video_delete',
|
||||||
|
filename: filename,
|
||||||
|
mid: video.id,
|
||||||
|
ke: video.ke,
|
||||||
|
time: s.nameToTime(filename),
|
||||||
|
end: s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')
|
||||||
|
},'GRP_'+video.ke);
|
||||||
|
s.setDiskUsedForGroup(video,-(video.size / 1000000))
|
||||||
|
fs.unlink(video.dir+filename,function(err){
|
||||||
|
fs.stat(video.dir+filename,function(err){
|
||||||
|
if(!err){
|
||||||
|
s.file('delete',video.dir+filename)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
videoQuery.push('(`mid`=? AND `ke`=? AND `time`=?)')
|
||||||
|
queryValues = queryValues.concat([video.id,video.ke,time])
|
||||||
|
})
|
||||||
|
query += videoQuery.join(' OR ')
|
||||||
|
s.sqlQuery(query,queryValues,function(err){
|
||||||
|
if(err){
|
||||||
|
s.systemLog(lang['List of Videos Delete Error'],err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
s.deleteVideoFromCloudExtensions = {}
|
s.deleteVideoFromCloudExtensions = {}
|
||||||
s.deleteVideoFromCloudExtensionsRunner = function(e,storageType,video){
|
s.deleteVideoFromCloudExtensionsRunner = function(e,storageType,video){
|
||||||
// e = user
|
// e = user
|
||||||
|
|
|
@ -4,7 +4,52 @@ var https = require('https');
|
||||||
var express = require('express');
|
var express = require('express');
|
||||||
var app = express()
|
var app = express()
|
||||||
module.exports = function(s,config,lang,io){
|
module.exports = function(s,config,lang,io){
|
||||||
var server = http.createServer(app);
|
//get page URL
|
||||||
|
if(!config.baseURL){
|
||||||
|
config.baseURL = ""
|
||||||
|
}else if(config.baseURL !== ''){
|
||||||
|
config.baseURL = s.checkCorrectPathEnding(config.baseURL)
|
||||||
|
}
|
||||||
|
//Render Configurations - Web Paths
|
||||||
|
if(config.webPaths === undefined){config.webPaths={}}
|
||||||
|
//main access URI
|
||||||
|
if(config.webPaths.home === undefined){config.webPaths.home='/'}
|
||||||
|
//Super User URI
|
||||||
|
if(config.webPaths.super === undefined){config.webPaths.super='/super'}
|
||||||
|
//Admin URI
|
||||||
|
if(config.webPaths.admin === undefined){config.webPaths.admin='/admin'}
|
||||||
|
//Libraries URI
|
||||||
|
if(config.webPaths.libs === undefined){config.webPaths.libs='/libs'}
|
||||||
|
//API Prefix
|
||||||
|
if(config.webPaths.apiPrefix === undefined){config.webPaths.apiPrefix = s.checkCorrectPathEnding(config.webPaths.home)}else{config.webPaths.apiPrefix = s.checkCorrectPathEnding(config.webPaths.apiPrefix)}
|
||||||
|
//Admin API Prefix
|
||||||
|
if(config.webPaths.adminApiPrefix === undefined){config.webPaths.adminApiPrefix=s.checkCorrectPathEnding(config.webPaths.admin)}else{config.webPaths.adminApiPrefix = s.checkCorrectPathEnding(config.webPaths.adminApiPrefix)}
|
||||||
|
//Super API Prefix
|
||||||
|
if(config.webPaths.superApiPrefix === undefined){config.webPaths.superApiPrefix=s.checkCorrectPathEnding(config.webPaths.super)}else{config.webPaths.superApiPrefix = s.checkCorrectPathEnding(config.webPaths.superApiPrefix)}
|
||||||
|
//Render Configurations - Page Render Paths
|
||||||
|
if(config.renderPaths === undefined){config.renderPaths={}}
|
||||||
|
//login page
|
||||||
|
if(config.renderPaths.index === undefined){config.renderPaths.index='pages/index'}
|
||||||
|
//dashboard page
|
||||||
|
if(config.renderPaths.home === undefined){config.renderPaths.home='pages/home'}
|
||||||
|
//sub-account administration page
|
||||||
|
if(config.renderPaths.admin === undefined){config.renderPaths.admin='pages/admin'}
|
||||||
|
//superuser page
|
||||||
|
if(config.renderPaths.super === undefined){config.renderPaths.super='pages/super'}
|
||||||
|
//2-Factor Auth page
|
||||||
|
if(config.renderPaths.factorAuth === undefined){config.renderPaths.factorAuth='pages/factor'}
|
||||||
|
//Streamer v1 (Dashcam Prototype) page
|
||||||
|
if(config.renderPaths.streamer === undefined){config.renderPaths.streamer='pages/streamer'}
|
||||||
|
//Streamer v2 (Dashcam) page
|
||||||
|
if(config.renderPaths.dashcam === undefined){config.renderPaths.dashcam='pages/dashcam'}
|
||||||
|
//embeddable widget page
|
||||||
|
if(config.renderPaths.embed === undefined){config.renderPaths.embed='pages/embed'}
|
||||||
|
//mjpeg full screen page
|
||||||
|
if(config.renderPaths.mjpeg === undefined){config.renderPaths.mjpeg='pages/mjpeg'}
|
||||||
|
//gridstack only page
|
||||||
|
if(config.renderPaths.grid === undefined){config.renderPaths.grid='pages/grid'}
|
||||||
|
//slick.js (cycle) page
|
||||||
|
if(config.renderPaths.cycle === undefined){config.renderPaths.cycle='pages/cycle'}
|
||||||
//SSL options
|
//SSL options
|
||||||
if(config.ssl&&config.ssl.key&&config.ssl.cert){
|
if(config.ssl&&config.ssl.key&&config.ssl.cert){
|
||||||
config.ssl.key=fs.readFileSync(s.checkRelativePath(config.ssl.key),'utf8')
|
config.ssl.key=fs.readFileSync(s.checkRelativePath(config.ssl.key),'utf8')
|
||||||
|
@ -24,12 +69,47 @@ module.exports = function(s,config,lang,io){
|
||||||
serverHTTPS.listen(config.ssl.port,config.bindip,function(){
|
serverHTTPS.listen(config.ssl.port,config.bindip,function(){
|
||||||
console.log('SSL '+lang.Shinobi+' : SSL Web Server Listening on '+config.ssl.port);
|
console.log('SSL '+lang.Shinobi+' : SSL Web Server Listening on '+config.ssl.port);
|
||||||
});
|
});
|
||||||
io.attach(serverHTTPS);
|
if(config.webPaths.home !== '/'){
|
||||||
|
io.attach(serverHTTPS,{
|
||||||
|
path:'/socket.io',
|
||||||
|
transports: ['websocket']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
io.attach(serverHTTPS,{
|
||||||
|
path:s.checkCorrectPathEnding(config.webPaths.home)+'socket.io',
|
||||||
|
transports: ['websocket']
|
||||||
|
})
|
||||||
|
io.attach(serverHTTPS,{
|
||||||
|
path:s.checkCorrectPathEnding(config.webPaths.admin)+'socket.io',
|
||||||
|
transports: ['websocket']
|
||||||
|
})
|
||||||
|
io.attach(serverHTTPS,{
|
||||||
|
path:s.checkCorrectPathEnding(config.webPaths.super)+'socket.io',
|
||||||
|
transports: ['websocket']
|
||||||
|
})
|
||||||
}
|
}
|
||||||
//start HTTP
|
//start HTTP
|
||||||
|
var server = http.createServer(app);
|
||||||
server.listen(config.port,config.bindip,function(){
|
server.listen(config.port,config.bindip,function(){
|
||||||
console.log(lang.Shinobi+' : Web Server Listening on '+config.port);
|
console.log(lang.Shinobi+' : Web Server Listening on '+config.port);
|
||||||
});
|
});
|
||||||
io.attach(server);
|
if(config.webPaths.home !== '/'){
|
||||||
|
io.attach(server,{
|
||||||
|
path:'/socket.io',
|
||||||
|
transports: ['websocket']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
io.attach(server,{
|
||||||
|
path:s.checkCorrectPathEnding(config.webPaths.home)+'socket.io',
|
||||||
|
transports: ['websocket']
|
||||||
|
})
|
||||||
|
io.attach(server,{
|
||||||
|
path:s.checkCorrectPathEnding(config.webPaths.admin)+'socket.io',
|
||||||
|
transports: ['websocket']
|
||||||
|
})
|
||||||
|
io.attach(server,{
|
||||||
|
path:s.checkCorrectPathEnding(config.webPaths.super)+'socket.io',
|
||||||
|
transports: ['websocket']
|
||||||
|
})
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,6 @@ var exec = require('child_process').exec;
|
||||||
var spawn = require('child_process').spawn;
|
var spawn = require('child_process').spawn;
|
||||||
var execSync = require('child_process').execSync;
|
var execSync = require('child_process').execSync;
|
||||||
module.exports = function(s,config,lang,app){
|
module.exports = function(s,config,lang,app){
|
||||||
var closeResponse = function(res,endData){
|
|
||||||
res.setHeader('Content-Type', 'application/json')
|
|
||||||
res.end(s.prettyPrint(endData))
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* API : Administrator : Edit Sub-Account (Account to share cameras with)
|
* API : Administrator : Edit Sub-Account (Account to share cameras with)
|
||||||
*/
|
*/
|
||||||
|
@ -21,7 +17,7 @@ module.exports = function(s,config,lang,app){
|
||||||
}
|
}
|
||||||
if(user.details.sub){
|
if(user.details.sub){
|
||||||
endData.msg = user.lang['Not Permitted']
|
endData.msg = user.lang['Not Permitted']
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var form = s.getPostData(req)
|
var form = s.getPostData(req)
|
||||||
|
@ -56,7 +52,7 @@ module.exports = function(s,config,lang,app){
|
||||||
}else{
|
}else{
|
||||||
endData.msg = lang.postDataBroken
|
endData.msg = lang.postDataBroken
|
||||||
}
|
}
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
},res,req)
|
},res,req)
|
||||||
})
|
})
|
||||||
/**
|
/**
|
||||||
|
@ -69,7 +65,7 @@ module.exports = function(s,config,lang,app){
|
||||||
}
|
}
|
||||||
if(user.details.sub){
|
if(user.details.sub){
|
||||||
endData.msg = user.lang['Not Permitted']
|
endData.msg = user.lang['Not Permitted']
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var uid = s.getPostData(req,'uid',false)
|
var uid = s.getPostData(req,'uid',false)
|
||||||
|
@ -90,7 +86,7 @@ module.exports = function(s,config,lang,app){
|
||||||
mail: mail
|
mail: mail
|
||||||
},'ADM_'+req.params.ke)
|
},'ADM_'+req.params.ke)
|
||||||
endData.ok = true
|
endData.ok = true
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
},res,req)
|
},res,req)
|
||||||
})
|
})
|
||||||
/**
|
/**
|
||||||
|
@ -109,7 +105,7 @@ module.exports = function(s,config,lang,app){
|
||||||
s.auth(req.params,function(user){
|
s.auth(req.params,function(user){
|
||||||
if(user.details.sub){
|
if(user.details.sub){
|
||||||
endData.msg = user.lang['Not an Administrator Account']
|
endData.msg = user.lang['Not an Administrator Account']
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var form = s.getPostData(req)
|
var form = s.getPostData(req)
|
||||||
|
@ -159,7 +155,9 @@ module.exports = function(s,config,lang,app){
|
||||||
config.webPaths.adminApiPrefix+':auth/configureMonitor/:ke/:id',
|
config.webPaths.adminApiPrefix+':auth/configureMonitor/:ke/:id',
|
||||||
config.webPaths.adminApiPrefix+':auth/configureMonitor/:ke/:id/:f'
|
config.webPaths.adminApiPrefix+':auth/configureMonitor/:ke/:id/:f'
|
||||||
], function (req,res){
|
], function (req,res){
|
||||||
req.ret={ok:false};
|
var endData = {
|
||||||
|
ok: false
|
||||||
|
}
|
||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
res.header("Access-Control-Allow-Origin",req.headers.origin);
|
res.header("Access-Control-Allow-Origin",req.headers.origin);
|
||||||
s.auth(req.params,function(user){
|
s.auth(req.params,function(user){
|
||||||
|
@ -167,88 +165,28 @@ module.exports = function(s,config,lang,app){
|
||||||
if(req.params.f !== 'delete'){
|
if(req.params.f !== 'delete'){
|
||||||
var form = s.getPostData(req)
|
var form = s.getPostData(req)
|
||||||
if(!form){
|
if(!form){
|
||||||
req.ret.msg = user.lang.monitorEditText1;
|
endData.msg = user.lang.monitorEditText1;
|
||||||
res.end(s.prettyPrint(req.ret))
|
res.end(s.prettyPrint(endData))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
form.mid = req.params.id.replace(/[^\w\s]/gi,'').replace(/ /g,'')
|
||||||
if(!user.details.sub ||
|
if(!user.details.sub ||
|
||||||
user.details.allmonitors === '1' ||
|
user.details.allmonitors === '1' ||
|
||||||
hasRestrictions && user.details.monitor_edit.indexOf(form.mid) >- 1 ||
|
hasRestrictions && user.details.monitor_edit.indexOf(form.mid) >- 1 ||
|
||||||
hasRestrictions && user.details.monitor_create === '1'){
|
hasRestrictions && user.details.monitor_create === '1'){
|
||||||
if(form&&form.mid&&form.name){
|
if(form && form.name){
|
||||||
req.set=[],req.ar=[];
|
s.checkDetails(form)
|
||||||
form.mid=req.params.id.replace(/[^\w\s]/gi,'').replace(/ /g,'');
|
form.ke = req.params.ke
|
||||||
try{
|
s.addOrEditMonitor(form,function(err,endData){
|
||||||
JSON.parse(form.details)
|
res.end(s.prettyPrint(endData))
|
||||||
}catch(er){
|
},user)
|
||||||
if(!form.details||!form.details.stream_type){
|
|
||||||
req.ret.msg=user.lang.monitorEditText2;
|
|
||||||
res.end(s.prettyPrint(req.ret))
|
|
||||||
return
|
|
||||||
}else{
|
|
||||||
form.details=JSON.stringify(form.details)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
form.ke=req.params.ke
|
|
||||||
req.logObject={details:JSON.parse(form.details),ke:req.params.ke,mid:req.params.id}
|
|
||||||
s.sqlQuery('SELECT * FROM Monitors WHERE ke=? AND mid=?',[form.ke,form.mid],function(er,r){
|
|
||||||
req.tx={f:'monitor_edit',mid:form.mid,ke:form.ke,mon:form};
|
|
||||||
if(r&&r[0]){
|
|
||||||
req.tx.new=false;
|
|
||||||
Object.keys(form).forEach(function(v){
|
|
||||||
if(form[v]&&form[v]!==''){
|
|
||||||
req.set.push(v+'=?'),req.ar.push(form[v]);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
req.set=req.set.join(',');
|
|
||||||
req.ar.push(form.ke),req.ar.push(form.mid);
|
|
||||||
s.userLog(form,{type:'Monitor Updated',msg:'by user : '+user.uid});
|
|
||||||
req.ret.msg=user.lang['Monitor Updated by user']+' : '+user.uid;
|
|
||||||
s.sqlQuery('UPDATE Monitors SET '+req.set+' WHERE ke=? AND mid=?',req.ar)
|
|
||||||
req.finish=1;
|
|
||||||
}else{
|
|
||||||
if(!s.group[form.ke].init.max_camera||s.group[form.ke].init.max_camera==''||Object.keys(s.group[form.ke].mon).length <= parseInt(s.group[form.ke].init.max_camera)){
|
|
||||||
req.tx.new=true;
|
|
||||||
req.st=[];
|
|
||||||
Object.keys(form).forEach(function(v){
|
|
||||||
if(form[v]&&form[v]!==''){
|
|
||||||
req.set.push(v),req.st.push('?'),req.ar.push(form[v]);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// req.set.push('ke'),req.st.push('?'),req.ar.push(form.ke);
|
|
||||||
req.set=req.set.join(','),req.st=req.st.join(',');
|
|
||||||
s.userLog(form,{type:'Monitor Added',msg:'by user : '+user.uid});
|
|
||||||
req.ret.msg=user.lang['Monitor Added by user']+' : '+user.uid;
|
|
||||||
s.sqlQuery('INSERT INTO Monitors ('+req.set+') VALUES ('+req.st+')',req.ar)
|
|
||||||
req.finish=1;
|
|
||||||
}else{
|
|
||||||
req.tx.f='monitor_edit_failed';
|
|
||||||
req.tx.ff='max_reached';
|
|
||||||
req.ret.msg=user.lang.monitorEditFailedMaxReached;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(req.finish===1){
|
|
||||||
form.details=JSON.parse(form.details)
|
|
||||||
req.ret.ok=true;
|
|
||||||
s.initiateMonitorObject({mid:form.mid,ke:form.ke});
|
|
||||||
s.group[form.ke].mon_conf[form.mid]=s.cleanMonitorObject(form);
|
|
||||||
if(form.mode==='stop'){
|
|
||||||
s.camera('stop',form);
|
|
||||||
}else{
|
|
||||||
s.camera('stop',form);setTimeout(function(){s.camera(form.mode,form);},5000)
|
|
||||||
};
|
|
||||||
s.tx(req.tx,'STR_'+form.ke);
|
|
||||||
};
|
|
||||||
s.tx(req.tx,'GRP_'+form.ke);
|
|
||||||
res.end(s.prettyPrint(req.ret))
|
|
||||||
})
|
|
||||||
}else{
|
}else{
|
||||||
req.ret.msg=user.lang.monitorEditText1;
|
endData.msg = user.lang.monitorEditText1;
|
||||||
res.end(s.prettyPrint(req.ret))
|
res.end(s.prettyPrint(endData))
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
req.ret.msg=user.lang['Not Permitted'];
|
endData.msg = user.lang['Not Permitted']
|
||||||
res.end(s.prettyPrint(req.ret))
|
res.end(s.prettyPrint(endData))
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(!user.details.sub || user.details.allmonitors === '1' || user.details.monitor_edit.indexOf(req.params.id) > -1 || hasRestrictions && user.details.monitor_create === '1'){
|
if(!user.details.sub || user.details.allmonitors === '1' || user.details.monitor_edit.indexOf(req.params.id) > -1 || hasRestrictions && user.details.monitor_create === '1'){
|
||||||
|
@ -281,12 +219,12 @@ module.exports = function(s,config,lang,app){
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
req.ret.ok=true;
|
endData.ok=true;
|
||||||
req.ret.msg='Monitor Deleted by user : '+user.uid
|
endData.msg='Monitor Deleted by user : '+user.uid
|
||||||
res.end(s.prettyPrint(req.ret))
|
res.end(s.prettyPrint(endData))
|
||||||
}else{
|
}else{
|
||||||
req.ret.msg=user.lang['Not Permitted'];
|
endData.msg=user.lang['Not Permitted'];
|
||||||
res.end(s.prettyPrint(req.ret))
|
res.end(s.prettyPrint(endData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},res,req)
|
},res,req)
|
||||||
|
@ -328,11 +266,11 @@ module.exports = function(s,config,lang,app){
|
||||||
},'GRP_' + req.params.ke)
|
},'GRP_' + req.params.ke)
|
||||||
endData.ok = true
|
endData.ok = true
|
||||||
}
|
}
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
endData.msg = lang.postDataBroken
|
endData.msg = lang.postDataBroken
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
}
|
}
|
||||||
},res,req)
|
},res,req)
|
||||||
})
|
})
|
||||||
|
@ -359,7 +297,7 @@ module.exports = function(s,config,lang,app){
|
||||||
form:'APIs'
|
form:'APIs'
|
||||||
},'GRP_' + req.params.ke)
|
},'GRP_' + req.params.ke)
|
||||||
endData.msg = lang.postDataBroken
|
endData.msg = lang.postDataBroken
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var row = {
|
var row = {
|
||||||
|
@ -381,11 +319,11 @@ module.exports = function(s,config,lang,app){
|
||||||
endData.ok = true
|
endData.ok = true
|
||||||
delete(s.api[row.code])
|
delete(s.api[row.code])
|
||||||
}
|
}
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
endData.msg = lang.postDataBroken
|
endData.msg = lang.postDataBroken
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
}
|
}
|
||||||
},res,req)
|
},res,req)
|
||||||
})
|
})
|
||||||
|
@ -421,8 +359,143 @@ module.exports = function(s,config,lang,app){
|
||||||
endData.ke = user.ke
|
endData.ke = user.ke
|
||||||
endData.keys = rows
|
endData.keys = rows
|
||||||
}
|
}
|
||||||
closeResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
})
|
})
|
||||||
},res,req)
|
},res,req)
|
||||||
})
|
})
|
||||||
|
/**
|
||||||
|
* API : Administrator : Change Group Preset. Currently affects Monitors only.
|
||||||
|
*/
|
||||||
|
app.all([
|
||||||
|
config.webPaths.apiPrefix+':auth/monitorStates/:ke/:stateName',
|
||||||
|
config.webPaths.apiPrefix+':auth/monitorStates/:ke/:stateName/:action',
|
||||||
|
config.webPaths.adminApiPrefix+':auth/monitorStates/:ke/:stateName',
|
||||||
|
config.webPaths.adminApiPrefix+':auth/monitorStates/:ke/:stateName/:action',
|
||||||
|
],function (req,res){
|
||||||
|
s.auth(req.params,function(user){
|
||||||
|
var endData = {
|
||||||
|
ok : false
|
||||||
|
}
|
||||||
|
if(user.details.sub){
|
||||||
|
endData.msg = user.lang['Not Permitted']
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var findPreset = function(callback){
|
||||||
|
s.sqlQuery("SELECT * FROM Presets WHERE ke=? AND type=? AND name=? LIMIT 1",[req.params.ke,'monitorStates',req.params.stateName],function(err,presets){
|
||||||
|
var preset
|
||||||
|
var notFound = false
|
||||||
|
if(presets && presets[0]){
|
||||||
|
preset = presets[0]
|
||||||
|
s.checkDetails(preset)
|
||||||
|
}else{
|
||||||
|
notFound = true
|
||||||
|
}
|
||||||
|
callback(notFound,preset)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
switch(req.params.action){
|
||||||
|
case'insert':case'edit':
|
||||||
|
var form = s.getPostData(req)
|
||||||
|
s.checkDetails(form)
|
||||||
|
if(!form || !form.monitors){
|
||||||
|
endData.msg = user.lang['Form Data Not Found']
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
findPreset(function(notFound,preset){
|
||||||
|
if(notFound === true){
|
||||||
|
endData.msg = lang["Inserted State Configuration"]
|
||||||
|
var details = {
|
||||||
|
monitors : form.monitors
|
||||||
|
}
|
||||||
|
var insertData = {
|
||||||
|
ke: req.params.ke,
|
||||||
|
name: req.params.stateName,
|
||||||
|
details: s.s(details),
|
||||||
|
type: 'monitorStates'
|
||||||
|
}
|
||||||
|
s.sqlQuery('INSERT INTO Presets ('+Object.keys(insertData).join(',')+') VALUES (?,?,?,?)',Object.values(insertData))
|
||||||
|
s.tx({
|
||||||
|
f: 'add_group_state',
|
||||||
|
details: details,
|
||||||
|
ke: req.params.ke,
|
||||||
|
name: req.params.stateName
|
||||||
|
},'GRP_'+req.params.ke)
|
||||||
|
}else{
|
||||||
|
endData.msg = lang["Edited State Configuration"]
|
||||||
|
var details = Object.assign(preset.details,{
|
||||||
|
monitors : form.monitors
|
||||||
|
})
|
||||||
|
s.sqlQuery('UPDATE Presets SET details=? WHERE ke=? AND name=?',[s.s(details),req.params.ke,req.params.stateName])
|
||||||
|
s.tx({
|
||||||
|
f: 'edit_group_state',
|
||||||
|
details: details,
|
||||||
|
ke: req.params.ke,
|
||||||
|
name: req.params.stateName
|
||||||
|
},'GRP_'+req.params.ke)
|
||||||
|
}
|
||||||
|
endData.ok = true
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case'delete':
|
||||||
|
findPreset(function(notFound,preset){
|
||||||
|
if(notFound === true){
|
||||||
|
endData.msg = user.lang['State Configuration Not Found']
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
}else{
|
||||||
|
s.sqlQuery('DELETE FROM Presets WHERE ke=? AND name=?',[req.params.ke,req.params.stateName],function(err){
|
||||||
|
if(!err){
|
||||||
|
endData.msg = lang["Deleted State Configuration"]
|
||||||
|
endData.ok = true
|
||||||
|
}
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
default://change monitors according to state
|
||||||
|
findPreset(function(notFound,preset){
|
||||||
|
if(notFound === false){
|
||||||
|
var sqlQuery = 'SELECT * FROM Monitors WHERE ke=? AND '
|
||||||
|
var monitorQuery = []
|
||||||
|
var sqlQueryValues = [req.params.ke]
|
||||||
|
var monitorPresets = {}
|
||||||
|
preset.details.monitors.forEach(function(monitor){
|
||||||
|
monitorQuery.push('mid=?')
|
||||||
|
sqlQueryValues.push(monitor.mid)
|
||||||
|
monitorPresets[monitor.mid] = monitor
|
||||||
|
})
|
||||||
|
sqlQuery += '('+monitorQuery.join(' OR ')+')'
|
||||||
|
s.sqlQuery(sqlQuery,sqlQueryValues,function(err,monitors){
|
||||||
|
if(monitors && monitors[0]){
|
||||||
|
monitors.forEach(function(monitor){
|
||||||
|
s.checkDetails(monitor)
|
||||||
|
s.checkDetails(monitorPresets[monitor.mid])
|
||||||
|
var monitorPreset = monitorPresets[monitor.mid]
|
||||||
|
monitorPreset.details = Object.assign(monitor.details,monitorPreset.details)
|
||||||
|
monitor = s.cleanMonitorObjectForDatabase(Object.assign(monitor,monitorPreset))
|
||||||
|
monitor.details = JSON.stringify(monitor.details)
|
||||||
|
s.addOrEditMonitor(Object.assign(monitor,{}),function(err,endData){
|
||||||
|
|
||||||
|
},user)
|
||||||
|
})
|
||||||
|
endData.ok = true
|
||||||
|
s.tx({f:'change_group_state',ke:req.params.ke,name:req.params.stateName},'GRP_'+req.params.ke)
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
}else{
|
||||||
|
endData.msg = user.lang['State Configuration has no monitors associated']
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
endData.msg = user.lang['State Configuration Not Found']
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},res,req)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,54 +11,15 @@ var httpProxy = require('http-proxy');
|
||||||
var proxy = httpProxy.createProxyServer({})
|
var proxy = httpProxy.createProxyServer({})
|
||||||
var ejs = require('ejs');
|
var ejs = require('ejs');
|
||||||
var CircularJSON = require('circular-json');
|
var CircularJSON = require('circular-json');
|
||||||
module.exports = function(s,config,lang,app){
|
module.exports = function(s,config,lang,app,io){
|
||||||
if(config.productType==='Pro'){
|
if(config.productType==='Pro'){
|
||||||
var LdapAuth = require('ldapauth-fork');
|
var LdapAuth = require('ldapauth-fork');
|
||||||
}
|
}
|
||||||
//get page URL
|
s.renderPage = function(req,res,paths,passables,callback){
|
||||||
if(!config.baseURL){
|
passables.window = {}
|
||||||
config.baseURL = ""
|
passables.originalURL = s.getOriginalUrl(req)
|
||||||
}else if(config.baseURL !== ''){
|
res.render(paths,passables,callback)
|
||||||
config.baseURL = s.checkCorrectPathEnding(config.baseURL)
|
|
||||||
}
|
}
|
||||||
//Render Configurations - Web Paths
|
|
||||||
if(config.webPaths === undefined){config.webPaths={}}
|
|
||||||
//main access URI
|
|
||||||
if(config.webPaths.home === undefined){config.webPaths.home='/'}
|
|
||||||
//Super User URI
|
|
||||||
if(config.webPaths.super === undefined){config.webPaths.super='/super'}
|
|
||||||
//Admin URI
|
|
||||||
if(config.webPaths.admin === undefined){config.webPaths.admin='/admin'}
|
|
||||||
//API Prefix
|
|
||||||
if(config.webPaths.apiPrefix === undefined){config.webPaths.apiPrefix='/'}else{config.webPaths.apiPrefix = s.checkCorrectPathEnding(config.webPaths.apiPrefix)}
|
|
||||||
//Admin API Prefix
|
|
||||||
if(config.webPaths.adminApiPrefix === undefined){config.webPaths.adminApiPrefix='/admin/'}else{config.webPaths.adminApiPrefix = s.checkCorrectPathEnding(config.webPaths.adminApiPrefix)}
|
|
||||||
//Super API Prefix
|
|
||||||
if(config.webPaths.superApiPrefix === undefined){config.webPaths.superApiPrefix='/super/'}else{config.webPaths.superApiPrefix = s.checkCorrectPathEnding(config.webPaths.superApiPrefix)}
|
|
||||||
//Render Configurations - Page Render Paths
|
|
||||||
if(config.renderPaths === undefined){config.renderPaths={}}
|
|
||||||
//login page
|
|
||||||
if(config.renderPaths.index === undefined){config.renderPaths.index='pages/index'}
|
|
||||||
//dashboard page
|
|
||||||
if(config.renderPaths.home === undefined){config.renderPaths.home='pages/home'}
|
|
||||||
//sub-account administration page
|
|
||||||
if(config.renderPaths.admin === undefined){config.renderPaths.admin='pages/admin'}
|
|
||||||
//superuser page
|
|
||||||
if(config.renderPaths.super === undefined){config.renderPaths.super='pages/super'}
|
|
||||||
//2-Factor Auth page
|
|
||||||
if(config.renderPaths.factorAuth === undefined){config.renderPaths.factorAuth='pages/factor'}
|
|
||||||
//Streamer v1 (Dashcam Prototype) page
|
|
||||||
if(config.renderPaths.streamer === undefined){config.renderPaths.streamer='pages/streamer'}
|
|
||||||
//Streamer v2 (Dashcam) page
|
|
||||||
if(config.renderPaths.dashcam === undefined){config.renderPaths.dashcam='pages/dashcam'}
|
|
||||||
//embeddable widget page
|
|
||||||
if(config.renderPaths.embed === undefined){config.renderPaths.embed='pages/embed'}
|
|
||||||
//mjpeg full screen page
|
|
||||||
if(config.renderPaths.mjpeg === undefined){config.renderPaths.mjpeg='pages/mjpeg'}
|
|
||||||
//gridstack only page
|
|
||||||
if(config.renderPaths.grid === undefined){config.renderPaths.grid='pages/grid'}
|
|
||||||
//slick.js (cycle) page
|
|
||||||
if(config.renderPaths.cycle === undefined){config.renderPaths.cycle='pages/cycle'}
|
|
||||||
//child node proxy check
|
//child node proxy check
|
||||||
//params = parameters
|
//params = parameters
|
||||||
//cb = callback
|
//cb = callback
|
||||||
|
@ -72,6 +33,10 @@ module.exports = function(s,config,lang,app){
|
||||||
cb()
|
cb()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s.closeJsonResponse = function(res,endData){
|
||||||
|
res.setHeader('Content-Type', 'application/json')
|
||||||
|
res.end(s.prettyPrint(endData))
|
||||||
|
}
|
||||||
//get post data
|
//get post data
|
||||||
s.getPostData = function(req,target,parseJSON){
|
s.getPostData = function(req,target,parseJSON){
|
||||||
if(!target)target = 'data'
|
if(!target)target = 'data'
|
||||||
|
@ -93,13 +58,18 @@ module.exports = function(s,config,lang,app){
|
||||||
}
|
}
|
||||||
////Pages
|
////Pages
|
||||||
app.enable('trust proxy');
|
app.enable('trust proxy');
|
||||||
app.use('/libs',express.static(s.mainDirectory + '/web/libs'));
|
if(config.webPaths.home !== '/'){
|
||||||
|
app.use('/libs',express.static(s.mainDirectory + '/web/libs'))
|
||||||
|
}
|
||||||
|
app.use(s.checkCorrectPathEnding(config.webPaths.home)+'libs',express.static(s.mainDirectory + '/web/libs'))
|
||||||
|
app.use(s.checkCorrectPathEnding(config.webPaths.admin)+'libs',express.static(s.mainDirectory + '/web/libs'))
|
||||||
|
app.use(s.checkCorrectPathEnding(config.webPaths.super)+'libs',express.static(s.mainDirectory + '/web/libs'))
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({extended: true}));
|
app.use(bodyParser.urlencoded({extended: true}));
|
||||||
app.set('views', s.mainDirectory + '/web');
|
app.set('views', s.mainDirectory + '/web');
|
||||||
app.set('view engine','ejs');
|
app.set('view engine','ejs');
|
||||||
//add template handler
|
//add template handler
|
||||||
if(config.renderPaths.handler!==undefined){require(s.mainDirectory+'/web/'+config.renderPaths.handler+'.js').addHandlers(s,app,io)}
|
if(config.renderPaths.handler!==undefined){require(s.mainDirectory+'/web/'+config.renderPaths.handler+'.js').addHandlers(s,app,io,config)}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API : Logout
|
* API : Logout
|
||||||
|
@ -118,7 +88,7 @@ module.exports = function(s,config,lang,app){
|
||||||
* Page : Login Screen
|
* Page : Login Screen
|
||||||
*/
|
*/
|
||||||
app.get(config.webPaths.home, function (req,res){
|
app.get(config.webPaths.home, function (req,res){
|
||||||
res.render(config.renderPaths.index,{lang:lang,config:config,screen:'dashboard',originalURL:s.getOriginalUrl(req)},function(err,html){
|
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config:config,screen:'dashboard'},function(err,html){
|
||||||
if(err){
|
if(err){
|
||||||
s.systemLog(err)
|
s.systemLog(err)
|
||||||
}
|
}
|
||||||
|
@ -129,7 +99,7 @@ module.exports = function(s,config,lang,app){
|
||||||
* Page : Administrator Login Screen
|
* Page : Administrator Login Screen
|
||||||
*/
|
*/
|
||||||
app.get(config.webPaths.admin, function (req,res){
|
app.get(config.webPaths.admin, function (req,res){
|
||||||
res.render(config.renderPaths.index,{lang:lang,config:config,screen:'admin',originalURL:s.getOriginalUrl(req)},function(err,html){
|
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config:config,screen:'admin'},function(err,html){
|
||||||
if(err){
|
if(err){
|
||||||
s.systemLog(err)
|
s.systemLog(err)
|
||||||
}
|
}
|
||||||
|
@ -141,7 +111,7 @@ module.exports = function(s,config,lang,app){
|
||||||
*/
|
*/
|
||||||
app.get(config.webPaths.super, function (req,res){
|
app.get(config.webPaths.super, function (req,res){
|
||||||
|
|
||||||
res.render(config.renderPaths.index,{lang:lang,config:config,screen:'super',originalURL:s.getOriginalUrl(req)},function(err,html){
|
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config:config,screen:'super'},function(err,html){
|
||||||
if(err){
|
if(err){
|
||||||
s.systemLog(err)
|
s.systemLog(err)
|
||||||
}
|
}
|
||||||
|
@ -171,23 +141,48 @@ module.exports = function(s,config,lang,app){
|
||||||
/**
|
/**
|
||||||
* API : Login handler. Dashboard, Streamer, Dashcam Administrator, Superuser
|
* API : Login handler. Dashboard, Streamer, Dashcam Administrator, Superuser
|
||||||
*/
|
*/
|
||||||
app.post([config.webPaths.home,s.checkCorrectPathEnding(config.webPaths.home)+':screen'],function (req,res){
|
app.post([
|
||||||
|
config.webPaths.home,
|
||||||
|
config.webPaths.admin,
|
||||||
|
config.webPaths.super,
|
||||||
|
s.checkCorrectPathEnding(config.webPaths.home)+':screen',
|
||||||
|
s.checkCorrectPathEnding(config.webPaths.admin)+':screen',
|
||||||
|
s.checkCorrectPathEnding(config.webPaths.super)+':screen',
|
||||||
|
],function (req,res){
|
||||||
req.ip = s.getClientIp(req)
|
req.ip = s.getClientIp(req)
|
||||||
if(req.query.json === 'true'){
|
if(req.query.json === 'true'){
|
||||||
res.header("Access-Control-Allow-Origin",req.headers.origin);
|
res.header("Access-Control-Allow-Origin",req.headers.origin);
|
||||||
}
|
}
|
||||||
|
var screenChooser = function(screen){
|
||||||
|
var search = function(screen){
|
||||||
|
if(req.url.indexOf(screen) > -1){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch(true){
|
||||||
|
case search(config.webPaths.admin):
|
||||||
|
return 'admin'
|
||||||
|
break;
|
||||||
|
case search(config.webPaths.super):
|
||||||
|
return 'super'
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 'dashboard'
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
// brute check
|
// brute check
|
||||||
if(s.failedLoginAttempts[req.body.mail] && s.failedLoginAttempts[req.body.mail].failCount >= 5){
|
if(s.failedLoginAttempts[req.body.mail] && s.failedLoginAttempts[req.body.mail].failCount >= 5){
|
||||||
if(req.query.json=='true'){
|
if(req.query.json=='true'){
|
||||||
res.end(s.prettyPrint({ok:false}))
|
res.end(s.prettyPrint({ok:false}))
|
||||||
}else{
|
}else{
|
||||||
res.render(config.renderPaths.index,{
|
s.renderPage(req,res,config.renderPaths.index,{
|
||||||
failedLogin:true,
|
failedLogin: true,
|
||||||
message:lang.failedLoginText1,
|
message: lang.failedLoginText1,
|
||||||
lang:lang,
|
lang: lang,
|
||||||
config:config,
|
config: config,
|
||||||
screen:req.params.screen,
|
screen: screenChooser(req.params.screen)
|
||||||
originalURL:s.getOriginalUrl(req)
|
|
||||||
},function(err,html){
|
},function(err,html){
|
||||||
if(err){
|
if(err){
|
||||||
s.systemLog(err)
|
s.systemLog(err)
|
||||||
|
@ -209,9 +204,8 @@ module.exports = function(s,config,lang,app){
|
||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
res.end(s.prettyPrint(data))
|
res.end(s.prettyPrint(data))
|
||||||
}else{
|
}else{
|
||||||
data.originalURL = s.getOriginalUrl(req)
|
|
||||||
data.screen=req.params.screen
|
data.screen=req.params.screen
|
||||||
res.render(focus,data,function(err,html){
|
s.renderPage(req,res,focus,data,function(err,html){
|
||||||
if(err){
|
if(err){
|
||||||
s.systemLog(err)
|
s.systemLog(err)
|
||||||
}
|
}
|
||||||
|
@ -241,13 +235,12 @@ module.exports = function(s,config,lang,app){
|
||||||
res.setHeader('Content-Type', 'application/json')
|
res.setHeader('Content-Type', 'application/json')
|
||||||
res.end(s.prettyPrint({ok:false}))
|
res.end(s.prettyPrint({ok:false}))
|
||||||
}else{
|
}else{
|
||||||
res.render(config.renderPaths.index,{
|
s.renderPage(req,res,config.renderPaths.index,{
|
||||||
failedLogin:true,
|
failedLogin: true,
|
||||||
message:lang.failedLoginText2,
|
message: lang.failedLoginText2,
|
||||||
lang:lang,
|
lang: lang,
|
||||||
config:config,
|
config: config,
|
||||||
screen:req.params.screen,
|
screen: screenChooser(req.params.screen)
|
||||||
originalURL:s.getOriginalUrl(req)
|
|
||||||
},function(err,html){
|
},function(err,html){
|
||||||
if(err){
|
if(err){
|
||||||
s.systemLog(err)
|
s.systemLog(err)
|
||||||
|
@ -344,7 +337,7 @@ module.exports = function(s,config,lang,app){
|
||||||
r.details=JSON.parse(r.details);
|
r.details=JSON.parse(r.details);
|
||||||
r.lang=s.getLanguageFile(r.details.lang)
|
r.lang=s.getLanguageFile(r.details.lang)
|
||||||
req.factorAuth=function(cb){
|
req.factorAuth=function(cb){
|
||||||
if(r.details.factorAuth==="1"){
|
if(r.details.factorAuth === "1"){
|
||||||
if(!r.details.acceptedMachines||!(r.details.acceptedMachines instanceof Object)){
|
if(!r.details.acceptedMachines||!(r.details.acceptedMachines instanceof Object)){
|
||||||
r.details.acceptedMachines={}
|
r.details.acceptedMachines={}
|
||||||
}
|
}
|
||||||
|
@ -671,14 +664,13 @@ module.exports = function(s,config,lang,app){
|
||||||
if(req.path.indexOf('/cycle/') > -1){
|
if(req.path.indexOf('/cycle/') > -1){
|
||||||
page = config.renderPaths.cycle
|
page = config.renderPaths.cycle
|
||||||
}
|
}
|
||||||
res.render(page,{
|
s.renderPage(req,res,page,{
|
||||||
data:Object.assign(req.params,req.query),
|
data:Object.assign(req.params,req.query),
|
||||||
baseUrl:req.protocol+'://'+req.hostname,
|
baseUrl:req.protocol+'://'+req.hostname,
|
||||||
config:config,
|
config:config,
|
||||||
lang:user.lang,
|
lang:user.lang,
|
||||||
$user:user,
|
$user:user,
|
||||||
monitors:r,
|
monitors:r,
|
||||||
originalURL:s.getOriginalUrl(req),
|
|
||||||
query:req.query
|
query:req.query
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -1490,17 +1482,22 @@ module.exports = function(s,config,lang,app){
|
||||||
req.ext=req.params.file.split('.')[1];
|
req.ext=req.params.file.split('.')[1];
|
||||||
var total = fs.statSync(req.dir).size;
|
var total = fs.statSync(req.dir).size;
|
||||||
if (req.headers['range']) {
|
if (req.headers['range']) {
|
||||||
var range = req.headers.range;
|
try{
|
||||||
var parts = range.replace(/bytes=/, "").split("-");
|
var range = req.headers.range;
|
||||||
var partialstart = parts[0];
|
var parts = range.replace(/bytes=/, "").split("-");
|
||||||
var partialend = parts[1];
|
var partialstart = parts[0];
|
||||||
|
var partialend = parts[1];
|
||||||
var start = parseInt(partialstart, 10);
|
var start = parseInt(partialstart, 10);
|
||||||
var end = partialend ? parseInt(partialend, 10) : total-1;
|
var end = partialend ? parseInt(partialend, 10) : total-1;
|
||||||
var chunksize = (end-start)+1;
|
var chunksize = (end-start)+1;
|
||||||
var file = fs.createReadStream(req.dir, {start: start, end: end});
|
var file = fs.createReadStream(req.dir, {start: start, end: end});
|
||||||
req.headerWrite={ 'Content-Range': 'bytes ' + start + '-' + end + '/' + total, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/'+req.ext }
|
req.headerWrite={ 'Content-Range': 'bytes ' + start + '-' + end + '/' + total, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/'+req.ext }
|
||||||
req.writeCode=206
|
req.writeCode=206
|
||||||
|
}catch(err){
|
||||||
|
req.headerWrite={ 'Content-Length': total, 'Content-Type': 'video/'+req.ext};
|
||||||
|
var file = fs.createReadStream(req.dir)
|
||||||
|
req.writeCode=200
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
req.headerWrite={ 'Content-Length': total, 'Content-Type': 'video/'+req.ext};
|
req.headerWrite={ 'Content-Length': total, 'Content-Type': 'video/'+req.ext};
|
||||||
var file=fs.createReadStream(req.dir)
|
var file=fs.createReadStream(req.dir)
|
||||||
|
@ -1844,4 +1841,27 @@ module.exports = function(s,config,lang,app){
|
||||||
}
|
}
|
||||||
},res,req);
|
},res,req);
|
||||||
})
|
})
|
||||||
|
/**
|
||||||
|
* API : Account Edit from Dashboard
|
||||||
|
*/
|
||||||
|
app.all(config.webPaths.apiPrefix+':auth/accounts/:ke/edit',function (req,res){
|
||||||
|
s.auth(req.params,function(user){
|
||||||
|
var endData = {
|
||||||
|
ok : false
|
||||||
|
}
|
||||||
|
var form = s.getPostData(req)
|
||||||
|
if(form){
|
||||||
|
endData.ok = true
|
||||||
|
s.accountSettingsEdit({
|
||||||
|
ke: req.params.ke,
|
||||||
|
uid: user.uid,
|
||||||
|
form: form,
|
||||||
|
cnid: user.cnid
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
endData.msg = lang.postDataBroken
|
||||||
|
}
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
},res,req)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ module.exports = function(s,config,lang,app){
|
||||||
if(s.group[req.params.ke]&&s.group[req.params.ke].mon[req.params.id]){
|
if(s.group[req.params.ke]&&s.group[req.params.ke].mon[req.params.id]){
|
||||||
if(s.group[req.params.ke].mon[req.params.id].isStarted === true){
|
if(s.group[req.params.ke].mon[req.params.id].isStarted === true){
|
||||||
req.params.uid=user.uid;
|
req.params.uid=user.uid;
|
||||||
res.render(config.renderPaths.embed,{data:req.params,baseUrl:req.protocol+'://'+req.hostname,config:config,lang:user.lang,mon:CircularJSON.parse(CircularJSON.stringify(s.group[req.params.ke].mon_conf[req.params.id])),originalURL:s.getOriginalUrl(req)});
|
s.renderPage(req,res,config.renderPaths.embed,{data:req.params,baseUrl:req.protocol+'://'+req.hostname,config:config,lang:user.lang,mon:CircularJSON.parse(CircularJSON.stringify(s.group[req.params.ke].mon_conf[req.params.id])),originalURL:s.getOriginalUrl(req)});
|
||||||
res.end()
|
res.end()
|
||||||
}else{
|
}else{
|
||||||
res.end(user.lang['Cannot watch a monitor that isn\'t running.'])
|
res.end(user.lang['Cannot watch a monitor that isn\'t running.'])
|
||||||
|
@ -102,7 +102,7 @@ module.exports = function(s,config,lang,app){
|
||||||
app.get([config.webPaths.apiPrefix+':auth/mjpeg/:ke/:id',config.webPaths.apiPrefix+':auth/mjpeg/:ke/:id/:channel'], function(req,res) {
|
app.get([config.webPaths.apiPrefix+':auth/mjpeg/:ke/:id',config.webPaths.apiPrefix+':auth/mjpeg/:ke/:id/:channel'], function(req,res) {
|
||||||
res.header("Access-Control-Allow-Origin",req.headers.origin);
|
res.header("Access-Control-Allow-Origin",req.headers.origin);
|
||||||
if(req.query.full=='true'){
|
if(req.query.full=='true'){
|
||||||
res.render(config.renderPaths.mjpeg,{url:'/'+req.params.auth+'/mjpeg/'+req.params.ke+'/'+req.params.id,originalURL:s.getOriginalUrl(req)});
|
s.renderPage(req,res,config.renderPaths.mjpeg,{url:config.webPaths.apiPrefix + req.params.auth+'/mjpeg/'+req.params.ke+'/'+req.params.id,originalURL:s.getOriginalUrl(req)});
|
||||||
res.end()
|
res.end()
|
||||||
}else{
|
}else{
|
||||||
s.auth(req.params,function(user){
|
s.auth(req.params,function(user){
|
||||||
|
|
|
@ -34,3 +34,10 @@ tool.getVideoImage = function (path, secs, callback) {
|
||||||
};
|
};
|
||||||
video.src = path;
|
video.src = path;
|
||||||
}
|
}
|
||||||
|
tool.checkCorrectPathEnding = function(x){
|
||||||
|
var length=x.length
|
||||||
|
if(x.charAt(length-1)!=='/'){
|
||||||
|
x=x+'/'
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
|
@ -3902,7 +3902,8 @@
|
||||||
return (new Date(now.getTime() + now.getTimezoneOffset() * 60000));
|
return (new Date(now.getTime() + now.getTimezoneOffset() * 60000));
|
||||||
}
|
}
|
||||||
var _this = this;
|
var _this = this;
|
||||||
var t = _this._ws = io(e.url,{
|
var t = _this._ws = io(e.config.url,{
|
||||||
|
path: e.config.path,
|
||||||
transports:['websocket']
|
transports:['websocket']
|
||||||
});
|
});
|
||||||
l._ws = t;
|
l._ws = t;
|
||||||
|
@ -6277,4 +6278,4 @@
|
||||||
}, {}]
|
}, {}]
|
||||||
}, {}, [21])(21)
|
}, {}, [21])(21)
|
||||||
});
|
});
|
||||||
//# sourceMappingURL=flv.min.js.map
|
//# sourceMappingURL=flv.min.js.map
|
||||||
|
|
|
@ -7,7 +7,11 @@ window.chartColors = {
|
||||||
purple: 'rgb(153, 102, 255)',
|
purple: 'rgb(153, 102, 255)',
|
||||||
grey: 'rgb(201, 203, 207)'
|
grey: 'rgb(201, 203, 207)'
|
||||||
};
|
};
|
||||||
$user.details=JSON.parse($user.details)
|
try{
|
||||||
|
$user.details = JSON.parse($user.details)
|
||||||
|
}catch(err){
|
||||||
|
|
||||||
|
}
|
||||||
$.ccio={
|
$.ccio={
|
||||||
fr:$('#files_recent'),
|
fr:$('#files_recent'),
|
||||||
mon:{}
|
mon:{}
|
||||||
|
@ -209,7 +213,7 @@ switch($user.details.lang){
|
||||||
url=url+'/'
|
url=url+'/'
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
url = '<%-originalURL%>'
|
url = '<%-window.libURL%>'
|
||||||
}
|
}
|
||||||
return url
|
return url
|
||||||
break;
|
break;
|
||||||
|
@ -575,7 +579,7 @@ switch($user.details.lang){
|
||||||
k.e=$('#monitor_live_'+d.mid+user.auth_token+' .stream-element');
|
k.e=$('#monitor_live_'+d.mid+user.auth_token+' .stream-element');
|
||||||
$.ccio.init('jpegModeStop',d,user);
|
$.ccio.init('jpegModeStop',d,user);
|
||||||
k.run=function(){
|
k.run=function(){
|
||||||
k.e.attr('src',user.auth_token+'/jpeg/'+d.ke+'/'+d.mid+'/s.jpg?time='+(new Date()).getTime())
|
k.e.attr('src',$.ccio.init('location',user)+user.auth_token+'/jpeg/'+d.ke+'/'+d.mid+'/s.jpg?time='+(new Date()).getTime())
|
||||||
}
|
}
|
||||||
k.e.load(function(){
|
k.e.load(function(){
|
||||||
$.ccio.mon[d.ke+d.mid+user.auth_token].jpegInterval=setTimeout(k.run,1000/k.jpegInterval);
|
$.ccio.mon[d.ke+d.mid+user.auth_token].jpegInterval=setTimeout(k.run,1000/k.jpegInterval);
|
||||||
|
@ -1876,7 +1880,7 @@ switch($user.details.lang){
|
||||||
return ii.o
|
return ii.o
|
||||||
}
|
}
|
||||||
//websocket functions
|
//websocket functions
|
||||||
$.users={}
|
$.users = {}
|
||||||
$.ccio.globalWebsocket=function(d,user){
|
$.ccio.globalWebsocket=function(d,user){
|
||||||
if(d.f!=='monitor_frame'&&d.f!=='os'&&d.f!=='video_delete'&&d.f!=='detector_trigger'&&d.f!=='detector_record_timeout_start'&&d.f!=='log'){$.ccio.log(d);}
|
if(d.f!=='monitor_frame'&&d.f!=='os'&&d.f!=='video_delete'&&d.f!=='detector_trigger'&&d.f!=='detector_record_timeout_start'&&d.f!=='log'){$.ccio.log(d);}
|
||||||
if(!user){
|
if(!user){
|
||||||
|
@ -2127,16 +2131,7 @@ $.ccio.globalWebsocket=function(d,user){
|
||||||
if($.ccio.op().jpeg_on===true){
|
if($.ccio.op().jpeg_on===true){
|
||||||
$.ccio.init('jpegMode',$.ccio.mon[d.ke+d.id+user.auth_token]);
|
$.ccio.init('jpegMode',$.ccio.mon[d.ke+d.id+user.auth_token]);
|
||||||
}else{
|
}else{
|
||||||
var url = $.ccio.init('location',user);
|
var path = tool.checkCorrectPathEnding(location.pathname)+'socket.io'
|
||||||
var prefix = 'ws'
|
|
||||||
if(location.protocol==='https:'){
|
|
||||||
prefix = 'wss'
|
|
||||||
}
|
|
||||||
if(url==''){
|
|
||||||
url = prefix+'://'+location.host+location.pathname
|
|
||||||
}else{
|
|
||||||
url = prefix+'://'+url.split('://')[1]
|
|
||||||
}
|
|
||||||
switch(d.d.stream_type){
|
switch(d.d.stream_type){
|
||||||
case'jpeg':
|
case'jpeg':
|
||||||
$.ccio.init('jpegMode',$.ccio.mon[d.ke+d.id+user.auth_token]);
|
$.ccio.init('jpegMode',$.ccio.mon[d.ke+d.id+user.auth_token]);
|
||||||
|
@ -2145,7 +2140,7 @@ $.ccio.globalWebsocket=function(d,user){
|
||||||
if($.ccio.mon[d.ke+d.id+user.auth_token].Base64 && $.ccio.mon[d.ke+d.id+user.auth_token].Base64.connected){
|
if($.ccio.mon[d.ke+d.id+user.auth_token].Base64 && $.ccio.mon[d.ke+d.id+user.auth_token].Base64.connected){
|
||||||
$.ccio.mon[d.ke+d.id+user.auth_token].Base64.disconnect()
|
$.ccio.mon[d.ke+d.id+user.auth_token].Base64.disconnect()
|
||||||
}
|
}
|
||||||
$.ccio.mon[d.ke+d.id+user.auth_token].Base64 = io(url,{transports: ['websocket'], forceNew: false})
|
$.ccio.mon[d.ke+d.id+user.auth_token].Base64 = io(location.origin,{ path: path, transports: ['websocket'], forceNew: false})
|
||||||
var ws = $.ccio.mon[d.ke+d.id+user.auth_token].Base64
|
var ws = $.ccio.mon[d.ke+d.id+user.auth_token].Base64
|
||||||
var buffer
|
var buffer
|
||||||
ws.on('diconnect',function(){
|
ws.on('diconnect',function(){
|
||||||
|
@ -2153,7 +2148,6 @@ $.ccio.globalWebsocket=function(d,user){
|
||||||
})
|
})
|
||||||
ws.on('connect',function(){
|
ws.on('connect',function(){
|
||||||
ws.emit('Base64',{
|
ws.emit('Base64',{
|
||||||
url: url,
|
|
||||||
auth: user.auth_token,
|
auth: user.auth_token,
|
||||||
uid: user.uid,
|
uid: user.uid,
|
||||||
ke: d.ke,
|
ke: d.ke,
|
||||||
|
@ -2224,7 +2218,8 @@ $.ccio.globalWebsocket=function(d,user){
|
||||||
ke:d.ke,
|
ke:d.ke,
|
||||||
uid:user.uid,
|
uid:user.uid,
|
||||||
id:d.id,
|
id:d.id,
|
||||||
url: url,
|
url: location.origin,
|
||||||
|
path: path,
|
||||||
onError : onPoseidonError
|
onError : onPoseidonError
|
||||||
})
|
})
|
||||||
$.ccio.mon[d.ke+d.id+user.auth_token].Poseidon.start();
|
$.ccio.mon[d.ke+d.id+user.auth_token].Poseidon.start();
|
||||||
|
@ -2261,7 +2256,8 @@ $.ccio.globalWebsocket=function(d,user){
|
||||||
id:d.id,
|
id:d.id,
|
||||||
maxLatency:d.d.stream_flv_maxLatency,
|
maxLatency:d.d.stream_flv_maxLatency,
|
||||||
hasAudio:false,
|
hasAudio:false,
|
||||||
url: url
|
url: location.origin,
|
||||||
|
path: path
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
options = {
|
options = {
|
||||||
|
@ -2338,14 +2334,13 @@ $.ccio.globalWebsocket=function(d,user){
|
||||||
$.ccio.mon[d.ke+d.id+user.auth_token].h265HttpStream.abort()
|
$.ccio.mon[d.ke+d.id+user.auth_token].h265HttpStream.abort()
|
||||||
}
|
}
|
||||||
if(d.d.stream_flv_type==='ws'){
|
if(d.d.stream_flv_type==='ws'){
|
||||||
$.ccio.mon[d.ke+d.id+user.auth_token].h265Socket = io(url,{transports: ['websocket'], forceNew: false})
|
$.ccio.mon[d.ke+d.id+user.auth_token].h265Socket = io(location.origin,{ path: path, transports: ['websocket'], forceNew: false})
|
||||||
var ws = $.ccio.mon[d.ke+d.id+user.auth_token].h265Socket
|
var ws = $.ccio.mon[d.ke+d.id+user.auth_token].h265Socket
|
||||||
ws.on('diconnect',function(){
|
ws.on('diconnect',function(){
|
||||||
console.log('h265Socket Stream Disconnected')
|
console.log('h265Socket Stream Disconnected')
|
||||||
})
|
})
|
||||||
ws.on('connect',function(){
|
ws.on('connect',function(){
|
||||||
ws.emit('h265',{
|
ws.emit('h265',{
|
||||||
url: url,
|
|
||||||
auth: user.auth_token,
|
auth: user.auth_token,
|
||||||
uid: user.uid,
|
uid: user.uid,
|
||||||
ke: d.ke,
|
ke: d.ke,
|
||||||
|
@ -2469,7 +2464,9 @@ $.ccio.globalWebsocket=function(d,user){
|
||||||
}
|
}
|
||||||
$.ccio.init('monitorInfo',d)
|
$.ccio.init('monitorInfo',d)
|
||||||
$.gR.drawList();
|
$.gR.drawList();
|
||||||
$.ccio.init('note',{title:'Monitor Saved',text:'<b>'+d.mon.name+'</b> <small>'+d.mon.mid+'</small> has been saved.',type:'success'});
|
if(!d.silenceNote){
|
||||||
|
$.ccio.init('note',{title:'Monitor Saved',text:'<b>'+d.mon.name+'</b> <small>'+d.mon.mid+'</small> has been saved.',type:'success'});
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case'monitor_starting':
|
case'monitor_starting':
|
||||||
// switch(d.mode){case'start':d.mode='Watch';break;case'record':d.mode='Record';break;}
|
// switch(d.mode){case'start':d.mode='Watch';break;case'record':d.mode='Record';break;}
|
||||||
|
@ -2632,7 +2629,7 @@ $.ccio.globalWebsocket=function(d,user){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$user.ws=io(location.origin,{
|
$user.ws=io(location.origin,{
|
||||||
path : location.pathname+'socket.io'
|
path : tool.checkCorrectPathEnding(location.pathname)+'socket.io'
|
||||||
});
|
});
|
||||||
$user.ws.on('connect',function (d){
|
$user.ws.on('connect',function (d){
|
||||||
$(document).ready(function(e){
|
$(document).ready(function(e){
|
||||||
|
@ -2751,7 +2748,6 @@ $user.ws.on('f',function (d){
|
||||||
d.currentlyEditing=$.aM.e.attr('mid')
|
d.currentlyEditing=$.aM.e.attr('mid')
|
||||||
if(d.currentlyEditing&&d.currentlyEditing!==''){
|
if(d.currentlyEditing&&d.currentlyEditing!==''){
|
||||||
d.currentlyEditing=JSON.parse(JSON.parse($.ccio.mon[d.currentlyEditing].details).detector_cascades)
|
d.currentlyEditing=JSON.parse(JSON.parse($.ccio.mon[d.currentlyEditing].details).detector_cascades)
|
||||||
console.log(d.currentlyEditing)
|
|
||||||
$.each(d.currentlyEditing,function(m,b){
|
$.each(d.currentlyEditing,function(m,b){
|
||||||
d.e=$('.detector_cascade_selection[value="'+m+'"]').prop('checked',true)
|
d.e=$('.detector_cascade_selection[value="'+m+'"]').prop('checked',true)
|
||||||
d.p=d.e.parents('.mdl-js-switch')
|
d.p=d.e.parents('.mdl-js-switch')
|
||||||
|
@ -3001,6 +2997,7 @@ $.zO.initCanvas=function(){
|
||||||
$.zO.f.find('[name="sensitivity"]').val('')
|
$.zO.f.find('[name="sensitivity"]').val('')
|
||||||
$.zO.f.find('[name="max_sensitivity"]').val('')
|
$.zO.f.find('[name="max_sensitivity"]').val('')
|
||||||
$.zO.f.find('[name="threshold"]').val('')
|
$.zO.f.find('[name="threshold"]').val('')
|
||||||
|
$.zO.f.find('[name="color_threshold"]').val('')
|
||||||
$.zO.rp.empty()
|
$.zO.rp.empty()
|
||||||
}else{
|
}else{
|
||||||
e.cord=$.zO.regionViewerDetails.cords[e.val];
|
e.cord=$.zO.regionViewerDetails.cords[e.val];
|
||||||
|
@ -3016,6 +3013,7 @@ $.zO.initCanvas=function(){
|
||||||
$.zO.f.find('[name="sensitivity"]').val(e.cord.sensitivity)
|
$.zO.f.find('[name="sensitivity"]').val(e.cord.sensitivity)
|
||||||
$.zO.f.find('[name="max_sensitivity"]').val(e.cord.max_sensitivity)
|
$.zO.f.find('[name="max_sensitivity"]').val(e.cord.max_sensitivity)
|
||||||
$.zO.f.find('[name="threshold"]').val(e.cord.threshold)
|
$.zO.f.find('[name="threshold"]').val(e.cord.threshold)
|
||||||
|
$.zO.f.find('[name="color_threshold"]').val(e.cord.color_threshold)
|
||||||
$.zO.e.find('.canvas_holder canvas').remove();
|
$.zO.e.find('.canvas_holder canvas').remove();
|
||||||
|
|
||||||
$.zO.initLiveStream()
|
$.zO.initLiveStream()
|
||||||
|
@ -3120,7 +3118,7 @@ $.zO.e.on('click','.add',function(e){
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
$.zO.regionViewerDetails.cords=e.save;
|
$.zO.regionViewerDetails.cords=e.save;
|
||||||
$.zO.regionViewerDetails.cords[e.gid]={name:e.gid,sensitivity:0.0005,max_sensitivity:'',threshold:1,points:[[0,0],[0,100],[100,0]]};
|
$.zO.regionViewerDetails.cords[e.gid]={name:e.gid,sensitivity:0.0005,max_sensitivity:'',threshold:1,color_threshold:9,points:[[0,0],[0,100],[100,0]]};
|
||||||
$.zO.rl.append('<option value="'+e.gid+'">'+e.gid+'</option>');
|
$.zO.rl.append('<option value="'+e.gid+'">'+e.gid+'</option>');
|
||||||
$.zO.rl.val(e.gid)
|
$.zO.rl.val(e.gid)
|
||||||
$.zO.rl.change();
|
$.zO.rl.change();
|
||||||
|
@ -3576,6 +3574,7 @@ $.aM.generateDefaultMonitorSettings=function(){
|
||||||
"detector_sensitivity": "",
|
"detector_sensitivity": "",
|
||||||
"detector_max_sensitivity": "",
|
"detector_max_sensitivity": "",
|
||||||
"detector_threshold": "1",
|
"detector_threshold": "1",
|
||||||
|
"detector_color_threshold": "",
|
||||||
"cords": "[]",
|
"cords": "[]",
|
||||||
"detector_buffer_vcodec": "auto",
|
"detector_buffer_vcodec": "auto",
|
||||||
"detector_buffer_fps": "",
|
"detector_buffer_fps": "",
|
||||||
|
@ -4204,6 +4203,10 @@ $.apM.f.submit(function(e){
|
||||||
if(!e.s.ip||e.s.ip.length<7){e.er.push('Enter atleast one IP')}
|
if(!e.s.ip||e.s.ip.length<7){e.er.push('Enter atleast one IP')}
|
||||||
if(e.er.length>0){$.apM.e.find('.msg').html(e.er.join('<br>'));return;}
|
if(e.er.length>0){$.apM.e.find('.msg').html(e.er.join('<br>'));return;}
|
||||||
$.each(e.s,function(n,v){e.s[n]=v.trim()})
|
$.each(e.s,function(n,v){e.s[n]=v.trim()})
|
||||||
|
// e.s = {
|
||||||
|
// "ip": "",
|
||||||
|
// "details": "{\"get_monitors\":\"1\",\"control_monitors\":\"1\",\"get_logs\":\"1\",\"watch_stream\":\"1\",\"watch_snapshot\":\"1\",\"watch_videos\":\"1\",\"delete_videos\":\"1\"}"
|
||||||
|
// }
|
||||||
$.post($.ccio.init('location',$user)+$user.auth_token+'/api/'+$user.ke+'/add',{data:JSON.stringify(e.s)},function(d){
|
$.post($.ccio.init('location',$user)+$user.auth_token+'/api/'+$user.ke+'/add',{data:JSON.stringify(e.s)},function(d){
|
||||||
$.ccio.log(d)
|
$.ccio.log(d)
|
||||||
})
|
})
|
||||||
|
@ -5695,7 +5698,7 @@ $('body')
|
||||||
}
|
}
|
||||||
if(!e.d.cords||e.d.cords===''){
|
if(!e.d.cords||e.d.cords===''){
|
||||||
e.d.cords={
|
e.d.cords={
|
||||||
red:{ name:"red",sensitivity:0.0005, max_sensitivity:"",points:[[0,0],[0,100],[100,0]] },
|
red:{ name:"red",sensitivity:0.0005, max_sensitivity:"",color_threshold:"",points:[[0,0],[0,100],[100,0]] },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$.zO.regionViewerDetails=e.d;
|
$.zO.regionViewerDetails=e.d;
|
||||||
|
@ -6104,14 +6107,14 @@ $('body')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//set dropdown toggle preferences
|
//set dropdown toggle preferences
|
||||||
e.o=$.ccio.op().dropdown_toggle;
|
e.o = $.ccio.op().dropdown_toggle
|
||||||
if(e.o){
|
if(e.o){
|
||||||
$.each(e.o,function(n,v){
|
$.each(e.o,function(n,v){
|
||||||
$('[dropdown_toggle="'+n+'"]').val(v).change()
|
$('[dropdown_toggle="'+n+'"]').val(v).change()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//set localStorage input values
|
//set localStorage input values
|
||||||
e.o=$.ccio.op();
|
e.o = $.ccio.op()
|
||||||
if(e.o){
|
if(e.o){
|
||||||
$.each(e.o,function(n,v){
|
$.each(e.o,function(n,v){
|
||||||
if(typeof v==='string'){
|
if(typeof v==='string'){
|
||||||
|
|
|
@ -243,7 +243,7 @@ var Poseidon = function () {
|
||||||
}
|
}
|
||||||
this._playing = true;
|
this._playing = true;
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this._socket = io(_this._monitor.url, { transports: ['websocket'], forceNew: false });
|
this._socket = io(_this._monitor.url, { path: _this._monitor.path, transports: ['websocket'], forceNew: false });
|
||||||
this._addSocketEvents();
|
this._addSocketEvents();
|
||||||
if (this._startstop) {
|
if (this._startstop) {
|
||||||
this._startstop.disabled = false;
|
this._startstop.disabled = false;
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
|
<%
|
||||||
|
window.libURL = originalURL + global.s.checkCorrectPathEnding(config.webPaths.admin)
|
||||||
|
%>
|
||||||
<% include blocks/header %>
|
<% include blocks/header %>
|
||||||
<script>$user=<%-JSON.stringify($user)%></script>
|
<script>$user=<%-JSON.stringify($user)%></script>
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/pnotify.custom.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/pnotify.custom.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/vbox.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/vbox.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/circles.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/circles.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/admin-page.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/admin-page.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/bootstrap.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/font-awesome.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/font-awesome.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/fullcalendar.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/fullcalendar.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/bootstrap-table.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap-table.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/main.dash2.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/main.dash2.css">
|
||||||
<body class="shinobi-bg">
|
<body class="shinobi-bg">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
@ -80,6 +83,7 @@
|
||||||
<% include blocks/confirm.ejs %>
|
<% include blocks/confirm.ejs %>
|
||||||
<% include blocks/subpermissions.ejs %>
|
<% include blocks/subpermissions.ejs %>
|
||||||
</body>
|
</body>
|
||||||
|
<script><% include ../libs/js/basic.js %></script>
|
||||||
<script><% include ../libs/js/socket.io.js %></script>
|
<script><% include ../libs/js/socket.io.js %></script>
|
||||||
<script><% include ../libs/js/pnotify.custom.min.js %></script>
|
<script><% include ../libs/js/pnotify.custom.min.js %></script>
|
||||||
<script><% include ../libs/js/moment.js %></script>
|
<script><% include ../libs/js/moment.js %></script>
|
||||||
|
@ -89,7 +93,9 @@
|
||||||
<script><% include ../libs/js/bootstrap-table.min.js %></script>
|
<script><% include ../libs/js/bootstrap-table.min.js %></script>
|
||||||
<script>
|
<script>
|
||||||
$.ccio={subs:{}};$.ls=localStorage;
|
$.ccio={subs:{}};$.ls=localStorage;
|
||||||
$.ccio.ws=io(location.origin);
|
$.ccio.ws=io(location.origin,{
|
||||||
|
path : tool.checkCorrectPathEnding(location.pathname)+'socket.io'
|
||||||
|
});
|
||||||
$.ccio.cx=function(x){if(!x.ke){x.ke=$user.ke;};if(!x.uid){x.uid=$user.uid;};return $.ccio.ws.emit('a',x)}
|
$.ccio.cx=function(x){if(!x.ke){x.ke=$user.ke;};if(!x.uid){x.uid=$user.uid;};return $.ccio.ws.emit('a',x)}
|
||||||
$.ccio.ws.on('connect',function(d){
|
$.ccio.ws.on('connect',function(d){
|
||||||
$.ccio.cx({f:'init',auth:$user.auth_token});
|
$.ccio.cx({f:'init',auth:$user.auth_token});
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
<link rel="icon" href="<%-originalURL%>libs/img/icon/favicon.ico" type="image/x-icon" />
|
<%
|
||||||
<link rel="shortcut icon" href="<%-originalURL%>libs/img/icon/favicon.ico" type="image/x-icon" />
|
if(!window.libURL)window.libURL = originalURL
|
||||||
|
%>
|
||||||
|
<link rel="icon" href="<%-window.libURL%>libs/img/icon/favicon.ico" type="image/x-icon" />
|
||||||
|
<link rel="shortcut icon" href="<%-window.libURL%>libs/img/icon/favicon.ico" type="image/x-icon" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
<meta name="apple-mobile-web-app-title" content="Shinobi">
|
<meta name="apple-mobile-web-app-title" content="Shinobi">
|
||||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" href="<%-window.libURL%>libs/img/icon/apple-touch-icon.png" />
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="<%-originalURL%>libs/img/icon/apple-touch-icon-57x57.png" />
|
<link rel="apple-touch-icon" sizes="57x57" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-57x57.png" />
|
||||||
<link rel="apple-touch-icon" sizes="72x72" href="<%-originalURL%>libs/img/icon/apple-touch-icon-72x72.png" />
|
<link rel="apple-touch-icon" sizes="72x72" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-72x72.png" />
|
||||||
<link rel="apple-touch-icon" sizes="76x76" href="<%-originalURL%>libs/img/icon/apple-touch-icon-76x76.png" />
|
<link rel="apple-touch-icon" sizes="76x76" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-76x76.png" />
|
||||||
<link rel="apple-touch-icon" sizes="114x114" href="<%-originalURL%>libs/img/icon/apple-touch-icon-114x114.png" />
|
<link rel="apple-touch-icon" sizes="114x114" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-114x114.png" />
|
||||||
<link rel="apple-touch-icon" sizes="120x120" href="<%-originalURL%>libs/img/icon/apple-touch-icon-120x120.png" />
|
<link rel="apple-touch-icon" sizes="120x120" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-120x120.png" />
|
||||||
<link rel="apple-touch-icon" sizes="144x144" href="<%-originalURL%>libs/img/icon/apple-touch-icon-144x144.png" />
|
<link rel="apple-touch-icon" sizes="144x144" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-144x144.png" />
|
||||||
<link rel="apple-touch-icon" sizes="152x152" href="<%-originalURL%>libs/img/icon/apple-touch-icon-152x152.png" />
|
<link rel="apple-touch-icon" sizes="152x152" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-152x152.png" />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="<%-originalURL%>libs/img/icon/apple-touch-icon-180x180.png" />
|
<link rel="apple-touch-icon" sizes="180x180" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-180x180.png" />
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
<head>
|
<head>
|
||||||
<title><%-lang.Shinobi%></title>
|
<title><%-lang.Shinobi%></title>
|
||||||
|
<% if(!window.libURL)window.libURL = originalURL + global.s.checkCorrectPathEnding(config.webPaths.home) %>
|
||||||
<% include header-meta.ejs %>
|
<% include header-meta.ejs %>
|
||||||
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
|
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/bootstrap.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/login.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/login.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/material.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/material.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/material.style.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/material.style.css">
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
<% include header-favicon.ejs %>
|
<% include header-favicon.ejs %>
|
||||||
<script src="<%-originalURL%>libs/js/jquery.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/jquery.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/jquery-ui.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/jquery-ui.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/jquery.serialize.js"></script>
|
<script src="<%-window.libURL%>libs/js/jquery.serialize.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<% cleanLang = function(string){
|
<% cleanLang = function(string){
|
||||||
if(!string){string=''}
|
if(!string){string=''}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<h4 class="modal-title" id="help_windowLabel"><i class="fa fa-question-circle"></i> <span><%-lang.Help%></span></h4>
|
<h4 class="modal-title" id="help_windowLabel"><i class="fa fa-question-circle"></i> <span><%-lang.Help%></span></h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<a href="http://shinobi.video/docs/donate"><img src="<%-originalURL%>libs/img/icon/apple-touch-icon-152x152.png" class="pull-right" style="border-radius:50%;margin-left:20px;border: 1px solid #c3996b;"></a>
|
<a href="http://shinobi.video/docs/donate"><img src="<%-window.libURL%>libs/img/icon/apple-touch-icon-152x152.png" class="pull-right" style="border-radius:50%;margin-left:20px;border: 1px solid #c3996b;"></a>
|
||||||
<p>For information about how to use Shinobi you can check out the <a target="_blank" href="http://shinobi.video/docs">Docs</a>.</p>
|
<p>For information about how to use Shinobi you can check out the <a target="_blank" href="http://shinobi.video/docs">Docs</a>.</p>
|
||||||
<p>If you would like to get professional support please consider ordering a <a href="http://shinobi.video/support">support package</a>. You can find <b>Moe Alam, The Author</b>, on the <a target="_blank" href="https://discord.gg/ehRd8Zz">Discord</a> Community Chat. For general questions and community support you can also try <a href="https://www.reddit.com/r/ShinobiCCTV">Reddit</a>.</p>
|
<p>If you would like to get professional support please consider ordering a <a href="http://shinobi.video/support">support package</a>. You can find <b>Moe Alam, The Author</b>, on the <a target="_blank" href="https://discord.gg/ehRd8Zz">Discord</a> Community Chat. For general questions and community support you can also try <a href="https://www.reddit.com/r/ShinobiCCTV">Reddit</a>.</p>
|
||||||
<p><strong>Support </strong> <a href="http://shinobi.video/support">from @moeiscool</a></p>
|
<p><strong>Support </strong> <a href="http://shinobi.video/support">from @moeiscool</a></p>
|
||||||
|
|
|
@ -143,6 +143,30 @@
|
||||||
</select></div>
|
</select></div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group h_l_input h_l_limited">
|
||||||
|
<label><div><span><%-lang['Use Global Amazon S3 Video Storage']%></span></div>
|
||||||
|
<div><select class="form-control" detail="aws_use_global">
|
||||||
|
<option value="1" selected><%-lang.Yes%></option>
|
||||||
|
<option value="0"><%-lang.No%></option>
|
||||||
|
</select></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group h_l_input h_l_limited">
|
||||||
|
<label><div><span><%-lang['Use Global Backblaze B2 Video Storage']%></span></div>
|
||||||
|
<div><select class="form-control" detail="b2_use_global">
|
||||||
|
<option value="1" selected><%-lang.Yes%></option>
|
||||||
|
<option value="0"><%-lang.No%></option>
|
||||||
|
</select></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group h_l_input h_l_limited">
|
||||||
|
<label><div><span><%-lang['Use Global WebDAV Video Storage']%></span></div>
|
||||||
|
<div><select class="form-control" detail="webdav_use_global">
|
||||||
|
<option value="1" selected><%-lang.Yes%></option>
|
||||||
|
<option value="0"><%-lang.No%></option>
|
||||||
|
</select></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-default pull-left" data-dismiss="modal"><i class="fa fa-times"></i> <%-lang.Close%></button>
|
<button type="button" class="btn btn-default pull-left" data-dismiss="modal"><i class="fa fa-times"></i> <%-lang.Close%></button>
|
||||||
|
@ -223,6 +247,14 @@ $.aN.e.on('change','[selector]',function(e){
|
||||||
$.aN.e.find('.'+e.a+'_input').hide()
|
$.aN.e.find('.'+e.a+'_input').hide()
|
||||||
$.aN.e.find('.'+e.a+'_'+e.v).show();
|
$.aN.e.find('.'+e.a+'_'+e.v).show();
|
||||||
}).find('[selector]').change();
|
}).find('[selector]').change();
|
||||||
|
$.aN.e.find('[detail="permissions"]').change(function(){
|
||||||
|
var hasAllPrivileges = $(this).val() === 'all'
|
||||||
|
var theClass = $('.h_l_limited')
|
||||||
|
if(hasAllPrivileges){
|
||||||
|
theClass.find('select').val('1')
|
||||||
|
theClass.find('input').val('')
|
||||||
|
}
|
||||||
|
})
|
||||||
//simple lister
|
//simple lister
|
||||||
$.aC={e:$('#accounts')};$.aC.t=$.aC.e.find('table')
|
$.aC={e:$('#accounts')};$.aC.t=$.aC.e.find('table')
|
||||||
$.aC.e.on('click','.add',function(e){
|
$.aC.e.on('click','.add',function(e){
|
||||||
|
|
|
@ -1141,7 +1141,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group-group orange shinobi-detector-opencv shinobi-detector-openalpr shinobi-detector-pythonyolo shinobi-detector-yolo shinobi-detector-pythondlib shinobi-detector_plug" section id="monSectionDetectorObject">
|
<div class="form-group-group orange shinobi-detector-opencv shinobi-detector-openalpr shinobi-detector-yolo shinobi-detector-dlib shinobi-detector_plug" section id="monSectionDetectorObject">
|
||||||
<h4><%-lang['Object Detection']%> <small><%-lang['Plugin']%> : <b class="shinobi-detector_name"></b> <b class="shinobi-detector-invert"><%-lang['Not Connected']%></b><b class="shinobi-detector" style="display:none"><%-lang['Connected']%></b></small></h4>
|
<h4><%-lang['Object Detection']%> <small><%-lang['Plugin']%> : <b class="shinobi-detector_name"></b> <b class="shinobi-detector-invert"><%-lang['Not Connected']%></b><b class="shinobi-detector" style="display:none"><%-lang['Connected']%></b></small></h4>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label><div><span><%-lang['Detect Objects']%></span></div>
|
<label><div><span><%-lang['Detect Objects']%></span></div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<% include blocks/header %>
|
<% include blocks/header %>
|
||||||
<script>var $user=<%- JSON.stringify($user) %>;</script>
|
<script>var $user=<%- JSON.stringify($user) %>;</script>
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/bootstrap.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap.min.css">
|
||||||
<div id="main" class="container">
|
<div id="main" class="container">
|
||||||
<a class="btn btn-danger btn-lg" record>Stream</a>
|
<a class="btn btn-danger btn-lg" record>Stream</a>
|
||||||
<div>
|
<div>
|
||||||
|
@ -19,13 +19,15 @@ requires https or firefox
|
||||||
</div>
|
</div>
|
||||||
<video id="video"><source></video>
|
<video id="video"><source></video>
|
||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
<script src="<%-originalURL%>libs/js/jquery.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/jquery.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/socket.io.js"></script>
|
<script src="<%-window.libURL%>libs/js/socket.io.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/menu.js"></script>
|
<script src="<%-window.libURL%>libs/js/menu.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$.ccio = {}
|
$.ccio = {}
|
||||||
$.ls = localStorage
|
$.ls = localStorage
|
||||||
$.ccio.ws = io(location.origin)
|
$.ccio.ws=io(location.origin,{
|
||||||
|
path : tool.checkCorrectPathEnding(location.pathname)+'socket.io'
|
||||||
|
});
|
||||||
$.ccio.ws.on('connect',function (d){
|
$.ccio.ws.on('connect',function (d){
|
||||||
$(document).ready(function(e){
|
$(document).ready(function(e){
|
||||||
$.ccio.cx=function(x){
|
$.ccio.cx=function(x){
|
||||||
|
@ -69,7 +71,7 @@ function _base64ToArrayBuffer(base64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$.ccio.framerate=2;
|
$.ccio.framerate=2;
|
||||||
|
|
||||||
$.ccio.stopSending=function(){
|
$.ccio.stopSending=function(){
|
||||||
$.ls.setItem('Shinobi_Dashcam_Started','0')
|
$.ls.setItem('Shinobi_Dashcam_Started','0')
|
||||||
$('#main').removeClass('recording');
|
$('#main').removeClass('recording');
|
||||||
|
@ -78,7 +80,7 @@ $.ccio.stopSending=function(){
|
||||||
try{
|
try{
|
||||||
mediaRecorder.stop()
|
mediaRecorder.stop()
|
||||||
}catch(err){
|
}catch(err){
|
||||||
|
|
||||||
}
|
}
|
||||||
$('[record]').unbind('click').click($.ccio.startSending)
|
$('[record]').unbind('click').click($.ccio.startSending)
|
||||||
}
|
}
|
||||||
|
@ -162,7 +164,7 @@ function log(message){
|
||||||
$.ccio.vid.data[0].innerHTML = $.ccio.vid.data[0].innerHTML+'<br>'+message ;
|
$.ccio.vid.data[0].innerHTML = $.ccio.vid.data[0].innerHTML+'<br>'+message ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Webcam */
|
/* Webcam */
|
||||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||||
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
||||||
|
@ -198,7 +200,7 @@ if(getBrowser() == "Chrome"){
|
||||||
var mediaRecorder;
|
var mediaRecorder;
|
||||||
var chunks = [];
|
var chunks = [];
|
||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
$.ccio.vid = {element:$('#video')[0],canvas:$('#canvas')[0],data:$('#data')};
|
$.ccio.vid = {element:$('#video')[0],canvas:$('#canvas')[0],data:$('#data')};
|
||||||
$.ccio.vid.element.controls = false;
|
$.ccio.vid.element.controls = false;
|
||||||
navigator.getUserMedia(constraints,function(stream,fn) {
|
navigator.getUserMedia(constraints,function(stream,fn) {
|
||||||
|
@ -217,16 +219,16 @@ navigator.getUserMedia(constraints,function(stream,fn) {
|
||||||
$.ccio.selected = null;
|
$.ccio.selected = null;
|
||||||
}
|
}
|
||||||
}, function(err){console.error('getUserMedia',err)});
|
}, function(err){console.error('getUserMedia',err)});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//draw selectable mons
|
//draw selectable mons
|
||||||
var tmp='';
|
var tmp='';
|
||||||
if($user.mons&&$user.mons.length>0){
|
if($user.mons&&$user.mons.length>0){
|
||||||
|
@ -250,8 +252,8 @@ navigator.getUserMedia(constraints,function(stream,fn) {
|
||||||
$.ls.setItem('Shinobi_Dashcam',e.a)
|
$.ls.setItem('Shinobi_Dashcam',e.a)
|
||||||
$('[monitor]').removeClass('active'),e.e.addClass('active');
|
$('[monitor]').removeClass('active'),e.e.addClass('active');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
$('body')
|
$('body')
|
||||||
.on('click','.logout',function(e){
|
.on('click','.logout',function(e){
|
||||||
localStorage.removeItem('ShinobiLogin_'+location.host);location.href='/';
|
localStorage.removeItem('ShinobiLogin_'+location.host);location.href='/';
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<a href="http://shinobi.video" target="_blank">
|
<a href="http://shinobi.video" target="_blank">
|
||||||
<img src="<%-originalURL%>libs/img/icon/apple-touch-icon-76x76.png" style="border-radius:50%">
|
<img src="<%-window.libURL%>libs/img/icon/apple-touch-icon-76x76.png" style="border-radius:50%">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="<%-originalURL%>libs/js/material.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/material.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$.ccio={f:$('#auth-form'),ls:localStorage.getItem('ShinobiAuth_'+location.host)}
|
$.ccio={f:$('#auth-form'),ls:localStorage.getItem('ShinobiAuth_'+location.host)}
|
||||||
$.ccio.gid=function(x){
|
$.ccio.gid=function(x){
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
<% var details = JSON.parse($user.details) %>
|
<%
|
||||||
|
var details = JSON.parse($user.details)
|
||||||
|
%>
|
||||||
<% include blocks/header %>
|
<% include blocks/header %>
|
||||||
<script>var $user = <%- JSON.stringify($user) %>;</script>
|
<script>var $user = <%- JSON.stringify($user) %>;</script>
|
||||||
<script>var lang = <%- JSON.stringify(lang) %>;</script>
|
<script>var lang = <%- JSON.stringify(lang) %>;</script>
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/pnotify.custom.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/pnotify.custom.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/vbox.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/vbox.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/daterangepicker.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/daterangepicker.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/circles.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/circles.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/bootstrap.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/font-awesome.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/font-awesome.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/fullcalendar.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/fullcalendar.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/gridstack.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/gridstack.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/gridstack-extra.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/gridstack-extra.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/bootstrap-table.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap-table.min.css">
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/main.dash2.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/main.dash2.css">
|
||||||
<style id="theme">
|
<style id="theme">
|
||||||
<% if(details.theme&&details.theme!==''){ %><%- include(__dirname+'/web/libs/themes/'+details.theme+'/style.css'); %><% } %>
|
<% if(details.theme&&details.theme!==''){ %><%- include(__dirname+'/web/libs/themes/'+details.theme+'/style.css'); %><% } %>
|
||||||
</style>
|
</style>
|
||||||
|
@ -171,30 +173,30 @@
|
||||||
<script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="<%= config.DropboxAppKey %>"></script>
|
<script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="<%= config.DropboxAppKey %>"></script>
|
||||||
<!--Dropbox End-->
|
<!--Dropbox End-->
|
||||||
<% } %>
|
<% } %>
|
||||||
<script src="<%-originalURL%>libs/js/material.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/material.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/pnotify.custom.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/pnotify.custom.min.js"></script>
|
||||||
<script><% include ../libs/js/moment.js %></script>
|
<script><% include ../libs/js/moment.js %></script>
|
||||||
<script><% include ../libs/js/livestamp.min.js %></script>
|
<script><% include ../libs/js/livestamp.min.js %></script>
|
||||||
<script src="<%-originalURL%>libs/js/placeholder.js"></script>
|
<script src="<%-window.libURL%>libs/js/placeholder.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/bootstrap.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/bootstrap.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/bootstrap-table.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/bootstrap-table.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/socket.io.js"></script>
|
<script src="<%-window.libURL%>libs/js/socket.io.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/fullcalendar.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/fullcalendar.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/hls.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/hls.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/libde265.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/libde265.min.js"></script>
|
||||||
<script type="text/javascript" src="<%-originalURL%>libs/js/flv.shinobi.js">;</script>
|
<script type="text/javascript" src="<%-window.libURL%>libs/js/flv.shinobi.js">;</script>
|
||||||
<script src="<%-originalURL%>libs/js/menu.js"></script>
|
<script src="<%-window.libURL%>libs/js/menu.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/clock.js"></script>
|
<script src="<%-window.libURL%>libs/js/clock.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/poseidon.js"></script>
|
<script src="<%-window.libURL%>libs/js/poseidon.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/Chart.js"></script>
|
<script src="<%-window.libURL%>libs/js/Chart.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/clusterPoints.js"></script>
|
<script src="<%-window.libURL%>libs/js/clusterPoints.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/daterangepicker.js"></script>
|
<script src="<%-window.libURL%>libs/js/daterangepicker.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/jquery.canvasAreaDraw.js"></script>
|
<script src="<%-window.libURL%>libs/js/jquery.canvasAreaDraw.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/jquery-ui.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/jquery-ui.min.js"></script>
|
||||||
<!--<script src="<%-originalURL%>libs/js/jquery.ui.touch.js"></script>-->
|
<!--<script src="<%-window.libURL%>libs/js/jquery.ui.touch.js"></script>-->
|
||||||
<script src="<%-originalURL%>libs/js/lodash.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/lodash.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/gridstack.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/gridstack.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/gridstack.jQueryUI.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/gridstack.jQueryUI.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/basic.js"></script>
|
<script src="<%-window.libURL%>libs/js/basic.js"></script>
|
||||||
<script><% include ../libs/js/main.dash2.js %></script>
|
<script><% include ../libs/js/main.dash2.js %></script>
|
||||||
<% include blocks/help.ejs %>
|
<% include blocks/help.ejs %>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<a href="http://shinobi.video" target="_blank">
|
<a href="http://shinobi.video" target="_blank">
|
||||||
<img src="<%-originalURL%>libs/img/icon/apple-touch-icon-76x76.png" style="border-radius:50%">
|
<img src="<%-window.libURL%>libs/img/icon/apple-touch-icon-76x76.png" style="border-radius:50%">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="<%-originalURL%>libs/js/material.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/material.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
<% var failedLogin;if(failedLogin===true){ %>
|
<% var failedLogin;if(failedLogin===true){ %>
|
||||||
localStorage.removeItem('ShinobiLogin_'+location.host)
|
localStorage.removeItem('ShinobiLogin_'+location.host)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<% include blocks/header %>
|
<% include blocks/header %>
|
||||||
<script>var $user=<%- JSON.stringify($user) %>;</script>
|
<script>var $user=<%- JSON.stringify($user) %>;</script>
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/bootstrap.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap.min.css">
|
||||||
<div id="main" class="container">
|
<div id="main" class="container">
|
||||||
<a class="btn btn-danger btn-lg" record>Stream</a>
|
<a class="btn btn-danger btn-lg" record>Stream</a>
|
||||||
<div>
|
<div>
|
||||||
|
@ -17,11 +17,14 @@ requires https or firefox
|
||||||
</div>
|
</div>
|
||||||
<video id="video"><source></video>
|
<video id="video"><source></video>
|
||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
<script src="<%-originalURL%>libs/js/socket.io.js"></script>
|
<script src="<%-window.libURL%>libs/js/socket.io.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/menu.js"></script>
|
<script src="<%-window.libURL%>libs/js/basic.js"></script>
|
||||||
|
<script src="<%-window.libURL%>libs/js/menu.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$.ccio={};$.ls=localStorage;
|
$.ccio={};$.ls=localStorage;
|
||||||
$.ccio.ws=io(location.origin);
|
$.ccio.ws=io(location.origin,{
|
||||||
|
path : tool.checkCorrectPathEnding(location.pathname)+'socket.io'
|
||||||
|
});
|
||||||
$.ccio.ws.on('connect',function (d){
|
$.ccio.ws.on('connect',function (d){
|
||||||
$(document).ready(function(e){
|
$(document).ready(function(e){
|
||||||
$.ccio.cx=function(x){if(!x.ke){x.ke=$user.ke;};if(!x.uid){x.uid=$user.uid;};return $.ccio.ws.emit('r',x)}
|
$.ccio.cx=function(x){if(!x.ke){x.ke=$user.ke;};if(!x.uid){x.uid=$user.uid;};return $.ccio.ws.emit('r',x)}
|
||||||
|
@ -64,13 +67,13 @@ $.ccio.start=function(){
|
||||||
},1000/$.ccio.framerate);
|
},1000/$.ccio.framerate);
|
||||||
$('[record]').unbind('click').click($.ccio.end)
|
$('[record]').unbind('click').click($.ccio.end)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$.ccio.vid = {e:$('#video'),c:$('#canvas')};
|
$.ccio.vid = {e:$('#video'),c:$('#canvas')};
|
||||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia||navigator.mediaDevices.getUserMedia;
|
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia||navigator.mediaDevices.getUserMedia;
|
||||||
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
||||||
|
@ -88,16 +91,16 @@ $.ccio.vid = {e:$('#video'),c:$('#canvas')};
|
||||||
$('[record]').click($.ccio.start)
|
$('[record]').click($.ccio.start)
|
||||||
})
|
})
|
||||||
}, function(err){console.error('getUserMedia',err)});
|
}, function(err){console.error('getUserMedia',err)});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//draw selectable mons
|
//draw selectable mons
|
||||||
var tmp='';
|
var tmp='';
|
||||||
if($user.mons&&$user.mons.length>0){
|
if($user.mons&&$user.mons.length>0){
|
||||||
|
@ -121,10 +124,10 @@ $.ccio.vid = {e:$('#video'),c:$('#canvas')};
|
||||||
$.ls.setItem('Shinobi_socket_camera',e.a)
|
$.ls.setItem('Shinobi_socket_camera',e.a)
|
||||||
$('[monitor]').removeClass('active'),e.e.addClass('active');
|
$('[monitor]').removeClass('active'),e.e.addClass('active');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
if($user.mons.length>0&&$.ls.getItem('Shinobi_socket_camera')){$('[monitor="'+$.ls.getItem('Shinobi_socket_camera')+'"]').click()}else{$.ccio.selected=null;}
|
if($user.mons.length>0&&$.ls.getItem('Shinobi_socket_camera')){$('[monitor="'+$.ls.getItem('Shinobi_socket_camera')+'"]').click()}else{$.ccio.selected=null;}
|
||||||
|
|
||||||
$('body')
|
$('body')
|
||||||
.on('click','.logout',function(e){
|
.on('click','.logout',function(e){
|
||||||
localStorage.removeItem('ShinobiLogin_'+location.host);location.href='/';
|
localStorage.removeItem('ShinobiLogin_'+location.host);location.href='/';
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title><%-lang.Superuser%> - <%-lang.Shinobi%></title>
|
<title><%-lang.Superuser%> - <%-lang.Shinobi%></title>
|
||||||
|
<% window.libURL = originalURL + global.s.checkCorrectPathEnding(config.webPaths.admin) %>
|
||||||
<% include blocks/header-meta.ejs %>
|
<% include blocks/header-meta.ejs %>
|
||||||
<% include blocks/header-favicon.ejs %>
|
<% include blocks/header-favicon.ejs %>
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
|
@ -10,16 +11,17 @@
|
||||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700,200" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700,200" rel="stylesheet" />
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" />
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" />
|
||||||
<!-- CSS Files -->
|
<!-- CSS Files -->
|
||||||
<link href="<%-originalURL%>libs/css/bootstrap4.min.css" rel="stylesheet" />
|
<link href="<%-window.libURL%>libs/css/bootstrap4.min.css" rel="stylesheet" />
|
||||||
<link href="<%-originalURL%>libs/css/main.dash2.css" rel="stylesheet" />
|
<link href="<%-window.libURL%>libs/css/main.dash2.css" rel="stylesheet" />
|
||||||
<link rel="stylesheet" href="<%-originalURL%>libs/css/pnotify.custom.min.css">
|
<link rel="stylesheet" href="<%-window.libURL%>libs/css/pnotify.custom.min.css">
|
||||||
<link href="<%-originalURL%>libs/css/now-ui-kit.css?v=1.1.0" rel="stylesheet" />
|
<link href="<%-window.libURL%>libs/css/now-ui-kit.css?v=1.1.0" rel="stylesheet" />
|
||||||
<link href="<%-originalURL%>libs/css/super-page.css" rel="stylesheet" />
|
<link href="<%-window.libURL%>libs/css/super-page.css" rel="stylesheet" />
|
||||||
<script src="<%-originalURL%>libs/js/jquery.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/jquery.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/jquery.serialize.js"></script>
|
<script src="<%-window.libURL%>libs/js/basic.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/pnotify.custom.min.js"></script>
|
<script src="<%-window.libURL%>libs/js/jquery.serialize.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/popper.min.js" type="text/javascript"></script>
|
<script src="<%-window.libURL%>libs/js/pnotify.custom.min.js"></script>
|
||||||
<script src="<%-originalURL%>libs/js/bootstrap4.min.js" type="text/javascript"></script>
|
<script src="<%-window.libURL%>libs/js/popper.min.js" type="text/javascript"></script>
|
||||||
|
<script src="<%-window.libURL%>libs/js/bootstrap4.min.js" type="text/javascript"></script>
|
||||||
<style>
|
<style>
|
||||||
.form-group label>div:first-child{width:40%}
|
.form-group label>div:first-child{width:40%}
|
||||||
.list-group li .form-group {margin:0}
|
.list-group li .form-group {margin:0}
|
||||||
|
@ -41,7 +43,7 @@
|
||||||
<span class="navbar-toggler-bar bar3"></span>
|
<span class="navbar-toggler-bar bar3"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse navbar-collapse justify-content-end" id="navigation" data-nav-image="<%-originalURL%>libs/img/blurred-image-1.jpg">
|
<div class="collapse navbar-collapse justify-content-end" id="navigation" data-nav-image="<%-window.libURL%>libs/img/blurred-image-1.jpg">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="javascript:location.href=location.pathname" class="nav-link" class="logout">
|
<a href="javascript:location.href=location.pathname" class="nav-link" class="logout">
|
||||||
|
@ -169,12 +171,12 @@
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<% include blocks/confirm.ejs %>
|
<% include blocks/confirm.ejs %>
|
||||||
<script src="<%-originalURL%>libs/js/pnotify.custom.min.js" type="text/javascript"></script>
|
<script src="<%-window.libURL%>libs/js/pnotify.custom.min.js" type="text/javascript"></script>
|
||||||
<script><% include ../libs/js/moment.js %></script>
|
<script><% include ../libs/js/moment.js %></script>
|
||||||
<script src="<%-originalURL%>libs/js/livestamp.min.js" type="text/javascript"></script>
|
<script src="<%-window.libURL%>libs/js/livestamp.min.js" type="text/javascript"></script>
|
||||||
<script src="<%-originalURL%>libs/js/socket.io.js" type="text/javascript"></script>
|
<script src="<%-window.libURL%>libs/js/socket.io.js" type="text/javascript"></script>
|
||||||
<script src="<%-originalURL%>libs/js/placeholder.js" type="text/javascript"></script>
|
<script src="<%-window.libURL%>libs/js/placeholder.js" type="text/javascript"></script>
|
||||||
<script src="<%-originalURL%>libs/js/now-ui-kit.js?v=1.1.0" type="text/javascript"></script>
|
<script src="<%-window.libURL%>libs/js/now-ui-kit.js?v=1.1.0" type="text/javascript"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
PNotify.prototype.options.styling = "fontawesome";
|
PNotify.prototype.options.styling = "fontawesome";
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
@ -208,7 +210,9 @@ switch($user.lang){
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$.ccio.ws=io(location.origin);
|
$.ccio.ws=io(location.origin,{
|
||||||
|
path : tool.checkCorrectPathEnding(location.pathname)+'socket.io'
|
||||||
|
});
|
||||||
$.ccio.cx=function(x){return $.ccio.ws.emit('super',x)}
|
$.ccio.cx=function(x){return $.ccio.ws.emit('super',x)}
|
||||||
$.ccio.ws.on('connect',function(d){
|
$.ccio.ws.on('connect',function(d){
|
||||||
$.ccio.cx({f:'init',mail:$user.mail,pass:$user.pass})
|
$.ccio.cx({f:'init',mail:$user.mail,pass:$user.pass})
|
||||||
|
|
2
web/templates/.gitignore
vendored
Normal file
2
web/templates/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
black
|
||||||
|
argon
|
Loading…
Add table
Add a link
Reference in a new issue