YouTube API: Get upload playlistID for YouTube Channel - youtube-api

I'm trying to figure out the best way to get a channel's upload playlistID given the channel's channelID. E.g. for the channel with channelID
UC9CuvdOVfMPvKCiwdGKL3cQ
The corresponding upload playlistID is
UU9CuvdOVfMPvKCiwdGKL3cQ
Notice the second character has changed from a "C" to a "U"
I can do this transformation via string manipulation, but I'm curious if there's a better, less hacky way to find the upload playlist ID through the official youtube api.
Here's some Kotlin code that shows my issue:
I can find the ChannelID for the "Game Grumps" channel through the following youtube api v3 search:
val req = youtube.search().list("snippet");
req.key = {API_KEY}
req.q = "Game Grumps"
req.type = "channel"
val response = req.execute();
The resulting Channel id (response.items[0].snippet.channelId) is UC9CuvdOVfMPvKCiwdGKL3cQ
But when I run the following to try to get the videos uploaded by the channel, I have to use the transformed ChannelID (starting with UU instead of UC)
val req = youtube.PlaylistItems().list("snippet")
req.playlistId = "UU9CuvdOVfMPvKCiwdGKL3cQ"
req.key = {API_KEY}
val response = req .execute()
If I use the untransformed "UC" channelID, I get the following error: The playlist identified with the requests playlistId parameter cannot be found.
Instead of just replacing the second character with a "U", what's the more robust way (e.g. using the youtube API) of translating a ChannelID to a PlaylistID (for the uploads from that channel)?

I would suggest using the official Youtube API, instead of trying to manipulate the strings. You can follow the instructions here:
Instructions to get video ids for all uploaded videos for a channel in V3
Get the channel id for the channel you want (you probably only need to do this once, then you can save it)
Use search.list
Set type to channel
Set q to the name of the channel you want
Grab the channel id (something like this: "channelId": "UC0X2VuXXXXXXXXXXXXXXXX")
Get the playlist id for the channel uploads using the channel id from step 1 (you probably only need to do this once, then you can save it)
Use channels.list
Set id to UC0X2VuXXXXXXXXXXXXXXXX from step 1
Grab the uploads key from contentDetails (something like this: "uploads": "UU0XXXXXXXXXXXXXXXXXXXX")
Get the videos via the playlistitems in the playlist using the playlist id from step 2
Use playlistItems.list
Set playlistId to UU0XXXXXXXXXXXXXXXXXXXX from step 2
Go through each PlaylistItem and pull out the video id

Related

How can I determine a public YouTube channel's username

The YouTube Data API allows us to query data about a channel using the channel id or the channel username.
I thought that a channel's username would be its "#handle" as listed below the channel title and (commonly) in the channel URL. But 3Blue1Brown is a clear counterexample to this.
from googleapiclient.discovery import build
# Instantiate a googleapiclient.discovery.Resource object for youtube
youtube = build(
serviceName='youtube',
version='v3',
developerKey='MYKEY'
)
# Define the request
request = youtube.channels().list(
part="contentDetails",
forUsername="3blue1brown"
)
# Execute the request and save the response
response = request.execute()
response
# {'kind': 'youtube#channelListResponse',
# 'etag': 'RuuXzTIr0OoDqI4S0RU6n4FqKEM',
# 'pageInfo': {'totalResults': 0, 'resultsPerPage': 5}}
I know I can just use the channel's id instead, but the id is becoming harder to find and frankly, it just bothers me that I don't know how to find a channel's username.

How to avoid omissions in video information acquisition when using the YouTube Data API?

