CoSome general cleanup. Converted all tabs to spaces for consistency, removed templates.py as it was no longer being used

This commit is contained in:
rembo10
2012-06-19 12:46:44 +05:30
parent 755b5082c7
commit a3f6d90f74
21 changed files with 3160 additions and 3601 deletions

View File

@@ -325,7 +325,7 @@ def initialize():
INTERFACE = check_setting_str(CFG, 'General', 'interface', 'default')
FOLDER_PERMISSIONS = check_setting_str(CFG, 'General', 'folder_permissions', '0755')
ENCODERFOLDER = check_setting_str(CFG, 'General', 'encoderfolder', '')
ENCODER = check_setting_str(CFG, 'General', 'encoder', 'ffmpeg')
BITRATE = check_setting_int(CFG, 'General', 'bitrate', 192)
@@ -363,7 +363,7 @@ def initialize():
# update folder formats in the config & bump up config version
if CONFIG_VERSION == '0':
from headphones.helpers import replace_all
file_values = { 'tracknumber': 'Track', 'title': 'Title','artist' : 'Artist', 'album' : 'Album', 'year' : 'Year' }
file_values = { 'tracknumber': 'Track', 'title': 'Title','artist' : 'Artist', 'album' : 'Album', 'year' : 'Year' }
folder_values = { 'artist' : 'Artist', 'album':'Album', 'year' : 'Year', 'releasetype' : 'Type', 'first' : 'First', 'lowerfirst' : 'first' }
FILE_FORMAT = replace_all(FILE_FORMAT, file_values)
FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values)
@@ -372,34 +372,34 @@ def initialize():
if CONFIG_VERSION == '1':
from headphones.helpers import replace_all
from headphones.helpers import replace_all
file_values = { 'Track': '$Track',
'Title': '$Title',
'Artist': '$Artist',
'Album': '$Album',
'Year': '$Year',
'track': '$track',
'title': '$title',
'artist': '$artist',
'album': '$album',
'year': '$year'
}
folder_values = { 'Artist': '$Artist',
'Album': '$Album',
'Year': '$Year',
'Type': '$Type',
'First': '$First',
'artist': '$artist',
'album': '$album',
'year': '$year',
'type': '$type',
'first': '$first'
}
FILE_FORMAT = replace_all(FILE_FORMAT, file_values)
FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values)
CONFIG_VERSION = '2'
file_values = { 'Track': '$Track',
'Title': '$Title',
'Artist': '$Artist',
'Album': '$Album',
'Year': '$Year',
'track': '$track',
'title': '$title',
'artist': '$artist',
'album': '$album',
'year': '$year'
}
folder_values = { 'Artist': '$Artist',
'Album': '$Album',
'Year': '$Year',
'Type': '$Type',
'First': '$First',
'artist': '$artist',
'album': '$album',
'year': '$year',
'type': '$type',
'first': '$first'
}
FILE_FORMAT = replace_all(FILE_FORMAT, file_values)
FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values)
CONFIG_VERSION = '2'
if not LOG_DIR:
LOG_DIR = os.path.join(DATA_DIR, 'logs')
@@ -435,12 +435,12 @@ def initialize():
# Check for new versions
if CHECK_GITHUB_ON_STARTUP:
try:
LATEST_VERSION = versioncheck.checkGithub()
except:
LATEST_VERSION = CURRENT_VERSION
try:
LATEST_VERSION = versioncheck.checkGithub()
except:
LATEST_VERSION = CURRENT_VERSION
else:
LATEST_VERSION = CURRENT_VERSION
LATEST_VERSION = CURRENT_VERSION
__INITIALIZED__ = True
return True
@@ -766,9 +766,9 @@ def shutdown(restart=False, update=False):
config_write()
if not restart and not update:
logger.info('Headphones is shutting down...')
logger.info('Headphones is shutting down...')
if update:
logger.info('Headphones is updating...')
logger.info('Headphones is updating...')
try:
versioncheck.update()
except Exception, e:
@@ -779,7 +779,7 @@ def shutdown(restart=False, update=False):
os.remove(PIDFILE)
if restart:
logger.info('Headphones is restarting...')
logger.info('Headphones is restarting...')
popen_list = [sys.executable, FULL_PATH]
popen_list += ARGS
if '--nolaunch' not in popen_list:

View File

@@ -2,9 +2,9 @@ from headphones import db
def getAlbumArt(albumid):
myDB = db.DBConnection()
asin = myDB.action('SELECT AlbumASIN from albums WHERE AlbumID=?', [albumid]).fetchone()[0]
url = 'http://ec1.images-amazon.com/images/P/%s.01.LZZZZZZZ.jpg' % asin
return url
myDB = db.DBConnection()
asin = myDB.action('SELECT AlbumASIN from albums WHERE AlbumID=?', [albumid]).fetchone()[0]
url = 'http://ec1.images-amazon.com/images/P/%s.01.LZZZZZZZ.jpg' % asin
return url

View File

