LoginSignup
51
55

More than 5 years have passed since last update.

Nodejsでニコ生のコメビュを作る

Last updated at Posted at 2015-05-10
d.hatena.ne.jp/toriimiyukki/20120124/1327417154
var net = require('net');
socket.connect(data.msPort, data.msAddr);
socket.setEncoding('utf-8');
socket.on('connect', function() {
    console.log('connected');
    socket.write('<thread thread="' + data.msThread + '" res_from="' + data.resFrom + '" version="20061206" >' + "\0");
});
socket.on('data', function(data) {
    console.log(data);
});

グーグルで検索すると見つかるこのコード片ではgetplayerstatusを取得しないので動きません。

  • 手動でAPIにアクセスして、該当箇所を書き換えると動きます。
    • data.msPort: <getplayerstatus><ms><port> の値
    • data.msAddr: <getplayerstatus><ms><addr> の値
    • data.msThread: <getplayerstatus><ms><thread> の値
    • data.resFrom: -1000~0 コメント開始位置

suck.js
var net= require('net');
var socket= net.connect(2811,'omsg101.live.nicovideo.jp');
socket.on('connect', function(){
  console.log('connected');
  socket.setEncoding('utf-8');
  socket.write('<thread thread="1435806943" res_from="-5" version="20061206" />\0');
});
socket.on('data',function(data){
  console.log(data);
});
data
<thread resultcode="0" thread="1435806943" last_res="2836" ticket="0x1dfc9b00" revision="1" server_time="1431262237"/><chat thread="1435806943" vpos="6450700" date="1431261909" date_usec="57301" mail="184" user_id="Idj1TdXOGrERXdFOUdiTX4sKIB0" anonymity="1" locale="jp">v(゚Д゚)v<♪ カァーニー カァーニー ショヌダー カジカジ バーブー ソムダー パッ! ♬</chat><chat>...</chat>

This sucks.
この記事では、ログインから順を追って説明します。

ログイン

https://secure.nicovideo.jp/secure/loginmail_telpasswordPOSTします。
requestモジュールを使用します。

$ npm install request
$ node login.js
login.js

var request= require('request');

request.post({
  url: 'https://secure.nicovideo.jp/secure/login',
  form: {
    mail_tel: 'your@mail.address',
    password: '********',
  },
},function(error,response){
  if(error!=null) throw error;

  var session= null;
  var cookies= response.headers['set-cookie'] || [];
  for(var i=0; i<cookies.length; i++){
    var cookie= cookies[i];
    if(cookie.match(/^user_session=user_session/)){
      session= cookie.slice(0,cookie.indexOf(';')+1);
    }
  }

  console.log(response.headers['set-cookie']);
  console.log(session);
});

ログインが正常であれば

response.headers['set-cookie']

[ 'nicosid=1431257919.1222609129; expires=Wed, 07-May-2025 11:38:39 GMT; path=/; domain=.nicovideo.jp',
  'user_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT',
  'user_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/',
  'user_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.nicovideo.jp',
  'user_session=user_session_000000_0000000000000000000000000000000000000000000000000000000000000000; expires=Tue, 09-Jun-2015 11:38:39 GMT; path=/; domain=.nicovideo.jp',
  'repair_history=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.nicovideo.jp' ]
session
user_session=user_session_000000_0000000000000000000000000000000000000000000000000000000000000000;

のような値が返ります。最終的に使用するのはsessionのみです。

以降はこのsessionを使いまわします。sessionはしばらく有効で、ローカルファイルとして値を保存しておくことで、メソッド毎にログイン処理を挟まずに済むでしょう。

プレイヤー(コメントサーバー)情報の取得

では早速、getplayerstatusが使用可能になったことを確認しましょう。

getplayerstatus.js
var request= require('request');
request({
  url: 'http://live.nicovideo.jp/api/getplayerstatus/nsen/hotaru',
  headers: {
    Cookie: session,
  },
},function(error,response){
  if(error!=null) throw error;

  console.log(response.body);
});
response.body
<?xml version="1.0" encoding="utf-8"?>
<getplayerstatus status="ok" time="1431262800"><stream><id>lv220580424</id><title>Nsen - 蛍の光チャンネル</title><description>Nsenからの去り際に自主的にお立ち寄り下さい。Nsenをご堪能頂いた後、また、ネットサーフィンを終え眠りにつく時などにオススメです。</description>...</stream>
...
<ms><addr>omsg101.live.nicovideo.jp</addr><port>2811</port><thread>1435806943</thread></ms>
...
</getplayerstatus>

プレイヤー(コメントサーバー)情報を取得することができました。

getplayerstatusは nsen, lv***, co***の3種類が使用可能です。

cheerioモジュールを使用して、必要な値だけを取り出します。

$ npm install cheerio
$ node getplayerstatus.js
getplayerstatus.js
var request= require('request');
var cheerio= require('cheerio');

request({
  url: 'http://live.nicovideo.jp/api/getplayerstatus/nsen/hotaru',
  headers: {
    Cookie: session,
  },
},function(error,response){
  if(error!=null) throw error;

  var $= cheerio.load(response.body);
  console.log($('getplayerstatus ms port').text());
  console.log($('getplayerstatus ms addr').text());
  console.log($('getplayerstatus ms thread').text());
});
console.log
2811
omsg101.live.nicovideo.jp
1435806943

プレイヤーへ接続する

これまでのコードを繋ぎあわせて、コメントを取得します。

nicolive.js
// Dependencies
var request= require('request');
var cheerio= require('cheerio');
var net= require('net');

// Demonstration
process.nextTick(function(){
  // Environment
  var id= 'your@mail.address';
  var pw= '********';
  var live_id= 'nsen/hotaru';

  // Boot
  nicolive.login(id,pw,function(error,session){
    if(error!=null) throw error;

    nicolive.fetchThread(live_id,session,function(error,thread){
      if(error!=null) throw error;

      nicolive.view(thread,function(error,viewer){
        if(error!=null) throw error;

        viewer.on('data',function(data){
          console.log(data);
        });
      });
    });
  });
});

// Methods
nicolive= {
  login: function(id,pw,callback){
    request.post({
      url: 'https://secure.nicovideo.jp/secure/login',
      form: {
        mail_tel: id,
        password: pw,
      },
    },function(error,response){
      if(error!=null) return callback(error);

      var session= null;
      var cookies= response.headers['set-cookie'] || [];
      for(var i=0; i<cookies.length; i++){
        var cookie= cookies[i];
        if(cookie.match(/^user_session=user_session/)){
          session= cookie.slice(0,cookie.indexOf(';')+1);
        }
      }
      if(session==null) return callback(new Error('Invalid user'));

      callback(null,session);
    });
  },
  fetchThread: function(live_id,session,callback){
    request({
      url: 'http://live.nicovideo.jp/api/getplayerstatus/'+live_id,
      headers: {
        Cookie: session,
      },
    },function(error,response){
      if(error!=null) return callback(error);

      var $= cheerio.load(response.body);
      callback(null,{
        port: $('getplayerstatus ms port').text(),
        addr: $('getplayerstatus ms addr').text(),
        thread: $('getplayerstatus ms thread').text(),
      });
    });
  },
  view: function(thread,callback){
    var viewer= net.connect(thread.port,thread.addr);
    viewer.on('connect', function(){
      viewer.setEncoding('utf-8');
      viewer.write('<thread thread="'+thread.thread+'" res_from="-5" version="20061206" />\0');

      callback(null,viewer);
    });
  },
}

module.exports= nicolive;
$ node nicolive.js
console.log(data);
<thread resultcode="0" thread="1435806943" last_res="2836" ticket="0x1dfc9b00" revision="1" server_time="1431262237"/><chat thread="1435806943" vpos="6450700" date="1431261909" date_usec="57301" mail="184" user_id="Idj1TdXOGrERXdFOUdiTX4sKIB0" anonymity="1" locale="jp">v(゚Д゚)v<♪ カァーニー カァーニー ショヌダー カジカジ バーブー ソムダー パッ! ♬</chat><chat>...</chat>

成果物(Electron製コメントビューアー)

d06cf958-ebda-11e4-9d22-5f9420129523.png

参考

51
55
1

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
51
55