Как вернуть дизлайки на YouTube

Не так давно сервис по обмену видео YouTube, который сейчас является второй по популярности онлайн-платформой, объявил, что, хотя дизлайки останутся, фактический их подсчет будет закрыт.

«Чтобы гарантировать, что YouTube способствует уважительному взаимодействию между зрителями и создателями, мы ввели несколько функций и политик для улучшения их опыта, – сообщила компания в своем блоге. — А ранее в этом году мы экспериментировали с кнопкой “Не нравится”, чтобы увидеть, могут ли изменения помочь лучше защитить наших авторов от преследований и уменьшить количество дизлайк-атак – когда люди специально активно увеличивают количество дизлайков на видео автора».

Хотя устранение публично доступных дизлайков может помочь создателям, есть мнение, что это также помогает YouTube, заставляя больше внимания уделять видео – даже тем, которые могут разочаровать некоторых зрителей. Отсутствие «дизлайков» означает, что пользовательский контент не проходит быструю публичную проверку.

Поэтому сегодня мы бы хотели рассказать, как вернуть дизлайки на YouTube с помощью Django Rest Framework и YoutubeV3 API. Это может быть полезно для анализа собственного контента и контента других блогеров, к примеру.

Вступление

В этой статье мы увидим, как с помощью YoutubeV3 API и Django Rest Framework отобразить количество дизлайков для любого видео на YouTube.

Чтобы протестировать данную систему в реальном времени, перейдите на любое видео на YouTube.

Замените www.youtube.com:

на alienx.tech:

Не меняйте идентификатор видео и убедитесь, что вы удалили www, иначе получите сообщение об ошибке конфиденциальности. Нажмите Enter.

В случае успеха ваш браузер перенаправит вас на страницу ниже, на которой отображается количество лайков и дизлайков:

Прежде чем мы погрузимся в создание микросервиса, давайте начнем с понимания того, как нам удалось этого добиться.

Как это работает

Стоит отметить, что мы получили данную идею от y2mate — сайта, с помощью которого можно бесплатно загружать YouTube-видео. Он работает путем вставки pp после слова youtube в ссылке, например:

Первое, что нам нужно было сделать, это создать API-маршрут, похожий на YouTube, на своем бэкэнде Django. Кроме того, также нужен API YouTube для сбора данных о воспроизводимом видео. Удивительно, но YouTube не сделал эту функцию приватной, что достаточно справедливо.

На наш взгляд, документация по API YouTube не является удобной для использования. Поэтому мы продолжили поиск более оптимального инструмента.

Мы нашли восхитительное бесплатное приложение на RapidAPI, которое позволяет вам использовать API YouTube V3 без ключа API из учетной записи разработчика Google!

Приложение очень хорошо поддерживается и имеет низкий ping. P.S.: Мы бы могли сказать, что это потрясающий API, просто посмотрев на рейтинг, который он получил в RapidAPI. Так что отрицательный отзыв действительно может помочь вам сэкономить время. Представьте себе подписку на платный API, который оказывается очень медленным. Однако вы могли бы посмотреть на соотношение «нравится» и «не нравится» перед покупкой. Поэтому знать, скольким людям не понравился тот или иной продукт, порой бывает крайне полезно.

На стороне сервера Django Rest нам нужен был prometheus (имя нашего сервера API), чтобы сделать запрос к API youtubeV3, а затем вернуть ответ пользователю в виде шаблона, а не json или любого другого формата. На наш взгляд, Django — самый мощный фреймворк для веб-разработки. Кроме того, он имеет встроенную функцию, которая как раз нам очень пригодится, — Renderers. Процесс рендеринга работает, беря промежуточное представление шаблона и контекста и превращая его в конечный поток байтов, который может быть предоставлен клиенту.

[python_ad_block]

Создание нашего API

В этом руководстве мы будем использовать Python 3.5+, Django Rest Web Framework и Youtube v3 API для извлечения видеоданных YouTube, включая счетчик дизлайков.

