diff --git a/.gitignore b/.gitignore index bfe2791c..058288f2 100644 --- a/.gitignore +++ b/.gitignore @@ -57,4 +57,5 @@ rules.ninja .ninja_log .ninja_deps aes_ctr128 +/embed/testing diff --git a/embed/core.js b/embed/core.js index 8e9c543b..8930e3f0 100644 --- a/embed/core.js +++ b/embed/core.js @@ -27,10 +27,10 @@ MistPlayer.prototype.sendEvent = function(type,message,target) { return true; } MistPlayer.prototype.addlog = function(msg) { - this.sendEvent('log',msg,this.target); + this.sendEvent('log',msg,this.element); } MistPlayer.prototype.adderror = function(msg) { - this.sendEvent('error',msg,this.target); + this.sendEvent('error',msg,this.element); } MistPlayer.prototype.build = function () { this.addlog('Error in player implementation'); @@ -40,6 +40,32 @@ MistPlayer.prototype.build = function () { err.className = 'error'; return err; } +MistPlayer.prototype.timer = { + timers: {}, + add: function(callback,delay){ + var me = this; + var i = setTimeout(function(){ + delete me.timers[i]; + callback(); + },delay); + this.timers[i] = { + delay: delay, + callback: callback + }; + return i; + }, + remove: function(i){ + clearTimeout(i); + delete this.timers[i]; + }, + clear: function(){ + for (var i in this.timers) { + clearTimeout(i); + } + this.timers = {}; + } +}; + //creates the player element, including custom functions MistPlayer.prototype.getElement = function(tag){ var ele = document.createElement(tag); @@ -164,14 +190,15 @@ MistPlayer.prototype.buildMistControls = function(){ str.push(('0'+secs).slice(-2)); return str.join(':'); } + var timestampValue, bar; function whilePlaying() { timestampValue.nodeValue = formatTime(ele.currentTime); bar.style.width = ((ele.currentTime-ele.startTime)/ele.duration*100)+'%'; - setTimeout(function(){ + me.timer.add(function(){ if (!ele.paused) { whilePlaying(); } - },0.1e3); + },0.5e3); }; function whileLivePlaying(track) { @@ -180,11 +207,11 @@ MistPlayer.prototype.buildMistControls = function(){ timestampValue.nodeValue = formatTime((playtime + track.lastms)/1e3); - setTimeout(function(){ + me.timer.add(function(){ if (!ele.paused) { whileLivePlaying(track); } - },0.1e3); + },0.5e3); }; @@ -216,7 +243,9 @@ MistPlayer.prototype.buildMistControls = function(){ if (options.live) { me.load(); } - me.play(); + else { + me.play(); + } } else { me.pause(); @@ -258,7 +287,7 @@ MistPlayer.prototype.buildMistControls = function(){ bar.style.left = (ele.startTime/ele.duration*100)+'%'; }; progress.ondragstart = function() { return false; }; - var bar = document.createElement('div'); + bar = document.createElement('div'); progress.appendChild(bar); bar.className = 'bar'; var buffers = []; @@ -271,6 +300,11 @@ MistPlayer.prototype.buildMistControls = function(){ ele.addEventListener('seeking',function(){ me.target.setAttribute('data-loading',''); }); + ele.addEventListener('seeked',function(){ + me.target.removeAttribute('data-loading'); + bar.style.left = (ele.currentTime/ele.duration*100)+'%'; + //TODO reset lasttime + }); ele.addEventListener('canplay',function(){ me.target.removeAttribute('data-loading'); }); @@ -285,7 +319,7 @@ MistPlayer.prototype.buildMistControls = function(){ var timestamp = document.createElement('div'); controls.appendChild(timestamp); timestamp.className = 'button timestamp'; - var timestampValue = document.createTextNode('-:--'); + timestampValue = document.createTextNode('-:--'); timestamp.title = 'Time'; timestamp.appendChild(timestampValue); @@ -417,6 +451,9 @@ MistPlayer.prototype.buildMistControls = function(){ name = tracks[i][j].lang; o.setAttribute('data-lang',tracks[i][j].lang); } + else if ('desc' in tracks[i][j]) { + name = tracks[i][j].desc; + } else { name = 'Track '+(Number(j)+1); } @@ -516,6 +553,9 @@ MistPlayer.prototype.buildMistControls = function(){ }); ele.addEventListener('ended',function(){ play.setAttribute('data-state','paused'); + if (options.live) { + me.load(); + } }); ele.addEventListener('volumechange',function(){ var vol = 1 - Math.pow(1-ele.volume,2); //transform back from quadratic @@ -610,7 +650,11 @@ MistPlayer.prototype.askNextCombo = function(msg){ var me = this; if (me.errorstate) { return; } me.errorstate = true; - me.addlog('Showing error window'); + me.report({ + type: 'playback', + warn: 'Showing error window', + msg: msg + }); //show the error var err = document.createElement('div'); @@ -618,7 +662,6 @@ MistPlayer.prototype.askNextCombo = function(msg){ err.appendChild(msgnode); err.className = 'error'; err.style.position = 'absolute'; - err.style.top = 0; err.style.width = '100%'; err.style['margin-left'] = 0; this.target.appendChild(err); @@ -626,7 +669,6 @@ MistPlayer.prototype.askNextCombo = function(msg){ //if there is a next source/player, show a button to activate it var opts = this.mistplaySettings.options; - opts.startCombo = this.mistplaySettings.startCombo; if (mistCheck(mistvideo[this.mistplaySettings.streamname],opts)) { var button = document.createElement('button'); var t = document.createTextNode('Try next source/player'); @@ -640,7 +682,7 @@ MistPlayer.prototype.askNextCombo = function(msg){ //show a button to reload with the current settings var button = document.createElement('button'); var i = document.createElement('div'); //a css countdown clock for 10sec - i.className = 'countdown10'; + i.className = 'countdown'; button.appendChild(i); var t = document.createTextNode('Reload this player'); button.appendChild(t); @@ -649,10 +691,14 @@ MistPlayer.prototype.askNextCombo = function(msg){ me.reload(); } - //after 10 seconds, reload the player - err.timeOut = setTimeout(function(){ + //after 20 seconds, reload the player + err.timeOut = me.timer.add(function(){ + me.report({ + type: 'playback', + warn: 'Automatically reloaded the current player after playback error' + }); button.click(); - },10e3); + },20e3); }; MistPlayer.prototype.cancelAskNextCombo = function(){ @@ -663,13 +709,17 @@ MistPlayer.prototype.cancelAskNextCombo = function(){ var err = this.target.querySelector('.error'); if (err) { this.target.removeChild(err); - if (err.timeOut) { clearTimeout(err.timeOut); } + if (err.timeOut) { this.timer.remove(err.timeOut); } } } }; MistPlayer.prototype.reload = function(){ this.unload(); mistPlay(this.mistplaySettings.streamname,this.mistplaySettings.options); + this.report({ + type: 'init', + info: 'Reloading player' + }); }; MistPlayer.prototype.nextCombo = function(){ this.unload(); @@ -680,8 +730,6 @@ MistPlayer.prototype.nextCombo = function(){ ///send information back to mistserver ///\param msg object containing the information to report MistPlayer.prototype.report = function(msg) { - return false; ///\todo Remove this when the backend reporting function has been coded - ///send a http post request ///\param url (string) url to send to @@ -717,6 +765,10 @@ MistPlayer.prototype.report = function(msg) { msg.userinfo.time = Math.round(((new Date) - this.options.initTime)/1e3); //seconds since the info js was loaded } + this.sendEvent('report',JSON.stringify(msg),this.element); + + return false; ///\todo Remove this when the backend reporting function has been coded + try { httpPost(this.options.host+'/report',{ report: JSON.stringify(msg) @@ -725,9 +777,10 @@ MistPlayer.prototype.report = function(msg) { catch (e) { } } MistPlayer.prototype.unload = function(){ + this.addlog('Unloading..'); if (('pause' in this) && (this.pause)) { this.pause(); } - if ('updateSrc' in this) { this.updateSrc(''); } - //delete this.element; + if ('updateSrc' in this) { this.updateSrc(''); this.load(); } + this.timer.clear(); this.target.innerHTML = ''; }; @@ -786,7 +839,7 @@ function mistCheck(streaminfo,options,embedLog) { return p_shortname; } else { - embedLog('This browser does not support '+loop[s].type); + embedLog('This browser does not support '+loop[s].type+' via '+loop[s].url); } } } @@ -862,11 +915,11 @@ function mistPlay(streamName,options) { loop: false, //don't loop when the stream has finished poster: null, //don't show an image before the stream has started callback: false, //don't call a function when the player has finished building - streaminfo: false, //don't use this streaminfo but collect it from the mistserverhost - startCombo: false, - forceType: false, - forcePlayer: false, - forceSource: false + streaminfo: false, //don't use this streaminfo but collect it from the mistserverhost + startCombo: false, //start looking for a player/source match at the start + forceType: false, //don't force a mimetype + forcePlayer: false, //don't force a player + forceSource: false //don't force a source }; for (var i in global) { options[i] = global[i]; @@ -879,9 +932,19 @@ function mistPlay(streamName,options) { mistError('MistServer host undefined.'); return; } + if (!options.target) { + mistError('Target container undefined'); + return; + } options.target.setAttribute('data-loading',''); + var classes = options.target.className.split(' '); + if (classes.indexOf('mistvideo') == -1) { + classes.push('mistvideo'); + options.target.className = classes.join(' '); + } + //check if the css is loaded if (!document.getElementById('mist_player_css')) { var css = document.createElement('link'); @@ -1033,20 +1096,26 @@ function mistPlay(streamName,options) { var skip = false; switch (t.type) { case 'video': - t.desc = ['['+t.codec+']',t.width+'x'+t.height,Math.round(t.bps/1024)+'kbps',t.fpks/1e3+'fps',t.lang]; + t.desc = [t.width+'x'+t.height,/*Math.round(t.bps/1024)+'kbps',*/t.fpks/1e3+'fps',t.codec]; + if (t.lang) { + t.desc.unshift(t.lang); + } break; case 'audio': - t.desc = ['['+t.codec+']',t.channels+' channels',Math.round(t.bps/1024)+'kbps',t.rate+'Hz',t.lang]; + t.desc = [(t.channels == 2 ? 'Stereo' : (t.channels == 1 ? 'Mono' : t.channels+' channels')),/*Math.round(t.bps/1024)+'kbps',*/Math.round(t.rate/1000)+'kHz',t.codec]; + if (t.lang) { + t.desc.unshift(t.lang); + } break; case 'subtitle': - t.desc = ['['+t.codec+']',t.lang]; + t.desc = [t.lang,t.codec]; break; default: skip = true; break; } if (skip) { continue; } - t.desc = t.desc.join(', '); + t.desc = t.desc.join(' '); tracks[t.type].push(t); } player.tracks = tracks; @@ -1115,8 +1184,6 @@ function mistPlay(streamName,options) { } //monitor for errors - element.checkStalledTimeout = false; - element.checkProgressTimeout = false; element.sendPingTimeout = setInterval(function(){ if (player.paused) { return; } player.report({ @@ -1128,8 +1195,7 @@ function mistPlay(streamName,options) { player.askNextCombo('The player has thrown an error'); var r = { type: 'playback', - error: 'The player has thrown an error', - origin: e.target.outerHTML.slice(0,e.target.outerHTML.indexOf('>')+1), + error: 'The player has thrown an error' }; if ('readyState' in player.element) { r.readyState = player.element.readyState; @@ -1137,90 +1203,90 @@ function mistPlay(streamName,options) { if ('networkState' in player.element) { r.networkState = player.element.networkState; } - if (('error' in player.element) && ('code' in player.element.error)) { + if (('error' in player.element) && (player.element.error) && ('code' in player.element.error)) { r.code = player.element.error.code; } player.report(r); }); + element.checkStalledTimeout = false; var stalled = function(e){ if (element.checkStalledTimeout) { return; } - element.checkStalledTimeout = setTimeout(function(){ - if (player.paused) { return; } + var curpos = player.element.currentTime; + if (curpos == 0) { return; } + element.checkStalledTimeout = player.timer.add(function(){ + if ((player.paused) || (curpos != player.element.currentTime)) { return; } player.askNextCombo('Playback has stalled'); player.report({ 'type': 'playback', - 'warn': 'Playback was stalled for > 8 sec' + 'warn': 'Playback was stalled for > 30 sec' }); - },10e3); + },30e3); }; element.addEventListener('stalled',stalled,true); element.addEventListener('waiting',stalled,true); - var progress = function(e){ - if (element.checkStalledTimeout) { - clearTimeout(element.checkStalledTimeout); - element.checkStalledTimeout = false; - player.cancelAskNextCombo(); - } - if (element.checkStalledTimeout) { - clearTimeout(element.checkStalledTimeout); - element.checkStalledTimeout = false; - player.cancelAskNextCombo(); - } - }; - element.addEventListener('progress',progress,true); - element.addEventListener('playing',progress,true); - element.addEventListener('play',function(){ - player.paused = false; - if ((!element.checkProgressTimeout) && (player.element) && ('currentTime' in player.element)) { - //check if the progress made is equal to the time spent - var lasttime = player.element.currentTime; - element.checkProgressTimeout = setInterval(function(){ - var newtime = player.element.currentTime; - if (newtime == 0) { return; } - var progress = newtime - lasttime; - lasttime = newtime; - if (progress < 0) { return; } - if (progress == 0) { - var msg = 'There should be playback but nothing was played'; - var r = { - type: 'playback', - warn: msg - }; - player.addlog(msg); - if ('readyState' in player.element) { - r.readyState = player.element.readyState; - } - if ('networkState' in player.element) { - r.networkState = player.element.networkState; - } - if (('error' in player.element) && (player.element.error) && ('code' in player.element.error)) { - r.code = player.element.error.code; - } - player.report(r); - player.askNextCombo('No playback'); - if ('load' in player.element) { player.element.load(); } - return; - } + + if (playerOpts.live) { + element.checkProgressTimeout = false; + var progress = function(e){ + if (element.checkStalledTimeout) { + player.timer.remove(element.checkStalledTimeout); + element.checkStalledTimeout = false; player.cancelAskNextCombo(); - if (progress < 4) { - var msg = 'It seems playback is lagging (progressed '+Math.round(progress*100)/100+'/8s)' - player.addlog(msg); - player.report({ - type: 'playback', - warn: msg - }); - return; - } - },8e3); - } - },true); - element.addEventListener('pause',function(){ - player.paused = true; - if (element.checkProgressTimeout) { - clearInterval(element.checkProgressTimeout); - element.checkProgressTimeout = false; - } - },true); + } + }; + //element.addEventListener('progress',progress,true); //sometimes, there is progress but no playback + element.addEventListener('playing',progress,true); + element.addEventListener('play',function(){ + player.paused = false; + if ((!element.checkProgressTimeout) && (player.element) && ('currentTime' in player.element)) { + //check if the progress made is equal to the time spent + var lasttime = player.element.currentTime; + element.checkProgressTimeout = setInterval(function(){ + var newtime = player.element.currentTime; + var progress = newtime - lasttime; + lasttime = newtime; + if (progress < 0) { return; } //its probably a looping VOD or we've just seeked + if (progress == 0) { + var msg = 'There should be playback but nothing was played'; + var r = { + type: 'playback', + warn: msg + }; + player.addlog(msg); + if ('readyState' in player.element) { + r.readyState = player.element.readyState; + } + if ('networkState' in player.element) { + r.networkState = player.element.networkState; + } + if (('error' in player.element) && (player.element.error) && ('code' in player.element.error)) { + r.code = player.element.error.code; + } + player.report(r); + player.askNextCombo('No playback'); + return; + } + player.cancelAskNextCombo(); + if (progress < 20) { + var msg = 'It seems playback is lagging (progressed '+Math.round(progress*100)/100+'/30s)' + player.addlog(msg); + player.report({ + type: 'playback', + warn: msg + }); + return; + } + },30e3); + } + },true); + element.addEventListener('pause',function(){ + player.paused = true; + if (element.checkProgressTimeout) { + clearInterval(element.checkProgressTimeout); + element.checkProgressTimeout = false; + } + },true); + } if (player.resize) { //monitor for resizes and fire if needed diff --git a/embed/mist.css b/embed/mist.css index 7aa74c8e..a8793eaf 100644 --- a/embed/mist.css +++ b/embed/mist.css @@ -1,16 +1,15 @@ .mistvideo { background: black center none no-repeat; - /*LTS - background-size: auto 30%; - background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBpZD0ic3ZnNTI4MCIgaGVpZ2h0PSIxNTAiIHdpZHRoPSIyMDIuNTIwMTciIHZlcnNpb249IjEuMSI+PGRlZnMgaWQ9ImRlZnM1MjgyIiAvPjxtZXRhZGF0YSBpZD0ibWV0YWRhdGE1Mjg1Ij48cmRmOlJERj48Y2M6V29yayByZGY6YWJvdXQ9IiI+PGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+PGRjOnR5cGUgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz48ZGM6dGl0bGU+PC9kYzp0aXRsZT48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PGcgaWQ9ImxheWVyMSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTQ4LjcyNjIzNCwtNDQ5Ljc1MjA0KSI+PHBhdGggc3R5bGU9ImZpbGw6IzhjYjNjZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgaWQ9InBhdGg0NiIgZD0ibSA2OS4wODIxNTMsNTM0LjI1MzE0IDgxLjAyODYzNyw0My4yNjQ4OCA4MS4wMjYwNSwtNDMuMjY0ODggLTMwLjUwNzA3LC02OS4wMDg5NCAtMTAxLjAzOTA2OCwwIC0zMC41MDg1NDksNjkuMDA4OTQgMCwwIHogbSA4MS4wMjg2MzcsNTAuMTE3MzIgLTg4LjgyNjQ4NiwtNDcuNDMwODggMzQuMzY5NDE4LC03Ny43NDA3OSAxMDguOTEzNTY4LDAgMzQuMzY5MDUsNzcuNzQwNzkgLTg4LjgyNTU1LDQ3LjQzMDg4IDAsMCIgLz48cGF0aCBzdHlsZT0iZmlsbDojYjVkM2UyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiBpZD0icGF0aDQ4IiBkPSJtIDIzNC44NzM1Miw1MzguMDM5NTkgLTE2Ni43NTE1MTksMCAwLC02LjA0NTQxIDE2Ni43NTE1MTksMCAwLDYuMDQ1NDEiIC8+PHBhdGggc3R5bGU9ImZpbGw6IzhjYjNjZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgaWQ9InBhdGg1MCIgZD0ibSA4My40ODcwMDksNTM1LjUyMDgyIGMgMCw5LjU5OTY4IC03Ljc4MTA4LDE3LjM4MDc1IC0xNy4zNzk2NTEsMTcuMzgwNzUgLTkuNTk5MTIyLDAgLTE3LjM4MTEyNCwtNy43ODEwNiAtMTcuMzgxMTI0LC0xNy4zODA3NSAwLC05LjU5Nzg0IDcuNzgyMDAyLC0xNy4zODA3NiAxNy4zODExMjQsLTE3LjM4MDc2IDkuNTk4NTcxLDAgMTcuMzc5NjUxLDcuNzgyOTIgMTcuMzc5NjUxLDE3LjM4MDc2IiAvPjxwYXRoIHN0eWxlPSJmaWxsOiM4Y2IzY2Y7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIGlkPSJwYXRoNTIiIGQ9Im0gMjUxLjI0NjQsNTM1LjUyMDgyIGMgMCw5LjU5OTY4IC03Ljc4MTA3LDE3LjM4MDc1IC0xNy4zODA3NCwxNy4zODA3NSAtOS41OTk2OCwwIC0xNy4zNzg5MiwtNy43ODEwNiAtMTcuMzc4OTIsLTE3LjM4MDc1IDAsLTkuNTk3ODQgNy43NzkyNCwtMTcuMzgwNzYgMTcuMzc4OTIsLTE3LjM4MDc2IDkuNTk5NjcsMCAxNy4zODA3NCw3Ljc4MjkyIDE3LjM4MDc0LDE3LjM4MDc2IiAvPjxwYXRoIHN0eWxlPSJmaWxsOiNiNWQzZTI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIGlkPSJwYXRoNTQiIGQ9Im0gMTU1Ljc4NzY4LDUzNy4xODI4IC01LjA1MjI4LC0zLjMyMjEyIDQ5LjM3MTA4LC03NS4wNjM1NiA1LjA1MDQzLDMuMzIyMTEgLTQ5LjM2OTIzLDc1LjA2MzU3IDAsMCIgLz48cGF0aCBzdHlsZT0iZmlsbDojYjVkM2UyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiBpZD0icGF0aDU2IiBkPSJtIDE0OC43ODYsNTM3Ljc4MTYyIC01Mi44OTY5NzcsLTc0LjA1NTY5IDQuOTE5NDE3LC0zLjUxNTU4IDUyLjg5NTMzLDc0LjA1NzU0IC00LjkxNzc3LDMuNTEzNzMgMCwwIiAvPjxwYXRoIHN0eWxlPSJmaWxsOiM4Y2IzY2Y7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIGlkPSJwYXRoNTgiIGQ9Im0gMjE0LjU5NjI4LDQ2Mi41OTgyOSBjIDAsNy4wOTc1IC01Ljc1MjQyLDEyLjg0ODEgLTEyLjg0NjI0LDEyLjg0ODEgLTcuMDk1NjUsMCAtMTIuODQ2MjUsLTUuNzUwNiAtMTIuODQ2MjUsLTEyLjg0ODEgMCwtNy4wOTM4MSA1Ljc1MDYsLTEyLjg0NjI1IDEyLjg0NjI1LC0xMi44NDYyNSA3LjA5MzgyLDAgMTIuODQ2MjQsNS43NTI0NCAxMi44NDYyNCwxMi44NDYyNSIgLz48cGF0aCBzdHlsZT0iZmlsbDojOGNiM2NmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiBpZD0icGF0aDYwIiBkPSJtIDExMS44MjQ4NCw0NjIuNTk4MjkgYyAwLDcuMDk3NSAtNS43NTEzMywxMi44NDgxIC0xMi44NDU4NzMsMTIuODQ4MSAtNy4wOTUyODUsMCAtMTIuODQ3NTMyLC01Ljc1MDYgLTEyLjg0NzUzMiwtMTIuODQ4MSAwLC03LjA5MzgxIDUuNzUyMjQ3LC0xMi44NDYyNSAxMi44NDc1MzIsLTEyLjg0NjI1IDcuMDk0NTQzLDAgMTIuODQ1ODczLDUuNzUyNDQgMTIuODQ1ODczLDEyLjg0NjI1IiAvPjxwYXRoIHN0eWxlPSJmaWxsOiM4Y2IzY2Y7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIGlkPSJwYXRoNjIiIGQ9Im0gMTY4Ljg3NzE0LDQ4Ny41MzUzNSBjIDAsOS4zOTE0NSAtNy42MTE1NywxNy4wMDQ4NyAtMTcuMDAxMTksMTcuMDA0ODcgLTkuMzg5NjMsMCAtMTcuMDAzMDQsLTcuNjEzNDIgLTE3LjAwMzA0LC0xNy4wMDQ4NyAwLC05LjM4OTYyIDcuNjEzNDEsLTE3LjAwMTIgMTcuMDAzMDQsLTE3LjAwMTIgOS4zODk2MiwwIDE3LjAwMTE5LDcuNjExNTggMTcuMDAxMTksMTcuMDAxMiIgLz48cGF0aCBzdHlsZT0iZmlsbDojYjVkM2UyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiBpZD0icGF0aDY0IiBkPSJtIDE2NS44NTUzNiw1MzYuNDAxNTYgYyAwLDcuNzIzOTYgLTYuMjU5MTMsMTMuOTgxMjYgLTEzLjk3OTQxLDEzLjk4MTI2IC03LjcyMDI5LDAgLTEzLjk4MTI2LC02LjI1NzMgLTEzLjk4MTI2LC0xMy45ODEyNiAwLC03LjcyMDI5IDYuMjYwOTcsLTEzLjk3OTQxIDEzLjk4MTI2LC0xMy45Nzk0MSA3LjcyMDI4LDAgMTMuOTc5NDEsNi4yNTkxMiAxMy45Nzk0MSwxMy45Nzk0MSIgLz48cGF0aCBzdHlsZT0iZmlsbDojOGNiM2NmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiBpZD0icGF0aDY2IiBkPSJtIDY4LjMzNTczNiw1MzcuNDA1NzQgLTIuOTQ1ODY2LC01LjI4MDc0IDgzLjg3ODg4LC00Ny45ODU0NyA0LjQ1NzEyLDYuNzkxNjIgLTg1LjM5MDEzNCw0Ni40NzQ1OSAwLDAiIC8+PHBhdGggc3R5bGU9ImZpbGw6IzhjYjNjZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgaWQ9InBhdGg2OCIgZD0ibSAxNDkuNDY5NTgsNDkwLjY1NDc3IC01Mi4xNDE3MjQsLTI1LjMxNDc2IDIuNTQ1NjY5LC01LjQ4MTU5IDUzLjY1MzM1NSwyMy44MDIwNCAtMy4zMDE4NSw2LjIzODg3IC0wLjc1NTQ1LDAuNzU1NDQiIC8+PHBhdGggc3R5bGU9ImZpbGw6IzhjYjNjZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgaWQ9InBhdGg3MCIgZD0ibSAxNDkuNDE0Myw0ODQuMDYzOTcgNTEuMDA3MjYsLTIzLjgwMjAzIDIuNjU1MSw1LjQyOTk5IC00OS40OTYzNSwyNS4zMTQ3NyIgLz48cGF0aCBzdHlsZT0iZmlsbDojOGNiM2NmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiBpZD0icGF0aDcyIiBkPSJtIDIzMy4wOTM2Miw1MzguNTA3NTggLTgzLjg4MDE2LC00Ny45ODU0NyA0LjU2NzY4LC02LjcyNzE0IDgyLjM2NzQzLDQ5LjQ5NjM3IC0zLjA1NDk1LDUuMjE2MjQgMCwwIiAvPjxwYXRoIHN0eWxlPSJmaWxsOiM4Y2IzY2Y7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIGlkPSJwYXRoNzQiIGQ9Im0gMTU0LjUyMDAxLDU4MC40ODQ1MiAtNi44MDA4NCwwIC0yLjI2NjM0LC05My43MDI3OCAxMS4zMzUzNiwwIC0yLjI2ODE4LDkzLjcwMjc4IDAsMCIgLz48cGF0aCBzdHlsZT0iZmlsbDojOGNiM2NmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiBpZD0icGF0aDc2IiBkPSJtIDE2OC4xMjE2OSw1ODIuMzczMTMgYyAwLDkuNTk5NjggLTcuNzgxMDcsMTcuMzc4OTEgLTE3LjM4MDc1LDE3LjM3ODkxIC05LjU5Nzg0LDAgLTE3LjM3ODkxLC03Ljc3OTIzIC0xNy4zNzg5MSwtMTcuMzc4OTEgMCwtOS41OTk2OCA3Ljc4MTA3LC0xNy4zODA3NiAxNy4zNzg5MSwtMTcuMzgwNzYgOS41OTk2OCwwIDE3LjM4MDc1LDcuNzgxMDggMTcuMzgwNzUsMTcuMzgwNzYiIC8+PC9nPjwvc3ZnPg=='); - LTS*/ display: inline-block; color: white; font-family: sans-serif; text-align: center; position: relative; text-shadow: 0 0 1px black, 0 0 1px black; + max-width: 100%; + max-height: 100%; + overflow: hidden; } .mistvideo[data-loading] { background-image: none; @@ -36,14 +35,23 @@ z-index: 5; } .mistvideo .error { - margin: 225px 20px 20px; - min-width: 300px; + margin: 2em 0.5em; z-index: 69; + bottom: 40%; } .mistvideo .error button { + background: black; + color: rgba(255,255,255,0.8); + border: 1px solid rgba(255,255,255,0.2); + font-family: inherit; + padding: 0.5em; margin: 5px auto; display: block; } +.mistvideo .error button:hover { + color: white; + border-color: white; +} .mistvideo .vjs-error-display:before { content: '' !important; } @@ -121,7 +129,8 @@ font-size: 8px; } .mistplayer .controls .button.play { - height: 45px; + height: 30px; + width: 30px; margin-left: 15px; } .mistplayer .controls.minimal .button.play, @@ -145,7 +154,7 @@ .mistplayer .controls .progress_container { flex-grow: 1; position: relative; - margin: 15px; + margin: 5px; } .mistplayer .controls.smaller .progress_container { margin: 5px; @@ -351,33 +360,33 @@ } } -.countdown10 { +.countdown { height: 1em; width: 1em; display: inline-block; vertical-align: bottom; border-radius: 50%; - background-image: linear-gradient(to right,black 50%,#ddd 0); + background-image: linear-gradient(to right,#bbb 50%,#333 0); border: 1px solid black; margin: 0 0.2em; opacity: 0; - animation: appear 10s step-start 1; + animation: appear 20s step-start 1; } -.countdown10:before { +.countdown:before { content: ''; display: block; margin-left: 50%; height: 100%; border-radius: 0 100% 100% 0 / 50%; - background-color: black; + background-color: #bbb; transform-origin: 0 50%; - animation: rotate 5s linear 2, bg 10s step-end 1; + animation: rotate 10s linear 2, bg 20s step-end 1; } @keyframes rotate { to { transform: rotate(.5turn); } } @keyframes bg { - 50% { background: #ddd; } + 50% { background: #333; } } @keyframes appear { to { opacity: 1; } diff --git a/embed/test.html b/embed/test.html deleted file mode 100644 index 3277ea6a..00000000 --- a/embed/test.html +++ /dev/null @@ -1,235 +0,0 @@ - - - Embed test - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Sup

- -
-
- - diff --git a/embed/wrappers/html5.js b/embed/wrappers/html5.js index cbf45a0b..7f9e13e6 100644 --- a/embed/wrappers/html5.js +++ b/embed/wrappers/html5.js @@ -95,11 +95,15 @@ p.prototype.build = function (options) { else { ele.pause(); } }; - if (options.live) { - ele.addEventListener('error',function(e){ + this.addlog('Built html'); + + //forward events + ele.addEventListener('error',function(e){ + + if (options.live) { if ((ele.error) && (ele.error.code == 3)) { - e.stopPropagation(); - ele.load(); + e.stopPropagation(); //dont let this error continue to prevent the core from trying to handle the error + me.load(); me.cancelAskNextCombo(); e.message = 'Handled decoding error'; me.addlog('Decoding error: reloading..'); @@ -107,18 +111,19 @@ p.prototype.build = function (options) { type: 'playback', warn: 'A decoding error was encountered, but handled' }); + return; } - },true); - } - - this.addlog('Built html'); - - //forward events - ele.addEventListener('error',function(e){ + } + var msg; if ('message' in e) { msg = e.message; } + else if ((e.target.tagName == 'SOURCE') && (e.target.getAttribute('src') == '')) { + e.stopPropagation(); + //this error is triggered because the unload function was fired + return; + } else { msg = 'readyState: '; switch (me.element.readyState) { @@ -155,12 +160,12 @@ p.prototype.build = function (options) { } } me.adderror(msg); - },true); + }); var events = ['abort','canplay','canplaythrough','durationchange','emptied','ended','interruptbegin','interruptend','loadeddata','loadedmetadata','loadstart','pause','play','playing','ratechange','seeked','seeking','stalled','volumechange','waiting','progress']; for (var i in events) { ele.addEventListener(events[i],function(e){ me.addlog('Player event fired: '+e.type); - },true); + }); } return cont; } @@ -176,7 +181,32 @@ p.prototype.loop = function(bool){ } return this.element.loop = bool; }; -p.prototype.load = function(){ return this.element.load(); }; +p.prototype.load = function(){ + var load; + if (this.element.paused) { + load = this.element.load(); + } + else { + //sometimes there is a play / pause interrupt: try again + //TODO figure out if this happens on paused or on playing + this.load(); + return; + } + + //this helps to prevent the player from just showing a black screen after a reload + if (this.element.paused) { + var me = this; + var unpause = function(){ + if (me.element.paused) { + me.element.play(); + } + me.element.removeEventListener('progress',unpause); + } + this.element.addEventListener('progress',unpause); + } + + return load; +}; if (document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled) { p.prototype.fullscreen = function(){ if(this.element.requestFullscreen) { diff --git a/embed/wrappers/videojs.js b/embed/wrappers/videojs.js index ebc07b00..3facb28d 100644 --- a/embed/wrappers/videojs.js +++ b/embed/wrappers/videojs.js @@ -6,15 +6,30 @@ mistplayers.videojs = { return (this.mimes.indexOf(mimetype) == -1 ? false : true); }, isBrowserSupported: function (mimetype,source,options,streaminfo,logfunc) { + + //dont use https if the player is loaded over http if ((options.host.substr(0,7) == 'http://') && (source.url.substr(0,8) == 'https://')) { if (logfunc) { logfunc('HTTP/HTTPS mismatch for this source'); } return false; } - var support = true; + + //dont use videojs if this location is loaded over file:// if ((location.protocol == 'file:') && (mimetype == 'html5/application/vnd.apple.mpegurl')) { if (logfunc) { logfunc('This source ('+mimetype+') won\'t work if the page is run via file://'); } return false; } + + //dont use HLS if there is an MP3 audio track, unless we're on apple or edge + if ((mimetype == 'html5/application/vnd.apple.mpegurl') && (['iPad','iPhone','iPod','MacIntel'].indexOf(navigator.platform) == -1) && (navigator.userAgent.indexOf('Edge') == -1)) { + for (var i in streaminfo.meta.tracks) { + var t = streaminfo.meta.tracks[i]; + if (t.codec == 'MP3') { + return false; + } + } + } + + return ('MediaSource' in window); }, player: function(){},