YouTubeのコンテンツがメンバー限定かをAPIで判定する

ドズル社のおんりーﾁｬﾝ ([おんりー / ドズル社](https://youtube.com/@QnlyQ)) の配信をお知らせするbot ([Jyormany bot🌟](https://x.com/jyormany_bot)) を制作・管理している中で、通知する配信枠がメンバー限定(メン限)かどうかを判定したいとなりました。

bot開発時にも考えてはいたのですが、YouTubeのデータを取得できる[YouTube Data API](https://developers.google.com/youtube?hl=ja) にはメンバー限定か否かを直接的に取得する方法がなく、諦めていました。

先日、やっぱり判定したいと思い立ち、webスクレイピングﾁｯｸなことをしようかとも考えたのですが、そのうち **「メン限は再生回数見えないじゃん！」** と、やっと気がつきました。APIからのデータのみでメンバー限定かを判定できると分かり個人的に嬉しかったので、メモ代わりにもと書き記しています。

:::note warn
コメント・チャット欄が有効かどうかでも判定できそうと思いましたが、一般公開でも配信者がそれらを無効にできると分かり、却下しました。
再生回数は無効にすることはできないようです。(この記事の投稿時点)
:::

:::note info
2024/07/09 追記 ここから
恥ずかしながらYouTubeの裏仕様(?)にやっと気づくことが出来たので、以下に追記します。
（もっと早く知りたかった。。。）
:::

# 自動再生リスト
何気なく調べ物をしていたら、とんでもないものを見つけてしまいました。
YouTubeの裏技みたいな機能ですが、（配信者でなく）YouTube側が自動で更新する、 __特定チャンネルの動画を ほぼ すべて集めた再生リスト__ がありました！

以下の２種類があるようです。（恐らく）
***
### 一般公開動画の再生リスト
含まれる動画の種類 : チャンネルの __一般公開__ 動画
Playlist ID: `UU{Channel IDの'UC'から先}`
(Channel IDが`UChogehoge`だった場合、Playlist IDは`UUhogehoge`

### メンバー限定動画の再生リスト
含まれる動画の種類 : チャンネルの __メンバー限定__ 動画
Playlist ID: `UUMO{Channel IDの'UC'から先}`
(Channel IDが`UChogehoge`だった場合、Playlist IDは`UUMOhogehoge`

***

これらの再生リストには、配信のほか、動画、Shorts動画も含まれるようです。

`https://www.youtube.com/playlist?list={Playlist ID}`
からWebサイトで開くこともできますし、

[**PlaylistItems: list**](https://developers.google.com/youtube/v3/docs/playlistItems/list?hl=ja) `GET https://www.googleapis.com/youtube/v3/playlistItems`
でAPIから中身を取得することもできます。

:::note warn
運営しているbotの場合、再生リストの更新(→`etag`の更新)をトリガーにデータ取得・通知を行っているので活用できるのですが、
特定の動画や、すでにIDが分かっている動画がメン限かどうかを判定したい場合は、以下の方法が便利かもしれません。

いずれの方法も、仕様の変更には一応気を付けておきたいです。
:::
:::note info
追記 ここまで
:::

# 判定方法
### 判定に必要な情報と条件


[**Videos: list**](https://developers.google.com/youtube/v3/docs/videos/list?hl=ja) `GET https://www.googleapis.com/youtube/v3/videos`
このエンドポイントには、詳細情報を取得したい動画・配信の 動画ID[^1] と、取得したい情報の種類(videoリソースプロパティ)を投げ、データを受け取ります。
リクエストパラメータ `part` に指定するvideoリソースプロパティと、その内容は次のようになります。

|プロパティ名|レスポンスのうち欲しい情報|取得できる情報|メン限とする条件|
|:-:|:-:|:-:|:-:|
|status|privacyStatus|動画の公開設定|`"public"`[^2]|
|statistics|viewCount|再生回数|(データなし)|

### レスポンスの例
#### 一般公開
```json
{
  "kind": "youtube#videoListResponse",
  "etag": "<etag>",
  "items": [
    {
      "kind": "youtube#video",
      "etag": "<videoEtag>",
      "id": "<videoID>",
      "status": {
        "uploadStatus": "uploaded",
        "privacyStatus": "public",
        "license": "youtube",
        "embeddable": true,
        "publicStatsViewable": true,
        "madeForKids": false
      },
      "statistics": {
        "viewCount": "22375",
        "likeCount": "1253",
        "favoriteCount": "0",
        "commentCount": "1"
      }
    }
  ],
  "pageInfo": {
    "totalResults": 1,
    "resultsPerPage": 1
  }
}
```
#### メンバー限定
```json
{
  "kind": "youtube#videoListResponse",
  "etag": "<etag>",
  "items": [
    {
      "kind": "youtube#video",
      "etag": "<videoEtag>",
      "id": "<videoID>",
      "status": {
        "uploadStatus": "processed",
        "privacyStatus": "public",
        "license": "youtube",
        "embeddable": true,
        "publicStatsViewable": true,
        "madeForKids": false
      },
      "statistics": {
        "likeCount": "411",
        "favoriteCount": "0",
        "commentCount": "6"
      }
    }
  ],
  "pageInfo": {
    "totalResults": 1,
    "resultsPerPage": 1
  }
}
```
#### 非公開
```json
{
  "kind": "youtube#videoListResponse",
  "etag": "<etag>",
  "items": [],
  "pageInfo": {
    "totalResults": 0,
    "resultsPerPage": 0
  }
}
```
`items[].statistics`内に、`viewCount`がメンバー限定のデータには含まれていないことが分かるかと思います。この有無を見つけるまで、何度も投げては間違い探し をしていました。
# Pythonで処理する場合
実際に運営しているbotのPythonプログラムでの判定処理を一例として挙げておきます。(公開用に割愛&一部書き換えてあります)
```python
# APIから取得したデータ(Dict)
videoData = {...}
for video in videoData["items"]:
    # 取得したデータがメンバー限定かを判定し、bool変数に代入(メンバー限定ならTrue)
    membershipQnly = (video["status"]["privacyStatus"] == "public") and (not "viewCount" in video["statistics"])
    # 〜〜〜動画ごとの処理〜〜〜
```
# おわりに
下手なだけかもしれませんが、APIでのメン限判定方法をネットでいくら探しても出てこず(ふつうメン限のデータををAPIで取得しない?）諦めていたものを、少し時間が経って頭を右ななめにひねっていたらｱﾚｱﾚｱﾚ?と気づき、とても嬉しかったです笑
WebAPIは手動で投げて裏側っぽいデータ(?)を見られたりしておもしろいですし、
YouTubeのAPIはWebサイト上からコストを使わずに投げられるものもあり嬉しいです。
# 参考
**自動再生リスト(追記分)**

https://atarms.hatenablog.com/entry/2021/11/09/061655

https://note.com/raiden_871254/n/n2affae588eda

**YouTube Data API - PlaylistItems: list (再生リスト内の動画項目の取得・追記分)**

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

**YouTube Data API - Videos: list (動画データの取得)**

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

**YouTube配信の公開範囲設定**

https://crobo.world/column/about-membership/#arkb-toc-13

# 紹介
**自分の人生を変えてくれた配信者さん**

https://youtube.com/@QnlyQ

**制作した X(Twitter) bot**

https://x.com/@Jyormany_bot

[^1]: 動画ごとに割り当てられる一意のID。動画のURLに`youtube.com/watch?v=<動画ID>`として生成されたり、`youtu.be/<動画ID>`としてアクセスできたりします。
[^2]: 配信者が配信の公開設定をする際、「非公開」/「限定公開」/「メンバー限定」/「公開」の4種類の公開範囲から選択することになり、それぞれの場合の`privacyStatus`の値は、`"private"` / `"unlisted"` / `"public"` / `"public"`となります。(「メンバー限定」の時は`"membersOnly"`とかにしてくれてもいいのに...)