| File: | C4/External/Amazon.pm |
| Coverage: | 38.0% |
| line | stmt | bran | cond | sub | time | code |
|---|---|---|---|---|---|---|
| 1 | package C4::External::Amazon; | |||||
| 2 | # Copyright (C) 2006 LibLime | |||||
| 3 | # <jmf at liblime dot com> | |||||
| 4 | # | |||||
| 5 | # This file is part of Koha. | |||||
| 6 | # | |||||
| 7 | # Koha is free software; you can redistribute it and/or modify it under the | |||||
| 8 | # terms of the GNU General Public License as published by the Free Software | |||||
| 9 | # Foundation; either version 2 of the License, or (at your option) any later | |||||
| 10 | # version. | |||||
| 11 | # | |||||
| 12 | # Koha is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| 13 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| 14 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| 15 | # | |||||
| 16 | # You should have received a copy of the GNU General Public License along | |||||
| 17 | # with Koha; if not, write to the Free Software Foundation, Inc., | |||||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||||
| 19 | ||||||
| 20 | 4 4 4 | 44612 21234 109 | use XML::Simple; | |||
| 21 | 4 4 4 | 1247 91280 33 | use LWP::Simple; | |||
| 22 | 4 4 4 | 1659 5 116 | use LWP::UserAgent; | |||
| 23 | 4 4 4 | 384 5405 873 | use HTTP::Request::Common; | |||
| 24 | 4 4 4 | 375 6 1510 | use C4::Koha; | |||
| 25 | 4 4 4 | 20 5 232 | use URI::Escape; | |||
| 26 | 4 4 4 | 17 14 70 | use POSIX; | |||
| 27 | 4 4 4 | 55604 66699 444 | use Digest::SHA qw(hmac_sha256_base64); | |||
| 28 | ||||||
| 29 | 4 4 4 | 29 9 93 | use strict; | |||
| 30 | 4 4 4 | 22 10 193 | use warnings; | |||
| 31 | ||||||
| 32 | 4 4 4 | 19 10 405 | use vars qw($VERSION @ISA @EXPORT); | |||
| 33 | ||||||
| 34 | BEGIN { | |||||
| 35 | 4 | 21 | require Exporter; | |||
| 36 | 4 | 11 | $VERSION = 0.03; | |||
| 37 | 4 | 46 | @ISA = qw(Exporter); | |||
| 38 | 4 | 3425 | @EXPORT = qw( | |||
| 39 | get_amazon_details | |||||
| 40 | get_amazon_tld | |||||
| 41 | ); | |||||
| 42 | } | |||||
| 43 | ||||||
| 44 | ||||||
| 45 | sub get_amazon_tld { | |||||
| 46 | 0 | my %tld = ( | ||||
| 47 | CA => '.ca', | |||||
| 48 | DE => '.de', | |||||
| 49 | FR => '.fr', | |||||
| 50 | JP => '.jp', | |||||
| 51 | UK => '.co.uk', | |||||
| 52 | US => '.com', | |||||
| 53 | ); | |||||
| 54 | ||||||
| 55 | 0 | my $locale = C4::Context->preference('AmazonLocale'); | ||||
| 56 | 0 | my $tld = $tld{ $locale } || '.com'; # default top level domain is .com | ||||
| 57 | 0 | return $tld; | ||||
| 58 | } | |||||
| 59 | ||||||
| 60 | ||||||
| 61 - 107 | =head1 NAME C4::External::Amazon - Functions for retrieving Amazon.com content in Koha =head2 FUNCTIONS This module provides facilities for retrieving Amazon.com content in Koha =over =item get_amazon_detail( $isbn, $record, $marcflavour, $services ) Get editorial reviews, customer reviews, and similar products using Amazon Web Services. Parameters: =over =item $isbn Biblio record isbn =item $record Biblio MARC record =item $marcflavour MARC flavor, MARC21 or UNIMARC =item $services Requested Amazon services: A ref to an array. For example, [ 'Similarities', 'EditorialReviews', 'Reviews' ]. No other service will be accepted. Services must be spelled exactly. If no sercice is requested, AWS isn't called. =back =item get_amazon_tld() Get Amazon Top Level Domain depending on Amazon local preference: AmazonLocal. For example, if AmazonLocal is 'UK', returns '.co.uk'. =back =cut | |||||
| 108 | ||||||
| 109 | ||||||
| 110 | sub get_amazon_details { | |||||
| 111 | 0 | my ( $isbn, $record, $marcflavour, $aws_ref ) = @_; | ||||
| 112 | ||||||
| 113 | 0 | return unless defined $aws_ref; | ||||
| 114 | 0 | my @aws = @$aws_ref; | ||||
| 115 | 0 | return if $#aws == -1; | ||||
| 116 | ||||||
| 117 | # Normalize the fields | |||||
| 118 | 0 | $isbn = GetNormalizedISBN($isbn); | ||||
| 119 | 0 | my $upc = GetNormalizedUPC($record,$marcflavour); | ||||
| 120 | 0 | my $ean = GetNormalizedEAN($record,$marcflavour); | ||||
| 121 | # warn "ISBN: $isbn | UPC: $upc | EAN: $ean"; | |||||
| 122 | ||||||
| 123 | # Choose the appropriate and available item identifier | |||||
| 124 | 0 | my ( $id_type, $item_id ) = | ||||
| 125 | defined($isbn) && length($isbn) == 13 ? ( 'EAN', $isbn ) : | |||||
| 126 | $isbn ? ( 'ASIN', $isbn ) : | |||||
| 127 | $upc ? ( 'UPC', $upc ) : | |||||
| 128 | $ean ? ( 'EAN', $upc ) : ( undef, undef ); | |||||
| 129 | 0 | return unless defined($id_type); | ||||
| 130 | ||||||
| 131 | # grab the item format to determine Amazon search index | |||||
| 132 | 0 | my %hformat = ( a => 'Books', g => 'Video', j => 'Music' ); | ||||
| 133 | 0 | my $search_index = $hformat{ substr($record->leader(),6,1) } || 'Books'; | ||||
| 134 | ||||||
| 135 | 0 | my $parameters={Service=>"AWSECommerceService" , | ||||
| 136 | "AWSAccessKeyId"=> C4::Context->preference('AWSAccessKeyID') , | |||||
| 137 | "Operation"=>"ItemLookup", | |||||
| 138 | "AssociateTag"=> C4::Context->preference('AmazonAssocTag') , | |||||
| 139 | "Version"=>"2009-06-01", | |||||
| 140 | "ItemId"=>$item_id, | |||||
| 141 | "IdType"=>$id_type, | |||||
| 142 | "ResponseGroup"=> join( ',', @aws ), | |||||
| 143 | "Timestamp"=>strftime("%Y-%m-%dT%H:%M:%SZ", gmtime) | |||||
| 144 | }; | |||||
| 145 | 0 | $$parameters{"SearchIndex"} = $search_index if $id_type ne 'ASIN'; | ||||
| 146 | 0 | my @params; | ||||
| 147 | 0 | while (my ($key,$value)=each %$parameters){ | ||||
| 148 | 0 | push @params, qq{$key=}.uri_escape($value, "^A-Za-z0-9\-_.~" ); | ||||
| 149 | } | |||||
| 150 | ||||||
| 151 | 0 | my $url; | ||||
| 152 | 0 | if (C4::Context->preference('AWSPrivateKey')) { | ||||
| 153 | 0 | $url = qq{http://webservices.amazon} . get_amazon_tld() . | ||||
| 154 | "/onca/xml?" . join("&",sort @params) . qq{&Signature=} . uri_escape(SignRequest(@params),"^A-Za-z0-9\-_.~" ); | |||||
| 155 | } else { | |||||
| 156 | 0 | $url = qq{http://webservices.amazon} . get_amazon_tld() . "/onca/xml?" .join("&",sort @params); | ||||
| 157 | 0 | warn "MUST set AWSPrivateKey syspref after 2009-08-15 in order to access Amazon web services"; | ||||
| 158 | } | |||||
| 159 | ||||||
| 160 | 0 | my $content = get($url); | ||||
| 161 | 0 | warn "could not retrieve $url" unless $content; | ||||
| 162 | 0 | my $xmlsimple = XML::Simple->new(); | ||||
| 163 | 0 | my $response = $xmlsimple->XMLin( | ||||
| 164 | $content, | |||||
| 165 | forcearray => [ qw(SimilarProduct EditorialReview Review Item) ], | |||||
| 166 | ) unless !$content; | |||||
| 167 | 0 | return $response; | ||||
| 168 | } | |||||
| 169 | ||||||
| 170 | sub SignRequest{ | |||||
| 171 | 0 | my @params=@_; | ||||
| 172 | 0 | my $tld=get_amazon_tld(); | ||||
| 173 | 0 | my $string = qq{GET\nwebservices.amazon$tld\n/onca/xml\n} . join("&",sort @params); | ||||
| 174 | 0 | return hmac_sha256_base64($string,C4::Context->preference('AWSPrivateKey')) . '='; | ||||
| 175 | } | |||||
| 176 | ||||||
| 177 | sub check_search_inside { | |||||
| 178 | 0 | my $isbn = shift; | ||||
| 179 | 0 | my $ua = LWP::UserAgent->new( | ||||
| 180 | agent => "Mozilla/4.76 [en] (Win98; U)", | |||||
| 181 | keep_alive => 1, | |||||
| 182 | env_proxy => 1, | |||||
| 183 | ); | |||||
| 184 | 0 | my $available = 1; | ||||
| 185 | 0 | my $uri = "http://www.amazon.com/gp/reader/$isbn/ref=sib_dp_pt/002-7879865-0184864#reader-link"; | ||||
| 186 | 0 | my $req = HTTP::Request->new(GET => $uri); | ||||
| 187 | 0 | $req->header ( | ||||
| 188 | 'Accept' => 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*', | |||||
| 189 | 'Accept-Charset' => 'iso-8859-1,*,utf-8', | |||||
| 190 | 'Accept-Language' => 'en-US' ); | |||||
| 191 | 0 | my $res = $ua->request($req); | ||||
| 192 | 0 | my $content = $res->content(); | ||||
| 193 | 0 | if ($content =~ m/This book is temporarily unavailable/) { | ||||
| 194 | 0 | undef $available; | ||||
| 195 | } | |||||
| 196 | 0 | return $available; | ||||
| 197 | } | |||||
| 198 | ||||||
| 199 | 1; | |||||