2007-10-29
■ [CustomFeed-Script] tumblrのAPIを叩いてCustomFeed::Script用にフィード化するPerlスクリプト

への反応:
API用意されてるのになんでRSSたたくんだろう。
それplaggerで、やることじゃないんじゃいかな。 - sasezakiの日記 - たんぶら部 - Tumblove -
が至極ごもっともだと思ったので,APIを叩く版を作った。
assets/plugins/CustomFeed-Script/tumblr.pl
引数は3つ。
- ユーザ名 or URL
- 例:sweetpotato,http://sweetpotato.tumblr.com/,http://tumblelog.marco.org/
- エントリ数(省略可能)
- 正の整数を指定する。省略時は20が使用される。10単位での指定が望ましい。エントリは10件ずつAPIを通じて取得し,取得した分は無駄なく結果として返すので,指定した数以上のエントリが返される場合もある。
- タイプ(省略可能)
- regular,quote,photo,link,conversation,videoのいずれかを指定することで,そのタイプの投稿のみを取得する。これらはそれぞれtumblrのDashboardの「Add a new...」の左から順に対応している。省略時は全てのタイプの投稿を取得する。
#!/usr/bin/perl
# author: SweetPotato
use strict;
use warnings;
use DateTime::Format::HTTP;
use FindBin;
use File::Spec::Functions qw/catfile/;
use HTML::Template;
use LWP::UserAgent;
use List::MoreUtils qw/any/;
use URI;
use Switch;
use XML::TreePP;
use YAML;
my $user = shift or die "specify user or url";
$user = "http://$user.tumblr.com" unless $user =~ m!^http://!;
die "bad url: $user" unless $user =~ m!^http://[^/]+/?$!;
$user =~ s!/$!!;
my $num = @ARGV ? shift : 20;
die "specify positive number: $num" unless $num > 0;
my $type = @ARGV ? shift : '';
if ($type ne '') {
any { $type eq $_ } qw/regular quote photo link conversation video/
or die "type must be one of regular, quote, photo, link, conversation, or video: $type";
}
my $ua = LWP::UserAgent->new;
my ($title, $timezone, @entry);
for (my $start = 0; $start < $num; $start += 10) {
my $url = URI->new("$user/api/read");
$url->query_form(start => $start, num => 10, type => $type);
my $res = $ua->get($url);
unless ($res->is_success) {
warn "GET $url failed: " . $res->status_line;
last;
}
my $parser = XML::TreePP->new;
$parser->set(utf8_flag => 1);
my $tree = $parser->parse($res->content);
$title = $tree->{tumblr}->{tumblelog}->{'-title'}
unless defined $title;
$timezone = $tree->{tumblr}->{tumblelog}->{'-timezone'}
unless defined $timezone;
for (@{ $tree->{tumblr}->{posts}->{post} || [] }) {
# pre-process for template
if ($_->{'-type'} eq 'photo') {
$_->{'photo-url'} = $_->{'photo-url'}->[0]->{'#text'};
}
if ($_->{'-type'} eq 'conversation') {
$_->{'conversation-text'} =~ s!\r\n!<br />!g;
}
push @entry, +{
link => $_->{'-url'},
date => &mk_date($_->{'-date'}, $timezone),
title => &mk_title($_),
body => &mk_body($_),
};
}
# fetch next ?
last if $tree->{tumblr}->{posts}->{'-start'} < $start;
}
binmode STDOUT, ":utf8";
print YAML::Dump +{
title => $title,
link => "$user/",
entry => \@entry,
};
sub mk_title {
my $post = shift;
switch ($post->{'-type'}) {
case 'regular' { return $post->{'regular-title'} || 'regular post' }
case 'quote' { return 'quote post' }
case 'photo' { return 'photo post' }
case 'link' { return $post->{'link-text'} || 'link post' }
case 'conversation' { return $post->{'conversation-title'} || 'conversation post' }
case 'video' { return 'video post' }
else { return }
}
return;
}
sub mk_date {
my ($date, $timezone) = @_;
DateTime::Format::HTTP->format_datetime(
DateTime::Format::HTTP->parse_datetime($date, $timezone)
);
}
sub mk_body {
my $post = shift;
my $t = HTML::Template->new(
filename => catfile($FindBin::Bin, 'tumblr.t'),
die_on_bad_params => 0,
);
$t->param($post);
return $t->output;
}
assets/plugins/CustomFeed-Script/tumblr.t
HTML::Template用テンプレート。
<TMPL_IF NAME="regular-body"> <TMPL_VAR NAME="regular-body"> </TMPL_IF> <TMPL_IF NAME="photo-url"> <img src="<TMPL_VAR ESCAPE=HTML NAME="photo-url">" /> <TMPL_IF NAME="photo-caption"> <br /><br /><TMPL_VAR NAME="photo-caption"> </TMPL_IF> </TMPL_IF> <TMPL_IF NAME="quote-text"> “<TMPL_VAR NAME="quote-text">” <TMPL_IF NAME="quote-source"> <br /><br />— <TMPL_VAR NAME="quote-source"> </TMPL_IF> </TMPL_IF> <TMPL_IF NAME="link-url"> <a href="<TMPL_VAR ESCAPE=HTML NAME="link-url">"> <TMPL_IF NAME="link-text"> <TMPL_VAR ESCAPE=HTML NAME="link-text"> <TMPL_ELSE> <TMPL_VAR ESCAPE=HTML NAME="link-url"> </TMPL_IF> </a> <TMPL_IF NAME="link-description"> <br /><br /><TMPL_VAR NAME="link-description"> </TMPL_IF> </TMPL_IF> <TMPL_IF NAME="conversation-text"> <TMPL_VAR NAME="conversation-text"> </TMPL_IF> <TMPL_IF NAME="video-player"> <TMPL_VAR NAME="video-player"> <TMPL_IF NAME="video-caption"> <br /><br /><TMPL_VAR NAME="video-caption"> </TMPL_IF> </TMPL_IF>
config.yaml
エロい例。
plugins: - module: Subscription::Config config: feed: - url: 'script:/path/to/tumblr.pl moeura 100 photo' - url: 'script:/path/to/tumblr.pl detailura 100 photo' - url: 'script:/path/to/tumblr.pl detailurac 100 photo' - module: CustomFeed::Script - module: Filter::FindEnclosures - module: Filter::FetchEnclosure config: dir: /path/to/enclosure fake_referer: 1
トラックバック - http://plagger.g.hatena.ne.jp/SweetPotato/20071029
「ntifier」,私も確認しましたが,何でしょうね……。コード中にはそのような部分文字列すら存在しないミステリー……。
コードを見て勉強させていただきます。