vsmov-core/resources/assets/js/jwplayer.hlsjs.min.js
Clemencia John 68260d170a vsmov 1.0.0
2026-04-15 21:11:19 -07:00

1022 lines
38 KiB
JavaScript

(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.jwplayer_hls_provider = 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 || 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 has = Object.prototype.hasOwnProperty
var prefix = '~'
/**
* Constructor to create a storage for our `EE` objects.
* An `Events` instance is a plain object whose properties are event names.
*
* @constructor
* @api private
*/
function Events () {}
//
// We try to not inherit from `Object.prototype`. In some engines creating an
// instance in this way is faster than calling `Object.create(null)` directly.
// If `Object.create(null)` is not supported we prefix the event names with a
// character to make sure that the built-in object properties are not
// overridden or used as an attack vector.
//
if (Object.create) {
Events.prototype = Object.create(null)
//
// This hack is needed because the `__proto__` property is still inherited in
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
//
if (!new Events().__proto__) prefix = false
}
/**
* Representation of a single event listener.
*
* @param {Function} fn The listener function.
* @param {Mixed} context The context to invoke the listener with.
* @param {Boolean} [once=false] Specify if the listener is a one-time listener.
* @constructor
* @api private
*/
function EE (fn, context, once) {
this.fn = fn
this.context = context
this.once = once || false
}
/**
* Minimal `EventEmitter` interface that is molded against the Node.js
* `EventEmitter` interface.
*
* @constructor
* @api public
*/
function EventEmitter () {
this._events = new Events()
this._eventsCount = 0
}
/**
* Return an array listing the events for which the emitter has registered
* listeners.
*
* @returns {Array}
* @api public
*/
EventEmitter.prototype.eventNames = function eventNames () {
var names = []
var events
var name
if (this._eventsCount === 0) return names
for (name in (events = this._events)) {
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name)
}
if (Object.getOwnPropertySymbols) {
return names.concat(Object.getOwnPropertySymbols(events))
}
return names
}
/**
* Return the listeners registered for a given event.
*
* @param {String|Symbol} event The event name.
* @param {Boolean} exists Only check if there are listeners.
* @returns {Array|Boolean}
* @api public
*/
EventEmitter.prototype.listeners = function listeners (event, exists) {
var evt = prefix ? prefix + event : event
var available = this._events[evt]
if (exists) return !!available
if (!available) return []
if (available.fn) return [available.fn]
for (var i = 0, l = available.length, ee = new Array(l); i < l; i++) {
ee[i] = available[i].fn
}
return ee
}
/**
* Calls each of the listeners registered for a given event.
*
* @param {String|Symbol} event The event name.
* @returns {Boolean} `true` if the event had listeners, else `false`.
* @api public
*/
EventEmitter.prototype.emit = function emit (event, a1, a2, a3, a4, a5) {
var evt = prefix ? prefix + event : event
if (!this._events[evt]) return false
var listeners = this._events[evt]
var len = arguments.length
var args
var i
if (listeners.fn) {
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true)
switch (len) {
case 1: return listeners.fn.call(listeners.context), true
case 2: return listeners.fn.call(listeners.context, a1), true
case 3: return listeners.fn.call(listeners.context, a1, a2), true
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true
}
for (i = 1, args = new Array(len - 1); i < len; i++) {
args[i - 1] = arguments[i]
}
listeners.fn.apply(listeners.context, args)
} else {
var length = listeners.length
var j
for (i = 0; i < length; i++) {
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true)
switch (len) {
case 1: listeners[i].fn.call(listeners[i].context); break
case 2: listeners[i].fn.call(listeners[i].context, a1); break
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break
default:
if (!args) {
for (j = 1, args = new Array(len - 1); j < len; j++) {
args[j - 1] = arguments[j]
}
}
listeners[i].fn.apply(listeners[i].context, args)
}
}
}
return true
}
/**
* Add a listener for a given event.
*
* @param {String|Symbol} event The event name.
* @param {Function} fn The listener function.
* @param {Mixed} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @api public
*/
EventEmitter.prototype.on = function on (event, fn, context) {
var listener = new EE(fn, context || this)
var evt = prefix ? prefix + event : event
if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++
else if (!this._events[evt].fn) this._events[evt].push(listener)
else this._events[evt] = [this._events[evt], listener]
return this
}
/**
* Add a one-time listener for a given event.
*
* @param {String|Symbol} event The event name.
* @param {Function} fn The listener function.
* @param {Mixed} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @api public
*/
EventEmitter.prototype.once = function once (event, fn, context) {
var listener = new EE(fn, context || this, true)
var evt = prefix ? prefix + event : event
if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++
else if (!this._events[evt].fn) this._events[evt].push(listener)
else this._events[evt] = [this._events[evt], listener]
return this
}
/**
* Remove the listeners of a given event.
*
* @param {String|Symbol} event The event name.
* @param {Function} fn Only remove the listeners that match this function.
* @param {Mixed} context Only remove the listeners that have this context.
* @param {Boolean} once Only remove one-time listeners.
* @returns {EventEmitter} `this`.
* @api public
*/
EventEmitter.prototype.removeListener = function removeListener (event, fn, context, once) {
var evt = prefix ? prefix + event : event
if (!this._events[evt]) return this
if (!fn) {
if (--this._eventsCount === 0) this._events = new Events()
else delete this._events[evt]
return this
}
var listeners = this._events[evt]
if (listeners.fn) {
if (
listeners.fn === fn &&
(!once || listeners.once) &&
(!context || listeners.context === context)
) {
if (--this._eventsCount === 0) this._events = new Events()
else delete this._events[evt]
}
} else {
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
if (
listeners[i].fn !== fn ||
(once && !listeners[i].once) ||
(context && listeners[i].context !== context)
) {
events.push(listeners[i])
}
}
//
// Reset the array, or remove it completely if we have no more listeners.
//
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events
else if (--this._eventsCount === 0) this._events = new Events()
else delete this._events[evt]
}
return this
}
/**
* Remove all listeners, or those of the specified event.
*
* @param {String|Symbol} [event] The event name.
* @returns {EventEmitter} `this`.
* @api public
*/
EventEmitter.prototype.removeAllListeners = function removeAllListeners (event) {
var evt
if (event) {
evt = prefix ? prefix + event : event
if (this._events[evt]) {
if (--this._eventsCount === 0) this._events = new Events()
else delete this._events[evt]
}
} else {
this._events = new Events()
this._eventsCount = 0
}
return this
}
//
// Alias methods names because people roll like that.
//
EventEmitter.prototype.off = EventEmitter.prototype.removeListener
EventEmitter.prototype.addListener = EventEmitter.prototype.on
//
// This function doesn't apply anymore.
//
EventEmitter.prototype.setMaxListeners = function setMaxListeners () {
return this
}
//
// Expose the prefix.
//
EventEmitter.prefixed = prefix
//
// Allow `EventEmitter` to be imported as module namespace.
//
EventEmitter.EventEmitter = EventEmitter
//
// Expose the module.
//
if (typeof module !== 'undefined') {
module.exports = EventEmitter
}
}, {}],
2: [function (_dereq_, module, exports) {
'use strict'
var EventEmitter = _dereq_('eventemitter3')
var E = module.exports = HlsProv
var provider_attached = false
// jwplayer v8+ dropped exposing jwplayer.events
var jwe = {
JWPLAYER_MEDIA_BEFORECOMPLETE: 'beforeComplete',
JWPLAYER_MEDIA_BUFFER: 'bufferChange',
JWPLAYER_MEDIA_BUFFER_FULL: 'bufferFull',
JWPLAYER_MEDIA_COMPLETE: 'complete',
JWPLAYER_MEDIA_ERROR: 'mediaError',
JWPLAYER_MEDIA_LEVELS: 'levels',
JWPLAYER_MEDIA_LEVEL_CHANGED: 'levelsChanged',
JWPLAYER_MEDIA_META: 'meta',
JWPLAYER_MEDIA_SEEK: 'seek',
JWPLAYER_MEDIA_SEEKED: 'seeked',
JWPLAYER_MEDIA_TIME: 'time',
JWPLAYER_MEDIA_TYPE: 'mediaType',
JWPLAYER_PLAYER_STATE: 'state',
JWPLAYER_PROVIDER_FIRST_FRAME: 'providerFirstFrame'
}
// XXX arik: protect against exceptions in api. currently jwplayer will be
// stuck + add test
function HlsProv (id) {
var jwplayer = E.jwplayer || window.jwplayer; var Hls = E.Hls || window.Hls
var jw = id && jwplayer(id)
console.log('init hola/hls provider v' + E.VERSION + ' hls v' + Hls.version +
(E.version ? ' hap v' + E.version : ''))
jw.provider = this
function empty_fn (name) { return function () {} }
var _this = this
this.hls_restore_pos = function () {
var new_pos = this.hls_queued.seek
var old_pos = video.currentTime
if (hls.streamController.state == 'STOPPED') {
// XXX pavelki: hack to use our start position
hls.streamController.startPosition = 0
hls.startLoad(new_pos || 0)
}
if (!new_pos) { return }
this._in_seek = true
video.currentTime = new_pos
this.trigger(jwe.JWPLAYER_MEDIA_SEEK, { position: old_pos,
offset: new_pos })
// XXX pavelki: hack to override W3 algorithm of media
// seeking: when video element has HAVE_NOTHING state,
// seeking event doesn't fire and loading doesn't start
if (!video.readyState) { video.dispatchEvent(new Event('seeking')) }
this.hls_queued.seek = 0
}
function check_playback_started (video) {
if (video.paused) { return void hls_log('video play refused') }
function rm_listeners () {
video.removeEventListener('playing', listener)
video.removeEventListener('pause', listener)
video.removeEventListener('abort', listener)
video.removeEventListener('error', listener)
}
function listener (e) {
rm_listeners()
if (e.type != 'playing') { hls_log('play() was interrupted by a "' + e.type + '" event') }
}
video.addEventListener('playing', listener)
video.addEventListener('abort', listener)
video.addEventListener('error', listener)
video.addEventListener('pause', listener)
}
function video_play () {
var promise = video.play() || check_playback_started(video)
if (promise && promise.catch) {
promise.catch(function (err) {
hls_log('video_play failed with ' + err)
console.warn(err)
_this.trigger('checkAutoplayFailed', {err})
// user gesture required to start playback
if (err.name == 'NotAllowedError' &&
video.hasAttribute('jw-gesture-required')) {
_this.trigger('autoplayFailed')
video.setAttribute('autoplay-failed', 'failed')
}
})
} else if (video.hasAttribute('jw-gesture-required')) {
// autoplay isn't supported in older versions of Safari (<10)
// and Chrome (<53)
_this.trigger('autoplayFailed')
video.setAttribute('autoplay-failed', 'failed')
}
}
function hls_log (msg) {
var dbg
// if (dbg = hls_params.debug) { dbg.log(msg) }
}
function hls_play () {
hls_log('hls_play state: ' + _this.hls_state + ' att:' + _this.attached)
if (!(_this.hls_queued.play = _this.hls_state != 'ready') &&
_this.attached) {
_this.hls_restore_pos()
video_play()
}
}
function hls_load (src) {
if (!src) { return }
if (_this.hls_state == 'ready') { _this.hls_state = 'idle' }
if (_this.level_cb) { hls.off(Hls.Events.LEVEL_LOADED, _this.level_cb) }
_this.level_cb = function () {
hls_log('hls play queued on level_cb:' + _this.hls_queued.play)
hls.off(Hls.Events.LEVEL_LOADED, _this.level_cb)
_this.level_cb = undefined
_this.hls_state = 'ready'
if (_this.hls_queued.play) { hls_play() }
_this.trigger(jwe.JWPLAYER_MEDIA_BUFFER_FULL)
}
hls.on(Hls.Events.LEVEL_LOADED, _this.level_cb)
hls.loadSource(src)
if (!hls.media) { _this.attachMedia() }
}
function on_video_src_change (video, allow_cb) {
var o = video
for (; o && !o.hasOwnProperty('src'); o = Object.getPrototypeOf(o));
if (!o) { return }
var prop = Object.getOwnPropertyDescriptor(o, 'src')
// XXX volodymyr: some browsers (e.g. safari9) may lock access to src,
// solution copied from polyfill.video_source_access in html5.js
if (!prop.get && !prop.set) {
prop.get = function () {
var src = video.getAttribute('src')
return src != null ? src : ''
}
prop.set = function (s) {
var el = document.createElement('source')
el.src = s || '' // will convert relative path into absolute uri
video.setAttribute('src', el.src)
}
}
Object.defineProperty(video, 'src', {
configurable: true,
enumerable: false,
set: function (src) {
if (allow_cb(prop.get.call(video), src)) { prop.set.call(video, src) }
},
get: prop.get
})
}
function get_default_src (sources) {
return sources &&
sources.find(function (s) { return s.default }) || sources[0]
}
function _log (method, message) {
if (_this.hls.holaLog && _this.hls.holaLog[method]) { _this.hls.holaLog[method].call(_this.hls.holaLog, message) }
}
// XXX marka: jwplayer inherits provider from DefaultProvider, so it will
// override our inheritance from EventEmitter, do it manually
this.events = new EventEmitter()
this.addEventListener = this.on = this.events.on.bind(this.events)
this.once = this.events.once.bind(this.events)
this.removeEventListener = this.off = this.events.off.bind(this.events)
this.trigger = this.emit = function (e) {
if (!_this.attached && !_this.before_complete) { return }
var args = [].slice.call(arguments)
_this.events.emit.apply(this.events, args)
if (e != 'all') {
args.unshift('all')
_this.events.emit.apply(this.events, args)
}
}
this.removeAllListeners = function (e) {
this.events.removeAllListeners(e)
}
this.hls_queued = { play: false, seek: 0 }
this.attached = true
this.hls_state = 'idle'
this.is_mobile = function () {
var ios; var and; var ua = navigator.userAgent
if ((ios = /iP(hone|ad|od)/i.test(ua)) || (and = /Android/i.test(ua))) { return { is_ios: ios, is_android: and } }
}
this.supports_captions = function () {
var ua = navigator.userAgent
return /(iPhone|iPad|iPod|iPod touch);.*?OS/.test(ua) ||
/ (Chrome|Version)\/\d+(\.\d+)+.* Safari\/\d+(\.\d+)+/.test(ua) ||
/Firefox\/(\d+(?:\.\d+)+)/.test(ua)
}
var element = document.getElementById(id); var container
var video = element ? element.querySelector('video') : undefined; var hls
var try_play; var can_play; var _is_mobile = this.is_mobile()
var visual_quality = { reason: 'initial choice', mode: 'auto' }
if (!video) {
video = document.createElement('video')
if (_is_mobile) { video.setAttribute('jw-gesture-required', '') }
}
video.className = 'jw-video jw-reset'
// XXX marka: mark html5 element to skip autodetection of dm/hls
video.hola_dm_hls_attached = true
// XXX pavelki: hack to override ozee's wrong src set
on_video_src_change(video, function (from, to) { return to != from + '?' })
var hls_params = E.hls_params || {}; var hola_log
this.ad_count = 0
if (jw) {
jw.on('captionsList', caption_track)
jw.on('captionsChanged', caption_track)
// XXX pavelki: counters for ad, need to make loading deferred
jw.on('adImpression', function () {
_this.ad_count++
})
jw.on('adComplete', function () { _this.ad_count-- })
jw.on('adSkipped', function () { _this.ad_count-- })
Object.assign(hls_params, jw.hola_config)
hls_params.xhrSetup = window.customXHR
hls_params.liveSyncDurationCount = 5
hls_params.fragLoadingRetryDelay = 500
hls_params.autoStartLoad = true
hls_params.maxBufferLength = 300
if (hls_params.debug != 'undefined') {
hola_log = hls_params.debug
delete hls_params.debug
}
}
hls_params.debug = {};
['debug', 'info', 'log', 'warn', 'error'].forEach(function (method) {
hls_params.debug[method] = _log.bind(null, method)
})
this.hls = hls = new Hls(hls_params)
hls.holaLog = hola_log
if (jw) { jw.hls = hls }
var _buffered, _duration, _position
function caption_track (cc) {
if (!_this.renderNatively) { return }
var tracks = video.textTracks; var new_id = cc.tracks[cc.track].id
for (var i = 0; i < tracks.length; i++) { tracks[i].mode = tracks[i]._id == new_id ? 'showing' : 'hidden' }
}
function get_seekable_end () {
var i; var end; var len = video.seekable ? video.seekable.length : 0
for (end = 0, i = 0; i < len; i++) { end = Math.max(end, video.seekable.end(i)) }
return end
}
function get_duration () {
var duration = video.duration; var end = get_seekable_end()
if (duration == Infinity && end) {
var seekable_dur = end - video.seekable.start(0)
if (seekable_dur != Infinity && seekable_dur > 120) { duration = -seekable_dur }
}
return duration
}
function get_duration_inf () {
return is_live() ? 1 / 0 : get_duration()
}
function is_live () {
var live, levels
try {
if (!(levels = hls.streamController.levels)) { return }
var loaded_lvl = levels.find(function (lvl) { return lvl.details })
live = loaded_lvl && !!loaded_lvl.details.live
} catch (e) { hls_log('is_live failed with ' + e) }
return live
}
function get_buffered () {
var buf = video.buffered; var dur = video.duration
if (!buf || !buf.length || dur <= 0 || dur == Infinity) { return 0 }
return Math.min(buf.end(buf.length - 1) / dur, 1.0)
}
function set_buffered (buffered, pos, duration) {
if (buffered == _buffered && duration == _duration) { return }
_buffered = buffered
_this.trigger(jwe.JWPLAYER_MEDIA_BUFFER, { bufferPercent: buffered * 100,
position: pos,
duration: get_duration_inf() })
}
function playback_complete () {
_this.setState('complete')
_this.trigger(jwe.JWPLAYER_MEDIA_COMPLETE)
_this.before_complete = false
}
var video_listeners = {
durationchange: function () {
_duration = get_duration()
set_buffered(get_buffered(), _position, _duration)
},
ended: function () {
if (_this.state == 'idle' || _this.state == 'complete') { return }
_this.before_complete = true
_this.trigger(jwe.JWPLAYER_MEDIA_BEFORECOMPLETE)
if (_this.attached) { playback_complete() }
},
error: function () {
_this.trigger(jwe.JWPLAYER_MEDIA_ERROR, {
message: 'Error loading media: File could not be played' })
},
loadstart: function () { video.setAttribute('jw-loaded', 'started') },
loadeddata: function () {
video.setAttribute('jw-loaded', 'data')
if (!_this.supports_captions()) { return }
video.textTracks.onaddtrack = function () {
_this.renderNatively = true
_this.trigger('subtitlesTracks', { tracks: video.textTracks })
}
// XXX pavelki: add checking of playlist
if (video.textTracks.length) { video.textTracks.onaddtrack() }
},
loadedmetadata: function () {
if (video.muted) {
video.muted = false
video.muted = true
}
video.setAttribute('jw-loaded', 'meta')
_duration = get_duration()
_this.trigger(jwe.JWPLAYER_MEDIA_META, { duration:
get_duration_inf(),
height: video.videoHeight,
width: video.videoWidth })
},
canplay: function () {
can_play = true
_this.trigger(jwe.JWPLAYER_MEDIA_BUFFER_FULL)
},
playing: function () {
_this.setState('playing')
if (!video.hasAttribute('jw-played')) { video.setAttribute('jw-played', '') }
if (video.hasAttribute('jw-gesture-required')) {
video.removeAttribute('jw-gesture-required')
video.removeAttribute('autoplay-failed')
}
_this.trigger(jwe.JWPLAYER_PROVIDER_FIRST_FRAME, {})
},
pause: function () {
if (_this.state == 'complete' || video.currentTime == video.duration) { return }
_this.setState('paused')
},
seeking: function () {
if (!_this._in_seek) {
_this._in_seek = true
_this.trigger(jwe.JWPLAYER_MEDIA_SEEK, { position: _position,
offset: video.currentTime })
}
},
seeked: function () {
_this._in_seek = false
_this.trigger(jwe.JWPLAYER_MEDIA_SEEKED)
},
progress: function () {
set_buffered(get_buffered(), _position, _duration)
},
timeupdate: function () {
_duration = get_duration()
_position = _duration < 0 ? -(get_seekable_end() - video.currentTime)
: video.currentTime
var a = {
position: _position,
duration: _duration,
currentTime: video.currentTime,
metadata: {currentTime: video.currentTime}
};
set_buffered(get_buffered(), _position, _duration);
if (_this.state=='playing')
{
_this.trigger(jwe.JWPLAYER_MEDIA_TIME, a);
}
// set_buffered(get_buffered(), _position, _duration)
// if (_this.state == 'playing') {
// _this.trigger(jwe.JWPLAYER_MEDIA_TIME, { position: _position,
// duration: get_duration_inf() })
// }
}
}
function wrap_gen (e) {
return function () {
if (!_this.attached) { return }
video_listeners[e]()
}
}
for (var e in video_listeners) { video.addEventListener(e, wrap_gen(e), false) }
function scaled_number (num) {
if (num === undefined) { return '' }
if (!num) { return '0' }
var k = 1024
var sizes = ['', 'K', 'M', 'G', 'T', 'P']
var i = Math.floor(Math.log(num) / Math.log(k))
num /= Math.pow(k, i)
if (num < 0.001) { return '0' }
if (num >= k - 1) { num = Math.trunc(num) }
var str = num.toFixed(num < 1 ? 3 : num < 10 ? 2 : num < 100 ? 1 : 0)
return str.replace(/\.0*$/, '') + sizes[i]
}
// XXX yurij: duplicate from videojs5-hlsjs to avoid deps
function level_label (level) {
if (level.height) { return level.height + 'p' }
if (level.width) { return Math.round(level.width * 9 / 16) + 'p' }
if (level.bitrate) { return scaled_number(level.bitrate) + 'bps' }
return 0
}
function get_levels () {
var levels = hls.levels || []; var res = []
// level 0 mimics native jw's hls provider behavior
if (levels.length > 1) { res.push({ label: 'Auto' }) }
levels.forEach(function (level) {
res.push({ bitrate: level.bitrate,
height: level.height,
label: level_label(level),
width: level.width })
})
return res
}
function get_level (level) {
var levels = hls.levels || []
level = level || hls.currentLevel
return {
// level 0 is dummy for 'Auto' option in jwplayer's UI
jw: hls.manual_level == -1 || levels.length < 2 ? 0 : level + 1,
real: levels.length < 2 ? 0 : level + 1
}
}
hls.on(Hls.Events.ERROR, function (event, data) {
if (!data.fatal) { return }
var msg
switch (data.details) {
case Hls.ErrorDetails.MANIFEST_LOAD_ERROR:
case Hls.ErrorDetails.MANIFEST_LOAD_TIMEOUT:
msg = 'Cannot load M3U8: ' + data.response.statusText
break
default:
msg = 'Error loading media: ' + data.details
break
}
var a = {key: 'cantPlayVideo', code: data.details, recoverable: false, stalling: false, suppressLevel: false, fatal: true, error: data};
_this.trigger(jwe.JWPLAYER_MEDIA_ERROR, a)
// var seen = [];
//
// var raw_error = JSON.stringify(data, function(key, val) {
// if (typeof val == "object") {
// if (seen.indexOf(val) >= 0)
// return;
// seen.push(val)
// }
// return val;
// });
//
// var time = getPlaying(video_id, episode_id);
//
// $.ajax({
// type: 'POST',
// url: '/play-trunk-error',
// data: {
// 'video_id': video_id,
// 'episode_id': episode_id,
// 'message': msg,
// 'raw_error' : raw_error,
// 'time': parseInt(time)
// },
// dataType: 'json',
// success: function (data) {
// },
// error: function (data) {
// }
// });
})
hls.on(Hls.Events.MANIFEST_LOADED, function () {
_this.trigger(jwe.JWPLAYER_MEDIA_LEVELS, {
currentQuality: get_level().jw,
levels: get_levels()
})
var levels; var is_video = 0
if (!(levels = hls.levels)) { return }
levels.forEach(function (level) {
is_video += +!!(level.videoCodec || !level.audioCodec &&
(level.bitrate > 64000 || level.width || level.height))
})
_this.trigger(jwe.JWPLAYER_MEDIA_TYPE, { mediaType: is_video
? 'video' : 'audio' })
})
hls.on(Hls.Events.LEVEL_SWITCH, function (e, data) {
var levels = get_levels(); var level_id = get_level(data.level)
_this.trigger(jwe.JWPLAYER_MEDIA_LEVEL_CHANGED, {
currentQuality: level_id.jw,
levels: levels
})
var level = levels[level_id.real]
visual_quality.level = level
visual_quality.level.index = level_id.real
visual_quality.level.label = hls.manual_level == -1 && levels.length > 1
? 'auto' : level.label
visual_quality.reason = visual_quality.reason || 'auto'
_this.trigger('visualQuality', visual_quality)
visual_quality.reason = ''
})
this.init = function (item) {
try_play = false
video.setAttribute('jw-loaded', 'init')
}
this.load = function (item) {
if (!this.attached) { return }
var newsource = get_default_src(item.sources).file
var video_state = video.getAttribute('jw-loaded')
var hq = this.hls_queued; var played = video.hasAttribute('jw-played')
if (!_is_mobile || played) {
// don't change state on mobile before user initiates playback
this.setState('loading')
}
hq.seek = Math.max(item.starttime - (hq.rw_sec || 0), 0)
if (this.hls_state != 'ready' || (this.source || '') != newsource ||
['init', 'started'].includes(video_state)) {
var sc
try_play = false
video.load()
hls.stopLoad(hls.media && this.hls_state == 'ready' &&
video_state == 'init')
hls_load(this.source = newsource)
video.setAttribute('jw-loaded', 'init')
} else { hls_play() }
if (_is_mobile && !played) {
if (!try_play && (!_is_mobile.is_ios || can_play)) {
try_play = true
can_play = false
video_play()
}
if (!video.paused && this.state != 'playing') { this.setState('loading') }
}
}
this.play = function () { hls_play() }
this.pause = function () {
video.pause()
_this.setState('paused')
}
this.stop = function () {
hls.stopLoad()
_this.setState('idle')
}
this.volume = function (vol) { video.volume = Math.min(vol / 100, 1.0) }
this.mute = function (state) { video.muted = !!state }
this.seek = function (pos) {
this._in_seek = true
if (this.hls_state == 'ready') {
var sv = video.currentTime
video.currentTime = pos
this.trigger(jwe.JWPLAYER_MEDIA_SEEK, { position: sv, offset: pos })
} else { this.hls_queued.seek = pos }
}
// XXX arik: todo, without it video resize will be wrong.
// eg. http://www.ozee.com/shows/muddha-mandaram#hola_mode=cdn&hola_zone=ozee_hap
this.resize = function (width, height, stretching) {}
this.remove = function () {
this.in_container = false
hls.stopLoad()
this.source = undefined
if (container === video.parentNode) { container.removeChild(video) }
}
this.destroy = function () {
for (var e in video_listeners) { video.removeEventListener(e, video_listeners[e], false) }
this.removeAllListeners()
}
this.setVisibility = function (state) {
container.style.visibility = state ? 'visible' : ''
container.style.opacity = state ? 1 : 0
}
this.setFullscreen = function () { return false }
this.getFullscreen = empty_fn('getFullscreen')
this.getContainer = function () { return container }
this.setContainer = function (element) {
container = element
container.appendChild(video)
this.in_container = true
}
hls.manual_level = -1
this.setCurrentQuality = function (level) {
if (level == hls.manual_level + 1) { return }
hls.manual_level = level - 1
if (!hls.hola_adaptive) { hls.loadLevel = hls.manual_level }
_this.trigger(jwe.JWPLAYER_MEDIA_LEVEL_CHANGED,
{ currentQuality: level, levels: get_levels() })
visual_quality.reason = 'api'
}
this.getName = function () { return { name: 'hola/hls' } }
this.get_position = function () { return video.currentTime }
this.getQualityLevels = function () { return get_levels() }
this.getCurrentQuality = function () { return get_level(hls.loadLevel).jw }
this.getAudioTracks = empty_fn('getAudioTracks')
this.getCurrentAudioTrack = empty_fn('getCurrentAudioTrack')
this.setCurrentAudioTrack = empty_fn('setCurrentAudioTrack')
this.checkComplete = function () { return !!this.before_complete }
this.setControls = empty_fn('setControls')
this.attachMedia = function () {
if (this.before_complete) { return playback_complete() }
if (this.ad_count) { hls_log('jwprovider attach inside ad ' + this.ad_count) }
this.attached = true
hls.attachMedia(video)
}
this.detachMedia = function () {
hls.trigger(Hls.Events.BUFFER_RESET)
hls.detachMedia()
if (this.level_cb) {
hls.off(Hls.Events.LEVEL_LOADED, this.level_cb)
this.level_cb = undefined
}
// XXX pavelki: hack to remove pending segments
try{
delete hls.bufferController.segments
}catch(err){
}
this.attached = false
return video
}
this.setState = function (state) {
var oldState = this.state || 'idle'
this.state = state
if (state == oldState) { return }
this.trigger(jwe.JWPLAYER_PLAYER_STATE, { newstate: state })
}
this.sendMediaType = function (levels) {
var is_audio = ['oga', 'aac', 'mp3', 'mpeg', 'vorbis']
.includes(levels[0].type)
this.trigger(jwe.JWPLAYER_MEDIA_TYPE, { mediaType: is_audio
? 'audio' : 'video' })
}
}
E.getName = function () { return { name: 'hola/hls' } }
// XXX yurij: copied from zjwplayer3.js to not depend on our code
function get_player_instances () {
var jwplayer = E.jwplayer || window.jwplayer
var i = 0; var res = []; var jw
// XXX marka/vadiml: a real instance will contain pause(), otherwise it
// will be {registerPlugin: ...} with anything the customer adds
while ((jw = jwplayer(i++)) && jw.pause) { res.push(jw) }
return res
}
function src_supported (src) {
if (src.type == 'hls') { return true }
return (src.file || '').match(/\.m3u8$/)
}
E.supports = function (src) {
var Hls = E.Hls || window.Hls
var is_ad = get_player_instances().every(function (j) {
// XXX yurij: jw.getPlaylist returns playlist item on early call
var pl = j.getPlaylist()
return (pl.every ? pl : [{ sources: [pl] }]).every(function (p) {
// XXX pavlo: playlist item can be w/o sources/allSources
return (p.allSources || p.sources || [{ file: p.file }])
.every(function (s) { return s.file != src.file })
})
})
if (is_ad) // XXX yurij: we are not supporting adaptive ads
{ return false }
return !E.disabled && src_supported(src) && Hls && Hls.isSupported()
}
E.attach = function () {
var jwplayer = E.jwplayer || window.jwplayer
E.disabled = false
if (!provider_attached) {
provider_attached = true
// XXX arik: unregister on error/fallback
jwplayer.api.registerProvider(this)
}
}
E.detach = function (hp) {
// we don't remove provider from list, just set it as disabled so it will
// return false in supports()
E.disabled = true
if (!hp || !hp.attached) { return }
hp.setState('idle')
hp.detachMedia()
}
// XXX vadiml copied from loader.js&zjwplayer3.js to not depend on our code.
// For use by HolaCDN Onboarding Tool extension
E.reload_jwplayer_instances = function () {
get_player_instances().forEach(function (jw) {
var c = jw.getConfig()
if (!c) { return }
// XXX marka: JW removes conf.advertising.client, try to restore it
if (c.advertising && !c.advertising.client && c.plugins) {
for (var url in c.plugins) {
if (c.plugins[url] !== c.advertising) { continue }
var m = url.match(/\/(\w+)\.js$/)
c.advertising.client = m && m[1]
break
}
}
jw.setup(c)
})
}
E.VERSION = '0.0.79'
}, { 'eventemitter3': 1 }] }, {}, [2])(2)
})
// # sourceMappingURL=jwplayer.hlsjs.js.map