かくすけのいろいろ作るブログ

かくすけの開発者ブログです。開発の他いろいろなモノづくりについて書きます。

【Ruby】Youtube API を使って自分の動画のうち一つをランダムに取得する

Rubyバージョン 2.6

こんにちは。かくすけです。
順調にかくすけWebページを作っているわけですが
今回はそれとは別に、簡単に作れて簡単にみなさまに公開できるものを作りたいと思います。
(何か初めてのことをしたかった)

ということで 「TwitterYoutubeの動画をランダムでツイートするBotを作ってみたいと思います。
このBot開発では
AWS Lambda
Twitter API
Youtube API
を使う予定です。初めての挑戦ばかりで楽しみ!

その第一歩として、今回はRubyYoutubeの動画一覧を取得するときのメモを残していきます。

手順

今回は次の手順でランダムな動画を取得します。
 (1)Googleへのログイン
 (2)Youtubeから再生リスト一覧を取得
 (3)1つの再生リストから動画情報一覧を取得
細かく説明していきます。

Google使用設定

YoutubeAPIを使って動画一覧を取得するわけですが、それを使うためにはまずGoogleログインの仕組みを作らなければなりません。
正しくはログインしなくても良いのですが、ログインしない場合1日に使える回数に制限があります。 開発時は何度も試してみたいのでログインしないと厳しいのです。

このGoogleログイン手順は次のページを参考にさせていただきました。
YoutubeではなくGoogle APIの使用方法の記事ですが、Google認証部分が参考になりました!ありがとうございます。

AWS LambdaからGoogle APIを呼び出す - Sanwa Systems Tech Blog

こちらのページの通り、一度ブラウザ上で認証し、API使用の許可設定をしないといけないんですよね~

ちょっと参考にさせていただいたページと画面構成が違ったので違った部分まで手順書きますね。
Google Developers Consoleにログインします。
Googleのページなのでいつの間にか画面構成など変わるかもしれません。
サイドバーにある「認証情報」を選択

f:id:kakusuke98:20190421133449p:plain

上の方にある「project」という文字またはすでに作ってるプロジェクト名をクリック
(私の場合はすでに作っていたので初期の状態を知りません。「project」じゃないかも)

f:id:kakusuke98:20190421133930p:plain

表示されたモーダル右上の「新しいプロジェクト」を選択

f:id:kakusuke98:20190421134208p:plain

プロジェクト作成画面に遷移します。 プロジェクト名を設定して「作成」を押します。

f:id:kakusuke98:20190421134315p:plain

プロジェクト作成中の表示がしばらく右上に表示されるので待ちます。
作成が完了したら

f:id:kakusuke98:20190421134558p:plain

ここで作成したプロジェクトを選択します。
すると、「認証情報を作成してね」という表示がされますので
「認証情報を作成」のプルダウンから「OAuth クライアントID」を選択します。

f:id:kakusuke98:20190421134705p:plain

注意されてしまいました。画面に従って同意画面を設定しましょう。

f:id:kakusuke98:20190421134949p:plain

ここからは参考にさせていただいたページと同じです!(手抜きといわないでください!)

AWS LambdaからGoogle APIを呼び出す - Sanwa Systems Tech Blog

「OAuth2.0のおさらい」の項目から「access token更新」までを行うのですが、「初回認証」の項目はちょっと変えます。

https://accounts.google.com/o/oauth2/v2/auth
  ?scope=https://www.googleapis.com/auth/gmail.readonly%20https://www.googleapis.com/auth/gmail.labels
  &redirect_uri=urn:ietf:wg:oauth:2.0:oob
  &response_type=code
  &client_id=999999999999-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com

とあるのですが、scopeの部分を変えます。以下のYoutube APIの説明ページをみます。

developers.google.com

f:id:kakusuke98:20190421140210p:plain

スコープスの表がありますね。 現在は4種類スコープが準備されているようですが、私は動画情報の読み込みだけをする予定なので
https://www.googleapis.com/auth/youtube.readonly」の読み込みだけでオッケーです。
つまり

https://accounts.google.com/o/oauth2/v2/auth
  ?scope=https://www.googleapis.com/auth/youtube.readonly
  &redirect_uri=urn:ietf:wg:oauth:2.0:oob
  &response_type=code
  &client_id=999999999999-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com

こうですね!

Youtubeから動画情報を取得する

Youtube API リファレンスを見ながらコードを書いていきます。

API Reference  |  YouTube Data API (v3)  |  Google Developers

今回は自分のチャンネルのランダムな動画1つを取得したいわけですが、 「ランダムな動画を取得する」ためのAPIは準備されていません。

ですので、ここでは
 (2)Youtubeから再生リスト一覧を取得
 (3)1つの再生リストから動画情報一覧を取得
という手順を踏んで動画1つを取得します。 'rest-api'というRubyのgemを使ってAPIを使用します。

まずコード全体

#!/usr/local/src/rbenv/shims/ruby
require 'rest-client'
require 'json'

