Статьи

Загрузка видео с помощью Rails и Ziggeo

ziggeo

Я помню времена, когда практически никто в Интернете не смотрел видео, потому что скорость соединения была слишком медленной. Затем скорость начала расти, и я мог скачивать музыкальные треки: загрузка одного трека заняла примерно 4-5 минут, пока я слушал другой. В 2005 году появился YouTube и начал распространяться видеоконтент. В настоящее время видео есть везде, и многие люди предпочитают их тексту (хотя есть и другие, которым нравится читать текст).

Я уже рассмотрел процесс работы с API YouTube в одной из моих предыдущих статей , поэтому сегодня мы обсудим другую платформу видеохостинга под названием Ziggeo . Он предоставляет API для хранения и управления видео, а также возможность встраивать их (используя простой проигрыватель). Кроме того, есть дополнительные функции, такие как комментарии, модерация, права доступа для обратных вызовов, интеграция со сторонними сервисами и многое другое. У Ziggeo есть как бесплатные, так и платные тарифные планы . С бесплатным планом вы можете загружать видео общей продолжительностью 100 минут, так что это отличный вариант для тестирования сервиса.

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

Исходный код доступен на GitHub .

Отдельное спасибо команде поддержки Ziggeo, которая предоставила быструю и профессиональную помощь.

Создание приложения

Как обычно, начните с создания нового приложения на Rails 5 под названием ZigZag :

 $ rails new ZigZag -T 

Загляните в некоторые необходимые драгоценные камни:

Gemfile

 # ... gem 'Ziggeo' gem 'dotenv-rails' gem 'devise' 
  • Ziggeo — это драгоценный камень, позволяющий вам легко работать с API Ziggeo. Обратите внимание, что его имя начинается с заглавной буквы «Z»!
  • Dotenv будет использоваться для хранения переменных среды для разработки.
  • Devise предоставит решение для аутентификации.

Установите эти драгоценные камни, создайте базовую конфигурацию для Devise и добавьте модель User :

 $ bundle install $ rails generate devise:install $ rails generate devise User $ rails db:migrate 

Создайте VideosController и настройте несколько маршрутов:

videos_controller.rb

 class VideosController < ApplicationController end 

конфиг / routes.rb

 # ... resources :videos, only: [:new, :index, :destroy] root 'videos#index' 

Обеспечить аутентификацию пользователя внутри ApplicationController :

application_controller.rb

 # ... before_action :authenticate_user! 

Также давайте отобразим флеш-сообщения внутри макета:

просмотров / макеты / application.html.erb

 # ... <% flash.each do |key, value| %> <div class="alert alert-<%= key %>"> <%= value %> </div> <% end %> 

Вот и все. Следующим шагом является настройка Ziggeo.

Начальная настройка Ziggeo

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

.env

 ZIGGEO_KEY=123 ZIGGEO_SECRET=abc ZIGGEO_ENCRYPTION=345 

Убедитесь, что вы исключили этот файл из Git:

.gitignore

 .env 

Ziggeo также предоставляет хорошее краткое руководство, так что вы можете просмотреть его. Затем включите необходимые файлы CSS и JavaScript:

просмотров / макеты / application.html.erb

 <link rel="stylesheet" href="//assets-cdn.ziggeo.com/v1-stable/ziggeo.css" /> <script src="//assets-cdn.ziggeo.com/v1-stable/ziggeo.js"></script> <script>ZiggeoApi.token = '<%= ENV['ZIGGEO_KEY'] %>';</script> 

В принципе, этого достаточно, чтобы начать загружать и встраивать видео на сайт.

Загрузка и запись

Ziggeo дает нам указание разместить специальный тег ( ziggeo ) на странице. Он одновременно выполняет функции видеоплеера, видеомагнитофона и устройства для загрузки видео. Для управления поведением и внешним видом компонента можно установить несколько параметров.

Вот самый простой вариант:

просмотры / видео / new.html.erb

 <ziggeo ziggeo-width="320" ziggeo-height="240"></ziggeo> 

Это создаст специальный элемент управления для записи и загрузки видео. Я не хочу, чтобы видео было слишком длинным, поэтому установите параметр ziggeo-limit :

 <ziggeo ziggeo-width="320" ziggeo-height="240" ziggeo-limit="60"></ziggeo> 

60 здесь означает «не более 60 секунд». Кроме того, было бы неплохо разрешить пользователю загружать уже записанные видео, поэтому установите ziggeo-perms allowupload для allowupload :

 <ziggeo ziggeo-limit="60" ziggeo-width="320" ziggeo-height="240" ziggeo-perms="allowupload"></ziggeo> 

