MDL-72607 media_vimeo: Fix vimeo URL parser

Fix vimeo URL parser to support the new vimeo URL format with privacy
settings (the video with password or domain restricted setting).
For example "https://vimeo.com/123456789/2bffff0000" the plugin must
parse the URL "https://player.vimeo.com/video/123456789?h=2bffff0000"
to the iframe source to make it compatible with the new vimeo URL
format.
See more about vimeo video privacy settings at
https://vimeo.com/blog/post/video-privacy-explained/
This commit is contained in:
Sam Møller 2021-09-23 13:24:54 +02:00
parent 385938b472
commit 87d26b4743
2 changed files with 130 additions and 3 deletions

View File

@ -34,7 +34,7 @@ defined('MOODLE_INTERNAL') || die();
*/
class media_vimeo_plugin extends core_media_player_external {
protected function embed_external(moodle_url $url, $name, $width, $height, $options) {
$videoid = $this->matches[1];
$videoid = $this->get_video_id();
$info = s($name);
// Note: resizing via url is not supported, user can click the fullscreen
@ -53,6 +53,33 @@ OET;
return $output;
}
/**
* Get Vimeo video ID.
* @return string
*/
protected function get_video_id(): string {
return $this->get_video_id_with_code() ?? $this->matches[1] ?? '';
}
/**
* Get video id with code.
* @return string|null If NULL then the URL does not contain the code.
*/
protected function get_video_id_with_code(): ?string {
$id = $this->matches[2] ?? null;
if (!empty($id)) {
$code = $this->matches[3] ?? null;
if (!empty($code)) {
return "{$id}?h={$code}";
}
return $id;
}
return null;
}
/**
* Returns regular expression to match vimeo URLs.
* @return string
@ -60,8 +87,8 @@ OET;
protected function get_regex() {
// Initial part of link.
$start = '~^https?://vimeo\.com/';
// Middle bit: either watch?v= or v/.
$middle = '([0-9]+)';
// Middle bit: either 123456789 or 123456789/abdef12345.
$middle = '(([0-9]+)/([0-9a-f]+)|[0-9]+)';
return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
}

View File

@ -131,4 +131,104 @@ class media_vimeo_testcase extends advanced_testcase {
$this->assertMatchesRegularExpression('~</iframe>~', $content);
$this->assertMatchesRegularExpression('~width="123" height="35"~', $content);
}
/**
* Test embedding without media filter (for example for displaying URL resorce)
* and test that player plugin is parsing the URL with the code.
*/
public function test_embed_url_with_code() {
global $CFG;
$url = new moodle_url('https://vimeo.com/1176321/abcdef12345');
$manager = core_media_manager::instance();
$embedoptions = array(
core_media_manager::OPTION_TRUSTED => true,
core_media_manager::OPTION_BLOCK => true,
);
$this->assertTrue($manager->can_embed_url($url, $embedoptions));
$content = $manager->embed_url($url, 'Test & file', 0, 0, $embedoptions);
// Video source URL is contains the new vimeo embedded URL format.
$this->assertStringContainsString('player.vimeo.com/video/1176321?h=abcdef12345', $content);
$this->assertMatchesRegularExpression('~mediaplugin_vimeo~', $content);
$this->assertMatchesRegularExpression('~</iframe>~', $content);
$this->assertMatchesRegularExpression('~width="' . $CFG->media_default_width . '" height="' .
$CFG->media_default_height . '"~', $content);
// Repeat sending the specific size to the manager.
$content = $manager->embed_url($url, 'New file', 123, 50, $embedoptions);
$this->assertMatchesRegularExpression('~width="123" height="50"~', $content);
}
/**
* Test that mediaplugin filter replaces a link to the supported file with media tag
* and test that player plugin is parsing the URL with the code.
*
* filter_mediaplugin is enabled by default.
*/
public function test_embed_link_with_code() {
global $CFG;
$url = new moodle_url('https://vimeo.com/1176321/abcdef12345');
$text = html_writer::link($url, 'Watch this one');
$content = format_text($text, FORMAT_HTML);
// Video source URL is contains the new vimeo embedded URL format.
$this->assertStringContainsString('player.vimeo.com/video/1176321?h=abcdef12345', $content);
$this->assertMatchesRegularExpression('~mediaplugin_vimeo~', $content);
$this->assertMatchesRegularExpression('~</iframe>~', $content);
$this->assertMatchesRegularExpression('~width="' . $CFG->media_default_width . '" height="' .
$CFG->media_default_height . '"~', $content);
}
/**
* Test that mediaplugin filter adds player code on top of <video> tags
* and test that player plugin is parse the URL with the code.
*
* filter_mediaplugin is enabled by default.
*/
public function test_embed_media_with_code() {
global $CFG;
$url = new moodle_url('https://vimeo.com/1176321/abcdef12345');
$trackurl = new moodle_url('http://example.org/some_filename.vtt');
$text = '<video controls="true"><source src="'.$url.'"/>' .
'<track src="'.$trackurl.'">Unsupported text</video>';
$content = format_text($text, FORMAT_HTML);
// Video source URL is contains the new vimeo embedded URL format.
$this->assertStringContainsString('player.vimeo.com/video/1176321?h=abcdef12345', $content);
$this->assertMatchesRegularExpression('~mediaplugin_vimeo~', $content);
$this->assertMatchesRegularExpression('~</iframe>~', $content);
$this->assertMatchesRegularExpression('~width="' . $CFG->media_default_width . '" height="' .
$CFG->media_default_height . '"~', $content);
// Video tag, unsupported text and tracks are removed.
$this->assertDoesNotMatchRegularExpression('~</video>~', $content);
$this->assertDoesNotMatchRegularExpression('~<source\b~', $content);
$this->assertDoesNotMatchRegularExpression('~Unsupported text~', $content);
$this->assertDoesNotMatchRegularExpression('~<track\b~i', $content);
// Video with dimensions and source specified as src attribute without <source> tag.
$text = '<video controls="true" width="123" height="35" src="'.$url.'">Unsupported text</video>';
$content = format_text($text, FORMAT_HTML);
$this->assertMatchesRegularExpression('~mediaplugin_vimeo~', $content);
$this->assertMatchesRegularExpression('~</iframe>~', $content);
$this->assertMatchesRegularExpression('~width="123" height="35"~', $content);
}
/**
* Test that mediaplugin filter skip the process when the URL is invalid.
*/
public function test_skip_invalid_url_format_with_code() {
$url = new moodle_url('https://vimeo.com/_________/abcdef12345s');
$text = html_writer::link($url, 'Invalid Vimeo URL');
$content = format_text($text, FORMAT_HTML);
$this->assertStringNotContainsString('player.vimeo.com/video/_________?h=abcdef12345s', $content);
$this->assertDoesNotMatchRegularExpression('~mediaplugin_vimeo~', $content);
$this->assertDoesNotMatchRegularExpression('~</iframe>~', $content);
}
}