Следуя лучшим практикам Python, мы создадим виртуальную среду для нашего проекта и установим необходимые пакеты. Подробнее про виртуальные среды (окружения) можно почитать в статье «Виртуальные окружения Python и инструменты для управления ими».

Итак, сначала создадим каталог проекта:

$ mkdir djangoapp
$ cd djangoapp

Теперь создаем виртуальную среду и устанавливаем необходимые пакеты.

Для систем macOS и Unix выполните следующую команду:

$ python3 -m venv myenv
$ source myenv/bin/activate
(myenv) $ pip3 install django djangorestframework requests

Для Windows:

$ python3 -m venv myenv
$ myenv\Scripts\activate
(myenv) $ pip3 install django djangorestframework requests

Youtube V3 API

Как упоминалось ранее, мы не будем получать доступ к API YouTube с помощью нашего собственного токена доступа. Вместо этого мы воспользуемся сторонним приложением, найденным в RapidAPI, который является одним из крупнейших торговых площадок API в Интернете.

Чтобы получить бесплатную версию youtubeV3API, создайте себе аккаунт на RapidAPI.

Настройка приложения Django

Сначала перейдем в созданный нами каталог приложения Django и создадим проект Django:

(myenv) $ django-admin startproject mainapp

Приведённый выше код автоматически сгенерирует некоторые файлы для скелета вашего проекта:

mainapp/
    manage.py
    mainapp/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

Теперь давайте перейдем в только что созданный каталог (убедитесь, что вы находитесь в том же каталоге, что и manage.py), и создайте каталог своего приложения:

(myenv) $ python manage.py startapp exam

Это создаст следующее:

exam/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

Найдите в файле mainapp/settings.py следующую строку и добавьте приложение, которое мы только что создали:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.humanize',#new line, explanation later
    'rest_framework',#new line
    'exam', #new line
]

Убедитесь, что вы находитесь в каталоге exam. Затем создайте новый каталог с именем templates и новый файл с именем urls.py. Ваша структура каталогов в exam должна выглядеть следующим образом:

exam/
    __init__.py
    admin.py
    apps.py
    migrations/
    templates/
        __init__.py
    models.py
    tests.py
    urls.py
    views.py

Проверьте ваш файл mainapp/urls.py и добавьте туда URL-адрес нашего приложения, чтобы включить URL-адреса, которые мы создадим в приложении exam:

"""mainapp URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path(' ', include('exam.urls')),#exam app url
]

Теперь добавьте в файл exc/urls.py наш сайт:

from django.urls import path, include
from . import views

urlpatterns = [
    path('watch', YoutubeStats.as_view(), name="youtubestats"),
]

Далее добавьте в файл exc/views.py следующие строки кода:

from django.shortcuts import render, redirect
import requests
from django.http import HttpResponse, HttpResponseRedirect
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.renderers import TemplateHTMLRenderer

class YoutubeStats(APIView):
      renderer_classes = [TemplateHTMLRenderer]
      template_name = 'youtube.html'

      def get(self, request):
          toScan = request.GET.get('v') #get users request(video URL in this case)
          #youtubev3 api
          parsed = str(toScan) #convert to string
          url = 'https://youtube-v31.p.rapidapi.com/videos'
          querystring = {"part":"contentDetails,snippet,statistics","id":parsed} 
          headers = {'x-rapidapi-host': "youtube-v31.p.rapidapi.com",'x-rapidapi-key': "GETYOURKEY"}
          response = requests.request("GET", url, headers=headers, params=querystring)
          DataResponse = response.json() 
          items = DataResponse.get('items')
          for data in items:
              chanid = data.get('snippet')
              channelid = chanid['channelId']
          #context = {'items':items, 'videoid':parsed}
          url2 = "https://youtube-v31.p.rapidapi.com/channels"
          querystring2 = {"part":"snippet,statistics","id":channelid}
          response2 = requests.request("GET", url2, headers=headers, params=querystring2)
          DataResponse2 = response2.json()
          items2 = DataResponse2.get('items')
          context = {'items':items, 'videoid':parsed, 'items2':items2,}
          return Response(context)

Разбор кода в файле views.py

В приведенном выше коде мы начинаем с инициализации класса YoutubeStats и имени шаблона нашего API. Затем мы получаем запрос пользователя, который был добавлен к видео для анализа (request.GET.get('v')). Затем мы преобразуем запрошенный идентификатор видео в строку. После этого отправляем запрос в API YouTube.

Пример ответа от API YouTube будет выглядеть следующим образом:

{
   "kind":"youtube#videoListResponse",
   "items":[
      {
         "kind":"youtube#video",
         "id":"frn3WT15Dy8",
         "snippet":{
            "publishedAt":"2021-11-23T01:30:12Z",
            "channelId":"UCPWXiRWZ29zrxPFIQT7eHSA",
            "title":"'This Is Now Becoming A Pattern': Jordan Slams YouTube Covid-19 'Censorship'",
            "description":"During a Wednesday hearing on COVID-19 misinformation, Rep. Jim Jordan (R-OH) criticized YouTube for removing a video containing 'misinformation.' The Ohio Republican said the social media company should not be censoring doctors over 'science.'",
            "thumbnails":{
               "default":{
                  "url":"https://i.ytimg.com/vi/frn3WT15Dy8/default.jpg",
                  "width":120,
                  "height":90
               },
               "medium":{
                  "url":"https://i.ytimg.com/vi/frn3WT15Dy8/mqdefault.jpg",
                  "width":320,
                  "height":180
               },
               "high":{
                  "url":"https://i.ytimg.com/vi/frn3WT15Dy8/hqdefault.jpg",
                  "width":480,
                  "height":360
               },
               "standard":{
                  "url":"https://i.ytimg.com/vi/frn3WT15Dy8/sddefault.jpg",
                  "width":640,
                  "height":480
               },
               "maxres":{
                  "url":"https://i.ytimg.com/vi/frn3WT15Dy8/maxresdefault.jpg",
                  "width":1280,
                  "height":720
               }
            },
            "channelTitle":"The Hill",
            "categoryId":"25",
            "liveBroadcastContent":"none",
            "defaultLanguage":"en-US",
            "localized":{
               "title":"'This Is Now Becoming A Pattern': Jordan Slams YouTube Covid-19 'Censorship'",
               "description":"During a Wednesday hearing on COVID-19 misinformation, Rep. Jim Jordan (R-OH) criticized YouTube for removing a video containing 'misinformation.' The Ohio Republican said the social media company should not be censoring doctors over 'science.'"
            },
            "defaultAudioLanguage":"en-US"
         },
         "contentDetails":{
            "duration":"PT6M19S",
            "dimension":"2d",
            "definition":"hd",
            "caption":"false",
            "licensedContent":true,
            "contentRating":{

            },
            "projection":"rectangular"
         },
         "statistics":{
            "viewCount":"989839",
            "likeCount":"35804",
            "dislikeCount":"798",
            "favoriteCount":"0",
            "commentCount":"7034"
         }
      }
   ],
   "pageInfo":{
      "totalResults":1,
      "resultsPerPage":1
   }
}

Чтобы получить название и количество подписчиков владельца канала, нам нужно сделать еще один запрос. Мы добавляем channel_ID в querystring2, а затем делаем запрос. После этого мы переходим к визуализации контекста в качестве окончательного ответа на наш HTML-шаблон, который мы создадим ниже.

Youtube Template

В папке exam/templates/ создайте файл youtube.html и добавьте следующие строки кода:

{% load humanize %}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
    />
    <style>
    @import url(https://fonts.googleapis.com/css2?family=Roboto&display=swap);*{margin:0;padding:0;box-sizing:border-box}body{background-color:rgba(200,200,200,.1);font-family:Roboto,sans-serif}.icon-spacing{padding:0 10px}.flex-column{flex-direction:column}.space-between{justify-content:space-between}.grid-container{position:relative;left:250px}nav{align-items:center;position:fixed;top:0;width:100%;height:50px;background-color:#fff;justify-content:space-between;z-index:1}#left-navbar{justify-content:space-evenly;width:12%;align-items:center;margin-left:15px}#mid-navbar{align-self:center;margin-right:20px;width:50%;justify-content:center}#search-bar{background-color:#fff;width:85%;padding:3px 10px;border:1px solid silver;border-radius:3px 0 0 3px;font-size:medium}#search-button{border:1px solid gray;padding:0 30px;border-radius:0 3px 3px 0}#right-navbar{align-items:center;width:120px;justify-content:space-between;margin-right:50px}.main-video{margin-left:initial}.flex{display:flex}.upcoming{font-family:Roboto,sans-serif;font-size:16px;color:#030303}.input{width:550px;position:relative;left:219px}.container{position:relative;top:85px;left:22px}.main-fc{width:60%;margin-left:30px}.other-videos{width:30%}#autobutton{border:none;background-color:transparent}.sidebar{position:relative;top:80px}.image{float:left;height:10px;position:relative;width:168px}.aside-video{grid-template-columns:180px 180px;display:grid;margin-bottom:4px}.song-title{font-size:14px;color:#030303;display:inline-block}.aside-description{position:relative;bottom:8px;font-size:12px}.artist-name{font-size:13px;color:#606060}.aside-views{font-size:13px;color:#606060}.video-duration{position:relative;float:right;bottom:18px;right:14px;font-size:12px;background-color:#000;color:#f5f5f5}.video-title{font-size:1.15rem;font-weight:300}.images{border-radius:50%;width:40px;height:40px}.smaller-gray{font-size:.9rem;color:gray}#video-below{justify-content:space-between;align-items:center}.video-section{justify-self:start}.subscribe-button{float:right;margin-top:-60px;background-color:#c00;font-size:smaller;border:none;color:#fff;padding:10px}.align-center{align-items:center;align-content:center;align-self:center}.inline{display:inline}.upnext{justify-content:center}.sidebar-attributes{font-family:Roboto,sans-serif;line-height:1.2em}.page-profile p{font-size:14px}#Squatty-potty{margin-bottom:-5px;padding-bottom:5px;margin-top:-20px}#avatar{margin-right:16px;margin-top:-40px;width:50px;height:50px}.user-name-bolded{margin:0 10px;font-size:small}.comment-description{margin-left:50px;margin-top:-20px;font-size:smaller}.smallest-gray{font-size:.7rem;color:gray}.reply{margin-left:10px;font-weight:300}.replies{margin-top:10px}.gray{color:#636363}.sort-button{display:grid;grid-template-columns:1fr 4.5fr}.sort-by{margin-left:10px}button{border:none;background-color:transparent}
    </style>
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
    />
    <title>Youtube Page</title>
  </head>

  <body>
    <nav class="flex">
      <div id="left-navbar" class="flex">
        <a href="#"><img src="https://res.cloudinary.com/prometheusapi/image/upload/v1638303419/hamburger_v2ird3.png" alt="" /></a>
        <a href="#"><img src="https://res.cloudinary.com/prometheusapi/image/upload/v1638303419/youtubelogos_kkvpsz.png" alt="" /></a>
      </div>
      <div id="mid-navbar" class="flex">
        <input id="search-bar" type="text" placeholder="Search" />
        <button id="search-button">
          <i class="fa fa-search" aria-hidden="true"></i>
        </button>
      </div>

      <div id="right-navbar" class="flex">
        <a href="#"><img src="https://res.cloudinary.com/prometheusapi/image/upload/v1638303419/nav1_ngreqx.png" alt="" /></a>
        <a href="#"><img src="https://res.cloudinary.com/prometheusapi/image/upload/v1638303419/nav2_zhlzur.png" alt="" /></a>
        <a href="#"><img src="https://res.cloudinary.com/prometheusapi/image/upload/v1638303419/nav4_oc1mlz.png" alt="" /></a>
        <a href="#"><img src="https://res.cloudinary.com/prometheusapi/image/upload/v1638303419/nav3_ayeunv.png" alt="" /></a>
      </div>
    </nav>
    {% for data in items %}
    <main class="d-flex space-between">
      <div class="main-fc d-flex flex-column">
        <div class="container">
          <div class="main-video">
            <iframe
              width="853"
              height="480"
              src="https://www.youtube.com/embed/{{videoid}}"
              allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
              allowfullscreen
            ></iframe>
            <br>
            <br>
            <h3 class="video-title">
              {{data.snippet.title}}
            </h3>
            <div id="video-below" class="flex flex-horizontal">
              <div class="video-views">
                <p class="smaller-gray">{{data.statistics.viewCount|intcomma}} views • {{data.snippet.publishedAt|slice:"10"}}</p>
              </div>
              <div class="flex">
                <button>
                  <i class="fa fa-thumbs-up icon-spacing" aria-hidden="true">
                    {{data.statistics.likeCount|intcomma}}</i
                  >
                </button>

                <button>
                  <i class="fa fa-thumbs-down icon-spacing" aria-hidden="true">
                    {{data.statistics.dislikeCount|intcomma}}</i
                  >
                </button>
                <button><i class="fa fa-share icon-spacing">SHARE</i></button>
                <button>
                  <i class="fa fa-save icon-spacing" aria-hidden="true">
                    SAVE</i
                  >
                </button>
                <button>
                  <i
                    class="fa fa-ellipsis-h icon-spacing"
                    aria-hidden="true"
                  ></i>
                </button>
              </div>
            </div>
            <hr />
            <br />
          </div>

          <div class="page-profile">
            <div class="user-description">
              <button class="subscribe-button">ALIENX</button>
            </div>
            <h3>
              {{data.snippet.channelTitle}}
            </h3>
            <p>
              {{data.snippet.description}}
            </p>
          </div>

          <div class="video-comments">
            <div class="comment-section">
              <hr />
              <div class="sort-button">
                <h6>{{data.statistics.commentCount|intcomma}} Comments</h6>
                <div>
                  {% endfor %}
                </div>
              </div>
              <i class="fa fa-sort-amount-down gray" aria-hidden="true"></i>
            </div>
            <hr />

          </div>
        </div>
      </div>

    </main>
  </body>
</html>

Пояснение HTML-кода

В приведенном выше коде мы начинаем с импорта очень важного пакета под названием Django Humanize. Этот пакет полезен для добавления так называемого «человеческого прикосновения» к данным. Таким образом мы делаем наш контент более читабельным для человеческого глаза. В нашем случае это нужно для изменения данных, извлеченных с YouTube. Данные, которые мы хотим «очеловечить», – это счетчики.

Из запроса API выше вы заметите, что в счетчиках нет запятых. Поэтому следующим шагом мы добавляем приведенный ниже код для форматирования данных в запятые:

<i class="fa fa-thumbs-up icon-spacing" aria-hidden="true">
                    {{data.statistics.likeCount|intcomma}}
</i>

Тестирование нашего API

Сделайте необходимые миграции, а затем запустите сервер. Перейдите к выбранному вами видео на YouTube и замените HTTPS на HTTP. Измените www.youtube.com на ваш локальный хост. В итоге вы получите примерно такой URL-адрес:

Заключение

Итак, сегодня мы разобрали, как вернуть дизлайки на YouTube с помощью Django Rest Framework и YoutubeV3 AP. Надеемся, данное руководство было вам полезно и теперь вы сможете получать более точную аналитику по вашим видео или смотреть, сколько дизлайков набрал ваш любимый блогер (или нелюбимый ?).

Желаем успехов в написании кода!

Перевод статьи «How to Restore Dislikes on YouTube with Django Rest Framework and YoutubeV3 API».