#!/usr/local/bin/perl -w #------------------------------------------------------ # AAA(Amazon Associate Assistants) Ver.0.01 / 20041119 # Copyright (C) DonaDona(KITAO Masato) 2004 #------------------------------------------------------ # [設定] ここから #----------------------------------------------- use strict; my $config = { #-------------------------------------------------------- # 標準設定 #-------------------------------------------------------- # アクセスするAmazon Web Servicesのアドレス aws_url => 'http://xml.amazon.co.jp/onca/xml3?', # Amazon Web Services Developer's Token / Subscription ID aws_token => '0Q00TC89ZRCXRJ390YR2', # 標準のアソシエイトID default_aid => 'hsjjp-22', # 異常なASINコードが来た場合の置換えASINコード(^^; alt_asin_code => 'B0001TW2OC', #-------------------------------------------------------- # 画像関連 #-------------------------------------------------------- img_src => { # カート追加画像のURL addcart => 'http://hsj.jp/aaa/remote-buy-jp2.gif', # 代替画像のURL alt => 'http://hsj.jp/aaa/comingsoon.gif', # ページ下部の広告画像のURL footer => 'http://hsj.jp/aaa/multiproduct_v3_468_anime.gif', }, #-------------------------------------------------------- # AAAの外部利用モード関連 #-------------------------------------------------------- open_mode => { # AAAの外部利用許可 (1: 許可する, 0: 許可しない) mode => 1, # AAAの外部判定(自サーバもしくはURIの範囲を規定) range => '', # AAAの外部利用許可時にdefault_aidで上書きする確率 (数値: 0〜100) overwrite_ratio => 50, }, #-------------------------------------------------------- # その他 #-------------------------------------------------------- # mt-sukeroku-plusのサンプル表示 (1: する, 0: しない) misc =>{ msp_code_view => 1, }, }; #----------------------------------------------- # [設定] ここまで #----------------------------------------------- BEGIN { unshift @INC, './'; # MTなフォルダに入れているのなら下の行をコメント解除 # unshift @INC, './extlib'; } use CGI; use LWP::UserAgent; use XML::Simple; use Jcode; #----------------------------------------------- # 変数宣言 #----------------------------------------------- my %opt; my $cgi = new CGI; my $myuri = 'http://' . $cgi->server_name . $cgi->script_name; my $aid = ''; my $ref = ''; my $mode = ''; # asin/list my $asin = ''; my $listid = ''; my $debug = ''; my $refer = ''; #----------------------------------------------- # 処理 #----------------------------------------------- &AAA_init(); if($opt{'js'}){ # AAA Live Associate Script出力モード &AAA_outputLiveAssociateScript($aid, $asin, $listid); } else{ # HTML print &AAA_htmlHeader(); if($asin ne '' || $listid ne ''){ if($asin ne ''){ &AAA_outputHtmlBody(&AWS_AsinSearch($aid, $asin), $aid, $asin); } else{ my @details = &AWS_ListManiaSearch($aid, $listid); if(ref($details[0]) eq 'HASH'){ my $pointer = ($opt{'rnd'} ? int(rand(@details)) : 0); my $detail = $details[$pointer]; if($detail->{Asin}){ &AAA_outputHtmlBody($detail, $aid, $detail->{Asin}); } } else{ print "

" . $details[0] . "

