#!/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";
bookmarklet for AAA is here.
AAA(plain),
AAA(within options)
EOD
return $ans;
}
####------------------------------------------------------------------------
#### AmazonアソシエイトID入力フォーム
####------------------------------------------------------------------------
sub AAA_htmlAssociateIdInputForm {
return << "EOD";
Amazon Assosiation ID Registration
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(
));
}
else{
push(@res, qq(
));
}
}
# コントロールパネルの出力
push(@res, qq(
Amazon.co.jp Item Search
));
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}
EOD
}
####------------------------------------------------------------------------
#### AAAコントロールパネルの出力
####------------------------------------------------------------------------
sub AAA_htmlControlPanel {
my @res;
push(@res, qq(AAA Control Panel HELP
));
push(@res, qq());
return join("\n", @res);
}
####------------------------------------------------------------------------
#### mt-sukeroku-plus用のサンプルを出力する。
####------------------------------------------------------------------------
sub AAA_htmlTextareaForSukeroku {
return << "EOD";
EOD
}
####------------------------------------------------------------------------
#### フッタの出力
####------------------------------------------------------------------------
sub AAA_htmlFooter {
my $ans = << "EOD";
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(
));
}
# 商品名
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(
));
}
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(($d->{Authors})){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, '作者: '); # 作者
}
push(@this, join(', ', map(escape($_), detailElementsToArray($d , 'Authors', 'Author'))));
push(@this, qq(
));
push(@html, join('', @this));
}
# アーティスト
if(($d->{Artists})){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, 'アーティスト: '); # アーティスト
}
push(@this, join(', ', map(escape($_), detailElementsToArray($d , 'Artists', 'Artist'))));
push(@this, qq(
));
push(@html, join('', @this));
}
# 出版社・メーカー
if($d->{Manufacturer}){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, '出版社・メーカー: '); # 出版社・メーカー
}
push(@this, escape($d->{Manufacturer}));
push(@this, qq(
));
push(@html, join('', @this));
}
# 発売日の表示
if($d->{ReleaseDate}){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, '発売日: '); # 発売日
}
push(@this, $d->{ReleaseDate});
if($d->{Availability} && $opt{'prc'}){
push(@this, ' (' . $d->{Availability} .')');
}
push(@this, qq(
));
push(@html, join('', @this));
}
# メディアの表示
if($d->{Media}){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, 'メディア: '); # メディア
}
push(@this, escape($d->{Media}));
push(@this, qq(
));
push(@html, join('', @this));
}
# トラック情報の表示
if($d->{Tracks} && $opt{'trc'} != 0){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, '曲目リスト: '); # 曲目リスト
}
push(@this, qq(
));
push(@this, join('', map('- ' . escape($_) . '
', detailElementsToArray($d , 'Tracks', 'Track'))));
push(@this, qq(
));
push(@html, join('', @this));
}
# 監督情報の表示
if($d->{Directors} && $opt{'trc'} != 0){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, '監督: '); # 監督
}
push(@this, join(', ', map(escape($_), detailElementsToArray($d , 'Directors', 'Director'))));
push(@this, qq(
));
push(@html, join('', @this));
}
# 出演者情報の表示
if($d->{Starring} && $opt{'trc'} != 0){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, '出演者: '); # 出演者
}
push(@this, join(', ', map(escape($_), detailElementsToArray($d , 'Starring', 'Actor'))));
push(@this, qq(
));
push(@html, join('', @this));
}
# プラットフォームの表示
if($d->{Platforms}){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, 'プラットフォーム: '); # プラットフォーム
}
push(@this, join(', ', map(escape($_), detailElementsToArray($d , 'Platforms', 'Platform'))));
push(@this, qq(
));
push(@html, join('', @this));
}
# 価格の表示
if($d->{OurPrice} && $opt{'prc'} != 0){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, '価格: '); # 価格
}
push(@this, escape($d->{OurPrice}));
# 定価の表示
if($d->{ListPrice} && !$opt{'dst'}){
push(@this, '(定価: '); # 定価
push(@this, escape($d->{ListPrice}) . ')');
}
push(@this, qq(
));
push(@html, join('', @this));
}
# 評価があり、かつ表示する場合。
if($d->{Reviews} && $opt{'dsr'} == 0){
my @this;
push(@this, qq(- ));
if(!$opt{'dst'}){
push(@this, '評価: '); # 評価
}
push(@this, $d->{Reviews}->{AvgCustomerRating});
push(@this, '(全' . $d->{Reviews}->{TotalCustomerReviews} . '件)');
push(@this, qq(
));
push(@html, join('', @this));
}
push(@html, qq(
));
# 商品購入カートボタンの表示
if($opt{'crt'}){
push(@html, qq(
));
}
# JavaScriptモードのみPowered by AAAの表示を出す。
if($opt{'js'}){
push(@html, qq(
));
}
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;
}