ニコ生アラート + コメントビューア + 1コメゲット ツールを作る(C#) その1

̃Gg[͂ĂȃubN}[Nɒlj


ニコニコ生放送用のツールとして
 
・アラート機能
・コメビュ機能
・1コメ投稿機能
 
をもつものをC#で作ってみました。アラート対象放送を検出直後”1GET”とコメントします。


とりあえず ニコ生アラート(苺) CUI版と名づけました。
サンプルアプリということで、CUIです。
 

2010/12/29 追記 vpos算出処理を変更
2011/01/28 追記 GetPlayerStatusのbase_time、user_id取得処理を変更
2011/01/31 続編を執筆しました(Webブラウザとクッキーを共有)。
2013/01/02 修正 文字列内のエスケープシーケンス(\nとか\”等の\)が消えていたので補修。 

サンプルツール使用法


そのままビルドすると、以下指定となります。

このツール.exe メアド パスワード [コミュID] [生主ID]

メアド、パスワードは必須です。
コミュID、生主IDは、アラートでひっかけたい放送のIDです、
指定しない場合は、最初にみつけた放送に問答無用で1コメ投稿します(取扱注意)。

起動例)
このツール.exe your_mail_address@hoge.mail.com your_password
 起動後、最初に開始した放送に接続し、1コメを送信。
このツール.exe your_mail_address@hoge.mail.com your_password co247262
 コミュニティID=co247262の放送が開始したら接続し、1コメを送信。
このツール.exe your_mail_address@hoge.mail.com your_password 426136
 生主ID=426136の放送が開始したら接続し、1コメを送信。
このツール.exe your_mail_address@hoge.mail.com your_password co247262 426136
 コミュニティID=co247262、または生主ID=426136の放送が開始したら接続し、1コメを送信。
 

構成


main()
{
	//コマンドライン引数チェック
	CheckCommandLine()

	//クッキー取得のためのログイン
	LoginForCokkieContainer()

	//認証APIのためのログイン
	LoginForGetAlertStatus()

	//認証API
	GetAlertStatus()

	//番組開始情報取得
	GetProgramInfo()
	{
		while(true)
		{
			//番組情報受信
			
			if(アラート対象番組)
			{
				//番組詳細情報取得
				GetPlayerStatus()

				//コメントサーバ接続
				GetCommnet()
				{
					//postkey取得
					GetPostKey
					
					//1コメ投稿
					
					//コメント表示
				}
			}
		}
	}
}

クッキー取得のためのログイン

 未稿
 

認証APIのためのログイン

 未稿
 

認証API

 未稿
 

番組開始情報取得

 未稿
 

番組詳細情報取得

 未稿
 

コメントサーバ接続

 未稿
 

コメント投稿

 未稿
 

ソースコード

自由に改造して頂いて構いません。
コミュ限放送判定、disconnect検出処理などはないので注意してください。
完全に俺ツールなので心して改造してください。

using System;
using System.Text;
using System.Xml;
using System.Net;
using System.IO;
using System.Net.Sockets;
using System.Diagnostics;
using System.Collections;
namespace NicoLive_Alert_ComenntView_1CommentSend
{
	class Program
	{
		//ログイン情報
		static string m_mail = "";//コマンドライン第1引数
		static string m_pass = "";//コマンドライン第2引数
		static CookieContainer m_cc;//クッキーコンテナ

		//アラート設定
		static long m_AlertCount = 0;   //アラート回数
		static long m_MaxAlertCount = 1;//最大アラート回数

		//アラートで引っかけたいID(//コマンドライン第3, 4引数)
		static string m_comID;//コミュID
		static string m_usrID;//生主ID

		//ログインAPI戻り値
		static string m_ticket = "";//認証用チケット

		//認証API(getalertstatus)戻り値
		static string m_addr = "";//番組開始情報サーバのアドレス
		static string m_port = "";//番組開始情報サーバのポート
		static string m_thread = "";//スレッドID

		//番組詳細情報取得API(getplayerstatus)戻り値
		//番組情報
		static string m_base_time = "";//開始時刻
		//ユーザ情報
		static string m_userid = "";//ユーザID
		//コメントサーバ情報
		static string m_ComSrvAddr = "";//コメントサーバのアドレス
		static string m_ComSrvPort = "";//コメントサーバのポート
		static string m_ComSrvThread = "";//スレッドID

		//getpostkey戻り値
		static string m_postkey = "";

		//他管理情報
		static DateTime m_DateTimeStart;//開始時刻(ローカル)

		static void Main(string[] args)
		{
			//コマンドライン引数チェック
			if (!CheckCommandLine(args))
			{
				return;
			}

			//認証API(ログイン不要)を叩く
			//本サンプルでは未使用
			//if (!GetAlertInfo())
			//{
			//	return;
			//}

			//普通にログインする(クッキーコンテナ取得のため)
			if (!LoginForCokkieContainer())
			{
				return;
			}

			//ログインAPIを叩く(認証API(要ログイン)叩く用)
			if (!LoginForGetAlertStatus())
			{
				return;
			}

			//認証API(要ログイン)を叩く
			if (!GetAlertStatus())
			{
				return;
			}

			//番組情報取得
			if (!GetProgramInfo())
			{
				return;
			}
		}
		//コマンドライン引数チェック
		static bool CheckCommandLine(string[] args)
		{
			try
			{
				if (args.Length < 2)
				{
					Console.WriteLine("使用法 : NicoLiveOneComementGetter.exe mail pass [comID] [userID]");
					return false;
				}
				//ログイン設定
				m_mail = args[0];
				m_pass = args[1];

				//アラートターゲット設定
				switch (args.Length)
				{
					case 2://引数2つ(検出次第ターゲットとする)
						m_comID = "";
						m_usrID = "";
						break;
					case 3://引数3つ(コミュID, 生主IDどちらかでアラート)
						if (args[0].StartsWith("co"))
						{
							m_comID = args[2];
						}
						else
						{
							m_usrID = args[2];
						}
						break;
					case 4://引数4つ(コミュID, 生主ID両方でアラート)
					default://それ以上(5つめ以降無視)
						m_comID = args[2];
						m_usrID = args[3];
						break;
				}
			}
			catch (Exception e)
			{
				Console.WriteLine("Message	:n" + e.Message);
				Console.WriteLine("Type	   :n" + e.GetType().FullName);
				Console.WriteLine("StackTrace :n" + e.StackTrace.ToString());
				return false;
			}
			return true;
		}

		//クッキーコンテナ取得のため、このツールで普通にログインする
		//この場合、ブラウザなど、他のツールのログインは解除される。
		static bool LoginForCokkieContainer()
		{
			try
			{
				string url = "https://secure.nicovideo.jp/secure/login?site=nicolive";

				//ログイン・ページへのアクセスパラメタ
				Hashtable vals = new Hashtable();
				//vals["next_url"] = "recent?tab=common";
				vals["next_url"] = "";
				vals["mail"] = m_mail;
				vals["password"] = m_pass;

				//パラメタを"param1=value1&param2=value2"の形にまとめる
				string param = "";
				foreach (string k in vals.Keys)
				{
					param += String.Format("{0}={1}&", k, vals[k]);
				}
				byte[] data = Encoding.ASCII.GetBytes(param);

				//HTTP POSTリクエストの作成
				m_cc = new CookieContainer(); //認証用クッキーを格納するコンテナ
				HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
				req.Method = "POST";
				req.ContentType = "application/x-www-form-urlencoded";
				req.ContentLength = data.Length;
				req.CookieContainer = m_cc;

				//POSTを実行
				Stream reqStream = req.GetRequestStream();
				reqStream.Write(data, 0, data.Length);
				reqStream.Close();

				//HTTP GETによるクッキーの取得
				//GET実行
				WebResponse res = req.GetResponse();
				Stream resStream = res.GetResponseStream();

				Encoding encoder = Encoding.GetEncoding("UTF-8");
				StreamReader sr = new StreamReader(resStream, encoder);
				string xml = sr.ReadToEnd();
				sr.Close();
				resStream.Close();

				//Console.WriteLine("○ログインAPIレスポンス取得");
				//Console.WriteLine(xml);//表示
				//Console.WriteLine();

				//XMLファイル保存サンプル
				//StreamWriter sw = new StreamWriter(@"C:hogeNicoLiveOneCommentGetter.log");
				//sw.Write(xml);
				//sw.Close();
			}
			catch (Exception e)
			{
				Console.WriteLine("Message	:n" + e.Message);
				Console.WriteLine("Type	   :n" + e.GetType().FullName);
				Console.WriteLine("StackTrace :n" + e.StackTrace.ToString());
				return false;
			}
			return true;
		}

		//ログインAPIを叩く(認証API(要ログイン)叩く用)
		static bool LoginForGetAlertStatus()
		{
			try
			{
				string url = "https://secure.nicovideo.jp/secure/login?site=nicolive_antenna";

				//ログイン・ページへのアクセスパラメタ
				Hashtable vals = new Hashtable();
				vals["mail"] = m_mail;
				vals["password"] = m_pass;

				//パラメタを"param1=value1&param2=value2"の形にまとめる
				string param = "";
				foreach (string k in vals.Keys)
				{
					param += String.Format("{0}={1}&", k, vals[k]);
				}
				byte[] data = Encoding.ASCII.GetBytes(param);

				//HTTP POSTリクエストの作成
				//m_cc = new CookieContainer(); //認証用クッキーを格納するコンテナ
				HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
				req.Method = "POST";
				req.ContentType = "application/x-www-form-urlencoded";
				req.ContentLength = data.Length;
				//req.CookieContainer = m_cc;

				//POSTを実行
				Stream reqStream = req.GetRequestStream();
				reqStream.Write(data, 0, data.Length);
				reqStream.Close();

				//HTTP GETによるクッキーの取得
				//GET実行
				WebResponse res = req.GetResponse();
				Stream resStream = res.GetResponseStream();

				Encoding encoder = Encoding.GetEncoding("UTF-8");
				StreamReader sr = new StreamReader(resStream, encoder);
				string xml = sr.ReadToEnd();
				sr.Close();
				resStream.Close();

				Console.WriteLine("○ログインAPIレスポンス取得");
				Console.WriteLine(xml);//表示
				Console.WriteLine();

				//上記の例として、以下のようなXMLが返ってくる、
				//<ticket>チケット</ticket>を取得する
				//<?xml version="1.0" encoding="utf-8"?>
				//<nicovideo_user_response status="ok">
				//<ticket>nicolive_antenna_42613614798762701880494232</ticket>
				//</nicovideo_user_response>

				//XML解析
				XmlDocument xdoc = new XmlDocument();
				xdoc.LoadXml(xml);
				XmlElement root = xdoc.DocumentElement;
				string status = root.Attributes[0].Value;
				if (status != "ok")
				{
					Console.WriteLine("×ログインに失敗しました");
					return false;
				}
				XmlNodeList tickets = root.GetElementsByTagName("ticket");
				m_ticket = tickets[0].InnerText;

				//表示
				Console.WriteLine("○ログイン情報");
				Console.WriteLine("  ログイン   " + status);
				Console.WriteLine("  チケット   " + m_ticket);
				Console.WriteLine();
			}
			catch (Exception e)
			{
				Console.WriteLine("Message	:n" + e.Message);
				Console.WriteLine("Type	   :n" + e.GetType().FullName);
				Console.WriteLine("StackTrace :n" + e.StackTrace.ToString());
				return false;
			}
			return true;
		}

		//認証API
		static bool GetAlertStatus()
		{
			try
			{
				string url = "http://live.nicovideo.jp/api/getalertstatus?ticket=" + m_ticket;

				//XML取得
				System.Net.WebClient wc = new System.Net.WebClient();
				wc.Encoding = System.Text.Encoding.UTF8;
				string xml = wc.DownloadString(url);
				wc.Dispose();
				Console.WriteLine("○認証API(getalertstatus)レスポンス取得");
				Console.WriteLine(xml);//表示

				//上記の例として、以下のようなXMLが返ってくる
				//サーバ情報は<addr>, <port>, <thread>から取得する
				//参加コミュも判明する
				//<getalertstatus status="ok" time="1293425828">
				//<user_id>426136</user_id>
				//<user_hash>A_bCdEfGhiJkLmN_OpQ</user_hash>
				//<user_name>ロフトくん</user_name>
				//<user_prefecture>99</user_prefecture>
				//<user_age>3</user_age>
				//<user_sex>1</user_sex>
				//<is_premium>1</is_premium>
				//
				//<communities>
				//<community_id>co247262</community_id>
				//<community_id>co*****</community_id>
				//<community_id>co*****</community_id>
				//<community_id>co*****</community_id>
				//<community_id>co*****</community_id>
				//<community_id>co*****</community_id>
				//<community_id>co******</community_id>
				//<community_id>co*****</community_id>
				//</communities>
				//
				//<ms>
				//<addr>twr01.live.nicovideo.jp</addr>
				//<port>2533</port>
				//<thread>1000000016</thread>
				//</ms>
				//</getalertstatus>

				//XML解析
				XmlDocument xdoc = new XmlDocument();
				xdoc.LoadXml(xml);
				XmlElement root = xdoc.DocumentElement;
				XmlNodeList ms = root.GetElementsByTagName("ms");

				//余談だが、ms.Countは常に0と想定し、ms[0]のみ読む。
				m_addr = ms[0].ChildNodes[0].InnerText;
				m_port = ms[0].ChildNodes[1].InnerText;
				m_thread = ms[0].ChildNodes[2].InnerText;

				//表示
				Console.WriteLine("○番組開始情報サーバ情報");
				Console.WriteLine("  アドレス   " + m_addr);
				Console.WriteLine("  ポート	 " + m_port);
				Console.WriteLine("  スレッドID " + m_thread);
				Console.WriteLine();
			}
			catch (Exception e)
			{
				Console.WriteLine("Message	:n" + e.Message);
				Console.WriteLine("Type	   :n" + e.GetType().FullName);
				Console.WriteLine("StackTrace :n" + e.StackTrace.ToString());
				return false;
			}
			return true;
		}

		//認証API(getalertinfo)を叩く
		static bool GetAlertInfo()
		{
			try
			{
				string url = "http://live.nicovideo.jp/api/getalertinfo";

				//XML取得
				System.Net.WebClient wc = new System.Net.WebClient();
				wc.Encoding = System.Text.Encoding.UTF8;
				string xml = wc.DownloadString(url);
				wc.Dispose();
				Console.WriteLine("○認証API(getalertinfo)レスポンス取得");
				Console.WriteLine(xml);//表示

				//上記の例として、以下のようなXMLが返ってくる、
				//サーバ情報は<addr>, <port>, <thread>から取得する
				//<getalertstatus status="ok" time="1293371009">
				//<user_id>Anonymous</user_id>
				//<user_hash>-CS4mPdPnMXL8cQJ2g4QakgwvuQ</user_hash>
				//  <ms>
				//	<addr>twr02.live.nicovideo.jp</addr>
				//	<port>2533</port>
				//	<thread>1000000017</thread>
				//  </ms>
				//</getalertstatus>

				//XML解析
				XmlDocument xdoc = new XmlDocument();
				xdoc.LoadXml(xml);
				XmlElement root = xdoc.DocumentElement;
				XmlNodeList ms = root.GetElementsByTagName("ms");

				//余談だが、ms.Countは常に0と想定し、ms[0]のみ読む。
				m_addr = ms[0].ChildNodes[0].InnerText;
				m_port = ms[0].ChildNodes[1].InnerText;
				m_thread = ms[0].ChildNodes[2].InnerText;

				//表示
				Console.WriteLine("○サーバ情報");
				Console.WriteLine("  アドレス   " + m_addr);
				Console.WriteLine("  ポート	 " + m_port);
				Console.WriteLine("  スレッドID " + m_thread);
				Console.WriteLine();

			}
			catch (Exception e)
			{
				Console.WriteLine("Message	:n" + e.Message);
				Console.WriteLine("Type	   :n" + e.GetType().FullName);
				Console.WriteLine("StackTrace :n" + e.StackTrace.ToString());
				return false;
			}
			return true;
		}

		//番組情報取得
		static bool GetProgramInfo()
		{
			try
			{
				//ホスト名からIPアドレスを取得
				IPAddress hostadd = Dns.GetHostEntry(m_addr).AddressList[0];
				//IPEndPointを取得
				IPEndPoint ephost = new IPEndPoint(hostadd, int.Parse(m_port));
				//Socketの作成
				System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(
					System.Net.Sockets.AddressFamily.InterNetwork,
					System.Net.Sockets.SocketType.Stream,
					System.Net.Sockets.ProtocolType.Tcp);
				//接続
				sock.Connect(ephost);

				//リクエストメッセージを送信
				//注)最後に'\0'を挿入しないとレスポンスは返ってこない
				string param = String.Format("<thread thread=\"{0}\" version=\"20061206\" res_from=\"-1\"/>\0", m_thread);
				byte[] data = Encoding.UTF8.GetBytes(param);
				sock.Send(data, data.Length, System.Net.Sockets.SocketFlags.None);

				//受信する
				const int MAX_RECEIVE_SIZE = 1024 * 100;
				string prev = "";
				while (m_AlertCount < m_MaxAlertCount)
				{
					byte[] resBytes = new byte[MAX_RECEIVE_SIZE];
					int resSize = sock.Receive(resBytes, resBytes.Length, System.Net.Sockets.SocketFlags.None);
					if (resSize == 0)
					{
						break;
					}
					string xml = prev + Encoding.UTF8.GetString(resBytes, 0, resSize);
					Console.WriteLine("○データ受信(" + resSize.ToString() + "byte)");
					//Console.WriteLine(xml);//全受信XML表示

					//XML解析
					//<thread hoge />\0<chat>情報</chat>\0<chat>情報</chat>\0の形で受信する
					//<thread hoge />は捨て、<chat>情報</chat>から情報を取り出す
					xml = xml.Replace('\0', '\n');
					string[] lines = xml.Split('\n');
					foreach (string line in lines)
					{
						Console.WriteLine(line);//受信XML表示(1行)
						if (line != "" && !line.EndsWith(">"))
						{
							//MAX_RECEIVE_SIZEいっぱいに受信した場合等
							//XMLが閉じていない場合は次回Receive時結合する
							prev = line;
							break;
						}
						if (line.StartsWith("<chat"))
						{
							//<chat>ここ</chat>を取り出す
							XmlDocument xdoc = new XmlDocument();
							xdoc.LoadXml(line);
							string[] infos = xdoc.InnerText.Split(',');
							if (infos.Length != 3)
							{
								//番組通知が1分間行われなかったときに発行されるダミーデータ
								//chatタグのテキスト部分に現在のUnixタイムが格納されるらしい
								continue;
							}
							Console.WriteLine("  放送   : " + infos[0]);
							Console.WriteLine("  コミュ : " + infos[1]);
							Console.WriteLine("  生主   : " + infos[2]);

							//アラート判定
							if (((infos[1] == m_comID) || (infos[2] == m_usrID))
							  || ((m_comID == "") && (m_usrID == "")))
							{
								//引っかかったら(または最初の放送をターゲットとする場合)ブラウザで開く
								Process.Start("http://live.nicovideo.jp/watch/lv" + infos[0]);

								//番組情報を取得
								if (!GetPlayerStatus(infos[0]))
								{
									break;
								}
								else
								{
									//コメントサーバ接続
									GetCommnet();
								}
								m_AlertCount++;
							}
						}
						if (m_AlertCount >= m_MaxAlertCount)
						{
							break;
						}
					}
				}

				//閉じる
				sock.Shutdown(System.Net.Sockets.SocketShutdown.Both);
				sock.Close();
			}
			catch (Exception e)
			{
				Console.WriteLine("Message	:n" + e.Message);
				Console.WriteLine("Type	   :n" + e.GetType().FullName);
				Console.WriteLine("StackTrace :n" + e.StackTrace.ToString());
				return false;
			}
			return true;
		}

		static bool GetPlayerStatus(string liveID)
		{
			try
			{
				string url = "http://live.nicovideo.jp/api/getplayerstatus?v=lv" + liveID;
				//string url = "http://live.nicovideo.jp/watch/lv" + liveID;

#if ぼつ
				//以下のようにただのDownloadStringでは
				//未ログインと怒られるのでぼつとした
				//XML取得
				System.Net.WebClient wc = new System.Net.WebClient();
				wc.Encoding = System.Text.Encoding.UTF8;
				string xml = wc.DownloadString(url);
				wc.Dispose();
#else
				//HTTP GET リクエストの作成
				//注)本APIから情報取得するには、ログインが必要っぽい
				//   しかし認証用API(要ログイン)はクッキーをくれなかった。
				//  そこで普通のログイン関数にてクッキーコンテナを取得、ここで使用している
				HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
				req.CookieContainer = m_cc;//取得済みのクッキーコンテナ
				WebResponse res = req.GetResponse();
				Stream resStream = res.GetResponseStream();
				StreamReader sr = new StreamReader(resStream, Encoding.UTF8);
				string xml = sr.ReadToEnd();
				sr.Close();
				resStream.Close();
#endif
				//上記の例として、以下のようなXMLが返ってくる。
				//stream : 番組情報
				//user   : リスナー情報(つまりこのツールによるログインアカウント情報)
				//rtmp   : ストリーミング配信情報
				//ms	 : サーバ情報(ここから<addr>, <port>, <thread>を取得する)
				//twitter: Twitter連携情報
				//player : エラー情報?不明
				//<?xml version="1.0" encoding="utf-8"?>
				//<getplayerstatus status="ok" time="1293429226">
				//  <stream>
				//	<id>lv********</id>
				//	<watch_count>0</watch_count>
				//	<title>【初見】○○の雑談枠【歓迎】</title>
				//	<description>雑談枠です。初見さん歓迎ノ</description>
				//	<comment_count>0</comment_count>
				//	<danjo_comment_mode>0</danjo_comment_mode>
				//	<hqstream>0</hqstream>
				//	<nicoden>0</nicoden>
				//	<relay_comment>0</relay_comment>
				//	<park>1</park>
				//	<bourbon_url></bourbon_url>
				//	<full_video></full_video>
				//	<after_video></after_video>
				//	<before_video></before_video>
				//	<kickout_video></kickout_video>
				//	<header_comment>0</header_comment>
				//	<footer_comment>0</footer_comment>
				//	<plugin_delay></plugin_delay>
				//	<plugin_url></plugin_url>
				//	<plugin_urls/>
				//	<provider_type>community</provider_type>
				//	<default_community>co******</default_community>
				//	<archive>0</archive>
				//	<is_dj_stream>0</is_dj_stream>
				//	<twitter_tag>#eternalplace25</twitter_tag>
				//	<is_owner>0</is_owner>
				//	<owner_id>******</owner_id>
				//	<is_reserved>0</is_reserved>
				//	<base_time>1293429118</base_time>
				//	<open_time>1293429118</open_time>
				//	<end_time>1293431025</end_time>
				//	<start_time>1293429225</start_time>
				//	<telop>
				//	<enable>0</enable></telop>
				//	<ichiba_notice_enable>0</ichiba_notice_enable>
				//	<comment_lock>0</comment_lock>
				//	<background_comment>0</background_comment>
				//	<contents_list>
				//	<contents id="main" disableAudio="0" disableVideo="0" start_time="1293429120">rtmp:rtmp://nlpoca28.live.nicovideo.jp:1935/publicorigin/01/,lv35877379</contents></contents_list>
				//	<press>
				//	<display_lines>-1</display_lines>
				//	<display_time>-1</display_time>
				//	<style_conf/></press>
				//	<is_priority_prefecture></is_priority_prefecture>
				//  </stream>
				//
				//  <user>
				//	<room_label>co******</room_label>
				//	<room_seetno>0</room_seetno>
				//	<userAge>3</userAge>
				//	<userSex>1</userSex>
				//	<userPrefecture>99</userPrefecture>
				//	<nickname>ロフトくん</nickname>
				//	<is_premium>1</is_premium>
				//	<user_id>14174847</user_id>
				//	<hkey></hkey>
				//	<is_join></is_join>
				//	<immu_comment>0</immu_comment>
				//	<can_broadcast>0</can_broadcast>
				//	<can_forcelogin>0</can_forcelogin>
				//	<twitter_info>
				//	<status>disabled</status>
				//	<after_auth>0</after_auth>
				//	<screen_name></screen_name>
				//	<followers_count>0</followers_count>
				//	<is_vip>0</is_vip>
				//	<profile_image_url>http://s.twimg.com/a/******/images/default_profile_6_normal.png</profile_image_url>
				//	<tweet_token>b6c1c673652a5471df98ca3c4909860c14377caa</tweet_token></twitter_info>
				//  </user>
				//
				//  <rtmp is_fms="1" rtmpt_port="80">
				//	<url>rtmp://nleza08.live.nicovideo.jp:1935/liveedge/live_101227_14_1</url>
				//	<ticket>******:lv******:0:******:80dfb64e4a643b7b</ticket>
				//  </rtmp>
				//
				//  <ms>
				//	<addr>msg102.live.nicovideo.jp</addr>
				//	<port>2814</port>
				//	<thread>1062357715</thread>
				//  </ms>
				//  <tid_list/>
				//
				//  <twitter>
				//	<live_enabled>1</live_enabled>
				//	<vip_mode_count>10000</vip_mode_count>
				//	<live_api_url>http://watch.live.nicovideo.jp/api/</live_api_url>
				//  </twitter>
				//
				//  <player>
				//	<error_report>1</error_report>
				//  </player>
				//</getplayerstatus>

				//XML解析
				XmlDocument xdoc = new XmlDocument();
				xdoc.LoadXml(xml);
				XmlElement root = xdoc.DocumentElement;
				//番組情報
				XmlNodeList stream = root.GetElementsByTagName("stream");
				//m_base_time = stream[0].ChildNodes[28].InnerText; //仕様変更のたびにずれるのでぼつ
				foreach (XmlNode node in stream[0].ChildNodes)
				{
					if (node.Name == "base_time")
					{
						m_base_time = node.InnerText;
					}
				}

				//user情報
				//m_userid = user[0].ChildNodes[7].InnerText;//仕様変更のたびにずれるのでぼつ
				XmlNodeList user = root.GetElementsByTagName("user");
				foreach (XmlNode node in user[0].ChildNodes)
				{
					if (node.Name == "user_id")
					{
						m_userid = node.InnerText;
					}
				}

				//サーバ情報
				XmlNodeList ms = root.GetElementsByTagName("ms");
				//余談だが、ms.Countは常に0と想定し、ms[0]のみ読む。
				m_ComSrvAddr = ms[0].ChildNodes[0].InnerText;
				m_ComSrvPort = ms[0].ChildNodes[1].InnerText;
				m_ComSrvThread = ms[0].ChildNodes[2].InnerText;

				//表示
				Console.WriteLine();
				Console.WriteLine("○ユーザ情報");
				Console.WriteLine("  ユーザID   " + m_userid);
				Console.WriteLine("○コメントサーバ情報");
				Console.WriteLine("  アドレス   " + m_ComSrvAddr);
				Console.WriteLine("  ポート	 " + m_ComSrvPort);
				Console.WriteLine("  スレッドID " + m_ComSrvThread);
				Console.WriteLine();
			}
			catch (Exception e)
			{
				Console.WriteLine();
				Console.WriteLine("×コメントサーバ情報");
				Console.WriteLine("  情報取得失敗");
				Console.WriteLine("Message	:n" + e.Message);
				Console.WriteLine("Type	   :n" + e.GetType().FullName);
				Console.WriteLine("StackTrace :n" + e.StackTrace.ToString());
				return false;
			}
			return true;
		}

		//コメントサーバ接続
		static bool GetCommnet()
		{
			try
			{
				//ホスト名からIPアドレスを取得
				IPAddress hostadd = Dns.GetHostEntry(m_ComSrvAddr).AddressList[0];
				//IPEndPointを取得
				IPEndPoint ephost = new IPEndPoint(hostadd, int.Parse(m_ComSrvPort));
				//Socketの作成
				System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(
					System.Net.Sockets.AddressFamily.InterNetwork,
					System.Net.Sockets.SocketType.Stream,
					System.Net.Sockets.ProtocolType.Tcp);
				//接続
				sock.Connect(ephost);

				//コメントリクエストメッセージを送信
				//注)最後に'\0'を挿入しないとレスポンスは返ってこない
				string param = String.Format("<thread thread=\"{0}\" version=\"20061206\" res_from=\"-100\"/>\0", m_ComSrvThread);
				byte[] data = Encoding.UTF8.GetBytes(param);
				sock.Send(data, data.Length, System.Net.Sockets.SocketFlags.None);

				//受信する
				const int MAX_RECEIVE_SIZE = 1024;
				string prev = "";
				while (true)
				{
					byte[] resBytes = new byte[MAX_RECEIVE_SIZE];
					int resSize = sock.Receive(resBytes, resBytes.Length, System.Net.Sockets.SocketFlags.None);
					if (resSize == 0)
					{
						break;
					}
					string xml = prev + Encoding.UTF8.GetString(resBytes, 0, resSize);
					//Console.WriteLine("○データ受信(" + resSize.ToString() + "byte)");
					//Console.WriteLine(xml);
					//Console.WriteLine();
					//XML解析
					//<thread hoge />\0<chat>情報</chat>\0<chat>情報</chat>\0の形で受信する
					//<thread hoge />は捨て、<chat>情報</chat>から情報を取り出す
					xml = xml.Replace('\0', '\n');
					string[] lines = xml.Split('\n');
					foreach (string line in lines)
					{
						Console.WriteLine(line);//受信XML表示(1行)
						if (line != "" && !line.EndsWith(">"))
						{
							//MAX_RECEIVE_SIZEいっぱいに受信した場合等
							//XMLが閉じていない場合は次回Receive時結合する
							prev = line;
							break;
						}
						//<thread hoge="hoge">は初回送られてくる
						if (line.StartsWith("<thread"))
						{
							//チケット、コメントサーバー時刻取得
							//<thread ticket="チケット" server_time="サーバー時刻" hoge="hoge">を取得
							string ticket = "";
							string server_time = "";
							XmlDocument xdoc = new XmlDocument();
							xdoc.LoadXml(line);
							XmlElement root = xdoc.DocumentElement;
							foreach (XmlAttribute attrib in root.Attributes)
							{
								if (attrib.Name == "ticket")
								{
									ticket = attrib.Value;
								}
								if (attrib.Name == "server_time")
								{
									server_time = attrib.Value;
								}
							}
							if ((ticket == "") || (server_time == ""))
							{
								return false;
							}
							//コメント処理開始時刻
							m_DateTimeStart = DateTime.Now;

							//vpos(放送経過時間[sec]*100)を算出
							//コメントサーバ開始時間
							Int64 serverTimeSpan = Int64.Parse(server_time) - Int64.Parse(m_base_time);
							//コメント投稿時間(1コメゲッターなのでここでは0secですね)
							Int64 localTimeSpan = GetUnixTime(DateTime.Now) - GetUnixTime(m_DateTimeStart);
							string vpos = ((serverTimeSpan + localTimeSpan) * 100).ToString();

							//postkeyを取得
							if (!GetPostKey())
							{
								return false;
							}

							//コメント投稿(1コメ)
							//注)最後に'\0'を挿入する
							param = String.Format("<chat thread=\"{0}\" ticket=\"{1}\" vpos=\"{2}\" postkey=\"{3}\" mail=\" 184\" user_id=\"{4}\" premium=\"1\">わくおつ</chat>\0"
								, m_ComSrvThread
								, ticket
								, vpos
								, m_postkey
								, m_userid);
							data = Encoding.UTF8.GetBytes(param);
							sock.Send(data, data.Length, System.Net.Sockets.SocketFlags.None);
							Console.WriteLine("○投稿します");
							Console.WriteLine(param);
						}
						if (line.StartsWith("<chat_result"))
						{
							//コメント投稿結果
							//<chat>ここ</chat>を取り出す
							Console.WriteLine("(投稿応答)");
							Console.WriteLine();
						}
						if (line.StartsWith("<chat "))
						{
							//コメント取得
							//<chat>ここ</chat>を取り出す
							XmlDocument xdoc = new XmlDocument();
							xdoc.LoadXml(line);
							Console.WriteLine(xdoc.InnerText);
						}
					}
				}
			}
			catch (Exception e)
			{
				Console.WriteLine("Message	:n" + e.Message);
				Console.WriteLine("Type	   :n" + e.GetType().FullName);
				Console.WriteLine("StackTrace :n" + e.StackTrace.ToString());
				return false;
			}
			return true;
		}
		//Unixタイムに変換
		public static Int64 GetUnixTime(DateTime targetTime)
		{
			TimeSpan elapsedTime = targetTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0);
			return (Int64)elapsedTime.TotalSeconds;
		}

		//postkey取得
		static bool GetPostKey()
		{
			try
			{
				//注)
				//block_no = 最新コメント番号(レス番) ÷ 100
				//らしい。1コメゲッタなので0にしてる。
				string url = "http://live.nicovideo.jp/api/getpostkey?thread=" + m_ComSrvThread + "&block_no=0";

				//HTTP GET リクエストの作成
				HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
				req.CookieContainer = m_cc;//取得済みのクッキーコンテナ
				WebResponse res = req.GetResponse();
				Stream resStream = res.GetResponseStream();
				StreamReader sr = new StreamReader(resStream, Encoding.UTF8);
				string text = sr.ReadToEnd();
				sr.Close();
				resStream.Close();
				//応答はプレーンテキストで
				//postkey=ergerwhg54hy4wfwegrghg
				//のように返ってくる
				m_postkey = text.Substring(8, text.Length - 8);
			}
			catch (Exception e)
			{
				Console.WriteLine("Message	:n" + e.Message);
				Console.WriteLine("Type	   :n" + e.GetType().FullName);
				Console.WriteLine("StackTrace :n" + e.StackTrace.ToString());
				return false;
			}
			return true;
		}
	}
}

