【Rails × YouTube】YouTubeのチャンネル情報を取得する方法

# はじめに
### 本記事ですること
Webアプリを個人開発していて、YouTubeのチャンネル情報を表示したいと思いました。
本記事では、YouTubeが提供しているAPIを利用して下記情報を取得・表示します。

　・ チャンネル登録者数
　・ 投稿動画数
　・ 最新動画
　・ 最新動画のタイトル

なお、実際の開発経験に基づきますので、非効率なコードや網羅的な説明でないことご容赦ください。
また、railsアプリがある状態を前提とします。

### ながれ
大きく以下の流れで進めていきます。

　1.　準備
　2.　使用

# 1.　準備
### 1-1.　プロジェクトの作成
YouTube（Google）のAPI利用には`プロジェクト`が必要です。
下記サイトにアクセスします。

[Google Cloud > APIとサービス](https://console.cloud.google.com/projectselector2/apis/dashboard?hl=ja&pli=1&supportedpurview=project)

利用規約への同意画面が表示された場合は同意します。

上に表示の「$300相当の〜」は、スルーして良いです。
初めての場合はプロジェクトがまだ無く、プロジェクトを選択するよう表示されています。
右に「プロジェクトを作成」とありますのでクリックします。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621619/a8143de5-a191-220c-8970-7bdd4f0149df.png)
<br>


任意のプロジェクト名を入力し、必要であればIDも編集ボタンより入力します。
「場所」はファイルを入れるフォルダのようにプロジェクトを分類するためのものなので、初めての場合はデフォルトの「組織なし」で問題ありません。
作成ボタンを押してプロジェクトを作成します。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621619/6f021c16-f15c-a1f5-fe13-b6a548f82697.png)
<br>

下画像のようになればプロジェクト作成は完了です。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621619/b5e06b2a-22d1-da9e-0e7b-8e7045f34c20.png)

### 1-2.　APIキーの取得
APIを利用するためにはプロジェクト作成の上、`APIキー`というものの取得が必要です。
左サイドバーより「認証情報」に移動します。

OAuth同意画面構成は、ユーザのプライベートデータに触れるアプリの場合は実施します。
今回はYouTubeで誰もが確認可能なパブリックデータを取得するので不要とします。

APIキーはまだありません。
上の「認証情報を作成」　→　「APIキー」と選択してAPIキーを作成します。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621619/9e911068-2a33-7f4e-8aca-2169721ce5a2.png)
<br>

APIキーの名前をクリックすると、キーの確認や名前変更が出来ます。
制限については省略しますが、個人開発規模のアプリでは不要と感じたためデフォルトのままにしています。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621619/4295db47-62aa-f9dc-1890-ab7ba6e4e07b.png)

### 1−3.　APIの有効化
YouTubeには複数のAPIがあり、今回取得する情報は`YouTube Data API v3`で可能です。

https://developers.google.com/youtube/v3?hl=ja

このAPIでは、チャンネル情報の取得や特定キーワードに合致する動画の検索等、あると便利なイメージしやすい機能を利用可能です。
このAPIはAPIキー取得時点ではまだ利用不可で、有効化してプロジェクトへの取り込みが必要です。

左サイドバーより「ライブラリ」に移動します。
検索欄より「youtube」等で検索またはページ下部にスクロールするとYouTube Data API v3があります。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621619/95edced0-6a89-9beb-9ceb-a9ef9baad25d.png)
<br>

有効ボタンをクリックして有効化します。
左サイドバーより「有効なAPIとサービス」に戻り、YouTube Data API v3が表示されていれば完了です。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621619/866bf356-c6c3-df55-9961-5b11ea34f2db.png)
<br>

コンソールで行う作業は以上です。

### 1-4.　環境変数の設定
ここからエディタに移り、各種ファイルにて作業をします。

先ほど取得したAPIキーを環境変数に保存します。
gemの`dotenv-rails`を導入すると管理が楽になるのでおすすめで、本記事ではこちらを使用します。
詳細は下記事をご覧ください。