"; } } } else{ print &AAA_htmlAssociateIdInputForm(); } print &AAA_htmlFooter(); } exit 0; ####------------------------------------------------------------------------ #### AAA Live Associate Scriptの生成 ####------------------------------------------------------------------------ sub AAA_outputLiveAssociateScript { # パラメータの取得 my ($aid, $asin, $listid) = @_; print "Content-type: text/javascript\n\n"; # 外部リンク時の処理 if(!($refer =~ /$config->{open_mode}->{range}/)){ # 外部利用許可していない場合 if(!$config->{open_mode}->{mode}){ print qq(document.write\('Access Denied.'\);\n); return; } else{ # 0〜99をランダムに生成し、設定値と比較し上書きを行う。 my $rand = int(rand(100)); if($rand < $config->{open_mode}->{overwrite_ratio}){ $aid = $config->{default_aid}; } } } if($listid){ my @details = &AWS_ListManiaSearch($aid, $listid); for(my $i = 0; $i < $opt{'cnt'}; $i++){ my $pointer = ($opt{'rnd'} ? int(rand(@details)) : $i); my $detail = $details[$pointer]; my @html = &AAA_generateHtml($detail, $aid, $detail->{Asin}); foreach my $html(@html){ $html =~ s|\'|\\\'|g; $html = qq(document.write\('${html}'\);\n); if($opt{'enc'} ne 'utf8'){ $html = Jcode::convert($html, $opt{'enc'}); } print $html; } } } elsif($asin){ my @html = &AAA_generateHtml(&AWS_AsinSearch($aid, $asin), $aid, $asin); foreach my $html(@html){ $html =~ s|\'|\\\'|g; $html = qq(document.write\('${html}'\);\n); if($opt{'enc'} ne 'utf8'){ $html = Jcode::convert($html, $opt{'enc'}); } print $html; } } } ####------------------------------------------------------------------------ #### ヘッダの出力 ####------------------------------------------------------------------------ sub AAA_htmlHeader { my $ans = ''; $ans .= $cgi->header( -type => 'text/html; charset=UTF-8', ); $ans .= $cgi->start_html( -title => "AAA(Amazon Associate Assistants) - HSJ.jp", -style => {'src' => './style.css'}, ); $ans .= << "EOD";

AAA(Amazon Associate Assistants)

bookmarklet for AAA is here. AAA(plain), AAA(within options)
EOD return $ans; } ####------------------------------------------------------------------------ #### AmazonアソシエイトID入力フォーム ####------------------------------------------------------------------------ sub AAA_htmlAssociateIdInputForm { return << "EOD";

Amazon Assosiation ID Registration

Amazon Association ID:

Help Page is here.

EOD } ####------------------------------------------------------------------------ #### HTMLボディを出力する。 ####------------------------------------------------------------------------ sub AAA_outputHtmlBody{ # パラメータの取得 my ($d, $aid, $asin) = @_; my @res; if($d == 0){ print qq(

Help Page is here.

); return; } if(!$d->{Asin}){ print qq(

${d}

); return; } # 左サイド push(@res, qq(
)); { my @html = &AAA_generateHtml($d, $aid, $asin); push(@res, &AAA_htmlPreview($d, $aid, $asin, @html)); } push(@res, qq(
)); # 右サイド push(@res, qq(
)); { # debuging info :) if($debug){ push(@res, qq(

Debug Information

)); if($mode eq 'asin'){ push(@res, qq(
ASIN:${asin}(AWS debug)
)); } else{ push(@res, qq(
LIST:${listid}(AWS debug)
)); } } # コントロールパネルの出力 push(@res, qq(

Amazon.co.jp Item Search

)); push(@res, qq(
)); push(@res, qq(
)); push(@res, qq()); push(@res, qq()); push(@res, qq()); push(@res, qq()); push(@res, qq()); push(@res, qq()); push(@res, qq(
)); push(@res, qq(
)); # コントロールパネルの出力 push(@res, &AAA_htmlControlPanel()); # mt-sukeroku-plus用の出力 if($config->{misc}->{msp_code_view}){ push(@res, &AAA_htmlTextareaForSukeroku()); } } push(@res, qq(
)); print join("\n", @res); } ####------------------------------------------------------------------------ #### AAA HTML Previewの出力 ####------------------------------------------------------------------------ sub AAA_htmlPreview { # パラメータの取得 my ($d, $aid, $asin, @html) = @_; my $html = join("\n", @html); my $escapedHtml = &escape($html); return << "EOD";

AAA Preview

${html}

HTML(Without CSS) Copy (IE only)

AAA Live Associate Script Copy (IE only)

EOD } ####------------------------------------------------------------------------ #### AAAコントロールパネルの出力 ####------------------------------------------------------------------------ sub AAA_htmlControlPanel { my @res; push(@res, qq(

