ニコニコ動画をブックマークする機会が増えたので、
まとめエントリの方もそれに対応してサムネイルを表示するようにしてみました。

Hatena::Bookmark::konaze (2008-08-13) - NOBODY:PLACE - MUTTER



参考にさせていただいたのは、こちら。

ニコニコ動画のサムネイル情報を取得する - WebProgを極めて居酒屋を開発する
Twitterで、こんな発言があったので
http://www.nicovideo.jp/api/getthumbinfo/sm9

Twitter / Akihiko Koizuka: http://www.nicovideo.jp/api...
ちょっとだけ遊んでみました。


公式にプレスリリースが出ているモノではないにせよ、
戀塚さんが明らかにされているサムネ用のAPIがあるようなのでそれを利用してみます。

APIにアクセスし、結果を取得する。

基本的には以前、YouTube APIでやったことと余り変わりません。

YouTube API を使ってみる。 - NOBODY:PLACE - MUTTER


サムネイルを取得する部分だけ抜き出してみるとこんな感じ。

my $url = "http://www.nicovideo.jp/api/getthumbinfo/$videoId";
my $xml = get ($url) or die("can't get xml");
my $parser = XML::Simple->new();
my $xml_ref = $parser->XMLin("$xml");
return $xml_ref->{'thumb'}->{'thumbnail_url'};

$videoIdってのは、ニコニコ動画のURIのこの部分。

http://www.nicovideo.jp/watch/sm3108399

それを目的のAPIに投げてやるだけで一定の返事があるわけで、
もの凄くシンプル。




はてなブックマーク→MovableTypeに組み込み。

これも以前にならって組み込み。

はてなブックマーク投稿用プログラムのカスタマイズ(その4) - NOBODY:PLACE - MUTTER



で、久しぶりにPerl書いたってことで超初歩的なエラー(文字列はeqで比較しろとか)を
たくさん出しつつリファクタリング→変更を行って、完成。

出来たコードはこんな感じ。


#!/usr/bin/perl

#----------------------------------------------------------------------
# [HatenaBookmark -> MovableType]
#   correspond to YouTube / NicoNicoDouga
#----------------------------------------------------------------------

use strict;
use warnings;

use DateTime;
use XML::Atom::Client;
use HTML::Template;
use Net::MovableType;

use LWP::Simple;
use XML::Simple;


#----------------------------------------------------------------------
# settings
#----------------------------------------------------------------------

# hbm2mt.pl
my $tplFile    = 'テンプレートファイル';

# HatenaBookmark
my $feedUri    = 'http://b.hatena.ne.jp/atom/feed';
my $hatenaUsername = 'はてなID';
my $hatenaPassword = 'はてなパスワード';

# MovableType
my $xmlrpcURL    = 'MovableTypeのXML-RPCの場所';
my $xmlrpcUser   = 'MovableTypeのユーザ';
my $xmlrpcPassword = 'XML-RPCのパスワード';
my $xmlrpcBlogId   = ブログID;
my $xmlrpcCategory = '投稿するカテゴリ';

# YouTube
my $youtubeDevId = 'YouTube Developer ID';


#----------------------------------------------------------------------
# Get HatenaBookmark Feed
#----------------------------------------------------------------------

my $api = XML::Atom::Client->new;
$api->username($hatenaUsername);
$api->password($hatenaPassword);
my $feed = $api->getFeed($feedUri);
die "getFeed Error" unless $feed;

my @entries = $feed->entries;
my @yesterdayEntries;
my $dt_yesterday;

for my $entry (@entries) {
  if ($entry->link->href =~ /suidou\.d-archives\.info|www\.nobodyplace\.com/){
  next;
  }
  my $issued = $entry->issued;
  my $dt = iso2DateTime($issued);
  my $issuedDate = $dt->ymd('');
  $dt_yesterday = DateTime->now->add( days => -1);
  $dt_yesterday->set_time_zone( '+09:00' );
  my $yesterdayDate = $dt_yesterday ->ymd('');
  if ($issuedDate eq $yesterdayDate) {
  push @yesterdayEntries, $entry;
  }
}


#----------------------------------------------------------------------
# Make entry with Template
#----------------------------------------------------------------------

my $tmpl = HTML::Template->new(filename => $tplFile);

