416 lines
18 KiB
Plaintext
416 lines
18 KiB
Plaintext
<script>var io=null;</script>
|
|
<%
|
|
data.name='SHINOBI_'+data.ke+'_'+data.id;
|
|
if(config.ssl&&config.ssl.port&&data.protocol==='https'){
|
|
data.port=config.ssl.port
|
|
}else{
|
|
data.port=config.port
|
|
}
|
|
if(!data.port||data.port===''||data.port==80||data.port==443){data.url=baseUrl}else{data.url=baseUrl+':'+data.port}
|
|
if(data.addon || data.addon.indexOf('relative')>-1){
|
|
data.url = ''
|
|
}else if(config.baseURL){
|
|
data.url = config.baseURL
|
|
}
|
|
if(data.url.charAt(data.url.length - 1) !== '/'){
|
|
data.url += '/'
|
|
}
|
|
%>
|
|
<script src="<%=data.url%>libs/js/socket.io.js"></script>
|
|
<script src="<%=data.url%>libs/js/poseidon.js"></script>
|
|
<script src="<%=data.url%>libs/js/hls.min.js"></script>
|
|
<script src="<%=data.url%>libs/js/flv.min.js"></script>
|
|
<% if(data.addon){
|
|
var ar={}
|
|
decodeURI(data.addon).split('|').forEach(function(v){
|
|
if(v.indexOf('=')>-1){
|
|
v=v.split('=');
|
|
ar[v[0]]=v[1];
|
|
}
|
|
})
|
|
if(!ar.width){ar.width=640;}
|
|
if(!ar.height){ar.height=480;}
|
|
if(data.addon.indexOf('jquery')>-1){ %>
|
|
<script src="<%=data.url%>libs/js/jquery.min.js"></script>
|
|
<% };
|
|
if(data.addon.indexOf('gui')>-1){ %>
|
|
<style>
|
|
body {position:relative;}
|
|
.shinobi_stream{position:absolute;width:100%;height:100%;top:0;left:0;}
|
|
.shinobi_hud{position:absolute;width:100%;height:100%;top:0;left:0;opacity:0;transition:0.2s}
|
|
.shinobi_hud:hover{opacity:1}
|
|
.shinobi_hud .shinobi_viewers{position:absolute;top:5px;left:5px;}
|
|
.shinobi_hud .shinobi_viewers{
|
|
display: inline-block;
|
|
min-width: 10px;
|
|
padding: 3px 7px;
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
line-height: 1;
|
|
color: #fff;
|
|
text-align: center;
|
|
white-space: nowrap;
|
|
vertical-align: middle;
|
|
background-color: #777;
|
|
border-radius: 10px;
|
|
font-family: sans-serif;
|
|
}
|
|
iframe.stream-element{border:0;}
|
|
/* All-CSS Toggle Switch (Checkbox Hack) by Marcus Burnette - https://codepen.io/mburnette/pen/LxNxNg */
|
|
.shinobi_ws_http_toggle {
|
|
width: 50px;
|
|
height: 20px;
|
|
position: absolute;
|
|
bottom: 10px;
|
|
left: 10px;
|
|
}
|
|
.shinobi_ws_http_toggle input[type=checkbox]{
|
|
height: 0;
|
|
width: 0;
|
|
visibility: hidden;
|
|
}
|
|
|
|
.shinobi_ws_http_toggle label {
|
|
cursor: pointer;
|
|
text-indent: -9999px;
|
|
width: 100px;
|
|
height: 20px;
|
|
background: grey;
|
|
display: block;
|
|
border-radius: 100px;
|
|
position: relative;
|
|
}
|
|
|
|
.shinobi_ws_http_toggle label:after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 5px;
|
|
left: 5px;
|
|
width: 10px;
|
|
height: 10px;
|
|
background: #fff;
|
|
border-radius: 90px;
|
|
transition: 0.3s;
|
|
}
|
|
|
|
.shinobi_ws_http_toggle input:checked + label {
|
|
background: #00118c;
|
|
}
|
|
|
|
.shinobi_ws_http_toggle input:checked + label:after {
|
|
left: calc(100% - 5px);
|
|
transform: translateX(-100%);
|
|
}
|
|
|
|
.shinobi_ws_http_toggle label:active:after {
|
|
width: 10px;
|
|
}
|
|
</style>
|
|
<% };
|
|
if(data.addon.indexOf('fullscreen')>-1){ %>
|
|
<style>
|
|
body,html{overflow: hidden;height:100%}
|
|
*{margin:0;padding:0;border:0}
|
|
.stream-element,.shinobi_stream{position:absolute;top:0;left:0;height:100%}
|
|
.shinobi_stream video{object-fit: fill}
|
|
</style>
|
|
<script>
|
|
$(window).resize(function(){
|
|
$('.stream-element').attr('width',$('body').width())
|
|
$('.stream-element').attr('height',$('body').height())
|
|
})
|
|
</script>
|
|
<% } %>
|
|
<% }else{
|
|
//no addon set, do defaults
|
|
var ar={};
|
|
ar.width=640;
|
|
ar.height=480;
|
|
} %>
|
|
<script>
|
|
$(document).ready(function(){
|
|
$('#<%= data.name %> canvas').attr('width',<%=ar.width%>).attr('height',<%=ar.height%>)
|
|
})
|
|
</script>
|
|
<div class="shinobi_stream" id="<%= data.name %>">
|
|
|
|
<% switch(mon.details.stream_type){
|
|
case'jpeg':
|
|
%><img class="stream-element"><%
|
|
break;
|
|
case'flv':case'hls':case'mp4':
|
|
%><video class="stream-element" autoplay></video><%
|
|
break;
|
|
case'mjpeg':
|
|
%><iframe class="stream-element"></iframe><%
|
|
break;
|
|
default:
|
|
%><canvas class="stream-element"></canvas><%
|
|
break;
|
|
} %>
|
|
|
|
|
|
<% if(data.addon&&data.addon.indexOf('gui')>-1){ %>
|
|
<div class="shinobi_hud">
|
|
<div class="shinobi_viewers" title="Current number of viewers"></div>
|
|
<div class="shinobi_ws_http_toggle" style="display:none">
|
|
<input type="checkbox" id="shinobi_ws_http_toggle" <% if(mon.details.stream_flv_type === 'ws'){ %>checked<% } %> /><label for="shinobi_ws_http_toggle">WebSocket</label>
|
|
</div>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
<script>
|
|
var SHINOBI_TIMER=setInterval(function(){
|
|
if(io){
|
|
clearInterval(SHINOBI_TIMER);delete(SHINOBI_TIMER);
|
|
if(!$.shinobi){
|
|
$.shinobi={}
|
|
};
|
|
if(!$.shinobi.mon){
|
|
$.shinobi.mon={}
|
|
};
|
|
$.shinobi.init=function(d){
|
|
switch($.shinobi.mon[d.id].details.stream_type){
|
|
case'b64':
|
|
if($.shinobi.mon[d.id].Base64 && $.shinobi.mon[d.id].Base64.connected){
|
|
$.shinobi.mon[d.id].Base64.disconnect()
|
|
}
|
|
$.shinobi.mon[d.id].Base64 = io('<%=data.url%>',{transports: ['websocket'], forceNew: false})
|
|
var ws = $.shinobi.mon[d.id].Base64
|
|
ws.on('diconnect',function(){
|
|
console.log('Base64 Stream Disconnected')
|
|
})
|
|
ws.on('connect',function(){
|
|
ws.emit('Base64',{
|
|
auth:'<%=data.auth%>',
|
|
ke:d.ke,
|
|
uid:'<%=data.uid%>',
|
|
id:d.id,
|
|
url: '<%=data.url%>'
|
|
})
|
|
if(!$.shinobi.mon[d.id].ctx||$.shinobi.mon[d.id].ctx.length===0){
|
|
$.shinobi.mon[d.id].ctx = $('#SHINOBI_'+d.ke+'_'+d.id+' .stream-element')
|
|
}
|
|
var ctx = $.shinobi.mon[d.id].ctx[0]
|
|
$.shinobi.mon[d.id].image = new Image()
|
|
var image = $.shinobi.mon[d.id].image
|
|
image.onload = function() {
|
|
$.shinobi.mon[d.id].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($.shinobi.mon[d.id].imageLoading === true)return console.log('drop');
|
|
// var base64Frame = 'data:image/jpeg;base64,'+$.ccio.base64ArrayBuffer(imageData)
|
|
$.shinobi.mon[d.id].imageLoading = true
|
|
// $.shinobi.mon[d.id].image.src = base64Frame
|
|
var arrayBufferView = new Uint8Array(imageData);
|
|
var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
|
|
$.shinobi.mon[d.id].imageUrl = URL.createObjectURL( blob );
|
|
$.shinobi.mon[d.id].image.src = $.shinobi.mon[d.id].imageUrl
|
|
$.shinobi.mon[d.id].last_frame = 'data:image/jpeg;base64,'+$.ccio.base64ArrayBuffer(imageData)
|
|
}catch(er){
|
|
console.log(er)
|
|
$.ccio.log('base64 frame')
|
|
}
|
|
})
|
|
})
|
|
break;
|
|
case'mp4':
|
|
var stream = $('#SHINOBI_'+d.ke+'_'+d.id+' .stream-element');
|
|
if($.shinobi.mon[d.id].details.stream_flv_type==='ws'){
|
|
if($.shinobi.mon[d.id].Poseidon){
|
|
$.shinobi.mon[d.id].Poseidon.destroy()
|
|
}
|
|
var createPoseidon = function(){
|
|
$.shinobi.mon[d.id].Poseidon = new Poseidon({
|
|
video: stream[0],
|
|
auth_token:'<%=data.auth%>',
|
|
ke:d.ke,
|
|
uid:'<%=data.uid%>',
|
|
id:d.id,
|
|
url: '<%=data.url%>'
|
|
});
|
|
$.shinobi.mon[d.id].Poseidon.start();
|
|
$.shinobi.mon[d.id].Poseidon._socket.on('data',function(res){
|
|
console.log(res)
|
|
})
|
|
}
|
|
try{
|
|
createPoseidon()
|
|
}catch(err){
|
|
console.log(err)
|
|
setTimeout(function(){
|
|
createPoseidon()
|
|
},3000)
|
|
}
|
|
}else{
|
|
stream.attr('src','<%=data.url%><%=data.auth%>/mp4/'+d.ke+'/'+d.id+'/s.mp4')
|
|
}
|
|
break;
|
|
case'flv':
|
|
if (flvjs.isSupported()) {
|
|
if($.shinobi.mon[d.id].flv){
|
|
$.shinobi.mon[d.id].flv.destroy()
|
|
}
|
|
var options = {};
|
|
// if($.shinobi.mon[d.id].details.stream_flv_type==='ws'){
|
|
// if($.shinobi.mon[d.id].details.stream_flv_maxLatency&&$.shinobi.mon[d.id].details.stream_flv_maxLatency!==''){
|
|
// $.shinobi.mon[d.id].details.stream_flv_maxLatency = parseInt($.shinobi.mon[d.id].details.stream_flv_maxLatency)
|
|
// }else{
|
|
// $.shinobi.mon[d.id].details.stream_flv_maxLatency = 20000;
|
|
// }
|
|
// options = {
|
|
// type: 'flv',
|
|
// isLive: true,
|
|
// auth_token:'<%=data.auth%>',
|
|
// ke:d.ke,
|
|
// uid:'<%=data.uid%>',
|
|
// id:d.id,
|
|
// maxLatency:$.shinobi.mon[d.id].details.stream_flv_maxLatency,
|
|
// hasAudio:false,
|
|
// url: '<%=data.url%>'
|
|
// }
|
|
// }else{
|
|
options = {
|
|
type: 'flv',
|
|
isLive: true,
|
|
url: '<%=data.url%><%=data.auth%>/flv/'+d.ke+'/'+d.id+'/s.flv'
|
|
}
|
|
// }
|
|
$.shinobi.mon[d.id].flv = flvjs.createPlayer(options);
|
|
$.shinobi.mon[d.id].flv.attachMediaElement($('#SHINOBI_'+d.ke+'_'+d.id+' .stream-element')[0]);
|
|
$.shinobi.mon[d.id].flv.on('error',function(err){
|
|
console.log(err)
|
|
});
|
|
$.shinobi.mon[d.id].flv.load();
|
|
$.shinobi.mon[d.id].flv.play();
|
|
}else{
|
|
alert({title:'Stream cannot be started',text:'FLV.js is not supported on this browser. Try another stream type.',type:'error'})
|
|
}
|
|
break;
|
|
case'jpeg':
|
|
d.mon=$.shinobi.mon[d.id]
|
|
k=d.mon.details;
|
|
k.jpegInterval=parseFloat(k.jpegInterval);
|
|
if(!k.jpegInterval||k.jpegInterval===''||isNaN(k.jpegInterval)){k.jpegInterval=1}
|
|
if(!$.shinobi.mon[d.mon.mid].jpegInterval){
|
|
clearInterval($.shinobi.mon[d.mon.mid].jpegInterval);
|
|
$.shinobi.mon[d.mon.mid].jpegInterval=setInterval(function(){
|
|
$('#SHINOBI_'+d.ke+'_'+d.id+' .stream-element').attr('src','<%=data.url%><%=data.auth%>/jpeg/'+d.mon.ke+'/'+d.mon.mid+'/s.jpg?time='+(new Date()).getTime())
|
|
},1000/k.jpegInterval);
|
|
}
|
|
break;
|
|
case'hls':
|
|
var video = $('#SHINOBI_'+d.ke+'_'+d.id+' .stream-element')[0];
|
|
d.url='<%=data.url%><%=data.auth%>/hls/'+d.ke+'/'+d.id+'/s.m3u8';
|
|
if($.shinobi.mon[d.id].hls){
|
|
$.shinobi.mon[d.id].hls.destroy()
|
|
}
|
|
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)||(navigator.userAgent.match(/(Safari)/)&&!navigator.userAgent.match('Chrome'))) {
|
|
video.src=d.url;
|
|
video.play();
|
|
}else{
|
|
$.shinobi.mon[d.id].hls = new Hls();
|
|
$.shinobi.mon[d.id].hls.loadSource(d.url);
|
|
$.shinobi.mon[d.id].hls.attachMedia(video);
|
|
$.shinobi.mon[d.id].hls.on(Hls.Events.MANIFEST_PARSED,function() {
|
|
video.play();
|
|
});
|
|
}
|
|
break;
|
|
case'mjpeg':
|
|
$('#SHINOBI_'+d.ke+'_'+d.id+' .stream-element').attr('src','<%=data.url%><%=data.auth%>/mjpeg/'+d.ke+'/'+d.id+'?full=true')
|
|
break;
|
|
}
|
|
}
|
|
$.shinobi.mon['<%=data.id%>']=<%- JSON.stringify(mon) %>;
|
|
if(!$.shinobi.callback){$.shinobi.callback=function(){}}
|
|
if(!$.shinobi.ws||$.shinobi.ws.connected===false){
|
|
$.shinobi.ws=io('<%=data.url%>');
|
|
$.shinobi.ws.on('f',function (d){
|
|
if(d.viewers){
|
|
$('#SHINOBI_'+d.ke+'_'+d.id+' .shinobi_viewers').html(d.viewers);
|
|
}
|
|
switch(d.f){
|
|
case'monitor_frame':
|
|
var image = new Image();
|
|
var ctx = $('#SHINOBI_'+d.ke+'_'+d.id+' canvas')[0];
|
|
image.onload = function() {
|
|
ctx.getContext("2d").drawImage(image,0,0,ctx.width,ctx.height);
|
|
delete(d.frame);
|
|
delete(image);
|
|
};
|
|
image.src='data:image/jpeg;base64,'+d.frame
|
|
break;
|
|
case'monitor_watch_off':case'monitor_watch_on':
|
|
$('#SHINOBI_'+d.ke+'_'+d.id+' .shinobi_viewers').html(d.viewers)
|
|
$.shinobi.init(d)
|
|
break;
|
|
case'monitor_edit':
|
|
if(!d.id){d.id=d.mon.mid;}
|
|
if($.shinobi.mon[d.id]){
|
|
clearInterval($.shinobi.mon[d.id].jpegInterval);
|
|
}
|
|
d.e=$('#SHINOBI_'+d.ke+'_'+d.id+'');
|
|
d.e.find('.stream-element').remove();
|
|
d.tmp='';
|
|
switch(d.mon.details.stream_type){
|
|
case'hls':
|
|
d.tmp+='<video class="stream-element" controls autoplay></video>';
|
|
break;
|
|
case'mjpeg':
|
|
d.tmp+='<iframe class="stream-element"></iframe>';
|
|
break;
|
|
case'jpeg'://base64
|
|
d.tmp+='<img class="stream-element">';
|
|
break;
|
|
default://base64
|
|
d.tmp+='<canvas class="stream-element"></canvas>';
|
|
break;
|
|
}
|
|
d.e.append(d.tmp).find('.stream-element').resize();
|
|
$(window).resize();
|
|
// d.mon.details=JSON.stringify(d.mon.details);
|
|
d.mon.id = d.mon.mid
|
|
$.shinobi.mon[d.mon.mid]=d.mon;
|
|
$.shinobi.init(d.mon);
|
|
break;
|
|
}
|
|
$.shinobi.callback()
|
|
});
|
|
};
|
|
$.shinobi.ws.emit('e',{f:'init',auth:'<%=data.auth%>',id:'<%=data.id%>',ke:'<%=data.ke%>'})
|
|
$(window).resize();
|
|
}
|
|
},1000);
|
|
//websocket / http toggle
|
|
$('#shinobi_ws_http_toggle').change(function(){
|
|
var monitor = $.shinobi.mon['<%=data.id%>'];
|
|
var parent = $(this).parents('.shinobi_ws_http_toggle')
|
|
var label = parent.find('label')
|
|
if(monitor.details.stream_flv_type !== 'ws'){
|
|
label.text('WebSocket')
|
|
monitor.details.stream_flv_type = 'ws'
|
|
}else{
|
|
label.text('HTTP')
|
|
monitor.details.stream_flv_type = 'http'
|
|
}
|
|
monitor.id = monitor.mid
|
|
$.shinobi.init(monitor);
|
|
})
|
|
$('.shinobi_ws_http_toggle').show()
|
|
</script> |