Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Brinken
2012-09-02 13:37:40 +02:00
10 changed files with 227 additions and 116 deletions

View File

@@ -618,7 +618,10 @@ m<%inherit file="base.html"/>
</div>
<div id="nmaoptions">
<div class="row">
<label>NotifyMyAndroid API Key</label>
<div class="row checkbox">
<input type="checkbox" name="nma_onsnatch" value="1" ${config['nma_onsnatch']} /><label>Notify on snatch?</label>
</div>
<label>NotifyMyAndroid API Key</label>
<input type="text" name="nma_apikey" value="${config['nma_apikey']}" size="30">
<small>Separate multiple api keys with commas</small>
</div>

View File

@@ -183,6 +183,7 @@ XBMC_NOTIFY = False
NMA_ENABLED = False
NMA_APIKEY = None
NMA_PRIORITY = None
NMA_ONSNATCH = None
SYNOINDEX_ENABLED = False
MIRRORLIST = ["musicbrainz.org","headphones","custom"]
MIRROR = None
@@ -254,7 +255,7 @@ def initialize():
ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, \
ENCODERVBRCBR, ENCODERLOSSLESS, DELETE_LOSSLESS_FILES, PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, MIRRORLIST, \
MIRROR, CUSTOMHOST, CUSTOMPORT, CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, \
XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, \
XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, \
PREFERRED_BITRATE_LOW_BUFFER
if __INITIALIZED__:
@@ -401,6 +402,7 @@ def initialize():
NMA_ENABLED = bool(check_setting_int(CFG, 'NMA', 'nma_enabled', 0))
NMA_APIKEY = check_setting_str(CFG, 'NMA', 'nma_apikey', '')
NMA_PRIORITY = check_setting_int(CFG, 'NMA', 'nma_priority', 0)
NMA_ONSNATCH = bool(check_setting_int(CFG, 'NMA', 'nma_onsnatch', 0))
SYNOINDEX_ENABLED = bool(check_setting_int(CFG, 'Synoindex', 'synoindex_enabled', 0))
@@ -676,6 +678,7 @@ def config_write():
new_config['NMA']['nma_enabled'] = int(NMA_ENABLED)
new_config['NMA']['nma_apikey'] = NMA_APIKEY
new_config['NMA']['nma_priority'] = NMA_PRIORITY
new_config['NMA']['nma_onsnatch'] = int(PROWL_ONSNATCH)
new_config['Synoindex'] = {}
new_config['Synoindex']['synoindex_enabled'] = int(SYNOINDEX_ENABLED)

View File

@@ -41,7 +41,7 @@ def artistlist_to_mbids(artistlist, forced=False):
for artist in artistlist:
if not artist:
if not artist and not (artist == ' '):
continue
results = mb.findArtist(artist, limit=1)
@@ -103,6 +103,9 @@ def addArtisttoDB(artistid, extrasonly=False):
logger.warn('Cannot import Various Artists.')
return
# We'll use this to see if we should update the 'LastUpdated' time stamp
errors = False
myDB = db.DBConnection()
# Delete from blacklist if it's on there
@@ -171,6 +174,7 @@ def addArtisttoDB(artistid, extrasonly=False):
continue
if not releaselist:
errors = True
continue
# This will be used later to build a hybrid release
@@ -186,10 +190,12 @@ def addArtisttoDB(artistid, extrasonly=False):
try:
releasedict = mb.getRelease(releaseid, include_artist_info=False)
except Exception, e:
errors = True
logger.info('Unable to get release information for %s: %s' % (release['id'], e))
continue
if not releasedict:
errors = True
continue
controlValueDict = {"ReleaseID": release['id']}
@@ -342,17 +348,19 @@ def addArtisttoDB(artistid, extrasonly=False):
if headphones.AUTOWANT_ALL:
newValueDict['Status'] = "Wanted"
#start a search for the album
import searcher
searcher.searchforalbum(albumid=rg['id'])
elif album['ReleaseDate'] > helpers.today() and headphones.AUTOWANT_UPCOMING:
newValueDict['Status'] = "Wanted"
else:
newValueDict['Status'] = "Skipped"
myDB.upsert("albums", newValueDict, controlValueDict)
#start a search for the album if it's new and autowant_all is selected:
# Should this run in a background thread? Don't know if we want to have a bunch of
# simultaneous threads running
if not rg_exists and headphones.AUTOWANT_ALL:
from headphones import searcher
searcher.searchforalbum(albumid=rg['id'])
myDB.action('DELETE from tracks WHERE AlbumID=?', [rg['id']])
tracks = myDB.action('SELECT * from alltracks WHERE ReleaseID=?', [releaseid]).fetchall()
@@ -412,14 +420,18 @@ def addArtisttoDB(artistid, extrasonly=False):
"TotalTracks": totaltracks,
"HaveTracks": havetracks}
newValueDict['LastUpdated'] = helpers.now()
if not errors:
newValueDict['LastUpdated'] = helpers.now()
myDB.upsert("artists", newValueDict, controlValueDict)
logger.info(u"Seeing if we need album art for: " + artist['artist_name'])
cache.getThumb(ArtistID=artistid)
logger.info(u"Updating complete for: " + artist['artist_name'])
if errors:
logger.info("Finished updating artist: " + artist['artist_name'] + " but with errors, so not marking it as updated in the database")
else:
logger.info(u"Updating complete for: " + artist['artist_name'])
def addReleaseById(rid):

