From 618d8d129c90735ecbc32e3aa4d7bd9bda55ae64 Mon Sep 17 00:00:00 2001 From: Hill Ma Date: Fri, 4 Nov 2016 13:21:55 -0700 Subject: [PATCH 001/126] Fix Java build. - Use latest API dependency versions. - Add missing YouTube Reporting API dependency. - Fix outdated API usage. - Use latest version of Maven Compiler Plugin. --- java/pom.xml | 20 +++++++++++++------ .../youtube/cmdline/data/CommentHandling.java | 8 ++++---- .../youtube/cmdline/data/CommentThreads.java | 6 +++--- .../cmdline/reporting/RetrieveReports.java | 1 + 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/java/pom.xml b/java/pom.xml index 91146f20..6de21773 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -11,10 +11,11 @@ http://maven.apache.org - v3-rev107-1.18.0-rc - v1-rev24-1.17.0-rc - 1.18.0-rc - 1.18.0-rc + v3-rev179-1.22.0 + v1-rev63-1.22.0 + v1-rev10-1.22.0 + 1.20.0 + 1.20.0 UTF-8 @@ -34,13 +35,20 @@ ${project.youtube.version} - + com.google.apis google-api-services-youtubeAnalytics ${project.youtube.analytics.version} + + + com.google.apis + google-api-services-youtubereporting + ${project.youtube.reporting.version} + + org.codehaus.jackson @@ -73,7 +81,7 @@ maven-compiler-plugin - 2.3.2 + 3.6.0 1.6 1.6 diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentHandling.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentHandling.java index 7bde57b8..75f58c36 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentHandling.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentHandling.java @@ -26,8 +26,8 @@ import com.google.api.services.youtube.model.Comment; import com.google.api.services.youtube.model.CommentSnippet; import com.google.api.services.youtube.model.CommentThread; -import com.google.api.services.youtube.model.V3CommentListResponse; -import com.google.api.services.youtube.model.V3CommentThreadListResponse; +import com.google.api.services.youtube.model.CommentListResponse; +import com.google.api.services.youtube.model.CommentThreadListResponse; import com.google.common.collect.Lists; /** @@ -86,7 +86,7 @@ public static void main(String[] args) { // Call the YouTube Data API's commentThreads.list method to // retrieve video comment threads. - V3CommentThreadListResponse videoCommentsListResponse = youtube.commentThreads() + CommentThreadListResponse videoCommentsListResponse = youtube.commentThreads() .list("snippet").setVideoId(videoId).setTextFormat("plainText").execute(); List videoComments = videoCommentsListResponse.getItems(); @@ -138,7 +138,7 @@ public static void main(String[] args) { // Call the YouTube Data API's comments.list method to retrieve // existing comment // replies. - V3CommentListResponse commentsListResponse = youtube.comments().list("snippet") + CommentListResponse commentsListResponse = youtube.comments().list("snippet") .setParentId(parentId).setTextFormat("plainText").execute(); List comments = commentsListResponse.getItems(); diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentThreads.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentThreads.java index e0e3de8d..b421da43 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentThreads.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentThreads.java @@ -27,7 +27,7 @@ import com.google.api.services.youtube.model.CommentSnippet; import com.google.api.services.youtube.model.CommentThread; import com.google.api.services.youtube.model.CommentThreadSnippet; -import com.google.api.services.youtube.model.V3CommentThreadListResponse; +import com.google.api.services.youtube.model.CommentThreadListResponse; import com.google.common.collect.Lists; /** @@ -135,7 +135,7 @@ public static void main(String[] args) { // Call the YouTube Data API's commentThreads.list method to // retrieve video comment threads. - V3CommentThreadListResponse videoCommentsListResponse = youtube.commentThreads() + CommentThreadListResponse videoCommentsListResponse = youtube.commentThreads() .list("snippet").setVideoId(videoId).setTextFormat("plainText").execute(); List videoComments = videoCommentsListResponse.getItems(); @@ -172,7 +172,7 @@ public static void main(String[] args) { // Call the YouTube Data API's commentThreads.list method to // retrieve channel comment threads. - V3CommentThreadListResponse channelCommentsListResponse = youtube.commentThreads() + CommentThreadListResponse channelCommentsListResponse = youtube.commentThreads() .list("snippet").setChannelId(channelId).setTextFormat("plainText").execute(); List channelComments = channelCommentsListResponse.getItems(); diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/RetrieveReports.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/RetrieveReports.java index 0757a409..211bb0d5 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/RetrieveReports.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/RetrieveReports.java @@ -16,6 +16,7 @@ import com.google.api.client.auth.oauth2.Credential; import com.google.api.client.googleapis.json.GoogleJsonResponseException; +import com.google.api.client.http.GenericUrl; import com.google.api.services.samples.youtube.cmdline.Auth; import com.google.api.services.youtubereporting.YouTubeReporting; import com.google.api.services.youtubereporting.YouTubeReporting.Media.Download; From 14f3a10fb3e860353b761345359ef1859f921b58 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 18 Nov 2016 15:43:33 -0500 Subject: [PATCH 002/126] Update README to list code samples in directory --- go/README | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/go/README b/go/README index c64bde18..41fc7b9e 100644 --- a/go/README +++ b/go/README @@ -15,8 +15,7 @@ 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. +The YouTube Data API 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". @@ -34,3 +33,37 @@ oauth.go contains code that is shared between the code samples that require OAut 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. + +Samples in this directory: + +### Authorize a request + +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. + +### Upload a video + +Method: youtube.videos.insert +Description: This code sample calls the API's videos.insert method to upload a video to the channel +associated with the request. + +### Retrieve my uploads + +Method: youtube.playlistItems.list +Description: This 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 + +Method: youtube.search.list +Description: This code sample calls the API's search.list method to retrieve search results associated +with a particular keyword. + +### Post a channel bulletin + +Method: youtube.activities.insert +Description: This code sample calls the API's activities.insert method to post a bulletin to the +channel associated with the request. From 28ea40f9087a48701cba917772b8c00903f92b3b Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 18 Nov 2016 15:46:04 -0500 Subject: [PATCH 003/126] Create README.md prior to deleting README --- go/README.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 go/README.md diff --git a/go/README.md b/go/README.md new file mode 100644 index 00000000..41fc7b9e --- /dev/null +++ b/go/README.md @@ -0,0 +1,69 @@ +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 YouTube Data API 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. + +Samples in this directory: + +### Authorize a request + +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. + +### Upload a video + +Method: youtube.videos.insert +Description: This code sample calls the API's videos.insert method to upload a video to the channel +associated with the request. + +### Retrieve my uploads + +Method: youtube.playlistItems.list +Description: This 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 + +Method: youtube.search.list +Description: This code sample calls the API's search.list method to retrieve search results associated +with a particular keyword. + +### Post a channel bulletin + +Method: youtube.activities.insert +Description: This code sample calls the API's activities.insert method to post a bulletin to the +channel associated with the request. From 254219110cebec50c0e36c037a7369dc390030de Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 18 Nov 2016 15:46:29 -0500 Subject: [PATCH 004/126] Delete README This file has been replaced by README.md --- go/README | 69 ------------------------------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 go/README diff --git a/go/README b/go/README deleted file mode 100644 index 41fc7b9e..00000000 --- a/go/README +++ /dev/null @@ -1,69 +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 YouTube Data API 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. - -Samples in this directory: - -### Authorize a request - -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. - -### Upload a video - -Method: youtube.videos.insert -Description: This code sample calls the API's videos.insert method to upload a video to the channel -associated with the request. - -### Retrieve my uploads - -Method: youtube.playlistItems.list -Description: This 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 - -Method: youtube.search.list -Description: This code sample calls the API's search.list method to retrieve search results associated -with a particular keyword. - -### Post a channel bulletin - -Method: youtube.activities.insert -Description: This code sample calls the API's activities.insert method to post a bulletin to the -channel associated with the request. From d1485d1d8423520620a88620f74b710134b221e5 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 18 Nov 2016 16:04:56 -0500 Subject: [PATCH 005/126] Link to samples from README --- go/README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/go/README.md b/go/README.md index 41fc7b9e..dfe80f12 100644 --- a/go/README.md +++ b/go/README.md @@ -34,36 +34,36 @@ 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. -Samples in this directory: +## Samples in this directory: -### Authorize a request +### [Authorize a request](/youtube/api-samples/blob/master/go/oauth.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. -### Upload a video +### [Upload a video](/youtube/api-samples/blob/master/go/upload_video.go) -Method: youtube.videos.insert +Method: youtube.videos.insert
Description: This code sample calls the API's videos.insert method to upload a video to the channel associated with the request. -### Retrieve my uploads +### [Retrieve my uploads](/youtube/api-samples/blob/master/go/my_uploads.go) -Method: youtube.playlistItems.list +Method: youtube.playlistItems.list
Description: This 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 +### [Search by keyword](/youtube/api-samples/blob/master/go/search_by_keyword.go) -Method: youtube.search.list +Method: youtube.search.list
Description: This code sample calls the API's search.list method to retrieve search results associated with a particular keyword. -### Post a channel bulletin +### [Post a channel bulletin](/youtube/api-samples/blob/master/go/post_bulletin.go) -Method: youtube.activities.insert +Method: youtube.activities.insert
Description: This code sample calls the API's activities.insert method to post a bulletin to the channel associated with the request. From b4fa3873384238832ea45d1bb2bf35a47c9501ce Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 08:13:44 -0500 Subject: [PATCH 006/126] Add README.md listing samples in dotnet directory --- dotnet/README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 dotnet/README.md diff --git a/dotnet/README.md b/dotnet/README.md new file mode 100644 index 00000000..e784a903 --- /dev/null +++ b/dotnet/README.md @@ -0,0 +1,33 @@ +## Samples in this directory: + +### [Upload a video](/youtube/api-samples/blob/master/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. + +### [Retrieve my uploads](/youtube/api-samples/blob/master/dotnet/MyUploads.go) + +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](/youtube/api-samples/blob/master/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. + +### [Create a playlist](/youtube/api-samples/blob/master/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 a content owner's managed channels](/youtube/api-samples/blob/master/dotnet/papi_my_managed_channels.cs) + +Method: youtube.channels.list +Description: The following code sample calls the YouTube Data API's channels.list method to retrieve a list +of channels managed by the content owner making the API request. From 2a3632c62fcacddb3382d156619bda701654ac0d Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 08:57:27 -0500 Subject: [PATCH 007/126] Add README.md listing samples in python directory --- python/README.md | 253 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 python/README.md diff --git a/python/README.md b/python/README.md new file mode 100644 index 00000000..5ef166c7 --- /dev/null +++ b/python/README.md @@ -0,0 +1,253 @@ +## Samples in this directory: + +### [Add a channel section](/youtube/api-samples/blob/master/python/add_channel_section.py) + +Method: youtube.channelSections.insert
+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 featured video](/youtube/api-samples/blob/master/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. + +### [Add a channel subscription](/youtube/api-samples/blob/master/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. + +### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/python/captions.py) + +Method: youtube.captions.insert, youtube.captions.list, youtube.captions.update, youtube.captions.download, +youtube.captions.delete
+Description: This sample demonstrates how to use the following API methods to create and manage YouTube video caption +tracks:
+

    +
  • It calls the captions.insert method with the isDraft parameter set to true +to upload a caption track in draft status.
  • +
  • It calls the captions.list method with the videoId parameter to retrieve video caption +tracks.
  • +
  • It calls the captions.update method with the caption in the request body to update a caption track.
  • +
  • It calls the captions.download method to download the caption track.
  • +
  • It calls the captions.delete method to delete the caption track, using the id parameter to +identify the caption track.
  • +
+ +### [Post a channel bulletin](/youtube/api-samples/blob/master/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. + +### [Set and retrieve localized metadata for a channel](/youtube/api-samples/blob/master/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:
+
    +
  • It calls the channels.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.
  • +
  • It calls the channels.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
  • +
  • It calls the channels.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that channel.
  • +
+ +### [Set and retrieve localized metadata for a channel section](/youtube/api-samples/blob/master/python/channel_section_localizations.py) + +Method: youtube.channelSections.update, youtube.channelSections.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a +channel section:
+
    +
  • It calls the 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.
  • +
  • It calls the channelSections.list method with the hl parameter set to a specific language +to retrieve localized metadata in that language.
  • +
  • It calls the channelSections.list method and includes localizations in the +part parameter value to retrieve all of the localized metadata for that channel section.
  • +
+ +### [Create and manage comments](/youtube/api-samples/blob/master/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: The following code sample demonstrates how to use the following API methods to create and manage comments:
+
    +
  • It calls the commentThreads.list method with the videoId parameter set to retrieve comments +for a video.
  • +
  • It calls the comments.insert method with the parentId parameter set to reply to an existing +comment.
  • +
  • It calls the comments.list method with the parentId parameter to retrieve the comments in the +thread.
  • +
  • It calls the comments.update method with comment in the request body to update a comment.
  • +
  • It calls the 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.
+ +### [Create and manage comment threads](/youtube/api-samples/blob/master/python/comment_threads.py) + +Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
+Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
+
    +
  • It calls the commentThreads.insert method once with the channelId parameter to create a +channel comment and once with the videoId parameter to create a video comment.
  • +
  • It calls the commentThreads.list method once with the channelId parameter to retrieve +channel comments and once with the videoId parameter to retrieve video comments.
  • +
  • It calls the 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.
  • +
+ +### [Create a broadcast](/youtube/api-samples/blob/master/python/create_broadcast.py) + +Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
+Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. + +### [Create a reporting job](/youtube/api-samples/blob/master/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. + +### [Search by geolocation](/youtube/api-samples/blob/master/python/geolocation_search.py) + +Method: youtube.search.list, youtube.videos.list
+Description: This sample calls the API's search.list method with 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. + +### [Like a video](/youtube/api-samples/blob/master/python/like_video.py) + +Method: youtube.videos.rate
+Description: This sample calls the API's videos.rate method to set a positive rating for a video. + +### [Retrieve a channel's broadcasts](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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 my uploads](/youtube/api-samples/blob/master/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. + +### [Set and retrieve localized metadata for a playlist](/youtube/api-samples/blob/master/python/playlist_localizations.py) + +Method: youtube.playlists.update, youtube.playlists.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a +playlist:
+
    +
  • It calls the 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.
  • +
  • It calls the playlists.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
  • +
  • It calls the playlists.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that playlist.
  • +
+ +### [Create a playlist](/youtube/api-samples/blob/master/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. + +### [Retrieve reports](/youtube/api-samples/blob/master/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. + +### [Search by keyword](/youtube/api-samples/blob/master/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. + +### [Upload a watermark image and set it for a channel](/youtube/api-samples/blob/master/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. + +### [Shuffle existing channel sections](/youtube/api-samples/blob/master/python/shuffle_channel_sections.py) + +Method: youtube.channelSections.list,youtube.channelSections.update
+Description: This sample calls the API's channelSections.list method to get the list of current channel +sections, shuffles them, and then calls channelSections.update to change the position of each.

+More information on channel sections is available in the +YouTube Help Center. + +### [Remove a watermark image from a channel](/youtube/api-samples/blob/master/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. + +### [Update a video](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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 channel's banner to this image. + +### [Upload a video thumbnail image](/youtube/api-samples/blob/master/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 video](/youtube/api-samples/blob/master/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. + +### [Set and retrieve localized metadata for a video](/youtube/api-samples/blob/master/python/video_localizations.py) + +Method: youtube.videos.update, youtube.videos.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata +for a video:
+
    +
  • It calls the 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.
  • +
  • It calls the videos.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
  • +
  • It calls the videos.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that video.
  • +
+ +### [Retrieve top 10 videos by viewcount](/youtube/api-samples/blob/master/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. From 42a6da64ec1c516ac87c65e7e5dd2a7744ea8c0a Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 09:08:34 -0500 Subject: [PATCH 008/126] Add README.md listing files in ruby directory --- ruby/README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 ruby/README.md diff --git a/ruby/README.md b/ruby/README.md new file mode 100644 index 00000000..fcc276f2 --- /dev/null +++ b/ruby/README.md @@ -0,0 +1,47 @@ +## Samples in this directory: + +### [Add a channel subscription](/youtube/api-samples/blob/master/ruby/add_subscription.rb) + +Method: youtube.subscriptions.insert
+Description: This sample calls the API's subscriptions.insert method to add a subscription +to a specified channel. + +### [Post a channel bulletin](/youtube/api-samples/blob/master/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. + +### [Upload a video](/youtube/api-samples/blob/master/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 my uploads](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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. + +### [Retrieve top 10 videos by viewcount](/youtube/api-samples/blob/master/ruby/yt_analytics_report.rb) + +Method: youtube.playlists.insert
+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. + +### [Authorize a request](/youtube/api-samples/blob/master/ruby/oauth/oauth_util.rb) + +Description: The following 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. From 7af4255d35e63e1aa09fe1b70c5607b51ca5b828 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 09:28:18 -0500 Subject: [PATCH 009/126] Add README.md listing samples in php directory --- php/README.md | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 php/README.md diff --git a/php/README.md b/php/README.md new file mode 100644 index 00000000..63e3116b --- /dev/null +++ b/php/README.md @@ -0,0 +1,225 @@ +## Samples in this directory: + +### [Add a channel section](/youtube/api-samples/blob/master/php/add_channel_section.php) + +Method: youtube.channelSections.insert
+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](/youtube/api-samples/blob/master/php/add_subscription.php) + +Method: youtube.subscriptions.insert
+Description: This sample calls the API's subscriptions.insert method to add a subscription to a specified +channel. + +### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/php/captions.php) + +Method: youtube.captions.insert, youtube.captions.list, youtube.captions.update, youtube.captions.download, +youtube.captions.delete
+Description: This sample demonstrates how to use the following API methods to create and manage YouTube video caption +tracks:
+

    +
  • It calls the captions.insert method with the isDraft parameter set to true +to upload a caption track in draft status.
  • +
  • It calls the captions.list method with the videoId parameter to retrieve video caption +tracks.
  • +
  • It calls the captions.update method with the caption in the request body to update a caption track.
  • +
  • It calls the captions.download method to download the caption track.
  • +
  • It calls the captions.delete method to delete the caption track, using the id parameter to +identify the caption track.
  • +
+ +### [Set and retrieve localized metadata for a channel](/youtube/api-samples/blob/master/php/channel_localizations.php) + +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:
+
    +
  • It calls the channels.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.
  • +
  • It calls the channels.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
  • +
  • It calls the channels.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that channel.
  • +
+ +### [Set and retrieve localized metadata for a channel section](/youtube/api-samples/blob/master/php/channel_section_localizations.php) + +Method: youtube.channelSections.update, youtube.channelSections.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a +channel section:
+
    +
  • It calls the 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.
  • +
  • It calls the channelSections.list method with the hl parameter set to a specific language +to retrieve localized metadata in that language.
  • +
  • It calls the channelSections.list method and includes localizations in the +part parameter value to retrieve all of the localized metadata for that channel section.
  • +
+ +### [Create and manage comments](/youtube/api-samples/blob/master/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.delete
+Description: The following code sample demonstrates how to use the following API methods to create and manage comments:
+
    +
  • It calls the commentThreads.list method with the videoId parameter set to retrieve comments +for a video.
  • +
  • It calls the comments.insert method with the parentId parameter set to reply to an existing +comment.
  • +
  • It calls the comments.list method with the parentId parameter to retrieve the comments in the +thread.
  • +
  • It calls the comments.update method with comment in the request body to update a comment.
  • +
  • It calls the 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.
  • +
+ +### [Create and manage comment threads](/youtube/api-samples/blob/master/php/comment_threads.php) + +Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
+Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
+
    +
  • It calls the commentThreads.insert method once with the channelId parameter to create a +channel comment and once with the videoId parameter to create a video comment.
  • +
  • It calls the commentThreads.list method once with the channelId parameter to retrieve +channel comments and once with the videoId parameter to retrieve video comments.
  • +
  • It calls the 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.
  • +
+ +### [Create a broadcast](/youtube/api-samples/blob/master/php/create_broadcast.php) + +Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
+Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. + +### [Create a reporting job](/youtube/api-samples/blob/master/php/create_reporting_job.php) + +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. + +### [Search by geolocation](/youtube/api-samples/blob/master/php/geolocation_search.php) + +Method: youtube.search.list, youtube.videos.list
+Description: This sample calls the API's search.list method with 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. + +### [Retrieve a channel's broadcasts](/youtube/api-samples/blob/master/php/list_broadcasts.php) + +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](/youtube/api-samples/blob/master/php/list_streams.php) + +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 my uploads](/youtube/api-samples/blob/master/php/my_uploads.php) + +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. + +### [Set and retrieve localized metadata for a playlist](/youtube/api-samples/blob/master/php/playlist_localizations.php) + +Method: youtube.playlists.update, youtube.playlists.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a +playlist:
+
    +
  • It calls the 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.
  • +
  • It calls the playlists.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
  • +
  • It calls the playlists.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that playlist.
  • +
+ +### [Create a playlist](/youtube/api-samples/blob/master/php/playlist_updates.php) + +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. + +### [Upload a video](/youtube/api-samples/blob/master/php/resumable_upload.php) + +Method: youtube.videos.insert
+Description: The following code sample calls the API's videos.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. + +### [Retrieve reports](/youtube/api-samples/blob/master/php/retrieve_reports.php) + +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. + +### [Search by keyword](/youtube/api-samples/blob/master/php/search.php) + +Method: youtube.search.list
+Description: This sample calls the API's search.list method to retrieve search results associated with +a particular keyword. + +### [Shuffle existing channel sections](/youtube/api-samples/blob/master/php/shuffle_channel_sections.php) + +Method: youtube.channelSections.list,youtube.channelSections.update
+Description: This sample calls the API's channelSections.list method to get the list of current channel +sections, shuffles them, and then calls channelSections.update to change the position of each.

+More information on channel sections is available in the +YouTube Help Center. + +### [Update a video](/youtube/api-samples/blob/master/php/update_video.php) + +Method: youtube.videos.update
+Description: This code sample demonstrates how to add tags into an existing video.

The following code +sample calls the API's 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](/youtube/api-samples/blob/master/php/upload_banner.php) + +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 channel's banner to this image. + +### [Upload a video thumbnail image](/youtube/api-samples/blob/master/php/upload_thumbnail.php) + +Method: youtube.thumbnails.set
+Description: This sample demonstrates how to upload a custom video thumbnail to YouTube and set it for a video. +It calls the API's youtube.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. + +### [Set and retrieve localized metadata for a video](/youtube/api-samples/blob/master/php/video_localizations.php) + +Method: youtube.videos.update, youtube.videos.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata +for a video:
+
    +
  • It calls the 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.
  • +
  • It calls the videos.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
  • +
  • It calls the videos.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that video.
  • +
From 2d57d1cb3254f2e6af3d6928d0f70e92636c5d3d Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 09:28:52 -0500 Subject: [PATCH 010/126] Delete topics.py since Freebase API is deprecated --- python/topics.py | 90 ------------------------------------------------ 1 file changed, 90 deletions(-) delete mode 100644 python/topics.py diff --git a/python/topics.py b/python/topics.py deleted file mode 100644 index 5bbfbfd7..00000000 --- a/python/topics.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/python - -from apiclient.discovery import build -from apiclient.errors import HttpError -from oauth2client.tools import argparser - -import json -import urllib - - -# Set DEVELOPER_KEY to the API key value from the APIs & auth > Registered apps -# tab of -# https://cloud.google.com/console -# Please ensure that you have enabled the YouTube Data API for your project. -DEVELOPER_KEY = "REPLACE_ME" -YOUTUBE_API_SERVICE_NAME = "youtube" -YOUTUBE_API_VERSION = "v3" -FREEBASE_SEARCH_URL = "https://www.googleapis.com/freebase/v1/search?%s" - -def get_topic_id(options): - # Retrieve a list of Freebase topics associated with the provided query term. - freebase_params = dict(query=options.query, key=DEVELOPER_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.") - - # Display the list of matching Freebase topics. - mids = [] - index = 1 - print "The following topics were found:" - for result in freebase_response["result"]: - mids.append(result["mid"]) - print " %2d. %s (%s)" % (index, result.get("name", "Unknown"), - result.get("notable", {}).get("name", "Unknown")) - index += 1 - - # Display a prompt for the user to select a topic and return the topic ID - # of the selected topic. - mid = None - while mid is None: - index = raw_input("Enter a topic number to find related YouTube %ss: " % - options.type) - try: - mid = mids[int(index) - 1] - except ValueError: - pass - return mid - - -def youtube_search(mid, options): - youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, - developerKey=DEVELOPER_KEY) - - # Call the search.list method to retrieve results associated with the - # specified Freebase topic. - search_response = youtube.search().list( - topicId=mid, - type=options.type, - part="id,snippet", - maxResults=options.max_results - ).execute() - - # Print the title and ID of each matching resource. - for search_result in search_response.get("items", []): - if search_result["id"]["kind"] == "youtube#video": - print "%s (%s)" % (search_result["snippet"]["title"], - search_result["id"]["videoId"]) - elif search_result["id"]["kind"] == "youtube#channel": - print "%s (%s)" % (search_result["snippet"]["title"], - search_result["id"]["channelId"]) - elif search_result["id"]["kind"] == "youtube#playlist": - print "%s (%s)" % (search_result["snippet"]["title"], - search_result["id"]["playlistId"]) - - -if __name__ == "__main__": - argparser.add_argument("--query", help="Freebase search term", default="Google") - argparser.add_argument("--max-results", help="Max YouTube results", - default=25) - argparser.add_argument("--type", - help="YouTube result type: video, playlist, or channel", default="channel") - args = argparser.parse_args() - - mid = get_topic_id(args) - try: - youtube_search(mid, args) - except HttpError, e: - print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content) From aa25f02c119c2653c75cf5c956cfa2b2f69bcf19 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 09:29:40 -0500 Subject: [PATCH 011/126] Delete sample since Freebase API is deprecated --- go/search_by_topic.go | 173 ------------------------------------------ 1 file changed, 173 deletions(-) delete mode 100644 go/search_by_topic.go 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 -} From 021f439684ea33b0bbdbdf1e220c848b6e6cc5c9 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 09:30:26 -0500 Subject: [PATCH 012/126] Delete Topics.java because Freebase API is deprecated --- .../samples/youtube/cmdline/data/Topics.java | 349 ------------------ 1 file changed, 349 deletions(-) delete mode 100644 java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Topics.java diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Topics.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Topics.java deleted file mode 100644 index c79d823a..00000000 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Topics.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (c) 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.api.services.samples.youtube.cmdline.data; - -import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpRequest; -import com.google.api.client.http.HttpRequestInitializer; -import com.google.api.services.samples.youtube.cmdline.Auth; -import com.google.api.services.youtube.YouTube; -import com.google.api.services.youtube.model.ResourceId; -import com.google.api.services.youtube.model.SearchListResponse; -import com.google.api.services.youtube.model.SearchResult; -import com.google.api.services.youtube.model.Thumbnail; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.codehaus.jackson.JsonNode; -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.node.ArrayNode; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * This application demonstrates a semantic YouTube search that prompts the - * user to enter a search term and select a topic related to that term. The - * class calls the Freebase API to get a topic ID, then passes that id along - * with another user query term to the YouTube APIs. The result is a list of - * videos based on a semantic search. - * - * @author Jeremy Walker - */ -public class Topics { - - /** - * Define a global variable that identifies the name of a file that - * contains the developer's API key. - */ - private static final String PROPERTIES_FILENAME = "youtube.properties"; - - /** - * Define a global variable that specifies the maximum number of videos - * that an API response can contain. - */ - private static final long NUMBER_OF_VIDEOS_RETURNED = 5; - - /** - * Define a global variable that specifies the maximum number of topics - * that an API response can contain. - */ - private static final long NUMBER_OF_TOPICS_RETURNED = 5; - - /** - * Define a global instance of a Youtube object, which will be used - * to make YouTube Data API requests. - */ - private static YouTube youtube; - - /** - * Execute a search request that starts by calling the Freebase API to - * retrieve a topic ID matching a user-provided term. Then initialize a - * YouTube object to search for YouTube videos and call the YouTube Data - * API's youtube.search.list method to retrieve a list of videos associated - * with the selected Freebase topic and with another search query term, - * which the user also enters. Finally, display the titles, video IDs, and - * thumbnail images for the first five videos in the YouTube Data API - * response. - * - * @param args This application does not use command line arguments. - */ - public static void main(String[] args) { - // Read the developer key from the properties file. - Properties properties = new Properties(); - try { - InputStream in = Topics.class.getResourceAsStream("/" + PROPERTIES_FILENAME); - properties.load(in); - - } catch (IOException e) { - System.err.println("There was an error reading " + PROPERTIES_FILENAME + ": " + e.getCause() - + " : " + e.getMessage()); - System.exit(1); - } - - - try { - // Retrieve a Freebase topic ID based on a user-entered query term. - String topicsId = getTopicId(); - if (topicsId.length() < 1) { - System.out.println("No topic id will be applied to your search."); - } - - // Prompt the user to enter a search query term. This term will be - // used to retrieve YouTube search results related to the topic - // selected above. - String queryTerm = getInputQuery("search"); - - // This object is used to make YouTube Data API requests. The last - // argument is required, but since we don't need anything - // initialized when the HttpRequest is initialized, we override - // the interface and provide a no-op function. - youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, new HttpRequestInitializer() { - public void initialize(HttpRequest request) throws IOException { - } - }) - .setApplicationName("youtube-cmdline-search-sample") - .build(); - - YouTube.Search.List search = youtube.search().list("id,snippet"); - - // Set your developer key from the {{ Google Cloud Console }} for - // non-authenticated requests. See: - // {{ https://cloud.google.com/console }} - String apiKey = properties.getProperty("youtube.apikey"); - search.setKey(apiKey); - search.setQ(queryTerm); - if (topicsId.length() > 0) { - search.setTopicId(topicsId); - } - - // Restrict the search results to only include videos. See: - // https://developers.google.com/youtube/v3/docs/search/list#type - search.setType("video"); - - // To increase efficiency, only retrieve the fields that the - // application uses. - search.setFields("items(id/kind,id/videoId,snippet/title,snippet/thumbnails/default/url)"); - search.setMaxResults(NUMBER_OF_VIDEOS_RETURNED); - SearchListResponse searchResponse = search.execute(); - - List searchResultList = searchResponse.getItems(); - - if (searchResultList != null) { - prettyPrint(searchResultList.iterator(), queryTerm, topicsId); - } else { - System.out.println("There were no results for your query."); - } - } catch (GoogleJsonResponseException e) { - System.err.println("There was a service error: " + e.getDetails().getCode() + - " : " + e.getDetails().getMessage()); - e.printStackTrace(); - } catch (IOException e) { - System.err.println("There was an IO error: " + e.getCause() + " : " + e.getMessage()); - e.printStackTrace(); - } - } - - /* - * Prompt the user to enter a search term and return the user's input. - * - * @param searchCategory This value is displayed to the user to clarify the information that the application is requesting. - */ - private static String getInputQuery(String searchCategory) throws IOException { - - String inputQuery = ""; - - BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in)); - - do { - System.out.print("Please enter a " + searchCategory + " term: "); - inputQuery = bReader.readLine(); - } while (inputQuery.length() < 1); - - return inputQuery; - } - - /** - * Retrieve Freebase topics that match a user-provided query term. Then - * prompt the user to select a topic and return its topic ID. - */ - private static String getTopicId() throws IOException { - - // The application will return an empty string if no matching topic ID - // is found or no results are available. - String topicsId = ""; - - // Prompt the user to enter a query term for finding Freebase topics. - String topicQuery = getInputQuery("topics"); - - // The Freebase Java library does not provide search functionality, so - // the application needs to call directly against the URL. This code - // constructs the proper URL, then uses jackson classes to convert the - // JSON response into a Java object. You can learn more about the - // Freebase search calls at: http://wiki.freebase.com/wiki/ApiSearch. - HttpClient httpclient = new DefaultHttpClient(); - List params = new ArrayList(); - params.add(new BasicNameValuePair("query", topicQuery)); - params.add(new BasicNameValuePair("limit", Long.toString(NUMBER_OF_TOPICS_RETURNED))); - - String serviceURL = "https://www.googleapis.com/freebase/v1/search"; - String url = serviceURL + "?" + URLEncodedUtils.format(params, "UTF-8"); - - HttpResponse httpResponse = httpclient.execute(new HttpGet(url)); - HttpEntity entity = httpResponse.getEntity(); - - if (entity != null) { - InputStream instream = entity.getContent(); - try { - - // Convert the JSON to an object. This code does not do an - // exact map from JSON to POJO (Plain Old Java object), but - // you could create additional classes and use them with the - // mapper.readValue() function to get that exact mapping. - ObjectMapper mapper = new ObjectMapper(); - JsonNode rootNode = mapper.readValue(instream, JsonNode.class); - - // Confirm that the HTTP request was handled successfully by - // checking the API response's HTTP response code. - if (rootNode.get("status").asText().equals("200 OK")) { - // In the API response, the "result" field contains the - // list of needed results. - ArrayNode arrayNodeResults = (ArrayNode) rootNode.get("result"); - // Prompt the user to select a topic from the list of API - // results. - topicsId = getUserChoice(arrayNodeResults); - } - } finally { - instream.close(); - } - } - return topicsId; - } - - /** - * Output results from the Freebase topic search to the user, prompt the - * user to select a topic, and return the appropriate topic ID. - * - * @param freebaseResults ArrayNode This object contains the search results. - */ - private static String getUserChoice(ArrayNode freebaseResults) throws IOException { - - String freebaseId = ""; - - if (freebaseResults.size() < 1) { - return freebaseId; - } - - // Print a list of topics retrieved from Freebase. - for (int i = 0; i < freebaseResults.size(); i++) { - JsonNode node = freebaseResults.get(i); - System.out.print(" " + i + " = " + node.get("name").asText()); - if (node.get("notable") != null) { - System.out.print(" (" + node.get("notable").get("name").asText() + ")"); - } - System.out.println(""); - } - - BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in)); - String inputChoice; - - // Prompt the user to select a topic. - do { - System.out.print("Choose the number of the Freebase Node: "); - inputChoice = bReader.readLine(); - } while (!isValidIntegerSelection(inputChoice, freebaseResults.size())); - - // Return the topic ID needed for the API request that retrieves - // YouTube search results. - JsonNode node = freebaseResults.get(Integer.parseInt(inputChoice)); - freebaseId = node.get("mid").asText(); - return freebaseId; - } - - /** - * Confirm that the string represents a valid, positive integer, that is - * less than or equal to 999,999,999. (Since the API will not return a - * billion results for a query, any integer that the user enters will need - * to be less than that to be valid, anyway.) - * - * @param input The string to test. - * @param max The integer must be less then this maximum number. - */ - public static boolean isValidIntegerSelection(String input, int max) { - if (input.length() > 9) - return false; - - boolean validNumber = false; - // Only accept positive numbers with a maximum of nine digits. - Pattern intsOnly = Pattern.compile("^\\d{1,9}$"); - Matcher makeMatch = intsOnly.matcher(input); - - if (makeMatch.find()) { - int number = Integer.parseInt(makeMatch.group()); - if ((number >= 0) && (number < max)) { - validNumber = true; - } - } - return validNumber; - } - - /* - * Prints out all results in the Iterator. For each result, print the - * title, video ID, and thumbnail. - * - * @param iteratorSearchResults Iterator of SearchResults to print - * @param query Search query (String) - */ - private static void prettyPrint(Iterator iteratorSearchResults, String query, String topicsId) { - - System.out.println("\n============================================================="); - System.out.println(" First " + NUMBER_OF_VIDEOS_RETURNED + " videos for search on \"" + query + "\" with Topics id: " + topicsId + "."); - System.out.println("=============================================================\n"); - - if (!iteratorSearchResults.hasNext()) { - System.out.println(" There aren't any results for your query."); - } - - while (iteratorSearchResults.hasNext()) { - - SearchResult singleVideo = iteratorSearchResults.next(); - ResourceId rId = singleVideo.getId(); - - // Confirm that the result represents a video. Otherwise, the - // item will not contain a video ID. - if (rId.getKind().equals("youtube#video")) { - Thumbnail thumbnail = singleVideo.getSnippet().getThumbnails().getDefault(); - - System.out.println(" Video Id" + rId.getVideoId()); - System.out.println(" Title: " + singleVideo.getSnippet().getTitle()); - System.out.println(" Thumbnail: " + thumbnail.getUrl()); - System.out.println("\n-------------------------------------------------------------\n"); - } - } - } -} From f89b2754040b5d2ce7a23e2d9e06af3aeb799ff2 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 10:10:40 -0500 Subject: [PATCH 013/126] Update and rename README to README.md Add descriptions of code samples. --- java/README | 21 ----- java/README.md | 236 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+), 21 deletions(-) delete mode 100644 java/README create mode 100644 java/README.md 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..fb35bd2e --- /dev/null +++ b/java/README.md @@ -0,0 +1,236 @@ +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 + +## Samples in this directory: + +### [Authorize a request](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/AddSubscription.java) + +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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/InvideoProgramming.java) + +Method: youtube.channels.update
+Description: This sample calls the API's channels.update method to set invideoPromotion +properties for the channel. + +### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Captions.java) + +Method: youtube.captions.insert, youtube.captions.list, youtube.captions.update, youtube.captions.download, +youtube.captions.delete
+Description: This sample demonstrates how to use the following API methods to create and manage YouTube video caption +tracks:
+
    +
  • It calls the captions.insert method with the isDraft parameter set to true +to upload a caption track in draft status.
  • +
  • It calls the captions.list method with the videoId parameter to retrieve video caption +tracks.
  • +
  • It calls the captions.update method with the caption in the request body to update a caption track.
  • +
  • It calls the captions.download method to download the caption track.
  • +
  • It calls the captions.delete method to delete the caption track, using the id parameter to +identify the caption track.
  • +
