YouTube-API-Integration: Hochladen von Videos mit Django

Veröffentlicht: 2022-03-11

Vor kurzem habe ich für einen Kunden gearbeitet und Videobewertungen in seine Website integriert. Wie jeder motivierte Entwickler, der ein neuartiges Problem löst, habe ich es zuerst gegoogelt und eine Fülle von nicht hilfreichen oder fehlgeleiteten Antworten gefunden, wie man etwas völlig anderes erreichen kann, oder veraltete und nicht gepflegte Python-Pakete. Schließlich biss ich in den sauren Apfel und das Team und ich bauten alles von Grund auf neu auf: Wir erstellten die Ansichten, lernten die API von Google kennen, erstellten den API-Client und schafften es schließlich, Videos programmgesteuert von Django hochzuladen.

In diesem Beitrag werde ich versuchen, Sie Schritt für Schritt durch das Posten von YouTube-Videos aus Ihrer Django-App zu führen. Dies erfordert ein wenig Herumspielen mit den Google-API-Anmeldeinformationen – zuerst mit der Weboberfläche, dann mit dem Code. Der YouTube-Teil selbst ist sehr einfach. Wir müssen verstehen, wie Google-Zeug funktioniert, weil es manchmal schwierig ist und die Informationen über viele Orte verteilt sind.

Voraussetzungen

Ich empfehle, sich vor Arbeitsbeginn mit Folgendem vertraut zu machen:

  • YouTube-Daten-API: Python-Schnellstart
  • YouTube-Daten-API: API-Referenz
  • YouTube-Daten-API: Codebeispiele
  • Google Python API-Clientbibliothek
  • Google Python API-Clientbibliothek: Referenzdokument
  • Google Python API-Clientbibliothek: Codebeispiele
  • YouTube-API: Python-Codebeispiele

Ein interessanter Codeabschnitt ist das folgende Python-Snippet aus den 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')

Einstieg

Nachdem Sie die Voraussetzungen gelesen haben, können Sie loslegen. Mal sehen, was wir brauchen.

Werkzeuggürtel

Lassen Sie uns im Grunde eine virtuelle Umgebung erstellen. Ich persönlich bevorzuge pyenv. Beides einzurichten geht über den Rahmen dieses Beitrags hinaus, daher werde ich unten einige pyenv-Befehle posten und, wenn Sie virtualenv bevorzugen, die Befehle entsprechend ersetzen.

Ich werde in diesem Beitrag Python 3.7 und Django 2.1 verwenden.

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

Lassen Sie uns dies in den Inhalt einfügen (nur wenn Sie pyenv verwenden, wird es automatisch aktiviert, wenn Sie den Ordner betreten):

 djangoyt

Abhängigkeiten installieren:

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

Jetzt ist es an der Zeit, unser Django-Projekt zu starten:

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

Pause für einige Google Config

Lassen Sie uns jetzt unsere Projektanmeldeinformationen konfigurieren, damit wir die Google-APIs verwenden können.

Schritt 1. Rufen Sie die folgende URL auf:

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

Schritt 2. Erstellen Sie ein neues Projekt.

Erstellen Sie ein neues Projekt

Schritt 3. Klicken Sie auf „APIs und Dienste aktivieren“.

Aktivieren Sie APIs und Dienste.

Schritt 4. Suchen Sie nach YouTube Data API v3 und klicken Sie auf „Aktivieren“.

Suchen Sie nach YouTube Data API v3 und klicken Sie auf „Aktivieren“.

Schritt 5. Sie sollten eine Nachricht über Anmeldeinformationen erhalten.

eine Nachricht über Anmeldeinformationen

Schritt 6. Klicken Sie auf die blaue Schaltfläche „Create Credentials“ auf der rechten Seite, und Sie sollten den folgenden Bildschirm erhalten:

Klicken Sie auf die blaue Schaltfläche „Create Credentials“.

Schritt 7. Wählen Sie Webserver, Benutzerdaten:

Wählen Sie Webserver, Benutzerdaten

Schritt 8. Fügen Sie autorisierte JS-Ursprünge hinzu und leiten Sie URIs um. Weiter bis zum Ende:

