2009-03-08
■ [tech][perl][plagger] Dropbox + Plaggerでお手軽Podcastもどき
大変世間に遅ればせながら、ストレージ共有サービスDropboxを使い始めました。
ユーザー登録後クライアントを設定したら、ローカルに設定した「Dropboxフォルダ」にファイルを放り込むだけ。あとは自動的に同期が行われて、クライアントさえ入っていればネット上のどこからでもローカルのファイルのようにこれを共有することができます。
便利なことにこの「Dropbox」はファイルの入出力情報をRSSで吐いてくれるので、これを使って面白いことができないかなと考えてみました。
たとえば・・・置かれたMp3ファイルのアップデート状況だけ抜き出せば、なんちゃってPodcastプラットフォームとしてDropboxを使えないかなと。
というわけでPlaggerを使い、DropboxのユーザーディレクトリにアップされたMp3の情報を抜き出してPodcastのフィードを生成する仕組みを作ってみました。
Plagger::Plugin::CustomFeed::Dropbox::Mp3
Dropboxのユーザーフィードからmp3の追加部分を抜き出し、Podcast用のフィードとして構成しなおします。
package Plagger::Plugin::CustomFeed::Dropbox::Mp3; use strict; use warnings; use base qw(Plagger::Plugin); use Plagger::Date; use Plagger::Feed; use Plagger::Util; use Plagger::Enclosure; use XML::LibXML; use HTML::TokeParser::Simple; use DateTime::Format::DateParse; sub register { my ($self, $context) = @_; # エントリーロード時のフックを設定 $context->register_hook( $self, 'subscription.load' => \&load, ); } sub load { my ($self, $context) = @_; my $ym = Plagger::Date->now()->strftime("%y%m"); my $feed = Plagger::Feed->new(); $feed->aggregator(sub { $self->aggregate($context, $ym); }); $context->subscription->add($feed); } sub aggregate { my ($self, $context, $ym) = @_; my $feed = Plagger::Feed->new(); my $renewaltime = Plagger::Date->now(); $renewaltime->set_locale("ja_JP"); $feed->link($self->conf->{url}); $feed->title($self->conf->{title}); $feed->description($self->conf->{desc}); # Feedをパース my $items = $self->parse( Plagger::Util::load_uri(URI->new($self->conf->{url})) ); # パースしたFeedのエントリたちをRSSに登録していく for my $item (@$items) { my $entry = Plagger::Entry->new(); $entry->title($item->{title}); $entry->link($item->{link}); $entry->date($item->{datetime}); my $enclosure = Plagger::Enclosure->new(); $enclosure->url($item->{link}); $enclosure->auto_set_type(); $entry->add_enclosure($enclosure); $feed->add_entry($entry); } $context->update->add($feed); } sub parse { my ($self, $content) = @_; my $list = []; # XMLパース my $parser = XML::LibXML->new(); my $dom = $parser->parse_string($content); my @nodes_item = $dom->findnodes('//item'); # エントリーからHTMLタグ(Aタグ)のhref部分を抜き出してリストに追加 foreach my $node_item (@nodes_item) { # エントリーのタイトルに「added」(ファイル追加)が含まれたものだけ対象 my $action = $node_item->findvalue('title'); next if ($action !~ /added/); my $content = $node_item->findvalue('description'); # UTC形式で書かれたpubDateをJSTに変換(YYYYMMDDhhmmss) my $pubDate = $node_item->findvalue('pubDate'); my $dt = DateTime::Format::DateParse->parse_datetime($pubDate); $dt->set_time_zone('Asia/Tokyo'); my $datetime = sprintf("%04d%02d%02d%02d%02d%02d", $dt->year, $dt->month, $dt->day, $dt->hour, $dt->minute, $dt->second, ); my $html_parser = HTML::TokeParser::Simple->new( string => $content ); while(my $token = $html_parser->get_token) { if ($token->is_start_tag('a')) { my $title = $token->get_attr('title'); next if ($title !~ /\.mp3$/); if ($title =~ /(.+)\.mp3$/) { $title = $1; } my $href = $token->get_attr('href'); push (@$list, { datetime => $datetime, title => $title, link => $href, }); } } } @$list = sort { $b->{datetime} cmp $a->{datetime} } @$list; $list; } 1;
config部分
プラグインを経由して整形したフィードをPublish::Feed経由でRSS2.0に書き出します。podcast.yamlとか適当に名前をつけるよろし。
フィードの書き出し先はwebサーバの公開ディレクトリにします。
plugins: - module: CustomFeed::Dropbox::Mp3 config: url: https://www.getdropbox.com/****/events.xml # チェックするDropboxのフィードURL title: Amayan Dropbox Mp3 updates # Podcastのタイトル desc: Dropboxでポッドキャストなのだっ # Podcastの説明文 - module: Publish::Feed config: format: RSS dir: /home/amayan/dir/ # フィードの書き出し先(ローカルの絶対パス) filename: podcast.xml # 書き出しするファイル名
実際の動かし方
ローカルのDropboxフォルダにmp3ファイルを置く
番組のタイトルをファイル名にして保存するだけ。
Plaggerを動作させる
実行するplaggerコマンドの直下にあるlibディレクトリ内にプラグインを入れていることを前提にしています。
$ ./plagger -c podcast.yaml
実際に運用する場合は、これをcronで回したりするといい感じだと思います。
フィードを生成する
<?xml version="1.0" encoding="UTF-8"?> <rss xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"> <channel> <generator>Plagger/0.7.17</generator> <link>https://www.getdropbox.com/****/events.xml</link> <description>Dropboxでポッドキャストなのだっ</description> <title>Amayan Dropbox Mp3 updates</title> <pubDate>Sun, 08 Mar 2009 14:48:14 +0900</pubDate> <item> <author>nobody@example.com</author> <dc:creator>nobody@example.com</dc:creator> <link>https://dl.getdropbox.com/u/645112/%E9%9F%B3%E5%A3%B0%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%281KHz%29.mp3</link> <enclosure length="" url="https://dl.getdropbox.com/u/645112/%E9%9F%B3%E5%A3%B0%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%281KHz%29.mp3" type="audio/mpeg">https://dl.getdropbox.com/u/645112/%E9%9F%B3%E5%A3%B0%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%281KHz%29.mp3audio/mpeg</enclosure> <title>音声サンプル(1KHz)</title> <guid isPermaLink="false">tag:vps00462,2006:https://dl.getdropbox.com/u/645112/%E9%9F%B3%E5%A3%B0%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%281KHz%29.mp3</guid> </item> </channel> </rss>
(iTunesで見てもらいやすくするために) 公開する
iTunesがインストールされているクライアントの場合、itpc://で始まるURIを開くと自動的にiTunesが立ち上がってインポートを行ってくれる*1ので、下記のような「クリック一発登録」のリンクを作成します。
サンプルはこんな感じです。http://akabane.amayan.jp/podcast.html
<html> <head> <title>Podcast登録</title> </head> <body> <a href="itpc://akabane.amayan.jp/podcast.xml">クリックして登録</a> </body> </html>
このリンクをクリックすると、例えばWindows Vistaの場合は以下のようなダイアログが出るので「アプリケーションの起動」をクリックします。
その後はiTunes側で自動的にインポートしてくれて、ミッション完了!
素敵なPodcastライフを!
まとめ&余談
わざわざ外部のサービスを利用したりするほど積極的には更新/公開するつもりはないけれど、特定の友人間で気軽な交換日記的に音声を上げあってチェックできるような仕組みがほしいなーというときになかなか重宝しそうです。
あとは擬似ライブ放送のような形で時差的にファイルをどんどんアップしていきたいときなど、普段配信しているPodcastとは別に「特別チャンネル」のような形で立ち上げて見るのも楽しそう。
せっかく作ったプラグインなので、ゆーすけべーさんが以前やっていた*2ようにCodeReposへ登録してみようかとも思うのですが・・・いったいどこまでファイルを上げればよいものやら。
現状はローカルにチェックアウトしたSixapartのPlaggerリポジトリにファイルを足して(コミットはしていない)使っている状況なのですが、この場合はトップレベルからまるまるCodeReposへインポートしてしまう形でいいのでしょうか。。教えてエロい人!
2009/07/13追記: githubに上げました http://github.com/amayan/Plagger--Plugin--CustomFeed--Dropbox--Mp3/tree/master
*1:WebDog: iTunesにポッドキャストをダイレクト登録させる裏技より。すごく役立ちました!ありがとうございます!
*2:ゆーすけべー日記: Plaggerでニコニコ動画を一括ダウンロード&変換 Podcast を生成して iPod touch で見る - 2007年11月最新版
- 127 http://reader.livedoor.com/reader/
- 59 http://d.hatena.ne.jp/
- 36 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&hs=ip3&q=plagger+podcast&btnG=検索&lr=
- 34 http://mixi.jp/view_diary.pl?id=1102024704&owner_id=25661
- 22 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rls=GGLD,GGLD:2005-26,GGLD:ja&q=mysql+ホスト名
- 18 http://b.hatena.ne.jp/entrylist
- 15 http://www.google.co.jp/search?hl=ja&lr=lang_ja&client=firefox-a&rls=org.mozilla:ja:official&q=HTML::Parser&start=10&sa=N
- 14 http://www.google.co.jp/search?hl=ja&safe=off&client=firefox-a&rls=org.mozilla:ja-JP-mac:official&hs=3nJ&q=XML::LibXML&btnG=検索&lr=lang_ja
- 14 http://www.google.com/reader/view/
- 12 http://b.hatena.ne.jp/entrymobile/12441337






