#!/usr/bin/perl # --------------------------------------------------------------------- # awsxom: AWSからデータを取得して書影その他を作成(ECS v4対応版) # Author: Fukazawa Tsuyoshi # Version: 2006-11-24 # http://fukaz55.main.jp/ # # Product Advertising API対応版 # Modified: castor # Version: 2009-08-14 # --------------------------------------------------------------------- package awsxom; use strict; use LWP::UserAgent; use CGI qw/:standard/; use FileHandle; use POSIX qw(strftime); use URI::Escape; use Digest::SHA qw(hmac_sha256_base64); #use lib "$blosxom::plugin_dir/lib"; #use Digest::SHA::PurePerl qw(hmac_sha256_base64); # --- Plug-in package variables -------- my $asoid = "AmazonアソシエイトID"; # AmazonアソシエイトID my $accesskey = "アクセスキー"; # アクセスキー my $secretkey = "シークレットキー"; # シークレットキー my $cachedir = "$blosxom::plugin_state_dir/aws_cache"; # XMLのキャッシュ用ディレクトリ my $EXPIRE = 24 * 7; # データを再読込する間隔(単位:時間) my $default_template = "awsxom"; # デフォルトのテンプレートファイル名 my $VERSION = '1.4'; my $ua_name = "awsxom $VERSION"; my $debug_mode = 0; # --------------------------------------------------------------------- sub start { # キャッシュ用ディレクトリの作成 if (!-e $cachedir) { my $mkdir_r = mkdir($cachedir, 0755); warn $mkdir_r ? "blosxom : aws plugin > \$cachedir, $cachedir, created.\n" : "blosxom : aws plugin > mkdir missed:$!"; $mkdir_r or return 0; } 1; } # --------------------------------------------------------------------- sub story { my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_; $$body_ref = conv($$body_ref); 1; } # --------------------------------------------------------------------- sub head { my($pkg, $currentdir, $head_ref) = @_; $$head_ref = conv($$head_ref); 1; } # --------------------------------------------------------------------- sub foot { my($pkg, $currentdir, $foot_ref) = @_; $$foot_ref = conv($$foot_ref); 1; } # --------------------------------------------------------------------- sub conv { $_ = shift; # ASIN/ISBNが書かれていたら置き換える # テンプレート指定版 s/(?:ASIN|ISBN):([A-Z0-9]{10}):(.*?):/to_html($1,$2)/ge; # テンプレート無指定版 s/(?:ASIN|ISBN):([A-Z0-9]{10})/to_html($1,$default_template)/ge; return $_; } # --------------------------------------------------------------------- # ASINからAmazonのアフィリエイト用HTMLを作成 sub to_html { my ($asin, $template) = @_; # ASINとテンプレ名称 my $cache = "$cachedir/$asin.xml"; my $url = "http://webservices.amazon.co.jp/onca/xml"; my $outfile = "$cachedir/$asin.html"; my @q = ( "Service=AWSECommerceService", "AWSAccessKeyId=$accesskey", "Operation=ItemLookup", "ItemId=$asin", "ResponseGroup=Medium%2COffers", "Timestamp=". uri_escape(strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())), "Version=2009-07-01", ); my $qs = join "&", sort(@q); my $tosign = join "\n", 'GET', 'webservices.amazon.co.jp', '/onca/xml', $qs; my $signature = hmac_sha256_base64( $tosign, $secretkey ); $signature .= '=' while length($signature) % 4; $url .= "?$qs&Signature=". uri_escape($signature); # 取り込み直す必要はあるか? if (!(-e $cache) || (-M $cache > ($EXPIRE / 24))) { # AWSから情報を取得してキャッシュファイルに保存 # UserAgent初期化 my $ua = new LWP::UserAgent; $ua->agent($ua_name); $ua->timeout(60); my $rtn = $ua->mirror($url, $cache); } # キャッシュからXMLを読み込んで解析 my $content = getFile($cache); my %detail = parseXML($content, $asin); # テンプレートを展開。エラーの場合はエラー文字列を返す my $form; if (!defined($detail{"ErrorMsg"})) { $form = &$blosxom::template($blosxom::path, $template, 'html'); $form =~ s/\$(\w+)/$detail{$1}/ge; } else { $form = "

" . $detail{"ErrorMsg"} . "

"; } return $form; } # --------------------------------------------------------------------- # ファイルを読み込む sub getFile { my $cache = shift; my $fh = new FileHandle; $fh->open($cache); my @data = <$fh>; $fh->close(); my $content = join('', @data); return undef if (!$content); return $content; } # --------------------------------------------------------------------- sub parseXML { my ($buf, $asin) = @_; my %detail; # Amazonへのリンク $detail{"Link"} = "http://www.amazon.co.jp/exec/obidos/ASIN/$asin/ref=nosim/$asoid"; # 個々の要素の抽出 $detail{"Asin"} = $1 if ($buf =~ /([^<]*)<\/ASIN>/); $detail{"ProductName"} = $1 if ($buf =~ /([^<]*)<\/Title>/); $detail{"Catalog"} = $1 if ($buf =~ /<Binding>([^<]*)<\/Binding>/); $detail{"ReleaseDate"} = $1 if ($buf =~ /<PublicationDate>([^<]*)<\/PublicationDate>/); $detail{"ReleaseDate"} = $1 if ($buf =~ /<ReleaseDate>([^<]*)<\/ReleaseDate>/); $detail{"Manufacturer"} = $1 if ($buf =~ /<Manufacturer>([^<]*)<\/Manufacturer>/); $detail{"ImageUrlSmall"} = $1 if ($buf =~ /<SmallImage>[^<]*?<URL>([^<]*)<\/URL>/); $detail{"ImageUrlMedium"} = $1 if ($buf =~ /<MediumImage>[^<]*?<URL>([^<]*)<\/URL>/); $detail{"ImageUrlLarge"} = $1 if ($buf =~ /<LargeImage>[^<]*?<URL>([^<]*)<\/URL>/); $detail{"Availability"} = $1 if ($buf =~ /<Availability>([^<]*)<\/Availability>/); $detail{"ListPrice"} = $1 if ($buf =~ /<LowestNewPrice>.*?<FormattedPrice>([^<]*)<\/FormattedPrice>/); $detail{"OurPrice"} = $1 if ($buf =~ /<ListPrice>.*?<FormattedPrice>([^<]*)<\/FormattedPrice>/); $detail{"UsedPrice"} = $1 if ($buf =~ /<LowestUsedPrice>.*?<FormattedPrice>([^<]*)<\/FormattedPrice>/); $detail{"Author"} = $1 if ($buf =~ /<Author>([^<]*)<\/Author>/); # エラー? if ($buf =~ /<Errors>.*?<Message>([^<]*)<\/Message>/) { $detail{"ErrorMsg"} = $1; } return %detail; } # --------------------------------------------------------------------- # デバッグ用 sub print_debug { return if (!$debug_mode); my $fd = new FileHandle; $fd->open("awsxom.log", "a"); print $fd "$_[0]"; $fd->close(); } 1;