Fügen Sie autorisierte JS-Ursprünge hinzu und leiten Sie URIs um.

OK, wir sind mit der Einrichtung unserer Anmeldeinformationen fertig. Sie können die Anmeldeinformationen entweder im JSON-Format herunterladen oder die Client-ID und das Client-Secret kopieren.

Zurück zu Django

Beginnen wir mit unserer allerersten Django-App. Ich nenne es normalerweise „Kern“:

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

Fügen wir nun Folgendes zu unserer Stammdatei urls.py hinzu, um die Homepage-Anfragen an unsere Kern-App weiterzuleiten:

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

Lassen Sie uns in der Kern-App eine weitere urls.py-Datei haben, auch mit etwas Konfiguration:

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

Sehen Sie, es gibt einen leeren Pfad, der auf HomePageView zeigt. Zeit, etwas Code hinzuzufügen.

Lassen Sie uns jetzt eine einfache TemplateView machen, nur um zu sehen, wie es läuft.

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

Und natürlich brauchen wir eine grundlegende Vorlage:

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

Wir müssen einige Einstellungen vornehmen:

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

Lassen Sie uns nun ein YoutubeForm erstellen und es als form_class zur Ansicht hinzufügen:

 # 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

Versuchen Sie jetzt, Ihre Anwendung auszuführen, und die Seite sieht folgendermaßen aus:

Seitenvorschau

Pause, um die Autorisierung durchzuführen

Zunächst müssen Sie ein Modell erstellen, um Ihre Anmeldeinformationen zu speichern. Sie könnten eine Datei, ein Cache-System oder eine andere Speicherlösung verwenden, aber eine Datenbank scheint vernünftig und skalierbar zu sein, und Sie können auch Anmeldeinformationen pro Benutzer speichern, wenn Sie möchten.

Bevor Sie fortfahren, muss eine Anpassung vorgenommen werden – es gibt einen Fork von oauth2client, der Django 2.1 unterstützt, den wir verwenden müssen. Bald werden wir offizielle Unterstützung haben, aber in der Zwischenzeit können Sie die Änderungen an der Gabel überprüfen. Sie sind sehr einfach.

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

Gehen Sie zu Ihrer settings.py und platzieren Sie die Client-ID und das Client-Secret , die Sie in den vorherigen Schritten von Google erhalten haben.

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

Achtung: Das Speichern von Geheimnissen in Ihrem Code wird nicht empfohlen. Ich mache das nur als Demonstration. Ich empfehle die Verwendung von Umgebungsvariablen in Ihrer Produktions-App und nicht die Festcodierung von Geheimnissen in Anwendungsdateien. Wenn Sie das JSON von Google heruntergeladen haben, können Sie alternativ auch seinen Pfad anstelle der obigen Einstellungen angeben:

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

Das oauth2client-Paket bietet bereits viele Funktionen, wobei ein CredentialsField bereits fertig ist, das wir verwenden können. Es ist möglich, weitere Felder hinzuzufügen, z. B. einen Fremdschlüssel und erstellte/geänderte Daten, damit wir robuster werden, aber bleiben wir einfach.

Einfaches Modell zum Speichern von Anmeldeinformationen:

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

Zeit zum Erstellen von Migrationen und Migrieren:

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

Lassen Sie uns nun unsere API-Ansichten ändern, um unsere Anwendung autorisieren zu können:

Fügen wir in unserer Datei core/urls.py einen weiteren Eintrag für die erste Autorisierungsansicht hinzu:

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

Der erste Teil von AuthorizeView wird also sein:

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

Und dann der zweite Teil:

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

Wenn also kein oder ein ungültiger Berechtigungsnachweis vorhanden ist, generieren Sie einen und leiten Sie ihn dann an die Autorisierungs-URL weiter. Ansonsten einfach auf die Homepage gehen, damit wir ein Video hochladen können!

Lassen Sie uns jetzt auf die Ansicht zugreifen und sehen, was passiert:

Autorisierungsfehler

Lassen Sie uns dann einen Benutzer erstellen, bevor Sie zu dieser Seite gehen.

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