+ +### [Post a channel bulletin](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelBulletin.java) + +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. + +### [Set and retrieve localized metadata for a channel](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelLocalizations.java) + +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:
+
    +
  • It calls the channels.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.
  • +
  • It calls the channels.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
  • +
  • It calls the channels.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that channel.
  • +
+ +### [Set and retrieve localized metadata for a channel section](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelSectionLocalizations.java) + +Method: youtube.channelSections.update, youtube.channelSections.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a +channel section:
+
    +
  • It calls the 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.
  • +
  • It calls the channelSections.list method with the hl parameter set to a specific language +to retrieve localized metadata in that language.
  • +
  • It calls the channelSections.list method and includes localizations in the +part parameter value to retrieve all of the localized metadata for that channel section.
  • +
+ +### [Create and manage comments](/youtube/api-samples/blob/master/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.delete
+Description: This sample demonstrates how to use the following API methods to create and manage comments:
+
    +
  • It calls the commentThreads.list method with the videoId parameter set to retrieve comments +for a video.
  • +
  • It calls the comments.insert method with the parentId parameter set to reply to an existing +comment.
  • +
  • It calls the comments.list method with the parentId parameter to retrieve the comments in the +thread.
  • +
  • It calls the comments.update method with comment in the request body to update a comment.
  • +
  • It calls the 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.
+ +### [Create and manage comment threads](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentThreads.java) + +Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
+Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
+
    +
  • It calls the commentThreads.insert method once with the channelId parameter to create a +channel comment and once with the videoId parameter to create a video comment.
  • +
  • It calls the commentThreads.list method once with the channelId parameter to retrieve +channel comments and once with the videoId parameter to retrieve video comments.
  • +
  • It calls the 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.
  • +
+ +### [Search by geolocation](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/GeolocationSearch.java) + +Method: youtube.search.list, youtube.videos.list
+Description: This sample calls the API's search.list method with 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. + +### [Retrieve my uploads](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/MyUploads.java) + +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. + +### [Set and retrieve localized metadata for a playlist](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistLocalizations.java) + +Method: youtube.playlists.update, youtube.playlists.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a +playlist:
+
    +
  • It calls the 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.
  • +
  • It calls the playlists.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
  • +
  • It calls the playlists.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that playlist.
  • +
+ +### [Create a playlist](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistUpdates.java) + +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. + +### [Search by keyword](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Search.java) + +Method: youtube.search.list
+Description: This sample calls the API's search.list method to retrieve search results associated with +a particular keyword. + +### [Update a video](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UpdateVideo.java) + +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 video thumbnail image](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadThumbnail.java) + +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 video](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadVideo.java) + +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. + +### [Set and retrieve localized metadata for a video](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/VideoLocalizations.java) + +Method: youtube.videos.update, youtube.videos.list
+Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata +for a video:
+
    +
  • It calls the 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.
  • +
  • It calls the videos.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
  • +
  • It calls the videos.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that video.
  • +
+ +### [Retrieve top 10 videos by viewcount](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/analytics/YouTubeAnalyticsReports.java) + +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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/CreateReportingJob.java) + +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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/RetrieveReports.java) + +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. + +### [Create a broadcast](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/CreateBroadcast.java) + +Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
+Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. + +### [Retrieve a channel's broadcasts](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java) + +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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListStreams.java) + +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. From a982b3d84071d2f725afac3096d85da60b66b130 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 10:44:04 -0500 Subject: [PATCH 014/126] Create README.md listing samples in js directory --- javascript/README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 javascript/README.md diff --git a/javascript/README.md b/javascript/README.md new file mode 100644 index 00000000..cf911e76 --- /dev/null +++ b/javascript/README.md @@ -0,0 +1,52 @@ +## Samples in this directory: + +### [Authorize a request](/youtube/api-samples/blob/master/javascript/auth.js) + +Description: The auth.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.

+For requests that do not require authentication, you could also use the +key query parameter to specify an API key rather than using OAuth 2.0.

+Note: You need to update the client ID in the auth.js file. You can obtain your own +client ID by registering your application in the +Google Developers Console. + +### [Do resumable uploads with CORS](/youtube/api-samples/blob/master/javascript/cors_upload.js) + +Description: This code sample demonstrates how to execute a resumable upload using XHR/CORS. + +### [Upload a video](/youtube/api-samples/blob/master/javascript/upload_video.js) + +Method: youtube.videos.insert
+Description: This code sample calls the API's videos.insert method to upload a video to the channel +associated with the request. + +### [Retrieve my uploads](/youtube/api-samples/blob/master/javascript/my_uploads.js) + +Method: youtube.playlistItems.list
+Description: This 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](/youtube/api-samples/blob/master/javascript/search.js) + +Method: youtube.search.list
+Description: This code sample calls the API's search.list method to retrieve search results associated +with a particular keyword. + +### [Create a playlist](/youtube/api-samples/blob/master/javascript/playlist_updates.js) + +Method: youtube.playlists.insert
+Description: This sample creates a private playlist and add videos to it. (You could, of course, modify the code so +that it creates a publicly visible playlist or so that it checks a form value to determine whether the playlist is +public or private.) Note that you need to update the client ID in the auth.js file to run this code. + +### [Calling the Analytics API](/youtube/api-samples/blob/master/javascript/analytics_codelab.js) + +Method: youtubeAnalytics.reports.query
+Description: This sample uses the YouTube Data and YouTube Analytics APIs to retrieve YouTube channel metrics. +The samples use the Google APIs JavaScript client library +to demonstrate API functionality. The Building a Sample Application +document walks you through the steps of building this application and discusses different portions of this code in more +detail. From 946485c6995be53ad079eeff4d585d46e3f9dfbb Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 10:58:46 -0500 Subject: [PATCH 015/126] Remove sample not in directory --- dotnet/README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dotnet/README.md b/dotnet/README.md index e784a903..37157c63 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -25,9 +25,3 @@ associated with a particular keyword. 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 a content owner's managed channels](/youtube/api-samples/blob/master/dotnet/papi_my_managed_channels.cs) - -Method: youtube.channels.list -Description: The following code sample calls the YouTube Data API's channels.list method to retrieve a list -of channels managed by the content owner making the API request. From 337066acac4e50478069d4f554f3dd051435948b Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 11:00:24 -0500 Subject: [PATCH 016/126] Fix typo --- dotnet/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/README.md b/dotnet/README.md index 37157c63..35c5945c 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -6,7 +6,7 @@ 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. -### [Retrieve my uploads](/youtube/api-samples/blob/master/dotnet/MyUploads.go) +### [Retrieve my uploads](/youtube/api-samples/blob/master/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 From 194642b870414fa8e54e586e35358d0265216e69 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 11:04:06 -0500 Subject: [PATCH 017/126] Fix comment --- dotnet/MyUploads.cs | 2 -- 1 file changed, 2 deletions(-) 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; From 62a0cb98c0d36f8fd6c4fb4d3ed62758e5b34c35 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 11:04:28 -0500 Subject: [PATCH 018/126] Fix comment --- dotnet/PlaylistUpdates.cs | 2 -- 1 file changed, 2 deletions(-) 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; From f5dd6b3d496ad400d375e956f23a8b462ac8c072 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 11:04:48 -0500 Subject: [PATCH 019/126] Fix comment --- dotnet/Search.cs | 2 -- 1 file changed, 2 deletions(-) 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; From b957ed3809c6e4131bff62afea7875ab0cd7a3f6 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 11:05:04 -0500 Subject: [PATCH 020/126] Fix comment --- dotnet/UploadVideo.cs | 2 -- 1 file changed, 2 deletions(-) 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; From a45003072d1f5992259f6d4cd01be6dea563afd9 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 22 Nov 2016 11:45:39 -0500 Subject: [PATCH 021/126] Fix typos --- php/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/php/README.md b/php/README.md index 63e3116b..44e3488d 100644 --- a/php/README.md +++ b/php/README.md @@ -35,7 +35,7 @@ tracks. identify the caption track. -### [Set and retrieve localized metadata for a channel](/youtube/api-samples/blob/master/php/channel_localizations.php) +### [Set and retrieve localized channel metadata](/youtube/api-samples/blob/master/php/channel_localizations.php) 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 @@ -50,7 +50,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that channel. -### [Set and retrieve localized metadata for a channel section](/youtube/api-samples/blob/master/php/channel_section_localizations.php) +### [Set and retrieve localized channel section metadata](/youtube/api-samples/blob/master/php/channel_section_localizations.php) Method: youtube.channelSections.update, youtube.channelSections.list
Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -110,10 +110,10 @@ job. ### [Search by geolocation](/youtube/api-samples/blob/master/php/geolocation_search.php) Method: youtube.search.list, youtube.videos.list
-Description: This sample calls the API's search.list method with 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. +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. ### [Retrieve a channel's broadcasts](/youtube/api-samples/blob/master/php/list_broadcasts.php) @@ -136,7 +136,7 @@ to the channel associated with the request. The code also calls the channe mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded videos. -### [Set and retrieve localized metadata for a playlist](/youtube/api-samples/blob/master/php/playlist_localizations.php) +### [Set and retrieve localized playlist metadata](/youtube/api-samples/blob/master/php/playlist_localizations.php) Method: youtube.playlists.update, youtube.playlists.list
Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -198,9 +198,9 @@ to persist these changes on YouTube. 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 channel's banner to this image. +returned URL, the sample calls channels.update method to update the channel's banner to this image. -### [Upload a video thumbnail image](/youtube/api-samples/blob/master/php/upload_thumbnail.php) +### [Upload a custom video thumbnail image](/youtube/api-samples/blob/master/php/upload_thumbnail.php) Method: youtube.thumbnails.set
Description: This sample demonstrates how to upload a custom video thumbnail to YouTube and set it for a video. From 7c98eb937043553f145b337e744665a4c5243e0d Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Wed, 23 Nov 2016 11:48:01 -0500 Subject: [PATCH 022/126] Fix method name for YouTube Analytics sample --- ruby/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/README.md b/ruby/README.md index fcc276f2..aa75ba22 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -34,7 +34,7 @@ associated with a particular keyword. ### [Retrieve top 10 videos by viewcount](/youtube/api-samples/blob/master/ruby/yt_analytics_report.rb) -Method: youtube.playlists.insert
+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 From c74bbf5dc8fc4df0970f23d00b687f1d064d078d Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Wed, 23 Nov 2016 12:07:03 -0500 Subject: [PATCH 023/126] Fix typos --- python/README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/python/README.md b/python/README.md index 5ef166c7..cb72fe84 100644 --- a/python/README.md +++ b/python/README.md @@ -47,7 +47,7 @@ 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. -### [Set and retrieve localized metadata for a channel](/youtube/api-samples/blob/master/python/channel_localizations.py) +### [Set and retrieve localized channel metadata](/youtube/api-samples/blob/master/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 @@ -62,7 +62,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that channel. -### [Set and retrieve localized metadata for a channel section](/youtube/api-samples/blob/master/python/channel_section_localizations.py) +### [Set and retrieve localized channel section metadata](/youtube/api-samples/blob/master/python/channel_section_localizations.py) Method: youtube.channelSections.update, youtube.channelSections.list
Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -80,7 +80,7 @@ to retrieve localized metadata in that language. Method: youtube.commentThreads.list, youtube.comments.insert, youtube.comments.list, youtube.comments.update, youtube.comments.setModerationStatus, youtube.comments.markAsSpam, youtube.comments.delete
-Description: The following code sample demonstrates how to use the following API methods to create and manage comments:
+Description: This sample demonstrates how to use the following API methods to create and manage comments:
  • It calls the commentThreads.list method with the videoId parameter set to retrieve comments for a video.
  • @@ -121,10 +121,11 @@ job. ### [Search by geolocation](/youtube/api-samples/blob/master/python/geolocation_search.py) Method: youtube.search.list, youtube.videos.list
    -Description: This sample calls the API's search.list method with 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. +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. ### [Like a video](/youtube/api-samples/blob/master/python/like_video.py) @@ -152,7 +153,7 @@ to the channel associated with the request. The code also calls the channe mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded videos. -### [Set and retrieve localized metadata for a playlist](/youtube/api-samples/blob/master/python/playlist_localizations.py) +### [Set and retrieve localized playlist metadata](/youtube/api-samples/blob/master/python/playlist_localizations.py) Method: youtube.playlists.update, youtube.playlists.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -196,7 +197,7 @@ watermark image for a channel. The request must be authorized by the channel tha Method: youtube.channelSections.list,youtube.channelSections.update
    Description: This sample calls the API's channelSections.list method to get the list of current channel -sections, shuffles them, and then calls channelSections.update to change the position of each.

    +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. @@ -216,7 +217,7 @@ authorizing the request. 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 channel's banner to this image. +returned URL, the sample calls channels.update method to update the channel's banner to that image. ### [Upload a video thumbnail image](/youtube/api-samples/blob/master/python/upload_thumbnail.py) @@ -230,7 +231,7 @@ 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. -### [Set and retrieve localized metadata for a video](/youtube/api-samples/blob/master/python/video_localizations.py) +### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/python/video_localizations.py) Method: youtube.videos.update, youtube.videos.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata From 2b3494999967701b6feb65fc4e309cd9143293d6 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Wed, 23 Nov 2016 12:17:52 -0500 Subject: [PATCH 024/126] Fix typos --- java/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/java/README.md b/java/README.md index fb35bd2e..288ccea3 100644 --- a/java/README.md +++ b/java/README.md @@ -61,7 +61,7 @@ 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. -### [Set and retrieve localized metadata for a channel](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelLocalizations.java) +### [Set and retrieve localized channel metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelLocalizations.java) 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 @@ -76,7 +76,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that channel.
-### [Set and retrieve localized metadata for a channel section](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelSectionLocalizations.java) +### [Set and retrieve localized channel section metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelSectionLocalizations.java) Method: youtube.channelSections.update, youtube.channelSections.list
Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -123,9 +123,9 @@ channel comment. In each case, the request body contains the comment -Description: This sample calls the API's search.list method with q, location and +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 +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. ### [Retrieve my uploads](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/MyUploads.java) @@ -136,7 +136,7 @@ to the channel associated with the request. The code also calls the channe mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded videos. -### [Set and retrieve localized metadata for a playlist](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistLocalizations.java) +### [Set and retrieve localized playlist metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistLocalizations.java) Method: youtube.playlists.update, youtube.playlists.list
Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -168,7 +168,7 @@ 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 video thumbnail image](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadThumbnail.java) +### [Upload a custom video thumbnail image](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadThumbnail.java) Method: youtube.thumbnails.set
Description: This sample calls the API's thumbnails.set method to upload an image and set it as the @@ -180,7 +180,7 @@ 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. -### [Set and retrieve localized metadata for a video](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/VideoLocalizations.java) +### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/VideoLocalizations.java) Method: youtube.videos.update, youtube.videos.list
Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata From 0ac71e3f60ae61c3cfeff3de30414b18dd02a50f Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Wed, 23 Nov 2016 15:19:43 -0500 Subject: [PATCH 025/126] Add description of upload_video.html --- javascript/README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/javascript/README.md b/javascript/README.md index cf911e76..239800f6 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -18,8 +18,18 @@ Description: This code sample demonstrates how to execute a resumable upload usi ### [Upload a video](/youtube/api-samples/blob/master/javascript/upload_video.js) Method: youtube.videos.insert
-Description: This code sample calls the API's videos.insert method to upload a video to the channel -associated with the request. +Description: This JavaScript sample performs the following functions:
+
    +
  1. It retrieves the channel name and thumbnail of the authenticated user's channel using the API's channels.list method.
  2. +
  3. It handles the video upload to YouTube using the resumable upload protocol.
  4. +
  5. It polls for the uploaded video's upload and processing status using the API's videos.list method by setting the part parameter value to status.
  6. +

+ +The HTML page uses JQuery, the plusone.js and upload_video.js JavaScript files, and the +upload_video.css file to upload a video file to YouTube.

