Integrare YouTube API: Încărcarea videoclipurilor cu Django

Publicat: 2022-03-11

Cu puțin timp în urmă, lucram pentru un client, integrând recenzii video în site-ul lor. La fel ca orice dezvoltator motivat care rezolvă o problemă nouă, primul lucru pe care l-am făcut a fost Google și am găsit o multitudine de răspunsuri inutile sau greșite despre cum să obțin ceva complet diferit sau pachete Python învechite și neîntreținute. În cele din urmă, am mușcat glonțul și echipa și am construit totul de la zero: am creat vizualizările, am aflat despre API-ul Google, am creat clientul API și, în cele din urmă, am reușit să încărcăm în mod programatic videoclipuri de la Django.

În această postare, voi încerca să vă ghidez pas cu pas în modul de a posta videoclipuri YouTube din aplicația Django. Acest lucru va necesita un pic de joc cu acreditările Google API - mai întâi cu interfața web, apoi cu codul. Partea YouTube în sine este foarte simplă. Trebuie să înțelegem cum funcționează lucrurile Google, deoarece uneori sunt dificile și informațiile sunt răspândite în multe locuri.

Cerințe preliminare

Vă recomand să vă familiarizați cu următoarele înainte de a începe lucrul:

  • YouTube Data API: Python Quickstart
  • YouTube Data API: API Reference
  • YouTube Data API: Exemple de cod
  • Biblioteca client Google Python API
  • Biblioteca client Google Python API: document de referință
  • Biblioteca client Google Python API: Exemple de cod
  • API YouTube: Exemple de cod Python

Un fragment interesant de cod de remarcat este următorul fragment Python din Google YouTube API Docs:

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

Noțiuni de bază

După ce ați citit cerințele preliminare, este timpul să începeți. Să vedem de ce avem nevoie.

Curea port scule

Practic, să creăm un mediu virtual. Eu personal prefer pyenv. Configurarea ambelor nu intră în domeniul de aplicare al acestei postări, așa că voi posta câteva comenzi pyenv mai jos și, dacă preferința dvs. este virtualenv , nu ezitați să înlocuiți comenzile în consecință.

Voi folosi Python 3.7 și Django 2.1 în această postare.

 ➜ ~/projects $ mkdir django-youtube ➜ ~/projects $ cd django-youtube ➜ ~/projects/django-youtube $ pyenv virtualenv 3.7.0 djangoyt ➜ ~/projects/django-youtube $ vim .python-version

Să punem asta în conținut (doar dacă folosești pyenv, deci se activează automat când intri în folder):

 djangoyt

Instalarea dependențelor:

 ➜ ~/projects/django-youtube $ pip install google-api-python-client google-auth\ google-auth-oauthlib google-auth-httplib2 oauth2client Django unipath jsonpickle

Acum este timpul să începem proiectul nostru django:

 ➜ ~/projects/django-youtube $ django-admin startproject django_youtube .

Întrerupeți pentru unele configurații Google

Să ne configuram acum acreditările proiectului, astfel încât să putem folosi API-urile Google.

Pasul 1. Accesați următorul URL:

https://console.developers.google.com/apis/library/youtube.googleapis.com

Pasul 2. Creați un nou proiect.

Creați un nou proiect

Pasul 3. Faceți clic pe „Activați API-urile și serviciile”.

Activați API-urile și serviciile.

Pasul 4. Căutați YouTube Data API v3 și faceți clic pe „Activați”.

Căutați YouTube Data API v3 și faceți clic pe „Activați”.

Pasul 5. Ar trebui să primiți un mesaj despre acreditări.

un mesaj despre acreditări

Pasul 6. Faceți clic pe butonul albastru „Creați acreditări” din partea dreaptă și ar trebui să obțineți următorul ecran:

Faceți clic pe butonul albastru „Creați acreditări”.

Pasul 7. Alegeți server web, date utilizator:

Alegeți Web server, User Data

Pasul 8. Adăugați origini JS autorizate și URI-uri de redirecționare. Continuați până la sfârșit:

Adăugați origini JS autorizate și URI-uri de redirecționare.

