From 947269640c9a75326516ecccc0feee9d8d1a57c0 Mon Sep 17 00:00:00 2001 From: merlinsantiago982-cmd Date: Mon, 29 Jun 2026 19:18:57 +0800 Subject: [PATCH] fix(youtube): support playlist video type filter --- README.md | 1 + supadata/youtube.py | 34 +++++++++++++++++++--------------- tests/test_client.py | 25 +++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index f88c509..a983b8a 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ print(f"Playlist: {playlist}") # Get video IDs from a YouTube playlist playlist_videos = supadata.youtube.playlist.videos( id="https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc", # can be url or playlist id + type="all", # 'all', 'video', 'short', or 'live' limit=50 ) print(f"Regular videos: {playlist_videos.video_ids}") diff --git a/supadata/youtube.py b/supadata/youtube.py index eca0604..3694ca3 100644 --- a/supadata/youtube.py +++ b/supadata/youtube.py @@ -22,6 +22,15 @@ class YouTube: pass + +def _video_ids_from_response(response: dict) -> VideoIds: + return VideoIds( + video_ids=response.get("video_ids", response.get("videoIds", [])), + short_ids=response.get("short_ids", response.get("shortIds", [])), + live_ids=response.get("live_ids", response.get("liveIds", [])), + ) + + # -------------------------------------------------------------------------- # Private Classes for API Namespaces # -------------------------------------------------------------------------- @@ -79,11 +88,7 @@ def videos( response: dict = self._youtube._request( "GET", "/youtube/channel/videos", params=query_params ) - return VideoIds( - video_ids=response.get("video_ids", []), - short_ids=response.get("short_ids", []), - live_ids=response.get("live_ids", []) - ) + return _video_ids_from_response(response) @@ -124,12 +129,18 @@ def __call__(self, id: str) -> YoutubePlaylist: return YoutubePlaylist(**response, last_updated=last_updated) - def videos(self, id: str, limit: Optional[int] = None) -> VideoIds: + def videos( + self, + id: str, + limit: Optional[int] = None, + type: Literal["all", "video", "short", "live"] = "all", + ) -> VideoIds: """Get video IDs from a YouTube playlist. Args: id: YouTube Playlist ID. limit: Max videos to return (default 30, max 5000). + type: Type of videos ('all', 'video', 'short', 'live'). Default 'all'. Returns: VideoIds object containing lists of video IDs. @@ -138,20 +149,14 @@ def videos(self, id: str, limit: Optional[int] = None) -> VideoIds: SupadataError: If the API request fails or limit is invalid. """ self._youtube._validate_limit(limit) - query_params = {"id": id} + query_params = {"id": id, "type": type} if limit: query_params["limit"] = limit - if type: - query_params["type"] = type response: dict = self._youtube._request( "GET", "/youtube/playlist/videos", params=query_params ) - return VideoIds( - video_ids=response.get("video_ids", []), - short_ids=response.get("short_ids", []), - live_ids=response.get("live_ids", []) - ) + return _video_ids_from_response(response) class _Video: @@ -644,4 +649,3 @@ def batch(self) -> _Batch: An object for batch result operations. """ return _Batch(self) # Return a new instance each time - diff --git a/tests/test_client.py b/tests/test_client.py index f52136b..235ec75 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -512,7 +512,7 @@ def test_youtube_playlist_videos(client: Supadata, requests_mock) -> None: ] } requests_mock.get( - f"{client.base_url}/youtube/playlist/videos?id={playlist_id}", + f"{client.base_url}/youtube/playlist/videos?id={playlist_id}&type=all", json=mock_response, ) @@ -534,6 +534,27 @@ def test_youtube_playlist_videos(client: Supadata, requests_mock) -> None: assert i in mock_response["liveIds"] +def test_youtube_playlist_videos_with_type(client: Supadata, requests_mock) -> None: + playlist_id = "PL0vfts4VzfNjQOM9VClyL5R0LeuTxlAR3" + mock_response = { + "videoIds": [], + "shortIds": [ + "short1", + "short2", + ], + "liveIds": [], + } + requests_mock.get( + f"{client.base_url}/youtube/playlist/videos?id={playlist_id}&type=short", + json=mock_response, + ) + + playlist_videos = client.youtube.playlist.videos(playlist_id, type="short") + assert playlist_videos.video_ids == [] + assert playlist_videos.short_ids == mock_response["shortIds"] + assert playlist_videos.live_ids == [] + + def test_youtube_playlist_videos_invalid_id(client: Supadata, requests_mock) -> None: playlist_id = "PL0vfts4VzfNjQOM9VClyL50LeuTxlAR3" mock_response = { @@ -543,7 +564,7 @@ def test_youtube_playlist_videos_invalid_id(client: Supadata, requests_mock) -> } requests_mock.get( - f"{client.base_url}/youtube/playlist/videos?id={playlist_id}", + f"{client.base_url}/youtube/playlist/videos?id={playlist_id}&type=all", status_code=404, json=mock_response, )