LSP: dynamic push parameters

This commit is contained in:
Cat 2020-10-27 15:21:32 +01:00 committed by Thulinma
parent 415b2ec058
commit d01acc5858
2 changed files with 108 additions and 51 deletions

View file

@ -117,33 +117,33 @@ $(this).closest("div").attr("data-stream"))}),B=$("<span>").addClass("image");if
b).attr("data-stream",b))}break;default:var l=$("<tbody>").append($("<tr>").append("<td>").attr("colspan",6).text("Loading.."));h=$("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Stream name").attr("data-sort-type","string").addClass("sorting-asc")).append($("<th>").text("Source").attr("data-sort-type","string")).append($("<th>").text("Status").attr("data-sort-type","int")).append($("<th>").css("text-align","right").text("Connections").attr("data-sort-type","int")).append($("<th>")).append($("<th>")))).append(l);
c.append(h);h.stupidtable();var q=function(){var a=[],b;for(b in mist.data.active_streams)a.push({streams:[mist.data.active_streams[b]],fields:["clients"],start:-2});mist.send(function(){$.extend(true,z,mist.data.streams);var a=0;l.html("");d.sort();for(var b in d){var c=d[b],g;g=c in mist.data.streams?mist.data.streams[c]:z[c];var e=$("<td>").css("text-align","right").html($("<span>").addClass("description").text("Loading..")),f=0;if(typeof mist.data.totals!="undefined"&&typeof mist.data.totals[c]!=
"undefined"){var h=mist.data.totals[c].all_protocols.clients,f=0;if(h.length){for(a in h)f=f+h[a][1];f=Math.round(f/h.length)}}e.html(UI.format.number(f));if(f==0&&g.online==1)g.online=2;f=$("<td>").css("text-align","right").css("white-space","nowrap");(!("ischild"in g)||!g.ischild)&&f.html($("<button>").text("Settings").click(function(){UI.navto("Edit",$(this).closest("tr").data("index"))})).append($("<button>").text("Delete").click(function(){var a=$(this).closest("tr").data("index");if(confirm('Are you sure you want to delete the stream "'+
a+'"?')){delete mist.data.streams[a];var b={};mist.data.LTS?b.deletestream=[a]:b.streams=mist.data.streams;mist.send(function(){UI.navto("Streams")},b)}}));h=$("<span>").text(g.name);g.ischild&&h.css("padding-left","1em");var Ca=UI.format.status(g),Da=$("<button>").text("Preview").click(function(){UI.navto("Preview",$(this).closest("tr").data("index"))}),j=$("<button>").text("Embed").click(function(){UI.navto("Embed",$(this).closest("tr").data("index"))});if("filesfound"in z[c]||g.online<0){Ca.html("");
Da="";e.html("");j=""}l.append($("<tr>").data("index",c).html($("<td>").html(h).attr("title",g.name=="..."?"The results were truncated":g.name).addClass("overflow_ellipsis")).append($("<td>").text(g.source).attr("title",g.source).addClass("description").addClass("overflow_ellipsis").css("max-width","20em")).append($("<td>").data("sort-value",g.online).html(Ca)).append(e).append($("<td>").css("white-space","nowrap").html(Da).append(j)).append(f));a++}},{totals:a,active_streams:true})};if(mist.data.LTS){var n=
a+'"?')){delete mist.data.streams[a];var b={};mist.data.LTS?b.deletestream=[a]:b.streams=mist.data.streams;mist.send(function(){UI.navto("Streams")},b)}}));h=$("<span>").text(g.name);g.ischild&&h.css("padding-left","1em");var Ca=UI.format.status(g),j=$("<button>").text("Preview").click(function(){UI.navto("Preview",$(this).closest("tr").data("index"))}),k=$("<button>").text("Embed").click(function(){UI.navto("Embed",$(this).closest("tr").data("index"))});if("filesfound"in z[c]||g.online<0){Ca.html("");
j="";e.html("");k=""}l.append($("<tr>").data("index",c).html($("<td>").html(h).attr("title",g.name=="..."?"The results were truncated":g.name).addClass("overflow_ellipsis")).append($("<td>").text(g.source).attr("title",g.source).addClass("description").addClass("overflow_ellipsis").css("max-width","20em")).append($("<td>").data("sort-value",g.online).html(Ca)).append(e).append($("<td>").css("white-space","nowrap").html(j).append(k)).append(f));a++}},{totals:a,active_streams:true})};if(mist.data.LTS){var n=
0,o=0;for(e in mist.data.streams){h=mist.data.capabilities.inputs.Folder||mist.data.capabilities.inputs["Folder.exe"];if(!h)break;if(mist.inputMatch(h.source_match,mist.data.streams[e].source)){z[e].source=z[e].source+"*";z[e].filesfound=null;mist.send(function(a,b){var c=b.stream,d=0,g;a:for(g in a.browse.files){var f;for(f in mist.data.capabilities.inputs)if(!(f.indexOf("Buffer")>=0||f.indexOf("Buffer.exe")>=0||f.indexOf("Folder")>=0||f.indexOf("Folder.exe")>=0)&&mist.inputMatch(mist.data.capabilities.inputs[f].source_match,
"/"+a.browse.files[g])){var e=c+"+"+a.browse.files[g];z[e]=ja(e,mist.data.streams[c]);z[e].source=mist.data.streams[c].source+a.browse.files[g];d++;if(d>=500){z[c+"+zzzzzzzzz"]={ischild:true,name:"...",online:-1};break a}}}"files"in a.browse&&a.browse.files.length?z[c].filesfound=true:mist.data.streams[c].filesfound=false;o++;if(n==o){mist.send(function(){q()},{active_streams:true});UI.interval.set(function(){q()},5E3)}},{browse:mist.data.streams[e].source},{stream:e});n++}}if(n==0){mist.send(function(){q()},
{active_streams:true});UI.interval.set(function(){q()},5E3)}}else{mist.send(function(){q()},{active_streams:true});UI.interval.set(function(){q()},5E3)}}};if(mist.data.LTS){var la=0,Ea=0,t={},Fa=[];for(g in mist.data.streams)if(mist.inputMatch((mist.data.capabilities.inputs.Folder||mist.data.capabilities.inputs["Folder.exe"]).source_match,mist.data.streams[g].source))Fa.push(g),mist.send(function(a,c){var d=c.stream,g=0,f;a:for(f in a.browse.files){var e;for(e in mist.data.capabilities.inputs)if(!(e.indexOf("Buffer")>=
0||e.indexOf("Folder")>=0)&&mist.inputMatch(mist.data.capabilities.inputs[e].source_match,"/"+a.browse.files[f])){t[d+"+"+a.browse.files[f]]=true;g++;if(g>=500){t[d+"+zzzzzzzzz"]=true;break a}}}Ea++;la==Ea&&mist.send(function(){for(var a in mist.data.active_streams){var c=mist.data.active_streams[a].split("+");if(c.length>1&&c[0]in mist.data.streams){t[mist.data.active_streams[a]]=true;z[mist.data.active_streams[a]]=ja(mist.data.active_streams[a],mist.data.streams[c[0]])}}t=Object.keys(t);t=t.concat(Object.keys(mist.data.streams));
t.sort();ka(b,t,Fa)},{active_streams:true})},{browse:mist.data.streams[g].source},{stream:g}),la++;0==la&&mist.send(function(){for(var a in mist.data.active_streams){var c=mist.data.active_streams[a].split("+");if(c.length>1&&c[0]in mist.data.streams){t[mist.data.active_streams[a]]=true;z[mist.data.active_streams[a]]=ja(mist.data.active_streams[a],mist.data.streams[c[0]])}}t=Object.keys(t);mist.data.streams&&(t=t.concat(Object.keys(mist.data.streams)));t.sort();ka(b,t)},{active_streams:!0})}else ka(b,
Object.keys(mist.data.streams));break;case "Edit":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,b)},{capabilities:!0});c.append("Loading..");return}K=!1;""!=b&&(K=!0);if(K){var Ga=b,o=mist.data.streams[Ga];c.find("h2").append(' "'+Ga+'"')}else c.html($("<h2>").text("New Stream")),o={};var Ha=[];for(r in mist.data.capabilities.inputs)Ha.push(mist.data.capabilities.inputs[r].source_match);var ca=$("<div>"),Ia=function(a){var c={};if(!mist.data.streams)mist.data.streams=
{};mist.data.streams[o.name]=o;b!=o.name&&delete mist.data.streams[b];c.addstream={};c.addstream[o.name]=o;if(b!=o.name)c.deletestream=[b];if(o.stop_sessions&&b!=""){c.stop_sessions=b;delete o.stop_sessions}mist.send(function(){delete mist.data.streams[o.name].online;delete mist.data.streams[o.name].error;UI.navto(a,a=="Preview"?o.name:"")},c)},Ja=$("<style>").text("button.saveandpreview { display: none; }"),M=$("<span>"),ma=function(){var a=c.find("[name=name]").val();if(a){var b=parseURL(mist.user.host),
{active_streams:true});UI.interval.set(function(){q()},5E3)}}else{mist.send(function(){q()},{active_streams:true});UI.interval.set(function(){q()},5E3)}}};if(mist.data.LTS){var la=0,Da=0,t={},Ea=[];for(g in mist.data.streams)if(mist.inputMatch((mist.data.capabilities.inputs.Folder||mist.data.capabilities.inputs["Folder.exe"]).source_match,mist.data.streams[g].source))Ea.push(g),mist.send(function(a,c){var d=c.stream,g=0,f;a:for(f in a.browse.files){var e;for(e in mist.data.capabilities.inputs)if(!(e.indexOf("Buffer")>=
0||e.indexOf("Folder")>=0)&&mist.inputMatch(mist.data.capabilities.inputs[e].source_match,"/"+a.browse.files[f])){t[d+"+"+a.browse.files[f]]=true;g++;if(g>=500){t[d+"+zzzzzzzzz"]=true;break a}}}Da++;la==Da&&mist.send(function(){for(var a in mist.data.active_streams){var c=mist.data.active_streams[a].split("+");if(c.length>1&&c[0]in mist.data.streams){t[mist.data.active_streams[a]]=true;z[mist.data.active_streams[a]]=ja(mist.data.active_streams[a],mist.data.streams[c[0]])}}t=Object.keys(t);t=t.concat(Object.keys(mist.data.streams));
t.sort();ka(b,t,Ea)},{active_streams:true})},{browse:mist.data.streams[g].source},{stream:g}),la++;0==la&&mist.send(function(){for(var a in mist.data.active_streams){var c=mist.data.active_streams[a].split("+");if(c.length>1&&c[0]in mist.data.streams){t[mist.data.active_streams[a]]=true;z[mist.data.active_streams[a]]=ja(mist.data.active_streams[a],mist.data.streams[c[0]])}}t=Object.keys(t);mist.data.streams&&(t=t.concat(Object.keys(mist.data.streams)));t.sort();ka(b,t)},{active_streams:!0})}else ka(b,
Object.keys(mist.data.streams));break;case "Edit":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a,b)},{capabilities:!0});c.append("Loading..");return}K=!1;""!=b&&(K=!0);if(K){var Fa=b,o=mist.data.streams[Fa];c.find("h2").append(' "'+Fa+'"')}else c.html($("<h2>").text("New Stream")),o={};var Ga=[];for(r in mist.data.capabilities.inputs)Ga.push(mist.data.capabilities.inputs[r].source_match);var ca=$("<div>"),Ha=function(a){var c={};if(!mist.data.streams)mist.data.streams=
{};mist.data.streams[o.name]=o;b!=o.name&&delete mist.data.streams[b];c.addstream={};c.addstream[o.name]=o;if(b!=o.name)c.deletestream=[b];if(o.stop_sessions&&b!=""){c.stop_sessions=b;delete o.stop_sessions}mist.send(function(){delete mist.data.streams[o.name].online;delete mist.data.streams[o.name].error;UI.navto(a,a=="Preview"?o.name:"")},c)},Ia=$("<style>").text("button.saveandpreview { display: none; }"),M=$("<span>"),ma=function(){var a=c.find("[name=name]").val();if(a){var b=parseURL(mist.user.host),
d=c.find("[name=source]").val(),g=d.match(/@.*/);g&&(g=g[0].substring(1));var f=d.replace(/(?:.+?):\/\//,""),f=f.split("/"),f=f[0],f=f.split(":"),f=f[0];(d=d.match(/:\d+/))&&(d=d[0]);var e={},h=["RTMP","RTSP","RTMP.exe","RTSP.exe"],j;for(j in h)h[j]in mist.data.capabilities.connectors&&(e[h[j]]=mist.data.capabilities.connectors[h[j]].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(j in mist.data.config.protocols){var i=mist.data.config.protocols[j];
if(i.connector==k){if("port"in i)e[k]=i.port;break}}e[k]=e[k]==h[k]?"":":"+e[k]}e.TS="";e["TS.exe"]="";M.find(".field").closest("label").hide();for(j in e){var B;k=d?d:e[j];switch(j){case "RTMP":case "RTMP.exe":B="rtmp://"+b.host+k+"/"+(g?g:"live")+"/";M.find(".field.RTMPurl").setval(B).closest("label").show();M.find(".field.RTMPkey").setval(a==""?"STREAMNAME":a).closest("label").show();B=B+(a==""?"STREAMNAME":a);break;case "RTSP":case "RTSP.exe":B="rtsp://"+b.host+k+"/"+(a==""?"STREAMNAME":a)+(g?
"?pass="+g:"");break;case "TS":case "TS.exe":B="udp://"+(f==""?b.host:f)+k+"/"}M.find(".field."+j.replace(".exe","")).setval(B).closest("label").show()}}},Ka=$("<div>"),na={},t=[],La=$("<div>");for(r in mist.data.capabilities.processes)t.push([r,mist.data.capabilities.processes[r].hrn?mist.data.capabilities.processes[r].hrn:mist.data.capabilities.processes[r].name]);if(t.length){var $a=[{label:"New process",type:"select",select:t,value:t[0][0],pointer:{main:na,index:"process"},"function":function(){var a=
$(this).getval();if(a!=null){var a=mist.data.capabilities.processes[a],b=[$("<h4>").text(a.name+" Process options")];La.html(UI.buildUI(b.concat(mist.convertBuildOptions(a,na))))}}},La];Ka.append(UI.buildUI([$("<br>"),$("<h3>").text("Stream processes"),{label:"Stream processes",itemLabel:"stream process",type:"sublist",sublist:$a,saveas:na,pointer:{main:o,index:"processes"}}]))}c.append(UI.buildUI([{label:"Stream name",type:"str",validate:["required","streamname"],pointer:{main:o,index:"name"},help:"Set the name this stream will be recognised by for players and/or stream pushing."},
{label:"Source",type:"browse",filetypes:Ha,pointer:{main:o,index:"source"},help:"<p> Below is the explanation of the input methods for MistServer. Anything between brackets () will go to default settings if not specified. </p> <table class=valigntop> <tr> <th colspan=3><b>File inputs</b></th> </tr> <tr> <th>File</th> <td> Linux/MacOS:&nbsp;/PATH/FILE<br> Windows:&nbsp;/cygdrive/DRIVE/PATH/FILE </td> <td> For file input please specify the proper path and file.<br> Supported inputs are: DTSC, FLV, MP3. MistServer Pro has TS, MP4, ISMV added as input. </td> </tr> <th> Folder </th> <td> Linux/MacOS:&nbsp;/PATH/<br> Windows:&nbsp;/cygdrive/DRIVE/PATH/ </td> <td class=LTSonly> A folder stream makes all the recognised files in the selected folder available as a stream. </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <tr> <th colspan=3><b>Push inputs</b></th> </tr> <tr> <th>RTMP</th> <td>push://(IP)(@PASSWORD)</td> <td> IP is white listed IP for pushing towards MistServer, if left empty all are white listed.<br> PASSWORD is the application under which to push to MistServer, if it doesn't match the stream will be rejected. PASSWORD is MistServer Pro only. </td> </tr> <tr> <th>RTSP</th> <td>push://(IP)(@PASSWORD)</td> <td class=LTSonly>IP is white listed IP for pushing towards MistServer, if left empty all are white listed.</td> </tr> <tr> <th>TS</th> <td>tsudp://(IP):PORT(/INTERFACE)</td> <td class=LTSonly> IP is the IP address used to listen for this stream, multi-cast IP range is: 224.0.0.0 - 239.255.255.255. If IP is not set all addresses will listened to.<br> PORT is the port you reserve for this stream on the chosen IP.<br> INTERFACE is the interface used, if left all interfaces will be used. </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <tr> <th colspan=3><b>Pull inputs</b></th> </tr> <tr> <th>DTSC</th> <td>dtsc://MISTSERVER_IP:PORT/(STREAMNAME)</td> <td>MISTSERVER_IP is the IP of another MistServer to pull from.<br> PORT is the DTSC port of the other MistServer. (default is 4200)<br> STREAMNAME is the name of the target stream on the other MistServer. If left empty, the name of this stream will be used. </td> </tr> <tr> <th>HLS</th> <td>http://URL/TO/STREAM.m3u8</td> <td class=LTSonly>The URL where the HLS stream is available to MistServer.</td> </tr> <tr> <th>RTSP</th> <td>rtsp://(USER:PASSWORD@)IP(:PORT)(/path)</td> <td class=LTSonly> USER:PASSWORD is the account used if authorization is required.<br> IP is the IP address used to pull this stream from.<br> PORT is the port used to connect through.<br> PATH is the path to be used to identify the correct stream. </td> </tr> </table>".replace(/LTSonly/g,
mist.data.LTS?'""':"LTSonly"),"function":function(){var a=$(this).val();Ja.remove();M.html("");if(a!=""){var b=null,d;for(d in mist.data.capabilities.inputs)if(typeof mist.data.capabilities.inputs[d].source_match!="undefined"&&mist.inputMatch(mist.data.capabilities.inputs[d].source_match,a)){b=d;break}if(b===null)ca.html($("<h3>").text("Unrecognized input").addClass("red")).append($("<span>").text("Please edit the stream source.").addClass("red"));else{b=mist.data.capabilities.inputs[b];ca.html($("<h3>").text(b.name+
" Input options"));var g=mist.convertBuildOptions(b,o);"always_match"in mist.data.capabilities.inputs[d]&&mist.inputMatch(mist.data.capabilities.inputs[d].always_match,a)&&g.push({label:"Always on",type:"checkbox",help:"Keep this input available at all times, even when there are no active viewers.",pointer:{main:o,index:"always_on"}});ca.append(UI.buildUI(g));if(b.name=="Folder")c.append(Ja);else if(["Buffer","Buffer.exe","TS","TS.exe"].indexOf(b.name)>-1){d=[$("<br>"),$("<span>").text("Configure your source to push to:")];
"?pass="+g:"");break;case "TS":case "TS.exe":B="udp://"+(f==""?b.host:f)+k+"/"}M.find(".field."+j.replace(".exe","")).setval(B).closest("label").show()}}},Ja=$("<div>"),na={},t=[],Ka=$("<div>");for(r in mist.data.capabilities.processes)t.push([r,mist.data.capabilities.processes[r].hrn?mist.data.capabilities.processes[r].hrn:mist.data.capabilities.processes[r].name]);if(t.length){var Za=[{label:"New process",type:"select",select:t,value:t[0][0],pointer:{main:na,index:"process"},"function":function(){var a=
$(this).getval();if(a!=null){var a=mist.data.capabilities.processes[a],b=[$("<h4>").text(a.name+" Process options")];Ka.html(UI.buildUI(b.concat(mist.convertBuildOptions(a,na))))}}},Ka];Ja.append(UI.buildUI([$("<br>"),$("<h3>").text("Stream processes"),{label:"Stream processes",itemLabel:"stream process",type:"sublist",sublist:Za,saveas:na,pointer:{main:o,index:"processes"}}]))}c.append(UI.buildUI([{label:"Stream name",type:"str",validate:["required","streamname"],pointer:{main:o,index:"name"},help:"Set the name this stream will be recognised by for players and/or stream pushing."},
{label:"Source",type:"browse",filetypes:Ga,pointer:{main:o,index:"source"},help:"<p> Below is the explanation of the input methods for MistServer. Anything between brackets () will go to default settings if not specified. </p> <table class=valigntop> <tr> <th colspan=3><b>File inputs</b></th> </tr> <tr> <th>File</th> <td> Linux/MacOS:&nbsp;/PATH/FILE<br> Windows:&nbsp;/cygdrive/DRIVE/PATH/FILE </td> <td> For file input please specify the proper path and file.<br> Supported inputs are: DTSC, FLV, MP3. MistServer Pro has TS, MP4, ISMV added as input. </td> </tr> <th> Folder </th> <td> Linux/MacOS:&nbsp;/PATH/<br> Windows:&nbsp;/cygdrive/DRIVE/PATH/ </td> <td class=LTSonly> A folder stream makes all the recognised files in the selected folder available as a stream. </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <tr> <th colspan=3><b>Push inputs</b></th> </tr> <tr> <th>RTMP</th> <td>push://(IP)(@PASSWORD)</td> <td> IP is white listed IP for pushing towards MistServer, if left empty all are white listed.<br> PASSWORD is the application under which to push to MistServer, if it doesn't match the stream will be rejected. PASSWORD is MistServer Pro only. </td> </tr> <tr> <th>RTSP</th> <td>push://(IP)(@PASSWORD)</td> <td class=LTSonly>IP is white listed IP for pushing towards MistServer, if left empty all are white listed.</td> </tr> <tr> <th>TS</th> <td>tsudp://(IP):PORT(/INTERFACE)</td> <td class=LTSonly> IP is the IP address used to listen for this stream, multi-cast IP range is: 224.0.0.0 - 239.255.255.255. If IP is not set all addresses will listened to.<br> PORT is the port you reserve for this stream on the chosen IP.<br> INTERFACE is the interface used, if left all interfaces will be used. </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <tr> <th colspan=3><b>Pull inputs</b></th> </tr> <tr> <th>DTSC</th> <td>dtsc://MISTSERVER_IP:PORT/(STREAMNAME)</td> <td>MISTSERVER_IP is the IP of another MistServer to pull from.<br> PORT is the DTSC port of the other MistServer. (default is 4200)<br> STREAMNAME is the name of the target stream on the other MistServer. If left empty, the name of this stream will be used. </td> </tr> <tr> <th>HLS</th> <td>http://URL/TO/STREAM.m3u8</td> <td class=LTSonly>The URL where the HLS stream is available to MistServer.</td> </tr> <tr> <th>RTSP</th> <td>rtsp://(USER:PASSWORD@)IP(:PORT)(/path)</td> <td class=LTSonly> USER:PASSWORD is the account used if authorization is required.<br> IP is the IP address used to pull this stream from.<br> PORT is the port used to connect through.<br> PATH is the path to be used to identify the correct stream. </td> </tr> </table>".replace(/LTSonly/g,
mist.data.LTS?'""':"LTSonly"),"function":function(){var a=$(this).val();Ia.remove();M.html("");if(a!=""){var b=null,d;for(d in mist.data.capabilities.inputs)if(typeof mist.data.capabilities.inputs[d].source_match!="undefined"&&mist.inputMatch(mist.data.capabilities.inputs[d].source_match,a)){b=d;break}if(b===null)ca.html($("<h3>").text("Unrecognized input").addClass("red")).append($("<span>").text("Please edit the stream source.").addClass("red"));else{b=mist.data.capabilities.inputs[b];ca.html($("<h3>").text(b.name+
" Input options"));var g=mist.convertBuildOptions(b,o);"always_match"in mist.data.capabilities.inputs[d]&&mist.inputMatch(mist.data.capabilities.inputs[d].always_match,a)&&g.push({label:"Always on",type:"checkbox",help:"Keep this input available at all times, even when there are no active viewers.",pointer:{main:o,index:"always_on"}});ca.append(UI.buildUI(g));if(b.name=="Folder")c.append(Ia);else if(["Buffer","Buffer.exe","TS","TS.exe"].indexOf(b.name)>-1){d=[$("<br>"),$("<span>").text("Configure your source to push to:")];
switch(b.name){case "Buffer":case "Buffer.exe":d.push({label:"RTMP full url",type:"span",clipboard:true,readonly:true,classes:["RTMP"],help:"Use this RTMP url if your client doesn't ask for a stream key"});d.push({label:"RTMP url",type:"span",clipboard:true,readonly:true,classes:["RTMPurl"],help:"Use this RTMP url if your client also asks for a stream key"});d.push({label:"RTMP stream key",type:"span",clipboard:true,readonly:true,classes:["RTMPkey"],help:"Use this key if your client asks for a stream key"});
d.push({label:"RTSP",type:"span",clipboard:true,readonly:true,classes:["RTSP"]});break;case "TS":case "TS.exe":a.charAt(0)=="/"?d=[]:d.push({label:"TS",type:"span",clipboard:true,readonly:true,classes:["TS"]})}M.html(UI.buildUI(d));ma()}}}}},{label:"Stop sessions",type:"checkbox",help:"When saving these stream settings, kill this stream's current connections.",LTSonly:!0,pointer:{main:o,index:"stop_sessions"}},M,$("<br>"),{type:"custom",custom:ca},Ka,$("<br>"),$("<h3>").text("Encryption"),{type:"help",
d.push({label:"RTSP",type:"span",clipboard:true,readonly:true,classes:["RTSP"]});break;case "TS":case "TS.exe":a.charAt(0)=="/"?d=[]:d.push({label:"TS",type:"span",clipboard:true,readonly:true,classes:["TS"]})}M.html(UI.buildUI(d));ma()}}}}},{label:"Stop sessions",type:"checkbox",help:"When saving these stream settings, kill this stream's current connections.",LTSonly:!0,pointer:{main:o,index:"stop_sessions"}},M,$("<br>"),{type:"custom",custom:ca},Ja,$("<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."},{label:"License acquisition url",type:"str",LTSonly:!0,pointer:{main:o,index:"la_url"}},$("<br>"),{label:"Content key",type:"str",LTSonly:!0,pointer:{main:o,index:"contentkey"}},{type:"text",text:" - or - "},{label:"Key ID",type:"str",LTSonly:!0,pointer:{main:o,
index:"keyid"}},{label:"Key seed",type:"str",LTSonly:!0,pointer:{main:o,index:"keyseed"}},{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Streams")}},{type:"save",label:"Save","function":function(){Ia("Streams")}},{type:"save",label:"Save and Preview","function":function(){Ia("Preview")},classes:["saveandpreview"]}]}]));c.find("[name=name]").keyup(function(){ma()});ma();break;case "Preview":""==b&&UI.navto("Streams");var N=parseURL(mist.user.host),U=N.protocol,
index:"keyid"}},{label:"Key seed",type:"str",LTSonly:!0,pointer:{main:o,index:"keyseed"}},{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Streams")}},{type:"save",label:"Save","function":function(){Ha("Streams")}},{type:"save",label:"Save and Preview","function":function(){Ha("Preview")},classes:["saveandpreview"]}]}]));c.find("[name=name]").keyup(function(){ma()});ma();break;case "Preview":""==b&&UI.navto("Streams");var N=parseURL(mist.user.host),U=N.protocol,
R=N.host,G=":8080",u=U+R+G+"/";for(r in mist.data.config.protocols)if(s=mist.data.config.protocols[r],"HTTP"==s.connector||"HTTP.exe"==s.connector){s.pubaddr&&s.pubaddr.length?"string"==typeof s.pubaddr?u=s.pubaddr.replace(/\/$/,"")+"/":s.pubaddr.length&&(u=s.pubaddr[0].replace(/\/$/,"")+"/"):(G=s.port?":"+s.port:":8080",u=U+R+G+"/");break}var Q=$("<div>").css({display:"flex","flex-flow":"row wrap","flex-shrink":1,"min-width":"auto"}),V="";-1==b.indexOf("+")&&(V=$("<button>").text("Settings").addClass("settings").click(function(){UI.navto("Edit",
b)}));c.html($("<div>").addClass("bigbuttons").append(V).append($("<button>").text("Embed").addClass("embed").click(function(){UI.navto("Embed",b)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Preview of "'+b+'"')).append(Q);var H=encodeURIComponent(b),Ma=$("<div>").css("flex-shrink","1").css("min-width","auto").css("max-width","100%");Q.append(Ma);var Na=$("<div>"),W=$("<div>").text("Loading player..").css("max-width",
"100%").css("flex-shrink","1").css("min-width","auto"),oa=$("<div>").addClass("controls");Ma.append(W).append(Na).append(oa);$("link#devcss").length||c.append($("<link>").attr("rel","stylesheet").attr("type","text/css").attr("href",u+"skins/dev.css").attr("id","devcss"));var Oa=function(){Na.text("");var d=document.createElement("script");c.append(d);d.src=u+"player.js";d.onerror=function(){W.html($("<p>").append('Failed to load <a href="'+u+'player.js">'+u+"player.js</a>.")).append($("<p>").append("Please check if you've activated the HTTP protocol, if your http port is blocked, or if you're trying to load HTTPS on an HTTP page.")).append($("<button>").text("Reload").css("display",
"block").click(function(){Oa()}))};d.onload=function(){var g=b,f=function(){var a=MistVideoObject.reference;oa.html("");oa.append(a.UI.buildStructure({type:"container",classes:["mistvideo-column"],style:{flexShrink:1},children:[{"if":function(){return this.playerName&&this.source},then:{type:"container",classes:["mistvideo-description"],style:{display:"block"},children:[{type:"playername",style:{display:"inline"}},{type:"text",text:"is playing",style:{margin:"0 0.2em"}},{type:"mimetype"}]}},{type:"decodingIssues",
b)}));c.html($("<div>").addClass("bigbuttons").append(V).append($("<button>").text("Embed").addClass("embed").click(function(){UI.navto("Embed",b)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Preview of "'+b+'"')).append(Q);var H=encodeURIComponent(b),La=$("<div>").css("flex-shrink","1").css("min-width","auto").css("max-width","100%");Q.append(La);var Ma=$("<div>"),W=$("<div>").text("Loading player..").css("max-width",
"100%").css("flex-shrink","1").css("min-width","auto"),oa=$("<div>").addClass("controls");La.append(W).append(Ma).append(oa);$("link#devcss").length||c.append($("<link>").attr("rel","stylesheet").attr("type","text/css").attr("href",u+"skins/dev.css").attr("id","devcss"));var Na=function(){Ma.text("");var d=document.createElement("script");c.append(d);d.src=u+"player.js";d.onerror=function(){W.html($("<p>").append('Failed to load <a href="'+u+'player.js">'+u+"player.js</a>.")).append($("<p>").append("Please check if you've activated the HTTP protocol, if your http port is blocked, or if you're trying to load HTTPS on an HTTP page.")).append($("<button>").text("Reload").css("display",
"block").click(function(){Na()}))};d.onload=function(){var g=b,f=function(){var a=MistVideoObject.reference;oa.html("");oa.append(a.UI.buildStructure({type:"container",classes:["mistvideo-column"],style:{flexShrink:1},children:[{"if":function(){return this.playerName&&this.source},then:{type:"container",classes:["mistvideo-description"],style:{display:"block"},children:[{type:"playername",style:{display:"inline"}},{type:"text",text:"is playing",style:{margin:"0 0.2em"}},{type:"mimetype"}]}},{type:"decodingIssues",
style:{"max-width":"30em","flex-flow":"column nowrap"}},{type:"container",classes:["mistvideo-column","mistvideo-devcontrols"],children:[{type:"text",text:"Player control"},{type:"container",classes:["mistvideo-devbuttons"],style:{"flex-wrap":"wrap"},children:[{"if":function(){return!(!this.player||!this.player.api)},then:{type:"button",title:"Reload the video source",label:"Reload video",onclick:function(){this.player.api.load()}}},{type:"button",title:"Build MistVideo again",label:"Reload player",
onclick:function(){this.reload()}},{type:"button",title:"Switch to the next available player and source combination",label:"Try next combination",onclick:function(){this.nextCombo()}}]},{type:"forcePlayer"},{type:"forceType"},{type:"forceSource"}]},{type:"log"}]}))};if(!(a!="Preview"||!b||b==""||g!=b)){W[0].addEventListener("initialized",f);W[0].addEventListener("initializeFailed",f);MistVideoObject.reference=mistPlay(g,{target:W[0],host:u,skin:"dev",loop:true,MistVideoObject:MistVideoObject})}c[0].removeChild(d)};
MistVideoObject.reference={unload:function(){d.onload=function(){this.parentElement&&this.parentElement.removeChild(this)}}}};Oa();var Pa=$("<div>").append($("<h3>").text("Meta information")),da=$("<span>").text("Loading..");Pa.append(da);Q.append(Pa);""!=H&&$.ajax({type:"GET",url:u+"json_"+H+".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)da.html("No meta information available.");else{a=
MistVideoObject.reference={unload:function(){d.onload=function(){this.parentElement&&this.parentElement.removeChild(this)}}}};Na();var Oa=$("<div>").append($("<h3>").text("Meta information")),da=$("<span>").text("Loading..");Oa.append(da);Q.append(Oa);""!=H&&$.ajax({type:"GET",url:u+"json_"+H+".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)da.html("No meta information available.");else{a=
[];a.push({label:"Type",type:"span",value:c.live?"Live":"Pre-recorded (VoD)"});"format"in c&&a.push({label:"Format",type:"span",value:c.format});c.live&&a.push({label:"Buffer window",type:"span",value:UI.format.addUnit(c.buffer_window,"ms")});var d={audio:{vheader:"Audio",labels:["Codec","Duration","Avg bitrate","Peak bitrate","Channels","Samplerate","Language","Track index"],content:[]},video:{vheader:"Video",labels:["Codec","Duration","Avg bitrate","Peak bitrate","Size","Framerate","Language","Track index",
"Has B-Frames"],content:[]},subtitle:{vheader:"Subtitles",labels:["Codec","Duration","Avg bitrate","Peak bitrate","Language","Track index"],content:[]}},g=Object.keys(c.tracks);g.sort(function(a,b){a=a.split("_").pop();b=b.split("_").pop();return a-b});var f=1,e=1,h=1,j;for(j in g){var k=g[j],i=c.tracks[k];switch(i.type){case "audio":d.audio.content.push({header:"Track "+k.split("_").pop(),body:[i.codec,UI.format.duration((i.lastms-i.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(i.firstms/
1E3)+" to "+UI.format.duration(i.lastms/1E3)+"</span>",b(i,"bps"),b(i,"maxbps"),i.channels,UI.format.addUnit(UI.format.number(i.rate),"Hz"),"language"in i?i.language:"unknown",f]});f++;break;case "video":d.video.content.push({header:"Track "+k.split("_").pop(),body:[i.codec,UI.format.duration((i.lastms-i.firstms)/1E3)+"<br><span class=description>"+UI.format.duration(i.firstms/1E3)+" to "+UI.format.duration(i.lastms/1E3)+"</span>",b(i,"bps"),b(i,"maxbps"),UI.format.addUnit(i.width,"x ")+UI.format.addUnit(i.height,
@ -152,13 +152,13 @@ h]});h++}}}b=["audio","video","subtitle"];j=$("<div>").css({display:"flex","flex
b)}));c.html($("<div>").addClass("bigbuttons").append(V).append($("<button>").text("Preview").addClass("preview").click(function(){UI.navto("Preview",b)})).append($("<button>").addClass("cancel").addClass("return").text("Return").click(function(){UI.navto("Streams")}))).append($("<h2>").text('Embed "'+b+'"'));var X=$("<span>");c.append(X);var H=encodeURIComponent(b),N=parseURL(mist.user.host),U=N.protocol,R=N.host,G=":8080",Y,ea={},u={http:U+R+G+"/"};for(r in mist.data.config.protocols)if(s=mist.data.config.protocols[r],
"HTTP"==s.connector||"HTTP.exe"==s.connector)s.pubaddr?("string"==typeof s.pubaddr?u.http=s.pubaddr.replace(/\/$/,"")+"/":s.pubaddr.length&&(u.http=s.pubaddr[0].replace(/\/$/,"")+"/"),ea.http=s.pubaddr):(G=s.port?":"+s.port:":8080",u.http=U+R+G+"/");else if("HTTPS"==s.connector||"HTTPS.exe"==s.connector)s.pubaddr&&s.pubaddr.length?("string"==typeof s.pubaddr?u.https=s.pubaddr.replace(/\/$/,"")+"/":s.pubaddr.length&&(u.https=s.pubaddr[0].replace(/\/$/,"")+"/"),ea.https=s.pubaddr):(Y=s.port?":"+s.port:
":4433",u.https="https://"+R+Y+"/");var O=u.http,A={http:u.http};"https"in u&&(A.https=u.https);if(otherhost.host||otherhost.https){O=(otherhost.https&&Y?"https://":"http://")+(otherhost.host?otherhost.host:N.host)+(otherhost.https&&Y?Y:G)+"/";if(otherhost.host&&("http"in ea||(A.http=parseURL(A.http,{hostname:otherhost.host}).full),"https"in A&&!("https"in ea)))A.https=parseURL(A.https,{hostname:otherhost.host}).full;O=otherhost.https?A.https:A.http}var Z=!1,pa={forcePlayer:"",forceType:"",controls:!0,
autoplay:!0,loop:!1,muted:!1,fillSpace:!1,poster:"",urlappend:"",setTracks:{}},p=$.extend({},pa),Qa=UI.stored.getOpts();"embedoptions"in Qa&&(p=$.extend(p,Qa.embedoptions,!0),"object"!=typeof p.setTracks&&(p.setTracks={}));var fa={};switch(p.controls){case "stock":fa.controls="stock";break;case !0:fa.controls=1;break;case !1:fa.controls=0}var x=function(){function a(b){switch(typeof b){case "string":return $.isNumeric(b)?b:'"'+b+'"';case "object":return JSON.stringify(b);default:return b}}Z&&UI.stored.saveOpt("embedoptions",
autoplay:!0,loop:!1,muted:!1,fillSpace:!1,poster:"",urlappend:"",setTracks:{}},p=$.extend({},pa),Pa=UI.stored.getOpts();"embedoptions"in Pa&&(p=$.extend(p,Pa.embedoptions,!0),"object"!=typeof p.setTracks&&(p.setTracks={}));var fa={};switch(p.controls){case "stock":fa.controls="stock";break;case !0:fa.controls=1;break;case !1:fa.controls=0}var x=function(){function a(b){switch(typeof b){case "string":return $.isNumeric(b)?b:'"'+b+'"';case "object":return JSON.stringify(b);default:return b}}Z&&UI.stored.saveOpt("embedoptions",
p);for(var c=b+"_",d=12,g="";d--;){var f;f=Math.floor(Math.random()*62);f=f<10?f:f<36?String.fromCharCode(f+55):String.fromCharCode(f+61);g=g+f}var c=c+g,d=['target: document.getElementById("'+c+'")'],e;for(e in p)e=="prioritize_type"?p[e]&&p[e]!=""&&d.push("forcePriority: "+JSON.stringify({source:[["type",[p[e]]]]})):e=="monitor_action"?p[e]&&p[e]!=""&&p[e]=="nextCombo"&&d.push('monitor: {\n action: function(){\n this.MistVideo.log("Switching to nextCombo because of poor playback in "+this.MistVideo.source.type+" ("+Math.round(this.vars.score*1000)/10+"%)");\n this.MistVideo.nextCombo();\n }\n }'):
p[e]!=pa[e]&&(p[e]!=null&&(typeof p[e]!="object"||JSON.stringify(p[e])!=JSON.stringify(pa[e])))&&d.push(e+": "+a(p[e]));e=[];e.push('<div class="mistvideo" id="'+c+'">');e.push(" <noscript>");e.push(' <a href="'+(otherhost.https?A.https:A.http)+H+'.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("'+b+'",{');e.push(" "+d.join(",\n "));e.push(" });");
e.push(" };");e.push(" if (!window.mistplayers) {");e.push(' var p = document.createElement("script");');if("https"in u&&parseURL(u.http).protocol!="https://"){e.push(' if (location.protocol == "https:") { p.src = "'+A.https+'player.js" } ');e.push(' else { p.src = "'+A.http+'player.js" } ')}else e.push(' p.src = "'+O+'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")},qa=$("<span>").text("Loading.."),Ra=x(p),S=$("<div>").text("Loading..").css("display","flex").css("flex-flow","column nowrap"),Sa="";"https"in u&&(Sa=UI.buildUI([{label:"Use HTTPS",type:"checkbox","function":function(){if($(this).getval()!=otherhost.https){otherhost.https=$(this).getval();UI.navto("Embed",b)}},value:otherhost.https}]).find("label"));X.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:N.host)).append($("<span>").addClass("unit").append($("<button>").text("Apply").click(function(){otherhost.host=$(this).closest("label").find("input").val();UI.navto("Embed",b)}))))).append(Sa)).append(UI.buildUI([$("<h3>").text("Urls"),{label:"Stream info json",type:"str",value:O+"json_"+H+".js",readonly:!0,clipboard:!0,help:"Information about this stream as a json page."},{label:"Stream info script",type:"str",value:O+"info_"+H+".js",readonly:!0,
clipboard:!0,help:"This script loads information about this stream into a mistvideo javascript object."},{label:"HTML page",type:"str",value:O+H+".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:Ra,rows:Ra.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."},
e.push("</div>");return e.join("\n")},qa=$("<span>").text("Loading.."),Qa=x(p),S=$("<div>").text("Loading..").css("display","flex").css("flex-flow","column nowrap"),Ra="";"https"in u&&(Ra=UI.buildUI([{label:"Use HTTPS",type:"checkbox","function":function(){if($(this).getval()!=otherhost.https){otherhost.https=$(this).getval();UI.navto("Embed",b)}},value:otherhost.https}]).find("label"));X.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:N.host)).append($("<span>").addClass("unit").append($("<button>").text("Apply").click(function(){otherhost.host=$(this).closest("label").find("input").val();UI.navto("Embed",b)}))))).append(Ra)).append(UI.buildUI([$("<h3>").text("Urls"),{label:"Stream info json",type:"str",value:O+"json_"+H+".js",readonly:!0,clipboard:!0,help:"Information about this stream as a json page."},{label:"Stream info script",type:"str",value:O+"info_"+H+".js",readonly:!0,
clipboard:!0,help:"This script loads information about this stream into a mistvideo javascript object."},{label:"HTML page",type:"str",value:O+H+".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:Qa,rows:Qa.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."},{label:"Prioritize type",type:"select",select:[["","Automatic"]],pointer:{main:p,index:"prioritize_type"},classes:["prioritize_type"],"function":function(){if(Z){p.prioritize_type=$(this).getval();$(".embed_code").setval(x(p))}},help:"Try to use this source type first, but full back to something else if it is not available."},
{label:"Force type",type:"select",select:[["","Automatic"]],pointer:{main:p,index:"forceType"},classes:["forceType"],"function":function(){if(Z){p.forceType=$(this).getval();$(".embed_code").setval(x(p))}},help:"Only use this particular source."},{label:"Force player",type:"select",select:[["","Automatic"]],pointer:{main:p,index:"forcePlayer"},classes:["forcePlayer"],"function":function(){if(Z){p.forcePlayer=$(this).getval();$(".embed_code").setval(x(p))}},help:"Only use this particular player."},
{label:"Controls",type:"select",select:[["1","MistServer Controls"],["stock","Player controls"],["0","None"]],pointer:{main:fa,index:"controls"},"function":function(){p.controls=$(this).getval()==1;switch($(this).getval()){case 0:p.controls=false;break;case 1:p.controls=true;break;case "stock":p.controls="stock"}$(".embed_code").setval(x(p))},help:"The type of controls that should be shown."},{label:"Autoplay",type:"checkbox",pointer:{main:p,index:"autoplay"},"function":function(){p.autoplay=$(this).getval();
@ -182,27 +182,27 @@ min:0,help:"How long the delay should be before MistServer retries an automatic
[],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)},{push_stop:c});e.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?");var g={},f;for(f in a.push_list)if((c==""||a.push_list[f][1]==c)&&(d==""||a.push_list[f][2]==d))g[a.push_list[f][0]]=a.push_list[f];if(Object.keys(g).length==0)return alert("No matching pushes.");c="Are you sure you want to stop these pushes?\n\n";for(f in g)c=c+(g[f][1]+
" to "+g[f][2]+"\n");if(confirm(c)){g=Object.keys(g);mist.send(function(){b(g)},{push_stop:g});for(f in g)e.find("tr[data-pushid="+g[f]+"]").html($("<td colspan=99>").html($("<span>").addClass("red").text("Stopping..")))}}))).append(e)}UI.interval.set(function(){mist.send(function(a){var b=e.find("tr").first();e.empty();e.append(b);for(var d in a.push_list)e.append(c(a.push_list[d]))},{push_list:1})},5E3)},{push_settings:1,push_list:1,push_auto_list:1});break;case "Start Push":if(!("capabilities"in
mist.data)){c.append("Loading Mist capabilities..");mist.send(function(){UI.navto("Start Push",b)},{capabilities:1});return}var w,ha=function(a){var d=false,g=b.split("_");b=g[0];g.length==2&&(d=g[1]);if(d!==false&&typeof a=="undefined")mist.send(function(a){ha(a.push_auto_list[d])},{push_auto_list:1});else{var e=[],f;for(f in mist.data.capabilities.connectors){g=mist.data.capabilities.connectors[f];"push_urls"in g&&(e=e.concat(g.push_urls))}b=="auto"&&c.find("h2").text("Add automatic push");var h=
{};if(b=="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){f=h.target.split("recstartunix=")[1];h.recstartunix=f.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)}}f=[{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>",
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:w,LTSonly:1},{label:"Target",type:"str",help:"Where the stream will be pushed to.<br> Valid formats: <ul> <li>"+e.join("</li><li>")+"</li> </ul> Valid text replacements: <ul> <li>$stream - inserts the stream name used to push to MistServer</li> <li>$day - inserts the current day number</li><li>$month - inserts the current month number</li> <li>$year - inserts the current year number</li><li>$hour - inserts the hour timestamp when stream was received</li> <li>$minute - inserts the minute timestamp the stream was received</li> <li>$seconds - inserts the seconds timestamp when the stream was received</li> <li>$datetime - inserts $year.$month.$day.$hour.$minute.$seconds timestamp when the stream was received</li> </ul> Valid URL parameters: <ul> <li>recstart=123 - media timestamp in milisseconds where the push should start</li> <li>recstop=456 - media timestamp in miliseconds where the push should stop</li> <li>recstartunix=150000000 - unix time in seconds where the push should start. This will override the recstart parameter.</li> <li>recstopunix=150000000 - unix time in seconds where the push should stop. This will override the recstop parameter.</li> </ul>",
pointer:{main:h,index:"target"},validate:["required",function(a){for(var b in e)if(mist.inputMatch(e[b],a))return false;return{msg:"Does not match a valid target.<br>Valid formats:<ul><li>"+e.join("</li><li>")+"</li></ul>",classes:["red"]}}],LTSonly:1}];b=="auto"&&f.push($("<h4>").text("Optional parameters"),{type:"unix",label:"Schedule time",min:0,help:"The time where the push will become active. The default is to start immediately.",pointer:{main:h,index:"scheduletime"}},{type:"unix",label:"Recording start time",
min:0,help:"Where in the media buffer the recording will start. Defaults to the most recently received keyframe.<br>Only makes sense for live streams.",pointer:{main:h,index:"recstartunix"}},{type:"unix",label:"Complete time",min:0,help:"The time where the push will stop. Defaults to never stop automatically.<br>Only makes sense for live streams.",pointer:{main:h,index:"completetime"}});f.push({type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Push")}},{type:"save",
label:"Save","function":function(){var c={};h.recstartunix?c.recstartunix="recstartunix="+h.recstartunix:h.scheduletime&&(c.recstartunix="recstartunix="+h.scheduletime);delete h.recstartunix;if(Object.keys(c).length){var d="?",g=h.target.split("?");if(g.length>1){var d="&",g=g[g.length-1],g=g.split("&"),e;for(e in g){var f=g[e].split("=")[0];f in c&&delete c[f]}}if(Object.keys(c).length){d=d+Object.values(c).join("&");h.target=h.target+d}}c={};c[b=="auto"?"push_auto_add":"push_start"]=h;if(typeof a!=
"undefined"&&(a[0]!=h.stream||a[1]!=h.target))c.push_auto_remove=[a];mist.send(function(){UI.navto("Push")},c)}}]});c.append(UI.buildUI(f))}};mist.data.LTS?mist.send(function(a){(w=a.active_streams)||(w=[]);var a=[],b;for(b in w)w[b].indexOf("+")!=-1&&a.push(w[b].replace(/\+.*/,"")+"+");w=w.concat(a);var c=0,d=0;for(b in mist.data.streams){w.push(b);if(mist.inputMatch(UI.findInput("Folder").source_match,mist.data.streams[b].source)){w.push(b+"+");mist.send(function(a,b){var g=b.stream,e;for(e in a.browse.files)for(var f in mist.data.capabilities.inputs)f.indexOf("Buffer")>=
0||(f.indexOf("Folder")>=0||f.indexOf("Buffer.exe")>=0||f.indexOf("Folder.exe")>=0)||mist.inputMatch(mist.data.capabilities.inputs[f].source_match,"/"+a.browse.files[e])&&w.push(g+"+"+a.browse.files[e]);d++;if(c==d){w=w.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();ha()}},{browse:mist.data.streams[b].source},{stream:b});c++}}if(c==d){w=w.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();ha()}},{active_streams:1}):(w=Object.keys(mist.data.streams),ha());break;case "Triggers":if(!("triggers"in
mist.data.config)||!mist.data.config.triggers)mist.data.config.triggers={};var C=$("<tbody>"),Ta=$("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Trigger on").attr("data-sort-type","string").addClass("sorting-asc")).append($("<th>").text("Applies to").attr("data-sort-type","string")).append($("<th>").text("Handler").attr("data-sort-type","string")).append($("<th>")))).append(C);c.append(UI.buildUI([{type:"help",help:"Triggers are a way to react to events that occur inside MistServer. These allow you to block specific users, redirect streams, keep tabs on what is being pushed where, etcetera. For full documentation, please refer to the developer documentation section on the MistServer website."}])).append($("<button>").text("New trigger").click(function(){UI.navto("Edit Trigger")})).append(Ta);
Ta.stupidtable();var ra=mist.data.config.triggers;for(r in ra)for(var Ua in ra[r]){var sa=triggerRewrite(ra[r][Ua]);C.append($("<tr>").attr("data-index",r+","+Ua).append($("<td>").text(r)).append($("<td>").text("streams"in sa?sa.streams.join(", "):"")).append($("<td>").text(sa.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(",");
mist.data)){c.append("Loading Mist capabilities..");mist.send(function(){UI.navto("Start Push",b)},{capabilities:1});return}var w,ha=function(a){var d=false,g=b.split("_");b=g[0];g.length==2&&(d=g[1]);if(d!==false&&typeof a=="undefined")mist.send(function(a){ha(a.push_auto_list[d])},{push_auto_list:1});else{var e=[],f={},h;for(h in mist.data.capabilities.connectors){g=mist.data.capabilities.connectors[h];if("push_urls"in g){e=e.concat(g.push_urls);f[h]=g.push_urls}}b=="auto"&&c.find("h2").text("Add automatic push");
var i={params:{}};if(b=="auto"&&typeof a!="undefined"){i={stream:a[0],target:a[1],params:{}};g=i.target.split("?");if(g.length>1){params=g.pop();i.target=g.join("?");params=params.split("&");for(h in params){g=params[h].split("=");i.params[g.shift()]=g.join("=")}}}var j=$("<div>").css("margin","1em 0");h=[{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>",
pointer:{main:i,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:w,LTSonly:1},{label:"Target",type:"str",help:"Where the stream will be pushed to.<br> Valid formats: <ul> <li>"+e.join("</li><li>")+"</li> </ul> Valid text replacements: <ul> <li>$stream - inserts the stream name used to push to MistServer</li> <li>$day - inserts the current day number</li><li>$month - inserts the current month number</li> <li>$year - inserts the current year number</li><li>$hour - inserts the hour timestamp when stream was received</li> <li>$minute - inserts the minute timestamp the stream was received</li> <li>$seconds - inserts the seconds timestamp when the stream was received</li> <li>$datetime - inserts $year.$month.$day.$hour.$minute.$seconds timestamp when the stream was received</li> </ul> Valid URL parameters: <ul> <li>recstart=123 - media timestamp in milisseconds where the push should start</li> <li>recstop=456 - media timestamp in miliseconds where the push should stop</li> <li>recstartunix=150000000 - unix time in seconds where the push should start. This will override the recstart parameter.</li> <li>recstopunix=150000000 - unix time in seconds where the push should stop. This will override the recstop parameter.</li> </ul>",
pointer:{main:i,index:"target"},validate:["required",function(a){for(var b in e)if(mist.inputMatch(e[b],a))return false;return{msg:"Does not match a valid target.<br>Valid formats:<ul><li>"+e.join("</li><li>")+"</li></ul>",classes:["red"]}}],"function":function(){var a=false;for(connector in f)for(var b in f[connector])if(mist.inputMatch(f[connector][b],$(this).getval())){a=connector;break}if(a){j.html($("<h3>").text(mist.data.capabilities.connectors[a].friendly));j.append(UI.buildUI(mist.convertBuildOptions({desc:mist.data.capabilities.connectors[a].desc,
optional:mist.data.capabilities.connectors[a].push_parameters},i.params)))}else j.html($("<h4>").addClass("red").text("Unrecognized target.")).append($("<span>").text("Please edit the push target."))},LTSonly:1},j];h.push({type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Push")}},{type:"save",label:"Save","function":function(){var c=i.params,d;for(d in c)c[d]===null&&delete c[d];if(Object.keys(c).length){var g="?",e=i.target.split("?");if(e.length>1){g="&";e=e[e.length-
1];e=e.split("&");for(d in e){var f=e[d].split("=")[0];f in c&&delete c[f]}}if(Object.keys(c).length){e=[];for(d in c)e.push(d+"="+c[d]);g=g+e.join("&");i.target=i.target+g}}c={};c[b=="auto"?"push_auto_add":"push_start"]=i;if(typeof a!="undefined"&&(a[0]!=i.stream||a[1]!=i.target))c.push_auto_remove=[a];mist.send(function(){UI.navto("Push")},c)}}]});c.append(UI.buildUI(h))}};mist.data.LTS?mist.send(function(a){(w=a.active_streams)||(w=[]);var a=[],b;for(b in w)w[b].indexOf("+")!=-1&&a.push(w[b].replace(/\+.*/,
"")+"+");w=w.concat(a);var c=0,d=0;for(b in mist.data.streams){w.push(b);if(mist.inputMatch(UI.findInput("Folder").source_match,mist.data.streams[b].source)){w.push(b+"+");mist.send(function(a,b){var g=b.stream,e;for(e in a.browse.files)for(var f in mist.data.capabilities.inputs)f.indexOf("Buffer")>=0||(f.indexOf("Folder")>=0||f.indexOf("Buffer.exe")>=0||f.indexOf("Folder.exe")>=0)||mist.inputMatch(mist.data.capabilities.inputs[f].source_match,"/"+a.browse.files[e])&&w.push(g+"+"+a.browse.files[e]);
d++;if(c==d){w=w.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();ha()}},{browse:mist.data.streams[b].source},{stream:b});c++}}if(c==d){w=w.filter(function(a,b,c){return c.lastIndexOf(a)===b}).sort();ha()}},{active_streams:1}):(w=Object.keys(mist.data.streams),ha());break;case "Triggers":if(!("triggers"in mist.data.config)||!mist.data.config.triggers)mist.data.config.triggers={};var C=$("<tbody>"),Sa=$("<table>").html($("<thead>").html($("<tr>").html($("<th>").text("Trigger on").attr("data-sort-type",
"string").addClass("sorting-asc")).append($("<th>").text("Applies to").attr("data-sort-type","string")).append($("<th>").text("Handler").attr("data-sort-type","string")).append($("<th>")))).append(C);c.append(UI.buildUI([{type:"help",help:"Triggers are a way to react to events that occur inside MistServer. These allow you to block specific users, redirect streams, keep tabs on what is being pushed where, etcetera. For full documentation, please refer to the developer documentation section on the MistServer website."}])).append($("<button>").text("New trigger").click(function(){UI.navto("Edit Trigger")})).append(Sa);
Sa.stupidtable();var ra=mist.data.config.triggers;for(r in ra)for(var Ta in ra[r]){var sa=triggerRewrite(ra[r][Ta]);C.append($("<tr>").attr("data-index",r+","+Ta).append($("<td>").text(r)).append($("<td>").text("streams"in sa?sa.streams.join(", "):"")).append($("<td>").text(sa.handler)).append($("<td>").html($("<button>").text("Edit").click(function(){UI.navto("Edit Trigger",$(this).closest("tr").attr("data-index"))})).append($("<button>").text("Delete").click(function(){var a=$(this).closest("tr").attr("data-index").split(",");
if(confirm("Are you sure you want to delete this "+a[0]+" trigger?")){mist.data.config.triggers[a[0]].splice(a[1],1);mist.data.config.triggers[a[0]].length==0&&delete mist.data.config.triggers[a[0]];mist.send(function(){UI.navto("Triggers")},{config:mist.data.config})}}))))}break;case "Edit Trigger":if(!("triggers"in mist.data.config)||!mist.data.config.triggers)mist.data.config.triggers={};if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a)},{capabilities:!0});c.append("Loading..");
return}if(b)var b=b.split(","),aa=triggerRewrite(mist.data.config.triggers[b[0]][b[1]]),o={triggeron:b[0],appliesto:aa.streams,url:aa.handler,async:aa.sync,"default":aa["default"],params:aa.params};else c.html($("<h2>").text("New Trigger")),o={};var Va=[];for(r in mist.data.capabilities.triggers)Va.push([r,r+": "+mist.data.capabilities.triggers[r].when]);var ta=$("<div>").addClass("desc"),Wa=$("<div>");c.append(UI.buildUI([{label:"Trigger on",pointer:{main:o,index:"triggeron"},help:"For what event this trigger should activate.",
type:"select",select:Va,LTSonly:!0,validate:["required"],"function":function(){var a=$(this).getval(),b=mist.data.capabilities.triggers[a];ta.html("");if(b){a=[$("<h4>").text("Trigger properties"),{type:"help",help:'The trigger "<i>'+a+'</i>" has the following properties:'},{type:"span",label:"Triggers",value:b.when,help:"When this trigger is activated"}];b.payload!=""&&a.push({label:"Payload",type:"textarea",value:b.payload,rows:b.payload.split("\n").length,readonly:true,clipboard:true,help:"The information this trigger sends to the handler."});
return}if(b)var b=b.split(","),aa=triggerRewrite(mist.data.config.triggers[b[0]][b[1]]),o={triggeron:b[0],appliesto:aa.streams,url:aa.handler,async:aa.sync,"default":aa["default"],params:aa.params};else c.html($("<h2>").text("New Trigger")),o={};var Ua=[];for(r in mist.data.capabilities.triggers)Ua.push([r,r+": "+mist.data.capabilities.triggers[r].when]);var ta=$("<div>").addClass("desc"),Va=$("<div>");c.append(UI.buildUI([{label:"Trigger on",pointer:{main:o,index:"triggeron"},help:"For what event this trigger should activate.",
type:"select",select:Ua,LTSonly:!0,validate:["required"],"function":function(){var a=$(this).getval(),b=mist.data.capabilities.triggers[a];ta.html("");if(b){a=[$("<h4>").text("Trigger properties"),{type:"help",help:'The trigger "<i>'+a+'</i>" has the following properties:'},{type:"span",label:"Triggers",value:b.when,help:"When this trigger is activated"}];b.payload!=""&&a.push({label:"Payload",type:"textarea",value:b.payload,rows:b.payload.split("\n").length,readonly:true,clipboard:true,help:"The information this trigger sends to the handler."});
a.push({type:"span",label:"Requires response",value:function(a){switch(a){case "ignored":return"No. The trigger will ignore the response of the handler.";case "always":return"Yes. The trigger needs a response to proceed.";case "when-blocking":return"The trigger needs a response to proceed if it is configured to be blocking.";default:return a}}(b.response),help:"Whether this trigger requires a response from the trigger handler"});a.push({type:"span",label:"Response action",value:b.response_action,
help:"What this trigger will do with its handler's response"});ta.append(UI.buildUI(a));b.stream_specific?$("[name=appliesto]").closest(".UIelement").show():$("[name=appliesto]").setval([]).closest(".UIelement").hide();if(b.argument){$("[name=params]").closest(".UIelement").show();Wa.text(b.argument)}else $("[name=params]").setval("").closest(".UIelement").hide()}}},ta,$("<h4>").text("Trigger settings"),{label:"Applies to",pointer:{main:o,index:"appliesto"},help:"For triggers that can apply to specific streams, this value decides what streams they are triggered for. (none checked = always triggered)",
help:"What this trigger will do with its handler's response"});ta.append(UI.buildUI(a));b.stream_specific?$("[name=appliesto]").closest(".UIelement").show():$("[name=appliesto]").setval([]).closest(".UIelement").hide();if(b.argument){$("[name=params]").closest(".UIelement").show();Va.text(b.argument)}else $("[name=params]").setval("").closest(".UIelement").hide()}}},ta,$("<h4>").text("Trigger settings"),{label:"Applies to",pointer:{main:o,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:o,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:o,index:"async"},LTSonly:!0},{label:"Parameters",type:"str",help:$("<div>").text("The extra data you want this trigger to use.").append(Wa),pointer:{main:o,index:"params"},LTSonly:!0},{label:"Default response",type:"str",help:"The default response in case the handler fails or is set to non-blocking.",placeholder:"true",pointer:{main:o,index:"default"},LTSonly:!0},{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Triggers")}},{type:"save",label:"Save",
pointer:{main:o,index:"async"},LTSonly:!0},{label:"Parameters",type:"str",help:$("<div>").text("The extra data you want this trigger to use.").append(Va),pointer:{main:o,index:"params"},LTSonly:!0},{label:"Default response",type:"str",help:"The default response in case the handler fails or is set to non-blocking.",placeholder:"true",pointer:{main:o,index:"default"},LTSonly:!0},{type:"buttons",buttons:[{type:"cancel",label:"Cancel","function":function(){UI.navto("Triggers")}},{type:"save",label:"Save",
"function":function(){b&&mist.data.config.triggers[b[0]].splice(b[1],1);var a={handler:o.url,sync:o.async?true:false,streams:typeof o.appliesto=="undefined"?[]:o.appliesto,params:o.params,"default":o["default"]};if(!("triggers"in mist.data.config))mist.data.config.triggers={};o.triggeron in mist.data.config.triggers||(mist.data.config.triggers[o.triggeron]=[]);mist.data.config.triggers[o.triggeron].push(a);mist.send(function(){UI.navto("Triggers")},{config:mist.data.config})}}]}]));$("[name=triggeron]").trigger("change");
break;case "Logs":var Xa=$("<button>").text("Refresh now").click(function(){$(this).text("Loading..");mist.send(function(){ua();Xa.text("Refresh now")})}).css("padding","0.2em 0.5em").css("flex-grow",0);c.append(UI.buildUI([{type:"help",help:"Here you have an overview of all edited settings within MistServer and possible warnings or errors MistServer has encountered. MistServer stores up to 100 logs at a time."},{label:"Refresh every",type:"select",select:[[10,"10 seconds"],[30,"30 seconds"],[60,
"minute"],[300,"5 minutes"]],value:30,"function":function(){UI.interval.clear();UI.interval.set(function(){mist.send(function(){ua()})},$(this).val()*1E3)},help:"How often the table below should be updated."},{label:"..or",type:"DOMfield",DOMfield:Xa,help:"Instantly refresh the table below."}]));c.append($("<button>").text("Purge logs").click(function(){mist.send(function(){mist.data.log=[];UI.navto("Logs")},{clearstatlogs:true})}));C=$("<tbody>").css("font-size","0.9em");c.append($("<table>").addClass("logs").append(C));
var ab=function(a){var b=$("<span>").text(a);switch(a){case "WARN":b.addClass("orange");break;case "ERROR":case "FAIL":b.addClass("red")}return b},ua=function(){var a=mist.data.log;if(a){a.length>=2&&a[0][0]<a[a.length-1][0]&&a.reverse();C.html("");for(var b in a){var c=$("<span>").addClass("content"),d=a[b][2].split("|"),g;for(g in d)c.append($("<span>").text(d[g]));C.append($("<tr>").html($("<td>").text(UI.format.dateTime(a[b][0],"long")).css("white-space","nowrap")).append($("<td>").html(ab(a[b][1])).css("text-align",
break;case "Logs":var Wa=$("<button>").text("Refresh now").click(function(){$(this).text("Loading..");mist.send(function(){ua();Wa.text("Refresh now")})}).css("padding","0.2em 0.5em").css("flex-grow",0);c.append(UI.buildUI([{type:"help",help:"Here you have an overview of all edited settings within MistServer and possible warnings or errors MistServer has encountered. MistServer stores up to 100 logs at a time."},{label:"Refresh every",type:"select",select:[[10,"10 seconds"],[30,"30 seconds"],[60,
"minute"],[300,"5 minutes"]],value:30,"function":function(){UI.interval.clear();UI.interval.set(function(){mist.send(function(){ua()})},$(this).val()*1E3)},help:"How often the table below should be updated."},{label:"..or",type:"DOMfield",DOMfield:Wa,help:"Instantly refresh the table below."}]));c.append($("<button>").text("Purge logs").click(function(){mist.send(function(){mist.data.log=[];UI.navto("Logs")},{clearstatlogs:true})}));C=$("<tbody>").css("font-size","0.9em");c.append($("<table>").addClass("logs").append(C));
var $a=function(a){var b=$("<span>").text(a);switch(a){case "WARN":b.addClass("orange");break;case "ERROR":case "FAIL":b.addClass("red")}return b},ua=function(){var a=mist.data.log;if(a){a.length>=2&&a[0][0]<a[a.length-1][0]&&a.reverse();C.html("");for(var b in a){var c=$("<span>").addClass("content"),d=a[b][2].split("|"),g;for(g in d)c.append($("<span>").text(d[g]));C.append($("<tr>").html($("<td>").text(UI.format.dateTime(a[b][0],"long")).css("white-space","nowrap")).append($("<td>").html($a(a[b][1])).css("text-align",
"center")).append($("<td>").html(c).css("text-align","left")))}}};ua();break;case "Statistics":var D=$("<span>").text("Loading..");c.append(D);var o={graph:"new"},y=mist.stored.get().graphs?$.extend(!0,{},mist.stored.get().graphs):{},ba={};for(r in mist.data.streams)ba[r]=!0;for(r in mist.data.active_streams)ba[mist.data.active_streams[r]]=!0;var ba=Object.keys(ba).sort(),va=[];for(r in mist.data.config.protocols)va.push(mist.data.config.protocols[r].connector);va.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",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:o,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(y).length+1)).closest("label").show()}else{var c=y[$(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")}}},
@ -211,10 +211,10 @@ false);break;case "time":$s.children("option").prop("disabled",false).filter('[v
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",true);break;default:$s.find("input[type=radio]").prop("disabled",false)}}},{label:"Data origin",type:"radioselect",radioselect:[["total","All"],["stream","The stream:",ba],["protocol","The protocol:",va]],pointer:{main:o,index:"origin"},
value:["total"],classes:["graph_origin"]},{type:"buttons",buttons:[{label:"Add data set",type:"save","function":function(){var a;if(o.graph=="new"){a=UI.plot.addGraph(o,b);y[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=y[o.graph];var c=UI.plot.datatype.getOptions({datatype:o.datatype,origin:o.origin});a.datasets.push(c);UI.plot.save(a);UI.plot.go(y)}}]}]));var b=$("<div>").addClass("graph_container");c.append(b);
var d=D.find("select.graph_ids");for(a in y){var g=UI.plot.addGraph(y[a],b);d.append($("<option>").text(g.id)).val(g.id);var e=[],f;for(f in y[a].datasets){var h=UI.plot.datatype.getOptions({datatype:y[a].datasets[f].datatype,origin:y[a].datasets[f].origin});e.push(h)}g.datasets=e;y[g.id]=g}d.trigger("change");UI.plot.go(y);UI.interval.set(function(){UI.plot.go(y)},1E4)},{active_streams:!0,capabilities:!0});break;case "Server Stats":if("undefined"==typeof mist.data.capabilities){mist.send(function(){UI.navto(a)},
{capabilities:!0});c.append("Loading..");return}var wa=$("<table>"),L=$("<table>"),Ya={vheader:"CPUs",labels:["Model","Processor speed","Amount of cores","Amount of threads"],content:[]};for(r in mist.data.capabilities.cpu){var ia=mist.data.capabilities.cpu[r];Ya.content.push({header:"CPU #"+(Number(r)+1),body:[ia.model,UI.format.addUnit(UI.format.number(ia.mhz),"MHz"),ia.cores,ia.threads]})}var bb=UI.buildVheaderTable(Ya),Za=function(){var a=mist.data.capabilities.mem,b=mist.data.capabilities.load,
{capabilities:!0});c.append("Loading..");return}var wa=$("<table>"),L=$("<table>"),Xa={vheader:"CPUs",labels:["Model","Processor speed","Amount of cores","Amount of threads"],content:[]};for(r in mist.data.capabilities.cpu){var ia=mist.data.capabilities.cpu[r];Xa.content.push({header:"CPU #"+(Number(r)+1),body:[ia.model,UI.format.addUnit(UI.format.number(ia.mhz),"MHz"),ia.cores,ia.threads]})}var ab=UI.buildVheaderTable(Xa),Ya=function(){var a=mist.data.capabilities.mem,b=mist.data.capabilities.load,
a={vheader:"Memory",labels:["Used","Cached","Available","Total"],content:[{header:"Physical memory",body:[UI.format.bytes(a.used*1048576)+" ("+UI.format.addUnit(b.memory,"%")+")",UI.format.bytes(a.cached*1048576),UI.format.bytes(a.free*1048576),UI.format.bytes(a.total*1048576)]},{header:"Swap memory",body:[UI.format.bytes((a.swaptotal-a.swapfree)*1048576),UI.format.addUnit("","N/A"),UI.format.bytes(a.swapfree*1048576),UI.format.bytes(a.swaptotal*1048576)]}]},a=UI.buildVheaderTable(a);wa.replaceWith(a);
wa=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);L.replaceWith(b);L=b};Za();c.append(UI.buildUI([{type:"help",help:"You can find general server statistics here. Note that memory and CPU usage is for your entire machine, not just MistServer."}])).append($("<table>").css("width",
"auto").addClass("nolay").append($("<tr>").append($("<td>").append(wa)).append($("<td>").append(L))).append($("<tr>").append($("<td>").append(bb).attr("colspan",2))));UI.interval.set(function(){mist.send(function(){Za()},{capabilities:true})},3E4);break;case "Email for Help":var E=$.extend({},mist.data);delete E.statistics;delete E.totals;delete E.clients;delete E.capabilities;E=JSON.stringify(E);E="Version: "+mist.data.config.version+"\n\nConfig:\n"+E;o={};c.append(UI.buildUI([{type:"help",help:"You can use this form to email MistServer support if you're having difficulties.<br>A copy of your server config file will automatically be included."},
wa=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);L.replaceWith(b);L=b};Ya();c.append(UI.buildUI([{type:"help",help:"You can find general server statistics here. Note that memory and CPU usage is for your entire machine, not just MistServer."}])).append($("<table>").css("width",
"auto").addClass("nolay").append($("<tr>").append($("<td>").append(wa)).append($("<td>").append(L))).append($("<tr>").append($("<td>").append(ab).attr("colspan",2))));UI.interval.set(function(){mist.send(function(){Ya()},{capabilities:true})},3E4);break;case "Email for Help":var E=$.extend({},mist.data);delete E.statistics;delete E.totals;delete E.clients;delete E.capabilities;E=JSON.stringify(E);E="Version: "+mist.data.config.version+"\n\nConfig:\n"+E;o={};c.append(UI.buildUI([{type:"help",help:"You can use this form to email MistServer support if you're having difficulties.<br>A copy of your server config file will automatically be included."},
{type:"str",label:"Your name",validate:["required"],pointer:{main:o,index:"name"},value:mist.user.name},{type:"email",label:"Your email address",validate:["required"],pointer:{main:o,index:"email"}},{type:"hidden",value:"Integrated Help",pointer:{main:o,index:"subject"}},{type:"hidden",value:"-",pointer:{main:o,index:"company"}},{type:"textarea",rows:20,label:"Your message",validate:["required"],pointer:{main:o,index:"message"}},{type:"textarea",rows:20,label:"Your config file",readonly:!0,value:E,
pointer:{main:o,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",data:o,success:function(a){a=$("<span>").html(a);a.find("script").remove();c.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:c.append($("<p>").text("This tab does not exist."))}c.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)):a=$(this).find("input, select, textarea");if(a.length){$(a[0]).focus();return false}})}};"origin"in location||(location.origin=location.protocol+"//");var host;host="file://"==location.origin?"http://localhost:4242/api":location.origin+location.pathname.replace(/\/+$/,"")+"/api";

View file

@ -5346,10 +5346,12 @@ var UI = {
//retrieve a list of valid targets
var target_match = [];
var connector2target_match = {};
for (var i in mist.data.capabilities.connectors) {
var conn = mist.data.capabilities.connectors[i];
if ('push_urls' in conn) {
target_match = target_match.concat(conn.push_urls);
connector2target_match[i] = conn.push_urls;
}
}
@ -5357,12 +5359,28 @@ var UI = {
$main.find('h2').text('Add automatic push');
}
var saveas = {};
//FOR NOW, ASSUME PROTOCOL SETTINGS BUILDSETTINGS ARE USED
var saveas = {params:{}};
if ((other == "auto") && (typeof edit != "undefined")) {
saveas = {
"stream": edit[0],
"target": edit[1]
"target": edit[1],
"params": {}
};
var parts = saveas.target.split("?");
if (parts.length > 1) {
params = parts.pop(); //contains the part that comes after the ?, eg recstartunix=123&scheduletime=456
saveas.target = parts.join("?"); //the rest of the url string can go back into the target
params = params.split("&");
for (var i in params) {
var param = params[i].split("=");
saveas.params[param.shift()] = param.join("=");
}
}
/*
if (edit.length >= 3) { saveas.scheduletime = edit[2]; }
if (edit.length >= 4) { saveas.completetime = edit[3]; }
if (saveas.target.indexOf("recstartunix=") > -1) {
@ -5375,8 +5393,9 @@ var UI = {
saveas.target = saveas.target.replace("recstartunix="+saveas.recstartunix,"").replace("?&","?").replace("&&","&");
if (saveas.target[saveas.target.length-1] == "?") { saveas.target = saveas.target.slice(0,-1); }
}
}*/
}
var $additional_params = $("<div>").css("margin","1em 0");
var build = [{
label: 'Stream name',
type: 'str',
@ -5443,9 +5462,38 @@ var UI = {
classes: ['red']
}
}],
"function": function(){
//find what kind of target this is
var match = false;
for (connector in connector2target_match) {
for (var i in connector2target_match[connector]) {
if (mist.inputMatch(connector2target_match[connector][i],$(this).getval())) {
match = connector;
break;
}
}
}
if (!match) {
$additional_params.html(
$("<h4>").addClass("red").text("Unrecognized target.")
).append(
$("<span>").text("Please edit the push target.")
);
return;
}
$additional_params.html($("<h3>").text(mist.data.capabilities.connectors[match].friendly));
var capa = {
desc: mist.data.capabilities.connectors[match].desc,
optional: mist.data.capabilities.connectors[match].push_parameters
};
$additional_params.append(UI.buildUI(mist.convertBuildOptions(capa,saveas.params)));
},
LTSonly: 1
}];
},$additional_params];
/*
if (other == "auto") { //options only for automatic pushes
build.push($("<h4>").text("Optional parameters"),{
@ -5477,7 +5525,7 @@ var UI = {
}
});
}
}*/
build.push({
type: 'buttons',
@ -5491,15 +5539,20 @@ var UI = {
type: 'save',
label: 'Save',
'function': function(){
var params = {};
if (saveas.recstartunix) {
var params = saveas.params;
for (var i in params) {
if (params[i] === null) {
delete params[i];
}
}
/*if (saveas.recstartunix) {
//append recstartunix to target
params["recstartunix"] = "recstartunix="+saveas.recstartunix;
}
else if (saveas.scheduletime) {
params["recstartunix"] = "recstartunix="+saveas.scheduletime;
}
delete saveas.recstartunix;
delete saveas.recstartunix;*/
if (Object.keys(params).length) {
var append = "?";
var curparams = saveas.target.split("?");
@ -5513,7 +5566,11 @@ var UI = {
}
}
if (Object.keys(params).length) {
append += Object.values(params).join("&");
var str = [];
for (var i in params) {
str.push(i+"="+params[i]);
}
append += str.join("&");
saveas.target += append;
}
}