コメントビューア用。
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を投げれば、次のチャットメッセージを拾うことができます。