Created
March 13, 2024 22:01
-
-
Save ciencia/86edec03454a68e7b98320e165252513 to your computer and use it in GitHub Desktop.
patch MediaWiki extension TimedMediaHandler autoplay videos REL1_39
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/extension.json b/extension.json | |
index dc9cc247..d878a1ee 100644 | |
--- a/extension.json | |
+++ b/extension.json | |
@@ -102,10 +102,12 @@ | |
"CanonicalNamespaces": "main", | |
"FileDeleteComplete": "main", | |
"FileUpload": "main", | |
+ "GetPreferences": "main", | |
"ImageOpenShowImageInlineBefore": "main", | |
"ImagePageAfterImageLinks": "main", | |
"ImagePageFileHistoryLine": "main", | |
"LoadExtensionSchemaUpdates": "main", | |
+ "MakeGlobalVariablesScript": "main", | |
"MediaWikiPerformAction": "iframe", | |
"RevisionFromEditComplete": "main", | |
"ParserTestGlobals": "main", | |
@@ -306,8 +308,16 @@ | |
"description": "Path of a soundfont to use for MIDI-converted audio", | |
"public": true, | |
"value": null | |
+ }, | |
+ "TmhEnableAutoPlayVideos": { | |
+ "description": "Allow videos to play automatically (but muted) using the autoplay attribute.", | |
+ "public": true, | |
+ "value": false | |
} | |
}, | |
+ "DefaultUserOptions": { | |
+ "timedmediahandler-autoplayvideos": "allow" | |
+ }, | |
"ResourceFileModulePaths": { | |
"localBasePath": "", | |
"remoteExtPath": "TimedMediaHandler" | |
diff --git a/i18n/TimedMediaHandler.i18n.magic.php b/i18n/TimedMediaHandler.i18n.magic.php | |
index 0c8a66c9..a90bb922 100644 | |
--- a/i18n/TimedMediaHandler.i18n.magic.php | |
+++ b/i18n/TimedMediaHandler.i18n.magic.php | |
@@ -15,6 +15,7 @@ $magicWords['en'] = [ | |
'timedmedia_disablecontrols' => [ 0, 'disablecontrols=$1' ], | |
'timedmedia_loop' => [ 0, 'loop' ], | |
'timedmedia_muted' => [ 0, 'muted' ], | |
+ 'timedmedia_autoplay' => [ 0, 'autoplay' ], | |
]; | |
$magicWords['af'] = [ | |
diff --git a/i18n/en.json b/i18n/en.json | |
index 8f3aba6e..dead22d3 100644 | |
--- a/i18n/en.json | |
+++ b/i18n/en.json | |
@@ -188,5 +188,8 @@ | |
"videojs-captions-create": "Create captions", | |
"transcodestatistics": "Transcode statistics", | |
"timedmedia-timedtext-title-edit-subtitles": "$1 subtitles for clip: $2", | |
- "timedmedia-timedtext-title-create-subtitles": "No $1 subtitles were found for clip: $2" | |
+ "timedmedia-timedtext-title-create-subtitles": "No $1 subtitles were found for clip: $2", | |
+ "timedmedia-preference-autoplayvideos": "Behavior of videos marked to play automatically", | |
+ "timedmedia-preference-autoplayvideos-allow": "Allow videos marked as such to play automatically", | |
+ "timedmedia-preference-autoplayvideos-never": "Never play videos automatically" | |
} | |
diff --git a/i18n/es.json b/i18n/es.json | |
index a260ec6a..b3af4c5b 100644 | |
--- a/i18n/es.json | |
+++ b/i18n/es.json | |
@@ -154,5 +154,8 @@ | |
"videojs-more-information": "Más información", | |
"videojs-quality": "Calidad de vídeo", | |
"timedmedia-timedtext-title-edit-subtitles": "$1 subtítulos para el clip: $2", | |
- "timedmedia-timedtext-title-create-subtitles": "No se ha encontrado subtítulos $1 para el clip: $2" | |
+ "timedmedia-timedtext-title-create-subtitles": "No se ha encontrado subtítulos $1 para el clip: $2", | |
+ "timedmedia-preference-autoplayvideos": "Comportamiento de los vídeos marcados para su reproducción automática", | |
+ "timedmedia-preference-autoplayvideos-allow": "Permitir la reproducción automática de vídeos", | |
+ "timedmedia-preference-autoplayvideos-never": "Nunca permitir la reproducción automática de vídeos" | |
} | |
diff --git a/i18n/qqq.json b/i18n/qqq.json | |
index 3d31c394..572f8b1b 100644 | |
--- a/i18n/qqq.json | |
+++ b/i18n/qqq.json | |
@@ -209,5 +209,8 @@ | |
"videojs-captions-create": "Menu entry in the captions menu of the video player, to navigate to the create captions interface. In some languages captions are known as subtitles.", | |
"transcodestatistics": "{{doc-special|TranscodeStatistics}}", | |
"timedmedia-timedtext-title-edit-subtitles": "$1 is language name for subtitles (e.g. \"English\"), $2 is title of file that timed text is for.\nShown as the page title on a TimedText namespace page when the page exists. See also {{msg-mw|timedmedia-timedtext-title-create-subtitles}}.", | |
- "timedmedia-timedtext-title-create-subtitles": "$1 is language name, $2 is title of file that timed text is for.\nShown as the page title on a TimedText namespace page when the page does not exist. See also {{msg-mw|timedmedia-timedtext-title-edit-subtitles}}." | |
+ "timedmedia-timedtext-title-create-subtitles": "$1 is language name, $2 is title of file that timed text is for.\nShown as the page title on a TimedText namespace page when the page does not exist. See also {{msg-mw|timedmedia-timedtext-title-edit-subtitles}}.", | |
+ "timedmedia-preference-autoplayvideos": "Label in user preferences for a drop-down controlling the behavior of videos marked to play automatically.", | |
+ "timedmedia-preference-autoplayvideos-allow": "Videos marked to play automatically will start playing upon page load. One of the options for {{msg-mw|timedmedia-preference-autoplayvideos}}.", | |
+ "timedmedia-preference-autoplayvideos-never": "Videos marked to play automatically will require user interaction to start playing. One of the options for {{msg-mw|timedmedia-preference-autoplayvideos}}." | |
} | |
diff --git a/includes/Hooks.php b/includes/Hooks.php | |
index 136a8cae..f77aedc0 100644 | |
--- a/includes/Hooks.php | |
+++ b/includes/Hooks.php | |
@@ -17,6 +17,7 @@ use MediaWiki\Hook\BeforePageDisplayHook; | |
use MediaWiki\Hook\CanonicalNamespacesHook; | |
use MediaWiki\Hook\FileDeleteCompleteHook; | |
use MediaWiki\Hook\FileUploadHook; | |
+use MediaWiki\Hook\MakeGlobalVariablesScriptHook; | |
use MediaWiki\Hook\ParserTestGlobalsHook; | |
use MediaWiki\Hook\SkinTemplateNavigation__UniversalHook; | |
use MediaWiki\Hook\TitleMoveHook; | |
@@ -28,6 +29,7 @@ use MediaWiki\Page\Hook\ImageOpenShowImageInlineBeforeHook; | |
use MediaWiki\Page\Hook\ImagePageAfterImageLinksHook; | |
use MediaWiki\Page\Hook\ImagePageFileHistoryLineHook; | |
use MediaWiki\Page\Hook\RevisionFromEditCompleteHook; | |
+use MediaWiki\Preferences\Hook\GetPreferencesHook; | |
use MediaWiki\Revision\RevisionRecord; | |
use MediaWiki\SpecialPage\Hook\WgQueryPagesHook; | |
use MediaWiki\TimedMediaHandler\WebVideoTranscode\WebVideoTranscode; | |
@@ -55,17 +57,18 @@ class Hooks implements | |
CanonicalNamespacesHook, | |
FileDeleteCompleteHook, | |
FileUploadHook, | |
+ GetPreferencesHook, | |
ImageOpenShowImageInlineBeforeHook, | |
ImagePageAfterImageLinksHook, | |
ImagePageFileHistoryLineHook, | |
LoadExtensionSchemaUpdatesHook, | |
+ MakeGlobalVariablesScriptHook, | |
ParserTestGlobalsHook, | |
RevisionFromEditCompleteHook, | |
SkinTemplateNavigation__UniversalHook, | |
TitleMoveHook, | |
WgQueryPagesHook | |
{ | |
- | |
/** | |
* Register TimedMediaHandler namespace IDs | |
* | |
@@ -475,6 +478,44 @@ class Hooks implements | |
return true; | |
} | |
+ /** | |
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/GetPreferences | |
+ * Register extension preferences | |
+ * @param User $user | |
+ * @param array &$prefs | |
+ */ | |
+ public function onGetPreferences( $user, &$prefs ) { | |
+ global $wgTmhEnableAutoPlayVideos; | |
+ | |
+ if ( $wgTmhEnableAutoPlayVideos === true ) { | |
+ $prefs['timedmediahandler-autoplayvideos'] = [ | |
+ 'type' => 'select', | |
+ 'label-message' => 'timedmedia-preference-autoplayvideos', | |
+ 'section' => 'rendering/files', | |
+ 'options-messages' => [ | |
+ 'timedmedia-preference-autoplayvideos-allow' => 'allow', | |
+ 'timedmedia-preference-autoplayvideos-never' => 'never', | |
+ ], | |
+ ]; | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/MakeGlobalVariablesScript | |
+ * Export variables which depend on the current user | |
+ * @param array &$vars | |
+ * @param OutputPage $out | |
+ * @return void | |
+ */ | |
+ public function onMakeGlobalVariablesScript( &$vars, $out ): void { | |
+ global $wgTmhEnableAutoPlayVideos; | |
+ | |
+ $user = $out->getUser(); | |
+ $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup(); | |
+ $vars['wgTMHAutoplayVideos'] = $wgTmhEnableAutoPlayVideos && | |
+ $userOptionsLookup->getOption( $user, 'timedmediahandler-autoplayvideos' ) == 'allow'; | |
+ } | |
+ | |
/** | |
* @param array &$qp | |
*/ | |
diff --git a/includes/TimedMediaHandler.php b/includes/TimedMediaHandler.php | |
index e33d136e..d9cc76ab 100644 | |
--- a/includes/TimedMediaHandler.php | |
+++ b/includes/TimedMediaHandler.php | |
@@ -39,6 +39,7 @@ class TimedMediaHandler extends MediaHandler { | |
'timedmedia_disablecontrols' => 'disablecontrols', | |
'timedmedia_loop' => 'loop', | |
'timedmedia_muted' => 'muted', | |
+ 'timedmedia_autoplay' => 'autoplay', | |
]; | |
} | |
@@ -135,6 +136,8 @@ class TimedMediaHandler extends MediaHandler { | |
* @return bool | |
*/ | |
public function normaliseParams( $image, &$params ) { | |
+ global $wgTmhEnableAutoPlayVideos; | |
+ | |
$timeParam = [ 'thumbtime', 'start', 'end' ]; | |
// Parse time values if endtime or thumbtime can't be more than length -1 | |
foreach ( $timeParam as $pn ) { | |
@@ -194,6 +197,18 @@ class TimedMediaHandler extends MediaHandler { | |
foreach ( [ 'loop', 'muted' ] as $flag ) { | |
$params[ $flag ] = isset( $params[ $flag ] ); | |
} | |
+ | |
+ // Autoplay only for video, since audio will likely be blocked | |
+ // by browsers | |
+ $params[ 'autoplay' ] = isset( $params[ 'autoplay' ] ) && | |
+ !$this->isAudio( $image ) && | |
+ ( $wgTmhEnableAutoPlayVideos === true ); | |
+ | |
+ // Autoplay videos must be muted | |
+ if ( $params[ 'autoplay' ] ) { | |
+ $params[ 'muted' ] = true; | |
+ } | |
+ | |
return true; | |
} | |
@@ -389,6 +404,7 @@ class TimedMediaHandler extends MediaHandler { | |
'loop' => $params['loop'] ?? false, | |
'muted' => $params['muted'] ?? false, | |
'inline' => $params['inline'] ?? false, | |
+ 'autoPlay' => $params['autoplay'] ?? false, | |
]; | |
// Allow start and end query string params on image pages (T203994) | |
diff --git a/includes/TimedMediaTransformOutput.php b/includes/TimedMediaTransformOutput.php | |
index 01d690cc..83ae1c81 100644 | |
--- a/includes/TimedMediaTransformOutput.php | |
+++ b/includes/TimedMediaTransformOutput.php | |
@@ -62,6 +62,9 @@ class TimedMediaTransformOutput extends MediaTransformOutput { | |
/** @var bool */ | |
protected $loop; | |
+ /** @var bool */ | |
+ protected $autoPlay; | |
+ | |
// The prefix for player ids | |
private const PLAYER_ID_PREFIX = 'mwe_player_'; | |
@@ -87,6 +90,7 @@ class TimedMediaTransformOutput extends MediaTransformOutput { | |
$this->inline = $conf['inline'] ?? false; | |
$this->muted = $conf['muted'] ?? false; | |
$this->loop = $conf['loop'] ?? false; | |
+ $this->autoPlay = $conf['autoPlay'] ?? false; | |
} | |
/** | |
@@ -455,10 +459,19 @@ class TimedMediaTransformOutput extends MediaTransformOutput { | |
if ( $this->fillwindow ) { | |
$mediaAttr[ 'data-player' ] = 'fillwindow'; | |
} | |
- if ( $this->inline ) { | |
+ if ( $this->inline || $this->autoPlay ) { | |
$mediaAttr['class'] .= ' mw-tmh-inline'; | |
+ if ( $this->autoPlay ) { | |
+ // javascript will trigger the video playback with this class | |
+ $mediaAttr['class'] .= ' mw-tmh-autoplay'; | |
+ } | |
$mediaAttr['playsinline'] = ''; | |
- $mediaAttr['preload'] = 'auto'; | |
+ if ( $this->inline ) { | |
+ // autoplay will start playing when it gets on the viewport | |
+ // Do not preload it to prevent browsers from downloading | |
+ // a video that may never be viewed | |
+ $mediaAttr['preload'] = 'auto'; | |
+ } | |
} | |
// Used by Score extension and to disable specific controls from wikicode | |
* Unmerged path jsdoc.json | |
diff --git a/resources/ext.tmh.player.element.js b/resources/ext.tmh.player.element.js | |
index 6cd6038d..1069bc9d 100644 | |
--- a/resources/ext.tmh.player.element.js | |
+++ b/resources/ext.tmh.player.element.js | |
@@ -15,7 +15,14 @@ function MediaElement( element ) { | |
this.element = element; | |
this.$element = $( element ); | |
this.isAudio = element.tagName.toLowerCase() === 'audio'; | |
+ this.isAutoplayVideo = mw.config.get( 'wgTMHAutoplayVideos' ) === true && | |
+ !this.isAudio && | |
+ element.classList.contains( 'mw-tmh-autoplay' ); | |
this.$placeholder = null; | |
+ // This property gets set for autoplay videos when they were playing | |
+ // and went outside of the viewport. Need to differentiate from videos | |
+ // paused by the user | |
+ this.pausedByIntersectionObserver = false; | |
} | |
/** | |
@@ -33,6 +40,15 @@ MediaElement.currentlyPlaying = false; | |
*/ | |
MediaElement.$interstitial = null; | |
+/** | |
+ * Watches for autoplay videos entering or leaving the viewport, to play or | |
+ * pause them automatically | |
+ * | |
+ * @static | |
+ * @type {IntersectionObserver} | |
+ */ | |
+let lazyVideoObserver = null; | |
+ | |
function secondsToComponents( totalSeconds ) { | |
totalSeconds = parseInt( totalSeconds, 10 ); | |
var hours = Math.floor( totalSeconds / 3600 ); | |
@@ -86,6 +102,52 @@ function secondsToDurationLongString( totalSeconds ) { | |
return mw.msg( 'timedmedia-duration-s', seconds ); | |
} | |
+/** | |
+ * Checks video element visibility and play/pause them | |
+ * Only relevant for autoplay videos | |
+ * | |
+ * @param {IntersectionObserverEntry} entry | |
+ */ | |
+function playPauseVideosFromVisibility( entry ) { | |
+ const $element = $( entry.target ); | |
+ const mediaElement = $element.data( 'MediaElement' ); | |
+ const videojsPlayer = $element.data( 'videojsPlayer' ); | |
+ | |
+ if ( entry.isIntersecting ) { | |
+ if ( !videojsPlayer ) { | |
+ // Player not initialized | |
+ // Unobserve current element since it will be | |
+ // replaced by a cloned node | |
+ lazyVideoObserver.unobserve( entry.target ); | |
+ mediaElement.playInlineOrOpenDialog(); | |
+ } else if ( | |
+ videojsPlayer.paused() && | |
+ mediaElement.pausedByIntersectionObserver | |
+ ) { | |
+ videojsPlayer.play(); | |
+ mediaElement.pausedByIntersectionObserver = false; | |
+ } | |
+ } else { | |
+ if ( videojsPlayer && !videojsPlayer.paused() ) { | |
+ videojsPlayer.pause(); | |
+ mediaElement.pausedByIntersectionObserver = true; | |
+ } | |
+ } | |
+} | |
+ | |
+function initLazyVideoObserver() { | |
+ if ( lazyVideoObserver !== null ) { | |
+ return; | |
+ } | |
+ if ( 'IntersectionObserver' in window ) { | |
+ lazyVideoObserver = new IntersectionObserver( | |
+ function ( entries ) { | |
+ entries.forEach( playPauseVideosFromVisibility ); | |
+ } | |
+ ); | |
+ } | |
+} | |
+ | |
/** | |
* Load our customizations for the media element, | |
* loading videojs inline or upon click inside a MediaDialog | |
@@ -108,7 +170,9 @@ MediaElement.prototype.load = function () { | |
id: $clonedVid.attr( 'id' ) + '_placeholder', | |
disabled: '', | |
tabindex: -1 | |
- } ).removeAttr( 'src' ); | |
+ } ) | |
+ .removeAttr( 'src' ) | |
+ .data( 'MediaElement', this ); | |
if ( !this.isAudio ) { | |
var aspectRatio = this.$element.attr( 'width' ) + ' / ' + this.$element.attr( 'height' ); | |
@@ -159,6 +223,12 @@ MediaElement.prototype.load = function () { | |
if ( playing ) { | |
this.playInlineOrOpenDialog(); | |
+ } else if ( this.isAutoplayVideo ) { | |
+ initLazyVideoObserver(); | |
+ // Autoplay videos will be handled by the intersection observer | |
+ if ( lazyVideoObserver !== null ) { | |
+ lazyVideoObserver.observe( $clonedVid[ 0 ] ); | |
+ } | |
} | |
}; | |
@@ -241,10 +311,13 @@ MediaElement.prototype.clickHandler = function ( event ) { | |
MediaElement.prototype.playInlineOrOpenDialog = function () { | |
var mediaElement = this; | |
- MediaElement.$interstitial = $( '<div>' ).addClass( 'mw-tmh-player-interstitial' ) | |
- .append( $( '<div>' ).addClass( 'mw-tmh-player-progress' ) | |
- .append( $( '<div>' ).addClass( 'mw-tmh-player-progress-bar' ) ) ) | |
- .appendTo( document.body ); | |
+ // Do not add a progress bar for inline player | |
+ if ( !this.isInline() ) { | |
+ MediaElement.$interstitial = $( '<div>' ).addClass( 'mw-tmh-player-interstitial' ) | |
+ .append( $( '<div>' ).addClass( 'mw-tmh-player-progress' ) | |
+ .append( $( '<div>' ).addClass( 'mw-tmh-player-progress-bar' ) ) ) | |
+ .appendTo( document.body ); | |
+ } | |
// If we're using ogv.js, we have to initialize the audio context | |
// during a click event to work on Safari, especially for iOS. | |
@@ -275,6 +348,7 @@ MediaElement.prototype.playInlineOrOpenDialog = function () { | |
} | |
if ( this.isInline() ) { | |
+ const self = this; | |
mw.loader.using( 'ext.tmh.player.inline' ).then( function () { | |
mediaElement.$placeholder.find( 'a, .mw-tmh-label' ).detach(); | |
mediaElement.$placeholder.find( 'video,audio' ) | |
@@ -292,8 +366,21 @@ MediaElement.prototype.playInlineOrOpenDialog = function () { | |
// because some versions of EdgeHTML don't fire these events. | |
// Support: Edge 18 | |
setTimeout( function () { | |
- MediaElement.$interstitial.detach(); | |
+ if ( self.isAutoplayVideo ) { | |
+ // Hides the control bar for autoplay videos when they | |
+ // start playing | |
+ videojsPlayer.userActive( false ); | |
+ } | |
videojsPlayer.play(); | |
+ if ( self.isAutoplayVideo && lazyVideoObserver !== null ) { | |
+ // References for IntersectionObserver | |
+ $( self.element ) | |
+ .data( 'videojsPlayer', videojsPlayer ) | |
+ .data( 'MediaElement', self ); | |
+ // Add the element to the IntersectionObserver to pause | |
+ // it when it goes outside of the viewport | |
+ lazyVideoObserver.observe( self.element ); | |
+ } | |
}, 0 ); | |
} ); | |
} ); | |
diff --git a/tests/parser/parserTests.txt b/tests/parser/parserTests.txt | |
index 98299636..22e46cad 100644 | |
--- a/tests/parser/parserTests.txt | |
+++ b/tests/parser/parserTests.txt | |
@@ -220,3 +220,51 @@ Video with flag muted and loop | |
!! html/parsoid | |
<p><span class="mw-default-size" typeof="mw:Video" data-parsoid='{"optList":[{"ck":"bogus","ak":"noplayer"},{"ck":"bogus","ak":"noicon"},{"ck":"bogus","ak":"disablecontrols=ok"},{"ck":"caption","ak":"These are bogus."}]}' data-mw='{"caption":"These are bogus."}'><span><video poster="http://example.com/images/thumb/0/00/Video.ogv/320px--Video.ogv.jpg" controls="" preload="none" height="240" width="320" resource="./File:Video.ogv"><source src="http://example.com/images/0/00/Video.ogv" type='video/ogg; codecs="theora"' data-file-width="320" data-file-height="240" data-title="Original Ogg file, 320 × 240 (590 kbps)" data-shorttitle="Ogg source"/></video></span></span></p> | |
!! end | |
+ | |
+!! test | |
+Video with flag autoplay but not enabled from config | |
+!! wikitext | |
+[[File:Video.ogv|autoplay|These are bogus.]] | |
+!! html/php | |
+<p><video id="mwe_player_1" poster="http://example.com/images/thumb/0/00/Video.ogv/320px--Video.ogv.jpg" controls="" preload="none" width="320" height="240" data-durationhint="5" data-mwtitle="Video.ogv" data-mwprovider="local"><source src="http://example.com/images/0/00/Video.ogv" type="video/ogg; codecs="theora"" data-title="Original Ogg file, 320 × 240 (590 kbps)" data-shorttitle="Ogg source" data-width="320" data-height="240" data-bandwidth="590013" data-framerate="30" /></video> | |
+</p> | |
+!! html/parsoid | |
+<p><span class="mw-default-size" typeof="mw:Video" data-parsoid='{"optList":[{"ck":"bogus","ak":"noplayer"},{"ck":"bogus","ak":"noicon"},{"ck":"bogus","ak":"disablecontrols=ok"},{"ck":"caption","ak":"These are bogus."}]}' data-mw='{"caption":"These are bogus."}'><span><video poster="http://example.com/images/thumb/0/00/Video.ogv/320px--Video.ogv.jpg" controls="" preload="none" height="240" width="320" resource="./File:Video.ogv"><source src="http://example.com/images/0/00/Video.ogv" type='video/ogg; codecs="theora"' data-file-width="320" data-file-height="240" data-title="Original Ogg file, 320 × 240 (590 kbps)" data-shorttitle="Ogg source"/></video></span></span></p> | |
+!! end | |
+ | |
+!! test | |
+Video with flag autoplay | |
+!! config | |
+wgTmhEnableAutoPlayVideos=true | |
+!! wikitext | |
+[[File:Video.ogv|autoplay|These are bogus.]] | |
+!! html/php | |
+<p><video id="mwe_player_1" poster="http://example.com/images/thumb/0/00/Video.ogv/320px--Video.ogv.jpg" controls="" preload="none" muted="" class="mw-tmh-inline mw-tmh-autoplay" width="320" height="240" playsinline="" data-durationhint="5" data-mwtitle="Video.ogv" data-mwprovider="local"><source src="http://example.com/images/0/00/Video.ogv" type="video/ogg; codecs="theora"" data-title="Original Ogg file, 320 × 240 (590 kbps)" data-shorttitle="Ogg source" data-width="320" data-height="240" data-bandwidth="590013" data-framerate="30" /></video> | |
+</p> | |
+!! html/parsoid | |
+<p><span class="mw-default-size" typeof="mw:Video" data-parsoid='{"optList":[{"ck":"bogus","ak":"noplayer"},{"ck":"bogus","ak":"noicon"},{"ck":"bogus","ak":"disablecontrols=ok"},{"ck":"caption","ak":"These are bogus."}]}' data-mw='{"caption":"These are bogus."}'><span><video poster="http://example.com/images/thumb/0/00/Video.ogv/320px--Video.ogv.jpg" controls="" preload="none" height="240" width="320" resource="./File:Video.ogv"><source src="http://example.com/images/0/00/Video.ogv" type='video/ogg; codecs="theora"' data-file-width="320" data-file-height="240" data-title="Original Ogg file, 320 × 240 (590 kbps)" data-shorttitle="Ogg source"/></video></span></span></p> | |
+!! end | |
+ | |
+## FIXME: Mock transcoding on the php side as well | |
+!! test | |
+Video with a transcoded source | |
+!! config | |
+wgParserEnableLegacyMediaDOM=false | |
+!! wikitext | |
+[[File:Transcode.webm|thumb|Hello]] | |
+!! html/parsoid | |
+<figure class="mw-default-size" typeof="mw:File/Thumb"><span><video poster="http://example.com/images/thumb/0/09/Transcode.webm/180px--Transcode.webm.jpg" controls="" preload="none" height="132" width="180" resource="./File:Transcode.webm" data-durationhint="4" class="mw-file-element"><source src="http://example.com/images/0/09/Transcode.webm" type='video/webm; codecs="vp8, vorbis"' data-file-width="492" data-file-height="360"/><source src="http://example.com/images/transcoded/0/09/Transcode.webm/Transcode.webm.240p.vp9.webm" type='video/webm; codecs="vp9, opus"' data-width="328" data-height="240" data-transcodekey="240p.vp9.webm"/></video></span><figcaption>Hello</figcaption></figure> | |
+!! end | |
+ | |
+!! test | |
+Video with markup in alt option | |
+!! config | |
+wgParserEnableLegacyMediaDOM=false | |
+!! wikitext | |
+[[File:Video.ogv|alt=testing '''bold''' in alt]] | |
+!! html/php | |
+<p><span class="mw-default-size" typeof="mw:File"><span><video id="mwe_player_1" poster="http://example.com/images/thumb/0/00/Video.ogv/320px--Video.ogv.jpg" controls="" preload="none" width="320" height="240" data-durationhint="5" data-mwtitle="Video.ogv" data-mwprovider="local"><source src="http://example.com/images/0/00/Video.ogv" type="video/ogg; codecs="theora"" data-title="Original Ogg file, 320 × 240 (590 kbps)" data-shorttitle="Ogg source" data-width="320" data-height="240" data-bandwidth="590013" data-framerate="30" /></video></span></span> | |
+</p> | |
+!! html/parsoid | |
+<p><span class="mw-default-size" typeof="mw:File mw:ExpandedAttrs" about="#mwt1" data-mw='{"attribs":[["alt",{"html":"alt=testing <b data-parsoid='{\"dsr\":[29,39,3,3]}'>bold</b> in alt","txt":"testing bold in alt"}]]}'><span><video poster="http://example.com/images/thumb/0/00/Video.ogv/320px--Video.ogv.jpg" controls="" preload="none" height="240" width="320" resource="./File:Video.ogv" data-durationhint="5" class="mw-file-element"><source src="http://example.com/images/0/00/Video.ogv" type='video/ogg; codecs="theora"' data-file-width="320" data-file-height="240"/></video></span></span></p> | |
+!! end | |
diff --git a/tests/phpunit/mocks/MockOggHandler.php b/tests/phpunit/mocks/MockOggHandler.php | |
index 299d1f66..783a8650 100644 | |
--- a/tests/phpunit/mocks/MockOggHandler.php | |
+++ b/tests/phpunit/mocks/MockOggHandler.php | |
@@ -64,6 +64,7 @@ class MockOggHandler extends OggHandler { | |
'disablecontrols' => $params['disablecontrols'] ?? false, | |
'loop' => $params['loop'] ?? false, | |
'muted' => $params['muted'] ?? false, | |
+ 'autoPlay' => $params['autoplay'] ?? false, | |
]; | |
// No thumbs for audio |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment