YouTube API 통합: Django로 동영상 업로드
게시 됨: 2022-03-11얼마 전 저는 고객 웹사이트에 비디오 리뷰를 통합하는 일을 하고 있었습니다. 새로운 문제를 해결하는 의욕적인 개발자와 마찬가지로 내가 가장 먼저 한 일은 구글링이었고 완전히 다르거나 오래되고 유지 관리되지 않은 Python 패키지를 달성하는 방법에 대한 도움이 되지 않거나 잘못된 답변을 많이 찾았습니다. 결국 저는 총알과 팀을 깨고 처음부터 모든 것을 구축했습니다. 뷰를 만들고, Google API에 대해 배우고, API 클라이언트를 만들고, 결국 Django에서 프로그래밍 방식으로 비디오를 업로드하는 데 성공했습니다.
이 게시물에서는 Django 앱에서 YouTube 동영상을 게시하는 방법을 단계별로 안내해 드리겠습니다. 이를 위해서는 먼저 웹 인터페이스를 사용하고 그 다음에는 코드를 사용하여 Google API 자격 증명을 사용하는 데 약간의 시간이 필요합니다. YouTube 부분 자체는 매우 간단합니다. 때로는 까다롭고 정보가 여러 곳에 퍼져 있기 때문에 Google 항목이 작동하는 방식을 이해해야 합니다.
전제 조건
작업을 시작하기 전에 다음 사항을 숙지하는 것이 좋습니다.
- YouTube 데이터 API: Python 빠른 시작
- YouTube 데이터 API: API 참조
- YouTube 데이터 API: 코드 샘플
- Google Python API 클라이언트 라이브러리
- Google Python API 클라이언트 라이브러리: 참조 문서
- Google Python API 클라이언트 라이브러리: 코드 샘플
- YouTube API: Python 코드 샘플
주목할 만한 흥미로운 코드는 Google YouTube API 문서의 다음 Python 스니펫입니다.
# Sample python code for videos.insert def videos_insert(client, properties, media_file, **kwargs): resource = build_resource(properties) # See full sample for function kwargs = remove_empty_kwargs(**kwargs) # See full sample for function request = client.videos().insert( body=resource, media_body=MediaFileUpload(media_file, chunksize=-1, resumable=True), **kwargs ) # See full sample for function return resumable_upload(request, 'video', 'insert') media_file = 'sample_video.flv' if not os.path.exists(media_file): exit('Please specify a valid file location.') videos_insert(client, {'snippet.categoryId': '22', 'snippet.defaultLanguage': '', 'snippet.description': 'Description of uploaded video.', 'snippet.tags[]': '', 'snippet.title': 'Test video upload', 'status.embeddable': '', 'status.license': '', 'status.privacyStatus': 'private', 'status.publicStatsViewable': ''}, media_file, part='snippet,status')
시작하기
전제 조건을 읽었으면 시작할 때입니다. 무엇이 필요한지 봅시다.
공구 벨트
기본적으로 가상 환경을 만들어 봅시다. 나는 개인적으로 pyenv를 선호합니다. 둘 다 설정하는 것은 이 게시물의 범위를 벗어나므로 아래에 몇 가지 pyenv 명령을 게시할 예정이며 기본 설정이 virtualenv
인 경우 그에 따라 명령을 자유롭게 교체하십시오.
이 포스트에서는 Python 3.7과 Django 2.1을 사용할 것입니다.
➜ ~/projects $ mkdir django-youtube ➜ ~/projects $ cd django-youtube ➜ ~/projects/django-youtube $ pyenv virtualenv 3.7.0 djangoyt ➜ ~/projects/django-youtube $ vim .python-version
이것을 내용에 넣자(pyenv를 사용하는 경우에만 폴더에 들어갈 때 자동으로 활성화됩니다):
djangoyt
종속성 설치:
➜ ~/projects/django-youtube $ pip install google-api-python-client google-auth\ google-auth-oauthlib google-auth-httplib2 oauth2client Django unipath jsonpickle
이제 django 프로젝트를 시작할 시간입니다.
➜ ~/projects/django-youtube $ django-admin startproject django_youtube .
일부 Google Config 일시중지
이제 Google API를 사용할 수 있도록 프로젝트 자격 증명을 구성하겠습니다.
1단계. 다음 URL로 이동합니다.
https://console.developers.google.com/apis/library/youtube.googleapis.com
2단계. 새 프로젝트를 만듭니다.
3단계. "API 및 서비스 활성화"를 클릭합니다.
4단계. YouTube Data API v3를 찾아 "사용"을 클릭합니다.
5단계. 자격 증명에 대한 메시지를 받아야 합니다.
6단계. 오른쪽에 있는 "자격 증명 만들기" 파란색 버튼을 클릭하면 다음 화면이 표시됩니다.
7단계. 웹 서버, 사용자 데이터 선택:
8단계. 승인된 JS 원본을 추가하고 URI를 리디렉션합니다. 끝까지 계속:
자, 자격 증명 설정이 완료되었습니다. 자격 증명을 JSON 형식으로 다운로드하거나 클라이언트 ID 및 클라이언트 암호 를 복사할 수 있습니다.
장고로 돌아가기
첫 번째 Django 앱을 시작하겠습니다. 나는 보통 그것을 "핵심"이라고 부른다:
(djangoyt) ➜ ~/projects/django-youtube $ python manage.py startapp core
이제 루트 urls.py 파일에 다음을 추가하여 홈페이지 요청을 핵심 앱으로 라우팅하겠습니다.
# <root>/urls.py from django.urls import path, include path('', include(('core.urls', 'core'), namespace='core')),
핵심 앱에서 일부 구성과 함께 다른 urls.py 파일이 있습니다.
# core/urls.py from django.conf import settings from django.conf.urls.static import static from django.urls import path from .views import HomePageView urlpatterns = [ path('', HomePageView.as_view(), name='home') ] if settings.DEBUG: urlpatterns += static( settings.STATIC_URL, document_root=settings.STATIC_ROOT) urlpatterns += static( settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
HomePageView
를 가리키는 빈 경로가 있는지 확인하십시오. 코드를 추가할 시간입니다.
이제 실행 중인 간단한 TemplateView
를 실행해 보겠습니다.
# core/views.py from django.shortcuts import render from django.views.generic import TemplateView class HomePageView(TemplateView): template_name = 'core/home.html'
물론 기본 템플릿이 필요합니다.
# core/templates/core/home.html <!DOCTYPE html> <html> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> </body> </html>
몇 가지 설정 조정을 수행해야 합니다.
# settings.py from unipath import Path # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = Path(__file__).parent INSTALLED_APPS 'core', STATIC_ROOT = BASE_DIR.parent.child('staticfiles') STATIC_URL = '/static/' MEDIA_ROOT = BASE_DIR.parent.child('uploads') MEDIA_URL = '/media/'
이제 YoutubeForm
을 만들고 보기에 form_class
로 추가해 보겠습니다.
# core/views.py from django import forms from django.views.generic.edit import FormView class YouTubeForm(forms.Form): pass class HomePageView(FormView): template_name = 'core/home.html' form_class = YouTubeForm
지금 애플리케이션을 실행하면 페이지가 다음과 같이 표시됩니다.
승인을 위해 일시 중지
먼저 자격 증명을 저장할 모델을 만들어야 합니다. 파일, 캐시 시스템 또는 기타 스토리지 솔루션을 통해 할 수 있지만 데이터베이스는 합리적이고 확장 가능한 것처럼 보이며 원하는 경우 사용자별로 자격 증명을 저장할 수도 있습니다.
계속하기 전에 조정이 필요합니다. 우리가 사용해야 하는 Django 2.1을 지원하는 oauth2client 포크가 있습니다. 곧 공식 지원을 받게 되지만 그 동안 포크 변경 사항을 확인할 수 있습니다. 그들은 매우 간단합니다.
pip install -e git://github.com/Schweigi/[email protected]#egg=oauth2client Because of compatibility with Django 2.1
settings.py
로 이동하여 이전 단계에서 Google에서 얻은 클라이언트 ID 와 클라이언트 암호 를 입력합니다.
# settings.py GOOGLE_OAUTH2_CLIENT_ GOOGLE_OAUTH2_CLIENT_SECRET = '<your client secret>'
주의: 코드에 비밀을 저장하는 것은 권장 되지 않습니다. 저는 이것을 단순히 시연으로 하고 있습니다. 프로덕션 앱에서 환경 변수를 사용하고 애플리케이션 파일에 비밀을 하드코딩하지 않는 것이 좋습니다. 또는 Google에서 JSON을 다운로드한 경우 위의 설정 대신 경로를 지정할 수도 있습니다.
GOOGLE_OAUTH2_CLIENT_SECRETS_JSON = '/path/to/client_id.json'
oauth2client 패키지는 이미 우리가 사용할 수 있는 CredentialsField
가 완료되어 많은 기능을 제공합니다. 외래 키 및 생성/수정 날짜와 같은 더 많은 필드를 추가할 수 있으므로 더 강력해 지지만 단순하게 유지하겠습니다.
자격 증명을 저장하는 간단한 모델:
# core/models.py from django.db import models from oauth2client.contrib.django_util.models import CredentialsField class CredentialsModel(models.Model): credential = CredentialsField()
마이그레이션 생성 및 마이그레이션 시간:
(djangoyt) ➜ ~/projects/django-youtube $ ./manage.py makemigrations core (djangoyt) ➜ ~/projects/django-youtube $ ./manage.py migrate
이제 애플리케이션을 인증할 수 있도록 API 보기를 변경해 보겠습니다.

