Skip to content

Commit a0e45b6

Browse files
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.
1 parent d598fb3 commit a0e45b6

File tree

1 file changed

+142
-103
lines changed

1 file changed

+142
-103
lines changed

python/yt_analytics_report.py

Lines changed: 142 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,170 @@
11
#!/usr/bin/python
22

3-
from datetime import datetime, timedelta
4-
import httplib2
3+
###
4+
#
5+
# Retrieves YouTube Analytics report data. The script's default behavior
6+
# is to retrieve data for the authenticated user's channel. However, if you
7+
# set a value for the --content-owner command-line argument, then the script
8+
# retrieves data for that content owner. Note that the user running the script
9+
# must be authorized to retrieve data for that content owner.
10+
#
11+
# Note that when you retrieve Analytics data for a content owner, your API
12+
# request must set a value for the "filters" request parameter as explained
13+
# in the API documentation here:
14+
# https://developers.google.com/youtube/analytics/v1/content_owner_reports#Filters
15+
#
16+
# By default, if you set a value for the --content-owner argument, then the
17+
# "filters" parameter is set to "claimedStatus==claimed". (On the other hand,
18+
# this value is not set if you are retrieving data for your own channel.)
19+
#
20+
# You can use the --filters command-line argument to set the "filters" parameter
21+
# for any request. For example:
22+
# * --filters="channel==CHANNEL_ID"
23+
# * --filters="channel==CHANNEL_ID;country==COUNTRY_CODE"
24+
# * --filters="video==VIDEO_ID"
25+
# " --filters="claimedStatus==claimed;uploaderType==thirdParty"
26+
# and so forth.
27+
#
28+
###
29+
30+
import argparse
531
import os
6-
import sys
732

8-
from apiclient.discovery import build
9-
from apiclient.errors import HttpError
10-
from oauth2client.client import flow_from_clientsecrets
11-
from oauth2client.file import Storage
12-
from oauth2client.tools import argparser, run_flow
33+
import google.oauth2.credentials
34+
import google_auth_oauthlib.flow
35+
from googleapiclient.discovery import build
36+
from googleapiclient.errors import HttpError
37+
from google_auth_oauthlib.flow import InstalledAppFlow
38+
from datetime import datetime, timedelta
1339

1440

1541
# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
1642
# the OAuth 2.0 information for this application, including its client_id and
1743
# client_secret. You can acquire an OAuth 2.0 client ID and client secret from
1844
# the {{ Google Cloud Console }} at
1945
# {{ https://cloud.google.com/console }}.
20-
# Please ensure that you have enabled the YouTube Data and YouTube Analytics
21-
# APIs for your project.
22-
# For more information about using OAuth2 to access the YouTube Data API, see:
23-
# https://developers.google.com/youtube/v3/guides/authentication
24-
# For more information about the client_secrets.json file format, see:
46+
# Please ensure that you have enabled the YouTube Analytics API for your project.
47+
# For more information about using OAuth2 to access the YouTube Analytics API, see:
48+
# https://developers.google.com/youtube/reporting/guides/authorization
49+
# For more information about the client_secret.json file format, see:
2550
# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
26-
CLIENT_SECRETS_FILE = "client_secrets.json"
51+
CLIENT_SECRETS_FILE = 'client_secret.json'
2752