OK, am terminat cu acreditările noastre configurate. Puteți fie să descărcați acreditările într-un format JSON, fie să copiați ID -ul clientului și Secretul clientului .

Înapoi la Django

Să începem prima noastră aplicație Django. De obicei îl numesc „core”:

 (djangoyt) ➜ ~/projects/django-youtube $ python manage.py startapp core

Acum, să adăugăm următoarele în fișierul nostru rădăcină urls.py pentru a direcționa solicitările paginii de pornire către aplicația noastră principală:

 # <root>/urls.py from django.urls import path, include path('', include(('core.urls', 'core'), namespace='core')),

În aplicația de bază, să avem un alt fișier urls.py, cu câteva configurații:

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

Vedeți că există o cale goală care indică către HomePageView . E timpul să adaugi niște coduri.

Să facem acum un simplu TemplateView doar pentru a-l vedea rulând.

 # core/views.py from django.shortcuts import render from django.views.generic import TemplateView class HomePageView(TemplateView): template_name = 'core/home.html'

Și, desigur, avem nevoie de un șablon de bază:

 # core/templates/core/home.html <!DOCTYPE html> <html> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> </body> </html>

Trebuie să facem câteva modificări ale setărilor:

 # 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/'

Să creăm acum un YoutubeForm și să-l adăugăm ca form_class la vizualizare:

 # 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

Încercați să rulați aplicația dvs. acum și pagina va arăta astfel:

Previzualizarea paginii

Întrerupeți pentru a face autorizarea

În primul rând, trebuie să creați un model pentru a vă stoca acreditările. Puteți să faceți un fișier, un sistem de cache sau orice altă soluție de stocare, dar o bază de date pare rezonabilă și scalabilă și, de asemenea, puteți stoca acreditările pentru fiecare utilizator, dacă doriți.

Înainte de a continua, trebuie făcută o ajustare — există o furcăre a oauth2client care acceptă Django 2.1 pe care trebuie să-l folosim. În curând, vom avea asistență oficială, dar între timp, puteți inspecta modificările furcii. Sunt foarte simple.

 pip install -e git://github.com/Schweigi/[email protected]#egg=oauth2client Because of compatibility with Django 2.1

Accesați settings.py și plasați ID -ul clientului și Secretul clientului pe care le-ați primit de la Google în pașii anteriori.

 # settings.py GOOGLE_OAUTH2_CLIENT_ GOOGLE_OAUTH2_CLIENT_SECRET = '<your client secret>'

Atenție: stocarea secretelor în codul dvs. nu este recomandată. Fac asta pur și simplu ca o demonstrație. Recomand să folosiți variabilele de mediu în aplicația dvs. de producție și să nu codificați secrete în fișierele aplicației. Alternativ, dacă ați descărcat JSON de la Google, puteți specifica și calea acestuia în loc de setările de mai sus:

 GOOGLE_OAUTH2_CLIENT_SECRETS_JSON = '/path/to/client_id.json'

Pachetul oauth2client oferă deja o mulțime de funcționalități, cu un CredentialsField deja făcut pe care îl putem folosi. Este posibil să adăugați mai multe câmpuri, cum ar fi o cheie străină și date create/modificate, astfel încât să devenim mai robusti, dar să rămânem simpli.

Model simplu pentru stocarea acreditărilor:

 # core/models.py from django.db import models from oauth2client.contrib.django_util.models import CredentialsField class CredentialsModel(models.Model): credential = CredentialsField()

Este timpul să creați migrații și să migrați:

 (djangoyt) ➜ ~/projects/django-youtube $ ./manage.py makemigrations core (djangoyt) ➜ ~/projects/django-youtube $ ./manage.py migrate

Acum să ne schimbăm vizualizările API pentru a ne putea autoriza aplicația:

În fișierul nostru core/urls.py , să adăugăm o altă intrare pentru prima vizualizare de autorizare:

 # core/urls.py from .views import AuthorizeView, HomePageView urlpatterns = [ # [...] path('authorize/', AuthorizeView.as_view(), name='authorize'), ]

Deci, prima parte a AuthorizeView va fi:

 # 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/')'''

Și apoi partea a doua:

 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('/')

