Merge branch 'master' into misc

This commit is contained in:
Antoine Bertin
2011-08-23 19:50:13 +02:00
9 changed files with 126 additions and 51 deletions

View File

@@ -25,6 +25,9 @@
<%def name="body()">
<div id="paddingheader">
<h1>${artist['ArtistName']}<h1>
%if artist['Status'] == 'Loading':
<h3><i>(Album information for this artist is currently being loaded)</i></h3>
%endif
</div>
<form action="markAlbums" method="get"><input type="hidden" name="ArtistID" value=${artist['ArtistID']}>
<p class="indented">Mark selected albums as

View File

@@ -25,6 +25,9 @@
<%def name="body()">
<div id="paddingheader">
<h1>${artist['ArtistName']}<h1>
%if artist['Status'] == 'Loading':
<h3><i>(Album information for this artist is currently being loaded)</i></h3>
%endif
</div>
<form action="markAlbums" method="get"><input type="hidden" name="ArtistID" value=${artist['ArtistID']}>
<p class="indented">Mark selected albums as

View File

@@ -120,7 +120,8 @@ BITRATE = None
SAMPLINGFREQUENCY = None
ADVANCEDENCODER = None
ENCODEROUTPUTFORMAT = None
VORBISQUALITY = None
ENCODERQUALITY = None
ENCODERVBRCBR = None
def CheckSection(sec):
""" Check if INI section exists, if not create it """
@@ -180,7 +181,7 @@ def initialize():
LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \
NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, \
NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, \
ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, ENCODE, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, VORBISQUALITY
ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, ENCODE, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRVBR
if __INITIALIZED__:
return False
@@ -269,7 +270,8 @@ def initialize():
ENCODE = bool(check_setting_int(CFG, 'General', 'encode', 0))
ADVANCEDENCODER = check_setting_str(CFG, 'General', 'advancedencoder', '')
ENCODEROUTPUTFORMAT = check_setting_str(CFG, 'General', 'encoderoutputformat', 'mp3')
VORBISQUALITY = check_setting_int(CFG, 'General', 'vorbisquality', 60)
ENCODERQUALITY = check_setting_int(CFG, 'General', 'vorbisquality', 60)
ENCODERVBRCBR = check_setting_str(CFG, 'General', 'encodervbrcbr', 'cbr')
if not LOG_DIR:
LOG_DIR = os.path.join(DATA_DIR, 'logs')
@@ -455,8 +457,9 @@ def config_write():
new_config['General']['encoderfolder'] = ENCODERFOLDER
new_config['General']['advancedencoder'] = ADVANCEDENCODER
new_config['General']['encoderoutputformat'] = ENCODEROUTPUTFORMAT
new_config['General']['vorbisquality'] = VORBISQUALITY
new_config['General']['encoderquality'] = ENCODERQUALITY
new_config['General']['encodervbrcbr'] = ENCODERVBRCBR
new_config.write()

View File