続編(Webブラウザとクッキーを共有)も御覧下さい。


49 thoughts on “ニコ生アラート + コメントビューア + 1コメゲット ツールを作る(C#) その1

  1. はじめまして。 上記のコードを 全部ひとつのテキストにまとめ、csc.exeコンパイラでコンパイルしようとしたところ以下のエラーが出てしまいます

    a.cs(341,5): warning CS0168: The variable ‘e’ is declared but never used

    341-345行めあたりはこの部分でした

    Console.WriteLine(” スレッドID ” + m_thread);
    Console.WriteLine();
    }
    catch (Exception e)

    何か間違っていましたらご教授願います。

  2. >#1 by unknownさん
    こんにちわ。
    warning CS0168 は、未使用の変数がある場合の警告ですので、他にエラーメッセージがなければ、
    正常にコンパイルできていると思います。a.exeを探してみてください。

    ご参考までに、a.exeの出力先を指定する構文を載せておきます。
    構文)
    csc /out:”出力exe名” “入力ソース名”

    例)
    csc /out:”C:hogea.exe” “C:hogea.cs”

    また、ニコ生のAPI(GetPlayerStatus)に、ニコニコ電話/ニコ生セッション♪の戻り値が追加されていたので、
    関数GetPlayerStatus()を修正していますのでご確認下さい。(ついでにwarning CS0168対応もやってます^^ノ)

  3. お世話になります。修正ありがとうございます!
    コンパイルも無事できました。

    出来上がったexeへのショートカットを下記のように作り、コミュ指定なしでテストしてみました。

    C:WINDOWSMicrosoft.NETFrameworkv2.0.50727a.exe hoge@mail.com pass

    自動でブラウザが立ち上がり、生放送のURLが出るまではいいのですが、事前にログイン中でもログインがされていない状態になっていて、ID/PASSを入れてログインないとコメントが打てないようです。(ログインすると直後に1GETが打てていました)

    IE/Firefox共に同じ症状だったのですが、何か解決策がありましたらよろしくお願い致します。

    また、exeに指定するID/PASSは、普段使用しているものと別のものを指定したほうがよいのでしょうか? どこかで聞いたのは、ひとつのPCで複数ログイン可能なID/PASSは2つまでで、それ以上だと回線が切れる、という情報でした。(同IDでも生放送を3窓開くと1つが切れてしまうことも)

    通常使用しながらこのexeを同時IDで常駐させておくことも可能でしょうか? 

  4. Pingback: ニコ生アラート + コメントビューア + 1コメゲット ツールを作る(C#) その2 « 夏研ブログ

  5. >#3 by unknownさん
    こんにちわ。無事コンパイルできてよかったです。

    このツールがニコ生にログインすると、
    それまでログインしていた別のツール(ブラウザ)は、
    自動的にログアウトしてしまいます。

    そこで、クッキー取得ライブラリを利用し、
    既にログイン済みのブラウザからクッキーをもらうように改造してみました。
    別途dllを組み込む必要がありますが、ブラウザがログアウトすることがなくなります。

    ニコ生アラート + コメントビューア + 1コメゲット ツールを作る(C#) その2
    http://c-loft.com/blog/?p=1127
    を参照下さい。

  6. Pingback: rtmpdump.exeでニコ生を保存する « 夏研ブログ

  7. 明けましておめでとうございます。
    よろしくお願い申し上げます。

    質問がありご連絡させていただきました。
    540行目からなのですが
    前の段階でログインが成功しているにも関わらず
    xmlを取得するとnotloginと怒られてしまいます。
    これは何が原因でしょうか?
    クッキーの受け渡しがうまくいってないのかな・・・
    もし、ご都合がよろしければ教えていただけましたら幸いです。

  8. >tentenさん
    明けましておめでとうございます。よろしくお願い致します。

    GetPlayerStatus()のxmlに、notloginと書いてあるので、
    GetPlayerStatus()で使用しているクッキー(変数名m_cc)が
    正しく取れていない(ニコニコにログインできていない)と予測されます。

    m_ccを取得しているメソッドは、LoginForCokkieContainer()です。
    このツールのコマンドライン引数に指定されたメアド・パスワードを使用して
    ニコニコにログインすることで取得しております。
    (通常、ブラウザからニコニコにログインする際にメアド・パスワードを入力する
    処理をこのツールのこのメソッドでやっています。)

    メアド、パスワードが間違っていたりして、ログインに失敗すると、
    m_ccに値は入りますが、正しいクッキーは入りません。

    ログイン成功、失敗の例としてはLoginForCokkieContainer()で取得したxml文字列の中に
    以下が含まれているかどうかで判定できます。

    [成功時]
    ○○さん(○○は自分のユーザ名です。)

    [失敗時(メアド、パスワードが間違っていた場合)]
    入力したメールアドレスまたはパスワードが間違っています

    まずは正常にログイン完了しているか確認してみて下さい。
    (また、このツールにそのようなチェック処理を追加してあげると便利です、ぜひカスタマイズして下さい。)

    ※ちなみにLoginForCokkieContainer()で取得したxmlは、ニコ生トップページのHTML文字列です。このxmlは長文なのでテキストエディタ等にコピペしたほうが見やすいです。さらに改行がされてなくて見にくいので”</”を”\n</”に置換するなど整形して見た方がよいです。(<は半角))

    ※本ツールからニコニコ動画にログインすると、それまでそのアカウントでログインしていたブラウザはログアウトしてしまいますのでご注意下さい。
    続編 http://c-loft.com/blog/?p=1127 ではブラウザとクッキーを共有することでブラウザのログアウトを防ぐ方法を紹介しております。

  9. dll入れてみました。ありがとうございます。
    プログラムもすっきりして非常にいいですね。
    ちなみに、
    CookieGetterSharpDistribution20120629
    を入れてみましたが

    comboBox1.Items.AddRange(CookieGetter.CreateInstances(true));

    とし

    ICookieGetter cookieGetter = CookieGetter.CreateInstance((CookieStatus)comboBox1.SelectedItem);

    としたら

    型 ‘System.NullReferenceException’ のハンドルされていない例外が CookieGetterSharp.dll で発生しました
    追加情報: オブジェクト参照がオブジェクト インスタンスに設定されていません。

    とエラーになりました。作者さんに質問したいのですが
    ニコニココミュニティで質問して教えていただけるものなのか・・・
    2013年はじまったばかりだしがんばります。

  10. >tentenさん
    こんにちは。
    私が以前開発したGUIアプリでは以下のようにしています。

    ・コンボボックスの初期化
    コンボボックスにブラウザタイプを順番に追加しています。
    AddRangeで一気に追加もいけそうかも。

                //ブラウザ選択欄
                //列挙型BrowserTypeのメンバを全て指定
                Array arr = Enum.GetValues(typeof(BrowserType));
                foreach (BrowserType type in arr)
                {
                    comboBoxBrowser.Items.Add(type);
                }
    

    ・クッキー取得
    コンボボックスの選択indexをブラウザタイプにキャストして
    CookieGetter.CreateInstance()に指定しています。

                    //選択されたブラウザタイプ
                    BrowserType type = (BrowserType)comboBoxBrowser.SelectedIndex;
                   //クッキー取得
                    ICookieGetter cookieGetter = CookieGetter.CreateInstance(type);
                    Cookie user_session = null;
                    //ニコニコのクッキー取得(URL文字列はブログに貼り付けるとリンクのHTMLタグが表示されちゃうので回避のため分離してます)
                    user_session = cookieGetter.GetCookie(new Uri("http:// + "live.nicovideo.jp/"), "user_session");
                    if (user_session == null)
                    {
                        //失敗処理
                    }
                    else
                    {
                        //成功処理
                        m_cc = new CookieContainer();
                        m_cc.Add(user_session);
                    }
    

    CookieGetterの細かい挙動については作者さんにお尋ねしてみるのが
    よいかと思います。参考になりましたら幸いです。

  11. 非常にご丁寧な返信を頂き、誠にありがとうございます。
    お陰さまで成功しました。
    今後ともよろしくお願いいたします。

  12. >tenten さん
    こんにちは。ツール制作の参考になりましたら幸いです。
    おもしろツールの登場に期待しています^^

  13. 立て続けに質問失礼します。

    これを送信したところ(res_fromは1も試しました。)
    そうしたところ

    応答がこれしかなく<chat・・・
    で始まるコメントの取得ができません。
    何故なんでしょうか?
    よろしくお願い申し上げます。

    • あれ、タグが消えてる・・・
      もう一度書き直します。

      <thread thread=”**********” version=”20061206″ res_from=”0″ />

      これを送信しました。(res_fromは1も試しました。)
      そうしたところ

      <thread resultcode=”0″ thread=”**********” last_res=”3″ ticket=”0x******** revision=”1″ server_time=”1357216263″/>

      応答がこれしかなく<chat・・・
      で始まるコメントの取得ができません。
      何故なんでしょうか?
      よろしくお願い申し上げます。

  14. >tentenさん
    こんにちは。
    resultcode=”0″が返ってきているのでいちおう正常に<thread thread=・・・を送信できているように見えます。
    (なので、放送にコメントが投稿されれば、<chat・・・で始まるコメントを受信できそうに思えます。)

    本ブログ記事掲載の(正確には続編( http://c-loft.com/blog/?p=1127 )の)ソースコード(オリジナルソース)はそのままお使いでしょうか?
    こちらの環境で、オリジナルソースコード+以下dll使用で1コメ投稿、コメント受信を動作確認済です。
     CookieGetterSharpDistribution20120629
      \CookieGetterSharpDistribution20120629
       \ankoSQLite
        \NET2
         \CookieGetterSharp.dll
         \ankoSQLite3.dll
    それともオリジナルソースを部分的に流用したり、独自改造されていますか??

    1. オリジナルソースをそのまま使用しているのに動かない場合
    動作環境(プレ/一般アカウントとかコミュ限放送とかもろもろ)の違いが疑われます。
    2. オリジナルソースを部分的に流用したり、独自改造された場合
    環境の違いに加えて改造による影響も発生します。

    まずはオリジナルソースでコメントが受信できているかをお試し下さい。
    流用・改造はその動作確認後に徐々に加えていくとよいかと思います。

  15. ご返信ありがとうございます。
    改造というよりは、コメント送信前にまずは取得だと思い
    できうる限りコードを削って最も単純化したものにしていました。
    それで駄目になったみたいです。
    おそらく
    xml = xml.Replace(”, ‘\n’);
    これを抜いていたのが原因だと思います。

  16. また、続けざまで質問申し訳ないです。
    マルチポストでうつろさんのコミュの掲示板で質問してみたのですが
    お忙しいのかお返事を頂けませんでしたので、
    大変失礼だとは承知していますが
    ご容赦いただけますようお願い申し上げます。

  17. ユーザプロフィールページを取得したいのですが

    //既にログインしているブラウザのクッキー共有
    CookieCollection collection = CookieGetter.CreateInstance((BrowserType)comboBox1.SelectedIndex).GetCookieCollection(new Uri(textBoxurl.Text));
    CookieCollection m_cc = new CookieContainer();
    m_cc.Add(collection[“user_session”]);

  18. //ユーザページ取得
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(ユーザーページアドレス);
    req.Method = “POST”;
    req.ContentType = “application/x-www-form-urlencoded”;
    req.CookieContainer = m_cc;

    using (StreamReader sr = new StreamReader(req.GetRequestStream(), Encoding.GetEncoding(“UTF-8”)))←ここでエラー
    {
    string html = sr.ReadToEnd();
    }

    型 ‘System.ArgumentException’ の初回例外が mscorlib.dll で発生しました
    追加情報: ストリームを読み取れませんでした。
    この例外のハンドラーがある場合は、プログラムを安全に続行できます。

    とエラーになってしまいます。
    もし、ご都合がよろしければ教えていただけましたら幸いです。

  19. リンクがひっかかって正常に書き込みできなかったみたいです。
    連投申し訳ございません。

  20. >tentenさん
    こんにちは。
    (ちょっとコメントのスパム判定の設定が厳しすぎるかもしれませんね。)

    ユーザページのHTMLを取得したい場合は、HTTP GETリクエストで取得できます。(書き込み頂いたコードはHTTP POSTリクエストのコードのようです。)
    関数GetPlayerStatus()の以下部分でHTTP GETを実施しているので真似してみて下さい。
    POSTとGETは似ているようで微妙に使っているメソッドが異なります。

    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
    req.CookieContainer = m_cc;//取得済みのクッキーコンテナ
    WebResponse res = req.GetResponse();
    Stream resStream = res.GetResponseStream();
    StreamReader sr = new StreamReader(resStream, Encoding.UTF8);
    string xml = sr.ReadToEnd();
    sr.Close();
    resStream.Close();
    
  21. ありがとうございます。できました。
    無闇に複雑にしてたんですね・・・
    助かりました。

  22. お世話になっております。
    postkeyの取得でつまずいてしまいました。
    block_no=0にしてみましたが
    ———
    postkey=
    ———
    こんな風にしか取得できないです。
    試しに1コメしてblock_no=1
    にしても同様でした。
    ブラウザから見たら普通に取得できるんですが。
    もし、ご都合がよろしければ教えていただけましたら嬉しいです。

  23. 自己解決しました。
    ただ、意味が理解できていません。

    req = (HttpWebRequest)WebRequest.Create(“live.nicovideo.jp/api/getpostkey?thread=” + m_ComSrvThread + “&block_no=0”);
    req.CookieContainer = m_cc;//取得済みのクッキーコンテナ

    このようにするとうまくいくのです。

    req.CookieContainer = m_cc;//取得済みのクッキーコンテナ
    req = (HttpWebRequest)WebRequest.Create(“live.nicovideo.jp/api/getpostkey?thread=” + m_ComSrvThread + “&block_no=0”);

    こうだとだめでした。
    クッキーってページ取得前に設定するものだとばかり
    考えていましたが違うようです。

    それと、今のpostkeyの仕様が変わったせいか
    text.Substring(8, text.Length – 8);
    このようにすると

    型 ‘System.ArgumentOutOfRangeException’ のハンドルされていない例外が mscorlib.dll で発生しました

    追加情報: startIndex に文字列の長さより大きい値を指定することはできません。

    こんなエラーが帰ってきます。

  24. ごめんなさいエラーはこっちが正しいです

    型 ‘System.ArgumentOutOfRangeException’ のハンドルされていない例外が mscorlib.dll で発生しました

    追加情報: 長さを 0 未満にすることはできません。

  25. >tentenさん
    こんにちは。

    req.CookieContainer = m_cc;//取得済みのクッキーコンテナ
    req = (HttpWebRequest)WebRequest.Create(“live.nicovideo.jp/api/getpostkey?thread=” + m_ComSrvThread + “&block_no=0″);

    上記記述の場合は、2行目でreqが新規で上書きされてしまうので、
    1行目で代入したクッキーは消えてしまいます。

    text.Substring(8, text.Length – 8);がエラーするのは、
    textに入っている文字が短すぎる(text.Lengthが8より小さい)場合が考えられます。
    エラーする際にtextに何が入っているか確認してみて下さい。

  26. お世話様でございます。昨日は大変失礼いたしました。
    ソースの内容がだんだん理解できて来ました。
    そこで、またなのですが
    184のuser_idはどのように取得していますでしょうか?
    見てたらどこで取得できるものなのか理解できなかったです。
    ご都合がよろしければ教えていただけましたら嬉しいです。

  27. 更新してなかったのでご返信を拝見していなかったです。
    postkeyに関しては
    using (StreamReader sr = new StreamReader(req.GetResponse().GetResponseStream(), Encoding.UTF8))
    {
    m_postkey = Regex.Replace(sr.ReadToEnd(), “postkey=”, “”);
    }

    こんな感じでただ置換するだけでいけました。
    ありがとうございまうす。

  28. >tentenさん
    こんにちは。
    自分のuser_idでしたらGetPlayerStatus()にて、
    変数m_useridに格納しています。

  29. ロフトさん、ありがとうございます。
    そこなのですが、生IDしか取得できず184IDが出てこないのです。
    一度、本家のプレーヤーにて184で投稿するにチェックを入れてから
    取得してみたのですが、やはり生IDしか出てこないのです。

    ちなみにuse_idを生IDとしmailに184を入れて投稿した場合は
    生IDでの投稿となりました。

  30. >tentenさん
    こんにちは。
    (自分の投稿を送信後、)受信したコメの内、yourpost=”1″が付いているコメントが自分のコメントです。
    以下のようなデータが受信されると思います。

    <chat thread=”********” no=”****” vpos=”*****” date=”********” date_usec=”*****” mail=”184″ yourpost=”1″ user_id=”ABCDEFGH” premium=”**” anonymity=”1″ score=”**”>わくおつ

  31. 1コメゲッターの最新版をダウンロードしてIeを選択して情報を取得するボタンを押したのですが1つもコミュがでてきません・・・ 使用ブラウザはIEです。

  32. >メムさん
    こんにちは。ツールのご利用ありがとうございます。
    以下を確認してみて下さい。

    1 ブラウザ(IE)でニコニコのページを開き、ニコニコにログインできていることを確認して下さい。
    2 クッキー共有元ブラウザ欄には、IE系は3つあります。
     IE、IEComponent、IESafemodeの3つがありますので3つとも試してみて下さい。
    3 それでも失敗する場合、以下をお知らせ下さい。
     「参加コミュ情報を取得できませんでした。」というダイアログは出ますか?
    “ログ”タブにエラー内容が記述されていたらその文章を教えて下さい。

    なお、こちらのブログ記事は1コメゲッターの開発方法の紹介ページとなります。
    ニコ生1コメゲッター ニコわんこのサポートは、
    ニコニコミュニティ掲示板、またはTwitterにて行なっております。

    お手数ですが、ご返信はコミュ掲示板に書き込み頂くか、
    Twitterにてloftkunに話しかけて下さい。
      コミュニティ http://com.nicovideo.jp/community/co247262
      Twitter https://twitter.com/loftkun

  33. ロフトさんへ
    ご返信ありがとうございます。
    投稿する前の184取得がうまきいかないのですが
    とりあえずそれは置いときまして

    クッキーゲッターの事なので恐縮ですが
    FireFoxだと
    m_cc.Add(collection[“user_session”]);
    ここでエラーになってしまいます。
    うつろさんにも報告しておきます。

  34. こんにちは、SNAKE(すなけ)です
    一つお聞きしたいのですが
    static bool GetPlayerStatus(string liveID)
    {
    try
    {
    string url = “http://live.nicovideo.jp/api/getplayerstatus?v=lv” + liveID;

    上記のコードでstatic bool GetPlayerStatus(string liveID)の部分のliveIDをtryの中で取得したいのですが
    その場合はどうすればいいですか?

    やりたいことは、ボタンを押した時にlvから始まる放送番号を取得してtextBoxに表示するのをしたいんです

  35. >tentenさん
    こんにちは。
    投稿する前の184取得とはコメントを投稿せずに自分の184IDを知りたいということですか?(自分は方法はちょっと思い当たりません。。。)

  36. >SNAKEさん
    こんにちは。
    tryの中でliveIDを取得したいというのがピンときません。。。
    (提示いただいたソースコードは、既にtryの中でliveIDを使っています。)

  37. すみません・・・tryの中でliveIDを取得したいというのは忘れてください
    private void button1_Click_1(object sender, EventArgs e)
    {

       }
    上記のコードのなかでliveIDを取得したいんです

  38. >SNAKEさん
    こんにちは。
    なるほど、本ブログ記事のサンプルコードのようなCUI(コマンドラインのアプリ)ではなく、GUI(フォームを持つアプリ)を独自に作成されているのですね。
    そうすると、作成されているGUIアプリの構造をお知らせいただかないと、お答えできないです><。
    うpロダにソース一式をうpしていただくか、http://ideone.com/ に貼り付けていただくと何かアドバイスできるかもしれません。

  39. ソース一式をアップロードいたしました、ダウンロードパスワードはツイッターのDMにて送信させていただきます
    http://ux.getuploader.com/Programming_C_language/download/34/%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6.zip
    現在ロフトさんのブログを見て、放送プレビューの部分でIEにログインしてないと
    「ログインしてください」と表示されてしまうのでブラウザクッキー共有できるようにしているのですが、どうすればいいのかわかりません・・・もしお時間がありましたらご教授お願いいたします

  40. ロフトさんへ
    ご返信頂きありがとうございます。
    という事は最初の投稿で生IDでもmailで184フラグを立ててれば
    184IDになるのですか。
    何回かやってみたものの生IDが出てしまってたので
    私のやり方がまずかったかもしれないです。
    ありがとうございます。

  41. ロフトさん、おひさしぶりです。
    私の作っていたソフトも、もうそろそろ完成しそうです。
    ありがとうございます。
    その時は何かしらの形でロフトさんの名前を動画か
    何かに記載したいと思いますがよろしいでしょうか?
    できればコミュかIDを教えていただければ幸いです。
    ナイショ設定なら全然大丈夫ですので。

    それとあれから色々調べてたのですが
    ポストキーはどうやら仕様が変更されたらしく
    100コメごとじゃなく毎回取得し直さないといけないようです。
    また、
    live.nicovideo.jp/api/getalertinfo
    このページなのですが
    はもしかして184IDじゃないでしょうか?
    27文字ですし。
    ちょっと気になりました。よろしくお願いいたします。

  42. >tentenさん
    こんにちは、お久しぶりです。
    完成間近ですか、どんなソフトか楽しみです。
    コミュはこちらです http://com.nicovideo.jp/community/co247262 掲載して頂いてよいですよ。

    live.nicovideo.jp/api/getalertinfoですが、ニコ生アラート用のAPIなので、
    184ではないと思います(多分)。

    ご参考:ニコ生アラート(本家)の仕様とは (ニコナマアラートホンケノシヨウとは) [単語記事] – ニコニコ大百科
    http://dic.nicovideo.jp/a/%E3%83%8B%E3%82%B3%E7%94%9F%E3%82%A2%E3%83%A9%E3%83%BC%E3%83%88%28%E6%9C%AC%E5%AE%B6%29%E3%81%AE%E4%BB%95%E6%A7%98

  43. ロフトさんこんにちは。
    google chromeのデベロッパーツールを使用して解析しようとしたんですが
    コメントを送信した場合何も表示されません。Networkタブで普通ならGETやPOSTのデーターとか表示されるんですがニコ生のコメントの場合何も表示されませんでした。
    ロフトさんは何で解析したんでしょうか?教えていただけると助かります!

  44. >ナナシさん
    こんにちは。
    google chromeのデベロッパーツールは使用したことがないのですが、おおそらくHTTPプロトコルの通信が見れるツールなのですね。

    ニコ生のGetPlayerStatusなどのAPIはHTTP通信なのでデベロッパーツールで見ることができ、
    コメント送受信はプロトコルがHTTPではなくTCP(いわゆるソケット通信)なので、
    TCP通信を表示できるツールでないと見れないのではないかと思います。

    wiresharkというフリーのパケット解析ツールがあります。
    これを使うとHTTPやTCPなどいろいろなプロトコルの通信をのぞき見できます。

    通信全てをキャプチャして表示するツールなので、ログががんがん流れます。
    表示フィルタリング(プロトコルを指定したり、送信元/先を指定したり)の機能やキャプったパケットをファイルに保存する機能等がありますので利用されてみると良いかと思います。
    (お使いのPCが無線LANでしたら通信をキャプるのに設定が必要だったかもしれません、ぐぐってみて下さい。)

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です