ニコ動マイリスト系APIまとめ

ニコニコのマイリスト系のツールを趣味プロで作る時、大体「ニコニコ動画のAPIまとめ」にお世話になっているのですが、情報が古いのか、記載ミスなのか分かりませんが解説の通りにやってもうまく行かない部分があるのでメモ。
なかなかニコ動のAPI(特にマイリスト、静画)を解説してるサイトも見当たらないですしね。
すでにきちんと記載されているものは省きますので、「ニコニコ動画APIまとめ」と合わせながら御覧ください。

  • item_typeは動画、静画の種類を表す(他にもあるかも)
    • 0:動画
    • 5:静画
  • とりあえずマイリスト以外のマイリストから他のマイリストへの動画、静画移動
  • 他のマイリストからとりあえずマイリストへの動画、静画移動、コピー
    • 需要がないからなのかAPIは存在しない(ニコ動本体のマイリストページでもとりあえずマイリストへの移動は実装されていない)
    • どうしてもそういうことをしたい場合は、ITEM_IDを元に「とりあえずマイリスト」へ新規にアイテム(動画・静画)を追加、移動元のマイリストからそのアイテムを削除で一応実装できる
      ※ただし、とりあえずマイリストへ追加する場合、マイリストコメントを入力することが出来ないため、マイリストコメントは破棄される


なお、APIのレスポンスでerrorのJSONが返ってきた場合の「\u671f\u9650\u5207\u308c\u306e\u30c8\u30fc\u30af\u30f3\u3067\u3059」などはユニコードエスケープシーケンスですので、変換してあげると日本語として読めます。ちなみにこの場合は「期限切れのトークンです」というメッセージ。このサイトなどで変換できます。


新しいAPI見つけたら随時補足したいと思います。

ニコニコ動画の検索画面に「もしかして:」を表示するユーザスクリプト

グーグル先生は素晴らしく、検索窓のサジェスト機能もさることながら、検索ワードのスペルミスなどに対し、「もしかして:○○」と正しいであろう検索ワードを表示してくれます。

頭の悪い僕には素晴らしい機能で、「tomorrow」を「tomorow」や「tommorow」などと入力しては毎回訂正されます。


ニコ動の検索でも同じで、「tomorrow never knows」をきちんと入力出来なかったりで、正しい検索結果を得られないことも多々あったりです。

そんな時は、いちいちグーグル先生で検索をかけて、正しいスペルや漢字を調べて入力しなおしていましたが、面倒くさかったのでニコ動の検索結果画面に「もしかして:」を表示できるようにしてみました。

  • インストール:ここをクリック
  • 導入方法は以前の日記を読むかぐぐってください
  • 使用イメージ


ちなみに、タグ検索画面でも、日本語でもきちんとサジェストしてくれます。
ただし面倒なので「静画」、「マイリスト」、「生放送」ではサジェストするようにしてないです。


適当に作ったので、不具合あったら教えてください。

sqlite3-rubyのインストール

(同じ日にエントリを上げてしまってコメント欄が被っていたので分離しました)
unix及びrubyでwebアプリ開発のお勉強中に躓いたのでメモ。

sqlite3-rubyをインストールするにはsqlite-develのインストールが必要だが、その方法を見るとどのサイトも

yum install sqlite-devel

と書いてあり、sudo権限がない場合や、ローカルにインストールしたい場合などにこれではインストール出来ず、必然的にsqlite3-rubyもインストールできない。

これを解決するため、まずはsqliteを手動でローカルにインストールする。

$ mkdir sqlite
$ cd sqlite
$ wget http://www.sqlite.org/sqlite-amalgamation-3.6.23.1.tar.gz
$ tar vxzf sqlite-amalgamation-3.6.23.1.tar.gz
$ cd sqlite-3.6.23.1
$ ./configure --prefix=$HOME

後に

$ make

して

$ make install

でインストール。

ようやく本題のsqlite3-rubyのインストールに入れるが、普通にインストールすると

$ gem install sqlite3-ruby
Building native extensions.  This could take a while...
ERROR:  Error installing sqlite3-ruby:
        ERROR: Failed to build gem native extension.

/home/atago/.rvm/rubies/ruby-head/bin/ruby extconf.rb
checking for sqlite3.h... no
sqlite3.h is missing. Try 'port install sqlite3 +universal' or 'yum install sqlite3-devel'
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/home/atago/.rvm/rubies/ruby-head/bin/ruby
        --with-sqlite3-dir
        --without-sqlite3-dir
        --with-sqlite3-include
        --without-sqlite3-include=${sqlite3-dir}/include
        --with-sqlite3-lib
        --without-sqlite3-lib=${sqlite3-dir}/lib


