[PYTHON] Upload videos using YouTube API

Overview

This article uploads videos using the youtube API. The language is Python3. You can proceed according to the official document below, but I have added some points that I was addicted to.

YouTube API-Upload Video

environment

As a premise, it is assumed that the project has been created with GCP.

Advance preparation

Install google-api-python-client

Install the library to use google API.

python


$ pip install google-api-python-client

Application registration on GCP

1. Creation of approval information

Open the link below and create your credentials from the GCP console. This time we will use OAuth 2.0. GCP Console-Credentials (https://console.developers.google.com/apis/credentials?hl=ja)

(1) Go to Create Credentials> OAuth Client ID (select the project in the upper left) スクリーンショット 2020-01-21 23.30.36.png

(2) Select "Other". Name is created by entering any value スクリーンショット 2020-01-21 23.31.32.png

(3) Client ID and client secret can be obtained スクリーンショット 2020-01-21 23.32.38.png

Also, if the OAuth consent screen has not been created, create it. スクリーンショット 2020-01-22 0.13.48.png

Fill in the application name and support email fields and press the create button at the bottom of the screen. スクリーンショット 2020-01-22 0.14.13.png

2. Enable YouTube API

Open the link below and search for the YouTube Data API from the GCP console. As of 2020.1, it is "YouTube Data API v3". When you open it, there is an enable button, so enable it. GCP Console-API Library

スクリーンショット 2020-01-21 23.43.01.png

Creating source for upload

Folder structure

Working folder


$ tree
.
├── movies
│   └── sample001.MP4  #Video to be uploaded
├── client_secrets.json
└── upload_video.py

Source

There are two sources, JSON and Python for authentication information.

Authentication information

Create client_secrets.json. For client_id and client_secret, set the values of the client ID and client secret created in "1. Creating authorization information".

client_secrets.json


{
  "web": {
    "client_id": "[[INSERT CLIENT ID HERE]]",
    "client_secret": "[[INSERT CLIENT SECRET HERE]]",
    "redirect_uris": [],
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://accounts.google.com/o/oauth2/token"
  }
}

Python

Basically, you can use the source of Official, but if it is written in Python2 system and it is Python3 as it is It doesn't work. So, I'll rewrite it a little so that it works with Python3. There are two rewrite points as follows. ・ Migrate from httplib to http.client -Rewriting the print statement (As an aside, change the indent to 4 bytes)

upload_video.py(Official comments have been deleted due to space limitations)


import http.client  #httplib is Python3 is http.Migrate to 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


httplib2.RETRIES = 1
MAX_RETRIES = 10
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)
RETRIABLE_STATUS_CODES = [500, 502, 503, 504]
CLIENT_SECRETS_FILE = "client_secrets.json"
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))

YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"


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
        )
    )

    insert_request = youtube.videos().insert(
        part=",".join(body.keys()),
        body=body,
        media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True)
    )

    resumable_upload(insert_request)


def resumable_upload(insert_request):
    response = None
    error = None
    retry = 0
    while response is None:
        try:
            print("Uploading file...")  #print statement
            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))

A little source commentary