AAA Control Panel HELP

)); push(@res, qq(
)); if($mode eq 'asin'){ push(@res, qq()); } else{ push(@res, qq()); } if($debug){ push(@res, qq()); } push(@res, qq()); push(@res, qq()); push(@res, qq(
)); return join("\n", @res); } ####------------------------------------------------------------------------ #### mt-sukeroku-plus用のサンプルを出力する。 ####------------------------------------------------------------------------ sub AAA_htmlTextareaForSukeroku { return << "EOD";

mt-sukeroku-plus(YukiWiki)

mt-sukeroku-plus(PukiWiki:detail)

mt-sukeroku-plus(PukiWiki:image)

mt-sukeroku-plus(Hatena:detail)

mt-sukeroku-plus(Hatena:image)

EOD } ####------------------------------------------------------------------------ #### フッタの出力 ####------------------------------------------------------------------------ sub AAA_htmlFooter { my $ans = << "EOD";
 Amazon.co.jp
EOD $ans .= $cgi->end_html; } ####------------------------------------------------------------------------ #### Requestパラメータの読み込み ####------------------------------------------------------------------------ sub AAA_init { #------------------------------------------------------------------------- # 標準パラメータ #------------------------------------------------------------------------- $aid = $cgi->param('aid'); $ref = $cgi->param('ref'); $asin = $cgi->param('asin'); $listid = $cgi->param('list'); $debug = ($cgi->param('dbg') eq '' ? 0 : $cgi->param('dbg')); $refer = $ENV{'HTTP_REFERER'}; #------------------------------------------------------------------------- # 動作オプション #------------------------------------------------------------------------- # ・出力件数 $opt{'cnt'} = ($cgi->param('cnt') eq '' ? 1 : $cgi->param('cnt')); # ・ランダム出力フラグ $opt{'rnd'} = ($cgi->param('rnd') eq '' ? 0 : $cgi->param('rnd')); # ・書籍タイトルの『』付けの有無 $opt{'btq'} = ($cgi->param('btq') eq '' ? 0 : $cgi->param('btq')); # ・CDトラック情報の有無 $opt{'trc'} = ($cgi->param('trc') eq '' ? 0 : $cgi->param('trc')); # ・評価情報の有無 $opt{'dsr'} = ($cgi->param('dsr') eq '' ? 0 : $cgi->param('dsr')); # ・見出しの有無 $opt{'dst'} = ($cgi->param('dst') eq '' ? 0 : $cgi->param('dst')); # ・価格情報の有無 $opt{'prc'} = ($cgi->param('prc') eq '' ? 0 : $cgi->param('prc')); # ・カート投入フォームの有無 $opt{'crt'} = ($cgi->param('crt') eq '' ? 0 : $cgi->param('crt')); # ・サブパネルモードでの動作 $opt{'sub'} = ($cgi->param('sub') eq '' ? 0 : $cgi->param('sub')); # ・JavaScriptモードでの動作 $opt{'js'} = ($cgi->param('js') eq '' ? 0 : $cgi->param('js')); # ・JavaScriptモードでのキャラクタエンコーディング $opt{'enc'} = ($cgi->param('enc') eq '' ? 'utf8' : $cgi->param('enc')); # ・フォーマットの指定 $opt{'fmt'} = ($cgi->param('fmt') eq '' ? 'detail' : $cgi->param('fmt')); # ・画像サイズの設定 $opt{'img'} = 'm'; #($cgi->param('img') eq '' ? 'm' : $cgi->param('img')); #------------------------------------------------------------------------- # 指定ナシ/妥当性がない時はデフォルトに。 #------------------------------------------------------------------------- if($aid eq ''){ $aid = $config->{default_aid}; } if(!($aid =~ /^[0-9A-z]+\-[0-9]+$/)){ $aid = $config->{default_aid}; } if($config->{open_mode}->{range} eq ''){ $config->{open_mode}->{range} = '^http://' . $cgi->server_name . '/'; } # ASINコードの取得。こんないい加減でいいのかいな(^^; if($asin eq '' && $listid eq ''){ if($ref =~ /\/exec\/obidos\/ASIN\//){ if($ref =~ /\/ASIN\/([0-9A-Z]+)\//){ $asin = $1; } } elsif($ref =~ /\/exec\/obidos\/tg\/listmania\//){ if($ref =~ /\/list-browse\/\-\/([0-9A-Z]+)\//){ $listid = $1; } } } # ASINコードが不正なときは代替コードに置き換える。 $mode = 'asin'; if($listid ne ''){ if(!($listid =~ /^[0-9A-z]{13}$/)){ $asin = $config->{alt_asin_code}; } else{ $mode = 'list'; } } else{ if(!($asin =~ /^[0-9A-z]{10}$/)){ $asin = $config->{alt_asin_code}; } } # 出力件数は1〜3件まで(モードがリストのときだけ) if($mode eq 'list'){ if(!($opt{'cnt'} >= 1 && $opt{'cnt'} <= 3)){ $opt{'cnt'} = 1; } } else{ $opt{'cnt'} = 1; } # 乱数の種の初期化 srand(time ^ ($$ + ($$ << 15))); } ####------------------------------------------------------------------------ #### AWSでAsinコードによる検索を行う(based on aws.pl) ####------------------------------------------------------------------------ sub AWS_AsinSearch { # パラメータの取得 my ($aid, $asin) = @_; my $aws_url = $config->{aws_url}; my $aws_token = $config->{aws_token}; my @query; # リクエストの生成 push @query, "AsinSearch=$asin"; push @query, "dev-t=$aws_token"; push @query, "t=$aid"; push @query, "f=xml"; push @query, "type=heavy"; push @query, "locale=jp"; $aws_url .= join("&", @query); # 実行&結果取得 my $ua = new LWP::UserAgent; $ua->agent("AAA_Agent(${myuri})"); my $req = new HTTP::Request('GET', $aws_url); my $res = $ua->request($req); my $answer = XMLin($res->{'_content'}); if(!($answer)){ return 0; } else{ if($answer->{Details}){ return $answer->{Details}; } else{ return $answer->{ErrorMsg}; } } } ####------------------------------------------------------------------------ #### AWSでListManiaIDによる検索を行う ####------------------------------------------------------------------------ sub AWS_ListManiaSearch { # パラメータの取得 my ($aid, $listid) = @_; my $aws_url = $config->{aws_url}; my $aws_token = $config->{aws_token}; my @query; # リクエストの生成 push @query, "ListManiaSearch=$listid"; push @query, "dev-t=$aws_token"; push @query, "t=$aid"; push @query, "f=xml"; push @query, "type=heavy"; push @query, "locale=jp"; $aws_url .= join("&", @query); # 実行&結果取得 my $ua = new LWP::UserAgent; $ua->agent("AAA_Agent(${myuri})"); my $req = new HTTP::Request('GET', $aws_url); my $res = $ua->request($req); my $answer = XMLin($res->{'_content'}); if(!($answer)){ return 0; } else{ my @details; if (ref($answer->{Details}) eq 'ARRAY') { push(@details,@{$answer->{Details}}); } elsif($answer->{Details}){ push(@details,$answer->{Details}); } else{ push(@details,$answer->{ErrorMsg}); } return @details; } } ####------------------------------------------------------------------------ #### HTML生成(商品名と画像に関する部分) ####------------------------------------------------------------------------ sub AAA_generateHtmlNameImage{ # パラメータの取得 my ($d, $aid, $asin, $fid) = @_; # 変数 my @html; my $productName = escape($d->{ProductName}); my $altImage = $config->{img_src}->{alt}; my $imageUrl = ($opt{'img'} eq 's') ? $d->{ImageUrlSmal} : ($opt{'img'} eq 'l') ? $d->{ImageUrlLarge} : $d->{ImageUrlMedium}; # 書影画像 if($fid eq 'image'){ push(@html, qq(${productName})); } # 商品名 if($fid eq 'name'){ push(@html, qq()); # 商品が書籍で題名の『』付けをする場合(isbnコードの頭が4の場合は『』、それ以外は""で囲む) if($d->{Catalog} eq 'Book' && $opt{'btq'} == 1){ if($d->{Isbn} =~ /^4/){ push(@html, "『${productName}』"); } else{ push(@html, "\"${productName}\""); } } else{ push(@html, ${productName}); } push(@html, qq()); } return @html; } ####------------------------------------------------------------------------ #### AAA Htmlの生成 ####------------------------------------------------------------------------ sub AAA_generateHtml{ # パラメータの取得 my ($d, $aid, $asin) = @_; if($d == 0 || !$d->{Asin}){ my @html; push(@html, qq(

