본문 바로가기
Python

[파이썬] 유투브 API 동영상 업로드하기

by 퍼포먼스마케팅코더 2022. 7. 11.
반응형

 

 

파이썬 OAuth 2.0  최초 유투브 API 인증

1.  새 프로젝트에서 이름을 정하고, 사용자 인증 정보 내 OAuth 2.0 클라이언트 ID 의 새로 키 발급을 진행한다. 

이에 웹 애플케이션으로 유형을 만들고, 승인된 리디렉션 URL은 http://localhost:8080/ 으로 정해둔다.

파이썬 유투브 API 동영상 업로드하기

 

아래와 같이 최종 생성 완료되면, Json 파일로 해당 파일을 다운 받아 일정한 디렉토리에 넣어둔다.

 

2. OAuth 동의 화면 내에 테스트 상태로 해놓고, 이외 범위는 Youtube 와 관련된 모든 사항은 다 허용 범위로 설정해 준다. 그리고 최종 테스트 사용자는 본인 이메일 계정이 들어있는지 확인하고 넘어간다.

 

 

3.  Youtube Data API V3 는 무조건 API 사용 설정되도록 아래와 같은 이미지가 나오도록 허용해준다. 이는 해당 신규 프로젝트 내에  Youtube API로 동영상 업로드를 하는데 반드시 필수적인 일이기에 확인이 필요하다.

 

 

파이썬 OAuth 2.0  최초 유투브 API 인증시 문제 해결

1. 일단 최초 인증 문제시 local host 내에 연결할 수 없다는 문구가 뜬 적이 있다. 이는 anaconda를 재부팅하여 다시 jupyter notebook을 연결하면 해결된다.

 

2. 또한 구글 로그인 인증시 mismatch 라는 문구가 뜰 때가 있다. 이는 localhost 8080으로 설정이 안 돼서 그런 문구가 뜨는 것이다. 리디렉션시 localhost:8080 으로 설정해 둬야 제대로 로그인시 해당 mistmatch 문구가 안 뜨고 넘어갈 수 있다.

 

파이썬 OAuth 2.0  유투브 API 동영상 업로드 

upload video.py 디렉토리 내 작성

아래에서 유일하게 건들것은 CLIENT_SECRETS_FILE 이다. client_secret json 파일을 다운로드 받아 저장했다면 해당 디렉토리를 기록해둬서 아래 CLIENT_SECRETS_FILE 에만 입력하면 된다.  이외 해당 코드를 아나콘다의 폴더 내에 upload_video.py 파일로 저장해 놓으면 된다. 이후 해당 파이썬 파일을 import upload_video 로 불러와서 처리할 것이다. 

#!/usr/bin/env python
# coding: utf-8

# In[5]:


import http.client
import httplib2
import os
import random
import sys
import time

from apiclient.discovery import build
from apiclient.errors import HttpError
from apiclient.http import MediaFileUpload
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import argparser, run_flow


# Explicitly tell the underlying HTTP transport library not to retry, since
# we are handling retry logic ourselves.
httplib2.RETRIES = 1

# Maximum number of times to retry before giving up.
MAX_RETRIES = 10

# Always retry when these exceptions are raised.
RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, http.client.NotConnected,
  http.client.IncompleteRead, http.client.ImproperConnectionState,
  http.client.CannotSendRequest, http.client.CannotSendHeader,
  http.client.ResponseNotReady, http.client.BadStatusLine)

# Always retry when an apiclient.errors.HttpError with one of these status
# codes is raised.
RETRIABLE_STATUS_CODES = [500, 502, 503, 504]

# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
# the OAuth 2.0 information for this application, including its client_id and
# client_secret. You can acquire an OAuth 2.0 client ID and client secret from
# the Google API Console at
# https://console.developers.google.com/.
# Please ensure that you have enabled the YouTube Data API for your project.
# For more information about using OAuth2 to access the YouTube Data API, see:
#   https://developers.google.com/youtube/v3/guides/authentication
# For more information about the client_secrets.json file format, see:
#   https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
CLIENT_SECRETS_FILE = "C:/Users/user/raw/youtube/client_secrets.json"

# This OAuth 2.0 access scope allows an application to upload files to the
# authenticated user's YouTube channel, but doesn't allow other types of access.
YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"

# This variable defines a message to display if the CLIENT_SECRETS_FILE is
# missing.
MISSING_CLIENT_SECRETS_MESSAGE = """
WARNING: Please configure OAuth 2.0

To make this sample run you will need to populate the client_secrets.json file
found at:

   %s

with information from the API Console
https://console.developers.google.com/

For more information about the client_secrets.json file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
""" % os.path.abspath(os.path.join(os.path.dirname(__file__),
                                   CLIENT_SECRETS_FILE))

