LoginSignup
7
7

ニコ生チャット取得

Last updated at Posted at 2020-07-26

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

前提として、ニコ生チャット取得はWebSocketの接続を2本行う必要があることに留意。

コミュニティIDを元に、配信ページを取得

  • https://live.nicovideo.jp/watch/co{コミュニティID}
    • 例: https://live.nicovideo.jp/watch/co4930985

(2021/05/29にURLが変わったようです。live2 -> live)

ページに埋め込まれた放送情報を取得する

(2023/05/13あたりでprogram.broadcastIdが無くなったようです。audienceTokenの先頭に同じIDが入ってるので適当に切り出してください)

    const embeddedData = JSON.parse(document.getElementById("embedded-data").getAttribute("data-props"));
  • 以下の場合は配信が終了してる
    • embeddedData.program.status === 'ENDED'
    • embeddedData.program.endTime < 現在時刻
    const audienceToken = embeddedData.player.audienceToken;
    const frontendId = embeddedData.site.frontendId;
    const broadcastId = audienceToken.match(/^\d+/)[0];

スレッドIDを取得する

WebSocketで以下に接続

const url = `wss://a.live2.nicovideo.jp/unama/wsapi/v2/watch/${broadcastId}?audience_token=${audienceToken}&frontend_id=${frontendId}`

2021/01/21追記
WebSocket接続時、ちゃんとしたブラウザのUser-Agentをヘッダに含めないと、CONNECT_ERRORが返ってくるようになりました。ChromeのUser-Agentあたりを適当に含めてあげてください。

メッセージのやり取りは以下の通り。簡単のためにJSONで表記しているが、実際は文字列化して送受信される。

send
{
  "type": "startWatching",
  "data": { 
    "stream": { "quality": "high", "protocol": "hls", "latency": "low", "chasePlay": false },
    "room": { "protocol": "webSocket", "commentable": true },
    "reconnect": false
  },
}
send
{ 
  "type": "getAkashic",
  "data": { "chasePlay": false } 
}
receive
{
    "type":"room",
    "data":{
      isFirst: boolean,
      messageServer: {
        type: string,
        /** コメントサーバのWebSocketURL */
        uri: string,
      },
      name: string,
      /** スレッドID */
      threadId: string,
      waybackkey: string,
    }
}
  • ここで抜き出すべき要素は以下。
    • data.messageServer.uri
    • data.threadId

チャットサーバに接続してスレッドIDを送信

先程取得したコメントサーバのURLにWebSocket接続。
WebSocketのリクエストヘッダの指定が必要。

    const ws = new WebSocket(wsUrl, 'niconama', {
      headers: {
        'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
        'Sec-WebSocket-Protocol': 'msg.nicovideo.jp#json',
      },
    });

以下WebSocketでの送受信。

send
[
    {
        "ping": {
            "content": "rs:0"
        }
    },
    {
        "ping": {
            "content": "ps:0"
        }
    },
    {
        "thread": {
            "thread": "★スレッドID★",
            "version": "20061206",
            "user_id": "guest",
            "res_from": -150,
            "with_global": 1,
            "scores": 1,
            "nicoru": 0
        }
    },
    {
        "ping": {
            "content": "pf:0"
        }
    },
    {
        "ping": {
            "content": "rf:0"
        }
    }
]

チャット情報の受信

コメントサーバのWebSocketにスレッドIDを送信したら、コメント情報が返ってくる。

receive
開いた時点までのチャット情報がドカッと来る。
obj.ping.content: 'rf:0'のものを受信したらおしまい。

以降は下記のchatオブジェクトを含んだメッセージを受信し続ける。

receive
{
  chat: {
    anonymity?: number;
    /** チャットコメント */
    content: string;
    /** Dateを数値化したやつ */
    date: number;
    date_usec: number;
    /** 匿名の時は184が入ってる */
    mail?: string;
    /** コメント番号 */
    no: number;
    /**
     *  謎のフラグ
     * - 1: プレミアム会員
     * - 3: 配信者自身
     */
    premium?: number;
    score?: number;
    thread: string;
    user_id: string;
    vpos: number;
  };
}

また、定期的にWebSocketに対してpingを打つ必要がある。特にメッセージを含める必要はない。
これをしないと途中でメッセージが来なくなる。
JavaScriptなら、WebSocketインスタンスが持っているpingをsetInterval実行するだけでOK。

ws.ping();
7
7
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
7
7