Index: trunk/extensions/TimedMediaHandler/maintenance/WebVideoJobRunner.php |
— | — | @@ -34,11 +34,11 @@ |
35 | 35 | } |
36 | 36 | // Check if WebVideoJobRuner is already running: |
37 | 37 | $jobRunnerCount = 0; |
| 38 | + $fistPid = null; |
38 | 39 | foreach( $this->getProcessList() as $pid => $proc ){ |
39 | 40 | if( strpos( $proc['args'], 'WebVideoJobRunner.php' ) !== false ){ |
40 | | - $jobRunnerCount++; |
41 | | - if( $jobRunnerCount > 1){ |
42 | | - $this->error( "WebVideoJobRunner.php is already running on this box with pid $pid" ); |
| 41 | + if( intval( $proc['time'] ) != 0 ){ |
| 42 | + $this->error( "WebVideoJobRunner.php is already running on this box with pid $pid and $fistPid" ); |
43 | 43 | exit(1); |
44 | 44 | } |
45 | 45 | } |
Index: trunk/extensions/TimedMediaHandler/TranscodeStatusTable.php |
— | — | @@ -0,0 +1,140 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * TranscodeStatusTable outputs a "transcode" status table to the ImagePage |
| 5 | + * |
| 6 | + * If logged in as autoconfirmed users can reset transcode states |
| 7 | + * via the transcode api entry point |
| 8 | + * |
| 9 | + */ |
| 10 | +class TranscodeStatusTable { |
| 11 | + |
| 12 | + public static function getHTML( $file ){ |
| 13 | + global $wgUser, $wgOut; |
| 14 | + |
| 15 | + // Add transcode table css and javascript: |
| 16 | + $wgOut->addModules( array( 'ext.tmh.transcodetable' ) ); |
| 17 | + |
| 18 | + $o = '<h2>' . wfMsgHtml( 'timedmedia-status-header' ) . '</h2>'; |
| 19 | + // Give the user a purge page link |
| 20 | + $o.= Linker::link( $file->getTitle(), wfMsg('timedmedia-update-status'), array(), array( 'action'=> 'purge' ) ); |
| 21 | + |
| 22 | + $o.= Xml::openElement( 'table', array( 'class' => 'wikitable transcodestatus' ) ) . "\n" |
| 23 | + . '<tr>' |
| 24 | + . '<th>'.wfMsgHtml( 'timedmedia-status' ) .'</th>' |
| 25 | + . '<th>' . wfMsgHtml( 'timedmedia-transcodeinfo' ) . '</th>' |
| 26 | + . '<th>'.wfMsgHtml( 'timedmedia-direct-link' ) .'</th>'; |
| 27 | + |
| 28 | + if( array_search( 'resetTranscode', $wgUser->getRights() )!== false ){ |
| 29 | + $o.= '<th>' . wfMsgHtml( 'timedmedia-actions' ) . '</th>'; |
| 30 | + } |
| 31 | + |
| 32 | + $o.= "</tr>\n"; |
| 33 | + |
| 34 | + $o.= self::getTranscodeRows( $file ); |
| 35 | + |
| 36 | + $o.= Xml::closeElement( 'table' ); |
| 37 | + return $o; |
| 38 | + } |
| 39 | + |
| 40 | + public static function getTranscodeRows( $file ){ |
| 41 | + global $wgUser; |
| 42 | + $o=''; |
| 43 | + $transcodeRows = WebVideoTranscode::getTranscodeState( $file->getTitle()->getDbKey() ); |
| 44 | + |
| 45 | + foreach( $transcodeRows as $transcodeKey => $state ){ |
| 46 | + $o.='<tr>'; |
| 47 | + // Status: |
| 48 | + $o.='<td>' . self::getStatusMsg( $file, $state ) . '</td>'; |
| 49 | + |
| 50 | + // Encode info: |
| 51 | + $o.='<td>' . wfMsgHtml('timedmedia-derivative-desc-' . $transcodeKey ) . '</td>'; |
| 52 | + |
| 53 | + // Download file |
| 54 | + $o.='<td>'; |
| 55 | + $o.= ( !is_null( $state['time_success'] ) ) ? |
| 56 | + '<a href="'.self::getSourceUrl( $file, $transcodeKey ) .'" title="'.wfMsg('timedmedia-download' ) .'"><div class="download-btn"></div></a></td>' : |
| 57 | + wfMsgHtml('timedmedia-not-ready' ); |
| 58 | + $o.='</td>'; |
| 59 | + |
| 60 | + // Check if we should include actions: |
| 61 | + if( array_search( 'resetTranscode', $wgUser->getRights() )!== false ){ |
| 62 | + // include reset transcode action buttons |
| 63 | + |
| 64 | + } |
| 65 | + $o.='</tr>'; |
| 66 | + } |
| 67 | + return $o; |
| 68 | + } |
| 69 | + public static function getSourceUrl( $file, $transcodeKey ){ |
| 70 | + $fileName = $file->getTitle()->getDbKey(); |
| 71 | + |
| 72 | + $thumbName = $file->thumbName( array() ); |
| 73 | + $thumbUrl = $file->getThumbUrl( $thumbName ); |
| 74 | + $thumbUrlDir = dirname( $thumbUrl ); |
| 75 | + return $thumbUrlDir . '/' .$file->getName() . '.' . $transcodeKey; |
| 76 | + } |
| 77 | + |
| 78 | + public static function getStatusMsg( $file, $state ){ |
| 79 | + // Check for success: |
| 80 | + if( !is_null( $state['time_success'] ) ) { |
| 81 | + return wfMsgHtml('timedmedia-completed-on', $state['time_success'] ); |
| 82 | + } |
| 83 | + // Check for error: |
| 84 | + if( !is_null( $state['time_error'] ) ){ |
| 85 | + if( !is_null( $state['error'] ) ){ |
| 86 | + $showErrorLink = Linker::link( $file->getTitle(), wfMsg('timedmedia-show-error'), array( |
| 87 | + 'title' => wfMsgHtml('timedmedia-error-on', $state['time_error'] ), |
| 88 | + 'class' => 'errorlink', |
| 89 | + 'data-error' => $state['error'] |
| 90 | + )); |
| 91 | + } |
| 92 | + return wfMsgHtml('timedmedia-error-on', $state['time_error'] ) . $showErrorLink; |
| 93 | + } |
| 94 | + // Check for started encoding |
| 95 | + if( !is_null( $state['time_startwork'] ) ){ |
| 96 | + $timePassed = wfTimestamp() - wfTimestamp( TS_UNIX, strtotime( $state['time_startwork'] ) ); |
| 97 | + |
| 98 | + // Get the rough estimate of time done: ( this is not very costly considering everything else |
| 99 | + // that happens in an action=purge video page request ) |
| 100 | + $filePath = WebVideoTranscode::getTargetEncodePath( $file, $state['key'] ); |
| 101 | + if( is_file( $filePath ) ){ |
| 102 | + $targetSize = WebVideoTranscode::getProjectedFileSize( $file, $state['key'] ); |
| 103 | + if( $targetSize === false ){ |
| 104 | + $doneMsg = wfMsgHtml('timedmedia-unknown-target-size', $wgLang->formatSize( filesize( $filePath ) ) ); |
| 105 | + } else { |
| 106 | + $doneMsg = wfMsgHtml('timedmedia-percent-done', round( filesize( $filePath ) / $targetSize, 2 ) ); |
| 107 | + } |
| 108 | + } |
| 109 | + return wfMsgHtml('timedmedia-started-transcode', self::getTimePassedMsg( $timePassed ), $doneMsg ); |
| 110 | + } |
| 111 | + // Check for job added ( but not started encoding ) |
| 112 | + if( !is_null( $state['time_addjob'] ) ){ |
| 113 | + $timePassed = wfTimestamp() - wfTimestamp( TS_UNIX, strtotime( $state['time_addjob'] ) ); |
| 114 | + return wfMsgHtml('timedmedia-in-job-queue', self::getTimePassedMsg( $timePassed ) ); |
| 115 | + } |
| 116 | + // Return unknown status error: |
| 117 | + return wfMsgHtml('timedmedia-status-unknown'); |
| 118 | + } |
| 119 | + public static function getTimePassedMsg( $timePassed ){ |
| 120 | + $t['days'] = floor($timePassed/60/60/24); |
| 121 | + $t['hours'] = floor($timePassed/60/60)%24; |
| 122 | + $t['minutes'] = floor($timePassed/60)%60; |
| 123 | + $t['seconds'] = $timePassed%60; |
| 124 | + foreach( $t as $k => $v ){ |
| 125 | + if($v == 0 ){ |
| 126 | + $t[$k] = ''; |
| 127 | + }else{ |
| 128 | + $t[$k] = wfMsg( 'timedmedia-' . $k, $v); |
| 129 | + } |
| 130 | + } |
| 131 | + // Add the tailing and $1 text: |
| 132 | + if( $t['seconds'] !== '' ){ |
| 133 | + $t['seconds'] = wfMsg('timedmedia-and', $t['seconds'] ); |
| 134 | + } else if( $t['minutes'] !== '' ){ |
| 135 | + $t['minutes'] = wfMsg('timedmedia-and', $t['minutes'] ); |
| 136 | + } else if( $t['hours'] !== '' ){ |
| 137 | + $t['hours'] = wfMsg('timedmedia-and', $t['hours'] ); |
| 138 | + } |
| 139 | + return wfMsgHtml('timedmedia-days-hours-min-sec-time', $t['days'], $t['hours'], $t['minutes'], $t['seconds'] ); |
| 140 | + } |
| 141 | +} |
\ No newline at end of file |
Index: trunk/extensions/TimedMediaHandler/TimedMediaHandler.php |
— | — | @@ -28,6 +28,12 @@ |
29 | 29 | |
30 | 30 | /*** end MwEmbed module configuration: ******************************/ |
31 | 31 | |
| 32 | +// Add the rest transcode right: |
| 33 | +$wgAvailableRights[] = 'resetTranscode'; |
| 34 | + |
| 35 | +// Which users can restart failed or expired transcode jobs |
| 36 | +$wgGroupPermissions['sysop']['resetTranscode'] = true; |
| 37 | + |
32 | 38 | // The minimum size for an embed video player: |
33 | 39 | $wgMinimumVideoPlayerSize = 200; |
34 | 40 | |
— | — | @@ -96,6 +102,9 @@ |
97 | 103 | $wgAutoloadClasses['TimedMediaTransformOutput'] = "$timedMediaDir/TimedMediaTransformOutput.php"; |
98 | 104 | $wgAutoloadClasses['TimedMediaIframeOutput'] = "$timedMediaDir/TimedMediaIframeOutput.php"; |
99 | 105 | $wgAutoloadClasses['TimedMediaThumbnail'] = "$timedMediaDir/TimedMediaThumbnail.php"; |
| 106 | +// Transcode Page |
| 107 | +$wgAutoloadClasses['TranscodeStatusTable'] = "$timedMediaDir/TranscodeStatusTable.php"; |
| 108 | + |
100 | 109 | // Testing: |
101 | 110 | $wgAutoloadClasses['ApiTestCaseVideoUpload'] = "$timedMediaDir/tests/phpunit/ApiTestCaseVideoUpload.php"; |
102 | 111 | |
Index: trunk/extensions/TimedMediaHandler/handlers/WebMHandler/WebMHandler.php |
— | — | @@ -78,10 +78,10 @@ |
79 | 79 | if ( !$metadata || isset( $metadata['error'] ) ) { |
80 | 80 | return false; |
81 | 81 | } |
82 | | - // id3 gives 'V_VP8' for what we call VP8 |
83 | 82 | if( isset( $metadata['audio'] ) && $metadata['audio']['dataformat'] == 'vorbis' ){ |
84 | 83 | $streamTypes[] = 'Vorbis'; |
85 | 84 | } |
| 85 | + // id3 gives 'V_VP8' for what we call VP8 |
86 | 86 | if( $metadata['video']['dataformat'] == 'V_VP8' ){ |
87 | 87 | $streamTypes[] = 'VP8'; |
88 | 88 | } |
Index: trunk/extensions/TimedMediaHandler/TimedMediaHandler.i18n.php |
— | — | @@ -33,6 +33,30 @@ |
34 | 34 | 'timedmedia-oggThumb-version' => 'OggHandler requires oggThumb version $1 or later.', |
35 | 35 | 'timedmedia-oggThumb-failed' => 'oggThumb failed to create the thumbnail.', |
36 | 36 | |
| 37 | + // Transcode status table: |
| 38 | + |
| 39 | + 'timedmedia-status-header' => 'Transcode status', |
| 40 | + 'timedmedia-update-status' => 'Update transcode status', |
| 41 | + 'timedmedia-status' => 'status', |
| 42 | + 'timedmedia-status-unknown' => 'unknown status', |
| 43 | + 'timedmedia-transcodeinfo' => 'Transcode derivative description', |
| 44 | + 'timedmedia-actions' => 'actions', |
| 45 | + 'timedmedia-direct-link' => 'Download derivative', |
| 46 | + 'timedmedia-not-ready' => 'Not ready', |
| 47 | + 'timedmedia-completed-on' => 'Completed transcode $1', |
| 48 | + 'timedmedia-error-on' => 'Error in transcode on $1. ', |
| 49 | + 'timedmedia-started-transcode' => 'Transcode started $1 ago. $2', |
| 50 | + 'timedmedia-percent-done' => 'About $1% done', |
| 51 | + 'timedmedia-in-job-queue' => 'Added to Job queue $1 ago', |
| 52 | + 'timedmedia-unknown-target-size'=> 'Unknown target size, $1 encoded', |
| 53 | + 'timedmedia-days' => '{{PLURAL:$1|day|$1 days}}', |
| 54 | + 'timedmedia-hours' => '{{PLURAL:$1|hour|$1 hours}}', |
| 55 | + 'timedmedia-minutes' => '{{PLURAL:$1|minute|$1 minutes}}', |
| 56 | + 'timedmedia-seconds' => '{{PLURAL:$1|second|$1 seconds}}', |
| 57 | + 'timedmedia-and' => 'and $1', |
| 58 | + 'timedmedia-days-hours-min-sec-time' => '$1, $2, $3 $4', |
| 59 | + 'timedmedia-show-error' => 'Show error', |
| 60 | + |
37 | 61 | // Original uploaded asset |
38 | 62 | 'timedmedia-ogg' => 'Ogg', |
39 | 63 | 'timedmedia-webm' => 'WebM', |
Index: trunk/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscode.php |
— | — | @@ -40,7 +40,7 @@ |
41 | 41 | const ENC_WEBM_HQ_VBR = '720_VBR.webm'; |
42 | 42 | |
43 | 43 | // Static cache of transcode state per instantiation |
44 | | - public static $transcodeStateCache = null; |
| 44 | + public static $transcodeState = array() ; |
45 | 45 | |
46 | 46 | /** |
47 | 47 | * Encoding parameters are set via firefogg encode api |
— | — | @@ -140,6 +140,7 @@ |
141 | 141 | $file->getName() . '.' . |
142 | 142 | $transcodeKey ; |
143 | 143 | } |
| 144 | + |
144 | 145 | /** |
145 | 146 | * Get the target encode path for a video encode |
146 | 147 | * |
— | — | @@ -150,11 +151,12 @@ |
151 | 152 | */ |
152 | 153 | static public function getTargetEncodePath( &$file, $transcodeKey ){ |
153 | 154 | // TODO probably should use some other temporary non-web accessible location for |
154 | | - // in-progress encodes. |
| 155 | + // in-progress encodes, its nice having it publicly accessible for debugging though |
155 | 156 | $filePath = self::getDerivativeFilePath( $file, $transcodeKey ); |
156 | 157 | $ext = strtolower( pathinfo( "$filePath", PATHINFO_EXTENSION ) ); |
157 | 158 | return "{$filePath}.queue.{$ext}"; |
158 | 159 | } |
| 160 | + |
159 | 161 | /** |
160 | 162 | * Get the max size of the web stream ( constant bitrate ) |
161 | 163 | */ |
— | — | @@ -168,6 +170,22 @@ |
169 | 171 | } |
170 | 172 | return $maxSize; |
171 | 173 | } |
| 174 | + /** |
| 175 | + * Give a rough estimate on file size |
| 176 | + * Note this is not always accurate.. especially with variable bitrate codecs ;) |
| 177 | + */ |
| 178 | + static public function getProjectedFileSize( $file, $transcodeKey){ |
| 179 | + $settings = self::$derivativeSettings[$transcodeKey]; |
| 180 | + if( $settings[ 'videoBitrate' ] && $settings['audioBitrate'] ){ |
| 181 | + return $file->getLength * 8 * ( |
| 182 | + self::$derivativeSettings[$transcodeKey]['videoBitrate'] |
| 183 | + + |
| 184 | + self::$derivativeSettings[$transcodeKey]['audioBitrate'] |
| 185 | + ); |
| 186 | + } |
| 187 | + // Else just return the size of the source video ( we have no idea how large the actual derivative size will be ) |
| 188 | + return $file->getLength * $file->getHandler()->getBitrate( $file ) * 8; |
| 189 | + } |
172 | 190 | |
173 | 191 | /** |
174 | 192 | * Static function to get the set of video assets |
— | — | @@ -321,25 +339,26 @@ |
322 | 340 | */ |
323 | 341 | public static function isTranscodeReady( $fileName, $transcodeKey ){ |
324 | 342 | |
325 | | - // Check if we need to populate the transcodeState cache: |
326 | | - if( !self::$transcodeStateCache || !isset( self::$transcodeStateCache[ $fileName ] ) ) { |
327 | | - self::getTranscodeStateCache( $fileName ); |
328 | | - } |
| 343 | + // Check if we need to populate the transcodeState cache: |
| 344 | + $transcodeState = self::getTranscodeState( $fileName ); |
| 345 | + |
329 | 346 | // If no state is found the cache for this file is false: |
330 | | - if( !isset( self::$transcodeStateCache[ $fileName ][ $transcodeKey ]) |
331 | | - || |
332 | | - self::$transcodeStateCache[ $fileName ][ $transcodeKey ] === false ) |
333 | | - { |
| 347 | + if( !isset( $transcodeState[ $transcodeKey ] ) ) { |
334 | 348 | return false; |
335 | 349 | } |
336 | | - // Else return the state: |
337 | | - return self::$transcodeStateCache[$fileName][$transcodeKey]['ready']; |
| 350 | + // Else return boolean ready state ( if not null, then ready ): |
| 351 | + return !is_null( $transcodeState[ $transcodeKey ]['time_success'] ); |
338 | 352 | } |
339 | 353 | /** |
340 | | - * Clear the transcode state cache: |
| 354 | + * Clear the transcode state cache: |
| 355 | + * @param String $fileName Optional fileName to clear transcode cache for |
341 | 356 | */ |
342 | | - public static function clearTranscodeCache(){ |
343 | | - self::$transcodeStateCache = null; |
| 357 | + public static function clearTranscodeCache( $fileName = null){ |
| 358 | + if( $fileName ){ |
| 359 | + self::$transcodeState[ $fileName ] = array(); |
| 360 | + } else { |
| 361 | + self::$transcodeState = array(); |
| 362 | + } |
344 | 363 | } |
345 | 364 | |
346 | 365 | /** |
— | — | @@ -348,24 +367,29 @@ |
349 | 368 | * |
350 | 369 | * @param string $fileName key |
351 | 370 | */ |
352 | | - public static function getTranscodeStateCache( $fileName ){ |
353 | | - wfProfileIn( __METHOD__ ); |
354 | | - $res = wfGetDB( DB_SLAVE )->select( 'transcode', |
355 | | - array( 'transcode_key', 'transcode_time_success','transcode_time_addjob','transcode_final_bitrate' ) , |
356 | | - array( 'transcode_image_name' => $fileName ), |
357 | | - __METHOD__, |
358 | | - array( 'LIMIT' => 100 ) |
359 | | - ); |
360 | | - // Populate the per transcode state cache |
361 | | - foreach ( $res as $row ) { |
362 | | - self::$transcodeStateCache[$fileName][ $row->transcode_key ] = array( |
363 | | - 'ready' => !is_null( $row->transcode_time_success ), |
364 | | - 'bitrate' => $row->transcode_final_bitrate, |
365 | | - 'addjob' => $row->transcode_time_addjob, |
| 371 | + public static function getTranscodeState( $fileName ){ |
| 372 | + if( ! isset( self::$transcodeState[$fileName] ) ){ |
| 373 | + wfProfileIn( __METHOD__ ); |
| 374 | + $res = wfGetDB( DB_SLAVE )->select( 'transcode', |
| 375 | + '*', |
| 376 | + array( 'transcode_image_name' => $fileName ), |
| 377 | + __METHOD__, |
| 378 | + array( 'LIMIT' => 100 ) |
366 | 379 | ); |
367 | | - } |
368 | | - wfProfileOut( __METHOD__ ); |
| 380 | + // Populate the per transcode state cache |
| 381 | + foreach ( $res as $row ) { |
| 382 | + // strip the out the "transcode_" from keys |
| 383 | + $trascodeState = array(); |
| 384 | + foreach( $row as $k => $v ){ |
| 385 | + $trascodeState[ str_replace( 'transcode_', '', $k ) ] = $v; |
| 386 | + } |
| 387 | + self::$transcodeState[ $fileName ][ $row->transcode_key ] = $trascodeState; |
| 388 | + } |
| 389 | + wfProfileOut( __METHOD__ ); |
| 390 | + } |
| 391 | + return self::$transcodeState[ $fileName ]; |
369 | 392 | } |
| 393 | + |
370 | 394 | /** |
371 | 395 | * Remove any transcode jobs associated with a given $fileName |
372 | 396 | * |
— | — | @@ -390,6 +414,8 @@ |
391 | 415 | array( 'transcode_image_name' => $fileName ), |
392 | 416 | __METHOD__ |
393 | 417 | ); |
| 418 | + // Remove from local cache: |
| 419 | + self::clearTranscodeCache( $fileName ); |
394 | 420 | } |
395 | 421 | |
396 | 422 | /** |
— | — | @@ -474,7 +500,7 @@ |
475 | 501 | "{$dataPrefix}width" => $width, |
476 | 502 | "{$dataPrefix}height" => $height, |
477 | 503 | // a "ready" transcode should have a bitrate: |
478 | | - "{$dataPrefix}bandwidth" => self::$transcodeStateCache[$fileName][ $transcodeKey ]['bitrate'], |
| 504 | + "{$dataPrefix}bandwidth" => self::$transcodeState[$fileName][ $transcodeKey ]['final_bitrate'], |
479 | 505 | "{$dataPrefix}framerate" => $framerate, |
480 | 506 | ); |
481 | 507 | } |
— | — | @@ -489,25 +515,20 @@ |
490 | 516 | $fileName = $file->getTitle()->getDbKey(); |
491 | 517 | |
492 | 518 | // Check if we need to update the transcode state: |
493 | | - if( !self::$transcodeStateCache || !isset( self::$transcodeStateCache[ $fileName ] ) ) { |
494 | | - self::getTranscodeStateCache( $fileName ); |
495 | | - } |
| 519 | + $transcodeState = self::getTranscodeState( $fileName ); |
496 | 520 | |
497 | 521 | // Check if the job has been added: |
498 | | - if( ! isset( self::$transcodeStateCache[$fileName][$transcodeKey] ) |
499 | | - || |
500 | | - is_null( self::$transcodeStateCache[$fileName][$transcodeKey]['addjob'] ) ) |
501 | | - { |
502 | | - // add to job queue and update the db |
| 522 | + if( is_null( $transcodeState[ $transcodeKey ]['time_addjob'] ) ) { |
| 523 | + // Add to job queue and update the db |
503 | 524 | $job = new WebVideoTranscodeJob( $file->getTitle(), array( |
504 | 525 | 'transcodeMode' => 'derivative', |
505 | 526 | 'transcodeKey' => $transcodeKey, |
506 | | - ) ); |
| 527 | + ) ); |
507 | 528 | $jobId = $job->insert(); |
508 | 529 | if( $jobId ){ |
509 | 530 | $db = wfGetDB( DB_MASTER ); |
510 | 531 | // update the transcode state: |
511 | | - if( ! isset( self::$transcodeStateCache[$fileName][$transcodeKey] ) ){ |
| 532 | + if( ! isset( $transcodeState[$transcodeKey] ) ){ |
512 | 533 | // insert the transcode row with jobadd time |
513 | 534 | $db->insert( |
514 | 535 | 'transcode', |
— | — | @@ -532,8 +553,8 @@ |
533 | 554 | __METHOD__ |
534 | 555 | ); |
535 | 556 | } |
536 | | - // Update the state cache |
537 | | - self::getTranscodeStateCache( $fileName ); |
| 557 | + // Clear the state cache ( now that we have updated the page ) |
| 558 | + self::clearTranscodeCache( $fileName ); |
538 | 559 | } |
539 | 560 | // no jobId ? error out in some way? |
540 | 561 | } |
— | — | @@ -578,4 +599,3 @@ |
579 | 600 | return ( $targetMaxSize > $largerSize ); |
580 | 601 | } |
581 | 602 | } |
582 | | - |
Index: trunk/extensions/TimedMediaHandler/TimedMediaHandler.hooks.php |
— | — | @@ -50,6 +50,10 @@ |
51 | 51 | ) ), |
52 | 52 | 'embedPlayerIframeStyle'=> array_merge( $baseExtensionResource, array( |
53 | 53 | 'styles' => 'resources/embedPlayerIframe.css', |
| 54 | + ) ), |
| 55 | + 'ext.tmh.transcodetable' => array_merge($baseExtensionResource, array( |
| 56 | + 'scripts' => 'resources/ext.tmh.transcodetable.js', |
| 57 | + 'styles' => 'resources/transcodeTable.css' |
54 | 58 | ) ) |
55 | 59 | ); |
56 | 60 | |
— | — | @@ -88,9 +92,12 @@ |
89 | 93 | $wgExtraNamespaces[NS_TIMEDTEXT] = "TimedText"; |
90 | 94 | $wgExtraNamespaces[NS_TIMEDTEXT_TALK] = "TimedText_talk"; |
91 | 95 | |
92 | | - // if on a timed text page, display timed text page: |
| 96 | + // Check for timed text page: |
93 | 97 | $wgHooks[ 'ArticleFromTitle' ][] = 'TimedMediaHandlerHooks::checkForTimedTextPage'; |
94 | 98 | |
| 99 | + // Add transcode status to video asset pages: |
| 100 | + $wgHooks[ 'ImagePageAfterImageLinks' ][] = 'TimedMediaHandlerHooks::checkForTranscodeStatus'; |
| 101 | + |
95 | 102 | return true; |
96 | 103 | } |
97 | 104 | |
— | — | @@ -100,7 +107,22 @@ |
101 | 108 | } |
102 | 109 | return true; |
103 | 110 | } |
104 | | - |
| 111 | + public static function checkForTranscodeStatus( $article, &$html ){ |
| 112 | + // load the file: |
| 113 | + $file = wfFindFile( $article->getTitle() ); |
| 114 | + // cant find file |
| 115 | + if( !$file ){ |
| 116 | + return true; |
| 117 | + } |
| 118 | + |
| 119 | + // get mediaType |
| 120 | + $mediaType = $file->getHandler()->getMetadataType( $image = '' ); |
| 121 | + // if ogg or webm format and not audio show transcode page: |
| 122 | + if( ( $mediaType == 'webm' || $mediaType == 'ogg' ) && ! $file->getHandler()->isAudio( $file ) ){ |
| 123 | + $html = TranscodeStatusTable::getHTML( $file ); |
| 124 | + } |
| 125 | + return true; |
| 126 | + } |
105 | 127 | public static function checkArticleDeleteComplete( &$article, &$user, $reason, $id ){ |
106 | 128 | // Check if the article is a file and remove transcode jobs: |
107 | 129 | if( $article->getTitle()->getNamespace() == NS_FILE ) { |
Index: trunk/extensions/TimedMediaHandler/resources/loading_spinner.gif |
Cannot display: file marked as a binary type. |
svn:mime-type = image/gif |
Index: trunk/extensions/TimedMediaHandler/resources/download_sprite.png |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes on: trunk/extensions/TimedMediaHandler/resources/download_sprite.png |
___________________________________________________________________ |
Added: svn:mime-type |
108 | 130 | + application/octet-stream |
Index: trunk/extensions/TimedMediaHandler/resources/transcodeTable.css |
— | — | @@ -0,0 +1,10 @@ |
| 2 | +.transcodestatus .download-btn { |
| 3 | + background-image: url('download_sprite.png'); |
| 4 | + width: 49px; |
| 5 | + height: 36px; |
| 6 | + background-repeat:no-repeat; |
| 7 | + background-position: -50px; |
| 8 | +} |
| 9 | +.transcodestatus .download-btn:hover { |
| 10 | + background-position: 0 0; |
| 11 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/TimedMediaHandler/resources/transcodeTable.css |
___________________________________________________________________ |
Added: svn:mime-type |
1 | 12 | + text/plain |
Index: trunk/extensions/TimedMediaHandler/resources/mw.PopUpThumbVideo.js |
— | — | @@ -8,7 +8,7 @@ |
9 | 9 | var _parent = this; |
10 | 10 | $( this ).find('a').click( function(){ |
11 | 11 | var $video = $( unescape( $(_parent).attr('data-videopayload') ) ); |
12 | | - mw.addDialog( { |
| 12 | + mw.addDialog({ |
13 | 13 | 'width' : 'auto', |
14 | 14 | 'height' : 'auto', |
15 | 15 | 'title' : $video.attr('data-mwtitle'), |
— | — | @@ -21,7 +21,7 @@ |
22 | 22 | } |
23 | 23 | return true; |
24 | 24 | } |
25 | | - } ) |
| 25 | + }) |
26 | 26 | .css('overflow', 'hidden') |
27 | 27 | .find('video,audio').embedPlayer(); |
28 | 28 | // don't follow file link |
Index: trunk/extensions/TimedMediaHandler/resources/ext.tmh.transcodetable.js |
— | — | @@ -0,0 +1,22 @@ |
| 2 | +/** |
| 3 | +* Javascript to support transcode table on image page |
| 4 | +*/ |
| 5 | +$(document).ready(function(){ |
| 6 | + // Error link popup: |
| 7 | + $('.transcodestatus .errorlink').click(function(){ |
| 8 | + // pop up dialog |
| 9 | + mw.addDialog({ |
| 10 | + 'width' : '640', |
| 11 | + 'height' : '480', |
| 12 | + 'title' : $(this).attr('title'), |
| 13 | + 'content' : $('<textarea />') |
| 14 | + .css({ |
| 15 | + 'width':'99%', |
| 16 | + 'height':'99%' |
| 17 | + }) |
| 18 | + .text( $(this).attr('data-error') ) |
| 19 | + }) |
| 20 | + .css('overflow', 'hidden'); |
| 21 | + return false; |
| 22 | + }) |
| 23 | +}) |
Property changes on: trunk/extensions/TimedMediaHandler/resources/ext.tmh.transcodetable.js |
___________________________________________________________________ |
Added: svn:mime-type |
1 | 24 | + text/plain |