#!/usr/bin/perl -w
#
# A thin wrapper around Net::Amazon with output templating. Requires
# Net::Amazon and an Amazon Web Services account. Run perldoc(1) on this
# file for additional documentation.
#
# The author disclaims all copyrights and releases this document into
# the public domain.
use strict;
use Net::Amazon ();
use HTML::Entities qw(encode_entities);
my $search_mode;
my $output_template = $ENV{AMAZON_UTIL_TEMPLATE};
my $pages = 1;
use Getopt::Long;
GetOptions(
'mode|m=s' => \$search_mode,
'pages|p=s' => \$pages,
'template|t=s' => \$output_template,
'help|h|?' => \&print_help,
);
print_help() if !@ARGV;
if ( !grep { $_ eq 'mode' } @ARGV and defined $search_mode ) {
push @ARGV, 'mode', $search_mode;
}
if ( !defined $output_template ) {
$output_template = '%{Asin} %{ProductName}';
}
# fix backslashed characters to literal, add newline if no trailing
# whitespace found
$output_template =~ s/(\\.)/qq{"$1"}/eeg;
$output_template .= $/ unless $output_template =~ m/ \s$ /x;
my $AWS_ACCESS_KEY_ID = $ENV{AWS_ACCESS_KEY_ID};
if ( !defined $AWS_ACCESS_KEY_ID ) {
die
"error: set AWS_ACCESS_KEY_ID env variable: https://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key$/";
}
my $ua = Net::Amazon->new(
token => $AWS_ACCESS_KEY_ID,
max_pages => $pages,
strict => 1,
);
my $response;
eval { $response = $ua->search(@ARGV); };
if ($@) {
die "error: invalid search: errstr=$@";
}
if ( !$response->is_success() ) {
die 'error: request failed: errstr=', $response->message(), $/;
}
#binmode( STDOUT, ':utf8' );
for my $item ( $response->properties ) {
# Most folks would use a proper Template module here...
my $output_string = $output_template;
$output_string =~
s/ %{ (\w+) } / $item->can($1) ? encode_entities($item->$1) : '%{'.$1.'}' /egx;
print $output_string;
}
exit 0;
sub print_help {
print <<"HELP";
Usage: $0 [options] Net::Amazon search() arguments as list
Options:
--help, -h, -? Display this message.
--mode=search-mode Optional. "books" or "music" or so forth.
--pages=3 Defaults to 1 page. Add more for more results.
--template='...' Customize the output template.
Run perldoc(1) on this script for additional documentation.
HELP
exit 100;
}
=head1 NAME
amazon-util - thin wrapper around Net::Amazon
=head1 SYNOPSIS
$ export AWS_ACCESS_KEY_ID=...
$ amazon-util --mode=books power 'title: Amazon Hacks'
The AWS_ACCESS_KEY_ID can be obtained from:
https://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key
=head1 DESCRIPTION
=head2 Overview
A thin wrapper around the C<search()> method of L<Net::Amazon>, with
output templating for easy conversion into HTML or other formats.
=head2 Normal Usage
$ export AWS_ACCESS_KEY_ID=...
$ amazon-util [--mode=books] \
[--pages=3] \
[--template=...] \
Net::Amazon search() method arguments as list
See L<"OPTIONS"> for details on the command line switches supported. See
L<Net::Amazon> for more information on the arguments supported by the
C<search> method.
=head1 OPTIONS
This script currently supports the following command line switches:
=over 4
=item B<--help>, B<-h>, B<-?>
Prints a brief usage note about the script.
=item B<--mode>=I<search-mode>
Specify a custom search mode, for example "books" or "music". This
option can also be typed out on the command line:
$ amazon-util power 'title: Amazon Hacks' mode books
Either method ensures the search() method call passes in the required
C<mode => search-mode> argument. C<mode books> takes precedent over the
B<--mode> option, so a shell alias could set a default C<--mode=books>,
and C<mode music> written on the command line to override the default.
=item B<--pages>=I<number-of-pages>
The default search returns one page of results (10 items). Increasing
the pages returns more results. More pages will require more time to
query for.
=item B<--template>=I<output-template>
Custom output template. Defaults to C<%{Asin} %{ProductName}> if not
specified. Also can be set via the C<AMAZON_UTIL_TEMPLATE> environment
variable. This is what I use to ensure links contain my Associate ID:
$ export AMAZON_UTIL_TEMPLATE='<a href="http://www.amazon.com/o/ASIN/%{Asin}/sialorg-20/ref=nosim">%{ProductName}</a>'
$ amazon-util --mode=books power 'title: Amazon Hacks ' <a href="http://www.amazon.com/o/ASIN/0596005423/sialorg-20/ref=nosim">Amazon Hacks: 100 Industrial-Strength Tips & Tools (Hacks)</a>
Basically, any C<%{name}> parameter in the template is, if possible,
replaced with the HTML-escaped output from a method call of C<name>
to the L<Net::Amazon::Property> or subclass module as appropriate
for the item.
=back
=head1 EXAMPLES
On Mac OS X, the C<pbcopy(1)> utility facilitates moving from the
command line to a HTML editor:
$ amazon-util --mode=books power 'title: Amazon Hacks' | pbcopy
Otherwise, consult the L<Net::Amazon> documentation. Any argument used
to the C<search> method can be specified as a list on the command line:
$ua->search(browsenode=>"4025", mode=>"books", keywords=>"perl")
Would become:
$ amazon-util browsenode 4025 mode books keywords perl
Note that this conversion does not support data structure arguments to
C<search>, such as:
$ua->search(asin => ["0201360683", "0596005083"])
Only scalar arguments:
$ua->search(asin => 0201360683)
$ amazon-util asin 0201360683
=head1 BUGS
=head2 Reporting Bugs
If the bug is in the latest version, send a report to the author.
Patches that fix problems or add new features are welcome.
=head2 Known Issues
None at this time. Note, however, the lack of unit tests.
=head1 SEE ALSO
perl(1), L<Net::Amazon>
=head1 AUTHOR
Jeremy Mates, http://sial.org/contact/
=head1 COPYRIGHT
The author disclaims all copyrights and releases this document into the
public domain.
=cut