--The YouTube Data API passes the contents set in snippet to the API. ʻThe body in initialize_upload makes a dict of the value to be passed as a snippet. --The value passed to snippet is obtained from the argument as ʻargs. --In get_authenticated_service, the object (?) That uses the API is built and returned from the resource name and operation name (insert etc.) of the YouTube Data API. In this case, pass the built object to ʻinitialize_upload and execute upload with youtube.videos (). Insert`.

Perform upload

From the command line, execute as follows. Since there are many arguments, it may be easier to use a shell script if you want to execute it several times.

Perform video upload


$ python upload_video.py --file="./movies/sample001.MP4" \
                       --title="Sample Movie" \
                       --description="This is a sample movie." \
                       --category="22" \
                       --privacyStatus="private"

The meanings of the arguments are as follows.

--file: Path of the video to upload --title: Video title after upload --description: Video description --category: Category. The default is 22 --privacyStatus: Video publishing settings. Post privately if private

The items and meanings that can be specified as snippet are described below.

YouTube Data API Videos [YouTube Data API Videos: insert] (https://developers.google.com/youtube/v3/docs/videos/insert?hl=ja)

When you execute it for the first time, the screen will change to the browser and ask for Google account selection and YouTube management permission, so please allow it according to the screen. スクリーンショット 2020-01-22 1.06.45.png

If you see a screen like the one below in Chrome, show the details and go to the unsafe page at the bottom left

スクリーンショット 2020-01-22 1.07.11.png

Allow video management. (Although it may be displayed on another screen, continue to allow it.) スクリーンショット 2020-01-22 1.07.22.png

Depending on the size of the video, the upload will be completed as follows after a while.

Execution result


Uploading file...
Video id '[video id]' was successfully uploaded.

You can also confirm that the video has been posted from the YouTube screen.

What I was addicted to: API usage restrictions

Originally, I wanted to use the API to upload a large number of videos in a batch, but when I wrote and executed a program that repeatedly executes the API, the following error occurred.

Uploading file...
An HTTP error 403 occurred:
b'{\n "error": {\n  "errors": [\n   {\n    "domain": "youtube.quota",\n    "reason": "quotaExceeded",\n    "message": "The request cannot be completed because you have exceeded your \\u003ca href=\\"/youtube/v3/getting-started#quota\\"\\u003equota\\u003c/a\\u003e."\n   }\n  ],\n  "code": 403,\n  "message": "The request cannot be completed because you have exceeded your \\u003ca href=\\"/youtube/v3/getting-started#quota\\"\\u003equota\\u003c/a\\u003e."\n }\n}\n'

When I investigated, the API is limited to 10,000 per day, and it is said that about 1,600 units will be used for uploading videos. So, it seems that you can upload videos to YouTube via API about 6 videos / day ...

YouTube Data API-Errors YouTube Data API Overview-Quota Usage

An application is required to raise this, but I gave it up because it was just for personal use. At least I could have done what I wanted to do if it was 30 pieces / day, but if it was 6 pieces, manual work might be faster ...

It may be useful if you want to upload videos in your application.

reference

(Official) YouTube Data API

Recommended Posts

Upload videos using YouTube API
I tried to search videos using Youtube Data API (beginner)
I tried using YOUTUBE Data API V3
Get Youtube data in Python using Youtube Data API
How to download youtube videos using pytube3
Try to download Youtube videos using Pytube
[Python] Get all comments using Youtube Data API
Transcription of YouTube videos using GCP's Cloud Speech-to-Text
Anonymous upload of images using Imgur API (using Python)
Upload JPG file using Google Drive API in Python
Test CloudStack API Using Simulator
Age recognition using Pepper's API
Try using the Twitter API
Try using the Twitter API
Try using the PeeringDB 2.0 API
Use configparser when using API
Play with YouTube Data API v3 using Google API Python Client
Regularly upload files to Google Drive using the Google Drive API in Python
[Python] I tried to get various information using YouTube Data API!
Try using Janus gateway's Admin API
Get Salesforce data using REST API
Proxy measures when using WEB API
Data acquisition using python googlemap api
Logo detection using TensorFlow Object Detection API
[Python3] Google translate google translate without using api
Try using Pleasant's API (python / FastAPI)
Upload packages to PyPI using tokens
Get Amazon data using Keep API # 1 Get data
Data acquisition memo using Backlog API
Edit videos in Python using MoviePy
Try using Python argparse's action API
Create API using hug with mod_wsgi
Facial expression recognition using Pepper's API
Create a CRUD API using FastAPI
Run Ansible from Python using API
I tried using the checkio API
Identify the YouTube channel of Hikakin videos from thumbnail images using CNN