Test script additions and cleanup

- run test with "node test.js" or "npm test" inside the Shinobi directory
- minor readability cleanup
+ show Object Detection section with yolo plugin
+ prettify Video Grid css
+ make thumbnail load recursive instead of at once
merge-requests/35/head
Moe 2018-10-23 17:37:51 -07:00
parent 224a06cb3e
commit ee881f7415
12 changed files with 154 additions and 105 deletions

View File

@ -8,33 +8,13 @@
// If you like what I am doing here and want me to continue please consider donating :)
// PayPal : paypal@m03.ca
//
var os = require('os');
var io = new (require('socket.io'))()
// s = Shinobi
s = {
//Total Memory
coreCount : os.cpus().length,
//Total Memory
totalmem : os.totalmem(),
//Check Platform
platform : os.platform(),
//JSON stringify short-hand
s : JSON.stringify,
//Pretty Print JSON
prettyPrint : function(obj){return JSON.stringify(obj,null,3)},
//Check if Windows
isWin : (process.platform === 'win32' || process.platform === 'win64'),
//UTC Offset
utcOffset : require('moment')().utcOffset(),
//directory path for this file
mainDirectory : __dirname
}
//library loader
var loadLib = function(lib){
return require(__dirname+'/libs/'+lib+'.js')
}
//process handlers
loadLib('process')(process)
var s = loadLib('process')(process,__dirname)
//configuration loader
var config = loadLib('config')(s)
//language loader

View File

