Coub API Tutorial

  • Tutorial
The other day we released the Coub API . Now you can make applications, watch a tape, like, rebob, that is, almost everything that can be done on the site can be done through the API. But most importantly - now you can create cobs from third-party applications through the API

In this tutorial, I will show you how to make the simplest Coba client on Ruby on Rails. The application allows you to log in through the cob and generate such a cob with any text:



The working version of this application is located at fantozzi.dev2.workisfun.ru , the application code from this tutorial can be viewed on Github: github.com/igorgladkoborodov/memegenerator

OAuth


Kob uses the standard protocol for authorizing OAuth 2.0 . It is used in so many services that provide an external API (Facebook, for example), there are a lot of documentation and libraries for any platform on it.

Authorization works something like this: the application with its unique key goes to a special page on coub.com, where Kob asks if the user agrees to give the application access. If the user permits, then Kob returns the user back to the application, and gives the user token along with the request, which is then used for all user API requests. The same thing happens, for example, when logging in via Facebook or Twitter.

We will write on RoR and for authorization through OAuth for rails everything has been written for a long time, we will use the omniauth-oauth2 gem and the official conia omniauth-coub gem for this .

Application creation and authorization


We create an application with the eloquent name memegenerator and fasten it to Pow (or who uses what):

$ cd ~/apps/
$ rails new memegenerator
$ ln -s ~/apps/memegenerator/ ~/.pow/memegenerator

We check in the browser that we have an empty rail application at memegenerator.dev .

2. Register our new application at coub.com/dev/applications.



In the Website field, indicate the URL of our test application, in the Callback URL field, write
http://memegenerator.dev/auth/coub/callback


After creating the application, Cob will give us the Application ID and Secret, we will need them further:



3. Install the omniauth-coub:

Gemfile gem:
gem "omniauth-coub"

$ bundle install

4. Add the cob to the omniauth providers:

config / initializers / omniauth.rb:
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :coub, ENV["COUB_KEY"], ENV["COUB_SECRET"], scope: "logged_in,create"
end

COUB_KEY and COUB_SECRET are the Application ID and Secret from the last step, you can add them to ENV variables or insert lines right here for the test, although leaving the keys in the code is undesirable, you know.

If you have Pow, you can add variables in the .powenv file in the application root:

.powenv:
export COUB_KEY="[Application ID]"
export COUB_SECRET="[Secret]"

In scope you can specify what rights the application will have. Our application is only needed to create cobs, so we won’t ask for anything extra, only permission to authorize and create cobs: logged_in, create. The full list of access modes can be found in the API documentation .

5. Create a user model with the from_omniauth method, which creates or finds in the user database according to the data that the authorization server on Kobe passed to us.

What happens at this point and in a couple of the following points is well explained in one of the RailsCasts episodes .

$ rails g model user provider:string uid:string auth_token:string name:string
$ rake db:migrate

app / models / user.rb:
class User < ActiveRecord::Base
  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap do |user|
      user.auth_token = auth.credentials.token
      user.name = auth.extra.raw_info.name
      user.save!
    end
  end
end

6. Create a session controller. Through it we create and delete a session.

The create method is where the user returns with his token and authorization data. Here we create the user through the from_omniauth method, which we wrote in the last step, and save his token, write it to the cookie, so that when the browser restarts, this session can be returned.

$ rails g controller sessions

app / controllers / sessions_controller.rb:
class SessionsController < ApplicationController
  def create
    user = User.from_omniauth(env["omniauth.auth"])
    cookies.permanent[:auth_token] = user.auth_token
    redirect_to root_url
  end
  def destroy
    cookies.delete(:auth_token)
    redirect_to root_url
  end
  def index
  end
end

Let the application muzzle live in the session controller, so the index method is here.

7. To have access to the current user, we add the current_user method to the ApplicationController, which searches for the user in the database if we have a cookie with its token.

app / controllers / application_controller.rb:
helper_method :current_user
def current_user
  @current_user ||= User.find_by_auth_token(cookies[:auth_token]) if cookies[:auth_token]
end

8. We display on the face a link to the login or show the current user with a link to the exit.

app / views / sessions / index.html.erb:
<% if current_user %>
  <%= current_user.name %>
  <%= link_to "Log out", logout_path, method: :delete %>
<% else %>
  <%= link_to "Auth with Coub", "/auth/coub" %>
<% end %>

On the path / auth / coub, the omniauth-oauth2 gem will redirect to the authorization page on coub.com.

9. We register routes:

config / routes.rb:
Rails.application.routes.draw do
  root "sessions#index"
  get "/auth/:provider/callback" => "sessions#create"
  delete "logout" => "sessions#destroy"
end

Everything with authorization. We go to memegenerator.dev , check. It should look something like this:



Now in our database there is a user with a token that can make requests through the Coub API.

API Requests


Having a token, you can make requests to the API. These are regular HTTP requests, as in a browser. GET requests can also be tested in the browser. Each request, in addition to its parameters, must contain the access_token parameter with the user token that the authorization server gave us before.

For example, to like a cob, you need to execute something like this:
POST http://coub.com/api/v2/likes?id=[coub_id]&channel_id=[channel_id]&access_token=[users_token]

Some requests can be made without a token, for example, infa about a coba (only public cobs are available without a token). This is a GET request, this link can be opened simply in the browser:
GET http://coub.com/api/v2/coubs/4yp6r

All these requests are well documented, a complete list can be found here: coub.com/dev/docs/Coub+API/Overview

Client


Each time, manually making requests and adding a token is inconvenient, so we add the Client model to the client method through which we will make requests:

app / models / user.rb:
def client
  @client ||= Faraday.new(:url => "http://coub.com/api/v2/", :params => {:access_token => auth_token})
end

Gemfile:
gem "faraday"

$ bundle install

We make requests through Faraday, this is an Ruby HTTP client.

Run the console, test the requests for api:

$ rails c
> user = User.first
> user.client.get "coubs/4yp6r"

Answers are given in JSON format, so if we want to read what the server returned, we need to parse the response with the standard JSON library:

> coub_info = JSON.parse(user.client.get("coubs/4yp6r").body)
> coub_info["id"]
=> 9090841

We have the Cob ID, let's like it:

> user.client.post "likes?id=#{coub_info["id"]}"


We generate video


We have a video, a shot from the movie, we need to put text on it three times at different times. To work with video through the console, there is the ffmpeg program, in it through the console you can do almost anything with the video.

On a poppy via Homebrew, it is set like this:

$ brew install ffmpeg --with-freetype

We overlay the text through ffmpeg with the drawtext filter:

$ ffmpeg -i template.mp4 -vf "drawtext=enable='between(t,1,2)':text=Blah:fontfile=PFDinTextCondPro-XBlack.ttf:fontsize=40:fontcolor=white:x=(w-tw)/2:y=(h*0.9-th)" output.mp4


This line means:

1. ffmpeg -i template.mp4 -vf : take the video file template.mp4. The file for this tutorial can be downloaded here .

2. drawtext = enable : overlay text

3. between (t, 1,2) : first to second second

4. fontfile = PFDinTextCondPro-XBlack.ttf : use a file with a font in TTF format

5. text = Blah : write the text Blah

6. fontsize = 40 : font size

7. fontcolor = white : white

8. x = (w-tw) / 2: y = (h * 0.9-th): the position of the text in the center at the bottom (w and h is the size of the video, tw and th is the size of the block with text)

9. output.mp4 : write everything to this file

To write three texts, you just need to write three drawtext separated by a comma:

$ ffmpeg -i template.mp4 -vf "drawtext=enable='between(t,1,2)':text=Text1:fontfile=PFDinTextCondPro-XBlack.ttf:fontsize=40:fontcolor=white:x=(w-tw)/2:y=(h*0.9-th), drawtext=enable='between(t,3,5)':text=Text2:fontfile=PFDinTextCondPro-XBlack.ttf:fontsize=40:fontcolor=white:x=(w-tw)/2:y=(h*0.9-th), drawtext=enable='between(t,6.3,8)':text=Text3:fontfile=PFDinTextCondPro-XBlack.ttf:fontsize=40:fontcolor=white:x=(w-tw)/2:y=(h*0.9-th)" output.mp4

In the tempo folder, you can add the template.mp4 file and the font file (you can take any TTF from the font folder) and try to run it in the console, it should generate the correct video.

Download video


We have a video, now we need to make a cob from it.

Cob is downloaded through the API in three stages:

1. First, we initialize the download with the POST request coubs / init_upload, in the response we get the id of the cob and its permalink.
$ rails c
> user = User.first
> init_response = JSON.parse(user.client.post("coubs/init_upload").body)
> coub_id = init_response["id"]
> permalink = init_response["permalink"]

2. Download the video with the POST request coubs /: id / upload_video. The file is transmitted in the request body, in the Content-Type header you need to transfer video / mp4:

> user.client.post do |r|
   r.url "coubs/#{coub_id}/upload_video"
   r.headers["Content-Type"] = "video/mp4"
   r.body = File.open("tmp/output.mp4", "r").read
 end

If we want to download a separate soundtrack to a cob, then this can be done with a separate request coubs /: id / upload_audio. This time we do not need this, so we omit this request.

3. Finalize the creation of the cob by the POST request coubs /: id / finalize_upload, in the parameters we transfer the title, privacy settings, tags, whether the sound is turned on.

> user.client.post "coubs/#{coub_id}/finalize_upload", title: "Test coub", original_visibility_type: "private", tags: "tag1, tag2, tag3", sound_enabled: true

After downloading Koba, it will take some time to process: the video on Koba's servers will be converted to several formats for different platforms, previews and a bunch of all kinds of such resource-intensive things will be generated. Conversion progress can be checked by GET request coubs /: id / finalize_status. It gives something like this JSON {percent_done: 20, done: false}.

> user.client.get "coubs/#{coub_id}/finalize_status"

OK. We tested it in the console, now all this needs to be collected in the application.

Coub Model


Create a Coub Model:

$ rails g model coub user:belongs_to title:string visibility_type:string tags:string permalink:string coub_id:string text1:string text2:string text3:string
$ rake db:migrate

2. We make the generate_video_file method, which drives the video from the video template and the three texts in the text1, text2, text3 fields. We put the video template and font in the assets. We put the finished video in the tmp folder.

app / models / coub.rb:
def escape_ffmpeg_text(text)
  text.to_s.gsub("'", "\\\\\\\\\\\\\\\\\\\\\\\\'").gsub(":", "\\\\\\\\\\\\\\\\:").mb_chars.upcase # Crazy ffmpeg escaping
end
def ffmpeg_drawtext(text, from, to)
  font_file = File.join(Rails.root, "app", "assets", "fonts", "PFDinTextCondPro-XBlack.ttf")
  "drawtext=enable='between(t,#{from},#{to})':text=#{escape_ffmpeg_text(text)}:fontfile=#{font_file}:fontsize=40:fontcolor=white:x=(w-tw)/2:y=(h*0.9-th)"
end
def generate_video_file
  self.video_file = File.join(Rails.root, "tmp", "output-#{Time.now.to_i}.mp4")
  template_file = File.join(Rails.root, "app", "assets", "videos", "template.mp4")
  `ffmpeg -i #{template_file} -vf \"#{ffmpeg_drawtext(text1, 1, 2)}, #{ffmpeg_drawtext(text2, 3, 5)}, #{ffmpeg_drawtext(text3, 6.3, 8)}\" #{video_file}`
  return video_file
end

3. We make a method that uploads video to Cob in three stages:

app / models / coub.rb:
def upload_video
  self.title ||= text2
  self.visibility_type ||= "private"
  self.tags ||= ""
  init_response = JSON.parse(client.post("coubs/init_upload").body)
  self.coub_id = init_response["id"]
  self.permalink = init_response["permalink"]
  save
  client.post do |r|
    r.url "coubs/#{coub_id}/upload_video"
    r.headers["Content-Type"] = "video/mp4"
    r.body = File.open(video_file, "r").read
  end
  client.post "coubs/#{coub_id}/finalize_upload",
    title: title,
    original_visibility_type: visibility_type,
    tags: tags,
    sound_enabled: true
end
def generate_and_upload_video
  generate_video_file
  upload_video
end

4. We write that the cob belongs to the user and at the same time we write the client method for convenient access to the client through the user:

app / models / coub.rb:
belongs_to :user
def client
  @client ||= user.client
end

5. The url method returns the url of the cob by permalink:

app / models / coub.rb:
def url
  "http://coub.com/view/#{permalink}"
end

Check if everything works:

$ rails c
> coub = Coub.new
> coub.user = User.first
> coub.text1 = 'Text 1'
> coub.text2 = 'Text 2'
> coub.text3 = 'Text 3'
> coub.tags = 'tag1, tag2, tag3'
> coub.visibility_type = 'unlisted'
> coub.generate_and_upload_video
> coub.url
=> "http://coub.com/view/5dbyc"

You can go to this url and look at the blue screen “Your coub is being processed”.

It remains to make a controller for all this:

1. Create a coubs controller. It will consist of two methods: index (this will be a new face, instead of sessions # index) and create. When creating a coba, we immediately redirect to it.

$ rails g controller coubs

app / controllers / coubs_controller.rb:
class CoubsController < ApplicationController
  def index
  end
  def create
    @coub = Coub.create(coub_params.merge(:user => current_user))
    @coub.generate_and_upload_video
    redirect_to @coub.url
  end
private
  def coub_params
    params.require(:coub).permit(:text1, :text2, :text3, :visibility_type, :tags)
  end
end

2. Drag index.html.erb from sessions to coubs and fasten the form there:

app / views / coubs / index.html.erb:
<% if current_user %>
  

You’re logged in as <%= current_user.name %>. <%= link_to "Log out", logout_path, method: :delete %>

<%= form_for Coub.new, url: {action: "create"} do |f| %> <%= f.text_field :text1, placeholder: "To me", maxlength: 30, size: 50 %>
<%= f.text_field :text2, placeholder: "Your Coub API", maxlength: 30, size: 50 %>
<%= f.text_field :text3, placeholder: "Is a piece of shit", maxlength: 30, size: 50 %>
<%= f.select :visibility_type, options_for_select(["public", "friends", "unlisted", "private"]) %>
<%= f.text_field :tags, placeholder: "first tag, second tag" %>
<%= f.submit "Create Coub" %> <% end %> <% else %>

Please log in via Coub.

<% end %>

That's it, now we go into the browser, and check that everything works:


In this tutorial, I described only how the API works. Of course, for this application, there is still much to add: validations, checking API responses, error handling, draw an interface, tests. A slightly doped version of this script lies here http://fantozzi.dev2.workisfun.ru , everything is the same there, but the video is prepared and downloaded asynchronously through delayed_job.

The sources of this tutorial are in the github: https://github.com/igorgladkoborodov/memegenerator/ .

If you have any questions about this tutorial or API, write to igor@coub.com .

Also popular now: