まめ畑

ゆるゆると書いていきます

ニコニコの色々をDL&見てみよう

さて、そろそろニコニコ動画の動画のDLやコメントのGETが出来るサンプルプログラムのコードを掲載したいと思います。
詳細なAPIの意味や使い方などは、この日記のニコニコのイロハ1・2・番外編を参照して下さい。
あと、例外処理やスレッドによる動画DL時の処理などはこまごまと省いているので、使う時などは適時追加してください。
バグ満載ですので使用は気をつけてください。
急増品なので、見てくれは悪いですが一部を切り取って、改変すると色々なリストが見れて面白いかもしれません。
また、GUIで作成してあるので、ハンドラ部分は察してくださいm(_ _)m
つっこみ歓迎です。


2/23追記
DLをするようなテストをすると、Formを生成しているスレッド以外からFormのメンバを更新しようとするので例外が発生する問題を改善しました。

  • いめーじ

  • コード
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Collections;
using System.Xml;
using System.Threading;

namespace NicoTest
{
    public partial class Form1 : Form
    {
        readonly private string loginUrl = "https://secure.nicovideo.jp/secure/login?site=niconico";
        readonly private string baseUrl = "http://www.nicovideo.jp/watch/";
        readonly private string flvUrl = "http://www.nicovideo.jp/api/getflv?v=";
        readonly private string thumbUrl = "http://www.nicovideo.jp/api/getthumbinfo/";
        readonly private Encoding encoder = Encoding.GetEncoding("UTF-8");

        private Hashtable apiParam = new Hashtable();
        private string fileName = "";

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            updateStat();
            CookieContainer cc = new CookieContainer();   //クッキー1
            CookieContainer cc2 = new CookieContainer();  //クッキー2
            if (checkBox1.Checked) setSaveFile();
            this.Refresh();
            loginToNicoVide(cc);    //ニコニコにログイン
            prepAccess(cc,cc2);     //クッキー2をGET
            getXml();               //動画情報をGET
            accessToApi(cc);        //動画のアドレスyやメッセージサーバの情報などをGET
            getMessage(cc);         //コメントをGET
            this.Refresh();
            if (checkBox1.Checked)    //ダウンロード
            {
                Thread downLoad = new Thread(new ParameterizedThreadStart(downloadFlv));
                downLoad.IsBackground = true;
                downLoad.Start(cc2);
                //downLoad.Join();
            }
            updateStat();
        }

