| 
1 | 1 | #!/usr/bin/python  | 
2 | 2 | 
 
  | 
3 | 3 | # Usage example:  | 
4 |  | -# python playlist_localizations.py --action='<action>' --playlist_id='<playlist_id>' --defaultlanguage='<default_language>' --language='<language>' --title='<title>' --description='<description>'  | 
 | 4 | +# python playlist_localizations.py --action='<action>' --playlist_id='<playlist_id>' --default_language='<default_language>' --language='<language>' --title='<title>' --description='<description>'  | 
5 | 5 | 
 
  | 
6 |  | -import httplib2  | 
 | 6 | +import argparse  | 
7 | 7 | import os  | 
8 |  | -import sys  | 
9 | 8 | 
 
  | 
10 |  | -from apiclient.discovery import build  | 
11 |  | -from apiclient.errors import HttpError  | 
12 |  | -from oauth2client.client import flow_from_clientsecrets  | 
13 |  | -from oauth2client.file import Storage  | 
14 |  | -from oauth2client.tools import argparser, run_flow  | 
 | 9 | +import google.oauth2.credentials  | 
 | 10 | +import google_auth_oauthlib.flow  | 
 | 11 | +from googleapiclient.discovery import build  | 
 | 12 | +from googleapiclient.errors import HttpError  | 
 | 13 | +from google_auth_oauthlib.flow import InstalledAppFlow  | 
15 | 14 | 
 
  | 
16 | 15 | 
 
  | 
17 | 16 | # The CLIENT_SECRETS_FILE variable specifies the name of a file that contains  | 
 | 
25 | 24 | #   https://developers.google.com/youtube/v3/guides/authentication  | 
26 | 25 | # For more information about the client_secrets.json file format, see:  | 
27 | 26 | #   https://developers.google.com/api-client-library/python/guide/aaa_client_secrets  | 
28 |  | -CLIENT_SECRETS_FILE = "client_secrets.json"  | 
 | 27 | +CLIENT_SECRETS_FILE = 'client_secret.json'  | 
29 | 28 | 
 
  | 
30 | 29 | # This OAuth 2.0 access scope allows for full read/write access to the  | 
31 | 30 | # authenticated user's account.  | 
32 |  | -YOUTUBE_READ_WRITE_SCOPE = "https://www.googleapis.com/auth/youtube"  | 
33 |  | -YOUTUBE_API_SERVICE_NAME = "youtube"  | 
34 |  | -YOUTUBE_API_VERSION = "v3"  | 
35 |  | - | 
36 |  | -# This variable defines a message to display if the CLIENT_SECRETS_FILE is  | 
37 |  | -# missing.  | 
38 |  | -MISSING_CLIENT_SECRETS_MESSAGE = """  | 
39 |  | -WARNING: Please configure OAuth 2.0  | 
40 |  | -
  | 
41 |  | -To make this sample run you will need to populate the client_secrets.json file  | 
42 |  | -found at:  | 
43 |  | -   %s  | 
44 |  | -with information from the APIs Console  | 
45 |  | -https://console.developers.google.com  | 
46 |  | -
  | 
47 |  | -For more information about the client_secrets.json file format, please visit:  | 
48 |  | -https://developers.google.com/api-client-library/python/guide/aaa_client_secrets  | 
49 |  | -""" % os.path.abspath(os.path.join(os.path.dirname(__file__),  | 
50 |  | -                                   CLIENT_SECRETS_FILE))  | 
 | 31 | +SCOPES = ['https://www.googleapis.com/auth/youtube']  | 
 | 32 | +API_SERVICE_NAME = 'youtube'  | 
 | 33 | +API_VERSION = 'v3'  | 
51 | 34 | 
 
  | 
52 |  | -# Authorize the request and store authorization credentials.  | 
53 |  | -def get_authenticated_service(args):  | 
54 |  | -  flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_READ_WRITE_SCOPE,  | 
55 |  | -    message=MISSING_CLIENT_SECRETS_MESSAGE)  | 
56 |  | - | 
57 |  | -  storage = Storage("%s-oauth2.json" % sys.argv[0])  | 
58 |  | -  credentials = storage.get()  | 
59 |  | - | 
60 |  | -  if credentials is None or credentials.invalid:  | 
61 |  | -    credentials = run_flow(flow, storage, args)  | 
62 |  | - | 
63 |  | -  return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,  | 
64 |  | -    http=credentials.authorize(httplib2.Http()))  | 
 | 35 | +ACTIONS = ('get', 'list', 'set')  | 
