ジャンルを選択し、好みの作業用BGMを流し付けるソフトを作ろうと思った。
作った所で、J◯SRACが怖いので公開することはできないけど。
今回は、ログインとキーワード・タグ双方の検索結果取得までやってみた。
検索APIについては
ニコニコ動画に動画検索APIができたらしいので取り急ぎScalaで
調べてみたら、C#で同じようなことをやっているサイトが一応あった。
C#で検索結果を取得
ただ、このサイトでは文字列処理でJSONの解析を行なっている。
.NET Framework3.5からは、標準でDataContractJsonSerializerというJSON解析用のライブラリが提供されているので用いた。
ニコニコ動画にログイン
ニコニコ動画は検索するためにはログインしてCookieをもつ必要がある。
C#でのログインは、いくらでもサンプルがあるのでぱぱっと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
private readonly string LOGIN_FORM_URL = "https://secure.nicovideo.jp/secure/login?site=niconico"; private readonly string LOGIN_FAIL_MESSAGE = "入力したメールアドレスまたはパスワードが間違っています"; private CookieContainer cookie; public bool Login(string id,string password) { Hashtable vals = new Hashtable(); vals["next_url"] = ""; vals["mail"] = id; vals["password"] = password; var st = Post(LOGIN_FORM_URL, vals, Encoding.ASCII,out cookie); var sr = new StreamReader(st, Encoding.UTF8); //失敗の判断はメッセージの有無で決める return sr.ReadToEnd().Contains(LOGIN_FAIL_MESSAGE); } public static Stream Post(string url,Hashtable param,Encoding enc,out CookieContainer cc) { string query = ""; foreach (string k in param.Keys) query += String.Format("{0}={1}&", k, param[k]); byte[] data = enc.GetBytes(query); cc = new CookieContainer(); HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; req.ContentLength = data.Length; req.CookieContainer = cc; //POST送信 Stream reqStream = req.GetRequestStream(); reqStream.Write(data, 0, data.Length); reqStream.Close(); return req.GetResponse().GetResponseStream(); } |
Stream Post(string url,Hashtable param,Encoding enc,out CookieContainer cc)
はPostの汎用メソッド。
string url:ログインページのURL
Hashtable param:param["パラメータ名"] = パラメータのハッシュテーブル
Encoding enc:POSTの文字コード
out CookieContainer cc:Cookie
ニコニコ動画の検索
キーワード検索の場合
http://ext.nicovideo.jp/api/search/search/検索キーワード?mode=watch&order=d&page=1&sort=n
タグ検索の場合
http://ext.nicovideo.jp/api/search/tag/検索タグ?mode=watch&order=d&page=1&sort=n
でGETすればJSONが返される。
pageで検索結果のページ数の選択。
sortでソート対象
orderで並び順 を指定できる。
例えば
再生数が多い順:sort=v&order=d
再生数が少ない順:sort=v&order=a
マイリストが多い順:sort=m&order=d
マイリストが少ない順:sort=m&order=a
といった具合だ。ココらへんは実際の検索時URIをみれば良いだろう。
今回は単純な検索だけを行う。
取得するJSONは双方次のような形である。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
{"list": [ { "id":"smXXXXX", "thumbnail_url":"http:\/\/tn-skr4.smilevideo.jp\/smile?i=XXXXX", "length":"4:11", "title":"XXXXXXX", "view_counter":71, "num_res":1, "mylist_counter":3, "first_retrieve":"2013-12-01 17:25:19", "description_short":"XXXXXXX" }, { "id":"smYYYYY", (略) "description_short":"YYYYYYY" },・・・・・・ ], "count":4, "page":1, "status":"ok" } |
“list”の中に個々の動画の情報が入れられる。
id:動画ID
thumbnail_url:動画URL
description_short:動画説明文の一部
といった具合だ。
“count”には検索結果の数
“page”は検索結果のページ番号
“status”には成功すると”ok”、失敗すると”fail”が入る。
DataContractJsonSerializerで扱うにはこのデータ構造を.Netオブジェクトで表現しなければならない。
次のように書ける。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
[DataContract] public class VideoInfo { [DataMember] public string id { get; set; } [DataMember] public string thumbnail_url { get; set; } [DataMember] public string length { get; set; } [DataMember] public string title { get; set; } [DataMember] public int view_counter { get; set; } [DataMember] public int num_res { get; set; } [DataMember] public int mylist_counter { get; set; } [DataMember] public string first_retrieve { get; set; } [DataMember] public string description_short { get; set; } } [DataContract] public class SearchInfo { [DataMember(Name = "list")] public List<VideoInfo> list { get; set; } [DataMember(Name = "count")] public int count { get; set; } [DataMember(Name = "page")] public int page { get; set; } [DataMember(Name = "status")] public string status { get; set; } } |
これを用いて実際に検索結果を取得したのが次になる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public SearchInfo SearchKeyword(string keyword,bool SearchByTag) { Stream stm; if (SearchByTag) stm = Get(String.Format("{0}{1}?mode=watch&order=d&page=1&sort=n", SEARCH_TAG_URL, keyword), cookie); else stm = Get(String.Format("{0}{1}?mode=watch&order=d&page=1&sort=n", SEARCH_URL, keyword), cookie); var str = new StreamReader(stm); var json = str.ReadToEnd(); //シリアライザー var serializer = new DataContractJsonSerializer(typeof(SearchInfo)); //バイト配列を読み込む var sr = new MemoryStream(Encoding.Unicode.GetBytes(json)); //JSONデータをobject->クラスにして受け取る return (SearchInfo)serializer.ReadObject(sr); } public static Stream Get(string uri,CookieContainer cc) { var req = (HttpWebRequest)WebRequest.Create(uri); req.CookieContainer = cc; return req.GetResponse().GetResponseStream(); } |
Getする際にCookieがないと検索に失敗してstatusに”fail”が入る。
キーワード検索とタグ検索の違いはURLだけだ。
Getした文字列をByte配列にして、シリアライザーに突っ込んでいる。
実際に適当なフォームを作ってやってみた。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
private void button1_Click(object sender, EventArgs e) { var res = nc.SearchKeyword(textBox_key.Text,false); textBox1.Text = ""; foreach (var a in res.list) { textBox1.Text += a.title + "\r\n"; } } private void button2_Click(object sender, EventArgs e) { var res = nc.SearchKeyword(textBox_tag.Text,true); textBox2.Text = ""; foreach (var a in res.list) { textBox2.Text += a.title + "\r\n"; } } |