Merge branch 'dev' into 'master'
Shiny Pikachu See merge request Shinobi-Systems/Shinobi!14merge-requests/23/head
commit
7c35dfa6f6
|
@ -102,6 +102,7 @@ Courthouse Vancouver Robson Square
|
|||
Node.js - https://nodejs.org/en/
|
||||
MariaDB - https://mariadb.org/
|
||||
FFmpeg - https://www.ffmpeg.org/
|
||||
request - https://www.npmjs.com/package/request
|
||||
Express (npm) - https://expressjs.com/ https://www.npmjs.com/package/express
|
||||
EJS (npm) - http://ejs.co/ https://www.npmjs.com/package/ejs
|
||||
pam-diff (npm) (Motion Detector) - https://github.com/kevinGodell/pam-diff
|
||||
|
|
587
camera.js
587
camera.js
|
@ -116,7 +116,6 @@ if(config.databaseType===undefined){config.databaseType='mysql'}
|
|||
if(config.pluginKeys===undefined)config.pluginKeys={};
|
||||
if(config.databaseLogs===undefined){config.databaseLogs=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)}
|
||||
//Web Paths
|
||||
if(config.webPaths===undefined){config.webPaths={}}
|
||||
|
@ -220,42 +219,24 @@ if(databaseOptions.client === 'sqlite3' && databaseOptions.connection.filename =
|
|||
databaseOptions.connection.filename = __dirname+"/shinobi.sqlite"
|
||||
}
|
||||
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){
|
||||
if(!values){values=[]}
|
||||
var valuesNotFunction = true;
|
||||
if(typeof values === 'function'){
|
||||
var onMoveOn = values;
|
||||
var values = [];
|
||||
valuesNotFunction = false;
|
||||
}
|
||||
if(!onMoveOn){onMoveOn=function(){}}
|
||||
if(values&&valuesNotFunction){
|
||||
var splitQuery = query.split('?')
|
||||
var newQuery = ''
|
||||
splitQuery.forEach(function(v,n){
|
||||
newQuery += v
|
||||
if(values[n]){
|
||||
if(isNaN(values[n])){
|
||||
newQuery += "'"+values[n]+"'"
|
||||
var value = values[n]
|
||||
if(value){
|
||||
if(isNaN(value) || value instanceof Date){
|
||||
newQuery += "'"+value+"'"
|
||||
}else{
|
||||
newQuery += values[n]
|
||||
newQuery += value
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -264,7 +245,11 @@ s.mergeQueryValues = function(query,values){
|
|||
}
|
||||
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(typeof values === 'function'){
|
||||
var onMoveOn = values;
|
||||
|
@ -272,24 +257,53 @@ s.sqlQuery = function(query,values,onMoveOn,hideLog){
|
|||
}
|
||||
if(!onMoveOn){onMoveOn=function(){}}
|
||||
var mergedQuery = s.mergeQueryValues(query,values)
|
||||
return s.databaseEngine.raw(query,values)
|
||||
.asCallback(function(err,r){
|
||||
if(err&&config.databaseLogs){
|
||||
s.systemLog('s.sqlQuery QUERY',query)
|
||||
s.systemLog('s.sqlQuery ERROR',err)
|
||||
s.debugLog('s.sqlQuery QUERY',mergedQuery)
|
||||
return s.databaseEngine
|
||||
.raw(query,values)
|
||||
.asCallback(function(err,r){
|
||||
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'){
|
||||
switch(databaseOptions.client){
|
||||
case'sqlite3':
|
||||
if(!r)r=[]
|
||||
break;
|
||||
default:
|
||||
if(r)r=r[0]
|
||||
break;
|
||||
onMoveOn(err,r)
|
||||
}
|
||||
})
|
||||
}
|
||||
//discord bot
|
||||
if(config.discordBot === true){
|
||||
try{
|
||||
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
|
||||
s.ffmpegKill=function(){
|
||||
|
@ -345,7 +359,7 @@ s.txWithSubPermissions = function(z,y,permissionChoices){
|
|||
var valid=0
|
||||
var checked=permissionChoices.length
|
||||
permissionChoices.forEach(function(b){
|
||||
if(user.details[b].indexOf(z.mid)!==-1){
|
||||
if(user.details[b] && user.details[b].indexOf(z.mid)!==-1){
|
||||
++valid
|
||||
}
|
||||
})
|
||||
|
@ -449,6 +463,21 @@ s.getFunctionParamNames = function(func) {
|
|||
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){
|
||||
var pamDiffCompliantArray = [],
|
||||
arrayForOtherStuff = [],
|
||||
|
@ -494,7 +523,7 @@ s.getRequest = function(url,callback){
|
|||
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].mon[e.id].spawn){
|
||||
s.group[e.ke].mon[e.mid].allowStdinWrite = false
|
||||
s.group[e.ke].mon[e.id].allowStdinWrite = false
|
||||
s.txToDashcamUsers({
|
||||
f : 'disable_stream',
|
||||
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)
|
||||
}
|
||||
//system log
|
||||
s.systemLog=function(q,w,e){
|
||||
s.systemLog = function(q,w,e){
|
||||
if(!w){w=''}
|
||||
if(!e){e=''}
|
||||
if(config.systemLog===true){
|
||||
|
@ -560,6 +589,17 @@ s.systemLog=function(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
|
||||
if(config.ssl&&config.ssl.key&&config.ssl.cert){
|
||||
config.ssl.key=fs.readFileSync(s.checkRelativePath(config.ssl.key),'utf8')
|
||||
|
@ -659,12 +699,7 @@ s.init=function(x,e,k,fn){
|
|||
switch(x){
|
||||
case 0://init camera
|
||||
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].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].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={}};
|
||||
|
@ -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].delete){clearTimeout(s.group[e.ke].mon[e.mid].delete)}
|
||||
if(!s.group[e.ke].mon_conf){s.group[e.ke].mon_conf={}}
|
||||
s.init('apps',e)
|
||||
break;
|
||||
case'group':
|
||||
if(!s.group[e.ke]){
|
||||
|
@ -688,6 +722,11 @@ s.init=function(x,e,k,fn){
|
|||
if(!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)}
|
||||
//save global space limit for group key (mb)
|
||||
s.group[e.ke].sizeLimit=e.limit;
|
||||
|
@ -723,6 +762,18 @@ s.init=function(x,e,k,fn){
|
|||
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){
|
||||
s.group[e.ke].init[v]=ar[v]
|
||||
})
|
||||
|
@ -918,15 +969,12 @@ s.video=function(x,e,k){
|
|||
time = e.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];
|
||||
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]){
|
||||
r=r[0]
|
||||
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){
|
||||
if(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)
|
||||
evs.forEach(function(ev){
|
||||
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);
|
||||
s.file('delete',ev.dir);
|
||||
s.init('diskUsedSet',e,-(ev.size/1000000))
|
||||
|
@ -1238,10 +1286,6 @@ s.video=function(x,e,k){
|
|||
k.details.dir = e.details.dir
|
||||
}
|
||||
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 = [
|
||||
e.mid,
|
||||
e.ke,
|
||||
|
@ -2442,9 +2486,7 @@ s.camera=function(x,e,cn,tx){
|
|||
e.details.fatal_max = parseFloat(e.details.fatal_max)
|
||||
}
|
||||
var errorFatal = function(errorMessage){
|
||||
if(config.debugSystem === true){
|
||||
console.log(errorMessage,(new Error()).stack)
|
||||
}
|
||||
s.debugLog(errorMessage)
|
||||
clearTimeout(s.group[e.ke].mon[e.id].err_fatal_timeout);
|
||||
++errorFatalCount;
|
||||
if(s.group[e.ke].mon[e.id].started===1){
|
||||
|
@ -2518,7 +2560,7 @@ s.camera=function(x,e,cn,tx){
|
|||
cutoff *= 100
|
||||
}
|
||||
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();
|
||||
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']}});
|
||||
|
@ -3193,8 +3235,71 @@ s.camera=function(x,e,cn,tx){
|
|||
|
||||
}).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
|
||||
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){
|
||||
r=r[0];
|
||||
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);
|
||||
delete(s.group[d.ke].mon[d.id].detector_mail);
|
||||
},detector_mail_timeout);
|
||||
d.frame_filename='Motion_'+(d.mon.name.replace(/[^\w\s]/gi, ''))+'_'+d.id+'_'+d.ke+'_'+s.formattedTime()+'.jpg';
|
||||
fs.readFile(s.dir.streams+'/'+d.ke+'/'+d.id+'/s.jpg',function(err, frame){
|
||||
var files = []
|
||||
var sendMail = function(){
|
||||
d.mailOptions = {
|
||||
from: '"ShinobiCCTV" <no-reply@shinobi.video>', // sender address
|
||||
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>',
|
||||
};
|
||||
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>'
|
||||
attachments: files
|
||||
}
|
||||
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>'
|
||||
})
|
||||
nodemailer.sendMail(d.mailOptions, (error, info) => {
|
||||
if (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){
|
||||
|
@ -3839,57 +3962,64 @@ var tx;
|
|||
if(r&&r[0]){
|
||||
r=r[0];
|
||||
d.d=JSON.parse(r.details);
|
||||
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)
|
||||
//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)
|
||||
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)
|
||||
}
|
||||
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;
|
||||
|
@ -3901,15 +4031,15 @@ var tx;
|
|||
switch(d.fff){
|
||||
case'videos&events':
|
||||
if(!d.eventLimit){
|
||||
d.eventLimit=500
|
||||
d.eventLimit = 500
|
||||
}else{
|
||||
d.eventLimit = parseInt(d.eventLimit);
|
||||
}
|
||||
if(!d.eventStartDate&&d.startDate){
|
||||
d.eventStartDate=d.startDate
|
||||
d.eventStartDate = s.stringToSqlTime(d.startDate)
|
||||
}
|
||||
if(!d.eventEndDate&&d.endDate){
|
||||
d.eventEndDate=d.endDate
|
||||
d.eventEndDate = s.stringToSqlTime(d.endDate)
|
||||
}
|
||||
var monitorQuery = ''
|
||||
var monitorValues = []
|
||||
|
@ -3932,15 +4062,13 @@ var tx;
|
|||
var eventQuery = 'SELECT * FROM Events WHERE ke=?';
|
||||
var eventQueryValues = [cn.ke];
|
||||
if(d.eventStartDate&&d.eventStartDate!==''){
|
||||
d.eventStartDate=d.eventStartDate.replace('T',' ')
|
||||
if(d.eventEndDate&&d.eventEndDate!==''){
|
||||
d.eventEndDate=d.eventEndDate.replace('T',' ')
|
||||
eventQuery+=' AND `time` >= ? AND `time` <= ?';
|
||||
eventQueryValues.push(decodeURIComponent(d.eventStartDate))
|
||||
eventQueryValues.push(decodeURIComponent(d.eventEndDate))
|
||||
eventQueryValues.push(d.eventStartDate)
|
||||
eventQueryValues.push(d.eventEndDate)
|
||||
}else{
|
||||
eventQuery+=' AND `time` >= ?';
|
||||
eventQueryValues.push(decodeURIComponent(d.eventStartDate))
|
||||
eventQueryValues.push(d.eventStartDate)
|
||||
}
|
||||
}
|
||||
if(monitorValues.length>0){
|
||||
|
@ -3969,10 +4097,10 @@ var tx;
|
|||
eventQuery.push()
|
||||
}
|
||||
if(!d.videoStartDate&&d.startDate){
|
||||
d.videoStartDate=d.startDate
|
||||
d.videoStartDate = s.stringToSqlTime(d.startDate)
|
||||
}
|
||||
if(!d.videoEndDate&&d.endDate){
|
||||
d.videoEndDate=d.endDate
|
||||
d.videoEndDate = s.stringToSqlTime(d.endDate)
|
||||
}
|
||||
var getVideos = function(callback){
|
||||
var videoQuery='SELECT * FROM Videos WHERE ke=?';
|
||||
|
@ -3986,19 +4114,15 @@ var tx;
|
|||
}
|
||||
switch(true){
|
||||
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+' ?';
|
||||
videoQueryValues.push(d.videoStartDate)
|
||||
videoQueryValues.push(d.videoEndDate)
|
||||
break;
|
||||
case(d.videoStartDate&&d.videoStartDate!==''):
|
||||
d.videoStartDate=d.videoStartDate.replace('T',' ')
|
||||
videoQuery+=' AND `time` '+d.videoStartDateOperator+' ?';
|
||||
videoQueryValues.push(d.videoStartDate)
|
||||
break;
|
||||
case(d.videoEndDate&&d.videoEndDate!==''):
|
||||
d.videoEndDate=d.videoEndDate.replace('T',' ')
|
||||
videoQuery+=' AND `end` '+d.videoEndDateOperator+' ?';
|
||||
videoQueryValues.push(d.videoEndDate)
|
||||
break;
|
||||
|
@ -4406,10 +4530,24 @@ var tx;
|
|||
d.value=d.value.concat([d.ke,d.$uid])
|
||||
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.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;
|
||||
case'delete':
|
||||
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);
|
||||
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}})
|
||||
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){
|
||||
|
@ -5637,7 +5775,11 @@ app.get(['/:auth/videos/:ke','/:auth/videos/:ke/:id'], function (req,res){
|
|||
res.setHeader('Content-Type', 'application/json');
|
||||
res.header("Access-Control-Allow-Origin",req.headers.origin);
|
||||
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([]))
|
||||
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.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==''){
|
||||
req.query.startOperator='>='
|
||||
}
|
||||
|
@ -5675,8 +5823,6 @@ app.get(['/:auth/videos/:ke','/:auth/videos/:ke/:id'], function (req,res){
|
|||
}
|
||||
switch(true){
|
||||
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.count_sql+=' AND `time` '+req.query.startOperator+' ? AND `end` '+req.query.endOperator+' ?';
|
||||
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)
|
||||
break;
|
||||
case(req.query.start&&req.query.start!==''):
|
||||
req.query.start=req.query.start.replace('T',' ')
|
||||
req.sql+=' AND `time` '+req.query.startOperator+' ?';
|
||||
req.count_sql+=' AND `time` '+req.query.startOperator+' ?';
|
||||
req.ar.push(req.query.start)
|
||||
req.count_ar.push(req.query.start)
|
||||
break;
|
||||
case(req.query.end&&req.query.end!==''):
|
||||
req.query.end=req.query.end.replace('T',' ')
|
||||
req.sql+=' AND `end` '+req.query.endOperator+' ?';
|
||||
req.count_sql+=' AND `end` '+req.query.endOperator+' ?';
|
||||
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));
|
||||
return
|
||||
}
|
||||
s.sqlQuery(req.count_sql,req.count_ar,function(err,count){
|
||||
s.video('linkBuild',r,req.params.auth)
|
||||
if(req.query.limit.indexOf(',')>-1){
|
||||
req.skip=parseInt(req.query.limit.split(',')[0])
|
||||
req.query.limit=parseInt(req.query.limit.split(',')[0])
|
||||
}else{
|
||||
req.skip=0
|
||||
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));
|
||||
})
|
||||
s.sqlQuery(req.count_sql,req.count_ar,function(err,count){
|
||||
s.video('linkBuild',r,req.params.auth)
|
||||
if(req.query.limit.indexOf(',')>-1){
|
||||
req.skip=parseInt(req.query.limit.split(',')[0])
|
||||
req.query.limit=parseInt(req.query.limit.split(',')[0])
|
||||
}else{
|
||||
req.skip=0
|
||||
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,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!==''){
|
||||
req.params.start=req.params.start.replace('T',' ')
|
||||
req.params.start = s.stringToSqlTime(req.params.start)
|
||||
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.ar.push(decodeURIComponent(req.params.start))
|
||||
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.header("Access-Control-Allow-Origin",req.headers.origin);
|
||||
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([]))
|
||||
return
|
||||
}
|
||||
|
@ -5818,13 +5962,13 @@ app.get(['/:auth/logs/:ke','/:auth/logs/:ke/:id'], function (req,res){
|
|||
req.query.endOperator='<='
|
||||
}
|
||||
if(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.query.start = s.stringToSqlTime(req.query.start)
|
||||
req.query.end = s.stringToSqlTime(req.query.end)
|
||||
req.sql+=' AND `time` '+req.query.startOperator+' ? AND `time` '+req.query.endOperator+' ?';
|
||||
req.ar.push(req.query.start)
|
||||
req.ar.push(req.query.end)
|
||||
}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.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.header("Access-Control-Allow-Origin",req.headers.origin);
|
||||
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){
|
||||
req.ret.msg='No Monitor Data found.'
|
||||
res.end(s.s(req.ret, null, 3))
|
||||
|
@ -5905,7 +6050,10 @@ app.all(['/:auth/configureMonitor/:ke/:id','/:auth/configureMonitor/:ke/:id/:f']
|
|||
}
|
||||
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){
|
||||
req.set=[],req.ar=[];
|
||||
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);
|
||||
});
|
||||
//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
|
||||
app.get('/:auth/videos/:ke/:id/:file', function (req,res){
|
||||
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 = 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]){
|
||||
req.dir=s.video('getDir',r[0])+req.params.file
|
||||
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 = 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];
|
||||
s.sqlQuery(req.sql,req.ar,function(err,r){
|
||||
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.';
|
||||
}else{
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
@ -6890,6 +7126,7 @@ if(config.childNodes.mode === 'child'){
|
|||
}
|
||||
s.systemLog(v.mail+' : '+lang.startUpText0+' : '+rr.length,v.size)
|
||||
s.init('group',v)
|
||||
s.init('apps',v)
|
||||
s.systemLog(v.mail+' : '+lang.startUpText1,countFinished+'/'+count)
|
||||
if(countFinished===count){
|
||||
s.systemLog(lang.startUpText4)
|
||||
|
|
|
@ -104,6 +104,8 @@
|
|||
"Can View Streams": "Can View Streams",
|
||||
"Can View Videos": "Can View Videos",
|
||||
"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 Delete Videos": "Can Delete Videos",
|
||||
"Delete Video": "Delete Video",
|
||||
|
@ -178,6 +180,7 @@
|
|||
"Monitor Groups": "Monitor Groups",
|
||||
"Group Name": "Group Name",
|
||||
"WebDAV": "WebDAV",
|
||||
"Discord Bot": "Discord Bot",
|
||||
"URL": "URL",
|
||||
"Autosave": "Autosave",
|
||||
"Save Directory": "Save Directory",
|
||||
|
@ -186,6 +189,7 @@
|
|||
"Monitors per row": "Monitors per row <small>for Montage</small>",
|
||||
"Browser Console Log": "Browser Console Log",
|
||||
"Log Stream": "Log Stream",
|
||||
"Privileges": "Privileges",
|
||||
"All Monitors and Privileges": "All Monitors and Privileges",
|
||||
"Permissions": "Permissions",
|
||||
"Time-lapse Tool": "Time-lapse Tool",
|
||||
|
@ -211,9 +215,13 @@
|
|||
"Set to Watch Only": "Set to Watch Only",
|
||||
"Save as": "Save as",
|
||||
"Add New": "Add New",
|
||||
"Zip and Download": "Zip and Download",
|
||||
"Export Selected Videos": "Export Selected Videos",
|
||||
"Delete Selected Videos": "Delete Selected Videos",
|
||||
"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.",
|
||||
"Export Video": "Export Video",
|
||||
"Delete Filter": "Delete Filter",
|
||||
"confirmDeleteFilter": "Do you want to delete this filter? You cannot recover it.",
|
||||
"Fix Video": "Fix Video",
|
||||
|
@ -249,6 +257,7 @@
|
|||
"Unable to Launch": "Unable to Launch",
|
||||
"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.",
|
||||
"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.",
|
||||
"in": "in",
|
||||
"ago": "ago",
|
||||
|
@ -369,7 +378,9 @@
|
|||
"Allow Next Trigger": "Allow Next Trigger <small>in Milliseconds</small>",
|
||||
"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>",
|
||||
"Discord Alert on Trigger": "Discord Alert on Trigger",
|
||||
"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",
|
||||
"Trigger Record": "Trigger Record",
|
||||
"Recording Timeout": "Recording Timeout <small>in Minutes</small>",
|
||||
|
@ -432,6 +443,8 @@
|
|||
"libx264": "libx264",
|
||||
"libx265": "libx265",
|
||||
"copy": "copy",
|
||||
"Audio": "Audio",
|
||||
"Mute Audio": "Mute Audio",
|
||||
"No Audio": "No Audio",
|
||||
"aac": "aac",
|
||||
"ac3": "ac3",
|
||||
|
@ -576,6 +589,8 @@
|
|||
"Preview":"Preview",
|
||||
"Websocket Connected":"Websocket Connected",
|
||||
"Websocket Disconnected":"Websocket Disconnected",
|
||||
"Token":"Token",
|
||||
"Channel ID":"Channel ID",
|
||||
"New Authentication Token":"New Authentication Token",
|
||||
"All Logs":"All Logs",
|
||||
"For Group":"For Group",
|
||||
|
@ -588,8 +603,10 @@
|
|||
"in Days":"in Days",
|
||||
"Can edit how long to keep Logs":"Can edit how long to keep Logs",
|
||||
"Can use Admin Panel":"Can use Admin Panel",
|
||||
"Can use Discord Bot":"Can use Discord Bot",
|
||||
"Can use WebDAV":"Can use WebDAV",
|
||||
"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",
|
||||
"Leave blank for unlimited":"Leave blank for unlimited",
|
||||
"Limited":"Limited",
|
||||
|
|
|
@ -12,6 +12,20 @@ $.ccio={
|
|||
fr:$('#files_recent'),
|
||||
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){
|
||||
var arr = jsonToDownload;
|
||||
if(arr.length===0 && errorResponse){
|
||||
|
@ -899,7 +913,46 @@ switch($user.details.lang){
|
|||
break;
|
||||
case 1://monitor icon
|
||||
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);
|
||||
break;
|
||||
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>';
|
||||
tmp+='<div class="btn-group btn-group-sm">'//start of btn list
|
||||
$.each([
|
||||
{label:"<%-cleanLang(lang.Snapshot)%>",attr:'monitor="snapshot"',class:'primary',icon:'camera'},
|
||||
{label:"<%-cleanLang(lang['Show Logs'])%>",attr:'monitor="show_data"',class:'warning',icon:'exclamation-triangle'},
|
||||
// {label:"<%-cleanLang(lang['Show Logs'])%>",attr:'class_toggle="show_data" data-target="'+dataTarget+'"',class:'warning',icon:'exclamation-triangle'},
|
||||
{label:"<%-cleanLang(lang.Control)%>",attr:'monitor="control_toggle"',class:'default arrows',icon:'arrows'},
|
||||
{label:"<%-cleanLang(lang['Status Indicator'])%>",attr:'monitor="watch_on"',class:'success signal',icon:'plug'},
|
||||
{label:"<%-cleanLang(lang['Detector'])%>",attr:'monitor="motion"',class:'warning',icon:'grav'},
|
||||
{label:"<%-cleanLang(lang.Pop)%>",attr:'monitor="pop"',class:'default',icon:'external-link'},
|
||||
// {label:"<%-cleanLang(lang.Magnify)%>",attr:'monitor="magnify"',class:'default',icon:'search-plus'},
|
||||
{label:"<%-cleanLang(lang.Calendar)%>",attr:'monitor="calendar"',class:'default',icon:'calendar'},
|
||||
{label:"<%-cleanLang(lang['Power Viewer'])%>",attr:'monitor="powerview"',class:'default',icon:'map-marker'},
|
||||
{label:"<%-cleanLang(lang['Time-lapse'])%>",attr:'monitor="timelapse"',class:'default',icon:'angle-double-right'},
|
||||
{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'},
|
||||
{label:"<%-cleanLang(lang.Fullscreen)%>",attr:'monitor="fullscreen"',class:'default',icon:'arrows-alt'},
|
||||
{label:"<%-cleanLang(lang.Close)%>",attr:'monitor="watch_off"',class:'danger',icon:'times'},
|
||||
],function(n,v){
|
||||
var buttons = {
|
||||
"Snapshot": {
|
||||
"label": "Snapshot",
|
||||
"attr": "monitor=\"snapshot\"",
|
||||
"class": "primary",
|
||||
"icon": "camera"
|
||||
},
|
||||
"Show Logs": {
|
||||
"label": "Show Logs",
|
||||
"attr": "monitor=\"show_data\"",
|
||||
"class": "warning",
|
||||
"icon": "exclamation-triangle"
|
||||
},
|
||||
"Control": {
|
||||
"label": "Control",
|
||||
"attr": "monitor=\"control_toggle\"",
|
||||
"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+='</div>';//end of btn list
|
||||
|
@ -1015,6 +1135,11 @@ switch($user.details.lang){
|
|||
}
|
||||
}
|
||||
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;
|
||||
case'user-row':
|
||||
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])
|
||||
$.timelapse.drawTimeline(false)
|
||||
}
|
||||
if($.vidview.loadedVideos && $.vidview.loadedVideos[d.filename])delete($.vidview.loadedVideos[d.filename])
|
||||
break;
|
||||
case'video_build_success':
|
||||
if(!d.mid){d.mid=d.id;};d.status=1;
|
||||
|
@ -2519,6 +2645,14 @@ $.ccio.cx=function(x,user){
|
|||
$(document).ready(function(e){
|
||||
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; ");
|
||||
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
|
||||
$.ccio.form={};
|
||||
$.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><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
|
||||
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>'
|
||||
})
|
||||
$.multimon.table.html(tmp)
|
||||
|
@ -4068,27 +4202,78 @@ $.vidview.f.submit(function(e){
|
|||
$('#videos_viewer_limit,#videos_viewer_daterange').change(function(){
|
||||
$.vidview.f.submit()
|
||||
})
|
||||
$.vidview.e.find('.delete_selected').click(function(e){
|
||||
e.s={}
|
||||
$.vidview.getSelected = function(getArray){
|
||||
var arr = {}
|
||||
if(getArray){
|
||||
arr = []
|
||||
}
|
||||
$.vidview.f.find('[data-ke] input:checked').each(function(n,v){
|
||||
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.title.text('<%-cleanLang(lang['Delete Selected Videos'])%>')
|
||||
e.html='<%-cleanLang(lang.DeleteSelectedVideosMsg)%><div style="margin-bottom:15px"></div>'
|
||||
var deleteLinks = []
|
||||
$.each(e.s,function(n,v){
|
||||
e.html+=n+'<br>';
|
||||
if($.vidview.loadedVideos[n])deleteLinks.push($.vidview.loadedVideos[n].links.deleteVideo)
|
||||
})
|
||||
$.confirm.body.html(e.html)
|
||||
$.confirm.click({title:'Delete Video',class:'btn-danger'},function(){
|
||||
$.each(e.s,function(n,v){
|
||||
$.getJSON($.ccio.init('location',$.users[v.auth])+v.auth+'/videos/'+$user.ke+'/'+v.mid+'/'+n+'/delete',function(d){
|
||||
$.each(deleteLinks,function(n,link){
|
||||
$.getJSON(link,function(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){
|
||||
e.limit=$.vidview.limit.val();
|
||||
e.page=$(this).attr('page');
|
||||
|
@ -4948,6 +5133,15 @@ $('body')
|
|||
$('.monitor_item').attr('data-gs-auto-position','no')
|
||||
}
|
||||
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')){
|
||||
case'text':
|
||||
|
@ -5161,6 +5355,7 @@ $('body')
|
|||
d.fn()
|
||||
$.vidview.pages.find('[page="'+$.vidview.current_page+'"]').addClass('active')
|
||||
e.v=$.vidview.e;
|
||||
$.vidview.loadedVideos = {}
|
||||
e.b=e.v.modal('show').find('.modal-body .contents');
|
||||
e.t=e.v.find('.modal-title i');
|
||||
switch(e.a){
|
||||
|
@ -5169,7 +5364,8 @@ $('body')
|
|||
e.ar=[];
|
||||
if(d.videos[0]){
|
||||
$.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];
|
||||
if(n){v.title=n.name+' - '+(parseInt(v.size)/1000000).toFixed(2)+'mb';}
|
||||
v.start=v.time;
|
||||
|
@ -5221,13 +5417,14 @@ $('body')
|
|||
e.tmp+='<tbody>';
|
||||
$.each(d.videos,function(n,v){
|
||||
if(v.status!==0){
|
||||
$.vidview.loadedVideos[v.filename] = Object.assign(v,{})
|
||||
var href = $.ccio.init('videoUrlBuild',v)
|
||||
v.mon=$.ccio.mon[v.ke+v.mid+user.auth_token];
|
||||
v.start=v.time;
|
||||
// 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+='<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.time+'">'+$.ccio.timeObject(v.time).format('h:mm:ss A, MMMM Do YYYY')+'</td>';
|
||||
e.tmp+='<td>'+v.mon.name+'</td>';
|
||||
|
|
|
@ -181,7 +181,9 @@ $.sU.e.on('click','.permission',function(e){
|
|||
$.each($.ccio.subs[$.pR.user],function(n,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){
|
||||
if(e.d[b]){
|
||||
$.each(e.d[b],function(n,v){
|
||||
|
@ -193,37 +195,43 @@ $.sU.e.on('click','.permission',function(e){
|
|||
|
||||
//permission window
|
||||
$.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){
|
||||
e.e=$(this),
|
||||
e.mon=$('.permission-view')
|
||||
e.details=$.pR.e.find('[name="details"]')
|
||||
e.json=JSON.parse(e.details.val())
|
||||
if(e.e.val()=='1'){
|
||||
if(e.e.val() === '1'){
|
||||
e.mon.hide();
|
||||
e.json.allmonitors='1';
|
||||
}else{
|
||||
e.mon.show()
|
||||
e.json.allmonitors='0';
|
||||
$.pR.e.find('[monitor]').first().change()
|
||||
}
|
||||
e.details.val(JSON.stringify(e.json))
|
||||
})
|
||||
$.pR.e.on('click','[check]',function(e){
|
||||
$(this).parents('.form-group-group').find('select').val($(this).attr('check')).first().change()
|
||||
})
|
||||
$.pR.e.on('change','[monitor]',function(e){
|
||||
e.monitors=[];
|
||||
e.key=$(this).attr('monitor');
|
||||
e.details=$.pR.e.find('[name="details"]')
|
||||
try{e.detail=JSON.parse(e.details.val())}catch(err){e.detail={}}
|
||||
if(!e.detail){e.detail={}}
|
||||
$.pR.e.find('[monitor="'+e.key+'"]').each(function(n,v){
|
||||
v=$(v)
|
||||
if(v.val()=='1'){
|
||||
e.monitors.push(v.attr('mid'))
|
||||
}
|
||||
});
|
||||
e.detail[e.key]=e.monitors;
|
||||
$.pR.e.find('[monitor]').each(function(n,kel){
|
||||
var monitors = [];
|
||||
var key = $(kel).attr('monitor')
|
||||
$.pR.e.find('[monitor="'+key+'"]').each(function(n,v){
|
||||
var el = $(v)
|
||||
if(el.val() === '1'){
|
||||
monitors.push(el.attr('mid'))
|
||||
}
|
||||
});
|
||||
e.detail[key] = monitors
|
||||
})
|
||||
e.details.val(JSON.stringify(e.detail))
|
||||
});
|
||||
$.pR.f.submit(function(e){
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<script src="libs/js/jquery-ui.min.js"></script>
|
||||
<script src="libs/js/jquery.serialize.js"></script>
|
||||
</head>
|
||||
<% cleanLang=function(string){
|
||||
<% cleanLang = function(string){
|
||||
if(!string){string=''}
|
||||
return string.replace(/'/g,"\\'")
|
||||
} %>
|
||||
}%>
|
|
@ -119,6 +119,14 @@
|
|||
</select></div>
|
||||
</label>
|
||||
</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">
|
||||
<label><div><span><%-lang['Can use LDAP']%></span></div>
|
||||
<div><select class="form-control" detail="use_ldap">
|
||||
|
|
|
@ -953,20 +953,31 @@
|
|||
<div><input class="form-control" detail="detector_command_timeout" placeholder="10"></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-12">
|
||||
<label><div><span><%-lang['Email on Trigger']%></span></div>
|
||||
<div><select class="form-control" detail="detector_mail">
|
||||
<option value="0" selected><%-lang.No%></option>
|
||||
<option value="1"><%-lang.Yes%></option>
|
||||
</select></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group col-md-12">
|
||||
<label><div><span><%-lang['Allow Next Email']%></span></div>
|
||||
<div><input class="form-control" detail="detector_mail_timeout" placeholder="10"></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><div><span><%-lang['Email on Trigger']%></span></div>
|
||||
<div><select class="form-control" detail="detector_mail" selector="h_det_email">
|
||||
<option value="0" selected><%-lang.No%></option>
|
||||
<option value="1"><%-lang.Yes%></option>
|
||||
</select></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group h_det_email_input h_det_email_1">
|
||||
<label><div><span><%-lang['Allow Next Email']%></span></div>
|
||||
<div><input class="form-control" detail="detector_mail_timeout" placeholder="10"></div>
|
||||
</label>
|
||||
</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 class="hidden">
|
||||
<div><input detail="cords" placeholder=""></div>
|
||||
|
|
|
@ -179,6 +179,31 @@
|
|||
</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'){ %>
|
||||
<div class="form-group-group forestgreen">
|
||||
<h4><%-lang.LDAP%></h4>
|
||||
|
|
|
@ -10,13 +10,40 @@
|
|||
</div>
|
||||
<div class="modal-body" style="max-height:600px;overflow:auto">
|
||||
<div class="text-center msg"></div>
|
||||
<div class="form-group">
|
||||
<label><div><span><%-lang['All Monitors and Privileges']%></span></div>
|
||||
<div><select class="form-control" detail="allmonitors">
|
||||
<option value="0" selected><%-lang.No%></option>
|
||||
<option value="1"><%-lang.Yes%></option>
|
||||
</select></div>
|
||||
</label>
|
||||
<div class="form-group-group">
|
||||
<h4><%-lang['Privileges']%></h4>
|
||||
<div class="form-group">
|
||||
<label><div><span><%-lang['All Monitors and Privileges']%></span></div>
|
||||
<div><select class="form-control" detail="allmonitors">
|
||||
<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 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 class="form-group-group blue permission-view" id="monitors_section">
|
||||
<h4>
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
<div class="modal-footer">
|
||||
<div class="row">
|
||||
<div class="col-md-4 text-left">
|
||||
<a class="btn btn-danger delete_selected"><i class="fa fa-trash-o"></i> <%-lang['Delete selected']%></a>
|
||||
<a class="btn btn-danger delete_selected"><i class="fa fa-trash-o"></i> <%-lang['Delete']%></a>
|
||||
<a class="btn btn-default export_selected"><i class="fa fa-folder-o"></i> <%-lang['Zip and Download']%></a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="text-center" id="videos_viewer_pages"></div>
|
||||
|
|
|
@ -107,9 +107,10 @@ if(data.addon.indexOf('gui')>-1){ %>
|
|||
<% };
|
||||
if(data.addon.indexOf('fullscreen')>-1){ %>
|
||||
<style>
|
||||
body,html{overflow: hidden;}
|
||||
body,html{overflow: hidden;height:100%}
|
||||
*{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>
|
||||
<script>
|
||||
$(window).resize(function(){
|
||||
|
|
|
@ -19,21 +19,12 @@
|
|||
<%= details.css %>
|
||||
</style>
|
||||
<style>
|
||||
<% if(details.sub&&details.allmonitors==='0'){
|
||||
if(details.monitor_edit&&details.monitor_edit!==''){
|
||||
details.monitor_edit.forEach(function(v,n){ %>
|
||||
[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}
|
||||
<%
|
||||
})
|
||||
}
|
||||
<% if(details.video_delete&&details.video_delete!==''){
|
||||
details.video_delete.forEach(function(v,n){ %>
|
||||
[mid="<%= v %>"] .permission_video_delete{display:inline-block}
|
||||
<%
|
||||
})
|
||||
}else{ %>
|
||||
.permission_video_delete,.permission_monitor_edit{display:inline-block}
|
||||
th.permission_video_delete,td.permission_video_delete{display:table-cell}
|
||||
<% } %>
|
||||
</style>
|
||||
|
@ -50,7 +41,7 @@
|
|||
<div class="mdl-layout__header-row">
|
||||
<ul class="nav navbar-nav">
|
||||
<li title="<%-lang['Toggle Sidebar']%>" class_toggle="hide-side" data-target=".mdl-js-layout"><a> <i class="fa fa-bars"></i> </a></li>
|
||||
<li title="<%-lang['Add Monitor']%>" mid="" ke="" class="hidden-xs permission_monitor_edit"><a monitor="edit"> <i class="fa fa-plus"></i> </a></li>
|
||||
<li title="<%-lang['Add Monitor']%>" mid="" ke="" class="hidden-xs permission_monitor_create"><a monitor="edit"> <i class="fa fa-plus"></i> </a></li>
|
||||
<li title="<%-lang['Power Video Viewer']%>" class="hidden-xs" mid="" ke=""><a monitor="powerview"> <i class="fa fa-map-marker"></i> </a></li>
|
||||
<li>
|
||||
<a title="<%-lang['Monitor Groups']%>" id="group_list_button" class="mdl-js-button"> <i class="fa fa-video-camera"></i> </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" 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" 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>
|
||||
<% 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="#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="#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="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" 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="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>
|
||||
|
|
|
@ -17,7 +17,6 @@ requires https or firefox
|
|||
</div>
|
||||
<video id="video"><source></video>
|
||||
<canvas id="canvas"></canvas>
|
||||
<script src="libs/js/jquery.min.js"></script>
|
||||
<script src="libs/js/socket.io.js"></script>
|
||||
<script src="libs/js/menu.js"></script>
|
||||
<script>
|
||||
|
|
Loading…
Reference in New Issue