Melden wir uns auch damit über /admin an. Danach greifen wir wieder auf unsere /authorize/ -Ansicht zu.

Lassen Sie uns einloggen

Genehmigung

Dann,

404 Fehler

OK, es wurde versucht, auf die Rückruf-URL umzuleiten, die wir vor langer Zeit mit Google konfiguriert haben. Jetzt müssen wir die Callback-Ansicht implementieren.

Fügen wir unserer core/urls.py einen weiteren Eintrag hinzu:

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

Und noch eine Ansicht:

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

Hinweis: Der Flow wurde außerhalb von AuthorizeView verschoben und wurde global. Idealerweise sollten Sie es unter der AuthorizeView erstellen und in einem Cache speichern und dann im Callback abrufen. Aber das ist nicht Gegenstand dieses Beitrags.

Die Get-Methode von AuthorizeView lautet jetzt:

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

Sie können sich hier ähnliche Implementierungen ansehen. Das oauth2client -Paket selbst bietet Ansichten, aber ich bevorzuge es besonders, meine benutzerdefinierte Oauth-Ansicht zu implementieren.

  • 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

Wenn Sie jetzt die /authorize/ -URL erneut versuchen, sollte der OAuth-Fluss funktionieren. Zeit zu sehen, ob sich diese Arbeit lohnt und unser Video hochzuladen! Der HomePageView wird zuerst nach Anmeldeinformationen suchen und wenn alles in Ordnung ist, können wir unser Video hochladen.

Sehen wir uns an, wie unser neuer Code für die HomePageView aussehen wird:

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

Und die neue Vorlage:

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

Vergessen Sie nicht, das Videofeld zu YouTubeForm hinzuzufügen:

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

Auf geht's!

Formular hochladen

Überprüfen Sie dann die Studio-Seite Ihres YouTube-Kontos (es ist wichtig, einen Kanal zu haben):

Video hochgeladen

Voila!

Schlussnotizen

Der Code muss verbessert werden, aber es ist ein guter Ausgangspunkt. Ich hoffe, es hat bei den meisten Problemen mit der YouTube-API-Integration von Google geholfen. Hier sind noch ein paar wichtige Dinge zu beachten:

  • Für die Autorisierung ist es wichtig, eine Anmeldung und zusätzliche Berechtigungen für den Benutzer zu verlangen, der Ihre Anwendung zum Hochladen von Videos autorisiert.
  • Die Flow-Variable muss aus der globalen Position verschoben werden. Es ist in einer Produktionsumgebung nicht sicher. Es ist beispielsweise besser, basierend auf der Benutzer-ID oder Sitzung, die auf die erste Ansicht zugegriffen hat, zwischenzuspeichern.
  • Google stellt nur bei der ersten Autorisierung ein Aktualisierungstoken bereit. Nach einiger Zeit, meistens einer Stunde, läuft Ihr Token ab, und wenn Sie nicht mit der API interagiert haben, erhalten Sie invalid_grant Antworten. Die erneute Autorisierung desselben Benutzers, der bereits einen Client autorisiert hat, garantiert Ihr Aktualisierungstoken nicht. Sie müssen den Antrag auf Ihrer Google-Kontoseite widerrufen und dann den Autorisierungsprozess erneut durchführen. In einigen Fällen müssen Sie möglicherweise eine Aufgabe ausführen, um das Token ständig zu aktualisieren.
  • Aus unserer Sicht müssen wir eine Anmeldung verlangen, da wir eine Benutzeranmeldeinformation verwenden, die direkt mit der Anfrage zusammenhängt.

FlowExchange-Fehler

Das Hochladen nimmt viel Zeit in Anspruch und wenn Sie dies in Ihrem Hauptbewerbungsprozess tun, kann dies dazu führen, dass die gesamte Bewerbung während des Hochladens blockiert wird. Der richtige Weg wäre, es in einen eigenen Prozess zu verschieben und Uploads asynchron zu verarbeiten.

Verwirrt? Lesen Sie mehr in Orchestrating a Background Job Workflow in Celery for Python .