56 $prefixOrRepoGroup =
null,
57 $repoGroupOrContentLanguage =
null,
58 $contentLanguageOrBadFileLookup =
null,
59 $badFileLookupOrUnused =
null
63 if ( !is_string( $prefixOrRepoGroup ) ) {
65 $repoGroup = $prefixOrRepoGroup;
66 $contentLanguage = $repoGroupOrContentLanguage;
67 $badFileLookup = $contentLanguageOrBadFileLookup;
70 $prefix = $prefixOrRepoGroup;
71 $repoGroup = $repoGroupOrContentLanguage;
72 $contentLanguage = $contentLanguageOrBadFileLookup;
73 $badFileLookup = $badFileLookupOrUnused;
75 parent::__construct( $query, $moduleName, $prefix );
77 $services = MediaWikiServices::getInstance();
78 $this->repoGroup = $repoGroup ?? $services->getRepoGroup();
79 $this->contentLanguage = $contentLanguage ?? $services->getContentLanguage();
80 $this->badFileLookup = $badFileLookup ?? $services->getBadFileLookup();
86 $prop = array_fill_keys(
$params[
'prop'],
true );
91 'version' =>
$params[
'metadataversion'],
92 'language' =>
$params[
'extmetadatalanguage'],
93 'multilang' =>
$params[
'extmetadatamultilang'],
94 'extmetadatafilter' =>
$params[
'extmetadatafilter'],
98 if ( isset(
$params[
'badfilecontexttitle'] ) ) {
99 $badFileContextTitle = Title::newFromText(
$params[
'badfilecontexttitle'] );
100 if ( !$badFileContextTitle || $badFileContextTitle->isExternal() ) {
102 $this->
dieWithError( [
'apierror-bad-badfilecontexttitle', $p ],
'invalid-title' );
105 $badFileContextTitle =
null;
108 $pageIds = $this->
getPageSet()->getGoodAndMissingTitlesByNamespace();
109 if ( !empty( $pageIds[
NS_FILE] ) ) {
110 $titles = array_keys( $pageIds[
NS_FILE] );
114 if (
$params[
'continue'] !==
null ) {
116 $fromTitle = $cont[0];
117 $fromTimestamp = $cont[1];
119 foreach ( $titles as $key => $title ) {
120 if ( $title < $fromTitle ) {
121 unset( $titles[$key] );
129 $findTitles = array_map(
static function ( $title ) use ( $performer ) {
132 'private' => $performer,
137 $images = $this->repoGroup->getLocalRepo()->findFiles( $findTitles );
139 $images = $this->repoGroup->findFiles( $findTitles );
143 foreach ( $titles as $title ) {
145 $pageId = $pageIds[
NS_FILE][$title];
148 $start = $title === $fromTitle ? $fromTimestamp :
$params[
'start'];
150 if ( !isset( $images[$title] ) ) {
151 if ( isset( $prop[
'uploadwarning'] ) || isset( $prop[
'badfile'] ) ) {
153 $images[$title] = $this->repoGroup->getLocalRepo()->newFile( $title );
155 $info[
'imagerepository'] =
'';
158 [
'query',
'pages', (
int)$pageId ],
159 'imagerepository',
''
167 $img = $images[$title];
169 if ( self::getTransformCount() >= self::TRANSFORM_LIMIT ) {
170 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
173 $start ??
wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
182 if ( !isset( $info[
'imagerepository'] ) ) {
183 $info[
'imagerepository'] = $img->getRepoName();
185 if ( isset( $prop[
'badfile'] ) ) {
186 $info[
'badfile'] = (bool)$this->badFileLookup->isBadFile( $title, $badFileContextTitle );
189 $fit = $result->addValue( [
'query',
'pages' ], (
int)$pageId, $info );
191 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
198 $start ??
wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
214 if ( $badFileContextTitle && $finalThumbParams ) {
215 $finalThumbParams[
'targetlang'] = $badFileContextTitle->getPageLanguage()->getCode();
222 ( $start ===
null || $img->getTimestamp() <= $start ) &&
223 (
$params[
'end'] ===
null || $img->getTimestamp() >=
$params[
'end'] )
228 static::getInfo( $img, $prop, $result,
229 $finalThumbParams, $opts
233 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
236 wfTimestamp( TS_ISO_8601, $img->getTimestamp() ) );
247 $count = ( $gotOne ? 1 : 0 );
248 $oldies = $img->getHistory(
$params[
'limit'] - $count + 1, $start,
$params[
'end'] );
250 foreach ( $oldies as $oldie ) {
251 if ( ++$count >
$params[
'limit'] ) {
255 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
257 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
263 static::getInfo( $oldie, $prop, $result,
264 $finalThumbParams, $opts
268 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
270 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
422 public static function getInfo( $file, $prop, $result, $thumbParams =
null, $opts =
false ) {
425 $services = MediaWikiServices::getInstance();
427 if ( !$opts || is_string( $opts ) ) {
429 'version' => $opts ?:
'latest',
430 'language' => $services->getContentLanguage(),
431 'multilang' =>
false,
432 'extmetadatafilter' => [],
433 'revdelUser' =>
null,
436 $version = $opts[
'version'];
438 ApiResult::META_TYPE =>
'assoc',
442 $exists = $file->exists();
446 if ( isset( $prop[
'timestamp'] ) && $exists ) {
447 $vals[
'timestamp'] =
wfTimestamp( TS_ISO_8601, $file->getTimestamp() );
451 if ( isset( $opts[
'revdelUser'] ) && $opts[
'revdelUser'] ) {
452 $revdelUser = $opts[
'revdelUser'];
453 $canShowField =
static function ( $field ) use ( $file, $revdelUser ) {
454 return $file->userCan( $field, $revdelUser );
457 $canShowField =
static function ( $field ) use ( $file ) {
458 return !$file->isDeleted( $field );
462 $user = isset( $prop[
'user'] );
463 $userid = isset( $prop[
'userid'] );
465 if ( ( $user || $userid ) && $exists ) {
466 if ( $file->isDeleted( File::DELETED_USER ) ) {
467 $vals[
'userhidden'] =
true;
470 if ( $canShowField( File::DELETED_USER ) ) {
472 $uploader = $file->getUploader( File::RAW );
474 $vals[
'user'] = $uploader ? $uploader->getName() :
'';
477 $vals[
'userid'] = $uploader ? $uploader->getId() : 0;
479 if ( $uploader && $services->getUserNameUtils()->isTemp( $uploader->getName() ) ) {
480 $vals[
'temp'] =
true;
482 if ( $uploader && !$uploader->isRegistered() ) {
483 $vals[
'anon'] =
true;
490 if ( ( isset( $prop[
'size'] ) || isset( $prop[
'dimensions'] ) ) && $exists ) {
491 $vals[
'size'] = (int)$file->getSize();
492 $vals[
'width'] = (int)$file->getWidth();
493 $vals[
'height'] = (int)$file->getHeight();
495 $pageCount = $file->pageCount();
496 if ( $pageCount !==
false ) {
497 $vals[
'pagecount'] = $pageCount;
501 $length = $file->getLength();
504 $vals[
'duration'] = (float)$length;
508 $pcomment = isset( $prop[
'parsedcomment'] );
509 $comment = isset( $prop[
'comment'] );
511 if ( ( $pcomment || $comment ) && $exists ) {
512 if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
513 $vals[
'commenthidden'] =
true;
516 if ( $canShowField( File::DELETED_COMMENT ) ) {
518 $vals[
'parsedcomment'] = $services->getCommentFormatter()->format(
519 $file->getDescription( File::RAW ), $file->getTitle() );
522 $vals[
'comment'] = $file->getDescription( File::RAW );
527 $canonicaltitle = isset( $prop[
'canonicaltitle'] );
528 $url = isset( $prop[
'url'] );
529 $sha1 = isset( $prop[
'sha1'] );
530 $meta = isset( $prop[
'metadata'] );
531 $extmetadata = isset( $prop[
'extmetadata'] );
532 $commonmeta = isset( $prop[
'commonmetadata'] );
533 $mime = isset( $prop[
'mime'] );
534 $mediatype = isset( $prop[
'mediatype'] );
535 $archive = isset( $prop[
'archivename'] );
536 $bitdepth = isset( $prop[
'bitdepth'] );
537 $uploadwarning = isset( $prop[
'uploadwarning'] );
539 if ( $uploadwarning ) {
540 $vals[
'html'] = SpecialUpload::getExistsWarning( UploadBase::getExistsWarning( $file ) );
543 if ( $file->isDeleted( File::DELETED_FILE ) ) {
544 $vals[
'filehidden'] =
true;
548 if ( $anyHidden && $file->isDeleted( File::DELETED_RESTRICTED ) ) {
549 $vals[
'suppressed'] =
true;
553 if ( isset( $opts[
'revdelUser'] ) && $opts[
'revdelUser']
554 && !$file->userCan( File::DELETED_FILE, $opts[
'revdelUser'] )
557 } elseif ( $file->isDeleted( File::DELETED_FILE ) ) {
561 if ( $canonicaltitle ) {
562 $vals[
'canonicaltitle'] = $file->getTitle()->getPrefixedText();
566 $urlUtils = $services->getUrlUtils();
569 if ( $thumbParams !==
null ) {
570 $mto = $file->transform( $thumbParams );
571 self::$transformCount++;
572 if ( $mto && !$mto->isError() ) {
573 $vals[
'thumburl'] = (string)$urlUtils->expand( $mto->getUrl(),
PROTO_CURRENT );
577 if ( $mto->getUrl() !== $file->getUrl() ) {
578 $vals[
'thumbwidth'] = (int)$mto->getWidth();
579 $vals[
'thumbheight'] = (int)$mto->getHeight();
581 $vals[
'thumbwidth'] = (int)$file->getWidth();
582 $vals[
'thumbheight'] = (int)$file->getHeight();
585 if ( isset( $prop[
'thumbmime'] ) && $file->getHandler() ) {
586 [ , $mime ] = $file->getHandler()->getThumbType(
587 $mto->getExtension(), $file->getMimeType(), $thumbParams );
588 $vals[
'thumbmime'] = $mime;
591 Linker::processResponsiveImages( $file, $mto, [
592 'width' => $vals[
'thumbwidth'],
593 'height' => $vals[
'thumbheight']
595 foreach ( $mto->responsiveUrls as $density => $url ) {
596 $vals[
'responsiveUrls'][$density] = (string)$urlUtils->expand( $url,
PROTO_CURRENT );
598 } elseif ( $mto && $mto->isError() ) {
600 '@phan-var MediaTransformError $mto';
601 $vals[
'thumberror'] = $mto->toText();
604 $vals[
'url'] = (string)$urlUtils->expand( $file->getFullUrl(),
PROTO_CURRENT );
606 $vals[
'descriptionurl'] = (string)$urlUtils->expand( $file->getDescriptionUrl(),
PROTO_CURRENT );
608 $shortDescriptionUrl = $file->getDescriptionShortUrl();
609 if ( $shortDescriptionUrl !==
null ) {
610 $vals[
'descriptionshorturl'] = (string)$urlUtils->expand( $shortDescriptionUrl,
PROTO_CURRENT );
615 $vals[
'filemissing'] =
true;
618 if ( $sha1 && $exists ) {
619 $vals[
'sha1'] = Wikimedia\base_convert( $file->getSha1(), 36, 16, 40 );
622 if ( $meta && $exists ) {
623 $metadata = $file->getMetadataArray();
624 if ( $metadata && $version !==
'latest' ) {
625 $metadata = $file->convertMetadataVersion( $metadata, $version );
627 $vals[
'metadata'] = $metadata ? static::processMetaData( $metadata, $result ) :
null;
629 if ( $commonmeta && $exists ) {
630 $metaArray = $file->getCommonMetaArray();
631 $vals[
'commonmetadata'] = $metaArray ? static::processMetaData( $metaArray, $result ) : [];
634 if ( $extmetadata && $exists ) {
641 $format->getContext()->setLanguage( $opts[
'language'] );
642 $extmetaArray = $format->fetchExtendedMetadata( $file );
643 if ( $opts[
'extmetadatafilter'] ) {
644 $extmetaArray = array_intersect_key(
645 $extmetaArray, array_fill_keys( $opts[
'extmetadatafilter'],
true )
648 $vals[
'extmetadata'] = $extmetaArray;
651 if ( $mime && $exists ) {
652 $vals[
'mime'] = $file->getMimeType();
655 if ( $mediatype && $exists ) {
656 $vals[
'mediatype'] = $file->getMediaType();
659 if ( $archive && $file->isOld() ) {
661 '@phan-var OldLocalFile $file';
662 $vals[
'archivename'] = $file->getArchiveName();
665 if ( $bitdepth && $exists ) {
666 $vals[
'bitdepth'] = $file->getBitDepth();
729 ParamValidator::PARAM_ISMULTI =>
true,
730 ParamValidator::PARAM_DEFAULT =>
'timestamp|user',
731 ParamValidator::PARAM_TYPE => static::getPropertyNames(),
735 ParamValidator::PARAM_TYPE =>
'limit',
736 ParamValidator::PARAM_DEFAULT => 1,
737 IntegerDef::PARAM_MIN => 1,
742 ParamValidator::PARAM_TYPE =>
'timestamp'
745 ParamValidator::PARAM_TYPE =>
'timestamp'
748 ParamValidator::PARAM_TYPE =>
'integer',
749 ParamValidator::PARAM_DEFAULT => -1,
751 'apihelp-query+imageinfo-param-urlwidth',
756 ParamValidator::PARAM_TYPE =>
'integer',
757 ParamValidator::PARAM_DEFAULT => -1
759 'metadataversion' => [
760 ParamValidator::PARAM_TYPE =>
'string',
761 ParamValidator::PARAM_DEFAULT =>
'1',
763 'extmetadatalanguage' => [
764 ParamValidator::PARAM_TYPE =>
'string',
765 ParamValidator::PARAM_DEFAULT =>
766 $this->contentLanguage->getCode(),
768 'extmetadatamultilang' => [
769 ParamValidator::PARAM_TYPE =>
'boolean',
770 ParamValidator::PARAM_DEFAULT =>
false,
772 'extmetadatafilter' => [
773 ParamValidator::PARAM_TYPE =>
'string',
774 ParamValidator::PARAM_ISMULTI =>
true,
777 ParamValidator::PARAM_DEFAULT =>
'',
778 ParamValidator::PARAM_TYPE =>
'string',
780 'badfilecontexttitle' => [
781 ParamValidator::PARAM_TYPE =>
'string',
787 ParamValidator::PARAM_TYPE =>
'boolean',
788 ParamValidator::PARAM_DEFAULT =>
false,