CDTubeの作り方をソースつきで追ってみる。まずはPlaggerのconfig.yaml
global:
assets_path: /path/to/assets
timezone: Asia/Tokyo
plugins:
- module: Subscription::Config
config:
feed:
- url: http://www.tbs.co.jp/cdtv/cddb/thisweek-j.html
- module: CustomFeed::Config
- module: Filter::CountdownTube
config:
locale: jp
associate_id: xxxxxxxxxx-22
developer_token: XXXXXXXXXX
- module: Filter::ForcePermalink
- module: Publish::Feed
config:
format: RSS
dir: ../root
filename: index.xml
- module: Publish::JavaScript
config:
dir: ../root
filename: index.js
- module: Store::DBIC
config:
schema_class: Plagger::Schema::SQLite
connect_info: [ 'dbi:SQLite:/path/to/plagger.db', ]
CustomFeed::Configのassets内のyaml。authorにアーティスト名、ランキングの順位を無理やりrateプロパティに入れている
match: http://www¥.tbs¥.co¥.jp/cdtv/cddb/thisweek-j¥.html
extract: <td class="t1" align="right">(.*?)¥.</td>.*?songdb/song.*?">(.*?)</a>.*?artistdb/artist.*?">(.*?)</a>
extract_capture: rank track artist
extract_after_hook: |
$data->{title} = $data->{track};
$data->{author} = $data->{artist};
$data->{rate} = $data->{rank};
Filter::CountdownTubeはこんな感じ。titleとauthorを元にAmazonとYouTubeに検索をかけている。mizzyさんが作ったPluginを参考にさせていただきました。後ほどCatalystで使うためにbodyにYouTubeのビデオIDを入れる。
package Plagger::Plugin::Filter::CountdownTube;
use strict;
use base qw( Plagger::Plugin );
use Net::Amazon;
use Net::Amazon::Request::Keyword;
use Encode;
use HTML::Entities;
sub register {
my($self, $context) = @_;
$context->register_hook(
$self,
'update.entry.fixup' => ¥&filter,
);
}
sub filter {
my($self, $context, $args) = @_;
my $e = $args->{entry};
my $attr;
$attr->{token} = $self->conf->{developer_token};
$attr->{locale} = $self->conf->{locale};
$attr->{affiliate_id} = $self->conf->{associate_id};
my $keywords = $e->title . " " . $e->author;
decode_entities($keywords);
$context->log( info => "Searching $keywords on Amazon...");
my $item = search_aws($attr, $keywords, "music-jp");
my $video_id = search_youtube($self,$context,$keywords);
if($video_id eq ''){
$video_id = search_youtube($self,$context,decode_entities($e->title));
}
if($item){
$e->link($item->url);
$e->icon({ url => $item->ImageUrlSmall });
$e->summary($item->ProductDescription);
$e->body($video_id);
}
}
sub search_aws {
my($attr, $keywords, $mode) = @_;
my $ua = Net::Amazon->new(%$attr);
$keywords = encode("UTF-8", "$keywords");
my $req = Net::Amazon::Request::Keyword->new(
keyword => $keywords,
mode => $mode,
);
my $response = $ua->request($req);
my $item = ($response->properties())[0];
return $item;
}
sub search_youtube{
my ($self,$context,$query) = @_;
my $url = URI->new('http://youtube.com/results');
my $file = $self->cache->path_to('youtube_search_result.html');
$query = encode('UTF-8', $query) unless $context->conf->{no_decode_utf8};
$context->log( info => 'Getting YouTube search results for ' . $query );
my $ua = Plagger::UserAgent->new;
$url->query_form(
search_type => 'search_videos',
search_query => $query,
);
my $res = $ua->mirror( $url->as_string => $file );
if($res->is_error){
$context->log( error => $res->status );
return;
}
open my $fh, "<:encoding(utf-8)", $file
or return $context->log(error => "$file: $!");
my $video_id;
while (<$fh>) {
m!<a href="/watch¥?v=(.*?)"!
and do{
$video_id = $1;
$context->log(info => "$video_id get!");
last;
};
};
return $video_id;
}
1;
フィードの準備ができたので、Catalystのアプリを実装。PlaggerからStore-DBICされたSQLiteのdbがモデルになる。DBIC::Schemeのヘルパースクリプトを使ってクラスを自動生成。
$ ./script/cdtube_create.pl model Plagger DBIC::Schema CDTube::Model::Schema create=static dbi:SQLite:/path/to/plagger.db
次にコントローラーの実装。必要に応じてモデルにもメソッドを追加する。コントローラーはRoot.pmのみで済ませた。DBIC::Scheme、初めて使ったけどいい感じです。諸事情のため、reseltsetのpagerは使ってない。
package CDTube::Controller::Root;
use strict;
use warnings;
use base 'Catalyst::Controller';
use Data::Dumper;
__PACKAGE__->config->{namespace} = '';
sub default : Private {
my ( $self, $c ) = @_;
my $of = $c->request->arguments->[0] || 1;
if($of > 100){$of = 1};
$c->log->debug("of is $of");
my @entries;
my $it = $c->model('Plagger::Entry')->search(
{},
{ order_by => 'cast(rate AS INTEGER) ASC',
});
while(my $e = $it->next ){
if($e->rate > ($of - 1)){
if($e->rate < ( $of + 10)){
push(@entries,$e);
}
}
}
my @feed = $c->model('Plagger::Feed')->all;
my $week = $feed[0]->week;
$c->stash->{week} = $week;
$c->stash->{of} = $of;
$c->stash->{entries} = ¥@entries;
$c->stash->{template} = 'index.tt';
}
sub end : ActionClass('RenderView') {}
1;
後はビューの実装。$entry->bodyでYouTubeのビデオIDがとれるのでそのままembedのタグに入れ込む。
ページング処理がちょっと複雑になったけど、わりとあっさりとできた。と、一通り完成したら、細かい修正加えて、HTMLをMT風にしてスタイルを適用。あとはmod_perlで動くことを確認して、できあがりです。