Example #1
0
 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
Example #2
0
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])
Example #3
0
    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
Example #4
0
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)
Example #5
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)
            )
Example #6
0
    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
Example #7
0
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],
                )
Example #8
0
    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)
Example #9
0
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
Example #10
0
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
Example #11
0
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
Example #12
0
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
Example #13
0
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
Example #14
0
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
Example #15
0
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)
Example #16
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
Example #17
0
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)
Example #18
0
 def __init__(self):
     try:
         self.objc = __import__("objc")
         self.AppKit = __import__("AppKit")
     except:
         logger.warn('OS X Notification: Cannot import objc or AppKit')
         pass
Example #19
0
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)
Example #20
0
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)
Example #21
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
Example #22
0
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
Example #23
0
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
Example #24
0
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
Example #25
0
    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')
Example #26
0
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))
Example #27
0
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
Example #28
0
    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
Example #29
0
    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
Example #30
0
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)	
Example #31
0
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)
Example #32
0
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
Example #33
0
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
Example #34
0
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
Example #35
0
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)
Example #36
0
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))
Example #37
0
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
Example #38
0
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
Example #39
0
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)
Example #40
0
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
Example #41
0
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
Example #42
0
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
Example #43
0
    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
Example #44
0
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
Example #45
0
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
Example #46
0
    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
Example #47
0
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
Example #48
0
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)
Example #49
0
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()
Example #50
0
    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')
Example #51
0
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)
Example #52
0
    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')        
Example #53
0
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
Example #54
0
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
Example #55
0
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
Example #56
0
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))
Example #58
0
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
Example #59
0
    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
Example #60
0
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']