diff --git a/apps-script/quickstart.gs b/apps-script/quickstart.gs
new file mode 100644
index 00000000..78f51cdc
--- /dev/null
+++ b/apps-script/quickstart.gs
@@ -0,0 +1,36 @@
+// Note: Apps Script automatically requests authorization
+// based on the API's used in the code.
+
+function channelsListByUsername(part, params) {
+ var response = YouTube.Channels.list(part,
+ params);
+ var channel = response.items[0];
+ var dataRow = [channel.id, channel.snippet.title, channel.statistics.viewCount];
+ SpreadsheetApp.getActiveSpreadsheet().appendRow(dataRow);
+}
+
+function getChannel() {
+ var ui = SpreadsheetApp.getUi();
+ var channelName = ui.prompt("Enter the channel name: ").getResponseText();
+ channelsListByUsername('snippet,contentDetails,statistics',
+ {'forUsername': channelName});
+}
+
+function getGoogleDevelopersChannel() {
+ channelsListByUsername('snippet,contentDetails,statistics',
+ {'forUsername': 'GoogleDevelopers'});
+}
+
+function onOpen() {
+ var firstCell = SpreadsheetApp.getActiveSheet().getRange(1, 1).getValue();
+ if (firstCell != 'ID') {
+ var headerRow = ["ID", "Title", "View count"];
+ SpreadsheetApp.getActiveSpreadsheet().appendRow(headerRow);
+ }
+ var ui = SpreadsheetApp.getUi();
+ ui.createMenu('YouTube Data')
+ .addItem('Add channel data', 'getChannel')
+ .addSeparator()
+ .addItem('Add GoogleDevelopers data', 'getGoogleDevelopersChannel')
+ .addToUi();
+}
diff --git a/apps-script/snippets/README.md b/apps-script/snippets/README.md
new file mode 100644
index 00000000..7c7f00c5
--- /dev/null
+++ b/apps-script/snippets/README.md
@@ -0,0 +1,32 @@
+# Apps Script Code Snippets
+
+The `youtube-data-api.gs` file in this directory contains code snippets that are generated
+by the Data API code snippet tool at:
+https://developers.google.com/youtube/v3/code_samples/code_snippets
+
+You can use that tool to test different parameter values and to generate code samples with
+those modified parameter values. The tool generates code for several other programming
+languages as well.
+
+Each function in the file demonstrates a particular use case for a particular API method.
+For example, there are several different use cases for calling the `search.list()` method,
+such as searching by keyword or searching for live events.
+
+In addition to the use-case-specific functions, the file also contains some boilerplate code
+that prints some data from an API response to the logging console. The print function is
+currently designed just to show that each API response returns data and serves as a placeholder
+for any function that would actually process an API response.
+
+## Running these samples
+
+To run these samples:
+
+1. Create a spreadsheet in [Google Drive](https://spreadsheets.google.com).
+2. Select **Tools > Script Editor** from the menu bar.
+3. Paste this code into the script editor and save your file.
+4. In the script, select **Resources > Advanced Google Services** and toggle the option for the
+ YouTube Data API to on.
+5. Click the link to the Google Developers Console and enable the YouTube Data API for the project.
+6. Go back to the script editor and click 'OK' to indicate that you have finished enabling advanced services.
+7. Run the `Main` function in your script.
+8. Select **View > Logs** to see the output from the script.
diff --git a/apps-script/snippets/apps-script.gs b/apps-script/snippets/apps-script.gs
new file mode 100644
index 00000000..1ac8e92d
--- /dev/null
+++ b/apps-script/snippets/apps-script.gs
@@ -0,0 +1,475 @@
+// Sample Apps Script code for printing API response data
+function printResults(response) {
+ var props = ['type', 'title', 'textDisplay', 'channelId', 'videoId', 'hl', 'gl', 'label'];
+ for (var r = 0; r < response['items'].length; r++) {
+ var item = response['items'][r];
+ var itemId = '';
+ var value;
+ if (item['rating']) {
+ itemId = item['id'];
+ value = 'Rating: ' + item['rating'];
+ } else {
+ if (item['id']['videoId']) {
+ itemId = item['id']['videoId'];
+ } else if (item['id']['channelId']) {
+ itemId = item['id']['channelId'];
+ } else {
+ itemId = item['id'];
+ }
+
+ for (var p = 0; p < props.length; p++) {
+ if (item['snippet'][props[p]]) {
+ value = itemId + ': ' + item['snippet'][props[p]];
+ break;
+ }
+ }
+ }
+ Logger.log(value);
+ }
+}
+
+/**
+ * This example retrieves the 25 most recent activities for the Google Developers
+ * channel. It retrieves the snippet and contentDetails parts for each activity
+ * resource.
+ */
+function activitiesList(part, channelId, maxResults) {
+ var response = YouTube.Activities.list(part,
+ {'channelId': channelId,
+ 'maxResults': maxResults});
+ printResults(response);
+}
+
+/**
+ * This example retrieves the 25 most recent activities performed by the user
+ * authorizing the API request.
+ */
+function activitiesListMine(part, maxResults, mine) {
+ var response = YouTube.Activities.list(part,
+ {'maxResults': maxResults,
+ 'mine': mine});
+ printResults(response);
+}
+
+/**
+ * This example lists caption tracks available for the Volvo Trucks "Epic Split"
+ * commercial, featuring Jean-Claude Van Damme. (This video was selected because
+ * it has many available caption tracks and also because it is awesome.)
+ */
+function captionsList(part, videoId) {
+ var response = YouTube.Captions.list(part, videoId);
+ printResults(response);
+}
+
+/**
+ * This example retrieves channel data for the GoogleDevelopers YouTube channel.
+ * It uses the id request parameter to identify the channel by its YouTube channel
+ * ID.
+ */
+function channelsListById(part, id) {
+ var response = YouTube.Channels.list(part,
+ {'id': id});
+ printResults(response);
+}
+
+/**
+ * This example retrieves channel data for the GoogleDevelopers YouTube channel.
+ * It uses the forUsername request parameter to identify the channel by its
+ * YouTube username.
+ */
+function channelsListByUsername(part, forUsername) {
+ var response = YouTube.Channels.list(part,
+ {'forUsername': forUsername});
+ printResults(response);
+}
+
+/**
+ * This example retrieves the channel data for the authorized user's YouTube
+ * channel. It uses the mine request parameter to indicate that the API should
+ * only return channels owned by the user authorizing the request.
+ */
+function channelsListMine(part, mine) {
+ var response = YouTube.Channels.list(part,
+ {'mine': mine});
+ printResults(response);
+}
+
+/**
+ * This example retrieves the channel sections shown on the Google Developers
+ * channel, using the channelId request parameter to identify the channel.
+ */
+function channelSectionsListById(part, channelId) {
+ var response = YouTube.ChannelSections.list(part,
+ {'channelId': channelId});
+ printResults(response);
+}
+
+/**
+ * This example retrieves the channel sections shown on the authorized user's
+ * channel. It uses the mine request parameter to indicate that the API should
+ * return channel sections on that channel.
+ */
+function channelSectionsListMine(part, mine) {
+ var response = YouTube.ChannelSections.list(part,
+ {'mine': mine});
+ printResults(response);
+}
+
+/**
+ * This example retrieves comment replies for a specified comment, which is
+ * identified by the parentId request parameter. In this example, the parent
+ * comment is the first comment on a video about Apps Script. The video was chosen
+ * because this particular comment had multiple replies (in multiple languages)
+ * and also because Apps Script is really useful.
+ */
+function commentsList(part, parentId) {
+ var response = YouTube.Comments.list(part,
+ {'parentId': parentId});
+ printResults(response);
+}
+
+/**
+ * This example retrieves all comment threads associated with a particular
+ * channel. The response could include comments about the channel or about the
+ * channel's videos. The request's allThreadsRelatedToChannelId parameter
+ * identifies the channel.
+ */
+function commentThreadsListAllThreadsByChannelId(part, allThreadsRelatedToChannelId) {
+ var response = YouTube.CommentThreads.list(part,
+ {'allThreadsRelatedToChannelId': allThreadsRelatedToChannelId});
+ printResults(response);
+}
+
+/**
+ * This example retrieves all comment threads about the specified channel. The
+ * request's channelId parameter identifies the channel. The response does not
+ * include comments left on videos that the channel uploaded.
+ */
+function commentThreadsListByChannelId(part, channelId) {
+ var response = YouTube.CommentThreads.list(part,
+ {'channelId': channelId});
+ printResults(response);
+}
+
+/**
+ * This example retrieves all comment threads associated with a particular video.
+ * The request's videoId parameter identifies the video.
+ */
+function commentThreadsListByVideoId(part, videoId) {
+ var response = YouTube.CommentThreads.list(part,
+ {'videoId': videoId});
+ printResults(response);
+}
+
+/**
+ * This example retrieves a list of application languages that the YouTube website
+ * supports. The example sets the hlparameter value to es_MX, indicating that text
+ * values in the API response should be provided in that language. That
+ * parameter's default value is en_US.
+ */
+function i18nLanguagesList(part, hl) {
+ var response = YouTube.I18nLanguages.list(part,
+ {'hl': hl});
+ printResults(response);
+}
+
+/**
+ * This example retrieves a list of content regions that the YouTube website
+ * supports. The example sets the hlparameter value to es_MX, indicating that text
+ * values in the API response should be provided in that language. That
+ * parameter's default value is en_US.
+ */
+function i18nRegionsList(part, hl) {
+ var response = YouTube.I18nRegions.list(part,
+ {'hl': hl});
+ printResults(response);
+}
+
+/**
+ * This example retrieves the list of videos in a specified playlist. The
+ * request's playlistId parameter identifies the playlist.
+
+Note that the API
+ * response does not include metadata about the playlist itself, such as the
+ * playlist's title and description. Additional metadata about the videos in the
+ * playlist can also be retrieved using the videos.listmethod.
+ */
+function playlistItemsListByPlaylistId(part, maxResults, playlistId) {
+ var response = YouTube.PlaylistItems.list(part,
+ {'maxResults': maxResults,
+ 'playlistId': playlistId});
+ printResults(response);
+}
+
+/**
+ * This example retrieves playlists owned by the YouTube channel that the
+ * request's channelId parameter identifies.
+ */
+function playlistsListByChannelId(part, channelId, maxResults) {
+ var response = YouTube.Playlists.list(part,
+ {'channelId': channelId,
+ 'maxResults': maxResults});
+ printResults(response);
+}
+
+/**
+ * This example retrieves playlists created in the authorized user's YouTube
+ * channel. It uses the mine request parameter to indicate that the API should
+ * only return playlists owned by the user authorizing the request.
+ */
+function playlistsListMine(part, mine) {
+ var response = YouTube.Playlists.list(part,
+ {'mine': mine});
+ printResults(response);
+}
+
+/**
+ * This example retrieves the first 25 search results associated with the keyword
+ * surfing. Since the request doesn't specify a value for the type request
+ * parameter, the response can include videos, playlists, and channels.
+ */
+function searchListByKeyword(part, maxResults, q, type) {
+ var response = YouTube.Search.list(part,
+ {'maxResults': maxResults,
+ 'q': q,
+ 'type': type});
+ printResults(response);
+}
+
+/**
+ * This example retrieves search results associated with the keyword surfing that
+ * also specify in their metadata a geographic location within 10 miles of the
+ * point identified by the location parameter value. (The sample request specifies
+ * a point on the North Shore of Oahu, Hawaii . The request retrieves the top five
+ * results, which is the default number returned when the maxResults parameter is
+ * not specified.
+ */
+function searchListByLocation(part, location, locationRadius, q, type) {
+ var response = YouTube.Search.list(part,
+ {'location': location,
+ 'locationRadius': locationRadius,
+ 'q': q,
+ 'type': type});
+ printResults(response);
+}
+
+/**
+ * This example retrieves a list of acdtive live broadcasts (see the eventType
+ * parameter value) that are associated with the keyword news. Since the eventType
+ * parameter is set, the request must also set the type parameter value to video.
+ */
+function searchListLiveEvents(part, eventType, maxResults, q, type) {
+ var response = YouTube.Search.list(part,
+ {'eventType': eventType,
+ 'maxResults': maxResults,
+ 'q': q,
+ 'type': type});
+ printResults(response);
+}
+
+/**
+ * This example searches within the authorized user's videos for videos that match
+ * the keyword fun. The forMine parameter indicates that the response should only
+ * search within the authorized user's videos. Also, since this request uses the
+ * forMine parameter, it must also set the type parameter value to video.
+
+If you
+ * have not uploaded any videos associated with that term, you will not see any
+ * items in the API response list.
+ */
+function searchListMine(part, maxResults, forMine, q, type) {
+ var response = YouTube.Search.list(part,
+ {'maxResults': maxResults,
+ 'forMine': forMine,
+ 'q': q,
+ 'type': type});
+ printResults(response);
+}
+
+/**
+ * This example sets the relatedToVideoId parameter to retrieve a list of videos
+ * related to that video. Since the relatedToVideoId parameter is set, the request
+ * must also set the type parameter value to video.
+ */
+function searchListRelatedVideos(part, relatedToVideoId, type) {
+ var response = YouTube.Search.list(part,
+ {'relatedToVideoId': relatedToVideoId,
+ 'type': type});
+ printResults(response);
+}
+
+/**
+ * This example retrieves a list of channels that the specified channel subscribes
+ * to. In this example, the API response lists channels to which the GoogleDevelopers channel
+ * subscribes.
+ */
+function subscriptionsListByChannelId(part, channelId) {
+ var response = YouTube.Subscriptions.list(part,
+ {'channelId': channelId});
+ printResults(response);
+}
+
+/**
+ * This example determines whether the user authorizing the API request subscribes
+ * to the channel that the forChannelId parameter identifies. To check whether
+ * another channel (instead of the authorizing user's channel) subscribes to the
+ * specified channel, remove the mine parameter from this request and add the channelId parameter
+ * instead.
+
+In this example, the API response contains one item if you subscribe to
+ * the GoogleDevelopers channel. Otherwise, the request does not return any items.
+ */
+function subscriptionsListForChannelId(part, forChannelId, mine) {
+ var response = YouTube.Subscriptions.list(part,
+ {'forChannelId': forChannelId,
+ 'mine': mine});
+ printResults(response);
+}
+
+/**
+ * This example uses the mySubscribers parameter to retrieve the list of channels
+ * to which the authorized user subscribes.
+ */
+function subscriptionsListMySubscribers(part, mySubscribers) {
+ var response = YouTube.Subscriptions.list(part,
+ {'mySubscribers': mySubscribers});
+ printResults(response);
+}
+
+/**
+ * This example uses the mine parameter to retrieve a list of channels that
+ * subscribe to the authenticated user's channel.
+ */
+function subscriptionsListMySubscriptions(part, mine) {
+ var response = YouTube.Subscriptions.list(part,
+ {'mine': mine});
+ printResults(response);
+}
+
+/**
+ * This example shows how to retrieve a list of reasons that can be used to report
+ * abusive videos. You can retrieve the text labels in other languages by
+ * specifying a value for the hl request parameter.
+ */
+function videoAbuseReportReasonsList(part) {
+ var response = YouTube.VideoAbuseReportReasons.list(part);
+ printResults(response);
+}
+
+/**
+ * This example retrieves a list of categories that can be associated with YouTube
+ * videos in the United States. The regionCode parameter specifies the country for
+ * which categories are being retrieved.
+ */
+function videoCategoriesList(part, regionCode) {
+ var response = YouTube.VideoCategories.list(part,
+ {'regionCode': regionCode});
+ printResults(response);
+}
+
+/**
+ * This example uses the regionCode to retrieve a list of categories that can be
+ * associated with YouTube videos in Spain. It also uses the hl parameter to
+ * indicate that text labels in the response should be specified in Spanish.
+ */
+function videoCategoriesListForRegion(part, hl, regionCode) {
+ var response = YouTube.VideoCategories.list(part,
+ {'hl': hl,
+ 'regionCode': regionCode});
+ printResults(response);
+}
+
+/**
+ * This example retrieves information about a specific video. It uses the id
+ * parameter to identify the video.
+ */
+function videosListById(part, id) {
+ var response = YouTube.Videos.list(part,
+ {'id': id});
+ printResults(response);
+}
+
+/**
+ * This example retrieves a list of YouTube's most popular videos. The regionCode
+ * parameter identifies the country for which you are retrieving videos. The
+ * sample code is set to default to return the most popular videos in the United
+ * States. You could also use the videoCategoryId parameter to retrieve the most
+ * popular videos in a particular category.
+ */
+function videosListMostPopular(part, chart, regionCode, videoCategoryId) {
+ var response = YouTube.Videos.list(part,
+ {'chart': chart,
+ 'regionCode': regionCode,
+ 'videoCategoryId': videoCategoryId});
+ printResults(response);
+}
+
+/**
+ * This example retrieves information about a group of videos. The id parameter
+ * value is a comma-separated list of YouTube video IDs. You might issue a request
+ * like this to retrieve additional information about the items in a playlist or
+ * the results of a search query.
+ */
+function videosListMultipleIds(part, id) {
+ var response = YouTube.Videos.list(part,
+ {'id': id});
+ printResults(response);
+}
+
+/**
+ * This example retrieves a list of videos liked by the user authorizing the API
+ * request. By setting the rating parameter value to dislike, you could also use
+ * this code to retrieve disliked videos.
+ */
+function videosListMyRatedVideos(part, myRating) {
+ var response = YouTube.Videos.list(part,
+ {'myRating': myRating});
+ printResults(response);
+}
+
+/**
+ * This example retrieves the rating that the user authorizing the request gave to
+ * a particular video. In this example, the video is of Amy Cuddy's TED talk about
+ * body language.
+ */
+function videosGetRating(id) {
+ var response = YouTube.Videos.getRating(id);
+ printResults(response);
+}
+
+function Main() {
+ activitiesList('snippet,contentDetails', 'UC_x5XG1OV2P6uZZ5FSM9Ttw', 25);
+ activitiesListMine('snippet,contentDetails', 25, true);
+ captionsList('snippet', 'M7FIvfx5J10');
+ channelsListById('snippet,contentDetails,statistics', 'UC_x5XG1OV2P6uZZ5FSM9Ttw');
+ channelsListByUsername('snippet,contentDetails,statistics', 'GoogleDevelopers');
+ channelsListMine('snippet,contentDetails,statistics', true);
+ channelSectionsListById('snippet,contentDetails', 'UC_x5XG1OV2P6uZZ5FSM9Ttw');
+ channelSectionsListMine('snippet,contentDetails', true);
+ commentsList('snippet', 'z13icrq45mzjfvkpv04ce54gbnjgvroojf0');
+ commentThreadsListAllThreadsByChannelId('snippet,replies', 'UC_x5XG1OV2P6uZZ5FSM9Ttw');
+ commentThreadsListByChannelId('snippet,replies', 'UCAuUUnT6oDeKwE6v1NGQxug');
+ commentThreadsListByVideoId('snippet,replies', 'm4Jtj2lCMAA');
+ i18nLanguagesList('snippet', 'es_MX');
+ i18nRegionsList('snippet', 'es_MX');
+ playlistItemsListByPlaylistId('snippet,contentDetails', 25, 'PLBCF2DAC6FFB574DE');
+ playlistsListByChannelId('snippet,contentDetails', 'UC_x5XG1OV2P6uZZ5FSM9Ttw', 25);
+ playlistsListMine('snippet,contentDetails', true);
+ searchListByKeyword('snippet', 25, 'surfing', 'video');
+ searchListByLocation('snippet', '21.5922529,-158.1147114', '10mi', 'surfing', 'video');
+ searchListLiveEvents('snippet', 'live', 25, 'news', 'video');
+ searchListMine('snippet', 25, true, 'fun', 'video');
+ searchListRelatedVideos('snippet', 'Ks-_Mh1QhMc', 'video');
+ subscriptionsListByChannelId('snippet,contentDetails', 'UC_x5XG1OV2P6uZZ5FSM9Ttw');
+ subscriptionsListForChannelId('snippet,contentDetails', 'UC_x5XG1OV2P6uZZ5FSM9Ttw', true);
+ subscriptionsListMySubscribers('snippet,contentDetails,subscriberSnippet', true);
+ subscriptionsListMySubscriptions('snippet,contentDetails', true);
+ videoAbuseReportReasonsList('snippet');
+ videoCategoriesList('snippet', 'US');
+ videoCategoriesListForRegion('snippet', 'es', 'ES');
+ videosListById('snippet,contentDetails,statistics', 'Ks-_Mh1QhMc');
+ videosListMostPopular('snippet,contentDetails,statistics', 'mostPopular', 'US', '');
+ videosListMultipleIds('snippet,contentDetails,statistics', 'Ks-_Mh1QhMc,c0KYU2j0TM4,eIho2S0ZahI');
+ videosListMyRatedVideos('snippet,contentDetails,statistics', 'like');
+ videosGetRating('Ks-_Mh1QhMc,c0KYU2j0TM4,eIho2S0ZahI');
+}
diff --git a/apps-script/youtube.gs b/apps-script/youtube.gs
index d4b55344..cf812534 100644
--- a/apps-script/youtube.gs
+++ b/apps-script/youtube.gs
@@ -1,29 +1,6 @@
-// TITLE: Search by topic
-// DESCRIPTION: use_function_comment
-// API_METHOD: youtube.search.list
-/**
- * This function searches for videos that are associated with a particular Freebase
- * topic, logging their video IDs and titles to the Apps Script log. This example uses
- * the topic ID for Google Apps Script.
- *
- * Note that this sample limits the results to 25. To return more results, pass
- * additional parameters as documented here:
- * https://developers.google.com/youtube/v3/docs/search/list
- */
-function searchByTopic() {
- var mid = '/m/0gjf126';
- var results = YouTube.Search.list('id,snippet', {topicId: mid, maxResults: 25});
-
- for(var i in results.items) {
- var item = results.items[i];
- Logger.log('[%s] Title: %s', item.id.videoId, item.snippet.title);
- }
-}
-
-// TITLE: Search by keyword
-// DESCRIPTION: use_function_comment
-// API_METHOD: youtube.search.list
/**
+ * Title: Search by keyword
+ * Method: youtube.search.list
* This function searches for videos related to the keyword 'dogs'. The video IDs and titles
* of the search results are logged to Apps Script's log.
*
@@ -41,10 +18,9 @@ function searchByKeyword() {
}
-// TITLE: Retrieve my uploads
-// DESCRIPTION: use_function_comment
-// API_METHOD: youtube.channels.list
/**
+ * Title: Retrieve my uploads
+ * Method: youtube.channels.list
* This function retrieves the current script user's uploaded videos. To execute,
* it requires the OAuth read/write scope for YouTube as well as user authorization.
* In Apps Script's runtime environment, the first time a user runs a script, Apps
@@ -93,10 +69,9 @@ function retrieveMyUploads() {
}
}
-// TITLE: Update video
-// DESCRIPTION: use_function_comment
-// API_METHOD: youtube.videos.update
/**
+ * Title: Update video
+ * Method: youtube.videos.update
* This sample finds the active user's uploads, then updates the most recent
* upload's description by appending a string.
*/
@@ -133,10 +108,9 @@ function updateVideo() {
}
}
-// TITLE: Subscribe to channel
-// DESCRIPTION: use_function_comment
-// API_METHOD: youtube.subscriptions.insert
/**
+ * Title: Subscribe to channel
+ * Method: youtube.subscriptions.insert
* This sample subscribes the active user to the GoogleDevelopers
* YouTube channel, specified by the channelId.
*/
@@ -165,10 +139,9 @@ function addSubscription() {
}
}
-// TITLE: Post channel bulletin
-// DESCRIPTION: use_function_comment
-// API_METHOD: youtube.activities.insert
/**
+ * Title: Post channel bulletin
+ * Method: youtube.activities.insert
* This function creates and posts a new channel bulletin, adding a video and message. Note that this
* will also accept a playlist ID. After completing the API call, logs the output to the log.
*/
@@ -194,10 +167,9 @@ function postChannelBulletin() {
Logger.log(response);
}
-// TITLE: Export YouTube Analytics data to Google Sheets
-// DESCRIPTION: use_function_comment
-// API_METHOD: youtubeAnalytics.reports.query
/**
+ * Title: Export YouTube Analytics data to Google Sheets
+ * Method: youtubeAnalytics.reports.query
* This function uses the YouTube Analytics API to fetch data about the
* authenticated user's channel, creating a new Google Sheet in the user's Drive
* with the data.
diff --git a/dotnet/MyUploads.cs b/dotnet/MyUploads.cs
index 7b1b1976..01a22314 100644
--- a/dotnet/MyUploads.cs
+++ b/dotnet/MyUploads.cs
@@ -1,5 +1,3 @@
-/*
-
using System;
using System.IO;
using System.Reflection;
diff --git a/dotnet/PlaylistUpdates.cs b/dotnet/PlaylistUpdates.cs
index a2fe769b..f8e27fd4 100644
--- a/dotnet/PlaylistUpdates.cs
+++ b/dotnet/PlaylistUpdates.cs
@@ -1,5 +1,3 @@
-/*
-
using System;
using System.IO;
using System.Reflection;
diff --git a/dotnet/README.md b/dotnet/README.md
new file mode 100644
index 00000000..3d9a8932
--- /dev/null
+++ b/dotnet/README.md
@@ -0,0 +1,27 @@
+## Samples in this directory:
+
+### [Create a playlist](/dotnet/PlaylistUpdates.cs)
+
+Method: youtube.playlists.insert
+Description: The following code sample calls the API's playlists.insert method to create a private playlist
+owned by the channel authorizing the request.
+
+### [Retrieve my uploads](/dotnet/MyUploads.cs)
+
+Method: youtube.playlistItems.list
+Description: The following code sample calls the API's playlistItems.list method to retrieve a list of videos
+uploaded to the channel associated with the request. The code also calls the channels.list method with the
+mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded
+videos.
+
+### [Search by keyword](/dotnet/Search.cs)
+
+Method: youtube.search.list
+Description: The following code sample calls the API's search.list method to retrieve search results
+associated with a particular keyword.
+
+### [Upload a video](/dotnet/UploadVideo.cs)
+
+Method: youtube.videos.insert
+Description: The following code sample calls the API's videos.insert method to upload a video to the channel
+associated with the request.
diff --git a/dotnet/Search.cs b/dotnet/Search.cs
index a31a3eff..c84357f3 100644
--- a/dotnet/Search.cs
+++ b/dotnet/Search.cs
@@ -1,5 +1,3 @@
-/*
-
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/dotnet/UploadVideo.cs b/dotnet/UploadVideo.cs
index f6d7b893..0e718b37 100644
--- a/dotnet/UploadVideo.cs
+++ b/dotnet/UploadVideo.cs
@@ -1,5 +1,3 @@
-/*
-
using System;
using System.IO;
using System.Reflection;
diff --git a/go/README b/go/README
deleted file mode 100644
index c64bde18..00000000
--- a/go/README
+++ /dev/null
@@ -1,36 +0,0 @@
-Minimum Go version: go 1.1+
-
-To run these code samples, you will need to install the dependent libraries via
-the "go get" command. These code samples require the goauth2 and google-api-go-client
-libraries which can be installed with the following commands:
-
- go get code.google.com/p/goauth2/oauth
- go get code.google.com/p/google-api-go-client/youtube/v3
-
-The keyword search and topic search samples can be run via the standard "go run" command
-once the developerKey constant is populated with an API key created at
-https://code.google.com/apis/console.
-
-Example usage:
-
- go run search_key_keyword.go
-
-The Freebase API and YouTube Data APIs must be enabled for the project associated with this
-key.
-
-To run any sample that requires authorization on behalf of a user, such as checking
-for uploads, this requires the shared oauth.go file to be passed as a parameter to "go run".
-These samples require a "Web Application" client ID and client secret pair which can
-also be created at the Google API console at https://code.google.com/apis/console. Once
-a client ID and secret pair have been created, these values must be populated into
-client_secrets.json in the corresponding fields. A template client_secrets.json has been
-provided in client_secrets.json.sample. Rename this file and populate the fields.
-
-Example usage:
-
- go run my_uploads.go oauth.go
-
-oauth.go contains code that is shared between the code samples that require OAuth 2.0
-authorization, so it must be passed as a parameter to "go run".
-
-More information about the YouTube APIs can be found at https://developer.google.com/youtube.
diff --git a/go/README.md b/go/README.md
new file mode 100644
index 00000000..f85a7847
--- /dev/null
+++ b/go/README.md
@@ -0,0 +1,81 @@
+Recommended Go version: latest version
+
+To run these code samples, you will need to install the dependent libraries via
+the "go get" command. See the client library's getting started guide for more detail:
+https://github.com/google/google-api-go-client/blob/master/GettingStarted.md
+
+You also need to enable the YouTube Data API for the project associated with your developer
+credentials.
+
+## Authorization credentials
+To run any sample that does not require user authorization, such as search\_by\_keyword.go,
+you need to replace the value of the `developerKey` constant with a valid API key:
+
+```
+const developerKey = "YOUR DEVELOPER KEY"
+```
+
+To run any sample that requires authorization on behalf of a user, such as retrieving the
+authenticated user's uploads, you need an OAuth 2.0 client ID and client secret pair. These
+can be created at the Google API console at https://developers.google.com/console. After
+creating your OAuth 2.0 credentials, download the client\_secret.json file to the directory
+in which you are running these samples.
+
+## Running samples
+
+Samples can be run with the standard "go run" command as long as your API key or OAuth 2.0
+credentials are in place. The samples use the `errors.go` file to
+print out API errors, so you need to also include that file in the "go run" command. Samples
+that require authorization also require the `oauth2.go` file to be included in the
+"go run" command:
+
+Example usages:
+
+```
+ go run search_by_keyword.go errors.go
+ go run my_uploads.go errors.go oauth2.go
+ go run upload_video.go errors.go oauth2.go --filename="sample_video.flv" --title="Test video" --keywords="golang test"
+```
+
+More information about the YouTube APIs can be found at https://developers.google.com/youtube.
+
+## Samples in this directory:
+
+### [Authorize a request](/go/oauth2.go)
+
+Description: This code sample performs OAuth 2.0 authorization by checking for the presence of a local file that
+contains authorization credentials. If the file is not present, the script opens a browser and waits for a response,
+then saves the returned credentials locally.
+
+### [List playlists](/go/playlists.go)
+
+Methods: youtube.playlists.list
+Description: This code sample calls the API's `playlists.list` method. Use command-line flags to define the parameters you want to use in the request as shown in the following examples:
playlistItems.list method to retrieve a list of
+videos uploaded to the channel associated with the request. The code also calls the channels.list
+method with the mine parameter set to true to retrieve the playlist ID that identifies
+the channel's uploaded videos.
+
+### [Search by keyword](/go/search_by_keyword.go)
+
+Method: youtube.search.listsearch.list method to retrieve search results associated
+with a particular keyword.
+
+### [Upload a video](/go/upload_video.go)
+
+Method: youtube.videos.insertvideos.insert method to upload a video to the channel
+associated with the request.
diff --git a/go/errors.go b/go/errors.go
new file mode 100644
index 00000000..a53fa3e4
--- /dev/null
+++ b/go/errors.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+ "log"
+)
+
+func handleError(err error, message string) {
+ if message == "" {
+ message = "Error making API call"
+ }
+ if err != nil {
+ log.Fatalf(message + ": %v", err.Error())
+ }
+}
diff --git a/go/my_uploads.go b/go/my_uploads.go
index cdddbf87..216ce3cf 100644
--- a/go/my_uploads.go
+++ b/go/my_uploads.go
@@ -1,60 +1,54 @@
package main
import (
- "flag"
"fmt"
"log"
- "code.google.com/p/google-api-go-client/youtube/v3"
+ "google.golang.org/api/youtube/v3"
)
-func main() {
- flag.Parse()
-
- client, err := buildOAuthHTTPClient(youtube.YoutubeReadonlyScope)
- if err != nil {
- log.Fatalf("Error building OAuth client: %v", err)
+// Retrieve playlistItems in the specified playlist
+func playlistItemsList(service *youtube.Service, part string, playlistId string, pageToken string) *youtube.PlaylistItemListResponse {
+ call := service.PlaylistItems.List(part)
+ call = call.PlaylistId(playlistId)
+ if pageToken != "" {
+ call = call.PageToken(pageToken)
}
+ response, err := call.Do()
+ handleError(err, "")
+ return response
+}
+// Retrieve resource for the authenticated user's channel
+func channelsListMine(service *youtube.Service, part string) *youtube.ChannelListResponse {
+ call := service.Channels.List(part)
+ call = call.Mine(true)
+ response, err := call.Do()
+ handleError(err, "")
+ return response
+}
+
+func main() {
+ client := getClient(youtube.YoutubeReadonlyScope)
service, err := youtube.New(client)
+
if err != nil {
log.Fatalf("Error creating YouTube client: %v", err)
}
- // Start making YouTube API calls.
- // Call the channels.list method. Set the mine parameter to true to
- // retrieve the playlist ID for uploads to the authenticated user's
- // channel.
- call := service.Channels.List("contentDetails").Mine(true)
-
- response, err := call.Do()
- if err != nil {
- // The channels.list method call returned an error.
- log.Fatalf("Error making API call to list channels: %v", err.Error())
- }
+ response := channelsListMine(service, "contentDetails")
for _, channel := range response.Items {
playlistId := channel.ContentDetails.RelatedPlaylists.Uploads
+
// Print the playlist ID for the list of uploaded videos.
fmt.Printf("Videos in list %s\r\n", playlistId)
nextPageToken := ""
for {
- // Call the playlistItems.list method to retrieve the
- // list of uploaded videos. Each request retrieves 50
- // videos until all videos have been retrieved.
- playlistCall := service.PlaylistItems.List("snippet").
- PlaylistId(playlistId).
- MaxResults(50).
- PageToken(nextPageToken)
-
- playlistResponse, err := playlistCall.Do()
-
- if err != nil {
- // The playlistItems.list method call returned an error.
- log.Fatalf("Error fetching playlist items: %v", err.Error())
- }
-
+ // Retrieve next set of items in the playlist.
+ playlistResponse := playlistItemsList(service, "snippet", playlistId, nextPageToken)
+
for _, playlistItem := range playlistResponse.Items {
title := playlistItem.Snippet.Title
videoId := playlistItem.Snippet.ResourceId.VideoId
diff --git a/go/oauth.go b/go/oauth.go
deleted file mode 100644
index 58ff987b..00000000
--- a/go/oauth.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "errors"
- "flag"
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
-
- "code.google.com/p/goauth2/oauth"
-)
-
-const missingClientSecretsMessage = `
-Please configure OAuth 2.0
-
-To make this sample run, you need to populate the client_secrets.json file
-found at:
-
- %v
-
-with information from the {{ Google Cloud Console }}
-{{ https://cloud.google.com/console }}
-
-For more information about the client_secrets.json file format, please visit:
-https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
-`
-
-var (
- clientSecretsFile = flag.String("secrets", "client_secrets.json", "Client Secrets configuration")
- cacheFile = flag.String("cache", "request.token", "Token cache file")
-)
-
-// ClientConfig is a data structure definition for the client_secrets.json file.
-// The code unmarshals the JSON configuration file into this structure.
-type ClientConfig struct {
- ClientID string `json:"client_id"`
- ClientSecret string `json:"client_secret"`
- RedirectURIs []string `json:"redirect_uris"`
- AuthURI string `json:"auth_uri"`
- TokenURI string `json:"token_uri"`
-}
-
-// Config is a root-level configuration object.
-type Config struct {
- Installed ClientConfig `json:"installed"`
- Web ClientConfig `json:"web"`
-}
-
-// openURL opens a browser window to the specified location.
-// This code originally appeared at:
-// http://stackoverflow.com/questions/10377243/how-can-i-launch-a-process-that-is-not-a-file-in-go
-func openURL(url string) error {
- var err error
- switch runtime.GOOS {
- case "linux":
- err = exec.Command("xdg-open", url).Start()
- case "windows":
- err = exec.Command("rundll32", "url.dll,FileProtocolHandler", "http://localhost:4001/").Start()
- case "darwin":
- err = exec.Command("open", url).Start()
- default:
- err = fmt.Errorf("Cannot open URL %s on this platform", url)
- }
- return err
-}
-
-// readConfig reads the configuration from clientSecretsFile.
-// It returns an oauth configuration object for use with the Google API client.
-func readConfig(scope string) (*oauth.Config, error) {
- // Read the secrets file
- data, err := ioutil.ReadFile(*clientSecretsFile)
- if err != nil {
- pwd, _ := os.Getwd()
- fullPath := filepath.Join(pwd, *clientSecretsFile)
- return nil, fmt.Errorf(missingClientSecretsMessage, fullPath)
- }
-
- cfg := new(Config)
- err = json.Unmarshal(data, &cfg)
- if err != nil {
- return nil, err
- }
-
- var redirectUri string
- if len(cfg.Web.RedirectURIs) > 0 {
- redirectUri = cfg.Web.RedirectURIs[0]
- } else if len(cfg.Installed.RedirectURIs) > 0 {
- redirectUri = cfg.Installed.RedirectURIs[0]
- } else {
- return nil, errors.New("Must specify a redirect URI in config file or when creating OAuth client")
- }
-
- return &oauth.Config{
- ClientId: cfg.Installed.ClientID,
- ClientSecret: cfg.Installed.ClientSecret,
- Scope: scope,
- AuthURL: cfg.Installed.AuthURI,
- TokenURL: cfg.Installed.TokenURI,
- RedirectURL: redirectUri,
- TokenCache: oauth.CacheFile(*cacheFile),
- // Get a refresh token so we can use the access token indefinitely
- AccessType: "offline",
- // If we want a refresh token, we must set this attribute
- // to force an approval prompt or the code won't work.
- ApprovalPrompt: "force",
- }, nil
-}
-
-// startWebServer starts a web server that listens on http://localhost:8080.
-// The webserver waits for an oauth code in the three-legged auth flow.
-func startWebServer() (codeCh chan string, err error) {
- listener, err := net.Listen("tcp", "localhost:8080")
- if err != nil {
- return nil, err
- }
- codeCh = make(chan string)
- go http.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- code := r.FormValue("code")
- codeCh <- code // send code to OAuth flow
- listener.Close()
- w.Header().Set("Content-Type", "text/plain")
- fmt.Fprintf(w, "Received code: %v\r\nYou can now safely close this browser window.", code)
- }))
-
- return codeCh, nil
-}
-
-// buildOAuthHTTPClient takes the user through the three-legged OAuth flow.
-// It opens a browser in the native OS or outputs a URL, then blocks until
-// the redirect completes to the /oauth2callback URI.
-// It returns an instance of an HTTP client that can be passed to the
-// constructor of the YouTube client.
-func buildOAuthHTTPClient(scope string) (*http.Client, error) {
- config, err := readConfig(scope)
- if err != nil {
- msg := fmt.Sprintf("Cannot read configuration file: %v", err)
- return nil, errors.New(msg)
- }
-
- transport := &oauth.Transport{Config: config}
-
- // Try to read the token from the cache file.
- // If an error occurs, do the three-legged OAuth flow because
- // the token is invalid or doesn't exist.
- token, err := config.TokenCache.Token()
- if err != nil {
- // Start web server.
- // This is how this program receives the authorization code
- // when the browser redirects.
- codeCh, err := startWebServer()
- if err != nil {
- return nil, err
- }
-
- // Open url in browser
- url := config.AuthCodeURL("")
- err = openURL(url)
- if err != nil {
- fmt.Println("Visit the URL below to get a code.",
- " This program will pause until the site is visted.")
- } else {
- fmt.Println("Your browser has been opened to an authorization URL.",
- " This program will resume once authorization has been provided.\n")
- }
- fmt.Println(url)
-
- // Wait for the web server to get the code.
- code := <-codeCh
-
- // This code caches the authorization code on the local
- // filesystem, if necessary, as long as the TokenCache
- // attribute in the config is set.
- token, err = transport.Exchange(code)
- if err != nil {
- return nil, err
- }
- }
-
- transport.Token = token
- return transport.Client(), nil
-}
diff --git a/go/oauth2.go b/go/oauth2.go
new file mode 100644
index 00000000..a612999c
--- /dev/null
+++ b/go/oauth2.go
@@ -0,0 +1,223 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "os/exec"
+ "os/user"
+ "path/filepath"
+ "runtime"
+
+ "golang.org/x/net/context"
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/google"
+)
+
+// This variable indicates whether the script should launch a web server to
+// initiate the authorization flow or just display the URL in the terminal
+// window. Note the following instructions based on this setting:
+// * launchWebServer = true
+// 1. Use OAuth2 credentials for a web application
+// 2. Define authorized redirect URIs for the credential in the Google APIs
+// Console and set the RedirectURL property on the config object to one
+// of those redirect URIs. For example:
+// config.RedirectURL = "http://localhost:8090"
+// 3. In the startWebServer function below, update the URL in this line
+// to match the redirect URI you selected:
+// listener, err := net.Listen("tcp", "localhost:8090")
+// The redirect URI identifies the URI to which the user is sent after
+// completing the authorization flow. The listener then captures the
+// authorization code in the URL and passes it back to this script.
+// * launchWebServer = false
+// 1. Use OAuth2 credentials for an installed application. (When choosing
+// the application type for the OAuth2 client ID, select "Other".)
+// 2. Set the redirect URI to "urn:ietf:wg:oauth:2.0:oob", like this:
+// config.RedirectURL = "urn:ietf:wg:oauth:2.0:oob"
+// 3. When running the script, complete the auth flow. Then copy the
+// authorization code from the browser and enter it on the command line.
+const launchWebServer = false
+
+const missingClientSecretsMessage = `
+Please configure OAuth 2.0
+To make this sample run, you need to populate the client_secrets.json file
+found at:
+ %v
+with information from the {{ Google Cloud Console }}
+{{ https://cloud.google.com/console }}
+For more information about the client_secrets.json file format, please visit:
+https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
+`
+
+// getClient uses a Context and Config to retrieve a Token
+// then generate a Client. It returns the generated Client.
+func getClient(scope string) *http.Client {
+ ctx := context.Background()
+
+ b, err := ioutil.ReadFile("client_secret.json")
+ if err != nil {
+ log.Fatalf("Unable to read client secret file: %v", err)
+ }
+
+ // If modifying the scope, delete your previously saved credentials
+ // at ~/.credentials/youtube-go.json
+ config, err := google.ConfigFromJSON(b, scope)
+ if err != nil {
+ log.Fatalf("Unable to parse client secret file to config: %v", err)
+ }
+
+ // Use a redirect URI like this for a web app. The redirect URI must be a
+ // valid one for your OAuth2 credentials.
+ config.RedirectURL = "http://localhost:8090"
+ // Use the following redirect URI if launchWebServer=false in oauth2.go
+ // config.RedirectURL = "urn:ietf:wg:oauth:2.0:oob"
+
+ cacheFile, err := tokenCacheFile()
+ if err != nil {
+ log.Fatalf("Unable to get path to cached credential file. %v", err)
+ }
+ tok, err := tokenFromFile(cacheFile)
+ if err != nil {
+ authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
+ if launchWebServer {
+ fmt.Println("Trying to get token from web")
+ tok, err = getTokenFromWeb(config, authURL)
+ } else {
+ fmt.Println("Trying to get token from prompt")
+ tok, err = getTokenFromPrompt(config, authURL)
+ }
+ if err == nil {
+ saveToken(cacheFile, tok)
+ }
+ }
+ return config.Client(ctx, tok)
+}
+
+// startWebServer starts a web server that listens on http://localhost:8080.
+// The webserver waits for an oauth code in the three-legged auth flow.
+func startWebServer() (codeCh chan string, err error) {
+ listener, err := net.Listen("tcp", "localhost:8090")
+ if err != nil {
+ return nil, err
+ }
+ codeCh = make(chan string)
+
+ go http.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ code := r.FormValue("code")
+ codeCh <- code // send code to OAuth flow
+ listener.Close()
+ w.Header().Set("Content-Type", "text/plain")
+ fmt.Fprintf(w, "Received code: %v\r\nYou can now safely close this browser window.", code)
+ }))
+
+ return codeCh, nil
+}
+
+// openURL opens a browser window to the specified location.
+// This code originally appeared at:
+// http://stackoverflow.com/questions/10377243/how-can-i-launch-a-process-that-is-not-a-file-in-go
+func openURL(url string) error {
+ var err error
+ switch runtime.GOOS {
+ case "linux":
+ err = exec.Command("xdg-open", url).Start()
+ case "windows":
+ err = exec.Command("rundll32", "url.dll,FileProtocolHandler", "http://localhost:4001/").Start()
+ case "darwin":
+ err = exec.Command("open", url).Start()
+ default:
+ err = fmt.Errorf("Cannot open URL %s on this platform", url)
+ }
+ return err
+}
+
+// Exchange the authorization code for an access token
+func exchangeToken(config *oauth2.Config, code string) (*oauth2.Token, error) {
+ tok, err := config.Exchange(oauth2.NoContext, code)
+ if err != nil {
+ log.Fatalf("Unable to retrieve token %v", err)
+ }
+ return tok, nil
+}
+
+// getTokenFromPrompt uses Config to request a Token and prompts the user
+// to enter the token on the command line. It returns the retrieved Token.
+func getTokenFromPrompt(config *oauth2.Config, authURL string) (*oauth2.Token, error) {
+ var code string
+ fmt.Printf("Go to the following link in your browser. After completing " +
+ "the authorization flow, enter the authorization code on the command " +
+ "line: \n%v\n", authURL)
+
+ if _, err := fmt.Scan(&code); err != nil {
+ log.Fatalf("Unable to read authorization code %v", err)
+ }
+ fmt.Println(authURL)
+ return exchangeToken(config, code)
+}
+
+// getTokenFromWeb uses Config to request a Token.
+// It returns the retrieved Token.
+func getTokenFromWeb(config *oauth2.Config, authURL string) (*oauth2.Token, error) {
+ codeCh, err := startWebServer()
+ if err != nil {
+ fmt.Printf("Unable to start a web server.")
+ return nil, err
+ }
+
+ err = openURL(authURL)
+ if err != nil {
+ log.Fatalf("Unable to open authorization URL in web server: %v", err)
+ } else {
+ fmt.Println("Your browser has been opened to an authorization URL.",
+ " This program will resume once authorization has been provided.\n")
+ fmt.Println(authURL)
+ }
+
+ // Wait for the web server to get the code.
+ code := <-codeCh
+ return exchangeToken(config, code)
+}
+
+// tokenCacheFile generates credential file path/filename.
+// It returns the generated credential path/filename.
+func tokenCacheFile() (string, error) {
+ usr, err := user.Current()
+ if err != nil {
+ return "", err
+ }
+ tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials")
+ os.MkdirAll(tokenCacheDir, 0700)
+ return filepath.Join(tokenCacheDir,
+ url.QueryEscape("youtube-go.json")), err
+}
+
+// tokenFromFile retrieves a Token from a given file path.
+// It returns the retrieved Token and any read error encountered.
+func tokenFromFile(file string) (*oauth2.Token, error) {
+ f, err := os.Open(file)
+ if err != nil {
+ return nil, err
+ }
+ t := &oauth2.Token{}
+ err = json.NewDecoder(f).Decode(t)
+ defer f.Close()
+ return t, err
+}
+
+// saveToken uses a file path to create a file and store the
+// token in it.
+func saveToken(file string, token *oauth2.Token) {
+ fmt.Println("trying to save token")
+ fmt.Printf("Saving credential file to: %s\n", file)
+ f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
+ if err != nil {
+ log.Fatalf("Unable to cache oauth token: %v", err)
+ }
+ defer f.Close()
+ json.NewEncoder(f).Encode(token)
+}
diff --git a/go/playlists.go b/go/playlists.go
new file mode 100644
index 00000000..2769a582
--- /dev/null
+++ b/go/playlists.go
@@ -0,0 +1,72 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+
+ "google.golang.org/api/youtube/v3"
+)
+
+var (
+ method = flag.String("method", "list", "The API method to execute. (List is the only method that this sample currently supports.")
+
+ channelId = flag.String("channelId", "", "Retrieve playlists for this channel. Value is a YouTube channel ID.")
+ hl = flag.String("hl", "", "Retrieve localized resource metadata for the specified application language.")
+ maxResults = flag.Int64("maxResults", 5, "The maximum number of playlist resources to include in the API response.")
+ mine = flag.Bool("mine", false, "List playlists for authenticated user's channel. Default: false.")
+ onBehalfOfContentOwner = flag.String("onBehalfOfContentOwner", "", "Indicates that the request's auth credentials identify a user authorized to act on behalf of the specified content owner.")
+ pageToken = flag.String("pageToken", "", "Token that identifies a specific page in the result set that should be returned.")
+ part = flag.String("part", "snippet", "Comma-separated list of playlist resource parts that API response will include.")
+ playlistId = flag.String("playlistId", "", "Retrieve information about this playlist.")
+)
+
+func playlistsList(service *youtube.Service, part string, channelId string, hl string, maxResults int64, mine bool, onBehalfOfContentOwner string, pageToken string, playlistId string) *youtube.PlaylistListResponse {
+ call := service.Playlists.List(part)
+ if channelId != "" {
+ call = call.ChannelId(channelId)
+ }
+ if hl != "" {
+ call = call.Hl(hl)
+ }
+ call = call.MaxResults(maxResults)
+ if mine != false {
+ call = call.Mine(true)
+ }
+ if onBehalfOfContentOwner != "" {
+ call = call.OnBehalfOfContentOwner(onBehalfOfContentOwner)
+ }
+ if pageToken != "" {
+ call = call.PageToken(pageToken)
+ }
+ if playlistId != "" {
+ call = call.Id(playlistId)
+ }
+ response, err := call.Do()
+ handleError(err, "")
+ return response
+}
+
+func main() {
+ flag.Parse()
+
+ if *channelId == "" && *mine == false && *playlistId == "" {
+ log.Fatalf("You must either set a value for the channelId or playlistId flag or set the mine flag to 'true'.")
+ }
+ client := getClient(youtube.YoutubeReadonlyScope)
+
+ service, err := youtube.New(client)
+ if err != nil {
+ log.Fatalf("Error creating YouTube client: %v", err)
+ }
+
+ response := playlistsList(service, "snippet,contentDetails", *channelId, *hl, *maxResults, *mine, *onBehalfOfContentOwner, *pageToken, *playlistId)
+
+ for _, playlist := range response.Items {
+ playlistId := playlist.Id
+ playlistTitle := playlist.Snippet.Title
+
+ // Print the playlist ID and title for the playlist resource.
+ fmt.Println(playlistId, ": ", playlistTitle)
+ }
+}
diff --git a/go/post_bulletin.go b/go/post_bulletin.go
deleted file mode 100644
index e76d06c7..00000000
--- a/go/post_bulletin.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
- "log"
-
- "code.google.com/p/google-api-go-client/youtube/v3"
-)
-
-var (
- message = flag.String("message", "", "Text message to post")
- videoID = flag.String("videoid", "", "ID of video to post")
- playlistID = flag.String("playlistid", "", "ID of playlist to post")
-)
-
-func main() {
- flag.Parse()
-
- // A bulletin must contain a message and may also contain a video or a
- // playlist. You can post a message with or without an accompanying video
- // or playlist, but you can't post a video and playlist at the same time.
- if *message == "" {
- log.Fatalf("Please provide a message.")
- }
-
- if *videoID != "" && *playlistID != "" {
- log.Fatalf("You cannot post a video and a playlist at the same time.")
- }
-
- client, err := buildOAuthHTTPClient(youtube.YoutubeScope)
- if err != nil {
- log.Fatalf("Error building OAuth client: %v", err)
- }
-
- service, err := youtube.New(client)
- if err != nil {
- log.Fatalf("Error creating YouTube client: %v", err)
- }
-
- // Start making YouTube API calls.
- parts := "snippet"
- bulletin := &youtube.Activity{
- Snippet: &youtube.ActivitySnippet{
- Description: *message,
- },
- }
-
- if *videoID != "" || *playlistID != "" {
- parts = "snippet,contentDetails"
-
- // The resource ID element value differs depending on
- // whether a playlist or a video is being posted.
- var resourceId *youtube.ResourceId
- switch {
- case *videoID != "":
- resourceId = &youtube.ResourceId{
- Kind: "youtube#video",
- VideoId: *videoID,
- }
- case *playlistID != "":
- resourceId = &youtube.ResourceId{
- Kind: "youtube#playlist",
- PlaylistId: *playlistID,
- }
- }
-
- bulletin.ContentDetails = &youtube.ActivityContentDetails{
- Bulletin: &youtube.ActivityContentDetailsBulletin{
- ResourceId: resourceId,
- },
- }
- }
-
- call := service.Activities.Insert(parts, bulletin)
- _, err = call.Do()
- if err != nil {
- log.Fatalf("Error making API call to post bulletin: %v", err.Error())
- }
-
- fmt.Println("The bulletin was posted to your channel.")
-}
diff --git a/go/quickstart.go b/go/quickstart.go
new file mode 100644
index 00000000..dc5d83d3
--- /dev/null
+++ b/go/quickstart.go
@@ -0,0 +1,140 @@
+// Sample Go code for user authorization
+
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "os"
+ "os/user"
+ "path/filepath"
+
+ "golang.org/x/net/context"
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/google"
+ "google.golang.org/api/youtube/v3"
+)
+
+const missingClientSecretsMessage = `
+Please configure OAuth 2.0
+`
+
+// getClient uses a Context and Config to retrieve a Token
+// then generate a Client. It returns the generated Client.
+func getClient(ctx context.Context, config *oauth2.Config) *http.Client {
+ cacheFile, err := tokenCacheFile()
+ if err != nil {
+ log.Fatalf("Unable to get path to cached credential file. %v", err)
+ }
+ tok, err := tokenFromFile(cacheFile)
+ if err != nil {
+ tok = getTokenFromWeb(config)
+ saveToken(cacheFile, tok)
+ }
+ return config.Client(ctx, tok)
+}
+
+// getTokenFromWeb uses Config to request a Token.
+// It returns the retrieved Token.
+func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
+ authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
+ fmt.Printf("Go to the following link in your browser then type the "+
+ "authorization code: \n%v\n", authURL)
+
+ var code string
+ if _, err := fmt.Scan(&code); err != nil {
+ log.Fatalf("Unable to read authorization code %v", err)
+ }
+
+ tok, err := config.Exchange(oauth2.NoContext, code)
+ if err != nil {
+ log.Fatalf("Unable to retrieve token from web %v", err)
+ }
+ return tok
+}
+
+// tokenCacheFile generates credential file path/filename.
+// It returns the generated credential path/filename.
+func tokenCacheFile() (string, error) {
+ usr, err := user.Current()
+ if err != nil {
+ return "", err
+ }
+ tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials")
+ os.MkdirAll(tokenCacheDir, 0700)
+ return filepath.Join(tokenCacheDir,
+ url.QueryEscape("youtube-go-quickstart.json")), err
+}
+
+// tokenFromFile retrieves a Token from a given file path.
+// It returns the retrieved Token and any read error encountered.
+func tokenFromFile(file string) (*oauth2.Token, error) {
+ f, err := os.Open(file)
+ if err != nil {
+ return nil, err
+ }
+ t := &oauth2.Token{}
+ err = json.NewDecoder(f).Decode(t)
+ defer f.Close()
+ return t, err
+}
+
+// saveToken uses a file path to create a file and store the
+// token in it.
+func saveToken(file string, token *oauth2.Token) {
+ fmt.Printf("Saving credential file to: %s\n", file)
+ f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
+ if err != nil {
+ log.Fatalf("Unable to cache oauth token: %v", err)
+ }
+ defer f.Close()
+ json.NewEncoder(f).Encode(token)
+}
+
+func handleError(err error, message string) {
+ if message == "" {
+ message = "Error making API call"
+ }
+ if err != nil {
+ log.Fatalf(message + ": %v", err.Error())
+ }
+}
+
+func channelsListByUsername(service *youtube.Service, part string, forUsername string) {
+ call := service.Channels.List(part)
+ call = call.ForUsername(forUsername)
+ response, err := call.Do()
+ handleError(err, "")
+ fmt.Println(fmt.Sprintf("This channel's ID is %s. Its title is '%s', " +
+ "and it has %d views.",
+ response.Items[0].Id,
+ response.Items[0].Snippet.Title,
+ response.Items[0].Statistics.ViewCount))
+}
+
+
+func main() {
+ ctx := context.Background()
+
+ b, err := ioutil.ReadFile("client_secret.json")
+ if err != nil {
+ log.Fatalf("Unable to read client secret file: %v", err)
+ }
+
+ // If modifying these scopes, delete your previously saved credentials
+ // at ~/.credentials/youtube-go-quickstart.json
+ config, err := google.ConfigFromJSON(b, youtube.YoutubeReadonlyScope)
+ if err != nil {
+ log.Fatalf("Unable to parse client secret file to config: %v", err)
+ }
+ client := getClient(ctx, config)
+ service, err := youtube.New(client)
+
+ handleError(err, "Error creating YouTube client")
+
+ channelsListByUsername(service, "snippet,contentDetails,statistics", "GoogleDevelopers")
+}
diff --git a/go/search_by_keyword.go b/go/search_by_keyword.go
index 38fa7fb6..3c8f0b64 100644
--- a/go/search_by_keyword.go
+++ b/go/search_by_keyword.go
@@ -6,8 +6,8 @@ import (
"log"
"net/http"
- "code.google.com/p/google-api-go-client/googleapi/transport"
- "code.google.com/p/google-api-go-client/youtube/v3"
+ "google.golang.org/api/googleapi/transport"
+ "google.golang.org/api/youtube/v3"
)
var (
@@ -34,9 +34,7 @@ func main() {
Q(*query).
MaxResults(*maxResults)
response, err := call.Do()
- if err != nil {
- log.Fatalf("Error making search API call: %v", err)
- }
+ handleError(err, "")
// Group video, channel, and playlist results in separate lists.
videos := make(map[string]string)
diff --git a/go/search_by_topic.go b/go/search_by_topic.go
deleted file mode 100644
index f5be7151..00000000
--- a/go/search_by_topic.go
+++ /dev/null
@@ -1,173 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "errors"
- "flag"
- "fmt"
- "io/ioutil"
- "log"
- "net/http"
- "net/url"
- "os"
-
- "code.google.com/p/google-api-go-client/googleapi/transport"
- "code.google.com/p/google-api-go-client/youtube/v3"
-)
-
-var (
- query = flag.String("query", "Google", "Freebase search term")
- maxResults = flag.Int64("max-results", 25, "Max YouTube results")
- resultType = flag.String("type", "channel", "YouTube result type: video, playlist, or channel")
-)
-
-const developerKey = "YOUR DEVELOPER KEY HERE"
-const freebaseSearchURL = "https://www.googleapis.com/freebase/v1/search?%s"
-
-// Notable is struct for unmarshalling JSON values from the API.
-type Notable struct {
- Name string
- ID string
-}
-
-// FreebaseTopic is struct for unmarshalling JSON values from the API.
-type FreebaseTopic struct {
- Mid string
- ID string
- Name string
- Notable Notable
- Lang string
- Score float64
-}
-
-// FreebaseResponse is struct for unmarshalling JSON values from the Freebase API.
-type FreebaseResponse struct {
- Status string
- Result []FreebaseTopic
-}
-
-func main() {
- flag.Parse()
-
- topicID, err := getTopicID(*query)
- if err != nil {
- log.Fatalf("Cannot fetch topic ID from Freebase: %v", err)
- }
-
- err = youtubeSearch(topicID)
- if err != nil {
- log.Fatalf("Cannot make YouTube API call: %v", err)
- }
-}
-
-// getTopicID queries Freebase with the given string. It then prompts the user
-// to select a topic, then returns the selected topic so that the topic can be
-// used to search YouTube for videos, channels or playlists.
-func getTopicID(topic string) (string, error) {
- urlParams := url.Values{
- "query": []string{topic},
- "key": []string{developerKey},
- }
-
- apiURL := fmt.Sprintf(freebaseSearchURL, urlParams.Encode())
-
- resp, err := http.Get(apiURL)
- if err != nil {
- return "", err
- } else if resp.StatusCode != http.StatusOK {
- errorMsg := fmt.Sprintf("Received HTTP status code %v using developer key: %v",
- resp.StatusCode, developerKey)
- return "", errors.New(errorMsg)
- }
-
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", err
- }
-
- var data FreebaseResponse
- err = json.Unmarshal(body, &data)
- if err != nil {
- return "", nil
- }
-
- if len(data.Result) == 0 {
- return "", errors.New("No matching terms were found in Freebase.")
- }
-
- // Print a list of topics for the user to select.
- fmt.Println("The following topics were found:")
- for index, topic := range data.Result {
- if topic.Notable.Name == "" {
- topic.Notable.Name = "Unknown"
- }
- fmt.Printf(" %2d. %s (%s)\r\n", index+1, topic.Name, topic.Notable.Name)
- }
-
- prompt := fmt.Sprintf("Enter a topic number to find related YouTube %s [1-%v]: ",
- *resultType, len(data.Result))
- selection, err := readInt(prompt, 1, len(data.Result))
- if err != nil {
- return "", nil
- }
- choice := data.Result[selection-1]
- return choice.Mid, nil
-}
-
-// readInt reads an integer from standard input and verifies that the value
-// is between the allowed min and max values (inclusive).
-func readInt(prompt string, min int, max int) (int, error) {
- // Loop until we have a valid input.
- for {
- fmt.Print(prompt)
- var i int
- _, err := fmt.Fscan(os.Stdin, &i)
- if err != nil {
- return 0, err
- }
- if i < min || i > max {
- fmt.Println("Invalid input.")
- continue
- }
- return i, nil
- }
-}
-
-// youtubeSearch searches YouTube for the topic given in the query flag and
-// prints the results. This function takes a mid parameter, which specifies
-// a value retrieved using the Freebase API.
-func youtubeSearch(mid string) error {
- client := &http.Client{
- Transport: &transport.APIKey{Key: developerKey},
- }
-
- service, err := youtube.New(client)
- if err != nil {
- return err
- }
-
- // Make the API call to YouTube.
- call := service.Search.List("id,snippet").
- TopicId(mid).
- Type(*resultType).
- MaxResults(*maxResults)
- response, err := call.Do()
- if err != nil {
- return err
- }
-
- // Iterate through each item and output it.
- for _, item := range response.Items {
- itemID := ""
- switch item.Id.Kind {
- case "youtube#video":
- itemID = item.Id.VideoId
- case "youtube#channel":
- itemID = item.Id.ChannelId
- case "youtube#playlist":
- itemID = item.Id.PlaylistId
- }
- fmt.Printf("%v (%v)\r\n", item.Snippet.Title, itemID)
- }
- return nil
-}
diff --git a/go/upload_video.go b/go/upload_video.go
index 04d3ed5f..24972c63 100644
--- a/go/upload_video.go
+++ b/go/upload_video.go
@@ -7,7 +7,7 @@ import (
"os"
"strings"
- "code.google.com/p/google-api-go-client/youtube/v3"
+ "google.golang.org/api/youtube/v3"
)
var (
@@ -26,10 +26,7 @@ func main() {
log.Fatalf("You must provide a filename of a video file to upload")
}
- client, err := buildOAuthHTTPClient(youtube.YoutubeUploadScope)
- if err != nil {
- log.Fatalf("Error building OAuth client: %v", err)
- }
+ client := getClient(youtube.YoutubeUploadScope)
service, err := youtube.New(client)
if err != nil {
@@ -59,8 +56,6 @@ func main() {
}
response, err := call.Media(file).Do()
- if err != nil {
- log.Fatalf("Error making YouTube API call: %v", err)
- }
+ handleError(err, "")
fmt.Printf("Upload successful! Video ID: %v\n", response.Id)
}
diff --git a/java/README b/java/README
deleted file mode 100644
index b71843bc..00000000
--- a/java/README
+++ /dev/null
@@ -1,21 +0,0 @@
-Prerequisites for this code sample:
-- Java 1.6
-- Apache Maven (http://maven.apache.org)
-
-Before running the sample, client_secrets.json must be populated with a
-client ID and client secret. You can create an ID/secret pair at:
-
- https://code.google.com/apis/console
-
-To build this code sample from the command line, type:
-
- mvn compile
-
-To run the code sample from the command line, enter the following:
-
- mvn exec:java -Dexec.mainClass="FULL_CLASS_NAME"
-
-For more instructions about how to set up Maven and/or your IDE to run
-YouTube API samples, see this video:
-
- http://youtu.be/pb_t5_ShQOM
diff --git a/java/README.md b/java/README.md
new file mode 100644
index 00000000..d9baaf89
--- /dev/null
+++ b/java/README.md
@@ -0,0 +1,267 @@
+Prerequisites for this code sample:
+- Java 1.6
+- Apache Maven (http://maven.apache.org)
+
+Before running the sample, client_secrets.json must be populated with a
+client ID and client secret. You can create an ID/secret pair at:
+
+ https://code.google.com/apis/console
+
+To build this code sample from the command line, type:
+
+ mvn compile
+
+To run a code sample from the command line, enter the following:
+
+ mvn exec:java -Dexec.mainClass="FULL_CLASS_NAME"
+
+For samples that require arguments, also specify -Dexec.args, e.g.:
+
+ mvn exec:java -Dexec.mainClass="FULL_CLASS_NAME" -Dexec.args="arg1 arg2"
+
+For more instructions about how to set up Maven and/or your IDE to run
+YouTube API samples, see this video:
+
+ http://youtu.be/pb_t5_ShQOM
+
+## Samples in this directory:
+
+### [Authorize a request](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/Auth.java)
+
+Description: This sample demonstrates how to use OAuth 2.0 to authorize an application to access resources on a user's behalf.
+
+### [Add a channel subscription](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/AddSubscription.java)
+
+Method: youtube.subscriptions.insertsubscriptions.insert method to add a subscription to a specified
+channel.
+
+### [Add a featured video](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/InvideoProgramming.java)
+
+Method: youtube.channels.updatechannels.update method to set invideoPromotion
+properties for the channel.
+
+### [Create a playlist](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistUpdates.java)
+
+Method: youtube.playlists.insertplaylists.insert method to create a private playlist owned by the
+channel authorizing the request.
+
+### [Create and manage comments](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentHandling.java)
+
+Method: youtube.commentThreads.list, youtube.comments.insert, youtube.comments.list, youtube.comments.update,
+youtube.comments.setModerationStatus, youtube.comments.markAsSpam, youtube.comments.deletecommentThreads.list method with the videoId parameter set to retrieve comments
+for a video.comments.insert method with the parentId parameter set to reply to an existing
+comment.comments.list method with the parentId parameter to retrieve the comments in the
+thread.comments.update method with comment in the request body to update a comment.comments.setModerationStatus method to set the moderation status of the comment, the
+comments.markAsSpam method to mark the comment as spam, and the comments.delete method to
+delete the comment, using the id parameter to identify the comment.commentThreads.insert method once with the channelId parameter to create a
+channel comment and once with the videoId parameter to create a video comment.commentThreads.list method once with the channelId parameter to retrieve
+channel comments and once with the videoId parameter to retrieve video comments.commentThreads.update method once to update a video comment and then again to update a
+channel comment. In each case, the request body contains the comment resource being updated.captions.insert method with the isDraft parameter set to true
+to upload a caption track in draft status.captions.list method with the videoId parameter to retrieve video caption
+tracks.captions.update method with the caption in the request body to update a caption track.captions.download method to download the caption track.captions.delete method to delete the caption track, using the id parameter to
+identify the caption track.activities.insert method to post a bulletin to the channel
+associated with the request.
+
+### [Retrieve my uploads](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/MyUploads.java)
+
+Method: youtube.playlistItems.listplaylistItems.list method to retrieve a list of videos uploaded
+to the channel associated with the request. The code also calls the channels.list method with the
+mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded
+videos.
+
+### [Search by keyword](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Search.java)
+
+Method: youtube.search.listsearch.list method to retrieve search results associated with
+a particular keyword.
+
+### [Search by location](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/GeolocationSearch.java)
+
+Method: youtube.search.list, youtube.videos.listsearch.list method with the type, q, location, and
+locationRadius parameters to retrieve search results matching the provided keyword within the radius centered
+at a particular location. Using the video IDs from the search result, the sample calls the API's videos.list
+method to retrieve location details of each video.
+
+### [Set and retrieve localized channel metadata](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelLocalizations.java)
+
+Method: youtube.channels.update, youtube.channels.listchannels.update method to update the default language of a channel's metadata and to add a
+localized version of this metadata in a selected language. Note that to set the default language for a channel resource,
+you actually need to update the brandingSettings.channel.defaultLanguage property.channels.list method with the hl parameter set to a specific language to
+retrieve localized metadata in that language.channels.list method and includes localizations in the part
+parameter value to retrieve all of the localized metadata for that channel.channelSections.update method to update the default language of a channel section's
+metadata and to add a localized version of this metadata in a selected language.channelSections.list method with the hl parameter set to a specific language
+to retrieve localized metadata in that language.channelSections.list method and includes localizations in the
+part parameter value to retrieve all of the localized metadata for that channel section.playlists.update method to update the default language of a playlist's metadata and to add
+a localized version of this metadata in a selected language.playlists.list method with the hl parameter set to a specific language to
+retrieve localized metadata in that language.playlists.list method and includes localizations in the part
+parameter value to retrieve all of the localized metadata for that playlist.videos.update method to update the default language of a video's metadata and to add
+a localized version of this metadata in a selected language.videos.list method with the hl parameter set to a specific language to
+retrieve localized metadata in that language.videos.list method and includes localizations in the part
+parameter value to retrieve all of the localized metadata for that video.videos.update method to update a video owned by the channel
+authorizing the request.
+
+### [Upload a custom video thumbnail image](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadThumbnail.java)
+
+Method: youtube.thumbnails.setthumbnails.set method to upload an image and set it as the
+thumbnail image for a video. The request must be authorized by the channel that owns the video.
+
+### [Upload a video](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadVideo.java)
+
+Method: youtube.videos.insertvideos.insert method to upload a video to the channel associated
+with the request.
+
+### [Retrieve top 10 videos by viewcount](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/analytics/YouTubeAnalyticsReports.java)
+
+Method: youtubeAnalytics.reports.queryreports.query method to retrieve YouTube Analytics data.
+By default, the report retrieves the top 10 videos based on viewcounts, and it returns several metrics for those
+videos, sorting the results in reverse order by viewcount. By setting command line parameters, you can use the
+same code to retrieve other reports as well.
+
+### [Create a reporting job](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/CreateReportingJob.java)
+
+Method: youtubeReporting.reportTypes.list, youtubeReporting.jobs.createreportTypes.list method
+to retrieve a list of available report types. It then calls the jobs.create method to create a new reporting
+job.
+
+### [Retrieve reports](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/RetrieveReports.java)
+
+Method: youtubeReporting.jobs.list, youtubeReporting.reports.listjobs.list method to retrieve reporting jobs. It then calls the reports.list method with the
+jobId parameter set to a specific job ID to retrieve reports created by that job. Finally, the sample
+prints out the download URL for each report.
+
+### [Create a broadcast and stream](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/CreateBroadcast.java)
+
+Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insertliveBroadcasts.insert and liveStreams.insert
+methods to create a broadcast and a stream. Then, it calls the liveBroadcasts.bind method to bind
+the stream to the broadcast.
+
+### [Retrieve a channel's broadcasts](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java)
+
+Method: youtube.liveBroadcasts.listliveBroadcasts.list method to retrieve a list of broadcasts for
+the channel associated with the request. By default, the request retrieves all broadcasts for the channel, but you can
+also specify a value for the --broadcast-status option to only retrieve broadcasts with a particular status.
+
+### [Retrieve a channel's live video streams](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListStreams.java)
+
+Method: youtube.liveStreams.listliveStreams.list method to retrieve a list of video stream settings
+that a channel can use to broadcast live events on YouTube.
+
+
+### [Get a live chat id](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java)
+
+Methods: youtube.videos.list, youtube.liveBroadcasts.listvideoId parameter
+or the live broadcast for the authorized user's channel. The liveChatId is required for other samples
+that interact with live chat.
+
+### [Insert a live chat message](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/InsertLiveChatMessage.java)
+
+Method: youtube.liveChatMessages.insertauth.js script demonstrates how to use the Google APIs Client Library for JavaScript
+to provide API access and authorize user requests. All of the subsequent samples on this page use this script to
+authorize their requests.key query parameter to specify an API key rather than using OAuth 2.0.auth.js file. You can obtain your own
+client ID by registering your application in the
+Google Developers Console.
+
+### [Do resumable uploads with CORS](/javascript/cors_upload.js)
+
+Method: youtube.videos.insert
+Description: This code sample demonstrates how to execute a resumable upload using XHR/CORS.
+
+### [Create a playlist](/javascript/playlist_updates.js)
+
+Method: youtube.playlists.insertauth.js file to run this code.auth.js and playlist_updates.js JavaScript files, to display a simple form for adding videos to the playlist.
+
+### [Retrieve my uploads](/javascript/my_uploads.js)
+
+Method: youtube.playlistItems.listchannels.list method. This API call also sets the mine parameter to true to retrieve channel information for the authorizing user.playlistItems.list method to retrieve the videos in that list.auth.js and my_uploads.js JavaScript files, and a CSS file to display the list of uploaded videos.
+
+### [Search by keyword](/javascript/search.js)
+
+Method: youtube.search.listsearch.list method to retrieve search results associated
+with a particular keyword. The HTML page uses JQuery, along with the auth.js and search.js JavaScript files, to show a simple search form and display the list of search results.
+
+### [Upload a video](/javascript/upload_video.js)
+
+Method: youtube.videos.insertcors_upload.js and upload_video.js JavaScript files, and the
+upload_video.css file to upload a video file to YouTube.data-clientid attribute in the code for the Sign-In Button
+with your project's client ID. The only valid JavaScript origin for the client ID in the sample code is
+http://localhost. This means that you could test the sample locally, but it would not work in your
+production application.
+
+### [Calling the Analytics API](/javascript/analytics_codelab.js)
+
+Method: youtubeAnalytics.reports.querywww.google.com/jsapi),
+which lets you easily import one or more Google APIs. This example uses the API loader to load the Google Visualization API,
+which is used to chart the retrieved Analytics data. Finally, the
+Google APIs Client Library for JavaScript
+helps you to implement OAuth 2.0 authentication and to call the YouTube Analytics API.
diff --git a/javascript/nodejs-quickstart.js b/javascript/nodejs-quickstart.js
new file mode 100644
index 00000000..68d0591f
--- /dev/null
+++ b/javascript/nodejs-quickstart.js
@@ -0,0 +1,125 @@
+var fs = require('fs');
+var readline = require('readline');
+var {google} = require('googleapis');
+var OAuth2 = google.auth.OAuth2;
+
+// If modifying these scopes, delete your previously saved credentials
+// at ~/.credentials/youtube-nodejs-quickstart.json
+var SCOPES = ['https://www.googleapis.com/auth/youtube.readonly'];
+var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
+ process.env.USERPROFILE) + '/.credentials/';
+var TOKEN_PATH = TOKEN_DIR + 'youtube-nodejs-quickstart.json';
+
+// Load client secrets from a local file.
+fs.readFile('client_secret.json', function processClientSecrets(err, content) {
+ if (err) {
+ console.log('Error loading client secret file: ' + err);
+ return;
+ }
+ // Authorize a client with the loaded credentials, then call the YouTube API.
+ authorize(JSON.parse(content), getChannel);
+});
+
+/**
+ * Create an OAuth2 client with the given credentials, and then execute the
+ * given callback function.
+ *
+ * @param {Object} credentials The authorization client credentials.
+ * @param {function} callback The callback to call with the authorized client.
+ */
+function authorize(credentials, callback) {
+ var clientSecret = credentials.installed.client_secret;
+ var clientId = credentials.installed.client_id;
+ var redirectUrl = credentials.installed.redirect_uris[0];
+ var oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl);
+
+ // Check if we have previously stored a token.
+ fs.readFile(TOKEN_PATH, function(err, token) {
+ if (err) {
+ getNewToken(oauth2Client, callback);
+ } else {
+ oauth2Client.credentials = JSON.parse(token);
+ callback(oauth2Client);
+ }
+ });
+}
+
+/**
+ * Get and store new token after prompting for user authorization, and then
+ * execute the given callback with the authorized OAuth2 client.
+ *
+ * @param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
+ * @param {getEventsCallback} callback The callback to call with the authorized
+ * client.
+ */
+function getNewToken(oauth2Client, callback) {
+ var authUrl = oauth2Client.generateAuthUrl({
+ access_type: 'offline',
+ scope: SCOPES
+ });
+ console.log('Authorize this app by visiting this url: ', authUrl);
+ var rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout
+ });
+ rl.question('Enter the code from that page here: ', function(code) {
+ rl.close();
+ oauth2Client.getToken(code, function(err, token) {
+ if (err) {
+ console.log('Error while trying to retrieve access token', err);
+ return;
+ }
+ oauth2Client.credentials = token;
+ storeToken(token);
+ callback(oauth2Client);
+ });
+ });
+}
+
+/**
+ * Store token to disk be used in later program executions.
+ *
+ * @param {Object} token The token to store to disk.
+ */
+function storeToken(token) {
+ try {
+ fs.mkdirSync(TOKEN_DIR);
+ } catch (err) {
+ if (err.code != 'EEXIST') {
+ throw err;
+ }
+ }
+ fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
+ if (err) throw err;
+ console.log('Token stored to ' + TOKEN_PATH);
+ });
+}
+
+/**
+ * Lists the names and IDs of up to 10 files.
+ *
+ * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
+ */
+function getChannel(auth) {
+ var service = google.youtube('v3');
+ service.channels.list({
+ auth: auth,
+ part: 'snippet,contentDetails,statistics',
+ forUsername: 'GoogleDevelopers'
+ }, function(err, response) {
+ if (err) {
+ console.log('The API returned an error: ' + err);
+ return;
+ }
+ var channels = response.data.items;
+ if (channels.length == 0) {
+ console.log('No channel found.');
+ } else {
+ console.log('This channel\'s ID is %s. Its title is \'%s\', and ' +
+ 'it has %s views.',
+ channels[0].id,
+ channels[0].snippet.title,
+ channels[0].statistics.viewCount);
+ }
+ });
+}
diff --git a/javascript/quickstart.html b/javascript/quickstart.html
new file mode 100644
index 00000000..a8f264d5
--- /dev/null
+++ b/javascript/quickstart.html
@@ -0,0 +1,120 @@
+
+
+
+ YouTube Data API Quickstart
+ + + + + + + + + + + + diff --git a/javascript/yt_analytics_v2.html b/javascript/yt_analytics_v2.html new file mode 100644 index 00000000..7ab4cf41 --- /dev/null +++ b/javascript/yt_analytics_v2.html @@ -0,0 +1,35 @@ + + + + diff --git a/php/README.md b/php/README.md new file mode 100644 index 00000000..8a4b63be --- /dev/null +++ b/php/README.md @@ -0,0 +1,227 @@ +## Samples in this directory: + +### [Add a channel section](/php/add_channel_section.php) + +Method: youtube.channelSections.insertchannelSections.insert method to create channel sections.
+The code accepts a number of command line arguments that let you specify the section's type, display style, title, position,
+and content.brandingSettings.channel.showBrowseView
+property so that the channel displays content in a browse view (rather than a feed view). A channel's sections are only
+visible if the channel displays content in a browse view.subscriptions.insert method to add a subscription to a specified
+channel.
+
+### [Create a playlist](/php/playlist_updates.php)
+
+Method: youtube.playlists.insertplaylists.insert method to create a private playlist owned by the
+channel authorizing the request.
+
+### [Create and manage comments](/php/comment_handling.php)
+
+Method: youtube.commentThreads.list, youtube.comments.insert, youtube.comments.list, youtube.comments.update,
+youtube.comments.setModerationStatus, youtube.comments.markAsSpam, youtube.comments.deletecommentThreads.list method with the videoId parameter set to retrieve comments
+for a video.comments.insert method with the parentId parameter set to reply to an existing
+comment.comments.list method with the parentId parameter to retrieve the comments in the
+thread.comments.update method with comment in the request body to update a comment.comments.setModerationStatus method to set the moderation status of the comment, the
+comments.markAsSpam method to mark the comment as spam, and the comments.delete method to
+delete the comment, using the id parameter to identify the comment.commentThreads.insert method once with the channelId parameter to create a
+channel comment and once with the videoId parameter to create a video comment.commentThreads.list method once with the channelId parameter to retrieve
+channel comments and once with the videoId parameter to retrieve video comments.commentThreads.update method once to update a video comment and then again to update a
+channel comment. In each case, the request body contains the comment resource being updated.captions.insert method with the isDraft parameter set to true
+to upload a caption track in draft status.captions.list method with the videoId parameter to retrieve video caption
+tracks.captions.update method with the caption in the request body to update a caption track.captions.download method to download the caption track.captions.delete method to delete the caption track, using the id parameter to
+identify the caption track.playlistItems.list method to retrieve a list of videos uploaded
+to the channel associated with the request. The code also calls the channels.list method with the
+mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded
+videos.
+
+### [Search by keyword](/php/search.php)
+
+Method: youtube.search.listsearch.list method to retrieve search results associated with
+a particular keyword.
+
+### [Search by location](/php/geolocation_search.php)
+
+Method: youtube.search.list, youtube.videos.listsearch.list method with the type, q,
+location and locationRadius parameters to retrieve search results matching the provided
+keyword within the radius centered at a particular location. Using the video IDs from the search result, the sample
+calls the API's videos.list method to retrieve location details of each video.
+
+### [Set and retrieve localized channel metadata](/php/channel_localizations.php)
+
+Method: youtube.channels.update, youtube.channels.listchannels.update method to update the default language of a channel's metadata and to add a
+localized version of this metadata in a selected language. Note that to set the default language for a channel resource,
+you actually need to update the brandingSettings.channel.defaultLanguage property.channels.list method with the hl parameter set to a specific language to
+retrieve localized metadata in that language.channels.list method and includes localizations in the part
+parameter value to retrieve all of the localized metadata for that channel.channelSections.update method to update the default language of a channel section's
+metadata and to add a localized version of this metadata in a selected language.channelSections.list method with the hl parameter set to a specific language
+to retrieve localized metadata in that language.channelSections.list method and includes localizations in the
+part parameter value to retrieve all of the localized metadata for that channel section.playlists.update method to update the default language of a playlist's metadata and to add
+a localized version of this metadata in a selected language.playlists.list method with the hl parameter set to a specific language to
+retrieve localized metadata in that language.playlists.list method and includes localizations in the part
+parameter value to retrieve all of the localized metadata for that playlist.videos.update method to update the default language of a video's metadata and to add
+a localized version of this metadata in a selected language.videos.list method with the hl parameter set to a specific language to
+retrieve localized metadata in that language.videos.list method and includes localizations in the part
+parameter value to retrieve all of the localized metadata for that video.channelSections.list method to get the list of current channel
+sections, shuffles them, and then calls channelSections.update to change the position of each.youtube.videos.list method with id parameter set to videoId
+to get the video object. Using this video object, the sample gets the list of tags and appends new tags at the
+end of this list. Finally, the code calls youtube.videos.update method with updated video object
+to persist these changes on YouTube.
+
+### [Upload a banner image and set as channel's banner](/php/upload_banner.php)
+
+Method: youtube.channelBanners.insert, youtube.channels.updatechannelBanners.insert method to upload an image. With the
+returned URL, the sample calls channels.update method to update the channel's banner to this image.
+
+### [Upload a custom video thumbnail image](/php/upload_thumbnail.php)
+
+Method: youtube.thumbnails.setyoutube.thumbnails.set method with videoId parameter set to a video
+ID to use a custom image as a thumbnail to the video. For the image upload, the program utilizes the
+Google_MediaFileUpload class with the resumable parameter set to
+true to upload the image piece-by-piece, allowing for subsequent retries to resume uploading from
+a point close to where the previous retry failed, a feature useful for programs that need to upload large files.
+
+### [Upload a video](/php/resumable_upload.php)
+
+Method: youtube.videos.insertvideos.insert method to add a video to user's
+channel. The code also utilizes Google_MediaFileUpload class with the resumable upload
+parameter set to true to be able to to upload the video in chunks.
+
+### [Create a broadcast and stream](/php/create_broadcast.php)
+
+Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insertliveBroadcasts.insert and liveStreams.insert
+methods to create a broadcast and a stream. Then, it calls the liveBroadcasts.bind method to bind
+the stream to the broadcast.
+
+### [Retrieve a channel's broadcasts](/php/list_broadcasts.php)
+
+Method: youtube.liveBroadcasts.listliveBroadcasts.list method to retrieve a list of broadcasts for
+the channel associated with the request. By default, the request retrieves all broadcasts for the channel, but you can
+also specify a value for the --broadcast-status option to only retrieve broadcasts with a particular status.
+
+### [Retrieve a channel's live video streams](/php/list_streams.php)
+
+Method: youtube.liveStreams.listliveStreams.list method to retrieve a list of video stream settings
+that a channel can use to broadcast live events on YouTube.
+
+### [Create a reporting job](/php/create_reporting_job.php)
+
+Method: youtubeReporting.reportTypes.list, youtubeReporting.jobs.createreportTypes.list method
+to retrieve a list of available report types. It then calls the jobs.create method to create a new reporting
+job.
+
+### [Retrieve reports](/php/retrieve_reports.php)
+
+Method: youtubeReporting.jobs.list, youtubeReporting.reports.listjobs.list method to retrieve reporting jobs. It then calls the reports.list method with the
+jobId parameter set to a specific job id to retrieve reports created by that job. Finally, the sample
+prints out the download URL for each report.
diff --git a/php/quickstart.php b/php/quickstart.php
new file mode 100644
index 00000000..0af550ff
--- /dev/null
+++ b/php/quickstart.php
@@ -0,0 +1,112 @@
+setAuthConfigFile('client_secret.json');
+ // Set to valid redirect URI for your project.
+ $client->setRedirectUri('http://localhost');
+
+ $client->addScope(Google_Service_YouTube::YOUTUBE_READONLY);
+ $client->setAccessType('offline');
+
+ // Load previously authorized credentials from a file.
+ $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
+ if (file_exists($credentialsPath)) {
+ $accessToken = file_get_contents($credentialsPath);
+ } else {
+ // Request authorization from the user.
+ $authUrl = $client->createAuthUrl();
+ printf("Open the following link in your browser:\n%s\n", $authUrl);
+ print 'Enter verification code: ';
+ $authCode = trim(fgets(STDIN));
+
+ // Exchange authorization code for an access token.
+ $accessToken = $client->authenticate($authCode);
+
+ // Store the credentials to disk.
+ if(!file_exists(dirname($credentialsPath))) {
+ mkdir(dirname($credentialsPath), 0700, true);
+ }
+ file_put_contents($credentialsPath, $accessToken);
+ printf("Credentials saved to %s\n", $credentialsPath);
+ }
+ $client->setAccessToken($accessToken);
+
+ // Refresh the token if it's expired.
+ if ($client->isAccessTokenExpired()) {
+ $client->refreshToken($client->getRefreshToken());
+ file_put_contents($credentialsPath, $client->getAccessToken());
+ }
+ return $client;
+}
+
+/**
+ * Expands the home directory alias '~' to the full path.
+ * @param string $path the path to expand.
+ * @return string the expanded path.
+ */
+function expandHomeDirectory($path) {
+ $homeDirectory = getenv('HOME');
+ if (empty($homeDirectory)) {
+ $homeDirectory = getenv("HOMEDRIVE") . getenv("HOMEPATH");
+ }
+ return str_replace('~', realpath($homeDirectory), $path);
+}
+
+// Define an object that will be used to make all API requests.
+$client = getClient();
+$service = new Google_Service_YouTube($client);
+
+if (isset($_GET['code'])) {
+ if (strval($_SESSION['state']) !== strval($_GET['state'])) {
+ die('The session state did not match.');
+ }
+
+ $client->authenticate($_GET['code']);
+ $_SESSION['token'] = $client->getAccessToken();
+ header('Location: ' . $redirect);
+}
+
+if (isset($_SESSION['token'])) {
+ $client->setAccessToken($_SESSION['token']);
+}
+
+if (!$client->getAccessToken()) {
+ print("no access token, whaawhaaa");
+ exit;
+}
+
+// Call channels.list to retrieve information
+
+function channelsListByUsername($service, $part, $params) {
+ $params = array_filter($params);
+ $response = $service->channels->listChannels(
+ $part,
+ $params
+ );
+
+ $description = sprintf(
+ 'This channel\'s ID is %s. Its title is %s, and it has %s views.',
+ $response['items'][0]['id'],
+ $response['items'][0]['snippet']['title'],
+ $response['items'][0]['statistics']['viewCount']);
+ print $description . "\n";
+}
+
+channelsListByUsername($service, 'snippet,contentDetails,statistics', array('forUsername' => 'GoogleDevelopers'));
+?>
diff --git a/php/retrieve_reports.php b/php/retrieve_reports.php
index f5b71fb2..3bd986f8 100644
--- a/php/retrieve_reports.php
+++ b/php/retrieve_reports.php
@@ -1,12 +1,15 @@
* For more information about using OAuth 2.0 to access Google APIs, please see:
* No jobs found.
'); - } else if ($_GET['reportUrl']){ - downloadReport($youtubeReporting, $_GET['reportUrl'], $htmlBody); - } else if ($_GET['jobId']){ - retrieveReports($youtubeReporting, $_GET['jobId'], $htmlBody); - } - } catch (Google_Service_Exception $e) { - $htmlBody .= sprintf('A service error occurred: %s
An client error occurred: %s
- You need to set \$OAUTH2_CLIENT_ID and
- \$OAUTH2_CLIENT_ID before proceeding.
-
-END;
-} else {
- // If the user hasn't authorized the app, initiate the OAuth flow
- $state = mt_rand();
- $client->setState($state);
- $_SESSION['state'] = $state;
-
- $authUrl = $client->createAuthUrl();
- $htmlBody = << You need to authorize access before proceeding.
-END;
+ return str_replace('~', realpath($homeDirectory), $path);
}
-
/**
* Returns a list of reporting jobs. (jobs.listJobs)
*
* @param Google_Service_YouTubereporting $youtubeReporting YouTube Reporting service object.
- * @param $htmlBody - html body.
+ * @param string $onBehalfOfContentOwner A content owner ID.
*/
-function listReportingJobs(Google_Service_YouTubeReporting $youtubeReporting, &$htmlBody) {
- // Call the YouTube Reporting API's jobs.list method to retrieve reporting jobs.
- $reportingJobs = $youtubeReporting->jobs->listJobs();
-
- $htmlBody .= " No reports found. Videos: The following topics were found:Reporting Jobs
";
+function listReportingJobs(Google_Service_YouTubeReporting $youtubeReporting,
+ $onBehalfOfContentOwner = '', $includeSystemManaged = False) {
+ $reportingJobs = $youtubeReporting->jobs->listJobs(
+ array('onBehalfOfContentOwner' => $onBehalfOfContentOwner,
+ 'includeSystemManaged' => $includeSystemManaged));
+ print ('REPORTING JOBS' . PHP_EOL . '**************' . PHP_EOL);
foreach ($reportingJobs as $job) {
- $htmlBody .= sprintf('
';
-
- return $reportingJobs;
+ print(PHP_EOL);
}
-
/**
* Lists reports created by a specific job. (reports.listJobsReports)
*
* @param Google_Service_YouTubereporting $youtubeReporting YouTube Reporting service object.
* @param string $jobId The ID of the job.
- * @param $htmlBody - html body.
+ * @param string $onBehalfOfContentOwner A content owner ID.
*/
-function retrieveReports(Google_Service_YouTubeReporting $youtubeReporting, $jobId, &$htmlBody) {
- // Call the YouTube Reporting API's reports.list method to retrieve reports created by a job.
- $reports = $youtubeReporting->jobs_reports->listJobsReports($jobId);
-
- if (empty($reports)) {
- $htmlBody .= sprintf('Reports for the job "%s"
', $jobId);
- foreach ($reports as $report) {
- $htmlBody .= sprintf('
';
- }
+function listReportsForJob(Google_Service_YouTubeReporting $youtubeReporting,
+ $jobId, $onBehalfOfContentOwner = '') {
+ $reports = $youtubeReporting->jobs_reports->listJobsReports($jobId,
+ array('onBehalfOfContentOwner' => $onBehalfOfContentOwner));
+ print ('DOWNLOADABLE REPORTS' . PHP_EOL . '********************' . PHP_EOL);
+ foreach ($reports['reports'] as $report) {
+ print('Created: ' . date('d M Y', strtotime($report['createTime'])) .
+ ' (' . date('d M Y', strtotime($report['startTime'])) .
+ ' to ' . date('d M Y', strtotime($report['endTime'])) . ')' .
+ PHP_EOL . ' ' . $report['downloadUrl'] . PHP_EOL . PHP_EOL);
}
}
-
/**
* Download the report specified by the URL. (media.download)
*
* @param Google_Service_YouTubereporting $youtubeReporting YouTube Reporting service object.
* @param string $reportUrl The URL of the report to be downloaded.
+ * @param string $outputFile The file to write the report to locally.
* @param $htmlBody - html body.
*/
-function downloadReport(Google_Service_YouTubeReporting $youtubeReporting, $reportUrl, &$htmlBody) {
+function downloadReport(Google_Service_YouTubeReporting $youtubeReporting,
+ $reportUrl, $outputFile) {
$client = $youtubeReporting->getClient();
- // Setting the defer flag to true tells the client to return a request which can be called
- // with ->execute(); instead of making the API call immediately.
+ // Setting the defer flag to true tells the client to return a request that
+ // can be called with ->execute(); instead of making the API call immediately.
$client->setDefer(true);
- // Call the YouTube Reporting API's media.download method to download a report.
- $request = $youtubeReporting->media->download("");
- $request->setUrl($reportUrl);
- $response = $client->execute($request);
-
- file_put_contents("reportFile", $response->getResponseBody());
+ // Call YouTube Reporting API's media.download method to download a report.
+ $request = $youtubeReporting->media->download('', array('alt' => 'media'));
+ $request = $request->withUri(new \GuzzleHttp\Psr7\Uri($reportUrl));
+ $responseBody = '';
+ try {
+ $response = $client->execute($request);
+ $responseBody = $response->getBody();
+ } catch (Google_Service_Exception $e) {
+ $responseBody = $e->getTrace()[0]['args'][0]->getResponseBody();
+ }
+ file_put_contents($outputFile, $responseBody);
$client->setDefer(false);
}
-?>
-
-
-
-
+Description: This sample calls the API's channelSections.insert method to create channel sections.
+The code accepts a number of command line arguments that let you specify the section's type, display style, title, position,
+and content.
+This sample also updates the channel's
+brandingSettings.channel.showBrowseView
+property so that the channel displays content in a browse view (rather than a feed view). A channel's sections are only
+visible if the channel displays content in a browse view.
More information on channel sections is available in the
+YouTube Help Center.
+
+### [Add a channel subscription](/python/add_subscription.py)
+
+Method: youtube.subscriptions.insert
+Description: This sample calls the API's subscriptions.insert method to add a subscription to a specified
+channel.
+
+### [Add a featured video](/python/add_featured_video.py)
+
+Method: youtube.channels.update
+Description: This sample calls the API's channels.update method to set invideoPromotion
+properties for the channel.
+
+### [Create a playlist](/python/playlist_updates.py)
+
+Method: youtube.playlists.insert
+Description: This sample calls the API's playlists.insert method to create a private playlist owned by the
+channel authorizing the request.
+
+### [Create and manage comments](/python/comment_handling.py)
+
+Method: youtube.commentThreads.list, youtube.comments.insert, youtube.comments.list, youtube.comments.update,
+youtube.comments.setModerationStatus, youtube.comments.markAsSpam, youtube.comments.delete
+Description: This sample demonstrates how to use the following API methods to create and manage comments:
+
+
+
+### [Create and manage comment threads](/python/comment_threads.py)
+
+Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.updatecommentThreads.list method with the videoId parameter set to retrieve comments
+for a video.comments.insert method with the parentId parameter set to reply to an existing
+comment.comments.list method with the parentId parameter to retrieve the comments in the
+thread.comments.update method with comment in the request body to update a comment.comments.setModerationStatus method to set the moderation status of the comment, the
+comments.markAsSpam method to mark the comment as spam, and the comments.delete method to
+delete the comment, using the id parameter to identify the comment.
+Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
+
+
+
+### [Create and manage YouTube video caption tracks](/python/captions.py)
+
+Method: youtube.captions.insert, youtube.captions.list, youtube.captions.update, youtube.captions.download,
+youtube.captions.deletecommentThreads.insert method once with the channelId parameter to create a
+channel comment and once with the videoId parameter to create a video comment.commentThreads.list method once with the channelId parameter to retrieve
+channel comments and once with the videoId parameter to retrieve video comments.commentThreads.update method once to update a video comment and then again to update a
+channel comment. In each case, the request body contains the comment resource being updated.
+Description: This sample demonstrates how to use the following API methods to create and manage YouTube video caption
+tracks:
+
+
+
+### [Like a video](/python/like_video.py)
+
+Method: youtube.videos.ratecaptions.insert method with the isDraft parameter set to true
+to upload a caption track in draft status.captions.list method with the videoId parameter to retrieve video caption
+tracks.captions.update method with the caption in the request body to update a caption track.captions.download method to download the caption track.captions.delete method to delete the caption track, using the id parameter to
+identify the caption track.
+Description: This sample calls the API's videos.rate method to set a positive rating for a video.
+
+### [Post a channel bulletin](/python/channel_bulletin.py)
+
+Method: youtube.activities.insert
+Description: This sample calls the API's activities.insert method to post a bulletin to the channel
+associated with the request.
+
+### [Remove a watermark image from a channel](/python/unset_watermark.py)
+
+Method: youtube.watermarks.unset
+Description: This sample calls the API's watermarks.unset method to remove the watermark
+image for a channel. The request must be authorized by the channel that owns the video.
+
+### [Retrieve my uploads](/python/my_uploads.py)
+
+Method: youtube.playlistItems.list
+Description: This sample calls the API's playlistItems.list method to retrieve a list of videos uploaded
+to the channel associated with the request. The code also calls the channels.list method with the
+mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded
+videos.
+
+### [Search by keyword](/python/search.py)
+
+Method: youtube.search.list
+Description: This sample calls the API's search.list method to retrieve search results associated with
+a particular keyword.
+
+### [Search by location](/python/geolocation_search.py)
+
+Method: youtube.search.list, youtube.videos.list
+Description: This sample calls the API's search.list method with the type,
+q, location, and locationRadius parameters to retrieve search results
+matching the provided keyword within the radius centered at a particular location. Using the video ids from
+the search result, the sample calls the API's videos.list method to retrieve location details
+of each video.
+
+### [Set and retrieve localized channel metadata](/python/channel_localizations.py)
+
+Method: youtube.channels.update, youtube.channels.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a
+channel:
+
+
+
+### [Set and retrieve localized channel section metadata](/python/channel_section_localizations.py)
+
+Method: youtube.channelSections.update, youtube.channelSections.listchannels.update method to update the default language of a channel's metadata and to add a
+localized version of this metadata in a selected language. Note that to set the default language for a channel resource,
+you actually need to update the brandingSettings.channel.defaultLanguage property.channels.list method with the hl parameter set to a specific language to
+retrieve localized metadata in that language.channels.list method and includes localizations in the part
+parameter value to retrieve all of the localized metadata for that channel.
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a
+channel section:
+
+
+
+### [Set and retrieve localized playlist metadata](/python/playlist_localizations.py)
+
+Method: youtube.playlists.update, youtube.playlists.listchannelSections.update method to update the default language of a channel section's
+metadata and to add a localized version of this metadata in a selected language.channelSections.list method with the hl parameter set to a specific language
+to retrieve localized metadata in that language.channelSections.list method and includes localizations in the
+part parameter value to retrieve all of the localized metadata for that channel section.
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a
+playlist:
+
+
+
+### [Set and retrieve localized video metadata](/python/video_localizations.py)
+
+Method: youtube.videos.update, youtube.videos.listplaylists.update method to update the default language of a playlist's metadata and to add
+a localized version of this metadata in a selected language.playlists.list method with the hl parameter set to a specific language to
+retrieve localized metadata in that language.playlists.list method and includes localizations in the part
+parameter value to retrieve all of the localized metadata for that playlist.
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata
+for a video:
+
+
+
+### [Shuffle existing channel sections](/python/shuffle_channel_sections.py)
+
+Method: youtube.channelSections.list,youtube.channelSections.updatevideos.update method to update the default language of a video's metadata and to add
+a localized version of this metadata in a selected language.videos.list method with the hl parameter set to a specific language to
+retrieve localized metadata in that language.videos.list method and includes localizations in the part
+parameter value to retrieve all of the localized metadata for that video.
+Description: This sample calls the API's channelSections.list method to get the list of current channel
+sections. Then it shuffles the list and calls channelSections.update to change the position of each item.
+More information on channel sections is available in the
+YouTube Help Center.
+
+### [Update a video](/python/update_video.py)
+
+Method: youtube.videos.update
+Description: This sample calls the API's videos.update method to update a video owned by the channel
+authorizing the request.
+
+### [Upload a banner image and set as channel's banner](/python/upload_banner.py)
+
+Method: youtube.channelBanners.insert, youtube.channels.update
+Description: This sample calls the API's channelBanners.insert method to upload an image. With the
+returned URL, the sample calls channels.update method to update the channel's banner to that image.
+
+### [Upload a video](/python/upload_video.py)
+
+Method: youtube.videos.insert
+Description: This sample calls the API's videos.insert method to upload a video to the channel associated
+with the request.
+
+### [Upload a video thumbnail image](/python/upload_thumbnail.py)
+
+Method: youtube.thumbnails.set
+Description: This sample calls the API's thumbnails.set method to upload an image and set it as the
+thumbnail image for a video. The request must be authorized by the channel that owns the video.
+
+### [Upload a watermark image and set it for a channel](/python/set_watermark.py)
+
+Method: youtube.watermarks.set
+Description: This sample calls the API's watermarks.set method to upload an image and set it as the
+watermark image for a channel. The request must be authorized by the channel that owns the video.
+
+### [Create a broadcast and stream](/python/create_broadcast.py)
+
+Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
+Description: This sample calls the API's liveBroadcasts.insert and liveStreams.insert
+methods to create a broadcast and a stream. Then, it calls the liveBroadcasts.bind method to bind
+the stream to the broadcast.
+
+### [Retrieve a channel's broadcasts](/python/list_broadcasts.py)
+
+Method: youtube.liveBroadcasts.list
+Description: This sample calls the API's liveBroadcasts.list method to retrieve a list of broadcasts for
+the channel associated with the request. By default, the request retrieves all broadcasts for the channel, but you can
+also specify a value for the --broadcast-status option to only retrieve broadcasts with a particular status.
+
+### [Retrieve a channel's live video streams](/python/list_streams.py)
+
+Method: youtube.liveStreams.list
+Description: This sample calls the API's liveStreams.list method to retrieve a list of video stream settings
+that a channel can use to broadcast live events on YouTube.
+
+### [Retrieve top 10 videos by viewcount](/python/yt_analytics_report.py)
+
+Method: youtubeAnalytics.reports.query
+Description: This sample calls the API's reports.query method to retrieve YouTube Analytics data.
+By default, the report retrieves the top 10 videos based on viewcounts, and it returns several metrics for those
+videos, sorting the results in reverse order by viewcount. By setting command line parameters, you can use the
+same code to retrieve other reports as well.
+
+### [Create a reporting job](/python/create_reporting_job.py)
+
+Method: youtubeReporting.reportTypes.list, youtubeReporting.jobs.create
+Description: This sample demonstrates how to create a reporting job. It calls the reportTypes.list method
+to retrieve a list of available report types. It then calls the jobs.create method to create a new reporting
+job.
+
+### [Retrieve reports](/python/retrieve_reports.py)
+
+Method: youtubeReporting.jobs.list, youtubeReporting.reports.list
+Description: This sample demonstrates how to retrieve reports created by a specific job. It calls the
+jobs.list method to retrieve reporting jobs. It then calls the reports.list method with the
+jobId parameter set to a specific job id to retrieve reports created by that job. Finally, the sample
+prints out the download URL for each report.
diff --git a/python/add_channel_section.py b/python/add_channel_section.py
index e51fcf6c..c2b82911 100644
--- a/python/add_channel_section.py
+++ b/python/add_channel_section.py
@@ -1,15 +1,14 @@
#!/usr/bin/python
-import httplib2
+import argparse
import os
import re
-import sys
-from apiclient.discovery import build
-from apiclient.errors import HttpError
-from oauth2client.client import flow_from_clientsecrets
-from oauth2client.file import Storage
-from oauth2client.tools import argparser, run_flow
+import google.oauth2.credentials
+import google_auth_oauthlib.flow
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from google_auth_oauthlib.flow import InstalledAppFlow
# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
@@ -23,72 +22,50 @@
# For more information about the client_secrets.json file format, see:
# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
-CLIENT_SECRETS_FILE = "client_secrets.json"
-
-# This variable defines a message to display if the CLIENT_SECRETS_FILE is
-# missing.
-MISSING_CLIENT_SECRETS_MESSAGE = """
-WARNING: Please configure OAuth 2.0
-
-To make this sample run you will need to populate the client_secrets.json file
-found at:
-
- %s
-
-with information from the {{ Cloud Console }}
-{{ https://cloud.google.com/console }}
-
-For more information about the client_secrets.json file format, please visit:
-https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
-""" % os.path.abspath(os.path.join(os.path.dirname(__file__),
- CLIENT_SECRETS_FILE))
+CLIENT_SECRETS_FILE = 'client_secret.json'
# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account.
-YOUTUBE_SCOPE = "https://www.googleapis.com/auth/youtube"
-YOUTUBE_API_SERVICE_NAME = "youtube"
-YOUTUBE_API_VERSION = "v3"
-
-SECTION_TYPES = ("allPlaylists", "completedEvents", "likedPlaylists",
- "likes", "liveEvents", "multipleChannels", "multiplePlaylists",
- "popularUploads", "recentActivity", "recentPosts", "recentUploads",
- "singlePlaylist", "upcomingEvents",)
-SECTION_STYLES = ("horizontalRow", "verticalList",)
+SCOPES = ['https://www.googleapis.com/auth/youtube']
+API_SERVICE_NAME = 'youtube'
+API_VERSION = 'v3'
-def get_authenticated_service(args):
- flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_SCOPE,
- message=MISSING_CLIENT_SECRETS_MESSAGE)
+SECTION_TYPES = ('allPlaylists', 'completedEvents', 'likedPlaylists',
+ 'likes', 'liveEvents', 'multipleChannels', 'multiplePlaylists',
+ 'popularUploads', 'recentActivity', 'recentPosts', 'recentUploads',
+ 'singlePlaylist', 'upcomingEvents',)
+SECTION_STYLES = ('horizontalRow', 'verticalList',)
- storage = Storage("%s-oauth2.json" % sys.argv[0])
- credentials = storage.get()
- if credentials is None or credentials.invalid:
- credentials = run_flow(flow, storage, args)
+def get_authenticated_service():
+ flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
+ credentials = flow.run_console()
+ return build(API_SERVICE_NAME, API_VERSION, credentials = credentials)
- return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
- http=credentials.authorize(httplib2.Http()))
+def print_response(response):
+ print(response)
def enable_browse_view(youtube):
channels_list_response = youtube.channels().list(
- part="brandingSettings",
+ part='brandingSettings',
mine=True
).execute()
- channel = channels_list_response["items"][0]
- channel["brandingSettings"]["channel"]["showBrowseView"] = True
+ channel = channels_list_response['items'][0]
+ channel['brandingSettings']['channel']['showBrowseView'] = True
youtube.channels().update(
- part="brandingSettings",
+ part='brandingSettings',
body=channel
).execute()
def add_channel_section(youtube, args):
channels = None
if args.channels:
- channels = re.split("\s*,\s*", args.channels)
+ channels = re.split('\s*,\s*', args.channels)
playlists = None
if args.playlists:
- playlists = re.split("\s*,\s*", args.playlists)
+ playlists = re.split('\s*,\s*', args.playlists)
body = dict(
snippet=dict(
@@ -104,28 +81,31 @@ def add_channel_section(youtube, args):
)
youtube.channelSections().insert(
- part="snippet,contentDetails",
+ part='snippet,contentDetails',
body=body
).execute()
if __name__ == '__main__':
- argparser.add_argument("--type", choices=SECTION_TYPES, required=True,
- help="The type of the section to be added.")
- argparser.add_argument("--style", choices=SECTION_STYLES, required=True,
- help="The style of the section to be added.")
- argparser.add_argument("--title",
- help=("The title to display for the new section. This is only used "
- "with the multiplePlaylists or multipleChannels section types."))
- argparser.add_argument("--position", type=int,
- help=("The position of the new section. "
- "Use 0 for the top, or don't set a value for the bottom."))
- argparser.add_argument("--playlists",
- help="One or more playlist ids, comma-separated (e.g. PL...).")
- argparser.add_argument("--channels",
- help="One or more channel ids, comma-separated (e.g. UC...).")
- args = argparser.parse_args()
-
- youtube = get_authenticated_service(args)
+
+ parser = argparse.ArgumentParser(description='Process some integers.')
+ parser.add_argument('--type', choices=SECTION_TYPES, required=True,
+ help='The type of the section to be added.')
+ parser.add_argument('--style', choices=SECTION_STYLES, required=True,
+ help='The style of the section to be added.')
+ parser.add_argument('--title',
+ help='The title to display for the new section. This is only used '
+ 'with the multiplePlaylists or multipleChannels section types.')
+ parser.add_argument('--position', type=int,
+ help='The position of the new section. Use 0 for the top, '
+ 'or don\'t set a value for the bottom.')
+ parser.add_argument('--playlists',
+ help='One or more playlist ids, comma-separated (e.g. PL...).')
+ parser.add_argument('--channels',
+ help='One or more channel ids, comma-separated (e.g. UC...).')
+
+ args = parser.parse_args()
+
+ youtube = get_authenticated_service()
try:
# Before channel shelves will appear on your channel's web page, browse
# view needs to be enabled. If you know that your channel already has
@@ -135,6 +115,6 @@ def add_channel_section(youtube, args):
add_channel_section(youtube, args)
except HttpError, e:
- print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
+ print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content)
else:
- print "Added new channel section."
+ print 'Added new channel section.
diff --git a/python/add_subscription.py b/python/add_subscription.py
index dadaae0b..2ac0510e 100644
--- a/python/add_subscription.py
+++ b/python/add_subscription.py
@@ -1,14 +1,19 @@
#!/usr/bin/python
-import httplib2
+# This code sample shows how to add a channel subscription.
+# The default channel-id is for the GoogleDevelopers YouTube channel.
+# Sample usage:
+# python add_subscription.py --channel-id=UC_x5XG1OV2P6uZZ5FSM9Ttw
+
+import argparse
import os
-import sys
+import re
-from apiclient.discovery import build
-from apiclient.errors import HttpError
-from oauth2client.client import flow_from_clientsecrets
-from oauth2client.file import Storage
-from oauth2client.tools import argparser, run_flow
+import google.oauth2.credentials
+import google_auth_oauthlib.flow
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from google_auth_oauthlib.flow import InstalledAppFlow
# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
@@ -21,46 +26,18 @@
# https://developers.google.com/youtube/v3/guides/authentication
# For more information about the client_secrets.json file format, see:
# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
-CLIENT_SECRETS_FILE = "client_secrets.json"
+CLIENT_SECRETS_FILE = 'client_secret.json'
# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account.
-YOUTUBE_READ_WRITE_SCOPE = "https://www.googleapis.com/auth/youtube"
-YOUTUBE_API_SERVICE_NAME = "youtube"
-YOUTUBE_API_VERSION = "v3"
-
-# This variable defines a message to display if the CLIENT_SECRETS_FILE is
-# missing.
-MISSING_CLIENT_SECRETS_MESSAGE = """
-WARNING: Please configure OAuth 2.0
-
-To make this sample run you will need to populate the client_secrets.json file
-found at:
-
- %s
-
-with information from the {{ Cloud Console }}
-{{ https://cloud.google.com/console }}
-
-For more information about the client_secrets.json file format, please visit:
-https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
-""" % os.path.abspath(os.path.join(os.path.dirname(__file__),
- CLIENT_SECRETS_FILE))
-
-def get_authenticated_service(args):
- flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE,
- scope=YOUTUBE_READ_WRITE_SCOPE,
- message=MISSING_CLIENT_SECRETS_MESSAGE)
-
- storage = Storage("%s-oauth2.json" % sys.argv[0])
- credentials = storage.get()
-
- if credentials is None or credentials.invalid:
- credentials = run_flow(flow, storage, args)
-
- return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
- http=credentials.authorize(httplib2.Http()))
+SCOPES = ['https://www.googleapis.com/auth/youtube']
+API_SERVICE_NAME = 'youtube'
+API_VERSION = 'v3'
+def get_authenticated_service():
+ flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
+ credentials = flow.run_console()
+ return build(API_SERVICE_NAME, API_VERSION, credentials = credentials)
# This method calls the API's youtube.subscriptions.insert method to add a
# subscription to the specified channel.
@@ -75,17 +52,18 @@ def add_subscription(youtube, channel_id):
)
)).execute()
- return add_subscription_response["snippet"]["title"]
+ return add_subscription_response['snippet']['title']
-if __name__ == "__main__":
- argparser.add_argument("--channel-id", help="ID of the channel to subscribe to.",
- default="UCtVd0c0tGXuTSbU5d8cSBUg")
- args = argparser.parse_args()
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Process arguments.')
+ parser.add_argument('--channel-id', help='ID of the channel to subscribe to.',
+ default='UC_x5XG1OV2P6uZZ5FSM9Ttw')
+ args = parser.parse_args()
- youtube = get_authenticated_service(args)
+ youtube = get_authenticated_service()
try:
channel_title = add_subscription(youtube, args.channel_id)
except HttpError, e:
- print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
+ print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content)
else:
- print "A subscription to '%s' was added." % channel_title
+ print 'A subscription to \'%s\' was added.' % channel_title
diff --git a/python/batch_report_download.py b/python/batch_report_download.py
deleted file mode 100644
index 6a1d28af..00000000
--- a/python/batch_report_download.py
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/usr/bin/python
-
-import httplib2
-import os
-import sys
-import urllib
-
-from apiclient.discovery import build, build_from_document
-from apiclient.errors import HttpError
-from apiclient.http import MediaIoBaseDownload
-from oauth2client.client import flow_from_clientsecrets
-from oauth2client.file import Storage
-from oauth2client.tools import argparser, run_flow
-
-
-# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
-# the OAuth 2.0 information for this application, including its client_id and
-# client_secret. You can acquire an OAuth 2.0 client ID and client secret from
-# the Google Cloud Console at
-# https://cloud.google.com/console.
-# Please ensure that you have enabled the YouTube Analytics API for your project.
-# For more information about using OAuth2 to access Google APIs, see:
-# https://developers.google.com/youtube/v3/guides/authentication
-# For more information about the client_secrets.json file format, see:
-# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
-CLIENT_SECRETS_FILE = "client_secrets.json"
-
-# This OAuth 2.0 access scope allows for full read/write access to the
-# authenticated user's account.
-SCOPES = ("https://www.googleapis.com/auth/yt-analytics-monetary.readonly",
- "https://www.googleapis.com/auth/yt-analytics.readonly")
-YOUTUBE_ANALYTICS_API_SERVICE_NAME = "youtubeAnalytics"
-YOUTUBE_ANALYTICS_API_VERSION = "v1beta1"
-
-# This variable defines a message to display if the CLIENT_SECRETS_FILE is
-# missing.
-MISSING_CLIENT_SECRETS_MESSAGE = """
-WARNING: Please configure OAuth 2.0
-
-To make this sample run you will need to populate the client_secrets.json file
-found at:
-
- %s
-
-with information from the Cloud Console
-https://cloud.google.com/console
-
-For more information about the client_secrets.json file format, please visit:
-https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
-""" % os.path.abspath(os.path.join(os.path.dirname(__file__),
- CLIENT_SECRETS_FILE))
-
-# Maps a shorthand notation for the different report types to the string used
-# to identify each type in the batchReportDefinitionList response.
-REPORT_TYPES_TO_NAMES = dict(
- assets="Full asset report",
- claims="Full claim report"
-)
-
-def get_authenticated_service(args):
- flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE,
- scope=" ".join(SCOPES),
- message=MISSING_CLIENT_SECRETS_MESSAGE)
-
- storage = Storage("%s-oauth2.json" % sys.argv[0])
- credentials = storage.get()
-
- if credentials is None or credentials.invalid:
- credentials = run_flow(flow, storage, args)
-
- http = credentials.authorize(httplib2.Http())
-
- return build(YOUTUBE_ANALYTICS_API_SERVICE_NAME,
- YOUTUBE_ANALYTICS_API_VERSION, http=http)
-
-def get_available_reports(youtubeAnalytics, contentOwner):
- definitions_list_response = youtubeAnalytics.batchReportDefinitions().list(
- onBehalfOfContentOwner=contentOwner,
- ).execute()
-
- return definitions_list_response["items"]
-
-def get_info_for_report(youtubeAnalytics, contentOwner, report_id):
- reports_list_response = youtubeAnalytics.batchReports().list(
- onBehalfOfContentOwner=contentOwner,
- batchReportDefinitionId=report_id
- ).execute()
-
- url = reports_list_response["items"][0]["outputs"][0]["downloadUrl"]
- date = reports_list_response["items"][0]["timeSpan"]["startTime"]
- return (url, date)
-
-if __name__ == "__main__":
- argparser.add_argument("--content-owner-id", required=True,
- help="ID of the content owner.")
- argparser.add_argument("--report-type", required=True,
- choices=REPORT_TYPES_TO_NAMES.keys(), help="The type of report to download.")
- argparser.add_argument("--download-directory", default=os.getcwd(),
- help="The directory to download the report into.")
- args = argparser.parse_args()
-
- # Steps to download a batch report:
- # 1. Given an authorized instance of the YouTube Analytics service, retrieve
- # a list of all the available report definitions via
- # youtubeAnalytics.batchReportDefinitions.list()
- # 2. Iterate through the report definitions to find the one we're interested
- # in based on its name: either an assets or claims report.
- # 3. Get the unique id of the report definition, which will in turn be passed
- # in to youtubeAnalytics.batchReports.list().
- # 4. The youtubeAnalytics.batchReports.list() reponse will contain one or more
- # days' worth of reports. The code gets download info for the first item
- # in the response, which will be the most recent day's report.
- # 5. Parse out the date and the download URL for the relevant report, and use
- # that to download the report, with the date used as part of the file name.
- youtubeAnalytics = get_authenticated_service(args)
- try:
- reports = get_available_reports(youtubeAnalytics, args.content_owner_id)
-
- report_id = None
- for report in reports:
- if (REPORT_TYPES_TO_NAMES[args.report_type] == report["name"]
- and report["status"] == "supported"):
- report_id = report["id"]
- break
-
- if report_id:
- (url, date) = get_info_for_report(youtubeAnalytics,
- args.content_owner_id, report_id)
-
- file_path = os.path.join(args.download_directory,
- "%s-%s.csv" % (args.report_type, date))
-
- # This is a simple approach to downloading a file at a given URL.
- # If desired, you can add in a callback method to log the
- # progress of the download. See
- # http://docs.python.org/2/library/urllib.html#urllib.urlretrieve
- urllib.urlretrieve(url, file_path)
-
- print "The report was downloaded to %s" % file_path
- else:
- # There might not be a report available if, for instance, there are no
- # assets or claims associated with a given content owner's account.
- print "No report of type '%s' was available." % args.report_type
- except HttpError, e:
- print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
diff --git a/python/channel_localizations.py b/python/channel_localizations.py
index 6a615e70..a244ca6d 100644
--- a/python/channel_localizations.py
+++ b/python/channel_localizations.py
@@ -1,17 +1,17 @@
#!/usr/bin/python
# Usage example:
-# python channel_localizations.py --action='playlistItems.list method to retrieve a list of videos uploaded
+to a specified channel. The channel can be identified by its channel ID or channel name. The code also calls the
+channels.list method to retrieve the playlist ID that identifies the channel's uploaded videos.
+
+### [Search by keyword](/python_appengine/search/main.py)
+
+Method: youtube.search.list
+Description: This code sample calls the API's search.list method to retrieve search results associated
+with a particular keyword.
diff --git a/python_appengine/search/main.py b/python_appengine/search/main.py
index d5640d61..baefaab6 100644
--- a/python_appengine/search/main.py
+++ b/python_appengine/search/main.py
@@ -23,7 +23,7 @@ def get(self):
if DEVELOPER_KEY == "REPLACE_ME":
self.response.write("""You must set up a project and get an API key
to run this project. Please visit
-
-
- {% endfor %}
-
-
diff --git a/python_appengine/topics/main.py b/python_appengine/topics/main.py
deleted file mode 100644
index e389c4cd..00000000
--- a/python_appengine/topics/main.py
+++ /dev/null
@@ -1,108 +0,0 @@
-import os
-import urllib
-import webapp2
-import jinja2
-
-from apiclient.discovery import build
-from optparse import OptionParser
-
-import json
-
-JINJA_ENVIRONMENT = jinja2.Environment(
- loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
- extensions=['jinja2.ext.autoescape'])
-
-REGISTRATION_INSTRUCTIONS = """
- You must set up a project and get an API key to run this code. Please see
- the instructions for creating a project and a key at https://developers.google.com/youtube/registering_an_application.
-
- Make sure that you have enabled the YouTube Data API (v3) and the Freebase
- API for your project."""
-
-# Set API_KEY to the "API key" value from the Google Developers Console:
-# https://console.developers.google.com/project/_/apiui/credential
-# Please ensure that you have enabled the YouTube Data API and Freebase API
-# for your project.
-API_KEY = "REPLACE_ME"
-YOUTUBE_API_SERVICE_NAME = "youtube"
-YOUTUBE_API_VERSION = "v3"
-FREEBASE_SEARCH_URL = "https://www.googleapis.com/freebase/v1/search?%s"
-QUERY_TERM = "dog"
-
-class MainHandler(webapp2.RequestHandler):
-
- def get(self):
- if API_KEY == 'REPLACE_ME':
- self.response.write(REGISTRATION_INSTRUCTIONS)
- else:
- # Present a list of Freebase topic IDs for the query term
- self.list_topics(QUERY_TERM)
-
- def list_topics(self, QUERY_TERM):
- # Retrieve a list of Freebase topics associated with the query term
- freebase_params = dict(query=QUERY_TERM, key=API_KEY)
- freebase_url = FREEBASE_SEARCH_URL % urllib.urlencode(freebase_params)
- freebase_response = json.loads(urllib.urlopen(freebase_url).read())
-
- if len(freebase_response["result"]) == 0:
- exit("No matching terms were found in Freebase.")
-
- # Create a page that shows a select box listing the topics.
- # When the user selects a topic and submits the form, the
- # 'post' method below will handle the form submission and
- # retrieve videos for the selected topic.
- select_topic_page = ('''
-
-
-
+Description: This sample calls the API's subscriptions.insert method to add a subscription
+to a specified channel.
+
+### [Post a channel bulletin](/ruby/channel_bulletin.rb)
+
+Method: youtube.activities.insert
+Description: This sample calls the API's activities.insert method to post a bulletin to the channel
+associated with the request.
+
+### [Retrieve my uploads](/ruby/my_uploads.rb)
+
+Method: youtube.playlistItems.list
+Description: This sample calls the API's playlistItems.list method to retrieve a list of videos uploaded
+to the channel associated with the request. The code also calls the channels.list method with the
+mine parameter set to true to retrieve the playlist ID that identifies the channel's
+uploaded videos.
+
+### [Search by keyword](/ruby/search.rb)
+
+Method: youtube.search.list
+Description: This sample calls the API's search.list method to retrieve search results
+associated with a particular keyword.
+
+### [Upload a video](/ruby/upload_video.rb)
+
+Method: youtube.videos.insert
+Description: This sample calls the API's videos.insert method to upload a video to the channel
+associated with the request.
+
+### [Retrieve top 10 videos by viewcount](/ruby/yt_analytics_report.rb)
+
+Method: youtubeAnalytics.reports.query
+Description: This sample calls the API's reports.query method to retrieve YouTube Analytics data.
+By default, the report retrieves the top 10 videos based on viewcounts, and it returns several metrics for those
+videos, sorting the results in reverse order by viewcount. By setting command line parameters, you can use the same
+code to retrieve other reports as well.
diff --git a/ruby/quickstart.rb b/ruby/quickstart.rb
new file mode 100644
index 00000000..bd73fc22
--- /dev/null
+++ b/ruby/quickstart.rb
@@ -0,0 +1,64 @@
+# Sample Ruby code for user authorization
+
+require 'rubygems'
+gem 'google-api-client', '>0.7'
+require 'google/apis'
+require 'google/apis/youtube_v3'
+require 'googleauth'
+require 'googleauth/stores/file_token_store'
+
+require 'fileutils'
+require 'json'
+
+# REPLACE WITH VALID REDIRECT_URI FOR YOUR CLIENT
+REDIRECT_URI = 'http://localhost'
+APPLICATION_NAME = 'YouTube Data API Ruby Tests'
+
+# REPLACE WITH NAME/LOCATION OF YOUR client_secrets.json FILE
+CLIENT_SECRETS_PATH = 'client_secret.json'
+
+# REPLACE FINAL ARGUMENT WITH FILE WHERE CREDENTIALS WILL BE STORED
+CREDENTIALS_PATH = File.join(Dir.home, '.credentials',
+ "youtube-quickstart-ruby-credentials.yaml")
+
+# SCOPE FOR WHICH THIS SCRIPT REQUESTS AUTHORIZATION
+SCOPE = Google::Apis::YoutubeV3::AUTH_YOUTUBE_READONLY
+
+def authorize
+ FileUtils.mkdir_p(File.dirname(CREDENTIALS_PATH))
+
+ client_id = Google::Auth::ClientId.from_file(CLIENT_SECRETS_PATH)
+ token_store = Google::Auth::Stores::FileTokenStore.new(file: CREDENTIALS_PATH)
+ authorizer = Google::Auth::UserAuthorizer.new(
+ client_id, SCOPE, token_store)
+ user_id = 'default'
+ credentials = authorizer.get_credentials(user_id)
+ if credentials.nil?
+ url = authorizer.get_authorization_url(base_url: REDIRECT_URI)
+ puts "Open the following URL in the browser and enter the " +
+ "resulting code after authorization"
+ puts url
+ code = gets
+ credentials = authorizer.get_and_store_credentials_from_code(
+ user_id: user_id, code: code, base_url: REDIRECT_URI)
+ end
+ credentials
+end
+
+# Initialize the API
+service = Google::Apis::YoutubeV3::YouTubeService.new
+service.client_options.application_name = APPLICATION_NAME
+service.authorization = authorize
+
+# Sample ruby code for channels.list
+
+def channels_list_by_username(service, part, **params)
+ response = service.list_channels(part, params).to_json
+ item = JSON.parse(response).fetch("items")[0]
+
+ puts ("This channel's ID is #{item.fetch("id")}. " +
+ "Its title is '#{item.fetch("snippet").fetch("title")}', and it has " +
+ "#{item.fetch("statistics").fetch("viewCount")} views.")
+end
+
+channels_list_by_username(service, 'snippet,contentDetails,statistics', for_username: 'GoogleDevelopers')