Current File : /home/jvzmxxx/wiki1/extensions/TimedMediaHandler/TimedMediaHandler_body.php
<?php

class TimedMediaHandler extends MediaHandler {

	/**
	 * @return bool
	 */
	function isEnabled() {
		return true;
	}

	/**
	 * Get an image size array like that returned by getimagesize(), or false if it
	 * can't be determined.
	 * @param $file File
	 * @param $path string
	 * @param $metadata bool
	 * @return array|bool
	 */
	function getImageSize( $file, $path, $metadata = false ) {
		/* override by handler */
		return false;
	}

	/**
	 * Get the list of supported wikitext embed params
	 * @return array
	 */
	function getParamMap() {
		return [
			'img_width' => 'width',
			'timedmedia_thumbtime' => 'thumbtime',
			'timedmedia_starttime' => 'start',
			'timedmedia_endtime' => 'end',
			'timedmedia_disablecontrols' => 'disablecontrols',
		];
	}

	/**
	 * Validate a embed file parameters
	 *
	 * @param $name {String} Name of the param
	 * @param $value {Mixed} Value to validated
	 * @return bool
	 */
	function validateParam( $name, $value ) {
		if ( $name == 'thumbtime' || $name == 'start' || $name == 'end' ) {
			if ( $this->parseTimeString( $value ) === false ) {
				return false;
			}
		} elseif ( $name == 'disablecontrols' ) {
			$values = explode( ',', $value );
			foreach ( $values as $v ) {
				if ( !in_array( $v, [ 'options', 'timedText', 'fullscreen' ] ) ) {
					return false;
				}
			}
		} elseif ( $name === 'width' || $name === 'height' ) {
			return $value > 0;
		}
		return true;
	}

	/**
	 * TODO we should really have "$file" available here to validate the param string
	 * @param $params array
	 * @return string
	 */
	function makeParamString( $params ) {
		// Add the width param string ( same as images {width}px )
		$paramString ='';
		$paramString.= ( isset( $params['width'] ) )?  $params['width'] . 'px' : '';
		$paramString.= ( $paramString != '' )? '-' : '';

		// Get the raw thumbTime from thumbtime or start param
		if ( isset ( $params['thumbtime'] ) ) {
			$thumbTime = $params['thumbtime'];
		} elseif ( isset ( $params['start'] ) ) {
			$thumbTime = $params['start'];
		} else {
			$thumbTime = false;
		}

		if ( $thumbTime !== false ) {
			$time = $this->parseTimeString( $thumbTime );
			if ( $time !== false ) {
				return $paramString. 'seek=' . $time;
			}
		}

		if ( !$paramString ) {
			$paramString = 'mid';
		}
		return $paramString;
	}

	/**
	 * Used by thumb.php to find url parameters
	 *
	 * @param $str string
	 * @return array|bool Array of thumbnail parameters, or false if string cannot be parsed
	 */
	function parseParamString( $str ) {
		$params = [];
		if ( preg_match( '/^(mid|(\d*)px-)*(seek=([\d.]+))*$/', $str, $matches ) ) {
			$size = $thumbtime = null;
			if ( isset( $matches[2] ) ) {
				$size = $matches[2];
			}
			if ( isset( $matches[4] ) ) {
				$thumbtime = $matches[4];
			}

			if ( !is_null( $size ) && $size !== '' ) {
				$params['width'] = (int) $size;
			}
			if ( !is_null( $thumbtime ) ) {
				$params['thumbtime'] = (float) $thumbtime;
			}
			return $params; // valid thumbnail URL
		} else {
			// invalid parameter string
			return false;
		}
	}

