Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand Down
34 changes: 19 additions & 15 deletions supadata/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
# --------------------------------------------------------------------------
Expand Down Expand Up @@ -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)



Expand Down Expand Up @@ -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.
Expand All @@ -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:
Expand Down Expand Up @@ -644,4 +649,3 @@ def batch(self) -> _Batch:
An object for batch result operations.
"""
return _Batch(self) # Return a new instance each time

25 changes: 23 additions & 2 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)

Expand All @@ -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 = {
Expand All @@ -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,
)
Expand Down