diff --git a/headphones/cache.py b/headphones/cache.py
index cee70ff0..49e9023e 100644
--- a/headphones/cache.py
+++ b/headphones/cache.py
@@ -22,6 +22,7 @@ from headphones import db, helpers, logger, lastfm, request
LASTFM_API_KEY = "690e1ed3bc00bc91804cd8f7fe5ed6d4"
+
class Cache(object):
"""
This class deals with getting, storing and serving up artwork (album
@@ -92,7 +93,6 @@ class Cache(object):
return days_old
-
def _is_current(self, filename=None, date=None):
if filename:
@@ -431,6 +431,7 @@ class Cache(object):
self.thumb_errors = True
self.thumb_url = image_url
+
def getArtwork(ArtistID=None, AlbumID=None):
c = Cache()
@@ -445,6 +446,7 @@ def getArtwork(ArtistID=None, AlbumID=None):
artwork_file = os.path.basename(artwork_path)
return "cache/artwork/" + artwork_file
+
def getThumb(ArtistID=None, AlbumID=None):
c = Cache()
@@ -459,6 +461,7 @@ def getThumb(ArtistID=None, AlbumID=None):
thumbnail_file = os.path.basename(artwork_path)
return "cache/artwork/" + thumbnail_file
+
def getInfo(ArtistID=None, AlbumID=None):
c = Cache()
@@ -467,6 +470,7 @@ def getInfo(ArtistID=None, AlbumID=None):
return info_dict
+
def getImageLinks(ArtistID=None, AlbumID=None):
c = Cache()
diff --git a/headphones/classes.py b/headphones/classes.py
index c6b14055..acb29f86 100644
--- a/headphones/classes.py
+++ b/headphones/classes.py
@@ -24,9 +24,11 @@ import datetime
from common import USER_AGENT
+
class HeadphonesURLopener(urllib.FancyURLopener):
version = USER_AGENT
+
class AuthURLOpener(HeadphonesURLopener):
"""
URLOpener class that supports http auth without needing interactive password entry.
@@ -35,6 +37,7 @@ class AuthURLOpener(HeadphonesURLopener):
user: username to use for HTTP auth
pw: password to use for HTTP auth
"""
+
def __init__(self, user, pw):
self.username = user
self.password = pw
@@ -65,6 +68,7 @@ class AuthURLOpener(HeadphonesURLopener):
self.numTries = 0
return HeadphonesURLopener.open(self, url)
+
class SearchResult:
"""
Represents a search result from an indexer.
@@ -96,24 +100,28 @@ class SearchResult:
myString += " " + extra + "\n"
return myString
+
class NZBSearchResult(SearchResult):
"""
Regular NZB result with an URL to the NZB
"""
resultType = "nzb"
+
class NZBDataSearchResult(SearchResult):
"""
NZB result where the actual NZB XML data is stored in the extraInfo
"""
resultType = "nzbdata"
+
class TorrentSearchResult(SearchResult):
"""
Torrent result with an URL to the torrent
"""
resultType = "torrent"
+
class Proper:
def __init__(self, name, url, date):
self.name = name
diff --git a/headphones/common.py b/headphones/common.py
index cadad088..17dd7f54 100644
--- a/headphones/common.py
+++ b/headphones/common.py
@@ -44,6 +44,7 @@ ARCHIVED = 6 # releases that you don't have locally (counts toward download comp
IGNORED = 7 # releases that you don't want included in your download stats
SNATCHED_PROPER = 9 # qualified with quality
+
class Quality:
NONE = 0
diff --git a/headphones/config.py b/headphones/config.py
index 2023e7a1..0fad26b9 100644
--- a/headphones/config.py
+++ b/headphones/config.py
@@ -4,6 +4,7 @@ import os
import re
from configobj import ConfigObj
+
def bool_int(value):
"""
Casts a config value into a 0 or 1
@@ -230,6 +231,7 @@ _config_definitions = {
'XLDPROFILE': (str, 'General', '')
}
+
class Config(object):
""" Wraps access to particular values in a config file """
diff --git a/headphones/cuesplit.py b/headphones/cuesplit.py
index 8bf5d016..3becab7d 100755
--- a/headphones/cuesplit.py
+++ b/headphones/cuesplit.py
@@ -69,6 +69,7 @@ WAVE_FILE_TYPE_BY_EXTENSION = {
#SHNTOOL_COMPATIBLE = ('Waveform Audio', 'WavPack', 'Free Lossless Audio Codec')
SHNTOOL_COMPATIBLE = ('Free Lossless Audio Codec')
+
def check_splitter(command):
'''Check xld or shntools installed'''
try:
@@ -82,6 +83,7 @@ def check_splitter(command):
return False
return True
+
def split_baby(split_file, split_cmd):
'''Let's split baby'''
logger.info('Splitting %s...', split_file.decode(headphones.SYS_ENCODING, 'replace'))
@@ -115,6 +117,7 @@ def split_baby(split_file, split_cmd):
logger.info('Split success %s', split_file.decode(headphones.SYS_ENCODING, 'replace'))
return True
+
def check_list(list, ignore=0):
'''Checks a list for None elements. If list have None (after ignore index) then it should pass only if all elements
are None threreafter. Returns a tuple without the None entries.'''
@@ -146,12 +149,14 @@ def check_list(list, ignore=0):
return tuple(list1+list2)
+
def trim_cue_entry(string):
'''Removes leading and trailing "s.'''
if string[0] == '"' and string[-1] == '"':
string = string[1:-1]
return string
+
def int_to_str(value, length=2):
'''Converts integer to string eg 3 to "03"'''
try:
@@ -164,6 +169,7 @@ def int_to_str(value, length=2):
content = '0' + content
return content
+
def split_file_list(ext=None):
file_list = [None for m in range(100)]
if ext and ext[0] != '.':
@@ -260,6 +266,7 @@ class Directory:
else:
self.content.append(File(self.path + os.sep + i))
+
class File:
def __init__(self, path):
self.path = path
@@ -285,6 +292,7 @@ class File:
return content
+
class CueFile(File):
def __init__(self, path):
@@ -434,6 +442,7 @@ class CueFile(File):
content += '\n'
return content
+
class MetaFile(File):
def __init__(self, path):
File.__init__(self, path)
@@ -498,6 +507,7 @@ class MetaFile(File):
'''Returns tracks count'''
return len(self.content['tracks']) - self.content['tracks'].count(None)
+
class WaveFile(File):
def __init__(self, path, track_nr=None):
File.__init__(self, path)
@@ -537,6 +547,7 @@ class WaveFile(File):
if self.type == 'Free Lossless Audio Codec':
return FLAC(self.name)
+
def split(albumpath):
os.chdir(albumpath)
diff --git a/headphones/db.py b/headphones/db.py
index 9c07db9b..c943b66f 100644
--- a/headphones/db.py
+++ b/headphones/db.py
@@ -28,10 +28,12 @@ import headphones
from headphones import logger
+
def dbFilename(filename="headphones.db"):
return os.path.join(headphones.DATA_DIR, filename)
+
def getCacheSize():
#this will protect against typecasting problems produced by empty string and None settings
if not headphones.CONFIG.CACHE_SIZEMB:
@@ -39,6 +41,7 @@ def getCacheSize():
return 0
return int(headphones.CONFIG.CACHE_SIZEMB)
+
class DBConnection:
def __init__(self, filename="headphones.db"):
diff --git a/headphones/exceptions.py b/headphones/exceptions.py
index a1e62f1a..5d0ddf52 100644
--- a/headphones/exceptions.py
+++ b/headphones/exceptions.py
@@ -13,11 +13,13 @@
# You should have received a copy of the GNU General Public License
# along with Headphones. If not, see .
+
class HeadphonesException(Exception):
"""
Generic Headphones Exception - should never be thrown, only subclassed
"""
+
class NewzbinAPIThrottled(HeadphonesException):
"""
Newzbin has throttled us, deal with it
diff --git a/headphones/getXldProfile.py b/headphones/getXldProfile.py
index ec0e0e5e..b17e2244 100755
--- a/headphones/getXldProfile.py
+++ b/headphones/getXldProfile.py
@@ -5,6 +5,7 @@ import xml.parsers.expat as expat
import commands
from headphones import logger
+
def getXldProfile(xldProfile):
xldProfileNotFound = xldProfile
expandedPath = os.path.expanduser('~/Library/Preferences/jp.tmkk.XLD.plist')
diff --git a/headphones/helpers.py b/headphones/helpers.py
index 92288fe1..ebd5a24e 100644
--- a/headphones/helpers.py
+++ b/headphones/helpers.py
@@ -31,6 +31,7 @@ RE_FEATURING = re.compile(r"[fF]t\.|[fF]eaturing|[fF]eat\.|\b[wW]ith\b|&|vs\.")
RE_CD_ALBUM = re.compile(r"\(?((CD|disc)\s*[0-9]+)\)?", re.I)
RE_CD = re.compile(r"^(CD|dics)\s*[0-9]+$", re.I)
+
def multikeysort(items, columns):
comparers = [ ((itemgetter(col[1:].strip()), -1) if col.startswith('-') else (itemgetter(col.strip()), 1)) for col in columns]
@@ -44,12 +45,14 @@ def multikeysort(items, columns):
return sorted(items, cmp=comparer)
+
def checked(variable):
if variable:
return 'Checked'
else:
return ''
+
def radio(variable, pos):
if variable == pos:
@@ -57,6 +60,7 @@ def radio(variable, pos):
else:
return ''
+
def latinToAscii(unicrap):
"""
From couch potato
@@ -98,6 +102,7 @@ def latinToAscii(unicrap):
r += str(i)
return r
+
def convert_milliseconds(ms):
seconds = ms/1000
@@ -109,6 +114,7 @@ def convert_milliseconds(ms):
return minutes
+
def convert_seconds(s):
gmtime = time.gmtime(s)
@@ -119,15 +125,18 @@ def convert_seconds(s):
return minutes
+
def today():
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")
+
def get_age(date):
try:
@@ -142,17 +151,20 @@ def get_age(date):
return days_old
+
def bytes_to_mb(bytes):
mb = int(bytes)/1048576
size = '%.1f MB' % mb
return size
+
def mb_to_bytes(mb_str):
result = re.search('^(\d+(?:\.\d+)?)\s?(?:mb)?', mb_str, flags=re.I)
if result:
return int(float(result.group(1))*1048576)
+
def piratesize(size):
split = size.split(" ")
factor = float(split[0])
@@ -170,6 +182,7 @@ def piratesize(size):
return size
+
def replace_all(text, dic, normalize=False):
if not text:
@@ -187,6 +200,7 @@ def replace_all(text, dic, normalize=False):
text = text.replace(i, j)
return text
+
def replace_illegal_chars(string, type="file"):
if type == "file":
string = re.sub('[\?"*:|<>/]', '_', string)
@@ -195,6 +209,7 @@ def replace_illegal_chars(string, type="file"):
return string
+
def cleanName(string):
pass1 = latinToAscii(string).lower()
@@ -202,6 +217,7 @@ def cleanName(string):
return out_string
+
def cleanTitle(title):
title = re.sub('[\.\-\/\_]', ' ', title).lower()
@@ -213,6 +229,7 @@ def cleanTitle(title):
return title
+
def split_path(f):
"""
Split a path into components, starting with the drive letter (if any). Given
@@ -244,6 +261,7 @@ def split_path(f):
# Done
return components
+
def expand_subfolders(f):
"""
Try to expand a given folder and search for subfolders containing media
@@ -310,6 +328,7 @@ def expand_subfolders(f):
logger.debug("Expanded subfolders in folder: %s", media_folders)
return media_folders
+
def extract_data(s):
s = s.replace('_', ' ')
@@ -337,6 +356,7 @@ def extract_data(s):
else:
return (None, None, None)
+
def extract_metadata(f):
"""
Scan all files in the given directory and decide on an artist, album and
@@ -435,6 +455,7 @@ def extract_metadata(f):
return (None, None, None)
+
def get_downloaded_track_list(albumpath):
"""
Return a list of audio files for the given directory.
@@ -449,6 +470,7 @@ def get_downloaded_track_list(albumpath):
return downloaded_track_list
+
def preserve_torrent_direcory(albumpath):
"""
Copy torrent directory to headphones-modified to keep files for seeding.
@@ -465,6 +487,7 @@ def preserve_torrent_direcory(albumpath):
". Not continuing. Error: " + str(e))
return None
+
def cue_split(albumpath):
"""
Attempts to check and split audio files by a cue for the given directory.
@@ -504,6 +527,7 @@ def cue_split(albumpath):
return False
+
def extract_logline(s):
# Default log format
pattern = re.compile(r'(?P.*?)\s\-\s(?P.*?)\s*\:\:\s(?P.*?)\s\:\s(?P.*)', re.VERBOSE)
@@ -517,6 +541,7 @@ def extract_logline(s):
else:
return None
+
def extract_song_data(s):
#headphones default format
@@ -548,6 +573,7 @@ def extract_song_data(s):
logger.info("Couldn't parse %s into a valid Newbin format", s)
return (name, album, year)
+
def smartMove(src, dest, delete=True):
from headphones import logger
@@ -588,11 +614,15 @@ def smartMove(src, dest, delete=True):
# TODO: Grab config values from sab to know when these options are checked. For now we'll just iterate through all combinations
+
def sab_replace_dots(name):
return name.replace('.', ' ')
+
+
def sab_replace_spaces(name):
return name.replace(' ', '_')
+
def sab_sanitize_foldername(name):
""" Return foldername with dodgy chars converted to safe ones
Remove any leading and trailing dot and space characters
@@ -634,12 +664,14 @@ def sab_sanitize_foldername(name):
return name
+
def split_string(mystring, splitvar=','):
mylist = []
for each_word in mystring.split(splitvar):
mylist.append(each_word.strip())
return mylist
+
def create_https_certificates(ssl_cert, ssl_key):
"""
Stolen from SickBeard (http://github.com/midgetspy/Sick-Beard):
diff --git a/headphones/importer.py b/headphones/importer.py
index 5f274a08..8f16e7e5 100644
--- a/headphones/importer.py
+++ b/headphones/importer.py
@@ -32,6 +32,7 @@ blacklisted_special_artists = ['f731ccc4-e22a-43af-a747-64213329e088',
'125ec42a-7229-4250-afc5-e057484327fe',
'89ad4ac3-39f7-470e-963a-56509c546377']
+
def is_exists(artistid):
myDB = db.DBConnection()
@@ -52,7 +53,6 @@ def artistlist_to_mbids(artistlist, forced=False):
if not artist and not (artist == ' '):
continue
-
# If adding artists through Manage New Artists, they're coming through as non-unicode (utf-8?)
# and screwing everything up
if not isinstance(artist, unicode):
@@ -105,12 +105,14 @@ def artistlist_to_mbids(artistlist, forced=False):
except Exception as 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)
+
def addArtisttoDB(artistid, extrasonly=False, forcefull=False):
# Putting this here to get around the circular import. We're using this to update thumbnails for artist/albums
@@ -172,7 +174,6 @@ def addArtisttoDB(artistid, extrasonly=False, forcefull=False):
else:
sortname = artist['artist_name']
-
logger.info(u"Now adding/updating: " + artist['artist_name'])
controlValueDict = {"ArtistID": artistid}
newValueDict = {"ArtistName": artist['artist_name'],
@@ -240,7 +241,6 @@ def addArtisttoDB(artistid, extrasonly=False, forcefull=False):
check_release_date = None
new_release_group = True
-
if new_release_group:
logger.info("[%s] Now adding: %s (New Release Group)" % (artist['artist_name'], rg['title']))
new_releases = mb.get_new_releases(rgid, includeExtras)
@@ -504,6 +504,7 @@ def addArtisttoDB(artistid, extrasonly=False, forcefull=False):
for album_search in album_searches:
searcher.searchforalbum(albumid=album_search)
+
def finalize_update(artistid, artistname, errors=False):
# Moving this little bit to it's own function so we can update have tracks & latest album when deleting extras
@@ -533,6 +534,7 @@ def finalize_update(artistid, artistname, errors=False):
myDB.upsert("artists", newValueDict, controlValueDict)
+
def addReleaseById(rid, rgid=None):
myDB = db.DBConnection()
@@ -689,6 +691,7 @@ def addReleaseById(rid, rgid=None):
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')
@@ -718,6 +721,7 @@ def updateFormat():
myDB.upsert("have", newValueDict, controlValueDict)
logger.info('Finished finding media format for %s files' % len(havetracks))
+
def getHybridRelease(fullreleaselist):
"""
Returns a dictionary of best group of tracks from the list of releases and
diff --git a/headphones/lastfm.py b/headphones/lastfm.py
index 9a3a24ab..c97c019e 100644
--- a/headphones/lastfm.py
+++ b/headphones/lastfm.py
@@ -30,6 +30,7 @@ API_KEY = "395e6ec6bb557382fc41fde867bce66f"
# Required for API request limit
lock = threading.Lock()
+
def request_lastfm(method, **kwargs):
"""
Call a Last.FM API method. Automatically sets the method and API key. Method
@@ -62,6 +63,7 @@ def request_lastfm(method, **kwargs):
return data
+
def getSimilar():
myDB = db.DBConnection()
results = myDB.select("SELECT ArtistID from artists ORDER BY HaveTracks DESC")
@@ -107,6 +109,7 @@ def getSimilar():
logger.debug("Inserted %d artists into Last.FM tag cloud", len(top_list))
+
def getArtists():
myDB = db.DBConnection()
results = myDB.select("SELECT ArtistID from artists")
@@ -136,6 +139,7 @@ def getArtists():
logger.info("Imported %d new artists from Last.FM", len(artistlist))
+
def getTagTopArtists(tag, limit=50):
myDB = db.DBConnection()
results = myDB.select("SELECT ArtistID from artists")
diff --git a/headphones/librarysync.py b/headphones/librarysync.py
index e4a94332..0a0c8e28 100644
--- a/headphones/librarysync.py
+++ b/headphones/librarysync.py
@@ -22,9 +22,10 @@ from beets.mediafile import MediaFile, FileTypeError, UnreadableFileError
from headphones import db, logger, helpers, importer, lastfm
# You can scan a single directory and append it to the current library by specifying append=True, ArtistID & ArtistName
-def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None, cron=False):
+def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None, cron=False):
+
if cron and not headphones.CONFIG.LIBRARYSCAN:
return
@@ -180,7 +181,6 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None, cron=Fal
file_count+=1
-
# Now we start track matching
logger.info("%s new/modified songs found and added to the database" % new_song_count)
song_list = myDB.action("SELECT * FROM have WHERE Matched IS NULL AND LOCATION LIKE ?", [dir.decode(headphones.SYS_ENCODING, 'replace')+"%"])
@@ -293,7 +293,6 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None, cron=Fal
logger.info('Completed matching tracks from directory: %s' % dir.decode(headphones.SYS_ENCODING, 'replace'))
-
if not append:
logger.info('Updating scanned artist track counts')
@@ -343,6 +342,8 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None, cron=Fal
logger.info('Library scan complete')
#ADDED THIS SECTION TO MARK ALBUMS AS DOWNLOADED IF ARTISTS ARE ADDED EN MASSE BEFORE LIBRARY IS SCANNED
+
+
def update_album_status(AlbumID=None):
myDB = db.DBConnection()
logger.info('Counting matched tracks to mark albums as skipped/downloaded')
diff --git a/headphones/logger.py b/headphones/logger.py
index ad1e46af..781d5402 100644
--- a/headphones/logger.py
+++ b/headphones/logger.py
@@ -39,6 +39,7 @@ logger = logging.getLogger("headphones")
# Global queue for multiprocessing logging
queue = None
+
class LogListHandler(logging.Handler):
"""
Log handler for Web UI.
@@ -50,6 +51,7 @@ class LogListHandler(logging.Handler):
headphones.LOG_LIST.insert(0, (helpers.now(), message, record.levelname, record.threadName))
+
@contextlib.contextmanager
def listener():
"""
@@ -85,6 +87,7 @@ def listener():
finally:
queue_listener.stop()
+
def initMultiprocessing():
"""
Remove all handlers and add QueueHandler on top. This should only be called
@@ -108,6 +111,7 @@ def initMultiprocessing():
# Change current thread name for log record
threading.current_thread().name = multiprocessing.current_process().name
+
def initLogger(console=False, verbose=False):
"""
Setup logging for Headphones. It uses the logger instance with the name
@@ -163,6 +167,7 @@ def initLogger(console=False, verbose=False):
# Install exception hooks
initHooks()
+
def initHooks(global_exceptions=True, thread_exceptions=True, pass_original=True):
"""
This method installs exception catching mechanisms. Any exception caught
diff --git a/headphones/lyrics.py b/headphones/lyrics.py
index ea8458ee..ea6fcd8f 100644
--- a/headphones/lyrics.py
+++ b/headphones/lyrics.py
@@ -18,6 +18,7 @@ import htmlentitydefs
from headphones import logger, request
+
def getLyrics(artist, song):
params = { "artist": artist.encode('utf-8'),
@@ -60,6 +61,7 @@ def getLyrics(artist, song):
return lyrics
+
def convert_html_entities(s):
matches = re.findall("\d+;", s)
if len(matches) > 0:
diff --git a/headphones/mb.py b/headphones/mb.py
index 135567a6..8985d9d0 100644
--- a/headphones/mb.py
+++ b/headphones/mb.py
@@ -32,6 +32,8 @@ mb_lock = threading.Lock()
# Quick fix to add mirror switching on the fly. Need to probably return the mbhost & mbport that's
# being used, so we can send those values to the log
+
+
def startmb():
mbuser = None
@@ -73,6 +75,7 @@ def startmb():
return True
+
def findArtist(name, limit=1):
with mb_lock:
@@ -123,6 +126,7 @@ def findArtist(name, limit=1):
})
return artistlist
+
def findRelease(name, limit=1, artist=None):
with mb_lock:
@@ -201,6 +205,7 @@ def findRelease(name, limit=1, artist=None):
})
return releaselist
+
def getArtist(artistid, extrasonly=False):
with mb_lock:
@@ -247,7 +252,6 @@ def getArtist(artistid, extrasonly=False):
# if 'end' in artist['life-span']:
# artist_dict['artist_enddate'] = unicode(artist['life-span']['end'])
-
releasegroups = []
if not extrasonly:
@@ -321,6 +325,7 @@ def getArtist(artistid, extrasonly=False):
return artist_dict
+
def getReleaseGroup(rgid):
"""
Returns a list of releases in a release group
@@ -342,6 +347,7 @@ def getReleaseGroup(rgid):
else:
return releaseGroup['release-list']
+
def getRelease(releaseid, include_artist_info=True):
"""
Deep release search to get track info
@@ -377,7 +383,6 @@ def getRelease(releaseid, include_artist_info=True):
except:
release['country'] = u'Unknown'
-
if include_artist_info:
if 'release-group' in results:
@@ -404,6 +409,7 @@ def getRelease(releaseid, include_artist_info=True):
return release
+
def get_new_releases(rgid, includeExtras=False, forcefull=False):
myDB = db.DBConnection()
@@ -486,7 +492,6 @@ def get_new_releases(rgid, includeExtras=False, forcefull=False):
logger.warn('Release ' + releasedata['id'] + ' has no Artists associated.')
return False
-
release['ReleaseCountry'] = unicode(releasedata['country']) if 'country' in releasedata else u'Unknown'
#assuming that the list will contain media and that the format will be consistent
try:
@@ -570,6 +575,7 @@ def get_new_releases(rgid, includeExtras=False, forcefull=False):
return num_new_releases
+
def getTracksFromRelease(release):
totalTracks = 1
tracks = []
@@ -590,6 +596,8 @@ def getTracksFromRelease(release):
return tracks
# Used when there is a disambiguation
+
+
def findArtistbyAlbum(name):
myDB = db.DBConnection()
@@ -613,7 +621,6 @@ def findArtistbyAlbum(name):
logger.warn('Attempt to query MusicBrainz for %s failed (%s)' % (name, str(e)))
time.sleep(5)
-
if not results:
return False
@@ -631,10 +638,9 @@ def findArtistbyAlbum(name):
#artist_dict['url'] = u'http://musicbrainz.org/artist/' + newArtist['id']
#artist_dict['score'] = int(releaseGroup['ext:score'])
-
-
return artist_dict
+
def findAlbumID(artist=None, album=None):
results = None
diff --git a/headphones/music_encoder.py b/headphones/music_encoder.py
index 9fa521b0..2bd1113b 100644
--- a/headphones/music_encoder.py
+++ b/headphones/music_encoder.py
@@ -30,6 +30,7 @@ if headphones.CONFIG.ENCODER == 'xld':
else:
XLD = False
+
def encode(albumPath):
# Return if xld details not found
@@ -226,6 +227,7 @@ def encode(albumPath):
return musicFinalFiles
+
def command_map(args):
"""
Wrapper for the '[multiprocessing.]map()' method, to unpack the arguments
@@ -243,6 +245,7 @@ def command_map(args):
logger.exception("Encoder raised an exception.")
return False
+
def command(encoder, musicSource, musicDest, albumPath):
"""
Encode a given music file with a certain encoder. Returns True on success,
@@ -357,6 +360,7 @@ def command(encoder, musicSource, musicDest, albumPath):
return encoded
+
def getTimeEncode(start):
seconds =int(time.time()-start)
hours = seconds / 3600
diff --git a/headphones/notifiers.py b/headphones/notifiers.py
index 75a4f670..fc81f62e 100644
--- a/headphones/notifiers.py
+++ b/headphones/notifiers.py
@@ -39,6 +39,7 @@ try:
except ImportError:
from cgi import parse_qsl
+
class GROWL(object):
"""
Growl notifications, for OS X.
@@ -124,6 +125,7 @@ class GROWL(object):
self.notify('ZOMG Lazors Pewpewpew!', 'Test Message')
+
class PROWL(object):
"""
Prowl notifications.
@@ -177,6 +179,7 @@ class PROWL(object):
self.notify('ZOMG Lazors Pewpewpew!', 'Test Message')
+
class MPC(object):
"""
MPC library update
@@ -264,6 +267,7 @@ class XBMC(object):
except Exception:
logger.error('Error sending notification request to XBMC')
+
class LMS(object):
"""
Class for updating a Logitech Media Server
@@ -305,6 +309,7 @@ class LMS(object):
if not request:
logger.warn('Error sending rescan request to LMS')
+
class Plex(object):
def __init__(self):
@@ -391,6 +396,7 @@ class Plex(object):
except:
logger.warn('Error sending notification request to Plex Media Server')
+
class NMA(object):
def notify(self, artist=None, album=None, snatched=None):
title = 'Headphones'
@@ -427,6 +433,7 @@ class NMA(object):
else:
return True
+
class PUSHBULLET(object):
def __init__(self):
@@ -480,6 +487,7 @@ class PUSHBULLET(object):
self.notify('Main Screen Activate', 'Test Message')
+
class PUSHALOT(object):
def notify(self, message, event):
@@ -519,6 +527,7 @@ class PUSHALOT(object):
logger.info(u"Pushalot notification failed.")
return False
+
class Synoindex(object):
def __init__(self, util_loc='/usr/syno/bin/synoindex'):
self.util_loc = util_loc
@@ -555,6 +564,7 @@ class Synoindex(object):
for path in path_list:
self.notify(path)
+
class PUSHOVER(object):
def __init__(self):
@@ -613,6 +623,7 @@ class PUSHOVER(object):
self.notify('Main Screen Activate', 'Test Message')
+
class TwitterNotifier(object):
REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token'
@@ -689,7 +700,6 @@ class TwitterNotifier(object):
headphones.CONFIG.TWITTER_PASSWORD = access_token['oauth_token_secret']
return True
-
def _send_tweet(self, message=None):
username=self.consumer_key
@@ -717,6 +727,7 @@ class TwitterNotifier(object):
return self._send_tweet(prefix+": "+message)
+
class OSX_NOTIFY(object):
def __init__(self):
@@ -727,6 +738,7 @@ class OSX_NOTIFY(object):
def swizzle(self, cls, SEL, func):
old_IMP = cls.instanceMethodForSelector_(SEL)
+
def wrapper(self, *args, **kwargs):
return func(self, old_IMP, *args, **kwargs)
new_IMP = self.objc.selector(wrapper, selector=old_IMP.selector,
@@ -772,6 +784,7 @@ class OSX_NOTIFY(object):
def swizzled_bundleIdentifier(self, original, swizzled):
return 'ade.headphones.osxnotify'
+
class BOXCAR(object):
def __init__(self):
@@ -798,6 +811,7 @@ class BOXCAR(object):
logger.warn('Error sending Boxcar2 Notification: %s' % e)
return False
+
class SubSonicNotifier(object):
def __init__(self):
diff --git a/headphones/nzbget.py b/headphones/nzbget.py
index f892caf1..80ce36db 100644
--- a/headphones/nzbget.py
+++ b/headphones/nzbget.py
@@ -19,7 +19,6 @@
# along with Sick Beard. If not, see .
-
import httplib
import datetime
@@ -32,6 +31,7 @@ import xmlrpclib
from headphones import logger
+
def sendNZB(nzb):
addToTop = False
@@ -48,7 +48,6 @@ def sendNZB(nzb):
nzbgetXMLrpc = 'http://' + nzbgetXMLrpc
headphones.CONFIG.NZBGET_HOST.replace('http://', '', 1)
-
url = nzbgetXMLrpc % {"host": headphones.CONFIG.NZBGET_HOST, "username": headphones.CONFIG.NZBGET_USERNAME, "password": headphones.CONFIG.NZBGET_PASSWORD}
nzbGetRPC = xmlrpclib.ServerProxy(url)
diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py
index 18b19b69..ef2b7f0f 100755
--- a/headphones/postprocessor.py
+++ b/headphones/postprocessor.py
@@ -32,6 +32,7 @@ from headphones import logger, helpers, request, mb, music_encoder
postprocessor_lock = threading.Lock()
+
def checkFolder():
with postprocessor_lock:
@@ -57,6 +58,7 @@ def checkFolder():
else:
logger.info("No folder name found for " + album['Title'])
+
def verify(albumid, albumpath, Kind=None, forced=False):
myDB = db.DBConnection()
@@ -276,6 +278,7 @@ def verify(albumid, albumpath, Kind=None, forced=False):
else:
logger.info(u"Already marked as unprocessed: " + albumpath.decode(headphones.SYS_ENCODING, 'replace'))
+
def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list, Kind=None):
logger.info('Starting post-processing for: %s - %s' % (release['ArtistName'], release['AlbumTitle']))
@@ -500,6 +503,7 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
mpc = notifiers.MPC()
mpc.notify()
+
def embedAlbumArt(artwork, downloaded_track_list):
logger.info('Embedding album art')
@@ -519,6 +523,7 @@ def embedAlbumArt(artwork, downloaded_track_list):
logger.error(u'Error embedding album art to: %s. Error: %s' % (downloaded_track.decode(headphones.SYS_ENCODING, 'replace'), str(e)))
continue
+
def addAlbumArt(artwork, albumpath, release):
logger.info('Adding album art to folder')
@@ -552,6 +557,7 @@ def addAlbumArt(artwork, albumpath, release):
logger.error('Error saving album art: %s', e)
return
+
def cleanupFiles(albumpath):
logger.info('Cleaning up files')
@@ -564,6 +570,7 @@ def cleanupFiles(albumpath):
except Exception as e:
logger.error(u'Could not remove file: %s. Error: %s' % (files.decode(headphones.SYS_ENCODING, 'replace'), e))
+
def renameNFO(albumpath):
logger.info('Renaming NFO')
@@ -577,6 +584,7 @@ def renameNFO(albumpath):
except Exception as e:
logger.error(u'Could not rename file: %s. Error: %s' % (os.path.join(r, file).decode(headphones.SYS_ENCODING, 'replace'), e))
+
def moveFiles(albumpath, release, tracks):
logger.info("Moving files: %s" % albumpath)
try:
@@ -809,6 +817,7 @@ def moveFiles(albumpath, release, tracks):
return destination_paths
+
def correctMetadata(albumid, release, downloaded_track_list):
logger.info('Preparing to write metadata to tracks....')
@@ -862,6 +871,7 @@ def correctMetadata(albumid, release, downloaded_track_list):
except Exception, e:
logger.warn("Error writing metadata to '%s': %s", item.path.decode(headphones.SYS_ENCODING, 'replace'), str(e))
+
def embedLyrics(downloaded_track_list):
logger.info('Adding lyrics')
@@ -909,6 +919,7 @@ def embedLyrics(downloaded_track_list):
else:
logger.debug('No lyrics found for track: %s', item.title)
+
def renameFiles(albumpath, downloaded_track_list, release):
logger.info('Renaming files')
try:
@@ -975,7 +986,6 @@ def renameFiles(albumpath, downloaded_track_list, release):
new_file_name = helpers.replace_all(headphones.CONFIG.FILE_FORMAT.strip(), values).replace('/', '_') + ext
-
new_file_name = helpers.replace_illegal_chars(new_file_name).encode(headphones.SYS_ENCODING, 'replace')
if headphones.CONFIG.FILE_UNDERSCORES:
@@ -997,6 +1007,7 @@ def renameFiles(albumpath, downloaded_track_list, release):
logger.error('Error renaming file: %s. Error: %s', downloaded_track.decode(headphones.SYS_ENCODING, 'replace'), e)
continue
+
def updateFilePermissions(albumpaths):
for folder in albumpaths:
@@ -1010,6 +1021,7 @@ def updateFilePermissions(albumpaths):
logger.error("Could not change permissions for file: %s", full_path)
continue
+
def renameUnprocessedFolder(albumpath):
i = 0
@@ -1026,6 +1038,7 @@ def renameUnprocessedFolder(albumpath):
os.rename(albumpath, new_folder_name)
return
+
def forcePostProcess(dir=None, expand_subfolders=True, album_dir=None):
if album_dir:
diff --git a/headphones/request.py b/headphones/request.py
index 5e0c6c62..3367428e 100644
--- a/headphones/request.py
+++ b/headphones/request.py
@@ -27,6 +27,7 @@ import collections
# Dictionary with last request times, for rate limiting.
last_requests = collections.defaultdict(int)
+
def request_response(url, method="get", auto_raise=True,
whitelist_status_code=None, rate_limit=None, **kwargs):
"""
@@ -125,6 +126,7 @@ def request_response(url, method="get", auto_raise=True,
except requests.RequestException as e:
logger.error("Request raised exception: %s", e)
+
def request_soup(url, **kwargs):
"""
Wrapper for `request_response', which will return a BeatifulSoup object if
@@ -137,6 +139,7 @@ def request_soup(url, **kwargs):
if response is not None:
return BeautifulSoup(response.content, parser)
+
def request_minidom(url, **kwargs):
"""
Wrapper for `request_response', which will return a Minidom object if no
@@ -148,6 +151,7 @@ def request_minidom(url, **kwargs):
if response is not None:
return minidom.parseString(response.content)
+
def request_json(url, **kwargs):
"""
Wrapper for `request_response', which will decode the response as JSON
@@ -175,6 +179,7 @@ def request_json(url, **kwargs):
if headphones.VERBOSE:
server_message(response)
+
def request_content(url, **kwargs):
"""
Wrapper for `request_response', which will return the raw content.
@@ -185,6 +190,7 @@ def request_content(url, **kwargs):
if response is not None:
return response.content
+
def request_feed(url, **kwargs):
"""
Wrapper for `request_response', which will return a feed object.
@@ -195,6 +201,7 @@ def request_feed(url, **kwargs):
if response is not None:
return feedparser.parse(response.content)
+
def server_message(response):
"""
Extract server message from response and log in to logger with DEBUG level.
diff --git a/headphones/sab.py b/headphones/sab.py
index 80a09f2c..1a67c028 100644
--- a/headphones/sab.py
+++ b/headphones/sab.py
@@ -30,6 +30,7 @@ from headphones.common import USER_AGENT
from headphones import logger
from headphones import notifiers, helpers
+
def sendNZB(nzb):
params = {}
@@ -127,6 +128,7 @@ def sendNZB(nzb):
logger.info(u"Unknown failure sending NZB to sab. Return text is: " + sabText)
return False
+
def checkConfig():
params = { 'mode': 'get_config',
diff --git a/headphones/searcher.py b/headphones/searcher.py
index b64284ee..83811d01 100644
--- a/headphones/searcher.py
+++ b/headphones/searcher.py
@@ -54,6 +54,7 @@ gazelle = None
# RUtracker search object
rutracker = rutrackersearch.Rutracker()
+
def fix_url(s, charset="utf-8"):
"""
Fix the URL so it is proper formatted and encoded.
@@ -68,6 +69,7 @@ def fix_url(s, charset="utf-8"):
return urlparse.urlunsplit((scheme, netloc, path, qs, anchor))
+
def torrent_to_file(target_file, data):
"""
Write torrent data to file, and change permissions accordingly. Will return
@@ -94,6 +96,7 @@ def torrent_to_file(target_file, data):
# Done
return True
+
def read_torrent_name(torrent_file, default_name=None):
"""
Read the torrent file and return the torrent name. If the torrent name
@@ -123,6 +126,7 @@ def read_torrent_name(torrent_file, default_name=None):
# Return default
return default_name
+
def calculate_torrent_hash(link, data=None):
"""
Calculate the torrent hash from a magnet link or data.
@@ -141,6 +145,7 @@ def calculate_torrent_hash(link, data=None):
return torrent_hash
+
def get_seed_ratio(provider):
"""
Return the seed ratio for the specified provider, if applicable. Defaults to
@@ -170,6 +175,7 @@ def get_seed_ratio(provider):
return seed_ratio
+
def searchforalbum(albumid=None, new=False, losslessOnly=False, choose_specific_download=False):
myDB = db.DBConnection()
@@ -204,6 +210,7 @@ def searchforalbum(albumid=None, new=False, losslessOnly=False, choose_specific_
logger.info('Search for Wanted albums complete')
+
def do_sorted_search(album, new, losslessOnly, choose_specific_download=False):
NZB_PROVIDERS = (headphones.CONFIG.HEADPHONES_INDEXER or headphones.CONFIG.NEWZNAB or headphones.CONFIG.NZBSORG or headphones.CONFIG.OMGWTFNZBS)
@@ -249,7 +256,6 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False):
results = nzb_results + torrent_results
-
if choose_specific_download:
return results
@@ -264,11 +270,13 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False):
if data and bestqual:
send_to_downloader(data, bestqual, album)
+
def removeDisallowedFilenameChars(filename):
validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits)
cleanedFilename = unicodedata.normalize('NFKD', filename).encode('ASCII', 'ignore').lower()
return ''.join(c for c in cleanedFilename if c in validFilenameChars)
+
def more_filtering(results, album, albumlength, new):
low_size_limit = None
@@ -332,6 +340,7 @@ def more_filtering(results, album, albumlength, new):
return results
+
def sort_search_results(resultlist, album, new, albumlength):
if new and not len(resultlist):
@@ -401,6 +410,7 @@ def sort_search_results(resultlist, album, new, albumlength):
return finallist
+
def get_year_from_release_date(release_date):
try:
@@ -410,6 +420,7 @@ def get_year_from_release_date(release_date):
return year
+
def searchNZB(album, new=False, losslessOnly=False, albumlength=None):
albumid = album['AlbumID']
@@ -678,6 +689,7 @@ def searchNZB(album, new=False, losslessOnly=False, albumlength=None):
return results
+
def send_to_downloader(data, bestqual, album):
logger.info(u'Found best result from %s: %s - %s', bestqual[3], bestqual[2], bestqual[0], helpers.bytes_to_mb(bestqual[1]))
@@ -920,6 +932,7 @@ def send_to_downloader(data, bestqual, album):
boxcar = notifiers.BOXCAR()
boxcar.notify('Headphones snatched: ' + title, b2msg, rgid)
+
def verifyresult(title, artistterm, term, lossless):
title = re.sub('[\.\-\/\_]', ' ', title)
@@ -985,6 +998,7 @@ def verifyresult(title, artistterm, term, lossless):
return True
+
def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
global gazelle # persistent what.cd api object to reduce number of login attempts
@@ -1057,7 +1071,6 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
return proxy_url
-
if headphones.CONFIG.KAT:
provider = "Kick Ass Torrents"
ka_term = term.replace("!", "")
@@ -1446,6 +1459,8 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
return results
# THIS IS KIND OF A MESS AND PROBABLY NEEDS TO BE CLEANED UP
+
+
def preprocess(resultlist):
for result in resultlist:
diff --git a/headphones/searcher_rutracker.py b/headphones/searcher_rutracker.py
index 5e2f3c62..815cd903 100644
--- a/headphones/searcher_rutracker.py
+++ b/headphones/searcher_rutracker.py
@@ -20,6 +20,7 @@ import urllib
import re
import os
+
class Rutracker():
logged_in = False
diff --git a/headphones/torrentfinished.py b/headphones/torrentfinished.py
index dcea9c68..38b5b30b 100644
--- a/headphones/torrentfinished.py
+++ b/headphones/torrentfinished.py
@@ -20,6 +20,8 @@ from headphones import db, utorrent, transmission, logger
postprocessor_lock = threading.Lock()
# Remove Torrent + data if Post Processed and finished Seeding
+
+
def checkTorrentFinished():
logger.info("Checking if any torrents have finished seeding and can be removed")
diff --git a/headphones/transmission.py b/headphones/transmission.py
index 2d42f227..4a5897f9 100644
--- a/headphones/transmission.py
+++ b/headphones/transmission.py
@@ -27,6 +27,7 @@ import headphones
# TODO: Store the session id so we don't need to make 2 calls
# Store torrent id so we can check up on it
+
def addTorrent(link):
method = 'torrent-add'
@@ -60,6 +61,7 @@ def addTorrent(link):
logger.info('Transmission returned status %s' % response['result'])
return False
+
def getTorrentFolder(torrentid):
method = 'torrent-get'
arguments = { 'ids': torrentid, 'fields': ['name', 'percentDone']}
@@ -80,6 +82,7 @@ def getTorrentFolder(torrentid):
return torrent_folder_name
+
def setSeedRatio(torrentid, ratio):
method = 'torrent-set'
if ratio != 0:
@@ -91,6 +94,7 @@ def setSeedRatio(torrentid, ratio):
if not response:
return False
+
def removeTorrent(torrentid, remove_data = False):
method = 'torrent-get'
@@ -120,6 +124,7 @@ def removeTorrent(torrentid, remove_data = False):
return False
+
def torrentAction(method, arguments):
host = headphones.CONFIG.TRANSMISSION_HOST
diff --git a/headphones/updater.py b/headphones/updater.py
index 30b9f057..4b1e8910 100644
--- a/headphones/updater.py
+++ b/headphones/updater.py
@@ -17,6 +17,7 @@ import headphones
from headphones import logger, db, importer
+
def dbUpdate(forcefull=False):
myDB = db.DBConnection()
diff --git a/headphones/utorrent.py b/headphones/utorrent.py
index 8410a4d4..e705678d 100644
--- a/headphones/utorrent.py
+++ b/headphones/utorrent.py
@@ -21,6 +21,7 @@ import headphones
from headphones import logger
from collections import namedtuple
+
class utorrentclient(object):
TOKEN_REGEX = "([^<>]+)
"
@@ -156,12 +157,14 @@ class utorrentclient(object):
logger.debug('URL: ' + str(url))
logger.debug('uTorrent webUI raised the following error: ' + str(err))
+
def labelTorrent(hash):
label = headphones.CONFIG.UTORRENT_LABEL
uTorrentClient = utorrentclient()
if label:
uTorrentClient.setprops(hash, 'label', label)
+
def removeTorrent(hash, remove_data = False):
uTorrentClient = utorrentclient()
status, torrentList = uTorrentClient.list()
@@ -177,6 +180,7 @@ def removeTorrent(hash, remove_data = False):
return False
return False
+
def setSeedRatio(hash, ratio):
uTorrentClient = utorrentclient()
uTorrentClient.setprops(hash, 'seed_override', '1')
@@ -186,6 +190,7 @@ def setSeedRatio(hash, ratio):
# TODO passing -1 should be unlimited
uTorrentClient.setprops(hash, 'seed_ratio', -10)
+
def dirTorrent(hash, cacheid=None, return_name=None):
uTorrentClient = utorrentclient()
@@ -212,6 +217,7 @@ def dirTorrent(hash, cacheid=None, return_name=None):
return None, None
+
def addTorrent(link, hash):
uTorrentClient = utorrentclient()
@@ -243,6 +249,7 @@ def addTorrent(link, hash):
labelTorrent(hash)
return os.path.basename(os.path.normpath(torrent_folder))
+
def getSettingsDirectories():
uTorrentClient = utorrentclient()
settings = uTorrentClient.get_settings()
diff --git a/headphones/versioncheck.py b/headphones/versioncheck.py
index f8d735d5..8eb9bf0c 100644
--- a/headphones/versioncheck.py
+++ b/headphones/versioncheck.py
@@ -22,6 +22,7 @@ import subprocess
from headphones import logger, version, request
+
def runGit(args):
if headphones.CONFIG.GIT_PATH:
@@ -59,6 +60,7 @@ def runGit(args):
return (output, err)
+
def getVersion():
if version.HEADPHONES_VERSION.startswith('win32build'):
@@ -115,6 +117,7 @@ def getVersion():
else:
return None, 'master'
+
def checkGithub():
headphones.COMMITS_BEHIND = 0
@@ -161,6 +164,7 @@ def checkGithub():
return headphones.LATEST_VERSION
+
def update():
if headphones.INSTALL_TYPE == 'win':
logger.info('Windows .exe updating not supported yet.')
diff --git a/headphones/webserve.py b/headphones/webserve.py
index 3cb54991..c9412c4e 100644
--- a/headphones/webserve.py
+++ b/headphones/webserve.py
@@ -37,6 +37,7 @@ except ImportError:
# Python 2.6.x fallback, from libs
from ordereddict import OrderedDict
+
def serve_template(templatename, **kwargs):
interface_dir = os.path.join(str(headphones.PROG_DIR), 'data/interfaces/')
@@ -50,6 +51,7 @@ def serve_template(templatename, **kwargs):
except:
return exceptions.html_error_template().render()
+
class WebInterface(object):
def index(self):
@@ -102,7 +104,6 @@ class WebInterface(object):
return serve_template(templatename="artist.html", title=artist['ArtistName'], artist=artist, albums=albums, extras=extras_dict)
artistPage.exposed = True
-
def albumPage(self, AlbumID):
myDB = db.DBConnection()
album = myDB.action('SELECT * from albums WHERE AlbumID=?', [AlbumID]).fetchone()
@@ -132,7 +133,6 @@ class WebInterface(object):
return serve_template(templatename="album.html", title=title, album=album, tracks=tracks, description=description)
albumPage.exposed = True
-
def search(self, name, type):
if len(name) == 0:
raise cherrypy.HTTPRedirect("home")
@@ -472,7 +472,6 @@ class WebInterface(object):
check = set([(cleanName(d['ArtistName']).lower(), cleanName(d['AlbumTitle']).lower()) for d in headphones_album_dictionary])
unmatchedalbums = [d for d in have_album_dictionary if (cleanName(d['ArtistName']).lower(), cleanName(d['AlbumTitle']).lower()) not in check]
-
return serve_template(templatename="manageunmatched.html", title="Manage Unmatched Items", unmatchedalbums=unmatchedalbums)
manageUnmatched.exposed = True
@@ -782,7 +781,6 @@ class WebInterface(object):
totalcount = 0
myDB = db.DBConnection()
-
sortcolumn = 'ArtistSortName'
sortbyhavepercent = False
if iSortCol_0 == '2':
@@ -809,7 +807,6 @@ class WebInterface(object):
if sortcolumn == 'ReleaseDate':
filtered.reverse()
-
artists = filtered[iDisplayStart:(iDisplayStart+iDisplayLength)]
rows = []
for artist in artists:
@@ -840,7 +837,6 @@ class WebInterface(object):
rows.append(row)
-
dict = {'iTotalDisplayRecords': len(filtered),
'iTotalRecords': totalcount,
'aaData': rows,
@@ -1362,6 +1358,7 @@ class WebInterface(object):
return msg
osxnotifyregister.exposed = True
+
class Artwork(object):
def index(self):
return "Artwork"
@@ -1400,6 +1397,7 @@ class Artwork(object):
def index(self):
return "Here be thumbs"
index.exposed = True
+
def default(self, ArtistOrAlbum="", ID=None):
from headphones import cache
ArtistID = None
diff --git a/headphones/webstart.py b/headphones/webstart.py
index 7010a83f..932ef3d2 100644
--- a/headphones/webstart.py
+++ b/headphones/webstart.py
@@ -22,6 +22,7 @@ from headphones import logger
from headphones.webserve import WebInterface
from headphones.helpers import create_https_certificates
+
def initialize(options=None):
if options is None:
options = {}
@@ -111,7 +112,6 @@ def initialize(options=None):
})
conf['/api'] = { 'tools.auth_basic.on': False }
-
# Prevent time-outs
cherrypy.engine.timeout_monitor.unsubscribe()
cherrypy.tree.mount(WebInterface(), str(options['http_root']), config=conf)