Integrasi API YouTube: Mengunggah Video dengan Django
Diterbitkan: 2022-03-11Beberapa waktu yang lalu, saya bekerja untuk klien, mengintegrasikan ulasan video di situs web mereka. Seperti pengembang termotivasi yang memecahkan masalah baru, hal pertama yang saya lakukan adalah Google, dan saya menemukan sejumlah besar jawaban yang tidak membantu atau salah arah tentang cara mencapai sesuatu yang sama sekali berbeda, atau paket Python yang ketinggalan zaman dan tidak terawat. Akhirnya, saya menggigit peluru dan tim dan saya membangun semuanya dari awal: kami membuat tampilan, belajar tentang API Google, membuat klien API, dan akhirnya berhasil mengunggah video secara terprogram dari Django.
Dalam posting ini, saya akan mencoba memandu Anda langkah demi langkah dalam cara memposting video YouTube dari aplikasi Django Anda. Ini akan membutuhkan sedikit bermain-main dengan kredensial Google API—pertama dengan antarmuka web, lalu dengan kodenya. Bagian YouTube itu sendiri sangat mudah. Kita perlu memahami cara kerja barang-barang Google karena terkadang rumit dan informasinya tersebar di banyak tempat.
Prasyarat
Saya sarankan untuk membiasakan diri Anda dengan hal-hal berikut sebelum kita mulai bekerja:
- API Data YouTube: Panduan Memulai Python
- API Data YouTube: Referensi API
- API Data YouTube: Contoh Kode
- Pustaka Klien Google Python API
- Pustaka Klien Google Python API: Dokumen Referensi
- Pustaka Klien Google Python API: Contoh Kode
- YouTube API: Contoh Kode Python
Sedikit kode yang menarik untuk diperhatikan adalah Cuplikan Python berikut dari 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')
Mulai
Setelah Anda membaca prasyarat, saatnya untuk memulai. Mari kita lihat apa yang kita butuhkan.
Sabuk alat
Pada dasarnya, mari kita buat lingkungan virtual. Saya pribadi lebih suka pyenv. Menyiapkan keduanya berada di luar cakupan posting ini, jadi saya akan memposting beberapa perintah pyenv di bawah ini dan, jika preferensi Anda adalah virtualenv
, jangan ragu untuk mengganti perintah yang sesuai.
Saya akan menggunakan Python 3.7 dan Django 2.1 dalam posting ini.
➜ ~/projects $ mkdir django-youtube ➜ ~/projects $ cd django-youtube ➜ ~/projects/django-youtube $ pyenv virtualenv 3.7.0 djangoyt ➜ ~/projects/django-youtube $ vim .python-version
Mari kita masukkan ini ke dalam konten (hanya jika Anda menggunakan pyenv, sehingga aktif secara otomatis saat Anda masuk ke folder):
djangoyt
Menginstal dependensi:
➜ ~/projects/django-youtube $ pip install google-api-python-client google-auth\ google-auth-oauthlib google-auth-httplib2 oauth2client Django unipath jsonpickle
Sekarang waktunya untuk memulai proyek Django kita:
➜ ~/projects/django-youtube $ django-admin startproject django_youtube .
Jeda untuk beberapa Google Config
Mari konfigurasikan kredensial proyek kita sekarang sehingga kita dapat menggunakan Google API.
Langkah 1. Buka URL berikut:
https://console.developers.google.com/apis/library/youtube.googleapis.com
Langkah 2. Buat proyek baru.
Langkah 3. Klik “Aktifkan API dan Layanan.”
Langkah 4. Cari YouTube Data API v3, dan klik "Aktifkan."
Langkah 5. Anda akan mendapatkan pesan tentang kredensial.
Langkah 6. Klik tombol biru "Buat kredensial" di sisi kanan, dan Anda akan mendapatkan layar berikut:
Langkah 7. Pilih server Web, Data Pengguna:
Langkah 8. Tambahkan asal JS resmi dan arahkan URI. Lanjutkan sampai akhir:
OK kita selesai dengan pengaturan kredensial kita. Anda dapat mengunduh kredensial dalam format JSON atau menyalin ID Klien dan Rahasia Klien .
Kembali ke Django
Mari kita mulai aplikasi Django pertama kita. Saya biasanya menamakannya "inti":
(djangoyt) ➜ ~/projects/django-youtube $ python manage.py startapp core
Sekarang, mari tambahkan berikut ini ke file urls.py root kami untuk merutekan permintaan beranda ke aplikasi inti kami:
# <root>/urls.py from django.urls import path, include path('', include(('core.urls', 'core'), namespace='core')),
Di aplikasi inti, mari buat file urls.py lain, dengan beberapa konfigurasi juga:
# 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)
Lihat ada jalur kosong yang menunjuk ke HomePageView
. Saatnya menambahkan beberapa kode.
Mari kita lakukan sekarang TemplateView
sederhana hanya untuk melihatnya berjalan.
# core/views.py from django.shortcuts import render from django.views.generic import TemplateView class HomePageView(TemplateView): template_name = 'core/home.html'
Dan tentu saja kita membutuhkan template dasar:
# core/templates/core/home.html <!DOCTYPE html> <html> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> </body> </html>
Kita perlu melakukan beberapa tweak pengaturan:
# 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/'
Mari buat sekarang YoutubeForm
dan tambahkan sebagai form_class
ke tampilan:
# 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
Coba jalankan aplikasi Anda sekarang, dan halamannya akan terlihat seperti ini:
Jeda untuk Melakukan Otorisasi
Pertama-tama, Anda harus membuat model untuk menyimpan kredensial Anda. Anda dapat melalui file, sistem cache, atau solusi penyimpanan lainnya, tetapi database tampaknya masuk akal dan dapat diskalakan, dan Anda juga dapat menyimpan kredensial per pengguna jika Anda mau.
Sebelum melanjutkan, penyesuaian perlu dilakukan—ada fork dari oauth2client yang mendukung Django 2.1 yang harus kita gunakan. Segera, kami akan memiliki dukungan resmi, tetapi sementara itu, Anda dapat memeriksa perubahan garpu. Mereka sangat sederhana.
pip install -e git://github.com/Schweigi/[email protected]#egg=oauth2client Because of compatibility with Django 2.1
Buka settings.py
Anda dan tempatkan ID Klien dan Rahasia Klien yang Anda dapatkan dari Google di langkah sebelumnya.
# settings.py GOOGLE_OAUTH2_CLIENT_ GOOGLE_OAUTH2_CLIENT_SECRET = '<your client secret>'
Perhatian: menyimpan rahasia dalam kode Anda tidak disarankan. Saya melakukan ini hanya sebagai demonstrasi. Saya sarankan menggunakan variabel lingkungan di aplikasi produksi Anda, dan bukan rahasia hardcoding dalam file aplikasi. Atau, jika Anda mengunduh JSON dari Google, Anda juga dapat menentukan jalurnya alih-alih pengaturan di atas:
GOOGLE_OAUTH2_CLIENT_SECRETS_JSON = '/path/to/client_id.json'
Paket oauth2client sudah menyediakan banyak fungsi, dengan CredentialsField
sudah selesai yang dapat kita gunakan. Dimungkinkan untuk menambahkan lebih banyak bidang, seperti kunci asing dan tanggal yang dibuat/dimodifikasi sehingga kita menjadi lebih kuat, tetapi mari kita tetap sederhana.
Model sederhana untuk menyimpan kredensial:

# core/models.py from django.db import models from oauth2client.contrib.django_util.models import CredentialsField class CredentialsModel(models.Model): credential = CredentialsField()
Saatnya membuat migrasi dan migrasi:
(djangoyt) ➜ ~/projects/django-youtube $ ./manage.py makemigrations core (djangoyt) ➜ ~/projects/django-youtube $ ./manage.py migrate
Sekarang mari kita ubah tampilan API kita untuk dapat mengotorisasi aplikasi kita:
Di file core/urls.py
, mari tambahkan entri lain untuk tampilan otorisasi pertama:
# core/urls.py from .views import AuthorizeView, HomePageView urlpatterns = [ # [...] path('authorize/', AuthorizeView.as_view(), name='authorize'), ]
Jadi, bagian pertama dari AuthorizeView adalah:
# 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/')'''
Dan kemudian bagian kedua:
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('/')
Jadi, jika tidak ada kredensial atau kredensial tidak valid, buat kredensial lalu arahkan ke URL otorisasi. Jika tidak, cukup buka beranda agar kami dapat mengunggah video!
Mari akses tampilan sekarang dan lihat apa yang terjadi:
Mari kita buat pengguna, sebelum pergi ke halaman itu.
(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.
Mari kita juga masuk dengannya melalui /admin
. Setelah itu, mari akses kembali tampilan /authorize/
kita.
Kemudian,
Oke, itu mencoba mengarahkan ulang ke URL panggilan balik yang kami konfigurasikan lama dengan Google. Sekarang kita perlu mengimplementasikan tampilan callback.
Mari tambahkan satu entri lagi ke core/urls.py kami:
# core/urls.py from .views import AuthorizeView, HomePageView, Oauth2CallbackView urlpatterns = [ # [...] path('oauth2callback/', Oauth2CallbackView.as_view(), name='oauth2callback') ]
Dan tampilan lain:
# 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('/')
Catatan: Alur dipindahkan ke luar AuthorizeView, menjadi global. Idealnya, Anda harus membuatnya di bawah AuthorizeView dan menyimpannya di cache, lalu mengambilnya di callback. Tapi itu di luar cakupan posting ini.
Metode get dari AuthorizeView sekarang:
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('/')
Anda dapat melihat implementasi serupa di sini. Paket oauth2client
itu sendiri menyediakan tampilan tetapi saya lebih suka menerapkan tampilan Oauth kustom saya.
- 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
Sekarang jika Anda mencoba kembali /authorize/
URL, alur OAuth akan berfungsi. Saatnya untuk melihat apakah karya ini layak dan unggah video kami! HomePageView
pertama-tama akan memeriksa kredensial dan jika semuanya baik-baik saja, kami siap untuk mengunggah video kami.
Mari kita periksa bagaimana kode baru kita untuk HomePageView akan terlihat:
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!')
Dan template baru:
{# 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>
Jangan lupa untuk menambahkan bidang video ke YouTubeForm:
class YouTubeForm(forms.Form): video = forms.FileField()
Ini dia!
Dan kemudian, periksa di halaman Studio akun YouTube Anda (penting untuk memiliki saluran):
Voila!
Catatan Penutup
Kode perlu beberapa perbaikan, tetapi ini adalah titik awal yang baik. Saya harap ini membantu sebagian besar masalah Integrasi API YouTube Google. Berikut adalah beberapa hal yang lebih penting untuk diperhatikan:
- Untuk otorisasi, penting untuk meminta login dan izin tambahan bagi pengguna yang akan mengotorisasi aplikasi Anda untuk mengupload video.
- Variabel aliran perlu dipindahkan dari menjadi global. Itu tidak aman di lingkungan produksi. Lebih baik menyimpan cache berdasarkan ID pengguna atau sesi yang mengakses tampilan pertama, misalnya.
- Google hanya memberikan token penyegaran saat Anda melakukan otorisasi pertama. Jadi setelah beberapa waktu, sebagian besar satu jam, token Anda akan kedaluwarsa dan jika Anda tidak berinteraksi dengan API mereka, Anda akan mulai menerima tanggapan
invalid_grant
. Mengotorisasi ulang pengguna yang sama yang telah mengotorisasi klien tidak akan menjamin token penyegaran Anda. Anda harus mencabut aplikasi di halaman Akun Google Anda dan kemudian melakukan proses otorisasi lagi. Dalam beberapa kasus, Anda mungkin perlu menjalankan tugas untuk terus menyegarkan token. - Kami perlu meminta login dalam tampilan kami karena kami menggunakan kredensial pengguna yang terkait langsung dengan permintaan.
Mengunggah membutuhkan banyak waktu, dan melakukannya dalam proses aplikasi utama Anda dapat menyebabkan seluruh aplikasi diblokir saat pengunggahan terjadi. Cara yang benar adalah dengan memindahkannya ke dalam prosesnya sendiri dan menangani unggahan secara asinkron.
Bingung? Jangan, baca lebih lanjut di Mengatur Alur Kerja Pekerjaan Latar Belakang di Seledri untuk Python .