View File

@@ -33,7 +33,7 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None):
dir = dir.encode(headphones.SYS_ENCODING)
if not os.path.isdir(dir):
logger.warn('Cannot find directory: %s. Not scanning' % dir.decode(headphones.SYS_ENCODING))
logger.warn('Cannot find directory: %s. Not scanning' % dir.decode(headphones.SYS_ENCODING, 'replace'))
return
myDB = db.DBConnection()
@@ -48,7 +48,7 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None):
myDB.action('DELETE from have')
logger.info('Scanning music directory: %s' % dir)
logger.info('Scanning music directory: %s' % dir.decode(headphones.SYS_ENCODING, 'replace'))
new_artists = []
bitrates = []
@@ -105,7 +105,7 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None):
# Now we start track matching
total_number_of_songs = len(song_list)
logger.info("Found " + str(total_number_of_songs) + " tracks in: '" + dir + "'. Matching tracks to the appropriate releases....")
logger.info("Found " + str(total_number_of_songs) + " tracks in: '" + dir.decode(headphones.SYS_ENCODING, 'replace') + "'. Matching tracks to the appropriate releases....")
# Sort the song_list by most vague (e.g. no trackid or releaseid) to most specific (both trackid & releaseid)
# When we insert into the database, the tracks with the most specific information will overwrite the more general matches
@@ -299,7 +299,7 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None):
myDB.action('INSERT INTO have (ArtistName, AlbumTitle, TrackNumber, TrackTitle, TrackLength, BitRate, Genre, Date, TrackID, Location, CleanName, Format) VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [song['ArtistName'], song['AlbumTitle'], song['TrackNumber'], song['TrackTitle'], song['TrackLength'], song['BitRate'], song['Genre'], song['Date'], song['TrackID'], song['Location'], CleanName, song['Format']])
logger.info('Completed matching tracks from directory: %s' % dir)
logger.info('Completed matching tracks from directory: %s' % dir.decode(headphones.SYS_ENCODING, 'replace'))
if not append:

View File

@@ -49,41 +49,41 @@ def encode(albumPath):
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)
musicTemp = os.path.normpath(os.path.splitext(music)[0]+'.'+headphones.ENCODEROUTPUTFORMAT.encode(headphones.SYS_ENCODING))
musicTempFiles.append(os.path.join(tempDirEncode, musicTemp))
else:
logger.debug('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)
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')
encoder=os.path.join(headphones.ENCODERFOLDER.encode(headphones.SYS_ENCODING),'lame')
elif headphones.ENCODER=='ffmpeg':
encoder=os.path.join(headphones.ENCODERFOLDER,'ffmpeg')
encoder=os.path.join(headphones.ENCODERFOLDER.encode(headphones.SYS_ENCODING),'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))
logger.warn(u'Lame cant encode "%s" format for "%s", use ffmpeg' % (os.path.splitext(music)[1].decode(headphones.SYS_ENCODING, 'replace'),music.decode(headphones.SYS_ENCODING, 'replace')))
else:
if (music.lower().endswith('.mp3') and (infoMusic.bitrate/1000<=headphones.BITRATE)):
logger.info('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music,headphones.BITRATE))
logger.info('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music.decode(headphones.SYS_ENCODING, 'replace'),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))
logger.warn('Can not reencode .ogg music "%s"' % (music.decode(headphones.SYS_ENCODING, 'replace')))
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.info('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music,headphones.BITRATE))
logger.info('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music.decode(headphones.SYS_ENCODING, 'replace'),headphones.BITRATE))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
@@ -97,7 +97,7 @@ def encode(albumPath):
musicFinalFiles.append(os.path.join(r, music))
if ifencoded==0:
logger.info('Encoding for folder "%s" is not needed' % (albumPath))
logger.info('Encoding for folder "%s" is not needed' % (albumPath.decode(headphones.SYS_ENCODING, 'replace')))
return musicFinalFiles

View File

@@ -171,14 +171,17 @@ class NMA:
return response
def notify(self, artist, album):
def notify(self, artist=None, album=None, snatched_nzb=None):
apikey = self.apikey
priority = self.priority
event = artist + ' - ' + album + ' complete!'
description = "Headphones has downloaded and postprocessed: " + artist + ' [' + album + ']'
if snatched_nzb:
event = snatched_nzb + " snatched!"
description = "Headphones has snatched: " + snatched_nzb + " and has sent it to SABnzbd+"
else:
event = artist + ' - ' + album + ' complete!'
description = "Headphones has downloaded and postprocessed: " + artist + ' [' + album + ']'
data = { 'apikey': apikey, 'application':'Headphones', 'event': event, 'description': description, 'priority': priority}
@@ -223,4 +226,4 @@ class Synoindex:
def notify_multiple(self, path_list):
if isinstance(path_list, list):
for path in path_list:
self.notify(path)
self.notify(path)

View File

@@ -160,7 +160,7 @@ def verify(albumid, albumpath):
try:
f = MediaFile(downloaded_track)
except Exception, e:
logger.info("Exception from MediaFile for: " + downloaded_track + " : " + str(e))
logger.info(u"Exception from MediaFile for: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace') + u" : " + unicode(e))
continue
metaartist = helpers.latinToAscii(f.artist.lower()).encode('UTF-8')
@@ -222,13 +222,13 @@ def verify(albumid, albumpath):
doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list)
return
logger.warn('Could not identify album: %s. It may not be the intended album.' % albumpath)
logger.warn(u'Could not identify album: %s. It may not be the intended album.' % albumpath.decode(headphones.SYS_ENCODING, 'replace'))
myDB.action('UPDATE snatched SET status = "Unprocessed" WHERE AlbumID=?', [albumid])
processed = re.search(r' \(Unprocessed\)(?:\[\d+\])?', albumpath)
if not processed:
renameUnprocessedFolder(albumpath)
else:
logger.info("Already marked as unprocessed: " + albumpath)
logger.info(u"Already marked as unprocessed: " + albumpath.decode(headphones.SYS_ENCODING, 'replace'))
def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list):
@@ -266,12 +266,13 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list)
if headphones.RENAME_FILES:
renameFiles(albumpath, downloaded_track_list, release)
if headphones.MOVE_FILES and headphones.DESTINATION_DIR:
albumpaths = moveFiles(albumpath, release, tracks)
if headphones.MOVE_FILES and not headphones.DESTINATION_DIR:
logger.error('No DESTINATION_DIR has been set. Set "Destination Directory" to the parent directory you want to move the files to')
pass
albumpaths = [albumpath]
elif headphones.MOVE_FILES and headphones.DESTINATION_DIR:
albumpaths = moveFiles(albumpath, release, tracks)
else:
albumpaths = [albumpath]
myDB = db.DBConnection()
myDB.action('UPDATE albums SET status = "Downloaded" WHERE AlbumID=?', [albumid])
@@ -281,9 +282,9 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list)
for albumpath in albumpaths:
librarysync.libraryScan(dir=albumpath, append=True, ArtistID=release['ArtistID'], ArtistName=release['ArtistName'])
logger.info('Post-processing for %s - %s complete' % (release['ArtistName'], release['AlbumTitle']))
logger.info(u'Post-processing for %s - %s complete' % (release['ArtistName'], release['AlbumTitle']))
if headphones.PROWL_ONSNATCH:
if headphones.PROWL_ENABLED:
pushmessage = release['ArtistName'] + ' - ' + release['AlbumTitle']
logger.info(u"Prowl request")
prowl = notifiers.PROWL()
@@ -312,7 +313,7 @@ def embedAlbumArt(artwork, downloaded_track_list):
try:
f = MediaFile(downloaded_track)
except:
logger.error('Could not read %s. Not adding album art' % downloaded_track)
logger.error(u'Could not read %s. Not adding album art' % downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
continue
logger.debug('Adding album art to: %s' % downloaded_track)
@@ -336,7 +337,7 @@ def cleanupFiles(albumpath):
try:
os.remove(os.path.join(r, files))
except Exception, e:
logger.error('Could not remove file: %s. Error: %s' % (files, e))
logger.error(u'Could not remove file: %s. Error: %s' % (files.decode(headphones.SYS_ENCODING, 'replace'), e))
def moveFiles(albumpath, release, tracks):
@@ -486,9 +487,9 @@ def moveFiles(albumpath, release, tracks):
try:
os.remove(file_to_move)
except Exception, e:
logger.error("Error deleting file '" + file_to_move.decode(headphones.SYS_ENCODING) + "' from source directory")
logger.error("Error deleting file '" + file_to_move.decode(headphones.SYS_ENCODING, 'replace') + "' from source directory")
else:
logger.error("Error copying '" + file_to_move.decode(headphones.SYS_ENCODING) + "'. Not deleting from download directory")
logger.error("Error copying '" + file_to_move.decode(headphones.SYS_ENCODING, 'replace') + "'. Not deleting from download directory")
elif make_lossless_folder and not make_lossy_folder:
@@ -519,13 +520,13 @@ def moveFiles(albumpath, release, tracks):
try:
os.chmod(os.path.normpath(temp_f).encode(headphones.SYS_ENCODING), int(headphones.FOLDER_PERMISSIONS, 8))
except Exception, e:
logger.error("Error trying to change permissions on folder: %s" % temp_f)
logger.error("Error trying to change permissions on folder: %s" % temp_f.decode(headphones.SYS_ENCODING, 'replace'))
# If we failed to move all the files out of the directory, this will fail too
try:
shutil.rmtree(albumpath)
except Exception, e:
logger.error('Could not remove directory: %s. %s' % (albumpath, e))
logger.error('Could not remove directory: %s. %s' % (albumpath.decode(headphones.SYS_ENCODING, 'replace'), e))
destination_paths = []
@@ -552,10 +553,10 @@ def correctMetadata(albumid, release, downloaded_track_list):
elif any(downloaded_track.lower().endswith('.' + x.lower()) for x in headphones.LOSSY_MEDIA_FORMATS):
lossy_items.append(beets.library.Item.from_path(downloaded_track))
else:
logger.warn("Skipping: " + downloaded_track.decode(headphones.SYS_ENCODING) + " because it is not a mutagen friendly file format")
logger.warn("Skipping: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace') + " because it is not a mutagen friendly file format")
except Exception, e:
logger.error("Beets couldn't create an Item from: " + downloaded_track.decode(headphones.SYS_ENCODING) + " - not a media file?" + str(e))
logger.error("Beets couldn't create an Item from: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace') + " - not a media file?" + str(e))
for items in [lossy_items, lossless_items]:
@@ -586,9 +587,9 @@ def correctMetadata(albumid, release, downloaded_track_list):
for item in items:
try:
item.write()
logger.info("Successfully applied metadata to: " + item.path.decode(headphones.SYS_ENCODING))
logger.info("Successfully applied metadata to: " + item.path.decode(headphones.SYS_ENCODING, 'replace'))
except Exception, e:
logger.warn("Error writing metadata to " + item.path.decode(headphones.SYS_ENCODING) + ": " + str(e))
logger.warn("Error writing metadata to " + item.path.decode(headphones.SYS_ENCODING, 'replace') + ": " + str(e))
def embedLyrics(downloaded_track_list):
logger.info('Adding lyrics')
@@ -600,14 +601,14 @@ def embedLyrics(downloaded_track_list):
try:
f = MediaFile(downloaded_track)
except:
logger.error('Could not read %s. Not checking lyrics' % downloaded_track)
logger.error('Could not read %s. Not checking lyrics' % downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
if f.albumartist and f.title:
metalyrics = lyrics.getLyrics(f.albumartist, f.title)
elif f.artist and f.title:
metalyrics = lyrics.getLyrics(f.artist, f.title)
else:
logger.info('No artist/track metadata found for track: %s. Not fetching lyrics' % downloaded_track)
logger.info('No artist/track metadata found for track: %s. Not fetching lyrics' % downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
metalyrics = None
if lyrics:
@@ -627,7 +628,7 @@ def renameFiles(albumpath, downloaded_track_list, release):
try:
f = MediaFile(downloaded_track)
except:
logger.info("MediaFile couldn't parse: " + downloaded_track.decode(headphones.SYS_ENCODING))
logger.info("MediaFile couldn't parse: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
continue
if not f.track:
@@ -637,7 +638,7 @@ def renameFiles(albumpath, downloaded_track_list, release):
if not f.title:
basename = unicode(os.path.basename(downloaded_track), headphones.SYS_ENCODING, errors='replace')
basename = os.path.basename(downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
title = os.path.splitext(basename)[0]
ext = os.path.splitext(basename)[1]
@@ -678,7 +679,7 @@ def renameFiles(albumpath, downloaded_track_list, release):
try:
os.rename(downloaded_track, new_file)
except Exception, e:
logger.error('Error renaming file: %s. Error: %s' % (downloaded_track.decode(headphones.SYS_ENCODING), e))
logger.error('Error renaming file: %s. Error: %s' % (downloaded_track.decode(headphones.SYS_ENCODING, 'replace'), e))
continue
def renameUnprocessedFolder(albumpath):
@@ -698,66 +699,55 @@ def renameUnprocessedFolder(albumpath):
return
def forcePostProcess():
if not headphones.DOWNLOAD_DIR:
logger.error('No DOWNLOAD_DIR has been set. Set "Music Download Directory:" to your SAB download directory on the settings page.')
return
download_dirs = []
if headphones.DOWNLOAD_DIR:
download_dirs.append(headphones.DOWNLOAD_DIR.encode(headphones.SYS_ENCODING))
if headphones.DOWNLOAD_TORRENT_DIR:
download_dirs.append(headphones.DOWNLOAD_TORRENT_DIR.encode(headphones.SYS_ENCODING))
logger.info('Checking to see if there are any folders to process in download_dir(s): %s' % str(download_dirs).decode(headphones.SYS_ENCODING, 'replace'))
# Get a list of folders in the download_dir
folders = []
for download_dir in download_dirs:
for folder in os.listdir(download_dir):
path_to_folder = os.path.join(download_dir, folder)
if os.path.isdir(path_to_folder):
folders.append(path_to_folder)
if len(folders):
logger.info('Found %i folders to process' % len(folders))
else:
processing = "nzb"
processing_next = "torrent"
while processing != "done":
if headphones.DOWNLOAD_DIR and processing == "nzb":
download_dir = headphones.DOWNLOAD_DIR.encode('utf-8')
if not headphones.DOWNLOAD_TORRENT_DIR:
processing_next = "done"
if headphones.DOWNLOAD_TORRENT_DIR and processing == "torrent":
download_dir = headphones.DOWNLOAD_TORRENT_DIR.encode('utf-8')
processing_next = "done"
if not headphones.DOWNLOAD_DIR and processing == "nzb":
download_dir = headphones.DOWNLOAD_TORRENT_DIR.encode('utf-8')
processing_next = "done"
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))]
logger.info('Found no folders to process in: %s' % str(download_dirs).decode(headphones.SYS_ENCODING, 'replace'))
# Parse the folder names to get artist album info
for folder in folders:
folder_basename = os.path.basename(folder).decode(headphones.SYS_ENCODING, 'replace')
logger.info('Processing: %s' % folder_basename)
if len(folders):
logger.info('Found %i folders to process' % len(folders))
pass
try:
name, album, year = helpers.extract_data(folder_basename)
except:
logger.info("Couldn't parse " + folder_basename + " into any valid format.")
continue
if name and album and year:
myDB = db.DBConnection()
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'], folder)
else:
logger.info('Found no folders to process in: %s' % download_dir)
return
# Parse the folder names to get artist album info
for folder in folders:
albumpath = os.path.join(download_dir, folder)
folder = unicode(folder, headphones.SYS_ENCODING, errors='replace')
logger.info('Processing: %s' % folder)
logger.info('Querying MusicBrainz for the release group id for: %s - %s' % (name, album))
from headphones import mb
try:
name, album, year = helpers.extract_data(folder)
rgid = mb.findAlbumID(helpers.latinToAscii(name), helpers.latinToAscii(album))
except:
logger.info("Couldn't parse " + folder + " into any valid format.")
logger.error('Can not get release information for this album')
continue
if name and album and year:
myDB = db.DBConnection()
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)
else:
logger.info('Querying MusicBrainz for the release group id for: %s - %s' % (name, album))
from headphones import mb
try:
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))
processing = processing_next
if rgid:
verify(rgid, folder)
else:
logger.info('No match found on MusicBrainz for: %s - %s' % (name, album))

View File

@@ -27,7 +27,7 @@ import urllib2, cookielib
from headphones.common import USER_AGENT
from headphones import logger
from headphones import notifiers
from headphones import notifiers, helpers
def sendNZB(nzb):
@@ -64,8 +64,10 @@ def sendNZB(nzb):
# if we get a raw data result we want to upload it to SAB
elif nzb.resultType == "nzbdata":
# Sanitize the file a bit, since we can only use ascii chars with MultiPartPostHandler
nzbdata = helpers.latinToAscii(nzb.extraInfo[0])
params['mode'] = 'addfile'
multiPartParams = {"nzbfile": (nzb.name+".nzb", nzb.extraInfo[0])}
multiPartParams = {"nzbfile": (nzb.name+".nzb", nzbdata)}
if not headphones.SAB_HOST.startswith('http'):
headphones.SAB_HOST = 'http://' + headphones.SAB_HOST
@@ -78,7 +80,7 @@ def sendNZB(nzb):
try:
if nzb.resultType == "nzb":
f = urllib.urlopen(url)
f = urllib.urlopen(url)
elif nzb.resultType == "nzbdata":
cookies = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies),
@@ -97,7 +99,11 @@ def sendNZB(nzb):
except httplib.InvalidURL, e:
logger.error(u"Invalid SAB host, check your config. Current host: %s" % headphones.SAB_HOST)
return False
except Exception, e:
logger.error(u"Error: " + str(e))
return False
if f == None:
logger.info(u"No data returned from SABnzbd, NZB not sent")
return False
@@ -118,10 +124,14 @@ def sendNZB(nzb):
if sabText == "ok":
logger.info(u"NZB sent to SAB successfully")
if headphones.PROWL_ONSNATCH:
logger.info(u"Prowl request")
if headphones.PROWL_ENABLED and headphones.PROWL_ONSNATCH:
logger.info(u"Sending Prowl notification")
prowl = notifiers.PROWL()
prowl.notify(nzb.name,"Download started")
if headphones.NMA_ENABLED and headphones.NMA_ONSNATCH:
logger.debug(u"Sending NMA notification")
nma = notifiers.NMA()
nma.notify(snatched_nzb=nzb.name)
return True
elif sabText == "Missing authentication":

View File

@@ -511,6 +511,7 @@ class WebInterface(object):
"nma_enabled": checked(headphones.NMA_ENABLED),
"nma_apikey": headphones.NMA_APIKEY,
"nma_priority": int(headphones.NMA_PRIORITY),
"nma_onsnatch": checked(headphones.NMA_ONSNATCH),
"synoindex_enabled": checked(headphones.SYNOINDEX_ENABLED),
"mirror_list": headphones.MIRRORLIST,
"mirror": headphones.MIRROR,
@@ -550,7 +551,7 @@ class WebInterface(object):
interface=None, log_dir=None, music_encoder=0, encoder=None, bitrate=None, samplingfrequency=None, encoderfolder=None, advancedencoder=None,
encoderoutputformat=None, encodervbrcbr=None, encoderquality=None, encoderlossless=0, delete_lossless_files=0, prowl_enabled=0, prowl_onsnatch=0,
prowl_keys=None, prowl_priority=0, xbmc_enabled=0, xbmc_host=None, xbmc_username=None, xbmc_password=None, xbmc_update=0, xbmc_notify=0, nma_enabled=False,
nma_apikey=None, nma_priority=0, synoindex_enabled=False, mirror=None, customhost=None, customport=None, customsleep=None, hpuser=None, hppass=None,
nma_apikey=None, nma_priority=0, nma_onsnatch=0, synoindex_enabled=False, mirror=None, customhost=None, customport=None, customsleep=None, hpuser=None, hppass=None,
preferred_bitrate_high_buffer=None, preferred_bitrate_low_buffer=None, **kwargs):
headphones.HTTP_HOST = http_host
@@ -639,6 +640,7 @@ class WebInterface(object):
headphones.NMA_ENABLED = nma_enabled
headphones.NMA_APIKEY = nma_apikey
headphones.NMA_PRIORITY = nma_priority
headphones.NMA_ONSNATCH = nma_onsnatch
headphones.SYNOINDEX_ENABLED = synoindex_enabled
headphones.MIRROR = mirror
headphones.CUSTOMHOST = customhost

88
init-alt.freebsd Normal file
View File

@@ -0,0 +1,88 @@
#!/bin/sh
#
# PROVIDE: headphones
# REQUIRE: sabnzbd
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# headphones_enable (bool): Set to NO by default.
# Set it to YES to enable it.
# headphones_user: The user account Headphones daemon runs as what
# you want it to be. It uses '_sabnzbd' user by
# default. Do not sets it as empty or it will run
# as root.
# headphones_dir: Directory where Headphones lives.
# Default: /usr/local/headphones
# headphones_chdir: Change to this directory before running Headphones.
# Default is same as headphones_dir.
# headphones_pid: The name of the pidfile to create.
# Default is headphones.pid in headphones_dir.
. /etc/rc.subr
name="headphones"
rcvar=${name}_enable
load_rc_config ${name}
: ${headphones_enable:="NO"}
: ${headphones_user:="_sabnzbd"}
: ${headphones_dir:="/usr/local/headphones"}
: ${headphones_chdir:="${headphones_dir}"}
: ${headphones_pid:="${headphones_dir}/headphones.pid"}
: ${headphones_conf:="${headphones_dir}/config.ini"}
WGET="/usr/local/bin/wget" # You need wget for this script to safely shutdown Headphones.
if [ -e "${headphones_conf}" ]; then
HOST=`grep -A64 "\[General\]" "${headphones_conf}"|egrep "^http_host"|perl -wple 's/^http_host = (.*)$/$1/'`
PORT=`grep -A64 "\[General\]" "${headphones_conf}"|egrep "^http_port"|perl -wple 's/^http_port = (.*)$/$1/'`
fi
status_cmd="${name}_status"
stop_cmd="${name}_stop"
command="${headphones_dir}/Headphones.py"
command_args="--daemon --quiet --nolaunch --port ${PORT} --pidfile ${headphones_pid} --config ${headphones_conf}"
# Check for wget and refuse to start without it.
if [ ! -x "${WGET}" ]; then
warn "Headphones not started: You need wget to safely shut down Headphones."
exit 1
fi
# Ensure user is root when running this script.
if [ `id -u` != "0" ]; then
echo "Oops, you should be root before running this!"
exit 1
fi
verify_headphones_pid() {
# Make sure the pid corresponds to the Headphones process.
pid=`cat ${headphones_pid} 2>/dev/null`
ps -p ${pid} | grep -q "python ${headphones_dir}/Headphones.py"
return $?
}
# Try to stop Headphones cleanly by calling shutdown over http.
headphones_stop() {
if [ ! -e "${headphones_conf}" ]; then
echo "Headphones' settings file does not exist. Try starting Headphones, as this should create the file."
exit 1
fi
echo "Stopping $name"
verify_headphones_pid
${WGET} -O - -q --user=${SBUSR} --password=${SBPWD} "http://${HOST}:${PORT}/shutdown/" >/dev/null
if [ -n "${pid}" ]; then
wait_for_pids ${pid}
echo "Stopped $name"
fi
}
headphones_status() {
verify_headphones_pid && echo "$name is running as ${pid}" || echo "$name is not running"
}
run_rc_command "$1"