""" RelatedAmazonProducts.py Uses your Amazon Web Services account to query products related to your Folksonomy Tags. This plugin does not require Folksonomy, however if you are using Folksonomy, please get the latest version of it, as there were some potential conlicts over the 'tags' metadata entry. Obtains a REST response from the following URL: http://webservices.amazon.com/onca/xml?Service=AWSECommerceService &AWSAccessKeyId=config['aws_access_key'] &AssociateTag=config['aws_associates_id'] &SearchIndex=config['aws_product_type'] &Operation=ItemSearch &Keywords= &Availability=Available &Merchant=Amazon [&Publisher=config['aws_favorite_pub']] [&BrowseNode=config['amazon_browse_node']] Specify your AWS Access Key and the type of product to search for in your config.py, like so (defaults are as shown here): py['aws_access_key']= # Your AWS Access key py['aws_associates_id']= # Your Amazon Associates ID py['aws_product_type']=Books # The type of product to search on. py['aws_favorite_pub']= # Restricts selections to a particular publisher py['story_product_count']=4 # The number of books to show on a page. py['aws_image_size']="MediumImage"" # The size of the amazon img to retrieve aws_image_size can be one of: SmallImage MediumImage LargeImage I like to use MediumImage and then scale it down using CSS. The SmallImage returns a very low-res picture from Amazon, and is useful if you don't have a lot of bandwidth. aws_product_type, aws_favorite_pub, and amazon_browse_node can be overridden on a per-story basis by defining metadata with the same key name in your story. So for instance, if your config.py specifies an aws_product_type of "Books", but you just posted about DVDs, you could override this setting for your story by doing: My Post on DVDs #tags batman,superman,mighty mouse #aws_product_type DVD

DVDs are awesome.

Valid aws_product_type values are [ "Books","Music","DVD","Toys","Video Games","Software","Software Video Games", "Electronics","Tools","Sporting Goods","Art Supplies","Kitchen","Gourmet Food", "Apparel","PC Hardware","VHS" ] aws_product_type defautls to "Books" For a list of valid amazon browse nodes, please see: http://www.amazon.com/gp/aws/sdk/main.html/002-5817805-8594421?s=AWSEcommerceService&v=2005-03-23&p=ApiReference/BrowseNodeValuesArticle My site uses BrowseNode 5, which is the code for Computing and Internet under Books in the US. Populates a varaible $relatedproducts for use in your story template, that will contain HTML like:
If you do not want to generate related products for a particular entry, add a "noproducts" metadata entry: My Entry with No Products #noproducts """ __author__ = 'Timothy C. Fanelli ' __version__ = '1.0.0' __url__ = 'http://www.timfanelli.com' # Variables import os, re, sys, string, xml.dom.minidom, urllib class Product(object): def __init__(self,asin,title,link,img,relevance): self.asin = asin self.title = title self.link = link self.img = img self.relevance = relevance def cb_prepare(args): request = args['request'] config = request.getConfiguration() data = request.getData() if not config.has_key('story_product_count'): config['story_product_count']=4 itemSearchUrl = "http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId=%s&Operation=ItemSearch&Merchant=Amazon&ResponseGroup=Small,Images&Sort=relevancerank" % ( config['aws_access_key'] ) if config.has_key('aws_associates_id'): itemSearchUrl = itemSearchUrl + "&AssociateTag=%s" % config['aws_associates_id'] data['itemsearch'] = itemSearchUrl def cb_story(args): """ populates the relatedproducts variable for an entry if it is the only entry being rendered. """ renderer = args['renderer'] if ( len(renderer.getContent()) != 1 ): return entry = args['entry'] request = args['request'] data = request.getData() config = request.getConfiguration() if not entry.has_key('tags') or entry.has_key('noproducts'): return tags = entry.getMetadata('tags') # if folksonomy has already done it's job, then we want to use rawtags instead. if entry.has_key('rawtags'): tags = entry.getMetadata('rawtags') producttype = "Books" if config.has_key('aws_product_type'): producttype = config['aws_product_type'] if entry.has_key('aws_product_type'): producttype = entry.getMetadata('aws_product_type') publisher = "" if config.has_key('aws_favorite_pub'): publisher = config['aws_favorite_pub'] if entry.has_key('aws_favorite_pub'): publisher = entry.getMetadata('aws_favorite_pub') browseNode = -1 if config.has_key('amazon_browse_node'): browseNode = config['amazon_browse_node'] if entry.has_key('amazon_browse_node'): browseNode = int( entry.getMetadata('amazon_browse_node') ) products = [] for tag in tags.split(','): tagprods = getProductsForTag(tag,config,data,producttype,publisher,browseNode) if tagprods: products.extend(tagprods) if products: products = sortProducts(products) products = products[ : min( config['story_product_count'], len(products) ) ] relatedproductsheader = config['related_products_header'] if entry.has_key('related_products_header'): relatedproductsheader = entry.getMetadata('related_products_header') relatedproducts = "".join( [ "\n\n\n" % ( p.link, p.img ) for p in products ] ) entry['relatedproducts'] = "
\n

%s

\n

%s

\n
" % ( relatedproductsheader, relatedproducts ) def sortProducts( products ): """ Sorts products removing duplicates as it goes. Products will be sorted by frequency, and then if no product is determined to have enough frequency to be worthwhile, then we'll resort based on keyword relevance. """ maxcount = 0; ranked = [] asinCount = {} for p in products: if asinCount.has_key(p.asin): asinCount[p.asin] = (asinCount[p.asin][0] + 1, p) else: asinCount[p.asin] = (1,p) maxcount = max( maxcount, asinCount[p.asin][0] ) ranked = asinCount.values() ranked.sort() ranked.reverse() # If max occurrances isn't a great way to go, let's sort on relevance: print >>sys.stderr, "Ranked maxcount: %s" % str(maxcount) if ( maxcount < 2 ): ranked = [ (p.relevance,p) for p in products ] ranked.sort() ranked = [ r[1] for r in ranked ] return ranked def getProductsForTag(tag,config,data,producttype,publisher,browsenode): itemSearchUrl = data['itemsearch'] + "&%s" % ( urllib.urlencode( [("Keywords", tag), ("SearchIndex",producttype)] ) ) imgsize = "MediumImage" if config.has_key('aws_image_size'): imgsize = config['aws_image_size'] if ( len(publisher) > 0 ): itemSearchUrl = itemSearchUrl + "&Publisher=%s" % publisher if ( browsenode >= 0 ): itemSearchUrl = itemSearchUrl + "&BrowseNode=%s" % str(browsenode) xmlresp = urllib.urlopen( itemSearchUrl ) products = [] if xmlresp: doc = xml.dom.minidom.parse(xmlresp) producttags = doc.getElementsByTagName('Item') relevance = 0 for product in producttags: asintag = product.getElementsByTagName('ASIN')[0] asin = getText( asintag.childNodes ) titletag = product.getElementsByTagName('Title')[0] title = getText( titletag.childNodes ) linknode = product.getElementsByTagName('DetailPageURL')[0] link = getText( linknode.childNodes ) img = "" mediumimg = product.getElementsByTagName(imgsize) if mediumimg: mediumimgurl = mediumimg[0].getElementsByTagName('URL')[0] img = getText( mediumimgurl.childNodes ) products.append(Product(asin,title,link,img,relevance)) relevance = relevance + 1 doc.unlink() if products: return products def getText( nodeList ): text = "" for node in nodeList: if node.nodeType == node.TEXT_NODE: text = text + node.data return text