Index: trunk/extensions/OggHandler/OggHandler.php
===================================================================
--- trunk/extensions/OggHandler/OggHandler.php (revision 25466)
+++ trunk/extensions/OggHandler/OggHandler.php (revision 25467)
@@ -22,6 +22,7 @@
$wgFFmpegLocation = 'ffmpeg';
$wgExtensionMessagesFiles['OggHandler'] = "$oggDir/OggHandler.i18n.php";
$wgParserOutputHooks['OggHandler'] = array( 'OggHandler', 'outputHook' );
+$wgHooks['LanguageGetMagic'][] = 'OggHandler::registerMagicWords';
// Filename or URL path to the Cortado Java player applet.
//
Index: trunk/extensions/OggHandler/pause.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/OggHandler/pause.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Index: trunk/extensions/OggHandler/OggPlayer.js
===================================================================
--- trunk/extensions/OggHandler/OggPlayer.js (revision 25466)
+++ trunk/extensions/OggHandler/OggPlayer.js (revision 25467)
@@ -13,21 +13,24 @@
// Configuration from MW
'msg': {},
'cortadoUrl' : '',
- 'smallFileUrl' : '',
+ 'extPathUrl' : '',
'showPlayerSelect': true,
'controlsHeightGuess': 20,
- // Main entry point: initialise a video player
- // Player will be created as a child of the given ID
- // There may be multiple players in a document
- 'init': function ( player, id, videoUrl, width, height, length, linkUrl ) {
- elt = document.getElementById( id );
+ /**
+ * Main entry point: initialise a video player
+ * Player will be created as a child of the given ID
+ * There may be multiple players in a document.
+ * Parameters are: id, videoUrl, width, height, length, linkUrl
+ */
+ 'init': function ( player, params ) {
+ elt = document.getElementById( params.id );
// Save still image HTML
- if ( !(id in this.savedThumbs) ) {
+ if ( !(params.id in this.savedThumbs) ) {
var thumb = document.createDocumentFragment();
thumb.appendChild( elt.cloneNode( true ) );
- this.savedThumbs[id] = thumb;
+ this.savedThumbs[params.id] = thumb;
}
this.detect( elt );
@@ -62,40 +65,41 @@
switch ( player ) {
case 'videoElement':
- this.embedVideoElement( elt, videoUrl, width, height, length );
+ this.embedVideoElement( elt, params );
break;
case 'oggPlugin':
- this.embedOggPlugin( elt, videoUrl, width, height, length );
+ this.embedOggPlugin( elt, params );
break;
case 'vlc-mozilla':
- this.embedVlcPlugin( elt, videoUrl, width, height, length );
+ this.embedVlcPlugin( elt, params );
break;
case 'vlc-activex':
- this.embedVlcActiveX( elt, videoUrl, width, height, length );
+ this.embedVlcActiveX( elt, params );
break;
case 'cortado':
- this.embedCortado( elt, videoUrl, width, height, length );
+ this.embedCortado( elt, params );
break;
case 'quicktime-mozilla':
- this.embedQuicktimePlugin( elt, videoUrl, width, height, length );
+ this.embedQuicktimePlugin( elt, params );
break;
case 'thumbnail':
- if ( id in this.savedThumbs ) {
- elt.appendChild( this.savedThumbs[id].cloneNode( true ) );
+ if ( params.id in this.savedThumbs ) {
+ elt.appendChild( this.savedThumbs[params.id].cloneNode( true ) );
} else {
- elt.appendChild( document.createTextNode( 'Missing saved thumbnail for ' + id ) );
+ elt.appendChild( document.createTextNode( 'Missing saved thumbnail for ' + params.id ) );
}
break;
default:
- elt.innerHTML = this.msg['ogg-no-player'] + '<br/>';
+ elt.innerHTML = '<div>' + this.msg['ogg-no-player'] + '</div>';
player = 'none';
}
if ( player != 'thumbnail' ) {
- var optionsBox = this.makeOptionsBox( player, id, videoUrl, width, height, length, linkUrl );
- var optionsLink = this.makeOptionsLink( id );
- elt.appendChild( document.createElement( 'br' ) );
- elt.appendChild( optionsBox );
- elt.appendChild( optionsLink );
+ var optionsBox = this.makeOptionsBox( player, params );
+ var optionsLink = this.makeOptionsLink( params.id );
+ var div = document.createElement( 'div' );
+ div.appendChild( optionsBox );
+ div.appendChild( optionsLink );
+ elt.appendChild( div );
}
},
@@ -197,22 +201,22 @@
}
},
- 'makeOptionsBox' : function ( selectedPlayer, id, videoUrl, width, height, length, linkUrl ) {
+ 'makeOptionsBox' : function ( selectedPlayer, params ) {
var div, p, a, ul, li, button;
div = document.createElement( 'div' );
- div.style.cssText = "width: " + ( width - 10 ) + "px; display: none;";
+ div.style.cssText = "width: " + ( params.width - 10 ) + "px; display: none;";
div.className = 'ogg-player-options';
- div.id = id + '_options_box';
+ div.id = params.id + '_options_box';
div.align = 'center';
ul = document.createElement( 'ul' );
// Description page link
- if ( linkUrl ) {
+ if ( params.linkUrl ) {
li = document.createElement( 'li' );
a = document.createElement( 'a' );
- a.href = linkUrl;
+ a.href = params.linkUrl;
a.appendChild( document.createTextNode( this.msg['ogg-desc-link'] ) );
li.appendChild( a );
ul.appendChild( li );
@@ -221,7 +225,7 @@
// Download link
li = document.createElement( 'li' );
a = document.createElement( 'a' );
- a.href = videoUrl;
+ a.href = params.videoUrl;
a.appendChild( document.createTextNode( this.msg['ogg-download'] ) );
li.appendChild( a );
ul.appendChild( li );
@@ -236,15 +240,21 @@
// Make player list
ul = document.createElement( 'ul' );
for ( var i = 0; i < this.players.length + 1; i++ ) {
- var player;
+ var player, playerMsg;
if ( i == this.players.length ) {
player = 'thumbnail';
+ if ( params.isVideo ) {
+ playerMsg = 'ogg-player-thumbnail';
+ } else {
+ playerMsg = 'ogg-player-soundthumb';
+ }
} else {
player = this.players[i];
// Skip unsupported players
if ( ! this.clientSupports[player] ) {
continue;
}
+ playerMsg = 'ogg-player-' + player;
}
// Make list item
@@ -252,13 +262,13 @@
if ( player == selectedPlayer ) {
var strong = document.createElement( 'strong' );
strong.appendChild( document.createTextNode(
- this.msg['ogg-player-' + player] + ' ' + this.msg['ogg-player-selected'] ) );
+ this.msg[playerMsg] + ' ' + this.msg['ogg-player-selected'] ) );
li.appendChild( strong );
} else {
a = document.createElement( 'a' );
a.href = 'javascript:void("' + player + '")';
- a.onclick = this.makePlayerFunction( player, id, videoUrl, width, height, length, linkUrl );
- a.appendChild( document.createTextNode( this.msg['ogg-player-' + player] ) );
+ a.onclick = this.makePlayerFunction( player, params );
+ a.appendChild( document.createTextNode( this.msg[playerMsg] ) );
li.appendChild( a );
}
ul.appendChild( li );
@@ -269,7 +279,7 @@
div2.style.cssText = 'text-align: center;';
button = document.createElement( 'button' );
button.appendChild( document.createTextNode( this.msg['ogg-dismiss'] ) );
- button.onclick = this.makeDismissFunction( id );
+ button.onclick = this.makeDismissFunction( params.id );
div2.appendChild( button );
div.appendChild( div2 );
@@ -319,165 +329,172 @@
}
},
- 'makePlayerFunction' : function ( player, id, videoUrl, width, height, length, linkUrl ) {
+ 'makePlayerFunction' : function ( player, params ) {
var this_ = this;
return function () {
if ( player != 'thumbnail' ) {
document.cookie = "ogg_player=" + player;
}
- this_.init( player, id, videoUrl, width, height, length, linkUrl );
+ this_.init( player, params );
};
},
- 'newButton': function ( caption, callback ) {
+ 'newButton': function ( caption, image, callback ) {
var elt = document.createElement('input');
- elt.type = 'button';
- elt.value = this.msg[caption];
+ elt.type = 'image';
+ elt.src = this.extPathUrl + '/' + image;
+ elt.alt = elt.value = elt.title = this.msg[caption];
elt.onclick = callback;
return elt;
},
'newPlayButton': function ( videoElt ) {
- return this.newButton( 'ogg-play', function () { videoElt.play(); } );
+ return this.newButton( 'ogg-play', 'play.png', function () { videoElt.play(); } );
},
'newPauseButton': function ( videoElt ) {
- return this.newButton( 'ogg-pause', function () { videoElt.pause(); } );
+ return this.newButton( 'ogg-pause', 'pause.png', function () { videoElt.pause(); } );
},
'newStopButton': function ( videoElt ) {
- return this.newButton( 'ogg-stop', function () { videoElt.stop(); } );
+ return this.newButton( 'ogg-stop', 'stop.png', function () { videoElt.stop(); } );
},
- 'embedVideoElement': function ( elt, videoUrl, width, height, length ) {
+ 'embedVideoElement': function ( elt, params ) {
var videoElt = document.createElement('video');
- videoElt.setAttribute( 'width', width );
- videoElt.setAttribute( 'height', height + this.controlsHeightGuess );
- videoElt.setAttribute( 'src', videoUrl );
+ videoElt.setAttribute( 'width', params.width );
+ videoElt.setAttribute( 'height', params.height + this.controlsHeightGuess );
+ videoElt.setAttribute( 'src', params.videoUrl );
videoElt.setAttribute( 'autoplay', '1' );
videoElt.setAttribute( 'controls', '1' );
- elt.appendChild( videoElt );
+ var div = document.createElement( 'div' );
+ div.appendChild( videoElt );
+ elt.appendChild( div );
// Try to detect implementations that don't support controls
// This works for the Opera test build
if ( !videoElt.controls ) {
- elt.appendChild( document.createElement( 'br' ) );
- elt.appendChild( this.newPlayButton( videoElt ) );
- elt.appendChild( this.newPauseButton( videoElt ) );
- elt.appendChild( this.newStopButton( videoElt ) );
+ div = document.createElement( 'div' );
+ div.appendChild( this.newPlayButton( videoElt ) );
+ div.appendChild( this.newPauseButton( videoElt ) );
+ div.appendChild( this.newStopButton( videoElt ) );
+ elt.appendChild( div );
//videoElt.play();
}
},
- 'embedOggPlugin': function ( elt, videoUrl, width, height, length ) {
+ 'embedOggPlugin': function ( elt, params ) {
var id = elt.id + "_obj";
elt.innerHTML +=
- "<object id=" + this.hq( id ) +
+ "<div><object id=" + this.hq( id ) +
" type='application/ogg'" +
- " width=" + this.hq( width ) +
- " height=" + this.hq( height + this.controlsHeightGuess ) +
- " data=" + this.hq( videoUrl ) + "></object>";
+ " width=" + this.hq( params.width ) +
+ " height=" + this.hq( params.height + this.controlsHeightGuess ) +
+ " data=" + this.hq( params.videoUrl ) + "></object></div>";
},
- 'embedVlcPlugin' : function ( elt, videoUrl, width, height, length ) {
+ 'embedVlcPlugin' : function ( elt, params ) {
var id = elt.id + "_obj";
elt.innerHTML +=
- "<object id=" + this.hq( id ) +
+ "<div><object id=" + this.hq( id ) +
" type='application/x-vlc-plugin'" +
- " width=" + this.hq( width ) +
- " height=" + this.hq( height ) +
- " data=" + this.hq( videoUrl ) + "></object>";
+ " width=" + this.hq( params.width ) +
+ " height=" + this.hq( params.height ) +
+ " data=" + this.hq( params.videoUrl ) + "></object></div>";
var videoElt = document.getElementById( id );
- elt.appendChild( document.createElement( 'br' ) );
+ var div = document.createElement( 'div' );
// TODO: seek bar
- elt.appendChild( this.newPlayButton( videoElt ) );
- elt.appendChild( this.newPauseButton( videoElt ) );
- elt.appendChild( this.newStopButton( videoElt ) );
+ div.appendChild( this.newPlayButton( videoElt ) );
+ div.appendChild( this.newPauseButton( videoElt ) );
+ div.appendChild( this.newStopButton( videoElt ) );
+ elt.appendChild( div );
},
- 'embedVlcActiveX' : function ( elt, videoUrl, width, height, length ) {
+ 'embedVlcActiveX' : function ( elt, params ) {
var id = elt.id + "_obj";
var html =
- '<object id=' + this.hq( id ) +
+ '<div><object id=' + this.hq( id ) +
' classid="clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921"' +
' codebase="http://downloads.videolan.org/pub/videolan/vlc/latest/win32/axvlc.cab#Version=0,8,6,0"' +
- ' width=' + this.hq( width ) +
- ' height=' + this.hq( height ) +
- ' style="width: ' + this.hx( width ) + 'px; height: ' + this.hx( height ) + 'px;"' +
+ ' width=' + this.hq( params.width ) +
+ ' height=' + this.hq( params.height ) +
+ ' style="width: ' + this.hx( params.width ) + 'px; height: ' + this.hx( params.height ) + 'px;"' +
">" +
- '<param name="mrl" value=' + this.hq( videoUrl ) + '/>' +
- '</object>';
+ '<param name="mrl" value=' + this.hq( params.videoUrl ) + '/>' +
+ '</object></div>';
elt.innerHTML += html;
var videoElt = document.getElementById( id );
// IE says "sorry, I wasn't listening, what were the dimensions again?"
- if ( width && height ) {
- videoElt.width = width;
- videoElt.height = height;
- videoElt.style.width = width + 'px';
- videoElt.style.height = height + 'px';
+ if ( params.width && params.height ) {
+ videoElt.width = params.width;
+ videoElt.height = params.height;
+ videoElt.style.width = params.width + 'px';
+ videoElt.style.height = params.height + 'px';
}
-
- elt.appendChild( document.createElement( 'br' ) );
+ var div = document.createElement( 'div' );
// TODO: seek bar
- elt.appendChild( this.newButton( 'ogg-play', function() { videoElt.playlist.play(); } ) );
+ div.appendChild( this.newButton( 'ogg-play', 'play.png', function() { videoElt.playlist.play(); } ) );
// FIXME: playlist.pause() doesn't work
- elt.appendChild( this.newButton( 'ogg-stop', function() { videoElt.playlist.stop(); } ) );
+ div.appendChild( this.newButton( 'ogg-stop', 'stop.png', function() { videoElt.playlist.stop(); } ) );
+ elt.appendChild( div );
},
- 'embedCortado' : function ( elt, videoUrl, width, height, length ) {
+ 'embedCortado' : function ( elt, params ) {
var statusHeight = 18;
// Given extra vertical space, cortado centres the video and then overlays the status
// line, leaving an ugly black bar at the top. So we don't give it any.
- var playerHeight = height < statusHeight ? statusHeight : height;
+ var playerHeight = params.height < statusHeight ? statusHeight : params.height;
// Create the applet all at once
// In Opera, document.createElement('applet') immediately creates
// a non-working applet with unchangeable parameters, similar to the
// problem with IE and ActiveX.
- elt.innerHTML =
+ elt.innerHTML = '<div>' +
'<applet code="com.fluendo.player.Cortado.class" ' +
- ' width=' + this.hq( width ) +
+ ' width=' + this.hq( params.width ) +
' height=' + this.hq( playerHeight ) +
' archive=' + this.hq( this.cortadoUrl ) + '>' +
- ' <param name="url" value=' + this.hq( videoUrl ) + '/>' +
- ' <param name="duration" value=' + this.hq( length ) + '/>' +
+ ' <param name="url" value=' + this.hq( params.videoUrl ) + '/>' +
+ ' <param name="duration" value=' + this.hq( params.length ) + '/>' +
' <param name="seekable" value="true"/>' +
' <param name="autoPlay" value="true"/>' +
' <param name="showStatus" value="show"/>' +
' <param name="statusHeight" value="' + statusHeight + '"/>' +
- '</applet>';
+ '</applet>' +
+ '</div>';
// Disable autoPlay in the DOM right now, to prevent Mozilla from
// restarting an arbitrary number of applet instances on a back button click.
// Unfortunately this means that some clients (e.g. Opera) won't autoplay at all
- var videoElt = elt.getElementsByTagName( 'applet' )[0];
+ var videoElt = elt.getElementsByTagName( 'div' ) [0] .
+ getElementsByTagName( 'applet' )[0];
this.setParam( videoElt, 'autoPlay', '' );
},
- 'embedQuicktimePlugin': function ( elt, videoUrl, width, height, length ) {
+ 'embedQuicktimePlugin': function ( elt, params ) {
var id = elt.id + "_obj";
var controllerHeight = 16; // by observation
elt.innerHTML +=
- "<object id=" + this.hq( id ) +
+ "<div><object id=" + this.hq( id ) +
" type='video/quicktime'" +
- " width=" + this.hq( width ) +
- " height=" + this.hq( height + controllerHeight ) +
+ " width=" + this.hq( params.width ) +
+ " height=" + this.hq( params.height + controllerHeight ) +
// Use QTSRC parameter instead of data attribute to allow progressive download
// The data attribute and src parameter point to a small file, as recommended in
// http://developer.apple.com/documentation/QuickTime/Conceptual/QTScripting_HTML/QTScripting_HTML_Document/chapter_1000_section_6.html
- " data=" + this.hq( this.smallFileUrl ) +
+ " data=" + this.hq( this.extPathUrl + '/null_file' ) +
">" +
// Scale, don't clip
"<param name='SCALE' value='Aspect'/>" +
"<param name='AUTOPLAY' value='True'/>" +
- "<param name='src' value=" + this.hq( this.smallFileUrl ) + "/>" +
- "<param name='QTSRC' value=" + this.hq( videoUrl ) + "/>" +
- "</object>";
+ "<param name='src' value=" + this.hq( this.extPathUrl + '/null_file' ) + "/>" +
+ "<param name='QTSRC' value=" + this.hq( params.videoUrl ) + "/>" +
+ "</object></div>";
// Disable autoplay on back button
var this_ = this;
Index: trunk/extensions/OggHandler/play.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/OggHandler/play.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Index: trunk/extensions/OggHandler/stop.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/OggHandler/stop.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Index: trunk/extensions/OggHandler/OggHandler_body.php
===================================================================
--- trunk/extensions/OggHandler/OggHandler_body.php (revision 25466)
+++ trunk/extensions/OggHandler/OggHandler_body.php (revision 25467)
@@ -1,8 +1,12 @@
<?php
+// TODO: Fix core printable stylesheet. Descendant selectors suck.
+
class OggHandler extends MediaHandler {
const OGG_METADATA_VERSION = 1;
+ static $magicDone = false;
+
var $videoTypes = array( 'Theora' );
var $audioTypes = array( 'Vorbis', 'Speex', 'FLAC' );
@@ -10,36 +14,80 @@
return true;
}
+ static function registerMagicWords( &$magicData, $code ) {
+ wfLoadExtensionMessages( 'OggHandler' );
+ return true;
+ }
+
function getParamMap() {
- // TODO: add thumbtime, noplayer
- return array( 'img_width' => 'width' );
+ wfLoadExtensionMessages( 'OggHandler' );
+ return array(
+ 'img_width' => 'width',
+ 'ogg_noplayer' => 'noplayer',
+ 'ogg_thumbtime' => 'thumbtime',
+ );
}
function validateParam( $name, $value ) {
- // TODO
+ if ( $name == 'thumbtime' ) {
+ if ( $this->parseTimeString( $value ) === false ) {
+ return false;
+ }
+ }
return true;
}
+ function parseTimeString( $seekString, $length = false ) {
+ $parts = explode( ':', $seekString );
+ $time = 0;
+ for ( $i = 0; $i < count( $parts ); $i++ ) {
+ if ( !is_numeric( $parts[$i] ) ) {
+ return false;
+ }
+ $time += intval( $parts[$i] ) * pow( 60, count( $parts ) - $i - 1 );
+ }
+
+ if ( $time < 0 ) {
+ wfDebug( __METHOD__.": specified negative time, using zero\n" );
+ $time = 0;
+ } elseif ( $length !== false && $time > $length - 1 ) {
+ wfDebug( __METHOD__.": specified near-end or past-the-end time {$time}s, using end minus 1s\n" );
+ $time = $length - 1;
+ }
+ return $time;
+ }
+
function makeParamString( $params ) {
- // No parameters just yet, the thumbnails are always full-size
- return '';
- /*
- $s = '';
- foreach ( $params as $name => $value ) {
- if ( $s !== '' ) {
- $s .= '-';
+ if ( isset( $params['thumbtime'] ) ) {
+ $time = $this->parseTimeString( $params['thumbtime'] );
+ if ( $time !== false ) {
+ return 'seek=' . $time;
}
- $s .= "$name=$value";
- }*/
+ }
+ return 'mid';
}
function parseParamString( $str ) {
- // TODO
+ $m = false;
+ if ( preg_match( '/^seek=(\d+)$/', $str, $m ) ) {
+ return array( 'thumbtime' => $m[0] );
+ }
return array();
}
function normaliseParams( $image, &$params ) {
- // TODO
+ if ( isset( $params['thumbtime'] ) ) {
+ $length = $this->getLength( $image );
+ $time = $this->parseTimeString( $params['thumbtime'] );
+ if ( $time === false ) {
+ return false;
+ } elseif ( $time > $length - 1 ) {
+ $params['thumbtime'] = $length - 1;
+ } elseif ( $time <= 0 ) {
+ $params['thumbtime'] = 0;
+ }
+ }
+
return true;
}
@@ -124,32 +172,52 @@
function doTransform( $file, $dstPath, $dstUrl, $params, $flags = 0 ) {
global $wgFFmpegLocation;
- // Hack for miscellaneous callers
- global $wgOut;
- $this->setHeaders( $wgOut );
-
$width = $params['width'];
$srcWidth = $file->getWidth();
$srcHeight = $file->getHeight();
$height = $srcWidth == 0 ? $srcHeight : $width * $srcHeight / $srcWidth;
$length = $this->getLength( $file );
+ $noPlayer = isset( $params['noplayer'] );
+ if ( !$noPlayer ) {
+ // Hack for miscellaneous callers
+ global $wgOut;
+ $this->setHeaders( $wgOut );
+ }
+
if ( $srcHeight == 0 || $srcWidth == 0 ) {
// Make audio player
- $icon = $file->iconThumb();
+ if ( $noPlayer ) {
+ $scriptPath = self::getMyScriptPath();
+ return new ThumbnailImage( $file, "$scriptPath/info.png", 22, 22 );
+ }
if ( empty( $params['width'] ) ) {
$width = 200;
} else {
$width = $params['width'];
}
- $height = $icon->getHeight();
- return new OggAudioDisplay( $file, $file->getURL(), $icon->getUrl(), $width, $height, $length );
+ $height = empty( $params['height'] ) ? 20 : $params['height'];
+ return new OggAudioDisplay( $file, $file->getURL(), $width, $height, $length );
}
+ // Video thumbnail only
+ if ( $noPlayer ) {
+ return new ThumbnailImage( $file, $dstUrl, $width, $height, $dstPath );
+ }
+
if ( $flags & self::TRANSFORM_LATER ) {
return new OggVideoDisplay( $file, $file->getURL(), $dstUrl, $width, $height, $length );
}
+ $thumbTime = false;
+ if ( isset( $params['thumbtime'] ) ) {
+ $thumbTime = $this->parseTimeString( $params['thumbtime'], $length );
+ }
+ if ( $thumbTime === false ) {
+ # Seek to midpoint by default, it tends to be more interesting than the start
+ $thumbTime = $length / 2;
+ }
+
wfMkdirParents( dirname( $dstPath ) );
wfDebug( "Creating video thumbnail at $dstPath\n" );
@@ -159,14 +227,13 @@
# MJPEG, that's the same as JPEG except it's supported by the windows build of ffmpeg
# No audio, one frame
' -f mjpeg -an -vframes 1' .
- # Seek to midpoint, it tends to be more interesting than the fade in at the start
- ' -ss ' . intval( $length / 2 ) . ' ' .
+ ' -ss ' . intval( $thumbTime ) . ' ' .
wfEscapeShellArg( $dstPath ) . ' 2>&1';
$retval = 0;
$returnText = wfShellExec( $cmd, $retval );
- if ( $retval ) {
+ if ( $this->removeBadFile( $dstPath, $retval ) || $retval ) {
// Filter nonsense
$lines = explode( "\n", str_replace( "\r\n", "\n", $returnText ) );
if ( substr( $lines[0], 0, 6 ) == 'FFmpeg' ) {
@@ -308,8 +375,13 @@
}
}
+ static function getMyScriptPath() {
+ global $wgScriptPath;
+ return "$wgScriptPath/extensions/OggHandler";
+ }
+
function setHeaders( $out ) {
- global $wgScriptPath, $wgOggScriptVersion, $wgCortadoJarFile;
+ global $wgOggScriptVersion, $wgCortadoJarFile;
if ( $out->hasHeadItem( 'OggHandler' ) ) {
return;
}
@@ -320,23 +392,24 @@
'ogg-player-videoElement', 'ogg-player-oggPlugin', 'ogg-player-cortado', 'ogg-player-vlc-mozilla',
'ogg-player-vlc-activex', 'ogg-player-quicktime-mozilla', 'ogg-player-quicktime-activex',
'ogg-player-thumbnail', 'ogg-player-selected', 'ogg-use-player', 'ogg-more', 'ogg-download',
- 'ogg-desc-link', 'ogg-dismiss' );
+ 'ogg-desc-link', 'ogg-dismiss', 'ogg-player-soundthumb' );
$msgValues = array_map( 'wfMsg', $msgNames );
$jsMsgs = Xml::encodeJsVar( (object)array_combine( $msgNames, $msgValues ) );
$cortadoUrl = $wgCortadoJarFile;
+ $scriptPath = self::getMyScriptPath();
if( substr( $cortadoUrl, 0, 1 ) != '/'
&& substr( $cortadoUrl, 0, 4 ) != 'http' ) {
- $cortadoUrl = "$wgScriptPath/extensions/OggHandler/$cortadoUrl";
+ $cortadoUrl = "$scriptPath/$cortadoUrl";
}
$encCortadoUrl = Xml::encodeJsVar( $cortadoUrl );
- $encSmallFileUrl = Xml::encodeJsVar( "$wgScriptPath/extensions/OggHandler/null_file" );
+ $encExtPathUrl = Xml::encodeJsVar( $scriptPath );
$out->addHeadItem( 'OggHandler', <<<EOT
-<script type="text/javascript" src="$wgScriptPath/extensions/OggHandler/OggPlayer.js?$wgOggScriptVersion"></script>
+<script type="text/javascript" src="$scriptPath/OggPlayer.js?$wgOggScriptVersion"></script>
<script type="text/javascript">
wgOggPlayer.msg = $jsMsgs;
wgOggPlayer.cortadoUrl = $encCortadoUrl;
-wgOggPlayer.smallFileUrl = $encSmallFileUrl;
+wgOggPlayer.extPathUrl = $encExtPathUrl;
</script>
<style type="text/css">
.ogg-player-options {
@@ -390,47 +463,110 @@
if ( substr( $this->videoUrl, 0, 4 ) != 'http' ) {
global $wgServer;
- $encUrl = Xml::encodeJsVar( $wgServer . $this->videoUrl );
+ $url = $wgServer . $this->videoUrl;
} else {
- $encUrl = Xml::encodeJsVar( $this->videoUrl );
+ $url = $this->videoUrl;
}
$length = intval( $this->length );
$width = intval( $this->width );
$height = intval( $this->height );
- $alt = empty( $options['alt'] ) ? '' : $options['alt'];
- $attribs = array( 'src' => $this->url );
+ $alt = empty( $options['alt'] ) ? $this->file->getTitle()->getText() : $options['alt'];
+ $scriptPath = OggHandler::getMyScriptPath();
+ $thumbDivAttribs = array();
+ $showDescIcon = false;
if ( $this->isVideo ) {
$msgStartPlayer = wfMsg( 'ogg-play-video' );
- $attribs['width'] = $width;
- $attribs['height'] = $height;
+ $imgAttribs = array(
+ 'src' => $this->url,
+ 'width' => $width,
+ 'height' => $height );
$playerHeight = $height;
} else {
+ // Sound file
+ if ( $height > 100 ) {
+ // Use a big file icon
+ global $wgScriptPath;
+ $imgAttribs = array(
+ 'src' => "$wgScriptPath/skins/common/images/icons/fileicon-ogg.png",
+ 'width' => 125,
+ 'height' => 125,
+ );
+ } else {
+ // make an icon later if necessary
+ $imgAttribs = false;
+ $showDescIcon = true;
+ //$thumbDivAttribs = array( 'style' => 'text-align: right;' );
+ }
$msgStartPlayer = wfMsg( 'ogg-play-sound' );
$playerHeight = 0;
- // Don't add width and height to the icon image, it won't match its true size
}
- $thumb = Xml::element( 'img', $attribs, null );
+ // Set $thumb to the thumbnail img tag, or the thing that goes where
+ // the thumbnail usually goes
+ $descIcon = false;
if ( !empty( $options['desc-link'] ) ) {
$linkAttribs = $this->getDescLinkAttribs( $alt );
- $thumb = Xml::tags( 'a', $linkAttribs, $thumb );
- $encLink = Xml::encodeJsVar( $linkAttribs['href'] );
+ if ( $showDescIcon ) {
+ // Make image description icon link
+ $imgAttribs = array(
+ 'src' => "$scriptPath/info.png",
+ 'width' => 22,
+ 'height' => 22
+ );
+ $linkAttribs['title'] = wfMsg( 'ogg-desc-link' );
+ $descIcon = Xml::tags( 'a', $linkAttribs,
+ Xml::element( 'img', $imgAttribs, null ) );
+ $thumb = '';
+ } else {
+ $thumb = Xml::tags( 'a', $linkAttribs,
+ Xml::element( 'img', $imgAttribs, null ) );
+ }
+ $linkUrl = $linkAttribs['href'];
} else {
// We don't respect the file-link option, click-through to download is not appropriate
- $encLink = 'false';
+ $linkUrl = false;
+ if ( $imgAttribs ) {
+ $thumb = Xml::element( 'img', $imgAttribs, null );
+ } else {
+ $thumb = '';
+ }
}
- $thumb .= "<br/>\n";
$id = "ogg_player_" . OggTransformOutput::$serial;
- $s = Xml::tags( 'div', array( 'id' => $id, /*'align' => 'center',*/ 'style' => 'width: ' . $width . 'px' ),
- $thumb .
- Xml::element( 'button',
- array(
- 'onclick' => "wgOggPlayer.init(false, '$id', $encUrl, $width, $playerHeight, $length, $encLink);",
- ),
- $msgStartPlayer
- )
+ $playerParams = Xml::encodeJsVar( (object)array(
+ 'id' => $id,
+ 'videoUrl' => $url,
+ 'width' => $width,
+ 'height' => $playerHeight,
+ 'length' => $length,
+ 'linkUrl' => $linkUrl,
+ 'isVideo' => $this->isVideo ) );
+
+ $s = Xml::tags( 'div',
+ array(
+ 'id' => $id,
+ 'style' => "width: {$width}px;" ),
+ ( $thumb ? Xml::tags( 'div', array(), $thumb ) : '' ) .
+ Xml::tags( 'div', array(),
+ Xml::tags( 'button',
+ array(
+ 'onclick' => "wgOggPlayer.init(false, $playerParams);",
+ 'style' => "width: {$width}px;",
+ 'title' => $msgStartPlayer,
+ ),
+ Xml::element( 'img',
+ array(
+ 'src' => "$scriptPath/play.png",
+ 'width' => 22,
+ 'height' => 22,
+ 'alt' => $msgStartPlayer
+ ),
+ null
+ )
+ )
+ ) .
+ ( $descIcon ? Xml::tags( 'div', array(), $descIcon ) : '' )
);
return $s;
}
@@ -443,8 +579,8 @@
}
class OggAudioDisplay extends OggTransformOutput {
- function __construct( $file, $videoUrl, $iconUrl, $width, $height, $length ) {
- parent::__construct( $file, $videoUrl, $iconUrl, $width, $height, $length, false );
+ function __construct( $file, $videoUrl, $width, $height, $length ) {
+ parent::__construct( $file, $videoUrl, false, $width, $height, $length, false );
}
}
Index: trunk/extensions/OggHandler/README
===================================================================
--- trunk/extensions/OggHandler/README (revision 25466)
+++ trunk/extensions/OggHandler/README (revision 25467)
@@ -20,9 +20,19 @@
http://www.flumotion.net/cortado/
+We have patched Cortado to allow multiple instances to exist on the one page,
+the patch is in cortado-tweak.diff. The recompiled binary is at
+cortado-ovt-stripped-0.2.2.1-patched.jar .
+
The PEAR directory contains a fork of the File_Ogg package, licensed under the
LGPL. The stock File_Ogg will not work -- I have made many aggressive changes
including support for stream formats other than Vorbis. I'll try to get my
changes committed to the official PEAR tree at some point in the future.
+The icons play.png, pause.png, stop.png and info.png are from the Crystal Project:
+
+ http://www.everaldo.com/crystal/
+
+They are licensed under the LGPL.
+
-- Tim Starling
Index: trunk/extensions/OggHandler/OggHandler.i18n.php
===================================================================
--- trunk/extensions/OggHandler/OggHandler.i18n.php (revision 25466)
+++ trunk/extensions/OggHandler/OggHandler.i18n.php (revision 25467)
@@ -25,6 +25,7 @@
'ogg-player-quicktime-mozilla' => 'QuickTime', # only translate this message to other languages if you have to change it
'ogg-player-quicktime-activex' => 'QuickTime (ActiveX)', # only translate this message to other languages if you have to change it
'ogg-player-thumbnail' => 'Still image only',
+ 'ogg-player-soundthumb' => 'No player',
'ogg-player-selected' => '(selected)',
'ogg-use-player' => 'Use player: ',
'ogg-more' => 'More...',
@@ -79,3 +80,10 @@
'ogg-player-oggPlugin' => 'Ogg-plugin',
),
);
+
+$magicWords = array(
+ 'en' => array(
+ 'ogg_noplayer' => array( 0, 'noplayer' ),
+ 'ogg_thumbtime' => array( 0, 'thumbtime=$1' ),
+ ),
+);
Index: trunk/extensions/OggHandler/info.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/OggHandler/info.png
___________________________________________________________________
Name: svn:mime-type
+ image/png