Deci, dacă nu există acreditări sau acreditările sunt invalide, generați una și apoi redirecționați-o către adresa URL de autorizare. În caz contrar, trebuie doar să accesați pagina de pornire pentru a putea încărca un videoclip!

Să accesăm vizualizarea acum și să vedem ce se întâmplă:

Eroare de autorizare

Să creăm un utilizator, înainte de a merge la pagina respectivă.

 (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.

Să ne conectăm și cu el prin /admin . După aceea, să accesăm din nou vizualizarea noastră /authorize/ .

Să ne autentificăm

Autorizare

Apoi,

404 Eroare

OK, a încercat să redirecționeze la adresa URL de apel invers pe care am configurat-o cu mult timp în urmă cu Google. Acum trebuie să implementăm vizualizarea de apel invers.

Să mai adăugăm o intrare în core/urls.py:

 # core/urls.py from .views import AuthorizeView, HomePageView, Oauth2CallbackView urlpatterns = [ # [...] path('oauth2callback/', Oauth2CallbackView.as_view(), name='oauth2callback') ]

Si inca o vedere:

 # 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('/')

Notă: fluxul a fost mutat în afara AuthorizeView, devenind global. În mod ideal, ar trebui să îl creați sub AuthorizeView și să îl salvați într-un cache, apoi să îl preluați în apel invers. Dar asta nu se încadrează în scopul acestei postări.

Metoda get a AuthorizeView este acum:

 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('/')

Puteți arunca o privire la implementări similare aici. Pachetul oauth2client în sine oferă vizualizări, dar prefer să implementez vizualizarea mea personalizată 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

Acum, dacă încercați din nou adresa URL /authorize/ , fluxul OAuth ar trebui să funcționeze. Este timpul să vedem dacă această muncă merită și să încărcați videoclipul nostru! HomePageView va verifica mai întâi acreditările și, dacă totul este bine, suntem gata să încărcăm videoclipul nostru.

Să verificăm cum va arăta noul nostru cod pentru 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!')

Și noul șablon:

 {# 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>

Nu uitați să adăugați câmpul video la YouTubeForm:

 class YouTubeForm(forms.Form): video = forms.FileField()

Începem!

Încărcați formularul

Și apoi, verificând pagina Studio a contului tău YouTube (este important să ai un canal):

Video încărcat

Voila!

Note de închidere

Codul are nevoie de unele îmbunătățiri, dar este un bun punct de plecare. Sper că a ajutat cu majoritatea problemelor de integrare a API-ului YouTube de la Google. Iată câteva lucruri mai importante de reținut:

  • Pentru autorizare, este important să solicitați autentificare și permisiuni suplimentare pentru utilizatorul care va autoriza aplicația dvs. să încarce videoclipuri.
  • Variabila de flux trebuie mutată din a fi globală. Nu este sigur într-un mediu de producție. Este mai bine să memorați cache pe baza ID-ului utilizatorului sau a sesiunii care a accesat prima vizualizare, de exemplu.
  • Google oferă un indicativ de reîmprospătare numai atunci când efectuați prima autorizare. Deci, după ceva timp, în mare parte o oră, token-ul tău va expira și dacă nu ai interacționat cu API-ul lor, vei începe să primești răspunsuri invalid_grant . Reautorizarea aceluiași utilizator care a autorizat deja un client nu va garanta indicativul de reîmprospătare. Trebuie să revocați aplicația din pagina Conturi Google și apoi să faceți din nou procesul de autorizare. În unele cazuri, poate fi necesar să rulați o sarcină pentru a continua să reîmprospătați simbolul.
  • Trebuie să solicităm autentificare în vizualizarea noastră, deoarece folosim o autentificare de utilizator direct legată de cerere.

Eroare FlowExchange

Încărcarea durează mult timp, iar efectuarea acesteia în procesul principal de aplicare poate cauza blocarea întregii aplicații în timp ce are loc încărcarea. Modul corect ar fi să îl mutați în propriul proces și să gestionați încărcările în mod asincron.

Confuz? Nu fiți, citiți mai multe în Orchestrarea unui flux de lucru în fundal în Celery pentru Python .