def tweet_random_video
  # Google認証(トークンは有効期限があるため、使用直前に更新取得する)
  RestClient.post("https://accounts.google.com/o/oauth2/token?client_id=#{Googleの認証で取得したclient_id}&client_secret=#{Googleの認証で取得したclient_secret}&refresh_token=#{Googleの認証で取得したreflesh_token}&grant_type=refresh_token", {}) { |response, request, result|
    case response.code
    when 200..299
      response_hash = JSON.parse(response)

      # 取得したアクセストークンを保持
      @access_token = response_hash['access_token']

      # Youtubeから再生リスト一覧を取得
      # ランダムでプレイリストのIDを一つ取得する
      playlist_ids = get_playlists
      return false if playlist_ids == false
      playlist_id = playlist_ids.to_a.sample

      # 取得したプレイリスト内の動画一覧を取得する
      # ランダムで動画のIDを一つ取得する
      videos = get_list_contents(playlist_id)
      return false if videos == false
      video = videos.to_a.sample

      p "ランダムな動画の情報を取得しました。#{video}"
    else
      p "Google認証に失敗しました。レスポンス:#{response}"
    end
  }
end

#--------------------------------------------
# 再生リストの一覧を返す
# 戻り値:再生リストのID一覧を格納した配列
#--------------------------------------------
def get_playlists
  next_page_flag = true
  nextPageToken = ''
  playlist_ids = []
  url = "https://www.googleapis.com/youtube/v3/playlists?part=id&mine=true&maxResults=50"

  # 全ページ分繰り返す
  while next_page_flag do
    url = "#{url}&pageToken=#{nextPageToken}" if nextPageToken != ''
    RestClient.get(url, {:Authorization => "Bearer #{@access_token}"}) { |response, request, result, &block|
      case response.code
      when 200..299
        response_hash = JSON.parse(response)
        if response_hash.has_key?('nextPageToken')
          nextPageToken = response_hash['nextPageToken']  # 次ページ取得用トークン
        else
          next_page_flag = false
        end
        # プレイリストのIDを配列に入れていく
        response_hash['items'].each do |item|
          playlist_ids << item['id']
        end
      else
        p "再生リスト一覧の取得に失敗しました。レスポンス:#{response}"
        return false
      end
    }
  end
  return playlist_ids
end


#--------------------------------------------
# 再生リスト内の動画一覧を取得し、動画情報の配列を返す
# 引数:
#   playlist_id: 動画一覧を取得する再生リストのID
# 戻り値:取得した動画一覧の情報を格納した配列
#--------------------------------------------
def get_list_contents(playlist_id)
  next_page_flag = true
  nextPageToken = ''
  videos = []
  url = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&mine=true&maxResults=50&playlistId=#{playlist_id}"

  # 全ページ分繰り返す
  while next_page_flag do
    url = "#{url}&pageToken=#{nextPageToken}" if nextPageToken != ''
    RestClient.get(url, {:Authorization => "Bearer #{@access_token}"}) { |response, request, result, &block|
      case response.code
      when 200..299
        response_hash = JSON.parse(response)
        if response_hash.has_key?('nextPageToken')
          nextPageToken = response_hash['nextPageToken']  # 次ページ取得用トークン
        else
          next_page_flag = false
        end
        # 動画のIDを配列に入れていく
        response_hash['items'].each do |item|
          videos << {video_id: item['snippet']['resourceId']['videoId'],
                    title: item['snippet']['title']}
        end
      else
        p "動画一覧の取得に失敗しました。レスポンス:#{response}"
        return false
      end
    }
  end
  return videos
end

#--------------------------------------------
# Twitterにログインし、ツイートする(予定)
#--------------------------------------------

tweet_random_video

いつもRailsばっかりでRuby単体で使うことなんてないのでメソッド構成とか正直自信ありません。
内容はコメントに書いている通りなのですが
Google認証用トークン取得
・再生リストの一覧を取得
・再生リストから1つのリストを選択
・再生リスト内動画の情報一覧を取得
・動画情報一覧から1つを選んで画面に表示
という手順で動きます。

Youtube APIで再生リスト一覧や動画一覧を取得する場合、1度に50件までしか取れません。
50件とったら次の50件をとるための"nextPageToken"という情報が受け取れるので
"nextPageToken"を使ってまた次のページの一覧を取得する。という方法をとる必要があります。

また、再生リスト内動画の一覧をとるときに"part=snippet"を指定することで動画のタイトルなどの詳細情報を取得しています。
ここで取得した情報を使ってYoutube公式での動画視聴用のURLが生成できるはずです。

その他は特に珍しいことはしていません!
一般的なAPIの使い方だと思います。
もし需要があればもうちょっと詳しく書いてみたいと思います。

次回はTwitterAPI使用部分を進めます!
実はそこまで一日でやってしまいたいと思っていたのですが、TwitterってAPI使うために申請が必要なんだそうで・・・
現在申請中です。

参考:
Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ ※2018年9月時点の情報 - Qiita

Twitterって厳しいんですね。
確かに悪用などには使われそうなイメージはありますね。

しばらくは待ちになってしまいますが、ゴールデンウィーク中には完成させたいところです!!