@@ -13,12 +13,14 @@ except ImportError:
import lib.argparse as argparse
def encode(albumPath):
tempDirEncode=os.path.join(albumPath,"temp")
musicFiles=[]
musicFinalFiles=[]
musicTempFiles=[]
encoder =""
startAlbumTime=time.clock()
ifencoded=0
if not os.path.exists(tempDirEncode):
os.mkdir(tempDirEncode)
else:
@@ -30,7 +32,7 @@ def encode(albumPath):
for music in f:
if any(music.endswith('.' + x) for x in headphones.MEDIA_FORMATS):
musicFiles.append(os.path.join(r, music))
musicTemp = os.path.splitext(music)[0]+'.'+headphones.ENCODEROUTPUTFORMAT
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':
@@ -49,33 +51,46 @@ def encode(albumPath):
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.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.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)
logger.info('Encoding for folder "%s" is completed' % (albumPath))
time.sleep(1)
for r,d,f in os.walk(albumPath):
for music in f:
if any(music.endswith('.' + x) 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))
else:
logger.info('Encoding for folder "%s" is completed in %s' % (albumPath,getTimeEncode(startAlbumTime)))
return musicFinalFiles
def command(encoder,musicSource,musicDest,albumPath):
return_code=1
cmd=''
startMusicTime=time.clock()
if headphones.ENCODER == 'lame':
cmd=encoder + ' -h --resample ' + str(headphones.SAMPLINGFREQUENCY) + ' -b ' + str(headphones.BITRATE)
cmd=encoder + ' -h'
if headphones.ENCODERVBRCBR=='cbr':
cmd=cmd+ ' --resample ' + str(headphones.SAMPLINGFREQUENCY) + ' -b ' + str(headphones.BITRATE)
elif headphones.ENCODERVBRCBR=='vbr':
cmd=cmd+''
cmd=cmd+ ' ' + headphones.ADVANCEDENCODER
cmd=cmd+ ' "' + musicSource + '"'
cmd=cmd+ ' "' + musicDest +'"'
@@ -86,10 +101,23 @@ def command(encoder,musicSource,musicDest,albumPath):
cmd=cmd+ ' -acodec libvorbis'
if headphones.ENCODEROUTPUTFORMAT=='m4a':
cmd=cmd+ ' -strict experimental'
cmd=cmd+ ' -y -ac 2 -map_metadata 0:0,s0 -vn -ar ' + str(headphones.SAMPLINGFREQUENCY) + ' -ab ' + str(headphones.BITRATE) + 'k'
if headphones.ENCODERVBRCBR=='cbr':
cmd=cmd+ ' -ar ' + str(headphones.SAMPLINGFREQUENCY) + ' -ab ' + str(headphones.BITRATE) + 'k'
elif headphones.ENCODERVBRCBR=='vbr':
cmd=cmd+''
cmd=cmd+ ' -y -ac 2 -map_metadata 0:0,s0 -vn'
cmd=cmd+ ' ' + headphones.ADVANCEDENCODER
cmd=cmd+ ' "' + musicDest + '"'
return_code = call(cmd, shell=True)
if (return_code==0) and (os.path.exists(musicDest)):
os.remove(musicSource)
shutil.move(musicDest,albumPath)
shutil.move(musicDest,albumPath)
logger.info('Music "%s" encoded in %s' % (musicSource,getTimeEncode(startMusicTime)))
def getTimeEncode(start):
seconds =int(time.clock()-start)
hours = seconds / 3600
seconds -= 3600*hours
minutes = seconds / 60
seconds -= 60*minutes
return "%02d:%02d:%02d" % (hours, minutes, seconds)

View File

@@ -121,6 +121,17 @@ def cleanName(string):
return out_string
def cleanTitle(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

View File

@@ -8,15 +8,6 @@ from headphones import db, logger, helpers, importer
def libraryScan(dir=None):
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=? WHERE TrackID=?', [None, track['TrackID']])
if not dir:
dir = headphones.MUSIC_DIR
@@ -24,6 +15,19 @@ def libraryScan(dir=None):
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=? WHERE TrackID=?', [None, None, track['TrackID']])
logger.info('Scanning music directory: %s' % dir)
@@ -114,12 +118,14 @@ def libraryScan(dir=None):
firstchar = '0-9'
else:
firstchar = sortname[0]
lowerfirst = firstchar.lower()
albumvalues = { 'artist': artist,
'album': album,
'year': year,
'first': firstchar,
'lowerfirst': lowerfirst
}
@@ -145,16 +151,18 @@ def libraryScan(dir=None):
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))
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:
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=?', [match[0], track['TrackID']])
myDB.action('DELETE from have WHERE Location=?', [match[0]])
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:

View File

@@ -7,8 +7,8 @@ from headphones import logger
def getLyrics(artist, song):
params = { "artist": artist,
"song": song,
params = { "artist": artist.encode('utf-8'),
"song": song.encode('utf-8'),
"fmt": 'xml'
}
@@ -43,7 +43,12 @@ def getLyrics(artist, song):
m = re.compile('''<div class='lyricbox'><div class='rtMatcher'>.*?</div>(.*?)<!--''').search(lyricspage)
if not m:
return
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)

View File

@@ -453,7 +453,7 @@ def findAlbumID(artist=None, album=None):
try:
results = q.getReleaseGroups(f)
break
except WebServiceError, e:
except Exception, e:
logger.warn('Attempt to query MusicBrainz for %s - %s failed: %s. Sleeping 5 seconds.' % (artist, album, e))
attempt += 1
time.sleep(5)

View File