my @tmpl_entries;
for my $entry (@yesterdayEntries) {
  my $tag;
  my $flag_notnp = 0;
  my $dc = XML::Atom::Namespace->new(dc => 'http://purl.org/dc/elements/1.1/');
  for my $subject ($entry->getlist($dc, 'subject')) {
  if($subject eq 'notnp'){$flag_notnp = 1;}
    $tag .= '<span class="tag">[<a href="http://b.hatena.ne.jp/konaze/' . $subject . '/" target="_blank">' . $subject . '</a>]</span>';
  }
  if($flag_notnp == 1){next;}

  my $summary = '<span class="comment">' . $entry->summary . '</span>';
  
  my $thumnail;
  my $thumnailUri;

  my @rellink  = grep {$_->rel eq 'related' || $_->rel eq 'alternate'} $entry->link;
  my $target_url  = $rellink[0]->href if(@rellink);
  my $bookmark_url  = $rellink[1]->href if(@rellink);

  if($target_url =~ /^http:\/\/www.youtube.com\/watch\?v=(.+)/){
    $thumnailUri = getThumnail($1, 'y');
  } elsif($target_url =~ /^http:\/\/www.nicovideo.jp\/watch\/(.+)/) {
    $thumnailUri = getThumnail($1, 'n');
  }
  if($thumnailUri){
    $thumnail = "<div class=\"thumnail\"><img src=\"" . $thumnailUri . "\" /></div>";
  }

  my @tmpl_entry = (
  {
    title => $entry->title,
    url => $target_url,
    summary => $summary,
      tag => $tag,
      thumnail => $thumnail,
      bookmark_url => $bookmark_url,
    }
  );

  push @tmpl_entries, @tmpl_entry; 
}

die if ((scalar @tmpl_entries) == 0);

$tmpl->param(entry => \@tmpl_entries);

my $text = $tmpl->output();

$text =~ s/<dd><\/dd>//g;
print $text;


#----------------------------------------------------------------------
# Post to MovableType
#----------------------------------------------------------------------

my $mt = new Net::MovableType($xmlrpcURL);
$mt->username($xmlrpcUser);
$mt->password($xmlrpcPassword);
$mt->blogId($xmlrpcBlogId);

my $title   = $feed->title . "(" . $dt_yesterday ->ymd('-') . ")";
my $description = $text;

my $entry = {
  title   => $title,
  description => $description,
  mt_keywords => "hatena bookmark"
};

my $new_id = $mt->newPost($entry, 0);

# *Debug* if you wanna post this entry as a draft, comment out these 2 lines.
$mt->setPostCategories($new_id, $xmlrpcCategory);
$mt->publishPost($new_id);


#----------------------------------------------------------------------
# Get Thumnail[YouTube / NicoNicoDouga]
#----------------------------------------------------------------------

sub getThumnail {
  my($videoId, $videoType) = @_;
  if($videoType eq 'y'){
    my $url = "http://www.youtube.com/api2_rest?method=youtube.videos.get_details&dev_id=$youtubeDevId&video_id=$videoId";
    my $xml = get ($url) or die("can't get xml");
    my $parser = XML::Simple->new();
    my $xml_ref = $parser->XMLin("$xml");
    return $xml_ref->{'video_details'}->{'thumbnail_url'};
  }elsif($videoType eq 'n'){
    my $url = "http://www.nicovideo.jp/api/getthumbinfo/$videoId";
    my $xml = get ($url) or die("can't get xml");
    my $parser = XML::Simple->new();
    my $xml_ref = $parser->XMLin("$xml");
    return $xml_ref->{'thumb'}->{'thumbnail_url'};
  }
}


#----------------------------------------------------------------------
# TIME: ISO -> DateTime
#----------------------------------------------------------------------

sub iso2DateTime {
  my $ts = shift;
  return unless $ts =~ /^(\d{4})(?:-?(\d{2})(?:-?(\d\d?)(?:T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|([+-]\d{2}:\d{2}))?)?)?)?/;
  my ($y, $mo, $d, $h, $m, $s, $zone) =
  ($1, $2 || 1, $3 || 1, $4 || 0, $5 || 0, $6 || 0, $7);

  my $dt = DateTime->new(
    year   => $y,
    month  => $mo,
    day  => $d,
    hour   => $h,
    minute => $m,
    second => $s,
    nanosecond => 0,
    time_zone => $zone,
    );
  return $dt;
}



ちなみにテンプレートファイルはこんな感じ。

<div class="hatena_bookmark">
<TMPL_LOOP name="entry"><dl class="entry"><dt><TMPL_VAR NAME=thumnail><a href="http://b.hatena.ne.jp/entry/<TMPL_VAR NAME=url>" target="_blank"><img src="http://www.nobodyplace.com/img/icon/hbm.gif" border="0"></a> <a href="<TMPL_VAR name="url">" title="<TMPL_VAR name="title">" target="_blank"><TMPL_VAR name="title"></a></dt><dd><TMPL_VAR name="tag"> <TMPL_VAR name="summary"> <span class="hatenastar"><a href="<TMPL_VAR name="bookmark_url">" class="hatenastar-title"><TMPL_VAR name="title"></a></span></dd></dl>
</TMPL_LOOP>
<div class="powered">Powered by <a href="http://b.hatena.ne.jp/" title="はてなブックマーク">はてなブックマーク</a></div>
</div>