        private void loginToNicoVide(CookieContainer cc)
        {
            try
            {
                Hashtable hs = new Hashtable();
                string param = "";
                hs["next_url"] = "";
                hs["mail"] = textBox1.Text;
                hs["password"] = textBox2.Text;

                foreach (string key in hs.Keys)
                {
                    param += string.Format("{0}={1}&", key, hs[key]);
                }

                byte[] data = Encoding.ASCII.GetBytes(param);
                HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create(loginUrl);
                hwr.Method = "POST";
                hwr.ContentType = "application/x-www-form-urlencoded";
                hwr.ContentLength = data.Length;
                hwr.CookieContainer = cc;

                Stream sr = hwr.GetRequestStream();
                sr.Write(data, 0, data.Length);
                sr.Close();

                WebResponse wres = hwr.GetResponse();
                Stream res = wres.GetResponseStream();
                StreamReader str = new StreamReader(res, encoder);
                string response = str.ReadToEnd();
                str.Close();
                res.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void prepAccess(CookieContainer cc, CookieContainer cc2)
        {
            try
            {
                HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create(baseUrl + textBox3.Text);
                hwr.CookieContainer = cc;

                HttpWebResponse res = (HttpWebResponse)hwr.GetResponse();
                CookieCollection cookies = hwr.CookieContainer.GetCookies(hwr.RequestUri);
                cc2.Add(cookies);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void getXml()
        {
            try
            {
                XmlUrlResolver xur = new XmlUrlResolver();
                xur.Credentials = CredentialCache.DefaultCredentials;
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.XmlResolver = xur;
                XmlReader xr = XmlReader.Create(thumbUrl + textBox3.Text,settings);

                while (xr.Read())
                {
                    if (xr.NodeType == XmlNodeType.Element)
                    {
                        if (xr.LocalName.Equals("title"))
                        {
                            textBox5.Text = xr.ReadString();
                        }
                        else if (xr.LocalName.Equals("thumbnail_url"))
                        {
                            using (WebClient myClient = new WebClient())
                            {
                                MemoryStream streamImage = new MemoryStream(myClient.DownloadData(xr.ReadString()));
                                pictureBox1.Image = Image.FromStream(streamImage);
                            }
                        }
                        else if (xr.LocalName.Equals("last_res_body"))
                        {
                            textBox6.Text = xr.ReadString();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        private void accessToApi(CookieContainer cc)
        {
            try
            {
                string videoId = "";
                if (!textBox3.Text.StartsWith("sm")) videoId += "sm" + textBox3.Text;
                else videoId = textBox3.Text;
                HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create(flvUrl + videoId);
                hwr.CookieContainer = cc;

                WebResponse wres = hwr.GetResponse();
                Stream res = wres.GetResponseStream();
                StreamReader str = new StreamReader(res, encoder);
                string response = System.Web.HttpUtility.UrlDecode(str.ReadToEnd());
                str.Close();
                res.Close();
                splitParam(response);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void splitParam(string param)
        {
            string[] urlParam = param.Split('&');

            foreach (string key in urlParam)
            {
                string[] para = key.Split('=');
                if (para[0].Equals("url")) apiParam[para[0]] = para[1] + "=" + para[2];
                else apiParam[para[0]] = para[1];
            }
        }

        private void getMessage(CookieContainer cc)
        {
            try
            {
                string videoId = "";
                if (!textBox3.Text.StartsWith("sm")) videoId += "sm" + textBox3.Text;
                else videoId = textBox3.Text;
                string postData = "<thread res_from=\"-100\" version=\"20061206\" thread=\"" + apiParam["thread_id"] + "\" />";
                byte[] data = Encoding.ASCII.GetBytes(postData);

                HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create((string)apiParam["ms"]);
                hwr.CookieContainer = cc;
                hwr.Method = "POST";
                hwr.ContentType = "text/xml";
                hwr.ContentLength = data.Length;

                Stream sr = hwr.GetRequestStream();
                sr.Write(data, 0, data.Length);
                sr.Close();

                WebResponse wres = hwr.GetResponse();
                Stream res = wres.GetResponseStream();
                StreamReader str = new StreamReader(res, encoder);
                createMessage(str);
                str.Close();
                res.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void createMessage(StreamReader str)
        {
            try
            {
                XmlReader xr = XmlReader.Create(str);

                while (xr.Read())
                {
                    if (xr.NodeType == XmlNodeType.Element)
                    {
                        if (xr.LocalName.Equals("chat"))
                        {
                            textBox4.AppendText(xr.ReadString()+"\n");
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void downloadFlv(object cc)
        {
            try
            {
                setStat("DL中・・・");
                Console.WriteLine(apiParam["url"]);
                HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create((string)apiParam["url"]);
                hwr.CookieContainer = (CookieContainer)cc;
                hwr.Timeout = 30 * 1000;

                WebResponse wres = hwr.GetResponse();
                Stream res = wres.GetResponseStream();
                FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
                int intBuffSize = 1024;
                int intFileSize = 0;
                int intRet = 0;
                while(true)
                {
                    byte[] bytBuff = new byte[intBuffSize];
                    //1024バイトずつ読み込む
                    intRet = res.Read(bytBuff, 0, intBuffSize);
                    if (intRet == 0) break;
                    //ファイルへ書き込み
                    fs.Write(bytBuff, 0, intRet);
                    intFileSize += intRet;
                }
                res.Close();
                fs.Close();
                setStat("DL終了・・・");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private delegate void setStatCallback(string msg);

        private void setStat(string msg){
            if(this.InvokeRequired){
                Invoke(new setStatCallback(setStat),new Object[]{msg});
                return;
            }
            this.Refresh();
            toolStripStatusLabel1.Text = msg;
        }

        private void setSaveFile()
        {
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                fileName = saveFileDialog1.FileName;
            }
        }

        private void updateStat()
        {
            button1.Enabled = !button1.Enabled;
            button2.Enabled = !button2.Enabled;
            textBox1.Enabled = !textBox1.Enabled;
            textBox2.Enabled = !textBox2.Enabled;
            textBox3.Enabled = !textBox3.Enabled;
            checkBox1.Enabled = !checkBox1.Enabled;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            textBox1.Text = "";
            textBox2.Text = "";
            textBox3.Text = "sm";
        }
    }
}

とりあえず、情報をすっぱ抜いてます。
コーディング規約むしってます。
本当にすいません・・・。

なんか、ニコニコ動画(SP1)になるそうで、仕様変更時はまた調べてみたいと思います。