Skip to content

Commit

Permalink
MDL-72607 media_vimeo: Fix vimeo URL parser
Browse files Browse the repository at this point in the history
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/
  • Loading branch information
sampraxis committed Oct 18, 2021
1 parent 385938b commit 87d26b4
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 3 deletions.
33 changes: 30 additions & 3 deletions media/player/vimeo/classes/plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*/
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
Expand All @@ -53,15 +53,42 @@ protected function embed_external(moodle_url $url, $name, $width, $height, $opti
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
*/
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;
}

Expand Down
100 changes: 100 additions & 0 deletions media/player/vimeo/tests/player_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,104 @@ public function test_embed_media() {
$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);
}
}

0 comments on commit 87d26b4

Please sign in to comment.