https://qiita.com/__Wata16__/items/d2d3aa21623f8c026d5d



```plaintext:.env
GOOGLE_API_KEY = "***************************************"
```
dotenv-railsを使用する場合、.envの.gitignoreへの記載を忘れないようお気をつけください。

### 1-5.　gemの導入
Google（YouTube） APIの機能を利用するためには、`google-api-client`というgemの導入も必要です。

https://github.com/googleapis/google-api-ruby-client

```ruby:Gemfile
gem 'google-api-client'
```

```terminal:ターミナル
$ bundle install
```

# 2.　使用
### 2-1.　Controller

```ruby:Controller
require 'google/apis/youtube_v3'
youtube = Google::Apis::YoutubeV3::YouTubeService.new
youtube.key = ENV['GOOGLE_API_KEY']

url = DBに保存しているYouTubeのURL

if url.include?("@")
  youtube_handle = url[url.index("@")..-1]
  youtube_id = Rails.cache.fetch("youtube_handle_to_id_#{youtube_handle}", expires_in: 12.hours) do
    youtube_handle_to_id = youtube.list_searches("snippet", q: youtube_handle, type: "channel", max_results: 1).to_h
    youtube_handle_to_id[:items][0][:id][:channel_id]
  end
elsif url.include?("/UC")
  youtube_id = url[url.index("/UC")+1..-1]
end

@youtube_channel = Rails.cache.fetch("youtube_channel_#{youtube_id}", expires_in: 12.hours) do
  youtube.list_channels("statistics", id: youtube_id).to_h
end
@youtube_video = Rails.cache.fetch("youtube_video_#{youtube_id}", expires_in: 12.hours) do
  youtube.list_searches("snippet", channel_id: youtube_id, type: 'video', max_results: 1, order: :date).to_h
end
```
<br>
順番に見ていきます。

***
```ruby
require 'google/apis/youtube_v3'
youtube = Google::Apis::YoutubeV3::YouTubeService.new
youtube.key = ENV['GOOGLE_API_KEY']
```

<INS>require 'google/apis/youtube_v3'</INS>
　→　YouTube Data API v3を使用するためのライブラリの呼び出し

<INS>youtube = Google::Apis::YoutubeV3::YouTubeService.new</INS>
　→　YouTubeServiceクラスよりインスタンスの作成
 
<INS>youtube.key = ENV['GOOGLE_API_KEY']</INS>
　→　先ほど設定した環境変数の使用

***

```ruby
if url.include?("@")
  youtube_handle = url[url.index("@")..-1]
  youtube_id = Rails.cache.fetch("youtube_handle_to_id_#{youtube_handle}", expires_in: 12.hours) do
    youtube_handle_to_id = youtube.list_searches("snippet", q: youtube_handle, type: "channel", max_results: 1).to_h
    youtube_handle_to_id[:items][0][:id][:channel_id]
  end
elsif url.include?("/UC")
  youtube_id = url[url.index("/UC")+1..-1]
end
```

DBに保存されるチャンネルURLは下記の2つを想定しています。

　・ https://<foo>www</foo>.youtube.com/<font color="blue">**@ハンドル**</font>
　・ https://<foo>www</foo>.youtube.com/<font color="blue">**channel/チャンネルID**</font>

<details>
<summary>補足</summary>
URLは他にも複数の形式があるため、逆にこの形以外（@ハンドル?si=〜 等）で登録した場合は、上記処理が正常に行われないので別途考慮しなければいけませんが、今日ではハンドルかチャンネルIDを用いたURLが多いとは思っています。<br>
また、URLの登録である理由は、YouTubeだけではなく他配信サイトも登録出来るようにしているので、便宜上この形としています。
</details>

if文で上記2種類のURLにより分岐させています。
チャンネル情報はIDを用いて取得するため、ハンドルの場合はIDに変換しています。
IDは公式からの名言はありませんが、「**UC**」から始まるようです。

