UNPKG

flowplayer

Version:
1,352 lines (1,131 loc) 379 kB
/*! Flowplayer v7.2.7 (2018-08-13) | flowplayer.com/license */ /*! (C) WebReflection Mit Style License */ (function(e){function g(e,t,n,r){for(var i,s=n.slice(),o=w(t,e),u=0,a=s.length;u<a;u++){handler=s[u],typeof handler=="object"&&typeof handler.handleEvent=="function"?handler.handleEvent(o):handler.call(e,o);if(o.stoppedImmediatePropagation)break}return i=!o.stoppedPropagation,r&&i&&e.parentNode?e.parentNode.dispatchEvent(o):!o.defaultPrevented}function y(e,t){return{configurable:!0,get:e,set:t}}function b(e,t,n){var r=f(t||e,n);u(e,"textContent",y(function(){return r.get.call(this)},function(e){r.set.call(this,e)}))}function w(e,t){return e.currentTarget=t,e.eventPhase=e.target===e.currentTarget?2:3,e}function E(e,t){var n=e.length;while(n--&&e[n]!==t);return n}function S(){if(this.tagName==="BR")return"\n";var e=this.firstChild,t=[];while(e)e.nodeType!==8&&e.nodeType!==7&&t.push(e.textContent),e=e.nextSibling;return t.join("")}function x(e){return e.nodeType!==9&&document.documentElement.contains(e)}function T(e){!n&&d.test(document.readyState)&&(n=!n,document.detachEvent(r,T),e=document.createEvent("Event"),e.initEvent(i,!0,!0),document.dispatchEvent(e))}function N(e){var t;while(t=this.lastChild)this.removeChild(t);e!=null&&this.appendChild(document.createTextNode(e))}function C(t,n){return n||(n=e.event),n.target||(n.target=n.srcElement||n.fromElement||document),n.timeStamp||(n.timeStamp=(new Date).getTime()),n}if(document.createEvent)return;var t=!0,n=!1,r="onreadystatechange",i="DOMContentLoaded",s="__IE8__"+Math.random(),o=e.Object,u=o.defineProperty||function(e,t,n){e[t]=n.value},a=o.defineProperties||function(t,n){for(var r in n)if(l.call(n,r))try{u(t,r,n[r])}catch(i){e.console&&console.log(r+" failed on object:",t,i.message)}},f=o.getOwnPropertyDescriptor,l=o.prototype.hasOwnProperty,c=e.Element.prototype,h=e.Text.prototype,p=/^[a-z]+$/,d=/loaded|complete/,v={},m=document.createElement("div");b(e.HTMLCommentElement.prototype,c,"nodeValue"),b(e.HTMLScriptElement.prototype,null,"text"),b(h,null,"nodeValue"),b(e.HTMLTitleElement.prototype,null,"text"),u(e.HTMLStyleElement.prototype,"textContent",function(e){return y(function(){return e.get.call(this.styleSheet)},function(t){e.set.call(this.styleSheet,t)})}(f(e.CSSStyleSheet.prototype,"cssText"))),a(c,{textContent:{get:S,set:N},firstElementChild:{get:function(){for(var e=this.childNodes||[],t=0,n=e.length;t<n;t++)if(e[t].nodeType==1)return e[t]}},lastElementChild:{get:function(){for(var e=this.childNodes||[],t=e.length;t--;)if(e[t].nodeType==1)return e[t]}},previousElementSibling:{get:function(){var e=this.previousSibling;while(e&&e.nodeType!=1)e=e.previousSibling;return e}},nextElementSibling:{get:function(){var e=this.nextSibling;while(e&&e.nodeType!=1)e=e.nextSibling;return e}},childElementCount:{get:function(){for(var e=0,t=this.childNodes||[],n=t.length;n--;e+=t[n].nodeType==1);return e}},addEventListener:{value:function(e,t,n){var r=this,i="on"+e,o=r[s]||u(r,s,{value:{}})[s],a=o[i]||(o[i]={}),f=a.h||(a.h=[]),c;if(!l.call(a,"w")){a.w=function(e){return e[s]||g(r,C(r,e),f,!1)};if(!l.call(v,i))if(p.test(e))try{c=document.createEventObject(),c[s]=!0,r.nodeType!=9&&r.parentNode==null&&m.appendChild(r),r.fireEvent(i,c),v[i]=!0}catch(c){v[i]=!1;while(m.hasChildNodes())m.removeChild(m.firstChild)}else v[i]=!1;(a.n=v[i])&&r.attachEvent(i,a.w)}E(f,t)<0&&f[n?"unshift":"push"](t)}},dispatchEvent:{value:function(e){var t=this,n="on"+e.type,r=t[s],i=r&&r[n],o=!!i,u;return e.target||(e.target=t),o?i.n?t.fireEvent(n,e):g(t,e,i.h,!0):(u=t.parentNode)?u.dispatchEvent(e):!0,!e.defaultPrevented}},removeEventListener:{value:function(e,t,n){var r=this,i="on"+e,o=r[s],u=o&&o[i],a=u&&u.h,f=a?E(a,t):-1;-1<f&&a.splice(f,1)}}}),a(h,{addEventListener:{value:c.addEventListener},dispatchEvent:{value:c.dispatchEvent},removeEventListener:{value:c.removeEventListener}}),a(e.XMLHttpRequest.prototype,{addEventListener:{value:function(e,t,n){var r=this,i="on"+e,o=r[s]||u(r,s,{value:{}})[s],a=o[i]||(o[i]={}),f=a.h||(a.h=[]);E(f,t)<0&&(r[i]||(r[i]=function(){var t=document.createEvent("Event");t.initEvent(e,!0,!0),r.dispatchEvent(t)}),f[n?"unshift":"push"](t))}},dispatchEvent:{value:function(e){var t=this,n="on"+e.type,r=t[s],i=r&&r[n],o=!!i;return o&&(i.n?t.fireEvent(n,e):g(t,e,i.h,!0))}},removeEventListener:{value:c.removeEventListener}}),a(e.Event.prototype,{bubbles:{value:!0,writable:!0},cancelable:{value:!0,writable:!0},preventDefault:{value:function(){this.cancelable&&(this.defaultPrevented=!0,this.returnValue=!1)}},stopPropagation:{value:function(){this.stoppedPropagation=!0,this.cancelBubble=!0}},stopImmediatePropagation:{value:function(){this.stoppedImmediatePropagation=!0,this.stopPropagation()}},initEvent:{value:function(e,t,n){this.type=e,this.bubbles=!!t,this.cancelable=!!n,this.bubbles||this.stopPropagation()}}}),a(e.HTMLDocument.prototype,{textContent:{get:function(){return this.nodeType===11?S.call(this):null},set:function(e){this.nodeType===11&&N.call(this,e)}},addEventListener:{value:function(n,s,o){var u=this;c.addEventListener.call(u,n,s,o),t&&n===i&&!d.test(u.readyState)&&(t=!1,u.attachEvent(r,T),e==top&&function a(e){try{u.documentElement.doScroll("left"),T()}catch(t){setTimeout(a,50)}}())}},dispatchEvent:{value:c.dispatchEvent},removeEventListener:{value:c.removeEventListener},createEvent:{value:function(e){var t;if(e!=="Event")throw new Error("unsupported "+e);return t=document.createEventObject(),t.timeStamp=(new Date).getTime(),t}}}),a(e.Window.prototype,{getComputedStyle:{value:function(){function i(e){this._=e}function s(){}var e=/^(?:[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|))(?!px)[a-z%]+$/,t=/^(top|right|bottom|left)$/,n=/\-([a-z])/g,r=function(e,t){return t.toUpperCase()};return i.prototype.getPropertyValue=function(i){var s=this._,o=s.style,u=s.currentStyle,a=s.runtimeStyle,f,l,c;return i=(i==="float"?"style-float":i).replace(n,r),f=u?u[i]:o[i],e.test(f)&&!t.test(i)&&(l=o.left,c=a&&a.left,c&&(a.left=u.left),o.left=i==="fontSize"?"1em":f,f=o.pixelLeft+"px",o.left=l,c&&(a.left=c)),f==null?f:f+""||"auto"},s.prototype.getPropertyValue=function(){return null},function(e,t){return t?new s(e):new i(e)}}()},addEventListener:{value:function(t,n,r){var i=e,o="on"+t,u;i[o]||(i[o]=function(e){return g(i,C(i,e),u,!1)}),u=i[o][s]||(i[o][s]=[]),E(u,n)<0&&u[r?"unshift":"push"](n)}},dispatchEvent:{value:function(t){var n=e["on"+t.type];return n?n.call(e,t)!==!1&&!t.defaultPrevented:!0}},removeEventListener:{value:function(t,n,r){var i="on"+t,u=(e[i]||o)[s],a=u?E(u,n):-1;-1<a&&u.splice(a,1)}}})})(this); (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.flowplayer = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ 'use strict'; var common = module.exports = {}, ClassList = _dereq_('class-list'), $ = window.jQuery, punycode = _dereq_('punycode'), computedStyle = _dereq_('computed-style'); common.noop = function() {}; common.identity = function(i) { return i; }; common.removeNode = function(el) { if (!el || !el.parentNode) return; el.parentNode.removeChild(el); }; common.find = function(query, ctx) { if ($) return $(query, ctx).toArray(); ctx = ctx || document; return Array.prototype.map.call(ctx.querySelectorAll(query), function(el) { return el; }); }; common.text = function(el, txt) { el[('innerText' in el) ? 'innerText' : 'textContent'] = txt; }; common.findDirect = function(query, ctx) { return common.find(query, ctx).filter(function(node) { return node.parentNode === ctx; }); }; common.hasClass = function(el, kls) { if (typeof el.className !== 'string') return false; return ClassList(el).contains(kls); }; common.isSameDomain = function(url) { var w = window.location, a = common.createElement('a', { href: url }); return w.hostname === a.hostname && w.protocol === a.protocol && w.port === a.port; }; common.css = function(el, property, value) { if (typeof property === 'object') { return Object.keys(property).forEach(function(key) { common.css(el, key, property[key]); }); } if (typeof value !== 'undefined') { if (value === '') return el ? el.style.removeProperty(property) : undefined; return el ? el.style.setProperty(property, value) : undefined; } return el ? computedStyle(el, property) : undefined; }; common.createElement = function(tag, attributes, innerHTML) { try { var el = document.createElement(tag); for (var key in attributes) { if (!attributes.hasOwnProperty(key)) continue; if (key === 'css') { common.css(el, attributes[key]); } else { common.attr(el, key, attributes[key]); } } if (innerHTML) el.innerHTML = innerHTML; return el; } catch (e) { if (!$) throw e; return $('<' + tag + '>' + innerHTML + '</' + tag + '>').attr(attributes)[0]; } }; common.toggleClass = function(el, cls, flag) { if (!el) return; var classes = ClassList(el); if (typeof flag === 'undefined') classes.toggle(cls); else if (flag) classes.add(cls); else if (!flag) classes.remove(cls); }; common.addClass = function(el, cls) { return common.toggleClass(el, cls, true); }; common.removeClass = function(el, cls) { return common.toggleClass(el, cls, false); }; common.append = function(par, child) { par.appendChild(child); return par; }; common.appendTo = function(child, par) { common.append(par, child); return child; }; common.prepend = function(par, child) { par.insertBefore(child, par.firstChild); }; // Inserts `el` after `child` that is child of `par` common.insertAfter = function(par, child, el) { if (child == common.lastChild(par)) par.appendChild(el); var childIndex = Array.prototype.indexOf.call(par.children, child); par.insertBefore(el, par.children[childIndex + 1]); }; common.html = function(elms, val) { elms = elms.length ? elms : [elms]; elms.forEach(function(elm) { elm.innerHTML = val; }); }; common.attr = function(el, key, val) { if (key === 'class') key = 'className'; if (common.hasOwnOrPrototypeProperty(el, key)) { try { el[key] = val; } catch (e) { // Most likely IE not letting set property if ($) { $(el).attr(key, val); } else { throw e; } } } else { if (val === false) { el.removeAttribute(key); } else { el.setAttribute(key, val); } } return el; }; common.prop = function(el, key, val) { if (typeof val === 'undefined') { return el && el[key]; } el[key] = val; }; common.offset = function(el) { var ret = el.getBoundingClientRect(); if (el.offsetWidth / el.offsetHeight > el.clientWidth / el.clientHeight) { // https://github.com/flowplayer/flowplayer/issues/757 ret = { left: ret.left * 100, right: ret.right * 100, top: ret.top * 100, bottom: ret.bottom * 100, width: ret.width * 100, height: ret.height * 100 }; } return ret; }; common.width = function(el, val) { /*jshint -W093 */ if (val) return el.style.width = (''+val).replace(/px$/, '') + 'px'; var ret = common.offset(el).width; return typeof ret === 'undefined' ? el.offsetWidth : ret; }; common.height = function(el, val) { /*jshint -W093 */ if (val) return el.style.height = (''+val).replace(/px$/, '') + 'px'; var ret = common.offset(el).height; return typeof ret === 'undefined' ? el.offsetHeight : ret; }; common.lastChild = function(el) { return el.children[el.children.length - 1]; }; common.hasParent = function(el, parentSelector) { var parent = el.parentElement; while (parent) { if (typeof parentSelector !== 'string') { // is an element if (parent === parentSelector) return true; } else { if (common.matches(parent, parentSelector)) return true; } parent = parent.parentElement; } return false; }; common.createAbsoluteUrl = function(url) { return common.createElement('a', {href: url}).href; // This won't work on IE7 }; common.xhrGet = function(url, successCb, errorCb) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState !== 4) return; if (this.status >= 400) return errorCb(); successCb(this.responseText); }; xhr.open('get', url, true); xhr.send(); }; common.pick = function(obj, props) { var ret = {}; props.forEach(function(prop) { if (obj.hasOwnProperty(prop)) ret[prop] = obj[prop]; }); return ret; }; common.hostname = function(host) { return punycode.toUnicode(host || window.location.hostname); }; //Hacks common.browser = { webkit: 'WebkitAppearance' in document.documentElement.style }; common.getPrototype = function(el) { /* jshint proto:true */ if (!Object.getPrototypeOf) return el.__proto__; return Object.getPrototypeOf(el); }; common.hasOwnOrPrototypeProperty = function(obj, prop) { var o = obj; while (o) { if (Object.prototype.hasOwnProperty.call(o, prop)) return true; o = common.getPrototype(o); } return false; }; // Polyfill for Element.matches // adapted from https://developer.mozilla.org/en/docs/Web/API/Element/matches common.matches = function(elem, selector) { var proto = Element.prototype, fn = proto.matches || proto.matchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector || proto.webkitMatchesSelector || function (selector) { var element = this, matches = (element.document || element.ownerDocument).querySelectorAll(selector), i = 0; while (matches[i] && matches[i] !== element) { i++; } return matches[i] ? true : false; }; return fn.call(elem, selector); }; // Polyfill for CSSStyleDeclaration // from https://github.com/shawnbot/aight (function(CSSSDProto) { function getAttribute(property) { return property.replace(/-[a-z]/g, function(bit) { return bit[1].toUpperCase(); }); } // patch CSSStyleDeclaration.prototype using IE8's methods if (typeof CSSSDProto.setAttribute !== "undefined") { CSSSDProto.setProperty = function(property, value) { return this.setAttribute(getAttribute(property), String(value) /*, important */ ); }; CSSSDProto.getPropertyValue = function(property) { return this.getAttribute(getAttribute(property)) || null; }; CSSSDProto.removeProperty = function(property) { var value = this.getPropertyValue(property); this.removeAttribute(getAttribute(property)); return value; }; } })(window.CSSStyleDeclaration.prototype); },{"class-list":36,"computed-style":37,"punycode":44}],2:[function(_dereq_,module,exports){ 'use strict'; var common = _dereq_('../common'); // movie required in opts module.exports = function embed(swf, flashvars, wmode, bgColor) { wmode = wmode || "opaque"; var id = "obj" + ("" + Math.random()).slice(2, 15), tag = '<object class="fp-engine" id="' + id+ '" name="' + id + '" ', msie = navigator.userAgent.indexOf('MSIE') > -1; tag += msie ? 'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">' : ' data="' + swf + '" type="application/x-shockwave-flash">'; var opts = { width: "100%", height: "100%", allowscriptaccess: "always", wmode: wmode, quality: "high", flashvars: "", // https://github.com/flowplayer/flowplayer/issues/13#issuecomment-9369919 movie: swf + (msie ? "?" + id : ""), name: id }; if (wmode !== 'transparent') opts.bgcolor = bgColor || '#333333'; // flashvars Object.keys(flashvars).forEach(function(key) { opts.flashvars += key + "=" + flashvars[key] + "&"; }); // parameters Object.keys(opts).forEach(function(key) { tag += '<param name="' + key + '" value="'+ opts[key] +'"/>'; }); tag += "</object>"; var el = common.createElement('div', {}, tag); return common.find('object', el); }; // Flash is buggy allover if (window.attachEvent) { window.attachEvent("onbeforeunload", function() { window.__flash_savedUnloadHandler = window.__flash_unloadHandler = function() {}; }); } },{"../common":1}],3:[function(_dereq_,module,exports){ 'use strict'; var flowplayer = _dereq_('../flowplayer'), common = _dereq_('../common'), embed = _dereq_('./embed'), extend = _dereq_('extend-object'), bean = _dereq_('bean'), engineImpl; engineImpl = function flashEngine(player, root) { var conf = player.conf, loadVideo, callbackId, api; var suspended, timeouts = []; var engine = { engineName: engineImpl.engineName, pick: function(sources) { var source = extend({}, (function() { if (flowplayer.support.flashVideo) { var selectedSource; for (var i = 0, source; i < sources.length; i++) { source = sources[i]; if (/mp4|flv|flash/i.test(source.type)) selectedSource = source; if (player.conf.swfHls && /mpegurl/i.test(source.type)) selectedSource = source; if (selectedSource && !/mp4/i.test(selectedSource.type)) return selectedSource; // Did not find any source or source was video/mp4, let's try find more } return selectedSource; // Accept the fact we don't have anything or just an MP4 } })()); if (!source) return; if (source.src && !isAbsolute(source.src) && !player.conf.rtmp && !source.rtmp) source.src = common.createAbsoluteUrl(source.src); return source; }, suspendEngine: function() { suspended = true; }, resumeEngine: function() { suspended = false; }, load: function(video) { loadVideo = video; timeouts.forEach(function(t) { clearTimeout(t); }); function escapeURL(url) { return url.replace(/&amp;/g, '%26').replace(/&/g, '%26').replace(/=/g, '%3D'); } var html5Tag = common.findDirect('video', root)[0] || common.find('.fp-player > video', root)[0], url = video.src, is_absolute = isAbsolute(url); var removeTag = function() { common.removeNode(html5Tag); }; var hasSupportedSource = function(sources) { return sources.some(function(src) { return !!html5Tag.canPlayType(src.type); }); }; if (flowplayer.support.video && common.prop(html5Tag, 'autoplay') && hasSupportedSource(video.sources)) bean.one(html5Tag, 'timeupdate', removeTag); else removeTag(); // convert to absolute var rtmp = video.rtmp || conf.rtmp; if (!is_absolute && !rtmp) url = common.createAbsoluteUrl(url); if (api && isHLS(video) && api.data !== common.createAbsoluteUrl(conf.swfHls)) engine.unload(); if (api) { ['live', 'preload', 'loop'].forEach(function(prop) { if (!video.hasOwnProperty(prop)) return; api.__set(prop, video[prop]); }); Object.keys(video.flashls || {}).forEach(function(key) { api.__set('hls_' + key, video.flashls[key]); }); var providerChangeNeeded = false; if (!is_absolute && rtmp) api.__set('rtmp', rtmp.url || rtmp); else { var oldRtmp = api.__get('rtmp'); providerChangeNeeded = !!oldRtmp; api.__set('rtmp', null); } api.__play(url, providerChangeNeeded || video.rtmp && video.rtmp !== conf.rtmp); } else { callbackId = "fpCallback" + ("" + Math.random()).slice(3, 15); url = escapeURL(url); var opts = { hostname: conf.embedded ? common.hostname(conf.hostname) : common.hostname(location.hostname), url: url, callback: callbackId }; if (root.getAttribute('data-origin')) { opts.origin = root.getAttribute('data-origin'); } // optional conf ['proxy', 'key', 'autoplay', 'preload', 'subscribe', 'live', 'loop', 'debug', 'splash', 'poster', 'rtmpt'].forEach(function(key) { if (conf.hasOwnProperty(key)) opts[key] = conf[key]; if (video.hasOwnProperty(key)) opts[key] = video[key]; if ((conf.rtmp || {}).hasOwnProperty(key)) opts[key] = (conf.rtmp || {})[key]; if ((video.rtmp || {}).hasOwnProperty(key)) opts[key] = (video.rtmp || {})[key]; }); if (conf.splash) opts.autoplay = true; if (conf.rtmp) opts.rtmp = conf.rtmp.url || conf.rtmp; if (video.rtmp) opts.rtmp = video.rtmp.url || video.rtmp; Object.keys(video.flashls || {}).forEach(function(key) { var val = video.flashls[key]; opts['hls_' + key] = val; }); var hlsQualities = typeof video.hlsQualities !== 'undefined' ? video.hlsQualities : conf.hlsQualities; if (typeof hlsQualities !== 'undefined') opts.hlsQualities = hlsQualities ? encodeURIComponent(JSON.stringify(hlsQualities)) : hlsQualities; // bufferTime, bufferTimeMax might be 0 if (conf.bufferTime !== undefined) opts.bufferTime = conf.bufferTime; if (conf.bufferTimeMax !== undefined) opts.bufferTimeMax = conf.bufferTimeMax; if (is_absolute) delete opts.rtmp; // issues #376 if (opts.rtmp) { opts.rtmp = escapeURL(opts.rtmp); } // issues #733, 906 var bgColor = conf.bgcolor || common.css(root, 'background-color') ||'', bg; if (bgColor.indexOf('rgb') === 0) { bg = toHex(bgColor); } else if (bgColor.indexOf('#') === 0) { bg = toLongHex(bgColor); } // issues #387 opts.initialVolume = player.volumeLevel; var swfUrl = isHLS(video) ? conf.swfHls : conf.swf; api = embed(swfUrl, opts, conf.wmode, bg)[0]; var container = common.find('.fp-player', root)[0]; common.prepend(container, api); player.off('quality.flashengine').on('quality.flashengine', function(ev, _api, quality) { var hlsQualities = typeof player.video.hlsQualities !== 'undefined' ? player.video.hlsQualities : player.conf.hlsQualities; if (!hlsQualities) return; try { api.__quality(quality); } catch (e) { // VOD / RTMP engine does not support quality player.debug('Error changing quality in flash engine', e); } }); // throw error if no loading occurs setTimeout(function() { try { if (!api.PercentLoaded()) { return player.trigger("error", [player, { code: 7, url: conf.swf }]); } } catch (e) {} }, 5000); // detect disabled flash // timeouts.push(setTimeout(function() { if (typeof api.PercentLoaded === 'undefined') { player.trigger('flashdisabled', [player]); } }, 15000)); timeouts.push(setTimeout(function() { if (typeof api.PercentLoaded === 'undefined') { player.trigger('flashdisabled', [player, false]); } }, 500)); player.off('resume.flashhack').on('resume.flashhack', function() { var timer = setTimeout(function() { var currentTime = api.__status().time; var timer2 = setTimeout(function() { if (player.playing && !player.loading && api.__status().time === currentTime) { player.trigger('flashdisabled', [player]); } }, 400); timeouts.push(timer2); player.one('seek.flashhack pause.flashhack load.flashack', function() { clearTimeout(timer2); }); }, 800); timeouts.push(timer); player.one('progress', function() { clearTimeout(timer); }); }); api.pollInterval = setInterval(function () { if (!api || suspended) return; var status = api.__status ? api.__status() : null; if (!status) return; if (player.conf.live || player.live || video.live) { video.seekOffset = status.seekOffset; video.duration = status.duration + status.seekOffset; } if (player.playing && status.time && status.time !== player.video.time) player.trigger("progress", [player, status.time]); video.buffer = status.buffer / video.bytes * video.duration; player.trigger("buffer", [player, video.buffer]); if (!video.buffered && status.time > 0) { video.buffered = true; player.trigger("buffered", [player]); } }, 250); // listen window[callbackId] = function(type, arg) { var video = loadVideo; if (conf.debug) { if (type.indexOf('debug') === 0 && arg && arg.length) { console.log.apply(console, ['-- ' + type].concat(arg)); } else console.log("--", type, arg); } var event = { type: type }; switch (type) { // RTMP sends a lot of finish events in vain // case "finish": if (conf.rtmp) return; case "ready": arg = extend(video, arg); break; case "click": event.flash = true; break; case "keydown": event.which = arg; break; case "seek": video.time = arg; break; case "status": player.trigger("progress", [player, arg.time]); if (arg.buffer < video.bytes && !video.buffered) { video.buffer = arg.buffer / video.bytes * video.duration; player.trigger("buffer", video.buffer); } else if (!video.buffered) { video.buffered = true; player.trigger("buffered"); } break; case "metadata": var str = atob(arg); arg = { key: str.substr(10, 4), data: str.substr(21) } break; } if (type === 'click' || type === 'keydown') { event.target = root; bean.fire(root, type, [event]); } else if (type != 'buffered' && type !== 'unload') { // add some delay so that player is truly ready after an event setTimeout(function() { player.trigger(event, [player, arg]); }, 1); } else if (type === 'unload') { player.trigger(event, [player, arg]); } }; } }, // not supported yet speed: common.noop, unload: function() { if (api && api.__unload) api.__unload(); try { if (callbackId && window[callbackId])delete window[callbackId]; } catch (e) {} common.find("object", root).forEach(common.removeNode); api = 0; player.off('.flashengine'); player.off('.flashhack'); clearInterval(api.pollInterval); timeouts.forEach(function(t) { clearTimeout(t); }); } }; ['pause','resume','seek','volume'].forEach(function(name) { engine[name] = function(arg) { try { if (player.ready) { if (arg === undefined) { api["__" + name](); } else { api["__" + name](arg); } } } catch (e) { if (typeof api["__" + name] === 'undefined') { //flash lost it's methods return player.trigger('flashdisabled', [player]); } throw e; } }; }); function toHex(bg) { function hex(x) { return ("0" + parseInt(x).toString(16)).slice(-2); } bg = bg.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); if (!bg) return; return '#' + hex(bg[1]) + hex(bg[2]) + hex(bg[3]); } function toLongHex(bg) { if (bg.length === 7) return bg; var a = bg.split('').slice(1); return '#' + a.map(function(i) { return i + i; }).join(''); } function isHLS(video) { return /application\/x-mpegurl/i.test(video.type); } return engine; }; engineImpl.engineName = 'flash'; engineImpl.canPlay = function(type, conf) { return flowplayer.support.flashVideo && /video\/(mp4|flash|flv)/i.test(type) || flowplayer.support.flashVideo && conf.swfHls && /mpegurl/i.test(type); }; flowplayer.engines.push(engineImpl); function isAbsolute(url) { return /^https?:/.test(url); } },{"../common":1,"../flowplayer":31,"./embed":2,"bean":34,"extend-object":39}],4:[function(_dereq_,module,exports){ 'use strict'; var flowplayer = _dereq_('../flowplayer') , support = flowplayer.support , common = flowplayer.common , bean = flowplayer.bean , html5factory = _dereq_('./html5-factory'); function canPlay(type) { if (typeof window.Hls === 'undefined') return false; return /mpegurl/.test(type) && window.Hls.isSupported(); } var engine; engine = function(player, root) { var Hls = window.Hls , lastSelectedLevel , lastSource; function hlsjsExt(video, api, engineApi) { var conf = flowplayer.extend({ recoverMediaError: true }, player.conf.hlsjs, video.hlsjs); if (player.engine.hls) player.engine.hls.destroy(); var hls = player.engine.hls = new Hls(conf); engine.extensions.forEach(function(ext) { ext({ hls: hls, player: player, root: root, videoTag: api }); }); hls.loadSource(video.src); // API overriders engineApi.resume = function() { if (player.live && !player.dvr) api.currentTime = hls.liveSyncPosition || 0; api.play(); }; engineApi.seek = function(seekTo) { try { if (player.live || player.dvr) { api.currentTime = Math.min( seekTo, (hls.liveSyncPosition || api.duration - conf.livePositionOffset) ); } else api.currentTime = seekTo; } catch (e) { player.debug('Failed to seek to ', seekTo, e); } }; if (conf.bufferWhilePaused === false) { player.on('pause', function() { hls.stopLoad(); player.one('resume', function() { hls.startLoad(); }); }); } // Quality selection player.on('quality', function(_ev, _api, q) { hls.nextLevel = lastSelectedLevel = q; }); // HLS.js error handling var recoverMediaErrorDate , swapAudioCodecDate; var recover = function(isNetworkError) { player.debug('hlsjs - recovery'); common.removeClass(root, 'is-paused'); common.addClass(root, 'is-seeking'); bean.one(api, 'seeked', function() { if (api.paused) { common.removeClass(root, 'is-poster'); player.poster = false; api.play(); } common.removeClass(root, 'is-seeking'); }); if (isNetworkError) return hls.startLoad(); var now = performance.now(); if (!recoverMediaErrorDate || now - recoverMediaErrorDate > 3000) { recoverMediaErrorDate = performance.now(); hls.recoverMediaError(); } else if (!swapAudioCodecDate || (now - swapAudioCodecDate) > 3000) { swapAudioCodecDate = performance.now(); hls.swapAudioCodec(); hls.recoverMediaError(); } }; hls.on(Hls.Events.MANIFEST_PARSED, function(_, data) { var hlsQualities = video.hlsQualities || player.conf.hlsQualities , confQualities , qualityLabels = {} , levels = data.levels; if (hlsQualities === false) return hls.attachMedia(api); if (hlsQualities === 'drive') switch (levels.length) { case 4: confQualities = [1, 2, 3]; break; case 5: confQualities = [1, 2, 3, 4]; break; case 6: confQualities = [1, 3, 4, 5]; break; case 7: confQualities = [1, 3, 5, 6]; break; case 8: confQualities = [1, 3, 6, 7]; break; default: if (levels.length < 3 || (levels[0].height && levels[2].height && levels[0].height === levels[2].height)) { confQualities = []; } else { confQualities = [1, 2]; } break; } video.qualities = [{ value: -1, label: 'Auto' }] if (Array.isArray(hlsQualities)) { var confAutoQuality = hlsQualities.find(function(q) { return q === -1 || q.level && q.level === -1; }); if (!confAutoQuality) video.qualities = []; else video.qualities[0].label = typeof confAutoQuality !== 'number' ? confAutoQuality.label : video.qualities[0].label; confQualities = hlsQualities.map(function(q) { if (typeof q.level !== 'undefined') qualityLabels[q.level] = q.label; return typeof q.level !== 'undefined' ? q.level : q; }); } var initialLevel = -2; video.qualities = video.qualities.concat(levels.map(function(level, i) { if (confQualities && confQualities.indexOf(i) === -1) return false; var label = qualityLabels[i] || (Math.min(level.width, level.height) + 'p'); if (!qualityLabels[i] && hlsQualities !== 'drive') label += ' (' + Math.round(level.bitrate / 1000) + 'k)'; if (i === lastSelectedLevel) initialLevel = i; return { value: i, label: label }; })).filter(common.identity); var currentLevel = video.quality = initialLevel === -2 ? video.qualities[0].value || -1 : initialLevel; if (currentLevel !== hls.currentLevel) hls.currentLevel = currentLevel; // End quality selection hls.attachMedia(api); if (lastSource && video.src !== lastSource) api.play(); lastSource = video.src; }); hls.on(Hls.Events.ERROR, function(ev, data) { if (!data.fatal) return; if (conf.recoverNetworkError && data.type === Hls.ErrorTypes.NETWORK_ERROR) recover(true); else if (conf.recoverMediaError && data.type === Hls.ErrorTypes.MEDIA_ERROR) recover(false); else { var code = 5; if (data.type === Hls.ErrorTypes.NETWORK_ERROR) code = 2; if (data.type === Hls.ErrorTypes.MEDIA_ERROR) code = 3; hls.destroy(); player.trigger('error', [player, { code: code }]); } }); player.one('unload', function() { hls.destroy(); }); return { handlers: { error: function(e, videoTag) { var errorCode = videoTag.error && videoTag.error.code; if (conf.recoverMediaError && errorCode === 3 || !errorCode) { e.preventDefault(); recover(false); return true; } if (conf.recoverNetworkError && errorCode === 2) { e.preventDefault(); recover(true); return true; } } } }; } return html5factory('hlsjs-lite', player, root, canPlay, hlsjsExt); }; engine.canPlay = function(type, conf) { if (conf.hlsjs === false || (conf.clip && conf.clip.hlsjs === false)) return false; if (support.browser.safari && !(conf.clip && conf.clip.hlsjs || conf.hlsjs || {}).safari) return false; return flowplayer.support.video && canPlay(type); }; engine.engineName = 'hlsjs-lite'; engine.plugin = function(extension) { engine.extensions.push(extension); } engine.extensions = []; flowplayer.engines.push(engine); },{"../flowplayer":31,"./html5-factory":5}],5:[function(_dereq_,module,exports){ /*eslint indent: ["error", 2]*/ /*eslint quotes: ["error", "single"]*/ var flowplayer = _dereq_('../flowplayer') , common = flowplayer.common , support = flowplayer.support , bean = flowplayer.bean , extend = flowplayer.extend; var desktopSafari = support.browser.safari && !support.iOS; // HTML5 --> Flowplayer event var EVENTS = { ended: 'finish', pause: 'pause', play: 'resume', timeupdate: 'progress', volumechange: 'volume', ratechange: 'speed', seeked: 'seek', loadedmetadata: !desktopSafari ? 'ready' : 0, canplaythrough: desktopSafari ? 'ready' : 0, durationchange: 'ready', error: 'error', dataunavailable: 'error', webkitendfullscreen: !flowplayer.support.inlineVideo && 'unload', progress: 'buffer' }; function html5factory(engineName, player, root, canPlay, ext) { var api = common.findDirect('video', root)[0] || common.find('.fp-player > video', root)[0] , conf = player.conf , timer , volumeLevel , self; return self = { engineName: engineName, pick: function(sources) { var source = support.video && sources.filter(function(s) { return canPlay(s.type); })[0]; if (!source) return; if (typeof source.src === 'string') source.src = common.createAbsoluteUrl(source.src); return source; }, load: function(video) { var container = common.find('.fp-player', root)[0] , created = false; if (!api) { api = document.createElement('video'); common.prepend(container, api); api.autoplay = !!conf.splash; created = true; } common.addClass(api, 'fp-engine'); common.find('track', api).forEach(common.removeNode); api.preload = 'none'; if (!conf.nativesubtitles) common.attr(api, 'crossorigin', false); if (!conf.disableInline) { api.setAttribute('webkit-playsinline', 'true'); api.setAttribute('playsinline', 'true'); } if (!support.inlineVideo) { common.css(api, { position: 'absolute', top: '-9999em' }); } if (support.subtitles && conf.nativesubtitles && video.subtitles && video.subtitles.length) { common.addClass(api, 'native-subtitles'); var subtitles = video.subtitles; var setMode = function(mode) { var tracks = api.textTracks; if (!tracks.length) return; tracks[0].mode = mode; }; if (subtitles.some(function(st) { return !common.isSameDomain(st.src); })) common.attr(api, 'crossorigin', 'anonymous'); if (typeof api.textTracks.addEventListener === 'function') api.textTracks.addEventListener('addtrack', function() { setMode('disabled'); setMode('showing'); }); subtitles.forEach(function(st) { api.appendChild(common.createElement('track', { kind: 'subtitles', srclang: st.srclang || 'en', label: st.label || 'en', src: st.src, 'default': st['default'] })); }); } // IE does not fire delegated timeupdate events bean.off(api, 'timeupdate', common.noop); bean.on(api, 'timeupdate', common.noop); common.prop(api, 'loop', false); player.off('.loophack'); if (video.loop || conf.loop) { player.on('finish.loophack', function() { player.resume(); }); } if (typeof volumeLevel !== 'undefined') { api.volume = volumeLevel; } var extra = ext(video, api, self); if (conf.autoplay || conf.splash || video.autoplay) { player.debug('Autoplay / Splash setup, try to start video'); api.load(); var play = function () { try { var p = api.play(); if (p && p.catch) { var recoverAutoplay = function(err) { if (err.name === 'AbortError' && err.code === 20) { if (!created) return api.play().catch(recoverAutoplay); else return; } if (!conf.mutedAutoplay) throw new Error('Unable to autoplay'); player.debug('Play errored, trying muted', err); player.mute(true, true); return api.play(); } p.catch(recoverAutoplay).catch(function() { conf.autoplay = false; player.mute(false, true); // Restore volume as playback failed player.trigger('stop', [player]); }); } } catch(e) { player.debug('play() error thrown', e); } }; if (api.readyState > 0) play(); else bean.one(api, 'canplay', play); } self._listeners = listen(api, common.find('source', api).concat(api), video, extra) || self._listeners; if (conf.autoplay || conf.splash || video.autoplay) return; // No preload check needed var preloadCheck = function() { if (!isInViewport(root)) return; player.debug('player is in viewport, preload'); if (support.preloadMetadata) api.preload = 'metadata'; else api.load(); bean.off(document, 'scroll.preloadviewport'); }; bean.off(document, 'scroll.preloadviewport'); bean.on(document, 'scroll.preloadviewport', function() { window.requestAnimationFrame(preloadCheck); }); preloadCheck(); }, mute: function(flag) { api.muted = !!flag; player.trigger('mute', [player, flag]); player.trigger('volume', [player, flag ? 0 : api.volume]); }, pause: function() { api.pause(); }, resume: function() { api.play(); }, speed: function(val) { api.playbackRate = val; }, seek: function(time) { var pausedState = api.paused || player.finished; try { api.currentTime = time; if (pausedState) bean.one(api, 'seeked', function() { api.pause(); }); } catch (ignored) {} }, volume: function(level) { volumeLevel = level; if (api) { api.volume = level; if (level) self.mute(false); } }, unload: function() { bean.off(document, 'scroll.preloadviewport'); common.find('video.fp-engine', root).forEach(function (videoTag) { if ('MediaSource' in window) { videoTag.src = URL.createObjectURL(new MediaSource()); } else { videoTag.src = ''; } common.removeNode(videoTag); }); timer = clearInterval(timer); var instanceId = root.getAttribute('data-flowplayer-instance-id'); delete api.listeners[instanceId]; api = 0; if (self._listeners) Object.keys(self._listeners).forEach(function(typ) { self._listeners[typ].forEach(function(l) { root.removeEventListener(typ, l, true); }); }); } }; function listen(api, sources, video, extra) { // listen only once var instanceId = root.getAttribute('data-flowplayer-instance-id'); if (api.listeners && api.listeners.hasOwnProperty(instanceId)) { api.listeners[instanceId] = video; return; } (api.listeners || (api.listeners = {}))[instanceId] = video; bean.on(sources, 'error', function(e) { try { if (canPlay(e.target.getAttribute('type'))) { player.trigger('error', [player, { code: 4, video: extend(video, {src: api.src, url: api.src}) }]); } } catch (er) { // Most likely: https://bugzilla.mozilla.org/show_bug.cgi?id=208427 } }); player.on('shutdown', function() { bean.off(sources); bean.off(api, '.dvrhack'); player.off('.loophack'); }); var eventListeners = {}; //Special event handling for HLS metadata events var listenMetadata = function(track) { if (track.kind !== 'metadata') return; track.mode = 'hidden'; track.addEventListener('cuechange', function() { if (!track.activeCues.length) return; player.trigger('metadata', [player, track.activeCues[0].value]); }, false); }; if (api && api.textTracks && api.textTracks.length) Array.prototype.forEach.call(api.textTracks, listenMetadata); if (api && api.textTracks && typeof api.textTracks.addEventListener === 'function') api.textTracks.addEventListener('addtrack', function(tev) { listenMetadata(tev.track); }, false); if (player.conf.dvr || player.dvr || video.dvr) { bean.on(api, 'progress.dvrhack', function() { if (!api.seekable.length) return; player.video.duration = api.seekable.end(null); player.video.seekOffset = api.seekable.start(null); player.trigger('dvrwindow', [player, { start: api.seekable.start(null), end: api.seekable.end(null) }]); if (api.currentTime >= api.seekable.start(null)) return; api.currentTime = api.seekable.start(null); }); } Object.keys(EVENTS).forEach(function(type) { var flow = EVENTS[type]; if (type === 'webkitendfullscreen' && player.conf.disableInline) flow = 'unload'; if (!flow) return; var l = function(e) { video = api.listeners[instanceId]; if (!e.target || !common.hasClass(e.target, 'fp-engine')) return; if (!/progress/.test(flow)) player.debug(type, '->', flow, e); var triggerEvent = function(f) { player.trigger(f || flow, [player, arg]); }; // no events if player not ready if (!player.ready && !/ready|error/.test(flow) || !flow || !common.find('video', root).length) { if (flow === 'resume') player.one('ready', function() { setTimeout(function() { triggerEvent(); }) }); return; } var arg; if (flow === 'unload') { //Call player unload player.unload(); return; } switch (flow) { case 'ready': if (player.ready) return player.debug('Player already ready, not sending duplicate ready event'); if ((!api.duration || api.duration === Infinity) && !player.live) return player.debug('No duration and VOD setup, not sending ready event'); arg = extend(video, { duration: api.duration < Number.MAX_VALUE ? api.duration : 0, width: api.videoWidth, height: api.videoHeight, url: api.currentSrc }); arg.seekable = arg.duration; player.debug('Ready: ', arg); if (!player.live && !arg.duration && !support.hlsDuration && type === 'loadeddata') { var durationChanged = function() { arg.duration = api.duration; try { arg.seekable = api.seekable && api.seekable.end(null); } catch (ignored) {} triggerEvent(); api.removeEventListener('durationchange', durationChanged); common.toggleClass(root, 'is-live', false); }; api.addEventListener('durationchange', durationChanged); // Ugly hack to handle broken Android devices var timeUpdated = function() { if (!player.ready && !api.duration) { // No duration even though the video already plays arg.duration = 0; common.addClass(root, 'is-live'); // Make UI believe it's live triggerEvent(); } api.removeEventListener('timeupdate', timeUpdated); }; api.addEventListener('timeupdate', timeUpdated); return; } break; case 'progress': case 'seek': if (api.currentTime > 0 || player.live) { arg = Math.max(api.currentTime, 0); } else if (flow === 'seek' && api.currentTime === 0) { arg = 0; } else if (flow == 'progress') { return; } break; case 'buffer': arg = []; for (var i=0; i < api.buffered.length; i++) { arg.push({ start: api.buffered.start(i), end: api.buffered.end(i) }); } if (api.buffered.length && api.buffered.end(null) === api.duration) triggerEvent('buffered'); break; case 'speed': arg = round(api.playbackRate); break; case 'volume': arg = round(api.muted ? 0 : api.volume); break; case 'error': try { if (extra && extra.handlers && extra.handlers.error) { var handled = extra.handlers.error(e, api); if (handled) return;