NicoliveIo
ニコニコ生放送のコメントサーバーの寄生サーバー
インストール
$ npm install nicolive.io --save
なぜ?
ニコニコ生放送のコメントサーバーはtcpネットワークを使用して受信できますが、ブラウザには標準で搭載されているものがありません(多くは非標準で、ユーザーに実験機能をONにするなど、特殊の操作を強いるものが殆どです)。
このモジュールでは、ユーザーに代行してコメントサーバーに接続し、受信したxmlをパースして、socket.ioを介してユーザーへ通知します。webブラウザでコメントビューアを制作する人は、クロスドメイン制限を無視して、コメントサーバーへアクセスすることが可能になります。
課題
従来のコメントビューアと同じく、ブラウザに埋め込まれたuserSessionをクッキーから取得する手段が必要です。 このモジュールでは、userSessionを取得していることを前提にしており、ブラウザ側のユーティリティを一切提供しません。
デモ
Angular-Materialを使用したデモです。
API
NicoliveIo
constructor(requestListener) -> nicoliveIo
class nicolive.io
をrequireすると、__socket.ioクラスを継承__した、nicoliveIo
インスタンスと、NicoliveIo
クラスを返します。
var nicoliveIo= ;var NicoliveIo= NicoliveIo; console;// [// 'checkRequest',// 'serveClient',// 'set',// 'path',// 'adapter',// 'origins',// 'attach',// 'listen',// 'attachServe',// 'serve',// 'bind',// 'onconnection',// 'of',// 'close',// 'on',// 'to',// 'in',// 'use',// 'emit',// 'send',// 'write',// 'json'// ] console;// true
NicoliveIo
コンストラクタの第一引数に任意のrequestListener
を渡すことで、socket.io
が補足しなかったrequestイベントを、渡したrequestListner
で受信できます。
以下は例では、Express4をrequestListner
に使用して、socket.ioサーバーと静的ファイルサーバーの両方をhttp://localhost:59798
上に起動します。
$ npm install express --save $ mkdir public$ echo 'nicolive.io is available' > public/index.html $ node app.js# Listen at http://localhost:59798
app.js
// Dependenciesvar express= ;var NicoliveIo= NicoliveIo; // Setup expressvar app= ;app; // Setup nicolive.iovar server= app; // Bootserver;
nicoliveIo.listen(port,callback)
指定portでサーバーを起動します。callback関数を渡した場合、起動が完了したときに呼び出します。
nicoliveIo.close(callback)
サーバーをショットダウンします。callback関数を渡した場合、ショットダウンが完了したときに呼び出します。
nicoliveIo.on('connection',callback(clientSocket))
サーバーへ接続に成功したclientのEventEmitterインスタンスを、callback関数に渡します。 NicoliveIoはclientと接続が確立した時に、自動でイベントを追加します。追加するイベントは下記のとおりです。
auth
clientSocketEvent:clientからuserSessionを受け取り、getplayerstatusへアクセスします。userSessionが有効であればauthorized
イベントを、不正であればerror
イベントを送信します。
view
clientSocketEvent:clientからcannelIdを受け取り、getplayerstatusを経由してtcpでコメントに接続します。接続に成功すると、NicoliveIoはコメントサーバーから受信したxmlを解析し、解析結果でclientに送信し続けます。
接続中、送信するイベントは3種類あります:
thread
イベント:{resultcode,last_res,ticket,...} 接続したコメントサーバーの情報、接続が成功した時、はじめに1度だけイベントを発行する。resultcodeが'0'なら成功、それ以外なら失敗。失敗コードの詳細はresultcodeで検索してください。chat
イベント:{'thread','vpos','date','date_usec','user_id','premium','no','text'} コメント・運営コメント・広告コメントのパース結果chat_result
イベント:{{chat_attributes...},status} clientSocketEvent:comment
を参照。statusが0であれば、コメントは受理されています
comment
clientSocketEvent:clientにauthorizedイベントを送信済みであれば、コメントします。
コメントの結果をchat_result
イベントでclientに送信します。
error
clientSocketEvent:サーバー側で発生した例外をこのイベントで補足し、clientにwarn
イベントを送信します。
disconnect
clientSocketEvent:clientがdisconnectメソッドを実行すると、サーバーはただちにtcpを切断します。
createNextStream
clientSocketEvent:clientがプレミアム会員であれば、第一引数の配信idの情報を使用して、放送枠を作成します。
window.io
クライアントは、まず初めにsocket.ioの依存ファイルである/socket.io/socket.io.jsを読み込む必要があります。以下はportを59798でサーバーを起動した場合の例です。
io.connect(url) -> serverSocket
以下のような順序でサーバーへイベントを送信することで、コメントをリアルタイムに受信します。
userSessionについて
userSessionは、ニコニコ生放送内で、以下をアドレスバーに実行すると取得できます。
javascript:;// window.alert:"user_session_000000_0000000000000000000000000000000000000000000000000000000000000000"
以下は開発コンソールで取得する場合です。
documentcookie;// user_session_000000_0000000000000000000000000000000000000000000000000000000000000000
connect
serverSocketEvent:起動したサーバーと接続に成功したとき、受信します。サーバーが再起動した時や、クライアントの回線異常により再接続した場合、2回以上イベントが発行することに注意してください。
var serverSocket= io;serverSocket;// connected
authorized
serverSocketEvent:サーバーのauth
イベントへuserSessionを送信し、認証に成功したとき、受信します。
var serverSocket= io;serverSocket;serverSocket;// connected// authorized {port: "2806", addr: "omsg103.live.nicovideo.jp", thread: "1450455950", user_id: "143728", premium: "1"...}
thread
serverSocketEvent:サーバーのview
イベントへチャンネルidを送信し、スレッドに接続できたとき、受信します。
var userSession= 'user_session_000000_0000000000000000000000000000000000000000000000000000000000000000'; var serverSocket= io;serverSocket;serverSocket;serverSocket;serverSocket;// connected// authorized {port: "2806", addr: "omsg103.live.nicovideo.jp", thread: "1450455950", user_id: "143728", premium: "1"...}// thread {resultcode: "0", thread: "1450455950", last_res: 1863, ticket: "0x14facd80", revision: "1"...}
chat
serverSocketEvent:チャンネルidのコメント1件につき1イベントを受信します。
var userSession= 'user_session_000000_0000000000000000000000000000000000000000000000000000000000000000'; var serverSocket= io;serverSocket;serverSocket;serverSocket;serverSocket;// connected// authorized {port: "2806", addr: "omsg103.live.nicovideo.jp", thread: "1450455950", user_id: "143728", premium: "1"...}// thread {resultcode: "0", thread: "1450455950", last_res: 1863, ticket: "0x14facd80", revision: "1"...}// chat {thread: "1450455950", vpos: "1276900", date: "1436653369", date_usec: "133900", user_id: "900000000"...}// chat {thread: "1450455950", vpos: "1299400", date: "1436653594", date_usec: "286322", user_id: "900000000"...}// chat {thread: "1450455950", vpos: "1299400", date: "1436653594", date_usec: "343074", user_id: "900000000"...}// chat {thread: "1450455950", vpos: "1299400", date: "1436653594", date_usec: "398244", user_id: "900000000"...}// chat {thread: "1450455950", vpos: "1299400", date: "1436653594", date_usec: "452674", user_id: "900000000"...}
chat_result
serverSocketEvent:サーバーのcomment
イベントへ文章を送信し、結果が返ったとき、受信します。
コールバックの第一引数には、成否の情報statusを含んでいます。
//...serverSocket;serverSocket;// chat_result {text:"てすてすてす", status: "0", thread: "1450455950", no: "1864", date: "1436653696", date_usec: "110007", mail: "184"...}
getplayerstatus
serverSocketEvent:このイベントはデバッグ用です。自身のthread
イベントの直前に受信します。コールバックの第一引数には、サーバーが使用した接続に必要な最低限な情報と、getplayerstatusのパース前のxmlデータを含んでいます。
serverSocket;// getplayerstatus {addr: "omsg103.live.nicovideo.jp"port: "2806"premium: "1"thread: "1450455950"user_id: "143728"xml: "<?xml version="1.0" encoding="utf-8"?>↵<getplayerstatus status="ok" time="1436653695"><stream><id>lv227714286</id><title>Nsen - 蛍の光チャンネル</title><description>Nsenからの去り際に自主的にお立ち寄り下さい。Nsenをご堪能頂いた後、また、ネットサーフィンを終え眠りにつく時などにオススメです。</description>...</getplayerstatus>"}
getpostkey
serverSocketEvent:このイベントはデバッグ用です。自身のchat_result
イベントの直前に受信します。コールバックの第一引数には、tcpサーバーへの書き込みに必要なpostkeyのみが渡されます。
serverSocket;// getpostkey .1436653726.KL6uM4PMV8cKULkBJqXjdmm1Ye0
warn
serverSocketEvent:このイベントはデバッグ用です。サーバーが補足したエラーを受け取ります。
serverSocket;serverSocket;serverSocket; serverSocket;// notlogin// notfound// nothread
serverSocket.emit('nickname',user_id,callback) -> {error,nickname}
静画APIへアクセスしてユーザー名をコールバック関数に渡します。ユーザーが存在しない場合でも、nicknameが-
のユーザーとして扱うことに注意してください。
serverSocket; serverSocket; serverSocket;
serverSocket.emit('createNextStream',preventStreamId,callback) -> {error,nextSreamId}
自動次枠取得を試みます。枠内容はpreventStreamId
を参照します。
この機能は実験的です。
serverSocket;
end_of_thread
serverSocketEvent:問い合わせたチャンネルidが終了した/終了している場合、このイベントを受信します。後述のcurrent
イベントをサーバーに送信することで、次枠が開始していないか確認できます。
serverSocket.emit('current',callback(error,playerStatus))
view
イベントで問い合わせたコミュニティの配信中のplayerStatusを取得します。これは、end_of_thread
イベントを受け取ってしばらく後、同じコミュニティで新しく放送が開始した時、検出できることを意味します。
Test
$ git clone https://github.com/59naga/nicolive.io.git$ cd nicolive.io$ npm install $ export SESSION=your_user_session_value$ npm test