65 | 36 | 
 
  | 
 | 37 | +# Authorize the request and store authorization credentials.  | 
 | 38 | +def get_authenticated_service():  | 
 | 39 | +  flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)  | 
 | 40 | +  credentials = flow.run_console()  | 
 | 41 | +  return build(API_SERVICE_NAME, API_VERSION, credentials = credentials)  | 
66 | 42 | 
 
  | 
67 | 43 | # Call the API's playlists.update method to update an existing playlist's default language,  | 
68 | 44 | # localized title and description in a specific language.  | 
69 |  | -def set_playlist_localization(youtube, playlist_id, default_language, language, title, description):  | 
 | 45 | +def set_playlist_localization(youtube, args):  | 
 | 46 | + | 
70 | 47 |   results = youtube.playlists().list(  | 
71 |  | -    part="snippet,localizations",  | 
72 |  | -    id=playlist_id  | 
 | 48 | +    part='snippet,localizations',  | 
 | 49 | +    id=args.playlist_id  | 
73 | 50 |   ).execute()  | 
74 | 51 | 
 
  | 
75 |  | -  playlist = results["items"][0]  | 
76 |  | -  # Ensure that a value is set for the resource's snippet.defaultLanguage property.  | 
77 |  | -  playlist["snippet"]["defaultLanguage"] = default_language  | 
78 |  | -  if "localizations" not in playlist:  | 
79 |  | -    playlist["localizations"] = {}  | 
80 |  | -  playlist["localizations"][language] = {  | 
81 |  | -    "title": title,  | 
82 |  | -    "description": description  | 
83 |  | -  }  | 
84 |  | - | 
 | 52 | +  playlist = results['items'][0]  | 
 | 53 | + | 
 | 54 | +  # If the language argument is set, set the localized title and description  | 
 | 55 | +  # for that language. The "title" and "description" arguments have default  | 
 | 56 | +  # values to make the script simpler to run as a demo. In an actual app, you  | 
 | 57 | +  # would likely want to set those arguments also.  | 
 | 58 | +  if args.language and args.language != '':  | 
 | 59 | +    if 'localizations' not in playlist:  | 
 | 60 | +      playlist['localizations'] = {}  | 
 | 61 | + | 
 | 62 | +    playlist['localizations'][args.language] = {  | 
 | 63 | +      'title': args.title,  | 
 | 64 | +      'description': args.description  | 
 | 65 | +    }  | 
 | 66 | + | 
 | 67 | +  # If the default language is set AND there is localized metadata for that  | 
 | 68 | +  # language, set the video's title and description to match the localized  | 
 | 69 | +  # title and description for the newly set default language.  | 
 | 70 | +  if args.default_language:  | 
 | 71 | +    playlist['snippet']['defaultLanguage'] = args.default_language  | 
 | 72 | +    if args.default_language in playlist['localizations']:  | 
 | 73 | +      playlist['snippet']['title'] = (  | 
 | 74 | +          playlist['localizations'][args.default_language]['title'])  | 
 | 75 | +      playlist['snippet']['description'] = (  | 
 | 76 | +          playlist['localizations'][args.default_language]['description'])  | 
 | 77 | + | 
 | 78 | +  print(playlist)  | 
 | 79 | + | 
 | 80 | +  # Update the playlist resource  | 
85 | 81 |   update_result = youtube.playlists().update(  | 
86 |  | -    part="snippet,localizations",  | 
 | 82 | +    part='snippet,localizations',  | 
87 | 83 |     body=playlist  | 
88 | 84 |   ).execute()  | 
89 | 85 | 
 
  | 
