自動でVtuberの配信予定を更新するカレンダーを作ってみた

## はじめに

はじめまして。ほどよくエンジニアをがんばっているシュンといいます。
[自動でVtuberの配信予定を更新するカレンダーを作ってみた](https://shun1218.github.io/vtuber-calendar.html)ので、その過程を書きたいと思います。
今回はYouTube Data APIを使ってYouTubeチャンネルの動画情報を取得します。

## 環境

- Azure VM (Windows Server 2016)
- Python 3.7

### 用意するデータ

- YouTube チャンネルID

### 取得するデータ

- チャンネル情報
- 動画情報

## 方法

まずはじめに、YouTube Data APIを利用できるようにGoogleにアプリケーションを登録します。
詳しい方法は[こちら](https://developers.google.com/youtube/v3/getting-started?hl=ja)。
（ちなみに、このページからAPIを試すこともできます。）
ここで手に入れたAPIキーを利用して、動画情報を取得していきます。

取得の流れとしてはこんな感じになります。

1. チャンネルIDからそのチャンネルの動画IDを取得
1. 動画IDから動画情報を取得

### 1. チャンネルIDからそのチャンネルの動画IDを取得

チャンネルIDは知りたいチャンネルのホームを開いたときのURLから取得できます。
例えば僕のイチオシの[湊あくあ](https://www.hololive.tv/portfolio/items/336383)さんの場合は、
[https://www.youtube.com/channel/UC1opHUrw8rvnsadT-iGp7Cg](https://www.youtube.com/channel/UC1opHUrw8rvnsadT-iGp7Cg)
これがYouTubeチャンネルのURLなので、チャンネルIDは**UC1opHUrw8rvnsadT-iGp7Cg**になります。

このチャンネルIDを使って動画のリストを取得します。

```python
import urllib.request
import json
import ssl

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

def get_video_info(channel_id, page_token=None, published_after=None):
    url = 'https://www.googleapis.com/youtube/v3/search'
    params = {
        'key': 'YOUTUBE_API_KEY',
        'part': 'id',
        'channelId': channel_id,
        'maxResults': 50,
        'order': 'date'
    }
    if page_token is not None:
        params['pageToken'] = page_token
    if published_after is not None:
        params['publishedAfter'] = published_after
    req = urllib.request.Request('{}?{}'.format(url, urllib.parse.urlencode(params)))
    with urllib.request.urlopen(req, context=context) as res:
        body = json.load(res)
        return body
```

チャンネルID以外にもパラメータとして以下の値を指定します。

- key
  - 最初に取得したAPIキー。
- part
  - idとsnippetが指定できます。今回は動画IDが分かればいいのでidを指定。
- channelId
  - チャンネルID。
- maxResults
  - 返ってくるアイテムの最大数。最大で50なので50を指定。
- order
  - いろいろ設定できます。日時順で欲しいのでdateを指定。
- pageToken
  - 一度で指定した条件に当てはまる動画を取得しきれない場合、nextPageTokenとして次のページを示す値が得られるのでそれを指定することで続きを取得。
- publishedAfter
  - 日時を指定して、その日時より後に作成された動画を取得。
  - 日時形式例: 2020-01-01T00:00:00Z

### 2. 動画IDから動画情報を取得

取得した動画IDを使って今度は各動画の詳細情報を取得します。

```python
def get_video_details(video_ids):
    url = 'https://www.googleapis.com/youtube/v3/videos'
    params = {
        'key': 'YOUTUBE_API_KEY',
        'part': 'snippet, liveStreamingDetails',
        'id': video_ids
    }

    req = urllib.request.Request('{}?{}'.format(url, urllib.parse.urlencode(params)))
    with urllib.request.urlopen(req, context=context) as res:
        body = json.load(res)
        return body
```

パラメータは新たにidとして動画IDを指定しているほか、partにsnippetとliveStreamingDetailsを指定しています。
これで動画の基本的な情報に加えてライブ配信時の情報も取得できます。

```python
def get_videos(items):
    video_ids = ''
    for item in items:
        if 'videoId' in item['id']:
            video_ids += item['id']['videoId']
            video_ids += ', '
    video_details = get_video_details(video_ids[:-2])
    for video_detail in video_details['items']:
        print(video_detail)
```

最初に取得した動画IDのリストの中には再生リストのIDも含まれているので、videoIdを持っているものだけを集めてから動画情報を取得しています。

これらを合わせて実行するコードが↓になります。

```python
video_info = get_video_info(channel_id='CHANNEL_ID', published_after='DATETIME')
get_videos(video_info['items'])
while 'nextPageToken' in video_info:
    page_token = video_info['nextPageToken']
    video_info = get_video_info(channel_id='CHANNEL_ID', page_token=page_token)
    get_videos(video_info['items'])
```

最初に日時を指定して取得、その後はnextPageTokenがある限り、取得を続けます。
[湊あくあチャンネル](https://www.youtube.com/channel/UC1opHUrw8rvnsadT-iGp7Cg)の場合、チャンネル設立が2018/7/31なので、これより古い日時で取得を始めれば全動画の情報を取得できます。

実際はこのあとカレンダーの更新等を続けて行いますが、それはまたの機会に......。