Note that if you use this code in your own application, you must replace the value of the 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. ### [Retrieve my uploads](/youtube/api-samples/blob/master/javascript/my_uploads.js) From 2329115a799d290695be42d4860501d253dbe828 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Wed, 23 Nov 2016 15:31:23 -0500 Subject: [PATCH 026/126] Add descriptions of remaining HTML files --- javascript/README.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/javascript/README.md b/javascript/README.md index 239800f6..5d6525a6 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -23,9 +23,9 @@ Description: This JavaScript sample performs the following functions:
  • It retrieves the channel name and thumbnail of the authenticated user's channel using the API's channels.list method.
  • It handles the video upload to YouTube using the resumable upload protocol.
  • It polls for the uploaded video's upload and processing status using the API's videos.list method by setting the part parameter value to status.
  • -
    + -The HTML page uses JQuery, the plusone.js and upload_video.js JavaScript files, and the +The HTML page uses JQuery, the cors_upload.js and upload_video.js JavaScript files, and the upload_video.css file to upload a video file to YouTube.

    Note that if you use this code in your own application, you must replace the value of the 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 @@ -34,24 +34,31 @@ production application. ### [Retrieve my uploads](/youtube/api-samples/blob/master/javascript/my_uploads.js) Method: youtube.playlistItems.list
    -Description: This 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. +Description: The JavaScript sample code performs the following functions:
    +
      +
    1. It retrieves the playlist ID for videos uploaded to the user's channel using the API's channels.list method. This API call also sets the mine parameter to true to retrieve channel information for the authorizing user.
    2. +
    3. It passes that ID to the playlistItems.list method to retrieve the videos in that list.
    4. +
    5. It displays the list of videos.
    6. +
    7. It constructs next and previous page buttons and sets their visibility based on the information in the API response.
    8. +
    + +The HTML page below uses JQuery, the auth.js and my_uploads.js JavaScript files, and a CSS file to display the list of uploaded videos. ### [Search by keyword](/youtube/api-samples/blob/master/javascript/search.js) Method: youtube.search.list
    Description: This code sample calls the API's search.list method to retrieve search results associated -with a particular keyword. +with a particular keyword. The HTML page below 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. ### [Create a playlist](/youtube/api-samples/blob/master/javascript/playlist_updates.js) Method: youtube.playlists.insert
    -Description: This sample creates a private playlist and add videos to it. (You could, of course, modify the code so -that it creates a publicly visible playlist or so that it checks a form value to determine whether the playlist is +Description: This JavaScript code creates a private playlist and adds videos to that playlist. (You could, of course, modify the code so that it creates a publicly visible playlist or so that it checks a form value to determine whether the playlist is public or private.) Note that you need to update the client ID in the auth.js file to run this code. +The HTML page below uses JQuery, along with the auth.js and playlist_updates.js JavaScript files, to display a simple form for adding videos to the playlist. + ### [Calling the Analytics API](/youtube/api-samples/blob/master/javascript/analytics_codelab.js) Method: youtubeAnalytics.reports.query
    From 269d94124525ac50020fd5e46766c858ff1f3f36 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Wed, 23 Nov 2016 15:34:48 -0500 Subject: [PATCH 027/126] Fix formatting, typos --- javascript/README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/javascript/README.md b/javascript/README.md index 5d6525a6..5c34dc98 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -42,22 +42,19 @@ Description: The JavaScript sample code performs the following functions:
  • It constructs next and previous page buttons and sets their visibility based on the information in the API response.
  • -The HTML page below uses JQuery, the auth.js and my_uploads.js JavaScript files, and a CSS file to display the list of uploaded videos. +The HTML page uses JQuery, the auth.js and my_uploads.js JavaScript files, and a CSS file to display the list of uploaded videos. ### [Search by keyword](/youtube/api-samples/blob/master/javascript/search.js) Method: youtube.search.list
    Description: This code sample calls the API's search.list method to retrieve search results associated -with a particular keyword. The HTML page below 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. +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. ### [Create a playlist](/youtube/api-samples/blob/master/javascript/playlist_updates.js) Method: youtube.playlists.insert
    Description: This JavaScript code creates a private playlist and adds videos to that playlist. (You could, of course, modify the code so that it creates a publicly visible playlist or so that it checks a form value to determine whether the playlist is -public or private.) Note that you need to update the client ID in the auth.js file to run this code. - -The HTML page below uses JQuery, along with the auth.js and playlist_updates.js JavaScript files, to display a simple form for adding videos to the playlist. +public or private.) Note that you need to update the client ID in the auth.js file to run this code.

    The HTML page uses JQuery, along with the auth.js and playlist_updates.js JavaScript files, to display a simple form for adding videos to the playlist. ### [Calling the Analytics API](/youtube/api-samples/blob/master/javascript/analytics_codelab.js) From 444d263457f428df4a5f965f5c3f78176331c9a6 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 14:40:27 -0500 Subject: [PATCH 028/126] Create README.md listing samples in directory --- python_appengine/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 python_appengine/README.md diff --git a/python_appengine/README.md b/python_appengine/README.md new file mode 100644 index 00000000..ba26b8f7 --- /dev/null +++ b/python_appengine/README.md @@ -0,0 +1,14 @@ +## Samples in this directory: + +### [Retrieve a channel's uploads](/youtube/api-samples/blob/master/python_appengine/user_uploads/main.py) + +Method: youtube.playlistItems.list +Description: This code sample calls the API's 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](/youtube/api-samples/blob/master/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. From 48ad7270d0367687ba21d11e3810fd97b85d08a8 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 14:41:58 -0500 Subject: [PATCH 029/126] Deleting sample, which shows deprecated features --- python_appengine/topics/main.py | 108 -------------------------------- 1 file changed, 108 deletions(-) delete mode 100644 python_appengine/topics/main.py 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 = (''' - - -

    The following topics were found:

    -
    - -

    -
    - - - ''' - - # Display the HTML page listing the topic choices. - self.response.out.write(select_topic_page) - - def post(self): - topic_id = self.request.get('topic') - - # Service for calling the YouTube API - youtube = build(YOUTUBE_API_SERVICE_NAME, - YOUTUBE_API_VERSION, - developerKey=API_KEY) - - # Execute the search request using default query term and retrieved topic. - search_response = youtube.search().list( - part = 'id,snippet', - type = 'video', - topicId = topic_id - ).execute() - - videos = [] - - for search_result in search_response.get("items", []): - videos.append(search_result) - - template_values = { - 'videos': videos - } - - self.response.headers['Content-type'] = 'text/html' - template = JINJA_ENVIRONMENT.get_template('index.html') - self.response.write(template.render(template_values)) - -app = webapp2.WSGIApplication([ - ('/.*', MainHandler), -], debug=True) From 8a125cf99c6c4939b22ca2fcc14b8d5fd0ee30f7 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 14:42:10 -0500 Subject: [PATCH 030/126] Deleting sample, which shows deprecated features --- python_appengine/topics/index.html | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 python_appengine/topics/index.html diff --git a/python_appengine/topics/index.html b/python_appengine/topics/index.html deleted file mode 100644 index 62be2374..00000000 --- a/python_appengine/topics/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - -

    Videos:

    - {% for video in videos %} - -

    - {% endfor %} - - From 737303860c83166c95bf1ba4370853de2fe6347c Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 14:42:19 -0500 Subject: [PATCH 031/126] Deleting sample, which shows deprecated features --- python_appengine/topics/app.yaml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 python_appengine/topics/app.yaml diff --git a/python_appengine/topics/app.yaml b/python_appengine/topics/app.yaml deleted file mode 100644 index 6ccfdcc6..00000000 --- a/python_appengine/topics/app.yaml +++ /dev/null @@ -1,23 +0,0 @@ -application: your-app-id -version: 1 -runtime: python27 -api_version: 1 -threadsafe: yes - -handlers: -- url: /favicon\.ico - static_files: favicon.ico - upload: favicon\.ico - -- url: /favicon\.ico - static_files: favicon.ico - upload: favicon\.ico - -- url: /.* - script: main.app - -libraries: -- name: webapp2 - version: "2.5.2" -- name: jinja2 - version: latest From 5851a4a0406ec53cfe3858722d8a0530943e1b8c Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 14:46:33 -0500 Subject: [PATCH 032/126] Correct formatting --- python_appengine/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_appengine/README.md b/python_appengine/README.md index ba26b8f7..11663edc 100644 --- a/python_appengine/README.md +++ b/python_appengine/README.md @@ -10,5 +10,5 @@ to a specified channel. The channel can be identified by its channel ID or chann ### [Search by keyword](/youtube/api-samples/blob/master/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 +Description: This code sample calls the API's search.list method to retrieve search results associated with a particular keyword. From 7c8ed9aaee07cdcaf5938e681400c7d78beeed46 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 14:57:17 -0500 Subject: [PATCH 033/126] Remove sample showing deprecated feature --- apps-script/youtube.gs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/apps-script/youtube.gs b/apps-script/youtube.gs index d4b55344..8130706f 100644 --- a/apps-script/youtube.gs +++ b/apps-script/youtube.gs @@ -1,25 +1,3 @@ -// 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 From 47772c01b17b8740b3c2ba9bde02486f51d35a78 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 15:27:34 -0500 Subject: [PATCH 034/126] Move title, method names to main function comments --- apps-script/youtube.gs | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/apps-script/youtube.gs b/apps-script/youtube.gs index 8130706f..cf812534 100644 --- a/apps-script/youtube.gs +++ b/apps-script/youtube.gs @@ -1,7 +1,6 @@ -// 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. * @@ -19,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 @@ -71,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. */ @@ -111,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. */ @@ -143,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. */ @@ -172,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. From 41c51b15df705d18b3e5b18b4a28dee41df2a883 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 16:21:26 -0500 Subject: [PATCH 035/126] Alphabetize samples by title --- python/README.md | 256 +++++++++++++++++++++++------------------------ 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/python/README.md b/python/README.md index cb72fe84..a14fbab2 100644 --- a/python/README.md +++ b/python/README.md @@ -9,20 +9,56 @@ 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 +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](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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. -### [Add a channel subscription](/youtube/api-samples/blob/master/python/add_subscription.py) +### [Create a playlist](/youtube/api-samples/blob/master/python/playlist_updates.py) -Method: youtube.subscriptions.insert
    -Description: This sample calls the API's subscriptions.insert method to add a subscription to a specified -channel. +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](/youtube/api-samples/blob/master/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:
    +

      +
    • It calls the commentThreads.list method with the videoId parameter set to retrieve comments +for a video.
    • +
    • It calls the comments.insert method with the parentId parameter set to reply to an existing +comment.
    • +
    • It calls the comments.list method with the parentId parameter to retrieve the comments in the +thread.
    • +
    • It calls the comments.update method with comment in the request body to update a comment.
    • +
    • It calls the 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.
    + +### [Create and manage comment threads](/youtube/api-samples/blob/master/python/comment_threads.py) + +Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
    +Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
    +
      +
    • It calls the commentThreads.insert method once with the channelId parameter to create a +channel comment and once with the videoId parameter to create a video comment.
    • +
    • It calls the commentThreads.list method once with the channelId parameter to retrieve +channel comments and once with the videoId parameter to retrieve video comments.
    • +
    • It calls the 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.
    • +
    ### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/python/captions.py) @@ -41,12 +77,46 @@ tracks. identify the caption track. +### [Like a video](/youtube/api-samples/blob/master/python/like_video.py) + +Method: youtube.videos.rate
    +Description: This sample calls the API's videos.rate method to set a positive rating for a video. + ### [Post a channel bulletin](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/python/channel_localizations.py) Method: youtube.channels.update, youtube.channels.list
    @@ -76,83 +146,6 @@ to retrieve localized metadata in that language. part parameter value to retrieve all of the localized metadata for that channel section. -### [Create and manage comments](/youtube/api-samples/blob/master/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:
    -
      -
    • It calls the commentThreads.list method with the videoId parameter set to retrieve comments -for a video.
    • -
    • It calls the comments.insert method with the parentId parameter set to reply to an existing -comment.
    • -
    • It calls the comments.list method with the parentId parameter to retrieve the comments in the -thread.
    • -
    • It calls the comments.update method with comment in the request body to update a comment.
    • -
    • It calls the 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.
    - -### [Create and manage comment threads](/youtube/api-samples/blob/master/python/comment_threads.py) - -Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
    -Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
    -
      -
    • It calls the commentThreads.insert method once with the channelId parameter to create a -channel comment and once with the videoId parameter to create a video comment.
    • -
    • It calls the commentThreads.list method once with the channelId parameter to retrieve -channel comments and once with the videoId parameter to retrieve video comments.
    • -
    • It calls the 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.
    • -
    - -### [Create a broadcast](/youtube/api-samples/blob/master/python/create_broadcast.py) - -Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    -Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. - -### [Create a reporting job](/youtube/api-samples/blob/master/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. - -### [Search by geolocation](/youtube/api-samples/blob/master/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. - -### [Like a video](/youtube/api-samples/blob/master/python/like_video.py) - -Method: youtube.videos.rate
    -Description: This sample calls the API's videos.rate method to set a positive rating for a video. - -### [Retrieve a channel's broadcasts](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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 my uploads](/youtube/api-samples/blob/master/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. - ### [Set and retrieve localized playlist metadata](/youtube/api-samples/blob/master/python/playlist_localizations.py) Method: youtube.playlists.update, youtube.playlists.list
    @@ -167,31 +160,19 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that playlist. -### [Create a playlist](/youtube/api-samples/blob/master/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. - -### [Retrieve reports](/youtube/api-samples/blob/master/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. - -### [Search by keyword](/youtube/api-samples/blob/master/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. - -### [Upload a watermark image and set it for a channel](/youtube/api-samples/blob/master/python/set_watermark.py) +### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/python/video_localizations.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. +Method: youtube.videos.update, youtube.videos.list
    +Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata +for a video:
    +
      +
    • It calls the 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.
    • +
    • It calls the videos.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
    • +
    • It calls the videos.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that video.
    • +
    ### [Shuffle existing channel sections](/youtube/api-samples/blob/master/python/shuffle_channel_sections.py) @@ -201,12 +182,6 @@ sections. Then it shuffles the list and calls channelSections.updateYouTube Help Center. -### [Remove a watermark image from a channel](/youtube/api-samples/blob/master/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. - ### [Update a video](/youtube/api-samples/blob/master/python/update_video.py) Method: youtube.videos.update
    @@ -219,31 +194,41 @@ 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](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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 video](/youtube/api-samples/blob/master/python/upload_video.py) +### [Upload a watermark image and set it for a channel](/youtube/api-samples/blob/master/python/set_watermark.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. +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. -### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/python/video_localizations.py) +### [Create a broadcast](/youtube/api-samples/blob/master/python/create_broadcast.py) -Method: youtube.videos.update, youtube.videos.list
    -Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata -for a video:
    -
      -
    • It calls the 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.
    • -
    • It calls the videos.list method with the hl parameter set to a specific language to -retrieve localized metadata in that language.
    • -
    • It calls the videos.list method and includes localizations in the part -parameter value to retrieve all of the localized metadata for that video.
    • -
    +Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    +Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. + +### [Retrieve a channel's broadcasts](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/python/yt_analytics_report.py) @@ -252,3 +237,18 @@ Description: This sample calls the API's reports.query method to re 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](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/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. From febf747d1e13f1ea67cbccbbbfd6ce76a9fe6c51 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 16:24:32 -0500 Subject: [PATCH 036/126] Alphabetize samples by title --- dotnet/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dotnet/README.md b/dotnet/README.md index 35c5945c..33152d0c 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -1,10 +1,10 @@ ## Samples in this directory: -### [Upload a video](/youtube/api-samples/blob/master/dotnet/UploadVideo.cs) +### [Create a playlist](/youtube/api-samples/blob/master/dotnet/PlaylistUpdates.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. +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](/youtube/api-samples/blob/master/dotnet/MyUploads.cs) @@ -20,8 +20,8 @@ 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. -### [Create a playlist](/youtube/api-samples/blob/master/dotnet/PlaylistUpdates.cs) +### [Upload a video](/youtube/api-samples/blob/master/dotnet/UploadVideo.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. +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. From 443723cbe390e35b2630be76ac5820ee0e847f2f Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 16:25:24 -0500 Subject: [PATCH 037/126] Alphabetize samples by title --- go/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/go/README.md b/go/README.md index dfe80f12..a0432c54 100644 --- a/go/README.md +++ b/go/README.md @@ -42,11 +42,11 @@ Description: This code sample performs OAuth 2.0 authorization by checking for t 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. -### [Upload a video](/youtube/api-samples/blob/master/go/upload_video.go) +### [Post a channel bulletin](/youtube/api-samples/blob/master/go/post_bulletin.go) -Method: youtube.videos.insert
    -Description: This code sample calls the API's videos.insert method to upload a video to the channel -associated with the request. +Method: youtube.activities.insert
    +Description: This code sample calls the API's activities.insert method to post a bulletin to the +channel associated with the request. ### [Retrieve my uploads](/youtube/api-samples/blob/master/go/my_uploads.go) @@ -62,8 +62,8 @@ Method: youtube.search.list
    Description: This code sample calls the API's search.list method to retrieve search results associated with a particular keyword. -### [Post a channel bulletin](/youtube/api-samples/blob/master/go/post_bulletin.go) +### [Upload a video](/youtube/api-samples/blob/master/go/upload_video.go) -Method: youtube.activities.insert
    -Description: This code sample calls the API's activities.insert method to post a bulletin to the -channel associated with the request. +Method: youtube.videos.insert
    +Description: This code sample calls the API's videos.insert method to upload a video to the channel +associated with the request. From 5964ca761dd6098bcf352828bde53bba089480cf Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 16:28:00 -0500 Subject: [PATCH 038/126] Alphabetize samples by title Example for authorizing requests is still first since it applies to almost all other examples in the directory. --- java/README.md | 140 ++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/java/README.md b/java/README.md index 288ccea3..f37d0fa3 100644 --- a/java/README.md +++ b/java/README.md @@ -38,6 +38,42 @@ Method: youtube.channels.update
    Description: This sample calls the API's channels.update method to set invideoPromotion properties for the channel. +### [Create a playlist](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistUpdates.java) + +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](/youtube/api-samples/blob/master/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.delete
    +Description: This sample demonstrates how to use the following API methods to create and manage comments:
    +
      +
    • It calls the commentThreads.list method with the videoId parameter set to retrieve comments +for a video.
    • +
    • It calls the comments.insert method with the parentId parameter set to reply to an existing +comment.
    • +
    • It calls the comments.list method with the parentId parameter to retrieve the comments in the +thread.
    • +
    • It calls the comments.update method with comment in the request body to update a comment.
    • +
    • It calls the 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.
    + +### [Create and manage comment threads](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentThreads.java) + +Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
    +Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
    +
      +
    • It calls the commentThreads.insert method once with the channelId parameter to create a +channel comment and once with the videoId parameter to create a video comment.
    • +
    • It calls the commentThreads.list method once with the channelId parameter to retrieve +channel comments and once with the videoId parameter to retrieve video comments.
    • +
    • It calls the 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.
    • +
    + ### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Captions.java) Method: youtube.captions.insert, youtube.captions.list, youtube.captions.update, youtube.captions.download, @@ -61,6 +97,28 @@ 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/MyUploads.java) + +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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Search.java) + +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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/GeolocationSearch.java) + +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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelLocalizations.java) Method: youtube.channels.update, youtube.channels.list
    @@ -90,52 +148,6 @@ to retrieve localized metadata in that language. part parameter value to retrieve all of the localized metadata for that channel section. -### [Create and manage comments](/youtube/api-samples/blob/master/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.delete
    -Description: This sample demonstrates how to use the following API methods to create and manage comments:
    -
      -
    • It calls the commentThreads.list method with the videoId parameter set to retrieve comments -for a video.
    • -
    • It calls the comments.insert method with the parentId parameter set to reply to an existing -comment.
    • -
    • It calls the comments.list method with the parentId parameter to retrieve the comments in the -thread.
    • -
    • It calls the comments.update method with comment in the request body to update a comment.
    • -
    • It calls the 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.
    - -### [Create and manage comment threads](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentThreads.java) - -Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
    -Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
    -
      -
    • It calls the commentThreads.insert method once with the channelId parameter to create a -channel comment and once with the videoId parameter to create a video comment.
    • -
    • It calls the commentThreads.list method once with the channelId parameter to retrieve -channel comments and once with the videoId parameter to retrieve video comments.
    • -
    • It calls the 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.
    • -
    - -### [Search by geolocation](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/GeolocationSearch.java) - -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. - -### [Retrieve my uploads](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/MyUploads.java) - -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. - ### [Set and retrieve localized playlist metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistLocalizations.java) Method: youtube.playlists.update, youtube.playlists.list
    @@ -150,17 +162,19 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that playlist. -### [Create a playlist](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistUpdates.java) - -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. - -### [Search by keyword](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Search.java) +### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/VideoLocalizations.java) -Method: youtube.search.list
    -Description: This sample calls the API's search.list method to retrieve search results associated with -a particular keyword. +Method: youtube.videos.update, youtube.videos.list
    +Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata +for a video:
    +
      +
    • It calls the 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.
    • +
    • It calls the videos.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
    • +
    • It calls the videos.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that video.
    • +
    ### [Update a video](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UpdateVideo.java) @@ -180,20 +194,6 @@ 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. -### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/VideoLocalizations.java) - -Method: youtube.videos.update, youtube.videos.list
    -Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata -for a video:
    -
      -
    • It calls the 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.
    • -
    • It calls the videos.list method with the hl parameter set to a specific language to -retrieve localized metadata in that language.
    • -
    • It calls the videos.list method and includes localizations in the part -parameter value to retrieve all of the localized metadata for that video.
    • -
    - ### [Retrieve top 10 videos by viewcount](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/analytics/YouTubeAnalyticsReports.java) Method: youtubeAnalytics.reports.query
    From 3575c690b90080dcb4567ac1564403e6c59f6548 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 16:28:55 -0500 Subject: [PATCH 039/126] Alphabetize method-specific samples by title --- javascript/README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/javascript/README.md b/javascript/README.md index 5c34dc98..31226753 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -15,21 +15,11 @@ client ID by registering your application in the Description: This code sample demonstrates how to execute a resumable upload using XHR/CORS. -### [Upload a video](/youtube/api-samples/blob/master/javascript/upload_video.js) - -Method: youtube.videos.insert
    -Description: This JavaScript sample performs the following functions:
    -
      -
    1. It retrieves the channel name and thumbnail of the authenticated user's channel using the API's channels.list method.
    2. -
    3. It handles the video upload to YouTube using the resumable upload protocol.
    4. -
    5. It polls for the uploaded video's upload and processing status using the API's videos.list method by setting the part parameter value to status.
    6. -
    +### [Create a playlist](/youtube/api-samples/blob/master/javascript/playlist_updates.js) -The HTML page uses JQuery, the cors_upload.js and upload_video.js JavaScript files, and the -upload_video.css file to upload a video file to YouTube.

    Note that if you use this code in your own application, you must replace the value of the 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. +Method: youtube.playlists.insert
    +Description: This JavaScript code creates a private playlist and adds videos to that playlist. (You could, of course, modify the code so that it creates a publicly visible playlist or so that it checks a form value to determine whether the playlist is +public or private.) Note that you need to update the client ID in the auth.js file to run this code.

    The HTML page uses JQuery, along with the auth.js and playlist_updates.js JavaScript files, to display a simple form for adding videos to the playlist. ### [Retrieve my uploads](/youtube/api-samples/blob/master/javascript/my_uploads.js) @@ -50,11 +40,21 @@ Method: youtube.search.list
    Description: This code sample calls the API's search.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. -### [Create a playlist](/youtube/api-samples/blob/master/javascript/playlist_updates.js) +### [Upload a video](/youtube/api-samples/blob/master/javascript/upload_video.js) -Method: youtube.playlists.insert
    -Description: This JavaScript code creates a private playlist and adds videos to that playlist. (You could, of course, modify the code so that it creates a publicly visible playlist or so that it checks a form value to determine whether the playlist is -public or private.) Note that you need to update the client ID in the auth.js file to run this code.

    The HTML page uses JQuery, along with the auth.js and playlist_updates.js JavaScript files, to display a simple form for adding videos to the playlist. +Method: youtube.videos.insert
    +Description: This JavaScript sample performs the following functions:
    +
      +
    1. It retrieves the channel name and thumbnail of the authenticated user's channel using the API's channels.list method.
    2. +
    3. It handles the video upload to YouTube using the resumable upload protocol.
    4. +
    5. It polls for the uploaded video's upload and processing status using the API's videos.list method by setting the part parameter value to status.
    6. +
    + +The HTML page uses JQuery, the cors_upload.js and upload_video.js JavaScript files, and the +upload_video.css file to upload a video file to YouTube.

    Note that if you use this code in your own application, you must replace the value of the 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](/youtube/api-samples/blob/master/javascript/analytics_codelab.js) From 3606b7f08f739d8fe4dfa305ccb4542674a108d0 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 16:33:51 -0500 Subject: [PATCH 040/126] Alphabetize samples by title --- php/README.md | 216 +++++++++++++++++++++++++------------------------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/php/README.md b/php/README.md index 44e3488d..6dfc54c8 100644 --- a/php/README.md +++ b/php/README.md @@ -9,7 +9,7 @@ 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 +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](/youtube/api-samples/blob/master/php/add_subscription.php) @@ -18,51 +18,11 @@ Method: youtube.subscriptions.insert
    Description: This sample calls the API's subscriptions.insert method to add a subscription to a specified channel. -### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/php/captions.php) - -Method: youtube.captions.insert, youtube.captions.list, youtube.captions.update, youtube.captions.download, -youtube.captions.delete
    -Description: This sample demonstrates how to use the following API methods to create and manage YouTube video caption -tracks:
    -

      -
    • It calls the captions.insert method with the isDraft parameter set to true -to upload a caption track in draft status.
    • -
    • It calls the captions.list method with the videoId parameter to retrieve video caption -tracks.
    • -
    • It calls the captions.update method with the caption in the request body to update a caption track.
    • -
    • It calls the captions.download method to download the caption track.
    • -
    • It calls the captions.delete method to delete the caption track, using the id parameter to -identify the caption track.
    • -
    - -### [Set and retrieve localized channel metadata](/youtube/api-samples/blob/master/php/channel_localizations.php) - -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:
    -
      -
    • It calls the channels.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.
    • -
    • It calls the channels.list method with the hl parameter set to a specific language to -retrieve localized metadata in that language.
    • -
    • It calls the channels.list method and includes localizations in the part -parameter value to retrieve all of the localized metadata for that channel.
    • -
    - -### [Set and retrieve localized channel section metadata](/youtube/api-samples/blob/master/php/channel_section_localizations.php) +### [Create a playlist](/youtube/api-samples/blob/master/php/playlist_updates.php) -Method: youtube.channelSections.update, youtube.channelSections.list
    -Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a -channel section:
    -
      -
    • It calls the 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.
    • -
    • It calls the channelSections.list method with the hl parameter set to a specific language -to retrieve localized metadata in that language.
    • -
    • It calls the channelSections.list method and includes localizations in the -part parameter value to retrieve all of the localized metadata for that channel section.
    • -
    +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](/youtube/api-samples/blob/master/php/comment_handling.php) @@ -95,19 +55,38 @@ channel comments and once with the videoId parameter to retrieve vi channel comment. In each case, the request body contains the comment resource being updated. -### [Create a broadcast](/youtube/api-samples/blob/master/php/create_broadcast.php) +### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/php/captions.php) -Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    -Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. +Method: youtube.captions.insert, youtube.captions.list, youtube.captions.update, youtube.captions.download, +youtube.captions.delete
    +Description: This sample demonstrates how to use the following API methods to create and manage YouTube video caption +tracks:
    +
      +
    • It calls the captions.insert method with the isDraft parameter set to true +to upload a caption track in draft status.
    • +
    • It calls the captions.list method with the videoId parameter to retrieve video caption +tracks.
    • +
    • It calls the captions.update method with the caption in the request body to update a caption track.
    • +
    • It calls the captions.download method to download the caption track.
    • +
    • It calls the captions.delete method to delete the caption track, using the id parameter to +identify the caption track.
    • +
    -### [Create a reporting job](/youtube/api-samples/blob/master/php/create_reporting_job.php) +### [Retrieve my uploads](/youtube/api-samples/blob/master/php/my_uploads.php) -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. +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](/youtube/api-samples/blob/master/php/search.php) -### [Search by geolocation](/youtube/api-samples/blob/master/php/geolocation_search.php) +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](/youtube/api-samples/blob/master/php/geolocation_search.php) Method: youtube.search.list, youtube.videos.list
    Description: This sample calls the API's search.list method with the type, q, @@ -115,26 +94,34 @@ Description: This sample calls the API's search.list method with th 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. -### [Retrieve a channel's broadcasts](/youtube/api-samples/blob/master/php/list_broadcasts.php) - -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](/youtube/api-samples/blob/master/php/list_streams.php) +### [Set and retrieve localized channel metadata](/youtube/api-samples/blob/master/php/channel_localizations.php) -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. +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:
    +
      +
    • It calls the channels.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.
    • +
    • It calls the channels.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
    • +
    • It calls the channels.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that channel.
    • +
    -### [Retrieve my uploads](/youtube/api-samples/blob/master/php/my_uploads.php) +### [Set and retrieve localized channel section metadata](/youtube/api-samples/blob/master/php/channel_section_localizations.php) -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. +Method: youtube.channelSections.update, youtube.channelSections.list
    +Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a +channel section:
    +
      +
    • It calls the 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.
    • +
    • It calls the channelSections.list method with the hl parameter set to a specific language +to retrieve localized metadata in that language.
    • +
    • It calls the channelSections.list method and includes localizations in the +part parameter value to retrieve all of the localized metadata for that channel section.
    • +
    ### [Set and retrieve localized playlist metadata](/youtube/api-samples/blob/master/php/playlist_localizations.php) @@ -150,32 +137,19 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that playlist. -### [Create a playlist](/youtube/api-samples/blob/master/php/playlist_updates.php) - -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. - -### [Upload a video](/youtube/api-samples/blob/master/php/resumable_upload.php) +### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/php/video_localizations.php) -Method: youtube.videos.insert
    -Description: The following code sample calls the API's videos.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. - -### [Retrieve reports](/youtube/api-samples/blob/master/php/retrieve_reports.php) - -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. - -### [Search by keyword](/youtube/api-samples/blob/master/php/search.php) - -Method: youtube.search.list
    -Description: This sample calls the API's search.list method to retrieve search results associated with -a particular keyword. +Method: youtube.videos.update, youtube.videos.list
    +Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata +for a video:
    +
      +
    • It calls the 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.
    • +
    • It calls the videos.list method with the hl parameter set to a specific language to +retrieve localized metadata in that language.
    • +
    • It calls the videos.list method and includes localizations in the part +parameter value to retrieve all of the localized metadata for that video.
    • +
    ### [Shuffle existing channel sections](/youtube/api-samples/blob/master/php/shuffle_channel_sections.php) @@ -210,16 +184,42 @@ ID to use a custom image as a thumbnail to the video. For the image upload, the 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. -### [Set and retrieve localized metadata for a video](/youtube/api-samples/blob/master/php/video_localizations.php) +### [Upload a video](/youtube/api-samples/blob/master/php/resumable_upload.php) -Method: youtube.videos.update, youtube.videos.list
    -Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata -for a video:
    -
      -
    • It calls the 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.
    • -
    • It calls the videos.list method with the hl parameter set to a specific language to -retrieve localized metadata in that language.
    • -
    • It calls the videos.list method and includes localizations in the part -parameter value to retrieve all of the localized metadata for that video.
    • -
    +Method: youtube.videos.insert
    +Description: The following code sample calls the API's videos.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](/youtube/api-samples/blob/master/php/create_broadcast.php) + +Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    +Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. + +### [Retrieve a channel's broadcasts](/youtube/api-samples/blob/master/php/list_broadcasts.php) + +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](/youtube/api-samples/blob/master/php/list_streams.php) + +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. + +### [Create a reporting job](/youtube/api-samples/blob/master/php/create_reporting_job.php) + +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](/youtube/api-samples/blob/master/php/retrieve_reports.php) + +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. From 733fbd230eef730cf99e308c30187cc82e8e1368 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 28 Nov 2016 16:34:52 -0500 Subject: [PATCH 041/126] Alphabetize by title Sample for authorizing a request is still first, sample for YT Analytics API is still last --- ruby/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ruby/README.md b/ruby/README.md index aa75ba22..3e04fbd7 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -1,5 +1,11 @@ ## Samples in this directory: +### [Authorize a request](/youtube/api-samples/blob/master/ruby/oauth/oauth_util.rb) + +Description: The following 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. + ### [Add a channel subscription](/youtube/api-samples/blob/master/ruby/add_subscription.rb) Method: youtube.subscriptions.insert
    @@ -12,12 +18,6 @@ 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. -### [Upload a video](/youtube/api-samples/blob/master/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 my uploads](/youtube/api-samples/blob/master/ruby/my_uploads.rb) Method: youtube.playlistItems.list
    @@ -32,6 +32,12 @@ 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](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/ruby/yt_analytics_report.rb) Method: youtubeAnalytics.reports.query
    @@ -39,9 +45,3 @@ Description: This sample calls the API's reports.query method to re 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. - -### [Authorize a request](/youtube/api-samples/blob/master/ruby/oauth/oauth_util.rb) - -Description: The following 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. From 2814b8c6dd14cf830fc123168026d874185e43da Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 29 Nov 2016 11:35:35 -0500 Subject: [PATCH 042/126] Fix description of Live Streaming API script --- php/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/README.md b/php/README.md index 6dfc54c8..97a9ec2c 100644 --- a/php/README.md +++ b/php/README.md @@ -191,10 +191,12 @@ Description: The following code sample calls the API's videos.insertGoogle_MediaFileUpload
    class with the resumable upload parameter set to true to be able to to upload the video in chunks. -### [Create a broadcast](/youtube/api-samples/blob/master/php/create_broadcast.php) +### [Create a broadcast and stream](/youtube/api-samples/blob/master/php/create_broadcast.php) Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    -Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. +Description: This sample calls the API's liveBroadcasts.insert and liveStreams.insert +method 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](/youtube/api-samples/blob/master/php/list_broadcasts.php) From 3afb2fdfdf79399b71f359013570c6bf7be9f810 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 29 Nov 2016 11:36:08 -0500 Subject: [PATCH 043/126] Fix description of Live Streaming API script --- python/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/README.md b/python/README.md index a14fbab2..180310cd 100644 --- a/python/README.md +++ b/python/README.md @@ -212,10 +212,12 @@ 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](/youtube/api-samples/blob/master/python/create_broadcast.py) +### [Create a broadcast and stream](/youtube/api-samples/blob/master/python/create_broadcast.py) Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    -Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. +Description: This sample calls the API's liveBroadcasts.insert and liveStreams.insert +method 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](/youtube/api-samples/blob/master/python/list_broadcasts.py) From b7dc035fa9bf1c069b3ed8d1b659bcc7c70f34fc Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 29 Nov 2016 11:36:34 -0500 Subject: [PATCH 044/126] Fix Live Streaming API script description --- java/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/README.md b/java/README.md index f37d0fa3..1c4492b8 100644 --- a/java/README.md +++ b/java/README.md @@ -217,10 +217,12 @@ Description: This sample demonstrates how to retrieve reports created by a speci 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/CreateBroadcast.java) +### [Create a broadcast and stream](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/CreateBroadcast.java) Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    -Description: This sample calls the API's liveBroadcasts.insert method to create a broadcast. +Description: This sample calls the API's liveBroadcasts.insert and liveStreams.insert +method 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java) From 142a308c484a2e8000363235cb156ed3b9f40d52 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 29 Nov 2016 11:38:28 -0500 Subject: [PATCH 045/126] Fix typo --- java/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/README.md b/java/README.md index 1c4492b8..1fd0a128 100644 --- a/java/README.md +++ b/java/README.md @@ -221,7 +221,7 @@ prints out the download URL for each report. Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    Description: This sample calls the API's liveBroadcasts.insert and liveStreams.insert -method to create a broadcast and a stream. Then, it calls the liveBroadcasts.bind method to bind +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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java) From 2da27de120809ef23bf61f46219aaf9cfefecf19 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 29 Nov 2016 11:38:42 -0500 Subject: [PATCH 046/126] Fix typo --- php/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/README.md b/php/README.md index 97a9ec2c..80e12d36 100644 --- a/php/README.md +++ b/php/README.md @@ -195,7 +195,7 @@ parameter set to true to be able to to upload the video in chunks. Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    Description: This sample calls the API's liveBroadcasts.insert and liveStreams.insert -method to create a broadcast and a stream. Then, it calls the liveBroadcasts.bind method to bind +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](/youtube/api-samples/blob/master/php/list_broadcasts.php) From 85d43c74f83a3eb5793a9d6a2782207407e696f3 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 29 Nov 2016 11:39:02 -0500 Subject: [PATCH 047/126] Fix typo --- python/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/README.md b/python/README.md index 180310cd..6b1bb3d4 100644 --- a/python/README.md +++ b/python/README.md @@ -216,7 +216,7 @@ watermark image for a channel. The request must be authorized by the channel tha Method: youtube.liveBroadcasts.bind,youtube.liveBroadcasts.insert,youtube.liveStreams.insert
    Description: This sample calls the API's liveBroadcasts.insert and liveStreams.insert -method to create a broadcast and a stream. Then, it calls the liveBroadcasts.bind method to bind +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](/youtube/api-samples/blob/master/python/list_broadcasts.py) From c288f5548bd59e57091c2dcd3d5d3441767d7e53 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 29 Nov 2016 14:11:09 -0500 Subject: [PATCH 048/126] Update description of YT Analytics sample --- javascript/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/javascript/README.md b/javascript/README.md index 31226753..e8e87ea9 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -13,6 +13,7 @@ client ID by registering your application in the ### [Do resumable uploads with CORS](/youtube/api-samples/blob/master/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](/youtube/api-samples/blob/master/javascript/playlist_updates.js) @@ -64,3 +65,11 @@ The samples use the Go to demonstrate API functionality. The Building a Sample Application document walks you through the steps of building this application and discusses different portions of this code in more detail. + +In addition to the JavaScript file described above, the HTML page uses jQuery, which +provides helper methods to simplify HTML document traversing, event handling, animating and Ajax interactions. It also +uses the Google API loader (www.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. From 4d20a4306a6b24a99148fbec5d40699b4c0e918b Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 29 Nov 2016 14:13:48 -0500 Subject: [PATCH 049/126] Formatting --- javascript/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/README.md b/javascript/README.md index e8e87ea9..31d2c4ee 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -64,7 +64,7 @@ Description: This sample uses the YouTube Data and YouTube Analytics APIs to ret The samples use the Google APIs JavaScript client library to demonstrate API functionality. The Building a Sample Application document walks you through the steps of building this application and discusses different portions of this code in more -detail. +detail.

    In addition to the JavaScript file described above, the HTML page uses jQuery, which provides helper methods to simplify HTML document traversing, event handling, animating and Ajax interactions. It also From a394a3a720e1f049882d1bc9e2bd67ed5b1ec82c Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 5 Dec 2016 16:01:43 -0500 Subject: [PATCH 050/126] Create file with snippets for all API read methods This file contains snippets generated using default parameter values in the API code snippet tool at https://devsite.googleplex.com/youtube/v3/code_samples/code_snippets. The file contains the boilerplate code for Apps Script, which is a basic function that prints some output from each API response to the logging console as well as all of the snippets for the API methods. Currently, the functions cover all of the API's read-only methods. --- apps-script/snippets/apps-script.gs | 475 ++++++++++++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 apps-script/snippets/apps-script.gs 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'); +} From 6f5d67b56580cb61e79a18dd900c5253e720d428 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 5 Dec 2016 16:19:02 -0500 Subject: [PATCH 051/126] Add README.md for Apps Script snippets --- apps-script/snippets/README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 apps-script/snippets/README.md 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. From fe307fd1d2029fc5dc563cef4f315c7f5ad2e78c Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Fri, 9 Dec 2016 10:54:33 -0800 Subject: [PATCH 052/126] Fix typo in developer key detection --- python_appengine/search/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 - to do so.""" + to do so.""") else: youtube = build( YOUTUBE_API_SERVICE_NAME, From 7d75b788da505ec67ee8b2cb56600dbe6eea76df Mon Sep 17 00:00:00 2001 From: Ross Smith II Date: Tue, 20 Dec 2016 10:19:19 -0800 Subject: [PATCH 053/126] Workaround github's formatter bug --- python/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/README.md b/python/README.md index 6b1bb3d4..6c0306e0 100644 --- a/python/README.md +++ b/python/README.md @@ -45,7 +45,8 @@ thread.
  • It calls the comments.update method with comment in the request body to update a comment.
  • It calls the 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.
  • +delete the comment, using the id parameter to identify the comment. + ### [Create and manage comment threads](/youtube/api-samples/blob/master/python/comment_threads.py) From 7a8667a1cfc139ef292d614ad93e4760a022da3a Mon Sep 17 00:00:00 2001 From: Jen O'Byrne Date: Fri, 13 Jan 2017 19:41:14 +1300 Subject: [PATCH 054/126] Fix dotnet sample urls URLs on github were redirecting to a 404 page because url was being appended to twice. Removing "youtube/api-samples/blob/master/" as github will do it for you. --- dotnet/README.md | 8 +++--- go/README.md | 10 +++---- java/README.md | 48 +++++++++++++++---------------- javascript/README.md | 14 ++++----- php/README.md | 46 +++++++++++++++--------------- python/README.md | 58 +++++++++++++++++++------------------- python_appengine/README.md | 4 +-- ruby/README.md | 14 ++++----- 8 files changed, 101 insertions(+), 101 deletions(-) diff --git a/dotnet/README.md b/dotnet/README.md index 33152d0c..3d9a8932 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -1,12 +1,12 @@ ## Samples in this directory: -### [Create a playlist](/youtube/api-samples/blob/master/dotnet/PlaylistUpdates.cs) +### [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](/youtube/api-samples/blob/master/dotnet/MyUploads.cs) +### [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 @@ -14,13 +14,13 @@ uploaded to the channel associated with the request. The code also calls the mine
    parameter set to true to retrieve the playlist ID that identifies the channel's uploaded videos. -### [Search by keyword](/youtube/api-samples/blob/master/dotnet/Search.cs) +### [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](/youtube/api-samples/blob/master/dotnet/UploadVideo.cs) +### [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 diff --git a/go/README.md b/go/README.md index a0432c54..8f7a0035 100644 --- a/go/README.md +++ b/go/README.md @@ -36,19 +36,19 @@ More information about the YouTube APIs can be found at https://developer.google ## Samples in this directory: -### [Authorize a request](/youtube/api-samples/blob/master/go/oauth.go) +### [Authorize a request](/go/oauth.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. -### [Post a channel bulletin](/youtube/api-samples/blob/master/go/post_bulletin.go) +### [Post a channel bulletin](/go/post_bulletin.go) Method: youtube.activities.insert
    Description: This code sample calls the API's activities.insert method to post a bulletin to the channel associated with the request. -### [Retrieve my uploads](/youtube/api-samples/blob/master/go/my_uploads.go) +### [Retrieve my uploads](/go/my_uploads.go) Method: youtube.playlistItems.list
    Description: This code sample calls the API's playlistItems.list method to retrieve a list of @@ -56,13 +56,13 @@ videos uploaded to the channel associated with the request. The code also calls method with the mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded videos. -### [Search by keyword](/youtube/api-samples/blob/master/go/search_by_keyword.go) +### [Search by keyword](/go/search_by_keyword.go) Method: youtube.search.list
    Description: This code sample calls the API's search.list method to retrieve search results associated with a particular keyword. -### [Upload a video](/youtube/api-samples/blob/master/go/upload_video.go) +### [Upload a video](/go/upload_video.go) Method: youtube.videos.insert
    Description: This code sample calls the API's videos.insert method to upload a video to the channel diff --git a/java/README.md b/java/README.md index 1fd0a128..4246fafe 100644 --- a/java/README.md +++ b/java/README.md @@ -22,29 +22,29 @@ YouTube API samples, see this video: ## Samples in this directory: -### [Authorize a request](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/Auth.java) +### [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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/AddSubscription.java) +### [Add a channel subscription](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/AddSubscription.java) 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/InvideoProgramming.java) +### [Add a featured video](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/InvideoProgramming.java) Method: youtube.channels.update
    Description: This sample calls the API's channels.update method to set invideoPromotion properties for the channel. -### [Create a playlist](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistUpdates.java) +### [Create a playlist](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistUpdates.java) 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentHandling.java) +### [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.delete
    @@ -61,7 +61,7 @@ thread. 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. -### [Create and manage comment threads](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentThreads.java) +### [Create and manage comment threads](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/CommentThreads.java) Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
    Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
    @@ -74,7 +74,7 @@ channel comments and once with the videoId parameter to retrieve vi channel comment. In each case, the request body contains the comment resource being updated. -### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Captions.java) +### [Create and manage YouTube video caption tracks](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Captions.java) Method: youtube.captions.insert, youtube.captions.list, youtube.captions.update, youtube.captions.download, youtube.captions.delete
    @@ -91,13 +91,13 @@ tracks. identify the caption track. -### [Post a channel bulletin](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelBulletin.java) +### [Post a channel bulletin](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelBulletin.java) 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/MyUploads.java) +### [Retrieve my uploads](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/MyUploads.java) Method: youtube.playlistItems.list
    Description: This sample calls the API's playlistItems.list method to retrieve a list of videos uploaded @@ -105,13 +105,13 @@ to the channel associated with the request. The code also calls the channe mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded videos. -### [Search by keyword](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Search.java) +### [Search by keyword](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Search.java) 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/GeolocationSearch.java) +### [Search by location](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/GeolocationSearch.java) Method: youtube.search.list, youtube.videos.list
    Description: This sample calls the API's search.list method with the type, q, location, and @@ -119,7 +119,7 @@ Description: This sample calls the API's search.list method with th 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelLocalizations.java) +### [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.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -134,7 +134,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that channel. -### [Set and retrieve localized channel section metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelSectionLocalizations.java) +### [Set and retrieve localized channel section metadata](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/ChannelSectionLocalizations.java) Method: youtube.channelSections.update, youtube.channelSections.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -148,7 +148,7 @@ to retrieve localized metadata in that language. part parameter value to retrieve all of the localized metadata for that channel section. -### [Set and retrieve localized playlist metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistLocalizations.java) +### [Set and retrieve localized playlist metadata](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/PlaylistLocalizations.java) Method: youtube.playlists.update, youtube.playlists.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -162,7 +162,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that playlist. -### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/VideoLocalizations.java) +### [Set and retrieve localized video metadata](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/VideoLocalizations.java) Method: youtube.videos.update, youtube.videos.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata @@ -176,25 +176,25 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that video. -### [Update a video](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UpdateVideo.java) +### [Update a video](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UpdateVideo.java) 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 custom video thumbnail image](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadThumbnail.java) +### [Upload a custom video thumbnail image](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadThumbnail.java) 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 video](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadVideo.java) +### [Upload a video](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/UploadVideo.java) 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/analytics/YouTubeAnalyticsReports.java) +### [Retrieve top 10 videos by viewcount](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/analytics/YouTubeAnalyticsReports.java) Method: youtubeAnalytics.reports.query
    Description: This sample calls the API's reports.query method to retrieve YouTube Analytics data. @@ -202,14 +202,14 @@ By default, the report retrieves the top 10 videos based on viewcounts, and it r 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/CreateReportingJob.java) +### [Create a reporting job](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/CreateReportingJob.java) 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/RetrieveReports.java) +### [Retrieve reports](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/reporting/RetrieveReports.java) Method: youtubeReporting.jobs.list, youtubeReporting.reports.list
    Description: This sample demonstrates how to retrieve reports created by a specific job. It calls the @@ -217,21 +217,21 @@ Description: This sample demonstrates how to retrieve reports created by a speci 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/CreateBroadcast.java) +### [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.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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java) +### [Retrieve a channel's broadcasts](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java) 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](/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListStreams.java) +### [Retrieve a channel's live video streams](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListStreams.java) Method: youtube.liveStreams.list
    Description: This sample calls the API's liveStreams.list method to retrieve a list of video stream settings diff --git a/javascript/README.md b/javascript/README.md index 31d2c4ee..a51d446a 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -1,6 +1,6 @@ ## Samples in this directory: -### [Authorize a request](/youtube/api-samples/blob/master/javascript/auth.js) +### [Authorize a request](/javascript/auth.js) Description: The auth.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 @@ -11,18 +11,18 @@ For requests that do not require authentication, you could also use the client ID by registering your application in the Google Developers Console. -### [Do resumable uploads with CORS](/youtube/api-samples/blob/master/javascript/cors_upload.js) +### [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](/youtube/api-samples/blob/master/javascript/playlist_updates.js) +### [Create a playlist](/javascript/playlist_updates.js) Method: youtube.playlists.insert
    Description: This JavaScript code creates a private playlist and adds videos to that playlist. (You could, of course, modify the code so that it creates a publicly visible playlist or so that it checks a form value to determine whether the playlist is public or private.) Note that you need to update the client ID in the auth.js file to run this code.

    The HTML page uses JQuery, along with the auth.js and playlist_updates.js JavaScript files, to display a simple form for adding videos to the playlist. -### [Retrieve my uploads](/youtube/api-samples/blob/master/javascript/my_uploads.js) +### [Retrieve my uploads](/javascript/my_uploads.js) Method: youtube.playlistItems.list
    Description: The JavaScript sample code performs the following functions:
    @@ -35,13 +35,13 @@ Description: The JavaScript sample code performs the following functions:
    The HTML page uses JQuery, the auth.js and my_uploads.js JavaScript files, and a CSS file to display the list of uploaded videos. -### [Search by keyword](/youtube/api-samples/blob/master/javascript/search.js) +### [Search by keyword](/javascript/search.js) Method: youtube.search.list
    Description: This code sample calls the API's search.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](/youtube/api-samples/blob/master/javascript/upload_video.js) +### [Upload a video](/javascript/upload_video.js) Method: youtube.videos.insert
    Description: This JavaScript sample performs the following functions:
    @@ -57,7 +57,7 @@ with your project's client ID. The only valid JavaScript origin for the client I http://localhost. This means that you could test the sample locally, but it would not work in your production application. -### [Calling the Analytics API](/youtube/api-samples/blob/master/javascript/analytics_codelab.js) +### [Calling the Analytics API](/javascript/analytics_codelab.js) Method: youtubeAnalytics.reports.query
    Description: This sample uses the YouTube Data and YouTube Analytics APIs to retrieve YouTube channel metrics. diff --git a/php/README.md b/php/README.md index 80e12d36..8a4b63be 100644 --- a/php/README.md +++ b/php/README.md @@ -1,6 +1,6 @@ ## Samples in this directory: -### [Add a channel section](/youtube/api-samples/blob/master/php/add_channel_section.php) +### [Add a channel section](/php/add_channel_section.php) Method: youtube.channelSections.insert
    Description: This sample calls the API's channelSections.insert method to create channel sections. @@ -12,19 +12,19 @@ property so that the channel displays content in a browse view (rather than a fe 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](/youtube/api-samples/blob/master/php/add_subscription.php) +### [Add a channel subscription](/php/add_subscription.php) Method: youtube.subscriptions.insert
    Description: This sample calls the API's subscriptions.insert method to add a subscription to a specified channel. -### [Create a playlist](/youtube/api-samples/blob/master/php/playlist_updates.php) +### [Create a playlist](/php/playlist_updates.php) 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](/youtube/api-samples/blob/master/php/comment_handling.php) +### [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.delete
    @@ -42,7 +42,7 @@ thread. delete the comment, using the id parameter to identify the comment. -### [Create and manage comment threads](/youtube/api-samples/blob/master/php/comment_threads.php) +### [Create and manage comment threads](/php/comment_threads.php) Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
    Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
    @@ -55,7 +55,7 @@ channel comments and once with the videoId parameter to retrieve vi channel comment. In each case, the request body contains the comment resource being updated. -### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/php/captions.php) +### [Create and manage YouTube video caption tracks](/php/captions.php) Method: youtube.captions.insert, youtube.captions.list, youtube.captions.update, youtube.captions.download, youtube.captions.delete
    @@ -72,7 +72,7 @@ tracks. identify the caption track. -### [Retrieve my uploads](/youtube/api-samples/blob/master/php/my_uploads.php) +### [Retrieve my uploads](/php/my_uploads.php) Method: youtube.playlistItems.list
    Description: This sample calls the API's playlistItems.list method to retrieve a list of videos uploaded @@ -80,13 +80,13 @@ to the channel associated with the request. The code also calls the channe mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded videos. -### [Search by keyword](/youtube/api-samples/blob/master/php/search.php) +### [Search by keyword](/php/search.php) 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](/youtube/api-samples/blob/master/php/geolocation_search.php) +### [Search by location](/php/geolocation_search.php) Method: youtube.search.list, youtube.videos.list
    Description: This sample calls the API's search.list method with the type, q, @@ -94,7 +94,7 @@ Description: This sample calls the API's search.list method with th 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](/youtube/api-samples/blob/master/php/channel_localizations.php) +### [Set and retrieve localized channel metadata](/php/channel_localizations.php) 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 @@ -109,7 +109,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that channel. -### [Set and retrieve localized channel section metadata](/youtube/api-samples/blob/master/php/channel_section_localizations.php) +### [Set and retrieve localized channel section metadata](/php/channel_section_localizations.php) Method: youtube.channelSections.update, youtube.channelSections.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -123,7 +123,7 @@ to retrieve localized metadata in that language. part parameter value to retrieve all of the localized metadata for that channel section. -### [Set and retrieve localized playlist metadata](/youtube/api-samples/blob/master/php/playlist_localizations.php) +### [Set and retrieve localized playlist metadata](/php/playlist_localizations.php) Method: youtube.playlists.update, youtube.playlists.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -137,7 +137,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that playlist. -### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/php/video_localizations.php) +### [Set and retrieve localized video metadata](/php/video_localizations.php) Method: youtube.videos.update, youtube.videos.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata @@ -151,7 +151,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that video. -### [Shuffle existing channel sections](/youtube/api-samples/blob/master/php/shuffle_channel_sections.php) +### [Shuffle existing channel sections](/php/shuffle_channel_sections.php) Method: youtube.channelSections.list,youtube.channelSections.update
    Description: This sample calls the API's channelSections.list method to get the list of current channel @@ -159,7 +159,7 @@ sections, shuffles them, and then calls channelSections.update to c More information on channel sections is available in the YouTube Help Center. -### [Update a video](/youtube/api-samples/blob/master/php/update_video.php) +### [Update a video](/php/update_video.php) Method: youtube.videos.update
    Description: This code sample demonstrates how to add tags into an existing video.

    The following code @@ -168,13 +168,13 @@ to get the video object. Using this video object, the sample gets the list of ta 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](/youtube/api-samples/blob/master/php/upload_banner.php) +### [Upload a banner image and set as channel's banner](/php/upload_banner.php) 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 this image. -### [Upload a custom video thumbnail image](/youtube/api-samples/blob/master/php/upload_thumbnail.php) +### [Upload a custom video thumbnail image](/php/upload_thumbnail.php) Method: youtube.thumbnails.set
    Description: This sample demonstrates how to upload a custom video thumbnail to YouTube and set it for a video. @@ -184,41 +184,41 @@ ID to use a custom image as a thumbnail to the video. For the image upload, the 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](/youtube/api-samples/blob/master/php/resumable_upload.php) +### [Upload a video](/php/resumable_upload.php) Method: youtube.videos.insert
    Description: The following code sample calls the API's videos.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](/youtube/api-samples/blob/master/php/create_broadcast.php) +### [Create a broadcast and stream](/php/create_broadcast.php) 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](/youtube/api-samples/blob/master/php/list_broadcasts.php) +### [Retrieve a channel's broadcasts](/php/list_broadcasts.php) 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](/youtube/api-samples/blob/master/php/list_streams.php) +### [Retrieve a channel's live video streams](/php/list_streams.php) 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. -### [Create a reporting job](/youtube/api-samples/blob/master/php/create_reporting_job.php) +### [Create a reporting job](/php/create_reporting_job.php) 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](/youtube/api-samples/blob/master/php/retrieve_reports.php) +### [Retrieve reports](/php/retrieve_reports.php) Method: youtubeReporting.jobs.list, youtubeReporting.reports.list
    Description: This sample demonstrates how to retrieve reports created by a specific job. It calls the diff --git a/python/README.md b/python/README.md index 6c0306e0..3aacd516 100644 --- a/python/README.md +++ b/python/README.md @@ -1,6 +1,6 @@ ## Samples in this directory: -### [Add a channel section](/youtube/api-samples/blob/master/python/add_channel_section.py) +### [Add a channel section](/python/add_channel_section.py) Method: youtube.channelSections.insert
    Description: This sample calls the API's channelSections.insert method to create channel sections. @@ -12,25 +12,25 @@ property so that the channel displays content in a browse view (rather than a fe 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](/youtube/api-samples/blob/master/python/add_subscription.py) +### [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](/youtube/api-samples/blob/master/python/add_featured_video.py) +### [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](/youtube/api-samples/blob/master/python/playlist_updates.py) +### [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](/youtube/api-samples/blob/master/python/comment_handling.py) +### [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
    @@ -48,7 +48,7 @@ thread. delete the comment, using the id parameter to identify the comment. -### [Create and manage comment threads](/youtube/api-samples/blob/master/python/comment_threads.py) +### [Create and manage comment threads](/python/comment_threads.py) Method: youtube.commentThreads.insert, youtube.commentThreads.list, youtube.commentThreads.update
    Description: This sample demonstrates how to use the following API methods to create and manage top-level comments:
    @@ -61,7 +61,7 @@ channel comments and once with the videoId parameter to retrieve vi channel comment. In each case, the request body contains the comment resource being updated. -### [Create and manage YouTube video caption tracks](/youtube/api-samples/blob/master/python/captions.py) +### [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.delete
    @@ -78,24 +78,24 @@ tracks. identify the caption track. -### [Like a video](/youtube/api-samples/blob/master/python/like_video.py) +### [Like a video](/python/like_video.py) Method: youtube.videos.rate
    Description: This sample calls the API's videos.rate method to set a positive rating for a video. -### [Post a channel bulletin](/youtube/api-samples/blob/master/python/channel_bulletin.py) +### [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](/youtube/api-samples/blob/master/python/unset_watermark.py) +### [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](/youtube/api-samples/blob/master/python/my_uploads.py) +### [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 @@ -103,13 +103,13 @@ to the channel associated with the request. The code also calls the channe mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded videos. -### [Search by keyword](/youtube/api-samples/blob/master/python/search.py) +### [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](/youtube/api-samples/blob/master/python/geolocation_search.py) +### [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, @@ -118,7 +118,7 @@ matching the provided keyword within the radius centered at a particular locatio 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](/youtube/api-samples/blob/master/python/channel_localizations.py) +### [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 @@ -133,7 +133,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that channel. -### [Set and retrieve localized channel section metadata](/youtube/api-samples/blob/master/python/channel_section_localizations.py) +### [Set and retrieve localized channel section metadata](/python/channel_section_localizations.py) Method: youtube.channelSections.update, youtube.channelSections.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -147,7 +147,7 @@ to retrieve localized metadata in that language. part parameter value to retrieve all of the localized metadata for that channel section. -### [Set and retrieve localized playlist metadata](/youtube/api-samples/blob/master/python/playlist_localizations.py) +### [Set and retrieve localized playlist metadata](/python/playlist_localizations.py) Method: youtube.playlists.update, youtube.playlists.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata for a @@ -161,7 +161,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that playlist. -### [Set and retrieve localized video metadata](/youtube/api-samples/blob/master/python/video_localizations.py) +### [Set and retrieve localized video metadata](/python/video_localizations.py) Method: youtube.videos.update, youtube.videos.list
    Description: This sample demonstrates how to use the following API methods to set and retrieve localized metadata @@ -175,7 +175,7 @@ retrieve localized metadata in that language. parameter value to retrieve all of the localized metadata for that video. -### [Shuffle existing channel sections](/youtube/api-samples/blob/master/python/shuffle_channel_sections.py) +### [Shuffle existing channel sections](/python/shuffle_channel_sections.py) Method: youtube.channelSections.list,youtube.channelSections.update
    Description: This sample calls the API's channelSections.list method to get the list of current channel @@ -183,57 +183,57 @@ sections. Then it shuffles the list and calls channelSections.updateYouTube Help Center. -### [Update a video](/youtube/api-samples/blob/master/python/update_video.py) +### [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](/youtube/api-samples/blob/master/python/upload_banner.py) +### [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](/youtube/api-samples/blob/master/python/upload_video.py) +### [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](/youtube/api-samples/blob/master/python/upload_thumbnail.py) +### [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](/youtube/api-samples/blob/master/python/set_watermark.py) +### [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](/youtube/api-samples/blob/master/python/create_broadcast.py) +### [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](/youtube/api-samples/blob/master/python/list_broadcasts.py) +### [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](/youtube/api-samples/blob/master/python/list_streams.py) +### [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](/youtube/api-samples/blob/master/python/yt_analytics_report.py) +### [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. @@ -241,14 +241,14 @@ By default, the report retrieves the top 10 videos based on viewcounts, and it r 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](/youtube/api-samples/blob/master/python/create_reporting_job.py) +### [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](/youtube/api-samples/blob/master/python/retrieve_reports.py) +### [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 diff --git a/python_appengine/README.md b/python_appengine/README.md index 11663edc..d380961b 100644 --- a/python_appengine/README.md +++ b/python_appengine/README.md @@ -1,13 +1,13 @@ ## Samples in this directory: -### [Retrieve a channel's uploads](/youtube/api-samples/blob/master/python_appengine/user_uploads/main.py) +### [Retrieve a channel's uploads](/python_appengine/user_uploads/main.py) Method: youtube.playlistItems.list Description: This code sample calls the API's 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](/youtube/api-samples/blob/master/python_appengine/search/main.py) +### [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 diff --git a/ruby/README.md b/ruby/README.md index 3e04fbd7..8774d3a7 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -1,24 +1,24 @@ ## Samples in this directory: -### [Authorize a request](/youtube/api-samples/blob/master/ruby/oauth/oauth_util.rb) +### [Authorize a request](/ruby/oauth/oauth_util.rb) Description: The following 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. -### [Add a channel subscription](/youtube/api-samples/blob/master/ruby/add_subscription.rb) +### [Add a channel subscription](/ruby/add_subscription.rb) Method: youtube.subscriptions.insert
    Description: This sample calls the API's subscriptions.insert method to add a subscription to a specified channel. -### [Post a channel bulletin](/youtube/api-samples/blob/master/ruby/channel_bulletin.rb) +### [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](/youtube/api-samples/blob/master/ruby/my_uploads.rb) +### [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 @@ -26,19 +26,19 @@ to the channel associated with the request. The code also calls the channe mine parameter set to true to retrieve the playlist ID that identifies the channel's uploaded videos. -### [Search by keyword](/youtube/api-samples/blob/master/ruby/search.rb) +### [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](/youtube/api-samples/blob/master/ruby/upload_video.rb) +### [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](/youtube/api-samples/blob/master/ruby/yt_analytics_report.rb) +### [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. From 1c7f9c8d544031bc0b95eb783bbea2c0d6b3e466 Mon Sep 17 00:00:00 2001 From: Jim Rogers Date: Thu, 23 Mar 2017 09:55:08 -0700 Subject: [PATCH 055/126] Set broadcast type when listing broadcasts, otherwise nothing is returned --- .../services/samples/youtube/cmdline/live/ListBroadcasts.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java index 0fafb563..6a421267 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListBroadcasts.java @@ -63,8 +63,8 @@ public static void main(String[] args) { youtube.liveBroadcasts().list("id,snippet"); // Indicate that the API response should not filter broadcasts - // based on their status. - liveBroadcastRequest.setBroadcastStatus("all"); + // based on their type or status. + liveBroadcastRequest.setBroadcastType("all").setBroadcastStatus("all"); // Execute the API request and return the list of broadcasts. LiveBroadcastListResponse returnedListResponse = liveBroadcastRequest.execute(); From 37e595b4d7b62583280b0a4dfe8bf24306f2e7be Mon Sep 17 00:00:00 2001 From: Jim Rogers Date: Thu, 23 Mar 2017 13:05:47 -0700 Subject: [PATCH 056/126] Add samples for live chat --- java/README.md | 34 ++- java/pom.xml | 2 +- .../cmdline/live/DeleteLiveChatMessage.java | 98 +++++++ .../youtube/cmdline/live/GetLiveChatId.java | 134 +++++++++ .../cmdline/live/InsertLiveChatMessage.java | 116 ++++++++ .../cmdline/live/ListLiveChatMessages.java | 272 ++++++++++++++++++ 6 files changed, 653 insertions(+), 3 deletions(-) create mode 100644 java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java create mode 100644 java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java create mode 100644 java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/InsertLiveChatMessage.java create mode 100644 java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java diff --git a/java/README.md b/java/README.md index 4246fafe..bd7e0862 100644 --- a/java/README.md +++ b/java/README.md @@ -11,9 +11,13 @@ To build this code sample from the command line, type: mvn compile -To run the code sample from the command line, enter the following: +To run a code sample from the command line, enter the following: - mvn exec:java -Dexec.mainClass="FULL_CLASS_NAME" + 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: @@ -236,3 +240,29 @@ also specify a value for the --broadcast-status option to only retr 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. + + +### [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.list
    +Description: This sample retrieves a live chat id from either a videoId parameter +or the current user's live broadcast. 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.insert
    +Description: This sample inserts a live chat message into the live chat specified by either +a videoId parameter or the current user's live broadcast. + +### [Delete a live chat message](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java) + +Method: youtube.liveChatMessages.delete
    +Description: This sample deletes a live chat message from the live chat specified by either +a videoId parameter or the current user's live broadcast. + +### [List live chat messages](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java) + +Method: youtube.liveChatMessages.list
    +Description: This sample lists live chat messages from the chat specified by either +a videoId parameter or the current user's live broadcast. diff --git a/java/pom.xml b/java/pom.xml index 6de21773..200ffec1 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -11,7 +11,7 @@ http://maven.apache.org - v3-rev179-1.22.0 + v3-rev182-1.22.0 v1-rev63-1.22.0 v1-rev10-1.22.0 1.20.0 diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java new file mode 100644 index 00000000..a081fb12 --- /dev/null +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.api.services.samples.youtube.cmdline.live; + +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.googleapis.json.GoogleJsonResponseException; +import com.google.api.services.samples.youtube.cmdline.Auth; +import com.google.api.services.youtube.YouTube; +import com.google.api.services.youtube.YouTubeScopes; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Delets a message from a live broadcast, using OAuth 2.0 to authorize API requests. + * + * @author Jim Rogers + */ +public class DeleteLiveChatMessage { + + /** + * Define a global instance of a Youtube object, which will be used + * to make YouTube Data API requests. + */ + private static YouTube youtube; + + /** + * Deletes a message from a live broadcast. + * + * @param args The message id to delete (required) followed by the videoId (optional). If the + * videoId is given, live chat messages will be retrieved from the chat associated with this + * video. If the videoId is not specified, the signed in user's current live broadcast will be + * used instead. + */ + public static void main(String[] args) { + // Get the message id to delete + if (args.length == 0) { + System.err.println("No message id specified"); + System.exit(1); + } + String messageId = args[0]; + + // This OAuth 2.0 access scope allows for read-only access to the + // authenticated user's account, but not other types of account access. + List scopes = new ArrayList(); + scopes.add(YouTubeScopes.YOUTUBE_FORCE_SSL); + scopes.add(YouTubeScopes.YOUTUBE); + + try { + // Authorize the request. + Credential credential = Auth.authorize(scopes, "deletelivechatmessage"); + + // This object is used to make YouTube Data API requests. + youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential) + .setApplicationName("youtube-cmdline-deletechatmessages-sample").build(); + + // Get the liveChatId + String liveChatId = GetLiveChatId.getLiveChatId( + youtube, + args.length == 2 ? args[1] : null); + if (liveChatId != null) { + System.out.println("Live chat id: " + liveChatId); + } else { + System.err.println("Unable to find a live chat id"); + System.exit(1); + } + + // Delete the message from live chat + YouTube.LiveChatMessages.Delete liveChatDelete = + youtube.liveChatMessages().delete(messageId); + liveChatDelete.execute(); + System.out.println("Deleted message id " + messageId); + } catch (GoogleJsonResponseException e) { + System.err + .println("GoogleJsonResponseException code: " + e.getDetails().getCode() + " : " + + e.getDetails().getMessage()); + e.printStackTrace(); + } catch (IOException e) { + System.err.println("IOException: " + e.getMessage()); + e.printStackTrace(); + } catch (Throwable t) { + System.err.println("Throwable: " + t.getMessage()); + t.printStackTrace(); + } + } +} diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java new file mode 100644 index 00000000..0a5b71a0 --- /dev/null +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.api.services.samples.youtube.cmdline.live; + +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.googleapis.json.GoogleJsonResponseException; +import com.google.api.services.samples.youtube.cmdline.Auth; +import com.google.api.services.youtube.YouTube; +import com.google.api.services.youtube.YouTubeScopes; +import com.google.api.services.youtube.model.LiveBroadcast; +import com.google.api.services.youtube.model.LiveBroadcastListResponse; +import com.google.api.services.youtube.model.Video; +import com.google.api.services.youtube.model.VideoListResponse; +import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.List; + +/** + * Gets a live chat id from a video id or current signed in user. + * + * The videoId is often included in the video's url, e.g.: + * https://www.youtube.com/watch?v=L5Xc93_ZL60 + * ^ videoId + * The video URL may be found in the browser address bar, or by right-clicking a video and selecting + * Copy video URL from the context menu. + * + * @author Jim Rogers + */ +public class GetLiveChatId { + + /** + * Define a global instance of a Youtube object, which will be used + * to make YouTube Data API requests. + */ + private static YouTube youtube; + + /** + * Poll live chat messages and SuperChat details from a live broadcast. + * + * @param args videoId (optional). If the videoId is given, live chat messages will be retrieved + * from the chat associated with this video. If the videoId is not specified, the signed in + * user's current live broadcast will be used instead. + */ + public static void main(String[] args) { + + // This OAuth 2.0 access scope allows for read-only access to the + // authenticated user's account, but not other types of account access. + List scopes = Lists.newArrayList(YouTubeScopes.YOUTUBE_READONLY); + + try { + // Authorize the request. + Credential credential = Auth.authorize(scopes, "getlivechatid"); + + // This object is used to make YouTube Data API requests. + youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential) + .setApplicationName("youtube-cmdline-getlivechatid-sample").build(); + + // Get the liveChatId + String liveChatId = getLiveChatId(youtube, args.length == 1 ? args[0] : null); + if (liveChatId != null) { + System.out.println("Live chat id: " + liveChatId); + } else { + System.err.println("Unable to find a live chat id"); + System.exit(1); + } + } catch (GoogleJsonResponseException e) { + System.err + .println("GoogleJsonResponseException code: " + e.getDetails().getCode() + " : " + + e.getDetails().getMessage()); + e.printStackTrace(); + + } catch (IOException e) { + System.err.println("IOException: " + e.getMessage()); + e.printStackTrace(); + } catch (Throwable t) { + System.err.println("Throwable: " + t.getMessage()); + t.printStackTrace(); + } + } + + /** + * Retrieves the liveChatId from the videoId, if specified. If not specified, will find the + * liveChatId for the signed in user's live broadcast. + * + * @param youtube The object is used to make YouTube Data API requests. + * @param videoId The videoId associated with the live chat (optional). + * @return A liveChatId, or null if not found. + */ + static String getLiveChatId(YouTube youtube, String videoId) throws IOException { + if (videoId != null && !videoId.isEmpty()) { + // Get liveChatId from the video + YouTube.Videos.List videoList = youtube.videos() + .list("liveStreamingDetails") + .setFields("items/liveStreamingDetails/activeLiveChatId") + .setId(videoId); + VideoListResponse response = videoList.execute(); + for (Video v : response.getItems()) { + String liveChatId = v.getLiveStreamingDetails().getActiveLiveChatId(); + if (liveChatId != null && !liveChatId.isEmpty()) { + return liveChatId; + } + } + } else { + // Get signed in user's liveChatId + YouTube.LiveBroadcasts.List broadcastList = youtube + .liveBroadcasts() + .list("snippet") + .setFields("items/snippet/liveChatId") + .setBroadcastType("all") + .setBroadcastStatus("active"); + LiveBroadcastListResponse broadcastListResponse = broadcastList.execute(); + for (LiveBroadcast b : broadcastListResponse.getItems()) { + String liveChatId = b.getSnippet().getLiveChatId(); + if (liveChatId != null && !liveChatId.isEmpty()) { + return liveChatId; + } + } + } + + return null; + } +} diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/InsertLiveChatMessage.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/InsertLiveChatMessage.java new file mode 100644 index 00000000..e8e66f62 --- /dev/null +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/InsertLiveChatMessage.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.api.services.samples.youtube.cmdline.live; + +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.googleapis.json.GoogleJsonResponseException; +import com.google.api.services.samples.youtube.cmdline.Auth; +import com.google.api.services.youtube.YouTube; +import com.google.api.services.youtube.YouTubeScopes; +import com.google.api.services.youtube.model.LiveChatMessage; +import com.google.api.services.youtube.model.LiveChatMessageSnippet; +import com.google.api.services.youtube.model.LiveChatTextMessageDetails; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Inserts a message into a live broadcast of the current user or a video specified by id. + * + * The videoId is often included in the video's url, e.g.: + * https://www.youtube.com/watch?v=L5Xc93_ZL60 + * ^ videoId + * The video URL may be found in the browser address bar, or by right-clicking a video and selecting + * Copy video URL from the context menu. + * + * @author Jim Rogers + */ +public class InsertLiveChatMessage { + + /** + * Define a global instance of a Youtube object, which will be used + * to make YouTube Data API requests. + */ + private static YouTube youtube; + + /** + * Inserts a message into a live broadcast. + * + * @param args The message to insert (required) followed by the videoId (optional). + * If the videoId is given, live chat messages will be retrieved from the chat associated with + * this video. If the videoId is not specified, the signed in user's current live broadcast will + * be used instead. + */ + public static void main(String[] args) { + // Get the chat message to insert + if (args.length == 0) { + System.err.println("No message specified"); + System.exit(1); + } + String message = args[0]; + + // This OAuth 2.0 access scope allows for read-only access to the + // authenticated user's account, but not other types of account access. + List scopes = new ArrayList(); + scopes.add(YouTubeScopes.YOUTUBE_FORCE_SSL); + scopes.add(YouTubeScopes.YOUTUBE); + + try { + // Authorize the request. + Credential credential = Auth.authorize(scopes, "insertlivechatmessage"); + + // This object is used to make YouTube Data API requests. + youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential) + .setApplicationName("youtube-cmdline-insertchatmessage-sample").build(); + + // Get the liveChatId + String liveChatId = GetLiveChatId.getLiveChatId( + youtube, + args.length == 2 ? args[1] : null); + if (liveChatId != null) { + System.out.println("Live chat id: " + liveChatId); + } else { + System.err.println("Unable to find a live chat id"); + System.exit(1); + } + + // Insert the message into live chat + LiveChatMessage liveChatMessage = new LiveChatMessage(); + LiveChatMessageSnippet snippet = new LiveChatMessageSnippet(); + snippet.setType("textMessageEvent"); + snippet.setLiveChatId(liveChatId); + snippet.setDisplayMessage(message); + LiveChatTextMessageDetails details = new LiveChatTextMessageDetails(); + details.setMessageText(message); + snippet.setTextMessageDetails(details); + liveChatMessage.setSnippet(snippet); + YouTube.LiveChatMessages.Insert liveChatInsert = + youtube.liveChatMessages().insert("snippet", liveChatMessage); + LiveChatMessage response = liveChatInsert.execute(); + System.out.println("Inserted message id " + response.getId()); + } catch (GoogleJsonResponseException e) { + System.err + .println("GoogleJsonResponseException code: " + e.getDetails().getCode() + " : " + + e.getDetails().getMessage()); + e.printStackTrace(); + } catch (IOException e) { + System.err.println("IOException: " + e.getMessage()); + e.printStackTrace(); + } catch (Throwable t) { + System.err.println("Throwable: " + t.getMessage()); + t.printStackTrace(); + } + } +} diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java new file mode 100644 index 00000000..223915c0 --- /dev/null +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.api.services.samples.youtube.cmdline.live; + +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.googleapis.json.GoogleJsonResponseException; +import com.google.api.services.samples.youtube.cmdline.Auth; +import com.google.api.services.youtube.YouTube; +import com.google.api.services.youtube.YouTubeScopes; +import com.google.api.services.youtube.model.LiveChatMessage; +import com.google.api.services.youtube.model.LiveChatMessageAuthorDetails; +import com.google.api.services.youtube.model.LiveChatMessageListResponse; +import com.google.api.services.youtube.model.LiveChatMessageSnippet; +import com.google.api.services.youtube.model.LiveChatSuperChatDetails; +import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +/** + * Lists live chat messages and SuperChat details from a live broadcast. + * + * The videoId is often included in the video's url, e.g.: + * https://www.youtube.com/watch?v=L5Xc93_ZL60 + * ^ videoId + * The video URL may be found in the browser address bar, or by right-clicking a video and selecting + * Copy video URL from the context menu. + * + * @author Jim Rogers + */ +public class ListLiveChatMessages { + + /** + * Common fields to retrieve for chat messages + */ + private static final String LIVE_CHAT_FIELDS = + "items(authorDetails(channelId,displayName,isChatModerator,isChatOwner,isChatSponsor," + + "profileImageUrl),snippet(displayMessage,superChatDetails,publishedAt))," + + "nextPageToken,pollingIntervalMillis"; + + /** + * Define a global instance of a Youtube object, which will be used + * to make YouTube Data API requests. + */ + private static YouTube youtube; + + /** + * A timer used to schedule message retrieval. + */ + private static Timer pollTimer; + + /** + * Lists live chat messages and SuperChat details from a live broadcast. + * + * @param args videoId (optional). If the videoId is given, live chat messages will be retrieved + * from the chat associated with this video. If the videoId is not specified, the signed in + * user's current live broadcast will be used instead. + */ + public static void main(String[] args) { + + // This OAuth 2.0 access scope allows for read-only access to the + // authenticated user's account, but not other types of account access. + List scopes = Lists.newArrayList(YouTubeScopes.YOUTUBE_READONLY); + + try { + // Authorize the request. + Credential credential = Auth.authorize(scopes, "listlivechatmessages"); + + // This object is used to make YouTube Data API requests. + youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential) + .setApplicationName("youtube-cmdline-listchatmessages-sample").build(); + + // Get the liveChatId + String liveChatId = GetLiveChatId.getLiveChatId( + youtube, + args.length == 1 ? args[0] : null); + if (liveChatId != null) { + System.out.println("Live chat id: " + liveChatId); + } else { + System.err.println("Unable to find a live chat id"); + System.exit(1); + } + + /** + * List live chat messages with poll interval from server. Alternatively, messages + * may be requested at a fixed interval with listChatMessagesFixedPeriod, e.g. + * listChatMessagesFixedPeriod(liveChatId, 1000, 0) + */ + listChatMessages(liveChatId, null, 0); + } catch (GoogleJsonResponseException e) { + System.err + .println("GoogleJsonResponseException code: " + e.getDetails().getCode() + " : " + + e.getDetails().getMessage()); + e.printStackTrace(); + + } catch (IOException e) { + System.err.println("IOException: " + e.getMessage()); + e.printStackTrace(); + } catch (Throwable t) { + System.err.println("Throwable: " + t.getMessage()); + t.printStackTrace(); + } + } + + /** + * Lists live chat messages, polling at the server supplied interval. + * + * @param liveChatId The live chat id to list messages from. + * @param nextPageToken The page token from the previous request, if any. + * @param delayMs The delay in milliseconds before making the request. + */ + private static void listChatMessages( + final String liveChatId, + final String nextPageToken, + long delayMs) { + System.out.println( + String.format("Getting chat messages in %1$.3f seconds...", delayMs * 0.001)); + pollTimer = new Timer(); + pollTimer.schedule( + new TimerTask() { + @Override + public void run() { + try { + // Get chat messages from YouTube + LiveChatMessageListResponse response = youtube + .liveChatMessages() + .list(liveChatId, "snippet, authorDetails") + .setPageToken(nextPageToken) + .setFields(LIVE_CHAT_FIELDS) + .execute(); + + // Display messages and super chat details + List messages = response.getItems(); + for (int i = 0; i < messages.size(); i++) { + LiveChatMessage message = messages.get(i); + LiveChatMessageSnippet snippet = message.getSnippet(); + System.out.println(buildOutput( + snippet.getDisplayMessage(), + message.getAuthorDetails(), + snippet.getSuperChatDetails())); + } + + // Request the next page of messages + listChatMessages( + liveChatId, + response.getNextPageToken(), + response.getPollingIntervalMillis()); + } catch (Throwable t) { + System.err.println("Throwable: " + t.getMessage()); + t.printStackTrace(); + } + } + }, delayMs); + } + + /** + * Lists live chat messages, polling at the client supplied interval. This method is not + * recommended because it will consume more API usage, but it may be necessary in some + * applications that require lower latency. Page tokens do not work when polling faster than the + * server supplied interval, so we need to keep track of the publish time to avoid duplicate + * message output. Message ids will not work for tracking the last received message because + * messages may be removed from chat. + * + * @param liveChatId The live chat id to list messages from. + * @param periodMs The fixed interval to poll messages. + * @param minPublishTime The minimum message time to output. + */ + private static void listChatMessagesFixedPeriod( + final String liveChatId, + final long periodMs, + final long minPublishTime) { + System.out.println( + String.format("Getting chat messages in %1$.3f seconds...", periodMs * 0.001)); + pollTimer = new Timer(); + pollTimer.schedule( + new TimerTask() { + @Override + public void run() { + try { + // Get chat messages from YouTube + LiveChatMessageListResponse response = youtube + .liveChatMessages() + .list(liveChatId, "snippet, authorDetails") + .setFields(LIVE_CHAT_FIELDS) + .execute(); + + // Display messages and super chat details + long maxPublishTime = minPublishTime; + List messages = response.getItems(); + for (int i = 0; i < messages.size(); i++) { + LiveChatMessage message = messages.get(i); + LiveChatMessageSnippet snippet = message.getSnippet(); + long publishTime = snippet.getPublishedAt().getValue(); + if (publishTime >= minPublishTime) { + System.out.println(buildOutput( + snippet.getDisplayMessage(), + message.getAuthorDetails(), + snippet.getSuperChatDetails())); + } + maxPublishTime = Math.max(maxPublishTime, publishTime); + } + + // Request the next page of messages + listChatMessagesFixedPeriod(liveChatId, periodMs, maxPublishTime + 1); + } catch (Throwable t) { + System.err.println("Throwable: " + t.getMessage()); + t.printStackTrace(); + } + } + }, periodMs); + } + + /** + * Formats a chat message for console output. + * + * @param message The display message to output. + * @param author The author of the message. + * @param superChatDetails SuperChat details associated with the message. + * @return A formatted string for console output. + */ + private static String buildOutput( + String message, + LiveChatMessageAuthorDetails author, + LiveChatSuperChatDetails superChatDetails) { + StringBuilder output = new StringBuilder(); + if (superChatDetails != null) { + output.append(superChatDetails.getAmountDisplayString()); + output.append("SUPERCHAT RECEIVED FROM "); + } + output.append(author.getDisplayName()); + if (author.getIsChatOwner() || author.getIsChatOwner() || author.getIsChatSponsor()) { + output.append(" ("); + boolean appendComma = false; + if (author.getIsChatOwner()) { + output.append("OWNER"); + appendComma = true; + } + if (author.getIsChatModerator()) { + if (appendComma) { + output.append(", "); + } + output.append("MODERATOR"); + appendComma = true; + } + if (author.getIsChatSponsor()) { + if (appendComma) { + output.append(", "); + } + output.append("SPONSER"); + } + output.append(")"); + } + if (message != null && !message.isEmpty()) { + output.append(": "); + output.append(message); + } + return output.toString(); + } +} From 045e729e3eb1a1b7dc617eb7678ff6d40f50f1f5 Mon Sep 17 00:00:00 2001 From: Jim Rogers Date: Thu, 23 Mar 2017 13:32:02 -0700 Subject: [PATCH 057/126] Fix typo --- .../samples/youtube/cmdline/live/ListLiveChatMessages.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java index 223915c0..8bae1583 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java @@ -259,7 +259,7 @@ private static String buildOutput( if (appendComma) { output.append(", "); } - output.append("SPONSER"); + output.append("SPONSOR"); } output.append(")"); } From cb3a3813bf5e9b1efa39aa7223a4b79d01d50755 Mon Sep 17 00:00:00 2001 From: Jim Rogers Date: Thu, 23 Mar 2017 13:54:55 -0700 Subject: [PATCH 058/126] Apply formatting --- java/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/README.md b/java/README.md index bd7e0862..92256d2c 100644 --- a/java/README.md +++ b/java/README.md @@ -9,7 +9,7 @@ client ID and client secret. You can create an ID/secret pair at: To build this code sample from the command line, type: - mvn compile + mvn compile To run a code sample from the command line, enter the following: From e741fc278302a7b35058c80a2648af4a0e7181f4 Mon Sep 17 00:00:00 2001 From: Jim Rogers Date: Fri, 24 Mar 2017 14:45:57 -0700 Subject: [PATCH 059/126] Remove fixed period poll sample --- .../cmdline/live/ListLiveChatMessages.java | 73 +------------------ 1 file changed, 4 insertions(+), 69 deletions(-) diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java index 8bae1583..e9aac0a0 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java @@ -57,11 +57,6 @@ public class ListLiveChatMessages { */ private static YouTube youtube; - /** - * A timer used to schedule message retrieval. - */ - private static Timer pollTimer; - /** * Lists live chat messages and SuperChat details from a live broadcast. * @@ -94,11 +89,7 @@ public static void main(String[] args) { System.exit(1); } - /** - * List live chat messages with poll interval from server. Alternatively, messages - * may be requested at a fixed interval with listChatMessagesFixedPeriod, e.g. - * listChatMessagesFixedPeriod(liveChatId, 1000, 0) - */ + // Get live chat messages listChatMessages(liveChatId, null, 0); } catch (GoogleJsonResponseException e) { System.err @@ -116,7 +107,8 @@ public static void main(String[] args) { } /** - * Lists live chat messages, polling at the server supplied interval. + * Lists live chat messages, polling at the server supplied interval. Owners and moderators of a + * live chat will poll at a faster rate. * * @param liveChatId The live chat id to list messages from. * @param nextPageToken The page token from the previous request, if any. @@ -128,7 +120,7 @@ private static void listChatMessages( long delayMs) { System.out.println( String.format("Getting chat messages in %1$.3f seconds...", delayMs * 0.001)); - pollTimer = new Timer(); + Timer pollTimer = new Timer(); pollTimer.schedule( new TimerTask() { @Override @@ -166,63 +158,6 @@ public void run() { }, delayMs); } - /** - * Lists live chat messages, polling at the client supplied interval. This method is not - * recommended because it will consume more API usage, but it may be necessary in some - * applications that require lower latency. Page tokens do not work when polling faster than the - * server supplied interval, so we need to keep track of the publish time to avoid duplicate - * message output. Message ids will not work for tracking the last received message because - * messages may be removed from chat. - * - * @param liveChatId The live chat id to list messages from. - * @param periodMs The fixed interval to poll messages. - * @param minPublishTime The minimum message time to output. - */ - private static void listChatMessagesFixedPeriod( - final String liveChatId, - final long periodMs, - final long minPublishTime) { - System.out.println( - String.format("Getting chat messages in %1$.3f seconds...", periodMs * 0.001)); - pollTimer = new Timer(); - pollTimer.schedule( - new TimerTask() { - @Override - public void run() { - try { - // Get chat messages from YouTube - LiveChatMessageListResponse response = youtube - .liveChatMessages() - .list(liveChatId, "snippet, authorDetails") - .setFields(LIVE_CHAT_FIELDS) - .execute(); - - // Display messages and super chat details - long maxPublishTime = minPublishTime; - List messages = response.getItems(); - for (int i = 0; i < messages.size(); i++) { - LiveChatMessage message = messages.get(i); - LiveChatMessageSnippet snippet = message.getSnippet(); - long publishTime = snippet.getPublishedAt().getValue(); - if (publishTime >= minPublishTime) { - System.out.println(buildOutput( - snippet.getDisplayMessage(), - message.getAuthorDetails(), - snippet.getSuperChatDetails())); - } - maxPublishTime = Math.max(maxPublishTime, publishTime); - } - - // Request the next page of messages - listChatMessagesFixedPeriod(liveChatId, periodMs, maxPublishTime + 1); - } catch (Throwable t) { - System.err.println("Throwable: " + t.getMessage()); - t.printStackTrace(); - } - } - }, periodMs); - } - /** * Formats a chat message for console output. * From 518a2d355aaf7ce235b912ab72a6ae8df46ae223 Mon Sep 17 00:00:00 2001 From: Jim Rogers Date: Fri, 24 Mar 2017 15:12:07 -0700 Subject: [PATCH 060/126] Fix output for moderators --- .../samples/youtube/cmdline/live/ListLiveChatMessages.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java index e9aac0a0..8954ffaa 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java @@ -176,7 +176,7 @@ private static String buildOutput( output.append("SUPERCHAT RECEIVED FROM "); } output.append(author.getDisplayName()); - if (author.getIsChatOwner() || author.getIsChatOwner() || author.getIsChatSponsor()) { + if (author.getIsChatOwner() || author.getIsChatModerator() || author.getIsChatSponsor()) { output.append(" ("); boolean appendComma = false; if (author.getIsChatOwner()) { From cf7f9b3159c93f127fac853397e519004a250897 Mon Sep 17 00:00:00 2001 From: Jim Rogers Date: Tue, 28 Mar 2017 11:02:08 -0700 Subject: [PATCH 061/126] Clean up from CR feedback --- java/README.md | 17 +++-- .../cmdline/live/DeleteLiveChatMessage.java | 20 +----- .../youtube/cmdline/live/GetLiveChatId.java | 71 +++++++++++-------- .../cmdline/live/InsertLiveChatMessage.java | 16 ++--- .../cmdline/live/ListLiveChatMessages.java | 40 +++++------ 5 files changed, 76 insertions(+), 88 deletions(-) diff --git a/java/README.md b/java/README.md index 92256d2c..d9baaf89 100644 --- a/java/README.md +++ b/java/README.md @@ -218,7 +218,7 @@ job. 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 +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) @@ -245,24 +245,23 @@ 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.list
    -Description: This sample retrieves a live chat id from either a videoId parameter -or the current user's live broadcast. The liveChatId is required for other samples +Description: This sample retrieves the live chat ID from either a videoId 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.insert
    -Description: This sample inserts a live chat message into the live chat specified by either -a videoId parameter or the current user's live broadcast. +Description: This sample inserts a live chat message into the the specified video or the live broadcast for +the authorized user's channel. ### [Delete a live chat message](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java) Method: youtube.liveChatMessages.delete
    -Description: This sample deletes a live chat message from the live chat specified by either -a videoId parameter or the current user's live broadcast. +Description: This sample deletes the specified live chat message. ### [List live chat messages](/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java) Method: youtube.liveChatMessages.list
    -Description: This sample lists live chat messages from the chat specified by either -a videoId parameter or the current user's live broadcast. +Description: This sample lists live chat messages from the specified video or from the live broadcast for +the authorized user's channel. diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java index a081fb12..51721623 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/DeleteLiveChatMessage.java @@ -19,8 +19,8 @@ import com.google.api.services.samples.youtube.cmdline.Auth; import com.google.api.services.youtube.YouTube; import com.google.api.services.youtube.YouTubeScopes; +import com.google.common.collect.Lists; import java.io.IOException; -import java.util.ArrayList; import java.util.List; /** @@ -52,11 +52,8 @@ public static void main(String[] args) { } String messageId = args[0]; - // This OAuth 2.0 access scope allows for read-only access to the - // authenticated user's account, but not other types of account access. - List scopes = new ArrayList(); - scopes.add(YouTubeScopes.YOUTUBE_FORCE_SSL); - scopes.add(YouTubeScopes.YOUTUBE); + // This OAuth 2.0 access scope allows for write access to the authenticated user's account. + List scopes = Lists.newArrayList(YouTubeScopes.YOUTUBE_FORCE_SSL); try { // Authorize the request. @@ -66,17 +63,6 @@ public static void main(String[] args) { youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential) .setApplicationName("youtube-cmdline-deletechatmessages-sample").build(); - // Get the liveChatId - String liveChatId = GetLiveChatId.getLiveChatId( - youtube, - args.length == 2 ? args[1] : null); - if (liveChatId != null) { - System.out.println("Live chat id: " + liveChatId); - } else { - System.err.println("Unable to find a live chat id"); - System.exit(1); - } - // Delete the message from live chat YouTube.LiveChatMessages.Delete liveChatDelete = youtube.liveChatMessages().delete(messageId); diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java index 0a5b71a0..31602a05 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java @@ -68,7 +68,9 @@ public static void main(String[] args) { .setApplicationName("youtube-cmdline-getlivechatid-sample").build(); // Get the liveChatId - String liveChatId = getLiveChatId(youtube, args.length == 1 ? args[0] : null); + String liveChatId = args.length == 1 + ? getLiveChatId(youtube, args[0]) + : getLiveChatId(youtube); if (liveChatId != null) { System.out.println("Live chat id: " + liveChatId); } else { @@ -91,41 +93,48 @@ public static void main(String[] args) { } /** - * Retrieves the liveChatId from the videoId, if specified. If not specified, will find the - * liveChatId for the signed in user's live broadcast. + * Retrieves the liveChatId from the authenticated user's live broadcast. * * @param youtube The object is used to make YouTube Data API requests. - * @param videoId The videoId associated with the live chat (optional). * @return A liveChatId, or null if not found. */ - static String getLiveChatId(YouTube youtube, String videoId) throws IOException { - if (videoId != null && !videoId.isEmpty()) { - // Get liveChatId from the video - YouTube.Videos.List videoList = youtube.videos() - .list("liveStreamingDetails") - .setFields("items/liveStreamingDetails/activeLiveChatId") - .setId(videoId); - VideoListResponse response = videoList.execute(); - for (Video v : response.getItems()) { - String liveChatId = v.getLiveStreamingDetails().getActiveLiveChatId(); - if (liveChatId != null && !liveChatId.isEmpty()) { - return liveChatId; - } + static String getLiveChatId(YouTube youtube) throws IOException { + // Get signed in user's liveChatId + YouTube.LiveBroadcasts.List broadcastList = youtube + .liveBroadcasts() + .list("snippet") + .setFields("items/snippet/liveChatId") + .setBroadcastType("all") + .setBroadcastStatus("active"); + LiveBroadcastListResponse broadcastListResponse = broadcastList.execute(); + for (LiveBroadcast b : broadcastListResponse.getItems()) { + String liveChatId = b.getSnippet().getLiveChatId(); + if (liveChatId != null && !liveChatId.isEmpty()) { + return liveChatId; } - } else { - // Get signed in user's liveChatId - YouTube.LiveBroadcasts.List broadcastList = youtube - .liveBroadcasts() - .list("snippet") - .setFields("items/snippet/liveChatId") - .setBroadcastType("all") - .setBroadcastStatus("active"); - LiveBroadcastListResponse broadcastListResponse = broadcastList.execute(); - for (LiveBroadcast b : broadcastListResponse.getItems()) { - String liveChatId = b.getSnippet().getLiveChatId(); - if (liveChatId != null && !liveChatId.isEmpty()) { - return liveChatId; - } + } + + return null; + } + + /** + * Retrieves the liveChatId from the broadcast associated with a videoId. + * + * @param youtube The object is used to make YouTube Data API requests. + * @param videoId The videoId associated with the live broadcast. + * @return A liveChatId, or null if not found. + */ + static String getLiveChatId(YouTube youtube, String videoId) throws IOException { + // Get liveChatId from the video + YouTube.Videos.List videoList = youtube.videos() + .list("liveStreamingDetails") + .setFields("items/liveStreamingDetails/activeLiveChatId") + .setId(videoId); + VideoListResponse response = videoList.execute(); + for (Video v : response.getItems()) { + String liveChatId = v.getLiveStreamingDetails().getActiveLiveChatId(); + if (liveChatId != null && !liveChatId.isEmpty()) { + return liveChatId; } } diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/InsertLiveChatMessage.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/InsertLiveChatMessage.java index e8e66f62..09fe059c 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/InsertLiveChatMessage.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/InsertLiveChatMessage.java @@ -22,8 +22,8 @@ import com.google.api.services.youtube.model.LiveChatMessage; import com.google.api.services.youtube.model.LiveChatMessageSnippet; import com.google.api.services.youtube.model.LiveChatTextMessageDetails; +import com.google.common.collect.Lists; import java.io.IOException; -import java.util.ArrayList; import java.util.List; /** @@ -61,11 +61,8 @@ public static void main(String[] args) { } String message = args[0]; - // This OAuth 2.0 access scope allows for read-only access to the - // authenticated user's account, but not other types of account access. - List scopes = new ArrayList(); - scopes.add(YouTubeScopes.YOUTUBE_FORCE_SSL); - scopes.add(YouTubeScopes.YOUTUBE); + // This OAuth 2.0 access scope allows for write access to the authenticated user's account. + List scopes = Lists.newArrayList(YouTubeScopes.YOUTUBE_FORCE_SSL); try { // Authorize the request. @@ -76,9 +73,9 @@ public static void main(String[] args) { .setApplicationName("youtube-cmdline-insertchatmessage-sample").build(); // Get the liveChatId - String liveChatId = GetLiveChatId.getLiveChatId( - youtube, - args.length == 2 ? args[1] : null); + String liveChatId = args.length == 2 + ? GetLiveChatId.getLiveChatId(youtube, args[1]) + : GetLiveChatId.getLiveChatId(youtube); if (liveChatId != null) { System.out.println("Live chat id: " + liveChatId); } else { @@ -91,7 +88,6 @@ public static void main(String[] args) { LiveChatMessageSnippet snippet = new LiveChatMessageSnippet(); snippet.setType("textMessageEvent"); snippet.setLiveChatId(liveChatId); - snippet.setDisplayMessage(message); LiveChatTextMessageDetails details = new LiveChatTextMessageDetails(); details.setMessageText(message); snippet.setTextMessageDetails(details); diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java index 8954ffaa..463326ed 100644 --- a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/ListLiveChatMessages.java @@ -26,6 +26,7 @@ import com.google.api.services.youtube.model.LiveChatSuperChatDetails; import com.google.common.collect.Lists; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; @@ -79,9 +80,9 @@ public static void main(String[] args) { .setApplicationName("youtube-cmdline-listchatmessages-sample").build(); // Get the liveChatId - String liveChatId = GetLiveChatId.getLiveChatId( - youtube, - args.length == 1 ? args[0] : null); + String liveChatId = args.length == 1 + ? GetLiveChatId.getLiveChatId(youtube, args[0]) + : GetLiveChatId.getLiveChatId(youtube); if (liveChatId != null) { System.out.println("Live chat id: " + liveChatId); } else { @@ -176,25 +177,22 @@ private static String buildOutput( output.append("SUPERCHAT RECEIVED FROM "); } output.append(author.getDisplayName()); - if (author.getIsChatOwner() || author.getIsChatModerator() || author.getIsChatSponsor()) { + List roles = new ArrayList(); + if (author.getIsChatOwner()) { + roles.add("OWNER"); + } + if (author.getIsChatModerator()) { + roles.add("MODERATOR"); + } + if (author.getIsChatSponsor()) { + roles.add("SPONSOR"); + } + if (roles.size() > 0) { output.append(" ("); - boolean appendComma = false; - if (author.getIsChatOwner()) { - output.append("OWNER"); - appendComma = true; - } - if (author.getIsChatModerator()) { - if (appendComma) { - output.append(", "); - } - output.append("MODERATOR"); - appendComma = true; - } - if (author.getIsChatSponsor()) { - if (appendComma) { - output.append(", "); - } - output.append("SPONSOR"); + String delim = ""; + for (String role : roles) { + output.append(delim).append(role); + delim = ", "; } output.append(")"); } From f37fb9f4288a780b90860f8c81bb75da672a01f8 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 24 Apr 2017 14:35:19 -0400 Subject: [PATCH 062/126] Add file for coming-soon PHP quickstart guide. --- php/quickstart.php | 113 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 php/quickstart.php diff --git a/php/quickstart.php b/php/quickstart.php new file mode 100644 index 00000000..94c6477f --- /dev/null +++ b/php/quickstart.php @@ -0,0 +1,113 @@ +setAuthConfigFile('client_secrets.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')); +?> From 55bf40114f1cd9e1c4d1da246fe1d55707695c8d Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 24 Apr 2017 16:50:49 -0400 Subject: [PATCH 063/126] Add file for coming-soon Python quickstart guide. --- python/quickstart.py | 61 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 python/quickstart.py diff --git a/python/quickstart.py b/python/quickstart.py new file mode 100644 index 00000000..3ada92ef --- /dev/null +++ b/python/quickstart.py @@ -0,0 +1,61 @@ +# Sample Python code for user authorization + +import httplib2 +import os +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 + +# 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. +CLIENT_SECRETS_FILE = "client_secret.json" + +# This OAuth 2.0 access scope allows for full read/write access to the +# authenticated user's account and requires requests to use an SSL connection. +YOUTUBE_READ_WRITE_SSL_SCOPE = "https://www.googleapis.com/auth/youtube.readonly" +API_SERVICE_NAME = "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" + +# Authorize the request and store authorization credentials. +def get_authenticated_service(args): + flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_READ_WRITE_SSL_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) + + # Trusted testers can download this discovery document from the developers page + # and it should be in the same directory with the code. + return build(API_SERVICE_NAME, API_VERSION, + http=credentials.authorize(httplib2.Http())) + +args = argparser.parse_args() +service = get_authenticated_service(args) + +### END BOILERPLATE CODE + +# Sample python code for channels.list + +def channels_list_by_username(service, **kwargs): + results = service.channels().list( + **kwargs + ).execute() + + print('This channel\'s ID is %s. Its title is %s, and it has %s views.' % + (results['items'][0]['id'], + results['items'][0]['snippet']['title'], + results['items'][0]['statistics']['viewCount'])) + +channels_list_by_username(service, part='snippet,contentDetails,statistics', forUsername='GoogleDevelopers') From 53c6d50a1872c71b49c6c6104572aa8db5585f3f Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 24 Apr 2017 17:29:34 -0400 Subject: [PATCH 064/126] Add file for coming-soon Ruby quickstart guide. --- ruby/quickstart.rb | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 ruby/quickstart.rb 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') From d810b927c243db04ffcf6eff0d58ab1b79f13222 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 24 Apr 2017 18:07:25 -0400 Subject: [PATCH 065/126] Add file for coming-soon Go quickstart guide. --- go/quickstart.go | 140 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 go/quickstart.go diff --git a/go/quickstart.go b/go/quickstart.go new file mode 100644 index 00000000..7e3687c8 --- /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("quickstart_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") +} From f66c00abdf854da3dccc7c0ec17f1a34a9cdae47 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Mon, 24 Apr 2017 18:11:39 -0400 Subject: [PATCH 066/126] Fix name of client_secret.json file in example. --- go/quickstart.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/quickstart.go b/go/quickstart.go index 7e3687c8..dc5d83d3 100644 --- a/go/quickstart.go +++ b/go/quickstart.go @@ -120,7 +120,7 @@ func channelsListByUsername(service *youtube.Service, part string, forUsername s func main() { ctx := context.Background() - b, err := ioutil.ReadFile("quickstart_client_secret.json") + b, err := ioutil.ReadFile("client_secret.json") if err != nil { log.Fatalf("Unable to read client secret file: %v", err) } From b9e6a9aea0a97d8300271a3c8c0668ac88d6a246 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 25 Apr 2017 10:47:29 -0400 Subject: [PATCH 067/126] Add file for coming-soon Java quickstart guide. --- .../youtube/cmdline/data/Quickstart.java | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Quickstart.java diff --git a/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Quickstart.java b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Quickstart.java new file mode 100644 index 00000000..efefe20b --- /dev/null +++ b/java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Quickstart.java @@ -0,0 +1,119 @@ +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp; +import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; +import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; +import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonResponseException; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.util.store.FileDataStoreFactory; + +import com.google.api.services.youtube.YouTubeScopes; +import com.google.api.services.youtube.model.*; +import com.google.api.services.youtube.YouTube; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; + + +public class Quickstart { + + /** Application name. */ + private static final String APPLICATION_NAME = "API Sample"; + + /** Directory to store user credentials for this application. */ + private static final java.io.File DATA_STORE_DIR = new java.io.File( + System.getProperty("user.home"), ".credentials/youtube-java-quickstart"); + + /** Global instance of the {@link FileDataStoreFactory}. */ + private static FileDataStoreFactory DATA_STORE_FACTORY; + + /** Global instance of the JSON factory. */ + private static final JsonFactory JSON_FACTORY = + JacksonFactory.getDefaultInstance(); + + /** Global instance of the HTTP transport. */ + private static HttpTransport HTTP_TRANSPORT; + + /** Global instance of the scopes required by this quickstart. + * + * If modifying these scopes, delete your previously saved credentials + * at ~/.credentials/drive-java-quickstart + */ + private static final List SCOPES = + Arrays.asList(YouTubeScopes.YOUTUBE_READONLY); + + static { + try { + HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport(); + DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR); + } catch (Throwable t) { + t.printStackTrace(); + System.exit(1); + } + } + + /** + * Create an authorized Credential object. + * @return an authorized Credential object. + * @throws IOException + */ + public static Credential authorize() throws IOException { + // Load client secrets. + InputStream in = + Quickstart.class.getResourceAsStream("/client_secret.json"); + GoogleClientSecrets clientSecrets = + GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in)); + + // Build flow and trigger user authorization request. + GoogleAuthorizationCodeFlow flow = + new GoogleAuthorizationCodeFlow.Builder( + HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES) + .setDataStoreFactory(DATA_STORE_FACTORY) + .setAccessType("offline") + .build(); + Credential credential = new AuthorizationCodeInstalledApp( + flow, new LocalServerReceiver()).authorize("user"); + return credential; + } + + /** + * Build and return an authorized API client service, such as a YouTube + * Data API client service. + * @return an authorized API client service + * @throws IOException + */ + public static YouTube getYouTubeService() throws IOException { + Credential credential = authorize(); + return new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential) + .setApplicationName(APPLICATION_NAME) + .build(); + } + + public static void main(String[] args) throws IOException { + YouTube youtube = getYouTubeService(); + try { + YouTube.Channels.List channelsListByUsernameRequest = youtube.channels().list("snippet,contentDetails,statistics"); + channelsListByUsernameRequest.setForUsername("GoogleDevelopers"); + + ChannelListResponse response = channelsListByUsernameRequest.execute(); + Channel channel = response.getItems().get(0); + System.out.printf( + "This channel's ID is %s. Its title is '%s', and it has %s views.\n", + channel.getId(), + channel.getSnippet().getTitle(), + channel.getStatistics().getViewCount()); + } catch (GoogleJsonResponseException e) { + e.printStackTrace(); + System.err.println("There was a service error: " + + e.getDetails().getCode() + " : " + e.getDetails().getMessage()); + } catch (Throwable t) { + t.printStackTrace(); + } + } +} From 47c49fed14859957ed74fd2706259935937eb885 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 25 Apr 2017 11:33:47 -0400 Subject: [PATCH 068/126] Add file for coming-soon JS quickstart guide. --- javascript/quickstart.html | 120 +++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 javascript/quickstart.html 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 + + + +

    YouTube Data API Quickstart

    + + + + + +
    
    +
    +    
    +
    +    
    +  
    +
    
    From 954f7e0cc35b03b03adca7557128e083df76a9c0 Mon Sep 17 00:00:00 2001
    From: Andy Diamondstein 
    Date: Tue, 25 Apr 2017 12:02:34 -0400
    Subject: [PATCH 069/126] Add file for coming-soon node.js quickstart guide.
    
    ---
     javascript/nodejs-quickstart.js | 124 ++++++++++++++++++++++++++++++++
     1 file changed, 124 insertions(+)
     create mode 100644 javascript/nodejs-quickstart.js
    
    diff --git a/javascript/nodejs-quickstart.js b/javascript/nodejs-quickstart.js
    new file mode 100644
    index 00000000..4e9f26a4
    --- /dev/null
    +++ b/javascript/nodejs-quickstart.js
    @@ -0,0 +1,124 @@
    +var fs = require('fs');
    +var readline = require('readline');
    +var google = require('googleapis');
    +var googleAuth = require('google-auth-library');
    +
    +// 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 auth = new googleAuth();
    +  var oauth2Client = new auth.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));
    +  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.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);
    +    }
    +  });
    +}
    
    From 875d380396ba5771322f7d1bf678bbf42b63ecc6 Mon Sep 17 00:00:00 2001
    From: Andy Diamondstein 
    Date: Tue, 25 Apr 2017 13:58:36 -0400
    Subject: [PATCH 070/126] Add file for coming-soon Apps Script quickstart
     guide.
    
    ---
     apps-script/quickstart.gs | 36 ++++++++++++++++++++++++++++++++++++
     1 file changed, 36 insertions(+)
     create mode 100644 apps-script/quickstart.gs
    
    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();
    +}
    
    From 51ee11451eb1b7d22a4d390d0c458984b0d6f2d5 Mon Sep 17 00:00:00 2001
    From: Daniel Zahariev 
    Date: Wed, 7 Jun 2017 15:32:14 +0300
    Subject: [PATCH 071/126] Fix report downloading in PHP example #70
    
    ---
     php/retrieve_reports.php | 6 +++---
     1 file changed, 3 insertions(+), 3 deletions(-)
    
    diff --git a/php/retrieve_reports.php b/php/retrieve_reports.php
    index f5b71fb2..8c5aa17e 100644
    --- a/php/retrieve_reports.php
    +++ b/php/retrieve_reports.php
    @@ -167,11 +167,11 @@ function downloadReport(Google_Service_YouTubeReporting $youtubeReporting, $repo
       $client->setDefer(true);
     
       // Call the YouTube Reporting API's media.download method to download a report.
    -  $request = $youtubeReporting->media->download("");
    -  $request->setUrl($reportUrl);
    +  $request = $youtubeReporting->media->download("", array("alt" => "media"));
    +  $request = $request->withUri(new \GuzzleHttp\Psr7\Uri($reportUrl));
       $response = $client->execute($request);
     
    -  file_put_contents("reportFile", $response->getResponseBody());
    +  file_put_contents("reportFile", $response->getBody());
       $client->setDefer(false);
     }
     ?>
    
    From c086040967207efb7efd4b109edfc97f25a7fe89 Mon Sep 17 00:00:00 2001
    From: Andy Diamondstein 
    Date: Tue, 20 Jun 2017 10:33:23 -0400
    Subject: [PATCH 072/126] Fix require autoload.php statement.
    
    ---
     php/quickstart.php | 11 +++++------
     1 file changed, 5 insertions(+), 6 deletions(-)
    
    diff --git a/php/quickstart.php b/php/quickstart.php
    index 94c6477f..c85fa59f 100644
    --- a/php/quickstart.php
    +++ b/php/quickstart.php
    @@ -1,11 +1,10 @@
     setRedirectUri('http://localhost');
     
    -  $client->addScope(GOOGLE_SERVICE_YOUTUBE::YOUTUBE_READONLY);
    +  $client->addScope(Google_Service_YouTube::YOUTUBE_READONLY);
       $client->setAccessType('offline');
     
       // Load previously authorized credentials from a file.
    
    From 6a4c3b283ce9e59e64e803173ddb5c35936b6e19 Mon Sep 17 00:00:00 2001
    From: Andy Diamondstein 
    Date: Tue, 20 Jun 2017 10:38:29 -0400
    Subject: [PATCH 073/126] Fix name of client_secret.json file.
    
    ---
     php/quickstart.php | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/php/quickstart.php b/php/quickstart.php
    index c85fa59f..0af550ff 100644
    --- a/php/quickstart.php
    +++ b/php/quickstart.php
    @@ -16,8 +16,8 @@
     
     function getClient() {
       $client = new Google_Client();
    -  // Set to name/location of your client_secrets.json file.
    -  $client->setAuthConfigFile('client_secrets.json');
    +  // Set to name/location of your client_secret.json file.
    +  $client->setAuthConfigFile('client_secret.json');
       // Set to valid redirect URI for your project.
       $client->setRedirectUri('http://localhost');
     
    
    From 84b332b42b2002bc51fa58d485a9b89692b5a8c9 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Nick=20J=C3=BCttner?= 
    Date: Sun, 16 Jul 2017 12:23:22 +0200
    Subject: [PATCH 074/126] replace old package paths
    
    ---
     go/my_uploads.go        | 2 +-
     go/post_bulletin.go     | 2 +-
     go/search_by_keyword.go | 4 ++--
     go/upload_video.go      | 2 +-
     4 files changed, 5 insertions(+), 5 deletions(-)
    
    diff --git a/go/my_uploads.go b/go/my_uploads.go
    index cdddbf87..dec398d7 100644
    --- a/go/my_uploads.go
    +++ b/go/my_uploads.go
    @@ -5,7 +5,7 @@ import (
     	"fmt"
     	"log"
     
    -	"code.google.com/p/google-api-go-client/youtube/v3"
    +	"google.golang.org/api/youtube/v3"
     )
     
     func main() {
    diff --git a/go/post_bulletin.go b/go/post_bulletin.go
    index e76d06c7..aa7c5fa0 100644
    --- a/go/post_bulletin.go
    +++ b/go/post_bulletin.go
    @@ -5,7 +5,7 @@ import (
     	"fmt"
     	"log"
     
    -	"code.google.com/p/google-api-go-client/youtube/v3"
    +	"google.golang.org/api/youtube/v3"
     )
     
     var (
    diff --git a/go/search_by_keyword.go b/go/search_by_keyword.go
    index 38fa7fb6..93132a44 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 (
    diff --git a/go/upload_video.go b/go/upload_video.go
    index 04d3ed5f..1879ff95 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 (
    
    From 8045ac23b73edfe9f9bed2924c8d5452801006ac Mon Sep 17 00:00:00 2001
    From: Andy Diamondstein 
    Date: Fri, 11 Aug 2017 11:34:57 -0400
    Subject: [PATCH 075/126] Create oauth2.go file
    
    Update authorization example to show how to obtain code via web server or via command-line prompt.
    ---
     go/oauth2.go | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++
     1 file changed, 200 insertions(+)
     create mode 100644 go/oauth2.go
    
    diff --git a/go/oauth2.go b/go/oauth2.go
    new file mode 100644
    index 00000000..850304e1
    --- /dev/null
    +++ b/go/oauth2.go
    @@ -0,0 +1,200 @@
    +package main
    +
    +import (
    +	"encoding/json"
    +	"fmt"
    +	"log"
    +	"net"
    +	"net/http"
    +	"net/url"
    +	"os"
    +	"os/exec"
    +	"os/user"
    +	"path/filepath"
    +	"runtime"
    +
    +	"golang.org/x/net/context"
    +	"golang.org/x/oauth2"
    +)
    +
    +// 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(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 {
    +		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
    +}
    +
    +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)
    +}
    
    From 0edd15a44a82fdfbb64c0c4ab7348c94d8c7f1c8 Mon Sep 17 00:00:00 2001
    From: Andy Diamondstein 
    Date: Fri, 11 Aug 2017 11:45:46 -0400
    Subject: [PATCH 076/126] Remove old references to code.google.com
    
    Update README to remove obsolete references.
    ---
     go/README.md | 38 ++++++++++++++------------------------
     1 file changed, 14 insertions(+), 24 deletions(-)
    
    diff --git a/go/README.md b/go/README.md
    index 8f7a0035..08c50850 100644
    --- a/go/README.md
    +++ b/go/README.md
    @@ -1,53 +1,43 @@
     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 "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
     
     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.
    +https://developers.google.com/console.
     
     Example usage:
     
    -   go run search_key_keyword.go
    +   go run search\_by\_keyword.go
     
     The YouTube Data API 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.
    +for uploads, this requires the shared oauth2.go file to be passed as a parameter to "go run".
    +These samples require an OAuth 2.0 client ID and client secret pair, which can
    +also 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.
     
     Example usage:
     
    -   go run my_uploads.go oauth.go
    +   go run my\_uploads.go oauth2.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".
    +The **oauth2.go** file 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.
    +More information about the YouTube APIs can be found at https://developers.google.com/youtube.
     
     ## Samples in this directory:
     
    -### [Authorize a request](/go/oauth.go)
    +### [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.
     
    -### [Post a channel bulletin](/go/post_bulletin.go)
    -
    -Method: youtube.activities.insert
    -Description: This code sample calls the API's activities.insert method to post a bulletin to the -channel associated with the request. - ### [Retrieve my uploads](/go/my_uploads.go) Method: youtube.playlistItems.list
    From 08bd397ff23d9b136bb67a0bba71eaa0097f8b57 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 12:14:42 -0400 Subject: [PATCH 077/126] Move more auth logic to oauth2.go Move read of client_secret.json to oauth2.go and set RedirectURL there as well. --- go/oauth2.go | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/go/oauth2.go b/go/oauth2.go index 850304e1..a612999c 100644 --- a/go/oauth2.go +++ b/go/oauth2.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "fmt" + "io/ioutil" "log" "net" "net/http" @@ -15,6 +16,7 @@ import ( "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 @@ -54,8 +56,28 @@ 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(ctx context.Context, config *oauth2.Config) *http.Client { - cacheFile, err := tokenCacheFile() +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) } @@ -114,6 +136,7 @@ func openURL(url string) error { 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 { From fd21cdebf823878ca83d2e5f0a7df0d940852074 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 12:56:07 -0400 Subject: [PATCH 078/126] Update code to simplify auth flow --- go/my_uploads.go | 60 ++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/go/my_uploads.go b/go/my_uploads.go index dec398d7..216ce3cf 100644 --- a/go/my_uploads.go +++ b/go/my_uploads.go @@ -1,60 +1,54 @@ package main import ( - "flag" "fmt" "log" "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 From c8a19d23443882b5d05b629b803f158abc358f9c Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 12:57:47 -0400 Subject: [PATCH 079/126] Add simple error handler --- go/errors.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 go/errors.go 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()) + } +} From 4ed97339dd0b47aed88f8d5a7f99d8e80b517a83 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 13:08:24 -0400 Subject: [PATCH 080/126] Explain how to authorize requests and run samples Fix explanation of how to authorize requests and run samples. --- go/README.md | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/go/README.md b/go/README.md index 08c50850..d3d4aeb3 100644 --- a/go/README.md +++ b/go/README.md @@ -4,29 +4,37 @@ 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 -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://developers.google.com/console. +You also need to enable the YouTube Data API for the project associated with your developer +credentials. -Example usage: +## 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: -   go run search\_by\_keyword.go +``` +const developerKey = "YOUR DEVELOPER KEY" +``` -The YouTube Data API 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 oauth2.go file to be passed as a parameter to "go run". -These samples require an OAuth 2.0 client ID and client secret pair, which can -also be created at the Google API console at https://developers.google.com/console. After +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. -Example usage: +## 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: - go run my\_uploads.go oauth2.go +Example usages: -The **oauth2.go** file 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". +``` +   go run search\_by\_keyword.go errors.go + go run my\_uploads.go errors.go oauth2.go +``` More information about the YouTube APIs can be found at https://developers.google.com/youtube. From d42037722324803930737c609d8a26f81e37e24f Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 13:09:11 -0400 Subject: [PATCH 081/126] Recommend latest Go version --- go/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/README.md b/go/README.md index d3d4aeb3..ff9f8670 100644 --- a/go/README.md +++ b/go/README.md @@ -1,4 +1,4 @@ -Minimum Go version: go 1.1+ +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: From 4968ec0dae5dfcb5fdff4a575e702d7bf047306e Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 13:10:15 -0400 Subject: [PATCH 082/126] Retrieve my uploads also calls channels.list --- go/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/README.md b/go/README.md index ff9f8670..bf83cb08 100644 --- a/go/README.md +++ b/go/README.md @@ -48,7 +48,7 @@ then saves the returned credentials locally. ### [Retrieve my uploads](/go/my_uploads.go) -Method: youtube.playlistItems.list
    +Methods: youtube.channels.list, youtube.playlistItems.list
    Description: This 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 From df2ae7ca63534669f0e5259bb56812ea7ef40dd6 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 13:12:01 -0400 Subject: [PATCH 083/126] Delete obsolete version of oauth code Please refer to oauth2.go instead. --- go/oauth.go | 187 ---------------------------------------------------- 1 file changed, 187 deletions(-) delete mode 100644 go/oauth.go 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 -} From cdd3985b4e3128f768202ccc288977e7e98dd95c Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 13:12:51 -0400 Subject: [PATCH 084/126] Remove example using obsolete OAuth code --- go/post_bulletin.go | 82 --------------------------------------------- 1 file changed, 82 deletions(-) delete mode 100644 go/post_bulletin.go diff --git a/go/post_bulletin.go b/go/post_bulletin.go deleted file mode 100644 index aa7c5fa0..00000000 --- a/go/post_bulletin.go +++ /dev/null @@ -1,82 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "log" - - "google.golang.org/api/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.") -} From d4c68cb488e6b4aa6d454a618af0c62d1f185e72 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 14:29:06 -0400 Subject: [PATCH 085/126] Use standard error handler for API response --- go/search_by_keyword.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/go/search_by_keyword.go b/go/search_by_keyword.go index 93132a44..3c8f0b64 100644 --- a/go/search_by_keyword.go +++ b/go/search_by_keyword.go @@ -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) From 8f1af187d39691de8b22daccfcbb26fc253d4fcc Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 14:40:59 -0400 Subject: [PATCH 086/126] Update code to use newer oauth2.go file --- go/upload_video.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/go/upload_video.go b/go/upload_video.go index 1879ff95..24972c63 100644 --- a/go/upload_video.go +++ b/go/upload_video.go @@ -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) } From 788ebac9979ebdab558ee7d0373a07ec1aeb0f56 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 11 Aug 2017 14:42:59 -0400 Subject: [PATCH 087/126] Add example for upload_video.go to README --- go/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/go/README.md b/go/README.md index bf83cb08..956dc16b 100644 --- a/go/README.md +++ b/go/README.md @@ -32,8 +32,9 @@ that require authorization also require the `oauth2.go` file to be included in t Example usages: ``` -   go run search\_by\_keyword.go errors.go - go run my\_uploads.go errors.go oauth2.go +   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. From e869e9526600916e5c398b623e009d84e3dd5450 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 15 Aug 2017 11:05:22 -0400 Subject: [PATCH 088/126] Add sample for playlists.list method This sample shows how to use the playlists.list method. Use command-line flags to specify the query you want to run. --- go/playlists.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 go/playlists.go 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) + } +} From 720dc5c43f014d23168d697edcfc1e1d458e4864 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Tue, 15 Aug 2017 11:07:30 -0400 Subject: [PATCH 089/126] Update README.md --- go/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/go/README.md b/go/README.md index 956dc16b..f85a7847 100644 --- a/go/README.md +++ b/go/README.md @@ -47,6 +47,19 @@ Description: This code sample performs OAuth 2.0 authorization by checking for t 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:

    + +``` +# Retrieve playlists for a specified channel +go run playlists.go oauth.go errors.go --channelId=UC_x5XG1OV2P6uZZ5FSM9Ttw + +# Retrieve authenticated user's playlists +go run playlists.go oauth.go errors.go --mine=true +``` + ### [Retrieve my uploads](/go/my_uploads.go) Methods: youtube.channels.list, youtube.playlistItems.list
    From 5193a5a4decc848bad8fa09c72e5aa46c7d260d2 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Wed, 16 Aug 2017 12:44:27 -0400 Subject: [PATCH 090/126] Update retrieve_reports.php Support command-line parameters to set content owner, job ID, download URL. Support option to include system-managed reports. Update auth flow. --- php/retrieve_reports.php | 259 ++++++++++++++++++++------------------- 1 file changed, 130 insertions(+), 129 deletions(-) diff --git a/php/retrieve_reports.php b/php/retrieve_reports.php index 8c5aa17e..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: * * Please ensure that you have enabled the YouTube Data API for your project. */ -$OAUTH2_CLIENT_ID = 'REPLACE_ME'; -$OAUTH2_CLIENT_SECRET = 'REPLACE_ME'; - -$client = new Google_Client(); -$client->setClientId($OAUTH2_CLIENT_ID); -$client->setClientSecret($OAUTH2_CLIENT_SECRET); - -/* - * This OAuth 2.0 access scope allows for full read/write access to the - * authenticated user's account. - */ -$client->setScopes('https://www.googleapis.com/auth/yt-analytics-monetary.readonly'); -$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'], - FILTER_SANITIZE_URL); -$client->setRedirectUri($redirect); - -// YouTube Reporting object used to make YouTube Reporting API requests. -$youtubeReporting = new Google_Service_YoutubeReporting($client); +function getClient() { + $client = new Google_Client(); + $client->setAuthConfigFile('client_secrets_php.json'); + $client->addScope( + 'https://www.googleapis.com/auth/yt-analytics-monetary.readonly'); + $client->setRedirectUri('urn:ietf:wg:oauth:2.0:oob'); + $client->setAccessType('offline'); + + // Load previously authorized credentials from a file. + $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH); + if (file_exists($credentialsPath)) { + $accessToken = json_decode(file_get_contents($credentialsPath), true); + } 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); + $refreshToken = $client->getRefreshToken(); + + // Store the credentials to disk. + if(!file_exists(dirname($credentialsPath))) { + mkdir(dirname($credentialsPath), 0700, true); + } + file_put_contents($credentialsPath, json_encode($accessToken)); + printf('Credentials saved to %s\n', $credentialsPath); -// Check if an auth token exists for the required scopes -$tokenSessionKey = 'token-' . $client->prepareScopes(); -if (isset($_GET['code'])) { - if (strval($_SESSION['state']) !== strval($_GET['state'])) { - die('The session state did not match.'); + //fclose($fp); } + $client->setAccessToken($accessToken); - $client->authenticate($_GET['code']); - $_SESSION[$tokenSessionKey] = $client->getAccessToken(); - header('Location: ' . $redirect); -} + // Refresh the token if it's expired. + if ($client->isAccessTokenExpired()) { + $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); + file_put_contents($credentialsPath, json_encode($client->getAccessToken())); + } -if (isset($_SESSION[$tokenSessionKey])) { - $client->setAccessToken($_SESSION[$tokenSessionKey]); + return $client; } -// Check to ensure that the access token was successfully acquired. -if ($client->getAccessToken()) { - $htmlBody = ''; - try { - if (empty(listReportingJobs($youtubeReporting, $htmlBody))) { - $htmlBody .= sprintf('

    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

    ', - htmlspecialchars($e->getMessage())); - } catch (Google_Exception $e) { - $htmlBody .= sprintf('

    An client error occurred: %s

    ', - htmlspecialchars($e->getMessage())); +/** + * 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'); } - $_SESSION[$tokenSessionKey] = $client->getAccessToken(); -} elseif ($OAUTH2_CLIENT_ID == 'REPLACE_ME') { - $htmlBody = <<Client Credentials Required -

    - 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 = <<Authorization Required -

    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 .= "

    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('
    • id: "%s", name: "%s" report type: "%s"
    • ', $job['id'], - $job['name'], $job['reportTypeId']); + print($job['reportTypeId'] . ':' . $job['id'] . PHP_EOL); } - $htmlBody .= '
    '; - - 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('

    No reports found.

    '); - } else { - $htmlBody .= sprintf('

    Reports for the job "%s"

      ', $jobId); - foreach ($reports as $report) { - $htmlBody .= sprintf('
    • From "%s" to "%s" downloadable at "%s"
    • ', - $report['startTime'], $report['endTime'], $report['downloadUrl']); - $htmlBody .= '
    '; - } +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("", array("alt" => "media")); + // 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)); - $response = $client->execute($request); - - file_put_contents("reportFile", $response->getBody()); + $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); } -?> - - - -Retrieve reports - - -
    -
    - Job Id: -
    -
    -
    - Report URL: -
    -
    -
    - - - +// Define an object that will be used to make all API requests. +$client = getClient(); +// YouTube Reporting object used to make YouTube Reporting API requests. +$youtubeReporting = new Google_Service_YouTubeReporting($client); + +if ($CONTENT_OWNER_ID) { + if (!$DOWNLOAD_URL && !$JOB_ID) { + listReportingJobs($youtubeReporting, $CONTENT_OWNER_ID, + $INCLUDE_SYSTEM_MANAGED); + } else if ($JOB_ID) { + listReportsForJob($youtubeReporting, $JOB_ID, $CONTENT_OWNER_ID); + } else if ($DOWNLOAD_URL && $OUTPUT_FILE) { + downloadReport($youtubeReporting, $DOWNLOAD_URL, $OUTPUT_FILE); + } +} + +?> From 5b036f3e798db6b3432773b1d361631c5d0de318 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 29 Sep 2017 11:01:36 -0400 Subject: [PATCH 091/126] Create quickstart_web.py file Add sample for quickstart guide that shows how to create a simple Python app that uses the Flask web application framework. --- python/quickstart_web.py | 167 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 python/quickstart_web.py diff --git a/python/quickstart_web.py b/python/quickstart_web.py new file mode 100644 index 00000000..50040159 --- /dev/null +++ b/python/quickstart_web.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- + +import os + +import flask +import google.oauth2.credentials +import google_auth_oauthlib.flow +import googleapiclient.discovery + +# 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. +CLIENT_SECRETS_FILE = "client_secret.json" + +# This OAuth 2.0 access scope allows for full read/write access to the +# authenticated user's account and requires requests to use an SSL connection. +SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' + +app = flask.Flask(__name__) +# Note: A secret key is included in the sample so that it works, but if you +# use this code in your application please replace this with a truly secret +# key. See http://flask.pocoo.org/docs/0.12/quickstart/#sessions. +app.secret_key = 'REPLACE ME - this value is here as a placeholder.' + + +@app.route('/') +def index(): + if 'credentials' not in flask.session: + return flask.redirect('authorize') + + # Load the credentials from the session. + credentials = google.oauth2.credentials.Credentials( + **flask.session['credentials']) + + client = googleapiclient.discovery.build( + API_SERVICE_NAME, API_VERSION, credentials=credentials) + return channels_list_by_username(client, + part='snippet,contentDetails,statistics', + forUsername='GoogleDevelopers') + + +@app.route('/authorize') +def authorize(): + # Create a flow instance to manage the OAuth 2.0 Authorization Grant Flow + # steps. + flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( + CLIENT_SECRETS_FILE, scopes=SCOPES) + flow.redirect_uri = flask.url_for('oauth2callback', _external=True) + authorization_url, state = flow.authorization_url( + # This parameter enables offline access which gives your application + # both an access and refresh token. + access_type='offline', + # This parameter enables incremental auth. + include_granted_scopes='true') + + # Store the state in the session so that the callback can verify that + # the authorization server response. + flask.session['state'] = state + + return flask.redirect(authorization_url) + + +@app.route('/oauth2callback') +def oauth2callback(): + # Specify the state when creating the flow in the callback so that it can + # verify the authorization server response. + state = flask.session['state'] + flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( + CLIENT_SECRETS_FILE, scopes=SCOPES, state=state) + flow.redirect_uri = flask.url_for('oauth2callback', _external=True) + + # Use the authorization server's response to fetch the OAuth 2.0 tokens. + authorization_response = flask.request.url + flow.fetch_token(authorization_response=authorization_response) + + # Store the credentials in the session. + # ACTION ITEM for developers: + # Store user's access and refresh tokens in your data store if + # incorporating this code into your real app. + credentials = flow.credentials + flask.session['credentials'] = { + 'token': credentials.token, + 'refresh_token': credentials.refresh_token, + 'token_uri': credentials.token_uri, + 'client_id': credentials.client_id, + 'client_secret': credentials.client_secret, + 'scopes': credentials.scopes + } + + return flask.redirect(flask.url_for('index')) + +def print_response(response): + if response: + return flask.jsonify(**response) + else: + return ('This request does not return a response. For these samples, ' + + 'this is generally true for requests that delete resources, ' + + 'such as playlists.delete(), but it is also ' + + 'true for some other methods, such as videos.rate().') + +# Build a resource based on a list of properties given as key-value pairs. +# Leave properties with empty values out of the inserted resource. +def build_resource(properties): + resource = {} + for p in properties: + # Given a key like "snippet.title", split into "snippet" and "title", where + # "snippet" will be an object and "title" will be a property in that object. + prop_array = p.split('.') + ref = resource + for pa in range(0, len(prop_array)): + is_array = False + key = prop_array[pa] + + # For properties that have array values, convert a name like + # "snippet.tags[]" to snippet.tags, and set a flag to handle + # the value as an array. + if key[-2:] == '[]': + key = key[0:len(key)-2:] + is_array = True + + if pa == (len(prop_array) - 1): + # Leave properties without values out of inserted resource. + if properties[p]: + if is_array: + ref[key] = properties[p].split(',') + else: + ref[key] = properties[p] + elif key not in ref: + # For example, the property is "snippet.title", but the resource does + # not yet have a "snippet" object. Create the snippet object here. + # Setting "ref = ref[key]" means that in the next time through the + # "for pa in range ..." loop, we will be setting a property in the + # resource's "snippet" object. + ref[key] = {} + ref = ref[key] + else: + # For example, the property is "snippet.description", and the resource + # already has a "snippet" object. + ref = ref[key] + return resource + +# Remove keyword arguments that are not set +def remove_empty_kwargs(**kwargs): + good_kwargs = {} + if kwargs is not None: + for key, value in kwargs.iteritems(): + if value: + good_kwargs[key] = value + return good_kwargs + +def channels_list_by_username(client, **kwargs): + kwargs = remove_empty_kwargs(**kwargs) # See full sample for function + response = client.channels().list( + **kwargs + ).execute() + + return print_response(response) + + + +if __name__ == '__main__': + # When running locally, disable OAuthlib's HTTPs verification. When + # running in production *do not* leave this option enabled. + os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' + app.run('localhost', 8090, debug=True) From d788e74a9b1a51046ec6de7eafac980c39d124ad Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 29 Sep 2017 11:52:45 -0400 Subject: [PATCH 092/126] Update quickstart.py auth libraries Update auth library from oauth2client to google-auth. --- python/quickstart.py | 58 +++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/python/quickstart.py b/python/quickstart.py index 3ada92ef..3868e4af 100644 --- a/python/quickstart.py +++ b/python/quickstart.py @@ -1,14 +1,12 @@ # Sample Python code for user authorization -import httplib2 import os -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 + +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 # the OAuth 2.0 information for this application, including its client_id and @@ -17,45 +15,33 @@ # This OAuth 2.0 access scope allows for full read/write access to the # authenticated user's account and requires requests to use an SSL connection. -YOUTUBE_READ_WRITE_SSL_SCOPE = "https://www.googleapis.com/auth/youtube.readonly" -API_SERVICE_NAME = "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" - -# Authorize the request and store authorization credentials. -def get_authenticated_service(args): - flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_READ_WRITE_SSL_SCOPE, - message=MISSING_CLIENT_SECRETS_MESSAGE) - - storage = Storage("%s-oauth2.json" % sys.argv[0]) - credentials = storage.get() +SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' - 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) - # Trusted testers can download this discovery document from the developers page - # and it should be in the same directory with the code. - return build(API_SERVICE_NAME, API_VERSION, - http=credentials.authorize(httplib2.Http())) + credentials = flow.run_console() -args = argparser.parse_args() -service = get_authenticated_service(args) - -### END BOILERPLATE CODE - -# Sample python code for channels.list + return build(API_SERVICE_NAME, API_VERSION, credentials = credentials) def channels_list_by_username(service, **kwargs): results = service.channels().list( **kwargs ).execute() - + print('This channel\'s ID is %s. Its title is %s, and it has %s views.' % (results['items'][0]['id'], results['items'][0]['snippet']['title'], results['items'][0]['statistics']['viewCount'])) -channels_list_by_username(service, part='snippet,contentDetails,statistics', forUsername='GoogleDevelopers') +if __name__ == '__main__': + # When running locally, disable OAuthlib's HTTPs verification. When + # running in production *do not* leave this option enabled. + os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' + #app.run('localhost', 8090, debug=True) + service = get_authenticated_service() + channels_list_by_username(service, + part='snippet,contentDetails,statistics', + forUsername='GoogleDevelopers') From aa7b057c5757f3109e7235b4a8b99499c2d4e909 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 29 Sep 2017 11:54:08 -0400 Subject: [PATCH 093/126] Remove commented out statement --- python/quickstart.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/quickstart.py b/python/quickstart.py index 3868e4af..de2aa315 100644 --- a/python/quickstart.py +++ b/python/quickstart.py @@ -21,9 +21,7 @@ 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) def channels_list_by_username(service, **kwargs): @@ -40,7 +38,6 @@ def channels_list_by_username(service, **kwargs): # When running locally, disable OAuthlib's HTTPs verification. When # running in production *do not* leave this option enabled. os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' - #app.run('localhost', 8090, debug=True) service = get_authenticated_service() channels_list_by_username(service, part='snippet,contentDetails,statistics', From 62cfdb9d4c3b00340520acb3f756181c5314d166 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 29 Sep 2017 11:57:32 -0400 Subject: [PATCH 094/126] Remove functions not needed in quickstart app --- python/quickstart_web.py | 52 ---------------------------------------- 1 file changed, 52 deletions(-) diff --git a/python/quickstart_web.py b/python/quickstart_web.py index 50040159..95740923 100644 --- a/python/quickstart_web.py +++ b/python/quickstart_web.py @@ -100,58 +100,7 @@ def print_response(response): 'such as playlists.delete(), but it is also ' + 'true for some other methods, such as videos.rate().') -# Build a resource based on a list of properties given as key-value pairs. -# Leave properties with empty values out of the inserted resource. -def build_resource(properties): - resource = {} - for p in properties: - # Given a key like "snippet.title", split into "snippet" and "title", where - # "snippet" will be an object and "title" will be a property in that object. - prop_array = p.split('.') - ref = resource - for pa in range(0, len(prop_array)): - is_array = False - key = prop_array[pa] - - # For properties that have array values, convert a name like - # "snippet.tags[]" to snippet.tags, and set a flag to handle - # the value as an array. - if key[-2:] == '[]': - key = key[0:len(key)-2:] - is_array = True - - if pa == (len(prop_array) - 1): - # Leave properties without values out of inserted resource. - if properties[p]: - if is_array: - ref[key] = properties[p].split(',') - else: - ref[key] = properties[p] - elif key not in ref: - # For example, the property is "snippet.title", but the resource does - # not yet have a "snippet" object. Create the snippet object here. - # Setting "ref = ref[key]" means that in the next time through the - # "for pa in range ..." loop, we will be setting a property in the - # resource's "snippet" object. - ref[key] = {} - ref = ref[key] - else: - # For example, the property is "snippet.description", and the resource - # already has a "snippet" object. - ref = ref[key] - return resource - -# Remove keyword arguments that are not set -def remove_empty_kwargs(**kwargs): - good_kwargs = {} - if kwargs is not None: - for key, value in kwargs.iteritems(): - if value: - good_kwargs[key] = value - return good_kwargs - def channels_list_by_username(client, **kwargs): - kwargs = remove_empty_kwargs(**kwargs) # See full sample for function response = client.channels().list( **kwargs ).execute() @@ -159,7 +108,6 @@ def channels_list_by_username(client, **kwargs): return print_response(response) - if __name__ == '__main__': # When running locally, disable OAuthlib's HTTPs verification. When # running in production *do not* leave this option enabled. From b32b9f6ef1291c8e129132f9a09bbea37db02de9 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 29 Sep 2017 12:03:33 -0400 Subject: [PATCH 095/126] Additional simplifications to quickstart --- python/quickstart_web.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/python/quickstart_web.py b/python/quickstart_web.py index 95740923..c3e89248 100644 --- a/python/quickstart_web.py +++ b/python/quickstart_web.py @@ -91,21 +91,12 @@ def oauth2callback(): return flask.redirect(flask.url_for('index')) -def print_response(response): - if response: - return flask.jsonify(**response) - else: - return ('This request does not return a response. For these samples, ' + - 'this is generally true for requests that delete resources, ' + - 'such as playlists.delete(), but it is also ' + - 'true for some other methods, such as videos.rate().') - def channels_list_by_username(client, **kwargs): response = client.channels().list( **kwargs ).execute() - return print_response(response) + return flask.jsonify(**response) if __name__ == '__main__': From fe3b13a5e9f574d472119f933982f21c4550c547 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 29 Sep 2017 12:05:04 -0400 Subject: [PATCH 096/126] Minor formatting fixes --- python/quickstart_web.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/quickstart_web.py b/python/quickstart_web.py index c3e89248..ec58f56f 100644 --- a/python/quickstart_web.py +++ b/python/quickstart_web.py @@ -3,6 +3,7 @@ import os import flask + import google.oauth2.credentials import google_auth_oauthlib.flow import googleapiclient.discovery @@ -36,6 +37,7 @@ def index(): client = googleapiclient.discovery.build( API_SERVICE_NAME, API_VERSION, credentials=credentials) + return channels_list_by_username(client, part='snippet,contentDetails,statistics', forUsername='GoogleDevelopers') From c03017d41a1184dc469486acdb2e8d3b121ccdbf Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Thu, 19 Oct 2017 18:19:00 -0400 Subject: [PATCH 097/126] Update auth libraries used in example The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. --- python/add_channel_section.py | 120 ++++++++++++++-------------------- 1 file changed, 50 insertions(+), 70 deletions(-) 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. From 8235ff8d3f1757a0b4b6b5e9d8f583e70d9a1f29 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 20 Oct 2017 12:10:25 -0400 Subject: [PATCH 098/126] Update auth libraries used in example The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. --- python/add_subscription.py | 80 ++++++++++++++------------------------ 1 file changed, 29 insertions(+), 51 deletions(-) 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 From 27f1205805439aff26ccf6d1c9b98c0f8d228c04 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 20 Oct 2017 12:22:34 -0400 Subject: [PATCH 099/126] Remove oauth2client usages. Update search.py to remove usage of deprecated oauth2client library. --- python/search.py | 65 +++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/python/search.py b/python/search.py index 8e9d2add..1df6ba7b 100644 --- a/python/search.py +++ b/python/search.py @@ -1,17 +1,25 @@ #!/usr/bin/python -from apiclient.discovery import build -from apiclient.errors import HttpError -from oauth2client.tools import argparser +# This sample executes a search request for the specified search term. +# Sample usage: +# python search.py --key=surfing --max-results=10 +# NOTE: To use the sample, you must provide a developer key obtained +# in the Google APIs Console. Search for "REPLACE_ME" in this code +# to find the correct place to provide that key.. + +import argparse + +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError # Set DEVELOPER_KEY to the API key value from the APIs & auth > Registered apps # tab of # https://cloud.google.com/console # Please ensure that you have enabled the YouTube Data API for your project. -DEVELOPER_KEY = "REPLACE_ME" -YOUTUBE_API_SERVICE_NAME = "youtube" -YOUTUBE_API_VERSION = "v3" +DEVELOPER_KEY = 'REPLACE_ME' +YOUTUBE_API_SERVICE_NAME = 'youtube' +YOUTUBE_API_VERSION = 'v3' def youtube_search(options): youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, @@ -21,7 +29,7 @@ def youtube_search(options): # query term. search_response = youtube.search().list( q=options.q, - part="id,snippet", + part='id,snippet', maxResults=options.max_results ).execute() @@ -31,28 +39,29 @@ def youtube_search(options): # Add each result to the appropriate list, and then display the lists of # matching videos, channels, and playlists. - for search_result in search_response.get("items", []): - if search_result["id"]["kind"] == "youtube#video": - videos.append("%s (%s)" % (search_result["snippet"]["title"], - search_result["id"]["videoId"])) - elif search_result["id"]["kind"] == "youtube#channel": - channels.append("%s (%s)" % (search_result["snippet"]["title"], - search_result["id"]["channelId"])) - elif search_result["id"]["kind"] == "youtube#playlist": - playlists.append("%s (%s)" % (search_result["snippet"]["title"], - search_result["id"]["playlistId"])) - - print "Videos:\n", "\n".join(videos), "\n" - print "Channels:\n", "\n".join(channels), "\n" - print "Playlists:\n", "\n".join(playlists), "\n" - - -if __name__ == "__main__": - argparser.add_argument("--q", help="Search term", default="Google") - argparser.add_argument("--max-results", help="Max results", default=25) - args = argparser.parse_args() + for search_result in search_response.get('items', []): + if search_result['id']['kind'] == 'youtube#video': + videos.append('%s (%s)' % (search_result['snippet']['title'], + search_result['id']['videoId'])) + elif search_result['id']['kind'] == 'youtube#channel': + channels.append('%s (%s)' % (search_result['snippet']['title'], + search_result['id']['channelId'])) + elif search_result['id']['kind'] == 'youtube#playlist': + playlists.append('%s (%s)' % (search_result['snippet']['title'], + search_result['id']['playlistId'])) + + print 'Videos:\n', '\n'.join(videos), '\n' + print 'Channels:\n', '\n'.join(channels), '\n' + print 'Playlists:\n', '\n'.join(playlists), '\n' + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--q', help='Search term', default='Google') + parser.add_argument('--max-results', help='Max results', default=25) + args = parser.parse_args() try: youtube_search(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) From 175641601483e7e2812062fc6e31650940806961 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 20 Oct 2017 12:32:24 -0400 Subject: [PATCH 100/126] Update auth libraries, add rating argument The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. Also add a rating argument that can be passed on the command line. --- python/like_video.py | 101 ++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 58 deletions(-) diff --git a/python/like_video.py b/python/like_video.py index 36a988f5..4f0899a6 100644 --- a/python/like_video.py +++ b/python/like_video.py @@ -1,14 +1,18 @@ #!/usr/bin/python -import httplib2 +# This sample shows how to rate a video. +# Sample usage: +# python like_video.py --videoId=OE63BYWdqC4 --rating=like + +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,64 +25,45 @@ # 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 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_READ_WRITE_SCOPE = "https://www.googleapis.com/auth/youtube" -YOUTUBE_API_SERVICE_NAME = "youtube" -YOUTUBE_API_VERSION = "v3" - -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())) - -# Add the video rating. This code sets the rating to "like," but you could -# also support an additional option that supports values of "like" and -# "dislike." -def like_video(youtube, video_id): +SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' + +RATINGS = ('like', 'dislike', 'none') + +# Authorize the request and store authorization credentials. +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) + +# Add the video rating. This code sets the rating to 'like,' but you could +# also support an additional option that supports values of 'like' and +# 'dislike.' +def like_video(youtube, args): youtube.videos().rate( - id=video_id, - rating="like" + id=args.videoId, + rating=args.rating ).execute() -if __name__ == "__main__": - argparser.add_argument("--videoid", default="L-oNKK1CrnU", - help="ID of video to like.") - args = argparser.parse_args() +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--videoId', default='OE63BYWdqC4', + help='ID of video to like.') + parser.add_argument('--rating', default='like', + choices=RATINGS, + help='Indicates whether the rating is "like", "dislike", or "none".') + args = parser.parse_args() - youtube = get_authenticated_service(args) + youtube = get_authenticated_service() try: - like_video(youtube, args.videoid) + like_video(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 "%s has been liked." % args.videoid + print ('The %s rating has been added for video ID %s.' % + (args.rating, args.videoId)) From 38651dec50dcc425196f7708ca0206dffea51bae Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 20 Oct 2017 12:36:47 -0400 Subject: [PATCH 101/126] Remove oauth2client usages Remove usage of oauth2client library, which is now deprecated. --- python/geolocation_search.py | 56 ++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/python/geolocation_search.py b/python/geolocation_search.py index c051943d..922f7048 100644 --- a/python/geolocation_search.py +++ b/python/geolocation_search.py @@ -1,17 +1,25 @@ #!/usr/bin/python -from apiclient.discovery import build -from apiclient.errors import HttpError -from oauth2client.tools import argparser +# This sample executes a search request for the specified search term. +# Sample usage: +# python geolocation_search.py --q=surfing --location-"37.42307,-122.08427" --location-radius=50km --max-results=10 +# NOTE: To use the sample, you must provide a developer key obtained +# in the Google APIs Console. Search for "REPLACE_ME" in this code +# to find the correct place to provide that key.. + +import argparse + +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError # Set DEVELOPER_KEY to the API key value from the APIs & auth > Registered apps # tab of # https://cloud.google.com/console # Please ensure that you have enabled the YouTube Data API for your project. -DEVELOPER_KEY = "REPLACE_ME" -YOUTUBE_API_SERVICE_NAME = "youtube" -YOUTUBE_API_VERSION = "v3" +DEVELOPER_KEY = 'REPLACE_ME' +YOUTUBE_API_SERVICE_NAME = 'youtube' +YOUTUBE_API_VERSION = 'v3' def youtube_search(options): youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, @@ -21,19 +29,19 @@ def youtube_search(options): # query term. search_response = youtube.search().list( q=options.q, - type="video", + type='video', location=options.location, locationRadius=options.location_radius, - part="id,snippet", + part='id,snippet', maxResults=options.max_results ).execute() search_videos = [] # Merge video ids - for search_result in search_response.get("items", []): - search_videos.append(search_result["id"]["videoId"]) - video_ids = ",".join(search_videos) + for search_result in search_response.get('items', []): + search_videos.append(search_result['id']['videoId']) + video_ids = ','.join(search_videos) # Call the videos.list method to retrieve location details for each video. video_response = youtube.videos().list( @@ -44,23 +52,23 @@ def youtube_search(options): videos = [] # Add each result to the list, and then display the list of matching videos. - for video_result in video_response.get("items", []): - videos.append("%s, (%s,%s)" % (video_result["snippet"]["title"], - video_result["recordingDetails"]["location"]["latitude"], - video_result["recordingDetails"]["location"]["longitude"])) + for video_result in video_response.get('items', []): + videos.append('%s, (%s,%s)' % (video_result['snippet']['title'], + video_result['recordingDetails']['location']['latitude'], + video_result['recordingDetails']['location']['longitude'])) - print "Videos:\n", "\n".join(videos), "\n" + print 'Videos:\n', '\n'.join(videos), '\n' -if __name__ == "__main__": - argparser.add_argument("--q", help="Search term", default="Google") - argparser.add_argument("--location", help="Location", default="37.42307,-122.08427") - argparser.add_argument("--location-radius", help="Location radius", default="5km") - argparser.add_argument("--max-results", help="Max results", default=25) - args = argparser.parse_args() +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--q', help='Search term', default='Google') + parser.add_argument('--location', help='Location', default='37.42307,-122.08427') + parser.add_argument('--location-radius', help='Location radius', default='5km') + parser.add_argument('--max-results', help='Max results', default=25) + args = parser.parse_args() try: youtube_search(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) From 4dc5d936d545f53ad71890750df889d0053b294a Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 20 Oct 2017 12:37:12 -0400 Subject: [PATCH 102/126] Fix instructional comment --- python/search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/search.py b/python/search.py index 1df6ba7b..ccb17729 100644 --- a/python/search.py +++ b/python/search.py @@ -2,7 +2,7 @@ # This sample executes a search request for the specified search term. # Sample usage: -# python search.py --key=surfing --max-results=10 +# python search.py --q=surfing --max-results=10 # NOTE: To use the sample, you must provide a developer key obtained # in the Google APIs Console. Search for "REPLACE_ME" in this code # to find the correct place to provide that key.. From b0a876292289d818b9c01e22325d9accf1a3cd46 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 20 Oct 2017 12:40:39 -0400 Subject: [PATCH 103/126] Update auth libraries used in example The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. --- python/list_broadcasts.py | 79 +++++++++++++-------------------------- 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/python/list_broadcasts.py b/python/list_broadcasts.py index 421d1f66..67e44ab4 100644 --- a/python/list_broadcasts.py +++ b/python/list_broadcasts.py @@ -1,14 +1,14 @@ #!/usr/bin/python -import httplib2 +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,74 +21,49 @@ # 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 read-only access to the authenticated # user's account, but not other types of account access. -YOUTUBE_READONLY_SCOPE = "https://www.googleapis.com/auth/youtube.readonly" -YOUTUBE_API_SERVICE_NAME = "youtube" -YOUTUBE_API_VERSION = "v3" +SCOPES = ['https://www.googleapis.com/auth/youtube.readonly'] +API_SERVICE_NAME = '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 +VALID_BROADCAST_STATUSES = ('all', 'active', 'completed', 'upcoming',) -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)) - -VALID_BROADCAST_STATUSES = ("all", "active", "completed", "upcoming",) - -def get_authenticated_service(args): - flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, - scope=YOUTUBE_READONLY_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())) +# Authorize the request and store authorization credentials. +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) # Retrieve a list of broadcasts with the specified status. def list_broadcasts(youtube, broadcast_status): - print "Broadcasts with status '%s':" % broadcast_status + print 'Broadcasts with status "%s":' % broadcast_status list_broadcasts_request = youtube.liveBroadcasts().list( broadcastStatus=broadcast_status, - part="id,snippet", + part='id,snippet', maxResults=50 ) while list_broadcasts_request: list_broadcasts_response = list_broadcasts_request.execute() - for broadcast in list_broadcasts_response.get("items", []): - print "%s (%s)" % (broadcast["snippet"]["title"], broadcast["id"]) + for broadcast in list_broadcasts_response.get('items', []): + print '%s (%s)' % (broadcast['snippet']['title'], broadcast['id']) list_broadcasts_request = youtube.liveBroadcasts().list_next( list_broadcasts_request, list_broadcasts_response) -if __name__ == "__main__": - argparser.add_argument("--broadcast-status", help="Broadcast status", +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--broadcast-status', help='Broadcast status', choices=VALID_BROADCAST_STATUSES, default=VALID_BROADCAST_STATUSES[0]) - args = argparser.parse_args() + args = parser.parse_args() - youtube = get_authenticated_service(args) + youtube = get_authenticated_service() try: list_broadcasts(youtube, args.broadcast_status) 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) From f058c43383fbfc640c162ca5bdb72bbaeaaf26ce Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 20 Oct 2017 12:41:40 -0400 Subject: [PATCH 104/126] Update auth libraries used in example The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. --- python/list_streams.py | 87 ++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 58 deletions(-) diff --git a/python/list_streams.py b/python/list_streams.py index 095febae..14090fa9 100644 --- a/python/list_streams.py +++ b/python/list_streams.py @@ -1,14 +1,13 @@ #!/usr/bin/python -import httplib2 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,71 +20,43 @@ # 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 read-only access to the authenticated # user's account, but not other types of account access. -YOUTUBE_READONLY_SCOPE = "https://www.googleapis.com/auth/youtube.readonly" -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_READONLY_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.readonly'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' + +# Authorize the request and store authorization credentials. +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) + # Retrieve a list of the liveStream resources associated with the currently # authenticated user's channel. def list_streams(youtube): - print "Live streams:" + print 'Live streams:' list_streams_request = youtube.liveStreams().list( - part="id,snippet", + part='id,snippet', mine=True, maxResults=50 - ) - + ) + while list_streams_request: list_streams_response = list_streams_request.execute() - - for stream in list_streams_response.get("items", []): - print "%s (%s)" % (stream["snippet"]["title"], stream["id"]) - + + for stream in list_streams_response.get('items', []): + print '%s (%s)' % (stream['snippet']['title'], stream['id']) + list_streams_request = youtube.liveStreams().list_next( list_streams_request, list_streams_response) - -if __name__ == "__main__": - args = argparser.parse_args() - - youtube = get_authenticated_service(args) + +if __name__ == '__main__': + youtube = get_authenticated_service() try: list_streams(youtube) 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) From 37022382ee87ac6cb9a1efa747042d33b2b489de Mon Sep 17 00:00:00 2001 From: Andy Diamondstein Date: Fri, 20 Oct 2017 13:42:00 -0400 Subject: [PATCH 105/126] Update auth libraries, fix brandingSettings update The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. Update code sample to update brandingSettings (defaultLanguage) and localizations separately. Support localized channel title and localized channel description. --- python/channel_localizations.py | 171 ++++++++++++++++---------------- 1 file changed, 87 insertions(+), 84 deletions(-) diff --git a/python/channel_localizations.py b/python/channel_localizations.py index 6a615e70..88a8fced 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='' --channel_id='' --default_language='' --language='' --description='' +# python channel_localizations.py --action='' --channel_id='' --default_language='' --language='' --title='' --description='<description>' -import httplib2 +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 @@ -25,73 +25,72 @@ # 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 APIs Console -https://console.developers.google.com - -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)) +SCOPES = ['https://www.googleapis.com/auth/youtube'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' # Authorize the request and store authorization credentials. -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())) - +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) # Call the API's channels.update method to update an existing channel's default language, # and localized description in a specific language. -def set_channel_localization(youtube, channel_id, default_language, language, description): +def set_channel_localization(youtube, args): results = youtube.channels().list( - part="brandingSettings,localizations", - id=channel_id + part='localizations', + id=args.channel_id ).execute() - channel = results["items"][0] + channel = results['items'][0] + # Ensure that a value is set for the resource's snippet.defaultLanguage property. # To set the snippet.defaultLanguage property for a channel resource, # you actually need to update the brandingSettings.channel.defaultLanguage property. - channel["brandingSettings"]["channel"]["defaultLanguage"] = default_language - if "localizations" not in channel: - channel["localizations"] = {} - channel["localizations"][language] = { - "description": description + if 'localizations' not in channel: + channel['localizations'] = {} + if args.title and args.description and args.language: + channel['localizations'][args.language] = { + 'title': args.title, + 'description': args.description } + # Set the default language if it is provided as an argument + if args.default_language: + results = youtube.channels().list( + part='brandingSettings', + id=args.channel_id + ).execute() + branding_settings_channel = results['items'][0] + # This property must be removed when changing the default language + # or set to the original channel title to avoid a + # channelTitleUpdateForbidden error. + del branding_settings_channel['brandingSettings']['channel']['title'] + branding_settings_channel['brandingSettings']['channel']['defaultLanguage'] = ( + args.default_language) + language_result = youtube.channels().update( + part='brandingSettings', + body=branding_settings_channel + ).execute() + updated_default_language = ( + language_result['brandingSettings']['channel']['defaultLanguage']) + print 'Updated language to %s' % updated_default_language + update_result = youtube.channels().update( - part="brandingSettings,localizations", + part='localizations', body=channel ).execute() - localization = update_result["localizations"][language] + localization = update_result['localizations'][args.language] - print ("Updated channel '%s' default language to '%s', localized description" - " to '%s' in language '%s'" % (channel_id, localization["description"], language)) + print ('Updated channel \'%s\' localized title and description to ' + '\'%s\' and \'%s\' in language \'%s\'' % + (args.channel_id, localization['title'], localization['description'], args.language)) # Call the API's channels.list method to retrieve an existing channel localization. @@ -99,7 +98,7 @@ def set_channel_localization(youtube, channel_id, default_language, language, de # this method will return text in the default language. def get_channel_localization(youtube, channel_id, language): results = youtube.channels().list( - part="snippet", + part='snippet', id=channel_id, hl=language ).execute() @@ -107,55 +106,59 @@ def get_channel_localization(youtube, channel_id, language): # The localized object contains localized text if the hl parameter specified # a language for which localized text is available. Otherwise, the localized # object will contain metadata in the default language. - localized = results["items"][0]["snippet"]["localized"] + localized = results['items'][0]['snippet']['localized'] - print "Channel description is '%s' in language '%s'" % (localized["description"], language) + print 'Channel description is \'%s\' in language \'%s\'' % (localized['description'], language) # Call the API's channels.list method to list the existing channel localizations. def list_channel_localizations(youtube, channel_id): results = youtube.channels().list( - part="snippet,localizations", + part='snippet,localizations', id=channel_id ).execute() - localizations = results["items"][0]["localizations"] + localizations = results['items'][0]['localizations'] for language, localization in localizations.iteritems(): - print "Channel description is '%s' in language '%s'" % (localization["description"], language) - - -if __name__ == "__main__": - # The "action" option specifies the action to be processed. - argparser.add_argument("--action", help="Action") - # The "channel_id" option specifies the ID of the selected YouTube channel. - argparser.add_argument("--channel_id", - help="ID for channel for which the localization will be applied.") - # The "default_language" option specifies the language of the channel's default metadata. - argparser.add_argument("--default_language", help="Default language of the channel to update.", - default="en") - # The "language" option specifies the language of the localization that is being processed. - argparser.add_argument("--language", help="Language of the localization.", default="de") - # The "description" option specifies the localized description of the chanel to be set. - argparser.add_argument("--description", help="Localized description of the channel to be set.", - default="Localized Description") - - args = argparser.parse_args() + print 'Channel description is \'%s\' in language \'%s\'' % (localization['description'], language) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + # The 'action' option specifies the action to be processed. + parser.add_argument('--action', help='Action') + # The 'channel_id' option specifies the ID of the selected YouTube channel. + parser.add_argument('--channel_id', + help='ID for channel for which the localization will be applied.') + # The 'default_language' option specifies the language of the channel's default metadata. + parser.add_argument('--default_language', help='Default language of the channel to update.', + default=None) + # The 'language' option specifies the language of the localization that is being processed. + parser.add_argument('--language', help='Language of the localization.', default='de') + # The 'title' option specifies the localized title of the chanel to be set. + parser.add_argument('--title', help='Localized title of the channel to be set.', + default='Localized title') + # The 'description' option specifies the localized description of the chanel to be set. + parser.add_argument('--description', help='Localized description of the channel to be set.', + default='Localized description') + + args = parser.parse_args() if not args.channel_id: - exit("Please specify channel id using the --channel_id= parameter.") + exit('Please specify channel id using the --channel_id= parameter.') - youtube = get_authenticated_service(args) + youtube = get_authenticated_service() try: if args.action == 'set': - set_channel_localization(youtube, args.channel_id, args.default_language, args.language, args.description) + set_channel_localization(youtube, args) elif args.action == 'get': get_channel_localization(youtube, args.channel_id, args.language) elif args.action == 'list': list_channel_localizations(youtube, args.channel_id) else: - exit("Please specify a valid action using the --action= parameter.") + exit('Please specify a valid action using the --action= parameter.') 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 "Set and retrieved localized metadata for a channel." + print 'Set or retrieved localized metadata for a channel.' From b38c3d22a2c8ce935e8b65f5ea86087e810cea97 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 20 Oct 2017 14:50:38 -0400 Subject: [PATCH 106/126] Update auth libraries, fix script The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. This update also fixes this script so that it executes properly. --- python/my_uploads.py | 121 ++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/python/my_uploads.py b/python/my_uploads.py index d4e9af2e..0480f24d 100644 --- a/python/my_uploads.py +++ b/python/my_uploads.py @@ -1,13 +1,18 @@ #!/usr/bin/python -import httplib2 +# Retrieve the authenticated user's uploaded videos. +# Sample usage: +# python my_uploads.py + +import argparse import os -import sys +import re -from apiclient.discovery import build -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 @@ -20,77 +25,63 @@ # 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 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 read-only access to the authenticated # user's account, but not other types of account access. -YOUTUBE_READONLY_SCOPE = "https://www.googleapis.com/auth/youtube.readonly" -YOUTUBE_API_SERVICE_NAME = "youtube" -YOUTUBE_API_VERSION = "v3" - -flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, - message=MISSING_CLIENT_SECRETS_MESSAGE, - scope=YOUTUBE_READONLY_SCOPE) - -storage = Storage("%s-oauth2.json" % sys.argv[0]) -credentials = storage.get() - -if credentials is None or credentials.invalid: - flags = argparser.parse_args() - credentials = run_flow(flow, storage, flags) - -youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, - http=credentials.authorize(httplib2.Http())) - -# Retrieve the contentDetails part of the channel resource for the -# authenticated user's channel. -channels_response = youtube.channels().list( - mine=True, - part="contentDetails" -).execute() - -for channel in channels_response["items"]: - # From the API response, extract the playlist ID that identifies the list - # of videos uploaded to the authenticated user's channel. - uploads_list_id = channel["contentDetails"]["relatedPlaylists"]["uploads"] - - print "Videos in list %s" % uploads_list_id - +SCOPES = ['https://www.googleapis.com/auth/youtube.readonly'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' + +# Authorize the request and store authorization credentials. +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) + +def get_my_uploads_list(): + # Retrieve the contentDetails part of the channel resource for the + # authenticated user's channel. + channels_response = youtube.channels().list( + mine=True, + part='contentDetails' + ).execute() + + for channel in channels_response['items']: + # From the API response, extract the playlist ID that identifies the list + # of videos uploaded to the authenticated user's channel. + return channel['contentDetails']['relatedPlaylists']['uploads'] + + return None + +def list_my_uploaded_videos(uploads_playlist_id): # Retrieve the list of videos uploaded to the authenticated user's channel. playlistitems_list_request = youtube.playlistItems().list( - playlistId=uploads_list_id, - part="snippet", - maxResults=50 + playlistId=uploads_playlist_id, + part='snippet', + maxResults=5 ) + print 'Videos in list %s' % uploads_playlist_id while playlistitems_list_request: playlistitems_list_response = playlistitems_list_request.execute() # Print information about each video. - for playlist_item in playlistitems_list_response["items"]: - title = playlist_item["snippet"]["title"] - video_id = playlist_item["snippet"]["resourceId"]["videoId"] - print "%s (%s)" % (title, video_id) + for playlist_item in playlistitems_list_response['items']: + title = playlist_item['snippet']['title'] + video_id = playlist_item['snippet']['resourceId']['videoId'] + print '%s (%s)' % (title, video_id) playlistitems_list_request = youtube.playlistItems().list_next( playlistitems_list_request, playlistitems_list_response) - print +if __name__ == '__main__': + youtube = get_authenticated_service() + try: + uploads_playlist_id = get_my_uploads_list() + if uploads_playlist_id: + list_my_uploaded_videos(uploads_playlist_id) + else: + print('There is no uploaded videos playlist for this user.') + except HttpError, e: + print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content) From e09f1feb51a5b4b275501e0414478d6e567cc7bc Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Mon, 23 Oct 2017 11:22:35 -0400 Subject: [PATCH 107/126] Update auth libraries, separate "set" operations The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. In addition, the code for setting video localizations has been updated so that if the default language is set, the code checks to see whether the video has a title and description in that language. If so, the script sets the video's title and description to the current title and description in the default language. (Without that step, the title and description for the new default language are changed to match the title and description of the old default language.) --- python/video_localizations.py | 227 ++++++++++++++++++---------------- 1 file changed, 119 insertions(+), 108 deletions(-) diff --git a/python/video_localizations.py b/python/video_localizations.py index bd08653e..3412923a 100644 --- a/python/video_localizations.py +++ b/python/video_localizations.py @@ -3,15 +3,15 @@ # Usage example: # python video_localizations.py --action='<action>' --video_id='<video_id>' --default_language='<default_language>' --language='<language>' --title='<title>' --description='<description>' -import httplib2 +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 @@ -25,142 +25,153 @@ # 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 APIs Console -https://console.developers.google.com - -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)) +SCOPES = ['https://www.googleapis.com/auth/youtube'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' -# Authorize the request and store authorization credentials. -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())) +# Supported actions +ACTIONS = ('get', 'list', 'set') +# Authorize the request and store authorization credentials. +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) # Call the API's videos.update method to update an existing video's default language, # localized title and description in a specific language. -def set_video_localization(youtube, video_id, default_language, language, title, description): +def set_video_localization(youtube, args): + + # Retrieve the snippet and localizations for the video. results = youtube.videos().list( - part="snippet,localizations", - id=video_id + part='snippet,localizations', + id=args.video_id ).execute() - video = results["items"][0] - # Ensure that a value is set for the resource's snippet.defaultLanguage property. - video["snippet"]["defaultLanguage"] = default_language - if "localizations" not in video: - video["localizations"] = {} - video["localizations"][language] = { - "title": title, - "description": description - } - + video = results['items'][0] + + # If the language argument is set, set the localized title and description + # for that language. The "title" and "description" arguments have default + # values to make the script simpler to run as a demo. In an actual app, you + # would likely want to set those arguments also. + if args.language and args.language != '': + if 'localizations' not in video: + video['localizations'] = {} + + video['localizations'][args.language] = { + 'title': args.title, + 'description': args.description + } + + # If the default language is set AND there is localized metadata for that + # language, set the video's title and description to match the localized + # title and description for the newly set default language. + if args.default_language and args.default_language in video['localizations']: + video['snippet']['defaultLanguage'] = args.default_language + video['snippet']['title'] = ( + video['localizations'][args.default_language]['title']) + video['snippet']['description'] = ( + video['localizations'][args.default_language]['description']) + + # Update the video resource. update_result = youtube.videos().update( - part="snippet,localizations", - body=video - ).execute() - - localization = update_result["localizations"][language] - - print ("Updated video '%s' default language to '%s', localized title to '%s'" - " and description to '%s' in language '%s'" - % (video_id, default_language, localization["title"], localization["description"], language)) - + part='snippet,localizations', + body=video + ).execute() + + # Print the actions taken by running the script. + if args.language: + for language in update_result['localizations']: + # Languages with locales, like "pt-br" are returned as pt-BR in metadata. + # This ensures that the language specified when running the script can be + # matched to the language returned in the metadata. + if language.lower() == args.language.lower(): + localization = update_result['localizations'][args.language] + print ('Updated video \'%s\' localized title to \'%s\'' + ' and description to \'%s\' in language \'%s\'' % + (args.video_id, + localization['title'], + localization['description'], + args.language)) + break + + if (args.default_language and + args.default_language == update_result['snippet']['defaultLanguage']): + print 'Updated default language to %s' % args.default_language # Call the API's videos.list method to retrieve an existing video localization. # If the localized text is not available in the requested language, -# this method will return text in the default language. -def get_video_localization(youtube, video_id, language): +# this method returns text in the default language. +def get_video_localization(youtube, args): results = youtube.videos().list( - part="snippet", - id=video_id, - hl=language + part='snippet', + id=args.video_id, + hl=args.language ).execute() # The localized object contains localized text if the hl parameter specified # a language for which localized text is available. Otherwise, the localized - # object will contain metadata in the default language. - localized = results["items"][0]["snippet"]["localized"] + # object contains metadata in the default language. + localized = results['items'][0]['snippet']['localized'] - print ("Video title is '%s' and description is '%s' in language '%s'" - % (localized["title"], localized["description"], language)) + print ('Video title is \'%s\' and description is \'%s\' in language \'%s\'' + % (localized['title'], localized['description'], args.language)) # Call the API's videos.list method to list the existing video localizations. -def list_video_localizations(youtube, video_id): +def list_video_localizations(youtube, args): results = youtube.videos().list( - part="snippet,localizations", - id=video_id + part='snippet,localizations', + id=args.video_id ).execute() - localizations = results["items"][0]["localizations"] + localizations = results['items'][0]['localizations'] for language, localization in localizations.iteritems(): - print ("Video title is '%s' and description is '%s' in language '%s'" - % (localization["title"], localization["description"], language)) - - -if __name__ == "__main__": - # The "action" option specifies the action to be processed. - argparser.add_argument("--action", help="Action") - # The "video_id" option specifies the ID of the selected YouTube video. - argparser.add_argument("--video_id", - help="ID for video for which the localization will be applied.") - # The "default_language" option specifies the language of the video's default metadata. - argparser.add_argument("--default_language", help="Default language of the video to update.", - default="en") - # The "language" option specifies the language of the localization that is being processed. - argparser.add_argument("--language", help="Language of the localization.", default="de") - # The "title" option specifies the localized title of the video to be set. - argparser.add_argument("--title", help="Localized title of the video to be set.", - default="Localized Title") - # The "description" option specifies the localized description of the video to be set. - argparser.add_argument("--description", help="Localized description of the video to be set.", - default="Localized Description") - - args = argparser.parse_args() + print ('Video title is \'%s\' and description is \'%s\' in language \'%s\'' + % (localization['title'], localization['description'], language)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + # The action to be processed: 'get', 'list', and 'set' are supported. + parser.add_argument('--action', help='Action', choices=ACTIONS, required=True) + # The ID of the selected YouTube video. + parser.add_argument('--video_id', + help='The video ID for which localizations are being set or retrieved.', + required=True) + # The language of the video's default metadata. + parser.add_argument('--default_language', + help='Default language of the video to update.') + # The language of the localization that is being processed. + parser.add_argument('--language', help='Language of the localization.') + # The localized video title for the specified language. + parser.add_argument('--title', + help='Localized title of the video to be set.', + default='Localized Title') + # The localized description for the specified language. + parser.add_argument('--description', + help='Localized description of the video to be set.', + default='Localized Description') + + args = parser.parse_args() if not args.video_id: - exit("Please specify video id using the --video_id= parameter.") + exit('Please specify video id using the --video_id= parameter.') - youtube = get_authenticated_service(args) + youtube = get_authenticated_service() try: if args.action == 'set': - set_video_localization(youtube, args.video_id, args.default_language, args.language, args.title, args.description) + set_video_localization(youtube, args) elif args.action == 'get': - get_video_localization(youtube, args.video_id, args.language) + get_video_localization(youtube, args) elif args.action == 'list': - list_video_localizations(youtube, args.video_id) - else: - exit("Please specify a valid action using the --action= parameter.") + list_video_localizations(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 "Set and retrieved localized metadata for a video." + print 'Set and retrieved localized metadata for a video From f9ea8bfa59aa2c2068b0dbd648d627996842469d Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Mon, 23 Oct 2017 11:29:49 -0400 Subject: [PATCH 108/126] Update auth libraries The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. --- python/shuffle_channel_sections.py | 71 +++++++++--------------------- 1 file changed, 21 insertions(+), 50 deletions(-) diff --git a/python/shuffle_channel_sections.py b/python/shuffle_channel_sections.py index 2d9e0e29..fb05e522 100644 --- a/python/shuffle_channel_sections.py +++ b/python/shuffle_channel_sections.py @@ -1,15 +1,13 @@ #!/usr/bin/python -import httplib2 import os import random -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,52 +21,27 @@ # 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" +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) - - 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())) +# Authorize the request and store authorization credentials. +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) def get_current_channel_sections(youtube): channel_sections_list_response = youtube.channelSections().list( - part="snippet,contentDetails", + part='snippet,contentDetails', mine=True ).execute() - return channel_sections_list_response["items"] + return channel_sections_list_response['items'] def shuffle_channel_sections(youtube, channel_sections): # This will randomly reorder the items in the channel_sections list. @@ -77,21 +50,19 @@ def shuffle_channel_sections(youtube, channel_sections): for channel_section in channel_sections: # Each section in the list of shuffled sections is sequentially # set to position 0, i.e. the top. - channel_section["snippet"]["position"] = 0 + channel_section['snippet']['position'] = 0 youtube.channelSections().update( - part="snippet,contentDetails", + part='snippet,contentDetails', body=channel_section ).execute() if __name__ == '__main__': - args = argparser.parse_args() - - youtube = get_authenticated_service(args) + youtube = get_authenticated_service() try: channel_sections = get_current_channel_sections(youtube) shuffle_channel_sections(youtube, channel_sections) 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 "The existing channel sections have been randomly shuffled." + print 'The existing channel sections have been randomly shuffled.' From 2ac0c7e9d8ac2e1b1b923d1a67ffd9422159835b Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Tue, 24 Oct 2017 09:43:38 -0400 Subject: [PATCH 109/126] Update auth libraries, add snippet metadata opts The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. In addition, the code now supports other arguments for updating snippet metadata (title, description, tags). The --tags argument replaces the existing tags, while the --add_tag argument appends a tag to the current list. --- python/update_video.py | 124 ++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/python/update_video.py b/python/update_video.py index 2d428e6b..58609cb1 100644 --- a/python/update_video.py +++ b/python/update_video.py @@ -1,14 +1,16 @@ #!/usr/bin/python -import httplib2 +# Update the snippet metadata for a video. Sample usage: +# python update_video.py --video_id=<VIDEO_ID> --tags="<TAG1, TAG2>" --title="New title" --description="New description" + +import argparse import os -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 @@ -21,89 +23,87 @@ # 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)) +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_READ_WRITE_SCOPE, - message=MISSING_CLIENT_SECRETS_MESSAGE) +# Authorize the request and store authorization credentials. +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) - 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())) - -def update_video(youtube, options): +def update_video(youtube, args): # Call the API's videos.list method to retrieve the video resource. videos_list_response = youtube.videos().list( - id=options.video_id, + id=args.video_id, part='snippet' ).execute() - # If the response does not contain an array of "items" then the video was + # If the response does not contain an array of 'items' then the video was # not found. - if not videos_list_response["items"]: - print "Video '%s' was not found." % options.video_id + if not videos_list_response['items']: + print 'Video "%s" was not found.' % args.video_id sys.exit(1) # Since the request specified a video ID, the response only contains one # video resource. This code extracts the snippet from that resource. - videos_list_snippet = videos_list_response["items"][0]["snippet"] + videos_list_snippet = videos_list_response['items'][0]['snippet'] + + # Set video title, description, default language if specified in args. + if args.title: + videos_list_snippet['title'] = args.title + if args.description: + videos_list_snippet['description'] = args.description # Preserve any tags already associated with the video. If the video does # not have any tags, create a new array. Append the provided tag to the # list of tags associated with the video. - if "tags" not in videos_list_snippet: - videos_list_snippet["tags"] = [] - videos_list_snippet["tags"].append(options.tag) + if 'tags' not in videos_list_snippet: + videos_list_snippet['tags'] = [] + if args.tags: + videos_list_snippet['tags'] = args.tags.split(',') + elif args.add_tag: + videos_list_snippet['tags'].append(args.add_tag) + + print(videos_list_snippet); # Update the video resource by calling the videos.update() method. videos_update_response = youtube.videos().update( part='snippet', body=dict( snippet=videos_list_snippet, - id=options.video_id + id=args.video_id )).execute() -if __name__ == "__main__": - argparser.add_argument("--video-id", help="ID of video to update.", + print('The updated video metadata is:\n' + + 'Title: ' + videos_update_response['snippet']['title'] + '\n') + if videos_update_response['snippet']['description']: + print ('Description: ' + + videos_update_response['snippet']['description'] + '\n') + if videos_update_response['snippet']['tags']: + print ('Tags: ' + ','.join(videos_update_response['snippet']['tags']) + '\n') + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--video_id', help='ID of video to update.', required=True) - argparser.add_argument("--tag", default="youtube", - help="Additional tag to add to video.") - args = argparser.parse_args() - - youtube = get_authenticated_service(args) + parser.add_argument('--tags', + help='Comma-separated list of tags relevant to the video. This argument ' + + 'replaces the existing list of tags.') + parser.add_argument('--add_tag', help='Additional tag to add to video. ' + + 'This argument does not affect current tags.') + parser.add_argument('--title', help='Title of the video.') + parser.add_argument('--description', help='Description of the video.') + args = parser.parse_args() + + youtube = get_authenticated_service() try: update_video(youtube, args) except HttpError, e: - print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content) - else: - print "Tag '%s' was added to video id '%s'." % (args.tag, args.video_id) + print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content) + print 'Tag "%s" was added to video id "%s".' % (args.add_tag, args.video_id) From 7a7aa3e2d69e4d1b7f71ec91b6ad23864eeb1661 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Thu, 26 Oct 2017 17:25:31 -0400 Subject: [PATCH 110/126] Update auth libraries, add title/description args The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. The changes also add --title and --description arguments for the playlist title and description. A final note is that this script seems to be misnamed. This change did not change the functionality of the script, but it's likely a future change will either make this script update a playlist rather than insert one or provide an option for selecting an operation to perform for a playlist. --- python/playlist_updates.py | 112 ++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/python/playlist_updates.py b/python/playlist_updates.py index 60e14158..b1ab0504 100644 --- a/python/playlist_updates.py +++ b/python/playlist_updates.py @@ -1,14 +1,18 @@ #!/usr/bin/python -import httplib2 +# This code sample creates a private playlist in the authorizing user's +# YouTube channel. +# Usage: +# python playlist_updates.py --title=<TITLE> --description=<DESCRIPTION> + +import argparse import os -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 @@ -21,58 +25,54 @@ # 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 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_READ_WRITE_SCOPE = "https://www.googleapis.com/auth/youtube" -YOUTUBE_API_SERVICE_NAME = "youtube" -YOUTUBE_API_VERSION = "v3" - -flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, - message=MISSING_CLIENT_SECRETS_MESSAGE, - scope=YOUTUBE_READ_WRITE_SCOPE) - -storage = Storage("%s-oauth2.json" % sys.argv[0]) -credentials = storage.get() - -if credentials is None or credentials.invalid: - flags = argparser.parse_args() - credentials = run_flow(flow, storage, flags) - -youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, - http=credentials.authorize(httplib2.Http())) - -# This code creates a new, private playlist in the authorized user's channel. -playlists_insert_response = youtube.playlists().insert( - part="snippet,status", - body=dict( +SCOPES = ['https://www.googleapis.com/auth/youtube'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' + +# Authorize the request and store authorization credentials. +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) + +def add_playlist(youtube, args): + + body = dict( snippet=dict( - title="Test Playlist", - description="A private playlist created with the YouTube API v3" + title=args.title, + description=args.description ), status=dict( - privacyStatus="private" - ) - ) -).execute() - -print "New playlist id: %s" % playlists_insert_response["id"] + privacyStatus='private' + ) + ) + + playlists_insert_response = youtube.playlists().insert( + part='snippet,status', + body=body + ).execute() + + print 'New playlist ID: %s' % playlists_insert_response['id'] + +if __name__ == '__main__': + + parser = argparse.ArgumentParser() + parser.add_argument('--title', + default='Test Playlist', + help='The title of the new playlist.') + parser.add_argument('--description', + default='A private playlist created with the YouTube Data API.', + help='The description of the new playlist.') + + args = parser.parse_args() + + youtube = get_authenticated_service() + try: + add_playlist(youtube, args) + except HttpError, e: + print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content) From dfd5cfdf63716f704a3bf0876dae90f78122f0a5 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 11:13:18 -0400 Subject: [PATCH 111/126] Add prerequisites --- python/README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/python/README.md b/python/README.md index 3aacd516..77f25069 100644 --- a/python/README.md +++ b/python/README.md @@ -1,3 +1,29 @@ +## Prerequisites + +* Python 2.6 or greater + +* The pip package management tool + +* The Google APIs Client Library for Python: + ``` + pip install --upgrade google-api-python-client + ``` +* The google-auth, google-auth-oauthlib, and google-auth-httplib2 for user authorization. + ``` + pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2 + ``` + +### Setting up your project and running code samples + +1. Create a project in the API Console and set up credentials for a web application. Set the authorized redirect URIs as appropriate. +2. Save the client_secrets.json file associated with your credentials to a local file. +3. Copy the full code sample to a local file in the same directory as the client_secrets.json file (or modify the sample to correctly identify that file's location. +4. Run the sample from the command line and set command-line arguments as necessary: + + ```python sample.py --arg1=value1 --arg2=value2 ...``` + +5. Most samples print something to STDOUT. You can also check the YouTube website to see the effects of requests that write data, such as requests that create playlists or channel sections. + ## Samples in this directory: ### [Add a channel section](/python/add_channel_section.py) From c8e98d8da316a9d45b1a15082145a1710b4ec444 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 11:14:46 -0400 Subject: [PATCH 112/126] Update auth libraries, add options, documentation The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. The updated script has improved options, allowing the user to set a content owner ID, job ID, report URL, and/or local filename using command-line arguments. The logic also now bypasses certain functions depending on the command-line arguments set. For example, if you specify the URL of the report that you want to download, the script doesn't prompt you to select a job and a report (since you've already done that). The prerequisites section in the README file explains how to run this sample (and others in this directory). --- python/retrieve_reports.py | 203 +++++++++++++++++++++---------------- 1 file changed, 116 insertions(+), 87 deletions(-) diff --git a/python/retrieve_reports.py b/python/retrieve_reports.py index 7f799c3c..f30005bf 100644 --- a/python/retrieve_reports.py +++ b/python/retrieve_reports.py @@ -1,23 +1,36 @@ #!/usr/bin/python -# Usage example: -# python retrieve_reports.py - -import httplib2 +### +# +# This script retrieves YouTube Reporting API reports. Use cases: +# 1. If you specify a report URL, the script downloads that report. +# 2. Otherwise, if you specify a job ID, the script retrieves a list of +# available reports for that job and prompts you to select a report. +# Then it retrieves that report as in case 1. +# 3. Otherwise, the list retrieves a list of jobs for the user or, +# if specified, the content owner that the user is acting on behalf of. +# Then it prompts the user to select a job, and then executes case 2 and +# then case 1. +# Usage examples: +# python retrieve_reports.py --content_owner_id=<CONTENT_OWNER_ID> --local_file=<LOCAL_FILE> +# python retrieve_reports.py --content_owner_id=<CONTENT_OWNER_ID> --job_id=<JOB_ID> --local_file=<LOCAL_FILE> +# python retrieve_reports.py --content_owner_id=<CONTENT_OWNER_ID> --report_url=<REPORT_URL> --local_file=<LOCAL_FILE> +# +### + +import argparse import os -import sys -from apiclient.discovery import build -from apiclient.errors import HttpError -from apiclient.http import MediaIoBaseDownload +import google.oauth2.credentials +import google_auth_oauthlib.flow +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError +from googleapiclient.http import MediaIoBaseDownload +from google_auth_oauthlib.flow import InstalledAppFlow from io import FileIO -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 @@ -27,84 +40,75 @@ # 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 read access to the YouTube Analytics monetary reports for -# authenticated user's account. Any request that retrieves earnings or ad performance metrics must -# use this scope. -YOUTUBE_ANALYTICS_MONETARY_READ_SCOPE = ( - "https://www.googleapis.com/auth/yt-analytics-monetary.readonly") -YOUTUBE_REPORTING_API_SERVICE_NAME = "youtubereporting" -YOUTUBE_REPORTING_API_VERSION = "v1" - -# 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 APIs Console -https://console.developers.google.com - -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)) - -# Authorize the request and store authorization credentials. -def get_authenticated_service(args): - flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_ANALYTICS_MONETARY_READ_SCOPE, - message=MISSING_CLIENT_SECRETS_MESSAGE) +CLIENT_SECRETS_FILE = 'client_secret.json' - 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_REPORTING_API_SERVICE_NAME, YOUTUBE_REPORTING_API_VERSION, - http=credentials.authorize(httplib2.Http())) +# This OAuth 2.0 access scope allows for read access to YouTube Analytics +# monetary reports for the authenticated user's account. Any request that +# retrieves earnings or ad performance metrics must use this scope. +SCOPES = ['https://www.googleapis.com/auth/yt-analytics-monetary.readonly'] +API_SERVICE_NAME = 'youtubereporting' +API_VERSION = 'v1' +# Authorize the request and store authorization credentials. +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) + +# Remove keyword arguments that are not set. +def remove_empty_kwargs(**kwargs): + good_kwargs = {} + if kwargs is not None: + for key, value in kwargs.iteritems(): + if value: + good_kwargs[key] = value + return good_kwargs # Call the YouTube Reporting API's jobs.list method to retrieve reporting jobs. -def list_reporting_jobs(youtube_reporting): - results = youtube_reporting.jobs().list( - ).execute() +def list_reporting_jobs(youtube_reporting, **kwargs): + # Only include the onBehalfOfContentOwner keyword argument if the user + # set a value for the --content_owner argument. + kwargs = remove_empty_kwargs(**kwargs) + + # Retrieve the reporting jobs for the user (or content owner). + results = youtube_reporting.jobs().list(**kwargs).execute() - if "jobs" in results and results["jobs"]: - jobs = results["jobs"] + if 'jobs' in results and results['jobs']: + jobs = results['jobs'] for job in jobs: - print ("Reporting job id: %s\n name: %s\n for reporting type: %s\n" - % (job["id"], job["name"], job["reportTypeId"])) + print ('Reporting job id: %s\n name: %s\n for reporting type: %s\n' + % (job['id'], job['name'], job['reportTypeId'])) else: - print "No jobs found" + print 'No jobs found' return False return True - # Call the YouTube Reporting API's reports.list method to retrieve reports created by a job. -def retrieve_reports(youtube_reporting, job_id): +def retrieve_reports(youtube_reporting, **kwargs): + # Only include the onBehalfOfContentOwner keyword argument if the user + # set a value for the --content_owner argument. + kwargs = remove_empty_kwargs(**kwargs) + + # Retrieve available reports for the selected job. results = youtube_reporting.jobs().reports().list( - jobId=job_id + **kwargs ).execute() - if "reports" in results and results["reports"]: - reports = results["reports"] + if 'reports' in results and results['reports']: + reports = results['reports'] for report in reports: - print ("Report from '%s' to '%s' downloadable at '%s'" - % (report["startTime"], report["endTime"], report["downloadUrl"])) + print ('Report dates: %s to %s\n download URL: %s\n' + % (report['startTime'], report['endTime'], report['downloadUrl'])) # Call the YouTube Reporting API's media.download method to download the report. -def download_report(youtube_reporting, report_url): +def download_report(youtube_reporting, report_url, local_file): request = youtube_reporting.media().download( - resourceName="" + resourceName=' ' ) request.uri = report_url - fh = FileIO('report', mode='wb') + fh = FileIO(local_file, mode='wb') # Stream/download the report in a single request. downloader = MediaIoBaseDownload(fh, request, chunksize=-1) @@ -112,32 +116,57 @@ def download_report(youtube_reporting, report_url): while done is False: status, done = downloader.next_chunk() if status: - print "Download %d%%." % int(status.progress() * 100) - print "Download Complete!" + print 'Download %d%%.' % int(status.progress() * 100) + print 'Download Complete!' -# Prompt the user to enter a job id for report retrieval. Then return the id. +# Prompt the user to select a job and return the specified ID. def get_job_id_from_user(): - job_id = raw_input("Please enter the job id for the report retrieval: ") - print ("You chose '%s' as the job Id for the report retrieval." % job_id) + job_id = raw_input('Please enter the job id for the report retrieval: ') + print ('You chose "%s" as the job Id for the report retrieval.' % job_id) return job_id - -# Prompt the user to enter a report URL for download. Then return the URL. +# Prompt the user to select a report URL and return the specified URL. def get_report_url_from_user(): - report_url = raw_input("Please enter the report URL to download: ") - print ("You chose '%s' to download." % report_url) + report_url = raw_input('Please enter the report URL to download: ') + print ('You chose "%s" to download.' % report_url) return report_url -if __name__ == "__main__": - args = argparser.parse_args() - - youtube_reporting = get_authenticated_service(args) +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--content_owner', default='', + help='ID of content owner for which you are retrieving jobs and reports') + parser.add_argument('--job_id', default=None, + help='ID of the job for which you are retrieving reports. If not ' + + 'provided AND report_url is also not provided, then the script ' + + 'calls jobs.list() to retrieve a list of jobs.') + parser.add_argument('--report_url', default=None, + help='URL of the report to retrieve. If not specified, the script ' + + 'calls reports.list() to retrieve a list of reports for the ' + + 'selected job.') + parser.add_argument('--local_file', default='yt_report.txt', + help='The name of the local file where the downloaded report will be written.') + args = parser.parse_args() + + youtube_reporting = get_authenticated_service() try: - if list_reporting_jobs(youtube_reporting): - retrieve_reports(youtube_reporting, get_job_id_from_user()) - download_report(youtube_reporting, get_report_url_from_user()) + # If the user has not specified a job ID or report URL, retrieve a list + # of available jobs and prompt the user to select one. + if not args.job_id and not args.report_url: + if list_reporting_jobs(youtube_reporting, + onBehalfOfContentOwner=args.content_owner): + args.job_id = get_job_id_from_user() + + # If the user has not specified a report URL, retrieve a list of reports + # available for the specified job and prompt the user to select one. + if args.job_id and not args.report_url: + retrieve_reports(youtube_reporting, + jobId=args.job_id, + onBehalfOfContentOwner=args.content_owner) + args.report_url = get_report_url_from_user() + + # Download the selected report. + if args.report_url: + download_report(youtube_reporting, args.report_url, args.local_file) except HttpError, e: - print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content) - else: - print "Retrieved reports." + print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content) From d598fb3634820fbf91696f13cc8d4282a5f4c857 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 11:47:52 -0400 Subject: [PATCH 113/126] Update auth libraries and make script improvements The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. In addition, the code now has more flexible support for command-line arguments. For example, it does not set a default language by default ... you need to specify that on the command line. In addition, you can now add a localization without setting a default language or set a default language without adding a localization. Finally, the --mine argument lets you list all of your channel's sections and their localized values, making it easier to then use the script to add a localization for a single channel section. --- python/channel_section_localizations.py | 253 ++++++++++++++---------- 1 file changed, 152 insertions(+), 101 deletions(-) diff --git a/python/channel_section_localizations.py b/python/channel_section_localizations.py index a20ecf02..b809d5df 100644 --- a/python/channel_section_localizations.py +++ b/python/channel_section_localizations.py @@ -1,17 +1,22 @@ #!/usr/bin/python -# Usage example: +# Retrieve or set localized channel section metadata. +# See the Prerequisites section in the README file in this directory +# for more information about running this sample locally. + +# Usage examples: +# python channel_sections_localizations.py --action=list --mine=True # python channel_sections_localizations.py --action='<action>' --channel_section_id='<channel_section_id>' --default_language='<default_language>' --language='<language>' --title='<title>' -import httplib2 +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 @@ -25,135 +30,181 @@ # 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 APIs Console -https://console.developers.google.com - -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)) - -# Authorize the request and store authorization credentials. -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) +SCOPES = ['https://www.googleapis.com/auth/youtube'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' - return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, - http=credentials.authorize(httplib2.Http())) +ACTIONS = ('get', 'list', 'set') +# Authorize the request and store authorization credentials. +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) # Call the API's channelSections.update method to update an existing channel section's # default language, and localized title in a specific language. -def set_channel_section_localization(youtube, channel_section_id, default_language, language, title): +def set_channel_section_localization(youtube, args): + + # Retrieve the snippet and localizations for the channel section. results = youtube.channelSections().list( - part="snippet,localizations", - id=channel_section_id + part='snippet,contentDetails,localizations', + id=args.channel_section_id ).execute() - channel_section = results["items"][0] - # Ensure that a value is set for the resource's snippet.defaultLanguage property. - channel_section["snippet"]["defaultLanguage"] = default_language - if "localizations" not in channel_section: - channel_section["localizations"] = {} - channel_section["localizations"][language] = { - "title": title - } + channel_section = results['items'][0] + + # If the language argument is set, set the localized title for that language. + # The "title" argument has a default value to make the script simpler to run + # as a demo. But in an actual app, you would likely want to set its value. + if args.language and args.language != '': + if 'localizations' not in channel_section: + channel_section['localizations'] = {} + + channel_section['localizations'][args.language] = { + 'title': args.title, + } + + # If the default language is set AND there is localized metadata for that + # language, set the channel section's title and description to match the + # localized title and description for the newly set default language. + if args.default_language: + channel_section['snippet']['defaultLanguage'] = args.default_language + if args.default_language in channel_section['localizations']: + channel_section['snippet']['title'] = ( + channel_section['localizations'][args.default_language]['title']) update_result = youtube.channelSections().update( - part="snippet,localizations", + part='snippet,contentDetails,localizations', body=channel_section ).execute() - localization = update_result["localizations"][language] - - print ("Updated channel section '%s' default language to '%s', localized title" - " to '%s' in language '%s'" % (channel_section_id, localization["title"], language)) - + if args.language: + for language in update_result['localizations']: + # Languages with locales, like "pt-br" are returned as pt-BR in metadata. + # This ensures that the language specified when running the script can be + # matched to the language returned in the metadata. + if language.lower() == args.language.lower(): + localization = update_result['localizations'][args.language] + print ('Updated channel section %s localized title to %s in \'%s\'.' % + (args.channel_section_id, localization['title'], args.language)) + break + + if (args.default_language and + args.default_language == update_result['snippet']['defaultLanguage']): + print 'Updated default language to %s.' % args.default_language # Call the API's channelSections.list method to retrieve an existing channel section localization. # If the localized text is not available in the requested language, # this method will return text in the default language. -def get_channel_section_localization(youtube, channel_section_id, language): +def get_channel_section_localization(youtube, args): results = youtube.channelSections().list( - part="snippet", - id=channel_section_id, - hl=language + part='snippet', + id=args.channel_section_id, + hl=args.language ).execute() # The localized object contains localized text if the hl parameter specified # a language for which localized text is available. Otherwise, the localized # object will contain metadata in the default language. - localized = results["items"][0]["snippet"]["localized"] - - print "Channel section title is '%s' in language '%s'" % (localized["title"], language) + localized = results['items'][0]['snippet']['localized'] + print('The channel section\'s title is \'%s\' in language \'%s\'.' % + (localized['title'], language)) -# Call the API's channelSections.list method to list the existing channel section localizations. -def list_channel_section_localizations(youtube, channel_section_id): +# Call the API's channelSections.list method to list all existing localizations +# for the channel section. +def list_channel_section_localizations(youtube, args): results = youtube.channelSections().list( - part="snippet,localizations", - id=channel_section_id + part='snippet,localizations', + id=args.channel_section_id ).execute() - localizations = results["items"][0]["localizations"] + localizations = results['items'][0]['localizations'] for language, localization in localizations.iteritems(): - print "Channel section title is '%s' in language '%s'" % (localization["title"], language) - - -if __name__ == "__main__": - # The "action" option specifies the action to be processed. - argparser.add_argument("--action", help="Action") - # The "channel_section_id" option specifies the ID of the selected YouTube channel section. - argparser.add_argument("--channel_section_id", - help="ID for channel section for which the localization will be applied.") - # The "default_language" option specifies the language of the channel section's default metadata. - argparser.add_argument("--default_language", - help="Default language of the channel section to update.", default="en") - # The "language" option specifies the language of the localization that is being processed. - argparser.add_argument("--language", help="Language of the localization.", default="de") - # The "title" option specifies the localized title of the channel section to be set. - argparser.add_argument("--title", help="Localized title of the channel section to be set.", - default="Localized Title") - - args = argparser.parse_args() - - if not args.channel_section_id: - exit("Please specify channel section id using the --channel_section_id= parameter.") - - youtube = get_authenticated_service(args) + print('The channel section title is \'%s\' in language \'%s\'.' % + (localization['title'], language)) + +# Call the API's channelSections.list method to list localizations for all +# channel sections in the authorizing user\'s channel. This function might +# be called as a way of identifying the ID of the section you actually want +# to update. +def list_my_channel_section_localizations(youtube, args): + results = youtube.channelSections().list( + part='snippet,localizations', + mine=True, + ).execute() + + print(results) + + for i in range(0, len(results['items'])): + item = results['items'][i] + print str(item['snippet']['position']) + ':' + print ' ID: ' + item['id'] + print ' Type: ' + item['snippet']['type'] + if ('title' in item['snippet'] and item['snippet']['title']): + print ' Title: ' + str(item['snippet']['title']) + + if 'localizations' in results['items'][i]: + localizations = results['items'][i]['localizations'] + print(' Localized titles by language:') + for language, localization in localizations.iteritems(): + print(' ' + language + ': ' + localization['title']) + else: + print(' No localizations. :(\n') + + #for language, localization in localizations.iteritems(): + # print('The channel section title is \'%s\' in language \'%s\'.' % + # (localization['title'], language)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + # The 'action' option specifies the action to be processed. + parser.add_argument('--action', choices=ACTIONS, required=True, + help='The type of operation. Supported values are: "get", "list", "set"') + # The ID of the channel section for which data is being retrieved or updated. + parser.add_argument('--channel_section_id', + help='ID of channel section for which localized data is being ' + + 'retrieved or updated.') + # The language of the channel section's default metadata. + parser.add_argument('--default_language', + help='Default language of the channel section to update.') + # The language of the localization that is being processed. + parser.add_argument('--language', help='Language of the localized metadata.') + # The localized channel section title for the specified language. + parser.add_argument('--title', + help='Localized title of the channel section to be set.', + default='Localized Title') + # The language of the channel section's default metadata. + parser.add_argument('--mine', type=bool, default=False, + help='List localizations for all of my channel sections.') + + args = parser.parse_args() + + if not args.channel_section_id and not args.mine: + exit('You must either specify a channel section ID using the ' + + '--channel_section_id argument or retrieve localizations ' + + 'for all of your channel sections by setting the --mine ' + + 'argument to True.') + + youtube = get_authenticated_service() try: if args.action == 'set': - set_channel_section_localization(youtube, args.channel_section_id, args.default_language, args.language, args.title) + set_channel_section_localization(youtube, args) elif args.action == 'get': - get_channel_section_localization(youtube, args.channel_section_id, args.language) + get_channel_section_localization(youtube, args) elif args.action == 'list': - list_channel_section_localizations(youtube, args.channel_section_id) + if args.mine: + list_my_channel_section_localizations(youtube, args) + else: + list_channel_section_localizations(youtube, args) else: - exit("Please specify a valid action using the --action= parameter.") + exit('Please specify a valid action using the --action= parameter.') except HttpError, e: - print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content) - else: - print "Set and retrieved localized metadata for a channel section." + print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content) From a0e45b621f6f6d516b13bc8960050a954e7f4624 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 14:00:29 -0400 Subject: [PATCH 114/126] Update script options, functionality, docs, auth Functionality updates: - Add ability to run script for channel ID or content owner - Add option to set filters - Change default metrics, remove default max results - Remove additional call to YouTube Data API to get channel ID and just set ids=channel==MINE - Add function to properly set "ids" parameter depending on whether content-owner or channel-id command-line arguments are set - Pass API request parameters as keyword arguments (**args) rather than listing them line by line The functionality in the script is more thoroughly documented. Also see the Prerequisites section of the README file for more information about running this sample. Finally, the oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. --- python/yt_analytics_report.py | 245 ++++++++++++++++++++-------------- 1 file changed, 142 insertions(+), 103 deletions(-) diff --git a/python/yt_analytics_report.py b/python/yt_analytics_report.py index 6e816106..1df122bf 100644 --- a/python/yt_analytics_report.py +++ b/python/yt_analytics_report.py @@ -1,15 +1,41 @@ #!/usr/bin/python -from datetime import datetime, timedelta -import httplib2 +### +# +# Retrieves YouTube Analytics report data. The script's default behavior +# is to retrieve data for the authenticated user's channel. However, if you +# set a value for the --content-owner command-line argument, then the script +# retrieves data for that content owner. Note that the user running the script +# must be authorized to retrieve data for that content owner. +# +# Note that when you retrieve Analytics data for a content owner, your API +# request must set a value for the "filters" request parameter as explained +# in the API documentation here: +# https://developers.google.com/youtube/analytics/v1/content_owner_reports#Filters +# +# By default, if you set a value for the --content-owner argument, then the +# "filters" parameter is set to "claimedStatus==claimed". (On the other hand, +# this value is not set if you are retrieving data for your own channel.) +# +# You can use the --filters command-line argument to set the "filters" parameter +# for any request. For example: +# * --filters="channel==CHANNEL_ID" +# * --filters="channel==CHANNEL_ID;country==COUNTRY_CODE" +# * --filters="video==VIDEO_ID" +# " --filters="claimedStatus==claimed;uploaderType==thirdParty" +# and so forth. +# +### + +import argparse import os -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 +from datetime import datetime, timedelta # The CLIENT_SECRETS_FILE variable specifies the name of a file that contains @@ -17,115 +43,128 @@ # 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 Data and YouTube Analytics -# APIs for your project. -# For more information about using OAuth2 to access the YouTube Data API, see: -# https://developers.google.com/youtube/v3/guides/authentication -# For more information about the client_secrets.json file format, see: +# Please ensure that you have enabled the YouTube Analytics API for your project. +# For more information about using OAuth2 to access the YouTube Analytics API, see: +# https://developers.google.com/youtube/reporting/guides/authorization +# For more information about the client_secret.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' # These OAuth 2.0 access scopes allow for read-only access to the authenticated # user's account for both YouTube Data API resources and YouTube Analytics Data. -YOUTUBE_SCOPES = ["https://www.googleapis.com/auth/youtube.readonly", - "https://www.googleapis.com/auth/yt-analytics.readonly"] -YOUTUBE_API_SERVICE_NAME = "youtube" -YOUTUBE_API_VERSION = "v3" -YOUTUBE_ANALYTICS_API_SERVICE_NAME = "youtubeAnalytics" -YOUTUBE_ANALYTICS_API_VERSION = "v1" - -# 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_services(args): - flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, - scope=" ".join(YOUTUBE_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()) - - youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, - http=http) - youtube_analytics = build(YOUTUBE_ANALYTICS_API_SERVICE_NAME, - YOUTUBE_ANALYTICS_API_VERSION, http=http) - - return (youtube, youtube_analytics) - -def get_channel_id(youtube): - channels_list_response = youtube.channels().list( - mine=True, - part="id" - ).execute() - - return channels_list_response["items"][0]["id"] - -def run_analytics_report(youtube_analytics, channel_id, options): - # Call the Analytics API to retrieve a report. For a list of available - # reports, see: +SCOPES = ['https://www.googleapis.com/auth/yt-analytics.readonly'] +API_SERVICE_NAME = 'youtubeAnalytics' +API_VERSION = 'v1' + +# Authorize the request and store authorization credentials. +def get_authenticated_service(): + flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES) + credentials = flow.run_console() + + api_service = build(API_SERVICE_NAME, API_VERSION, credentials=credentials) + return api_service + +# Remove keyword arguments that are not set. +def remove_empty_args(args): + original_args = vars(args) + good_args = {} + if original_args is not None: + for key, value in original_args.iteritems(): + # The channel_id and content_owner arguments are provided as a means + # of properly setting the "ids" parameter value. However, they should + # not be included in the API request (since they're not parameters + # supported by this method). + if value and key != 'channel_id' and key != 'content_owner': + good_args[key] = value + return good_args + +# Set the "ids" request parameter for the YouTube Analytics API request. +def set_ids_parameter(args): + if args.content_owner: + args.ids = 'contentOwner==' + args.content_owner + if args.filters == '': + args.filters = 'claimedStatus==claimed' + elif args.channel_id: + args.ids = 'channel==' + args.channel_id + else: + args.ids = 'channel==MINE' + args = remove_empty_args(args) + print args + return args + +def run_analytics_report(youtube_analytics, args): + # Call the Analytics API to retrieve a report. Pass args in as keyword + # arguments to set values for the following parameters: + # + # * ids + # * metrics + # * dimensions + # * filters + # * start_date + # * end_date + # * sort + # * max_results + # + # For a list of available reports, see: # https://developers.google.com/youtube/analytics/v1/channel_reports + # https://developers.google.com/youtube/analytics/v1/content_owner_reports analytics_query_response = youtube_analytics.reports().query( - ids="channel==%s" % channel_id, - metrics=options.metrics, - dimensions=options.dimensions, - start_date=options.start_date, - end_date=options.end_date, - max_results=options.max_results, - sort=options.sort + **args ).execute() - print "Analytics Data for Channel %s" % channel_id + #print 'Analytics Data for Channel %s' % channel_id - for column_header in analytics_query_response.get("columnHeaders", []): - print "%-20s" % column_header["name"], + for column_header in analytics_query_response.get('columnHeaders', []): + print '%-20s' % column_header['name'], print - for row in analytics_query_response.get("rows", []): + for row in analytics_query_response.get('rows', []): for value in row: - print "%-20s" % value, + print '%-20s' % value, print -if __name__ == "__main__": +if __name__ == '__main__': now = datetime.now() - one_day_ago = (now - timedelta(days=1)).strftime("%Y-%m-%d") - one_week_ago = (now - timedelta(days=7)).strftime("%Y-%m-%d") - - argparser.add_argument("--metrics", help="Report metrics", - default="views,comments,favoritesAdded,favoritesRemoved,likes,dislikes,shares") - argparser.add_argument("--dimensions", help="Report dimensions", - default="video") - argparser.add_argument("--start-date", default=one_week_ago, - help="Start date, in YYYY-MM-DD format") - argparser.add_argument("--end-date", default=one_day_ago, - help="End date, in YYYY-MM-DD format") - argparser.add_argument("--max-results", help="Max results", default=10) - argparser.add_argument("--sort", help="Sort order", default="-views") - args = argparser.parse_args() - - (youtube, youtube_analytics) = get_authenticated_services(args) + one_day_ago = (now - timedelta(days=1)).strftime('%Y-%m-%d') + one_week_ago = (now - timedelta(days=7)).strftime('%Y-%m-%d') + + parser = argparse.ArgumentParser() + + # Set channel ID or content owner. Default is authenticated user's channel. + parser.add_argument('--channel-id', default='', + help='YouTube channel ID for which data should be retrieved. ' + + 'Note that the default behavior is to retrieve data for ' + + 'the authenticated user\'s channel.') + parser.add_argument('--content-owner', default='', + help='The name of the content owner for which data should be ' + + 'retrieved. If you retrieve data for a content owner, then ' + + 'your API request must also set a value for the "filters" ' + + 'parameter. See the help for that parameter for more details.') + + # Metrics, dimensions, filters + parser.add_argument('--metrics', help='Report metrics', + default='views,estimatedMinutesWatched,averageViewDuration') + parser.add_argument('--dimensions', help='Report dimensions', default='') + parser.add_argument('--filters', default='', + help='Filters for the report. Note that the filters request parameter ' + + 'must be set in YouTube Analytics API requests for content owner ' + + 'reports. The script sets "filters=claimedStatus==claimed" if a ' + + 'content owner is specified and filters are not specified.') + + # Report dates. Defaults to start 7 days ago, end yesterday. + parser.add_argument('--start-date', default=one_week_ago, + help='Start date, in YYYY-MM-DD format') + parser.add_argument('--end-date', default=one_day_ago, + help='End date, in YYYY-MM-DD format') + + parser.add_argument('--max-results', help='Max results') + parser.add_argument('--sort', help='Sort order', default='') + + args = parser.parse_args() + args = set_ids_parameter(args) + + youtube_analytics = get_authenticated_service() try: - channel_id = get_channel_id(youtube) - run_analytics_report(youtube_analytics, channel_id, args) + run_analytics_report(youtube_analytics, 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) From b374c1ecf1279bb79c8d9bf0ae163f56f1236eab Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 14:04:11 -0400 Subject: [PATCH 115/126] Fix typos in comments --- python/yt_analytics_report.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/yt_analytics_report.py b/python/yt_analytics_report.py index 1df122bf..35a52f31 100644 --- a/python/yt_analytics_report.py +++ b/python/yt_analytics_report.py @@ -22,8 +22,8 @@ # * --filters="channel==CHANNEL_ID" # * --filters="channel==CHANNEL_ID;country==COUNTRY_CODE" # * --filters="video==VIDEO_ID" -# " --filters="claimedStatus==claimed;uploaderType==thirdParty" -# and so forth. +# * --filters="claimedStatus==claimed;uploaderType==thirdParty" +# * etc. # ### From d45d4fe55abb3b23b8e94bd07edf0ce317c24b7c Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 15:09:38 -0400 Subject: [PATCH 116/126] Update auth libs, default privacy status The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. This update also updates the default privacy status for videos uploaded via this script to "private". The privacy status can be changed using the --privacyStatus command line argument. --- python/upload_video.py | 119 ++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 73 deletions(-) diff --git a/python/upload_video.py b/python/upload_video.py index 2e68766c..0b52bc36 100644 --- a/python/upload_video.py +++ b/python/upload_video.py @@ -1,18 +1,18 @@ #!/usr/bin/python +import argparse import httplib import httplib2 import os import random -import sys import time -from apiclient.discovery import build -from apiclient.errors import HttpError -from apiclient.http import MediaFileUpload -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 googleapiclient.http import MediaFileUpload +from google_auth_oauthlib.flow import InstalledAppFlow # Explicitly tell the underlying HTTP transport library not to retry, since @@ -42,53 +42,27 @@ # 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 an application to upload files to the # authenticated user's YouTube channel, but doesn't allow other types of access. -YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload" -YOUTUBE_API_SERVICE_NAME = "youtube" -YOUTUBE_API_VERSION = "v3" +SCOPES = ['https://www.googleapis.com/auth/youtube.upload'] +API_SERVICE_NAME = '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 +VALID_PRIVACY_STATUSES = ('public', 'private', 'unlisted') -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)) - -VALID_PRIVACY_STATUSES = ("public", "private", "unlisted") - - -def get_authenticated_service(args): - flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, - scope=YOUTUBE_UPLOAD_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())) +# Authorize the request and store authorization credentials. +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) def initialize_upload(youtube, options): tags = None if options.keywords: - tags = options.keywords.split(",") + tags = options.keywords.split(',') body=dict( snippet=dict( @@ -104,14 +78,14 @@ def initialize_upload(youtube, options): # Call the API's videos.insert method to create and upload the video. insert_request = youtube.videos().insert( - part=",".join(body.keys()), + part=','.join(body.keys()), body=body, # The chunksize parameter specifies the size of each chunk of data, in # bytes, that will be uploaded at a time. Set a higher value for # reliable connections as fewer chunks lead to faster uploads. Set a lower # value for better recovery on less reliable connections. # - # Setting "chunksize" equal to -1 in the code below means that the entire + # Setting 'chunksize' equal to -1 in the code below means that the entire # file will be uploaded in a single HTTP request. (If the upload fails, # it will still be retried where it left off.) This is usually a best # practice, but if you're using Python older than 2.6 or if you're @@ -124,58 +98,57 @@ def initialize_upload(youtube, options): # This method implements an exponential backoff strategy to resume a # failed upload. -def resumable_upload(insert_request): +def resumable_upload(request): response = None error = None retry = 0 while response is None: try: - print "Uploading file..." - status, response = insert_request.next_chunk() + print 'Uploading file...' + status, response = request.next_chunk() if response is not None: if 'id' in response: - print "Video id '%s' was successfully uploaded." % response['id'] + print 'Video id "%s" was successfully uploaded.' % response['id'] else: - exit("The upload failed with an unexpected response: %s" % response) + exit('The upload failed with an unexpected response: %s' % response) except HttpError, e: if e.resp.status in RETRIABLE_STATUS_CODES: - error = "A retriable HTTP error %d occurred:\n%s" % (e.resp.status, + error = 'A retriable HTTP error %d occurred:\n%s' % (e.resp.status, e.content) else: raise except RETRIABLE_EXCEPTIONS, e: - error = "A retriable error occurred: %s" % e + error = 'A retriable error occurred: %s' % e if error is not None: print error retry += 1 if retry > MAX_RETRIES: - exit("No longer attempting to retry.") + exit('No longer attempting to retry.') max_sleep = 2 ** retry sleep_seconds = random.random() * max_sleep - print "Sleeping %f seconds and then retrying..." % sleep_seconds + print 'Sleeping %f seconds and then retrying...' % sleep_seconds time.sleep(sleep_seconds) if __name__ == '__main__': - argparser.add_argument("--file", required=True, help="Video file to upload") - argparser.add_argument("--title", help="Video title", default="Test Title") - argparser.add_argument("--description", help="Video description", - default="Test Description") - argparser.add_argument("--category", default="22", - help="Numeric video category. " + - "See https://developers.google.com/youtube/v3/docs/videoCategories/list") - argparser.add_argument("--keywords", help="Video keywords, comma separated", - default="") - argparser.add_argument("--privacyStatus", choices=VALID_PRIVACY_STATUSES, - default=VALID_PRIVACY_STATUSES[0], help="Video privacy status.") - args = argparser.parse_args() - - if not os.path.exists(args.file): - exit("Please specify a valid file using the --file= parameter.") - - youtube = get_authenticated_service(args) + parser = argparse.ArgumentParser() + parser.add_argument('--file', required=True, help='Video file to upload') + parser.add_argument('--title', help='Video title', default='Test Title') + parser.add_argument('--description', help='Video description', + default='Test Description') + parser.add_argument('--category', default='22', + help='Numeric video category. ' + + 'See https://developers.google.com/youtube/v3/docs/videoCategories/list') + parser.add_argument('--keywords', help='Video keywords, comma separated', + default='') + parser.add_argument('--privacyStatus', choices=VALID_PRIVACY_STATUSES, + default='private', help='Video privacy status.') + args = parser.parse_args() + + youtube = get_authenticated_service() + try: initialize_upload(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) From e084e3eff22376014aa28f82300d24250f4bd514 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 15:12:36 -0400 Subject: [PATCH 117/126] Delete obsolete code sample --- python/batch_report_download.py | 145 -------------------------------- 1 file changed, 145 deletions(-) delete mode 100644 python/batch_report_download.py 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) From 2fa8d26e895940b05d02f2c26fdcef8fbc0feaa9 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 16:12:41 -0400 Subject: [PATCH 118/126] Support more options, update auth flow Add command line options for setting content owner (for onBehalfOfContentOwner parameter) and for whether the script should list system-managed reports when listing reports. Instead of making --name a required command line argument, prompt the user to enter a name if one isn't set. This prompt occurs after the user selects a report type. Allow user to set report type on command line and thereby bypass the report type selection. The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. --- python/create_reporting_job.py | 160 ++++++++++++++++++--------------- 1 file changed, 87 insertions(+), 73 deletions(-) diff --git a/python/create_reporting_job.py b/python/create_reporting_job.py index 23d14ea7..0fd821c1 100644 --- a/python/create_reporting_job.py +++ b/python/create_reporting_job.py @@ -1,17 +1,20 @@ #!/usr/bin/python +# Create a reporting job for the authenticated user's channel or +# for a content owner that the user's account is linked to. # Usage example: # python create_reporting_job.py --name='<name>' +# python create_reporting_job.py --content-owner='<CONTENT OWNER ID>' +# python create_reporting_job.py --content-owner='<CONTENT_OWNER_ID>' --report-type='<REPORT_TYPE_ID>' --name='<REPORT_NAME>' -import httplib2 +import argparse import os -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 @@ -25,98 +28,109 @@ # 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 read access to the YouTube Analytics monetary reports for # authenticated user's account. Any request that retrieves earnings or ad performance metrics must # use this scope. -YOUTUBE_ANALYTICS_MONETARY_READ_SCOPE = ( - "https://www.googleapis.com/auth/yt-analytics-monetary.readonly") -YOUTUBE_REPORTING_API_SERVICE_NAME = "youtubereporting" -YOUTUBE_REPORTING_API_VERSION = "v1" - -# 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 APIs Console -https://console.developers.google.com - -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)) +SCOPES = ['https://www.googleapis.com/auth/yt-analytics-monetary.readonly'] +API_SERVICE_NAME = 'youtubereporting' +API_VERSION = 'v1' # Authorize the request and store authorization credentials. -def get_authenticated_service(args): - flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_ANALYTICS_MONETARY_READ_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_REPORTING_API_SERVICE_NAME, YOUTUBE_REPORTING_API_VERSION, - http=credentials.authorize(httplib2.Http())) - +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) + +# Remove keyword arguments that are not set. +def remove_empty_kwargs(**kwargs): + good_kwargs = {} + if kwargs is not None: + for key, value in kwargs.iteritems(): + if value: + good_kwargs[key] = value + return good_kwargs # Call the YouTube Reporting API's reportTypes.list method to retrieve report types. -def list_report_types(youtube_reporting): - results = youtube_reporting.reportTypes().list().execute() - reportTypes = results["reportTypes"] - - if "reportTypes" in results and results["reportTypes"]: - reportTypes = results["reportTypes"] +def list_report_types(youtube_reporting, **kwargs): + # Provide keyword arguments that have values as request parameters. + kwargs = remove_empty_kwargs(**kwargs) + results = youtube_reporting.reportTypes().list(**kwargs).execute() + reportTypes = results['reportTypes'] + + if 'reportTypes' in results and results['reportTypes']: + reportTypes = results['reportTypes'] for reportType in reportTypes: - print "Report type id: %s\n name: %s\n" % (reportType["id"], reportType["name"]) + print 'Report type id: %s\n name: %s\n' % (reportType['id'], reportType['name']) else: - print "No report types found" + print 'No report types found' return False return True # Call the YouTube Reporting API's jobs.create method to create a job. -def create_reporting_job(youtube_reporting, report_type_id, name): +def create_reporting_job(youtube_reporting, report_type_id, **kwargs): + # Provide keyword arguments that have values as request parameters. + kwargs = remove_empty_kwargs(**kwargs) + reporting_job = youtube_reporting.jobs().create( body=dict( - reportTypeId=report_type_id, - name=name - ) + reportTypeId=args.report_type, + name=args.name + ), + **kwargs ).execute() - print ("Reporting job '%s' created for reporting type '%s' at '%s'" - % (reporting_job["name"], reporting_job["reportTypeId"], - reporting_job["createTime"])) + print ('Reporting job "%s" created for reporting type "%s" at "%s"' + % (reporting_job['name'], reporting_job['reportTypeId'], + reporting_job['createTime'])) # Prompt the user to enter a report type id for the job. Then return the id. def get_report_type_id_from_user(): - report_type_id = raw_input("Please enter the reportTypeId for the job: ") - print ("You chose '%s' as the report type Id for the job." % report_type_id) + report_type_id = raw_input('Please enter the reportTypeId for the job: ') + print ('You chose "%s" as the report type Id for the job.' % report_type_id) return report_type_id +# Prompt the user to set a job name +def prompt_user_to_set_job_name(): + job_name = raw_input('Please set a name for the job: ') + print ('Great! "%s" is a memorable name for this job.' % job_name) + return job_name + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + # The 'name' option specifies the name that will be used for the reporting job. + parser.add_argument('--content-owner', default='', + help='ID of content owner for which you are retrieving jobs and reports.') + parser.add_argument('--include-system-managed', default=False, + help='Whether the API response should include system-managed reports') + parser.add_argument('--name', default='', + help='Name for the reporting job. The script prompts you to set a name ' + + 'for the job if you do not provide one using this argument.') + parser.add_argument('--report-type', default=None, + help='The type of report for which you are creating a job.') + args = parser.parse_args() + + youtube_reporting = get_authenticated_service() -if __name__ == "__main__": - # The "name" option specifies the name that will be used for the reporting job. - argparser.add_argument("--name", - help="Required; name for the reporting job.") - args = argparser.parse_args() - - if not args.name: - exit("Please specify name using the --name= parameter.") - - youtube_reporting = get_authenticated_service(args) try: - if list_report_types(youtube_reporting): - create_reporting_job(youtube_reporting, get_report_type_id_from_user(), args.name) + # Prompt user to select report type if they didn't set one on command line. + if not args.report_type: + if list_report_types(youtube_reporting, + onBehalfOfContentOwner=args.content_owner, + includeSystemManaged=args.include_system_managed): + args.report_type = get_report_type_id_from_user() + # Prompt user to set job name if not set on command line. + if not args.name: + args.name = prompt_user_to_set_job_name() + # Create the job. + if args.report_type: + create_reporting_job(youtube_reporting, + args, + onBehalfOfContentOwner=args.content_owner) except HttpError, e: - print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content) - else: - print "Created reporting job." + print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content) From f1b9f38f5a5bdcd0dfe02292fb71f084fe01fdbe Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 17:01:03 -0400 Subject: [PATCH 119/126] Update auth libraries and make script improvements The oauth2client library is deprecated. This update changes the sample to use the google-auth and google-auth-oauthlib libraries instead. In addition, the code now has more flexible support for command-line arguments. For example, it does not set a default language by default ... you need to specify that on the command line. In addition, you can now add a localization without setting a default language or set a default language without adding a localization. (You cannot add localizations if the playlist doesn't have a default language at all, but once it does have a default language, you do not need to set it every subsequent time you run the script.) --- python/playlist_localizations.py | 233 ++++++++++++++++--------------- 1 file changed, 122 insertions(+), 111 deletions(-) diff --git a/python/playlist_localizations.py b/python/playlist_localizations.py index 0152f92f..f34007be 100644 --- a/python/playlist_localizations.py +++ b/python/playlist_localizations.py @@ -1,17 +1,16 @@ #!/usr/bin/python # Usage example: -# python playlist_localizations.py --action='<action>' --playlist_id='<playlist_id>' --defaultlanguage='<default_language>' --language='<language>' --title='<title>' --description='<description>' +# python playlist_localizations.py --action='<action>' --playlist_id='<playlist_id>' --default_language='<default_language>' --language='<language>' --title='<title>' --description='<description>' -import httplib2 +import argparse import os -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 @@ -25,142 +24,154 @@ # 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 APIs Console -https://console.developers.google.com - -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)) +SCOPES = ['https://www.googleapis.com/auth/youtube'] +API_SERVICE_NAME = 'youtube' +API_VERSION = 'v3' -# Authorize the request and store authorization credentials. -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())) +ACTIONS = ('get', 'list', 'set') +# Authorize the request and store authorization credentials. +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) # Call the API's playlists.update method to update an existing playlist's default language, # localized title and description in a specific language. -def set_playlist_localization(youtube, playlist_id, default_language, language, title, description): +def set_playlist_localization(youtube, args): + results = youtube.playlists().list( - part="snippet,localizations", - id=playlist_id + part='snippet,localizations', + id=args.playlist_id ).execute() - playlist = results["items"][0] - # Ensure that a value is set for the resource's snippet.defaultLanguage property. - playlist["snippet"]["defaultLanguage"] = default_language - if "localizations" not in playlist: - playlist["localizations"] = {} - playlist["localizations"][language] = { - "title": title, - "description": description - } - + playlist = results['items'][0] + + # If the language argument is set, set the localized title and description + # for that language. The "title" and "description" arguments have default + # values to make the script simpler to run as a demo. In an actual app, you + # would likely want to set those arguments also. + if args.language and args.language != '': + if 'localizations' not in playlist: + playlist['localizations'] = {} + + playlist['localizations'][args.language] = { + 'title': args.title, + 'description': args.description + } + + # If the default language is set AND there is localized metadata for that + # language, set the video's title and description to match the localized + # title and description for the newly set default language. + if args.default_language: + playlist['snippet']['defaultLanguage'] = args.default_language + if args.default_language in playlist['localizations']: + playlist['snippet']['title'] = ( + playlist['localizations'][args.default_language]['title']) + playlist['snippet']['description'] = ( + playlist['localizations'][args.default_language]['description']) + + print(playlist) + + # Update the playlist resource update_result = youtube.playlists().update( - part="snippet,localizations", + part='snippet,localizations', body=playlist ).execute() - localization = update_result["localizations"][language] - - print ("Updated playlist '%s' default language to '%s', localized title to '%s'" - " and description to '%s' in language '%s'" - % (playlist_id, localization["title"], localization["description"], language)) - + # Print the actions taken by running the script. + if args.language: + for language in update_result['localizations']: + # Languages with locales, like "pt-br" are returned as pt-BR in metadata. + # This ensures that the language specified when running the script can be + # matched to the language returned in the metadata. + if language.lower() == args.language.lower(): + localization = update_result['localizations'][args.language] + print ('Updated playlist \'%s\' localized title to \'%s\'' + ' and description to \'%s\' in language \'%s\'' % + (args.playlist_id, + localization['title'], + localization['description'], + args.language)) + break + + if (args.default_language and + args.default_language == update_result['snippet']['defaultLanguage']): + print 'Updated default language to %s' % args.default_language # Call the API's playlists.list method to retrieve an existing playlist localization. # If the localized text is not available in the requested language, # this method will return text in the default language. -def get_playlist_localization(youtube, playlist_id, language): +def get_playlist_localization(youtube, args): results = youtube.playlists().list( - part="snippet", - id=playlist_id, - hl=language + part='snippet', + id=args.playlist_id, + hl=args.language ).execute() # The localized object contains localized text if the hl parameter specified # a language for which localized text is available. Otherwise, the localized # object will contain metadata in the default language. - localized = results["items"][0]["snippet"]["localized"] + localized = results['items'][0]['snippet']['localized'] - print ("Playlist title is '%s' and description is '%s' in language '%s'" - % (localized["title"], localized["description"], language)) + print ('Playlist title is "%s" and description is "%s" in language "%s"' + % (localized['title'], localized['description'], args.language)) -# Call the API's playlists.list method to list the existing playlist localizations. -def list_playlist_localizations(youtube, playlist_id): +# Call the API's playlists.list method to list existing localizations +# for the playlist. +def list_playlist_localizations(youtube, args): results = youtube.playlists().list( - part="snippet,localizations", - id=playlist_id + part='snippet,localizations', + id=args.playlist_id ).execute() - localizations = results["items"][0]["localizations"] - - for language, localization in localizations.iteritems(): - print ("Playlist title is '%s' and description is '%s' in language '%s'" - % (localization["title"], localization["description"], language)) - - -if __name__ == "__main__": - # The "action" option specifies the action to be processed. - argparser.add_argument("--action", help="Action") - # The "playlist_id" option specifies the ID of the selected YouTube playlist. - argparser.add_argument("--playlist_id", - help="ID for playlist for which the localization will be applied.") - # The "default_language" option specifies the language of the playlist's default metadata. - argparser.add_argument("--default_language", help="Default language of the playlist to update.", - default="en") - # The "language" option specifies the language of the localization that is being processed. - argparser.add_argument("--language", help="Language of the localization.", default="de") - # The "title" option specifies the localized title of the playlist to be set. - argparser.add_argument("--title", help="Localized title of the playlist to be set.", - default="Localized Title") - # The "description" option specifies the localized description of the playlist to be set. - argparser.add_argument("--description", help="Localized description of the playlist to be set.", - default="Localized Description") - - args = argparser.parse_args() - - if not args.playlist_id: - exit("Please specify playlist id using the --playlist_id= parameter.") - - youtube = get_authenticated_service(args) + if 'localizations' in results['items'][0]: + localizations = results['items'][0]['localizations'] + + for language, localization in localizations.iteritems(): + print ('Playlist title is "%s" and description is "%s" in language "%s"' + % (localization['title'], localization['description'], language)) + else: + print 'There aren\'t any localizations for this playlist yet.' + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + # The action to be processed: 'get', 'list', and 'set' are supported. + parser.add_argument('--action', required=True, help='Action', choices=ACTIONS) + # The ID of the selected YouTube olaylist. + parser.add_argument('--playlist_id', + help='The playlist ID for which localizations are being set or retrieved.', + required=True) + # The langauge of the playlist's default metadata. + parser.add_argument('--default_language', + help='Default language to set for the playlist.') + # The language of the localization that is being set or retrieved. + parser.add_argument('--language', help='Language of the localization.') + # The localized title to set in the specified language. + parser.add_argument('--title', + help='Localized title to be set for the playlist.', + default='Localized Title') + # The localized description to set in the specified language. + parser.add_argument('--description', + help='Localized description to be set for the playlist.', + default='Localized Description') + + args = parser.parse_args() + + youtube = get_authenticated_service() + try: if args.action == 'set': - set_playlist_localization(youtube, args.playlist_id, args.default_language, args.language, args.title, args.description) + set_playlist_localization(youtube, args) elif args.action == 'get': - get_playlist_localization(youtube, args.playlist_id, args.language) + get_playlist_localization(youtube, args) elif args.action == 'list': - list_playlist_localizations(youtube, args.playlist_id) - else: - exit("Please specify a valid action using the --action= parameter.") + list_playlist_localizations(youtube, args) except HttpError, e: - print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content) - else: - print "Set and retrieved localized metadata for a playlist." + print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content) From 9e0a102355ea427655a4beafc3b666c7cc5b5b3d Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 17:07:40 -0400 Subject: [PATCH 120/126] For list action, video may not have localizations --- python/video_localizations.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/python/video_localizations.py b/python/video_localizations.py index 3412923a..20778c8e 100644 --- a/python/video_localizations.py +++ b/python/video_localizations.py @@ -129,12 +129,14 @@ def list_video_localizations(youtube, args): id=args.video_id ).execute() - localizations = results['items'][0]['localizations'] - - for language, localization in localizations.iteritems(): - print ('Video title is \'%s\' and description is \'%s\' in language \'%s\'' - % (localization['title'], localization['description'], language)) - + if 'localizations' in results['items'][0]: + localizations = results['items'][0]['localizations'] + + for language, localization in localizations.iteritems(): + print ('Video title is \'%s\' and description is \'%s\' in language \'%s\'' + % (localization['title'], localization['description'], language)) + else: + print 'There aren\'t any localizations for this video yet.' if __name__ == '__main__': parser = argparse.ArgumentParser() From 31bee48eb139164eafc35b35e12d67846672ba83 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 17:09:25 -0400 Subject: [PATCH 121/126] Handle error case For list action, the channel might not have localizations. --- python/channel_localizations.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/python/channel_localizations.py b/python/channel_localizations.py index 88a8fced..a244ca6d 100644 --- a/python/channel_localizations.py +++ b/python/channel_localizations.py @@ -118,11 +118,12 @@ def list_channel_localizations(youtube, channel_id): id=channel_id ).execute() - localizations = results['items'][0]['localizations'] - - for language, localization in localizations.iteritems(): - print 'Channel description is \'%s\' in language \'%s\'' % (localization['description'], language) - + if 'localizations' in results['items'][0]: + localizations = results['items'][0]['localizations'] + for language, localization in localizations.iteritems(): + print 'Channel description is \'%s\' in language \'%s\'' % (localization['description'], language) + else: + print 'There aren\'t any localizations for this channel yet.' if __name__ == '__main__': parser = argparse.ArgumentParser() From 3732e66c11d5f2691bdac629226c501fc73e2277 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Fri, 27 Oct 2017 17:10:37 -0400 Subject: [PATCH 122/126] Handle error case When listing localizations, handle case where the channel section doesn't have any yet. --- python/channel_section_localizations.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/python/channel_section_localizations.py b/python/channel_section_localizations.py index b809d5df..e4c2658f 100644 --- a/python/channel_section_localizations.py +++ b/python/channel_section_localizations.py @@ -124,11 +124,14 @@ def list_channel_section_localizations(youtube, args): id=args.channel_section_id ).execute() - localizations = results['items'][0]['localizations'] - - for language, localization in localizations.iteritems(): - print('The channel section title is \'%s\' in language \'%s\'.' % - (localization['title'], language)) + if 'localizations' in results['items'][0]: + localizations = results['items'][0]['localizations'] + + for language, localization in localizations.iteritems(): + print('The channel section title is \'%s\' in language \'%s\'.' % + (localization['title'], language)) + else: + print 'This channel section does not have localizations yet.' # Call the API's channelSections.list method to list localizations for all # channel sections in the authorizing user\'s channel. This function might From 32f087d172e601cd02ecdcf207b5d076f603f1ac Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Tue, 6 Mar 2018 15:49:28 -0500 Subject: [PATCH 123/126] Update nodejs quickstart example - update code sample to address breaking changes in google-api-nodejs-client - fs asynchronous functions display an error without a callback --- javascript/nodejs-quickstart.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/javascript/nodejs-quickstart.js b/javascript/nodejs-quickstart.js index 4e9f26a4..e75a2f69 100644 --- a/javascript/nodejs-quickstart.js +++ b/javascript/nodejs-quickstart.js @@ -1,7 +1,7 @@ var fs = require('fs'); var readline = require('readline'); -var google = require('googleapis'); -var googleAuth = require('google-auth-library'); +var {google} = require('googleapis'); +var OAuth2 = google.auth.OAuth2; // If modifying these scopes, delete your previously saved credentials // at ~/.credentials/youtube-nodejs-quickstart.json @@ -31,8 +31,7 @@ function authorize(credentials, callback) { var clientSecret = credentials.installed.client_secret; var clientId = credentials.installed.client_id; var redirectUrl = credentials.installed.redirect_uris[0]; - var auth = new googleAuth(); - var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl); + var oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl); // Check if we have previously stored a token. fs.readFile(TOKEN_PATH, function(err, token) { @@ -90,7 +89,10 @@ function storeToken(token) { throw err; } } - fs.writeFile(TOKEN_PATH, JSON.stringify(token)); + fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => { + if (err) throw err; + console.log('Token stored to ' + TOKEN_PATH); + }); console.log('Token stored to ' + TOKEN_PATH); } @@ -110,7 +112,7 @@ function getChannel(auth) { console.log('The API returned an error: ' + err); return; } - var channels = response.items; + var channels = response.data.items; if (channels.length == 0) { console.log('No channel found.'); } else { From 53a12c02961c47a24ca32777e7af8b0e4e07d967 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Tue, 6 Mar 2018 16:16:56 -0500 Subject: [PATCH 124/126] Remove duplicate print statement --- javascript/nodejs-quickstart.js | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/nodejs-quickstart.js b/javascript/nodejs-quickstart.js index e75a2f69..68d0591f 100644 --- a/javascript/nodejs-quickstart.js +++ b/javascript/nodejs-quickstart.js @@ -93,7 +93,6 @@ function storeToken(token) { if (err) throw err; console.log('Token stored to ' + TOKEN_PATH); }); - console.log('Token stored to ' + TOKEN_PATH); } /** From cdf1f87f5ede7dce8a17f14471f986d8821e68de Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Thu, 26 Apr 2018 15:43:49 -0400 Subject: [PATCH 125/126] Add JS sample for calling YT Analytics API (v2) --- javascript/yt_analytics_v2.html | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 javascript/yt_analytics_v2.html 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 @@ +<script src="https://apis.google.com/js/api.js"></script> +<script> + function authenticate() { + return gapi.auth2.getAuthInstance() + .signIn({scope: "https://www.googleapis.com/auth/yt-analytics.readonly"}) + .then(function() { console.log("Sign-in successful"); }, + function(err) { console.error("Error signing in", err); }); + } + function loadClient() { + return gapi.client.load("https://youtubeanalytics.googleapis.com/$discovery/rest?version=v2") + .then(function() { console.log("GAPI client loaded for API"); }, + function(err) { console.error("Error loading GAPI client for API", err); }); + } + // Make sure the client is loaded and sign-in is complete before calling this method. + function execute() { + return gapi.client.youtubeAnalytics.reports.query({ + "ids": "channel==MINE", + "startDate": "2017-01-01", + "endDate": "2017-12-31", + "metrics": "views,estimatedMinutesWatched,averageViewDuration,averageViewPercentage,subscribersGained", + "dimensions": "day", + "sort": "day" + }) + .then(function(response) { + // Handle the results here (response.result has the parsed body). + console.log("Response", response); + }, + function(err) { console.error("Execute error", err); }); + } + gapi.load("client:auth2", function() { + gapi.auth2.init({client_id: 'YOUR_CLIENT_ID'}); + }); +</script> +<button onclick="authenticate().then(loadClient)">authorize and load</button> +<button onclick="execute()">execute</button> From 07263305b59a7c3275bc7e925f9ce6cabf774022 Mon Sep 17 00:00:00 2001 From: Andy Diamondstein <adiamondstein@google.com> Date: Thu, 26 Apr 2018 16:10:32 -0400 Subject: [PATCH 126/126] Add .py sample for calling YT Analytics API (v2) --- python/yt_analytics_v2.py | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 python/yt_analytics_v2.py diff --git a/python/yt_analytics_v2.py b/python/yt_analytics_v2.py new file mode 100644 index 00000000..47aa32e2 --- /dev/null +++ b/python/yt_analytics_v2.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +import os +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 + +SCOPES = ['https://www.googleapis.com/auth/yt-analytics.readonly'] + +API_SERVICE_NAME = 'youtubeAnalytics' +API_VERSION = 'v2' +CLIENT_SECRETS_FILE = 'YOUR_CLIENT_SECRET_FILE.json' +def get_service(): + flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES) + credentials = flow.run_console() + return build(API_SERVICE_NAME, API_VERSION, credentials = credentials) + +def execute_api_request(client_library_function, **kwargs): + response = client_library_function( + **kwargs + ).execute() + + print(response) + +if __name__ == '__main__': + # Disable OAuthlib's HTTPs verification when running locally. + # *DO NOT* leave this option enabled when running in production. + os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' + + youtubeAnalytics = get_service() + execute_api_request( + youtubeAnalytics.reports().query, + ids='channel==MINE', + startDate='2017-01-01', + endDate='2017-12-31', + metrics='estimatedMinutesWatched,views,likes,subscribersGained' + dimensions='day', + sort='day' + )