Embed: Support for subtitles and metadata tracks over websocket

LSP: Preview tab: Show meta information for metadata tracks
LSP/embed: use new inclzero flag to receive sources that are enabled, but that don't currently have active tracks; and bugfix for metadata update for tracks not firing if sources have also changed
Embed: dashjs: disable stock subtitles unless activated
This commit is contained in:
Cat 2022-11-09 10:41:21 +01:00 committed by Thulinma
parent f3ba13d6bb
commit c337fff614
11 changed files with 514 additions and 85 deletions

File diff suppressed because one or more lines are too long

View file

@ -67,6 +67,10 @@ svg.icon .spin,svg.icon.spin{animation:mistvideo-spin 1.5s infinite linear;trans
.mistvideo{line-height:1.2;font-size:14.5px} .mistvideo{line-height:1.2;font-size:14.5px}
.mistvideo svg{margin:2.5px} .mistvideo svg{margin:2.5px}
.mistvideo-video{display:flex;align-items:center;justify-content:center} .mistvideo-video{display:flex;align-items:center;justify-content:center}
.mistvideo-subtitles{position:absolute;width:100%;height:100%;pointer-events:none;display:flex;align-items:flex-end;justify-content:center}
.mistvideo-subtitles>*{margin-bottom:.5em;padding:.1em .3em;text-align:center;background:rgba(0,0,0,.6);white-space:pre-wrap}
.mistvideo-subtitles>:empty{display:none}
.mistvideo[data-fullscreen] .mistvideo-subtitles{font-size:3vh}
.mistvideo-background{background-color:$background} .mistvideo-background{background-color:$background}
.mistvideo-totalTime:before{content:'/';margin:.2em} .mistvideo-totalTime:before{content:'/';margin:.2em}
.mistvideo-progress{padding:10px 0;margin:-10px 0;z-index:2} .mistvideo-progress{padding:10px 0;margin:-10px 0;z-index:2}

View file

@ -67,6 +67,10 @@ svg.icon .spin,svg.icon.spin{animation:mistvideo-spin 1.5s infinite linear;trans
.mistvideo{line-height:1.2;font-size:14.5px} .mistvideo{line-height:1.2;font-size:14.5px}
.mistvideo svg{margin:2.5px} .mistvideo svg{margin:2.5px}
.mistvideo-video{display:flex;align-items:center;justify-content:center} .mistvideo-video{display:flex;align-items:center;justify-content:center}
.mistvideo-subtitles{position:absolute;width:100%;height:100%;pointer-events:none;display:flex;align-items:flex-end;justify-content:center}
.mistvideo-subtitles>*{margin-bottom:.5em;padding:.1em .3em;text-align:center;background:rgba(0,0,0,.6);white-space:pre-wrap}
.mistvideo-subtitles>:empty{display:none}
.mistvideo[data-fullscreen] .mistvideo-subtitles{font-size:3vh}
.mistvideo-background{background-color:$background} .mistvideo-background{background-color:$background}
.mistvideo-totalTime:before{content:'/';margin:.2em} .mistvideo-totalTime:before{content:'/';margin:.2em}
.mistvideo-progress{padding:10px 0;margin:-10px 0;z-index:2} .mistvideo-progress{padding:10px 0;margin:-10px 0;z-index:2}

View file

@ -1 +1 @@
mistplayers.dashjs={name:"Dash.js player",mimes:["dash/video/mp4"],priority:MistUtil.object.keys(mistplayers).length+1,isMimeSupported:function(e){return MistUtil.array.indexOf(this.mimes,e)==-1?false:true},isBrowserSupported:function(e,t,i){if(location.protocol!=MistUtil.http.url.split(t.url).protocol){i.log("HTTP/HTTPS mismatch for this source");return false}if(location.protocol=="file:"){i.log("This source ("+e+") won't load if the page is run via file://");return false}if(!("MediaSource"in window)){return false}if(!MediaSource.isTypeSupported){return true}var r={};var a=false;for(var s in i.info.meta.tracks){if(i.info.meta.tracks[s].type=="meta"){if(i.info.meta.tracks[s].codec=="subtitle"){a=true}continue}if(!(i.info.meta.tracks[s].type in r)){r[i.info.meta.tracks[s].type]={}}r[i.info.meta.tracks[s].type][MistUtil.tracks.translateCodec(i.info.meta.tracks[s])]=1}var o=[];for(var n in r){var l=false;for(var f in r[n]){if(MediaSource.isTypeSupported('video/mp4;codecs="'+f+'"')){l=true;break}}if(l){o.push(n)}}if(a){for(var s in i.info.source){if(i.info.source[s].type=="html5/text/vtt"){o.push("subtitle");break}}}return o.length?o:false},player:function(){this.onreadylist=[]},scriptsrc:function(e){return e+"/dashjs.js"}};var p=mistplayers.dashjs.player;p.prototype=new MistPlayer;p.prototype.build=function(e,t){var i=this;this.onDashLoad=function(){if(e.destroyed){return}e.log("Building DashJS player..");var r=document.createElement("video");if("Proxy"in window){var a={get:{},set:{}};e.player.api=new Proxy(r,{get:function(e,t,i){if(t in a.get){return a.get[t].apply(e,arguments)}var r=e[t];if(typeof r==="function"){return function(){return r.apply(e,arguments)}}return r},set:function(e,t,i){if(t in a.set){return a.set[t].call(e,i)}return e[t]=i}});if(e.info.type=="live"){a.get.duration=function(){var t=0;if(this.buffered.length){t=this.buffered.end(this.buffered.length-1)}var i=((new Date).getTime()-e.player.api.lastProgress.getTime())*.001;return t+i+-1*e.player.api.liveOffset+45};a.set.currentTime=function(t){var i=t-e.player.api.duration;e.log("Seeking to "+MistUtil.format.time(t)+" ("+Math.round(i*-10)/10+"s from live)");e.video.currentTime=t};MistUtil.event.addListener(r,"progress",function(){e.player.api.lastProgress=new Date});e.player.api.lastProgress=new Date;e.player.api.liveOffset=0}}else{i.api=r}if(e.options.autoplay){r.setAttribute("autoplay","")}if(e.options.loop&&e.info.type!="live"){r.setAttribute("loop","")}if(e.options.poster){r.setAttribute("poster",e.options.poster)}if(e.options.muted){r.muted=true}if(e.options.controls=="stock"){r.setAttribute("controls","")}var s=dashjs.MediaPlayer().create();s.initialize(r,e.source.url,e.options.autoplay);i.dash=s;var o=["METRIC_ADDED","METRIC_UPDATED","METRIC_CHANGED","METRICS_CHANGED","FRAGMENT_LOADING_STARTED","FRAGMENT_LOADING_COMPLETED","LOG","PLAYBACK_TIME_UPDATED","PLAYBACK_PROGRESS"];for(var n in dashjs.MediaPlayer.events){if(o.indexOf(n)<0){i.dash.on(dashjs.MediaPlayer.events[n],function(t){e.log("Player event fired: "+t.type)})}}e.player.setSize=function(e){this.api.style.width=e.width+"px";this.api.style.height=e.height+"px"};e.player.api.setSource=function(t){e.player.dash.attachSource(t)};var l=false;i.dash.on("allTextTracksAdded",function(){l=true});e.player.api.setSubtitle=function(t){if(!l){var r=function(){e.player.api.setSubtitle(t);i.dash.off("allTextTracksAdded",r)};i.dash.on("allTextTracksAdded",r);return}if(!t){i.dash.enableText(false);return}var a=i.dash.getTracksFor("text");for(var s in a){var o="idx"in t?t.idx:t.trackid;if(a[s].id==o){i.dash.setTextTrack(s);if(!i.dash.isTextEnabled()){i.dash.enableText()}return true}}return false};MistUtil.event.addListener(r,"progress",function(t){if(e.container.getAttribute("data-loading")=="stalled"){e.container.removeAttribute("data-loading")}});i.api.unload=function(){i.dash.reset()};e.log("Built html");t(r)};if("dashjs"in window){this.onDashLoad()}else{var r=MistUtil.scripts.insert(e.urlappend(mistplayers.dashjs.scriptsrc(e.options.host)),{onerror:function(t){var i="Failed to load dashjs.js";if(t.message){i+=": "+t.message}e.showError(i)},onload:i.onDashLoad},e)}}; mistplayers.dashjs={name:"Dash.js player",mimes:["dash/video/mp4"],priority:MistUtil.object.keys(mistplayers).length+1,isMimeSupported:function(e){return MistUtil.array.indexOf(this.mimes,e)==-1?false:true},isBrowserSupported:function(e,t,i){if(location.protocol!=MistUtil.http.url.split(t.url).protocol){i.log("HTTP/HTTPS mismatch for this source");return false}if(location.protocol=="file:"){i.log("This source ("+e+") won't load if the page is run via file://");return false}if(!("MediaSource"in window)){return false}if(!MediaSource.isTypeSupported){return true}var r={};var a=false;for(var s in i.info.meta.tracks){if(i.info.meta.tracks[s].type=="meta"){if(i.info.meta.tracks[s].codec=="subtitle"){a=true}continue}if(!(i.info.meta.tracks[s].type in r)){r[i.info.meta.tracks[s].type]={}}r[i.info.meta.tracks[s].type][MistUtil.tracks.translateCodec(i.info.meta.tracks[s])]=1}var o=[];for(var n in r){var l=false;for(var f in r[n]){if(MediaSource.isTypeSupported('video/mp4;codecs="'+f+'"')){l=true;break}}if(l){o.push(n)}}if(a){for(var s in i.info.source){if(i.info.source[s].type=="html5/text/vtt"){o.push("subtitle");break}}}return o.length?o:false},player:function(){this.onreadylist=[]},scriptsrc:function(e){return e+"/dashjs.js"}};var p=mistplayers.dashjs.player;p.prototype=new MistPlayer;p.prototype.build=function(e,t){var i=this;this.onDashLoad=function(){if(e.destroyed){return}e.log("Building DashJS player..");var r=document.createElement("video");if("Proxy"in window){var a={get:{},set:{}};e.player.api=new Proxy(r,{get:function(e,t,i){if(t in a.get){return a.get[t].apply(e,arguments)}var r=e[t];if(typeof r==="function"){return function(){return r.apply(e,arguments)}}return r},set:function(e,t,i){if(t in a.set){return a.set[t].call(e,i)}return e[t]=i}});if(e.info.type=="live"){a.get.duration=function(){var t=0;if(this.buffered.length){t=this.buffered.end(this.buffered.length-1)}var i=((new Date).getTime()-e.player.api.lastProgress.getTime())*.001;return t+i+-1*e.player.api.liveOffset+45};a.set.currentTime=function(t){var i=t-e.player.api.duration;e.log("Seeking to "+MistUtil.format.time(t)+" ("+Math.round(i*-10)/10+"s from live)");e.video.currentTime=t};MistUtil.event.addListener(r,"progress",function(){e.player.api.lastProgress=new Date});e.player.api.lastProgress=new Date;e.player.api.liveOffset=0}}else{i.api=r}if(e.options.autoplay){r.setAttribute("autoplay","")}if(e.options.loop&&e.info.type!="live"){r.setAttribute("loop","")}if(e.options.poster){r.setAttribute("poster",e.options.poster)}if(e.options.muted){r.muted=true}if(e.options.controls=="stock"){r.setAttribute("controls","")}var s=dashjs.MediaPlayer().create();s.initialize(r,e.source.url,e.options.autoplay);i.dash=s;var o=["METRIC_ADDED","METRIC_UPDATED","METRIC_CHANGED","METRICS_CHANGED","FRAGMENT_LOADING_STARTED","FRAGMENT_LOADING_COMPLETED","LOG","PLAYBACK_TIME_UPDATED","PLAYBACK_PROGRESS"];for(var n in dashjs.MediaPlayer.events){if(o.indexOf(n)<0){i.dash.on(dashjs.MediaPlayer.events[n],function(t){e.log("Player event fired: "+t.type)})}}e.player.setSize=function(e){this.api.style.width=e.width+"px";this.api.style.height=e.height+"px"};e.player.api.setSource=function(t){e.player.dash.attachSource(t)};if(e.options.controls!="stock"){i.dash.updateSettings({streaming:{text:{defaultEnabled:false}}})}var l=false;i.dash.on("allTextTracksAdded",function(){l=true});e.player.api.setSubtitle=function(t){if(!l){var r=function(){e.player.api.setSubtitle(t);i.dash.off("allTextTracksAdded",r)};i.dash.on("allTextTracksAdded",r);return}if(!t){i.dash.enableText(false);return}var a=i.dash.getTracksFor("text");for(var s in a){var o="idx"in t?t.idx:t.trackid;if(a[s].id==o){i.dash.setTextTrack(s);if(!i.dash.isTextEnabled()){i.dash.enableText()}return true}}return false};MistUtil.event.addListener(r,"progress",function(t){if(e.container.getAttribute("data-loading")=="stalled"){e.container.removeAttribute("data-loading")}});i.api.unload=function(){i.dash.reset()};e.log("Built html");t(r)};if("dashjs"in window){this.onDashLoad()}else{var r=MistUtil.scripts.insert(e.urlappend(mistplayers.dashjs.scriptsrc(e.options.host)),{onerror:function(t){var i="Failed to load dashjs.js";if(t.message){i+=": "+t.message}e.showError(i)},onload:i.onDashLoad},e)}};

View file

@ -35,7 +35,8 @@ function MistVideo(streamName,options) {
maxheight: false, //no max height (apart from targets dimensions) maxheight: false, //no max height (apart from targets dimensions)
ABR_resize: true, //for supporting wrappers: when the player resizes, request a video track that matches the resolution best ABR_resize: true, //for supporting wrappers: when the player resizes, request a video track that matches the resolution best
ABR_bitrate: true, //for supporting wrappers: when there are playback issues, request a lower bitrate video track ABR_bitrate: true, //for supporting wrappers: when there are playback issues, request a lower bitrate video track
useDateTime: true, //when the unix timestamp of the stream is known, display the date/time useDateTime: true, //when the unix timestamp of the stream is known, display the date/time,
subscribeToMetaTrack: false, //pass [[track index,callback]]; the callback function will be called whenever the specified meta data track receives a message.
MistVideoObject: false//no reference object is passed MistVideoObject: false//no reference object is passed
},options); },options);
if (options.host) { options.host = MistUtil.http.url.sanitizeHost(options.host); } if (options.host) { options.host = MistUtil.http.url.sanitizeHost(options.host); }
@ -115,7 +116,6 @@ function MistVideo(streamName,options) {
this.log("A reloadDelay of more than an hour was set: assuming milliseconds were intended. ReloadDelay is now "+options.reloadDelay+"s"); this.log("A reloadDelay of more than an hour was set: assuming milliseconds were intended. ReloadDelay is now "+options.reloadDelay+"s");
} }
new MistSkin(this); new MistSkin(this);
this.checkCombo = function(options,quiet) { this.checkCombo = function(options,quiet) {
@ -664,6 +664,250 @@ function MistVideo(streamName,options) {
if (MistVideo.monitor) { MistVideo.monitor.reset(); } if (MistVideo.monitor) { MistVideo.monitor.reset(); }
}); });
} }
if ("currentTime" in MistVideo.player.api) {
var json_source = MistUtil.sources.find(MistVideo.info.source,{
type: "html5/text/javascript",
protocol: "ws"+(location.protocol.charAt(location.protocol.length-2) == "s" ? "s" : "")+":"
});
if (json_source) {
MistVideo.metaTrackSubscriptions = {
subscriptions: {},
socket: null,
listeners: {},
init: function(){
var me = this;
this.socket = new WebSocket(MistUtil.http.url.addParam(MistVideo.urlappend(json_source.url),{rate:1}));
me.send_queue = [];
me.checktimer = null;
me.s = function(obj){
if (me.socket.readyState == me.socket.OPEN) {
me.socket.send(JSON.stringify(obj));
return true;
}
if (me.socket.readyState >= me.socket.CLOSING) {
//reopen websocket
me.init();
}
//add message to queue
this.send_queue.push(obj);
};
var stayahead = 5; //ask MistServer to fastforward to stayahead seconds ahead, so we receive messages earlier
var isfarahead = false; //for rate limiting the 'pause when too far ahead'-function
me.socket.setTracks = function(){
me.s({type:"tracks",meta:MistUtil.object.keys(me.subscriptions).join(",")});
};
me.socket.onopen = function(){
MistVideo.log("Metadata socket opened");
me.socket.setTracks();
if (MistVideo.player.api.playbackRate != 1) { me.s({type:"set_speed",play_rate:MistVideo.player.api.playbackRate}); }
me.s({type:"seek",seek_time:Math.round(MistVideo.player.api.currentTime*1e3),ff_to:Math.round((MistVideo.player.api.currentTime+stayahead)*1e3)});
me.socket.addEventListener("message",function(e){
if (!e.data) { MistVideo.log("Subtitle websocket received empty message."); return; }
var message = JSON.parse(e.data);
if (!message) { MistVideo.log("Subtitle websocket received invalid message."); return; }
if (("time" in message) && ("track" in message) && ("data" in message)) {
if (message.track in me.subscriptions) {
//console.warn("received:",message.track,message.data);
me.subscriptions[message.track].buffer.push(message);
console.warn("received:",message.track,message.time*1e-3,"currentTime:",MistVideo.player.api.currentTime,"latency",Math.round(MistVideo.player.api.currentTime-message.time*1e-3),"bufferlength:",me.subscriptions[message.track].buffer.length,"timer:",!!me.checktimer);
if (!me.checktimer) {
me.check();
}
else {
var willCheckAt = MistVideo.timers.list[me.checktimer];
if (willCheckAt) {
var messageAt = (new Date()).getTime() + message.time - MistVideo.player.api.currentTime*1e3;
if (willCheckAt > messageAt) {
MistVideo.log("The metadata socket received a message that should be displayed sooner than the current check time; resetting");
MistVideo.timers.stop(me.checktimer);
me.checktimer = null;
me.check();
}
}
}
}
}
//per track, the messages should arrive in the correct order and we shouldn't need to do sorting
if ("type" in message) {
switch (message.type) {
case "on_time": {
if (!isfarahead && (message.data.current > (MistVideo.player.api.currentTime + stayahead*6)*1e3)) {
//the playing point for the metadata track is very far ahead of the player;
isfarahead = true;
me.s({type:"hold"});
MistVideo.log("Pausing metadata buffer because it is very far ahead, checking again in 5 seconds: "+message.data.current+" > "+MistVideo.player.api.currentTime*1e3)
MistVideo.timers.start(function(){
if (!MistVideo.player.api.paused) { me.s({type:"play"}); }
me.s({type:"fast_forward",ff_to:Math.round((MistVideo.player.api.currentTime+stayahead)*1e3)});
},5e3);
}
break;
}
case "seek": {
for (var i in me.subscriptions) {
me.subscriptions[i].buffer = [];
}
MistVideo.log("Cleared metadata buffer after completed seek");
if (me.checktimer) {
//there might be a timer going for some time in the future: stop it,
MistVideo.timers.stop(me.checktimer);
me.checktimer = null;
}
}
break;
}
}
});
me.socket.onclose = function(){
//dont me.init();, send function will reopen if needed instead
MistVideo.log("Metadata socket closed");
}
while (me.send_queue.length && (me.socket.readyState == me.socket.OPEN)) {
me.s(me.send_queue.shift());
}
};
if (!("seeked" in this.listeners)) { //prevent duplication
var lastff = (new Date()).getTime(); //init at now, as a seek with ff_to is also sent at init time
me.check = function(){
//console.warn(me.checktimer,"check");
if (me.checktimer) {
MistVideo.timers.stop(me.checktimer);
me.checktimer = null;
}
if (MistVideo.player.api.paused) { return; }
var nextAtGlobal = null;
for (var i in me.subscriptions) {
var buffer = me.subscriptions[i].buffer;
while (buffer.length && (buffer[0].time <= MistVideo.player.api.currentTime*1e3)) {
var message = buffer.shift();
if (message.time < (MistVideo.player.api.currentTime - 5) * 1e3) {
//the message is at least 5 seconds older than the video time
continue;
}
else {
for (var j in me.subscriptions[i].callbacks) {
me.subscriptions[i].callbacks[j].call(MistVideo,message);
}
}
}
if (buffer.length) {
//save when the next message should be played
nextAtGlobal = Math.min(nextAtGlobal === null ? 1e9 : nextAtGlobal,buffer[0].time);
}
}
//add rate limiting: do not ask for fast forward more than once every 5 seconds
var now = (new Date()).getTime()
if (now > lastff+5e3) {
me.s({type:"fast_forward",ff_to:Math.round((MistVideo.player.api.currentTime+stayahead)*1e3)});
lastff = now;
}
if (nextAtGlobal) {
var delay = nextAtGlobal-MistVideo.player.api.currentTime*1e3;
me.checktimer = MistVideo.timers.start(function(){
me.check();
},delay);
}
};
this.listeners.seeked = MistUtil.event.addListener(MistVideo.video,"seeked",function(){
for (var i in me.subscriptions) {
me.subscriptions[i].buffer = [];
}
me.s({type:"seek",seek_time:Math.round(MistVideo.player.api.currentTime*1e3),ff_to:Math.round((MistVideo.player.api.currentTime+stayahead)*1e3)});
lastff = (new Date()).getTime();
//console.warn("seek to",Math.round(MistVideo.player.api.currentTime*1e3));
});
this.listeners.pause = MistUtil.event.addListener(MistVideo.video,"pause",function(){
me.s({type:"hold"});
MistVideo.timers.stop(me.checktimer);
me.checktimer = null;
});
this.listeners.playing = MistUtil.event.addListener(MistVideo.video,"playing",function(){
me.s({type:"play"});
if (!me.checktimer) me.check();
});
this.listeners.ratechange = MistUtil.event.addListener(MistVideo.video,"ratechange",function(){
me.s({type:"set_speed",play_rate:MistVideo.player.api.playbackRate});
});
}
},
destroy: function(){
MistVideo.log("Closing metadata socket..");
this.socket.close();
this.socket = null;
this.subscriptions = {};
for (var i in this.listeners) {
MistUtil.event.removeListener(this.listeners[i]);
}
this.listeners = {};
},
add: function (trackid,callback) {
if (typeof callback != "function") { return; }
if (!(trackid in this.subscriptions)) {
this.subscriptions[trackid] = {
buffer: [],
callbacks: []
};
}
this.subscriptions[trackid].callbacks.push(callback);
if (this.socket === null) {
this.init();
}
else {
this.socket.setTracks();
}
},
remove: function(trackid,callback){
if (trackid in this.subscriptions) {
for (var i in this.subscriptions[trackid].callbacks) {
if (callback == this.subscriptions[trackid].callbacks[i]) {
this.subscriptions[trackid].callbacks.splice(i,1);
break;
}
}
if (this.subscriptions[trackid].callbacks.length == 0) {
delete this.subscriptions[trackid];
if (MistUtil.object.keys(this.subscriptions).length) {
this.socket.setTracks();
}
else {
this.destroy();
}
}
}
}
};
if (options.subscribeToMetaTrack.length) {
if (typeof options.subscribeToMetaTrack[0] != "object") {
options.subscribeToMetaTrack = [options.subscribeToMetaTrack];
}
for (var i in options.subscribeToMetaTrack) {
MistVideo.metaTrackSubscriptions.add.apply(MistVideo.metaTrackSubscriptions,options.subscribeToMetaTrack[i]);
}
}
}
}
} }
//remove placeholder and add UI structure //remove placeholder and add UI structure
@ -1051,7 +1295,7 @@ function MistVideo(streamName,options) {
//switch to polling-mode if websockets are not supported //switch to polling-mode if websockets are not supported
function openWithGet() { function openWithGet() {
var url = MistUtil.http.url.addParam(MistVideo.urlappend(options.host+"/json_"+encodeURIComponent(MistVideo.stream)+".js"),{metaeverywhere:1}); var url = MistUtil.http.url.addParam(MistVideo.urlappend(options.host+"/json_"+encodeURIComponent(MistVideo.stream)+".js"),{metaeverywhere:1,inclzero:1});
MistVideo.log("Requesting stream info from "+url); MistVideo.log("Requesting stream info from "+url);
MistUtil.http.get(url,function(d){ MistUtil.http.get(url,function(d){
if (MistVideo.destroyed) { return; } if (MistVideo.destroyed) { return; }
@ -1070,7 +1314,7 @@ function MistVideo(streamName,options) {
function openSocket() { function openSocket() {
MistVideo.log("Opening stream status stream through websocket.."); MistVideo.log("Opening stream status stream through websocket..");
var url = MistVideo.options.host.replace(/^http/i,"ws"); var url = MistVideo.options.host.replace(/^http/i,"ws");
url = MistUtil.http.url.addParam(MistVideo.urlappend(url+"/json_"+encodeURIComponent(MistVideo.stream)+".js"),{metaeverywhere:1}); url = MistUtil.http.url.addParam(MistVideo.urlappend(url+"/json_"+encodeURIComponent(MistVideo.stream)+".js"),{metaeverywhere:1,inclzero:1});
var socket; var socket;
try { try {
socket = new WebSocket(url); socket = new WebSocket(url);
@ -1415,10 +1659,8 @@ function MistVideo(streamName,options) {
if (diff) { if (diff) {
//console.log("Difference",diff,data,MistVideo.info); //console.log("Difference",diff,data,MistVideo.info);
if ("source" in diff) { if (("source" in diff) && ("error" in MistVideo.info)) {
if ("error" in MistVideo.info) { MistVideo.reload("Reloading, stream info has error");
MistVideo.reload("Reloading, stream info has error");
}
return; return;
} }
@ -1513,6 +1755,9 @@ function MistVideo(streamName,options) {
} }
} }
} }
if (this.metaTrackSubscriptions && this.metaTrackSubscriptions.socket) {
this.metaTrackSubscriptions.destroy();
}
if ((this.UI) && (this.UI.elements)) { if ((this.UI) && (this.UI.elements)) {
for (var i in this.UI.elements) { for (var i in this.UI.elements) {
var e = this.UI.elements[i]; var e = this.UI.elements[i];

View file

@ -59,7 +59,8 @@ MistSkins["default"] = {
type: "container", type: "container",
children: [ children: [
{type: "videobackground", alwaysDisplay: false, delay: 5 }, {type: "videobackground", alwaysDisplay: false, delay: 5 },
{type: "video"} {type: "video"},
{type: "subtitles"}
] ]
}, },
controls: { controls: {
@ -1534,19 +1535,29 @@ MistSkins["default"] = {
var type = tracktypes[j]; var type = tracktypes[j];
var t = tracks[type]; var t = tracks[type];
if (MistUtil.array.indexOf(["video","audio","subtitle"],type) <= -1) {
//Do not display this track type
continue;
}
if (type == "subtitle") { if (type == "subtitle") {
if ((!("player" in MistVideo)) || (!("api" in MistVideo.player)) || (!("setSubtitle" in MistVideo.player.api))) { if ((!("player" in MistVideo)) || (!("api" in MistVideo.player)) || (!("setWSSubtitle" in MistVideo.player.api) && !("setSubtitle" in MistVideo.player.api))) {
//this player does not support adding subtitles, don't show track selection in the interface //this player does not support adding subtitles, don't show track selection in the interface
MistVideo.log("Subtitle selection was disabled as this player does not support it."); MistVideo.log("Subtitle selection was disabled as this player does not support it.");
continue; continue;
} }
var mime = "html5/text/vtt"
if ("setWSSubtitle" in MistVideo.player.api) {
mime = "html5/text/javascript";
}
//check if the VTT output is available //check if the VTT output is available
var subtitleSource = false; var subtitleSource = false;
for (var i in MistVideo.info.source) { for (var i in MistVideo.info.source) {
var source = MistVideo.info.source[i]; var source = MistVideo.info.source[i];
//this is a subtitle source, and it's the same protocol (HTTP/HTTPS) as the video source //this is a subtitle source, and it's the same protocol (HTTP/HTTPS) as the video source
if ((source.type == "html5/text/vtt") && (MistUtil.http.url.split(source.url).protocol == MistUtil.http.url.split(MistVideo.source.url).protocol.replace(/^ws/,"http"))) { if ((source.type == mime) && (MistUtil.http.url.split(source.url).protocol == MistUtil.http.url.split(MistVideo.source.url).protocol.replace(/^ws/,"http"))) {
subtitleSource = source.url.replace(/.srt$/,".vtt"); subtitleSource = source.url.replace(/.srt$/,".vtt");
break; break;
} }
@ -1554,7 +1565,7 @@ MistSkins["default"] = {
if (!subtitleSource) { if (!subtitleSource) {
//if we can't find a subtitle output, don't show track selection in the interface //if we can't find a subtitle output, don't show track selection in the interface
MistVideo.log("Subtitle selection was disabled as an SRT source could not be found."); MistVideo.log("Subtitle selection was disabled as a source could not be found.");
continue; continue;
} }
@ -1722,16 +1733,21 @@ MistSkins["default"] = {
} }
catch (e) {} catch (e) {}
if (this.value != "") { if ("setWSSubtitle" in MistVideo.player.api) {
//gather metadata for this subtitle track here MistVideo.player.api.setWSSubtitle(this.value == "" ? undefined : this.value);
var trackinfo = MistUtil.object.extend({},t[this.value]);
trackinfo.label = orderValues(trackinfo.describe).join(" ");
trackinfo.src = MistUtil.http.url.addParam(subtitleSource,{track:this.value});
MistVideo.player.api.setSubtitle(trackinfo);
} }
else { else {
MistVideo.player.api.setSubtitle(); if (this.value != "") {
//gather metadata for this subtitle track here
var trackinfo = MistUtil.object.extend({},t[this.value]);
trackinfo.label = orderValues(trackinfo.describe).join(" ");
trackinfo.src = MistUtil.http.url.addParam(subtitleSource,{track:this.value});
MistVideo.player.api.setSubtitle(trackinfo);
}
else {
MistVideo.player.api.setSubtitle();
}
} }
}); });
@ -2101,6 +2117,7 @@ MistSkins["default"] = {
} }
if (event.defaultPrevented) { if (event.defaultPrevented) {
MistVideo.log("Error event was defaultPrevented, not showing.");
container.clear(); container.clear();
} }
}; };
@ -2277,8 +2294,89 @@ MistSkins["default"] = {
return ele; return ele;
} },
subtitles: function(options){
if (!("WebSocket" in window)) { return false; }
var MistVideo = this;
if (!("player" in MistVideo) || !("api" in MistVideo.player) || !("currentTime" in MistVideo.player.api)) { return false; }
if (!("metaTrackSubscriptions" in MistVideo)) { return false; }
function clearFormatting(str) {
str = str.replace(/\<\/?[bui]\>/gi,""); //remove <b>,</b>,<u>,</u>,<i>,</i>
str = str.replace(/{\/?[bui]}/gi,""); //remove {b},{/b},{u},{/u},{i},{/i}
str = str.replace(/{\\a\d+}/gi,""); //remove {\a3} (line position)
str = str.replace(/\<\/?font[^>]*?\>/gi,""); //remove <font color="white">,</font>
return str;
}
var container = document.createElement("div");
var c = document.createElement("span");
container.appendChild(c);
var textNode = document.createTextNode("");
c.appendChild(textNode);
var timer = false;
function displayMessage(message) {
textNode.nodeValue = clearFormatting(message.data);
if (timer) {
//a previous message is still being displayed, remove the timer so that it doesn't remove the new message
MistVideo.timers.stop(timer);
timer = null;
}
function setTimer(delay) {
timer = MistVideo.timers.start(function(){
if (MistVideo.player.api.paused) {
//leave the subtitle for now, and start a new timer once the video starts playing
var playing = MistUtil.event.addListener(MistVideo.video,"playing",function(){
setTimer(message.time + ("duration" in message ? message.duration : 5e3) - MistVideo.player.api.currentTime*1e3);
MistUtil.event.removeListener(playing);
});
return;
}
textNode.nodeValue = "";
},delay);
}
setTimer("duration" in message ? message.duration : 5e3);
}
//when seeking, clear the current subtitle message
MistUtil.event.addListener(MistVideo.video,"seeked",function(){
textNode.nodeValue = "";
if (timer) { MistVideo.timers.stop(timer); }
timer = null;
});
if (!("setWSSubtitle" in MistVideo.player.api)) {
//insert generic subtitle function unless it already exists
var trackid = false;
MistVideo.player.api.setWSSubtitle = function(id){
if (id == trackid) { return; } //already selected
//first add, then remove: this prevents the websocket closing because no tracks are selected
if (typeof id != "undefined") {
MistVideo.metaTrackSubscriptions.add(id,displayMessage);
}
if (id != trackid) {
MistVideo.metaTrackSubscriptions.remove(trackid,displayMessage);
}
trackid = (id == "undefined" ? false : id);
}
}
return container;
}
}, },
colors: { colors: {
fill: "#fff", fill: "#fff",

View file

@ -10,6 +10,28 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.mistvideo-subtitles {
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
display: flex;
align-items: flex-end;
justify-content: center;
}
.mistvideo-subtitles > * {
margin-bottom: 0.5em;
padding: 0.1em 0.3em;
text-align: center;
background: rgba(0,0,0,0.6);
white-space: pre-wrap;
}
.mistvideo-subtitles > *:empty {
display: none;
}
.mistvideo[data-fullscreen] .mistvideo-subtitles {
font-size: 3vh;
}
.mistvideo-background { background-color: $background; } .mistvideo-background { background-color: $background; }
.mistvideo-totalTime:before { .mistvideo-totalTime:before {
content: '/'; content: '/';

View file

@ -848,7 +848,7 @@ var MistUtil = {
} }
break; break;
case "rate": case "rate":
name[j] = Math.round(track.rate)+"Khz"; name[j] = Math.round(track.rate*1e-3)+"Khz";
break; break;
case "language": case "language":
if (track[j] != "Undetermined") { name[j] = track[j]; } if (track[j] != "Undetermined") { name[j] = track[j]; }
@ -1130,5 +1130,35 @@ var MistUtil = {
getAndroid: function(){ getAndroid: function(){
var match = navigator.userAgent.toLowerCase().match(/android\s([\d\.]*)/i); var match = navigator.userAgent.toLowerCase().match(/android\s([\d\.]*)/i);
return match ? match[1] : false; return match ? match[1] : false;
},
sources: {
find: function(sources,matchObj){
/*
Example use:
MistUtil.sources.find(MistVideo.info.source,{
type: "html5/text/javascript",
protocol: "wss:"
})
*/
outer:
for (var i in sources) {
for (var j in matchObj) {
if (j == "protocol") {
if (sources[i].url.slice(0,matchObj.protocol.length) != matchObj.protocol) {
continue outer;
}
}
else {
if (sources[i][j] != matchObj[j]) {
continue outer;
}
}
}
//if any key of matchObj did not match the source, the outer loop was continued and this code does not execute
return sources[i];
}
return false;
}
} }
}; };

View file

@ -177,6 +177,9 @@ p.prototype.build = function (MistVideo,callback) {
MistVideo.player.dash.attachSource(url); MistVideo.player.dash.attachSource(url);
}; };
if (MistVideo.options.controls != "stock"){
me.dash.updateSettings({streaming:{text:{defaultEnabled:false}}});
}
var subsloaded = false; var subsloaded = false;
me.dash.on("allTextTracksAdded",function(){ me.dash.on("allTextTracksAdded",function(){
subsloaded = true; subsloaded = true;

View file

@ -36,15 +36,15 @@ $controls=$("<div>").addClass("controls");$checklist=$("<div>").addClass("checkl
1E3)});break;case "selectinput":e=$("<div>").addClass("selectinput");l=$("<select>");e.append(l);l.data("input",!1);for(c in d.selectinput)o=$("<option>"),l.append(o),"string"==typeof d.selectinput[c]?o.text(d.selectinput[c]):(o.text(d.selectinput[c][1]),"string"==typeof d.selectinput[c][0]?o.val(d.selectinput[c][0]):(o.val("CUSTOM"),l.data("input")||l.data("input",UI.buildUI([d.selectinput[c][0]]).children())));l.data("input")&&e.append(l.data("input"));l.change(function(){"CUSTOM"==$(this).val()? 1E3)});break;case "selectinput":e=$("<div>").addClass("selectinput");l=$("<select>");e.append(l);l.data("input",!1);for(c in d.selectinput)o=$("<option>"),l.append(o),"string"==typeof d.selectinput[c]?o.text(d.selectinput[c]):(o.text(d.selectinput[c][1]),"string"==typeof d.selectinput[c][0]?o.val(d.selectinput[c][0]):(o.val("CUSTOM"),l.data("input")||l.data("input",UI.buildUI([d.selectinput[c][0]]).children())));l.data("input")&&e.append(l.data("input"));l.change(function(){"CUSTOM"==$(this).val()?
$(this).data("input").css("display","flex"):$(this).data("input").hide()});l.trigger("change");break;case "inputlist":e=$("<div>").addClass("inputlist");e.data("newitem",function(){var a;if("input"in d)a=UI.buildUI([d.input]).find(".field_container");else{var b=Object.assign({},d);delete b.validate;delete b.pointer;b.type="str";a=UI.buildUI([b]).find(".field_container")}a.removeClass("isSetting");a.addClass("listitem");var c=function(b){$(this).is(":last-child")?""!=$(this).find(".field").getval()? $(this).data("input").css("display","flex"):$(this).data("input").hide()});l.trigger("change");break;case "inputlist":e=$("<div>").addClass("inputlist");e.data("newitem",function(){var a;if("input"in d)a=UI.buildUI([d.input]).find(".field_container");else{var b=Object.assign({},d);delete b.validate;delete b.pointer;b.type="str";a=UI.buildUI([b]).find(".field_container")}a.removeClass("isSetting");a.addClass("listitem");var c=function(b){$(this).is(":last-child")?""!=$(this).find(".field").getval()?
(b=a.clone().keyup(c),b.find(".field").setval(""),$(this).after(b)):8==b.which&&$(this).prev().find(".field").focus():""==$(this).find(".field").getval()&&(b=$(this).prev(),b.length||(b=$(this).next()),b.find(".field").focus(),$(this).remove())};a.keyup(c);return a});e.append(e.data("newitem"));break;case "sublist":e=$("<div>").addClass("sublist");l=$("<div>").addClass("curvals");l.append($("<span>").text("None."));var x=$("<div>").addClass("itemsettings"),i=$("<button>").text("New "+d.itemLabel), (b=a.clone().keyup(c),b.find(".field").setval(""),$(this).after(b)):8==b.which&&$(this).prev().find(".field").focus():""==$(this).find(".field").getval()&&(b=$(this).prev(),b.length||(b=$(this).next()),b.find(".field").focus(),$(this).remove())};a.keyup(c);return a});e.append(e.data("newitem"));break;case "sublist":e=$("<div>").addClass("sublist");l=$("<div>").addClass("curvals");l.append($("<span>").text("None."));var x=$("<div>").addClass("itemsettings"),i=$("<button>").text("New "+d.itemLabel),
g=d.sublist,f=d,k=e,q=m;e.data("build",function(a,b){for(var c in f.saveas)c in a||delete f.saveas[c];f.saveas=Object.assign(f.saveas,a);c="New";"undefined"!=typeof b&&(c="Edit");c=UI.buildUI([$("<h4>").text(c+" "+f.itemLabel)].concat(g).concat([{label:"Save first",type:"str",classes:["onlyshowhelp"],validate:[function(){return{msg:"Did you want to save this "+f.itemLabel+"?",classes:["red"]}}]},{type:"buttons",buttons:[{label:"Cancel",type:"cancel","function":function(){x.html("");i.show();q.show()}}, g=d.sublist,f=d,k=e,r=m;e.data("build",function(a,b){for(var c in f.saveas)c in a||delete f.saveas[c];f.saveas=Object.assign(f.saveas,a);c="New";"undefined"!=typeof b&&(c="Edit");c=UI.buildUI([$("<h4>").text(c+" "+f.itemLabel)].concat(g).concat([{label:"Save first",type:"str",classes:["onlyshowhelp"],validate:[function(){return{msg:"Did you want to save this "+f.itemLabel+"?",classes:["red"]}}]},{type:"buttons",buttons:[{label:"Cancel",type:"cancel","function":function(){x.html("");i.show();r.show()}},
{label:"Save "+f.itemLabel,type:"save",preSave:function(){$(this).closest(".input_container").find(".onlyshowhelp").closest("label").hide()},failedValidate:function(){$(this).closest(".input_container").find(".onlyshowhelp").closest("label").show()},"function":function(){var a=k.getval(),c=Object.assign({},f.saveas),d;for(d in c)null===c[d]&&delete c[d];"undefined"==typeof b?a.push(c):a[b]=c;k.setval(a);x.html("");i.show();q.show()}}]}]));x.html(c);i.hide();q.hide()});var G=e;i.click(function(){G.data("build")({})}); {label:"Save "+f.itemLabel,type:"save",preSave:function(){$(this).closest(".input_container").find(".onlyshowhelp").closest("label").hide()},failedValidate:function(){$(this).closest(".input_container").find(".onlyshowhelp").closest("label").show()},"function":function(){var a=k.getval(),c=Object.assign({},f.saveas),d;for(d in c)null===c[d]&&delete c[d];"undefined"==typeof b?a.push(c):a[b]=c;k.setval(a);x.html("");i.show();r.show()}}]}]));x.html(c);i.hide();r.hide()});var G=e;i.click(function(){G.data("build")({})});
g.unshift({type:"str",label:"Human readable name",placeholder:"none",help:"A convenient name to describe this "+d.itemLabel+". It won't be used by MistServer.",pointer:{main:d.saveas,index:"x-LSP-name"}});e.data("savelist",[]);e.append(l).append(i);b.append(x);break;case "json":e=$("<textarea>").on("keydown",function(a){a.stopPropagation()}).on("keyup change",function(){this.style.height="";this.style.height=(this.scrollHeight?this.scrollHeight+20:14*this.value.split("\n").length+20)+"px"}).css("min-height", g.unshift({type:"str",label:"Human readable name",placeholder:"none",help:"A convenient name to describe this "+d.itemLabel+". It won't be used by MistServer.",pointer:{main:d.saveas,index:"x-LSP-name"}});e.data("savelist",[]);e.append(l).append(i);b.append(x);break;case "json":e=$("<textarea>").on("keydown",function(a){a.stopPropagation()}).on("keyup change",function(){this.style.height="";this.style.height=(this.scrollHeight?this.scrollHeight+20:14*this.value.split("\n").length+20)+"px"}).css("min-height",
"3em");l=function(a,b){if(""!=$(b).val()&&null===a)return{msg:"Invalid json",classes:["red"]}};"validate"in d?d.validate.push(l):d.validate=[l];break;case "bitmask":e=$("<div>").addClass("bitmask");for(c in d.bitmask)e.append($("<label>").append($("<input>").attr("type","checkbox").attr("name","bitmask_"+("pointer"in d?d.pointer.index:"")).attr("value",d.bitmask[c][0]).addClass("field")).append($("<span>").text(d.bitmask[c][1])));m.attr("for","none");break;default:e=$("<input>").attr("type","text"), "3em");l=function(a,b){if(""!=$(b).val()&&null===a)return{msg:"Invalid json",classes:["red"]}};"validate"in d?d.validate.push(l):d.validate=[l];break;case "bitmask":e=$("<div>").addClass("bitmask");for(c in d.bitmask)e.append($("<label>").append($("<input>").attr("type","checkbox").attr("name","bitmask_"+("pointer"in d?d.pointer.index:"")).attr("value",d.bitmask[c][0]).addClass("field")).append($("<span>").text(d.bitmask[c][1])));m.attr("for","none");break;default:e=$("<input>").attr("type","text"),
"maxlength"in d&&e.attr("maxlength",d.maxlength),"minlength"in d&&e.attr("minlength",d.minlength)}e.addClass("field").data("opts",d);"pointer"in d&&e.attr("name",d.pointer.index);h.append(e);if("classes"in d)for(j in d.classes)e.addClass(d.classes[j]);"placeholder"in d&&e.attr("placeholder",d.placeholder);"default"in d&&e.attr("placeholder",d["default"]);"unit"in d&&h.append($("<span>").addClass("unit").html(d.unit));"prefix"in d&&h.prepend($("<span>").addClass("unit").html(d.prefix));"readonly"in "maxlength"in d&&e.attr("maxlength",d.maxlength),"minlength"in d&&e.attr("minlength",d.minlength)}e.addClass("field").data("opts",d);"pointer"in d&&e.attr("name",d.pointer.index);h.append(e);if("classes"in d)for(j in d.classes)e.addClass(d.classes[j]);"placeholder"in d&&e.attr("placeholder",d.placeholder);"default"in d&&e.attr("placeholder",d["default"]);"unit"in d&&h.append($("<span>").addClass("unit").html(d.unit));"prefix"in d&&h.prepend($("<span>").addClass("unit").html(d.prefix));"readonly"in
d&&(e.attr("readonly","readonly"),e.click(function(){$(this).select()}));"qrcode"in d&&h.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")&& d&&(e.attr("readonly","readonly"),e.click(function(){$(this).select()}));"qrcode"in d&&h.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")&&
h.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); h.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);if("dependent"in d)for(c in d.dependent)m.attr("data-dependent-"+c,d.dependent[c]);switch(d.type){case "browse":l=$("<div>").addClass("grouper").append(m);b.append(l);l=$("<button>").text("Browse").on("keydown",function(a){a.stopPropagation()});h.append(l);l.click(function(){function a(b){h.text("Loading..");mist.send(function(a){e.text(a.browse.path[0]);mist.data.LTS&&d.setval(a.browse.path[0]+"/");h.html(i.clone(true).text("..").attr("title", alert("Failed to copy:\n"+a)}})));"rows"in d&&e.attr("rows",d.rows);if("dependent"in d)for(c in d.dependent)m.attr("data-dependent-"+c,d.dependent[c]);switch(d.type){case "browse":l=$("<div>").addClass("grouper").append(m);b.append(l);l=$("<button>").text("Browse").on("keydown",function(a){a.stopPropagation()});h.append(l);l.click(function(){function a(b){h.text("Loading..");mist.send(function(a){e.text(a.browse.path[0]);mist.data.LTS&&d.setval(a.browse.path[0]+"/");h.html(i.clone(true).text("..").attr("title",
"Folder up"));if(a.browse.subdirectories){a.browse.subdirectories.sort();for(var b in a.browse.subdirectories){var f=a.browse.subdirectories[b];h.append(i.clone(true).attr("title",e.text()+m+f).text(f))}}if(a.browse.files){a.browse.files.sort();for(b in a.browse.files){var f=a.browse.files[b],l=e.text()+m+f,f=$("<a>").text(f).addClass("file").attr("title",l);h.append(f);if(k){var j=true,q;for(q in k)if(typeof k[q]!="undefined"&&mist.inputMatch(k[q],l)){j=false;break}j&&f.hide()}f.click(function(){var a= "Folder up"));if(a.browse.subdirectories){a.browse.subdirectories.sort();for(var b in a.browse.subdirectories){var f=a.browse.subdirectories[b];h.append(i.clone(true).attr("title",e.text()+m+f).text(f))}}if(a.browse.files){a.browse.files.sort();for(b in a.browse.files){var f=a.browse.files[b],l=e.text()+m+f,f=$("<a>").text(f).addClass("file").attr("title",l);h.append(f);if(k){var j=true,r;for(r in k)if(typeof k[r]!="undefined"&&mist.inputMatch(k[r],l)){j=false;break}j&&f.hide()}f.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),f=$("<button>").text("Stop browsing").click(function(){g.show();c.remove();d.removeAttr("readonly").css("opacity",1)}),e=$("<span>").addClass("field"),h=$("<div>").addClass("browse_contents"),i=$("<a>").addClass("folder"),k=d.data("filetypes"); $(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),f=$("<button>").text("Stop browsing").click(function(){g.show();c.remove();d.removeAttr("readonly").css("opacity",1)}),e=$("<span>").addClass("field"),h=$("<div>").addClass("browse_contents"),i=$("<a>").addClass("folder"),k=d.data("filetypes");
b.append(c);c.append($("<label>").addClass("UIelement").append($("<span>").addClass("label").text("Current folder:")).append($("<span>").addClass("field_container").append(e).append(f))).append(h);var m="/";mist.data.config.version.indexOf("indows")>-1&&(m="\\");i.click(function(){var b=e.text()+m+$(this).text();a(b)});b=d.getval();f=b.split("://");f.length>1&&(b=f[0]=="file"?f[1]:"");b=b.split(m);b.pop();b=b.join(m);g.hide();a(b)});break;case "geolimited":case "hostlimited":l={field:e};l.blackwhite= b.append(c);c.append($("<label>").addClass("UIelement").append($("<span>").addClass("label").text("Current folder:")).append($("<span>").addClass("field_container").append(e).append(f))).append(h);var m="/";mist.data.config.version.indexOf("indows")>-1&&(m="\\");i.click(function(){var b=e.text()+m+$(this).text();a(b)});b=d.getval();f=b.split("://");f.length>1&&(b=f[0]=="file"?f[1]:"");b=b.split(m);b.pop();b=b.join(m);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", $("<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",
@ -94,7 +94,7 @@ value:m},$("<br>"),$("<h3>").text("Write config now"),{type:"help",help:"Tick th
a)}}]}]));if(mist.data.LTS){var f=function(a){function b(a){if(a.update){var d="";"progress"in a.update&&(d=" ("+a.update.progress+"%)");e.text("Updating.."+d);c(a.log);setTimeout(function(){mist.send(function(a){b(a)},{update:true})},1E3)}else UI.showTab("Overview")}function c(a){a=a.filter(function(a){return a[1]=="UPDR"});if(a.length){var b=$("<div>");e.append(b);for(var d in a)b.append($("<div>").text(a[d][2]))}}if(!a.update||!("uptodate"in a.update)){e.text("Unknown, checking..");setTimeout(function(){mist.send(function(a){"update"in a)}}]}]));if(mist.data.LTS){var f=function(a){function b(a){if(a.update){var d="";"progress"in a.update&&(d=" ("+a.update.progress+"%)");e.text("Updating.."+d);c(a.log);setTimeout(function(){mist.send(function(a){b(a)},{update:true})},1E3)}else UI.showTab("Overview")}function c(a){a=a.filter(function(a){return a[1]=="UPDR"});if(a.length){var b=$("<div>");e.append(b);for(var d in a)b.append($("<div>").text(a[d][2]))}}if(!a.update||!("uptodate"in a.update)){e.text("Unknown, checking..");setTimeout(function(){mist.send(function(a){"update"in
a&&f(a)},{checkupdate:true})},5E3)}else if(a.update.error)e.addClass("red").text(a.update.error);else if(a.update.uptodate)e.text("Your version is up to date.").addClass("green");else{if(a.update.progress){e.addClass("orange").removeClass("red").text("Updating..");b(a)}else{e.text("");e.append($("<span>").addClass("red").text("On "+(new Date(a.update.date)).toLocaleDateString()+" version "+a.update.version+" became available."));(!a.update.url||a.update.url.slice(-4)!=".zip")&&e.append($("<button>").text("Rolling update").css({"font-size":"1em", a&&f(a)},{checkupdate:true})},5E3)}else if(a.update.error)e.addClass("red").text(a.update.error);else if(a.update.uptodate)e.text("Your version is up to date.").addClass("green");else{if(a.update.progress){e.addClass("orange").removeClass("red").text("Updating..");b(a)}else{e.text("");e.append($("<span>").addClass("red").text("On "+(new Date(a.update.date)).toLocaleDateString()+" version "+a.update.version+" became available."));(!a.update.url||a.update.url.slice(-4)!=".zip")&&e.append($("<button>").text("Rolling update").css({"font-size":"1em",
"margin-left":"1em"}).click(function(){if(confirm("Are you sure you want to execute a rolling update?")){e.addClass("orange").removeClass("red").text("Rolling update command sent..");mist.send(function(a){b(a)},{autoupdate:true})}}));var d=$("<a>").attr("href",a.update.url).attr("target","_blank").text("Manual download");d[0].protocol="https:";e.append($("<div>").append(d))}c(a.log)}};f(mist.data);if("license"in mist.data.config){if("active_products"in mist.data.config.license&&Object.keys(mist.data.config.license.active_products).length){var k= "margin-left":"1em"}).click(function(){if(confirm("Are you sure you want to execute a rolling update?")){e.addClass("orange").removeClass("red").text("Rolling update command sent..");mist.send(function(a){b(a)},{autoupdate:true})}}));var d=$("<a>").attr("href",a.update.url).attr("target","_blank").text("Manual download");d[0].protocol="https:";e.append($("<div>").append(d))}c(a.log)}};f(mist.data);if("license"in mist.data.config){if("active_products"in mist.data.config.license&&Object.keys(mist.data.config.license.active_products).length){var k=
$("<table>").css("text-indent","0");o.html(k);k.append($("<tr>").append($("<th>").append("Product")).append($("<th>").append("Updates until")).append($("<th>").append("Use until")).append($("<th>").append("Max. simul. instances")));for(var q in mist.data.config.license.active_products){var G=mist.data.config.license.active_products[q];k.append($("<tr>").append($("<td>").append(G.name)).append($("<td>").append(G.updates_final?G.updates_final:"&infin;")).append($("<td>").append(G.use_final?G.use_final: $("<table>").css("text-indent","0");o.html(k);k.append($("<tr>").append($("<th>").append("Product")).append($("<th>").append("Updates until")).append($("<th>").append("Use until")).append($("<th>").append("Max. simul. instances")));for(var r in mist.data.config.license.active_products){var G=mist.data.config.license.active_products[r];k.append($("<tr>").append($("<td>").append(G.name)).append($("<td>").append(G.updates_final?G.updates_final:"&infin;")).append($("<td>").append(G.use_final?G.use_final:
"&infin;")).append($("<td>").append(G.amount?G.amount:"&infin;")))}}else o.text("None. ");o.append($("<a>").text("More details").attr("href","https://shop.mistserver.org/myinvoices").attr("target","_blank"))}}else e.text("");var Da=function(){var a={totals:{fields:["clients"],start:-10},active_streams:true};if(!("cabailities"in mist.data))a.capabilities=true;mist.send(function(){Ea()},a)},Ea=function(){j.text("active_streams"in mist.data?mist.data.active_streams?mist.data.active_streams.length:0: "&infin;")).append($("<td>").append(G.amount?G.amount:"&infin;")))}}else o.text("None. ");o.append($("<a>").text("More details").attr("href","https://shop.mistserver.org/myinvoices").attr("target","_blank"))}}else e.text("");var Da=function(){var a={totals:{fields:["clients"],start:-10},active_streams:true};if(!("cabailities"in mist.data))a.capabilities=true;mist.send(function(){Ea()},a)},Ea=function(){j.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..";h.text(a);t.text(UI.format.dateTime(mist.data.config.time,"long"));m.html("");a=0;"license"in mist.data.config&&"user_msg"in mist.data.config.license&&mist.data.log.unshift([mist.data.config.license.time,"ERROR",mist.data.config.license.user_msg]);for(var b in mist.data.log){var c=mist.data.log[b];if(["FAIL","ERROR"].indexOf(c[1])> "?");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..";h.text(a);t.text(UI.format.dateTime(mist.data.config.time,"long"));m.html("");a=0;"license"in mist.data.config&&"user_msg"in mist.data.config.license&&mist.data.log.unshift([mist.data.config.license.time,"ERROR",mist.data.config.license.user_msg]);for(var 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]));m.append($("<div>").append($("<span>").append(UI.format.time(c[0]))).append(d));if(a==5)break}}a==0&&m.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)}l.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); -1){a++;var d=$("<span>").addClass("content").addClass("red"),e=c[2].split("|");for(b in e)d.append($("<span>").text(e[b]));m.append($("<div>").append($("<span>").append(UI.format.time(c[0]))).append(d));if(a==5)break}}a==0&&m.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)}l.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);
@ -131,36 +131,36 @@ c=d.length?c+d.join(", "):c+"None.";if(d.length!=a.length){a=a.filter(function(a
"both")).append($("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Protocol")).append($("<th>").text("Status")).append($("<th>").text("Settings")).append($("<th>")))).append(F));var Ha=function(){function a(b){var c=mist.data.capabilities.connectors[b.connector];if(!c)return"";var d=[],e=["required","optional"],w;for(w in e)for(var g in c[e[w]])b[g]&&b[g]!=""?d.push(g+": "+b[g]):c[e[w]][g]["default"]&&d.push(g+": "+c[e[w]][g]["default"]);return $("<span>").addClass("description").text(d.join(", "))} "both")).append($("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Protocol")).append($("<th>").text("Status")).append($("<th>").text("Settings")).append($("<th>")))).append(F));var Ha=function(){function a(b){var c=mist.data.capabilities.connectors[b.connector];if(!c)return"";var d=[],e=["required","optional"],w;for(w in e)for(var g in c[e[w]])b[g]&&b[g]!=""?d.push(g+": "+b[g]):c[e[w]][g]["default"]&&d.push(g+": "+c[e[w]][g]["default"]);return $("<span>").addClass("description").text(d.join(", "))}
F.html("");for(var b in mist.data.config.protocols){var c=mist.data.config.protocols[b],d=mist.data.capabilities.connectors[c.connector];F.append($("<tr>").data("index",b).append($("<td>").text(d&&d.friendly?d.friendly:c.connector)).append($("<td>").html(UI.format.status(c))).append($("<td>").html(a(c))).append($("<td>").css("text-align","right").html($("<button>").text("Edit").click(function(){UI.navto("Edit Protocol",$(this).closest("tr").data("index"))})).append($("<button>").text("Delete").click(function(){var a= F.html("");for(var b in mist.data.config.protocols){var c=mist.data.config.protocols[b],d=mist.data.capabilities.connectors[c.connector];F.append($("<tr>").data("index",b).append($("<td>").text(d&&d.friendly?d.friendly:c.connector)).append($("<td>").html(UI.format.status(c))).append($("<td>").html(a(c))).append($("<td>").css("text-align","right").html($("<button>").text("Edit").click(function(){UI.navto("Edit Protocol",$(this).closest("tr").data("index"))})).append($("<button>").text("Delete").click(function(){var a=
$(this).closest("tr").data("index");if(confirm('Are you sure you want to delete the protocol "'+mist.data.config.protocols[a].connector+'"?')){mist.send(function(){UI.navto("Protocols")},{deleteprotocol:mist.data.config.protocols[a]});mist.data.config.protocols.splice(a,1)}}))))}};Ha();UI.interval.set(function(){mist.send(function(){Ha()})},1E4);break;case "Edit Protocol":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,b)},{capabilities:!0});c.append("Loading..");return}z= $(this).closest("tr").data("index");if(confirm('Are you sure you want to delete the protocol "'+mist.data.config.protocols[a].connector+'"?')){mist.send(function(){UI.navto("Protocols")},{deleteprotocol:mist.data.config.protocols[a]});mist.data.config.protocols.splice(a,1)}}))))}};Ha();UI.interval.set(function(){mist.send(function(){Ha()})},1E4);break;case "Edit Protocol":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,b)},{capabilities:!0});c.append("Loading..");return}z=
!1;""!=b&&0<=b&&(z=!0);var V={};for(q in mist.data.config.protocols)V[mist.data.config.protocols[q].connector]=1;var Ja=function(a){var b=mist.data.capabilities.connectors[a],c=mist.convertBuildOptions(b,p);if(z)var d=$.extend({},p);c.push({type:"hidden",pointer:{main:p,index:"connector"},value:a});c.push({type:"buttons",buttons:[{type:"save",label:"Save","function":function(){var a={};z?a.updateprotocol=[d,p]:a.addprotocol=p;mist.send(function(){UI.navto("Protocols")},a)}},{type:"cancel",label:"Cancel", !1;""!=b&&0<=b&&(z=!0);var V={};for(r in mist.data.config.protocols)V[mist.data.config.protocols[r].connector]=1;var Ja=function(a){var b=mist.data.capabilities.connectors[a],c=mist.convertBuildOptions(b,p);if(z)var d=$.extend({},p);c.push({type:"hidden",pointer:{main:p,index:"connector"},value:a});c.push({type:"buttons",buttons:[{type:"save",label:"Save","function":function(){var a={};z?a.updateprotocol=[d,p]:a.addprotocol=p;mist.send(function(){UI.navto("Protocols")},a)}},{type:"cancel",label:"Cancel",
"function":function(){UI.navto("Protocols")}}]});if("deps"in b&&b.deps!=""){k=$("<span>").text("Dependencies:");$ul=$("<ul>");k.append($ul);if(typeof b.deps=="string")b.deps=b.deps.split(", ");for(var e in b.deps){a=$("<li>").text(b.deps[e]+" ");$ul.append(a);typeof V[b.deps[e]]!="undefined"||typeof V[b.deps[e]+".exe"]!="undefined"?a.append($("<span>").addClass("green").text("(Configured)")):a.append($("<span>").addClass("red").text("(Not yet configured)"))}c.unshift({type:"text",text:k[0].innerHTML})}return UI.buildUI(c)}, "function":function(){UI.navto("Protocols")}}]});if("deps"in b&&b.deps!=""){k=$("<span>").text("Dependencies:");$ul=$("<ul>");k.append($ul);if(typeof b.deps=="string")b.deps=b.deps.split(", ");for(var e in b.deps){a=$("<li>").text(b.deps[e]+" ");$ul.append(a);typeof V[b.deps[e]]!="undefined"||typeof V[b.deps[e]+".exe"]!="undefined"?a.append($("<span>").addClass("green").text("(Configured)")):a.append($("<span>").addClass("red").text("(Not yet configured)"))}c.unshift({type:"text",text:k[0].innerHTML})}return UI.buildUI(c)},
V={};for(q in mist.data.config.protocols)V[mist.data.config.protocols[q].connector]=1;if(z){var s=mist.data.config.protocols[b],p=s;c.find("h2").append(' "'+s.connector+'"');c.append(Ja(s.connector))}else{c.html($("<h2>").text("New Protocol"));var p={},u=[["",""]];for(q in mist.data.capabilities.connectors)u.push([q,mist.data.capabilities.connectors[q].friendly?mist.data.capabilities.connectors[q].friendly:q]);var S=$("<span>");c.append(UI.buildUI([{label:"Protocol",type:"select",select:u,"function":function(){$(this).getval()!= V={};for(r in mist.data.config.protocols)V[mist.data.config.protocols[r].connector]=1;if(z){var s=mist.data.config.protocols[b],p=s;c.find("h2").append(' "'+s.connector+'"');c.append(Ja(s.connector))}else{c.html($("<h2>").text("New Protocol"));var p={},u=[["",""]];for(r in mist.data.capabilities.connectors)u.push([r,mist.data.capabilities.connectors[r].friendly?mist.data.capabilities.connectors[r].friendly:r]);var S=$("<span>");c.append(UI.buildUI([{label:"Protocol",type:"select",select:u,"function":function(){$(this).getval()!=
""&&S.html(Ja($(this).getval()))}}])).append(S)}break;case "Streams":if(!("capabilities"in mist.data)){c.html("Loading..");mist.send(function(){UI.navto(a)},{capabilities:!0});return}var La=$("<button>"),O=$("<span>").text("Loading..");c.append(UI.buildUI([{type:"help",help:"Here you can create, edit or delete new and existing streams. Go to stream preview or embed a video player on your website."},$("<div>").css({width:"45.25em",display:"flex","justify-content":"flex-end"}).append(La).append($("<button>").text("Create a new stream").click(function(){UI.navto("Edit")}))])).append(O); ""&&S.html(Ja($(this).getval()))}}])).append(S)}break;case "Streams":if(!("capabilities"in mist.data)){c.html("Loading..");mist.send(function(){UI.navto(a)},{capabilities:!0});return}var La=$("<button>"),O=$("<span>").text("Loading..");c.append(UI.buildUI([{type:"help",help:"Here you can create, edit or delete new and existing streams. Go to stream preview or embed a video player on your website."},$("<div>").css({width:"45.25em",display:"flex","justify-content":"flex-end"}).append(La).append($("<button>").text("Create a new stream").click(function(){UI.navto("Edit")}))])).append(O);
""==b&&(g=mist.stored.get(),"viewmode"in g&&(b=g.viewmode));La.text("Switch to "+("thumbnails"==b?"list":"thumbnail")+" view").click(function(){mist.stored.set("viewmode",b=="thumbnails"?"list":"thumbnails");UI.navto("Streams",b=="thumbnails"?"list":"thumbnails")});var C=$.extend(!0,{},mist.data.streams),oa=function(a,b){var c=$.extend({},b);delete c.meta;delete c.error;c.online=2;c.name=a;c.ischild=true;return c},pa=function(b,d,e){O.remove();switch(b){case "thumbnails":var g=$("<div>").addClass("preview_icons"), ""==b&&(g=mist.stored.get(),"viewmode"in g&&(b=g.viewmode));La.text("Switch to "+("thumbnails"==b?"list":"thumbnail")+" view").click(function(){mist.stored.set("viewmode",b=="thumbnails"?"list":"thumbnails");UI.navto("Streams",b=="thumbnails"?"list":"thumbnails")});var C=$.extend(!0,{},mist.data.streams),oa=function(a,b){var c=$.extend({},b);delete c.meta;delete c.error;c.online=2;c.name=a;c.ischild=true;return c},pa=function(b,d,e){O.remove();switch(b){case "thumbnails":var g=$("<div>").addClass("preview_icons"),
f;f=e||[];d.sort();d.unshift("");O.remove();c.append($("<h2>").text(a)).append(UI.buildUI([{label:"Filter the streams",type:"datalist",datalist:d,pointer:{main:{},index:"stream"},help:"If you type something here, the box below will only show streams with names that contain your text.","function":function(){var a=$(this).val();g.children().each(function(){$(this).hide();$(this).attr("data-stream").indexOf(a)>-1&&$(this).show()})}}]));d.shift();c.append($("<span>").addClass("description").text("Choose a stream below.")).append(g); f;f=e||[];d.sort();d.unshift("");O.remove();c.append($("<h2>").text(a)).append(UI.buildUI([{label:"Filter the streams",type:"datalist",datalist:d,pointer:{main:{},index:"stream"},help:"If you type something here, the box below will only show streams with names that contain your text.","function":function(){var a=$(this).val();g.children().each(function(){$(this).hide();$(this).attr("data-stream").indexOf(a)>-1&&$(this).show()})}}]));d.shift();c.append($("<span>").addClass("description").text("Choose a stream below.")).append(g);
for(var h in d){var b=d[h],i="",k=$("<button>").text("Delete").click(function(){var a=$(this).closest("div").attr("data-stream");if(confirm('Are you sure you want to delete the stream "'+a+'"?')){delete mist.data.streams[a];var b={};b.deletestream=[a];mist.send(function(){UI.navto("Streams")},b)}}),l=$("<button>").text("Settings").click(function(){UI.navto("Edit",$(this).closest("div").attr("data-stream"))}),e=$("<button>").text("Preview").click(function(){UI.navto("Preview",$(this).closest("div").attr("data-stream"))}), for(var h in d){var b=d[h],i="",k=$("<button>").text("Delete").click(function(){var a=$(this).closest("div").attr("data-stream");if(confirm('Are you sure you want to delete the stream "'+a+'"?')){delete mist.data.streams[a];var b={};b.deletestream=[a];mist.send(function(){UI.navto("Streams")},b)}}),l=$("<button>").text("Settings").click(function(){UI.navto("Edit",$(this).closest("div").attr("data-stream"))}),e=$("<button>").text("Preview").click(function(){UI.navto("Preview",$(this).closest("div").attr("data-stream"))}),
Ka=$("<button>").text("Embed").click(function(){UI.navto("Embed",$(this).closest("div").attr("data-stream"))}),r=$("<span>").addClass("image");if(b.indexOf("+")>-1){i=b.split("+");i=mist.data.streams[i[0]].source+i[1];l=k="";r.addClass("wildcard")}else{i=mist.data.streams[b].source;if(f.indexOf(b)>-1){Ka=e="";r.addClass("folder")}}g.append($("<div>").append($("<span>").addClass("streamname").text(b)).append(r).append($("<span>").addClass("description").text(i)).append($("<span>").addClass("button_container").append(l).append(k).append(e).append(Ka)).attr("title", Ka=$("<button>").text("Embed").click(function(){UI.navto("Embed",$(this).closest("div").attr("data-stream"))}),q=$("<span>").addClass("image");if(b.indexOf("+")>-1){i=b.split("+");i=mist.data.streams[i[0]].source+i[1];l=k="";q.addClass("wildcard")}else{i=mist.data.streams[b].source;if(f.indexOf(b)>-1){Ka=e="";q.addClass("folder")}}g.append($("<div>").append($("<span>").addClass("streamname").text(b)).append(q).append($("<span>").addClass("description").text(i)).append($("<span>").addClass("button_container").append(l).append(k).append(e).append(Ka)).attr("title",
b).attr("data-stream",b))}break;default:var j=$("<tbody>").append($("<tr>").append("<td>").attr("colspan",6).text("Loading.."));h=$("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Stream name").attr("data-sort-type","string").addClass("sorting-asc")).append($("<th>").text("Source").attr("data-sort-type","string")).append($("<th>").text("Status").attr("data-sort-type","int")).append($("<th>").css("text-align","right").text("Connections").attr("data-sort-type","int")).append($("<th>")).append($("<th>")))).append(j); b).attr("data-stream",b))}break;default:var j=$("<tbody>").append($("<tr>").append("<td>").attr("colspan",6).text("Loading.."));h=$("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Stream name").attr("data-sort-type","string").addClass("sorting-asc")).append($("<th>").text("Source").attr("data-sort-type","string")).append($("<th>").text("Status").attr("data-sort-type","int")).append($("<th>").css("text-align","right").text("Connections").attr("data-sort-type","int")).append($("<th>")).append($("<th>")))).append(j);
c.append(h);h.stupidtable();var m=function(){var a=[],b;for(b in mist.data.active_streams)a.push({streams:[mist.data.active_streams[b]],fields:["clients"],start:-2});mist.send(function(){$.extend(true,C,mist.data.streams);var a=0;j.html("");d.sort();for(var b in d){var c=d[b],e;e=c in mist.data.streams?mist.data.streams[c]:C[c];var g=$("<td>").css("text-align","right").html($("<span>").addClass("description").text("Loading..")),w=0;if(typeof mist.data.totals!="undefined"&&typeof mist.data.totals[c]!= c.append(h);h.stupidtable();var m=function(){var a=[],b;for(b in mist.data.active_streams)a.push({streams:[mist.data.active_streams[b]],fields:["clients"],start:-2});mist.send(function(){$.extend(true,C,mist.data.streams);var a=0;j.html("");d.sort();for(var b in d){var c=d[b],e;e=c in mist.data.streams?mist.data.streams[c]:C[c];var g=$("<td>").css("text-align","right").html($("<span>").addClass("description").text("Loading..")),w=0;if(typeof mist.data.totals!="undefined"&&typeof mist.data.totals[c]!=
"undefined"){var f=mist.data.totals[c].all_protocols.clients,w=0;if(f.length){for(a in f)w=w+f[a][1];w=Math.round(w/f.length)}}g.html(UI.format.number(w));if(w==0&&e.online==1)e.online=2;w=$("<td>").css("text-align","right").css("white-space","nowrap");(!("ischild"in e)||!e.ischild)&&w.html($("<button>").text("Settings").click(function(){UI.navto("Edit",$(this).closest("tr").data("index"))})).append($("<button>").text("Delete").click(function(){var a=$(this).closest("tr").data("index");if(confirm('Are you sure you want to delete the stream "'+ "undefined"){var f=mist.data.totals[c].all_protocols.clients,w=0;if(f.length){for(a in f)w=w+f[a][1];w=Math.round(w/f.length)}}g.html(UI.format.number(w));if(w==0&&e.online==1)e.online=2;w=$("<td>").css("text-align","right").css("white-space","nowrap");(!("ischild"in e)||!e.ischild)&&w.html($("<button>").text("Settings").click(function(){UI.navto("Edit",$(this).closest("tr").data("index"))})).append($("<button>").text("Delete").click(function(){var a=$(this).closest("tr").data("index");if(confirm('Are you sure you want to delete the stream "'+
a+'"?')){delete mist.data.streams[a];var b={};mist.data.LTS?b.deletestream=[a]:b.streams=mist.data.streams;mist.send(function(){UI.navto("Streams")},b)}}));f=$("<span>").text(e.name);e.ischild&&f.css("padding-left","1em");var h=UI.format.status(e),i=$("<button>").text("Preview").click(function(){UI.navto("Preview",$(this).closest("tr").data("index"))}),r=$("<button>").text("Embed").click(function(){UI.navto("Embed",$(this).closest("tr").data("index"))});if("filesfound"in C[c]||e.online<0){h.html(""); a+'"?')){delete mist.data.streams[a];var b={};mist.data.LTS?b.deletestream=[a]:b.streams=mist.data.streams;mist.send(function(){UI.navto("Streams")},b)}}));f=$("<span>").text(e.name);e.ischild&&f.css("padding-left","1em");var h=UI.format.status(e),i=$("<button>").text("Preview").click(function(){UI.navto("Preview",$(this).closest("tr").data("index"))}),q=$("<button>").text("Embed").click(function(){UI.navto("Embed",$(this).closest("tr").data("index"))});if("filesfound"in C[c]||e.online<0){h.html("");
i="";g.html("");r=""}j.append($("<tr>").data("index",c).html($("<td>").html(f).attr("title",e.name=="..."?"The results were truncated":e.name).addClass("overflow_ellipsis")).append($("<td>").text(e.source).attr("title",e.source).addClass("description").addClass("overflow_ellipsis").css("max-width","20em")).append($("<td>").data("sort-value",e.online).html(h)).append(g).append($("<td>").css("white-space","nowrap").html(i).append(r)).append(w));a++}},{totals:a,active_streams:true})};if(mist.data.LTS){var q= i="";g.html("");q=""}j.append($("<tr>").data("index",c).html($("<td>").html(f).attr("title",e.name=="..."?"The results were truncated":e.name).addClass("overflow_ellipsis")).append($("<td>").text(e.source).attr("title",e.source).addClass("description").addClass("overflow_ellipsis").css("max-width","20em")).append($("<td>").data("sort-value",e.online).html(h)).append(g).append($("<td>").css("white-space","nowrap").html(i).append(q)).append(w));a++}},{totals:a,active_streams:true})};if(mist.data.LTS){var r=
0,Ma=0;for(f in mist.data.streams){h=mist.data.capabilities.inputs.Folder||mist.data.capabilities.inputs["Folder.exe"];if(!h)break;if(mist.inputMatch(h.source_match,mist.data.streams[f].source)){C[f].source=C[f].source+"*";C[f].filesfound=null;mist.send(function(a,b){var c=b.stream,d=0,e;a:for(e in a.browse.files){var g;for(g in mist.data.capabilities.inputs)if(!(g.indexOf("Buffer")>=0||g.indexOf("Buffer.exe")>=0||g.indexOf("Folder")>=0||g.indexOf("Folder.exe")>=0)&&mist.inputMatch(mist.data.capabilities.inputs[g].source_match, 0,Ma=0;for(f in mist.data.streams){h=mist.data.capabilities.inputs.Folder||mist.data.capabilities.inputs["Folder.exe"];if(!h)break;if(mist.inputMatch(h.source_match,mist.data.streams[f].source)){C[f].source=C[f].source+"*";C[f].filesfound=null;mist.send(function(a,b){var c=b.stream,d=0,e;a:for(e in a.browse.files){var g;for(g in mist.data.capabilities.inputs)if(!(g.indexOf("Buffer")>=0||g.indexOf("Buffer.exe")>=0||g.indexOf("Folder")>=0||g.indexOf("Folder.exe")>=0)&&mist.inputMatch(mist.data.capabilities.inputs[g].source_match,
"/"+a.browse.files[e])){var w=c+"+"+a.browse.files[e];C[w]=oa(w,mist.data.streams[c]);C[w].source=mist.data.streams[c].source+a.browse.files[e];d++;if(d>=500){C[c+"+zzzzzzzzz"]={ischild:true,name:"...",online:-1};break a}}}"files"in a.browse&&a.browse.files.length?C[c].filesfound=true:mist.data.streams[c].filesfound=false;Ma++;if(q==Ma){mist.send(function(){m()},{active_streams:true});UI.interval.set(function(){m()},5E3)}},{browse:mist.data.streams[f].source},{stream:f});q++}}if(q==0){mist.send(function(){m()}, "/"+a.browse.files[e])){var w=c+"+"+a.browse.files[e];C[w]=oa(w,mist.data.streams[c]);C[w].source=mist.data.streams[c].source+a.browse.files[e];d++;if(d>=500){C[c+"+zzzzzzzzz"]={ischild:true,name:"...",online:-1};break a}}}"files"in a.browse&&a.browse.files.length?C[c].filesfound=true:mist.data.streams[c].filesfound=false;Ma++;if(r==Ma){mist.send(function(){m()},{active_streams:true});UI.interval.set(function(){m()},5E3)}},{browse:mist.data.streams[f].source},{stream:f});r++}}if(r==0){mist.send(function(){m()},
{active_streams:true});UI.interval.set(function(){m()},5E3)}}else{mist.send(function(){m()},{active_streams:true});UI.interval.set(function(){m()},5E3)}}};if(mist.data.LTS){var qa=0,Na=0,u={},Oa=[];for(g in mist.data.streams)if(mist.inputMatch((mist.data.capabilities.inputs.Folder||mist.data.capabilities.inputs["Folder.exe"]).source_match,mist.data.streams[g].source))Oa.push(g),mist.send(function(a,c){var d=c.stream,e=0,g;a:for(g in a.browse.files){var f;for(f in mist.data.capabilities.inputs)if(!(f.indexOf("Buffer")>= {active_streams:true});UI.interval.set(function(){m()},5E3)}}else{mist.send(function(){m()},{active_streams:true});UI.interval.set(function(){m()},5E3)}}};if(mist.data.LTS){var qa=0,Na=0,u={},Oa=[];for(g in mist.data.streams)if(mist.inputMatch((mist.data.capabilities.inputs.Folder||mist.data.capabilities.inputs["Folder.exe"]).source_match,mist.data.streams[g].source))Oa.push(g),mist.send(function(a,c){var d=c.stream,e=0,g;a:for(g in a.browse.files){var f;for(f in mist.data.capabilities.inputs)if(!(f.indexOf("Buffer")>=
0||f.indexOf("Folder")>=0)&&mist.inputMatch(mist.data.capabilities.inputs[f].source_match,"/"+a.browse.files[g])){u[d+"+"+a.browse.files[g]]=true;e++;if(e>=500){u[d+"+zzzzzzzzz"]=true;break a}}}Na++;qa==Na&&mist.send(function(){for(var a in mist.data.active_streams){var c=mist.data.active_streams[a].split("+");if(c.length>1&&c[0]in mist.data.streams){u[mist.data.active_streams[a]]=true;C[mist.data.active_streams[a]]=oa(mist.data.active_streams[a],mist.data.streams[c[0]])}}u=Object.keys(u);u=u.concat(Object.keys(mist.data.streams)); 0||f.indexOf("Folder")>=0)&&mist.inputMatch(mist.data.capabilities.inputs[f].source_match,"/"+a.browse.files[g])){u[d+"+"+a.browse.files[g]]=true;e++;if(e>=500){u[d+"+zzzzzzzzz"]=true;break a}}}Na++;qa==Na&&mist.send(function(){for(var a in mist.data.active_streams){var c=mist.data.active_streams[a].split("+");if(c.length>1&&c[0]in mist.data.streams){u[mist.data.active_streams[a]]=true;C[mist.data.active_streams[a]]=oa(mist.data.active_streams[a],mist.data.streams[c[0]])}}u=Object.keys(u);u=u.concat(Object.keys(mist.data.streams));
u.sort();pa(b,u,Oa)},{active_streams:true})},{browse:mist.data.streams[g].source},{stream:g}),qa++;0==qa&&mist.send(function(){for(var a in mist.data.active_streams){var c=mist.data.active_streams[a].split("+");if(c.length>1&&c[0]in mist.data.streams){u[mist.data.active_streams[a]]=true;C[mist.data.active_streams[a]]=oa(mist.data.active_streams[a],mist.data.streams[c[0]])}}u=Object.keys(u);mist.data.streams&&(u=u.concat(Object.keys(mist.data.streams)));u.sort();pa(b,u)},{active_streams:!0})}else pa(b, u.sort();pa(b,u,Oa)},{active_streams:true})},{browse:mist.data.streams[g].source},{stream:g}),qa++;0==qa&&mist.send(function(){for(var a in mist.data.active_streams){var c=mist.data.active_streams[a].split("+");if(c.length>1&&c[0]in mist.data.streams){u[mist.data.active_streams[a]]=true;C[mist.data.active_streams[a]]=oa(mist.data.active_streams[a],mist.data.streams[c[0]])}}u=Object.keys(u);mist.data.streams&&(u=u.concat(Object.keys(mist.data.streams)));u.sort();pa(b,u)},{active_streams:!0})}else pa(b,
Object.keys(mist.data.streams));break;case "Edit":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,b)},{capabilities:!0});c.append("Loading..");return}z=!1;""!=b&&(z=!0);if(z){var Pa=b,p=mist.data.streams[Pa];c.find("h2").append(' "'+Pa+'"')}else c.html($("<h2>").text("New Stream")),p={};var Qa=[];for(q in mist.data.capabilities.inputs)Qa.push(mist.data.capabilities.inputs[q].source_match);var fa=$("<div>"),Ra=function(a){var c={};if(!mist.data.streams)mist.data.streams= Object.keys(mist.data.streams));break;case "Edit":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,b)},{capabilities:!0});c.append("Loading..");return}z=!1;""!=b&&(z=!0);if(z){var Pa=b,p=mist.data.streams[Pa];c.find("h2").append(' "'+Pa+'"')}else c.html($("<h2>").text("New Stream")),p={};var Qa=[];for(r in mist.data.capabilities.inputs)Qa.push(mist.data.capabilities.inputs[r].source_match);var fa=$("<div>"),Ra=function(a){var c={};if(!mist.data.streams)mist.data.streams=
{};mist.data.streams[p.name]=p;b!=p.name&&delete mist.data.streams[b];c.addstream={};c.addstream[p.name]=p;if(b!=p.name)c.deletestream=[b];if(p.stop_sessions&&b!=""){c.stop_sessions=b;delete p.stop_sessions}mist.send(function(){delete mist.data.streams[p.name].online;delete mist.data.streams[p.name].error;UI.navto(a,a=="Preview"?p.name:"")},c)},Sa=$("<style>").text("button.saveandpreview { display: none; }"),P=$("<span>"),ra=function(){var a=c.find("[name=name]").val();if(a){var b=parseURL(mist.user.host), {};mist.data.streams[p.name]=p;b!=p.name&&delete mist.data.streams[b];c.addstream={};c.addstream[p.name]=p;if(b!=p.name)c.deletestream=[b];if(p.stop_sessions&&b!=""){c.stop_sessions=b;delete p.stop_sessions}mist.send(function(){delete mist.data.streams[p.name].online;delete mist.data.streams[p.name].error;UI.navto(a,a=="Preview"?p.name:"")},c)},Sa=$("<style>").text("button.saveandpreview { display: none; }"),P=$("<span>"),ra=function(){var a=c.find("[name=name]").val();if(a){var b=parseURL(mist.user.host),
d=c.find("[name=source]").val(),e=d.match(/@.*/);e&&(e=e[0].substring(1));var g=d.replace(/(?:.+?):\/\//,""),g=g.split("/"),g=g[0],g=g.split(":"),g=g[0];(d=d.match(/:\d+/))&&(d=d[0]);var f={},h=["RTMP","RTSP","RTMP.exe","RTSP.exe"],i;for(i in h)h[i]in mist.data.capabilities.connectors&&(f[h[i]]=mist.data.capabilities.connectors[h[i]].optional.port["default"]);var h={RTMP:1935,"RTMP.exe":1935,RTSP:554,"RTSP.exe":554,TS:-1,"TS.exe":-1},k;for(k in f){for(i in mist.data.config.protocols){var l=mist.data.config.protocols[i]; d=c.find("[name=source]").val(),e=d.match(/@.*/);e&&(e=e[0].substring(1));var g=d.replace(/(?:.+?):\/\//,""),g=g.split("/"),g=g[0],g=g.split(":"),g=g[0];(d=d.match(/:\d+/))&&(d=d[0]);var f={},h=["RTMP","RTSP","RTMP.exe","RTSP.exe"],i;for(i in h)h[i]in mist.data.capabilities.connectors&&(f[h[i]]=mist.data.capabilities.connectors[h[i]].optional.port["default"]);var h={RTMP:1935,"RTMP.exe":1935,RTSP:554,"RTSP.exe":554,TS:-1,"TS.exe":-1},k;for(k in f){for(i in mist.data.config.protocols){var l=mist.data.config.protocols[i];
if(l.connector==k){if("port"in l)f[k]=l.port;break}}f[k]=f[k]==h[k]?"":":"+f[k]}f.TS="";f["TS.exe"]="";P.find(".field").closest("label").hide();for(i in f){var r;k=d?d:f[i];switch(i){case "RTMP":case "RTMP.exe":r="rtmp://"+b.host+k+"/"+(e?e:"live")+"/";P.find(".field.RTMPurl").setval(r).closest("label").show();P.find(".field.RTMPkey").setval(a==""?"STREAMNAME":a).closest("label").show();r=r+(a==""?"STREAMNAME":a);break;case "RTSP":case "RTSP.exe":r="rtsp://"+b.host+k+"/"+(a==""?"STREAMNAME":a)+(e? if(l.connector==k){if("port"in l)f[k]=l.port;break}}f[k]=f[k]==h[k]?"":":"+f[k]}f.TS="";f["TS.exe"]="";P.find(".field").closest("label").hide();for(i in f){var q;k=d?d:f[i];switch(i){case "RTMP":case "RTMP.exe":q="rtmp://"+b.host+k+"/"+(e?e:"live")+"/";P.find(".field.RTMPurl").setval(q).closest("label").show();P.find(".field.RTMPkey").setval(a==""?"STREAMNAME":a).closest("label").show();q=q+(a==""?"STREAMNAME":a);break;case "RTSP":case "RTSP.exe":q="rtsp://"+b.host+k+"/"+(a==""?"STREAMNAME":a)+(e?
"?pass="+e:"");break;case "TS":case "TS.exe":r="udp://"+(g==""?b.host:g)+k+"/"}P.find(".field."+i.replace(".exe","")).setval(r).closest("label").show()}}},Ta=$("<div>"),sa={},u=[],Ua=$("<div>");for(q in mist.data.capabilities.processes)u.push([q,mist.data.capabilities.processes[q].hrn?mist.data.capabilities.processes[q].hrn:mist.data.capabilities.processes[q].name]);if(u.length){var jb=[{label:"New process",type:"select",select:u,value:u[0][0],pointer:{main:sa,index:"process"},"function":function(){var a= "?pass="+e:"");break;case "TS":case "TS.exe":q="udp://"+(g==""?b.host:g)+k+"/"}P.find(".field."+i.replace(".exe","")).setval(q).closest("label").show()}}},Ta=$("<div>"),sa={},u=[],Ua=$("<div>");for(r in mist.data.capabilities.processes)u.push([r,mist.data.capabilities.processes[r].hrn?mist.data.capabilities.processes[r].hrn:mist.data.capabilities.processes[r].name]);if(u.length){var jb=[{label:"New process",type:"select",select:u,value:u[0][0],pointer:{main:sa,index:"process"},"function":function(){var a=
$(this).getval();if(a!=null){var a=mist.data.capabilities.processes[a],b=[$("<h4>").text(a.name+" Process options")];Ua.html(UI.buildUI(b.concat(mist.convertBuildOptions(a,sa))))}}},Ua];Ta.append(UI.buildUI([$("<br>"),$("<h3>").text("Stream processes"),{label:"Stream processes",itemLabel:"stream process",type:"sublist",sublist:jb,saveas:sa,pointer:{main:p,index:"processes"}}]))}c.append(UI.buildUI([{label:"Stream name",type:"str",validate:["required","streamname"],pointer:{main:p,index:"name"},help:"Set the name this stream will be recognised by for players and/or stream pushing."}, $(this).getval();if(a!=null){var a=mist.data.capabilities.processes[a],b=[$("<h4>").text(a.name+" Process options")];Ua.html(UI.buildUI(b.concat(mist.convertBuildOptions(a,sa))))}}},Ua];Ta.append(UI.buildUI([$("<br>"),$("<h3>").text("Stream processes"),{label:"Stream processes",itemLabel:"stream process",type:"sublist",sublist:jb,saveas:sa,pointer:{main:p,index:"processes"}}]))}c.append(UI.buildUI([{label:"Stream name",type:"str",validate:["required","streamname"],pointer:{main:p,index:"name"},help:"Set the name this stream will be recognised by for players and/or stream pushing."},
{label:"Source",type:"browse",filetypes:Qa,pointer:{main:p,index:"source"},help:"<p> Below is the explanation of the input methods for MistServer. Anything between brackets () will go to default settings if not specified. </p> <table class=valigntop> <tr> <th colspan=3><b>File inputs</b></th> </tr> <tr> <th>File</th> <td> Linux/MacOS:&nbsp;/PATH/FILE<br> Windows:&nbsp;/cygdrive/DRIVE/PATH/FILE </td> <td> For file input please specify the proper path and file.<br> Supported inputs are: DTSC, FLV, MP3. MistServer Pro has TS, MP4, ISMV added as input. </td> </tr> <th> Folder </th> <td> Linux/MacOS:&nbsp;/PATH/<br> Windows:&nbsp;/cygdrive/DRIVE/PATH/ </td> <td> A folder stream makes all the recognised files in the selected folder available as a stream. </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <tr> <th colspan=3><b>Push inputs</b></th> </tr> <tr> <th>RTMP</th> <td>push://(IP)(@PASSWORD)</td> <td> IP is white listed IP for pushing towards MistServer, if left empty all are white listed.<br> PASSWORD is the application under which to push to MistServer, if it doesn't match the stream will be rejected. PASSWORD is MistServer Pro only. </td> </tr> <tr> <th>RTSP</th> <td>push://(IP)(@PASSWORD)</td> <td>IP is white listed IP for pushing towards MistServer, if left empty all are white listed.</td> </tr> <tr> <th>TS</th> <td>tsudp://(IP):PORT(/INTERFACE)</td> <td> IP is the IP address used to listen for this stream, multi-cast IP range is: 224.0.0.0 - 239.255.255.255. If IP is not set all addresses will listened to.<br> PORT is the port you reserve for this stream on the chosen IP.<br> INTERFACE is the interface used, if left all interfaces will be used. </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <tr> <th colspan=3><b>Pull inputs</b></th> </tr> <tr> <th>DTSC</th> <td>dtsc://MISTSERVER_IP:PORT/(STREAMNAME)</td> <td>MISTSERVER_IP is the IP of another MistServer to pull from.<br> PORT is the DTSC port of the other MistServer. (default is 4200)<br> STREAMNAME is the name of the target stream on the other MistServer. If left empty, the name of this stream will be used. </td> </tr> <tr> <th>HLS</th> <td>http://URL/TO/STREAM.m3u8</td> <td>The URL where the HLS stream is available to MistServer.</td> </tr> <tr> <th>RTSP</th> <td>rtsp://(USER:PASSWORD@)IP(:PORT)(/path)</td> <td> USER:PASSWORD is the account used if authorization is required.<br> IP is the IP address used to pull this stream from.<br> PORT is the port used to connect through.<br> PATH is the path to be used to identify the correct stream. </td> </tr> </table>", {label:"Source",type:"browse",filetypes:Qa,pointer:{main:p,index:"source"},help:"<p> Below is the explanation of the input methods for MistServer. Anything between brackets () will go to default settings if not specified. </p> <table class=valigntop> <tr> <th colspan=3><b>File inputs</b></th> </tr> <tr> <th>File</th> <td> Linux/MacOS:&nbsp;/PATH/FILE<br> Windows:&nbsp;/cygdrive/DRIVE/PATH/FILE </td> <td> For file input please specify the proper path and file.<br> Supported inputs are: DTSC, FLV, MP3. MistServer Pro has TS, MP4, ISMV added as input. </td> </tr> <th> Folder </th> <td> Linux/MacOS:&nbsp;/PATH/<br> Windows:&nbsp;/cygdrive/DRIVE/PATH/ </td> <td> A folder stream makes all the recognised files in the selected folder available as a stream. </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <tr> <th colspan=3><b>Push inputs</b></th> </tr> <tr> <th>RTMP</th> <td>push://(IP)(@PASSWORD)</td> <td> IP is white listed IP for pushing towards MistServer, if left empty all are white listed.<br> PASSWORD is the application under which to push to MistServer, if it doesn't match the stream will be rejected. PASSWORD is MistServer Pro only. </td> </tr> <tr> <th>RTSP</th> <td>push://(IP)(@PASSWORD)</td> <td>IP is white listed IP for pushing towards MistServer, if left empty all are white listed.</td> </tr> <tr> <th>TS</th> <td>tsudp://(IP):PORT(/INTERFACE)</td> <td> IP is the IP address used to listen for this stream, multi-cast IP range is: 224.0.0.0 - 239.255.255.255. If IP is not set all addresses will listened to.<br> PORT is the port you reserve for this stream on the chosen IP.<br> INTERFACE is the interface used, if left all interfaces will be used. </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <tr> <th colspan=3><b>Pull inputs</b></th> </tr> <tr> <th>DTSC</th> <td>dtsc://MISTSERVER_IP:PORT/(STREAMNAME)</td> <td>MISTSERVER_IP is the IP of another MistServer to pull from.<br> PORT is the DTSC port of the other MistServer. (default is 4200)<br> STREAMNAME is the name of the target stream on the other MistServer. If left empty, the name of this stream will be used. </td> </tr> <tr> <th>HLS</th> <td>http://URL/TO/STREAM.m3u8</td> <td>The URL where the HLS stream is available to MistServer.</td> </tr> <tr> <th>RTSP</th> <td>rtsp://(USER:PASSWORD@)IP(:PORT)(/path)</td> <td> USER:PASSWORD is the account used if authorization is required.<br> IP is the IP address used to pull this stream from.<br> PORT is the port used to connect through.<br> PATH is the path to be used to identify the correct stream. </td> </tr> </table>",
"function":function(){var a=$(this).val();Sa.remove();P.html("");if(a!=""){var b=null,d;for(d in mist.data.capabilities.inputs)if(typeof mist.data.capabilities.inputs[d].source_match!="undefined"&&mist.inputMatch(mist.data.capabilities.inputs[d].source_match,a)){b=d;break}if(b===null)fa.html($("<h3>").text("Unrecognized input").addClass("red")).append($("<span>").text("Please edit the stream source.").addClass("red"));else{b=mist.data.capabilities.inputs[b];fa.html($("<h3>").text(b.name+" Input options")); "function":function(){var a=$(this).val();Sa.remove();P.html("");if(a!=""){var b=null,d;for(d in mist.data.capabilities.inputs)if(typeof mist.data.capabilities.inputs[d].source_match!="undefined"&&mist.inputMatch(mist.data.capabilities.inputs[d].source_match,a)){b=d;break}if(b===null)fa.html($("<h3>").text("Unrecognized input").addClass("red")).append($("<span>").text("Please edit the stream source.").addClass("red"));else{b=mist.data.capabilities.inputs[b];fa.html($("<h3>").text(b.name+" Input options"));
var e=mist.convertBuildOptions(b,p);"always_match"in mist.data.capabilities.inputs[d]&&mist.inputMatch(mist.data.capabilities.inputs[d].always_match,a)&&e.push({label:"Always on",type:"checkbox",help:"Keep this input available at all times, even when there are no active viewers.",pointer:{main:p,index:"always_on"}});fa.append(UI.buildUI(e));if(b.name=="Folder")c.append(Sa);else if(["Buffer","Buffer.exe","TS","TS.exe"].indexOf(b.name)>-1){d=[$("<br>"),$("<span>").text("Configure your source to push to:")]; var e=mist.convertBuildOptions(b,p);"always_match"in mist.data.capabilities.inputs[d]&&mist.inputMatch(mist.data.capabilities.inputs[d].always_match,a)&&e.push({label:"Always on",type:"checkbox",help:"Keep this input available at all times, even when there are no active viewers.",pointer:{main:p,index:"always_on"}});fa.append(UI.buildUI(e));if(b.name=="Folder")c.append(Sa);else if(["Buffer","Buffer.exe","TS","TS.exe"].indexOf(b.name)>-1){d=[$("<br>"),$("<span>").text("Configure your source to push to:")];
switch(b.name){case "Buffer":case "Buffer.exe":d.push({label:"RTMP full url",type:"span",clipboard:true,readonly:true,classes:["RTMP"],help:"Use this RTMP url if your client doesn't ask for a stream key"});d.push({label:"RTMP url",type:"span",clipboard:true,readonly:true,classes:["RTMPurl"],help:"Use this RTMP url if your client also asks for a stream key"});d.push({label:"RTMP stream key",type:"span",clipboard:true,readonly:true,classes:["RTMPkey"],help:"Use this key if your client asks for a stream key"}); switch(b.name){case "Buffer":case "Buffer.exe":d.push({label:"RTMP full url",type:"span",clipboard:true,readonly:true,classes:["RTMP"],help:"Use this RTMP url if your client doesn't ask for a stream key"});d.push({label:"RTMP url",type:"span",clipboard:true,readonly:true,classes:["RTMPurl"],help:"Use this RTMP url if your client also asks for a stream key"});d.push({label:"RTMP stream key",type:"span",clipboard:true,readonly:true,classes:["RTMPkey"],help:"Use this key if your client asks for a stream key"});
d.push({label:"RTSP",type:"span",clipboard:true,readonly:true,classes:["RTSP"]});break;case "TS":case "TS.exe":a.charAt(0)=="/"?d=[]:d.push({label:"TS",type:"span",clipboard:true,readonly:true,classes:["TS"]})}P.html(UI.buildUI(d));ra()}}}}},{label:"Stop sessions",type:"checkbox",help:"When saving these stream settings, kill this stream's current connections.",pointer:{main:p,index:"stop_sessions"}},P,$("<br>"),{type:"custom",custom:fa},Ta,{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Streams")}}, d.push({label:"RTSP",type:"span",clipboard:true,readonly:true,classes:["RTSP"]});break;case "TS":case "TS.exe":a.charAt(0)=="/"?d=[]:d.push({label:"TS",type:"span",clipboard:true,readonly:true,classes:["TS"]})}P.html(UI.buildUI(d));ra()}}}}},{label:"Stop sessions",type:"checkbox",help:"When saving these stream settings, kill this stream's current connections.",pointer:{main:p,index:"stop_sessions"}},P,$("<br>"),{type:"custom",custom:fa},Ta,{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Streams")}},
{type:"save",label:"Save","function":function(){Ra("Streams")}},{type:"save",label:"Save and Preview","function":function(){Ra("Preview")},classes:["saveandpreview"]}]}]));c.find("[name=name]").keyup(function(){ra()});ra();break;case "Preview":""==b&&UI.navto("Streams");var Q=parseURL(mist.user.host),W=Q.protocol,T=Q.host,J=":8080",v=W+T+J+"/";for(q in mist.data.config.protocols)if(s=mist.data.config.protocols[q],"HTTP"==s.connector||"HTTP.exe"==s.connector){s.pubaddr&&s.pubaddr.length?"string"== {type:"save",label:"Save","function":function(){Ra("Streams")}},{type:"save",label:"Save and Preview","function":function(){Ra("Preview")},classes:["saveandpreview"]}]}]));c.find("[name=name]").keyup(function(){ra()});ra();break;case "Preview":""==b&&UI.navto("Streams");var Q=parseURL(mist.user.host),W=Q.protocol,T=Q.host,J=":8080",v=W+T+J+"/";for(r in mist.data.config.protocols)if(s=mist.data.config.protocols[r],"HTTP"==s.connector||"HTTP.exe"==s.connector){s.pubaddr&&s.pubaddr.length?"string"==
typeof s.pubaddr?v=s.pubaddr.replace(/\/$/,"")+"/":s.pubaddr.length&&(v=s.pubaddr[0].replace(/\/$/,"")+"/"):(J=s.port?":"+s.port:":8080",v=W+T+J+"/");break}var S=$("<div>").css({display:"flex","flex-flow":"row wrap","flex-shrink":1,"min-width":"auto"}),X="";-1==b.indexOf("+")&&(X=$("<button>").text("Settings").addClass("settings").click(function(){UI.navto("Edit",b)}));c.html($("<div>").addClass("bigbuttons").append(X).append($("<button>").text("Embed").addClass("embed").click(function(){UI.navto("Embed", typeof s.pubaddr?v=s.pubaddr.replace(/\/$/,"")+"/":s.pubaddr.length&&(v=s.pubaddr[0].replace(/\/$/,"")+"/"):(J=s.port?":"+s.port:":8080",v=W+T+J+"/");break}var S=$("<div>").css({display:"flex","flex-flow":"row wrap","flex-shrink":1,"min-width":"auto"}),X="";-1==b.indexOf("+")&&(X=$("<button>").text("Settings").addClass("settings").click(function(){UI.navto("Edit",b)}));c.html($("<div>").addClass("bigbuttons").append(X).append($("<button>").text("Embed").addClass("embed").click(function(){UI.navto("Embed",
b)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Preview of "'+b+'"')).append(S);var K=encodeURIComponent(b),Va=$("<div>").css("flex-shrink","1").css("min-width","auto").css("max-width","100%");S.append(Va);var Wa=$("<div>"),Y=$("<div>").text("Loading player..").css("max-width","100%").css("flex-shrink","1").css("min-width","auto"),ta=$("<div>").addClass("controls");Va.append(Y).append(Wa).append(ta);$("link#devcss").length|| b)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Preview of "'+b+'"')).append(S);var K=encodeURIComponent(b),Va=$("<div>").css("flex-shrink","1").css("min-width","auto").css("max-width","100%");S.append(Va);var Wa=$("<div>"),Y=$("<div>").text("Loading player..").css("max-width","100%").css("flex-shrink","1").css("min-width","auto"),ta=$("<div>").addClass("controls");Va.append(Y).append(Wa).append(ta);$("link#devcss").length||
c.append($("<link>").attr("rel","stylesheet").attr("type","text/css").attr("href",v+"skins/dev.css").attr("id","devcss"));var Xa=function(){Wa.text("");var d=document.createElement("script");c.append(d);d.src=v+"player.js";d.onerror=function(){Y.html($("<p>").append('Failed to load <a href="'+v+'player.js">'+v+"player.js</a>.")).append($("<p>").append("Please check if you've activated the HTTP protocol, if your http port is blocked, or if you're trying to load HTTPS on an HTTP page.")).append($("<button>").text("Reload").css("display", c.append($("<link>").attr("rel","stylesheet").attr("type","text/css").attr("href",v+"skins/dev.css").attr("id","devcss"));var Xa=function(){Wa.text("");var d=document.createElement("script");c.append(d);d.src=v+"player.js";d.onerror=function(){Y.html($("<p>").append('Failed to load <a href="'+v+'player.js">'+v+"player.js</a>.")).append($("<p>").append("Please check if you've activated the HTTP protocol, if your http port is blocked, or if you're trying to load HTTPS on an HTTP page.")).append($("<button>").text("Reload").css("display",
@ -168,20 +168,21 @@ c.append($("<link>").attr("rel","stylesheet").attr("type","text/css").attr("href
style:{"max-width":"30em","flex-flow":"column nowrap"}},{type:"container",classes:["mistvideo-column","mistvideo-devcontrols"],children:[{type:"text",text:"Player control"},{type:"container",classes:["mistvideo-devbuttons"],style:{"flex-wrap":"wrap"},children:[{"if":function(){return!(!this.player||!this.player.api)},then:{type:"button",title:"Reload the video source",label:"Reload video",onclick:function(){this.player.api.load()}}},{type:"button",title:"Build MistVideo again",label:"Reload player", style:{"max-width":"30em","flex-flow":"column nowrap"}},{type:"container",classes:["mistvideo-column","mistvideo-devcontrols"],children:[{type:"text",text:"Player control"},{type:"container",classes:["mistvideo-devbuttons"],style:{"flex-wrap":"wrap"},children:[{"if":function(){return!(!this.player||!this.player.api)},then:{type:"button",title:"Reload the video source",label:"Reload video",onclick:function(){this.player.api.load()}}},{type:"button",title:"Build MistVideo again",label:"Reload player",
onclick:function(){this.reload()}},{type:"button",title:"Switch to the next available player and source combination",label:"Try next combination",onclick:function(){this.nextCombo()}}]},{type:"forcePlayer"},{type:"forceType"},{type:"forceSource"}]},{type:"log"}]}))};if(!(a!="Preview"||!b||b==""||e!=b)){Y[0].addEventListener("initialized",g);Y[0].addEventListener("initializeFailed",g);MistVideoObject.reference=mistPlay(e,{target:Y[0],host:v,skin:"dev",loop:true,MistVideoObject:MistVideoObject})}c[0].removeChild(d)}; onclick:function(){this.reload()}},{type:"button",title:"Switch to the next available player and source combination",label:"Try next combination",onclick:function(){this.nextCombo()}}]},{type:"forcePlayer"},{type:"forceType"},{type:"forceSource"}]},{type:"log"}]}))};if(!(a!="Preview"||!b||b==""||e!=b)){Y[0].addEventListener("initialized",g);Y[0].addEventListener("initializeFailed",g);MistVideoObject.reference=mistPlay(e,{target:Y[0],host:v,skin:"dev",loop:true,MistVideoObject:MistVideoObject})}c[0].removeChild(d)};
MistVideoObject.reference={unload:function(){d.onload=function(){this.parentElement&&this.parentElement.removeChild(this)}}}};Xa();var ua=$("<div>").append($("<h3>").text("Meta information")),ga=$("<span>").text("Loading..");ua.append(ga);var Ya=$("<div>").addClass("process_info");ua.append(Ya);S.append(ua);if(""!=K){$.ajax({type:"GET",url:v+"json_"+K+".js",success:function(a){var b=function(a,b){return"maxbps"in a?UI.format.bytes(a[b],1):b=="maxbps"?UI.format.bytes(a.bps,1):"unknown"},c=a.meta;if(!c|| MistVideoObject.reference={unload:function(){d.onload=function(){this.parentElement&&this.parentElement.removeChild(this)}}}};Xa();var ua=$("<div>").append($("<h3>").text("Meta information")),ga=$("<span>").text("Loading..");ua.append(ga);var Ya=$("<div>").addClass("process_info");ua.append(Ya);S.append(ua);if(""!=K){$.ajax({type:"GET",url:v+"json_"+K+".js",success:function(a){var b=function(a,b){return"maxbps"in a?UI.format.bytes(a[b],1):b=="maxbps"?UI.format.bytes(a.bps,1):"unknown"},c=a.meta;if(!c||
!c.tracks)ga.html("No meta information available.");else{a=[];a.push({label:"Type",type:"span",value:c.live?"Live":"Pre-recorded (VoD)"});"format"in c&&a.push({label:"Format",type:"span",value:c.format});c.live&&a.push({label:"Buffer window",type:"span",value:UI.format.addUnit(c.buffer_window,"ms")});var d={audio:{vheader:"Audio",labels:["Codec","Duration","Avg bitrate","Peak bitrate","Channels","Samplerate","Language","Track index"],content:[]},video:{vheader:"Video",labels:["Codec","Duration","Avg bitrate", !c.tracks)ga.html("No meta information available.");else{a=[];a.push({label:"Type",type:"span",value:c.live?"Live":"Pre-recorded (VoD)"});"format"in c&&a.push({label:"Format",type:"span",value:c.format});c.live&&a.push({label:"Buffer window",type:"span",value:UI.format.addUnit(c.buffer_window,"ms")});var d={audio:{vheader:"Audio",labels:["Codec","Duration","Avg bitrate","Peak bitrate","Channels","Samplerate","Language","Track index",""],content:[]},video:{vheader:"Video",labels:["Codec","Duration",
"Peak bitrate","Size","Framerate","Language","Track index","Has B-Frames"],content:[]},subtitle:{vheader:"Subtitles",labels:["Codec","Duration","Avg bitrate","Peak bitrate","Language","Track index"],content:[]}},e=Object.keys(c.tracks);e.sort(function(a,b){a=a.split("_").pop();b=b.split("_").pop();return a-b});var g=1,f=1,h=1,i;for(i in e){var k=e[i],r=c.tracks[k];switch(r.type){case "audio":d.audio.content.push({header:"Track "+k.split("_").pop(),body:[r.codec,UI.format.duration((r.lastms-r.firstms)/ "Avg bitrate","Peak bitrate","Size","Framerate","Language","Track index","Has B-Frames"],content:[]},subtitle:{vheader:"Subtitles",labels:["Codec","Duration","Avg bitrate","Peak bitrate","Language","Track index","","",""],content:[]},meta:{vheader:"Metadata",labels:["Codec","Duration","Avg bitrate","Peak bitrate","","","","",""],content:[]}},e=Object.keys(c.tracks);e.sort(function(a,b){a=a.split("_").pop();b=b.split("_").pop();return a-b});var g=1,f=1,h=1,i;for(i in e){var k=e[i],q=c.tracks[k];switch(q.type){case "audio":d.audio.content.push({header:"Track "+
1E3)+"<br><span class=description>"+UI.format.duration(r.firstms/1E3)+" to "+UI.format.duration(r.lastms/1E3)+"</span>",b(r,"bps"),b(r,"maxbps"),r.channels,UI.format.addUnit(UI.format.number(r.rate),"Hz"),"language"in r?r.language:"unknown",g]});g++;break;case "video":d.video.content.push({header:"Track "+k.split("_").pop(),body:[r.codec,UI.format.duration((r.lastms-r.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(r.firstms/1E3)+" to "+UI.format.duration(r.lastms/1E3)+"</span>",b(r, k.split("_").pop(),body:[q.codec,UI.format.duration((q.lastms-q.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(q.firstms/1E3)+" to "+UI.format.duration(q.lastms/1E3)+"</span>",b(q,"bps"),b(q,"maxbps"),q.channels,UI.format.addUnit(UI.format.number(q.rate),"Hz"),"language"in q?q.language:"unknown",g,""]});g++;break;case "video":d.video.content.push({header:"Track "+k.split("_").pop(),body:[q.codec,UI.format.duration((q.lastms-q.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(q.firstms/
"bps"),b(r,"maxbps"),UI.format.addUnit(r.width,"x ")+UI.format.addUnit(r.height,"px"),UI.format.addUnit(UI.format.number(r.fpks/1E3),"fps"),"language"in r?r.language:"unknown",f,"bframes"in r?"yes":"no"]});f++;break;case "meta":case "subtitle":if(r.codec=="subtitle"||r.type=="subtitle"){d.subtitle.content.push({header:"Track "+k.split("_").pop(),body:[r.codec,UI.format.duration((r.lastms-r.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(r.firstms/1E3)+" to "+UI.format.duration(r.lastms/ 1E3)+" to "+UI.format.duration(q.lastms/1E3)+"</span>",b(q,"bps"),b(q,"maxbps"),UI.format.addUnit(q.width,"x ")+UI.format.addUnit(q.height,"px"),UI.format.addUnit(UI.format.number(q.fpks/1E3),"fps"),"language"in q?q.language:"unknown",f,"bframes"in q?"yes":"no"]});f++;break;case "meta":case "subtitle":if(q.codec=="subtitle"||q.type=="subtitle"){d.subtitle.content.push({header:"Track "+k.split("_").pop(),body:[q.codec,UI.format.duration((q.lastms-q.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(q.firstms/
1E3)+"</span>",b(r,"bps"),b(r,"maxbps"),"language"in r?r.language:"unknown",h]});h++}}}b=["audio","video","subtitle"];i=$("<div>").css({display:"flex","flex-flow":"row wrap","font-size":"0.9em"});for(k in b)d[b[k]].content.length&&i.append(UI.buildVheaderTable(d[b[k]]).css("width","auto"));a.push($("<span>").text("Tracks:"));a.push(i);ga.html(UI.buildUI(a))}},error:function(){ga.html("Error while retrieving stream info.")}});var Za=function(){var a={proc_list:b};if(!mist.data.capabilities)a.capabilities= 1E3)+" to "+UI.format.duration(q.lastms/1E3)+"</span>",b(q,"bps"),b(q,"maxbps"),"language"in q?q.language:"unknown",h,"","",""]});h++}else d.meta.content.push({header:"Track "+k.split("_").pop(),body:[q.codec,UI.format.duration((q.lastms-q.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(q.firstms/1E3)+" to "+UI.format.duration(q.lastms/1E3)+"</span>",b(q,"bps"),b(q,"maxbps"),"","","","",""]})}}b=["audio","video","subtitle","meta"];i=$("<div>").css({display:"flex","flex-flow":"row wrap",
true;mist.send(function(a){if(a.proc_list){var b=$("<table>").css("width","auto"),c={"Process type:":function(a){return $("<b>").text(a.process)},"Source:":function(a){var b=$("<span>").text(a.source);a.source_tracks&&a.source_tracks.length&&b.append($("<span>").addClass("description").text(" track "+a.source_tracks.slice(0,-2).concat(a.source_tracks.slice(-2).join(" and ")).join(", ")));return b},"Sink:":function(a){var b=$("<span>").text(a.sink);a.sink_tracks&&a.sink_tracks.length&&b.append($("<span>").addClass("description").text(" track "+ "font-size":"0.9em"});for(k in b)d[b[k]].content.length&&i.append(UI.buildVheaderTable(d[b[k]]).css("width","auto"));a.push($("<span>").text("Tracks:"));a.push(i);ga.html(UI.buildUI(a))}},error:function(){ga.html("Error while retrieving stream info.")}});var Za=function(){var a={proc_list:b};if(!mist.data.capabilities)a.capabilities=true;mist.send(function(a){if(a.proc_list){var b=$("<table>").css("width","auto"),c={"Process type:":function(a){return $("<b>").text(a.process)},"Source:":function(a){var b=
a.sink_tracks.slice(0,-2).concat(a.sink_tracks.slice(-2).join(" and ")).join(", ")));return b},"Active for:":function(a){var b=(new Date).setSeconds((new Date).getSeconds()-a.active_seconds);return $("<span>").append($("<span>").text(UI.format.duration(a.active_seconds))).append($("<span>").addClass("description").text(" since "+UI.format.time(b/1E3)))},"Pid:":function(a,b){return b},"Logs:":function(a){var b=$("<div>").text("None.");if(a.logs&&a.logs.length){b.html("").addClass("description").css({overflow:"auto", $("<span>").text(a.source);a.source_tracks&&a.source_tracks.length&&b.append($("<span>").addClass("description").text(" track "+a.source_tracks.slice(0,-2).concat(a.source_tracks.slice(-2).join(" and ")).join(", ")));return b},"Sink:":function(a){var b=$("<span>").text(a.sink);a.sink_tracks&&a.sink_tracks.length&&b.append($("<span>").addClass("description").text(" track "+a.sink_tracks.slice(0,-2).concat(a.sink_tracks.slice(-2).join(" and ")).join(", ")));return b},"Active for:":function(a){var b=
maxHeight:"6em",display:"flex",flexFlow:"column-reverse nowrap"});for(var c in a.logs){var d=a.logs[c];b.prepend($("<div>").append(UI.format.time(d[0])+" ["+d[1]+"] "+d[2]))}}return b},"Additional info:":function(a){var b;if(a.ainfo&&Object.keys(a.ainfo).length){b=$("<table>");for(var c in a.ainfo){var d=mist.data.capabilities.processes[a.process].ainfo[c];d||(d={name:c});b.append($("<tr>").append($("<th>").text(d.name+":")).append($("<td>").html(a.ainfo[c]).append(d.unit?$("<span>").addClass("unit").text(d.unit): (new Date).setSeconds((new Date).getSeconds()-a.active_seconds);return $("<span>").append($("<span>").text(UI.format.duration(a.active_seconds))).append($("<span>").addClass("description").text(" since "+UI.format.time(b/1E3)))},"Pid:":function(a,b){return b},"Logs:":function(a){var b=$("<div>").text("None.");if(a.logs&&a.logs.length){b.html("").addClass("description").css({overflow:"auto",maxHeight:"6em",display:"flex",flexFlow:"column-reverse nowrap"});for(var c in a.logs){var d=a.logs[c];b.prepend($("<div>").append(UI.format.time(d[0])+
"")))}}else b=$("<span>").addClass("description").text("N/A");return b}};Ya.html($("<h4>").text("Stream processes")).append(b);for(var d in c){var e=$("<tr>");b.append(e);e.append($("<th>").text(d).css("vertical-align","top"));for(var g in a.proc_list){$out=c[d](a.proc_list[g],g);e.append($("<td>").html($out).css("vertical-align","top"))}}}},a)};UI.interval.set(function(){Za()},5E3);Za()}break;case "Embed":""==b&&UI.navTo("Streams");X="";-1==b.indexOf("+")&&(X=$("<button>").addClass("settings").text("Settings").click(function(){UI.navto("Edit", " ["+d[1]+"] "+d[2]))}}return b},"Additional info:":function(a){var b;if(a.ainfo&&Object.keys(a.ainfo).length){b=$("<table>");for(var c in a.ainfo){var d=mist.data.capabilities.processes[a.process].ainfo[c];d||(d={name:c});b.append($("<tr>").append($("<th>").text(d.name+":")).append($("<td>").html(a.ainfo[c]).append(d.unit?$("<span>").addClass("unit").text(d.unit):"")))}}else b=$("<span>").addClass("description").text("N/A");return b}};Ya.html($("<h4>").text("Stream processes")).append(b);for(var d in c){var e=
b)}));c.html($("<div>").addClass("bigbuttons").append(X).append($("<button>").text("Preview").addClass("preview").click(function(){UI.navto("Preview",b)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Embed "'+b+'"'));var Z=$("<span>");c.append(Z);var K=encodeURIComponent(b),Q=parseURL(mist.user.host),W=Q.protocol,T=Q.host,J=":8080",aa,ha={},v={http:W+T+J+"/"};for(q in mist.data.config.protocols)if(s=mist.data.config.protocols[q], $("<tr>");b.append(e);e.append($("<th>").text(d).css("vertical-align","top"));for(var g in a.proc_list){$out=c[d](a.proc_list[g],g);e.append($("<td>").html($out).css("vertical-align","top"))}}}},a)};UI.interval.set(function(){Za()},5E3);Za()}break;case "Embed":""==b&&UI.navTo("Streams");X="";-1==b.indexOf("+")&&(X=$("<button>").addClass("settings").text("Settings").click(function(){UI.navto("Edit",b)}));c.html($("<div>").addClass("bigbuttons").append(X).append($("<button>").text("Preview").addClass("preview").click(function(){UI.navto("Preview",
"HTTP"==s.connector||"HTTP.exe"==s.connector)s.pubaddr?("string"==typeof s.pubaddr?v.http=s.pubaddr.replace(/\/$/,"")+"/":s.pubaddr.length&&(v.http=s.pubaddr[0].replace(/\/$/,"")+"/"),ha.http=s.pubaddr):(J=s.port?":"+s.port:":8080",v.http=W+T+J+"/");else if("HTTPS"==s.connector||"HTTPS.exe"==s.connector)s.pubaddr&&s.pubaddr.length?("string"==typeof s.pubaddr?v.https=s.pubaddr.replace(/\/$/,"")+"/":s.pubaddr.length&&(v.https=s.pubaddr[0].replace(/\/$/,"")+"/"),ha.https=s.pubaddr):(aa=s.port?":"+s.port: b)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Embed "'+b+'"'));var Z=$("<span>");c.append(Z);var K=encodeURIComponent(b),Q=parseURL(mist.user.host),W=Q.protocol,T=Q.host,J=":8080",aa,ha={},v={http:W+T+J+"/"};for(r in mist.data.config.protocols)if(s=mist.data.config.protocols[r],"HTTP"==s.connector||"HTTP.exe"==s.connector)s.pubaddr?("string"==typeof s.pubaddr?v.http=s.pubaddr.replace(/\/$/,"")+"/":s.pubaddr.length&&
":4433",v.https="https://"+T+aa+"/");var R=v.http,D={http:v.http};"https"in v&&(D.https=v.https);if(otherhost.host||otherhost.https){R=(otherhost.https&&aa?"https://":"http://")+(otherhost.host?otherhost.host:Q.host)+(otherhost.https&&aa?aa:J)+"/";if(otherhost.host&&("http"in ha||(D.http=parseURL(D.http,{hostname:otherhost.host}).full),"https"in D&&!("https"in ha)))D.https=parseURL(D.https,{hostname:otherhost.host}).full;R=otherhost.https?D.https:D.http}var ba=!1,va={forcePlayer:"",forceType:"",controls:!0, (v.http=s.pubaddr[0].replace(/\/$/,"")+"/"),ha.http=s.pubaddr):(J=s.port?":"+s.port:":8080",v.http=W+T+J+"/");else if("HTTPS"==s.connector||"HTTPS.exe"==s.connector)s.pubaddr&&s.pubaddr.length?("string"==typeof s.pubaddr?v.https=s.pubaddr.replace(/\/$/,"")+"/":s.pubaddr.length&&(v.https=s.pubaddr[0].replace(/\/$/,"")+"/"),ha.https=s.pubaddr):(aa=s.port?":"+s.port:":4433",v.https="https://"+T+aa+"/");var R=v.http,D={http:v.http};"https"in v&&(D.https=v.https);if(otherhost.host||otherhost.https){R=
autoplay:!0,loop:!1,muted:!1,fillSpace:!1,poster:"",urlappend:"",setTracks:{}},n=$.extend({},va),$a=UI.stored.getOpts();"embedoptions"in $a&&(n=$.extend(n,$a.embedoptions,!0),"object"!=typeof n.setTracks&&(n.setTracks={}));var ia={};switch(n.controls){case "stock":ia.controls="stock";break;case !0:ia.controls=1;break;case !1:ia.controls=0}var A=function(){function a(b){switch(typeof b){case "string":return $.isNumeric(b)?b:'"'+b+'"';case "object":return JSON.stringify(b);default:return b}}ba&&UI.stored.saveOpt("embedoptions", (otherhost.https&&aa?"https://":"http://")+(otherhost.host?otherhost.host:Q.host)+(otherhost.https&&aa?aa:J)+"/";if(otherhost.host&&("http"in ha||(D.http=parseURL(D.http,{hostname:otherhost.host}).full),"https"in D&&!("https"in ha)))D.https=parseURL(D.https,{hostname:otherhost.host}).full;R=otherhost.https?D.https:D.http}var ba=!1,va={forcePlayer:"",forceType:"",controls:!0,autoplay:!0,loop:!1,muted:!1,fillSpace:!1,poster:"",urlappend:"",setTracks:{}},n=$.extend({},va),$a=UI.stored.getOpts();"embedoptions"in
n);for(var c=b+"_",d=12,e="";d--;){var g;g=Math.floor(Math.random()*62);g=g<10?g:g<36?String.fromCharCode(g+55):String.fromCharCode(g+61);e=e+g}var c=c+e,d=['target: document.getElementById("'+c+'")'],f;for(f in n)f=="prioritize_type"?n[f]&&n[f]!=""&&d.push("forcePriority: "+JSON.stringify({source:[["type",[n[f]]]]})):f=="monitor_action"?n[f]&&n[f]!=""&&n[f]=="nextCombo"&&d.push('monitor: {\n action: function(){\n this.MistVideo.log("Switching to nextCombo because of poor playback in "+this.MistVideo.source.type+" ("+Math.round(this.vars.score*1000)/10+"%)");\n this.MistVideo.nextCombo();\n }\n }'): $a&&(n=$.extend(n,$a.embedoptions,!0),"object"!=typeof n.setTracks&&(n.setTracks={}));var ia={};switch(n.controls){case "stock":ia.controls="stock";break;case !0:ia.controls=1;break;case !1:ia.controls=0}var A=function(){function a(b){switch(typeof b){case "string":return $.isNumeric(b)?b:'"'+b+'"';case "object":return JSON.stringify(b);default:return b}}ba&&UI.stored.saveOpt("embedoptions",n);for(var c=b+"_",d=12,e="";d--;){var g;g=Math.floor(Math.random()*62);g=g<10?g:g<36?String.fromCharCode(g+
55):String.fromCharCode(g+61);e=e+g}var c=c+e,d=['target: document.getElementById("'+c+'")'],f;for(f in n)f=="prioritize_type"?n[f]&&n[f]!=""&&d.push("forcePriority: "+JSON.stringify({source:[["type",[n[f]]]]})):f=="monitor_action"?n[f]&&n[f]!=""&&n[f]=="nextCombo"&&d.push('monitor: {\n action: function(){\n this.MistVideo.log("Switching to nextCombo because of poor playback in "+this.MistVideo.source.type+" ("+Math.round(this.vars.score*1000)/10+"%)");\n this.MistVideo.nextCombo();\n }\n }'):
n[f]!=va[f]&&(n[f]!=null&&(typeof n[f]!="object"||JSON.stringify(n[f])!=JSON.stringify(va[f])))&&d.push(f+": "+a(n[f]));f=[];f.push('<div class="mistvideo" id="'+c+'">');f.push(" <noscript>");f.push(' <a href="'+(otherhost.https?D.https:D.http)+K+'.html" target="_blank">');f.push(" Click here to play this video");f.push(" </a>");f.push(" </noscript>");f.push(" <script>");f.push(" var a = function(){");f.push(' mistPlay("'+b+'",{');f.push(" "+d.join(",\n "));f.push(" });"); n[f]!=va[f]&&(n[f]!=null&&(typeof n[f]!="object"||JSON.stringify(n[f])!=JSON.stringify(va[f])))&&d.push(f+": "+a(n[f]));f=[];f.push('<div class="mistvideo" id="'+c+'">');f.push(" <noscript>");f.push(' <a href="'+(otherhost.https?D.https:D.http)+K+'.html" target="_blank">');f.push(" Click here to play this video");f.push(" </a>");f.push(" </noscript>");f.push(" <script>");f.push(" var a = function(){");f.push(' mistPlay("'+b+'",{');f.push(" "+d.join(",\n "));f.push(" });");
f.push(" };");f.push(" if (!window.mistplayers) {");f.push(' var p = document.createElement("script");');if("https"in v&&parseURL(v.http).protocol!="https://"){f.push(' if (location.protocol == "https:") { p.src = "'+D.https+'player.js" } ');f.push(' else { p.src = "'+D.http+'player.js" } ')}else f.push(' p.src = "'+R+'player.js"');f.push(" document.head.appendChild(p);");f.push(" p.onload = a;");f.push(" }");f.push(" else { a(); }");f.push(" <\/script>"); f.push(" };");f.push(" if (!window.mistplayers) {");f.push(' var p = document.createElement("script");');if("https"in v&&parseURL(v.http).protocol!="https://"){f.push(' if (location.protocol == "https:") { p.src = "'+D.https+'player.js" } ');f.push(' else { p.src = "'+D.http+'player.js" } ')}else f.push(' p.src = "'+R+'player.js"');f.push(" document.head.appendChild(p);");f.push(" p.onload = a;");f.push(" }");f.push(" else { a(); }");f.push(" <\/script>");
f.push("</div>");return f.join("\n")},wa=$("<span>").text("Loading.."),ab=A(n),U=$("<div>").text("Loading..").css("display","flex").css("flex-flow","column nowrap"),bb="";"https"in v&&(bb=UI.buildUI([{label:"Use HTTPS",type:"checkbox","function":function(){if($(this).getval()!=otherhost.https){otherhost.https=$(this).getval();UI.navto("Embed",b)}},value:otherhost.https}]).find("label"));Z.append($("<span>").addClass("input_container").append($("<label>").addClass("UIelement").append($("<span>").addClass("label").text("Use a different host:")).append($("<span>").addClass("field_container").append($("<input>").attr("type", f.push("</div>");return f.join("\n")},wa=$("<span>").text("Loading.."),ab=A(n),U=$("<div>").text("Loading..").css("display","flex").css("flex-flow","column nowrap"),bb="";"https"in v&&(bb=UI.buildUI([{label:"Use HTTPS",type:"checkbox","function":function(){if($(this).getval()!=otherhost.https){otherhost.https=$(this).getval();UI.navto("Embed",b)}},value:otherhost.https}]).find("label"));Z.append($("<span>").addClass("input_container").append($("<label>").addClass("UIelement").append($("<span>").addClass("label").text("Use a different host:")).append($("<span>").addClass("field_container").append($("<input>").attr("type",
@ -193,9 +194,9 @@ $("<h4>").text("Embed code options (optional)").css("margin-top",0),{type:"help"
$(".embed_code").setval(A(n))},help:"Whether or not the video should play as the page is loaded."},{label:"Loop",type:"checkbox",pointer:{main:n,index:"loop"},"function":function(){n.loop=$(this).getval();$(".embed_code").setval(A(n))},help:"If the video should restart when the end is reached."},{label:"Start muted",type:"checkbox",pointer:{main:n,index:"muted"},"function":function(){n.muted=$(this).getval();$(".embed_code").setval(A(n))},help:"If the video should restart when the end is reached."}, $(".embed_code").setval(A(n))},help:"Whether or not the video should play as the page is loaded."},{label:"Loop",type:"checkbox",pointer:{main:n,index:"loop"},"function":function(){n.loop=$(this).getval();$(".embed_code").setval(A(n))},help:"If the video should restart when the end is reached."},{label:"Start muted",type:"checkbox",pointer:{main:n,index:"muted"},"function":function(){n.muted=$(this).getval();$(".embed_code").setval(A(n))},help:"If the video should restart when the end is reached."},
{label:"Fill available space",type:"checkbox",pointer:{main:n,index:"fillSpace"},"function":function(){n.fillSpace=$(this).getval();$(".embed_code").setval(A(n))},help:"The video will fit the available space in its container, even if the video stream has a smaller resolution."},{label:"Poster",type:"str",pointer:{main:n,index:"poster"},"function":function(){n.poster=$(this).getval();$(".embed_code").setval(A(n))},help:"URL to an image that is displayed when the video is not playing."},{label:"Video URL addition", {label:"Fill available space",type:"checkbox",pointer:{main:n,index:"fillSpace"},"function":function(){n.fillSpace=$(this).getval();$(".embed_code").setval(A(n))},help:"The video will fit the available space in its container, even if the video stream has a smaller resolution."},{label:"Poster",type:"str",pointer:{main:n,index:"poster"},"function":function(){n.poster=$(this).getval();$(".embed_code").setval(A(n))},help:"URL to an image that is displayed when the video is not playing."},{label:"Video URL addition",
type:"str",pointer:{main:n,index:"urlappend"},help:"The embed script will append this string to the video url, useful for sending through params.",classes:["embed_code_forceprotocol"],"function":function(){n.urlappend=$(this).getval();$(".embed_code").setval(A(n))}},{label:"Preselect tracks",type:"DOMfield",DOMfield:U,help:"Pre-select these tracks."},{label:"Monitoring action",type:"select",select:[["","Ask the viewer what to do"],["nextCombo","Try the next source / player combination"]],pointer:{main:n, type:"str",pointer:{main:n,index:"urlappend"},help:"The embed script will append this string to the video url, useful for sending through params.",classes:["embed_code_forceprotocol"],"function":function(){n.urlappend=$(this).getval();$(".embed_code").setval(A(n))}},{label:"Preselect tracks",type:"DOMfield",DOMfield:U,help:"Pre-select these tracks."},{label:"Monitoring action",type:"select",select:[["","Ask the viewer what to do"],["nextCombo","Try the next source / player combination"]],pointer:{main:n,
index:"monitor_action"},"function":function(){n.monitor_action=$(this).getval();$(".embed_code").setval(A(n))},help:"What the player should do when playback is poor."},$("<h3>").text("Protocol stream urls"),wa]));$.ajax({type:"GET",url:R+"json_"+K+".js",success:function(a){var b=[],c=Z.find(".field.forceType"),d=Z.find(".field.prioritize_type"),e;for(e in a.source){var f=a.source[e],g=UI.humanMime(f.type);b.push({label:g?g+" <span class=description>("+f.type+")</span>":UI.format.capital(f.type),type:"str", index:"monitor_action"},"function":function(){n.monitor_action=$(this).getval();$(".embed_code").setval(A(n))},help:"What the player should do when playback is poor."},$("<h3>").text("Protocol stream urls"),wa]));$.ajax({type:"GET",url:R+"json_"+K+".js?inclzero=1",success:function(a){var b=[],c=Z.find(".field.forceType"),d=Z.find(".field.prioritize_type"),e;for(e in a.source){var f=a.source[e],g=UI.humanMime(f.type);b.push({label:g?g+" <span class=description>("+f.type+")</span>":UI.format.capital(f.type),
value:f.url,readonly:true,qrcode:true,clipboard:true});g=UI.humanMime(f.type);if(c.children('option[value="'+f.type+'"]').length==0){c.append($("<option>").text(g?g+" ("+f.type+")":UI.format.capital(f.type)).val(f.type));d.append($("<option>").text(g?g+" ("+f.type+")":UI.format.capital(f.type)).val(f.type))}}c.val(n.forceType);d.val(n.prioritize_type);wa.html(UI.buildUI(b));U.html("");b={};for(e in a.meta.tracks){c=a.meta.tracks[e];if(c.codec=="subtitle")c.type="subtitle";if(!(c.type!="audio"&&c.type!= type:"str",value:f.url,readonly:true,qrcode:true,clipboard:true});g=UI.humanMime(f.type);if(c.children('option[value="'+f.type+'"]').length==0){c.append($("<option>").text(g?g+" ("+f.type+")":UI.format.capital(f.type)).val(f.type));d.append($("<option>").text(g?g+" ("+f.type+")":UI.format.capital(f.type)).val(f.type))}}c.val(n.forceType);d.val(n.prioritize_type);wa.html(UI.buildUI(b));U.html("");b={};if(a.meta)for(e in a.meta.tracks){c=a.meta.tracks[e];if(c.codec=="subtitle")c.type="subtitle";if(!(c.type!=
"video"&&c.type!="subtitle")){c.type in b||(b[c.type]=c.type=="subtitle"?[]:[["","Autoselect "+c.type]]);b[c.type].push([c.trackid,UI.format.capital(c.type)+" track "+(b[c.type].length+(c.type=="subtitle"?1:0))])}}if(Object.keys(b).length){U.closest("label").show();var a=["audio","video","subtitle"],h;for(h in a){e=a[h];if(b[e]&&b[e].length){c=$("<select>").attr("data-type",e).css("flex-grow","1").change(function(){$(this).val()==""?delete n.setTracks[$(this).attr("data-type")]:n.setTracks[$(this).attr("data-type")]= "audio"&&c.type!="video"&&c.type!="subtitle")){c.type in b||(b[c.type]=c.type=="subtitle"?[]:[["","Autoselect "+c.type]]);b[c.type].push([c.trackid,UI.format.capital(c.type)+" track "+(b[c.type].length+(c.type=="subtitle"?1:0))])}}if(Object.keys(b).length){U.closest("label").show();var a=["audio","video","subtitle"],h;for(h in a){e=a[h];if(b[e]&&b[e].length){c=$("<select>").attr("data-type",e).css("flex-grow","1").change(function(){$(this).val()==""?delete n.setTracks[$(this).attr("data-type")]:n.setTracks[$(this).attr("data-type")]=
$(this).val();$(".embed_code").setval(A(n))});U.append(c);e=="subtitle"?b[e].unshift(["","No "+e]):b[e].push([-1,"No "+e]);for(var i in b[e])c.append($("<option>").val(b[e][i][0]).text(b[e][i][1]));if(e in n.setTracks){c.val(n.setTracks[e]);if(c.val()==null){c.val("");delete n.setTracks[e];$(".embed_code").setval(A(n))}}}}}else U.closest("label").hide();ba=true},error:function(){wa.html("Error while retrieving stream info.");U.closest("label").hide();n.setTracks={}}});var ja=document.createElement("script"); $(this).val();$(".embed_code").setval(A(n))});U.append(c);e=="subtitle"?b[e].unshift(["","No "+e]):b[e].push([-1,"No "+e]);for(var i in b[e])c.append($("<option>").val(b[e][i][0]).text(b[e][i][1]));if(e in n.setTracks){c.val(n.setTracks[e]);if(c.val()==null){c.val("");delete n.setTracks[e];$(".embed_code").setval(A(n))}}}}}else U.closest("label").hide();ba=true},error:function(){wa.html("Error while retrieving stream info.");U.closest("label").hide();n.setTracks={}}});var ja=document.createElement("script");
ja.src=v.http+"player.js";document.head.appendChild(ja);ja.onload=function(){var a=Z.find(".field.forcePlayer"),b;for(b in mistplayers)a.append($("<option>").text(mistplayers[b].name).val(b));document.head.removeChild(this)};ja.onerror=function(){document.head.removeChild(this)};break;case "Push":var L=$("<div>").text("Loading..");c.append(L);mist.send(function(a){function b(a){setTimeout(function(){mist.send(function(c){var d=false;if("push_list"in c&&c.push_list&&c.push_list.length){var d=true, ja.src=v.http+"player.js";document.head.appendChild(ja);ja.onload=function(){var a=Z.find(".field.forcePlayer"),b;for(b in mistplayers)a.append($("<option>").text(mistplayers[b].name).val(b));document.head.removeChild(this)};ja.onerror=function(){document.head.removeChild(this)};break;case "Push":var L=$("<div>").text("Loading..");c.append(L);mist.send(function(a){function b(a){setTimeout(function(){mist.send(function(c){var d=false;if("push_list"in c&&c.push_list&&c.push_list.length){var d=true,
f;for(f in c.push_list)if(a.indexOf(c.push_list[f][0])>-1){d=false;break}}else d=true;if(d)for(f in a)e.find("tr[data-pushid="+a[f]+"]").remove();else b()},{push_list:1})},1E3)}function c(f,g){var h=$("<span>"),i=$("<span>");if(g=="Automatic"&&f.length>=4){var k=function(a,b,c){a=""+("$"+a+" ");switch(Number(b)){case 0:a=a+"is true";break;case 1:a=a+"is false";break;case 2:a=a+("== "+c);break;case 3:a=a+("!= "+c);break;case 10:a=a+("> (numerical) "+c);break;case 11:a=a+(">= (numerical) "+c);break; f;for(f in c.push_list)if(a.indexOf(c.push_list[f][0])>-1){d=false;break}}else d=true;if(d)for(f in a)e.find("tr[data-pushid="+a[f]+"]").remove();else b()},{push_list:1})},1E3)}function c(f,g){var h=$("<span>"),i=$("<span>");if(g=="Automatic"&&f.length>=4){var k=function(a,b,c){a=""+("$"+a+" ");switch(Number(b)){case 0:a=a+"is true";break;case 1:a=a+"is false";break;case 2:a=a+("== "+c);break;case 3:a=a+("!= "+c);break;case 10:a=a+("> (numerical) "+c);break;case 11:a=a+(">= (numerical) "+c);break;
@ -214,7 +215,7 @@ var f={},g;for(g in a.push_list)if((c==""||a.push_list[g][1]==c)&&(d==""||a.push
e.find("tr").first();e.empty();e.append(b);for(var d in a.push_list)e.append(c(a.push_list[d]))},{push_list:1})},5E3)},{push_settings:1,push_list:1,push_auto_list:1});break;case "Start Push":if(!("capabilities"in mist.data)||!("variable_list"in mist.data)||!("external_writer_list"in mist.data)){c.append("Loading Mist capabilities..");mist.send(function(){UI.navto("Start Push",b)},{capabilities:1,variable_list:!0,external_writer_list:!0});return}var y,ka=function(a){var d=false,f=b.split("_");b=f[0]; e.find("tr").first();e.empty();e.append(b);for(var d in a.push_list)e.append(c(a.push_list[d]))},{push_list:1})},5E3)},{push_settings:1,push_list:1,push_auto_list:1});break;case "Start Push":if(!("capabilities"in mist.data)||!("variable_list"in mist.data)||!("external_writer_list"in mist.data)){c.append("Loading Mist capabilities..");mist.send(function(){UI.navto("Start Push",b)},{capabilities:1,variable_list:!0,external_writer_list:!0});return}var y,ka=function(a){var d=false,f=b.split("_");b=f[0];
f.length==2&&(d=f[1]);if(d!==false&&typeof a=="undefined")mist.send(function(a){ka(a.push_auto_list[d])},{push_auto_list:1});else{var e=[],g=[],h={},i=[],k;for(k in mist.data.capabilities.connectors){f=mist.data.capabilities.connectors[k];if("push_urls"in f){h[k]=f.push_urls;for(var l in f.push_urls)f.push_urls[l][0]=="/"?e.push(f.push_urls[l]):g.push(f.push_urls[l])}}if(mist.data.external_writer_list)for(k in mist.data.external_writer_list){f=mist.data.external_writer_list[k];if(f.length>=3)for(l in f[2])i.push(f[2][l]+ f.length==2&&(d=f[1]);if(d!==false&&typeof a=="undefined")mist.send(function(a){ka(a.push_auto_list[d])},{push_auto_list:1});else{var e=[],g=[],h={},i=[],k;for(k in mist.data.capabilities.connectors){f=mist.data.capabilities.connectors[k];if("push_urls"in f){h[k]=f.push_urls;for(var l in f.push_urls)f.push_urls[l][0]=="/"?e.push(f.push_urls[l]):g.push(f.push_urls[l])}}if(mist.data.external_writer_list)for(k in mist.data.external_writer_list){f=mist.data.external_writer_list[k];if(f.length>=3)for(l in f[2])i.push(f[2][l]+
"://")}e.sort();g.sort();b=="auto"&&c.find("h2").text("Add automatic push");var j={params:{}},m=[];if(b=="auto"&&typeof a!="undefined"){j={stream:a[0],target:a[1],params:{}};l=j.target.split("?");if(l.length>1){m=l.pop();j.target=l.join("?");m=m.split("&");for(k in m){l=m[k].split("=");j.params[l.shift()]=l.join("=")}}if(a.length>=3)j.scheduletime=a[2]!=0?a[2]:null;if(a.length>=4)j.completetime=a[3]!=0?a[3]:null;if(a.length>=5)j.startVariableName=a[4]!=""?a[4]:null;if(a.length>=6)j.startVariableOperator= "://")}e.sort();g.sort();b=="auto"&&c.find("h2").text("Add automatic push");var j={params:{}},m=[];if(b=="auto"&&typeof a!="undefined"){j={stream:a[0],target:a[1],params:{}};l=j.target.split("?");if(l.length>1){m=l.pop();j.target=l.join("?");m=m.split("&");for(k in m){l=m[k].split("=");j.params[l.shift()]=l.join("=")}}if(a.length>=3)j.scheduletime=a[2]!=0?a[2]:null;if(a.length>=4)j.completetime=a[3]!=0?a[3]:null;if(a.length>=5)j.startVariableName=a[4]!=""?a[4]:null;if(a.length>=6)j.startVariableOperator=
a[5]!=""?a[5]:null;if(a.length>=7)j.startVariableValue=a[6]!=""?a[6]:null;if(a.length>=8)j.endVariableName=a[7]!=""?a[7]:null;if(a.length>=9)j.endVariableOperator=a[8]!=""?a[8]:null;if(a.length>=10)j.endVariableValue=a[9]!=""?a[9]:null}var q=$("<div>").css("margin","1em 0"),n=$("<div>"),o;if(b=="auto"){n.css("margin","1em 0").html(UI.buildUI([{label:"This push should be active",help:"When 'based on server time' is selected, a start and/or end timestamp can be configured. When it's 'based on a variable', the push will be activated while the specified variable matches the specified value.", a[5]!=""?a[5]:null;if(a.length>=7)j.startVariableValue=a[6]!=""?a[6]:null;if(a.length>=8)j.endVariableName=a[7]!=""?a[7]:null;if(a.length>=9)j.endVariableOperator=a[8]!=""?a[8]:null;if(a.length>=10)j.endVariableValue=a[9]!=""?a[9]:null}var r=$("<div>").css("margin","1em 0"),n=$("<div>"),o;if(b=="auto"){n.css("margin","1em 0").html(UI.buildUI([{label:"This push should be active",help:"When 'based on server time' is selected, a start and/or end timestamp can be configured. When it's 'based on a variable', the push will be activated while the specified variable matches the specified value.",
type:"select",select:[["time","Based on server time"],["variable","Based on a variable"]],value:j.startVariableName||j.endVariableName?"variable":"time",classes:["activewhen"],"function":function(){var a=n.find(".varbased").closest(".UIelement"),b=n.find(".timebased").closest(".UIelement");if($(this).getval()=="time"){a.hide();b.css("display","")}else{b.hide();a.css("display","");n.find('[name="startVariableOperator"]').trigger("change");n.find('[name="endVariableOperator"]').trigger("change")}}}, type:"select",select:[["time","Based on server time"],["variable","Based on a variable"]],value:j.startVariableName||j.endVariableName?"variable":"time",classes:["activewhen"],"function":function(){var a=n.find(".varbased").closest(".UIelement"),b=n.find(".timebased").closest(".UIelement");if($(this).getval()=="time"){a.hide();b.css("display","")}else{b.hide();a.css("display","");n.find('[name="startVariableOperator"]').trigger("change");n.find('[name="endVariableOperator"]').trigger("change")}}},
$("<br>"),$("<span>").addClass("UIelement").append($("<h3>").text("Start the push").addClass("varbased")),{classes:["varbased"],label:"Use this variable",type:"str",help:"This variable should be used to determine if this push should be started.",prefix:"$",datalist:Object.keys(mist.data.variable_list||[]),pointer:{main:j,index:"startVariableName"}},{classes:["varbased"],label:"Comparison operator",type:"select",select:[[0,"is true"],[1,"is false"],[2,"=="],[3,"!="],[10,"> (numerical)"],[11,">= (numerical)"], $("<br>"),$("<span>").addClass("UIelement").append($("<h3>").text("Start the push").addClass("varbased")),{classes:["varbased"],label:"Use this variable",type:"str",help:"This variable should be used to determine if this push should be started.",prefix:"$",datalist:Object.keys(mist.data.variable_list||[]),pointer:{main:j,index:"startVariableName"}},{classes:["varbased"],label:"Comparison operator",type:"select",select:[[0,"is true"],[1,"is false"],[2,"=="],[3,"!="],[10,"> (numerical)"],[11,">= (numerical)"],
[12,"< (numerical)"],[13,"<= (numerical)"],[20,"> (lexical)"],[21,">= (lexical)"],[22,"< (lexical)"],[23,"<= (lexical)"]],value:2,css:{display:"none"},help:"How would you like to compare this variable?",pointer:{main:j,index:"startVariableOperator"},"function":function(){var a=n.find('[name="startVariableValue"]').closest(".UIelement");Number($(this).getval())<2?a.hide():a.css("display","")}},{classes:["varbased"],label:"Variable value",type:"str",help:"The variable will be compared with this value to determine if this push should be started.<br>You can also enter another variable here!", [12,"< (numerical)"],[13,"<= (numerical)"],[20,"> (lexical)"],[21,">= (lexical)"],[22,"< (lexical)"],[23,"<= (lexical)"]],value:2,css:{display:"none"},help:"How would you like to compare this variable?",pointer:{main:j,index:"startVariableOperator"},"function":function(){var a=n.find('[name="startVariableValue"]').closest(".UIelement");Number($(this).getval())<2?a.hide():a.css("display","")}},{classes:["varbased"],label:"Variable value",type:"str",help:"The variable will be compared with this value to determine if this push should be started.<br>You can also enter another variable here!",
@ -226,18 +227,18 @@ help:"This may either be a full stream name, a partial wildcard stream name, or
pointer:{main:j,index:"stream"},validate:["required",function(a){a=a.split("+");a=a[0];return a in mist.data.streams?false:{msg:"'"+a+"' is not a stream name.",classes:["orange"],"break":false}}],datalist:y},{label:"Target",type:"str",help:"Where the stream will be pushed to.<br> Valid push formats: <ul> <li>"+g.join("</li><li>")+"</li> </ul> Valid file formats: <ul> <li>"+e.join("</li><li>")+ pointer:{main:j,index:"stream"},validate:["required",function(a){a=a.split("+");a=a[0];return a in mist.data.streams?false:{msg:"'"+a+"' is not a stream name.",classes:["orange"],"break":false}}],datalist:y},{label:"Target",type:"str",help:"Where the stream will be pushed to.<br> Valid push formats: <ul> <li>"+g.join("</li><li>")+"</li> </ul> Valid file formats: <ul> <li>"+e.join("</li><li>")+
"</li> </ul> "+(i.length?"Additionally, the following protocols (from generic writers) may be used in combination with any of the above file formats:<ul><li>"+i.join("</li><li>")+"</li></ul>":"")+" Valid text replacements: <ul> <li>$stream - inserts the stream name used to push to MistServer</li> <li>$day - inserts the current day number</li><li>$month - inserts the current month number</li> <li>$year - inserts the current year number</li><li>$hour - inserts the hour timestamp when stream was received</li> <li>$minute - inserts the minute timestamp the stream was received</li> <li>$seconds - inserts the seconds timestamp when the stream was received</li> <li>$datetime - inserts $year.$month.$day.$hour.$minute.$seconds timestamp when the stream was received</li> </ul>", "</li> </ul> "+(i.length?"Additionally, the following protocols (from generic writers) may be used in combination with any of the above file formats:<ul><li>"+i.join("</li><li>")+"</li></ul>":"")+" Valid text replacements: <ul> <li>$stream - inserts the stream name used to push to MistServer</li> <li>$day - inserts the current day number</li><li>$month - inserts the current month number</li> <li>$year - inserts the current year number</li><li>$hour - inserts the hour timestamp when stream was received</li> <li>$minute - inserts the minute timestamp the stream was received</li> <li>$seconds - inserts the seconds timestamp when the stream was received</li> <li>$datetime - inserts $year.$month.$day.$hour.$minute.$seconds timestamp when the stream was received</li> </ul>",
pointer:{main:j,index:"target"},validate:["required",function(a){for(var b in g)if(mist.inputMatch(g[b],a))return false;for(b in e){if(mist.inputMatch(e[b],a))return false;for(var c in i)if(mist.inputMatch(i[c]+e[b].slice(1),a))return false}return{msg:"Does not match a valid target.<br>Valid push formats: <ul> <li>"+g.join("</li><li>")+"</li> </ul> Valid file formats: <ul> <li>"+e.join("</li><li>")+ pointer:{main:j,index:"target"},validate:["required",function(a){for(var b in g)if(mist.inputMatch(g[b],a))return false;for(b in e){if(mist.inputMatch(e[b],a))return false;for(var c in i)if(mist.inputMatch(i[c]+e[b].slice(1),a))return false}return{msg:"Does not match a valid target.<br>Valid push formats: <ul> <li>"+g.join("</li><li>")+"</li> </ul> Valid file formats: <ul> <li>"+e.join("</li><li>")+
"</li> </ul> "+(i.length?"Additionally, the following protocols may be used in combination with any of the above file formats:<ul><li>"+i.join("</li><li>")+"</li></ul>":""),classes:["red"]}}],"function":function(){var a=false,b=$(this).getval();for(connector in h)for(var c in h[connector]){if(mist.inputMatch(h[connector][c],b)){a=connector;break}if(h[connector][c][0]=="/")for(var d in i)if(mist.inputMatch(i[d]+h[connector][c].slice(1),b)){a=connector;break}}if(a){q.html($("<h3>").text(mist.data.capabilities.connectors[a].friendly.replace("over HTTP", "</li> </ul> "+(i.length?"Additionally, the following protocols may be used in combination with any of the above file formats:<ul><li>"+i.join("</li><li>")+"</li></ul>":""),classes:["red"]}}],"function":function(){var a=false,b=$(this).getval();for(connector in h)for(var c in h[connector]){if(mist.inputMatch(h[connector][c],b)){a=connector;break}if(h[connector][c][0]=="/")for(var d in i)if(mist.inputMatch(i[d]+h[connector][c].slice(1),b)){a=connector;break}}if(a){r.html($("<h3>").text(mist.data.capabilities.connectors[a].friendly.replace("over HTTP",
"")));o={};for(c in mist.data.capabilities.connectors[a].push_parameters){d=mist.data.capabilities.connectors[a].push_parameters[c];if(!d.prot_only||!(String().match&&b.match(/.+\:\/\/.+/)===null))d.file_only&&b[0]!="/"||(o[c]=d)}a={desc:mist.data.capabilities.connectors[a].desc.replace("over HTTP",""),optional:o,sort:"sort"};a=mist.convertBuildOptions(a,j.params);b=[];for(c in m){d=m[c].split("=");var f=d[0];f in o||b.push(f+(d.length>1?"="+d.slice(1).join("="):""))}a.push($("<br>"));a.push({type:"inputlist", "")));o={};for(c in mist.data.capabilities.connectors[a].push_parameters){d=mist.data.capabilities.connectors[a].push_parameters[c];if(!d.prot_only||!(String().match&&b.match(/.+\:\/\/.+/)===null))d.file_only&&b[0]!="/"||(o[c]=d)}a={desc:mist.data.capabilities.connectors[a].desc.replace("over HTTP",""),optional:o,sort:"sort"};a=mist.convertBuildOptions(a,j.params);b=[];for(c in m){d=m[c].split("=");var f=d[0];f in o||b.push(f+(d.length>1?"="+d.slice(1).join("="):""))}a.push($("<br>"));a.push({type:"inputlist",
label:"Custom url parameters",value:b,classes:["custom_url_parameters"],input:{type:"str",placeholder:"name=value",prefix:""},help:"Any custom url parameters not covered by the parameters configurable above.",pointer:{main:j,index:"custom_url_params"}});q.append(UI.buildUI(a))}else q.html($("<h4>").addClass("red").text("Unrecognized target.")).append($("<span>").text("Please edit the push target."))}},n,q];k.push({type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Push")}}, label:"Custom url parameters",value:b,classes:["custom_url_parameters"],input:{type:"str",placeholder:"name=value",prefix:""},help:"Any custom url parameters not covered by the parameters configurable above.",pointer:{main:j,index:"custom_url_params"}});r.append(UI.buildUI(a))}else r.html($("<h4>").addClass("red").text("Unrecognized target.")).append($("<span>").text("Please edit the push target."))}},n,r];k.push({type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Push")}},
{type:"save",label:"Save",preSave:function(){delete j.startVariableName;delete j.startVariableOperator;delete j.startVariableValue;delete j.endVariableName;delete j.endVariableOperator;delete j.endVariableValue;delete j.completetime;delete j.scheduletime},"function":function(){var c=j.params,d;for(d in c)c[d]===null?delete c[d]:d in o||delete c[d];if(j.startVariableName||j.endVariableName){j.scheduletime=0;j.completetime=0}if(j.startVariableName===null){delete j.startVariableName;delete j.startVariableOperator; {type:"save",label:"Save",preSave:function(){delete j.startVariableName;delete j.startVariableOperator;delete j.startVariableValue;delete j.endVariableName;delete j.endVariableOperator;delete j.endVariableValue;delete j.completetime;delete j.scheduletime},"function":function(){var c=j.params,d;for(d in c)c[d]===null?delete c[d]:d in o||delete c[d];if(j.startVariableName||j.endVariableName){j.scheduletime=0;j.completetime=0}if(j.startVariableName===null){delete j.startVariableName;delete j.startVariableOperator;
delete j.startVariableValue}if(j.endVariableName===null){delete j.endVariableName;delete j.endVariableOperator;delete j.endVariableValue}if(j.scheduletime)c.recstartunix=j.scheduletime;if(Object.keys(c).length||j.custom_url_params&&j.custom_url_params.length){var f="?",e=j.target.split("?");if(e.length>1){f="&";e=e[e.length-1];e=e.split("&");for(d in e){var g=e[d].split("=")[0];g in c&&delete c[g]}}if(Object.keys(c).length||j.custom_url_params&&j.custom_url_params.length){e=[];for(d in c)e.push(d+ delete j.startVariableValue}if(j.endVariableName===null){delete j.endVariableName;delete j.endVariableOperator;delete j.endVariableValue}if(j.scheduletime)c.recstartunix=j.scheduletime;if(Object.keys(c).length||j.custom_url_params&&j.custom_url_params.length){var f="?",e=j.target.split("?");if(e.length>1){f="&";e=e[e.length-1];e=e.split("&");for(d in e){var g=e[d].split("=")[0];g in c&&delete c[g]}}if(Object.keys(c).length||j.custom_url_params&&j.custom_url_params.length){e=[];for(d in c)e.push(d+
"="+c[d]);for(d in j.custom_url_params)e.push(j.custom_url_params[d]);f=f+e.join("&");j.target=j.target+f}}delete j.params;delete j.custom_url_params;c={};c[b=="auto"?"push_auto_add":"push_start"]=j;if(typeof a!="undefined"&&(a[0]!=j.stream||a[1]!=j.target))c.push_auto_remove=[a];mist.send(function(){UI.navto("Push")},c)}}]});c.append(UI.buildUI(k))}};mist.data.LTS?mist.send(function(a){(y=a.active_streams)||(y=[]);var a=[],b;for(b in y)y[b].indexOf("+")!=-1&&a.push(y[b].replace(/\+.*/,"")+"+");y= "="+c[d]);for(d in j.custom_url_params)e.push(j.custom_url_params[d]);f=f+e.join("&");j.target=j.target+f}}delete j.params;delete j.custom_url_params;c={};c[b=="auto"?"push_auto_add":"push_start"]=j;if(typeof a!="undefined"&&(a[0]!=j.stream||a[1]!=j.target))c.push_auto_remove=[a];mist.send(function(){UI.navto("Push")},c)}}]});c.append(UI.buildUI(k))}};mist.data.LTS?mist.send(function(a){(y=a.active_streams)||(y=[]);var a=[],b;for(b in y)y[b].indexOf("+")!=-1&&a.push(y[b].replace(/\+.*/,"")+"+");y=
y.concat(a);var c=0,d=0;for(b in mist.data.streams){y.push(b);if(mist.inputMatch(UI.findInput("Folder").source_match,mist.data.streams[b].source)){y.push(b+"+");mist.send(function(a,b){var f=b.stream,e;for(e in a.browse.files)for(var g in mist.data.capabilities.inputs)g.indexOf("Buffer")>=0||(g.indexOf("Folder")>=0||g.indexOf("Buffer.exe")>=0||g.indexOf("Folder.exe")>=0)||mist.inputMatch(mist.data.capabilities.inputs[g].source_match,"/"+a.browse.files[e])&&y.push(f+"+"+a.browse.files[e]);d++;if(c== y.concat(a);var c=0,d=0;for(b in mist.data.streams){y.push(b);if(mist.inputMatch(UI.findInput("Folder").source_match,mist.data.streams[b].source)){y.push(b+"+");mist.send(function(a,b){var f=b.stream,e;for(e in a.browse.files)for(var g in mist.data.capabilities.inputs)g.indexOf("Buffer")>=0||(g.indexOf("Folder")>=0||g.indexOf("Buffer.exe")>=0||g.indexOf("Folder.exe")>=0)||mist.inputMatch(mist.data.capabilities.inputs[g].source_match,"/"+a.browse.files[e])&&y.push(f+"+"+a.browse.files[e]);d++;if(c==
d){y=y.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();ka()}},{browse:mist.data.streams[b].source},{stream:b});c++}}if(c==d){y=y.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();ka()}},{active_streams:1}):(y=Object.keys(mist.data.streams),ka());break;case "Triggers":if(!("triggers"in mist.data.config)||!mist.data.config.triggers)mist.data.config.triggers={};var F=$("<tbody>"),cb=$("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Trigger on").attr("data-sort-type", d){y=y.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();ka()}},{browse:mist.data.streams[b].source},{stream:b});c++}}if(c==d){y=y.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();ka()}},{active_streams:1}):(y=Object.keys(mist.data.streams),ka());break;case "Triggers":if(!("triggers"in mist.data.config)||!mist.data.config.triggers)mist.data.config.triggers={};var F=$("<tbody>"),cb=$("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Trigger on").attr("data-sort-type",
"string").addClass("sorting-asc")).append($("<th>").text("Applies to").attr("data-sort-type","string")).append($("<th>").text("Handler").attr("data-sort-type","string")).append($("<th>")))).append(F);c.append(UI.buildUI([{type:"help",help:"Triggers are a way to react to events that occur inside MistServer. These allow you to block specific users, redirect streams, keep tabs on what is being pushed where, etcetera. For full documentation, please refer to the developer documentation section on the MistServer website."}])).append($("<button>").text("New trigger").click(function(){UI.navto("Edit Trigger")})).append(cb); "string").addClass("sorting-asc")).append($("<th>").text("Applies to").attr("data-sort-type","string")).append($("<th>").text("Handler").attr("data-sort-type","string")).append($("<th>")))).append(F);c.append(UI.buildUI([{type:"help",help:"Triggers are a way to react to events that occur inside MistServer. These allow you to block specific users, redirect streams, keep tabs on what is being pushed where, etcetera. For full documentation, please refer to the developer documentation section on the MistServer website."}])).append($("<button>").text("New trigger").click(function(){UI.navto("Edit Trigger")})).append(cb);
cb.stupidtable();var xa=mist.data.config.triggers;for(q in xa)for(var db in xa[q]){var ya=triggerRewrite(xa[q][db]);F.append($("<tr>").attr("data-index",q+","+db).append($("<td>").text(q)).append($("<td>").text("streams"in ya?ya.streams.join(", "):"")).append($("<td>").text(ya.handler)).append($("<td>").html($("<button>").text("Edit").click(function(){UI.navto("Edit Trigger",$(this).closest("tr").attr("data-index"))})).append($("<button>").text("Delete").click(function(){var a=$(this).closest("tr").attr("data-index").split(","); cb.stupidtable();var xa=mist.data.config.triggers;for(r in xa)for(var db in xa[r]){var ya=triggerRewrite(xa[r][db]);F.append($("<tr>").attr("data-index",r+","+db).append($("<td>").text(r)).append($("<td>").text("streams"in ya?ya.streams.join(", "):"")).append($("<td>").text(ya.handler)).append($("<td>").html($("<button>").text("Edit").click(function(){UI.navto("Edit Trigger",$(this).closest("tr").attr("data-index"))})).append($("<button>").text("Delete").click(function(){var a=$(this).closest("tr").attr("data-index").split(",");
if(confirm("Are you sure you want to delete this "+a[0]+" trigger?")){mist.data.config.triggers[a[0]].splice(a[1],1);mist.data.config.triggers[a[0]].length==0&&delete mist.data.config.triggers[a[0]];mist.send(function(){UI.navto("Triggers")},{config:mist.data.config})}}))))}break;case "Edit Trigger":if(!("triggers"in mist.data.config)||!mist.data.config.triggers)mist.data.config.triggers={};if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,b)},{capabilities:!0});c.append("Loading.."); if(confirm("Are you sure you want to delete this "+a[0]+" trigger?")){mist.data.config.triggers[a[0]].splice(a[1],1);mist.data.config.triggers[a[0]].length==0&&delete mist.data.config.triggers[a[0]];mist.send(function(){UI.navto("Triggers")},{config:mist.data.config})}}))))}break;case "Edit Trigger":if(!("triggers"in mist.data.config)||!mist.data.config.triggers)mist.data.config.triggers={};if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,b)},{capabilities:!0});c.append("Loading..");
return}if(b)var b=b.split(","),ca=triggerRewrite(mist.data.config.triggers[b[0]][b[1]]),p={triggeron:b[0],appliesto:ca.streams,url:ca.handler,async:ca.sync,"default":ca["default"],params:ca.params};else c.html($("<h2>").text("New Trigger")),p={};var eb=[];for(q in mist.data.capabilities.triggers)eb.push([q,q+": "+mist.data.capabilities.triggers[q].when]);var za=$("<div>").addClass("desc"),fb=$("<div>");c.append(UI.buildUI([{label:"Trigger on",pointer:{main:p,index:"triggeron"},help:"For what event this trigger should activate.", return}if(b)var b=b.split(","),ca=triggerRewrite(mist.data.config.triggers[b[0]][b[1]]),p={triggeron:b[0],appliesto:ca.streams,url:ca.handler,async:ca.sync,"default":ca["default"],params:ca.params};else c.html($("<h2>").text("New Trigger")),p={};var eb=[];for(r in mist.data.capabilities.triggers)eb.push([r,r+": "+mist.data.capabilities.triggers[r].when]);var za=$("<div>").addClass("desc"),fb=$("<div>");c.append(UI.buildUI([{label:"Trigger on",pointer:{main:p,index:"triggeron"},help:"For what event this trigger should activate.",
type:"select",select:eb,validate:["required"],"function":function(){var a=$(this).getval(),b=mist.data.capabilities.triggers[a];za.html("");if(b){a=[$("<h4>").text("Trigger properties"),{type:"help",help:'The trigger "<i>'+a+'</i>" has the following properties:'},{type:"span",label:"Triggers",value:b.when,help:"When this trigger is activated"}];b.payload!=""&&a.push({label:"Payload",type:"textarea",value:b.payload,rows:b.payload.split("\n").length,readonly:true,clipboard:true,help:"The information this trigger sends to the handler."}); type:"select",select:eb,validate:["required"],"function":function(){var a=$(this).getval(),b=mist.data.capabilities.triggers[a];za.html("");if(b){a=[$("<h4>").text("Trigger properties"),{type:"help",help:'The trigger "<i>'+a+'</i>" has the following properties:'},{type:"span",label:"Triggers",value:b.when,help:"When this trigger is activated"}];b.payload!=""&&a.push({label:"Payload",type:"textarea",value:b.payload,rows:b.payload.split("\n").length,readonly:true,clipboard:true,help:"The information this trigger sends to the handler."});
a.push({type:"span",label:"Requires response",value:function(a){switch(a){case "ignored":return"No. The trigger will ignore the response of the handler.";case "always":return"Yes. The trigger needs a response to proceed.";case "when-blocking":return"The trigger needs a response to proceed if it is configured to be blocking.";default:return a}}(b.response),help:"Whether this trigger requires a response from the trigger handler"});a.push({type:"span",label:"Response action",value:b.response_action, a.push({type:"span",label:"Requires response",value:function(a){switch(a){case "ignored":return"No. The trigger will ignore the response of the handler.";case "always":return"Yes. The trigger needs a response to proceed.";case "when-blocking":return"The trigger needs a response to proceed if it is configured to be blocking.";default:return a}}(b.response),help:"Whether this trigger requires a response from the trigger handler"});a.push({type:"span",label:"Response action",value:b.response_action,
help:"What this trigger will do with its handler's response"});za.append(UI.buildUI(a));b.stream_specific?$("[name=appliesto]").closest(".UIelement").show():$("[name=appliesto]").setval([]).closest(".UIelement").hide();if(b.argument){$("[name=params]").closest(".UIelement").show();fb.text(b.argument)}else $("[name=params]").setval("").closest(".UIelement").hide()}}},za,$("<h4>").text("Trigger settings"),{label:"Applies to",pointer:{main:p,index:"appliesto"},help:"For triggers that can apply to specific streams, this value decides what streams they are triggered for. (none checked = always triggered)", help:"What this trigger will do with its handler's response"});za.append(UI.buildUI(a));b.stream_specific?$("[name=appliesto]").closest(".UIelement").show():$("[name=appliesto]").setval([]).closest(".UIelement").hide();if(b.argument){$("[name=params]").closest(".UIelement").show();fb.text(b.argument)}else $("[name=params]").setval("").closest(".UIelement").hide()}}},za,$("<h4>").text("Trigger settings"),{label:"Applies to",pointer:{main:p,index:"appliesto"},help:"For triggers that can apply to specific streams, this value decides what streams they are triggered for. (none checked = always triggered)",
@ -247,15 +248,15 @@ pointer:{main:p,index:"async"}},{label:"Parameters",type:"str",help:$("<div>").t
mist.send(function(){Aa();gb.text("Refresh now")})}).css("padding","0.2em 0.5em").css("flex-grow",0);c.append(UI.buildUI([{type:"help",help:"Here you have an overview of all edited settings within MistServer and possible warnings or errors MistServer has encountered. MistServer stores up to 100 logs at a time."},{label:"Refresh every",type:"select",select:[[10,"10 seconds"],[30,"30 seconds"],[60,"minute"],[300,"5 minutes"]],value:30,"function":function(){UI.interval.clear();UI.interval.set(function(){mist.send(function(){Aa()})}, mist.send(function(){Aa();gb.text("Refresh now")})}).css("padding","0.2em 0.5em").css("flex-grow",0);c.append(UI.buildUI([{type:"help",help:"Here you have an overview of all edited settings within MistServer and possible warnings or errors MistServer has encountered. MistServer stores up to 100 logs at a time."},{label:"Refresh every",type:"select",select:[[10,"10 seconds"],[30,"30 seconds"],[60,"minute"],[300,"5 minutes"]],value:30,"function":function(){UI.interval.clear();UI.interval.set(function(){mist.send(function(){Aa()})},
$(this).val()*1E3)},help:"How often the table below should be updated."},{label:"..or",type:"DOMfield",DOMfield:gb,help:"Instantly refresh the table below."}]));c.append($("<button>").text("Purge logs").click(function(){mist.send(function(){mist.data.log=[];UI.navto("Logs")},{clearstatlogs:true})}));F=$("<tbody>").css("font-size","0.9em");c.append($("<table>").addClass("logs").append(F));var kb=function(a){var b=$("<span>").text(a);switch(a){case "WARN":b.addClass("orange");break;case "ERROR":case "FAIL":b.addClass("red")}return b}, $(this).val()*1E3)},help:"How often the table below should be updated."},{label:"..or",type:"DOMfield",DOMfield:gb,help:"Instantly refresh the table below."}]));c.append($("<button>").text("Purge logs").click(function(){mist.send(function(){mist.data.log=[];UI.navto("Logs")},{clearstatlogs:true})}));F=$("<tbody>").css("font-size","0.9em");c.append($("<table>").addClass("logs").append(F));var kb=function(a){var b=$("<span>").text(a);switch(a){case "WARN":b.addClass("orange");break;case "ERROR":case "FAIL":b.addClass("red")}return b},
Aa=function(){var a=mist.data.log;if(a){a.length>=2&&a[0][0]<a[a.length-1][0]&&a.reverse();F.html("");for(var b in a){var c=$("<span>").addClass("content"),d=a[b][2].split("|"),f;for(f in d)c.append($("<span>").text(d[f]));F.append($("<tr>").html($("<td>").text(UI.format.dateTime(a[b][0],"long")).css("white-space","nowrap")).append($("<td>").html(kb(a[b][1])).css("text-align","center")).append($("<td>").html(c).css("text-align","left")))}}};Aa();break;case "Statistics":var H=$("<span>").text("Loading.."); Aa=function(){var a=mist.data.log;if(a){a.length>=2&&a[0][0]<a[a.length-1][0]&&a.reverse();F.html("");for(var b in a){var c=$("<span>").addClass("content"),d=a[b][2].split("|"),f;for(f in d)c.append($("<span>").text(d[f]));F.append($("<tr>").html($("<td>").text(UI.format.dateTime(a[b][0],"long")).css("white-space","nowrap")).append($("<td>").html(kb(a[b][1])).css("text-align","center")).append($("<td>").html(c).css("text-align","left")))}}};Aa();break;case "Statistics":var H=$("<span>").text("Loading..");
c.append(H);var p={graph:"new"},B=mist.stored.get().graphs?$.extend(!0,{},mist.stored.get().graphs):{},da={};for(q in mist.data.streams)da[q]=!0;for(q in mist.data.active_streams)da[mist.data.active_streams[q]]=!0;var da=Object.keys(da).sort(),Ba=[];for(q in mist.data.config.protocols)Ba.push(mist.data.config.protocols[q].connector);Ba.sort();mist.send(function(){UI.plot.datatype.templates.cpuload.cores=0;for(var a in mist.data.capabilities.cpu)UI.plot.datatype.templates.cpuload.cores=UI.plot.datatype.templates.cpuload.cores+ c.append(H);var p={graph:"new"},B=mist.stored.get().graphs?$.extend(!0,{},mist.stored.get().graphs):{},da={};for(r in mist.data.streams)da[r]=!0;for(r in mist.data.active_streams)da[mist.data.active_streams[r]]=!0;var da=Object.keys(da).sort(),Ba=[];for(r in mist.data.config.protocols)Ba.push(mist.data.config.protocols[r].connector);Ba.sort();mist.send(function(){UI.plot.datatype.templates.cpuload.cores=0;for(var a in mist.data.capabilities.cpu)UI.plot.datatype.templates.cpuload.cores=UI.plot.datatype.templates.cpuload.cores+
mist.data.capabilities.cpu[a].cores;H.html(UI.buildUI([{type:"help",help:"Here you will find the MistServer stream statistics, you can select various categories yourself. All statistics are live: up to five minutes are saved."},$("<h3>").text("Select the data to display"),{label:"Add to",type:"select",select:[["new","New graph"]],pointer:{main:p,index:"graph"},classes:["graph_ids"],"function":function(){if($(this).val()){var a=H.find(".graph_xaxis"),b=H.find(".graph_id");if($(this).val()=="new"){a.children("option").prop("disabled", mist.data.capabilities.cpu[a].cores;H.html(UI.buildUI([{type:"help",help:"Here you will find the MistServer stream statistics, you can select various categories yourself. All statistics are live: up to five minutes are saved."},$("<h3>").text("Select the data to display"),{label:"Add to",type:"select",select:[["new","New graph"]],pointer:{main:p,index:"graph"},classes:["graph_ids"],"function":function(){if($(this).val()){var a=H.find(".graph_xaxis"),b=H.find(".graph_id");if($(this).val()=="new"){a.children("option").prop("disabled",
false);b.setval("Graph "+(Object.keys(B).length+1)).closest("label").show()}else{var c=B[$(this).val()].xaxis;a.children("option").prop("disabled",true).filter('[value="'+c+'"]').prop("disabled",false);b.closest("label").hide()}a.children('option[value="'+a.val()+'"]:disabled').length&&a.val(a.children("option:enabled").first().val());a.trigger("change")}}},{label:"Graph id",type:"str",pointer:{main:p,index:"id"},classes:["graph_id"],validate:[function(a){return a in B?{msg:"This graph id has already been used. Please enter something else.", false);b.setval("Graph "+(Object.keys(B).length+1)).closest("label").show()}else{var c=B[$(this).val()].xaxis;a.children("option").prop("disabled",true).filter('[value="'+c+'"]').prop("disabled",false);b.closest("label").hide()}a.children('option[value="'+a.val()+'"]:disabled').length&&a.val(a.children("option:enabled").first().val());a.trigger("change")}}},{label:"Graph id",type:"str",pointer:{main:p,index:"id"},classes:["graph_id"],validate:[function(a){return a in B?{msg:"This graph id has already been used. Please enter something else.",
classes:["red"]}:false}]},{label:"Axis type",type:"select",select:[["time","Time line"]],pointer:{main:p,index:"xaxis"},value:"time",classes:["graph_xaxis"],"function":function(){$s=H.find(".graph_datatype");switch($(this).getval()){case "coords":$s.children("option").prop("disabled",true).filter('[value="coords"]').prop("disabled",false);break;case "time":$s.children("option").prop("disabled",false).filter('[value="coords"]').prop("disabled",true)}if(!$s.val()||$s.children('option[value="'+$s.val()+ classes:["red"]}:false}]},{label:"Axis type",type:"select",select:[["time","Time line"]],pointer:{main:p,index:"xaxis"},value:"time",classes:["graph_xaxis"],"function":function(){$s=H.find(".graph_datatype");switch($(this).getval()){case "coords":$s.children("option").prop("disabled",true).filter('[value="coords"]').prop("disabled",false);break;case "time":$s.children("option").prop("disabled",false).filter('[value="coords"]').prop("disabled",true)}if(!$s.val()||$s.children('option[value="'+$s.val()+
'"]:disabled').length){$s.val($s.children("option:enabled").first().val());$s.trigger("change")}}},{label:"Data type",type:"select",select:[["clients","Connections"],["upbps","Bandwidth (up)"],["downbps","Bandwidth (down)"],["cpuload","CPU use"],["memload","Memory load"],["coords","Client location"],["perc_lost","Lost packages"],["perc_retrans","Re-transmitted packages"]],pointer:{main:p,index:"datatype"},classes:["graph_datatype"],"function":function(){$s=H.find(".graph_origin");switch($(this).getval()){case "cpuload":case "memload":$s.find("input[type=radio]").not('[value="total"]').prop("disabled", '"]:disabled').length){$s.val($s.children("option:enabled").first().val());$s.trigger("change")}}},{label:"Data type",type:"select",select:[["clients","Connections"],["upbps","Bandwidth (up)"],["downbps","Bandwidth (down)"],["cpuload","CPU use"],["memload","Memory load"],["coords","Client location"],["perc_lost","Lost packages"],["perc_retrans","Re-transmitted packages"]],pointer:{main:p,index:"datatype"},classes:["graph_datatype"],"function":function(){$s=H.find(".graph_origin");switch($(this).getval()){case "cpuload":case "memload":$s.find("input[type=radio]").not('[value="total"]').prop("disabled",
true);$s.find('input[type=radio][value="total"]').prop("checked",true);break;default:$s.find("input[type=radio]").prop("disabled",false)}}},{label:"Data origin",type:"radioselect",radioselect:[["total","All"],["stream","The stream:",da],["protocol","The protocol:",Ba]],pointer:{main:p,index:"origin"},value:["total"],classes:["graph_origin"]},{type:"buttons",buttons:[{label:"Add data set",type:"save","function":function(){var a;if(p.graph=="new"){a=UI.plot.addGraph(p,b);B[a.id]=a;H.find("input.graph_id").val(""); true);$s.find('input[type=radio][value="total"]').prop("checked",true);break;default:$s.find("input[type=radio]").prop("disabled",false)}}},{label:"Data origin",type:"radioselect",radioselect:[["total","All"],["stream","The stream:",da],["protocol","The protocol:",Ba]],pointer:{main:p,index:"origin"},value:["total"],classes:["graph_origin"]},{type:"buttons",buttons:[{label:"Add data set",type:"save","function":function(){var a;if(p.graph=="new"){a=UI.plot.addGraph(p,b);B[a.id]=a;H.find("input.graph_id").val("");
H.find("select.graph_ids").append($("<option>").text(a.id)).val(a.id).trigger("change")}else a=B[p.graph];var c=UI.plot.datatype.getOptions({datatype:p.datatype,origin:p.origin});a.datasets.push(c);UI.plot.save(a);UI.plot.go(B)}}]}]));var b=$("<div>").addClass("graph_container");c.append(b);var d=H.find("select.graph_ids");for(a in B){var f=UI.plot.addGraph(B[a],b);d.append($("<option>").text(f.id)).val(f.id);var e=[],g;for(g in B[a].datasets){var h=UI.plot.datatype.getOptions({datatype:B[a].datasets[g].datatype, H.find("select.graph_ids").append($("<option>").text(a.id)).val(a.id).trigger("change")}else a=B[p.graph];var c=UI.plot.datatype.getOptions({datatype:p.datatype,origin:p.origin});a.datasets.push(c);UI.plot.save(a);UI.plot.go(B)}}]}]));var b=$("<div>").addClass("graph_container");c.append(b);var d=H.find("select.graph_ids");for(a in B){var f=UI.plot.addGraph(B[a],b);d.append($("<option>").text(f.id)).val(f.id);var e=[],g;for(g in B[a].datasets){var h=UI.plot.datatype.getOptions({datatype:B[a].datasets[g].datatype,
origin:B[a].datasets[g].origin});e.push(h)}f.datasets=e;B[f.id]=f}d.trigger("change");UI.plot.go(B);UI.interval.set(function(){UI.plot.go(B)},1E4)},{active_streams:!0,capabilities:!0});break;case "Server Stats":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a)},{capabilities:!0});c.append("Loading..");return}var Ca=$("<table>"),O=$("<table>"),hb={vheader:"CPUs",labels:["Model","Processor speed","Amount of cores","Amount of threads"],content:[]};for(q in mist.data.capabilities.cpu){var la= origin:B[a].datasets[g].origin});e.push(h)}f.datasets=e;B[f.id]=f}d.trigger("change");UI.plot.go(B);UI.interval.set(function(){UI.plot.go(B)},1E4)},{active_streams:!0,capabilities:!0});break;case "Server Stats":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a)},{capabilities:!0});c.append("Loading..");return}var Ca=$("<table>"),O=$("<table>"),hb={vheader:"CPUs",labels:["Model","Processor speed","Amount of cores","Amount of threads"],content:[]};for(r in mist.data.capabilities.cpu){var la=
mist.data.capabilities.cpu[q];hb.content.push({header:"CPU #"+(Number(q)+1),body:[la.model,UI.format.addUnit(UI.format.number(la.mhz),"MHz"),la.cores,la.threads]})}var lb=UI.buildVheaderTable(hb),ib=function(){var a=mist.data.capabilities.mem,b=mist.data.capabilities.load,a={vheader:"Memory",labels:["Used","Cached","Available","Total"],content:[{header:"Physical memory",body:[UI.format.bytes(a.used*1048576)+" ("+UI.format.addUnit(b.memory,"%")+")",UI.format.bytes(a.cached*1048576),UI.format.bytes(a.free* mist.data.capabilities.cpu[r];hb.content.push({header:"CPU #"+(Number(r)+1),body:[la.model,UI.format.addUnit(UI.format.number(la.mhz),"MHz"),la.cores,la.threads]})}var lb=UI.buildVheaderTable(hb),ib=function(){var a=mist.data.capabilities.mem,b=mist.data.capabilities.load,a={vheader:"Memory",labels:["Used","Cached","Available","Total"],content:[{header:"Physical memory",body:[UI.format.bytes(a.used*1048576)+" ("+UI.format.addUnit(b.memory,"%")+")",UI.format.bytes(a.cached*1048576),UI.format.bytes(a.free*
1048576),UI.format.bytes(a.total*1048576)]},{header:"Swap memory",body:[UI.format.bytes((a.swaptotal-a.swapfree)*1048576),UI.format.addUnit("","N/A"),UI.format.bytes(a.swapfree*1048576),UI.format.bytes(a.swaptotal*1048576)]}]},a=UI.buildVheaderTable(a);Ca.replaceWith(a);Ca=a;b={vheader:"Load average",labels:["CPU use","1 minute","5 minutes","15 minutes"],content:[{header:"&nbsp;",body:[UI.format.addUnit(UI.format.number(mist.data.capabilities.cpu_use/10),"%"),UI.format.number(b.one/100),UI.format.number(b.five/ 1048576),UI.format.bytes(a.total*1048576)]},{header:"Swap memory",body:[UI.format.bytes((a.swaptotal-a.swapfree)*1048576),UI.format.addUnit("","N/A"),UI.format.bytes(a.swapfree*1048576),UI.format.bytes(a.swaptotal*1048576)]}]},a=UI.buildVheaderTable(a);Ca.replaceWith(a);Ca=a;b={vheader:"Load average",labels:["CPU use","1 minute","5 minutes","15 minutes"],content:[{header:"&nbsp;",body:[UI.format.addUnit(UI.format.number(mist.data.capabilities.cpu_use/10),"%"),UI.format.number(b.one/100),UI.format.number(b.five/
100),UI.format.number(b.fifteen/100)]}]};b=UI.buildVheaderTable(b);O.replaceWith(b);O=b};ib();c.append(UI.buildUI([{type:"help",help:"You can find general server statistics here. Note that memory and CPU usage is for your entire machine, not just MistServer."}])).append($("<table>").css("width","auto").addClass("nolay").append($("<tr>").append($("<td>").append(Ca)).append($("<td>").append(O))).append($("<tr>").append($("<td>").append(lb).attr("colspan",2))));UI.interval.set(function(){mist.send(function(){ib()}, 100),UI.format.number(b.fifteen/100)]}]};b=UI.buildVheaderTable(b);O.replaceWith(b);O=b};ib();c.append(UI.buildUI([{type:"help",help:"You can find general server statistics here. Note that memory and CPU usage is for your entire machine, not just MistServer."}])).append($("<table>").css("width","auto").addClass("nolay").append($("<tr>").append($("<td>").append(Ca)).append($("<td>").append(O))).append($("<tr>").append($("<td>").append(lb).attr("colspan",2))));UI.interval.set(function(){mist.send(function(){ib()},
{capabilities:true})},3E4);break;case "Email for Help":var I=$.extend({},mist.data);delete I.statistics;delete I.totals;delete I.clients;delete I.capabilities;I=JSON.stringify(I);I="Version: "+mist.data.config.version+"\n\nConfig:\n"+I;p={};c.append(UI.buildUI([{type:"help",help:"You can use this form to email MistServer support if you're having difficulties.<br>A copy of your server config file will automatically be included."},{type:"str",label:"Your name",validate:["required"],pointer:{main:p, {capabilities:true})},3E4);break;case "Email for Help":var I=$.extend({},mist.data);delete I.statistics;delete I.totals;delete I.clients;delete I.capabilities;I=JSON.stringify(I);I="Version: "+mist.data.config.version+"\n\nConfig:\n"+I;p={};c.append(UI.buildUI([{type:"help",help:"You can use this form to email MistServer support if you're having difficulties.<br>A copy of your server config file will automatically be included."},{type:"str",label:"Your name",validate:["required"],pointer:{main:p,

View file

@ -4932,7 +4932,7 @@ var UI = {
var tables = { var tables = {
audio: { audio: {
vheader: 'Audio', vheader: 'Audio',
labels: ['Codec','Duration','Avg bitrate','Peak bitrate','Channels','Samplerate','Language','Track index'], labels: ['Codec','Duration','Avg bitrate','Peak bitrate','Channels','Samplerate','Language','Track index',""],
content: [] content: []
}, },
video: { video: {
@ -4942,7 +4942,12 @@ var UI = {
}, },
subtitle: { subtitle: {
vheader: 'Subtitles', vheader: 'Subtitles',
labels: ['Codec','Duration','Avg bitrate','Peak bitrate','Language','Track index'], labels: ['Codec','Duration','Avg bitrate','Peak bitrate','Language','Track index',"","",""],
content: []
},
meta: {
vheader: 'Metadata',
labels: ['Codec','Duration','Avg bitrate','Peak bitrate',"","","","",""],
content: [] content: []
} }
} }
@ -4979,7 +4984,8 @@ var UI = {
track.channels, track.channels,
UI.format.addUnit(UI.format.number(track.rate),'Hz'), UI.format.addUnit(UI.format.number(track.rate),'Hz'),
('language' in track ? track.language : 'unknown'), ('language' in track ? track.language : 'unknown'),
(trackindex.audio) (trackindex.audio),
""
] ]
}); });
trackindex.audio++; trackindex.audio++;
@ -5012,15 +5018,29 @@ var UI = {
peakoravg(track,"bps"), peakoravg(track,"bps"),
peakoravg(track,"maxbps"), peakoravg(track,"maxbps"),
('language' in track ? track.language : 'unknown'), ('language' in track ? track.language : 'unknown'),
(trackindex.subtitle) (trackindex.subtitle),
"","",""
] ]
}); });
trackindex.subtitle++ trackindex.subtitle++
break; break;
} }
else {
tables.meta.content.push({
header: 'Track '+i.split('_').pop(),
body: [
track.codec,
UI.format.duration((track.lastms-track.firstms)/1000)+'<br><span class=description>'+UI.format.duration(track.firstms/1000)+' to '+UI.format.duration(track.lastms/1000)+'</span>',
peakoravg(track,"bps"),
peakoravg(track,"maxbps"),
"","","","",""
]
});
break;
}
} }
} }
var tracktypes = ['audio','video','subtitle']; var tracktypes = ['audio','video','subtitle','meta'];
var $c = $('<div>').css({ var $c = $('<div>').css({
'display': 'flex', 'display': 'flex',
'flex-flow': 'row wrap', 'flex-flow': 'row wrap',
@ -5603,7 +5623,7 @@ var UI = {
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: otherbase+'json_'+escapedstream+'.js', url: otherbase+'json_'+escapedstream+'.js?inclzero=1',
success: function(d) { success: function(d) {
var build = []; var build = [];
@ -5637,22 +5657,24 @@ var UI = {
$setTracks.html(''); $setTracks.html('');
var tracks = {}; var tracks = {};
for (var i in d.meta.tracks) { if (d.meta) {
var t = d.meta.tracks[i]; for (var i in d.meta.tracks) {
if (t.codec == "subtitle") { var t = d.meta.tracks[i];
t.type = "subtitle"; if (t.codec == "subtitle") {
} t.type = "subtitle";
if ((t.type != 'audio') && (t.type != 'video') && (t.type != "subtitle")) { continue; } }
if ((t.type != 'audio') && (t.type != 'video') && (t.type != "subtitle")) { continue; }
if (!(t.type in tracks)) { if (!(t.type in tracks)) {
if (t.type == "subtitle") { if (t.type == "subtitle") {
tracks[t.type] = []; tracks[t.type] = [];
} }
else { else {
tracks[t.type] = [[(''),"Autoselect "+t.type]]; tracks[t.type] = [[(''),"Autoselect "+t.type]];
}
} }
tracks[t.type].push([t.trackid,UI.format.capital(t.type)+' track '+(tracks[t.type].length+(t.type == "subtitle" ? 1 : 0))]);
} }
tracks[t.type].push([t.trackid,UI.format.capital(t.type)+' track '+(tracks[t.type].length+(t.type == "subtitle" ? 1 : 0))]);
} }
if (Object.keys(tracks).length) { if (Object.keys(tracks).length) {
$setTracks.closest('label').show(); $setTracks.closest('label').show();