(function(Modernizr, webshims){ "use strict"; var $ = webshims.$; var hasNative = Modernizr.audio && Modernizr.video; var supportsLoop = false; var bugs = webshims.bugs; var swfType = 'mediaelement-jaris'; var loadSwf = function(){ webshims.ready(swfType, function(){ if(!webshims.mediaelement.createSWF){ webshims.mediaelement.loadSwf = true; webshims.reTest([swfType], hasNative); } }); }; var wsCfg = webshims.cfg; var options = wsCfg.mediaelement; var hasFullTrackSupport; var hasSwf; if(!options){ webshims.error("mediaelement wasn't implemented but loaded"); return; } if(hasNative){ var videoElem = document.createElement('video'); Modernizr.videoBuffered = ('buffered' in videoElem); Modernizr.mediaDefaultMuted = ('defaultMuted' in videoElem); supportsLoop = ('loop' in videoElem); webshims.capturingEvents(['play', 'playing', 'waiting', 'paused', 'ended', 'durationchange', 'loadedmetadata', 'canplay', 'volumechange']); if(!Modernizr.videoBuffered ){ webshims.addPolyfill('mediaelement-native-fix', { d: ['dom-support'] }); webshims.loader.loadList(['mediaelement-native-fix']); } if(!options.preferFlash){ var noSwitch = { 1: 1 }; var switchOptions = function(e){ var media, error, parent; if(!options.preferFlash && ($(e.target).is('audio, video') || ((parent = e.target.parentNode) && $('source', parent).last()[0] == e.target)) && (media = $(e.target).closest('audio, video')) && (error = media.prop('error')) && !noSwitch[error.code] ){ $(function(){ if(hasSwf && !options.preferFlash){ loadSwf(); webshims.ready('WINDOWLOAD '+swfType, function(){ setTimeout(function(){ if(!options.preferFlash && webshims.mediaelement.createSWF && !media.is('.nonnative-api-active')){ options.preferFlash = true; document.removeEventListener('error', switchOptions, true); $('audio, video').each(function(){ webshims.mediaelement.selectSource(this); }); webshims.error("switching mediaelements option to 'preferFlash', due to an error with native player: "+e.target.src+" Mediaerror: "+ media.prop('error')+ 'first error: '+ error); } }, 9); }); } else{ document.removeEventListener('error', switchOptions, true); } }); } }; document.addEventListener('error', switchOptions, true); $('audio, video').each(function(){ var error = $.prop(this, 'error'); if(error && !noSwitch[error]){ switchOptions({target: this}); return false; } }); } } if(Modernizr.track && !bugs.track){ (function(){ if(!bugs.track){ bugs.track = typeof $('')[0].readyState != 'number'; } if(!bugs.track){ try { new TextTrackCue(2, 3, ''); } catch(e){ bugs.track = true; } } })(); } hasFullTrackSupport = Modernizr.track && !bugs.track; webshims.register('mediaelement-core', function($, webshims, window, document, undefined, options){ hasSwf = swfmini.hasFlashPlayerVersion('9.0.115'); $('html').addClass(hasSwf ? 'swf' : 'no-swf'); var mediaelement = webshims.mediaelement; mediaelement.parseRtmp = function(data){ var src = data.src.split('://'); var paths = src[1].split('/'); var i, len, found; data.server = src[0]+'://'+paths[0]+'/'; data.streamId = []; for(i = 1, len = paths.length; i < len; i++){ if(!found && paths[i].indexOf(':') !== -1){ paths[i] = paths[i].split(':')[1]; found = true; } if(!found){ data.server += paths[i]+'/'; } else { data.streamId.push(paths[i]); } } if(!data.streamId.length){ webshims.error('Could not parse rtmp url'); } data.streamId = data.streamId.join('/'); }; var getSrcObj = function(elem, nodeName){ elem = $(elem); var src = {src: elem.attr('src') || '', elem: elem, srcProp: elem.prop('src')}; var tmp; if(!src.src){return src;} tmp = elem.attr('data-server'); if(tmp != null){ src.server = tmp; } tmp = elem.attr('type') || elem.attr('data-type'); if(tmp){ src.type = tmp; src.container = $.trim(tmp.split(';')[0]); } else { if(!nodeName){ nodeName = elem[0].nodeName.toLowerCase(); if(nodeName == 'source'){ nodeName = (elem.closest('video, audio')[0] || {nodeName: 'video'}).nodeName.toLowerCase(); } } if(src.server){ src.type = nodeName+'/rtmp'; src.container = nodeName+'/rtmp'; } else { tmp = mediaelement.getTypeForSrc( src.src, nodeName, src ); if(tmp){ src.type = tmp; src.container = tmp; } } } if(!src.container){ $(elem).attr('data-wsrecheckmimetype', ''); } tmp = elem.attr('media'); if(tmp){ src.media = tmp; } if(src.type == 'audio/rtmp' || src.type == 'video/rtmp'){ if(src.server){ src.streamId = src.src; } else { mediaelement.parseRtmp(src); } } return src; }; var hasYt = !hasSwf && ('postMessage' in window) && hasNative; var loadTrackUi = function(){ if(loadTrackUi.loaded){return;} loadTrackUi.loaded = true; if(!options.noAutoTrack){ webshims.ready('WINDOWLOAD', function(){ loadThird(); webshims.loader.loadList(['track-ui']); }); } }; // var loadMediaGroup = function(){ // if(!loadMediaGroup.loaded){ // loadMediaGroup.loaded = true; // webshims.ready(window.MediaController ? 'WINDOWLOAD' : 'DOM', function(){ // webshims.loader.loadList(['mediagroup']); // }); // } // }; var loadYt = (function(){ var loaded; return function(){ if(loaded || !hasYt){return;} loaded = true; webshims.loader.loadScript("https://www.youtube.com/player_api"); $(function(){ webshims._polyfill(["mediaelement-yt"]); }); }; })(); var loadThird = function(){ if(hasSwf){ loadSwf(); } else { loadYt(); } }; webshims.addPolyfill('mediaelement-yt', { test: !hasYt, d: ['dom-support'] }); // webshims.addModule('mediagroup', { // d: ['mediaelement', 'dom-support'] // }); mediaelement.mimeTypes = { audio: { //ogm shouldn´t be used! 'audio/ogg': ['ogg','oga', 'ogm'], 'audio/ogg;codecs="opus"': 'opus', 'audio/mpeg': ['mp2','mp3','mpga','mpega'], 'audio/mp4': ['mp4','mpg4', 'm4r', 'm4a', 'm4p', 'm4b', 'aac'], 'audio/wav': ['wav'], 'audio/3gpp': ['3gp','3gpp'], 'audio/webm': ['webm'], 'audio/fla': ['flv', 'f4a', 'fla'], 'application/x-mpegURL': ['m3u8', 'm3u'] }, video: { //ogm shouldn´t be used! 'video/ogg': ['ogg','ogv', 'ogm'], 'video/mpeg': ['mpg','mpeg','mpe'], 'video/mp4': ['mp4','mpg4', 'm4v'], 'video/quicktime': ['mov','qt'], 'video/x-msvideo': ['avi'], 'video/x-ms-asf': ['asf', 'asx'], 'video/flv': ['flv', 'f4v'], 'video/3gpp': ['3gp','3gpp'], 'video/webm': ['webm'], 'application/x-mpegURL': ['m3u8', 'm3u'], 'video/MP2T': ['ts'] } } ; mediaelement.mimeTypes.source = $.extend({}, mediaelement.mimeTypes.audio, mediaelement.mimeTypes.video); mediaelement.getTypeForSrc = function(src, nodeName, data){ if(src.indexOf('youtube.com/watch?') != -1 || src.indexOf('youtube.com/v/') != -1){ return 'video/youtube'; } if(src.indexOf('rtmp') === 0){ return nodeName+'/rtmp'; } src = src.split('?')[0].split('#')[0].split('.'); src = src[src.length - 1]; var mt; $.each(mediaelement.mimeTypes[nodeName], function(mimeType, exts){ if(exts.indexOf(src) !== -1){ mt = mimeType; return false; } }); return mt; }; mediaelement.srces = function(mediaElem, srces){ mediaElem = $(mediaElem); if(!srces){ srces = []; var nodeName = mediaElem[0].nodeName.toLowerCase(); var src = getSrcObj(mediaElem, nodeName); if(!src.src){ $('source', mediaElem).each(function(){ src = getSrcObj(this, nodeName); if(src.src){srces.push(src);} }); } else { srces.push(src); } return srces; } else { mediaElem.removeAttr('src').removeAttr('type').find('source').remove(); if(!$.isArray(srces)){ srces = [srces]; } srces.forEach(function(src){ if(typeof src == 'string'){ src = {src: src}; } mediaElem.append($(document.createElement('source')).attr(src)); }); } }; $.fn.loadMediaSrc = function(srces, poster){ return this.each(function(){ if(poster !== undefined){ $(this).removeAttr('poster'); if(poster){ $.attr(this, 'poster', poster); } } mediaelement.srces(this, srces); $(this).mediaLoad(); }); }; mediaelement.swfMimeTypes = ['video/3gpp', 'video/x-msvideo', 'video/quicktime', 'video/x-m4v', 'video/mp4', 'video/m4p', 'video/x-flv', 'video/flv', 'audio/mpeg', 'audio/aac', 'audio/mp4', 'audio/x-m4a', 'audio/m4a', 'audio/mp3', 'audio/x-fla', 'audio/fla', 'youtube/flv', 'video/jarisplayer', 'jarisplayer/jarisplayer', 'video/youtube', 'video/rtmp', 'audio/rtmp']; mediaelement.canThirdPlaySrces = function(mediaElem, srces){ var ret = ''; if(hasSwf || hasYt){ mediaElem = $(mediaElem); srces = srces || mediaelement.srces(mediaElem); $.each(srces, function(i, src){ if(src.container && src.src && ((hasSwf && mediaelement.swfMimeTypes.indexOf(src.container) != -1) || (hasYt && src.container == 'video/youtube'))){ ret = src; return false; } }); } return ret; }; var nativeCanPlayType = {}; mediaelement.canNativePlaySrces = function(mediaElem, srces){ var ret = ''; if(hasNative){ mediaElem = $(mediaElem); var nodeName = (mediaElem[0].nodeName || '').toLowerCase(); var nativeCanPlay = (nativeCanPlayType[nodeName] || {prop: {_supvalue: false}}).prop._supvalue || mediaElem[0].canPlayType; if(!nativeCanPlay){return ret;} srces = srces || mediaelement.srces(mediaElem); $.each(srces, function(i, src){ if(src.type && nativeCanPlay.call(mediaElem[0], src.type) ){ ret = src; return false; } }); } return ret; }; var emptyType = (/^\s*application\/octet\-stream\s*$/i); var getRemoveEmptyType = function(){ var ret = emptyType.test($.attr(this, 'type') || ''); if(ret){ $(this).removeAttr('type'); } return ret; }; mediaelement.setError = function(elem, message){ if($('source', elem).filter(getRemoveEmptyType).length){ webshims.error('"application/octet-stream" is a useless mimetype for audio/video. Please change this attribute.'); try { $(elem).mediaLoad(); } catch(er){} } else { if(!message){ message = "can't play sources"; } $(elem).pause().data('mediaerror', message); webshims.error('mediaelementError: '+ message); setTimeout(function(){ if($(elem).data('mediaerror')){ $(elem).addClass('media-error').trigger('mediaerror'); } }, 1); } }; var handleThird = (function(){ var requested; var readyType = hasSwf ? swfType : 'mediaelement-yt'; return function( mediaElem, ret, data ){ //readd to ready webshims.ready(readyType, function(){ if(mediaelement.createSWF && $(mediaElem).parent()[0]){ mediaelement.createSWF( mediaElem, ret, data ); } else if(!requested) { requested = true; loadThird(); handleThird( mediaElem, ret, data ); } }); if(!requested && hasYt && !mediaelement.createSWF){ loadYt(); } }; })(); var stepSources = function(elem, data, useSwf, _srces, _noLoop){ var ret; if(useSwf || (useSwf !== false && data && data.isActive == 'third')){ ret = mediaelement.canThirdPlaySrces(elem, _srces); if(!ret){ if(_noLoop){ mediaelement.setError(elem, false); } else { stepSources(elem, data, false, _srces, true); } } else { handleThird(elem, ret, data); } } else { ret = mediaelement.canNativePlaySrces(elem, _srces); if(!ret){ if(_noLoop){ mediaelement.setError(elem, false); if(data && data.isActive == 'third') { mediaelement.setActive(elem, 'html5', data); } } else { stepSources(elem, data, true, _srces, true); } } else if(data && data.isActive == 'third') { mediaelement.setActive(elem, 'html5', data); } } }; var stopParent = /^(?:embed|object|datalist)$/i; var selectSource = function(elem, data){ var baseData = webshims.data(elem, 'mediaelementBase') || webshims.data(elem, 'mediaelementBase', {}); var _srces = mediaelement.srces(elem); var parent = elem.parentNode; clearTimeout(baseData.loadTimer); $(elem).removeClass('media-error'); $.data(elem, 'mediaerror', false); if(!_srces.length || !parent || parent.nodeType != 1 || stopParent.test(parent.nodeName || '')){return;} data = data || webshims.data(elem, 'mediaelement'); if(mediaelement.sortMedia){ _srces.sort(mediaelement.sortMedia); } stepSources(elem, data, options.preferFlash || undefined, _srces); }; mediaelement.selectSource = selectSource; $(document).on('ended', function(e){ var data = webshims.data(e.target, 'mediaelement'); if( supportsLoop && (!data || data.isActive == 'html5') && !$.prop(e.target, 'loop')){return;} setTimeout(function(){ if( $.prop(e.target, 'paused') || !$.prop(e.target, 'loop') ){return;} $(e.target).prop('currentTime', 0).play(); }, 1); }); var handleMedia = false; var initMediaElements = function(){ var testFixMedia = function(){ if(webshims.implement(this, 'mediaelement')){ selectSource(this); if(!Modernizr.mediaDefaultMuted && $.attr(this, 'muted') != null){ $.prop(this, 'muted', true); } //fixes for FF 12 and IE9/10 || does not hurt, if run in other browsers if(hasNative && (!supportsLoop || ('ActiveXObject' in window))){ var bufferTimer; var lastBuffered; var elem = this; var getBufferedString = function(){ var buffered = $.prop(elem, 'buffered'); if(!buffered){return;} var bufferString = ""; for(var i = 0, len = buffered.length; i < len;i++){ bufferString += buffered.end(i); } return bufferString; }; var testBuffer = function(){ var buffered = getBufferedString(); if(buffered != lastBuffered){ lastBuffered = buffered; webshims.info('needed to trigger progress manually'); $(elem).triggerHandler('progress'); } }; $(this) .on({ 'play loadstart progress': function(e){ if(e.type == 'progress'){ lastBuffered = getBufferedString(); } clearTimeout(bufferTimer); bufferTimer = setTimeout(testBuffer, 400); }, 'emptied stalled mediaerror abort suspend': function(e){ if(e.type == 'emptied'){ lastBuffered = false; } clearTimeout(bufferTimer); } }) ; if('ActiveXObject' in window && $.prop(this, 'paused') && !$.prop(this, 'readyState') && $(this).is('audio[preload="none"][controls]:not([autoplay],.nonnative-api-active)')){ $(this).prop('preload', 'metadata').mediaLoad(); } } } }; webshims.ready('dom-support', function(){ handleMedia = true; if(!supportsLoop){ webshims.defineNodeNamesBooleanProperty(['audio', 'video'], 'loop'); } ['audio', 'video'].forEach(function(nodeName){ var supLoad, supController; supLoad = webshims.defineNodeNameProperty(nodeName, 'load', { prop: { value: function(){ var data = webshims.data(this, 'mediaelement'); selectSource(this, data); if(hasNative && (!data || data.isActive == 'html5') && supLoad.prop._supvalue){ supLoad.prop._supvalue.apply(this, arguments); } $(this).triggerHandler('wsmediareload'); } } }); nativeCanPlayType[nodeName] = webshims.defineNodeNameProperty(nodeName, 'canPlayType', { prop: { value: function(type){ var ret = ''; if(hasNative && nativeCanPlayType[nodeName].prop._supvalue){ ret = nativeCanPlayType[nodeName].prop._supvalue.call(this, type); if(ret == 'no'){ ret = ''; } } if(!ret && hasSwf){ type = $.trim((type || '').split(';')[0]); if(mediaelement.swfMimeTypes.indexOf(type) != -1){ ret = 'maybe'; } } return ret; } } }); // supController = webshims.defineNodeNameProperty(nodeName, 'controller', { // prop: { // get: function(type){ // if(!loadMediaGroup.loaded){ // loadMediaGroup(); // } // if(mediaelement.controller){ // return mediaelement.controller[nodeName].get.apply(this, arguments); // } // return supController.prop._supget && supController.prop._supget.apply(this, arguments); // }, // set: function(){ // var that = this; // var args = arguments; // if(!loadMediaGroup.loaded){ // loadMediaGroup(); // } // if(mediaelement.controller){ // return mediaelement.controller[nodeName].set.apply(that, args); // } else { // webshims.ready('mediagroup', function(){ // mediaelement.controller[nodeName].set.apply(that, args); // }); // } // return supController.prop._supset && supController.prop._supset.apply(this, arguments); // } // } // }); // webshims.ready('mediagroup', function(){ // mediaelement.controller[nodeName].sup = supController; // }); }); // webshims.onNodeNamesPropertyModify(['audio', 'video'], ['mediaGroup'], { // set: function(){ // var that = this; // var args = arguments; // if(!loadMediaGroup.loaded){ // loadMediaGroup(); // } // if(mediaelement.mediagroup){ // mediaelement.mediagroup.set.apply(that, args); // } else { // webshims.ready('mediagroup', function(){ // mediaelement.mediagroup.set.apply(that, args); // }); // } // }, // initAttr: true // }); webshims.onNodeNamesPropertyModify(['audio', 'video'], ['src', 'poster'], { set: function(){ var elem = this; var baseData = webshims.data(elem, 'mediaelementBase') || webshims.data(elem, 'mediaelementBase', {}); clearTimeout(baseData.loadTimer); baseData.loadTimer = setTimeout(function(){ selectSource(elem); elem = null; }, 9); } }); webshims.addReady(function(context, insertedElement){ var media = $('video, audio', context) .add(insertedElement.filter('video, audio')) .each(testFixMedia) ; if(!loadTrackUi.loaded && $('track', media).length){ loadTrackUi(); } // if(!loadMediaGroup.loaded && this.getAttribute('mediagroup')){ // loadMediaGroup(); // } media = null; }); }); if(hasNative && !handleMedia){ webshims.addReady(function(context, insertedElement){ if(!handleMedia){ $('video, audio', context) .add(insertedElement.filter('video, audio')) .each(function(){ if(!mediaelement.canNativePlaySrces(this)){ loadThird(); handleMedia = true; return false; } }) ; } }); } }; if(hasFullTrackSupport){ webshims.defineProperty(TextTrack.prototype, 'shimActiveCues', { get: function(){ return this._shimActiveCues || this.activeCues; } }); } //set native implementation ready, before swf api is retested if(hasNative){ webshims.isReady('mediaelement-core', true); initMediaElements(); webshims.ready('WINDOWLOAD mediaelement', loadThird); } else { webshims.ready(swfType, initMediaElements); } webshims.ready('track', loadTrackUi); }); })(Modernizr, webshims);;webshims.register('track', function($, webshims, window, document, undefined){ "use strict"; var mediaelement = webshims.mediaelement; var id = new Date().getTime(); var ADDBACK = $.fn.addBack ? 'addBack' : 'andSelf'; //descriptions are not really shown, but they are inserted into the dom var showTracks = {subtitles: 1, captions: 1, descriptions: 1}; var notImplemented = function(){ webshims.error('not implemented yet'); }; var dummyTrack = $(''); var supportTrackMod = Modernizr.ES5 && Modernizr.objectAccessor; var createEventTarget = function(obj){ var eventList = {}; obj.addEventListener = function(name, fn){ if(eventList[name]){ webshims.error('always use $.on to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn); } eventList[name] = fn; }; obj.removeEventListener = function(name, fn){ if(eventList[name] && eventList[name] != fn){ webshims.error('always use $.on/$.off to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn); } if(eventList[name]){ delete eventList[name]; } }; return obj; }; var cueListProto = { getCueById: function(id){ var cue = null; for(var i = 0, len = this.length; i < len; i++){ if(this[i].id === id){ cue = this[i]; break; } } return cue; } }; var numericModes = { 0: 'disabled', 1: 'hidden', 2: 'showing' }; var textTrackProto = { shimActiveCues: null, _shimActiveCues: null, activeCues: null, cues: null, kind: 'subtitles', label: '', language: '', id: '', mode: 'disabled', oncuechange: null, toString: function() { return "[object TextTrack]"; }, addCue: function(cue){ if(!this.cues){ this.cues = mediaelement.createCueList(); } else { var lastCue = this.cues[this.cues.length-1]; if(lastCue && lastCue.startTime > cue.startTime){ webshims.error("cue startTime higher than previous cue's startTime"); } } if(cue.track && cue.track.removeCue){ cue.track.removeCue(cue); } cue.track = this; this.cues.push(cue); }, //ToDo: make it more dynamic removeCue: function(cue){ var cues = this.cues || []; var i = 0; var len = cues.length; if(cue.track != this){ webshims.error("cue not part of track"); return; } for(; i < len; i++){ if(cues[i] === cue){ cues.splice(i, 1); cue.track = null; break; } } if(cue.track){ webshims.error("cue not part of track"); return; } }/*, DISABLED: 'disabled', OFF: 'disabled', HIDDEN: 'hidden', SHOWING: 'showing', ERROR: 3, LOADED: 2, LOADING: 1, NONE: 0*/ }; var copyProps = ['kind', 'label', 'srclang']; var copyName = {srclang: 'language'}; var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty); var updateMediaTrackList = function(baseData, trackList){ var removed = []; var added = []; var newTracks = []; var i, len; if(!baseData){ baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {}); } if(!trackList){ baseData.blockTrackListUpdate = true; trackList = $.prop(this, 'textTracks'); baseData.blockTrackListUpdate = false; } clearTimeout(baseData.updateTrackListTimer); $('track', this).each(function(){ var track = $.prop(this, 'track'); newTracks.push(track); if(trackList.indexOf(track) == -1){ added.push(track); } }); if(baseData.scriptedTextTracks){ for(i = 0, len = baseData.scriptedTextTracks.length; i < len; i++){ newTracks.push(baseData.scriptedTextTracks[i]); if(trackList.indexOf(baseData.scriptedTextTracks[i]) == -1){ added.push(baseData.scriptedTextTracks[i]); } } } for(i = 0, len = trackList.length; i < len; i++){ if(newTracks.indexOf(trackList[i]) == -1){ removed.push(trackList[i]); } } if(removed.length || added.length){ trackList.splice(0); for(i = 0, len = newTracks.length; i < len; i++){ trackList.push(newTracks[i]); } for(i = 0, len = removed.length; i < len; i++){ $([trackList]).triggerHandler($.Event({type: 'removetrack', track: removed[i]})); } for(i = 0, len = added.length; i < len; i++){ $([trackList]).triggerHandler($.Event({type: 'addtrack', track: added[i]})); } if(baseData.scriptedTextTracks || removed.length){ $(this).triggerHandler('updatetrackdisplay'); } } }; var refreshTrack = function(track, trackData){ if(!trackData){ trackData = webshims.data(track, 'trackData'); } if(trackData && !trackData.isTriggering){ trackData.isTriggering = true; setTimeout(function(){ $(track).closest('audio, video').triggerHandler('updatetrackdisplay'); trackData.isTriggering = false; }, 1); } }; var isDefaultTrack = (function(){ var defaultKinds = { subtitles: { subtitles: 1, captions: 1 }, descriptions: {descriptions: 1}, chapters: {chapters: 1} }; defaultKinds.captions = defaultKinds.subtitles; return function(track){ var kind, firstDefaultTrack; var isDefault = $.prop(track, 'default'); if(isDefault && (kind = $.prop(track, 'kind')) != 'metadata'){ firstDefaultTrack = $(track) .parent() .find('track[default]') .filter(function(){ return !!(defaultKinds[kind][$.prop(this, 'kind')]); })[0] ; if(firstDefaultTrack != track){ isDefault = false; webshims.error('more than one default track of a specific kind detected. Fall back to default = false'); } } return isDefault; }; })(); var emptyDiv = $('
')[0]; var TextTrackCue = function(startTime, endTime, text){ if(arguments.length != 3){ webshims.error("wrong arguments.length for TextTrackCue.constructor"); } this.startTime = startTime; this.endTime = endTime; this.text = text; createEventTarget(this); }; TextTrackCue.prototype = { onenter: null, onexit: null, pauseOnExit: false, getCueAsHTML: function(){ var lastText = ""; var parsedText = ""; var fragment = document.createDocumentFragment(); var fn; if(!owns(this, 'getCueAsHTML')){ fn = this.getCueAsHTML = function(){ var i, len; if(lastText != this.text){ lastText = this.text; parsedText = mediaelement.parseCueTextToHTML(lastText); emptyDiv.innerHTML = parsedText; for(i = 0, len = emptyDiv.childNodes.length; i < len; i++){ fragment.appendChild(emptyDiv.childNodes[i].cloneNode(true)); } } return fragment.cloneNode(true); }; } return fn ? fn.apply(this, arguments) : fragment.cloneNode(true); }, track: null, id: '' //todo--> // , // snapToLines: true, // line: 'auto', // size: 100, // position: 50, // vertical: '', // align: 'middle' }; window.TextTrackCue = TextTrackCue; mediaelement.createCueList = function(){ return $.extend([], cueListProto); }; mediaelement.parseCueTextToHTML = (function(){ var tagSplits = /(<\/?[^>]+>)/ig; var allowedTags = /^(?:c|v|ruby|rt|b|i|u)/; var regEnd = /\<\s*\//; var addToTemplate = function(localName, attribute, tag, html){ var ret; if(regEnd.test(html)){ ret = ''+ localName +'>'; } else { tag.splice(0, 1); ret = '<'+ localName +' '+ attribute +'="'+ (tag.join(' ').replace(/\"/g, '"')) +'">'; } return ret; }; var replacer = function(html){ var tag = html.replace(/[<\/>]+/ig,"").split(/[\s\.]+/); if(tag[0]){ tag[0] = tag[0].toLowerCase(); if(allowedTags.test(tag[0])){ if(tag[0] == 'c'){ html = addToTemplate('span', 'class', tag, html); } else if(tag[0] == 'v'){ html = addToTemplate('q', 'title', tag, html); } } else { html = ""; } } return html; }; return function(cueText){ return cueText.replace(tagSplits, replacer); }; })(); mediaelement.loadTextTrack = function(mediaelem, track, trackData, _default){ var loadEvents = 'play playing updatetrackdisplay'; var obj = trackData.track; var load = function(){ var error, ajax, src, createAjax; if(obj.mode != 'disabled' && $.attr(track, 'src') && (src = $.prop(track, 'src'))){ $(mediaelem).off(loadEvents, load); if(!trackData.readyState){ error = function(){ trackData.readyState = 3; obj.cues = null; obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = null; $(track).triggerHandler('error'); }; trackData.readyState = 1; try { obj.cues = mediaelement.createCueList(); obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = mediaelement.createCueList(); createAjax = function(){ ajax = $.ajax({ dataType: 'text', url: src, success: function(text){ if(ajax.getResponseHeader('content-type') != 'text/vtt'){ webshims.error('set the mime-type of your WebVTT files to text/vtt. see: http://dev.w3.org/html5/webvtt/#text/vtt'); } mediaelement.parseCaptions(text, obj, function(cues){ if(cues && 'length' in cues){ trackData.readyState = 2; $(track).triggerHandler('load'); $(mediaelem).triggerHandler('updatetrackdisplay'); } else { error(); } }); }, error: error }); }; if($.ajax){ createAjax(); } else { webshims.ready('$ajax', createAjax); webshims.loader.loadList(['$ajax']); } } catch(er){ error(); webshims.error(er); } } } }; trackData.readyState = 0; obj.shimActiveCues = null; obj._shimActiveCues = null; obj.activeCues = null; obj.cues = null; $(mediaelem).off(loadEvents, load); $(mediaelem).on(loadEvents, load); if(_default){ obj.mode = showTracks[obj.kind] ? 'showing' : 'hidden'; load(); } }; mediaelement.createTextTrack = function(mediaelem, track){ var obj, trackData; if(track.nodeName){ trackData = webshims.data(track, 'trackData'); if(trackData){ refreshTrack(track, trackData); obj = trackData.track; } } if(!obj){ obj = createEventTarget(webshims.objectCreate(textTrackProto)); if(!supportTrackMod){ copyProps.forEach(function(copyProp){ var prop = $.prop(track, copyProp); if(prop){ obj[copyName[copyProp] || copyProp] = prop; } }); } if(track.nodeName){ if(supportTrackMod){ copyProps.forEach(function(copyProp){ webshims.defineProperty(obj, copyName[copyProp] || copyProp, { get: function(){ return $.prop(track, copyProp); } }); }); } obj.id = $(track).prop('id'); trackData = webshims.data(track, 'trackData', {track: obj}); mediaelement.loadTextTrack(mediaelem, track, trackData, isDefaultTrack(track)); } else { if(supportTrackMod){ copyProps.forEach(function(copyProp){ webshims.defineProperty(obj, copyName[copyProp] || copyProp, { value: track[copyProp], writeable: false }); }); } obj.cues = mediaelement.createCueList(); obj.activeCues = obj._shimActiveCues = obj.shimActiveCues = mediaelement.createCueList(); obj.mode = 'hidden'; obj.readyState = 2; } if(obj.kind == 'subtitles' && !obj.language){ webshims.error('you must provide a language for track in subtitles state'); } obj.__wsmode = obj.mode; } return obj; }; /* taken from: Captionator 0.5.1 [CaptionCrunch] Christopher Giffard, 2011 Share and enjoy https://github.com/cgiffard/Captionator modified for webshims */ mediaelement.parseCaptionChunk = (function(){ // Set up timestamp parsers var WebVTTTimestampParser = /^(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s+\-\-\>\s+(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s*(.*)/; var GoogleTimestampParser = /^([\d\.]+)\s+\+([\d\.]+)\s*(.*)/; var WebVTTDEFAULTSCueParser = /^(DEFAULTS|DEFAULT)\s+\-\-\>\s+(.*)/g; var WebVTTSTYLECueParser = /^(STYLE|STYLES)\s+\-\-\>\s*\n([\s\S]*)/g; var WebVTTCOMMENTCueParser = /^(COMMENT|COMMENTS)\s+\-\-\>\s+(.*)/g; return function(subtitleElement,objectCount){ var cueDefaults = []; var subtitleParts, timeIn, timeOut, html, timeData, subtitlePartIndex, cueSettings = "", id, specialCueData; var timestampMatch, tmpCue; // WebVTT Special Cue Logic if ((specialCueData = WebVTTDEFAULTSCueParser.exec(subtitleElement))) { // cueDefaults = specialCueData.slice(2).join(""); // cueDefaults = cueDefaults.split(/\s+/g).filter(function(def) { return def && !!def.length; }); return null; } else if ((specialCueData = WebVTTSTYLECueParser.exec(subtitleElement))) { return null; } else if ((specialCueData = WebVTTCOMMENTCueParser.exec(subtitleElement))) { return null; // At this stage, we don't want to do anything with these. } subtitleParts = subtitleElement.split(/\n/g); // Trim off any blank lines (logically, should only be max. one, but loop to be sure) while (!subtitleParts[0].replace(/\s+/ig,"").length && subtitleParts.length > 0) { subtitleParts.shift(); } if (subtitleParts[0].match(/^\s*[a-z0-9-\_]+\s*$/ig)) { // The identifier becomes the cue ID (when *we* load the cues from file. Programatically created cues can have an ID of whatever.) id = String(subtitleParts.shift().replace(/\s*/ig,"")); } for (subtitlePartIndex = 0; subtitlePartIndex < subtitleParts.length; subtitlePartIndex ++) { var timestamp = subtitleParts[subtitlePartIndex]; if ((timestampMatch = WebVTTTimestampParser.exec(timestamp))) { // WebVTT timeData = timestampMatch.slice(1); timeIn = parseInt((timeData[0]||0) * 60 * 60,10) + // Hours parseInt((timeData[1]||0) * 60,10) + // Minutes parseInt((timeData[2]||0),10) + // Seconds parseFloat("0." + (timeData[3]||0)); // MS timeOut = parseInt((timeData[4]||0) * 60 * 60,10) + // Hours parseInt((timeData[5]||0) * 60,10) + // Minutes parseInt((timeData[6]||0),10) + // Seconds parseFloat("0." + (timeData[7]||0)); // MS /* if (timeData[8]) { cueSettings = timeData[8]; } */ } // We've got the timestamp - return all the other unmatched lines as the raw subtitle data subtitleParts = subtitleParts.slice(0,subtitlePartIndex).concat(subtitleParts.slice(subtitlePartIndex+1)); break; } if (!timeIn && !timeOut) { // We didn't extract any time information. Assume the cue is invalid! webshims.warn("couldn't extract time information: "+[timeIn, timeOut, subtitleParts.join("\n"), id].join(' ; ')); return null; } /* // Consolidate cue settings, convert defaults to object var compositeCueSettings = cueDefaults .reduce(function(previous,current,index,array){ previous[current.split(":")[0]] = current.split(":")[1]; return previous; },{}); // Loop through cue settings, replace defaults with cue specific settings if they exist compositeCueSettings = cueSettings .split(/\s+/g) .filter(function(set) { return set && !!set.length; }) // Convert array to a key/val object .reduce(function(previous,current,index,array){ previous[current.split(":")[0]] = current.split(":")[1]; return previous; },compositeCueSettings); // Turn back into string like the TextTrackCue constructor expects cueSettings = ""; for (var key in compositeCueSettings) { if (compositeCueSettings.hasOwnProperty(key)) { cueSettings += !!cueSettings.length ? " " : ""; cueSettings += key + ":" + compositeCueSettings[key]; } } */ // The remaining lines are the subtitle payload itself (after removing an ID if present, and the time); html = subtitleParts.join("\n"); tmpCue = new TextTrackCue(timeIn, timeOut, html); if(id){ tmpCue.id = id; } return tmpCue; }; })(); mediaelement.parseCaptions = function(captionData, track, complete) { var subtitles = mediaelement.createCueList(); var cue, lazyProcess, regWevVTT; var startDate; var isWEBVTT; if (captionData) { regWevVTT = /^WEBVTT(\s*FILE)?/ig; lazyProcess = function(i, len){ for(; i < len; i++){ cue = captionData[i]; if(regWevVTT.test(cue)){ isWEBVTT = true; } else if(cue.replace(/\s*/ig,"").length){ if(!isWEBVTT){ webshims.error('please use WebVTT format. This is the standard'); complete(null); break; } cue = mediaelement.parseCaptionChunk(cue, i); if(cue){ track.addCue(cue); } } if(startDate < (new Date().getTime()) - 30){ i++; setTimeout(function(){ startDate = new Date().getTime(); lazyProcess(i, len); }, 90); break; } } if(i >= len){ if(!isWEBVTT){ webshims.error('please use WebVTT format. This is the standard'); } complete(track.cues); } }; captionData = captionData.replace(/\r\n/g,"\n"); setTimeout(function(){ captionData = captionData.replace(/\r/g,"\n"); setTimeout(function(){ startDate = new Date().getTime(); captionData = captionData.split(/\n\n+/g); lazyProcess(0, captionData.length); }, 9); }, 9); } else { webshims.error("Required parameter captionData not supplied."); } }; mediaelement.createTrackList = function(mediaelem, baseData){ baseData = baseData || webshims.data(mediaelem, 'mediaelementBase') || webshims.data(mediaelem, 'mediaelementBase', {}); if(!baseData.textTracks){ baseData.textTracks = []; webshims.defineProperties(baseData.textTracks, { onaddtrack: {value: null}, onremovetrack: {value: null}, onchange: {value: null}, getTrackById: { value: function(id){ var track = null; for(var i = 0; i < baseData.textTracks.length; i++){ if(id == baseData.textTracks[i].id){ track = baseData.textTracks[i]; break; } } return track; } } }); createEventTarget(baseData.textTracks); $(mediaelem).on('updatetrackdisplay', function(){ var track; for(var i = 0; i < baseData.textTracks.length; i++){ track = baseData.textTracks[i]; if(track.__wsmode != track.mode){ track.__wsmode = track.mode; $([ baseData.textTracks ]).triggerHandler('change'); } } }); } return baseData.textTracks; }; if(!Modernizr.track){ webshims.defineNodeNamesBooleanProperty(['track'], 'default'); webshims.reflectProperties(['track'], ['srclang', 'label']); webshims.defineNodeNameProperties('track', { src: { //attr: {}, reflect: true, propType: 'src' } }); } webshims.defineNodeNameProperties('track', { kind: { attr: Modernizr.track ? { set: function(value){ var trackData = webshims.data(this, 'trackData'); this.setAttribute('data-kind', value); if(trackData){ trackData.attrKind = value; } }, get: function(){ var trackData = webshims.data(this, 'trackData'); if(trackData && ('attrKind' in trackData)){ return trackData.attrKind; } return this.getAttribute('kind'); } } : {}, reflect: true, propType: 'enumarated', defaultValue: 'subtitles', limitedTo: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata'] } }); $.each(copyProps, function(i, copyProp){ var name = copyName[copyProp] || copyProp; webshims.onNodeNamesPropertyModify('track', copyProp, function(){ var trackData = webshims.data(this, 'trackData'); var track = this; if(trackData){ if(copyProp == 'kind'){ refreshTrack(this, trackData); } if(!supportTrackMod){ trackData.track[name] = $.prop(this, copyProp); } } }); }); webshims.onNodeNamesPropertyModify('track', 'src', function(val){ if(val){ var data = webshims.data(this, 'trackData'); var media; if(data){ media = $(this).closest('video, audio'); if(media[0]){ mediaelement.loadTextTrack(media, this, data); } } } }); // webshims.defineNodeNamesProperties(['track'], { ERROR: { value: 3 }, LOADED: { value: 2 }, LOADING: { value: 1 }, NONE: { value: 0 }, readyState: { get: function(){ return (webshims.data(this, 'trackData') || {readyState: 0}).readyState; }, writeable: false }, track: { get: function(){ return mediaelement.createTextTrack($(this).closest('audio, video')[0], this); }, writeable: false } }, 'prop'); webshims.defineNodeNamesProperties(['audio', 'video'], { textTracks: { get: function(){ var media = this; var baseData = webshims.data(media, 'mediaelementBase') || webshims.data(media, 'mediaelementBase', {}); var tracks = mediaelement.createTrackList(media, baseData); if(!baseData.blockTrackListUpdate){ updateMediaTrackList.call(media, baseData, tracks); } return tracks; }, writeable: false }, addTextTrack: { value: function(kind, label, lang){ var textTrack = mediaelement.createTextTrack(this, { kind: dummyTrack.prop('kind', kind || '').prop('kind'), label: label || '', srclang: lang || '' }); var baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {}); if (!baseData.scriptedTextTracks) { baseData.scriptedTextTracks = []; } baseData.scriptedTextTracks.push(textTrack); updateMediaTrackList.call(this); return textTrack; } } }, 'prop'); //wsmediareload var thUpdateList = function(e){ if($(e.target).is('audio, video')){ var baseData = webshims.data(e.target, 'mediaelementBase'); if(baseData){ clearTimeout(baseData.updateTrackListTimer); baseData.updateTrackListTimer = setTimeout(function(){ updateMediaTrackList.call(e.target, baseData); }, 0); } } }; var getNativeReadyState = function(trackElem, textTrack){ return textTrack.readyState || trackElem.readyState; }; var stopOriginalEvent = function(e){ if(e.originalEvent){ e.stopImmediatePropagation(); } }; var startTrackImplementation = function(){ if(webshims.implement(this, 'track')){ var shimedTrack = $.prop(this, 'track'); var origTrack = this.track; var kind; var readyState; if(origTrack){ kind = $.prop(this, 'kind'); readyState = getNativeReadyState(this, origTrack); if (origTrack.mode || readyState) { shimedTrack.mode = numericModes[origTrack.mode] || origTrack.mode; } //disable track from showing + remove UI if(kind != 'descriptions'){ origTrack.mode = (typeof origTrack.mode == 'string') ? 'disabled' : 0; this.kind = 'metadata'; $(this).attr({kind: kind}); } } $(this).on('load error', stopOriginalEvent); } }; webshims.addReady(function(context, insertedElement){ var insertedMedia = insertedElement.filter('video, audio, track').closest('audio, video'); $('video, audio', context) .add(insertedMedia) .each(function(){ updateMediaTrackList.call(this); }) .on('emptied updatetracklist wsmediareload', thUpdateList) .each(function(){ if(Modernizr.track){ var shimedTextTracks = $.prop(this, 'textTracks'); var origTextTracks = this.textTracks; if(shimedTextTracks.length != origTextTracks.length){ webshims.error("textTracks couldn't be copied"); } $('track', this).each(startTrackImplementation); } }) ; insertedMedia.each(function(){ var media = this; var baseData = webshims.data(media, 'mediaelementBase'); if(baseData){ clearTimeout(baseData.updateTrackListTimer); baseData.updateTrackListTimer = setTimeout(function(){ updateMediaTrackList.call(media, baseData); }, 9); } }); }); if(Modernizr.texttrackapi){ $('video, audio').trigger('trackapichange'); } });