Теперь вы можете проверить это. Любое загруженное видео будет отображаться на вкладках «Видео» и «Модерация» на панели управления Ziggeo. Помимо самого видеофайла, вы увидите дополнительную мета-информацию, такую ​​как ее длина, размер, дата создания, теги и многое другое. Также есть удобный раздел «События», в котором перечислены все события, произошедшие внутри вашего приложения.

Встраивание видео

Используйте тот же тег ziggeo для встраивания видео на страницу. Основным атрибутом является ziggeo-video , принимающее uid видео:

 <ziggeo ziggeo-video='123abc' ziggeo-width="320" ziggeo-height="240"> </ziggeo> 

Более того, видео можно воспроизводить во всплывающем окне. Для этого просто установите аргумент ziggeo-popup :

 <ziggeo ziggeo-video='123abc' ziggeo-width="320" ziggeo-height="240" ziggeo-popup> </ziggeo> 

Существует песочница, где вы можете увидеть загрузку и внедрение в действии, а также протестировать различные параметры конфигурации.

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

Прослушивание событий

Ziggeo предоставляет целую кучу событий Javascript, которые вы можете слушать: play , pause , uploaded и camera_nosignal чтобы назвать несколько. Например, давайте создадим пользовательский индикатор выполнения, показывающий, как идет процесс загрузки видео. Это легко сделать с upload_progress события upload_progress которое постоянно upload_progress о том, сколько байт уже загружено.

Прежде всего, добавьте элемент progress на страницу. Я использую Bootstrap 4 для стилизации, но вы можете использовать любой другой CSS-фреймворк или написать свой собственный стиль:

просмотры / видео / new.html.erb

 <!-- ... --> <progress class="progress progress-striped hidden-xs-up" value="0" max="100"></progress> 

Класс hidden-xs-up будет скрывать этот индикатор на всех экранах. В качестве альтернативы вы можете просто сказать display: none .

Теперь напишите немного кода CoffeeScript:

JavaScripts / videos.coffee

 jQuery(document).on 'turbolinks:load', -> ZiggeoApi.Events.on "upload_progress", ( uploaded, total, data ) -> $('progress').removeClass('hidden-xs-up').attr 'value', (uploaded / total) * 100 

ZiggeoApi — это глобальный объект, доступный для нас после загрузки JS Ziggeo. uploaded и total переменные содержат количество байтов, поэтому их деление и умножение на 100 дает нам процент. Переменная data содержит информацию о загружаемом видео.

Не забудьте включить этот новый файл:

JavaScript / application.js

 //= require videos 

Еще одна вещь, которую мы можем сделать — перенаправить пользователя на корневую страницу после загрузки видео:

JavaScripts / videos.coffee

 ZiggeoApi.Events.on "submitted", ( data ) -> window.location.href = '/' 

Просто, не правда ли?

Также обратите внимание, что Ziggeo предоставляет некоторые вызываемые методы для манипулирования игроком и загрузчиком. Эти методы можно найти в документах .

Запрос API

Итак, теперь видео можно загружать, но мы нигде не показываем их. Чтобы получить список загруженных видео, вы можете использовать драгоценный камень Ziggeo, который мы включили в начале статьи.

Работать с ним очень просто. Вам просто нужно создать экземпляр клиента, передав все три ключа, полученные ранее, и затем вызвать необходимый метод:

videos_controller.rb

 # ... def index ziggeo = Ziggeo.new(ENV['ZIGGEO_KEY'], ENV['ZIGGEO_SECRET'], ENV['ZIGGEO_ENCRYPTION']) @videos = ziggeo.videos.index end 

Метод index принимает такие аргументы, как limit и skip для дальнейшей настройки запроса. В результате переменная @videos будет содержать массив хэшей, каждый из которых хранит uid видео и другую метаинформацию. Этот массив теперь можно отобразить на главной странице:

просмотры / видео / index.html.erb

 <h1>Videos</h1> <%= link_to 'Add video', new_video_path %> <%= render partial: 'video', collection: @videos, as: :video %> 

Обратите внимание, что мы не можем сказать render @videos как это простой массив. Теперь рендер игрока внутри партиала. Видео будет открыто во всплывающем окне:

просмотры / видео / _video.html.erb

 <div class="card"> <div class="card-block"> <ziggeo ziggeo-video='<%= video['token'] %>' ziggeo-width="320" ziggeo-height="240" ziggeo-popup> </ziggeo> </div> 

Поле token содержит уникальный идентификатор видео.

Связывание видео с пользователями

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

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

модели / user.rb

 # ... before_create -> { self.uid = generate_uid } private def generate_uid loop do uid = Digest::MD5.hexdigest(self.email + self.created_at.to_s + rand(10000).to_s) return uid unless User.exists?(uid: uid) end end 

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

Поле uid еще не существует, поэтому создайте соответствующую миграцию сейчас:

 $ rails g migration add_uid_to_users uid:string 