90 |  | -  localization = update_result["localizations"][language]  | 
91 |  | - | 
92 |  | -  print ("Updated playlist '%s' default language to '%s', localized title to '%s'"  | 
93 |  | -         " and description to '%s' in language '%s'"  | 
94 |  | -         % (playlist_id, localization["title"], localization["description"], language))  | 
95 |  | - | 
 | 86 | +  # Print the actions taken by running the script.  | 
 | 87 | +  if args.language:  | 
 | 88 | +    for language in update_result['localizations']:  | 
 | 89 | +      # Languages with locales, like "pt-br" are returned as pt-BR in metadata.  | 
 | 90 | +      # This ensures that the language specified when running the script can be  | 
 | 91 | +      # matched to the language returned in the metadata.  | 
 | 92 | +      if language.lower() == args.language.lower():  | 
 | 93 | +        localization = update_result['localizations'][args.language]  | 
 | 94 | +        print ('Updated playlist \'%s\' localized title to \'%s\''  | 
 | 95 | +               ' and description to \'%s\' in language \'%s\'' %  | 
 | 96 | +               (args.playlist_id,  | 
 | 97 | +                localization['title'],  | 
 | 98 | +                localization['description'],  | 
 | 99 | +                args.language))  | 
 | 100 | +        break  | 
 | 101 | + | 
 | 102 | +  if (args.default_language and  | 
 | 103 | +      args.default_language == update_result['snippet']['defaultLanguage']):  | 
 | 104 | +    print 'Updated default language to %s' % args.default_language  | 
96 | 105 | 
 
  | 
97 | 106 | # Call the API's playlists.list method to retrieve an existing playlist localization.  | 
98 | 107 | # If the localized text is not available in the requested language,  | 
99 | 108 | # this method will return text in the default language.  | 
100 |  | -def get_playlist_localization(youtube, playlist_id, language):  | 
 | 109 | +def get_playlist_localization(youtube, args):  | 
101 | 110 |   results = youtube.playlists().list(  | 
102 |  | -    part="snippet",  | 
103 |  | -    id=playlist_id,  | 
104 |  | -    hl=language  | 
 | 111 | +    part='snippet',  | 
 | 112 | +    id=args.playlist_id,  | 
 | 113 | +    hl=args.language  | 
105 | 114 |   ).execute()  | 
106 | 115 | 
 
  | 
107 | 116 |   # The localized object contains localized text if the hl parameter specified  | 
108 | 117 |   # a language for which localized text is available. Otherwise, the localized  | 
109 | 118 |   # object will contain metadata in the default language.  | 
110 |  | -  localized = results["items"][0]["snippet"]["localized"]  | 
 | 119 | +  localized = results['items'][0]['snippet']['localized']  | 
111 | 120 | 
 
  | 
112 |  | -  print ("Playlist title is '%s' and description is '%s' in language '%s'"  | 
113 |  | -         % (localized["title"], localized["description"], language))  | 
 | 121 | +  print ('Playlist title is "%s" and description is "%s" in language "%s"'  | 
 | 122 | +         % (localized['title'], localized['description'], args.language))  | 
114 | 123 | 
 
  | 
115 | 124 | 
 
  | 
116 |  | -# Call the API's playlists.list method to list the existing playlist localizations.  | 
117 |  | -def list_playlist_localizations(youtube, playlist_id):  | 
 | 125 | +# Call the API's playlists.list method to list existing localizations  | 
 | 126 | +# for the playlist.  | 
 | 127 | +def list_playlist_localizations(youtube, args):  | 
118 | 128 |   results = youtube.playlists().list(  | 
119 |  | -    part="snippet,localizations",  | 
120 |  | -    id=playlist_id  | 
 | 129 | +    part='snippet,localizations',  | 
 | 130 | +    id=args.playlist_id  | 
121 | 131 |   ).execute()  | 
122 | 132 | 
 
  | 