@@ -18,7 +18,7 @@ def checkFolder():
if album['FolderName']:
album_path = os.path.join(headphones.DOWNLOAD_DIR, album['FolderName'])
album_path = os.path.join(headphones.DOWNLOAD_DIR, album['FolderName']).encode(headphones.SYS_ENCODING)
if os.path.exists(album_path):
logger.debug('Found %s. Verifying....' % album['FolderName'])
@@ -36,13 +36,17 @@ def verify(albumid, albumpath):
#TODO: This should be a call to a class method.. copied it out of importer with only minor changes
#TODO: odd things can happen when there are diacritic characters in the folder name, need to translate them?
import mb
release_dict = None
try:
release_dict = mb.getReleaseGroup(albumid)
except Exception, e:
logger.info('Unable to get release information for manual album with rgid: ' + albumid)
logger.info('Unable to get release information for manual album with rgid: %s. Error: %s' % (albumid, e))
return
if not release_dict:
logger.warn('Unable to get release information for manual album with rgid: ' + albumid)
logger.info('Unable to get release information for manual album with rgid: %s' % albumid)
return
logger.info(u"Now adding/updating artist: " + release_dict['artist_name'])
@@ -110,8 +114,6 @@ def verify(albumid, albumpath):
release = myDB.action('SELECT * from albums WHERE AlbumID=?', [albumid]).fetchone()
tracks = myDB.select('SELECT * from tracks WHERE AlbumID=?', [albumid])
albumpath = albumpath.encode(headphones.SYS_ENCODING)
downloaded_track_list = []
for r,d,f in os.walk(albumpath):
@@ -302,12 +304,15 @@ def moveFiles(albumpath, release, tracks):
firstchar = '0-9'
else:
firstchar = sortname[0]
lowerfirst = firstchar.lower()
values = { 'artist': artist,
'album': album,
'year': year,
'first': firstchar,
'lowerfirst': lowerfirst
}
@@ -429,21 +434,27 @@ def renameFiles(albumpath, downloaded_track_list, release):
tracknumber = '%02d' % f.track
if not f.title:
basename = os.path.basename(downloaded_track)
basename = unicode(os.path.basename(downloaded_track), headphones.SYS_ENCODING, errors='replace')
title = os.path.splitext(basename)[0]
ext = os.path.splitext(basename)[1]
new_file_name = helpers.cleanTitle(title) + ext
else:
title = f.title
values = { 'tracknumber': tracknumber,
'title': title,
'artist': release['ArtistName'],
'album': release['AlbumTitle'],
'year': year
}
ext = os.path.splitext(downloaded_track)[1]
values = { 'tracknumber': tracknumber,
'title': title,
'artist': release['ArtistName'],
'album': release['AlbumTitle'],
'year': year
}
ext = os.path.splitext(downloaded_track)[1]
new_file_name = helpers.replace_all(headphones.FILE_FORMAT, values).replace('/','_') + ext
new_file_name = helpers.replace_all(headphones.FILE_FORMAT, values).replace('/','_') + ext
new_file_name = new_file_name.replace('?','_').replace(':', '_').encode(headphones.SYS_ENCODING)
@@ -508,14 +519,14 @@ def forcePostProcess():
logger.error('No DOWNLOAD_DIR has been set. Set "Music Download Directory:" to your SAB download directory on the settings page.')
return
else:
download_dir = headphones.DOWNLOAD_DIR
download_dir = headphones.DOWNLOAD_DIR.encode('utf-8')
logger.info('Checking to see if there are any folders to process in download_dir: %s' % download_dir)
# Get a list of folders in the download_dir
folders = [d for d in os.listdir(download_dir) if os.path.isdir(os.path.join(download_dir, d))]
if len(folders):
logger.info('Found %i folders: %s' % (len(folders), str(folders)))
logger.info('Found %i folders to process' % len(folders))
pass
else:
logger.info('Found no folders to process in: %s' % download_dir)
@@ -525,6 +536,9 @@ def forcePostProcess():
for folder in folders:
albumpath = os.path.join(download_dir, folder)
folder = unicode(folder, headphones.SYS_ENCODING, errors='replace')
logger.info('Processing: %s' % folder)
try:
name, album, year = helpers.extract_data(folder)
@@ -534,7 +548,7 @@ def forcePostProcess():
if name and album and year:
myDB = db.DBConnection()
release = myDB.action('SELECT AlbumID, ArtistName, AlbumTitle from albums WHERE ArtistName=? and AlbumTitle=?', [name, album]).fetchone()
release = myDB.action('SELECT AlbumID, ArtistName, AlbumTitle from albums WHERE ArtistName LIKE ? and AlbumTitle LIKE ?', [name, album]).fetchone()
if release:
logger.info('Found a match in the database: %s - %s. Verifying to make sure it is the correct album' % (release['ArtistName'], release['AlbumTitle']))
verify(release['AlbumID'], albumpath)
@@ -542,11 +556,11 @@ def forcePostProcess():
logger.info('Querying MusicBrainz for the release group id for: %s - %s' % (name, album))
from headphones import mb
try:
rgid = mb.findAlbumID(name, album)
rgid = mb.findAlbumID(helpers.latinToAscii(name), helpers.latinToAscii(album))
except:
logger.error('Can not get release information for this album')
continue
if rgid:
verify(rgid, albumpath)
else:
logger.info('No match found on MusicBrainz for: %s - %s' % (name, album))