NiconamaCommentViewer(ニコ生コメントビューア)のプラグイン作成法 3


ニコニコ生放送用のコメントビューアであるNiconamaCommentViewerのプラグインの作成法メモです。

第一回は、開発環境を準備し、何もしないプラグイン作成を行いました。
第二回は、フォームを表示するだけのプラグインを作成しました。

今回は、ついにプラグインに機能を持たせてみます。

2011/08/16 追記 using System.Windows.Forms;追加時は、参照設定も追加する旨
2012/06/19 追記 コメント 2012年4月19日 at 10:06 PM の修正を反映



イベントハンドラを実装しよう


コメビュ本体からプラグインに通知されるイベントを利用することで、コメビュ本体と連動した動作を実装できます。

イベントには、放送への接続イベントや、コメント受信イベント等があります。
(詳しくは開発者用ドキュメントのIPluginHost Eventsの項目を参照してください。)
 
ここでは、
・放送への接続時イベント
・放送からの切断時イベント
・コメント受信時イベント
のイベントハンドラを実装してみます。

第二回のソースコードを元に改造していきます。
   

①ハンドラの登録

ハンドラとはコメビュ本体からのイベントを受け取る関数です。+演算子で登録できます。
Class1.cs

        /// <summary>
        /// プログインを実行する
        /// </summary>
        public void Run()
        {
            if (_form == null)
            {
                MessageBox.Show("フォームを生成します", Name);//動作確認用MessageBox

                //フォームの生成
                _form = new Form1();
                _form.Show((System.Windows.Forms.IWin32Window)_host.MainForm);

                //フォームが閉じられた際のイベントハンドラ追加
                _form.FormClosed += new System.Windows.Forms.FormClosedEventHandler(_form_FormClosed);

                //放送接続イベントハンドラ追加
                _host.BroadcastConnected += new BroadcastConnectedEventHandler(_host_BroadcastConnected);

                //放送切断イベントハンドラ追加
                _host.BroadcastDisConnected += new BroadcastDisConnectedEventHandler(_host_BroadcastDisConnected);

                //コメント受信時のイベントハンドラ追加
                _host.ReceivedComment += new ReceivedCommentEventHandler(_host_ReceivedComment);
            }
        }

以下関数名を+演算子で登録してみました。 

・_host_BroadcastConnected
 放送に接続した際のイベントハンドラです。ユーザが”接続”ボタンを押した際に呼ばれます。
 主にプラグインの開始処理を実装することになるでしょう。
・_host_BroadcastDisConnected
 放送から切断した際のイベントハンドラです。ユーザが”切断”ボタンを押した際に呼ばれます。
 主にプラグインの終了処理を実装することになるでしょう。
・_host_ReceivedComment
 コメントを受信した際のイベントハンドラです。
 受信コメントを扱う処理を実装することになるでしょう。

まだ上記のハンドラ関数名を登録しただけです。
次にハンドラ内部の処理を実装します。
 

②ハンドラの実装

ここでは、動作確認用として、MessageBoxを表示するだけの処理を実装してみましょう。
 
MessageBoxを使うために、using System.Windows.Forms;が必要なので追加します。


2011/08/16 追記 以下エラーの対処法を追記します。


エラー CS0234: 型または名前空間名 ‘Windows’ は名前空間 ‘System’ に存在しません。アセンブリ参照が不足しています。


ソリューションエクスプローラの参照設定->参照の追加ダイアログで、.NETタブを選択し、
コンポーネント名 System.Windows.Forms を選択し、OKを押してダイアログを閉じ、
ソリューションエクスプローラの参照設定にSystem.Windows.Formsが追加されていることを確認してください。

Class1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Plugin;
using System.Windows.Forms;

namespace NCV_Plugin_Sample
{
    public class Class1 : IPlugin
    {
        private IPluginHost _host = null;
        private Form1 _form = null;
                :

 
各ハンドラにMessageBox表示処理を実装します。
Class1.cs

        //放送接続時イベントハンドラ
        void _host_BroadcastConnected(object sender, EventArgs e)
        {
            MessageBox.Show("放送に接続しました", Name);//動作確認用MessageBox
        }

        //放送切断時イベントハンドラ
        void _host_BroadcastDisConnected(object sender, EventArgs e)
        {
            MessageBox.Show("放送から切断しました", Name);//動作確認用MessageBox
        }

        //コメント受信時イベントハンドラ
        void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
        {
            MessageBox.Show("コメントを受信しました", Name);//動作確認用MessageBox
        }

フォームが閉じられたら、ハンドラを削除しておきます。
-演算子でハンドラを削除します。
Class1.cs

        //フォームが閉じられた際のイベントハンドラ
        void _form_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
        {
            MessageBox.Show("フォームが閉じられました", Name);//動作確認用MessageBox

            //イベントハンドラを削除する
            //フォームが閉じられた際のイベントハンドラ削除
            _form.FormClosed -= _form_FormClosed;

            //放送開始直後イベントハンドラ削除
            _host.BroadcastConnected -= _host_BroadcastConnected;

            //放送終了直後のイベントハンドラ削除
            _host.BroadcastDisConnected -= _host_BroadcastDisConnected;

            //コメント受信時のイベントハンドラ削除
            _host.ReceivedComment -= _host_ReceivedComment;

            _form = null;
        }

上記コードをビルド、動作確認してみましょう。
それぞれのイベントハンドラで、MessageBoxが表示されることを確認して下さい。
 
無事に動作確認が終わったら、MessageBox.Show(~~);のコードは消してかまいません。
 
イベントハンドラの動作が確認できたところで、次は、もっと役に立つ機能を実装してみます。
 

プラグイン実装例


①全自動ガップラグイン

自動でぬるぽにガッしてみましょう

        //コメント受信時イベントハンドラ
        void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
        {
            //受信したコメント数を取り出す
            int count = e.CommentDataList.Count;
            if (count == 0)
            {
                return;
            }

            //最新のコメントデータを取り出す
            NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[count-1];

            //コメント文字列を取り出す
            string comment = commentData.Comment;

            //①
            //コメントに"ぬるぽ"が含まれているか判定し、
            //含まれていたら、"ガッ"とコメントする
            if (comment.Contains("ぬるぽ"))
            {
                if (_oldSendComment != "ガッ")//※前回"ガッ"を送信していないかチェック(同一ワードの連続投稿防止)
                {
                    //含まれているので"ガッ"をコメントする
                    bool result = _host.SendComment("ガッ");

                    //コメント成功?
                    if (result == true)
                    {
                        //フォームに表示する(まだ実装していません)
                        //string no = commentData.No;//コメ番を取り出す
                        //_form.OutputLog(no, "ぬるぽ", "ガッ");

                        //前回送信コメント
                        _oldSendComment = "ガッ";

                        //MessageBox.Show("ぬるぽを検出したのでガッしました", Name);//動作確認用MessageBox
                    }
                }
            }
        }

これで、ぬるぽに自動対応できるプラグインができました。
 

②③自動応答プラグイン

ぬるぽ→ガッ以外のパターンを増やしてみます。
(①と同じ処理なので関数化してすっきりさせてみます。)
※_oldSendCommentは連続コメ送信防止用です。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Plugin;
using System.Windows.Forms;
namespace NCV_Plugin_Sample_02
{
    public class Class1 : IPlugin
    {
        private IPluginHost _host = null;
        private Form1 _form = null;

        private string _oldSendComment = "";//前回送信コメント
                :
                :
        /// <summary>
        /// data.Commentにw1が含まれていたらw2とコメントする
        /// </summary>
        /// <param name="data">コメントデータ</param>
        /// <param name="w1">検出文字列</param>
        /// <param name="w2">投稿文字列</param>
        void AnalyzeContainsAndAutoReply(NicoLibrary.NicoLiveData.LiveCommentData data, string w1, string w2)
        {
            //コメント文字列を取り出す
            string comment = data.Comment;

            //コメントにw1が含まれていたら
            if (comment.Contains(w1))
            {
                if (_oldSendComment != w2)//※同一ワードの連続投稿防止
                {
                    //w2をコメント送信する
                    bool result = _host.SendComment(w2);

                    //コメント送信成功?
                    if (result == true)
                    {
                        //ログをフォームに表示する(まだ実装していません)
                        //string no = data.No;//コメ番を取り出す
                        //_form.OutputLog(no, w1, w2);

                        //前回送信コメント
                        _oldSendComment = w2;

                        //MessageBox.Show(w1+"を検出したので"+w2+"をコメントしました", Name);//動作確認用MessageBox
                    }
                }
            }
        }

上記関数の呼び出し部です。関数化したのでいろんなパターンを簡単に増産できますね。

        //コメント受信時イベントハンドラ
        void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
        {
            //受信したコメント数を取り出す
            int count = e.CommentDataList.Count;
            if (count == 0)
            {
                return;
            }
            //最新のコメントデータを取り出す
            NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[count-1];

            //①コメントに"ぬるぽ"が含まれているか判定し、含まれていたら、"ガッ"とコメントする
            AnalyzeContainsAndAutoReply(commentData, "ぬるぽ", "ガッ");
            //②コメントに"初見"が含まれているか判定し、含まれていたら、"初見さんこんにちは"とコメントする
            AnalyzeContainsAndAutoReply(commentData, "初見", "初見さんこんにちは");
            //③コメントに"大丈夫か?"が含まれているか判定し、含まれていたら、"大丈夫だ、問題ない。"とコメントする
            AnalyzeContainsAndAutoReply(commentData, "大丈夫か?", "大丈夫だ、問題ない。");
        }

④自動応答プラグインの応答パターンをユーザーに決めさせる

フォームにtextBox1とtextBo2を追加します。

textBox1に入力された言葉を検出したら、
textBox2に入力された文字列をコメントするようにしてみます。

つまり、以下のように改造すればよいですね。

            AnalyzeContainsAndAutoReply(commentData, textBox1のtext, textBox2のtext); 

ただし、textBoxはフォームクラスのメンバですので、
別のクラス(ここではプラグインクラス)値から取得するには少し工夫が必要です。
最後に掲載しているソースを参考にしてください。
(フォームクラスにGetWord1メソッド、GetWord2メソッドを実装し、textBoxの文字列を返すようにしています。)
 

⑤動作ログを表示する(開発者用の機能です)

プラグインに機能を追加していくと、思わぬ不具合が発生することがあります。
そこで、プラグインの動作が確認できるよう、ログを残してみます。

フォームにtextBox3を追加し、複数行表示にします。
(MultilineプロパティをTrueにして、マウスでtextBoxの広さをを複数行分ににする。
ScrollBarsプロパティをVerticalにして、スクロールできるようにします。)

プラグインのログを残したい動作(たとえばプラグインからコメントを送信する際など)
textBox3に動作ログを残すようにします。
最後に掲載しているソースを参考にしてください。
(フォームクラスに実装したOutputLogメソッドをプラグインクラスから呼んでいます)

他にも


こんなプラグインが作れそうですね。

キリ番ゲットプラグイン

コメ番号はcommentData.Noで取得できます。
コメント受信イベントハンドラにて、現在のコメ番号が、キリ番-1であれば、
すかさず”キリ番ゲット”とコメントします。
その際、狙いたいキリ番番号と、送信したいコメント文字列をtextBox等で設定できると便利でしょう。

タイマープラグイン

放送経過時間が_host.GetElapsedTime()で取得できることを利用します。
現在時刻と、取得した放送経過時間から、お知らせコメントを投稿すべき時刻が決まります。
 

全ソースコード

Class1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Plugin;
using System.Windows.Forms;
namespace NCV_Plugin_Sample_02
{
    public class Class1 : IPlugin
    {
        private IPluginHost _host = null;
        private Form1 _form = null;

        private string _oldSendComment = "";//前回送信コメント

        #region IPlugin メンバ

        /// <summary>
        /// IsAutoRunがtrueの場合、アプリケーション起動時に自動実行される
        /// </summary>
        public void AutoRun()
        {
            MessageBox.Show("プラグインが開始されました", Name);//動作確認用MessageBox
        }

        /// <summary>
        /// プラグインの説明
        /// </summary>
        public string Description
        {
            get { return "プラグインのサンプルです"; }
        }

        /// <summary>
        /// プラグインのホスト
        /// </summary>
        public IPluginHost Host
        {
            get
            {
                return _host;
            }
            set
            {
                _host = value;
            }
        }

        /// <summary>
        /// アプリケーション起動時にプラグインを自動実行するかどうか
        /// </summary>
        public bool IsAutoRun
        {
            get { return false; }
        }

        /// <summary>
        /// プラグインの名前
        /// </summary>
        public string Name
        {
            get { return "サンプルプラグイン イベント対応版"; }
        }

        /// <summary>
        /// プログインを実行する
        /// </summary>
        public void Run()
        {
            if (_form == null)
            {
                MessageBox.Show("フォームを生成します", Name);//動作確認用MessageBox

                //フォームの生成
                _form = new Form1();
                _form.Show((System.Windows.Forms.IWin32Window)_host.MainForm);

                //フォームが閉じられた際のイベントハンドラ追加
                _form.FormClosed += new System.Windows.Forms.FormClosedEventHandler(_form_FormClosed);

                //放送開始直後イベントハンドラ追加
                _host.BroadcastConnected += new BroadcastConnectedEventHandler(_host_BroadcastConnected);

                //放送終了直後のイベントハンドラ追加
                _host.BroadcastDisConnected += new BroadcastDisConnectedEventHandler(_host_BroadcastDisConnected);

                //コメント受信時のイベントハンドラ追加
                _host.ReceivedComment += new ReceivedCommentEventHandler(_host_ReceivedComment);
            }
        }