Assumption / What I want to achieve
I want to use YouTube Data API V3 to get the video ID without any omissions, and find out if the cause of the trouble is in the code or in the video settings of YouTube (API side).
Problem
The following code is used to get the video information from YouTube Data API, but the number of IDs I got did not match the number of videos that are actually posted.
from apiclient.discovery
import build
id = "UCD-miitqNY3nyukJ4Fnf4_A" #sampleID
token_check = None
nextPageToken = None
id_info = []
while True:
if token_check != None:
nextPageToken = token_check
Search_Video = youtube.search().list(
part = "id",
channelId = id,
maxResults = 50,
order = 'date',
safeSearch = "none",
pageToken = nextPageToken
).execute()
for ID_check in Search_Video.get("items", []):
if ID_check["id"]["kind"] == "youtube#video":
id_info.append(ID_check["id"]["videoId"])
try:
token_check = Search_Video["nextPageToken"]
except:
print(len(id_info)) #check number of IDs
break
I also used the YouTube Data API function to get the videoCount information of the channel, and noticed that the value of videoCount did not match the number of IDs obtained by the code above, which is why I posted this.
According to channels() API, this channel have 440 videos, but the above code gets only 412 videos (at 10:30 a.m. JST).
Supplemental Information
・Python 3.9.0
・YouTube Data API v3
You have to acknowledge that the Search.list API endpoint does not have a crisp behavior. That means you should not expect precise results from it. Google does not document this behavior as such, but this forum has many posts from users experiencing that.
If you want to obtain all the IDs of videos uploaded by a given channel then you should employ the following two-step procedure:
Step 1: Obtain the ID of the Uploads Playlist of a Channel.
Invoke the Channels.list API endpoint, queried with its request parameter id set to the ID of the channel of your interest (or, otherwise, with its request parameter mine set to true) for to obtain that channel's uploads playlist ID, contentDetails.relatedPlaylists.uploads.
def get_channel_uploads_playlist_id(youtube, channel_id):
response = youtube.channels().list(
fields = 'items/contentDetails/relatedPlaylists/uploads',
part = 'contentDetails',
id = channel_id,
maxResults = 1
).execute()
items = response.get('items')
if items:
return items[0] \
['contentDetails'] \
['relatedPlaylists'] \
.get('uploads')
else:
return None
Do note that the function get_channel_uploads_playlist_id should only be called once for to obtain the uploads playlist
ID of a given channel; subsequently use that ID as many times as needed.
Step 2: Retrieve All IDs of Videos of a Playlist.
Invoke the PlaylistItems.list API endpoint, queried with its request parameter playlistId set to the ID obtained from get_channel_uploads_playlist_id:
def get_playlist_video_ids(youtube, playlist_id):
request = youtube.playlistItems().list(
fields = 'nextPageToken,items/snippet/resourceId',
playlistId = playlist_id,
part = 'snippet',
maxResults = 50
)
videos = []
is_video = lambda item: \
item['snippet']['resourceId']['kind'] == 'youtube#video'
video_id = lambda item: \
item['snippet']['resourceId']['videoId']
while request:
response = request.execute()
items = response.get('items', [])
assert len(items) <= 50
videos.extend(map(video_id, filter(is_video, items)))
request = youtube.playlistItems().list_next(
request, response)
return videos
Do note that, when using the Google's APIs Client Library for Python (as you do), API result set pagination is trivially simple: just use the list_next method of the Python API object corresponding to the respective paginated API endpoint (as was shown above):
request = API_OBJECT.list(...)
while request:
response = request.execute()
...
request = API_OBJECT.list_next(
request, response)
Also note that above I used twice the fields request parameter. This is good practice: ask from the API only the info that is of actual use.
Yet an important note: the PlaylistItems.list endpoint would not return items that correspond to private videos of a channel when invoked with an API key. This happens when your youtube object was constructed by calling the function apiclient.discovery.build upon passing to it the parameter developerKey.
PlaylistItems.list returns items corresponding to private videos only to the channel owner. This happens when the youtube object is constructed by calling the function apiclient.discovery.build upon passing to it the parameter credentials and if credentials refer to the channel that owns the respective playlist.
An additional important note: according to Google staff, there's an upper 20000 limit set by design for the number of items returned via PlaylistItems.list endpoint when queried for a given channel's uploads playlist. This is unfortunate, but a fact.

Optimize query to YouTube API

