Merge branch 'development' into LTS_development

This commit is contained in:
Thulinma 2019-02-26 15:36:37 +01:00
commit 94563a6acb
13 changed files with 185 additions and 91 deletions

2
embed/imgs/tmp.svg Normal file
View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="100%" width="100%" class="mist icon graph" preserveaspectratio="none" viewBox="1 -1 2.000999927520752 1" style="width: 4em; height: 1em;"><defs><linearGradient id="uid8410939318158481" x1="0" x2="0" y1="-1" y2="0" gradientunits="userSpaceOnUse"><stop offset="0" stop-color="green"></stop><stop offset="0.33" stop-color="yellow"></stop><stop offset="0.66" stop-color="orange"></stop><stop offset="0" stop-color="red"></stop></lineargradient></defs><path vector-effect="non-scaling-stroke" stroke="url(#uid8410939318158481)" d="M1,-1 L2.000999927520752,-1 L3.000999927520752,-0.9170000000000007"></path></svg>

After

Width:  |  Height:  |  Size: 660 B

File diff suppressed because one or more lines are too long

View file

@ -17,7 +17,7 @@ button:hover{opacity:1}
select{background-color:transparent;color:$stroke;border:none;margin:0 .5em;font-size:inherit;cursor:pointer;-ms-background-color:red}
select>option{background-color:$background}
.browser-edge select,.browser-safari select{border:1px solid $semiFill;border-top:none;border-left:none;margin-top:2px}
@keyframes spin{
@keyframes mistvideo-spin{
0%{transform:rotate(0)}
100%{transform:rotate(360deg)}
}
@ -50,8 +50,8 @@ a{color:$accent}
.mistvideo-placeholder{max-width:100%;max-height:100%}
.mistvideo-topright{position:absolute;top:0;right:0}
.mistvideo-topleft{position:absolute;top:0;left:0}
.mistvideo-delay-display{animation:appear 1s;animation-iteration-count:1;animation-timing-function:steps(1,end)}
@keyframes appear{
.mistvideo-delay-display{animation:mistvideo-appear 1s;animation-iteration-count:1;animation-timing-function:steps(1,end)}
@keyframes mistvideo-appear{
from{opacity:0}
to{opacity:1}
}
@ -60,7 +60,7 @@ svg.icon .fill,svg.icon.fill{fill:$fill}
svg.icon .semiFill,svg.icon.semiFill{fill:$semiFill}
svg.icon .stroke,svg.icon.stroke{stroke:$stroke;vector-effect:non-scaling-stroke}
svg.icon.off .toggle .fill,svg.icon.off .toggle .semiFill,svg.icon.off .toggle.fill,svg.icon.off .toggle.semiFill{fill:none}
svg.icon .spin,svg.icon.spin{animation:spin 1.5s infinite linear;transform-origin:50% 50%}
svg.icon .spin,svg.icon.spin{animation:mistvideo-spin 1.5s infinite linear;transform-origin:50% 50%}
.vjs-text-track-display{pointer-events:none}
.mistvideo{line-height:1.2;font-size:14.5px}
.mistvideo svg{margin:2.5px}
@ -89,5 +89,5 @@ svg.icon.timeout{display:inline-block;height:1em;width:1em;margin:0;margin-right
.mistvideo-error[data-passive] .message{max-width:none}
.mistvideo-error .mistvideo-buttoncontainer{display:flex;flex-flow:row nowrap;justify-content:center}
.mistvideo-error .mistvideo-buttoncontainer .mistvideo-button{white-space:nowrap}
.browser-ie .mist.icon.loading{animation:spin 1.5s infinite linear;transform-origin:50% 50%}
.browser-ie .mist.icon.loading{animation:mistvideo-spin 1.5s infinite linear;transform-origin:50% 50%}
.browser-ie .mist.icon.loading .spin{animation:none}

View file

@ -17,7 +17,7 @@ button:hover{opacity:1}
select{background-color:transparent;color:$stroke;border:none;margin:0 .5em;font-size:inherit;cursor:pointer;-ms-background-color:red}
select>option{background-color:$background}
.browser-edge select,.browser-safari select{border:1px solid $semiFill;border-top:none;border-left:none;margin-top:2px}
@keyframes spin{
@keyframes mistvideo-spin{
0%{transform:rotate(0)}
100%{transform:rotate(360deg)}
}
@ -50,8 +50,8 @@ a{color:$accent}
.mistvideo-placeholder{max-width:100%;max-height:100%}
.mistvideo-topright{position:absolute;top:0;right:0}
.mistvideo-topleft{position:absolute;top:0;left:0}
.mistvideo-delay-display{animation:appear 1s;animation-iteration-count:1;animation-timing-function:steps(1,end)}
@keyframes appear{
.mistvideo-delay-display{animation:mistvideo-appear 1s;animation-iteration-count:1;animation-timing-function:steps(1,end)}
@keyframes mistvideo-appear{
from{opacity:0}
to{opacity:1}
}
@ -60,7 +60,7 @@ svg.icon .fill,svg.icon.fill{fill:$fill}
svg.icon .semiFill,svg.icon.semiFill{fill:$semiFill}
svg.icon .stroke,svg.icon.stroke{stroke:$stroke;vector-effect:non-scaling-stroke}
svg.icon.off .toggle .fill,svg.icon.off .toggle .semiFill,svg.icon.off .toggle.fill,svg.icon.off .toggle.semiFill{fill:none}
svg.icon .spin,svg.icon.spin{animation:spin 1.5s infinite linear;transform-origin:50% 50%}
svg.icon .spin,svg.icon.spin{animation:mistvideo-spin 1.5s infinite linear;transform-origin:50% 50%}
.vjs-text-track-display{pointer-events:none}
.mistvideo{line-height:1.2;font-size:14.5px}
.mistvideo svg{margin:2.5px}
@ -89,7 +89,7 @@ svg.icon.timeout{display:inline-block;height:1em;width:1em;margin:0;margin-right
.mistvideo-error[data-passive] .message{max-width:none}
.mistvideo-error .mistvideo-buttoncontainer{display:flex;flex-flow:row nowrap;justify-content:center}
.mistvideo-error .mistvideo-buttoncontainer .mistvideo-button{white-space:nowrap}
.browser-ie .mist.icon.loading{animation:spin 1.5s infinite linear;transform-origin:50% 50%}
.browser-ie .mist.icon.loading{animation:mistvideo-spin 1.5s infinite linear;transform-origin:50% 50%}
.browser-ie .mist.icon.loading .spin{animation:none}
.mistvideo-log{margin:.5em 0}
.mistvideo-log .logs{max-height:10em;min-height:5em;width:100%;padding:.2em 0;padding-right:1em;overflow-y:auto;overflow-x:hidden;font-size:.9em}

View file

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

View file

@ -733,7 +733,7 @@ function MistVideo(streamName,options) {
//check tracks exist
var meta = MistUtil.tracks.parse(MistVideo.info.meta.tracks);
for (var i in usetracks) {
if ((i in meta) && ((usetracks[i] in meta[i]) || (usetracks[i] == 0))) { continue; }
if ((i in meta) && ((usetracks[i] in meta[i]) || (usetracks[i] == "none"))) { continue; }
MistVideo.log("Skipping trackselection of "+i+" track "+usetracks[i]+" because it does not exist");
delete usetracks[i];
}
@ -750,7 +750,7 @@ function MistVideo(streamName,options) {
switch (i) {
case "audio":
case "video":
if (usetracks[i] == 0) { continue; }
if (usetracks[i] == "none") { continue; }
hlstracks.push(usetracks[i]);
break;
}
@ -782,21 +782,68 @@ function MistVideo(streamName,options) {
}
if (options.setTracks) {
if ("setTrack" in MistVideo.player.api) {
MistVideo.player.onready(function(){
for (var i in options.setTracks) {
MistVideo.player.api.setTrack(i,options.setTracks[i]);
}
if (options.setTracks) {
var setTracks = MistUtil.object.extend({},options.setTracks);
if (("subtitle" in options.setTracks) && ("setSubtitle" in MistVideo.player.api)) {
MistVideo.player.onready(function(){
//find the source for subtitles
var subtitleSource = false;
for (var i in MistVideo.info.source) {
var source = MistVideo.info.source[i];
//this is a subtitle source, and it's the same protocol (HTTP/HTTPS) as the video source
if ((source.type == "html5/text/vtt") && (MistUtil.http.url.split(source.url).protocol == MistUtil.http.url.split(MistVideo.source.url).protocol)) {
subtitleSource = source.url.replace(/.srt$/,".vtt");
break;
}
});
}
else if ("setTracks" in MistVideo.player.api) {
MistVideo.player.onready(function(){
MistVideo.player.api.setTracks(options.setTracks);
});
}
}
if (!subtitleSource) { return; }
//find the track meta information
var tracks = MistUtil.tracks.parse(MistVideo.info.meta.tracks);
if (!("subtitle" in tracks) || !(setTracks.subtitle in tracks.subtitle)) { return; }
meta = tracks.subtitle[setTracks.subtitle];
//add source to the meta
meta.src = MistUtil.http.url.addParam(subtitleSource,{track:setTracks.subtitle});
meta.label = "automatic";
meta.lang = "unknown";
MistVideo.player.api.setSubtitle(meta);
MistUtil.event.send("playerUpdate_trackChanged",{
type: "subtitle",
trackid: setTracks.subtitle
}, MistVideo.video);
delete setTracks.subtitle;
});
}
if ("setTrack" in MistVideo.player.api) {
MistVideo.player.onready(function(){
for (var i in setTracks) {
MistVideo.player.api.setTrack(i,setTracks[i]);
MistUtil.event.send("playerUpdate_trackChanged",{
type: i,
trackid: setTracks[i]
}, MistVideo.video);
}
});
}
else if ("setTracks" in MistVideo.player.api) {
MistVideo.player.onready(function(){
MistVideo.player.api.setTracks(setTracks);
});
for (var i in setTracks) {
MistUtil.event.send("playerUpdate_trackChanged",{
type: i,
trackid: setTracks[i]
}, MistVideo.video);
}
}
}
}

View file

@ -1292,23 +1292,23 @@ MistSkins["default"] = {
return MistVideo.player.api.setTrack(type,value);
}
else {
//gather what tracks we should use
var usetracks = {};
for (var i in selections) {
if ((i == "subtitle") || (selections[i].value == "")) { continue; } //subtitle tracks are handled seperately
usetracks[i] = selections[i].value;
}
if (value != ""){ usetracks[type] = value; }
//use setTracks
if ("setTracks" in MistVideo.player.api) {
return MistVideo.player.api.setTracks(usetracks);
}
//use setSource
if ("setSource" in MistVideo.player.api) {
return MistVideo.player.api.setSource(
MistUtil.http.url.addParam(MistVideo.source.url,usetracks)
);
}
//gather what tracks we should use
var usetracks = {};
for (var i in selections) {
if ((i == "subtitle") || (selections[i].value == "")) { continue; } //subtitle tracks are handled seperately
usetracks[i] = selections[i].value;
}
if (value != ""){ usetracks[type] = value; }
//use setTracks
if ("setTracks" in MistVideo.player.api) {
return MistVideo.player.api.setTracks(usetracks);
}
//use setSource
if ("setSource" in MistVideo.player.api) {
return MistVideo.player.api.setSource(
MistUtil.http.url.addParam(MistVideo.source.url,usetracks)
);
}
}
}
@ -1393,7 +1393,7 @@ MistSkins["default"] = {
}
}
var value = 0;
var value = "none";
if (this.checked) {
if (this.trackType in selections) {
value = selections[this.trackType].value;
@ -1403,9 +1403,9 @@ MistSkins["default"] = {
}
}
else {
value = 0;
value = "none";
}
changeToTracks(this.trackType,(this.checked ? value : 0));
changeToTracks(this.trackType,(this.checked ? value : "none"));
});
}
}
@ -1463,14 +1463,18 @@ MistSkins["default"] = {
//add options to the select
function n(str) {
if (str == "") { return -1; }
return Number(str);
}
var options = MistUtil.object.keys(t,function(a,b){
return Number(a) - Number(b);
return n(a) - n(b);
}); //sort them
for (var i in options) {
var track = t[options[i]];
var option = document.createElement("option");
select.appendChild(option);
option.value = track.trackid;
option.value = ("idx" in track ? track.idx : track.trackid);
if (MistUtil.object.keys(track.different).length) {
option.appendChild(document.createTextNode(orderValues(track.different).join(" ")));
}
@ -1479,6 +1483,15 @@ MistSkins["default"] = {
option.appendChild(document.createTextNode("Track "+(Number(i)+1)));
}
}
MistUtil.event.addListener(MistVideo.video,"playerUpdate_trackChanged",function(e){
if (e.message.type != type) { return; }
select.value = e.message.trackid;
MistVideo.log("Player selected "+type+" track with id "+e.message.trackid);
},select);
if (type == "subtitle") {
MistUtil.event.addListener(select,"change",function(){
try {
@ -1538,13 +1551,6 @@ MistSkins["default"] = {
}
*/
MistUtil.event.addListener(MistVideo.video,"playerUpdate_trackChanged",function(e){
if (e.message.type != type) { return; }
select.value = e.message.trackid;
MistVideo.log("Player selected "+type+" track with id "+e.message.trackid);
},select);
}
}
else {

View file

@ -130,7 +130,7 @@ svg.icon.timeout {
white-space: nowrap;
}
.browser-ie .mist.icon.loading {
animation: spin 1.5s infinite linear;
animation: mistvideo-spin 1.5s infinite linear;
transform-origin: 50% 50%;
}
.browser-ie .mist.icon.loading .spin { animation: none; }

View file

@ -102,7 +102,7 @@ select > option {
margin-top: 2px;
}
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
@keyframes mistvideo-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
[data-fullscreen] {
position: fixed;
top: 0;
@ -200,11 +200,11 @@ a {
left: 0;
}
.mistvideo-delay-display {
animation: appear 1s;
animation: mistvideo-appear 1s;
animation-iteration-count: 1;
animation-timing-function: steps(1,end);
}
@keyframes appear { from { opacity: 0; } to { opacity: 1; } }
@keyframes mistvideo-appear { from { opacity: 0; } to { opacity: 1; } }
svg.icon {
display: block;
@ -220,7 +220,7 @@ svg.icon.off .toggle.semiFill,
svg.icon.off .toggle .fill,
svg.icon.off .toggle .semiFill { fill: none; }
svg.icon.spin, svg.icon .spin {
animation: spin 1.5s infinite linear;
animation: mistvideo-spin 1.5s infinite linear;
transform-origin: 50% 50%;
}
.vjs-text-track-display {

View file

@ -495,10 +495,33 @@ var MistUtil = {
//remove all block comments
css = css.replace(/\/\*.*?\*\//g,"");
//save all @{} blocks
var save = css.match(/@.*?{.*}/g);
//remove all @ {} blocks (media, keyframes, screen etc) and save it to re-insert them after class prepending
//match anything starting with @ something {, until the first }
var save = css.match(/@[^}]*}/g);
for (var i in save) {
css = css.replace(save[i],"@@@@");
//add a placeholder for unfinished replace
css = css.replace(save[i],"@@#@@");
var replacecount = 1;
//while the amount of }s we've replaced is smaller than the amount of {'s in the match
while (replacecount < (save[i].match(/{/g).length)) {
//find the next } and save it in a group
var match = css.match(/@@#@@([^}]*})/); //match anything starting with @@#@@ until the first }
//replace the full match with the unfinished placeholder
css = css.replace(match[0],"@@#@@");
//add the group (the code untill the next }) to the save
save[i] += match[1];
//increase the counter
replacecount++;
}
//after the edits, @@@@ will be replaced with the contents of save[i]
css = css.replace("@@#@@","@@@@");
}
//find and replace selectors
@ -676,7 +699,7 @@ var MistUtil = {
}
if (!(track.type in output)) { output[track.type] = {}; }
output[track.type][track.trackid] = track;
output[track.type][("idx" in track ? track.idx : track.trackid)] = track;
//make up something logical for the track displayname
var name = {};

View file

@ -138,7 +138,7 @@ p.prototype.build = function (MistVideo,callback) {
//trackswitching
MistVideo.player.api.setTrack = function(type,id){
var meta = MistUtil.tracks.parse(MistVideo.info.meta.tracks);
if ((!(type in meta)) || ((!(id in meta[type]) && (id != 0)))) {
if ((!(type in meta)) || ((!(id in meta[type]) && (id != "none")))) {
MistVideo.log("Skipping trackselection of "+type+" track "+id+" because it does not exist");
return;
}
@ -157,7 +157,8 @@ p.prototype.build = function (MistVideo,callback) {
MistUtil.array.multiSort(mistTracks,["bps"]);
var n = false;
for (var i in mistTracks) {
if (mistTracks[i].trackid == id) {
var trackid = ("idx" in mistTracks[i] ? mistTracks[i].idx : mistTracks[i].trackid);
if (trackid == id) {
n = i;
break;
}
@ -191,7 +192,7 @@ p.prototype.build = function (MistVideo,callback) {
//sort by bitrate
MistUtil.array.multiSort(mistTracks,["bps"]);
//get mist's id for the track
var id = mistTracks[e.newQuality].trackid;
var id = ("idx" in mistTracks[e.newQuality] ? mistTracks[e.newQuality].idx : mistTracks[e.newQuality].trackid);
//create an event to pass this to the skin
MistUtil.event.send("playerUpdate_trackChanged",{
@ -222,7 +223,8 @@ p.prototype.build = function (MistVideo,callback) {
var dashsubs = me.dash.getTracksFor("text");
for (var i in dashsubs) {
if (dashsubs[i].id == trackmeta.trackid) {
var trackid = ("idx" in trackmeta ? trackmeta.idx : trackmeta.trackid);
if (dashsubs[i].id == trackid) {
me.dash.setTextTrack(i);
if (!me.dash.isTextEnabled()) { me.dash.enableText(); }
return true;

View file

@ -159,22 +159,22 @@ $(this).getval();$(".embed_code").setval(x(q))},help:"If the video should restar
{label:"Poster",type:"str",pointer:{main:q,index:"poster"},"function":function(){q.poster=$(this).getval();$(".embed_code").setval(x(q))},help:"URL to an image that is displayed when the video is not playing."},{label:"Video URL addition",type:"str",pointer:{main:q,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(){q.urlappend=$(this).getval();$(".embed_code").setval(x(q))}},
{label:"Preselect tracks",type:"DOMfield",DOMfield:L,help:"Pre-select these tracks."},{label:"Monitoring action",type:"select",select:[["","Ask the viewer what to do"],["nextCombo","Try the next source / player combination"]],pointer:{main:q,index:"monitor_action"},"function":function(){q.monitor_action=$(this).getval();$(".embed_code").setval(x(q))},help:"What the player should do when playback is poor."},$("<h3>").text("Protocol stream urls"),ba]));$.ajax({type:"GET",url:H+"json_"+C+".js",success:function(a){var b=
[],c=O.find(".forceType"),d=O.find(".prioritize_type"),g;for(g in a.source){var e=a.source[g],f=UI.humanMime(e.type);b.push({label:f?f+" <span class=description>("+e.type+")</span>":UI.format.capital(e.type),type:"str",value:e.url,readonly:true,qrcode:true,clipboard:true});f=UI.humanMime(e.type);if(c.children('option[value="'+e.type+'"]').length==0){c.append($("<option>").text(f?f+" ("+e.type+")":UI.format.capital(e.type)).val(e.type));d.append($("<option>").text(f?f+" ("+e.type+")":UI.format.capital(e.type)).val(e.type))}}c.val(q.forceType);
d.val(q.prioritize_type);ba.html(UI.buildUI(b));L.html("");b={};for(g in a.meta.tracks){c=a.meta.tracks[g];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(g in b){a=$("<select>").attr("data-type",g).css("flex-grow","1").change(function(){$(this).val()==""?delete q.setTracks[$(this).attr("data-type")]:q.setTracks[$(this).attr("data-type")]=
$(this).val();$(".embed_code").setval(x(q))});L.append(a);b[g].push([-1,"No "+g]);for(var h in b[g])a.append($("<option>").val(b[g][h][0]).text(b[g][h][1]));if(g in q.setTracks){a.val(q.setTracks[g]);if(a.val()==null){a.val("");delete q.setTracks[g];$(".embed_code").setval(x(q))}}}}else L.closest("label").hide();P=true},error:function(){ba.html("Error while retrieving stream info.");L.closest("label").hide();q.setTracks={}}});o=document.createElement("script");o.src=K+"player.js";document.head.appendChild(o);
o.onload=function(){var a=O.find(".forcePlayer"),b;for(b in mistplayers)a.append($("<option>").text(mistplayers[b].name).val(b));document.head.removeChild(this)};o.onerror=function(){document.head.removeChild(this)};break;case "Push":var D=$("<div>").text("Loading..");d.append(D);mist.send(function(a){function b(a){setTimeout(function(){mist.send(function(c){var d=false;if("push_list"in c&&c.push_list&&c.push_list.length){var d=true,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)g.find("tr[data-pushid="+a[e]+"]").remove();else b()},{push_list:1})},1E3)}function c(e,f){var h=$("<span>");if(f=="Automatic"&&e.length>=4){h.append($("<span>").text(e[2]));e[3]&&h.append($("<span>").text(", schedule on "+(new Date(e[3]*1E3)).toLocaleString()));e.length>=5&&e[4]&&h.append($("<span>").text(", complete on "+(new Date(e[4]*1E3)).toLocaleString()))}else 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(f=="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(f=="Automatic"?"Removing..":"Stopping..")));if(f=="Automatic"){var c=e.slice(1);mist.send(function(){a.remove()},{push_auto_remove:[c]})}else mist.send(function(){b([e[0]])},
{push_stop:[e[0]]})}}));if(f=="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 f=[],h;for(h in a.push_list)if(e[1]==a.push_list[h][1]&&e[2]==
a.push_list[h][2]){f.push(a.push_list[h][0]);g.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(f)},{push_stop:f,push_settings:{wait:0}})}}))}return $("<tr>").attr("data-pushid",e[0]).append($("<td>").text(e[1])).append($("<td>").append(h.children())).append(i)}D.html(UI.buildUI([{type:"help",help:"You can push streams to files or other servers, allowing them to broadcast your stream as well."}]));
var d=a.push_settings;d||(d={});var g=$("<table>").append($("<tr>").append($("<th>").text("Stream")).append($("<th>").text("Target")).append($("<th>"))),e=g.clone();if("push_list"in a)for(var f in a.push_list)g.append(c(a.push_list[f],"Manual"));if("push_auto_list"in a)for(f in a.push_auto_list){var h=a.push_auto_list[f].slice();h.unshift(-1);e.append(c(h,"Automatic"))}D.append($("<h3>").text("Automatic pushes")).append(UI.buildUI([{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",label:"Save","function":function(){mist.send(function(){UI.navto("Push")},{push_settings:d})}}]}])).append($("<button>").text("Add an automatic push").click(function(){UI.navto("Start Push",
"auto")}));e.find("tr").length==1?D.append($("<div>").text("No automatic pushes have been configured.").addClass("text").css("margin-top","0.5em")):D.append(e);D.append($("<h3>").text("Pushes")).append($("<button>").text("Start a push").click(function(){UI.navto("Start Push")}));if(g.find("tr").length==1)D.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(f in a.push_list){e.indexOf(a.push_list[f][1])==-1&&e.push(a.push_list[f][1]);h.indexOf(a.push_list[f][2])==-1&&h.push(a.push_list[f][2])}e.sort();h.sort();for(f in e)i.append($("<option>").text(e[f]));for(f in h)j.append($("<option>").text(h[f]));D.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)},
{push_stop:c});g.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 e={},f;for(f in a.push_list)if((c==""||a.push_list[f][1]==c)&&(d==""||a.push_list[f][2]==d))e[a.push_list[f][0]]=a.push_list[f];if(Object.keys(e).length==0)return alert("No matching pushes.");c="Are you sure you want to stop these pushes?\n\n";for(f in e)c=c+(e[f][1]+" to "+e[f][2]+"\n");if(confirm(c)){e=Object.keys(e);mist.send(function(){b(e)},{push_stop:e});for(f in e)g.find("tr[data-pushid="+e[f]+"]").html($("<td colspan=99>").html($("<span>").addClass("red").text("Stopping..")))}}))).append(g)}},
{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 v,T=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){T(a.push_auto_list[b])},{push_auto_list:1});else{var g=[],f;for(f in mist.data.capabilities.connectors){e=mist.data.capabilities.connectors[f];"push_urls"in
e&&(g=g.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){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>",
d.val(q.prioritize_type);ba.html(UI.buildUI(b));L.html("");b={};for(g in a.meta.tracks){c=a.meta.tracks[g];if(c.codec=="subtitle")c.type="subtitle";if(!(c.type!="audio"&&c.type!="video"&&c.type!="subtitle")){c.type in b||(b[c.type]=c.type=="subtitle"?[]:[["","Autoselect "+c.type]]);b[c.type].push([c.trackid,UI.format.capital(c.type)+" track "+(b[c.type].length+(c.type=="subtitle"?1:0))])}}if(Object.keys(b).length){L.closest("label").show();var a=["audio","video","subtitle"],h;for(h in a){g=a[h];if(b[g].length){c=
$("<select>").attr("data-type",g).css("flex-grow","1").change(function(){$(this).val()==""?delete q.setTracks[$(this).attr("data-type")]:q.setTracks[$(this).attr("data-type")]=$(this).val();$(".embed_code").setval(x(q))});L.append(c);g=="subtitle"?b[g].unshift(["","No "+g]):b[g].push([-1,"No "+g]);for(var i in b[g])c.append($("<option>").val(b[g][i][0]).text(b[g][i][1]));if(g in q.setTracks){c.val(q.setTracks[g]);if(c.val()==null){c.val("");delete q.setTracks[g];$(".embed_code").setval(x(q))}}}}}else L.closest("label").hide();
P=true},error:function(){ba.html("Error while retrieving stream info.");L.closest("label").hide();q.setTracks={}}});o=document.createElement("script");o.src=K+"player.js";document.head.appendChild(o);o.onload=function(){var a=O.find(".forcePlayer"),b;for(b in mistplayers)a.append($("<option>").text(mistplayers[b].name).val(b));document.head.removeChild(this)};o.onerror=function(){document.head.removeChild(this)};break;case "Push":var D=$("<div>").text("Loading..");d.append(D);mist.send(function(a){function b(a){setTimeout(function(){mist.send(function(c){var d=
false;if("push_list"in c&&c.push_list&&c.push_list.length){var d=true,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)g.find("tr[data-pushid="+a[e]+"]").remove();else b()},{push_list:1})},1E3)}function c(e,f){var h=$("<span>");if(f=="Automatic"&&e.length>=4){h.append($("<span>").text(e[2]));e[3]&&h.append($("<span>").text(", schedule on "+(new Date(e[3]*1E3)).toLocaleString()));e.length>=5&&e[4]&&h.append($("<span>").text(", complete on "+(new Date(e[4]*
1E3)).toLocaleString()))}else 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(f=="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(f==
"Automatic"?"Removing..":"Stopping..")));if(f=="Automatic"){var c=e.slice(1);mist.send(function(){a.remove()},{push_auto_remove:[c]})}else mist.send(function(){b([e[0]])},{push_stop:[e[0]]})}}));if(f=="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 f=[],h;for(h in a.push_list)if(e[1]==a.push_list[h][1]&&e[2]==a.push_list[h][2]){f.push(a.push_list[h][0]);g.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(f)},{push_stop:f,push_settings:{wait:0}})}}))}return $("<tr>").attr("data-pushid",e[0]).append($("<td>").text(e[1])).append($("<td>").append(h.children())).append(i)}D.html(UI.buildUI([{type:"help",
help:"You can push streams to files or other servers, allowing them to broadcast your stream as well."}]));var d=a.push_settings;d||(d={});var g=$("<table>").append($("<tr>").append($("<th>").text("Stream")).append($("<th>").text("Target")).append($("<th>"))),e=g.clone();if("push_list"in a)for(var f in a.push_list)g.append(c(a.push_list[f],"Manual"));if("push_auto_list"in a)for(f in a.push_auto_list){var h=a.push_auto_list[f].slice();h.unshift(-1);e.append(c(h,"Automatic"))}D.append($("<h3>").text("Automatic pushes")).append(UI.buildUI([{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",label:"Save","function":function(){mist.send(function(){UI.navto("Push")},
{push_settings:d})}}]}])).append($("<button>").text("Add an automatic push").click(function(){UI.navto("Start Push","auto")}));e.find("tr").length==1?D.append($("<div>").text("No automatic pushes have been configured.").addClass("text").css("margin-top","0.5em")):D.append(e);D.append($("<h3>").text("Pushes")).append($("<button>").text("Start a push").click(function(){UI.navto("Start Push")}));if(g.find("tr").length==1)D.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(f in a.push_list){e.indexOf(a.push_list[f][1])==-1&&e.push(a.push_list[f][1]);h.indexOf(a.push_list[f][2])==-1&&h.push(a.push_list[f][2])}e.sort();h.sort();for(f in e)i.append($("<option>").text(e[f]));for(f in h)j.append($("<option>").text(h[f]));D.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)},{push_stop:c});g.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 e={},f;for(f in a.push_list)if((c==""||a.push_list[f][1]==c)&&(d==""||a.push_list[f][2]==d))e[a.push_list[f][0]]=a.push_list[f];if(Object.keys(e).length==0)return alert("No matching pushes.");c="Are you sure you want to stop these pushes?\n\n";for(f in e)c=c+(e[f][1]+
" to "+e[f][2]+"\n");if(confirm(c)){e=Object.keys(e);mist.send(function(){b(e)},{push_stop:e});for(f in e)g.find("tr[data-pushid="+e[f]+"]").html($("<td colspan=99>").html($("<span>").addClass("red").text("Stopping..")))}}))).append(g)}},{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 v,T=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){T(a.push_auto_list[b])},{push_auto_list:1});else{var g=[],f;for(f in mist.data.capabilities.connectors){e=mist.data.capabilities.connectors[f];"push_urls"in e&&(g=g.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){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:v,LTSonly:1},{label:"Target",type:"str",help:"Where the stream will be pushed to.<br> Valid formats: <ul> <li>"+g.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 g)if(mist.inputMatch(g[b],a))return false;return{msg:"Does not match a valid target.<br>Valid formats:<ul><li>"+g.join("</li><li>")+"</li></ul>",classes:["red"]}}],LTSonly:1}];c=="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",