core/urls.py
파일에서 첫 번째 인증 보기에 대한 다른 항목을 추가해 보겠습니다.
# core/urls.py from .views import AuthorizeView, HomePageView urlpatterns = [ # [...] path('authorize/', AuthorizeView.as_view(), name='authorize'), ]
따라서 AuthorizeView의 첫 번째 부분은 다음과 같습니다.
# core/views.py from django.conf import settings from django.shortcuts import render, redirect from django.views.generic.base import View from oauth2client.client import flow_from_clientsecrets, OAuth2WebServerFlow from oauth2client.contrib import xsrfutil from oauth2client.contrib.django_util.storage import DjangoORMStorage from .models import CredentialsModel # [...] class AuthorizeView(View): def get(self, request, *args, **kwargs): storage = DjangoORMStorage( CredentialsModel, 'id', request.user.id, 'credential') credential = storage.get() flow = OAuth2WebServerFlow( client_id=settings.GOOGLE_OAUTH2_CLIENT_ID, client_secret=settings.GOOGLE_OAUTH2_CLIENT_SECRET, scope='https://www.googleapis.com/auth/youtube', redirect_uri='http://localhost:8888/oauth2callback/') # or if you downloaded the client_secrets file '''flow = flow_from_clientsecrets( settings.GOOGLE_OAUTH2_CLIENT_SECRETS_JSON, scope='https://www.googleapis.com/auth/youtube', redirect_uri='http://localhost:8888/oauth2callback/')'''
그리고 두 번째 부분:
if credential is None or credential.invalid == True: flow.params['state'] = xsrfutil.generate_token( settings.SECRET_KEY, request.user) authorize_url = flow.step1_get_authorize_url() return redirect(authorize_url) return redirect('/')
따라서 자격 증명이 없거나 자격 증명이 유효하지 않은 경우 자격 증명을 생성한 다음 인증 URL로 리디렉션합니다. 그렇지 않으면 홈페이지로 이동하여 비디오를 업로드할 수 있습니다!
이제 뷰에 액세스하여 어떤 일이 발생하는지 살펴보겠습니다.
그런 다음 해당 페이지로 이동하기 전에 사용자를 생성해 보겠습니다.
(djangoyt) ➜ ~/projects/django-youtube $ python manage.py createsuperuser Username (leave blank to use 'ivan'): ivan Email address: ivan***@mail.com Password: Password (again): This password is too short. It must contain at least 8 characters. Bypass password validation and create user anyway? [y/N]: y Superuser created successfully.
/admin
을 통해서도 로그인해 봅시다. 그런 다음 /authorize/
보기에 다시 액세스해 보겠습니다.
그 다음에,
알겠습니다. 오래 전에 Google에서 구성한 콜백 URL로 리디렉션을 시도했습니다. 이제 콜백 보기를 구현해야 합니다.
core/urls.py에 항목을 하나 더 추가해 보겠습니다.
# core/urls.py from .views import AuthorizeView, HomePageView, Oauth2CallbackView urlpatterns = [ # [...] path('oauth2callback/', Oauth2CallbackView.as_view(), name='oauth2callback') ]
그리고 또 다른 보기:
# core/views.py # the following variable stays as global for now flow = OAuth2WebServerFlow( client_id=settings.GOOGLE_OAUTH2_CLIENT_ID, client_secret=settings.GOOGLE_OAUTH2_CLIENT_SECRET, scope='https://www.googleapis.com/auth/youtube', redirect_uri='http://localhost:8888/oauth2callback/') # or if you downloaded the client_secrets file '''flow = flow_from_clientsecrets( settings.GOOGLE_OAUTH2_CLIENT_SECRETS_JSON, scope='https://www.googleapis.com/auth/youtube', redirect_uri='http://localhost:8888/oauth2callback/')''' # [...] class Oauth2CallbackView(View): def get(self, request, *args, **kwargs): if not xsrfutil.validate_token( settings.SECRET_KEY, request.GET.get('state').encode(), request.user): return HttpResponseBadRequest() credential = flow.step2_exchange(request.GET) storage = DjangoORMStorage( CredentialsModel, 'id', request.user.id, 'credential') storage.put(credential) return redirect('/')
참고: 흐름이 AuthorizeView 외부로 이동되어 전역이 되었습니다. 이상적으로는 AuthorizeView에서 생성하고 캐시에 저장한 다음 콜백에서 검색해야 합니다. 그러나 그것은 이 포스트의 범위를 벗어납니다.
AuthorizeView의 get 메소드는 다음과 같습니다.
def get(self, request, *args, **kwargs): storage = DjangoORMStorage( CredentialsModel, 'id', request.user.id, 'credential') credential = storage.get() if credential is None or credential.invalid == True: flow.params['state'] = xsrfutil.generate_token( settings.SECRET_KEY, request.user) authorize_url = flow.step1_get_authorize_url() return redirect(authorize_url) return redirect('/')
여기에서 유사한 구현을 살펴볼 수 있습니다. oauth2client
패키지 자체가 보기를 제공하지만 저는 특히 사용자 정의 Oauth 보기를 구현하는 것을 선호합니다.
- https://github.com/google/google-api-python-client/blob/master/samples/django_sample/plus/views.py
- https://github.com/google/oauth2client/blob/master/oauth2client/contrib/django_util/views.py
이제 /authorize/
URL을 다시 시도하면 OAuth 흐름이 작동해야 합니다. 이 작업이 가치가 있는지 확인하고 비디오를 업로드할 시간입니다! HomePageView
는 먼저 자격 증명을 확인하고 문제가 없으면 비디오를 업로드할 준비가 됩니다.
HomePageView에 대한 새 코드가 어떻게 보이는지 확인해 보겠습니다.
import tempfile from django.http import HttpResponse, HttpResponseBadRequest from googleapiclient.discovery import build from googleapiclient.http import MediaFileUpload class HomePageView(FormView): template_name = 'core/home.html' form_class = YouTubeForm def form_valid(self, form): fname = form.cleaned_data['video'].temporary_file_path() storage = DjangoORMStorage( CredentialsModel, 'id', self.request.user.id, 'credential') credentials = storage.get() client = build('youtube', 'v3', credentials=credentials) body = { 'snippet': { 'title': 'My Django Youtube Video', 'description': 'My Django Youtube Video Description', 'tags': 'django,howto,video,api', 'categoryId': '27' }, 'status': { 'privacyStatus': 'unlisted' } } with tempfile.NamedTemporaryFile('wb', suffix='yt-django') as tmpfile: with open(fname, 'rb') as fileobj: tmpfile.write(fileobj.read()) insert_request = client.videos().insert( part=','.join(body.keys()), body=body, media_body=MediaFileUpload( tmpfile.name, chunksize=-1, resumable=True) ) insert_request.execute() return HttpResponse('It worked!')
그리고 새 템플릿:
{# core/templates/core/home.html #} <!DOCTYPE html> <html> <body> <h1>Upload your video</h1> <p>Here is the form:</p> <form action="." method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="Submit"> </form> </body> </html>
YouTubeForm에 비디오 필드를 추가하는 것을 잊지 마십시오.
class YouTubeForm(forms.Form): video = forms.FileField()
여기 우리가 간다!
그런 다음 YouTube 계정 Studio 페이지에서 확인합니다(채널이 있어야 함).
짜잔!
마감 노트
코드는 약간의 개선이 필요하지만 좋은 출발점입니다. Google의 YouTube API 통합 문제 대부분에 도움이 되었기를 바랍니다. 다음은 주의해야 할 몇 가지 중요한 사항입니다.
- 승인을 위해서는 애플리케이션이 비디오를 업로드하도록 승인할 사용자에 대한 로그인 및 추가 권한이 필요합니다.
- 흐름 변수는 전역 변수에서 벗어나야 합니다. 프로덕션 환경에서는 안전하지 않습니다. 예를 들어 첫 번째 보기에 액세스한 사용자 ID 또는 세션을 기반으로 캐시하는 것이 좋습니다.
- Google은 첫 번째 인증을 수행할 때만 새로 고침 토큰을 제공합니다. 따라서 일정 시간(대부분 한 시간)이 지나면 토큰이 만료되고 해당 API와 상호 작용하지 않으면
invalid_grant
응답을 받기 시작합니다. 이미 클라이언트를 승인한 동일한 사용자를 재승인해도 새로 고침 토큰이 보장되지 않습니다. Google 계정 페이지에서 신청을 취소한 다음 승인 절차를 다시 수행해야 합니다. 경우에 따라 토큰을 계속 새로 고치기 위해 작업을 실행해야 할 수도 있습니다. - 요청과 직접 관련된 사용자 자격 증명을 사용하기 때문에 보기에서 로그인을 요구해야 합니다.
업로드하는 데 많은 시간이 걸리며 기본 애플리케이션 프로세스에서 업로드하면 업로드가 진행되는 동안 전체 애플리케이션이 차단될 수 있습니다. 올바른 방법은 자체 프로세스로 이동하고 업로드를 비동기식으로 처리하는 것입니다.
혼란스러운? 그러지 마세요. Python용 Celery에서 백그라운드 작업 워크플로 조정에서 자세히 읽어보세요.