From b9db0330e4d1ba3986375a20174e44c1b8544633 Mon Sep 17 00:00:00 2001 From: James Vega Date: Sat, 25 Sep 2004 16:59:23 +0000 Subject: [PATCH] Update others/amazon.py to latest version and add the new region support to plugins/Amazon.py (supybot.plugins.Amazon.region) --- others/amazon.py | 665 +++++++++++++++++++++++++--------------------- plugins/Amazon.py | 85 ++++-- 2 files changed, 423 insertions(+), 327 deletions(-) diff --git a/others/amazon.py b/others/amazon.py index 06585844c..207cf2ba4 100644 --- a/others/amazon.py +++ b/others/amazon.py @@ -1,301 +1,364 @@ -"""Python wrapper - - -for Amazon web APIs - -This module allows you to access Amazon's web APIs, -to do things like search Amazon and get the results programmatically. -Described here: - http://www.amazon.com/webservices - -You need a Amazon-provided license key to use these services. -Follow the link above to get one. These functions will look in -several places (in this order) for the license key: -- the "license_key" argument of each function -- the module-level LICENSE_KEY variable (call setLicense once to set it) -- an environment variable called AMAZON_LICENSE_KEY -- a file called ".amazonkey" 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.txt" in your home directory -- a file called ".amazonkey" in the same directory as amazon.py -- a file called "amazonkey.txt" in the same directory as amazon.py - -Sample usage: ->>> import amazon ->>> amazon.setLicense('...') # must get your own key! ->>> pythonBooks = amazon.searchByKeyword('Python') ->>> pythonBooks[0].ProductName -u'Learning Python (Help for Programmers)' ->>> pythonBooks[0].URL -... ->>> pythonBooks[0].OurPrice -... - -Other available functions: -- browseBestSellers -- searchByASIN -- searchByUPC -- searchByAuthor -- searchByArtist -- searchByActor -- searchByDirector -- searchByManufacturer -- searchByListMania -- searchSimilar -- searchByWishlist - -Other usage notes: -- 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 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 http_proxy="http://x/y/z" which overrides your system setting -""" - -__author__ = "Mark Pilgrim (f8dy@diveintomark.org)" -__version__ = "0.61" -__cvsversion__ = "$Revision$"[11:-2] -__date__ = "$Date$"[7:-2] -__copyright__ = "Copyright (c) 2002 Mark Pilgrim" -__license__ = "Python" -# Powersearch and return object type fix by Joseph Reagle - -from xml.dom import minidom -import os, sys, getopt, cgi, urllib -try: - import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py - timeoutsocket.setDefaultSocketTimeout(10) -except ImportError: - pass - -LICENSE_KEY = None -HTTP_PROXY = None - -# don't touch the rest of these constants -class AmazonError(Exception): pass -class NoLicenseKey(Exception): pass -_amazonfile1 = ".amazonkey" -_amazonfile2 = "amazonkey.txt" -_licenseLocations = ( - (lambda key: key, 'passed to the function in license_key variable'), - (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'), - (lambda key: _contentsOf(os.getcwd(), _amazonfile1), '%s in the current directory' % _amazonfile1), - (lambda key: _contentsOf(os.getcwd(), _amazonfile2), '%s in the current directory' % _amazonfile2), - (lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile1), '%s in your home directory' % _amazonfile1), - (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), - (lambda key: _contentsOf(_getScriptDir(), _amazonfile2), '%s in the amazon.py directory' % _amazonfile2) - ) - -## administrative functions -def version(): - print """PyAmazon %(__version__)s -%(__copyright__)s -released %(__date__)s -""" % globals() - -## utility functions -def setLicense(license_key): - """set license key""" - global LICENSE_KEY - LICENSE_KEY = license_key - -def getLicense(license_key = None): - """get license key - - license key can come from any number of locations; - see module docs for search order""" - for get, location in _licenseLocations: - rc = get(license_key) - if rc: return rc - raise NoLicenseKey, 'get a license key at http://www.amazon.com/webservices' - -def setProxy(http_proxy): - """set HTTP proxy""" - global HTTP_PROXY - HTTP_PROXY = http_proxy - -def getProxy(http_proxy = None): - """get HTTP proxy""" - return http_proxy or HTTP_PROXY - -def getProxies(http_proxy = None): - http_proxy = getProxy(http_proxy) - if http_proxy: - proxies = {"http": http_proxy} - else: - proxies = None - return proxies - -def _contentsOf(dirname, filename): - filename = os.path.join(dirname, filename) - if not os.path.exists(filename): return None - fsock = open(filename) - contents = fsock.read() - fsock.close() - return contents - -def _getScriptDir(): - if __name__ == '__main__': - return os.path.abspath(os.path.dirname(sys.argv[0])) - else: - return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__)) - -class Bag: pass - -def unmarshal(element): - rc = Bag() - if isinstance(element, minidom.Element) and (element.tagName == 'Details'): - rc.URL = element.attributes["url"].value - childElements = [e for e in element.childNodes if isinstance(e, minidom.Element)] - if childElements: - for child in childElements: - key = child.tagName - if hasattr(rc, key): - if type(getattr(rc, key)) <> type([]): - setattr(rc, key, [getattr(rc, key)]) - setattr(rc, key, getattr(rc, key) + [unmarshal(child)]) - elif isinstance(child, minidom.Element) and (child.tagName == 'Details'): - # make the first Details element a key - setattr(rc,key,[unmarshal(child)]) - #dbg: because otherwise 'hasattr' only tests - #dbg: on the second occurence: if there's a - #dbg: single return to a query, it's not a - #dbg: list. This module should always - #dbg: return a list of Details objects. - else: - setattr(rc, key, unmarshal(child)) - else: - rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)]) - if element.tagName == 'SalesRank': - rc = int(rc.replace(',', '')) - return rc - -def buildURL(search_type, keyword, product_line, type, page, license_key): - url = "http://xml.amazon.com/onca/xml3?v=2.0&f=xml&t=webservices-20" - url += "&dev-t=%s" % license_key.strip() - url += "&type=%s" % type - if page: - url += "&page=%s" % page - if product_line: - url += "&mode=%s" % product_line - url += "&%s=%s" % (search_type, urllib.quote(keyword)) - return url - - -## main functions - - -def search(search_type, keyword, product_line, type="heavy", page=None, - license_key = None, http_proxy = None): - """search Amazon - - You need a license key to call this function; see - http://www.amazon.com/webservices - to get one. Then you can either pass it to - this function every time, or set it globally; see the module docs for details. - - Parameters: - keyword - keyword to search - search_type - in (KeywordSearch, BrowseNodeSearch, AsinSearch, UpcSearch, AuthorSearch, ArtistSearch, ActorSearch, DirectorSearch, ManufacturerSearch, ListManiaSearch, SimilaritySearch) - product_line - type of product to search for. restrictions based on search_type - UpcSearch - in (music, classical) - AuthorSearch - must be "books" - ArtistSearch - in (music, classical) - ActorSearch - in (dvd, vhs, video) - DirectorSearch - in (dvd, vhs, video) - ManufacturerSearch - in (electronics, kitchen, videogames, software, photo, pc-hardware) - http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages - - Returns: list of Bags, each Bag may contain the following attributes: - Asin - Amazon ID ("ASIN" number) of this item - Authors - list of authors - Availability - "available", etc. - BrowseList - list of related categories - Catalog - catalog type ("Book", etc) - CollectiblePrice - ?, format "$34.95" - ImageUrlLarge - URL of large image of this item - ImageUrlMedium - URL of medium image of this item - ImageUrlSmall - URL of small image of this item - Isbn - ISBN number - ListPrice - list price, format "$34.95" - Lists - list of ListMania lists that include this item - Manufacturer - manufacturer - Media - media ("Paperback", "Audio CD", etc) - NumMedia - number of different media types in which this item is available - OurPrice - Amazon price, format "$24.47" - ProductName - name of this item - ReleaseDate - release date, format "09 April, 1999" - Reviews - reviews (AvgCustomerRating, plus list of CustomerReview with Rating, Summary, Content) - SalesRank - sales rank (integer) - SimilarProducts - list of Product, which is ASIN number - ThirdPartyNewPrice - ?, format "$34.95" - URL - URL of this item - """ - license_key = getLicense(license_key) - url = buildURL(search_type, keyword, product_line, type, page, license_key) - proxies = getProxies(http_proxy) - u = urllib.FancyURLopener(proxies) - usock = u.open(url) - xmldoc = minidom.parse(usock) - -# from xml.dom.ext import PrettyPrint -# PrettyPrint(xmldoc) - - usock.close() - data = unmarshal(xmldoc).ProductInfo - if hasattr(data, 'ErrorMsg'): - raise AmazonError, data.ErrorMsg - else: - return data.Details - -def searchByKeyword(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None): - return search("KeywordSearch", keyword, product_line, type, page, license_key, http_proxy) - -def browseBestSellers(browse_node, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None): - return search("BrowseNodeSearch", browse_node, product_line, type, page, license_key, http_proxy) - -def searchByASIN(ASIN, type="heavy", license_key=None, http_proxy=None): - return search("AsinSearch", ASIN, None, type, None, license_key, http_proxy) - -def searchByUPC(UPC, type="heavy", license_key=None, http_proxy=None): - return search("UpcSearch", UPC, None, type, None, license_key, http_proxy) - -def searchByAuthor(author, type="heavy", page=1, license_key=None, http_proxy=None): - return search("AuthorSearch", author, "books", type, page, license_key, http_proxy) - -def searchByArtist(artist, product_line="music", type="heavy", page=1, license_key=None, http_proxy=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) - -def searchByActor(actor, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=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) - -def searchByDirector(director, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=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) - -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"): - 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) - -def searchByListMania(listManiaID, type="heavy", page=1, license_key=None, http_proxy=None): - return search("ListManiaSearch", listManiaID, None, type, page, license_key, http_proxy) - -def searchSimilar(ASIN, type="heavy", page=1, license_key=None, http_proxy=None): - return search("SimilaritySearch", ASIN, None, type, page, license_key, http_proxy) - -def searchByWishlist(wishlistID, type="heavy", page=1, license_key=None, http_proxy=None): - return search("WishlistSearch", wishlistID, None, type, page, license_key, http_proxy) - -def searchByPower(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None): - return search("PowerSearch", keyword, product_line, type, page, license_key, http_proxy) - # >>> RecentKing = amazon.searchByPower('author:Stephen King and pubdate:2003') - # >>> SnowCrash = amazon.searchByPower('title:Snow Crash') +"""Python wrapper + + +for Amazon web APIs + +This module allows you to access Amazon's web APIs, +to do things like search Amazon and get the results programmatically. +Described here: + http://www.amazon.com/webservices + +You need a Amazon-provided license key to use these services. +Follow the link above to get one. These functions will look in +several places (in this order) for the license key: +- the "license_key" argument of each function +- the module-level LICENSE_KEY variable (call setLicense once to set it) +- an environment variable called AMAZON_LICENSE_KEY +- a file called ".amazonkey" 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.txt" in your home directory +- a file called ".amazonkey" in the same directory as amazon.py +- a file called "amazonkey.txt" in the same directory as amazon.py + +Sample usage: +>>> import amazon +>>> amazon.setLicense('...') # must get your own key! +>>> pythonBooks = amazon.searchByKeyword('Python') +>>> pythonBooks[0].ProductName +u'Learning Python (Help for Programmers)' +>>> pythonBooks[0].URL +... +>>> pythonBooks[0].OurPrice +... + +Other available functions: +- browseBestSellers +- searchByASIN +- searchByUPC +- searchByAuthor +- searchByArtist +- searchByActor +- searchByDirector +- searchByManufacturer +- searchByListMania +- searchSimilar +- searchByWishlist + +Other usage notes: +- 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 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 http_proxy="http://x/y/z" which overrides your system setting +""" + +__author__ = "Mark Pilgrim (f8dy@diveintomark.org)" +__version__ = "0.64.1" +__cvsversion__ = "$Revision$"[11:-2] +__date__ = "$Date$"[7:-2] +__copyright__ = "Copyright (c) 2002 Mark Pilgrim" +__license__ = "Python" +# Powersearch and return object type fix by Joseph Reagle + +# Locale support by Michael Josephson + +# Modification to _contentsOf to strip trailing whitespace when loading Amazon key +# from a file submitted by Patrick Phalen. + +# Support for specifying locale and associates ID as search parameters and +# internationalisation fix for the SalesRank integer conversion by +# Christian Theune , gocept gmbh & co. kg + +# Support for BlendedSearch contributed by Alex Choo + +from xml.dom import minidom +import os, sys, getopt, cgi, urllib, string +try: + import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py + timeoutsocket.setDefaultSocketTimeout(10) +except ImportError: + pass + +LICENSE_KEY = None +ASSOCIATE = "webservices-20" +HTTP_PROXY = None +LOCALE = "us" + +# don't touch the rest of these constants +class AmazonError(Exception): pass +class NoLicenseKey(Exception): pass +_amazonfile1 = ".amazonkey" +_amazonfile2 = "amazonkey.txt" +_licenseLocations = ( + (lambda key: key, 'passed to the function in license_key variable'), + (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'), + (lambda key: _contentsOf(os.getcwd(), _amazonfile1), '%s in the current directory' % _amazonfile1), + (lambda key: _contentsOf(os.getcwd(), _amazonfile2), '%s in the current directory' % _amazonfile2), + (lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile1), '%s in your home directory' % _amazonfile1), + (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), + (lambda key: _contentsOf(_getScriptDir(), _amazonfile2), '%s in the amazon.py directory' % _amazonfile2) + ) +_supportedLocales = { + "us" : (None, "xml.amazon.com"), + "uk" : ("uk", "xml-eu.amazon.com"), + "de" : ("de", "xml-eu.amazon.com"), + "jp" : ("jp", "xml.amazon.co.jp") + } + +## administrative functions +def version(): + print """PyAmazon %(__version__)s +%(__copyright__)s +released %(__date__)s +""" % globals() + +def setAssociate(associate): + global ASSOCIATE + ASSOCIATE=associate + +def getAssociate(override=None): + return override or ASSOCIATE + +## utility functions + +def _checkLocaleSupported(locale): + if not _supportedLocales.has_key(locale): + raise AmazonError, ("Unsupported locale. Locale must be one of: %s" % + string.join(_supportedLocales, ", ")) + +def setLocale(locale): + """set locale""" + global LOCALE + _checkLocaleSupported(locale) + LOCALE = locale + +def getLocale(locale=None): + """get locale""" + return locale or LOCALE + +def setLicense(license_key): + """set license key""" + global LICENSE_KEY + LICENSE_KEY = license_key + +def getLicense(license_key = None): + """get license key + + license key can come from any number of locations; + see module docs for search order""" + for get, location in _licenseLocations: + rc = get(license_key) + if rc: return rc + raise NoLicenseKey, 'get a license key at http://www.amazon.com/webservices' + +def setProxy(http_proxy): + """set HTTP proxy""" + global HTTP_PROXY + HTTP_PROXY = http_proxy + +def getProxy(http_proxy = None): + """get HTTP proxy""" + return http_proxy or HTTP_PROXY + +def getProxies(http_proxy = None): + http_proxy = getProxy(http_proxy) + if http_proxy: + proxies = {"http": http_proxy} + else: + proxies = None + return proxies + +def _contentsOf(dirname, filename): + filename = os.path.join(dirname, filename) + if not os.path.exists(filename): return None + fsock = open(filename) + contents = fsock.read().strip() + fsock.close() + return contents + +def _getScriptDir(): + if __name__ == '__main__': + return os.path.abspath(os.path.dirname(sys.argv[0])) + else: + return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__)) + +class Bag: pass + +def unmarshal(element): + rc = Bag() + if isinstance(element, minidom.Element) and (element.tagName == 'Details'): + rc.URL = element.attributes["url"].value + childElements = [e for e in element.childNodes if isinstance(e, minidom.Element)] + if childElements: + for child in childElements: + key = child.tagName + if hasattr(rc, key): + if type(getattr(rc, key)) <> type([]): + setattr(rc, key, [getattr(rc, key)]) + setattr(rc, key, getattr(rc, key) + [unmarshal(child)]) + elif isinstance(child, minidom.Element) and (child.tagName == 'Details'): + # make the first Details element a key + setattr(rc,key,[unmarshal(child)]) + #dbg: because otherwise 'hasattr' only tests + #dbg: on the second occurence: if there's a + #dbg: single return to a query, it's not a + #dbg: list. This module should always + #dbg: return a list of Details objects. + else: + setattr(rc, key, unmarshal(child)) + else: + rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)]) + if element.tagName == 'SalesRank': + rc = rc.replace('.', '') + rc = rc.replace(',', '') + rc = int(rc) + return rc + +def buildURL(search_type, keyword, product_line, type, page, license_key, locale, associate): + _checkLocaleSupported(locale) + url = "http://" + _supportedLocales[locale][1] + "/onca/xml3?f=xml" + url += "&t=%s" % associate + url += "&dev-t=%s" % license_key.strip() + url += "&type=%s" % type + if _supportedLocales[locale][0]: + url += "&locale=%s" % _supportedLocales[locale][0] + if page: + url += "&page=%s" % page + if product_line: + url += "&mode=%s" % product_line + url += "&%s=%s" % (search_type, urllib.quote(keyword)) + return url + + +## main functions + + +def search(search_type, keyword, product_line, type = "heavy", page = None, + license_key=None, http_proxy = None, locale = None, associate = None): + """search Amazon + + You need a license key to call this function; see + http://www.amazon.com/webservices + to get one. Then you can either pass it to + this function every time, or set it globally; see the module docs for details. + + Parameters: + keyword - keyword to search + search_type - in (KeywordSearch, BrowseNodeSearch, AsinSearch, UpcSearch, AuthorSearch, ArtistSearch, ActorSearch, DirectorSearch, ManufacturerSearch, ListManiaSearch, SimilaritySearch) + product_line - type of product to search for. restrictions based on search_type + UpcSearch - in (music, classical) + AuthorSearch - must be "books" + ArtistSearch - in (music, classical) + ActorSearch - in (dvd, vhs, video) + DirectorSearch - in (dvd, vhs, video) + ManufacturerSearch - in (electronics, kitchen, videogames, software, photo, pc-hardware) + http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages + + Returns: list of Bags, each Bag may contain the following attributes: + Asin - Amazon ID ("ASIN" number) of this item + Authors - list of authors + Availability - "available", etc. + BrowseList - list of related categories + Catalog - catalog type ("Book", etc) + CollectiblePrice - ?, format "$34.95" + ImageUrlLarge - URL of large image of this item + ImageUrlMedium - URL of medium image of this item + ImageUrlSmall - URL of small image of this item + Isbn - ISBN number + ListPrice - list price, format "$34.95" + Lists - list of ListMania lists that include this item + Manufacturer - manufacturer + Media - media ("Paperback", "Audio CD", etc) + NumMedia - number of different media types in which this item is available + OurPrice - Amazon price, format "$24.47" + ProductName - name of this item + ReleaseDate - release date, format "09 April, 1999" + Reviews - reviews (AvgCustomerRating, plus list of CustomerReview with Rating, Summary, Content) + SalesRank - sales rank (integer) + SimilarProducts - list of Product, which is ASIN number + ThirdPartyNewPrice - ?, format "$34.95" + URL - URL of this item + """ + license_key = getLicense(license_key) + locale = getLocale(locale) + associate = getAssociate(associate) + url = buildURL(search_type, keyword, product_line, type, page, + license_key, locale, associate) + proxies = getProxies(http_proxy) + u = urllib.FancyURLopener(proxies) + usock = u.open(url) + xmldoc = minidom.parse(usock) + +# from xml.dom.ext import PrettyPrint +# PrettyPrint(xmldoc) + + usock.close() + if search_type == "BlendedSearch": + data = unmarshal(xmldoc).BlendedSearch + 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) diff --git a/plugins/Amazon.py b/plugins/Amazon.py index f470df1a3..4913eee98 100644 --- a/plugins/Amazon.py +++ b/plugins/Amazon.py @@ -63,6 +63,9 @@ def configure(advanced): You can apply for a key at http://www.amazon.com/webservices/""") +class Region(registry.OnlySomeStrings): + validStrings = ('us', 'uk', 'de', 'jp') + class LicenseKey(registry.String): def set(self, s): # 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 Amazon.com URLs in the channel with a description of the item at the URL.""")) +conf.registerChannelValue(conf.supybot.plugins.Amazon, 'region', Region('us', + """Determines the region that will be used when performing searches.""")) class Amazon(callbacks.PrivmsgCommandAndRegexp): threaded = True callBefore = ['URL'] regexps = ['amzSnarfer'] + def __init__(self): + self.__parent = super(Amazon, self) + self.__parent.__init__() + def callCommand(self, name, irc, msg, *L, **kwargs): try: - super(Amazon, self).callCommand(name, irc, msg, *L, **kwargs) + self.__parent.callCommand(name, irc, msg, *L, **kwargs) except amazon.NoLicenseKey, e: irc.error('You must have a free Amazon web services license key ' '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 ' \ '%(publisher)s; price: %(price)s%(url)s' + chan = msg.args[0] + bold = self.registryValue('bold', chan) + region = self.registryValue('region', chan) try: - book = amazon.searchByKeyword(isbn) - bold = self.registryValue('bold', msg.args[0]) + book = amazon.searchByKeyword(isbn, locale=region) res = self._genResults(s, attribs, book, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -187,9 +198,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): } s = '%(title)s, written by %(author)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: - books = amazon.searchByKeyword(keyword) - bold = self.registryValue('bold', msg.args[0]) + books = amazon.searchByKeyword(keyword, locale=region) res = self._genResults(s, attribs, books, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -227,9 +240,12 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): } s = '%(title)s (%(media)s), rated %(mpaa)s; released ' \ '%(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: - videos = amazon.searchByKeyword(keyword, product_line=product) - bold = self.registryValue('bold', msg.args[0]) + videos = amazon.searchByKeyword(keyword, product_line=product, + locale=region) res = self._genResults(s, attribs, videos, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -259,9 +275,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): 'URL' : 'url' } s = '%(title)s; price: %(price)s%(url)s' + chan = msg.args[0] + region = self.registryValue('region', chan) + bold = self.registryValue('bold', chan) try: - item = amazon.searchByASIN(asin) - bold = self.registryValue('bold', msg.args[0]) + item = amazon.searchByASIN(asin, locale=region) res = self._genResults(s, attribs, item, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -294,9 +312,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): 'URL' : 'url' } 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: - item = amazon.searchByUPC(upc) - bold = self.registryValue('bold', msg.args[0]) + item = amazon.searchByUPC(upc, locale=region) res = self._genResults(s, attribs, item, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -328,9 +348,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): } s = '%(title)s, written by %(author)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: - books = amazon.searchByAuthor(author) - bold = self.registryValue('bold', msg.args[0]) + books = amazon.searchByAuthor(author, locale=region) res = self._genResults(s, attribs, books, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -427,9 +449,12 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): } s = '%(title)s (%(media)s), by %(artist)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: - items = amazon.searchByArtist(artist, product_line=product) - bold = self.registryValue('bold', msg.args[0]) + items = amazon.searchByArtist(artist, product_line=product, + locale=region) res = self._genResults(s, attribs, items, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -468,9 +493,12 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): } s = '%(title)s (%(media)s), rated %(mpaa)s; released ' \ '%(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: - items = amazon.searchByActor(actor, product_line=product) - bold = self.registryValue('bold', msg.args[0]) + items = amazon.searchByActor(actor, product_line=product, + locale=region) res = self._genResults(s, attribs, items, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -509,9 +537,12 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): } s = '%(title)s (%(media)s), rated %(mpaa)s; released ' \ '%(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: - items = amazon.searchByDirector(director, product_line=product) - bold = self.registryValue('bold', msg.args[0]) + items = amazon.searchByDirector(director, product_line=product, + locale=region) res = self._genResults(s, attribs, items, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -548,10 +579,13 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): 'URL' : 'url' } s = '%(title)s; price: %(price)s%(url)s' + chan = msg.args[0] + region = self.registryValue('region', chan) + bold = self.registryValue('bold', chan) try: items = amazon.searchByManufacturer(manufacturer, - product_line=product) - bold = self.registryValue('bold', msg.args[0]) + product_line=product, + locale=region) res = self._genResults(s, attribs, items, url, bold, 'title') if res: irc.reply(utils.commaAndify(res)) @@ -565,9 +599,6 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): if not self.registryValue('linkSnarfer', msg.args[0]): return 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', 'Manufacturer' : 'publisher', 'Authors' : 'author', @@ -579,9 +610,11 @@ class Amazon(callbacks.PrivmsgCommandAndRegexp): } s = '%(title)s; %(artist)s; %(author)s; %(mpaa)s; %(media)s; '\ '%(date)s; %(publisher)s; price: %(price)s' + chan = msg.args[0] + region = self.registryValue('region', chan) + bold = self.registryValue('bold', chan) try: - item = amazon.searchByASIN(match) - bold = self.registryValue('bold', msg.args[0]) + item = amazon.searchByASIN(match, locale=region) res = self._genResults(s, attribs, item, False, bold, 'title') if res: res = utils.commaAndify(res)