LSP: dont remove the autopush that is being edited if stream and target havent changed; dont use TS output port for stream push hint

This commit is contained in:
Cat 2017-11-07 12:58:12 +01:00
parent a2961866b5
commit 7da2327e44
2 changed files with 109 additions and 99 deletions

View file

@ -109,94 +109,95 @@ y[g]=W(g,mist.data.streams[b]);y[g].source=mist.data.streams[b].source+a.browse.
true);la++;Y==la&&mist.send(function(){for(var a in mist.data.active_streams){var b=mist.data.active_streams[a].split("+");if(b.length>1&&b[0]in mist.data.streams){s[mist.data.active_streams[a]]=true;y[mist.data.active_streams[a]]=W(mist.data.active_streams[a],mist.data.streams[b[0]])}}s=Object.keys(s);s=s.concat(Object.keys(mist.data.streams));s.sort();X(c,s,ma)},{active_streams:true})},{browse:mist.data.streams[e].source},{stream:e}),Y++;0==Y&&mist.send(function(){for(var a in mist.data.active_streams){var b= true);la++;Y==la&&mist.send(function(){for(var a in mist.data.active_streams){var b=mist.data.active_streams[a].split("+");if(b.length>1&&b[0]in mist.data.streams){s[mist.data.active_streams[a]]=true;y[mist.data.active_streams[a]]=W(mist.data.active_streams[a],mist.data.streams[b[0]])}}s=Object.keys(s);s=s.concat(Object.keys(mist.data.streams));s.sort();X(c,s,ma)},{active_streams:true})},{browse:mist.data.streams[e].source},{stream:e}),Y++;0==Y&&mist.send(function(){for(var a in mist.data.active_streams){var b=
mist.data.active_streams[a].split("+");if(b.length>1&&b[0]in mist.data.streams){s[mist.data.active_streams[a]]=true;y[mist.data.active_streams[a]]=W(mist.data.active_streams[a],mist.data.streams[b[0]])}}s=Object.keys(s);mist.data.streams&&(s=s.concat(Object.keys(mist.data.streams)));s.sort();X(c,s)},{active_streams:!0})}else X(c,Object.keys(mist.data.streams));break;case "Edit":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,c)},{capabilities:!0});d.append("Loading.."); mist.data.active_streams[a].split("+");if(b.length>1&&b[0]in mist.data.streams){s[mist.data.active_streams[a]]=true;y[mist.data.active_streams[a]]=W(mist.data.active_streams[a],mist.data.streams[b[0]])}}s=Object.keys(s);mist.data.streams&&(s=s.concat(Object.keys(mist.data.streams)));s.sort();X(c,s)},{active_streams:!0})}else X(c,Object.keys(mist.data.streams));break;case "Edit":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,c)},{capabilities:!0});d.append("Loading..");
return}E=!1;""!=c&&(E=!0);E?(g=c,n=mist.data.streams[g],d.find("h2").append(' "'+g+'"')):(d.html($("<h2>").text("New Stream")),n={});g=[];for(f in mist.data.capabilities.inputs)g.push(mist.data.capabilities.inputs[f].source_match);var R=$("<div>"),na=function(a){var b={};if(!mist.data.streams)mist.data.streams={};mist.data.streams[n.name]=n;c!=n.name&&delete mist.data.streams[c];b.addstream={};b.addstream[n.name]=n;if(c!=n.name)b.deletestream=[c];if(n.stop_sessions&&c!=""){b.stop_sessions=c;delete n.stop_sessions}mist.send(function(){delete mist.data.streams[n.name].online; return}E=!1;""!=c&&(E=!0);E?(g=c,n=mist.data.streams[g],d.find("h2").append(' "'+g+'"')):(d.html($("<h2>").text("New Stream")),n={});g=[];for(f in mist.data.capabilities.inputs)g.push(mist.data.capabilities.inputs[f].source_match);var R=$("<div>"),na=function(a){var b={};if(!mist.data.streams)mist.data.streams={};mist.data.streams[n.name]=n;c!=n.name&&delete mist.data.streams[c];b.addstream={};b.addstream[n.name]=n;if(c!=n.name)b.deletestream=[c];if(n.stop_sessions&&c!=""){b.stop_sessions=c;delete n.stop_sessions}mist.send(function(){delete mist.data.streams[n.name].online;
delete mist.data.streams[n.name].error;UI.navto(a,a=="Preview"?n.name:"")},b)},oa=$("<style>").text("button.saveandpreview { display: none; }"),H=$("<span>"),Z=function(){var a=d.find("[name=name]").val();if(a){var c=parseURL(mist.user.host),b=d.find("[name=source]").val(),f=b.match(/@.*/);f&&(f=f[0].substring(1));var g=b.replace(/(?:.+?):\/\//,""),g=g.split("/"),g=g[0],g=g.split(":"),g=g[0];(b=b.match(/:\d+/))&&(b=b[0]);var e={},h=["RTMP","RTSP","TS","RTMP.exe","RTSP.exe","TS.exe"],i;for(i in h)h[i]in delete mist.data.streams[n.name].error;UI.navto(a,a=="Preview"?n.name:"")},b)},oa=$("<style>").text("button.saveandpreview { display: none; }"),H=$("<span>"),Z=function(){var a=d.find("[name=name]").val();if(a){var c=parseURL(mist.user.host),b=d.find("[name=source]").val(),f=b.match(/@.*/);f&&(f=f[0].substring(1));var g=b.replace(/(?:.+?):\/\//,""),g=g.split("/"),g=g[0],g=g.split(":"),g=g[0];(b=b.match(/:\d+/))&&(b=b[0]);var e={},h=["RTMP","RTSP","RTMP.exe","RTSP.exe"],i;for(i in h)h[i]in mist.data.capabilities.connectors&&
mist.data.capabilities.connectors&&(e[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 e){for(i in mist.data.config.protocols){var j=mist.data.config.protocols[i];if(j.connector==k){if("port"in j)e[k]=j.port;break}}e[k]=e[k]==h[k]?"":":"+e[k]}H.find(".field").closest("label").hide();for(i in e){var z;k=b?b:e[i];switch(i){case "RTMP":case "RTMP.exe":z="rtmp://"+c.host+k+"/"+(f?f:"live")+"/"; (e[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 e){for(i in mist.data.config.protocols){var j=mist.data.config.protocols[i];if(j.connector==k){if("port"in j)e[k]=j.port;break}}e[k]=e[k]==h[k]?"":":"+e[k]}e.TS="";e["TS.exe"]="";H.find(".field").closest("label").hide();for(i in e){var z;k=b?b:e[i];switch(i){case "RTMP":case "RTMP.exe":z="rtmp://"+c.host+k+"/"+(f?f:"live")+"/";H.find(".field.RTMPurl").setval(z).closest("label").show();
H.find(".field.RTMPurl").setval(z).closest("label").show();H.find(".field.RTMPkey").setval(a==""?"STREAMNAME":a).closest("label").show();z=z+(a==""?"STREAMNAME":a);break;case "RTSP":case "RTSP.exe":z="rtsp://"+c.host+k+"/"+(a==""?"STREAMNAME":a)+(f?"?pass="+f:"");break;case "TS":case "TS.exe":z="udp://"+(g==""?c.host:g)+k+"/"}H.find(".field."+i.replace(".exe","")).setval(z).closest("label").show()}}};d.append(UI.buildUI([{label:"Stream name",type:"str",validate:["required","streamname"],pointer:{main:n, H.find(".field.RTMPkey").setval(a==""?"STREAMNAME":a).closest("label").show();z=z+(a==""?"STREAMNAME":a);break;case "RTSP":case "RTSP.exe":z="rtsp://"+c.host+k+"/"+(a==""?"STREAMNAME":a)+(f?"?pass="+f:"");break;case "TS":case "TS.exe":z="udp://"+(g==""?c.host:g)+k+"/"}H.find(".field."+i.replace(".exe","")).setval(z).closest("label").show()}}};d.append(UI.buildUI([{label:"Stream name",type:"str",validate:["required","streamname"],pointer:{main:n,index:"name"},help:"Set the name this stream will be recognised by for players and/or stream pushing."},
index:"name"},help:"Set the name this stream will be recognised by for players and/or stream pushing."},{label:"Source",type:"browse",filetypes:g,pointer:{main:n,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><tr><td>File input</td><td>Syntax</td><td>Explanation</td></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<br>(Pro&nbsp;only)</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>Push input</td><td>Syntax</td><td>Explanation</td></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. <tr><th>RTSP<br>(Pro&nbsp;only)</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<br>(Pro&nbsp;only)</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>Pull input</td><td>Syntax</td><td>Explanation</td></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<br>(Pro&nbsp;only)</th><td>http://URL/TO/STREAM.m3u8</td><td>The URL where the HLS stream is available to MistServer.</td></tr></table>", {label:"Source",type:"browse",filetypes:g,pointer:{main:n,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><tr><td>File input</td><td>Syntax</td><td>Explanation</td></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<br>(Pro&nbsp;only)</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>Push input</td><td>Syntax</td><td>Explanation</td></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. <tr><th>RTSP<br>(Pro&nbsp;only)</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<br>(Pro&nbsp;only)</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>Pull input</td><td>Syntax</td><td>Explanation</td></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<br>(Pro&nbsp;only)</th><td>http://URL/TO/STREAM.m3u8</td><td>The URL where the HLS stream is available to MistServer.</td></tr></table>",
"function":function(){var a=$(this).val();oa.remove();H.html("");if(a!=""){var c=null,b;for(b in mist.data.capabilities.inputs)if(typeof mist.data.capabilities.inputs[b].source_match!="undefined"&&mist.inputMatch(mist.data.capabilities.inputs[b].source_match,a)){c=b;break}if(c===null)R.html($("<h3>").text("Unrecognized input").addClass("red")).append($("<span>").text("Please edit the stream source.").addClass("red"));else{c=mist.data.capabilities.inputs[c];R.html($("<h3>").text(c.name+" Input options")); "function":function(){var a=$(this).val();oa.remove();H.html("");if(a!=""){var c=null,b;for(b in mist.data.capabilities.inputs)if(typeof mist.data.capabilities.inputs[b].source_match!="undefined"&&mist.inputMatch(mist.data.capabilities.inputs[b].source_match,a)){c=b;break}if(c===null)R.html($("<h3>").text("Unrecognized input").addClass("red")).append($("<span>").text("Please edit the stream source.").addClass("red"));else{c=mist.data.capabilities.inputs[c];R.html($("<h3>").text(c.name+" Input options"));
var f=mist.convertBuildOptions(c,n);"always_match"in mist.data.capabilities.inputs[b]&&mist.inputMatch(mist.data.capabilities.inputs[b].always_match,a)&&f.push({label:"Always on",type:"checkbox",help:"Keep this input available at all times, even when there are no active viewers.",pointer:{main:n,index:"always_on"}});R.append(UI.buildUI(f));if(c.name=="Folder")d.append(oa);else if(["Buffer","Buffer.exe","TS","TS.exe"].indexOf(c.name)>-1){a=[$("<span>").text("Configure your source to push to:")];switch(c.name){case "Buffer":case "Buffer.exe":a.push({label:"RTMP full url", var f=mist.convertBuildOptions(c,n);"always_match"in mist.data.capabilities.inputs[b]&&mist.inputMatch(mist.data.capabilities.inputs[b].always_match,a)&&f.push({label:"Always on",type:"checkbox",help:"Keep this input available at all times, even when there are no active viewers.",pointer:{main:n,index:"always_on"}});R.append(UI.buildUI(f));if(c.name=="Folder")d.append(oa);else if(["Buffer","Buffer.exe","TS","TS.exe"].indexOf(c.name)>-1){b=[$("<br>"),$("<span>").text("Configure your source to push to:")];
type:"span",clipboard:true,readonly:true,classes:["RTMP"],help:"Use this RTMP url if your client doesn't ask for a stream key"});a.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"});a.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"});a.push({label:"RTSP",type:"span",clipboard:true,readonly:true,classes:["RTSP"]}); switch(c.name){case "Buffer":case "Buffer.exe":b.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"});b.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"});b.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"});
break;case "TS":case "TS.exe":a.push({label:"TS",type:"span",clipboard:true,readonly:true,classes:["TS"]})}H.html("<br>").append(UI.buildUI(a));Z()}}}}},{label:"Stop sessions",type:"checkbox",help:"When saving these stream settings, kill this stream's current connections.",LTSonly:!0,pointer:{main:n,index:"stop_sessions"}},H,$("<br>"),{type:"custom",custom:R},$("<br>"),$("<h3>").text("Encryption"),{type:"help",help:"To enable encryption, the licence acquisition url must be entered, as well as either the content key or the key ID and seed.<br>Unsure how you should fill in your encryption or missing your preferred encryption? Please contact us."}, b.push({label:"RTSP",type:"span",clipboard:true,readonly:true,classes:["RTSP"]});break;case "TS":case "TS.exe":a.charAt(0)=="/"?b=[]:b.push({label:"TS",type:"span",clipboard:true,readonly:true,classes:["TS"]})}H.html(UI.buildUI(b));Z()}}}}},{label:"Stop sessions",type:"checkbox",help:"When saving these stream settings, kill this stream's current connections.",LTSonly:!0,pointer:{main:n,index:"stop_sessions"}},H,$("<br>"),{type:"custom",custom:R},$("<br>"),$("<h3>").text("Encryption"),{type:"help",
{label:"License acquisition url",type:"str",LTSonly:!0,pointer:{main:n,index:"la_url"}},$("<br>"),{label:"Content key",type:"str",LTSonly:!0,pointer:{main:n,index:"contentkey"}},{type:"text",text:" - or - "},{label:"Key ID",type:"str",LTSonly:!0,pointer:{main:n,index:"keyid"}},{label:"Key seed",type:"str",LTSonly:!0,pointer:{main:n,index:"keyseed"}},{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Streams")}},{type:"save",label:"Save","function":function(){na("Streams")}}, help:"To enable encryption, the licence acquisition url must be entered, as well as either the content key or the key ID and seed.<br>Unsure how you should fill in your encryption or missing your preferred encryption? Please contact us."},{label:"License acquisition url",type:"str",LTSonly:!0,pointer:{main:n,index:"la_url"}},$("<br>"),{label:"Content key",type:"str",LTSonly:!0,pointer:{main:n,index:"contentkey"}},{type:"text",text:" - or - "},{label:"Key ID",type:"str",LTSonly:!0,pointer:{main:n,
{type:"save",label:"Save and Preview","function":function(){na("Preview")},classes:["saveandpreview"]}]}]));d.find("[name=name]").keyup(function(){Z()});Z();break;case "Preview":""==c&&UI.navto("Streams");b=":8080";for(f in mist.data.config.protocols)if(r=mist.data.config.protocols[f],"HTTP"==r.connector||"HTTP.exe"==r.connector)b=r.port?":"+r.port:":8080";var g=parseURL(mist.user.host),N=g.protocol+g.host+b+"/",K=$("<div>").css({display:"flex","flex-flow":"row wrap"}),g="";-1==c.indexOf("+")&&(g= index:"keyid"}},{label:"Key seed",type:"str",LTSonly:!0,pointer:{main:n,index:"keyseed"}},{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Streams")}},{type:"save",label:"Save","function":function(){na("Streams")}},{type:"save",label:"Save and Preview","function":function(){na("Preview")},classes:["saveandpreview"]}]}]));d.find("[name=name]").keyup(function(){Z()});Z();break;case "Preview":""==c&&UI.navto("Streams");b=":8080";for(f in mist.data.config.protocols)if(r=
$("<button>").text("Settings").addClass("settings").click(function(){UI.navto("Edit",c)}));d.html($("<div>").addClass("bigbuttons").append(g).append($("<button>").text("Embed").addClass("embed").click(function(){UI.navto("Embed",c)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Preview of "'+c+'"')).append(K);var I=encodeURIComponent(c);f=$("<div>");K.append(f);var aa=$("<div>"),S=$("<select>").append($("<option>").text("Automatic").val("")).change(function(){ba()}), mist.data.config.protocols[f],"HTTP"==r.connector||"HTTP.exe"==r.connector)b=r.port?":"+r.port:":8080";var g=parseURL(mist.user.host),N=g.protocol+g.host+b+"/",K=$("<div>").css({display:"flex","flex-flow":"row wrap"}),g="";-1==c.indexOf("+")&&(g=$("<button>").text("Settings").addClass("settings").click(function(){UI.navto("Edit",c)}));d.html($("<div>").addClass("bigbuttons").append(g).append($("<button>").text("Embed").addClass("embed").click(function(){UI.navto("Embed",c)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Preview of "'+
O=$("<select>").append($("<option>").text("Automatic").val("")).change(function(){ba()}),g=UI.buildUI([{label:"Use player",type:"DOMfield",DOMfield:S,help:"Choose a player to preview"},{label:"Use source",type:"DOMfield",DOMfield:O,help:"Choose an output type to preview"}]),P=$("<div>").addClass("mistvideo").text("Loading player..");f.append(P).append(aa).append(g);var ba=function(){B.html("");if(typeof mistvideo!="undefined")for(var a in mistvideo)if("embedded"in mistvideo[a])for(var b in mistvideo[a].embedded)try{mistvideo[a].embedded[b].player.unload()}catch(d){}a= c+'"')).append(K);var I=encodeURIComponent(c);f=$("<div>");K.append(f);var aa=$("<div>"),S=$("<select>").append($("<option>").text("Automatic").val("")).change(function(){ba()}),O=$("<select>").append($("<option>").text("Automatic").val("")).change(function(){ba()}),g=UI.buildUI([{label:"Use player",type:"DOMfield",DOMfield:S,help:"Choose a player to preview"},{label:"Use source",type:"DOMfield",DOMfield:O,help:"Choose an output type to preview"}]),P=$("<div>").addClass("mistvideo").text("Loading player..");
{target:P[0],maxheight:window.innerHeight-$("header").height(),maxwidth:window.innerWidth-UI.elements.menu.width()-100,host:N.replace(/\/$/,""),loop:true};if(S.val()!="")a.forcePlayer=S.val();if(O.val()!="")a.forceSource=O.val();mistPlay(c,a)},B=$("<div>").addClass("player_log");f.append($("<div>").append($("<h3>").text("Player log:")).append(B));var pa="";P.on("log error",function(a){var c=false;B.height()+B.scrollTop()==B[0].scrollHeight&&(c=true);var b=a.type+a.originalEvent.message,d="["+UI.format.time((new Date).getTime()/ f.append(P).append(aa).append(g);var ba=function(){B.html("");if(typeof mistvideo!="undefined")for(var a in mistvideo)if("embedded"in mistvideo[a])for(var b in mistvideo[a].embedded)try{mistvideo[a].embedded[b].player.unload()}catch(d){}a={target:P[0],maxheight:window.innerHeight-$("header").height(),maxwidth:window.innerWidth-UI.elements.menu.width()-100,host:N.replace(/\/$/,""),loop:true};if(S.val()!="")a.forcePlayer=S.val();if(O.val()!="")a.forceSource=O.val();mistPlay(c,a)},B=$("<div>").addClass("player_log");
1E3)+"]";if(pa==b){var a=B.children().last(),c=a.children("[data-amount]"),f=c.attr("data-amount");f++;c.text("("+f+"x)").attr("data-amount",f);a.children(".timestamp").text(d)}else{B.append($("<div>").append($("<span>").addClass("timestamp").text(d).css("margin-right","0.5em")).append($("<span>").text(a.originalEvent.message)).append($("<span>").attr("data-amount",1).css("margin-left","0.5em")).addClass(a.type=="error"?"red":""));c&&B.scrollTop(B[0].scrollHeight)}pa=b});var qa=function(){aa.text(""); f.append($("<div>").append($("<h3>").text("Player log:")).append(B));var pa="";P.on("log error",function(a){var c=false;B.height()+B.scrollTop()==B[0].scrollHeight&&(c=true);var b=a.type+a.originalEvent.message,d="["+UI.format.time((new Date).getTime()/1E3)+"]";if(pa==b){var a=B.children().last(),c=a.children("[data-amount]"),f=c.attr("data-amount");f++;c.text("("+f+"x)").attr("data-amount",f);a.children(".timestamp").text(d)}else{B.append($("<div>").append($("<span>").addClass("timestamp").text(d).css("margin-right",
var a=document.createElement("script");d.append(a);a.src=N+"player.js";a.onerror=function(){P.html("Failed to load player.js").append($("<button>").text("Reload").css("display","block").click(function(){qa()}))};a.onload=function(){for(var b in mistplayers)S.append($("<option>").text(mistplayers[b].name).val(b));ba();P.on("initialized",function(){if(O.children().length<=1)for(var a in mistvideo[c].source){var b=mistvideo[c].source[a],d=UI.humanMime(b.type);O.append($("<option>").val(a).text(d?d+" @ "+ "0.5em")).append($("<span>").text(a.originalEvent.message)).append($("<span>").attr("data-amount",1).css("margin-left","0.5em")).addClass(a.type=="error"?"red":""));c&&B.scrollTop(B[0].scrollHeight)}pa=b});var qa=function(){aa.text("");var a=document.createElement("script");d.append(a);a.src=N+"player.js";a.onerror=function(){P.html("Failed to load player.js").append($("<button>").text("Reload").css("display","block").click(function(){qa()}))};a.onload=function(){for(var b in mistplayers)S.append($("<option>").text(mistplayers[b].name).val(b));
b.url.substring(b.url.length-b.relurl.length,0):UI.format.capital(b.type)+" @ "+b.url.substring(b.url.length-b.relurl.length,0)))}a=mistvideo[c].embedded[mistvideo[c].embedded.length-1];d=UI.humanMime(a.player.options.source.type);aa.html("You're watching "+(d?d+" <span class=description>("+a.player.options.source.type+")</span>":UI.format.capital(a.player.options.source.type))+" through "+mistplayers[a.selectedPlayer].name+".")});d[0].removeChild(a)}};qa();f=$("<div>").append($("<h3>").text("Meta information")); ba();P.on("initialized",function(){if(O.children().length<=1)for(var a in mistvideo[c].source){var b=mistvideo[c].source[a],d=UI.humanMime(b.type);O.append($("<option>").val(a).text(d?d+" @ "+b.url.substring(b.url.length-b.relurl.length,0):UI.format.capital(b.type)+" @ "+b.url.substring(b.url.length-b.relurl.length,0)))}a=mistvideo[c].embedded[mistvideo[c].embedded.length-1];d=UI.humanMime(a.player.options.source.type);aa.html("You're watching "+(d?d+" <span class=description>("+a.player.options.source.type+
var T=$("<span>").text("Loading..");f.append(T);K.append(f);$.ajax({type:"GET",url:N+"json_"+I+".js",success:function(a){var c=function(a,c){return"maxbps"in a?UI.format.bytes(a[c],1):c=="maxbps"?UI.format.bytes(a.bps,1):"unknown"},b=a.meta;if(!b||!b.tracks)T.html("No meta information available.");else{a=[];a.push({label:"Type",type:"span",value:b.live?"Live":"Pre-recorded (VoD)"});"format"in b&&a.push({label:"Format",type:"span",value:b.format});b.live&&a.push({label:"Buffer window",type:"span", ")</span>":UI.format.capital(a.player.options.source.type))+" through "+mistplayers[a.selectedPlayer].name+".")});d[0].removeChild(a)}};qa();f=$("<div>").append($("<h3>").text("Meta information"));var T=$("<span>").text("Loading..");f.append(T);K.append(f);$.ajax({type:"GET",url:N+"json_"+I+".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)T.html("No meta information available.");else{a=
value:UI.format.addUnit(b.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","Peak bitrate","Size","Framerate","Language","Track index"],content:[]},subtitle:{vheader:"Subtitles",labels:["Codec","Duration","Avg bitrate","Peak bitrate","Language","Track index"],content:[]}},f=Object.keys(b.tracks);f.sort(function(a,c){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","Peak bitrate","Size","Framerate","Language","Track index"],
a.split("_").pop();c=c.split("_").pop();return a-c});var g=1,e=1,h=1,i;for(i in f){var k=f[i],j=b.tracks[k];switch(j.type){case "audio":d.audio.content.push({header:"Track "+k.split("_").pop(),body:[j.codec,UI.format.duration((j.lastms-j.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(j.firstms/1E3)+" to "+UI.format.duration(j.lastms/1E3)+"</span>",c(j,"bps"),c(j,"maxbps"),j.channels,UI.format.addUnit(UI.format.number(j.rate),"Hz"),"language"in j?j.language:"unknown",g]});g++;break; content:[]},subtitle:{vheader:"Subtitles",labels:["Codec","Duration","Avg bitrate","Peak bitrate","Language","Track index"],content:[]}},f=Object.keys(c.tracks);f.sort(function(a,b){a=a.split("_").pop();b=b.split("_").pop();return a-b});var g=1,e=1,h=1,i;for(i in f){var k=f[i],j=c.tracks[k];switch(j.type){case "audio":d.audio.content.push({header:"Track "+k.split("_").pop(),body:[j.codec,UI.format.duration((j.lastms-j.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(j.firstms/1E3)+
case "video":d.video.content.push({header:"Track "+k.split("_").pop(),body:[j.codec,UI.format.duration((j.lastms-j.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(j.firstms/1E3)+" to "+UI.format.duration(j.lastms/1E3)+"</span>",c(j,"bps"),c(j,"maxbps"),UI.format.addUnit(j.width,"x ")+UI.format.addUnit(j.height,"px"),UI.format.addUnit(UI.format.number(j.fpks/1E3),"fps"),"language"in j?j.language:"unknown",e]});e++;break;case "meta":case "subtitle":if(j.codec=="subtitle"||j.type=="subtitle"){d.subtitle.content.push({header:"Track "+ " to "+UI.format.duration(j.lastms/1E3)+"</span>",b(j,"bps"),b(j,"maxbps"),j.channels,UI.format.addUnit(UI.format.number(j.rate),"Hz"),"language"in j?j.language:"unknown",g]});g++;break;case "video":d.video.content.push({header:"Track "+k.split("_").pop(),body:[j.codec,UI.format.duration((j.lastms-j.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(j.firstms/1E3)+" to "+UI.format.duration(j.lastms/1E3)+"</span>",b(j,"bps"),b(j,"maxbps"),UI.format.addUnit(j.width,"x ")+UI.format.addUnit(j.height,
k.split("_").pop(),body:[j.codec,UI.format.duration((j.lastms-j.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(j.firstms/1E3)+" to "+UI.format.duration(j.lastms/1E3)+"</span>",c(j,"bps"),c(j,"maxbps"),"language"in j?j.language:"unknown",h]});h++}}}c=["audio","video","subtitle"];i=$("<div>").css({display:"flex","flex-flow":"row wrap","font-size":"0.9em"});for(k in c)d[c[k]].content.length&&i.append(UI.buildVheaderTable(d[c[k]]).css("width","auto"));a.push($("<span>").text("Tracks:")); "px"),UI.format.addUnit(UI.format.number(j.fpks/1E3),"fps"),"language"in j?j.language:"unknown",e]});e++;break;case "meta":case "subtitle":if(j.codec=="subtitle"||j.type=="subtitle"){d.subtitle.content.push({header:"Track "+k.split("_").pop(),body:[j.codec,UI.format.duration((j.lastms-j.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(j.firstms/1E3)+" to "+UI.format.duration(j.lastms/1E3)+"</span>",b(j,"bps"),b(j,"maxbps"),"language"in j?j.language:"unknown",h]});h++}}}b=["audio","video",
a.push(i);T.html(UI.buildUI(a))}},error:function(){T.html("Error while retrieving stream info.")}});break;case "Embed":""==c&&UI.navTo("Streams");g="";-1==c.indexOf("+")&&(g=$("<button>").addClass("settings").text("Settings").click(function(){UI.navto("Edit",c)}));d.html($("<div>").addClass("bigbuttons").append(g).append($("<button>").text("Preview").addClass("preview").click(function(){UI.navto("Preview",c)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Embed "'+ "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);T.html(UI.buildUI(a))}},error:function(){T.html("Error while retrieving stream info.")}});break;case "Embed":""==c&&UI.navTo("Streams");g="";-1==c.indexOf("+")&&(g=$("<button>").addClass("settings").text("Settings").click(function(){UI.navto("Edit",c)}));d.html($("<div>").addClass("bigbuttons").append(g).append($("<button>").text("Preview").addClass("preview").click(function(){UI.navto("Preview",
c+'"'));var U=$("<span>");d.append(U);I=encodeURIComponent(c);g=parseURL(mist.user.host);b={"":{port:":8080"}};for(f in mist.data.config.protocols){r=mist.data.config.protocols[f];if("HTTP"==r.connector||"HTTP.exe"==r.connector)b[""].port=r.port?":"+r.port:":8080";if("HTTPS"==r.connector||"HTTPS.exe"==r.connector)b.s={},b.s.port=r.port?":"+r.port:":4433"}var J=N="http://"+g.host+b[""].port+"/";if(otherhost.host||otherhost.https)J=(otherhost.https&&"s"in b?"https://":"http://")+(otherhost.host?otherhost.host: c)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Embed "'+c+'"'));var U=$("<span>");d.append(U);I=encodeURIComponent(c);g=parseURL(mist.user.host);b={"":{port:":8080"}};for(f in mist.data.config.protocols){r=mist.data.config.protocols[f];if("HTTP"==r.connector||"HTTP.exe"==r.connector)b[""].port=r.port?":"+r.port:":8080";if("HTTPS"==r.connector||"HTTPS.exe"==r.connector)b.s={},b.s.port=r.port?":"+r.port:
g.host)+(otherhost.https&&"s"in b?b.s.port:b[""].port)+"/";var ca={forcePlayer:"",forceType:"",controls:!0,autoplay:!0,loop:!1,width:"",height:"",maxwidth:"",maxheight:"",poster:"",urlappend:"",setTracks:{}},o=$.extend({},ca);f=UI.stored.getOpts();"embedoptions"in f&&(o=$.extend(o,f.embedoptions,!0),"object"!=typeof o.setTracks&&(o.setTracks={}));f={};switch(o.controls){case "stock":f.controls="stock";break;case !0:f.controls=1;break;case !1:f.controls=0}var v=function(){function a(c){switch(typeof c){case "string":return $.isNumeric(c)? ":4433"}var J=N="http://"+g.host+b[""].port+"/";if(otherhost.host||otherhost.https)J=(otherhost.https&&"s"in b?"https://":"http://")+(otherhost.host?otherhost.host:g.host)+(otherhost.https&&"s"in b?b.s.port:b[""].port)+"/";var ca={forcePlayer:"",forceType:"",controls:!0,autoplay:!0,loop:!1,width:"",height:"",maxwidth:"",maxheight:"",poster:"",urlappend:"",setTracks:{}},o=$.extend({},ca);f=UI.stored.getOpts();"embedoptions"in f&&(o=$.extend(o,f.embedoptions,!0),"object"!=typeof o.setTracks&&(o.setTracks=
c:'"'+c+'"';case "object":return JSON.stringify(c);default:return c}}UI.stored.saveOpt("embedoptions",o);for(var b=c+"_",d=12,f="";d--;){var g;g=Math.floor(Math.random()*62);g=g<10?g:g<36?String.fromCharCode(g+55):String.fromCharCode(g+61);f=f+g}var b=b+f,d=['target: document.getElementById("'+b+'")'],e;for(e in o)o[e]!=ca[e]&&(typeof o[e]!="object"||JSON.stringify(o[e])!=JSON.stringify(ca[e]))&&d.push(e+": "+a(o[e]));e=[];e.push('<div class="mistvideo" id="'+b+'">');e.push(" <noscript>");e.push(' <a href="'+ {}));f={};switch(o.controls){case "stock":f.controls="stock";break;case !0:f.controls=1;break;case !1:f.controls=0}var v=function(){function a(b){switch(typeof b){case "string":return $.isNumeric(b)?b:'"'+b+'"';case "object":return JSON.stringify(b);default:return b}}UI.stored.saveOpt("embedoptions",o);for(var b=c+"_",d=12,f="";d--;){var g;g=Math.floor(Math.random()*62);g=g<10?g:g<36?String.fromCharCode(g+55):String.fromCharCode(g+61);f=f+g}var b=b+f,d=['target: document.getElementById("'+b+'")'],
J+I+'.html" target="_blank">');e.push(" Click here to play this video");e.push(" </a>");e.push(" </noscript>");e.push(" <script>");e.push(" var a = function(){");e.push(' mistPlay("'+c+'",{');e.push(" "+d.join(",\n "));e.push(" });");e.push(" };");e.push(" if (!window.mistplayers) {");e.push(' var p = document.createElement("script");');e.push(' p.src = "'+J+'player.js"');e.push(" document.head.appendChild(p);");e.push(" p.onload = a;"); e;for(e in o)o[e]!=ca[e]&&(typeof o[e]!="object"||JSON.stringify(o[e])!=JSON.stringify(ca[e]))&&d.push(e+": "+a(o[e]));e=[];e.push('<div class="mistvideo" id="'+b+'">');e.push(" <noscript>");e.push(' <a href="'+J+I+'.html" target="_blank">');e.push(" Click here to play this video");e.push(" </a>");e.push(" </noscript>");e.push(" <script>");e.push(" var a = function(){");e.push(' mistPlay("'+c+'",{');e.push(" "+d.join(",\n "));e.push(" });");e.push(" };");
e.push(" }");e.push(" else { a(); }");e.push(" <\/script>");e.push("</div>");return e.join("\n")},da=$("<span>").text("Loading.."),r=v(o),L=$("<div>").text("Loading..").css("display","flex"),ra="";"s"in b&&(ra=UI.buildUI([{label:"Use HTTPS",type:"checkbox","function":function(){if($(this).getval()!=otherhost.https){otherhost.https=$(this).getval();UI.navto("Embed",c)}},value:otherhost.https}]).find("label"));U.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", e.push(" if (!window.mistplayers) {");e.push(' var p = document.createElement("script");');e.push(' p.src = "'+J+'player.js"');e.push(" document.head.appendChild(p);");e.push(" p.onload = a;");e.push(" }");e.push(" else { a(); }");e.push(" <\/script>");e.push("</div>");return e.join("\n")},da=$("<span>").text("Loading.."),r=v(o),L=$("<div>").text("Loading..").css("display","flex"),ra="";"s"in b&&(ra=UI.buildUI([{label:"Use HTTPS",type:"checkbox","function":function(){if($(this).getval()!=
"text").addClass("field").val(otherhost.host?otherhost.host:g.host)).append($("<span>").addClass("unit").append($("<button>").text("Apply").click(function(){otherhost.host=$(this).closest("label").find("input").val();UI.navto("Embed",c)}))))).append(ra)).append(UI.buildUI([$("<h3>").text("Urls"),{label:"Stream info json",type:"str",value:J+"json_"+I+".js",readonly:!0,clipboard:!0,help:"Information about this stream as a json page."},{label:"Stream info script",type:"str",value:J+"info_"+I+".js",readonly:!0, otherhost.https){otherhost.https=$(this).getval();UI.navto("Embed",c)}},value:otherhost.https}]).find("label"));U.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","text").addClass("field").val(otherhost.host?otherhost.host:g.host)).append($("<span>").addClass("unit").append($("<button>").text("Apply").click(function(){otherhost.host=
clipboard:!0,help:"This script loads information about this stream into a mistvideo javascript object."},{label:"HTML page",type:"str",value:J+I+".html",readonly:!0,qrcode:!0,clipboard:!0,help:"A basic html containing the embedded stream."},$("<h3>").text("Embed code"),{label:"Embed code",type:"textarea",value:r,rows:r.split("\n").length+3,readonly:!0,classes:["embed_code"],clipboard:!0,help:"Include this code on your webpage to embed the stream. The options below can be used to configure how your content is displayed."}, $(this).closest("label").find("input").val();UI.navto("Embed",c)}))))).append(ra)).append(UI.buildUI([$("<h3>").text("Urls"),{label:"Stream info json",type:"str",value:J+"json_"+I+".js",readonly:!0,clipboard:!0,help:"Information about this stream as a json page."},{label:"Stream info script",type:"str",value:J+"info_"+I+".js",readonly:!0,clipboard:!0,help:"This script loads information about this stream into a mistvideo javascript object."},{label:"HTML page",type:"str",value:J+I+".html",readonly:!0,
$("<h4>").text("Embed code options (optional)").css("margin-top",0),{type:"help",help:"Use these controls to customise what this embedded video will look like.<br>Not all players have all of these options."},{label:"Force player",type:"select",select:[["","Automatic"]],pointer:{main:o,index:"forcePlayer"},classes:["forcePlayer"],"function":function(){o.forcePlayer=$(this).getval();$(".embed_code").setval(v(o))},help:"Only use this particular player."},{label:"Force source",type:"select",select:[["", qrcode:!0,clipboard:!0,help:"A basic html containing the embedded stream."},$("<h3>").text("Embed code"),{label:"Embed code",type:"textarea",value:r,rows:r.split("\n").length+3,readonly:!0,classes:["embed_code"],clipboard:!0,help:"Include this code on your webpage to embed the stream. The options below can be used to configure how your content is displayed."},$("<h4>").text("Embed code options (optional)").css("margin-top",0),{type:"help",help:"Use these controls to customise what this embedded video will look like.<br>Not all players have all of these options."},
"Automatic"]],pointer:{main:o,index:"forceType"},classes:["forceType"],"function":function(){o.forceType=$(this).getval();$(".embed_code").setval(v(o))},help:"Only use this particular source."},{label:"Controls",type:"select",select:[["1","MistServer Controls"],["stock","Player controls"],["0","None"]],pointer:{main:f,index:"controls"},"function":function(){o.controls=$(this).getval()==1;switch($(this).getval()){case 0:o.controls=false;break;case 1:o.controls=true;break;case "stock":o.controls="stock"}$(".embed_code").setval(v(o))}, {label:"Force player",type:"select",select:[["","Automatic"]],pointer:{main:o,index:"forcePlayer"},classes:["forcePlayer"],"function":function(){o.forcePlayer=$(this).getval();$(".embed_code").setval(v(o))},help:"Only use this particular player."},{label:"Force source",type:"select",select:[["","Automatic"]],pointer:{main:o,index:"forceType"},classes:["forceType"],"function":function(){o.forceType=$(this).getval();$(".embed_code").setval(v(o))},help:"Only use this particular source."},{label:"Controls",
help:"The type of controls that should be shown."},{label:"Autoplay",type:"checkbox",pointer:{main:o,index:"autoplay"},"function":function(){o.autoplay=$(this).getval();$(".embed_code").setval(v(o))},help:"Whether or not the video should play as the page is loaded."},{label:"Loop",type:"checkbox",pointer:{main:o,index:"loop"},"function":function(){o.loop=$(this).getval();$(".embed_code").setval(v(o))},help:"If the video should restart when the end is reached."},{label:"Force width",type:"int",min:0, type:"select",select:[["1","MistServer Controls"],["stock","Player controls"],["0","None"]],pointer:{main:f,index:"controls"},"function":function(){o.controls=$(this).getval()==1;switch($(this).getval()){case 0:o.controls=false;break;case 1:o.controls=true;break;case "stock":o.controls="stock"}$(".embed_code").setval(v(o))},help:"The type of controls that should be shown."},{label:"Autoplay",type:"checkbox",pointer:{main:o,index:"autoplay"},"function":function(){o.autoplay=$(this).getval();$(".embed_code").setval(v(o))},
unit:"px",pointer:{main:o,index:"width"},"function":function(){o.width=$(this).getval();$(".embed_code").setval(v(o))},help:"Enforce a fixed width."},{label:"Force height",type:"int",min:0,unit:"px",pointer:{main:o,index:"height"},"function":function(){o.height=$(this).getval();$(".embed_code").setval(v(o))},help:"Enforce a fixed height."},{label:"Maximum width",type:"int",min:0,unit:"px",pointer:{main:o,index:"maxwidth"},"function":function(){o.maxwidth=$(this).getval();$(".embed_code").setval(v(o))}, help:"Whether or not the video should play as the page is loaded."},{label:"Loop",type:"checkbox",pointer:{main:o,index:"loop"},"function":function(){o.loop=$(this).getval();$(".embed_code").setval(v(o))},help:"If the video should restart when the end is reached."},{label:"Force width",type:"int",min:0,unit:"px",pointer:{main:o,index:"width"},"function":function(){o.width=$(this).getval();$(".embed_code").setval(v(o))},help:"Enforce a fixed width."},{label:"Force height",type:"int",min:0,unit:"px",
help:"The maximum width this video can use."},{label:"Maximum height",type:"int",min:0,unit:"px",pointer:{main:o,index:"maxheight"},"function":function(){o.maxheight=$(this).getval();$(".embed_code").setval(v(o))},help:"The maximum height this video can use."},{label:"Poster",type:"str",pointer:{main:o,index:"poster"},"function":function(){o.poster=$(this).getval();$(".embed_code").setval(v(o))},help:"URL to an image that is displayed when the video is not playing."},{label:"Video URL addition",type:"str", pointer:{main:o,index:"height"},"function":function(){o.height=$(this).getval();$(".embed_code").setval(v(o))},help:"Enforce a fixed height."},{label:"Maximum width",type:"int",min:0,unit:"px",pointer:{main:o,index:"maxwidth"},"function":function(){o.maxwidth=$(this).getval();$(".embed_code").setval(v(o))},help:"The maximum width this video can use."},{label:"Maximum height",type:"int",min:0,unit:"px",pointer:{main:o,index:"maxheight"},"function":function(){o.maxheight=$(this).getval();$(".embed_code").setval(v(o))},
pointer:{main:o,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(){o.urlappend=$(this).getval();$(".embed_code").setval(v(o))}},{label:"Preselect tracks",type:"DOMfield",DOMfield:L,help:"Pre-select these tracks."},$("<h3>").text("Protocol stream urls"),da]));$.ajax({type:"GET",url:J+"json_"+I+".js",success:function(a){var c=[],b=U.find(".forceType"),d;for(d in a.source){var f= help:"The maximum height this video can use."},{label:"Poster",type:"str",pointer:{main:o,index:"poster"},"function":function(){o.poster=$(this).getval();$(".embed_code").setval(v(o))},help:"URL to an image that is displayed when the video is not playing."},{label:"Video URL addition",type:"str",pointer:{main:o,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(){o.urlappend=
a.source[d],e=UI.humanMime(f.type);c.push({label:e?e+" <span class=description>("+f.type+")</span>":UI.format.capital(f.type),type:"str",value:f.url,readonly:true,qrcode:true,clipboard:true});e=UI.humanMime(f.type);b.append($("<option>").text(e?e+" ("+f.type+")":UI.format.capital(f.type)).val(f.type))}da.html(UI.buildUI(c));L.html("");c={};for(d in a.meta.tracks){b=a.meta.tracks[d];b.type!="audio"&&b.type!="video"||(b.type in c?c[b.type].push([b.trackid,UI.format.capital(b.type)+" track "+(c[b.type].length+ $(this).getval();$(".embed_code").setval(v(o))}},{label:"Preselect tracks",type:"DOMfield",DOMfield:L,help:"Pre-select these tracks."},$("<h3>").text("Protocol stream urls"),da]));$.ajax({type:"GET",url:J+"json_"+I+".js",success:function(a){var b=[],c=U.find(".forceType"),d;for(d in a.source){var f=a.source[d],e=UI.humanMime(f.type);b.push({label:e?e+" <span class=description>("+f.type+")</span>":UI.format.capital(f.type),type:"str",value:f.url,readonly:true,qrcode:true,clipboard:true});e=UI.humanMime(f.type);
1)]):c[b.type]=[["",UI.format.capital(b.type)+" track 1"]])}if(Object.keys(c).length){L.closest("label").show();for(d in c){a=$("<select>").attr("data-type",d).css("flex-grow","1").change(function(){$(this).val()==""?delete o.setTracks[$(this).attr("data-type")]:o.setTracks[$(this).attr("data-type")]=$(this).val();$(".embed_code").setval(v(o))});L.append(a);c[d].push([-1,"No "+d]);for(var g in c[d])a.append($("<option>").val(c[d][g][0]).text(c[d][g][1]));if(d in o.setTracks){a.val(o.setTracks[d]); c.append($("<option>").text(e?e+" ("+f.type+")":UI.format.capital(f.type)).val(f.type))}da.html(UI.buildUI(b));L.html("");b={};for(d in a.meta.tracks){c=a.meta.tracks[d];c.type!="audio"&&c.type!="video"||(c.type in b?b[c.type].push([c.trackid,UI.format.capital(c.type)+" track "+(b[c.type].length+1)]):b[c.type]=[["",UI.format.capital(c.type)+" track 1"]])}if(Object.keys(b).length){L.closest("label").show();for(d in b){a=$("<select>").attr("data-type",d).css("flex-grow","1").change(function(){$(this).val()==
if(a.val()==null){a.val("");delete o.setTracks[d];$(".embed_code").setval(v(o))}}}}else L.closest("label").hide()},error:function(){da.html("Error while retrieving stream info.");L.closest("label").hide();o.setTracks={}}});f=document.createElement("script");f.src=N+"player.js";document.head.appendChild(f);f.onload=function(){var a=U.find(".forcePlayer"),c;for(c in mistplayers)a.append($("<option>").text(mistplayers[c].name).val(c));document.head.removeChild(this)};f.onerror=function(){document.head.removeChild(this)}; ""?delete o.setTracks[$(this).attr("data-type")]:o.setTracks[$(this).attr("data-type")]=$(this).val();$(".embed_code").setval(v(o))});L.append(a);b[d].push([-1,"No "+d]);for(var g in b[d])a.append($("<option>").val(b[d][g][0]).text(b[d][g][1]));if(d in o.setTracks){a.val(o.setTracks[d]);if(a.val()==null){a.val("");delete o.setTracks[d];$(".embed_code").setval(v(o))}}}}else L.closest("label").hide()},error:function(){da.html("Error while retrieving stream info.");L.closest("label").hide();o.setTracks=
break;case "Push":var C=$("<div>").text("Loading..");d.append(C);mist.send(function(a){function c(a){setTimeout(function(){mist.send(function(b){var d=false;if("push_list"in b&&b.push_list&&b.push_list.length){var d=true,e;for(e in b.push_list)if(a.indexOf(b.push_list[e][0])>-1){d=false;break}}else d=true;if(d)for(e in a)f.find("tr[data-pushid="+a[e]+"]").remove();else c()},{push_list:1})},1E3)}function b(e,g){var h=$("<span>");g=="Automatic"&&e.length>=4?h.append($("<span>").text(e[2])).append($("<span>").text(", schedule on "+ {}}});f=document.createElement("script");f.src=N+"player.js";document.head.appendChild(f);f.onload=function(){var a=U.find(".forcePlayer"),b;for(b in mistplayers)a.append($("<option>").text(mistplayers[b].name).val(b));document.head.removeChild(this)};f.onerror=function(){document.head.removeChild(this)};break;case "Push":var C=$("<div>").text("Loading..");d.append(C);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=
(new Date(e[3]*1E3)).toLocaleString())).append($("<span>").text(", complete on "+(new Date(e[4]*1E3)).toLocaleString())):e.length>=4&&e[2]!=e[3]?h.append($("<span>").text(e[2])).append($("<span>").html("&#187").addClass("unit").css("margin","0 0.5em")).append($("<span>").text(e[3])):h.append($("<span>").text(e[2]));var i=$("<td>").append($("<button>").text(g=="Automatic"?"Remove":"Stop").click(function(){if(confirm("Are you sure you want to "+$(this).text().toLowerCase()+" this push?\n"+e[1]+" to "+ true,e;for(e in c.push_list)if(a.indexOf(c.push_list[e][0])>-1){d=false;break}}else d=true;if(d)for(e in a)f.find("tr[data-pushid="+a[e]+"]").remove();else b()},{push_list:1})},1E3)}function c(e,g){var h=$("<span>");g=="Automatic"&&e.length>=4?h.append($("<span>").text(e[2])).append($("<span>").text(", schedule on "+(new Date(e[3]*1E3)).toLocaleString())).append($("<span>").text(", complete on "+(new Date(e[4]*1E3)).toLocaleString())):e.length>=4&&e[2]!=e[3]?h.append($("<span>").text(e[2])).append($("<span>").html("&#187").addClass("unit").css("margin",
e[2])){var a=$(this).closest("tr");a.html($("<td colspan=99>").html($("<span>").addClass("red").text(g=="Automatic"?"Removing..":"Stopping..")));if(g=="Automatic"){var b=e.slice(1);mist.send(function(){a.remove()},{push_auto_remove:[b]})}else mist.send(function(){c([e[0]])},{push_stop:[e[0]]})}}));if(g=="Automatic"){i.prepend($("<button>").text("Edit").click(function(){UI.navto("Start Push","auto_"+($(this).closest("tr").index()-1))}));i.append($("<button>").text("Stop pushes").click(function(){if(confirm('Are you sure you want to stop all pushes matching \n"'+ "0 0.5em")).append($("<span>").text(e[3])):h.append($("<span>").text(e[2]));var i=$("<td>").append($("<button>").text(g=="Automatic"?"Remove":"Stop").click(function(){if(confirm("Are you sure you want to "+$(this).text().toLowerCase()+" this push?\n"+e[1]+" to "+e[2])){var a=$(this).closest("tr");a.html($("<td colspan=99>").html($("<span>").addClass("red").text(g=="Automatic"?"Removing..":"Stopping..")));if(g=="Automatic"){var c=e.slice(1);mist.send(function(){a.remove()},{push_auto_remove:[c]})}else mist.send(function(){b([e[0]])},
e[1]+" to "+e[2]+'"?'+(d.wait!=0?"\n\nRetrying is enabled. You'll probably want to set that to 0.":""))){var b=$(this);b.text("Stopping pushes..");var g=[],h;for(h in a.push_list)if(e[1]==a.push_list[h][1]&&e[2]==a.push_list[h][2]){g.push(a.push_list[h][0]);f.find("tr[data-pushid="+a.push_list[h][0]+"]").html($("<td colspan=99>").html($("<span>").addClass("red").text("Stopping..")))}mist.send(function(){b.text("Stop pushes");c(g)},{push_stop:g,push_settings:{wait:0}})}}))}return $("<tr>").attr("data-pushid", {push_stop:[e[0]]})}}));if(g=="Automatic"){i.prepend($("<button>").text("Edit").click(function(){UI.navto("Start Push","auto_"+($(this).closest("tr").index()-1))}));i.append($("<button>").text("Stop pushes").click(function(){if(confirm('Are you sure you want to stop all pushes matching \n"'+e[1]+" to "+e[2]+'"?'+(d.wait!=0?"\n\nRetrying is enabled. You'll probably want to set that to 0.":""))){var c=$(this);c.text("Stopping pushes..");var g=[],h;for(h in a.push_list)if(e[1]==a.push_list[h][1]&&e[2]==
e[0]).append($("<td>").text(e[1])).append($("<td>").append(h.children())).append(i)}C.html("");var d=a.push_settings;d||(d={});C.append(UI.buildUI([{type:"help",help:"You can push streams to files or other servers, allowing them to broadcast your stream as well."},$("<h3>").text("Settings"),{label:"Delay before retry",unit:"s",type:"int",min:0,help:"How long the delay should be before MistServer retries an automatic push.<br>If set to 0, it does not retry.","default":0,pointer:{main:d,index:"wait"}, a.push_list[h][2]){g.push(a.push_list[h][0]);f.find("tr[data-pushid="+a.push_list[h][0]+"]").html($("<td colspan=99>").html($("<span>").addClass("red").text("Stopping..")))}mist.send(function(){c.text("Stop pushes");b(g)},{push_stop:g,push_settings:{wait:0}})}}))}return $("<tr>").attr("data-pushid",e[0]).append($("<td>").text(e[1])).append($("<td>").append(h.children())).append(i)}C.html("");var d=a.push_settings;d||(d={});C.append(UI.buildUI([{type:"help",help:"You can push streams to files or other servers, allowing them to broadcast your stream as well."},
LTSonly:1},{label:"Maximum retries",unit:"/s",type:"int",min:0,help:"The maximum amount of retries per second (for all automatic pushes).<br>If set to 0, there is no limit.","default":0,pointer:{main:d,index:"maxspeed"},LTSonly:1},{type:"buttons",buttons:[{type:"save",label:"Save","function":function(){mist.send(function(){UI.navto("Push")},{push_settings:d})}}]}]));var f=$("<table>").append($("<tr>").append($("<th>").text("Stream")).append($("<th>").text("Target")).append($("<th>"))),e=f.clone(); $("<h3>").text("Settings"),{label:"Delay before retry",unit:"s",type:"int",min:0,help:"How long the delay should be before MistServer retries an automatic push.<br>If set to 0, it does not retry.","default":0,pointer:{main:d,index:"wait"},LTSonly:1},{label:"Maximum retries",unit:"/s",type:"int",min:0,help:"The maximum amount of retries per second (for all automatic pushes).<br>If set to 0, there is no limit.","default":0,pointer:{main:d,index:"maxspeed"},LTSonly:1},{type:"buttons",buttons:[{type:"save",
if("push_list"in a)for(var g in a.push_list)f.append(b(a.push_list[g],"Manual"));if("push_auto_list"in a)for(g in a.push_auto_list){var h=a.push_auto_list[g].slice();h.unshift(-1);e.append(b(h,"Automatic"))}C.append($("<h3>").text("Automatic pushes")).append($("<button>").text("Add an automatic push").click(function(){UI.navto("Start Push","auto")}));e.find("tr").length==1?C.append($("<div>").text("No automatic pushes have been configured.").addClass("text").css("margin-top","0.5em")):C.append(e); label:"Save","function":function(){mist.send(function(){UI.navto("Push")},{push_settings:d})}}]}]));var f=$("<table>").append($("<tr>").append($("<th>").text("Stream")).append($("<th>").text("Target")).append($("<th>"))),e=f.clone();if("push_list"in a)for(var g in a.push_list)f.append(c(a.push_list[g],"Manual"));if("push_auto_list"in a)for(g in a.push_auto_list){var h=a.push_auto_list[g].slice();h.unshift(-1);e.append(c(h,"Automatic"))}C.append($("<h3>").text("Automatic pushes")).append($("<button>").text("Add an automatic push").click(function(){UI.navto("Start Push",
C.append($("<h3>").text("Pushes")).append($("<button>").text("Start a push").click(function(){UI.navto("Start Push")}));if(f.find("tr").length==1)C.append($("<div>").text("No pushes are active.").addClass("text").css("margin-top","0.5em"));else{var e=[],h=[],i=$("<select>").css("margin-left","0.5em").append($("<option>").text("Any stream").val("")),j=$("<select>").css("margin-left","0.5em").append($("<option>").text("Any target").val(""));for(g in a.push_list){e.indexOf(a.push_list[g][1])==-1&&e.push(a.push_list[g][1]); "auto")}));e.find("tr").length==1?C.append($("<div>").text("No automatic pushes have been configured.").addClass("text").css("margin-top","0.5em")):C.append(e);C.append($("<h3>").text("Pushes")).append($("<button>").text("Start a push").click(function(){UI.navto("Start Push")}));if(f.find("tr").length==1)C.append($("<div>").text("No pushes are active.").addClass("text").css("margin-top","0.5em"));else{var e=[],h=[],i=$("<select>").css("margin-left","0.5em").append($("<option>").text("Any stream").val("")),
h.indexOf(a.push_list[g][2])==-1&&h.push(a.push_list[g][2])}e.sort();h.sort();for(g in e)i.append($("<option>").text(e[g]));for(g in h)j.append($("<option>").text(h[g]));C.append($("<button>").text("Stop all pushes").click(function(){var b=[],d;for(d in a.push_list)b.push(a.push_list[d][0]);if(b.length!=0&&confirm("Are you sure you want to stop all pushes?")){mist.send(function(){c(b)},{push_stop:b});f.find("tr:not(:first-child)").html($("<td colspan=99>").append($("<span>").addClass("red").text("Stopping.."))); j=$("<select>").css("margin-left","0.5em").append($("<option>").text("Any target").val(""));for(g in a.push_list){e.indexOf(a.push_list[g][1])==-1&&e.push(a.push_list[g][1]);h.indexOf(a.push_list[g][2])==-1&&h.push(a.push_list[g][2])}e.sort();h.sort();for(g in e)i.append($("<option>").text(e[g]));for(g in h)j.append($("<option>").text(h[g]));C.append($("<button>").text("Stop all pushes").click(function(){var c=[],d;for(d in a.push_list)c.push(a.push_list[d][0]);if(c.length!=0&&confirm("Are you sure you want to stop all pushes?")){mist.send(function(){b(c)},
$(this).remove()}})).append($("<label>").css("margin-left","1em").append($("<span>").text("Stop all pushes that match: ").css("font-size","0.9em")).append(i).append($("<span>").css("margin-left","0.5em").text("and").css("font-size","0.9em")).append(j).append($("<button>").css("margin-left","0.5em").text("Apply").click(function(){var b=i.val(),d=j.val();if(b==""&&d=="")return alert("Looks like you want to stop all pushes. Maybe you should use that button?");var e={},g;for(g in a.push_list)if((b==""|| {push_stop:c});f.find("tr:not(:first-child)").html($("<td colspan=99>").append($("<span>").addClass("red").text("Stopping..")));$(this).remove()}})).append($("<label>").css("margin-left","1em").append($("<span>").text("Stop all pushes that match: ").css("font-size","0.9em")).append(i).append($("<span>").css("margin-left","0.5em").text("and").css("font-size","0.9em")).append(j).append($("<button>").css("margin-left","0.5em").text("Apply").click(function(){var c=i.val(),d=j.val();if(c==""&&d=="")return alert("Looks like you want to stop all pushes. Maybe you should use that button?");
a.push_list[g][1]==b)&&(d==""||a.push_list[g][2]==d))e[a.push_list[g][0]]=a.push_list[g];if(Object.keys(e).length==0)return alert("No matching pushes.");b="Are you sure you want to stop these pushes?\n\n";for(g in e)b=b+(e[g][1]+" to "+e[g][2]+"\n");if(confirm(b)){e=Object.keys(e);mist.send(function(){c(e)},{push_stop:e});for(g in e)f.find("tr[data-pushid="+e[g]+"]").html($("<td colspan=99>").html($("<span>").addClass("red").text("Stopping..")))}}))).append(f)}},{push_settings:1,push_list:1,push_auto_list:1}); var e={},g;for(g in a.push_list)if((c==""||a.push_list[g][1]==c)&&(d==""||a.push_list[g][2]==d))e[a.push_list[g][0]]=a.push_list[g];if(Object.keys(e).length==0)return alert("No matching pushes.");c="Are you sure you want to stop these pushes?\n\n";for(g in e)c=c+(e[g][1]+" to "+e[g][2]+"\n");if(confirm(c)){e=Object.keys(e);mist.send(function(){b(e)},{push_stop:e});for(g in e)f.find("tr[data-pushid="+e[g]+"]").html($("<td colspan=99>").html($("<span>").addClass("red").text("Stopping..")))}}))).append(f)}},
break;case "Start Push":if(!("capabilities"in mist.data)){d.append("Loading Mist capabilities..");mist.send(function(){UI.navto("Start Push",c)},{capabilities:1});return}var t,V=function(a){var b=false,e=c.split("_");c=e[0];e.length==2&&(b=e[1]);if(b!==false&&typeof a=="undefined")mist.send(function(a){V(a.push_auto_list[b])},{push_auto_list:1});else{var f=[],g;for(g in mist.data.capabilities.connectors){e=mist.data.capabilities.connectors[g];"push_urls"in e&&(f=f.concat(e.push_urls))}c=="auto"&& {push_settings:1,push_list:1,push_auto_list:1});break;case "Start Push":if(!("capabilities"in mist.data)){d.append("Loading Mist capabilities..");mist.send(function(){UI.navto("Start Push",c)},{capabilities:1});return}var t,V=function(a){var b=false,e=c.split("_");c=e[0];e.length==2&&(b=e[1]);if(b!==false&&typeof a=="undefined")mist.send(function(a){V(a.push_auto_list[b])},{push_auto_list:1});else{var f=[],g;for(g in mist.data.capabilities.connectors){e=mist.data.capabilities.connectors[g];"push_urls"in
d.find("h2").text("Add automatic push");var h={};if(c=="auto"&&typeof a!="undefined"){h={stream:a[0],target:a[1]};if(a.length>=3)h.scheduletime=a[2];if(a.length>=4)h.completetime=a[3];if(h.target.indexOf("recstartunix=")>-1){g=h.target.split("recstartunix=")[1];h.recstartunix=g.split("&")[0];h.target=h.target.replace("recstartunix="+h.recstartunix,"").replace("?&","?").replace("&&","&");if(h.target[h.target.length-1]=="?")h.target=h.target.slice(0,-1)}}g=[{label:"Stream name",type:"str",help:"This may either be a full stream name, a partial wildcard stream name, or a full wildcard stream name.<br>For example, given the stream <i>a</i> you can use:<ul><li><i>a</i>: the stream configured as <i>a</i></li><li><i>a+</i>: all streams configured as <i>a</i> with a wildcard behind it, but not <i>a</i> itself</li><li><i>a+b</i>: only the version of stream <i>a</i> that has wildcard <i>b</i></li></ul>", e&&(f=f.concat(e.push_urls))}c=="auto"&&d.find("h2").text("Add automatic push");var h={};if(c=="auto"&&typeof a!="undefined"){h={stream:a[0],target:a[1]};if(a.length>=3)h.scheduletime=a[2];if(a.length>=4)h.completetime=a[3];if(h.target.indexOf("recstartunix=")>-1){g=h.target.split("recstartunix=")[1];h.recstartunix=g.split("&")[0];h.target=h.target.replace("recstartunix="+h.recstartunix,"").replace("?&","?").replace("&&","&");if(h.target[h.target.length-1]=="?")h.target=h.target.slice(0,-1)}}g=[{label:"Stream name",
pointer:{main:h,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:t,LTSonly:1},{label:"Target",type:"str",help:"Where the stream will be pushed to.<br>Valid formats:<ul><li>"+f.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>", type:"str",help:"This may either be a full stream name, a partial wildcard stream name, or a full wildcard stream name.<br>For example, given the stream <i>a</i> you can use:<ul><li><i>a</i>: the stream configured as <i>a</i></li><li><i>a+</i>: all streams configured as <i>a</i> with a wildcard behind it, but not <i>a</i> itself</li><li><i>a+b</i>: only the version of stream <i>a</i> that has wildcard <i>b</i></li></ul>",pointer:{main:h,index:"stream"},validate:["required",function(a){a=a.split("+");
pointer:{main:h,index:"target"},validate:["required",function(a){for(var b in f)if(mist.inputMatch(f[b],a))return false;return{msg:"Does not match a valid target.<br>Valid formats:<ul><li>"+f.join("</li><li>")+"</li></ul>",classes:["red"]}}],LTSonly:1}];c=="auto"&&g.push({type:"unix",label:"Schedule time",min:0,help:"TODO",pointer:{main:h,index:"scheduletime"}},{type:"unix",label:"Recording start time",min:0,help:"TODO",pointer:{main:h,index:"recstartunix"}},{type:"unix",label:"Complete time",min:0, a=a[0];return a in mist.data.streams?false:{msg:"'"+a+"' is not a stream name.",classes:["orange"],"break":false}}],datalist:t,LTSonly:1},{label:"Target",type:"str",help:"Where the stream will be pushed to.<br>Valid formats:<ul><li>"+f.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>",
help:"TODO",pointer:{main:h,index:"completetime"}});g.push({type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Push")}},{type:"save",label:"Save","function":function(){var b={};h.recstartunix?b.recstartunix="recstartunix="+h.recstartunix:h.scheduletime&&(b.recstartunix="recstartunix="+h.scheduletime);delete h.recstartunix;if(Object.keys(b).length){var d="?",e=h.target.split("?");if(e.length>1){var d="&",e=e[e.length-1],e=e.split("&"),f;for(f in e){var g=e[f].split("=")[0]; pointer:{main:h,index:"target"},validate:["required",function(a){for(var b in f)if(mist.inputMatch(f[b],a))return false;return{msg:"Does not match a valid target.<br>Valid formats:<ul><li>"+f.join("</li><li>")+"</li></ul>",classes:["red"]}}],LTSonly:1}];c=="auto"&&g.push($("<h4>").text("Optional parameters"),{type:"unix",label:"Schedule time",min:0,help:"TODO",pointer:{main:h,index:"scheduletime"}},{type:"unix",label:"Recording start time",min:0,help:"TODO",pointer:{main:h,index:"recstartunix"}},
g in b&&delete b[g]}}if(Object.keys(b).length){d=d+Object.values(b).join("&");h.target=h.target+d}}b={};b[c=="auto"?"push_auto_add":"push_start"]=h;if(typeof a!="undefined")b.push_auto_remove=[a];mist.send(function(){UI.navto("Push")},b)}}]});d.append(UI.buildUI(g))}};mist.data.LTS?mist.send(function(a){(t=a.active_streams)||(t=[]);var a=[],b;for(b in t)t[b].indexOf("+")!=-1&&a.push(t[b].replace(/\+.*/,"")+"+");t=t.concat(a);var c=0,d=0;for(b in mist.data.streams){t.push(b);if(mist.inputMatch(UI.findInput("Folder").source_match, {type:"unix",label:"Complete time",min:0,help:"TODO",pointer:{main:h,index:"completetime"}});g.push({type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Push")}},{type:"save",label:"Save","function":function(){var b={};h.recstartunix?b.recstartunix="recstartunix="+h.recstartunix:h.scheduletime&&(b.recstartunix="recstartunix="+h.scheduletime);delete h.recstartunix;if(Object.keys(b).length){var d="?",e=h.target.split("?");if(e.length>1){var d="&",e=e[e.length-1],e=
mist.data.streams[b].source)){t.push(b+"+");mist.send(function(a,b){var e=b.stream,f;for(f 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[f])&&t.push(e+"+"+a.browse.files[f]);d++;if(c==d){t=t.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();V()}},{browse:mist.data.streams[b].source},{stream:b}); e.split("&"),f;for(f in e){var g=e[f].split("=")[0];g in b&&delete b[g]}}if(Object.keys(b).length){d=d+Object.values(b).join("&");h.target=h.target+d}}b={};b[c=="auto"?"push_auto_add":"push_start"]=h;if(typeof a!="undefined"&&(a[0]!=h.stream||a[1]!=h.target))b.push_auto_remove=[a];mist.send(function(){UI.navto("Push")},b)}}]});d.append(UI.buildUI(g))}};mist.data.LTS?mist.send(function(a){(t=a.active_streams)||(t=[]);var a=[],b;for(b in t)t[b].indexOf("+")!=-1&&a.push(t[b].replace(/\+.*/,"")+"+");
c++}}if(c==d){t=t.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();V()}},{active_streams:1}):(t=Object.keys(mist.data.streams),V());break;case "Triggers":"triggers"in mist.data.config||(mist.data.config.triggers={});x=$("<tbody>");b=$("<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", t=t.concat(a);var c=0,d=0;for(b in mist.data.streams){t.push(b);if(mist.inputMatch(UI.findInput("Folder").source_match,mist.data.streams[b].source)){t.push(b+"+");mist.send(function(a,b){var e=b.stream,f;for(f 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[f])&&t.push(e+"+"+a.browse.files[f]);d++;if(c==
"string")).append($("<th>")))).append(x);d.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(b);b.stupidtable();b=mist.data.config.triggers; d){t=t.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();V()}},{browse:mist.data.streams[b].source},{stream:b});c++}}if(c==d){t=t.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();V()}},{active_streams:1}):(t=Object.keys(mist.data.streams),V());break;case "Triggers":"triggers"in mist.data.config||(mist.data.config.triggers={});x=$("<tbody>");b=$("<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",
for(f in b)for(g in b[f])r=triggerRewrite(b[f][g]),x.append($("<tr>").attr("data-index",f+","+g).append($("<td>").text(f)).append($("<td>").text("streams"in r?r.streams.join(", "):"")).append($("<td>").text(r.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 "+ "string")).append($("<th>").text("Handler").attr("data-sort-type","string")).append($("<th>")))).append(x);d.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(b);
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":"triggers"in mist.data.config||(mist.data.config.triggers={});c?(c=c.split(","),f=triggerRewrite(mist.data.config.triggers[c[0]][c[1]]),n={triggeron:c[0],appliesto:f.streams,url:f.handler,async:f.sync,"default":f["default"],params:f.params}):(d.html($("<h2>").text("New Trigger")), b.stupidtable();b=mist.data.config.triggers;for(f in b)for(g in b[f])r=triggerRewrite(b[f][g]),x.append($("<tr>").attr("data-index",f+","+g).append($("<td>").text(f)).append($("<td>").text("streams"in r?r.streams.join(", "):"")).append($("<td>").text(r.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(",");
n={});d.append(UI.buildUI([{label:"Trigger on",pointer:{main:n,index:"triggeron"},help:"For what event this trigger should activate.",type:"select",select:[["SYSTEM_START","SYSTEM_START: after MistServer boot"],["SYSTEM_STOP","SYSTEM_STOP: right before MistServer shutdown"],["SYSTEM_CONFIG","SYSTEM_CONFIG: after MistServer configurations have changed"],["OUTPUT_START","OUTPUT_START: right after the start command has been send to a protocol"],["OUTPUT_STOP","OUTPUT_STOP: right after the close command has been send to a protocol "], 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":"triggers"in mist.data.config||(mist.data.config.triggers={});c?(c=c.split(","),f=triggerRewrite(mist.data.config.triggers[c[0]][c[1]]),n={triggeron:c[0],appliesto:f.streams,url:f.handler,async:f.sync,
["STREAM_ADD","STREAM_ADD: right before new stream configured"],["STREAM_CONFIG","STREAM_CONFIG: right before a stream configuration has changed"],["STREAM_REMOVE","STREAM_REMOVE: right before a stream has been deleted"],["STREAM_SOURCE","STREAM_SOURCE: right before stream source is loaded"],["STREAM_LOAD","STREAM_LOAD: right before stream input is loaded in memory"],["STREAM_READY","STREAM_READY: when the stream input is loaded and ready for playback"],["STREAM_UNLOAD","STREAM_UNLOAD: right before the stream input is removed from memory"], "default":f["default"],params:f.params}):(d.html($("<h2>").text("New Trigger")),n={});d.append(UI.buildUI([{label:"Trigger on",pointer:{main:n,index:"triggeron"},help:"For what event this trigger should activate.",type:"select",select:[["SYSTEM_START","SYSTEM_START: after MistServer boot"],["SYSTEM_STOP","SYSTEM_STOP: right before MistServer shutdown"],["SYSTEM_CONFIG","SYSTEM_CONFIG: after MistServer configurations have changed"],["OUTPUT_START","OUTPUT_START: right after the start command has been send to a protocol"],
["STREAM_PUSH","STREAM_PUSH: right before an incoming push is accepted"],["STREAM_TRACK_ADD","STREAM_TRACK_ADD: right before a track will be added to a stream; e.g.: additional push received"],["STREAM_TRACK_REMOVE","STREAM_TRACK_REMOVE: right before a track will be removed track from a stream; e.g.: push timeout"],["STREAM_BUFFER","STREAM_BUFFER: when a buffer changes between mostly full or mostly empty"],["RTMP_PUSH_REWRITE","RTMP_PUSH_REWRITE: allows rewriting of RTMP push URLs from external to internal representation before further parsing"], ["OUTPUT_STOP","OUTPUT_STOP: right after the close command has been send to a protocol "],["STREAM_ADD","STREAM_ADD: right before new stream configured"],["STREAM_CONFIG","STREAM_CONFIG: right before a stream configuration has changed"],["STREAM_REMOVE","STREAM_REMOVE: right before a stream has been deleted"],["STREAM_SOURCE","STREAM_SOURCE: right before stream source is loaded"],["STREAM_LOAD","STREAM_LOAD: right before stream input is loaded in memory"],["STREAM_READY","STREAM_READY: when the stream input is loaded and ready for playback"],
["PUSH_OUT_START","PUSH_OUT_START: before recording/pushing, allow target changes."],["RECORDING_END","RECORDING_END: after a recording finishes."],["CONN_OPEN","CONN_OPEN: right after a new incoming connection has been received"],["CONN_CLOSE","CONN_CLOSE: right after a connection has been closed"],["CONN_PLAY","CONN_PLAY: right before a stream playback of a connection"],["USER_NEW","USER_NEW: a new user connects that hasn't been allowed or denied access before"],["LIVE_BANDWIDTH","LIVE_BANDWIDTH: when the value specified as param is surpassed"]], ["STREAM_UNLOAD","STREAM_UNLOAD: right before the stream input is removed from memory"],["STREAM_PUSH","STREAM_PUSH: right before an incoming push is accepted"],["STREAM_TRACK_ADD","STREAM_TRACK_ADD: right before a track will be added to a stream; e.g.: additional push received"],["STREAM_TRACK_REMOVE","STREAM_TRACK_REMOVE: right before a track will be removed track from a stream; e.g.: push timeout"],["STREAM_BUFFER","STREAM_BUFFER: when a buffer changes between mostly full or mostly empty"],["RTMP_PUSH_REWRITE",
LTSonly:!0,validate:["required"],"function":function(){switch($(this).getval()){case "SYSTEM_START":case "SYSTEM_STOP":case "SYSTEM_CONFIG":case "OUTPUT_START":case "OUTPUT_STOP":case "RTMP_PUSH_REWRITE":$("[name=appliesto]").setval([]).closest(".UIelement").hide();$("[name=params]").setval("").closest(".UIelement").hide();break;case "LIVE_BANDWIDTH":$("[name=appliesto]").closest(".UIelement").show();$("[name=params]").closest(".UIelement").show();break;default:$("[name=appliesto]").closest(".UIelement").show(); "RTMP_PUSH_REWRITE: allows rewriting of RTMP push URLs from external to internal representation before further parsing"],["PUSH_OUT_START","PUSH_OUT_START: before recording/pushing, allow target changes."],["RECORDING_END","RECORDING_END: after a recording finishes."],["CONN_OPEN","CONN_OPEN: right after a new incoming connection has been received"],["CONN_CLOSE","CONN_CLOSE: right after a connection has been closed"],["CONN_PLAY","CONN_PLAY: right before a stream playback of a connection"],["USER_NEW",
$("[name=params]").setval("").closest(".UIelement").hide()}}},{label:"Applies to",pointer:{main:n,index:"appliesto"},help:"For triggers that can apply to specific streams, this value decides what streams they are triggered for. (none checked = always triggered)",type:"checklist",checklist:Object.keys(mist.data.streams),LTSonly:!0},$("<br>"),{label:"Handler (URL or executable)",help:"This can be either an HTTP URL or a full path to an executable.",pointer:{main:n,index:"url"},validate:["required"], "USER_NEW: a new user connects that hasn't been allowed or denied access before"],["LIVE_BANDWIDTH","LIVE_BANDWIDTH: when the value specified as param is surpassed"]],LTSonly:!0,validate:["required"],"function":function(){switch($(this).getval()){case "SYSTEM_START":case "SYSTEM_STOP":case "SYSTEM_CONFIG":case "OUTPUT_START":case "OUTPUT_STOP":case "RTMP_PUSH_REWRITE":$("[name=appliesto]").setval([]).closest(".UIelement").hide();$("[name=params]").setval("").closest(".UIelement").hide();break;case "LIVE_BANDWIDTH":$("[name=appliesto]").closest(".UIelement").show();
type:"str",LTSonly:!0},{label:"Blocking",type:"checkbox",help:"If checked, pauses processing and uses the response of the handler. If the response does not start with 1, true, yes or cont, further processing is aborted. If unchecked, processing is never paused and the response is not checked.",pointer:{main:n,index:"async"},LTSonly:!0},{label:"Parameters",type:"str",help:"The extra data you want this trigger to use.",pointer:{main:n,index:"params"},LTSonly:!0},{label:"Default response",type:"str", $("[name=params]").closest(".UIelement").show();break;default:$("[name=appliesto]").closest(".UIelement").show();$("[name=params]").setval("").closest(".UIelement").hide()}}},{label:"Applies to",pointer:{main:n,index:"appliesto"},help:"For triggers that can apply to specific streams, this value decides what streams they are triggered for. (none checked = always triggered)",type:"checklist",checklist:Object.keys(mist.data.streams),LTSonly:!0},$("<br>"),{label:"Handler (URL or executable)",help:"This can be either an HTTP URL or a full path to an executable.",
help:"For blocking requests, the default response in case the handler cannot be executed for any reason.",pointer:{main:n,index:"default"},LTSonly:!0},{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Triggers")}},{type:"save",label:"Save","function":function(){c&&mist.data.config.triggers[c[0]].splice(c[1],1);var a={handler:n.url,sync:n.async?true:false,streams:typeof n.appliesto=="undefined"?[]:n.appliesto,params:n.params,"default":n["default"]};if(!("triggers"in pointer:{main:n,index:"url"},validate:["required"],type:"str",LTSonly:!0},{label:"Blocking",type:"checkbox",help:"If checked, pauses processing and uses the response of the handler. If the response does not start with 1, true, yes or cont, further processing is aborted. If unchecked, processing is never paused and the response is not checked.",pointer:{main:n,index:"async"},LTSonly:!0},{label:"Parameters",type:"str",help:"The extra data you want this trigger to use.",pointer:{main:n,index:"params"},
mist.data.config))mist.data.config.triggers={};n.triggeron in mist.data.config.triggers||(mist.data.config.triggers[n.triggeron]=[]);mist.data.config.triggers[n.triggeron].push(a);mist.send(function(){UI.navto("Triggers")},{config:mist.data.config})}}]}]));$("[name=triggeron]").trigger("change");break;case "Logs":var sa=$("<button>").text("Refresh now").click(function(){$(this).text("Loading..");mist.send(function(){ea();sa.text("Refresh now")})}).css("padding","0.2em 0.5em").css("flex-grow",0);d.append(UI.buildUI([{type:"help", LTSonly:!0},{label:"Default response",type:"str",help:"For blocking requests, the default response in case the handler cannot be executed for any reason.",pointer:{main:n,index:"default"},LTSonly:!0},{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Triggers")}},{type:"save",label:"Save","function":function(){c&&mist.data.config.triggers[c[0]].splice(c[1],1);var a={handler:n.url,sync:n.async?true:false,streams:typeof n.appliesto=="undefined"?[]:n.appliesto,params:n.params,
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(){ea()})},$(this).val()*1E3)},help:"How often the table below should be updated."},{label:"..or",type:"DOMfield", "default":n["default"]};if(!("triggers"in mist.data.config))mist.data.config.triggers={};n.triggeron in mist.data.config.triggers||(mist.data.config.triggers[n.triggeron]=[]);mist.data.config.triggers[n.triggeron].push(a);mist.send(function(){UI.navto("Triggers")},{config:mist.data.config})}}]}]));$("[name=triggeron]").trigger("change");break;case "Logs":var sa=$("<button>").text("Refresh now").click(function(){$(this).text("Loading..");mist.send(function(){ea();sa.text("Refresh now")})}).css("padding",
DOMfield:sa,help:"Instantly refresh the table below."}]));d.append($("<button>").text("Purge logs").click(function(){mist.send(function(){mist.data.log=[];UI.navto("Logs")},{clearstatlogs:true})}));x=$("<tbody>").css("font-size","0.9em");d.append($("<table>").addClass("logs").append(x));var ua=function(a){var b=$("<span>").text(a);switch(a){case "WARN":b.addClass("orange");break;case "ERROR":case "FAIL":b.addClass("red")}return b},ea=function(){var a=mist.data.log;if(a){a.length>=2&&a[0][0]<a[a.length- "0.2em 0.5em").css("flex-grow",0);d.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(){ea()})},$(this).val()*1E3)},help:"How often the table below should be updated."},
1][0]&&a.reverse();x.html("");for(var b in a){var c=$("<span>").addClass("content"),d=a[b][2].split("|"),e;for(e in d)c.append($("<span>").text(d[e]));x.append($("<tr>").html($("<td>").text(UI.format.dateTime(a[b][0],"long")).css("white-space","nowrap")).append($("<td>").html(ua(a[b][1])).css("text-align","center")).append($("<td>").html(c).css("text-align","left")))}}};ea();break;case "Statistics":var D=$("<span>").text("Loading..");d.append(D);var n={graph:"new"},w=mist.stored.get().graphs?$.extend(!0, {label:"..or",type:"DOMfield",DOMfield:sa,help:"Instantly refresh the table below."}]));d.append($("<button>").text("Purge logs").click(function(){mist.send(function(){mist.data.log=[];UI.navto("Logs")},{clearstatlogs:true})}));x=$("<tbody>").css("font-size","0.9em");d.append($("<table>").addClass("logs").append(x));var ua=function(a){var b=$("<span>").text(a);switch(a){case "WARN":b.addClass("orange");break;case "ERROR":case "FAIL":b.addClass("red")}return b},ea=function(){var a=mist.data.log;if(a){a.length>=
{},mist.stored.get().graphs):{},Q={};for(f in mist.data.streams)Q[f]=!0;for(f in mist.data.active_streams)Q[mist.data.active_streams[f]]=!0;var Q=Object.keys(Q).sort(),fa=[];for(f in mist.data.config.protocols)fa.push(mist.data.config.protocols[f].connector);fa.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;D.html(UI.buildUI([{type:"help", 2&&a[0][0]<a[a.length-1][0]&&a.reverse();x.html("");for(var b in a){var c=$("<span>").addClass("content"),d=a[b][2].split("|"),e;for(e in d)c.append($("<span>").text(d[e]));x.append($("<tr>").html($("<td>").text(UI.format.dateTime(a[b][0],"long")).css("white-space","nowrap")).append($("<td>").html(ua(a[b][1])).css("text-align","center")).append($("<td>").html(c).css("text-align","left")))}}};ea();break;case "Statistics":var D=$("<span>").text("Loading..");d.append(D);var n={graph:"new"},w=mist.stored.get().graphs?
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:n,index:"graph"},classes:["graph_ids"],"function":function(){if($(this).val()){var a=D.find(".graph_xaxis"),b=D.find(".graph_id");if($(this).val()=="new"){a.children("option").prop("disabled",false);b.setval("Graph "+(Object.keys(w).length+ $.extend(!0,{},mist.stored.get().graphs):{},Q={};for(f in mist.data.streams)Q[f]=!0;for(f in mist.data.active_streams)Q[mist.data.active_streams[f]]=!0;var Q=Object.keys(Q).sort(),fa=[];for(f in mist.data.config.protocols)fa.push(mist.data.config.protocols[f].connector);fa.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;
1)).closest("label").show()}else{var c=w[$(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:n,index:"id"},classes:["graph_id"],validate:[function(a){return a in w?{msg:"This graph id has already been used. Please enter something else.",classes:["red"]}: D.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:n,index:"graph"},classes:["graph_ids"],"function":function(){if($(this).val()){var a=D.find(".graph_xaxis"),b=D.find(".graph_id");if($(this).val()=="new"){a.children("option").prop("disabled",
false}]},{label:"Axis type",type:"select",select:[["time","Time line"]],pointer:{main:n,index:"xaxis"},value:"time",classes:["graph_xaxis"],"function":function(){$s=D.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()); false);b.setval("Graph "+(Object.keys(w).length+1)).closest("label").show()}else{var c=w[$(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:n,index:"id"},classes:["graph_id"],validate:[function(a){return a in w?{msg:"This graph id has already been used. Please enter something else.",
$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"]],pointer:{main:n,index:"datatype"},classes:["graph_datatype"],"function":function(){$s=D.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", classes:["red"]}:false}]},{label:"Axis type",type:"select",select:[["time","Time line"]],pointer:{main:n,index:"xaxis"},value:"time",classes:["graph_xaxis"],"function":function(){$s=D.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()+
true);break;default:$s.find("input[type=radio]").prop("disabled",false)}}},{label:"Data origin",type:"radioselect",radioselect:[["total","All"],["stream","The stream:",Q],["protocol","The protocol:",fa]],pointer:{main:n,index:"origin"},value:["total"],classes:["graph_origin"]},{type:"buttons",buttons:[{label:"Add data set",type:"save","function":function(){var a;if(n.graph=="new"){a=UI.plot.addGraph(n,b);w[a.id]=a;D.find("input.graph_id").val("");D.find("select.graph_ids").append($("<option>").text(a.id)).val(a.id).trigger("change")}else a= '"]: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"]],pointer:{main:n,index:"datatype"},classes:["graph_datatype"],"function":function(){$s=D.find(".graph_origin");switch($(this).getval()){case "cpuload":case "memload":$s.find("input[type=radio]").not('[value="total"]').prop("disabled",
w[n.graph];var c=UI.plot.datatype.getOptions({datatype:n.datatype,origin:n.origin});a.datasets.push(c);UI.plot.save(a);UI.plot.go(w)}}]}]));var b=$("<div>").addClass("graph_container");d.append(b);var c=D.find("select.graph_ids");for(a in w){var e=UI.plot.addGraph(w[a],b);c.append($("<option>").text(e.id)).val(e.id);var f=[],g;for(g in w[a].datasets){var h=UI.plot.datatype.getOptions({datatype:w[a].datasets[g].datatype,origin:w[a].datasets[g].origin});f.push(h)}e.datasets=f;w[e.id]=e}c.trigger("change"); 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:",Q],["protocol","The protocol:",fa]],pointer:{main:n,index:"origin"},value:["total"],classes:["graph_origin"]},{type:"buttons",buttons:[{label:"Add data set",type:"save","function":function(){var a;if(n.graph=="new"){a=UI.plot.addGraph(n,b);w[a.id]=a;D.find("input.graph_id").val("");
UI.plot.go(w);UI.interval.set(function(){UI.plot.go(w)},1E4)},{active_streams:!0,capabilities:!0});break;case "Server Stats":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a)},{capabilities:!0});d.append("Loading..");return}var ga=$("<table>"),F=$("<table>"),g={vheader:"CPUs",labels:["Model","Processor speed","Amount of cores","Amount of threads"],content:[]};for(f in mist.data.capabilities.cpu)b=mist.data.capabilities.cpu[f],g.content.push({header:"CPU #"+(Number(f)+ D.find("select.graph_ids").append($("<option>").text(a.id)).val(a.id).trigger("change")}else a=w[n.graph];var c=UI.plot.datatype.getOptions({datatype:n.datatype,origin:n.origin});a.datasets.push(c);UI.plot.save(a);UI.plot.go(w)}}]}]));var b=$("<div>").addClass("graph_container");d.append(b);var c=D.find("select.graph_ids");for(a in w){var e=UI.plot.addGraph(w[a],b);c.append($("<option>").text(e.id)).val(e.id);var f=[],g;for(g in w[a].datasets){var h=UI.plot.datatype.getOptions({datatype:w[a].datasets[g].datatype,
1),body:[b.model,UI.format.addUnit(UI.format.number(b.mhz),"MHz"),b.cores,b.threads]});f=UI.buildVheaderTable(g);var ta=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- origin:w[a].datasets[g].origin});f.push(h)}e.datasets=f;w[e.id]=e}c.trigger("change");UI.plot.go(w);UI.interval.set(function(){UI.plot.go(w)},1E4)},{active_streams:!0,capabilities:!0});break;case "Server Stats":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a)},{capabilities:!0});d.append("Loading..");return}var ga=$("<table>"),F=$("<table>"),g={vheader:"CPUs",labels:["Model","Processor speed","Amount of cores","Amount of threads"],content:[]};for(f in mist.data.capabilities.cpu)b=
a.swapfree)*1048576),UI.format.addUnit("","N/A"),UI.format.bytes(a.swapfree*1048576),UI.format.bytes(a.swaptotal*1048576)]}]},a=UI.buildVheaderTable(a);ga.replaceWith(a);ga=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);F.replaceWith(b);F= mist.data.capabilities.cpu[f],g.content.push({header:"CPU #"+(Number(f)+1),body:[b.model,UI.format.addUnit(UI.format.number(b.mhz),"MHz"),b.cores,b.threads]});f=UI.buildVheaderTable(g);var ta=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*
b};ta();d.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(ga)).append($("<td>").append(F))).append($("<tr>").append($("<td>").append(f).attr("colspan",2))));UI.interval.set(function(){mist.send(function(){ta()},{capabilities:true})},3E4);break;case "Email for Help":f=$.extend({},mist.data); 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);ga.replaceWith(a);ga=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/
delete f.statistics;delete f.totals;delete f.clients;delete f.capabilities;f=JSON.stringify(f);f="Version: "+mist.data.config.version+"\n\nConfig:\n"+f;n={};d.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:n,index:"name"},value:mist.user.name},{type:"email",label:"Your email address",validate:["required"], 100),UI.format.number(b.fifteen/100)]}]};b=UI.buildVheaderTable(b);F.replaceWith(b);F=b};ta();d.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(ga)).append($("<td>").append(F))).append($("<tr>").append($("<td>").append(f).attr("colspan",2))));UI.interval.set(function(){mist.send(function(){ta()},
pointer:{main:n,index:"email"}},{type:"hidden",value:"Integrated Help",pointer:{main:n,index:"subject"}},{type:"hidden",value:"-",pointer:{main:n,index:"company"}},{type:"textarea",rows:20,label:"Your message",validate:["required"],pointer:{main:n,index:"message"}},{type:"textarea",rows:20,label:"Your config file",readonly:!0,value:f,pointer:{main:n,index:"configfile"}},{type:"buttons",buttons:[{type:"save",label:"Send","function":function(a){$(a).text("Sending..");$.ajax({type:"POST",url:"https://mistserver.org/contact?skin=plain", {capabilities:true})},3E4);break;case "Email for Help":f=$.extend({},mist.data);delete f.statistics;delete f.totals;delete f.clients;delete f.capabilities;f=JSON.stringify(f);f="Version: "+mist.data.config.version+"\n\nConfig:\n"+f;n={};d.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:n,index:"name"},
data:n,success:function(a){a=$("<span>").html(a);a.find("script").remove();d.html(a[0].innerHTML)}})}}]}]));break;case "Disconnect":mist.user.password="";delete mist.user.authstring;delete mist.user.loggedin;sessionStorage.removeItem("mistLogin");UI.navto("Login");break;default:d.append($("<p>").text("This tab does not exist."))}d.find(".field").filter(function(){var a=$(this).getval();return a==""||a==null?true:false}).each(function(){var a=[];$(this).is("input, select, textarea")?a.push($(this)): value:mist.user.name},{type:"email",label:"Your email address",validate:["required"],pointer:{main:n,index:"email"}},{type:"hidden",value:"Integrated Help",pointer:{main:n,index:"subject"}},{type:"hidden",value:"-",pointer:{main:n,index:"company"}},{type:"textarea",rows:20,label:"Your message",validate:["required"],pointer:{main:n,index:"message"}},{type:"textarea",rows:20,label:"Your config file",readonly:!0,value:f,pointer:{main:n,index:"configfile"}},{type:"buttons",buttons:[{type:"save",label:"Send",
a=$(this).find("input, select, textarea");if(a.length){$(a[0]).focus();return false}});!navigator.doNotTrack&&mist.user.loggedin&&d.append($("<img>").attr("src","https://www.google-analytics.com/collect?v=1&tid=UA-32426932-1&cid="+mist.data.config.iid+"&t=pageview&dp="+encodeURIComponent("/MI/"+a)+"&dh=MI."+(mist.data.LTS?"Pro":"OS")).css({width:"1px",height:"1px","min-width":"1px",opacity:0.1,position:"absolute",left:"-1000px"}))}}};"origin"in location||(location.origin=location.protocol+"//");var host; "function":function(a){$(a).text("Sending..");$.ajax({type:"POST",url:"https://mistserver.org/contact?skin=plain",data:n,success:function(a){a=$("<span>").html(a);a.find("script").remove();d.html(a[0].innerHTML)}})}}]}]));break;case "Disconnect":mist.user.password="";delete mist.user.authstring;delete mist.user.loggedin;sessionStorage.removeItem("mistLogin");UI.navto("Login");break;default:d.append($("<p>").text("This tab does not exist."))}d.find(".field").filter(function(){var a=$(this).getval();
host="file://"==location.origin?"http://localhost:4242/api":location.origin+location.pathname.replace(/\/+$/,"")+"/api"; return a==""||a==null?true:false}).each(function(){var a=[];$(this).is("input, select, textarea")?a.push($(this)):a=$(this).find("input, select, textarea");if(a.length){$(a[0]).focus();return false}});!navigator.doNotTrack&&mist.user.loggedin&&d.append($("<img>").attr("src","https://www.google-analytics.com/collect?v=1&tid=UA-32426932-1&cid="+mist.data.config.iid+"&t=pageview&dp="+encodeURIComponent("/MI/"+a)+"&dh=MI."+(mist.data.LTS?"Pro":"OS")).css({width:"1px",height:"1px","min-width":"1px",opacity:0.1,
position:"absolute",left:"-1000px"}))}}};"origin"in location||(location.origin=location.protocol+"//");var host;host="file://"==location.origin?"http://localhost:4242/api":location.origin+location.pathname.replace(/\/+$/,"")+"/api";
var mist={data:{},user:{name:"",password:"",host:host},send:function(a,c,d){var c=c||{},d=d||{},d=$.extend(true,{timeOut:3E4,sendData:c},d),b={authorize:{password:mist.user.authstring?MD5(mist.user.password+mist.user.authstring):"",username:mist.user.name}};$.extend(true,b,c);log("Send",$.extend(true,{},c));b={url:mist.user.host,type:"POST",data:{command:JSON.stringify(b)},dataType:"jsonp",crossDomain:true,timeout:d.timeout*1E3,async:true,error:function(b,e){delete mist.user.loggedin;if(!d.hide){switch(e){case "timeout":e= var mist={data:{},user:{name:"",password:"",host:host},send:function(a,c,d){var c=c||{},d=d||{},d=$.extend(true,{timeOut:3E4,sendData:c},d),b={authorize:{password:mist.user.authstring?MD5(mist.user.password+mist.user.authstring):"",username:mist.user.name}};$.extend(true,b,c);log("Send",$.extend(true,{},c));b={url:mist.user.host,type:"POST",data:{command:JSON.stringify(b)},dataType:"jsonp",crossDomain:true,timeout:d.timeout*1E3,async:true,error:function(b,e){delete mist.user.loggedin;if(!d.hide){switch(e){case "timeout":e=
$("<i>").text("The connection timed out. ");break;case "abort":e=$("<i>").text("The connection was aborted. ");break;default:e=$("<i>").text(e+". ").css("text-transform","capitalize")}$("#message").addClass("red").text("An error occurred while attempting to communicate with MistServer:").append($("<br>")).append(e).append($("<a>").text("Send server request again").click(function(){mist.send(a,c,d)}))}UI.navto("Login")},success:function(b){log("Receive",$.extend(true,{},b),"as reply to",d.sendData); $("<i>").text("The connection timed out. ");break;case "abort":e=$("<i>").text("The connection was aborted. ");break;default:e=$("<i>").text(e+". ").css("text-transform","capitalize")}$("#message").addClass("red").text("An error occurred while attempting to communicate with MistServer:").append($("<br>")).append(e).append($("<a>").text("Send server request again").click(function(){mist.send(a,c,d)}))}UI.navto("Login")},success:function(b){log("Receive",$.extend(true,{},b),"as reply to",d.sendData);
delete mist.user.loggedin;switch(b.authorize.status){case "OK":if("streams"in b)if(b.streams)if("incomplete list"in b.streams){delete b.streams["incomplete list"];$.extend(mist.data.streams,b.streams)}else mist.data.streams=b.streams;else mist.data.streams={};var e=$.extend({},b),h=["config","capabilities","ui_settings","LTS","active_streams","browse","log","totals"],q;for(q in e)h.indexOf(q)==-1&&delete e[q];$.extend(mist.data,e);mist.user.loggedin=true;UI.elements.connection.status.text("Connected").removeClass("red").addClass("green"); delete mist.user.loggedin;switch(b.authorize.status){case "OK":if("streams"in b)if(b.streams)if("incomplete list"in b.streams){delete b.streams["incomplete list"];$.extend(mist.data.streams,b.streams)}else mist.data.streams=b.streams;else mist.data.streams={};var e=$.extend({},b),h=["config","capabilities","ui_settings","LTS","active_streams","browse","log","totals"],q;for(q in e)h.indexOf(q)==-1&&delete e[q];$.extend(mist.data,e);mist.user.loggedin=true;UI.elements.connection.status.text("Connected").removeClass("red").addClass("green");

View file

@ -3156,7 +3156,7 @@ var UI = {
var port = {}; var port = {};
var trythese = ['RTMP','RTSP','TS','RTMP.exe','RTSP.exe','TS.exe']; var trythese = ['RTMP','RTSP','RTMP.exe','RTSP.exe'];
for (var i in trythese) { for (var i in trythese) {
if (trythese[i] in mist.data.capabilities.connectors) { if (trythese[i] in mist.data.capabilities.connectors) {
port[trythese[i]] = mist.data.capabilities.connectors[trythese[i]].optional.port['default']; port[trythese[i]] = mist.data.capabilities.connectors[trythese[i]].optional.port['default'];
@ -3183,6 +3183,8 @@ var UI = {
if (port[protocol] == defport[protocol]) { port[protocol] = ''; } if (port[protocol] == defport[protocol]) { port[protocol] = ''; }
else { port[protocol] = ':'+port[protocol]; } else { port[protocol] = ':'+port[protocol]; }
} }
port.TS = "";
port["TS.exe"] = "";
$livestreamhint.find('.field').closest('label').hide(); $livestreamhint.find('.field').closest('label').hide();
for (var i in port) { for (var i in port) {
@ -3270,7 +3272,7 @@ var UI = {
$main.append($style); $main.append($style);
} }
else if (['Buffer','Buffer.exe','TS','TS.exe'].indexOf(input.name) > -1) { else if (['Buffer','Buffer.exe','TS','TS.exe'].indexOf(input.name) > -1) {
var fields = [$('<span>').text('Configure your source to push to:')]; var fields = [$("<br>"),$('<span>').text('Configure your source to push to:')];
switch (input.name) { switch (input.name) {
case 'Buffer': case 'Buffer':
case 'Buffer.exe': case 'Buffer.exe':
@ -3308,16 +3310,21 @@ var UI = {
break; break;
case 'TS': case 'TS':
case 'TS.exe': case 'TS.exe':
fields.push({ if (source.charAt(0) == "/") {
label: 'TS', fields = [];
type: 'span', }
clipboard: true, else {
readonly: true, fields.push({
classes: ['TS'] label: 'TS',
}); type: 'span',
clipboard: true,
readonly: true,
classes: ['TS']
});
}
break; break;
} }
$livestreamhint.html('<br>').append(UI.buildUI(fields)); $livestreamhint.html(UI.buildUI(fields));
updateLiveStreamHint(); updateLiveStreamHint();
} }
} }
@ -4656,7 +4663,7 @@ var UI = {
if (other == "auto") { //options only for automatic pushes if (other == "auto") { //options only for automatic pushes
build.push({ build.push($("<h4>").text("Optional parameters"),{
type: "unix", type: "unix",
label: "Schedule time", label: "Schedule time",
min: 0, min: 0,
@ -4728,7 +4735,9 @@ var UI = {
var obj = {}; var obj = {};
obj[(other == 'auto' ? 'push_auto_add' : 'push_start')] = saveas; obj[(other == 'auto' ? 'push_auto_add' : 'push_start')] = saveas;
if (typeof edit != "undefined") { obj.push_auto_remove = [edit]; } if ((typeof edit != "undefined") && ((edit[0] != saveas.stream) || (edit[1] != saveas.target))) {
obj.push_auto_remove = [edit];
}
mist.send(function(){ mist.send(function(){
UI.navto('Push'); UI.navto('Push');