123 |  | -  localizations = results["items"][0]["localizations"]  | 
124 |  | - | 
125 |  | -  for language, localization in localizations.iteritems():  | 
126 |  | -    print ("Playlist title is '%s' and description is '%s' in language '%s'"  | 
127 |  | -           % (localization["title"], localization["description"], language))  | 
128 |  | - | 
129 |  | - | 
130 |  | -if __name__ == "__main__":  | 
131 |  | -  # The "action" option specifies the action to be processed.  | 
132 |  | -  argparser.add_argument("--action", help="Action")  | 
133 |  | -  # The "playlist_id" option specifies the ID of the selected YouTube playlist.  | 
134 |  | -  argparser.add_argument("--playlist_id",  | 
135 |  | -    help="ID for playlist for which the localization will be applied.")  | 
136 |  | -  # The "default_language" option specifies the language of the playlist's default metadata.  | 
137 |  | -  argparser.add_argument("--default_language", help="Default language of the playlist to update.",  | 
138 |  | -    default="en")  | 
139 |  | -  # The "language" option specifies the language of the localization that is being processed.  | 
140 |  | -  argparser.add_argument("--language", help="Language of the localization.", default="de")  | 
141 |  | -  # The "title" option specifies the localized title of the playlist to be set.  | 
142 |  | -  argparser.add_argument("--title", help="Localized title of the playlist to be set.",  | 
143 |  | -    default="Localized Title")  | 
144 |  | -  # The "description" option specifies the localized description of the playlist to be set.  | 
145 |  | -  argparser.add_argument("--description", help="Localized description of the playlist to be set.",  | 
146 |  | -    default="Localized Description")  | 
147 |  | - | 
148 |  | -  args = argparser.parse_args()  | 
149 |  | - | 
150 |  | -  if not args.playlist_id:  | 
151 |  | -    exit("Please specify playlist id using the --playlist_id= parameter.")  | 
152 |  | - | 
153 |  | -  youtube = get_authenticated_service(args)  | 
 | 133 | +  if 'localizations' in results['items'][0]:  | 
 | 134 | +    localizations = results['items'][0]['localizations']  | 
 | 135 | + | 
 | 136 | +    for language, localization in localizations.iteritems():  | 
 | 137 | +      print ('Playlist title is "%s" and description is "%s" in language "%s"'  | 
 | 138 | +             % (localization['title'], localization['description'], language))  | 
 | 139 | +  else:  | 
 | 140 | +    print 'There aren\'t any localizations for this playlist yet.'  | 
 | 141 | + | 
 | 142 | + | 
 | 143 | +if __name__ == '__main__':  | 
 | 144 | +  parser = argparse.ArgumentParser()  | 
 | 145 | +  # The action to be processed: 'get', 'list', and 'set' are supported.  | 
 | 146 | +  parser.add_argument('--action', required=True, help='Action', choices=ACTIONS)  | 
 | 147 | +  # The ID of the selected YouTube olaylist.  | 
 | 148 | +  parser.add_argument('--playlist_id',  | 
 | 149 | +    help='The playlist ID for which localizations are being set or retrieved.',  | 
 | 150 | +    required=True)  | 
 | 151 | +  # The langauge of the playlist's default metadata.  | 
 | 152 | +  parser.add_argument('--default_language',  | 
 | 153 | +    help='Default language to set for the playlist.')  | 
 | 154 | +  # The language of the localization that is being set or retrieved.  | 
 | 155 | +  parser.add_argument('--language', help='Language of the localization.')  | 
 | 156 | +  # The localized title to set in the specified language.  | 
 | 157 | +  parser.add_argument('--title',  | 
 | 158 | +    help='Localized title to be set for the playlist.',  | 
 | 159 | +    default='Localized Title')  | 
 | 160 | +  # The localized description to set in the specified language.  | 
 | 161 | +  parser.add_argument('--description',  | 
 | 162 | +    help='Localized description to be set for the playlist.',  | 
 | 163 | +    default='Localized Description')  | 
 | 164 | + | 
 | 165 | +  args = parser.parse_args()  | 
 | 166 | + | 
 | 167 | +  youtube = get_authenticated_service()  | 
 | 168 | + | 
154 | 169 |   try:  | 
155 | 170 |     if args.action == 'set':  | 
156 |  | -      set_playlist_localization(youtube, args.playlist_id, args.default_language, args.language, args.title, args.description)  | 
 | 171 | +      set_playlist_localization(youtube, args)  | 
157 | 172 |     elif args.action == 'get':  | 
158 |  | -      get_playlist_localization(youtube, args.playlist_id, args.language)  | 
 | 173 | +      get_playlist_localization(youtube, args)  | 
159 | 174 |     elif args.action == 'list':  | 
160 |  | -      list_playlist_localizations(youtube, args.playlist_id)  | 
161 |  | -    else:  | 
162 |  | -      exit("Please specify a valid action using the --action= parameter.")  | 
 | 175 | +      list_playlist_localizations(youtube, args)  | 
163 | 176 |   except HttpError, e:  | 
164 |  | -    print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)  | 
165 |  | -  else:  | 
166 |  | -    print "Set and retrieved localized metadata for a playlist."  | 
 | 177 | +    print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content)  | 
0 commit comments