2853
# These OAuth 2.0 access scopes allow for read-only access to the authenticated
2954
# user's account for both YouTube Data API resources and YouTube Analytics Data.
30-
YOUTUBE_SCOPES = ["https://www.googleapis.com/auth/youtube.readonly",
31-
"https://www.googleapis.com/auth/yt-analytics.readonly"]
32-
YOUTUBE_API_SERVICE_NAME = "youtube"
33-
YOUTUBE_API_VERSION = "v3"
34-
YOUTUBE_ANALYTICS_API_SERVICE_NAME = "youtubeAnalytics"
35-
YOUTUBE_ANALYTICS_API_VERSION = "v1"
36-
37-
# This variable defines a message to display if the CLIENT_SECRETS_FILE is
38-
# missing.
39-
MISSING_CLIENT_SECRETS_MESSAGE = """
40-
WARNING: Please configure OAuth 2.0
41-
42-
To make this sample run you will need to populate the client_secrets.json file
43-
found at:
44-
45-
%s
46-
47-
with information from the {{ Cloud Console }}
48-
{{ https://cloud.google.com/console }}
49-
50-
For more information about the client_secrets.json file format, please visit:
51-
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
52-
""" % os.path.abspath(os.path.join(os.path.dirname(__file__),
53-
CLIENT_SECRETS_FILE))
54-
55-
56-
def get_authenticated_services(args):
57-
flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE,
58-
scope=" ".join(YOUTUBE_SCOPES),
59-
message=MISSING_CLIENT_SECRETS_MESSAGE)
60-
61-
storage = Storage("%s-oauth2.json" % sys.argv[0])
62-
credentials = storage.get()
63-
64-
if credentials is None or credentials.invalid:
65-
credentials = run_flow(flow, storage, args)
66-
67-
http = credentials.authorize(httplib2.Http())
68-
69-
youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
70-
http=http)
71-
youtube_analytics = build(YOUTUBE_ANALYTICS_API_SERVICE_NAME,
72-
YOUTUBE_ANALYTICS_API_VERSION, http=http)
73-
74-
return (youtube, youtube_analytics)
75-
76-
def get_channel_id(youtube):
77-
channels_list_response = youtube.channels().list(
78-
mine=True,
79-
part="id"
80-
).execute()
81-
82-
return channels_list_response["items"][0]["id"]
83-
84-
def run_analytics_report(youtube_analytics, channel_id, options):
85-
# Call the Analytics API to retrieve a report. For a list of available
86-
# reports, see:
55+
SCOPES = ['https://www.googleapis.com/auth/yt-analytics.readonly']
56+
API_SERVICE_NAME = 'youtubeAnalytics'
57+
API_VERSION = 'v1'
58+
59+
# Authorize the request and store authorization credentials.
60+
def get_authenticated_service():
61+
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
62+
credentials = flow.run_console()
63+
64+
api_service = build(API_SERVICE_NAME, API_VERSION, credentials=credentials)
65+
return api_service
66+
67+
# Remove keyword arguments that are not set.
68+
def remove_empty_args(args):
69+
original_args = vars(args)
70+
good_args = {}
71+
if original_args is not None:
72+
for key, value in original_args.iteritems():
73+
# The channel_id and content_owner arguments are provided as a means
74+
# of properly setting the "ids" parameter value. However, they should
75+
# not be included in the API request (since they're not parameters
76+
# supported by this method).
77+
if value and key != 'channel_id' and key != 'content_owner':
78+
good_args[key] = value
79+
return good_args
80+
81+
# Set the "ids" request parameter for the YouTube Analytics API request.
82+
def set_ids_parameter(args):
83+
if args.content_owner:
84+
args.ids = 'contentOwner==' + args.content_owner
85+
if args.filters == '':
86+
args.filters = 'claimedStatus==claimed'
87+
elif args.channel_id:
88+
args.ids = 'channel==' + args.channel_id
89+
else:
90+
args.ids = 'channel==MINE'
91+
args = remove_empty_args(args)
92+
print args
93+
return args
94+
95+
def run_analytics_report(youtube_analytics, args):
96+
# Call the Analytics API to retrieve a report. Pass args in as keyword
97+
# arguments to set values for the following parameters:
98+
#
99+
# * ids
100+
# * metrics
101+
# * dimensions
102+
# * filters
103+
# * start_date
104+
# * end_date
105+
# * sort
106+
# * max_results
107+
#
108+
# For a list of available reports, see:
87109
# https://developers.google.com/youtube/analytics/v1/channel_reports
110+
# https://developers.google.com/youtube/analytics/v1/content_owner_reports
88111
analytics_query_response = youtube_analytics.reports().query(
89-
ids="channel==%s" % channel_id,
90-
metrics=options.metrics,
91-
dimensions=options.dimensions,
92-
start_date=options.start_date,
93-
end_date=options.end_date,
94-
max_results=options.max_results,
95-
sort=options.sort
112+
**args
96113
).execute()
97114

