Browse Source

Add playlist feature to Youtube

develop
LecygneNoir 5 years ago
parent
commit
070408bb67
2 changed files with 103 additions and 3 deletions
  1. +1
    -1
      README.md
  2. +102
    -2
      lib/yt_upload.py

+ 1
- 1
README.md View File

@ -152,7 +152,7 @@ Languages:
- [x] thumbnail/preview
- [x] multiple lines description (see [issue 4](https://git.lecygnenoir.info/LecygneNoir/prismedia/issues/4))
- [x] add videos to playlist for Peertube
- [ ] add videos to playlist for Youtube
- [x] add videos to playlist for Youtube
- [x] Use a config file (NFO) file to retrieve videos arguments
- [x] Allow to choose peertube or youtube upload (to resume failed upload for example)
- [x] Add publishAt option to plan your videos

+ 102
- 2
lib/yt_upload.py View File

@ -51,13 +51,14 @@ RETRIABLE_STATUS_CODES = [500, 502, 503, 504]
CLIENT_SECRETS_FILE = 'youtube_secret.json'
CREDENTIALS_PATH = ".youtube_credentials.json"
SCOPES = ['https://www.googleapis.com/auth/youtube.upload']
SCOPES = ['https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/auth/youtube.force-ssl']
API_SERVICE_NAME = 'youtube'
API_VERSION = 'v3'
# Authorize the request and store authorization credentials.
def get_authenticated_service():
check_authenticated_scopes()
flow = InstalledAppFlow.from_client_secrets_file(
CLIENT_SECRETS_FILE, SCOPES)
if exists(CREDENTIALS_PATH):
@ -121,6 +122,17 @@ def initialize_upload(youtube, options):
publishAt = tz.localize(publishAt).isoformat()
body['status']['publishAt'] = str(publishAt)
if options.get('--playlist'):
playlist_id = get_playlist_by_name(youtube, options.get('--playlist'))
if not playlist_id and options.get('--playlistCreate'):
playlist_id = create_playlist(youtube, options.get('--playlist'))
elif not playlist_id:
logging.warning("Youtube: Playlist `" + options.get('--playlist') + "` is unknown.")
logging.warning("If you want to create it, set the --playlistCreate option.")
playlist_id = ""
else:
playlist_id = ""
# Call the API's videos.insert method to create and upload the video.
insert_request = youtube.videos().insert(
part=','.join(body.keys()),
@ -133,9 +145,77 @@ def initialize_upload(youtube, options):
if video_id and options.get('--thumbnail'):
set_thumbnail(youtube, options.get('--thumbnail'), videoId=video_id)
# If we get a video_id, upload is successful and we are able to set playlist
if video_id and options.get('--playlist'):
set_playlist(youtube, playlist_id, video_id)
def get_playlist_by_name(youtube, playlist_name):
response = youtube.playlists().list(
part='snippet,id',
mine=True,
maxResults=50
).execute()
for playlist in response["items"]:
if playlist["snippet"]['title'] == playlist_name:
return playlist['id']
def create_playlist(youtube, playlist_name):
template = ('Youtube: Playlist %s does not exist, creating it.')
logging.info(template % (str(playlist_name)))
resources = build_resource({'snippet.title': playlist_name,
'snippet.description': '',
'status.privacyStatus': 'public'})
response = youtube.playlists().insert(
body=resources,
part='status,snippet,id'
).execute()
return response["id"]
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
def set_thumbnail(youtube, media_file, **kwargs):
kwargs = utils.remove_empty_kwargs(**kwargs) # See full sample for function
kwargs = utils.remove_empty_kwargs(**kwargs)
request = youtube.thumbnails().set(
media_body=MediaFileUpload(media_file, chunksize=-1,
resumable=True),
@ -146,6 +226,26 @@ def set_thumbnail(youtube, media_file, **kwargs):
return resumable_upload(request, 'thumbnail', 'set')
def set_playlist(youtube, playlist_id, video_id):
logging.info('Youtube: Configuring playlist...')
resource = build_resource({'snippet.playlistId': playlist_id,
'snippet.resourceId.kind': 'youtube#video',
'snippet.resourceId.videoId': video_id,
'snippet.position': ''}
)
try:
youtube.playlistItems().insert(
body=resource,
part='snippet'
).execute()
except Exception as e:
if hasattr(e, 'message'):
logging.error("Youtube: Error: " + str(e.message))
else:
logging.error("Youtube: Error: " + str(e))
logging.info('Youtube: Video is correclty added to the playlist.')
# This method implements an exponential backoff strategy to resume a
# failed upload.
def resumable_upload(request, resource, method):

Loading…
Cancel
Save