Help optimize YouTube API requests. The entire quota is spent in 5 minutes
Get id TOP 5 trends:
https://www.googleapis.com/youtube/v3/videos?part=contentDetails&key={token}&fields=items(id)&chart=mostPopular&regionCode=RU&maxResults=5
Get channel id and channel name from video id:
https://www.googleapis.com/youtube/v3/videos?part=snippet&id={VideoId}&key={token}
Get channel name from username
https://www.googleapis.com/youtube/v3/channels?key={token}&forUsername={UserName}&part=id
Get channel image:
https://www.googleapis.com/youtube/v3/channels?id={ChannelId}&part=snippet&key={token}
Video count on channel:
​https://www.googleapis.com/youtube/v3/playlistItems?playlistId={ChannelId}&key={token}&part=snippet
Last video on channel:
https://www.googleapis.com/youtube/v3/search?key={token}&channelId={ChannelId}&part=id&order=date&maxResults=1
These are a few tips I think it might help:
Set specific fields to retrieve in each request.
The "search" request is the one who consumes more quota than the rest of your requests.
Here are your modified requests:
Get id TOP 5 trends - Demo:
https://www.googleapis.com/youtube/v3/videos?part=contentDetails&chart=mostPopular&hl=<REGION_CODE>&maxResults=5&fields=items%2Fid&key={YOUR_API_KEY}
Get channel id and channel name from video id: - demo
https://www.googleapis.com/youtube/v3/videos?part=snippet&id=<VIDEO_ID>&fields=items(snippet(channelId%2CchannelTitle))&key={YOUR_API_KEY}
Get channel name from username (also bring at the same time the channel image and its count of uploaded videos) - demo
https://www.googleapis.com/youtube/v3/channels?part=snippet%2Cstatistics&forUsername=<CHANNEL_USERNAME>&fields=items(snippet(thumbnails%2Ctitle)%2Cstatistics%2FvideoCount)&key={YOUR_API_KEY}
Last video on channel: - demo
Here you can use other approach:
Use the channel_id and replace the value as follows:
Channel: Microsoft Hololens:
Channel_id: UCT2rZIAL-zNqeK1OmLLUa6g
Uploads (playlist): UUT2rZIAL-zNqeK1OmLLUa6g
Once you get the uploads (playlist), use the following request:
https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails&playlistId=<UPLOAD_PLAYLIST>&fields=items(contentDetails(videoId%2CvideoPublishedAt))&key={YOUR_API_KEY}
And use the latest videoId from the response - (which has the most recent updated time).

YouTube API PlaylistItems/list limited to 5000 results?

I am trying to get a list of all titles from YouTube channel machinima. Machinima currently has (I'm guessing here) tens of thousands of videos.
The following Python script is supposed to walk the chain of pages containing playlist items (the playlist being user's uploads).
channels_response = youtube.channels().list(
id=DEFAULT_CHANNEL,
part="contentDetails"
).execute()
if len(channels_response["items"]) == 0:
channels_response = youtube.channels().list(
forUsername=DEFAULT_CHANNEL,
part="contentDetails"
).execute()
for channel in channels_response["items"]:
# From the API response, extract the playlist ID that identifies the list
# of videos uploaded to the authenticated user's channel.
uploads_list_id = channel["contentDetails"]["relatedPlaylists"]["uploads"]
print "Videos in list %s" % uploads_list_id
# Retrieve the list of videos uploaded to the authenticated user's channel.
playlistitems_list_request = youtube.playlistItems().list(
playlistId=uploads_list_id,
part="snippet",
maxResults=50
)
while playlistitems_list_request:
playlistitems_list_response = playlistitems_list_request.execute()
# Print information about each video.
for playlist_item in playlistitems_list_response["items"]:
title = playlist_item["snippet"]["title"]
video_id = playlist_item["snippet"]["resourceId"]["videoId"]
print video_id
videos.append(video_id)
titles.append(title)
playlistitems_list_request = youtube.playlistItems().list_next(
playlistitems_list_request, playlistitems_list_response)
However, for some reason, I always end up getting no more than 5,000 videos.
I checked the API documentation, but there is no reference of limit of such sort. The code I'm using is from the official documentation too (slightly modified) and should work.
Does anyone know how could I get ALL the videos from Machinima?
EDIT: Update on October 20th. The limit seems to have disappeared.

Resolving two types of YouTube channel URLs in API v3

I'm taking a youtube url as user input.
The logic I have is as follows:
if(URL === link_to_video) then get video
else if( URL == link_to_channel) then get all_videos_of_channel.
I am doing this via JavaScript and using the YouTube API v3.
The problem is, it seems youtube has two types of URLs to youtube channels.
/channel/, eg:
www.youtube.com/channel/UCaHNFIob5Ixv74f5on3lvIw
/user/,
eg: www.youtube.com/user/CalvinHarrisVEVO
both the above links will take you to the same channel, but my current uploader code supports only /user/CalvinHarrisVEVO.
is there any way to make both the URLs behave similarly in terms of obtaining the channel videos?
One solution would be to parse the url and then apply this logic:
if there is `channel` in the url link
call the APIv3 with the **id** of the channel
Ressource : youtube.channels.list
else if there is 'user'
call the APIv3 with the **forUsername** of the channel
Ressource : youtube.channels.list
Check : https://developers.google.com/apis-explorer/#p/youtube/v3/youtube.channels.list

Resources