Gem files will remain installed in /home/atago/.rvm/gems/ruby-head/gems/sqlite3-ruby-1.3.0 for inspection.
Results logged to /home/atago/.rvm/gems/ruby-head/gems/sqlite3-ruby-1.3.0/ext/sqlite3/gem_make.out

とエラーを吐く。
sqlite-develをyumコマンドでなく、手作業でローカルにインストールしたため、パスを明示的にしてやらないといけないので、エラーに書かれているよう、オプションを指定して実行してあげる。

$ gem install sqlite3-ruby -- --with-sqlite3-dir=$HOME

これでようやくsqlite3-rubyをインストールできた。

再生数の減衰率で見るシリーズ物の人気

2009年の11月に書いたエントリについて色々とコメントを頂きいていたので、また調べてみました。
※本エントリの「人気」とは再生数の減衰から数値的に見たものを指しており、それぞれの作品の面白さを表したものではありません。その作品が面白いかどうかは実際にご覧になって判断してください。


◎対象シリーズ
(前回のエントリで用いたシリーズを対象としました。ただし、いくつか動画毎マイリストが削除されたのか、見つからないものがあったのでそれらのシリーズは除外しています。)
()内の数値は第1話目に相当する動画の再生数です。
データは2010年7月7日時点でのものを用いました。

※くされ戦記は、「【革新PK】くされ戦記 OP【開幕】」は本編としては該当しないのではというご指摘を頂いたため、今回は純粋に1話目(「【革新PK】くされ戦記 1匹目【握り飯】」)からの集計になっています。


まず、前回と同じく話数と再生数を集計して結果をグラフ化し、さらに累乗近似曲線から減衰率を求めた。
◎集計方法〜話数と再生数〜
マイリスト内の各動画の再生数を取得
公平に集計するため、グラフにした時に見やすくするため、以下のルールにより集計

  • 原則として本編のみを対象とする(マイリストに含まれていて、かつ、第○話と続いているものが対象。マイリストに含まれていても「外伝」となっているものは除外)
  • 各シリーズ1話目の再生数で正規化したものを図示(このため、グラフの縦軸は再生数でなく第1話から見た再生数の割合になる)


◎結果〜話数と再生数〜
グラフ1.アイマス架空戦記シリーズの再生数変移の累乗近似曲線(横軸は話数、縦軸は正規化した再生数)

グラフ2.ゲーム実況プレイシリーズの再生数変移の累乗近似曲線(横軸は話数、縦軸は正規化した再生数)

表.各シリーズの減衰率(ただし減衰率は累乗近似曲線の累乗値)

アイマス架空戦記シリーズ 減衰率
美希の天下創世 -0.286
天海無用! 三国志 -0.237
im@s白馬将軍 -0.388
アイドル探しの旅in戦国 -0.507
くされ戦記 -0.138
閣下立志伝 -0.219
実況プレイ動画シリーズ 減衰率
【訛り実況プレイ】 サイレントヒル -0.336
【シェバロリ視点】バイオハザード5 おゆったり実況プレイ -0.349
【訛り実況プレイ】 零 -ZERO- -0.431
ゆっくりレオンのバイオハザード4 -0.098
難解マゾゲー アウターワールドを実況プレイ -0.421
色々と残念な サイベリアを実況プレイ -0.308
【訛り実況】 FINAL FANTASY X -0.159


◎考察〜話数と再生数〜

  • 再生数の減衰率を人気度の指標とすることはある程度有用であると考えられる
  • アイマス架空戦記と実況プレイ動画の減衰率を一概に比較することは出来ず、各シリーズによって減衰率の基準を考える必要があると考えられる
  • 話数が少ないものは減衰率が高くなる傾向にある
  • くされ戦記とゆっくりレオンの減衰率は良い意味で異常

次に、投稿間隔と再生数の増減の関連性を調べた。
◎集計方法〜投稿間隔による再生数変化〜
上記で集計したデータを用い、各シリーズのある話とその1つ前の話の投稿間隔を求め、1つ前の話との再生数の差にどのような変化があるかを、アイマス架空戦記シリーズと実況プレイ動画シリーズについてそれぞれ調べた。


◎結果〜投稿間隔による再生数変化〜
グラフ3.アイマス架空戦記シリーズの投稿間隔による再生数変化(横軸は投稿間隔で単位は日数、縦軸は正規化した再生数の増減を示す)