View file

@ -4667,18 +4667,27 @@ var UI = {
var tracks = {};
for (var i in d.meta.tracks) {
var t = d.meta.tracks[i];
if ((t.type != 'audio') && (t.type != 'video')) { continue; }
if (t.codec == "subtitle") {
t.type = "subtitle";
}
if ((t.type != 'audio') && (t.type != 'video') && (t.type != "subtitle")) { continue; }
if (!(t.type in tracks)) {
tracks[t.type] = [['',UI.format.capital(t.type)+' track 1']];
}
else {
tracks[t.type].push([t.trackid,UI.format.capital(t.type)+' track '+(tracks[t.type].length+1)]);
if (t.type == "subtitle") {
tracks[t.type] = [];
}
else {
tracks[t.type] = [[(''),"Autoselect "+t.type]];
}
}
tracks[t.type].push([t.trackid,UI.format.capital(t.type)+' track '+(tracks[t.type].length+(t.type == "subtitle" ? 1 : 0))]);
}
if (Object.keys(tracks).length) {
$setTracks.closest('label').show();
for (var i in tracks) {
var trackarray = ["audio","video","subtitle"];
for (var n in trackarray) {
var i = trackarray[n];
if (!tracks[i].length) { continue; }
var $select = $('<select>').attr('data-type',i).css('flex-grow','1').change(function(){
if ($(this).val() == '') {
delete embedoptions.setTracks[$(this).attr('data-type')];
@ -4689,7 +4698,12 @@ var UI = {
$('.embed_code').setval(embedhtml(embedoptions));
});
$setTracks.append($select);
tracks[i].push([-1,'No '+i]);
if (i == "subtitle") {
tracks[i].unshift(["","No "+i]);
}
else {
tracks[i].push([-1,'No '+i]);
}
for (var j in tracks[i]) {
$select.append(
$('<option>').val(tracks[i][j][0]).text(tracks[i][j][1])