        /// <summary>
        /// プラグインのバージョン
        /// </summary>
        public string Version
        {
            get { return "1.0"; }
        }

        //フォームが閉じられた際のイベントハンドラ
        void _form_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
        {
            MessageBox.Show("フォームが閉じられました", Name);//動作確認用MessageBox

            //イベントハンドラを削除する
            //フォームが閉じられた際のイベントハンドラ削除
            _form.FormClosed -= _form_FormClosed;

            //放送開始直後イベントハンドラ削除
            _host.BroadcastConnected -= _host_BroadcastConnected;

            //放送終了直後のイベントハンドラ削除
            _host.BroadcastDisConnected -= _host_BroadcastDisConnected;

            //コメント受信時のイベントハンドラ削除
            _host.ReceivedComment -= _host_ReceivedComment;

            _form = null;
        }

        //放送接続時イベントハンドラ
        void _host_BroadcastConnected(object sender, EventArgs e)
        {
            MessageBox.Show("放送に接続しました", Name);//動作確認用MessageBox
        }

        //放送切断時イベントハンドラ
        void _host_BroadcastDisConnected(object sender, EventArgs e)
        {
            MessageBox.Show("放送から切断しました", Name);//動作確認用MessageBox
        }

        //コメント受信時イベントハンドラ
        void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
        {
            //受信したコメント数を取り出す
            int count = e.CommentDataList.Count;
            if (count == 0)
            {
                return;
            }
            //最新のコメントデータを取り出す
            NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[count-1];

            //コメント文字列を取り出す
            string comment = commentData.Comment;

            //①
            //コメントに"ぬるぽ"が含まれているか判定し、
            //含まれていたら、"ガッ"とコメントする
            if (comment.Contains("ぬるぽ"))
            {
                if (_oldSendComment != "ガッ")//※前回"ガッ"を送信していないかチェック(同一ワードの連続投稿防止)
                {
                    //含まれているので"ガッ"をコメントする
                    bool result = _host.SendComment("ガッ");

                    //コメント成功?
                    if (result == true)
                    {
                        //フォームに表示する
                        //コメ番を取り出す
                        string no = commentData.No;
                        _form.OutputLog(no, "ぬるぽ", "ガッ");

                        //前回送信コメント
                        _oldSendComment = "ガッ";

                        MessageBox.Show("ぬるぽを検出したのでガッしました", Name);//動作確認用MessageBox
                    }
                }
            }

            //②
            //コメントに"初見"が含まれているか判定し、
            //含まれていたら、"初見さんこんにちは"とコメントする
            //(①と全く同じ処理なので、関数化してみたので、コードが無駄に長くならず、すっきりした。→①も関数化しておこう)
            AnalyzeContainsAndAutoReply(commentData, "初見", "初見さんこんにちは");
            
            //③
            //コメントに"大丈夫か?"が含まれているか判定し、
            //含まれていたら、"大丈夫だ、問題ない。"とコメントする
            //(②で関数を作っておいた恩恵として、③の機能追加はコードを1行書くだけですんだ)
            AnalyzeContainsAndAutoReply(commentData, "大丈夫か?", "大丈夫だ、問題ない。");

            //④
            //コメントにtexBox1で指定された文字列が含まれているか判定し、
            //含まれていたら、textBox2で指定された文字列をコメントする

            //textBox1に記入された文字列をフォームからもらい、word1とする
            string word1 = _form.GetWord1();

            //textBox2に記入された文字列をフォームからもらい、word2とする
            string word2 = _form.GetWord2();

            //word1とword2に何か書いてあったら
            if ((word1 != "") && (word2 != ""))
            {
                //例の関数を呼ぶ
                AnalyzeContainsAndAutoReply(commentData, word1, word2);
            }

        }

        /// <summary>
        /// data.Commentにw1が含まれていたらw2とコメントする
        /// </summary>
        /// <param name="data">コメントデータ</param>
        /// <param name="w1">検出文字列</param>
        /// <param name="w2">投稿文字列</param>
        void AnalyzeContainsAndAutoReply(NicoLibrary.NicoLiveData.LiveCommentData data, string w1, string w2)
        {
            //コメント文字列を取り出す
            string comment = data.Comment;

            //コメントにw1が含まれていたら
            if (comment.Contains(w1))
            {
                if (_oldSendComment != w2)//※同一ワードの連続投稿防止
                {
                    //w2をコメント送信する
                    bool result = _host.SendComment(w2);

                    //コメント送信成功?
                    if (result == true)
                    {
                        //ログをフォームに表示する
                        string no = data.No;//コメ番を取り出す
                        _form.OutputLog(no, w1, w2);

                        //前回送信コメント
                        _oldSendComment = w2;

                        MessageBox.Show(w1+"を検出したので"+w2+"をコメントしました", Name);//動作確認用MessageBox
                    }
                }
            }
        }
        #endregion
    }
}

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Plugin;
namespace NCV_Plugin_Sample_02
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //textBox1に記入された文字列を返す
        public string GetWord1()
        {
            return textBox1.Text;
        }

        //textBox2に記入された文字列を返す
        public string GetWord2()
        {
            return textBox2.Text;
        }

        //textBox3にログを表示する
        public void OutputLog(string n, string w1, string w2)
        {
            //ログを追加する
            textBox3.Text += "コメ番" + n + ": " + w1 + " に対して " + w2 + " とコメントしました";
        }
    }
}

続編、デバッグ編もどうぞノ

156件のコメント

  1. ピンバック:NiconamaCommentViewer(ニコ生コメントビューア)のプラグイン作成法 2 « 夏研ブログ

  2. 初めまして、ぽわわ と申します。
    掲載記事にひかれて拝見させていただきました。

    実行の際、コメントを送信するときに
    「_host.SendComment()」を上手く動作させることができずに困っています。

    掲載ソース「Class1.cs」の 219行目
    「bool result = _host.SendComment(w2);」等ですが、

    NCV 0.91.0.8 を使用しているので
    2011/04/22(金)のメンテは関係ないだろうと、勝手に想像はしているのですが・・・。

    何かヒントを頂けると幸いです。

