19
22

More than 3 years have passed since last update.

Youtubeチャット取得

Last updated at Posted at 2021-01-30

コメントビューア用。
OAuthが要るようなAPIは使わず、未登録で取得できるコメントを取得。
あくまで執筆時点の情報です。仕様が変わる可能性もあるのであしからず。

元々解析済みだったのですが、2021/01/29にYoutubeにガッツリ仕様変更入って調査をしたのでついでに書きます。


1. 配信ページを取得

Youtubeの動画URLは、ライブ配信、アップロード動画に関わらず、同じURL体系をしています。
例: https://www.youtube.com/watch?v=K0x0tZ4kRzs

URLのうちv=xxxxxを便宜上LiveIDと呼びますが、このLiveIDはライブ配信を行うたびに変わるため、コメントビューアを作る場合はLiveID以外の情報でページを取得する必要があります。
※限定公開動画の場合はアカウントログインして頑張るか、LiveID直接指定が必要です

その方法は単純で、以下URLにアクセスするだけでOKです。
https://www.youtube.com/channel/{チャンネルID}/live
配信が始まっていない場合はチャンネルトップが表示され、配信が始まっている場合はwatch?v=xxxxと同様のページが表示されます。

2. 初期パラメータ取得

配信ページに埋め込まれている、チャット取得に必要な初期パラメータを取得します。
いずれもページ冒頭のscriptタグに埋め込まれているため、配信ページのソースから文字列マッチングを駆使して拾います。
以下はjsによるサンプル。

      const key = htmlsrc.match(/innertubeApiKey":".*?"/)[0]
        .split(':')[1]
        .replace(/"/g, '');

      const continuation = htmlsrc.match(/continuation":".*?"/)[0]
        .split(':')[1]
        .replace(/"/g, '');
// エラーハンドリングは実装者の裁量に任せます

3. コメント取得(リクエスト)

YoutubeチャットはPOSTで取得します。
リクエストボディは以下。

const body = {
  context: {
    client: {
      clientName: 'WEB', // 指定しないと怒られる
      clientVersion: '2.20210126.08.02', // 割となんでもよさそう
      timeZone: 'Asia/Tokyo', // 返ってくるタイムスタンプに影響ありそう
      utcOffsetMinutes: 540,  // 返ってくるタイムスタンプに影響ありそう
      mainAppWebInfo: {
        graftUrl: `https://www.youtube.com/live_chat?continuation=`, // ここのcontinuationパラメータが空でも通る
      },
    },
    request: {
      useSsl: true,
    },
  },
  continuation: "xxxxxxxxx", // さっき取得したcontinuation
};
// 実際にブラウザで配信ページを開いた場合、上記に加えてテレメトリっぽいデータがマシマシに乗っかっています。

上記のJSONを、以下のURLに対してPOSTします。headerのContent-Type: application/jsonもお忘れなく。
https://www.youtube.com/youtubei/v1/live_chat/get_live_chat?key={key} {key}はさっき取得したやつ

4. コメント取得(レスポンス)

コメビュにとってはどうでもいい情報が大量に載っていて、ざっくり言うと以下のGetLiveChatResponse です。
https://github.com/pasta04/unacast/blob/master/src/main/youtube-chat/%40types/yt-response.d.ts

以下、必要なところだけをかいつまんだサンプルレスポンスです。

const response = {
  continuationContents: {
    liveChatContinuation: {
      // 配列ですが、基本的に0番目だけ取得でよさそうです
      continuations: [
        {
          // 個人チャンネルの配信はこっちの属性で指定されることが多い
          invalidationContinuationData: {
            continuation: 'xxxxxxxxxxxxxxxxx', // 次のコメント取得の時に指定するcontinuation
          },
          // 公式チャンネルの配信はこっちの属性で指定されることが多い
          timedContinuationData: {
            continuation: 'xxxxxxxxxxxxxxxxx', // 次のコメント取得の時に指定するcontinuation
          }
        },
      ],
      // 以下はレスポンスに含まれないことがあるので注意
      // チャットなどの分だけactionsの要素が含まれます
      // 初回取得時のみ、配列の末尾要素にチャットルール用のメッセージが入り込むので適宜除外してください
      actions: [
        {
          item: {
            // チャットの種類によって入ってたり入ってなかったり
            liveChatTextMessageRenderer: {
              message: {
                runs: [
                  {
                    text: 'ここにチャットメッセージ',
                  },
                  // メッセージに特殊絵文字(画像)が含まれている場合、テキストと画像が配列の個別要素として返却されます
                ],
              },
              authorName: {
                simpleText: '投稿者のなまえ',
              },
              authorPhoto: {
                thumbnails: [
                  {
                    url: 'アイコン画像のURL',
                  },
                ],
              },
            },
            // スパチャもこの辺に属性が増えてます
          },
        },
      ],
    },
  },
};

あとは上記レスポンスで取得したcontinuationを使って3. コメント取得(リクエスト)のPOSTを投げれば、次のチャットメッセージを拾うことができます。

19
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
22