Package: quodlibet-plugins Version: 20080329-1 Severity: normal albumart.py no longer works due to Amazon deprecating the old version (3.x) of their API. Attached are a new version of _amazon.py (from http://pyaws.sourceforge.net/) and a slightly modified version of albumart.py to work with the new module.
-- System Information: Debian Release: lenny/sid APT prefers testing APT policy: (600, 'testing'), (500, 'unstable'), (1, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 2.6.24-1-amd64 (SMP w/1 CPU core) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/bash Versions of packages quodlibet-plugins depends on: ii exfalso 1.0-2 audio tag editor for GTK+ quodlibet-plugins recommends no packages. -- no debconf information
#Copyright 2005 Eduardo Gonzalez, Niklas Janlert #Amazon API code by Mark Pilgrim # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation import os import sys import urllib import threading from cStringIO import StringIO import gtk import gobject import pango import util import qltk import config from plugins.songsmenu import SongsMenuPlugin if sys.version_info < (2, 4): from sets import Set as set try: import amazon except ImportError: import _amazon as amazon class AlbumArtWindow(gtk.Window): def __init__(self, songs): gtk.Window.__init__(self) self.set_border_width(12) self.set_title("AlbumArt") self.set_default_size(650, 350) #TreeView stuff self.liststore = liststore = gtk.ListStore(object, str) treeview = gtk.TreeView(liststore) treeview.set_headers_visible(False) selection = treeview.get_selection() selection.set_mode(gtk.SELECTION_SINGLE) selection.connect("changed", self.__preview) rend = gtk.CellRendererPixbuf() def cell_data(column, cell, model, iter): cell.set_property("pixbuf", model[iter][0]["thumb"]) tvcol1 = gtk.TreeViewColumn("Pixbuf", rend) tvcol1.set_cell_data_func(rend, cell_data) tvcol1.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY) rend.set_property('xpad', 2) rend.set_property('ypad', 2) rend.set_property('width', 56) rend.set_property('height', 56) treeview.append_column(tvcol1) rend = gtk.CellRendererText() rend.set_property("ellipsize", pango.ELLIPSIZE_END) tvcol2 = gtk.TreeViewColumn("Info", rend, markup=1) treeview.append_column(tvcol2) sw = gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) sw.set_shadow_type(gtk.SHADOW_IN) sw.add(treeview) #Image frame and save button self.image = image = gtk.Image() frame = gtk.Frame() frame.set_shadow_type(gtk.SHADOW_IN) frame.add(image) vbox = gtk.VBox(spacing=5) vbox.pack_start(frame) self.button = button = gtk.Button(stock=gtk.STOCK_SAVE) button.set_sensitive(False) def save_cb(button, combo): model, path = selection.get_selected() data = model[path][0]["cover_data"] fname = self.__get_fname(songs, combo) self.__save_cover(data, fname) combo = gtk.combo_box_new_text() try: set_fn = config.get("plugins", "cover_fn") except: set_fn = ".folder.jpg" active = -1 for i, fn in enumerate([".folder.jpg", "folder.jpg", "cover.jpg"]): combo.append_text(fn) if fn == set_fn: active = i if active == -1: combo.append_text(set_fn) combo.set_active(len(combo.get_model()) - 1) else: combo.set_active(active) button.connect("clicked", save_cb, combo) bbox = gtk.HButtonBox() bbox.pack_start(combo) bbox.pack_start(button, expand=False, fill=False) bbox.set_layout(gtk.BUTTONBOX_SPREAD) vbox.pack_start(bbox, expand=False, fill=False) hpaned = gtk.HPaned() hpaned.pack1(sw) hpaned.pack2(vbox) hpaned.set_position(300) self.add(hpaned) thread = threading.Thread(target=self.__search, args=(songs,)) thread.setDaemon(True) thread.start() self.show_all() def __search(self, songs): artist = songs[0]('artist') album = songs[0]('album') amazon.setLicenseKey("0RKH4ZH1JCFZHMND91G2") try: query = album + " " + artist query = query.encode("latin1", 'replace') bags = amazon.ItemSearch( query, SearchIndex="Music", ResponseGroup="Medium") except (amazon.AWSException, KeyError), msg: dialog = qltk.Message(gtk.MESSAGE_ERROR, None, "Search error", msg) dialog.connect('response', self.__destroy_cb) gobject.idle_add(dialog.show) except UnicodeEncodeError, msg: dialog = qltk.Message(gtk.MESSAGE_ERROR, None, "Encoding error", msg) dialog.connect('response', self.__destroy_cb) gobject.idle_add(dialog.show) else: # Just keep the top 10 matches i = 0 for bag in bags: i += 1 if i > 10: break gobject.idle_add(self.__add_bag, self.liststore, bag) def __destroy_cb(self, widget, *args): widget.destroy() self.destroy() def __add_bag(self, model, bag): # Text part title = util.escape(getattr(bag, "Title", "")) # print >>sys.stderr, bag.Artist, dir(bag.Artist) artist = getattr(bag, "Artist", "") # if isinstance(artist, list): # artist = ", ".join(artist) artist = util.escape(artist) if hasattr(bag, "ReleaseDate"): date = "(%s)" %util.escape(bag.ReleaseDate) else: date = "" markup = "<i><b>%s</b></i> %s\n%s" %(title, date, artist) item = {"bag": bag, "thumb": None, "thumb_data": ""} iter = model.append([item, markup]) if hasattr(bag, "SmallImage"): # Image part urlinfo = urllib.urlopen(bag.SmallImage.URL) sock = urlinfo.fp._sock sock.setblocking(0) data = StringIO() loader = gtk.gdk.PixbufLoader() loader.connect("closed", self.__got_thumb_cb, data, item, model, iter) gobject.io_add_watch( sock, gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP, self.__copy_image, loader, data) def __got_thumb_cb(self, loader, data, item, model, iter): cover = loader.get_pixbuf() if cover.get_width() > 1: w = h = 48 cover = cover.scale_simple(w, h, gtk.gdk.INTERP_NEAREST) thumb = gtk.gdk.Pixbuf( gtk.gdk.COLORSPACE_RGB, True, 8, w + 2, h + 2) thumb.fill(0x000000ff) cover.copy_area(0, 0, w, h, thumb, 1, 1) item["thumb"] = thumb item["thumb_data"] = data.getvalue() model.row_changed(model.get_path(iter), iter) def __preview(self, selection): model, path = selection.get_selected() item = model[path][0] self.image.hide() self.button.set_sensitive(False) if item["thumb"]: # If there exists no thumbnail, then nothing bigger. if "cover" not in item: self.__get_cover(item, item["bag"].LargeImage.URL) else: self.image.set_from_pixbuf(item["cover"]) self.image.show() self.button.set_sensitive(True) def __get_cover(self, item, url): data = StringIO() urlinfo = urllib.urlopen(url) sock = urlinfo.fp._sock sock.setblocking(0) loader = gtk.gdk.PixbufLoader() gobject.io_add_watch( sock, gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP, self.__copy_image, loader, data) loader.connect("closed", self.__got_cover_cb, data, item, url) def update(loader, x, y, w, h, image): if (w, h) > (1, 1): image.set_from_pixbuf(loader.get_pixbuf()) image.show() loader.connect("area-updated", update, self.image) def __got_cover_cb(self, loader, data, item, url): cover = loader.get_pixbuf() # For some reason we get a 1x1 image if the given size didn't exist if cover.get_width() > 1: item["cover"] = cover item["cover_data"] = data.getvalue() self.image.set_from_pixbuf(item["cover"]) self.button.set_sensitive(True) elif url == item["bag"].LargeImage.URL: self.__get_cover(item, item["bag"].MediumImage.URL) else: item["cover"] = item["thumb"] item["cover_data"] = item["thumb_data"] self.image.set_from_pixbuf(item["cover"]) self.button.set_sensitive(True) def __copy_image(self, src, condition, loader, data): if condition in (gobject.IO_ERR, gobject.IO_HUP): loader.close() src.close() return False else: # Read buf = src.recv(1024) if buf: loader.write(buf) data.write(buf) return True # Run again else: loader.close() src.close() return False def __save_cover(self, data, fname): if os.path.exists(fname) and not qltk.ConfirmAction(None, "File exists", "The file <b>%s</b> already exists." "\n\nOverwrite?" %util.escape(fname)).run(): return f = open(fname, "w") f.write(data) f.close() self.destroy() def __get_fname(self, songs, combo): append = combo.get_model()[(combo.get_active(),)][0] dirname = songs[0]("~dirname") fname = os.path.join(dirname, append) #print "Will save to", fname config.set("plugins", "cover_fn", append) return fname class DownloadAlbumArt(SongsMenuPlugin): PLUGIN_ID = "Download Album art" PLUGIN_NAME = _("Download Album Art") PLUGIN_DESC = "Downloads album covers from Amazon.com" PLUGIN_ICON = gtk.STOCK_FIND PLUGIN_VERSION = "0.25" def PluginPreferences(parent): b = gtk.Button("Visit Amazon.com") b.connect('clicked', lambda s: util.website('http://www.amazon.com/')) return b PluginPreferences = staticmethod(PluginPreferences) plugin_album = AlbumArtWindow
"""Python wrapper for AWS E-Commerce Serive APIs. Based upon pyamazon (http://www.josephson.org/projects/pyamazon/) with efforts to meet the latest AWS specification. The Amazon's web APIs specication is 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 - foo would return the python object, XMLfoo returns the DOM object License: Python Software Foundation License """ import os, urllib, string, inspect from xml.dom import minidom __author__ = "Kun Xi < [EMAIL PROTECTED] >" __version__ = "0.2.0" __license__ = "Python Software Foundation" """Package-wide variables: """ LICENSE_KEY = None; HTTP_PROXY = None LOCALE = "us" VERSION = "2007-02-22" __supportedLocales = { None : "webservices.amazon.com", "us" : "webservices.amazon.com", "uk" : "webservices.amazon.co.uk", "de" : "webservices.amazon.de", "jp" : "webservices.amazon.co.jp", "fr" : "webservices.amazon.fr", "ca" : "webservices.amazon.ca" } __licenseKeys = ( (lambda key: key), (lambda key: LICENSE_KEY), (lambda key: os.environ.get('AWS_LICENSE_KEY', None)) ) class AWSException(Exception) : '''Base class for all AWS exceptions''' pass class NoLicenseKey(AWSException) : pass class BadLocale(AWSException) : pass # Runtime exception class ExactParameterRequirement(AWSException): pass class ExceededMaximumParameterValues(AWSException): pass class InsufficientParameterValues(AWSException): pass class InternalError(AWSException): pass class InvalidEnumeratedParameter(AWSException): pass class InvalidISO8601Time(AWSException): pass class InvalidOperationForMarketplace(AWSException): pass class InvalidOperationParameter(AWSException): pass class InvalidParameterCombination(AWSException): pass class InvalidParameterValue(AWSException): pass class InvalidResponseGroup(AWSException): pass class InvalidServiceParameter(AWSException): pass class InvalidSubscriptionId(AWSException): pass class InvalidXSLTAddress(AWSException): pass class MaximumParameterRequirement(AWSException): pass class MinimumParameterRequirement(AWSException): pass class MissingOperationParameter(AWSException): pass class MissingParameterCombination(AWSException): pass class MissingParameters(AWSException): pass class MissingParameterValueCombination(AWSException): pass class MissingServiceParameter(AWSException): pass class ParameterOutOfRange(AWSException): pass class ParameterRepeatedInRequest(AWSException): pass class RestrictedParameterValueCombination(AWSException): pass class XSLTTransformationError(AWSException): pass class Bag : '''Wrapper class for DOM nodes''' pass # Utilities functions def setLocale(locale): """set locale if unsupported locale is set, BadLocale is raised.""" global LOCALE if not __supportedLocales.has_key(locale): raise BadLocale, ("Unsupported locale. Locale must be one of: %s" % ', '.join([x for x in __supportedLocales.keys() if x])) LOCALE = locale def getLocale(): """get locale""" return LOCALE def setLicenseKey(license_key=None): """set license key license key can come from any number of locations; see module docs for search order. if no license key is specified, BadLocale is raised.""" global LICENSE_KEY for get in __licenseKeys: rc = get(license_key) if rc: LICENSE_KEY = rc; return; raise NoLicenseKey, ("Please get the license key from http://www.amazon.com/webservices") def getLicenseKey(): """get license key if no license key is specified, BadLocale is raised.""" if not LICENSE_KEY: raise NoLicenseKey, ("Please get the license key from http://www.amazon.com/webservices") return LICENSE_KEY def getVersion(): """get version""" return VERSION def buildRequest(argv): """Build the REST request URL from argv, all key, value pairs in argv are quoted.""" url = "http://" + __supportedLocales[getLocale()] + "/onca/xml?Service=AWSECommerceService&" return url + '&'.join(['%s=%s' % (k,urllib.quote(str(v))) for (k,v) in argv.items() if v]) def buildException(els): """Build the exception from the returned DOM node Only the first exception is raised.""" error = els[0] class_name = error.childNodes[0].firstChild.data[4:] msg = error.childNodes[1].firstChild.data e = globals()[ class_name ](msg) return e def query(url): """Send the query url and return the DOM Exception is raised if there is errors""" u = urllib.FancyURLopener(HTTP_PROXY) usock = u.open(url) dom = minidom.parse(usock) usock.close() errors = dom.getElementsByTagName('Error') if errors: e = buildException(errors) raise e return dom def rawObject(XMLSearch, arguments, kwItem, plugins=None): '''Return a unique object''' dom = XMLSearch(** arguments) return unmarshal(dom.getElementsByTagName(kwItem).item(0), plugins) def rawIterator(XMLSearch, arguments, kwItems, plugins=None): '''Return list of objects''' dom = XMLSearch(** arguments) items = unmarshal(dom.getElementsByTagName(kwItems).item(0), plugins, wrappedIterator()) return items class wrappedIterator(list): '''Return inherited list object, we may add more attributes later''' pass class pagedIterator: '''Return a page-based iterator''' def __init__(self, XMLSearch, arguments, kwPage, kwItems, plugins=None): """XMLSearch: the callback function that returns the DOM arguments: the arguments for XMLSearch kwPage, kwItems: Tag name of Page, Items to organize the object plugins: please check unmarshal """ self.__search = XMLSearch self.__arguments = arguments self.__keywords ={'Page':kwPage, 'Items':kwItems} self.__plugins = plugins self.__page = arguments[kwPage] or 1 self.__index = 0 dom = self.__search(** self.__arguments) self.__items = unmarshal(dom.getElementsByTagName(kwItems).item(0), plugins, wrappedIterator()) try: self.__len = int(dom.getElementsByTagName("TotalResults").item(0).firstChild.data) except AttributeError, e: self.__len = len(self.__items) def __len__(self): return self.__len def __iter__(self): return self def next(self): if self.__index < self.__len: self.__index = self.__index + 1 return self.__getitem__(self.__index-1) else: raise StopIteration def __getitem__(self, key): try: num = int(key) except TypeError, e: raise e if num >= self.__len: raise IndexError page = num / 10 + 1 index = num % 10 if page != self.__page: self.__arguments[self.__keywords['Page']] = page dom = self.__search(** self.__arguments) self.__items = unmarshal(dom.getElementsByTagName(self.__keywords['Items']).item(0), self.__plugins, wrappedIterator()) self.__page = page return self.__items[index] def unmarshal(element, plugins=None, rc=None): """Return the Bag object with attributes populated using DOM element element: the root of the DOM element we are interested in plugins: callback functions to fine-tune the object structure rc: parent object, used in the recursive call This core function is inspired by Mark Pilgrim ([EMAIL PROTECTED]) with some enhancement. Each node.tagName is evalued by plugins' callback functions: if plugins['isBypassed'] is true: this elment is ignored if plugins['isPivoted'] is true: this children of this elment is moved to grandparents this object is ignored. if plugins['isCollective'] is true: this elment is mapped to [] if plugins['isCollected'] is true: this children of elment is appended to grandparent this object is ignored. """ if(rc == None): rc = Bag() if(plugins == None): plugins = {} 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, plugins)]) elif isinstance(child, minidom.Element): if plugins.has_key('isPivoted') and plugins['isPivoted'](child.tagName): unmarshal(child, plugins, rc) elif plugins.has_key('isBypassed') and plugins['isBypassed'](child.tagName): continue elif plugins.has_key('isCollective') and plugins['isCollective'](child.tagName): setattr(rc, key, unmarshal(child, plugins, wrappedIterator([]))) elif plugins.has_key('isCollected') and plugins['isCollected'](child.tagName): rc.append(unmarshal(child, plugins)) else: setattr(rc, key, unmarshal(child, plugins)) else: rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)]) return rc # User interfaces def ItemLookup(ItemId, IdType=None, SearchIndex=None, MerchantId=None, Condition=None, DeliveryMethod=None, ISPUPostalCode=None, OfferPage=None, ReviewPage=None, VariationPage=None, ResponseGroup=None, AWSAccessKeyId=None): '''ItemLookup in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isPivoted': lambda x: x == 'ItemAttributes', 'isCollective': lambda x: x == 'Items', 'isCollected': lambda x: x == 'Item'} return pagedIterator(XMLItemLookup, argv, 'OfferPage', 'Items', plugins) def XMLItemLookup(ItemId, IdType=None, SearchIndex=None, MerchantId=None, Condition=None, DeliveryMethod=None, ISPUPostalCode=None, OfferPage=None, ReviewPage=None, VariationPage=None, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of ItemLookup in ECS''' Operation = "ItemLookup" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) def ItemSearch(Keywords, SearchIndex="Blended", Availability=None, Title=None, Power=None, BrowseNode=None, Artist=None, Author=None, Actor=None, Director=None, AudienceRating=None, Manufacturer=None, MusicLabel=None, Composer=None, Publisher=None, Brand=None, Conductor=None, Orchestra=None, TextStream=None, ItemPage=None, Sort=None, City=None, Cuisine=None, Neighborhood=None, MinimumPrice=None, MaximumPrice=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None): '''ItemSearch in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isPivoted': lambda x: x == 'ItemAttributes', 'isCollective': lambda x: x == 'Items', 'isCollected': lambda x: x == 'Item'} return pagedIterator(XMLItemSearch, argv, "ItemPage", 'Items', plugins) def XMLItemSearch(Keywords, SearchIndex="Blended", Availability=None, Title=None, Power=None, BrowseNode=None, Artist=None, Author=None, Actor=None, Director=None, AudienceRating=None, Manufacturer=None, MusicLabel=None, Composer=None, Publisher=None, Brand=None, Conductor=None, Orchestra=None, TextStream=None, ItemPage=None, Sort=None, City=None, Cuisine=None, Neighborhood=None, MinimumPrice=None, MaximumPrice=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of ItemSearch in ECS''' Operation = "ItemSearch" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) def SimilarityLookup(ItemId, SimilarityType=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None): '''SimilarityLookup in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isPivoted': lambda x: x == 'ItemAttributes', 'isCollective': lambda x: x == 'Items', 'isCollected': lambda x: x == 'Item'} return rawIterator(XMLSimilarityLookup, argv, 'Items', plugins) def XMLSimilarityLookup(ItemId, SimilarityType=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of SimilarityLookup in ECS''' Operation = "SimilarityLookup" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) # List Operations def ListLookup(ListType, ListId, ProductPage=None, ProductGroup=None, Sort=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None): '''ListLookup in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isPivoted': lambda x: x == 'ItemAttributes', 'isCollective': lambda x: x == 'Lists', 'isCollected': lambda x: x == 'List'} return pagedIterator(XMLListLookup, argv, 'ProductPage', 'Lists', plugins) def XMLListLookup(ListType, ListId, ProductPage=None, ProductGroup=None, Sort=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of ListLookup in ECS''' Operation = "ListLookup" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) def ListSearch(ListType, Name=None, FirstName=None, LastName=None, Email=None, City=None, State=None, ListPage=None, ResponseGroup=None, AWSAccessKeyId=None): '''ListSearch in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isPivoted': lambda x: x == 'ItemAttributes', 'isCollective': lambda x: x == 'Lists', 'isCollected': lambda x: x == 'List'} return pagedIterator(XMLListSearch, argv, 'ListPage', 'Lists', plugins) def XMLListSearch(ListType, Name=None, FirstName=None, LastName=None, Email=None, City=None, State=None, ListPage=None, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of ListSearch in ECS''' Operation = "ListSearch" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) #Remote Shopping Cart Operations def CartCreate(Items, Quantities, ResponseGroup=None, AWSAccessKeyId=None): '''CartCreate in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] return __cartOperation(XMLCartCreate, argv) def XMLCartCreate(Items, Quantities, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of CartCreate in ECS''' Operation = "CartCreate" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] for x in ('Items', 'Quantities'): del argv[x] __fromListToItems(argv, Items, 'ASIN', Quantities) return query(buildRequest(argv)) def CartAdd(Cart, Items, Quantities, ResponseGroup=None, AWSAccessKeyId=None): '''CartAdd in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] return __cartOperation(XMLCartAdd, argv) def XMLCartAdd(Cart, Items, Quantities, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of CartAdd in ECS''' Operation = "CartAdd" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY CartId = Cart.CartId HMAC = Cart.HMAC argv = inspect.getargvalues(inspect.currentframe())[-1] for x in ('Items', 'Cart', 'Quantities'): del argv[x] __fromListToItems(argv, Items, 'ASIN', Quantities) return query(buildRequest(argv)) def CartGet(Cart, ResponseGroup=None, AWSAccessKeyId=None): '''CartGet in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] return __cartOperation(XMLCartGet, argv) def XMLCartGet(Cart, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of CartGet in ECS''' Operation = "CartGet" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY CartId = Cart.CartId HMAC = Cart.HMAC argv = inspect.getargvalues(inspect.currentframe())[-1] del argv['Cart'] return query(buildRequest(argv)) def CartModify(Cart, Items, Actions, ResponseGroup=None, AWSAccessKeyId=None): '''CartModify in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] return __cartOperation(XMLCartModify, argv) def XMLCartModify(Cart, Items, Actions, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of CartModify in ECS''' Operation = "CartModify" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY CartId = Cart.CartId HMAC = Cart.HMAC argv = inspect.getargvalues(inspect.currentframe())[-1] for x in ('Cart', 'Items', 'Actions'): del argv[x] __fromListToItems(argv, Items, 'CartItemId', Actions) return query(buildRequest(argv)) def CartClear(Cart, ResponseGroup=None, AWSAccessKeyId=None): '''CartClear in ECS''' argv = inspect.getargvalues(inspect.currentframe())[-1] return __cartOperation(XMLCartClear, argv) def XMLCartClear(Cart, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of CartClear in ECS''' Operation = "CartClear" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY CartId = Cart.CartId HMAC = Cart.HMAC argv = inspect.getargvalues(inspect.currentframe())[-1] del argv['Cart'] return query(buildRequest(argv)) def __fromListToItems(argv, items, id, actions): '''Convert list to AWS REST arguments''' for i in range(len(items)): argv["Item.%d.%s" % (i+1, id)] = getattr(items[i], id); action = actions[i] if isinstance(action, int): argv["Item.%d.Quantity" % (i+1)] = action else: argv["Item.%d.Action" % (i+1)] = action def __cartOperation(XMLSearch, arguments): '''Generic cart operation''' plugins = {'isBypassed': lambda x: x == 'Request', 'isCollective': lambda x: x in ('CartItems', 'SavedForLaterItems'), 'isCollected': lambda x: x in ('CartItem', 'SavedForLaterItem') } return rawObject(XMLSearch, arguments, 'Cart', plugins) # Seller Operation def SellerLookup(Sellers, ResponseGroup=None, AWSAccessKeyId=None): '''SellerLookup in AWS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isBypassed': lambda x: x == 'Request', 'isCollective': lambda x: x == 'Sellers', 'isCollected': lambda x: x == 'Seller'} return rawIterator(XMLSellerLookup, argv, 'Sellers', plugins) def XMLSellerLookup(Sellers, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of SellerLookup in AWS''' Operation = "SellerLookup" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY SellerId = ",".join(Sellers) argv = inspect.getargvalues(inspect.currentframe())[-1] del argv['Sellers'] return query(buildRequest(argv)) def SellerListingLookup(SellerId, Id, IdType="Listing", ResponseGroup=None, AWSAccessKeyId=None): '''SellerListingLookup in AWS Notice: although the repsonse includes TotalPage, TotalResults, there is no ListingPage in the request, so we have to use rawIterator instead of pagedIterator. Hope Amazaon would fix this inconsistance''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isBypassed': lambda x: x == 'Request', 'isCollective': lambda x: x == 'SellerListings', 'isCollected': lambda x: x == 'SellerListing'} return rawIterator(XMLSellerListingLookup, argv, "SellerListings", plugins) def XMLSellerListingLookup(SellerId, Id, IdType="Listing", ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of SellerListingLookup in AWS''' Operation = "SellerListingLookup" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) def SellerListingSearch(SellerId, Title=None, Sort=None, ListingPage=None, OfferStatus=None, ResponseGroup=None, AWSAccessKeyId=None): '''SellerListingSearch in AWS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isBypassed': lambda x: x == 'Request', 'isCollective': lambda x: x == 'SellerListings', 'isCollected': lambda x: x == 'SellerListing'} return pagedIterator(XMLSellerListingSearch, argv, "ListingPage", "SellerListings", plugins) def XMLSellerListingSearch(SellerId, Title=None, Sort=None, ListingPage=None, OfferStatus=None, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of SellerListingSearch in AWS''' Operation = "SellerListingSearch" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) def CustomerContentSearch(Name=None, Email=None, CustomerPage=1, ResponseGroup=None, AWSAccessKeyId=None): '''CustomerContentSearch in AWS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isBypassed': lambda x: x == 'Request', 'isCollective': lambda x: x in ('Customers', 'CustomerReviews'), 'isCollected': lambda x: x in ('Customer', 'Review')} return rawIterator(XMLCustomerContentSearch, argv, 'Customers', plugins) def XMLCustomerContentSearch(Name=None, Email=None, CustomerPage=1, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of CustomerContentSearch in AWS''' Operation = "CustomerContentSearch" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] for x in ('Name', 'Email'): if not argv[x]: del argv[x] return query(buildRequest(argv)) def CustomerContentLookup(CustomerId, ReviewPage=1, ResponseGroup=None, AWSAccessKeyId=None): '''CustomerContentLookup in AWS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isBypassed': lambda x: x == 'Request', 'isCollective': lambda x: x == 'Customers', 'isCollected': lambda x: x == 'Customer'} return rawIterator(XMLCustomerContentLookup, argv, 'Customers', plugins) def XMLCustomerContentLookup(CustomerId, ReviewPage=1, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of CustomerContentLookup in AWS''' Operation = "CustomerContentLookup" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) # BrowseNode def BrowseNodeLookup(BrowseNodeId, ResponseGroup=None, AWSAccessKeyId=None): '''BrowseNodeLookup in AWS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isBypassed': lambda x: x == 'Request', 'isCollective': lambda x: x == 'Children', 'isCollected': lambda x: x == 'BrowseNode'} return rawIterator(XMLBrowseNodeLookup, argv, 'BrowseNodes', plugins) def XMLBrowseNodeLookup(BrowseNodeId, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of BrowseNodeLookup in AWS''' Operation = "BrowseNodeLookup" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) # Help def Help(HelpType, About, ResponseGroup=None, AWSAccessKeyId=None): '''Help in AWS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isBypassed': lambda x: x == 'Request', 'isCollective': lambda x: x in ('RequiredParameters', 'AvailableParameters', 'DefaultResponseGroups', 'AvailableResponseGroups'), 'isCollected': lambda x: x in ('Parameter', 'ResponseGroup') } return rawObject(XMLHelp, argv, 'Information', plugins) def XMLHelp(HelpType, About, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of Help in AWS''' Operation = "Help" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) # Transaction def TransactionLookup(TransactionId, ResponseGroup=None, AWSAccessKeyId=None): '''TransactionLookup in AWS''' argv = inspect.getargvalues(inspect.currentframe())[-1] plugins = {'isBypassed': lambda x: x == 'Request', 'isCollective': lambda x: x in ('Transactions', 'TransactionItems', 'Shipments'), 'isCollected': lambda x: x in ('Transaction', 'TransactionItem', 'Shipment')} return rawIterator(XMLTransactionLookup, argv, 'Transactions', plugins) def XMLTransactionLookup(TransactionId, ResponseGroup=None, AWSAccessKeyId=None): '''DOM representation of TransactionLookup in AWS''' Operation = "TransactionLookup" AWSAccessKeyId = AWSAccessKeyId or LICENSE_KEY argv = inspect.getargvalues(inspect.currentframe())[-1] return query(buildRequest(argv)) if __name__ == "__main__" : setLicenseKey("YOUR-LICENSE-HERE"); sll = SellerListingLookup("A3ENSIQ3ZA4FFN", "1106K206331") print dir(sll[0])