    因みに、
    掲載ソース「Class1.cs」の 219行目を「bool result = true」にすれば
    送信はしませんが他は動作しているので
    ポイントは「_host.SendComment()」周りなのかな?と思っています。(・_・;?

  3. >#1 ぽわわさん
    こんばんわ。
    ご指摘のとおり、_host.SendComment()メソッド内で
    エラーしてそうでした。NCVの内部エラーかなと思います。
    (例外:インデックスが配列の境界外です。が発生)

    _host.SendComment(“184”, “しょけん”);
    のように引数2つバージョンのメソッドも用意されています。
    こちらは正常にコメント送信できるようです、
    試してみてください。

  4. ありがとうございます。
    上手く動作しました!

    第一引数のコマンドに
    どんなものがあるのか今から調べてみようと思います(^^)

  5. >#3 ぽわわさん
    こんばんわ。
    無事動作とのこと、よかったです。
    コマンドはニコ生のコマンドボタンで設定できるもの
    (カラー、サイズ、位置)に対応してそうですが、、はたまた真相はどうなのか、
    自身の目で確かめてみてください^^ノ

  6. お手数をおかけしました。
    アドバイスのおかげで、次のステップに進めました♪
    どんなコマンドが出てくるのか楽しみですw(^^)

  7. はじめまして。
    プラグイン作成で質問です。

    動作を簡単に説明しますと
    ————————————–
    テキストボックスで指定のコメント番号を入力して
    チェックボックスにチェックを入れたら入力したコメント番号を取得して運営コメントに飛ばす。
    ————————————–
    この動作をするのは可能なんでしょうか?。
    可能でしたら、ソースコードを教えてもらえませんか?

    プログラミングは、初心者でなかなかわからなくて。
    無理でしたら教えてもらわなくてもいいです。

    長々とすいません

  8. >#6 ゆんさん
    こんばんわ。
    指定したコメ番のコメント文と同じ文章で
    運営コメントを投稿する機能ということでよいでしょうか?

    以下はそれであっていると仮定した場合の実装例です。

    1 コメントを受信する

    2 チェックボックスがOnならば、
    受信したコメントの番号を調べる

    3 受信したコメント番号がテキストボックスのコメント番号と同じならば、
    そのコメント文を運営コメントとして投稿する。

    ◆1 コメント受信
    ・プラグインを起動する前のコメントもケアする場合
    GetAcquiredComment()で、プラグインを起動する前に投稿されていたコメントを取得します。
    (過去1000件までという制約があったかもしれません。)
    プラグインが起動されたら、まずGetAcquiredComment()で
    コメントをまとめて取得し、2、3の処理を行います。

    プラグインが起動されたら呼ばれる処理()
    {
        if(チェックボックスがOnならば)
        {
            List<LiveCommentData> listReceivedComment = new List<LiveCommentData>();
            listReceivedComment = _host.GetAcquiredComment();
            foreach (LiveCommentData data in listReceivedComment)
            {
                if(data.No == テキストボックスのNo)
                {
                    //運営コメを送信する例
                    SendOwnerComment("184", data.Comment, "投稿者名");
                }
            }
        }
    }
    

    ・プラグイン起動後に投稿されるコメントの処理
    コメント受信イベントハンドラでリアルタイムに取得し、
    2、3の処理を行うことになります。
    コメント受信イベントハンドラは、ブログのサンプルコードを参考にしてみて下さい。

    ◆2, 3 チェックボックスのOnOffと、テキストボックスの文章を取得
    チェックボックスのOnOffは、checkBox1.Checked
    テキストボックスの文章は、textBox1.Textで取得できます。
    ブログのサンプルコードのForm1.csを改造してみて下さい。

    ◆3 運営コメントの投稿
    SendOwnerComment()で投稿できるようです。以下の3種類が用意されています。
    引数3つバージョンの使用例は前述の通りです。
    bool SendOwnerComment(string comment);
    bool SendOwnerComment(string command, string comment, string name);
    bool SendOwnerComment(bool anonymity, string location, string size, string color, string comment, string name, string sound);

  9. 返答ありがとうございます。

    ここまで丁寧に返答してくださるとは感謝してます。
    さっそくやってみます!

  10. プラグイン開発の参考になりましたら幸いですノ

  11. こんにちは。再び質問です。

    チェックボックスがONのときの処理はどこにかけばいいのでしょうか?。
    今頃その質問と思うかもしれませんがすいません。
    作業時間がなかったもので。

  12. >#10 by ゆんさん
    こんにちは。
    チェックボックス判定は、コメント取得時に実施します。

    プラグイン起動前に投稿されたコメント処理の例です

    public void Run()
    {
        if (_form == null)//フォームが生成されてなければ
        {
            //※ブログ本文のサンプルコードをご参照下さい
            //フォームの生成
            //フォームが閉じられた際のイベントハンドラ追加
            //放送開始直後イベントハンドラ追加
            //放送終了直後のイベントハンドラ追加
            //コメント受信時のイベントハンドラ追加
        }
    
        if(チェックボックスがOnならば)
        {
            //過去コメデータのリストを取得
            List<LiveCommentData> listReceivedComment = new List<LiveCommentData>();
            listReceivedComment = _host.GetAcquiredComment();
            //過去コメデータのリストからコメデータ1つを取り出しながらループ
            foreach (LiveCommentData data in listReceivedComment)
            {
                if(data.No == テキストボックスのNo)//テキストボックスで指定されたコメ番ならば
                {
                    //運営コメを送信する例
                    SendOwnerComment("184", data.Comment, "投稿者名");
                }
            }
        }
    }
    

    プラグイン起動後に投稿されたコメント処理の例です

    //コメント受信時イベントハンドラ
    void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
    {
        if(チェックボックスがOnならば)
        {
            //受信したコメント数を取り出す
            int count = e.CommentDataList.Count;
    
            //最新のコメントデータを取り出す
            LiveCommentData data = e.CommentDataList[count-1];
    
            if(data.No == テキストボックスのNo)//テキストボックスで指定されたコメ番ならば
            {
                //運営コメを送信する例
                SendOwnerComment("184", data.Comment, "投稿者名");
            }
        }
    
    }
    

    上記例では、
    過去コメの場合は、コメント取得前にチェックボックス判定を行い、
    最新コメの場合は、コメント取得後にチェックボックス判定を行っています。

    ご不明な点は遠慮なく聞いてくださいノ

  13. こんにちは。迅速な対応ありがとうございます。

    if(チェックボックスがonならば)

    “チェックボックスがonならば”はcheckBox1.Checkedでいいのですか?。

    もしそうならば、エラーに checkBox1はコンテキストないに存在しません(?)とたぶん出ると思うんですが。

    そこはどうなんでしょう?

  14. >#12 by ゆん さん
    こんにちは。

    textBox1やcheckbox1はフォームクラスのprivateなメンバですので、
    別のクラス(ここではプラグインクラス)から直接アクセスできません。

    そこで、フォームクラスにテキストボックスやチェックボックスの値を
    戻り値で返すpublicなメソッドを追加してあげるとうまくいきます。

    ブログ本文サンプルコードのGetWord1メソッドは、テキストボックスの値を
    プラグインのクラス側から取得するためのメソッドになります、参考にしてみて下さい。

  15. 丁寧な回答ありがとうございました。
    プラグイン作成についてだいたいわかってきました。
    また何かあったらお願いします。

  16. >#14 by ゆん さん
    参考になりましたら幸いです。プラグイン作成応援しておりますノ

  17. はじめまして。
    ロフトさんのプラグイン大変使いやすく重宝しております。

    質問なのですが、Formのボタンが押されたらSendCommentで通常コメントを送信
    というコードはどういうふうに書けばいいのでしょうか?
    教えていただけると幸いです。

    C#初心者なもので初歩的な質問でしたらすみません。

  18. >#16 by こじ さん
    こんにちは。
    http://c-loft.com/blog/?p=878 のコードをベースに、
    ボタンを押すと運営コメを送信するように改造する方法をご紹介します。
    以下①、②、③の手順になります。

    ①フォームを持つプラグインを作る
     http://c-loft.com/blog/?p=878
     の記事にてご紹介しております。
     ただし、まっさらなフォームしかありませんので、
     さらに、以下②、③の手順を行います。

    ②フォームにボタンを追加し、ボタンが押されたときのイベントハンドラを書く。
     こちらは、C#開発の基本手順になります。
     以下コード例です(button1_Clickを追加しました)。
     _hostも追加しています、これについては後述します。
    Form1.cs

    using Plugin;
    namespace NCV_Plugin_Sample_02
    {
        public partial class Form1 : Form
        {
            IPluginHost _host;
    
            public Form1()
            {
                InitializeComponent();
                _host = null;
            }
            private void button1_Click(object sender, EventArgs e)
            {
                if (_host != null)
                {
                    //_host.SendComment("184", "通常コメントテスト");//通常コメ
                    _host.SendOwnerComment("運営コメントテスト");//運営コメ
                    
                    //※ちなみにtextboxを追加して以下のようにすると便利
                    //_host.SendOwnerComment(textbox1.Text);
                }
            }
        }
    }
    

    ③フォームにプラグインのホストを持たせる
     SendCommentやSendOwnerComment等、コメビュの機能を使うには、
     IPluginHost _host;が必要です。
     Class1クラスは_hostを持っており、SendCommentやSendOwnerComment等を呼ぶことができます。
     Form1クラスは_hostを持っていないので、外部から_hostをもらう必要があります。
     
     そこでForm1に_hostをもらうためのメソッドを追加します。
     以下コード例です(SetHostメソッドを追加しました)。
    Form1.cs

    using Plugin;
    namespace NCV_Plugin_Sample_02
    {
        public partial class Form1 : Form
        {
            IPluginHost _host;
    
            public Form1()
            {
                InitializeComponent();
                _host = null;
            }
            public void SetHost(IPluginHost host)
            {
                //ホストをもらう
                _host = host;
            }
            private void button1_Click(object sender, EventArgs e)
            {
                if (_host != null)
                {
                    //_host.SendComment("184", "通常コメントテスト");//通常コメ
                    _host.SendOwnerComment("運営コメントテスト");//運営コメ
                    
                }
            }
        }
    }
    

     上記で追加した_formのSetHost()メソッドをClass1から呼び、Class1の_hostをForm1に渡します。
     以下コード例です(_form.SetHost(_host);を呼ぶコードを追加しました)。
    Class1.cs

    public void Run()
    {
        if (_form == null)
        {
            //フォームの生成
            _form = new NCV_Plugin_Sample_02.Form1();
            _form.Show((System.Windows.Forms.IWin32Window)_host.MainForm);
    
            //閉じられた際のイベントハンドラ追加
            _form.FormClosed += new System.Windows.Forms.FormClosedEventHandler(_form_FormClosed);
    
            //フォームにhostを渡す
            if(_host.IsConnected == true)
            {
                _form.SetHost(_host);
            }
        }
    }
    

    Class1クラス以外のクラス(今回はForm1クラス)に_hostを渡すことで、
    本来_hostを持たないクラスでもコメビュの機能(_hostのメソッド)を使用できるようになります。

    ご参考になれば幸いです。ご不明な点はお尋ね下さいノ

  19. 回答ありがとうございます
    大変参考になりました。
    ありがとうございました

  20. こんにちは。

    ついにプラグインが完成したのでお知らせします。
    色々助けていただきありがとうございました!。
    少し変えたりしましたが^^;

    配布場所はこちらです
    http://ux.getuploader.com/sakuani/

  21. >#19 by ゆん
    安価に便利なプラグインですね、より多くの方に使っていただくには、

    http://nicowiki.com/tools.html
    こちらのWikiを編集して掲載したり、

    http://sites.google.com/site/itaodotcom/home/ncv_plugin
    こちらのブログの管理人様(板尾さん)にお知らせすると、掲載して頂けると思いますよーノ

  22. はじめまして
    コミュニティの内容を変更するプラグインを考えていたのですが、cookieがよく分からなくて詰みました。
    コメビュ開発者のプラグイン作成用ドキュメントのあれを読んだんですが、どう書けばいいか分からず試せずで質問しました。

    NCVで使われているcookieを取得またはIE等のcookieの取得をして、コミュニティプロフィールを編集するプラグインを作りたいのですが、ここの「C#によるWEBサイトへのログイン方法」ってページのプログラムを使う方法しかありませんか?
    もしNCVのcookieをそのまま使用出来るのであれば、すいませんがソースコードを書いていただけませんか?
    出来ないのであれば「C#によるWEBサイトへのログイン方法」のプログラムを使わせていただきます。

    回答宜しくお願いします。

  23. ロフトくん

    >サミチさん
    はじめまして、こんにちわ。
    NCVのcookieをプラグインから取得するインタフェースは現状ないようでした。
    したがって、「C#によるWEBサイトへのログイン方法」の方法を使うことになると思います。

    本件の解説:
    これからニコ生ツールやNCVプラグインを作ってみようと思われる方向けに本件を解説します。

    一般に、ツールからログインするには、ツールから直接ログインする or ブラウザとクッキー共有する方法があります。
    前者は、「C#によるWEBサイトへのログイン方法」 http://c-loft.com/blog/?p=637
    後者は、「ニコ生アラート + コメントビューア + 1コメゲット ツールを作る(C#) その2」 http://c-loft.com/blog/?p=1127
    で紹介しています。

    今回は、NCVプラグインからニコニコにログインしたいという話です。
    既にNCV本体がニコ生にログインしているところが、単体のツールとは異なりますね。
    NCV本体のcookieをプラグインが取得(共有)することができれば、
    そのcookieでニコニコにログインができそうです。
    そこで、そのようなインタフェースがあるかを確認することになります。
    プラグイン作成用ドキュメントを見る限り、そのようなインタフェースはなさそうでした。

    クッキーそのものは取得できないようですが、
    クッキー共有元ブラウザ種別は、AppSettingInPlugin LoginUserSetting CookieSourceから
    取得できるようです、これをもとに判別したブラウザと、
    前述のブログ記事p=1127 の方法で、クッキーを共有すればニコニコにログインできそうです。

    また、コミュ編集権限を持つアカウントであれば、ブログ記事p=637のように、
    コミュ編集ページのHTML解析により、適切なパラメタをPOSTすることで、
    プラグインからコミュ情報編集ができると思われます。

  24. 詳しくありがとうございました。
    ちゃんと出来るか不安ですが頑張ります。(プログラミングは約2年やってるけど遊び半分で基礎すらないw)
    本当にありがとうございました。

  25. こんばんは。毎回丁寧な対応に感謝しています!。
    今、自動接続についてやているんですが
    なかなか理解できなくて困っています・・・。

    -現状-
    public void …..
    {
    Regex livn = new Regex(“[(co)(lv)(ch)][0-9]+”);
    if(checkBox1.Checked)
    {
    if(livn.IsMatch(wburl))
    {
    //自動接続
    checkBox1.Checked = false;
    }
    }
    }

    放送接続には void ConnectLive(string livenumber) を使うのかと思うのですが、記述がよくわからないです・・・。
    毎回忙しい中すいません。

    -追伸
    遅れましたがコミュニティのほうをリンクさせていただきました。
    IEでコミュニティなどだけログインできない状態のため書き込みでき
    ませんでした(進行形)。もし迷惑・許可できない場合は言ってください。

  26. ロフトくん

    >サミチさん
    お役に立てましたら光栄です。応援しております。

  27. ロフトくん

    >ゆんさん
    こんばんは。
    はい、ConnectLiveで接続できますよー。

    以下、一例です。
    Alert()の処理は略しています。

    Form1.cs

        public class Form1 : Form
        {
            IPluginHost _host = null;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            /// <summary>
            /// プラグインホストを設定する
            /// </summary>
            /// <param name="host"></param>
            public void SetHost(Plugin.IPluginHost host)
            {
                _host = host;
            }
    
            /// <summary>
            /// アラート
            /// </summary>
            public void Alert()
            {
                if(アラート条件にHIT)
                {
                    Connect(放送番号等);
                }
            }
    
            /// <summary>
            /// 放送接続メソッド呼び出し
            /// </summary>
            /// <param name="program"></param>
            public void Connect(string program)
            {
                if (_host != null)
                {
                    _host.ConnectLive(program);
                }
            }
        }
    

    Class1.cs

        public class Class1 : IPlugin
        {
            #region IPlugin メンバー
            private IPluginHost _host = null;
            private Form1 _form = null;
    
                             :
    
            public void Run()
            {
                if (_form == null)
                {
                    //フォームの生成
                    _form = new Form1();
                    _form.Show((System.Windows.Forms.IWin32Window)_host.MainForm);
    
                    //プラグインホストを設定する
                    _form.SetHost(_host);
                }
            }
    
                             :
    

    上記は、プラグイン側から_form.SetHost(_host);を呼んで、
    フォーム側でプラグインホストを使えるようにしています。

    不足な点は、追加で聞いてくださって構いません。

  28. ロフトくん

    >ゆんさん
    コミュリンクありがとうございます。

  29. しゅーべると

    初めまして。
    このブログを見てプラグインを作成しております。
    感謝しております。

    さて本題ですが、
    現在NCV本体側で取得、または設定したユーザー名を取得する方法を探しております。

    何かいい方法ありませんでしょうか?

  30. こんばんは。
    回答ありがとうございます!。
    毎回本当に助かります。
    また、質問に来ると思うのでその時はお願いします。

    -コミュリンクが迷惑ではなくてよかったです。

  31. ロフトくん

    >しゅーべるとさん
    はじめまして、記事を読んで頂き、ありがとうございます。

    開発者ドキュメントのIPluginHost Membersの項目を
    眺めていったところ、
    GetUserSettingInPlugin()で取得できる情報の中に、
    ニックネームが入っているようです。
    以下、複数行設定(あらかじめMultiline プロパティを true )したtextbox1に表示する例です。

    Form1.cs

        public partial class Form1 : Form
        {
            IPluginHost _host = null;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            /// <summary>
            /// プラグインホストを設定する
            /// </summary>
            public void SetHost(Plugin.IPluginHost host)
            {
                _host = host;
            }
    
            /// <summary>
            /// ユーザー設定を取得・表示する
            /// </summary>
            private void button1_Click(object sender, EventArgs e)
            {
                if (_host != null)
                {
                    //ユーザー設定リストを取得
                    UserSettingInPlugin userSetting = _host.GetUserSettingInPlugin();
    
                    //ユーザー設定を取り出す
                    string info = "";
                    foreach (UserSettingInPlugin.UserData data in userSetting.UserDataList)
                    {
                        //取り出せる値は開発者ドキュメントの
                        //UserSettingInPlugin..::..UserData Members
                        //のページを参照してください。
                        info +=   data.RegisterTime + " "       //登録日時
                                + data.UserId+ " "              //ユーザーID
                                + data.NickName + " "           //ニックネーム
                                + data.BGColor.ToString()  + " "//背景色
                                + data.IsReadOut.ToString()+ " "//コメント読み上げ対象か
                                + data.CommunityNum             //依存コミュニティorチャンネル番号
                                + "\r\n";
                    }
    
                    //ユーザー設定を表示
                    textBox1.Text = info;
                }
            }
        }
    

    Class1.cs

    public class Class1 : IPlugin
    {
        #region IPlugin メンバー
        private IPluginHost _host = null;
        private Form1 _form = null;
    
                         :
    
        public void Run()
        {
            if (_form == null)
            {
                //フォームの生成
                _form = new Form1();
                _form.Show((System.Windows.Forms.IWin32Window)_host.MainForm);
    
                //プラグインホストを設定する
                _form.SetHost(_host);
            }
        }
    
                         :
    
    
  32. ロフトくん

    >ゆんさん
    いえいえ、コミュリンク大歓迎ですよー

  33. はじめまして、ビンといいます。
    ここで勉強させて頂いてNCVプラグイン開発を進めています。

    自分の開発はVB.netで行っているのですが、ここで学んだことのVB.net版を作成・ネットで公開してもよろしいでしょうか?

  34. ロフトくん

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

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

  35. 許可を頂きありがとうございます。
    引用・参考元の表記はさせてもらいますね。

  36. こんにちは、
    プラグインの作成にこちらのサイトをよく参考にさせて頂いています。
    非常に分かりやすくてとても勉強になります。

    早速で申し訳ありませんが、もしお分かりでしたら教えて頂きたいことがあります。

    BSP権限でのコメントの仕方ですが、
    SendPresscastCommentメソッドを使ってコメントをしようとした場合、
    権限が無い人が行うと権限がありませんとエラーになります。

    そこでBSP権限の有無をチェックしてから権限がある人のみコメント送信ができるようにしたいのですが、
    BSP権限の有無を取得する方法が分かりませんでした・・・。

    どのように取得すればよろしいでしょうか、ご教授頂けますと幸いです。

  37. ロフトくん

    >さぼちくさん
    こんにちは。
    以下で判定できるようです。

    using NicoLibrary.NicoScraper;
                            :
                            :
    	NicoLiveInfo nicoLiveInfo = _host.GetLiveInfo();
    	if (nicoLiveInfo.IsBSP == true)
    	{
    	    MessageBox.Show("BSP権限あるよ");
    	}
    	else
    	{
    	    MessageBox.Show("BSP権限ないよ");
    	}
    
    • 早速の回答ありがとうございます!

      組み込んだところ意図した動作をさせることができました!
      NicoLibraryについての情報がほとんどなくて非常に苦労していましたので
      大変助かりました。

      今後もこのような形で質問させて頂くかもしれませんが、お時間あるときにでも
      お付き合い頂けますと幸いです。

      P.S. 先ほどコミュニティがあることに気付いたので早速参加させて頂きました。

  38. ロフトくん

    >さぽちくさん
    開発者向けドキュメント(Plugin_Doc.chm)と、VisualStudioの右クリック->定義 機能でめぼしいメンバを探していく感じですね。
    コミュ参加ありがとうございます。
    放送頻度は高くないですがツール開発の話もしていますのでよろしければ見に来て下さい。

  39. こんにちは。
    とてもわかりやすい説明で助かっています、

    ですがちょっと行き詰ってしまったので質問させていただきます。
    初歩的な質問ですがよろしくお願いします。

    自分は、NCVを起動したときからプラグインを自動で実行する。というものを
    いろいろ試行錯誤し、やってみたのですが。
    なぜかほかの放送では自動で実行できるのに、自分の放送では「動作を停止しました」と出てしまい、放送に接続できません。
    どうしたらよいでしょうか。

    • 補足です。

      フォームを表示しなくても自動で実行できるようにしてみたいのです。
      よろしくお願いします

      • すいません。。。よろしくお願いいたします・・・。

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using Plugin;
        namespace NCV_Plugin_Sample
        {
        public class Class1 : IPlugin
        {
        private IPluginHost _host = null;

        #region IPlugin メンバ

        ///
        /// IsAutoRunがtrueの場合、アプリケーション起動時に自動実行される
        ///
        public void AutoRun()
        {
        //throw new NotImplementedException();
        //コメント受信時のイベントハンドラ追加
        _host.ReceivedComment += new ReceivedCommentEventHandler(_host_ReceivedComment);
        }

        ///
        /// プラグインの説明
        ///
        public string Description
        {
        //get { throw new NotImplementedException(); }
        get { return “プラグインのサンプルです”; }
        }

        ///
        /// プラグインのホスト
        ///
        public IPluginHost Host
        {
        get
        {
        //throw new NotImplementedException();
        return this._host;
        }
        set
        {
        //throw new NotImplementedException();
        this._host = value;
        }
        }

        ///
        /// アプリケーション起動時にプラグインを自動実行するかどうか
        ///
        public bool IsAutoRun
        {
        //get { throw new NotImplementedException(); }
        get { return true; }
        }

        ///
        /// プラグインの名前
        ///
        public string Name
        {
        //get { throw new NotImplementedException(); }
        get { return “サンプルプラグイン”; }
        }

        ///
        /// プログインを実行する
        ///
        public void Run()
        {
        //throw new NotImplementedException();
        }

        ///
        /// プラグインのバージョン
        ///
        public string Version
        {
        //get { throw new NotImplementedException(); }
        get { return “1.0”; }
        }
        //コメント受信時イベントハンドラ
        void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
        {
        //受信したコメント数を取り出す
        int count = e.CommentDataList.Count;

        //最新のコメントデータを取り出す
        NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[count – 1];

        //コメント文字列を取り出す
        string comment = commentData.Comment;

        //①
        //コメントに”ぬるぽ”が含まれているか判定し、
        //含まれていたら、”ガッ”とコメントする
        if (comment.Contains(“ぬるぽ”))
        {
        //含まれているので”ガッ”をコメントする
        bool result = _host.SendComment(“ガッ”);

        }
        }

        #endregion
        }
        }

  40. ロフトくん

    コメントがない放送に接続した場合、int count値が0になるみたいですね。
    count値が0の場合はreturnするとよいかと思います。

            //コメント受信時イベントハンドラ
            void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
            {
                //受信したコメント数を取り出す
                int count = e.CommentDataList.Count;
    
                if (count == 0)
                {
                    return;
                }
    
                //最新のコメントデータを取り出す
                NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[count - 1];
    
                //コメント文字列を取り出す
                string comment = commentData.Comment;
    
                //①
                //コメントに”ぬるぽ”が含まれているか判定し、
                //含まれていたら、”ガッ”とコメントする
                if (comment.Contains("ぬるぽ"))
                {
                //含まれているので”ガッ”をコメントする
                bool result = _host.SendComment("ガッ");
    
                }
            }
    
  41. はじめまして!!プラグイン制作において、とても参考になる記事ばかりで感謝しております。
    現在、「@(名前)」でコテハンが自動登録できるように、ユーザー背景色もコメントで自動登録できればと思い制作しているのですが、「ユーザーIDを指定して、NCVのユーザー背景色を塗り替える」という動作は可能でしょうか?

    ご教授いただけますと非常に幸いです。
    よろしくお願いいたします。
     

  42. ロフトくん

    >XNさん
    こんにちは。
    _host.GetUserSettingInPlugin() にて現状のユーザー設定を取得し、
    _host.EditUserSettingInPlugin()にてユーザー設定を書き換えることが可能です。

                    //ユーザ設定リストを取得
                    Plugin.UserSettingInPlugin userSetting = _host.GetUserSettingInPlugin();
    
                    //ユーザ設定リストを探索
                    foreach (Plugin.UserSettingInPlugin.UserData data in userSetting.UserDataList)
                    {
                        //ユーザID 1234のユーザのデータを書き換える例
                        if (data.UserId == "1234")
                        {
                            data.BGColor = Color.Blue;//青
                            data.BGColor = Color.FromArgb(0xFF, 0x00, 0x00, 0xFF);//A, R, G, B による指定の例(10進数なら (255, 0, 0, 255) )
                            _host.EditUserSettingInPlugin(data);
                        }
                    }
    

    他、ユーザ設定の追加(AddUserSettingInPlugin)や、削除(DeleteUserSettingInPlugin)も可能なようです。
    プラグイン開発者向けドキュメントを参照してみて下さい。

  43. はじめまして。
    FMEAutometorでNCV連携しているのですが、
    プラグインのフォームを開いたまま、FMEAutometorで枠取りすると、
    NCVが落ちてしまいます。
    落ちないようにするためにはどうすればよいでしょうか?

  44. ロフトくん

    >PGさん
    こんにちは、はじめまして。
    FMEAutometorは使ったことがなくて憶測になりますが、
    FMEAutometorで枠取りすると、その放送をNCVで開くような連携機能でしょうか?

    すると、NCVが放送に接続するタイミングでエラーが起きている可能性があるので、
    プラグインに原因がありそうならば、放送への接続ハンドラにブレークポイントを貼って、
    ステップ実行してみて、どこでエラーしているか見てみるとよいかと思います。

    プラグインのステップ実行の方法については以下の記事をご参照下さい。
    http://c-loft.com/blog/?p=1793

  45. 解決しました。
    上の記事( 2012年4月19日)に書いてありました。
    失礼しました。

  46. ロフトくん

    >PGさん
    こんにちは、解決してよかったです。
    ブログ本文に反映しておきました。

  47. こんばんは。
    また質問させて下さい。

    1:コメントしたユーザーのコテハンを取得する方法
    (_host.GetUserSettingInPlugin() にて現状のユーザー設定を取得できるというのは
    知っています)

    2:放送時間の残り時間を知る方法
    (経過時間を取得する方法は知っています。延長された場合の残り時間取得方法が分かりません。)

    すみませんが、よろしくお願いします。

  48. ロフトくん

    >PGさん
    こんにちは。

    >1:コメントしたユーザーのコテハンを取得する方法
    当ブログ記事コメント 2011年8月25日 at 6:50 PM をご参照下さい。
    UserSettingInPlugin.UserData型メンバにNickNameがあるようです。

    > 2:放送時間の残り時間を知る方法
    こちらはやったことないので憶測です。
    GetPlayerStatus()戻り値のEndTimeが放送終了時間のようです。
    残り時間 = EndTime – StartTime – 経過時間
    (延長されたらEndTimeは伸びるようなので、
    延長されたタイミングで計算しなおすとよいかと思われます。)

  49. お返事ありがとうございます。
    お返事を参考に調べましたが、上手くいっていません。

    1)について
    // コテハン取得関数
    public string getKotehan()
    {
    UserSettingInPlugin userSetting = _host.GetUserSettingInPlugin();
    string kotehan= “”;
    foreach (UserSettingInPlugin.UserData data in userSetting.UserDataList)
    {
    if(data.UserId == 今コメントした人のID) ←ここのif文の条件が分かりません
    {
    kotehan = data.NickName;
    }

    return kotehan;
    }

    2)について

    NicoLivePlayerStatus state = _host.GetPlayerStatus();
    stateのメンバにEndTime 、StartTimeがなくて困っております。(>0<)
    stateにはTimeというメンバがありますが、それはそれは違うようです。

    すみませんが、お暇な時で結構ですのでご回答願います。

  50. ロフトくん

    >PGさん
    こんにちは。

    1)について
    今コメントした人のID取得はコメント受信時イベントハンドラで
    実施するとよいと思われます。

            void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
            {
                //受信したコメント数を取り出す
                int count = e.CommentDataList.Count;
                if (count == 0)
                {
                    return;
                }
    
                //最新のコメントデータを取り出す
                NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[count - 1];
    
                //ユーザIDを取り出す
                string userid = commentData.UserId;
    

    2)について
    http://watch.live.nicovideo.jp/api/getplayerstatus?v=lvxxxxxxxx
    上記URLから取得できるニコ生API getplayerstatusの応答に
    start_timeとend_timeがあるのですが、
    見た感じ、NCVプラグインに公開されている_host.GetPlayerStatus()戻り値には
    start_timeしか含まれていないようです。

    NicoLivePlayerStatus status =  _host.GetPlayerStatus();
    string startTime = status.Stream.StartTime;//ある
    string endTIme = status.Stream.EndTime;//ない
    

    NCV本体側で対応(NCV開発者に対応をお願い)する or
    プラグイン側で対応(上記URLに対してHTTP GETを行う処理を実装)する
    のどちらかになるかと思います。

    HTTP GETの方法については、
    ブログ記事 http://c-loft.com/blog/?p=1127 をご参照下さい(関数 GetPlayerStatus() )。
    (クッキーが必要です。この方法を使う場合はお知らせ下さい。
    クッキーの情報は別途DM等でお知らせします。)

    http://live.nicovideo.jp/api/getpublishstatus?v=lvxxxxxxxx
    ちなみに、上記URLから取得できるニコ生API getpublishstatusの応答にも
    start_timeとend_timeがあり、
    こちらは、NCVプラグインに公開されている_host.GetPublishStatus()戻り値に
    両方含まれています。
    ただし、getpublishstatusは放送主専用APIです。
    生主向けの機能を実装されるならばこちらの方法で実現できるのではないかと思います。

    //放送主のみ
    NicoLivePublishStatus publish =  _host.GetPublishStatus();
    string startTime = publish.Stream.StartTime; //ある
    string endTime = publish.Stream.EndTime;//ある
    
  51. 丁寧な回答ありがとうございます。

    1) commentDataのメンバにIDがあったのですね。
    よく調べずにすみませんでした。

    2)については生主限定の機能で行こうと思い、以下のテストプログラムを書いてみました。
    //////////////////////////////////////////////////////////////////////////////////////////////
    private void button1_Click(object sender, EventArgs e)
    {
    if (_host != null)
    {
    NicoLivePlayerStatus player = _host.GetPlayerStatus();
    if (state.Stream.IsOwner == “1”)
    {// 生主
    NicoLivePublishStatus publish = _host.GetPublishStatus();
    if (player.Stream.StartTime != null) MessageBox.Show(player.Stream.StartTime); // 表示される
    if (publish.Stream.StartTime != null) MessageBox.Show(publish.Stream.StartTime); // 表示されない
    if (publish.Stream.EndTime != null) MessageBox.Show(publish.Stream.EndTime); // 表示されない
    }
    }
    }
    //////////////////////////////////////////////////////////////////////////////////////////////
    (↑のプラグラムが間違っていたら、ご指摘ください。)

