2012-03-01 17:37:16 +00:00
|
|
|
<?php
|
2015-11-16 14:59:34 +00:00
|
|
|
|
2020-04-19 22:41:19 +00:00
|
|
|
namespace PageImages;
|
|
|
|
|
|
|
|
use ApiBase;
|
|
|
|
use ApiQuery;
|
|
|
|
use ApiQueryBase;
|
2023-08-19 04:18:19 +00:00
|
|
|
use MediaWiki\Title\Title;
|
2023-10-15 19:41:43 +00:00
|
|
|
use RepoGroup;
|
2022-04-03 23:28:52 +00:00
|
|
|
use Wikimedia\ParamValidator\ParamValidator;
|
2022-04-03 20:16:07 +00:00
|
|
|
use Wikimedia\ParamValidator\TypeDef\IntegerDef;
|
2020-04-04 15:34:58 +00:00
|
|
|
|
2013-07-07 18:58:56 +00:00
|
|
|
/**
|
|
|
|
* Expose image information for a page via a new prop=pageimages API.
|
2015-11-16 14:59:34 +00:00
|
|
|
*
|
|
|
|
* @see https://www.mediawiki.org/wiki/Extension:PageImages#API
|
|
|
|
*
|
2018-05-25 04:42:29 +00:00
|
|
|
* @license WTFPL
|
2015-11-17 08:54:24 +00:00
|
|
|
* @author Max Semenik
|
2015-11-16 14:59:34 +00:00
|
|
|
* @author Ryan Kaldari
|
|
|
|
* @author Yuvi Panda
|
|
|
|
* @author Sam Smith
|
2013-07-07 18:58:56 +00:00
|
|
|
*/
|
2012-03-01 17:37:16 +00:00
|
|
|
class ApiQueryPageImages extends ApiQueryBase {
|
2023-10-15 19:41:43 +00:00
|
|
|
/** @var RepoGroup */
|
|
|
|
private $repoGroup;
|
|
|
|
|
2016-03-07 08:47:51 +00:00
|
|
|
/**
|
2017-12-06 21:02:05 +00:00
|
|
|
* @param ApiQuery $query API query module
|
|
|
|
* @param string $moduleName Name of this query module
|
2023-10-15 19:41:43 +00:00
|
|
|
* @param RepoGroup $repoGroup
|
2016-03-07 08:47:51 +00:00
|
|
|
*/
|
2023-10-15 19:41:43 +00:00
|
|
|
public function __construct(
|
|
|
|
ApiQuery $query,
|
|
|
|
$moduleName,
|
|
|
|
RepoGroup $repoGroup
|
|
|
|
) {
|
2012-03-01 17:37:16 +00:00
|
|
|
parent::__construct( $query, $moduleName, 'pi' );
|
2023-10-15 19:41:43 +00:00
|
|
|
$this->repoGroup = $repoGroup;
|
2012-03-01 17:37:16 +00:00
|
|
|
}
|
|
|
|
|
2015-10-02 08:58:54 +00:00
|
|
|
/**
|
|
|
|
* Gets the set of titles to get page images for.
|
|
|
|
*
|
|
|
|
* Note well that the set of titles comprises the set of "good" titles
|
|
|
|
* (see {@see ApiPageSet::getGoodTitles}) union the set of "missing"
|
|
|
|
* titles in the File namespace that might correspond to foreign files.
|
|
|
|
* The latter are included because titles in the File namespace are
|
2022-07-07 20:04:36 +00:00
|
|
|
* expected to be found with {@see \RepoGroup::findFile}.
|
2015-10-02 08:58:54 +00:00
|
|
|
*
|
2015-10-31 01:30:18 +00:00
|
|
|
* @return Title[] A map of page ID, which will be negative in the case
|
2015-10-02 08:58:54 +00:00
|
|
|
* of missing titles in the File namespace, to Title object
|
|
|
|
*/
|
|
|
|
protected function getTitles() {
|
|
|
|
$pageSet = $this->getPageSet();
|
|
|
|
$titles = $pageSet->getGoodTitles();
|
|
|
|
|
|
|
|
// T98791: We want foreign files to be treated like local files
|
|
|
|
// in #execute, so include the set of missing filespace pages,
|
|
|
|
// which were initially rejected in ApiPageSet#execute.
|
|
|
|
$missingTitles = $pageSet->getMissingTitlesByNamespace();
|
2019-03-11 03:22:21 +00:00
|
|
|
$missingFileTitles = $missingTitles[NS_FILE] ?? [];
|
2015-10-02 08:58:54 +00:00
|
|
|
|
|
|
|
// $titles is a map of ID to title object, which is ideal,
|
|
|
|
// whereas $missingFileTitles is a map of title text to ID.
|
2019-10-31 21:16:14 +00:00
|
|
|
// Do not use array_merge here as it doesn't preserve keys.
|
|
|
|
foreach ( $missingFileTitles as $dbkey => $id ) {
|
|
|
|
$titles[$id] = Title::makeTitle( NS_FILE, $dbkey );
|
2015-10-01 21:23:23 +00:00
|
|
|
}
|
2015-10-02 08:58:54 +00:00
|
|
|
|
|
|
|
return $titles;
|
|
|
|
}
|
|
|
|
|
2017-12-06 22:44:34 +00:00
|
|
|
/**
|
|
|
|
* Evaluates the parameters, performs the requested retrieval of page images,
|
|
|
|
* and sets up the result
|
|
|
|
*/
|
2015-10-02 08:58:54 +00:00
|
|
|
public function execute() {
|
2012-03-01 17:37:16 +00:00
|
|
|
$params = $this->extractRequestParams();
|
|
|
|
$prop = array_flip( $params['prop'] );
|
2012-03-05 21:36:43 +00:00
|
|
|
if ( !count( $prop ) ) {
|
2018-08-18 15:52:45 +00:00
|
|
|
$this->dieWithError(
|
|
|
|
[ 'apierror-paramempty', $this->encodeParamName( 'prop' ) ], 'noprop'
|
|
|
|
);
|
2012-03-05 21:36:43 +00:00
|
|
|
}
|
2012-03-01 17:37:16 +00:00
|
|
|
|
2015-10-02 08:58:54 +00:00
|
|
|
$allTitles = $this->getTitles();
|
|
|
|
|
|
|
|
if ( count( $allTitles ) === 0 ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-07 18:58:56 +00:00
|
|
|
// Find the offset based on the continue param
|
|
|
|
$offset = 0;
|
2012-03-05 21:36:43 +00:00
|
|
|
if ( isset( $params['continue'] ) ) {
|
2013-07-07 18:58:56 +00:00
|
|
|
// Get the position (not the key) of the 'continue' page within the
|
|
|
|
// array of titles. Set this as the offset.
|
|
|
|
$pageIds = array_keys( $allTitles );
|
|
|
|
$offset = array_search( intval( $params['continue'] ), $pageIds );
|
|
|
|
// If the 'continue' page wasn't found, die with error
|
2016-11-03 19:16:56 +00:00
|
|
|
$this->dieContinueUsageIf( !$offset );
|
2012-03-05 21:36:43 +00:00
|
|
|
}
|
2013-07-07 18:58:56 +00:00
|
|
|
|
2016-11-10 00:02:00 +00:00
|
|
|
$limit = $params['limit'];
|
2013-07-07 18:58:56 +00:00
|
|
|
// Slice the part of the array we want to find images for
|
|
|
|
$titles = array_slice( $allTitles, $offset, $limit, true );
|
|
|
|
|
|
|
|
// Get the next item in the title array and use it to set the continue value
|
|
|
|
$nextItemArray = array_slice( $allTitles, $offset + $limit, 1, true );
|
|
|
|
if ( $nextItemArray ) {
|
|
|
|
$this->setContinueEnumParameter( 'continue', key( $nextItemArray ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find any titles in the file namespace so we can handle those separately
|
2016-11-21 23:29:28 +00:00
|
|
|
$filePageTitles = [];
|
2013-07-07 18:58:56 +00:00
|
|
|
foreach ( $titles as $id => $title ) {
|
|
|
|
if ( $title->inNamespace( NS_FILE ) ) {
|
|
|
|
$filePageTitles[$id] = $title;
|
|
|
|
unset( $titles[$id] );
|
2012-05-08 21:42:07 +00:00
|
|
|
}
|
2013-07-07 18:58:56 +00:00
|
|
|
}
|
|
|
|
|
2016-11-10 00:02:00 +00:00
|
|
|
$size = $params['thumbsize'];
|
2020-08-12 10:32:53 +00:00
|
|
|
$lang = $params['langcode'];
|
2013-07-07 18:58:56 +00:00
|
|
|
// Extract page images from the page_props table
|
|
|
|
if ( count( $titles ) > 0 ) {
|
|
|
|
$this->addTables( 'page_props' );
|
2016-11-21 23:29:28 +00:00
|
|
|
$this->addFields( [ 'pp_page', 'pp_propname', 'pp_value' ] );
|
|
|
|
$this->addWhere( [ 'pp_page' => array_keys( $titles ),
|
2020-04-20 13:34:12 +00:00
|
|
|
'pp_propname' => PageImages::getPropNames( $params['license'] ) ] );
|
2013-07-07 18:58:56 +00:00
|
|
|
|
|
|
|
$res = $this->select( __METHOD__ );
|
|
|
|
|
2016-11-10 00:02:00 +00:00
|
|
|
$buffer = [];
|
|
|
|
$propNameAny = PageImages::getPropName( false );
|
2013-07-07 18:58:56 +00:00
|
|
|
foreach ( $res as $row ) {
|
|
|
|
$pageId = $row->pp_page;
|
2016-11-10 00:02:00 +00:00
|
|
|
if ( !array_key_exists( $pageId, $buffer ) || $row->pp_propname === $propNameAny ) {
|
|
|
|
$buffer[$pageId] = $row;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ( $buffer as $pageId => $row ) {
|
2013-07-07 18:58:56 +00:00
|
|
|
$fileName = $row->pp_value;
|
2020-08-12 10:32:53 +00:00
|
|
|
$this->setResultValues( $prop, $pageId, $fileName, $size, $lang );
|
2012-05-08 21:42:07 +00:00
|
|
|
}
|
2017-12-06 21:59:16 +00:00
|
|
|
// End page props image extraction
|
|
|
|
}
|
2013-07-07 18:58:56 +00:00
|
|
|
|
|
|
|
// Extract images from file namespace pages. In this case we just use
|
|
|
|
// the file itself rather than searching for a page_image. (Bug 50252)
|
|
|
|
foreach ( $filePageTitles as $pageId => $title ) {
|
|
|
|
$fileName = $title->getDBkey();
|
2020-08-12 10:32:53 +00:00
|
|
|
$this->setResultValues( $prop, $pageId, $fileName, $size, $lang );
|
2012-03-01 17:37:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-06 22:44:34 +00:00
|
|
|
/**
|
|
|
|
* Get the cache mode for the data generated by this module
|
|
|
|
*
|
|
|
|
* @param array $params Ignored parameters
|
|
|
|
* @return string Always returns "public"
|
|
|
|
*/
|
2014-03-29 11:47:53 +00:00
|
|
|
public function getCacheMode( $params ) {
|
|
|
|
return 'public';
|
|
|
|
}
|
|
|
|
|
2013-07-07 18:58:56 +00:00
|
|
|
/**
|
|
|
|
* For a given page, set API return values for thumbnail and pageimage as needed
|
|
|
|
*
|
|
|
|
* @param array $prop The prop values from the API request
|
2015-10-31 01:30:18 +00:00
|
|
|
* @param int $pageId The ID of the page
|
2013-07-07 18:58:56 +00:00
|
|
|
* @param string $fileName The name of the file to transform
|
2015-10-31 01:30:18 +00:00
|
|
|
* @param int $size The thumbsize value from the API request
|
2020-08-12 10:32:53 +00:00
|
|
|
* @param string $lang The language code from the API request
|
2013-07-07 18:58:56 +00:00
|
|
|
*/
|
2020-08-12 10:32:53 +00:00
|
|
|
protected function setResultValues( array $prop, $pageId, $fileName, $size, $lang ) {
|
2016-11-21 23:29:28 +00:00
|
|
|
$vals = [];
|
2015-04-03 19:11:28 +00:00
|
|
|
if ( isset( $prop['thumbnail'] ) || isset( $prop['original'] ) ) {
|
2023-10-15 19:41:43 +00:00
|
|
|
$file = $this->repoGroup->findFile( $fileName );
|
2016-11-03 18:27:32 +00:00
|
|
|
if ( $file ) {
|
|
|
|
if ( isset( $prop['thumbnail'] ) ) {
|
2020-08-12 10:32:53 +00:00
|
|
|
$thumb = $file->transform( [
|
|
|
|
'width' => $size,
|
|
|
|
'lang' => $lang
|
|
|
|
] );
|
2015-04-02 23:06:16 +00:00
|
|
|
if ( $thumb && $thumb->getUrl() ) {
|
2016-02-27 19:27:11 +00:00
|
|
|
// You can request a thumb 1000x larger than the original
|
|
|
|
// which (in case of bitmap original) will return a Thumb object
|
|
|
|
// that will lie about its size but have the original as an image.
|
|
|
|
$reportedSize = $thumb->fileIsSource() ? $file : $thumb;
|
2016-11-21 23:29:28 +00:00
|
|
|
$vals['thumbnail'] = [
|
2015-04-02 23:06:16 +00:00
|
|
|
'source' => wfExpandUrl( $thumb->getUrl(), PROTO_CURRENT ),
|
2016-02-27 19:27:11 +00:00
|
|
|
'width' => $reportedSize->getWidth(),
|
|
|
|
'height' => $reportedSize->getHeight(),
|
2016-11-21 23:29:28 +00:00
|
|
|
];
|
2015-04-02 23:06:16 +00:00
|
|
|
}
|
2013-07-07 18:58:56 +00:00
|
|
|
}
|
2015-04-02 23:06:16 +00:00
|
|
|
|
2016-11-03 18:27:32 +00:00
|
|
|
if ( isset( $prop['original'] ) ) {
|
2020-08-12 10:32:53 +00:00
|
|
|
$originalSize = [
|
|
|
|
'width' => $file->getWidth(),
|
|
|
|
'height' => $file->getHeight()
|
|
|
|
];
|
|
|
|
if ( $lang ) {
|
|
|
|
$file = $file->transform( [
|
|
|
|
'lang' => $lang,
|
|
|
|
'width' => $originalSize['width'],
|
|
|
|
'height' => $originalSize['height']
|
|
|
|
] );
|
|
|
|
}
|
2016-11-03 18:27:32 +00:00
|
|
|
$original_url = wfExpandUrl( $file->getUrl(), PROTO_CURRENT );
|
2016-12-02 22:09:55 +00:00
|
|
|
|
|
|
|
$vals['original'] = [
|
|
|
|
'source' => $original_url,
|
2020-08-12 10:32:53 +00:00
|
|
|
'width' => $originalSize['width'],
|
|
|
|
'height' => $originalSize['height']
|
2016-12-02 22:09:55 +00:00
|
|
|
];
|
2015-04-03 19:11:28 +00:00
|
|
|
}
|
2015-04-02 23:06:16 +00:00
|
|
|
}
|
2013-07-07 18:58:56 +00:00
|
|
|
}
|
2015-04-02 23:06:16 +00:00
|
|
|
|
2013-07-07 18:58:56 +00:00
|
|
|
if ( isset( $prop['name'] ) ) {
|
|
|
|
$vals['pageimage'] = $fileName;
|
|
|
|
}
|
2015-04-02 23:06:16 +00:00
|
|
|
|
2016-11-21 23:29:28 +00:00
|
|
|
$this->getResult()->addValue( [ 'query', 'pages' ], $pageId, $vals );
|
2013-07-07 18:58:56 +00:00
|
|
|
}
|
|
|
|
|
2017-12-06 22:44:34 +00:00
|
|
|
/**
|
|
|
|
* Return an array describing all possible parameters to this module
|
|
|
|
* @return array
|
|
|
|
*/
|
2012-03-01 17:37:16 +00:00
|
|
|
public function getAllowedParams() {
|
2016-11-21 23:29:28 +00:00
|
|
|
return [
|
|
|
|
'prop' => [
|
2022-04-03 23:28:52 +00:00
|
|
|
ParamValidator::PARAM_TYPE => [ 'thumbnail', 'name', 'original' ],
|
|
|
|
ParamValidator::PARAM_ISMULTI => true,
|
|
|
|
ParamValidator::PARAM_DEFAULT => 'thumbnail|name',
|
2023-08-05 00:20:47 +00:00
|
|
|
ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
|
2016-11-21 23:29:28 +00:00
|
|
|
],
|
|
|
|
'thumbsize' => [
|
2022-04-03 23:28:52 +00:00
|
|
|
ParamValidator::PARAM_TYPE => 'integer',
|
|
|
|
ParamValidator::PARAM_DEFAULT => 50,
|
2016-11-21 23:29:28 +00:00
|
|
|
],
|
|
|
|
'limit' => [
|
2022-04-03 23:28:52 +00:00
|
|
|
ParamValidator::PARAM_DEFAULT => 50,
|
|
|
|
ParamValidator::PARAM_TYPE => 'limit',
|
2022-04-03 20:16:07 +00:00
|
|
|
IntegerDef::PARAM_MIN => 1,
|
|
|
|
IntegerDef::PARAM_MAX => 50,
|
|
|
|
IntegerDef::PARAM_MAX2 => 100,
|
2016-11-21 23:29:28 +00:00
|
|
|
],
|
2016-11-10 00:02:00 +00:00
|
|
|
'license' => [
|
2022-04-03 23:28:52 +00:00
|
|
|
ParamValidator::PARAM_TYPE => [ PageImages::LICENSE_FREE, PageImages::LICENSE_ANY ],
|
|
|
|
ParamValidator::PARAM_ISMULTI => false,
|
|
|
|
ParamValidator::PARAM_DEFAULT => $this->getConfig()->get( 'PageImagesAPIDefaultLicense' ),
|
2023-08-05 00:20:47 +00:00
|
|
|
ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
|
2016-11-10 00:02:00 +00:00
|
|
|
],
|
2016-11-21 23:29:28 +00:00
|
|
|
'continue' => [
|
2022-04-03 23:28:52 +00:00
|
|
|
ParamValidator::PARAM_TYPE => 'integer',
|
2018-04-25 19:46:58 +00:00
|
|
|
ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
|
2016-11-21 23:29:28 +00:00
|
|
|
],
|
2020-08-12 10:32:53 +00:00
|
|
|
'langcode' => [
|
2022-04-03 23:28:52 +00:00
|
|
|
ParamValidator::PARAM_TYPE => 'string',
|
|
|
|
ParamValidator::PARAM_DEFAULT => null
|
2020-08-12 10:32:53 +00:00
|
|
|
]
|
2016-11-21 23:29:28 +00:00
|
|
|
];
|
2012-03-01 17:37:16 +00:00
|
|
|
}
|
|
|
|
|
2015-02-09 21:06:49 +00:00
|
|
|
/**
|
2017-12-06 21:15:51 +00:00
|
|
|
* @inheritDoc
|
2015-02-09 21:06:49 +00:00
|
|
|
*/
|
|
|
|
protected function getExamplesMessages() {
|
2016-11-21 23:29:28 +00:00
|
|
|
return [
|
2015-02-09 21:06:49 +00:00
|
|
|
'action=query&prop=pageimages&titles=Albert%20Einstein&pithumbsize=100' =>
|
|
|
|
'apihelp-query+pageimages-example-1',
|
2016-11-21 23:29:28 +00:00
|
|
|
];
|
2015-02-09 21:06:49 +00:00
|
|
|
}
|
|
|
|
|
2017-12-06 22:44:34 +00:00
|
|
|
/**
|
|
|
|
* @see ApiBase::getHelpUrls()
|
|
|
|
* @return string
|
|
|
|
*/
|
2016-12-02 18:39:07 +00:00
|
|
|
public function getHelpUrls() {
|
|
|
|
return "https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:PageImages#API";
|
|
|
|
}
|
|
|
|
|
2013-07-07 18:58:56 +00:00
|
|
|
}
|