@@ -7,295 +7,295 @@ from xml.dom.minidom import Document
import copy
cmd_list = [ 'getIndex', 'getArtist', 'getAlbum', 'getUpcoming', 'getWanted', 'getSimilar', 'getHistory', 'getLogs',
'findArtist', 'findAlbum', 'addArtist', 'delArtist', 'pauseArtist', 'resumeArtist', 'refreshArtist',
'queueAlbum', 'unqueueAlbum', 'forceSearch', 'forceProcess', 'getVersion', 'checkGithub',
'shutdown', 'restart', 'update', ]
'findArtist', 'findAlbum', 'addArtist', 'delArtist', 'pauseArtist', 'resumeArtist', 'refreshArtist',
'queueAlbum', 'unqueueAlbum', 'forceSearch', 'forceProcess', 'getVersion', 'checkGithub',
'shutdown', 'restart', 'update', ]
class Api(object):
def __init__(self):
self.apikey = None
self.cmd = None
self.id = None
self.kwargs = None
def __init__(self):
self.apikey = None
self.cmd = None
self.id = None
self.kwargs = None
self.data = None
self.data = None
self.callback = None
self.callback = None
def checkParams(self,*args,**kwargs):
if not headphones.API_ENABLED:
self.data = 'API not enabled'
return
if not headphones.API_KEY:
self.data = 'API key not generated'
return
if len(headphones.API_KEY) != 32:
self.data = 'API key not generated correctly'
return
if 'apikey' not in kwargs:
self.data = 'Missing api key'
return
if kwargs['apikey'] != headphones.API_KEY:
self.data = 'Incorrect API key'
return
else:
self.apikey = kwargs.pop('apikey')
if 'cmd' not in kwargs:
self.data = 'Missing parameter: cmd'
return
if kwargs['cmd'] not in cmd_list:
self.data = 'Unknown command: %s' % kwargs['cmd']
return
else:
self.cmd = kwargs.pop('cmd')
self.kwargs = kwargs
self.data = 'OK'
def checkParams(self,*args,**kwargs):
if not headphones.API_ENABLED:
self.data = 'API not enabled'
return
if not headphones.API_KEY:
self.data = 'API key not generated'
return
if len(headphones.API_KEY) != 32:
self.data = 'API key not generated correctly'
return
if 'apikey' not in kwargs:
self.data = 'Missing api key'
return
if kwargs['apikey'] != headphones.API_KEY:
self.data = 'Incorrect API key'
return
else:
self.apikey = kwargs.pop('apikey')
if 'cmd' not in kwargs:
self.data = 'Missing parameter: cmd'
return
if kwargs['cmd'] not in cmd_list:
self.data = 'Unknown command: %s' % kwargs['cmd']
return
else:
self.cmd = kwargs.pop('cmd')
self.kwargs = kwargs
self.data = 'OK'
def fetchData(self):
if self.data == 'OK':
logger.info('Recieved API command: ' + self.cmd)
methodToCall = getattr(self, "_" + self.cmd)
result = methodToCall(**self.kwargs)
if 'callback' not in self.kwargs:
if type(self.data) == type(''):
return self.data
else:
return simplejson.dumps(self.data)
else:
self.callback = self.kwargs['callback']
self.data = simplejson.dumps(self.data)
self.data = self.callback + '(' + self.data + ');'
return self.data
else:
return self.data
def _dic_from_query(self,query):
myDB = db.DBConnection()
rows = myDB.select(query)
rows_as_dic = []
for row in rows:
row_as_dic = dict(zip(row.keys(), row))
rows_as_dic.append(row_as_dic)
return rows_as_dic
def _getIndex(self, **kwargs):
self.data = self._dic_from_query('SELECT * from artists order by ArtistSortName COLLATE NOCASE')
return
def _getArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
artist = self._dic_from_query('SELECT * from artists WHERE ArtistID="' + self.id + '"')
albums = self._dic_from_query('SELECT * from albums WHERE ArtistID="' + self.id + '" order by ReleaseDate DESC')
self.data = { 'artist': artist, 'albums': albums }
return
def _getAlbum(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
album = self._dic_from_query('SELECT * from albums WHERE AlbumID="' + self.id + '"')
tracks = self._dic_from_query('SELECT * from tracks WHERE AlbumID="' + self.id + '"')
description = self._dic_from_query('SELECT * from descriptions WHERE ReleaseGroupID="' + self.id + '"')
self.data = { 'album' : album, 'tracks' : tracks, 'description' : description }
return
def _getHistory(self, **kwargs):
self.data = self._dic_from_query('SELECT * from snatched order by DateAdded DESC')
return
def _getUpcoming(self, **kwargs):
self.data = self._dic_from_query("SELECT * from albums WHERE ReleaseDate > date('now') order by ReleaseDate DESC")
return
def _getWanted(self, **kwargs):
self.data = self._dic_from_query("SELECT * from albums WHERE Status='Wanted'")
return
def _getSimilar(self, **kwargs):
self.data = self._dic_from_query('SELECT * from lastfmcloud')
return
def _getLogs(self, **kwargs):
pass
def _findArtist(self, **kwargs):
if 'name' not in kwargs:
self.data = 'Missing parameter: name'
return
if 'limit' in kwargs:
limit = kwargs['limit']
else:
limit=50
self.data = mb.findArtist(kwargs['name'], limit)
def fetchData(self):
if self.data == 'OK':
logger.info('Recieved API command: ' + self.cmd)
methodToCall = getattr(self, "_" + self.cmd)
result = methodToCall(**self.kwargs)
if 'callback' not in self.kwargs:
if type(self.data) == type(''):
return self.data
else:
return simplejson.dumps(self.data)
else:
self.callback = self.kwargs['callback']
self.data = simplejson.dumps(self.data)
self.data = self.callback + '(' + self.data + ');'
return self.data
else:
return self.data
def _dic_from_query(self,query):
myDB = db.DBConnection()
rows = myDB.select(query)
rows_as_dic = []
for row in rows:
row_as_dic = dict(zip(row.keys(), row))
rows_as_dic.append(row_as_dic)
return rows_as_dic
def _getIndex(self, **kwargs):
self.data = self._dic_from_query('SELECT * from artists order by ArtistSortName COLLATE NOCASE')
return
def _getArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
artist = self._dic_from_query('SELECT * from artists WHERE ArtistID="' + self.id + '"')
albums = self._dic_from_query('SELECT * from albums WHERE ArtistID="' + self.id + '" order by ReleaseDate DESC')
self.data = { 'artist': artist, 'albums': albums }
return
def _getAlbum(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
album = self._dic_from_query('SELECT * from albums WHERE AlbumID="' + self.id + '"')
tracks = self._dic_from_query('SELECT * from tracks WHERE AlbumID="' + self.id + '"')
description = self._dic_from_query('SELECT * from descriptions WHERE ReleaseGroupID="' + self.id + '"')
self.data = { 'album' : album, 'tracks' : tracks, 'description' : description }
return
def _getHistory(self, **kwargs):
self.data = self._dic_from_query('SELECT * from snatched order by DateAdded DESC')
return
def _getUpcoming(self, **kwargs):
self.data = self._dic_from_query("SELECT * from albums WHERE ReleaseDate > date('now') order by ReleaseDate DESC")
return
def _getWanted(self, **kwargs):
self.data = self._dic_from_query("SELECT * from albums WHERE Status='Wanted'")
return
def _getSimilar(self, **kwargs):
self.data = self._dic_from_query('SELECT * from lastfmcloud')
return
def _getLogs(self, **kwargs):
pass
def _findArtist(self, **kwargs):
if 'name' not in kwargs:
self.data = 'Missing parameter: name'
return
if 'limit' in kwargs:
limit = kwargs['limit']
else:
limit=50
self.data = mb.findArtist(kwargs['name'], limit)
def _findAlbum(self, **kwargs):
if 'name' not in kwargs:
self.data = 'Missing parameter: name'
return
if 'limit' in kwargs:
limit = kwargs['limit']
else:
limit=50
self.data = mb.findRelease(kwargs['name'], limit)
def _addArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
try:
importer.addArtisttoDB(self.id)
except Exception, e:
self.data = e
return
def _delArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
myDB = db.DBConnection()
myDB.action('DELETE from artists WHERE ArtistID="' + self.id + '"')
myDB.action('DELETE from albums WHERE ArtistID="' + self.id + '"')
myDB.action('DELETE from tracks WHERE ArtistID="' + self.id + '"')
def _pauseArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
myDB = db.DBConnection()
controlValueDict = {'ArtistID': self.id}
newValueDict = {'Status': 'Paused'}
myDB.upsert("artists", newValueDict, controlValueDict)
def _resumeArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
myDB = db.DBConnection()
controlValueDict = {'ArtistID': self.id}
newValueDict = {'Status': 'Active'}
myDB.upsert("artists", newValueDict, controlValueDict)
def _refreshArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
try:
importer.addArtisttoDB(self.id)
except Exception, e:
self.data = e
return
def _queueAlbum(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
if 'new' in kwargs:
new = kwargs['new']
else:
new = False
if 'lossless' in kwargs:
lossless = kwargs['lossless']
else:
lossless = False
myDB = db.DBConnection()
controlValueDict = {'AlbumID': self.id}
if lossless:
newValueDict = {'Status': 'Wanted Lossless'}
else:
newValueDict = {'Status': 'Wanted'}
myDB.upsert("albums", newValueDict, controlValueDict)
searcher.searchforalbum(self.id, new)
def _unqueueAlbum(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
myDB = db.DBConnection()
controlValueDict = {'AlbumID': self.id}
newValueDict = {'Status': 'Skipped'}
myDB.upsert("albums", newValueDict, controlValueDict)
def _forceSearch(self, **kwargs):
searcher.searchforalbum()
def _forceProcess(self, **kwargs):
postprocessor.forcePostProcess()
def _getVersion(self, **kwargs):
self.data = {
'git_path' : headphones.GIT_PATH,
'install_type' : headphones.INSTALL_TYPE,
'current_version' : headphones.CURRENT_VERSION,
'latest_version' : headphones.LATEST_VERSION,
'commits_behind' : headphones.COMMITS_BEHIND,
}
def _checkGithub(self, **kwargs):
versioncheck.checkGithub()
self._getVersion()
def _shutdown(self, **kwargs):
headphones.SIGNAL = 'shutdown'
def _restart(self, **kwargs):
headphones.SIGNAL = 'restart'
def _update(self, **kwargs):
headphones.SIGNAL = 'update'
def _findAlbum(self, **kwargs):
if 'name' not in kwargs:
self.data = 'Missing parameter: name'
return
if 'limit' in kwargs:
limit = kwargs['limit']
else:
limit=50
self.data = mb.findRelease(kwargs['name'], limit)
def _addArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
try:
importer.addArtisttoDB(self.id)
except Exception, e:
self.data = e
return
def _delArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
myDB = db.DBConnection()
myDB.action('DELETE from artists WHERE ArtistID="' + self.id + '"')
myDB.action('DELETE from albums WHERE ArtistID="' + self.id + '"')
myDB.action('DELETE from tracks WHERE ArtistID="' + self.id + '"')
def _pauseArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
myDB = db.DBConnection()
controlValueDict = {'ArtistID': self.id}
newValueDict = {'Status': 'Paused'}
myDB.upsert("artists", newValueDict, controlValueDict)
def _resumeArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
myDB = db.DBConnection()
controlValueDict = {'ArtistID': self.id}
newValueDict = {'Status': 'Active'}
myDB.upsert("artists", newValueDict, controlValueDict)
def _refreshArtist(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
try:
importer.addArtisttoDB(self.id)
except Exception, e:
self.data = e
return
def _queueAlbum(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
if 'new' in kwargs:
new = kwargs['new']
else:
new = False
if 'lossless' in kwargs:
lossless = kwargs['lossless']
else:
lossless = False
myDB = db.DBConnection()
controlValueDict = {'AlbumID': self.id}
if lossless:
newValueDict = {'Status': 'Wanted Lossless'}
else:
newValueDict = {'Status': 'Wanted'}
myDB.upsert("albums", newValueDict, controlValueDict)
searcher.searchforalbum(self.id, new)
def _unqueueAlbum(self, **kwargs):
if 'id' not in kwargs:
self.data = 'Missing parameter: id'
return
else:
self.id = kwargs['id']
myDB = db.DBConnection()
controlValueDict = {'AlbumID': self.id}
newValueDict = {'Status': 'Skipped'}
myDB.upsert("albums", newValueDict, controlValueDict)
def _forceSearch(self, **kwargs):
searcher.searchforalbum()
def _forceProcess(self, **kwargs):
postprocessor.forcePostProcess()
def _getVersion(self, **kwargs):
self.data = {
'git_path' : headphones.GIT_PATH,
'install_type' : headphones.INSTALL_TYPE,
'current_version' : headphones.CURRENT_VERSION,
'latest_version' : headphones.LATEST_VERSION,
'commits_behind' : headphones.COMMITS_BEHIND,
}
def _checkGithub(self, **kwargs):
versioncheck.checkGithub()
self._getVersion()
def _shutdown(self, **kwargs):
headphones.SIGNAL = 'shutdown'
def _restart(self, **kwargs):
headphones.SIGNAL = 'restart'
def _update(self, **kwargs):
headphones.SIGNAL = 'update'

View File

@@ -15,70 +15,70 @@ db_lock = threading.Lock()
def dbFilename(filename="headphones.db"):
return os.path.join(headphones.DATA_DIR, filename)
return os.path.join(headphones.DATA_DIR, filename)
class DBConnection:
def __init__(self, filename="headphones.db"):
self.filename = filename
self.connection = sqlite3.connect(dbFilename(filename), timeout=20)
self.connection.row_factory = sqlite3.Row
def action(self, query, args=None):
with db_lock:
def __init__(self, filename="headphones.db"):
self.filename = filename
self.connection = sqlite3.connect(dbFilename(filename), timeout=20)
self.connection.row_factory = sqlite3.Row
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
return sqlResult
def select(self, query, args=None):
sqlResults = self.action(query, args).fetchall()
if sqlResults == None:
return []
return sqlResults
def upsert(self, tableName, valueDict, keyDict):
changesBefore = self.connection.total_changes
genParams = lambda myDict : [x + " = ?" for x in myDict.keys()]
query = "UPDATE "+tableName+" SET " + ", ".join(genParams(valueDict)) + " WHERE " + " AND ".join(genParams(keyDict))
self.action(query, valueDict.values() + keyDict.values())
if self.connection.total_changes == changesBefore:
query = "INSERT INTO "+tableName+" (" + ", ".join(valueDict.keys() + keyDict.keys()) + ")" + \
" VALUES (" + ", ".join(["?"] * len(valueDict.keys() + keyDict.keys())) + ")"
self.action(query, valueDict.values() + keyDict.values())
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
return sqlResult
def select(self, query, args=None):
sqlResults = self.action(query, args).fetchall()
if sqlResults == None:
return []
return sqlResults
def upsert(self, tableName, valueDict, keyDict):
changesBefore = self.connection.total_changes
genParams = lambda myDict : [x + " = ?" for x in myDict.keys()]
query = "UPDATE "+tableName+" SET " + ", ".join(genParams(valueDict)) + " WHERE " + " AND ".join(genParams(keyDict))
self.action(query, valueDict.values() + keyDict.values())
if self.connection.total_changes == changesBefore:
query = "INSERT INTO "+tableName+" (" + ", ".join(valueDict.keys() + keyDict.keys()) + ")" + \
" VALUES (" + ", ".join(["?"] * len(valueDict.keys() + keyDict.keys())) + ")"
self.action(query, valueDict.values() + keyDict.values())

View File

@@ -20,120 +20,120 @@ def multikeysort(items, columns):
return sorted(items, cmp=comparer)
def checked(variable):
if variable:
return 'Checked'
else:
return ''
if variable:
return 'Checked'
else:
return ''
def radio(variable, pos):
if variable == pos:
return 'Checked'
else:
return ''
if variable == pos:
return 'Checked'
else:
return ''
def latinToAscii(unicrap):
"""
From couch potato
"""
xlate = {0xc0:'A', 0xc1:'A', 0xc2:'A', 0xc3:'A', 0xc4:'A', 0xc5:'A',
0xc6:'Ae', 0xc7:'C',
0xc8:'E', 0xc9:'E', 0xca:'E', 0xcb:'E', 0x86:'e',
0xcc:'I', 0xcd:'I', 0xce:'I', 0xcf:'I',
0xd0:'Th', 0xd1:'N',
0xd2:'O', 0xd3:'O', 0xd4:'O', 0xd5:'O', 0xd6:'O', 0xd8:'O',
0xd9:'U', 0xda:'U', 0xdb:'U', 0xdc:'U',
0xdd:'Y', 0xde:'th', 0xdf:'ss',
0xe0:'a', 0xe1:'a', 0xe2:'a', 0xe3:'a', 0xe4:'a', 0xe5:'a',
0xe6:'ae', 0xe7:'c',
0xe8:'e', 0xe9:'e', 0xea:'e', 0xeb:'e', 0x0259:'e',
0xec:'i', 0xed:'i', 0xee:'i', 0xef:'i',
0xf0:'th', 0xf1:'n',
0xf2:'o', 0xf3:'o', 0xf4:'o', 0xf5:'o', 0xf6:'o', 0xf8:'o',
0xf9:'u', 0xfa:'u', 0xfb:'u', 0xfc:'u',
0xfd:'y', 0xfe:'th', 0xff:'y',
0xa1:'!', 0xa2:'{cent}', 0xa3:'{pound}', 0xa4:'{currency}',
0xa5:'{yen}', 0xa6:'|', 0xa7:'{section}', 0xa8:'{umlaut}',
0xa9:'{C}', 0xaa:'{^a}', 0xab:'<<', 0xac:'{not}',
0xad:'-', 0xae:'{R}', 0xaf:'_', 0xb0:'{degrees}',
0xb1:'{+/-}', 0xb2:'{^2}', 0xb3:'{^3}', 0xb4:"'",
0xb5:'{micro}', 0xb6:'{paragraph}', 0xb7:'*', 0xb8:'{cedilla}',
0xb9:'{^1}', 0xba:'{^o}', 0xbb:'>>',
0xbc:'{1/4}', 0xbd:'{1/2}', 0xbe:'{3/4}', 0xbf:'?',
0xd7:'*', 0xf7:'/'
}
"""
From couch potato
"""
xlate = {0xc0:'A', 0xc1:'A', 0xc2:'A', 0xc3:'A', 0xc4:'A', 0xc5:'A',
0xc6:'Ae', 0xc7:'C',
0xc8:'E', 0xc9:'E', 0xca:'E', 0xcb:'E', 0x86:'e',
0xcc:'I', 0xcd:'I', 0xce:'I', 0xcf:'I',
0xd0:'Th', 0xd1:'N',
0xd2:'O', 0xd3:'O', 0xd4:'O', 0xd5:'O', 0xd6:'O', 0xd8:'O',
0xd9:'U', 0xda:'U', 0xdb:'U', 0xdc:'U',
0xdd:'Y', 0xde:'th', 0xdf:'ss',
0xe0:'a', 0xe1:'a', 0xe2:'a', 0xe3:'a', 0xe4:'a', 0xe5:'a',
0xe6:'ae', 0xe7:'c',
0xe8:'e', 0xe9:'e', 0xea:'e', 0xeb:'e', 0x0259:'e',
0xec:'i', 0xed:'i', 0xee:'i', 0xef:'i',
0xf0:'th', 0xf1:'n',
0xf2:'o', 0xf3:'o', 0xf4:'o', 0xf5:'o', 0xf6:'o', 0xf8:'o',
0xf9:'u', 0xfa:'u', 0xfb:'u', 0xfc:'u',
0xfd:'y', 0xfe:'th', 0xff:'y',
0xa1:'!', 0xa2:'{cent}', 0xa3:'{pound}', 0xa4:'{currency}',
0xa5:'{yen}', 0xa6:'|', 0xa7:'{section}', 0xa8:'{umlaut}',
0xa9:'{C}', 0xaa:'{^a}', 0xab:'<<', 0xac:'{not}',
0xad:'-', 0xae:'{R}', 0xaf:'_', 0xb0:'{degrees}',
0xb1:'{+/-}', 0xb2:'{^2}', 0xb3:'{^3}', 0xb4:"'",
0xb5:'{micro}', 0xb6:'{paragraph}', 0xb7:'*', 0xb8:'{cedilla}',
0xb9:'{^1}', 0xba:'{^o}', 0xbb:'>>',
0xbc:'{1/4}', 0xbd:'{1/2}', 0xbe:'{3/4}', 0xbf:'?',
0xd7:'*', 0xf7:'/'
}
r = ''
for i in unicrap:
if xlate.has_key(ord(i)):
r += xlate[ord(i)]
elif ord(i) >= 0x80:
pass
else:
r += str(i)
return r
r = ''
for i in unicrap:
if xlate.has_key(ord(i)):
r += xlate[ord(i)]
elif ord(i) >= 0x80:
pass
else:
r += str(i)
return r
def convert_milliseconds(ms):
seconds = ms/1000
gmtime = time.gmtime(seconds)
if seconds > 3600:
minutes = time.strftime("%H:%M:%S", gmtime)
else:
minutes = time.strftime("%M:%S", gmtime)
seconds = ms/1000
gmtime = time.gmtime(seconds)
if seconds > 3600:
minutes = time.strftime("%H:%M:%S", gmtime)
else:
minutes = time.strftime("%M:%S", gmtime)
return minutes
return minutes
def convert_seconds(s):
gmtime = time.gmtime(s)
if s > 3600:
minutes = time.strftime("%H:%M:%S", gmtime)
else:
minutes = time.strftime("%M:%S", gmtime)
gmtime = time.gmtime(s)
if s > 3600:
minutes = time.strftime("%H:%M:%S", gmtime)
else:
minutes = time.strftime("%M:%S", gmtime)
return minutes
return minutes
def today():
today = datetime.date.today()
yyyymmdd = datetime.date.isoformat(today)
return yyyymmdd
today = datetime.date.today()
yyyymmdd = datetime.date.isoformat(today)
return yyyymmdd
def now():
now = datetime.datetime.now()
return now.strftime("%Y-%m-%d %H:%M:%S")
now = datetime.datetime.now()
return now.strftime("%Y-%m-%d %H:%M:%S")
def bytes_to_mb(bytes):
mb = int(bytes)/1048576
size = '%.1f MB' % mb
return size
mb = int(bytes)/1048576
size = '%.1f MB' % mb
return size
def replace_all(text, dic):
for i, j in dic.iteritems():
text = text.replace(i, j)
return text
for i, j in dic.iteritems():
text = text.replace(i, j)
return text
def cleanName(string):
pass1 = latinToAscii(string).lower()
out_string = re.sub('[\.\-\/\!\@\#\$\%\^\&\*\(\)\+\-\"\'\,\;\:\[\]\{\}\<\>\=\_]', '', pass1).encode('utf-8')
return out_string
pass1 = latinToAscii(string).lower()
out_string = re.sub('[\.\-\/\!\@\#\$\%\^\&\*\(\)\+\-\"\'\,\;\:\[\]\{\}\<\>\=\_]', '', pass1).encode('utf-8')
return out_string
def cleanTitle(title):
title = re.sub('[\.\-\/\_]', ' ', title).lower()
# Strip out extra whitespace
title = ' '.join(title.split())
title = title.title()
return title
title = re.sub('[\.\-\/\_]', ' ', title).lower()
# Strip out extra whitespace
title = ' '.join(title.split())
title = title.title()
return title
def extract_data(s):
from headphones import logger
#headphones default format
@@ -161,18 +161,18 @@ def extract_data(s):
return (name, album, year)
def extract_logline(s):
# Default log format
pattern = re.compile(r'(?P<timestamp>.*?)\s\-\s(?P<level>.*?)\s*\:\:\s(?P<thread>.*?)\s\:\s(?P<message>.*)', re.VERBOSE)
match = pattern.match(s)
if match:
timestamp = match.group("timestamp")
level = match.group("level")
thread = match.group("thread")
message = match.group("message")
return (timestamp, level, thread, message)
else:
return None
# Default log format
pattern = re.compile(r'(?P<timestamp>.*?)\s\-\s(?P<level>.*?)\s*\:\:\s(?P<thread>.*?)\s\:\s(?P<message>.*)', re.VERBOSE)
match = pattern.match(s)
if match:
timestamp = match.group("timestamp")
level = match.group("level")
thread = match.group("thread")
message = match.group("message")
return (timestamp, level, thread, message)
else:
return None
def extract_song_data(s):
#headphones default format
@@ -202,4 +202,4 @@ def extract_song_data(s):
return (name, album, year)
else:
logger.info("Couldn't parse " + s + " into a valid Newbin format")
return (name, album, year)
return (name, album, year)

View File

@@ -7,369 +7,369 @@ import headphones
from headphones import logger, helpers, db, mb, albumart, lastfm
various_artists_mbid = '89ad4ac3-39f7-470e-963a-56509c546377'
def is_exists(artistid):
myDB = db.DBConnection()
# See if the artist is already in the database
artistlist = myDB.select('SELECT ArtistID, ArtistName from artists WHERE ArtistID=?', [artistid])
myDB = db.DBConnection()
# See if the artist is already in the database
artistlist = myDB.select('SELECT ArtistID, ArtistName from artists WHERE ArtistID=?', [artistid])
if any(artistid in x for x in artistlist):
logger.info(artistlist[0][1] + u" is already in the database. Updating 'have tracks', but not artist information")
return True
else:
return False
if any(artistid in x for x in artistlist):
logger.info(artistlist[0][1] + u" is already in the database. Updating 'have tracks', but not artist information")
return True
else:
return False
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)
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 addArtistIDListToDB(artistidlist):
# Used to add a list of artist IDs to the database in a single thread
logger.debug("Importer: Adding artist ids %s" % artistidlist)
for artistid in artistidlist:
addArtisttoDB(artistid)
# Used to add a list of artist IDs to the database in a single thread
logger.debug("Importer: Adding artist ids %s" % artistidlist)
for artistid in artistidlist:
addArtisttoDB(artistid)
def addArtisttoDB(artistid, extrasonly=False):
# Can't add various artists - throws an error from MB
if artistid == various_artists_mbid:
logger.warn('Cannot import Various Artists.')
return
myDB = db.DBConnection()
# Can't add various artists - throws an error from MB
if artistid == various_artists_mbid:
logger.warn('Cannot import Various Artists.')
return
myDB = db.DBConnection()
# We need the current minimal info in the database instantly
# so we don't throw a 500 error when we redirect to the artistPage
# We need the current minimal info in the database instantly
# so we don't throw a 500 error when we redirect to the artistPage
controlValueDict = {"ArtistID": artistid}
controlValueDict = {"ArtistID": artistid}
# Don't replace a known artist name with an "Artist ID" placeholder
# Don't replace a known artist name with an "Artist ID" placeholder
dbartist = myDB.action('SELECT * FROM artists WHERE ArtistID=?', [artistid]).fetchone()
if dbartist is None:
newValueDict = {"ArtistName": "Artist ID: %s" % (artistid),
"Status": "Loading"}
else:
newValueDict = {"Status": "Loading"}
dbartist = myDB.action('SELECT * FROM artists WHERE ArtistID=?', [artistid]).fetchone()
if dbartist is None:
newValueDict = {"ArtistName": "Artist ID: %s" % (artistid),
"Status": "Loading"}
else:
newValueDict = {"Status": "Loading"}
myDB.upsert("artists", newValueDict, controlValueDict)
artist = mb.getArtist(artistid, extrasonly)
if not artist:
logger.warn("Error fetching artist info. ID: " + artistid)
if dbartist is None:
newValueDict = {"ArtistName": "Fetch failed, try refreshing. (%s)" % (artistid),
"Status": "Active"}
else:
newValueDict = {"Status": "Active"}
myDB.upsert("artists", newValueDict, controlValueDict)
return
if artist['artist_name'].startswith('The '):
sortname = artist['artist_name'][4:]
else:
sortname = artist['artist_name']
myDB.upsert("artists", newValueDict, controlValueDict)
artist = mb.getArtist(artistid, extrasonly)
if not artist:
logger.warn("Error fetching artist info. ID: " + artistid)
if dbartist is None:
newValueDict = {"ArtistName": "Fetch failed, try refreshing. (%s)" % (artistid),
"Status": "Active"}
else:
newValueDict = {"Status": "Active"}
myDB.upsert("artists", newValueDict, controlValueDict)
return
if artist['artist_name'].startswith('The '):
sortname = artist['artist_name'][4:]
else:
sortname = artist['artist_name']
logger.info(u"Now adding/updating: " + artist['artist_name'])
controlValueDict = {"ArtistID": artistid}
newValueDict = {"ArtistName": artist['artist_name'],
"ArtistSortName": sortname,
"DateAdded": helpers.today(),
"Status": "Loading"}
if headphones.INCLUDE_EXTRAS:
newValueDict['IncludeExtras'] = 1
myDB.upsert("artists", newValueDict, controlValueDict)
logger.info(u"Now adding/updating: " + artist['artist_name'])
controlValueDict = {"ArtistID": artistid}
newValueDict = {"ArtistName": artist['artist_name'],
"ArtistSortName": sortname,
"DateAdded": helpers.today(),
"Status": "Loading"}
if headphones.INCLUDE_EXTRAS:
newValueDict['IncludeExtras'] = 1
myDB.upsert("artists", newValueDict, controlValueDict)
for rg in artist['releasegroups']:
rgid = rg['id']
# check if the album already exists
rg_exists = myDB.select("SELECT * from albums WHERE AlbumID=?", [rg['id']])
try:
release_dict = mb.getReleaseGroup(rgid)
except Exception, e:
logger.info('Unable to get release information for %s - there may not be any official releases in this release group' % rg['title'])
continue
if not release_dict:
continue
logger.info(u"Now adding/updating album: " + rg['title'])
controlValueDict = {"AlbumID": rg['id']}
if len(rg_exists):
newValueDict = {"AlbumASIN": release_dict['asin'],
"ReleaseDate": release_dict['releasedate'],
}
else:
newValueDict = {"ArtistID": artistid,
"ArtistName": artist['artist_name'],
"AlbumTitle": rg['title'],
"AlbumASIN": release_dict['asin'],
"ReleaseDate": release_dict['releasedate'],
"DateAdded": helpers.today(),
"Type": rg['type']
}
if headphones.AUTOWANT_ALL:
newValueDict['Status'] = "Wanted"
elif release_dict['releasedate'] > helpers.today() and headphones.AUTOWANT_UPCOMING:
newValueDict['Status'] = "Wanted"
else:
newValueDict['Status'] = "Skipped"
myDB.upsert("albums", newValueDict, controlValueDict)
try:
lastfm.getAlbumDescription(rg['id'], artist['artist_name'], rg['title'])
except Exception, e:
logger.error('Attempt to retrieve album description from Last.fm failed: %s' % e)
# I changed the albumid from releaseid -> rgid, so might need to delete albums that have a releaseid
for release in release_dict['releaselist']:
myDB.action('DELETE from albums WHERE AlbumID=?', [release['releaseid']])
myDB.action('DELETE from tracks WHERE AlbumID=?', [release['releaseid']])
for track in release_dict['tracks']:
cleanname = helpers.cleanName(artist['artist_name'] + ' ' + rg['title'] + ' ' + track['title'])
controlValueDict = {"TrackID": track['id'],
"AlbumID": rg['id']}
newValueDict = {"ArtistID": artistid,
"ArtistName": artist['artist_name'],
"AlbumTitle": rg['title'],
"AlbumASIN": release_dict['asin'],
"TrackTitle": track['title'],
"TrackDuration": track['duration'],
"TrackNumber": track['number'],
"CleanName": cleanname
}
match = myDB.action('SELECT Location, BitRate, Format from have WHERE CleanName=?', [cleanname]).fetchone()
if not match:
match = myDB.action('SELECT Location, BitRate, Format from have WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [artist['artist_name'], rg['title'], track['title']]).fetchone()
if not match:
match = myDB.action('SELECT Location, BitRate, Format from have WHERE TrackID=?', [track['id']]).fetchone()
if match:
newValueDict['Location'] = match['Location']
newValueDict['BitRate'] = match['BitRate']
newValueDict['Format'] = match['Format']
myDB.action('DELETE from have WHERE Location=?', [match['Location']])
myDB.upsert("tracks", newValueDict, controlValueDict)
latestalbum = myDB.action('SELECT AlbumTitle, ReleaseDate, AlbumID from albums WHERE ArtistID=? order by ReleaseDate DESC', [artistid]).fetchone()
totaltracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID=?', [artistid]))
havetracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID=? AND Location IS NOT NULL', [artistid])) + len(myDB.select('SELECT TrackTitle from have WHERE ArtistName like ?', [artist['artist_name']]))
for rg in artist['releasegroups']:
rgid = rg['id']
# check if the album already exists
rg_exists = myDB.select("SELECT * from albums WHERE AlbumID=?", [rg['id']])
try:
release_dict = mb.getReleaseGroup(rgid)
except Exception, e:
logger.info('Unable to get release information for %s - there may not be any official releases in this release group' % rg['title'])
continue
if not release_dict:
continue
logger.info(u"Now adding/updating album: " + rg['title'])
controlValueDict = {"AlbumID": rg['id']}
if len(rg_exists):
newValueDict = {"AlbumASIN": release_dict['asin'],
"ReleaseDate": release_dict['releasedate'],
}
else:
newValueDict = {"ArtistID": artistid,
"ArtistName": artist['artist_name'],
"AlbumTitle": rg['title'],
"AlbumASIN": release_dict['asin'],
"ReleaseDate": release_dict['releasedate'],
"DateAdded": helpers.today(),
"Type": rg['type']
}
if headphones.AUTOWANT_ALL:
newValueDict['Status'] = "Wanted"
elif release_dict['releasedate'] > helpers.today() and headphones.AUTOWANT_UPCOMING:
newValueDict['Status'] = "Wanted"
else:
newValueDict['Status'] = "Skipped"
myDB.upsert("albums", newValueDict, controlValueDict)
try:
lastfm.getAlbumDescription(rg['id'], artist['artist_name'], rg['title'])
except Exception, e:
logger.error('Attempt to retrieve album description from Last.fm failed: %s' % e)
# I changed the albumid from releaseid -> rgid, so might need to delete albums that have a releaseid
for release in release_dict['releaselist']:
myDB.action('DELETE from albums WHERE AlbumID=?', [release['releaseid']])
myDB.action('DELETE from tracks WHERE AlbumID=?', [release['releaseid']])
for track in release_dict['tracks']:
cleanname = helpers.cleanName(artist['artist_name'] + ' ' + rg['title'] + ' ' + track['title'])
controlValueDict = {"TrackID": track['id'],
"AlbumID": rg['id']}
newValueDict = {"ArtistID": artistid,
"ArtistName": artist['artist_name'],
"AlbumTitle": rg['title'],
"AlbumASIN": release_dict['asin'],
"TrackTitle": track['title'],
"TrackDuration": track['duration'],
"TrackNumber": track['number'],
"CleanName": cleanname
}
match = myDB.action('SELECT Location, BitRate, Format from have WHERE CleanName=?', [cleanname]).fetchone()
if not match:
match = myDB.action('SELECT Location, BitRate, Format from have WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [artist['artist_name'], rg['title'], track['title']]).fetchone()
if not match:
match = myDB.action('SELECT Location, BitRate, Format from have WHERE TrackID=?', [track['id']]).fetchone()
if match:
newValueDict['Location'] = match['Location']
newValueDict['BitRate'] = match['BitRate']
newValueDict['Format'] = match['Format']
myDB.action('DELETE from have WHERE Location=?', [match['Location']])
myDB.upsert("tracks", newValueDict, controlValueDict)
latestalbum = myDB.action('SELECT AlbumTitle, ReleaseDate, AlbumID from albums WHERE ArtistID=? order by ReleaseDate DESC', [artistid]).fetchone()
totaltracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID=?', [artistid]))
havetracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID=? AND Location IS NOT NULL', [artistid])) + len(myDB.select('SELECT TrackTitle from have WHERE ArtistName like ?', [artist['artist_name']]))
controlValueDict = {"ArtistID": artistid}
if latestalbum:
newValueDict = {"Status": "Active",
"LatestAlbum": latestalbum['AlbumTitle'],
"ReleaseDate": latestalbum['ReleaseDate'],
"AlbumID": latestalbum['AlbumID'],
"TotalTracks": totaltracks,
"HaveTracks": havetracks}
else:
newValueDict = {"Status": "Active",
"TotalTracks": totaltracks,
"HaveTracks": havetracks}
newValueDict['LastUpdated'] = helpers.now()
myDB.upsert("artists", newValueDict, controlValueDict)
logger.info(u"Updating complete for: " + artist['artist_name'])
controlValueDict = {"ArtistID": artistid}
if latestalbum:
newValueDict = {"Status": "Active",
"LatestAlbum": latestalbum['AlbumTitle'],
"ReleaseDate": latestalbum['ReleaseDate'],
"AlbumID": latestalbum['AlbumID'],
"TotalTracks": totaltracks,
"HaveTracks": havetracks}
else:
newValueDict = {"Status": "Active",
"TotalTracks": totaltracks,
"HaveTracks": havetracks}
newValueDict['LastUpdated'] = helpers.now()
myDB.upsert("artists", newValueDict, controlValueDict)
logger.info(u"Updating complete for: " + artist['artist_name'])
def addReleaseById(rid):
myDB = db.DBConnection()
myDB = db.DBConnection()
rgid = None
artistid = None
release_dict = None
results = myDB.select("SELECT albums.ArtistID, releases.ReleaseGroupID from releases, albums WHERE releases.ReleaseID=? and releases.ReleaseGroupID=albums.AlbumID LIMIT 1", [rid])
for result in results:
rgid = result['ReleaseGroupID']
artistid = result['ArtistID']
logger.debug("Found a cached releaseid : releasegroupid relationship: " + rid + " : " + rgid)
if not rgid:
#didn't find it in the cache, get the information from MB
logger.debug("Didn't find releaseID " + rid + " in the cache. Looking up its ReleaseGroupID")
try:
release_dict = mb.getRelease(rid)
except Exception, e:
logger.info('Unable to get release information for Release: ' + str(rid) + " " + str(e))
return
if not release_dict:
logger.info('Unable to get release information for Release: ' + str(rid) + " no dict")
return
rgid = release_dict['rgid']
artistid = release_dict['artist_id']
#we don't want to make more calls to MB here unless we have to, could be happening quite a lot
rg_exists = myDB.select("SELECT * from albums WHERE AlbumID=?", [rgid])
#make sure the artist exists since I don't know what happens later if it doesn't
artist_exists = myDB.select("SELECT * from artists WHERE ArtistID=?", [artistid])
if not artist_exists and release_dict:
if release_dict['artist_name'].startswith('The '):
sortname = release_dict['artist_name'][4:]
else:
sortname = release_dict['artist_name']
logger.info(u"Now manually adding: " + release_dict['artist_name'] + " - with status Paused")
controlValueDict = {"ArtistID": release_dict['artist_id']}
newValueDict = {"ArtistName": release_dict['artist_name'],
"ArtistSortName": sortname,
"DateAdded": helpers.today(),
"Status": "Paused"}
if headphones.INCLUDE_EXTRAS:
newValueDict['IncludeExtras'] = 1
myDB.upsert("artists", newValueDict, controlValueDict)
elif not artist_exists and not release_dict:
logger.error("Artist does not exist in the database and did not get a valid response from MB. Skipping release.")
return
if not rg_exists and release_dict: #it should never be the case that we have an rg and not the artist
#but if it is this will fail
logger.info(u"Now adding-by-id album (" + release_dict['title'] + ") from id: " + rgid)
controlValueDict = {"AlbumID": rgid}
rgid = None
artistid = None
release_dict = None
results = myDB.select("SELECT albums.ArtistID, releases.ReleaseGroupID from releases, albums WHERE releases.ReleaseID=? and releases.ReleaseGroupID=albums.AlbumID LIMIT 1", [rid])
for result in results:
rgid = result['ReleaseGroupID']
artistid = result['ArtistID']
logger.debug("Found a cached releaseid : releasegroupid relationship: " + rid + " : " + rgid)
if not rgid:
#didn't find it in the cache, get the information from MB
logger.debug("Didn't find releaseID " + rid + " in the cache. Looking up its ReleaseGroupID")
try:
release_dict = mb.getRelease(rid)
except Exception, e:
logger.info('Unable to get release information for Release: ' + str(rid) + " " + str(e))
return
if not release_dict:
logger.info('Unable to get release information for Release: ' + str(rid) + " no dict")
return
rgid = release_dict['rgid']
artistid = release_dict['artist_id']
#we don't want to make more calls to MB here unless we have to, could be happening quite a lot
rg_exists = myDB.select("SELECT * from albums WHERE AlbumID=?", [rgid])
#make sure the artist exists since I don't know what happens later if it doesn't
artist_exists = myDB.select("SELECT * from artists WHERE ArtistID=?", [artistid])
if not artist_exists and release_dict:
if release_dict['artist_name'].startswith('The '):
sortname = release_dict['artist_name'][4:]
else:
sortname = release_dict['artist_name']
logger.info(u"Now manually adding: " + release_dict['artist_name'] + " - with status Paused")
controlValueDict = {"ArtistID": release_dict['artist_id']}
newValueDict = {"ArtistName": release_dict['artist_name'],
"ArtistSortName": sortname,
"DateAdded": helpers.today(),
"Status": "Paused"}
if headphones.INCLUDE_EXTRAS:
newValueDict['IncludeExtras'] = 1
myDB.upsert("artists", newValueDict, controlValueDict)
elif not artist_exists and not release_dict:
logger.error("Artist does not exist in the database and did not get a valid response from MB. Skipping release.")
return
if not rg_exists and release_dict: #it should never be the case that we have an rg and not the artist
#but if it is this will fail
logger.info(u"Now adding-by-id album (" + release_dict['title'] + ") from id: " + rgid)
controlValueDict = {"AlbumID": rgid}
newValueDict = {"ArtistID": release_dict['artist_id'],
"ArtistName": release_dict['artist_name'],
"AlbumTitle": release_dict['rg_title'],
"AlbumASIN": release_dict['asin'],
"ReleaseDate": release_dict['date'],
"DateAdded": helpers.today(),
"Status": 'Wanted',
"Type": release_dict['rg_type']
}
myDB.upsert("albums", newValueDict, controlValueDict)
newValueDict = {"ArtistID": release_dict['artist_id'],
"ArtistName": release_dict['artist_name'],
"AlbumTitle": release_dict['rg_title'],
"AlbumASIN": release_dict['asin'],
"ReleaseDate": release_dict['date'],
"DateAdded": helpers.today(),
"Status": 'Wanted',
"Type": release_dict['rg_type']
}
myDB.upsert("albums", newValueDict, controlValueDict)
#keep a local cache of these so that external programs that are adding releasesByID don't hammer MB
myDB.action('INSERT INTO releases VALUES( ?, ?)', [rid, release_dict['rgid']])
for track in release_dict['tracks']:
cleanname = helpers.cleanName(release_dict['artist_name'] + ' ' + release_dict['rg_title'] + ' ' + track['title'])
controlValueDict = {"TrackID": track['id'],
"AlbumID": rgid}
newValueDict = {"ArtistID": release_dict['artist_id'],
"ArtistName": release_dict['artist_name'],
"AlbumTitle": release_dict['rg_title'],
"AlbumASIN": release_dict['asin'],
"TrackTitle": track['title'],
"TrackDuration": track['duration'],
"TrackNumber": track['number'],
"CleanName": cleanname
}
match = myDB.action('SELECT Location, BitRate, Format from have WHERE CleanName=?', [cleanname]).fetchone()
if not match:
match = myDB.action('SELECT Location, BitRate, Format from have WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [release_dict['artist_name'], release_dict['rg_title'], track['title']]).fetchone()
if not match:
match = myDB.action('SELECT Location, BitRate, Format from have WHERE TrackID=?', [track['id']]).fetchone()
if match:
newValueDict['Location'] = match['Location']
newValueDict['BitRate'] = match['BitRate']
newValueDict['Format'] = match['Format']
myDB.action('DELETE from have WHERE Location=?', [match['Location']])
myDB.upsert("tracks", newValueDict, controlValueDict)
#start a search for the album
import searcher
searcher.searchNZB(rgid, False)
elif not rg_exists and not release_dict:
logger.error("ReleaseGroup does not exist in the database and did not get a valid response from MB. Skipping release.")
return
else:
logger.info('Release ' + str(rid) + " already exists in the database!")
#keep a local cache of these so that external programs that are adding releasesByID don't hammer MB
myDB.action('INSERT INTO releases VALUES( ?, ?)', [rid, release_dict['rgid']])
for track in release_dict['tracks']:
cleanname = helpers.cleanName(release_dict['artist_name'] + ' ' + release_dict['rg_title'] + ' ' + track['title'])
controlValueDict = {"TrackID": track['id'],
"AlbumID": rgid}
newValueDict = {"ArtistID": release_dict['artist_id'],
"ArtistName": release_dict['artist_name'],
"AlbumTitle": release_dict['rg_title'],
"AlbumASIN": release_dict['asin'],
"TrackTitle": track['title'],
"TrackDuration": track['duration'],
"TrackNumber": track['number'],
"CleanName": cleanname
}
match = myDB.action('SELECT Location, BitRate, Format from have WHERE CleanName=?', [cleanname]).fetchone()
if not match:
match = myDB.action('SELECT Location, BitRate, Format from have WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [release_dict['artist_name'], release_dict['rg_title'], track['title']]).fetchone()
if not match:
match = myDB.action('SELECT Location, BitRate, Format from have WHERE TrackID=?', [track['id']]).fetchone()
if match:
newValueDict['Location'] = match['Location']
newValueDict['BitRate'] = match['BitRate']
newValueDict['Format'] = match['Format']
myDB.action('DELETE from have WHERE Location=?', [match['Location']])
myDB.upsert("tracks", newValueDict, controlValueDict)
#start a search for the album
import searcher
searcher.searchNZB(rgid, False)
elif not rg_exists and not release_dict:
logger.error("ReleaseGroup does not exist in the database and did not get a valid response from MB. Skipping release.")
return
else:
logger.info('Release ' + str(rid) + " already exists in the database!")
def updateFormat():
myDB = db.DBConnection()
tracks = myDB.select('SELECT * from tracks WHERE Location IS NOT NULL and Format IS NULL')
if len(tracks) > 0:
logger.info('Finding media format for %s files' % len(tracks))
for track in tracks:
try:
f = MediaFile(track['Location'])
except Exception, e:
logger.info("Exception from MediaFile for: " + track['Location'] + " : " + str(e))
continue
controlValueDict = {"TrackID": track['TrackID']}
newValueDict = {"Format": f.format}
myDB.upsert("tracks", newValueDict, controlValueDict)
logger.info('Finished finding media format for %s files' % len(tracks))
havetracks = myDB.select('SELECT * from have WHERE Location IS NOT NULL and Format IS NULL')
if len(havetracks) > 0:
logger.info('Finding media format for %s files' % len(havetracks))
for track in havetracks:
try:
f = MediaFile(track['Location'])
except Exception, e:
logger.info("Exception from MediaFile for: " + track['Location'] + " : " + str(e))
continue
controlValueDict = {"TrackID": track['TrackID']}
newValueDict = {"Format": f.format}
myDB.upsert("have", newValueDict, controlValueDict)
logger.info('Finished finding media format for %s files' % len(havetracks))
myDB = db.DBConnection()
tracks = myDB.select('SELECT * from tracks WHERE Location IS NOT NULL and Format IS NULL')
if len(tracks) > 0:
logger.info('Finding media format for %s files' % len(tracks))
for track in tracks:
try:
f = MediaFile(track['Location'])
except Exception, e:
logger.info("Exception from MediaFile for: " + track['Location'] + " : " + str(e))
continue
controlValueDict = {"TrackID": track['TrackID']}
newValueDict = {"Format": f.format}
myDB.upsert("tracks", newValueDict, controlValueDict)
logger.info('Finished finding media format for %s files' % len(tracks))
havetracks = myDB.select('SELECT * from have WHERE Location IS NOT NULL and Format IS NULL')
if len(havetracks) > 0:
logger.info('Finding media format for %s files' % len(havetracks))
for track in havetracks:
try:
f = MediaFile(track['Location'])
except Exception, e:
logger.info("Exception from MediaFile for: " + track['Location'] + " : " + str(e))
continue
controlValueDict = {"TrackID": track['TrackID']}
newValueDict = {"Format": f.format}
myDB.upsert("have", newValueDict, controlValueDict)
logger.info('Finished finding media format for %s files' % len(havetracks))

View File

@@ -11,179 +11,179 @@ api_key = '395e6ec6bb557382fc41fde867bce66f'
def getSimilar():
myDB = db.DBConnection()
results = myDB.select('SELECT ArtistID from artists ORDER BY HaveTracks DESC')
artistlist = []
for result in results[:12]:
url = 'http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&mbid=%s&api_key=%s' % (result['ArtistID'], api_key)
try:
data = urllib.urlopen(url).read()
except:
time.sleep(1)
continue
if len(data) < 200:
continue
d = minidom.parseString(data)
node = d.documentElement
artists = d.getElementsByTagName("artist")
for artist in artists:
namenode = artist.getElementsByTagName("name")[0].childNodes
mbidnode = artist.getElementsByTagName("mbid")[0].childNodes
for node in namenode:
artist_name = node.data
for node in mbidnode:
artist_mbid = node.data
try:
if not any(artist_mbid in x for x in results):
artistlist.append((artist_name, artist_mbid))
except:
continue
count = defaultdict(int)
for artist, mbid in artistlist:
count[artist, mbid] += 1
items = count.items()
top_list = sorted(items, key=lambda x: x[1], reverse=True)[:25]
random.shuffle(top_list)
myDB.action('''DELETE from lastfmcloud''')
for tuple in top_list:
artist_name, artist_mbid = tuple[0]
count = tuple[1]
myDB.action('INSERT INTO lastfmcloud VALUES( ?, ?, ?)', [artist_name, artist_mbid, count])
myDB = db.DBConnection()
results = myDB.select('SELECT ArtistID from artists ORDER BY HaveTracks DESC')
artistlist = []
for result in results[:12]:
url = 'http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&mbid=%s&api_key=%s' % (result['ArtistID'], api_key)
try:
data = urllib.urlopen(url).read()
except:
time.sleep(1)
continue
if len(data) < 200:
continue
d = minidom.parseString(data)
node = d.documentElement
artists = d.getElementsByTagName("artist")
for artist in artists:
namenode = artist.getElementsByTagName("name")[0].childNodes
mbidnode = artist.getElementsByTagName("mbid")[0].childNodes
for node in namenode:
artist_name = node.data
for node in mbidnode:
artist_mbid = node.data
try:
if not any(artist_mbid in x for x in results):
artistlist.append((artist_name, artist_mbid))
except:
continue
count = defaultdict(int)
for artist, mbid in artistlist:
count[artist, mbid] += 1
items = count.items()
top_list = sorted(items, key=lambda x: x[1], reverse=True)[:25]
random.shuffle(top_list)
myDB.action('''DELETE from lastfmcloud''')
for tuple in top_list:
artist_name, artist_mbid = tuple[0]
count = tuple[1]
myDB.action('INSERT INTO lastfmcloud VALUES( ?, ?, ?)', [artist_name, artist_mbid, count])
def getArtists():
myDB = db.DBConnection()
results = myDB.select('SELECT ArtistID from artists')
myDB = db.DBConnection()
results = myDB.select('SELECT ArtistID from artists')
if not headphones.LASTFM_USERNAME:
return
else:
username = headphones.LASTFM_USERNAME
url = 'http://ws.audioscrobbler.com/2.0/?method=library.getartists&limit=10000&api_key=%s&user=%s' % (api_key, username)
data = urllib.urlopen(url).read()
d = minidom.parseString(data)
artists = d.getElementsByTagName("artist")
artistlist = []
for artist in artists:
mbidnode = artist.getElementsByTagName("mbid")[0].childNodes
if not headphones.LASTFM_USERNAME:
return
else:
username = headphones.LASTFM_USERNAME
url = 'http://ws.audioscrobbler.com/2.0/?method=library.getartists&limit=10000&api_key=%s&user=%s' % (api_key, username)
data = urllib.urlopen(url).read()
d = minidom.parseString(data)
artists = d.getElementsByTagName("artist")
artistlist = []
for artist in artists:
mbidnode = artist.getElementsByTagName("mbid")[0].childNodes
for node in mbidnode:
artist_mbid = node.data
try:
if not any(artist_mbid in x for x in results):
artistlist.append(artist_mbid)
except:
continue
from headphones import importer
for artistid in artistlist:
importer.addArtisttoDB(artistid)
for node in mbidnode:
artist_mbid = node.data
try:
if not any(artist_mbid in x for x in results):
artistlist.append(artist_mbid)
except:
continue
from headphones import importer
for artistid in artistlist:
importer.addArtisttoDB(artistid)
def getAlbumDescription(rgid, artist, album):
myDB = db.DBConnection()
result = myDB.select('SELECT Summary from descriptions WHERE ReleaseGroupID=?', [rgid])
if result:
return
params = { "method": 'album.getInfo',
"api_key": api_key,
myDB = db.DBConnection()
result = myDB.select('SELECT Summary from descriptions WHERE ReleaseGroupID=?', [rgid])
if result:
return
params = { "method": 'album.getInfo',
"api_key": api_key,
"artist": artist.encode('utf-8'),
"album": album.encode('utf-8')
}
searchURL = 'http://ws.audioscrobbler.com/2.0/?' + urllib.urlencode(params)
data = urllib.urlopen(searchURL).read()
if data == '<?xml version="1.0" encoding="utf-8"?><lfm status="failed"><error code="6">Album not found</error></lfm>':
return
try:
d = minidom.parseString(data)
searchURL = 'http://ws.audioscrobbler.com/2.0/?' + urllib.urlencode(params)
data = urllib.urlopen(searchURL).read()
if data == '<?xml version="1.0" encoding="utf-8"?><lfm status="failed"><error code="6">Album not found</error></lfm>':
return
try:
d = minidom.parseString(data)
albuminfo = d.getElementsByTagName("album")
for item in albuminfo:
summarynode = item.getElementsByTagName("summary")[0].childNodes
contentnode = item.getElementsByTagName("content")[0].childNodes
for node in summarynode:
summary = node.data
for node in contentnode:
content = node.data
controlValueDict = {'ReleaseGroupID': rgid}
newValueDict = {'Summary': summary,
'Content': content}
myDB.upsert("descriptions", newValueDict, controlValueDict)
except:
return
albuminfo = d.getElementsByTagName("album")
for item in albuminfo:
summarynode = item.getElementsByTagName("summary")[0].childNodes
contentnode = item.getElementsByTagName("content")[0].childNodes
for node in summarynode:
summary = node.data
for node in contentnode:
content = node.data
controlValueDict = {'ReleaseGroupID': rgid}
newValueDict = {'Summary': summary,
'Content': content}
myDB.upsert("descriptions", newValueDict, controlValueDict)
except:
return
def getAlbumDescriptionOld(rgid, releaselist):
"""
This was a dumb way to do it - going to just use artist & album name but keeping this here
because I may use it to fetch and cache album art
"""
"""
This was a dumb way to do it - going to just use artist & album name but keeping this here
because I may use it to fetch and cache album art
"""
myDB = db.DBConnection()
result = myDB.select('SELECT Summary from descriptions WHERE ReleaseGroupID=?', [rgid])
if result:
return
for release in releaselist:
mbid = release['releaseid']
url = 'http://ws.audioscrobbler.com/2.0/?method=album.getInfo&mbid=%s&api_key=%s' % (mbid, api_key)
data = urllib.urlopen(url).read()
if data == '<?xml version="1.0" encoding="utf-8"?><lfm status="failed"><error code="6">Album not found</error></lfm>':
continue
try:
d = minidom.parseString(data)
albuminfo = d.getElementsByTagName("album")
for item in albuminfo:
summarynode = item.getElementsByTagName("summary")[0].childNodes
contentnode = item.getElementsByTagName("content")[0].childNodes
for node in summarynode:
summary = node.data
for node in contentnode:
content = node.data
controlValueDict = {'ReleaseGroupID': rgid}
newValueDict = {'ReleaseID': mbid,
'Summary': summary,
'Content': content}
myDB.upsert("descriptions", newValueDict, controlValueDict)
break
except:
continue
myDB = db.DBConnection()
result = myDB.select('SELECT Summary from descriptions WHERE ReleaseGroupID=?', [rgid])
if result:
return
for release in releaselist:
mbid = release['releaseid']
url = 'http://ws.audioscrobbler.com/2.0/?method=album.getInfo&mbid=%s&api_key=%s' % (mbid, api_key)
data = urllib.urlopen(url).read()
if data == '<?xml version="1.0" encoding="utf-8"?><lfm status="failed"><error code="6">Album not found</error></lfm>':
continue
try:
d = minidom.parseString(data)
albuminfo = d.getElementsByTagName("album")
for item in albuminfo:
summarynode = item.getElementsByTagName("summary")[0].childNodes
contentnode = item.getElementsByTagName("content")[0].childNodes
for node in summarynode:
summary = node.data
for node in contentnode:
content = node.data
controlValueDict = {'ReleaseGroupID': rgid}
newValueDict = {'ReleaseID': mbid,
'Summary': summary,
'Content': content}
myDB.upsert("descriptions", newValueDict, controlValueDict)
break
except:
continue

View File

@@ -8,212 +8,212 @@ from headphones import db, logger, helpers, importer
def libraryScan(dir=None):
if not dir:
dir = headphones.MUSIC_DIR
try:
dir = str(dir)
except UnicodeEncodeError:
dir = unicode(dir).encode('unicode_escape')
if not os.path.isdir(dir):
logger.warn('Cannot find directory: %s. Not scanning' % dir)
return
if not dir:
dir = headphones.MUSIC_DIR
try:
dir = str(dir)
except UnicodeEncodeError:
dir = unicode(dir).encode('unicode_escape')
if not os.path.isdir(dir):
logger.warn('Cannot find directory: %s. Not scanning' % dir)
return
myDB = db.DBConnection()
# Clean up bad filepaths
tracks = myDB.select('SELECT Location, TrackID from tracks WHERE Location IS NOT NULL')
for track in tracks:
if not os.path.isfile(track['Location'].encode(headphones.SYS_ENCODING)):
myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [None, None, None, track['TrackID']])
myDB = db.DBConnection()
# Clean up bad filepaths
tracks = myDB.select('SELECT Location, TrackID from tracks WHERE Location IS NOT NULL')
for track in tracks:
if not os.path.isfile(track['Location'].encode(headphones.SYS_ENCODING)):
myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [None, None, None, track['TrackID']])
logger.info('Scanning music directory: %s' % dir)
logger.info('Scanning music directory: %s' % dir)
new_artists = []
bitrates = []
new_artists = []
bitrates = []
myDB.action('DELETE from have')
for r,d,f in os.walk(dir):
for files in f:
# MEDIA_FORMATS = music file extensions, e.g. mp3, flac, etc
if any(files.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
myDB.action('DELETE from have')
for r,d,f in os.walk(dir):
for files in f:
# MEDIA_FORMATS = music file extensions, e.g. mp3, flac, etc
if any(files.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
song = os.path.join(r, files)
file = unicode(os.path.join(r, files), headphones.SYS_ENCODING, errors='replace')
song = os.path.join(r, files)
file = unicode(os.path.join(r, files), headphones.SYS_ENCODING, errors='replace')
# Try to read the metadata
try:
f = MediaFile(song)
# Try to read the metadata
try:
f = MediaFile(song)
except:
logger.error('Cannot read file: ' + file)
continue
# Grab the bitrates for the auto detect bit rate option
if f.bitrate:
bitrates.append(f.bitrate)
# Try to find a match based on artist/album/tracktitle
if f.albumartist:
f_artist = f.albumartist
elif f.artist:
f_artist = f.artist
else:
continue
if f_artist and f.album and f.title:
except:
logger.error('Cannot read file: ' + file)
continue
# Grab the bitrates for the auto detect bit rate option
if f.bitrate:
bitrates.append(f.bitrate)
# Try to find a match based on artist/album/tracktitle
if f.albumartist:
f_artist = f.albumartist
elif f.artist:
f_artist = f.artist
else:
continue
if f_artist and f.album and f.title:
track = myDB.action('SELECT TrackID from tracks WHERE CleanName LIKE ?', [helpers.cleanName(f_artist +' '+f.album+' '+f.title)]).fetchone()
if not track:
track = myDB.action('SELECT TrackID from tracks WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [f_artist, f.album, f.title]).fetchone()
if track:
myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [file, f.bitrate, f.format, track['TrackID']])
continue
# Try to match on mbid if available and we couldn't find a match based on metadata
if f.mb_trackid:
track = myDB.action('SELECT TrackID from tracks WHERE CleanName LIKE ?', [helpers.cleanName(f_artist +' '+f.album+' '+f.title)]).fetchone()
if not track:
track = myDB.action('SELECT TrackID from tracks WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [f_artist, f.album, f.title]).fetchone()
if track:
myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [file, f.bitrate, f.format, track['TrackID']])
continue
# Try to match on mbid if available and we couldn't find a match based on metadata
if f.mb_trackid:
# Wondering if theres a better way to do this -> do one thing if the row exists,
# do something else if it doesn't
track = myDB.action('SELECT TrackID from tracks WHERE TrackID=?', [f.mb_trackid]).fetchone()
if track:
myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [file, f.bitrate, f.format, track['TrackID']])
continue
# if we can't find a match in the database on a track level, it might be a new artist or it might be on a non-mb release
new_artists.append(f_artist)
# The have table will become the new database for unmatched tracks (i.e. tracks with no associated links in the database
myDB.action('INSERT INTO have (ArtistName, AlbumTitle, TrackNumber, TrackTitle, TrackLength, BitRate, Genre, Date, TrackID, Location, CleanName, Format) VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [f_artist, f.album, f.track, f.title, f.length, f.bitrate, f.genre, f.date, f.mb_trackid, file, helpers.cleanName(f_artist+' '+f.album+' '+f.title), f.format])
# Wondering if theres a better way to do this -> do one thing if the row exists,
# do something else if it doesn't
track = myDB.action('SELECT TrackID from tracks WHERE TrackID=?', [f.mb_trackid]).fetchone()
if track:
myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [file, f.bitrate, f.format, track['TrackID']])
continue
# if we can't find a match in the database on a track level, it might be a new artist or it might be on a non-mb release
new_artists.append(f_artist)
# The have table will become the new database for unmatched tracks (i.e. tracks with no associated links in the database
myDB.action('INSERT INTO have (ArtistName, AlbumTitle, TrackNumber, TrackTitle, TrackLength, BitRate, Genre, Date, TrackID, Location, CleanName, Format) VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [f_artist, f.album, f.track, f.title, f.length, f.bitrate, f.genre, f.date, f.mb_trackid, file, helpers.cleanName(f_artist+' '+f.album+' '+f.title), f.format])
logger.info('Completed scanning of directory: %s' % dir)
logger.info('Checking filepaths to see if we can find any matches')
logger.info('Completed scanning of directory: %s' % dir)
logger.info('Checking filepaths to see if we can find any matches')
# Now check empty file paths to see if we can find a match based on their folder format
tracks = myDB.select('SELECT * from tracks WHERE Location IS NULL')
for track in tracks:
release = myDB.action('SELECT * from albums WHERE AlbumID=?', [track['AlbumID']]).fetchone()
# Now check empty file paths to see if we can find a match based on their folder format
tracks = myDB.select('SELECT * from tracks WHERE Location IS NULL')
for track in tracks:
release = myDB.action('SELECT * from albums WHERE AlbumID=?', [track['AlbumID']]).fetchone()
try:
year = release['ReleaseDate'][:4]
except TypeError:
year = ''
artist = release['ArtistName'].replace('/', '_')
album = release['AlbumTitle'].replace('/', '_')
releasetype = release['Type'].replace('/', '_')
if release['ArtistName'].startswith('The '):
sortname = release['ArtistName'][4:]
else:
sortname = release['ArtistName']
if sortname.isdigit():
firstchar = '0-9'
else:
firstchar = sortname[0]
try:
year = release['ReleaseDate'][:4]
except TypeError:
year = ''
artist = release['ArtistName'].replace('/', '_')
album = release['AlbumTitle'].replace('/', '_')
releasetype = release['Type'].replace('/', '_')
if release['ArtistName'].startswith('The '):
sortname = release['ArtistName'][4:]
else:
sortname = release['ArtistName']
if sortname.isdigit():
firstchar = '0-9'
else:
firstchar = sortname[0]
albumvalues = { '$Artist': artist,
'$Album': album,
'$Year': year,
'$Type': releasetype,
'$First': firstchar,
'$artist': artist.lower(),
'$album': album.lower(),
'$year': year,
'$type': releasetype.lower(),
'$first': firstchar.lower()
}
folder = helpers.replace_all(headphones.FOLDER_FORMAT, albumvalues)
folder = folder.replace('./', '_/').replace(':','_').replace('?','_')
if folder.endswith('.'):
folder = folder.replace(folder[len(folder)-1], '_')
albumvalues = { '$Artist': artist,
'$Album': album,
'$Year': year,
'$Type': releasetype,
'$First': firstchar,
'$artist': artist.lower(),
'$album': album.lower(),
'$year': year,
'$type': releasetype.lower(),
'$first': firstchar.lower()
}
folder = helpers.replace_all(headphones.FOLDER_FORMAT, albumvalues)
folder = folder.replace('./', '_/').replace(':','_').replace('?','_')
if folder.endswith('.'):
folder = folder.replace(folder[len(folder)-1], '_')
if not track['TrackNumber']:
tracknumber = ''
else:
tracknumber = '%02d' % track['TrackNumber']
title = track['TrackTitle']
trackvalues = { '$Track': tracknumber,
'$Title': title,
'$Artist': release['ArtistName'],
'$Album': release['AlbumTitle'],
'$Year': year,
'$track': tracknumber,
'$title': title.lower(),
'$artist': release['ArtistName'].lower(),
'$album': release['AlbumTitle'].lower(),
'$year': year
}
new_file_name = helpers.replace_all(headphones.FILE_FORMAT, trackvalues).replace('/','_') + '.*'
new_file_name = new_file_name.replace('?','_').replace(':', '_')
full_path_to_file = os.path.normpath(os.path.join(headphones.MUSIC_DIR, folder, new_file_name)).encode(headphones.SYS_ENCODING, 'replace')
if not track['TrackNumber']:
tracknumber = ''
else:
tracknumber = '%02d' % track['TrackNumber']
title = track['TrackTitle']
trackvalues = { '$Track': tracknumber,
'$Title': title,
'$Artist': release['ArtistName'],
'$Album': release['AlbumTitle'],
'$Year': year,
'$track': tracknumber,
'$title': title.lower(),
'$artist': release['ArtistName'].lower(),
'$album': release['AlbumTitle'].lower(),
'$year': year
}
new_file_name = helpers.replace_all(headphones.FILE_FORMAT, trackvalues).replace('/','_') + '.*'
new_file_name = new_file_name.replace('?','_').replace(':', '_')
full_path_to_file = os.path.normpath(os.path.join(headphones.MUSIC_DIR, folder, new_file_name)).encode(headphones.SYS_ENCODING, 'replace')
match = glob.glob(full_path_to_file)
if match:
match = glob.glob(full_path_to_file)
if match:
logger.info('Found a match: %s. Writing MBID to metadata' % match[0])
unipath = unicode(match[0], headphones.SYS_ENCODING, errors='replace')
logger.info('Found a match: %s. Writing MBID to metadata' % match[0])
unipath = unicode(match[0], headphones.SYS_ENCODING, errors='replace')
myDB.action('UPDATE tracks SET Location=? WHERE TrackID=?', [unipath, track['TrackID']])
myDB.action('DELETE from have WHERE Location=?', [unipath])
# Try to insert the appropriate track id so we don't have to keep doing this
try:
f = MediaFile(match[0])
f.mb_trackid = track['TrackID']
f.save()
myDB.action('UPDATE tracks SET BitRate=?, Format=? WHERE TrackID=?', [f.bitrate, f.format, track['TrackID']])
myDB.action('UPDATE tracks SET Location=? WHERE TrackID=?', [unipath, track['TrackID']])
myDB.action('DELETE from have WHERE Location=?', [unipath])
# Try to insert the appropriate track id so we don't have to keep doing this
try:
f = MediaFile(match[0])
f.mb_trackid = track['TrackID']
f.save()
myDB.action('UPDATE tracks SET BitRate=?, Format=? WHERE TrackID=?', [f.bitrate, f.format, track['TrackID']])
logger.debug('Wrote mbid to track: %s' % match[0])
logger.debug('Wrote mbid to track: %s' % match[0])
except:
logger.error('Error embedding track id into: %s' % match[0])
continue
except:
logger.error('Error embedding track id into: %s' % match[0])
continue
logger.info('Done checking empty filepaths')
logger.info('Done syncing library with directory: %s' % dir)
# Clean up the new artist list
unique_artists = {}.fromkeys(new_artists).keys()
current_artists = myDB.select('SELECT ArtistName, ArtistID from artists')
artist_list = [f for f in unique_artists if f.lower() not in [x[0].lower() for x in current_artists]]
# Update track counts
logger.info('Updating track counts')
logger.info('Done checking empty filepaths')
logger.info('Done syncing library with directory: %s' % dir)
# Clean up the new artist list
unique_artists = {}.fromkeys(new_artists).keys()
current_artists = myDB.select('SELECT ArtistName, ArtistID from artists')
artist_list = [f for f in unique_artists if f.lower() not in [x[0].lower() for x in current_artists]]
# Update track counts
logger.info('Updating track counts')
for artist in current_artists:
havetracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID like ? AND Location IS NOT NULL', [artist['ArtistID']])) + len(myDB.select('SELECT TrackTitle from have WHERE ArtistName like ?', [artist['ArtistName']]))
myDB.action('UPDATE artists SET HaveTracks=? WHERE ArtistID=?', [havetracks, artist['ArtistID']])
logger.info('Found %i new artists' % len(artist_list))
for artist in current_artists:
havetracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID like ? AND Location IS NOT NULL', [artist['ArtistID']])) + len(myDB.select('SELECT TrackTitle from have WHERE ArtistName like ?', [artist['ArtistName']]))
myDB.action('UPDATE artists SET HaveTracks=? WHERE ArtistID=?', [havetracks, artist['ArtistID']])
logger.info('Found %i new artists' % len(artist_list))
if len(artist_list):
if headphones.ADD_ARTISTS:
logger.info('Importing %i new artists' % len(artist_list))
importer.artistlist_to_mbids(artist_list)
else:
logger.info('To add these artists, go to Manage->Manage New Artists')
headphones.NEW_ARTISTS = artist_list
if headphones.DETECT_BITRATE:
headphones.PREFERRED_BITRATE = sum(bitrates)/len(bitrates)/1000
if len(artist_list):
if headphones.ADD_ARTISTS:
logger.info('Importing %i new artists' % len(artist_list))
importer.artistlist_to_mbids(artist_list)
else:
logger.info('To add these artists, go to Manage->Manage New Artists')
headphones.NEW_ARTISTS = artist_list
if headphones.DETECT_BITRATE:
headphones.PREFERRED_BITRATE = sum(bitrates)/len(bitrates)/1000

View File

@@ -13,69 +13,69 @@ MAX_FILES = 5
# Simple rotating log handler that uses RotatingFileHandler
class RotatingLogger(object):
def __init__(self, filename, max_size, max_files):
self.filename = filename
self.max_size = max_size
self.max_files = max_files
def initLogger(self, verbose=1):
l = logging.getLogger('headphones')
l.setLevel(logging.DEBUG)
self.filename = os.path.join(headphones.LOG_DIR, self.filename)
filehandler = handlers.RotatingFileHandler(self.filename, maxBytes=self.max_size, backupCount=self.max_files)
filehandler.setLevel(logging.DEBUG)
fileformatter = logging.Formatter('%(asctime)s - %(levelname)-7s :: %(message)s', '%d-%b-%Y %H:%M:%S')
filehandler.setFormatter(fileformatter)
l.addHandler(filehandler)
if verbose:
consolehandler = logging.StreamHandler()
if verbose == 1:
consolehandler.setLevel(logging.INFO)
if verbose == 2:
consolehandler.setLevel(logging.DEBUG)
consoleformatter = logging.Formatter('%(asctime)s - %(levelname)s :: %(message)s', '%d-%b-%Y %H:%M:%S')
consolehandler.setFormatter(consoleformatter)
l.addHandler(consolehandler)
def log(self, message, level):
def __init__(self, filename, max_size, max_files):
self.filename = filename
self.max_size = max_size
self.max_files = max_files
def initLogger(self, verbose=1):
l = logging.getLogger('headphones')
l.setLevel(logging.DEBUG)
self.filename = os.path.join(headphones.LOG_DIR, self.filename)
filehandler = handlers.RotatingFileHandler(self.filename, maxBytes=self.max_size, backupCount=self.max_files)
filehandler.setLevel(logging.DEBUG)
fileformatter = logging.Formatter('%(asctime)s - %(levelname)-7s :: %(message)s', '%d-%b-%Y %H:%M:%S')
filehandler.setFormatter(fileformatter)
l.addHandler(filehandler)
if verbose:
consolehandler = logging.StreamHandler()
if verbose == 1:
consolehandler.setLevel(logging.INFO)
if verbose == 2:
consolehandler.setLevel(logging.DEBUG)
consoleformatter = logging.Formatter('%(asctime)s - %(levelname)s :: %(message)s', '%d-%b-%Y %H:%M:%S')
consolehandler.setFormatter(consoleformatter)
l.addHandler(consolehandler)
def log(self, message, level):
logger = logging.getLogger('headphones')
threadname = threading.currentThread().getName()
if level != 'DEBUG':
headphones.LOG_LIST.insert(0, (helpers.now(), message, level, threadname))
message = threadname + ' : ' + message
logger = logging.getLogger('headphones')
threadname = threading.currentThread().getName()
if level != 'DEBUG':
headphones.LOG_LIST.insert(0, (helpers.now(), message, level, threadname))
message = threadname + ' : ' + message
if level == 'DEBUG':
logger.debug(message)
elif level == 'INFO':
logger.info(message)
elif level == 'WARNING':
logger.warn(message)
else:
logger.error(message)
if level == 'DEBUG':
logger.debug(message)
elif level == 'INFO':
logger.info(message)
elif level == 'WARNING':
logger.warn(message)
else:
logger.error(message)
headphones_log = RotatingLogger('headphones.log', MAX_SIZE, MAX_FILES)
def debug(message):
headphones_log.log(message, level='DEBUG')
headphones_log.log(message, level='DEBUG')
def info(message):
headphones_log.log(message, level='INFO')
headphones_log.log(message, level='INFO')
def warn(message):
headphones_log.log(message, level='WARNING')
headphones_log.log(message, level='WARNING')
def error(message):
headphones_log.log(message, level='ERROR')
headphones_log.log(message, level='ERROR')

View File

@@ -7,53 +7,53 @@ from headphones import logger
def getLyrics(artist, song):
params = { "artist": artist.encode('utf-8'),
"song": song.encode('utf-8'),
"fmt": 'xml'
params = { "artist": artist.encode('utf-8'),
"song": song.encode('utf-8'),
"fmt": 'xml'
}
searchURL = 'http://lyrics.wikia.com/api.php?' + urllib.urlencode(params)
try:
data = urllib.urlopen(searchURL).read()
except Exception, e:
logger.warn('Error opening: %s. Error: %s' % (searchURL, e))
return
try:
parseddata = minidom.parseString(data)
except Exception, e:
logger.warn('Error parsing data from url: %s. Error: %s' % (searchURL, e))
return
url = parseddata.getElementsByTagName("url")
if url:
lyricsurl = url[0].firstChild.nodeValue
else:
logger.info('No lyrics found for %s - %s' % (artist, song))
return
try:
lyricspage = urllib.urlopen(lyricsurl).read()
except Exception, e:
logger.warn('Error fetching lyrics from: %s. Error: %s' % (lyricsurl, e))
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
searchURL = 'http://lyrics.wikia.com/api.php?' + urllib.urlencode(params)
try:
data = urllib.urlopen(searchURL).read()
except Exception, e:
logger.warn('Error opening: %s. Error: %s' % (searchURL, e))
return
try:
parseddata = minidom.parseString(data)
except Exception, e:
logger.warn('Error parsing data from url: %s. Error: %s' % (searchURL, e))
return
url = parseddata.getElementsByTagName("url")
if url:
lyricsurl = url[0].firstChild.nodeValue
else:
logger.info('No lyrics found for %s - %s' % (artist, song))
return
try:
lyricspage = urllib.urlopen(lyricsurl).read()
except Exception, e:
logger.warn('Error fetching lyrics from: %s. Error: %s' % (lyricsurl, e))
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 convert_html_entities(s):
matches = re.findall("&#\d+;", s)
@@ -77,4 +77,4 @@ def convert_html_entities(s):
if htmlentitydefs.name2codepoint.has_key(name):
s = s.replace(hit, unichr(htmlentitydefs.name2codepoint[name]))
s = s.replace(amp, "&")
return s
return s

View File

@@ -52,10 +52,10 @@ def startmb(forcemb=False):
# Add headphones credentials
if headphones.MIRROR == "headphones":
if not mbuser and mbpass:
logger.warn("No username or password set for VIP server")
if not mbuser and mbpass:
logger.warn("No username or password set for VIP server")
else:
musicbrainzngs.hpauth(mbuser,mbpass)
musicbrainzngs.hpauth(mbuser,mbpass)
# Don't really need to return q anymore since ngs, but maybe we can return an 'initialized=True' instead?
q = musicbrainzngs

View File

@@ -13,124 +13,124 @@ except ImportError:
import lib.argparse as argparse
def encode(albumPath):
tempDirEncode=os.path.join(albumPath,"temp")
musicFiles=[]
musicFinalFiles=[]
musicTempFiles=[]
encoder =""
startAlbumTime=time.time()
ifencoded=0
if not os.path.exists(tempDirEncode):
os.mkdir(tempDirEncode)
else:
shutil.rmtree(tempDirEncode)
time.sleep(1)
os.mkdir(tempDirEncode)
for r,d,f in os.walk(albumPath):
for music in f:
if any(music.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
if (headphones.ENCODERLOSSLESS):
if (music.lower().endswith('.flac')):
musicFiles.append(os.path.join(r, music))
musicTemp = os.path.normpath(os.path.splitext(music)[0]+'.'+headphones.ENCODEROUTPUTFORMAT).encode(headphones.SYS_ENCODING)
musicTempFiles.append(os.path.join(tempDirEncode, musicTemp))
else:
logger.warn('Music "%s" is already encoded' % (music))
else:
musicFiles.append(os.path.join(r, music))
musicTemp = os.path.normpath(os.path.splitext(music)[0]+'.'+headphones.ENCODEROUTPUTFORMAT).encode(headphones.SYS_ENCODING)
musicTempFiles.append(os.path.join(tempDirEncode, musicTemp))
if headphones.ENCODER=='lame':
encoder=os.path.join(headphones.ENCODERFOLDER,'lame')
elif headphones.ENCODER=='ffmpeg':
encoder=os.path.join(headphones.ENCODERFOLDER,'ffmpeg')
i=0
for music in musicFiles:
infoMusic=MediaFile(music)
if headphones.ENCODER == 'lame':
if not any(music.lower().endswith('.' + x) for x in ["mp3", "wav"]):
logger.warn('Lame cant encode "%s" format for "%s", use ffmpeg' % (os.path.splitext(music)[1],music))
else:
if (music.lower().endswith('.mp3') and (infoMusic.bitrate/1000<=headphones.BITRATE)):
logger.warn('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music,headphones.BITRATE))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
else:
if headphones.ENCODEROUTPUTFORMAT=='ogg':
if music.lower().endswith('.ogg'):
logger.warn('Can not reencode .ogg music "%s"' % (music))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
elif (headphones.ENCODEROUTPUTFORMAT=='mp3' or headphones.ENCODEROUTPUTFORMAT=='m4a'):
if (music.lower().endswith('.'+headphones.ENCODEROUTPUTFORMAT) and (infoMusic.bitrate/1000<=headphones.BITRATE)):
logger.warn('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music,headphones.BITRATE))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
i=i+1
shutil.rmtree(tempDirEncode)
time.sleep(1)
for r,d,f in os.walk(albumPath):
for music in f:
if any(music.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
musicFinalFiles.append(os.path.join(r, music))
if ifencoded==0:
logger.info('Encoding for folder "%s" is not needed' % (albumPath))
return musicFinalFiles
tempDirEncode=os.path.join(albumPath,"temp")
musicFiles=[]
musicFinalFiles=[]
musicTempFiles=[]
encoder =""
startAlbumTime=time.time()
ifencoded=0
if not os.path.exists(tempDirEncode):
os.mkdir(tempDirEncode)
else:
shutil.rmtree(tempDirEncode)
time.sleep(1)
os.mkdir(tempDirEncode)
for r,d,f in os.walk(albumPath):
for music in f:
if any(music.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
if (headphones.ENCODERLOSSLESS):
if (music.lower().endswith('.flac')):
musicFiles.append(os.path.join(r, music))
musicTemp = os.path.normpath(os.path.splitext(music)[0]+'.'+headphones.ENCODEROUTPUTFORMAT).encode(headphones.SYS_ENCODING)
musicTempFiles.append(os.path.join(tempDirEncode, musicTemp))
else:
logger.warn('Music "%s" is already encoded' % (music))
else:
musicFiles.append(os.path.join(r, music))
musicTemp = os.path.normpath(os.path.splitext(music)[0]+'.'+headphones.ENCODEROUTPUTFORMAT).encode(headphones.SYS_ENCODING)
musicTempFiles.append(os.path.join(tempDirEncode, musicTemp))
if headphones.ENCODER=='lame':
encoder=os.path.join(headphones.ENCODERFOLDER,'lame')
elif headphones.ENCODER=='ffmpeg':
encoder=os.path.join(headphones.ENCODERFOLDER,'ffmpeg')
i=0
for music in musicFiles:
infoMusic=MediaFile(music)
if headphones.ENCODER == 'lame':
if not any(music.lower().endswith('.' + x) for x in ["mp3", "wav"]):
logger.warn('Lame cant encode "%s" format for "%s", use ffmpeg' % (os.path.splitext(music)[1],music))
else:
if (music.lower().endswith('.mp3') and (infoMusic.bitrate/1000<=headphones.BITRATE)):
logger.warn('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music,headphones.BITRATE))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
else:
if headphones.ENCODEROUTPUTFORMAT=='ogg':
if music.lower().endswith('.ogg'):
logger.warn('Can not reencode .ogg music "%s"' % (music))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
elif (headphones.ENCODEROUTPUTFORMAT=='mp3' or headphones.ENCODEROUTPUTFORMAT=='m4a'):
if (music.lower().endswith('.'+headphones.ENCODEROUTPUTFORMAT) and (infoMusic.bitrate/1000<=headphones.BITRATE)):
logger.warn('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music,headphones.BITRATE))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
i=i+1
shutil.rmtree(tempDirEncode)
time.sleep(1)
for r,d,f in os.walk(albumPath):
for music in f:
if any(music.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
musicFinalFiles.append(os.path.join(r, music))
if ifencoded==0:
logger.info('Encoding for folder "%s" is not needed' % (albumPath))
return musicFinalFiles
def command(encoder,musicSource,musicDest,albumPath):
return_code=1
cmd=''
startMusicTime=time.time()
if headphones.ENCODER == 'lame':
if headphones.ADVANCEDENCODER =='':
cmd=encoder + ' -h'
if headphones.ENCODERVBRCBR=='cbr':
cmd=cmd+ ' --resample ' + str(headphones.SAMPLINGFREQUENCY) + ' -b ' + str(headphones.BITRATE)
elif headphones.ENCODERVBRCBR=='vbr':
cmd=cmd+' -V'+str(headphones.ENCODERQUALITY)
cmd=cmd+ ' ' + headphones.ADVANCEDENCODER
else:
cmd=cmd+' '+ headphones.ADVANCEDENCODER
cmd=cmd+ ' "' + musicSource + '"'
cmd=cmd+ ' "' + musicDest +'"'
elif headphones.ENCODER == 'ffmpeg':
cmd=encoder+ ' -i'
cmd=cmd+ ' "' + musicSource + '"'
if headphones.ADVANCEDENCODER =='':
if headphones.ENCODEROUTPUTFORMAT=='ogg':
cmd=cmd+ ' -acodec libvorbis'
if headphones.ENCODEROUTPUTFORMAT=='m4a':
cmd=cmd+ ' -strict experimental'
if headphones.ENCODERVBRCBR=='cbr':
cmd=cmd+ ' -ar ' + str(headphones.SAMPLINGFREQUENCY) + ' -ab ' + str(headphones.BITRATE) + 'k'
elif headphones.ENCODERVBRCBR=='vbr':
cmd=cmd+' -aq ' + str(headphones.ENCODERQUALITY)
cmd=cmd+ ' -y -ac 2 -vn'
else:
cmd=cmd+' '+ headphones.ADVANCEDENCODER
cmd=cmd+ ' "' + musicDest + '"'
print cmd
time.sleep(10)
return_code = call(cmd, shell=True)
if (return_code==0) and (os.path.exists(musicDest)):
os.remove(musicSource)
shutil.move(musicDest,albumPath)
logger.info('Music "%s" encoded in %s' % (musicSource,getTimeEncode(startMusicTime)))
return_code=1
cmd=''
startMusicTime=time.time()
if headphones.ENCODER == 'lame':
if headphones.ADVANCEDENCODER =='':
cmd=encoder + ' -h'
if headphones.ENCODERVBRCBR=='cbr':
cmd=cmd+ ' --resample ' + str(headphones.SAMPLINGFREQUENCY) + ' -b ' + str(headphones.BITRATE)
elif headphones.ENCODERVBRCBR=='vbr':
cmd=cmd+' -V'+str(headphones.ENCODERQUALITY)
cmd=cmd+ ' ' + headphones.ADVANCEDENCODER
else:
cmd=cmd+' '+ headphones.ADVANCEDENCODER
cmd=cmd+ ' "' + musicSource + '"'
cmd=cmd+ ' "' + musicDest +'"'
elif headphones.ENCODER == 'ffmpeg':
cmd=encoder+ ' -i'
cmd=cmd+ ' "' + musicSource + '"'
if headphones.ADVANCEDENCODER =='':
if headphones.ENCODEROUTPUTFORMAT=='ogg':
cmd=cmd+ ' -acodec libvorbis'
if headphones.ENCODEROUTPUTFORMAT=='m4a':
cmd=cmd+ ' -strict experimental'
if headphones.ENCODERVBRCBR=='cbr':
cmd=cmd+ ' -ar ' + str(headphones.SAMPLINGFREQUENCY) + ' -ab ' + str(headphones.BITRATE) + 'k'
elif headphones.ENCODERVBRCBR=='vbr':
cmd=cmd+' -aq ' + str(headphones.ENCODERQUALITY)
cmd=cmd+ ' -y -ac 2 -vn'
else:
cmd=cmd+' '+ headphones.ADVANCEDENCODER
cmd=cmd+ ' "' + musicDest + '"'
print cmd
time.sleep(10)
return_code = call(cmd, shell=True)
if (return_code==0) and (os.path.exists(musicDest)):
os.remove(musicSource)
shutil.move(musicDest,albumPath)
logger.info('Music "%s" encoded in %s' % (musicSource,getTimeEncode(startMusicTime)))
def getTimeEncode(start):
seconds =int(time.time()-start)
hours = seconds / 3600
seconds -= 3600*hours
minutes = seconds / 60
seconds -= 60*minutes
return "%02d:%02d:%02d" % (hours, minutes, seconds)
seconds =int(time.time()-start)
hours = seconds / 3600
seconds -= 3600*hours
minutes = seconds / 60
seconds -= 60*minutes
return "%02d:%02d:%02d" % (hours, minutes, seconds)

View File

@@ -64,110 +64,110 @@ class PROWL:
class XBMC:
def __init__(self):
self.hosts = headphones.XBMC_HOST
self.username = headphones.XBMC_USERNAME
self.password = headphones.XBMC_PASSWORD
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 __init__(self):
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
updatecommand = {'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(music)'}
logger.info('Sending library update command to XBMC')
request = self._send(updatecommand)
if not request:
logger.warn('Error sending update request to XBMC')
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')
self.hosts = headphones.XBMC_HOST
self.username = headphones.XBMC_USERNAME
self.password = headphones.XBMC_PASSWORD
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 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
updatecommand = {'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(music)'}
logger.info('Sending library update command to XBMC')
request = self._send(updatecommand)
if not request:
logger.warn('Error sending update request to XBMC')
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')
class NMA:
def __init__(self):
self.apikey = headphones.NMA_APIKEY
self.priority = headphones.NMA_PRIORITY
def _send(self, data):
url_data = urllib.urlencode(data)
url = 'https://www.notifymyandroid.com/publicapi/notify'
req = urllib2.Request(url, url_data)
def __init__(self):
self.apikey = headphones.NMA_APIKEY
self.priority = headphones.NMA_PRIORITY
def _send(self, data):
url_data = urllib.urlencode(data)
url = 'https://www.notifymyandroid.com/publicapi/notify'
req = urllib2.Request(url, url_data)
try:
handle = urllib2.urlopen(req)
except Exception, e:
logger.warn('Error opening NotifyMyAndroid url: ' % e)
return
try:
handle = urllib2.urlopen(req)
except Exception, e:
logger.warn('Error opening NotifyMyAndroid url: ' % e)
return
response = handle.read().decode(headphones.SYS_ENCODING)
return response
def notify(self, artist, album):
apikey = self.apikey
priority = self.priority
event = artist + ' - ' + album + ' complete!'
description = "Headphones has downloaded and postprocessed: " + artist + ' [' + album + ']'
data = { 'apikey': apikey, 'application':'Headphones', 'event': event, 'description': description, 'priority': priority}
response = handle.read().decode(headphones.SYS_ENCODING)
return response
def notify(self, artist, album):
apikey = self.apikey
priority = self.priority
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')
logger.info('Sending notification request to NotifyMyAndroid')
request = self._send(data)
if not request:
logger.warn('Error sending notification request to NotifyMyAndroid')

File diff suppressed because it is too large Load Diff

View File

@@ -66,7 +66,7 @@ def sendNZB(nzb):
multiPartParams = {"nzbfile": (nzb.name+".nzb", nzb.extraInfo[0])}
if not headphones.SAB_HOST.startswith('http'):
headphones.SAB_HOST = 'http://' + headphones.SAB_HOST
headphones.SAB_HOST = 'http://' + headphones.SAB_HOST
if headphones.SAB_HOST.endswith('/'):
headphones.SAB_HOST = headphones.SAB_HOST[0:len(headphones.SAB_HOST)-1]

View File

@@ -126,9 +126,9 @@ def searchNZB(albumid=None, new=False, losslessOnly=False):
if albums[0] in albums[1] or len(albums[0]) < 4 or len(albums[1]) < 4:
term = cleanartist + ' ' + cleanalbum + ' ' + year
elif albums[0] == 'Various Artists':
term = cleanalbum + ' ' + year
term = cleanalbum + ' ' + year
else:
term = cleanartist + ' ' + cleanalbum
term = cleanartist + ' ' + cleanalbum
# Replace bad characters in the term and unicode it
term = re.sub('[\.\-\/]', ' ', term).encode('utf-8')
@@ -152,7 +152,7 @@ def searchNZB(albumid=None, new=False, losslessOnly=False):
# hopefully this will fix it for now. If you notice anything else it gets stuck on, please post it
# on Github so it can be added
if term.lower().startswith("the "):
term = term[4:]
term = term[4:]
params = { "page": "download",
@@ -169,26 +169,26 @@ def searchNZB(albumid=None, new=False, losslessOnly=False):
searchURL = "http://rss.nzbmatrix.com/rss.php?" + urllib.urlencode(params)
logger.info(u'Parsing results from <a href="%s">NZBMatrix</a>' % searchURL)
try:
data = urllib2.urlopen(searchURL, timeout=20).read()
data = urllib2.urlopen(searchURL, timeout=20).read()
except urllib2.URLError, e:
logger.warn('Error fetching data from NZBMatrix: %s' % e)
data = False
logger.warn('Error fetching data from NZBMatrix: %s' % e)
data = False
if data:
d = feedparser.parse(data)
for item in d.entries:
try:
url = item.link
title = item.title
size = int(item.links[1]['length'])
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
except AttributeError, e:
logger.info(u"No results found from NZBMatrix for %s" % term)
d = feedparser.parse(data)
for item in d.entries:
try:
url = item.link
title = item.title
size = int(item.links[1]['length'])
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
except AttributeError, e:
logger.info(u"No results found from NZBMatrix for %s" % term)
if headphones.NEWZNAB:
provider = "newznab"
@@ -211,31 +211,31 @@ def searchNZB(albumid=None, new=False, losslessOnly=False):
logger.info(u'Parsing results from <a href="%s">%s</a>' % (searchURL, headphones.NEWZNAB_HOST))
try:
data = urllib2.urlopen(searchURL, timeout=20).read()
data = urllib2.urlopen(searchURL, timeout=20).read()
except urllib2.URLError, e:
logger.warn('Error fetching data from %s: %s' % (headphones.NEWZNAB_HOST, e))
data = False
logger.warn('Error fetching data from %s: %s' % (headphones.NEWZNAB_HOST, e))
data = False
if data:
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from %s for %s" % (headphones.NEWZNAB_HOST, term))
pass
else:
for item in d.entries:
try:
url = item.link
title = item.title
size = int(item.links[1]['length'])
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
except Exception, e:
logger.error(u"An unknown error occured trying to parse the feed: %s" % e)
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from %s for %s" % (headphones.NEWZNAB_HOST, term))
pass
else:
for item in d.entries:
try:
url = item.link
title = item.title
size = int(item.links[1]['length'])
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
except Exception, e:
logger.error(u"An unknown error occured trying to parse the feed: %s" % e)
if headphones.NZBSORG:
provider = "nzbsorg"
@@ -258,31 +258,31 @@ def searchNZB(albumid=None, new=False, losslessOnly=False):
logger.info(u'Parsing results from <a href="%s">nzbs.org</a>' % searchURL)
try:
data = urllib2.urlopen(searchURL, timeout=20).read()
data = urllib2.urlopen(searchURL, timeout=20).read()
except urllib2.URLError, e:
logger.warn('Error fetching data from nzbs.org: %s' % e)
data = False
logger.warn('Error fetching data from nzbs.org: %s' % e)
data = False
if data:
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from nzbs.org for %s" % term)
pass
else:
for item in d.entries:
try:
url = item.link
title = item.title
size = int(item.links[1]['length'])
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
except Exception, e:
logger.error(u"An unknown error occured trying to parse the feed: %s" % e)
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from nzbs.org for %s" % term)
pass
else:
for item in d.entries:
try:
url = item.link
title = item.title
size = int(item.links[1]['length'])
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
except Exception, e:
logger.error(u"An unknown error occured trying to parse the feed: %s" % e)
if headphones.NEWZBIN:
provider = "newzbin"
@@ -300,9 +300,9 @@ def searchNZB(albumid=None, new=False, losslessOnly=False):
params = {
"fpn": "p",
'u_nfo_posts_only': 0,
'u_url_posts_only': 0,
'u_comment_posts_only': 0,
'u_show_passworded': 0,
'u_url_posts_only': 0,
'u_comment_posts_only': 0,
'u_show_passworded': 0,
"searchaction": "Search",
#"dl": 1,
"category": categories,
@@ -403,28 +403,28 @@ def searchNZB(albumid=None, new=False, losslessOnly=False):
if new:
while True:
if len(nzblist):
alreadydownloaded = myDB.select('SELECT * from snatched WHERE URL=?', [nzblist[0][2]])
if len(alreadydownloaded):
logger.info('%s has already been downloaded. Skipping.' % nzblist[0][0])
nzblist.pop(0)
else:
break
else:
logger.info('No more results found for %s' % term)
return "none"
while True:
if len(nzblist):
alreadydownloaded = myDB.select('SELECT * from snatched WHERE URL=?', [nzblist[0][2]])
if len(alreadydownloaded):
logger.info('%s has already been downloaded. Skipping.' % nzblist[0][0])
nzblist.pop(0)
else:
break
else:
logger.info('No more results found for %s' % term)
return "none"
logger.info(u"Pre-processing result")
(data, bestqual) = preprocess(nzblist)
if data and bestqual:
logger.info(u'Found best result: <a href="%s">%s</a> - %s' % (bestqual[2], bestqual[0], helpers.bytes_to_mb(bestqual[1])))
logger.info(u'Found best result: <a href="%s">%s</a> - %s' % (bestqual[2], bestqual[0], helpers.bytes_to_mb(bestqual[1])))
nzb_folder_name = '%s - %s [%s]' % (helpers.latinToAscii(albums[0]).encode('UTF-8').replace('/', '_'), helpers.latinToAscii(albums[1]).encode('UTF-8').replace('/', '_'), year)
if headphones.SAB_HOST and not headphones.BLACKHOLE:
@@ -455,9 +455,9 @@ def searchNZB(albumid=None, new=False, losslessOnly=False):
def verifyresult(title, artistterm, term):
title = re.sub('[\.\-\/\_]', ' ', title)
title = re.sub('[\.\-\/\_]', ' ', title)
#if artistterm != 'Various Artists':
#
# if not re.search('^' + re.escape(artistterm), title, re.IGNORECASE):
@@ -472,23 +472,23 @@ def verifyresult(title, artistterm, term):
#another attempt to weed out substrings. We don't want "Vol III" when we were looking for "Vol II"
tokens = re.split('\W', term, re.IGNORECASE | re.UNICODE)
for token in tokens:
tokens = re.split('\W', term, re.IGNORECASE | re.UNICODE)
for token in tokens:
if not token:
continue
if token == 'Various' or token == 'Artists' or token == 'VA':
continue
if not re.search('(?:\W|^)+' + token + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE):
cleantoken = ''.join(c for c in token if c not in string.punctuation)
if not not re.search('(?:\W|^)+' + cleantoken + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE):
dic = {'!':'i', '$':'s'}
dumbtoken = helpers.replace_all(token, dic)
if not not re.search('(?:\W|^)+' + dumbtoken + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE):
logger.info("Removed from results: " + title + " (missing tokens: " + token + " and " + cleantoken + ")")
return False
return True
if not token:
continue
if token == 'Various' or token == 'Artists' or token == 'VA':
continue
if not re.search('(?:\W|^)+' + token + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE):
cleantoken = ''.join(c for c in token if c not in string.punctuation)
if not not re.search('(?:\W|^)+' + cleantoken + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE):
dic = {'!':'i', '$':'s'}
dumbtoken = helpers.replace_all(token, dic)
if not not re.search('(?:\W|^)+' + dumbtoken + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE):
logger.info("Removed from results: " + title + " (missing tokens: " + token + " and " + cleantoken + ")")
return False
return True
def getresultNZB(result):
@@ -521,7 +521,7 @@ def preprocess(resultlist):
usenet_retention = 2000
else:
usenet_retention = int(headphones.USENET_RETENTION)
for result in resultlist:
nzb = getresultNZB(result)
if nzb:
@@ -581,9 +581,9 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False):
if albums[0] in albums[1] or len(albums[0]) < 4 or len(albums[1]) < 4:
term = cleanartist + ' ' + cleanalbum + ' ' + year
elif albums[0] == 'Various Artists':
term = cleanalbum + ' ' + year
term = cleanalbum + ' ' + year
else:
term = cleanartist + ' ' + cleanalbum
term = cleanartist + ' ' + cleanalbum
# Replace bad characters in the term and unicode it
term = re.sub('[\.\-\/]', ' ', term).encode('utf-8')
@@ -619,51 +619,50 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False):
searchURL = providerurl + "/?%s" % urllib.urlencode(params)
try:
data = urllib2.urlopen(searchURL, timeout=20).read()
data = urllib2.urlopen(searchURL, timeout=20).read()
except urllib2.URLError, e:
logger.warn('Error fetching data from %s: %s' % (provider, e))
data = False
logger.warn('Error fetching data from %s: %s' % (provider, e))
data = False
if data:
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from %s for %s" % (provider, term))
pass
else:
for item in d.entries:
try:
rightformat = True
title = item.title
seeders = item.seeds
url = item.links[1]['url']
size = int(item.links[1]['length'])
try:
if format == "2":
request = urllib2.Request(url)
request.add_header('Accept-encoding', 'gzip')
response = urllib2.urlopen(request)
if response.info().get('Content-Encoding') == 'gzip':
buf = StringIO( response.read())
f = gzip.GzipFile(fileobj=buf)
torrent = f.read()
else:
torrent = response.read()
if int(torrent.find(".mp3")) > 0 and int(torrent.find(".flac")) < 1:
rightformat = False
except Exception, e:
rightformat = False
if rightformat == True and size < maxsize and minimumseeders < int(seeders):
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
else:
logger.info('%s is larger than the maxsize, the wrong format or has to little seeders for this category, skipping. (Size: %i bytes, Seeders: %i, Format: %s)' % (title, size, int(seeders), rightformat))
except Exception, e:
logger.error(u"An unknown error occured in the KAT parser: %s" % e)
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from %s for %s" % (provider, term))
pass
else:
for item in d.entries:
try:
rightformat = True
title = item.title
seeders = item.seeds
url = item.links[1]['url']
size = int(item.links[1]['length'])
try:
if format == "2":
request = urllib2.Request(url)
request.add_header('Accept-encoding', 'gzip')
response = urllib2.urlopen(request)
if response.info().get('Content-Encoding') == 'gzip':
buf = StringIO( response.read())
f = gzip.GzipFile(fileobj=buf)
torrent = f.read()
else:
torrent = response.read()
if int(torrent.find(".mp3")) > 0 and int(torrent.find(".flac")) < 1:
rightformat = False
except Exception, e:
rightformat = False
if rightformat == True and size < maxsize and minimumseeders < int(seeders):
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
else:
logger.info('%s is larger than the maxsize, the wrong format or has to little seeders for this category, skipping. (Size: %i bytes, Seeders: %i, Format: %s)' % (title, size, int(seeders), rightformat))
except Exception, e:
logger.error(u"An unknown error occured in the KAT parser: %s" % e)
if headphones.ISOHUNT:
provider = "ISOhunt"
providerurl = url_fix("http://isohunt.com/js/rss/" + term)
@@ -687,54 +686,54 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False):
searchURL = providerurl + "?%s" % urllib.urlencode(params)
try:
data = urllib2.urlopen(searchURL, timeout=20).read()
data = urllib2.urlopen(searchURL, timeout=20).read()
except urllib2.URLError, e:
logger.warn('Error fetching data from %s: %s' % (provider, e))
data = False
logger.warn('Error fetching data from %s: %s' % (provider, e))
data = False
if data:
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from %s for %s" % (provider, term))
pass
else:
for item in d.entries:
try:
rightformat = True
title = re.sub(r"(?<= \[)(.+)(?=\])","",item.title)
title = title.replace("[]","")
sxstart = item.description.find("Seeds: ") + 7
seeds = ""
while item.description[sxstart:sxstart + 1] != " ":
seeds = seeds + item.description[sxstart:sxstart + 1]
sxstart = sxstart + 1
url = item.links[1]['url']
size = int(item.links[1]['length'])
try:
if format == "2":
request = urllib2.Request(url)
request.add_header('Accept-encoding', 'gzip')
response = urllib2.urlopen(request)
if response.info().get('Content-Encoding') == 'gzip':
buf = StringIO( response.read())
f = gzip.GzipFile(fileobj=buf)
torrent = f.read()
else:
torrent = response.read()
if int(torrent.find(".mp3")) > 0 and int(torrent.find(".flac")) < 1:
rightformat = False
except Exception, e:
rightformat = False
if rightformat == True and size < maxsize and minimumseeders < seeds:
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
else:
logger.info('%s is larger than the maxsize, the wrong format or has to little seeders for this category, skipping. (Size: %i bytes, Seeders: %i, Format: %s)' % (title, size, int(seeds), rightformat))
except Exception, e:
logger.error(u"An unknown error occured in the ISOhunt parser: %s" % e)
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from %s for %s" % (provider, term))
pass
else:
for item in d.entries:
try:
rightformat = True
title = re.sub(r"(?<= \[)(.+)(?=\])","",item.title)
title = title.replace("[]","")
sxstart = item.description.find("Seeds: ") + 7
seeds = ""
while item.description[sxstart:sxstart + 1] != " ":
seeds = seeds + item.description[sxstart:sxstart + 1]
sxstart = sxstart + 1
url = item.links[1]['url']
size = int(item.links[1]['length'])
try:
if format == "2":
request = urllib2.Request(url)
request.add_header('Accept-encoding', 'gzip')
response = urllib2.urlopen(request)
if response.info().get('Content-Encoding') == 'gzip':
buf = StringIO( response.read())
f = gzip.GzipFile(fileobj=buf)
torrent = f.read()
else:
torrent = response.read()
if int(torrent.find(".mp3")) > 0 and int(torrent.find(".flac")) < 1:
rightformat = False
except Exception, e:
rightformat = False
if rightformat == True and size < maxsize and minimumseeders < seeds:
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
else:
logger.info('%s is larger than the maxsize, the wrong format or has to little seeders for this category, skipping. (Size: %i bytes, Seeders: %i, Format: %s)' % (title, size, int(seeds), rightformat))
except Exception, e:
logger.error(u"An unknown error occured in the ISOhunt parser: %s" % e)
if headphones.MININOVA:
provider = "Mininova"
@@ -755,53 +754,53 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False):
searchURL = providerurl
try:
data = urllib2.urlopen(searchURL, timeout=20).read()
data = urllib2.urlopen(searchURL, timeout=20).read()
except urllib2.URLError, e:
logger.warn('Error fetching data from %s: %s' % (provider, e))
data = False
logger.warn('Error fetching data from %s: %s' % (provider, e))
data = False
if data:
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from %s for %s" % (provider, term))
pass
else:
for item in d.entries:
try:
rightformat = True
title = item.title
sxstart = item.description.find("Ratio: ") + 7
seeds = ""
while item.description[sxstart:sxstart + 1] != " ":
seeds = seeds + item.description[sxstart:sxstart + 1]
sxstart = sxstart + 1
url = item.links[1]['url']
size = int(item.links[1]['length'])
try:
if format == "2":
request = urllib2.Request(url)
request.add_header('Accept-encoding', 'gzip')
response = urllib2.urlopen(request)
if response.info().get('Content-Encoding') == 'gzip':
buf = StringIO( response.read())
f = gzip.GzipFile(fileobj=buf)
torrent = f.read()
else:
torrent = response.read()
if int(torrent.find(".mp3")) > 0 and int(torrent.find(".flac")) < 1:
rightformat = False
except Exception, e:
rightformat = False
if rightformat == True and size < maxsize and minimumseeders < seeds:
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
else:
logger.info('%s is larger than the maxsize, the wrong format or has to little seeders for this category, skipping. (Size: %i bytes, Seeders: %i, Format: %s)' % (title, size, int(seeds), rightformat))
except Exception, e:
logger.error(u"An unknown error occured in the MiniNova Parser: %s" % e)
d = feedparser.parse(data)
if not len(d.entries):
logger.info(u"No results found from %s for %s" % (provider, term))
pass
else:
for item in d.entries:
try:
rightformat = True
title = item.title
sxstart = item.description.find("Ratio: ") + 7
seeds = ""
while item.description[sxstart:sxstart + 1] != " ":
seeds = seeds + item.description[sxstart:sxstart + 1]
sxstart = sxstart + 1
url = item.links[1]['url']
size = int(item.links[1]['length'])
try:
if format == "2":
request = urllib2.Request(url)
request.add_header('Accept-encoding', 'gzip')
response = urllib2.urlopen(request)
if response.info().get('Content-Encoding') == 'gzip':
buf = StringIO( response.read())
f = gzip.GzipFile(fileobj=buf)
torrent = f.read()
else:
torrent = response.read()
if int(torrent.find(".mp3")) > 0 and int(torrent.find(".flac")) < 1:
rightformat = False
except Exception, e:
rightformat = False
if rightformat == True and size < maxsize and minimumseeders < seeds:
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
else:
logger.info('%s is larger than the maxsize, the wrong format or has to little seeders for this category, skipping. (Size: %i bytes, Seeders: %i, Format: %s)' % (title, size, int(seeds), rightformat))
except Exception, e:
logger.error(u"An unknown error occured in the MiniNova Parser: %s" % e)
@@ -847,28 +846,28 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False):
if new:
while True:
if len(torrentlist):
alreadydownloaded = myDB.select('SELECT * from snatched WHERE URL=?', [torrentlist[0][2]])
if len(alreadydownloaded):
logger.info('%s has already been downloaded. Skipping.' % torrentlist[0][0])
torrentlist.pop(0)
else:
break
else:
logger.info('No more results found for %s' % term)
return
while True:
if len(torrentlist):
alreadydownloaded = myDB.select('SELECT * from snatched WHERE URL=?', [torrentlist[0][2]])
if len(alreadydownloaded):
logger.info('%s has already been downloaded. Skipping.' % torrentlist[0][0])
torrentlist.pop(0)
else:
break
else:
logger.info('No more results found for %s' % term)
return
logger.info(u"Pre-processing result")
(data, bestqual) = preprocesstorrent(torrentlist)
if data and bestqual:
logger.info(u'Found best result: <a href="%s">%s</a> - %s' % (bestqual[2], bestqual[0], helpers.bytes_to_mb(bestqual[1])))
logger.info(u'Found best result: <a href="%s">%s</a> - %s' % (bestqual[2], bestqual[0], helpers.bytes_to_mb(bestqual[1])))
torrent_folder_name = '%s - %s [%s]' % (helpers.latinToAscii(albums[0]).encode('UTF-8').replace('/', '_'), helpers.latinToAscii(albums[1]).encode('UTF-8').replace('/', '_'), year)
if headphones.TORRENTBLACKHOLE_DIR == "sendtracker":

View File

@@ -1,440 +0,0 @@
from headphones import db
_header = '''
<html>
<head>
<title>Headphones</title>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<link rel="icon" type="image/x-icon" href="images/favicon.ico" />
<link rel="apple-touch-icon" href="images/headphoneslogo.png" />
</head>
<body>
<div class="container">'''
_shutdownheader = '''
<html>
<head>
<title>Headphones</title>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<link rel="icon" type="image/x-icon" href="images/favicon.ico" />
<link rel="apple-touch-icon" href="images/headphoneslogo.png" />
<meta http-equiv="refresh" content="%s;url=index">
</head>
<body>
<div class="container">'''
_logobar = '''
<div class="logo"><a href="home"><img src="images/headphoneslogo.png" border="0">headphones</a></div>
<div class="search"><form action="findArtist" method="GET">
<input type="text" value="Add an artist" onfocus="if
(this.value==this.defaultValue) this.value='';" name="name" />
<input type="submit" /></form></div><br />
'''
_nav = '''<div class="nav">
<a href="home">HOME</a>
<a href="upcoming">UPCOMING</a>
<a href="extras">EXTRAS</a>
<a href="manage">MANAGE</a>
<a href="history">HISTORY</a>
<a href="logs">LOGS</a>
<a href="config">SETTINGS</a>
<div style="float:right">
<a href="restart" title="Restart"><img src="images/restart.png" height="15px" width="15px" border="0"></a>
<a href="shutdown" title="Shutdown"><img src="images/shutdown.png" height="15px" width="15px" border="0"></a>
</div>
</div>'''
_footer = '''
</div><div class="footer"><br /><div class="center"><form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="93FFC6WDV97QS">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form><br /><div class="version">Version: %s</div>
</div></div>
</body>
</html>'''
configform = form = '''
<br>
<center>
<div class="smalltext">
<a href="#web_interface" >Web Interface</a> |
<a href="#download" class="smalltext">Download Settings</a> |
<a href="#providers" class="smalltext">Search Providers</a> |
<a href="#post_processing" class="smalltext">Quality &amp; Post Processing</a> |
<a href="#advanced_settings" class="smalltext">Advanced Settings</a>
</div>
</center>
<div class="table">
<div class="config">
<form action="configUpdate" method="post">
<a name="web_interface"><h1><u>Web Interface</u></h1></a>
<table class="configtable" summary="Web Interface">
<tr>
<td>
<p>
HTTP Host: <br><br>
<input type="text" name="http_host" value="%s" size="30" maxlength="40"><br>
<i class="smalltext">i.e. localhost or 0.0.0.0</i>
</p>
</td>
<td>
<p>
HTTP Username: <br><br>
<input type="text" name="http_username" value="%s" size="30" maxlength="40">
</p>
</td>
</tr>
<tr>
<td>
<p>
HTTP Port: <br><br>
<input type="text" name="http_port" value="%s" size="20" maxlength="40">
</p>
</td>
<td>
<p>
HTTP Password: <br><br>
<input type="password" name="http_password" value="%s" size="30" maxlength="40">
</p>
</td>
</tr>
<tr>
<td>
<p>Launch Browser on Startup:<input type="checkbox" name="launch_browser" value="1" %s /></p>
</td>
</tr>
</table>
<a name="download"><h1><u>Download Settings</u></h1></a>
<table class="configtable" summary="Download Settings">
<tr>
<td>
<p>SABnzbd Host:</p><input type="text" name="sab_host" value="%s" size="30" maxlength="40"><br>
<i class="smalltext">usually localhost:8080</i>
</td>
<td>
<p>SABnzbd Username:</p><input type="text" name="sab_username" value="%s" size="20" maxlength="40">
</td>
</tr>
<tr>
<td>
<br>
<p>SABnzbd API:</p><input type="text" name="sab_apikey" value="%s" size="46" maxlength="40">
</td>
<td>
<br>
<p>SABnzbd Password:</p><input type="password" name="sab_password" value="%s" size="20" maxlength="40">
</td>
</tr>
<tr>
<td>
<br>
<p>SABnzbd Category:</p><input type="text" name="sab_category" value="%s" size="20" maxlength="40">
</td>
<td>
<br>
<p>Music Download Directory:</p><input type="text" name="download_dir" value="%s" size="60"><br>
<i class="smalltext">Full path to the directory where SAB downloads your music<br>
i.e. /Users/name/Downloads/music</i>
</td>
</tr>
<tr>
<td>
<br>
<p>Use Black Hole:</p><input type="checkbox" name="blackhole" value=1 %s />
</td>
<td>
<br>
<p>Black Hole Directory:</p><input type="text" name="blackhole_dir" value="%s" size="60"><br>
<i class="smalltext">Folder your Download program watches for NZBs</i>
</td>
</tr>
<tr>
<td>
<br>
<p>Usenet Retention:</p><input type="text" name="usenet_retention" value="%s" size="20" maxlength="40">
</td>
</tr>
</table>
<a name="providers"><h1><u>Search Providers</u></h1></a>
<table class="configtable" summary="Search Providers">
<tr>
<td>
<p>NZBMatrix: <input type="checkbox" name="nzbmatrix" value="1" %s /></p>
</td>
<td>
<p>
NZBMatrix Username: <br>
<input type="text" name="nzbmatrix_username" value="%s" size="30" maxlength="40">
</p>
</td>
<td>
<p>
NZBMatrix API: <br>
<input type="text" name="nzbmatrix_apikey" value="%s" size="46" maxlength="40">
</p>
</td>
</tr>
<tr>
<td>
<br>
<p>Newznab: <input type="checkbox" name="newznab" value="1" %s /></p>
</td>
<td>
<br>
<p>
Newznab Host:<br>
<input type="text" name="newznab_host" value="%s" size="30" maxlength="40"><br>
<i class="smalltext">i.e. http://nzb.su</i>
</p>
</td>
<td>
<br>
<p>
Newznab API:<br>
<input type="text" name="newznab_apikey" value="%s" size="46" maxlength="40">
</p>
</td>
</tr>
<tr>
<td>
<br>
<p>NZBs.org:<input type="checkbox" name="nzbsorg" value="1" %s /></p>
</td>
<td>
<br>
<p>
NZBs.org UID:<br>
<input type="text" name="nzbsorg_uid" value="%s" size="30" maxlength="40">
</p>
</td>
<td>
<br>
<p>
NZBs.org Hash:<br>
<input type="text" name="nzbsorg_hash" value="%s" size="46" maxlength="40">
</p>
</td>
</tr>
<tr>
<td>
<br>
<p>Newzbin:<input type="checkbox" name="newzbin" value="1" %s /></p>
</td>
<td>
<br>
<p>
Newzbin UID:<br>
<input type="text" name="newzbin_uid" value="%s" size="30" maxlength="40">
</p>
</td>
<td>
<br>
<p>
Newzbin Password:<br>
<input type="text" name="newzbin_password" value="%s" size="46" maxlength="40">
</p>
</td>
</tr>
</table>
<a name="post_processing"><h1><u>Quality &amp; Post Processing</u></h1></a>
<table class="configtable" summary="Quality & Post Processing">
<tr>
<td>
<b>Album Quality:</b>
<p>
<input type="radio" name="preferred_quality" value="0" %s />Highest Quality excluding Lossless<br /><br />
<input type="radio" name="preferred_quality" value="1" %s />Highest Quality including Lossless<br /><br />
<input type="radio" name="preferred_quality" value="3" %s />Lossless Only<br /><br />
<input type="radio" name="preferred_quality" value="2" %s />Preferred Bitrate:
<input type="text" name="preferred_bitrate" value="%s" size="5" maxlength="5" />kbps <br>
<i class="smalltext2"><input type="checkbox" name="detect_bitrate" value="1" %s />Auto-Detect Preferred Bitrate </i>
</p>
</td>
<td>
<b>Post-Processing:</b>
<p>
<input type="checkbox" name="move_files" value="1" %s />Move downloads to Destination Folder<br />
<input type="checkbox" name="rename_files" value="1" %s />Rename files<br>
<input type="checkbox" name="correct_metadata" value="1" %s />Correct metadata<br>
<input type="checkbox" name="cleanup_files" value="1" %s />Delete leftover files (.m3u, .nfo, .sfv, .nzb, etc.)<br>
<input type="checkbox" name="add_album_art" value="1" %s>Add album art as 'folder.jpg' to album folder<br>
<input type="checkbox" name="embed_album_art" value="1" %s>Embed album art in each file
</p>
</td>
</tr>
<tr>
<td>
<br>
<p><b>Path to Destination folder</b>:<br><input type="text" name="destination_dir" value="%s" size="60">
<br>
<i class="smalltext">i.e. /Users/name/Music/iTunes or /Volumes/share/music</i>
</p>
</td>
</tr>
</table>
<a name="advanced_settings"><h1><u>Advanced Settings</u></h1></a>
<table class="configtable" summary="Advanced Settings">
<tr>
<td>
<b>Renaming Options:</b>
<br>
<p><b>Folder Format</b>:<br><input type="text" name="folder_format" value="%s" size="60">
<br>
<i class="smalltext">Use: artist, album, year and first (first letter in artist name)<br />
E.g.: first/artist/album [year] = G/Girl Talk/All Day [2010]</i>
</p>
<p><b>File Format</b>:<br><input type="text" name="file_format" value="%s" size="60">
<br>
<i class="smalltext">Use: tracknumber, title, artist, album and year</i>
</p>
</td>
<td>
<b>Miscellaneous:</b>
<p>
<input type="checkbox" name="include_extras" value="1" %s />Automatically Include Extras When Adding an Artist<br />
<i class="smalltext">Extras includes: EPs, Compilations, Live Albums, Remix Albums and Singles</i>
</p>
<p><b>Log Directory</b>:<br><input type="text" name="log_dir" value="%s" size="60">
</p>
</td>
<td>
<b>Prowl Notification:</b>
<p>
<input type="checkbox" name="prowl_enabled" value="1" %s />Enabled?
</p>
<p>
<i class="smalltext">API key:</i>
<input type="text" name="prowl_keys" value="%s" size="50">
</p>
<p>
<input type="checkbox" name="prowl_onsnatch" value="1" %s />Notify on snatch?</p>
<p><b>Priority (-2,-1,0,1 or 2):</b><input type="text" name="prowl_priority" value="%s" size="5">
</p>
</td>
</tr>
</table>
<p class="center"><input type="submit" value="Save Changes"><br>
(Web Interface changes require a restart to take effect)</p>
</form>
</div>
</div>'''
def displayAlbums(ArtistID, Type=None):
myDB = db.DBConnection()
results = myDB.select('SELECT AlbumTitle, ReleaseDate, AlbumID, Status, ArtistName, AlbumASIN from albums WHERE ArtistID=? AND Type=? order by ReleaseDate DESC', [ArtistID, Type])
if not len(results):
return
typeheadings = {'Album' : 'Official Albums',
'Compilation': 'Compilations',
'EP': 'EPs',
'Live': 'Live Albums',
'Remix': 'Remixes',
'Single': 'Singles'}
page = ['''<p class="mediumcentered">%s</p>
<table border="0" cellpadding="3">
<tr>
<th align="left" width="30"></th>
<th align="left" width="120">Album Name</th>
<th align="center" width="100">Release Date</th>
<th align="center" width="180">Status</th>
<th align="center">Have</th>
</tr>''' % typeheadings[Type]]
i = 0
while i < len(results):
totaltracks = len(myDB.select('SELECT TrackTitle from tracks WHERE AlbumID=?', [results[i][2]]))
havetracks = len(myDB.select('SELECT TrackTitle from have WHERE ArtistName like ? AND AlbumTitle like ?', [results[i][4], results[i][0]]))
try:
percent = (havetracks*100)/totaltracks
if percent > 100:
percent = 100
except ZeroDivisionError:
percent = 100
if results[i][3] == 'Skipped':
newStatus = '''%s [<A class="external" href="queueAlbum?AlbumID=%s&ArtistID=%s">want</a>]''' % (results[i][3], results[i][2], ArtistID)
elif results[i][3] == 'Wanted':
newStatus = '''<b>%s</b>[<A class="external" href="unqueueAlbum?AlbumID=%s&ArtistID=%s">skip</a>]''' % (results[i][3], results[i][2], ArtistID)
elif results[i][3] == 'Downloaded':
newStatus = '''<b>%s</b>[<A class="external" href="queueAlbum?AlbumID=%s&ArtistID=%s">retry</a>][<A class="external" href="queueAlbum?AlbumID=%s&ArtistID=%s&new=True">new</a>]''' % (results[i][3], results[i][2], ArtistID, results[i][2], ArtistID)
elif results[i][3] == 'Snatched':
newStatus = '''<b>%s</b>[<A class="external" href="queueAlbum?AlbumID=%s&ArtistID=%s">retry</a>][<A class="external" href="queueAlbum?AlbumID=%s&ArtistID=%s&new=True">new</a>]''' % (results[i][3], results[i][2], ArtistID, results[i][2], ArtistID)
else:
newStatus = '%s' % (results[i][3])
page.append('''<tr>
<td align="left">
<td align="left" width="240"><a href="albumPage?AlbumID=%s">%s</a>
(<A class="external" href="http://musicbrainz.org/release-group/%s.html">link</a>)</td>
<td align="center" width="160">%s</td>
<td align="center">%s</td>
<td><div class="progress-container"><div style="width: %s%%"><div class="smalltext3">%s/%s</div></div></div></td>
</tr>''' % (results[i][5], results[i][2], results[i][0], results[i][2], results[i][1], newStatus, percent, havetracks, totaltracks))
i = i+1
page.append('</table><br />')
return ''.join(page)

View File

@@ -4,15 +4,15 @@ from headphones import logger, db, importer
def dbUpdate():
myDB = db.DBConnection()
myDB = db.DBConnection()
activeartists = myDB.select('SELECT ArtistID, ArtistName from artists WHERE Status="Active" or Status="Loading" order by LastUpdated ASC')
activeartists = myDB.select('SELECT ArtistID, ArtistName from artists WHERE Status="Active" or Status="Loading" order by LastUpdated ASC')
logger.info('Starting update for %i active artists' % len(activeartists))
for artist in activeartists:
artistid = artist[0]
importer.addArtisttoDB(artistid)
logger.info('Update complete')
logger.info('Starting update for %i active artists' % len(activeartists))
for artist in activeartists:
artistid = artist[0]
importer.addArtisttoDB(artistid)
logger.info('Update complete')

View File

@@ -10,205 +10,205 @@ branch = "master"
def runGit(args):
if headphones.GIT_PATH:
git_locations = ['"'+headphones.GIT_PATH+'"']
else:
git_locations = ['git']
if platform.system().lower() == 'darwin':
git_locations.append('/usr/local/git/bin/git')
output = err = None
for cur_git in git_locations:
cmd = cur_git+' '+args
try:
logger.debug('Trying to execute: "' + cmd + '" with shell in ' + headphones.PROG_DIR)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=headphones.PROG_DIR)
output, err = p.communicate()
logger.debug('Git output: ' + output)
except OSError:
logger.debug('Command ' + cmd + ' didn\'t work, couldn\'t find git')
continue
if 'not found' in output or "not recognized as an internal or external command" in output:
logger.debug('Unable to find git with command ' + cmd)
output = None
elif 'fatal:' in output or err:
logger.error('Git returned bad info. Are you sure this is a git installation?')
output = None
elif output:
break
return (output, err)
if headphones.GIT_PATH:
git_locations = ['"'+headphones.GIT_PATH+'"']
else:
git_locations = ['git']
if platform.system().lower() == 'darwin':
git_locations.append('/usr/local/git/bin/git')
output = err = None
for cur_git in git_locations:
cmd = cur_git+' '+args
try:
logger.debug('Trying to execute: "' + cmd + '" with shell in ' + headphones.PROG_DIR)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=headphones.PROG_DIR)
output, err = p.communicate()
logger.debug('Git output: ' + output)
except OSError:
logger.debug('Command ' + cmd + ' didn\'t work, couldn\'t find git')
continue
if 'not found' in output or "not recognized as an internal or external command" in output:
logger.debug('Unable to find git with command ' + cmd)
output = None
elif 'fatal:' in output or err:
logger.error('Git returned bad info. Are you sure this is a git installation?')
output = None
elif output:
break
return (output, err)
def getVersion():
if version.HEADPHONES_VERSION.startswith('build '):
headphones.INSTALL_TYPE = 'win'
# Don't have a way to update exe yet, but don't want to set VERSION to None
return 'Windows Install'
elif os.path.isdir(os.path.join(headphones.PROG_DIR, '.git')):
headphones.INSTALL_TYPE = 'git'
output, err = runGit('rev-parse HEAD')
if not output:
logger.error('Couldn\'t find latest installed version.')
return None
cur_commit_hash = output.strip()
if not re.match('^[a-z0-9]+$', cur_commit_hash):
logger.error('Output doesn\'t look like a hash, not using it')
return None
return cur_commit_hash
else:
headphones.INSTALL_TYPE = 'source'
version_file = os.path.join(headphones.PROG_DIR, 'version.txt')
if not os.path.isfile(version_file):
return None
fp = open(version_file, 'r')
current_version = fp.read().strip(' \n\r')
fp.close()
if current_version:
return current_version
else:
return None
if version.HEADPHONES_VERSION.startswith('build '):
headphones.INSTALL_TYPE = 'win'
# Don't have a way to update exe yet, but don't want to set VERSION to None
return 'Windows Install'
elif os.path.isdir(os.path.join(headphones.PROG_DIR, '.git')):
headphones.INSTALL_TYPE = 'git'
output, err = runGit('rev-parse HEAD')
if not output:
logger.error('Couldn\'t find latest installed version.')
return None
cur_commit_hash = output.strip()
if not re.match('^[a-z0-9]+$', cur_commit_hash):
logger.error('Output doesn\'t look like a hash, not using it')
return None
return cur_commit_hash
else:
headphones.INSTALL_TYPE = 'source'
version_file = os.path.join(headphones.PROG_DIR, 'version.txt')
if not os.path.isfile(version_file):
return None
fp = open(version_file, 'r')
current_version = fp.read().strip(' \n\r')
fp.close()
if current_version:
return current_version
else:
return None
def checkGithub():
# Get the latest commit available from github
url = 'https://api.github.com/repos/%s/headphones/commits/%s' % (user, branch)
logger.info ('Retrieving latest version information from github')
try:
result = urllib2.urlopen(url).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' % (user, headphones.CURRENT_VERSION, headphones.LATEST_VERSION)
try:
result = urllib2.urlopen(url).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
# Get the latest commit available from github
url = 'https://api.github.com/repos/%s/headphones/commits/%s' % (user, branch)
logger.info ('Retrieving latest version information from github')
try:
result = urllib2.urlopen(url).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' % (user, headphones.CURRENT_VERSION, headphones.LATEST_VERSION)
try:
result = urllib2.urlopen(url).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
def update():
if headphones.INSTALL_TYPE == 'win':
logger.info('Windows .exe updating not supported yet.')
pass
if headphones.INSTALL_TYPE == 'win':
logger.info('Windows .exe updating not supported yet.')
pass
elif headphones.INSTALL_TYPE == 'git':
output, err = runGit('pull origin ' + version.HEADPHONES_VERSION)
if not output:
logger.error('Couldn\'t download latest version')
for line in output.split('\n'):
if 'Already up-to-date.' in line:
logger.info('No update available, not updating')
logger.info('Output: ' + str(output))
elif line.endswith('Aborting.'):
logger.error('Unable to update from git: '+line)
logger.info('Output: ' + str(output))
else:
tar_download_url = 'https://github.com/%s/headphones/tarball/%s' % (user, branch)
update_dir = os.path.join(headphones.PROG_DIR, 'update')
version_path = os.path.join(headphones.PROG_DIR, 'version.txt')
try:
logger.info('Downloading update from: '+tar_download_url)
data = urllib2.urlopen(tar_download_url)
except (IOError, URLError):
logger.error("Unable to retrieve new version from "+tar_download_url+", can't update")
return
download_name = data.geturl().split('/')[-1]
tar_download_path = os.path.join(headphones.PROG_DIR, download_name)
# Save tar to disk
f = open(tar_download_path, 'wb')
f.write(data.read())
f.close()
# Extract the tar to update folder
logger.info('Extracing file' + tar_download_path)
tar = tarfile.open(tar_download_path)
tar.extractall(update_dir)
tar.close()
# Delete the tar.gz
logger.info('Deleting file' + tar_download_path)
os.remove(tar_download_path)
# Find update dir name
update_dir_contents = [x for x in os.listdir(update_dir) if os.path.isdir(os.path.join(update_dir, x))]
if len(update_dir_contents) != 1:
logger.error(u"Invalid update data, update failed: "+str(update_dir_contents))
return
content_dir = os.path.join(update_dir, update_dir_contents[0])
# walk temp folder and move files to main folder
for dirname, dirnames, filenames in os.walk(content_dir):
dirname = dirname[len(content_dir)+1:]
for curfile in filenames:
old_path = os.path.join(content_dir, dirname, curfile)
new_path = os.path.join(headphones.PROG_DIR, dirname, curfile)
if os.path.isfile(new_path):
os.remove(new_path)
os.renames(old_path, new_path)
# Update version.txt
try:
ver_file = open(version_path, 'w')
ver_file.write(headphones.LATEST_VERSION)
ver_file.close()
except IOError, e:
logger.error(u"Unable to write current version to version.txt, update not complete: "+ex(e))
return
elif headphones.INSTALL_TYPE == 'git':
output, err = runGit('pull origin ' + version.HEADPHONES_VERSION)
if not output:
logger.error('Couldn\'t download latest version')
for line in output.split('\n'):
if 'Already up-to-date.' in line:
logger.info('No update available, not updating')
logger.info('Output: ' + str(output))
elif line.endswith('Aborting.'):
logger.error('Unable to update from git: '+line)
logger.info('Output: ' + str(output))
else:
tar_download_url = 'https://github.com/%s/headphones/tarball/%s' % (user, branch)
update_dir = os.path.join(headphones.PROG_DIR, 'update')
version_path = os.path.join(headphones.PROG_DIR, 'version.txt')
try:
logger.info('Downloading update from: '+tar_download_url)
data = urllib2.urlopen(tar_download_url)
except (IOError, URLError):
logger.error("Unable to retrieve new version from "+tar_download_url+", can't update")
return
download_name = data.geturl().split('/')[-1]
tar_download_path = os.path.join(headphones.PROG_DIR, download_name)
# Save tar to disk
f = open(tar_download_path, 'wb')
f.write(data.read())
f.close()
# Extract the tar to update folder
logger.info('Extracing file' + tar_download_path)
tar = tarfile.open(tar_download_path)
tar.extractall(update_dir)
tar.close()
# Delete the tar.gz
logger.info('Deleting file' + tar_download_path)
os.remove(tar_download_path)
# Find update dir name
update_dir_contents = [x for x in os.listdir(update_dir) if os.path.isdir(os.path.join(update_dir, x))]
if len(update_dir_contents) != 1:
logger.error(u"Invalid update data, update failed: "+str(update_dir_contents))
return
content_dir = os.path.join(update_dir, update_dir_contents[0])
# walk temp folder and move files to main folder
for dirname, dirnames, filenames in os.walk(content_dir):
dirname = dirname[len(content_dir)+1:]
for curfile in filenames:
old_path = os.path.join(content_dir, dirname, curfile)
new_path = os.path.join(headphones.PROG_DIR, dirname, curfile)
if os.path.isfile(new_path):
os.remove(new_path)
os.renames(old_path, new_path)
# Update version.txt
try:
ver_file = open(version_path, 'w')
ver_file.write(headphones.LATEST_VERSION)
ver_file.close()
except IOError, e:
logger.error(u"Unable to write current version to version.txt, update not complete: "+ex(e))
return

File diff suppressed because it is too large Load Diff

View File

@@ -10,16 +10,16 @@ from headphones.webserve import WebInterface
def initialize(options={}):
cherrypy.config.update({
'log.screen': False,
'server.thread_pool': 10,
'server.socket_port': options['http_port'],
'server.socket_host': options['http_host'],
'engine.autoreload_on': False,
})
cherrypy.config.update({
'log.screen': False,
'server.thread_pool': 10,
'server.socket_port': options['http_port'],
'server.socket_host': options['http_host'],
'engine.autoreload_on': False,
})
conf = {
'/': {
conf = {
'/': {
'tools.staticdir.root': os.path.join(headphones.PROG_DIR, 'data')
},
'/interfaces':{
@@ -39,32 +39,32 @@ def initialize(options={}):
'tools.staticdir.dir': "js"
},
'/favicon.ico':{
'tools.staticfile.on': True,
'tools.staticfile.filename': "images/favicon.ico"
'tools.staticfile.on': True,
'tools.staticfile.filename': "images/favicon.ico"
}
}
if options['http_password'] != "":
conf['/'].update({
'tools.auth_basic.on': True,
'tools.auth_basic.realm': 'Headphones',
'tools.auth_basic.checkpassword': cherrypy.lib.auth_basic.checkpassword_dict(
{options['http_username']:options['http_password']})
})
if options['http_password'] != "":
conf['/'].update({
'tools.auth_basic.on': True,
'tools.auth_basic.realm': 'Headphones',
'tools.auth_basic.checkpassword': cherrypy.lib.auth_basic.checkpassword_dict(
{options['http_username']:options['http_password']})
})
# Prevent time-outs
cherrypy.engine.timeout_monitor.unsubscribe()
cherrypy.tree.mount(WebInterface(), options['http_root'], config = conf)
try:
cherrypy.process.servers.check_port(options['http_host'], options['http_port'])
cherrypy.server.start()
except IOError:
print 'Failed to start on port: %i. Is something else running?' % (options['http_port'])
sys.exit(0)
cherrypy.server.wait()
# Prevent time-outs
cherrypy.engine.timeout_monitor.unsubscribe()
cherrypy.tree.mount(WebInterface(), options['http_root'], config = conf)
try:
cherrypy.process.servers.check_port(options['http_host'], options['http_port'])
cherrypy.server.start()
except IOError:
print 'Failed to start on port: %i. Is something else running?' % (options['http_port'])
sys.exit(0)
cherrypy.server.wait()