https://support.google.com/youtube/community-guide/266478726/youtube%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%ABurl%E3%81%AE%E4%BB%95%E6%A7%98%E3%81%A8%E4%BD%BF%E3%81%84%E6%96%B9%E3%80%81%E6%B3%A8%E6%84%8F%E7%82%B9?hl=ja

<INS>youtube_handle = url[url.index("@")..-1]</INS>
　→　URLから@を含むハンドルの抽出
 
<INS>youtube_id = Rails.cache.fetch("youtube_handle_to_id_#{youtube_handle}", expires_in: 12.hours)</INS>
　→　キーに一致するデータのキャッシュからの読み込み
APIは使用量が`10,000/日`と上限がありますので、規定に達すると使用不可になります。

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621619/ec3df13a-00a2-bde8-b08d-c72027c20f10.png)


また、処理の内容により消費するコストが決まっています。

https://developers.google.com/youtube/v3/getting-started?hl=ja#quota

そのため、使用量を節約するために2度目以降はキャッシュを使用すると良いです。
初めてのAPI使用やキャッシュの有効期限が切れていた場合はdo~end間を実行します。
 
<INS>youtube_handle_to_id = youtube.list_searches("snippet", q: youtube_handle, type: "channel", max_results: 1).to_h</INS>
　→　抽出したハンドルでそのチャンネルの検索
先ほど作成したインスタンスyoutubeは`list_searches`メソッドが使用可能で、ワードを指定した動画やチャンネルの検索が可能です。
詳細は公式ドキュメントをご確認ください。

https://developers.google.com/youtube/v3/docs/search/list?hl=ja