Настройте миграцию, чтобы включить индекс, обеспечивающий уникальность:

дб / мигрирует / xyz_add_uid_to_users.rb

 class AddUidToUsers < ActiveRecord::Migration[5.0] def change add_column :users, :uid, :string add_index :users, :uid, unique: true end end 

Теперь примените миграцию:

 $ rails db:migrate 

Имея этот идентификатор, мы можем установить токен для видео. Это так же просто, как предоставление аргумента ziggeo-tags . Помните, что он принимает строку через запятую:

просмотры / видео / new.html.erb

 <ziggeo ziggeo-limit="60" ziggeo-width="320" ziggeo-height="240" ziggeo-perms="allowupload" ziggeo-tags="<%= current_user.uid %>"></ziggeo> 

Большой! Теперь, чтобы получать только видео текущего пользователя, установите параметр tags для метода index :

videos_controller.rb

 # ... def index ziggeo = Ziggeo.new(ENV['ZIGGEO_KEY'], ENV['ZIGGEO_SECRET'], ENV['ZIGGEO_ENCRYPTION']) @videos = ziggeo.videos.index(tags: current_user.uid) end 

Хорошо, но мы можем сделать лучше. Проблема с API Ziggeo заключается в том, что нет возможности получить только те видео, которые были одобрены модератором. Это странно, но служба поддержки Ziggeo подтвердила эту информацию. Конечно, мы можем отфильтровать утвержденные видео в нашем контроллере с помощью метода keep_if , но если вы захотите использовать механизм разбиения на страницы, все станет довольно сложно. Поэтому, почему бы нам не настроить обратные вызовы сервера и сохранить информацию о видео в нашей собственной базе данных так, как мы считаем нужным? Давайте сделаем это в следующем разделе!

Настройка обратных вызовов

Подготовка и создание видео

