/src/pyechonest/pyechonest/catalog.py
Python | 312 lines | 272 code | 13 blank | 27 comment | 7 complexity | d963df1771b8203a8c5316cc0521c3f2 MD5 | raw file
1#!/usr/bin/env python 2# encoding: utf-8 3 4""" 5Copyright (c) 2010 The Echo Nest. All rights reserved. 6Created by Scotty Vercoe on 2010-08-25. 7 8The Catalog module loosely covers http://developer.echonest.com/docs/v4/catalog.html 9Refer to the official api documentation if you are unsure about something. 10""" 11try: 12 import json 13except ImportError: 14 import simplejson as json 15import datetime 16 17import util 18from proxies import CatalogProxy, ResultList 19import artist, song 20 21# deal with datetime in json 22dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) else None 23 24class Catalog(CatalogProxy): 25 """ 26 A Catalog object 27 28 Attributes: 29 id (str): Catalog ID 30 31 name (str): Catalog Name 32 33 read (list): A list of catalog items (objects if they are resolved, else dictionaries) 34 35 feed (list): A list of dictionaries for news, blogs, reviews, audio, video for a catalog's artists 36 37 Create an catalog object like so: 38 39 >>> c = catalog.Catalog('CAGPXKK12BB06F9DE9') # get existing catalog 40 >>> c = catalog.Catalog('test_song_catalog', 'song') # get existing or create new catalog 41 42 """ 43 def __init__(self, id, type=None, **kwargs): 44 """ 45 Create a catalog object (get a catalog by ID or get or create one given by name and type) 46 47 Args: 48 id (str): A catalog id or name 49 50 Kwargs: 51 type (str): 'song' or 'artist', specifying the catalog type 52 53 Returns: 54 A catalog object 55 56 Example: 57 58 >>> c = catalog.Catalog('my_songs', type='song') 59 >>> c.id 60 u'CAVKUPC12BCA792120' 61 >>> c.name 62 u'my_songs' 63 >>> 64 65 """ 66 super(Catalog, self).__init__(id, type, **kwargs) 67 68 def __repr__(self): 69 return "<%s - %s>" % (self._object_type.encode('utf-8'), self.name.encode('utf-8')) 70 71 def __str__(self): 72 return self.name.encode('utf-8') 73 74 def update(self, items): 75 """ 76 Update a catalog object 77 78 Args: 79 items (list): A list of dicts describing update data and action codes (see api docs) 80 81 Kwargs: 82 83 Returns: 84 A ticket id 85 86 Example: 87 88 >>> c = catalog.Catalog('my_songs', type='song') 89 >>> items 90 [{'action': 'update', 91 'item': {'artist_name': 'dAn ThE aUtOmAtOr', 92 'disc_number': 1, 93 'genre': 'Instrumental', 94 'item_id': '38937DDF04BC7FC4', 95 'play_count': 5, 96 'release': 'Bombay the Hard Way: Guns, Cars & Sitars', 97 'song_name': 'Inspector Jay From Dehli', 98 'track_number': 9, 99 'url': 'file://localhost/Users/tylerw/Music/iTunes/iTunes%20Media/Music/Dan%20the%20Automator/Bombay%20the%20Hard%20Way_%20Guns,%20Cars%20&%20Sitars/09%20Inspector%20Jay%20From%20Dehli.m4a'}}] 100 >>> ticket = c.update(items) 101 >>> ticket 102 u'7dcad583f2a38e6689d48a792b2e4c96' 103 >>> c.status(ticket) 104 {u'ticket_status': u'complete', u'update_info': []} 105 >>> 106 107 """ 108 post_data = {} 109 items_json = json.dumps(items, default=dthandler) 110 post_data['data'] = items_json 111 112 response = self.post_attribute("update", data=post_data) 113 return response['ticket'] 114 115 def status(self, ticket): 116 """ 117 Check the status of a catalog update 118 119 Args: 120 ticket (str): A string representing a ticket ID 121 122 Kwargs: 123 124 Returns: 125 A dictionary representing ticket status 126 127 Example: 128 129 >>> ticket 130 u'7dcad583f2a38e6689d48a792b2e4c96' 131 >>> c.status(ticket) 132 {u'ticket_status': u'complete', u'update_info': []} 133 >>> 134 135 """ 136 return self.get_attribute_simple("status", ticket=ticket) 137 138 def get_profile(self): 139 """ 140 Check the status of a catalog update 141 142 Args: 143 144 Kwargs: 145 146 Returns: 147 A dictionary representing ticket status 148 149 Example: 150 151 >>> c 152 <catalog - test_song_catalog> 153 >>> c.profile() 154 {u'id': u'CAGPXKK12BB06F9DE9', 155 u'name': u'test_song_catalog', 156 u'pending_tickets': [], 157 u'resolved': 2, 158 u'total': 4, 159 u'type': u'song'} 160 >>> 161 162 """ 163 result = self.get_attribute("profile") 164 return result['catalog'] 165 166 profile = property(get_profile) 167 168 def read_items(self, buckets=None, results=15, start=0): 169 """ 170 Returns data from the catalog; also expanded for the requested buckets 171 172 Args: 173 174 Kwargs: 175 buckets (list): A list of strings specifying which buckets to retrieve 176 177 results (int): An integer number of results to return 178 179 start (int): An integer starting value for the result set 180 181 Returns: 182 A list of objects in the catalog; list contains additional attributes 'start' and 'total' 183 184 Example: 185 186 >>> c 187 <catalog - my_songs> 188 >>> c.read_items(results=1) 189 [<song - Harmonice Mundi II>] 190 >>> 191 """ 192 kwargs = {} 193 kwargs['bucket'] = buckets or [] 194 response = self.get_attribute("read", results=results, start=start, **kwargs) 195 rval = ResultList([]) 196 rval.start = response['catalog']['start'] 197 rval.total = response['catalog']['total'] 198 for item in response['catalog']['items']: 199 new_item = None 200 # song item 201 if 'song_id' in item: 202 item['id'] = item.pop('song_id') 203 item['title'] = item.pop('song_name') 204 request = item['request'] 205 new_item = song.Song(**util.fix(item)) 206 new_item.request = request 207 # artist item 208 elif 'artist_id' in item: 209 item['id'] = item.pop('artist_id') 210 item['name'] = item.pop('artist_name') 211 request = item['request'] 212 new_item = artist.Artist(**util.fix(item)) 213 new_item.request = request 214 # unresolved item 215 else: 216 new_item = item 217 rval.append(new_item) 218 return rval 219 220 read = property(read_items) 221 222 def get_feed(self, buckets=None, since=None, results=15, start=0): 223 """ 224 Returns feed (news, blogs, reviews, audio, video) for the catalog artists; response depends on requested buckets 225 226 Args: 227 228 Kwargs: 229 buckets (list): A list of strings specifying which feed items to retrieve 230 231 results (int): An integer number of results to return 232 233 start (int): An integer starting value for the result set 234 235 Returns: 236 A list of news, blogs, reviews, audio or video document dicts; 237 238 Example: 239 240 >>> c 241 <catalog - my_artists> 242 >>> c.get_feed(results=15) 243 {u'date_found': u'2011-02-06T07:50:25', 244 u'date_posted': u'2011-02-06T07:50:23', 245 u'id': u'caec686c0dff361e4c53dceb58fb9d2f', 246 u'name': u'Linkin Park \u2013 \u201cWaiting For The End\u201d + \u201cWhen They Come For Me\u201d 2/5 SNL', 247 u'references': [{u'artist_id': u'ARQUMH41187B9AF699', 248 u'artist_name': u'Linkin Park'}], 249 u'summary': u'<span>Linkin</span> <span>Park</span> performed "Waiting For The End" and "When They Come For Me" on Saturday Night Live. Watch the videos below and pick up their album A Thousand Suns on iTunes, Amazon MP3, CD Social Bookmarking ... ', 250 u'type': u'blogs', 251 u'url': u'http://theaudioperv.com/2011/02/06/linkin-park-waiting-for-the-end-when-they-come-for-me-25-snl/'} 252 >>> 253 """ 254 kwargs = {} 255 kwargs['bucket'] = buckets or [] 256 if since: 257 kwargs['since']=since 258 response = self.get_attribute("feed", results=results, start=start, **kwargs) 259 rval = ResultList(response['feed']) 260 return rval 261 262 feed = property(get_feed) 263 264 265 def delete(self): 266 """ 267 Deletes the entire catalog 268 269 Args: 270 271 Kwargs: 272 273 Returns: 274 The deleted catalog's id. 275 276 Example: 277 278 >>> c 279 <catalog - test_song_catalog> 280 >>> c.delete() 281 {u'id': u'CAXGUPY12BB087A21D'} 282 >>> 283 284 """ 285 return self.post_attribute("delete") 286 287 288def list(results=30, start=0): 289 """ 290 Returns list of all catalogs created on this API key 291 292 Args: 293 294 Kwargs: 295 results (int): An integer number of results to return 296 297 start (int): An integer starting value for the result set 298 299 Returns: 300 A list of catalog objects 301 302 Example: 303 304 >>> catalog.list() 305 [<catalog - test_artist_catalog>, <catalog - test_song_catalog>, <catalog - my_songs>] 306 >>> 307 308 309 """ 310 result = util.callm("%s/%s" % ('catalog', 'list'), {'results': results, 'start': start}) 311 return [Catalog(**util.fix(d)) for d in result['response']['catalogs']] 312