Reputation: 13
I need to get the ID and title for all videos from my own YouTube channel. Some of videos are unlisted, but I want to get them too. I use this version of the client library:
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-youtube</artifactId>
<version>v3-rev222-1.25.0</version>
</dependency>
According to the documentation I use this Java code:
YouTube.Search.List request = youtubeService.search()
.list("id,snippet");
SearchListResponse response = request.setChannelId(channelId)
.setForMine(true)
.setMaxResults(50L)
.setType("video")
.execute();
But got this exception:
400 Bad Request
GET https://www.googleapis.com/youtube/v3/search?channelId=channelId&forMine=true&maxResults=50&part=id,snippet&type=video
{
"code" : 400,
"errors" : [ {
"domain" : "youtube.search",
"location" : "parameters.",
"locationType" : "other",
"message" : "The request contains an invalid combination of search filters and/or restrictions. Note that you must set the <code>type</code> parameter to <code>video</code> if you set either the <code>forContentOwner</code> or <code>forMine</code> parameters to <code>true</code>. You must also set the <code>type</code> parameter to <code>video</code> if you set a value for the <code>eventType</code>, <code>videoCaption</code>, <code>videoCategoryId</code>, <code>videoDefinition</code>, <code>videoDimension</code>, <code>videoDuration</code>, <code>videoEmbeddable</code>, <code>videoLicense</code>, <code>videoSyndicated</code>, or <code>videoType</code> parameters.",
"reason" : "invalidSearchFilter"
} ],
"message" : "The request contains an invalid combination of search filters and/or restrictions. Note that you must set the <code>type</code> parameter to <code>video</code> if you set either the <code>forContentOwner</code> or <code>forMine</code> parameters to <code>true</code>. You must also set the <code>type</code> parameter to <code>video</code> if you set a value for the <code>eventType</code>, <code>videoCaption</code>, <code>videoCategoryId</code>, <code>videoDefinition</code>, <code>videoDimension</code>, <code>videoDuration</code>, <code>videoEmbeddable</code>, <code>videoLicense</code>, <code>videoSyndicated</code>, or <code>videoType</code> parameters."
}
Moreover I got the same error using interactive tool on this page:
https://developers.google.com/youtube/v3/docs/search/list?apix=true
.
If I remove .setForMine(true)
it works fine, but doesn't give me unlisted videos (gives me only public videos).
Are there any possibilities to get the ID and title of all videos (unlisted included) from my own channel via the API?
Upvotes: 0
Views: 1896
Reputation: 6985
The short answer to your question is: indeed, there is an API that will provide all video metadata of your channel, including the metadata of unlisted videos.
For the longer answer, just bear with me for a while:
First thing, do note that a given video has a privacy status of the following kinds:
status.privacyStatus
(string)
The video's privacy status. Valid values for this property are:
- private
- public
- unlisted
For to obtain the IDs of all videos uploaded by your channel, irrespective of their privacy status, you'll have to invoke the PlaylistItems.list
API endpoint queried with the parameter playlistId
set to the ID of your channel's uploads playlist, while issuing an OAuth authorized request (that is: passing to the API a valid access token; using only an API key will make the endpoint return only public videos):
List<String> scopes = Lists.newArrayList(
"https://www.googleapis.com/auth/youtube.readonly"); // or ".../auth/youtube"
Credential credential = Auth.authorize(scopes, "myuploads");
youtube = new YouTube.Builder(
Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential)
.setApplicationName("myuploads")
.build();
List<String> videoIdList = new ArrayList<String>();
YouTube.PlaylistItems.List playlistItemRequest =
youtube.playlistItems().list("contentDetails");
playlistItemRequest.setFields("nextPageToken,items/contentDetails/videoId");
playlistItemRequest.setMaxResults(50);
playlistItemRequest.setPlaylistId(uploadsPlaylistId);
String nextToken = "";
do {
playlistItemRequest.setPageToken(nextToken);
PlaylistItemListResponse playlistItemResult = playlistItemRequest.execute();
for (PlaylistItem playlistItem: playlistItemResult.getItems())
videoIdList.add(playlistItem.getContentDetails().getVideoId());
nextToken = playlistItemResult.getNextPageToken();
} while (nextToken != null);
Now, the Videos.list
API endpoint will provide you all the metadata of the videos of which IDs are collected by videoIdList
.
List<Video> videoList = new ArrayList<Video>();
while (videoIdList.size() > 0) {
int endIndex = videoIdList.size() < 50 ? videoIdList.size() : 50;
List<String> subList = videoIdList.subList(0, endIndex);
YouTube.Videos.List videosRequest =
youtube.videos().list("id,contentDetails,status,snippet, statistics");
videosRequest.setId(String.join(",", subList));
VideoListResponse videosResponse = videoRequest.execute();
videoList.AddAll(videosResponse.getItems());
subList.clear();
}
Note that, if videoIdList
is of size N
at the beginning of the loop above -- since the parameter id
of Videos.list
endpoint can be specified as a comma-separated list of video IDs --, the loop code reduces the number of calls to Videos.list
endpoint from N
to Math.floor(N / 50) + (N % 50 ? 1 : 0)
by appropriately using the feature of id
just mentioned.
The uploads playlist ID -- uploadsPlaylistId
-- may very easily be obtained by invoking the Channels.list
endpoint queried with the parameter id
set to your channel's ID, or, otherwise, queried with the parameter mine
set to true
:
YouTube.Channels.List channelRequest =
youtube.channels().list("contentDetails");
channelRequest.setMine(true);
channelRequest.setFields("items/contentDetails/relatedPlaylists/uploads");
ChannelListResponse channelResult = channelRequest.execute();
Note that above I used the fields
parameter for to get from the API only the info that's needed.
The uploads playlist ID is then to be found within the endpoint's JSON response as value of the property:
items[0].contentDetails.relatedPlaylists.uploads
.
Translated to Java, this property path would become the following chain of getters, ending with getUploads
:
channelResult.getItems().get(0).getContentDetails().getRelatedPlaylists().getUploads()
.
Note that for a given channel, you need to obtain the uploads playlist ID only once, then use it as many times as you wish. Usually, a channel ID and its corresponding uploads playlist ID are related by s/^UC([0-9a-zA-Z_-]{22})$/UU\1/
.
For an almost complete implementation of the API calls I described above (excluding the loop that fills up the list videoList
), I'll recommend to make use of the following sample program from Google: MyUploads.java
. The loop that constructs the list videoList
is similar to the one found in GeolocationSearch.java
. The implementation of method Auth.authorize
is to be found in Auth.java
.
Upvotes: 2