From a5f917bbc55e295896b8084f6657eb8b6abaf8a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fabian=20Silva=20Delgado?= Date: Fri, 15 Jul 2016 15:33:36 -0300 Subject: Add TimedMediaHandler extension that allows display audio and video files in wiki pages, using the same syntax as for image files --- .../EmbedPlayer/resources/mw.MediaSource.js | 490 +++++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaSource.js (limited to 'extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaSource.js') diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaSource.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaSource.js new file mode 100644 index 00000000..9449a5d4 --- /dev/null +++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaSource.js @@ -0,0 +1,490 @@ +/** + * mediaSource class represents a source for a media element. + * + * @param {Element} + * element: MIME type of the source. + * @constructor + */ + +/** + * The base source attribute checks also see: + * http://dev.w3.org/html5/spec/Overview.html#the-source-element + */ + +( function( mw, $ ) { "use strict"; + +mw.mergeConfig( 'EmbedPlayer.SourceAttributes', [ + // source id + 'id', + + // media url + 'src', + + // Title string for the source asset + 'title', + + // boolean if we support temporal url requests on the source media + 'URLTimeEncoding', + + // Store the node name for type identification + 'nodeName', + + /** + * data- attributes ( not yet standards ) + */ + + // Media has a startOffset ( used for plugins that + // display ogg page time rather than presentation time + 'data-startoffset', + + // A hint to the duration of the media file so that duration + // can be displayed in the player without loading the media file + 'data-durationhint', + + // Source stream qualities + // NOTE data- is striped from the attribute as we build out the "mediaSource" object + 'data-shorttitle', // short title for stream ( useful for stream switching control bar widget) + 'data-width', // the width of the stream + 'data-height', // the height of the stream + 'data-bandwidth', // the overall bitrate of the stream in bytes + 'data-sizebytes', // the size of the stream in bytes + 'data-framerate', // the framereate of the stream + 'data-flavorid', // a source flavor id ( useful for targeting devices ) + 'data-aspect', // the aspect ratio, useful for adaptive protocal urls that don't have a strict height / width + + // Used as title in download panel + 'data-title', + + // Used for download attribute on mediawiki + 'data-mwtitle', + // used for setting the api provider for mediawiki + 'data-mwprovider', + + // to disable menu or timedText for a given embed + 'data-disablecontrols', + + // used for language direction of subtitles + 'data-dir', + + // Media start time + 'start', + + // Media end time + 'end', + + // If the source is the default source + 'default' +] ); + +mw.MediaSource = function( element ) { + this.init( element ); +}; + +mw.MediaSource.prototype = { + // MIME type of the source. + mimeType:null, + + // URI of the source. + uri:null, + + // Title of the source. + title: null, + + // True if the source has been marked as the default. + markedDefault: false, + + // True if the source supports url specification of offset and duration + URLTimeEncoding:false, + + // Start offset of the requested segment + startOffset: 0, + + // Duration of the requested segment (0 if not known) + duration:0, + + // source id + id: null, + + // Start time in npt format + startNpt: null, + + // End time in npt format + endNpt: null, + + // Language of the file + srclang: null, + /** + * MediaSource constructor: + */ + init : function( element ) { + var _this = this; + // mw.log('EmbedPlayer::adding mediaSource: ' + element); + this.src = $( element ).attr( 'src' ); + + // Set default URLTimeEncoding if we have a time url: + // not ideal way to discover if content is on an oggz_chop server. + // should check some other way. + var pUrl = new mw.Uri ( this.src ); + if ( typeof pUrl.query[ 't' ] != 'undefined' ) { + this.URLTimeEncoding = true; + } + + var sourceAttr = mw.config.get( 'EmbedPlayer.SourceAttributes' ); + $.each( sourceAttr, function( inx, attr ){ + if ( $( element ).attr( attr ) ) { + // strip data- from the attribute name + var attrName = ( attr.indexOf('data-') === 0) ? attr.substr(5) : attr + _this[ attrName ] = $( element ).attr( attr ); + } + }); + + // Normalize "label" to "title" ( label is the actual spec so use that over title ) + if( this.label ){ + this.title = this.label; + } + + // Set the content type: + if ( $( element ).attr( 'type' ) ) { + this.mimeType = $( element ).attr( 'type' ); + }else if ( $( element ).attr( 'content-type' ) ) { + this.mimeType = $( element ).attr( 'content-type' ); + }else if( $( element )[0].tagName.toLowerCase() == 'audio' ){ + // If the element is an "audio" tag set audio format + this.mimeType = 'audio/ogg'; + } else { + this.mimeType = this.detectType( this.src ); + } + + // Conform the mime type to ogg + if( this.mimeType == 'video/theora') { + this.mimeType = 'video/ogg'; + } + + if( this.mimeType == 'audio/vorbis') { + this.mimeType = 'audio/ogg'; + } + + // Check for parent elements ( supplies categories in "track" ) + if( $( element ).parent().attr('category') ) { + this.category = $( element ).parent().attr('category'); + } + + if( $( element ).attr( 'default' ) ){ + this.markedDefault = true; + } + + // Get the url duration ( if applicable ) + this.getURLDuration(); + }, + + /** + * Update Source title via Element + * + * @param {Element} + * element Source element to update attributes from + */ + updateSource: function( element ) { + // for now just update the title: + if ( $( element ).attr( "title" ) ) { + this.title = $( element ).attr( "title" ); + } + }, + + /** + * Updates the src time and start & end + * + * @param {String} + * start_time: in NPT format + * @param {String} + * end_time: in NPT format + */ + updateSrcTime: function ( startNpt, endNpt ) { + // mw.log("f:updateSrcTime: "+ startNpt+'/'+ endNpt + ' from org: ' + + // this.startNpt+ '/'+this.endNpt); + // mw.log("pre uri:" + this.src); + // if we have time we can use: + if ( this.URLTimeEncoding ) { + // make sure its a valid start time / end time (else set default) + if ( !mw.npt2seconds( startNpt ) ) { + startNpt = this.startNpt; + } + + if ( !mw.npt2seconds( endNpt ) ) { + endNpt = this.endNpt; + } + + this.src = mw.replaceUrlParams( this.src, { + 't': startNpt + '/' + endNpt + }); + + // update the duration + this.getURLDuration(); + } + }, + + /** + * Sets the duration and sets the end time if unset + * + * @param {Float} + * duration: in seconds + */ + setDuration: function ( duration ) { + this.duration = duration; + if ( !this.endNpt ) { + this.endNpt = mw.seconds2npt( this.startOffset + duration ); + } + }, + + /** + * MIME type accessor function. + * + * @return {String} the MIME type of the source. + */ + getMIMEType: function() { + if( this.mimeType ) { + return this.mimeType; + } + this.mimeType = this.detectType( this.src ); + return this.mimeType; + }, + /** + * Update the local src + * @param {String} + * src The URL to the media asset + */ + setSrc: function( src ){ + this.src = src; + }, + + /** + * URI function. + * + * @param {Number} + * serverSeekTime Int: Used to adjust the URI for url based + * seeks) + * @return {String} the URI of the source. + */ + getSrc: function( serverSeekTime ) { + if ( !serverSeekTime || !this.URLTimeEncoding ) { + return this.src; + } + var endvar = ''; + if ( this.endNpt ) { + endvar = '/' + this.endNpt; + } + return mw.replaceUrlParams( this.src, + { + 't': mw.seconds2npt( serverSeekTime ) + endvar + } + ); + }, + /** + * Title accessor function. + * + * @return {String} Title of the source. + */ + getTitle : function() { + if( this.title ){ + return this.title; + } + // Text tracks use "label" instead of "title" + if( this.label ){ + return this.label; + } + + // Return a Title based on mime type: + var mimeType = this.getMIMEType().split( ';' )[0]; + switch( mimeType ) { + case 'video/h264' : + case 'video/mp4' : + return mw.msg( 'mwe-embedplayer-video-h264' ); + break; + case 'video/x-flv' : + return mw.msg( 'mwe-embedplayer-video-flv' ); + break; + case 'video/webm' : + return mw.msg( 'mwe-embedplayer-video-webm'); + break; + case 'video/ogg' : + return mw.msg( 'mwe-embedplayer-video-ogg' ); + break; + case 'audio/ogg' : + return mw.msg( 'mwe-embedplayer-video-audio' ); + break; + case 'audio/mpeg' : + return mw.msg('mwe-embedplayer-audio-mpeg'); + break; + case 'video/3gp' : + return mw.msg('mwe-embedplayer-video-3gp'); + break; + case 'video/mpeg' : + return mw.msg('mwe-embedplayer-video-mpeg'); + break; + case 'video/x-msvideo' : + return mw.msg('mwe-embedplayer-video-msvideo' ); + break; + } + + // Return title based on file name: + try{ + var fileName = new mw.Uri( mw.absoluteUrl( this.getSrc() ) ).path.split('/').pop(); + if( fileName ){ + return fileName; + } + } catch(e){} + + // Return the mime type string if not known type. + return this.mimeType; + }, + /** + * Get a short title for the stream + */ + getShortTitle: function(){ + var _this =this; + if( this.shorttitle ){ + return this.shorttitle; + } + // Just use a short "long title" + var longTitle = this.getTitle(); + if(longTitle.length > 20) { + longTitle = longTitle.substring(0,17)+"..."; + } + return longTitle + }, + /** + * + * Get Duration of the media in milliseconds from the source url. + * + * Supports media_url?t=ntp_start/ntp_end url request format + */ + getURLDuration : function() { + // check if we have a URLTimeEncoding: + if ( this.URLTimeEncoding ) { + var annoURL = new mw.Uri( this.src ); + if ( annoURL.query.t ) { + var times = annoURL.query.t.split( '/' ); + this.startNpt = times[0]; + this.endNpt = times[1]; + this.startOffset = mw.npt2seconds( this.startNpt ); + this.duration = mw.npt2seconds( this.endNpt ) - this.startOffset; + } else { + // look for this info as attributes + if ( this.startOffset ) { + this.startNpt = mw.seconds2npt( this.startOffset ); + } + if ( this.duration ) { + this.endNpt = mw.seconds2npt( parseInt( this.duration ) + parseInt( this.startOffset ) ); + } + } + } + }, + /** + * Get the extension of a url + * @param String uri + */ + getExt : function( uri ){ + var urlParts = new mw.Uri( uri ); + // Get the extension from the url or from the relative name: + var ext = ( urlParts.file ) ? /[^.]+$/.exec( urlParts.file ) : /[^.]+$/.exec( uri ); + // remove the hash string if present + ext = /[^#]*/g.exec( ext.toString() ); + ext = ext || ''; + return ext.toString().toLowerCase(); + }, + /** + * Get the flavorId if available. + */ + getFlavorId: function(){ + if( this.flavorid ){ + return this.flavorid; + } + return ; + }, + + /** + * Attempts to detect the type of a media file based on the URI. + * + * @param {String} + * uri URI of the media file. + * @return {String} The guessed MIME type of the file. + */ + detectType: function( uri ) { + // NOTE: if media is on the same server as the javascript + // we can issue a HEAD request and read the mime type of the media... + // ( this will detect media mime type independently of the url name ) + // http://www.jibbering.com/2002/4/httprequest.html + switch( this.getExt( uri ) ) { + case 'smil': + case 'sml': + return 'application/smil'; + break; + case 'm4v': + case 'mp4': + return 'video/h264'; + break; + case 'm3u8': + return 'application/vnd.apple.mpegurl'; + break; + case 'webm': + return 'video/webm'; + break; + case '3gp': + return 'video/3gp'; + break; + case 'srt': + return 'text/x-srt'; + break; + case 'flv': + return 'video/x-flv'; + break; + case 'ogg': + case 'ogv': + return 'video/ogg'; + break; + case 'oga': + return 'audio/ogg'; + break; + case 'mp3': + return 'audio/mpeg'; + case 'm4a': + return 'audio/mp4'; + break; + case 'anx': + return 'video/ogg'; + break; + case 'xml': + return 'text/xml'; + break; + case 'avi': + return 'video/x-msvideo'; + break; + case 'mpg': + return 'video/mpeg'; + break; + case 'mpeg': + return 'video/mpeg'; + break; + } + mw.log( "Error: could not detect type of media src: " + uri ); + }, + /** + * bitrate is mesured in kbs rather than bandwith bytes per second + */ + getBitrate: function() { + if( this.bandwidth ){ + return this.bandwidth / 1024; + } + return 0; + }, + /** + * Get the size of the stream in bytes + */ + getSize: function(){ + if( this.sizebytes ){ + return this.sizebytes; + } + return 0; + } +}; + +} )( mediaWiki, jQuery ); -- cgit v1.2.2