Merge branch 'dev' into 'master'

Tabantha Frontier

See merge request Shinobi-Systems/Shinobi!49
merge-requests/55/head^2
Moe 2019-01-27 23:22:34 +00:00
commit 8bccd65fa1
84 changed files with 9372 additions and 743 deletions

View File

@ -27,7 +27,7 @@ if [ ! -e "./super.json" ]; then
fi
echo "Shinobi - Run yum update"
sudo yum update -y
sudo yum install make -y
sudo yum install make zip -y
echo "============="
echo "Shinobi - Do you want to Install FFMPEG?"
echo "(y)es or (N)o"
@ -143,21 +143,14 @@ if [ "$mysqlDefaultData" = "y" ] || [ "$mysqlDefaultData" = "Y" ]; then
echo "====================================="
echo "====================================="
fi
if [ ! "$sqliteormariadb" = "M" ] && [ ! "$sqliteormariadb" = "m" ]; then
echo "====================================="
echo "||===== Install Completed =====||"
echo "====================================="
echo "|| Login with the Superuser and create a new user!!"
echo "||==================================="
echo "|| Open http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080/super in your web browser."
echo "||==================================="
echo "|| Default Superuser : admin@shinobi.video"
echo "|| Default Password : admin"
echo "====================================="
echo "====================================="
else
echo "+=================================+"
echo "||===== Install Completed =====||"
echo "|| Access the main Shinobi panel at http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080 in your web browser."
echo "+=================================+"
fi
echo "====================================="
echo "||===== Install Completed =====||"
echo "====================================="
echo "|| Login with the Superuser and create a new user!!"
echo "||==================================="
echo "|| Open http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080/super in your web browser."
echo "||==================================="
echo "|| Default Superuser : admin@shinobi.video"
echo "|| Default Password : admin"
echo "====================================="
echo "====================================="

View File

@ -0,0 +1,41 @@
# Install prerequisites
DIR=`dirname $0`
INSTALLERS_DIR="$DIR"
echo "-----------------------------------"
if ! [ -x "$(command -v opencv_version)" ]; then
echo "Installing OpenCV"
dos2unix $INSTALLERS_DIR/opencv-cuda.sh
sh $INSTALLERS_DIR/opencv-cuda.sh
else
echo "OpenCV found... : $(opencv_version)"
fi
# this includes all the ones missing from OpenALPR's guide.
sudo apt install libtesseract-dev git cmake build-essential libleptonica-dev -y
sudo apt install liblog4cplus-dev libcurl3-dev -y
sudo apt install libleptonica-dev -y
sudo apt install libcurl4-openssl-dev -y
sudo apt install liblog4cplus-dev -y
sudo apt install beanstalkd -y
sudo apt install openjdk-8-jdk -y
# Clone the latest code from GitHub
git clone https://github.com/openalpr/openalpr.git
# Setup the build directory
cd openalpr/src
mkdir build
cd build
# setup the compile environment
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_INSTALL_SYSCONFDIR:PATH=/etc ..
# compile the library
make
# Install the binaries/libraries to your local system (prefix is /usr)
sudo make install
# Test the library
wget http://plates.openalpr.com/h786poj.jpg -O lp.jpg
alpr lp.jpg
rm lp.jpg

View File

@ -1,4 +1,14 @@
# Install prerequisites
DIR=`dirname $0`
INSTALLERS_DIR="$DIR"
echo "-----------------------------------"
if ! [ -x "$(command -v opencv_version)" ]; then
echo "Installing OpenCV"
dos2unix $INSTALLERS_DIR/opencv-cuda.sh
sh $INSTALLERS_DIR/opencv-cuda.sh
else
echo "OpenCV found... : $(opencv_version)"
fi
# this includes all the ones missing from OpenALPR's guide.
sudo apt install libtesseract-dev git cmake build-essential libleptonica-dev -y
sudo apt install liblog4cplus-dev libcurl3-dev -y
@ -28,4 +38,4 @@ sudo make install
# Test the library
wget http://plates.openalpr.com/h786poj.jpg -O lp.jpg
alpr lp.jpg
rm lp.jpg
rm lp.jpg

View File

@ -115,15 +115,6 @@ sudo chmod -R 755 .
touch INSTALL/installed.txt
dos2unix /home/Shinobi/INSTALL/shinobi
ln -s /home/Shinobi/INSTALL/shinobi /usr/bin/shinobi
if [ "$mysqlDefaultData" = "y" ] || [ "$mysqlDefaultData" = "Y" ]; then
echo "=====================================" > INSTALL/installed.txt
echo "======= Login Credentials =======" >> INSTALL/installed.txt
echo "|| Username : $userEmail" >> INSTALL/installed.txt
echo "|| Password : $userPasswordPlain" >> INSTALL/installed.txt
echo "|| API Key : $apiKey" >> INSTALL/installed.txt
echo "=====================================" >> INSTALL/installed.txt
echo "=====================================" >> INSTALL/installed.txt
fi
echo "Shinobi - Start Shinobi and set to start on boot?"
echo "(y)es or (N)o"
read startShinobi
@ -134,31 +125,14 @@ if [ "$startShinobi" = "y" ] || [ "$startShinobi" = "Y" ]; then
sudo pm2 save
sudo pm2 list
fi
if [ "$mysqlDefaultData" = "y" ] || [ "$mysqlDefaultData" = "Y" ]; then
echo "details written to INSTALL/installed.txt"
echo "====================================="
echo "======= Login Credentials ======="
echo "|| Username : $userEmail"
echo "|| Password : $userPasswordPlain"
echo "|| API Key : $apiKey"
echo "====================================="
echo "====================================="
fi
if [ ! "$sqliteormariadb" = "M" ] && [ ! "$sqliteormariadb" = "m" ]; then
echo "====================================="
echo "||===== Install Completed =====||"
echo "====================================="
echo "|| Login with the Superuser and create a new user!!"
echo "||==================================="
echo "|| Open http://$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1):8080/super in your web browser."
echo "||==================================="
echo "|| Default Superuser : admin@shinobi.video"
echo "|| Default Password : admin"
echo "====================================="
echo "====================================="
else
echo "+=================================+"
echo "||===== Install Completed =====||"
echo "|| Access the main Shinobi panel at http://$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1):8080 in your web browser."
echo "+=================================+"
fi
echo "====================================="
echo "||===== Install Completed =====||"
echo "====================================="
echo "|| Login with the Superuser and create a new user!!"
echo "||==================================="
echo "|| Open http://$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1):8080/super in your web browser."
echo "||==================================="
echo "|| Default Superuser : admin@shinobi.video"
echo "|| Default Password : admin"
echo "====================================="
echo "====================================="

View File

@ -1,30 +1,68 @@
#!/bin/bash
installationDirectory="/home/Shinobi"
if [ ! "$1" ]; then
if [ ! -e "/etc/shinobisystems/path.txt" ]; then
installationDirectory="/home/Shinobi"
else
installationDirectory=$(cat /etc/shinobisystems/cctv.txt)
fi
cd $installationDirectory
currentBuild=$(git show --oneline -s)
gitOrigin=$(git remote show origin)
splitBuildString=($currentBuild)
currentCommitNumber=${splitBuildString[0]}
if [[ $gitOrigin == *'ShinobiCE'* ]]; then
repo="CE"
else
repo="Pro"
fi
if [[ $@ == *'help'* ]] || [ ! "$1" ]; then
echo "========================================================="
echo "==!! Shinobi : The Open Source CCTV and NVR Solution !!=="
echo "========================================================="
echo "You are missing function parameters."
echo "Example : shinobi [command] .."
echo "Example : shinobi flush restart logs"
if [ ! "$1" ]; then
echo "You are missing function parameters."
echo "Example : shinobi [command] .."
echo "Example : shinobi flush restart logs"
else
echo "Hello there! if you need support come on over"
echo "to the Shinobi Community Chat! :)"
echo "https://discordapp.com/invite/mdhmvuH/"
fi
echo "========================================================="
echo "Your available options for COMMAND are as follows"
echo "========================================================="
echo "| start or s :"
echo "| start :"
echo "|--> Start camera.js and cron.js under PM2 (Process Manager)"
echo "-"
echo "| restart or r :"
echo "| restart :"
echo "|--> Restart all processes running under the PM2 daemon."
echo "-"
echo "| stop, exit, or e :"
echo "| stop, exit :"
echo "|--> Stop all processes running under the PM2 daemon."
echo "-"
echo "| version :"
echo "|--> get version of your current build by git."
echo "-"
echo "| logs :"
echo "|--> Get PM2 log stream with last 100 lines."
echo "-"
echo "| clear, flush, or f :"
echo "| update :"
echo "|--> Update via Git."
echo "-"
echo "| getMaster :"
echo "|--> Switch to the Master Branch (For Pro Repo only)."
echo "-"
echo "| getDev :"
echo "|--> Switch to the Development Branch (For Pro Repo only)."
echo "-"
echo "| clear, flush :"
echo "|--> Clear all PM2 logs."
echo "-"
echo "| bootupEnable :"
echo "|--> Start Shinobi on OS reboot."
echo "-"
echo "| bootupDisable :"
echo "|--> Disable starting Shinobi on OS reboot."
echo "-"
echo "| kill :"
echo "|--> Stop the entire PM2 daemon."
fi
@ -34,7 +72,8 @@ fi
if [[ $@ == *'restart'* ]]; then
proccessAlive=$(pm2 list | grep camera)
if [ "$proccessAlive" ]; then
pm2 restart all
pm2 restart $installationDirectory/camera.js
pm2 restart $installationDirectory/cron.js
else
echo "Shinobi process is not running."
fi
@ -58,11 +97,64 @@ fi
if [[ $@ == *'stop'* ]] || [[ $@ == *'exit'* ]]; then
proccessAlive=$(pm2 list | grep camera)
if [ "$proccessAlive" ]; then
pm2 kill
pm2 stop $installationDirectory/camera.js
pm2 stop $installationDirectory/cron.js
else
echo "Shinobi process is not running."
fi
fi
if [[ $@ == *'version'* ]]; then
echo "Build ID : $currentCommitNumber"
if [[ $repo == "Pro" ]]; then
echo "Repository : Shinobi Pro"
else
echo "Repository : Shinobi CE"
fi
echo $currentBuild
fi
if [[ $@ == *'bootupEnable'* ]] || [[ $@ == *'bootupenable'* ]]; then
pm2 startup
pm2 save
fi
if [[ $@ == *'bootupDisable'* ]] || [[ $@ == *'bootupdisable'* ]]; then
pm2 unstartup
pm2 save
fi
if [[ $@ == *'getDev'* ]] || [[ $@ == *'getdev'* ]]; then
if [[ $repo == "Pro" ]]; then
git checkout dev
echo "Shinobi - Restart Shinobi to make the changes take affect."
else
echo "Shinobi - Cannot use \"getDev\" with Shinobi CE"
fi
fi
if [[ $@ == *'getMaster'* ]] || [[ $@ == *'getmaster'* ]]; then
if [[ $repo == "Pro" ]]; then
git checkout master
echo "Shinobi - Restart Shinobi to make the changes take affect."
else
echo "Shinobi - Cannot use \"getMaster\" with Shinobi CE"
fi
fi
if [[ $@ == *'update'* ]]; then
echo "============="
echo "Shinobi - Are you sure you want to update? This will restart Shinobi."
echo "(y)es or (N)o"
read updateshinobi
if [ "$updateshinobi" = "y" ] || [ "$updateshinobi" = "Y" ]; then
echo "Beginning Update Process..."
pm2 stop $installationDirectory/camera.js
pm2 stop $installationDirectory/cron.js
npm install --unsafe-perm
npm audit fix --force
git reset --hard
git pull
pm2 start $installationDirectory/camera.js
pm2 start $installationDirectory/cron.js
else
echo "Cancelled Update Process."
fi
fi
if [[ $@ == *'kill'* ]]; then
pm2 kill
fi

View File

@ -0,0 +1,41 @@
var fs = require('fs');
var moment = require('moment');
var exec = require('child_process').exec;
var execSync = require('child_process').execSync;
s = {
isWin: (process.platform === 'win32' || process.platform === 'win64'),
mainDirectory: __dirname.split('/INSTALL')[0]
}
var createTerminalCommands = function(callback){
var next = function(){
if(callback)callback()
}
if(!s.isWin){
var etcPath = '/etc/shinobisystems/'
console.log('Creating "' + etcPath + '"...')
var createPathFile = function(){
var pathTxt = etcPath + 'cctv.txt'
console.log('Creating "' + pathTxt + '"...')
fs.writeFile(pathTxt,s.mainDirectory,function(err){
if(err)console.log(err)
fs.chmod(pathTxt,0o777,function(err){
if(err)console.log(err)
console.log('Linking "' + s.mainDirectory + '/INSTALL/shinobi" to "/usr/bin/shinobi"...')
fs.symlink(s.mainDirectory + '/INSTALL/shinobi', '/usr/bin/shinobi', next)
console.log('You can now use `shinobi` in terminal.')
})
})
}
fs.stat(etcPath,function(err,stat){
if(!err && stat){
createPathFile()
}else{
fs.mkdir(etcPath,createPathFile)
}
})
}else{
//no commands for windows yet
next()
}
}
createTerminalCommands()

View File

@ -30,12 +30,17 @@ if [ ! -e "./super.json" ]; then
echo "* You can edit these settings in \"super.json\" located in the Shinobi directory."
sudo cp super.sample.json super.json
fi
if ! [ -x "$(command -v ifconfig)" ]; then
echo "============="
echo "Shinobi - Installing Net-Tools"
sudo apt install net-tools -y
fi
if ! [ -x "$(command -v node)" ]; then
echo "============="
echo "Shinobi - Installing Node.js"
wget https://deb.nodesource.com/setup_9.x
chmod +x setup_9.x
./setup_9.x
wget https://deb.nodesource.com/setup_8.x
chmod +x setup_8.x
./setup_8.x
sudo apt install nodejs -y
else
echo "Node.js Found..."
@ -44,7 +49,7 @@ fi
if ! [ -x "$(command -v npm)" ]; then
sudo apt install npm -y
fi
sudo apt install make -y
sudo apt install make zip -y
if ! [ -x "$(command -v ffmpeg)" ]; then
if [ "$getubuntuversion" = "16" ] || [ "$getubuntuversion" < "16" ]; then
echo "============="
@ -132,21 +137,14 @@ if [ "$startShinobi" = "y" ] || [ "$startShinobi" = "y" ]; then
sudo pm2 save
sudo pm2 list
fi
if [ ! "$sqliteormariadb" = "M" ] && [ ! "$sqliteormariadb" = "m" ]; then
echo "====================================="
echo "||===== Install Completed =====||"
echo "====================================="
echo "|| Login with the Superuser and create a new user!!"
echo "||==================================="
echo "|| Open http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080/super in your web browser."
echo "||==================================="
echo "|| Default Superuser : admin@shinobi.video"
echo "|| Default Password : admin"
echo "====================================="
echo "====================================="
else
echo "+=================================+"
echo "||===== Install Completed =====||"
echo "|| Access the main Shinobi panel at http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080 in your web browser."
echo "+=================================+"
fi
echo "====================================="
echo "||===== Install Completed =====||"
echo "====================================="
echo "|| Login with the Superuser and create a new user!!"
echo "||==================================="
echo "|| Open http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080/super in your web browser."
echo "||==================================="
echo "|| Default Superuser : admin@shinobi.video"
echo "|| Default Password : admin"
echo "====================================="
echo "====================================="

View File

@ -26,7 +26,9 @@ loadLib('codeTester')(s,config,lang,io)
//basic functions
loadLib('basic')(s,config)
//video processing engine
loadLib('ffmpeg')(s,config,function(){
loadLib('ffmpeg')(s,config,function(ffmpeg){
//ffmpeg coProcessor
loadLib('ffmpegCoProcessor')(s,config,lang,ffmpeg)
//database connection : mysql, sqlite3..
loadLib('sql')(s,config)
//working directories : videos, streams, fileBin..
@ -67,6 +69,8 @@ loadLib('ffmpeg')(s,config,function(){
loadLib('notification')(s,config,lang)
//custom module loader
loadLib('customAutoLoad')(s,config,lang,app,io)
//scheduling engine
loadLib('scheduler')(s,config,lang,app,io)
//on-start actions, daemon(s) starter
loadLib('startup')(s,config,lang)
})

View File

@ -34,6 +34,10 @@
"API": "API",
"ONVIF": "ONVIF",
"FFprobe": "Probe",
"Monitor States": "Monitor States",
"Schedule": "Schedule",
"Schedules": "Schedules",
"Monitor States and Schedules": "Monitor States and Schedules",
"Filters": "Filters",
"Full URL Path": "Full URL Path",
"Logs": "Logs",
@ -116,6 +120,8 @@
"Can View Videos and Events": "Can View Videos and Events",
"Can Delete Videos and Events": "Can Delete Videos and Events",
"Saved Filters": "Saved Filters",
"Saved Presets": "Saved Presets",
"Saved Schedules": "Saved Schedules",
"Filter Name": "Filter Name",
"Find Where": "Find Where",
"Reason": "Reason",
@ -288,9 +294,15 @@
"DeleteMonitorText": "Do you want to delete this monitor? You cannot recover it. You can choose for the files to remain in the filesystem. If you choose to recreate a monitor with the same ID the videos and events will become visible in the dashboard.",
"DeleteMonitorsText": "Do you want to delete these monitors? You cannot recover them. You can choose to keep the files for these IDs in the filesystem. If you choose to recreate a monitor with one of the IDs the videos and events will become visible in the dashboard.",
"Invalid JSON": "Invalid JSON",
"Invalid Data": "Invalid Data",
"Name cannot be empty.": "Name cannot be empty.",
"Start Time cannot be empty.": "Start Time cannot be empty.",
"Must be atleast one row": "Must be atleast one row",
"InvalidJSONText": "Please ensure this is a valid JSON string for Shinobi monitor configuration.",
"Passwords don't match": "Passwords don't match",
"Email address is in use.": "Email address is in use.",
"Group Key is in use.": "Group Key is in use.",
"Create Sub-Accounts at /admin": "Create Sub-Accounts at /admin",
"No Events found for this video": "No Events found for this video",
"Video and Time Span (Minutes)": "Video and Time Span (Minutes)",
"Video Length (minutes) and Motion Count per video": "Video Length (minutes) and Motion Count per video",
@ -329,6 +341,10 @@
"Filter for Objects only": "Filter for Objects only",
"Custom": "Custom",
"Detector": "Detector",
"Audio Detector": "Audio Detector",
"Audio Detection": "Audio Detection",
"Minimum dB": "Minimum dB",
"Maximum dB": "Maximum dB",
"Connected": "Connected",
"Not Saved": "Not Saved",
"Not Connected": "Not Connected",
@ -400,7 +416,17 @@
"Image Height": "Image Height",
"Record File Type": "Record File Type",
"Video Codec": "Video Codec",
"Delete Monitor States Preset": "Delete Monitor States Preset",
"Delete Monitor State?": "Delete Monitor State",
"deleteMonitorStateText1": "Do you want to delete this Monitor States Preset?",
"deleteMonitorStateText2": "Do you want to delete this Monitor's Preset?",
"Search Images": "Search Images",
"Launch in New Window": "Launch in New Window",
"Preset": "Preset",
"Presets": "Presets",
"possibleInternalError": "Possible Internal Error",
"sizePurgeLockedText": "The Size Purge Lock (deleteOverMax) appears to have failed to unlock. Unlocking now...",
"Use coProcessor": "Use coProcessor",
"Audio Codec": "Audio Codec",
"Video Record Rate": "Video Record Rate <small>(FPS)</small>",
"Record Width": "Record Width",
@ -415,6 +441,7 @@
"Stream to YouTube": "Stream to YouTube",
"Stream to YouTube Flags": "Stream to YouTube Flags",
"Recording Flags": "Recording Flags",
"Traditional Recording Flags": "Traditional Recording Flags",
"Output Method": "Output Method",
"Webhook": "Webhook",
"Event Webhook Error": "Event Webhook Error",
@ -426,6 +453,8 @@
"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>",
"Attach Video Clip": "Attach Video Clip",
"Error While Decoding": "Error While Decoding",
"ErrorWhileDecodingText": "Your hardware may have an unstable connection to the network. Check your network connections.",
"Discord": "Discord",
"Discord Alert on Trigger": "Discord Alert on Trigger",
"Allow Next Email": "Allow Next Email <small>in Minutes</small>",
@ -642,6 +671,7 @@
"Monitor mode is already": "Monitor mode is already",
"Monitor or Key does not exist.": "Monitor or Key does not exist.",
"No Group with this key exists": "No Group with this key exists",
"Success": "Success",
"Trigger Successful": "Trigger Successful",
"No such file": "No such file",
"h265BrowserText1": "If you are trying to play an H.265 file, you may need to download it and open it in another application like VLC.",
@ -666,6 +696,10 @@
"Inserted State Configuration": "Inserted State Configuration",
"Edited State Configuration": "Edited State Configuration",
"Deleted State Configuration": "Deleted State Configuration",
"Schedule Configuration Not Found": "Schedule Configuration Not Found",
"Inserted Schedule Configuration": "Inserted Schedule Configuration",
"Edited Schedule Configuration": "Edited Schedule Configuration",
"Deleted Schedule Configuration": "Deleted Schedule Configuration",
"Dashboard Language": "Dashboard Language",
"Form Data Not Found": "Form Data Not Found",
"File Not Found": "File Not Found",
@ -777,6 +811,11 @@
"RTMP Stream":"RTMP Stream",
"Stream Channel":"Stream Channel",
"Confidence":"Confidence",
"Trainer Engine":"Trainer Engine",
"Train":"Train",
"TrainConfirm":"Are you sure you want to begin training? This can take more than 12 hours with over 500 images. This will consume a large amount of resources, like RAM or CPU.",
"Batch":"Batch",
"Subdivision":"Subdivision",
"Map":"Map",
"Add Map":"Add Map",
"Add Input Feed":"Add Input Feed",
@ -792,6 +831,7 @@
"TV Channel ID":"TV Channel ID",
"TV Channel Group":"TV Channel Group",
"Emotion Average":"Emotion Average",
"Require Object to be in Region":"Require Object to be in Region",
"Show Regions of Interest":"Show Regions of Interest",
"Confidence of Detection":"Confidence of Detection",
"Edit Selected":"Edit Selected",

View File

@ -12,7 +12,7 @@ module.exports = function(s,config){
if(s.isWin===true){
cmd = "Taskkill /IM ffmpeg.exe /F"
}else{
cmd = "ps aux | grep -ie ffmpeg | awk '{print $2}' | xargs kill -9"
cmd = "pkill -9 ffmpeg"
}
exec(cmd,{detached: true})
};
@ -33,7 +33,7 @@ module.exports = function(s,config){
s.parseJSON = function(string){
var parsed
try{
string = JSON.parse(string)
parsed = JSON.parse(string)
}catch(err){
}
@ -226,4 +226,19 @@ module.exports = function(s,config){
break;
}
}
s.createTimeout = function(timeoutVar,timeoutLength,defaultLength,multiplier,callback){
var theTimeout
if(!multiplier)multiplier = 1000 * 60
if(!timeoutLength || timeoutLength === ''){
theTimeout = defaultLength
}else{
theTimeout = parseFloat(timeoutLength) * multiplier
}
clearTimeout(timeoutVar)
timeoutVar = setTimeout(function(){
clearTimeout(timeoutVar)
delete(timeoutVar)
if(callback)callback()
},theTimeout)
}
}

View File

@ -1,24 +1,134 @@
var fs = require('fs')
var express = require('express')
module.exports = function(s,config,lang,app,io){
var checkFolder = function(folderName){
var folderPath = __dirname + '/' + folderName
fs.readdir(folderPath,function(err,folderContents){
if(!err && folderContents){
folderContents.forEach(function(filename){
if(filename.indexOf('.js') > -1){
var customModulePath = folderPath + '/' + filename
s.customAutoLoadModules = {}
s.customAutoLoadTree = {
pages: [],
PageBlocks: [],
LibsJs: [],
LibsCss: [],
adminPageBlocks: [],
adminLibsJs: [],
adminLibsCss: [],
superPageBlocks: [],
superLibsJs: [],
superLibsCss: []
}
var folderPath = __dirname + '/customAutoLoad'
var search = function(searchFor,searchIn){return searchIn.indexOf(searchFor) > -1}
fs.readdir(folderPath,function(err,folderContents){
if(!err && folderContents){
folderContents.forEach(function(filename){
s.customAutoLoadModules[filename] = {}
var customModulePath = folderPath + '/' + filename
if(filename.indexOf('.js') > -1){
s.customAutoLoadModules[filename].type = 'file'
try{
require(customModulePath)(s,config,lang,app,io)
}catch(err){
console.log('Failed to Load Module : ' + filename)
console.log(err)
}
}else{
if(fs.lstatSync(customModulePath).isDirectory()){
s.customAutoLoadModules[filename].type = 'folder'
try{
require(customModulePath)(s,config,lang,app,io)
fs.readdir(customModulePath,function(err,folderContents){
folderContents.forEach(function(name){
switch(name){
case'web':
var webFolder = s.checkCorrectPathEnding(customModulePath) + 'web/'
fs.readdir(webFolder,function(err,webFolderContents){
webFolderContents.forEach(function(name){
switch(name){
case'libs':
case'pages':
if(name === 'libs'){
if(config.webPaths.home !== '/'){
app.use('/libs',express.static(webFolder + '/libs'))
}
app.use(s.checkCorrectPathEnding(config.webPaths.home)+'libs',express.static(webFolder + '/libs'))
app.use(s.checkCorrectPathEnding(config.webPaths.admin)+'libs',express.static(webFolder + '/libs'))
app.use(s.checkCorrectPathEnding(config.webPaths.super)+'libs',express.static(webFolder + '/libs'))
}
var libFolder = webFolder + name + '/'
fs.readdir(libFolder,function(err,webFolderContents){
webFolderContents.forEach(function(libName){
var thirdLevelName = libFolder + libName
switch(libName){
case'js':
case'css':
case'blocks':
fs.readdir(thirdLevelName,function(err,webFolderContents){
webFolderContents.forEach(function(filename){
var fullPath = thirdLevelName + '/' + filename
var blockPrefix = ''
switch(true){
case search('super.',filename):
blockPrefix = 'super'
break;
case search('admin.',filename):
blockPrefix = 'admin'
break;
}
switch(libName){
case'js':
s.customAutoLoadTree[blockPrefix + 'LibsJs'].push(filename)
break;
case'css':
s.customAutoLoadTree[blockPrefix + 'LibsCss'].push(filename)
break;
case'blocks':
s.customAutoLoadTree[blockPrefix + 'PageBlocks'].push(fullPath)
break;
}
})
})
break;
default:
if(libName.indexOf('.ejs') > -1){
s.customAutoLoadTree.pages.push(thirdLevelName)
}
break;
}
})
})
break;
}
})
})
break;
case'languages':
var languagesFolder = s.checkCorrectPathEnding(customModulePath) + 'languages/'
fs.readdir(languagesFolder,function(err,files){
if(err)return console.log(err);
files.forEach(function(filename){
var fileData = require(languagesFolder + filename)
var rule = filename.replace('.json','')
if(config.language === rule){
lang = Object.assign(lang,fileData)
}
if(s.loadedLanguages[rule]){
s.loadedLanguages[rule] = Object.assign(s.loadedLanguages[rule],fileData)
}else{
s.loadedLanguages[rule] = Object.assign(s.copySystemDefaultLanguage(),fileData)
}
})
})
break;
}
})
})
}catch(err){
console.log('Failed to Load Module : ' + filename)
console.log(err)
}
}
})
}else{
fs.mkdirSync(folderPath)
}
})
}
checkFolder('customAutoLoad')
}
})
}else{
fs.mkdirSync(folderPath)
}
})
}

View File

@ -1,6 +1,11 @@
var P2P = require('pipe2pam');
// Matrix In Region Libs >
var SAT = require('sat')
var V = SAT.Vector;
var P = SAT.Polygon;
// Matrix In Region Libs />
var P2P = require('pipe2pam')
// pamDiff is based on https://www.npmjs.com/package/pam-diff
var PamDiff = require('./detectorPamDiff.js');
var PamDiff = require('pam-diff')
module.exports = function(s,config){
s.createPamDiffEngine = function(e){
var width,
@ -46,7 +51,7 @@ module.exports = function(s,config){
[width,height],
[width,0]
]
};
}
}
e.triggerTimer = {}
@ -58,7 +63,7 @@ module.exports = function(s,config){
regions : regions.forPam,
drawMatrix : e.details.detector_show_matrix
});
s.group[e.ke].mon[e.id].p2p = new P2P();
s.group[e.ke].mon[e.id].p2p = new P2P()
var regionArray = Object.values(regionJson)
if(config.detectorMergePamRegionTriggers === true){
// merge pam triggers for performance boost
@ -317,4 +322,39 @@ module.exports = function(s,config){
}
return trigger
}
s.isAtleastOneMatrixInRegion = function(regions,matrices,callback){
var regionPolys = []
var matrixPoints = []
regions.forEach(function(region,n){
var polyPoints = []
region.points.forEach(function(point){
polyPoints.push(new V(parseInt(point[0]),parseInt(point[1])))
})
regionPolys[n] = new P(new V(0,0), polyPoints)
})
var collisions = []
var foundInRegion = false
matrices.forEach(function(matrix){
var matrixPoints = [
new V(matrix.x,matrix.y),
new V(matrix.width,matrix.y),
new V(matrix.width,matrix.height),
new V(matrix.x,matrix.height)
]
var matrixPoly = new P(new V(0,0), matrixPoints)
regionPolys.forEach(function(region,n){
var response = new SAT.Response()
var collided = SAT.testPolygonPolygon(matrixPoly, region, response)
if(collided === true){
collisions.push({
matrix: matrix,
region: regions[n]
})
foundInRegion = true
}
})
})
if(callback)callback(foundInRegion,collisions)
return foundInRegion
}
}

View File

@ -4,6 +4,25 @@ var exec = require('child_process').exec;
var spawn = require('child_process').spawn;
var request = require('request');
module.exports = function(s,config,lang){
var addEventDetailsToString = function(eventData,string,addOps){
//d = event data
if(!addOps)addOps = {}
var newString = string + ''
var d = Object.assign(eventData,addOps)
var detailString = s.stringJSON(d.details)
newString
.replace(/{{TIME}}/g,d.currentTimestamp)
.replace(/{{REGION_NAME}}/g,d.details.name)
.replace(/{{SNAP_PATH}}/g,s.dir.streams+'/'+d.ke+'/'+d.id+'/s.jpg')
.replace(/{{MONITOR_ID}}/g,d.id)
.replace(/{{GROUP_KEY}}/g,d.ke)
.replace(/{{DETAILS}}/g,detailString)
if(d.details.confidence){
newString = newString
.replace(/{{CONFIDENCE}}/g,d.details.confidence)
}
return newString
}
s.filterEvents = function(x,d){
switch(x){
case'archive':
@ -45,6 +64,7 @@ module.exports = function(s,config,lang){
}
d.mon=s.group[d.ke].mon_conf[d.id];
var currentConfig = s.group[d.ke].mon[d.id].details
var hasMatrices = (d.details.matrices && d.details.matrices.length > 0)
//read filters
if(
currentConfig.use_detector_filters === '1' &&
@ -160,7 +180,7 @@ module.exports = function(s,config,lang){
})
if(d.details.matrices && d.details.matrices.length === 0 || filter.halt === true){
return
}else if(d.details.matrices && d.details.matrices.length > 0){
}else if(hasMatrices){
var reviewedMatrix = []
d.details.matrices.forEach(function(matrix){
if(matrix)reviewedMatrix.push(matrix)
@ -193,6 +213,16 @@ module.exports = function(s,config,lang){
return
}
}
// check if object should be in region
if(hasMatrices && currentConfig.detector_obj_region === '1'){
var regions = s.group[d.ke].mon[d.id].parsedObjects.cords
var isMatrixInRegions = s.isAtleastOneMatrixInRegion(regions,d.details.matrices)
if(isMatrixInRegions){
s.debugLog('Matrix in region!')
}else{
return
}
}
// check modified indifference
if(filter.indifference !== false && d.details.confidence < parseFloat(filter.indifference)){
// fails indifference check for modified indifference
@ -210,12 +240,12 @@ module.exports = function(s,config,lang){
})
}else{
//save this detection result in SQL, only coords. not image.
if(filter.save && currentConfig.detector_save==='1'){
if(filter.save && currentConfig.detector_save === '1'){
s.sqlQuery('INSERT INTO Events (ke,mid,details) VALUES (?,?,?)',[d.ke,d.id,detailString])
}
if(currentConfig.detector_notrigger === '1'){
var detector_notrigger_timeout
if(!currentConfig.detector_notrigger_timeout||currentConfig.detector_notrigger_timeout===''){
if(!currentConfig.detector_notrigger_timeout||currentConfig.detector_notrigger_timeout === ''){
detector_notrigger_timeout = 10
}
detector_notrigger_timeout = parseFloat(currentConfig.detector_notrigger_timeout)*1000*60;
@ -270,17 +300,7 @@ module.exports = function(s,config,lang){
})
if(filter.webhook && currentConfig.detector_webhook === '1'){
var detector_webhook_url = currentConfig.detector_webhook_url
.replace(/{{TIME}}/g,d.currentTimestamp)
.replace(/{{REGION_NAME}}/g,d.details.name)
.replace(/{{SNAP_PATH}}/g,s.dir.streams+'/'+d.ke+'/'+d.id+'/s.jpg')
.replace(/{{MONITOR_ID}}/g,d.id)
.replace(/{{GROUP_KEY}}/g,d.ke)
.replace(/{{DETAILS}}/g,detailString)
if(d.details.confidence){
detector_webhook_url = detector_webhook_url
.replace(/{{CONFIDENCE}}/g,d.details.confidence)
}
var detector_webhook_url = addEventDetailsToString(d,currentConfig.detector_webhook_url)
request({url:detector_webhook_url,method:'GET',encoding:null},function(err,data){
if(err){
s.userLog(d,{type:lang["Event Webhook Error"],msg:{error:err,data:data}})
@ -289,28 +309,8 @@ module.exports = function(s,config,lang){
}
if(filter.command && currentConfig.detector_command_enable === '1' && !s.group[d.ke].mon[d.id].detector_command){
var detector_command_timeout
if(!currentConfig.detector_command_timeout||currentConfig.detector_command_timeout===''){
detector_command_timeout = 1000*60*10;
}else{
detector_command_timeout = parseFloat(currentConfig.detector_command_timeout)*1000*60;
}
s.group[d.ke].mon[d.id].detector_command=setTimeout(function(){
clearTimeout(s.group[d.ke].mon[d.id].detector_command);
delete(s.group[d.ke].mon[d.id].detector_command);
},detector_command_timeout);
var detector_command = currentConfig.detector_command
.replace(/{{TIME}}/g,d.currentTimestamp)
.replace(/{{REGION_NAME}}/g,d.details.name)
.replace(/{{SNAP_PATH}}/g,s.dir.streams+'/'+d.ke+'/'+d.id+'/s.jpg')
.replace(/{{MONITOR_ID}}/g,d.id)
.replace(/{{GROUP_KEY}}/g,d.ke)
.replace(/{{DETAILS}}/g,detailString)
if(d.details.confidence){
detector_command = detector_command
.replace(/{{CONFIDENCE}}/g,d.details.confidence)
}
s.createTimeout(s.group[d.ke].mon[d.id].detector_command,currentConfig.detector_command_timeout,10)
var detector_command = addEventDetailsToString(d,currentConfig.detector_command)
exec(detector_command,{detached: true})
}
}

View File

@ -382,7 +382,16 @@ module.exports = function(s,config,onFinish){
//x = temporary values
//check if CUDA is enabled
e.isStreamer = (e.type === 'dashcam'|| e.type === 'socket')
if(e.details.accelerator === '1' && e.details.hwaccel === 'cuvid' && e.details.hwaccel_vcodec === ('h264_cuvid' || 'hevc_cuvid' || 'mjpeg_cuvid' || 'mpeg4_cuvid')){
e.coProcessor = false
if(
e.details.use_coprocessor === '1' &&
e.details.accelerator === '1' &&
e.isStreamer === false &&
(!e.details.input_maps || e.details.input_maps.length === 0) &&
(e.details.snap === '1' || e.details.stream_type === 'mjpeg' || e.details.stream_type === 'b64' || e.details.detector === '1')
){
e.coProcessor = true
}else if(e.details.accelerator === '1' && e.details.hwaccel === 'cuvid' && e.details.hwaccel_vcodec === ('h264_cuvid' || 'hevc_cuvid' || 'mjpeg_cuvid' || 'mpeg4_cuvid')){
e.cudaEnabled = true
}
//
@ -563,9 +572,11 @@ module.exports = function(s,config,onFinish){
x.pipe+=x.preset_stream+x.stream_acodec+x.stream_vcodec+' -f hls'+x.cust_stream+' -hls_time '+x.hls_time+' -hls_list_size '+x.hls_list_size+' -start_number 0 -hls_allow_cache 0 -hls_flags +delete_segments+omit_endlist "'+e.sdir+'s.m3u8"';
break;
case'mjpeg':
if(e.coProcessor === false){
if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality;
if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions}
x.pipe+=' -an -c:v mjpeg -f mpjpeg -boundary_tag shinobi'+x.cust_stream+x.stream_video_filters+' pipe:1';
}
break;
case'h265':
x.cust_stream+=' -movflags +frag_keyframe+empty_moov+default_base_moof -metadata title="Shinobi H.265 Stream" -reset_timestamps 1'
@ -578,9 +589,11 @@ module.exports = function(s,config,onFinish){
x.pipe+=' -f hevc'+x.stream_acodec+x.stream_vcodec+x.cust_stream+' pipe:1';
break;
case'b64':case'':case undefined:case null://base64
if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality;
if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions}
x.pipe+=' -an -c:v mjpeg -f image2pipe'+x.cust_stream+x.stream_video_filters+' pipe:1';
if(e.coProcessor === false){
if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality;
if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions}
x.pipe+=' -an -c:v mjpeg -f image2pipe'+x.cust_stream+x.stream_video_filters+' pipe:1';
}
break;
default:
x.pipe=''
@ -588,11 +601,12 @@ module.exports = function(s,config,onFinish){
}
if(e.details.stream_channels){
e.details.stream_channels.forEach(function(v,n){
// if(v.stream_type === 'mjpeg')e.coProcessor = true;
x.pipe += s.createStreamChannel(e,n+config.pipeAddition,v)
})
}
//api - snapshot bin/ cgi.bin (JPEG Mode)
if(e.details.snap === '1'){
if(e.details.snap === '1' && e.coProcessor === false){
if(e.details.input_map_choices&&e.details.input_map_choices.snap){
//add input feed map
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.snap)
@ -735,12 +749,23 @@ module.exports = function(s,config,onFinish){
x.record_string+=x.vcodec+x.record_fps+x.record_video_filters+x.record_dimensions+x.segment;
}
}
ffmpeg.buildAudioDetector = function(e,x){
if(e.details.detector_audio === '1'){
if(e.details.input_map_choices&&e.details.input_map_choices.detector_audio){
//add input feed map
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector_audio)
}else{
x.pipe += ' -map 0:a'
}
x.pipe += ' -acodec pcm_s16le -f s16le -ac 1 -ar 16000 pipe:6'
}
}
ffmpeg.buildMainDetector = function(e,x){
//e = monitor object
//x = temporary values
x.cust_detect = ' '
//detector - plugins, motion
if(e.details.detector === '1' && e.details.detector_send_frames === '1'){
if(e.details.detector === '1' && e.details.detector_send_frames === '1' && e.coProcessor === false){
if(e.details.input_map_choices&&e.details.input_map_choices.detector){
//add input feed map
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
@ -761,14 +786,15 @@ module.exports = function(s,config,onFinish){
if(e.details.detector_use_detect_object === '1'){
//for object detection
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
x.pipe += ' -f singlejpeg '+x.detector_vf+x.cust_detect+x.dratio+' pipe:4';
x.pipe += ' -an -f singlejpeg '+x.detector_vf+x.cust_detect+x.dratio+' pipe:4';
}
}else{
x.pipe+=' -f image2pipe '+x.detector_vf+x.cust_detect+x.dratio+' pipe:3';
x.pipe+=' -an -f image2pipe '+x.detector_vf+x.cust_detect+x.dratio+' pipe:3';
}
}
//Traditional Recording Buffer
if(e.details.detector=='1'&&e.details.detector_trigger=='1'&&e.details.detector_record_method==='sip'){
if(e.details.cust_sip_record && e.details.cust_sip_record !== ''){x.pipe += ' ' + e.details.cust_sip_record}
if(e.details.input_map_choices&&e.details.input_map_choices.detector_sip_buffer){
//add input feed map
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector_sip_buffer)
@ -836,6 +862,12 @@ module.exports = function(s,config,onFinish){
x.pipe+=x.detector_buffer_fps+x.detector_buffer_acodec+' -c:v '+e.details.detector_buffer_vcodec+' -f hls -tune '+e.details.detector_buffer_tune+' -g '+e.details.detector_buffer_g+' -hls_time '+e.details.detector_buffer_hls_time+' -hls_list_size '+e.details.detector_buffer_hls_list_size+' -start_number '+e.details.detector_buffer_start_number+' -live_start_index '+e.details.detector_buffer_live_start_index+' -hls_allow_cache 0 -hls_flags +delete_segments+omit_endlist "'+e.sdir+'detectorStream.m3u8"'
}
}
ffmpeg.buildCoProcessorFeed = function(e,x){
if(e.coProcessor === true){
// the coProcessor ffmpeg consumes this HLS stream (no audio, frames only)
x.pipe += ' -q:v 1 -an -c:v copy -f hls -tune zerolatency -g 1 -hls_time 2 -hls_list_size 3 -start_number 0 -live_start_index 3 -hls_allow_cache 0 -hls_flags +delete_segments+omit_endlist "'+e.sdir+'coProcessor.m3u8"'
}
}
ffmpeg.assembleMainPieces = function(e,x){
//create executeable FFMPEG command
x.ffmpegCommandString = x.loglevel+x.input_fps;
@ -852,6 +884,9 @@ module.exports = function(s,config,onFinish){
case'mjpeg':
x.ffmpegCommandString += ' -reconnect 1 -f mjpeg'+x.cust_input+x.hwaccel+' -i "'+e.url+'"';
break;
// case'rtmp':
// x.ffmpegCommandString += x.cust_input+x.hwaccel+' -i -';
// break;
case'h264':case'hls':case'mp4':
x.ffmpegCommandString += x.cust_input+x.hwaccel+' -i "'+e.url+'"';
break;
@ -886,7 +921,9 @@ module.exports = function(s,config,onFinish){
ffmpeg.buildMainInput(e,x)
ffmpeg.buildMainStream(e,x)
ffmpeg.buildMainRecording(e,x)
ffmpeg.buildAudioDetector(e,x)
ffmpeg.buildMainDetector(e,x)
ffmpeg.buildCoProcessorFeed(e,x)
s.onFfmpegCameraStringCreationExtensions.forEach(function(extender){
extender(e,x)
})

234
libs/ffmpegCoProcessor.js Normal file
View File

@ -0,0 +1,234 @@
var spawn = require('child_process').spawn;
module.exports = function(s,config,lang,ffmpeg){
ffmpeg.buildCoProcessorInput = function(e,x){
if(e.details.userLoglevel&&e.details.userLoglevel!==''){x.loglevel='-loglevel '+e.details.userLoglevel;}else{x.loglevel='-loglevel error'}
x.input = x.loglevel+' -re -i '+e.sdir+'coProcessor.m3u8'
}
ffmpeg.buildCoProcessorStream = function(e,x){
x.stream_video_filters = []
//stream - timestamp
if(e.details.stream_timestamp&&e.details.stream_timestamp=="1"&&e.details.vcodec!=='copy'){
//font
if(e.details.stream_timestamp_font&&e.details.stream_timestamp_font!==''){x.stream_timestamp_font=e.details.stream_timestamp_font}else{x.stream_timestamp_font='/usr/share/fonts/truetype/freefont/FreeSans.ttf'}
//position x
if(e.details.stream_timestamp_x&&e.details.stream_timestamp_x!==''){x.stream_timestamp_x=e.details.stream_timestamp_x}else{x.stream_timestamp_x='(w-tw)/2'}
//position y
if(e.details.stream_timestamp_y&&e.details.stream_timestamp_y!==''){x.stream_timestamp_y=e.details.stream_timestamp_y}else{x.stream_timestamp_y='0'}
//text color
if(e.details.stream_timestamp_color&&e.details.stream_timestamp_color!==''){x.stream_timestamp_color=e.details.stream_timestamp_color}else{x.stream_timestamp_color='white'}
//box color
if(e.details.stream_timestamp_box_color&&e.details.stream_timestamp_box_color!==''){x.stream_timestamp_box_color=e.details.stream_timestamp_box_color}else{x.stream_timestamp_box_color='0x00000000@1'}
//text size
if(e.details.stream_timestamp_font_size&&e.details.stream_timestamp_font_size!==''){x.stream_timestamp_font_size=e.details.stream_timestamp_font_size}else{x.stream_timestamp_font_size='10'}
x.stream_video_filters.push('drawtext=fontfile='+x.stream_timestamp_font+':text=\'%{localtime}\':x='+x.stream_timestamp_x+':y='+x.stream_timestamp_y+':fontcolor='+x.stream_timestamp_color+':box=1:boxcolor='+x.stream_timestamp_box_color+':fontsize='+x.stream_timestamp_font_size);
}
//stream - watermark for -vf
if(e.details.stream_watermark&&e.details.stream_watermark=="1"&&e.details.stream_watermark_location&&e.details.stream_watermark_location!==''){
switch(e.details.stream_watermark_position){
case'tl'://top left
x.stream_watermark_position='10:10'
break;
case'tr'://top right
x.stream_watermark_position='main_w-overlay_w-10:10'
break;
case'bl'://bottom left
x.stream_watermark_position='10:main_h-overlay_h-10'
break;
default://bottom right
x.stream_watermark_position='(main_w-overlay_w-10)/2:(main_h-overlay_h-10)/2'
break;
}
x.stream_video_filters.push('movie='+e.details.stream_watermark_location+'[watermark],[in][watermark]overlay='+x.stream_watermark_position+'[out]');
}
//stream - rotation
if(e.details.rotate_stream&&e.details.rotate_stream!==""&&e.details.rotate_stream!=="no"&&e.details.stream_vcodec!=='copy'){
x.stream_video_filters.push('transpose='+e.details.rotate_stream);
}
if(e.details.svf&&e.details.svf!==''){
x.stream_video_filters.push(e.details.svf)
}
if(x.stream_video_filters.length>0){
x.stream_video_filters=' -vf '+x.stream_video_filters.join(',')
}else{
x.stream_video_filters=''
}
if(e.details.cust_stream&&e.details.cust_stream!==''){x.cust_stream=' '+e.details.cust_stream}else{x.cust_stream=''}
if(e.details.stream_fps&&e.details.stream_fps!==''){x.stream_fps=' -r '+e.details.stream_fps}else{x.stream_fps=''}
if(e.details.stream_vcodec !== 'copy' || e.details.stream_type === 'mjpeg' || e.details.stream_type === 'b64'){
x.cust_stream += x.stream_fps
}
switch(e.details.stream_type){
case'mjpeg':
if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality;
if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions}
x.pipe += ' -an -c:v mjpeg -f mpjpeg -boundary_tag shinobi'+x.cust_stream+x.stream_video_filters+' pipe:1';
break;
case'b64':case'':case undefined:case null://base64
if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality;
if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions}
x.pipe += ' -an -c:v mjpeg -f image2pipe'+x.cust_stream+x.stream_video_filters+' pipe:1';
break;
}
}
ffmpeg.buildCoProcessorDetector = function(e,x){
//detector frames
x.cust_detect=' '
if(e.details.detector === '1'){
if(e.details.detector_fps && e.details.detector_fps !== ''){
x.detector_fps = e.details.detector_fps
}else{
x.detector_fps = '2'
}
if(e.details.detector_scale_x && e.details.detector_scale_x !== '' && e.details.detector_scale_y && e.details.detector_scale_y !== ''){
x.dratio=' -s '+e.details.detector_scale_x+'x'+e.details.detector_scale_y
}else{
x.dratio=' -s 320x240'
}
if(e.details.cust_detect&&e.details.cust_detect!==''){x.cust_detect+=e.details.cust_detect;}
if(e.details.detector_pam==='1'){
x.pipe += ' -an -c:v pam -pix_fmt gray -f image2pipe -r '+x.detector_fps+x.cust_detect+x.dratio+' pipe:3'
if(e.details.detector_use_detect_object === '1'){
if(e.details.detector_use_motion === '1'){
if(e.details.detector_scale_x_object && e.details.detector_scale_x_object !== '' && e.details.detector_scale_y_object && e.details.detector_scale_y_object !== ''){
x.dratio=' -s '+e.details.detector_scale_x_object+'x'+e.details.detector_scale_y_object
}
if(e.details.detector_fps_object && e.details.detector_fps_object !== ''){
x.detector_fps = e.details.detector_fps_object
}
}
//for object detection
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
x.pipe += ' -f singlejpeg -vf fps='+x.detector_fps+x.cust_detect+x.dratio+' pipe:4';
}
}else{
x.pipe+=' -f singlejpeg -vf fps='+x.detector_fps+x.cust_detect+x.dratio+' pipe:3';
}
}
}
ffmpeg.buildCoProcessorJpegApi = function(e,x){
//snapshot frames
if(e.details.snap === '1'){
if(!e.details.snap_fps || e.details.snap_fps === ''){e.details.snap_fps = 1}
if(e.details.snap_vf && e.details.snap_vf !== ''){x.snap_vf=' -vf '+e.details.snap_vf}else{x.snap_vf=''}
if(e.details.snap_scale_x && e.details.snap_scale_x !== '' && e.details.snap_scale_y && e.details.snap_scale_y !== ''){x.snap_ratio = ' -s '+e.details.snap_scale_x+'x'+e.details.snap_scale_y}else{x.snap_ratio=''}
if(e.details.cust_snap && e.details.cust_snap !== ''){x.cust_snap = ' '+e.details.cust_snap}else{x.cust_snap=''}
x.pipe += ' -update 1 -r '+e.details.snap_fps+x.cust_snap+x.snap_ratio+x.snap_vf+' "'+e.sdir+'s.jpg" -y';
}
}
ffmpeg.buildCoProcessorPipeArray = function(e,x){
x.stdioPipes = [];
var times = config.pipeAddition;
if(e.details.stream_channels){
times+=e.details.stream_channels.length
}
for(var i=0; i < times; i++){
x.stdioPipes.push('pipe')
}
}
s.ffmpegCoProcessor = function(e){
if(e.coProcessor === false)return;
var x = {}
x.pipe = ''
ffmpeg.buildCoProcessorInput(e,x)
ffmpeg.buildCoProcessorStream(e,x)
ffmpeg.buildCoProcessorDetector(e,x)
ffmpeg.buildCoProcessorJpegApi(e,x)
ffmpeg.buildCoProcessorPipeArray(e,x)
var commandString = x.input + x.pipe
if(commandString === x.input){
return false
}
s.group[e.ke].mon[e.mid].coProcessorCmd = commandString
return spawn(config.ffmpegDir,s.splitForFFPMEG((commandString).replace(/\s+/g,' ').trim()),{detached: true,stdio:x.stdioPipes})
}
s.coSpawnLauncher = function(e){
if(s.group[e.ke].mon[e.id].isStarted === true && e.coProcessor === true){
s.coSpawnClose(e)
s.group[e.ke].mon[e.id].coSpawnProcessor = s.ffmpegCoProcessor(e)
if(s.group[e.ke].mon[e.id].coSpawnProcessor === false){
return
}
s.userLog(e,{type:lang['coProcessor Started'],msg:{msg:lang.coProcessorTextStarted,cmd:s.group[e.ke].mon[e.id].coProcessorCmd}});
s.group[e.ke].mon[e.id].coSpawnProcessorExit = function(){
s.userLog(e,{type:lang['coProcess Unexpected Exit'],msg:{msg:lang['coProcess Crashed for Monitor']+' : '+e.id,cmd:s.group[e.ke].mon[e.id].coProcessorCmd}});
setTimeout(function(){
s.coSpawnLauncher(e)
},2000)
}
s.group[e.ke].mon[e.id].coSpawnProcessor.on('end',s.group[e.ke].mon[e.id].coSpawnProcessorExit)
s.group[e.ke].mon[e.id].coSpawnProcessor.on('exit',s.group[e.ke].mon[e.id].coSpawnProcessorExit)
var checkLog = function(d,x){return d.indexOf(x)>-1;}
s.group[e.ke].mon[e.id].coSpawnProcessor.stderr.on('data',function(d){
d=d.toString();
switch(true){
case checkLog(d,'deprecated pixel format used'):
case checkLog(d,'[hls @'):
case checkLog(d,'Past duration'):
case checkLog(d,'Last message repeated'):
case checkLog(d,'pkt->duration = 0'):
case checkLog(d,'Non-monotonous DTS'):
case checkLog(d,'NULL @'):
return
break;
}
s.userLog(e,{type:lang.coProcessor,msg:d});
})
if(e.frame_to_stream){
s.group[e.ke].mon[e.id].coSpawnProcessor.stdout.on('data',e.frame_to_stream)
}
if(e.details.detector === '1'){
s.ocvTx({f:'init_monitor',id:e.id,ke:e.ke})
//frames from motion detect
if(e.details.detector_pam === '1'){
s.createPamDiffEngine(e)
s.group[e.ke].mon[e.id].coSpawnProcessor.stdio[3].pipe(s.group[e.ke].mon[e.id].p2p).pipe(s.group[e.ke].mon[e.id].pamDiff)
if(e.details.detector_use_detect_object === '1'){
s.group[e.ke].mon[e.id].coSpawnProcessor.stdio[4].on('data',function(d){
s.group[e.ke].mon[e.id].lastJpegDetectorFrame = d
})
}
}else if(s.ocv){
if(s.ocv.connectionType !== 'ram'){
s.group[e.ke].mon[e.id].coSpawnProcessor.stdio[3].on('data',function(d){
s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d});
})
}else{
s.group[e.ke].mon[e.id].coSpawnProcessor.stdio[3].on('data',function(d){
if(!s.group[e.ke].mon[e.id].detectorFrameSaveBuffer){
s.group[e.ke].mon[e.id].detectorFrameSaveBuffer=[d]
}else{
s.group[e.ke].mon[e.id].detectorFrameSaveBuffer.push(d)
}
if(d[d.length-2] === 0xFF && d[d.length-1] === 0xD9){
var buffer = Buffer.concat(s.group[e.ke].mon[e.id].detectorFrameSaveBuffer);
var frameLocation = s.dir.streams + e.ke + '/' + e.id + '/' + s.gid(5) + '.jpg'
if(s.ocv){
fs.writeFile(frameLocation,buffer,function(err){
if(err){
s.debugLog(err)
}else{
s.ocvTx({f:'frameFromRam',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frameLocation:frameLocation})
}
})
}
s.group[e.ke].mon[e.id].detectorFrameSaveBuffer = null;
}
})
}
}
}
}
}
s.coSpawnClose = function(e){
if(s.group[e.ke].mon[e.id].coSpawnProcessor){
s.group[e.ke].mon[e.id].coSpawnProcessor.removeListener('end',s.group[e.ke].mon[e.id].coSpawnProcessorExit);
s.group[e.ke].mon[e.id].coSpawnProcessor.removeListener('exit',s.group[e.ke].mon[e.id].coSpawnProcessorExit);
s.group[e.ke].mon[e.id].coSpawnProcessor.stdin.pause()
s.group[e.ke].mon[e.id].coSpawnProcessor.kill()
delete(s.group[e.ke].mon[e.id].coSpawnProcessor)
s.userLog(e,{type:lang['coProcessor Stopped'],msg:{msg:lang.coProcessorTextStopped+' : '+e.id}});
}
}
}

View File

@ -6,6 +6,7 @@ var Mp4Frag = require('mp4frag');
var onvif = require('node-onvif');
var request = require('request');
var connectionTester = require('connection-tester')
var SoundDetection = require('shinobi-sound-detection')
var URL = require('url')
module.exports = function(s,config,lang){
s.initiateMonitorObject = function(e){
@ -21,6 +22,7 @@ module.exports = function(s,config,lang){
if(!s.group[e.ke].mon[e.mid].eventBasedRecording){s.group[e.ke].mon[e.mid].eventBasedRecording={}};
if(!s.group[e.ke].mon[e.mid].watch){s.group[e.ke].mon[e.mid].watch={}};
if(!s.group[e.ke].mon[e.mid].fixingVideos){s.group[e.ke].mon[e.mid].fixingVideos={}};
if(!s.group[e.ke].mon[e.mid].parsedObjects){s.group[e.ke].mon[e.mid].parsedObjects={}};
if(!s.group[e.ke].mon[e.mid].isStarted){s.group[e.ke].mon[e.mid].isStarted = false};
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={}}
@ -103,7 +105,7 @@ module.exports = function(s,config,lang){
var snapBuffer = []
var snapProcess = spawn(config.ffmpegDir,('-loglevel quiet -re -i '+url+options+' -frames:v 1 -f image2pipe pipe:1').split(' '),{detached: true})
snapProcess.stdout.on('data',function(data){
snapBuffer.push(data)
if(snapBuffer)snapBuffer.push(data)
})
snapProcess.stderr.on('data',function(data){
console.log(data.toString())
@ -266,6 +268,7 @@ module.exports = function(s,config,lang){
if(s.group[e.ke].mon[e.id].childNode){
s.cx({f:'kill',d:s.cleanMonitorObject(e)},s.group[e.ke].mon[e.id].childNodeId)
}else{
s.coSpawnClose(e)
if(!x||x===1){return};
p=x.pid;
if(s.group[e.ke].mon_conf[e.id].type===('dashcam'||'socket'||'jpeg'||'pipe')){
@ -282,12 +285,20 @@ module.exports = function(s,config,lang){
s.cameraCheckObjectsInDetails = function(e){
//parse Objects
(['detector_cascades','cords','detector_filters','input_map_choices']).forEach(function(v){
if(e.details&&e.details[v]&&(e.details[v] instanceof Object)===false){
if(e.details && e.details[v]){
try{
if(e.details[v] === '') e.details[v] = '{}'
e.details[v]=JSON.parse(e.details[v]);
if(!e.details[v])e.details[v]={};
s.group[e.ke].mon[e.id].details = e.details;
if(!e.details[v] || e.details[v] === '')e.details[v] = '{}'
e.details[v] = s.parseJSON(e.details[v])
if(!e.details[v])e.details[v] = {}
s.group[e.ke].mon[e.id].details = e.details
switch(v){
case'cords':
s.group[e.ke].mon[e.id].parsedObjects[v] = Object.values(s.parseJSON(e.details[v]))
break;
default:
s.group[e.ke].mon[e.id].parsedObjects[v] = s.parseJSON(e.details[v])
break;
}
}catch(err){
}
@ -776,7 +787,47 @@ module.exports = function(s,config,lang){
if(e.type==='jpeg'){
s.cameraPullJpegStream(e)
}
if(e.details.detector === '1'){
if(e.details.detector_audio === '1'){
var triggerLevel
var triggerLevelMax
if(e.details.detector_audio_min_db && e.details.detector_audio_min_db !== ''){
triggerLevel = parseInt(e.details.detector_audio_min_db)
}else{
triggerLevel = 5
}
if(e.details.detector_audio_max_db && e.details.detector_audio_max_db !== ''){
triggerLevelMax = parseInt(e.details.detector_audio_max_db)
}
var audioDetector = new SoundDetection({
format: {
bitDepth: 16,
numberOfChannels: 1,
signed: true
},
triggerLevel: triggerLevel,
triggerLevelMax: triggerLevelMax
},function(dB) {
s.triggerEvent({
f:'trigger',
id:e.id,
ke:e.ke,
name: 'db',
details:{
plug:'audio',
name:'db',
reason:'soundChange',
confidence:dB
},
plates:[],
imgHeight:e.details.detector_scale_y,
imgWidth:e.details.detector_scale_x
})
})
s.group[e.ke].mon[e.id].audioDetector = audioDetector
audioDetector.start()
s.group[e.ke].mon[e.id].spawn.stdio[6].pipe(audioDetector.streamDecoder)
}
if(e.details.detector === '1' && e.coProcessor === false){
s.ocvTx({f:'init_monitor',id:e.id,ke:e.ke})
//frames from motion detect
if(e.details.detector_pam === '1'){
@ -865,7 +916,11 @@ module.exports = function(s,config,lang){
break;
}
if(e.frameToStream){
s.group[e.ke].mon[e.id].spawn.stdout.on('data',e.frameToStream)
if(e.coProcessor === true && e.details.stream_type === ('b64'||'mjpeg')){
}else{
s.group[e.ke].mon[e.id].spawn.stdout.on('data',e.frameToStream)
}
}
if(e.details.stream_channels && e.details.stream_channels !== ''){
var createStreamEmitter = function(channel,number){
@ -911,6 +966,12 @@ module.exports = function(s,config,lang){
s.group[e.ke].mon[e.id].spawn.stderr.on('data',function(d){
d=d.toString();
switch(true){
// case checkLog(d,'No space left on device'):
//
// break;
case checkLog(d,'error while decoding'):
s.userLog(e,{type:lang['Error While Decoding'],msg:lang.ErrorWhileDecodingText});
break;
case checkLog(d,'[hls @'):
case checkLog(d,'Past duration'):
case checkLog(d,'Last message repeated'):
@ -938,6 +999,7 @@ module.exports = function(s,config,lang){
case checkLog(d,'mjpeg_decode_dc'):
case checkLog(d,'bad vlc'):
case checkLog(d,'error dc'):
case checkLog(d,'No route to host'):
s.launchMonitorProcesses(e)
break;
case /T[0-9][0-9]-[0-9][0-9]-[0-9][0-9]./.test(d):
@ -999,7 +1061,7 @@ module.exports = function(s,config,lang){
e.detector_notrigger_timeout = parseFloat(e.details.detector_notrigger_timeout)*1000*60;
s.group[e.ke].mon[e.id].detector_notrigger_timeout_function = function(){
s.onDetectorNoTriggerTimeoutExtensions.forEach(function(extender){
extender(r,e)
extender(e)
})
}
clearInterval(s.group[e.ke].mon[e.id].detector_notrigger_timeout)
@ -1012,7 +1074,11 @@ module.exports = function(s,config,lang){
if(s.group[e.ke].mon[e.id].isStarted === true){
fs.stat(e.sdir+'s.jpg',function(err,snap){
var notStreaming = function(){
s.launchMonitorProcesses(e)
if(e.coProcessor === true){
s.coSpawnLauncher(e)
}else{
s.launchMonitorProcesses(e)
}
s.userLog(e,{type:lang['Camera is not streaming'],msg:{msg:lang['Restarting Process']}})
s.orphanedVideoCheck(e,2,null,true)
}
@ -1097,6 +1163,11 @@ module.exports = function(s,config,lang){
){
s.cameraFilterFfmpegLog(e)
}
if(e.coProcessor === true){
setTimeout(function(){
s.coSpawnLauncher(e)
},6000)
}
s.onMonitorStartExtensions.forEach(function(extender){
extender(Object.assign(s.group[e.ke].mon_conf[e.id],{}),e)
})
@ -1435,8 +1506,8 @@ module.exports = function(s,config,lang){
s.group[e.ke].mon[e.mid].isRecording = false
}
//set up fatal error handler
if(e.details.fatal_max===''){
e.details.fatal_max = 10
if(e.details.fatal_max === ''){
e.details.fatal_max = 0
}else{
e.details.fatal_max = parseFloat(e.details.fatal_max)
}
@ -1454,4 +1525,48 @@ module.exports = function(s,config,lang){
}
if(typeof cn === 'function'){setTimeout(function(){cn()},1000)}
}
//
s.activateMonitorStates = function(groupKey,stateName,user,callback){
var endData = {
ok: false
}
s.findPreset([groupKey,'monitorStates',stateName],function(notFound,preset){
if(notFound === false){
var sqlQuery = 'SELECT * FROM Monitors WHERE ke=? AND '
var monitorQuery = []
var sqlQueryValues = [groupKey]
var monitorPresets = {}
preset.details.monitors.forEach(function(monitor){
monitorQuery.push('mid=?')
sqlQueryValues.push(monitor.mid)
monitorPresets[monitor.mid] = monitor
})
sqlQuery += '('+monitorQuery.join(' OR ')+')'
s.sqlQuery(sqlQuery,sqlQueryValues,function(err,monitors){
if(monitors && monitors[0]){
monitors.forEach(function(monitor){
s.checkDetails(monitor)
s.checkDetails(monitorPresets[monitor.mid])
var monitorPreset = monitorPresets[monitor.mid]
monitorPreset.details = Object.assign(monitor.details,monitorPreset.details)
monitor = s.cleanMonitorObjectForDatabase(Object.assign(monitor,monitorPreset))
monitor.details = JSON.stringify(monitor.details)
s.addOrEditMonitor(Object.assign(monitor,{}),function(err,endData){
},user)
})
endData.ok = true
s.tx({f:'change_group_state',ke:groupKey,name:stateName},'GRP_'+groupKey)
callback(endData)
}else{
endData.msg = user.lang['State Configuration has no monitors associated']
callback(endData)
}
})
}else{
endData.msg = user.lang['State Configuration Not Found']
callback(endData)
}
})
}
}

View File

@ -1,3 +1,4 @@
var fs = require("fs")
var Discord = require("discord.js")
module.exports = function(s,config,lang){
//discord bot

263
libs/scheduler.js Normal file
View File

@ -0,0 +1,263 @@
module.exports = function(s,config,lang,app,io){
s.schedules = {}
//Get all Schedules
s.getAllSchedules = function(callback){
s.schedules = {}
s.sqlQuery('SELECT * FROM Schedules',function(err,rows){
rows.forEach(function(schedule){
s.updateSchedule(schedule)
})
if(callback)callback()
})
}
//update schedule
s.updateSchedule = function(row){
var schedule = Object.assign(row,{})
if(!s.schedules[schedule.ke])s.schedules[schedule.ke] = {}
s.checkDetails(schedule)
if(!s.schedules[schedule.ke][schedule.name]){
s.schedules[schedule.ke][schedule.name] = schedule
}else{
s.schedules[schedule.ke][schedule.name] = Object.assign(s.schedules[schedule.ke][schedule.name],schedule)
}
}
//check time in schedule
s.checkTimeAgainstSchedule = function(start,end,callback){
try{
if(
start
){
var checkStartTime = new Date()
var startSplit = start.split(':')
var startHour = parseInt(startSplit[0])
var startMin = parseInt(startSplit[1])
checkStartTime.setHours(startHour)
checkStartTime.setMinutes(startMin)
if(end){
var checkEndTime = new Date()
var endSplit = end.split(':')
var endHour = parseInt(endSplit[0])
var endMin = parseInt(endSplit[1])
checkEndTime.setHours(endHour)
checkEndTime.setMinutes(endMin)
}
var currentDate = new Date()
if(
(
currentDate >= checkStartTime &&
currentDate <= checkEndTime
) ||
currentDate >= checkStartTime && !end
){
callback()
}else{
callback({
currentDate : currentDate,
startTime : checkStartTime,
endTime : checkEndTime
})
}
}else{
callback()
}
}catch(err){
console.log(err)
callback()
}
}
//check all Schedules
s.checkSchedules = function(v,callback){
var groupKeys = Object.keys(s.schedules)
groupKeys.forEach(function(key){
var scheduleNames = Object.keys(s.schedules[key])
scheduleNames.forEach(function(name){
var schedule = s.schedules[key][name]
if(!schedule.active && schedule.enabled === 1 && schedule.start && schedule.details.monitorStates){
s.checkTimeAgainstSchedule(schedule.start,schedule.end,function(err){
if(!err){
schedule.active = true
var monitorStates = schedule.details.monitorStates
monitorStates.forEach(function(stateName){
s.activateMonitorStates(key,stateName,{
ke: key,
uid: 'System',
details: {},
permissions: {},
lang: lang
},function(endData){
// console.log(endData)
})
})
}else{
schedule.active = false
}
})
}
})
})
}
//
s.findSchedule = function(groupKey,name,callback){
//presetQueryVals = [ke, type, name]
s.sqlQuery("SELECT * FROM Schedules WHERE ke=? AND name=? LIMIT 1",[groupKey,name],function(err,schedules){
var schedule
var notFound = false
if(schedules && schedules[0]){
schedule = schedules[0]
s.checkDetails(schedule)
}else{
notFound = true
}
callback(notFound,schedule)
})
}
//
var onProcessReady = function(){
s.getAllSchedules(function(){
s.checkSchedules()
})
setInterval(function(){
s.checkSchedules()
},1000 * 60 * 5)
}
/**
* WebServerPath : API : Get Schedule
*/
app.all([
config.webPaths.apiPrefix+':auth/schedule/:ke',
config.webPaths.adminApiPrefix+':auth/schedule/:ke',
config.webPaths.apiPrefix+':auth/schedule/:ke/:name',
config.webPaths.adminApiPrefix+':auth/schedule/:ke/:name',
config.webPaths.apiPrefix+':auth/schedules/:ke',
config.webPaths.adminApiPrefix+':auth/schedules/:ke',
config.webPaths.apiPrefix+':auth/schedules/:ke/:name',
config.webPaths.adminApiPrefix+':auth/schedules/:ke/:name',
],function (req,res){
s.auth(req.params,function(user){
var endData = {
ok : false
}
if(user.details.sub){
endData.msg = user.lang['Not Permitted']
s.closeJsonResponse(res,endData)
return
}
var theQuery = "SELECT * FROM Schedules WHERE ke=?"
var theQueryValues = [req.params.ke]
if(req.params.name){
theQuery += ' AND name=?'
theQueryValues.push(req.params.name)
}
s.sqlQuery(theQuery,theQueryValues,function(err,schedules){
if(schedules && schedules[0]){
endData.ok = true
schedules.forEach(function(schedule){
s.checkDetails(schedule)
})
endData.schedules = schedules
}else{
endData.msg = user.lang['Not Found']
}
s.closeJsonResponse(res,endData)
})
})
})
/**
* WebServerPath : API : Update Schedule
*/
app.all([
config.webPaths.apiPrefix+':auth/schedule/:ke/:name/:action',
config.webPaths.adminApiPrefix+':auth/schedule/:ke/:name/:action',
config.webPaths.apiPrefix+':auth/schedules/:ke/:name/:action',
config.webPaths.adminApiPrefix+':auth/schedules/:ke/:name/:action'
],function (req,res){
s.auth(req.params,function(user){
var endData = {
ok : false
}
if(user.details.sub){
endData.msg = user.lang['Not Permitted']
s.closeJsonResponse(res,endData)
return
}
switch(req.params.action){
case'insert':case'edit':
var form = s.getPostData(req)
s.checkDetails(form)
if(!form || !form.details){
endData.msg = user.lang['Form Data Not Found']
s.closeJsonResponse(res,endData)
return
}
form.enabled = parseInt(form.enabled) || 1;
s.findSchedule(req.params.ke,req.params.name,function(notFound,preset){
if(notFound === true){
endData.msg = lang["Inserted Schedule Configuration"]
var insertData = {
ke: req.params.ke,
name: req.params.name,
details: s.stringJSON(form.details),
start: form.start,
end: form.end,
enabled: form.enabled
}
s.sqlQuery('INSERT INTO Schedules ('+Object.keys(insertData).join(',')+') VALUES (?,?,?,?,?,?)',Object.values(insertData))
s.tx({
f: 'add_schedule',
insertData: insertData,
ke: req.params.ke,
name: req.params.name
},'GRP_'+req.params.ke)
}else{
endData.msg = lang["Edited Schedule Configuration"]
var insertData = {
details: s.stringJSON(form.details),
start: form.start,
end: form.end,
enabled: form.enabled,
ke: req.params.ke,
name: req.params.name
}
s.sqlQuery('UPDATE Schedules SET details=?,start=?,end=?,enabled=? WHERE ke=? AND name=?',Object.values(insertData))
s.tx({
f: 'edit_schedule',
insertData: insertData,
ke: req.params.ke,
name: req.params.name
},'GRP_'+req.params.ke)
}
s.updateSchedule({
ke: req.params.ke,
name: req.params.name,
details: s.stringJSON(form.details),
start: form.start,
end: form.end,
enabled: form.enabled
})
endData.ok = true
s.closeJsonResponse(res,endData)
})
break;
case'delete':
s.findSchedule(req.params.ke,req.params.name,function(notFound,schedule){
if(notFound === true){
endData.msg = user.lang['Schedule Configuration Not Found']
s.closeJsonResponse(res,endData)
}else{
s.sqlQuery('DELETE FROM Schedules WHERE ke=? AND name=?',[req.params.ke,req.params.name],function(err){
if(!err){
endData.msg = lang["Deleted Schedule Configuration"]
endData.ok = true
if(s.schedules[schedule.ke])delete(s.schedules[schedule.ke][schedule.name])
}
s.closeJsonResponse(res,endData)
})
}
})
break;
}
})
})
//bind events
s.onProcessReady(onProcessReady)
}

View File

@ -1365,7 +1365,7 @@ module.exports = function(s,config,lang,io){
if(cn.cron){
delete(s.cron);
}
if(cn.ocv){
if(cn.ocv && s.ocv){
s.tx({f:'detector_unplugged',plug:s.ocv.plug},'CPU')
delete(s.ocv);
delete(s.api[cn.id])

View File

@ -10,6 +10,12 @@ module.exports = function(s,config){
if(s.databaseOptions.client.indexOf('sqlite')>-1){
s.databaseOptions.client = 'sqlite3';
s.databaseOptions.useNullAsDefault = true;
try{
require('sqlite3')
}catch(err){
console.log('Installing SQlite3 Module...')
require('child_process').execSync('npm install sqlite3 --unsafe-perm')
}
}
if(s.databaseOptions.client === 'sqlite3' && s.databaseOptions.connection.filename === undefined){
s.databaseOptions.connection.filename = s.mainDirectory+"/shinobi.sqlite"
@ -99,6 +105,10 @@ module.exports = function(s,config){
},true)
}
},true)
//add Schedules table, will remove in future
s.sqlQuery("CREATE TABLE IF NOT EXISTS `Schedules` (`ke` varchar(50) DEFAULT NULL,`name` text,`details` text,`start` varchar(10) DEFAULT NULL,`end` varchar(10) DEFAULT NULL,`enabled` int(1) NOT NULL DEFAULT '1')" + mySQLtail + ';',[],function(err){
if(err)console.error(err)
},true)
//add Cloud Videos table, will remove in future
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Cloud Videos` (`mid` varchar(50) NOT NULL,`ke` varchar(50) DEFAULT NULL,`href` text NOT NULL,`size` float DEFAULT NULL,`time` timestamp NULL DEFAULT NULL,`end` timestamp NULL DEFAULT NULL,`status` int(1) DEFAULT \'0\',`details` text)' + mySQLtail + ';',[],function(err){
if(err)console.error(err)

View File

@ -4,16 +4,33 @@ var moment = require('moment');
var crypto = require('crypto');
var exec = require('child_process').exec;
var execSync = require('child_process').execSync;
module.exports = function(s,config,lang,io,processReady){
module.exports = function(s,config,lang,io,){
console.log('FFmpeg version : '+s.ffmpegVersion)
console.log('Node.js version : '+execSync("node -v"))
s.processReady = function(){
s.systemLog(lang.startUpText5)
process.send('ready')
s.onProcessReadyExtensions.forEach(function(extender){
extender(true)
})
if(processReady)processReady()
process.send('ready')
}
var checkForTerminalCommands = function(callback){
var next = function(){
if(callback)callback()
}
if(!s.isWin){
var etcPath = '/etc/shinobisystems/cctv.txt'
fs.stat(etcPath,function(err,stat){
if(err || !stat){
exec('node '+ s.mainDirectory + '/INSTALL/terminalCommands.js',function(err){
if(err)console.log(err)
})
}
next()
})
}else{
next()
}
}
var loadedAccounts = []
var loadMonitors = function(callback){
@ -151,6 +168,9 @@ module.exports = function(s,config,lang,io,processReady){
})
})
},10000)
//hourly check to see if sizePurge has failed to unlock
//checks to see if request count is the number of monitors + 10
s.checkForStalePurgeLocks()
//run prerequsite queries, load users and monitors
if(config.childNodes.mode !== 'child'){
//sql/database connection with knex
@ -158,11 +178,13 @@ module.exports = function(s,config,lang,io,processReady){
//run prerequsite queries
s.preQueries()
setTimeout(function(){
//load administrators (groups)
loadAdminUsers(function(){
//load monitors (for groups)
loadMonitors(function(){
s.processReady()
checkForTerminalCommands(function(){
//load administrators (groups)
loadAdminUsers(function(){
//load monitors (for groups)
loadMonitors(function(){
s.processReady()
})
})
})
},1500)

View File

@ -15,7 +15,7 @@ module.exports = function(s,config){
if(s.group[e.ke].sizePurgeQueue.length > 0){
checkQueue()
}else{
s.group[e.ke].sizePurging=false
s.group[e.ke].sizePurging = false
s.sendDiskUsedAmountToClients(e)
}
}
@ -260,11 +260,11 @@ module.exports = function(s,config){
d.form.details.use_admin=d.d.use_admin
d.form.details.use_ldap=d.d.use_ldap
//check
if(d.d.edit_days=="0"){
d.form.details.days=d.d.days;
if(d.d.edit_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.edit_size == "0"){
d.form.details.size = d.d.size;
}
if(d.d.sub){
d.form.details.sub=d.d.sub;
@ -308,4 +308,43 @@ module.exports = function(s,config){
}
})
}
s.findPreset = function(presetQueryVals,callback){
//presetQueryVals = [ke, type, name]
s.sqlQuery("SELECT * FROM Presets WHERE ke=? AND type=? AND name=? LIMIT 1",presetQueryVals,function(err,presets){
var preset
var notFound = false
if(presets && presets[0]){
preset = presets[0]
s.checkDetails(preset)
}else{
notFound = true
}
callback(notFound,preset)
})
}
if(config.cron.deleteOverMax === true){
s.checkForStalePurgeLocks = function(){
var doCheck = function(){
Object.keys(s.group).forEach(function(groupKey){
var userGroup = s.group[groupKey]
var monitorCount = 10
if(userGroup.mon)monitorCount = Object.keys(userGroup.mon).length
var purgeRequestCount = userGroup.sizePurgeQueue.length
var isLocked = (userGroup.sizePurging === true)
if(isLocked && purgeRequestCount > monitorCount + 10){
s.group[groupKey].sizePurgeQueue = []
s.group[groupKey].sizePurging = false
s.systemLog(lang.sizePurgeLockedText + ' : ' + groupKey)
}
})
}
clearTimeout(s.checkForStalePurgeLocksInterval)
s.checkForStalePurgeLocksInterval = setInterval(function(){
doCheck()
},1000 * 60 * 60)
doCheck()
}
}else{
s.checkForStalePurgeLocks = function(){}
}
}

View File

@ -419,19 +419,7 @@ module.exports = function(s,config,lang,app){
s.closeJsonResponse(res,endData)
return
}
var findPreset = function(callback){
s.sqlQuery("SELECT * FROM Presets WHERE ke=? AND type=? AND name=? LIMIT 1",[req.params.ke,'monitorStates',req.params.stateName],function(err,presets){
var preset
var notFound = false
if(presets && presets[0]){
preset = presets[0]
s.checkDetails(preset)
}else{
notFound = true
}
callback(notFound,preset)
})
}
var presetQueryVals = [req.params.ke,'monitorStates',req.params.stateName]
switch(req.params.action){
case'insert':case'edit':
var form = s.getPostData(req)
@ -441,7 +429,7 @@ module.exports = function(s,config,lang,app){
s.closeJsonResponse(res,endData)
return
}
findPreset(function(notFound,preset){
s.findPreset(presetQueryVals,function(notFound,preset){
if(notFound === true){
endData.msg = lang["Inserted State Configuration"]
var details = {
@ -478,7 +466,7 @@ module.exports = function(s,config,lang,app){
})
break;
case'delete':
findPreset(function(notFound,preset){
s.findPreset(presetQueryVals,function(notFound,preset){
if(notFound === true){
endData.msg = user.lang['State Configuration Not Found']
s.closeJsonResponse(res,endData)
@ -494,43 +482,8 @@ module.exports = function(s,config,lang,app){
})
break;
default://change monitors according to state
findPreset(function(notFound,preset){
if(notFound === false){
var sqlQuery = 'SELECT * FROM Monitors WHERE ke=? AND '
var monitorQuery = []
var sqlQueryValues = [req.params.ke]
var monitorPresets = {}
preset.details.monitors.forEach(function(monitor){
monitorQuery.push('mid=?')
sqlQueryValues.push(monitor.mid)
monitorPresets[monitor.mid] = monitor
})
sqlQuery += '('+monitorQuery.join(' OR ')+')'
s.sqlQuery(sqlQuery,sqlQueryValues,function(err,monitors){
if(monitors && monitors[0]){
monitors.forEach(function(monitor){
s.checkDetails(monitor)
s.checkDetails(monitorPresets[monitor.mid])
var monitorPreset = monitorPresets[monitor.mid]
monitorPreset.details = Object.assign(monitor.details,monitorPreset.details)
monitor = s.cleanMonitorObjectForDatabase(Object.assign(monitor,monitorPreset))
monitor.details = JSON.stringify(monitor.details)
s.addOrEditMonitor(Object.assign(monitor,{}),function(err,endData){
},user)
})
endData.ok = true
s.tx({f:'change_group_state',ke:req.params.ke,name:req.params.stateName},'GRP_'+req.params.ke)
s.closeJsonResponse(res,endData)
}else{
endData.msg = user.lang['State Configuration has no monitors associated']
s.closeJsonResponse(res,endData)
}
})
}else{
endData.msg = user.lang['State Configuration Not Found']
s.closeJsonResponse(res,endData)
}
s.activateMonitorStates(req.params.ke,req.params.stateName,user,function(endData){
s.closeJsonResponse(res,endData)
})
break;
}

View File

@ -8,6 +8,7 @@ var execSync = require('child_process').execSync;
var exec = require('child_process').exec;
var spawn = require('child_process').spawn;
var httpProxy = require('http-proxy');
var onvif = require('node-onvif');
var proxy = httpProxy.createProxyServer({})
var ejs = require('ejs');
var CircularJSON = require('circular-json');
@ -286,7 +287,8 @@ module.exports = function(s,config,lang,app,io){
// config: config,
$user: req.resp,
lang: r.lang,
define: s.getDefinitonFile(r.details.lang)
define: s.getDefinitonFile(r.details.lang),
customAutoLoad: s.customAutoLoadTree
})
})
break;
@ -297,7 +299,8 @@ module.exports = function(s,config,lang,app,io){
// config: config,
$user: req.resp,
lang: r.lang,
define: s.getDefinitonFile(r.details.lang)
define: s.getDefinitonFile(r.details.lang),
customAutoLoad: s.customAutoLoadTree
})
})
break;
@ -311,17 +314,36 @@ module.exports = function(s,config,lang,app,io){
$subs: rr,
$mons: rrr,
lang: r.lang,
define: s.getDefinitonFile(r.details.lang)
define: s.getDefinitonFile(r.details.lang),
customAutoLoad: s.customAutoLoadTree
})
})
})
}else{
//not admin user
renderPage(config.renderPaths.home,{$user:req.resp,config:config,lang:r.lang,define:s.getDefinitonFile(r.details.lang),addStorage:s.dir.addStorage,fs:fs,__dirname:s.mainDirectory});
renderPage(config.renderPaths.home,{
$user:req.resp,
config:config,
lang:r.lang,
define:s.getDefinitonFile(r.details.lang),
addStorage:s.dir.addStorage,
fs:fs,
__dirname:s.mainDirectory,
customAutoLoad: s.customAutoLoadTree
});
}
break;
default:
renderPage(config.renderPaths.home,{$user:req.resp,config:config,lang:r.lang,define:s.getDefinitonFile(r.details.lang),addStorage:s.dir.addStorage,fs:fs,__dirname:s.mainDirectory});
renderPage(config.renderPaths.home,{
$user:req.resp,
config:config,
lang:r.lang,
define:s.getDefinitonFile(r.details.lang),
addStorage:s.dir.addStorage,
fs:fs,
__dirname:s.mainDirectory,
customAutoLoad: s.customAutoLoadTree
});
break;
}
s.userLog({ke:r.ke,mid:'$USER'},{type:r.lang['New Authentication Token'],msg:{for:req.body.function,mail:r.mail,id:r.uid,ip:req.ip}})
@ -511,6 +533,7 @@ module.exports = function(s,config,lang,app,io){
r=[]
}
data.Logs = r
data.customAutoLoad = s.customAutoLoadTree
fs.readFile(s.location.config,'utf8',function(err,file){
data.plainConfig = JSON.parse(file)
renderPage(config.renderPaths.super,data)
@ -1375,7 +1398,7 @@ module.exports = function(s,config,lang,app,io){
values.push(time)
})
s.sqlQuery('SELECT * FROM Videos WHERE '+where.join(' OR '),values,function(err,r){
var resp = {ok:false}
var resp = {ok: false}
if(r && r[0]){
resp.ok = true
var zipDownload = null
@ -1396,7 +1419,7 @@ module.exports = function(s,config,lang,app,io){
fs.mkdirSync(fileBinDir);
}
r.forEach(function(video){
timeFormatted = s.formattedTime(video.time)
var timeFormatted = s.formattedTime(video.time)
video.filename = timeFormatted+'.'+video.ext
var dir = s.getVideoDirectory(video)+video.filename
var tempVideoFile = timeFormatted+' - '+video.mid+'.'+video.ext
@ -1418,16 +1441,27 @@ module.exports = function(s,config,lang,app,io){
var zipDownload = fs.createReadStream(zippedFile)
zipDownload.pipe(res)
zipDownload.on('error', function (error) {
s.userLog({ke:req.params.ke,mid:'$USER'},{title:'Zip Download Error',msg:error.toString()})
var errorString = error.toString()
s.userLog({
ke: req.params.ke,
mid: '$USER'
},{
title: 'Zip Download Error',
msg: errorString
})
if(zipDownload && zipDownload.destroy){
zipDownload.destroy()
}
});
res.end(s.prettyPrint({
ok: false,
msg: errorString
}))
})
zipDownload.on('close', function () {
res.end()
zipDownload.destroy();
fs.unlinkSync(zippedFile);
});
zipDownload.destroy()
fs.unlinkSync(zippedFile)
})
})
}else{
failed({ok:false,msg:'No Videos Found'})
@ -1437,7 +1471,121 @@ module.exports = function(s,config,lang,app,io){
}else{
failed({ok:false,msg:'"videos" query variable is missing from request.'})
}
});
})
/**
* API : Zip Cloud Videos and Get Link from fileBin
*/
app.get(config.webPaths.apiPrefix+':auth/zipCloudVideos/: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.prettyPrint(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 `Cloud 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_Cloud_Backed_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);
}
var cloudDownloadCount = 0
var getFile = function(video,completed){
if(!video)completed();
s.checkDetails(video)
var filename = video.href.split('/')
filename = filename[filename.length - 1]
var timeFormatted = s.formattedTime(video.time)
var tempVideoFile = video.details.type + '-' + video.mid + '-' + filename
var tempFileWriteStream = fs.createWriteStream(fileBinDir+tempVideoFile)
tempFileWriteStream.on('finish', function() {
++cloudDownloadCount
getFile(r[cloudDownloadCount],completed)
})
var cloudVideoDownload = request(video.href)
cloudVideoDownload.on('response', function (res) {
res.pipe(tempFileWriteStream)
})
tempFiles.push(fileBinDir+tempVideoFile)
script += ' "'+tempVideoFile+'"'
}
getFile(r[cloudDownloadCount],function(){
fs.writeFileSync(tempScript,script,'utf8')
var zipCreate = spawn('sh',(tempScript).split(' '),{detached: true})
zipCreate.stderr.on('data',function(data){
s.userLog({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) {
var errorString = error.toString()
s.userLog({
ke: req.params.ke,
mid: '$USER'
},{
title: 'Zip Download Error',
msg: errorString
})
if(zipDownload && zipDownload.destroy){
zipDownload.destroy()
}
res.end(s.prettyPrint({
ok: false,
msg: errorString
}))
})
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.'})
}
})
/**
* API : Get Cloud Video File (proxy)
*/
@ -1524,27 +1672,34 @@ module.exports = function(s,config,lang,app,io){
/**
* API : Motion Trigger via GET request
*/
app.get(config.webPaths.apiPrefix+':auth/motion/:ke/:id', function (req,res){
s.auth(req.params,function(user){
if(req.query.data){
try{
var d={id:req.params.id,ke:req.params.ke,details:JSON.parse(req.query.data)};
}catch(err){
res.end('Data Broken',err);
return;
}
}else{
res.end('No Data');
return;
}
if(!d.ke||!d.id||!s.group[d.ke]){
res.end(user.lang['No Group with this key exists']);
return;
}
s.triggerEvent(d)
res.end(user.lang['Trigger Successful'])
},res,req);
})
app.get(config.webPaths.apiPrefix+':auth/motion/:ke/:id', function (req,res){
s.auth(req.params,function(user){
var endData = {
}
if(req.query.data){
try{
var d = {
id: req.params.id,
ke: req.params.ke,
details: JSON.parse(req.query.data)
}
}catch(err){
res.end('Data Broken',err)
return
}
}else{
res.end('No Data')
return
}
if(!d.ke||!d.id||!s.group[d.ke]){
res.end(user.lang['No Group with this key exists'])
return
}
s.triggerEvent(d)
res.end(user.lang['Trigger Successful'])
},res,req)
})
/**
* API : WebHook Tester
*/

View File

@ -622,4 +622,16 @@ module.exports = function(s,config,lang,app){
}
},res,req)
})
/**
* API : Superuser : Force Check for Stale Purge Locks
*/
app.all(config.webPaths.superApiPrefix+':auth/system/checkForStalePurgeLocks', function (req,res){
s.superAuth(req.params,function(resp){
var endData = {
ok : true
}
s.checkForStalePurgeLocks()
res.end(s.prettyPrint(endData))
},res,req)
})
}

View File

@ -1,12 +1,12 @@
{
"name": "shinobi",
"productName": "Shinobi",
"version": "1.0.38",
"version": "2.0.0",
"description": "CCTV and NVR in Node.js",
"main": "camera.js",
"bin": "camera.js",
"scripts": {
"test": "node test.js",
"test": "node camera.js test",
"start": "chmod +x INSTALL/start.sh && INSTALL/start.sh"
},
"repository": {
@ -19,30 +19,33 @@
},
"homepage": "https://gitlab.com/Shinobi-Systems/Shinobi#readme",
"dependencies": {
"aws-sdk": "^2.279.1",
"backblaze-b2": "^1.0.4",
"body-parser": "^1.15.2",
"circular-json": "0.3.1",
"connection-tester": "^0.1.1",
"mp4frag": "^0.0.22",
"discord.js": "^11.3.2",
"ejs": "^2.5.5",
"express": "^4.14.0",
"http-proxy": "^1.17.0",
"jsonfile": "^3.0.1",
"moment": "^2.17.0",
"mysql": "^2.12.0",
"knex": "^0.14.2",
"aws-sdk": "^2.279.1",
"pam-diff": "^0.10.2",
"pipe2pam": "^0.6.2",
"nodemailer": "^4.0.1",
"ldapauth-fork": "^4.0.2",
"moment": "^2.17.0",
"mp4frag": "^0.0.22",
"mysql": "^2.12.0",
"node-onvif": "^0.1.4",
"nodemailer": "^4.0.1",
"pam-diff": "^0.10.2",
"path": "^0.12.7",
"pipe2pam": "^0.6.2",
"request": "^2.79.0",
"socket.io": "^1.7.1",
"socket.io-client": "^1.7.2",
"http-proxy": "^1.17.0",
"sqlite3": "^4.0.4",
"webdav-fs": "^1.11.0",
"discord.js": "^11.3.2",
"backblaze-b2": "^1.0.4",
"ldapauth-fork": "^4.0.2"
"sat": "^0.7.1",
"shinobi-sound-detection": "^0.1.7"
},
"devDependencies": {}
}

View File

@ -0,0 +1,53 @@
DIR=`dirname $0`
INSTALLERS_DIR="$DIR/../../INSTALL"
if ! [ -x "$(command -v dos2unix)" ]; then
echo "-----------------------------------"
echo "Installing dos2unix"
apt install dos2unix -y
fi
echo "-----------------------------------"
if ! [ -x "$(command -v alpr)" ]; then
echo "Installing OpenALPR"
echo "Do you want to Install OpenALPR with CUDA enabled?"
echo "(Y)es or (n)o?"
echo "Press [ENTER] for default (Yes)"
read openalprcudaenabled
if [ "$openalprcudaenabled" = "n" ] || [ "$openalprcudaenabled" = "N" ]; then
sed -i -e 's/detector = lbpgpu/detector = lbpcpu/g' "$DIR/openalpr.conf"
dos2unix $INSTALLERS_DIR/openalpr-cpu-easy.sh
sh $INSTALLERS_DIR/openalpr-cpu-easy.sh
else
sed -i -e 's/detector = lbpcpu/detector = lbpgpu/g' "$DIR/openalpr.conf"
dos2unix $INSTALLERS_DIR/openalpr-gpu-easy.sh
sh $INSTALLERS_DIR/openalpr-gpu-easy.sh
fi
else
echo "OpenALPR found... : $(alpr --version)"
fi
echo "-----------------------------------"
if [ ! -e "$DIR/conf.json" ]; then
echo "Creating conf.json"
cp $DIR/conf.sample.json $DIR/conf.json
else
echo "conf.json already exists..."
fi
echo "-----------------------------------"
echo "Installing Modules.."
npm install --unsafe-perm
echo "Finding and Fixing Module Vulnerabilities.."
npm audit fix --force
echo "Shinobi - Do you want to start the plugin?"
echo "(Y)es or (n)o?"
echo "Press [ENTER] for default (Yes)"
read startplugin
if [ "$startplugin" = "n" ] || [ "$startplugin" = "N" ]; then
echo "-----------------------------------"
echo "Start the plugin with pm2 like so :"
echo "pm2 start $DIR/shinobi-openalpr.js"
echo "-----------------------------------"
echo "Start the plugin without pm2 :"
echo "node $DIR/shinobi-openalpr.js"
else
pm2 start shinobi-openalpr.js
pm2 save
fi

View File

@ -1,49 +1,32 @@
# OpenALPR and Motion Detector
# OpenALPR
Install required libraries.
**Ubuntu and Debian only**
**Ubuntu 17.10 and 18.04 only**
```
sudo apt update && sudo apt install libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev build-essential g++ openalpr openalpr-daemon openalpr-utils libopenalpr-dev -y
```
> By default plugins run as a client. `camera.js` is running as the host awaiting a plugin to connect to it. To learn about how to connect a plugin as a Host please review the "Run the plugin as a Host" section at the end of this README.
**Install the Node.js Canvas engine**
1. Go to the plugin's directory and run the installer for OpenALPR. **/home/Shinobi** is the default directory for where Shinobi is installed.
```
cd /home/Shinobi/plugins/openalpr
sh INSTALL.sh
```
```
sudo npm install canvas@1.6
```
Go to the Shinobi directory. **Below is an example.**
2. Then add the plugin key to the **Main Configuration** file, the `conf.json` located in **/home/Shinobi**. You will find the `pluginKeys` object empty on a new install as seen below.
```
"pluginKeys":{}
```
> Add the key so it looks something like this.
```
cd /home/Shinobi
```
```
"pluginKeys":{
"OpenALPR": "SomeOpenALPRkeySoPeopleDontMessWithYourShinobi"
}
```
Copy the config file.
3. Restart Shinobi to apply the Plugin Key. Shinobi does not need to be restarted when a plugin is initiated or stopped after applying changes to the Main Configuration file.
```
cp plugins/openalpr/conf.sample.json plugins/openalpr/conf.json
```
Edit it the new file. Host should be `localhost` and port should match the `listening port for camera.js`.
```
nano plugins/openalpr/conf.json
```
Start the plugin.
```
node plugins/openalpr/shinobi-openalpr.js
```
Or to daemonize with PM2.
```
pm2 start plugins/openalpr/shinobi-openalpr.js
```
Doing this will reveal options in the monitor configuration. Shinobi does not need to be restarted when a plugin is initiated or stopped.
> You should change `SomeOpenALPRkeySoPeopleDontMessWithYourShinobi` to something else in both the main configuration and plugin configuration. Both files changed need to be matching keys of course.
## Run the plugin as a Host
> The main app (Shinobi) will be the client and the plugin will be the host. The purpose of allowing this method is so that you can use one plugin for multiple Shinobi instances. Allowing you to easily manage connections without starting multiple processes.
@ -51,7 +34,7 @@ Doing this will reveal options in the monitor configuration. Shinobi does not ne
Edit your plugins configuration file. Set the `hostPort` **to be different** than the `listening port for camera.js`.
```
nano plugins/openalpr/conf.json
nano conf.json
```
Here is a sample of a Host configuration for the plugin.
@ -70,7 +53,7 @@ Here is a sample of a Host configuration for the plugin.
}
```
Now modify the **main configuration file** located in the main directory of Shinobi. *Where you currently should be.*
Now modify the **Main Configuration** file located in the main directory of Shinobi. *Where you currently should be.*
```
nano conf.json
@ -90,4 +73,4 @@ Add the `plugins` array if you don't already have it. Add the following *object
"type" : "detector"
}
],
```
```

View File

@ -4,7 +4,6 @@
"description": "OpenALPR plugin for Shinobi",
"main": "shinobi-openalpr.js",
"dependencies": {
"canvas": "^1.6.7",
"express": "^4.16.2",
"moment": "^2.19.2",
"socket.io": "^2.0.4"

View File

@ -26,7 +26,9 @@ try{
}
// Base Init />>
// OpenALPR Init >>
if(config.alprConfig===undefined){config.alprConfig=__dirname+'/openalpr.conf'}
if(config.alprConfig === undefined){
config.alprConfig = __dirname + '/openalpr.conf'
}
// OpenALPR Init />>
s.detectObject = function(buffer,d,tx,frameLocation){
var detectStuff = function(frame){

View File

@ -125,6 +125,18 @@ CREATE TABLE IF NOT EXISTS `Files` (
`status` int(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `Files` ADD COLUMN `time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status`;
-- Data exporting was unselected.
-- Dumping structure for table ccio.Schedules
CREATE TABLE IF NOT EXISTS `Schedules` (
`ke` varchar(50) DEFAULT NULL,
`name` text,
`details` text,
`start` varchar(10) DEFAULT NULL,
`end` varchar(10) DEFAULT NULL,
`enabled` int(1) NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Data exporting was unselected.
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;

View File

@ -12,7 +12,7 @@ processArgv.forEach(function(val) {
var theSplit = val.split('=');
var index = theSplit[0];
var value = theSplit[1];
if(index === 'addToConfig'){
if(index.indexOf('addToConfig') > -1){
try{
value = JSON.parse(value)
config = Object.assign(config,value)
@ -36,4 +36,4 @@ processArgv.forEach(function(val) {
jsonfile.writeFile(configLocation,config,{spaces: 2},function(){
console.log('Changes Complete. Here is what it is now.')
console.log(JSON.stringify(config,null,2))
})
})

View File

@ -0,0 +1,89 @@
/*Cusotm Bootstrap*/
.col-5ths,
.col-sm-5ths,
.col-md-5ths,
.col-lg-5ths {
position: relative;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
.col-5ths {
-webkit-box-flex: 0;
-webkit-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
@media (min-width: 576px) {
.col-sm-5ths {
-webkit-box-flex: 0;
-webkit-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
}
@media (min-width: 768px) {
.col-md-5ths {
-webkit-box-flex: 0;
-webkit-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
}
::-webkit-scrollbar-thumb:hover {
background-color:#bd9565;
}
::-webkit-scrollbar-thumb {
background-color:#bd9565;
border: 2px solid transparent;
border-radius: 10px;
background-clip: padding-box;
}
/**/
.flex{display:flex}
.flex>div{flex:1}
.flex-block{display:inline-flex;width:100%;flex-flow: row wrap;}
.flex-unit-3{flex:3}
.flex-inline{display: inline-flex;position:relative}
@import (less) "../less/pie.less";
ul{list-style:none}
*{transition:0.2s;box-sizing:border-box}
.affix-top{position:fixed}
.no-padding{padding:0!important}
.no-margin{margin:0!important}
.pre-inline{white-space: normal;word-break: normal}
.pre-inline>ul{margin:0;padding:0}
a{cursor:pointer}
nav h4{cursor:default;font-size:95%;padding:16px 40px;font-weight:100;text-transform:uppercase;letter-spacing:2px}
.m-r{margin-right:10px}
.m-b{margin-bottom:10px}
.m-t{margin-top:10px}
.m-l{margin-left:10px}
.overflow-hidden{overflow: hidden!important}
.list-inline{list-style:none}
.list-inline li{display:inline-block;vertical-align: top;margin:0;}
.truncate{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
img{max-width:100%}
.display-table{display:table;width:100%}
.display-inline{display:inline-block}
.display-table-cell{display:table-cell}
.small{font-size:80%}
.super-center{position:absolute;left:0;top:0;right:0;bottom:0;margin:auto;width: 4em;height: 1em;}
.permission_monitor_edit{display:none}
.permission_video_delete{display:none}
.nodata .divider{margin:5px 0}
.loading .divider{margin:5px 0}
/* Video Grid */
.video_grid{overflow: auto;height: 100%;display: block;}
.video_grid .col-md-2{padding-left:5px;padding-right:5px;padding-bottom:10px}
.video_grid .thumb{width:100%;height:150px;display:inline-block;background-size:cover;position:relative;overflow:hidden;border-radius:4px;border:1px solid #000;box-shadow:0 0 10px #151515}
.video_grid .thumb .title-strip, .video_grid .thumb .button-strip{width:100%;position:absolute;left:0;background:rgba(0,0,0,0.7);color:#fff;padding:4px}
.video_grid .thumb .title-strip{top:0;opacity:0.5}
.video_grid .thumb .button-strip{bottom:0;opacity:0}
.video_grid .thumb:hover .title-strip, .video_grid .thumb:hover .button-strip{opacity:1}

View File

@ -0,0 +1,44 @@
form.modal-body{margin:0}
.form-group label span{padding:5px;font-weight: 400;color: #2d2d2d;display:block;border-bottom: 1px dotted #ddd;font-size: 10pt;}
.form-group label{display:table}
.form-group label>div{display:table-cell}
.form-group label>div:nth-child(2n-1){width:30%}
.form-group label>div:nth-child(2){width:70%;padding:5px;border:1px solid #dedede;border-radius:5px}
.dark .form-group label>div,.dark .form-group label>div>span{border-color:#454545;color:#fff}
.important.form-group label>div:nth-child(2),.important.form-group label>div>span{border-color:red}
.form-group label span small{margin-left: 2px;display:block;font-weight: 600;}
.form-group-group .round-left{border-radius: 50px 0 0 50px;margin-left:10px}
.form-group-group blockquote:before,.form-group-group blockquote:after{display:none!important}
.form-group-group blockquote{letter-spacing:normal;font-style:normal}
.form-group-group blockquote p:empty{display:none}
.form-group-group blockquote p{font-size:inherit}
.form-group-group blockquote p:last-child{margin-bottom:0}
.form-group-group-group>div,.form-group-group-group .h_us_advanced>div{margin-bottom:15px;}
.form-group-group{padding:0 10px 10px 10px;overflow:hidden;margin-bottom:15px;border-radius:5px;border:1px solid #ddd;background:#fff}
.form-group-group table{width:100%}
.form-group-group table tr td{padding:10px 5px}
.form-group-group table tr:not(:last-child) td{border-bottom:1px dotted #eee}
.form-group-group .mdl-list__item{border-bottom:1px solid #eee;}
.form-group-group .mdl-list__item:hover{background:#e6e6e6;border-radius:4px;}
.dark .form-group-group .mdl-list__item{color:#fff;border-bottom:1px solid #444;}
.dark .form-group-group .mdl-list__item:hover{background:#555;}
.form-group-group:last-child,.form-group-group > .form-group:last-child{margin-bottom:0}
.form-group-group h4{margin:0 -10px 15px -10px;padding:15px;background:#ddd;}
.form-group-group h4 small{color:#fff;}
.form-group-group.red{border-color:#d9534f}
.form-group-group.red h4{background:#d9534f;color:#fff}
.form-group-group.purple{border-color:#3f51b5}
.form-group-group.purple h4{background:#3f51b5;color:#fff}
.form-group-group.blue{border-color:#337ab7}
.form-group-group.blue h4{background:#337ab7;color:#fff}
.form-group-group.navy{border-color:#31708f}
.form-group-group.navy h4{background:#31708f;color:#fff}
.form-group-group.green{border-color:#449d44}
.form-group-group.green h4{background:#449d44;color:#fff}
.form-group-group.forestgreen{border-color:#1e4046}
.form-group-group.forestgreen h4{background:#1e4046;color:#fff}
.form-group-group.orange{border-color:#c49a68}
.form-group-group.orange h4{background:#c49a68;color:#fff}
.form-group-group.grey{border-color:#777}
.form-group-group.grey h4{background:#777;color:#fff}
.dark .form-group-group{background:#222}

View File

View File

@ -0,0 +1,86 @@
.jpegMode .cpu_load .progress-bar,.jpegMode .ram_load .progress-bar{background-color:#5cb85c}
.jpegMode [system="jpegToggle"],[system].text-success{color:#5cb85c!important}
.monitor_item .stream-hud{opacity:0;position:absolute;top:0;left:0;width:100%;height:100%;z-index:2}
.monitor_item .stream-hud .camera_cpu_usage{position:absolute;top:0;left:0;width: 100%;}
.monitor_item .stream-hud .camera_cpu_usage .progress{width: 100%;}
.monitor_item .stream-hud .camera_cpu_usage:hover .progress{height:20px;transition:0.2s}
.monitor_item .stream-hud .controls{position:absolute;top:10px;left:10px;}
.monitor_item .stream-hud:hover{opacity:1}
.monitor_item .stream-hud .bottom-text{position:absolute;bottom:0;left:0;width:70%;padding:5px;text-shadow: 0 0 10px #333;}
.monitor_item .stream-hud:hover .bottom-text{top:0;}
.monitor_item .stream-hud .bottom-text .detector-fade{background: rgba(0,0,0,0.4);padding:10px 20px;border-radius:10px}
.monitor_item .stream-hud .lamp{position:absolute;top:5px;right:5px;z-index:1;text-shadow: 0 0 15px #333;}
.monitor_item[mode="Disabled"] .stream-hud .lamp{color:#5d5d5d}
.monitor_item[mode="Watch Only"] .stream-hud .lamp{color:#5da8e8}
.monitor_item[mode="Idle"] .stream-hud .lamp{color:#fff}
.monitor_item[mode="Record"] .stream-hud .lamp{color:#d9534f}
/*.data-menu{max-height:700px}*/
.data-menu:not(:last-child){border-right:1px solid #fff;}
.data-menu.logs{list-style:none;}
.monitor_item .motionVision{display:none}
.monitor_item .grid-stack-item-content{width:100%!important;left:0!important;right:0!important}
.monitor_item .ui-resizable-se {bottom: 10px!important;}
.monitor_item .stream-block{position: relative;text-align: center}
.monitor_item .mdl-data_window{overflow-x: auto;background:rgba(0,0,0,0.7);color:#fff;height:100%}
.monitor_item .mdl-data_window:not(.col-md-6){width:0;min-width:0;height:0px;min-height:0}
.monitor_item.fullscreen img.stream-element{height:100%;width:auto}
.monitor_item.fullscreen canvas.stream-element{height:auto;width:auto;background-color:black;}
.monitor_item .stream-element{border: 0;object-fit: fill;height: 100%;width:100%}
.monitor_item{position:relative;padding:0;transition:none;background:#000}
.monitor_item .mdl-card{min-height:auto;border:1px solid #272727;border-radius:0px;overflow:hidden}
.monitor_item .mdl-card__media{position:relative;padding:0!important;display:block!important;background:#000;}
.monitor_item.selected .stream-element{height:600px}
.monitor_item.selected .fa-expand:before{content:"\f066"}
.monitor_item .mdl-card__supporting-text{background:#222;color:#fff!important;display:block;min-height:auto!important}
.monitor_item.detector_triggered .detector-fade{opacity:1}
.monitor_item .detector-fade{opacity:0}
.monitor_item .indifference{position:absolute;width:100%;left:0;top:0;transition:0.2s;}
.monitor_item .progress{width:100%;background:#333;box-shadow:0;}
.monitor_item .indifference:hover .progress{height:20px;transition:0.2s}
.hide_indifference .indifference{display:none!important}
.hide_indifference [class_toggle="hide_indifference"]{color:#d9534f!important}
.monitor_item .mdl-card:not(.mdl-cell--4-col-desktop) .mdl-card__supporting-text .monitor_details{display:none;font-size:90%;margin-bottom:10px}
.monitor_item[mode="Record"] [mode="record"]{display:none}
.monitor_item[mode="Watch Only"] [mode="start"]{display:none}
.monitor_item .stream-hud .controls .btn{opacity:0.7}
.monitor_item.doObjectDetection .progress-bar{background-color: #57d94f}
.data-menu{text-align:left}
.data-menu ul,.side-menu ul{list-style:none;margin:0;padding:0;}
.data-menu li,.side-menu li:not(.mdl-menu__item){
border-bottom:1px solid #54502d;padding:10px;
}
.data-menu .progress-circle{margin:0 10px 0 0;position:relative;height:40px;width:40px;float:left}
.data-menu .progress-circle span:after{content:''}
img.circle-img,div.circle-img{border-radius:50%;height:50px;width:50px}
.circle-img.sm{height:25px;width:25px}
@media screen and (max-width:1500px){
.monitor_item .mdl-card__supporting-text .btn{
padding: 5px 10px;
font-size: 11px;
line-height: 1.5;
}
}
#monitors_live .monitor_item [class_toggle="show_logs"]{display:none}
#monitors_live .monitor_item .indifference{top:-5px}
#monitors_live .monitor_item .mdl-cell--8-col{width:100%;border:0;border-radius:0;margin:0;position:relative}
#monitors_live .monitor_item .mdl-cell--4-col-desktop,.monitor_item .mdl-card__supporting-text{display:none}
#monitors_live .monitor_item .mdl-card__supporting-text .monitor_details,#monitors_live .monitor_item .mdl-card__supporting-text .btn-group{display:none;text-align:center}
#monitors_live .monitor_item .mdl-card__supporting-text:not(.meta){display:block;position:absolute;bottom:0;left:0;height:0;padding:0;overflow:visible}
#monitors_live .monitor_item.show_data .mdl-card__supporting-text:not(.meta){width:50%}
#monitors_live .monitor_item.detector_triggered .mdl-card__supporting-text:not(.meta) .indifference{opacity:0.5;}
#monitors_live .monitor_item:hover .mdl-card__supporting-text:not(.meta){padding:15px;z-index:15;height:auto;}
#monitors_live .monitor_item:hover .mdl-card__supporting-text .monitor_details{display:block}
#monitors_live .monitor_item:hover .mdl-card__supporting-text .btn-group{display:inline-block}
.signal.green{background:#5cb85c}
[status="1"] .btn[video="launch"],[data-status="1"] .btn[video="launch"]{background:#337ab7;border-color:#337ab7}
[status="2"] .btn[launch="video"],[status="2"] .btn[video="launch"],[data-status="2"] .btn[video="launch"]{background:#a59100;border-color:#a59100}
.signal.red{background:#c9302c}

View File

@ -0,0 +1,8 @@
#pvideo_viewer iframe{border:0;width:100%;height:350px;margin-bottom:10px;overflow:hidden}
#pvideo_viewer video{max-height:300px;max-width:100%;}
#pvideo_viewer .holder{height:300px;}
#pvideo_viewer h3{margin-top:0}
#pvideo_viewer .progressBar{position:relative;}
#pvideo_viewer .bufferBar{position:absolute;left:0;top:0;opacity:0.4}
#pvideo_viewer .timeBar{position:relative;z-index: 222;background:transparent}
#pvideo_viewer h3{font-family:monospace}

View File

@ -0,0 +1,89 @@
/*Control Pad*/
.PTZ_controls {
z-index: 111;
position: absolute;
left: 20px;
top: 20px;
margin:0;
display: inline-block;
width: 120px;
}
.PTZ_controls .btn-group{margin-top:10px}
.PTZ_controls .pad {
position: relative;
height: 120px;
width: 120px;
background: #b7b7b7;
border-radius: 50%;
box-shadow: inset 0 0 1px rgba(120, 120, 120, 0.6), inset 0 2px 2px rgba(0, 0, 0, 0.1), 0 2px 2px rgba(240, 240, 240, 0.4);
}
.PTZ_controls .control {
position: absolute;
}
.PTZ_controls .pad .control {
height: 30px;
width: 30px;
background: #636363;
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.6), 0 0 0 3px rgba(60, 60, 60, 0.2), 0 0 0 4px rgba(60, 60, 60, 0.2);
border-radius: 2px;
}
.PTZ_controls .zoom_in{
top: 0;
right: 0;
}
.PTZ_controls .zoom_out{
bottom: 0;
right: 0;
}
.PTZ_controls .nv_enabled{
top: 0;
right: 0;
}
.PTZ_controls .nv_disable{
bottom: 0;
right: 0;
}
.PTZ_controls .pad .top {
top: 15px;
left: 50%;
margin: 0 0 0 -15px;
}
.PTZ_controls .pad .left {
top: 45px;
left: 15px;
}
.PTZ_controls .pad .right {
top: 45px;
right: 15px;
}
.PTZ_controls .pad .control.right:before {
transform: rotate(90deg) translate(-3px, -5px);
}
.PTZ_controls .pad .bottom {
bottom: 15px;
left: 50%;
margin: 0 0 0 -15px;
}
/* Overlap the other controls to hide box-shadow */
.PTZ_controls .pad .middle {
height: 34px;
width: 34px;
z-index: 5;
top: 43px;
left: 50%;
margin: 0 0 0 -17px;
box-shadow: none;
border-radius: 3px;
}
.PTZ_controls .pad .middle:after {
position: absolute;
top: 50%;
left: 50%;
margin: -35% 0 0 -35%;
content: '';
background: #636363;
height: 70%;
width: 70%;
border-radius: 100%;
box-shadow: inset 0 0 2px rgba(120, 120, 120, 0.6), inset 0 2px 8px rgba(0, 0, 0, 0.1), 0 2px 2px rgba(240, 240, 240, 0.2);
}

View File

@ -0,0 +1,5 @@
#region_editor .modal-body{text-align:center;overflow:auto;max-height:800px}
#region_editor .canvas_holder{position:relative;display:inline-block;overflow:auto;min-height:450px}
#region_editor .cord_element{position:absolute;background:rgba(221, 221, 221, 0.8);z-index:11;padding:5px;}
#region_editor .cord_element.selected{z-index:12;}
#region_editor .cord_element .controls{margin-bottom:5px;}

View File

@ -0,0 +1,11 @@
.right-to-left {text-align:right}
.right-to-left select{direction: rtl;}
.right-to-left input,.right-to-left textarea{direction: rtl;text-align:right}
.right-to-left .form-group label span{padding-right:10px}
.right-to-left .modal-footer{text-align:left}
.right-to-left .mdl-menu__item>div>*{flex:1}
.right-to-left .mdl-menu__item>div>i{margin-right:0;margin-left:5px}
.right-to-left .mdl-menu__item{text-align:right}
.right-to-left .mdl-menu__item i{float:right}
.right-to-left .pull-right,.right-to-left .close{float:left!important}
.right-to-left .pull-left,.right-to-left .mdl-menu__item span{float:right!important}

View File

@ -0,0 +1,13 @@
#timelapse_video_line{overflow-y:scroll;overflow-x:hidden;max-height:400px;margin:0;text-align:left}
#timelapse_video_display .videoBefore,#timelapse_video_display .videoAfter{display:none}
.timelapse_video:not(:last-child){border-bottom:1px solid #444;}
.timelapse_video .frame{width:50px;height:50px;background-size:cover;background-position:center;border-radius:5px}
.timelapse_video>div>div:not(:last-child){padding-right:10px}
.timelapse_video .flex-block:not(:last-child){padding-bottom:10px}
.timelapse_video.list-group-item{padding:10px}
.timelapse_hud{position: relative;background:#000}
.timelapse_hud .timelapse_playRate{position: absolute;font-family: monospace;top:10px;right:0;left:0;margin:auto;font-size:23px}
#timelapse .progress-bar{transition:0.5s!important}
.timelapse_hud .controlBar{position: absolute;background:rgba(22,22,22,0.8);width:100%;left:0;bottom:0;}
.timelapse_hud .hover-hide{opacity:0}
.timelapse_hud:hover .hover-hide{opacity:1;z-index:5}

View File

@ -1,87 +1,3 @@
/*Cusotm Bootstrap*/
.col-5ths,
.col-sm-5ths,
.col-md-5ths,
.col-lg-5ths {
position: relative;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
.col-5ths {
-webkit-box-flex: 0;
-webkit-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
@media (min-width: 576px) {
.col-sm-5ths {
-webkit-box-flex: 0;
-webkit-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
}
@media (min-width: 768px) {
.col-md-5ths {
-webkit-box-flex: 0;
-webkit-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
}
::-webkit-scrollbar-thumb:hover {
background-color:#bd9565;
}
::-webkit-scrollbar-thumb {
background-color:#bd9565;
border: 2px solid transparent;
border-radius: 10px;
background-clip: padding-box;
}
/**/
.flex{display:flex}
.flex>div{flex:1}
.flex-block{display:inline-flex;width:100%;flex-flow: row wrap;}
.flex-unit-3{flex:3}
.flex-inline{display: inline-flex;position:relative}
@import (less) "../less/pie.less";
ul{list-style:none}
*{transition:0.2s;box-sizing:border-box}
.affix-top{position:fixed}
.no-padding{padding:0!important}
.no-margin{margin:0!important}
.pre-inline{white-space: normal;word-break: normal}
.pre-inline>ul{margin:0;padding:0}
a{cursor:pointer}
nav h4{cursor:default;font-size:95%;padding:16px 40px;font-weight:100;text-transform:uppercase;letter-spacing:2px}
.m-r{margin-right:10px}
.m-b{margin-bottom:10px}
.m-t{margin-top:10px}
.m-l{margin-left:10px}
.overflow-hidden{overflow: hidden!important}
.list-inline{list-style:none}
.list-inline li{display:inline-block;vertical-align: top;margin:0;}
.truncate{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
img{max-width:100%}
.display-table{display:table;width:100%}
.display-inline{display:inline-block}
.display-table-cell{display:table-cell}
.small{font-size:80%}
.super-center{position:absolute;left:0;top:0;right:0;bottom:0;margin:auto;width: 4em;height: 1em;}
.jpegMode .cpu_load .progress-bar,.jpegMode .ram_load .progress-bar{background-color:#5cb85c}
.jpegMode [system="jpegToggle"],[system].text-success{color:#5cb85c!important}
.permission_monitor_edit{display:none}
.permission_video_delete{display:none}
.nodata .divider{margin:5px 0}
.loading .divider{margin:5px 0}
#accbtn{
text-overflow: ellipsis;
white-space: nowrap;
@ -89,75 +5,6 @@ img{max-width:100%}
padding: 0;
}
.monitor_item .stream-hud{opacity:0;position:absolute;top:0;left:0;width:100%;height:100%;z-index:2}
.monitor_item .stream-hud .camera_cpu_usage{position:absolute;top:0;left:0;width: 100%;}
.monitor_item .stream-hud .camera_cpu_usage .progress{width: 100%;}
.monitor_item .stream-hud .camera_cpu_usage:hover .progress{height:20px;transition:0.2s}
.monitor_item .stream-hud .controls{position:absolute;top:10px;left:10px;}
.monitor_item .stream-hud:hover{opacity:1}
.monitor_item .stream-hud .bottom-text{position:absolute;bottom:0;left:0;width:100%;padding:5px;text-shadow: 0 0 10px #333;}
.monitor_item .stream-hud .bottom-text .detector-fade{background: rgba(0,0,0,0.4);padding:10px 20px;border-radius:10px}
.monitor_item .stream-hud .lamp{position:absolute;top:5px;right:5px;z-index:1;text-shadow: 0 0 15px #333;}
.monitor_item[mode="Disabled"] .stream-hud .lamp{color:#5d5d5d}
.monitor_item[mode="Watch Only"] .stream-hud .lamp{color:#5da8e8}
.monitor_item[mode="Idle"] .stream-hud .lamp{color:#fff}
.monitor_item[mode="Record"] .stream-hud .lamp{color:#d9534f}
/*.data-menu{max-height:700px}*/
.data-menu:not(:last-child){border-right:1px solid #fff;}
.data-menu.logs{list-style:none;}
.monitor_item .motionVision{display:none}
.monitor_item .grid-stack-item-content{width:100%!important;left:0!important;right:0!important}
.monitor_item .ui-resizable-se {bottom: 10px!important;}
.monitor_item .stream-block{position: relative;text-align: center}
.monitor_item .mdl-data_window{overflow-x: auto;background:rgba(0,0,0,0.7);color:#fff;height:100%}
.monitor_item .mdl-data_window:not(.col-md-6){width:0;min-width:0;height:0px;min-height:0}
.monitor_item.fullscreen img.stream-element{height:100%;width:auto}
.monitor_item.fullscreen canvas.stream-element{height:auto;width:auto;background-color:black;}
.monitor_item .stream-element{border: 0;object-fit: fill;height: 100%;width:100%}
.monitor_item{position:relative;padding:0;transition:none;background:#000}
.monitor_item .mdl-card{min-height:auto;border:1px solid #272727;border-radius:0px;overflow:hidden}
.monitor_item .mdl-card__media{position:relative;padding:0!important;display:block!important;background:#000;}
.monitor_item.selected .stream-element{height:600px}
.monitor_item.selected .fa-expand:before{content:"\f066"}
.monitor_item .mdl-card__supporting-text{background:#222;color:#fff!important;display:block;min-height:auto!important}
.monitor_item.detector_triggered .detector-fade{opacity:1}
.monitor_item .detector-fade{opacity:0}
.monitor_item .indifference{position:absolute;width:100%;left:0;top:0;transition:0.2s;}
.monitor_item .progress{width:100%;background:#333;box-shadow:0;}
.monitor_item .indifference:hover .progress{height:20px;transition:0.2s}
.hide_indifference .indifference{display:none!important}
.hide_indifference [class_toggle="hide_indifference"]{color:#d9534f!important}
.monitor_item .mdl-card:not(.mdl-cell--4-col-desktop) .mdl-card__supporting-text .monitor_details{display:none;font-size:90%;margin-bottom:10px}
.monitor_item[mode="Record"] [mode="record"]{display:none}
.monitor_item[mode="Watch Only"] [mode="start"]{display:none}
.monitor_item .stream-hud .controls .btn{opacity:0.7}
.monitor_item.doObjectDetection .progress-bar{background-color: #57d94f}
@media screen and (max-width:1500px){
.monitor_item .mdl-card__supporting-text .btn{
padding: 5px 10px;
font-size: 11px;
line-height: 1.5;
}
}
#monitors_live .monitor_item [class_toggle="show_logs"]{display:none}
#monitors_live .monitor_item .indifference{top:-5px}
#monitors_live .monitor_item .mdl-cell--8-col{width:100%;border:0;border-radius:0;margin:0;position:relative}
#monitors_live .monitor_item .mdl-cell--4-col-desktop,.monitor_item .mdl-card__supporting-text{display:none}
#monitors_live .monitor_item .mdl-card__supporting-text .monitor_details,#monitors_live .monitor_item .mdl-card__supporting-text .btn-group{display:none;text-align:center}
#monitors_live .monitor_item .mdl-card__supporting-text:not(.meta){display:block;position:absolute;bottom:0;left:0;height:0;padding:0;}
#monitors_live .monitor_item.show_data .mdl-card__supporting-text:not(.meta){width:50%}
#monitors_live .monitor_item.detector_triggered .mdl-card__supporting-text:not(.meta) .indifference{opacity:0.5;}
#monitors_live .monitor_item:hover .mdl-card__supporting-text:not(.meta){padding:15px;z-index:15;height:auto;}
#monitors_live .monitor_item:hover .mdl-card__supporting-text .monitor_details{display:block}
#monitors_live .monitor_item:hover .mdl-card__supporting-text .btn-group{display:inline-block}
#vis_pwrvideo{height:250px}
#monSectionStreamChannels,#monSectionInputMaps{margin-bottom: 15px;}
#monSectionStreamChannels:empty,#monSectionInputMaps:empty{display:none}
@ -169,19 +16,12 @@ img{max-width:100%}
.demo-blog .demo-blog__posts.montage{max-width:100%}
.mdl-layout__drawer{overflow-y: visible!important}
.hide-side .mdl-layout__drawer{overflow-y: hidden}
.mdl-layout__header-row{padding-left:10!important}
.mdl-layout__header-row .nav>li>a{border-radius:50%;}
.mdl-layout__drawer-button i{position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;height:1em;color:#fff}
.data-menu{text-align:left}
.data-menu ul,.side-menu ul{list-style:none;margin:0;padding:0;}
.data-menu li,.side-menu li{
border-bottom:1px solid #54502d;padding:10px;
}
.data-menu .progress-circle{margin:0 10px 0 0;position:relative;height:40px;width:40px;float:left}
.data-menu .progress-circle span:after{content:''}
img.circle-img,div.circle-img{border-radius:50%;height:50px;width:50px}
.circle-img.sm{height:25px;width:25px}
.video_video{margin:auto;max-width:100%;max-height:600px;}
#confirm_window .video_video{margin-top:15px}
@ -200,60 +40,9 @@ img.circle-img,div.circle-img{border-radius:50%;height:50px;width:50px}
.flex-container-modal-body .flex-block>div{flex:1;float:none}
.modal{overflow:auto!important}
form.modal-body{margin:0}
#region_editor .modal-body{text-align:center;overflow:auto;max-height:800px}
#region_editor .canvas_holder{position:relative;display:inline-block;overflow:auto;min-height:450px}
#region_editor .cord_element{position:absolute;background:rgba(221, 221, 221, 0.8);z-index:11;padding:5px;}
#region_editor .cord_element.selected{z-index:12;}
#region_editor .cord_element .controls{margin-bottom:5px;}
.form-group label span{padding:5px;font-weight: 400;color: #2d2d2d;display:block;border-bottom: 1px dotted #ddd;font-size: 10pt;}
.form-group label{display:table}
.form-group label>div{display:table-cell}
.form-group label>div:nth-child(2n-1){width:30%}
.form-group label>div:nth-child(2){width:70%;padding:5px;border:1px solid #dedede;border-radius:5px}
.dark .form-group label>div,.dark .form-group label>div>span{border-color:#454545;color:#fff}
.important.form-group label>div:nth-child(2),.important.form-group label>div>span{border-color:red}
.form-group label span small{margin-left: 2px;display:block;font-weight: 600;}
.form-group-group .round-left{border-radius: 50px 0 0 50px;margin-left:10px}
.form-group-group blockquote:before,.form-group-group blockquote:after{display:none!important}
.form-group-group blockquote{letter-spacing:normal;font-style:normal}
.form-group-group blockquote p:empty{display:none}
.form-group-group blockquote p{font-size:inherit}
.form-group-group blockquote p:last-child{margin-bottom:0}
.form-group-group-group>div,.form-group-group-group .h_us_advanced>div{margin-bottom:15px;}
.form-group-group{padding:0 10px 10px 10px;overflow:hidden;margin-bottom:15px;border-radius:5px;border:1px solid #ddd;background:#fff}
.form-group-group table{width:100%}
.form-group-group table tr td{padding:10px 5px}
.form-group-group table tr:not(:last-child) td{border-bottom:1px dotted #eee}
.form-group-group .mdl-list__item{border-bottom:1px solid #eee;}
.form-group-group .mdl-list__item:hover{background:#e6e6e6;border-radius:4px;}
.dark .form-group-group .mdl-list__item{color:#fff;border-bottom:1px solid #444;}
.dark .form-group-group .mdl-list__item:hover{background:#555;}
.form-group-group:last-child,.form-group-group > .form-group:last-child{margin-bottom:0}
.form-group-group h4{margin:0 -10px 15px -10px;padding:15px;background:#ddd;}
.form-group-group h4 small{color:#fff;}
.form-group-group.red{border-color:#d9534f}
.form-group-group.red h4{background:#d9534f;color:#fff}
.form-group-group.purple{border-color:#3f51b5}
.form-group-group.purple h4{background:#3f51b5;color:#fff}
.form-group-group.blue{border-color:#337ab7}
.form-group-group.blue h4{background:#337ab7;color:#fff}
.form-group-group.navy{border-color:#31708f}
.form-group-group.navy h4{background:#31708f;color:#fff}
.form-group-group.green{border-color:#449d44}
.form-group-group.green h4{background:#449d44;color:#fff}
.form-group-group.forestgreen{border-color:#1e4046}
.form-group-group.forestgreen h4{background:#1e4046;color:#fff}
.form-group-group.orange{border-color:#c49a68}
.form-group-group.orange h4{background:#c49a68;color:#fff}
.form-group-group.grey{border-color:#777}
.form-group-group.grey h4{background:#777;color:#fff}
.dark .form-group-group{background:#222}
.videos_list .title{font-size:12pt;padding:0 10px}
[status="1"] .btn[video="launch"],[data-status="1"] .btn[video="launch"]{background:#337ab7;border-color:#337ab7}
[status="2"] .btn[launch="video"],[status="2"] .btn[video="launch"],[data-status="2"] .btn[video="launch"]{background:#a59100;border-color:#a59100}
.signal.red{background:#c9302c}
.signal.green{background:#5cb85c}
.demo-drawer{background:#2b2a2a;color:#fff;}
.demo-drawer.mdl-layout__drawer .mdl-navigation{padding-top:0;}
.demo-drawer::-webkit-scrollbar{display:none;}
@ -285,6 +74,8 @@ form.modal-body{margin:0}
.nav-xs.side-menu.list-blocks .monitor_block img{width:40px;height:40px;}
.side-menu.list-blocks .monitor_block .box{width:calc(100% - 70px);display:inline-block}
.nav-xs.side-menu.list-blocks .monitor_block .list-data{display:none}
.side-menu .mdl-menu{z-index: 12}
#monitors_list .monitor_block{transition:none}
.dropdown-menu.scrollable{max-height:300px}
.upload_file input{display:none}
@ -306,39 +97,11 @@ form.modal-body{margin:0}
.form-group label{width:100%}
#pvideo_viewer iframe{border:0;width:100%;height:350px;margin-bottom:10px;overflow:hidden}
#pvideo_viewer video{max-height:300px;max-width:100%;}
#pvideo_viewer .holder{height:300px;}
#pvideo_viewer h3{margin-top:0}
#pvideo_viewer .progressBar{position:relative;}
#pvideo_viewer .bufferBar{position:absolute;left:0;top:0;opacity:0.4}
#pvideo_viewer .timeBar{position:relative;z-index: 222;background:transparent}
#pvideo_viewer h3{font-family:monospace}
#vis_monitors{overflow:auto;max-height:400px}
#vis_monitors .btn-group-vertical{width:100%}
/*timeline*/
#timelapse_video_line{overflow-y:scroll;overflow-x:hidden;max-height:400px;margin:0;text-align:left}
#timelapse_video_display .videoBefore,#timelapse_video_display .videoAfter{display:none}
.timelapse_video:not(:last-child){border-bottom:1px solid #444;}
.timelapse_video .frame{width:50px;height:50px;background-size:cover;background-position:center;border-radius:5px}
.timelapse_video>div>div:not(:last-child){padding-right:10px}
.timelapse_video .flex-block:not(:last-child){padding-bottom:10px}
.timelapse_video.list-group-item{padding:10px}
.timelapse_hud{position: relative;background:#000}
.timelapse_hud .timelapse_playRate{position: absolute;font-family: monospace;top:10px;right:0;left:0;margin:auto;font-size:23px}
#timelapse .progress-bar{transition:0.5s!important}
.timelapse_hud .controlBar{position: absolute;background:rgba(22,22,22,0.8);width:100%;left:0;bottom:0;}
.timelapse_hud .hover-hide{opacity:0}
.timelapse_hud:hover .hover-hide{opacity:1;z-index:5}
.video_grid{overflow: auto;height: 100%;display: block;}
.video_grid .col-md-2{padding-left:5px;padding-right:5px;padding-bottom:10px}
.video_grid .thumb{width:100%;height:150px;display:inline-block;background-size:cover;position:relative;overflow:hidden;border-radius:4px;border:1px solid #000;box-shadow:0 0 10px #151515}
.video_grid .thumb .title-strip, .video_grid .thumb .button-strip{width:100%;position:absolute;left:0;background:rgba(0,0,0,0.7);color:#fff;padding:4px}
.video_grid .thumb .title-strip{top:0;opacity:0.5}
.video_grid .thumb .button-strip{bottom:0;opacity:0}
.video_grid .thumb:hover .title-strip, .video_grid .thumb:hover .button-strip{opacity:1}
.table-striped>tbody>tr>td{vertical-align:middle}
.table-striped .thumbnail{width:100px;height:80px;border-radius:5px;margin:0;display:inline-block;}
@ -352,13 +115,6 @@ form.modal-body{margin:0}
background-color: #c49a68;
border-color: #c49a68;
}
.dark.modal .modal-header,.dark.modal .modal-footer{background:#333;border-color:#444;}
.dark.modal .modal-header{color:#fff;}
.dark.modal .modal-footer>*:not(.btn){color:#fff;}
.dark.modal .modal-body{background:#333;}
.dark.modal .close{color:#fff;}
.dark.modal{color:#fff;}
.dark .table-striped>tbody>tr:nth-of-type(even){background:#616161}
.dark .table-striped>tbody>tr>td{border-color:#222;color:#fff}
.dark .table-striped>thead>tr>th{border-color:#222;color:#fff;background:#616161;vertical-align:middle;}
@ -481,95 +237,10 @@ ul.msg_list li .message {
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__header{
margin-left: 0px;width:100%;transition:0.2s
}
/*Control Pad*/
.PTZ_controls {
z-index: 111;
position: absolute;
left: 20px;
top: 20px;
margin:0;
display: inline-block;
width: 120px;
}
.PTZ_controls .btn-group{margin-top:10px}
.PTZ_controls .pad {
position: relative;
height: 120px;
width: 120px;
background: #b7b7b7;
border-radius: 50%;
box-shadow: inset 0 0 1px rgba(120, 120, 120, 0.6), inset 0 2px 2px rgba(0, 0, 0, 0.1), 0 2px 2px rgba(240, 240, 240, 0.4);
}
.PTZ_controls .control {
position: absolute;
}
.PTZ_controls .pad .control {
height: 30px;
width: 30px;
background: #636363;
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.6), 0 0 0 3px rgba(60, 60, 60, 0.2), 0 0 0 4px rgba(60, 60, 60, 0.2);
border-radius: 2px;
}
.PTZ_controls .zoom_in{
top: 0;
right: 0;
}
.PTZ_controls .zoom_out{
bottom: 0;
right: 0;
}
.PTZ_controls .nv_enabled{
top: 0;
right: 0;
}
.PTZ_controls .nv_disable{
bottom: 0;
right: 0;
}
.PTZ_controls .pad .top {
top: 15px;
left: 50%;
margin: 0 0 0 -15px;
}
.PTZ_controls .pad .left {
top: 45px;
left: 15px;
}
.PTZ_controls .pad .right {
top: 45px;
right: 15px;
}
.PTZ_controls .pad .control.right:before {
transform: rotate(90deg) translate(-3px, -5px);
}
.PTZ_controls .pad .bottom {
bottom: 15px;
left: 50%;
margin: 0 0 0 -15px;
}
/* Overlap the other controls to hide box-shadow */
.PTZ_controls .pad .middle {
height: 34px;
width: 34px;
z-index: 5;
top: 43px;
left: 50%;
margin: 0 0 0 -17px;
box-shadow: none;
border-radius: 3px;
}
.PTZ_controls .pad .middle:after {
position: absolute;
top: 50%;
left: 50%;
margin: -35% 0 0 -35%;
content: '';
background: #636363;
height: 70%;
width: 70%;
border-radius: 100%;
box-shadow: inset 0 0 2px rgba(120, 120, 120, 0.6), inset 0 2px 8px rgba(0, 0, 0, 0.1), 0 2px 2px rgba(240, 240, 240, 0.2);
}
.mdl-menu__item>div{display:flex;align-items: center;width:100%}
.mdl-menu__item>div>i{margin-right:5px}
/*Digital Zoom*/
.stream-block{
position: relative;
@ -663,20 +334,7 @@ ul.msg_list li .message {
-moz-animation: blink 1s linear infinite;
animation: blink 1s linear infinite;
}
.mdl-menu__item>div{display:flex;align-items: center;width:100%}
.mdl-menu__item>div>i{margin-right:5px}
/*For languages that are right to left*/
.right-to-left {text-align:right}
.right-to-left select{direction: rtl;}
.right-to-left input,.right-to-left textarea{direction: rtl;text-align:right}
.right-to-left .form-group label span{padding-right:10px}
.right-to-left .modal-footer{text-align:left}
.right-to-left .mdl-menu__item>div>*{flex:1}
.right-to-left .mdl-menu__item>div>i{margin-right:0;margin-left:5px}
.right-to-left .mdl-menu__item{text-align:right}
.right-to-left .mdl-menu__item i{float:right}
.right-to-left .pull-right,.right-to-left .close{float:left!important}
.right-to-left .pull-left,.right-to-left .mdl-menu__item span{float:right!important}
/* All-CSS Toggle Switch (Checkbox Hack) by Marcus Burnette - https://codepen.io/mburnette/pen/LxNxNg */
.marc-toggle {
width: 50px;

View File

@ -0,0 +1,742 @@
/*Cusotm Bootstrap*/
.col-5ths,
.col-sm-5ths,
.col-md-5ths,
.col-lg-5ths {
position: relative;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
.col-5ths {
-webkit-box-flex: 0;
-webkit-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
@media (min-width: 576px) {
.col-sm-5ths {
-webkit-box-flex: 0;
-webkit-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
}
@media (min-width: 768px) {
.col-md-5ths {
-webkit-box-flex: 0;
-webkit-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
}
::-webkit-scrollbar-thumb:hover {
background-color:#bd9565;
}
::-webkit-scrollbar-thumb {
background-color:#bd9565;
border: 2px solid transparent;
border-radius: 10px;
background-clip: padding-box;
}
/**/
.flex{display:flex}
.flex>div{flex:1}
.flex-block{display:inline-flex;width:100%;flex-flow: row wrap;}
.flex-unit-3{flex:3}
.flex-inline{display: inline-flex;position:relative}
@import (less) "../less/pie.less";
ul{list-style:none}
*{transition:0.2s;box-sizing:border-box}
.affix-top{position:fixed}
.no-padding{padding:0!important}
.no-margin{margin:0!important}
.pre-inline{white-space: normal;word-break: normal}
.pre-inline>ul{margin:0;padding:0}
a{cursor:pointer}
nav h4{cursor:default;font-size:95%;padding:16px 40px;font-weight:100;text-transform:uppercase;letter-spacing:2px}
.m-r{margin-right:10px}
.m-b{margin-bottom:10px}
.m-t{margin-top:10px}
.m-l{margin-left:10px}
.overflow-hidden{overflow: hidden!important}
.list-inline{list-style:none}
.list-inline li{display:inline-block;vertical-align: top;margin:0;}
.truncate{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
img{max-width:100%}
.display-table{display:table;width:100%}
.display-inline{display:inline-block}
.display-table-cell{display:table-cell}
.small{font-size:80%}
.super-center{position:absolute;left:0;top:0;right:0;bottom:0;margin:auto;width: 4em;height: 1em;}
.jpegMode .cpu_load .progress-bar,.jpegMode .ram_load .progress-bar{background-color:#5cb85c}
.jpegMode [system="jpegToggle"],[system].text-success{color:#5cb85c!important}
.permission_monitor_edit{display:none}
.permission_video_delete{display:none}
.nodata .divider{margin:5px 0}
.loading .divider{margin:5px 0}
#accbtn{
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
padding: 0;
}
.monitor_item .stream-hud{opacity:0;position:absolute;top:0;left:0;width:100%;height:100%;z-index:2}
.monitor_item .stream-hud .camera_cpu_usage{position:absolute;top:0;left:0;width: 100%;}
.monitor_item .stream-hud .camera_cpu_usage .progress{width: 100%;}
.monitor_item .stream-hud .camera_cpu_usage:hover .progress{height:20px;transition:0.2s}
.monitor_item .stream-hud .controls{position:absolute;top:10px;left:10px;}
.monitor_item .stream-hud:hover{opacity:1}
.monitor_item .stream-hud .bottom-text{position:absolute;bottom:0;left:0;width:100%;padding:5px;text-shadow: 0 0 10px #333;}
.monitor_item .stream-hud .bottom-text .detector-fade{background: rgba(0,0,0,0.4);padding:10px 20px;border-radius:10px}
.monitor_item .stream-hud .lamp{position:absolute;top:5px;right:5px;z-index:1;text-shadow: 0 0 15px #333;}
.monitor_item[mode="Disabled"] .stream-hud .lamp{color:#5d5d5d}
.monitor_item[mode="Watch Only"] .stream-hud .lamp{color:#5da8e8}
.monitor_item[mode="Idle"] .stream-hud .lamp{color:#fff}
.monitor_item[mode="Record"] .stream-hud .lamp{color:#d9534f}
/*.data-menu{max-height:700px}*/
.data-menu:not(:last-child){border-right:1px solid #fff;}
.data-menu.logs{list-style:none;}
.monitor_item .motionVision{display:none}
.monitor_item .grid-stack-item-content{width:100%!important;left:0!important;right:0!important}
.monitor_item .ui-resizable-se {bottom: 10px!important;}
.monitor_item .stream-block{position: relative;text-align: center}
.monitor_item .mdl-data_window{overflow-x: auto;background:rgba(0,0,0,0.7);color:#fff;height:100%}
.monitor_item .mdl-data_window:not(.col-md-6){width:0;min-width:0;height:0px;min-height:0}
.monitor_item.fullscreen img.stream-element{height:100%;width:auto}
.monitor_item.fullscreen canvas.stream-element{height:auto;width:auto;background-color:black;}
.monitor_item .stream-element{border: 0;object-fit: fill;height: 100%;width:100%}
.monitor_item{position:relative;padding:0;transition:none;background:#000}
.monitor_item .mdl-card{min-height:auto;border:1px solid #272727;border-radius:0px;overflow:hidden}
.monitor_item .mdl-card__media{position:relative;padding:0!important;display:block!important;background:#000;}
.monitor_item.selected .stream-element{height:600px}
.monitor_item.selected .fa-expand:before{content:"\f066"}
.monitor_item .mdl-card__supporting-text{background:#222;color:#fff!important;display:block;min-height:auto!important}
.monitor_item.detector_triggered .detector-fade{opacity:1}
.monitor_item .detector-fade{opacity:0}
.monitor_item .indifference{position:absolute;width:100%;left:0;top:0;transition:0.2s;}
.monitor_item .progress{width:100%;background:#333;box-shadow:0;}
.monitor_item .indifference:hover .progress{height:20px;transition:0.2s}
.hide_indifference .indifference{display:none!important}
.hide_indifference [class_toggle="hide_indifference"]{color:#d9534f!important}
.monitor_item .mdl-card:not(.mdl-cell--4-col-desktop) .mdl-card__supporting-text .monitor_details{display:none;font-size:90%;margin-bottom:10px}
.monitor_item[mode="Record"] [mode="record"]{display:none}
.monitor_item[mode="Watch Only"] [mode="start"]{display:none}
.monitor_item .stream-hud .controls .btn{opacity:0.7}
.monitor_item.doObjectDetection .progress-bar{background-color: #57d94f}
@media screen and (max-width:1500px){
.monitor_item .mdl-card__supporting-text .btn{
padding: 5px 10px;
font-size: 11px;
line-height: 1.5;
}
}
#monitors_live .monitor_item [class_toggle="show_logs"]{display:none}
#monitors_live .monitor_item .indifference{top:-5px}
#monitors_live .monitor_item .mdl-cell--8-col{width:100%;border:0;border-radius:0;margin:0;position:relative}
#monitors_live .monitor_item .mdl-cell--4-col-desktop,.monitor_item .mdl-card__supporting-text{display:none}
#monitors_live .monitor_item .mdl-card__supporting-text .monitor_details,#monitors_live .monitor_item .mdl-card__supporting-text .btn-group{display:none;text-align:center}
#monitors_live .monitor_item .mdl-card__supporting-text:not(.meta){display:block;position:absolute;bottom:0;left:0;height:0;padding:0;overflow:visible;}
#monitors_live .monitor_item.show_data .mdl-card__supporting-text:not(.meta){width:50%}
#monitors_live .monitor_item.detector_triggered .mdl-card__supporting-text:not(.meta) .indifference{opacity:0.5;}
#monitors_live .monitor_item:hover .mdl-card__supporting-text:not(.meta){padding:15px;z-index:15;height:auto;}
#monitors_live .monitor_item:hover .mdl-card__supporting-text .monitor_details{display:block}
#monitors_live .monitor_item:hover .mdl-card__supporting-text .btn-group{display:inline-block}
#vis_pwrvideo{height:250px}
#monSectionStreamChannels,#monSectionInputMaps{margin-bottom: 15px;}
#monSectionStreamChannels:empty,#monSectionInputMaps:empty{display:none}
#region_editor_live iframe,.canvas_holder canvas{border:0;position:absolute;left:0;top:0}
.canvas_holder canvas{z-index:11}
.demo-blog .mdl-card__media ~ .mdl-card__supporting-text{position:relative;overflow:initial;cursor:move}
.demo-blog .mdl-card__media ~ .mdl-card__supporting-text .btn-group{cursor: default}
.demo-blog .demo-blog__posts.montage{max-width:100%}
.mdl-layout__header-row{padding-left:10!important}
.mdl-layout__header-row .nav>li>a{border-radius:50%;}
.mdl-layout__drawer-button i{position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;height:1em;color:#fff}
.data-menu{text-align:left}
.data-menu ul,.side-menu ul{list-style:none;margin:0;padding:0;}
.data-menu li,.side-menu li{
border-bottom:1px solid #54502d;padding:10px;
}
.data-menu .progress-circle{margin:0 10px 0 0;position:relative;height:40px;width:40px;float:left}
.data-menu .progress-circle span:after{content:''}
img.circle-img,div.circle-img{border-radius:50%;height:50px;width:50px}
.circle-img.sm{height:25px;width:25px}
.video_video{margin:auto;max-width:100%;max-height:600px;}
#confirm_window .video_video{margin-top:15px}
#confirm_window .info-table{margin-top:15px}
@media (max-width: 768px){
.full.modal .modal-body,.medium.modal .modal-body{max-height:400px;overflow:auto}
}
@media (min-width: 768px){
.modal.full,.modal.medium{padding-left:0!important;}
.modal.full .modal-dialog{width:calc(100% - 10px)!important;margin: 30px auto;}
.modal.medium .modal-dialog{width:calc(70% - 10px)!important;margin: 30px auto;}
.full.modal .modal-body,.medium.modal .modal-body{height:calc(100% - 200px);overflow:auto}
}
.flex-container-modal-body{overflow: auto}
.flex-container-modal-body .flex-block>div{flex:1;float:none}
.modal{overflow:auto!important}
form.modal-body{margin:0}
#region_editor .modal-body{text-align:center;overflow:auto;max-height:800px}
#region_editor .canvas_holder{position:relative;display:inline-block;overflow:auto;min-height:450px}
#region_editor .cord_element{position:absolute;background:rgba(221, 221, 221, 0.8);z-index:11;padding:5px;}
#region_editor .cord_element.selected{z-index:12;}
#region_editor .cord_element .controls{margin-bottom:5px;}
.form-group label span{padding:5px;font-weight: 400;color: #2d2d2d;display:block;border-bottom: 1px dotted #ddd;font-size: 10pt;}
.form-group label{display:table}
.form-group label>div{display:table-cell}
.form-group label>div:nth-child(2n-1){width:30%}
.form-group label>div:nth-child(2){width:70%;padding:5px;border:1px solid #dedede;border-radius:5px}
.dark .form-group label>div,.dark .form-group label>div>span{border-color:#454545;color:#fff}
.important.form-group label>div:nth-child(2),.important.form-group label>div>span{border-color:red}
.form-group label span small{margin-left: 2px;display:block;font-weight: 600;}
.form-group-group .round-left{border-radius: 50px 0 0 50px;margin-left:10px}
.form-group-group blockquote:before,.form-group-group blockquote:after{display:none!important}
.form-group-group blockquote{letter-spacing:normal;font-style:normal}
.form-group-group blockquote p:empty{display:none}
.form-group-group blockquote p{font-size:inherit}
.form-group-group blockquote p:last-child{margin-bottom:0}
.form-group-group-group>div,.form-group-group-group .h_us_advanced>div{margin-bottom:15px;}
.form-group-group{padding:0 10px 10px 10px;overflow:hidden;margin-bottom:15px;border-radius:5px;border:1px solid #ddd;background:#fff}
.form-group-group table{width:100%}
.form-group-group table tr td{padding:10px 5px}
.form-group-group table tr:not(:last-child) td{border-bottom:1px dotted #eee}
.form-group-group .mdl-list__item{border-bottom:1px solid #eee;}
.form-group-group .mdl-list__item:hover{background:#e6e6e6;border-radius:4px;}
.dark .form-group-group .mdl-list__item{color:#fff;border-bottom:1px solid #444;}
.dark .form-group-group .mdl-list__item:hover{background:#555;}
.form-group-group:last-child,.form-group-group > .form-group:last-child{margin-bottom:0}
.form-group-group h4{margin:0 -10px 15px -10px;padding:15px;background:#ddd;}
.form-group-group h4 small{color:#fff;}
.form-group-group.red{border-color:#d9534f}
.form-group-group.red h4{background:#d9534f;color:#fff}
.form-group-group.purple{border-color:#3f51b5}
.form-group-group.purple h4{background:#3f51b5;color:#fff}
.form-group-group.blue{border-color:#337ab7}
.form-group-group.blue h4{background:#337ab7;color:#fff}
.form-group-group.navy{border-color:#31708f}
.form-group-group.navy h4{background:#31708f;color:#fff}
.form-group-group.green{border-color:#449d44}
.form-group-group.green h4{background:#449d44;color:#fff}
.form-group-group.forestgreen{border-color:#1e4046}
.form-group-group.forestgreen h4{background:#1e4046;color:#fff}
.form-group-group.orange{border-color:#c49a68}
.form-group-group.orange h4{background:#c49a68;color:#fff}
.form-group-group.grey{border-color:#777}
.form-group-group.grey h4{background:#777;color:#fff}
.dark .form-group-group{background:#222}
.videos_list .title{font-size:12pt;padding:0 10px}
[status="1"] .btn[video="launch"],[data-status="1"] .btn[video="launch"]{background:#337ab7;border-color:#337ab7}
[status="2"] .btn[launch="video"],[status="2"] .btn[video="launch"],[data-status="2"] .btn[video="launch"]{background:#a59100;border-color:#a59100}
.signal.red{background:#c9302c}
.signal.green{background:#5cb85c}
.demo-drawer{background:#2b2a2a;color:#fff;}
.demo-drawer.mdl-layout__drawer .mdl-navigation{padding-top:0;}
.demo-drawer::-webkit-scrollbar{display:none;}
.small-square-img{height:40px;width:40px;border-radius:5px}
.side-menu .monitor_block{padding:0;position:relative}
.side-menu .monitor_block img{width:100%;height:75px;cursor:pointer;border: 0.5px inset #263238;}
@media screen and (max-width:1025px){
.side-menu .monitor_block img{height:175px;}
}
.side-menu .monitor_block:hover .icons{opacity:1}
.side-menu .monitor_block:hover .title{opacity:1}
.side-menu .monitor_block .icons,.side-menu .monitor_block .title{opacity:0;width:100%;bottom:0;left:0;background:rgba(0,0,0,0.6);position:absolute;padding:2.5px;z-index:11;cursor:move}
.side-menu .monitor_block .title{bottom:auto;top:0;color:#fff}
.nav-xs.side-menu .monitor_block{width:100%}
.side-menu .monitor_block .list-data{display:none}
.output_data:empty{display:none}
.output_data{max-height:500px;font-family:monospace;padding:10px;border-radius:5px;background:#f3f3f3;overflow:auto}
.dark .output_data{background:#222;}
#probe .output_data div>div{margin-left:10px}
.side-menu.list-blocks .monitor_block .icons,.side-menu.list-blocks .monitor_block .title{position:inherit;opacity:1;background:none}
.side-menu.list-blocks .monitor_block .title{padding:5px;border-radius:5px;background:#222;}
.side-menu.list-blocks .monitor_block:not(:last-child){border-bottom: 1px solid #54502d;}
.side-menu.list-blocks .monitor_block:first-child{border-top: 1px solid #54502d;}
.side-menu.list-blocks .monitor_block{float:none;width:100%;padding: 10px}
.side-menu.list-blocks .monitor_block.ui-sortable-helper{background:rgba(0,0,0,0.6);border-radius:5px;padding:5px;border:0}
.side-menu.list-blocks .monitor_block .list-data{display:block}
.side-menu.list-blocks .monitor_block img{width:60px;height:60px;cursor:pointer;display:inline-block;margin-right:10px;border-radius:50%;vertical-align:top;border:0}
.nav-xs.side-menu.list-blocks .monitor_block img{width:40px;height:40px;}
.side-menu.list-blocks .monitor_block .box{width:calc(100% - 70px);display:inline-block}
.nav-xs.side-menu.list-blocks .monitor_block .list-data{display:none}
#monitors_list .monitor_block{transition:none}
.dropdown-menu.scrollable{max-height:300px}
.upload_file input{display:none}
#video_preview .stream-objects{right:0;margin:auto;display:inline-block;position:relative;width:auto}
.stream-block,.stream-objects{overflow: hidden!important}
.stream-objects{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}
.stream-objects .tag{position:absolute;bottom:100%;left:0;background:red;color:#fff;font-family:monospace;font-size:80%;border-radius:5px 5px 0 0 ;padding:3px 5px;}
.stream-objects .stream-detected-object{position:absolute;top:0;left:0;border:3px solid red;background:transparent;border-radius:5px}
.stream-objects .stream-detected-point{position:absolute;top:0;left:0;border:3px solid yellow;background:transparent;border-radius:5px}
.stream-objects .point{position:absolute;top:0;left:0;border:3px solid red;border-radius:50%}
#side_menu_right.nav-xs{width:0!important;overflow:hidden}
.side-menu table{color:#fff;}
#main_canvas{background:#333;color:#fff;padding-top:0}
#main_header{background:#222;color:#fff;}
#logs_modal table tr td:first-child{width:10%}
[class_toggle]{cursor:pointer}
.form-group label{width:100%}
#pvideo_viewer iframe{border:0;width:100%;height:350px;margin-bottom:10px;overflow:hidden}
#pvideo_viewer video{max-height:300px;max-width:100%;}
#pvideo_viewer .holder{height:300px;}
#pvideo_viewer h3{margin-top:0}
#pvideo_viewer .progressBar{position:relative;}
#pvideo_viewer .bufferBar{position:absolute;left:0;top:0;opacity:0.4}
#pvideo_viewer .timeBar{position:relative;z-index: 222;background:transparent}
#pvideo_viewer h3{font-family:monospace}
#vis_monitors{overflow:auto;max-height:400px}
#vis_monitors .btn-group-vertical{width:100%}
/*timeline*/
#timelapse_video_line{overflow-y:scroll;overflow-x:hidden;max-height:400px;margin:0;text-align:left}
#timelapse_video_display .videoBefore,#timelapse_video_display .videoAfter{display:none}
.timelapse_video:not(:last-child){border-bottom:1px solid #444;}
.timelapse_video .frame{width:50px;height:50px;background-size:cover;background-position:center;border-radius:5px}
.timelapse_video>div>div:not(:last-child){padding-right:10px}
.timelapse_video .flex-block:not(:last-child){padding-bottom:10px}
.timelapse_video.list-group-item{padding:10px}
.timelapse_hud{position: relative;background:#000}
.timelapse_hud .timelapse_playRate{position: absolute;font-family: monospace;top:10px;right:0;left:0;margin:auto;font-size:23px}
#timelapse .progress-bar{transition:0.5s!important}
.timelapse_hud .controlBar{position: absolute;background:rgba(22,22,22,0.8);width:100%;left:0;bottom:0;}
.timelapse_hud .hover-hide{opacity:0}
.timelapse_hud:hover .hover-hide{opacity:1;z-index:5}
.video_grid{overflow: auto;height: 100%;display: block;}
.video_grid .col-md-2{padding-left:5px;padding-right:5px;padding-bottom:10px}
.video_grid .thumb{width:100%;height:150px;display:inline-block;background-size:cover;position:relative;overflow:hidden;border-radius:4px;border:1px solid #000;box-shadow:0 0 10px #151515}
.video_grid .thumb .title-strip, .video_grid .thumb .button-strip{width:100%;position:absolute;left:0;background:rgba(0,0,0,0.7);color:#fff;padding:4px}
.video_grid .thumb .title-strip{top:0;opacity:0.5}
.video_grid .thumb .button-strip{bottom:0;opacity:0}
.video_grid .thumb:hover .title-strip, .video_grid .thumb:hover .button-strip{opacity:1}
.table-striped>tbody>tr>td{vertical-align:middle}
.table-striped .thumbnail{width:100px;height:80px;border-radius:5px;margin:0;display:inline-block;}
#motion_list{height:155px;overflow:auto;border-radius:5px;border:1px solid #444;position:relative;background: #222;margin:0}
.dark .list-group-item{border-color: #444;background:#222}
.dark .list-group-item.active{background:#c49a68;border-color:#a7865f}
.novideos{text-transform: uppercase;text-align: center;border-bottom:0!important;padding-top: 55%!important;letter-spacing:2px}
.btn-warning {
color: #fff;
background-color: #c49a68;
border-color: #c49a68;
}
.dark.modal .modal-header,.dark.modal .modal-footer{background:#333;border-color:#444;}
.dark.modal .modal-header{color:#fff;}
.dark.modal .modal-footer>*:not(.btn){color:#fff;}
.dark.modal .modal-body{background:#333;}
.dark.modal .close{color:#fff;}
.dark.modal{color:#fff;}
.dark .table-striped>tbody>tr:nth-of-type(even){background:#616161}
.dark .table-striped>tbody>tr>td{border-color:#222;color:#fff}
.dark .table-striped>thead>tr>th{border-color:#222;color:#fff;background:#616161;vertical-align:middle;}
.dark .table-striped>tbody>tr:nth-of-type(odd){background-color: #4c4747;}
.dark .table>tbody>tr.active>td{background:inherit;border:0}
.dark code{color: #c49a68;background-color: #36333d;}
.dark a:not(.btn){color: #c49a68;}
.follow-list ul{padding:0;margin:0;font-family:"Roboto","Helvetica","Arial",sans-serif;}
.follow-list ul a:not(.btn){color:#fff}
.os_bars{width:600px;display:inline-block;padding:5px 0 0 10px}
@media screen and (max-width: 600px){
.os_bars{width:200px;}
.os_bars label{padding:2.5px 0;margin:0;font-size:8pt}
}
.os_bars .display-table .display-table-cell{padding:5px;vertical-align:center;width:33%}
.progress{height:5px;margin:0;}
.os_bars label,.os_bars .percent{padding:2.5px 0;margin:0;font-size:7.5pt}
.ui-pnotify-hide .ui-pnotify{display:none!important}
/*cool dropdown thing*/
ul.msg_list li {
background: #f7f7f7;color:#333;
padding: 5px;
display: list-item;
margin: 6px 6px 0;
width: 96% !important
}
ul.msg_list li div{display:block}
ul.msg_list li:last-child {
margin-bottom: 6px;
padding: 10px
}
ul.msg_list li a {
padding: 3px 5px !important
}
ul.msg_list li .progress {
height:5px;margin:10px 0 0 0;
}
ul.msg_list li .image img {
border-radius: 2px 2px 2px 2px;
-webkit-border-radius: 2px 2px 2px 2px;
float: left;
margin-right: 10px;
width: 11%
}
ul.msg_list li .time {
font-size: 11px;
font-style: italic;
font-weight: bold;
position: absolute;
}
ul.msg_list li .message {
display: block !important;
font-size: 11px
}
.dropdown-menu.msg_list span {
white-space: normal
}
.dropdown-menu {
border: medium none;
box-shadow: none;
display: none;
float: left;
font-size: 12px;
left: 0;
list-style: none outside none;
padding: 0;
position: absolute;
text-shadow: none;
top: 100%;
z-index: 9998;
border: 1px solid #D9DEE4;
border-top-left-radius: 0;
border-top-right-radius: 0
}
.dropdown-menu>li>a {
color: #5A738E
}
.navbar-nav .open .dropdown-menu {
position: absolute;
background: #fff;
margin-top: 0;
border: 1px solid #D9DEE4;
-webkit-box-shadow: none;
right: 0;
left: auto;
width: 220px
}
.is-small-screen .nav>li{display:inline-block}
.navbar-nav .open .dropdown-menu li a{padding:7px 15px}
.navbar-nav .open .dropdown-menu.msg_list {
width: 300px
}
.nav>li>a{color:#fff}
.nav>li>a:focus, .nav>li>a:hover,.nav .open>a, .nav .open>a:focus, .nav .open>a:hover{background:#867560}
.mdl-js-layout.hide-side:not(.is-small-screen){
}
@media screen and (min-width: 1025px){
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__drawer {
width: 0px;transition:0.2s
}
}
.mdl-js-layout.hide-side:not(.is-small-screen) .mdl-layout__header .mdl-layout__drawer-button{
display:none;
}
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__content{
margin-left: 0px;transition:0.2s
}
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__header{
margin-left: 0px;width:100%;transition:0.2s
}
/*Control Pad*/
.PTZ_controls {
z-index: 111;
position: absolute;
left: 20px;
top: 20px;
margin:0;
display: inline-block;
width: 120px;
}
.PTZ_controls .btn-group{margin-top:10px}
.PTZ_controls .pad {
position: relative;
height: 120px;
width: 120px;
background: #b7b7b7;
border-radius: 50%;
box-shadow: inset 0 0 1px rgba(120, 120, 120, 0.6), inset 0 2px 2px rgba(0, 0, 0, 0.1), 0 2px 2px rgba(240, 240, 240, 0.4);
}
.PTZ_controls .control {
position: absolute;
}
.PTZ_controls .pad .control {
height: 30px;
width: 30px;
background: #636363;
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.6), 0 0 0 3px rgba(60, 60, 60, 0.2), 0 0 0 4px rgba(60, 60, 60, 0.2);
border-radius: 2px;
}
.PTZ_controls .zoom_in{
top: 0;
right: 0;
}
.PTZ_controls .zoom_out{
bottom: 0;
right: 0;
}
.PTZ_controls .nv_enabled{
top: 0;
right: 0;
}
.PTZ_controls .nv_disable{
bottom: 0;
right: 0;
}
.PTZ_controls .pad .top {
top: 15px;
left: 50%;
margin: 0 0 0 -15px;
}
.PTZ_controls .pad .left {
top: 45px;
left: 15px;
}
.PTZ_controls .pad .right {
top: 45px;
right: 15px;
}
.PTZ_controls .pad .control.right:before {
transform: rotate(90deg) translate(-3px, -5px);
}
.PTZ_controls .pad .bottom {
bottom: 15px;
left: 50%;
margin: 0 0 0 -15px;
}
/* Overlap the other controls to hide box-shadow */
.PTZ_controls .pad .middle {
height: 34px;
width: 34px;
z-index: 5;
top: 43px;
left: 50%;
margin: 0 0 0 -17px;
box-shadow: none;
border-radius: 3px;
}
.PTZ_controls .pad .middle:after {
position: absolute;
top: 50%;
left: 50%;
margin: -35% 0 0 -35%;
content: '';
background: #636363;
height: 70%;
width: 70%;
border-radius: 100%;
box-shadow: inset 0 0 2px rgba(120, 120, 120, 0.6), inset 0 2px 8px rgba(0, 0, 0, 0.1), 0 2px 2px rgba(240, 240, 240, 0.2);
}
/*Digital Zoom*/
.stream-block{
position: relative;
overflow: auto;
}
.zoomGlass {
overflow: hidden;
transition: none;
width: 175px; height: 175px;
position: absolute;
border-radius: 15px;
border: 3px solid #ddd;
z-index:9999;
}
.zoomGlass iframe,.zoomGlass canvas{position:absolute;transition: none;}
.zoomGlass .hoverShade{position:absolute;width:100%;height:100%}
.dark.form-control,.dark .form-control {
display: block;
width: 100%;
height: 35px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.5;
color: #eee;
background-color: #36333d;
background-image: none;
border: 1px solid #444;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.dark.form-control:focus,.dark .form-control:focus {
color: #ddd;
background-color: #333;
box-shadow: none;
}
/*** custom checkboxes ***/
.checkbox input[type=checkbox] { display:none; } /* to hide the checkbox itself */
.checkbox input[type=checkbox] + label:before {
font-family: FontAwesome;
display: inline-block;
}
.checkbox input[type=checkbox] + label:before { content: "\f096"; } /* unchecked icon */
.checkbox input[type=checkbox] + label:before { letter-spacing: 10px; } /* space between checkbox and label */
.checkbox input[type=checkbox]:checked + label:before { content: "\f046"; } /* checked icon */
.checkbox input[type=checkbox]:checked + label:before { letter-spacing: 5px; } /* allow space for check mark */
/*Clock*/
#time-date {font-size:12px; text-align:center;}
@media screen and (min-width:1025px){
#clock {padding-right:35px}
}
#clock ul { width:150px; margin:0 auto; padding:0px; list-style:none; text-align:center; }
#clock ul li { display:inline; font-size:1.6em; text-align:center;font-family:monospace;}
#clock .point { position:relative; -moz-animation:mymove 1s ease infinite; -webkit-animation:mymove 1s ease infinite; }
/*custom vis.js css*/
.vis-timeline{background:#212121;color:#fff;border-color:#444}
.vis-time-axis .vis-text{color: #dedede}
.vis-item.vis-range .vis-item-content{background:#333;color:#fff}
.vis-time-axis .vis-grid.vis-minor{border-color:#444}
@-moz-document url-prefix() {
.full.modal .modal-body, .medium.modal .modal-body {
height:70%
}
}
/*animations*/
@keyframes blink {
0% { opacity:1 }
50% { opacity:0 }
100% { opacity:1 }
}
@-webkit-keyframes blink {
0% { opacity:1 }
50% { opacity:0 }
100% { opacity:1 }
}
.blink,[mode="Record"] .lamp {
-webkit-animation: blink 1s linear infinite;
-moz-animation: blink 1s linear infinite;
animation: blink 1s linear infinite;
}
.mdl-menu__item>div{display:flex;align-items: center;width:100%}
.mdl-menu__item>div>i{margin-right:5px}
/*For languages that are right to left*/
.right-to-left {text-align:right}
.right-to-left select{direction: rtl;}
.right-to-left input,.right-to-left textarea{direction: rtl;text-align:right}
.right-to-left .form-group label span{padding-right:10px}
.right-to-left .modal-footer{text-align:left}
.right-to-left .mdl-menu__item>div>*{flex:1}
.right-to-left .mdl-menu__item>div>i{margin-right:0;margin-left:5px}
.right-to-left .mdl-menu__item{text-align:right}
.right-to-left .mdl-menu__item i{float:right}
.right-to-left .pull-right,.right-to-left .close{float:left!important}
.right-to-left .pull-left,.right-to-left .mdl-menu__item span{float:right!important}
/* All-CSS Toggle Switch (Checkbox Hack) by Marcus Burnette - https://codepen.io/mburnette/pen/LxNxNg */
.marc-toggle {
width: 50px;
height: 25px;
}
.marc-toggle.abs-bot-left {
position: absolute;
bottom: 10px;
left: 10px;
}
.marc-toggle.abs-bot-right {
position: absolute;
bottom: 10px;
right: 10px;
}
.marc-toggle input[type=checkbox]{
height: 0;
width: 0;
visibility: hidden;
}
.marc-toggle label {
cursor: pointer;
text-indent: -9999px;
width: 100px;
height: 20px;
background: grey;
display: block;
border-radius: 100px;
margin-bottom: 0;
position: relative;
}
.marc-toggle label:after {
content: '';
position: absolute;
top: 5px;
left: 5px;
width: 10px;
height: 10px;
background: #fff;
border-radius: 90px;
transition: 0.3s;
}
.marc-toggle input:checked + label {
background: #00118c;
}
.marc-toggle input:checked + label:after {
left: calc(100% - 5px);
transform: translateX(-100%);
}
.marc-toggle label:active:after {
width: 10px;
}
/*hexagon pattern*/
.bg-hexagon {
background-color: #054e9f;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cg fill-rule='evenodd'%3E%3Cg id='hexagons' fill='%23fdfdfd' fill-opacity='0.4' fill-rule='nonzero'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}

View File

@ -608,15 +608,6 @@ _:-ms-input-placeholder, :root .demo-graph {
opacity: 0.46;
border-radius: 2px;
}
.social-btn__twitter {
background-image: url('https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png');
}
.social-btn__blogger {
background-image: url('https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png');
}
.social-btn__gplus {
background-image: url('https://www.gstatic.com/images/icons/material/system/2x/post_gplus_black_24dp.png');
}
.social-btn__share {
color: rgba(0, 0, 0, 0.54);
background: transparent;

View File

@ -0,0 +1,32 @@
$(document).ready(function(e){
//api window
$.apM={e:$('#apis')};$.apM.f=$.apM.e.find('form');
$.apM.md=$.apM.f.find('[detail]');
$.apM.md.change($.ccio.form.details).first().change();
$.apM.f.submit(function(e){
e.preventDefault();e.e=$(this),e.s=e.e.serializeObject();
e.er=[];
if(!e.s.ip||e.s.ip.length<7){e.er.push('Enter atleast one IP')}
if(e.er.length>0){$.apM.e.find('.msg').html(e.er.join('<br>'));return;}
$.each(e.s,function(n,v){e.s[n]=v.trim()})
// e.s = {
// "ip": "",
// "details": "{\"get_monitors\":\"1\",\"control_monitors\":\"1\",\"get_logs\":\"1\",\"watch_stream\":\"1\",\"watch_snapshot\":\"1\",\"watch_videos\":\"1\",\"delete_videos\":\"1\"}"
// }
$.post($.ccio.init('location',$user)+$user.auth_token+'/api/'+$user.ke+'/add',{data:JSON.stringify(e.s)},function(d){
$.ccio.log(d)
})
});
$.apM.e.on('click','.delete',function(e){
e.e=$(this);e.p=e.e.parents('[api_key]'),e.code=e.p.attr('api_key');
$.confirm.e.modal('show');
$.confirm.title.text('Delete API Key');
e.html='Do you want to delete this API key? You cannot recover it.';
$.confirm.body.html(e.html);
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
$.post($.ccio.init('location',$user)+$user.auth_token+'/api/'+$user.ke+'/delete',{data:JSON.stringify({code:e.code})},function(d){
$.ccio.log(d)
})
})
})
})

299
web/libs/js/dash2.basic.js Normal file
View File

@ -0,0 +1,299 @@
$.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.op = function(r,rr,rrr){
if(!rrr){rrr={};};if(typeof rrr === 'string'){rrr={n:rrr}};if(!rrr.n){rrr.n='ShinobiOptions_'+location.host}
ii={o:localStorage.getItem(rrr.n)};try{ii.o=JSON.parse(ii.o)}catch(e){ii.o={}}
if(!ii.o){ii.o={}}
if(r&&rr&&!rrr.x){
ii.o[r]=rr;
}
switch(rrr.x){
case 0:
delete(ii.o[r])
break;
case 1:
delete(ii.o[r][rr])
break;
}
localStorage.setItem(rrr.n,JSON.stringify(ii.o))
return ii.o
}
$.ccio.log = function(x,y,z){
if($.ccio.op().browserLog==="1"){
if(!y){y=''};if(!z){z=''};
console.log(x,y,z)
}
}
$.ccio.gid = function(x){
if(!x){x=10};var t = "";var p = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < x; i++ )
t += p.charAt(Math.floor(Math.random() * p.length));
return t;
};
$.ccio.downloadJSON = function(jsonToDownload,filename,errorResponse){
var arr = jsonToDownload;
if(arr.length===0 && errorResponse){
errorResponse.type = 'error'
$.ccio.init('note',errorResponse);
return
}
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(arr,null,3));
$('#temp').html('<a></a>')
.find('a')
.attr('href',dataStr)
.attr('download',filename)
[0].click()
}
$.ccio.timeObject = function(time,isUTC){
if(isUTC === true){
return moment(time).utc()
}
return moment(time)
}
$.ccio.base64ArrayBuffer = function(arrayBuffer) {
var base64 = ''
var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
var bytes = new Uint8Array(arrayBuffer)
var byteLength = bytes.byteLength
var byteRemainder = byteLength % 3
var mainLength = byteLength - byteRemainder
var a, b, c, d
var chunk
// Main loop deals with bytes in chunks of 3
for (var i = 0; i < mainLength; i = i + 3) {
// Combine the three bytes into a single integer
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
// Use bitmasks to extract 6-bit segments from the triplet
a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12
c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6
d = chunk & 63 // 63 = 2^6 - 1
// Convert the raw binary segments to the appropriate ASCII encoding
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
}
// Deal with the remaining bytes and padding
if (byteRemainder == 1) {
chunk = bytes[mainLength]
a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
// Set the 4 least significant bits to zero
b = (chunk & 3) << 4 // 3 = 2^2 - 1
base64 += encodings[a] + encodings[b] + '=='
} else if (byteRemainder == 2) {
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4
// Set the 2 least significant bits to zero
c = (chunk & 15) << 2 // 15 = 2^4 - 1
base64 += encodings[a] + encodings[b] + encodings[c] + '='
}
return base64
}
$.ccio.snapshot=function(e,cb){
var image_data,url;
e.details=JSON.parse(e.mon.details);
if($.ccio.op().jpeg_on!==true){
var extend=function(image_data,width,height){
var len = image_data.length
var arraybuffer = new Uint8Array( len );
for (var i = 0; i < len; i++) {
arraybuffer[i] = image_data.charCodeAt(i);
}
try {
var blob = new Blob([arraybuffer], {type: 'application/octet-stream'});
} catch (e) {
var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder);
bb.append(arraybuffer);
var blob = bb.getBlob('application/octet-stream');
}
url = (window.URL || window.webkitURL).createObjectURL(blob);
finish(url,image_data,width,height);
try{
setTimeout(function(){
URL.revokeObjectURL(url)
},10000)
}catch(er){}
}
var finish = function(url,image_data,width,height){
cb(url,image_data,width,height);
}
switch(JSON.parse(e.mon.details).stream_type){
case'hls':case'flv':case'mp4':
$.ccio.snapshotVideo($('[mid='+e.mon.mid+'].monitor_item video')[0],function(base64,video_data,width,height){
extend(video_data,width,height)
})
break;
case'mjpeg':
$('#temp').html('<canvas></canvas>')
var c = $('#temp canvas')[0];
var img = $('img',$('[mid='+e.mon.mid+'].monitor_item .stream-element').contents())[0];
c.width = img.width;
c.height = img.height;
var ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0,c.width,c.height);
extend(atob(c.toDataURL('image/jpeg').split(',')[1]),c.width,c.height)
break;
case'h265':
var c = $('[mid='+e.mon.mid+'].monitor_item canvas')[0];
var ctx = c.getContext('2d');
extend(atob(c.toDataURL('image/jpeg').split(',')[1]),c.width,c.height)
break;
case'b64':
base64 = e.mon.last_frame.split(',')[1];
var image_data = new Image();
image_data.src = base64;
extend(atob(base64),image_data.width,image_data.height)
break;
case'jpeg':case'h265':
url=e.p.find('.stream-element').attr('src');
image_data = new Image();
image_data.src = url;
finish(url,image_data,image_data.width,image_data.height);
break;
}
}else{
url=e.p.find('.stream-element').attr('src');
image_data = new Image();
image_data.src = url;
cb(url,image_data,image_data.width,image_data.height);
}
}
$.ccio.snapshotVideo=function(videoElement,cb){
var image_data;
var base64
$('#temp').html('<canvas></canvas>')
var c = $('#temp canvas')[0];
var img = videoElement;
c.width = img.videoWidth;
c.height = img.videoHeight;
var ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0,c.width,c.height);
base64=c.toDataURL('image/jpeg')
image_data=atob(base64.split(',')[1]);
var arraybuffer = new ArrayBuffer(image_data.length);
var view = new Uint8Array(arraybuffer);
for (var i=0; i<image_data.length; i++) {
view[i] = image_data.charCodeAt(i) & 0xff;
}
try {
var blob = new Blob([arraybuffer], {type: 'application/octet-stream'});
} catch (e) {
var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder);
bb.append(arraybuffer);
var blob = bb.getBlob('application/octet-stream');
}
cb(base64,image_data,c.width,c.height);
}
$.ccio.magnifyStream = function(e){
if(!e.p){
e.e=$(this),
e.p=e.e.parents('[mid]')
}
if(e.animate === true){
var zoomGlassAnimate = 'animate'
}else{
var zoomGlassAnimate = 'css'
}
if(e.auto === true){
var streamBlockOperator = 'position'
}else{
var streamBlockOperator = 'offset'
}
if(e.useCanvas === true){
var magnifiedElement = 'canvas'
}else{
var magnifiedElement = 'iframe'
}
e.ke=e.p.attr('ke'),//group key
e.mid=e.p.attr('mid'),//monitor id
e.auth=e.p.attr('auth'),//authkey
e.mon=$.ccio.mon[e.ke+e.mid+e.auth]//monitor configuration
if(e.zoomAmount)e.mon.zoomAmount=3;
if(!e.mon.zoomAmount)e.mon.zoomAmount=3;
e.height=parseFloat(e.p.attr('realHeight')) * e.mon.zoomAmount//height of stream
e.width=parseFloat(e.p.attr('realWidth')) * e.mon.zoomAmount;//width of stream
var targetForZoom = e.p.find('.stream-element');
zoomGlass = e.p.find(".zoomGlass");
var zoomFrame = function(){
var magnify_offset = e.p.find('.stream-block')[streamBlockOperator]();
var mx = e.pageX - magnify_offset.left;
var my = e.pageY - magnify_offset.top;
var rx = Math.round(mx/targetForZoom.width()*e.width - zoomGlass.width()/2)*-1;
var ry = Math.round(my/targetForZoom.height()*e.height - zoomGlass.height()/2)*-1;
var px = mx - zoomGlass.width()/2;
var py = my - zoomGlass.height()/2;
zoomGlass[zoomGlassAnimate]({left: px, top: py}).find(magnifiedElement)[zoomGlassAnimate]({left: rx, top: ry});
}
if(!e.height||!e.width||zoomGlass.length===0){
$.ccio.snapshot(e,function(url,buffer,width,height){
e.width = width * e.mon.zoomAmount;
e.height = height * e.mon.zoomAmount;
e.p.attr('realWidth',width)
e.p.attr('realHeight',height)
zoomGlass = e.p.find(".zoomGlass");
if(zoomGlass.length===0){
if(e.useCanvas === true){
e.p.append('<div class="zoomGlass"><canvas class="blenderCanvas"></canvas></div>');
}else{
e.p.append('<div class="zoomGlass"><iframe src="'+e.auth+'/embed/'+e.ke+'/'+e.mid+'/fullscreen|jquery|relative"/><div class="hoverShade"></div></div>');
}
zoomGlass = e.p.find(".zoomGlass");
}
zoomGlass.find(magnifiedElement).css({height:e.height,width:e.width});
zoomFrame()
})
}else{
zoomGlass.find(magnifiedElement).css({height:e.height,width:e.width});
zoomFrame()
}
}
$.ccio.destroyStream = function(d,user,killElement){
if(d.mid && !d.id)d.id = d.mid
console.log(d.ke+d.id+user.auth_token)
console.log($.ccio.mon[d.ke+d.id+user.auth_token])
if($.ccio.mon[d.ke+d.id+user.auth_token]){
console.log('destroy')
$.ccio.init('closeVideo',{mid:d.id,ke:d.ke},user);
$.ccio.init('jpegModeStop',{mid:d.id,ke:d.ke},user);
$.ccio.init('clearTimers',d,user)
clearInterval($.ccio.mon[d.ke+d.id+user.auth_token].signal);delete($.ccio.mon[d.ke+d.id+user.auth_token].signal);
$.ccio.mon[d.ke+d.id+user.auth_token].watch = 0;
$.ccio.mon[d.ke+d.id+user.auth_token].PoseidonErrorCount = 0
if($.ccio.mon[d.ke+d.id+user.auth_token].hls){$.ccio.mon[d.ke+d.id+user.auth_token].hls.destroy()}
if($.ccio.mon[d.ke+d.id+user.auth_token].Poseidon){$.ccio.mon[d.ke+d.id+user.auth_token].Poseidon.stop()}
if($.ccio.mon[d.ke+d.id+user.auth_token].Base64){$.ccio.mon[d.ke+d.id+user.auth_token].Base64.disconnect()}
if($.ccio.mon[d.ke+d.id+user.auth_token].h265Socket){$.ccio.mon[d.ke+d.id+user.auth_token].h265Socket.disconnect()}
if($.ccio.mon[d.ke+d.id+user.auth_token].h265Player){$.ccio.mon[d.ke+d.id+user.auth_token].h265Player.stop()}
if($.ccio.mon[d.ke+d.id+user.auth_token].dash){$.ccio.mon[d.ke+d.id+user.auth_token].dash.reset()}
if($.ccio.mon[d.ke+d.id+user.auth_token].h265HttpStream && $.ccio.mon[d.ke+d.id+user.auth_token].abort){
$.ccio.mon[d.ke+d.id+user.auth_token].h265HttpStream.abort()
}
if(killElement){
$.grid.data().removeWidget($('#monitor_live_'+d.id+user.auth_token))
}
}
}

132
web/libs/js/dash2.config.js Normal file
View File

@ -0,0 +1,132 @@
$.ccio={
fr:$('#files_recent'),
mon:{},
useUTC: <%- config.useUTC || false %>,
definitions: <%-JSON.stringify(define)%>,
libURL: '<%-window.libURL%>'
};
<% if(config.DropboxAppKey){ %>
$.ccio.DropboxAppKey = '<%-window.DropboxAppKey%>'
<% } %>
$.ccio.HWAccelChoices = [
<% if(config.availableHWAccels) {
var methods = {
auto: {label:lang['Auto'],value:'auto'},
drm: {label:lang['drm'],value:'drm'},
cuvid: {label:lang['cuvid'],value:'cuvid'},
vaapi: {label:lang['vaapi'],value:'vaapi'},
qsv: {label:lang['qsv'],value:'qsv'},
vdpau: {label:lang['vdpau'],value:'vdpau'},
dxva2: {label:lang['dxva2'],value:'dxva2'},
vdpau: {label:lang['vdpau'],value:'vdpau'},
videotoolbox: {label:lang['videotoolbox'],value:'videotoolbox'}
}
config.availableHWAccels.forEach(function(availibleMethod){
if(methods[availibleMethod]){ %>
<%- JSON.stringify(methods[availibleMethod]) %>,
<% }
})
}
%>
]
try{
$user.details = JSON.parse($user.details)
}catch(err){
}
if(!$user.details.lang||$user.details.lang==''){
$user.details.lang="<%-config.language%>"
}
switch($user.details.lang){
case'ar'://Arabic
case'bn'://Bengali
$('body').addClass('right-to-left')
$('.mdl-menu__item').each(function(n,v){
v=$(v).find('i')
v.appendTo(v.parent())
})
break;
}
window.chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
//global form functions
$.ccio.form={};
$.ccio.form.details=function(e){
e.ar={},e.f=$(this).parents('form');
$.each(e.f.find('[detail]'),function(n,v){
v=$(v);e.ar[v.attr('detail')]=v.val();
});
e.f.find('[name="details"]').val(JSON.stringify(e.ar));
};
$(document).ready(function(e){
//check switch UI
e.o=$.ccio.op().switches;
if(e.o){
$.each(e.o,function(n,v){
$('[system="switch"][switch="'+n+'"]').each(function(m,b){
b=$(b);
switch(b.attr('type')){
case'text':
if(v===1){
b.addClass('text-success')
}else{
b.removeClass('text-success')
}
break;
}
})
})
}else{
$.ccio.op('switches',{notifyHide:0})
}
//set class toggle preferences
e.o=$.ccio.op().class_toggle;
if(e.o){
$.each(e.o,function(n,v){
if(v[1]===1){
$(n).addClass(v[0])
}else{
$(n).removeClass(v[0])
}
})
}
//set dropdown toggle preferences
e.o = $.ccio.op().dropdown_toggle
if(e.o){
$.each(e.o,function(n,v){
$('[dropdown_toggle="'+n+'"]').val(v).change()
})
}
//set localStorage input values
e.o = $.ccio.op()
if(e.o){
$.each(e.o,function(n,v){
if(typeof v==='string'){
var el = $('[localStorage="'+n+'"]')
if(el.is(':checkbox') === false){
el.val(v)
}
}
})
}
document.addEventListener("fullscreenchange", onFullScreenChange, false);
document.addEventListener("webkitfullscreenchange", onFullScreenChange, false);
document.addEventListener("mozfullscreenchange", onFullScreenChange, false);
function onFullScreenChange() {
var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement;
if(!fullscreenElement){
$('.fullscreen').removeClass('fullscreen')
setTimeout(function(){
$('canvas.stream-element').resize();
},2000)
}
}
})

View File

View File

@ -0,0 +1,61 @@
$(document).ready(function(e){
//filters window
if(!$user.details.filters)$user.details.filters={};
$.fI={e:$('#filters')};$.fI.f=$.fI.e.find('form');
$.fI.md=$.fI.f.find('[detail]');
$.ccio.init('filters');
$.ccio.tm('filters-where');
$.fI.e.on('click','.where .add',function(e){
$.ccio.tm('filters-where');
})
$.fI.e.on('click','.where .remove',function(e){
e.e=$('#filters_where .row');
if(e.e.length>1){
e.e.last().remove();
}
})
$('#saved_filters').change(function(e){
e.e=$(this),e.id=e.e.val();
$('#filters_where').empty()
if(e.id&&e.id!==''){
e.name=$user.details.filters[e.id].name;
$.each($user.details.filters[e.id].where,function(n,v){
$.ccio.tm('filters-where',v)
});
$.each($user.details.filters[e.id],function(n,v){
if(n==='where'){return}
$.fI.f.find('[name="'+n+'"]').val(v);
});
}else{
e.name=lang['Add New'];
$.fI.f.find('[name="id"]').val($.ccio.gid(5));
$.ccio.tm('filters-where');
}
$.fI.e.find('.filter_name').text(e.name)
}).change()
$.fI.f.find('.delete').click(function(e){
e.s=$.fI.f.serializeObject();
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Filter']);
e.html=lang.confirmDeleteFilter;
$.confirm.body.html(e.html);
$.confirm.click({title:lang['Delete Filter'],class:'btn-danger'},function(){
$.ccio.cx({f:'settings',ff:'filters',fff:'delete',form:e.s})
});
})
$.fI.f.submit(function(e){
e.preventDefault();e.e=$(this),e.s=e.e.serializeObject();
e.er=[];
$.each(e.s,function(n,v){e.s[n]=v.trim()})
e.s.where=[];
e.e.find('.where-row').each(function(n,v){
n={};
$(v).find('[where]').each(function(m,b){
b=$(b);
n[b.attr('where')]=b.val().trim();
})
e.s.where.push(n)
})
$.ccio.cx({f:'settings',ff:'filters',fff:'save',form:e.s})
});
})

View File

@ -0,0 +1,143 @@
$(document).ready(function(e){
//detector filters window
$.detectorFilters={e:$('#detector_filter')};
$.detectorFilters.f=$.detectorFilters.e.find('form');
$.detectorFilters.md=$.detectorFilters.f.find('[detail]');
$.detectorFilters.getSelected = function(){
return $('#detector_filters').val()
}
$.detectorFilters.drawOptions = function(){
var dFilters = $.detectorFilters.getCurrent()
$('#detector_filters optgroup').empty()
$.each(dFilters,function(n,dFilter){
$.ccio.tm('option',{auth_token:$user.auth_token,id:dFilter.id,name:dFilter.filter_name},'#detector_filters optgroup')
})
}
$.detectorFilters.getCurrent = function(){
try{
return JSON.parse($.aM.e.find('[detail="detector_filters"]').val())
}catch(err){
return {}
}
}
$.detectorFilters.save = function(){
var currentVals = $.detectorFilters.getCurrent()
currentVals[$.detectorFilters.lastSave.id] = $.detectorFilters.lastSave
$.aM.e.find('[detail="detector_filters"]').val(JSON.stringify(currentVals)).change()
}
$.ccio.tm('detector-filters-where');
$.detectorFilters.e.on('change','[where="p1"]',function(e){
var el = $(this)
var p1v = el.val()
var parent = el.parents('.row')
var p3 = parent.find('[where="p3"]')
var options = []
switch(p1v){
case'time':
options = [
'00:00:00'
]
break;
case'reason':
options = [
'licensePlate',
'object',
'motion',
]
break;
case'plug':
options = [
'PythonYolo',
'OpenCV',
'built-in',
]
break;
case'tag':
options = [
'car',
'tree',
'pottedplant',
]
break;
}
var msg = 'Value'
if(options.length > 0){
msg = 'Example : '+options.join(', ')
}
p3.attr('placeholder',msg)
})
$.detectorFilters.e.on('shown.bs.modal',function(e){
$.detectorFilters.drawOptions()
})
$.detectorFilters.e.on('click','.where .add',function(e){
$.ccio.tm('detector-filters-where');
})
$.detectorFilters.e.on('click','.where .remove',function(e){
e.e=$('#detector_filters_where .row');
if(e.e.length>1){
e.e.last().remove();
$('#detector_filters_where .row:last [where="p4"]').prop('disabled',true)
}
})
$.detectorFilters.f.find('.delete').click(function(e){
var currentVals = $.detectorFilters.getCurrent()
var newObject = {}
var deleteId = $.detectorFilters.getSelected()
$.each(currentVals,function(id,obj){
if(id === deleteId)return false;
newObject[id] = obj
})
$.aM.e.find('[detail="detector_filters"]').val(JSON.stringify(newObject)).change()
$.detectorFilters.drawOptions()
})
$('#detector_filters').change(function(){
e = {}
e.e=$(this),e.id=e.e.val();
$('#detector_filters_where').empty()
if(e.id&&e.id!==''){
var currentFilter = $.detectorFilters.getCurrent()[e.id]
e.name=currentFilter.name;
$.each(currentFilter.where,function(n,v){
$.ccio.tm('detector-filters-where',v)
});
$.each(currentFilter.actions,function(action,val){
$.detectorFilters.e.find('[actions="'+action+'"]').val(val)
});
$.each(currentFilter,function(n,v){
if(n==='where'){return}
$.detectorFilters.f.find('[name="'+n+'"]').val(v);
});
}else{
e.name=lang['Add New'];
$.detectorFilters.f.find('[name="id"]').val($.ccio.gid(5));
$.ccio.tm('detector-filters-where');
}
$.detectorFilters.e.find('.filter_name').text(e.name)
}).change()
$.detectorFilters.f.submit(function(ee){
ee.preventDefault()
e = {}
e.e=$(this),e.s=e.e.serializeObject();
e.er=[];
$.each(e.s,function(n,v){e.s[n]=v.trim()})
//create conditions object (where)
e.s.where=[];
e.e.find('.where-row').each(function(n,v){
n={};
$(v).find('[where]').each(function(m,b){
b=$(b);
n[b.attr('where')]=b.val().trim();
})
e.s.where.push(n)
})
// create actions object (do)
e.s.actions={};
e.e.find('.actions-row').each(function(n,v){
b=$(v).find('[actions]');
e.s.actions[b.attr('actions')] = b.val()
})
$.detectorFilters.lastSave = e.s
$.detectorFilters.save()
$.detectorFilters.e.modal('hide')
});
})

View File

@ -0,0 +1,915 @@
$.ccio.tm=function(x,d,z,user){
var tmp='';if(!d){d={}};
var k={}
if(d&&d.user){
user=d.user
}
if(!user){
user=$user
}
if(d.id&&!d.mid){d.mid=d.id;}
switch(x){
case 0://video
var url = $.ccio.init('videoUrlBuild',d)
href = 'href="'+url+'"'
// if(!d.filename){d.filename=$.ccio.init('tf',d.time)+'.'+d.ext;}
d.dlname=d.mid+'-'+d.filename;
d.startMoment=$.ccio.timeObject(d.time),
d.endMoment=$.ccio.timeObject(d.end),
d.hr=parseInt(d.startMoment.format('HH')),
d.per=parseInt(d.hr/24*100);
d.circle='<div title="at '+d.hr+' hours of '+d.startMoment.format('MMMM DD')+'" '+href+' video="launch" class="progress-circle progress-'+d.per+'"><span>'+d.hr+'</span></div>'
tmp+='<li class="video-item glM'+d.mid+user.auth_token+'" auth="'+user.auth_token+'" mid="'+d.mid+'" ke="'+d.ke+'" status="'+d.status+'" status="'+d.status+'" file="'+d.filename+'">'+d.circle+'<div><span title="'+d.endMoment.format()+'" class="livestamp"></span></div><div><div class="small"><b>'+lang.Start+'</b> : '+d.startMoment.format('h:mm:ss , MMMM Do YYYY')+'</div><div class="small"><b>'+lang.End+'</b> : '+d.endMoment.format('h:mm:ss , MMMM Do YYYY')+'</div></div><div><span class="pull-right">'+(parseInt(d.size)/1000000).toFixed(2)+'mb</span><div class="controls btn-group"><a class="btn btn-sm btn-primary" video="launch" '+href+'><i class="fa fa-play-circle"></i></a> <a download="'+d.dlname+'" '+href+' class="btn btn-sm btn-default"><i class="fa fa-download"></i></a>'
if($.ccio.DropboxAppKey){ tmp+='<a video="download" host="dropbox" download="'+d.dlname+'" '+href+' class="btn btn-sm btn-default"><i class="fa fa-dropbox"></i></a>' }
tmp+='<a title="'+lang['Delete Video']+'" video="delete" href="'+$.ccio.init('videoHrefToDelete',url)+'" class="btn btn-sm btn-danger permission_video_delete"><i class="fa fa-trash"></i></a></div></div></li>';
$(z).each(function(n,v){
v=$(v);
if(v.find('.video-item').length>10){v.find('.video-item:last').remove()}
})
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>'+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
try{k.d=JSON.parse(d.details);}catch(er){k.d=d.details;}
k.mode=$.ccio.init('humanReadMode',d.mode);
var dataTarget = '.monitor_item[mid=\''+d.mid+'\'][ke=\''+d.ke+'\'][auth=\''+user.auth_token+'\']';
tmp+='<div id="monitor_live_'+d.mid+user.auth_token+'" auth="'+user.auth_token+'" mid="'+d.mid+'" ke="'+d.ke+'" mode="'+k.mode+'" class="grid-stack-item monitor_item glM'+d.mid+user.auth_token+'"><div class="grid-stack-item-content">';
tmp+='<div class="stream-block no-padding mdl-card__media mdl-color-text--grey-50">';
tmp+='<div class="stream-objects"></div>';
tmp+='<div class="stream-hud">'
tmp+='<div class="camera_cpu_usage"><div class="progress"><div class="progress-bar progress-bar-danger" role="progressbar"><span></span></div></div></div>';
tmp+='<div class="lamp" title="'+k.mode+'"><i class="fa fa-eercast"></i></div><div class="controls"><span title="'+lang['Currently viewing']+'" class="label label-default"><span class="viewers"></span></span> <a class="btn-xs btn-danger btn" monitor="mode" mode="record"><i class="fa fa-circle"></i> '+lang['Start Recording']+'</a> <a class="btn-xs btn-primary btn" monitor="mode" mode="start"><i class="fa fa-eye"></i> '+lang['Set to Watch Only']+'</a></div></div></div></div>'
tmp+='<div class="mdl-card__supporting-text text-center">';
tmp+='<div class="indifference detector-fade"><div class="progress"><div class="progress-bar progress-bar-danger" role="progressbar"><span></span></div></div></div>';
tmp+='<div class="monitor_details">';
tmp+='<div><span class="monitor_name">'+d.name+'</span><span class="monitor_not_record_copy">, '+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
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"
},
"Video Grid": {
"label": "Video Grid",
"attr": "monitor=\"video_grid\"",
"class": "default",
"icon": "th"
},
"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
tmp+='</div>';//.stream-block
tmp+='<div class="mdl-data_window pull-right">';
tmp+='<div>';
tmp+='<div class="data-menu col-md-6 no-padding videos_monitor_list glM'+d.mid+user.auth_token+' scrollable"><ul></ul></div>';
tmp+='<div class="data-menu col-md-6 no-padding logs scrollable"></div>';
tmp+='</div>';
tmp+='</div>';//.mdl-data_window
tmp+='</div>';//.grid-stack-content
tmp+='</div>';//#monitor_live_...
break;
case 3://api key row
tmp+='<tr api_key="'+d.code+'"><td class="code">'+d.code+'</td><td class="ip">'+d.ip+'</td><td class="time">'+d.time+'</td><td class="text-right"><a class="delete btn btn-xs btn-danger">&nbsp;<i class="fa fa-trash"></i>&nbsp;</a></td></tr>';
break;
case 4://log row, draw to global and monitor
if(!d.time){d.time=$.ccio.init('t')}
tmp+='<li class="log-item">'
tmp+='<span>'
tmp+='<div>'+d.ke+' : <b>'+d.mid+'</b></div>'
tmp+='<span>'+d.log.type+'</span> '
tmp+='<b class="time livestamp" title="'+d.time+'"></b>'
tmp+='</span>'
tmp+='<div class="message">'
tmp+=$.ccio.init('jsontoblock',d.log.msg);
tmp+='</div>'
tmp+='</li>';
$(z).each(function(n,v){
v=$(v);
if(v.find('.log-item').length>10){v.find('.log-item:last').remove()}
})
break;
case 6://notification row
if(!d.time){d.time=$.ccio.init('t')}
if(!d.note.class){d.note.class=''}
tmp+='<li class="note-item '+d.note.class+'" ke="'+d.ke+'" auth="'+user.auth_token+'" mid="'+d.id+'">'
tmp+='<span>'
tmp+='<div>'+d.ke+' : <b>'+d.id+'</b></div>'
tmp+='<span>'+d.note.type+'</span> '
tmp+='<b class="time livestamp" title="'+d.time+'"></b>'
tmp+='</span>'
tmp+='<div class="message">'
tmp+=d.note.msg
tmp+='</div>'
tmp+='</li>';
break;
case'option':
var selected = ''
if(d.selected === true){selected = ' selected'}
tmp+='<option auth="'+user.auth_token+'"'+selected+' value="'+d.id+'">'+d.name+'</option>'
break;
case'stream-element':
try{k.d=JSON.parse(d.details);}catch(er){k.d=d.details}
if($.ccio.mon[d.ke+d.mid+user.auth_token]&&$.ccio.mon[d.ke+d.mid+user.auth_token].previousStreamType===k.d.stream_type){
return;
}
k.e=$('#monitor_live_'+d.mid+user.auth_token+' .stream-block');
k.e.find('.stream-element').remove();
if($.ccio.op().jpeg_on===true){
tmp+='<img class="stream-element">';
}else{
switch(k.d.stream_type){
case'hls':case'flv':case'mp4':
tmp+='<video class="stream-element" autoplay></video>';
break;
case'mjpeg':
tmp+='<iframe class="stream-element"></iframe>';
break;
case'jpeg':
tmp+='<img class="stream-element">';
break;
default://base64//h265
tmp+='<canvas class="stream-element"></canvas>';
break;
}
}
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+'"]')
if(d.e.length===0){
tmp+='<li class="user-row" uid="'+d.uid+'" ke="'+d.ke+'">';
tmp+='<span><div><span class="mail">'+d.mail+'</span> : <b class="uid">'+d.uid+'</b></div><span>Logged in</span> <b class="time livestamped" title="'+d.logged_in_at+'"></b></span>';
tmp+='</li>';
}else{
d.e.find('.mail').text(d.mail)
d.e.find('.time').livestamp('destroy').toggleClass('livestamped livestamp').text(d.logged_in_at)
}
$.ccio.init('ls')
break;
case'detector-filters-where':
if(!d)d={};
d.id=$('#filters_where .row').length;
if(!d.p1){d.p1='indifference'}
if(!d.p2){d.p2='='}
if(!d.p3){d.p3=''}
if(!d.p4){d.p4='&&'}
tmp+='<div class="row where-row">'
tmp+=' <div class="form-group col-md-3">'
tmp+=' <label>'
tmp+=' <select class="form-control" where="p1">'
tmp+=' <option value="indifference" selected>'+lang['Indifference']+'</option>'
tmp+=' <option value="name">'+lang['Region Name']+'</option>'
tmp+=' <option value="reason">'+lang['Reason']+'</option>'
tmp+=' <option value="time">'+lang['Time']+'</option>'
tmp+=' <option value="plug">'+lang['Detection Engine']+'</option>'
tmp+=' <optgroup label="Matrix">'
tmp+=' <option value="tag">'+lang['Object Tag']+'</option>'
tmp+=' <option value="confidence">'+lang['Confidence']+'</option>'
tmp+=' <option value="x">'+lang['X Point']+'</option>'
tmp+=' <option value="y">'+lang['Y Point']+'</option>'
tmp+=' <option value="height">'+lang['Height']+'</option>'
tmp+=' <option value="width">'+lang['Width']+'</option>'
tmp+=' </optgroup>'
tmp+=' </select>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group col-md-3">'
tmp+=' <label>'
tmp+=' <select class="form-control" where="p2">'
tmp+=' <option value="===" selected>'+lang['Equal to']+'</option>'
tmp+=' <option value="!==">'+lang['Not Equal to']+'</option>'
tmp+=' <option value="indexOf">'+lang['Contains']+'</option>'
tmp+=' <option value="!indexOf">'+lang['Does Not Contain']+'</option>'
tmp+=' <optgroup label="For Numbers">'
tmp+=' <option value=">=">'+lang['Greater Than or Equal to']+'</option>'
tmp+=' <option value=">">'+lang['Greater Than']+'</option>'
tmp+=' <option value="<">'+lang['Less Than']+'</option>'
tmp+=' <option value="<=">'+lang['Less Than or Equal to']+'</option>'
tmp+=' </optgroup>'
tmp+=' </select>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group col-md-3">'
tmp+=' <label>'
tmp+=' <input class="form-control" placeholder="Value" title="'+lang.Value+'" where="p3">'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group col-md-3">'
tmp+=' <label>'
tmp+=' <select class="form-control" where="p4">'
tmp+=' <option value="&&" selected>'+lang['AND']+'</option>'
tmp+=' <option value="||">'+lang['OR']+'</option>'
tmp+=' </select>'
tmp+=' </label>'
tmp+=' </div>'
tmp+='</div>'
break;
case'filters-where':
if(!d)d={};
d.id=$('#filters_where .row').length;
if(!d.p1){d.p1='mid'}
if(!d.p2){d.p2='='}
if(!d.p3){d.p3=''}
tmp+='<div class="row where-row">';
tmp+=' <div class="form-group col-md-4">';
tmp+=' <label>';
tmp+=' <select class="form-control" where="p1">';
tmp+=' <option value="mid" selected>'+lang['Monitor ID']+'</option>';
tmp+=' <option value="ext">'+lang['File Type']+'</option>';
tmp+=' <option value="time">'+lang['Start Time']+'</option>';
tmp+=' <option value="end">'+lang['End Time']+'</option>';
tmp+=' <option value="size">'+lang['Filesize']+'</option>';
tmp+=' <option value="status">'+lang['Video Status']+'</option>';
tmp+=' </select>';
tmp+=' </label>';
tmp+=' </div>';
tmp+=' <div class="form-group col-md-4">';
tmp+=' <label>';
tmp+=' <select class="form-control" where="p2">';
tmp+=' <option value="=" selected>'+lang['Equal to']+'</option>';
tmp+=' <option value="!=">'+lang['Not Equal to']+'</option>';
tmp+=' <option value=">=">'+lang['Greater Than or Equal to']+'</option>';
tmp+=' <option value=">">'+lang['Greater Than']+'</option>';
tmp+=' <option value="<">'+lang['Less Than']+'</option>';
tmp+=' <option value="<=">'+lang['Less Than or Equal to']+'</option>';
tmp+=' <option value="LIKE">'+lang['Like']+'</option>';
tmp+=' <option value="=~">'+lang['Matches']+'</option>';
tmp+=' <option value="!~">'+lang['Not Matches']+'</option>';
tmp+=' <option value="=[]">'+lang['In']+'</option>';
tmp+=' <option value="![]">'+lang['Not In']+'</option>';
tmp+=' </select>';
tmp+=' </label>';
tmp+=' </div>';
tmp+=' <div class="form-group col-md-4">';
tmp+=' <label>';
tmp+=' <input class="form-control" placeholder="Value" title="'+lang.Value+'" where="p3">';
tmp+=' </label>';
tmp+=' </div>';
tmp+='</div>';
break;
case 'link-set'://Link Shinobi - 1 set
if(!d.host){d.host=''}
if(!d.ke){d.ke=''}
if(!d.api){d.api=''}
if(!d.secure){d.secure="0"}
tmp+='<div class="linksGroup" links="'+d.host+'">'
tmp+='<h4 class="round-left">'+d.host+' <small>'+d.ke+'</small>&nbsp;<div class="pull-right"><a class="btn btn-danger btn-xs delete"><i class="fa fa-trash-o"></i></a></div></h4>'
tmp+='<div class="form-group"><label><div><span>'+lang.Host+'</span></div><div><input class="form-control" link="host" value="'+d.host+'"></div></label></div>'
tmp+='<div class="form-group"><label><div><span>'+lang['Group Key']+'</span></div><div><input class="form-control" link="ke" value="'+d.ke+'"></div></label></div>'
tmp+='<div class="form-group"><label><div><span>'+lang['API Key']+'</span></div><div><input class="form-control" link="api" value="'+d.api+'"></div></label></div>'
tmp+='<div class="form-group"><label><div><span>'+lang.Secure+' (HTTPS/WSS)</span></div><div><select class="form-control" link="secure"><option value="1">'+lang.Yes+'</option><option selected value="0">'+lang.No+'</option></select></div></label></div>'
tmp+='</div>';
break;
case 'form-group'://Input Map Selector
var fields = []
if(d.fields){
if(d.fields instanceof Object){
fields = [d]
}else{
fields = d
}
}
$.each(fields,function(n,v){
var value,hidden
if(!v.attribute)v.attribute='';
if(!v.placeholder)v.placeholder='';
if(!v.class)v.class='';
if(!v.inputType)v.inputType='value';
if(v.hidden){hidden='style="display:none"'}else{hidden=''};
if(v.value){value='value=""'}else{value=''};
tmp+=' <div class="form-group '+v.class+'" '+hidden+'>'
tmp+=' <label><div><span>'+v.label+'</span></div>'
tmp+=' <div>'
switch(v.type){
case'text':
tmp+='<input class="form-control" '+v.inputType+'="'+v.name+'" placeholder="'+v.placeholder+'" "'+value+'" '+v.attribute+'>'
break;
case'selector':
tmp+='<select class="form-control" '+v.inputType+'="'+v.name+'" placeholder="'+v.placeholder+'" '+v.attribute+'>'
$.each(v.choices,function(m,b){
tmp+='<option value="'+b.value+'">'+b.label+'</option>'
})
tmp+='</select>'
break;
}
tmp+=' </div>'
tmp+=' </label>'
tmp+=' </div>'
})
break;
case 'input-map-selector'://Input Map Selector
if(!d.map){d.map=''}
tmp+=' <div class="form-group map-row">'
tmp+=' <label><div><span>'+lang['Map']+'</span></div>'
tmp+=' <div>'
tmp+=' <div class="input-group input-group-sm">'
tmp+='<input class="form-control" map-input="map" value="'+d.map+'" placeholder="0">'
tmp+=' <div class="input-group-btn">'
tmp+=' <a class="btn btn-danger delete_map_row">&nbsp;<i class="fa fa-trash-o"></i>&nbsp;</a>'
tmp+=' </div>'
tmp+=' </div>'
tmp+=' </div>'
tmp+=' </label>'
tmp+=' </div>'
break;
case 'input-map'://Input Map Options
var tempID = $.ccio.gid();
if(!d.channel){
var numberOfChannelsDrawn = $('#monSectionInputMaps .input-map').length
d.channel=numberOfChannelsDrawn+1
}
var fields = [
// {
// name:'',
// class:'',
// placeholder:'',
// default:'',
// attribute:'',
// type:'text',
// },
{
name:'type',
label:lang['Input Type'],
default:'h264',
attribute:'selector="h_i_'+tempID+'"',
type:'selector',
choices:[
{label:lang['H.264 / H.265 / H.265+'],value:'h264'},
{label:lang['JPEG'],value:'jpeg'},
{label:lang['MJPEG'],value:'mjpeg'},
{label:lang['HLS (.m3u8)'],value:'hls'},
{label:lang['MPEG-4 (.mp4 / .ts)'],value:'mp4'},
{label:lang['Local'],value:'local'},
{label:lang['Raw'],value:'raw'},
]
},
{
name:'fulladdress',
label:lang['Full URL Path'],
placeholder:'Example : rtsp://admin:password@123.123.123.123/stream/1',
type:'text',
},
{
name:'sfps',
label:lang['Monitor Capture Rate'],
placeholder:'',
type:'text',
},
{
name:'aduration',
label:lang['Analyzation Duration'],
placeholder:'Example : 1000000',
type:'text',
},
{
name:'probesize',
label:lang['Probe Size'],
placeholder:'Example : 1000000',
type:'text',
},
{
name:'stream_loop',
label:lang['Loop Stream'],
class:'h_i_'+tempID+'_input h_i_'+tempID+'_mp4 h_i_'+tempID+'_raw',
hidden:true,
default:'0',
type:'selector',
choices:[
{label:'No',value:'0'},
{label:'Yes',value:'1'}
]
},
{
name:'rtsp_transport',
label:lang['RTSP Transport'],
class:'h_i_'+tempID+'_input h_i_'+tempID+'_h264',
default:'0',
type:'selector',
choices:[
{label:'Auto',value:''},
{label:'TCP',value:'tcp'},
{label:'UDP',value:'udp'}
]
},
{
name:'accelerator',
label:lang['Accelerator'],
attribute:'selector="h_accel_'+tempID+'"',
default:'0',
type:'selector',
choices:[
{label:'No',value:'0'},
{label:'Yes',value:'1'},
]
},
{
name:'hwaccel',
label:lang['hwaccel'],
class:'h_accel_'+tempID+'_input h_accel_'+tempID+'_1',
hidden:true,
default:'',
type:'selector',
choices: $.ccio.HWAccelChoices
},
{
name:'hwaccel_vcodec',
label:lang['hwaccel_vcodec'],
class:'h_accel_'+tempID+'_input h_accel_'+tempID+'_1',
hidden:true,
default:'auto',
type:'selector',
choices:[
{label:lang['Auto'],value:'auto'},
{label:lang['h264_cuvid'],value:'h264_cuvid',group:'NVIDIA'},
{label:lang['hevc_cuvid'],value:'hevc_cuvid',group:'NVIDIA'},
{label:lang['mjpeg_cuvid'],value:'mjpeg_cuvid',group:'NVIDIA'},
{label:lang['mpeg4_cuvid'],value:'mpeg4_cuvid',group:'NVIDIA'},
{label:lang['h264_qsv'],value:'h264_qsv',group:'Quick Sync Video'},
{label:lang['hevc_qsv'],value:'hevc_qsv',group:'Quick Sync Video'},
{label:lang['mpeg2_qsv'],value:'mpeg2_qsv',group:'Quick Sync Video'},
{label:lang['h264_mmal'],value:'h264_mmal',group:'Raspberry Pi'},
{label:lang['mpeg2_mmal'],value:'mpeg2_mmal',group:'Raspberry Pi'},
{label:lang['mpeg4_mmal'],value:'mpeg4_mmal',group:'Raspberry Pi'},
]
},
{
name:'hwaccel_device',
label:lang['hwaccel_device'],
class:'h_accel_'+tempID+'_input h_accel_'+tempID+'_1',
hidden:true,
placeholder:'Example : /dev/dri/video0',
type:'text',
},
];
tmp+='<div class="form-group-group forestgreen input-map" section id="monSectionMap'+tempID+'">'
tmp+=' <h4>'+lang["Input"]+' <b>'+lang["Map"]+' : <span class="place">'+d.channel+'</span></b>'
tmp+=' <div class="pull-right"><a class="btn btn-danger btn-xs delete"><i class="fa fa-trash-o"></i></a></div>'
tmp+=' </h4>'
$.each(fields,function(n,v){
if(!v.attribute)v.attribute='';
if(!v.placeholder)v.placeholder='';
if(!v.class)v.class='';
if(v.hidden){v.hidden='style="display:none"'}else{v.hidden=''};
tmp+=' <div class="form-group '+v.class+'" '+v.hidden+'>'
tmp+=' <label><div><span>'+v.label+'</span></div>'
tmp+=' <div>'
switch(v.type){
case'text':
tmp+='<input class="form-control" map-detail="'+v.name+'" placeholder="'+v.placeholder+'" '+v.attribute+'>'
break;
case'selector':
tmp+='<select class="form-control" map-detail="'+v.name+'" placeholder="'+v.placeholder+'" '+v.attribute+'>'
$.each(v.choices,function(m,b){
tmp+='<option value="'+b.value+'">'+b.label+'</option>'
})
tmp+='</select>'
break;
}
tmp+=' </div>'
tmp+=' </label>'
tmp+=' </div>'
})
tmp+='</div>'
break;
case 'stream-channel'://Stream Channel
var tempID = $.ccio.gid();
if(!d.channel){
var numberOfChannelsDrawn = $('#monSectionStreamChannels .stream-channel').length
d.channel=numberOfChannelsDrawn
}
tmp+='<div class="form-group-group blue stream-channel" section id="monSectionChannel'+tempID+'">'
tmp+=' <h4>'+lang["Stream Channel"]+' <span class="place">'+d.channel+'</span>'
tmp+=' <div class="pull-right"><a class="btn btn-danger btn-xs delete"><i class="fa fa-trash-o"></i></a></div>'
tmp+=' </h4>'
// tmp+=' <div class="form-group">'
// tmp+=' <label><div><span>'+lang["Input Selector"]+'</span></div>'
// tmp+=' <div><input class="form-control" channel-detail="stream_map" placeholder="0"></div>'
// tmp+=' </label>'
// tmp+=' </div>'
tmp+='<div class="form-group-group forestgreen" input-mapping="stream_channel-'+d.channel+'">'
tmp+=' <h4>'+lang['Input Feed']
tmp+=' <div class="pull-right">'
tmp+=' <a class="btn btn-success btn-xs add_map_row"><i class="fa fa-plus-square-o"></i></a>'
tmp+=' </div>'
tmp+=' </h4>'
tmp+=' <div class="choices"></div>'
tmp+='</div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Stream Type"]+'</span></div>'
tmp+=' <div><select class="form-control" channel-detail="stream_type" selector="h_st_channel_'+tempID+'" triggerChange="#monSectionChannel'+tempID+' [channel-detail=stream_vcodec]" triggerChangeIgnore="b64,mjpeg">'
tmp+=' <option value="mp4">'+lang["Poseidon"]+'</option>'
tmp+=' <option value="rtmp">'+lang["RTMP Stream"]+'</option>'
tmp+=' <option value="flv">'+lang["FLV"]+'</option>'
tmp+=' <option value="h264">'+lang["Raw H.264 Stream"]+'</option>'
tmp+=' <option value="hls">'+lang["HLS (includes Audio)"]+'</option>'
tmp+=' <option value="mjpeg">'+lang["MJPEG"]+'</option>'
tmp+=' </select></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="h_st_channel_'+tempID+'_input h_st_channel_'+tempID+'_rtmp">'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Server URL"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="rtmp_server_url" placeholder="Example : rtmp://live-api.facebook.com:80/rtmp/"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Stream Key"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="rtmp_stream_key" placeholder="Example : 1111111111?ds=1&a=xxxxxxxxxx"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' </div>'
tmp+=' <div class="form-group h_st_channel_'+tempID+'_input h_st_channel_'+tempID+'_mjpeg" style="display:none">'
tmp+=' <label><div><span>'+lang["# of Allow MJPEG Clients"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="stream_mjpeg_clients" placeholder="20"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="h_st_channel_'+tempID+'_input h_st_channel_'+tempID+'_hls h_st_channel_'+tempID+'_rtmp h_st_channel_'+tempID+'_flv h_st_channel_'+tempID+'_mp4 h_st_channel_'+tempID+'_h264">'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["HLS Video Encoder"]+'</span></div>'
tmp+=' <div><select class="form-control" channel-detail="stream_vcodec" selector="h_hls_v_channel_'+tempID+'">'
tmp+=' <option value="no" selected>'+lang["Auto"]+'</option>'
tmp+=' <option value="libx264">'+lang["libx264"]+'</option>'
tmp+=' <option value="libx265">'+lang["libx265"]+'</option>'
tmp+=' <option value="copy" selected>'+lang["copy"]+'</option>'
tmp+=' <optgroup label="'+lang["Hardware Accelerated"]+'">'
tmp+=' <option value="h264_vaapi">'+lang["h264_vaapi"]+'</option>'
tmp+=' <option value="hevc_vaapi">'+lang["hevc_vaapi"]+'</option>'
tmp+=' <option value="h264_nvenc">'+lang["h264_nvenc"]+'</option>'
tmp+=' <option value="hevc_nvenc">'+lang["hevc_nvenc"]+'</option>'
tmp+=' <option value="h264_qsv">'+lang["h264_qsv"]+'</option>'
tmp+=' <option value="hevc_qsv">'+lang["hevc_qsv"]+'</option>'
tmp+=' <option value="mpeg2_qsv">'+lang["mpeg2_qsv"]+'</option>'
tmp+=' <option value="h264_omx">'+lang["h264_omx"]+'</option>'
tmp+=' </optgroup>'
tmp+=' </select></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["HLS Audio Encoder"]+'</span></div>'
tmp+=' <div><select class="form-control" channel-detail="stream_acodec">'
tmp+=' <option value="no" selected>'+lang["No Audio"]+'</option>'
tmp+=' <option value="">'+lang["Auto"]+'</option>'
tmp+=' <option value="aac">'+lang["aac"]+'</option>'
tmp+=' <option value="ac3">'+lang["ac3"]+'</option>'
tmp+=' <option value="libmp3lame">'+lang["libmp3lame"]+'</option>'
tmp+=' <option value="copy">'+lang["copy"]+'</option>'
tmp+=' </select></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Rate"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="stream_fps" placeholder=""></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="h_st_channel_'+tempID+'_input h_st_channel_'+tempID+'_hls" style="display:none">'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["HLS Segment Length"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="hls_time" placeholder="2"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["HLS Preset"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="preset_stream" placeholder="ultrafast"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["HLS List Size"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="hls_list_size" placeholder="2"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' </div>'
tmp+=' <div class="h_st_channel_'+tempID+'_input h_st_channel_'+tempID+'_mjpeg h_st_channel_'+tempID+'_hls h_st_channel_'+tempID+'_rtmp h_st_channel_'+tempID+'_jsmpeg h_st_channel_'+tempID+'_flv h_st_channel_'+tempID+'_mp4 h_st_channel_'+tempID+'_h264 h_hls_v_channel_'+tempID+'_input h_hls_v_channel_'+tempID+'_libx264 h_hls_v_channel_'+tempID+'_libx265 h_hls_v_channel_'+tempID+'_h264_nvenc h_hls_v_channel_'+tempID+'_hevc_nvenc h_hls_v_channel_'+tempID+'_no" style="display:none">'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Quality"]+'</span></div>'
tmp+=' <div><input class="form-control" placeholder="23" channel-detail="stream_quality"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="h_st_channel_'+tempID+'_input h_st_channel_'+tempID+'_rtmp">'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Video Bit Rate"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="stream_v_br" placeholder=""></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Audio Bit Rate"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="stream_a_br" placeholder="128k"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Width"]+'</span></div>'
tmp+=' <div><input class="form-control" type="number" min="1" channel-detail="stream_scale_x" placeholder="Example : 640"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Height"]+'</span></div>'
tmp+=' <div><input class="form-control" type="number" min="1" channel-detail="stream_scale_y" placeholder="Example : 480"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Rotate"]+'</span></div>'
tmp+=' <div><select class="form-control" channel-detail="rotate_stream">'
tmp+=' <option value="no" selected>'+lang["No Rotation"]+'</option>'
tmp+=' <option value="2,transpose=2">'+lang["180 Degrees"]+'</option>'
tmp+=' <option value="0">'+lang["90 Counter Clockwise and Vertical Flip (default)"]+'</option>'
tmp+=' <option value="1">'+lang["90 Clockwise"]+'</option>'
tmp+=' <option value="2">'+lang["90 Clockwise and Vertical Flip"]+'</option>'
tmp+=' <option value="3">'+lang["90 Clockwise and Vertical Flip"]+'</option>'
tmp+=' </select></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Video Filter"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="svf"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' <div class="form-group">'
tmp+=' <label><div><span>'+lang["Stream Flags"]+'</span></div>'
tmp+=' <div><input class="form-control" channel-detail="cust_stream"></div>'
tmp+=' </label>'
tmp+=' </div>'
tmp+=' </div>'
tmp+=' </div>'
break;
}
if(z && x !== 2){
$(z).prepend(tmp)
}
switch(x){
case 1:
z='#monitors_list .link-monitors-list[auth="'+user.auth_token+'"][ke="'+d.ke+'"]'
if($('.link-monitors-list[auth="'+user.auth_token+'"][ke="'+d.ke+'"]').length===0){
$("#monitors_list").append('<div class="link-monitors-list" auth="'+user.auth_token+'" ke="'+d.ke+'"></div>')
var options = {
cellHeight: 80,
verticalMargin: 10,
};
//monitor="watch_off"
$(z).gridstack(options);
$(z).on('change', function(event, ui) {
var monitors = {}
$.grid.e.find(" .monitor_item").each(function(n,v){
var el = $(v)
var item = {}
item.ke = el.attr('ke')
item.mid = el.attr('mid')
item.x = el.attr('data-gs-x')
item.y = el.attr('data-gs-y')
item.height = el.attr('data-gs-height')
item.width = el.attr('data-gs-width')
monitors[item.ke+item.mid] = item
})
user.details.monitorOrder=monitors;
$.ccio.cx({f:'monitorOrder',monitorOrder:monitors},user)
});
}
$(z).prepend(tmp)
componentHandler.upgradeAllRegistered()
break;
case 0:case 4:
$.ccio.init('ls');
break;
case 2:
var x = 0;
var y = 0;
var width = $.grid.getMonitorsPerRow()
var height = width;
if(user.details && user.details.monitorOrder && user.details.monitorOrder[d.ke+d.mid]){
var saved = user.details.monitorOrder[d.ke+d.mid];
x = saved.x;
y = saved.y;
width = saved.width;
height = saved.height;
}
var autoPlacement = false
if($.ccio.op().switches.monitorOrder !== 1){
autoPlacement = true
}
$(z).data('gridstack').addWidget($(tmp), x, y, width, height, autoPlacement);
k.e=$('#monitor_live_'+d.mid+user.auth_token);
try{
if(JSON.parse(d.details).control=="1"){
k.e.find('[monitor="control_toggle"]').show()
}else{
k.e.find('.pad').remove();
k.e.find('[monitor="control_toggle"]').hide()
}
$.ccio.tm('stream-element',d,null,user)
}catch(re){$.ccio.log(re)}
k.mid=d.mid
k.mon=$.ccio.mon[d.ke+d.mid+user.auth_token]
$.ccio.init('monitorInfo',k)
break;
case'detector-filters-where':
$('#detector_filters_where').append(tmp);
$('#detector_filters_where .row [where="p4"][disabled]').prop('disabled',false)
$('#detector_filters_where .row:last [where="p1"]').val(d.p1)
$('#detector_filters_where .row:last [where="p2"]').val(d.p2)
$('#detector_filters_where .row:last [where="p3"]').val(d.p3)
$('#detector_filters_where .row:last [where="p4"]').val(d.p4).prop('disabled',true)
break;
case'filters-where':
$('#filters_where').append(tmp);
$('#filters_where .row:last [where="p1"]').val(d.p1)
$('#filters_where .row:last [where="p2"]').val(d.p2)
$('#filters_where .row:last [where="p3"]').val(d.p3)
break;
case'input-map':
var mapsList = $.aM.maps
mapsList.append(tmp)
mapsList.find('.input-map').last().find('[map-detail="aduration"]').change()
return tempID;
break;
case'stream-channel':
var channeList = $.aM.channels
channeList.append(tmp)
channeList.find('.stream-channel').last().find('[channel-detail="stream_vcodec"]').change()
return tempID;
break;
case'link-set':
$('[links="'+d.host+'"] [link="secure"]').val(d.secure).change()
break;
}
return tmp;
}
$.ccio.pm=function(x,d,z,user){
var tmp='';if(!d){d={}};
if(!user){
user=$user
}
switch(x){
case 0:
d.mon=$.ccio.mon[d.ke+d.mid+user.auth_token];
d.ev='.glM'+d.mid+user.auth_token+'.videos_list ul,.glM'+d.mid+user.auth_token+'.videos_monitor_list ul';d.fr=$.ccio.fr.find(d.ev),d.tmp='';
if(d.fr.length===0){$.ccio.fr.append('<div class="videos_list glM'+d.mid+user.auth_token+'"><h3 class="title">'+d.mon.name+'</h3><ul></ul></div>')}
if(d.videos&&d.videos.length>0){
$.each(d.videos,function(n,v){
if(v.status!==0){
tmp+=$.ccio.tm(0,v,null,user)
}
})
}else{
$('.glM'+d.mid+user.auth_token+'.videos_list,.glM'+d.mid+user.auth_token+'.videos_monitor_list').appendTo($.ccio.fr)
tmp+='<li class="notice novideos">No videos</li>';
}
$(d.ev).html(tmp);
$.ccio.init('ls');
break;
case 3:
z='#api_list';
$(z).empty();
$.each(d,function(n,v){
tmp+=$.ccio.tm(3,v,null,user);
})
break;
case'option':
$.each(d,function(n,v){
tmp+=$.ccio.tm('option',v,null,user);
})
break;
case'user-row':
$.each(d,function(n,v){
tmp+=$.ccio.tm('user-row',v,null,user);
})
z='#users_online'
break;
case'link-set':
$.sM.links.empty()
$.each(d,function(n,v){
tmp+=$.ccio.tm('link-set',v,'#linkShinobi',user)
})
break;
}
if(z){
$(z).prepend(tmp)
}
return tmp;
}

View File

@ -0,0 +1,767 @@
$(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()
}
})
//Group Selector
$.gR={e:$('#group_list'),b:$('#group_list_button')};
$.gR.drawList=function(){
var e={};
e.tmp='';
$.each($.ccio.init('monGroup'),function(n,v){
if($user.mon_groups[n]){
e.tmp+='<li class="mdl-menu__item" groups="'+n+'">'+$user.mon_groups[n].name+'</li>'
}
})
$.gR.e.html(e.tmp)
}
$.gR.e.on('click','[groups]',function(){
var e={};
e.e=$(this),
e.a=e.e.attr('groups');
var user=$.users[e.e.attr('auth')];
if(!user){user=$user}
if(user===$user){
e.chosen_set='watch_on'
}else{
e.chosen_set='watch_on_links'
}
$.each($.ccio.op()[e.chosen_set],function(n,v){
$.each(v,function(m,b){
$.ccio.cx({f:'monitor',ff:'watch_off',id:m,ke:n},user)
})
})
$.each($.ccio.mon_groups[e.a],function(n,v){
$.ccio.cx({f:'monitor',ff:'watch_on',id:v.mid,ke:v.ke},user)
})
})
//open all monitors
$('[class_toggle="list-blocks"][data-target="#left_menu"]').dblclick(function(){
$('#monitors_list .monitor_block').each(function(n,v){
var el = $(v)
var ke = el.attr('ke')
var mid = el.attr('mid')
var auth = el.attr('auth')
var monItem = $('.monitor_item[ke='+ke+'][mid='+mid+'][auth='+auth+']')
if(monItem.length > 0){
monItem.find('[monitor="watch_on"]').click()
}else{
el.find('[monitor="watch"]').click()
}
})
})
//search monitors list
$('#monitors_list_search').keyup(function(){
var monitorBlocks = $('.monitor_block');
var searchTerms = $(this).val().toLowerCase().split(' ')
if(searchTerms.length === 0 || searchTerms[0] === ''){
monitorBlocks.show()
return
}
monitorBlocks.hide()
$.each($.ccio.mon,function(n,monitor){
var searchThis = JSON.stringify($.ccio.init('cleanMon',monitor)).toLowerCase().replace('"','');
$.each(searchTerms,function(m,term){
if(searchThis.indexOf(term) >-1 ){
$('.monitor_block[ke="'+monitor.ke+'"][mid="'+monitor.mid+'"]').show()
}
})
})
})
//dynamic bindings
$.ccio.windowFocus = true
$(window).focus(function() {
$.ccio.windowFocus = true
clearInterval($.ccio.soundAlarmInterval)
}).blur(function() {
$.ccio.windowFocus = false
});
$('body')
.on('click','.logout',function(e){
var logout = function(user,callback){
$.get($.ccio.init('location',user)+user.auth_token+'/logout/'+user.ke+'/'+user.uid,callback)
}
$.each($.users,function(n,linkedShinobiUser){
logout(linkedShinobiUser,function(){});
})
logout($user,function(data){
console.log(data)
localStorage.removeItem('ShinobiLogin_'+location.host);
location.href=location.href;
});
})
.on('click','[video]',function(e){
e.e=$(this),
e.a=e.e.attr('video'),
e.p=e.e.parents('[mid]'),
e.ke=e.p.attr('ke'),
e.mid=e.p.attr('mid'),
e.file=e.p.attr('file');
e.auth=e.p.attr('auth');
e.status=e.p.attr('status');
if(!e.ke||!e.mid){
//for calendar plugin
e.p=e.e.parents('[data-mid]'),
e.ke=e.p.data('ke'),
e.mid=e.p.data('mid'),
e.file=e.p.data('file');
e.auth=e.p.data('auth');
e.status=e.p.data('status');
}
e.mon=$.ccio.mon[e.ke+e.mid+e.auth];
switch(e.a){
case'launch':
e.preventDefault();
e.href=$(this).attr('href')
var el = $('#video_viewer')
var modalBody = el.find('.modal-body')
el.find('.modal-title span').html(e.mon.name+' - '+e.file)
var html = '<video class="video_video" video="'+e.href+'" autoplay loop controls><source src="'+e.href+'" type="video/'+e.mon.ext+'"></video><br><small class="msg"></small>'
modalBody.html(html)
el.find('video')[0].onerror = function(){
modalBody.find('.msg').text(lang.h265BrowserText1)
}
el.attr('mid',e.mid);
footer = el.find('.modal-footer');
footer.find('.download_link').attr('href',e.href).attr('download',e.file);
footer.find('[monitor="download"][host="dropbox"]').attr('href',e.href);
el.modal('show')
.attr('ke',e.ke)
.attr('mid',e.mid)
.attr('auth',e.auth)
.attr('file',e.file);
if(e.status==1){
$.get($.ccio.init('videoHrefToRead',e.href),function(d){
if(d.ok !== true)console.log(d,new Error())
})
}
break;
case'delete':
e.preventDefault();
var videoLink = e.p.find('[download]').attr('href')
var href = $(this).attr('href')
console.log('videoLink',videoLink)
console.log(href)
if(!href){
href = $.ccio.init('location',$.users[e.auth])+e.auth+'/videos/'+e.ke+'/'+e.mid+'/'+e.file+'/delete<% if(config.useUTC === true){%>?isUTC=true<%}%>'
}
console.log(href)
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Video']+' : '+e.file)
e.html=lang.DeleteVideoMsg
e.html+='<video class="video_video" autoplay loop controls><source src="'+videoLink+'" type="video/'+e.mon.ext+'"></video>';
$.confirm.body.html(e.html)
$.confirm.click({title:'Delete Video',class:'btn-danger'},function(){
$.getJSON(href,function(d){
$.ccio.log(d)
})
});
break;
case'download':
e.preventDefault();
switch(e.e.attr('host')){
case'dropbox':
if($.ccio.DropboxAppKey){
Dropbox.save(e.e.attr('href'),e.e.attr('download'),{progress: function (progress) {$.ccio.log(progress)},success: function () {
$.ccio.log(lang.dropBoxSuccess);
}});
}
break;
}
break;
}
})
.on('change','[localStorage]',function(){
e = {}
e.e=$(this)
e.localStorage = e.e.attr('localStorage')
e.value = e.e.val()
$.ccio.op(e.localStorage,e.value)
})
.on('click','[system]',function(e){
var e={};
e.e=$(this),
e.a=e.e.attr('system');//the function
switch(e.a){
case'switch':
e.switch=e.e.attr('switch');
e.o=$.ccio.op().switches
if(!e.o){
e.o={}
}
if(!e.o[e.switch]){
e.o[e.switch]=0
}
if(e.o[e.switch]===1){
e.o[e.switch]=0
}else{
e.o[e.switch]=1
}
$.ccio.op('switches',e.o)
switch(e.switch){
case'monitorOrder':
if(e.o[e.switch] !== 1){
$('.monitor_item').attr('data-gs-auto-position','yes')
}else{
$('.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':
if(e.o[e.switch]===1){
e.e.addClass('text-success')
}else{
e.e.removeClass('text-success')
}
break;
}
break;
case'cronStop':
$.ccio.cx({f:'cron',ff:'stop'})
break;
case'cronRestart':
$.ccio.cx({f:'cron',ff:'restart'})
break;
case'jpegToggle':
e.cx={f:'monitor',ff:'jpeg_on'};
if($.ccio.op().jpeg_on===true){
e.cx.ff='jpeg_off';
}
$.ccio.cx(e.cx)
break;
}
})
.on('click','[class_toggle]',function(e){
e.e=$(this);
e.n=e.e.attr('data-target');
e.v=e.e.attr('class_toggle');
e.o=$.ccio.op().class_toggle;
if($(e.n).hasClass(e.v)){e.t=0}else{e.t=1}
if(!e.o)e.o={};
e.o[e.n]=[e.v,e.t];
$.ccio.op('class_toggle',e.o)
$(e.n).toggleClass(e.v);
})
.on('change','[dropdown_toggle]',function(e){
e.e=$(this);
e.n=e.e.attr('dropdown_toggle');
e.v=e.e.val();
e.o=$.ccio.op().dropdown_toggle;
if(!e.o)e.o={};
e.o[e.n]=e.v;
$.ccio.op('dropdown_toggle',e.o)
})
//monitor functions
.on('click','[monitor]',function(){
var e={};
e.e=$(this),
e.a=e.e.attr('monitor'),//the function
e.p=e.e.parents('[mid]'),//the parent element for monitor item
e.ke=e.p.attr('ke'),//group key
e.mid=e.p.attr('mid'),//monitor id
e.auth=e.p.attr('auth'),//authkey
e.mon=$.ccio.mon[e.ke+e.mid+e.auth];//monitor configuration
var user
if($.users[e.auth]){user=$.users[e.auth]}else{user=$user}
if(!user){
user=$user
}
switch(e.a){
case'show_data':
e.p.toggleClass('show_data')
var dataBlocks = e.p.find('.stream-block,.mdl-data_window')
if(e.p.hasClass('show_data')){
dataBlocks.addClass('col-md-6').removeClass('col-md-12')
}else{
dataBlocks.addClass('col-md-12').removeClass('col-md-6')
}
break;
case'motion':
if(!e.mon.motionDetectionRunning){
$.ccio.init('streamMotionDetectOn',e,user)
}else{
$.ccio.init('streamMotionDetectOff',e,user)
}
break;
case'pop':
e.fin=function(img){
if($.ccio.mon[e.ke+e.mid+user.auth_token].popOut){
$.ccio.mon[e.ke+e.mid+user.auth_token].popOut.close()
}
$.ccio.mon[e.ke+e.mid+user.auth_token].popOut = window.open($.ccio.init('location',user)+user.auth_token+'/embed/'+e.ke+'/'+e.mid+'/fullscreen|jquery|relative|gui','pop_'+e.mid+user.auth_token,'height='+img.height+',width='+img.width);
}
if(e.mon.watch===1){
$.ccio.snapshot(e,function(url){
$('#temp').html('<img>')
var img=$('#temp img')[0]
img.onload=function(){
e.fin(img)
}
img.src=url
})
}else{
var img={height:720,width:1280}
e.fin(img)
}
break;
case'mode':
e.mode=e.e.attr('mode')
if(e.mode){
$.getJSON($.ccio.init('location',user)+user.auth_token+'/monitor/'+e.ke+'/'+e.mid+'/'+e.mode,function(d){
$.ccio.log(d)
})
}
break;
case'timelapse':
$.timelapse.e.modal('show')
$.timelapse.monitors.find('.monitor').remove()
$.each($.ccio.mon,function(n,v){
$.timelapse.monitors.append('<option class="monitor" value="'+v.mid+'">'+v.name+'</option>')
})
e.e=$.timelapse.monitors.find('.monitor').prop('selected',false)
if(e.mid!==''){
e.e=$.timelapse.monitors.find('.monitor[value="'+e.mid+'"]')
}
e.e.first().prop('selected',true)
$.timelapse.f.submit()
break;
case'powerview':
$.pwrvid.e.modal('show')
$.pwrvid.m.empty()
$.each($.ccio.mon,function(n,v){
$.pwrvid.m.append('<option value="'+v.mid+'">'+v.name+'</option>')
})
e.e=$.pwrvid.m.find('option').prop('selected',false)
if(e.mid!==''){
e.e=$.pwrvid.m.find('[value="'+e.mid+'"]')
}
e.e.first().prop('selected',true)
$.pwrvid.f.submit()
break;
case'region':
if(!e.mon){
$.ccio.init('note',{title:lang['Unable to Launch'],text:lang.UnabletoLaunchText,type:'error'});
return;
}
e.d=JSON.parse(e.mon.details);
e.width=$.aM.e.find('[detail="detector_scale_x"]');
e.height=$.aM.e.find('[detail="detector_scale_y"]');
e.d.cords=$.aM.e.find('[detail="cords"]').val();
if(e.width.val()===''){
e.d.detector_scale_x=320;
e.d.detector_scale_y=240;
$.aM.e.find('[detail="detector_scale_x"]').val(e.d.detector_scale_x);
$.aM.e.find('[detail="detector_scale_y"]').val(e.d.detector_scale_y);
}else{
e.d.detector_scale_x=e.width.val();
e.d.detector_scale_y=e.height.val();
}
$.zO.e.modal('show');
$.zO.o().attr('width',e.d.detector_scale_x).attr('height',e.d.detector_scale_y);
$.zO.c.css({width:e.d.detector_scale_x,height:e.d.detector_scale_y});
if(e.d.cords&&(e.d.cords instanceof Object)===false){
try{e.d.cords=JSON.parse(e.d.cords);}catch(er){}
}
if(!e.d.cords||e.d.cords===''){
e.d.cords={
red:{ name:"red",sensitivity:0.0005, max_sensitivity:"",color_threshold:"",points:[[0,0],[0,100],[100,0]] },
}
}
$.zO.regionViewerDetails=e.d;
$.zO.initRegionList()
break;
case'detector_filters':
$.detectorFilters.e.modal('show');
break;
case'snapshot':
$.ccio.snapshot(e,function(url){
$('#temp').html('<a href="'+url+'" download="'+$.ccio.init('tf')+'_'+e.ke+'_'+e.mid+'.jpg">a</a>').find('a')[0].click();
});
break;
case'control':
e.a=e.e.attr('control')
$.ccio.cx({f:'monitor',ff:'control',direction:e.a,mid:e.mid,ke:e.ke},user)
break;
case'videos_table':case'calendar':case'video_grid'://call videos table or calendar or video grid
$.vidview.launcher=$(this);
e.limit=$.vidview.limit.val();
if(!$.vidview.current_mid||$.vidview.current_mid!==e.mid){
$.vidview.current_mid=e.mid
$.vidview.current_page=1;
if(e.limit.replace(/ /g,'')===''){
e.limit='100';
}
if(e.limit.indexOf(',')===-1){
e.limit='0,'+e.limit
}else{
e.limit='0,'+e.limit.split(',')[1]
}
if(e.limit=='0,0'){
e.limit='0'
}
$.vidview.limit.val(e.limit)
}
e.dateRange=$('#videos_viewer_daterange').data('daterangepicker');
var videoSet = 'videos'
switch($.vidview.set.val()){
case'cloud':
videoSet = 'cloudVideos'
break;
}
e.videoURL=$.ccio.init('location',user)+user.auth_token+'/'+videoSet+'/'+e.ke+'/'+e.mid+'?limit='+e.limit+'&start='+$.ccio.init('th',e.dateRange.startDate)+'&end='+$.ccio.init('th',e.dateRange.endDate);
$.getJSON(e.videoURL,function(d){
d.pages=d.total/100;
$('.video_viewer_total').text(d.total)
if(d.pages+''.indexOf('.')>-1){++d.pages}
$.vidview.page_count=d.pages;
d.count=1
$.vidview.pages.empty()
d.fn=function(drawOne){
if(d.count<=$.vidview.page_count){
$.vidview.pages.append('<a class="btn btn-primary" page="'+d.count+'">'+d.count+'</a> ')
++d.count;
d.fn()
}
}
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){
case'calendar':
$.vidview.e.removeClass('dark')
e.t.attr('class','fa fa-calendar')
e.ar=[];
if(d.videos[0]){
$.each(d.videos,function(n,v){
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;
// v.filename=$.ccio.init('tf',v.time)+'.'+v.ext;
e.ar.push(v);
}
})
e.b.html('')
try{e.b.fullCalendar('destroy')}catch(er){}
e.b.fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay,listWeek'
},
defaultDate: $.ccio.timeObject(d.videos[0].time).format('YYYY-MM-DD'),
navLinks: true,
eventLimit: true,
events:e.ar,
eventClick:function(f){
$('#temp').html('<div mid="'+f.mid+'" ke="'+f.ke+'" auth="'+user.auth_token+'" file="'+f.filename+'"><div video="launch" href="'+$.ccio.init('videoUrlBuild',f)+'"></div></div>').find('[video="launch"]').click();
$(this).css('border-color', 'red');
}
});
setTimeout(function(){e.b.fullCalendar('changeView','month');e.b.find('.fc-scroller').css('height','auto')},500)
}else{
e.b.html('<div class="text-center">'+lang.NoVideosFoundForDateRange+'</div>')
}
break;
case'video_grid':
$.vidview.e.addClass('dark')
var tmp = '<di class="video_grid row">';
$.each(d.videos,function(n,v){
var href = $.ccio.init('videoUrlBuild',v)
v.mon = $.ccio.mon[v.ke+v.mid+user.auth_token]
var parentTag = 'ke="'+v.ke+'" status="'+v.status+'" mid="'+v.mid+'" file="'+v.filename+'" auth="'+v.mon.user.auth_token+'"'
tmp += '<div class="col-md-2" '+parentTag+'>'
tmp += '<div class="thumb">'
tmp += '<div class="title-strip">'+$.ccio.timeObject(v.time).format('h:mm:ss A, MMMM Do YYYY')+'</div>'
tmp += '<div class="button-strip">'
tmp += '<div class="btn-group">'
tmp += '<a class="btn btn-xs btn-primary" video="launch" href="'+href+'">&nbsp;<i class="fa fa-play-circle"></i>&nbsp;</a>'
tmp += '<a class="btn btn-xs btn-default preview" href="'+href+'">&nbsp;<i class="fa fa-play-circle"></i>&nbsp;</a>'
tmp += '<a class="btn btn-xs btn-default" download="'+v.mid+'-'+v.filename+'" href="'+href+'">&nbsp;<i class="fa fa-download"></i>&nbsp;</a>'
tmp += '</div>'
tmp += '</div>'
tmp += '</div>'
tmp += '</div>'
})
tmp += '</div>'
e.b.html(tmp)
var i = 0
var getThumbnail = function(){
var v = d.videos[i]
if(v){
tool.getVideoImage($.ccio.init('videoUrlBuild',v),0,function(err,base64){
if(base64){
$('[ke="'+v.ke+'"][mid="'+v.mid+'"][file="'+v.filename+'"] .thumb').css('background-image','url('+base64+')')
}
++i
getThumbnail()
})
}
}
getThumbnail()
break;
case'videos_table':
var showThumbnail = $.ccio.op().showThumbnail === '1'
$.vidview.e.removeClass('dark')
e.t.attr('class','fa fa-film')
var tmp = '<table class="table table-striped" style="max-height:500px">';
tmp+='<thead>';
tmp+='<tr>';
tmp+='<th><div class="checkbox"><input id="videos_select_all" type="checkbox"><label for="videos_select_all"></label></div></th>';
if(showThumbnail)tmp+='<th data-field="Thumbnail" data-sortable="true">'+lang.Thumbnail+'</th>';
tmp+='<th data-field="Closed" data-sortable="true">'+lang.Closed+'</th>';
tmp+='<th data-field="Ended" data-sortable="true">'+lang.Ended+'</th>';
tmp+='<th data-field="Started" data-sortable="true">'+lang.Started+'</th>';
tmp+='<th data-field="Monitor" data-sortable="true">'+lang.Monitor+'</th>';
tmp+='<th data-field="Filename" data-sortable="true">'+lang.Filename+'</th>';
tmp+='<th data-field="Size" data-sortable="true">'+lang['Size (mb)']+'</th>';
tmp+='<th data-field="Preview" data-sortable="true">'+lang.Preview+'</th>';
tmp+='<th data-field="Watch" data-sortable="true">'+lang.Watch+'</th>';
tmp+='<th data-field="Download" data-sortable="true">'+lang.Download+'</th>';
tmp+='<th class="permission_video_delete" data-field="Delete" data-sortable="true">'+lang.Delete+'</th>';
// tmp+='<th class="permission_video_delete" data-field="Fix" data-sortable="true">'+lang.Fix+'</th>';
tmp+='</tr>';
tmp+='</thead>';
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;
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+'">';
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>';
if(showThumbnail)tmp+='<td class="text-center"><img class="thumbnail"></td>';
tmp+='<td><span class="livestamp" title="'+$.ccio.timeObject(v.end).format('YYYY-MM-DD HH:mm:ss')+'"></span></td>';
tmp+='<td title="'+v.end+'">'+$.ccio.timeObject(v.end).format('h:mm:ss A, MMMM Do YYYY')+'</td>';
tmp+='<td title="'+v.time+'">'+$.ccio.timeObject(v.time).format('h:mm:ss A, MMMM Do YYYY')+'</td>';
tmp+='<td>'+v.mon.name+'</td>';
tmp+='<td>'+v.filename+'</td>';
tmp+='<td>'+(parseInt(v.size)/1000000).toFixed(2)+'</td>';
tmp+='<td><a class="btn btn-sm btn-default preview" href="'+href+'">&nbsp;<i class="fa fa-play-circle"></i>&nbsp;</a></td>';
tmp+='<td><a class="btn btn-sm btn-primary" video="launch" href="'+href+'">&nbsp;<i class="fa fa-play-circle"></i>&nbsp;</a></td>';
tmp+='<td><a class="btn btn-sm btn-success" download="'+v.mid+'-'+v.filename+'" href="'+href+'">&nbsp;<i class="fa fa-download"></i>&nbsp;</a></td>';
tmp+='<td class="permission_video_delete"><a class="btn btn-sm btn-danger" video="delete" href="'+$.ccio.init('videoHrefToDelete',href)+'">&nbsp;<i class="fa fa-trash"></i>&nbsp;</a></td>';
// tmp+='<td class="permission_video_delete"><a class="btn btn-sm btn-warning" video="fix">&nbsp;<i class="fa fa-wrench"></i>&nbsp;</a></td>';
tmp+='</tr>';
}
})
tmp+='</tbody>';
tmp+='</table>';
e.b.html(tmp)
if(showThumbnail){
var i = 0
var getThumbnail = function(){
var v = d.videos[i]
if(v){
tool.getVideoImage($.ccio.init('videoUrlBuild',v),0,function(err,base64){
if(base64){
$('[data-ke="'+v.ke+'"][data-mid="'+v.mid+'"][data-file="'+v.filename+'"] .thumbnail')[0].src = base64
}
++i
getThumbnail()
})
}
}
getThumbnail()
}
$.ccio.init('ls');
$.vidview.e.find('table').bootstrapTable();
break;
}
})
break;
case'fullscreen':
e.e=e.e.parents('.monitor_item');
e.e.addClass('fullscreen')
e.vid=e.e.find('.stream-element')
if(e.vid.is('canvas')){
e.doc=$('body')
e.vid.attr('height',e.doc.height())
e.vid.attr('width',e.doc.width())
}
$.ccio.init('fullscreen',e.vid[0])
break;
case'watch_on':
$.ccio.cx({f:'monitor',ff:'watch_on',id:e.mid},user)
break;
case'control_toggle':
e.e=e.p.find('.PTZ_controls');
if(e.e.length>0){
e.e.remove()
}else{
var html = '<div class="PTZ_controls">'
html += '<div class="pad">'
html += '<div class="control top" monitor="control" control="up"></div>'
html += '<div class="control left" monitor="control" control="left"></div>'
html += '<div class="control right" monitor="control" control="right"></div>'
html += '<div class="control bottom" monitor="control" control="down"></div>'
html += '<div class="control middle" monitor="control" control="center"></div>'
html += '</div>'
html += '<div class="btn-group btn-group-sm btn-group-justified">'
html += '<a title="'+lang['Zoom In']+'" class="zoom_in btn btn-default" monitor="control" control="zoom_in"><i class="fa fa-search-plus"></i></a>'
html += '<a title="'+lang['Zoom Out']+'" class="zoom_out btn btn-default" monitor="control" control="zoom_out"><i class="fa fa-search-minus"></i></a>'
html += '</div>'
html += '<div class="btn-group btn-group-sm btn-group-justified">'
html += '<a title="'+lang['Enable Nightvision']+'" class="nv_enable btn btn-default" monitor="control" control="enable_nv"><i class="fa fa-moon-o"></i></a>'
html += '<a title="'+lang['Disable Nightvision']+'" class="nv_disable btn btn-default" monitor="control" control="disable_nv"><i class="fa fa-sun-o"></i></a>'
html += '</div>'
html += '</div>'
e.p.append(html)
}
break;
case'watch':
if($("#monitor_live_"+e.mid+user.auth_token).length===0||$.ccio.mon[e.ke+e.mid+user.auth_token].watch!==1){
$.ccio.cx({f:'monitor',ff:'watch_on',id:e.mid},user)
}else{
$("#main_canvas").animate({scrollTop:$("#monitor_live_"+e.mid+user.auth_token).offset().top-($('#main_header').height()+10)},500);
}
break;
case'watch_off':
$.ccio.cx({f:'monitor',ff:'watch_off',id:e.mid},user)
break;
case'delete':
e.m=$('#confirm_window').modal('show');e.f=e.e.attr('file');
$.confirm.title.text(lang['Delete Monitor']+' : '+e.mon.name)
e.html=lang.DeleteMonitorText
e.html+='<table class="info-table table table-striped"><tr>';
$.each($.ccio.init('cleanMon',e.mon),function(n,v,g){
if(n==='host'&&v.indexOf('@')>-1){g=v.split('@')[1]}else{g=v};
try{JSON.parse(g);return}catch(err){}
e.html+='<tr><td><b>'+n+'</b></td><td>'+g+'</td></tr>';
})
e.html+='</tr></table>';
$.confirm.body.html(e.html)
$.confirm.click([
{
title:'Delete Monitor',
class:'btn-danger',
callback:function(){
$.get($.ccio.init('location',user)+user.auth_token+'/configureMonitor/'+user.ke+'/'+e.mon.mid+'/delete',function(d){
$.ccio.log(d)
})
}
},
{
title:'Delete Monitor and Files',
class:'btn-danger',
callback:function(){
$.get($.ccio.init('location',user)+user.auth_token+'/configureMonitor/'+user.ke+'/'+e.mon.mid+'/delete?deleteFiles=true',function(d){
$.ccio.log(d)
})
}
}
])
break;
case'edit':
e.p=$('#add_monitor'),e.mt=e.p.find('.modal-title')
e.p.find('.am_notice').hide()
e.p.find('[detailcontainer="detector_cascades"]').prop('checked',false).parents('.mdl-js-switch').removeClass('is-checked')
if(!$.ccio.mon[e.ke+e.mid+user.auth_token]){
e.p.find('.am_notice_new').show()
//new monitor
e.p.find('[monitor="delete"]').hide()
e.mt.find('span').text('Add'),e.mt.find('i').attr('class','fa fa-plus');
//default values
e.values=$.aM.generateDefaultMonitorSettings();
}else{
e.p.find('.am_notice_edit').show()
//edit monitor
e.p.find('[monitor="delete"]').show()
e.mt.find('span').text(lang.Edit);
e.mt.find('i').attr('class','fa fa-wrench');
e.values=$.ccio.mon[e.ke+e.mid+user.auth_token];
}
$.aM.selected=e.values;
// e.openTabs=$.ccio.op().tabsOpen
// if(e.openTabs[e.mid]){
// e.values=e.openTabs[e.mid]
// }
$.aM.import(e)
$('#add_monitor').modal('show')
break;
}
})
.on('dblclick','[type="password"],.password_field',function(){
var _this = $(this)
var type = 'password'
_this.addClass('password_field')
if(_this.attr('type') === 'password'){
type = 'text'
}
_this.attr('type',type)
})
$('.modal').on('hidden.bs.modal',function(){
$(this).find('video').remove();
$(this).find('iframe').attr('src','about:blank');
});
$('.modal').on('shown.bs.modal',function(){
e={e:$(this).find('.flex-container-modal-body')}
if(e.e.length>0){
e.e.resize()
}
});
$('body')
.on('click','.scrollTo',function(ee){
ee.preventDefault()
var e = {e:$(this)};
e.parent=e.e.attr('scrollToParent')
if(!e.parent){
e.parent='body,html'
}
$(e.parent).animate({
scrollTop: $(e.e.attr('href')).position().top
}, 400);
})
.on('resize','.flex-container-modal-body',function(e){
e=$(this)
e.find('.flex-modal-block').css('height',e.height())
})
.on('resize','#monitors_live .monitor_item',function(e){
e.e=$(this).find('.stream-block');
e.c=e.e.find('canvas');
e.c.attr('height',e.e.height());
e.c.attr('width',e.e.width());
})
.on('keyup','.search-parent .search-controller',function(){
_this = this;
$.each($(".search-parent .search-body .search-row"), function() {
if($(this).text().toLowerCase().indexOf($(_this).val().toLowerCase()) === -1)
$(this).hide();
else
$(this).show();
});
})
.on('dblclick','.stream-hud',function(){
$(this).parents('[mid]').find('[monitor="fullscreen"]').click();
})
//.on('mousemove',".magnifyStream",$.ccio.magnifyStream)
//.on('touchmove',".magnifyStream",$.ccio.magnifyStream);
})

View File

@ -0,0 +1,61 @@
$(document).ready(function(e){
//monitor grid
$.grid={e:$('#monitors_live')}
$.grid.data = function(){
return $.grid.e.data('gridstack')
}
$.grid.getMonitorsPerRow = function(){
var x
switch($.ccio.op().montage){
case'1':
x = '12'
break;
case'2':
x = '6'
break;
case'3':
x = '4'
break;
case'4':
x = '3'
break;
case'5':
x = '5'
break;
case'6':
x = '2'
break;
default://3
x = '4'
break;
}
return x
}
$.grid.saveElementPositions = function() {
var monitors = {}
$.grid.e.find(" .monitor_item").each(function(n,v){
var el = $(v)
var item = {}
item.ke = el.attr('ke')
item.mid = el.attr('mid')
item.x = el.attr('data-gs-x')
item.y = el.attr('data-gs-y')
item.height = el.attr('data-gs-height')
item.width = el.attr('data-gs-width')
monitors[item.ke+item.mid] = item
})
$user.details.monitorOrder=monitors;
$.ccio.cx({f:'monitorOrder',monitorOrder:monitors})
}
$.grid.e
.gridstack({
cellHeight: 80,
verticalMargin: 0,
})
.on('dragstop', function(event,ui){
setTimeout(function(){
$.grid.saveElementPositions()
},700)
})
.on('gsresizestop', $.grid.saveElementPositions);
})

612
web/libs/js/dash2.init.js Normal file
View File

@ -0,0 +1,612 @@
$.ccio.init=function(x,d,user,k){
if(!k){k={}};k.tmp='';
if(d&&d.user){
user=d.user
}
if(!user){
user=$user
}
switch(x){
case'cleanMon':
var acceptedFields = [
'mid',
'ke',
'name',
'shto',
'shfr',
'details',
'type',
'ext',
'protocol',
'host',
'path',
'port',
'fps',
'mode',
'width',
'height'
]
var row = {};
$.each(d,function(m,b){
if(acceptedFields.indexOf(m)>-1){
row[m]=b;
}
})
return row
break;
case'cleanMons':
if(d==='object'){
var arr={}
}else{
var arr=[]
}
$.each($.ccio.mon,function(n,v){
var row = $.ccio.init('cleanMon',v)
if(d==='object'){
arr[n]=row
}else{
arr.push(row)
}
})
return arr;
break;
case'location':
var url
if(d&&d.info&&d.info.URL){
url=d.info.URL
if(url.charAt(url.length-1)!=='/'){
url=url+'/'
}
}else{
url = $.ccio.libURL
}
return url
break;
case'videoUrlBuild':
var url
if(d.href){
url = d.href
}else if(!d.href && d.hrefNoAuth){
url = $.ccio.init('location',user)+user.auth_token+d.hrefNoAuth
}
if(user!==$user&&url.charAt(0)==='/'){
url = $.ccio.init('location',user)+d.href.substring(1)
}
return url
break;
case'videoHrefToDelete':
var urlSplit = d.split('?')
var url = urlSplit[0]+'/delete'
if(urlSplit[1])url += '?' + urlSplit[1]
return url
break;
case'videoHrefToUnread':
var urlSplit = d.split('?')
var url = urlSplit[0]+'/status/1'
if(urlSplit[1])url += '?' + urlSplit[1]
return url
break;
case'videoHrefToRead':
var urlSplit = d.split('?')
var url = urlSplit[0]+'/status/2'
if(urlSplit[1])url += '?' + urlSplit[1]
return url
break;
// case'streamWindow':
// return $('.monitor_item[mid="'+d.id+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"]')
// break;
case'streamMotionDetectRestart':
$.ccio.init('streamMotionDetectOff',d,user)
$.ccio.init('streamMotionDetectOn',d,user)
break;
case'streamMotionDetectOff':
d.mon.motionDetectionRunning = false
$('.monitor_item[mid="'+d.mid+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"]').find('.stream-detected-object,.zoomGlass').remove()
clearInterval(d.mon.motionDetector)
break;
case'streamMotionDetectOn':
switch(JSON.parse(d.mon.details).stream_type){
case'hls':case'flv':case'mp4':
//pass
break;
default:
return $.ccio.init('note',{title:'Client-side Detector',text:'Could not be started. Only <b>FLV</b> and <b>HLS</b> can use this feature.',type:'error'});
break;
}
d.mon.motionDetectorNextDraw = true
d.mon.motionDetectionRunning = true
$.ccio.snapshot(d,function(url){
$('#temp').html('<img>')
var img=$('#temp img')[0]
img.onload=function(){
var frameNumber = 0,
mainWindow = $('.monitor_item[mid="'+d.mid+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"]'),
blenderCanvas = mainWindow.find(".blenderCanvas"),
motionVision = mainWindow.find(".motionVision"),
streamElement = mainWindow.find('.stream-element'),
streamElementTag = streamElement[0],
lastURL = null,
currentImage = null,
f = [],
drawMatrices = {
e:mainWindow,
monitorDetails:JSON.parse(d.mon.details),
stream:streamElement,
streamObjects:mainWindow.find('.stream-objects'),
details:{
name:'clientSideDetection',
}
};
widthRatio = streamElement.width() / img.width
heightRatio = streamElement.height() / img.height
drawMatrices.monitorDetails.detector_scale_x = img.width;
drawMatrices.monitorDetails.detector_scale_y = img.height;
function checkForMotion() {
blenderCanvas.width = img.width;
blenderCanvas.height = img.height;
blenderCanvasContext.drawImage(streamElementTag, 0, 0);
f[frameNumber] = blenderCanvasContext.getImageData(0, 0, blenderCanvas.width, blenderCanvas.height);
frameNumber = 0 == frameNumber ? 1 : 0;
currentImage = blenderCanvasContext.getImageData(0, 0, blenderCanvas.width, blenderCanvas.height);
foundPixels = [];
for (var currentImageLength = currentImage.data.length * 0.25, b = 0; b < currentImageLength;){
var pos = b * 4
currentImage.data[pos] = .5 * (255 - currentImage.data[pos]) + .5 * f[frameNumber].data[pos];
currentImage.data[pos + 1] = .5 * (255 - currentImage.data[pos + 1]) + .5 * f[frameNumber].data[pos + 1];
currentImage.data[pos + 2] = .5 * (255 - currentImage.data[pos + 2]) + .5 * f[frameNumber].data[pos + 2];
currentImage.data[pos + 3] = 255;
var score = (currentImage.data[pos] + currentImage.data[pos + 1] + currentImage.data[pos + 2]) / 3;
if(score>170){
var x = (pos / 4) % img.width;
var y = Math.floor((pos / 4) / img.width);
foundPixels.push([x,y])
}
b += 4;
}
var groupedPoints = Object.assign({},Cluster);
groupedPoints.iterations(25);
groupedPoints.data(foundPixels);
var groupedPoints = groupedPoints.clusters()
drawMatrices.details.matrices=[]
var mostHeight = 0;
var mostWidth = 0;
var mostWithMotion = null;
groupedPoints.forEach(function(v,n){
var matrix = {
topLeft:[img.width,img.height],
topRight:[0,img.height],
bottomRight:[0,0],
bottomLeft:[img.width,0],
}
v.points.forEach(function(b){
var x = b[0]
var y = b[1]
if(x<matrix.topLeft[0])matrix.topLeft[0]=x;
if(y<matrix.topLeft[1])matrix.topLeft[1]=y;
//Top Right point
if(x>matrix.topRight[0])matrix.topRight[0]=x;
if(y<matrix.topRight[1])matrix.topRight[1]=y;
//Bottom Right point
if(x>matrix.bottomRight[0])matrix.bottomRight[0]=x;
if(y>matrix.bottomRight[1])matrix.bottomRight[1]=y;
//Bottom Left point
if(x<matrix.bottomLeft[0])matrix.bottomLeft[0]=x;
if(y>matrix.bottomLeft[1])matrix.bottomLeft[1]=y;
})
matrix.x = matrix.topLeft[0];
matrix.y = matrix.topLeft[1];
matrix.width = matrix.topRight[0] - matrix.topLeft[0]
matrix.height = matrix.bottomLeft[1] - matrix.topLeft[1]
if(matrix.width>mostWidth&&matrix.height>mostHeight){
mostWidth = matrix.width;
mostHeight = matrix.height;
mostWithMotion = matrix;
}
drawMatrices.details.matrices.push(matrix)
})
$.ccio.magnifyStream({
p:mainWindow,
useCanvas:true,
zoomAmount:1,
auto:true,
animate:true,
pageX:((mostWithMotion.width / 2) + mostWithMotion.x) * widthRatio,
pageY:((mostWithMotion.height / 2) + mostWithMotion.y) * heightRatio
})
$.ccio.init('drawMatrices',drawMatrices)
if(d.mon.motionDetectorNextDraw===true){
clearTimeout(d.mon.motionDetectorNextDrawTimeout)
d.mon.motionDetectorNextDrawTimeout=setTimeout(function(){
d.mon.motionDetectorNextDraw = true;
},1000)
d.mon.motionDetectorNextDraw = false;
// console.log({
// p:mainWindow,
// pageX:((matrix.width / 2) + matrix.x) * widthRatio,
// pageY:((matrix.height / 2) + matrix.y) * heightRatio
// })
}
return drawMatrices.details.matrices;
}
if(blenderCanvas.length === 0){
mainWindow.append('<div class="zoomGlass"><canvas class="blenderCanvas"></canvas></div>')
blenderCanvas = mainWindow.find(".blenderCanvas")
}
blenderCanvas = blenderCanvas[0];
var blenderCanvasContext = blenderCanvas.getContext("2d");
clearInterval(d.mon.motionDetector)
d.mon.motionDetector = setInterval(checkForMotion,2000)
}
img.src=url
})
break;
case'streamURL':
var streamURL
switch(JSON.parse(d.details).stream_type){
case'jpeg':
streamURL=$.ccio.init('location',user)+user.auth_token+'/jpeg/'+d.ke+'/'+d.mid+'/s.jpg'
break;
case'mjpeg':
streamURL=$.ccio.init('location',user)+user.auth_token+'/mjpeg/'+d.ke+'/'+d.mid
break;
case'hls':
streamURL=$.ccio.init('location',user)+user.auth_token+'/hls/'+d.ke+'/'+d.mid+'/s.m3u8'
break;
case'flv':
streamURL=$.ccio.init('location',user)+user.auth_token+'/flv/'+d.ke+'/'+d.mid+'/s.flv'
break;
case'h265':
streamURL=$.ccio.init('location',user)+user.auth_token+'/h265/'+d.ke+'/'+d.mid+'/s.hevc'
break;
case'mp4':
streamURL=$.ccio.init('location',user)+user.auth_token+'/mp4/'+d.ke+'/'+d.mid+'/s.mp4'
break;
case'b64':
streamURL='Websocket'
break;
case'pam':
streamURL='Websocket'
break;
}
return streamURL
break;
case'humanReadMode':
switch(d){
case'idle':
k.mode=lang['Idle']
break;
case'stop':
k.mode=lang['Disabled']
break;
case'record':
k.mode=lang['Record']
break;
case'start':
k.mode=lang['Watch Only']
break;
}
return k.mode
break;
case'monitorInfo':
d.e=$('.glM'+d.mon.mid+user.auth_token);
if(JSON.parse(d.mon.details).vcodec!=='copy'&&d.mon.mode=='record'){
d.e.find('.monitor_not_record_copy').show()
}else{
d.e.find('.monitor_not_record_copy').hide()
}
d.e.find('.monitor_name').text(d.mon.name)
d.e.find('.monitor_mid').text(d.mon.mid)
d.e.find('.monitor_ext').text(d.mon.ext);
d.mode=$.ccio.init('humanReadMode',d.mon.mode,user)
d.e.find('.monitor_mode').text(d.mode)
d.e.find('.monitor_status').text(d.status)
d.e.attr('mode',d.mode)
d.e.find('.lamp').attr('title',d.mode)
break;
case'fullscreen':
if (d.requestFullscreen) {
d.requestFullscreen();
} else if (d.mozRequestFullScreen) {
d.mozRequestFullScreen();
} else if (d.webkitRequestFullscreen) {
d.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
}
break;
case'drawPoints':
d.height=d.stream.height()
d.width=d.stream.width()
if(d.monitorDetails.detector_scale_x===''){d.monitorDetails.detector_scale_x=320}
if(d.monitorDetails.detector_scale_y===''){d.monitorDetails.detector_scale_y=240}
d.widthRatio=d.width/d.monitorDetails.detector_scale_x
d.heightRatio=d.height/d.monitorDetails.detector_scale_y
d.streamObjects.find('.stream-detected-point[name="'+d.details.name+'"]').remove()
d.tmp=''
$.each(d.details.points,function(n,v){
d.tmp+='<div class="stream-detected-point" name="'+d.details.name+'" style="height:'+1+'px;width:'+1+'px;top:'+(d.heightRatio*v.x)+'px;left:'+(d.widthRatio*v.y)+'px;">'
if(v.tag){d.tmp+='<span class="tag">'+v.tag+'</span>'}
d.tmp+='</div>'
})
d.streamObjects.append(d.tmp)
break;
case'drawMatrices':
d.height=d.stream.height()
d.width=d.stream.width()
if(d.monitorDetails.detector_scale_x===''){d.monitorDetails.detector_scale_x=320}
if(d.monitorDetails.detector_scale_y===''){d.monitorDetails.detector_scale_y=240}
d.widthRatio=d.width/d.monitorDetails.detector_scale_x
d.heightRatio=d.height/d.monitorDetails.detector_scale_y
d.streamObjects.find('.stream-detected-object[name="'+d.details.name+'"]').remove()
d.tmp=''
$.each(d.details.matrices,function(n,v){
d.tmp+='<div class="stream-detected-object" name="'+d.details.name+'" style="height:'+(d.heightRatio*v.height)+'px;width:'+(d.widthRatio*v.width)+'px;top:'+(d.heightRatio*v.y)+'px;left:'+(d.widthRatio*v.x)+'px;">'
if(v.tag){d.tmp+='<span class="tag">'+v.tag+'</span>'}
d.tmp+='</div>'
})
d.streamObjects.append(d.tmp)
break;
case'clearTimers':
if(!d.mid){d.mid=d.id}
if($.ccio.mon[d.ke+d.mid+user.auth_token]){
clearTimeout($.ccio.mon[d.ke+d.mid+user.auth_token]._signal);
clearInterval($.ccio.mon[d.ke+d.mid+user.auth_token].hlsGarbageCollectorTimer)
clearTimeout($.ccio.mon[d.ke+d.mid+user.auth_token].jpegInterval);
clearInterval($.ccio.mon[d.ke+d.mid+user.auth_token].signal);
clearInterval($.ccio.mon[d.ke+d.mid+user.auth_token].m3uCheck);
if($.ccio.mon[d.ke+d.mid+user.auth_token].Base64 && $.ccio.mon[d.ke+d.mid+user.auth_token].Base64.connected){
$.ccio.mon[d.ke+d.mid+user.auth_token].Base64.disconnect()
}
if($.ccio.mon[d.ke+d.mid+user.auth_token].Poseidon){
$.ccio.mon[d.ke+d.mid+user.auth_token].Poseidon.stop()
}
}
break;
case'note':
k.o=$.ccio.op().switches
if(k.o&&k.o.notifyHide!==1){
new PNotify(d)
if(user.details.audio_note && user.details.audio_note !== ''){
var audio = new Audio('libs/audio/'+user.details.audio_note);
audio.play()
}
}
break;
case'monGroup':
$.ccio.mon_groups={};
$.each($.ccio.mon,function(n,v,x){
if(typeof v.details==='string'){
k.d=JSON.parse(v.details)
}else{
k.d=v.details
}
try{
k.groups=JSON.parse(k.d.groups)
$.each(k.groups,function(m,b){
if(!$.ccio.mon_groups[b])$.ccio.mon_groups[b]={}
$.ccio.mon_groups[b][v.mid]=v;
})
}catch(er){
}
})
return $.ccio.mon_groups;
break;
case'closeVideo':
var el = $('#monitor_live_'+d.mid+user.auth_token)
var video = el.find('video')
if(video.length === 1){
if(!video[0].paused){
video[0].onerror = function(){}
video[0].pause()
}
video.prop('src','');
video.find('source').remove();
video.remove();
}
break;
case'jpegModeStop':
clearTimeout($.ccio.mon[d.ke+d.mid+user.auth_token].jpegInterval);
delete($.ccio.mon[d.ke+d.mid+user.auth_token].jpegInterval);
$('#monitor_live_'+d.mid+user.auth_token+' .stream-element').unbind('load')
break;
case'jpegMode':
if(d.watch===1){
k=JSON.parse(d.details);
k.jpegInterval=parseFloat(k.jpegInterval);
if(!k.jpegInterval||k.jpegInterval===''||isNaN(k.jpegInterval)){k.jpegInterval=1}
$.ccio.tm('stream-element',$.ccio.mon[d.ke+d.mid+user.auth_token]);
k.e=$('#monitor_live_'+d.mid+user.auth_token+' .stream-element');
$.ccio.init('jpegModeStop',d,user);
k.run=function(){
k.e.attr('src',$.ccio.init('location',user)+user.auth_token+'/jpeg/'+d.ke+'/'+d.mid+'/s.jpg?time='+(new Date()).getTime())
}
k.e.load(function(){
$.ccio.mon[d.ke+d.mid+user.auth_token].jpegInterval=setTimeout(k.run,1000/k.jpegInterval);
}).error(function(){
$.ccio.mon[d.ke+d.mid+user.auth_token].jpegInterval=setTimeout(k.run,1000/k.jpegInterval);
})
k.run()
};
break;
case'jpegModeAll':
$.each($.ccio.mon,function(n,v){
$.ccio.init('jpegMode',v,user)
});
break;
case'getLocation':
var l = document.createElement("a");
l.href = d;
return l;
break;
case 'ls'://livestamp all
g={e:jQuery('.livestamp')};
g.e.each(function(){g.v=jQuery(this),g.t=g.v.attr('title');if(!g.t){return};g.v.toggleClass('livestamp livestamped').attr('title',$.ccio.init('t',g.t,user)).livestamp(g.t);})
return g.e
break;
case't'://format time
if(!d){d=new Date();}
return $.ccio.timeObject(d).format('YYYY-MM-DD HH:mm:ss')
break;
case'th'://format time hy
if(!d){d=new Date();}
return $.ccio.timeObject(d).format('YYYY-MM-DDTHH:mm:ss')
break;
case'tf'://time to filename
if(!d){d=new Date();}
return $.ccio.timeObject(d).format('YYYY-MM-DDTHH-mm-ss')
break;
case'fn'://row to filename
return $.ccio.init('tf',d.time,user)+'.'+d.ext
break;
case'filters':
k.tmp='<option value="" selected>'+lang['Add New']+'</option>';
$.each(user.details.filters,function(n,v){
k.tmp+='<option value="'+v.id+'">'+v.name+'</option>'
});
$('#saved_filters').html(k.tmp)
break;
case'id':
$('.usermail').html(d.mail)
try{k.d=JSON.parse(d.details);}catch(er){k.d=d.details;}
try{user.mon_groups=JSON.parse(k.d.mon_groups);}catch(er){}
if(!user.mon_groups)user.mon_groups={};
$.sM.reDrawMonGroups()
$.each(user,function(n,v){$.sM.e.find('[name="'+n+'"]').val(v).change()})
$.each(k.d,function(n,v){$.sM.e.find('[detail="'+n+'"]').val(v).change()})
$.gR.drawList();
$.ccio.pm('link-set',k.d.links,null,user)
break;
case'jsontoblock'://draw json as block
if(d instanceof Object){
$.each(d,function(n,v){
k.tmp+='<div>';
k.tmp+='<b>'+n+'</b> : '+$.ccio.init('jsontoblock',v,user);
k.tmp+='</div>';
})
}else{
k.tmp+='<span>';
k.tmp+=d;
k.tmp+='</span>';
}
break;
case'url':
var porty
if(d.port && d.port !== ''){
porty = ':' + d.port
}else{
porty = ''
}
d.url = d.protocol + '://' + d.host + porty
return d.url
break;
case'data-video':
if(!d){
$('[data-mid]').each(function(n,v){
v=$(v);v.attr('mid',v.attr('data-mid'))
});
$('[data-ke]').each(function(n,v){
v=$(v);v.attr('ke',v.attr('data-ke'))
});
$('[data-file]').each(function(n,v){
v=$(v);v.attr('file',v.attr('data-file'))
});
$('[data-status]').each(function(n,v){
v=$(v);v.attr('status',v.attr('data-status'))
});
$('[data-auth]').each(function(n,v){
v=$(v);v.attr('auth',v.attr('data-auth'))
});
}else{
$('[data-ke="'+d.ke+'"][data-mid="'+d.mid+'"][data-file="'+d.filename+'"][auth="'+user.auth_token+'"]').attr('mid',d.mid).attr('ke',d.ke).attr('status',d.status).attr('file',d.filename).attr('auth',user.auth_token);
}
break;
case'signal':
d.mon=$.ccio.mon[d.ke+d.id+user.auth_token];d.e=$('#monitor_live_'+d.id+user.auth_token+' .signal').addClass('btn-success').removeClass('btn-danger');d.signal=parseFloat(JSON.parse(d.mon.details).signal_check);
if(!d.signal||d.signal==NaN){d.signal=10;};d.signal=d.signal*1000*60;
clearTimeout($.ccio.mon[d.ke+d.id+user.auth_token]._signal);$.ccio.mon[d.ke+d.id+user.auth_token]._signal=setTimeout(function(){d.e.addClass('btn-danger').removeClass('btn-success');},d.signal)
break;
case'signal-check':
try{
d.mon=$.ccio.mon[d.ke+d.id+user.auth_token];d.p=$('#monitor_live_'+d.id+user.auth_token);
try{d.d=JSON.parse(d.mon.details)}catch(er){d.d=d.mon.details;}
d.check={c:0};
d.fn=function(){
if(!d.speed){d.speed=1000}
switch(d.d.stream_type){
case'b64':case'h265':
d.p.resize()
break;
case'hls':case'flv':case'mp4':
if(d.p.find('video')[0].paused){
if(d.d.signal_check_log==1){
d.log={type:'Stream Check',msg:lang.clientStreamFailedattemptingReconnect}
$.ccio.tm(4,d,'#logs,.monitor_item[mid="'+d.id+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"] .logs')
}
$.ccio.cx({f:'monitor',ff:'watch_on',id:d.id},user);
}else{
if(d.d.signal_check_log==1){
d.log={type:'Stream Check',msg:'Success'}
$.ccio.tm(4,d,'#logs,.monitor_item[mid="'+d.id+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"] .logs')
}
$.ccio.init('signal',d,user);
}
break;
default:
if($.ccio.op().jpeg_on===true){return}
$.ccio.snapshot(d,function(url){
d.check.f=url;
setTimeout(function(){
$.ccio.snapshot(d,function(url){
if(d.check.f===url){
if(d.check.c<3){
++d.check.c;
setTimeout(function(){
d.fn();
},d.speed)
}else{
if(d.d.signal_check_log==1){
d.log={type:'Stream Check',msg:'Client side ctream check failed, attempting reconnect.'}
$.ccio.tm(4,d,'#logs,.monitor_item[mid="'+d.id+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"] .logs')
}
delete(d.check)
$.ccio.cx({f:'monitor',ff:'watch_on',id:d.id},user);
}
}else{
if(d.d.signal_check_log==1){
d.log={type:'Stream Check',msg:'Success'}
$.ccio.tm(4,d,'#logs,.monitor_item[mid="'+d.id+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"] .logs')
}
delete(d.check)
$.ccio.init('signal',d,user);
}
});
},d.speed)
});
break;
}
}
d.fn();
}catch(er){
er=er.stack;
d.in=function(x){return er.indexOf(x)>-1}
switch(true){
case d.in("The HTMLImageElement provided is in the 'broken' state."):
delete(d.check)
$.ccio.cx({f:'monitor',ff:'watch_on',id:d.id},user);
break;
default:
$.ccio.log('signal-check',er)
break;
}
clearInterval($.ccio.mon[d.ke+d.id+user.auth_token].signal);delete($.ccio.mon[d.ke+d.id+user.auth_token].signal);
}
break;
}
return k.tmp;
}

View File

@ -0,0 +1,66 @@
$(document).ready(function(e){
//log viewer
$.log = {
e : $('#logs_modal'),
lm : $('#log_monitors'),
dateRange : $('#logs_daterange'),
loaded : {}
}
$.log.dateRange.daterangepicker({
startDate:$.ccio.timeObject().subtract(moment.duration("5:00:00")),
endDate:$.ccio.timeObject().add(moment.duration("24:00:00")),
timePicker: true,
timePicker24Hour: true,
timePickerSeconds: true,
timePickerIncrement: 30,
locale: {
format: 'MM/DD/YYYY h:mm A'
}
},function(start, end, label){
//change daterange
$.log.lm.change()
});
$.log.table = $.log.e.find('table')
$.log.e.on('shown.bs.modal', function () {
$.log.lm.find('option:not(.hard)').remove()
$.each($.ccio.mon,function(n,v){
v.id = v.mid
$.ccio.tm('option',v,'#log_monitors')
})
$.log.lm.change()
})
$.log.lm.change(function(){
e = {}
e.v = $(this).val();
e.urlSelector = e.v+'';
if(e.v === 'all'){
e.urlSelector = ''
}
e.dateRange = $.log.dateRange.data('daterangepicker');
$.log.loaded.startDate = e.dateRange.startDate
$.log.loaded.endDate = e.dateRange.endDate
var url = $.ccio.init('location',$user)+$user.auth_token+'/logs/'+$user.ke+'/'+e.urlSelector+'?start='+$.ccio.init('th',$.log.loaded.startDate)+'&end='+$.ccio.init('th',$.log.loaded.endDate)
$.get(url,function(d){
$.log.loaded.url = url
$.log.loaded.query = e.v
$.log.loaded.rows = d
e.tmp='';
if(d.length === 0){
e.tmp = '<tr class="text-center"><td>'+lang.NoLogsFoundForDateRange+'</td></tr>'
}else{
$.each(d,function(n,v){
e.tmp+='<tr class="search-row"><td title="'+v.time+'" class="livestamp"></td><td>'+v.time+'</td><td>'+v.mid+'</td><td>'+$.ccio.init('jsontoblock',v.info)+'</td></tr>'
})
}
$.log.table.find('tbody').html(e.tmp)
// $.log.table.bootstrapTable()
$.ccio.init('ls')
})
})
$.log.e.find('[download]').click(function(){
$.ccio.downloadJSON($.log.loaded,'Shinobi_Logs_'+(new Date())+'.json',{
title : 'No Logs Found',
text : 'No file will be downloaded.',
})
})
})

View File

@ -0,0 +1,773 @@
$(document).ready(function(e){
//Monitor Editor
$.aM={e:$('#add_monitor'),monitorsForCopy:$('#copy_settings_monitors')};
$.aM.f=$.aM.e.find('form')
$.aM.channels=$('#monSectionStreamChannels')
$.aM.maps=$('#monSectionInputMaps')
$.aM.e.find('.follow-list ul').affix();
$.each($.ccio.definitions["Monitor Settings"].blocks,function(n,v){
$.each(v.info,function(m,b){
if(!b.name){
console.log(b)
return
}
if(b.name.indexOf('detail=')>-1){
b.name=b.name.replace('detail=','')
v.element=$.aM.e.find('[detail="'+b.name+'"]')
}else{
v.element=$.aM.e.find('[name="'+b.name+'"]')
}
v.parent=v.element.parents('.form-group').find('label div:first-child span')
v.parent.find('small').remove()
v.parent.append('<small class="hover">'+b.description+'</small>')
})
})
$.aM.generateDefaultMonitorSettings=function(){
return {
"mode": "start",
"mid": $.ccio.gid(),
"name": "Some Stream",
"type": "h264",
"protocol": "rtsp",
"host": "",
"port": "",
"path": "",
"ext": "mp4",
"fps": "1",
"width": "640",
"height": "480",
"details": JSON.stringify({
"fatal_max": "0",
"notes": "",
"dir": "",
"auto_host_enable": "1",
"auto_host": "",
"rtsp_transport": "tcp",
"muser": "",
"mpass": "",
"port_force": "0",
"aduration": "1000000",
"probesize": "1000000",
"stream_loop": "0",
"sfps": "",
"accelerator": "0",
"hwaccel": "auto",
"hwaccel_vcodec": "",
"hwaccel_device": "",
"stream_type": "mp4",
"stream_flv_type": "ws",
"stream_mjpeg_clients": "",
"stream_vcodec": "copy",
"stream_acodec": "no",
"hls_time": "2",
"preset_stream": "ultrafast",
"hls_list_size": "3",
"signal_check": "10",
"signal_check_log": "0",
"stream_quality": "15",
"stream_fps": "2",
"stream_scale_x": "",
"stream_scale_y": "",
"rotate_stream": "no",
"svf": "",
"rtmp_vcodec": "h264",
"rtmp_acodec": "aac",
"stream_timestamp": "0",
"stream_timestamp_font": "",
"stream_timestamp_font_size": "",
"stream_timestamp_color": "",
"stream_timestamp_box_color": "",
"stream_timestamp_x": "",
"stream_timestamp_y": "",
"stream_watermark": "0",
"stream_watermark_location": "",
"stream_watermark_position": "tr",
"snap": "0",
"snap_fps": "",
"snap_scale_x": "",
"snap_scale_y": "",
"snap_vf": "",
"rawh264": "0",
"rawh264_vcodec": "copy",
"rawh264_acodec": "",
"rawh264_fps": "",
"rawh264_scale_x": "",
"rawh264_scale_y": "",
"rawh264_crf": "",
"rawh264_vf": "",
"vcodec": "copy",
"crf": "1",
"preset_record": "",
"acodec": "no",
"dqf": "0",
"cutoff": "15",
"rotate_record": "no",
"vf": "",
"timestamp": "0",
"timestamp_font": "",
"timestamp_font_size": "10",
"timestamp_color": "white",
"timestamp_box_color": "0x00000000@1",
"timestamp_x": "(w-tw)/2",
"timestamp_y": "0",
"watermark": "0",
"watermark_location": "",
"watermark_position": "tr",
"cust_input": "",
"cust_snap": "",
"cust_rawh264": "",
"cust_detect": "",
"cust_stream": "",
"cust_stream_server": "",
"cust_record": "",
"custom_output": "",
"detector": "0",
"detector_pam": "1",
"detector_webhook": "0",
"detector_webhook_url": "",
"detector_command_enable": "0",
"detector_command": "",
"detector_command_timeout": "",
"detector_lock_timeout": "",
"detector_save": "0",
"detector_frame_save": "0",
"detector_mail": "0",
"detector_mail_timeout": "",
"detector_record_method": "sip",
"detector_trigger": "1",
"detector_trigger_record_fps": "",
"detector_timeout": "10",
"watchdog_reset": "0",
"detector_delete_motionless_videos": "0",
"detector_send_frames": "1",
"detector_region_of_interest": "0",
"detector_fps": "",
"detector_scale_x": "640",
"detector_scale_y": "480",
"detector_use_motion": "1",
"detector_use_detect_object": "0",
"detector_frame": "0",
"detector_sensitivity": "",
"detector_max_sensitivity": "",
"detector_threshold": "1",
"detector_color_threshold": "",
"cords": "[]",
"detector_buffer_vcodec": "auto",
"detector_buffer_fps": "",
"detector_buffer_hls_time": "",
"detector_buffer_hls_list_size": "",
"detector_buffer_start_number": "",
"detector_buffer_live_start_index": "",
"detector_lisence_plate": "0",
"detector_lisence_plate_country": "us",
"detector_notrigger": "0",
"detector_notrigger_mail": "0",
"detector_notrigger_timeout": "",
"control": "0",
"control_base_url": "",
"control_stop": "0",
"control_url_stop_timeout": "",
"control_url_center": "",
"control_url_left": "",
"control_url_left_stop": "",
"control_url_right": "",
"control_url_right_stop": "",
"control_url_up": "",
"control_url_up_stop": "",
"control_url_down": "",
"control_url_down_stop": "",
"control_url_enable_nv": "",
"control_url_disable_nv": "",
"control_url_zoom_out": "",
"control_url_zoom_out_stop": "",
"control_url_zoom_in": "",
"control_url_zoom_in_stop": "",
"tv_channel": "0",
"groups": "[]",
"loglevel": "warning",
"sqllog": "0",
"detector_cascades": ""
}),
"shto": "[]",
"shfr": "[]"
}
}
$.aM.drawList=function(){
e={list:$.aM.e.find('.follow-list ul'),html:''}
$.aM.e.find('[section]:visible').each(function(n,v){
e.e=$(v)
e.id = e.e.attr('id');
e.title = e.e.find('h4').first().html();
var div = document.createElement('div');
div.innerHTML = e.title;
var elements = div.getElementsByTagName('a');
while (elements[0])
elements[0].parentNode.removeChild(elements[0])
var elements = div.getElementsByTagName('small');
while (elements[0])
elements[0].parentNode.removeChild(elements[0])
var repl = div.innerHTML;
e.html += '<li><a class="scrollTo" href="#'+e.id+'" scrollToParent="#add_monitor .modal-body">'+repl+'</a></li>'
})
e.list.html(e.html)
}
$.aM.import=function(e){
$.get($.ccio.init('location',$user)+$user.auth_token+'/hls/'+e.values.ke+'/'+e.values.mid+'/detectorStream.m3u8',function(data){
$('#monEditBufferPreview').html(data)
})
$.aM.e.find('.edit_id').text(e.values.mid);
$.aM.e.attr('mid',e.values.mid).attr('ke',e.values.ke).attr('auth',e.auth)
$.each(e.values,function(n,v){
$.aM.e.find('[name="'+n+'"]').val(v).change()
})
e.ss=JSON.parse(e.values.details);
//get maps
$.aM.maps.empty()
if(e.ss.input_maps&&e.ss.input_maps!==''){
var input_maps
try{
input_maps = JSON.parse(e.ss.input_maps)
}catch(er){
input_maps = e.ss.input_maps;
}
var mapContainers = $('[input-mapping]')
if(input_maps.length>0){
mapContainers.show()
$.each(input_maps,function(n,v){
var tempID = $.ccio.tm('input-map')
var parent = $('#monSectionMap'+tempID)
$.each(v,function(m,b){
parent.find('[map-detail="'+m+'"]').val(b).change()
})
})
}else{
mapContainers.hide()
}
}
//get channels
$.aM.channels.empty()
if(e.ss.stream_channels&&e.ss.stream_channels!==''){
var stream_channels
try{
stream_channels = JSON.parse(e.ss.stream_channels)
}catch(er){
stream_channels = e.ss.stream_channels;
}
$.each(stream_channels,function(n,v){
var tempID = $.ccio.tm('stream-channel')
var parent = $('#monSectionChannel'+tempID)
$.each(v,function(m,b){
parent.find('[channel-detail="'+m+'"]').val(b)
})
})
}
//get map choices for outputs
$('[input-mapping] .choices').empty()
if(e.ss.input_map_choices&&e.ss.input_map_choices!==''){
var input_map_choices
try{
input_map_choices = JSON.parse(e.ss.input_map_choices)
}catch(er){
input_map_choices = e.ss.input_map_choices;
}
$.each(input_map_choices,function(n,v){
$.each(v,function(m,b){
var parent = $('[input-mapping="'+n+'"] .choices')
$.ccio.tm('input-map-selector',b,parent)
})
})
}
$.aM.e.find('[detail]').each(function(n,v){
v=$(v).attr('detail');if(!e.ss[v]){e.ss[v]=''}
})
$.each(e.ss,function(n,v){
var theVal = v;
if(v instanceof Object){
theVal = JSON.stringify(v);
}
$.aM.e.find('[detail="'+n+'"]').val(theVal).change();
});
$.each(e.ss,function(n,v){
try{
var variable=JSON.parse(v)
}catch(err){
var variable=v
}
if(variable instanceof Object){
$('[detailContainer="'+n+'"][detailObject]').prop('checked',false)
$('[detailContainer="'+n+'"][detailObject]').parents('.mdl-js-switch').removeClass('is-checked')
if(variable instanceof Array){
$.each(variable,function(m,b,parentOfObject){
$('[detailContainer="'+n+'"][detailObject="'+b+'"]').prop('checked',true)
parentOfObject=$('[detailContainer="'+n+'"][detailObject="'+b+'"]').parents('.mdl-js-switch')
parentOfObject.addClass('is-checked')
})
}else{
$.each(variable,function(m,b){
if(typeof b ==='string'){
$('[detailContainer="'+n+'"][detailObject="'+m+'"]').val(b).change()
}else{
$('[detailContainer="'+n+'"][detailObject="'+m+'"]').prop('checked',true)
parentOfObject=$('[detailContainer="'+n+'"][detailObject="'+m+'"]').parents('.mdl-js-switch')
parentOfObject.addClass('is-checked')
}
})
}
}
});
try{
$.each(['groups','group_detector'],function(m,b){
var tmp=''
$.each($user.mon_groups,function(n,v){
tmp+='<li class="mdl-list__item">';
tmp+='<span class="mdl-list__item-primary-content">';
tmp+=v.name;
tmp+='</span>';
tmp+='<span class="mdl-list__item-secondary-action">';
tmp+='<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">';
tmp+='<input type="checkbox" '+b+' value="'+v.id+'" class="mdl-switch__input"';
if(!e.ss[b]){
e.ss[b]=[]
}
if(e.ss[b].indexOf(v.id)>-1){tmp+=' checked';}
tmp+=' />';
tmp+='</label>';
tmp+='</span>';
tmp+='</li>';
})
$('#monitor_'+b).html(tmp)
})
componentHandler.upgradeAllRegistered()
}catch(er){
console.log(er)
//no group, this 'try' will be removed in future.
};
$('#copy_settings').val('0').change()
var tmp = '';
$.each($.ccio.mon,function(n,v){
if(v.ke === $user.ke){
tmp += $.ccio.tm('option',{auth_token:$user.auth_token,id:v.mid,name:v.name},null,$user);
}
})
$.aM.monitorsForCopy.find('optgroup').html(tmp)
setTimeout(function(){$.aM.drawList()},1000)
}
//parse "Automatic" field in "Input" Section
$.aM.e.on('change','.auto_host_fill input,.auto_host_fill select',function(e){
var theSwitch = $.aM.e.find('[detail="auto_host_enable"]').val()
if(!theSwitch||theSwitch===''){
theSwitch='1'
}
if(theSwitch==='1'){
return
}
if($.aM.e.find('[name="host"]').val() !== ''){
$.aM.e.find('[detail="auto_host"]').val($.aM.buildMonitorURL())
}
})
$.aM.e.on('change','[detail="auto_host"]',function(e){
var isRTSP = false
var inputType = $.aM.e.find('[name="type"]').val()
var url = $(this).val()
var theSwitch = $.aM.e.find('[detail="auto_host_enable"]')
var disabled = theSwitch.val()
if(!disabled||disabled===''){
//if no value, then probably old version of monitor config. Set to Manual to avoid confusion.
disabled='0'
theSwitch.val('0').change()
}
if(disabled==='0'){
return
}
if(inputType === 'local'){
$.aM.e.find('[name="path"]').val(url).change()
}else{
var urlSplitByDots = url.split('.')
var has = function(query,searchIn){if(!searchIn){searchIn=url;};return url.indexOf(query)>-1}
var protocol = url.split('://')[0]
console.log(url.split('://'))
//switch RTSP, RTMP and RTMPS to parse URL
if(has('rtsp://')){
isRTSP = true;
url = url.replace('rtsp://','http://')
}
if(has('rtmp://')){
isRTMP = true;
url = url.replace('rtmp://','http://')
}
if(has('rtmps://')){
isRTMPS = true;
url = url.replace('rtmps://','http://')
}
//parse URL
var parsedURL = document.createElement('a');
parsedURL.href = url;
var pathname = parsedURL.pathname
if(url.indexOf('?') > -1){
pathname += '?'+url.split('?')[1]
}
$.aM.e.find('[name="protocol"]').val(protocol).change()
if(isRTSP){
$.aM.e.find('[detail="rtsp_transport"]').val('tcp').change()
$.aM.e.find('[detail="aduration"]').val(1000000).change()
$.aM.e.find('[detail="probesize"]').val(1000000).change()
}
$.aM.e.find('[detail="muser"]').val(parsedURL.username).change()
$.aM.e.find('[detail="mpass"]').val(parsedURL.password).change()
$.aM.e.find('[name="host"]').val(parsedURL.hostname).change()
$.aM.e.find('[name="port"]').val(parsedURL.port).change()
$.aM.e.find('[name="path"]').val(pathname).change()
delete(parsedURL)
}
})
$.aM.e.find('.refresh_cascades').click(function(e){
$.ccio.cx({f:'ocv_in',data:{f:'refreshPlugins',ke:$user.ke}})
})
$.aM.f.submit(function(ee){
ee.preventDefault();
e={e:$(this)};
e.s=e.e.serializeObject();
e.er=[];
$.each(e.s,function(n,v){e.s[n]=v.trim()});
e.s.mid=e.s.mid.replace(/[^\w\s]/gi,'').replace(/ /g,'')
if(e.s.mid.length<3){e.er.push('Monitor ID too short')}
if(e.s.port==''){
if(e.s.protocol === 'https'){
e.s.port = 443
}else{
e.s.port = 80
}
}
if(e.s.name==''){e.er.push('Monitor Name cannot be blank')}
// if(e.s.protocol=='rtsp'){e.s.ext='mp4',e.s.type='rtsp'}
if(e.er.length>0){
$.sM.e.find('.msg').html(e.er.join('<br>'));
$.ccio.init('note',{title:'Configuration Invalid',text:e.er.join('<br>'),type:'error'});
return;
}
$.post($.ccio.init('location',$user)+$user.auth_token+'/configureMonitor/'+$user.ke+'/'+e.s.mid,{data:JSON.stringify(e.s)},function(d){
$.ccio.log(d)
})
//
if($('#copy_settings').val() === '1'){
e.s.details = JSON.parse(e.s.details);
var copyMonitors = $.aM.monitorsForCopy.val();
var chosenSections = [];
var chosenMonitors = {};
if(!copyMonitors||copyMonitors.length===0){
$.ccio.init('note',{title:lang['No Monitors Selected'],text:lang.monSavedButNotCopied})
return
}
$.aM.e.find('[copy]').each(function(n,v){
var el = $(v)
if(el.val() === '1'){
chosenSections.push(el.attr('copy'))
}
})
var alterSettings = function(settingsToAlter,monitor){
monitor.details = JSON.parse(monitor.details);
$.aM.e.find(settingsToAlter).find('input,select,textarea').each(function(n,v){
var el = $(v);
var name = el.attr('name')
var detail = el.attr('detail')
var value
switch(true){
case !!name:
var value = e.s[name]
monitor[name] = value;
break;
case !!detail:
detail = detail.replace('"','')
var value = e.s.details[detail]
monitor.details[detail] = value;
break;
}
})
monitor.details = JSON.stringify(monitor.details);
return monitor;
}
$.each(copyMonitors,function(n,id){
var monitor
if(id === '$New'){
monitor = $.aM.generateDefaultMonitorSettings();
//connection
monitor.name = e.s.name+' - '+monitor.mid
monitor.type = e.s.type
monitor.protocol = e.s.protocol
monitor.host = e.s.host
monitor.port = e.s.port
monitor.path = e.s.path
monitor.details.fatal_max = e.s.details.fatal_max
monitor.details.port_force = e.s.details.port_force
monitor.details.muser = e.s.details.muser
monitor.details.password = e.s.details.password
monitor.details.rtsp_transport = e.s.details.rtsp_transport
monitor.details.auto_host = e.s.details.auto_host
monitor.details.auto_host_enable = e.s.details.auto_host_enable
//input
monitor.details.aduration = e.s.details.aduration
monitor.details.probesize = e.s.details.probesize
monitor.details.stream_loop = e.s.details.stream_loop
monitor.details.sfps = e.s.details.sfps
monitor.details.accelerator = e.s.details.accelerator
monitor.details.hwaccel = e.s.details.hwaccel
monitor.details.hwaccel_vcodec = e.s.details.hwaccel_vcodec
monitor.details.hwaccel_device = e.s.details.hwaccel_device
}else{
monitor = Object.assign({},$.ccio.init('cleanMon',$.ccio.mon[$user.ke+id+$user.auth_token]));
}
$.each(chosenSections,function(n,section){
monitor = alterSettings(section,monitor)
})
console.log(monitor)
$.post($.ccio.init('location',$user)+$user.auth_token+'/configureMonitor/'+$user.ke+'/'+monitor.mid,{data:JSON.stringify(monitor)},function(d){
$.ccio.log(d)
})
chosenMonitors[monitor.mid] = monitor;
})
console.log(chosenMonitors)
}
$.aM.e.modal('hide')
return false;
});
//////////////////
//Input Map (Feed)
$.aM.mapPlacementInit = function(){
$('.input-map').each(function(n,v){
var _this = $(this)
_this.find('.place').text(n+1)
})
}
$.aM.mapSave = function(){
var e={};
var mapContainers = $('[input-mapping]');
var stringForSave={}
mapContainers.each(function(q,t){
var mapRowElement = $(t).find('.map-row');
var mapRow = []
mapRowElement.each(function(n,v){
var map={}
$.each($(v).find('[map-input]'),function(m,b){
map[$(b).attr('map-input')]=$(b).val()
});
mapRow.push(map)
});
stringForSave[$(t).attr('input-mapping')] = mapRow;
});
$.aM.e.find('[detail="input_map_choices"]').val(JSON.stringify(stringForSave)).change();
}
$.aM.maps.on('click','.delete',function(){
$(this).parents('.input-map').remove()
var inputs = $('[map-detail]')
var mapContainers = $('[input-mapping]');
if(inputs.length===0){
$.aM.e.find('[detail="input_maps"]').val('[]').change()
mapContainers.hide();
}else{
inputs.first().change()
mapContainers.show();
}
$.aM.mapPlacementInit()
})
$.aM.e.on('change','[map-detail]',function(){
var e={};
e.e=$.aM.maps.find('.input-map')
e.s=[]
e.e.each(function(n,v){
var map={}
$.each($(v).find('[map-detail]'),function(m,b){
map[$(b).attr('map-detail')]=$(b).val()
});
e.s.push(map)
});
$.aM.e.find('[detail="input_maps"]').val(JSON.stringify(e.s)).change()
})
$.aM.e.on('click','[input-mapping] .add_map_row',function(){
$.ccio.tm('input-map-selector',{},$(this).parents('[input-mapping]').find('.choices'))
$.aM.mapSave()
})
$.aM.e.on('click','[input-mapping] .delete_map_row',function(){
$(this).parents('.map-row').remove()
$.aM.mapSave()
})
$.aM.e.on('change','[map-input]',function(){
$.aM.mapSave()
})
//////////////////
//Stream Channels
$.aM.channelSave = function(){
var e={};
e.e=$.aM.channels.find('.stream-channel')
e.s=[]
e.e.each(function(n,v){
var channel={}
$.each($(v).find('[channel-detail]'),function(m,b){
channel[$(b).attr('channel-detail')]=$(b).val()
});
e.s.push(channel)
});
$.aM.e.find('[detail="stream_channels"]').val(JSON.stringify(e.s)).change()
}
$.aM.channelPlacementInit = function(){
$('.stream-channel').each(function(n,v){
var _this = $(this)
_this.attr('stream-channel',n)
_this.find('.place').text(n)
_this.find('[input-mapping]').attr('input-mapping','stream_channel-'+n)
$.aM.mapSave()
})
}
$.aM.buildMonitorURL = function(){
var e={};
e.user=$.aM.e.find('[detail="muser"]').val();
e.pass=$.aM.e.find('[detail="mpass"]').val();
e.host=$.aM.e.find('[name="host"]').val();
e.protocol=$.aM.e.find('[name="protocol"]').val();
e.port=$.aM.e.find('[name="port"]').val();
e.path=$.aM.e.find('[name="path"]').val();
if($.aM.e.find('[name="type"]').val()==='local'){
e.url=e.path;
}else{
if(e.host.indexOf('@')===-1&&e.user!==''){
e.host=e.user+':'+e.pass+'@'+e.host;
}
e.url=$.ccio.init('url',e)+e.path;
}
return e.url
}
$.aM.channels.on('click','.delete',function(){
$(this).parents('.stream-channel').remove()
$.aM.channelSave()
$.aM.channelPlacementInit()
})
$.aM.e.on('change','[channel-detail]',function(){
$.aM.channelSave()
})
//////////////////
$.aM.e.on('change','[groups]',function(){
var e={};
e.e=$.aM.e.find('[groups]:checked');
e.s=[];
e.e.each(function(n,v){
e.s.push($(v).val())
});
$.aM.e.find('[detail="groups"]').val(JSON.stringify(e.s)).change()
})
$.aM.e.on('change','.detector_cascade_selection',function(){
var e={};
e.e=$.aM.e.find('.detector_cascade_selection:checked');
e.s={};
e.e.each(function(n,v){
e.s[$(v).val()]={}
});
$.aM.e.find('[detail="detector_cascades"]').val(JSON.stringify(e.s)).change()
})
//$.aM.e.on('change','.detector_cascade_selection',function(){
// var e={};
// e.details=$.aM.e.find('[name="details"]')
// try{
// e.detailsVal=JSON.parse(e.details.val())
// }catch(err){
// e.detailsVal={}
// }
// e.detailsVal.detector_cascades=[];
// e.e=$.aM.e.find('.detector_cascade_selection:checked');
// e.e.each(function(n,v){
// e.detailsVal.detector_cascades.push($(v).val())
// });
// e.details.val(JSON.stringify(e.detailsVal))
//})
$.aM.e.find('.probe_config').click(function(){
$.pB.e.find('[name="url"]').val($.aM.buildMonitorURL());
$.pB.f.submit();
$.pB.e.modal('show');
})
$.aM.e.find('.import_config').click(function(e){
var e={};e.e=$(this);e.mid=e.e.parents('[mid]').attr('mid');
$.confirm.e.modal('show');
$.confirm.title.text(lang['Import Monitor Configuration'])
e.html=lang.ImportMonitorConfigurationText+'<div style="margin-top:15px"><div class="form-group"><textarea placeholder="'+lang['Paste JSON here.']+'" class="form-control"></textarea></div><label class="upload_file btn btn-primary btn-block"> Upload File <input class="upload" type=file name="files[]"></label></div>';
$.confirm.body.html(e.html)
$.confirm.e.find('.upload').change(function(e){
var files = e.target.files; // FileList object
f = files[0];
var reader = new FileReader();
reader.onload = function(ee) {
$.confirm.e.find('textarea').val(ee.target.result);
}
reader.readAsText(f);
});
$.confirm.click({title:'Import',class:'btn-primary'},function(){
try{
e.values=JSON.parse($.confirm.e.find('textarea').val());
$.aM.import(e)
$.aM.e.modal('show')
}catch(err){
$.ccio.log(err)
$.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
}
});
});
$.aM.e.find('.save_config').click(function(e){
var e={};e.e=$(this);e.mid=e.e.parents('[mid]').attr('mid');e.s=$.aM.f.serializeObject();
if(!e.mid||e.mid===''){
e.mid='NewMonitor'
}
e.dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(e.s));
$('#temp').html('<a></a>')
.find('a')
.attr('href',e.dataStr)
.attr('download','Shinobi_'+e.mid+'_config.json')
[0].click()
});
$.aM.e.find('.add_map').click(function(e){
$('[input-mapping]').show()
$.ccio.tm('input-map')
});
$.aM.e.find('.add_channel').click(function(e){
$.ccio.tm('stream-channel')
});
$.aM.f.find('[detail="stream_type"]').change(function(e){
e.e=$(this);
if(e.e.val()==='jpeg'){$.aM.f.find('[detail="snap"]').val('1').change()}
})
$.aM.f.find('[name="type"]').change(function(e){
e.e=$(this);
if(e.e.val()==='h264'){$.aM.f.find('[name="protocol"]').val('rtsp').change()}
})
$.aM.md=$.aM.f.find('[detail]');
$.aM.md.change($.ccio.form.details)
$.aM.f.on('change','[selector]',function(){
e={e:$(this)}
e.v=e.e.val();
e.a=e.e.attr('selector')
e.triggerChange=e.e.attr('triggerchange')
e.triggerChangeIgnore=e.e.attr('triggerChangeIgnore')
$.aM.f.find('.'+e.a+'_input').hide()
$.aM.f.find('.'+e.a+'_'+e.v).show();
$.aM.f.find('.'+e.a+'_text').text($(this).find('option:selected').text())
if(e.triggerChange && e.triggerChange !== '' && !e.triggerChangeIgnore || (e.triggerChangeIgnore && e.triggerChangeIgnore.split(',').indexOf(e.v) === -1)){
console.log(e.triggerChange)
$(e.triggerChange).trigger('change')
}
$.aM.drawList()
});
$.aM.f.find('[name="type"]').change(function(e){
e.e=$(this);
e.v=e.e.val();
e.h=$.aM.f.find('[name="path"]');
e.p=e.e.parents('.form-group');
switch(e.v){
case'local':case'socket':
e.h.attr('placeholder','/dev/video0')
break;
default:
e.h.attr('placeholder','/videostream.cgi?1')
break;
}
});
})

View File

@ -0,0 +1,192 @@
$(document).ready(function(e){
//multi monitor manager
$.multimon={e:$('#multi_mon')};
$.multimon.table=$.multimon.e.find('.tableData tbody');
$.multimon.f=$.multimon.e.find('form');
$.multimon.f.on('change','#multimon_select_all',function(e){
e.e=$(this);
e.p=e.e.prop('checked')
e.a=$.multimon.f.find('input[type=checkbox][name]')
if(e.p===true){
e.a.prop('checked',true)
}else{
e.a.prop('checked',false)
}
})
$.multimon.e.find('.import_config').click(function(){
var e={};e.e=$(this);e.mid=e.e.parents('[mid]').attr('mid');
$.confirm.e.modal('show');
$.confirm.title.text(lang['Import Monitor Configuration'])
e.html=lang.ImportMultiMonitorConfigurationText+'<div style="margin-top:15px"><div class="form-group"><textarea placeholder="'+lang['Paste JSON here.']+'" class="form-control"></textarea></div><label class="upload_file btn btn-primary btn-block"> Upload File <input class="upload" type=file name="files[]"></label></div>';
$.confirm.body.html(e.html)
$.confirm.e.find('.upload').change(function(e){
var files = e.target.files; // FileList object
f = files[0];
var reader = new FileReader();
reader.onload = function(ee) {
$.confirm.e.find('textarea').val(ee.target.result);
}
reader.readAsText(f);
});
$.confirm.click({title:'Import',class:'btn-primary'},function(){
// setTimeout(function(){
// $.confirm.e.modal('show');
// },1000)
// $.confirm.title.text(lang['Are you sure?'])
// $.confirm.body.html(lang.ImportMultiMonitorConfigurationText)
// $.confirm.click({title:'Save Set',class:'btn-danger'},function(){
try{
var postMonitor = function(v){
$.post($.ccio.init('location',$user)+$user.auth_token+'/configureMonitor/'+$user.ke+'/'+v.mid,{data:JSON.stringify(v,null,3)},function(d){
$.ccio.log(d)
})
}
var parseZmMonitor = function(Monitor){
console.log(Monitor)
var newMon = $.aM.generateDefaultMonitorSettings()
newMon.details = JSON.parse(newMon.details)
newMon.details.stream_type = 'jpeg'
switch(Monitor.Type.toLowerCase()){
case'ffmpeg':case'libvlc':
newMon.details.auto_host_enable = '1'
newMon.details.auto_host = Monitor.Path
if(newMon.auto_host.indexOf('rtsp://') > -1 || newMon.auto_host.indexOf('rtmp://') > -1 || newMon.auto_host.indexOf('rtmps://') > -1){
newMon.type = 'h264'
}else{
$.ccio.init('note',{title:lang['Please Check Your Settings'],text:lang.migrateText1,type:'error'})
}
break;
case'local':
newMon.details.auto_host = Monitor.Device
break;
case'remote':
break;
}
newMon.details = JSON.stringify(newMon.details)
console.log(newMon)
return newMon
}
parsedData=JSON.parse($.confirm.e.find('textarea').val());
//zoneminder one monitor
if(parsedData.monitor){
$.aM.import({
values : parseZmMonitor(parsedData.monitor.Monitor)
})
$.aM.e.modal('show')
}else
//zoneminder multiple monitors
if(parsedData.monitors){
$.each(parsedData.monitors,function(n,v){
$.aM.import({
values : parseZmMonitor(parsedData.Monitor)
})
parseZmMonitor(v.Monitor)
})
}else
//shinobi one monitor
if(parsedData.mid){
postMonitor(parsedData)
}else
//shinobi multiple monitors
if(parsedData[0] && parsedData[0].mid){
$.each(parsedData,function(n,v){
postMonitor(v)
})
}
}catch(err){
$.ccio.log(err)
$.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
}
// });
});
})
$.multimon.getSelectedMonitors = function(unclean){
var arr=[];
if(unclean === true){
var monitors = $.ccio.mon
}else{
var monitors = $.ccio.init('cleanMons','object')
}
$.each($.multimon.f.serializeObject(),function(n,v){
arr.push(monitors[n])
})
return arr;
}
$.multimon.e.find('.delete').click(function(){
var arr=$.multimon.getSelectedMonitors(true);
if(arr.length===0){
$.ccio.init('note',{title:'No Monitors Selected',text:'Select atleast one monitor to delete.',type:'error'});
return
}
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete']+' '+lang['Monitors'])
e.html='<p>'+lang.DeleteMonitorsText+'</p>';
$.confirm.body.html(e.html)
$.confirm.click([
{
title:'Delete Monitors',
class:'btn-danger',
callback:function(){
$.each(arr,function(n,v){
$.get($.ccio.init('location',$user)+v.user.auth_token+'/configureMonitor/'+v.ke+'/'+v.mid+'/delete',function(data){
console.log(data)
})
})
}
},
{
title:'Delete Monitors and Files',
class:'btn-danger',
callback:function(){
$.each(arr,function(n,v){
$.get($.ccio.init('location',$user)+v.user.auth_token+'/configureMonitor/'+v.ke+'/'+v.mid+'/delete?deleteFiles=true',function(data){
console.log(data)
})
})
}
}
]);
})
//$.multimon.e.find('.edit_all').click(function(){
// var arr=$.multimon.getSelectedMonitors();
// var arrObject={}
// if(arr.length===0){
// $.ccio.init('note',{title:'No Monitors Selected',text:'Select atleast one monitor to delete.',type:'error'});
// return
// }
// $.multimonedit.selectedList = arr;
// $.multimonedit.e.modal('show')
//})
$.multimon.e.find('.save_config').click(function(){
var e={};e.e=$(this);
var arr=$.multimon.getSelectedMonitors();
if(arr.length===0){
$.ccio.init('note',{title:'No Monitors Selected',text:'Select atleast one monitor to delete.',type:'error'});
return
}
e.dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(arr));
$('#temp').html('<a></a>')
.find('a')
.attr('href',e.dataStr)
.attr('download','Shinobi_Monitors_'+(new Date())+'.json')
[0].click()
})
$.multimon.e.on('shown.bs.modal',function() {
var tmp=''
$.each($.ccio.mon,function(n,v){
var streamURL = $.ccio.init('streamURL',v)
if(streamURL!=='Websocket'&&v.mode!==('idle'&&'stop')){
streamURL='<a target="_blank" href="'+streamURL+'">'+streamURL+'</a>'
}
var img = $('#left_menu [mid="'+v.mid+'"][auth="'+v.user.auth_token+'"] [monitor="watch"]').attr('src')
tmp+='<tr mid="'+v.mid+'" ke="'+v.ke+'" auth="'+v.user.auth_token+'">'
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="'+lang.Pop+'" monitor="pop" class="btn btn-primary"><i class="fa fa-external-link"></i></a> <a title="'+lang.Calendar+'" monitor="calendar" class="btn btn-default"><i class="fa fa-calendar"></i></a> <a title="'+lang['Power Viewer']+'" class="btn btn-default" monitor="powerview"><i class="fa fa-map-marker"></i></a> <a title="'+lang['Time-lapse']+'" class="btn btn-default" monitor="timelapse"><i class="fa fa-angle-double-right"></i></a> <a title="'+lang['Videos List']+'" monitor="videos_table" class="btn btn-default"><i class="fa fa-film"></i></a> <a title="'+lang['Monitor Settings']+'" class="btn btn-default" monitor="edit"><i class="fa fa-wrench"></i></a></td>'
tmp+='</tr>'
})
$.multimon.table.html(tmp)
})
})

View File

@ -0,0 +1,60 @@
$(document).ready(function(e){
//onvif probe
$.oB={
e:$('#onvif_probe'),
v:$('#onvif_video'),
};
$.oB.f=$.oB.e.find('form');$.oB.o=$.oB.e.find('.output_data');
$.oB.f.submit(function(ee){
ee.preventDefault();
e={};
$.oB.foundMonitors={}
e.e=$(this),e.s=e.e.serializeObject();
$.oB.o.empty();
$.oB.e.find('._loading').show()
$.oB.e.find('[type="submit"]').prop('disabled',true)
$.ccio.cx({f:'onvif',ip:e.s.ip,port:e.s.port,user:e.s.user,pass:e.s.pass})
clearTimeout($.oB.checkTimeout)
$.oB.checkTimeout=setTimeout(function(){
if($.oB.o.find('tr').length===0){
$.oB.e.find('._loading').hide()
$.oB.e.find('[type="submit"]').prop('disabled',false)
$.oB.o.append('<td class="text-center _notfound">Sorry, nothing was found.</td>')
}
},5000)
return false;
});
$.oB.e.on('click','.copy',function(){
$('.hidden-xs [monitor="edit"]').click();
e={};
e.e = $(this).parents('[onvif_row]');
var id = e.e.attr('onvif_row');
var onvifRecord = $.oB.foundMonitors[id];
var streamURL = onvifRecord.uri;
if($.oB.e.find('[name="user"]').val()!==''){
streamURL = streamURL.split('://')
streamURL = streamURL[0]+'://'+$.oB.e.find('[name="user"]').val()+':'+$.oB.e.find('[name="pass"]').val()+'@'+streamURL[1];
}
$.aM.e.find('[detail="auto_host"]').val(streamURL).change()
$.aM.e.find('[name="mode"]').val('start')
$.oB.e.modal('hide')
})
$.oB.e.find('[name="ip"]').change(function(e){
$.ccio.op('onvif_probe_ip',$(this).val());
})
if($.ccio.op().onvif_probe_ip){
$.oB.e.find('[name="ip"]').val($.ccio.op().onvif_probe_ip)
}
$.oB.e.find('[name="port"]').change(function(e){
$.ccio.op('onvif_probe_port',$(this).val());
})
if($.ccio.op().onvif_probe_port){
$.oB.e.find('[name="port"]').val($.ccio.op().onvif_probe_port)
}
$.oB.e.find('[name="user"]').change(function(e){
$.ccio.op('onvif_probe_user',$(this).val());
})
if($.ccio.op().onvif_probe_user){
$.oB.e.find('[name="user"]').val($.ccio.op().onvif_probe_user)
}
})

View File

@ -0,0 +1,298 @@
$(document).ready(function(e){
//POWER videos window
$.pwrvid={e:$('#pvideo_viewer')};
$.pwrvid.f=$.pwrvid.e.find('form'),
$.pwrvid.d=$('#vis_pwrvideo'),
$.pwrvid.mL=$('#motion_list'),
$.pwrvid.m=$('#vis_monitors'),
$.pwrvid.lv=$('#live_view'),
$.pwrvid.dr=$('#pvideo_daterange'),
$.pwrvid.vp=$('#video_preview'),
$.pwrvid.seekBar=$('#pwrvid_seekBar'),
$.pwrvid.seekBarProgress=$.pwrvid.seekBar.find('.progress-bar'),
$.pwrvid.playRate = 1;
$.pwrvid.dr.daterangepicker({
startDate:$.ccio.timeObject().subtract(moment.duration("24:00:00")),
endDate:$.ccio.timeObject().add(moment.duration("24:00:00")),
timePicker: true,
timePicker24Hour: true,
timePickerSeconds: true,
timePickerIncrement: 30,
locale: {
format: 'MM/DD/YYYY h:mm A'
}
},function(start, end, label){
$.pwrvid.drawTimeline()
$.pwrvid.dr.focus()
});
$('#pvideo_show_events').change(function(){
$.pwrvid.drawTimeline()
})
$.pwrvid.e.on('click','[preview]',function(e){
e.e=$(this);
e.video=$.pwrvid.vp.find('video')[0];
if(e.video){
e.duration=e.video.duration;
e.now=e.video.currentTime;
}
if($.pwrvid.video){
clearInterval($.pwrvid.video.interval);
}
switch(e.e.attr('preview')){
case'fullscreen':
$.ccio.init('fullscreen',e.video)
break;
case'mute':
e.video.muted = !e.video.muted
e.e.find('i').toggleClass('fa-volume-off fa-volume-up')
e.e.toggleClass('btn-danger')
break;
case'play':
e.video.playbackRate = 1;
$.pwrvid.vpOnPlayPause(1)
break;
case'stepFrontFront':
e.add=e.e.attr('add')
e.stepFrontFront=parseInt(e.e.attr('stepFrontFront'))
if(!e.stepFrontFront||isNaN(e.stepFrontFront)){e.stepFrontFront = 5}
if(e.add==="0"){
$.pwrvid.playRate = e.stepFrontFront
}else{
$.pwrvid.playRate += e.stepFrontFront
}
e.video.playbackRate = $.pwrvid.playRate;
e.video.play()
break;
case'stepFront':
e.video.currentTime += 1;
e.video.pause()
break;
case'stepBackBack':
$.pwrvid.video.interval = setInterval(function(){
e.video.playbackRate = 1.0;
if(e.video.currentTime == 0){
clearInterval($.pwrvid.video.interval);
e.video.pause();
}
else{
e.video.currentTime += -.2;
}
},30);
break;
case'stepBack':
e.video.currentTime += -1;
e.video.pause()
break;
case'video':
// e.preventDefault();
e.p=e.e.parents('[mid]');
e.filename=e.p.attr('file');
$.pwrvid.vp.find('h3').text(e.filename)
e.href=e.e.attr('href');
e.status=e.p.attr('status');
e.mon=$.ccio.mon[e.p.attr('ke')+e.p.attr('mid')+$user.auth_token];
$.pwrvid.vp.find('.holder').html('<video class="video_video" video="'+e.href+'"><source src="'+e.href+'" type="video/'+e.mon.ext+'"></video>');
$.pwrvid.vp
.attr('mid',e.mon.mid)
.attr('mid',e.mon.user.auth_token)
.attr('ke',e.mon.ke)
.attr('status',e.status)
.attr('file',e.filename)
.find('[download],[video="download"]')
.attr('download',e.filename)
.attr('href',e.href)
$.pwrvid.vp.find('video').off('loadeddata').on('loadeddata',function(){
$.pwrvid.vp.find('.stream-objects .stream-detected-object').remove()
})
if(e.status==1){
$.get($.ccio.init('videoHrefToRead',e.href),function(d){
})
}
var labels=[]
var Dataset1=[]
var events=$.pwrvid.currentDataObject[e.filename].motion
var eventsLabeledByTime={}
$.each(events,function(n,v){
if(!v.details.confidence){v.details.confidence=0}
var time=$.ccio.timeObject(v.time).format('MM/DD/YYYY HH:mm:ss')
labels.push(time)
Dataset1.push(v.details.confidence)
eventsLabeledByTime[time]=v;
})
if(events.length>0){
$.pwrvid.mL.html("<canvas></canvas>")
var timeFormat = 'MM/DD/YYYY HH:mm:ss';
var color = Chart.helpers.color;
Chart.defaults.global.defaultFontColor = '#fff';
var config = {
type: 'bar',
data: {
labels: labels,
datasets: [{
type: 'line',
label: 'Motion Confidence',
backgroundColor: color(window.chartColors.red).alpha(0.2).rgbString(),
borderColor: window.chartColors.red,
data: Dataset1,
}]
},
options: {
maintainAspectRatio: false,
title: {
fontColor: "white",
text:"Events in this video"
},
scales: {
xAxes: [{
type: "time",
display: true,
time: {
format: timeFormat,
// round: 'day'
}
}],
},
}
};
var ctx = $.pwrvid.mL.find('canvas')[0].getContext("2d");
$.pwrvid.miniChart = new Chart(ctx, config);
$.pwrvid.mL.find('canvas').click(function(f) {
var target = $.pwrvid.miniChart.getElementsAtEvent(f)[0];
if(!target){return false}
var video = $.pwrvid.currentDataObject[e.filename];
var event = video.motion[target._index];
var video1 = $('#video_preview video')[0];
video1.currentTime=$.ccio.timeObject(event.time).diff($.ccio.timeObject(video.row.time),'seconds')
video1.play()
});
var colorNames = Object.keys(window.chartColors);
}else{
$.pwrvid.mL.html('<div class="super-center text-center" style="width:auto">'+lang['No Events found for this video']+'</div>')
}
$.pwrvid.video={filename:e.filename,href:e.href,mid:e.mon.mid,ke:e.mon.ke}
$.pwrvid.vpOnPlayPause=function(x,e){
var e={}
e.video=$.pwrvid.vp.find('video')[0]
e.i=$.pwrvid.vp.find('[preview="play"]').find('i')
if(e.video.paused===true){
e.i.removeClass('fa-pause').addClass('fa-play')
if(x==1)e.video.play();
}else{
e.i.removeClass('fa-play').addClass('fa-pause')
if(x==1)e.video.pause();
}
}
var videoElement=$.pwrvid.vp.find('video')[0]
$.pwrvid.vp.find('video')
.off('loadeddata').on('loadeddata', function() {
this.playbackRate = $.pwrvid.playRate;
this.play()
})
.off("pause").on("pause",$.pwrvid.vpOnPlayPause)
.off("play").on("play",$.pwrvid.vpOnPlayPause)
.off("timeupdate").on("timeupdate",function(){
var video = $.pwrvid.currentDataObject[e.filename];
var videoTime=$.ccio.timeObject(video.row.time).add(parseInt(videoElement.currentTime),'seconds').format('MM/DD/YYYY HH:mm:ss');
var event = eventsLabeledByTime[videoTime];
if(event){
if(event.details.plates){
console.log('licensePlateVideo',event)
}
if(event.details.matrices){
event.monitorDetails=JSON.parse(e.mon.details)
event.stream=$(videoElement)
event.streamObjects=$.pwrvid.vp.find('.stream-objects')
$.ccio.init('drawMatrices',event)
}
if(event.details.confidence){
$.pwrvid.vp.find('.motion-meter .progress-bar').css('width',event.details.confidence+'px').find('span').text(event.details.confidence)
}
}
var value= (( videoElement.currentTime / videoElement.duration ) * 100)+"%"
$.pwrvid.seekBarProgress.css("width",value);
})
$.pwrvid.seekBar.off("click").on("click", function(seek){
var offset = $(this).offset();
var left = (seek.pageX - offset.left);
var totalWidth = $.pwrvid.seekBar.width();
var percentage = ( left / totalWidth );
var vidTime = videoElement.duration * percentage;
videoElement.currentTime = vidTime;
});
break;
}
})
$.pwrvid.drawTimeline=function(getData){
var e={};
$.pwrvid.e.find('.nodata').hide()
if(getData===undefined){getData=true}
var mid=$.pwrvid.m.val();
$.pwrvid.e.find('.loading').show()
e.live_header=$.pwrvid.lv.find('h3 span');
e.live=$.pwrvid.lv.find('iframe');
e.dateRange=$.pwrvid.dr.data('daterangepicker');
e.videoLimit = $('#pvideo_video_limit').val();
e.eventLimit = $('#pvideo_event_limit').val();
if(e.eventLimit===''||isNaN(e.eventLimit)){e.eventLimit=500}
if(e.videoLimit===''||isNaN(e.videoLimit)){e.videoLimit=0}
var getTheData = function(){
e.live_header.text($.ccio.mon[$user.ke+mid+$user.auth_token].name)
e.live.attr('src',$.ccio.init('location',$user)+$user.auth_token+'/embed/'+$user.ke+'/'+mid+'/fullscreen|jquery|relative|gui')
var pulseLoading = function(){
var loading = $.pwrvid.e.find('.loading')
var currentColor = loading.css('color')
loading.animate('color','red')
setTimeout(function(){
loading.css('color',currentColor)
},500)
}
if(getData===true){
$.ccio.cx({
f:'monitor',
ff:'get',
fff:'videos&events',
videoLimit:e.videoLimit,
eventLimit:e.eventLimit,
startDate:$.ccio.init('th',e.dateRange.startDate),
endDate:$.ccio.init('th',e.dateRange.endDate),
ke:e.ke,
mid:mid
});
}else{
$.pwrvid.e.find('.loading').hide()
e.next($.pwrvid.currentVideos,$.pwrvid.currentEvents)
}
}
if(parseInt(e.eventLimit) >= 1000){
$.confirm.e.modal('show');
$.confirm.title.text(lang['Warning']+'!')
e.html=lang.powerVideoEventLimit
$.confirm.body.html(e.html)
$.confirm.click({title:lang.Request,class:'btn-primary'},function(){
getTheData()
});
}else{
getTheData()
}
}
$('#vis_monitors,#pvideo_event_limit,#pvideo_video_limit').change(function(){
$.pwrvid.f.submit()
})
$.pwrvid.f.submit(function(e){
e.preventDefault();
$.pwrvid.drawTimeline()
return false;
})
$.pwrvid.e.on('hidden.bs.modal',function(e){
$(this).find('iframe').attr('src','about:blank')
$.pwrvid.vp.find('.holder').empty()
delete($.pwrvid.currentDataObject)
delete($.pwrvid.currentData)
$.pwrvid.mL.empty()
$.pwrvid.d.empty()
})
})

View File

@ -0,0 +1,48 @@
$(document).ready(function(e){
//probe
$.pB={e:$('#probe')};$.pB.f=$.pB.e.find('form');$.pB.o=$.pB.e.find('.output_data');
$.pB.f.submit(function(e){
$.pB.e.find('._loading').show()
$.pB.o.empty();
$.pB.e.find('.stop').show();
$.pB.e.find('[type="submit"]').hide();
e.preventDefault();e.e=$(this),e.s=e.e.serializeObject();
e.s.url=e.s.url.trim();
var flags = '';
switch(e.s.mode){
case'json':
flags = '-v quiet -print_format json -show_format -show_streams';
break;
}
// if(e.s.url.indexOf('{{JSON}}')>-1){
// e.s.url='-v quiet -print_format json -show_format -show_streams '+e.s.url
// }
$.get($.ccio.init('location',$user)+$user.auth_token+'/probe/'+$user.ke+'?url='+e.s.url+'&flags='+flags,function(data){
if(data.ok===true){
var html
try{
html = $.ccio.init('jsontoblock',JSON.parse(data.result))
}catch(err){
html = data.result
}
$.pB.o.append(html)
}else{
$.ccio.init('note',{title:'Failed to Probe',text:data.error,type:'error'});
}
$.pB.e.find('._loading').hide()
$.pB.o.append('<div><b>END</b></div>');
$.pB.e.find('.stop').hide();
$.pB.e.find('[type="submit"]').show();
})
return false;
});
$.pB.e.on('hidden.bs.modal',function(){
$.pB.o.empty()
})
$.pB.e.find('.stop').click(function(e){
e.e=$(this);
// $.ccio.cx({f:'ffprobe',ff:'stop'})
});
})

View File

@ -0,0 +1,200 @@
$(document).ready(function(e){
//Region Editor
$.zO={e:$('#region_editor')};
$.zO.f=$.zO.e.find('form');
$.zO.o=function(){return $.zO.e.find('canvas')};
$.zO.c=$.zO.e.find('.canvas_holder');
$.zO.name=$.zO.e.find('[name="name"]');
$.zO.rl=$('#regions_list');
$.zO.rp=$('#regions_points');
$.zO.ca=$('#regions_canvas');
$.zO.saveCoords=function(){
$.aM.e.find('[detail="cords"]').val(JSON.stringify($.zO.regionViewerDetails.cords)).change()
}
$.zO.initRegionList=function(){
$('#regions_list,#region_points').empty();
$.each($.zO.regionViewerDetails.cords,function(n,v){
if(v&&v.name){
$.zO.rl.append('<option value="'+n+'">'+v.name+'</option>')
}
});
$.zO.rl.change();
}
$.zO.rl.change(function(e){
$.zO.initCanvas();
})
$.zO.initLiveStream=function(e){
var e={}
e.re=$('#region_editor_live');
e.re.find('iframe,img').attr('src','about:blank').hide()
if($('#region_still_image').is(':checked')){
e.re=e.re.find('img')
e.choice='jpeg'
}else{
e.re=e.re.find('iframe')
e.choice='embed'
}
e.src=$.ccio.init('location',$user)+$user.auth_token+'/'+e.choice+'/'+$user.ke+'/'+$.aM.selected.mid
if(e.choice=='embed'){
e.src+='/fullscreen|jquery|relative'
}else{
e.src+='/s.jpg'
}
if(e.re.attr('src')!==e.src){
e.re.attr('src',e.src).show()
}
e.re.attr('width',$.zO.regionViewerDetails.detector_scale_x)
e.re.attr('height',$.zO.regionViewerDetails.detector_scale_y)
}
$('#region_still_image').change(function(e){
e.o=$.ccio.op().switches
if(!e.o){e.o={}}
if($(this).is(':checked')){
e.o.regionStillImage=1
}else{
e.o.regionStillImage="0"
}
$.ccio.op('switches',e.o)
$.zO.initLiveStream()
}).ready(function(e){
e.switches=$.ccio.op().switches
if(e.switches&&e.switches.regionStillImage===1){
$('#region_still_image').prop('checked',true)
}
})
$.zO.initCanvas=function(){
var e={};
e.ar=[];
e.val=$.zO.rl.val();
if(!e.val){
$.zO.f.find('[name="name"]').val('')
$.zO.f.find('[name="sensitivity"]').val('')
$.zO.f.find('[name="max_sensitivity"]').val('')
$.zO.f.find('[name="threshold"]').val('')
$.zO.f.find('[name="color_threshold"]').val('')
$.zO.rp.empty()
}else{
e.cord=$.zO.regionViewerDetails.cords[e.val];
if(!e.cord.points){e.cord.points=[[0,0],[0,100],[100,0]]}
$.each(e.cord.points,function(n,v){
e.ar=e.ar.concat(v)
});
if(isNaN(e.cord.sensitivity)){
e.cord.sensitivity=$.zO.regionViewerDetails.detector_sensitivity;
}
$.zO.f.find('[name="name"]').val(e.val)
$.zO.e.find('.cord_name').text(e.val)
$.zO.f.find('[name="sensitivity"]').val(e.cord.sensitivity)
$.zO.f.find('[name="max_sensitivity"]').val(e.cord.max_sensitivity)
$.zO.f.find('[name="threshold"]').val(e.cord.threshold)
$.zO.f.find('[name="color_threshold"]').val(e.cord.color_threshold)
$.zO.e.find('.canvas_holder canvas').remove();
$.zO.initLiveStream()
e.e=$.zO.ca.val(e.ar.join(','))
e.e.canvasAreaDraw({
imageUrl:placeholder.getData(placeholder.plcimg({
bgcolor:'transparent',
text:' ',
size:$.zO.regionViewerDetails.detector_scale_x+'x'+$.zO.regionViewerDetails.detector_scale_y
}))
});
e.e.change();
}
}
$.zO.e.on('change','[name]:not([name="name"])',function(){
var el = $(this)
var val = el.val()
var key = el.attr('name')
$.zO.regionViewerDetails.cords[$.zO.rl.val()][key] = val
$.zO.saveCoords()
})
$.zO.e.on('change','[name="name"]',function(e){
e.old=$.zO.rl.val();
e.new=$.zO.name.val();
$.zO.regionViewerDetails.cords[e.new]=$.zO.regionViewerDetails.cords[e.old];
delete($.zO.regionViewerDetails.cords[e.old]);
$.zO.rl.find('option[value="'+e.old+'"]').attr('value',e.new).text(e.new)
$.zO.saveCoords()
})
$.zO.e.on('change','[point]',function(e){
e.points=[];
$('[points]').each(function(n,v){
v=$(v);
n=v.find('[point="x"]').val();
if(n){
e.points.push([n,v.find('[point="y"]').val()])
}
})
$.zO.regionViewerDetails.cords[$.zO.name.val()].points=e.points;
$.zO.initCanvas();
})
$.zO.e.find('.erase').click(function(e){
e.arr=[]
$.each($.zO.regionViewerDetails.cords,function(n,v){
if(v&&v!==$.zO.regionViewerDetails.cords[$.zO.rl.val()]){
e.arr.push(v)
}
})
$.zO.regionViewerDetails.cords=e.arr.concat([]);
if(Object.keys($.zO.regionViewerDetails.cords).length>0){
$.zO.initRegionList();
}else{
$.zO.f.find('input').prop('disabled',true)
$('#regions_points tbody').empty()
$('#regions_list [value="'+$.zO.rl.val()+'"]').remove()
$.aM.e.find('[detail="cords"]').val('[]')
}
});
//$.zO.e.find('.new').click(function(e){
// $.zO.regionViewerDetails.cords[$.zO.rl.val()]
// $.zO.initRegionList();
//})
$.zO.e.on('changed','#regions_canvas',function(e){
e.val=$(this).val().replace(/(,[^,]*),/g, '$1;').split(';');
e.ar=[];
$.each(e.val,function(n,v){
v=v.split(',')
if(v[1]){
e.ar.push([v[0],v[1]])
}
})
$.zO.regionViewerDetails.cords[$.zO.rl.val()].points=e.ar;
e.selected=$.zO.regionViewerDetails.cords[$.zO.rl.val()];
e.e=$('#regions_points tbody').empty();
$.each($.zO.regionViewerDetails.cords[$.zO.rl.val()].points,function(n,v){
if(isNaN(v[0])){v[0]=20}
if(isNaN(v[1])){v[1]=20}
e.e.append('<tr points="'+n+'"><td><input class="form-control" placeholder="X" point="x" value="'+v[0]+'"></td><td><input class="form-control" placeholder="Y" point="y" value="'+v[1]+'"></td><td class="text-right"><a class="delete btn btn-danger"><i class="fa fa-trash-o"></i></a></td></tr>')
});
$.zO.saveCoords()
})
$.zO.f.submit(function(e){
e.preventDefault();e.e=$(this),e.s=e.e.serializeObject();
return false;
});
$('#regions_points')
.on('click','.delete',function(e){
e.p=$(this).parents('tr'),e.row=e.p.attr('points');
delete($.zO.regionViewerDetails.cords[$.zO.rl.val()].points[e.row])
$.zO.saveCoords()
e.p.remove();
$.zO.rl.change();
})
$.zO.e.on('click','.add',function(e){
$.zO.f.find('input').prop('disabled',false)
e.gid=$.ccio.gid(5);
e.save={};
$.each($.zO.regionViewerDetails.cords,function(n,v){
if(v&&v!==null&&v!=='null'){
e.save[n]=v;
}
})
$.zO.regionViewerDetails.cords=e.save;
$.zO.regionViewerDetails.cords[e.gid]={name:e.gid,sensitivity:0.0005,max_sensitivity:'',threshold:1,color_threshold:9,points:[[0,0],[0,100],[100,0]]};
$.zO.rl.append('<option value="'+e.gid+'">'+e.gid+'</option>');
$.zO.rl.val(e.gid)
$.zO.rl.change();
});
})

View File

@ -0,0 +1,933 @@
$(document).ready(function(e){
//websocket functions
$.users = {}
$.ccio.cx=function(x,user){
if(!user){user=$user}
if(!x.ke){x.ke=user.ke;};
if(!x.uid){x.uid=user.uid;};
return user.ws.emit('f',x)
}
$.ccio.globalWebsocket=function(d,user){
if(d.f!=='monitor_frame'&&d.f!=='os'&&d.f!=='video_delete'&&d.f!=='detector_trigger'&&d.f!=='detector_record_timeout_start'&&d.f!=='log'){$.ccio.log(d);}
if(!user){
user=$user
}
if(d.viewers){
$('[ke="'+d.ke+'"][mid="'+d.id+'"][auth="'+user.auth_token+'"] .viewers').html(d.viewers);
}
switch(d.f){
case'note':
$.ccio.init('note',d.note,user);
break;
case'monitor_status':
console.log(d)
$('[ke="'+d.ke+'"][mid="'+d.id+'"][auth="'+user.auth_token+'"] .monitor_status').html(d.status);
break;
case'detector_trigger':
d.e=$('.monitor_item[ke="'+d.ke+'"][mid="'+d.id+'"][auth="'+user.auth_token+'"]')
if($.ccio.mon[d.ke+d.id+user.auth_token]&&d.e.length>0){
if(d.doObjectDetection === true){
d.e.addClass('doObjectDetection')
clearTimeout($.ccio.mon[d.ke+d.id+user.auth_token].detector_trigger_doObjectDetection_timeout)
$.ccio.mon[d.ke+d.id+user.auth_token].detector_trigger_doObjectDetection_timeout = setTimeout(function(){
d.e.removeClass('doObjectDetection')
},3000)
}else{
d.e.removeClass('doObjectDetection')
}
if(d.details.plates&&d.details.plates.length>0){
console.log('licensePlateStream',d.id,d)
}
if(d.details.matrices&&d.details.matrices.length>0){
d.monitorDetails=JSON.parse($.ccio.mon[d.ke+d.id+user.auth_token].details)
d.stream=d.e.find('.stream-element')
d.streamObjects=d.e.find('.stream-objects')
$.ccio.init('drawMatrices',d)
}
if(d.details.points&&Object.keys(d.details.points).length>0){
d.monitorDetails=JSON.parse($.ccio.mon[d.ke+d.id+user.auth_token].details)
d.stream=d.e.find('.stream-element')
d.streamObjects=d.e.find('.stream-objects')
$.ccio.init('drawPoints',d)
}
if(d.details.confidence){
d.tt=d.details.confidence;
if (d.tt > 100) { d.tt = 100 }
d.e.find('.indifference .progress-bar').css('width',d.tt + '%').find('span').html(d.details.confidence+'% change in <b>'+d.details.name+'</b>')
}
d.e.addClass('detector_triggered')
clearTimeout($.ccio.mon[d.ke+d.id+user.auth_token].detector_trigger_timeout);
$.ccio.mon[d.ke+d.id+user.auth_token].detector_trigger_timeout=setTimeout(function(){
$('.monitor_item[ke="'+d.ke+'"][mid="'+d.id+'"][auth="'+user.auth_token+'"]').removeClass('detector_triggered').find('.stream-detected-object,.stream-detected-point').remove()
},5000);
//noise alert
if(user.details.audio_alert && user.details.audio_alert !== '' && $.ccio.soundAlarmed !== true){
$.ccio.soundAlarmed = true
var audio = new Audio('libs/audio/'+user.details.audio_alert);
audio.onended = function(){
setTimeout(function(){
$.ccio.soundAlarmed = false
},user.details.audio_delay * 1000)
}
if($.ccio.windowFocus = true){
audio.play()
}else{
clearInterval($.ccio.soundAlarmInterval)
if(!user.details.audio_delay || user.details.audio_delay === ''){
user.details.audio_delay = 1
}else{
user.details.audio_delay = parseFloat(user.details.audio_delay)
}
$.ccio.soundAlarmInterval = setInterval(function(){
audio.play()
},user.details.audio_delay * 1000)
}
}
if(user.details.event_mon_pop === '1' && (!$.ccio.mon[d.ke+d.id+user.auth_token].popOut || $.ccio.mon[d.ke+d.id+user.auth_token].popOut.closed === true)){
d.e.find('[monitor="pop"]').click()
}
}
break;
case'init_success':
$('#monitors_list .link-monitors-list[auth="'+user.auth_token+'"][ke="'+user.ke+'"]').empty();
if(user===$user){
d.chosen_set='watch_on'
}else{
d.chosen_set='watch_on_links'
}
d.o=$.ccio.op()[d.chosen_set];
if(!d.o){d.o={}};
$.getJSON($.ccio.init('location',user)+user.auth_token+'/monitor/'+user.ke,function(f,g){
g=function(n,v){
$.ccio.mon[v.ke+v.mid+user.auth_token]=v;
v.user=user;
$.ccio.tm(1,v,null,user)
if(d.o[v.ke]&&d.o[v.ke][v.mid]===1){
$.ccio.cx({f:'monitor',ff:'watch_on',id:v.mid},user)
}
}
if(f.mid){
g(null,f)
}else{
$.each(f,g);
}
if($.ccio.op().jpeg_on===true){
$.ccio.cx({f:'monitor',ff:'jpeg_on'},user)
}
$.gR.drawList();
})
$.ccio.pm(3,d.apis,null,user);
$('.os_platform').html(d.os.platform)
$('.os_cpuCount').html(d.os.cpuCount)
$('.os_totalmem').html((d.os.totalmem/1000000).toFixed(2))
if(d.os.cpuCount>1){
$('.os_cpuCount_trailer').html('s')
}
break;
case'get_videos':
$.ccio.pm(0,d,null,user)
break;
case'log':
var attr = '[mid="'+d.mid+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"]'
$.ccio.tm(4,d,'#logs,'+attr+'.monitor_item .logs:visible,'+attr+'#add_monitor:visible .logs',user)
break;
case'camera_cpu_usage':
var el = $('.monitor_item[auth="'+user.auth_token+'"][ke="'+d.ke+'"][mid="'+d.id+'"] .camera_cpu_usage')
.attr('title',d.percent + '% ' + lang['CPU used by this stream'])
el.find('.progress-bar').css('width',d.percent)
el.find('.percent').html(d.percent + '%')
break;
case'os'://indicator
//cpu
d.cpu=parseFloat(d.cpu).toFixed(0)+'%';
$('.cpu_load .progress-bar').css('width',d.cpu);
$('.cpu_load .percent').html(d.cpu);
//ram
d.ram=(100-parseFloat(d.ram)).toFixed(0)+'%';
$('.ram_load .progress-bar').css('width',d.ram);
$('.ram_load .percent').html(d.ram);
break;
case'diskUsed':
if(!d.limit||d.limit===''){d.limit=10000}
d.percent=parseInt((d.size/d.limit)*100)+'%';
d.human=parseFloat(d.size)
if(d.human>1000){d.human=(d.human/1000).toFixed(2)+' GB'}else{d.human=d.human.toFixed(2)+' MB'}
$('.diskUsed .value').html(d.human)
$('.diskUsed .percent').html(d.percent)
$('.diskUsed .progress-bar').css('width',d.percent)
break;
case'video_fix_success':case'video_fix_start':
switch(d.f){
case'video_fix_success':
d.addClass='fa-wrench'
d.removeClass='fa-pulse fa-spinner'
break;
case'video_fix_start':
d.removeClass='fa-wrench'
d.addClass='fa-pulse fa-spinner'
break;
}
$('[mid="'+d.mid+'"][ke="'+d.ke+'"][file="'+d.filename+'"][auth="'+user.auth_token+'"] [video="fix"] i,[data-mid="'+d.mid+'"][data-ke="'+d.ke+'"][data-file="'+d.filename+'"][data-auth="'+user.auth_token+'"] [video="fix"] i').addClass(d.addClass).removeClass(d.removeClass)
break;
case'video_edit':case'video_archive':
$.ccio.init('data-video',d)
d.e=$('[file="'+d.filename+'"][mid="'+d.mid+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"],[data-file="'+d.filename+'"][data-mid="'+d.mid+'"][data-ke="'+d.ke+'"][data-auth="'+user.auth_token+'"]');
d.e.attr('status',d.status),d.e.attr('data-status',d.status);
console.log(d)
break;
case'video_delete':
// if($('.modal[mid="'+d.mid+'"][auth="'+user.auth_token+'"]').length>0){$('#video_viewer[mid="'+d.mid+'"]').attr('file',null).attr('ke',null).attr('mid',null).attr('auth',null).modal('hide')}
$('[file="'+d.filename+'"][mid="'+d.mid+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"]:not(.modal)').remove();
$('[data-file="'+d.filename+'"][data-mid="'+d.mid+'"][data-ke="'+d.ke+'"][data-auth="'+user.auth_token+'"]:not(.modal)').remove();
if($.pwrvid.currentDataObject&&$.pwrvid.currentDataObject[d.filename]){
delete($.timelapse.currentVideos[$.pwrvid.currentDataObject[d.filename].position])
$.pwrvid.drawTimeline(false)
}
if($.timelapse.currentVideos&&$.timelapse.currentVideos[d.filename]){
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;
d.e='.glM'+d.mid+user.auth_token+'.videos_list ul,.glM'+d.mid+user.auth_token+'.videos_monitor_list ul';$(d.e).find('.notice.novideos').remove();
$.ccio.tm(0,d,d.e,user)
break;
case'monitor_snapshot':
setTimeout(function(){
var snapElement = $('[mid="'+d.mid+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"] .snapshot')
switch(d.snapshot_format){
case'plc':
snapElement.attr('src',placeholder.getData(placeholder.plcimg(d.snapshot)))
break;
case'ab':
d.reader = new FileReader();
d.reader.addEventListener("loadend",function(){snapElement.attr('src',d.reader.result)});
d.reader.readAsDataURL(new Blob([d.snapshot],{type:"image/jpeg"}));
break;
case'b64':
snapElement.attr('src','data:image/jpeg;base64,'+d.snapshot)
break;
}
},1000)
break;
case'monitor_delete':
$('[mid="'+d.mid+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"]:not(.modal)').remove();
$.ccio.init('clearTimers',d)
delete($.ccio.mon[d.ke+d.mid+user.auth_token]);
break;
case'monitor_watch_off':case'monitor_stopping':
if(user===$user){
d.chosen_set='watch_on'
}else{
d.chosen_set='watch_on_links'
}
d.o=$.ccio.op()[d.chosen_set];
if(!d.o[d.ke]){d.o[d.ke]={}};d.o[d.ke][d.id]=0;$.ccio.op(d.chosen_set,d.o);
$.ccio.destroyStream(d,user,(d.f === 'monitor_watch_off'))
break;
case'monitor_watch_on':
if(user===$user){
d.chosen_set='watch_on'
}else{
d.chosen_set='watch_on_links'
}
d.o=$.ccio.op()[d.chosen_set];
if(!d.o){d.o={}};if(!d.o[d.ke]){d.o[d.ke]={}};d.o[d.ke][d.id]=1;$.ccio.op(d.chosen_set,d.o);
$.ccio.mon[d.ke+d.id+user.auth_token].watch=1;
delete($.ccio.mon[d.ke+d.id+user.auth_token].image)
delete($.ccio.mon[d.ke+d.id+user.auth_token].ctx)
d.e=$('#monitor_live_'+d.id+user.auth_token);
d.e.find('.stream-detected-object').remove()
$.ccio.init('clearTimers',d)
if(d.e.length === 1){
$.ccio.init('closeVideo',{mid:d.id,ke:d.ke},user);
}
if(d.e.length === 0){
$.ccio.tm(2,$.ccio.mon[d.ke+d.id+user.auth_token],'#monitors_live',user);
}
d.d=JSON.parse($.ccio.mon[d.ke+d.id+user.auth_token].details);
$.ccio.tm('stream-element',$.ccio.mon[d.ke+d.id+user.auth_token],null,user);
if($.ccio.op().jpeg_on===true){
$.ccio.init('jpegMode',$.ccio.mon[d.ke+d.id+user.auth_token]);
}else{
var path = tool.checkCorrectPathEnding(location.pathname)+'socket.io'
switch(d.d.stream_type){
case'jpeg':
$.ccio.init('jpegMode',$.ccio.mon[d.ke+d.id+user.auth_token]);
break;
case'b64':
if($.ccio.mon[d.ke+d.id+user.auth_token].Base64 && $.ccio.mon[d.ke+d.id+user.auth_token].Base64.connected){
$.ccio.mon[d.ke+d.id+user.auth_token].Base64.disconnect()
}
$.ccio.mon[d.ke+d.id+user.auth_token].Base64 = io(location.origin,{ path: path, transports: ['websocket'], forceNew: false})
var ws = $.ccio.mon[d.ke+d.id+user.auth_token].Base64
var buffer
ws.on('diconnect',function(){
console.log('Base64 Stream Disconnected')
})
ws.on('connect',function(){
ws.emit('Base64',{
auth: user.auth_token,
uid: user.uid,
ke: d.ke,
id: d.id,
// channel: channel
})
if(!$.ccio.mon[d.ke+d.id+user.auth_token].ctx||$.ccio.mon[d.ke+d.id+user.auth_token].ctx.length===0){
$.ccio.mon[d.ke+d.id+user.auth_token].ctx = $('#monitor_live_'+d.id+user.auth_token+' canvas');
}
var ctx = $.ccio.mon[d.ke+d.id+user.auth_token].ctx[0]
var ctx2d = ctx.getContext("2d")
$.ccio.mon[d.ke+d.id+user.auth_token].image = new Image()
var image = $.ccio.mon[d.ke+d.id+user.auth_token].image
image.onload = function() {
$.ccio.mon[d.ke+d.id+user.auth_token].imageLoading = false
d.x = 0
d.y = 0
// d.ratio = Math.min(ctx.width/image.width,ctx.height/image.height)
// d.height = image.height * d.ratio
// d.width = image.width * d.ratio
// if(d.width < ctx.width){
// d.x = (ctx.width / 2) - (d.width / 2)
// }
// if(d.height < ctx.height){
// d.y = (ctx.height / 2) - (d.height / 2)
// }
// ctx.getContext("2d").drawImage(image,d.x,d.y,d.width,d.height)
ctx.getContext("2d").drawImage(image,d.x,d.y,ctx.width,ctx.height)
URL.revokeObjectURL($.ccio.mon[d.ke+d.id+user.auth_token].imageUrl)
}
ws.on('data',function(imageData){
try{
if($.ccio.mon[d.ke+d.id+user.auth_token].imageLoading === true)return console.log('drop');
// var base64Frame = 'data:image/jpeg;base64,'+$.ccio.base64ArrayBuffer(imageData)
$.ccio.mon[d.ke+d.id+user.auth_token].imageLoading = true
// $.ccio.mon[d.ke+d.id+user.auth_token].image.src = base64Frame
var arrayBufferView = new Uint8Array(imageData);
var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
$.ccio.mon[d.ke+d.id+user.auth_token].imageUrl = URL.createObjectURL( blob );
$.ccio.mon[d.ke+d.id+user.auth_token].image.src = $.ccio.mon[d.ke+d.id+user.auth_token].imageUrl
$.ccio.mon[d.ke+d.id+user.auth_token].last_frame = 'data:image/jpeg;base64,'+$.ccio.base64ArrayBuffer(imageData)
}catch(er){
console.log(er)
$.ccio.log('base64 frame')
}
$.ccio.init('signal',d);
})
})
break;
case'mp4':
setTimeout(function(){
var stream = d.e.find('.stream-element');
var onPoseidonError = function(){
// setTimeout(function(){
// $.ccio.cx({f:'monitor',ff:'watch_on',id:d.id},user)
// },5000)
}
if(!$.ccio.mon[d.ke+d.id+user.auth_token].PoseidonErrorCount)$.ccio.mon[d.ke+d.id+user.auth_token].PoseidonErrorCount = 0
if($.ccio.mon[d.ke+d.id+user.auth_token].PoseidonErrorCount >= 5)return
if(d.d.stream_flv_type==='ws'){
if($.ccio.mon[d.ke+d.id+user.auth_token].Poseidon){
$.ccio.mon[d.ke+d.id+user.auth_token].Poseidon.stop()
}
try{
$.ccio.mon[d.ke+d.id+user.auth_token].Poseidon = new Poseidon({
video: stream[0],
auth_token:user.auth_token,
ke:d.ke,
uid:user.uid,
id:d.id,
url: location.origin,
path: path,
onError : onPoseidonError
})
$.ccio.mon[d.ke+d.id+user.auth_token].Poseidon.start();
}catch(err){
// onPoseidonError()
console.log('onTryPoseidonError',err)
}
}else{
stream.attr('src',$.ccio.init('location',user)+user.auth_token+'/mp4/'+d.ke+'/'+d.id+'/s.mp4')
stream[0].onerror = function(err){
console.error(err)
}
}
},2000)
break;
case'flv':
if (flvjs.isSupported()) {
if($.ccio.mon[d.ke+d.id+user.auth_token].flv){
$.ccio.mon[d.ke+d.id+user.auth_token].flv.destroy()
}
var options = {};
if(d.d.stream_flv_type==='ws'){
if(d.d.stream_flv_maxLatency&&d.d.stream_flv_maxLatency!==''){
d.d.stream_flv_maxLatency = parseInt(d.d.stream_flv_maxLatency)
}else{
d.d.stream_flv_maxLatency = 20000;
}
options = {
type: 'flv',
isLive: true,
auth_token:user.auth_token,
ke:d.ke,
uid:user.uid,
id:d.id,
maxLatency:d.d.stream_flv_maxLatency,
hasAudio:false,
url: location.origin,
path: path
}
}else{
options = {
type: 'flv',
isLive: true,
url: $.ccio.init('location',user)+user.auth_token+'/flv/'+d.ke+'/'+d.id+'/s.flv'
}
}
$.ccio.mon[d.ke+d.id+user.auth_token].flv = flvjs.createPlayer(options);
$.ccio.mon[d.ke+d.id+user.auth_token].flv.attachMediaElement($('#monitor_live_'+d.id+user.auth_token+' .stream-element')[0]);
$.ccio.mon[d.ke+d.id+user.auth_token].flv.on('error',function(err){
console.log(err)
});
$.ccio.mon[d.ke+d.id+user.auth_token].flv.load();
$.ccio.mon[d.ke+d.id+user.auth_token].flv.play();
}else{
$.ccio.init('note',{title:'Stream cannot be started',text:'FLV.js is not supported on this browser. Try another stream type.',type:'error'});
}
break;
case'hls':
d.fn=function(){
clearTimeout($.ccio.mon[d.ke+d.id+user.auth_token].m3uCheck)
d.url=$.ccio.init('location',user)+user.auth_token+'/hls/'+d.ke+'/'+d.id+'/s.m3u8';
$.get(d.url,function(m3u){
if(m3u=='File Not Found'){
$.ccio.mon[d.ke+d.id+user.auth_token].m3uCheck=setTimeout(function(){
d.fn()
},2000)
}else{
var video = $('#monitor_live_'+d.id+user.auth_token+' .stream-element')[0];
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)||(navigator.userAgent.match(/(Safari)/)&&!navigator.userAgent.match('Chrome'))) {
video.src=d.url;
if (video.paused) {
video.play();
}
}else{
$.ccio.mon[d.ke+d.id+user.auth_token].hlsGarbageCollector=function(){
if($.ccio.mon[d.ke+d.id+user.auth_token].hls){$.ccio.mon[d.ke+d.id+user.auth_token].hls.destroy();URL.revokeObjectURL(video.src)}
$.ccio.mon[d.ke+d.id+user.auth_token].hls = new Hls();
$.ccio.mon[d.ke+d.id+user.auth_token].hls.loadSource(d.url);
$.ccio.mon[d.ke+d.id+user.auth_token].hls.attachMedia(video);
$.ccio.mon[d.ke+d.id+user.auth_token].hls.on(Hls.Events.MANIFEST_PARSED,function() {
if (video.paused) {
video.play();
}
});
}
$.ccio.mon[d.ke+d.id+user.auth_token].hlsGarbageCollector()
$.ccio.mon[d.ke+d.id+user.auth_token].hlsGarbageCollectorTimer=setInterval($.ccio.mon[d.ke+d.id+user.auth_token].hlsGarbageCollector,1000*60*20)
}
}
})
}
d.fn()
break;
case'mjpeg':
$('#monitor_live_'+d.id+user.auth_token+' .stream-element').attr('src',$.ccio.init('location',user)+user.auth_token+'/mjpeg/'+d.ke+'/'+d.id+'/?full=true')
break;
case'h265':
var player = $.ccio.mon[d.ke+d.id+user.auth_token].h265Player
var video = $('#monitor_live_'+d.id+user.auth_token+' .stream-element')[0]
if (player) {
player.stop()
}
$.ccio.mon[d.ke+d.id+user.auth_token].h265Player = new libde265.RawPlayer(video)
var player = $.ccio.mon[d.ke+d.id+user.auth_token].h265Player
player.set_status_callback(function(msg, fps) {
})
player.launch()
if($.ccio.mon[d.ke+d.id+user.auth_token].h265Socket && $.ccio.mon[d.ke+d.id+user.auth_token].h265Socket.connected){
$.ccio.mon[d.ke+d.id+user.auth_token].h265Socket.disconnect()
}
if($.ccio.mon[d.ke+d.id+user.auth_token].h265HttpStream && $.ccio.mon[d.ke+d.id+user.auth_token].abort){
$.ccio.mon[d.ke+d.id+user.auth_token].h265HttpStream.abort()
}
if(d.d.stream_flv_type==='ws'){
$.ccio.mon[d.ke+d.id+user.auth_token].h265Socket = io(location.origin,{ path: path, transports: ['websocket'], forceNew: false})
var ws = $.ccio.mon[d.ke+d.id+user.auth_token].h265Socket
ws.on('diconnect',function(){
console.log('h265Socket Stream Disconnected')
})
ws.on('connect',function(){
ws.emit('h265',{
auth: user.auth_token,
uid: user.uid,
ke: d.ke,
id: d.id,
// channel: channel
})
ws.on('data',function(imageData){
player._handle_onChunk(imageData)
})
})
}else{
var url = $.ccio.init('location',user)+user.auth_token+'/h265/'+d.ke+'/'+d.id+'/s.hevc';
$.ccio.mon[d.ke+d.id+user.auth_token].h265HttpStream = player.createHttpStream(url)
}
break;
}
}
d.signal=parseFloat(d.d.signal_check);
if(!d.signal||d.signal==NaN){d.signal=10;};d.signal=d.signal*1000*60;
if(d.signal>0){
$.ccio.mon[d.ke+d.id+user.auth_token].signal=setInterval(function(){$.ccio.init('signal-check',{id:d.id,ke:d.ke})},d.signal);
}
d.e=$('.monitor_item[mid="'+d.id+'"][ke="'+d.ke+'"][auth="'+user.auth_token+'"]').resize()
if(d.e.find('.videos_monitor_list li').length===0){
d.dr=$('#videos_viewer_daterange').data('daterangepicker');
$.getJSON($.ccio.init('location',user)+user.auth_token+'/videos/'+d.ke+'/'+d.id+'?limit=10',function(f){
$.ccio.pm(0,{videos:f.videos,ke:d.ke,mid:d.id},null,user)
})
}
setTimeout(function(){
if($.ccio.mon[d.ke+d.id+user.auth_token].motionDetectionRunning===true){
$.ccio.init('streamMotionDetectRestart',{mid:d.id,ke:d.ke,mon:$.ccio.mon[d.ke+d.id+user.auth_token]},user);
}
},3000)
break;
case'pam_frame':
if(!$.ccio.mon[d.ke+d.id+user.auth_token].ctx||$.ccio.mon[d.ke+d.id+user.auth_token].ctx.length===0){
$.ccio.mon[d.ke+d.id+user.auth_token].ctx = $('#monitor_live_'+d.id+user.auth_token+' canvas');
$.ccio.mon[d.ke+d.id+user.auth_token].ctxContext = $.ccio.mon[d.ke+d.id+user.auth_token].ctx[0].getContext('2d');
}
var ctx = $.ccio.mon[d.ke+d.id+user.auth_token].ctxContext;
d.x = 0,d.y = 0;
d.ratio = Math.min($.ccio.mon[d.ke+d.id+user.auth_token].ctx.width()/d.imageData.width,$.ccio.mon[d.ke+d.id+user.auth_token].ctx.height()/d.imageData.height);
d.height = d.imageData.height*d.ratio;
d.width = d.imageData.width*d.ratio;
if( d.width < $.ccio.mon[d.ke+d.id+user.auth_token].ctx.width() )
d.x = ($.ccio.mon[d.ke+d.id+user.auth_token].ctx.width() / 2) - (d.width / 2);
if( d.height < $.ccio.mon[d.ke+d.id+user.auth_token].ctx.height() )
d.y = ($.ccio.mon[d.ke+d.id+user.auth_token].ctx.height() / 2) - (d.height / 2);
var imageData = ctx.createImageData(d.width,d.height)
imageData.data.set(new Uint8ClampedArray(d.imageData.data))
console.log(imageData)
ctx.putImageData(imageData, 0, 0);
break;
case'monitor_frame':
try{
if($.ccio.mon[d.ke+d.id+user.auth_token].imageLoading === true)return
if(!$.ccio.mon[d.ke+d.id+user.auth_token].ctx||$.ccio.mon[d.ke+d.id+user.auth_token].ctx.length===0){
$.ccio.mon[d.ke+d.id+user.auth_token].ctx = $('#monitor_live_'+d.id+user.auth_token+' canvas');
}
var ctx = $.ccio.mon[d.ke+d.id+user.auth_token].ctx[0]
if(!$.ccio.mon[d.ke+d.id+user.auth_token].image){
$.ccio.mon[d.ke+d.id+user.auth_token].image = new Image()
var image = $.ccio.mon[d.ke+d.id+user.auth_token].image
image.onload = function() {
$.ccio.mon[d.ke+d.id+user.auth_token].imageLoading = false
d.x = 0
d.y = 0
// d.ratio = Math.min(ctx.width/image.width,ctx.height/image.height)
// d.height = image.height * d.ratio
// d.width = image.width * d.ratio
// if(d.width < ctx.width){
// d.x = (ctx.width / 2) - (d.width / 2)
// }
// if(d.height < ctx.height){
// d.y = (ctx.height / 2) - (d.height / 2)
// }
// ctx.getContext("2d").drawImage(image,d.x,d.y,d.width,d.height)
ctx.getContext("2d").drawImage(image,d.x,d.y,ctx.width,ctx.height)
}
}
var base64Frame = 'data:image/jpeg;base64,'+d.frame
$.ccio.mon[d.ke+d.id+user.auth_token].imageLoading = true
$.ccio.mon[d.ke+d.id+user.auth_token].image.src = base64Frame
$.ccio.mon[d.ke+d.id+user.auth_token].last_frame = base64Frame
}catch(er){
console.log(er)
$.ccio.log('base64 frame')
}
$.ccio.init('signal',d);
break;
case'monitor_edit':
$.ccio.init('clearTimers',d)
d.e=$('[mid="'+d.mon.mid+'"][ke="'+d.mon.ke+'"][auth="'+user.auth_token+'"]');
d.e=$('#monitor_live_'+d.mid+user.auth_token);
d.e.find('.stream-detected-object').remove()
if(d.mon.details.control=="1"){d.e.find('[monitor="control_toggle"]').show()}else{d.e.find('.pad').remove();d.e.find('[monitor="control_toggle"]').hide()}
if(user===$user){
d.chosen_set='watch_on'
}else{
d.chosen_set='watch_on_links'
}
d.o=$.ccio.op()[d.chosen_set];
if(!d.o){d.o={}}
if(d.mon.details.cords instanceof Object){d.mon.details.cords=JSON.stringify(d.mon.details.cords);}
d.mon.details=JSON.stringify(d.mon.details);
if(!$.ccio.mon[d.ke+d.mid+user.auth_token]){$.ccio.mon[d.ke+d.mid+user.auth_token]={}}
$.ccio.init('jpegModeStop',d);
$.ccio.mon[d.ke+d.mid+user.auth_token].previousStreamType=d.mon.details.stream_type
$.each(d.mon,function(n,v){
$.ccio.mon[d.ke+d.mid+user.auth_token][n]=v;
});
$.ccio.mon[d.ke+d.mid+user.auth_token].user=user
if(d.new===true){$.ccio.tm(1,d.mon,null,user)}
switch(d.mon.mode){
case'start':case'record':
if(d.o[d.ke]&&d.o[d.ke][d.mid]===1){
$.ccio.cx({f:'monitor',ff:'watch_on',id:d.mid},user)
}
break;
}
$.ccio.init('monitorInfo',d)
$.gR.drawList();
if(!d.silenceNote){
$.ccio.init('note',{title:'Monitor Saved',text:'<b>'+d.mon.name+'</b> <small>'+d.mon.mid+'</small> has been saved.',type:'success'});
}
break;
case'monitor_starting':
// switch(d.mode){case'start':d.mode='Watch';break;case'record':d.mode='Record';break;}
// $.ccio.init('note',{title:'Monitor Starting',text:'Monitor <b>'+d.mid+'</b> is now running in mode <b>'+d.mode+'</b>',type:'success'});
d.e=$('#monitor_live_'+d.mid+user.auth_token)
if(d.e.length>0){$.ccio.cx({f:'monitor',ff:'watch_on',id:d.mid},user)}
break;
case'mode_jpeg_off':
$.ccio.op('jpeg_on',"0");
$.each($.ccio.mon,function(n,v,x){
$.ccio.init('jpegModeStop',v);
if(v.watch===1){
$.ccio.cx({f:'monitor',ff:'watch_on',id:v.mid},user)
}
});
$('body').removeClass('jpegMode')
break;
case'mode_jpeg_on':
$.ccio.op('jpeg_on',true);
$.ccio.init('jpegModeAll');
$('body').addClass('jpegMode')
break;
case'drawPowerVideoMainTimeLine':
var videos = d.videos;
var events = d.events;
// $.pwrvid.currentlyLoading = false
$.pwrvid.currentVideos=videos
$.pwrvid.currentEvents=events
$.pwrvid.e.find('.loading').hide()
$.pwrvid.e.find('.nodata').hide()
//$.pwrvid.drawTimeLine
if($.pwrvid.t&&$.pwrvid.t.destroy){$.pwrvid.t.destroy()}
data={};
$.each(videos.videos,function(n,v){
if(!v||!v.mid){return}
v.mon=$.ccio.mon[v.ke+v.mid+$user.auth_token];
// v.filename=$.ccio.init('tf',v.time)+'.'+v.ext;
if(v.status>0){
// data.push({src:v,x:v.time,y:$.ccio.timeObject(v.time).diff($.ccio.timeObject(v.end),'minutes')/-1})
data[v.filename]={
filename:v.filename,
time:v.time,
timeFormatted:$.ccio.timeObject(v.time).format('MM/DD/YYYY HH:mm'),
endTime:v.end,
close:$.ccio.timeObject(v.time).diff($.ccio.timeObject(v.end),'minutes')/-1,
motion:[],
row:v,
position:n
}
}
});
var eventsToCheck = Object.assign({},events)
$.each(data,function(m,b){
startTimeFormatted = $.ccio.timeObject(b.time).format('YYYY-MM-DD HH:mm:ss');
startTime = $.ccio.timeObject(b.time).format();
endTime = $.ccio.timeObject(b.endTime).format();
var newSetOfEventsWithoutChecked = {};
var eventTime
$.each(eventsToCheck,function(n,v){
try{
if(v.details.videoTime.indexOf('T') > -1){
eventTime = v.details.videoTime.split('T');
}else{
eventTime = v.details.videoTime.split(' ');
}
}catch(err){
if(v.time.indexOf('T') > -1){
eventTime = v.time.split('T');
}else{
eventTime = v.time.split(' ');
}
}
eventTime[1] = eventTime[1].replace(/-/g,':'),eventTime = eventTime.join(' ');
if(eventTime === startTimeFormatted){
data[m].motion.push(v)
}else if ($.ccio.timeObject(v.time).isBetween(startTime,$.ccio.timeObject(b.endTime).format())) {
data[m].motion.push(v)
}else{
newSetOfEventsWithoutChecked[n] = v;
}
})
eventsToCheck = newSetOfEventsWithoutChecked;
});
$.pwrvid.currentDataObject=data;
if($.pwrvid.chart){
$.pwrvid.d.empty()
delete($.pwrvid.chart)
}
$.pwrvid.currentData=Object.values(data);
if($.pwrvid.currentData.length>0){
var labels=[]
var Dataset1=[]
var Dataset2=[]
$.each(data,function(n,v){
labels.push(v.timeFormatted)
Dataset1.push(v.close)
Dataset2.push(v.motion.length)
})
$.pwrvid.d.html("<canvas></canvas>")
var timeFormat = 'MM/DD/YYYY HH:mm';
var color = Chart.helpers.color;
Chart.defaults.global.defaultFontColor = '#fff';
var config = {
type: 'bar',
data: {
labels: labels,
datasets: [{
type: 'line',
label: lang['Video and Time Span (Minutes)'],
backgroundColor: color(window.chartColors.blue).alpha(0.2).rgbString(),
borderColor: window.chartColors.blue,
data: Dataset1,
}, {
type: 'bar',
showTooltip: false,
label: lang['Counts of Motion'],
backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
borderColor: window.chartColors.red,
data:Dataset2,
}, ]
},
options: {
maintainAspectRatio: false,
title: {
fontColor: "white",
text: lang['Video Length (minutes) and Motion Count per video']
},
tooltips: {
callbacks: {
},
},
scales: {
xAxes: [{
type: "time",
display: true,
time: {
format: timeFormat,
// round: 'day'
}
}],
},
}
};
var ctx = $.pwrvid.d.find('canvas')[0].getContext("2d");
$.pwrvid.chart = new Chart(ctx, config);
$.pwrvid.d.find('canvas').click(function(e) {
var target = $.pwrvid.chart.getElementsAtEvent(e)[0];
if(!target){return false}
target = $.pwrvid.currentData[target._index];
$.pwrvid.e.find('.temp').html('<li class="glM'+target.row.mid+$user.auth_token+'" mid="'+target.row.mid+'" ke="'+target.row.ke+'" status="'+target.row.status+'" file="'+target.row.filename+'" auth="'+$user.auth_token+'"><a class="btn btn-sm btn-primary" preview="video" href="'+target.row.href+'"><i class="fa fa-play-circle"></i></a></li>').find('a').click()
});
var colorNames = Object.keys(window.chartColors);
}else{
$.pwrvid.e.find('.nodata').show()
}
break;
}
}
$user.ws=io(location.origin,{
path : tool.checkCorrectPathEnding(location.pathname)+'socket.io'
});
$user.ws.on('connect',function (d){
$(document).ready(function(e){
$.ccio.init('id',$user);
$.ccio.cx({f:'init',ke:$user.ke,auth:$user.auth_token,uid:$user.uid})
if($user.details&&$user.details.links){
$.each($user.details.links,function(n,v){
if(v.secure==='0'){
v.protocol='http'
}else{
v.protocol='https'
}
if(v.host.indexOf('://')>-1){
v.URL=v.protocol+'://'+v.host.split('://')[1]
}else{
v.URL=v.protocol+'://'+v.host
}
$.get(v.URL+'/'+v.api+'/userInfo/'+v.ke,function(e){
if(e.ok===true){
e.user.auth_token=v.api
$.users[v.api]=e.user
$.users[v.api].info=v
$.users[v.api].ws=io(v.host)
$.users[v.api].ws.on('ping', function(d){
$.users[v.api].ws.emit('pong',{beat:1});
});
$.users[v.api].ws.on('connect',function (d){
console.log(v.host,'connected')
$.ccio.cx({f:'init',ke:e.user.ke,auth:v.api,uid:e.user.uid},$.users[v.api])
})
$.users[v.api].ws.on('f',function (d){
$.ccio.globalWebsocket(d,$.users[v.api])
})
}
})
})
}
})
})
PNotify.prototype.options.styling = "fontawesome";
$user.ws.on('ping', function(d){
$user.ws.emit('pong',{beat:1});
});
$user.ws.on('f',function (d){
$.ccio.globalWebsocket(d)
switch(d.f){
case'api_key_deleted':
if($user.uid === d.uid){
$.ccio.init('note',{title:lang['API Key Deleted'],text:lang.APIKeyDeletedText,type:'notice'});
$('[api_key="'+d.form.code+'"]').remove()
}
break;
case'api_key_added':
if($user.uid === d.uid){
$.ccio.init('note',{title:lang['API Key Added'],text:lang.FiltersUpdatedText,type:'success'});
$.ccio.tm(3,d.form,'#api_list')
}
break;
case'filters_change':
$.ccio.init('note',{title:lang['Filters Updated'],text:lang.FiltersUpdatedText,type:'success'});
$user.details.filters=d.filters;
$.ccio.init('filters');
break;
case'user_settings_change':
$.ccio.init('note',{title:lang['Settings Changed'],text:lang.SettingsChangedText,type:'success'});
$.ccio.init('id',d.form);
d.form.details=JSON.parse(d.form.details)
$('#custom_css').append(d.form.details.css)
if(d.form.details){
$user.details=d.form.details
}
break;
case'users_online':
$.ccio.pm('user-row',d.users);
break;
case'user_status_change':
if(d.status===1){
$.ccio.tm('user-row',d.user,null)
}else{
$('.user-row[uid="'+d.uid+'"][ke="'+d.ke+'"]').remove()
}
break;
case'ffprobe_stop':
$.pB.e.find('._loading').hide()
$.pB.o.append('<div><b>END</b></div>');
$.pB.e.find('.stop').hide();
$.pB.e.find('[type="submit"]').show();
break;
case'ffprobe_start':
$.pB.e.find('._loading').show()
$.pB.o.empty();
$.pB.e.find('.stop').show();
$.pB.e.find('[type="submit"]').hide();
break;
case'ffprobe_data':
$.pB.results=JSON.parse(d.data)
$.pB.o.append($.ccio.init('jsontoblock',$.pB.results))
break;
case'detector_cascade_list':
d.tmp=''
$.each(d.cascades,function(n,v){
d.tmp+='<li class="mdl-list__item">';
d.tmp+='<span class="mdl-list__item-primary-content">';
d.tmp+=v;
d.tmp+='</span>';
d.tmp+='<span class="mdl-list__item-secondary-action">';
d.tmp+='<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">';
d.tmp+='<input type="checkbox" value="'+v+'" detailContainer="detector_cascades" detailObject="'+v+'" class="detector_cascade_selection mdl-switch__input"/>';
d.tmp+='</label>';
d.tmp+='</span>';
d.tmp+='</li>';
})
$('#detector_cascade_list').html(d.tmp)
componentHandler.upgradeAllRegistered()
//add auto select for preferences
d.currentlyEditing=$.aM.e.attr('mid')
if(d.currentlyEditing&&d.currentlyEditing!==''){
d.currentlyEditing=JSON.parse(JSON.parse($.ccio.mon[d.currentlyEditing].details).detector_cascades)
$.each(d.currentlyEditing,function(m,b){
d.e=$('.detector_cascade_selection[value="'+m+'"]').prop('checked',true)
d.p=d.e.parents('.mdl-js-switch')
if(d.p.length>0){
d.p.addClass('is-checked')
}
})
}
break;
case'detector_plugged':
if(!d.notice){d.notice=''}
$('.shinobi-detector').show()
$('.shinobi-detector-msg').html(d.notice)
$('.shinobi-detector_name').text(d.plug)
$('.shinobi-detector-'+d.plug).show()
$('.shinobi-detector-invert').hide()
$.aM.drawList()
break;
case'detector_unplugged':
$('.stream-objects .stream-detected-object').remove()
$('.shinobi-detector').hide()
$('.shinobi-detector-msg').empty()
$('.shinobi-detector_name').empty()
$('.shinobi-detector_plug').hide()
$('.shinobi-detector-invert').show()
$.aM.drawList()
break;
case'monitor_edit_failed':
d.pnote={title:'Monitor Not Saved',text:'<b>'+d.mon.name+'</b> <small>'+d.mon.mid+'</small> has not been saved.',type:'error'}
switch(d.ff){
case'max_reached':
d.pnote.text+=' '+lang.monitorEditFailedMaxReached
break;
}
$.ccio.init('note',d.pnote);
break;
// case'onvif_end':
// if(Object.keys($.oB.foundMonitorsCount).length===0){
// $.oB.e.find('._loading').hide()
// $.oB.e.find('[type="submit"]').prop('disabled',false)
// $.oB.o.append('<td class="text-center _notfound">Sorry, nothing was found.</td>')
// }
// break;
case'onvif':
var tempID = $.ccio.gid();
$.oB.foundMonitors[tempID] = Object.assign({},d);
$.oB.e.find('._loading').hide()
$.oB.e.find('._notfound').remove()
$.oB.e.find('[type="submit"]').prop('disabled',false)
d.info=$.ccio.init('jsontoblock',d.info)
if(d.uri){
d.stream=d.uri
}else{
d.stream='URL not Found'
}
$('#onvif_probe .output_data').append('<tr onvif_row="'+tempID+'"><td><a class="btn btn-sm btn-primary copy">&nbsp;<i class="fa fa-copy"></i>&nbsp;</a></td><td class="ip">'+d.ip+'</td><td class="port">'+d.port+'</td><td>'+$.ccio.init('jsontoblock',d.info)+'</td><td class="url">'+d.stream+'</td></tr>')
break;
}
delete(d);
});
})

View File

@ -0,0 +1,334 @@
$(document).ready(function(e){
//Timelapse Window
$.timelapse={e:$('#timelapse')}
$.timelapse.f=$.timelapse.e.find('form'),
$.timelapse.meter=$.timelapse.e.find('.motion-meter'),
$.timelapse.line=$('#timelapse_video_line'),
$.timelapse.display=$('#timelapse_video_display'),
$.timelapse.seekBar=$('#timelapse_seekBar'),
$.timelapse.seekBarProgress=$.timelapse.seekBar.find('.progress-bar'),
$.timelapse.dr=$('#timelapse_daterange'),
$.timelapse.mL=$.timelapse.e.find('.motion_list'),
$.timelapse.monitors=$.timelapse.e.find('.monitors_list');
$.timelapse.playDirection='videoAfter'
$.timelapse.playRate=15
$.timelapse.placeholder=placeholder.getData(placeholder.plcimg({bgcolor:'#b57d00',text:'...'}))
$.timelapse.dr.daterangepicker({
startDate:$.ccio.timeObject().subtract(moment.duration("24:00:00")),
endDate:$.ccio.timeObject().add(moment.duration("24:00:00")),
timePicker: true,
timePicker24Hour: true,
timePickerSeconds: true,
timePickerIncrement: 30,
locale: {
format: 'MM/DD/YYYY h:mm A'
}
},function(start, end, label){
$.timelapse.drawTimeline()
$.timelapse.dr.focus()
});
$.timelapse.f.find('input,select').change(function(){
$.timelapse.f.submit()
})
$.timelapse.f.submit(function(e){
e.preventDefault();
$.timelapse.drawTimeline()
return false;
})
$.timelapse.drawTimeline=function(getData){
var e={};
if(getData===undefined){getData=true}
var mid = $.timelapse.monitors.val()
e.dateRange=$.timelapse.dr.data('daterangepicker');
e.dateRange={startDate:e.dateRange.startDate,endDate:e.dateRange.endDate}
e.videoURL=$.ccio.init('location',$user)+$user.auth_token+'/videos/'+$user.ke+'/'+mid;
e.videoURL+='?limit=100&start='+$.ccio.init('th',e.dateRange.startDate)+'&end='+$.ccio.init('th',e.dateRange.endDate);
e.next=function(videos){
$.timelapse.currentVideos={}
e.tmp=''
$.each(videos.videos,function(n,v){
if(!v||!v.time){return}
// v.filename=$.ccio.init('tf',v.time)+'.'+v.ext;
v.videoBefore=videos.videos[n-1];
v.videoAfter=videos.videos[n+1];
// if(v.href.charAt(0)==='/'){
// v.href=$.ccio.init('location',user)+(v.href.substring(1))
// v.videoURL=$.ccio.init('location',user)+(v.videoURL.substring(1))
// }
v.position=n;
$.timelapse.currentVideos[v.filename]=v;
e.tmp+='<li class="glM'+v.mid+$user.auth_token+' list-group-item timelapse_video flex-block" timelapse="video" file="'+v.filename+'" href="'+v.href+'" mid="'+v.mid+'" ke="'+v.ke+'" auth="'+$user.auth_token+'">'
e.tmp+='<div class="flex-block">'
e.tmp+='<div class="flex-unit-3"><div class="frame" style="background-image:url('+$.timelapse.placeholder+')"></div></div>'
e.tmp+='<div class="flex-unit-3"><div><span title="'+v.time+'" class="livestamp"></span></div><div>'+v.filename+'</div></div>'
e.tmp+='<div class="flex-unit-3 text-right"><a class="btn btn-default" download="'+v.mid+'-'+v.filename+'" href="'+v.href+'">&nbsp;<i class="fa fa-download"></i>&nbsp;</a> <a class="btn btn-danger" video="delete" href="'+$.ccio.init('videoHrefToDelete',v.href)+'">&nbsp;<i class="fa fa-trash-o"></i>&nbsp;</a></div>'
e.tmp+='</div>'
e.tmp+='<div class="flex-block">'
e.tmp+='<div class="flex-unit-3"><div class="progress"><div class="progress-bar progress-bar-primary" role="progressbar" style="width:0%"></div></div></div>'
e.tmp+='</div>'
e.tmp+='</li>'
})
$.timelapse.line.html(e.tmp)
$.ccio.init('ls')
if(getData===true){
e.timeout=50
}else{
e.timeout=2000
}
setTimeout(function(){
if($.timelapse.e.find('.timelapse_video.active').length===0){
$.timelapse.e.find('[timelapse="video"]').first().click()
}
},e.timeout)
}
if(getData===true){
$.getJSON(e.videoURL,function(videos){
videos.videos=videos.videos.reverse()
$.timelapse.currentVideosArray=videos
e.next(videos)
})
}else{
e.next($.timelapse.currentVideosArray)
}
}
$.timelapse.playButtonIcon = $.timelapse.e.find('[timelapse="play"]').find('i')
$.timelapse.timelapseSpeedUseBasicSwitch = $('#timelapseSpeedUseBasic')
$.timelapse.timelapseSpeedUseBasicSwitch.on('change',function(){
var el = $.timelapse.e.find('.timelapseSpeedUseBasicSwitch')
if($(this).is(':checked')){
el.hide()
}else{
el.show()
}
$.timelapse.play()
})
$.timelapse.getUseBasicStatus = function(){return $.timelapse.timelapseSpeedUseBasicSwitch.prop('checked')}
$.timelapse.onPlayPause = function(toggleGui,secondWind){
if($.timelapse.paused === true){
$.timelapse.paused = false
if(toggleGui === true)$.timelapse.play();
}else{
$.timelapse.paused = true
if(toggleGui === true)$.timelapse.pause(secondWind);
}
}
$.timelapse.pause = function(secondWind){
//secondWind is used because sometimes pause can be pressed just as a video ends and the pause command does not register on the next video.
var videoNow = $.timelapse.display.find('video.videoNow')[0]
var pause = function(){
if(videoNow.paused == false)videoNow.pause()
clearInterval($.timelapse.interval)
$.timelapse.playButtonIcon.removeClass('fa-pause').addClass('fa-play')
}
pause()
if(secondWind === true)setTimeout(pause,250);
}
$.timelapse.play = function(x){
var videoNow = $.timelapse.display.find('video.videoNow')[0]
$.timelapse.pause()
clearInterval($.timelapse.interval)
if($.timelapse.getUseBasicStatus()){
videoNow.playbackRate = $.timelapse.playRate
if(videoNow.paused)videoNow.play()
}else{
videoNow.playbackRate = 1.0
$.timelapse.interval = setInterval(function(){
if(videoNow.currentTime >= videoNow.duration - .2){
clearInterval($.timelapse.interval)
videoNow.currentTime = videoNow.duration
}else{
videoNow.currentTime += .5
}
},500 / $.timelapse.playRate)
}
$.timelapse.playButtonIcon.removeClass('fa-play').addClass('fa-pause')
}
$.timelapse.rewind = function(e){
var videoNow = $.timelapse.display.find('video.videoNow')[0]
$.timelapse.pause()
videoNow.playbackRate = 1.0
clearInterval($.timelapse.interval)
$.timelapse.interval = setInterval(function(){
if(videoNow.currentTime <= 0.2){
clearInterval($.timelapse.interval)
videoNow.currentTime = 0
$('[timelapse][href="'+e.videoCurrentBefore.attr('video')+'"]').click()
var videoNowNew = $.timelapse.display.find('video.videoNow')[0]
videoNowNew.pause()
videoNowNew.currentTime = videoNowNew.duration - 0.1
$.timelapse.e.find('[timelapse="stepBackBack"]').click()
}else{
videoNow.currentTime += -.5
}
},500 / $.timelapse.playRate)
$.timelapse.playButtonIcon.removeClass('fa-play').addClass('fa-pause')
}
$.timelapse.e.on('click','[timelapse]',function(){
var e={}
e.e=$(this)
e.videoCurrentNow=$.timelapse.display.find('.videoNow')
e.videoCurrentAfter=$.timelapse.display.find('.videoAfter')
e.videoCurrentBefore=$.timelapse.display.find('.videoBefore')
if($.timelapse.videoInterval){
clearInterval($.timelapse.videoInterval);
}
switch(e.e.attr('timelapse')){
case'download':
$.timelapse.line.find('.active [download]').click()
break;
case'mute':
e.videoCurrentNow[0].muted = !e.videoCurrentNow[0].muted
$.timelapse.videoNowIsMuted = e.videoCurrentNow[0].muted
e.e.find('i').toggleClass('fa-volume-off fa-volume-up')
e.e.toggleClass('btn-danger')
break;
case'play':
e.videoCurrentNow[0].playbackRate = $.timelapse.playRate;
$.timelapse.onPlayPause(true,true)
break;
case'setPlayBackRate':
$.timelapse.pause()
$.timelapse.playRate = parseFloat(e.e.attr('playRate'))
$.timelapse.play()
break;
case'stepFrontFront':
e.add=e.e.attr('add')
e.stepFrontFront=parseInt(e.e.attr('stepFrontFront'))
if(!e.stepFrontFront||isNaN(e.stepFrontFront)){e.stepFrontFront = 5}
if(e.add==="0"){
$.timelapse.playRate = e.stepFrontFront
}else{
$.timelapse.playRate += e.stepFrontFront
}
e.videoCurrentNow[0].playbackRate = $.timelapse.playRate;
e.videoCurrentNow[0].play()
break;
case'stepFront':
e.videoCurrentNow[0].currentTime += 5;
e.videoCurrentNow[0].pause()
break;
case'stepBackBack':
// e.videoCurrentNow=$.timelapse.display.find('.videoNow')
// e.videoCurrentAfter=$.timelapse.display.find('.videoAfter')
// e.videoCurrentBefore=$.timelapse.display.find('.videoBefore')
$.timelapse.rewind(e)
break;
case'stepBack':
e.videoCurrentNow[0].currentTime += -5;
e.videoCurrentNow[0].pause()
break;
case'video':
$.timelapse.e.find('video').each(function(n,v){
v.pause()
})
e.drawVideoHTML=function(position){
var video
var exisitingElement=$.timelapse.display.find('.'+position)
if(position){
video=e.video[position]
}else{
position='videoNow'
video=e.video
}
if(video){
$.timelapse.display.append('<video class="video_video '+position+'" video="'+video.href+'" preload><source src="'+video.href+'" type="video/'+video.ext+'"></video>')
}
}
e.filename=e.e.attr('file')
e.video=$.timelapse.currentVideos[e.filename]
e.videoIsSame=(e.video.href==e.videoCurrentNow.attr('video'))
e.videoIsAfter=(e.video.href==e.videoCurrentAfter.attr('video'))
e.videoIsBefore=(e.video.href==e.videoCurrentBefore.attr('video'))
if(e.videoIsSame||e.videoIsAfter||e.videoIsBefore){
switch(true){
case e.videoIsSame:
$.ccio.log('$.timelapse','videoIsSame')
e.videoNow=$.timelapse.display.find('video.videoNow')
if(e.videoNow[0].paused===true){
e.videoNow[0].play()
}else{
e.videoNow[0].pause()
}
return
break;
case e.videoIsAfter:
$.ccio.log('$.timelapse','videoIsAfter')
e.videoCurrentBefore.remove()
e.videoCurrentAfter.removeClass('videoAfter').addClass('videoNow')
e.videoCurrentNow.removeClass('videoNow').addClass('videoBefore')
e.drawVideoHTML('videoAfter')
break;
case e.videoIsBefore:
$.ccio.log('$.timelapse','videoIsBefore')
e.videoCurrentAfter.remove()
e.videoCurrentBefore.removeClass('videoBefore').addClass('videoNow')
e.videoCurrentNow.removeClass('videoNow').addClass('videoAfter')
e.drawVideoHTML('videoBefore')
break;
}
}else{
$.ccio.log('$.timelapse','newSetOf3')
$.timelapse.display.empty()
e.drawVideoHTML()//videoNow
e.drawVideoHTML('videoBefore')
e.drawVideoHTML('videoAfter')
}
$.timelapse.display.find('video').each(function(n,v){
v.addEventListener('loadeddata', function() {
e.videoCurrentAfterPreview=$('.timelapse_video[href="'+$(v).attr('video')+'"] .frame')
if(e.videoCurrentAfterPreview.attr('set')!=='1'){
$.ccio.snapshotVideo(v,function(url,buffer){
e.videoCurrentAfterPreview.attr('set','1').css('background-image','url('+url+')')
if($(v).hasClass('videoAfter')){
v.currentTime=0
v.pause()
}
})
}
}, false);
})
e.videoNow=$.timelapse.display.find('video.videoNow')[0]
if($.timelapse.videoNowIsMuted){
e.videoNow.muted=true
}
$.timelapse.playButtonIcon.removeClass('fa-pause').addClass('fa-play')
$.timelapse.onended = function() {
$.timelapse.line.find('[file="'+e.video[$.timelapse.playDirection].filename+'"]').click()
};
e.videoNow.onended = $.timelapse.onended
e.videoNow.onerror = $.timelapse.onended
//
$(e.videoNow)
.off('play').on('play',$.timelapse.play)
.off('pause').on('pause',$.timelapse.onPlayPause)
.off('timeupdate').on('timeupdate',function(){
var value= (( e.videoNow.currentTime / e.videoNow.duration ) * 100)+"%"
$.timelapse.seekBarProgress.css("width",value);
$.timelapse.e.find('.timelapse_video[file="'+e.filename+'"] .progress-bar').css("width",value);
})
$.timelapse.play()
$.timelapse.seekBar.off("click").on("click", function(seek){
var offset = $(this).offset();
var left = (seek.pageX - offset.left);
var totalWidth = $.timelapse.seekBar.width();
var percentage = ( left / totalWidth );
var vidTime = e.videoNow.duration * percentage;
e.videoNow.currentTime = vidTime;
});
$.ccio.log('$.timelapse',e.video)
$.timelapse.line.find('.timelapse_video').removeClass('active')
e.videoCurrentNow=$.timelapse.display.find('.videoNow')
e.e.addClass('active')
if ($('#timelapse_video_line:hover').length === 0) {
$.timelapse.line.animate({scrollTop:$.timelapse.line.scrollTop() + e.e.position().top - $.timelapse.line.height()/2 + e.e.height()/2 - 40});
}
break;
}
$.timelapse.e.find('.timelapse_playRate').text('x'+$.timelapse.playRate)
})
$.timelapse.e.on('hidden.bs.modal',function(e){
delete($.timelapse.currentVideos)
delete($.timelapse.currentVideosArray)
})
})

View File

@ -0,0 +1,101 @@
$(document).ready(function(e){
//settings window
$.sM={e:$('#settings')};
$.sM.f=$.sM.e.find('form');
$.sM.links=$('#linkShinobi');
$.sM.g=$('#settings_mon_groups');
$.sM.md=$.sM.f.find('[detail]');
$.sM.md.change($.ccio.form.details);
$.sM.f.find('[selector]').change(function(e){
e.v=$(this).val();e.a=$(this).attr('selector')
$.sM.f.find('.'+e.a+'_input').hide()
$.sM.f.find('.'+e.a+'_'+e.v).show();
$.sM.f.find('.'+e.a+'_text').text($(this).find('option:selected').text())
});
$.sM.writewMonGroups=function(){
$.sM.f.find('[detail="mon_groups"]').val(JSON.stringify($user.mon_groups)).change()
}
$.sM.reDrawMonGroups=function(){
$.sM.g.empty();
$.ccio.pm('option',$user.mon_groups,'#settings_mon_groups')
$.sM.g.change();
};
$.sM.f.submit(function(e){
e.preventDefault();
$.sM.writewMonGroups()
$.sM.linkChange()
e.e=$(this),e.s=e.e.serializeObject();
e.er=[];
if(e.s.pass!==''&&e.password_again===e.s.pass){e.er.push(lang['Passwords don\'t match'])};
if(e.er.length>0){$.sM.e.find('.msg').html(e.er.join('<br>'));return;}
$.each(e.s,function(n,v){e.s[n]=v.trim()})
$.ccio.cx({f:'settings',ff:'edit',form:e.s})
$.sM.e.modal('hide')
});
$.sM.e.on('shown.bs.modal',function(){
$.sM.reDrawMonGroups()
})
$.sM.g.change(function(e){
e.v=$(this).val();
e.group=$user.mon_groups[e.v];
if(!e.group){return}
$.sM.selectedMonGroup=e.group;
$.each(e.group,function(n,v){
$.sM.f.find('[group="'+n+'"]').val(v)
})
});
$.sM.f.find('[group]').change(function(){
e = {}
e.v = $.sM.g.val()
if(!e.v||e.v==''){
e.e = $.sM.f.find('[group="name"]')
e.name = e.e.val()
$('.mon_groups .add').click();
e.v = $.sM.g.val()
e.e.val(e.name)
}
e.group=$user.mon_groups[e.v];
$.sM.f.find('[group]').each(function(n,v){
v=$(v)
e.group[v.attr('group')]=v.val()
});
$user.mon_groups[e.v]=e.group;
$.sM.g.find('option[value="'+$.sM.g.val()+'"]').text(e.group.name)
$.sM.writewMonGroups()
})
$.sM.f.on('click','.mon_groups .delete',function(e){
e.v=$.sM.g.val();
delete($user.mon_groups[e.v]);
$.sM.reDrawMonGroups()
})
$.sM.f.on('click','.mon_groups .add',function(e){
e.gid=$.ccio.gid(5);
$user.mon_groups[e.gid]={id:e.gid,name:e.gid};
$.sM.g.append($.ccio.tm('option',$user.mon_groups[e.gid]));
$.sM.g.val(e.gid)
$.sM.g.change();
});
$.sM.linkChange=function(){
var e={};
e.e=$.sM.e.find('[name="details"]')
e.details=JSON.parse(e.e.val())
e.details.links=[]
$.sM.links.find('.linksGroup').each(function(n,v){
var arr={}
$(v).find('[link]').each(function(m,b){
arr[$(b).attr('link')]=$(b).val()
})
e.details.links.push(arr)
})
e.e.val(JSON.stringify(e.details))
}
$.sM.f.on('change','[link]',$.sM.linkChange)
$.sM.e.on('click','.linkShinobi .delete',function(){
$(this).parents('.linksGroup').remove()
$.sM.linkChange()
})
$.sM.e.find('.linkShinobi .add').click(function(){
$.ccio.tm('link-set',{},'#linkShinobi')
$.sM.linkChange()
})
})

View File

@ -0,0 +1,147 @@
$(document).ready(function(e){
//videos window
$.vidview={
e:$('#videos_viewer'),
pages:$('#videos_viewer_pages'),
limit:$('#videos_viewer_limit'),
dr:$('#videos_viewer_daterange'),
preview:$('#videos_viewer_preview'),
set:$('#videos_viewer_set')
}
$.vidview.set.change(function(){
var el = $(this)
var isCloud = (el.val() === 'cloud')
var zipDlButton = $.vidview.e.find('.export_selected')
if(isCloud){
zipDlButton.hide()
}else{
zipDlButton.show()
}
})
$.vidview.f=$.vidview.e.find('form')
$.vidview.dr.daterangepicker({
startDate:$.ccio.timeObject().subtract(moment.duration("24:00:00")),
endDate:$.ccio.timeObject().add(moment.duration("24:00:00")),
timePicker: true,
timePicker24Hour: true,
timePickerSeconds: true,
timePickerIncrement: 30,
locale: {
format: 'MM/DD/YYYY h:mm A'
}
},function(start, end, label){
$.vidview.launcher.click()
$.vidview.dr.focus()
});
$.vidview.e.on('change','#videos_select_all',function(e){
e.e=$(this);
e.p=e.e.prop('checked')
e.a=$.vidview.e.find('input[type=checkbox][name]')
if(e.p===true){
e.a.prop('checked',true)
}else{
e.a.prop('checked',false)
}
})
$.vidview.f.submit(function(e){
e.preventDefault();
$.vidview.launcher.click()
return false;
})
$('#videos_viewer_limit,#videos_viewer_daterange,#videos_viewer_set').change(function(){
$.vidview.f.submit()
})
$.vidview.getSelected = function(getArray){
var arr = {}
if(getArray){
arr = []
}
$.vidview.f.find('[data-ke] input:checked').each(function(n,v){
v=$(v).parents('tr')
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(lang['Delete Selected Videos'])
e.html=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(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(lang['Export Selected Videos'])
var html = 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($.ccio.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');
$.vidview.current_page=e.page;
if(e.limit.replace(/ /g,'')===''){
e.limit='100';
}
if(e.limit.indexOf(',')>-1){
e.limit=parseInt(e.limit.split(',')[1])
}else{
e.limit=parseInt(e.limit)
}
$.vidview.limit.val((parseInt(e.page)-1)+'00,'+e.limit)
$.vidview.launcher.click()
})
$.vidview.e.on('click','.preview',function(e){
e.preventDefault()
e=$(this)
$.vidview.preview.html('<video class="video_video" video="'+e.attr('href')+'" preload controls autoplay><source src="'+e.attr('href')+'" type="video/mp4"></video>')
})
})

View File

@ -1156,7 +1156,9 @@ switch($user.details.lang){
tmp+='</li>';
break;
case'option':
tmp+='<option auth="'+user.auth_token+'" value="'+d.id+'">'+d.name+'</option>'
var selected = ''
if(d.selected === true){selected = ' selected'}
tmp+='<option auth="'+user.auth_token+'"'+selected+' value="'+d.id+'">'+d.name+'</option>'
break;
case'stream-element':
try{k.d=JSON.parse(d.details);}catch(er){k.d=d.details}

View File

@ -12,6 +12,9 @@
<link rel="stylesheet" href="<%-window.libURL%>libs/css/fullcalendar.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap-table.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/main.dash2.css">
<% customAutoLoad.adminLibsCss.forEach(function(lib){ %>
<link rel="stylesheet" href="<%-window.libURL%>libs/css/<%-lib%>">
<% }) %>
<body class="shinobi-bg">
<div class="container-fluid">
<div class="container">
@ -80,8 +83,14 @@
</div>
</div>
</div>
<script>
var adminApiPrefix = "<%=originalURL%><%=config.webPaths.adminApiPrefix%>"
</script>
<% include blocks/confirm.ejs %>
<% include blocks/subpermissions.ejs %>
<% customAutoLoad.adminPageBlocks.forEach(function(block){ %>
<%- include(block) %>
<% }) %>
</body>
<script><% include ../libs/js/basic.js %></script>
<script><% include ../libs/js/socket.io.js %></script>
@ -275,3 +284,6 @@ $('body')
localStorage.removeItem('ShinobiLogin_'+location.host);location.href=location.href;
})
</script>
<% customAutoLoad.adminLibsJs.forEach(function(lib){ %>
<script src="<%-window.libURL%>libs/js/<%-lib%>"></script>
<% }) %>

View File

@ -93,3 +93,4 @@
</form>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.apiwindow.js"></script>

View File

@ -259,3 +259,4 @@
</form>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.detectorfilter.js"></script>

View File

@ -28,8 +28,8 @@
<div class="form-group-group blue where">
<h4><%- lang['Find Where'] %>
<div class="pull-right">
<a class="btn btn-default btn-xs add">&nbsp;<i class="fa fa-plus"></i>&nbsp;</a>
<a class="btn btn-danger btn-xs remove">&nbsp;<i class="fa fa-minus"></i>&nbsp;</a>
<a class="btn btn-default btn-xs add">&nbsp;<i class="fa fa-plus"></i>&nbsp;</a>
<a class="btn btn-danger btn-xs remove">&nbsp;<i class="fa fa-minus"></i>&nbsp;</a>
</div>
</h4>
<div id="filters_where">
@ -39,20 +39,20 @@
<div class="form-group col-md-4">
<label>
<div><select class="form-control" name="sort_by">
<option value="time" selected><%- lang['Start Time'] %></option>
<option value="end"><%- lang['End Time'] %></option>
<option value="time" selected><%- lang['Start Time'] %></option>
<option value="end"><%- lang['End Time'] %></option>
<option value="mid"><%- lang['Monitor ID'] %></option>
<option value="ext"><%- lang['File Type'] %></option>
<option value="size"><%- lang['Filesize'] %></option>
<option value="status"><%- lang['Video Status'] %></option>
<option value="ext"><%- lang['File Type'] %></option>
<option value="size"><%- lang['Filesize'] %></option>
<option value="status"><%- lang['Video Status'] %></option>
</select></div>
</label>
</div>
<div class="form-group col-md-4">
<label>
<div><select class="form-control" name="sort_by_direction">
<option value="ASC" selected><%- lang['ASC'] %></option>
<option value="DESC"><%- lang['DESC'] %></option>
<option value="ASC" selected><%- lang['ASC'] %></option>
<option value="DESC"><%- lang['DESC'] %></option>
</select></div>
</label>
</div>
@ -68,8 +68,8 @@
<div class="form-group">
<label><div><span><%- lang['Enabled'] %></span></div>
<div><select class="form-control" name="enabled">
<option value="0" selected><%- lang['No'] %></option>
<option value="1"><%- lang['Yes'] %></option>
<option value="0" selected><%- lang['No'] %></option>
<option value="1"><%- lang['Yes'] %></option>
</select></div>
</label>
</div>
@ -77,24 +77,24 @@
<div class="form-group col-md-12 hidden">
<label><div><span><%- lang['Archive'] %></span></div>
<div><select class="form-control" name="archive">
<option value="0" selected><%- lang['No'] %></option>
<option value="1"><%- lang['Yes'] %></option>
<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['Email Details'] %></span></div>
<div><select class="form-control" name="email">
<option value="0" selected><%- lang['No'] %></option>
<option value="1"><%- lang['Yes'] %></option>
<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['Delete Matches'] %></span></div>
<div><select class="form-control" name="delete">
<option value="0" selected><%- lang['No'] %></option>
<option value="1"><%- lang['Yes'] %></option>
<option value="0" selected><%- lang['No'] %></option>
<option value="1"><%- lang['Yes'] %></option>
</select></div>
</label>
</div>
@ -115,4 +115,5 @@
</div>
</form>
</div>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.cronfilter.js"></script>

View File

@ -35,7 +35,7 @@
<div class="fixed-table-container">
<div class="fixed-table-body">
<table class="table table-striped">
<tbody class="search-body"></tbody>
<tbody class="search-body"></tbody>
</table>
</div>
</div>
@ -48,4 +48,5 @@
</div>
</div>
</div>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.logviewer.js"></script>

View File

@ -185,7 +185,7 @@
<script>
//add new
$.aN={e:$('#add_edit')};$.aN.f=$.aN.e.find('form')
$.aN.modeIsEdit = false
$.aN.modeIsEdit = function(){return $('#edit').is(':checked')}
$.aN.f.submit(function(e){
e.preventDefault();
var formValues = $.aN.f.serializeObject()
@ -193,7 +193,7 @@ $.aN.f.submit(function(e){
data: formValues
}
var webPath = 'registerAdmin'
if($.aN.modeIsEdit){
if($.aN.modeIsEdit()){
webPath = 'editAdmin'
postData.account = $.aN.selected
}
@ -210,14 +210,23 @@ $.aN.e.on('change','[name="mail"]',function(){
var thisVal = $(this).val()
$.each(users,function(n,user){
if($.aN.selected && user.ke !== $.aN.selected.ke && thisVal.toLowerCase() === user.mail.toLowerCase()){
new PNotify({text:"<%=lang['Email address is in use.']%>",type:'error'})
new PNotify({text:lang['Email address is in use.'],type:'error'})
}
})
})
//client side group key check
$.aN.e.on('change','[name="ke"]',function(){
var thisVal = $(this).val()
$.each(users,function(n,user){
if(!$.aN.modeIsEdit() && user.ke === thisVal){
new PNotify({text:lang['Group Key is in use.'] + ' ' + lang['Create Sub-Accounts at /admin'],type:'error'})
}
})
})
$.aN.e.on('change','[detail]',function(){
e = {}
e.ar = {}
if($.aN.modeIsEdit){
if($.aN.modeIsEdit()){
try{
e.ar = Object.assign(JSON.parse($.aN.selected.details),{})
}catch(err){
@ -232,12 +241,10 @@ $.aN.e.on('change','[detail]',function(){
})
$('#edit').change(function(e){
if($('#edit').is(':checked')){
$.aN.modeIsEdit = true
$('#title').text("<%-lang['Edit']%>")
$('#title').text(lang['Edit'])
$.aN.e.find('[name="ke"]').prop('disabled',true)
}else{
$.aN.modeIsEdit = false
$('#title').text("<%-lang['Add New']%>")
$('#title').text(lang['Add New'])
$.aN.e.find('input,select').prop('disabled',false)
}
$.aN.e.find('[detail]').first().change()
@ -288,6 +295,7 @@ $.aC.e.on('click','.delete',function(e){
});
})
$.aC.e.on('click','.permission',function(e){
$('#edit').prop('checked',true).change().parent().addClass('is-checked')
$.aN.e.modal('show')
e.e=$(this).parents('tr');
e.u=e.e.attr('ke');
@ -303,7 +311,6 @@ $.aC.e.on('click','.permission',function(e){
$.each(JSON.parse(e.account.details),function(n,v){
$.aN.e.find('[detail="'+n+'"]').val(v)
})
$('#edit').prop('checked',true).change().parent().addClass('is-checked')
// $.pR.e.modal('show');
})

View File

@ -0,0 +1,182 @@
<div class="modal dark fade" id="monitorStates" role="dialog" aria-labelledby="monitorStatesLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="monitorStatesLabel"><i class="fa fa-align-right"></i> &nbsp; <%-lang['Monitor States']%></h4>
</div>
<div class="modal-body">
<div class="form-group">
<label>
<div><select class="form-control" id="monitorStatesSelector">
<option value=""><%-lang['Add New']%></option>
<optgroup label="<%-lang['Saved Presets']%>"></optgroup>
</select></div>
</label>
</div>
<div class="form-group-group green">
<h4><%- lang['Preset'] %>
<div class="pull-right">
<a class="btn btn-danger btn-xs delete" style="display:none">&nbsp;<i class="fa fa-trash-o"></i>&nbsp;</a>
</div>
</h4>
<div class="form-group">
<label><div><span><%-lang['Name']%></span></div>
<div><input class="form-control" name="name"></div>
</label>
</div>
</div>
<div class="form-group-group blue">
<h4><%- lang['Monitors'] %>
<div class="pull-right">
<a class="btn btn-default btn-xs add">&nbsp;<i class="fa fa-plus"></i>&nbsp;</a>
</div>
</h4>
<div id="monitorStatesMonitors">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal"><i class="fa fa-times"></i> <%-lang.Close%></button>
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#schedules"><i class="fa fa-clock-o"></i> <%-lang.Schedules%></button>
<button type="submit" class="btn btn-success"><i class="fa fa-check"></i> <%-lang.Save%></button>
</div>
</form>
</div>
</div>
<script>
$(document).ready(function(){
$.monitorStates = {
e: $('#monitorStates'),
selector: $('#monitorStatesSelector'),
monitors: $('#monitorStatesMonitors'),
loaded: {}
}
$.monitorStates.f = $.monitorStates.e.find('form')
$.monitorStates.loadPresets = function(callback){
$.get($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke,function(d){
var html = ''
$.each(d.presets,function(n,v){
$.monitorStates.loaded[v.name] = v
html += '<option value="' + v.name + '">' + v.name + '</option>'
})
$.monitorStates.selector.find('optgroup').html(html)
if(callback)callback()
})
}
$.monitorStates.e.on('shown.bs.modal', function (e) {
if($.monitorStates.selector.val() === '')$.monitorStates.loadPresets()
})
$.monitorStates.add = function(loaded,doAppend){
if(!loaded){
json = ''
}else{
json = JSON.stringify(loaded,null,3)
}
var html = '<div class="state-monitor-row"><h4 style="margin-top:7.5px;margin-bottom:7.5px"><small>&nbsp;</small><div class="pull-right"><a class="btn btn-danger btn-xs delete-monitor"><i class="fa fa-trash-o"></i></a></div></h4><textarea class="json form-control" style="width:100%;height:300px">' + json +'</textarea></div>'
if(doAppend)$.monitorStates.monitors.append(html)
return html
}
$.monitorStates.e.find('.add').click(function(e){
$.monitorStates.add(null,true)
})
$.monitorStates.e.on('change','.json',function(e){
var el = $(this)
var val = el.val()
try{
el.css('border-color','green')
var parsed = JSON.parse(val)
el.val(JSON.stringify(parsed,null,3))
}catch(err){
el.css('border-color','red')
return $.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
}
})
$.monitorStates.e.on('click','.delete',function(e){
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Monitor States Preset']);
$.confirm.body.html(lang.deleteMonitorStateText1);
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
var form = $.monitorStates.f.serializeObject()
$.post($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke + '/' + form.name + '/delete',function(d){
$.ccio.log(d)
if(d.ok === true){
$.monitorStates.loadPresets()
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
})
})
$.monitorStates.e.on('click','.delete-monitor',function(e){
var el = $(this).parents('.state-monitor-row')
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Monitor State']);
$.confirm.body.html(lang.deleteMonitorStateText2)
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
el.remove()
})
})
$.monitorStates.selector.change(function(e){
var selected = $(this).val()
var loaded = $.monitorStates.loaded[selected]
var namespace = $.monitorStates.e.find('[name="name"]')
var deleteButton = $.monitorStates.e.find('.delete')
if(loaded){
namespace.val(loaded.name)
var html = ''
$.each(loaded.details.monitors,function(n,v){
html += $.monitorStates.add(v)
})
$.monitorStates.monitors.html(html)
deleteButton.show()
}else{
namespace.val('')
$.monitorStates.monitors.empty()
deleteButton.hide()
}
})
$.monitorStates.f.submit(function(e){
e.preventDefault()
var el = $(this)
var form = el.serializeObject()
var monitors = []
var failedToParseAJson = false
var rows = $.monitorStates.monitors.find('.state-monitor-row')
if(form.name === ''){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Name cannot be empty.'],type:'error'})
}
if(rows.length === 0){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Must be atleast one row'],type:'error'})
}
rows.each(function(n,v){
var el = $(v)
try{
console.log(el.find('.json').val())
var json = JSON.parse(el.find('.json').val())
if(json.mid)monitors.push(json)
}catch(err){
console.log(err)
failedToParseAJson = true
}
})
if(failedToParseAJson === true){
return $.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
}
var data = {
monitors: monitors
}
$.post($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke + '/' + form.name + '/insert',{data:data},function(d){
$.ccio.log(d)
if(d.ok === true){
$.monitorStates.loadPresets(function(){
$.monitorStates.selector.val(form.name)
})
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
return false;
})
})
</script>

View File

@ -169,7 +169,7 @@
</div>
<div class="form-group">
<label><div><span><%-lang['Retry Connection']%></span></div>
<div><input class="form-control" detail="fatal_max" placeholder="10"></div>
<div><input class="form-control" detail="fatal_max" placeholder="0"></div>
</label>
</div>
<div class="form-group">
@ -284,6 +284,14 @@
<div><input class="form-control" detail="hwaccel_device"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Use coProcessor']%></span></div>
<div><select class="form-control" detail="use_coprocessor">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
</div>
</div>
<!-- END of Input -->
@ -842,6 +850,11 @@
<div><input class="form-control" detail="cust_record"></div>
</label>
</div>
<div class="form-group h_rec_mtd_input h_rec_mtd_sip" style="display:none">
<label><div><span><%-lang['Traditional Recording Flags']%></span></div>
<div><input class="form-control" detail="cust_sip_record"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Output Method']%></span></div>
<div><input class="form-control" detail="custom_output" placeholder="-f flv rtmp://.."></div>
@ -1065,14 +1078,6 @@
</select></div>
</label>
</div>
<div class="form-group h_det_pam_input h_det_pam_1">
<label><div><span><%-lang['Show Matrices']%></span></div>
<div><select class="form-control" detail="detector_show_matrix">
<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['Indifference']%></span></div>
<div><input class="form-control" detail="detector_sensitivity" placeholder="0.5"></div>
@ -1114,16 +1119,6 @@
<div><input class="form-control" detail="detector_noise_filter_range" placeholder="6"></div>
</label>
</div>
<!--
<div class="form-group">
<label><div><span><%-lang['Show Regions of Interest']%></span></div>
<div><select class="form-control" detail="detector_region_of_interest">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
-->
<div class="form-group-group orange" section id="monSectionNoMotionDetector">
<h4><%-lang['"No Motion" Detector']%></h4>
<div class="form-group">
@ -1149,6 +1144,29 @@
</div>
</div>
</div>
<!-- Start of Audio Detection -->
<div class="form-group-group orange" section id="monSectionAudioDetector">
<h4><%-lang['Audio Detector']%></h4>
<div class="form-group">
<label><div><span><%-lang['Enabled']%></span></div>
<div><select class="form-control" detail="detector_audio">
<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['Minimum dB']%></span></div>
<div><input class="form-control" detail="detector_audio_min_db" placeholder="5"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Maximum dB']%></span></div>
<div><input class="form-control" detail="detector_audio_max_db" placeholder=""></div>
</label>
</div>
</div>
<!-- END of Audio Detection -->
<div class="form-group-group orange shinobi-detector-opencv shinobi-detector-openalpr shinobi-detector-yolo shinobi-detector-dlib shinobi-detector_plug" section id="monSectionDetectorObject">
<h4><%-lang['Object Detection']%> <small><%-lang['Plugin']%> : <b class="shinobi-detector_name"></b> <b class="shinobi-detector-invert"><%-lang['Not Connected']%></b><b class="shinobi-detector" style="display:none"><%-lang['Connected']%></b></small></h4>
<div class="form-group">
@ -1159,6 +1177,14 @@
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Require Object to be in Region']%></span></div>
<div><select class="form-control" detail="detector_obj_region">
<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['Check for Motion First']%></span></div>
<div><select class="form-control" detail="detector_use_motion" selector="h_det_mot_fir">
@ -1597,3 +1623,4 @@
</form>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.monitoredit.js"></script>

View File

@ -35,4 +35,5 @@
</div>
</div>
</div>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.multimon.js"></script>

View File

@ -84,3 +84,4 @@
</div>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.powervideo.js"></script>

View File

@ -30,7 +30,7 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal"><i class="fa fa-times"></i> <%-lang.Close%></button>
<a class="btn btn-danger stop" style="display:none"><%-lang.Stop%><span> &nbsp; <i class="fa fa-pulse fa-spinner"></i></span></a>
<a class="btn btn-danger stop" style="display:none"><%-lang.Stop%><span> &nbsp; <i class="fa fa-pulse fa-spinner"></i></span></a>
<button type="submit" class="btn btn-success"><%-lang.Check%></button>
</div>
</form>
@ -91,4 +91,7 @@
</div>
</form>
</div>
</div>
</div>
<!-- -->
<script src="<%-window.libURL%>libs/js/dash2.probe.js"></script>
<script src="<%-window.libURL%>libs/js/dash2.onvifscanner.js"></script>

View File

@ -81,3 +81,4 @@
</form>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.regioneditor.js"></script>

View File

@ -0,0 +1,179 @@
<div class="modal dark fade" id="schedules" role="dialog" aria-labelledby="schedulesLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="schedulesLabel"><i class="fa fa-clock-o"></i> &nbsp; <%-lang['Schedules']%></h4>
</div>
<div class="modal-body">
<div class="form-group">
<label>
<div><select class="form-control" id="schedulesSelector">
<option value=""><%-lang['Add New']%></option>
<optgroup label="<%-lang['Saved Schedules']%>"></optgroup>
</select></div>
</label>
</div>
<div class="form-group-group green">
<h4><%- lang['Schedule'] %>
<div class="pull-right">
<a class="btn btn-danger btn-xs delete" style="display:none">&nbsp;<i class="fa fa-trash-o"></i>&nbsp;</a>
</div>
</h4>
<div class="form-group">
<label><div><span><%-lang['Name']%></span></div>
<div><input class="form-control" name="name"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Enabled']%></span></div>
<div><select class="form-control" name="enabled">
<option value="1" selected><%-lang.Yes%></option>
<option value="0"><%-lang.No%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Start']%></span></div>
<div><input class="form-control" name="start" placeholder="HH:ss"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['End']%></span></div>
<div><input class="form-control" name="end" placeholder="HH:ss"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Monitor States']%></span></div>
<div><select class="form-control" style="min-height:100px" multiple name="monitorStates">
</select></div>
</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal"><i class="fa fa-times"></i> <%-lang.Close%></button>
<button type="submit" class="btn btn-success"><i class="fa fa-check"></i> <%-lang.Save%></button>
</div>
</form>
</div>
</div>
<script>
$(document).ready(function(){
$.schedules = {
e: $('#schedules'),
selector: $('#schedulesSelector'),
loadedMonitorStates: {},
loadedSchedules: {}
}
$.schedules.f = $.schedules.e.find('form')
$.schedules.selectedStates = $.schedules.e.find('[name="monitorStates"]')
$.schedules.loadSchedules = function(callback){
$.get($.ccio.init('location',$user) + $user.auth_token + '/schedule/' + $user.ke,function(d){
console.log(d)
var html = ''
$.each(d.schedules,function(n,v){
$.schedules.loadedSchedules[v.name] = v
html += $.ccio.tm('option',{
id: v.name,
name: v.name
})
})
$.schedules.selector.find('optgroup').html(html)
if(callback)callback()
})
}
$.schedules.loadMonitorStates = function(){
$.get($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke,function(d){
var html = ''
$.each(d.presets,function(n,v){
$.schedules.loadedMonitorStates[v.name] = v
html += $.ccio.tm('option',{
id: v.name,
name: v.name
})
})
$.schedules.selectedStates.html(html)
})
}
$.schedules.e.on('shown.bs.modal', function (e) {
$.schedules.loadMonitorStates()
$.schedules.loadSchedules()
})
$.schedules.e.on('click','.delete',function(e){
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Monitor States Preset']);
$.confirm.body.html(lang.deleteMonitorStateText1);
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
var form = $.schedules.f.serializeObject()
$.post($.ccio.init('location',$user) + $user.auth_token + '/schedule/' + $user.ke + '/' + form.name + '/delete',function(d){
$.ccio.log(d)
if(d.ok === true){
$.schedules.loadSchedules()
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
})
})
$.schedules.selector.change(function(e){
var selected = $(this).val()
var loaded = $.schedules.loadedSchedules[selected]
var namespace = $.schedules.e.find('[name="name"]')
var deleteButton = $.schedules.e.find('.delete')
$.schedules.selectedStates.find('option:selected').removeAttr('selected')
if(loaded){
namespace.val(loaded.name)
var html = ''
$.each(loaded,function(n,v){
$.schedules.f.find('[name="' + n + '"]').val(v)
})
$.each(loaded.details.monitorStates,function(n,v){
$.schedules.selectedStates.find('option[value="' + v + '"]').prop('selected',true)
})
deleteButton.show()
}else{
namespace.val('')
deleteButton.hide()
}
})
$.schedules.f.submit(function(e){
e.preventDefault()
var el = $(this)
var form = el.serializeObject()
var monitors = []
var failedToParseAJson = false
var rows = $.monitorStates.monitors.find('.state-monitor-row')
if(form.name === ''){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Name cannot be empty.'],type:'error'})
}
if(form.start === ''){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Start Time cannot be empty.'],type:'error'})
}
if(form.monitorStates instanceof Array === false){
form.monitorStates = [form.monitorStates]
}
console.log(form.monitorStates)
var data = {
start: form.start,
end: form.end,
enabled: form.enabled,
details:{
monitorStates: form.monitorStates
}
}
$.post($.ccio.init('location',$user) + $user.auth_token + '/schedule/' + $user.ke + '/' + form.name + '/insert',{data:data},function(d){
$.ccio.log(d)
if(d.ok === true){
$.schedules.loadSchedules(function(){
$.schedules.selector.val(form.name)
})
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
return false;
})
})
</script>

View File

@ -503,3 +503,4 @@
</form>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.usersettings.js"></script>

View File

@ -77,4 +77,5 @@
</div>
</div>
</div>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.timelapse.js"></script>

View File

@ -77,3 +77,4 @@
</div>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.vidview.js"></script>

View File

@ -14,7 +14,22 @@
<link rel="stylesheet" href="<%-window.libURL%>libs/css/gridstack.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/gridstack-extra.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap-table.min.css">
<!--
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.basic.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.forms.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.modal.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.monitors.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.powervideo.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.ptzcontrols.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.regioneditor.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.rightotleft.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.timelapse.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/main.dash2.css">
-->
<link rel="stylesheet" href="<%-window.libURL%>libs/css/main.dash2.old.css">
<% customAutoLoad.LibsCss.forEach(function(lib){ %>
<link rel="stylesheet" href="<%-window.libURL%>libs/css/<%-lib%>">
<% }) %>
<style id="theme">
<% if(details.theme&&details.theme!==''){ %><%- include(__dirname+'/web/libs/themes/'+details.theme+'/style.css'); %><% } %>
</style>
@ -121,6 +136,8 @@
<% 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="#monitorStates"><div><i class="fa fa-align-right"></i><div><%- lang['Monitor States'] %></div></div></li>
<li class="mdl-menu__item" data-toggle="modal" data-target="#schedules"><div><i class="fa fa-clock-o"></i><div><%- lang['Schedules'] %></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 permission_view_logs" data-toggle="modal" data-target="#logs_modal"><div><i class="fa fa-exclamation-triangle"></i><div><%- lang.Logs %></div></div></li>
@ -167,7 +184,12 @@
<% include blocks/probe.ejs %>
<% include blocks/region.ejs %>
<% include blocks/detectorfilters.ejs %>
<% include blocks/monitorStates.ejs %>
<% include blocks/schedules.ejs %>
<% include blocks/confirm.ejs %>
<% customAutoLoad.PageBlocks.forEach(function(block){ %>
<%- include(block) %>
<% }) %>
<% if(config.DropboxAppKey){ %>
<!--Dropbox Library, Change data-app-key to your app key. -->
<script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="<%= config.DropboxAppKey %>"></script>
@ -198,5 +220,15 @@
<script src="<%-window.libURL%>libs/js/gridstack.min.js"></script>
<script src="<%-window.libURL%>libs/js/gridstack.jQueryUI.min.js"></script>
<script src="<%-window.libURL%>libs/js/basic.js"></script>
<script><% include ../libs/js/main.dash2.js %></script>
<script><% include ../libs/js/dash2.config.js %></script>
<script src="<%-window.libURL%>libs/js/dash2.basic.js"></script>
<script src="<%-window.libURL%>libs/js/dash2.confirm.js"></script>
<script src="<%-window.libURL%>libs/js/dash2.socketio.js"></script>
<script src="<%-window.libURL%>libs/js/dash2.gridstack.js"></script>
<script src="<%-window.libURL%>libs/js/dash2.elements.js"></script>
<script src="<%-window.libURL%>libs/js/dash2.elementbuilder.js"></script>
<script src="<%-window.libURL%>libs/js/dash2.init.js"></script>
<% customAutoLoad.LibsJs.forEach(function(lib){ %>
<script src="<%-window.libURL%>libs/js/<%-lib%>"></script>
<% }) %>
<% include blocks/help.ejs %>

View File

@ -27,6 +27,9 @@
.list-group li .form-group {margin:0}
a {cursor:pointer}
</style>
<% customAutoLoad.superLibsCss.forEach(function(lib){ %>
<link rel="stylesheet" href="<%-window.libURL%>libs/css/<%-lib%>">
<% }) %>
</head>
<body class="index-page sidebar-collapse bg-hexagon">
@ -62,7 +65,7 @@
<div class="row">
<div class="col-md-12">
<div id="main-card" class="card">
<ul class="nav nav-tabs nav-tabs-neutral justify-content-center bg-primary" role="tablist">
<ul class="nav nav-tabs nav-tabs-neutral justify-content-center bg-primary" id="tablist" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#accounts" role="tab">Accounts</a>
</li>
@ -169,8 +172,15 @@
</div>
</div>
</div>
<div id="temp" style="display:none"></div>
</body>
<script>
var superApiPrefix = "<%=originalURL%><%=config.webPaths.superApiPrefix%>"
</script>
<% include blocks/confirm.ejs %>
<% customAutoLoad.superPageBlocks.forEach(function(block){ %>
<%- include(block) %>
<% }) %>
<script src="<%-window.libURL%>libs/js/pnotify.custom.min.js" type="text/javascript"></script>
<script><% include ../libs/js/moment.js %></script>
<script src="<%-window.libURL%>libs/js/livestamp.min.js" type="text/javascript"></script>
@ -178,6 +188,7 @@
<script src="<%-window.libURL%>libs/js/placeholder.js" type="text/javascript"></script>
<script src="<%-window.libURL%>libs/js/now-ui-kit.js?v=1.1.0" type="text/javascript"></script>
<script type="text/javascript">
var lang = <%- JSON.stringify(lang) || {} %>;
PNotify.prototype.options.styling = "fontawesome";
$(document).ready(function() {
// the body of this function is in assets/js/now-ui-kit.js
@ -530,4 +541,7 @@ $('body')
})
</script>
<% include blocks/mainpermissions.ejs %>
<% customAutoLoad.superLibsJs.forEach(function(lib){ %>
<script src="<%-window.libURL%>libs/js/<%-lib%>"></script>
<% }) %>
</html>