Coverage for youtube.py: 100%

53 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-10-01 05:56 +0000

1# This file is part of Vallenato.fr. 

2# 

3# Vallenato.fr is free software: you can redistribute it and/or modify 

4# it under the terms of the GNU Affero General Public License as published by 

5# the Free Software Foundation, either version 3 of the License, or 

6# (at your option) any later version. 

7# 

8# Vallenato.fr is distributed in the hope that it will be useful, 

9# but WITHOUT ANY WARRANTY; without even the implied warranty of 

10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

11# GNU Affero General Public License for more details. 

12# 

13# You should have received a copy of the GNU Affero General Public License 

14# along with Vallenato.fr. If not, see <http://www.gnu.org/licenses/>. 

15 

16# Adapted from: 

17# https://github.com/youtube/api-samples/blob/master/python/my_uploads.py 

18# https://github.com/youtube/api-samples/blob/master/python/upload_video.py 

19 

20import logging 

21import os 

22 

23from googleapiclient.discovery import build 

24from googleapiclient.errors import HttpError 

25from oauth2client.client import flow_from_clientsecrets 

26from oauth2client.file import Storage 

27from oauth2client.tools import run_flow 

28 

29# HttpError is re-exported for website.py/tests - __all__ marks the import as 

30# intentionally used, rather than needing a linter-specific suppression. 

31__all__ = ["HttpError"] 

32 

33logger = logging.getLogger(__name__) 

34 

35# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains 

36# the OAuth 2.0 information for this application, including its client_id and 

37# client_secret. You can acquire an OAuth 2.0 client ID and client secret from 

38# the {{ Google Cloud Console }} at 

39# {{ https://cloud.google.com/console }}. 

40# Please ensure that you have enabled the YouTube Data API for your project. 

41# For more information about using OAuth2 to access the YouTube Data API, see: 

42# https://developers.google.com/youtube/v3/guides/authentication 

43# For more information about the client_secrets.json file format, see: 

44# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets 

45CLIENT_SECRETS_FILE = "client_secret.json" 

46 

47# This OAuth 2.0 access scope allows an application to view videos and playlists 

48SCOPES = ["https://www.googleapis.com/auth/youtube.readonly"] 

49API_SERVICE_NAME = "youtube" 

50API_VERSION = "v3" 

51 

52# This variable defines a message to display if the CLIENT_SECRETS_FILE is 

53# missing. 

54MISSING_CLIENT_SECRETS_MESSAGE = f""" 

55WARNING: Please configure OAuth 2.0 

56 

57To make this sample run you will need to populate the client_secrets.json file 

58found at: 

59 {os.path.abspath(os.path.join(os.path.dirname(__file__), CLIENT_SECRETS_FILE))} 

60with information from the APIs Console 

61https://console.developers.google.com 

62 

63For more information about the client_secrets.json file format, please visit: 

64https://developers.google.com/api-client-library/python/guide/aaa_client_secrets 

65""" 

66 

67 

68# Authorize the request and store authorization credentials. 

69def yt_get_authenticated_service(args): 

70 flow = flow_from_clientsecrets( 

71 CLIENT_SECRETS_FILE, scope=SCOPES, message=MISSING_CLIENT_SECRETS_MESSAGE 

72 ) 

73 storage = Storage("vallenato.fr-oauth2.json") 

74 credentials = storage.get() 

75 if credentials is None or credentials.invalid: 

76 credentials = run_flow(flow, storage, args) 

77 return build( 

78 API_SERVICE_NAME, API_VERSION, credentials=credentials, cache_discovery=False 

79 ) 

80 

81 

82def yt_get_my_uploads_list(youtube): 

83 return "UU_8R235jg1ld6MCMOzz2khQ" 

84 # # Retrieve the contentDetails part of the channel resource for the 

85 # # authenticated user's channel. 

86 # channels_response = youtube.channels().list( 

87 # mine=True, 

88 # part='contentDetails' 

89 # ).execute() 

90 # 

91 # for channel in channels_response['items']: 

92 # # From the API response, extract the playlist ID that identifies the list 

93 # # of videos uploaded to the authenticated user's channel. 

94 # return channel['contentDetails']['relatedPlaylists']['uploads'] 

95 # return None 

96 

97 

98def yt_list_my_uploaded_videos(uploads_playlist_id, youtube): 

99 uploaded_videos = [] 

100 # Retrieve the list of videos uploaded to the authenticated user's channel. 

101 playlistitems_list_request = youtube.playlistItems().list( 

102 playlistId=uploads_playlist_id, part="contentDetails" 

103 ) 

104 

105 logger.debug(f"Videos in list {uploads_playlist_id}") 

106 while playlistitems_list_request: 

107 playlistitems_list_response = playlistitems_list_request.execute() 

108 

109 videoIds = ",".join( 

110 playlist_item["contentDetails"]["videoId"] 

111 for playlist_item in playlistitems_list_response["items"] 

112 ) 

113 

114 # To get the videos' tags, we need to do an extra query 

115 videos_list_request = youtube.videos().list(id=videoIds, part="snippet,status") 

116 

117 while videos_list_request: 

118 videos_list_response = videos_list_request.execute() 

119 

120 for video in videos_list_response["items"]: 

121 # Only keep Public videos 

122 if video["status"]["privacyStatus"] != "public": 

123 continue 

124 # Skip videos tagged as "no-website" or "Tutorial" 

125 if "tags" in video["snippet"] and ( 

126 "no-website" in video["snippet"]["tags"] 

127 or "Tutorial" in video["snippet"]["tags"] 

128 ): 

129 continue 

130 vid = {} 

131 vid["id"] = video["id"] 

132 vid["title"] = video["snippet"]["title"] 

133 vid["description"] = video["snippet"]["description"] 

134 try: 

135 vid["tags"] = video["snippet"]["tags"] 

136 except KeyError: 

137 vid["tags"] = [] 

138 vid["publishedAt"] = video["snippet"]["publishedAt"] 

139 # Sizes: default, medium, high, standard, maxres 

140 vid["thumbnail"] = video["snippet"]["thumbnails"]["medium"] 

141 

142 uploaded_videos.append(vid) 

143 logger.debug(vid) 

144 videos_list_request = youtube.videos().list_next( 

145 videos_list_request, videos_list_response 

146 ) 

147 

148 playlistitems_list_request = youtube.playlistItems().list_next( 

149 playlistitems_list_request, playlistitems_list_response 

150 ) 

151 return uploaded_videos