$d

)); return @html; } # HTML生成部分(詳細以外) if($opt{'fmt'} ne 'detail'){ my @html; my $productName = escape($d->{ProductName}); if($opt{'fmt'} eq 'box'){ my $divDetailClass = 'asin-detail'; if($opt{'sub'}){ $divDetailClass = 'asin-detail-sub'; } push(@html, qq(
)); push(@html, &AAA_generateHtmlNameImage($d, $aid, $asin, 'image')); push(@html, qq(

)); push(@html, &AAA_generateHtmlNameImage($d, $aid, $asin, 'name')); push(@html, qq(

)); # JavaScriptモードのみPowered by AAAの表示を出す。 if($opt{'js'}){ push(@html, qq(
Powered by AAA
)); } push(@html, qq(
)); } if($opt{'fmt'} eq 'image' || $opt{'fmt'} eq 'nameimage'){ push(@html, &AAA_generateHtmlNameImage($d, $aid, $asin, 'image')); } if($opt{'fmt'} eq 'name' || $opt{'fmt'} eq 'nameimage'){ push(@html, &AAA_generateHtmlNameImage($d, $aid, $asin, 'name')); } return @html; } # HTML生成部分(詳細) else{ return &AAA_generateHtmlDetail($d, $aid, $asin); } } ####------------------------------------------------------------------------ #### AAA Htmlの生成(詳細専用) ####------------------------------------------------------------------------ sub AAA_generateHtmlDetail { # パラメータの取得 my ($d, $aid, $asin) = @_; my @html; my $divDetailClass = 'asin-detail'; if($opt{'sub'}){ $divDetailClass = 'asin-detail-sub'; } # ベース部分 push(@html, qq(
)); push(@html, &AAA_generateHtmlNameImage($d, $aid, $asin, 'image')); push(@html, qq(

)); push(@html, &AAA_generateHtmlNameImage($d, $aid, $asin, 'name')); push(@html, qq(

)); # 詳細情報列挙 push(@html, qq()); # 商品購入カートボタンの表示 if($opt{'crt'}){ push(@html, qq(
)); push(@html, qq()); push(@html, qq()); push(@html, qq()); if($config->{img_src}->{addcart} eq ''){ push(@html, qq()); } else{ push(@html, qq()); } push(@html, qq(
)); } # JavaScriptモードのみPowered by AAAの表示を出す。 if($opt{'js'}){ push(@html, qq(
Powered by AAA
)); } push(@html, qq(
)); return @html; } ####------------------------------------------------------------------------ #### ネストしたXMLエレメントを配列にまとめる ####------------------------------------------------------------------------ sub detailElementsToArray(){ # パラメータの取得 my ($detail, $parent, $child) = @_; my @answer; if (ref($detail->{$parent}->{$child}) eq 'ARRAY') { push(@answer,@{$detail->{$parent}->{$child}}); } elsif($detail->{$parent}->{$child}){ push(@answer,$detail->{$parent}->{$child}); } return @answer; } ####------------------------------------------------------------------------ #### 前回値を反映したCheckBoxをレンダリングする(現在値でchecked="checked") ####------------------------------------------------------------------------ sub renderCheckbox(){ # パラメータの取得 my ($name, $nowvalue, $label) = @_; my $ans = ""; $ans = qq(); return $ans; } ####------------------------------------------------------------------------ #### 前回値を反映したComboBoxをレンダリングする(現在値をselected="selected") ####------------------------------------------------------------------------ sub renderCombobox(){ # パラメータの取得 my ($name, $nowvalue, @list) = @_; my $ans = qq(); return $ans; } ####------------------------------------------------------------------------ #### HTMLエスケープ ####------------------------------------------------------------------------ sub escape { my $s = shift; $s =~ s|\r\n|\n|g; $s =~ s|\&([^\#])|&$1|g; $s =~ s|<|<|g; $s =~ s|>|>|g; $s =~ s|\"|"|g; return $s; }