mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-22 03:17:45 +01:00
New feature: Preferred Quality. Specify a target bit rate or let the Music Scanner detect it for you
This commit is contained in:
@@ -86,6 +86,10 @@ h1{
|
||||
.smalltext{
|
||||
font-size: 11px;
|
||||
}
|
||||
.smalltext2{
|
||||
font-size: 11px;
|
||||
margin-left: 45px;
|
||||
}
|
||||
.mediumtext{
|
||||
font-size: 16px;
|
||||
margin-left: 100px;
|
||||
|
||||
+14
-10
@@ -55,7 +55,9 @@ MUSIC_DIR = None
|
||||
FOLDER_FORMAT = None
|
||||
FILE_FORMAT = None
|
||||
PATH_TO_XML = None
|
||||
PREFER_LOSSLESS = False
|
||||
PREFERRED_QUALITY = None
|
||||
PREFERRED_BITRATE = None
|
||||
DETECT_BITRATE = False
|
||||
FLAC_TO_MP3 = False
|
||||
MOVE_FILES = False
|
||||
RENAME_FILES = False
|
||||
@@ -139,13 +141,11 @@ def initialize():
|
||||
|
||||
global __INITIALIZED__, FULL_PATH, PROG_DIR, QUIET, DAEMON, DATA_DIR, CONFIG_FILE, CFG, LOG_DIR, CACHE_DIR, \
|
||||
HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, LAUNCH_BROWSER, GIT_PATH, \
|
||||
CURRENT_VERSION, LATEST_VERSION,\
|
||||
MUSIC_DIR, PREFER_LOSSLESS, FLAC_TO_MP3, MOVE_FILES, RENAME_FILES, FOLDER_FORMAT, \
|
||||
FILE_FORMAT, CLEANUP_FILES, ADD_ALBUM_ART, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, \
|
||||
NZB_SEARCH_INTERVAL, LIBRARYSCAN_INTERVAL, \
|
||||
SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \
|
||||
NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, \
|
||||
NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, \
|
||||
CURRENT_VERSION, LATEST_VERSION, MUSIC_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, \
|
||||
FLAC_TO_MP3, MOVE_FILES, RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, CLEANUP_FILES, \
|
||||
ADD_ALBUM_ART, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, NZB_SEARCH_INTERVAL, \
|
||||
LIBRARYSCAN_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
|
||||
|
||||
if __INITIALIZED__:
|
||||
@@ -175,7 +175,9 @@ def initialize():
|
||||
GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '')
|
||||
|
||||
MUSIC_DIR = check_setting_str(CFG, 'General', 'music_dir', '')
|
||||
PREFER_LOSSLESS = bool(check_setting_int(CFG, 'General', 'prefer_lossless', 0))
|
||||
PREFERRED_QUALITY = check_setting_int(CFG, 'General', 'preferred_quality', 0)
|
||||
PREFERRED_BITRATE = check_setting_int(CFG, 'General', 'preferred_bitrate', '')
|
||||
DETECT_BITRATE = bool(check_setting_int(CFG, 'General', 'detect_bitrate', 0))
|
||||
FLAC_TO_MP3 = bool(check_setting_int(CFG, 'General', 'flac_to_mp3', 0))
|
||||
MOVE_FILES = bool(check_setting_int(CFG, 'General', 'move_files', 0))
|
||||
RENAME_FILES = bool(check_setting_int(CFG, 'General', 'rename_files', 0))
|
||||
@@ -319,7 +321,9 @@ def config_write():
|
||||
new_config['General']['git_path'] = GIT_PATH
|
||||
|
||||
new_config['General']['music_dir'] = MUSIC_DIR
|
||||
new_config['General']['prefer_lossless'] = int(PREFER_LOSSLESS)
|
||||
new_config['General']['preferred_quality'] = PREFERRED_QUALITY
|
||||
new_config['General']['preferred_bitrate'] = PREFERRED_BITRATE
|
||||
new_config['General']['detect_bitrate'] = int(DETECT_BITRATE)
|
||||
new_config['General']['flac_to_mp3'] = int(FLAC_TO_MP3)
|
||||
new_config['General']['move_files'] = int(MOVE_FILES)
|
||||
new_config['General']['rename_files'] = int(RENAME_FILES)
|
||||
|
||||
+53
-1
@@ -2,6 +2,10 @@ import time
|
||||
from operator import itemgetter
|
||||
import datetime
|
||||
|
||||
import headphones
|
||||
|
||||
from headphones import db, logger
|
||||
|
||||
def multikeysort(items, columns):
|
||||
|
||||
comparers = [ ((itemgetter(col[1:].strip()), -1) if col.startswith('-') else (itemgetter(col.strip()), 1)) for col in columns]
|
||||
@@ -22,6 +26,13 @@ def checked(variable):
|
||||
else:
|
||||
return ''
|
||||
|
||||
def radio(variable, pos):
|
||||
|
||||
if variable == pos:
|
||||
return 'Checked'
|
||||
else:
|
||||
return ''
|
||||
|
||||
def latinToAscii(unicrap):
|
||||
"""
|
||||
From couch potato
|
||||
@@ -75,4 +86,45 @@ def convert_milliseconds(ms):
|
||||
def today():
|
||||
today = datetime.date.today()
|
||||
yyyymmdd = datetime.date.isoformat(today)
|
||||
return yyyymmdd
|
||||
return yyyymmdd
|
||||
|
||||
def bytes_to_mb(bytes):
|
||||
|
||||
mb = bytes/1048576
|
||||
size = '%.1f MB' % mb
|
||||
return size
|
||||
|
||||
def sortNZBList(resultlist, albumid):
|
||||
"""
|
||||
Takes a list of NZBresults from searcher.py and sorts them by distance to
|
||||
a target size based on bitrate * album duration
|
||||
"""
|
||||
|
||||
bitrate = headphones.PREFERRED_BITRATE
|
||||
|
||||
myDB = db.DBConnection()
|
||||
tracks = myDB.select('SELECT TrackDuration from tracks WHERE AlbumID=?', [albumid])
|
||||
|
||||
# album length in milliseconds
|
||||
albumlength = sum([pair[0] for pair in tracks])
|
||||
|
||||
# target size, in bytes
|
||||
targetsize = albumlength/1000 * bitrate * 128
|
||||
|
||||
logger.info('Target size: %s' % bytes_to_mb(targetsize))
|
||||
|
||||
newlist = []
|
||||
# resultlist = [(title, size, url), (title2, size2, url2)...]
|
||||
|
||||
for result in resultlist:
|
||||
|
||||
delta = abs(targetsize - result[1])
|
||||
newlist.append((result[0], result[1], result[2], delta))
|
||||
|
||||
bestqual = sorted(newlist, key=lambda title: title[3])[0]
|
||||
|
||||
return bestqual
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ def scanMusic(dir=None):
|
||||
if results:
|
||||
|
||||
lst = []
|
||||
bitrates = []
|
||||
|
||||
myDB = db.DBConnection()
|
||||
myDB.action('''DELETE from have''')
|
||||
@@ -49,6 +50,11 @@ def scanMusic(dir=None):
|
||||
|
||||
myDB.action('INSERT INTO have VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?)', [artist, f.album, f.track, f.title, f.length, f.bitrate, f.genre, f.date, f.mb_trackid])
|
||||
lst.append(artist)
|
||||
bitrates.append(f.bitrate)
|
||||
|
||||
# Get the average bitrate if the option is selected
|
||||
if headphones.DETECT_BITRATE:
|
||||
headphones.PREFERRED_BITRATE = sum(bitrates)/len(bitrates)/1000
|
||||
|
||||
artistlist = {}.fromkeys(lst).keys()
|
||||
logger.info(u"Preparing to import %i artists" % len(artistlist))
|
||||
|
||||
+16
-9
@@ -17,6 +17,7 @@ def searchNZB(albumid=None):
|
||||
|
||||
for albums in results:
|
||||
|
||||
albumid = albums[2]
|
||||
reldate = albums[3]
|
||||
year = reldate[:4]
|
||||
clname = string.replace(helpers.latinToAscii(albums[0]), ' & ', ' ')
|
||||
@@ -30,7 +31,7 @@ def searchNZB(albumid=None):
|
||||
|
||||
if headphones.NZBMATRIX:
|
||||
|
||||
if headphones.PREFER_LOSSLESS:
|
||||
if headphones.PREFERRED_QUALITY:
|
||||
categories = "23,22"
|
||||
maxsize = 2000000000
|
||||
else:
|
||||
@@ -60,7 +61,7 @@ def searchNZB(albumid=None):
|
||||
size = int(item.links[1]['length'])
|
||||
if size < maxsize:
|
||||
resultlist.append((title, size, url))
|
||||
logger.info('Found %s. Size: %i' % (title, size))
|
||||
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
|
||||
else:
|
||||
logger.info('%s is larger than the maxsize for this category, skipping. (Size: %i bytes)' % (title, size))
|
||||
|
||||
@@ -69,7 +70,7 @@ def searchNZB(albumid=None):
|
||||
|
||||
if headphones.NEWZNAB:
|
||||
|
||||
if headphones.PREFER_LOSSLESS:
|
||||
if headphones.PREFERRED_QUALITY:
|
||||
categories = "3040,3010"
|
||||
maxsize = 2000000000
|
||||
else:
|
||||
@@ -95,7 +96,7 @@ def searchNZB(albumid=None):
|
||||
size = int(item.links[1]['length'])
|
||||
if size < maxsize:
|
||||
resultlist.append((title, size, url))
|
||||
logger.info('Found %s. Size: %i' % (title, size))
|
||||
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
|
||||
else:
|
||||
logger.info('%s is larger than the maxsize for this category, skipping. (Size: %i bytes)' % (title, size))
|
||||
|
||||
@@ -104,7 +105,7 @@ def searchNZB(albumid=None):
|
||||
|
||||
if headphones.NZBSORG:
|
||||
|
||||
if headphones.PREFER_LOSSLESS:
|
||||
if headphones.PREFERRED_QUALITY:
|
||||
categories = "5,3010"
|
||||
maxsize = 2000000000
|
||||
else:
|
||||
@@ -132,7 +133,7 @@ def searchNZB(albumid=None):
|
||||
size = int(item.links[1]['length'])
|
||||
if size < maxsize:
|
||||
resultlist.append((title, size, url))
|
||||
logger.info('Found %s. Size: %i' % (title, size))
|
||||
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
|
||||
else:
|
||||
logger.info('%s is larger than the maxsize for this category, skipping. (Size: %i bytes)' % (title, size))
|
||||
|
||||
@@ -140,9 +141,15 @@ def searchNZB(albumid=None):
|
||||
logger.info(u"No results found. %s" % e)
|
||||
|
||||
if len(resultlist):
|
||||
bestqual = sorted(resultlist, key=lambda title: title[1], reverse=True)[0]
|
||||
|
||||
logger.info(u"Found best result: %s (%s) - %s bytes" % (bestqual[0], bestqual[2], bestqual[1]))
|
||||
|
||||
if headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE:
|
||||
|
||||
bestqual = helpers.sortNZBList(resultlist, albumid)
|
||||
|
||||
else:
|
||||
bestqual = sorted(resultlist, key=lambda title: title[1], reverse=True)[0]
|
||||
|
||||
logger.info(u"Found best result: %s (%s) - %s" % (bestqual[0], bestqual[2], helpers.bytes_to_mb(bestqual[1])))
|
||||
downloadurl = bestqual[2]
|
||||
|
||||
if headphones.SAB_HOST and not headphones.BLACKHOLE:
|
||||
|
||||
+16
-23
@@ -261,16 +261,24 @@ configform = form = '''
|
||||
<table class="configtable" summary="Quality & Post Processing">
|
||||
<tr>
|
||||
<td>
|
||||
<p><b>Album Quality:</b></p>
|
||||
<input type="checkbox" name="prefer_lossless" value="1" %s />Prefer lossless <br>
|
||||
<input type="checkbox" name="flac_to_mp3" value="1" %s />Convert lossless to mp3
|
||||
<b>Album Quality:</b>
|
||||
<p>
|
||||
<input type="radio" name="preferred_quality" value="0" %s />Highest Quality<br /><br />
|
||||
<input type="radio" name="preferred_quality" value="1" %s />Highest Quality including Lossless<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>
|
||||
<p>
|
||||
<p><b>iTunes:</b></p>
|
||||
<input type="checkbox" name="move_files" value="1" %s />Move downloads to Music Folder
|
||||
</p>
|
||||
<b>Post-Processing:</b>
|
||||
<p>
|
||||
<input type="checkbox" name="move_files" value="1" %s />Move downloads to Music Folder<br />
|
||||
<input type="checkbox" name="flac_to_mp3" value="1" %s />Convert lossless to mp3<br>
|
||||
<input type="checkbox" name="rename_files" value="1" %s />Rename & add metadata<br>
|
||||
<input type="checkbox" name="cleanup_files" value="1" %s />Delete leftover files<br>
|
||||
<input type="checkbox" name="add_album_art" value="1" %s>Add album art
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -283,23 +291,8 @@ configform = form = '''
|
||||
<i class="smalltext">i.e. /Users/name/Music/iTunes or /Volumes/share/music</i>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<b>Renaming & Metadata:</b>
|
||||
<p>
|
||||
<input type="checkbox" name="rename_files" value="1" %s />Rename & add metadata
|
||||
<br>
|
||||
<input type="checkbox" name="cleanup_files" value="1" %s />Delete leftover files
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<br>
|
||||
<p><b>Album Art:</b></p>
|
||||
<input type="checkbox" name="add_album_art" value="1" %s>Add album art
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="center"><input type="submit" value="Save Changes"><br>
|
||||
|
||||
+13
-7
@@ -13,7 +13,7 @@ import threading
|
||||
import headphones
|
||||
from headphones.mb import getReleaseGroup
|
||||
from headphones import templates, logger, searcher, db, importer, helpers, mb
|
||||
from headphones.helpers import checked
|
||||
from headphones.helpers import checked, radio
|
||||
|
||||
|
||||
class WebInterface(object):
|
||||
@@ -509,13 +509,17 @@ class WebInterface(object):
|
||||
checked(headphones.NZBSORG),
|
||||
headphones.NZBSORG_UID,
|
||||
headphones.NZBSORG_HASH,
|
||||
checked(headphones.PREFER_LOSSLESS),
|
||||
checked(headphones.FLAC_TO_MP3),
|
||||
radio(headphones.PREFERRED_QUALITY, 0),
|
||||
radio(headphones.PREFERRED_QUALITY, 1),
|
||||
radio(headphones.PREFERRED_QUALITY, 2),
|
||||
headphones.PREFERRED_BITRATE,
|
||||
checked(headphones.DETECT_BITRATE),
|
||||
checked(headphones.MOVE_FILES),
|
||||
headphones.MUSIC_DIR,
|
||||
checked(headphones.FLAC_TO_MP3),
|
||||
checked(headphones.RENAME_FILES),
|
||||
checked(headphones.CLEANUP_FILES),
|
||||
checked(headphones.ADD_ALBUM_ART)
|
||||
checked(headphones.ADD_ALBUM_ART),
|
||||
headphones.MUSIC_DIR
|
||||
))
|
||||
page.append(templates._footer % headphones.CURRENT_VERSION)
|
||||
return page
|
||||
@@ -526,7 +530,7 @@ class WebInterface(object):
|
||||
def configUpdate(self, http_host='0.0.0.0', http_username=None, http_port=8181, http_password=None, launch_browser=0,
|
||||
sab_host=None, sab_username=None, sab_apikey=None, sab_password=None, sab_category=None, download_dir=None, blackhole=0, blackhole_dir=None,
|
||||
usenet_retention=None, nzbmatrix=0, nzbmatrix_username=None, nzbmatrix_apikey=None, newznab=0, newznab_host=None, newznab_apikey=None,
|
||||
nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, prefer_lossless=0, flac_to_mp3=0, move_files=0, music_dir=None, rename_files=0, cleanup_files=0, add_album_art=0):
|
||||
nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, preferred_quality=0, preferred_bitrate=None, detect_bitrate=0, flac_to_mp3=0, move_files=0, music_dir=None, rename_files=0, cleanup_files=0, add_album_art=0):
|
||||
|
||||
headphones.HTTP_HOST = http_host
|
||||
headphones.HTTP_PORT = http_port
|
||||
@@ -551,7 +555,9 @@ class WebInterface(object):
|
||||
headphones.NZBSORG = nzbsorg
|
||||
headphones.NZBSORG_UID = nzbsorg_uid
|
||||
headphones.NZBSORG_HASH = nzbsorg_hash
|
||||
headphones.PREFER_LOSSLESS = prefer_lossless
|
||||
headphones.PREFERRED_QUALITY = int(preferred_quality)
|
||||
headphones.PREFERRED_BITRATE = int(preferred_bitrate)
|
||||
headphones.DETECT_BITRATE = detect_bitrate
|
||||
headphones.FLAC_TO_MP3 = flac_to_mp3
|
||||
headphones.MOVE_FILES = move_files
|
||||
headphones.MUSIC_DIR = music_dir
|
||||
|
||||
Reference in New Issue
Block a user