From 07dffec7f79048a3d16d87282fb4a6f617cff9b2 Mon Sep 17 00:00:00 2001 From: irebussoft Date: Tue, 15 Oct 2024 11:41:24 +0200 Subject: [PATCH] add fix to embed and live url support (#197) Co-authored-by: Ivan Morozov --- src/Youtube.php | 65 +++++++++++++++++++++++++++++++++---------- tests/YoutubeTest.php | 46 ++++++++++++++++++------------ 2 files changed, 78 insertions(+), 33 deletions(-) diff --git a/src/Youtube.php b/src/Youtube.php index 98fa14f..a013d0a 100644 --- a/src/Youtube.php +++ b/src/Youtube.php @@ -603,31 +603,66 @@ public function getActivitiesByChannelId($channelId, $part = ['id', 'snippet', ' } /** - * Parse a youtube URL to get the youtube Vid. - * Support both full URL (www.youtube.com) and short URL (youtu.be) + * Parse a YouTube URL to get the YouTube Video ID. + * Supports full URL (www.youtube.com), short URL (youtu.be), + * embed URL, and live stream URL. * * @param string $youtube_url * @throws \Exception - * @return string Video Id + * @return string Video ID */ public static function parseVidFromURL($youtube_url) { - if (strpos($youtube_url, 'youtube.com')) { - if (strpos($youtube_url, 'embed')) { + // Parse the URL into its components + $parsedUrl = parse_url($youtube_url); + + // Check if it's a valid YouTube URL + if (isset($parsedUrl['host'], $parsedUrl['path'])) { + + // Handle full YouTube URL (www.youtube.com) + if (strpos($parsedUrl['host'], 'youtube.com') !== false) { + + // Handle embed URLs (e.g., https://www.youtube.com/embed/{video_id}) + if (strpos($parsedUrl['path'], '/embed/') === 0) { + $path = static::_parse_url_path($youtube_url); + $vid = substr($path, strlen('/embed/')); + + return $vid; + } + + // Handle live URLs (e.g., https://www.youtube.com/live/{video_id}) + if (strpos($parsedUrl['path'], '/live/') === 0) { + $path = static::_parse_url_path($youtube_url); + $vid = substr($path, strlen('/live/')); + + return $vid; + } + + // Handle /v/ URLs (e.g., https://www.youtube.com/v/{video_id}) + if (strpos($parsedUrl['path'], '/v/') === 0) { + $path = static::_parse_url_path($youtube_url); + $vid = substr($path, strlen('/v/')); + + return $vid; + } + + // Handle standard YouTube video URLs (e.g., https://www.youtube.com/watch?v={video_id}) + $params = static::_parse_url_query($youtube_url); + if (isset($params['v'])) { + return $params['v']; + } + + // Handle short YouTube URLs (e.g., https://youtu.be/{video_id}) + } else if (strpos($parsedUrl['host'], 'youtu.be') !== false) { $path = static::_parse_url_path($youtube_url); - $vid = substr($path, 7); + $vid = substr($path, 1); // Remove the leading '/' + return $vid; - } else { - $params = static::_parse_url_query($youtube_url); - return $params['v']; } - } else if (strpos($youtube_url, 'youtu.be')) { - $path = static::_parse_url_path($youtube_url); - $vid = substr($path, 1); - return $vid; - } else { - throw new \Exception('The supplied URL does not look like a Youtube URL'); } + + // If no valid video ID is found, throw an exception + throw new \Exception('The supplied URL does not look like a valid YouTube URL'); } /** diff --git a/tests/YoutubeTest.php b/tests/YoutubeTest.php index bb86dff..74a132f 100644 --- a/tests/YoutubeTest.php +++ b/tests/YoutubeTest.php @@ -275,24 +275,6 @@ public function testGetPlaylistItemsByPlaylistId() $this->assertEquals('youtube#playlistItem', $data[0]->kind); } - public function testParseVIdFromURLFull() - { - $vId = $this->youtube->parseVidFromURL('http://www.youtube.com/watch?v=1FJHYqE0RDg'); - $this->assertEquals('1FJHYqE0RDg', $vId); - } - - public function testParseVIdFromURLShort() - { - $vId = $this->youtube->parseVidFromURL('http://youtu.be/1FJHYqE0RDg'); - $this->assertEquals('1FJHYqE0RDg', $vId); - } - - public function testParseVIdFromEmbedURL() - { - $vId = $this->youtube->parseVidFromURL('http://youtube.com/embed/1FJHYqE0RDg'); - $this->assertEquals('1FJHYqE0RDg', $vId); - } - /** * @dataProvider urlProvider */ @@ -380,4 +362,32 @@ public function testNotFoundAPICall2() $response = $this->youtube->getPlaylistsByChannelId($channelId); $this->assertEquals($response->getStatusCode(), 404); } + + /** + * @dataProvider youtubeUrlProvider + */ + public function testParseVidFromURL($url, $expectedVideoId) + { + $vId = $this->youtube->parseVidFromURL($url); + $this->assertEquals($expectedVideoId, $vId); + } + + public function youtubeUrlProvider() + { + return [ + ['http://www.youtube.com/watch?v=1FJHYqE0RDg', '1FJHYqE0RDg'], + ['http://youtu.be/1FJHYqE0RDg', '1FJHYqE0RDg'], + ['http://youtube.com/embed/1FJHYqE0RDg', '1FJHYqE0RDg'], + ['https://www.youtube.com/watch?v=dQw4w9WgXcQ', 'dQw4w9WgXcQ'], + ['https://youtu.be/dQw4w9WgXcQ', 'dQw4w9WgXcQ'], + ['https://youtu.be/ymNFyxvIdaM?si=7Ei20mEhPzrS_nZs', 'ymNFyxvIdaM'], + ['https://www.youtube.com/watch?v=ymNFyxvIdaM&ab_channel=BomfunkMCsVEVO', 'ymNFyxvIdaM'], + ['https://www.youtube.com/embed/dQw4w9WgXcQ', 'dQw4w9WgXcQ'], + ['https://www.youtube.com/watch?v=dQw4w9WgXcQ&list=PL590L5WQmH8dKahcfw2Uw8Ud28p4C9XDP', 'dQw4w9WgXcQ'], + ['https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=60', 'dQw4w9WgXcQ'], + ['https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be&t=90', 'dQw4w9WgXcQ'], + ['https://www.youtube.com/v/dQw4w9WgXcQ?version=3&autohide=1', 'dQw4w9WgXcQ'], + ['https://www.youtube.com/live/JAkh_0QKtMg?si=roYDVwBJ4csi6df_', 'JAkh_0QKtMg'] + ]; + } }