**[snippet](https://developers.google.com/youtube/v3/docs/search/list?hl=ja#:~:text=part,%E8%A8%AD%E5%AE%9A%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)**　：　必須のパラメータで、以降はオプションです。
**[q](https://developers.google.com/youtube/v3/docs/search/list?hl=ja#:~:text=01T00%3A00%3A00Z%EF%BC%89%E3%80%82-,q,%E3%81%BE%E3%81%99%E3%80%82%E3%83%91%E3%82%A4%E3%83%97%E6%96%87%E5%AD%97%E3%81%AE%20URL%20%E3%82%A8%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%97%E5%80%A4%E3%81%AF%20%257C%20%E3%81%A7%E3%81%99%E3%80%82,-regionCode)**　：　検索キーワードで、ここではハンドルを指定します。
**[type](https://developers.google.com/youtube/v3/docs/search/list?hl=ja#:~:text=%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B-,type,video,-videoCaption)**　：　取得する情報の種類で、ここではIDが知りたいのでchannelを指定します。
**[max_results](https://developers.google.com/youtube/v3/docs/search/list?hl=ja#:~:text=maxResults,%E3%81%AF%205%20%E3%81%A7%E3%81%99%E3%80%82)**　：　取得する情報の数です。
<br>

実行すると下記のような結果が得られ、チャンネルIDもあることが分かります。
```terminal:ターミナル
> youtube.list_searches("snippet", q: youtube_handle, type: "channel", max_results: 1).to_h

=> {:etag=>"0jBSw_0JOto5IIhcY8TSfjK-mFA",
 :items=>
  [{:etag=>"DrC58O-Ujaksetrc6lefVdPppFM",
    :id=>{:channel_id=>"UC4YaOt1yT-ZeyB0OmxHgolA", :kind=>"youtube#channel"},
    :kind=>"youtube#searchResult",
    :snippet=>
     {:channel_id=>"UC4YaOt1yT-ZeyB0OmxHgolA",
      :channel_title=>"A.I.Channel",
      :description=>"\"Mumble, mumble...Stay connected, I'm here with you.\" メンバーシップに関しましては、過去のメンバーシップ限定コンテンツを ...",
      :live_broadcast_content=>"none",
      :published_at=>"2016-10-19T06:03:24Z",
      :thumbnails=>
       {:default=>{:url=>"https://yt3.ggpht.com/tGIJZoN26oD-M5HXGGMC8MizD0iDFdzeaIygX3ArOxSZeJxsRt1IYDrwQgDW5fB9NRAse11-Zg=s88-c-k-c0xffffffff-no-rj-mo"},
        :high=>{:url=>"https://yt3.ggpht.com/tGIJZoN26oD-M5HXGGMC8MizD0iDFdzeaIygX3ArOxSZeJxsRt1IYDrwQgDW5fB9NRAse11-Zg=s800-c-k-c0xffffffff-no-rj-mo"},
        :medium=>{:url=>"https://yt3.ggpht.com/tGIJZoN26oD-M5HXGGMC8MizD0iDFdzeaIygX3ArOxSZeJxsRt1IYDrwQgDW5fB9NRAse11-Zg=s240-c-k-c0xffffffff-no-rj-mo"}},
      :title=>"A.I.Channel"}}],
 :kind=>"youtube#searchListResponse",
 :next_page_token=>"CAEQAA",
 :page_info=>{:results_per_page=>1, :total_results=>44},
 :region_code=>"JP"}
```

<INS>youtube_handle_to_id[:items][0][:id][:channel_id]</INS>
　→　チャンネルIDの取り出し
<br>

<INS>youtube_id = url[url.index("/UC")+1..-1]</INS>
　→　チャンネルIDの取り出し

***

```ruby
@youtube_channel = Rails.cache.fetch("youtube_channel_#{youtube_id}", expires_in: 12.hours) do
  youtube.list_channels("statistics", id: youtube_id).to_h
end
@youtube_video = Rails.cache.fetch("youtube_video_#{youtube_id}", expires_in: 12.hours) do
  youtube.list_searches("snippet", channel_id: youtube_id, type: 'video', max_results: 1, order: :date).to_h
end
```

<INS>youtube.list_channels("statistics", id: youtube_id).to_h</INS>
　→　チャンネル登録者数、投稿動画数の取得
先ほど作成したインスタンスyoutubeは`list_channels`メソッドが使用可能で、チャンネル情報の取得が可能です。
詳細は公式ドキュメントをご確認ください。

https://developers.google.com/youtube/v3/docs/channels/list?hl=ja

**[statistcs](https://developers.google.com/youtube/v3/docs/channels/list?hl=ja#:~:text=part,topicDetails)**　：　必須パラメータの1つで、チャンネル登録者数や動画数の取得が可能です。
**[id](https://developers.google.com/youtube/v3/docs/channels/list?hl=ja#:~:text=%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82-,id,%E3%81%AB%E3%81%AF%E3%80%81%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AE%20YouTube%20%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%20ID%20%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%BE%E3%81%99%E3%80%82,-managedByMe)**　：　チャンネルIDを指定します。

必須パラメータはカンマで区切ることで、複数指定可能です。
<br>
実行すると下記のような結果が得られ、登録者数と投稿動画数もあることが分かります。
```terminal:ターミナル
> youtube.list_channels("snippet, statistics", id: youtube_id).to_h

=> {:etag=>"0umQBzT3t1JtMVyifXCFoTCPCe8",
 :items=>
  [{:etag=>"EV3xfjH7Z1nU2IaFjFR5nhDf5og",
    :id=>"UC4YaOt1yT-ZeyB0OmxHgolA",
    :kind=>"youtube#channel",
    :statistics=>{:hidden_subscriber_count=>false, :subscriber_count=>3010000, :video_count=>113, :view_count=>55725282}}],
 :kind=>"youtube#channelListResponse",
 :page_info=>{:results_per_page=>5, :total_results=>1}}
```

<INS>youtube.list_searches("snippet", channel_id: youtube_id, type: 'video', max_results: 1, order: :date).to_h</INS>
　→　最新動画とそのタイトルの取得
list_searchesメソッドなので、基本は前述の通りです。

**[channel_id:](https://developers.google.com/youtube/v3/docs/search/list?hl=ja#:~:text=channelId,%E5%88%B6%E9%99%90%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82)**　：　チャンネルIDを指定します。
**[type](https://developers.google.com/youtube/v3/docs/search/list?hl=ja#:~:text=%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B-,type,video,-videoCaption)**　：　ここでは動画が知りたいのでvideoを指定します。
**[order](https://developers.google.com/youtube/v3/docs/search/list?hl=ja#:~:text=order,%E3%81%A7%E4%B8%A6%E3%81%B9%E6%9B%BF%E3%81%88%E3%82%89%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82)**　：　表示内容の並び替えができ、ここでは最新が欲しいのでdateを指定します。
<br>
実行すると下記のような結果が得られ、最新動画とそのタイトルもあることが分かります。
```terminal:ターミナル
> youtube.list_searches("snippet", channel_id: youtube_id, type: 'video', max_results: 1, order: :date).to_h

=> {:etag=>"bDKCTk5kGxmZnyifnkM3Xh4gAb8",
 :items=>
  [{:etag=>"B4d_ZimCsFVjXSoIkH9Z92v2uz8",
    :id=>{:kind=>"youtube#video", :video_id=>"QjD3DCIsc-o"},
    :kind=>"youtube#searchResult",
    :snippet=>
     {:channel_id=>"UC4YaOt1yT-ZeyB0OmxHgolA",
      :channel_title=>"A.I.Channel",
      :description=>"https://cognition.kizunaai.com https://youtube.com/live/EEmgm61cQjE.",
      :live_broadcast_content=>"none",
      :published_at=>"2024-06-29T15:00:07Z",
      :thumbnails=>
       {:default=>{:height=>90, :url=>"https://i.ytimg.com/vi/QjD3DCIsc-o/default.jpg", :width=>120},
        :high=>{:height=>360, :url=>"https://i.ytimg.com/vi/QjD3DCIsc-o/hqdefault.jpg", :width=>480},
        :medium=>{:height=>180, :url=>"https://i.ytimg.com/vi/QjD3DCIsc-o/mqdefault.jpg", :width=>320}},
      :title=>"Me in the dream"}}],
 :kind=>"youtube#searchListResponse",
 :next_page_token=>"CAEQAA",
 :page_info=>{:results_per_page=>1, :total_results=>37},
 :region_code=>"JP"}
```

以上で、Controllerファイルの編集は終了です。

ちなみに、list_channelsメソッドではオプションでハンドルも指定可能（[for_handle](https://developers.google.com/youtube/v3/docs/channels/list?hl=ja#:~:text=forHandle,%E8%A8%AD%E5%AE%9A%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)）なので、それを利用すればもう少し分かりやすく書けるのかもしれません。

### 2-2.　View
Controllerで得られた処理結果を表示します。
詳細は省略しますが、それぞれ下記のようにすれば表示されます。


・　チャンネル登録者数
```ruby
@youtube_channel[:items][0][:statistics][:subscriber_count].to_formatted_s(:delimited)
```
「to_formatted_s(:delimited)」で数値をカンマで区切ります。

<br>

・　投稿動画数
```ruby
@youtube_channel[:items][0][:statistics][:video_count].to_formatted_s(:delimited)
```
<br>

・　最新動画
```html
<iframe src="https://www.youtube.com/embed/<%= @youtube_video[:items][0][:id][:video_id] %>?rel=0" title="YouTube video player" allowfullscreen></iframe>
```

「?rel=0」で再生後に関連動画を非表示にします。

<br>

・　最新動画のタイトル
```ruby
@youtube_video[:items][0][:snippet][:title]
```

# さいごに
### その他
API使用量は[Google Cloudのコンソール](https://console.cloud.google.com/apis/dashboard?hl=ja)で確認可能です。
本番環境へのデプロイ時、そちらでも環境変数の設定を忘れないようお気をつけください。

### 参考
https://qiita.com/gyu_outputs/items/af4319258b3d67c57d24#searchs

https://note.com/sleaflet/n/n24cad629cd71

https://qiita.com/sodaihirai/items/9449c2eb657c6fd7cdb1

https://qiita.com/taptappun/items/a217b7017316881d6459