Merge branch 'dev' into 'master'

Shiny Pikachu

See merge request Shinobi-Systems/Shinobi!14
merge-requests/23/head
Moe 2018-07-11 02:38:47 +00:00
commit 7c35dfa6f6
14 changed files with 785 additions and 261 deletions

View File

@ -102,6 +102,7 @@ Courthouse Vancouver Robson Square
Node.js - https://nodejs.org/en/ Node.js - https://nodejs.org/en/
MariaDB - https://mariadb.org/ MariaDB - https://mariadb.org/
FFmpeg - https://www.ffmpeg.org/ FFmpeg - https://www.ffmpeg.org/
request - https://www.npmjs.com/package/request
Express (npm) - https://expressjs.com/ https://www.npmjs.com/package/express Express (npm) - https://expressjs.com/ https://www.npmjs.com/package/express
EJS (npm) - http://ejs.co/ https://www.npmjs.com/package/ejs EJS (npm) - http://ejs.co/ https://www.npmjs.com/package/ejs
pam-diff (npm) (Motion Detector) - https://github.com/kevinGodell/pam-diff pam-diff (npm) (Motion Detector) - https://github.com/kevinGodell/pam-diff

587
camera.js
View File

@ -116,7 +116,6 @@ if(config.databaseType===undefined){config.databaseType='mysql'}
if(config.pluginKeys===undefined)config.pluginKeys={}; if(config.pluginKeys===undefined)config.pluginKeys={};
if(config.databaseLogs===undefined){config.databaseLogs=false} if(config.databaseLogs===undefined){config.databaseLogs=false}
if(config.useUTC===undefined){config.useUTC=false} if(config.useUTC===undefined){config.useUTC=false}
if(config.strictDatabase===undefined){config.strictDatabase=false}
if(config.pipeAddition===undefined){config.pipeAddition=7}else{config.pipeAddition=parseInt(config.pipeAddition)} if(config.pipeAddition===undefined){config.pipeAddition=7}else{config.pipeAddition=parseInt(config.pipeAddition)}
//Web Paths //Web Paths
if(config.webPaths===undefined){config.webPaths={}} if(config.webPaths===undefined){config.webPaths={}}
@ -220,42 +219,24 @@ 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.sqlDate = function(value){
var dateQueryFunction = ''
if(databaseOptions.client === 'sqlite3'){
value = value.toLowerCase()
if (value.slice(-1) !== 's') {
value = value+'s'
}
dateQueryFunction = "datetime('now', '-"+value+"')"
}else{
value = value.toUpperCase()
if (value.slice(-1) === 'S') {
value = value.slice(0, -1);
}
dateQueryFunction = "DATE_SUB(NOW(), INTERVAL "+value+")"
}
return dateQueryFunction
}
s.mergeQueryValues = function(query,values){ s.mergeQueryValues = function(query,values){
if(!values){values=[]} if(!values){values=[]}
var valuesNotFunction = true; var valuesNotFunction = true;
if(typeof values === 'function'){ if(typeof values === 'function'){
var onMoveOn = values;
var values = []; var values = [];
valuesNotFunction = false; valuesNotFunction = false;
} }
if(!onMoveOn){onMoveOn=function(){}}
if(values&&valuesNotFunction){ if(values&&valuesNotFunction){
var splitQuery = query.split('?') var splitQuery = query.split('?')
var newQuery = '' var newQuery = ''
splitQuery.forEach(function(v,n){ splitQuery.forEach(function(v,n){
newQuery += v newQuery += v
if(values[n]){ var value = values[n]
if(isNaN(values[n])){ if(value){
newQuery += "'"+values[n]+"'" if(isNaN(value) || value instanceof Date){
newQuery += "'"+value+"'"
}else{ }else{
newQuery += values[n] newQuery += value
} }
} }
}) })
@ -264,7 +245,11 @@ s.mergeQueryValues = function(query,values){
} }
return newQuery return newQuery
} }
s.sqlQuery = function(query,values,onMoveOn,hideLog){ s.stringToSqlTime = function(value){
newValue = new Date(value.replace('T',' '))
return newValue
}
s.sqlQuery = function(query,values,onMoveOn){
if(!values){values=[]} if(!values){values=[]}
if(typeof values === 'function'){ if(typeof values === 'function'){
var onMoveOn = values; var onMoveOn = values;
@ -272,24 +257,53 @@ s.sqlQuery = function(query,values,onMoveOn,hideLog){
} }
if(!onMoveOn){onMoveOn=function(){}} if(!onMoveOn){onMoveOn=function(){}}
var mergedQuery = s.mergeQueryValues(query,values) var mergedQuery = s.mergeQueryValues(query,values)
return s.databaseEngine.raw(query,values) s.debugLog('s.sqlQuery QUERY',mergedQuery)
.asCallback(function(err,r){ return s.databaseEngine
if(err&&config.databaseLogs){ .raw(query,values)
s.systemLog('s.sqlQuery QUERY',query) .asCallback(function(err,r){
s.systemLog('s.sqlQuery ERROR',err) if(err){
console.log('s.sqlQuery QUERY ERRORED',query)
console.log('s.sqlQuery ERROR',err)
}
if(onMoveOn && typeof onMoveOn === 'function'){
switch(databaseOptions.client){
case'sqlite3':
if(!r)r=[]
break;
default:
if(r)r=r[0]
break;
} }
if(onMoveOn && typeof onMoveOn === 'function'){ onMoveOn(err,r)
switch(databaseOptions.client){ }
case'sqlite3': })
if(!r)r=[] }
break; //discord bot
default: if(config.discordBot === true){
if(r)r=r[0] try{
break; var Discord = require("discord.js")
s.sendDiscordAlert = function(data,files,groupKey){
if(!data)data = {};
var sendBody = Object.assign({
color: 3447003,
title: 'Alert from Shinobi',
description: "",
fields: [],
timestamp: new Date(),
footer: {
icon_url: "https://shinobi.video/libs/assets/icon/apple-touch-icon-152x152.png",
text: "Shinobi Systems"
} }
onMoveOn(err,r) },data)
} s.group[groupKey].discordBot.channels.get(s.group[groupKey].init.discordbot_channel).send({
}) embed: sendBody,
files: files
})
}
}catch(err){
console.log('Could not start Discord bot, please run "npm install discord.js" inside the Shinobi folder.')
s.sendDiscordAlert = function(){}
}
} }
//kill any ffmpeg running //kill any ffmpeg running
s.ffmpegKill=function(){ s.ffmpegKill=function(){
@ -345,7 +359,7 @@ s.txWithSubPermissions = function(z,y,permissionChoices){
var valid=0 var valid=0
var checked=permissionChoices.length var checked=permissionChoices.length
permissionChoices.forEach(function(b){ permissionChoices.forEach(function(b){
if(user.details[b].indexOf(z.mid)!==-1){ if(user.details[b] && user.details[b].indexOf(z.mid)!==-1){
++valid ++valid
} }
}) })
@ -449,6 +463,21 @@ s.getFunctionParamNames = function(func) {
result = []; result = [];
return result; return result;
} }
s.getDetectorStreams = function(monitor){
var pathDir = s.dir.streams+monitor.ke+'/'+monitor.id+'/'
var streamDirItems = fs.readdirSync(pathDir)
var items = []
streamDirItems.forEach(function(filename){
if(filename.indexOf('detectorStream') > -1 && filename.indexOf('.m3u8') === -1){
try{
items.push(pathDir+filename)
}catch(err){
console.log(err)
}
}
})
return items
}
s.createPamDiffRegionArray = function(regions,globalSensitivity,fullFrame){ s.createPamDiffRegionArray = function(regions,globalSensitivity,fullFrame){
var pamDiffCompliantArray = [], var pamDiffCompliantArray = [],
arrayForOtherStuff = [], arrayForOtherStuff = [],
@ -494,7 +523,7 @@ s.getRequest = function(url,callback){
s.kill=function(x,e,p){ s.kill=function(x,e,p){
if(s.group[e.ke]&&s.group[e.ke].mon[e.id]&&s.group[e.ke].mon[e.id].spawn !== undefined){ if(s.group[e.ke]&&s.group[e.ke].mon[e.id]&&s.group[e.ke].mon[e.id].spawn !== undefined){
if(s.group[e.ke].mon[e.id].spawn){ if(s.group[e.ke].mon[e.id].spawn){
s.group[e.ke].mon[e.mid].allowStdinWrite = false s.group[e.ke].mon[e.id].allowStdinWrite = false
s.txToDashcamUsers({ s.txToDashcamUsers({
f : 'disable_stream', f : 'disable_stream',
ke : e.ke, ke : e.ke,
@ -549,7 +578,7 @@ s.log=function(e,x){
// s.systemLog('s.log : ',{f:'log',ke:e.ke,mid:e.mid,log:x,time:s.timeObject()},'GRP_'+e.ke) // s.systemLog('s.log : ',{f:'log',ke:e.ke,mid:e.mid,log:x,time:s.timeObject()},'GRP_'+e.ke)
} }
//system log //system log
s.systemLog=function(q,w,e){ s.systemLog = function(q,w,e){
if(!w){w=''} if(!w){w=''}
if(!e){e=''} if(!e){e=''}
if(config.systemLog===true){ if(config.systemLog===true){
@ -560,6 +589,17 @@ s.systemLog=function(q,w,e){
return console.log(s.timeObject().format(),q,w,e) return console.log(s.timeObject().format(),q,w,e)
} }
} }
//system log
s.debugLog = function(q,w,e){
if(!w){w = ''}
if(!e){e = ''}
if(config.debugLog === true){
console.log(s.timeObject().format(),q,w,e)
if(config.debugLogVerbose === true){
console.log(new Error())
}
}
}
//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')
@ -659,12 +699,7 @@ s.init=function(x,e,k,fn){
switch(x){ switch(x){
case 0://init camera case 0://init camera
if(!s.group[e.ke]){s.group[e.ke]={}}; if(!s.group[e.ke]){s.group[e.ke]={}};
if(!s.group[e.ke].fileBin){s.group[e.ke].fileBin={}};
if(!s.group[e.ke].mon){s.group[e.ke].mon={}} if(!s.group[e.ke].mon){s.group[e.ke].mon={}}
if(!s.group[e.ke].sizeChangeQueue){s.group[e.ke].sizeChangeQueue=[]}
if(!s.group[e.ke].sizePurgeQueue){s.group[e.ke].sizePurgeQueue=[]}
if(!s.group[e.ke].users){s.group[e.ke].users={}}
if(!s.group[e.ke].dashcamUsers){s.group[e.ke].dashcamUsers={}}
if(!s.group[e.ke].mon[e.mid]){s.group[e.ke].mon[e.mid]={}} if(!s.group[e.ke].mon[e.mid]){s.group[e.ke].mon[e.mid]={}}
if(!s.group[e.ke].mon[e.mid].streamIn){s.group[e.ke].mon[e.mid].streamIn={}}; if(!s.group[e.ke].mon[e.mid].streamIn){s.group[e.ke].mon[e.mid].streamIn={}};
if(!s.group[e.ke].mon[e.mid].emitterChannel){s.group[e.ke].mon[e.mid].emitterChannel={}}; if(!s.group[e.ke].mon[e.mid].emitterChannel){s.group[e.ke].mon[e.mid].emitterChannel={}};
@ -679,7 +714,6 @@ s.init=function(x,e,k,fn){
if(!s.group[e.ke].mon[e.mid].started){s.group[e.ke].mon[e.mid].started=0}; if(!s.group[e.ke].mon[e.mid].started){s.group[e.ke].mon[e.mid].started=0};
if(s.group[e.ke].mon[e.mid].delete){clearTimeout(s.group[e.ke].mon[e.mid].delete)} if(s.group[e.ke].mon[e.mid].delete){clearTimeout(s.group[e.ke].mon[e.mid].delete)}
if(!s.group[e.ke].mon_conf){s.group[e.ke].mon_conf={}} if(!s.group[e.ke].mon_conf){s.group[e.ke].mon_conf={}}
s.init('apps',e)
break; break;
case'group': case'group':
if(!s.group[e.ke]){ if(!s.group[e.ke]){
@ -688,6 +722,11 @@ s.init=function(x,e,k,fn){
if(!s.group[e.ke].init){ if(!s.group[e.ke].init){
s.group[e.ke].init={} s.group[e.ke].init={}
} }
if(!s.group[e.ke].fileBin){s.group[e.ke].fileBin={}};
if(!s.group[e.ke].sizeChangeQueue){s.group[e.ke].sizeChangeQueue=[]}
if(!s.group[e.ke].sizePurgeQueue){s.group[e.ke].sizePurgeQueue=[]}
if(!s.group[e.ke].users){s.group[e.ke].users={}}
if(!s.group[e.ke].dashcamUsers){s.group[e.ke].dashcamUsers={}}
if(!e.limit||e.limit===''){e.limit=10000}else{e.limit=parseFloat(e.limit)} if(!e.limit||e.limit===''){e.limit=10000}else{e.limit=parseFloat(e.limit)}
//save global space limit for group key (mb) //save global space limit for group key (mb)
s.group[e.ke].sizeLimit=e.limit; s.group[e.ke].sizeLimit=e.limit;
@ -723,6 +762,18 @@ s.init=function(x,e,k,fn){
ar.webdav_pass ar.webdav_pass
); );
} }
//discordbot
if(!s.group[e.ke].discordBot &&
config.discordBot === true &&
ar.discordbot === '1' &&
ar.discordbot_token !== ''
){
s.group[e.ke].discordBot = new Discord.Client()
s.group[e.ke].discordBot.on('ready', () => {
console.log(`${r.mail} : Discord Bot Logged in as ${s.group[e.ke].discordBot.user.tag}!`)
})
s.group[e.ke].discordBot.login(ar.discordbot_token)
}
Object.keys(ar).forEach(function(v){ Object.keys(ar).forEach(function(v){
s.group[e.ke].init[v]=ar[v] s.group[e.ke].init[v]=ar[v]
}) })
@ -918,15 +969,12 @@ s.video=function(x,e,k){
time = e.time time = e.time
} }
time = new Date(time) time = new Date(time)
if(config.databaseType !== 'sqlite'){
time = moment(time).format('YYYY-MM-DD HH:mm:ss')
}
e.save=[e.id,e.ke,time]; e.save=[e.id,e.ke,time];
s.sqlQuery('SELECT * FROM Videos WHERE `mid`=? AND `ke`=? AND `time`=? LIMIT 1',e.save,function(err,r){ s.sqlQuery('SELECT * FROM Videos WHERE `mid`=? AND `ke`=? AND `time`=?',e.save,function(err,r){
if(r&&r[0]){ if(r&&r[0]){
r=r[0] r=r[0]
var dir=s.video('getDir',r) var dir=s.video('getDir',r)
s.sqlQuery('DELETE FROM Videos WHERE `mid`=? AND `ke`=? AND `time`=? LIMIT 1',e.save,function(){ s.sqlQuery('DELETE FROM Videos WHERE `mid`=? AND `ke`=? AND `time`=?',e.save,function(){
fs.stat(dir+filename,function(err,file){ fs.stat(dir+filename,function(err,file){
if(err){ if(err){
s.systemLog('File Delete Error : '+e.ke+' : '+' : '+e.mid,err) s.systemLog('File Delete Error : '+e.ke+' : '+' : '+e.mid,err)
@ -1093,7 +1141,7 @@ s.video=function(x,e,k){
if(!evs)return console.log(err) if(!evs)return console.log(err)
evs.forEach(function(ev){ evs.forEach(function(ev){
ev.dir=s.video('getDir',ev)+s.formattedTime(ev.time)+'.'+ev.ext; ev.dir=s.video('getDir',ev)+s.formattedTime(ev.time)+'.'+ev.ext;
k.del.push('(mid=? AND time=?)'); k.del.push('(mid=? AND `time`=?)');
k.ar.push(ev.mid),k.ar.push(ev.time); k.ar.push(ev.mid),k.ar.push(ev.time);
s.file('delete',ev.dir); s.file('delete',ev.dir);
s.init('diskUsedSet',e,-(ev.size/1000000)) s.init('diskUsedSet',e,-(ev.size/1000000))
@ -1238,10 +1286,6 @@ s.video=function(x,e,k){
k.details.dir = e.details.dir k.details.dir = e.details.dir
} }
if(config.useUTC === true)k.details.isUTC = config.useUTC; if(config.useUTC === true)k.details.isUTC = config.useUTC;
if(config.strictDatabase === true){
e.startTime = s.formattedTime(e.startTime)
e.endTime = s.formattedTime(e.endTime)
}
var save = [ var save = [
e.mid, e.mid,
e.ke, e.ke,
@ -2442,9 +2486,7 @@ s.camera=function(x,e,cn,tx){
e.details.fatal_max = parseFloat(e.details.fatal_max) e.details.fatal_max = parseFloat(e.details.fatal_max)
} }
var errorFatal = function(errorMessage){ var errorFatal = function(errorMessage){
if(config.debugSystem === true){ s.debugLog(errorMessage)
console.log(errorMessage,(new Error()).stack)
}
clearTimeout(s.group[e.ke].mon[e.id].err_fatal_timeout); clearTimeout(s.group[e.ke].mon[e.id].err_fatal_timeout);
++errorFatalCount; ++errorFatalCount;
if(s.group[e.ke].mon[e.id].started===1){ if(s.group[e.ke].mon[e.id].started===1){
@ -2518,7 +2560,7 @@ s.camera=function(x,e,cn,tx){
cutoff *= 100 cutoff *= 100
} }
s.group[e.ke].mon[e.id].checker=setTimeout(function(){ s.group[e.ke].mon[e.id].checker=setTimeout(function(){
if(s.group[e.ke].mon[e.id].started === 1){ if(s.group[e.ke].mon[e.id].started === 1 && s.group[e.ke].mon_conf[e.id].mode === 'record'){
launchMonitorProcesses(); launchMonitorProcesses();
s.init('monitorStatus',{id:e.id,ke:e.ke,status:lang.Restarting}); s.init('monitorStatus',{id:e.id,ke:e.ke,status:lang.Restarting});
s.log(e,{type:lang['Camera is not recording'],msg:{msg:lang['Restarting Process']}}); s.log(e,{type:lang['Camera is not recording'],msg:{msg:lang['Restarting Process']}});
@ -3193,8 +3235,71 @@ s.camera=function(x,e,cn,tx){
}).end(); }).end();
} }
var screenshotName = 'Motion_'+(d.mon.name.replace(/[^\w\s]/gi,''))+'_'+d.id+'_'+d.ke+'_'+s.formattedTime()
var screenshotBuffer = null
var detectorStreamBuffers = null
//discord bot
if(d.mon.details.detector_discordbot === '1' && !s.group[d.ke].mon[d.id].detector_discordbot){
var detector_discordbot_timeout
if(!d.mon.details.detector_discordbot_timeout||d.mon.details.detector_discordbot_timeout===''){
detector_discordbot_timeout = 1000*60*10;
}else{
detector_discordbot_timeout = parseFloat(d.mon.details.detector_discordbot_timeout)*1000*60;
}
//lock mailer so you don't get emailed on EVERY trigger event.
s.group[d.ke].mon[d.id].detector_discordbot=setTimeout(function(){
//unlock so you can mail again.
clearTimeout(s.group[d.ke].mon[d.id].detector_discordbot);
delete(s.group[d.ke].mon[d.id].detector_discordbot);
},detector_discordbot_timeout);
var files = []
var sendAlert = function(){
s.sendDiscordAlert({
author: {
name: s.group[d.ke].mon_conf[d.id].name,
icon_url: "https://shinobi.video/libs/assets/icon/apple-touch-icon-152x152.png"
},
title: lang.Event+' - '+screenshotName,
description: lang.EventText1+' '+s.timeObject(new Date).format(),
fields: [],
timestamp: new Date(),
footer: {
icon_url: "https://shinobi.video/libs/assets/icon/apple-touch-icon-152x152.png",
text: "Shinobi Systems"
}
},files,d.ke)
}
if(!detectorStreamBuffers){
detectorStreamBuffers = s.getDetectorStreams(d)
}
detectorStreamBuffers.slice(detectorStreamBuffers.length - 2,detectorStreamBuffers.length).forEach(function(filepath,n){
files.push({
attachment: filepath,
name: 'Video Clip '+n+'.ts'
})
})
if(screenshotBuffer){
sendAlert()
}else if(d.mon.details.snap === '1'){
fs.readFile(s.dir.streams+'/'+d.ke+'/'+d.id+'/s.jpg',function(err, frame){
if(err){
s.systemLog(lang.EventText2+' '+d.ke+' '+d.id,err)
}else{
screenshotBuffer = frame
files.push({
attachment: screenshotBuffer,
name: screenshotName+'.jpg'
})
}
sendAlert()
})
}else{
sendAlert()
}
}
//mailer //mailer
if(config.mail&&!s.group[d.ke].mon[d.id].detector_mail&&d.mon.details.detector_mail==='1'){ if(config.mail && !s.group[d.ke].mon[d.id].detector_mail && d.mon.details.detector_mail === '1'){
s.sqlQuery('SELECT mail FROM Users WHERE ke=? AND details NOT LIKE ?',[d.ke,'%"sub"%'],function(err,r){ s.sqlQuery('SELECT mail FROM Users WHERE ke=? AND details NOT LIKE ?',[d.ke,'%"sub"%'],function(err,r){
r=r[0]; r=r[0];
var detector_mail_timeout var detector_mail_timeout
@ -3209,35 +3314,53 @@ s.camera=function(x,e,cn,tx){
clearTimeout(s.group[d.ke].mon[d.id].detector_mail); clearTimeout(s.group[d.ke].mon[d.id].detector_mail);
delete(s.group[d.ke].mon[d.id].detector_mail); delete(s.group[d.ke].mon[d.id].detector_mail);
},detector_mail_timeout); },detector_mail_timeout);
d.frame_filename='Motion_'+(d.mon.name.replace(/[^\w\s]/gi, ''))+'_'+d.id+'_'+d.ke+'_'+s.formattedTime()+'.jpg'; var files = []
fs.readFile(s.dir.streams+'/'+d.ke+'/'+d.id+'/s.jpg',function(err, frame){ var sendMail = function(){
d.mailOptions = { d.mailOptions = {
from: '"ShinobiCCTV" <no-reply@shinobi.video>', // sender address from: '"ShinobiCCTV" <no-reply@shinobi.video>', // sender address
to: r.mail, // list of receivers to: r.mail, // list of receivers
subject: lang.Event+' - '+d.frame_filename, // Subject line subject: lang.Event+' - '+screenshotName, // Subject line
html: '<i>'+lang.EventText1+' '+s.timeObject(new Date).format()+'.</i>', html: '<i>'+lang.EventText1+' '+s.timeObject(new Date).format()+'.</i>',
}; attachments: files
if(err){
s.systemLog(lang.EventText2+' '+d.ke+' '+d.id,err)
}else{
d.mailOptions.attachments=[
{
filename: d.frame_filename,
content: frame
}
]
d.mailOptions.html='<i>'+lang.EventText3+'</i>'
} }
Object.keys(d.details).forEach(function(v,n){ Object.keys(d.details).forEach(function(v,n){
d.mailOptions.html+='<div><b>'+v+'</b> : '+d.details[v]+'</div>' d.mailOptions.html+='<div><b>'+v+'</b> : '+d.details[v]+'</div>'
}) })
nodemailer.sendMail(d.mailOptions, (error, info) => { nodemailer.sendMail(d.mailOptions, (error, info) => {
if (error) { if (error) {
s.systemLog(lang.MailError,error) s.systemLog(lang.MailError,error)
return ; return false;
} }
}); })
}
if(!detectorStreamBuffers){
detectorStreamBuffers = s.getDetectorStreams(d)
}
detectorStreamBuffers.slice(detectorStreamBuffers.length - 2,detectorStreamBuffers.length).forEach(function(filepath,n){
files.push({
attachment: filepath,
name: 'Video Clip '+n+'.ts'
})
}) })
if(screenshotBuffer){
sendMail()
}else if(d.mon.details.snap === '1'){
fs.readFile(s.dir.streams+'/'+d.ke+'/'+d.id+'/s.jpg',function(err, frame){
if(err){
s.systemLog(lang.EventText2+' '+d.ke+' '+d.id,err)
}else{
screenshotBuffer = frame
files.push({
filename: screenshotName+'.jpg',
content: frame
})
d.mailOptions.html='<i>'+lang.EventText3+'</i>'
}
sendMail()
})
}else{
sendMail()
}
}); });
} }
if(d.mon.details.detector_command_enable==='1'&&!s.group[d.ke].mon[d.id].detector_command){ if(d.mon.details.detector_command_enable==='1'&&!s.group[d.ke].mon[d.id].detector_command){
@ -3839,57 +3962,64 @@ var tx;
if(r&&r[0]){ if(r&&r[0]){
r=r[0]; r=r[0];
d.d=JSON.parse(r.details); d.d=JSON.parse(r.details);
if(d.d.get_server_log==='1'){ if(!d.d.sub || d.d.user_change === "1"){
cn.join('GRPLOG_'+d.ke) if(d.d.get_server_log==='1'){
}else{ cn.join('GRPLOG_'+d.ke)
cn.leave('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)
//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_webdav=d.d.use_webdav
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.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
d.form.details=JSON.stringify(d.form.details)
///
d.set=[],d.ar=[];
if(d.form.pass&&d.form.pass!==''){d.form.pass=s.md5(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){
s.group[d.ke].sizeLimit = parseFloat(newSize)
delete(s.group[d.ke].webdav)
s.init('apps',d)
} }
tx({f:'user_settings_change',uid:d.uid,ke:d.ke,form:d.form}); ///unchangeable from client side, so reset them in case they did.
}); d.form.details=JSON.parse(d.form.details)
//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_webdav=d.d.use_webdav
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
d.form.details=JSON.stringify(d.form.details)
///
d.set=[],d.ar=[];
if(d.form.pass&&d.form.pass!==''){d.form.pass=s.md5(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){
s.group[d.ke].sizeLimit = parseFloat(newSize)
delete(s.group[d.ke].webdav)
if(s.group[d.ke].discordBot && s.group[d.ke].discordBot.destroy){
s.group[d.ke].discordBot.destroy()
delete(s.group[d.ke].discordBot)
}
s.init('apps',d)
}
tx({f:'user_settings_change',uid:d.uid,ke:d.ke,form:d.form});
});
}
} }
}) })
break; break;
@ -3901,15 +4031,15 @@ var tx;
switch(d.fff){ switch(d.fff){
case'videos&events': case'videos&events':
if(!d.eventLimit){ if(!d.eventLimit){
d.eventLimit=500 d.eventLimit = 500
}else{ }else{
d.eventLimit = parseInt(d.eventLimit); d.eventLimit = parseInt(d.eventLimit);
} }
if(!d.eventStartDate&&d.startDate){ if(!d.eventStartDate&&d.startDate){
d.eventStartDate=d.startDate d.eventStartDate = s.stringToSqlTime(d.startDate)
} }
if(!d.eventEndDate&&d.endDate){ if(!d.eventEndDate&&d.endDate){
d.eventEndDate=d.endDate d.eventEndDate = s.stringToSqlTime(d.endDate)
} }
var monitorQuery = '' var monitorQuery = ''
var monitorValues = [] var monitorValues = []
@ -3932,15 +4062,13 @@ var tx;
var eventQuery = 'SELECT * FROM Events WHERE ke=?'; var eventQuery = 'SELECT * FROM Events WHERE ke=?';
var eventQueryValues = [cn.ke]; var eventQueryValues = [cn.ke];
if(d.eventStartDate&&d.eventStartDate!==''){ if(d.eventStartDate&&d.eventStartDate!==''){
d.eventStartDate=d.eventStartDate.replace('T',' ')
if(d.eventEndDate&&d.eventEndDate!==''){ if(d.eventEndDate&&d.eventEndDate!==''){
d.eventEndDate=d.eventEndDate.replace('T',' ')
eventQuery+=' AND `time` >= ? AND `time` <= ?'; eventQuery+=' AND `time` >= ? AND `time` <= ?';
eventQueryValues.push(decodeURIComponent(d.eventStartDate)) eventQueryValues.push(d.eventStartDate)
eventQueryValues.push(decodeURIComponent(d.eventEndDate)) eventQueryValues.push(d.eventEndDate)
}else{ }else{
eventQuery+=' AND `time` >= ?'; eventQuery+=' AND `time` >= ?';
eventQueryValues.push(decodeURIComponent(d.eventStartDate)) eventQueryValues.push(d.eventStartDate)
} }
} }
if(monitorValues.length>0){ if(monitorValues.length>0){
@ -3969,10 +4097,10 @@ var tx;
eventQuery.push() eventQuery.push()
} }
if(!d.videoStartDate&&d.startDate){ if(!d.videoStartDate&&d.startDate){
d.videoStartDate=d.startDate d.videoStartDate = s.stringToSqlTime(d.startDate)
} }
if(!d.videoEndDate&&d.endDate){ if(!d.videoEndDate&&d.endDate){
d.videoEndDate=d.endDate d.videoEndDate = s.stringToSqlTime(d.endDate)
} }
var getVideos = function(callback){ var getVideos = function(callback){
var videoQuery='SELECT * FROM Videos WHERE ke=?'; var videoQuery='SELECT * FROM Videos WHERE ke=?';
@ -3986,19 +4114,15 @@ var tx;
} }
switch(true){ switch(true){
case(d.videoStartDate&&d.videoStartDate!==''&&d.videoEndDate&&d.videoEndDate!==''): case(d.videoStartDate&&d.videoStartDate!==''&&d.videoEndDate&&d.videoEndDate!==''):
d.videoStartDate=d.videoStartDate.replace('T',' ')
d.videoEndDate=d.videoEndDate.replace('T',' ')
videoQuery+=' AND `time` '+d.videoStartDateOperator+' ? AND `end` '+d.videoEndDateOperator+' ?'; videoQuery+=' AND `time` '+d.videoStartDateOperator+' ? AND `end` '+d.videoEndDateOperator+' ?';
videoQueryValues.push(d.videoStartDate) videoQueryValues.push(d.videoStartDate)
videoQueryValues.push(d.videoEndDate) videoQueryValues.push(d.videoEndDate)
break; break;
case(d.videoStartDate&&d.videoStartDate!==''): case(d.videoStartDate&&d.videoStartDate!==''):
d.videoStartDate=d.videoStartDate.replace('T',' ')
videoQuery+=' AND `time` '+d.videoStartDateOperator+' ?'; videoQuery+=' AND `time` '+d.videoStartDateOperator+' ?';
videoQueryValues.push(d.videoStartDate) videoQueryValues.push(d.videoStartDate)
break; break;
case(d.videoEndDate&&d.videoEndDate!==''): case(d.videoEndDate&&d.videoEndDate!==''):
d.videoEndDate=d.videoEndDate.replace('T',' ')
videoQuery+=' AND `end` '+d.videoEndDateOperator+' ?'; videoQuery+=' AND `end` '+d.videoEndDateOperator+' ?';
videoQueryValues.push(d.videoEndDate) videoQueryValues.push(d.videoEndDate)
break; break;
@ -4406,10 +4530,24 @@ var tx;
d.value=d.value.concat([d.ke,d.$uid]) d.value=d.value.concat([d.ke,d.$uid])
s.sqlQuery("UPDATE Users SET "+d.condition.join(',')+" WHERE ke=? AND uid=?",d.value) s.sqlQuery("UPDATE Users SET "+d.condition.join(',')+" WHERE ke=? AND uid=?",d.value)
s.tx({f:'edit_sub_account',ke:d.ke,uid:d.$uid,mail:d.mail,form:d.form},'ADM_'+d.ke); s.tx({f:'edit_sub_account',ke:d.ke,uid:d.$uid,mail:d.mail,form:d.form},'ADM_'+d.ke);
s.sqlQuery("SELECT * FROM API WHERE ke=? AND uid=?",[d.ke,d.$uid],function(err,rows){
if(rows && rows[0]){
rows.forEach(function(row){
delete(s.api[row.code])
})
}
})
break; break;
case'delete': case'delete':
s.sqlQuery('DELETE FROM Users WHERE uid=? AND ke=? AND mail=?',[d.$uid,d.ke,d.mail]) s.sqlQuery('DELETE FROM Users WHERE uid=? AND ke=? AND mail=?',[d.$uid,d.ke,d.mail])
s.sqlQuery('DELETE FROM API WHERE uid=? AND ke=?',[d.$uid,d.ke]) s.sqlQuery("SELECT * FROM API WHERE ke=? AND uid=?",[d.ke,d.$uid],function(err,rows){
if(rows && rows[0]){
rows.forEach(function(row){
delete(s.api[row.code])
})
s.sqlQuery('DELETE FROM API WHERE uid=? AND ke=?',[d.$uid,d.ke])
}
})
s.tx({f:'delete_sub_account',ke:d.ke,uid:d.$uid,mail:d.mail},'ADM_'+d.ke); s.tx({f:'delete_sub_account',ke:d.ke,uid:d.$uid,mail:d.mail},'ADM_'+d.ke);
break; break;
} }
@ -4569,7 +4707,7 @@ var tx;
} }
s.log({ke:cn.ke,mid:'$USER'},{type:lang['Websocket Disconnected'],msg:{mail:s.group[cn.ke].users[cn.auth].mail,id:cn.uid,ip:cn.ip}}) s.log({ke:cn.ke,mid:'$USER'},{type:lang['Websocket Disconnected'],msg:{mail:s.group[cn.ke].users[cn.auth].mail,id:cn.uid,ip:cn.ip}})
delete(s.group[cn.ke].users[cn.auth]); delete(s.group[cn.ke].users[cn.auth]);
delete(s.group[cn.ke].dashcamUsers[cn.auth]); if(s.group[cn.ke].dashcamUsers && s.group[cn.ke].dashcamUsers[cn.auth])delete(s.group[cn.ke].dashcamUsers[cn.auth]);
} }
} }
if(cn.pluginEngine){ if(cn.pluginEngine){
@ -5637,7 +5775,11 @@ app.get(['/:auth/videos/:ke','/:auth/videos/:ke/:id'], function (req,res){
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){
if(user.permissions.watch_videos==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.video_view.indexOf(req.params.id)===-1){ var hasRestrictions = user.details.sub && user.details.allmonitors !== '1'
if(
user.permissions.watch_videos==="0" ||
hasRestrictions && (!user.details.video_view || user.details.video_view.indexOf(req.params.id)===-1)
){
res.end(s.s([])) res.end(s.s([]))
return return
} }
@ -5667,6 +5809,12 @@ app.get(['/:auth/videos/:ke','/:auth/videos/:ke/:id'], function (req,res){
} }
} }
if(req.query.start||req.query.end){ if(req.query.start||req.query.end){
if(req.query.start && req.query.start !== ''){
req.query.start = s.stringToSqlTime(req.query.start)
}
if(req.query.end && req.query.end !== ''){
req.query.end = s.stringToSqlTime(req.query.end)
}
if(!req.query.startOperator||req.query.startOperator==''){ if(!req.query.startOperator||req.query.startOperator==''){
req.query.startOperator='>=' req.query.startOperator='>='
} }
@ -5675,8 +5823,6 @@ app.get(['/:auth/videos/:ke','/:auth/videos/:ke/:id'], function (req,res){
} }
switch(true){ switch(true){
case(req.query.start&&req.query.start!==''&&req.query.end&&req.query.end!==''): case(req.query.start&&req.query.start!==''&&req.query.end&&req.query.end!==''):
req.query.start=req.query.start.replace('T',' ')
req.query.end=req.query.end.replace('T',' ')
req.sql+=' AND `time` '+req.query.startOperator+' ? AND `end` '+req.query.endOperator+' ?'; req.sql+=' AND `time` '+req.query.startOperator+' ? AND `end` '+req.query.endOperator+' ?';
req.count_sql+=' AND `time` '+req.query.startOperator+' ? AND `end` '+req.query.endOperator+' ?'; req.count_sql+=' AND `time` '+req.query.startOperator+' ? AND `end` '+req.query.endOperator+' ?';
req.ar.push(req.query.start) req.ar.push(req.query.start)
@ -5685,14 +5831,12 @@ app.get(['/:auth/videos/:ke','/:auth/videos/:ke/:id'], function (req,res){
req.count_ar.push(req.query.end) req.count_ar.push(req.query.end)
break; break;
case(req.query.start&&req.query.start!==''): case(req.query.start&&req.query.start!==''):
req.query.start=req.query.start.replace('T',' ')
req.sql+=' AND `time` '+req.query.startOperator+' ?'; req.sql+=' AND `time` '+req.query.startOperator+' ?';
req.count_sql+=' AND `time` '+req.query.startOperator+' ?'; req.count_sql+=' AND `time` '+req.query.startOperator+' ?';
req.ar.push(req.query.start) req.ar.push(req.query.start)
req.count_ar.push(req.query.start) req.count_ar.push(req.query.start)
break; break;
case(req.query.end&&req.query.end!==''): case(req.query.end&&req.query.end!==''):
req.query.end=req.query.end.replace('T',' ')
req.sql+=' AND `end` '+req.query.endOperator+' ?'; req.sql+=' AND `end` '+req.query.endOperator+' ?';
req.count_sql+=' AND `end` '+req.query.endOperator+' ?'; req.count_sql+=' AND `end` '+req.query.endOperator+' ?';
req.ar.push(req.query.end) req.ar.push(req.query.end)
@ -5712,17 +5856,17 @@ app.get(['/:auth/videos/:ke','/:auth/videos/:ke/:id'], function (req,res){
res.end(s.s({total:0,limit:req.query.limit,skip:0,videos:[]}, null, 3)); res.end(s.s({total:0,limit:req.query.limit,skip:0,videos:[]}, null, 3));
return return
} }
s.sqlQuery(req.count_sql,req.count_ar,function(err,count){ s.sqlQuery(req.count_sql,req.count_ar,function(err,count){
s.video('linkBuild',r,req.params.auth) s.video('linkBuild',r,req.params.auth)
if(req.query.limit.indexOf(',')>-1){ if(req.query.limit.indexOf(',')>-1){
req.skip=parseInt(req.query.limit.split(',')[0]) req.skip=parseInt(req.query.limit.split(',')[0])
req.query.limit=parseInt(req.query.limit.split(',')[0]) req.query.limit=parseInt(req.query.limit.split(',')[0])
}else{ }else{
req.skip=0 req.skip=0
req.query.limit=parseInt(req.query.limit) req.query.limit=parseInt(req.query.limit)
} }
res.end(s.s({isUTC:config.useUTC,total:count[0]['COUNT(*)'],limit:req.query.limit,skip:req.skip,videos:r}, null, 3)); res.end(s.s({isUTC:config.useUTC,total:count[0]['COUNT(*)'],limit:req.query.limit,skip:req.skip,videos:r}, null, 3));
}) })
}) })
},res,req); },res,req);
}); });
@ -5755,9 +5899,9 @@ app.get(['/:auth/events/:ke','/:auth/events/:ke/:id','/:auth/events/:ke/:id/:lim
} }
} }
if(req.params.start&&req.params.start!==''){ if(req.params.start&&req.params.start!==''){
req.params.start=req.params.start.replace('T',' ') req.params.start = s.stringToSqlTime(req.params.start)
if(req.params.end&&req.params.end!==''){ if(req.params.end&&req.params.end!==''){
req.params.end=req.params.end.replace('T',' ') req.params.end = s.stringToSqlTime(req.params.end)
req.sql+=' AND `time` >= ? AND `time` <= ?'; req.sql+=' AND `time` >= ? AND `time` <= ?';
req.ar.push(decodeURIComponent(req.params.start)) req.ar.push(decodeURIComponent(req.params.start))
req.ar.push(decodeURIComponent(req.params.end)) req.ar.push(decodeURIComponent(req.params.end))
@ -5788,7 +5932,7 @@ app.get(['/:auth/logs/:ke','/:auth/logs/:ke/:id'], function (req,res){
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){
if(user.permissions.get_logs==="0"){ if(user.permissions.get_logs==="0" || user.details.sub && user.details.view_logs !== '1'){
res.end(s.s([])) res.end(s.s([]))
return return
} }
@ -5818,13 +5962,13 @@ app.get(['/:auth/logs/:ke','/:auth/logs/:ke/:id'], function (req,res){
req.query.endOperator='<=' req.query.endOperator='<='
} }
if(req.query.start && req.query.start !== '' && req.query.end && req.query.end !== ''){ if(req.query.start && req.query.start !== '' && req.query.end && req.query.end !== ''){
req.query.start=req.query.start.replace('T',' ') req.query.start = s.stringToSqlTime(req.query.start)
req.query.end=req.query.end.replace('T',' ') req.query.end = s.stringToSqlTime(req.query.end)
req.sql+=' AND `time` '+req.query.startOperator+' ? AND `time` '+req.query.endOperator+' ?'; req.sql+=' AND `time` '+req.query.startOperator+' ? AND `time` '+req.query.endOperator+' ?';
req.ar.push(req.query.start) req.ar.push(req.query.start)
req.ar.push(req.query.end) req.ar.push(req.query.end)
}else if(req.query.start && req.query.start !== ''){ }else if(req.query.start && req.query.start !== ''){
req.query.start=req.query.start.replace('T',' ') req.query.start = s.stringToSqlTime(req.query.start)
req.sql+=' AND `time` '+req.query.startOperator+' ?'; req.sql+=' AND `time` '+req.query.startOperator+' ?';
req.ar.push(req.query.start) req.ar.push(req.query.start)
} }
@ -5886,7 +6030,8 @@ app.all(['/:auth/configureMonitor/:ke/:id','/:auth/configureMonitor/:ke/:id/:f']
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){
if(req.params.f!=='delete'){ var hasRestrictions = user.details.sub && user.details.allmonitors !== '1'
if(req.params.f !== 'delete'){
if(!req.body.data&&!req.query.data){ if(!req.body.data&&!req.query.data){
req.ret.msg='No Monitor Data found.' req.ret.msg='No Monitor Data found.'
res.end(s.s(req.ret, null, 3)) res.end(s.s(req.ret, null, 3))
@ -5905,7 +6050,10 @@ app.all(['/:auth/configureMonitor/:ke/:id','/:auth/configureMonitor/:ke/:id/:f']
} }
return return
} }
if(!user.details.sub||user.details.allmonitors==='1'||user.details.monitor_edit.indexOf(req.monitor.mid)>-1){ if(!user.details.sub ||
user.details.allmonitors === '1' ||
hasRestrictions && user.details.monitor_edit.indexOf(req.monitor.mid) >- 1 ||
hasRestrictions && user.details.monitor_create === '1'){
if(req.monitor&&req.monitor.mid&&req.monitor.name){ if(req.monitor&&req.monitor.mid&&req.monitor.name){
req.set=[],req.ar=[]; req.set=[],req.ar=[];
req.monitor.mid=req.params.id.replace(/[^\w\s]/gi,'').replace(/ /g,''); req.monitor.mid=req.params.id.replace(/[^\w\s]/gi,'').replace(/ /g,'');
@ -6148,6 +6296,94 @@ app.get('/:auth/fileBin/:ke/:id/:year/:month/:day/:file', function (req,res){
} }
s.auth(req.params,req.fn,res,req); s.auth(req.params,req.fn,res,req);
}); });
//zip videos and get link from fileBin
app.get('/:auth/zipVideos/:ke', function (req,res){
res.header("Access-Control-Allow-Origin",req.headers.origin);
var failed = function(resp){
res.setHeader('Content-Type', 'application/json');
res.end(s.s(resp))
}
if(req.query.videos && req.query.videos !== ''){
s.auth(req.params,function(user){
var videosSelected = JSON.parse(req.query.videos)
var where = []
var values = []
videosSelected.forEach(function(video){
where.push("(ke=? AND mid=? AND `time`=?)")
if(!video.ke)video.ke = req.params.ke
values.push(video.ke)
values.push(video.mid)
var time = s.nameToTime(video.filename)
if(req.query.isUTC === 'true'){
time = s.utcToLocal(time)
}
time = new Date(time)
values.push(time)
})
s.sqlQuery('SELECT * FROM Videos WHERE '+where.join(' OR '),values,function(err,r){
var resp = {ok:false}
if(r && r[0]){
resp.ok = true
var zipDownload = null
var tempFiles = []
var fileId = s.gid()
var fileBinDir = s.dir.fileBin+req.params.ke+'/'
var tempScript = s.dir.streams+req.params.ke+'/'+fileId+'.sh'
var zippedFilename = s.formattedTime()+'-'+fileId+'-Shinobi_Recordings.zip'
var zippedFile = fileBinDir+zippedFilename
var script = 'cd '+fileBinDir+' && zip -9 -r '+zippedFile
res.on('close', () => {
if(zipDownload && zipDownload.destroy){
zipDownload.destroy()
}
fs.unlink(zippedFile);
})
if(!fs.existsSync(fileBinDir)){
fs.mkdirSync(fileBinDir);
}
r.forEach(function(video){
timeFormatted = s.formattedTime(video.time)
video.filename = timeFormatted+'.'+video.ext
var dir = s.video('getDir',video)+video.filename
var tempVideoFile = timeFormatted+' - '+video.mid+'.'+video.ext
fs.writeFileSync(fileBinDir+tempVideoFile, fs.readFileSync(dir))
tempFiles.push(fileBinDir+tempVideoFile)
script += ' "'+tempVideoFile+'"'
})
fs.writeFileSync(tempScript,script,'utf8')
var zipCreate = spawn('sh',(tempScript).split(' '),{detached: true})
zipCreate.stderr.on('data',function(data){
s.log({ke:req.params.ke,mid:'$USER'},{title:'Zip Create Error',msg:data.toString()})
})
zipCreate.on('exit',function(data){
fs.unlinkSync(tempScript)
tempFiles.forEach(function(file){
fs.unlink(file,function(){})
})
res.setHeader('Content-Disposition', 'attachment; filename="'+zippedFilename+'"')
var zipDownload = fs.createReadStream(zippedFile)
zipDownload.pipe(res)
zipDownload.on('error', function (error) {
s.log({ke:req.params.ke,mid:'$USER'},{title:'Zip Download Error',msg:error.toString()})
if(zipDownload && zipDownload.destroy){
zipDownload.destroy()
}
});
zipDownload.on('close', function () {
res.end()
zipDownload.destroy();
fs.unlinkSync(zippedFile);
});
})
}else{
failed({ok:false,msg:'No Videos Found'})
}
})
},res,req);
}else{
failed({ok:false,msg:'"videos" query variable is missing from request.'})
}
});
// Get video file // Get video file
app.get('/:auth/videos/:ke/:id/:file', function (req,res){ app.get('/:auth/videos/:ke/:id/:file', function (req,res){
s.auth(req.params,function(user){ s.auth(req.params,function(user){
@ -6160,7 +6396,7 @@ app.get('/:auth/videos/:ke/:id/:file', function (req,res){
time = s.utcToLocal(time) time = s.utcToLocal(time)
} }
time = new Date(time) time = new Date(time)
s.sqlQuery('SELECT * FROM Videos WHERE ke=? AND mid=? AND time=?',[req.params.ke,req.params.id,time],function(err,r){ s.sqlQuery('SELECT * FROM Videos WHERE ke=? AND mid=? AND `time`=?',[req.params.ke,req.params.id,time],function(err,r){
if(r&&r[0]){ if(r&&r[0]){
req.dir=s.video('getDir',r[0])+req.params.file req.dir=s.video('getDir',r[0])+req.params.file
if (fs.existsSync(req.dir)){ if (fs.existsSync(req.dir)){
@ -6256,7 +6492,7 @@ app.get(['/:auth/videos/:ke/:id/:file/:mode','/:auth/videos/:ke/:id/:file/:mode/
time = s.utcToLocal(time) time = s.utcToLocal(time)
} }
time = new Date(time) time = new Date(time)
req.sql='SELECT * FROM Videos WHERE ke=? AND mid=? AND time=?'; req.sql='SELECT * FROM Videos WHERE ke=? AND mid=? AND `time`=?';
req.ar=[req.params.ke,req.params.id,time]; req.ar=[req.params.ke,req.params.id,time];
s.sqlQuery(req.sql,req.ar,function(err,r){ s.sqlQuery(req.sql,req.ar,function(err,r){
if(r&&r[0]){ if(r&&r[0]){
@ -6273,7 +6509,7 @@ app.get(['/:auth/videos/:ke/:id/:file/:mode','/:auth/videos/:ke/:id/:file/:mode/
req.ret.msg='Not a valid value.'; req.ret.msg='Not a valid value.';
}else{ }else{
req.ret.ok=true; req.ret.ok=true;
s.sqlQuery('UPDATE Videos SET status=? WHERE ke=? AND mid=? AND time=?',[req.params.f,req.params.ke,req.params.id,time]) s.sqlQuery('UPDATE Videos SET status=? WHERE ke=? AND mid=? AND `time`=?',[req.params.f,req.params.ke,req.params.id,time])
s.tx(r,'GRP_'+r.ke); s.tx(r,'GRP_'+r.ke);
} }
break; break;
@ -6890,6 +7126,7 @@ if(config.childNodes.mode === 'child'){
} }
s.systemLog(v.mail+' : '+lang.startUpText0+' : '+rr.length,v.size) s.systemLog(v.mail+' : '+lang.startUpText0+' : '+rr.length,v.size)
s.init('group',v) s.init('group',v)
s.init('apps',v)
s.systemLog(v.mail+' : '+lang.startUpText1,countFinished+'/'+count) s.systemLog(v.mail+' : '+lang.startUpText1,countFinished+'/'+count)
if(countFinished===count){ if(countFinished===count){
s.systemLog(lang.startUpText4) s.systemLog(lang.startUpText4)

View File

@ -104,6 +104,8 @@
"Can View Streams": "Can View Streams", "Can View Streams": "Can View Streams",
"Can View Videos": "Can View Videos", "Can View Videos": "Can View Videos",
"Can View Monitor": "Can View Monitor", "Can View Monitor": "Can View Monitor",
"Can Change User Settings": "Can Change User Settings",
"Can Create and Delete Monitors": "Can Create and Delete Monitors",
"Can Edit Monitor": "Can Edit Monitor", "Can Edit Monitor": "Can Edit Monitor",
"Can Delete Videos": "Can Delete Videos", "Can Delete Videos": "Can Delete Videos",
"Delete Video": "Delete Video", "Delete Video": "Delete Video",
@ -178,6 +180,7 @@
"Monitor Groups": "Monitor Groups", "Monitor Groups": "Monitor Groups",
"Group Name": "Group Name", "Group Name": "Group Name",
"WebDAV": "WebDAV", "WebDAV": "WebDAV",
"Discord Bot": "Discord Bot",
"URL": "URL", "URL": "URL",
"Autosave": "Autosave", "Autosave": "Autosave",
"Save Directory": "Save Directory", "Save Directory": "Save Directory",
@ -186,6 +189,7 @@
"Monitors per row": "Monitors per row <small>for Montage</small>", "Monitors per row": "Monitors per row <small>for Montage</small>",
"Browser Console Log": "Browser Console Log", "Browser Console Log": "Browser Console Log",
"Log Stream": "Log Stream", "Log Stream": "Log Stream",
"Privileges": "Privileges",
"All Monitors and Privileges": "All Monitors and Privileges", "All Monitors and Privileges": "All Monitors and Privileges",
"Permissions": "Permissions", "Permissions": "Permissions",
"Time-lapse Tool": "Time-lapse Tool", "Time-lapse Tool": "Time-lapse Tool",
@ -211,9 +215,13 @@
"Set to Watch Only": "Set to Watch Only", "Set to Watch Only": "Set to Watch Only",
"Save as": "Save as", "Save as": "Save as",
"Add New": "Add New", "Add New": "Add New",
"Zip and Download": "Zip and Download",
"Export Selected Videos": "Export Selected Videos",
"Delete Selected Videos": "Delete Selected Videos", "Delete Selected Videos": "Delete Selected Videos",
"DeleteSelectedVideosMsg": "Do you want to delete these videos? You cannot recover them.", "DeleteSelectedVideosMsg": "Do you want to delete these videos? You cannot recover them.",
"ExportSelectedVideosMsg": "Do you want to export these videos? It may take some time to zip and download.",
"clientStreamFailedattemptingReconnect": "Client side ctream check failed, attempting reconnect.", "clientStreamFailedattemptingReconnect": "Client side ctream check failed, attempting reconnect.",
"Export Video": "Export Video",
"Delete Filter": "Delete Filter", "Delete Filter": "Delete Filter",
"confirmDeleteFilter": "Do you want to delete this filter? You cannot recover it.", "confirmDeleteFilter": "Do you want to delete this filter? You cannot recover it.",
"Fix Video": "Fix Video", "Fix Video": "Fix Video",
@ -249,6 +257,7 @@
"Unable to Launch": "Unable to Launch", "Unable to Launch": "Unable to Launch",
"UnabletoLaunchText": "Please save new monitor first. Then attempt to launch the region editor.", "UnabletoLaunchText": "Please save new monitor first. Then attempt to launch the region editor.",
"NoVideosFoundForDateRange": "No Videos found in this date range. Try setting the start date further back.", "NoVideosFoundForDateRange": "No Videos found in this date range. Try setting the start date further back.",
"NoLogsFoundForDateRange": "No Logs found in this date range. Try widening the date range.",
"monitorEditFailedMaxReached": "Your account has reached the maximum number of cameras that can be created. Speak to an administrator if you would like this changed.", "monitorEditFailedMaxReached": "Your account has reached the maximum number of cameras that can be created. Speak to an administrator if you would like this changed.",
"in": "in", "in": "in",
"ago": "ago", "ago": "ago",
@ -369,7 +378,9 @@
"Allow Next Trigger": "Allow Next Trigger <small>in Milliseconds</small>", "Allow Next Trigger": "Allow Next Trigger <small>in Milliseconds</small>",
"Save Events to SQL": "Save Events to SQL", "Save Events to SQL": "Save Events to SQL",
"Email on Trigger": "Email on Trigger <small>Emails go to the main account holder's login address.</small>", "Email on Trigger": "Email on Trigger <small>Emails go to the main account holder's login address.</small>",
"Discord Alert on Trigger": "Discord Alert on Trigger",
"Allow Next Email": "Allow Next Email <small>in Minutes</small>", "Allow Next Email": "Allow Next Email <small>in Minutes</small>",
"Allow Next Discord Alert": "Allow Next Discord Alert <small>in Minutes</small>",
"How to Record": "How to Record", "How to Record": "How to Record",
"Trigger Record": "Trigger Record", "Trigger Record": "Trigger Record",
"Recording Timeout": "Recording Timeout <small>in Minutes</small>", "Recording Timeout": "Recording Timeout <small>in Minutes</small>",
@ -432,6 +443,8 @@
"libx264": "libx264", "libx264": "libx264",
"libx265": "libx265", "libx265": "libx265",
"copy": "copy", "copy": "copy",
"Audio": "Audio",
"Mute Audio": "Mute Audio",
"No Audio": "No Audio", "No Audio": "No Audio",
"aac": "aac", "aac": "aac",
"ac3": "ac3", "ac3": "ac3",
@ -576,6 +589,8 @@
"Preview":"Preview", "Preview":"Preview",
"Websocket Connected":"Websocket Connected", "Websocket Connected":"Websocket Connected",
"Websocket Disconnected":"Websocket Disconnected", "Websocket Disconnected":"Websocket Disconnected",
"Token":"Token",
"Channel ID":"Channel ID",
"New Authentication Token":"New Authentication Token", "New Authentication Token":"New Authentication Token",
"All Logs":"All Logs", "All Logs":"All Logs",
"For Group":"For Group", "For Group":"For Group",
@ -588,8 +603,10 @@
"in Days":"in Days", "in Days":"in Days",
"Can edit how long to keep Logs":"Can edit how long to keep Logs", "Can edit how long to keep Logs":"Can edit how long to keep Logs",
"Can use Admin Panel":"Can use Admin Panel", "Can use Admin Panel":"Can use Admin Panel",
"Can use Discord Bot":"Can use Discord Bot",
"Can use WebDAV":"Can use WebDAV", "Can use WebDAV":"Can use WebDAV",
"Can use LDAP":"Can use LDAP", "Can use LDAP":"Can use LDAP",
"Can View Logs":"Can View Logs",
"Can edit how long to keep Events":"Can edit how long to keep Events", "Can edit how long to keep Events":"Can edit how long to keep Events",
"Leave blank for unlimited":"Leave blank for unlimited", "Leave blank for unlimited":"Leave blank for unlimited",
"Limited":"Limited", "Limited":"Limited",

View File

@ -12,6 +12,20 @@ $.ccio={
fr:$('#files_recent'), fr:$('#files_recent'),
mon:{} mon:{}
}; };
$.ccio.permissionCheck = function(toCheck,monitorId){
var details = $user.details
if(details.sub && details.allmonitors === '0'){
var chosenValue = details[toCheck]
if(details[toCheck] instanceof Array && chosenValue.indexOf(monitorId) > -1){
return true
}else if(chosenValue === '1'){
return true
}
}else{
return true
}
return false
}
$.ccio.downloadJSON = function(jsonToDownload,filename,errorResponse){ $.ccio.downloadJSON = function(jsonToDownload,filename,errorResponse){
var arr = jsonToDownload; var arr = jsonToDownload;
if(arr.length===0 && errorResponse){ if(arr.length===0 && errorResponse){
@ -899,7 +913,46 @@ switch($user.details.lang){
break; break;
case 1://monitor icon case 1://monitor icon
d.src=placeholder.getData(placeholder.plcimg({bgcolor:'#b57d00',text:'...'})); d.src=placeholder.getData(placeholder.plcimg({bgcolor:'#b57d00',text:'...'}));
tmp+='<div auth="'+user.auth_token+'" mid="'+d.mid+'" ke="'+d.ke+'" title="'+d.mid+' : '+d.name+'" class="monitor_block glM'+d.mid+user.auth_token+' col-md-4"><img monitor="watch" class="snapshot" src="'+d.src+'"><div class="box"><div class="title monitor_name truncate">'+d.name+'</div><div class="list-data"><div class="monitor_mid">'+d.mid+'</div><div><b><%-cleanLang(lang['Save as'])%> :</b> <span class="monitor_ext">'+d.ext+'</span></div><div><b>Status :</b> <span class="monitor_status">'+d.status+'</span></div></div><div class="icons text-center"><div class="btn-group"><a class="btn btn-xs btn-default permission_monitor_edit" monitor="edit"><i class="fa fa-wrench"></i></a> <a monitor="videos_table" class="btn btn-xs btn-default"><i class="fa fa-film"></i></a> <a monitor="pop" class="btn btn-xs btn-success"><i class="fa fa-external-link"></i></a></div></div></div></div>'; tmp+='<div auth="'+user.auth_token+'" mid="'+d.mid+'" ke="'+d.ke+'" title="'+d.mid+' : '+d.name+'" class="monitor_block glM'+d.mid+user.auth_token+' col-md-4"><img monitor="watch" class="snapshot" src="'+d.src+'"><div class="box"><div class="title monitor_name truncate">'+d.name+'</div><div class="list-data"><div class="monitor_mid">'+d.mid+'</div><div><b><%-cleanLang(lang['Save as'])%> :</b> <span class="monitor_ext">'+d.ext+'</span></div><div><b>Status :</b> <span class="monitor_status">'+d.status+'</span></div></div><div class="icons text-center">'
tmp+='<div class="btn-group btn-group-xs">'
var buttons = {
"Pop": {
"label": "Pop",
"attr": "monitor=\"pop\"",
"class": "default",
"icon": "external-link"
},
"Power Viewer": {
"label": "Power Viewer",
"attr": "monitor=\"powerview\"",
"class": "default",
"icon": "map-marker"
},
"Videos List": {
"label": "Videos List",
"attr": "monitor=\"videos_table\"",
"class": "default",
"icon": "film"
},
"Monitor Settings": {
"label": "Monitor Settings",
"attr": "monitor=\"edit\"",
"class": "default",
"icon": "wrench"
}
}
if(!$.ccio.permissionCheck('video_view',d.mid)){
delete(buttons["Videos List"])
delete(buttons["Power Viewer"])
}
if(!$.ccio.permissionCheck('monitor_edit',d.mid)){
delete(buttons["Monitor Settings"])
}
$.each(buttons,function(n,v){
tmp+='<a class="btn btn-'+v.class+'" '+v.attr+' title="'+v.label+'"><i class="fa fa-'+v.icon+'"></i></a>'
})
tmp+='</div>\
</div></div></div>';
delete(d.src); delete(d.src);
break; break;
case 2://monitor stream case 2://monitor stream
@ -922,23 +975,90 @@ switch($user.details.lang){
tmp+='<div><span class="monitor_name">'+d.name+'</span><span class="monitor_not_record_copy">, <%-cleanLang(lang['Recording FPS'])%> : <span class="monitor_fps">'+d.fps+'</span></span></div>'; tmp+='<div><span class="monitor_name">'+d.name+'</span><span class="monitor_not_record_copy">, <%-cleanLang(lang['Recording FPS'])%> : <span class="monitor_fps">'+d.fps+'</span></span></div>';
tmp+='</div>'; tmp+='</div>';
tmp+='<div class="btn-group btn-group-sm">'//start of btn list tmp+='<div class="btn-group btn-group-sm">'//start of btn list
$.each([ var buttons = {
{label:"<%-cleanLang(lang.Snapshot)%>",attr:'monitor="snapshot"',class:'primary',icon:'camera'}, "Snapshot": {
{label:"<%-cleanLang(lang['Show Logs'])%>",attr:'monitor="show_data"',class:'warning',icon:'exclamation-triangle'}, "label": "Snapshot",
// {label:"<%-cleanLang(lang['Show Logs'])%>",attr:'class_toggle="show_data" data-target="'+dataTarget+'"',class:'warning',icon:'exclamation-triangle'}, "attr": "monitor=\"snapshot\"",
{label:"<%-cleanLang(lang.Control)%>",attr:'monitor="control_toggle"',class:'default arrows',icon:'arrows'}, "class": "primary",
{label:"<%-cleanLang(lang['Status Indicator'])%>",attr:'monitor="watch_on"',class:'success signal',icon:'plug'}, "icon": "camera"
{label:"<%-cleanLang(lang['Detector'])%>",attr:'monitor="motion"',class:'warning',icon:'grav'}, },
{label:"<%-cleanLang(lang.Pop)%>",attr:'monitor="pop"',class:'default',icon:'external-link'}, "Show Logs": {
// {label:"<%-cleanLang(lang.Magnify)%>",attr:'monitor="magnify"',class:'default',icon:'search-plus'}, "label": "Show Logs",
{label:"<%-cleanLang(lang.Calendar)%>",attr:'monitor="calendar"',class:'default',icon:'calendar'}, "attr": "monitor=\"show_data\"",
{label:"<%-cleanLang(lang['Power Viewer'])%>",attr:'monitor="powerview"',class:'default',icon:'map-marker'}, "class": "warning",
{label:"<%-cleanLang(lang['Time-lapse'])%>",attr:'monitor="timelapse"',class:'default',icon:'angle-double-right'}, "icon": "exclamation-triangle"
{label:"<%-cleanLang(lang['Videos List'])%>",attr:'monitor="videos_table"',class:'default',icon:'film'}, },
{label:"<%-cleanLang(lang['Monitor Settings'])%>",attr:'monitor="edit"',class:'default permission_monitor_edit',icon:'wrench'}, "Control": {
{label:"<%-cleanLang(lang.Fullscreen)%>",attr:'monitor="fullscreen"',class:'default',icon:'arrows-alt'}, "label": "Control",
{label:"<%-cleanLang(lang.Close)%>",attr:'monitor="watch_off"',class:'danger',icon:'times'}, "attr": "monitor=\"control_toggle\"",
],function(n,v){ "class": "default arrows",
"icon": "arrows"
},
"Status Indicator": {
"label": "Status Indicator",
"attr": "monitor=\"watch_on\"",
"class": "success signal",
"icon": "plug"
},
"Pop": {
"label": "Pop",
"attr": "monitor=\"pop\"",
"class": "default",
"icon": "external-link"
},
"Calendar": {
"label": "Calendar",
"attr": "monitor=\"calendar\"",
"class": "default ",
"icon": "calendar"
},
"Power Viewer": {
"label": "Power Viewer",
"attr": "monitor=\"powerview\"",
"class": "default",
"icon": "map-marker"
},
"Time-lapse": {
"label": "Time-lapse",
"attr": "monitor=\"timelapse\"",
"class": "default",
"icon": "angle-double-right"
},
"Videos List": {
"label": "Videos List",
"attr": "monitor=\"videos_table\"",
"class": "default",
"icon": "film"
},
"Monitor Settings": {
"label": "Monitor Settings",
"attr": "monitor=\"edit\"",
"class": "default",
"icon": "wrench"
},
"Fullscreen": {
"label": "Fullscreen",
"attr": "monitor=\"fullscreen\"",
"class": "default",
"icon": "arrows-alt"
},
"Close": {
"label": "Close",
"attr": "monitor=\"watch_off\"",
"class": "danger",
"icon": "times"
}
}
if(!$.ccio.permissionCheck('video_view',d.mid)){
delete(buttons["Videos List"])
delete(buttons["Time-lapse"])
delete(buttons["Power Viewer"])
delete(buttons["Calendar"])
}
if(!$.ccio.permissionCheck('monitor_edit',d.mid)){
delete(buttons["Monitor Settings"])
}
$.each(buttons,function(n,v){
tmp+='<a class="btn btn-'+v.class+'" '+v.attr+' title="'+v.label+'"><i class="fa fa-'+v.icon+'"></i></a>' tmp+='<a class="btn btn-'+v.class+'" '+v.attr+' title="'+v.label+'"><i class="fa fa-'+v.icon+'"></i></a>'
}) })
tmp+='</div>';//end of btn list tmp+='</div>';//end of btn list
@ -1015,6 +1135,11 @@ switch($user.details.lang){
} }
} }
k.e.append(tmp).find('.stream-element').resize(); k.e.append(tmp).find('.stream-element').resize();
if($.ccio.op().switches.monitorMuteAudio === 1){
k.e.find('video').each(function(n,el){
el.muted = "muted"
})
}
break; break;
case'user-row': case'user-row':
d.e=$('.user-row[uid="'+d.uid+'"][ke="'+d.ke+'"]') d.e=$('.user-row[uid="'+d.uid+'"][ke="'+d.ke+'"]')
@ -1802,6 +1927,7 @@ $.ccio.globalWebsocket=function(d,user){
delete($.timelapse.currentVideosArray.videos[$.timelapse.currentVideos[d.filename].position]) delete($.timelapse.currentVideosArray.videos[$.timelapse.currentVideos[d.filename].position])
$.timelapse.drawTimeline(false) $.timelapse.drawTimeline(false)
} }
if($.vidview.loadedVideos && $.vidview.loadedVideos[d.filename])delete($.vidview.loadedVideos[d.filename])
break; break;
case'video_build_success': case'video_build_success':
if(!d.mid){d.mid=d.id;};d.status=1; if(!d.mid){d.mid=d.id;};d.status=1;
@ -2519,6 +2645,14 @@ $.ccio.cx=function(x,user){
$(document).ready(function(e){ $(document).ready(function(e){
console.log("%cWarning!", "font: 2em monospace; color: red;"); console.log("%cWarning!", "font: 2em monospace; color: red;");
console.log('%cLeaving the developer console open is fine if you turn off "Network Recording". This is because it will keep a log of all files, including frames and videos segments.', "font: 1.2em monospace; "); console.log('%cLeaving the developer console open is fine if you turn off "Network Recording". This is because it will keep a log of all files, including frames and videos segments.', "font: 1.2em monospace; ");
if(!$.ccio.permissionCheck('monitor_create')){
$('#add_monitor_button_main').remove()
}
$.each(['user_change','monitor_create','view_logs'],function(n,permission){
if(!$.ccio.permissionCheck(permission)){
$('.permission_'+permission).remove()
}
})
//global form functions //global form functions
$.ccio.form={}; $.ccio.form={};
$.ccio.form.details=function(e){ $.ccio.form.details=function(e){
@ -3084,7 +3218,7 @@ $.multimon.e.on('shown.bs.modal',function() {
tmp+='<td><div class="checkbox"><input id="multimonCheck_'+v.ke+v.mid+v.user.auth_token+'" type="checkbox" name="'+v.ke+v.mid+v.user.auth_token+'" value="1"><label for="multimonCheck_'+v.ke+v.mid+v.user.auth_token+'"></label></div></td>' tmp+='<td><div class="checkbox"><input id="multimonCheck_'+v.ke+v.mid+v.user.auth_token+'" type="checkbox" name="'+v.ke+v.mid+v.user.auth_token+'" value="1"><label for="multimonCheck_'+v.ke+v.mid+v.user.auth_token+'"></label></div></td>'
tmp+='<td><a monitor="watch"><img class="small-square-img" src="'+img+'"></a></td><td>'+v.name+'<br><small>'+v.mid+'</small></td><td class="monitor_status">'+v.status+'</td><td>'+streamURL+'</td>' tmp+='<td><a monitor="watch"><img class="small-square-img" src="'+img+'"></a></td><td>'+v.name+'<br><small>'+v.mid+'</small></td><td class="monitor_status">'+v.status+'</td><td>'+streamURL+'</td>'
//buttons //buttons
tmp+='<td class="text-right"><a title="<%-cleanLang(lang.Pop)%>" monitor="pop" class="btn btn-primary"><i class="fa fa-external-link"></i></a> <a title="<%-cleanLang(lang.Calendar)%>" monitor="calendar" class="btn btn-default"><i class="fa fa-calendar"></i></a> <a title="<%-cleanLang(lang['Power Viewer'])%>" class="btn btn-default" monitor="powerview"><i class="fa fa-map-marker"></i></a> <a title="<%-cleanLang(lang['Time-lapse'])%>" class="btn btn-default" monitor="timelapse"><i class="fa fa-angle-double-right"></i></a> <a title="<%-cleanLang(lang['Videos List'])%>" monitor="videos_table" class="btn btn-default"><i class="fa fa-film"></i></a> <a title="<%-cleanLang(lang['Monitor Settings'])%>" class="btn btn-default permission_monitor_edit" monitor="edit"><i class="fa fa-wrench"></i></a></td>' tmp+='<td class="text-right"><a title="<%-cleanLang(lang.Pop)%>" monitor="pop" class="btn btn-primary"><i class="fa fa-external-link"></i></a> <a title="<%-cleanLang(lang.Calendar)%>" monitor="calendar" class="btn btn-default"><i class="fa fa-calendar"></i></a> <a title="<%-cleanLang(lang['Power Viewer'])%>" class="btn btn-default" monitor="powerview"><i class="fa fa-map-marker"></i></a> <a title="<%-cleanLang(lang['Time-lapse'])%>" class="btn btn-default" monitor="timelapse"><i class="fa fa-angle-double-right"></i></a> <a title="<%-cleanLang(lang['Videos List'])%>" monitor="videos_table" class="btn btn-default"><i class="fa fa-film"></i></a> <a title="<%-cleanLang(lang['Monitor Settings'])%>" class="btn btn-default" monitor="edit"><i class="fa fa-wrench"></i></a></td>'
tmp+='</tr>' tmp+='</tr>'
}) })
$.multimon.table.html(tmp) $.multimon.table.html(tmp)
@ -4068,27 +4202,78 @@ $.vidview.f.submit(function(e){
$('#videos_viewer_limit,#videos_viewer_daterange').change(function(){ $('#videos_viewer_limit,#videos_viewer_daterange').change(function(){
$.vidview.f.submit() $.vidview.f.submit()
}) })
$.vidview.e.find('.delete_selected').click(function(e){ $.vidview.getSelected = function(getArray){
e.s={} var arr = {}
if(getArray){
arr = []
}
$.vidview.f.find('[data-ke] input:checked').each(function(n,v){ $.vidview.f.find('[data-ke] input:checked').each(function(n,v){
v=$(v).parents('tr') v=$(v).parents('tr')
e.s[v.attr('data-file')]={mid:v.attr('data-mid'),auth:v.attr('data-auth')} if(getArray){
arr.push({filename:v.attr('data-file'),mid:v.attr('data-mid'),auth:v.attr('data-auth')})
}else{
arr[v.attr('data-file')]={mid:v.attr('data-mid'),auth:v.attr('data-auth')}
}
}) })
return arr
}
$.vidview.e.find('.delete_selected').click(function(){
e = {}
e.s = $.vidview.getSelected()
if(Object.keys(e.s).length === 0){
$.ccio.init('note',{
title:'No Videos Selected',
text:'You must choose at least one video.',
type:'error'
},$user);
return
}
$.confirm.e.modal('show'); $.confirm.e.modal('show');
$.confirm.title.text('<%-cleanLang(lang['Delete Selected Videos'])%>') $.confirm.title.text('<%-cleanLang(lang['Delete Selected Videos'])%>')
e.html='<%-cleanLang(lang.DeleteSelectedVideosMsg)%><div style="margin-bottom:15px"></div>' e.html='<%-cleanLang(lang.DeleteSelectedVideosMsg)%><div style="margin-bottom:15px"></div>'
var deleteLinks = []
$.each(e.s,function(n,v){ $.each(e.s,function(n,v){
e.html+=n+'<br>'; e.html+=n+'<br>';
if($.vidview.loadedVideos[n])deleteLinks.push($.vidview.loadedVideos[n].links.deleteVideo)
}) })
$.confirm.body.html(e.html) $.confirm.body.html(e.html)
$.confirm.click({title:'Delete Video',class:'btn-danger'},function(){ $.confirm.click({title:'Delete Video',class:'btn-danger'},function(){
$.each(e.s,function(n,v){ $.each(deleteLinks,function(n,link){
$.getJSON($.ccio.init('location',$.users[v.auth])+v.auth+'/videos/'+$user.ke+'/'+v.mid+'/'+n+'/delete',function(d){ $.getJSON(link,function(d){
$.ccio.log(d) $.ccio.log(d)
}) })
}) })
}); });
}) })
$.vidview.e.find('.export_selected').click(function(){
e = {}
var videos = $.vidview.getSelected(true)
if(videos.length === 0){
$.ccio.init('note',{
title:'No Videos Selected',
text:'You must choose at least one video.',
type:'error'
},$user);
return
}
$.confirm.e.modal('show');
$.confirm.title.text('<%-cleanLang(lang['Export Selected Videos'])%>')
var html = '<%-cleanLang(lang.ExportSelectedVideosMsg)%><div style="margin-bottom:15px"></div>'
$.each(videos,function(n,v){
html+=v.filename+'<br>';
})
$.confirm.body.html(html)
$.confirm.click({title:'Export Video',class:'btn-danger'},function(){
var queryVariables = []
queryVariables.push('videos='+JSON.stringify(videos))
if(<%-config.useUTC%> === true){
queryVariables.push('isUTC=true')
}
console.log(queryVariables)
var downloadZip = $.ccio.init('location',$user)+$user.auth_token+'/zipVideos/'+$user.ke+'?'+queryVariables.join('&')
$('#temp').html('<iframe>a</iframe>').find('iframe').attr('src',downloadZip);
});
})
$.vidview.pages.on('click','[page]',function(e){ $.vidview.pages.on('click','[page]',function(e){
e.limit=$.vidview.limit.val(); e.limit=$.vidview.limit.val();
e.page=$(this).attr('page'); e.page=$(this).attr('page');
@ -4948,6 +5133,15 @@ $('body')
$('.monitor_item').attr('data-gs-auto-position','no') $('.monitor_item').attr('data-gs-auto-position','no')
} }
break; break;
case'monitorMuteAudio':
$('.monitor_item video').each(function(n,el){
if(e.o[e.switch] === 1){
el.muted = true
}else{
el.muted = false
}
})
break;
} }
switch(e.e.attr('type')){ switch(e.e.attr('type')){
case'text': case'text':
@ -5161,6 +5355,7 @@ $('body')
d.fn() d.fn()
$.vidview.pages.find('[page="'+$.vidview.current_page+'"]').addClass('active') $.vidview.pages.find('[page="'+$.vidview.current_page+'"]').addClass('active')
e.v=$.vidview.e; e.v=$.vidview.e;
$.vidview.loadedVideos = {}
e.b=e.v.modal('show').find('.modal-body .contents'); e.b=e.v.modal('show').find('.modal-body .contents');
e.t=e.v.find('.modal-title i'); e.t=e.v.find('.modal-title i');
switch(e.a){ switch(e.a){
@ -5169,7 +5364,8 @@ $('body')
e.ar=[]; e.ar=[];
if(d.videos[0]){ if(d.videos[0]){
$.each(d.videos,function(n,v){ $.each(d.videos,function(n,v){
if(v.status!==0){ if(v.status !== 0){
$.vidview.loadedVideos[v.filename] = Object.assign(v,{})
var n=$.ccio.mon[v.ke+v.mid+user.auth_token]; var n=$.ccio.mon[v.ke+v.mid+user.auth_token];
if(n){v.title=n.name+' - '+(parseInt(v.size)/1000000).toFixed(2)+'mb';} if(n){v.title=n.name+' - '+(parseInt(v.size)/1000000).toFixed(2)+'mb';}
v.start=v.time; v.start=v.time;
@ -5221,13 +5417,14 @@ $('body')
e.tmp+='<tbody>'; e.tmp+='<tbody>';
$.each(d.videos,function(n,v){ $.each(d.videos,function(n,v){
if(v.status!==0){ if(v.status!==0){
$.vidview.loadedVideos[v.filename] = Object.assign(v,{})
var href = $.ccio.init('videoUrlBuild',v) var href = $.ccio.init('videoUrlBuild',v)
v.mon=$.ccio.mon[v.ke+v.mid+user.auth_token]; v.mon=$.ccio.mon[v.ke+v.mid+user.auth_token];
v.start=v.time; v.start=v.time;
// v.filename=$.ccio.init('tf',v.time)+'.'+v.ext; // v.filename=$.ccio.init('tf',v.time)+'.'+v.ext;
e.tmp+='<tr data-ke="'+v.ke+'" data-status="'+v.status+'" data-mid="'+v.mid+'" data-file="'+v.filename+'" data-auth="'+v.mon.user.auth_token+'">'; e.tmp+='<tr data-ke="'+v.ke+'" data-status="'+v.status+'" data-mid="'+v.mid+'" data-file="'+v.filename+'" data-auth="'+v.mon.user.auth_token+'">';
e.tmp+='<td><div class="checkbox"><input id="'+v.ke+'_'+v.filename+'" name="'+v.filename+'" value="'+v.mid+'" type="checkbox"><label for="'+v.ke+'_'+v.filename+'"></label></div></td>'; e.tmp+='<td><div class="checkbox"><input id="'+v.ke+'_'+v.filename+'" name="'+v.filename+'" value="'+v.mid+'" type="checkbox"><label for="'+v.ke+'_'+v.filename+'"></label></div></td>';
e.tmp+='<td><span class="livestamp" title="'+v.end+'"></span></td>'; e.tmp+='<td><span class="livestamp" title="'+$.ccio.timeObject(v.end).format('YYYY-MM-DD HH:mm:ss')+'"></span></td>';
e.tmp+='<td title="'+v.end+'">'+$.ccio.timeObject(v.end).format('h:mm:ss A, MMMM Do YYYY')+'</td>'; e.tmp+='<td title="'+v.end+'">'+$.ccio.timeObject(v.end).format('h:mm:ss A, MMMM Do YYYY')+'</td>';
e.tmp+='<td title="'+v.time+'">'+$.ccio.timeObject(v.time).format('h:mm:ss A, MMMM Do YYYY')+'</td>'; e.tmp+='<td title="'+v.time+'">'+$.ccio.timeObject(v.time).format('h:mm:ss A, MMMM Do YYYY')+'</td>';
e.tmp+='<td>'+v.mon.name+'</td>'; e.tmp+='<td>'+v.mon.name+'</td>';

View File

@ -181,7 +181,9 @@ $.sU.e.on('click','.permission',function(e){
$.each($.ccio.subs[$.pR.user],function(n,v){ $.each($.ccio.subs[$.pR.user],function(n,v){
$.pR.e.find('[name="'+n+'"]').val(v) $.pR.e.find('[name="'+n+'"]').val(v)
}) })
$.pR.e.find('[detail="allmonitors"]').val(e.d.allmonitors).change() $.pR.e.find('[detail]').each(function(n,v){
$(v).val(e.d[$(v).attr('detail')])
}).first().change()
$.each(['monitors','monitor_edit','video_delete','video_view'],function(m,b){ $.each(['monitors','monitor_edit','video_delete','video_view'],function(m,b){
if(e.d[b]){ if(e.d[b]){
$.each(e.d[b],function(n,v){ $.each(e.d[b],function(n,v){
@ -193,37 +195,43 @@ $.sU.e.on('click','.permission',function(e){
//permission window //permission window
$.pR={e:$('#permissions'),l:$('#permissionsLabel small')};$.pR.f=$.pR.e.find('form') $.pR={e:$('#permissions'),l:$('#permissionsLabel small')};$.pR.f=$.pR.e.find('form')
$.pR.e.on('change','[detail]',function(e){
e.f=$(this).parents('form');
var details = $.pR.e.find('[name="details"]')
e.ar = JSON.parse(details.val())
e.f.find('[detail]').each(function(n,v){
v = $(v);e.ar[v.attr('detail')] = v.val()
})
details.val(JSON.stringify(e.ar))
})
$.pR.e.on('change','[detail="allmonitors"]',function(e){ $.pR.e.on('change','[detail="allmonitors"]',function(e){
e.e=$(this), e.e=$(this),
e.mon=$('.permission-view') e.mon=$('.permission-view')
e.details=$.pR.e.find('[name="details"]') if(e.e.val() === '1'){
e.json=JSON.parse(e.details.val())
if(e.e.val()=='1'){
e.mon.hide(); e.mon.hide();
e.json.allmonitors='1';
}else{ }else{
e.mon.show() e.mon.show()
e.json.allmonitors='0';
$.pR.e.find('[monitor]').first().change() $.pR.e.find('[monitor]').first().change()
} }
e.details.val(JSON.stringify(e.json))
}) })
$.pR.e.on('click','[check]',function(e){ $.pR.e.on('click','[check]',function(e){
$(this).parents('.form-group-group').find('select').val($(this).attr('check')).first().change() $(this).parents('.form-group-group').find('select').val($(this).attr('check')).first().change()
}) })
$.pR.e.on('change','[monitor]',function(e){ $.pR.e.on('change','[monitor]',function(e){
e.monitors=[];
e.key=$(this).attr('monitor');
e.details=$.pR.e.find('[name="details"]') e.details=$.pR.e.find('[name="details"]')
try{e.detail=JSON.parse(e.details.val())}catch(err){e.detail={}} try{e.detail=JSON.parse(e.details.val())}catch(err){e.detail={}}
if(!e.detail){e.detail={}} if(!e.detail){e.detail={}}
$.pR.e.find('[monitor="'+e.key+'"]').each(function(n,v){ $.pR.e.find('[monitor]').each(function(n,kel){
v=$(v) var monitors = [];
if(v.val()=='1'){ var key = $(kel).attr('monitor')
e.monitors.push(v.attr('mid')) $.pR.e.find('[monitor="'+key+'"]').each(function(n,v){
} var el = $(v)
}); if(el.val() === '1'){
e.detail[e.key]=e.monitors; monitors.push(el.attr('mid'))
}
});
e.detail[key] = monitors
})
e.details.val(JSON.stringify(e.detail)) e.details.val(JSON.stringify(e.detail))
}); });
$.pR.f.submit(function(e){ $.pR.f.submit(function(e){

View File

@ -15,7 +15,7 @@
<script src="libs/js/jquery-ui.min.js"></script> <script src="libs/js/jquery-ui.min.js"></script>
<script src="libs/js/jquery.serialize.js"></script> <script src="libs/js/jquery.serialize.js"></script>
</head> </head>
<% cleanLang=function(string){ <% cleanLang = function(string){
if(!string){string=''} if(!string){string=''}
return string.replace(/'/g,"\\'") return string.replace(/'/g,"\\'")
} %> }%>

View File

@ -119,6 +119,14 @@
</select></div> </select></div>
</label> </label>
</div> </div>
<div class="form-group h_l_input h_l_limited">
<label><div><span><%-lang['Can use Discord Bot']%></span></div>
<div><select class="form-control" detail="use_discordbot">
<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"> <div class="form-group h_l_input h_l_limited">
<label><div><span><%-lang['Can use LDAP']%></span></div> <label><div><span><%-lang['Can use LDAP']%></span></div>
<div><select class="form-control" detail="use_ldap"> <div><select class="form-control" detail="use_ldap">

View File

@ -953,20 +953,31 @@
<div><input class="form-control" detail="detector_command_timeout" placeholder="10"></div> <div><input class="form-control" detail="detector_command_timeout" placeholder="10"></div>
</label> </label>
</div> </div>
<div class="row"> <div class="form-group">
<div class="form-group col-md-12"> <label><div><span><%-lang['Email on Trigger']%></span></div>
<label><div><span><%-lang['Email on Trigger']%></span></div> <div><select class="form-control" detail="detector_mail" selector="h_det_email">
<div><select class="form-control" detail="detector_mail"> <option value="0" selected><%-lang.No%></option>
<option value="0" selected><%-lang.No%></option> <option value="1"><%-lang.Yes%></option>
<option value="1"><%-lang.Yes%></option> </select></div>
</select></div> </label>
</label> </div>
</div> <div class="form-group h_det_email_input h_det_email_1">
<div class="form-group col-md-12"> <label><div><span><%-lang['Allow Next Email']%></span></div>
<label><div><span><%-lang['Allow Next Email']%></span></div> <div><input class="form-control" detail="detector_mail_timeout" placeholder="10"></div>
<div><input class="form-control" detail="detector_mail_timeout" placeholder="10"></div> </label>
</label> </div>
</div> <div class="form-group">
<label><div><span><%-lang['Discord Alert on Trigger']%></span></div>
<div><select class="form-control" detail="detector_discordbot" selector="h_det_discord">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group h_det_discord_input h_det_discord_1">
<label><div><span><%-lang['Allow Next Discord Alert']%></span></div>
<div><input class="form-control" detail="detector_discordbot_timeout" placeholder="10"></div>
</label>
</div> </div>
<div class="hidden"> <div class="hidden">
<div><input detail="cords" placeholder=""></div> <div><input detail="cords" placeholder=""></div>

View File

@ -179,6 +179,31 @@
</div> </div>
</div> </div>
<% } %> <% } %>
<% if(details.use_discordbot!=='0'){ %>
<div class="form-group-group forestgreen">
<h4><%-lang['Discord Bot']%></h4>
<div class="form-group">
<label><div><span><%-lang.Enabled%></span></div>
<div><select class="form-control" detail="discordbot" selector="u_discord_bot">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="u_discord_bot_input u_discord_bot_1">
<div class="form-group">
<label><div><span><%-lang.Token%></span></div>
<div><input type="password" class="form-control" placeholder="XXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXX_XXXXXXXXXXXXXXXXXX" detail="discordbot_token"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Channel ID']%></span></div>
<div><input class="form-control" placeholder="xxxxxxxxxxxxxxxxxx" detail="discordbot_channel"></div>
</label>
</div>
</div>
</div>
<% } %>
<% if(details.use_ldap!=='0'){ %> <% if(details.use_ldap!=='0'){ %>
<div class="form-group-group forestgreen"> <div class="form-group-group forestgreen">
<h4><%-lang.LDAP%></h4> <h4><%-lang.LDAP%></h4>

View File

@ -10,13 +10,40 @@
</div> </div>
<div class="modal-body" style="max-height:600px;overflow:auto"> <div class="modal-body" style="max-height:600px;overflow:auto">
<div class="text-center msg"></div> <div class="text-center msg"></div>
<div class="form-group"> <div class="form-group-group">
<label><div><span><%-lang['All Monitors and Privileges']%></span></div> <h4><%-lang['Privileges']%></h4>
<div><select class="form-control" detail="allmonitors"> <div class="form-group">
<option value="0" selected><%-lang.No%></option> <label><div><span><%-lang['All Monitors and Privileges']%></span></div>
<option value="1"><%-lang.Yes%></option> <div><select class="form-control" detail="allmonitors">
</select></div> <option value="0" selected><%-lang.No%></option>
</label> <option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group permission-view">
<label><div><span><%-lang['Can Create and Delete Monitors']%></span></div>
<div><select class="form-control" detail="monitor_create">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group permission-view">
<label><div><span><%-lang['Can Change User Settings']%></span></div>
<div><select class="form-control" detail="user_change">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Can View Logs']%></span></div>
<div><select class="form-control" detail="view_logs">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
</div> </div>
<div class="form-group-group blue permission-view" id="monitors_section"> <div class="form-group-group blue permission-view" id="monitors_section">
<h4> <h4>

View File

@ -31,7 +31,8 @@
<div class="modal-footer"> <div class="modal-footer">
<div class="row"> <div class="row">
<div class="col-md-4 text-left"> <div class="col-md-4 text-left">
<a class="btn btn-danger delete_selected"><i class="fa fa-trash-o"></i> &nbsp; <%-lang['Delete selected']%></a> <a class="btn btn-danger delete_selected"><i class="fa fa-trash-o"></i> &nbsp; <%-lang['Delete']%></a>
<a class="btn btn-default export_selected"><i class="fa fa-folder-o"></i> &nbsp; <%-lang['Zip and Download']%></a>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<div class="text-center" id="videos_viewer_pages"></div> <div class="text-center" id="videos_viewer_pages"></div>

View File

@ -107,9 +107,10 @@ if(data.addon.indexOf('gui')>-1){ %>
<% }; <% };
if(data.addon.indexOf('fullscreen')>-1){ %> if(data.addon.indexOf('fullscreen')>-1){ %>
<style> <style>
body,html{overflow: hidden;} body,html{overflow: hidden;height:100%}
*{margin:0;padding:0;border:0} *{margin:0;padding:0;border:0}
.stream-element,.shinobi_stream{position:absolute;top:0;left:0;} .stream-element,.shinobi_stream{position:absolute;top:0;left:0;height:100%}
.shinobi_stream video{object-fit: fill}
</style> </style>
<script> <script>
$(window).resize(function(){ $(window).resize(function(){

View File

@ -19,21 +19,12 @@
<%= details.css %> <%= details.css %>
</style> </style>
<style> <style>
<% if(details.sub&&details.allmonitors==='0'){ <% if(details.video_delete&&details.video_delete!==''){
if(details.monitor_edit&&details.monitor_edit!==''){ details.video_delete.forEach(function(v,n){ %>
details.monitor_edit.forEach(function(v,n){ %> [mid="<%= v %>"] .permission_video_delete{display:inline-block}
[mid="<%= v %>"] .permission_monitor_edit{display:inline-block} <%
<% })
})
}
if(details.video_delete&&details.video_delete!==''){
details.video_delete.forEach(function(v,n){ %>
[mid="<%= v %>"] .permission_video_delete{display:inline-block}
<%
})
}
}else{ %> }else{ %>
.permission_video_delete,.permission_monitor_edit{display:inline-block}
th.permission_video_delete,td.permission_video_delete{display:table-cell} th.permission_video_delete,td.permission_video_delete{display:table-cell}
<% } %> <% } %>
</style> </style>
@ -50,7 +41,7 @@
<div class="mdl-layout__header-row"> <div class="mdl-layout__header-row">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li title="<%-lang['Toggle Sidebar']%>" class_toggle="hide-side" data-target=".mdl-js-layout"><a>&nbsp;<i class="fa fa-bars"></i>&nbsp;</a></li> <li title="<%-lang['Toggle Sidebar']%>" class_toggle="hide-side" data-target=".mdl-js-layout"><a>&nbsp;<i class="fa fa-bars"></i>&nbsp;</a></li>
<li title="<%-lang['Add Monitor']%>" mid="" ke="" class="hidden-xs permission_monitor_edit"><a monitor="edit">&nbsp;<i class="fa fa-plus"></i>&nbsp;</a></li> <li title="<%-lang['Add Monitor']%>" mid="" ke="" class="hidden-xs permission_monitor_create"><a monitor="edit">&nbsp;<i class="fa fa-plus"></i>&nbsp;</a></li>
<li title="<%-lang['Power Video Viewer']%>" class="hidden-xs" mid="" ke=""><a monitor="powerview">&nbsp;<i class="fa fa-map-marker"></i>&nbsp;</a></li> <li title="<%-lang['Power Video Viewer']%>" class="hidden-xs" mid="" ke=""><a monitor="powerview">&nbsp;<i class="fa fa-map-marker"></i>&nbsp;</a></li>
<li> <li>
<a title="<%-lang['Monitor Groups']%>" id="group_list_button" class="mdl-js-button">&nbsp;<i class="fa fa-video-camera"></i>&nbsp;</a> <a title="<%-lang['Monitor Groups']%>" id="group_list_button" class="mdl-js-button">&nbsp;<i class="fa fa-video-camera"></i>&nbsp;</a>
@ -122,18 +113,19 @@
<li class="mdl-menu__item" data-toggle="modal" data-target="#multi_mon"><div><i class="fa fa-clone"></i><div><%- lang['Monitors'] %></div></div></li> <li class="mdl-menu__item" data-toggle="modal" data-target="#multi_mon"><div><i class="fa fa-clone"></i><div><%- lang['Monitors'] %></div></div></li>
<li class="mdl-menu__item" mid="" ke=""><div class="flex" monitor="powerview"><i class="fa fa-map-marker"></i><div><%- lang['Power Viewer'] %></div></div></li> <li class="mdl-menu__item" mid="" ke=""><div class="flex" monitor="powerview"><i class="fa fa-map-marker"></i><div><%- lang['Power Viewer'] %></div></div></li>
<li class="mdl-menu__item" mid="" ke=""><div class="flex" monitor="timelapse"><i class="fa fa-angle-double-right"></i><div><%- lang['Time-lapse'] %></div></div></li> <li class="mdl-menu__item" mid="" ke=""><div class="flex" monitor="timelapse"><i class="fa fa-angle-double-right"></i><div><%- lang['Time-lapse'] %></div></div></li>
<li class="mdl-menu__item" data-toggle="modal" data-target="#settings"><div><i class="fa fa-gears"></i><div><%- lang.Settings %></div></div></li> <li class="mdl-menu__item permission_user_change" data-toggle="modal" data-target="#settings"><div><i class="fa fa-gears"></i><div><%- lang.Settings %></div></div></li>
<li class="mdl-menu__item" data-toggle="modal" data-target="#apis"><div><i class="fa fa-code"></i><div><%- lang.API %></div></div></li> <li class="mdl-menu__item" data-toggle="modal" data-target="#apis"><div><i class="fa fa-code"></i><div><%- lang.API %></div></div></li>
<% if(!details.sub){ %> <% if(!details.sub){ %>
<li class="mdl-menu__item" data-toggle="modal" data-target="#onvif_probe"><div><i class="fa fa-rss"></i><div><%- lang.ONVIF %></div></div></li> <li class="mdl-menu__item" data-toggle="modal" data-target="#onvif_probe"><div><i class="fa fa-rss"></i><div><%- lang.ONVIF %></div></div></li>
<li class="mdl-menu__item" data-toggle="modal" data-target="#probe"><div><i class="fa fa-search"></i><div><%- lang.FFprobe %></div></div></li> <li class="mdl-menu__item" data-toggle="modal" data-target="#probe"><div><i class="fa fa-search"></i><div><%- lang.FFprobe %></div></div></li>
<li class="mdl-menu__item" data-toggle="modal" data-target="#filters"><div><i class="fa fa-filter"></i><div><%- lang.Filters %></div></div></li> <li class="mdl-menu__item" data-toggle="modal" data-target="#filters"><div><i class="fa fa-filter"></i><div><%- lang.Filters %></div></div></li>
<% } %> <% } %>
<li class="mdl-menu__item" data-toggle="modal" data-target="#logs_modal"><div><i class="fa fa-exclamation-triangle"></i><div><%- lang.Logs %></div></div></li> <li class="mdl-menu__item permission_view_logs" data-toggle="modal" data-target="#logs_modal"><div><i class="fa fa-exclamation-triangle"></i><div><%- lang.Logs %></div></div></li>
<li class="mdl-menu__item" class_toggle="list-blocks" data-target="#left_menu"><div><i class="fa fa-camera"></i><div><%- lang['List Toggle'] %></div></div></li> <li class="mdl-menu__item" class_toggle="list-blocks" data-target="#left_menu"><div><i class="fa fa-camera"></i><div><%- lang['List Toggle'] %></div></div></li>
<li class="mdl-menu__item" class_toggle="hide-side" data-target=".mdl-js-layout"><div><i class="fa fa-bars"></i><div><%- lang['Hide List'] %></div></div></li> <li class="mdl-menu__item" class_toggle="hide-side" data-target=".mdl-js-layout"><div><i class="fa fa-bars"></i><div><%- lang['Hide List'] %></div></div></li>
<li class="mdl-menu__item shinobi-detector-motion shinobi-detector-opencv shinobi-detector_plug" class_toggle="hide_indifference" data-target="body" style="display:none"><div><i class="fa fa-bolt"></i><div><%- lang['Motion GUI'] %></div></div></li> <li class="mdl-menu__item shinobi-detector-motion shinobi-detector-opencv shinobi-detector_plug" class_toggle="hide_indifference" data-target="body" style="display:none"><div><i class="fa fa-bolt"></i><div><%- lang['Motion GUI'] %></div></div></li>
<li class="mdl-menu__item" system="jpegToggle"><div><i class="fa fa-file-image-o"></i><div><%- lang['JPEG Mode'] %></div></div></li> <li class="mdl-menu__item" system="jpegToggle"><div><i class="fa fa-file-image-o"></i><div><%- lang['JPEG Mode'] %></div></div></li>
<li class="mdl-menu__item" system="switch" switch="monitorMuteAudio" type="text"><div><i class="fa fa-volume-down"></i><div><%- lang['Mute Audio'] %></div></div></li>
<li class="mdl-menu__item" system="switch" switch="monitorOrder" type="text"><div><i class="fa fa-sort"></i><div><%- lang['Order Streams'] %></div></div></li> <li class="mdl-menu__item" system="switch" switch="monitorOrder" type="text"><div><i class="fa fa-sort"></i><div><%- lang['Order Streams'] %></div></div></li>
<li class="mdl-menu__item" system="switch" switch="notifyHide" type="text"><div><i class="fa fa-exclamation-circle"></i><div><%- lang['Hide Notes'] %></div></div></li> <li class="mdl-menu__item" system="switch" switch="notifyHide" type="text"><div><i class="fa fa-exclamation-circle"></i><div><%- lang['Hide Notes'] %></div></div></li>
<li class="mdl-menu__item logout"><div><i class="fa fa-sign-out"></i><div><%- lang.Logout %></div></div></li> <li class="mdl-menu__item logout"><div><i class="fa fa-sign-out"></i><div><%- lang.Logout %></div></div></li>

View File

@ -17,7 +17,6 @@ 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="libs/js/jquery.min.js"></script>
<script src="libs/js/socket.io.js"></script> <script src="libs/js/socket.io.js"></script>
<script src="libs/js/menu.js"></script> <script src="libs/js/menu.js"></script>
<script> <script>