グラフ4.実況プレイ動画シリーズの投稿間隔による再生数変化(横軸は投稿間隔で単位は日数、縦軸は正規化した再生数の増減を示す)


◎考察〜投稿間隔による再生数変化〜

  • 傾向としては投稿間隔が開くと前の話数と比べて再生数は増加する傾向にあることが分かった
  • しかし、あくまで傾向であり、再生数を稼ぐためだけに投稿間隔を開けることは安直であると考えられる
  • 集計方法に問題がある可能性も高い


◎まとめ&雑記

  • 統計の知識を持たずに分析を行うことの限界を感じた
  • 現状では、減衰率を求めるための累乗近似曲線の精度を表すR-2乗値は高くても0.8であり、類似曲線としての精度はそこまで高くなく、あくまで参考値としてしか考えられない
  • 集計方法の妥当性も、もう少し時間をかけてきちんと調べたい
  • 相変わらずデータ数が少ないのであまり当てにならない
  • 誰かもっと大量のデータを扱って調査してみてください><
  • 今回のデータのエクセルファイルをうpしておきますので、ご自由にご活用ください。
  • また、マイリスト内の動画情報を取得するツール(マイリストのURLを入力してボタンをクリックすると、タイトル、再生数、マイリスト数、コメント数、再生時間、投稿日時をタブ区切りでテキストエリアに出力します)も公開しておきますので、マイリストの調査したい!って方がいたら使っていただくのも良いかもしれません。ただし、自分用に作ったツールですので使い勝手はよくありませんし、このソフトでは何の分析もできませんので取得したデータをエクセルなどにコピペしてお使いください^^;
  • ダウンロード


何かご意見等あればお待ちしております。

ニコニコ動画の検索ページの共起タグクラウド表示スクリプトを更新しました

少し前に作った動画検索結果ページに共起タグクラウドを表示するユーザスクリプトがニコ動の仕様変更により動かなかったのを修正しました。

php側での変更は一切なく、user.jsを変更しただけです。

変更前

var as = document.querySelectorAll("a.watch");

変更後

var as = document.querySelectorAll("a.vinfo_title");
  • 導入
    • こちらから。
    • 導入方法は過去の日記を参考にして下さい。
  • 使い方
    • &検索で用いたいタグのチェックボックスにチェックを付けて、「複数タグで検索」ボタンをクリック→ウマー
  • 注意事項
    • 前回のユーザスクリプトを導入している方は、競合してしまい予期せぬ動作を起こすため、前回のスクリプトをアンインストールしてから導入してください。

wicketで詰まった箇所:「ListView」と「ExternalLink」

wicketで非常に躓いた部分があったのでメモ。

wicketでは、tableのtr要素などの繰り返し要素を生成するために「Listview」という便利なコンポーネントが用意されています。

便利なのですが、個人的にはこれを導入するのが非常にやっかいでした。

繰り返す中でgetModelObjectを用いてリストのオブジェクトを生成するのですが、それをどう取ってやるのかがいまいちわからなくて詰まりました。

最初、

add(new ListView<TweetTable>("tweetlistview", tweets){
	@Override
	protected void populateItem(ListItem<TweetTable> item){
		final List<TweetTable> tweet = (List<TweetTable>)item.getModelObject();
		item.add(new Label("id", tweet.get(0).getId().toString()));
		item.add(new Label("tweet", tweet.get(0).getTweet()));
	}
});

としていたのですが(今考えるとなぜこうしていたのかも謎ですが)、これでは動かず、

add(new ListView<TweetTable>("tweetlistview", tweets){
	@Override
	protected void populateItem(ListItem<TweetTable> item){
		final TweetTable tweet = (TweetTable)item.getModelObject();
		item.add(new Label("id", tweet.getId().toString()));
		item.add(new Label("tweet", tweet.getTweet()));
	}
});

としてやることで動きました。
ん〜、ListViewに突っ込んだ型に合わせろってことなんでしょうかね。
理由はよく分かりません;


もう一つ躓いたもの。
wicketでは外部ページに遷移するリンクを生成するのにExternalLinkを用いるのですが、これの使い方を解説してるページが少なく、詰まりました。

<a>タグで挟む文字列が固定の時は

