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

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

  2. お世話になっております。
    お返事遅れましたが、きちんと動作しております!
    ありがとうございました!

    要望というか、技術的に可能かお聞きしたいのですが
    例えば特定のタグ・放送タイトルをつけている生放送に絞って1GETすることなどは可能でしょうか??

  3. >#1 by unknownさん
    こんにちわ。無事動作とのことよかったです。

    放送タイトルは取得可能です。
    関数GetPlayerStatusで取得しているXMLに含まれています。
    string xmlにgetplayerstatus(ニコ生API)の戻り値のXML全文を格納しています。
    (XMLの構造は、関数GetPlayerStatusのコメントに記載しています。)

    放送タイトルは、このXMLの<stream>タグ内の、<title>放送タイトル</title>に入っています。
    取り出し方は<usr>タグの<user_id>ユーザID</usr_id>の取り出し処理と同様になります。

    現在は、コミュID、生主IDにマッチした放送に対して、GetPlayerStatusを実施していますが、
    これを全番組に対して実施するよう変更し、放送タイトルを監視する改造が必要になります。

    放送タイトルと、任意キーワードとのマッチングは、以下のように実装できます。
    string title = 取り出した放送タイトル;
    if(title.Contains(“キーワード”))
    {
    //キーワードにマッチしたのでこの放送に1コメ送信
    }

    放送のタグについては、今のところ取得できるAPIがないようです。
    (放送カテゴリ(“一般”、”ゲーム”、”やってみた”等)であれば、
    ニコニコ生放送のRSS http://live.nicovideo.jp/recent/rss に載っており、
    <category>ゲーム</category>部分を抜き出すことで取得できます。
    PHPでの実装法を http://c-loft.com/blog/?p=598 に記載しています。)

    ご参考になれば幸いです。

  4. 放送のタグですが、APIがない現状では、放送ページのHTMLから取得するのが正攻法でしょうか、
    以下のようなHTMLになっているようです。
    <a class=”nicopedia” rel=”tag” href=”大百科URL” rel=”nofollow”>タグ名</a>

  5. 放送タグについて、追加情報です。
    APIでは無いですが、以下ページにアクセスすると
    検索結果のHTMLが返ってくるようです。
    http://live.nicovideo.jp/search/検索ワード?kind=tags

    定期的に検索をかけ、返ってきたHTMLから、
    視聴したい番組名やコミュ名、コミュID等でマッチングを
    行うことでアラートツールが作れそうですね。

    サイトのHTML文字列を取得するサンプルは以下に記載しております。
    http://c-loft.com/blog/?p=637

  6. はじめましてコミュニティから来ました。
    コンパイルしてみたんですが
    このようなエラーが返ってきてコンパイル出来ないのですがどうすればいいのでしょうか?

    source.cs(157,40): error CS1002: ; が必要です。
    source.cs(223,98): error CS1026: ) が必要です。
    source.cs(243,40): error CS1002: ; が必要です。
    source.cs(326,40): error CS1002: ; が必要です。
    source.cs(398,40): error CS1002: ; が必要です。
    source.cs(522,57): error CS1026: ) が必要です。
    source.cs(561,40): error CS1002: ; が必要です。
    source.cs(892,40): error CS1002: ; が必要です。

    お時間が相手いる時で結構ですのでよろしくお願いします。

  7. >#5 by 名無しさん
    こんにちわ。お返事遅れてごめんなさい。
    文法エラーの指摘ですので、ソースが書き換わっている可能性があります。
    ソースコード欄右上に、クリップボードにコピーするボタンを設置しました、
    (マウスオーバーで出現します)、一発でコピーできますので使ってみてください。

  8. 返事ありがとうございます
    157行目のところで”の中に”があるの事でエラーをだしているようです。
    コンパイラはVisualStudio 2010、VisualStudio 2008、csc.exeを使ってみましたが同じ結果でした。
    なんども質問してすみません

  9. >#7 by 名無しさん
    こんにちわ。
    エラー箇所は文字列中、文字eがある箇所に一致しているようですね。原因は分かりませんが文字コード周りかな?

    試しにeを含まない適当な文字列(または空文字””)に変えてビルドしてみてください。
    例) string url = “niconico”;

    上記でビルドが通りましたら改めて正しい文字列にしてみて下さい(該当箇所はコピペでなく、手打ちでの入力がいいかもしれません)。

  10. すいません解決しました。
    エラーになってた理由は
    Google Chromeを使っていたせいでした
    Chromeでソースコード欄のURLの部分がstring url = “<a href="http://live.nicovideo.jp…とタグごと表示されていたからでした
    なんども質問してすみませんでした

  11. >#9 by 名無しさん
    こんにちわ。確かにChromeだとHTMLタグが入りますね。
    ソースコードが書き換わるなんて・・・ (ToT)
    ブログの設定で直せないかなー、いじってみます。
    ご報告ありがとうございました。

  12. はじめまして

    クッキーの処理について検索して、こちらのページまでこさせてもらいました。
    「クッキー取得ライブラリ ver3」の使用方法大変わかり易く重宝しました。
    ありがとうございます。

    さて、クッキー取得ライブラリを使わさせていただいて少し疑問点が生じたので、よろしければご教授お願いいただけるでしょうか。

    疑問というのは、

    m_cc = new CookieContainer();
    m_cc.Add(user_session);

    上のコードなのですが、例えば、

    CookieCollection collection = cookieGetter.GetCookieCollection(new Uri(“http://live.nicovideo.jp/”));

    の”http://live.nicovideo.jp/” を ”http://www.google.co.jp/”と変更して、他のクッキーを取得することも可能なのでしょうか?

    いろいろ試してみたのですが、「CookieGetterSharp.dll」自体がニコニコ動画アドレスしか対応していないのかなと思いました。
    お暇なときでよろしいので、お教え願えますでしょうか。
    それでは失礼いたします。

  13. >#11 by あさきゆめみし さん
    こんばんわ。
    お好きなURLを指定できるようです。
    http://d.hatena.ne.jp/halxxxx/20091212/1260649353
    に、ブラウザ、URL、名前を指定してクッキーを取得するサンプルアプリが紹介されています。

    なおFirefox4など、最近登場したブラウザへの対応を、
    http://com.nicovideo.jp/community/co235502
    こちらのコミュニティオーナーの方が実施されています(CookieGetterSharpDistribution20110517)。

  14. おはようございます

    クッキーの取得できました。
    ロフトさんがどんなURLでもクッキーを取得できると教えてくれなければ、諦めてかけてました。ありがとうございます。

    最新ブラウザ対応については、今朝ダウンロードしました。
    とりあえず、今のコードにブラウザのクッキー取得を実装してから改めて最新のものにしたいと思います。

    最後に本当にありがとうございました。
    今後とも、ソフトウェア開発頑張ってください。
    ロフトさんのご活躍を期待しております。

  15. >#13 by あさきゆめみし さん
    無事クッキー取得できたとのこと、よかったです。

    なお、ライブラリをCookieGetterSharpDistribution20110517に入れ替えると、
    BrowserTypeの番号が変わります(Firefox4とかが増えてます。)
    番号の定義は、VisuauStudioでコード中の”BrowserType”を選択、右クリック->定義へ移動で 見れます。

    すばらしいライブラリの開発者に感謝ですね。ぜひぜひツール作りに役立てて下さい。

  16. はじめまして。
    C#の勉強を兼ねて、ここのソースに少し手を加えたので、私のブログに記事を書こうと思ってます。

    ゆくゆくは配布までしたいのですが、
    さすがにロフトさんの許可がなければ配布できまないと思いまして。

    記事には、
    ・ここのソースを参考にした事
    ・ここには迷惑をかけない事
    を書こうと思います。

    急ぎませんので、返事いただけるとありがたいです。

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

  17. >えりのあさん
    こんにちは、記事をご覧いただきありがとうございます。
    つたないソースですが、参考になりましたら幸いです。

    ソースコード改造、ブログへの掲載、
    ツールとしての公開はOKです。
    特に引用・参考元の表記は強制致しませんが、
    リンク形式で紹介頂くと喜びます。
    不具合等による問題の責任は免責でお願い致します。

    ニコニコ系ツール・プログラミング関連情報充実の
    お力添えになれましたら幸いですノ

  18. コンパイルすると、
    エラー:型または名前空間’Hel’が見つかりませんでした。usingディレクトリまたはアセンブリ参照が不足しています。
    と出ます。

    プログラミング初心者なので自分なりに調べましたが解決できてません。

    プログラムは、エラーが出たところを少し書きなおしただけです。ほかは書いてある通りにしてます。

    何か解決策ありますか?

  19. >はなさん
    こんにちは。
    CookieGetterSharp.dllを参照に追加されていますでしょうか?
    参照に追加されていない場合、そのようなエラーが出ます。

    >エラー:型または名前空間’Hel’が見つかりませんでした。
    >usingディレクトリまたはアセンブリ参照が不足しています。
    ちなみに’Hel’ではなく’Hal’です。
    9行目(using Hal.CookieGetterSharp;)の記述が
    あっているか確認してみてください。

  20. 参照設定もやってます。
    “Hel” はタイピングミスです。すみません。
    (using Hal.CookieGetterSharp;)の記述もあってます。

    何がいけないのでしょう?

  21. >はなさん
    こんにちは。
    名前空間のエラーなので、参照設定ができているかの確認が必要そうです。
    後述の確認をしてみてください。
    (VisualStudioでの開発の場合の確認事項です。)
    インテリセンスが効き、オブジェクトブラウザでdllの中が見えれば参照はできていると思います。

    ・インテリセンスによる確認
    ソースコードのどこかで(例えばmain関数の中で)、
    Hal.CookieGetterSharp.
    と打って、
    CookieGetterSharp.の.(ドット)の後ろで、Ctrl + Spaceを押して、
    インテリセンスが効くか確認してみて下さい。

    Hal.CookieGetterSharp.BrowserType
    Hal.CookieGetterSharp.CookieGetter
    のように、候補が表示されれば正常に参照設定できています。
    候補が表示されなければ参照設定できていません。

    ・オブジェクトブラウザによる確認
    ソリューションエクスプローラ->参照設定 をダブルクリックで開き、
    “CookieGetterSharp”があるかどうか確認してみてください。
    ある場合、”CookieGetterSharp”の文字をダブルクリックしてみて下さい。するとオブジェクトブラウザが起動します。
    オブジェクトブラウザで”CookieGetterSharp”の中身のクラスを
    のぞき見(Hal->CookieGetterSharp->BrowserType,CookieGetter等の一覧が見える)できれば参照設定はできています。

  22. こんばんは。
    返信がとても遅れてしまい申し訳ありません。
    コンパイラでの参照の仕方が違ったみたいでなんとか
    動くようになりましたが・・・
    490行あたりの

    int resSize = sock.Receive(resBytes, resBytes.Length, System.Net.Sockets.SocketFlags.None);

    で、これ以上先に進まず、動かなくなります(動いてないように見えます)。

    解決方法ありますか?
    度々、すみません。

  23. >はなさん
    こんにちは。コンパイル通ってよかったです。
    sock.Receiveは接続先(ニコ生鯖)からパケットを受信するまで待ち続けるため、
    止まって見えることはあります。

    490行あたりとのことなので、GetProgramInfo()内のsock.Receiveだと思いますが
    これは番組開始情報を受信するまで待ち続けます。

    放送枠数が少ない時間帯だと止まって見えることもありますが、
    夜のゴールデンタイムなど放送数が多い時間帯なら止まることはないです。
    まずは放送数の多い時間帯で試してみて下さい。

    また、事前の処理GetAlertInfo()にて、
    ニコ生鯖のアドレス(m_addr)、ポート(m_port)、スレッドID(m_thread)が
    取得できているか確認してみて下さい。
    GetAlertInfo()の結果として、例えば以下のようなログが表示されます。
    ○サーバ情報
    アドレス twr02.live.nicovideo.jp
    ポート 2531
    スレッドID 1000000013

  24. 追記:
    ソースコードの文字列中のエスケープ文字が消えていたので修正しました。
    \n → n 、 \” → ” になっていました。

  25. こんにちは。

    VBNETで使用しようと試行錯誤しています。

    質問なのですが、CookieGetterSharp.dllは現在でも利用できますか?

    どうも上手く取得できないようなので・・・

  26. >佐々木さん
    こんにちは。
    halxxxx氏が改造&公開されていたCookieGetterSharp.dllは
    開発が停止しているため、最近のブラウザ(Firefox4以降等)には
    対応していません。

    ニコニコミュニティ悠悠閑閑前途遼遠のコミュ主であるうつろ氏が
    最近のブラウザへの対応改造&公開されていますので、
    そちらを使用されることをお勧めします。

    なお、halxxxx氏のCookieGetterSharp.dllとは、
    BrowserTypeの定義値が変わりますので、
    配布されているdllを参照して確認して下さい。

    (ブログ本文もうつろ氏のCookieGetterSharp.dllをメインに書きなおした方がいいですね。。)

  27. ロフトくんさん、返信有難うございます。

    よく見たら追記で書いていましたね。
    よく確認せずすみませんでした。

    いろいろとやってみたいと思います。

  28. >佐々木さん
    できるだけ記事の内容も最新情報に更新した方がいいですよね、
    うつろ氏のCookieGetterSharp.dllがメインになるよう、
    更新したいと思います。

  29. ロフトくんさん、こんにちは。

    うつろ氏のCookieGetterSharp.dllをメインで書いて頂き有難うございます。
    助かります。

    現在、VB2010に移植中なのですが、Consoleではなく、デザイナでフォーム上に作成しています。
    そこで初歩的な質問いいでしょうか?

    Private Shared Sub Main(ByVal args As String())

    mainの引数に当たるargsは何にあたりますでしょうか?

    いままで、Consoleアプリを作ったことが無いので、少し戸惑っています・・・

  30. >佐々木さん
    こんにちは。
    main関数の引数について簡単に解説します。

    main関数の引数はコマンドライン引数と呼ばれるものです。

    コマンドライン引数とは、ツールを起動する際に、
    ツールの外部からツールに渡すことができる文字列です。

    渡された文字列を元に処理を切り替えるような実装をしておくことで、
    動作モードの切り替え等に利用できます。

    以下、サンプルです。

    'コンソールアプリケーションVBConsoleTest
    Module Module1
        Sub Main(ByVal args() As String)
            For Each arg In args
                System.Console.WriteLine(arg)
            Next
        End Sub
    End Module
    

    上記をビルド後、コマンドプロンプトを開き、cdコマンドで、
    exe(VBConsoleTest.exe)のあるフォルダに移動します。

    cd C:¥~Desktop\VBConsoleTest\VBConsoleTest\bin\Debug
    

    普通にexeを起動しただけでは何も表示されません。

    VBConsoleTest.exe
    

    コマンドライン引数を指定して起動すると、表示されます。
    外部から与えた文字列をツール内部で取得できていることが分かります。

    VBConsoleTest.exe abc 123
    abc
    123
    

     
     
    ブログ本文に掲載しているツールのコマンドライン引数は、
    以下のパターンで実装しています。

    ・引数なし
    例)ツール.exe
    argsには何も入ってきません。
    
    ・引数1つ
    例)ツール.exe co247262
    args[0] は "co247262"です。
    coで始まる文字列ならばコミュ番号と判断しています。
    
    例)ツール.exe 426136
    args[0] は "426136"です。
    coが付いていない文字列ならばユーザーIDと判断しています。
    
    ・引数2つ
    例)ツール.exe co247262 426136
    args[0] は "co247262"、
    args[1] は "426136"です
    

    コマンドライン引数は、特に言語(c/c++/C#/VB/java等)によらず(文法は変わりますが)、
    main関数の引数として実装可能な仕組みです。
    詳細は書籍やGoogle先生などを参考にして下さい。

  31. >佐々木さん
    また、コマンドライン引数は、コンソールアプリケーション(CUI)にも
    Windowsフォームアプリケーション(GUI)にも、
    外部から呼び出す際に与えることができ、
    ツール内部から取得も可能です。

    詳しくは

    http://dobon.net/vb/dotnet/programing/commandline.html
    を参照されてください。

    GUIアプリでコマンドライン引数を取得する場合、
    「’コマンドラインを配列で取得する」の方法がお勧めです。

    ただ、GUIアプリであれば、コマンドライン引数を使わなくても、
    フォームにチェックボックスやテキストボックスを配置するなどして、
    画面上で機能を選択できるようにする方が使いやすいかもしれません。

  32. ロフトくんさん、分かりやすく解説して頂き有り難うございます。

    なんとかVB2010でも作れそうです。

    これから移植?コードを書いていきたいと思います。

    完成しましたら、また報告させて頂きます。

  33. すみません、もう一つ質問させて下さい。

    このツール.exe co15655xx ←例です。

    で、コミュを指定し起動すると、いろんな番組の○データ受信を取り続けてしまいます。

    ○データ受信(241byte)

    7593979x,co121302x,1637647x
    放送 : 7593979x
    コミュ : co121302x
    生主 : 1637647x

    ○データ受信(118byte)
    7593979x,co115771x,207980x
    放送 : 7593979x
    コミュ : co115771x
    生主 : 207980x

    ○データ受信(119byte)
    7593980x,co141729x,1029938x
    放送 : 7593980x
    コミュ : co141729x
    生主 : 1029938x

    ○データ受信(119byte)
    7593977x,co145859x,2528826x
    放送 : 7593977x
    コミュ : co145859x
    生主 : 2528826x

    ○データ受信(119byte)
    7593981x,co130316x,2103013x
    放送 : 7593981x
    コミュ : co130316x
    生主 : 2103013x

    このツール.exe

    で、そのまま起動させると、、BrowserTypeではFirefoxを設定しているのですが、IEが立ち上がり、たぶん一番最新の放送を拾ってきて、コメントを拾っていきます。
    (通常使うブラウザをIEにしているのでそのせいかも知れません)

    ○データ受信(240byte)

    7593990x,co142734x,411513x
    放送 : 7593990x
    コミュ : co142734x
    生主 : 411513x

    ○ユーザ情報
    ユーザID 142997x
    ○コメントサーバ情報
    アドレス msg103.live.nicovideo.jp
    ポート 281x
    スレッドID 114296431x

    ○投稿します
    わくおつ

    何か設定などが間違っていますでしょうか?

  34. すみません、もう一つ質問させて下さい。

    このツール.exe co15655xx ←例です。

    で、コミュを指定し起動すると、いろんな番組の○データ受信を取り続けてしまいます。

    ○データ受信(241byte)

    7593979x,co121302x,1637647x
    放送 : 7593979x
    コミュ : co121302x
    生主 : 1637647x

    ○データ受信(118byte)
    7593979x,co115771x,207980x
    放送 : 7593979x
    コミュ : co115771x
    生主 : 207980x

    ○データ受信(119byte)
    7593980x,co141729x,1029938x
    放送 : 7593980x
    コミュ : co141729x
    生主 : 1029938x

    ○データ受信(119byte)
    7593977x,co145859x,2528826x
    放送 : 7593977x
    コミュ : co145859x
    生主 : 2528826x

    ○データ受信(119byte)
    7593981x,co130316x,2103013x
    放送 : 7593981x
    コミュ : co130316x
    生主 : 2103013x

    .
    .
    .

    このツール.exe

    で、そのまま起動させると、、BrowserTypeではFirefoxを設定しているのですが、IEが立ち上がり、たぶん一番最新の放送を拾ってきて、コメントを拾っていきます。
    (通常使うブラウザをIEにしているのでそのせいかも知れません)

    ○データ受信(240byte)

    7593990x,co142734x,411513x
    放送 : 7593990x
    コミュ : co142734x
    生主 : 411513x

    ○ユーザ情報
    ユーザID 142997x
    ○コメントサーバ情報
    アドレス msg103.live.nicovideo.jp
    ポート 281x
    スレッドID 114296431x

    ○投稿します
    わくおつ

    何か設定などが間違っていますでしょうか?

  35. >佐々木さん
    こんにちは。
    >このツール.exe co15655xx ←例です。
    この場合、コミュ番号co15655xxの番組開始を検出するまで
    データ受信を続けます。
    コミュ番号co15655xxの番組開始を検出すると、
    その番組に1コメを送信します。

    >このツール.exe
    この場合、最初に検出した放送に問答無用で1コメを送信します。

    起動するブラウザはProcess.Start(URL)というコマンドで指定しており、この場合、標準のブラウザが起動します。
    ブラウザを指定したい場合は、
    Process.Start(@”C:\~~\firefox.exe”, URL);のように、
    exeの場所を指定する必要があります。

  36. >佐々木さん
    こんにちは。
    いろいろと改善点のあるコードですが、是非便利ツール開発に役立てて下さいノ

  37. こんにちは。
    着実にコード作成進めています。

    プログラムと関係ないのですが・・・・

    ニコ生から送られてくるvposを、1/100秒でそのまま変換すると、放送の時間表示と違い、少し誤差が応じてくるのですが、何故か分かりますか?

  38. >佐々木さん
    こんにちは。
    私もvposから出すのかと思っていましたが、
    dateから出すと一致するようです。

    コメントの時間表示 =  date - start_time
    
    date       : コメントデータのchatタグから取得
    start_time : GetPlayerStatus応答のstream/start_timeタグから取得
    <stream>
     :
     <start_time>ここ</start_time>
     :
    </stream>
    
  39. ロフトくんさん、返信有難う御座います。

    なるほどvposではなかったのですか。
    ニコ生も間際らしいですね。

    おかげで経過時間の取得が出来ました。

    あとは、

    1.返ってくるpremiumのNoが8番(iPhone/iPod)、9番(携帯)の場合は、一般なのかプレミアムなのかの判断をどうやって考えるのか

    2.DataGridViewへの高速追加が可能なのか(1000コメ数を取得する場合かなりの時間がかかる為)

    3.184ではない場合、IDから名前を取得する方法

    4.コテハンの登録方法

    ぐらいでしょうか。

    まだ、時間がかかりそうですが、完成しましたらこちらでも報告させて頂きます。

    有難うございます。

  40. >佐々木さん
    こんにちは、本格的なコメビュ実装をされているのですね、
    応援しております。

    1, 3についてはベストな解ではないかもしれませんが、
    ユーザのマイページのHTMLからのスクレイピング(抜き出し)で取得は可能そうです。

    以下は、あるツール用に実装した、マイページからサムネURL文字列をスクレイピングする関数です。
    ひとつの選択肢としてご参考になれば幸いです。

    マイページはアクセス制限があり、”短時間での連続アクセスはご遠慮ください”と怒られる場合があるので、
    制限に引っかからないようにする必要があります。

    //ユーザーサムネURL取得
    static string GetUserImageURL(string userID)
    {
        string url_image = "";
        try
        {
            string url = "ht"+"tp://www.nicovideo.jp/user/" + userID;
    
            //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();
    
            //HTMLから文字列抽出
            string regular = "<div id=\"accountFace\"><img src=\"(?<tag_image>.*?)\" alt=";
            string regular_ng = "短時間での連続アクセスはご遠慮ください";
    
            Regex re = new Regex(regular, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            for (Match m = re.Match(text); m.Success; m = m.NextMatch())
            {
                //サムネURL抽出
                url_image = m.Groups["tag_image"].Value;
    
            }
            Regex re_ng = new Regex(regular_ng, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            for (Match m = re_ng.Match(text); m.Success; m = m.NextMatch())
            {
                //アクセス制限
                return "ng";
    
            }
            return url_image;
    
        }
        catch (Exception e)
        {
            Console.WriteLine("Message  :\n" + e.Message);
            Console.WriteLine("Type    :\n" + e.GetType().FullName);
            Console.WriteLine("StackTrace :\n" + e.StackTrace.ToString());
            return "";
        }
    }        
    

    2については私も研究中です。
    データとDataGridViewを関連付けることで、自動表示できそうな気がするのですが・・
    (http://c-loft.com/blog/?p=1375 にて研究開始) 良い方法があれば教えて下さい^^

    4についてはコテハン情報(ユーザID, コテハン)のファイル保存方式として、データベースファイルあるいはXMLファイルとして保存が良いのではないかと思います。

    データベースとしては、.NETアプリケーションから手軽に使える軽量データベースとしてSystem.Data.SQLiteを使い始めたのですが便利そうです。
    (とっかかりの記事を http://c-loft.com/blog/?p=1497 に書いています。)

    XML形式の保存には、オブジェクトのXMLシリアライズ(クラスのインスタンス→XML化)・デシリアライズ(XML→クラスのインスタンス化)が便利です。
    私はアプリの設定情報をもたせたクラスをシリアライズでXMLファイル保存・デシリアライズでXMLファイルから設定読み込みで使っています。

    また、XMLから欲しい情報(あるユーザIDのコテハンを)を抽出する方法として、(私は現状未習得ですが、)LINQ to XML によるクエリ発行という方法が”今風”で便利らしいです^^

  41. 追記
    ソースコード中、変数string urlの文字列( http://www.nicovideo.jp/ ~)に自動的にハイパーリンクのタグが付いてしまっていたので、
    わざと文字列を分割してます;___; ( ht + tp://www.nicovideo.jp/~)
    便利機能ではあるけど、ソースコードはいじらないで欲しいですね^^

  42. ロフトくんさん、重ね重ね有難うございます。
    おかげで早く完成しそうです。m(_ _)m

    実は自分はずーとVB2005を使っていたのですが、これを機会にVB2010で作ろうと思い試しています。
    http://c-loft.com/blog/?p=1497も見て勉強させて頂きたいと思います。

    XML関連は、かなり便利になっているようですね。
    便利なものは勉強して使わなといけないとは思っているのですが、なかなか・・・(^^;

    あと自分が入ってるコミュだと、コメント出来ない現象とかありますか?

    自分が入っていない放送だとコメント出来て、自分がコミュに入っている放送だとコメント出来ないという現象が出ましたので・・・

    ただこれは、自分がC#からVBに変更したおり間違ったのかなとも思っています。

  43. >佐々木さん
    こんにちは。
    参加コミュの放送で試して見ましたが起きませんでした、
    発生頻度はどれくらいでしょうか??

    現象としては、コメントをsock.Sendしても、ニコ生側から応答がない状態でしょうか??それとも異常応答が返ってきますか??

    正常にコメントできた場合は以下のようなstatus=”0″が返ってくると思います。

    <chat_result thread="xxxxxxxx" status="0" no="xx"/>
    (投稿応答)
    
    • こんにちは。

      確認した結果、
      status=”4″

      と返ってきています。

      ただし、これは、最初に作ったプログラムはちゃんと投稿できていて、かなり汚く作っていたので、新しくプロジェクトを作成し、整理して作ったコードでは、status=”4″が返ってくるという感じになっています。

      投稿部分のコードは、ココピペで何も変えていないので、さて何処がおかしいのだろうと考えているところです。

      今のところ思いつくのは、Form1_Loadに、
      BackgroundWorkerでのエラーを無効にする為、

      Control.CheckForIllegalCrossThreadCalls = False

      や、

      DataGridViewのちらつき防止のため、
      ダブルバッファしているぐらいでしょうか・・・
      myType.GetProperty(“DoubleBuffered”

      同じコードなのに、どこがいけないのか・・・

      原因を追求中です・・・

      • まだ原因はつかめていませんが、
        間違ったパラメータでコメント送信するとstatus=”4″が返ってくるらしいです。

        うーん、2つのブロジェクトの投稿を比べてみても、パラメータは同じように思えるのですが・・・

        ただ投稿エラーを起こすと、次の投稿を他の人とがすると、コメ番がずーとエラー箇所のコメ番になるので、そこらへんかなとも思っています。

  44. >佐々木さん
    こんにちは、うーん、パラメタですか、、
    もし再現できるコードがあれば私も見てみますので教えて下さい。

  45. ロフトくんさん、返信有難う御座います。

    BackgroundWorkerなどは関係なかったようです。
    どのパラメータが悪かったのか、詳しく分かれば少しは対処できるのですが・・・

    かなり大雑把ですが、コードになります。(^^;

    ‘書き込みがうまくいかない

    Dim cookieGetter__1 As ICookieGetter = CookieGetter.CreateInstance(BrowserType.Firefox)
    Dim collection As CookieCollection = cookieGetter__1.GetCookieCollection(New Uri(“http://live.nicovideo.jp/”))
    Dim user_session As Cookie = collection(“user_session”)
    m_cc = New CookieContainer()
    m_cc.Add(user_session)

    ‘Me.TextBox1.Text = (user_session.Value)

    m_comID = “”

    Dim liveID As String = lv_TextBox.Text

    Dim url As String = “http://live.nicovideo.jp/api/getalertinfo”

    ‘XML取得
    Dim wc As New System.Net.WebClient()
    wc.Encoding = System.Text.Encoding.UTF8
    Dim xml2 As String = wc.DownloadString(url)
    wc.Dispose()
    Console.WriteLine(“○認証API(getalertinfo)レスポンス取得”)
    Console.WriteLine(xml2)
    ‘表示
    ‘上記の例として、以下のようなXMLが返ってくる、
    ‘サーバ情報は, , から取得する

    ‘Anonymous
    ‘-CS4mPdPnMXL8cQJ2g4QakgwvuQ

    ‘ twr02.live.nicovideo.jp
    ‘ 2533
    ‘ 1000000017

    ‘XML解析
    Dim xdoc2 As New XmlDocument()
    xdoc2.LoadXml(xml2)
    Dim root As XmlElement = xdoc2.DocumentElement
    Dim ms As XmlNodeList = 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

    ‘表示
    Debug.WriteLine(“○サーバ情報”)
    Debug.WriteLine(” アドレス ” & m_addr)
    Debug.WriteLine(” ポート ” & m_port)
    Debug.WriteLine(” スレッドID ” & m_thread)

    Console.WriteLine()

    Dim url2 As String = “http://live.nicovideo.jp/api/getplayerstatus?v=” & liveID
    ‘string url = “http://live.nicovideo.jp/watch/lv” + liveID;

    ‘HTTP GET リクエストの作成
    ‘注)本APIから情報取得するには、ログインが必要っぽい
    ‘ しかし認証用API(要ログイン)はクッキーをくれなかった。
    ‘  そこで普通のログイン関数にてクッキーコンテナを取得、ここで使用している
    Dim req As HttpWebRequest = DirectCast(WebRequest.Create(url2), HttpWebRequest)
    req.CookieContainer = m_cc
    ‘取得済みのクッキーコンテナ
    ‘req.CookieContainer.SetCookies(new System.Uri(“http://live.nicovideo.jp/”), m_UserSession.Name + “;” + m_UserSession.Value);
    Dim res As WebResponse = req.GetResponse()
    Dim resStream As Stream = res.GetResponseStream()
    Dim sr As New StreamReader(resStream, Encoding.UTF8)
    Dim xml As String = sr.ReadToEnd()
    sr.Close()
    resStream.Close()

    ‘TextBox2.Text = xml

    Dim xdoc As New XmlDocument()
    xdoc.LoadXml(xml)
    Dim root2 As XmlElement = xdoc.DocumentElement
    ‘番組情報
    Dim stream As XmlNodeList = root2.GetElementsByTagName(“stream”)

    ‘m_base_time = stream[0].ChildNodes[28].InnerText; //仕様変更のたびにずれるのでぼつ
    For Each node As XmlNode In stream(0).ChildNodes
    If node.Name = “base_time” Then
    m_base_time = node.InnerText
    End If
    Next
    ‘user情報
    ‘m_userid = user[0].ChildNodes[7].InnerText;//仕様変更のたびにずれるのでぼつ
    Dim user As XmlNodeList = root2.GetElementsByTagName(“user”)
    For Each node As XmlNode In user(0).ChildNodes
    If node.Name = “user_id” Then
    m_userid = node.InnerText
    End If
    Next
    ‘サーバ情報
    Dim ms2 As XmlNodeList = root2.GetElementsByTagName(“ms”)
    ‘余談だが、ms.Countは常に0と想定し、ms[0]のみ読む。
    m_ComSrvAddr = ms2(0).ChildNodes(0).InnerText
    m_ComSrvPort = ms2(0).ChildNodes(1).InnerText
    m_ComSrvThread = ms2(0).ChildNodes(2).InnerText

    ‘表示

    Debug.WriteLine(“○ユーザ情報”)
    Debug.WriteLine(” ユーザID ” & m_userid)
    Debug.WriteLine(“○コメントサーバ情報”)
    Debug.WriteLine(” アドレス ” & m_ComSrvAddr)
    Debug.WriteLine(” ポート ” & m_ComSrvPort)
    Debug.WriteLine(” スレッドID ” & m_ComSrvThread)

    Dim hostadd As IPAddress = Dns.GetHostEntry(m_ComSrvAddr).AddressList(0)
    ‘IPEndPointを取得
    Dim ephost As New IPEndPoint(hostadd, Integer.Parse(m_ComSrvPort))
    ‘Socketの作成
    Dim sock As New System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)
    ‘接続
    sock.Connect(ephost)

    ‘コメントリクエストメッセージを送信
    ‘注)最後に”を挿入しないとレスポンスは返ってこない
    Dim param As String = [String].Format(“” & vbNullChar, m_ComSrvThread)
    Dim data As Byte() = Encoding.UTF8.GetBytes(param)
    sock.Send(data, data.Length, System.Net.Sockets.SocketFlags.None)

    ‘受信する
    Const MAX_RECEIVE_SIZE As Integer = 1024
    Dim prev As String = “”

    While True
    Dim resBytes As Byte() = New Byte(MAX_RECEIVE_SIZE – 1) {}
    Dim resSize As Integer = sock.Receive(resBytes, resBytes.Length, System.Net.Sockets.SocketFlags.None)
    If resSize = 0 Then
    Exit While
    End If
    Dim xml3 As String = prev & Encoding.UTF8.GetString(resBytes, 0, resSize)
    ‘Console.WriteLine(“○データ受信(” + resSize.ToString() + “byte)”);
    ‘Console.WriteLine(xml);
    ‘Console.WriteLine();
    ‘XML解析
    ‘情報情報の形で受信する
    ‘は捨て、情報から情報を取り出す
    xml3 = xml3.Replace(ControlChars.NullChar, ControlChars.Lf)
    Dim lines As String() = xml3.Split(ControlChars.Lf)
    For Each line As String In lines
    Debug.WriteLine(line)
    ‘受信XML表示(1行)
    If line “” AndAlso Not line.EndsWith(“>”) Then
    ‘MAX_RECEIVE_SIZEいっぱいに受信した場合等
    ‘XMLが閉じていない場合は次回Receive時結合する
    prev = line
    Exit For
    End If

    TextBox1.Text = xml3

    If line.StartsWith(“<thread") Then
    'チケット、コメントサーバー時刻取得
    'を取得
    Dim ticket As String = “”
    Dim server_time As String = “”
    Dim xdoc5 As New XmlDocument()
    xdoc5.LoadXml(line)
    Dim root5 As XmlElement = xdoc5.DocumentElement
    For Each attrib As XmlAttribute In root5.Attributes
    If attrib.Name = “ticket” Then
    ticket = attrib.Value
    End If
    If attrib.Name = “server_time” Then
    server_time = attrib.Value
    End If
    Next
    If (ticket = “”) OrElse (server_time = “”) Then

    End If
    ‘コメント処理開始時刻
    m_DateTimeStart = DateTime.Now

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

    ‘postkeyを取得
    If Not GetPostKey() Then

    End If

    ‘コメント投稿(1コメ)
    ‘注)最後に”を挿入する
    param = [String].Format(“プログラムテスト。1” & vbNullChar, m_ComSrvThread, ticket, vpos, m_postkey, m_userid)
    data = Encoding.UTF8.GetBytes(param)
    sock.Send(data, data.Length, System.Net.Sockets.SocketFlags.None)
    Debug.WriteLine(“○投稿します”)
    Debug.WriteLine(param)

    End If

    If line.StartsWith(“<chat_result") Then
    'コメント投稿結果
    'ここを取り出す
    Debug.WriteLine(“(投稿応答)”)
    Console.WriteLine()
    End If

          '(“<chat ")にするとエラーが出るため変更
    If line.StartsWith("chat ") Then
          
    'コメント取得
    'ここを取り出す
    Dim xdoc6 As New XmlDocument()
    xdoc6.LoadXml(line)
    Debug.WriteLine(xdoc6.InnerText)

    End If
    Next
    End While

    GetUnixTimeクラスと、GetPostKey()は、変更せず、そのまま使用させていただいています。

  46. >佐々木さん
    こんにちは。
    以下コードで、参加コミュ・非参加コミュに1コメ送信できたので差分等ないか確認してみて下さい。
    (URL部分はかってにHTMLリンクタグが入るので、わざと”h” & “ttp://~”にして、回避してます。)
    (ソースコード貼り付け時は[vb]~[/vb]で囲むと以下のようにハイライトされます。[ ]は半角です。)

    Imports System.Net
    Imports Hal.CookieGetterSharp
    Imports System.Xml
    Imports System.IO
    Imports System.Text
    
    Module Module1
        Dim m_ComSrvThread As String
        Dim m_cc As New CookieContainer()
        Dim m_postkey As String
        Sub Main()
            Dim cookieGetter__1 As ICookieGetter = CookieGetter.CreateInstance(BrowserType.Firefox)
            Dim collection As CookieCollection = cookieGetter__1.GetCookieCollection(New Uri("h" & "ttp://live.nicovideo.jp/"))
            Dim user_session As Cookie = collection("user_session")
            m_cc.Add(user_session)
            'Me.TextBox1.Text = (user_session.Value)
            Dim m_comID As String = ""
            Dim liveID As String = "lv79302213"
            Dim url As String = "h" & "ttp://live.nicovideo.jp/api/getalertinfo"
    
            'XML取得
            Dim wc As New System.Net.WebClient()
            wc.Encoding = System.Text.Encoding.UTF8
            Dim xml2 As String = wc.DownloadString(url)
            wc.Dispose()
            Console.WriteLine("○認証API(getalertinfo)レスポンス取得")
            Console.WriteLine(xml2)
            '表示
            '上記の例として、以下のようなXMLが返ってくる、
            'サーバ情報は, , から取得する
            '
            'Anonymous
            '-CS4mPdPnMXL8cQJ2g4QakgwvuQ
            '
            ' twr02.live.nicovideo.jp
            ' 2533
            ' 1000000017
            '
            '
    
            'XML解析
            Dim xdoc2 As New XmlDocument()
            xdoc2.LoadXml(xml2)
            Dim root As XmlElement = xdoc2.DocumentElement
            Dim ms As XmlNodeList = root.GetElementsByTagName("ms")
    
            '余談だが、ms.Countは常に0と想定し、ms[0]のみ読む。
            Dim m_addr As String = ms(0).ChildNodes(0).InnerText
            Dim m_port As String = ms(0).ChildNodes(1).InnerText
            Dim m_thread As String = ms(0).ChildNodes(2).InnerText
    
            '表示
            Console.WriteLine("○サーバ情報")
            Console.WriteLine(" アドレス " & m_addr)
            Console.WriteLine(" ポート " & m_port)
            Console.WriteLine(" スレッドID " & m_thread)
    
            Console.WriteLine()
    
            Dim url2 As String = "h" & "ttp://live.nicovideo.jp/api/getplayerstatus?v=" & liveID
            'string url = “h" & "ttp://live.nicovideo.jp/watch/lv” + liveID;
    
            'h" & "ttp GET リクエストの作成
            '注)本APIから情報取得するには、ログインが必要っぽい
            ' しかし認証用API(要ログイン)はクッキーをくれなかった。
            '  そこで普通のログイン関数にてクッキーコンテナを取得、ここで使用している
            Dim req As HttpWebRequest = DirectCast(WebRequest.Create(url2), HttpWebRequest)
            req.CookieContainer = m_cc '取得済みのクッキーコンテナ
            'req.CookieContainer.SetCookies(new System.Uri(“h" & "ttp://live.nicovideo.jp/”), m_UserSession.Name + “;” + m_UserSession.Value);
            Dim res As WebResponse = req.GetResponse()
            Dim resStream As Stream = res.GetResponseStream()
            Dim sr As New StreamReader(resStream, Encoding.UTF8)
            Dim xml As String = sr.ReadToEnd()
            sr.Close()
            resStream.Close()
    
            'TextBox2.Text = xml
    
            Dim xdoc As New XmlDocument()
            xdoc.LoadXml(xml)
            Dim root2 As XmlElement = xdoc.DocumentElement
            '番組情報
            Dim stream As XmlNodeList = root2.GetElementsByTagName("stream")
    
            'm_base_time = stream[0].ChildNodes[28].InnerText; //仕様変更のたびにずれるのでぼつ
            Dim m_base_time As String = ""
            For Each node As XmlNode In stream(0).ChildNodes
                If node.Name = "base_time" Then
                    m_base_time = node.InnerText
                End If
            Next
            'user情報
            'm_userid = user[0].ChildNodes[7].InnerText;//仕様変更のたびにずれるのでぼつ
            Dim m_userid As String = ""
            Dim user As XmlNodeList = root2.GetElementsByTagName("user")
            For Each node As XmlNode In user(0).ChildNodes
                If node.Name = "user_id" Then
                    m_userid = node.InnerText
                End If
            Next
            'サーバ情報
            Dim ms2 As XmlNodeList = root2.GetElementsByTagName("ms")
            '余談だが、ms.Countは常に0と想定し、ms[0]のみ読む。
            Dim m_ComSrvAddr As String = ms2(0).ChildNodes(0).InnerText
            Dim m_ComSrvPort As String = ms2(0).ChildNodes(1).InnerText
            m_ComSrvThread = ms2(0).ChildNodes(2).InnerText
    
            '表示
    
            Console.WriteLine("○ユーザ情報")
            Console.WriteLine(" ユーザID " & m_userid)
            Console.WriteLine("○コメントサーバ情報")
            Console.WriteLine(" アドレス " & m_ComSrvAddr)
            Console.WriteLine(" ポート " & m_ComSrvPort)
            Console.WriteLine(" スレッドID " & m_ComSrvThread)
    
            Dim hostadd As IPAddress = Dns.GetHostEntry(m_ComSrvAddr).AddressList(0)
            'IPEndPointを取得
            Dim ephost As New IPEndPoint(hostadd, Integer.Parse(m_ComSrvPort))
            'Socketの作成
            Dim sock As New System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)
            '接続
            sock.Connect(ephost)
    
            'コメントリクエストメッセージを送信
            '注)最後に”を挿入しないとレスポンスは返ってこない
            Dim param As String = [String].Format("<thread thread=""{0}"" version=""20061206"" res_from=""-100""/>" & vbNullChar, m_ComSrvThread)
            Dim data As Byte() = Encoding.UTF8.GetBytes(param)
            sock.Send(data, data.Length, System.Net.Sockets.SocketFlags.None)
    
            '受信する
            Const MAX_RECEIVE_SIZE As Integer = 1024
            Dim prev As String = ""
    
            While True
                Dim resBytes As Byte() = New Byte(MAX_RECEIVE_SIZE - 1) {}
                Dim resSize As Integer = sock.Receive(resBytes, resBytes.Length, System.Net.Sockets.SocketFlags.None)
                If resSize = 0 Then
                    Exit While
                End If
                Dim xml3 As String = prev & Encoding.UTF8.GetString(resBytes, 0, resSize)
                'Console.WriteLine(“○データ受信(” + resSize.ToString() + “byte)”);
                'Console.WriteLine(xml);
                'Console.WriteLine();
                'XML解析
                '情報情報の形で受信する
                'は捨て、情報から情報を取り出す
                xml3 = xml3.Replace(ControlChars.NullChar, ControlChars.Lf)
                Dim lines As String() = xml3.Split(ControlChars.Lf)
                For Each line As String In lines
                    Console.WriteLine(line)
                    '受信XML表示(1行)
                    If line <> "" AndAlso Not line.EndsWith(">") Then
                        'MAX_RECEIVE_SIZEいっぱいに受信した場合等
                        'XMLが閉じていない場合は次回Receive時結合する
                        prev = line
                        Exit For
                    End If
    
                    'TextBox1.Text = xml3
    
                    If line.StartsWith("<thread") Then
                        'チケット、コメントサーバー時刻取得
                        'を取得
                        Dim ticket As String = ""
                        Dim server_time As String = ""
                        Dim xdoc5 As New XmlDocument()
                        xdoc5.LoadXml(line)
                        Dim root5 As XmlElement = xdoc5.DocumentElement
                        For Each attrib As XmlAttribute In root5.Attributes
                            If attrib.Name = "ticket" Then
                                ticket = attrib.Value
                            End If
                            If attrib.Name = "server_time" Then
                                server_time = attrib.Value
                            End If
                        Next
                        If (ticket = "") OrElse (server_time = "") Then
    
                        End If
                        'コメント処理開始時刻
                        Dim m_DateTimeStart = DateTime.Now
    
                        'vpos(放送経過時間[sec]*100)を算出
                        'コメントサーバ開始時間
                        Dim serverTimeSpan As Int64 = Int64.Parse(server_time) - Int64.Parse(m_base_time)
                        'コメント投稿時間(1コメゲッターなのでここでは0secですね)
                        Dim localTimeSpan As Int64 = GetUnixTime(DateTime.Now) - GetUnixTime(m_DateTimeStart)
                        Dim vpos As String = ((serverTimeSpan + localTimeSpan) * 100).ToString()
    
                        'postkeyを取得
                        If Not GetPostKey() Then
    
                        End If
    
                        'コメント投稿(1コメ)
                        '注)最後に”を挿入する
                        param = [String].Format("<chat thread=""{0}"" ticket=""{1}"" vpos=""{2}"" postkey=""{3}"" mail=""184"" user_id=""{4}"" premium=""1"">わくおつ~</chat>" & vbNullChar,
                                                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)
    
                    End If
    
                    If line.StartsWith("<chat_result") Then
                        'コメント投稿結果
                        'ここを取り出す
                        Console.WriteLine("(投稿応答)")
                        Console.WriteLine()
                    End If
    
                    '(“<chat ")にするとエラーが出るため変更
                    If line.StartsWith("chat ") Then
    
                        'コメント取得
                        'ここを取り出す
                        Dim xdoc6 As New XmlDocument()
                        xdoc6.LoadXml(line)
                        Console.WriteLine(xdoc6.InnerText)
    
                    End If
                Next
            End While
    
        End Sub
        'Unixタイムに変換
        Function GetUnixTime(targetTime As DateTime) As Int64
            Dim elapsedTime As TimeSpan = targetTime.ToUniversalTime() - New DateTime(1970, 1, 1, 0, 0, 0, 0)
            GetUnixTime = elapsedTime.TotalSeconds()
        End Function
    
        Function GetPostKey() As Boolean
            Try
                '注)
                'block_no = 最新コメント番号(レス番) ÷ 100
                'らしい。1コメゲッタなので0にしてる。
                Dim url As String = "h" & "ttp://live.nicovideo.jp/api/getpostkey?thread=" + m_ComSrvThread + "&block_no=0"
    
                'h" & "ttp GET リクエストの作成
                Dim req As HttpWebRequest = WebRequest.Create(url)
                req.CookieContainer = m_cc '取得済みのクッキーコンテナ
                Dim res As WebResponse = req.GetResponse()
                Dim resStream As Stream = res.GetResponseStream()
                Dim sr As StreamReader = New StreamReader(resStream, Encoding.UTF8)
                Dim text As String = sr.ReadToEnd()
                sr.Close()
                resStream.Close()
                '応答はプレーンテキストで
                'postkey=ergerwhg54hy4wfwegrghg
                'のように返ってくる
                m_postkey = text.Substring(8, text.Length - 8)
    
            Catch e As Exception
    
                Console.WriteLine("Message    :n" + e.Message)
                Console.WriteLine("Type       :n" + e.GetType().FullName)
                Console.WriteLine("StackTrace :n" + e.StackTrace.ToString())
                Return False
            End Try
    
            Return True
        End Function
    End Module
    
    
  47. 気になった注意事項として、GetPostKey()関数が1コメゲッター用のため、コメビュ用途として使用するには以下改造が必要です。

    ・GetPostKey()で本来はblock_noを算出する必要があります。
    コメ番100コメごとにm_postkeyを更新する必要ありです。
    threadタグのlast_resやchatタグのnoの値からblock_noの値を決めるのがよいかと思います。

    (1コメゲッターは上記実装をサボって、block_noを常に0にしてます。総コメ数が100コメに満たない放送ではそのままのコードでいけます。)

    • ロフトくんさん、返信有難う御座います。
      おかげで様で上手く出来ました。

      原因はblock_noでしたね。
      参加コミュ・非参加コミュではなく、コメが100オーバーが、そうではないか・・・
      それで、パラメータエラーでstatus=”4″が返ってくる。

      有難うございます。

      2週間後ぐらいは、大まかな枠組みは完成するんじゃないかと思います。

      これを作り始めて、VBにはこんな機能があったのか・・・など、VB自体の勉強にもかなりなっています。

      C#もそうだと思いますが、同じ処理をするのにもいろいろあって、奥が深いですね・

  48. >佐々木さん
    こんにちは。
    block_noでしたか、判明してよかったです。
    私もツール作成しているときに新しい発見があるといろいろと勉強になります。

    • こんにちは。
      上手くいくはずが、上手くいかず、少し困っています。
      もし、よろしければアドバイスよろしいでしょうか・・・

      m_postkeyが取得できず、コメ投稿が出来ずにいます。
      block_no=”0″にするとm_postkeyは取得できます。

      下のコードで出来るはずなのですが、何故できないのかが分からない・・・

      ‘commentNumberにはlast_resからとったLastのレス番が入っています。

      Dim commentNoCC As Double

      Function GetPostKey() As Boolean
      Try

      ‘commentNumberが1285の場合は、12.85になります。
      commentNoCC = commentNumber / 100
      commentNoCC = commentNoCC.ToString()

      Dim url As String = “h” & “ttp://live.nicovideo.jp/api/getpostkey?thread=” + m_ComSrvThread + “&block_no=” & commentNoCC

      .
      .
      .
      URLまでは上手く行っているのですが・・・
      http://live.nicovideo.jp/api/getpostkey?thread=1149930xxx&block_no=12.85

      これだと、m_postkeyにはなにも入らないという。
      当然、前の段階のtextにも入っていません。

      なぜだか分かりますでしょうか?
      何度もすみませんm(_ _)m

  49. >佐々木さん
    こんにちは。
    整数型にすると取得できるようです。

        Function GetPostKey(count As String) As Boolean
            Try
                Dim block_no As UInt64 = UInt64.Parse(count) / 100
                Dim url As String = [String].Format("h" & "ttp://live.nicovideo.jp/api/getpostkey?thread=" + m_ComSrvThread + "&block_no={0}", block_no)
    
  50. ロフトくんさん、有難うございます。
    上手くいきました。
    UInt64というものを今まで使ったことがなく、また勉強になりました。

  51. こんにちは。私は、VB.NET を独学で学んでいる者です。現在、VB.NETでニコ生コメントビューアーを作ろうと考えています。大変参考・勉強になりました。

    >>佐々木さん
    VB2010への移植が完了したら、公開する予定はありますでしょうか? もしよろしければ、VB2010 版として、どこかで公開して頂けませんでしょうか?

    • VB2010でのソースコードを読解して勉強したいと思っています。勝手なお願いで申し訳ありません。よろしくお願いします。

  52. >島田さん
    こんにちは。
    私はもっぱらC#を使っておりますが、歴史が浅い分、
    世の中にはVB使いの方の方が多いかもですね。

    C#のソースをVBに変換するツールもあるようなので、
    変換精度が良ければ^^、役立つかもしれません。。

  53. >島田さん

    ロフトくんさんさえ良ければ、公開したいと思っています。
    メインコードのほとんどが、ロフトくんさんのコードなので・・・^^;

    簡単な部分はすでに完成しています。

    あとは、DataGridViiewに表示させるのに、現在はAddで登録していっていますが、DataTableに一旦格納してから入れるようにしたいのと、コメントの投稿が何故か不安定なので、そこの修正です。

    m_postkeyの問題なのかどうか・・・
    それともコメのスピードが早い場合、投稿で指定した時間が遅くなり投稿できないのか・・・

    まだ原因が掴めていない状態です。

  54. 最初は書き込みできて、postkeyが変わると書き込み出来なくなるって何故でしょう・・・

    うーん・・・

  55. >佐々木さん
    こんにちは、公開して頂いてよいですよ。
    VB関連情報の充実に役立てて頂ければ幸いです。

    postkeyは100コメごとに変わるものだった気がしますが、
    不具合があるのかな?時間のあるときに試してみます。

  56. こんにちは。
    なんとなく原因が分かって来ました。

    最初から書き込みが出来ない
    vpos=”1176600″ postkey=”O-H2LgY0Jb768f3bHznwGhtWdII”

    しかしvposが12~になったら書き込みできるようになった
    vpos=”1228200″ postkey=”O-H2LgY0Jb768f3bHznwGhtWdII”

    取得を/10にしたり、無変更にしたりといろいろ試してみたのですが、出来ませんでした。

    ニコ生が何を変更したのか、探すのも一苦労ですね・・・

  57. >佐々木さん
    こんにちは。某大手コメビュのコミュ掲示板で目にしたのですが、postkeyの仕様が変わった可能性があるみたいですね。
    ニコ生側でなんらかの仕様変更があった可能性がありますね、、
    そのコメビュでは暫定対策として、投稿に失敗したら再度postkeyを取得しなおしているようです。

  58. ロフトくんさん、返信有難う御座います。

    そっちの掲示板は見ていませんでした。
    真っ先に見なければいけない掲示板でしたね・・・

    >そのコメビュでは暫定対策として、投稿に失敗したら再度postkeyを取得しなおしているようです。

    なるほど、postkeyを再取得で投稿ですか、、
    さっそく試してみます。

    有難うございます。

  59. Private Sub GetCommnet()



    ‘コメントリクエストメッセージを送信
    ‘注)最後に”を挿入しないとレスポンスは返ってこない
    Dim param As String = [String].Format(“” & vbNullChar, m_ComSrvThread)
    Dim data As Byte() = Encoding.UTF8.GetBytes(param)
    sock.Send(data, data.Length, System.Net.Sockets.SocketFlags.None)

    ‘受信する
    Const MAX_RECEIVE_SIZE As Integer = 1024
    Dim prev As String = “”

    While True
    Dim resBytes As Byte() = New Byte(MAX_RECEIVE_SIZE – 1) {}
    Dim resSize As Integer = sock.Receive(resBytes, resBytes.Length, System.Net.Sockets.SocketFlags.None)
    If resSize = 0 Then
    Exit While
    End If
    Dim xml3 As String = prev & Encoding.UTF8.GetString(resBytes, 0, resSize)
    ‘Console.WriteLine(“○データ受信(” + resSize.ToString() + “byte)”);
    ‘Console.WriteLine(xml);
    ‘Console.WriteLine();
    ‘XML解析
    ‘情報情報の形で受信する
    ‘は捨て、情報から情報を取り出す
    xml3 = xml3.Replace(ControlChars.NullChar, ControlChars.Lf)
    Dim lines As String() = xml3.Split(ControlChars.Lf)
    For Each line As String In lines
    Debug.WriteLine(line)
    MsgBox(line)

    ‘受信XML表示(1行)
    If line “” AndAlso Not line.EndsWith(“>”) Then
    ‘MAX_RECEIVE_SIZEいっぱいに受信した場合等
    ‘XMLが閉じていない場合は次回Receive時結合する
    prev = line
    Exit For
    End If

    ‘TextBox1.Text = xml3

    If line.StartsWith(“<thread") Then
    'チケット、コメントサーバー時刻取得
    'を取得
    Dim ticket As String = ""
    Dim server_time As String = ""
    Dim xdoc5 As New XmlDocument()
    xdoc5.LoadXml(line)
    Dim root5 As XmlElement = xdoc5.DocumentElement
    For Each attrib As XmlAttribute In root5.Attributes
    If attrib.Name = "ticket" Then
    ticket = attrib.Value
    End If
    If attrib.Name = "server_time" Then
    server_time = attrib.Value
    End If
    Next
    If (ticket = "") OrElse (server_time = "") Then

    End If
    'コメント処理開始時刻
    Dim m_DateTimeStart = DateTime.Now

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

    'postkeyを取得
    GetPostKey(comentnumber)

    param = [String].Format("” & comtext & “” & vbNullChar,
    m_ComSrvThread, ticket, vpos, m_postkey, m_userid)

    End If

    data = Encoding.UTF8.GetBytes(param)
    sock.Send(data, data.Length, System.Net.Sockets.SocketFlags.None)
    Debug.WriteLine(“○投稿します”)
    Debug.WriteLine(param)

    End If

    If line.StartsWith(“<chat_result") Then
    'コメント投稿結果
    'ここを取り出す
    Debug.WriteLine("(投稿応答)")
    Console.WriteLine()
    End If

    If line.StartsWith("<chat ") Then

    'コメント取得
    'ここを取り出す
    Dim xdoc6 As New XmlDocument()
    xdoc6.LoadXml(line)
    Debug.WriteLine(xdoc6.InnerText)

    End If

    Exit Sub
    Next
    End While
    End Sub

  60. それで、帰ってきた status=”4″ で判断しようと思っているのですが、コードをいじってたら返ってこなくなってしまいました・・・

    lineを確認しているのですが、ひとつしか返ってきません。

    わくおつ

    暇な時にでもコードを見て頂けたら有難いです・・・・

    Private Sub GetCommnet()

    Private Shared Function GetCommnet() As Boolean

    の違いも関係あるでしょうか?

  61. ↑コメントの順番が逆ですね・・・

    こんにちは。

    原因解決しました。

    投稿出来てて、途中から投稿できなくなった場合は、postkeyが変更されているので、前のpostkeyに戻すと投稿できる。
    そしてまた投稿できなくなったら、postkeyを最新のpostkeyに戻す。

    この繰り返しで上手くいきます。

  62. >佐々木さん
    こんにちは、情報有難う御座います。
    投稿に失敗した場合はpostkeyを変更しないといけないのですね。
    何かしら理由があっての仕様だと思いますが、、、、、謎仕様ですね^^

  63. ロフトくんさん、こんにちは。

    なんとか無事に完成しました。
    いろいろと分からないことを助けて頂き有難うございました。
    仕様書はまだ出来ていませんが・・・
    ソフトへのリンクはこちらに貼ってもいいでしょうか?

  64. ところで、CookieGetterSharp.dll を使って、Webbrowserで接続する場合もあると思うのですが、CookieContainerを使って送信する場合、Cookieには何か書式とかあるのでしょうか?

  65. >佐々木さん
    こんにちは、サイト見ました、高機能ですね、これは流行る!

    Webbrowserクラスで接続すると、(Microsoftだから・・)
    IEのクッキーが使われるようなことを聞いたことがあるような気がします。

  66. ロフトくんさんはじめまして。
    始めたばかりの初心者ですが、上記のコードを参考にさせて頂き、ニコ生のコメビュ作っています。
    カン違いや間違いがあるかもしれませんが、コメントを頂けると幸いです。

    上記のコードにGUIをつけ、Threadで別スレッドでのコメントの取得をして、それをDataGridViewに表示させているのですが、エラーで止まってしまう事があります。
    具体的には弾幕など、1024近い文字数を受信する時に起きるようです。
    エラーが起きているラインを見ると上記プログラムでいうと、
    if (line.StartsWith(“<chat"))
    {
    //ここを取り出す
    XmlDocument xdoc = new XmlDocument();
    xdoc.LoadXml(line);

    のxdoc.loadXml(line)にて
    「予期しないファイルの終わりが検出されました。次の要素が閉じられていません」と出ていました。
    if (line != “” && !line.EndsWith(“>”))
    {
    //MAX_RECEIVE_SIZEいっぱいに受信した場合等
    //XMLが閉じていない場合は次回Receive時結合する

    辺りがまずいのだろうと思い、
    if (line != “” && !line.EndsWith(“chat>”))にしてみたり、MAX_RECEIVE_SIZEを増やしてみたりしたのですが改善されません。エラーがでたlineを見てみると、途切れた所で終わった文字列と次に受信した文字列が結合されているようです。
    参考に、コードを付けておきます。
    http://ideone.com/cfjd4
    お時間があれば、お知恵を貸して頂けると幸いです。宜しくお願いします。長文失礼しました。

  67. >さぎりさん
    こんにちは。

    気づいた点として、ブログ本文に掲載しているコードの
    GetCommnet()の修正箇所を2箇所お知らせします。

    以下★の処理の追加が必要です。
    一度prevを使ったら空文字でクリアしておかないと、次回古いprevを結合してしまいます。

                        string xml = prev + Encoding.UTF8.GetString(resBytes, 0, resSize);
                        prev = ""; //★prevを空文字でクリアしておく
    

     
     
     
    以下は文字列が中途半端なところで切れているならばという条件ですが、
    条件が甘いので強化が必要です。
    > でなければ(甘い条件)を、
    chatの閉じタグ( /chat> )か、threadの閉じタグ( /> )でなければ(強化した条件)
    に変更しています。(他にタグの種類がありましたら追加して下さい。)

    甘い条件だと、<chat ~~~>←ちょうどここまでを受信した際に閉じタグと誤判定します。

                            //if (line != "" && !line.EndsWith(">")) //甘い
                            if ((line != "") && !line.EndsWith("/chat>") && !line.EndsWith("/>"))
    

    同様の修正をGetProgramInfo()にも必要そうです。

  68. >ロフトくんさん
    こんばんは
    早いレスありがとうございます。
    なるほど、途切れる位置によって色々なパターンが考えられるんですね・・・
    上のコードを見よう見まねで書いているのでわかっていない事が多そうです。色々、パターンを考えながらやってみます。
    ありがとうございました><

  69. こんにちは。

    またまた助言をお願いしたく書く込しました。
    BSPの権限を与えられた人用の投稿方法とか分かりますか?

    運営コメでBSPの投稿はできてのですが、生主じゃなくBPS取得者のリスナーでの投稿方法が分からなくて・・・

    http://watch.live.nicovideo.jp/api/broadcast/
    に、tokenと /press show 色 コメント BPS取得者名
    でいいんですかね~

    自分がBSP取得者ではないので、テストも出来ずなかなか上手く出来ませんね

    検索してみても、運営コメの方法は書いてても、一般のBSPコメ投稿は誰もまだ書いていなく見つからないんですよね。

  70. >佐々木さん
    こんにちは。
    以下は、ニコわんこをBSP対応する際に調べた内容です。
    (調べ方としては、BSP権限のあるアカウントでBSP投稿した際の通信をwiresharkで覗き見です。)
    BSPコメを投稿できる環境がないとテストがむずいですね。

    ・APIのURL
    http://live.nicovideo.jp/api/presscast

    ・POSTパラメタ
    v=lv○○○○○
    body=BSPコメント本文
    color=BSPコメント色(0=niconicowhite, 1=red,,,)
    name=BSPコメント投稿者名
    mode=”json”
    token=トークン(presscast_token)

    ※presscast_tokenは、BSP権限者ならば、放送ページHTMLに
    書いてあるのでそれを使っています。

    ・レスポンスパラメタ
    POSTの応答として以下のようなjsonデータが返ってきます。
    statusでBSP投稿OK/NGが判定できます。
    {
    “status”:”ok”,
    “code”:””,
    “description”:”コメント”
    }

  71. ロフトくんxさん、いつも有難うございます。

    環境がなく、なかなかテストすることが難しいのですが、BSPの人に頼んでテストしながらやって行きたいと思います。

    有難うございます。
    助かりました。

  72. 初めましてここのソースからニコ生座席取得ツールを作ろうと考えているものです
    自分が考える方法としては自分の指定したコミュorユーザーの放送が始まると1コメを送信せずに座席のみを取得して座席番号を表示させてコメビュ機能を省こうと思っています
    そこで質問ですがこのソースコードのコメビュ機能となる部分はどこに当たりますか?
    まだまだ初心者なので勉強不足なのは承知ですがよろしければ教えて下さい
    コレで大手のすぐに満員になるような放送にも入れるようにと思って作るつもりです

  73. >ゆたんぽさん
    こんにちは。
    コメント処理はGetCommnet()でやっています。
    コメント鯖に接続、1コメを送信、受信コメを表示(コメビュ機能)を実施しています。

    ちなみに座席取得はGetPlayerStatus()でやっています。
    座席情報としてはroom_label、room_seetnoの値を見てみてください。
    (サンプルコードのuser_idの値の取り出し方が参考になるかと思います。)

  74. はじめまして。
    ニコわんこおもしろそうだったので、試してみました。
    参加コミュ情報が取得できずに困っております。ログには「クッキーの共有ができませんでした。」使用しているブラウザはgooglechromeなのですが、どこが問題なのでしょうか?

  75. >>初心者さん
    こんにちは。

    ※こちらのブログ記事は、アラートやコメビュを自作したい方向けの
     プログラミング方法の記事になります。
     ニコわんこのサポートはTwitter( https://twitter.com/loftkun )、または
     コミュ掲示板 http://com.nicovideo.jp/bbs/co247262 で行なっていますので
     今後は、そちらに書き込んで下さい。

    確認事項としては、
    ・GoogleChromeでニコニコにログイン済みであること。
    ・ニコわんこの、一般設定タブの、クッキー共有元ブラウザに
     GoogleChromeを選択していること。
    です。

    上記を実施しているのにクッキーの共有ができない場合は、
    ・GoogleChoromeのクッキーを削除して再度試す
    ・クッキー共有チェックツールが配布されているので判定してみる
     http://c-loft.com/nico/intro_NwhoisLoginSystem/
    の方法があります(詳細はコミュ掲示板にて)

  76. こちらの記事を参考に、CookieGetterSharpを使ってやってみたのですが、クッキーの取得でエラーが出てしまい、どう変えればいいのかわからないので、投稿させていただきました。

    [クッキー取得処理の1行目]
    ICookieGetter cookieGetter = CookieGetter.CreateInstance(BrowserType.Firefox4);

    上記の”CreateInstance”の部分なのですが、エラーの内容が「古い形式です」となっているのですが、変更になったとかで、新しい形式とかあるのでしょうか?
    もしかしたら、PCの環境なのかとも思ったのですが、全くわからない状態で・・。
    一応、記すとwin8でVSE2012(C#)/.NET FW4.5です。
    別途、.NET FW4を入れるべきなのでしょうか?

    もし、おわかりでしたらご教授お願いします。

  77. >STさん
    こんにちは。

    CookieGetterSharpDistribution20130703を見てみました。
    CookieGetter.CreateInstance()メソッドは[Obsolete]属性がついており、
    今後サポートされない(orもうサポートされていない)ようです。

    開発者さんへ.txtを見ると、
    CreateInstances()メソッドが用意されておりこちらを使うことが推奨されているようです。

    ICookieGetter[] cookieGetters = CookieGetter.CreateInstances(true);
    foreach(ICookieGetter cookieGetter in cookieGetters){
        if (cookieGetter.Status.BrowserType == BrowserType.Firefox)
        {
            //ブログ記事掲載の方法
            //System.Net.CookieCollection collection = cookieGetter.GetCookieCollection(new Uri("h"+"ttp://live.nicovideo.jp/"));
            //System.Net.Cookie user_session = collection["user_session"];
    
            //開発者さんへ.txtの方法
            System.Net.Cookie cookie = cookieGetter.GetCookie(new Uri("h"+"ttp://live.nicovideo.jp/"), "user_session");
        }
    }
    
    • なるほど、試してみます。ありがとうございます。

      >開発者さんへ.txtを見ると
      そういう意味だったのですね。
      見ることは見たのですが、意味がわからず見逃してました。

      何かありましたら、また、お世話になるかもしれませんが、その時はよろしくお願いします。

コメントを残す

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