98-
print "Analytics Data for Channel %s" % channel_id
115+
#print 'Analytics Data for Channel %s' % channel_id
99116

100-
for column_header in analytics_query_response.get("columnHeaders", []):
101-
print "%-20s" % column_header["name"],
117+
for column_header in analytics_query_response.get('columnHeaders', []):
118+
print '%-20s' % column_header['name'],
102119
print
103120

104-
for row in analytics_query_response.get("rows", []):
121+
for row in analytics_query_response.get('rows', []):
105122
for value in row:
106-
print "%-20s" % value,
123+
print '%-20s' % value,
107124
print
108125

109-
if __name__ == "__main__":
126+
if __name__ == '__main__':
110127
now = datetime.now()
111-
one_day_ago = (now - timedelta(days=1)).strftime("%Y-%m-%d")
112-
one_week_ago = (now - timedelta(days=7)).strftime("%Y-%m-%d")
113-
114-
argparser.add_argument("--metrics", help="Report metrics",
115-
default="views,comments,favoritesAdded,favoritesRemoved,likes,dislikes,shares")
116-
argparser.add_argument("--dimensions", help="Report dimensions",
117-
default="video")
118-
argparser.add_argument("--start-date", default=one_week_ago,
119-
help="Start date, in YYYY-MM-DD format")
120-
argparser.add_argument("--end-date", default=one_day_ago,
121-
help="End date, in YYYY-MM-DD format")
122-
argparser.add_argument("--max-results", help="Max results", default=10)
123-
argparser.add_argument("--sort", help="Sort order", default="-views")
124-
args = argparser.parse_args()
125-
126-
(youtube, youtube_analytics) = get_authenticated_services(args)
128+
one_day_ago = (now - timedelta(days=1)).strftime('%Y-%m-%d')
129+
one_week_ago = (now - timedelta(days=7)).strftime('%Y-%m-%d')
130+
131+
parser = argparse.ArgumentParser()
132+
133+
# Set channel ID or content owner. Default is authenticated user's channel.
134+
parser.add_argument('--channel-id', default='',
135+
help='YouTube channel ID for which data should be retrieved. ' +
136+
'Note that the default behavior is to retrieve data for ' +
137+
'the authenticated user\'s channel.')
138+
parser.add_argument('--content-owner', default='',
139+
help='The name of the content owner for which data should be ' +
140+
'retrieved. If you retrieve data for a content owner, then ' +
141+
'your API request must also set a value for the "filters" ' +
142+
'parameter. See the help for that parameter for more details.')
143+
144+
# Metrics, dimensions, filters
145+
parser.add_argument('--metrics', help='Report metrics',
146+
default='views,estimatedMinutesWatched,averageViewDuration')
147+
parser.add_argument('--dimensions', help='Report dimensions', default='')
148+
parser.add_argument('--filters', default='',
149+
help='Filters for the report. Note that the filters request parameter ' +
150+
'must be set in YouTube Analytics API requests for content owner ' +
151+
'reports. The script sets "filters=claimedStatus==claimed" if a ' +
152+
'content owner is specified and filters are not specified.')
153+
154+
# Report dates. Defaults to start 7 days ago, end yesterday.
155+
parser.add_argument('--start-date', default=one_week_ago,
156+
help='Start date, in YYYY-MM-DD format')
157+
parser.add_argument('--end-date', default=one_day_ago,
158+
help='End date, in YYYY-MM-DD format')
159+
160+
parser.add_argument('--max-results', help='Max results')
161+
parser.add_argument('--sort', help='Sort order', default='')
162+
163+
args = parser.parse_args()
164+
args = set_ids_parameter(args)
165+
166+
youtube_analytics = get_authenticated_service()
127167
try:
128-
channel_id = get_channel_id(youtube)
129-
run_analytics_report(youtube_analytics, channel_id, args)
168+
run_analytics_report(youtube_analytics, args)
130169
except HttpError, e:
131-
print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
170+
print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content)

0 commit comments

Comments
 (0)