2023-05-15 10:11:04 +02:00
#!/usr/bin/python
''' Uploads a video to YouTube. '''
from http import client
import httplib2
import os
import random
import time
import json
2023-06-25 16:12:23 +02:00
import asyncio
2023-05-15 10:11:04 +02:00
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
httplib2 . RETRIES = 1
MAX_RETRIES = 10
RETRIABLE_EXCEPTIONS = ( httplib2 . HttpLib2Error , IOError , client . NotConnected ,
client . IncompleteRead , client . ImproperConnectionState ,
client . CannotSendRequest , client . CannotSendHeader ,
client . ResponseNotReady , client . BadStatusLine )
RETRIABLE_STATUS_CODES = [ 500 , 502 , 503 , 504 ]
2023-05-25 21:47:11 +02:00
CLIENT_SECRETS_FILE = ' '
2023-05-15 10:11:04 +02:00
2023-05-15 15:35:08 +02:00
#SCOPES = ['https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/upload/youtube/v3/thumbnails/set', 'https://www.googleapis.com/auth/youtube.force-ssl']
SCOPES = [ ' https://www.googleapis.com/auth/youtube ' ]
2023-05-15 10:11:04 +02:00
API_SERVICE_NAME = ' youtube '
API_VERSION = ' v3 '
VALID_PRIVACY_STATUSES = ( ' public ' , ' private ' , ' unlisted ' )
# Authorize the request and store authorization credentials.
2023-06-25 16:12:23 +02:00
async def get_authenticated_service ( credentialsPath = " " ) :
2023-06-25 17:40:01 +02:00
CLIENT_SECRETS_FILE = " "
try :
CLIENT_SECRETS_FILE = os . path . join ( credentialsPath , " client_secret.json " )
except :
listdir = os . listdir ( credentialsPath )
for file in listdir :
if file . startswith ( " client_secret " ) :
#rename file to client_secret.json
os . rename ( os . path . join ( credentialsPath , file ) , os . path . join ( credentialsPath , " client_secret.json " ) )
CLIENT_SECRETS_FILE = os . path . join ( credentialsPath , " client_secret.json " )
break
if CLIENT_SECRETS_FILE == " " :
raise FileNotFoundError ( " No client_secret.json file found in the specified path ! " )
2023-05-15 15:35:08 +02:00
if os . path . exists ( f ' { credentialsPath } /credentials.json ' ) :
with open ( f ' { credentialsPath } /credentials.json ' ) as json_file :
2023-05-15 10:11:04 +02:00
data = json . load ( json_file )
credentials = google . oauth2 . credentials . Credentials (
token = data [ ' token ' ] ,
refresh_token = data [ ' refresh_token ' ] ,
token_uri = data [ ' token_uri ' ] ,
client_id = data [ ' client_id ' ] ,
client_secret = data [ ' client_secret ' ] ,
scopes = data [ ' scopes ' ]
)
else :
flow = InstalledAppFlow . from_client_secrets_file (
CLIENT_SECRETS_FILE , SCOPES )
2023-05-25 21:47:11 +02:00
credentials = flow . run_local_server ( success_message = " Heyy, yippie, you ' re authenticated ! You can close this window now ! " , authorization_prompt_message = " Please authorize this app to upload videos on your YouTube account ! " )
2023-05-15 15:35:08 +02:00
with open ( f ' { credentialsPath } /credentials.json ' , ' w ' ) as outfile :
2023-05-15 10:11:04 +02:00
outfile . write ( credentials . to_json ( ) )
return build ( API_SERVICE_NAME , API_VERSION , credentials = credentials )
2023-06-25 16:12:23 +02:00
async def initialize_upload ( youtube , options ) :
2023-05-15 10:11:04 +02:00
tags = None
if options [ ' keywords ' ] :
tags = options [ ' keywords ' ] . split ( ' , ' )
body = dict (
snippet = dict (
title = options [ ' title ' ] ,
description = options [ ' description ' ] ,
tags = tags ,
2023-05-15 15:35:08 +02:00
categoryId = options [ ' category ' ] ,
defaultLanguage = ' en '
2023-05-15 10:11:04 +02:00
) ,
status = dict (
2023-05-15 15:35:08 +02:00
privacyStatus = options [ ' privacyStatus ' ] ,
selfDeclaredMadeForKids = False
2023-05-15 10:11:04 +02:00
)
)
# Call the API's videos.insert method to create and upload the video.
insert_request = youtube . videos ( ) . insert (
part = ' , ' . join ( body . keys ( ) ) ,
body = body ,
media_body = MediaFileUpload ( options [ ' file ' ] , chunksize = - 1 , resumable = True )
)
2023-06-25 17:43:54 +02:00
videoid = await resumable_upload ( insert_request )
2023-05-15 15:35:08 +02:00
return videoid
2023-05-15 10:11:04 +02:00
2023-06-25 16:12:23 +02:00
async def resumable_upload ( request ) :
2023-05-15 10:11:04 +02:00
response = None
error = None
retry = 0
while response is None :
try :
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 ' ] )
2023-05-15 15:35:08 +02:00
return response [ ' id ' ]
2023-05-15 10:11:04 +02:00
else :
exit ( ' The upload failed with an unexpected response: %s ' % response )
except HttpError as e :
if e . resp . status in RETRIABLE_STATUS_CODES :
error = ' A retriable HTTP error %d occurred: \n %s ' % ( e . resp . status ,
e . content )
else :
raise
except RETRIABLE_EXCEPTIONS as 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. ' )
max_sleep = 2 * * retry
sleep_seconds = random . random ( ) * max_sleep
print ( ' Sleeping %f seconds and then retrying... ' % sleep_seconds )
2023-06-25 16:12:23 +02:00
await asyncio . sleep ( sleep_seconds )
2023-05-15 10:11:04 +02:00
2023-06-25 16:12:23 +02:00
async def upload_video ( path , title , description , category , keywords , privacyStatus = ' private ' , credentials_path = " " ) :
2023-05-15 15:35:08 +02:00
options = {
' file ' : path + " /montage.mp4 " ,
' title ' : title ,
' description ' : description ,
' category ' : category ,
' keywords ' : keywords ,
' privacyStatus ' : privacyStatus
2023-05-15 10:11:04 +02:00
}
2023-06-25 16:12:23 +02:00
youtube = await get_authenticated_service ( credentials_path )
2023-05-15 10:11:04 +02:00
try :
2023-06-25 16:12:23 +02:00
videoid = await initialize_upload ( youtube , options )
await upload_thumbnail ( videoid , path + " /miniature.png " , credentials_path )
return videoid
2023-05-15 10:11:04 +02:00
except HttpError as e :
2023-05-15 15:35:08 +02:00
print ( ' An HTTP error %d occurred: \n %s ' % ( e . resp . status , e . content ) )
2023-06-25 16:12:23 +02:00
async def upload_thumbnail ( video_id , file , credentials_path = " " ) :
2023-06-25 17:40:01 +02:00
youtube = await get_authenticated_service ( credentials_path )
2023-06-25 16:12:23 +02:00
youtube . thumbnails ( ) . set ( # type: ignore
2023-05-15 15:35:08 +02:00
videoId = video_id ,
media_body = file
) . execute ( )