    publish.Stream.StartTime と publish.Stream.EndTimeがnullになるようです。

    StartTimeはplayerで取得できているので、
    EndTimeについてはプラグイン側で対応したいと考えています。→生主限定機能ではなくなる

    ブログ記事 http://c-loft.com/blog/?p=1127 の関数 GetPlayerStatus() は読みました。
    よろしければ、クッキー情報を教えて下さい。

    以上です。

  52. ロフトくん

    >PGさん
    こんにちは。

    2)について
    GetPublishStatus()戻りの方はnullが返るみたいですね。
    クッキー情報はTwitter loftkun宛にDMを下さい。DMにてお知らせします。

  53. 2)がうまく動作しました。
    延長のタイミングはコメントで取得するようにしました。
    いろいろありがとうございました。

  54. こんばんわ

    NCVのプラグインをつくろうと思っています
    以前作った際も使わせていただきました
    今回はコメント残そうと思って

    作成予定のプラグインは
    「簡易ブラウザ」的なものです
    (生放送を視聴するための物)

    その際
    ・こちらの記事
    ・コメント欄の情報
    (cookie共有ブラウザの取得)
    ・「ニコ生アラート + コメントビューア + 1コメゲット ツールを作る(C#) その2」のクッキーゲッター周り
    のソース等
    お借りさせていただきます

  55. こめんと分けさせていただきますが
    もう一つ

    自分のwikiであるコメントビューアのプラグイン作成
    方法等の記事を書こうと思っています

    その際
    「NiconamaCommentViewer(ニコ生コメントビューア)のプラグイン作成法 1~3」
    の記事を利用して同じように書きたいと思っています
    大丈夫でしょうか??

  56. ロフトくん

    >じゅんさん
    こんにちは、ブログ参照&コメントありがとうございます。
    使えそうな情報がありましたらどうぞお使い下さいませ。

  57. こんにちは、SNAKE(すなけ)です
    教えていただきたいものがあるのですが、
    TextBoxに送信したい文字を入力し、ボタンを押すと入力した文字を送信するようにしたいのですが、この場合、どのようにコードを作ればよいか、ご教授いただけないでしょうか。よろしくお願いいたします、ちなみにNCVプラグインを作るのが今回が初です

  58. ロフトくん

    >SNAKEさん
    こんにちは。
    ボタンを押すとコメ(通常コメ、運営コメ)するプラグインの作成法を
    コメント欄 http://c-loft.com/blog/?p=1058#comment-46 にて紹介していますので、
    参考にされてみて下さい。
    送信するコメント文が”通常コメントテスト” “運営コメントテスト”のように固定になっていますので、Textboxを追加し、textbox.textを使うようにするとよいかと思います。

    ちなみに、プラグイン作成法 1、2の記事に比べ、3(本記事)は、ちょっといろいろ詰め込み過ぎた感があり、3はシンプルなプラグイン(Form,Textbox,Buttonとの連携方法)の紹介に留め、新規記事(4)を作成して自動応答プラグインなどを取り上げた方がよかったなーと思っています(が今のところ記事の書き直しは着手できていません。。。)
    その際はご要望いただいたテーマ(“TextBoxに送信したい文字を入力し、ボタンを押すと入力した文字を送信”)にしたいと思います。

  59. ありがとうございます!参考にさせていだだきます

  60. すみません、もう一つお聞きしたいものがあるのですが、
    自動応答に関して質問です、放送主のコメントは自動で応答しないように作りたいのですが、その場合はどうしたらよいですか?

  61. ロフトくん

    >SNAKEさん
    こんにちは。
    NicoLibrary.NicoLiveData.LiveCommentData hogeComment;の、
    hogeComment.premiumが”3″ならば放送主コメントのようです。

    ちなみに、放送主が自分の意思で投稿したコメントだけでなく、
    自動的に発行されるコマンド(“/commentmode shita”や”/hb ifseetno 1″等)も
    hogeComment.premiumが”3″のようです。(放送主による投稿として扱われているみたいですね。)

  62. ありがとうございます!解決しました!

  63. はじめまして、山田と申します
    VB覚えたてで「なにか趣味でできることはないか?」と
    徘徊していたところ、このサイトにとても興味が湧き
    VB2010Expressでがんばって作成法3まで辿り着けました。

    しかしながら、作成法3で実際に放送に接続するとNCVが
    強制終了されてしまいます。どうしても原因がわからない・・・

    そこで、次項のデバッグを参照したところ
    >VisualStudioのデバッグ->プロセスにアタッチという
    項目がどう探しても出てきませんでした・・・
    C#との違いかもしれませんが、デバッグができないと
    強制終了の原因が皆目見当つかずお手上げです

    少し調べたところExpressにはない機能なのか?
    と思えてきましたが、なにかご存知でしたら
    ご教授頂けませんでしょうか?
    なにはともあれデバッグなのです!

    お手数ですが宜しくお願いします。

  64. ロフトくん

    >山田さん
    はじめまして、こんにちは。
    VisualStudioエディション別対応情報が以下に掲載されております。
    (“その他のバージョン”からVisualStudio2010以外も確認できます。)
    http://msdn.microsoft.com/ja-jp/library/c6wf8e4z%28v=vs.100%29.aspx
    上記によるとExpressにない機能ということになります。

    http://c-loft.com/blog/?p=1793 の記事の手順2について
    VisualStudio Expressで可能かどうかについて補足します

    手順2 親アプリを起動する
    ・プロセスにアタッチ を利用する場合
     既に起動済みのアプリをデバッグ対象とするための機能です。
     →Expressにこの機能はありませんでした。

    ・自動化する場合
     DLL呼出しアプリを新規起動しアタッチする手順です。
     →Expressにこの設定は用意されていません。
      正確には設定画面(プロジェクト->プロパティ->デバッグ->開始動作->外部プログラムの開始(X) )が用意されていません。
      しかしながら、自分でslnファイルに設定を書いてあげればアタッチできてしまいます(先ほど試してみて気づきました、ありがとうございます。)。

    というわけで、VisualStudio Expressでも、プロセスへのアタッチは可能です。
    slnファイルをテキストエディタで開き、<PropertyGroup>~</PropertyGroup>の設定を追記します。

      <PropertyGroup>
        <!-- ビルドしたdllをNCVのpluginsフォルダにコピーします -->
        <PostBuildEvent>copy $(TargetDir)$(TargetFileName) "C:\hogehoge\ncvがあるフォルダ\plugins\"</PostBuildEvent>
        
        <!-- F5を押すとNCVを新規起動しプロセスにアタッチします。 -->
        <StartAction>Program</StartAction>
        <StartProgram>C:\hogehoge\ncvがあるフォルダ\NiconamaCommentViewer.exe</StartProgram>
      </PropertyGroup>
    

    TargetDirはビルドしたdllがあるディレクトリ、TargetFileNameはビルドしたdllの名前に置き換えてくれます。
    (VisualStudioのエディションによって表記が微妙に異なります、上記はVisualC# 2010での表記です。)

    上記設定を追加すると、F5押下でビルド後、dllをNCVのpluginsフォルダにコピー、NCV立ち上げを行います。
    プラグインの試験したい箇所にブレークポイントを貼っておく等して、プラグインのデバッグが可能となります、お試し下さい。

    • ロフトくん様
      解答頂き、ありがとうございます。
      頂いた内容を頑張ってVB風に翻訳して
      トライしてみようと思います!

      先日うつろさんの放送に行く機会がありまして
      VS2012だとExpressでもアタッチができると
      教えて頂き、そちらも試しているところです。

      ご丁寧に対応いただきありがとうございました。

      大変感謝しております!!
      またなにかありましたらご相談させて下さい!!

  65. ガラス草

    はじめまして、ガラス草と申します。
    どうしてもわからないことがあったので質問してもよろしいでしょうか。

    1)コメントの投稿時間はどのように取得すればいいのでしょうか。
    LiveCommentData.Dateプロパティを変換すればいいのではないかと踏んでいるのですが、
    この数字の意味するところが幾分つかめず困っています。
    (DateTime.Ticksとかではないようですし…)

    2) NicoLibraryについて、リファレンスなど詳しい情報はどこで手に入るでしょうか。

  66. ロフトくん

    >カラス草さん
    はじめまして、こんにちは。
    1)
    LiveCommentData.Dateプロパティの値が投稿時刻を表すUnixタイムスタンプです、より扱いやすいDateTime型に変換可能です。
    以下ブログ記事の 2012年11月15日 at 6:38 PM のコメントをご参照下さい。
    http://c-loft.com/blog/?p=878#comment-6237

    2)
    リファレンスは見たことがありません、見つけたら教えて下さい^^
    (自分は、VisualStudioでインテリセンスをながめる、右クリック->定義に移動で定義をながめる、オブジェクトブラウザでのぞく、めぼしいメンバはブレークポイントで止めて値を見る、他の開発者に聞いてみる、などをあしがかりにしています。)

  67. ガラス草

    UNIXタイムスタンプでしたか。問題が解決しました。
    ありがとうございました。

  68. お久しぶりです、さっそく質問なのですが。
    UserSettingInPlugin userSetting = _host.GetUserSettingInPlugin();
    foreach (UserSettingInPlugin.UserData data in userSetting.UserDataList)
    {
    string ssgr = data.NickName;
    _form.label19.Text = ssgr;
    }
    上記のコードで実行すると、すべてのコテハンデータを取得してしまうので、コメントした人だけのコテハンを取得したいですが、この場合どのようにすればいいのかわからないでの、ご教授いただけないでしょうか
    よろしくお願いいたします。

  69. ロフトくん

    >SNAKEさん
    こんにちは。お久しぶりです。
    コメントデータのIndexOfUserSettingの値がuserSetting.UserDataListのindexになっているようです。

                //受信済みコメント取得
                List<NicoLibrary.NicoLiveData.LiveCommentData> list = _host.GetAcquiredComment();
                foreach (NicoLibrary.NicoLiveData.LiveCommentData data in list)
                {
                    //UserDataListのindex判定
                    int index = data.IndexOfUserSetting;
                    if (index == -1)
                    {
                        continue;//ユーザ設定なし
                    }
                    //ユーザ設定を取得
                    UserSettingInPlugin userSetting = _host.GetUserSettingInPlugin();//毎回やると遅い?
                    UserSettingInPlugin.UserData userData = userSetting.UserDataList[index];
    
                    //userのコテハンを取り出したり、煮るなり焼くなり
                    //string nickName = userData.NickName;
                }
    
  70. こんにちは、質問させてください。
    _host_ReceivedComment(に、新規のformインスタンスを行って、表示しようとした際コメビュが強制終了してしまいます。解決する方法について教えてください。
        public Form1 youtube;
    public void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
    {
    //受信したコメント数を取り出す
    int count = e.CommentDataList.Count;
    if (count == 0)
    {
    return;
    }
    //最新のコメントデータを取り出す
    NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[count – 1];

    //コメント文字列を取り出す
    string comment = commentData.Comment;

    //textBox1に記入された文字列をフォームからもらい、word1とする
    //string word1 = _form.GetWord1();

    //textBox2に記入された文字列をフォームからもらい、word2とする
    //string word2 = _form.GetWord2();

    //例の関数を呼ぶ

    AnalyzeContainsAndAutoReply(comment);
    youtube =new Form1();
    youtube.textBox1.Text=comment;
         youtube.show;

  71. ロフトくん

    >さすけさん
    こんにちは。
    上記コードをtry{}catch{}で囲み、catch部分にブレークポイントを張って、
    例外が発生しているかを確認してみて下さい。
    例外発生している場合は例外の内容と、どのコードで発生しているか見てみて下さい。

    デバッグ方法については以下をご参照下さい。
    http://c-loft.com/blog/?p=1297
    http://c-loft.com/blog/?p=1793

    ポイントは以下です。
    ・大きく分けて、コメント取り出し処理と新規フォーム生成処理があるので、分けて、どちらで問題が発生しているか調べる
    ・コメントを受信する度に新規でフォームを生成している(画面にコメントの数だけ(大量の)フォームが現れることになります。)ので、
    既にフォームが生成済みならば新規生成はしないようにする(youtubeの初期値をnullとし、nullの時のみnew Form1()する。)
    ・(ちなみに youtube.show;と記載されているところはyoutube.Show();ですよね)
    ・という理由から、フォームの生成処理をプラグインの初期処理に移動したい
    http://c-loft.com/blog/?p=878 を参照下さい。

  72. こんにちは。いつもお世話になっています。やっと3まで進んで具体的なプラグイン作成に入っています。コメントを取得してそれをソケット通信で流すプラグ印が書きたいのですが、うまくいきません。コメント文字列を取り出すのあとにソケット通信プログラムを書いて代入するだけではだめなのでしょうか?
    ばっすいですが、こんな感じです。
    //コメント受信時イベントハンドラ
    void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
    {
    //受信したコメント数を取り出す
    int count = e.CommentDataList.Count;
    if (count == 0)
    {
    return;
    }

    //最新のコメントデータを取り出す
    NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[count – 1];

    //コメント文字列を取り出す
    string comment = commentData.Comment;
    }

    // C#.NETのソケット通信
    public partial class Form1 : Form
    {
    // ソケット生成
    private System.Net.Sockets.TcpClient objSck =
    new System.Net.Sockets.TcpClient();
    private System.Net.Sockets.NetworkStream objStm;
    private void Form1_Load(object sender, EventArgs e)
    {
    // ソケット接続
    objSck.Connect(“localhost”, 39390);
    // ソケットストリーム取得
    objStm = objSck.GetStream();
    }

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
    // ソケットクローズ
    objStm.Close();
    objSck.Close();
    }

    private void button1_Click(object sender, EventArgs e)
    {
    // ソケット送信
    Byte[] dat =
    System.Text.Encoding.GetEncoding(“SHIFT-JIS”).GetBytes(“abcあいう”);
    objStm.Write(dat, 0, dat.GetLength(0));
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
    // ソケット受信
    if (objSck.Available > 0)
    {
    Byte[] dat = new Byte[objSck.Available];
    objStm.Read(dat, 0, dat.GetLength(0));
    MessageBox.Show(
    System.Text.Encoding.GetEncoding(“SHIFT-JIS”).GetString(dat));
    }
    }

  73. ロフトくん

    >ぶりさん
    こんにちは。
    ソケット通信で送信する処理については、
    “コメント文字列を取り出すのあとにソケット通信プログラムを書いて代入”でよいと思います。

    現状、ソケット通信で送信する処理をForm1クラス(Form1.cs)の
    ボタンクリックハンドラに実装されているのを、
    プラグインクラス(Class1.cs)の
    コメント受信時のイベントハンドラの中に実装することになります。
    (objSck、objStmをForm1からClass1に移植。)

  74. ∫MoR dk/dθ

    いつもお世話になっております。
    早速質問ですが、最新のPlugin.dllとNicoLibrary.dllを使用すると、コメント受信イベントでNCVが落ちる(固まるでも例外が発生するでもなくパッと消える)という現象に悩まされています。
    以前NCV0.98の頃に作ったプラグインは問題なく受信できているのですが…

    <環境>
    ●win7 pro
    ●VC#Express2010
    ●.Net4.0を指定
    ●NCV 0.133.1.68の本体、および付属の上記dllを使用

    <再現状況>
    1.NCVSample2を元に、接続時に
    _host.ReceivedComment += new Plugin.ReceivedCommentEventHandler(Host_ReceivedComment);
    でコメント受信イベントを登録。切断時には削除しています。

    ここにブレークポイントを設定してデバッグすると問題なくヒットして進みます。

    2ー1.Host_ReceivedCommentイベントハンドラ内で
    this.Text = System.DateTime.Now.Millisecond.ToString(); // 現在時刻を表示
    とすると、コメントが来るたびに現在時刻がウィンドウのタイトルに表示されます。
    ブレークポイントもヒットするので問題ありません。

    2-2.しかし、同じくHost_ReceivedCommentイベントハンドラ内で
    this.Text = e.CommentDataList[0].Comment;
    としてコメントを扱おうとすると、この行でデバッグが終了するのです。
    例外が発生しているでもなく、またステップインも出来ないので何が原因かわからない所です(EventArgsを扱うと落ちるのだろうけど、扱えないと作る意味がない…)

    <以前作成した時の環境>
    ●VC#Express2008
    ●.Net3.5を指定
    ●NCV 0.098の本体、および付属dll

    「昔の環境に戻すべき」と言われればそれまでなのですが、他に同じ状況の方がいないか気になったのです。

    どうぞよろしくお願いいたします。

  75. ロフトくん

    >∫MoR dk/dθ さん
    こんにちは。
    新バージョン向けプラグインが配布できないとちょっとへこみますね。。。

    試しに同じような機能を持つプラグインを作ってみましたが、
    現象は起きないようでした。
    以下にソリューションごと置いています、よろしければ試してみてください。
    http://c-loft.com/soft/ncvPluginSample_20140219_01.zip
    <環境>
    ●win7 pro
    ●VS 2010 pro
    ●.Net4.0を指定
    ●NCV 0.133.1.68の本体、および付属の上記dllを使用

    また、よろしければどこかのアップローダーに一式を置いて頂けたら、
    こちらの環境でも再現するか試してみます。

  76. ∫MoR dk/dθ

     検証恐れ入ります。
     ひとつわかったことは、pluginsフォルダにPlugin.dllとNicoLibrary.dllを入れると接続時に強制終了、という事でした。
     参照設定ではデフォルトで「ローカルコピー」がTrueになってるので、追加した際に切らないといけませんね。気づけて良かったです。

     他はUPしていただいたソリューションが正常に動きました。もしかしたら「プロジェクトを最初から作り直す」が正しい対処法だったのかもしれません。
     よければこれを元に製作してもよろしいでしょうか?

     自前のうまく動かないプロジェクトをUPしようと思ったんですが、試しに起動したら問題なく動いたので様子を見たいと思います…気まぐれでは困る(´・ω・)

     大変お手数おかけしました、ありがとうございます。

  77. ロフトくん

    >∫MoR dk/dθ さん
    なるほど、本体のDLLを置くとそのような挙動になるのですね。。
    はい、ソリューションはお使い頂いて構いません。

  78. 初めまして。この記事を見てプラグインを作りたいなと思い作り始めてみたんですが
    良く分からなからなくなったので質問させてください。
    コメント受信時イベントハンドラの動作で、同じ時間に大量のコメントが送られてきた際。

    else
    {
    for (int i = 0; i<count; i++)
    {
    NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[i];

    string comment = commentData.Comment;

    if (comment.Contains("検索文字1"))
    {
    string w1 = commentData.Comment;
    _form.put(w1);
    }
    else if (comment.Contains("検索文字2"))
    {
    string w1 = commentData.Comment;
    _form.put(w1);
    }
    else { }
    }
    }
    という風に書いて、自分の枠で連投してみた結果、上手くいくときもあるのですが、いくつか重複して処理が進むことがありました。
    コメント番号を表示したところ
    1:あ
    2:あ
    3:あ
    4:あ
    5:あ
    6:あ
    7:あ
    4:あ
    5:あ
    6:あ
    7:あ
    8:あ
    9:あ
    10:あ
    どのようにしたら改善できますか?

  79. すみません。昨日の問題はコメント受信毎に過去ログを引っ張ってくる、という方法で一応解決しました。
    もっと効率のいい方法があったら教えてください。

    • ロフトくん

      >ろんさん
      こんにちは。

      コメント受信時イベントハンドラでは、
      最新のコメント1つのみを処理するのがお勧めです。

      過去のコメントに対する処理は、コメント受信時イベントハンドラではなく、
      例として、プラグイン処理開始や、プラグイン画面のボタンが押された時や、
      専用の処理スレッドを作る、等で処理するのがお勧めです。

      • 最新のコメント1つとは、記事に書かれているように
        NicoLibrary.NicoLiveData.LiveCommentData commentData = e.CommentDataList[count-1];ですよね?
        これで、連投したものをテキストに表示させようとすると


        ↑のように10コメ分連投したものが数個しか反映されなくどうしたらいいか悩んでいます。

        今は、数十秒毎に過去コメを読み込み更新みたいなな感じにして、映らなかったものも表示するようにしてます。

        • 補足です
          連投ツールを使ってるのと、1文字のコメントを送信してるので、コメントの送信速度が速く処理が追いついてないんだと思いますが、最新のコメントを取得して全て表示できる方法はありますか?

  80. ロフトくん

    >ろんさん
    コメントが多い放送の場合、
    コメント受信時イベントハンドラは、コメントを1つ受信の度に呼ばれるのではなく、
    コメントが複数e.CommentDataListに追加されて呼ばれることがあるそうです。

    コメント受信時イベントハンドラの中で最新のコメントを1つ処理するのではなく、
    未処理コメントを処理するようにするとよいようです。

    • 一番最初に投稿したプログラムの内容が一部被って表示されてしまったのは、複数e.CommentDataListに追加されたものが前に呼ばれたe.CommentDataListと一部被ってしまうということですかね。

      >>未処理コメントを処理する
      一番最初に投稿したプログラムの内容に、
      ID、コメ番、あたりもテキストに表示するようにし、
      コメント受信時に既に表示してある内容と一致しなければ表示する、といった感じでいいんですかね?
      質問ばかりで申し訳ないです。

      • ロフトくん

        >ろんさん
        一番最初に投稿されたプログラムは最新のコメント一つだけを処理している用に見えます、
        それが被っているということは、1つの最新コメントに対して、
        コメント受信時イベントハンドラは複数回呼ばれてしまうことがあるということになるかと思います。
        対策として、チェック機構を設ける必要があると思われます。

        >コメント受信時に既に表示してある内容と一致しなければ表示する、>といった感じでいいんですかね?
        はい、そのようなチェックが必要になるかと思います。

        • >ロフトくんさん
          毎度、素早い返信ありがとうございました!
          とても参考になりました。

  81. いつもお世話になっております。
    今コメントした人のニックネームが欲しいのですが、
    ロフトくん on 2012年6月23日 at 5:41 PM said:
    をどこに入れればいいのかわかりません。Form.csなのかclass.csなのか、それ以前のロフトくん on 2011年8月25日 at 6:50 PM said: はわかりやすかったのですが。これとid照合をする必要があるんですよね。たぶん。

  82. ロフトくん

    >BURIさん
    こんにちは。

    こちらの記事の以下コメントをご参照下さい。
    http://c-loft.com/blog/?p=1058
    ロフトくん on 2013年3月11日 at 5:34 PM

    少し試してみましたが、ニックネームが取得できないユーザは
    IndexOfUserSettingが-1になるようです。
    -1以外になるユーザの条件は不明・・・

  83. ここのコメントの
    ロフトくん on 2013年3月11日 at 5:34 PM said:
    のコメント参照しましたが、「コメントデータのIndexofUserSettingの値がuserSetting.UserDataListのindexになっているようです。」のindexがわかりません。

    コメントデータに含まれるある値がNCVの内部ユーザーリストの順番になっているということでしょうか?id照合よりは楽そうですが。

    発言を検索してみました。
    ロフトくん on 2011年8月25日 at6:50 PM said:
    「GetUserSettingInPlugin()で取得できる情報の中にニックネームが入っているようです。」
    ロフトくん on 2012年6月23日 at 7:23 AM said:
    「UserSettingInPlugin.UserData型メンバにNicknameがあるようです。」
    ロフトくん on 2012年6月23日 at 5:41 PM said:
    「今コメントした人のID取得はコメント受信時イベントハンドラで実施するとよいと思われます。」
    PG on 2012年6月23日 at 10:49 PM said:
    「CommentDataのメンバにIDがあったのですね。」

    プログラムですが、最初のユーザーリストを取得するプログラムの改造(煮るなり焼くなりを組み込み)で、コメントからのユーザー名はテキストボックスにひとつだけ表示されるようです。何個か表示させたくても今のところできません。

  84. ロフトくん

    >BURIさん
    こんにちは。

    >コメントデータに含まれるある値がNCVの内部ユーザーリストの順番に
    >なっているということでしょうか?id照合よりは楽そうですが。
    その通りです。
    ・受信コメント(NicoLibrary.NicoLiveData.LiveCommentData)を取り出す
    ・各受信コメントからユーザー設定リストのインデックス(IndexOfUserSetting)を取り出す
    ・ユーザ設定(UserSettingInPlugin)を取り出す
    ・受信コメントとユーザー設定リストはIndexOfUserSettingで関連付けられている
    UserSettingInPlugin.UserDataList[IndexOfUserSetting]が受信コメント発言者のユーザ設定ということになる
    ・ユーザ設定の中にニックネームがある
     String nickName = userSetting.UserDataList[index].NickName

    という関連があると、”IndexOfUserSetting”という変数名から予測されます。
    (また、NCV 更新履歴.txtには+α099の項目に以下記述があります。
    【要望】受信コメント情報構造体にユーザー設定リストのインデックスを追加した )

    実際に動かしてみるとIndexOfUserSettingが-1になる人ばかりなので、
    -1にならない条件は調べてみないと分からないっぽいです。
    Plugin_Doc.chmにも詳細は載ってなさそうなので、NCV作者さんに聞いてみるのも手だと思います。

    >コメントからのユーザー名はテキストボックスにひとつだけ表示されるようです。
    textBox1.Text = textBox1.Text + “\n\r” + info;
    のような感じで追記されるようにすべきでしたね。
    (また、テキストボックスを複数行設定(Multiline プロパティを true )し、
    マウスで縦幅を伸ばして複数行が見える状態にして上記を試してみて下さい。)

  85. ありがとうございました。なんとか動きました。

    >>実際に動かしてみるとIndexOfUserSettingが-1になる人ばか>>りなので、-1にならない条件は調べてみないと分からないっぽい>>です。
    私の行っているところは、生IDが多いので、どうも-1は184の乱数をはじいているようです。
    textBox1.Text = textBox1.Text + “\n\r” + info+” + “n\r;で改行されて表示されますがだぶる感じがしますね。

    後は絞込みだなあ。タイマーと。ある一定の時間にユーザー名の一部を数えるカウンタープログラムを組みたいのです。

    それよりプログラムがクラッシュ。「データが失われる可能性を防ぐため、デザイナーの読み込み前に以下のエラーを解決する必要があります。」と出て、解決できなくて困っています。

  86. ロフトくん

    >BURIさん
    こんにちは。
    >「データが失われる可能性を防ぐため、デザイナーの読み込み前に以下のエラーを解決する必要があります。」
    恐らく画面周りのコード(VisualStudioが自動的に準備するファイル含め)に矛盾が生じてしまい、デザイナが表示できてないのですね。
    怪しいところをいじってみて直らない場合はソリューション(プロジェクト)ごと新規作成してしまうのも手です(プラグインのコードなどはそのまま流用)。
    (作業が少し進むごとにソリューションのバックアップを取るのもお勧めです。)

  87. ありがとうございます。フォームの新規作成で何とか乗り切りました。「userのコテハンを取り出したり、煮るなり焼くなり。」がうまくできていません。タイマーで60秒間のユーザー名を取得するのと、その取得したユーザー名をまとめるのと、それを分析するのです。

    タイマーで60秒に一回のイベントを発生させて、それまでユーザー名を取得するのがよさそうです。プログレスバーの使い方も勉強しないとなあ。

    その取得したユーザー名をまとめるのは、追記ではうまくいきませんでした。テキストボックスの行数を数えるのも違うし、ハッシュテーブルを進められたんですが、どうも違う気がして。単なる文字列(,区切りとか)か配列か迷うところです。

    分析ともなると見当がつきません。COUNTIFってC#にはないのですね。要するに男女年齢のタグをユーザー名につけてそれで分析するというアナログな手法なのですが。ある文字列が数えられればそれでいいのです。

    簡単にでいいので、アドバイスお願いします。

  88. ロフトくん

    >BURIさん
    こんにちは。
    List(便利な配列)を使った例をご紹介します。
    以下をそのままお使い頂くというよりは一つの実装例のご紹介だと思って下さい。

    GetUnixTime()は以下をお使い下さい。
    http://www.atmarkit.co.jp/fdotnet/dotnettips/980unixtime/unixtime.html

    
            //コメントリスト
            private List<NicoLibrary.NicoLiveData.LiveCommentData> _list = new List<NicoLibrary.NicoLiveData.LiveCommentData>();
    
            //コメント受信時イベントハンドラ
            void _host_ReceivedComment(object sender, ReceivedCommentEventArgs e)
            {
                //コメントリストに追加
                _list.AddRange(e.CommentDataList);
                
            }
    
            //タイマーハンドラ
            void timerTick()
            {
                //例として、ユーザ名をまとめる用のリスト
                List<String> listName = new List<string>();
    
                //現在時刻
                long timestampNow = GetUnixTime(DateTime.Now);
    
                //全コメント解析
                foreach (NicoLibrary.NicoLiveData.LiveCommentData data in _list)
                {
                    
                    //コメント時刻
                    Long timestampComment = long.Parse( data.Date );
    
                    //古いコメントはスキップ
                    if (timestampComment < timestampNow - 60)
                    {
                        continue;
                    }
    
                    //まとめる
                    listName.Add(date.Name);
                }
    
                //まとめたものに対して処理
                int hogeCount = 0;
                foreach (String name in listName)
                {
                    if (name.Contains("ほげ"))
                    {
                        hogeCount++;//ほげを名前に含む人の数
                    }
                }
            }
    
  89. なるほどぉ。タイマーイベントでいちいち取得して何かに入れて分析するよりは、一気に取得して、時間で処理したほうがよさそうですね。実装例参考にがんばってみます。

  90. ぬるぽ ガップラグインと別スレッドで使い方を教えて頂いたCoretweetによるBotとを組み合わせようとしています。nknkときたときにある文字列をツイッターに投稿するように改造したいのですが、含まれていたらツイートするという部分で詰まっています。ご教示いただけたら幸いです。
    一応このように書いています。トークン等は省略。
    //コメントにnknk”が含まれているか判定し、
    //含まれていたら、ツイートする
    if (comment.Contains(“nknk”))
    {
    //含まれているので”猫が来ました。コミュのアドレスはこちら。”をコメントする
    var tokens = CoreTweet.Tokens.Create(“”
    , “”
    , “”
    , “”);

    var text = “猫が来ました。コミュのアドレスはこちら。”;
    bool result = tokens.Statuses.Update(new { status = text });

  91. ロフトくん

    >BURIさん
    こんにちは。ご提示いただいたコードの方針でよいと思います。
    不具合やエラー等は発生していますか?

  92. エラー 1 型 ‘CoreTweet.StatusResponse’ を型 ‘bool’ に暗黙的に変換できません。 C:\Users\BURI\documents\visual studio 2013\Projects\NCV_Plugin_niboshistreet\Class1.cs 129 32 NCV_Plugin_niboshistreet
    が出てしまって、ツイートのコマンドが実行できないようです。

  93. bool result =を外したら動きました。

  94. とりあえず完成はしコメントを監視してツイートはできるのですがツイートすると、プラグインが落ちてしまいます。何かの処理が足りないのでしょうか?

  95. ロフトくん

    >BURIさん
    こんにちは。
    デバッグ実行にてどの箇所で落ちているか調べてみることをお勧め致します。
    実装したソースの随所をtry-catchで囲んで、
    例外が発生していたら例外情報をDebug.WriteLine()して、
    VisualStudioのデバッグウィンドウに表示して確認するのも有効です。

    プラグインのデバッグ方法のご参考)
    http://c-loft.com/blog/?p=1297
    http://c-loft.com/blog/?p=1793

  96. System.Net.WebException はハンドルされませんでした。
    Message: 型 ‘System.Net.WebException’ のハンドルされていない例外が CoreTweet.dll で発生しました
    追加情報:リモート サーバーがエラーを返しました: (403) 使用不可能
    やってみました。
    ここで落ちているようです。

  97. メッセージを送信しようとすると「メッセージ送信に失敗しました(リモート サーバーがエラーを返しました: (403) 使用不可能)」と帰ってきます。最近同じ文言を送信していたりするとしばらくはエラーとなることがあります。メッセージを変えてお試しください。
    http://opentig.org/
    こんなのを見つけました。同じ文章や書き込みのしすぎはエラーをはくようですね。

  98. ツイッター文字列に時刻を加えることで回避しましたが、まだ例外が出ます。今度は
    ファイルまたはアセンブリ ‘Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed’、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。
    です。pluginフォルダに作ったプラグインのほかにcoretweet.dllとNewtonsoft.Json.dllを入れなくてはならないらしく、プラグイン読み込みの際にcore2tweetはバージョンが違いますというようなNCVのエラーが出ます。

  99. とりあえずビルドでできたファイルをすべてプラグインフォルダに入れたら動作しました。

    とりあえずかんせいですが、放送番号を取得するにはどうしたらいいでしょうか?コメビュで表示している放送番号は取得できそうですが、見当がつきません。

  100. ロフトくん

    >BURIさん
    こんにちは。放送番号はGetPlayerStatus()で取得可能です。

                NicoLibrary.NicoLiveAPI.NicoLivePlayerStatus status = _host.GetPlayerStatus();
                String liveNum = status.LiveNum;
    
  101. お世話になります。
    https://hsy.me/2015/07/05/itunes-com-sdk-with-csharp/
    このc#でiTunesを叩いて、情報を表示させるプログラムをコメビュプラグインとして、
    起動することには成功しています。
    テキストボックスを追加して、送信内容を表示することにも成功しています。ただ、ボタンを追加して、主コメに反映させるのが、http://c-loft.com/blog/?p=1058#comment-46
    を参考に実装してみましたが、うまくいきません。アドバイスお願いします。

  102. ロフトくん

    >BURIさん
    こんにちは。

    コードをtry{}catch{Exception e}で囲んでみてcatchに入っている場合は例外eの情報がヒントになりそうです。

    また、よろしければどこかのアップローダーに一式を置いて頂けたら、
    こちらの環境でも試せるかもしれません。

  103. アップローダーに一式置きました。よろしくお願いします。
    VS2017Communityです。
    https://ux.getuploader.com/blister/download/1

  104. ロフトくん

    > BURIさん
    iTunesの情報が見れて良いですね・・!

    Class1.cs の Run() や、
    放送接続時イベントハンドラ( _host_BroadcastConnected()を要追加 )の中に
    _form.SetHost(_host); を追加するとうまくいきそうです。

    ご不明な点は遠慮なく聞いてくださいノ

  105. 今度は例外が出てしまうようです。System.NullReferenceException オブジェクト参照がオブジェクトインスタンスに設定されていません。です。

  106. ロフトくん

    >BURIさん
    こんな感じでいかがでしょう?

    /// <summary>
    /// プラグインを起動する
    /// </summary>
    public void Run()
    {
        if (_form == null)
        {
            //フォームの生成
            _form = new Form1();
            _form.Show((System.Windows.Forms.IWin32Window)_host.MainForm);
    
            //閉じられた際のイベントハンドラ追加
            _form.FormClosed += new System.Windows.Forms.FormClosedEventHandler(_form_FormClosed);
    
            //コメント受信時のイベントハンドラ追加(今回はまだ実装しません)
            //_host.ReceivedComment += new ReceivedCommentEventHandler(_form.ReceivedComment);
    
            // 放送接続時イベントハンドラ
            _host.BroadcastConnected += _host_BroadcastConnected;
    
            //フォームにhostを渡す
            if (_host.IsConnected == true)
            {
                _form.SetHost(_host);
            }
    
        }
    }
    
    /// <summary>
    /// 放送接続時イベントハンドラ
    /// </summary>
    private void _host_BroadcastConnected(object sender, System.EventArgs e)
    {
        //フォームにhostを渡す
        if (_form != null)
        {
            _form.SetHost(_host);
        }
    }
    

    ご不明な点は遠慮なく聞いてくださいノ

  107. 手直しで無事動きました。ありがとうございました。

  108. https://hsy.me/2015/07/05/itunes-com-sdk-with-csharp/
    このプログラムなんですが、下のボタンが効きません。ボタン名はあっていると思うし、
    イベントでiTunesLIbの機能を呼び出しているだけだと思うのですが、私にはお手上げです。http://relog.xii.jp/mt5r/2011/01/itunes-com-for-windows-sdk.html
    iTunes COM SDKがある場所の情報です。解析していただければ、幸いです。

    • ロフトくん

      >BURIさん
      以下でいけそうです。

      1 ソリューションエクスプローラでForm1.csを
      ダブルクリックして画面のデザイナを表示させます。

      2 デザイナ上で3つのボタン( Prev, Play/Pause, Next ) を
      ダブルクリックすると以下のように
      Form1.csにボタンクリックハンドラのメソッドが
      新規で3つ生成されます。

      private void PrevButton_Click_1(object sender, EventArgs e)
      {
      }
      
      private void PlayPauseButton_Click_1(object sender, EventArgs e)
      {
      }
      
      private void NextButton_Click_1(object sender, EventArgs e)
      {
      }
      

      3 新規で生成されたメソッド内にiTunesの処理を実装します。

      private void PrevButton_Click_1(object sender, EventArgs e)
      {
          iTunes.PreviousTrack();
      }
      
      private void PlayPauseButton_Click_1(object sender, EventArgs e)
      {
          iTunes.PlayPause();
      }
      
      private void NextButton_Click_1(object sender, EventArgs e)
      {
          iTunes.NextTrack();
      }
      

      4 サンプルコードにもともとあったイベントハンドラは削除いただいて構いません
      ( これを再利用する設定方法もあるのですが割愛します )
      PrevButton_Click
      PlayPauseButton_Click
      NextButton_Click

      ご不明な点は遠慮なく聞いてくださいノ

  109. デザイナからイベントハンドラを作ればよいのですね。できました。
    もう一つお聞きしたいのですが、アートワークをCドライブ直下のフォルダにJpeg
    ファイルで生成するにはどうすればよいでしょうか?
    bmp.Save(@”C:\z_iTracker\Artwork.jpg”,System.Drawing.Imaging.ImageFormat.Jpeg);
    だけではbmpがどうたらのエラーが出てだめでした。
    テキストの書き出しは
    File.WriteAllText(@”C:\z_i-Tracker\iTunesInformer.txt”, MainComment.Text);
    File.WriteAllText(@”C:\z_i-Tracker\Title.txt”, TrackName);
    File.WriteAllText(@”C:\z_i-Tracker\Artist.txt”, Artist);
    File.WriteAllText(@”C:\z_i-Tracker\TitleName.txt”, “♪タイトル:” +TrackName);
    File.WriteAllText(@”C:\z_i-Tracker\ArtistName.txt”, “♪アーティスト:”+Artist);
    でうまくいきました。

  110. ロフトくん

    >BURIさん
    Bitmap bmp = new Bitmap(ArtworkPath);するとうまくいきます。

    void iTunes_OnPlayerPlayEvent(object iTrack)
    {
        ( 略 : )
    
        //アートワークを取得して保存
        a.SaveArtworkToFile(ArtworkPath);
    
        //アートワークをjpegで保存
        Bitmap bmp = new Bitmap(ArtworkPath);
        string savepath = @"C:\z_iTracker\" + System.IO.Path.GetFileName(ArtworkPath);
        bmp.Save(savepath, System.Drawing.Imaging.ImageFormat.Jpeg);
        bmp.Dispose();
    
        //保存したアートワークを取得(ファイルに落とさないと取れないから)
        Bitmap AlbumArtContent = new Bitmap(ArtworkPath);
    
        ( 略 : )
    }
    

    ご不明な点は遠慮なく聞いてくださいノ

  111. ローカルまたはパラメーター ‘bmp’ は、その名前が外側のローカルのスコープでローカルやパラメーターの定義に使用されているため、このスコープでは宣言できません。
    というエラーが9行目のbmpのところで出てしまいましたが、どうしたらよいのでしょうか?

  112. 前のコードが残っているためでした。申し訳ありません。

  113. お世話になっております。アートワークの保存どころかプラグインで表示されなくなっています。
    アートワークがあった場合、Enbed Artworkとボタンが表示されて埋め込みがなされるようになっているようですが、これもボタンを押した場合の処理を書かなくてはならないでょうか?よろしくお願いします。

    • ロフトくん

      >BURIさん
      よろしければどこかのアップローダーに一式を置いて頂けたら、
      こちらの環境でも試せるかもしれません。

  114. おひさしぶりです。アートワークが表示されないのは、NCVのプラグインディレクトリを作業ディレクトリとしていったんアートワークを保存して、取得して表示している過程で私の環境ではうまくいっていないようなんですが、プログラムディレクトリにNCV置いたときにユーザーアカウント制御とかで邪魔してるのかなと思い、ほかのディレクトリにNCV置いてみてもダメでした。私のアップローダーにソース一式置きますのでよろしくお願いします。
    https://ux.getuploader.com/blister/download/18

  115. ロフトくん

    >BURIさん

    こんにちは。
    以下のようにArtworkPathをSystem.Environment.CurrentDirectory配下にすると
    アプリケーション用のディレクトリに出力できますのでうまくいきます。
    Cドライブ直下にディレクトリやファイルを置くのは避けた方が良いです。

    ArtworkPath = System.Environment.CurrentDirectory + "\\artwork." + ext;
    

    今回書き換えたiTunes_OnPlayerPlayEventメソッドをこちらに置きました。
    https://gist.github.com/loftkun/ebcc1333f9f9534e945c2868403a9d94

  116. 対応ありがとうございました。しかし、うまくいきません。System.Environment.CurrentDirectoryってどこに出力されるんでしょう。NCV本体のあるディレクトリにもプラグインディレトリにもC:\Users\user\AppData\Roaming\posite-c\NiconamaCommentViewer配下にもありません。まずそこでうまくいっていないとすればローカルにiTunesからアートワークを取得してローカルに保存、ローカルから再取得してリサイズしてフォームに表示の過程がうまくいっていないことになりますね。

  117. ロフトくん

    >BURIさん

    System.Environment.CurrentDirectory は私の環境の場合以下です。

    C:\Users\loft\AppData\Roaming\posite-c\NiconamaCommentViewer\

    上記にはNCVの設定ファイルなどが置いてあり、プラグインからも自由にファイルの読み書きができます。

    もしファイルが出力されていなければ以下のように小さなコンソールアプリケーションにしてデバッグしてみると作業効率が良いです。

    https://gist.github.com/loftkun/3804308537f3898a94540bca93ea0ecb

    Console.WriteLine(“path=” + path);のpath(この場合は.exeがある場所になります。)や
    Console.WriteLine(“Exception e=” + e);の例外が起きていないか確認してみると良いと思います。

  118. 小さなコンソールアプリケーションではアートワーク出力されます。ですが、本体プログラムでは出力されません。どうしたらいいのだろう。

  119. ロフトくん

    > BURIさん
    こんにちは。
    とりあえず、小さなコンソールアプリケーションで出力されたのは良かったですね。

    次は小さなプラグインを作ってみるといかがでしょう?
    以下はMessageBox.Show()で保存工程を表示する例です。

    極力、iTunes_OnPlayerPlayEvent()以外のメソッドを持たせない、画像を保存するだけのプラグインです。
    http://c-loft.com/soft/research/NCV_ITunesInformer_20150525_01.zip

  120. うーん小さなプラグインでメッセージボックスが一切出ませんね。

    • ロフトくん

      >BURIさん

      メッセージボックスが出るのはiTUnesで再生開始してiTunes_OnPlayerPlayEvent()が呼ばれた時です。
      メッセージボックスがプラグイン等のウィンドウの後ろ(奥)に表示されることもあるので気をつけてみて下さい。
      出ない場合はメッセージボックスの処理を別の箇所にも増やしてみると良いです。

  121. 隠れてました。ただ、実行しても、そのアドレスにアートワークが保存されないですね。例外は出ていません。

    • ロフトくん

      >BURIさん

      ちなみに「保存先pathは」のダイアログに表示されたのはどんな文字列でしたでしょうか?
      (ダイアログをアクティブにして、Ctrl + c で文字列をコピーできます)

  122. —————————

    —————————
    保存先pathは C:\Users\user\AppData\Roaming\posite-c\NiconamaCommentViewer\artwork.png です。
    —————————
    OK
    —————————
    ですね。私のユーザーディレクトリのAppDataのRoming以下ですね。もちろんこのディレクトリは隠しディレクトリですが、表示されるようにしてあります。

  123. ロフトくん

    >BURIさん
    ありがとうございます。

    1 保存先path( C:\Users\user\AppData\Roaming\posite-c\NiconamaCommentViewer )
    にはNCVの設定ファイル(AppSetting.xmlなど)がありますよね?

    (ある場合)
    NCVを起動して何か設定を変更してみるとAppSetting.xmlが更新されることが確認できるかと思います。
    この確認ができた場合、NCV本体はファイルを保存できているけど、プラグインはファイル保存ができない、という状態ですね。

    2 次に、小さなコンソールアプリケーションの方も保存先pathをC:\Users\user\AppData\Roaming\posite-c\NiconamaCommentViewer\artwork.png
    にしてみると保存できるでしょうか?

    //アートワーク保存
    String path = System.Environment.CurrentDirectory + "\\artwork." + ext;
    path = @"C:\Users\users\AppData\Roaming\posite-c\NiconamaCommentViewer\artwork.png";
    Console.WriteLine("path=" + path);
    a.SaveArtworkToFile(path);
    

    私の環境では保存できました。

    保存できたら、プラグインの場合は保存できない理由がある。
    保存できなければ、このパスの場合は保存できない理由がある。
    になりそうですね。

  124. 1.変更が反映されません。
    2.保存できません。
    何かが邪魔しているんですかね。

  125. path=C:\Users\users\AppData\Roaming\posite-c\NiconamaCommentViewer\artwork.png
    Exception e=System.Runtime.InteropServices.COMException (0x80004005): エラー HRESULT E_FAIL が COM コンポーネントの呼び 出しから返されました。
    場所 iTunesLib.IITArtwork.SaveArtworkToFile(String filePath)
    場所 iTunesLibTest.Program.ITunes_OnPlayerPlayEvent(Object iTrack) 場所 C:\Users\user\source\repos\iTunesLibTest\iTunesLibTest\Program.cs:行 67
    このようなエラーが出て保存できません。

  126. ロフトくん

    >BURIさん
    ありがとうございます。

    1 保存先pathの”users”の部分について
    C:\Users\users\AppData\Roaming\posite-c\NiconamaCommentViewer\artwork.png

    私の場合はPCのユーザは”loft”にしているので、”users”の部分は以下のように”loft”です。
    C:\Users\loft\AppData\Roaming\posite-c\NiconamaCommentViewer\
    “users”というのはあくまで例として書いているので、
    BURIさんのPCのユーザ名に置き換えて試行頂くと良いです。
    また、ここが別のユーザの名前になっているとファイルの読み書きは(管理者権限がないと)できない点にも注意が必要です。

    2 NCVを起動して、設定→オプション→一般設定の
    「設定ファイル保存先フォルダの場所」を見てみると私の場合は以下のように1と同じpathが設定されていることを確認できます。
    C:\Users\loft\AppData\Roaming\posite-c\NiconamaCommentViewer\
    BURIさんの場合はいかがでしょうか?Users\の次がBURIさんのユーザ名になっているでしょうか?

    3 NCVを起動して、試しに何か設定を変えてみます。
    例として設定→オプション→一般設定→「起動時にNCVの更新チェックを行う」のチェックを変えて、
    NCVを終了するとAppSetting.xmlというファイルのIsUpdateCheckedという項目のtrue/falseが書き換わります。
    ( 設定ファイルが書き換わるのはNCVを終了する時なのでご注意下さい 。)
    再度、NCVを起動すると、確かに前回変更した設定(「起動時にNCVの更新チェックを行う」のチェック状態)が読み込まれることを確認できればNCV本体については設定の読み書きはOKです。

  127. NCV本体の読み書きはOKでした。設定ファイルが書き換わるのはNCVを終了する時なのでご注意下さい 。が悪影響していたようです。

  128. 1と2は確認しました。

  129. ロフトくん

    >BURIさん

    > path=C:\Users\users\AppData\Roaming\posite-c\NiconamaCommentViewer\artwork.png
    > Exception e=System.Runtime.InteropServices.COMException (0x80004005): エラー HRESULT E_FAIL > が COM コンポーネントの呼び 出しから返されました。
    > 場所 iTunesLib.IITArtwork.SaveArtworkToFile(String filePath)
    > 場所 iTunesLibTest.Program.ITunes_OnPlayerPlayEvent(Object iTrack) 場所 C:\Users\user\source\repos\iTunesLibTest\iTunesLibTest\Program.cs:行 67
    > このようなエラーが出て保存できません

    pathはUsers\usersでよいですか?(それともUsers\userですか?)

  130. Users\userでした。修正したところ、エラーは出なくなりましたが、保存はされませんね。

  131. コメント足してみましたが、以下の通りで保存されません。
    再生が開始されました。保存を開始します。
    path=C:\Users\user\AppData\Roaming\posite-c\NiconamaCommentViewer\artwork.png
    SaveArtworkToFile()を実行しました。例外は発生していません。
    なぜ保存されないんだろう?

  132. path = @”C:\z_i-tracker\artwork.png”にしてみたところ、保存できました。

  133. ロフトくん

    > BURIさん

    C:\z_i-tracker\artwork.png に保存できたのは良かったですね。
    このディレクトリで良ければそれで良いかと思います。

  134. 小さなプラグインやテストプラグインではC:\z_i-tracker\artwork.png に保存できたのですが、本プラグインに適用してみたところ、どうしてもうまくいきません。

    • ロフトくん

      > BURIさん

      テストプラグインに少しずつ本プラグインの機能を足しながら保存できるか確認していくと良いかと思います。

  135. ありがとうございました。おかげさまで、プラグインでのiTunes情報の表示、主コメへの反映、ファイルへの書き出しすべてうまくいきました。
    次はリクエスト機能をつけようと思い少しずつプログラミングしているのですが、ぬるぽがっのところを書き換えてみましたが、うまくいきません。
    とりあえず、https://prime503.hatenadiary.org/entry/20090916/1253075261を参考に
    曲名検索だけでもできるようにしたいのです。
    //①
    //コメントに”曲)”が含まれているか判定し、
    //含まれていたら、曲名をコメントする
    if (comment.Contains(“曲)”))
    {
    string songname = iTunes.LibraryPlaylist.Search(comment, 5);//return IITTrackCollection
    {
    //含まれているので曲名をコメントする
    bool result = _host.SendComment(songname+”がありました。”);
    こんな感じで書いてみましたが、iTunes.LibraryPlaylist.Search(comment, 5)の
    5の第二引数でエラーが出てしまいます。
    引数 2: は ‘int’ から ‘iTunesLib.ITPlaylistSearchField’ へ変換することはできません。
    という感じです。どうすればよいのか教えていただければ幸いです。

  136. 追記:
    using iTunesLib;とprivate iTunesApp iTunes;を追加しています。

  137. 曲検索コメントでうまくいくようになりました。iTunesのプレイリストへの追加もできるようになりました。ご報告まで。

  138. 質問です。
    上記の記事と同様にReceivedCommentイベントを用いてformでコメントを処理しています。
    その際にコメントをもとにDataTableやDataGridViewにデータを追加しようとしていたのですが何回か(おそらくスクロールバーが表示されるとき?)追加をすると応答なしとなって落ちてしまいます。処理の問題かと思いフォームにボタンを追加して同様のことをできるようにした場合には問題なく追加できました。
    またイベント自体でコメントを受け取る事自体はできているようでdatagridviewやdatatableに追加しなければ何事もなく処理できていました。
    上記の質問の中にReceivedCommentイベントの不具合のものがあり、そこで貼ってあるリンクのサンプルでDataGridViewに表示をさせてみましたが同様の状態になりました。
    ReceivedCommentイベントでコメントを受け取り、DataGridViewに追加できる方法があれば教えていただきたいです。

  139. お久しぶりです。一年前に作ったプラグインを最新版のNCVで動かしてみたところ、動きませんでした。フレームワークが違うからでしょうか?ここでは3.5に設定するようになっていますが、いくつに設定するのが適当なのでしょうか?

ぽて へ返信する キャンセル

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