Обратные вызовы настраиваются для каждого приложения, поэтому откройте панель управления, выберите приложение и нажмите « Управление»> «Веб-хуки» . Здесь введите URL-адрес (я выберу https://sitepoint-ziggeo.herokuapp.com/api/video_callbacks ) и в раскрывающемся списке выберите «JSON-кодировка». Теперь события будут пересылаться в /api/video_callbacks в форме запроса POST. Вот список всех обратных вызовов, которые вы можете использовать. Обратите внимание, что не все события пересылаются — только самые важные.

Прежде всего, мы хотим отслеживать добавление всех видео, поэтому потребуется новая модель под названием Video . Он будет содержать следующие поля:

  • uid (строка, индексированная, уникальная) — токен видео
  • user_id (integer, indexed) — внешний ключ для установления связи между пользователем и видео
  • duration (десятичное число) — продолжительность видео в секундах
  • ziggeo_created_at (datetime) — дата и время создания видео на Ziggeo
  • approved (логическое, проиндексировано) — одобрено ли модератором видео, по умолчанию установлено значение false

Создайте соответствующую миграцию:

 $ rails g model Video user:belongs_to uid:string duration:decimal ziggeo_created_at:datetime approved:boolean 

Настроить миграцию немного:

дБ / мигрирует / хуг / create_videos.rb

 # ... create_table :videos do |t| t.string :uid t.belongs_to :user, foreign_key: true t.decimal :duration, scale: 2, precision: 5 t.datetime :ziggeo_created_at t.boolean :approved, default: false t.timestamps end add_index :videos, :approved add_index :videos, :uid, unique: true 

Примените это:

 $ rails db:migrate 

Убедитесь, что установлены правильные ассоциации и проверки:

модели / user.rb

 # ... has_many :videos, dependent: :destroy 

модели / video.rb

 # ... belongs_to :user validates :uid, presence: true, uniqueness: true 

Теперь добавьте новое пространство имен маршрутов под :api :

конфиг / routes.rb

 namespace :api do resources :video_callbacks, only: [:create] end 

Создайте новый контроллер в папке api :

Контроллеры / API / video_callbacks_controller.rb

 class Api::VideoCallbacksController < ActionController::Base def create end end 

Когда приходит новое событие, ему event_type параметру event_type какое-то значение. В настоящее время нас будет интересовать событие video_ready . Давайте просто возьмем данные видео и создадим новую запись на его основе:

Контроллеры / API / video_callbacks_controller.rb

 class Api::VideoCallbacksController < ActionController::Base def create type = params['event_type'] respond_to do |format| @result = if type == 'video_ready' Video.from_api(params['data']['video']) end end end end 

Данные видео хранятся под клавишей ['data']['video'] .

Также ответьте кодом состояния 204 (без содержимого), если все в порядке, или кодом 500 (ошибка сервера), если что-то пошло не так:

Контроллеры / API / video_callbacks_controller.rb

 def create type = params['event_type'] respond_to do |format| @result = if type == 'video_ready' Video.from_api(params['data']['video']) end format.html { @result ? head(:no_content) : head(500) } end end 

Теперь from_api метод класса from_api . Он должен выбрать пользователя на основе тега видео (помните, что мы используем UID пользователя в качестве тега) и создать новую запись, которая принадлежит ему:

модели / video.rb

 # ... def self.from_api(data) user = User.find_by(uid: data['tags'][0]) video = user.videos.find_or_initialize_by(uid: data['token']) video.ziggeo_created_at = Time.at(data['created']) video.duration = data['duration'] video.save end 

tags содержат массив, поэтому мы просто берем первый элемент. Я заметил, что иногда событие может быть отправлено дважды, поэтому используйте find_or_initialize_by чтобы избежать создания дублированных записей. Что ж, это будет невозможно, так как набор индексов для uid обеспечивает уникальность, но все же.

Подтверждение видео

Когда видео одобрено или отклонено модератором, также отправляется соответствующее событие. Мы будем работать с video_approve события video_approve . Когда он прибудет, найдите видео в базе данных на основе его токена (uid) и установите для approved атрибута значение true :

Контроллеры / API / video_callbacks_controller.rb

 def create type = params['event_type'] respond_to do |format| @result = if type == 'video_ready' Video.from_api(params['data']['video']) else if type == 'video_approve' video = Video.find_by(uid: params['data']['video']['token']) video.approve! if video else true end end format.html { @result ? head(:no_content) : head(500) } end end 

Мы просто присваиваем true переменной экземпляра @result если событие какого-то другого типа. Вот approve! метод:

модели / video.rb

 # ... def approve! self.approved = true self.save end 

Удаление видео

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

Контроллеры / API / video_callbacks_controller.rb

 # ... def create type = params['event_type'] respond_to do |format| @result = if type == 'video_ready' Video.from_api(params['data']['video']) else if type == 'video_approve' || type == 'video_delete' video = Video.find_by(uid: params['data']['video']['token']) if video type == 'video_approve' ? video.approve! : video.destroy end else true end end format.html { @result ? head(:no_content) : head(500) } end end 

Ницца! Теперь, когда у нас есть эти обратные вызовы, действие index внутри VideosController можно переписать.

Отображение видео и метаинформации

Нам больше не нужен клиент Ziggeo внутри действия index . Вместо этого просто возьмите видео текущего пользователя — только те, которые были одобрены:

videos_controller.rb

 # ... def index @videos = current_user.videos.where(approved: true) end 

Поскольку каждое видео теперь имеет дополнительную мета-информацию, мы можем отображать ее и на главной странице:

просмотры / видео / _video.html.erb

 <div class="card"> <div class="card-block"> <ziggeo ziggeo-video='<%= video.uid %>' ziggeo-width="320" ziggeo-height="240" ziggeo-popup> </ziggeo> <p> <strong>Duration:</strong> <%= video.duration %>s<br> <strong>Created:</strong> <%= video.ziggeo_created_at %> </p> </div> </div> 

Удаление видео через API

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

Сначала представьте ссылку «удалить»:

просмотры / видео / _video.html.erb

 <ziggeo ziggeo-video='<%= video.uid %>' ziggeo-width="320" ziggeo-height="240" ziggeo-popup> </ziggeo> <!-- ... --> <p><%= link_to 'Delete', video_path(video.uid), method: :delete %></p> 

Обратите внимание, что я передаю uid видео, а не id — на самом деле мы не будем удалять видео из базы данных внутри действия destroy .

Чтобы удалить видео, нужен клиент Ziggeo API. Удаление выполняется с использованием метода delete который принимает uid.

videos_controller.rb

 # ... def destroy video = current_user.videos.find_by(uid: params[:id]) if video ziggeo = Ziggeo.new(ENV['ZIGGEO_KEY'], ENV['ZIGGEO_SECRET'], ENV['ZIGGEO_ENCRYPTION']) ziggeo.videos.delete(video.uid) flash[:success] = 'Video removed! It may take some time to reflect changes on the website.' else flash[:warning] = 'Cannot find such video...' end redirect_to root_path end 

Мы только удаляем видео из Ziggeo. После завершения этой операции событие video_delete будет отправлено нашему video_delete вызову, и соответствующая запись будет удалена из базы данных. Этот процесс не мгновенный, поэтому мы предупреждаем пользователя, что для отражения изменений может потребоваться некоторое время.

Вывод

Мы достигли конца этой статьи! Ziggeo предоставляет гораздо больше функциональности, чем мы видели сегодня, поскольку обсуждали только его основные функции. Поэтому обязательно прочитайте больше об этой услуге и попробуйте сами. Также обратите внимание, что Ziggeo доступен как дополнение Heroku и может быть интегрирован с такими популярными сервисами, как YouTube и Dropbox.

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