/*! Flowplayer v5.4.6 (2014-05-12) | flowplayer.org/license */ !function($) { /* jQuery.browser for 1.9+ We all love feature detection but that's sometimes not enough. @author Tero Piirainen */ !function($) { if (!$.browser) { var b = $.browser = {}, ua = navigator.userAgent.toLowerCase(), match = /(chrome)[ \/]([\w.]+)/.exec(ua) || /(safari)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+)/.exec(ua) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; if (match[1]) { b[match[1]] = true; b.version = match[2] || "0"; } } }(jQuery); // auto-install (any video tag with parent .flowplayer) $(function() { if (typeof $.fn.flowplayer == 'function') { $("video").parent(".flowplayer").flowplayer(); } }); var instances = [], extensions = [], UA = window.navigator.userAgent; /* flowplayer() */ window.flowplayer = function(fn) { return $.isFunction(fn) ? extensions.push(fn) : typeof fn == 'number' || fn === undefined ? instances[fn || 0] : $(fn).data("flowplayer"); }; $(window).on('beforeunload', function() { $.each(instances, function(i, api) { if (api.conf.splash) { api.unload(); } else { api.bind("error", function () { $(".flowplayer.is-error .fp-message").remove(); }); } }); }); var supportLocalStorage = false; try { if (typeof window.localStorage == "object") { window.localStorage.flowplayerTestStorage = "test"; supportLocalStorage = true; } } catch (ignored) {} $.extend(flowplayer, { version: '5.4.6', engine: {}, conf: {}, support: {}, defaults: { debug: false, // true = forced playback disabled: false, // first engine to try engine: 'html5', fullscreen: window == window.top, // keyboard shortcuts keyboard: true, // default aspect ratio ratio: 9 / 16, adaptiveRatio: false, // scale flash object to video's aspect ratio in normal mode? flashfit: false, rtmp: 0, splash: false, live: false, swf: "//releases.flowplayer.org/5.4.6/flowplayer.swf", speeds: [0.25, 0.5, 1, 1.5, 2], tooltip: true, // initial volume level volume: !supportLocalStorage ? 1 : localStorage.muted == "true" ? 0 : !isNaN(localStorage.volume) ? localStorage.volume || 1 : 1, // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#error-codes errors: [ // video exceptions '', 'Video loading aborted', 'Network error', 'Video not properly encoded', 'Video file not found', // player exceptions 'Unsupported video', 'Skin not found', 'SWF file not found', 'Subtitles not found', 'Invalid RTMP URL', 'Unsupported video format. Try installing Adobe Flash.' ], errorUrls: ['','','','','','','','','','', 'http://get.adobe.com/flashplayer/' ], playlist: [] } }); // keep track of players var playerCount = 1; // jQuery plugin $.fn.flowplayer = function(opts, callback) { if (typeof opts == 'string') opts = { swf: opts } if ($.isFunction(opts)) { callback = opts; opts = {} } return !opts && this.data("flowplayer") || this.each(function() { // private variables var root = $(this).addClass("is-loading"), conf = $.extend({}, flowplayer.defaults, flowplayer.conf, opts, root.data()), videoTag = $("video", root).addClass("fp-engine").removeAttr("controls"), urlResolver = videoTag.length ? new URLResolver(videoTag) : null, storage = {}, lastSeekPosition, engine; if (conf.playlist.length) { // Create initial video tag if called without var preload = videoTag.attr('preload'), placeHolder; if (videoTag.length) videoTag.replaceWith(placeHolder = $('
')); videoTag = $('').addClass('fp-engine'); placeHolder ? placeHolder.replaceWith(videoTag) : root.prepend(videoTag); if (flowplayer.support.video) videoTag.attr('preload', preload); if (typeof conf.playlist[0] === 'string') videoTag.attr('src', conf.playlist[0]); else { $.each(conf.playlist[0], function(i, plObj) { for (var type in plObj) { if (plObj.hasOwnProperty(type)) { videoTag.append($('').attr({type: 'video/' + type, src: plObj[type]})); } } }); } urlResolver = new URLResolver(videoTag); } //stop old instance var oldApi = root.data('flowplayer'); if (oldApi) oldApi.unload(); root.data('fp-player_id', root.data('fp-player_id') || playerCount++); try { storage = window.localStorage || storage; } catch(e) {} var isRTL = (this.currentStyle && this.currentStyle['direction'] === 'rtl') || (window.getComputedStyle && window.getComputedStyle(this, null).getPropertyValue('direction') === 'rtl'); if (isRTL) root.addClass('is-rtl'); /*** API ***/ var api = oldApi || { // properties conf: conf, currentSpeed: 1, volumeLevel: typeof conf.volume === "undefined" ? storage.volume * 1 : conf.volume, video: {}, // states disabled: false, finished: false, loading: false, muted: storage.muted == "true" || conf.muted, paused: false, playing: false, ready: false, splash: false, rtl: isRTL, // methods load: function(video, callback) { if (api.error || api.loading || api.disabled) return; // resolve URL video = urlResolver.resolve(video); $.extend(video, engine.pick(video.sources)); if (video.src) { var e = $.Event("load"); root.trigger(e, [api, video, engine]); if (!e.isDefaultPrevented()) { engine.load(video); // callback if ($.isFunction(video)) callback = video; if (callback) root.one("ready", callback); } else { api.loading = false; } } return api; }, pause: function(fn) { if (api.ready && !api.seeking && !api.disabled && !api.loading) { engine.pause(); api.one("pause", fn); } return api; }, resume: function() { if (api.ready && api.paused && !api.disabled) { engine.resume(); // Firefox (+others?) does not fire "resume" after finish if (api.finished) { api.trigger("resume", [api]); api.finished = false; } } return api; }, toggle: function() { return api.ready ? api.paused ? api.resume() : api.pause() : api.load(); }, /* seek(1.4) -> 1.4s time seek(true) -> 10% forward seek(false) -> 10% backward */ seek: function(time, callback) { if (api.ready) { if (typeof time == "boolean") { var delta = api.video.duration * 0.1; time = api.video.time + (time ? delta : -delta); } time = lastSeekPosition = Math.min(Math.max(time, 0), api.video.duration).toFixed(1); var ev = $.Event('beforeseek'); root.trigger(ev, [api, time]); if (!ev.isDefaultPrevented()) { engine.seek(time); if ($.isFunction(callback)) root.one("seek", callback); } else { api.seeking = false; root.toggleClass("is-seeking", api.seeking); // remove loading indicator } } return api; }, /* seekTo(1) -> 10% seekTo(2) -> 20% seekTo(3) -> 30% ... seekTo() -> last position */ seekTo: function(position, fn) { var time = position === undefined ? lastSeekPosition : api.video.duration * 0.1 * position; return api.seek(time, fn); }, mute: function(flag) { if (flag === undefined) flag = !api.muted; storage.muted = api.muted = flag; storage.volume = !isNaN(storage.volume) ? storage.volume : conf.volume; // make sure storage has volume api.volume(flag ? 0 : storage.volume, true); api.trigger("mute", flag); return api; }, volume: function(level, skipStore) { if (api.ready) { level = Math.min(Math.max(level, 0), 1); if (!skipStore) storage.volume = level; engine.volume(level); } return api; }, speed: function(val, callback) { if (api.ready) { // increase / decrease if (typeof val == "boolean") { val = conf.speeds[$.inArray(api.currentSpeed, conf.speeds) + (val ? 1 : -1)] || api.currentSpeed; } engine.speed(val); if (callback) root.one("speed", callback); } return api; }, stop: function() { if (api.ready) { api.pause(); api.seek(0, function() { root.trigger("stop"); }); } return api; }, unload: function() { if (!root.hasClass("is-embedding")) { if (conf.splash) { api.trigger("unload"); engine.unload(); } else { api.stop(); } } return api; }, disable: function(flag) { if (flag === undefined) flag = !api.disabled; if (flag != api.disabled) { api.disabled = flag; api.trigger("disable", flag); } return api; } }; api.conf = $.extend(api.conf, conf); /* event binding / unbinding */ $.each(['bind', 'one', 'unbind'], function(i, key) { api[key] = function(type, fn) { root[key](type, fn); return api; }; }); api.trigger = function(event, arg) { root.trigger(event, [api, arg]); return api; }; /*** Behaviour ***/ if (!root.data('flowplayer')) { // Only bind once root.bind("boot", function() { // conf $.each(['autoplay', 'loop', 'preload', 'poster'], function(i, key) { var val = videoTag.attr(key); if (val !== undefined) conf[key] = val ? val : true; }); // splash if (conf.splash || root.hasClass("is-splash") || !flowplayer.support.firstframe) { api.forcedSplash = !conf.splash && !root.hasClass("is-splash"); api.splash = conf.splash = conf.autoplay = true; root.addClass("is-splash"); if (flowplayer.support.video) videoTag.attr("preload", "none"); } if (conf.live || root.hasClass('is-live')) { api.live = conf.live = true; root.addClass('is-live'); } // extensions $.each(extensions, function(i) { this(api, root); }); // 1. use the configured engine engine = flowplayer.engine[conf.engine]; if (engine) engine = engine(api, root); if (engine.pick(urlResolver.initialSources)) { api.engine = conf.engine; // 2. failed -> try another } else { $.each(flowplayer.engine, function(name, impl) { if (name != conf.engine) { engine = this(api, root); if (engine.pick(urlResolver.initialSources)) api.engine = name; return false; } }); } // instances instances.push(api); // no engine if (!api.engine) return api.trigger("error", { code: flowplayer.support.flashVideo ? 5 : 10 }); // start conf.splash ? api.unload() : api.load(); // disabled if (conf.disabled) api.disable(); //initial volumelevel engine.volume(api.volumeLevel); // initial callback root.one("ready", callback); }).bind("load", function(e, api, video) { // unload others if (conf.splash) { $(".flowplayer").filter(".is-ready, .is-loading").not(root).each(function() { var api = $(this).data("flowplayer"); if (api.conf.splash) api.unload(); }); } // loading root.addClass("is-loading"); api.loading = true; }).bind("ready", function(e, api, video) { video.time = 0; api.video = video; function notLoading() { root.removeClass("is-loading"); api.loading = false; } if (conf.splash) root.one("progress", notLoading); else notLoading(); // saved state if (api.muted) api.mute(true); else api.volume(api.volumeLevel); }).bind("unload", function(e) { if (conf.splash) videoTag.remove(); root.removeClass("is-loading"); api.loading = false; }).bind("ready unload", function(e) { var is_ready = e.type == "ready"; root.toggleClass("is-splash", !is_ready).toggleClass("is-ready", is_ready); api.ready = is_ready; api.splash = !is_ready; }).bind("progress", function(e, api, time) { api.video.time = time; }).bind("speed", function(e, api, val) { api.currentSpeed = val; }).bind("volume", function(e, api, level) { api.volumeLevel = Math.round(level * 100) / 100; if (!api.muted) storage.volume = level; else if (level) api.mute(false); }).bind("beforeseek seek", function(e) { api.seeking = e.type == "beforeseek"; root.toggleClass("is-seeking", api.seeking); }).bind("ready pause resume unload finish stop", function(e, _api, video) { // PAUSED: pause / finish api.paused = /pause|finish|unload|stop/.test(e.type); // SHAKY HACK: first-frame / preload=none if (e.type == "ready") { api.paused = conf.preload == 'none'; if (video) { api.paused = !video.duration || !conf.autoplay && (conf.preload != 'none'); } } // the opposite api.playing = !api.paused; // CSS classes root.toggleClass("is-paused", api.paused).toggleClass("is-playing", api.playing); // sanity check if (!api.load.ed) api.pause(); }).bind("finish", function(e) { api.finished = true; }).bind("error", function() { videoTag.remove(); }); } // boot root.trigger("boot", [api, root]).data("flowplayer", api); }); }; !function() { var parseIpadVersion = function(UA) { var e = /Version\/(\d\.\d)/.exec(UA); if (e && e.length > 1) { return parseFloat(e[1], 10); } return 0; }; var s = flowplayer.support, browser = $.browser, video = $("")[0], IS_IE = browser.msie, UA = navigator.userAgent, IS_IPAD = /iPad|MeeGo/.test(UA) && !/CriOS/.test(UA), IS_IPAD_CHROME = /iPad/.test(UA) && /CriOS/.test(UA), IS_IPHONE = /iP(hone|od)/i.test(UA) && !/iPad/.test(UA), IS_ANDROID = /Android/.test(UA) && !/Firefox/.test(UA), IS_ANDROID_FIREFOX = /Android/.test(UA) && /Firefox/.test(UA), IS_SILK = /Silk/.test(UA), IS_WP = /IEMobile/.test(UA), IPAD_VER = IS_IPAD ? parseIpadVersion(UA) : 0, ANDROID_VER = IS_ANDROID ? parseFloat(/Android\ (\d\.\d)/.exec(UA)[1], 10) : 0; $.extend(s, { subtitles: !!video.addTextTrack, fullscreen: !IS_ANDROID && (typeof document.webkitCancelFullScreen == 'function' && !/Mac OS X 10_5.+Version\/5\.0\.\d Safari/.test(UA) || document.mozFullScreenEnabled || typeof document.exitFullscreen == 'function'), inlineBlock: !(IS_IE && browser.version < 8), touch: ('ontouchstart' in window), dataload: !IS_IPAD && !IS_IPHONE && !IS_WP, zeropreload: !IS_IE && !IS_ANDROID, // IE supports only preload=metadata volume: !IS_IPAD && !IS_ANDROID && !IS_IPHONE && !IS_SILK && !IS_IPAD_CHROME, cachedVideoTag: !IS_IPAD && !IS_IPHONE && !IS_IPAD_CHROME && !IS_WP, firstframe: !IS_IPHONE && !IS_IPAD && !IS_ANDROID && !IS_SILK && !IS_IPAD_CHROME && !IS_WP && !IS_ANDROID_FIREFOX, inlineVideo: !IS_IPHONE && !IS_WP && (!IS_ANDROID || ANDROID_VER >= 3), hlsDuration: !browser.safari || IS_IPAD || IS_IPHONE || IS_IPAD_CHROME, seekable: !IS_IPAD && !IS_IPAD_CHROME }); // flashVideo try { var plugin = navigator.plugins["Shockwave Flash"], ver = IS_IE ? new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable('$version') : plugin.description; if (!IS_IE && !plugin[0].enabledPlugin) s.flashVideo = false; else { ver = ver.split(/\D+/); if (ver.length && !ver[0]) ver = ver.slice(1); s.flashVideo = ver[0] > 9 || ver[0] == 9 && ver[3] >= 115; } } catch (ignored) {} try { s.video = !!video.canPlayType; s.video && video.canPlayType('video/mp4'); } catch (e) { s.video = false; } // animation s.animation = (function() { var vendors = ['','Webkit','Moz','O','ms','Khtml'], el = $("")[0]; for (var i = 0; i < vendors.length; i++) { if (el.style[vendors[i] + 'AnimationName'] !== 'undefined') return true; } })(); }(); /* The most minimal Flash embedding */ // movie required in opts function embed(swf, flashvars) { var id = "obj" + ("" + Math.random()).slice(2, 15), tag = '"; return $(tag); } // Flash is buggy allover if (window.attachEvent) { window.attachEvent("onbeforeunload", function() { __flash_savedUnloadHandler = __flash_unloadHandler = function() {}; }); } flowplayer.engine.flash = function(player, root) { var conf = player.conf, video = player.video, callbackId, objectTag, api; var engine = { pick: function(sources) { if (flowplayer.support.flashVideo) { // always pick video/flash first var flash = $.grep(sources, function(source) { return source.type == 'flash'; })[0]; if (flash) return flash; for (var i = 0, source; i < sources.length; i++) { source = sources[i]; if (/mp4|flv/.test(source.type)) return source; } } }, load: function(video) { function escapeURL(url) { return url.replace(/&/g, '%26').replace(/&/g, '%26').replace(/=/g, '%3D'); } var html5Tag = $("video", root), url = escapeURL(video.src); is_absolute = /^https?:/.test(url); // html5 tag not needed (pause needed for firefox) try { if (html5Tag.length > 0 && flowplayer.support.video) html5Tag[0].pause(); } catch (e) { // Omit errors on calling pause(), see https://github.com/flowplayer/flowplayer/issues/490 } var removeTag = function() { html5Tag.remove(); }; var hasSupportedSource = function(sources) { return $.grep(sources, function(src) { return !!html5Tag[0].canPlayType('video/' + src.type); }).length > 0; }; if (flowplayer.support.video && html5Tag.prop('autoplay') && hasSupportedSource(video.sources)) html5Tag.one('timeupdate', removeTag); else removeTag(); // convert to absolute if (!is_absolute && !conf.rtmp) url = $("").attr("src", url)[0].src; if (api) { api.__play(url); } else { callbackId = "fp" + ("" + Math.random()).slice(3, 15); var opts = { hostname: conf.embedded ? conf.hostname : location.hostname, url: url, callback: "jQuery."+ callbackId }; if (root.data("origin")) { opts.origin = root.data("origin"); } if (is_absolute) delete conf.rtmp; // optional conf $.each(['key', 'autoplay', 'preload', 'rtmp', 'loop', 'debug', 'preload', 'splash', 'bufferTime'], function(i, key) { if (conf[key]) opts[key] = conf[key]; }); // issue #376 if (opts.rtmp) { opts.rtmp = escapeURL(opts.rtmp); } objectTag = embed(conf.swf, opts); objectTag.prependTo(root); api = objectTag[0]; // throw error if no loading occurs setTimeout(function() { try { if (!api.PercentLoaded()) { return root.trigger("error", [player, { code: 7, url: conf.swf }]); } } catch (e) {} }, 5000); // detect disabled flash setTimeout(function() { if (typeof api.PercentLoaded === 'undefined') { root.trigger('flashdisabled', [player]); } }, 1000); // listen $[callbackId] = function(type, arg) { if (conf.debug && type != "status") console.log("--", type, arg); var event = $.Event(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", 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; } if (type != 'buffered') { // add some delay so that player is truly ready after an event setTimeout(function() { player.trigger(event, arg); }, 1) } }; } }, // not supported yet speed: $.noop, unload: function() { api && api.__unload && api.__unload(); delete $[callbackId]; $("object", root).remove(); api = 0; } }; $.each("pause,resume,seek,volume".split(","), function(i, name) { engine[name] = function(arg) { try { if (player.ready) { if (name == 'seek' && player.video.time && !player.paused) { player.trigger("beforeseek"); } if (arg === undefined) { api["__" + name](); } else { api["__" + name](arg); } } } catch (e) { if (typeof api["__" + name] === 'undefined') { //flash lost it's methods return root.trigger('flashdisabled', [player]); } throw e; } }; }); var win = $(window); // handle Flash object aspect ratio player.bind("ready fullscreen fullscreen-exit", function(e) { var origH = root.height(), origW = root.width(); if (player.conf.flashfit || /full/.test(e.type)) { var fs = player.isFullscreen, truefs = fs && FS_SUPPORT, ie7 = !flowplayer.support.inlineBlock, screenW = fs ? (truefs ? screen.width : win.width()) : origW, screenH = fs ? (truefs ? screen.height : win.height()) : origH, // default values for fullscreen-exit without flashfit hmargin = 0, vmargin = 0, objwidth = ie7 ? origW : '', objheight = ie7 ? origH : '', aspectratio, dataratio; if (player.conf.flashfit || e.type === "fullscreen") { aspectratio = player.video.width / player.video.height, dataratio = player.video.height / player.video.width, objheight = Math.max(dataratio * screenW), objwidth = Math.max(aspectratio * screenH); objheight = objheight > screenH ? objwidth * dataratio : objheight; objheight = Math.min(Math.round(objheight), screenH); objwidth = objwidth > screenW ? objheight * aspectratio : objwidth; objwidth = Math.min(Math.round(objwidth), screenW); vmargin = Math.max(Math.round((screenH + vmargin - objheight) / 2), 0); hmargin = Math.max(Math.round((screenW + hmargin - objwidth) / 2), 0); } $("object", root).css({ width: objwidth, height: objheight, marginTop: vmargin, marginLeft: hmargin }); } }); return engine; }; var VIDEO = $('')[0]; // HTML5 --> Flowplayer event var EVENTS = { // fired ended: 'finish', pause: 'pause', play: 'resume', progress: 'buffer', timeupdate: 'progress', volumechange: 'volume', ratechange: 'speed', //seeking: 'beforeseek', seeked: 'seek', // abort: 'resume', // not fired loadeddata: 'ready', // loadedmetadata: 0, // canplay: 0, // error events // load: 0, // emptied: 0, // empty: 0, error: 'error', dataunavailable: 'error' }; function round(val, per) { per = per || 100; return Math.round(val * per) / per; } function getType(type) { return /mpegurl/i.test(type) ? "application/x-mpegurl" : "video/" + type; } function canPlay(type) { if (!/^(video|application)/.test(type)) type = getType(type); return !!VIDEO.canPlayType(type).replace("no", ''); } function findFromSourcesByType(sources, type) { var arr = $.grep(sources, function(s) { return s.type === type; }); return arr.length ? arr[0] : null; } var videoTagCache; var createVideoTag = function(video) { if (videoTagCache) { return videoTagCache.attr({type: getType(video.type), src: video.src}); } return (videoTagCache = $("", { src: video.src, type: getType(video.type), 'class': 'fp-engine', 'autoplay': 'autoplay', preload: 'none', 'x-webkit-airplay': 'allow' })); } flowplayer.engine.html5 = function(player, root) { var videoTag = $("video", root), support = flowplayer.support, track = $("track", videoTag), conf = player.conf, self, timer, api; return self = { pick: function(sources) { if (support.video) { if (conf.videoTypePreference) { var mp4source = findFromSourcesByType(sources, conf.videoTypePreference); if (mp4source) return mp4source; } for (var i = 0, source; i < sources.length; i++) { if (canPlay(sources[i].type)) return sources[i]; } } }, load: function(video) { if (conf.splash && !api) { videoTag = createVideoTag(video).prependTo(root); if (!support.inlineVideo) { videoTag.css({ position: 'absolute', top: '-9999em' }); } if (track.length) videoTag.append(track.attr("default", "")); if (conf.loop) videoTag.attr("loop", "loop"); api = videoTag[0]; } else { api = videoTag[0]; var sources = videoTag.find('source'); if (!api.src && sources.length) { api.src = video.src; sources.remove(); } // change of clip if (player.video.src && video.src != player.video.src) { videoTag.attr("autoplay", "autoplay"); api.src = video.src; // preload=none or no initial "loadeddata" event } else if (conf.preload == 'none' || !support.dataload) { if (support.zeropreload) { player.trigger("ready", video).trigger("pause").one("ready", function() { root.trigger("resume", [player]); }); } else { player.one("ready", function() { root.trigger("pause", [player]); }); } } } listen(api, $("source", videoTag).add(videoTag), video); // iPad (+others?) demands load() if (conf.preload != 'none' || !support.zeropreload || !support.dataload) api.load(); if (conf.splash) api.load(); }, pause: function() { api.pause(); }, resume: function() { api.play(); }, speed: function(val) { api.playbackRate = val; }, seek: function(time) { try { var pausedState = player.paused; api.currentTime = time; if (pausedState) api.pause(); } catch (ignored) {} }, volume: function(level) { api.volume = level; }, unload: function() { $("video.fp-engine", root).remove(); if (!support.cachedVideoTag) videoTagCache = null; timer = clearInterval(timer); api = 0; } }; function listen(api, sources, video) { // listen only once if (api.listeners && api.listeners.hasOwnProperty(root.data('fp-player_id'))) return; (api.listeners || (api.listeners = {}))[root.data('fp-player_id')] = true; sources.bind("error", function(e) { try { if (e.originalEvent && $(e.originalEvent.originalTarget).is('img')) return e.preventDefault(); if (canPlay($(e.target).attr("type"))) { player.trigger("error", { code: 4 }); } } catch (er) { // Most likely: https://bugzilla.mozilla.org/show_bug.cgi?id=208427 } }); $.each(EVENTS, function(type, flow) { api.addEventListener(type, function(e) { // safari hack for bad URL (10s before fails) if (flow == "progress" && e.srcElement && e.srcElement.readyState === 0) { setTimeout(function() { if (!player.video.duration) { flow = "error"; player.trigger(flow, { code: 4 }); } }, 10000); } if (conf.debug && !/progress/.test(flow)) console.log(type, "->", flow, e); // no events if player not ready if (!player.ready && !/ready|error/.test(flow) || !flow || !$("video", root).length) { return; } var event = $.Event(flow), arg; switch (flow) { case "ready": arg = $.extend(video, { duration: api.duration, width: api.videoWidth, height: api.videoHeight, url: api.currentSrc, src: api.currentSrc }); try { arg.seekable = api.seekable && api.seekable.end(null); } catch (ignored) {} // buffer timer = timer || setInterval(function() { try { arg.buffer = api.buffered.end(null); } catch (ignored) {} if (arg.buffer) { if (round(arg.buffer, 1000) < round(arg.duration, 1000) && !arg.buffered) { player.trigger("buffer", e); } else if (!arg.buffered) { arg.buffered = true; player.trigger("buffer", e).trigger("buffered", e); clearInterval(timer); timer = 0; } } }, 250); if (!conf.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) {} player.trigger(event, arg); api.removeEventListener('durationchange', durationChanged); }; api.addEventListener('durationchange', durationChanged); return; } break; case "progress": case "seek": var dur = player.video.duration if (api.currentTime > 0) { arg = Math.max(api.currentTime, 0); break; } else if (flow == 'progress') { return; } case "speed": arg = round(api.playbackRate); break; case "volume": arg = round(api.volume); break; case "error": try { arg = (e.srcElement || e.originalTarget).error; } catch (er) { // Most likely https://bugzilla.mozilla.org/show_bug.cgi?id=208427 return; } } player.trigger(event, arg); }, false); }); } }; var TYPE_RE = /\.(\w{3,4})(\?.*)?$/i; function parseSource(el) { var src = el.attr("src"), type = el.attr("type") || "", suffix = src.split(TYPE_RE)[1]; type = /mpegurl/.test(type) ? "mpegurl" : type.replace("video/", ""); return { src: src, suffix: suffix || type, type: type || suffix }; } /* Resolves video object from initial configuration and from load() method */ function URLResolver(videoTag) { var self = this, sources = []; // initial sources $("source", videoTag).each(function() { sources.push(parseSource($(this))); }); if (!sources.length) sources.push(parseSource(videoTag)); self.initialSources = sources; self.resolve = function(video) { if (!video) return { sources: sources }; if ($.isArray(video)) { video = { sources: $.map(video, function(el) { var type, ret = $.extend({}, el); $.each(el, function(key, value) { type = key; }); ret.type = type; ret.src = el[type]; delete ret[type]; return ret; })}; } else if (typeof video == 'string') { video = { src: video, sources: [] }; $.each(sources, function(i, source) { if (source.type != 'flash') { video.sources.push({ type: source.type, src: video.src.replace(TYPE_RE, "." + source.suffix + "$2") }); } }); } return video; }; }; /* A minimal jQuery Slider plugin with all goodies */ // skip IE policies // document.ondragstart = function () { return false; }; // execute function everyloading …
"); setRatio(conf.ratio); // no fullscreen in IFRAME try { if (!conf.fullscreen) fullscreen.remove(); } catch (e) { fullscreen.remove(); } api.bind("ready", function() { var duration = api.video.duration; timelineApi.disable(api.disabled || !duration); conf.adaptiveRatio && setRatio(api.video.height / api.video.width); // initial time & volume durationEl.add(remaining).html(format(duration)); // do we need additional space for showing hour ((duration >= 3600) && root.addClass('is-long')) || root.removeClass('is-long'); volumeApi.slide(api.volumeLevel); }).bind("unload", function() { if (!origRatio) ratio.css("paddingTop", ""); // buffer }).bind("buffer", function() { var video = api.video, max = video.buffer / video.duration; if (!video.seekable && support.seekable) timelineApi.max(max); if (max < 1) buffer.css("width", (max * 100) + "%"); else buffer.css({ width: '100%' }); }).bind("speed", function(e, api, val) { speed.text(val + "x").addClass("fp-hilite"); setTimeout(function() { speed.removeClass("fp-hilite") }, 1000); }).bind("buffered", function() { buffer.css({ width: '100%' }); timelineApi.max(1); // progress }).bind("progress", function() { var time = api.video.time, duration = api.video.duration; if (!timelineApi.dragging) { timelineApi.slide(time / duration, api.seeking ? 0 : 250); } elapsed.html(format(time)); remaining.html("-" + format(duration - time)); }).bind("finish resume seek", function(e) { root.toggleClass("is-finished", e.type == "finish"); }).bind("stop", function() { elapsed.html(format(0)); timelineApi.slide(0, 100); }).bind("finish", function() { elapsed.html(format(api.video.duration)); timelineApi.slide(1, 100); root.removeClass("is-seeking"); // misc }).bind("beforeseek", function() { progress.stop(); }).bind("volume", function() { volumeApi.slide(api.volumeLevel); }).bind("disable", function() { var flag = api.disabled; timelineApi.disable(flag); volumeApi.disable(flag); root.toggleClass("is-disabled", api.disabled); }).bind("mute", function(e, api, flag) { root.toggleClass("is-muted", flag); }).bind("error", function(e, api, error) { root.removeClass("is-loading").addClass("is-error"); if (error) { error.message = conf.errors[error.code]; api.error = true; var el = $(".fp-message", root); $("h2", el).text((api.engine || 'html5') + ": " + error.message); $("p", el).text(error.url || api.video.url || api.video.src || conf.errorUrls[error.code]); root.unbind("mouseenter click").removeClass("is-mouseover"); } // hover }).bind("mouseenter mouseleave", function(e) { if (noToggle) return; var is_over = e.type == "mouseenter", lastMove; // is-mouseover/out hover(is_over); if (is_over) { root.bind("pause.x mousemove.x volume.x", function() { hover(true); lastMove = new Date; }); hovertimer = setInterval(function() { if (new Date - lastMove > 5000) { hover(false) lastMove = new Date; } }, 100); } else { root.unbind(".x"); clearInterval(hovertimer); } // allow dragging over the player edge }).bind("mouseleave", function() { if (timelineApi.dragging || volumeApi.dragging) { root.addClass("is-mouseover").removeClass("is-mouseout"); } // click }).bind("click.player", function(e) { if ($(e.target).is(".fp-ui, .fp-engine") || e.flash) { e.preventDefault(); return api.toggle(); } }).bind('contextmenu', function(ev) { ev.preventDefault(); var o = root.offset(), w = $(window), left = ev.clientX - o.left, t = ev.clientY - o.top + w.scrollTop(); var menu = root.find('.fp-context-menu').css({ left: left + 'px', top: t + 'px', display: 'block' }).on('click', function(ev) { ev.stopPropagation(); }); $('html').on('click.outsidemenu', function(ev) { menu.hide(); $('html').off('click.outsidemenu'); }); }).bind('flashdisabled', function() { root.addClass('is-flash-disabled').one('ready', function() { root.removeClass('is-flash-disabled').find('.fp-flash-disabled').remove(); }).append('spaceplay / pause
\qunload | stop
\ffullscreen
\shift + ←→slower / faster (latest Chrome and Safari)
\↑↓volume
\mmute
\←→seek
\. seek to previous\
12…6 seek to 10%, 20%, …60%
\" + lines[++i] + "
" + lines[i] + "