diff --git a/media/player/videojs/classes/plugin.php b/media/player/videojs/classes/plugin.php index 1f29e2e5b8f..53d723ba705 100644 --- a/media/player/videojs/classes/plugin.php +++ b/media/player/videojs/classes/plugin.php @@ -115,6 +115,12 @@ class media_videojs_plugin extends core_media_player_native { if ($this->youtube) { $datasetup[] = '"techOrder": ["youtube"]'; $datasetup[] = '"sources": [{"type": "video/youtube", "src":"' . $urls[0] . '"}]'; + + // Check if we have a time parameter. + if ($time = $urls[0]->get_param('t')) { + $datasetup[] = '"youtube": {"start": "' . self::get_start_time($time) . '"}'; + } + $sources = ''; // Do not specify tags - it may confuse browser. $isaudio = false; // Just in case. } else if ($flashtech) { @@ -218,6 +224,30 @@ class media_videojs_plugin extends core_media_player_native { parent::pick_video_size($width, $height); } + /** + * Method to convert Youtube time parameter string, which can contain human readable time + * intervals such as '1h5m', '1m10s', etc or a numeric seconds value + * + * @param string $timestr + * @return int + */ + protected static function get_start_time(string $timestr): int { + if (is_numeric($timestr)) { + // We can return the time string itself if it's already numeric. + return (int) $timestr; + } + + try { + // Parse the time string as an ISO 8601 time interval. + $timeinterval = new DateInterval('PT' . core_text::strtoupper($timestr)); + + return ($timeinterval->h * HOURSECS) + ($timeinterval->i * MINSECS) + $timeinterval->s; + } catch (Exception $ex) { + // Invalid time interval. + return 0; + } + } + public function get_supported_extensions() { global $CFG; require_once($CFG->libdir . '/filelib.php'); diff --git a/media/player/videojs/tests/player_test.php b/media/player/videojs/tests/player_test.php index b3a576d3deb..aa8de9f56ee 100644 --- a/media/player/videojs/tests/player_test.php +++ b/media/player/videojs/tests/player_test.php @@ -31,7 +31,7 @@ defined('MOODLE_INTERNAL') || die(); * @copyright 2016 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class media_videojs_testcase extends advanced_testcase { +class media_videojs_player_testcase extends advanced_testcase { /** * Pre-test setup. Preserves $CFG. @@ -273,19 +273,6 @@ class media_videojs_testcase extends advanced_testcase { $this->youtube_plugin_engaged($t); $this->assertContains('list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0', $t); - // Format: youtube video with start time. - $url = new moodle_url('https://www.youtube.com/watch?v=JNJMF1l3udM&t=1h11s'); - $t = $manager->embed_url($url); - $this->youtube_plugin_engaged($t); - $this->assertContains('t=1h11s', $t); - - // Format: youtube video within playlist with start time. - $url = new moodle_url('https://www.youtube.com/watch?v=dv2f_xfmbD8&index=4&list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0&t=1m5s'); - $t = $manager->embed_url($url); - $this->youtube_plugin_engaged($t); - $this->assertContains('list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0', $t); - $this->assertContains('t=1m5s', $t); - // Format: youtube playlist - not supported. $url = new moodle_url('http://www.youtube.com/view_play_list?p=PL6E18E2927047B662'); $t = $manager->embed_url($url); @@ -296,7 +283,41 @@ class media_videojs_testcase extends advanced_testcase { $url = new moodle_url('http://www.youtube.com/p/PL6E18E2927047B662'); $t = $manager->embed_url($url); $this->assertNotContains('mediaplugin_videojs', $t); + } + /** + * Data provider for {@see test_youtube_start_time} + * + * @return array + */ + public function youtube_start_time_provider(): array { + return [ + ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1h11s', 3611], + ['https://www.youtube.com/watch?v=dv2f_xfmbD8&index=4&list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0&t=1m5s', 65], + ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1h10m30s', 4230], + ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=3m', 180], + ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=43s', 43], + ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1234', 1234], + ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=invalid', 0], + ]; + } + + /** + * Test Youtube video embedding with URL's containing start time interval + * + * @param string $url + * @param int $expectedstart + * + * @dataProvider youtube_start_time_provider + */ + public function test_youtube_start_time(string $url, int $expectedstart) { + set_config('youtube', 1, 'media_videojs'); + set_config('useflash', 0, 'media_videojs'); + + $embedcode = core_media_manager::instance()->embed_url(new moodle_url($url)); + + $this->youtube_plugin_engaged($embedcode); + $this->assertContains(""youtube": {"start": "{$expectedstart}"}", $embedcode); } /**