VALID_PRIVACY_STATUSES = ("public", "private", "unlisted")


def get_authenticated_service(args):
  flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE,
    scope=YOUTUBE_UPLOAD_SCOPE,
    message=MISSING_CLIENT_SECRETS_MESSAGE)

  storage = Storage("%s-oauth2.json" % sys.argv[0])
  credentials = storage.get()

  if credentials is None or credentials.invalid:
    credentials = run_flow(flow, storage, args)

  return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
    http=credentials.authorize(httplib2.Http()))

def initialize_upload(youtube, options):
  tags = None
  if options.keywords:
    tags = options.keywords.split(",")

  body=dict(
    snippet=dict(
      title=options.title,
      description=options.description,
      tags=tags,
      categoryId=options.category
    ),
    status=dict(
      privacyStatus=options.privacyStatus
    )
  )

  # Call the API's videos.insert method to create and upload the video.
  insert_request = youtube.videos().insert(
    part=",".join(list(body.keys())),
    body=body,
    # The chunksize parameter specifies the size of each chunk of data, in
    # bytes, that will be uploaded at a time. Set a higher value for
    # reliable connections as fewer chunks lead to faster uploads. Set a lower
    # value for better recovery on less reliable connections.
    #
    # Setting "chunksize" equal to -1 in the code below means that the entire
    # file will be uploaded in a single HTTP request. (If the upload fails,
    # it will still be retried where it left off.) This is usually a best
    # practice, but if you're using Python older than 2.6 or if you're
    # running on App Engine, you should set the chunksize to something like
    # 1024 * 1024 (1 megabyte).
    media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True)
  )

  resumable_upload(insert_request)

# This method implements an exponential backoff strategy to resume a
# failed upload.
def resumable_upload(insert_request):
  response = None
  error = None
  retry = 0
  while response is None:
    try:
      print("Uploading file...")
      status, response = insert_request.next_chunk()
      if response is not None:
        if 'id' in response:
          print(("Video id '%s' was successfully uploaded." % response['id']))
        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))
      time.sleep(sleep_seconds)

if __name__ == '__main__':
  argparser.add_argument("--file", required=True, help="Video file to upload")
  argparser.add_argument("--title", help="Video title", default="Test Title")
  argparser.add_argument("--description", help="Video description",
    default="Test Description")
  argparser.add_argument("--category", default="22",
    help="Numeric video category. " +
      "See https://developers.google.com/youtube/v3/docs/videoCategories/list")
  argparser.add_argument("--keywords", help="Video keywords, comma separated",
    default="")
  argparser.add_argument("--privacyStatus", choices=VALID_PRIVACY_STATUSES,
    default=VALID_PRIVACY_STATUSES[0], help="Video privacy status.")
  args = argparser.parse_args()

  if not os.path.exists(args.file):
    exit("Please specify a valid file using the --file= parameter.")

  youtube = get_authenticated_service(args)
  try:
    initialize_upload(youtube, args)
  except HttpError as e:
    print(("An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)))


# In[ ]:

 

이후 os.system 명령어를 치면 바로 해결됨. 결과는 0으로 나와야된다.

이외 -- file 은 업로드할 동영상 mp4 디렉토리,   -- title은 제목, description은 제목이다.  -- keywords 는 해시태그나 키워드인것 같고, category ID 번호는 좀 찾아봐야될 것 같다. 이외 privacyStatus 는 public 일시 바로 공개로 영상 업로드이고, private로 설정시 비공개로 처리되어 영상이 업로드 된다.

 

import upload_video
import os

os.system('python C:/Users/user/upload_video.py --file="C:/Users/user/Desktop/videos/20211107_141646.mp4" --title="Summer vacation in California" --description="Had a great time surfing in Santa Cruz"  --keywords="surfing,Santa Cruz" --category="22" --privacyStatus="public"')

 

파이썬 OAuth 2.0  유투브 API 동영상 업로드 최종 확인

최종 채널에 들어가서 해당 영상이 잘 업로드 되었는지를 확인하면 된다. 보아하니 영상 업로드는 잘 된 것으로 보인다. 이외 추가적인 에러 등은 영상 업로드시의 할당량 초과, 이외 테스트 사용자로 인해 API 기간의 제한이 있다. 이럴 시 revoke 관련 오류 등이 있을 시 추가로 인증 문제만 해결해 나가면 된다. 그럼 끝.

반응형

댓글