Merge branch 'development' into LTS_development
This commit is contained in:
commit
25ddaa3595
13 changed files with 639 additions and 538 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -57,4 +57,5 @@ rules.ninja
|
|||
.ninja_log
|
||||
.ninja_deps
|
||||
aes_ctr128
|
||||
/embed/testing
|
||||
|
||||
|
|
|
@ -214,6 +214,7 @@ set(libSources
|
|||
${SOURCE_DIR}/lib/vorbis.cpp
|
||||
${SOURCE_DIR}/lib/triggers.cpp
|
||||
)
|
||||
|
||||
########################################
|
||||
# MistLib - Build #
|
||||
########################################
|
||||
|
@ -399,6 +400,7 @@ add_executable(MistOutHTTP
|
|||
generated/polytrope.js.h
|
||||
generated/dashjs.js.h
|
||||
generated/videojs.js.h
|
||||
generated/img.js.h
|
||||
generated/playerdash.js.h
|
||||
generated/playervideo.js.h
|
||||
generated/core.js.h
|
||||
|
@ -498,6 +500,10 @@ add_custom_command(OUTPUT generated/videojs.js.h
|
|||
COMMAND ./sourcery ${SOURCE_DIR}/embed/wrappers/videojs.js video_js generated/videojs.js.h
|
||||
DEPENDS sourcery ${SOURCE_DIR}/embed/wrappers/videojs.js
|
||||
)
|
||||
add_custom_command(OUTPUT generated/img.js.h
|
||||
COMMAND ./sourcery ${SOURCE_DIR}/embed/wrappers/img.js img_js generated/img.js.h
|
||||
DEPENDS sourcery ${SOURCE_DIR}/embed/wrappers/img.js
|
||||
)
|
||||
add_custom_command(OUTPUT generated/playerdash.js.h
|
||||
COMMAND ./sourcery ${SOURCE_DIR}/embed/players/dash.js playerdash_js generated/playerdash.js.h
|
||||
DEPENDS sourcery ${SOURCE_DIR}/embed/players/dash.js
|
||||
|
|
607
embed/core.js
607
embed/core.js
|
@ -27,10 +27,10 @@ MistPlayer.prototype.sendEvent = function(type,message,target) {
|
|||
return true;
|
||||
}
|
||||
MistPlayer.prototype.addlog = function(msg) {
|
||||
this.sendEvent('log',msg,this.target);
|
||||
this.sendEvent('log',msg,this.element);
|
||||
}
|
||||
MistPlayer.prototype.adderror = function(msg) {
|
||||
this.sendEvent('error',msg,this.target);
|
||||
this.sendEvent('error',msg,this.element);
|
||||
}
|
||||
MistPlayer.prototype.build = function () {
|
||||
this.addlog('Error in player implementation');
|
||||
|
@ -40,6 +40,32 @@ MistPlayer.prototype.build = function () {
|
|||
err.className = 'error';
|
||||
return err;
|
||||
}
|
||||
MistPlayer.prototype.timer = {
|
||||
timers: {},
|
||||
add: function(callback,delay){
|
||||
var me = this;
|
||||
var i = setTimeout(function(){
|
||||
delete me.timers[i];
|
||||
callback();
|
||||
},delay);
|
||||
this.timers[i] = {
|
||||
delay: delay,
|
||||
callback: callback
|
||||
};
|
||||
return i;
|
||||
},
|
||||
remove: function(i){
|
||||
clearTimeout(i);
|
||||
delete this.timers[i];
|
||||
},
|
||||
clear: function(){
|
||||
for (var i in this.timers) {
|
||||
clearTimeout(i);
|
||||
}
|
||||
this.timers = {};
|
||||
}
|
||||
};
|
||||
|
||||
//creates the player element, including custom functions
|
||||
MistPlayer.prototype.getElement = function(tag){
|
||||
var ele = document.createElement(tag);
|
||||
|
@ -164,14 +190,15 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
str.push(('0'+secs).slice(-2));
|
||||
return str.join(':');
|
||||
}
|
||||
var timestampValue, bar;
|
||||
function whilePlaying() {
|
||||
timestampValue.nodeValue = formatTime(ele.currentTime);
|
||||
bar.style.width = ((ele.currentTime-ele.startTime)/ele.duration*100)+'%';
|
||||
setTimeout(function(){
|
||||
me.timer.add(function(){
|
||||
if (!ele.paused) {
|
||||
whilePlaying();
|
||||
}
|
||||
},0.1e3);
|
||||
},0.5e3);
|
||||
};
|
||||
function whileLivePlaying(track) {
|
||||
|
||||
|
@ -180,11 +207,11 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
timestampValue.nodeValue = formatTime((playtime + track.lastms)/1e3);
|
||||
|
||||
|
||||
setTimeout(function(){
|
||||
me.timer.add(function(){
|
||||
if (!ele.paused) {
|
||||
whileLivePlaying(track);
|
||||
}
|
||||
},0.1e3);
|
||||
},0.5e3);
|
||||
};
|
||||
|
||||
|
||||
|
@ -213,7 +240,12 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
play.setAttribute('data-state','paused');
|
||||
play.onclick = function(){
|
||||
if (ele.paused) {
|
||||
me.play();
|
||||
if (options.live) {
|
||||
me.load();
|
||||
}
|
||||
else {
|
||||
me.play();
|
||||
}
|
||||
}
|
||||
else {
|
||||
me.pause();
|
||||
|
@ -255,7 +287,7 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
bar.style.left = (ele.startTime/ele.duration*100)+'%';
|
||||
};
|
||||
progress.ondragstart = function() { return false; };
|
||||
var bar = document.createElement('div');
|
||||
bar = document.createElement('div');
|
||||
progress.appendChild(bar);
|
||||
bar.className = 'bar';
|
||||
var buffers = [];
|
||||
|
@ -268,6 +300,11 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
ele.addEventListener('seeking',function(){
|
||||
me.target.setAttribute('data-loading','');
|
||||
});
|
||||
ele.addEventListener('seeked',function(){
|
||||
me.target.removeAttribute('data-loading');
|
||||
bar.style.left = (ele.currentTime/ele.duration*100)+'%';
|
||||
//TODO reset lasttime
|
||||
});
|
||||
ele.addEventListener('canplay',function(){
|
||||
me.target.removeAttribute('data-loading');
|
||||
});
|
||||
|
@ -282,7 +319,7 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
var timestamp = document.createElement('div');
|
||||
controls.appendChild(timestamp);
|
||||
timestamp.className = 'button timestamp';
|
||||
var timestampValue = document.createTextNode('-:--');
|
||||
timestampValue = document.createTextNode('-:--');
|
||||
timestamp.title = 'Time';
|
||||
timestamp.appendChild(timestampValue);
|
||||
|
||||
|
@ -298,12 +335,15 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
|
||||
var pos0 = sound.getBoundingClientRect().top - parseInt(style.borderTopWidth,10);
|
||||
var perc = (ypos - pos0 * zoom) / sound.offsetHeight / zoom;
|
||||
var secs = Math.max(0,perc) * ele.duration;
|
||||
return 1 - Math.min(1,Math.max(0,perc));
|
||||
|
||||
perc = 1 - Math.min(1,Math.max(0,perc)); //linear range between 0 and 1
|
||||
perc = 1 - Math.pow((1-perc),1/2); //transform to quadratic range between 0 and 1
|
||||
|
||||
return perc;
|
||||
}
|
||||
volume.className = 'volume';
|
||||
sound.title = 'Volume';
|
||||
if ('mistVolume' in localStorage) {
|
||||
if (('localStorage' in window) && (localStorage != null) && ('mistVolume' in localStorage)) {
|
||||
ele.volume = localStorage['mistVolume'];
|
||||
volume.style.height = ele.volume*100+'%';
|
||||
}
|
||||
|
@ -313,6 +353,7 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
};
|
||||
var mouseup = function(e){
|
||||
document.removeEventListener('mousemove',mousemove);
|
||||
controls.removeEventListener('mousemove',mousemove);
|
||||
document.removeEventListener('touchmove',mousemove);
|
||||
document.removeEventListener('mouseup',mouseup);
|
||||
document.removeEventListener('touchend',mouseup);
|
||||
|
@ -322,6 +363,7 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
catch (e) {}
|
||||
};
|
||||
document.addEventListener('mousemove',mousemove);
|
||||
controls.addEventListener('mousemove',mousemove); //this one is added because the controls hiding mechanism stops propagation to the document
|
||||
document.addEventListener('touchmove',mousemove);
|
||||
document.addEventListener('mouseup',mouseup);
|
||||
document.addEventListener('touchend',mouseup);
|
||||
|
@ -409,6 +451,9 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
name = tracks[i][j].lang;
|
||||
o.setAttribute('data-lang',tracks[i][j].lang);
|
||||
}
|
||||
else if ('desc' in tracks[i][j]) {
|
||||
name = tracks[i][j].desc;
|
||||
}
|
||||
else {
|
||||
name = 'Track '+(Number(j)+1);
|
||||
}
|
||||
|
@ -452,7 +497,7 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
}
|
||||
if (i == 'subtitle') {
|
||||
s.value = 0;
|
||||
if ('mistSubtitle' in localStorage) {
|
||||
if (('localStorage' in window) && (localStorage != null) && ('mistSubtitle' in localStorage)) {
|
||||
var option = s.querySelector('[data-lang="'+localStorage['mistSubtitle']+'"]');
|
||||
if (option) {
|
||||
s.value = option.value;
|
||||
|
@ -508,9 +553,13 @@ MistPlayer.prototype.buildMistControls = function(){
|
|||
});
|
||||
ele.addEventListener('ended',function(){
|
||||
play.setAttribute('data-state','paused');
|
||||
if (options.live) {
|
||||
me.load();
|
||||
}
|
||||
});
|
||||
ele.addEventListener('volumechange',function(){
|
||||
volume.style.height = ele.volume*100+'%';
|
||||
var vol = 1 - Math.pow(1-ele.volume,2); //transform back from quadratic
|
||||
volume.style.height = vol*100+'%';
|
||||
if (ele.volume == 0) {
|
||||
speaker.setAttribute('data-muted','');
|
||||
}
|
||||
|
@ -601,33 +650,56 @@ MistPlayer.prototype.askNextCombo = function(msg){
|
|||
var me = this;
|
||||
if (me.errorstate) { return; }
|
||||
me.errorstate = true;
|
||||
me.addlog('Showing error window');
|
||||
me.report({
|
||||
type: 'playback',
|
||||
warn: 'Showing error window',
|
||||
msg: msg
|
||||
});
|
||||
|
||||
//show the error
|
||||
var err = document.createElement('div');
|
||||
var msgnode = document.createTextNode(msg ? msg : 'Player or stream error detected');
|
||||
err.appendChild(msgnode);
|
||||
err.className = 'error';
|
||||
var button = document.createElement('button');
|
||||
var t = document.createTextNode('Try next source/player');
|
||||
button.appendChild(t);
|
||||
err.appendChild(button);
|
||||
button.onclick = function(){
|
||||
me.nextCombo();
|
||||
err.style.position = 'absolute';
|
||||
err.style.width = '100%';
|
||||
err.style['margin-left'] = 0;
|
||||
this.target.appendChild(err);
|
||||
this.element.style.opacity = '0.2';
|
||||
|
||||
//if there is a next source/player, show a button to activate it
|
||||
var opts = this.mistplaySettings.options;
|
||||
if (mistCheck(mistvideo[this.mistplaySettings.streamname],opts)) {
|
||||
var button = document.createElement('button');
|
||||
var t = document.createTextNode('Try next source/player');
|
||||
button.appendChild(t);
|
||||
err.appendChild(button);
|
||||
button.onclick = function(){
|
||||
me.nextCombo();
|
||||
}
|
||||
}
|
||||
|
||||
//show a button to reload with the current settings
|
||||
var button = document.createElement('button');
|
||||
var i = document.createElement('div'); //a css countdown clock for 10sec
|
||||
i.className = 'countdown';
|
||||
button.appendChild(i);
|
||||
var t = document.createTextNode('Reload this player');
|
||||
button.appendChild(t);
|
||||
err.appendChild(button);
|
||||
button.onclick = function(){
|
||||
me.reload();
|
||||
}
|
||||
err.style.position = 'absolute';
|
||||
err.style.top = 0;
|
||||
err.style.width = '100%';
|
||||
err.style['margin-left'] = 0;
|
||||
|
||||
this.target.appendChild(err);
|
||||
this.element.style.opacity = '0.2';
|
||||
//after 20 seconds, reload the player
|
||||
err.timeOut = me.timer.add(function(){
|
||||
me.report({
|
||||
type: 'playback',
|
||||
warn: 'Automatically reloaded the current player after playback error'
|
||||
});
|
||||
button.click();
|
||||
},20e3);
|
||||
|
||||
};
|
||||
MistPlayer.prototype.cancelAskNextCombo = function(){
|
||||
if (this.errorstate) {
|
||||
|
@ -637,12 +709,17 @@ MistPlayer.prototype.cancelAskNextCombo = function(){
|
|||
var err = this.target.querySelector('.error');
|
||||
if (err) {
|
||||
this.target.removeChild(err);
|
||||
if (err.timeOut) { this.timer.remove(err.timeOut); }
|
||||
}
|
||||
}
|
||||
};
|
||||
MistPlayer.prototype.reload = function(){
|
||||
this.unload();
|
||||
mistPlay(this.mistplaySettings.streamname,this.mistplaySettings.options);
|
||||
this.report({
|
||||
type: 'init',
|
||||
info: 'Reloading player'
|
||||
});
|
||||
};
|
||||
MistPlayer.prototype.nextCombo = function(){
|
||||
this.unload();
|
||||
|
@ -653,8 +730,6 @@ MistPlayer.prototype.nextCombo = function(){
|
|||
///send information back to mistserver
|
||||
///\param msg object containing the information to report
|
||||
MistPlayer.prototype.report = function(msg) {
|
||||
return false; ///\todo Remove this when the backend reporting function has been coded
|
||||
|
||||
|
||||
///send a http post request
|
||||
///\param url (string) url to send to
|
||||
|
@ -690,6 +765,10 @@ MistPlayer.prototype.report = function(msg) {
|
|||
msg.userinfo.time = Math.round(((new Date) - this.options.initTime)/1e3); //seconds since the info js was loaded
|
||||
}
|
||||
|
||||
this.sendEvent('report',JSON.stringify(msg),this.element);
|
||||
|
||||
return false; ///\todo Remove this when the backend reporting function has been coded
|
||||
|
||||
try {
|
||||
httpPost(this.options.host+'/report',{
|
||||
report: JSON.stringify(msg)
|
||||
|
@ -698,12 +777,100 @@ MistPlayer.prototype.report = function(msg) {
|
|||
catch (e) { }
|
||||
}
|
||||
MistPlayer.prototype.unload = function(){
|
||||
this.addlog('Unloading..');
|
||||
if (('pause' in this) && (this.pause)) { this.pause(); }
|
||||
if ('updateSrc' in this) { this.updateSrc(''); }
|
||||
//delete this.element;
|
||||
if ('updateSrc' in this) {
|
||||
this.updateSrc('');
|
||||
this.element.load(); //dont use this.load() to avoid interrupting play/pause
|
||||
}
|
||||
this.timer.clear();
|
||||
this.target.innerHTML = '';
|
||||
};
|
||||
|
||||
function mistCheck(streaminfo,options,embedLog) {
|
||||
if (typeof embedLog != 'function') { embedLog = function(){}; }
|
||||
|
||||
embedLog('Checking available players..');
|
||||
|
||||
var source = false;
|
||||
var mistPlayer = false;
|
||||
|
||||
if (options.startCombo) {
|
||||
options.startCombo.started = {
|
||||
player: false,
|
||||
source: false
|
||||
};
|
||||
}
|
||||
|
||||
function checkPlayer(p_shortname) {
|
||||
if ((options.startCombo) && (!options.startCombo.started.player)) {
|
||||
if (p_shortname != options.startCombo.player) { return false; }
|
||||
else {
|
||||
options.startCombo.started.player = true;
|
||||
}
|
||||
}
|
||||
|
||||
embedLog('Checking '+mistplayers[p_shortname].name+' (priority: '+mistplayers[p_shortname].priority+') ..');
|
||||
|
||||
//loop over the available sources and check if this player can play it
|
||||
var loop;
|
||||
if (options.forceSource) {
|
||||
loop = [streaminfo.source[options.forceSource]];
|
||||
}
|
||||
else {
|
||||
loop = streaminfo.source;
|
||||
}
|
||||
for (var s in loop) {
|
||||
if ((options.startCombo) && (!options.startCombo.started.source)) {
|
||||
if (s == options.startCombo.source) {
|
||||
options.startCombo.started.source = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((options.forceType) && (loop[s].type != options.forceType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mistplayers[p_shortname].isMimeSupported(loop[s].type)) {
|
||||
//this player supports this mime
|
||||
if (mistplayers[p_shortname].isBrowserSupported(loop[s].type,loop[s],options,streaminfo,embedLog)) {
|
||||
//this browser is supported
|
||||
embedLog('Found a working combo: '+mistplayers[p_shortname].name+' with '+loop[s].type+' @ '+loop[s].url);
|
||||
mistPlayer = p_shortname;
|
||||
source = loop[s];
|
||||
source.index = s;
|
||||
return p_shortname;
|
||||
}
|
||||
else {
|
||||
embedLog('This browser does not support '+loop[s].type+' via '+loop[s].url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.forcePlayer) {
|
||||
checkPlayer(options.forcePlayer);
|
||||
}
|
||||
else {
|
||||
//sort the players
|
||||
var sorted = Object.keys(mistplayers);
|
||||
sorted.sort(function(a,b){
|
||||
return mistplayers[a].priority - mistplayers[b].priority;
|
||||
});
|
||||
for (var n in sorted) {
|
||||
var p_shortname = sorted[n];
|
||||
if (checkPlayer(p_shortname)) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
return ((source && mistPlayer) ? {
|
||||
source: source,
|
||||
mistPlayer: mistPlayer
|
||||
} : false);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// SELECT AND ADD A VIDEO PLAYER TO THE TARGET //
|
||||
/////////////////////////////////////////////////
|
||||
|
@ -711,13 +878,13 @@ MistPlayer.prototype.unload = function(){
|
|||
function mistPlay(streamName,options) {
|
||||
|
||||
var protoplay = new MistPlayer();
|
||||
protoplay.streamname = streamName;
|
||||
function embedLog(msg) {
|
||||
protoplay.streamname = streamName;
|
||||
var embedLog = function(msg) {
|
||||
protoplay.sendEvent('log',msg,options.target);
|
||||
}
|
||||
};
|
||||
function mistError(msg) {
|
||||
var info = {};
|
||||
if ((typeof mistvideo != 'undefined') && ('streamName' in mistvideo)) { info = mistvideo[streamName]; }
|
||||
if ((typeof mistvideo != 'undefined') && (streamName in mistvideo)) { info = mistvideo[streamName]; }
|
||||
var displaymsg = msg;
|
||||
if ('on_error' in info) { displaymsg = info.on_error; }
|
||||
|
||||
|
@ -745,12 +912,17 @@ function mistPlay(streamName,options) {
|
|||
var local = options;
|
||||
var global = (typeof mistoptions == 'undefined' ? {} : mistoptions);
|
||||
var options = {
|
||||
host: null,
|
||||
autoplay: true,
|
||||
controls: true,
|
||||
loop: false,
|
||||
poster: null,
|
||||
callback: false
|
||||
host: null, //override mistserver host (default is the host that player.js is loaded from)
|
||||
autoplay: true, //start playing when loaded
|
||||
controls: true, //show controls (MistControls when available)
|
||||
loop: false, //don't loop when the stream has finished
|
||||
poster: null, //don't show an image before the stream has started
|
||||
callback: false, //don't call a function when the player has finished building
|
||||
streaminfo: false, //don't use this streaminfo but collect it from the mistserverhost
|
||||
startCombo: false, //start looking for a player/source match at the start
|
||||
forceType: false, //don't force a mimetype
|
||||
forcePlayer: false, //don't force a player
|
||||
forceSource: false //don't force a source
|
||||
};
|
||||
for (var i in global) {
|
||||
options[i] = global[i];
|
||||
|
@ -763,9 +935,19 @@ function mistPlay(streamName,options) {
|
|||
mistError('MistServer host undefined.');
|
||||
return;
|
||||
}
|
||||
if (!options.target) {
|
||||
mistError('Target container undefined');
|
||||
return;
|
||||
}
|
||||
|
||||
options.target.setAttribute('data-loading','');
|
||||
|
||||
var classes = options.target.className.split(' ');
|
||||
if (classes.indexOf('mistvideo') == -1) {
|
||||
classes.push('mistvideo');
|
||||
options.target.className = classes.join(' ');
|
||||
}
|
||||
|
||||
//check if the css is loaded
|
||||
if (!document.getElementById('mist_player_css')) {
|
||||
var css = document.createElement('link');
|
||||
|
@ -781,28 +963,11 @@ function mistPlay(streamName,options) {
|
|||
}
|
||||
}
|
||||
|
||||
//get info js
|
||||
var info = document.createElement('script');
|
||||
info.src = options.host+'/info_'+encodeURIComponent(streamName)+'.js';
|
||||
embedLog('Retrieving stream info from '+info.src);
|
||||
document.head.appendChild(info);
|
||||
info.onerror = function(){
|
||||
options.target.innerHTML = '';
|
||||
options.target.removeAttribute('data-loading');
|
||||
mistError('Error while loading stream info.');
|
||||
protoplay.report({
|
||||
type: 'init',
|
||||
error: 'Failed to load '+info.src
|
||||
});
|
||||
}
|
||||
info.onload = function(){
|
||||
function onstreaminfo() {
|
||||
options.target.innerHTML = '';
|
||||
options.target.removeAttribute('data-loading');
|
||||
embedLog('Stream info was loaded succesfully');
|
||||
|
||||
//clean up info script
|
||||
document.head.removeChild(info);
|
||||
|
||||
//get streaminfo data
|
||||
var streaminfo = mistvideo[streamName];
|
||||
//embedLog('Stream info contents: '+JSON.stringify(streaminfo));
|
||||
|
@ -817,139 +982,36 @@ function mistPlay(streamName,options) {
|
|||
return;
|
||||
}
|
||||
|
||||
//sort the sources by priority and mime, but prefer HTTPS
|
||||
streaminfo.source.sort(function(a,b){
|
||||
return (b.priority - a.priority) || a.type.localeCompare(b.type) || b.url.localeCompare(a.url);
|
||||
});
|
||||
|
||||
var mistPlayer = false;
|
||||
var source;
|
||||
var forceType = false;
|
||||
if (('forceType' in options) && (options.forceType)) {
|
||||
embedLog('Forcing '+options.forceType);
|
||||
forceType = options.forceType;
|
||||
}
|
||||
var forceSource = false;
|
||||
if (('forceSource' in options) && (options.forceSource)) {
|
||||
forceSource = options.forceSource;
|
||||
forceType = streaminfo.source[forceSource].type;
|
||||
embedLog('Forcing source '+options.forceSource+': '+forceType+' @ '+streaminfo.source[forceSource].url);
|
||||
options.forceType = streaminfo.source[options.forceSource].type;
|
||||
embedLog('Forcing source '+options.forceSource+': '+options.forceType+' @ '+streaminfo.source[options.forceSource].url);
|
||||
}
|
||||
var forceSupportCheck = false;
|
||||
if (('forceSupportCheck' in options) && (options.forceSupportCheck)) {
|
||||
embedLog('Forcing a full support check');
|
||||
forceSupportCheck = true;
|
||||
}
|
||||
var forcePlayer = false;
|
||||
if (('forcePlayer' in options) && (options.forcePlayer)) {
|
||||
if (options.forcePlayer in mistplayers) {
|
||||
embedLog('Forcing '+mistplayers[options.forcePlayer].name);
|
||||
forcePlayer = options.forcePlayer;
|
||||
}
|
||||
else {
|
||||
embedLog('The forced player ('+options.forcePlayer+') isn\'t known, ignoring. Possible values are: '+Object.keys(mistplayers).join(', '));
|
||||
options.forcePlayer = false;
|
||||
}
|
||||
}
|
||||
var startCombo = false;
|
||||
if ('startCombo' in options) {
|
||||
startCombo = options.startCombo;
|
||||
startCombo.started = {
|
||||
player: false,
|
||||
source: false
|
||||
};
|
||||
embedLog('Selecting a new player/source combo, starting after '+mistplayers[startCombo.player].name+' with '+streaminfo.source[startCombo.source].type+' @ '+streaminfo.source[startCombo.source].url);
|
||||
if (('startCombo' in options) && (options.startCombo)) {
|
||||
embedLog('Selecting a new player/source combo, starting after '+mistplayers[options.startCombo.player].name+' with '+streaminfo.source[options.startCombo.source].type+' @ '+streaminfo.source[options.startCombo.source].url);
|
||||
}
|
||||
|
||||
embedLog('Checking available players..');
|
||||
//sort the sources by simultracks, priority and mime, but prefer HTTPS
|
||||
streaminfo.source.sort(function(a,b){
|
||||
return (b.simul_tracks - a.simul_tracks) || (b.priority - a.priority) || a.type.localeCompare(b.type) || b.url.localeCompare(a.url);
|
||||
});
|
||||
|
||||
var source = false;
|
||||
|
||||
function checkPlayer(p_shortname) {
|
||||
if ((startCombo) && (!startCombo.started.player)) {
|
||||
if (p_shortname != startCombo.player) { return false; }
|
||||
else {
|
||||
startCombo.started.player = true;
|
||||
}
|
||||
}
|
||||
|
||||
embedLog('Checking '+mistplayers[p_shortname].name+' (priority: '+mistplayers[p_shortname].priority+') ..');
|
||||
streaminfo.working[p_shortname] = [];
|
||||
|
||||
if (forceType) {
|
||||
if ((mistplayers[p_shortname].mimes.indexOf(forceType) > -1) && (checkMime(p_shortname,forceType))) {
|
||||
return p_shortname;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var m in mistplayers[p_shortname].mimes) {
|
||||
if ((checkMime(p_shortname,mistplayers[p_shortname].mimes[m])) && (!forceSupportCheck)) {
|
||||
return p_shortname;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function checkMime(p_shortname,mime) {
|
||||
var loop;
|
||||
if (forceSource) {
|
||||
loop = [streaminfo.source[forceSource]];
|
||||
}
|
||||
else {
|
||||
loop = streaminfo.source;
|
||||
}
|
||||
var broadcast = false;
|
||||
for (var s in loop) {
|
||||
if (loop[s].type == mime) {
|
||||
broadcast = true;
|
||||
|
||||
if ((startCombo) && (!startCombo.started.source)) {
|
||||
if (s == startCombo.source) {
|
||||
startCombo.started.source = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mistplayers[p_shortname].isBrowserSupported(mime,loop[s],options,streaminfo,embedLog)) {
|
||||
embedLog('Found a working combo: '+mistplayers[p_shortname].name+' with '+mime+' @ '+loop[s].url);
|
||||
streaminfo.working[p_shortname].push(mime);
|
||||
if (!source) {
|
||||
mistPlayer = p_shortname;
|
||||
source = loop[s];
|
||||
source.index = s;
|
||||
}
|
||||
if (!forceSupportCheck) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
else {
|
||||
embedLog('This browser does not support '+mime);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (!broadcast) {
|
||||
embedLog('Mist doesn\'t broadcast '+mime);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
streaminfo.working = {};
|
||||
if (forcePlayer) {
|
||||
checkPlayer(forcePlayer);
|
||||
}
|
||||
else {
|
||||
//sort the players
|
||||
var sorted = Object.keys(mistplayers);
|
||||
sorted.sort(function(a,b){
|
||||
return mistplayers[a].priority - mistplayers[b].priority;
|
||||
});
|
||||
for (var n in sorted) {
|
||||
var p_shortname = sorted[n];
|
||||
if (checkPlayer(p_shortname)) { break; }
|
||||
}
|
||||
}
|
||||
var r = mistCheck(streaminfo,options,embedLog);
|
||||
var mistPlayer = r.mistPlayer;
|
||||
var source = r.source;
|
||||
|
||||
options.target.innerHTML = '';
|
||||
if (mistPlayer) {
|
||||
|
||||
//create the options to send to the player
|
||||
|
@ -964,7 +1026,7 @@ function mistPlay(streamName,options) {
|
|||
//pass player options and handle defaults
|
||||
playerOpts.autoplay = options.autoplay;
|
||||
playerOpts.controls = options.controls;
|
||||
playerOpts.loop = options.loop;
|
||||
playerOpts.loop = (playerOpts.live ? false : options.loop);
|
||||
playerOpts.poster = options.poster;
|
||||
|
||||
function calcSize() {
|
||||
|
@ -1026,6 +1088,7 @@ function mistPlay(streamName,options) {
|
|||
|
||||
if (player.setTracks(false)) {
|
||||
//gather track info
|
||||
//tracks
|
||||
var tracks = {
|
||||
video: [],
|
||||
audio: [],
|
||||
|
@ -1036,20 +1099,26 @@ function mistPlay(streamName,options) {
|
|||
var skip = false;
|
||||
switch (t.type) {
|
||||
case 'video':
|
||||
t.desc = ['['+t.codec+']',t.width+'x'+t.height,Math.round(t.bps/1024)+'kbps',t.fpks/1e3+'fps',t.lang];
|
||||
t.desc = [t.width+'x'+t.height,/*Math.round(t.bps/1024)+'kbps',*/t.fpks/1e3+'fps',t.codec];
|
||||
if (t.lang) {
|
||||
t.desc.unshift(t.lang);
|
||||
}
|
||||
break;
|
||||
case 'audio':
|
||||
t.desc = ['['+t.codec+']',t.channels+' channels',Math.round(t.bps/1024)+'kbps',t.rate+'Hz',t.lang];
|
||||
t.desc = [(t.channels == 2 ? 'Stereo' : (t.channels == 1 ? 'Mono' : t.channels+' channels')),/*Math.round(t.bps/1024)+'kbps',*/Math.round(t.rate/1000)+'kHz',t.codec];
|
||||
if (t.lang) {
|
||||
t.desc.unshift(t.lang);
|
||||
}
|
||||
break;
|
||||
case 'subtitle':
|
||||
t.desc = ['['+t.codec+']',t.lang];
|
||||
t.desc = [t.lang,t.codec];
|
||||
break;
|
||||
default:
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
if (skip) { continue; }
|
||||
t.desc = t.desc.join(', ');
|
||||
t.desc = t.desc.join(' ');
|
||||
tracks[t.type].push(t);
|
||||
}
|
||||
player.tracks = tracks;
|
||||
|
@ -1081,7 +1150,7 @@ function mistPlay(streamName,options) {
|
|||
//build the player
|
||||
player.mistplaySettings = {
|
||||
streamname: streamName,
|
||||
options: local,
|
||||
options: options,
|
||||
startCombo: {
|
||||
player: mistPlayer,
|
||||
source: source.index
|
||||
|
@ -1094,7 +1163,7 @@ function mistPlay(streamName,options) {
|
|||
catch (e) {
|
||||
//show the next player/reload buttons if there is an error in the player build code
|
||||
options.target.appendChild(player.element);
|
||||
player.askNextCombo('Error while building player');
|
||||
player.askNextCombo('Error while building player: '+e.stack);
|
||||
throw e;
|
||||
player.report({
|
||||
type: 'init',
|
||||
|
@ -1112,13 +1181,12 @@ function mistPlay(streamName,options) {
|
|||
|
||||
if (player.setTracks(false)) {
|
||||
player.onready(function(){
|
||||
//player.setTracks(usetracks);
|
||||
if ('setTracks' in options) { player.setTracks(options.setTracks); }
|
||||
});
|
||||
}
|
||||
|
||||
//monitor for errors
|
||||
element.checkStalledTimeout = false;
|
||||
element.checkProgressTimeout = false;
|
||||
element.sendPingTimeout = setInterval(function(){
|
||||
if (player.paused) { return; }
|
||||
player.report({
|
||||
|
@ -1130,8 +1198,7 @@ function mistPlay(streamName,options) {
|
|||
player.askNextCombo('The player has thrown an error');
|
||||
var r = {
|
||||
type: 'playback',
|
||||
error: 'The player has thrown an error',
|
||||
origin: e.target.outerHTML.slice(0,e.target.outerHTML.indexOf('>')+1),
|
||||
error: 'The player has thrown an error'
|
||||
};
|
||||
if ('readyState' in player.element) {
|
||||
r.readyState = player.element.readyState;
|
||||
|
@ -1139,85 +1206,90 @@ function mistPlay(streamName,options) {
|
|||
if ('networkState' in player.element) {
|
||||
r.networkState = player.element.networkState;
|
||||
}
|
||||
if (('error' in player.element) && ('code' in player.element.error)) {
|
||||
if (('error' in player.element) && (player.element.error) && ('code' in player.element.error)) {
|
||||
r.code = player.element.error.code;
|
||||
}
|
||||
player.report(r);
|
||||
});
|
||||
element.checkStalledTimeout = false;
|
||||
var stalled = function(e){
|
||||
if (element.checkStalledTimeout) { return; }
|
||||
element.checkStalledTimeout = setTimeout(function(){
|
||||
if (player.paused) { return; }
|
||||
var curpos = player.element.currentTime;
|
||||
if (curpos == 0) { return; }
|
||||
element.checkStalledTimeout = player.timer.add(function(){
|
||||
if ((player.paused) || (curpos != player.element.currentTime)) { return; }
|
||||
player.askNextCombo('Playback has stalled');
|
||||
player.report({
|
||||
'type': 'playback',
|
||||
'warn': 'Playback was stalled for > 10 sec'
|
||||
'warn': 'Playback was stalled for > 30 sec'
|
||||
});
|
||||
},10e3);
|
||||
},30e3);
|
||||
};
|
||||
element.addEventListener('stalled',stalled,true);
|
||||
element.addEventListener('waiting',stalled,true);
|
||||
var progress = function(e){
|
||||
if (element.checkStalledTimeout) {
|
||||
clearTimeout(element.checkStalledTimeout);
|
||||
element.checkStalledTimeout = false;
|
||||
player.cancelAskNextCombo();
|
||||
}
|
||||
};
|
||||
//element.addEventListener('progress',progress,true);
|
||||
//element.addEventListener('playing',progress,true);
|
||||
element.addEventListener('play',function(){
|
||||
player.paused = false;
|
||||
if ((!element.checkProgressTimeout) && (player.element) && ('currentTime' in player.element)) {
|
||||
//check if the progress made is equal to the time spent
|
||||
var lasttime = player.element.currentTime;
|
||||
element.checkProgressTimeout = setInterval(function(){
|
||||
var newtime = player.element.currentTime;
|
||||
progress();
|
||||
if (newtime == 0) { return; }
|
||||
var progressed = newtime - lasttime;
|
||||
lasttime = newtime;
|
||||
if (progressed == 0) {
|
||||
var msg = 'There should be playback but nothing was played';
|
||||
var r = {
|
||||
type: 'playback',
|
||||
warn: msg
|
||||
};
|
||||
player.addlog(msg);
|
||||
if ('readyState' in player.element) {
|
||||
r.readyState = player.element.readyState;
|
||||
}
|
||||
if ('networkState' in player.element) {
|
||||
r.networkState = player.element.networkState;
|
||||
}
|
||||
if (('error' in player.element) && (player.element.error) && ('code' in player.element.error)) {
|
||||
r.code = player.element.error.code;
|
||||
}
|
||||
player.report(r);
|
||||
player.askNextCombo('No playback');
|
||||
if ('load' in player.element) { player.element.load(); }
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerOpts.live) {
|
||||
element.checkProgressTimeout = false;
|
||||
var progress = function(e){
|
||||
if (element.checkStalledTimeout) {
|
||||
player.timer.remove(element.checkStalledTimeout);
|
||||
element.checkStalledTimeout = false;
|
||||
player.cancelAskNextCombo();
|
||||
if (progressed < 1) {
|
||||
var msg = 'It seems playback is lagging (progressed '+Math.round(progressed*100)/100+'/2s)'
|
||||
player.addlog(msg);
|
||||
player.report({
|
||||
type: 'playback',
|
||||
warn: msg
|
||||
});
|
||||
return;
|
||||
}
|
||||
},2e3);
|
||||
}
|
||||
},true);
|
||||
element.addEventListener('pause',function(){
|
||||
player.paused = true;
|
||||
if (element.checkProgressTimeout) {
|
||||
clearInterval(element.checkProgressTimeout);
|
||||
element.checkProgressTimeout = false;
|
||||
}
|
||||
},true);
|
||||
}
|
||||
};
|
||||
//element.addEventListener('progress',progress,true); //sometimes, there is progress but no playback
|
||||
element.addEventListener('playing',progress,true);
|
||||
element.addEventListener('play',function(){
|
||||
player.paused = false;
|
||||
if ((!element.checkProgressTimeout) && (player.element) && ('currentTime' in player.element)) {
|
||||
//check if the progress made is equal to the time spent
|
||||
var lasttime = player.element.currentTime;
|
||||
element.checkProgressTimeout = setInterval(function(){
|
||||
var newtime = player.element.currentTime;
|
||||
var progress = newtime - lasttime;
|
||||
lasttime = newtime;
|
||||
if (progress < 0) { return; } //its probably a looping VOD or we've just seeked
|
||||
if (progress == 0) {
|
||||
var msg = 'There should be playback but nothing was played';
|
||||
var r = {
|
||||
type: 'playback',
|
||||
warn: msg
|
||||
};
|
||||
player.addlog(msg);
|
||||
if ('readyState' in player.element) {
|
||||
r.readyState = player.element.readyState;
|
||||
}
|
||||
if ('networkState' in player.element) {
|
||||
r.networkState = player.element.networkState;
|
||||
}
|
||||
if (('error' in player.element) && (player.element.error) && ('code' in player.element.error)) {
|
||||
r.code = player.element.error.code;
|
||||
}
|
||||
player.report(r);
|
||||
player.askNextCombo('No playback');
|
||||
return;
|
||||
}
|
||||
player.cancelAskNextCombo();
|
||||
if (progress < 20) {
|
||||
var msg = 'It seems playback is lagging (progressed '+Math.round(progress*100)/100+'/30s)'
|
||||
player.addlog(msg);
|
||||
player.report({
|
||||
type: 'playback',
|
||||
warn: msg
|
||||
});
|
||||
return;
|
||||
}
|
||||
},30e3);
|
||||
}
|
||||
},true);
|
||||
element.addEventListener('pause',function(){
|
||||
player.paused = true;
|
||||
if (element.checkProgressTimeout) {
|
||||
clearInterval(element.checkProgressTimeout);
|
||||
element.checkProgressTimeout = false;
|
||||
}
|
||||
},true);
|
||||
}
|
||||
|
||||
if (player.resize) {
|
||||
//monitor for resizes and fire if needed
|
||||
|
@ -1239,8 +1311,8 @@ function mistPlay(streamName,options) {
|
|||
}
|
||||
else if (('source' in streaminfo) && (streaminfo.source.length)) {
|
||||
var str = 'Could not find a compatible player and protocol combination for this stream and browser. ';
|
||||
if (forceType) { str += "\n"+'The mimetype '+forceType+' was enforced. '; }
|
||||
if (forcePlayer) { str += "\n"+'The player '+mistplayers[forcePlayer].name+' was enforced. '; }
|
||||
if (options.forceType) { str += "\n"+'The mimetype '+options.forceType+' was enforced. '; }
|
||||
if (options.forcePlayer) { str += "\n"+'The player '+options.forcePlayer+' was enforced. '; }
|
||||
}
|
||||
else {
|
||||
var str = 'Stream not found.';
|
||||
|
@ -1252,4 +1324,33 @@ function mistPlay(streamName,options) {
|
|||
mistError(str);
|
||||
}
|
||||
}
|
||||
if ((options.streaminfo) && (typeof options.streaminfo == 'object') && ('type' in options.streaminfo)
|
||||
&& ('source' in options.streaminfo) && (options.streaminfo.source.length)
|
||||
&& ('meta' in options.streaminfo) && ('tracks' in options.streaminfo.meta)) { //catch some of the most problematic stuff
|
||||
if (typeof mistvideo == 'undefined') { mistvideo = {}; }
|
||||
mistvideo[streamName] = options.streaminfo;
|
||||
onstreaminfo();
|
||||
}
|
||||
else {
|
||||
//get info js
|
||||
var info = document.createElement('script');
|
||||
info.src = options.host+'/info_'+encodeURIComponent(streamName)+'.js';
|
||||
embedLog('Retrieving stream info from '+info.src);
|
||||
document.head.appendChild(info);
|
||||
info.onerror = function(){
|
||||
options.target.innerHTML = '';
|
||||
options.target.removeAttribute('data-loading');
|
||||
mistError('Error while loading stream info.');
|
||||
protoplay.report({
|
||||
type: 'init',
|
||||
error: 'Failed to load '+info.src
|
||||
});
|
||||
}
|
||||
info.onload = function(){
|
||||
//clean up info script
|
||||
document.head.removeChild(info);
|
||||
|
||||
onstreaminfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
198
embed/test.html
198
embed/test.html
|
@ -1,198 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Embed test</title>
|
||||
|
||||
<!--
|
||||
include script for paid players
|
||||
- jwplayer
|
||||
- theoplayer
|
||||
-->
|
||||
|
||||
<!--<script type='text/javascript' src='//cdn.theoplayer.com/latest/41718edc-cc2d-40d0-83d4-67c50c60f68f/theoplayer.loader.js'></script>-->
|
||||
<!--<script src=players/jwplayer.js></script>
|
||||
<script>jwplayer.key="2z0zTRsxD2HkL6m/LgDqvtUy2EThVn+gk1gN1Q==";</script>-->
|
||||
|
||||
<script>
|
||||
// global options can be set here
|
||||
var mistoptions = {
|
||||
//host: 'http://cat.mistserver.org:8080'
|
||||
host: 'http://thulmk3:8080'
|
||||
//host: 'https://cat.mistserver.org:4433'
|
||||
//host: 'http://localhost:8080'
|
||||
//host: 'http://live.us.picarto.tv:8080'
|
||||
//host: 'balderlaptop:8080'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script src=core.js></script>
|
||||
<!--<script src=wrappers/theoplayer.js></script>-->
|
||||
<!--<script src=wrappers/jwplayer.js></script>-->
|
||||
<script src=wrappers/html5.js></script>
|
||||
<script src=wrappers/videojs.js></script>
|
||||
<script src=wrappers/dashjs.js></script>
|
||||
<script src=wrappers/flash_strobe.js></script>
|
||||
<script src=wrappers/silverlight.js></script>
|
||||
<script src=wrappers/polytrope.js></script>
|
||||
|
||||
<script src=players/dash.js></script>
|
||||
<script src=players/videojs.js></script>
|
||||
|
||||
<link rel=stylesheet href=mist.css id=mist_player_css>
|
||||
<style>
|
||||
/* the website can override the css at will */
|
||||
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
max-width: 100vw;
|
||||
max-height: 100vh;
|
||||
}
|
||||
.mistvideo {
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
function mistinit(){
|
||||
var logele = document.querySelector('.log');
|
||||
var contele = document.querySelector('.cont');
|
||||
document.addEventListener('error',function(e){
|
||||
console.log('[Error] '+e.message,e.target);
|
||||
var msg = document.createTextNode('['+(new Date()).toTimeString().split(' ')[0]+'] '+e.message+' from '+e.target.outerHTML.slice(0,e.target.outerHTML.indexOf('>')+1));
|
||||
var div = document.createElement('div');
|
||||
div.appendChild(msg);
|
||||
div.style.color = 'red';
|
||||
logele.appendChild(div);
|
||||
});
|
||||
document.addEventListener('log',function(e){
|
||||
console.log('[log] '+e.message);
|
||||
return;
|
||||
var msg = document.createTextNode('['+(new Date()).toTimeString().split(' ')[0]+'] '+e.message);
|
||||
var div = document.createElement('div');
|
||||
div.appendChild(msg);
|
||||
logele.appendChild(div);
|
||||
});
|
||||
|
||||
//tryplayers = Object.keys(mistplayers);
|
||||
tryplayers = [];
|
||||
//tryplayers.push('automatic');
|
||||
//tryplayers.push('html5');
|
||||
tryplayers.push('dashjs');
|
||||
//tryplayers.push('videojs');
|
||||
//tryplayers.push('flash_strobe');
|
||||
//tryplayers.push('silverlight');
|
||||
streams = [];
|
||||
//streams.push('live');
|
||||
//streams.push('golive+emitan');
|
||||
//streams.push('subtel');
|
||||
//streams.push('ogg');
|
||||
//streams.push('vids+mist.mp4');
|
||||
//streams.push('vids+hahalol.mp3');
|
||||
//streams.push('lama');
|
||||
//streams.push('bunny');
|
||||
streams.push('golive+SockyChannel');
|
||||
|
||||
for (var j in streams) {
|
||||
for (var i in tryplayers) {
|
||||
var d = document.createElement('div');
|
||||
var c = document.createElement('div');
|
||||
c.className = 'mistvideo';
|
||||
c.title = tryplayers[i];
|
||||
d.appendChild(c);
|
||||
contele.appendChild(d);
|
||||
var p = mistPlay(streams[j],{
|
||||
target: c,
|
||||
maxwidth: 800,
|
||||
forcePlayer: tryplayers[i],
|
||||
//forceType: 'html5/video/mp4',
|
||||
//forceType: 'html5/audio/mp3',
|
||||
//forceType: 'html5/application/vnd.apple.mpegurl',
|
||||
//forceType: 'dash/video/mp4',
|
||||
//forceSource: 3,
|
||||
loop: true,
|
||||
//controls: 'stock'
|
||||
callback: function(player) {
|
||||
var button = document.createElement('button');
|
||||
button.innerHTML = 'askNextCombo();';
|
||||
button.onclick = function(){
|
||||
player.askNextCombo('Button was clicked');
|
||||
d.removeChild(this);
|
||||
};
|
||||
d.append(button);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
thumbnailing :')
|
||||
document.addEventListener('initialized',function(e){
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = 180;
|
||||
document.body.appendChild(canvas);
|
||||
var context = canvas.getContext('2d');
|
||||
var embedded;
|
||||
for (var i in mistvideo) {
|
||||
embedded = mistvideo[i].embedded[0];
|
||||
break;
|
||||
}
|
||||
var video = embedded.player.element;
|
||||
var f = video.width / canvas.width;
|
||||
canvas.height = video.height / f;
|
||||
video.addEventListener('canplay',function(){
|
||||
context.drawImage(video,0,0,canvas.width,canvas.height);
|
||||
var img = canvas.toDataURL('image/jpeg');
|
||||
document.write('<img src="'+img+'">');
|
||||
});
|
||||
});
|
||||
*/
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body onload=mistinit()>
|
||||
<h1>Sup</h1>
|
||||
<!--
|
||||
<div class='mistvideo' id='bunny_84yt98eh9g8ht'>
|
||||
<noscript>
|
||||
<video controls autoplay>
|
||||
<source src='http://localhost:8080/bunny.mp4' type='video/mp4'>
|
||||
<a href='http://localhost:8080/bunny.html' target='_blank'>
|
||||
Click here to play video
|
||||
</a>
|
||||
</video>
|
||||
</noscript>
|
||||
<script>
|
||||
(function(){
|
||||
var play = function(){
|
||||
mistPlay('vids+subtel.mp4',{
|
||||
//mistPlay('bunny',{
|
||||
target: document.getElementById('bunny_84yt98eh9g8ht'),
|
||||
//forcePlayer: 'dashjs'
|
||||
});
|
||||
}
|
||||
if (!window.mistplayers) { //import shit
|
||||
var p = document.createElement('script');
|
||||
p.src = 'http://localhost:8080/player.js';
|
||||
document.head.appendChild(p);
|
||||
p.onload = function(){
|
||||
play();
|
||||
}
|
||||
}
|
||||
else {
|
||||
play();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</div>-->
|
||||
<div class=cont></div>
|
||||
<div class=log></div>
|
||||
</body>
|
||||
</html>
|
|
@ -82,13 +82,19 @@ p.prototype.build = function (options,callback) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
me.adderror(msg);
|
||||
},true);
|
||||
//prevent onerror loops
|
||||
if (e.target == me.element) {
|
||||
e.message = msg;
|
||||
}
|
||||
else {
|
||||
me.adderror(msg);
|
||||
}
|
||||
});
|
||||
var events = ['abort','canplay','canplaythrough','durationchange','emptied','ended','interruptbegin','interruptend','loadeddata','loadedmetadata','loadstart','pause','play','playing','ratechange','seeked','seeking','stalled','volumechange','waiting'];
|
||||
for (var i in events) {
|
||||
ele.addEventListener(events[i],function(e){
|
||||
me.addlog('Player event fired: '+e.type);
|
||||
},true);
|
||||
});
|
||||
}
|
||||
|
||||
var player = dashjs.MediaPlayer().create();
|
||||
|
|
|
@ -95,11 +95,15 @@ p.prototype.build = function (options) {
|
|||
else { ele.pause(); }
|
||||
};
|
||||
|
||||
if (options.live) {
|
||||
ele.addEventListener('error',function(e){
|
||||
this.addlog('Built html');
|
||||
|
||||
//forward events
|
||||
ele.addEventListener('error',function(e){
|
||||
|
||||
if (options.live) {
|
||||
if ((ele.error) && (ele.error.code == 3)) {
|
||||
e.stopPropagation();
|
||||
ele.load();
|
||||
e.stopPropagation(); //dont let this error continue to prevent the core from trying to handle the error
|
||||
me.load();
|
||||
me.cancelAskNextCombo();
|
||||
e.message = 'Handled decoding error';
|
||||
me.addlog('Decoding error: reloading..');
|
||||
|
@ -107,18 +111,19 @@ p.prototype.build = function (options) {
|
|||
type: 'playback',
|
||||
warn: 'A decoding error was encountered, but handled'
|
||||
});
|
||||
return;
|
||||
}
|
||||
},true);
|
||||
}
|
||||
|
||||
this.addlog('Built html');
|
||||
|
||||
//forward events
|
||||
ele.addEventListener('error',function(e){
|
||||
}
|
||||
|
||||
var msg;
|
||||
if ('message' in e) {
|
||||
msg = e.message;
|
||||
}
|
||||
else if ((e.target.tagName == 'SOURCE') && (e.target.getAttribute('src') == '')) {
|
||||
e.stopPropagation();
|
||||
//this error is triggered because the unload function was fired
|
||||
return;
|
||||
}
|
||||
else {
|
||||
msg = 'readyState: ';
|
||||
switch (me.element.readyState) {
|
||||
|
@ -154,15 +159,20 @@ p.prototype.build = function (options) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
me.adderror(msg);
|
||||
},true);
|
||||
//prevent onerror loops
|
||||
if (e.target == me.element) {
|
||||
e.message = msg;
|
||||
}
|
||||
else {
|
||||
me.adderror(msg);
|
||||
}
|
||||
});
|
||||
var events = ['abort','canplay','canplaythrough','durationchange','emptied','ended','interruptbegin','interruptend','loadeddata','loadedmetadata','loadstart','pause','play','playing','ratechange','seeked','seeking','stalled','volumechange','waiting','progress'];
|
||||
for (var i in events) {
|
||||
ele.addEventListener(events[i],function(e){
|
||||
me.addlog('Player event fired: '+e.type);
|
||||
},true);
|
||||
});
|
||||
}
|
||||
|
||||
return cont;
|
||||
}
|
||||
p.prototype.play = function(){ return this.element.play(); };
|
||||
|
@ -177,7 +187,32 @@ p.prototype.loop = function(bool){
|
|||
}
|
||||
return this.element.loop = bool;
|
||||
};
|
||||
p.prototype.load = function(){ return this.element.load(); };
|
||||
p.prototype.load = function(){
|
||||
var load;
|
||||
if (this.element.paused) {
|
||||
load = this.element.load();
|
||||
}
|
||||
else {
|
||||
//sometimes there is a play / pause interrupt: try again
|
||||
//TODO figure out if this happens on paused or on playing
|
||||
this.load();
|
||||
return;
|
||||
}
|
||||
|
||||
//this helps to prevent the player from just showing a black screen after a reload
|
||||
if (this.element.paused) {
|
||||
var me = this;
|
||||
var unpause = function(){
|
||||
if (me.element.paused) {
|
||||
me.element.play();
|
||||
}
|
||||
me.element.removeEventListener('progress',unpause);
|
||||
}
|
||||
this.element.addEventListener('progress',unpause);
|
||||
}
|
||||
|
||||
return load;
|
||||
};
|
||||
if (document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled) {
|
||||
p.prototype.fullscreen = function(){
|
||||
if(this.element.requestFullscreen) {
|
||||
|
|
22
embed/wrappers/img.js
Normal file
22
embed/wrappers/img.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
mistplayers.img = {
|
||||
name: 'HTML img tag',
|
||||
mimes: ['html5/image/jpeg'],
|
||||
priority: Object.keys(mistplayers).length + 1,
|
||||
isMimeSupported: function (mimetype) {
|
||||
return (this.mimes.indexOf(mimetype) == -1 ? false : true);
|
||||
},
|
||||
isBrowserSupported: function (mimetype,source,options,streaminfo) {
|
||||
//only use this if we are sure we just want an image
|
||||
if ((options.forceType) || (options.forceSource) || (options.forcePlayer)) { return true; }
|
||||
return false;
|
||||
},
|
||||
player: function(){}
|
||||
};
|
||||
var p = mistplayers.img.player;
|
||||
p.prototype = new MistPlayer();
|
||||
p.prototype.build = function (options) {
|
||||
var ele = this.getElement('img');
|
||||
ele.src = options.src;
|
||||
ele.style.display = 'block';
|
||||
return ele;
|
||||
}
|
|
@ -6,15 +6,30 @@ mistplayers.videojs = {
|
|||
return (this.mimes.indexOf(mimetype) == -1 ? false : true);
|
||||
},
|
||||
isBrowserSupported: function (mimetype,source,options,streaminfo,logfunc) {
|
||||
|
||||
//dont use https if the player is loaded over http
|
||||
if ((options.host.substr(0,7) == 'http://') && (source.url.substr(0,8) == 'https://')) {
|
||||
if (logfunc) { logfunc('HTTP/HTTPS mismatch for this source'); }
|
||||
return false;
|
||||
}
|
||||
var support = true;
|
||||
|
||||
//dont use videojs if this location is loaded over file://
|
||||
if ((location.protocol == 'file:') && (mimetype == 'html5/application/vnd.apple.mpegurl')) {
|
||||
if (logfunc) { logfunc('This source ('+mimetype+') won\'t work if the page is run via file://'); }
|
||||
return false;
|
||||
}
|
||||
|
||||
//dont use HLS if there is an MP3 audio track, unless we're on apple or edge
|
||||
if ((mimetype == 'html5/application/vnd.apple.mpegurl') && (['iPad','iPhone','iPod','MacIntel'].indexOf(navigator.platform) == -1) && (navigator.userAgent.indexOf('Edge') == -1)) {
|
||||
for (var i in streaminfo.meta.tracks) {
|
||||
var t = streaminfo.meta.tracks[i];
|
||||
if (t.codec == 'MP3') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ('MediaSource' in window);
|
||||
},
|
||||
player: function(){},
|
||||
|
@ -117,13 +132,19 @@ p.prototype.build = function (options) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
me.adderror(msg);
|
||||
},true);
|
||||
//prevent onerror loops
|
||||
if (e.target == me.element) {
|
||||
e.message = msg;
|
||||
}
|
||||
else {
|
||||
me.adderror(msg);
|
||||
}
|
||||
});
|
||||
var events = ['abort','canplay','canplaythrough','durationchange','emptied','ended','interruptbegin','interruptend','loadeddata','loadedmetadata','loadstart','pause','play','playing','ratechange','seeked','seeking','stalled','volumechange','waiting','progress'];
|
||||
for (var i in events) {
|
||||
ele.addEventListener(events[i],function(e){
|
||||
me.addlog('Player event fired: '+e.type);
|
||||
},true);
|
||||
});
|
||||
}
|
||||
|
||||
return cont;
|
||||
|
|
|
@ -792,6 +792,13 @@ button.return:before {
|
|||
background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIGlkPSJzdmcyIiBoZWlnaHQ9IjQ1IiB3aWR0aD0iNDUiPjxkZWZzIGlkPSJkZWZzNCIgLz48bWV0YWRhdGEgaWQ9Im1ldGFkYXRhNyI+PHJkZjpSREY+PGNjOldvcmsgcmRmOmFib3V0PSIiPjxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PjxkYzp0eXBlIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+PGRjOnRpdGxlPjwvZGM6dGl0bGU+PC9jYzpXb3JrPjwvcmRmOlJERj48L21ldGFkYXRhPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTEwMDcuMzYyMikiIGlkPSJsYXllcjEiPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDEuMDE0MTgyNywtMC41ODU1Mzg2NywwLjU4NTUzODY3LDEuMDE0MTgyNywtMC40ODQxOTgzMSwxMDIyLjg4OTMpIiBkPSJNIDEwLjMxMjUsLTYuMzQzNzUgQSAyLjk0MTYxODYsMi45NDE2MTg2IDAgMCAwIDcuOTA2MjUsLTQuODc1IGwgLTE0LjEyNSwyNC41IGEgMi45NDE2MTg2LDIuOTQxNjE4NiAwIDAgMCAyLjU2MjUsNC40MDYyNSBsIDI4LjI4MTI1LDAgQSAyLjk0MTYxODYsMi45NDE2MTg2IDAgMCAwIDI3LjE1NjI1LDE5LjYyNSBMIDEzLC00Ljg3NSBhIDIuOTQxNjE4NiwyLjk0MTYxODYgMCAwIDAgLTIuNjg3NSwtMS40Njg3NSB6IiBpZD0icGF0aDM4MDkiIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLW9wYWNpdHk6MSIgLz48L2c+PC9zdmc+");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
line-height: 100px;
|
||||
}
|
||||
.preview_icons .image img {
|
||||
max-width: 200px;
|
||||
max-height: 100px;
|
||||
min-width: 0px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.preview_icons .image.folder {
|
||||
background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciICB2ZXJzaW9uPSIxLjEiICBpZD0ic3ZnMiIgIHZpZXdCb3g9IjAgMCA0NSA0NSIgIGhlaWdodD0iNDUiICB3aWR0aD0iNDUiPiA8ZGVmcyAgIGlkPSJkZWZzNCIgLz4gPG1ldGFkYXRhICAgaWQ9Im1ldGFkYXRhNyI+ICA8cmRmOlJERj4gICA8Y2M6V29yayAgICAgcmRmOmFib3V0PSIiPiAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgPGRjOnR5cGUgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4gICA8L2NjOldvcms+ICA8L3JkZjpSREY+IDwvbWV0YWRhdGE+IDxnICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTAwNy4zNjIyKSIgICBpZD0ibGF5ZXIxIj4gIDxwYXRoICAgIGlkPSJyZWN0NDE0NyIgICAgZD0ibSAyNi41MDAwMDEsMTAxNC4yOTk3IC01LjMzMzMzNCw1LjkyNzEgLTE4LjY2NjY2NywwIDAsMjkuNjM1NCAyNCwwIDE2LDAgYyAwLC0xMS44NTQyIDAsLTIzLjcwODMgMCwtMzUuNTYyNSB6IiAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MTtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiIC8+IDwvZz48L3N2Zz4=");
|
||||
|
|
|
@ -30,59 +30,60 @@ $(this).data("validate")(this,!0))return!1});b||(a.find(".isSetting").each(funct
|
|||
[3,"3 - Previous level, and warning messages"],[4,"4 - Previous level, and status messages for development"],[5,"5 - Previous level, and more status messages for development"],[6,"6 - Previous level, and verbose debugging messages"],[7,"7 - Previous level, and very verbose debugging messages"],[8,"8 - Report everything in extreme detail"],[9,"9 - Report everything in insane detail"],[10,"10 - All messages enabled"]];case "select":e=$("<select>");for(g in d.select){var p=$("<option>");"string"==typeof d.select[g]?
|
||||
p.text(d.select[g]):p.val(d.select[g][0]).text(d.select[g][1]);e.append(p)}break;case "textarea":e=$("<textarea>").on("keydown",function(a){a.stopPropagation()});break;case "checkbox":e=$("<input>").attr("type","checkbox");break;case "hidden":e=$("<input>").attr("type","hidden");m.hide();break;case "email":e=$("<input>").attr("type","email").attr("autocomplete","on").attr("required","");break;case "browse":e=$("<input>").attr("type","text");"filetypes"in d&&e.data("filetypes",d.filetypes);break;case "geolimited":case "hostlimited":e=
|
||||
$("<input>").attr("type","hidden");break;case "radioselect":e=$("<div>").addClass("radioselect");for(c in d.radioselect){var l=$("<input>").attr("type","radio").val(d.radioselect[c][0]).attr("name",d.label);("LTSonly"in d&&!mist.data.LTS||d.readonly)&&l.prop("disabled",!0);p=$("<label>").append(l).append($("<span>").html(d.radioselect[c][1]));e.append(p);if(2<d.radioselect[c].length)for(g in l=$("<select>").change(function(){$(this).parent().find("input[type=radio]:enabled").prop("checked","true")}),
|
||||
p.append(l),("LTSonly"in d&&!mist.data.LTS||d.readonly)&&l.prop("disabled",!0),d.radioselect[c][2])p=$("<option>"),l.append(p),d.radioselect[c][2][g]instanceof Array?p.val(d.radioselect[c][2][g][0]).html(d.radioselect[c][2][g][1]):p.html(d.radioselect[c][2][g])}break;case "checklist":e=$("<div>").addClass("checkcontainer");$controls=$("<div>").addClass("controls");$checklist=$("<div>").addClass("checklist");e.append($controls).append($checklist);$controls.append($("<label>").text("All").prepend($("<input>").attr("type",
|
||||
"checkbox").click(function(){$(this).is(":checked")?$(this).closest(".checkcontainer").find("input[type=checkbox]").prop("checked",!0):$(this).closest(".checkcontainer").find("input[type=checkbox]").prop("checked",!1)})));for(c in d.checklist)"string"==typeof d.checklist[c]&&(d.checklist[c]=[d.checklist[c],d.checklist[c]]),$checklist.append($("<label>").text(d.checklist[c][1]).prepend($("<input>").attr("type","checkbox").attr("name",d.checklist[c][0])));break;case "DOMfield":e=d.DOMfield;break;default:e=
|
||||
$("<input>").attr("type","text")}e.addClass("field").data("opts",d);"pointer"in d&&e.attr("name",d.pointer.index);f.append(e);if("classes"in d)for(g in d.classes)e.addClass(d.classes[g]);"placeholder"in d&&e.attr("placeholder",d.placeholder);"default"in d&&e.attr("placeholder",d["default"]);"unit"in d&&f.append($("<span>").addClass("unit").html(d.unit));"readonly"in d&&(e.attr("readonly","readonly"),e.click(function(){$(this).select()}));"qrcode"in d&&f.append($("<span>").addClass("unit").html($("<button>").text("QR").on("keydown",
|
||||
function(a){a.stopPropagation()}).click(function(){var a=String($(this).closest(".field_container").find(".field").getval()),b=$("<div>").addClass("qrcode");UI.popup.show($("<span>").addClass("qr_container").append($("<p>").text(a)).append(b));b.qrcode({text:a,size:Math.min(b.width(),b.height())})})));"clipboard"in d&&document.queryCommandSupported("copy")&&f.append($("<span>").addClass("unit").html($("<button>").text("Copy").on("keydown",function(a){a.stopPropagation()}).click(function(){var a=String($(this).closest(".field_container").find(".field").getval()),
|
||||
b=document.createElement("textarea");b.value=a;document.body.appendChild(b);b.select();var c=false;try{c=document.execCommand("copy")}catch(d){}if(c){$(this).text("Copied to clipboard!");document.body.removeChild(b);var g=$(this);setTimeout(function(){g.text("Copy")},5E3)}else{document.body.removeChild(b);alert("Failed to copy:\n"+a)}})));"rows"in d&&e.attr("rows",d.rows);"LTSonly"in d&&!mist.data.LTS&&(f.addClass("LTSonly"),e.prop("disabled",!0));switch(d.type){case "browse":l=$("<div>").addClass("grouper").append(m);
|
||||
b.append(l);l=$("<button>").text("Browse").on("keydown",function(a){a.stopPropagation()});f.append(l);l.click(function(){function a(b){m.text("Loading..");mist.send(function(a){f.text(a.browse.path[0]);mist.data.LTS&&d.setval(a.browse.path[0]+"/");m.html(l.clone(true).text("..").attr("title","Folder up"));if(a.browse.subdirectories){a.browse.subdirectories.sort();for(var b in a.browse.subdirectories){var e=a.browse.subdirectories[b];m.append(l.clone(true).attr("title",f.text()+q+e).text(e))}}if(a.browse.files){a.browse.files.sort();
|
||||
for(b in a.browse.files){var e=a.browse.files[b],h=f.text()+q+e,e=$("<a>").text(e).addClass("file").attr("title",h);m.append(e);if(p){var n=true,u;for(u in p)if(typeof p[u]!="undefined"&&mist.inputMatch(p[u],h)){n=false;break}n&&e.hide()}e.click(function(){var a=$(this).attr("title");d.setval(a).removeAttr("readonly").css("opacity",1);g.show();c.remove()})}}},{browse:b})}var b=$(this).closest(".grouper"),c=$("<div>").addClass("browse_container"),d=b.find(".field").attr("readonly","readonly").css("opacity",
|
||||
0.5),g=$(this),e=$("<button>").text("Stop browsing").click(function(){g.show();c.remove();d.removeAttr("readonly").css("opacity",1)}),f=$("<span>").addClass("field"),m=$("<div>").addClass("browse_contents"),l=$("<a>").addClass("folder"),p=d.data("filetypes");b.append(c);c.append($("<label>").addClass("UIelement").append($("<span>").addClass("label").text("Current folder:")).append($("<span>").addClass("field_container").append(f).append(e))).append(m);var q="/";mist.data.config.version.indexOf("indows")>
|
||||
-1&&(q="\\");l.click(function(){var b=f.text()+q+$(this).text();a(b)});b=d.getval();e=b.split("://");e.length>1&&(b=e[0]=="file"?e[1]:"");b=b.split(q);b.pop();b=b.join(q);g.hide();a(b)});break;case "geolimited":case "hostlimited":l={field:e};l.blackwhite=$("<select>").append($("<option>").val("-").text("Blacklist")).append($("<option>").val("+").text("Whitelist"));l.values=$("<span>").addClass("limit_value_list");switch(d.type){case "geolimited":l.prototype=$("<select>").append($("<option>").val("").text("[Select a country]"));
|
||||
for(c in UI.countrylist)l.prototype.append($("<option>").val(c).html(UI.countrylist[c]));break;case "hostlimited":l.prototype=$("<input>").attr("type","text").attr("placeholder","type a host")}l.prototype.on("change keyup",function(){$(this).closest(".field_container").data("subUI").blackwhite.trigger("change")});l.blackwhite.change(function(){var a=$(this).closest(".field_container").data("subUI"),b=[],c=false;a.values.children().each(function(){c=$(this).val();c!=""?b.push(c):$(this).remove()});
|
||||
a.values.append(a.prototype.clone(true));b.length>0?a.field.val($(this).val()+b.join(" ")):a.field.val("");a.field.trigger("change")});"LTSonly"in d&&!mist.data.LTS&&(l.blackwhite.prop("disabled",!0),l.prototype.prop("disabled",!0));l.values.append(l.prototype.clone(!0));f.data("subUI",l).addClass("limit_list").append(l.blackwhite).append(l.values)}"pointer"in d&&(e.data("pointer",d.pointer).addClass("isSetting"),l=d.pointer.main[d.pointer.index],"undefined"!=l&&e.setval(l));"value"in d&&e.setval(d.value);
|
||||
if("datalist"in d)for(c in l="datalist_"+c+MD5(e[0].outerHTML),e.attr("list",l),l=$("<datalist>").attr("id",l),f.append(l),d.datalist)l.append($("<option>").val(d.datalist[c]));f=$("<span>").addClass("help_container");m.append(f);"help"in d&&(f.append($("<span>").addClass("ih_balloon").html(d.help)),e.on("focus mouseover",function(){$(this).closest("label").addClass("active")}).on("blur mouseout",function(){$(this).closest("label").removeClass("active")}));if("validate"in d){m=[];for(g in d.validate){l=
|
||||
d.validate[g];if("function"!=typeof l)switch(l){case "required":l=function(a){return a==""?{msg:"This is a required field.",classes:["red"]}:false};break;case "int":l=function(a,b){var c=$(b).data("opts");if(!$(b)[0].validity.valid){var d=[];"min"in c&&d.push(" greater than or equal to "+c.min);"max"in c&&d.push(" smaller than or equal to "+c.max);return{msg:"Please enter an integer"+d.join(" and")+".",classes:["red"]}}if(parseInt(Number(a))!=a)return{msg:"Please enter an integer.",classes:["red"]}};
|
||||
break;case "streamname":l=function(a,b){if(!isNaN(a.charAt(0)))return{msg:"The first character may not be a number.",classes:["red"]};if(a.toLowerCase()!=a)return{msg:"Uppercase letters are not allowed.",classes:["red"]};if(a.replace(/[^\da-z_]/g,"")!=a)return{msg:"Special characters (except for underscores) are not allowed.",classes:["red"]};if("streams"in mist.data&&a in mist.data.streams&&$(b).data("pointer").main.name!=a)return{msg:"This streamname already exists.<br>If you want to edit an existing stream, please click edit on the the streams tab.",
|
||||
classes:["red"]}};break;default:l=function(){}}m.push(l)}e.data("validate_functions",m).data("help_container",f).data("validate",function(a,b){var c=$(a).getval(),d=$(a).data("validate_functions"),e=$(a).data("help_container");e.find(".err_balloon").remove();for(var g in d){var f=d[g](c,a);if(f){$err=$("<span>").addClass("err_balloon").html(f.msg);for(var m in f.classes)$err.addClass(f.classes[m]);e.prepend($err);b&&$(a).focus();return true}}return false}).addClass("hasValidate").on("change keyup",
|
||||
function(){$(this).data("validate")($(this))});""!=e.getval()&&e.trigger("change")}"function"in d&&(e.on("change keyup",d["function"]),e.trigger("change"))}}b.on("keydown",function(a){switch(a.which){case 13:$(this).find("button.save").first().trigger("click");break;case 27:$(this).find("button.cancel").first().trigger("click")}});return b},buildVheaderTable:function(a){var b=$("<table>").css("margin","0.2em"),c=$("<tr>").addClass("header").append($("<td>").addClass("vheader").attr("rowspan",a.labels.length+
|
||||
1).append($("<span>").text(a.vheader))),d=[];c.append($("<td>"));for(var e in a.labels)d.push($("<tr>").append($("<td>").html(""==a.labels[e]?" ":a.labels[e]+":")));for(var g in a.content)for(e in c.append($("<td>").html(a.content[g].header)),a.content[g].body)d[e].append($("<td>").html(a.content[g].body[e]));b.append($("<tbody>").append(c).append(d));return b},plot:{addGraph:function(a,b){var c={id:a.id,xaxis:a.xaxis,datasets:[],elements:{cont:$("<div>").addClass("graph"),plot:$("<div>").addClass("plot"),
|
||||
legend:$("<div>").addClass("legend").attr("draggable","true")}};UI.draggable(c.elements.legend);c.elements.cont.append(c.elements.plot).append(c.elements.legend);b.append(c.elements.cont);return c},go:function(a){if(!(1>Object.keys(a).length)){var b={totals:[],clients:[]},c;for(c in a)for(var d in a[c].datasets){var e=a[c].datasets[d];switch(e.datatype){case "clients":case "upbps":case "downbps":switch(e.origin[0]){case "total":b.totals.push({fields:[e.datatype],end:-15});break;case "stream":b.totals.push({fields:[e.datatype],
|
||||
streams:[e.origin[1]],end:-15});break;case "protocol":b.totals.push({fields:[e.datatype],protocols:[e.origin[1]],end:-15})}break;case "cpuload":case "memload":b.capabilities={}}}0==b.totals.length&&delete b.totals;0==b.clients.length&&delete b.clients;mist.send(function(){for(var b in a){var c=a[b];if(1>c.datasets.length){c.elements.plot.html("");c.elements.legend.html("");break}switch(c.xaxis){case "time":var d=[];c.yaxes={};var e=[],p;for(p in c.datasets){var l=c.datasets[p];l.display&&(l.getdata(),
|
||||
l.yaxistype in c.yaxes||(d.push(UI.plot.yaxes[l.yaxistype]),c.yaxes[l.yaxistype]=d.length),l.yaxis=c.yaxes[l.yaxistype],e.push(l))}d[0]&&(d[0].color=0);c.plot=$.plot(c.elements.plot,e,{legend:{show:!1},xaxis:UI.plot.xaxes[c.xaxis],yaxes:d,grid:{hoverable:!0,borderWidth:{top:0,right:0,bottom:1,left:1},color:"black",backgroundColor:{colors:["rgba(0,0,0,0)","rgba(0,0,0,0.025)"]}},crosshair:{mode:"x"}});d=$("<table>").addClass("legend-list").addClass("nolay").html($("<tr>").html($("<td>").html($("<h3>").text(c.id))).append($("<td>").css("padding-right",
|
||||
"2em").css("text-align","right").html($("<span>").addClass("value")).append($("<button>").data("opts",c).text("X").addClass("close").click(function(){var b=$(this).data("opts");if(confirm("Are you sure you want to remove "+b.id+"?")){b.elements.cont.remove();var c=$(".graph_ids option:contains("+b.id+")"),d=c.parent();c.remove();UI.plot.del(b.id);delete a[b.id];d.trigger("change");UI.plot.go(a)}}))));c.elements.legend.html(d);var u=function(a){var b=c.elements.legend.find(".value"),d=1;if(typeof a==
|
||||
"undefined")b.eq(0).html("Latest:");else{var e=c.plot.getXAxes()[0],a=Math.min(e.max,a),a=Math.max(e.min,a);b.eq(0).html(UI.format.time(a/1E3))}for(var g in c.datasets){var f=" ";if(c.datasets[g].display){var e=UI.plot.yaxes[c.datasets[g].yaxistype].tickFormatter,h=c.datasets[g].data;if(a)for(var l in h){if(h[l][0]==a){f=e(h[l][1]);break}if(h[l][0]>a){if(l!=0){f=h[l];h=h[l-1];f=e(f[1]+(a-f[0])*(h[1]-f[1])/(h[0]-f[0]))}break}}else f=e(c.datasets[g].data[c.datasets[g].data.length-1][1])}b.eq(d).html(f);
|
||||
d++}};c.plot.getOptions();for(p in c.datasets)e=$("<input>").attr("type","checkbox").data("index",p).data("graph",c).click(function(){var a=$(this).data("graph");$(this).is(":checked")?a.datasets[$(this).data("index")].display=true:a.datasets[$(this).data("index")].display=false;var b={};b[a.id]=a;UI.plot.go(b)}),c.datasets[p].display&&e.attr("checked","checked"),d.append($("<tr>").html($("<td>").html($("<label>").html(e).append($("<div>").addClass("series-color").css("background-color",c.datasets[p].color)).append(c.datasets[p].label))).append($("<td>").css("padding-right",
|
||||
"2em").css("text-align","right").html($("<span>").addClass("value")).append($("<button>").text("X").addClass("close").data("index",p).data("graph",c).click(function(){var b=$(this).data("index"),c=$(this).data("graph");if(confirm("Are you sure you want to remove "+c.datasets[b].label+" from "+c.id+"?")){c.datasets.splice(b,1);if(c.datasets.length==0){c.elements.cont.remove();var b=$(".graph_ids option:contains("+c.id+")"),d=b.parent();b.remove();d.trigger("change");UI.plot.del(c.id);delete a[c.id];
|
||||
UI.plot.go(a)}else{UI.plot.save(c);b={};b[c.id]=c;UI.plot.go(b)}}}))));u();var h=!1;c.elements.plot.on("plothover",function(a,b,c){if(b.x!=h){u(b.x);h=b.x}if(c){a=$("<span>").append($("<h3>").text(c.series.label).prepend($("<div>").addClass("series-color").css("background-color",c.series.color))).append($("<table>").addClass("nolay").html($("<tr>").html($("<td>").text("Time:")).append($("<td>").html(UI.format.dateTime(c.datapoint[0]/1E3,"long")))).append($("<tr>").html($("<td>").text("Value:")).append($("<td>").html(c.series.yaxis.tickFormatter(c.datapoint[1],
|
||||
c.series.yaxis)))));UI.tooltip.show(b,a.children())}else UI.tooltip.hide()}).on("mouseout",function(){u()})}}},b)}},save:function(a){var b={id:a.id,xaxis:a.xaxis,datasets:[]},c;for(c in a.datasets)b.datasets.push({origin:a.datasets[c].origin,datatype:a.datasets[c].datatype});a=mist.stored.get().graphs||{};a[b.id]=b;mist.stored.set("graphs",a)},del:function(a){var b=mist.stored.get().graphs||{};delete b[a];mist.stored.set("graphs",b)},datatype:{getOptions:function(a){var b=$.extend(!0,{},UI.plot.datatype.templates.general),
|
||||
c=$.extend(!0,{},UI.plot.datatype.templates[a.datatype]),a=$.extend(!0,c,a),a=$.extend(!0,b,a);switch(a.origin[0]){case "total":switch(a.datatype){case "cpuload":case "memload":break;default:a.label+=" (total)"}break;case "stream":case "protocol":a.label+=" ("+a.origin[1]+")"}var b=[],d;for(d in a.basecolor)c=a.basecolor[d],c+=50*(0.5-Math.random()),c=Math.round(c),c=Math.min(255,Math.max(0,c)),b.push(c);a.color="rgb("+b.join(",")+")";return a},templates:{general:{display:!0,datatype:"general",label:"",
|
||||
yaxistype:"amount",data:[],lines:{show:!0},points:{show:!1},getdata:function(){var a=mist.data.totals["stream"==this.origin[0]?this.origin[1]:"all_streams"]["protocol"==this.origin[0]?this.origin[1]:"all_protocols"][this.datatype];return this.data=a}},cpuload:{label:"CPU use",yaxistype:"percentage",basecolor:[237,194,64],cores:1,getdata:function(){var a=!1,b;for(b in this.data)this.data[b][0]<1E3*(mist.data.config.time-600)&&(a=b);!1!==a&&this.data.splice(0,Number(a)+1);this.data.push([1E3*mist.data.config.time,
|
||||
mist.data.capabilities.cpu_use/10]);return this.data}},memload:{label:"Memory load",yaxistype:"percentage",basecolor:[175,216,248],getdata:function(){var a=!1,b;for(b in this.data)this.data[b][0]<1E3*(mist.data.config.time-600)&&(a=b);!1!==a&&this.data.splice(0,Number(a)+1);this.data.push([1E3*mist.data.config.time,mist.data.capabilities.load.memory]);return this.data}},clients:{label:"Connections",basecolor:[203,75,75]},upbps:{label:"Bandwidth up",yaxistype:"bytespersec",basecolor:[77,167,77]},downbps:{label:"Bandwidth down",
|
||||
yaxistype:"bytespersec",basecolor:[148,64,237]}}},yaxes:{percentage:{name:"percentage",color:"black",tickColor:0,tickDecimals:0,tickFormatter:function(a){return UI.format.addUnit(UI.format.number(a),"%")},tickLength:0,min:0,max:100},amount:{name:"amount",color:"black",tickColor:0,tickDecimals:0,tickFormatter:function(a){return UI.format.number(a)},tickLength:0,min:0},bytespersec:{name:"bytespersec",color:"black",tickColor:0,tickDecimals:1,tickFormatter:function(a){return UI.format.bytes(a,!0)},tickLength:0,
|
||||
ticks:function(a){var b=0.3*Math.sqrt($(".graph").first().height()),b=(a.max-a.min)/b,c=Math.floor(Math.log(Math.abs(b))/Math.log(1024)),d=b/Math.pow(1024,c),e=-Math.floor(Math.log(d)/Math.LN10),g=a.tickDecimals;null!=g&&e>g&&(e=g);var m=Math.pow(10,-e),d=d/m,f;if(1.5>d)f=1;else if(3>d){if(f=2,2.25<d&&(null==g||e+1<=g))f=2.5,++e}else f=7.5>d?5:10;f=f*m*Math.pow(1024,c);null!=a.minTickSize&&f<a.minTickSize&&(f=a.minTickSize);a.delta=b;a.tickDecimals=Math.max(0,null!=g?g:e);a.tickSize=f;b=[];c=a.tickSize*
|
||||
Math.floor(a.min/a.tickSize);e=0;g=Number.NaN;do m=g,g=c+e*a.tickSize,b.push(g),++e;while(g<a.max&&g!=m);return b},min:0}},xaxes:{time:{name:"time",mode:"time",timezone:"browser",ticks:5}}},draggable:function(a){a.attr("draggable",!0);a.on("dragstart",function(a){$(this).css("opacity",0.4).data("dragstart",{click:{x:a.originalEvent.pageX,y:a.originalEvent.pageY},ele:{x:this.offsetLeft,y:this.offsetTop}})}).on("dragend",function(a){var c=$(this).data("dragstart"),d=c.ele.x-c.click.x+a.originalEvent.pageX,
|
||||
a=c.ele.y-c.click.y+a.originalEvent.pageY;$(this).css({opacity:1,top:a,left:d,right:"auto",bottom:"auto"})});a.parent().on("dragleave",function(){})},format:{time:function(a,b){var c=new Date(1E3*a),d=[];d.push(("0"+c.getHours()).slice(-2));d.push(("0"+c.getMinutes()).slice(-2));"short"!=b&&d.push(("0"+c.getSeconds()).slice(-2));return d.join(":")},date:function(a,b){var c=new Date(1E3*a),d="Sun Mon Tue Wed Thu Fri Sat".split(" "),e=[];"long"==b&&e.push(d[c.getDay()]);e.push(("0"+c.getDate()).slice(-2));
|
||||
e.push("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ")[c.getMonth()]);"short"!=b&&e.push(c.getFullYear());return e.join(" ")},dateTime:function(a,b){return UI.format.date(a,b)+", "+UI.format.time(a,b)},duration:function(a){var b=[0.001,1E3,60,60,24,7,1E9],c="ms sec min hr day week".split(" "),d={},e;for(e in c){var a=a/b[e],g=Math.round(a%b[Number(e)+1]);d[c[e]]=g;a-=g}var m;for(e=c.length-1;0<=e;e--)if(0<d[c[e]]){m=c[e];break}b=$("<span>");switch(m){case "week":b.append(UI.format.addUnit(d.week,
|
||||
"wks, ")).append(UI.format.addUnit(d.day,"days"));break;case "day":b.append(UI.format.addUnit(d.day,"days, ")).append(UI.format.addUnit(d.hr,"hrs"));break;default:b.append([("0"+d.hr).slice(-2),("0"+d.min).slice(-2),("0"+d.sec).slice(-2)+(d.ms?"."+d.ms:"")].join(":"))}return b[0].innerHTML},number:function(a){if(isNaN(Number(a))||0==a)return a;var b=Math.pow(10,3-Math.floor(Math.log(a)/Math.LN10)-1),a=Math.round(a*b)/b;if(1E4<a){number=a.toString().split(".");for(a=/(\d+)(\d{3})/;a.test(number[0]);)number[0]=
|
||||
number[0].replace(a,"$1 $2");a=number.join(".")}return a},status:function(a){var b=$("<span>");if("undefined"==typeof a.online)return b.text("Unknown, checking.."),"undefined"!=typeof a.error&&b.text(a.error),b;switch(a.online){case -1:b.text("Enabling");break;case 0:b.text("Unavailable").addClass("red");break;case 1:b.text("Active").addClass("green");break;case 2:b.text("Standby").addClass("orange");break;default:b.text(a.online)}"error"in a&&b.text(a.error);return b},capital:function(a){return a.charAt(0).toUpperCase()+
|
||||
a.substring(1)},addUnit:function(a,b){var c=$("<span>").html(a);c.append($("<span>").addClass("unit").html(b));return c[0].innerHTML},bytes:function(a,b){var c="bytes KiB MiB GiB TiB PiB".split(" ");if(0==a)unit=c[0];else{var d=Math.floor(Math.log(Math.abs(a))/Math.log(1024));0>d?unit=c[0]:(a/=Math.pow(1024,d),unit=c[d])}return UI.format.addUnit(UI.format.number(a),unit+(b?"/s":""))}},navto:function(a,b){var c=location.hash,d=c.split("@");d[0]=[mist.user.name,mist.user.host].join("&");d[1]=[a,b].join("&");
|
||||
"undefined"!=typeof screenlog&&screenlog.navto(d[1]);location.hash=d.join("@");location.hash==c&&$(window).trigger("hashchange")},showTab:function(a,b){var c=UI.elements.main;if(mist.user.loggedin&&!("ui_settings"in mist.data))c.html("Loading.."),mist.send(function(){UI.showTab(a,b)},{ui_settings:!0});else{var d=UI.elements.menu.removeClass("hide").find('.plain:contains("'+a+'")').closest(".button");0<d.length&&(UI.elements.menu.find(".button.active").removeClass("active"),d.addClass("active"));if("undefined"!=
|
||||
typeof mistvideo)for(var e in mistvideo)if("embedded"in mistvideo[e])for(var g in mistvideo[e].embedded)try{mistvideo[e].embedded[g].player.unload()}catch(m){}UI.interval.clear();c.html($("<h2>").text(a));switch(a){case "Login":if(mist.user.loggedin){UI.navto("Overview");return}UI.elements.menu.addClass("hide");UI.elements.connection.status.text("Disconnected").removeClass("green").addClass("red");c.append(UI.buildUI([{type:"help",help:"Please provide your account details.<br>You were asked to set these when MistController was started for the first time. If you did not yet set any account details, log in with your desired credentials to create a new account."},
|
||||
{label:"Host",help:"Url location of the MistServer API. Generally located at http://MistServerIP:4242/api","default":"http://localhost:4242/api",pointer:{main:mist.user,index:"host"}},{label:"Username",help:"Please enter your username here.",validate:["required"],pointer:{main:mist.user,index:"name"}},{label:"Password",type:"password",help:"Please enter your password here.",validate:["required"],pointer:{main:mist.user,index:"rawpassword"}},{type:"buttons",buttons:[{label:"Login",type:"save","function":function(){mist.user.password=
|
||||
p.append(l),("LTSonly"in d&&!mist.data.LTS||d.readonly)&&l.prop("disabled",!0),d.radioselect[c][2])p=$("<option>"),l.append(p),d.radioselect[c][2][g]instanceof Array?p.val(d.radioselect[c][2][g][0]).html(d.radioselect[c][2][g][1]):p.html(d.radioselect[c][2][g])}break;case "checklist":e=$("<div>").addClass("checkcontainer");$controls=$("<div>").addClass("controls");$checklist=$("<div>").addClass("checklist");e.append($checklist);for(c in d.checklist)"string"==typeof d.checklist[c]&&(d.checklist[c]=
|
||||
[d.checklist[c],d.checklist[c]]),$checklist.append($("<label>").text(d.checklist[c][1]).prepend($("<input>").attr("type","checkbox").attr("name",d.checklist[c][0])));break;case "DOMfield":e=d.DOMfield;break;default:e=$("<input>").attr("type","text")}e.addClass("field").data("opts",d);"pointer"in d&&e.attr("name",d.pointer.index);f.append(e);if("classes"in d)for(g in d.classes)e.addClass(d.classes[g]);"placeholder"in d&&e.attr("placeholder",d.placeholder);"default"in d&&e.attr("placeholder",d["default"]);
|
||||
"unit"in d&&f.append($("<span>").addClass("unit").html(d.unit));"readonly"in d&&(e.attr("readonly","readonly"),e.click(function(){$(this).select()}));"qrcode"in d&&f.append($("<span>").addClass("unit").html($("<button>").text("QR").on("keydown",function(a){a.stopPropagation()}).click(function(){var a=String($(this).closest(".field_container").find(".field").getval()),b=$("<div>").addClass("qrcode");UI.popup.show($("<span>").addClass("qr_container").append($("<p>").text(a)).append(b));b.qrcode({text:a,
|
||||
size:Math.min(b.width(),b.height())})})));"clipboard"in d&&document.queryCommandSupported("copy")&&f.append($("<span>").addClass("unit").html($("<button>").text("Copy").on("keydown",function(a){a.stopPropagation()}).click(function(){var a=String($(this).closest(".field_container").find(".field").getval()),b=document.createElement("textarea");b.value=a;document.body.appendChild(b);b.select();var c=false;try{c=document.execCommand("copy")}catch(d){}if(c){$(this).text("Copied to clipboard!");document.body.removeChild(b);
|
||||
var g=$(this);setTimeout(function(){g.text("Copy")},5E3)}else{document.body.removeChild(b);alert("Failed to copy:\n"+a)}})));"rows"in d&&e.attr("rows",d.rows);"LTSonly"in d&&!mist.data.LTS&&(f.addClass("LTSonly"),e.prop("disabled",!0));switch(d.type){case "browse":l=$("<div>").addClass("grouper").append(m);b.append(l);l=$("<button>").text("Browse").on("keydown",function(a){a.stopPropagation()});f.append(l);l.click(function(){function a(b){m.text("Loading..");mist.send(function(a){f.text(a.browse.path[0]);
|
||||
mist.data.LTS&&d.setval(a.browse.path[0]+"/");m.html(l.clone(true).text("..").attr("title","Folder up"));if(a.browse.subdirectories){a.browse.subdirectories.sort();for(var b in a.browse.subdirectories){var e=a.browse.subdirectories[b];m.append(l.clone(true).attr("title",f.text()+q+e).text(e))}}if(a.browse.files){a.browse.files.sort();for(b in a.browse.files){var e=a.browse.files[b],h=f.text()+q+e,e=$("<a>").text(e).addClass("file").attr("title",h);m.append(e);if(p){var n=true,u;for(u in p)if(typeof p[u]!=
|
||||
"undefined"&&mist.inputMatch(p[u],h)){n=false;break}n&&e.hide()}e.click(function(){var a=$(this).attr("title");d.setval(a).removeAttr("readonly").css("opacity",1);g.show();c.remove()})}}},{browse:b})}var b=$(this).closest(".grouper"),c=$("<div>").addClass("browse_container"),d=b.find(".field").attr("readonly","readonly").css("opacity",0.5),g=$(this),e=$("<button>").text("Stop browsing").click(function(){g.show();c.remove();d.removeAttr("readonly").css("opacity",1)}),f=$("<span>").addClass("field"),
|
||||
m=$("<div>").addClass("browse_contents"),l=$("<a>").addClass("folder"),p=d.data("filetypes");b.append(c);c.append($("<label>").addClass("UIelement").append($("<span>").addClass("label").text("Current folder:")).append($("<span>").addClass("field_container").append(f).append(e))).append(m);var q="/";mist.data.config.version.indexOf("indows")>-1&&(q="\\");l.click(function(){var b=f.text()+q+$(this).text();a(b)});b=d.getval();e=b.split("://");e.length>1&&(b=e[0]=="file"?e[1]:"");b=b.split(q);b.pop();
|
||||
b=b.join(q);g.hide();a(b)});break;case "geolimited":case "hostlimited":l={field:e};l.blackwhite=$("<select>").append($("<option>").val("-").text("Blacklist")).append($("<option>").val("+").text("Whitelist"));l.values=$("<span>").addClass("limit_value_list");switch(d.type){case "geolimited":l.prototype=$("<select>").append($("<option>").val("").text("[Select a country]"));for(c in UI.countrylist)l.prototype.append($("<option>").val(c).html(UI.countrylist[c]));break;case "hostlimited":l.prototype=$("<input>").attr("type",
|
||||
"text").attr("placeholder","type a host")}l.prototype.on("change keyup",function(){$(this).closest(".field_container").data("subUI").blackwhite.trigger("change")});l.blackwhite.change(function(){var a=$(this).closest(".field_container").data("subUI"),b=[],c=false;a.values.children().each(function(){c=$(this).val();c!=""?b.push(c):$(this).remove()});a.values.append(a.prototype.clone(true));b.length>0?a.field.val($(this).val()+b.join(" ")):a.field.val("");a.field.trigger("change")});"LTSonly"in d&&
|
||||
!mist.data.LTS&&(l.blackwhite.prop("disabled",!0),l.prototype.prop("disabled",!0));l.values.append(l.prototype.clone(!0));f.data("subUI",l).addClass("limit_list").append(l.blackwhite).append(l.values)}"pointer"in d&&(e.data("pointer",d.pointer).addClass("isSetting"),l=d.pointer.main[d.pointer.index],"undefined"!=l&&e.setval(l));"value"in d&&e.setval(d.value);if("datalist"in d)for(c in l="datalist_"+c+MD5(e[0].outerHTML),e.attr("list",l),l=$("<datalist>").attr("id",l),f.append(l),d.datalist)l.append($("<option>").val(d.datalist[c]));
|
||||
f=$("<span>").addClass("help_container");m.append(f);"help"in d&&(f.append($("<span>").addClass("ih_balloon").html(d.help)),e.on("focus mouseover",function(){$(this).closest("label").addClass("active")}).on("blur mouseout",function(){$(this).closest("label").removeClass("active")}));if("validate"in d){m=[];for(g in d.validate){l=d.validate[g];if("function"!=typeof l)switch(l){case "required":l=function(a){return a==""?{msg:"This is a required field.",classes:["red"]}:false};break;case "int":l=function(a,
|
||||
b){var c=$(b).data("opts");if(!$(b)[0].validity.valid){var d=[];"min"in c&&d.push(" greater than or equal to "+c.min);"max"in c&&d.push(" smaller than or equal to "+c.max);return{msg:"Please enter an integer"+d.join(" and")+".",classes:["red"]}}if(parseInt(Number(a))!=a)return{msg:"Please enter an integer.",classes:["red"]}};break;case "streamname":l=function(a,b){if(!isNaN(a.charAt(0)))return{msg:"The first character may not be a number.",classes:["red"]};if(a.toLowerCase()!=a)return{msg:"Uppercase letters are not allowed.",
|
||||
classes:["red"]};if(a.replace(/[^\da-z_]/g,"")!=a)return{msg:"Special characters (except for underscores) are not allowed.",classes:["red"]};if("streams"in mist.data&&a in mist.data.streams&&$(b).data("pointer").main.name!=a)return{msg:"This streamname already exists.<br>If you want to edit an existing stream, please click edit on the the streams tab.",classes:["red"]}};break;default:l=function(){}}m.push(l)}e.data("validate_functions",m).data("help_container",f).data("validate",function(a,b){var c=
|
||||
$(a).getval(),d=$(a).data("validate_functions"),e=$(a).data("help_container");e.find(".err_balloon").remove();for(var g in d){var f=d[g](c,a);if(f){$err=$("<span>").addClass("err_balloon").html(f.msg);for(var m in f.classes)$err.addClass(f.classes[m]);e.prepend($err);b&&$(a).focus();return true}}return false}).addClass("hasValidate").on("change keyup",function(){$(this).data("validate")($(this))});""!=e.getval()&&e.trigger("change")}"function"in d&&(e.on("change keyup",d["function"]),e.trigger("change"))}}b.on("keydown",
|
||||
function(a){switch(a.which){case 13:$(this).find("button.save").first().trigger("click");break;case 27:$(this).find("button.cancel").first().trigger("click")}});return b},buildVheaderTable:function(a){var b=$("<table>").css("margin","0.2em"),c=$("<tr>").addClass("header").append($("<td>").addClass("vheader").attr("rowspan",a.labels.length+1).append($("<span>").text(a.vheader))),d=[];c.append($("<td>"));for(var e in a.labels)d.push($("<tr>").append($("<td>").html(""==a.labels[e]?" ":a.labels[e]+
|
||||
":")));for(var g in a.content)for(e in c.append($("<td>").html(a.content[g].header)),a.content[g].body)d[e].append($("<td>").html(a.content[g].body[e]));b.append($("<tbody>").append(c).append(d));return b},plot:{addGraph:function(a,b){var c={id:a.id,xaxis:a.xaxis,datasets:[],elements:{cont:$("<div>").addClass("graph"),plot:$("<div>").addClass("plot"),legend:$("<div>").addClass("legend").attr("draggable","true")}};UI.draggable(c.elements.legend);c.elements.cont.append(c.elements.plot).append(c.elements.legend);
|
||||
b.append(c.elements.cont);return c},go:function(a){if(!(1>Object.keys(a).length)){var b={totals:[],clients:[]},c;for(c in a)for(var d in a[c].datasets){var e=a[c].datasets[d];switch(e.datatype){case "clients":case "upbps":case "downbps":switch(e.origin[0]){case "total":b.totals.push({fields:[e.datatype],end:-15});break;case "stream":b.totals.push({fields:[e.datatype],streams:[e.origin[1]],end:-15});break;case "protocol":b.totals.push({fields:[e.datatype],protocols:[e.origin[1]],end:-15})}break;case "cpuload":case "memload":b.capabilities=
|
||||
{}}}0==b.totals.length&&delete b.totals;0==b.clients.length&&delete b.clients;mist.send(function(){for(var b in a){var c=a[b];if(1>c.datasets.length){c.elements.plot.html("");c.elements.legend.html("");break}switch(c.xaxis){case "time":var d=[];c.yaxes={};var e=[],p;for(p in c.datasets){var l=c.datasets[p];l.display&&(l.getdata(),l.yaxistype in c.yaxes||(d.push(UI.plot.yaxes[l.yaxistype]),c.yaxes[l.yaxistype]=d.length),l.yaxis=c.yaxes[l.yaxistype],e.push(l))}d[0]&&(d[0].color=0);c.plot=$.plot(c.elements.plot,
|
||||
e,{legend:{show:!1},xaxis:UI.plot.xaxes[c.xaxis],yaxes:d,grid:{hoverable:!0,borderWidth:{top:0,right:0,bottom:1,left:1},color:"black",backgroundColor:{colors:["rgba(0,0,0,0)","rgba(0,0,0,0.025)"]}},crosshair:{mode:"x"}});d=$("<table>").addClass("legend-list").addClass("nolay").html($("<tr>").html($("<td>").html($("<h3>").text(c.id))).append($("<td>").css("padding-right","2em").css("text-align","right").html($("<span>").addClass("value")).append($("<button>").data("opts",c).text("X").addClass("close").click(function(){var b=
|
||||
$(this).data("opts");if(confirm("Are you sure you want to remove "+b.id+"?")){b.elements.cont.remove();var c=$(".graph_ids option:contains("+b.id+")"),d=c.parent();c.remove();UI.plot.del(b.id);delete a[b.id];d.trigger("change");UI.plot.go(a)}}))));c.elements.legend.html(d);var u=function(a){var b=c.elements.legend.find(".value"),d=1;if(typeof a=="undefined")b.eq(0).html("Latest:");else{var e=c.plot.getXAxes()[0],a=Math.min(e.max,a),a=Math.max(e.min,a);b.eq(0).html(UI.format.time(a/1E3))}for(var g in c.datasets){var f=
|
||||
" ";if(c.datasets[g].display){var e=UI.plot.yaxes[c.datasets[g].yaxistype].tickFormatter,h=c.datasets[g].data;if(a)for(var l in h){if(h[l][0]==a){f=e(h[l][1]);break}if(h[l][0]>a){if(l!=0){f=h[l];h=h[l-1];f=e(f[1]+(a-f[0])*(h[1]-f[1])/(h[0]-f[0]))}break}}else f=e(c.datasets[g].data[c.datasets[g].data.length-1][1])}b.eq(d).html(f);d++}};c.plot.getOptions();for(p in c.datasets)e=$("<input>").attr("type","checkbox").data("index",p).data("graph",c).click(function(){var a=$(this).data("graph");$(this).is(":checked")?
|
||||
a.datasets[$(this).data("index")].display=true:a.datasets[$(this).data("index")].display=false;var b={};b[a.id]=a;UI.plot.go(b)}),c.datasets[p].display&&e.attr("checked","checked"),d.append($("<tr>").html($("<td>").html($("<label>").html(e).append($("<div>").addClass("series-color").css("background-color",c.datasets[p].color)).append(c.datasets[p].label))).append($("<td>").css("padding-right","2em").css("text-align","right").html($("<span>").addClass("value")).append($("<button>").text("X").addClass("close").data("index",
|
||||
p).data("graph",c).click(function(){var b=$(this).data("index"),c=$(this).data("graph");if(confirm("Are you sure you want to remove "+c.datasets[b].label+" from "+c.id+"?")){c.datasets.splice(b,1);if(c.datasets.length==0){c.elements.cont.remove();var b=$(".graph_ids option:contains("+c.id+")"),d=b.parent();b.remove();d.trigger("change");UI.plot.del(c.id);delete a[c.id];UI.plot.go(a)}else{UI.plot.save(c);b={};b[c.id]=c;UI.plot.go(b)}}}))));u();var h=!1;c.elements.plot.on("plothover",function(a,b,c){if(b.x!=
|
||||
h){u(b.x);h=b.x}if(c){a=$("<span>").append($("<h3>").text(c.series.label).prepend($("<div>").addClass("series-color").css("background-color",c.series.color))).append($("<table>").addClass("nolay").html($("<tr>").html($("<td>").text("Time:")).append($("<td>").html(UI.format.dateTime(c.datapoint[0]/1E3,"long")))).append($("<tr>").html($("<td>").text("Value:")).append($("<td>").html(c.series.yaxis.tickFormatter(c.datapoint[1],c.series.yaxis)))));UI.tooltip.show(b,a.children())}else UI.tooltip.hide()}).on("mouseout",
|
||||
function(){u()})}}},b)}},save:function(a){var b={id:a.id,xaxis:a.xaxis,datasets:[]},c;for(c in a.datasets)b.datasets.push({origin:a.datasets[c].origin,datatype:a.datasets[c].datatype});a=mist.stored.get().graphs||{};a[b.id]=b;mist.stored.set("graphs",a)},del:function(a){var b=mist.stored.get().graphs||{};delete b[a];mist.stored.set("graphs",b)},datatype:{getOptions:function(a){var b=$.extend(!0,{},UI.plot.datatype.templates.general),c=$.extend(!0,{},UI.plot.datatype.templates[a.datatype]),a=$.extend(!0,
|
||||
c,a),a=$.extend(!0,b,a);switch(a.origin[0]){case "total":switch(a.datatype){case "cpuload":case "memload":break;default:a.label+=" (total)"}break;case "stream":case "protocol":a.label+=" ("+a.origin[1]+")"}var b=[],d;for(d in a.basecolor)c=a.basecolor[d],c+=50*(0.5-Math.random()),c=Math.round(c),c=Math.min(255,Math.max(0,c)),b.push(c);a.color="rgb("+b.join(",")+")";return a},templates:{general:{display:!0,datatype:"general",label:"",yaxistype:"amount",data:[],lines:{show:!0},points:{show:!1},getdata:function(){var a=
|
||||
mist.data.totals["stream"==this.origin[0]?this.origin[1]:"all_streams"]["protocol"==this.origin[0]?this.origin[1]:"all_protocols"][this.datatype];return this.data=a}},cpuload:{label:"CPU use",yaxistype:"percentage",basecolor:[237,194,64],cores:1,getdata:function(){var a=!1,b;for(b in this.data)this.data[b][0]<1E3*(mist.data.config.time-600)&&(a=b);!1!==a&&this.data.splice(0,Number(a)+1);this.data.push([1E3*mist.data.config.time,mist.data.capabilities.cpu_use/10]);return this.data}},memload:{label:"Memory load",
|
||||
yaxistype:"percentage",basecolor:[175,216,248],getdata:function(){var a=!1,b;for(b in this.data)this.data[b][0]<1E3*(mist.data.config.time-600)&&(a=b);!1!==a&&this.data.splice(0,Number(a)+1);this.data.push([1E3*mist.data.config.time,mist.data.capabilities.load.memory]);return this.data}},clients:{label:"Connections",basecolor:[203,75,75]},upbps:{label:"Bandwidth up",yaxistype:"bytespersec",basecolor:[77,167,77]},downbps:{label:"Bandwidth down",yaxistype:"bytespersec",basecolor:[148,64,237]}}},yaxes:{percentage:{name:"percentage",
|
||||
color:"black",tickColor:0,tickDecimals:0,tickFormatter:function(a){return UI.format.addUnit(UI.format.number(a),"%")},tickLength:0,min:0,max:100},amount:{name:"amount",color:"black",tickColor:0,tickDecimals:0,tickFormatter:function(a){return UI.format.number(a)},tickLength:0,min:0},bytespersec:{name:"bytespersec",color:"black",tickColor:0,tickDecimals:1,tickFormatter:function(a){return UI.format.bytes(a,!0)},tickLength:0,ticks:function(a){var b=0.3*Math.sqrt($(".graph").first().height()),b=(a.max-
|
||||
a.min)/b,c=Math.floor(Math.log(Math.abs(b))/Math.log(1024)),d=b/Math.pow(1024,c),e=-Math.floor(Math.log(d)/Math.LN10),g=a.tickDecimals;null!=g&&e>g&&(e=g);var m=Math.pow(10,-e),d=d/m,f;if(1.5>d)f=1;else if(3>d){if(f=2,2.25<d&&(null==g||e+1<=g))f=2.5,++e}else f=7.5>d?5:10;f=f*m*Math.pow(1024,c);null!=a.minTickSize&&f<a.minTickSize&&(f=a.minTickSize);a.delta=b;a.tickDecimals=Math.max(0,null!=g?g:e);a.tickSize=f;b=[];c=a.tickSize*Math.floor(a.min/a.tickSize);e=0;g=Number.NaN;do m=g,g=c+e*a.tickSize,
|
||||
b.push(g),++e;while(g<a.max&&g!=m);return b},min:0}},xaxes:{time:{name:"time",mode:"time",timezone:"browser",ticks:5}}},draggable:function(a){a.attr("draggable",!0);a.on("dragstart",function(a){$(this).css("opacity",0.4).data("dragstart",{click:{x:a.originalEvent.pageX,y:a.originalEvent.pageY},ele:{x:this.offsetLeft,y:this.offsetTop}})}).on("dragend",function(a){var c=$(this).data("dragstart"),d=c.ele.x-c.click.x+a.originalEvent.pageX,a=c.ele.y-c.click.y+a.originalEvent.pageY;$(this).css({opacity:1,
|
||||
top:a,left:d,right:"auto",bottom:"auto"})});a.parent().on("dragleave",function(){})},format:{time:function(a,b){var c=new Date(1E3*a),d=[];d.push(("0"+c.getHours()).slice(-2));d.push(("0"+c.getMinutes()).slice(-2));"short"!=b&&d.push(("0"+c.getSeconds()).slice(-2));return d.join(":")},date:function(a,b){var c=new Date(1E3*a),d="Sun Mon Tue Wed Thu Fri Sat".split(" "),e=[];"long"==b&&e.push(d[c.getDay()]);e.push(("0"+c.getDate()).slice(-2));e.push("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ")[c.getMonth()]);
|
||||
"short"!=b&&e.push(c.getFullYear());return e.join(" ")},dateTime:function(a,b){return UI.format.date(a,b)+", "+UI.format.time(a,b)},duration:function(a){var b=[0.001,1E3,60,60,24,7,1E9],c="ms sec min hr day week".split(" "),d={},e;for(e in c){var a=a/b[e],g=Math.round(a%b[Number(e)+1]);d[c[e]]=g;a-=g}var m;for(e=c.length-1;0<=e;e--)if(0<d[c[e]]){m=c[e];break}b=$("<span>");switch(m){case "week":b.append(UI.format.addUnit(d.week,"wks, ")).append(UI.format.addUnit(d.day,"days"));break;case "day":b.append(UI.format.addUnit(d.day,
|
||||
"days, ")).append(UI.format.addUnit(d.hr,"hrs"));break;default:b.append([("0"+d.hr).slice(-2),("0"+d.min).slice(-2),("0"+d.sec).slice(-2)+(d.ms?"."+d.ms:"")].join(":"))}return b[0].innerHTML},number:function(a){if(isNaN(Number(a))||0==a)return a;var b=Math.pow(10,3-Math.floor(Math.log(a)/Math.LN10)-1),a=Math.round(a*b)/b;if(1E4<a){number=a.toString().split(".");for(a=/(\d+)(\d{3})/;a.test(number[0]);)number[0]=number[0].replace(a,"$1 $2");a=number.join(".")}return a},status:function(a){var b=$("<span>");
|
||||
if("undefined"==typeof a.online)return b.text("Unknown, checking.."),"undefined"!=typeof a.error&&b.text(a.error),b;switch(a.online){case -1:b.text("Enabling");break;case 0:b.text("Unavailable").addClass("red");break;case 1:b.text("Active").addClass("green");break;case 2:b.text("Standby").addClass("orange");break;default:b.text(a.online)}"error"in a&&b.text(a.error);return b},capital:function(a){return a.charAt(0).toUpperCase()+a.substring(1)},addUnit:function(a,b){var c=$("<span>").html(a);c.append($("<span>").addClass("unit").html(b));
|
||||
return c[0].innerHTML},bytes:function(a,b){var c="bytes KiB MiB GiB TiB PiB".split(" ");if(0==a)unit=c[0];else{var d=Math.floor(Math.log(Math.abs(a))/Math.log(1024));0>d?unit=c[0]:(a/=Math.pow(1024,d),unit=c[d])}return UI.format.addUnit(UI.format.number(a),unit+(b?"/s":""))}},navto:function(a,b){var c=location.hash,d=c.split("@");d[0]=[mist.user.name,mist.user.host].join("&");d[1]=[a,b].join("&");"undefined"!=typeof screenlog&&screenlog.navto(d[1]);location.hash=d.join("@");location.hash==c&&$(window).trigger("hashchange")},
|
||||
showTab:function(a,b){var c=UI.elements.main;if(mist.user.loggedin&&!("ui_settings"in mist.data))c.html("Loading.."),mist.send(function(){UI.showTab(a,b)},{ui_settings:!0});else{var d=UI.elements.menu.removeClass("hide").find('.plain:contains("'+a+'")').closest(".button");0<d.length&&(UI.elements.menu.find(".button.active").removeClass("active"),d.addClass("active"));if("undefined"!=typeof mistvideo)for(var e in mistvideo)if("embedded"in mistvideo[e])for(var g in mistvideo[e].embedded)try{mistvideo[e].embedded[g].player.unload()}catch(m){}UI.interval.clear();
|
||||
c.html($("<h2>").text(a));switch(a){case "Login":if(mist.user.loggedin){UI.navto("Overview");return}UI.elements.menu.addClass("hide");UI.elements.connection.status.text("Disconnected").removeClass("green").addClass("red");c.append(UI.buildUI([{type:"help",help:"Please provide your account details.<br>You were asked to set these when MistController was started for the first time. If you did not yet set any account details, log in with your desired credentials to create a new account."},{label:"Host",
|
||||
help:"Url location of the MistServer API. Generally located at http://MistServerIP:4242/api","default":"http://localhost:4242/api",pointer:{main:mist.user,index:"host"}},{label:"Username",help:"Please enter your username here.",validate:["required"],pointer:{main:mist.user,index:"name"}},{label:"Password",type:"password",help:"Please enter your password here.",validate:["required"],pointer:{main:mist.user,index:"rawpassword"}},{type:"buttons",buttons:[{label:"Login",type:"save","function":function(){mist.user.password=
|
||||
MD5(mist.user.rawpassword);delete mist.user.rawpassword;mist.send(function(){UI.navto("Overview")})}}]}]));break;case "Create a new account":UI.elements.menu.addClass("hide");c.append($("<p>").text("No account has been created yet in the MistServer at ").append($("<i>").text(mist.user.host)).append("."));c.append(UI.buildUI([{type:"buttons",buttons:[{label:"Select other host",type:"cancel",css:{"float":"left"},"function":function(){UI.navto("Login")}}]},{type:"custom",custom:$("<br>")},{label:"Desired username",
|
||||
type:"str",validate:["required"],help:"Enter your desired username. In the future, you will need this to access the Management Interface.",pointer:{main:mist.user,index:"name"}},{label:"Desired password",type:"password",validate:["required",function(a,b){$(".match_password").not($(b)).trigger("change");return false}],help:"Enter your desired password. In the future, you will need this to access the Management Interface.",pointer:{main:mist.user,index:"rawpassword"},classes:["match_password"]},{label:"Repeat password",
|
||||
type:"password",validate:["required",function(a,b){return a!=$(".match_password").not($(b)).val()?{msg:'The fields "Desired password" and "Repeat password" do not match.',classes:["red"]}:false}],help:"Repeat your desired password.",classes:["match_password"]},{type:"buttons",buttons:[{type:"save",label:"Create new account","function":function(){mist.send(function(){UI.navto("Account created")},{authorize:{new_username:mist.user.name,new_password:mist.user.rawpassword}});mist.user.password=MD5(mist.user.rawpassword);
|
||||
delete mist.user.rawpassword}}]}]));break;case "Account created":UI.elements.menu.addClass("hide");c.append($("<p>").text("Your account has been created succesfully.")).append(UI.buildUI([{type:"text",text:"Would you like to enable all (currently) available protocols with their default settings?"},{type:"buttons",buttons:[{label:"Enable protocols",type:"save","function":function(){if(mist.data.config.protocols)c.append("Unable to enable all protocols as protocol settings already exist.<br>");else{c.append("Retrieving available protocols..<br>");
|
||||
mist.send(function(a){var b=[],d;for(d in a.capabilities.connectors)if(a.capabilities.connectors[d].required)c.append('Could not enable protocol "'+d+'" because it has required settings.<br>');else{b.push({connector:d});c.append('Enabled protocol "'+d+'".<br>')}c.append("Saving protocol settings..<br>");mist.send(function(){c.append("Protocols enabled. Redirecting..");setTimeout(function(){UI.navto("Overview")},5E3)},{config:{protocols:b}})},{capabilities:true})}}},{label:"Skip",type:"cancel","function":function(){UI.navto("Overview")}}]}]));
|
||||
break;case "Overview":var f=$("<span>").text("Loading.."),q=$("<span>"),p=$("<span>").addClass("logs"),l=$("<span>"),u=$("<span>"),h=$("<span>"),i=$("<span>");c.append(UI.buildUI([{type:"help",help:"You can find most basic information about your MistServer here.<br>You can also set the debug level and force a save to the config.json file that MistServer uses to save your settings. "},{type:"span",label:"Version",pointer:{main:mist.data.config,index:"version"}},{type:"span",label:"Version check",value:f,
|
||||
LTSonly:!0},{type:"span",label:"Server time",value:u},{type:"span",label:"Configured streams",value:mist.data.streams?Object.keys(mist.data.streams).length:0},{type:"span",label:"Active streams",value:q},{type:"span",label:"Current connections",value:l},{type:"span",label:"Enabled protocols",value:h},{type:"span",label:"Disabled protocols",value:i},{type:"span",label:"Recent problems",value:p},$("<br>"),{type:"str",label:"Human readable name",pointer:{main:mist.data.config,index:"name"},help:"You can name your MistServer here for personal use. You'll still need to set host name within your network yourself."},
|
||||
{type:"debug",label:"Debug level",pointer:{main:mist.data.config,index:"debug"},help:"You can set the amount of debug information MistServer saves in the log. A full reboot of MistServer is required before some components of MistServer can post debug information."},{type:"checkbox",label:"Force configurations save",pointer:{main:mist.data,index:"save"},help:"Tick the box in order to force an immediate save to the config.json MistServer uses to save your settings. Saving will otherwise happen upon closing MistServer. Don't forget to press save after ticking the box."},
|
||||
{type:"buttons",buttons:[{type:"save",label:"Save","function":function(){var a={config:mist.data.config};if(mist.data.save)a.save=mist.data.save;mist.send(function(){UI.navto("Overview")},a)}}]}]));if(mist.data.LTS){var k=function(){var a=mist.stored.get().update||{};"uptodate"in a?a.error?f.addClass("red").text(a.error):a.uptodate?f.text("Your version is up to date.").addClass("green"):f.addClass("red").text("Version outdated!").append($("<button>").text("Update").css({"font-size":"1em","margin-left":"1em"}).click(function(){if(confirm("Are you sure you want to execute a rolling update?")){f.addClass("orange").removeClass("red").text("Rolling update command sent..");
|
||||
mist.stored.del("update");mist.send(function(){UI.navto("Overview")},{autoupdate:true})}})):f.text("Unknown")};if(!mist.stored.get().update||36E5<(new Date).getTime()-mist.stored.get().update.lastchecked){var j=mist.stored.get().update||{};j.lastchecked=(new Date).getTime();mist.send(function(a){mist.stored.set("update",$.extend(true,j,a.update));k()},{checkupdate:!0})}else k()}else f.text("");g=function(){var a={totals:{fields:["clients"],start:-10},active_streams:true};if(!("cabailities"in mist.data))a.capabilities=
|
||||
true;mist.send(function(){ga()},a)};var ga=function(){q.text("active_streams"in mist.data?mist.data.active_streams?mist.data.active_streams.length:0:"?");if("totals"in mist.data&&"all_streams"in mist.data.totals)var a=mist.data.totals.all_streams.all_protocols.clients,a=a.length?UI.format.number(a[a.length-1][1]):0;else a="Loading..";l.text(a);u.text(UI.format.dateTime(mist.data.config.time,"long"));p.html("");var a=0,b;for(b in mist.data.log){var c=mist.data.log[b];if(["FAIL","ERROR"].indexOf(c[1])>
|
||||
-1){a++;var d=$("<span>").addClass("content").addClass("red"),e=c[2].split("|");for(b in e)d.append($("<span>").text(e[b]));p.append($("<div>").append($("<span>").append(UI.format.time(c[0]))).append(d));if(a==5)break}}a==0&&p.html("None.");a=[];c=[];for(b in mist.data.config.protocols){d=mist.data.config.protocols[b];a.indexOf(d.connector)>-1||a.push(d.connector)}h.text(a.length?a.join(", "):"None.");if("capabilities"in mist.data){for(b in mist.data.capabilities.connectors)a.indexOf(b)==-1&&c.push(b);
|
||||
i.text(c.length?c.join(", "):"None.")}else i.text("Loading..")};g();ga();UI.interval.set(g,3E4);break;case "Protocols":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a)},{capabilities:!0});c.append("Loading..");return}var z=$("<tbody>");c.append(UI.buildUI([{type:"help",help:"You can find an overview of all the protocols and their relevant information here. You can add, edit or delete protocols."}])).append($("<button>").text("Delete all protocols").click(function(){if(confirm("Are you sure you want to delete all currently configured protocols?")){mist.data.config.protocols=
|
||||
LTSonly:!0},{type:"span",label:"Server time",value:u},{type:"span",label:"Licensed to","default":"unknown",pointer:{main:mist.data.config.license,index:"user"},LTSonly:!0},{type:"span",label:"Configured streams",value:mist.data.streams?Object.keys(mist.data.streams).length:0},{type:"span",label:"Active streams",value:q},{type:"span",label:"Current connections",value:l},{type:"span",label:"Enabled protocols",value:h},{type:"span",label:"Disabled protocols",value:i},{type:"span",label:"Recent problems",
|
||||
value:p},$("<br>"),{type:"str",label:"Human readable name",pointer:{main:mist.data.config,index:"name"},help:"You can name your MistServer here for personal use. You'll still need to set host name within your network yourself."},{type:"debug",label:"Debug level",pointer:{main:mist.data.config,index:"debug"},help:"You can set the amount of debug information MistServer saves in the log. A full reboot of MistServer is required before some components of MistServer can post debug information."},{type:"checkbox",
|
||||
label:"Force configurations save",pointer:{main:mist.data,index:"save"},help:"Tick the box in order to force an immediate save to the config.json MistServer uses to save your settings. Saving will otherwise happen upon closing MistServer. Don't forget to press save after ticking the box."},{type:"buttons",buttons:[{type:"save",label:"Save","function":function(){var a={config:mist.data.config};if(mist.data.save)a.save=mist.data.save;mist.send(function(){UI.navto("Overview")},a)}}]}]));if(mist.data.LTS){var k=
|
||||
function(a){"uptodate"in a?a.error?f.addClass("red").text(a.error):a.uptodate?f.text("Your version is up to date.").addClass("green"):f.addClass("red").text("Version outdated!").append($("<button>").text("Update").css({"font-size":"1em","margin-left":"1em"}).click(function(){if(confirm("Are you sure you want to execute a rolling update?")){f.addClass("orange").removeClass("red").text("Rolling update command sent..");mist.stored.del("update");mist.send(function(){UI.navto("Overview")},{autoupdate:true})}})):
|
||||
f.text("Unknown")};if(!mist.stored.get().update||36E5<(new Date).getTime()-mist.stored.get().update.lastchecked){var j={};j.lastchecked=(new Date).getTime();mist.send(function(a){mist.stored.set("update",j);k(a.update)},{checkupdate:!0})}else mist.send(function(a){k(a.update)},{update:!0})}else f.text("");g=function(){var a={totals:{fields:["clients"],start:-10},active_streams:true};if(!("cabailities"in mist.data))a.capabilities=true;mist.send(function(){ga()},a)};var ga=function(){q.text("active_streams"in
|
||||
mist.data?mist.data.active_streams?mist.data.active_streams.length:0:"?");if("totals"in mist.data&&"all_streams"in mist.data.totals)var a=mist.data.totals.all_streams.all_protocols.clients,a=a.length?UI.format.number(a[a.length-1][1]):0;else a="Loading..";l.text(a);u.text(UI.format.dateTime(mist.data.config.time,"long"));p.html("");var a=0,b;for(b in mist.data.log){var c=mist.data.log[b];if(["FAIL","ERROR"].indexOf(c[1])>-1){a++;var d=$("<span>").addClass("content").addClass("red"),e=c[2].split("|");
|
||||
for(b in e)d.append($("<span>").text(e[b]));p.append($("<div>").append($("<span>").append(UI.format.time(c[0]))).append(d));if(a==5)break}}a==0&&p.html("None.");a=[];c=[];for(b in mist.data.config.protocols){d=mist.data.config.protocols[b];a.indexOf(d.connector)>-1||a.push(d.connector)}h.text(a.length?a.join(", "):"None.");if("capabilities"in mist.data){for(b in mist.data.capabilities.connectors)a.indexOf(b)==-1&&c.push(b);i.text(c.length?c.join(", "):"None.")}else i.text("Loading..")};g();ga();UI.interval.set(g,
|
||||
3E4);break;case "Protocols":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a)},{capabilities:!0});c.append("Loading..");return}var z=$("<tbody>");c.append(UI.buildUI([{type:"help",help:"You can find an overview of all the protocols and their relevant information here. You can add, edit or delete protocols."}])).append($("<button>").text("Delete all protocols").click(function(){if(confirm("Are you sure you want to delete all currently configured protocols?")){mist.data.config.protocols=
|
||||
[];mist.send(function(){UI.navto("Protocols")},{config:mist.data.config})}})).append($("<button>").text("Enable default protocols").click(function(){var a=Object.keys(mist.data.capabilities.connectors),b;for(b in mist.data.config.protocols){var c=a.indexOf(mist.data.config.protocols[b].connector);c>-1&&a.splice(c,1)}var d=[];for(b in a)(!("required"in mist.data.capabilities.connectors[a[b]])||Object.keys(mist.data.capabilities.connectors[a[b]].required).length==0)&&d.push(a[b]);c="Click OK to enable disabled protocols with their default settings:\n ";
|
||||
c=d.length?c+d.join(", "):c+"None.";if(d.length!=a.length){a=a.filter(function(a){return d.indexOf(a)<0});c=c+("\n\nThe following protocols can only be set manually:\n "+a.join(", "))}if(confirm(c)&&d.length){for(b in d)mist.data.config.protocols.push({connector:d[b]});mist.send(function(){UI.navto("Protocols")},{config:mist.data.config})}})).append("<br>").append($("<button>").text("New protocol").click(function(){UI.navto("Edit Protocol")}).css("clear","both")).append($("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Protocol")).append($("<th>").text("Status")).append($("<th>").text("Settings")).append($("<th>")))).append(z));
|
||||
var K=function(){function a(b){var c=mist.data.capabilities.connectors[b.connector];if(!c)return"";var d=[],e=["required","optional"],g;for(g in e)for(var t in c[e[g]])b[t]&&b[t]!=""?d.push(t+": "+b[t]):c[e[g]][t]["default"]&&d.push(t+": "+c[e[g]][t]["default"]);return $("<span>").addClass("description").text(d.join(", "))}z.html("");for(var b in mist.data.config.protocols){var c=mist.data.config.protocols[b];z.append($("<tr>").data("index",b).append($("<td>").text(c.connector)).append($("<td>").html(UI.format.status(c))).append($("<td>").html(a(c))).append($("<td>").css("text-align",
|
||||
|
|
69
lsp/mist.js
69
lsp/mist.js
|
@ -600,8 +600,7 @@ var UI = {
|
|||
case 'checklist':
|
||||
$field = $('<div>').addClass('checkcontainer');
|
||||
$controls = $('<div>').addClass('controls');
|
||||
$checklist = $('<div>').addClass('checklist');
|
||||
$field.append($controls).append($checklist);
|
||||
/* All tends to be confusing: disable it for now
|
||||
$controls.append(
|
||||
$('<label>').text('All').prepend(
|
||||
$('<input>').attr('type','checkbox').click(function(){
|
||||
|
@ -614,6 +613,10 @@ var UI = {
|
|||
})
|
||||
)
|
||||
);
|
||||
$field.append($controls);
|
||||
*/
|
||||
$checklist = $('<div>').addClass('checklist');
|
||||
$field.append($checklist);
|
||||
for (var i in e.checklist) {
|
||||
if (typeof e.checklist[i] == 'string') {
|
||||
e.checklist[i] = [e.checklist[i], e.checklist[i]];
|
||||
|
@ -1388,7 +1391,6 @@ var UI = {
|
|||
|
||||
break;
|
||||
case 'coords':
|
||||
//TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2067,6 +2069,15 @@ var UI = {
|
|||
type: 'span',
|
||||
label: 'Server time',
|
||||
value: $servertime
|
||||
},{
|
||||
type: 'span',
|
||||
label: 'Licensed to',
|
||||
'default': 'unknown',
|
||||
pointer: {
|
||||
main: mist.data.config.license,
|
||||
index: 'user'
|
||||
},
|
||||
LTSonly: true
|
||||
},{
|
||||
type: 'span',
|
||||
label: 'Configured streams',
|
||||
|
@ -2133,8 +2144,7 @@ var UI = {
|
|||
}
|
||||
]));
|
||||
if (mist.data.LTS) {
|
||||
function update_update() {
|
||||
var info = mist.stored.get().update || {};
|
||||
function update_update(info) {
|
||||
if (!('uptodate' in info)) {
|
||||
$versioncheck.text('Unknown');
|
||||
return;
|
||||
|
@ -2163,15 +2173,17 @@ var UI = {
|
|||
}
|
||||
|
||||
if ((!mist.stored.get().update) || ((new Date()).getTime()-mist.stored.get().update.lastchecked > 3600e3)) {
|
||||
var update = mist.stored.get().update || {};
|
||||
var update = {};
|
||||
update.lastchecked = (new Date()).getTime();
|
||||
mist.send(function(d){
|
||||
mist.stored.set('update',$.extend(true,update,d.update));
|
||||
update_update();
|
||||
mist.stored.set('update',update);
|
||||
update_update(d.update);
|
||||
},{checkupdate: true});
|
||||
}
|
||||
else {
|
||||
update_update();
|
||||
mist.send(function(d){
|
||||
update_update(d.update);
|
||||
},{update: true});
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2620,6 +2632,33 @@ var UI = {
|
|||
$main.append(
|
||||
$('<span>').addClass('description').text('Choose a stream below.')
|
||||
).append($shortcuts);
|
||||
|
||||
//if there is a JPG output, add actual thumnails \o/
|
||||
var thumbnails = false;
|
||||
///\todo activate this code when the backend is ready
|
||||
/*
|
||||
if (UI.findOutput('JPG')) {
|
||||
var jpgport = false;
|
||||
//find the http port and make sure JPG is enabled
|
||||
for (var i in mist.data.config.protocols) {
|
||||
var protocol = mist.data.config.protocols[i];
|
||||
if ((protocol.connector == 'HTTP') || (protocol.connector == 'HTTP.exe')) {
|
||||
jpgport = (protocol.port ? ':'+protocol.port : ':8080');
|
||||
}
|
||||
if ((protocol.connector == 'JPG') || (protocol.connector == 'JPG.exe')) {
|
||||
thumbnails = true;
|
||||
}
|
||||
}
|
||||
if ((thumbnails) && (jpgport)) {
|
||||
//now we get to use it as a magical function wheee!
|
||||
jpgport = parseURL(mist.user.host).host+jpgport;
|
||||
thumbnails = function(streamname) {
|
||||
return 'http://'+jpgport+'/'+encodeURIComponent(streamname)+'.jpg';
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
for (var i in select) {
|
||||
var streamname = select[i];
|
||||
var source = '';
|
||||
|
@ -2649,6 +2688,17 @@ var UI = {
|
|||
UI.navto('Embed',$(this).closest('div').attr('data-stream'));
|
||||
});
|
||||
var $image = $('<span>').addClass('image');
|
||||
|
||||
if ((thumbnails) && (folders.indexOf(streamname) == -1)) {
|
||||
//there is a JPG output and this isn't a folder
|
||||
$image.append(
|
||||
$('<img>').attr('src',thumbnails(streamname)).error(function(){
|
||||
$(this).hide();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
//its a wildcard stream
|
||||
if (streamname.indexOf('+') > -1) {
|
||||
var streambits = streamname.split('+');
|
||||
source = mist.data.streams[streambits[0]].source+streambits[1];
|
||||
|
@ -2658,6 +2708,7 @@ var UI = {
|
|||
}
|
||||
else {
|
||||
source = mist.data.streams[streamname].source;
|
||||
//its a folder stream
|
||||
if (folders.indexOf(streamname) > -1) {
|
||||
$preview = '';
|
||||
$embed = '';
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace Mist {
|
|||
//capa["optional"]["wrappers"]["allowed"].append("polytrope"); //currently borked
|
||||
capa["optional"]["wrappers"]["allowed"].append("flash_strobe");
|
||||
capa["optional"]["wrappers"]["allowed"].append("silverlight");
|
||||
capa["optional"]["wrappers"]["allowed"].append("img");
|
||||
capa["optional"]["wrappers"]["option"] = "--wrappers";
|
||||
capa["optional"]["wrappers"]["short"] = "w";
|
||||
cfg->addConnectorOptions(8080, capa);
|
||||
|
@ -589,6 +590,11 @@ namespace Mist {
|
|||
response.append((char*)video_js, (size_t)video_js_len);
|
||||
used = true;
|
||||
}
|
||||
if (it->asStringRef() == "img"){
|
||||
#include "img.js.h"
|
||||
response.append((char*)img_js, (size_t)img_js_len);
|
||||
used = true;
|
||||
}
|
||||
if (!used) {
|
||||
WARN_MSG("Unknown player type: %s",it->asStringRef().c_str());
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue