NLEではセッションを消費せずに配信用のURLやキーを取得しています。この動きと同じことが実装できれば、配信ツールでセッションを一個消費ということも無くなるはずです。ということで、解析結果とサンプルコード(Ruby)になります。
全体的な動作
- アップデート確認
- ログイン
- ライセンス取得
- ログイン
- 配信情報確認
- 動画配信!
なお、アップデート確認とライセンス取得は不要です。
ログイン
Request
- URL: https://account.nicovideo.jp/api/v1/login
- Method: POST
- User Agent: nicoliveenc/{NLEバージョン番号}
- Content Type: application/x-www-form-urlencoded
- Form Data:
- site: nicolive_encoder
- time: {UNIXタイム}
- hash_key: {8桁16進数} # 省略可
- mail: {メールアドレス}
- password: {パスワード}
hash_keyの生成方法は不明です。なくても認証できます。
Response
- Set Cookie:
- Name: nicosid
- Vlaue: {UNIXタイム}.{数字}
- Path: /
- Domain: .nicovideo.jp
-
Data: XML
<nicovideo_user_response status="ok"> <ticket>nicolive_encoder_{数字}</ticket> </nicovideo_user_response>
必要なのはticketのコンテンツのみです。nicosidは別に使わなくてもいいようです。もし、ログインに失敗している場合はstatusがfailになります。
バージョン確認
URL: http://live.nicovideo.jp/encoder/update.xml
NLEの最新バージョンを確認します。必須ではありません。詳細は省略。
ライセンス取得
URL: http://live.nicovideo.jp/encoder/getlicence
NLEのライセンスを取得します。必須ではありません。詳細は省略。
配信情報取得
Request
- URL: http://live.nicovideo.jp/api/getpublishstatus
- Method: POST
- User Agent: nicoliveenc/{NLEバージョン番号}
- Content Type: application/x-www-form-urlencoded
- Cookie: nicosid={loginで取得した値} # 省略可
- Form Data:
- ticket: {loginで取得したticketの値}
- nleserial: {getlicenceで取得したシリアル番号} # 省略可
- accept-multi: {0/1}
Cookieは渡さなくてもいいようです。nlserialにはライセンス取得で取得したシリアル番号が必要ですが、なくても問題ありません。accept-multiは一つのみ取得(0)か複数取得(1)を指定できます。値によって結果のXMLが変わります。
Response
accept-multi=0の場合
-
Data: XML
<getpublishstatus status="ok" time="1432436641" multi="true"> <stream>{動画の情報 省略}</stream> <user>{ユーザーの情報 省略}</user> <rtmp is_fms="1"> <url>rtmp://{ホスト}.live.nicovideo.jp:{ポート番号}/publicorigin/{数字}</url> <stream>lv{数字}</stream> <ticket>{ユーザID}:{ライブID}:{数字}:{数字}:{数字}:{数字}:{16進数}</ticket> <bitrate>{数字}</bitrate> </rtmp> </getpublishstatus>
accept-multi=1の場合
-
Data: XML
<getpublishstatus status="ok" time="1432436641" multi="true"> <list> <item> <stream>{動画の情報 省略}</stream> <rtmp is_fms="1"> <url>rtmp://{ホスト}.live.nicovideo.jp:{ポート番号}/publicorigin/{数字}</url> <stream>lv{数字}</stream> <ticket>{ユーザID}:{ライブID}:{数字}:{数字}:{数字}:{数字}:{16進数}</ticket> <bitrate>{数字}</bitrate> </rtmp> </item> </list> <user>{ユーザーの情報 省略}</user> </getpublishstatus>
statusがokなら配信可能です。配信できないときはfailが入ります。accept-multi=0の場合は、単純にアクセスしたときと同じです。accept-multi=1の場合は、配信の情報だけ、list化されてitemに入れられます。実際の配信URLとストリームキーは下記になります。
- 配信URL: {urlの値}?{tickeの値}
- ストリームキー: {streamの値}
bitrateは現在配信可能なビットレートを表します。
サンプルコード
以上を踏まえて、配信URL、ストリームキー、ビットレートを取得するツールを作りました。煮るなり、焼くなり、Go言語製コメビュに移植するなり、ご自由に!
# coding: utf-8
require "net/https"
require "uri"
require "nokogiri"
class SimNLE
NICOURI = {
login: URI("https://account.nicovideo.jp/api/v1/login"),
getpub: URI("http://live.nicovideo.jp/api/getpublishstatus"),
}
USER_AGENT = "simnle.rb/0.0.1"
def initialize(mail, password)
@mail = mail
@password = password
@ticket = nil
@nicosid = nil
end
def post_header
header = {
"User-Agent" => SimNLE::USER_AGENT,
"Content-Type" => "application/x-www-form-urlencoded",
}
if @nicosid
header["Cookie"] = "nicosid=#{URI.encode_www_form_component(@nicosid)}"
end
return header
end
def login
https = Net::HTTP.new(SimNLE::NICOURI[:login].host, 443)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
data = {
"site" => "nicolive_encoder",
"time" => Time.now.to_i.to_s,
"mail" => @mail,
"password" => @password,
}
response = nil
https.start do
response = https.post(SimNLE::NICOURI[:login].path,
URI.encode_www_form(data), post_header)
end
response.value
doc = Nokogiri::XML.parse(response.body)
case doc.xpath("/nicovideo_user_response").attribute("status").to_s
when "ok"
@ticket = doc.xpath("/nicovideo_user_response/ticket").inner_text
response.get_fields("set-cookie").each do |cookie_data|
list = cookie_data.split(";")[0].strip.split("=")
if list[0] == "nicosid"
@nicosid = list[1]
end
end
return @ticket
when "fail"
return nil
else
raise "Unknown status"
end
end
def getpub
unless @ticket || login
raise "Cannot login"
end
http = Net::HTTP.new(SimNLE::NICOURI[:getpub].host, 80)
data = {
"ticket" => @ticket,
"accept-multi" => 0,
}
response = nil
http.start do
response = http.post(SimNLE::NICOURI[:getpub].path,
URI.encode_www_form(data), post_header)
end
response.value
doc = Nokogiri::XML.parse(response.body)
case doc.xpath("/getpublishstatus").attribute("status").to_s
when "ok"
url = doc.xpath("/getpublishstatus/rtmp/url").inner_text
stream = doc.xpath("/getpublishstatus/rtmp/stream").inner_text
ticket = doc.xpath("/getpublishstatus/rtmp/ticket").inner_text
bitrate = doc.xpath("/getpublishstatus/rtmp/bitrate").inner_text
rtmp_url = "#{url}?#{ticket}"
rtmp_key = stream
return rtmp_url, rtmp_key, bitrate
when "fail"
return nil
else
raise "Unknown status"
end
end
end
if __FILE__ == $0
if ARGV.size < 2
warn "Usage: ruby #{$0} mail password"
exit 1
end
simnle = SimNLE.new(ARGV[0], ARGV[1])
# puts simnle.login
puts simnle.getpub
end