mediawiki-extensions-EmbedVideo
mediawiki-extensions-EmbedVideo copied to clipboard
Support embedding external videos in galleries
Detailed Description
There should be a way for people to embed external videos from sites that EmbedVideo supports in galleries.
Context
Embedding videos in galleries is fairly common on enthusiast wiki sites, and a lot of them prefer to embed from somewhere like YouTube rather than a locally uploaded .mp4 file or something.
Possible Implementation
I have looked into possible implementations for this already for use on Weird Gloop's wikis, and discovered:
- Fandom (and previously Gamepedia) use some kind of "fake" File handlers and have users "upload" external video (not the actual video, but some metadata representing it) so that they can be used in galleries without core modifications.
- There doesn't really seem to be a good way of using gallery-related hooks in core MediaWiki to achieve simply allowing EmbedVideo parser tags to be used in galleries and parsed correctly. Both BeforeParserFetchFileAndTitle and AfterParserFetchFileAndTitle seem unsuitable.
- We could potentially overwrite the core MediaWiki parser tag for
to run through a method that we have in EV first, convert the syntax to something more palatable for the core MW code (like a fake file name) and then bounce it back to core's handler method ( Parser::renderImageGallery), but this may make EV incompatible with other extensions that behave similarly. This is also probably an anti-pattern to what WMF would like in MW extensions.
Interested in thoughts on other potential implementations.
Extension:Video already has this functionality — albeit it renders its own <videogallery> tag, which is similar, but doesn't support also having images within the gallery alongside videos. Perhaps some inspiration could be taken from how that's done.
Although thinking about it, the Video extension is a bit of a mess, so perhaps taking inspo from that extension is not wise.
So I've had a first look at Parser::renderImageGallery to see how titles are retrieved.
The following parts directly filter out all lines in a gallery tag that do not conform to a "normal" page title. Parser.php#5178
$matches = [];
preg_match( "/^([^|]+)(\\|(.*))?$/", $line, $matches );
/// .....
$title = Title::newFromText( $matches[1], NS_FILE );
if ( $title === null ) {
# Bogus title. Ignore these so we don't bomb out later.
continue;
}
I'm personally not fond of overwriting large core MW files, so I think we have two options here:
- Introduce a separate gallery tag handling files and embeds
- Automatically create
File:pages for each used embed (like Fandom)
My preference lies with option 2, as this way, the core gallery logic is left untouched removing a lot of maintenance effort.
Initial ideas
Without having looked into the feasibility.
- Utilizing the job queue, dispatch a job somewhere around EmbedVideo::output
- Create a file page (if not exists) in the form of
File:ID.ServiceorFile:Video Title.service? - Load metadata from available OEmbed endpoints (if available)
- Introduce a mediahandler covering each service extension e.g.
File:foo.youtube,File:bar.spotify
The mediahandler in question would really just need to call EmbedVideo::output to generate the html.
Ideas on this, or oversights on my part? @jayktaylor @OAuthority
It looks like Parser::renderImageGallery only calls Parser::recursiveTagParse when handling the caption of each image in the gallery, so I'm unsure as to how you would automatically create File pages for the embeds since you can't just do this:
<gallery>
{{#ev:youtube|whatever}}
</gallery>
Relevant code:
if ( isset( $matches[3] ) ) {
// look for an |alt= definition while trying not to break existing
// captions with multiple pipes (|) in it, until a more sensible grammar
// is defined for images in galleries
// FIXME: Doing recursiveTagParse at this stage, and the trim before
// splitting on '|' is a bit odd, and different from makeImage.
$matches[3] = $this->recursiveTagParse( trim( $matches[3] ) );
// Protect LanguageConverter markup
$parameterMatches = StringUtils::delimiterExplode(
'-{', '}-',
'|',
$matches[3],
true /* nested */
);
}
It seems like if we wanted to do it, then core MW would need to be changed to support expanding tags before running the main part of the code in renderImageGallery (or equally, allow us to use a hook that runs before it). Only then could we intercept the {{#ev:}} tag, somehow figure out that we're inside of a <gallery>, and then generate a File page and replace the tag with the appropriate file page at parse time. Of course, if we don't want to do it automatically then we can go the Fandom route and give users a button to press to create a new File page based on some YouTube link or whatever, but that seems counter-intuitive to the way that the extension is already used/existing syntax.
Though I agree with the rest of your assessment that Fandom's approach with media handlers and File namespace pages is probably the most viable method.
Is there something I'm missing that would make this possible to achieve without submitting an MW core patch to give us a new hook?
Ah indeed, I've assumed that a separate embed outside a gallery would exist, which would have allowed to automatically create a relevant file page.
So from my current understanding we would indeed need to submit some kind of patch to MW core.
Speaking of, in order for this to get merged (faster), the introduced patch / hook would need to be relatively small.
When going the File NS approach, how about hooking into:
$matches = [];
preg_match( "/^([^|]+)(\\|(.*))?$/", $line, $matches );
// Newly introduced hook, name up for debate
$this->hookRunner->onAfterParserMatchGalleryFile(
$this, $line, &$matches
);
Which would allow registering some kind of file, and replacing the matches with a structure that MW understands.
I'll try to do a POC to see if this is feasible.
I don't have anything to add that Jayden hasn't already said, but I am thinking about something else. After this file page is created, it would be nice for some kind of check to potentially be performed to ensure that duplicate videos aren't uploaded (obviously this would depend on the way the name is generated for the file page.)
Furthermore, once a video is uploaded, would we want an embed to become eligible to add to a gallery without using {{#ev|}} syntax for another article? (I would presume yes).
Some preliminary previews for the mentioned POC.
It is not perfect by any means, but the initial idea of automatically creating a file page does seem to work.
When adding an embed to a page for example {{#ev:youtube|-4FPIL6e4SQ}}, a file page automatically created if it does not exist.
To ensure that no duplicates are created EmbedVideo is creating file pages in the form of File:ID.Service, which in the previously mentioned case would result in File:-4FPIL6e4SQ.youtube.
To then output something on the file page, a file handler calls EmbedHtmlFormatter::makeIframe, outputting a plain iframe (ignoring any consent settings).
While this does seem to work, there are also problems, namely the duplicate file detection employed by MW.
The current process uses empty files in order for the upload to succeed, but this results in:
Some other issues include:
- manually having to overwrite the mime type
- not being able to access the main parser in transform outputs (no loading of embed video modules for consent stuff)
Instead of using an empty file, a text file containing the video id could also be used, but...
Ideally a virtual file / no file could be used, but I do not see any methods relating to this.
Thoughts, ideas?
Hey @octfx, sorry for the delay - things were really hectic on my end with launching the League wiki etc.
So from my current understanding we would indeed need to submit some kind of patch to MW core. Speaking of, in order for this to get merged (faster), the introduced patch / hook would need to be relatively small.
When going the File NS approach, how about hooking into:
$matches = []; preg_match( "/^([^|]+)(\\|(.*))?$/", $line, $matches ); // Newly introduced hook, name up for debate $this->hookRunner->onAfterParserMatchGalleryFile( $this, $line, &$matches );Which would allow registering some kind of file, and replacing the matches with a structure that MW understands. I'll try to do a POC to see if this is feasible.
Agreed that this seems like a good place to put the hook.
When adding an embed to a page for example
{{#ev:youtube|-4FPIL6e4SQ}}, a file page automatically created if it does not exist. To ensure that no duplicates are created EmbedVideo is creating file pages in the form ofFile:ID.Service, which in the previously mentioned case would result inFile:-4FPIL6e4SQ.youtube.
This format for file names seems reasonable. Maybe we could prepend "ev-" or something to the filename to make it easier to find them? e.g when using Special:PrefixIndex
While this does seem to work, there are also problems, namely the duplicate file detection employed by MW. The current process uses empty files in order for the upload to succeed, but this results in:
I guess this is a little confusing if you're looking directly at the file pages, but honestly maybe it's not a big deal. As long as the files being empty/the same doesn't create problems with the actual media handling or how the extension works, I think we can probably just write this off as a quirk of how we're doing this.
Instead of using an empty file, a text file containing the video id could also be used, but... Ideally a virtual file / no file could be used, but I do not see any methods relating to this.
Would definitely prefer to use a virtual file/no file entirely rather than having lots of small 1KB files or whatever hanging out on the filesystem. Happy to help you look into whether this is achievable - do you have a branch or something with your POC? 😄