	/**
	 * @param $image File
	 * @param $params array
	 * @return bool
	 */
	function normaliseParams( $image, &$params ) {
		$timeParam = [ 'thumbtime', 'start', 'end' ];
		// Parse time values if endtime or thumbtime can't be more than length -1
		foreach ( $timeParam as $pn ) {
			if ( isset( $params[$pn] ) && $params[$pn] !== false ) {
				$length = $this->getLength( $image );
				$time = $this->parseTimeString( $params[$pn] );
				if ( $time === false ) {
					return false;
				} elseif ( $time > $length - 1 ) {
					$params[$pn] = $length - 1;
				} elseif ( $time <= 0 ) {
					$params[$pn] = 0;
				}
			}
		}

		if ( $this->isAudio( $image ) ) {
			// Assume a default for audio files
			$size = [
				'width' => 220,
				'height' => 23,
			];
		} else {
			$size = [
				'width' => $image->getWidth(),
				'height' => $image->getHeight(),
			];
		}
		// Make sure we don't try and up-scale the asset:
		if ( !$this->isAudio( $image ) && isset( $params['width'] )
			&& (int)$params['width'] > $size['width']
		) {
			$params['width'] = $size['width'];
		}

		if ( isset( $params['height'] ) && $params['height'] != -1 ) {
			if ( $params['width'] * $size['height'] > $params['height'] * $size['width'] ) {
				$params['width'] = self::fitBoxWidth( $size['width'], $size['height'], $params['height'] );
			}
		}
		if ( isset( $params['width'] ) ) {
			$params['height'] = File::scaleHeight( $size['width'], $size['height'], $params['width'] );
		}

		// Make sure start time is not > than end time
		if ( isset( $params['start'] )
			&& isset( $params['end'] )
			&& $params['start'] !== false
			&& $params['end'] !== false
		) {
			if ( $this->parseTimeString( $params['start'] ) > $this->parseTimeString( $params['end'] ) ) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Parser output hook only adds the required modules
	 *
	 * The core embedPlayer module lazy loaded by the loader modules
	 *
	 * @param $parser Parser
	 * @param $file File
	 */
	function parserTransformHook( $parser, $file ) {
		$parserOutput = $parser->getOutput();
		if ( isset( $parserOutput->hasTimedMediaTransform ) ) {
			return;
		}
		$parserOutput->hasTimedMediaTransform = true;
		if ( TimedMediaHandlerHooks::activePlayerMode() === 'mwembed' ) {
			$parserOutput->addModuleStyles( 'ext.tmh.thumbnail.styles' );
			$parserOutput->addModules( [
				'mw.MediaWikiPlayer.loader',
				'mw.PopUpMediaTransform',
				'mw.TMHGalleryHook.js',
			] );
		}

		if ( TimedMediaHandlerHooks::activePlayerMode() === 'videojs' ) {
			$parserOutput->addModuleStyles( 'ext.tmh.player.styles' );
			$parserOutput->addModules( 'ext.tmh.player' );
		}

		if ( $parserOutput ) {
			// Not present when run from outputpage hooks, like File/Category etc...
			$parserOutput->setExtensionData( 'mw_ext_TMH_hasTimedMediaTransform', true );
		}
	}

	/**
	 * Utility functions
	 * @param $timeString
	 * @param $length
	 * @return bool|int
	 */
	public static function parseTimeString( $timeString, $length = false ) {
		$parts = explode( ':', $timeString );
		$time = 0;
		$partsCount = count( $parts );
		// Check for extra :s
		if ( $partsCount > 3 ) {
			return false;
		}
		for ( $i = 0; $i < $partsCount; $i++ ) {
			if ( !is_numeric( $parts[$i] ) ) {
				return false;
			}
			$time += floatval( $parts[$i] ) * pow( 60, $partsCount - $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;
	}

	/**
	 * @static
	 * @param $timePassed
	 * @return string
	 */
	public static function getTimePassedMsg( $timePassed ) {
		$t = [];
		$t['days'] = floor( $timePassed/60/60/24 );
		$t['hours'] = floor( $timePassed/60/60 )%24;
		$t['minutes'] = floor( $timePassed/60 )%60;
		$t['seconds'] = $timePassed%60;

		foreach ( $t as $k => $v ) {
			if ( $v == 0 ) {
				unset( $t[$k] );
			} else {
				// Give grep a chance to find the usages:
				// timedmedia-days, timedmedia-hours, timedmedia-minutes,timedmedia-seconds
				$t[$k] = wfMessage( 'timedmedia-' . $k, $v )->text();
			}
		}
		if ( count( $t ) == 0 ) {
			$t = [ wfMessage( 'timedmedia-seconds', 0 )->text() ];
		}

		global $wgLang;
		return $wgLang->commaList( $t );
	}

	/**
	 * Converts seconds to Normal play time (NPT) time format:
	 * consist of hh:mm:ss.ms
	 * also see: http://www.ietf.org/rfc/rfc2326.txt section 3.6
	 *
	 * @param $time Number Seconds to be converted to npt time format
	 * @return bool|string
	 */
	public static function seconds2npt( $time ) {
		if ( !is_numeric( $time ) ) {
			wfDebug( __METHOD__.": trying to get npt time on NaN:" + $time );
			return false;
		}
		if ( $time < 0 ) {
			wfDebug( __METHOD__.": trying to time on negative value:" + $time );
			return false;
		}
		$hours = floor( $time / 3600 );
		$min = floor( ( $time / 60 ) % 60 );
		$sec = floor( $time % 60 );
		$ms = floor( $time * 1000 % 1000 );
		$ms = ( $ms != 0 ) ? sprintf( '.%03d', $ms ) : '';

		return sprintf( '%02d:%02d:%02d%s', $hours, $min, $sec, $ms );
	}

	/**
	 * @param $metadata
	 * @return bool|mixed
	 */
	function unpackMetadata( $metadata ) {
		wfSuppressWarnings();
		$unser = unserialize( $metadata );
		wfRestoreWarnings();
		if ( isset( $unser['version'] ) ) {
			return $unser;
		} else {
			return false;
		}
	}

	/**
	 * @param $image
	 * @param $metadata
	 * @return bool
	 */
	function isMetadataValid( $image, $metadata ) {
		return $this->unpackMetadata( $metadata ) !== false;
	}

	/**
	 * @param $ext
	 * @param $mime
	 * @param null $params
	 * @return array
	 */
	function getThumbType( $ext, $mime, $params = null ) {
		return [ 'jpg', 'image/jpeg' ];
	}

	/**
	 * checks if a given file is an audio file
	 * @param $file File
	 * @return bool
	 */
	function isAudio( $file ) {
		return ( $file->getWidth() == 0 && $file->getHeight() == 0 );
	}

	/**
	 * @param $file File
	 * @param $dstPath String
	 * @param $dstUrl String
	 * @param $params array
	 * @param $flags int
	 * @return bool|MediaTransformError|MediaTransformOutput|TimedMediaTransformOutput
	 */
	function doTransform( $file, $dstPath, $dstUrl, $params, $flags = 0 ) {
		# Important or height handling is wrong.
		if ( !$this->normaliseParams( $file, $params ) ) {
			return new TransformParameterError( $params );
		}

		$options = [
			'file' => $file,
			'length' => $this->getLength( $file ),
			'offset' => $this->getOffset( $file ),
			// Default thumbnail width and height for audio files is hardcoded to match the dimensions of
			// the filetype icon, see TimedMediaTransformOutput::getUrl(). Overridden for video below.
			'width' => isset( $params['width'] ) ? $params['width'] : 120,
			// Height is ignored for audio files anyway, and $params['height'] might be set to 0
			'height' => isset( $params['width'] ) ? $params['width'] : 120,
			'isVideo' => !$this->isAudio( $file ),
			'thumbtime' => isset(
				$params['thumbtime']
			) ? $params['thumbtime'] : intval( $file->getLength() / 2 ),
			'start' => isset( $params['start'] ) ? $params['start'] : false,
			'end' => isset( $params['end'] ) ? $params['end'] : false,
			'fillwindow' => isset( $params['fillwindow'] ) ? $params['fillwindow'] : false,
			'disablecontrols' => isset ( $params['disablecontrols'] ) ? $params['disablecontrols'] : false
		];

		// No thumbs for audio
		if ( !$options['isVideo'] ) {
			return new TimedMediaTransformOutput( $options );
		}

		// We're dealing with a video file now, set width and height
		$srcWidth = $file->getWidth();
		$srcHeight = $file->getHeight();

		$params['width'] = isset( $params['width'] ) ? $params['width'] : $srcWidth;

		// if height overtakes width use height as max:
		$targetWidth = $params['width'];
		$targetHeight = $srcWidth == 0 ? $srcHeight : round( $params['width'] * $srcHeight / $srcWidth );
		if ( isset( $params['height'] ) && $targetHeight > $params['height'] ) {
			$targetHeight = $params['height'];
			$targetWidth = round( $params['height'] * $srcWidth / $srcHeight );
		}

		$options[ 'width' ] = $targetWidth;
		$options[ 'height' ] = $targetHeight;

		// Setup pointer to thumb arguments
		$options[ 'thumbUrl' ] = $dstUrl;
		$options[ 'dstPath' ] = $dstPath;
		$options[ 'path' ] = $dstPath;

		// Check if transform is deferred:
		if ( $flags & self::TRANSFORM_LATER ) {
			return new TimedMediaTransformOutput( $options );
		}

		// Generate thumb:
		$thumbStatus = TimedMediaThumbnail::get( $options );
		if ( $thumbStatus !== true ) {
			return $thumbStatus;
		}

		return new TimedMediaTransformOutput( $options );
	}

	/**
	 * @param $file
	 * @return bool
	 */
	function canRender( $file ) {
		return true;
	}

	/**
	 * @param $file
	 * @return bool
	 */
	function mustRender( $file ) {
		return true;
	}

	/**
	 * Get a stream offset time
	 * @param $file
	 * @return int
	 */
	function getOffset( $file ) {
		return 0;
	}

	/**
	 * Get length of a file
	 * @param $file
	 * @return int
	 */
	function getLength( $file ) {
		return $file->getLength();
	}

	/**
	 * @param $file File
	 * @return String
	 */
	function getDimensionsString( $file ) {
		global $wgLang;

		if ( $file->getWidth() ) {
			return wfMessage( 'video-dims', $wgLang->formatTimePeriod( $this->getLength( $file ) ) )
				->numParams( $file->getWidth(), $file->getHeight() )->text();
		} else {
			return $wgLang->formatTimePeriod( $this->getLength( $file ) );
		}
	}

	public function filterThumbnailPurgeList( &$files, $options ) {
		global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet;

		$transcodeSet = array_merge( $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet );

		// dont remove derivatives on normal purge
		foreach ( array_slice( $files, 1 ) as $key => $file ) {
			foreach ( $transcodeSet as $transcodeKey ) {
				if ( preg_match( '/' . preg_quote( $transcodeKey ) . '$/', $file ) ) {
					unset( $files[$key] );
					break;
				}
			}
		}
	}
}