def findArtist(name, limit=1): with mb_lock: artistlist = [] attempt = 0 artistResults = None chars = set('!?*') if any((c in chars) for c in name): name = '"'+name+'"' q, sleepytime = startmb() while attempt < 5: try: artistResults = q.getArtists(ws.ArtistFilter(query=name, limit=limit)) break except WebServiceError, e: logger.warn('Attempt to query MusicBrainz for %s failed: %s [%s:%i]' % (name, e, mbhost, mbport)) attempt += 1 time.sleep(5) time.sleep(sleepytime) if not artistResults: return False for result in artistResults: if result.artist.name != result.artist.getUniqueName() and limit == 1: logger.debug('Found an artist with a disambiguation: %s - doing an album based search' % name) artistdict = findArtistbyAlbum(name) if not artistdict: logger.debug('Cannot determine the best match from an artist/album search. Using top match instead') artistlist.append({ 'name': result.artist.name, 'uniquename': result.artist.getUniqueName(), 'id': u.extractUuid(result.artist.id), 'url': result.artist.id, 'score': result.score }) else: artistlist.append(artistdict) else: artistlist.append({ 'name': result.artist.name, 'uniquename': result.artist.getUniqueName(), 'id': u.extractUuid(result.artist.id), 'url': result.artist.id, 'score': result.score }) return artistlist
def getRelease(releaseid): """ Deep release search to get track info """ with mb_lock: release = {} inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True) results = None attempt = 0 while attempt < 5: try: results = q.getReleaseById(releaseid, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve information from MusicBrainz for release "%s" failed: %s. SLeeping 5 seconds' % (releaseid, e)) attempt += 1 time.sleep(5) if not results: return False time.sleep(1) release['title'] = results.title release['id'] = u.extractUuid(results.id) release['asin'] = results.asin release['date'] = results.getEarliestReleaseDate() tracks = [] i = 1 for track in results.tracks: tracks.append({ 'number': i, 'title': track.title, 'id': u.extractUuid(track.id), 'url': track.id, 'duration': track.duration }) i += 1 release['tracks'] = tracks return release
def addReleases(artist_id, update_artist = True): artist_record = Artist.get(id=artist_id) musicbrainz_artist = musicbrainz.getBestArtistMatch(artist_record.name) release_ids = [] for release in musicbrainz_artist.getReleases(): release_ids.append(utils.extractUuid(release.id)) # These release results do not contain all the information, we must re-query for that info... for rid in release_ids: release = musicbrainz.getRelease(rid) if not release: continue release_group_id = utils.extractUuid(release.getReleaseGroup().id) try: release_group_tracked = Album.get(release_group_id=release_group_id) except peewee.DoesNotExist: release_group_tracked = None if release_group_tracked: continue release_record = Album.create( musicbrainz_id = rid, asin = release.getAsin(), release_group_id = release_group_id, artist_id = artist_id, name = release.getTitle(), type = release.getType(), released_on = release.getEarliestReleaseDate(), state = 'wanted') track_number = 1 for track in release.getTracks(): Track.create( album_id = release_record.id, number = track_number, title = track.getTitle(), length = track.getDuration(), state = 'wanted') track_number += 1 # Rescan the Music Library after adding new releases to see if the user has # them or not. Will not run if explicitly told not to by the caller. if(update_artist): ThreadPool.put(updateArtist, {'artist_id': artist_id})
def submitPuids(self, tracks2puids): """Submit track to PUID mappings. The C{tracks2puids} parameter has to be a dictionary, with the keys being MusicBrainz track IDs (either as absolute URIs or in their 36 character ASCII representation) and the values being PUIDs (ASCII, 36 characters). Note that this method only works if a valid user name and password have been set. See the example in L{Query} on how to supply authentication data. @param tracks2puids: a dictionary mapping track IDs to PUIDs @raise ConnectionError: couldn't connect to server @raise RequestError: invalid track or PUIDs @raise AuthenticationError: invalid user name and/or password """ assert self._clientId is not None, 'Please supply a client ID' params = [ ] params.append( ('client', self._clientId.encode('utf-8')) ) for (trackId, puid) in tracks2puids.iteritems(): trackId = mbutils.extractUuid(trackId, 'track') params.append( ('puid', trackId + ' ' + puid) ) encodedStr = urllib.urlencode(params, True) self._ws.post('track', '', encodedStr)
def submitUserTags(self, entityUri, tags): """Submit folksonomy tags for an entity. Note that all previously existing tags from the authenticated user are replaced with the ones given to this method. Other users' tags are not affected. @param entityUri: a string containing an absolute MB ID @param tags: A list of either L{Tag <musicbrainz2.model.Tag>} objects or strings @raise ValueError: invalid entityUri @raise ConnectionError: couldn't connect to server @raise RequestError: invalid ID, entity or tags @raise AuthenticationError: invalid user name and/or password """ entity = mbutils.extractEntityType(entityUri) uuid = mbutils.extractUuid(entityUri, entity) params = ( ('type', 'xml'), ('entity', entity), ('id', uuid), ('tags', ','.join([unicode(tag).encode('utf-8') for tag in tags])) ) encodedStr = urllib.urlencode(params) self._ws.post('tag', '', encodedStr)
def getBestArtistMatch(artist_name): with mb_lock: attempt = 0 if any((c in set('!?*')) for c in artist_name): artist_name = '"' + artist_name + '"' while attempt < 10: try: artist_results = query.getArtists(webservice.ArtistFilter(query=artist_name, limit=1)) if artist_results: includes = webservice.ArtistIncludes(releases=(model.Release.TYPE_ALBUM, model.Release.TYPE_OFFICIAL)) artist = artist_results[0].artist # Unfortunately, the search results do not contain release information, we have to query again for it... return query.getArtistById(utils.extractUuid(artist.id), includes) else: return None break except WebServiceError, e: logger.error('Attempt to query MusicBrainz for Artist %s failed: %s. Retrying in 10 seconds...' % (artist_name, e)) attempt += 1 time.sleep(10)
def getUserRating(self, entityUri): """Return the rating a user has applied to an entity. The given parameter has to be a fully qualified MusicBrainz ID, as returned by other library functions. Note that this method only works if a valid user name and password have been set. Only the rating the authenticated user applied to the entity will be returned. If username and/or password are incorrect, an AuthenticationError is raised. This method will return a L{Rating <musicbrainz2.model.Rating>} object. @param entityUri: a string containing an absolute MB ID @raise ValueError: invalid entityUri @raise ConnectionError: couldn't connect to server @raise RequestError: invalid ID or entity @raise AuthenticationError: invalid user name and/or password """ entity = mbutils.extractEntityType(entityUri) uuid = mbutils.extractUuid(entityUri, entity) params = { 'entity': entity, 'id': uuid } stream = self._ws.get('rating', '', filter=params) try: parser = MbXmlParser() result = parser.parse(stream) except ParseError, e: raise ResponseError(str(e), e)
def findArtist(name, limit=1): with mb_lock: artistlist = [] attempt = 0 while attempt < 5: try: artistResults = q.getArtists(ws.ArtistFilter(query=name, limit=limit)) break except WebServiceError, e: logger.warn('Attempt to retrieve information from MusicBrainz failed: %s' % e) attempt += 1 time.sleep(1) time.sleep(1) for result in artistResults: artistlist.append({ 'name': result.artist.name, 'uniquename': result.artist.getUniqueName(), 'id': u.extractUuid(result.artist.id), 'url': result.artist.id, 'score': result.score }) return artistlist
def submitUserRating(self, entityUri, rating): """Submit rating for an entity. Note that all previously existing rating from the authenticated user are replaced with the one given to this method. Other users' ratings are not affected. @param entityUri: a string containing an absolute MB ID @param rating: A L{Rating <musicbrainz2.model.Rating>} object or integer @raise ValueError: invalid entityUri @raise ConnectionError: couldn't connect to server @raise RequestError: invalid ID, entity or tags @raise AuthenticationError: invalid user name and/or password """ entity = mbutils.extractEntityType(entityUri) uuid = mbutils.extractUuid(entityUri, entity) params = ( ('type', 'xml'), ('entity', entity), ('id', uuid), ('rating', unicode(rating).encode('utf-8')) ) encodedStr = urllib.urlencode(params) self._ws.post('rating', '', encodedStr)
def submitISRCs(self, tracks2isrcs): """Submit track to ISRC mappings. The C{tracks2isrcs} parameter has to be a dictionary, with the keys being MusicBrainz track IDs (either as absolute URIs or in their 36 character ASCII representation) and the values being ISRCs (ASCII, 12 characters). Note that this method only works if a valid user name and password have been set. See the example in L{Query} on how to supply authentication data. @param tracks2isrcs: a dictionary mapping track IDs to ISRCs @raise ConnectionError: couldn't connect to server @raise RequestError: invalid track or ISRCs @raise AuthenticationError: invalid user name and/or password """ params = [ ] for (trackId, isrc) in tracks2isrcs.iteritems(): trackId = mbutils.extractUuid(trackId, 'track') params.append( ('isrc', trackId + ' ' + isrc) ) encodedStr = urllib.urlencode(params, True) self._ws.post('track', '', encodedStr)
def __init__(self, title=None, discId=None, releaseTypes=None, artistName=None, artistId=None, limit=None, offset=None, query=None, trackCount=None): """Constructor. If C{discId} or C{artistId} are set, only releases matching those IDs are returned. The C{releaseTypes} parameter allows to limit the types of the releases returned. You can set it to C{(Release.TYPE_ALBUM, Release.TYPE_OFFICIAL)}, for example, to only get officially released albums. Note that those values are connected using the I{AND} operator. MusicBrainz' support is currently very limited, so C{Release.TYPE_LIVE} and C{Release.TYPE_COMPILATION} exclude each other (see U{the documentation on release attributes <http://wiki.musicbrainz.org/AlbumAttribute>} for more information and all valid values). If both the C{artistName} and the C{artistId} parameter are given, the server will ignore C{artistName}. The C{query} parameter may contain a query in U{Lucene syntax <http://lucene.apache.org/java/docs/queryparsersyntax.html>}. Note that C{query} may not be used together with the other parameters except for C{limit} and C{offset}. @param title: a unicode string containing the release's title @param discId: a unicode string containing the DiscID @param releaseTypes: a sequence of release type URIs @param artistName: a unicode string containing the artist's name @param artistId: a unicode string containing the artist's ID @param limit: the maximum number of releases to return @param offset: start results at this zero-based offset @param query: a string containing a query in Lucene syntax @param trackCount: the number of tracks in the release @see: the constants in L{musicbrainz2.model.Release} """ if releaseTypes is None or len(releaseTypes) == 0: releaseTypesStr = None else: tmp = [ mbutils.extractFragment(x) for x in releaseTypes ] releaseTypesStr = ' '.join(tmp) self._params = [ ('title', title), ('discid', discId), ('releasetypes', releaseTypesStr), ('artist', artistName), ('artistid', mbutils.extractUuid(artistId)), ('limit', limit), ('offset', offset), ('query', query), ('count', trackCount), ] if not _paramsValid(self._params): raise ValueError('invalid combination of parameters')
def __init__(self, title=None, artistName=None, artistId=None, releaseTitle=None, releaseId=None, duration=None, puid=None, limit=None, offset=None, query=None): """Constructor. If C{artistId}, C{releaseId} or C{puid} are set, only tracks matching those IDs are returned. The server will ignore C{artistName} and C{releaseTitle} if C{artistId} or ${releaseId} are set respectively. The C{query} parameter may contain a query in U{Lucene syntax <http://lucene.apache.org/java/docs/queryparsersyntax.html>}. Note that C{query} may not be used together with the other parameters except for C{limit} and C{offset}. @param title: a unicode string containing the track's title @param artistName: a unicode string containing the artist's name @param artistId: a string containing the artist's ID @param releaseTitle: a unicode string containing the release's title @param releaseId: a string containing the release's title @param duration: the track's length in milliseconds @param puid: a string containing a PUID @param limit: the maximum number of releases to return @param offset: start results at this zero-based offset @param query: a string containing a query in Lucene syntax """ self._params = [ ('title', title), ('artist', artistName), ('artistid', mbutils.extractUuid(artistId)), ('release', releaseTitle), ('releaseid', mbutils.extractUuid(releaseId)), ('duration', duration), ('puid', puid), ('limit', limit), ('offset', offset), ('query', query), ] if not _paramsValid(self._params): raise ValueError('invalid combination of parameters')
def findRelease(name, limit=1): with mb_lock: releaselist = [] attempt = 0 releaseResults = None chars = set('!?') if any((c in chars) for c in name): name = '"' + name + '"' while attempt < 5: try: releaseResults = q.getReleases( ws.ReleaseFilter(query=name, limit=limit)) break except WebServiceError, e: logger.warn('Attempt to query MusicBrainz for %s failed: %s' % (name, e)) attempt += 1 time.sleep(5) time.sleep(1) if not releaseResults: return False for result in releaseResults: releaselist.append({ 'uniquename': result.release.artist.name, 'title': result.release.title, 'id': u.extractUuid(result.release.artist.id), 'albumid': u.extractUuid(result.release.id), 'url': result.release.artist.id, 'albumurl': result.release.id, 'score': result.score }) return releaselist
def findRelease(name, limit=1): with mb_lock: releaselist = [] attempt = 0 releaseResults = None chars = set('!?') if any((c in chars) for c in name): name = '"'+name+'"' q, sleepytime = startmb() while attempt < 5: try: releaseResults = q.getReleases(ws.ReleaseFilter(query=name, limit=limit)) break except WebServiceError, e: logger.warn('Attempt to query MusicBrainz for %s failed: %s' % (name, e)) attempt += 1 time.sleep(5) time.sleep(sleepytime) if not releaseResults: return False for result in releaseResults: releaselist.append({ 'uniquename': result.release.artist.name, 'title': result.release.title, 'id': u.extractUuid(result.release.artist.id), 'albumid': u.extractUuid(result.release.id), 'url': result.release.artist.id, 'albumurl': result.release.id, 'score': result.score }) return releaselist
def findRelease(name, limit=1): with mb_lock: releaselist = [] attempt = 0 releaseResults = None chars = set("!?") if any((c in chars) for c in name): name = '"' + name + '"' while attempt < 5: try: releaseResults = q.getReleases(ws.ReleaseFilter(query=name, limit=limit)) break except WebServiceError, e: logger.warn("Attempt to query MusicBrainz for %s failed: %s" % (name, e)) attempt += 1 time.sleep(5) time.sleep(1) if not releaseResults: return False for result in releaseResults: releaselist.append( { "uniquename": result.release.artist.name, "title": result.release.title, "id": u.extractUuid(result.release.artist.id), "albumid": u.extractUuid(result.release.id), "url": result.release.artist.id, "albumurl": result.release.id, "score": result.score, } ) return releaselist
def getReleaseGroup(rgid): """ Returns the best release out of any given release group """ with mb_lock: releaselist = [] inc = ws.ReleaseGroupIncludes(releases=True) attempt = 0 while attempt < 5: try: releaseGroup = q.getReleaseGroupById(rgid, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve information from MusicBrainz failed: %s' % e) attempt += 1 time.sleep(1) time.sleep(1) # I think for now we have to make separate queries for each release, in order # to get more detailed release info (ASIN, track count, etc.) for release in releaseGroup.releases: inc = ws.ReleaseIncludes(tracks=True) attempt = 0 while attempt < 5: try: releaseResult = q.getReleaseById(release.id, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve information for %s from MusicBrainz failed: %s' % (releaseResult.title, e)) attempt += 1 time.sleep(1) if not releaseResult: continue time.sleep(1) release_dict = { 'asin': bool(releaseResult.asin), 'tracks': len(releaseResult.getTracks()), 'releaseid': u.extractUuid(releaseResult.id) } releaselist.append(release_dict)
def removeFromUserCollection(self, releases): """Remove releases from a user's collection. The releases parameter must be a list. It can contain either L{Release} objects or a string representing a MusicBrainz release ID (either as absolute URIs or in their 36 character ASCII representation). Removing a release that is not in the collection has no effect. @param releases: a list of releases to remove from the user collection @raise ConnectionError: couldn't connect to server @raise AuthenticationError: invalid user name and/or password """ rels = [] for release in releases: if isinstance(release, Release): rels.append(mbutils.extractUuid(release.id)) else: rels.append(mbutils.extractUuid(release)) encodedStr = urllib.urlencode({'remove': ",".join(rels)}, True) self._ws.post('collection', '', encodedStr)
def findArtist(name, limit=1): with mb_lock: artistlist = [] attempt = 0 artistResults = None chars = set('!?') if any((c in chars) for c in name): name = '"'+name+'"' while attempt < 5: try: artistResults = q.getArtists(ws.ArtistFilter(query=name, limit=limit)) break except WebServiceError, e: logger.warn('Attempt to query MusicBrainz for %s failed: %s' % (name, e)) attempt += 1 time.sleep(5) time.sleep(1) if not artistResults: return False for result in artistResults: if result.artist.name != result.artist.getUniqueName() and limit == 1: logger.info('Found an artist with a disambiguation: %s - doing an album based search' % name) artistdict = findArtistbyAlbum(name) if not artistdict: return False else: artistlist.append(artistdict) else: artistlist.append({ 'name': result.artist.name, 'uniquename': result.artist.getUniqueName(), 'id': u.extractUuid(result.artist.id), 'url': result.artist.id, 'score': result.score }) return artistlist
def getArtist(artistid): with mb_lock: artist_dict = {} #Get all official release groups inc = ws.ArtistIncludes(releases=(m.Release.TYPE_OFFICIAL, m.Release.TYPE_ALBUM), releaseGroups=True) attempt = 0 while attempt < 5: try: artist = q.getArtistById(artistid, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve information from MusicBrainz failed: %s' % e) attempt += 1 time.sleep(1) time.sleep(1) artist_dict['artist_name'] = artist.name artist_dict['artist_sortname'] = artist.sortName artist_dict['artist_uniquename'] = artist.getUniqueName() artist_dict['artist_type'] = u.extractFragment(artist.type) artist_dict['artist_begindate'] = artist.beginDate artist_dict['artist_endDate'] = artist.endDate releasegroups = [] for rg in artist.getReleaseGroups(): releasegroups.append({ 'title': rg.title, 'id': u.extractUuid(rg.id), 'url': rg.id, 'type': u.getReleaseTypeName(rg.type) }) artist_dict['releasegroups'] = releasegroups return artist_dict
def getLabelById(self, id_, include=None): """Returns a L{model.Label} If no label with that ID can be found, or there is a server problem, an exception is raised. @param id_: a string containing the label's ID. @raise ConnectionError: couldn't connect to server @raise RequestError: invalid ID or include tags @raise ResourceNotFoundError: release doesn't exist @raise ResponseError: server returned invalid data """ uuid = mbutils.extractUuid(id_, 'label') result = self._getFromWebService('label', uuid, include) label = result.getLabel() if label is not None: return label else: raise ResponseError("server didn't return a label")
def getExtras(artistid): types = [m.Release.TYPE_EP, m.Release.TYPE_SINGLE, m.Release.TYPE_LIVE, m.Release.TYPE_REMIX, m.Release.TYPE_COMPILATION] for type in types: inc = ws.ArtistIncludes(releases=(m.Release.TYPE_OFFICIAL, type), releaseGroups=True) artist = q.getArtistById(artistid, inc) for rg in artist.getReleaseGroups(): rgid = u.extractUuid(rg.id) releaseid = getReleaseGroup(rgid) inc = ws.ReleaseIncludes(artist=True, releaseEvents= True, tracks= True, releaseGroup=True) results = ws.Query().getReleaseById(releaseid, inc) print results.title print u.getReleaseTypeName(results.releaseGroup.type)
def addArtist(id3_artist_name, path): musicbrainz_artist = musicbrainz.getBestArtistMatch(id3_artist_name) if musicbrainz_artist is None: unique_name = id3_artist_name artist_mb_id = None else: unique_name = musicbrainz_artist.getUniqueName() artist_mb_id = utils.extractUuid(musicbrainz_artist.id) try: artist = Artist.get(peewee.Q(musicbrainz_id=artist_mb_id) | peewee.Q(unique_name=unique_name)) except peewee.DoesNotExist: artist = Artist.create( name = id3_artist_name, unique_name = unique_name, location = path, state = 'wanted', musicbrainz_id = artist_mb_id) return artist
def getReleaseGroupById(self, id_, include=None): """Returns a release group. If no release group with that ID can be found, C{include} contains invalid tags, or there's a server problem, an exception is raised. @param id_: a string containing the release group's ID @param include: a L{ReleaseGroupIncludes} object, or None @return: a L{ReleaseGroup <musicbrainz2.model.ReleaseGroup>} object, or None @raise ConnectionError: couldn't connect to server @raise RequestError: invalid ID or include tags @raise ResourceNotFoundError: release doesn't exist @raise ResponseError: server returned invalid data """ uuid = mbutils.extractUuid(id_, 'release-group') result = self._getFromWebService('release-group', uuid, include) releaseGroup = result.getReleaseGroup() if releaseGroup is not None: return releaseGroup else: raise ResponseError("server didn't return releaseGroup")
def getArtistById(self, id_, include=None): """Returns an artist. If no artist with that ID can be found, C{include} contains invalid tags or there's a server problem, an exception is raised. @param id_: a string containing the artist's ID @param include: an L{ArtistIncludes} object, or None @return: an L{Artist <musicbrainz2.model.Artist>} object, or None @raise ConnectionError: couldn't connect to server @raise RequestError: invalid ID or include tags @raise ResourceNotFoundError: artist doesn't exist @raise ResponseError: server returned invalid data """ uuid = mbutils.extractUuid(id_, 'artist') result = self._getFromWebService('artist', uuid, include) artist = result.getArtist() if artist is not None: return artist else: raise ResponseError("server didn't return artist")
def getTrackById(self, id_, include=None): """Returns a track. If no track with that ID can be found, C{include} contains invalid tags or there's a server problem, an exception is raised. @param id_: a string containing the track's ID @param include: a L{TrackIncludes} object, or None @return: a L{Track <musicbrainz2.model.Track>} object, or None @raise ConnectionError: couldn't connect to server @raise RequestError: invalid ID or include tags @raise ResourceNotFoundError: track doesn't exist @raise ResponseError: server returned invalid data """ uuid = mbutils.extractUuid(id_, 'track') result = self._getFromWebService('track', uuid, include) track = result.getTrack() if track is not None: return track else: raise ResponseError("server didn't return track")
def findArtist(name, limit=1): with mb_lock: artistlist = [] attempt = 0 artistResults = None chars = set("!?*") if any((c in chars) for c in name): name = '"' + name + '"' while attempt < 5: try: artistResults = q.getArtists(ws.ArtistFilter(query=name, limit=limit)) break except WebServiceError, e: logger.warn("Attempt to query MusicBrainz for %s failed: %s" % (name, e)) attempt += 1 time.sleep(5) time.sleep(1) if not artistResults: return False for result in artistResults: if result.artist.name != result.artist.getUniqueName() and limit == 1: logger.debug("Found an artist with a disambiguation: %s - doing an album based search" % name) artistdict = findArtistbyAlbum(name) if not artistdict: logger.debug("Cannot determine the best match from an artist/album search. Using top match instead") artistlist.append( { "name": result.artist.name, "uniquename": result.artist.getUniqueName(), "id": u.extractUuid(result.artist.id), "url": result.artist.id, "score": result.score, } ) else: artistlist.append(artistdict) else: artistlist.append( { "name": result.artist.name, "uniquename": result.artist.getUniqueName(), "id": u.extractUuid(result.artist.id), "url": result.artist.id, "score": result.score, } ) return artistlist
def getArtist(artistid, extrasonly=False): with mb_lock: artist_dict = {} #Get all official release groups inc = ws.ArtistIncludes(releases=(m.Release.TYPE_OFFICIAL, m.Release.TYPE_ALBUM), releaseGroups=True) artist = None attempt = 0 while attempt < 5: try: artist = q.getArtistById(artistid, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve artist information from MusicBrainz failed for artistid: %s. Sleeping 5 seconds' % artistid) attempt += 1 time.sleep(5) if not artist: return False time.sleep(1) artist_dict['artist_name'] = artist.name artist_dict['artist_sortname'] = artist.sortName artist_dict['artist_uniquename'] = artist.getUniqueName() artist_dict['artist_type'] = u.extractFragment(artist.type) artist_dict['artist_begindate'] = artist.beginDate artist_dict['artist_enddate'] = artist.endDate releasegroups = [] if not extrasonly: for rg in artist.getReleaseGroups(): releasegroups.append({ 'title': rg.title, 'id': u.extractUuid(rg.id), 'url': rg.id, 'type': u.getReleaseTypeName(rg.type) }) # See if we need to grab extras myDB = db.DBConnection() try: includeExtras = myDB.select('SELECT IncludeExtras from artists WHERE ArtistID=?', [artistid])[0][0] except IndexError: includeExtras = False if includeExtras or headphones.INCLUDE_EXTRAS: includes = [m.Release.TYPE_COMPILATION, m.Release.TYPE_REMIX, m.Release.TYPE_SINGLE, m.Release.TYPE_LIVE, m.Release.TYPE_EP] for include in includes: inc = ws.ArtistIncludes(releases=(m.Release.TYPE_OFFICIAL, include), releaseGroups=True) artist = None attempt = 0 while attempt < 5: try: artist = q.getArtistById(artistid, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve artist information from MusicBrainz failed for artistid: %s. Sleeping 5 seconds' % artistid) attempt += 1 time.sleep(5) if not artist: continue for rg in artist.getReleaseGroups(): releasegroups.append({ 'title': rg.title, 'id': u.extractUuid(rg.id), 'url': rg.id, 'type': u.getReleaseTypeName(rg.type) })
def getReleaseGroup(rgid): """ Returns the best release out of any given release group """ with mb_lock: releaselist = [] inc = ws.ReleaseGroupIncludes(releases=True) releaseGroup = None attempt = 0 while attempt < 5: try: releaseGroup = q.getReleaseGroupById(rgid, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve information from MusicBrainz for release group "%s" failed. Sleeping 5 seconds' % rgid) attempt += 1 time.sleep(5) if not releaseGroup: return False time.sleep(1) # I think for now we have to make separate queries for each release, in order # to get more detailed release info (ASIN, track count, etc.) for release in releaseGroup.releases: inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True) releaseResult = None attempt = 0 while attempt < 5: try: releaseResult = q.getReleaseById(release.id, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve release information for %s from MusicBrainz failed: %s. Sleeping 5 seconds' % (releaseResult.title, e)) attempt += 1 time.sleep(5) if not releaseResult: continue if releaseResult.title.lower() != releaseGroup.title.lower(): continue time.sleep(1) formats = { '2xVinyl': '2', 'Vinyl': '2', 'CD': '0', 'Cassette': '3', '2xCD': '1', 'Digital Media': '0' } country = { 'US': '0', 'GB': '1', 'JP': '1', } try: format = int(replace_all(u.extractFragment(releaseResult.releaseEvents[0].format), formats)) except: format = 3 try: country = int(replace_all(releaseResult.releaseEvents[0].country, country)) except: country = 2 release_dict = { 'hasasin': bool(releaseResult.asin), 'asin': releaseResult.asin, 'trackscount': len(releaseResult.getTracks()), 'releaseid': u.extractUuid(releaseResult.id), 'releasedate': releaseResult.getEarliestReleaseDate(), 'format': format, 'country': country } tracks = [] i = 1 for track in releaseResult.tracks: tracks.append({ 'number': i, 'title': track.title, 'id': u.extractUuid(track.id), 'url': track.id, 'duration': track.duration }) i += 1 release_dict['tracks'] = tracks releaselist.append(release_dict)
def getRelease(releaseid): """ Deep release search to get track info """ with mb_lock: release = {} inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True, releaseGroup=True, artist=True) results = None attempt = 0 while attempt < 5: try: results = q.getReleaseById(releaseid, inc) break except WebServiceError, e: logger.warn( 'Attempt to retrieve information from MusicBrainz for release "%s" failed: %s. SLeeping 5 seconds' % (releaseid, e)) attempt += 1 time.sleep(5) if not results: return False time.sleep(1) release['title'] = results.title release['id'] = u.extractUuid(results.id) release['asin'] = results.asin release['date'] = results.getEarliestReleaseDate() rg = results.getReleaseGroup() if rg: release['rgid'] = u.extractUuid(rg.id) release['rg_title'] = rg.title release['rg_type'] = u.extractFragment(rg.type) else: logger.warn("Release " + releaseid + "had no ReleaseGroup associated") #so we can start with a releaseID from anywhere and get the artist info #it looks like MB api v1 only returns 1 artist object - 2.0 returns more... release['artist_name'] = results.artist.name release['artist_id'] = u.extractUuid(results.artist.id) tracks = [] i = 1 for track in results.tracks: tracks.append({ 'number': i, 'title': track.title, 'id': u.extractUuid(track.id), 'url': track.id, 'duration': track.duration }) i += 1 release['tracks'] = tracks return release
def getRelease(releaseid): """ Deep release search to get track info """ with mb_lock: release = {} inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True, releaseGroup=True, artist=True) results = None attempt = 0 while attempt < 5: try: results = q.getReleaseById(releaseid, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve information from MusicBrainz for release "%s" failed: %s. SLeeping 5 seconds' % (releaseid, e)) attempt += 1 time.sleep(5) if not results: return False time.sleep(1) release['title'] = results.title release['id'] = u.extractUuid(results.id) release['asin'] = results.asin release['date'] = results.getEarliestReleaseDate() rg = results.getReleaseGroup() if rg: release['rgid'] = u.extractUuid(rg.id) release['rg_title'] = rg.title release['rg_type'] = u.extractFragment(rg.type) else: logger.warn("Release " + releaseid + "had no ReleaseGroup associated") #so we can start with a releaseID from anywhere and get the artist info #it looks like MB api v1 only returns 1 artist object - 2.0 returns more... release['artist_name'] = results.artist.name release['artist_id'] = u.extractUuid(results.artist.id) tracks = [] i = 1 for track in results.tracks: tracks.append({ 'number': i, 'title': track.title, 'id': u.extractUuid(track.id), 'url': track.id, 'duration': track.duration }) i += 1 release['tracks'] = tracks return release
logger.warn('Attempt to query MusicBrainz for %s failed: %s. Sleeping 5 seconds.' % (name, e)) attempt += 1 time.sleep(5) time.sleep(1) if not results: return False artist_dict = {} for result in results: releaseGroup = result.releaseGroup artist_dict['name'] = releaseGroup.artist.name artist_dict['uniquename'] = releaseGroup.artist.getUniqueName() artist_dict['id'] = u.extractUuid(releaseGroup.artist.id) artist_dict['url'] = releaseGroup.artist.id artist_dict['score'] = result.score return artist_dict def findAlbumID(artist=None, album=None): term = '"'+album+'" AND artist:"'+artist+'"' f = ws.ReleaseGroupFilter(query=term, limit=1) results = None attempt = 0 while attempt < 5:
def getReleaseGroup(rgid): """ Returns a dictionary of the best stuff from a release group """ with mb_lock: releaselist = [] inc = ws.ReleaseGroupIncludes(releases=True, artist=True) releaseGroup = None attempt = 0 while attempt < 5: try: releaseGroup = q.getReleaseGroupById(rgid, inc) break except WebServiceError, e: logger.warn( 'Attempt to retrieve information from MusicBrainz for release group "%s" failed. Sleeping 5 seconds' % rgid ) attempt += 1 time.sleep(5) if not releaseGroup: return False time.sleep(1) # I think for now we have to make separate queries for each release, in order # to get more detailed release info (ASIN, track count, etc.) for release in releaseGroup.releases: inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True) releaseResult = None attempt = 0 while attempt < 5: try: releaseResult = q.getReleaseById(release.id, inc) break except WebServiceError, e: logger.warn( "Attempt to retrieve release information for %s from MusicBrainz failed: %s. Sleeping 5 seconds" % (releaseResult.title, e) ) attempt += 1 time.sleep(5) if not releaseResult: continue # Release filter for non-official live albums types = releaseResult.getTypes() if any("Live" in type for type in types): if not any("Official" in type for type in types): logger.debug("%s is not an official live album. Skipping" % releaseResult.name) continue time.sleep(1) formats = {"2xVinyl": "2", "Vinyl": "2", "CD": "0", "Cassette": "3", "2xCD": "1", "Digital Media": "0"} country = {"US": "0", "GB": "1", "JP": "2"} try: format = int(replace_all(u.extractFragment(releaseResult.releaseEvents[0].format), formats)) except: format = 3 try: country = int(replace_all(releaseResult.releaseEvents[0].country, country)) except: country = 3 release_dict = { "hasasin": bool(releaseResult.asin), "asin": releaseResult.asin, "trackscount": len(releaseResult.getTracks()), "releaseid": u.extractUuid(releaseResult.id), "releasedate": releaseResult.getEarliestReleaseDate(), "format": format, "country": country, } tracks = [] i = 1 for track in releaseResult.tracks: tracks.append( { "number": i, "title": track.title, "id": u.extractUuid(track.id), "url": track.id, "duration": track.duration, } ) i += 1 release_dict["tracks"] = tracks releaselist.append(release_dict)
item['trackscount_delta'] = abs(average_tracks - item['trackscount']) a = multikeysort( releaselist, ['-hasasin', 'country', 'format', 'trackscount_delta']) release_dict = { 'releaseid': a[0]['releaseid'], 'releasedate': releaselist[0]['releasedate'], 'trackcount': a[0]['trackscount'], 'tracks': a[0]['tracks'], 'asin': a[0]['asin'], 'releaselist': releaselist, 'artist_name': releaseGroup.artist.name, 'artist_id': u.extractUuid(releaseGroup.artist.id), 'title': releaseGroup.title, 'type': u.extractFragment(releaseGroup.type) } return release_dict def getRelease(releaseid): """ Deep release search to get track info """ with mb_lock: release = {}
def getReleaseGroup(rgid): """ Returns a dictionary of the best stuff from a release group """ with mb_lock: releaselist = [] inc = ws.ReleaseGroupIncludes(releases=True, artist=True) releaseGroup = None attempt = 0 while attempt < 5: try: releaseGroup = q.getReleaseGroupById(rgid, inc) break except WebServiceError, e: logger.warn( 'Attempt to retrieve information from MusicBrainz for release group "%s" failed. Sleeping 5 seconds' % rgid) attempt += 1 time.sleep(5) if not releaseGroup: return False time.sleep(1) # I think for now we have to make separate queries for each release, in order # to get more detailed release info (ASIN, track count, etc.) for release in releaseGroup.releases: inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True) releaseResult = None attempt = 0 while attempt < 5: try: releaseResult = q.getReleaseById(release.id, inc) break except WebServiceError, e: logger.warn( 'Attempt to retrieve release information for %s from MusicBrainz failed: %s. Sleeping 5 seconds' % (releaseResult.title, e)) attempt += 1 time.sleep(5) if not releaseResult: continue # Release filter for non-official live albums types = releaseResult.getTypes() if any('Live' in type for type in types): if not any('Official' in type for type in types): logger.debug('%s is not an official live album. Skipping' % releaseResult.name) continue time.sleep(1) formats = { '2xVinyl': '2', 'Vinyl': '2', 'CD': '0', 'Cassette': '3', '2xCD': '1', 'Digital Media': '0' } country = { 'US': '0', 'GB': '1', 'JP': '2', } try: format = int( replace_all( u.extractFragment( releaseResult.releaseEvents[0].format), formats)) except: format = 3 try: country = int( replace_all(releaseResult.releaseEvents[0].country, country)) except: country = 3 release_dict = { 'hasasin': bool(releaseResult.asin), 'asin': releaseResult.asin, 'trackscount': len(releaseResult.getTracks()), 'releaseid': u.extractUuid(releaseResult.id), 'releasedate': releaseResult.getEarliestReleaseDate(), 'format': format, 'country': country } tracks = [] i = 1 for track in releaseResult.tracks: tracks.append({ 'number': i, 'title': track.title, 'id': u.extractUuid(track.id), 'url': track.id, 'duration': track.duration }) i += 1 release_dict['tracks'] = tracks releaselist.append(release_dict)
def findArtist(name, limit=1): with mb_lock: artistlist = [] attempt = 0 artistResults = None chars = set('!?*') if any((c in chars) for c in name): name = '"' + name + '"' while attempt < 5: try: artistResults = q.getArtists( ws.ArtistFilter(query=name, limit=limit)) break except WebServiceError, e: logger.warn('Attempt to query MusicBrainz for %s failed: %s' % (name, e)) attempt += 1 time.sleep(5) time.sleep(1) if not artistResults: return False for result in artistResults: if result.artist.name != result.artist.getUniqueName( ) and limit == 1: logger.debug( 'Found an artist with a disambiguation: %s - doing an album based search' % name) artistdict = findArtistbyAlbum(name) if not artistdict: logger.debug( 'Cannot determine the best match from an artist/album search. Using top match instead' ) artistlist.append({ 'name': result.artist.name, 'uniquename': result.artist.getUniqueName(), 'id': u.extractUuid(result.artist.id), 'url': result.artist.id, 'score': result.score }) else: artistlist.append(artistdict) else: artistlist.append({ 'name': result.artist.name, 'uniquename': result.artist.getUniqueName(), 'id': u.extractUuid(result.artist.id), 'url': result.artist.id, 'score': result.score }) return artistlist
def getArtist(artistid, extrasonly=False): with mb_lock: artist_dict = {} #Get all official release groups inc = ws.ArtistIncludes(releases=(m.Release.TYPE_OFFICIAL, m.Release.TYPE_ALBUM), releaseGroups=True) artist = None attempt = 0 while attempt < 5: try: artist = q.getArtistById(artistid, inc) break except WebServiceError, e: logger.warn( 'Attempt to retrieve artist information from MusicBrainz failed for artistid: %s. Sleeping 5 seconds' % artistid) attempt += 1 time.sleep(5) if not artist: return False time.sleep(1) artist_dict['artist_name'] = artist.name artist_dict['artist_sortname'] = artist.sortName artist_dict['artist_uniquename'] = artist.getUniqueName() artist_dict['artist_type'] = u.extractFragment(artist.type) artist_dict['artist_begindate'] = artist.beginDate artist_dict['artist_enddate'] = artist.endDate releasegroups = [] if not extrasonly: for rg in artist.getReleaseGroups(): releasegroups.append({ 'title': rg.title, 'id': u.extractUuid(rg.id), 'url': rg.id, 'type': u.getReleaseTypeName(rg.type) }) # See if we need to grab extras myDB = db.DBConnection() try: includeExtras = myDB.select( 'SELECT IncludeExtras from artists WHERE ArtistID=?', [artistid])[0][0] except IndexError: includeExtras = False if includeExtras or headphones.INCLUDE_EXTRAS: includes = [ m.Release.TYPE_COMPILATION, m.Release.TYPE_REMIX, m.Release.TYPE_SINGLE, m.Release.TYPE_LIVE, m.Release.TYPE_EP, m.Release.TYPE_SOUNDTRACK ] for include in includes: inc = ws.ArtistIncludes(releases=(m.Release.TYPE_OFFICIAL, include), releaseGroups=True) artist = None attempt = 0 while attempt < 5: try: artist = q.getArtistById(artistid, inc) break except WebServiceError, e: logger.warn( 'Attempt to retrieve artist information from MusicBrainz failed for artistid: %s. Sleeping 5 seconds' % artistid) attempt += 1 time.sleep(5) if not artist: continue for rg in artist.getReleaseGroups(): releasegroups.append({ 'title': rg.title, 'id': u.extractUuid(rg.id), 'url': rg.id, 'type': u.getReleaseTypeName(rg.type) })