def _send(self, command): hosts = [x.strip() for x in self.hosts.split(',')] username = self.username password = self.password url_command = urllib.urlencode(command) for host in hosts: url = host + '/xbmcCmds/xbmcHttp/?' + url_command req = urllib2.Request(url) if password: base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '') req.add_header("Authorization", "Basic %s" % base64string) logger.info('XBMC url: %s' % url) try: handle = urllib2.urlopen(req) except Exception, e: logger.warn('Error opening XBMC url: ' % e) return response = handle.read().decode(headphones.SYS_ENCODING) return response
def updateHave(albumpath): results = [] for r,d,f in os.walk(albumpath): for files in f: if any(files.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS): results.append(os.path.join(r, files)) if results: myDB = db.DBConnection() for song in results: try: f = MediaFile(song) #logger.debug('Reading: %s' % song.decode('UTF-8')) except: logger.warn('Could not read file: %s' % song) continue else: if f.albumartist: artist = f.albumartist elif f.artist: artist = f.artist else: continue myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [unicode(song, headphones.SYS_ENCODING, errors="replace"), f.bitrate, f.format, artist, f.album, f.title])
def _sendhttp(self, host, command): username = self.username password = self.password url_command = urllib.urlencode(command) url = host + '/xbmcCmds/xbmcHttp/?' + url_command req = urllib2.Request(url) if password: base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '') req.add_header("Authorization", "Basic %s" % base64string) logger.info('Plex url: %s' % url) try: handle = urllib2.urlopen(req) except Exception as e: logger.warn('Error opening Plex url: %s' % e) return response = handle.read().decode(headphones.SYS_ENCODING) return response
def checkConfig(): params = { 'mode' : 'get_config', 'section' : 'misc' } if headphones.SAB_USERNAME: params['ma_username'] = headphones.SAB_USERNAME if headphones.SAB_PASSWORD: params['ma_password'] = headphones.SAB_PASSWORD if headphones.SAB_APIKEY: params['apikey'] = headphones.SAB_APIKEY if not headphones.SAB_HOST.startswith('http'): headphones.SAB_HOST = 'http://' + headphones.SAB_HOST if headphones.SAB_HOST.endswith('/'): headphones.SAB_HOST = headphones.SAB_HOST[0:len(headphones.SAB_HOST)-1] url = headphones.SAB_HOST + "/" + "api?" + urllib.urlencode(params) try: f = urllib.urlopen(url).read() except Exception, e: logger.warn("Unable to read SABnzbd config file - cannot determine renaming options (might affect auto & forced post processing)") return (0, 0)
def correctMetadata(albumid, release, downloaded_track_list): logger.info("Preparing to write metadata to tracks....") lossy_items = [] lossless_items = [] # Process lossless & lossy media formats separately for downloaded_track in downloaded_track_list: try: if any(downloaded_track.lower().endswith("." + x.lower()) for x in headphones.LOSSLESS_MEDIA_FORMATS): lossless_items.append(beets.library.Item.from_path(downloaded_track)) elif any(downloaded_track.lower().endswith("." + x.lower()) for x in headphones.LOSSY_MEDIA_FORMATS): lossy_items.append(beets.library.Item.from_path(downloaded_track)) else: logger.warn( "Skipping: " + downloaded_track.decode(headphones.SYS_ENCODING, "replace") + " because it is not a mutagen friendly file format" ) except Exception, e: logger.error( "Beets couldn't create an Item from: " + downloaded_track.decode(headphones.SYS_ENCODING, "replace") + " - not a media file?" + str(e) )
def notify(self, title, subtitle=None, text=None, sound=True): try: self.swizzle(self.objc.lookUpClass('NSBundle'), b'bundleIdentifier', self.swizzled_bundleIdentifier) NSUserNotification = self.objc.lookUpClass('NSUserNotification') NSUserNotificationCenter = self.objc.lookUpClass('NSUserNotificationCenter') NSAutoreleasePool = self.objc.lookUpClass('NSAutoreleasePool') if not NSUserNotification or not NSUserNotificationCenter: return False pool = NSAutoreleasePool.alloc().init() notification = NSUserNotification.alloc().init() notification.setTitle_(title) if subtitle: notification.setSubtitle_(subtitle) if text: notification.setInformativeText_(text) if sound: notification.setSoundName_("NSUserNotificationDefaultSoundName") notification.setHasActionButton_(False) notification_center = NSUserNotificationCenter.defaultUserNotificationCenter() notification_center.deliverNotification_(notification) del pool return True except Exception, e: logger.warn('Error sending OS X Notification: %s' % e) return False
def updateHave(albumpath): results = [] for r, d, f in os.walk(albumpath): for files in f: if any(files.endswith(x) for x in (".mp3", ".flac", ".aac", ".ogg", ".ape")): results.append(os.path.join(r, files)) if results: myDB = db.DBConnection() for song in results: try: f = MediaFile(song) # logger.debug('Reading: %s' % song.decode('UTF-8')) except: logger.warn("Could not read file: %s" % song) continue else: if f.albumartist: artist = f.albumartist elif f.artist: artist = f.artist else: continue myDB.action( "INSERT INTO have VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?)", [artist, f.album, f.track, f.title, f.length, f.bitrate, f.genre, f.date, f.mb_trackid], )
def remove_from_cache(self, ArtistID=None, AlbumID=None): """ Pass a musicbrainz id to this function (either ArtistID or AlbumID) """ if ArtistID: self.id = ArtistID self.id_type = 'artist' else: self.id = AlbumID self.id_type = 'album' self.query_type = 'artwork' if self._exists('artwork'): for artwork_file in self.artwork_files: try: os.remove(artwork_file) except: logger.warn('Error deleting file from the cache: %s', artwork_file) self.query_type = 'thumb' if self._exists('thumb'): for thumb_file in self.thumb_files: try: os.remove(thumb_file) except Exception: logger.warn('Error deleting file from the cache: %s', thumb_file)
def create_https_certificates(ssl_cert, ssl_key): """ Stolen from SickBeard (http://github.com/midgetspy/Sick-Beard): Create self-signed HTTPS certificares and store in paths 'ssl_cert' and 'ssl_key' """ from headphones import logger try: from OpenSSL import crypto from lib.certgen import createKeyPair, createCertRequest, createCertificate, TYPE_RSA, serial except: logger.warn("pyOpenSSL module missing, please install to enable HTTPS") return False # Create the CA Certificate cakey = createKeyPair(TYPE_RSA, 1024) careq = createCertRequest(cakey, CN='Certificate Authority') cacert = createCertificate(careq, (careq, cakey), serial, (0, 60*60*24*365*10)) # ten years cname = 'Headphones' pkey = createKeyPair(TYPE_RSA, 1024) req = createCertRequest(pkey, CN=cname) cert = createCertificate(req, (cacert, cakey), serial, (0, 60*60*24*365*10)) # ten years # Save the key and certificate to disk try: open(ssl_key, 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) open(ssl_cert, 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) except Exception, e: logger.error("Error creating SSL key and certificate: %s", e) return False
def findSeries(name, limit=1): serieslist = [] seriesResults = None chars = set('!?*-') if any((c in chars) for c in name): name = '"' + name + '"' criteria = {'series': name.lower()} with mb_lock: try: seriesResults = musicbrainzngs.search_series(limit=limit, **criteria)['series-list'] except musicbrainzngs.WebServiceError as e: logger.warn('Attempt to query MusicBrainz for %s failed (%s)' % (name, str(e))) mb_lock.snooze(5) if not seriesResults: return False for result in seriesResults: if 'disambiguation' in result: uniquename = unicode(result['name'] + " (" + result['disambiguation'] + ")") else: uniquename = unicode(result['name']) serieslist.append({ 'uniquename': uniquename, 'name': unicode(result['name']), 'type': unicode(result['type']), 'id': unicode(result['id']), 'url': unicode("http://musicbrainz.org/series/" + result['id']),#probably needs to be changed 'score': int(result['ext:score']) }) return serieslist
def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list, Kind=None): logger.info('Starting post-processing for: %s - %s' % (release['ArtistName'], release['AlbumTitle'])) # Check to see if we're preserving the torrent dir if headphones.KEEP_TORRENT_FILES and Kind=="torrent": new_folder = os.path.join(albumpath, 'headphones-modified'.encode(headphones.SYS_ENCODING, 'replace')) logger.info("Copying files to 'headphones-modified' subfolder to preserve downloaded files for seeding") try: shutil.copytree(albumpath, new_folder) # Update the album path with the new location albumpath = new_folder except Exception, e: logger.warn("Cannot copy/move files to temp folder: " + new_folder.decode(headphones.SYS_ENCODING, 'replace') + ". Not continuing. Error: " + str(e)) return # Need to update the downloaded track list with the new location. # Could probably just throw in the "headphones-modified" folder, # but this is good to make sure we're not counting files that may have failed to move downloaded_track_list = [] downloaded_cuecount = 0 for r,d,f in os.walk(albumpath): for files in f: if any(files.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS): downloaded_track_list.append(os.path.join(r, files)) elif files.lower().endswith('.cue'): downloaded_cuecount += 1
def getArtist(artistid, extrasonly=False): with mb_lock: artist_dict = {} artist = None try: limit = 200 artist = musicbrainzngs.get_artist_by_id(artistid)["artist"] newRgs = None artist["release-group-list"] = [] while newRgs == None or len(newRgs) >= limit: newRgs = musicbrainzngs.browse_release_groups( artistid, release_type="album", offset=len(artist["release-group-list"]), limit=limit )["release-group-list"] artist["release-group-list"] += newRgs except WebServiceError, e: logger.warn( "Attempt to retrieve artist information from MusicBrainz failed for artistid: %s (%s)" % (artistid, str(e)) ) time.sleep(5) except Exception, e: pass
def getSeries(seriesid): series_dict = {} series = None try: with mb_lock: series = musicbrainzngs.get_series_by_id(seriesid,includes=['release-group-rels'])['series'] except musicbrainzngs.WebServiceError as e: logger.warn('Attempt to retrieve series information from MusicBrainz failed for seriesid: %s (%s)' % (seriesid, str(e))) mb_lock.snooze(5) except Exception as e: pass if not series: return False if 'disambiguation' in series: series_dict['artist_name'] = unicode(series['name'] + " (" + unicode(series['disambiguation']) + ")") else: series_dict['artist_name'] = unicode(series['name']) releasegroups = [] for rg in series['release_group-relation-list']: releasegroup = rg['release-group'] releasegroups.append({ 'title':releasegroup['title'], 'date':releasegroup['first-release-date'], 'id':releasegroup['id'], 'type':rg['type'] }) series_dict['releasegroups'] = releasegroups return series_dict
def findRelease(name, limit=1): with mb_lock: releaselist = [] releaseResults = None chars = set("!?") if any((c in chars) for c in name): name = '"' + name + '"' try: releaseResults = musicbrainzngs.search_releases(query=name, limit=limit)["release-list"] except WebServiceError, e: # need to update exceptions logger.warn('Attempt to query MusicBrainz for "%s" failed: %s' % (name, str(e))) time.sleep(5) if not releaseResults: return False for result in releaseResults: releaselist.append( { "uniquename": unicode(result["artist-credit"][0]["artist"]["name"]), "title": unicode(result["title"]), "id": unicode(result["artist-credit"][0]["artist"]["id"]), "albumid": unicode(result["id"]), "url": unicode( "http://musicbrainz.org/artist/" + result["artist-credit"][0]["artist"]["id"] ), # probably needs to be changed "albumurl": unicode( "http://musicbrainz.org/release/" + result["id"] ), # probably needs to be changed "score": int(result["ext:score"]), } ) return releaselist
def checkConfig(): params = {"mode": "get_config", "section": "misc"} if headphones.SAB_USERNAME: params["ma_username"] = headphones.SAB_USERNAME if headphones.SAB_PASSWORD: params["ma_password"] = headphones.SAB_PASSWORD if headphones.SAB_APIKEY: params["apikey"] = headphones.SAB_APIKEY if not headphones.SAB_HOST.startswith("http"): headphones.SAB_HOST = "http://" + headphones.SAB_HOST if headphones.SAB_HOST.endswith("/"): headphones.SAB_HOST = headphones.SAB_HOST[0 : len(headphones.SAB_HOST) - 1] url = headphones.SAB_HOST + "/" + "api?" + urllib.urlencode(params) try: f = urllib.urlopen(url).read() except Exception, e: logger.warn( "Unable to read SABnzbd config file - cannot determine renaming options (might affect auto & forced post processing)" ) return (0, 0)
def findAlbumID(artist=None, album=None): results = None chars = set('!?*-') try: if album and artist: if any((c in chars) for c in album): album = '"'+album+'"' if any((c in chars) for c in artist): artist = '"'+artist+'"' criteria = {'release': album.lower()} criteria['artist'] = artist.lower() else: if any((c in chars) for c in album): album = '"'+album+'"' criteria = {'release': album.lower()} results = musicbrainzngs.search_release_groups(limit=1, **criteria).get('release-group-list') except musicbrainzngs.WebServiceError as e: logger.warn('Attempt to query MusicBrainz for %s - %s failed (%s)' % (artist, album, str(e))) time.sleep(5) if not results: return False if len(results) < 1: return False rgid = unicode(results[0]['id']) return rgid
def artistlist_to_mbids(artistlist, forced=False): for artist in artistlist: if not artist and not (artist == ' '): continue # If adding artists through Manage New Artists, they're coming through as non-unicode (utf-8?) # and screwing everything up if not isinstance(artist, unicode): try: artist = artist.decode('utf-8', 'replace') except: logger.warn("Unable to convert artist to unicode so cannot do a database lookup") continue results = mb.findArtist(artist, limit=1) if not results: logger.info('No results found for: %s' % artist) continue try: artistid = results[0]['id'] except IndexError: logger.info('MusicBrainz query turned up no matches for: %s' % artist) continue # Check if it's blacklisted/various artists (only check if it's not forced, e.g. through library scan auto-add.) # Forced example = Adding an artist from Manage New Artists myDB = db.DBConnection() if not forced: bl_artist = myDB.action('SELECT * FROM blacklist WHERE ArtistID=?', [artistid]).fetchone() if bl_artist or artistid in blacklisted_special_artists: logger.info("Artist ID for '%s' is either blacklisted or Various Artists. To add artist, you must do it manually (Artist ID: %s)" % (artist, artistid)) continue # Add to database if it doesn't exist if not is_exists(artistid): addArtisttoDB(artistid) # Just update the tracks if it does else: havetracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID=?', [artistid])) + len(myDB.select('SELECT TrackTitle from have WHERE ArtistName like ?', [artist])) myDB.action('UPDATE artists SET HaveTracks=? WHERE ArtistID=?', [havetracks, artistid]) # Delete it from the New Artists if the request came from there if forced: myDB.action('DELETE from newartists WHERE ArtistName=?', [artist]) # Update the similar artist tag cloud: logger.info('Updating artist information from Last.fm') try: lastfm.getSimilar() except Exception as e: logger.warn('Failed to update arist information from Last.fm: %s' % e)
def __init__(self): try: self.objc = __import__("objc") self.AppKit = __import__("AppKit") except: logger.warn('OS X Notification: Cannot import objc or AppKit') pass
def smartMove(src, dest, delete=True): from headphones import logger source_dir = os.path.dirname(src) filename = os.path.basename(src) if os.path.isfile(os.path.join(dest, filename)): logger.info('Destination file exists: %s', os.path.join(dest, filename)) title = os.path.splitext(filename)[0] ext = os.path.splitext(filename)[1] i = 1 while True: newfile = title + '(' + str(i) + ')' + ext if os.path.isfile(os.path.join(dest, newfile)): i += 1 else: logger.info('Renaming to %s', newfile) try: os.rename(src, os.path.join(source_dir, newfile)) filename = newfile except Exception as e: logger.warn('Error renaming %s: %s', src.decode(headphones.SYS_ENCODING, 'replace'), e) break try: if delete: shutil.move(os.path.join(source_dir, filename), os.path.join(dest, filename)) else: shutil.copy(os.path.join(source_dir, filename), os.path.join(dest, filename)) return True except Exception as e: logger.warn('Error moving file %s: %s', filename.decode(headphones.SYS_ENCODING, 'replace'), e)
def shutdown(restart=False, update=False): cherrypy.engine.exit() SCHED.shutdown(wait=False) CONFIG.write() if not restart and not update: logger.info('Headphones is shutting down...') if update: logger.info('Headphones is updating...') try: versioncheck.update() except Exception as e: logger.warn('Headphones failed to update: %s. Restarting.', e) if CREATEPID: logger.info('Removing pidfile %s', PIDFILE) os.remove(PIDFILE) if restart: logger.info('Headphones is restarting...') popen_list = [sys.executable, FULL_PATH] popen_list += ARGS if '--nolaunch' not in popen_list: popen_list += ['--nolaunch'] logger.info('Restarting Headphones with %s', popen_list) subprocess.Popen(popen_list, cwd=os.getcwd()) os._exit(0)
def update(self): # From what I read you can't update the music library on a per directory or per path basis # so need to update the whole thing hosts = [x.strip() for x in self.server_hosts.split(',')] for host in hosts: logger.info('Sending library update command to Plex Media Server@ '+host) url = "%s/library/sections" % host try: xml_sections = minidom.parse(urllib.urlopen(url)) except IOError, e: logger.warn("Error while trying to contact Plex Media Server: %s" % e) return False sections = xml_sections.getElementsByTagName('Directory') if not sections: logger.info(u"Plex Media Server not running on: " + host) return False for s in sections: if s.getAttribute('type') == "artist": url = "%s/library/sections/%s/refresh" % (host, s.getAttribute('key')) try: urllib.urlopen(url) except Exception, e: logger.warn("Error updating library section for Plex Media Server: %s" % e) return False
def findRelease(name, limit=1): with mb_lock: releaselist = [] releaseResults = None chars = set('!?') if any((c in chars) for c in name): name = '"'+name+'"' try: releaseResults = musicbrainzngs.search_releases(query=name,limit=limit)['release-list'] except WebServiceError, e: #need to update exceptions logger.warn('Attempt to query MusicBrainz for "%s" failed: %s' % (name, str(e))) time.sleep(5) if not releaseResults: return False for result in releaseResults: releaselist.append({ 'uniquename': unicode(result['artist-credit'][0]['artist']['name']), 'title': unicode(result['title']), 'id': unicode(result['artist-credit'][0]['artist']['id']), 'albumid': unicode(result['id']), 'url': unicode("http://musicbrainz.org/artist/" + result['artist-credit'][0]['artist']['id']),#probably needs to be changed 'albumurl': unicode("http://musicbrainz.org/release/" + result['id']),#probably needs to be changed 'score': int(result['ext:score']) }) return releaselist
def findSeries(name, limit=1): serieslist = [] seriesResults = None criteria = {"series": name.lower()} with mb_lock: try: seriesResults = musicbrainzngs.search_series(limit=limit, **criteria)["series-list"] except musicbrainzngs.WebServiceError as e: logger.warn("Attempt to query MusicBrainz for %s failed (%s)" % (name, str(e))) mb_lock.snooze(5) if not seriesResults: return False for result in seriesResults: if "disambiguation" in result: uniquename = unicode(result["name"] + " (" + result["disambiguation"] + ")") else: uniquename = unicode(result["name"]) serieslist.append( { "uniquename": uniquename, "name": unicode(result["name"]), "type": unicode(result["type"]), "id": unicode(result["id"]), "url": unicode("http://musicbrainz.org/series/" + result["id"]), # probably needs to be changed "score": int(result["ext:score"]), } ) return serieslist
def getRelease(releaseid, include_artist_info=True): """ Deep release search to get track info """ with mb_lock: release = {} results = None try: if include_artist_info: results = musicbrainzngs.get_release_by_id(releaseid, ["artists", "release-groups", "media", "recordings"]).get('release') else: results = musicbrainzngs.get_release_by_id(releaseid, ["media", "recordings"]).get('release') except musicbrainzngs.WebServiceError as e: logger.warn('Attempt to retrieve information from MusicBrainz for release "%s" failed (%s)' % (releaseid, str(e))) time.sleep(5) if not results: return False release['title'] = unicode(results['title']) release['id'] = unicode(results['id']) release['asin'] = unicode(results['asin']) if 'asin' in results else None release['date'] = unicode(results['date']) if 'date' in results else None try: release['format'] = unicode(results['medium-list'][0]['format']) except: release['format'] = u'Unknown' try: release['country'] = unicode(results['country']) except: release['country'] = u'Unknown' if include_artist_info: if 'release-group' in results: release['rgid'] = unicode(results['release-group']['id']) release['rg_title'] = unicode(results['release-group']['title']) try: release['rg_type'] = unicode(results['release-group']['type']) if release['rg_type'] == 'Album' and 'secondary-type-list' in results['release-group']: secondary_type = unicode(results['release-group']['secondary-type-list'][0]) if secondary_type != release['rg_type']: release['rg_type'] = secondary_type except KeyError: release['rg_type'] = u'Unknown' else: logger.warn("Release " + releaseid + "had no ReleaseGroup associated") release['artist_name'] = unicode(results['artist-credit'][0]['artist']['name']) release['artist_id'] = unicode(results['artist-credit'][0]['artist']['id']) release['tracks'] = getTracksFromRelease(results) return release
def notify(self, artist, album, albumartpath): hosts = [x.strip() for x in self.hosts.split(',')] header = "Headphones" message = "%s - %s added to your library" % (artist, album) time = "3000" # in ms for host in hosts: logger.info('Sending notification command to XMBC @ '+host) try: version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major'] if version < 12: #Eden notification = header + "," + message + "," + time + "," + albumartpath notifycommand = {'command': 'ExecBuiltIn', 'parameter': 'Notification('+notification+')'} request = self._sendhttp(host, notifycommand) else: #Frodo params = {'title':header, 'message': message, 'displaytime': int(time), 'image': albumartpath} request = self._sendjson(host, 'GUI.ShowNotification', params) if not request: raise Exception except: logger.warn('Error sending notification request to XBMC')
def getArtists(): myDB = db.DBConnection() results = myDB.select("SELECT ArtistID from artists") if not headphones.LASTFM_USERNAME: logger.warn("Last.FM username not set, not importing artists.") return logger.info("Fetching artists from Last.FM for username: %s", headphones.LASTFM_USERNAME) data = request_lastfm("library.getartists", limit=10000, user=headphones.LASTFM_USERNAME) if data and "artists" in data: artistlist = [] artists = data["artists"]["artist"] logger.debug("Fetched %d artists from Last.FM", len(artists)) for artist in artists: artist_mbid = artist["mbid"] if not any(artist_mbid in x for x in results): artistlist.append(artist_mbid) from headphones import importer for artistid in artistlist: importer.addArtisttoDB(artistid) logger.info("Imported %d new artists from Last.FM", len(artistlist))
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 notify(self, subject, message): message = MIMEText(message, 'plain', "utf-8") message['Subject'] = subject message['From'] = email.utils.formataddr(('Headphones', headphones.CONFIG.EMAIL_FROM)) message['To'] = headphones.CONFIG.EMAIL_TO try: if (headphones.CONFIG.EMAIL_SSL): mailserver = smtplib.SMTP_SSL(headphones.CONFIG.EMAIL_SMTP_SERVER, headphones.CONFIG.EMAIL_SMTP_PORT) else: mailserver = smtplib.SMTP(headphones.CONFIG.EMAIL_SMTP_SERVER, headphones.CONFIG.EMAIL_SMTP_PORT) if (headphones.CONFIG.EMAIL_TLS): mailserver.starttls() mailserver.ehlo() if headphones.CONFIG.EMAIL_SMTP_USER: mailserver.login(headphones.CONFIG.EMAIL_SMTP_USER, headphones.CONFIG.EMAIL_SMTP_PASSWORD) mailserver.sendmail(headphones.CONFIG.EMAIL_FROM, headphones.CONFIG.EMAIL_TO, message.as_string()) mailserver.quit() return True except Exception, e: logger.warn('Error sending Email: %s' % e) return False
def action(self, query, args=None): with db_lock: if query == None: return sqlResult = None attempt = 0 while attempt < 5: try: if args == None: #logger.debug(self.filename+": "+query) sqlResult = self.connection.execute(query) else: #logger.debug(self.filename+": "+query+" with args "+str(args)) sqlResult = self.connection.execute(query, args) self.connection.commit() break except sqlite3.OperationalError, e: if "unable to open database file" in e.message or "database is locked" in e.message: logger.warn('Database Error: %s' % e) attempt += 1 time.sleep(1) else: logger.error('Database error: %s' % e) raise except sqlite3.DatabaseError, e: logger.error('Fatal Error executing %s :: %s' % (query, e)) raise
def findArtistbyAlbum(name): myDB = db.DBConnection() artist = myDB.action('SELECT AlbumTitle from have WHERE ArtistName=? AND AlbumTitle IS NOT NULL ORDER BY RANDOM()', [name]).fetchone() if not artist: return False # Probably not neccessary but just want to double check if not artist['AlbumTitle']: return False term = '"'+artist['AlbumTitle']+'" AND artist:"'+name+'"' f = ws.ReleaseGroupFilter(query=term, limit=1) results = None attempt = 0 q, sleepytime = startmb() while attempt < 5: try: results = q.getReleaseGroups(f) break except WebServiceError, e: logger.warn('Attempt to query MusicBrainz for %s failed: %s. Sleeping 5 seconds.' % (name, e)) attempt += 1 time.sleep(5)
def shutdown(restart=False, update=False): cherrypy.engine.exit() SCHED.shutdown(wait=False) config_write() if not restart and not update: logger.info('Headphones is shutting down...') if update: logger.info('Headphones is updating...') try: versioncheck.update() except Exception, e: logger.warn('Headphones failed to update: %s. Restarting.' % e)
def checkGithub(): # Get the latest commit available from github url = 'https://api.github.com/repos/%s/headphones/commits/%s' % ( headphones.GIT_USER, headphones.GIT_BRANCH) logger.info('Retrieving latest version information from github') try: result = urllib2.urlopen(url, timeout=20).read() git = simplejson.JSONDecoder().decode(result) headphones.LATEST_VERSION = git['sha'] except: logger.warn('Could not get the latest commit from github') headphones.COMMITS_BEHIND = 0 return headphones.CURRENT_VERSION # See how many commits behind we are if headphones.CURRENT_VERSION: logger.info( 'Comparing currently installed version with latest github version') url = 'https://api.github.com/repos/%s/headphones/compare/%s...%s' % ( headphones.GIT_USER, headphones.CURRENT_VERSION, headphones.LATEST_VERSION) try: result = urllib2.urlopen(url, timeout=20).read() git = simplejson.JSONDecoder().decode(result) headphones.COMMITS_BEHIND = git['total_commits'] except: logger.warn('Could not get commits behind from github') headphones.COMMITS_BEHIND = 0 return headphones.CURRENT_VERSION if headphones.COMMITS_BEHIND >= 1: logger.info('New version is available. You are %s commits behind' % headphones.COMMITS_BEHIND) elif headphones.COMMITS_BEHIND == 0: logger.info('Headphones is up to date') elif headphones.COMMITS_BEHIND == -1: logger.info( 'You are running an unknown version of Headphones. Run the updater to identify your version' ) else: logger.info( 'You are running an unknown version of Headphones. Run the updater to identify your version' ) return headphones.LATEST_VERSION
class LMS(object): """ Class for updating a Logitech Media Server """ def __init__(self): self.hosts = headphones.LMS_HOST def _sendjson(self, host): data = {'id': 1, 'method': 'slim.request', 'params': ["",["rescan"]]} data = json.JSONEncoder().encode(data) content = {'Content-Type': 'application/json'} req = urllib2.Request(host+'/jsonrpc.js', data, content) try: handle = urllib2.urlopen(req) except Exception, e: logger.warn('Error opening LMS url: %s' % e) return response = json.JSONDecoder().decode(handle.read()) try: return response['result'] except: logger.warn('LMS returned error: %s' % response['error']) return
def get_all_releases(rgid,includeExtras=False): results = [] try: limit = 100 newResults = None while newResults == None or len(newResults) >= limit: newResults = musicbrainzngs.browse_releases(release_group=rgid,includes=['artist-credits','labels','recordings','release-groups','media'],limit=limit,offset=len(results)) if 'release-list' not in newResults: break #may want to raise an exception here instead ? newResults = newResults['release-list'] results += newResults except WebServiceError, e: logger.warn('Attempt to retrieve information from MusicBrainz for release group "%s" failed (%s)' % (rgid, str(e))) time.sleep(5) return False
def getresultNZB(result): nzb = None if result[3] == 'newzbin': params = urllib.urlencode({"username": headphones.NEWZBIN_UID, "password": headphones.NEWZBIN_PASSWORD, "reportid": result[2]}) url = "https://www.newzbin2.es" + "/api/dnzb/" urllib._urlopener = NewzbinDownloader() try: nzb = urllib.urlopen(url, data=params).read() except urllib2.URLError, e: logger.warn('Error fetching nzb from url: %s. Error: %s' % (url, e)) except exceptions.NewzbinAPIThrottled: #TODO: This has created a potentially infinite loop? As long as they keep throttling we keep trying. logger.info("Done waiting for Newzbin API throttle limit, starting downloads again") getresultNZB(result)
def daemonize(): if threading.activeCount() != 1: logger.warn('There are %r active threads. Daemonizing may cause \ strange behavior.' % threading.enumerate()) sys.stdout.flush() sys.stderr.flush() # Do first fork try: pid = os.fork() # @UndefinedVariable - only available in UNIX if pid != 0: sys.exit(0) except OSError, e: raise RuntimeError("1st fork failed: %s [%d]" % (e.strerror, e.errno))
def cue_split(albumpath, keep_original_folder=False): """ Attempts to check and split audio files by a cue for the given directory. """ # Walk directory and scan all media files count = 0 cue_count = 0 cue_dirs = [] for root, dirs, files in os.walk(albumpath): for _file in files: extension = os.path.splitext(_file)[1].lower()[1:] if extension in headphones.MEDIA_FORMATS: count += 1 elif extension == 'cue': cue_count += 1 if root not in cue_dirs: cue_dirs.append(root) # Split cue if cue_count and cue_count >= count and cue_dirs: # Copy to temp directory if keep_original_folder: temppath = preserve_torrent_directory(albumpath) if temppath: cue_dirs = [cue_dir.replace(albumpath, temppath) for cue_dir in cue_dirs] albumpath = temppath else: return None from headphones import logger, cuesplit logger.info("Attempting to split audio files by cue") cwd = os.getcwd() for cue_dir in cue_dirs: try: cuesplit.split(cue_dir) except Exception as e: os.chdir(cwd) logger.warn("Cue not split: " + str(e)) return None os.chdir(cwd) return albumpath return None
def findArtist(name, limit=1): with mb_lock: artistlist = [] artistResults = None chars = set('!?*') if any((c in chars) for c in name): name = '"'+name+'"' try: artistResults = musicbrainzngs.search_artists(query='artist:'+name,limit=limit)['artist-list'] except WebServiceError, e: logger.warn('Attempt to query MusicBrainz for %s failed (%s)' % (name, str(e))) time.sleep(5) if not artistResults: return False for result in artistResults: if 'disambiguation' in result: uniquename = unicode(result['sort-name'] + " (" + result['disambiguation'] + ")") else: uniquename = unicode(result['sort-name']) if result['name'] != uniquename and limit == 1: logger.info('Found an artist with a disambiguation: %s - doing an album based search' % name) artistdict = findArtistbyAlbum(name) if not artistdict: logger.info('Cannot determine the best match from an artist/album search. Using top match instead') artistlist.append({ # Just need the artist id if the limit is 1 # 'name': unicode(result['sort-name']), # 'uniquename': uniquename, 'id': unicode(result['id']), # 'url': unicode("http://musicbrainz.org/artist/" + result['id']),#probably needs to be changed # 'score': int(result['ext:score']) }) else: artistlist.append(artistdict) else: artistlist.append({ 'name': unicode(result['sort-name']), 'uniquename': uniquename, 'id': unicode(result['id']), 'url': unicode("http://musicbrainz.org/artist/" + result['id']),#probably needs to be changed 'score': int(result['ext:score']) }) return artistlist
def findAlbumID(artist=None, album=None): f = ws.ReleaseGroupFilter(title=album, artistName=artist, limit=1) results = None attempt = 0 while attempt < 5: try: results = q.getReleaseGroups(f) break except Exception, e: logger.warn( 'Attempt to query MusicBrainz for %s - %s failed: %s. Sleeping 5 seconds.' % (artist, album, e)) attempt += 1 time.sleep(5)
def preserve_torrent_directory(albumpath): """ Copy torrent directory to headphones-modified to keep files for seeding. """ from headphones import logger new_folder = os.path.join(albumpath, 'headphones-modified'.encode(headphones.SYS_ENCODING, 'replace')) logger.info( "Copying files to 'headphones-modified' subfolder to preserve downloaded files for seeding") try: shutil.copytree(albumpath, new_folder) return new_folder except Exception as e: logger.warn("Cannot copy/move files to temp folder: " + \ new_folder.decode(headphones.SYS_ENCODING, 'replace') + \ ". Not continuing. Error: " + str(e)) return None
def getLyrics(artist, song): params = { "artist": artist.encode('utf-8'), "song": song.encode('utf-8'), "fmt": 'xml' } url = 'http://lyrics.wikia.com/api.php' data = request.request_minidom(url, params=params) if not data: return url = data.getElementsByTagName("url") if url: lyricsurl = url[0].firstChild.nodeValue else: logger.info('No lyrics found for %s - %s' % (artist, song)) return lyricspage = request.request_content(lyricsurl) if not lyricspage: logger.warn('Error fetching lyrics from: %s' % lyricsurl) return m = re.compile( '''<div class='lyricbox'><div class='rtMatcher'>.*?</div>(.*?)<!--''' ).search(lyricspage) if not m: m = re.compile( '''<div class='lyricbox'><span style="padding:1em"><a href="/Category:Instrumental" title="Instrumental">''' ).search(lyricspage) if m: return u'(Instrumental)' else: logger.warn('Cannot find lyrics on: %s' % lyricsurl) return lyrics = convert_html_entities(m.group(1)).replace('<br />', '\n') lyrics = re.sub('<.*?>', '', lyrics) return lyrics
def findArtistbyAlbum(name): myDB = db.DBConnection() artist = myDB.action( 'SELECT AlbumTitle from have WHERE ArtistName=? AND AlbumTitle IS NOT NULL ORDER BY RANDOM()', [name]).fetchone() if not artist: return False # Probably not neccessary but just want to double check if not artist['AlbumTitle']: return False term = '"' + artist['AlbumTitle'] + '" AND artist:"' + name + '"' results = None try: with mb_lock: results = musicbrainzngs.search_release_groups(term).get( 'release-group-list') except musicbrainzngs.WebServiceError as e: logger.warn('Attempt to query MusicBrainz for %s failed (%s)' % (name, str(e))) mb_lock.snooze(5) if not results: return False artist_dict = {} for releaseGroup in results: newArtist = releaseGroup['artist-credit'][0]['artist'] # Only need the artist ID if we're doing an artist+album lookup #if 'disambiguation' in newArtist: # uniquename = unicode(newArtist['sort-name'] + " (" + newArtist['disambiguation'] + ")") #else: # uniquename = unicode(newArtist['sort-name']) #artist_dict['name'] = unicode(newArtist['sort-name']) #artist_dict['uniquename'] = uniquename artist_dict['id'] = unicode(newArtist['id']) #artist_dict['url'] = u'http://musicbrainz.org/artist/' + newArtist['id'] #artist_dict['score'] = int(releaseGroup['ext:score']) return artist_dict
def _sendjson(self, host, method, params={}): data = [{'id': 0, 'jsonrpc': '2.0', 'method': method, 'params': params}] data = simplejson.JSONEncoder().encode(data) content = {'Content-Type': 'application/json', 'Content-Length': len(data)} req = urllib2.Request(host+'/jsonrpc', data, content) if self.username and self.password: base64string = base64.encodestring('%s:%s' % (self.username, self.password)).replace('\n', '') req.add_header("Authorization", "Basic %s" % base64string) try: handle = urllib2.urlopen(req) except Exception, e: logger.warn('Error opening XBMC url: %s' % e) return
def startmb(): mbuser = None mbpass = None if headphones.CONFIG.MIRROR == "musicbrainz.org": mbhost = "musicbrainz.org" mbport = 80 sleepytime = 1 elif headphones.CONFIG.MIRROR == "custom": mbhost = headphones.CONFIG.CUSTOMHOST mbport = int(headphones.CONFIG.CUSTOMPORT) sleepytime = int(headphones.CONFIG.CUSTOMSLEEP) elif headphones.CONFIG.MIRROR == "headphones": mbhost = "144.76.94.239" mbport = 8181 mbuser = headphones.CONFIG.HPUSER mbpass = headphones.CONFIG.HPPASS sleepytime = 0 else: return False musicbrainzngs.set_useragent("headphones", "0.0", "https://github.com/rembo10/headphones") musicbrainzngs.set_hostname(mbhost + ":" + str(mbport)) # Their rate limiting should be redundant to our lock if sleepytime == 0: musicbrainzngs.set_rate_limit(False) else: #calling it with an it ends up blocking all requests after the first musicbrainzngs.set_rate_limit(limit_or_interval=float(sleepytime)) mb_lock.minimum_delta = sleepytime # Add headphones credentials if headphones.CONFIG.MIRROR == "headphones": if not mbuser and mbpass: logger.warn("No username or password set for VIP server") else: musicbrainzngs.hpauth(mbuser, mbpass) logger.debug( 'Using the following server values: MBHost: %s, MBPort: %i, Sleep Interval: %i', mbhost, mbport, sleepytime) return True
def findRelease(name, limit=1): with mb_lock: releaselistngs = [] releaseResultsngs = None chars = set('!?') if any((c in chars) for c in name): name = '"' + name + '"' q, sleepytime = startmb(forcemb=True) try: releaseResultsngs = musicbrainzngs.search_releases( query=name, limit=limit)['release-list'] except WebServiceError, e: #need to update exceptions logger.warn('Attempt to query MusicBrainz for "%s" failed: %s' % (name, str(e))) time.sleep(5) time.sleep(sleepytime) if not releaseResultsngs: return False for result in releaseResultsngs: releaselistngs.append({ 'uniquename': unicode(result['artist-credit'][0]['artist']['name']), 'title': unicode(result['title']), 'id': unicode(result['artist-credit'][0]['artist']['id']), 'albumid': unicode(result['id']), 'url': unicode("http://musicbrainz.org/artist/" + result['artist-credit'][0]['artist']['id'] ), #probably needs to be changed 'albumurl': unicode("http://musicbrainz.org/release/" + result['id']), #probably needs to be changed 'score': int(result['ext:score']) }) return releaselistngs
def notify(self, title, subtitle=None, text=None, sound=True, image=None): try: self.swizzle( self.objc.lookUpClass('NSBundle'), 'bundleIdentifier', self.swizzled_bundleIdentifier ) NSUserNotification = self.objc.lookUpClass('NSUserNotification') NSUserNotificationCenter = self.objc.lookUpClass( 'NSUserNotificationCenter') NSAutoreleasePool = self.objc.lookUpClass('NSAutoreleasePool') if not NSUserNotification or not NSUserNotificationCenter: return False pool = NSAutoreleasePool.alloc().init() notification = NSUserNotification.alloc().init() notification.setTitle_(title) if subtitle: notification.setSubtitle_(subtitle) if text: notification.setInformativeText_(text) if sound: notification.setSoundName_( "NSUserNotificationDefaultSoundName") if image: source_img = self.AppKit.NSImage.alloc().\ initByReferencingFile_(image) notification.setContentImage_(source_img) # notification.set_identityImage_(source_img) notification.setHasActionButton_(False) notification_center = NSUserNotificationCenter.\ defaultUserNotificationCenter() notification_center.deliverNotification_(notification) del pool return True except Exception as e: logger.warn('Error sending OS X Notification: %s' % e) return False
def checkGithub(): headphones.COMMITS_BEHIND = 0 # Get the latest version available from github logger.info('Retrieving latest version information from GitHub') url = 'https://api.github.com/repos/%s/headphones/commits/%s' % (headphones.GIT_USER, headphones.GIT_BRANCH) version = request.request_json(url, timeout=20, validator=lambda x: type(x) == dict) if version is None: logger.warn('Could not get the latest version from GitHub. Are you running a local development version?') return headphones.CURRENT_VERSION headphones.LATEST_VERSION = version['sha'] logger.debug("Latest version is %s", headphones.LATEST_VERSION) # See how many commits behind we are if not headphones.CURRENT_VERSION: logger.info('You are running an unknown version of Headphones. Run the updater to identify your version') return headphones.LATEST_VERSION if headphones.LATEST_VERSION == headphones.CURRENT_VERSION: logger.info('Headphones is up to date') return headphones.LATEST_VERSION logger.info('Comparing currently installed version with latest GitHub version') url = 'https://api.github.com/repos/%s/headphones/compare/%s...%s' % (headphones.GIT_USER, headphones.LATEST_VERSION, headphones.CURRENT_VERSION) commits = request.request_json(url, timeout=20, whitelist_status_code=404, validator=lambda x: type(x) == dict) if commits is None: logger.warn('Could not get commits behind from GitHub.') return headphones.LATEST_VERSION try: headphones.COMMITS_BEHIND = int(commits['behind_by']) logger.debug("In total, %d commits behind", headphones.COMMITS_BEHIND) except KeyError: logger.info('Cannot compare versions. Are you running a local development version?') headphones.COMMITS_BEHIND = 0 if headphones.COMMITS_BEHIND > 0: logger.info('New version is available. You are %s commits behind' % headphones.COMMITS_BEHIND) elif headphones.COMMITS_BEHIND == 0: logger.info('Headphones is up to date') return headphones.LATEST_VERSION
def checkConfig(): params = { 'mode': 'get_config', 'section': 'misc', } config_options = sab_api_call(params=params) if not config_options: logger.warn( "Unable to read SABnzbd config file - cannot determine renaming options (might affect auto & forced post processing)" ) return (0, 0) replace_spaces = config_options['config']['misc']['replace_spaces'] replace_dots = config_options['config']['misc']['replace_dots'] return (replace_spaces, replace_dots)
def getCachedArt(albumid): from headphones import cache c = cache.Cache() artwork_path = c.get_artwork_from_cache(AlbumID=albumid) if not artwork_path: return if artwork_path.startswith('http://'): artwork = request.request_content(artwork_path, timeout=20) if not artwork: logger.warn("Unable to open url: %s", artwork_path) return else: with open(artwork_path, "r") as fp: return fp.read()
def notify(self, artist, album, albumartpath): header = "Headphones" message = "%s - %s added to your library" % (artist, album) time = "3000" # in ms notification = header + "," + message + "," + time + "," + albumartpath notifycommand = { 'command': 'ExecBuiltIn', 'parameter': 'Notification(' + notification + ')' } logger.info('Sending notification command to XMBC') request = self._send(notifycommand) if not request: logger.warn('Error sending notification request to XBMC')
def artistlist_to_mbids(artistlist, forced=False): for artist in artistlist: if forced: artist = unicode(artist, 'utf-8') results = mb.findArtist(artist, limit=1) if not results: logger.info('No results found for: %s' % artist) continue try: artistid = results[0]['id'] except IndexError: logger.info('MusicBrainz query turned up no matches for: %s' % artist) continue # Add to database if it doesn't exist if artistid != various_artists_mbid and not is_exists(artistid): addArtisttoDB(artistid) # Just update the tracks if it does else: myDB = db.DBConnection() havetracks = len( myDB.select('SELECT TrackTitle from tracks WHERE ArtistID=?', [ artistid ])) + len( myDB.select( 'SELECT TrackTitle from have WHERE ArtistName like ?', [artist])) myDB.action('UPDATE artists SET HaveTracks=? WHERE ArtistID=?', [havetracks, artistid]) # Update the similar artist tag cloud: logger.info('Updating artist information from Last.fm') try: lastfm.getSimilar() except Exception, e: logger.warn('Failed to update arist information from Last.fm: %s' % e)
def notify(self, artist=None, album=None, snatched_nzb=None): apikey = self.apikey priority = self.priority if snatched_nzb: event = snatched_nzb + " snatched!" description = "Headphones has snatched: " + snatched_nzb + " and has sent it to SABnzbd+" else: event = artist + ' - ' + album + ' complete!' description = "Headphones has downloaded and postprocessed: " + artist + ' [' + album + ']' data = { 'apikey': apikey, 'application':'Headphones', 'event': event, 'description': description, 'priority': priority} logger.info('Sending notification request to NotifyMyAndroid') request = self._send(data) if not request: logger.warn('Error sending notification request to NotifyMyAndroid')
def startmb(): mbuser = None mbpass = None if headphones.MIRROR == "musicbrainz.org": mbhost = "musicbrainz.org" mbport = 80 sleepytime = 1 elif headphones.MIRROR == "custom": mbhost = headphones.CUSTOMHOST mbport = int(headphones.CUSTOMPORT) sleepytime = int(headphones.CUSTOMSLEEP) elif headphones.MIRROR == "headphones": mbhost = "178.63.142.150" mbport = 8181 mbuser = headphones.HPUSER mbpass = headphones.HPPASS sleepytime = 0 else: return False musicbrainzngs.set_useragent("headphones", "0.0", "https://github.com/rembo10/headphones") musicbrainzngs.set_hostname(mbhost + ":" + str(mbport)) if sleepytime == 0: musicbrainzngs.set_rate_limit(False) else: #calling it with an it ends up blocking all requests after the first musicbrainzngs.set_rate_limit(limit_or_interval=float(sleepytime)) # Add headphones credentials if headphones.MIRROR == "headphones": if not mbuser and mbpass: logger.warn("No username or password set for VIP server") else: musicbrainzngs.hpauth(mbuser, mbpass) logger.debug( 'Using the following server values:\nMBHost: %s ; MBPort: %i ; Sleep Interval: %i ' % (mbhost, mbport, sleepytime)) return True
def findSeries(name, limit=1): serieslist = [] seriesResults = None chars = set('!?*-') if any((c in chars) for c in name): name = '"' + name + '"' criteria = {'series': name.lower()} with mb_lock: try: seriesResults = musicbrainzngs.search_series( limit=limit, **criteria)['series-list'] except musicbrainzngs.WebServiceError as e: logger.warn('Attempt to query MusicBrainz for %s failed (%s)' % (name, str(e))) mb_lock.snooze(5) if not seriesResults: return False for result in seriesResults: if 'disambiguation' in result: uniquename = unicode(result['name'] + " (" + result['disambiguation'] + ")") else: uniquename = unicode(result['name']) serieslist.append({ 'uniquename': uniquename, 'name': unicode(result['name']), 'type': unicode(result['type']), 'id': unicode(result['id']), 'url': unicode("http://musicbrainz.org/series/" + result['id']), #probably needs to be changed 'score': int(result['ext:score']) }) return serieslist
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 daemonize(): if threading.activeCount() != 1: logger.warn('There are %r active threads. Daemonizing may cause \ strange behavior.' % threading.enumerate()) sys.stdout.flush() sys.stderr.flush() # Do first fork try: pid = os.fork() if pid == 0: pass else: # Exit the parent process logger.debug('Forking once...') os._exit(0) except OSError, e: sys.exit("1st fork failed: %s [%d]" % (e.strerror, e.errno))
def correctMetadata(albumid, release, downloaded_track_list): logger.info('Preparing to write metadata to tracks....') lossy_items = [] lossless_items = [] # Process lossless & lossy media formats separately for downloaded_track in downloaded_track_list: try: if any(downloaded_track.lower().endswith('.' + x.lower()) for x in headphones.LOSSLESS_MEDIA_FORMATS): lossless_items.append(beets.library.Item.from_path(downloaded_track)) elif any(downloaded_track.lower().endswith('.' + x.lower()) for x in headphones.LOSSY_MEDIA_FORMATS): lossy_items.append(beets.library.Item.from_path(downloaded_track)) else: logger.warn("Skipping: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace') + " because it is not a mutagen friendly file format") except Exception, e: logger.error("Beets couldn't create an Item from: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace') + " - not a media file?" + str(e))
def getArtist(artistid, extrasonly=False): with mb_lock: artist_dict = {} artist = None try: limit = 200 artist = musicbrainzngs.get_artist_by_id(artistid)['artist'] newRgs = None artist['release-group-list'] = [] while newRgs == None or len(newRgs) >= limit: newRgs = musicbrainzngs.browse_release_groups(artistid,release_type="album",offset=len(artist['release-group-list']),limit=limit)['release-group-list'] artist['release-group-list'] += newRgs except WebServiceError, e: logger.warn('Attempt to retrieve artist information from MusicBrainz failed for artistid: %s (%s)' % (artistid, str(e))) time.sleep(5) except Exception,e: pass
def action(self, query, args=None): if query == None: return sqlResult = None try: with self.connection as c: if args == None: sqlResult = c.execute(query) else: sqlResult = c.execute(query, args) except sqlite3.OperationalError, e: if "unable to open database file" in e.message or "database is locked" in e.message: logger.warn('Database Error: %s', e) else: logger.error('Database error: %s', e) raise
def getReleaseGroup(rgid): """ Returns a list of releases in a release group """ with mb_lock: releaselist = [] releaseGroup = None try: releaseGroup = musicbrainzngs.get_release_group_by_id(rgid,["artists","releases","media","discids",])['release-group'] except musicbrainzngs.WebServiceError as e: logger.warn('Attempt to retrieve information from MusicBrainz for release group "%s" failed (%s)' % (rgid, str(e))) time.sleep(5) if not releaseGroup: return False else: return releaseGroup['release-list']