Status | Subtype | Assigned | Task | ||
---|---|---|---|---|---|
Open | BUG REPORT | CKoerner_WMF | T309101 Allow video embedding from Wikimedia Commons at Diff | ||
Open | Feature | None | T364479 Allow media embedding from Wikimedia Commons using oEmbed | ||
Resolved | valerio.bozzolan | T388972 Understand how to create a new MediaWiki API (in core?) for oEmbed protocol management |
Event Timeline
Looking at all available APIs - https://www.mediawiki.org/w/api.php - to understand where somebody should propose something like this.
Considerations:
- 🔶 action=query probably nonsense to expand its children calls, since
- 💚 action=oembed may make sense at least for this prototype
P.S. since it does not make sense to try, I tried to use https://duck.ai using LLAMA 90B parameters with the prompt:
How should be named the new MediaWiki API that manages oembed protocol, under /w/api.php`
First answers (links deactivated, but look at action=something):
- https:// example.com/w/api.php?action=oembed&url=https:// example.com/wiki/File:Example.jpg
- https:// example.com/w/api.php?action=embed&url=https:// example.com/wiki/File:Example.jpg
- https:// example.com/w/api.php?action=mediaembed&url=https:// example.com/wiki/File:Example.jpg
- https:// example.com/w/api.php?action=oembedprovider&url=https:// example.com/wiki/File:Example.jpg
So I guess I will continue documenting myself about creating action=oembed since it makes some sense
Dear Diary,
Registering a new MediaWiki API was true fun. Here the friends I've met in this travel:
- I needed a fresh MediaWiki copy from latest
mainmaster branch from MediaWiki core- uhm interestingly in WMIT and WMCH I've invested hours in migrating the git branches from "master" to "main" after reading this Wikimedia discussion T254646, aaand wow I notice for the first time that MediaWiki core is still on "master". It makes sense for legacy reasons but I really never noticed that. Maybe knowing this would have helped me ignore it in other projects, or reduce this priority. lol
- the branch topic of mw core is covered here if you are interested, after a bit of digging: T377562: Rename mainline Git branch of MediaWiki core, extensions and skins from "master" to "main"
- uhm interestingly in WMIT and WMCH I've invested hours in migrating the git branches from "master" to "main" after reading this Wikimedia discussion T254646, aaand wow I notice for the first time that MediaWiki core is still on "master". It makes sense for legacy reasons but I really never noticed that. Maybe knowing this would have helped me ignore it in other projects, or reduce this priority. lol
- interestingly if you need to "run MediaWiki in Docker" you risk to land here: https://www.mediawiki.org/wiki/Docker/Hub
- but after 1 hour I've discovered that...
- it's the wrong page for everyday development. The real page for local development is: https://www.mediawiki.org/wiki/MediaWiki-Docker lol and nothing mentions it from there
- fixed/mitigated lol https://www.mediawiki.org/w/index.php?title=Docker%2FHub&diff=7478708&oldid=6855943
- in short, people should ignore the on-wiki documentation and just read DEVELOPERS.txt 👍 - https://gerrit.wikimedia.org/g/mediawiki/core/+/HEAD/DEVELOPERS.md
- fixed/mitigated lol https://www.mediawiki.org/w/index.php?title=Docker%2FHub&diff=7478708&oldid=6855943
- it's the wrong page for everyday development. The real page for local development is: https://www.mediawiki.org/wiki/MediaWiki-Docker lol and nothing mentions it from there
- but after 1 hour I've discovered that...
- Assuming that creating a core API was a good idea for this basic task, I've explored the codebase and found this nice home for APIs https://phabricator.wikimedia.org/source/mediawiki/browse/master/includes/api/
- Instead of writing something from scratch I've examined what would be a "similar" API to start from, using these mental criteria:
- API that may have a small amount of arguments
- ... may have non-complicated output (not with generators)
- ... may have small business logic
- ... may receive/validate a page title
- ... and with a non-esoteric / non-weird name/workflow lol
- therefore I've forked includes/api/ApiMove.php that was right under my eyes - really no other attempt to look at other things
- I've then created the file includes/api/ApiOEmbed.php from that
- I've adapted my class to do not act in "write-mode" and be "read-mode" instead
- basically dropping methods, since the base class already assumes no CSRF needed and no writes etc.
- see specific with write-mode: https://phabricator.wikimedia.org/source/mediawiki/browse/master/includes/api/ApiMove.php;5ddf4037f273ff82532a890ea1f9827f78f65814$229-235
- see generic already in read-mode: https://phabricator.wikimedia.org/source/mediawiki/browse/master/includes/api/ApiBase.php;5ddf4037f273ff82532a890ea1f9827f78f65814$451-453
- at this point the website was still working but the API was not listed
- 🔶 I guessed that Phabricator had an autoloader file with all the classes hardcoded in it (that may sounds obvious - but in other projects there is some PHP reflection in place to do this automagically - not in MediaWiki I guess)
- So I've found autoload.php and I tried to understand how to generate it
- THANKS MEDIAWIKI HACKERS for your commit messages in git log autoload.php and at least one commit was mentioning this: https://www.mediawiki.org/wiki/Manual:GenerateLocalAutoload.php
- So I've triggered it with: docker compose exec mediawiki php maintenance/run.php generateLocalAutoload
- it worked 🎉
- 🔶 Well, I hope that an automatic local thing somewhere would have helped me find this problem if I had been a novice. I'd be curious to know how people are supposed to discover this in general. For example in Phorge there is a lint error for this - maybe also in MediaWiki but really I don't know how to test this thing - if you know how to run this class lint (?) please share thanks
- uhm API still not listed here http://localhost:9000/w/api.php
- I've used grep -R 'ApiMove' . and then grep -R 'ApiMove::class' . and
OLLAMA 70Bto discover to dig inside ./includes/api/ApiMain.php - I was quite fascinated to see this old-fashioned array-based data structure with class name and services https://phabricator.wikimedia.org/source/mediawiki/browse/master/includes/api/ApiMain.php;5ddf4037f273ff82532a890ea1f9827f78f65814$0-92
- 🔶 we should create a task in MediaWiki-General (?) to introduce a PHP class (ApiModule ?) that defines these API modules IMVHO with a simple constructor of 2 args (string class and array services), and add a TODO in the code there as cross-reference to that task (dummy-patch). Reasons: this would reduce code, reduce possibility of typos, and would make the codebase a bit less PHP4 year 2000 when we had not PHP classes. I love putting PHP classes where we should introduce PHP classes. Downside: we add a file, but hey, we reduce the other file dimension, so it worth it to make future developers more happy and static analyzers more happy.
- probably this cleanup is a very good first task since that constant is private and only called here: https://phabricator.wikimedia.org/source/mediawiki/browse/master/includes/api/ApiMain.php;5ddf4037f273ff82532a890ea1f9827f78f65814$694
- probably it would require to move that ApiMain::MODULES from a constant to a static method - but again that's feasible since just 1 caller, no refactors needed
- 🔶 proposed quality assurance: check if this class ApiMain is supposed to be instantiated twice in the lifecycle of MediaWiki. If yes, remember to statically cache the result of this new ApiMain::MODULES method.
- probably it would require to move that ApiMain::MODULES from a constant to a static method - but again that's feasible since just 1 caller, no refactors needed
- 🔶 I also don't understand if these APIs have some kind of sort by... something? https://phabricator.wikimedia.org/source/mediawiki/browse/master/includes/api/ApiMain.php;5ddf4037f273ff82532a890ea1f9827f78f65814$694
- 🔶 I think they have no particular order. This means somebody, one day, will probably sort them by their own criteria, making git history not better.
- I will just be nice and append to the end lol like anybody else I guess
- probably this cleanup is a very good first task since that constant is private and only called here: https://phabricator.wikimedia.org/source/mediawiki/browse/master/includes/api/ApiMain.php;5ddf4037f273ff82532a890ea1f9827f78f65814$694
- 🔶 we should create a task in MediaWiki-General (?) to introduce a PHP class (ApiModule ?) that defines these API modules IMVHO with a simple constructor of 2 args (string class and array services), and add a TODO in the code there as cross-reference to that task (dummy-patch). Reasons: this would reduce code, reduce possibility of typos, and would make the codebase a bit less PHP4 year 2000 when we had not PHP classes. I love putting PHP classes where we should introduce PHP classes. Downside: we add a file, but hey, we reduce the other file dimension, so it worth it to make future developers more happy and static analyzers more happy.
- I've used grep -R 'ApiMove' . and then grep -R 'ApiMove::class' . and
- manually added - it works lol
Very shortly, you need:
diff --git a/autoload.php b/autoload.php index 31e2fdba1bd..9beee60b5c7 100644 --- a/autoload.php +++ b/autoload.php @@ -837,6 +837,7 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\Api\\ApiMessageTrait' => __DIR__ . '/includes/api/ApiMessageTrait.php', 'MediaWiki\\Api\\ApiModuleManager' => __DIR__ . '/includes/api/ApiModuleManager.php', 'MediaWiki\\Api\\ApiMove' => __DIR__ . '/includes/api/ApiMove.php', + 'MediaWiki\\Api\\ApiOembed' => __DIR__ . '/includes/api/ApiOembed.php', 'MediaWiki\\Api\\ApiOpenSearch' => __DIR__ . '/includes/api/ApiOpenSearch.php', 'MediaWiki\\Api\\ApiOpenSearchFormatJson' => __DIR__ . '/includes/api/ApiOpenSearchFormatJson.php', 'MediaWiki\\Api\\ApiOptions' => __DIR__ . '/includes/api/ApiOptions.php', diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index 956c901b3df..4154b2c369e 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -486,6 +486,9 @@ class ApiMain extends ApiBase { 'TempUserCreator', ] ], + 'oembed' => [ + 'class' => ApiOEmbed::class, + ], ]; /** diff --git a/includes/api/ApiOEmbed.php b/includes/api/ApiOEmbed.php new file mode 100644 index 00000000000..69031543e19 --- /dev/null +++ b/includes/api/ApiOEmbed.php @@ -0,0 +1,81 @@ +<?php +/** + * Copyright © 2025 Valerio Bozzolan <nsa+mediawiki@succhia.cz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +namespace MediaWiki\Api; + +use LogicException; +use MediaWiki\MainConfigNames; +use MediaWiki\Page\MovePageFactory; +use MediaWiki\Status\Status; +use MediaWiki\Title\Title; +use MediaWiki\User\Options\UserOptionsLookup; +use MediaWiki\Watchlist\WatchlistManager; +use RepoGroup; +use Wikimedia\ParamValidator\ParamValidator; + +/** + * API Module to move pages + * @ingroup API + */ +class ApiOEmbed extends ApiBase { + + public function __construct( + ApiMain $mainModule, + string $moduleName + ) { + parent::__construct( $mainModule, $moduleName ); + } + + public function execute() { + $params = $this->extractRequestParams(); + $this->requireOnlyOneParameter( $params, 'title' ); + $title = Title::newFromText( $params['title'] ); + if ( !$title || $title->isExternal() ) { + $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] ); + } + + $result = $this->getResult(); + $result->addValue( null, "asd", $params['title'] ); + } + + public function getAllowedParams() { + return [ + 'title' => [ + ParamValidator::PARAM_TYPE => 'string', + ParamValidator::PARAM_REQUIRED => true + ], + ]; + } + + protected function getExamplesMessages() { + $title = Title::newMainPage()->getPrefixedText(); + $mp = rawurlencode( $title ); + return [ + 'action=oembed&title={$title}' + => 'apihelp-query+oembed-example-simple', + ]; + } + + public function getHelpUrls() { + return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Oembed'; + } +}
\o/
\o/
Lol. Putting 7 story points but probably more. I've really enjoyed the friends met in this small travel. asd
Now I can concentrate in the oEmbed business logic.
Let's continue in T364479: Allow media embedding from Wikimedia Commons using oEmbed