Update others/amazon.py to latest version and add the new region support to

plugins/Amazon.py (supybot.plugins.Amazon.region)
This commit is contained in:
James Vega 2004-09-25 16:59:23 +00:00
parent b70a683df1
commit b9db0330e4
2 changed files with 423 additions and 327 deletions

View File

@ -1,301 +1,364 @@
"""Python wrapper """Python wrapper
for Amazon web APIs for Amazon web APIs
This module allows you to access Amazon's web APIs, This module allows you to access Amazon's web APIs,
to do things like search Amazon and get the results programmatically. to do things like search Amazon and get the results programmatically.
Described here: Described here:
http://www.amazon.com/webservices http://www.amazon.com/webservices
You need a Amazon-provided license key to use these services. You need a Amazon-provided license key to use these services.
Follow the link above to get one. These functions will look in Follow the link above to get one. These functions will look in
several places (in this order) for the license key: several places (in this order) for the license key:
- the "license_key" argument of each function - the "license_key" argument of each function
- the module-level LICENSE_KEY variable (call setLicense once to set it) - the module-level LICENSE_KEY variable (call setLicense once to set it)
- an environment variable called AMAZON_LICENSE_KEY - an environment variable called AMAZON_LICENSE_KEY
- a file called ".amazonkey" in the current directory - a file called ".amazonkey" in the current directory
- a file called "amazonkey.txt" in the current directory - a file called "amazonkey.txt" in the current directory
- a file called ".amazonkey" in your home directory - a file called ".amazonkey" in your home directory
- a file called "amazonkey.txt" in your home directory - a file called "amazonkey.txt" in your home directory
- a file called ".amazonkey" in the same directory as amazon.py - a file called ".amazonkey" in the same directory as amazon.py
- a file called "amazonkey.txt" in the same directory as amazon.py - a file called "amazonkey.txt" in the same directory as amazon.py
Sample usage: Sample usage:
>>> import amazon >>> import amazon
>>> amazon.setLicense('...') # must get your own key! >>> amazon.setLicense('...') # must get your own key!
>>> pythonBooks = amazon.searchByKeyword('Python') >>> pythonBooks = amazon.searchByKeyword('Python')
>>> pythonBooks[0].ProductName >>> pythonBooks[0].ProductName
u'Learning Python (Help for Programmers)' u'Learning Python (Help for Programmers)'
>>> pythonBooks[0].URL >>> pythonBooks[0].URL
... ...
>>> pythonBooks[0].OurPrice >>> pythonBooks[0].OurPrice
... ...
Other available functions: Other available functions:
- browseBestSellers - browseBestSellers
- searchByASIN - searchByASIN
- searchByUPC - searchByUPC
- searchByAuthor - searchByAuthor
- searchByArtist - searchByArtist
- searchByActor - searchByActor
- searchByDirector - searchByDirector
- searchByManufacturer - searchByManufacturer
- searchByListMania - searchByListMania
- searchSimilar - searchSimilar
- searchByWishlist - searchByWishlist
Other usage notes: Other usage notes:
- Most functions can take product_line as well, see source for possible values - Most functions can take product_line as well, see source for possible values
- All functions can take type="lite" to get less detail in results - All functions can take type="lite" to get less detail in results
- All functions can take page=N to get second, third, fourth page of results - All functions can take page=N to get second, third, fourth page of results
- All functions can take license_key="XYZ", instead of setting it globally - All functions can take license_key="XYZ", instead of setting it globally
- All functions can take http_proxy="http://x/y/z" which overrides your system setting - All functions can take http_proxy="http://x/y/z" which overrides your system setting
""" """
__author__ = "Mark Pilgrim (f8dy@diveintomark.org)" __author__ = "Mark Pilgrim (f8dy@diveintomark.org)"
__version__ = "0.61" __version__ = "0.64.1"
__cvsversion__ = "$Revision$"[11:-2] __cvsversion__ = "$Revision$"[11:-2]
__date__ = "$Date$"[7:-2] __date__ = "$Date$"[7:-2]
__copyright__ = "Copyright (c) 2002 Mark Pilgrim" __copyright__ = "Copyright (c) 2002 Mark Pilgrim"
__license__ = "Python" __license__ = "Python"
# Powersearch and return object type fix by Joseph Reagle <geek@goatee.net> # Powersearch and return object type fix by Joseph Reagle <geek@goatee.net>
from xml.dom import minidom # Locale support by Michael Josephson <mike@josephson.org>
import os, sys, getopt, cgi, urllib
try: # Modification to _contentsOf to strip trailing whitespace when loading Amazon key
import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py # from a file submitted by Patrick Phalen.
timeoutsocket.setDefaultSocketTimeout(10)
except ImportError: # Support for specifying locale and associates ID as search parameters and
pass # internationalisation fix for the SalesRank integer conversion by
# Christian Theune <ct@gocept.com>, gocept gmbh & co. kg
LICENSE_KEY = None
HTTP_PROXY = None # Support for BlendedSearch contributed by Alex Choo
# don't touch the rest of these constants from xml.dom import minidom
class AmazonError(Exception): pass import os, sys, getopt, cgi, urllib, string
class NoLicenseKey(Exception): pass try:
_amazonfile1 = ".amazonkey" import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py
_amazonfile2 = "amazonkey.txt" timeoutsocket.setDefaultSocketTimeout(10)
_licenseLocations = ( except ImportError:
(lambda key: key, 'passed to the function in license_key variable'), pass
(lambda key: LICENSE_KEY, 'module-level LICENSE_KEY variable (call setLicense to set it)'),
(lambda key: os.environ.get('AMAZON_LICENSE_KEY', None), 'an environment variable called AMAZON_LICENSE_KEY'), LICENSE_KEY = None
(lambda key: _contentsOf(os.getcwd(), _amazonfile1), '%s in the current directory' % _amazonfile1), ASSOCIATE = "webservices-20"
(lambda key: _contentsOf(os.getcwd(), _amazonfile2), '%s in the current directory' % _amazonfile2), HTTP_PROXY = None
(lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile1), '%s in your home directory' % _amazonfile1), LOCALE = "us"
(lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile2), '%s in your home directory' % _amazonfile2),
(lambda key: _contentsOf(_getScriptDir(), _amazonfile1), '%s in the amazon.py directory' % _amazonfile1), # don't touch the rest of these constants
(lambda key: _contentsOf(_getScriptDir(), _amazonfile2), '%s in the amazon.py directory' % _amazonfile2) class AmazonError(Exception): pass
) class NoLicenseKey(Exception): pass
_amazonfile1 = ".amazonkey"
## administrative functions _amazonfile2 = "amazonkey.txt"
def version(): _licenseLocations = (
print """PyAmazon %(__version__)s (lambda key: key, 'passed to the function in license_key variable'),
%(__copyright__)s (lambda key: LICENSE_KEY, 'module-level LICENSE_KEY variable (call setLicense to set it)'),
released %(__date__)s (lambda key: os.environ.get('AMAZON_LICENSE_KEY', None), 'an environment variable called AMAZON_LICENSE_KEY'),
""" % globals() (lambda key: _contentsOf(os.getcwd(), _amazonfile1), '%s in the current directory' % _amazonfile1),
(lambda key: _contentsOf(os.getcwd(), _amazonfile2), '%s in the current directory' % _amazonfile2),
## utility functions (lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile1), '%s in your home directory' % _amazonfile1),
def setLicense(license_key): (lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile2), '%s in your home directory' % _amazonfile2),
"""set license key""" (lambda key: _contentsOf(_getScriptDir(), _amazonfile1), '%s in the amazon.py directory' % _amazonfile1),
global LICENSE_KEY (lambda key: _contentsOf(_getScriptDir(), _amazonfile2), '%s in the amazon.py directory' % _amazonfile2)
LICENSE_KEY = license_key )
_supportedLocales = {
def getLicense(license_key = None): "us" : (None, "xml.amazon.com"),
"""get license key "uk" : ("uk", "xml-eu.amazon.com"),
"de" : ("de", "xml-eu.amazon.com"),
license key can come from any number of locations; "jp" : ("jp", "xml.amazon.co.jp")
see module docs for search order""" }
for get, location in _licenseLocations:
rc = get(license_key) ## administrative functions
if rc: return rc def version():
raise NoLicenseKey, 'get a license key at http://www.amazon.com/webservices' print """PyAmazon %(__version__)s
%(__copyright__)s
def setProxy(http_proxy): released %(__date__)s
"""set HTTP proxy""" """ % globals()
global HTTP_PROXY
HTTP_PROXY = http_proxy def setAssociate(associate):
global ASSOCIATE
def getProxy(http_proxy = None): ASSOCIATE=associate
"""get HTTP proxy"""
return http_proxy or HTTP_PROXY def getAssociate(override=None):
return override or ASSOCIATE
def getProxies(http_proxy = None):
http_proxy = getProxy(http_proxy) ## utility functions
if http_proxy:
proxies = {"http": http_proxy} def _checkLocaleSupported(locale):
else: if not _supportedLocales.has_key(locale):
proxies = None raise AmazonError, ("Unsupported locale. Locale must be one of: %s" %
return proxies string.join(_supportedLocales, ", "))
def _contentsOf(dirname, filename): def setLocale(locale):
filename = os.path.join(dirname, filename) """set locale"""
if not os.path.exists(filename): return None global LOCALE
fsock = open(filename) _checkLocaleSupported(locale)
contents = fsock.read() LOCALE = locale
fsock.close()
return contents def getLocale(locale=None):
"""get locale"""
def _getScriptDir(): return locale or LOCALE
if __name__ == '__main__':
return os.path.abspath(os.path.dirname(sys.argv[0])) def setLicense(license_key):
else: """set license key"""
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__)) global LICENSE_KEY
LICENSE_KEY = license_key
class Bag: pass
def getLicense(license_key = None):
def unmarshal(element): """get license key
rc = Bag()
if isinstance(element, minidom.Element) and (element.tagName == 'Details'): license key can come from any number of locations;
rc.URL = element.attributes["url"].value see module docs for search order"""
childElements = [e for e in element.childNodes if isinstance(e, minidom.Element)] for get, location in _licenseLocations:
if childElements: rc = get(license_key)
for child in childElements: if rc: return rc
key = child.tagName raise NoLicenseKey, 'get a license key at http://www.amazon.com/webservices'
if hasattr(rc, key):
if type(getattr(rc, key)) <> type([]): def setProxy(http_proxy):
setattr(rc, key, [getattr(rc, key)]) """set HTTP proxy"""
setattr(rc, key, getattr(rc, key) + [unmarshal(child)]) global HTTP_PROXY
elif isinstance(child, minidom.Element) and (child.tagName == 'Details'): HTTP_PROXY = http_proxy
# make the first Details element a key
setattr(rc,key,[unmarshal(child)]) def getProxy(http_proxy = None):
#dbg: because otherwise 'hasattr' only tests """get HTTP proxy"""
#dbg: on the second occurence: if there's a return http_proxy or HTTP_PROXY
#dbg: single return to a query, it's not a
#dbg: list. This module should always def getProxies(http_proxy = None):
#dbg: return a list of Details objects. http_proxy = getProxy(http_proxy)
else: if http_proxy:
setattr(rc, key, unmarshal(child)) proxies = {"http": http_proxy}
else: else:
rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)]) proxies = None
if element.tagName == 'SalesRank': return proxies
rc = int(rc.replace(',', ''))
return rc def _contentsOf(dirname, filename):
filename = os.path.join(dirname, filename)
def buildURL(search_type, keyword, product_line, type, page, license_key): if not os.path.exists(filename): return None
url = "http://xml.amazon.com/onca/xml3?v=2.0&f=xml&t=webservices-20" fsock = open(filename)
url += "&dev-t=%s" % license_key.strip() contents = fsock.read().strip()
url += "&type=%s" % type fsock.close()
if page: return contents
url += "&page=%s" % page
if product_line: def _getScriptDir():
url += "&mode=%s" % product_line if __name__ == '__main__':
url += "&%s=%s" % (search_type, urllib.quote(keyword)) return os.path.abspath(os.path.dirname(sys.argv[0]))
return url else:
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
## main functions class Bag: pass
def unmarshal(element):
def search(search_type, keyword, product_line, type="heavy", page=None, rc = Bag()
license_key = None, http_proxy = None): if isinstance(element, minidom.Element) and (element.tagName == 'Details'):
"""search Amazon rc.URL = element.attributes["url"].value
childElements = [e for e in element.childNodes if isinstance(e, minidom.Element)]
You need a license key to call this function; see if childElements:
http://www.amazon.com/webservices for child in childElements:
to get one. Then you can either pass it to key = child.tagName
this function every time, or set it globally; see the module docs for details. if hasattr(rc, key):
if type(getattr(rc, key)) <> type([]):
Parameters: setattr(rc, key, [getattr(rc, key)])
keyword - keyword to search setattr(rc, key, getattr(rc, key) + [unmarshal(child)])
search_type - in (KeywordSearch, BrowseNodeSearch, AsinSearch, UpcSearch, AuthorSearch, ArtistSearch, ActorSearch, DirectorSearch, ManufacturerSearch, ListManiaSearch, SimilaritySearch) elif isinstance(child, minidom.Element) and (child.tagName == 'Details'):
product_line - type of product to search for. restrictions based on search_type # make the first Details element a key
UpcSearch - in (music, classical) setattr(rc,key,[unmarshal(child)])
AuthorSearch - must be "books" #dbg: because otherwise 'hasattr' only tests
ArtistSearch - in (music, classical) #dbg: on the second occurence: if there's a
ActorSearch - in (dvd, vhs, video) #dbg: single return to a query, it's not a
DirectorSearch - in (dvd, vhs, video) #dbg: list. This module should always
ManufacturerSearch - in (electronics, kitchen, videogames, software, photo, pc-hardware) #dbg: return a list of Details objects.
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages else:
setattr(rc, key, unmarshal(child))
Returns: list of Bags, each Bag may contain the following attributes: else:
Asin - Amazon ID ("ASIN" number) of this item rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)])
Authors - list of authors if element.tagName == 'SalesRank':
Availability - "available", etc. rc = rc.replace('.', '')
BrowseList - list of related categories rc = rc.replace(',', '')
Catalog - catalog type ("Book", etc) rc = int(rc)
CollectiblePrice - ?, format "$34.95" return rc
ImageUrlLarge - URL of large image of this item
ImageUrlMedium - URL of medium image of this item def buildURL(search_type, keyword, product_line, type, page, license_key, locale, associate):
ImageUrlSmall - URL of small image of this item _checkLocaleSupported(locale)
Isbn - ISBN number url = "http://" + _supportedLocales[locale][1] + "/onca/xml3?f=xml"
ListPrice - list price, format "$34.95" url += "&t=%s" % associate
Lists - list of ListMania lists that include this item url += "&dev-t=%s" % license_key.strip()
Manufacturer - manufacturer url += "&type=%s" % type
Media - media ("Paperback", "Audio CD", etc) if _supportedLocales[locale][0]:
NumMedia - number of different media types in which this item is available url += "&locale=%s" % _supportedLocales[locale][0]
OurPrice - Amazon price, format "$24.47" if page:
ProductName - name of this item url += "&page=%s" % page
ReleaseDate - release date, format "09 April, 1999" if product_line:
Reviews - reviews (AvgCustomerRating, plus list of CustomerReview with Rating, Summary, Content) url += "&mode=%s" % product_line
SalesRank - sales rank (integer) url += "&%s=%s" % (search_type, urllib.quote(keyword))
SimilarProducts - list of Product, which is ASIN number return url
ThirdPartyNewPrice - ?, format "$34.95"
URL - URL of this item
""" ## main functions
license_key = getLicense(license_key)
url = buildURL(search_type, keyword, product_line, type, page, license_key)
proxies = getProxies(http_proxy) def search(search_type, keyword, product_line, type = "heavy", page = None,
u = urllib.FancyURLopener(proxies) license_key=None, http_proxy = None, locale = None, associate = None):
usock = u.open(url) """search Amazon
xmldoc = minidom.parse(usock)
You need a license key to call this function; see
# from xml.dom.ext import PrettyPrint http://www.amazon.com/webservices
# PrettyPrint(xmldoc) to get one. Then you can either pass it to
this function every time, or set it globally; see the module docs for details.
usock.close()
data = unmarshal(xmldoc).ProductInfo Parameters:
if hasattr(data, 'ErrorMsg'): keyword - keyword to search
raise AmazonError, data.ErrorMsg search_type - in (KeywordSearch, BrowseNodeSearch, AsinSearch, UpcSearch, AuthorSearch, ArtistSearch, ActorSearch, DirectorSearch, ManufacturerSearch, ListManiaSearch, SimilaritySearch)
else: product_line - type of product to search for. restrictions based on search_type
return data.Details UpcSearch - in (music, classical)
AuthorSearch - must be "books"
def searchByKeyword(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None): ArtistSearch - in (music, classical)
return search("KeywordSearch", keyword, product_line, type, page, license_key, http_proxy) ActorSearch - in (dvd, vhs, video)
DirectorSearch - in (dvd, vhs, video)
def browseBestSellers(browse_node, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None): ManufacturerSearch - in (electronics, kitchen, videogames, software, photo, pc-hardware)
return search("BrowseNodeSearch", browse_node, product_line, type, page, license_key, http_proxy) http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
def searchByASIN(ASIN, type="heavy", license_key=None, http_proxy=None): Returns: list of Bags, each Bag may contain the following attributes:
return search("AsinSearch", ASIN, None, type, None, license_key, http_proxy) Asin - Amazon ID ("ASIN" number) of this item
Authors - list of authors
def searchByUPC(UPC, type="heavy", license_key=None, http_proxy=None): Availability - "available", etc.
return search("UpcSearch", UPC, None, type, None, license_key, http_proxy) BrowseList - list of related categories
Catalog - catalog type ("Book", etc)
def searchByAuthor(author, type="heavy", page=1, license_key=None, http_proxy=None): CollectiblePrice - ?, format "$34.95"
return search("AuthorSearch", author, "books", type, page, license_key, http_proxy) ImageUrlLarge - URL of large image of this item
ImageUrlMedium - URL of medium image of this item
def searchByArtist(artist, product_line="music", type="heavy", page=1, license_key=None, http_proxy=None): ImageUrlSmall - URL of small image of this item
if product_line not in ("music", "classical"): Isbn - ISBN number
raise AmazonError, "product_line must be in ('music', 'classical')" ListPrice - list price, format "$34.95"
return search("ArtistSearch", artist, product_line, type, page, license_key, http_proxy) Lists - list of ListMania lists that include this item
Manufacturer - manufacturer
def searchByActor(actor, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None): Media - media ("Paperback", "Audio CD", etc)
if product_line not in ("dvd", "vhs", "video"): NumMedia - number of different media types in which this item is available
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')" OurPrice - Amazon price, format "$24.47"
return search("ActorSearch", actor, product_line, type, page, license_key, http_proxy) ProductName - name of this item
ReleaseDate - release date, format "09 April, 1999"
def searchByDirector(director, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None): Reviews - reviews (AvgCustomerRating, plus list of CustomerReview with Rating, Summary, Content)
if product_line not in ("dvd", "vhs", "video"): SalesRank - sales rank (integer)
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')" SimilarProducts - list of Product, which is ASIN number
return search("DirectorSearch", director, product_line, type, page, license_key, http_proxy) ThirdPartyNewPrice - ?, format "$34.95"
URL - URL of this item
def searchByManufacturer(manufacturer, product_line="pc-hardware", type="heavy", page=1, license_key=None, http_proxy=None): """
if product_line not in ("electronics", "kitchen", "videogames", "software", "photo", "pc-hardware"): license_key = getLicense(license_key)
raise AmazonError, "product_line must be in ('electronics', 'kitchen', 'videogames', 'software', 'photo', 'pc-hardware')" locale = getLocale(locale)
return search("ManufacturerSearch", manufacturer, product_line, type, page, license_key, http_proxy) associate = getAssociate(associate)
url = buildURL(search_type, keyword, product_line, type, page,
def searchByListMania(listManiaID, type="heavy", page=1, license_key=None, http_proxy=None): license_key, locale, associate)
return search("ListManiaSearch", listManiaID, None, type, page, license_key, http_proxy) proxies = getProxies(http_proxy)
u = urllib.FancyURLopener(proxies)
def searchSimilar(ASIN, type="heavy", page=1, license_key=None, http_proxy=None): usock = u.open(url)
return search("SimilaritySearch", ASIN, None, type, page, license_key, http_proxy) xmldoc = minidom.parse(usock)
def searchByWishlist(wishlistID, type="heavy", page=1, license_key=None, http_proxy=None): # from xml.dom.ext import PrettyPrint
return search("WishlistSearch", wishlistID, None, type, page, license_key, http_proxy) # PrettyPrint(xmldoc)
def searchByPower(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None): usock.close()
return search("PowerSearch", keyword, product_line, type, page, license_key, http_proxy) if search_type == "BlendedSearch":
# >>> RecentKing = amazon.searchByPower('author:Stephen King and pubdate:2003') data = unmarshal(xmldoc).BlendedSearch
# >>> SnowCrash = amazon.searchByPower('title:Snow Crash') else:
data = unmarshal(xmldoc).ProductInfo
if hasattr(data, 'ErrorMsg'):
raise AmazonError, data.ErrorMsg
else:
if search_type == "BlendedSearch":
# a list of ProductLine containing a list of ProductInfo
# containing a list of Details.
return data
else:
return data.Details
def searchByKeyword(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
return search("KeywordSearch", keyword, product_line, type, page, license_key, http_proxy, locale, associate)
def browseBestSellers(browse_node, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
return search("BrowseNodeSearch", browse_node, product_line, type, page, license_key, http_proxy, locale, associate)
def searchByASIN(ASIN, type="heavy", license_key=None, http_proxy=None, locale=None, associate=None):
return search("AsinSearch", ASIN, None, type, None, license_key, http_proxy, locale, associate)
def searchByUPC(UPC, type="heavy", license_key=None, http_proxy=None, locale=None, associate=None):
return search("UpcSearch", UPC, None, type, None, license_key, http_proxy, locale, associate)
def searchByAuthor(author, type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
return search("AuthorSearch", author, "books", type, page, license_key, http_proxy, locale, associate)
def searchByArtist(artist, product_line="music", type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
if product_line not in ("music", "classical"):
raise AmazonError, "product_line must be in ('music', 'classical')"
return search("ArtistSearch", artist, product_line, type, page, license_key, http_proxy, locale, associate)
def searchByActor(actor, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
if product_line not in ("dvd", "vhs", "video"):
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')"
return search("ActorSearch", actor, product_line, type, page, license_key, http_proxy, locale, associate)
def searchByDirector(director, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
if product_line not in ("dvd", "vhs", "video"):
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')"
return search("DirectorSearch", director, product_line, type, page, license_key, http_proxy, locale, associate)
def searchByManufacturer(manufacturer, product_line="pc-hardware", type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
if product_line not in ("electronics", "kitchen", "videogames", "software", "photo", "pc-hardware"):
raise AmazonError, "product_line must be in ('electronics', 'kitchen', 'videogames', 'software', 'photo', 'pc-hardware')"
return search("ManufacturerSearch", manufacturer, product_line, type, page, license_key, http_proxy, locale, associate)
def searchByListMania(listManiaID, type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
return search("ListManiaSearch", listManiaID, None, type, page, license_key, http_proxy, locale, associate)
def searchSimilar(ASIN, type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
return search("SimilaritySearch", ASIN, None, type, page, license_key, http_proxy, locale, associate)
def searchByWishlist(wishlistID, type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
return search("WishlistSearch", wishlistID, None, type, page, license_key, http_proxy, locale, associate)
def searchByPower(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
return search("PowerSearch", keyword, product_line, type, page, license_key, http_proxy, locale, associate)
# >>> RecentKing = amazon.searchByPower('author:Stephen King and pubdate:2003')
# >>> SnowCrash = amazon.searchByPower('title:Snow Crash')
def searchByBlended(keyword, type="heavy", page=1, license_key=None, http_proxy=None, locale=None, associate=None):
return search("BlendedSearch", keyword, None, type, page, license_key, http_proxy, locale, associate)

View File

@ -63,6 +63,9 @@ def configure(advanced):
You can apply for a key at You can apply for a key at
http://www.amazon.com/webservices/""") http://www.amazon.com/webservices/""")
class Region(registry.OnlySomeStrings):
validStrings = ('us', 'uk', 'de', 'jp')
class LicenseKey(registry.String): class LicenseKey(registry.String):
def set(self, s): def set(self, s):
# In case we decide we need to recover # In case we decide we need to recover
@ -82,14 +85,20 @@ conf.registerChannelValue(conf.supybot.plugins.Amazon, 'linkSnarfer',
registry.Boolean(False, """Determines whether the bot will reply to registry.Boolean(False, """Determines whether the bot will reply to
Amazon.com URLs in the channel with a description of the item at the Amazon.com URLs in the channel with a description of the item at the
URL.""")) URL."""))
conf.registerChannelValue(conf.supybot.plugins.Amazon, 'region', Region('us',
"""Determines the region that will be used when performing searches."""))
class Amazon(callbacks.PrivmsgCommandAndRegexp): class Amazon(callbacks.PrivmsgCommandAndRegexp):
threaded = True threaded = True
callBefore = ['URL'] callBefore = ['URL']
regexps = ['amzSnarfer'] regexps = ['amzSnarfer']
def __init__(self):
self.__parent = super(Amazon, self)
self.__parent.__init__()
def callCommand(self, name, irc, msg, *L, **kwargs): def callCommand(self, name, irc, msg, *L, **kwargs):
try: try:
super(Amazon, self).callCommand(name, irc, msg, *L, **kwargs) self.__parent.callCommand(name, irc, msg, *L, **kwargs)
except amazon.NoLicenseKey, e: except amazon.NoLicenseKey, e:
irc.error('You must have a free Amazon web services license key ' irc.error('You must have a free Amazon web services license key '
'in order to use this command. You can get one at ' 'in order to use this command. You can get one at '
@ -153,9 +162,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
} }
s = '%(title)s, written by %(author)s; published by ' \ s = '%(title)s, written by %(author)s; published by ' \
'%(publisher)s; price: %(price)s%(url)s' '%(publisher)s; price: %(price)s%(url)s'
chan = msg.args[0]
bold = self.registryValue('bold', chan)
region = self.registryValue('region', chan)
try: try:
book = amazon.searchByKeyword(isbn) book = amazon.searchByKeyword(isbn, locale=region)
bold = self.registryValue('bold', msg.args[0])
res = self._genResults(s, attribs, book, url, bold, 'title') res = self._genResults(s, attribs, book, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -187,9 +198,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
} }
s = '%(title)s, written by %(author)s; published by ' \ s = '%(title)s, written by %(author)s; published by ' \
'%(publisher)s; price: %(price)s%(url)s' '%(publisher)s; price: %(price)s%(url)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
books = amazon.searchByKeyword(keyword) books = amazon.searchByKeyword(keyword, locale=region)
bold = self.registryValue('bold', msg.args[0])
res = self._genResults(s, attribs, books, url, bold, 'title') res = self._genResults(s, attribs, books, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -227,9 +240,12 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
} }
s = '%(title)s (%(media)s), rated %(mpaa)s; released ' \ s = '%(title)s (%(media)s), rated %(mpaa)s; released ' \
'%(date)s; published by %(publisher)s; price: %(price)s%(url)s' '%(date)s; published by %(publisher)s; price: %(price)s%(url)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
videos = amazon.searchByKeyword(keyword, product_line=product) videos = amazon.searchByKeyword(keyword, product_line=product,
bold = self.registryValue('bold', msg.args[0]) locale=region)
res = self._genResults(s, attribs, videos, url, bold, 'title') res = self._genResults(s, attribs, videos, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -259,9 +275,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
'URL' : 'url' 'URL' : 'url'
} }
s = '%(title)s; price: %(price)s%(url)s' s = '%(title)s; price: %(price)s%(url)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
item = amazon.searchByASIN(asin) item = amazon.searchByASIN(asin, locale=region)
bold = self.registryValue('bold', msg.args[0])
res = self._genResults(s, attribs, item, url, bold, 'title') res = self._genResults(s, attribs, item, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -294,9 +312,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
'URL' : 'url' 'URL' : 'url'
} }
s = '%(title)s %(manufacturer)s; price: %(price)s%(url)s' s = '%(title)s %(manufacturer)s; price: %(price)s%(url)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
item = amazon.searchByUPC(upc) item = amazon.searchByUPC(upc, locale=region)
bold = self.registryValue('bold', msg.args[0])
res = self._genResults(s, attribs, item, url, bold, 'title') res = self._genResults(s, attribs, item, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -328,9 +348,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
} }
s = '%(title)s, written by %(author)s; published by ' \ s = '%(title)s, written by %(author)s; published by ' \
'%(publisher)s; price: %(price)s%(url)s' '%(publisher)s; price: %(price)s%(url)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
books = amazon.searchByAuthor(author) books = amazon.searchByAuthor(author, locale=region)
bold = self.registryValue('bold', msg.args[0])
res = self._genResults(s, attribs, books, url, bold, 'title') res = self._genResults(s, attribs, books, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -427,9 +449,12 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
} }
s = '%(title)s (%(media)s), by %(artist)s; published by ' \ s = '%(title)s (%(media)s), by %(artist)s; published by ' \
'%(publisher)s; price: %(price)s%(url)s' '%(publisher)s; price: %(price)s%(url)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
items = amazon.searchByArtist(artist, product_line=product) items = amazon.searchByArtist(artist, product_line=product,
bold = self.registryValue('bold', msg.args[0]) locale=region)
res = self._genResults(s, attribs, items, url, bold, 'title') res = self._genResults(s, attribs, items, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -468,9 +493,12 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
} }
s = '%(title)s (%(media)s), rated %(mpaa)s; released ' \ s = '%(title)s (%(media)s), rated %(mpaa)s; released ' \
'%(date)s; published by %(publisher)s; price: %(price)s%(url)s' '%(date)s; published by %(publisher)s; price: %(price)s%(url)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
items = amazon.searchByActor(actor, product_line=product) items = amazon.searchByActor(actor, product_line=product,
bold = self.registryValue('bold', msg.args[0]) locale=region)
res = self._genResults(s, attribs, items, url, bold, 'title') res = self._genResults(s, attribs, items, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -509,9 +537,12 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
} }
s = '%(title)s (%(media)s), rated %(mpaa)s; released ' \ s = '%(title)s (%(media)s), rated %(mpaa)s; released ' \
'%(date)s; published by %(publisher)s; price: %(price)s%(url)s' '%(date)s; published by %(publisher)s; price: %(price)s%(url)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
items = amazon.searchByDirector(director, product_line=product) items = amazon.searchByDirector(director, product_line=product,
bold = self.registryValue('bold', msg.args[0]) locale=region)
res = self._genResults(s, attribs, items, url, bold, 'title') res = self._genResults(s, attribs, items, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -548,10 +579,13 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
'URL' : 'url' 'URL' : 'url'
} }
s = '%(title)s; price: %(price)s%(url)s' s = '%(title)s; price: %(price)s%(url)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
items = amazon.searchByManufacturer(manufacturer, items = amazon.searchByManufacturer(manufacturer,
product_line=product) product_line=product,
bold = self.registryValue('bold', msg.args[0]) locale=region)
res = self._genResults(s, attribs, items, url, bold, 'title') res = self._genResults(s, attribs, items, url, bold, 'title')
if res: if res:
irc.reply(utils.commaAndify(res)) irc.reply(utils.commaAndify(res))
@ -565,9 +599,6 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
if not self.registryValue('linkSnarfer', msg.args[0]): if not self.registryValue('linkSnarfer', msg.args[0]):
return return
match = match.group(1) match = match.group(1)
# attribs is limited to ProductName since the URL can link to
# *any* type of product. The only attribute we know it will have
# is ProductName
attribs = {'ProductName' : 'title', attribs = {'ProductName' : 'title',
'Manufacturer' : 'publisher', 'Manufacturer' : 'publisher',
'Authors' : 'author', 'Authors' : 'author',
@ -579,9 +610,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp):
} }
s = '%(title)s; %(artist)s; %(author)s; %(mpaa)s; %(media)s; '\ s = '%(title)s; %(artist)s; %(author)s; %(mpaa)s; %(media)s; '\
'%(date)s; %(publisher)s; price: %(price)s' '%(date)s; %(publisher)s; price: %(price)s'
chan = msg.args[0]
region = self.registryValue('region', chan)
bold = self.registryValue('bold', chan)
try: try:
item = amazon.searchByASIN(match) item = amazon.searchByASIN(match, locale=region)
bold = self.registryValue('bold', msg.args[0])
res = self._genResults(s, attribs, item, False, bold, 'title') res = self._genResults(s, attribs, item, False, bold, 'title')
if res: if res:
res = utils.commaAndify(res) res = utils.commaAndify(res)