気象庁の降水情報画像のURIを作るPerlのモジュール

もう、梅雨も開けてしまったけれど、あえて雨ネタ。気象庁のレーダ・降水ナウキャストというのが便利でよく使ってる。で、昨日友達と、そこの画像をひろってきて携帯用にクロップしたり、降水状況監視したりしたら便利じゃね?などと話しになった。

それで、とりあえず、その画像のURIを拾ってくるモジュールを書いてみることに。ちゅうか、Perlでモジュール書くのははじめてなので何かとあやしげ。

とりあえず、使い方。コンストラクタに地域コードを渡してオブジェクトを作る。image_uriが画像のURIオブジェクトを返すメソッド。PASTの指定で過去のURI、FORECASTの指定で予報の画像のURIを表示します。

use warnings;
use strict;
use WWW::JMA::NowCast;

my $nc = WWW::JMA::NowCast->new ('KINKI');

my $img_uri;

$img_uri = $nc->image_uri;

$img_uri = $nc->image_uri(PAST => 2);
 
$img_uri = $nc->image_uri(FORECAST => 2);

http://www.jma.go.jp/jp/radnowc/imgs/radar/211/200608031200-00.png という感じのURIが帰ってくる。ただ、なにせ時々刻々とデータが更新されるのですでにこのURLはNot Foundになってる可能性大。

なんつか、サブルーチンがいい感じに制御結合でやだなぁ。

package WWW::JMA::NowCast;
use warnings;
use strict;
use base qw(Class::Accessor::Fast);
__PACKAGE__->mk_accessors(qw(areacode));

use Carp;
use URI;
use Date::Calc::Object qw(:all);

sub new {
    my $class      = shift;
    my $self       = {};
    my $areastring = shift;

    $self->{areacode} =
        $areastring =~ /^[+-]?\d+$/
      ? $areastring
      : $class->_map_areacode($areastring);

    return bless $self, $class;
}

sub _map_areacode {
    my $self         = shift;
    my $areastring   = shift;
    my %areacode_map = (
        ZENKOKU            => 000,
        HOKKAIDO_HOKUSEIBU => 201,
        HOKKAIDO_TOUBU     => 202,
        HOKKAIDO_NANSEIBU  => 203,
        TOHOKU_HOKUBU      => 204,
        TOHOKU_NANBU       => 205,
        KANTO              => 206,
        KOUSHIN            => 207,
        HOKURIKU_TOUBU     => 208,
        HOKURIKU_SEIBU     => 209,
        TOKAI              => 210,
        KINKI              => 211,
        CHUGOKU            => 212,
        SHIKOKU            => 213,
        KYUSHU_HOKUBU      => 214,
        KYUSHU_NANBU       => 215,
        AMAMI              => 216,
        OKINAWA_HONTO      => 217,
        DAITOUJIMA         => 218,
        MIYAKO_YAEYAMA     => 219,
    );
    if ( !$areacode_map{$areastring} ) {
        carp "can't find areacode\n";
        return 'no_such_area';
    }

    return $areacode_map{$areastring};
}

sub _calc_image_name {
    my $self = shift;
    my ( $direction, $offset ) = @_;

    my $date = Date::Calc->now();

    my $forecast_index = 0;
    if ( $direction && $direction eq 'past' ) {
        $date += [ 0, 0, 0, 0, -10 * $offset, 0 ];
    }
    elsif ( $direction && $direction eq 'forecast' ) {
        $date += [ 0, 0, 0, 0, -10, 0 ];
        $forecast_index = $offset;
    }
    else {
        $date += [ 0, 0, 0, 0, -10, 0 ];
    }

    $date->minutes( int( $date->minutes / 10 ) * 10 );

    return sprintf(
        "%d%02d%02d%02d%02d-%02d.png",
        $date->year,  $date->month,   $date->day,
        $date->hours, $date->minutes, $forecast_index,
    );
}

sub image_uri {
    my $self   = shift;
    my %option = @_;

    my $baseuri = URI->new('http://www.jma.go.jp/jp/radnowc/imgs/');

    my $image_name;
    my $image_path;
    if ( $option{PAST} && $option{FORECAST} ) {
        carp "passing both PAST and FORECAST options is not permitted\n";
        return;
    }
    elsif ( $option{PAST} ) {
        $image_name = $self->_calc_image_name( 'past', $option{PAST} );
        $image_path = "radar/$self->{areacode}/$image_name";
    }
    elsif ( $option{FORECAST} ) {
        $image_name = $self->_calc_image_name( 'forecast', $option{FORECAST} );
        $image_path = "nowcast/$self->{areacode}/$image_name";
    }
    else {
        $image_name = $self->_calc_image_name();
        $image_path = "radar/$self->{areacode}/$image_name";
    }
    $baseuri = URI->new_abs( $image_path, $baseuri );

    return $baseuri;
}

1;