<a href="#" wicket:id="external">外部ページ</a>
add(new ExternalLink("external", "http://hoge.com");

なのですが、<a>タグで挟む文字列もwicketで生成したい場合は

<a href="#" wicket:id="external">外部ページ</a>
String externalPageName = "ほげぺーじ";
add(new ExternalLink("external", "http://hoge.com", externalPageName);

となります。
これが分からず、ずっと

<a href="#" wicket:id="external">
<span wicket:id="str">文字列</span>
</a>
String externalPageName = "ほげぺーじ";
add(new ExternalLink("external", "http://hoge.com");
add(new Label("string", externalPageName);

としてエラーを返されていました。

ドキュメントをきちんと読めばいいのでしょうがね^^;


とりあえず、自分用メモ的な感じで書いておきました。

Apche Wicket自分用まとめ

お仕事で使うらしい、Apache Wicketについて勉強中。
復習がてら、今日学んだことを簡単にまとめておきます。
勉強は「WicketによるWebアプリケーション開発」で行っています。

Apache Wicketとは

  • javaで動くWebアプリケーションフレームの1つであり、サーブレットAPI仕様準拠なんので様々なJavaEEアプリサーバーで動作可能。
  • 設定ファイルいらずで、オブジェクト指向を生かしたWebアプリケーションの開発が可能になる。
  • ステートフルであり、ページの状態はWicketが保持。

詳しいインストール方法は本とか解説サイトを見ましょう。


基本的に、HTML上でコンポーネントを利用したら、それをJava上でも追加する形で使う。

<html>
<body>
  <form wicket:id="submitForm"></form>
</body>
</html>

としたのであれば、

Form<void> submitForm = new Form<void>("submitForm");
add(submitForm);

とする必要がある。

コンポーネントから入力(イベント)を受け取るには「onXXXXXX」をオーバーライドして用いる。
SubmitイベントならばonSubmitをオーバーライド。

Form<void> submitForm = new Form<void>("submitForm"){
  @override
  protected void onSubmit(){
    //処理内容
  }
}

※入力を受け取るため、Wicketを用いると上記のように匿名サブクラスを多様することになる。
このため、実際にアプリケーションを作る際には、javaの「匿名サブクラスから外部のローカル変数にアクセスする際はその変数はfinalである必要がある」という制約に注意する必要がある。

入力を受け取り、その値を使って処理するために入力値を受け取るための方法は、入力コンポーネントのgetModelメソッドを用いてモデルを取り出したあと、それに対してgetObjectメソッドを用いることで値を得る。
逆にオブジェクトに値を渡す場合は、setterを用いる。

TextField<String> field = …
//省略
Imodel<String> model = field.getModel();
String inputValue = model.getObjext();

ただし、modelをいちいち生成してやるのは面倒くさいので、getModelObjectを用いることで一発で取り出せる。

TextField<String> field = …
//省略
String inputValue = field.getModelObject();

Labelなどの非フォームコンポーネントは、型パラメータを指定出来ないためgetDefaultModelメソッドを用いた後にキャストを行う。
しかし、これも面倒くさいので、getDefaultModelObjectメソッドが用意されていたり、「たいてい、取り出したいのは文字だよね」ということで、getDefaultModelObjectAsStringを用いる。


実際にWicketで運用をしようと思うと設定が必要。
「配備モード」と「開発モード」の2種類があり、切り替え方法は4種類。

  1. メソッドのオーバーライド
  2. システムプロパティで設定
  3. ServletContextの初期化パラメータ
  4. filterの初期化初期化パラメータ

1.メソッドのオーバーライド

@override
public String getConfigurationType(){
  return Application.DEVELOPMENT;
}

4.filterの初期化初期化パラメータ

<filter>
  <init-pratform>
    <param-name>wicketconfiguraion</para-name>
    <para-value>deployment</para-valued>
  </init-pratform>
</filter>


HTMLタグとWciketコンポーネントを結びつけるにはwidth:id属性を用いる。(※配備モードで自動的に消される)


ビヘイビア化
タグの属性を変更するには、simpleAttributeModifierを用いる

new Label(id, "ラベル").add(nwe SimpleAttributeModifier["class", "red"]);

属性が固定値でないときは、AtttibuteModifierを用いる。

new Label(id, "ラベル").add(new AttributeModifier("colors",
  new AbstractReadOnlyModel<String>(){
    @override
    public String getObject(){
      return hasErro() ? "red" : "green";
    }
}));

タグに属性を新たに追加する場合はAttributeAppenderを用いる。


今日学んだのはこんな感じ。
あと、それぞれのオブジェクトについて細かくメソッドなんかを見たけど、それは詳しい解説サイトなり本なりを読んでください。