@ -12,14 +12,18 @@ module.exports = function(s,config,lang,app,io){
childNodeServer.listen(config.childNodes.port,config.bindip,function(){
console.log(lang.Shinobi+' - CHILD NODE PORT : '+config.childNodes.port);
});
console.log('childNodeWebsocket.attach(childNodeServer)')
s.debugLog('childNodeWebsocket.attach(childNodeServer)')
childNodeWebsocket.attach(childNodeServer);
//send data to child node function (experimental)
s.cx = function(z,y,x){if(!z.mid && !z.d){
var err = new Error();
console.log(err.stack);
};
if(x){return x.broadcast.to(y).emit('c',z)};childNodeWebsocket.to(y).emit('c',z);}
s.cx = function(z,y,x){
if(!z.mid && !z.d){
console.error('Missing ID')
}else if(x){
x.broadcast.to(y).emit('c',z)
}else{
childNodeWebsocket.to(y).emit('c',z)
}
}
//child Node Websocket
childNodeWebsocket.on('connection', function (cn) {
//functions for dispersing work to child servers;
@ -40,7 +44,6 @@ module.exports = function(s,config,lang,app,io){
d.availableHWAccels.forEach(function(accel){
if(config.availableHWAccels.indexOf(accel) === -1)config.availableHWAccels.push(accel)
})
tx({
f : 'init_success',
childNodes : s.childNodes

View File

@ -2,9 +2,10 @@ var fs = require('fs');
var spawn = require('child_process').spawn;
var execSync = require('child_process').execSync;
module.exports = function(s,config,onFinish){
var ffmpeg = {}
var downloadingFfmpeg = false;
//check local ffmpeg
var windowsFfmpegCheck = function(failback){
ffmpeg.checkForWindows = function(failback){
if (s.isWin && fs.existsSync(s.mainDirectory+'/ffmpeg/ffmpeg.exe')) {
config.ffmpegDir = s.mainDirectory+'/ffmpeg/ffmpeg.exe'
}else{
@ -12,7 +13,7 @@ module.exports = function(s,config,onFinish){
}
}
//check local ffmpeg
var unixFfmpegCheck = function(failback){
ffmpeg.checkForUnix = function(failback){
if(s.isWin === false){
if (fs.existsSync('/usr/bin/ffmpeg')) {
config.ffmpegDir = '/usr/bin/ffmpeg'
@ -28,7 +29,7 @@ module.exports = function(s,config,onFinish){
}
}
//check node module : ffmpeg-static
var ffmpegStaticCheck = function(failback){
ffmpeg.checkForNpmStatic = function(failback){
try{
var staticFFmpeg = require('ffmpeg-static').path;
if (fs.statSync(staticFFmpeg)) {
@ -44,7 +45,7 @@ module.exports = function(s,config,onFinish){
}
}
//check node module : ffbinaries
var ffbinaryCheck = function(failback){
ffmpeg.checkForFfbinary = function(failback){
try{
ffbinaries = require('ffbinaries')
var ffbinaryDir = s.mainDirectory + '/ffmpeg/'
@ -57,7 +58,7 @@ module.exports = function(s,config,onFinish){
},function () {
config.ffmpegDir = ffbinaryDir + 'ffmpeg'
console.log('ffbinaries : FFmpeg Downloaded.');
completeFfmpegCheck()
ffmpeg.completeCheck()
})
}
if (!fs.existsSync(ffbinaryDir + 'ffmpeg')) {
@ -72,7 +73,7 @@ module.exports = function(s,config,onFinish){
}
}
//ffmpeg version
var checkFfmpegVersion = function(callback){
ffmpeg.checkVersion = function(callback){
try{
s.ffmpegVersion = execSync(config.ffmpegDir+" -version").toString().split('Copyright')[0].replace('ffmpeg version','').trim()
if(s.ffmpegVersion.indexOf(': 2.')>-1){
@ -86,7 +87,7 @@ module.exports = function(s,config,onFinish){
callback()
}
//check available hardware acceleration methods
var checkFfmpegHwAccelMethods = function(callback){
ffmpeg.checkHwAccelMethods = function(callback){
if(config.availableHWAccels === undefined){
hwAccels = execSync(config.ffmpegDir+" -loglevel quiet -hwaccels").toString().split('\n')
hwAccels.shift()
@ -100,10 +101,10 @@ module.exports = function(s,config,onFinish){
}
callback()
}
var completeFfmpegCheck = function(){
checkFfmpegVersion(function(){
checkFfmpegHwAccelMethods(function(){
onFinish()
ffmpeg.completeCheck = function(){
ffmpeg.checkVersion(function(){
ffmpeg.checkHwAccelMethods(function(){
onFinish(ffmpeg)
})
})
}
@ -372,7 +373,7 @@ module.exports = function(s,config,onFinish){
}
return x.pipe
}
var buildMainInput = function(e,x){
ffmpeg.buildMainInput = function(e,x){
//e = monitor object
//x = temporary values
//check if CUDA is enabled
@ -435,7 +436,7 @@ module.exports = function(s,config,onFinish){
x.cust_input += ' -re'
}
}
var buildMainStream = function(e,x){
ffmpeg.buildMainStream = function(e,x){
//e = monitor object
//x = temporary values
x.stream_video_filters = []
@ -610,7 +611,7 @@ module.exports = function(s,config,onFinish){
//custom - output
if(e.details.custom_output&&e.details.custom_output!==''){x.pipe+=' '+e.details.custom_output;}
}
var buildMainRecording = function(e,x){
ffmpeg.buildMainRecording = function(e,x){
//e = monitor object
//x = temporary values
x.record_video_filters = []
@ -729,7 +730,7 @@ module.exports = function(s,config,onFinish){
x.record_string+=x.vcodec+x.record_fps+x.record_video_filters+x.record_dimensions+x.segment;
}
}
var buildMainDetector = function(e,x){
ffmpeg.buildMainDetector = function(e,x){
//e = monitor object
//x = temporary values
x.cust_detect = ' '
@ -830,7 +831,7 @@ 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"'
}
}
assembleMainPieces = function(e,x){
ffmpeg.assembleMainPieces = function(e,x){
//create executeable FFMPEG command
x.ffmpegCommandString = x.loglevel+x.input_fps;
//progress pipe
@ -862,7 +863,7 @@ module.exports = function(s,config,onFinish){
//add recording and stream outputs
x.ffmpegCommandString += x.record_string+x.pipe
}
createPipeArray = function(e,x){
ffmpeg.createPipeArray = function(e,x){
//create additional pipes from ffmpeg
x.stdioPipes = [];
var times = config.pipeAddition;
@ -875,14 +876,14 @@ module.exports = function(s,config,onFinish){
}
s.ffmpeg = function(e){
//set X for temporary values so we don't break our main monitor object.
var x={tmp:''};
var x = {tmp : ''}
//set some placeholding values to avoid "undefined" in ffmpeg string.
buildMainInput(e,x)
buildMainStream(e,x)
buildMainRecording(e,x)
buildMainDetector(e,x)
assembleMainPieces(e,x)
createPipeArray(e,x)
ffmpeg.buildMainInput(e,x)
ffmpeg.buildMainStream(e,x)
ffmpeg.buildMainRecording(e,x)
ffmpeg.buildMainDetector(e,x)
ffmpeg.assembleMainPieces(e,x)
ffmpeg.createPipeArray(e,x)
//hold ffmpeg command for log stream
s.group[e.ke].mon[e.mid].ffmpeg = x.ffmpegCommandString
//clean the string of spatial impurities and split for spawn()
@ -891,10 +892,10 @@ module.exports = function(s,config,onFinish){
return spawn(config.ffmpegDir,x.ffmpegCommandString,{detached: true,stdio:x.stdioPipes})
}
if(!config.ffmpegDir){
windowsFfmpegCheck(function(){
unixFfmpegCheck(function(){
ffbinaryCheck(function(){
ffmpegStaticCheck(function(){
ffmpeg.checkForWindows(function(){
ffmpeg.checkForUnix(function(){
ffmpeg.checkForFfbinary(function(){
ffmpeg.checkForNpmStatic(function(){
console.log('No FFmpeg found.')
})
})
@ -903,6 +904,7 @@ module.exports = function(s,config,onFinish){
}
if(downloadingFfmpeg === false){
//not downloading ffmpeg
completeFfmpegCheck()
ffmpeg.completeCheck()
}
return ffmpeg
}

View File

@ -1,4 +1,5 @@
module.exports = function(process){
var os = require('os')
module.exports = function(process,__dirname){
process.send = process.send || function () {};
process.on('uncaughtException', function (err) {
console.error('Uncaught Exception occured!');
@ -9,4 +10,24 @@ module.exports = function(process){
console.log('Shinobi is Exiting...')
process.exit();
});
// s = Shinobi
s = {
//Total Memory
coreCount : os.cpus().length,
//Total Memory
totalmem : os.totalmem(),
//Check Platform
platform : os.platform(),
//JSON stringify short-hand
s : JSON.stringify,
//Pretty Print JSON
prettyPrint : function(obj){return JSON.stringify(obj,null,3)},
//Check if Windows
isWin : (process.platform === 'win32' || process.platform === 'win64'),
//UTC Offset
utcOffset : require('moment')().utcOffset(),
//directory path for this file
mainDirectory : __dirname
}
return s
}

View File

@ -6,7 +6,7 @@
"main": "camera.js",
"bin": "camera.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"test": "node test.js",
"start": "chmod +x INSTALL/start.sh && INSTALL/start.sh"
},
"repository": {

32
test.js
View File

@ -8,40 +8,21 @@
// If you like what I am doing here and want me to continue please consider donating :)
// PayPal : paypal@m03.ca
//
var os = require('os');
var io = new (require('socket.io'))()
// s = Shinobi
s = {
//Total Memory
coreCount : os.cpus().length,
//Total Memory
totalmem : os.totalmem(),
//Check Platform
platform : os.platform(),
//JSON stringify short-hand
s : JSON.stringify,
//Pretty Print JSON
prettyPrint : function(obj){return JSON.stringify(obj,null,3)},
//Check if Windows
isWin : (process.platform === 'win32' || process.platform === 'win64'),
//UTC Offset
utcOffset : require('moment')().utcOffset(),
//directory path for this file
mainDirectory : __dirname
}
//library loader
var loadLib = function(lib){
return require(__dirname+'/libs/'+lib+'.js')
}
//process handlers
loadLib('process')(process)
var s = loadLib('process')(process,__dirname)
//configuration loader
var config = loadLib('config')(s)
// change ports for test
//********* test.js >
config.port = 9999
if(config.childNodes && config.childNodes.enabled === true && config.childNodes.mode === 'master'){
config.childNodes.port = 9998
}
//********* test.js />
//language loader
var lang = loadLib('language')(s,config)
//basic functions
@ -49,7 +30,10 @@ loadLib('basic')(s,config)
//load extender functions
loadLib('extenders')(s,config)
//video processing engine
loadLib('ffmpeg')(s,config,function(){
loadLib('ffmpeg')(s,config,function(ffmpeg){
//********* test.js >
s.ffmpegFunctions = ffmpeg
//********* test.js />
//database connection : mysql, sqlite3..
loadLib('sql')(s,config)
//working directories : videos, streams, fileBin..
@ -89,5 +73,5 @@ loadLib('ffmpeg')(s,config,function(){
//notifiers : discord..
loadLib('notification')(s,config,lang)
//on-start actions, daemon(s) starter
loadLib('test')(s,config,lang,app,io)
require(__dirname+'/test/run.js')(s,config,lang,app,io)
})

View File

@ -2,11 +2,12 @@ module.exports = function(s,config,lang,app,io){
var checkResult = function(functionName,expectedResult,testResult){
if(expectedResult !== testResult){
console.log(expectedResult,testResult)
throw new Error('- ' + functionName + ' : Failed!')
throw new Error('x ' + functionName + ' : Failed!')
}else{
console.log('- ' + functionName + ' : Success')
}
}
var sampleMonitorObject = require('./testMonitor-WatchOnly.json')
var test = {
"basic.js" : {
checkRelativePath : function(){
@ -82,10 +83,36 @@ module.exports = function(s,config,lang,app,io){
var expectedResult = [
'flag1',
'flag2',
'flag3',
'fl ag3',
]
var testResult = s.splitForFFPMEG('flag1 flag2 "flag3"')
var testResult = s.splitForFFPMEG('flag1 flag2 "fl ag3"')
checkResult('splitForFFPMEG',JSON.stringify(expectedResult),JSON.stringify(testResult))
},
"ffmpeg" : function(){
//command string builder
var x = {tmp : ''}
s.checkDetails(sampleMonitorObject)
sampleMonitorObject.url = s.buildMonitorUrl(sampleMonitorObject)
var expectedResult = '-loglevel warning -progress pipe:5 -analyzeduration 1000000 -probesize 1000000 -stream_loop -1 -fflags +igndts -re -i "https://cdn.shinobi.video:/videos/bears.mp4" -f mp4 -an -c:v copy -movflags +frag_keyframe+empty_moov+default_base_moof -metadata title="Poseidon Stream" -reset_timestamps 1 pipe:1'
s.ffmpegFunctions.buildMainInput(sampleMonitorObject,x)
s.ffmpegFunctions.buildMainStream(sampleMonitorObject,x)
s.ffmpegFunctions.buildMainRecording(sampleMonitorObject,x)
s.ffmpegFunctions.buildMainDetector(sampleMonitorObject,x)
s.ffmpegFunctions.assembleMainPieces(sampleMonitorObject,x)
var testResult = x.ffmpegCommandString
checkResult('ffmpeg',expectedResult,testResult)
//check pipe builder
var expectedResult = []
var times = config.pipeAddition
if(sampleMonitorObject.details.stream_channels){
times += sampleMonitorObject.details.stream_channels.length
}
for(var i=0; i < times; i++){
expectedResult.push('pipe')
}
s.ffmpegFunctions.createPipeArray(sampleMonitorObject,x)
var testResult = x.stdioPipes
checkResult('ffmpeg.createPipeArray',JSON.stringify(expectedResult),JSON.stringify(testResult))
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -332,9 +332,9 @@ form.modal-body{margin:0}
.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}
.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}

View File

@ -1,8 +1,21 @@
var tool = {}
tool.getVideoImage = function (path, secs, callback) {
var me = this, video = document.createElement('video');
var backCalled = false
var finish = function(err,data){
if(!backCalled){
backCalled = true
callback(err,data)
clearTimeout(timeout)
}
}
var timeout = setTimeout(function(){
finish(new Error('Failed Getting Snap from Video'))
},5000)
video.onloadedmetadata = function() {
this.currentTime = Math.min(Math.max(0, (secs < 0 ? this.duration : 0) + secs), this.duration)
video.play()
this.currentTime = Math.min(Math.max(0, (secs < 0 ? this.duration : 0) + secs), this.duration)
video.pause()
};
video.onseeked = function(e) {
var canvas = document.createElement('canvas')
@ -11,13 +24,13 @@ tool.getVideoImage = function (path, secs, callback) {
var ctx = canvas.getContext('2d')
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
var base64 = canvas.toDataURL()
callback(null, base64)
// delete(ctx)
// delete(video)
// delete(canvas)
finish(null, base64)
delete(ctx)
delete(video)
delete(canvas)
};
video.onerror = function(e) {
callback(e);
finish(e)
};
video.src = path;
}

View File

@ -5820,11 +5820,20 @@ $('body')
})
tmp += '</div>'
e.b.html(tmp)
$.each(d.videos,function(n,v){
tool.getVideoImage($.ccio.init('videoUrlBuild',v),0,function(err,base64){
$('[ke="'+v.ke+'"][mid="'+v.mid+'"][file="'+v.filename+'"] .thumb').css('background-image','url('+base64+')')
})
})
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':
$.vidview.e.removeClass('dark')
@ -5875,11 +5884,20 @@ $('body')
tmp+='</tbody>';
tmp+='</table>';
e.b.html(tmp)
$.each(d.videos,function(n,v){
tool.getVideoImage($.ccio.init('videoUrlBuild',v),0,function(err,base64){
$('[data-ke="'+v.ke+'"][data-mid="'+v.mid+'"][data-file="'+v.filename+'"] .thumbnail')[0].src = base64
})
})
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;

View File

@ -1141,7 +1141,7 @@
</div>
</div>
</div>
<div class="form-group-group orange shinobi-detector-opencv shinobi-detector-openalpr shinobi-detector-pythonyolo shinobi-detector-pythondlib shinobi-detector_plug" section id="monSectionDetectorObject">
<div class="form-group-group orange shinobi-detector-opencv shinobi-detector-openalpr shinobi-detector-pythonyolo shinobi-detector-yolo shinobi-detector-pythondlib shinobi-detector_plug" section id="monSectionDetectorObject">
<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">
<label><div><span><%-lang['Detect Objects']%></span></div>