mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-02 01:39:29 +01:00
984 lines
43 KiB
Python
984 lines
43 KiB
Python
# This file is part of Headphones.
|
|
#
|
|
# Headphones is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Headphones is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Headphones. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import os
|
|
import cherrypy
|
|
|
|
from mako.template import Template
|
|
from mako.lookup import TemplateLookup
|
|
from mako import exceptions
|
|
|
|
import time
|
|
import threading
|
|
|
|
import headphones
|
|
|
|
from headphones import logger, searcher, db, importer, mb, lastfm, librarysync
|
|
from headphones.helpers import checked, radio,today
|
|
|
|
import lib.simplejson as simplejson
|
|
|
|
import sys
|
|
|
|
|
|
|
|
def serve_template(templatename, **kwargs):
|
|
|
|
interface_dir = os.path.join(str(headphones.PROG_DIR), 'data/interfaces/')
|
|
template_dir = os.path.join(str(interface_dir), headphones.INTERFACE)
|
|
|
|
_hplookup = TemplateLookup(directories=[template_dir])
|
|
|
|
try:
|
|
template = _hplookup.get_template(templatename)
|
|
return template.render(**kwargs)
|
|
except:
|
|
return exceptions.html_error_template().render()
|
|
|
|
class WebInterface(object):
|
|
|
|
def index(self):
|
|
raise cherrypy.HTTPRedirect("home")
|
|
index.exposed=True
|
|
|
|
def home(self):
|
|
myDB = db.DBConnection()
|
|
artists = myDB.select('SELECT * from artists order by ArtistSortName COLLATE NOCASE')
|
|
return serve_template(templatename="index.html", title="Home", artists=artists)
|
|
home.exposed = True
|
|
|
|
def artistPage(self, ArtistID):
|
|
myDB = db.DBConnection()
|
|
artist = myDB.action('SELECT * FROM artists WHERE ArtistID=?', [ArtistID]).fetchone()
|
|
albums = myDB.select('SELECT * from albums WHERE ArtistID=? order by ReleaseDate DESC', [ArtistID])
|
|
|
|
# Don't redirect to the artist page until it has the bare minimum info inserted
|
|
# Redirect to the home page if we still can't get it after 5 seconds
|
|
retry = 0
|
|
|
|
while retry < 5:
|
|
if not artist:
|
|
time.sleep(1)
|
|
artist = myDB.action('SELECT * FROM artists WHERE ArtistID=?', [ArtistID]).fetchone()
|
|
retry += 1
|
|
else:
|
|
break
|
|
|
|
if not artist:
|
|
raise cherrypy.HTTPRedirect("home")
|
|
|
|
# Serve the extras up as a dict to make things easier for new templates
|
|
extras_list = ["single", "ep", "compilation", "soundtrack", "live", "remix", "spokenword", "audiobook"]
|
|
extras_dict = {}
|
|
|
|
if not artist['Extras']:
|
|
artist_extras = ""
|
|
else:
|
|
artist_extras = artist['Extras']
|
|
|
|
i = 1
|
|
for extra in extras_list:
|
|
if str(i) in artist_extras:
|
|
extras_dict[extra] = "checked"
|
|
else:
|
|
extras_dict[extra] = ""
|
|
i+=1
|
|
|
|
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()
|
|
tracks = myDB.select('SELECT * from tracks WHERE AlbumID=?', [AlbumID])
|
|
description = myDB.action('SELECT * from descriptions WHERE ReleaseGroupID=?', [AlbumID]).fetchone()
|
|
title = album['ArtistName'] + ' - ' + album['AlbumTitle']
|
|
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")
|
|
if type == 'artist':
|
|
searchresults = mb.findArtist(name, limit=100)
|
|
else:
|
|
searchresults = mb.findRelease(name, limit=100)
|
|
return serve_template(templatename="searchresults.html", title='Search Results for: "' + name + '"', searchresults=searchresults, type=type)
|
|
search.exposed = True
|
|
|
|
def addArtist(self, artistid):
|
|
threading.Thread(target=importer.addArtisttoDB, args=[artistid]).start()
|
|
threading.Thread(target=lastfm.getSimilar).start()
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % artistid)
|
|
addArtist.exposed = True
|
|
|
|
def getExtras(self, ArtistID, newstyle=False, **kwargs):
|
|
# if calling this function without the newstyle, they're using the old format
|
|
# which doesn't separate extras, so we'll grab all of them
|
|
#
|
|
# If they are, we need to convert kwargs to string format
|
|
if not newstyle:
|
|
extras = "1,2,3,4,5,6,7,8"
|
|
else:
|
|
temp_extras_list = []
|
|
# TODO: Put these extras as a global variable
|
|
i = 1
|
|
for extra in ["single", "ep", "compilation", "soundtrack", "live", "remix", "spokenword", "audiobook"]:
|
|
if extra in kwargs:
|
|
temp_extras_list.append(i)
|
|
i += 1
|
|
extras = ','.join(str(n) for n in temp_extras_list)
|
|
|
|
myDB = db.DBConnection()
|
|
controlValueDict = {'ArtistID': ArtistID}
|
|
newValueDict = {'IncludeExtras': 1,
|
|
'Extras': extras}
|
|
myDB.upsert("artists", newValueDict, controlValueDict)
|
|
threading.Thread(target=importer.addArtisttoDB, args=[ArtistID, True]).start()
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
|
getExtras.exposed = True
|
|
|
|
def removeExtras(self, ArtistID):
|
|
myDB = db.DBConnection()
|
|
controlValueDict = {'ArtistID': ArtistID}
|
|
newValueDict = {'IncludeExtras': 0}
|
|
myDB.upsert("artists", newValueDict, controlValueDict)
|
|
extraalbums = myDB.select('SELECT AlbumID from albums WHERE ArtistID=? AND Status="Skipped" AND Type!="Album"', [ArtistID])
|
|
for album in extraalbums:
|
|
myDB.action('DELETE from tracks WHERE ArtistID=? AND AlbumID=?', [ArtistID, album['AlbumID']])
|
|
myDB.action('DELETE from albums WHERE ArtistID=? AND AlbumID=?', [ArtistID, album['AlbumID']])
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
|
removeExtras.exposed = True
|
|
|
|
def pauseArtist(self, ArtistID):
|
|
logger.info(u"Pausing artist: " + ArtistID)
|
|
myDB = db.DBConnection()
|
|
controlValueDict = {'ArtistID': ArtistID}
|
|
newValueDict = {'Status': 'Paused'}
|
|
myDB.upsert("artists", newValueDict, controlValueDict)
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
|
pauseArtist.exposed = True
|
|
|
|
def resumeArtist(self, ArtistID):
|
|
logger.info(u"Resuming artist: " + ArtistID)
|
|
myDB = db.DBConnection()
|
|
controlValueDict = {'ArtistID': ArtistID}
|
|
newValueDict = {'Status': 'Active'}
|
|
myDB.upsert("artists", newValueDict, controlValueDict)
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
|
resumeArtist.exposed = True
|
|
|
|
def deleteArtist(self, ArtistID):
|
|
logger.info(u"Deleting all traces of artist: " + ArtistID)
|
|
myDB = db.DBConnection()
|
|
myDB.action('DELETE from artists WHERE ArtistID=?', [ArtistID])
|
|
myDB.action('DELETE from albums WHERE ArtistID=?', [ArtistID])
|
|
myDB.action('DELETE from tracks WHERE ArtistID=?', [ArtistID])
|
|
myDB.action('INSERT OR REPLACE into blacklist VALUES (?)', [ArtistID])
|
|
raise cherrypy.HTTPRedirect("home")
|
|
deleteArtist.exposed = True
|
|
|
|
|
|
def deleteEmptyArtists(self):
|
|
logger.info(u"Deleting all empty artists")
|
|
myDB = db.DBConnection()
|
|
emptyArtistIDs = [row['ArtistID'] for row in myDB.select("SELECT ArtistID FROM artists WHERE HaveTracks == 0 OR LatestAlbum IS NULL")]
|
|
for ArtistID in emptyArtistIDs:
|
|
logger.info(u"Deleting all traces of artist: " + ArtistID)
|
|
myDB.action('DELETE from artists WHERE ArtistID=?', [ArtistID])
|
|
myDB.action('DELETE from albums WHERE ArtistID=?', [ArtistID])
|
|
myDB.action('DELETE from tracks WHERE ArtistID=?', [ArtistID])
|
|
myDB.action('INSERT OR REPLACE into blacklist VALUES (?)', [ArtistID])
|
|
deleteEmptyArtists.exposed = True
|
|
|
|
|
|
def refreshArtist(self, ArtistID):
|
|
threading.Thread(target=importer.addArtisttoDB, args=[ArtistID]).start()
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
|
refreshArtist.exposed=True
|
|
|
|
def markAlbums(self, ArtistID=None, action=None, **args):
|
|
myDB = db.DBConnection()
|
|
if action == 'WantedNew' or action == 'WantedLossless':
|
|
newaction = 'Wanted'
|
|
else:
|
|
newaction = action
|
|
for mbid in args:
|
|
logger.info("Marking %s as %s" % (mbid, newaction))
|
|
controlValueDict = {'AlbumID': mbid}
|
|
newValueDict = {'Status': newaction}
|
|
myDB.upsert("albums", newValueDict, controlValueDict)
|
|
if action == 'Wanted':
|
|
searcher.searchforalbum(mbid, new=False)
|
|
if action == 'WantedNew':
|
|
searcher.searchforalbum(mbid, new=True)
|
|
if action == 'WantedLossless':
|
|
searcher.searchforalbum(mbid, lossless=True)
|
|
if ArtistID:
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
|
else:
|
|
raise cherrypy.HTTPRedirect("upcoming")
|
|
markAlbums.exposed = True
|
|
|
|
def addArtists(self, **args):
|
|
threading.Thread(target=importer.artistlist_to_mbids, args=[args, True]).start()
|
|
raise cherrypy.HTTPRedirect("home")
|
|
addArtists.exposed = True
|
|
|
|
def queueAlbum(self, AlbumID, ArtistID=None, new=False, redirect=None, lossless=False):
|
|
logger.info(u"Marking album: " + AlbumID + " as wanted...")
|
|
myDB = db.DBConnection()
|
|
controlValueDict = {'AlbumID': AlbumID}
|
|
if lossless:
|
|
newValueDict = {'Status': 'Wanted Lossless'}
|
|
logger.info("...lossless only!")
|
|
else:
|
|
newValueDict = {'Status': 'Wanted'}
|
|
myDB.upsert("albums", newValueDict, controlValueDict)
|
|
searcher.searchforalbum(AlbumID, new)
|
|
if ArtistID:
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
|
else:
|
|
raise cherrypy.HTTPRedirect(redirect)
|
|
queueAlbum.exposed = True
|
|
|
|
def unqueueAlbum(self, AlbumID, ArtistID):
|
|
logger.info(u"Marking album: " + AlbumID + "as skipped...")
|
|
myDB = db.DBConnection()
|
|
controlValueDict = {'AlbumID': AlbumID}
|
|
newValueDict = {'Status': 'Skipped'}
|
|
myDB.upsert("albums", newValueDict, controlValueDict)
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
|
unqueueAlbum.exposed = True
|
|
|
|
def deleteAlbum(self, AlbumID, ArtistID=None):
|
|
logger.info(u"Deleting all traces of album: " + AlbumID)
|
|
myDB = db.DBConnection()
|
|
myDB.action('DELETE from albums WHERE AlbumID=?', [AlbumID])
|
|
myDB.action('DELETE from tracks WHERE AlbumID=?', [AlbumID])
|
|
if ArtistID:
|
|
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
|
else:
|
|
raise cherrypy.HTTPRedirect("home")
|
|
deleteAlbum.exposed = True
|
|
|
|
def switchAlbum(self, AlbumID, ReleaseID):
|
|
'''
|
|
Take the values from allalbums/alltracks (based on the ReleaseID) and swap it into the album & track tables
|
|
'''
|
|
from headphones import albumswitcher
|
|
albumswitcher.switch(AlbumID, ReleaseID)
|
|
raise cherrypy.HTTPRedirect("albumPage?AlbumID=%s" % AlbumID)
|
|
switchAlbum.exposed = True
|
|
|
|
def upcoming(self):
|
|
myDB = db.DBConnection()
|
|
upcoming = myDB.select("SELECT * from albums WHERE ReleaseDate > date('now') order by ReleaseDate ASC")
|
|
wanted = myDB.select("SELECT * from albums WHERE Status='Wanted'")
|
|
return serve_template(templatename="upcoming.html", title="Upcoming", upcoming=upcoming, wanted=wanted)
|
|
upcoming.exposed = True
|
|
|
|
def manage(self):
|
|
return serve_template(templatename="manage.html", title="Manage")
|
|
manage.exposed = True
|
|
|
|
def manageArtists(self):
|
|
myDB = db.DBConnection()
|
|
artists = myDB.select('SELECT * from artists order by ArtistSortName COLLATE NOCASE')
|
|
return serve_template(templatename="manageartists.html", title="Manage Artists", artists=artists)
|
|
manageArtists.exposed = True
|
|
|
|
def manageAlbums(self, Status=None):
|
|
myDB = db.DBConnection()
|
|
if Status == "Upcoming":
|
|
albums = myDB.select("SELECT * from albums WHERE ReleaseDate > date('now')")
|
|
elif Status:
|
|
albums = myDB.select('SELECT * from albums WHERE Status=?', [Status])
|
|
else:
|
|
albums = myDB.select('SELECT * from albums')
|
|
return serve_template(templatename="managealbums.html", title="Manage Albums", albums=albums)
|
|
manageAlbums.exposed = True
|
|
|
|
def manageNew(self):
|
|
myDB = db.DBConnection()
|
|
newartists = myDB.select('SELECT * from newartists')
|
|
return serve_template(templatename="managenew.html", title="Manage New Artists", newartists=newartists)
|
|
manageNew.exposed = True
|
|
|
|
def markArtists(self, action=None, **args):
|
|
myDB = db.DBConnection()
|
|
artistsToAdd = []
|
|
for ArtistID in args:
|
|
if action == 'delete':
|
|
myDB.action('DELETE from artists WHERE ArtistID=?', [ArtistID])
|
|
myDB.action('DELETE from albums WHERE ArtistID=?', [ArtistID])
|
|
myDB.action('DELETE from tracks WHERE ArtistID=?', [ArtistID])
|
|
myDB.action('INSERT OR REPLACE into blacklist VALUES (?)', [ArtistID])
|
|
elif action == 'pause':
|
|
controlValueDict = {'ArtistID': ArtistID}
|
|
newValueDict = {'Status': 'Paused'}
|
|
myDB.upsert("artists", newValueDict, controlValueDict)
|
|
elif action == 'resume':
|
|
controlValueDict = {'ArtistID': ArtistID}
|
|
newValueDict = {'Status': 'Active'}
|
|
myDB.upsert("artists", newValueDict, controlValueDict)
|
|
else:
|
|
artistsToAdd.append(ArtistID)
|
|
if len(artistsToAdd) > 0:
|
|
logger.debug("Refreshing artists: %s" % artistsToAdd)
|
|
threading.Thread(target=importer.addArtistIDListToDB, args=[artistsToAdd]).start()
|
|
raise cherrypy.HTTPRedirect("home")
|
|
markArtists.exposed = True
|
|
|
|
def importLastFM(self, username):
|
|
headphones.LASTFM_USERNAME = username
|
|
headphones.config_write()
|
|
threading.Thread(target=lastfm.getArtists).start()
|
|
time.sleep(10)
|
|
raise cherrypy.HTTPRedirect("home")
|
|
importLastFM.exposed = True
|
|
|
|
def importItunes(self, path):
|
|
headphones.PATH_TO_XML = path
|
|
headphones.config_write()
|
|
threading.Thread(target=importer.itunesImport, args=[path]).start()
|
|
time.sleep(10)
|
|
raise cherrypy.HTTPRedirect("home")
|
|
importItunes.exposed = True
|
|
|
|
def musicScan(self, path, redirect=None, autoadd=0):
|
|
headphones.ADD_ARTISTS = autoadd
|
|
headphones.MUSIC_DIR = path
|
|
headphones.config_write()
|
|
try:
|
|
threading.Thread(target=librarysync.libraryScan).start()
|
|
except Exception, e:
|
|
logger.error('Unable to complete the scan: %s' % e)
|
|
time.sleep(10)
|
|
if redirect:
|
|
raise cherrypy.HTTPRedirect(redirect)
|
|
else:
|
|
raise cherrypy.HTTPRedirect("home")
|
|
musicScan.exposed = True
|
|
|
|
def forceUpdate(self):
|
|
from headphones import updater
|
|
threading.Thread(target=updater.dbUpdate).start()
|
|
raise cherrypy.HTTPRedirect("home")
|
|
forceUpdate.exposed = True
|
|
|
|
def forceSearch(self):
|
|
from headphones import searcher
|
|
threading.Thread(target=searcher.searchforalbum).start()
|
|
raise cherrypy.HTTPRedirect("home")
|
|
forceSearch.exposed = True
|
|
|
|
def forcePostProcess(self):
|
|
from headphones import postprocessor
|
|
threading.Thread(target=postprocessor.forcePostProcess).start()
|
|
raise cherrypy.HTTPRedirect("home")
|
|
forcePostProcess.exposed = True
|
|
|
|
def checkGithub(self):
|
|
from headphones import versioncheck
|
|
versioncheck.checkGithub()
|
|
raise cherrypy.HTTPRedirect("home")
|
|
checkGithub.exposed = True
|
|
|
|
def history(self):
|
|
myDB = db.DBConnection()
|
|
history = myDB.select('''SELECT * from snatched order by DateAdded DESC''')
|
|
return serve_template(templatename="history.html", title="History", history=history)
|
|
return page
|
|
history.exposed = True
|
|
|
|
def logs(self):
|
|
return serve_template(templatename="logs.html", title="Log", lineList=headphones.LOG_LIST)
|
|
logs.exposed = True
|
|
|
|
|
|
def getLog(self,iDisplayStart=0,iDisplayLength=100,iSortCol_0=0,sSortDir_0="desc",sSearch="",**kwargs):
|
|
|
|
iDisplayStart = int(iDisplayStart)
|
|
iDisplayLength = int(iDisplayLength)
|
|
|
|
filtered = []
|
|
if sSearch == "":
|
|
filtered = headphones.LOG_LIST[::]
|
|
else:
|
|
filtered = [row for row in headphones.LOG_LIST for column in row if sSearch in column]
|
|
|
|
sortcolumn = 0
|
|
if iSortCol_0 == '1':
|
|
sortcolumn = 2
|
|
elif iSortCol_0 == '2':
|
|
sortcolumn = 1
|
|
filtered.sort(key=lambda x:x[sortcolumn],reverse=sSortDir_0 == "desc")
|
|
|
|
rows = filtered[iDisplayStart:(iDisplayStart+iDisplayLength)]
|
|
rows = [[row[0],row[2],row[1]] for row in rows]
|
|
|
|
dict = {'iTotalDisplayRecords':len(filtered),
|
|
'iTotalRecords':len(headphones.LOG_LIST),
|
|
'aaData':rows,
|
|
}
|
|
s = simplejson.dumps(dict)
|
|
return s
|
|
getLog.exposed = True
|
|
|
|
def getArtists_json(self,iDisplayStart=0,iDisplayLength=100,sSearch="",iSortCol_0='0',sSortDir_0='asc',**kwargs):
|
|
iDisplayStart = int(iDisplayStart)
|
|
iDisplayLength = int(iDisplayLength)
|
|
filtered = []
|
|
totalcount = 0
|
|
myDB = db.DBConnection()
|
|
|
|
|
|
sortcolumn = 'ArtistSortName'
|
|
sortbyhavepercent = False
|
|
if iSortCol_0 == '2':
|
|
sortcolumn = 'Status'
|
|
elif iSortCol_0 == '3':
|
|
sortcolumn = 'ReleaseDate'
|
|
elif iSortCol_0 == '4':
|
|
sortbyhavepercent = True
|
|
|
|
if sSearch == "":
|
|
query = 'SELECT * from artists order by %s COLLATE NOCASE %s' % (sortcolumn,sSortDir_0)
|
|
filtered = myDB.select(query)
|
|
totalcount = len(filtered)
|
|
else:
|
|
query = 'SELECT * from artists WHERE ArtistSortName LIKE "%' + sSearch + '%" OR LatestAlbum LIKE "%' + sSearch +'%"' + 'ORDER BY %s COLLATE NOCASE %s' % (sortcolumn,sSortDir_0)
|
|
filtered = myDB.select(query)
|
|
totalcount = myDB.select('SELECT COUNT(*) from artists')[0][0]
|
|
|
|
if sortbyhavepercent:
|
|
filtered.sort(key=lambda x:(float(x['HaveTracks'])/x['TotalTracks'] if x['TotalTracks'] > 0 else 0.0,x['HaveTracks'] if x['HaveTracks'] else 0.0),reverse=sSortDir_0 == "asc")
|
|
|
|
#can't figure out how to change the datatables default sorting order when its using an ajax datasource so ill
|
|
#just reverse it here and the first click on the "Latest Album" header will sort by descending release date
|
|
if sortcolumn == 'ReleaseDate':
|
|
filtered.reverse()
|
|
|
|
|
|
artists = filtered[iDisplayStart:(iDisplayStart+iDisplayLength)]
|
|
rows = []
|
|
for artist in artists:
|
|
row = {"ArtistID":artist['ArtistID'],
|
|
"ArtistSortName":artist["ArtistSortName"],
|
|
"Status":artist["Status"],
|
|
"TotalTracks":artist["TotalTracks"],
|
|
"HaveTracks":artist["HaveTracks"],
|
|
"LatestAlbum":"",
|
|
"ReleaseDate":"",
|
|
"ReleaseInFuture":"False",
|
|
"AlbumID":"",
|
|
}
|
|
|
|
if not row['HaveTracks']:
|
|
row['HaveTracks'] = 0
|
|
if artist['ReleaseDate'] and artist['LatestAlbum']:
|
|
row['ReleaseDate'] = artist['ReleaseDate']
|
|
row['LatestAlbum'] = artist['LatestAlbum']
|
|
row['AlbumID'] = artist['AlbumID']
|
|
if artist['ReleaseDate'] > today():
|
|
row['ReleaseInFuture'] = "True"
|
|
elif artist['LatestAlbum']:
|
|
row['ReleaseDate'] = ''
|
|
row['LatestAlbum'] = artist['LatestAlbum']
|
|
row['AlbumID'] = artist['AlbumID']
|
|
|
|
rows.append(row)
|
|
|
|
|
|
dict = {'iTotalDisplayRecords':len(filtered),
|
|
'iTotalRecords':totalcount,
|
|
'aaData':rows,
|
|
}
|
|
s = simplejson.dumps(dict)
|
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
|
return s
|
|
getArtists_json.exposed=True
|
|
|
|
def clearhistory(self, type=None):
|
|
myDB = db.DBConnection()
|
|
if type == 'all':
|
|
logger.info(u"Clearing all history")
|
|
myDB.action('DELETE from snatched')
|
|
else:
|
|
logger.info(u"Clearing history where status is %s" % type)
|
|
myDB.action('DELETE from snatched WHERE Status=?', [type])
|
|
raise cherrypy.HTTPRedirect("history")
|
|
clearhistory.exposed = True
|
|
|
|
def generateAPI(self):
|
|
|
|
import hashlib, random
|
|
|
|
apikey = hashlib.sha224( str(random.getrandbits(256)) ).hexdigest()[0:32]
|
|
logger.info("New API generated")
|
|
return apikey
|
|
|
|
generateAPI.exposed = True
|
|
|
|
def config(self):
|
|
|
|
interface_dir = os.path.join(headphones.PROG_DIR, 'data/interfaces/')
|
|
interface_list = [ name for name in os.listdir(interface_dir) if os.path.isdir(os.path.join(interface_dir, name)) ]
|
|
|
|
config = {
|
|
"http_host" : headphones.HTTP_HOST,
|
|
"http_user" : headphones.HTTP_USERNAME,
|
|
"http_port" : headphones.HTTP_PORT,
|
|
"http_pass" : headphones.HTTP_PASSWORD,
|
|
"launch_browser" : checked(headphones.LAUNCH_BROWSER),
|
|
"api_enabled" : checked(headphones.API_ENABLED),
|
|
"api_key" : headphones.API_KEY,
|
|
"download_scan_interval" : headphones.DOWNLOAD_SCAN_INTERVAL,
|
|
"nzb_search_interval" : headphones.SEARCH_INTERVAL,
|
|
"libraryscan_interval" : headphones.LIBRARYSCAN_INTERVAL,
|
|
"sab_host" : headphones.SAB_HOST,
|
|
"sab_user" : headphones.SAB_USERNAME,
|
|
"sab_api" : headphones.SAB_APIKEY,
|
|
"sab_pass" : headphones.SAB_PASSWORD,
|
|
"sab_cat" : headphones.SAB_CATEGORY,
|
|
"download_dir" : headphones.DOWNLOAD_DIR,
|
|
"use_blackhole" : checked(headphones.BLACKHOLE),
|
|
"blackhole_dir" : headphones.BLACKHOLE_DIR,
|
|
"usenet_retention" : headphones.USENET_RETENTION,
|
|
"use_nzbmatrix" : checked(headphones.NZBMATRIX),
|
|
"nzbmatrix_user" : headphones.NZBMATRIX_USERNAME,
|
|
"nzbmatrix_api" : headphones.NZBMATRIX_APIKEY,
|
|
"use_newznab" : checked(headphones.NEWZNAB),
|
|
"newznab_host" : headphones.NEWZNAB_HOST,
|
|
"newznab_api" : headphones.NEWZNAB_APIKEY,
|
|
"newznab_enabled" : checked(headphones.NEWZNAB_ENABLED),
|
|
"extra_newznabs" : headphones.EXTRA_NEWZNABS,
|
|
"use_nzbsorg" : checked(headphones.NZBSORG),
|
|
"nzbsorg_uid" : headphones.NZBSORG_UID,
|
|
"nzbsorg_hash" : headphones.NZBSORG_HASH,
|
|
"use_newzbin" : checked(headphones.NEWZBIN),
|
|
"newzbin_uid" : headphones.NEWZBIN_UID,
|
|
"newzbin_pass" : headphones.NEWZBIN_PASSWORD,
|
|
"torrentblackhole_dir" : headphones.TORRENTBLACKHOLE_DIR,
|
|
"download_torrent_dir" : headphones.DOWNLOAD_TORRENT_DIR,
|
|
"numberofseeders" : headphones.NUMBEROFSEEDERS,
|
|
"use_isohunt" : checked(headphones.ISOHUNT),
|
|
"use_kat" : checked(headphones.KAT),
|
|
"use_mininova" : checked(headphones.MININOVA),
|
|
"use_waffles" : checked(headphones.WAFFLES),
|
|
"waffles_uid" : headphones.WAFFLES_UID,
|
|
"waffles_passkey": headphones.WAFFLES_PASSKEY,
|
|
"use_rutracker" : checked(headphones.RUTRACKER),
|
|
"rutracker_user" : headphones.RUTRACKER_USER,
|
|
"rutracker_password": headphones.RUTRACKER_PASSWORD,
|
|
"use_whatcd" : checked(headphones.WHATCD),
|
|
"whatcd_username" : headphones.WHATCD_USERNAME,
|
|
"whatcd_password": headphones.WHATCD_PASSWORD,
|
|
"pref_qual_0" : radio(headphones.PREFERRED_QUALITY, 0),
|
|
"pref_qual_1" : radio(headphones.PREFERRED_QUALITY, 1),
|
|
"pref_qual_3" : radio(headphones.PREFERRED_QUALITY, 3),
|
|
"pref_qual_2" : radio(headphones.PREFERRED_QUALITY, 2),
|
|
"pref_bitrate" : headphones.PREFERRED_BITRATE,
|
|
"pref_bitrate_high" : headphones.PREFERRED_BITRATE_HIGH_BUFFER,
|
|
"pref_bitrate_low" : headphones.PREFERRED_BITRATE_LOW_BUFFER,
|
|
"detect_bitrate" : checked(headphones.DETECT_BITRATE),
|
|
"move_files" : checked(headphones.MOVE_FILES),
|
|
"rename_files" : checked(headphones.RENAME_FILES),
|
|
"correct_metadata" : checked(headphones.CORRECT_METADATA),
|
|
"cleanup_files" : checked(headphones.CLEANUP_FILES),
|
|
"add_album_art" : checked(headphones.ADD_ALBUM_ART),
|
|
"embed_album_art" : checked(headphones.EMBED_ALBUM_ART),
|
|
"embed_lyrics" : checked(headphones.EMBED_LYRICS),
|
|
"dest_dir" : headphones.DESTINATION_DIR,
|
|
"lossless_dest_dir" : headphones.LOSSLESS_DESTINATION_DIR,
|
|
"folder_format" : headphones.FOLDER_FORMAT,
|
|
"file_format" : headphones.FILE_FORMAT,
|
|
"include_extras" : checked(headphones.INCLUDE_EXTRAS),
|
|
"autowant_upcoming" : checked(headphones.AUTOWANT_UPCOMING),
|
|
"autowant_all" : checked(headphones.AUTOWANT_ALL),
|
|
"log_dir" : headphones.LOG_DIR,
|
|
"cache_dir" : headphones.CACHE_DIR,
|
|
"interface_list" : interface_list,
|
|
"music_encoder": checked(headphones.MUSIC_ENCODER),
|
|
"encoder": headphones.ENCODER,
|
|
"bitrate": int(headphones.BITRATE),
|
|
"encoderfolder": headphones.ENCODERFOLDER,
|
|
"advancedencoder": headphones.ADVANCEDENCODER,
|
|
"encoderoutputformat": headphones.ENCODEROUTPUTFORMAT,
|
|
"samplingfrequency": headphones.SAMPLINGFREQUENCY,
|
|
"encodervbrcbr": headphones.ENCODERVBRCBR,
|
|
"encoderquality": headphones.ENCODERQUALITY,
|
|
"encoderlossless": checked(headphones.ENCODERLOSSLESS),
|
|
"delete_lossless_files": checked(headphones.DELETE_LOSSLESS_FILES),
|
|
"prowl_enabled": checked(headphones.PROWL_ENABLED),
|
|
"prowl_onsnatch": checked(headphones.PROWL_ONSNATCH),
|
|
"prowl_keys": headphones.PROWL_KEYS,
|
|
"prowl_priority": headphones.PROWL_PRIORITY,
|
|
"xbmc_enabled": checked(headphones.XBMC_ENABLED),
|
|
"xbmc_host": headphones.XBMC_HOST,
|
|
"xbmc_username": headphones.XBMC_USERNAME,
|
|
"xbmc_password": headphones.XBMC_PASSWORD,
|
|
"xbmc_update": checked(headphones.XBMC_UPDATE),
|
|
"xbmc_notify": checked(headphones.XBMC_NOTIFY),
|
|
"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,
|
|
"customhost": headphones.CUSTOMHOST,
|
|
"customport": headphones.CUSTOMPORT,
|
|
"customsleep": headphones.CUSTOMSLEEP,
|
|
"hpuser": headphones.HPUSER,
|
|
"hppass": headphones.HPPASS,
|
|
"cache_sizemb":headphones.CACHE_SIZEMB,
|
|
}
|
|
|
|
# Need to convert EXTRAS to a dictionary we can pass to the config: it'll come in as a string like 2,5,6,8
|
|
extras_list = ["single", "ep", "compilation", "soundtrack", "live", "remix", "spokenword", "audiobook"]
|
|
extras_dict = {}
|
|
|
|
i = 1
|
|
for extra in extras_list:
|
|
if str(i) in headphones.EXTRAS:
|
|
extras_dict[extra] = "checked"
|
|
else:
|
|
extras_dict[extra] = ""
|
|
i+=1
|
|
|
|
config["extras"] = extras_dict
|
|
|
|
return serve_template(templatename="config.html", title="Settings", config=config)
|
|
config.exposed = True
|
|
|
|
|
|
def configUpdate(self, http_host='0.0.0.0', http_username=None, http_port=8181, http_password=None, launch_browser=0, api_enabled=0, api_key=None,
|
|
download_scan_interval=None, nzb_search_interval=None, libraryscan_interval=None, 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, newznab_enabled=0, nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, newzbin=0, newzbin_uid=None,
|
|
newzbin_password=None, preferred_quality=0, preferred_bitrate=None, detect_bitrate=0, move_files=0, torrentblackhole_dir=None, download_torrent_dir=None,
|
|
numberofseeders=10, use_isohunt=0, use_kat=0, use_mininova=0, waffles=0, waffles_uid=None, waffles_passkey=None, whatcd=0, whatcd_username=None, whatcd_password=None,
|
|
rutracker=0, rutracker_user=None, rutracker_password=None, rename_files=0, correct_metadata=0, cleanup_files=0, add_album_art=0, embed_album_art=0, embed_lyrics=0,
|
|
destination_dir=None, lossless_destination_dir=None, folder_format=None, file_format=None, include_extras=0, single=0, ep=0, compilation=0, soundtrack=0, live=0,
|
|
remix=0, spokenword=0, audiobook=0, autowant_upcoming=False, autowant_all=False, interface=None, log_dir=None, cache_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, 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, cache_sizemb=None, **kwargs):
|
|
|
|
headphones.HTTP_HOST = http_host
|
|
headphones.HTTP_PORT = http_port
|
|
headphones.HTTP_USERNAME = http_username
|
|
headphones.HTTP_PASSWORD = http_password
|
|
headphones.LAUNCH_BROWSER = launch_browser
|
|
headphones.API_ENABLED = api_enabled
|
|
headphones.API_KEY = api_key
|
|
headphones.DOWNLOAD_SCAN_INTERVAL = download_scan_interval
|
|
headphones.SEARCH_INTERVAL = nzb_search_interval
|
|
headphones.LIBRARYSCAN_INTERVAL = libraryscan_interval
|
|
headphones.SAB_HOST = sab_host
|
|
headphones.SAB_USERNAME = sab_username
|
|
headphones.SAB_PASSWORD = sab_password
|
|
headphones.SAB_APIKEY = sab_apikey
|
|
headphones.SAB_CATEGORY = sab_category
|
|
headphones.DOWNLOAD_DIR = download_dir
|
|
headphones.BLACKHOLE = blackhole
|
|
headphones.BLACKHOLE_DIR = blackhole_dir
|
|
headphones.USENET_RETENTION = usenet_retention
|
|
headphones.NZBMATRIX = nzbmatrix
|
|
headphones.NZBMATRIX_USERNAME = nzbmatrix_username
|
|
headphones.NZBMATRIX_APIKEY = nzbmatrix_apikey
|
|
headphones.NEWZNAB = newznab
|
|
headphones.NEWZNAB_HOST = newznab_host
|
|
headphones.NEWZNAB_APIKEY = newznab_apikey
|
|
headphones.NEWZNAB_ENABLED = newznab_enabled
|
|
headphones.NZBSORG = nzbsorg
|
|
headphones.NZBSORG_UID = nzbsorg_uid
|
|
headphones.NZBSORG_HASH = nzbsorg_hash
|
|
headphones.NEWZBIN = newzbin
|
|
headphones.NEWZBIN_UID = newzbin_uid
|
|
headphones.NEWZBIN_PASSWORD = newzbin_password
|
|
headphones.TORRENTBLACKHOLE_DIR = torrentblackhole_dir
|
|
headphones.NUMBEROFSEEDERS = numberofseeders
|
|
headphones.DOWNLOAD_TORRENT_DIR = download_torrent_dir
|
|
headphones.ISOHUNT = use_isohunt
|
|
headphones.KAT = use_kat
|
|
headphones.MININOVA = use_mininova
|
|
headphones.WAFFLES = waffles
|
|
headphones.WAFFLES_UID = waffles_uid
|
|
headphones.WAFFLES_PASSKEY = waffles_passkey
|
|
headphones.RUTRACKER = rutracker
|
|
headphones.RUTRACKER_USER = rutracker_user
|
|
headphones.RUTRACKER_PASSWORD = rutracker_password
|
|
headphones.WHATCD = whatcd
|
|
headphones.WHATCD_USERNAME = whatcd_username
|
|
headphones.WHATCD_PASSWORD = whatcd_password
|
|
headphones.PREFERRED_QUALITY = int(preferred_quality)
|
|
headphones.PREFERRED_BITRATE = preferred_bitrate
|
|
headphones.PREFERRED_BITRATE_HIGH_BUFFER = preferred_bitrate_high_buffer
|
|
headphones.PREFERRED_BITRATE_LOW_BUFFER = preferred_bitrate_low_buffer
|
|
headphones.DETECT_BITRATE = detect_bitrate
|
|
headphones.MOVE_FILES = move_files
|
|
headphones.CORRECT_METADATA = correct_metadata
|
|
headphones.RENAME_FILES = rename_files
|
|
headphones.CLEANUP_FILES = cleanup_files
|
|
headphones.ADD_ALBUM_ART = add_album_art
|
|
headphones.EMBED_ALBUM_ART = embed_album_art
|
|
headphones.EMBED_LYRICS = embed_lyrics
|
|
headphones.DESTINATION_DIR = destination_dir
|
|
headphones.LOSSLESS_DESTINATION_DIR = lossless_destination_dir
|
|
headphones.FOLDER_FORMAT = folder_format
|
|
headphones.FILE_FORMAT = file_format
|
|
headphones.INCLUDE_EXTRAS = include_extras
|
|
headphones.AUTOWANT_UPCOMING = autowant_upcoming
|
|
headphones.AUTOWANT_ALL = autowant_all
|
|
headphones.INTERFACE = interface
|
|
headphones.LOG_DIR = log_dir
|
|
headphones.CACHE_DIR = cache_dir
|
|
headphones.MUSIC_ENCODER = music_encoder
|
|
headphones.ENCODER = encoder
|
|
headphones.BITRATE = int(bitrate)
|
|
headphones.SAMPLINGFREQUENCY = int(samplingfrequency)
|
|
headphones.ENCODERFOLDER = encoderfolder
|
|
headphones.ADVANCEDENCODER = advancedencoder
|
|
headphones.ENCODEROUTPUTFORMAT = encoderoutputformat
|
|
headphones.ENCODERVBRCBR = encodervbrcbr
|
|
headphones.ENCODERQUALITY = int(encoderquality)
|
|
headphones.ENCODERLOSSLESS = int(encoderlossless)
|
|
headphones.DELETE_LOSSLESS_FILES = int(delete_lossless_files)
|
|
headphones.PROWL_ENABLED = prowl_enabled
|
|
headphones.PROWL_ONSNATCH = prowl_onsnatch
|
|
headphones.PROWL_KEYS = prowl_keys
|
|
headphones.PROWL_PRIORITY = prowl_priority
|
|
headphones.XBMC_ENABLED = xbmc_enabled
|
|
headphones.XBMC_HOST = xbmc_host
|
|
headphones.XBMC_USERNAME = xbmc_username
|
|
headphones.XBMC_PASSWORD = xbmc_password
|
|
headphones.XBMC_UPDATE = xbmc_update
|
|
headphones.XBMC_NOTIFY = xbmc_notify
|
|
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
|
|
headphones.CUSTOMPORT = customport
|
|
headphones.CUSTOMSLEEP = customsleep
|
|
headphones.HPUSER = hpuser
|
|
headphones.HPPASS = hppass
|
|
headphones.CACHE_SIZEMB = cache_sizemb
|
|
|
|
# Handle the variable config options. Note - keys with False values aren't getting passed
|
|
|
|
headphones.EXTRA_NEWZNABS = []
|
|
|
|
for kwarg in kwargs:
|
|
if kwarg.startswith('newznab_host'):
|
|
newznab_number = kwarg[12:]
|
|
newznab_host = kwargs['newznab_host' + newznab_number]
|
|
newznab_api = kwargs['newznab_api' + newznab_number]
|
|
try:
|
|
newznab_enabled = int(kwargs['newznab_enabled' + newznab_number])
|
|
except KeyError:
|
|
newznab_enabled = 0
|
|
|
|
headphones.EXTRA_NEWZNABS.append((newznab_host, newznab_api, newznab_enabled))
|
|
|
|
# Convert the extras to list then string. Coming in as 0 or 1
|
|
temp_extras_list = []
|
|
extras_list = [single, ep, compilation, soundtrack, live, remix, spokenword, audiobook]
|
|
|
|
i = 1
|
|
for extra in extras_list:
|
|
if extra:
|
|
temp_extras_list.append(i)
|
|
i+=1
|
|
|
|
headphones.EXTRAS = ','.join(str(n) for n in temp_extras_list)
|
|
|
|
# Write the config
|
|
headphones.config_write()
|
|
|
|
#reconfigure musicbrainz database connection with the new values
|
|
mb.startmb()
|
|
|
|
raise cherrypy.HTTPRedirect("config")
|
|
|
|
configUpdate.exposed = True
|
|
|
|
def shutdown(self):
|
|
headphones.SIGNAL = 'shutdown'
|
|
message = 'Shutting Down...'
|
|
return serve_template(templatename="shutdown.html", title="Shutting Down", message=message, timer=15)
|
|
return page
|
|
|
|
shutdown.exposed = True
|
|
|
|
def restart(self):
|
|
headphones.SIGNAL = 'restart'
|
|
message = 'Restarting...'
|
|
return serve_template(templatename="shutdown.html", title="Restarting", message=message, timer=30)
|
|
restart.exposed = True
|
|
|
|
def update(self):
|
|
headphones.SIGNAL = 'update'
|
|
message = 'Updating...'
|
|
return serve_template(templatename="shutdown.html", title="Updating", message=message, timer=120)
|
|
return page
|
|
update.exposed = True
|
|
|
|
def extras(self):
|
|
myDB = db.DBConnection()
|
|
cloudlist = myDB.select('SELECT * from lastfmcloud')
|
|
return serve_template(templatename="extras.html", title="Extras", cloudlist=cloudlist)
|
|
return page
|
|
extras.exposed = True
|
|
|
|
def addReleaseById(self, rid):
|
|
threading.Thread(target=importer.addReleaseById, args=[rid]).start()
|
|
raise cherrypy.HTTPRedirect("home")
|
|
addReleaseById.exposed = True
|
|
|
|
def updateCloud(self):
|
|
|
|
lastfm.getSimilar()
|
|
raise cherrypy.HTTPRedirect("extras")
|
|
|
|
updateCloud.exposed = True
|
|
|
|
def api(self, *args, **kwargs):
|
|
|
|
from headphones.api import Api
|
|
|
|
a = Api()
|
|
|
|
a.checkParams(*args, **kwargs)
|
|
|
|
data = a.fetchData()
|
|
|
|
return data
|
|
|
|
api.exposed = True
|
|
|
|
def getInfo(self, ArtistID=None, AlbumID=None):
|
|
|
|
from headphones import cache
|
|
info_dict = cache.getInfo(ArtistID, AlbumID)
|
|
|
|
return simplejson.dumps(info_dict)
|
|
|
|
getInfo.exposed = True
|
|
|
|
def getArtwork(self, ArtistID=None, AlbumID=None):
|
|
|
|
from headphones import cache
|
|
return cache.getArtwork(ArtistID, AlbumID)
|
|
|
|
getArtwork.exposed = True
|
|
|
|
def getThumb(self, ArtistID=None, AlbumID=None):
|
|
|
|
from headphones import cache
|
|
return cache.getThumb(ArtistID, AlbumID)
|
|
|
|
getThumb.exposed = True
|
|
|
|
# If you just want to get the last.fm image links for an album, make sure to pass a releaseid and not a releasegroupid
|
|
def getImageLinks(self, ArtistID=None, AlbumID=None):
|
|
|
|
from headphones import cache
|
|
image_dict = cache.getImageLinks(ArtistID, AlbumID)
|
|
|
|
return simplejson.dumps(image_dict)
|
|
|
|
getImageLinks.exposed = True
|
|
|
|
class Artwork(object):
|
|
def index(self):
|
|
return "Artwork"
|
|
index.exposed = True
|
|
|
|
def default(self,ArtistOrAlbum="",ID=None):
|
|
from headphones import cache
|
|
ArtistID = None
|
|
AlbumID = None
|
|
if ArtistOrAlbum == "artist":
|
|
ArtistID = ID
|
|
elif ArtistOrAlbum == "album":
|
|
AlbumID = ID
|
|
|
|
relpath = cache.getArtwork(ArtistID,AlbumID)
|
|
|
|
if not relpath:
|
|
relpath = "data/interfaces/default/images/no-cover-art.png"
|
|
basedir = os.path.dirname(sys.argv[0])
|
|
path = os.path.join(basedir,relpath)
|
|
cherrypy.response.headers['Content-type'] = 'image/png'
|
|
cherrypy.response.headers['Cache-Control'] = 'no-cache'
|
|
else:
|
|
relpath = relpath.replace('cache/','',1)
|
|
path = os.path.join(headphones.CACHE_DIR,relpath)
|
|
fileext = os.path.splitext(relpath)[1][1::]
|
|
cherrypy.response.headers['Content-type'] = 'image/' + fileext
|
|
cherrypy.response.headers['Cache-Control'] = 'max-age=31556926'
|
|
|
|
path = os.path.normpath(path)
|
|
f = open(path,'rb')
|
|
return f.read()
|
|
default.exposed = True
|
|
|
|
class Thumbs(object):
|
|
def index(self):
|
|
return "Here be thumbs"
|
|
index.exposed = True
|
|
def default(self,ArtistOrAlbum="",ID=None):
|
|
from headphones import cache
|
|
ArtistID = None
|
|
AlbumID = None
|
|
if ArtistOrAlbum == "artist":
|
|
ArtistID = ID
|
|
elif ArtistOrAlbum == "album":
|
|
AlbumID = ID
|
|
|
|
relpath = cache.getThumb(ArtistID,AlbumID)
|
|
|
|
if not relpath:
|
|
relpath = "data/interfaces/default/images/no-cover-artist.png"
|
|
basedir = os.path.dirname(sys.argv[0])
|
|
path = os.path.join(basedir,relpath)
|
|
cherrypy.response.headers['Content-type'] = 'image/png'
|
|
cherrypy.response.headers['Cache-Control'] = 'no-cache'
|
|
else:
|
|
relpath = relpath.replace('cache/','',1)
|
|
path = os.path.join(headphones.CACHE_DIR,relpath)
|
|
fileext = os.path.splitext(relpath)[1][1::]
|
|
cherrypy.response.headers['Content-type'] = 'image/' + fileext
|
|
cherrypy.response.headers['Cache-Control'] = 'max-age=31556926'
|
|
|
|
path = os.path.normpath(path)
|
|
f = open(path,'rb')
|
|
return f.read()
|
|
default.exposed = True
|
|
|
|
thumbs = Thumbs()
|
|
|
|
|
|
WebInterface.artwork = Artwork()
|