Skip to content

Commit

Permalink
sunlight
Browse files Browse the repository at this point in the history
many bug fixes
update recommended
cpu indicator fixed (updated), dstat can be uninstalled
docker file updated to not install dstat
option to include timestamp on recordings
fix calendar launcher
display disk usage
  • Loading branch information
moeiscool committed Dec 29, 2016
1 parent 6ea7231 commit 73be2bd
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 80 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM ubuntu:xenial
RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y ffmpeg nodejs npm dstat
&& apt-get install -y ffmpeg nodejs npm
RUN ln -s /usr/bin/nodejs /usr/bin/node && mkdir /opt/shinobi
WORKDIR /opt/shinobi
ADD . .
Expand Down
8 changes: 0 additions & 8 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,14 +272,6 @@
<b>Optional for some OS</b>
- Install dstat :
```
apt-get install dstat
```
- It's the CPU indicator, the orange progress bar on the web panel.
- if you choose not to install or can't then it will just post an error in the log.
- Sadly there is no dstat for Mac OS.
- To daemonize the process install pm2 with
```
npm install pm2 -g
Expand Down
1 change: 0 additions & 1 deletion INSTALL.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
echo "Shinobi - Get dependencies"
#apt-get install ffmpeg
apt-get install libav-tools nodejs npm mysql-server -y
apt-get install dstat -y
echo "Shinobi - Linking node to nodejs"
ln -s /usr/bin/nodejs /usr/bin/node

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ Shinobi can record IP Cameras and Local Cameras.
- Server-side Tested on:
- Macbook (some old white one)
- Ubuntu 16.04 (should work on any linux)

- Macbook (2013, i5, 16GB RAM)
- Mac OS Sierra

-Odroid XU4 (Samsung Exynos5 Octa ARM, 2GB RAM)
- Ubuntu 16.04

- If you have successfully run Shinobi on a system not listed (client or server). Please send me a PM so I can add it to the list.

Expand Down
127 changes: 61 additions & 66 deletions camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// https://www.bountysource.com/teams/shinobi
//
var fs = require('fs');
var os = require('os-utils');
var path = require('path');
var mysql = require('mysql');
var moment = require('moment');
Expand Down Expand Up @@ -151,10 +152,8 @@ s.event=function(x,e){
e.save=[e.id,e.ke,s.nameToTime(e.filename),e.status];
sql.query('DELETE FROM Videos WHERE `mid`=? AND `ke`=? AND `time`=? AND `status`=?',e.save,function(err,r){
if(r&&r.affectedRows>0){
s.tx({f:'event_delete',filename:e.filename+'.'+e.ext,mid:e.id,ke:e.ke,time:s.nameToTime(e.filename),end:moment().format('YYYY-MM-DD HH:mm:ss')},'GRP_'+e.ke);
if(fs.existsSync(e.dir+e.filename+'.'+e.ext)){
s.file('delete',e.dir+e.filename+'.'+e.ext)
}
s.tx({f:'event_delete',filename:e.filename+'.'+e.ext,mid:e.mid,ke:e.ke,time:s.nameToTime(e.filename),end:moment().format('YYYY-MM-DD HH:mm:ss')},'GRP_'+e.ke);
s.file('delete',e.dir+e.filename+'.'+e.ext)
}
})
break;
Expand Down Expand Up @@ -192,59 +191,55 @@ s.event=function(x,e){
break;
}
}
s.ffmpeg=function(y,e,x){
s.ffmpeg=function(e,x){
if(!x){x={tmp:''}}
switch(y){
case'args':
// if(!e.details.cutoff||e.details.cutoff===''){x.cutoff=15}else{x.cutoff=parseFloat(e.details.cutoff)};if(isNaN(x.cutoff)===true){x.cutoff=15}
// x.segment=' -f segment -strftime 1 -segment_time '+(60*x.cutoff)+' -segment_format '+e.ext
x.time=' -vf drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:text=\'%{localtime}\':x=(w-tw)/2:y=0:fontcolor=white:box=1:boxcolor=0x00000000@1:fontsize=10';
switch(e.ext){
case'mp4':
x.vcodec='libx265';x.acodec='libfaac';
if(e.details.vcodec&&e.details.vcodec!==''){x.vcodec=e.details.vcodec}
if(e.details.acodec&&e.details.acodec!==''){x.acodec=e.details.acodec}
break;
case'webm':
x.acodec='libvorbis',x.vcodec='libvpx';
break;
}
if(e.fps&&e.fps!==''){e.framerate=' -r '+e.fps}else{e.framerate=''}
if(e.details.vf){x.vf=' -vf '+e.details.vf+'';}else{x.vf='';}
if(e.details.svf&&e.details.svf!==''){x.svf=' -vf '+e.details.svf;}else{x.svf='';}
if(!e.details.timestamp||e.details.timestamp==1){x.time=' -vf drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:text=\'%{localtime}\':x=(w-tw)/2:y=0:fontcolor=white:box=1:boxcolor=0x00000000@1:fontsize=10';}else{x.time=''}
switch(e.ext){
case'mp4':
x.vcodec='libx265';x.acodec='libfaac';
if(e.details.vcodec&&e.details.vcodec!==''){x.vcodec=e.details.vcodec}
if(e.details.acodec&&e.details.acodec!==''){x.acodec=e.details.acodec}
break;
case'webm':
x.acodec='libvorbis',x.vcodec='libvpx';
break;
}
if(e.fps&&e.fps!==''){e.framerate=' -r '+e.fps}else{e.framerate=''}
if(e.details.vf){x.vf=' -vf '+e.details.vf+'';}else{x.vf='';}
if(e.details.svf&&e.details.svf!==''){x.svf=' -vf '+e.details.svf;}else{x.svf='';}
// if(e.details.svf){'-vf "rotate=45*(PI/180)'}
switch(e.type){
case'socket':case'jpeg':case'pipe':
x.tmp='-loglevel quiet -pattern_type glob -f image2pipe -vcodec mjpeg -i -'+x.time+' -vcodec '+x.vcodec+e.framerate+' -use_wallclock_as_timestamps 1 -q:v 1'+x.vf+' '+e.dir+e.filename+'.'+e.ext;
break;
case'mjpeg':
if(e.mode=='record'){
x.watch=x.time+' -vcodec '+x.vcodec+e.framerate+' -s '+e.width+'x'+e.height+' -use_wallclock_as_timestamps 1 -q:v 1'+x.vf+' '+e.dir+e.filename+'.'+e.ext+''
}else{
x.watch='';
};
x.tmp='-loglevel quiet -reconnect 1 -f mjpeg -i '+e.url+''+x.watch+' -f image2pipe'+x.svf+' -s '+e.ratio+' pipe:1';
break;
case'h264':
if(e.mode=='record'){
x.watch=x.time+e.framerate+' -acodec '+x.acodec+' -movflags frag_keyframe+empty_moov -vcodec '+x.vcodec+' -s '+e.width+'x'+e.height+' -use_wallclock_as_timestamps 1 -q:v 1'+x.vf+' '+e.dir+e.filename+'.'+e.ext
}else{
x.watch='';
};
x.tmp='-loglevel quiet -i '+e.url+' -stimeout 2000'+x.watch+' -f image2pipe'+x.svf+' -s '+e.ratio+' pipe:1';
break;
case'local':
if(e.mode=='record'){
x.watch=x.time+e.framerate+' -acodec '+x.acodec+' -movflags frag_keyframe+empty_moov -vcodec '+x.vcodec+' -s '+e.width+'x'+e.height+' -use_wallclock_as_timestamps 1 -q:v 1'+x.vf+' '+e.dir+e.filename+'.'+e.ext
}else{
x.watch='';
};
x.tmp='-loglevel warning -i '+e.path+''+x.watch+' -f image2pipe'+x.svf+' -s '+e.ratio+' pipe:1';
break;
}
return spawn('ffmpeg',x.tmp.split(' '));
break;
switch(e.type){
case'socket':case'jpeg':case'pipe':
x.tmp='-loglevel quiet -pattern_type glob -f image2pipe -vcodec mjpeg -i -'+x.time+' -vcodec '+x.vcodec+e.framerate+' -use_wallclock_as_timestamps 1 -q:v 1'+x.vf+' '+e.dir+e.filename+'.'+e.ext;
break;
case'mjpeg':
if(e.mode=='record'){
x.watch=x.time+' -vcodec '+x.vcodec+e.framerate+' -s '+e.width+'x'+e.height+' -use_wallclock_as_timestamps 1 -q:v 1'+x.vf+' '+e.dir+e.filename+'.'+e.ext+''
}else{
x.watch='';
};
x.tmp='-loglevel quiet -reconnect 1 -f mjpeg -i '+e.url+''+x.watch+' -f image2pipe'+x.svf+' -s '+e.ratio+' pipe:1';
break;
case'h264':
if(e.mode=='record'){
x.watch=x.time+e.framerate+' -acodec '+x.acodec+' -movflags frag_keyframe+empty_moov -vcodec '+x.vcodec+' -s '+e.width+'x'+e.height+' -use_wallclock_as_timestamps 1 -q:v 1'+x.vf+' '+e.dir+e.filename+'.'+e.ext
}else{
x.watch='';
};
x.tmp='-loglevel quiet -i '+e.url+' -stimeout 2000'+x.watch+' -f image2pipe'+x.svf+' -s '+e.ratio+' pipe:1';
break;
case'local':
if(e.mode=='record'){
x.watch=x.time+e.framerate+' -acodec '+x.acodec+' -movflags frag_keyframe+empty_moov -vcodec '+x.vcodec+' -s '+e.width+'x'+e.height+' -use_wallclock_as_timestamps 1 -q:v 1'+x.vf+' '+e.dir+e.filename+'.'+e.ext
}else{
x.watch='';
};
x.tmp='-loglevel warning -i '+e.path+''+x.watch+' -f image2pipe'+x.svf+' -s '+e.ratio+' pipe:1';
break;
}
return spawn('ffmpeg',x.tmp.split(' '));
}
s.file=function(x,e){
if(!e){e={}};
Expand Down Expand Up @@ -339,6 +334,7 @@ s.camera=function(x,e,cn,tx){
s.kill(s.users[e.ke].mon[e.id].spawn,e);
clearInterval(s.users[e.ke].mon[e.id].running);
s.users[e.ke].mon[e.id].started=0;
if(s.users[e.ke].mon[e.mid].record){s.users[e.ke].mon[e.mid].record.yes=0}
s.tx({f:'monitor_stopping',id:e.id,ke:e.ke,time:s.moment(),reason:e.reason},'GRP_'+e.ke);
if(e.delete===1){
s.users[e.ke].mon[e.id].delete=setTimeout(function(){delete(s.users[e.ke].mon[e.id]);},60000*60);
Expand All @@ -361,14 +357,18 @@ s.camera=function(x,e,cn,tx){
if (!fs.existsSync(e.dir)){
fs.mkdirSync(e.dir);
}
}else{
s.users[e.ke].mon[e.mid].record.yes=0;
}
s.tx({f:'monitor_starting',id:e.id,time:s.moment()},'GRP_'+e.ke);
e.error_count=0;
e.set=function(x){
e.set=function(y){
clearInterval(s.users[e.ke].mon[e.id].running);
if(x==='record'){
s.users[e.ke].mon[e.id].running=setInterval(function(){//start loop
e.fn(x)
e.fn(y)
},e.details.cutoff);
}
}
e.init_event=function(k){
s.kill(s.users[e.ke].mon[e.id].spawn,e);
Expand Down Expand Up @@ -407,7 +407,7 @@ s.camera=function(x,e,cn,tx){
}
e.frames=0;
if(!s.users[e.ke].mon[e.id].record){s.users[e.ke].mon[e.id].record={yes:1}};
if(x==='record'||e.type==='mjpeg'||e.type==='h264'||e.type==='local'){s.users[e.ke].mon[e.id].spawn = s.ffmpeg('args',e);}
if(x==='record'||e.type==='mjpeg'||e.type==='h264'||e.type==='local'){s.users[e.ke].mon[e.id].spawn = s.ffmpeg(e);}
switch(e.type){
case'jpeg':
e.captureOne=function(f){
Expand Down Expand Up @@ -678,11 +678,7 @@ s.tx({f:'monitor_watch_on',viewers:Object.keys(s.users[d.ke].mon[d.id].watch).le
case'event':
switch(d.ff){
case'delete':
if (d.status&&fs.existsSync(s.dir.events+d.ke+'/'+d.mid+'/'+d.filename)){
s.event('delete',d)
}else{
tx({f:'event_not_exist',query:d});
}
break;
}
break;
Expand Down Expand Up @@ -932,13 +928,12 @@ sql.query('SELECT * FROM Monitors WHERE mode != "stop"', function(err,r) {
},1500)

try{
//cpu load indicator
s.com = spawn('dstat', ['-c', '--nocolor']);
s.com.stdout.on('data', function(data,txt){
txt = new Buffer(data).toString('utf8', 0, data.length);
io.emit('f',{f:'cpu',data:100 - parseInt(txt.split(' ')[2])});
});
}catch(err){console.log('No dstat, CPU indicator will not work. Continuing...')}
setInterval(function(){
os.cpuUsage(function(cpu){
io.emit('f',{f:'cpu',data:cpu});
});
},2000);
}catch(err){console.log('CPU indicator will not work. Continuing...')}
//check disk space every 20 minutes
s.disk=function(x){
df(function (er,d) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"path": "^0.12.7",
"del": "^2.2.2",
"node-df": "^0.1.1",
"os-utils": "^0.0.14",
"request": "^2.79.0",
"socket.io": "^1.7.1",
"socket.io-client": "^1.7.2"
Expand Down
2 changes: 1 addition & 1 deletion web/libs/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ ul.msg_list li a {
padding: 3px 5px !important
}
ul.msg_list li .progress {
height:10px;margin:10px 0 0 0;
height:5px;margin:10px 0 0 0;
}

ul.msg_list li .image img {
Expand Down
9 changes: 6 additions & 3 deletions web/libs/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ $.ccio={fr:$('#files_recent'),mon:{}};
break;
case 1://monitor
d.src=placeholder.getData(placeholder.plcimg({bgcolor:'#b57d00',text:'...'}));
tmp+='<div mid="'+d.mid+'" ke="'+d.ke+'" title="'+d.mid+' : '+d.name+'" class="monitor_block col-md-4"><img monitor="watch" class="snapshot" src="'+d.src+'"><div class="box"><div class="title truncate">'+d.name+'</div><div class="list-data"><div>'+d.mid+'</div><div><b>Save as :</b> '+d.ext+'</div><div><b>Mode :</b> '+d.mode+'</div></div><div class="icons"><a class="btn btn-xs btn-default" monitor="edit"><i class="fa fa-wrench"></i></a> <a event="calendar" class="btn btn-xs btn-default"><i class="fa fa-film"></i></a></div></div></div>';
tmp+='<div mid="'+d.mid+'" ke="'+d.ke+'" title="'+d.mid+' : '+d.name+'" class="monitor_block col-md-4"><img monitor="watch" class="snapshot" src="'+d.src+'"><div class="box"><div class="title truncate">'+d.name+'</div><div class="list-data"><div>'+d.mid+'</div><div><b>Save as :</b> '+d.ext+'</div><div><b>Mode :</b> '+d.mode+'</div></div><div class="icons"><a class="btn btn-xs btn-default" monitor="edit"><i class="fa fa-wrench"></i></a> <a monitor="calendar" class="btn btn-xs btn-default"><i class="fa fa-film"></i></a></div></div></div>';
delete(d.src);
break;
case 2:
Expand All @@ -66,7 +66,7 @@ $.ccio={fr:$('#files_recent'),mon:{}};
// tmp+='<img>';
// break;
// }
tmp+='<div class="hud super-center"><div class="side-menu scrollable"></div><div class="top_bar"><span class="badge badge-sm badge-danger"><i class="fa fa-eye"></i> <span class="viewers"></span></span></div><div class="bottom_bar"><span class="monitor_name">'+d.name+'</span><div class="pull-right"><a event="calendar" class="btn btn-sm btn-default"><i class="fa fa-film"></i></a> <a class="btn btn-sm btn-default" monitor="edit"><i class="fa fa-wrench"></i></a> <a title="Status" class="btn btn-sm btn-danger signal" monitor="watch_on"><i class="fa fa-circle"></i></a> <a title="Enlarge" monitor="bigify" class="btn btn-sm btn-default"><i class="fa fa-expand"></i></a> <a title="Close Stream" monitor="watch_off" class="btn btn-sm btn-danger"><i class="fa fa-times"></i></a></div></div></div></div>';
tmp+='<div class="hud super-center"><div class="side-menu scrollable"></div><div class="top_bar"><span class="badge badge-sm badge-danger"><i class="fa fa-eye"></i> <span class="viewers"></span></span></div><div class="bottom_bar"><span class="monitor_name">'+d.name+'</span><div class="pull-right"><a monitor="calendar" class="btn btn-sm btn-default"><i class="fa fa-film"></i></a> <a class="btn btn-sm btn-default" monitor="edit"><i class="fa fa-wrench"></i></a> <a title="Status" class="btn btn-sm btn-danger signal" monitor="watch_on"><i class="fa fa-circle"></i></a> <a title="Enlarge" monitor="bigify" class="btn btn-sm btn-default"><i class="fa fa-expand"></i></a> <a title="Close Stream" monitor="watch_off" class="btn btn-sm btn-danger"><i class="fa fa-times"></i></a></div></div></div></div>';
break;
}
if(z){
Expand Down Expand Up @@ -145,6 +145,7 @@ $.ccio.ws.on('f',function (d){
$('#logs').prepend(d.tmp);$.ccio.init('ls');
break;
case'cpu':
d.data=(d.data*100).toFixed(0)
$('.cpu_load .progress-bar').css('width',d.data+'%')
break;
case'disk':
Expand Down Expand Up @@ -376,6 +377,8 @@ $('body')
$.confirm.body.html(e.html)
$.confirm.click({title:'Delete Event',class:'btn-danger'},function(){
$.ccio.cx({f:'event',ff:'delete',status:1,filename:e.file,ke:e.ke,mid:e.mid});
if($('.modal[mid="'+e.mid+'"]').length>0){$('.modal[mid="'+e.mid+'"]').modal('hide')}
$('[file="'+e.file+'"][mid="'+e.mid+'"][ke="'+e.ke+'"]').remove();
});
break;
case'download':
Expand Down Expand Up @@ -475,7 +478,7 @@ $('body')
if(!$.ccio.mon[e.mid]){
e.p.find('[monitor="delete"]').hide()
e.mt.find('span').text('Add'),e.mt.find('i').attr('class','fa fa-plus');
e.values={"mode":"stop","mid":"","name":"","protocol":"http","ext":"webm","type":"jpeg","host":"","path":"","port":"","fps":"1","width":"640","height":"480","details":JSON.stringify({"vf":"","svf":"fps=1","sfps":"1000","cutoff":"15","vcodec":"copy","acodec":"copy","motion":"0"}),"shto":"[]","shfr":"[]"}
e.values={"mode":"stop","mid":"","name":"","protocol":"http","ext":"webm","type":"jpeg","host":"","path":"","port":"","fps":"1","width":"640","height":"480","details":JSON.stringify({"vf":"","svf":"fps=1","sfps":"1000","cutoff":"15","vcodec":"copy","acodec":"copy","motion":"0","timestamp":"1"}),"shto":"[]","shfr":"[]"}
}else{
e.p.find('[monitor="delete"]').show()
e.mt.find('span').text('Edit'),e.mt.find('i').attr('class','fa fa-wrench'),e.values=$.ccio.mon[e.mid];
Expand Down
8 changes: 8 additions & 0 deletions web/pages/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,14 @@ <h4 class="modal-title" id="add_monitorLabel"><i class="fa fa-plus"></i> &nbsp;
<input class="form-control" detail="sfps">
</label>
</div>
<div class="form-group h_m_input h_m_record">
<label><span>Timestamp</span>
<select class="form-control" detail="timestamp">
<option value="1">Yes</option>
<option value="0">No</option>
</select>
</label>
</div>
<div class="form-group h_m_input h_m_record">
<label><span>Record Video Filter</span>
<input class="form-control" detail="vf">
Expand Down

0 comments on commit 73be2bd

Please sign in to comment.