Files
forzaapk/smc/temp/js/flowplayer.js
mstfyldz 192dfc2de8 smc
2026-02-16 18:52:45 +03:00

699 lines
22 KiB
JavaScript

'use strict';
var extend = require('extend-object'),
isFunction = require('is-function'),
bean = require('bean'),
slider = require('./ext/ui/slider'),
barSlider = require('./ext/ui/bar-slider'),
common = require('./common'),
events = require('./ext/events');
var instances = [],
extensions = [];
var oldHandler = window.onbeforeunload;
window.onbeforeunload = function(ev) {
instances.forEach(function(api) {
if (api.conf.splash) {
api.unload();
} else {
api.bind("error", function () {
common.find('.flowplayer.is-error .fp-message').forEach(common.removeNode);
});
}
});
if (oldHandler) return oldHandler(ev);
};
var isSafari = /Safari/.exec(navigator.userAgent) && !/Chrome/.exec(navigator.userAgent),
m = /(\d+\.\d+) Safari/.exec(navigator.userAgent),
safariVersion = m ? Number(m[1]) : 100;
/* flowplayer() */
var flowplayer = module.exports = function(fn, opts, callback) {
if (isFunction(fn)) return extensions.push(fn);
if (typeof fn == 'number' || typeof fn === 'undefined') return instances[fn || 0];
if (fn.nodeType) { // Is an element
if (fn.getAttribute('data-flowplayer-instance-id') !== null) { // Already flowplayer instance
return instances[fn.getAttribute('data-flowplayer-instance-id')];
}
if (!opts) return; // Can't initialize without data
return initializePlayer(fn, opts, callback);
}
if (fn.jquery) return flowplayer(fn[0], opts, callback);
if (typeof fn === 'string') {
var el = common.find(fn)[0];
return el && flowplayer(el, opts, callback);
}
};
extend(flowplayer, {
version: '@VERSION',
engines: [],
engine: function(name) {
return flowplayer.engines.filter(function(e) { return e.engineName === name; })[0];
},
extensions: [],
conf: {},
set: function(key, value) {
if (typeof key === 'string') flowplayer.conf[key] = value;
else extend(flowplayer.conf, key);
},
registerExtension: function(js, css) {
flowplayer.extensions.push([js, css]);
},
support: {},
defaults: {
debug: false,
// true = forced playback
disabled: false,
fullscreen: window == window.top,
// keyboard shortcuts
keyboard: true,
// default aspect ratio
ratio: 9 / 16,
adaptiveRatio: false,
rtmp: 0,
proxy: 'best',
hlsQualities: true,
seekStep: false,
splash: false,
live: false,
livePositionOffset: 120,
swf: "//@CDN/@VERSION/@CDN_PATHflowplayer.swf",
swfHls: "//@CDN/@VERSION/@CDN_PATHflowplayerhls.swf",
speeds: [0.25, 0.5, 1, 1.5, 2],
tooltip: true,
mouseoutTimeout: 5000,
mutedAutoplay: true,
clickToUnMute: true,
// initial volume level
volume: 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: [],
hlsFix: isSafari && safariVersion < 8,
disableInline: false
},
// Expose utilities for plugins
bean: bean,
common: common,
slider: slider,
barSlider: barSlider,
extend: extend
});
// keep track of players
var playerCount = 0;
var URLResolver = require('./ext/resolve');
if (typeof window.jQuery !== 'undefined') {
var $ = window.jQuery;
// auto-install (any video tag with parent .flowplayer)
$(function() {
if (typeof $.fn.flowplayer == 'function') {
$('.flowplayer:has(video:not(.fp-engine),script[type="application/json"])').flowplayer();
}
});
// jQuery plugin
var videoTagConfig = function(videoTag) {
if (!videoTag.length) return {};
var clip = videoTag.data() || {}, conf = {};
$.each(['autoplay', 'loop', 'preload', 'poster'], function(i, key) {
var val = videoTag.attr(key);
if (val !== undefined && ['autoplay', 'poster'].indexOf(key) !== -1) conf[key] = val ? val : true;
else if (val !== undefined) clip[key] = val ? val : true;
});
videoTag[0].autoplay = videoTag[0].preload = false;
clip.subtitles = videoTag.find('track').map(function() {
var tr = $(this);
return {
src: tr.attr('src'),
kind: tr.attr('kind'),
label: tr.attr('label'),
srclang: tr.attr('srclang'),
'default': tr.prop('default')
};
}).get();
clip.sources = (new URLResolver()).sourcesFromVideoTag(videoTag, $);
return extend(conf, {clip: clip});
};
$.fn.flowplayer = function(opts, callback) {
return this.each(function() {
if (typeof opts == 'string') opts = { swf: opts };
if (isFunction(opts)) { callback = opts; opts = {}; }
var root = $(this),
scriptConf = root.find('script[type="application/json"]'),
confObject = scriptConf.length ? JSON.parse(scriptConf.text()) : videoTagConfig(root.find('video')),
conf = $.extend({}, opts || {}, confObject, root.data());
var api = initializePlayer(this, conf, callback);
events.EVENTS.forEach(function(evName) {
api.on(evName + '.jquery', function(ev) {
root.trigger.call(root, ev.type, ev.detail && ev.detail.args);
});
});
root.data('flowplayer', api);
});
};
}
function initializePlayer(element, opts, callback) {
if (opts && opts.embed) opts.embed = extend({}, flowplayer.defaults.embed, opts.embed);
var supportLocalStorage = false;
try {
if (typeof flowplayer.conf.storage === 'undefined' && typeof window.localStorage == "object") {
window.localStorage.flowplayerTestStorage = "test";
supportLocalStorage = true;
}
} catch (ignored) {}
var root = element,
conf = extend({}, flowplayer.defaults, flowplayer.conf, opts),
storage = {},
originalClass = root.className,
lastSeekPosition,
engine,
urlResolver = new URLResolver();
common.addClass(root, 'is-loading');
common.toggleClass(root, 'no-flex', !flowplayer.support.flex);
common.toggleClass(root, 'no-svg', !flowplayer.support.svg);
try {
storage = flowplayer.conf.storage || (supportLocalStorage ? window.localStorage : storage);
} catch(e) {}
conf.volume = storage.muted === "true" ? 0 : conf.volume !== flowplayer.defaults.volume ? conf.volume : !isNaN(storage.volume) ? storage.volume : conf.volume;
conf.debug = !!storage.flowplayerDebug || conf.debug;
if (conf.aspectRatio && typeof conf.aspectRatio === 'string') {
var parts = conf.aspectRatio.split(/[:\/]/);
conf.ratio = parts[1] / parts[0];
}
var isRTL = (root.currentStyle && root.currentStyle.direction === 'rtl') ||
(window.getComputedStyle && window.getComputedStyle(root, null) !== null && window.getComputedStyle(root, null).getPropertyValue('direction') === 'rtl');
if (isRTL) common.addClass(root, 'is-rtl');
/*** API ***/
var api = {
// properties
conf: conf,
currentSpeed: 1,
volumeLevel: conf.muted ? 0 : 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
//
hijack: function(hijack) {
try {
api.engine.suspendEngine();
} catch (e) { /* */ }
api.hijacked = hijack;
},
release: function() {
try {
api.engine.resumeEngine();
} catch (e) { /* */ }
api.hijacked = false;
},
debug: function() {
if (!conf.debug) return;
console.log.apply(console, ['DEBUG'].concat([].slice.call(arguments)));
},
load: function(video, callback) {
if (api.error || api.loading) return;
api.video = {};
api.finished = false;
video = video || conf.clip;
// resolve URL
video = extend({}, urlResolver.resolve(video, conf.clip.sources));
if (api.playing || api.engine) video.autoplay = true;
var engineImpl = selectEngine(video);
if (!engineImpl) return setTimeout(function() { api.trigger("error", [api, { code: flowplayer.support.flashVideo ? 5 : 10 }]); }) && api;
if (!engineImpl.engineName) throw new Error('engineName property of factory should be exposed');
if (!api.engine || engineImpl.engineName !== api.engine.engineName) {
api.ready = false;
if (api.engine) {
api.engine.unload();
api.conf.autoplay = true;
}
engine = api.engine = engineImpl(api, root);
api.one('ready', function() {
setTimeout(function() {
if (api.muted) api.mute(true, true);
else engine.volume(api.volumeLevel);
});
});
}
extend(video, engine.pick(video.sources.filter(function(source) { // Filter out sources explicitly configured for some other engine
if (!source.engine) return true;
return source.engine === engine.engineName;
})));
if (video.src) {
var e = api.trigger('load', [api, video, engine], true);
if (!e.defaultPrevented) {
api.ready = false;
engine.load(video);
// callback
if (isFunction(video)) callback = video;
if (callback) api.one("ready", callback);
} else {
api.loading = false;
}
}
return api;
},
pause: function(fn) {
if (api.hijacked) return api.hijacked.pause(fn) | api;
if (api.ready && !api.seeking && !api.loading) {
engine.pause();
api.one("pause", fn);
}
return api;
},
resume: function() {
var ev = api.trigger('beforeresume', [api], true);
if (ev.defaultPrevented) return;
if (api.hijacked) return api.hijacked.resume() | api;
if (api.ready && api.paused) {
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 (typeof time == "boolean") {
var delta = api.conf.seekStep || api.video.duration * 0.1;
time = api.video.time + (time ? delta : -delta);
time = Math.min(Math.max(time, 0), api.video.duration - 0.1);
}
if (typeof time === 'undefined') return api;
if (api.hijacked) return api.hijacked.seek(time, callback) | api;
if (api.ready) {
lastSeekPosition = time;
var ev = api.trigger('beforeseek', [api, time], true);
if (!ev.defaultPrevented) {
engine.seek(time);
if (isFunction(callback)) api.one("seek", callback);
} else {
api.seeking = false;
common.toggleClass(root, '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) {
if (position === undefined) return api.seek(lastSeekPosition, fn);
if (api.video.seekOffset !== undefined) { // Live stream
return api.seek(api.video.seekOffset + (api.video.duration - api.video.seekOffset) * 0.1 * position, fn);
}
return api.seek(api.video.duration * 0.1 * position, fn);
},
mute: function(flag, skipStore) {
if (flag === undefined) flag = !api.muted;
api.muted = flag;
if (!skipStore) {
storage.muted = flag;
storage.volume = !isNaN(storage.volume) ? storage.volume : conf.volume; // make sure storage has volume
}
if (typeof engine.mute !== 'undefined') engine.mute(flag);
else {
api.volume(flag ? 0 : storage.volume, true);
api.trigger("mute", [api, 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[conf.speeds.indexOf(api.currentSpeed) + (val ? 1 : -1)] || api.currentSpeed;
}
engine.speed(val);
if (callback) root.one("speed", callback);
}
return api;
},
stop: function() {
if (api.ready) {
api.pause();
if (!api.live || api.dvr) {
api.seek(0, function() {
api.trigger("stop", [api]);
});
} else {
api.trigger("stop", [api]);
}
}
return api;
},
unload: function() {
if (conf.splash) {
api.trigger("unload", [api]);
if (engine) {
engine.unload();
api.engine = engine = 0;
}
} else {
api.stop();
}
return api;
},
shutdown: function() {
api.unload();
api.trigger('shutdown', [api]);
bean.off(root);
delete instances[root.getAttribute('data-flowplayer-instance-id')];
root.removeAttribute('data-flowplayer-instance-id');
},
disable: function(flag) {
if (flag === undefined) flag = !api.disabled;
if (flag != api.disabled) {
api.disabled = flag;
api.trigger("disable", flag);
}
return api;
},
registerExtension: function(jsUrls, cssUrls) {
jsUrls = jsUrls || [];
cssUrls = cssUrls || [];
if (typeof jsUrls === 'string') jsUrls = [jsUrls];
if (typeof cssUrls === 'string') cssUrls = [cssUrls];
jsUrls.forEach(function(url) { api.extensions.js.push(url); });
cssUrls.forEach(function(url) { api.extensions.css.push(url); });
}
};
api.conf = extend(api.conf, conf);
api.extensions = { js: [], css: [] };
flowplayer.extensions.forEach(function(i) {
api.registerExtension(i[0], i[1]);
});
/* event binding / unbinding */
events(api);
var selectEngine = function(clip) {
var engine;
var engines = flowplayer.engines;
if (conf.engine) {
var eng = engines.filter(function(e) { return e.engineName === conf.engine; })[0];
if (eng && clip.sources.some(function(source) {
if (source.engine && source.engine !== eng.engineName) return false;
return eng.canPlay(source.type, api.conf);
})) return eng;
}
if (conf.enginePreference) engines = flowplayer.engines.filter(function(one) { return conf.enginePreference.indexOf(one.engineName) > -1; }).sort(function(a, b) {
return conf.enginePreference.indexOf(a.engineName) - conf.enginePreference.indexOf(b.engineName);
});
clip.sources.some(function(source) {
var eng = engines.filter(function(engine) {
if (source.engine && source.engine !== engine.engineName) return false;
return engine.canPlay(source.type, api.conf);
}).shift();
if (eng) engine = eng;
return !!eng;
});
return engine;
};
/*** Behaviour ***/
if (!root.getAttribute('data-flowplayer-instance-id')) { // Only bind once
root.setAttribute('data-flowplayer-instance-id', playerCount++);
api.on('boot', function() {
var support = flowplayer.support;
// splash
if (conf.splash || common.hasClass(root, "is-splash") ||
!support.firstframe) {
api.forcedSplash = !conf.splash && !common.hasClass(root, "is-splash");
api.splash = true;
if (!conf.splash) conf.splash = true;
common.addClass(root, "is-splash");
}
if (conf.splash) common.find('video', root).forEach(common.removeNode);
if (conf.dvr || conf.live || common.hasClass(root, 'is-live')) {
api.live = conf.live = true;
api.dvr = conf.dvr = !!conf.dvr || common.hasClass(root, 'is-dvr');
common.addClass(root, 'is-live');
common.toggleClass(root, 'is-dvr', api.dvr);
}
// extensions
extensions.forEach(function(e) {
e(api, root);
});
// instances
instances.push(api);
// start
if (conf.splash) api.unload(); else api.load();
// disabled
if (conf.disabled) api.disable();
// initial callback
api.one("ready", callback);
api.one('shutdown', function() { root.className = originalClass; });
}).on("load", function(e, api, video) {
// unload others
if (conf.splash) {
common.find('.flowplayer.is-ready,.flowplayer.is-loading').forEach(function(el) {
var playerId = el.getAttribute('data-flowplayer-instance-id');
if (playerId === root.getAttribute('data-flowplayer-instance-id')) return;
var a = instances[Number(playerId)];
if (a && a.conf.splash) a.unload();
});
}
// loading
common.addClass(root, "is-loading");
api.loading = true;
if (typeof video.live !== 'undefined' || typeof video.dvr !== 'undefined') {
common.toggleClass(root, 'is-live', video.dvr || video.live);
common.toggleClass(root, 'is-dvr', !!video.dvr);
api.live = video.dvr || video.live;
api.dvr = !!video.dvr;
}
}).on("ready", function(e, api, video) {
video.time = 0;
api.video = video;
common.removeClass(root, "is-loading");
api.loading = false;
// saved state
if (api.muted) api.mute(true, true);
else api.volume(api.volumeLevel);
// see https://github.com/flowplayer/flowplayer/issues/479
var hlsFix = api.conf.hlsFix && /mpegurl/i.exec(video.type);
common.toggleClass(root, 'hls-fix', !!hlsFix);
}).on("unload", function() {
common.removeClass(root, "is-loading");
api.loading = false;
}).on("ready unload", function(e) {
var is_ready = e.type == "ready";
common.toggleClass(root, 'is-splash', !is_ready);
common.toggleClass(root, 'is-ready', is_ready);
api.ready = is_ready;
api.splash = !is_ready;
}).on("progress", function(e, api, time) {
api.video.time = time;
}).on('buffer', function(e, api, buffered) {
api.video.buffer = typeof buffered === 'number' ? buffered : buffered.length ? buffered[buffered.length - 1].end : 0;
}).on("speed", function(e, api, val) {
api.currentSpeed = val;
}).on("volume", function(e, api, level) {
api.volumeLevel = Math.round(level * 100) / 100;
if (api.muted && level) api.mute(false);
}).on("beforeseek seek", function(e) {
api.seeking = e.type == "beforeseek";
common.toggleClass(root, 'is-seeking', api.seeking);
}).on("ready pause resume unload finish stop", function(e) {
// PAUSED: pause / finish
api.paused = /pause|finish|unload|stop/.test(e.type);
api.paused = api.paused || e.type === 'ready' && !conf.autoplay && !api.playing;
// the opposite
api.playing = !api.paused;
// CSS classes
common.toggleClass(root, 'is-paused', api.paused);
common.toggleClass(root, 'is-playing', api.playing);
// sanity check
if (!api.load.ed) api.pause();
}).on("finish", function() {
api.finished = true;
}).on("error", function() {
});
}
// boot
api.trigger('boot', [api, root]);
return api;
}