diff --git a/data/interfaces/default/_inc_footer.tmpl b/data/interfaces/default/_inc_footer.tmpl new file mode 100644 index 00000000..9bf2eafe --- /dev/null +++ b/data/interfaces/default/_inc_footer.tmpl @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/data/interfaces/default/_inc_header.tmpl b/data/interfaces/default/_inc_header.tmpl new file mode 100644 index 00000000..c28e76cd --- /dev/null +++ b/data/interfaces/default/_inc_header.tmpl @@ -0,0 +1,30 @@ +#attr title = "" +#attr rootPath = "" +#attr scripts = "" +#attr styles = "" + + + Headphones $title + + + + + +
+ + +
+
+
+
\ No newline at end of file diff --git a/data/interfaces/default/albumPage.tmpl b/data/interfaces/default/albumPage.tmpl new file mode 100644 index 00000000..66b9f4d1 --- /dev/null +++ b/data/interfaces/default/albumPage.tmpl @@ -0,0 +1,45 @@ +#attr $albumASIN = "" +#attr $albumTitle = "" +#attr $albumID = "" +#attr $artitstID = "" +#attr $artistName = "" +#import os.path +#import time +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_header.tmpl") + + + + + + + + + + + + #for $track in $tracks + + + + + + #end for +
+ #if $albumASIN: + +
+ #end if +
+ ${artistName} -${albumTitle}
+ Download
+
Track #Track TitleDuration
${track[7]} + ${track[3]}(link) + + #try + #echo time.strftime("%M:%S", time.gmtime(int($track[4])/1000)) + #except + n/a + #end try +
+ +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_footer.tmpl") \ No newline at end of file diff --git a/data/interfaces/default/artistInfo.tmpl b/data/interfaces/default/artistInfo.tmpl new file mode 100644 index 00000000..ae8480ae --- /dev/null +++ b/data/interfaces/default/artistInfo.tmpl @@ -0,0 +1,13 @@ +#attr $artistName = "" +#attr $artistUuid = "" +#attr $releaseGroups = [] +#import os.path +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_header.tmpl") + Artist Name: $artistName
+ Unique ID: $artistUuid
+
+ Albums:
+ #for $releaseGroup in $releaseGroups: + $releaseGroup
+ #end for +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_footer.tmpl") \ No newline at end of file diff --git a/data/interfaces/default/artistPage.tmpl b/data/interfaces/default/artistPage.tmpl new file mode 100644 index 00000000..76af1721 --- /dev/null +++ b/data/interfaces/default/artistPage.tmpl @@ -0,0 +1,39 @@ +#attr $artistName = "" +#attr $artistID = "" +#import os.path +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_header.tmpl") + + + + + + + + + + + #for $album in $albums + + + + + + + #end for +
+

$artistName

+
Album NameRelease DateStatus
+ + $album[0] + (link)$album[1] + #if $album[3] == 'Skipped': + $album[3][want] + #elif $album[3] == 'Wanted': + $album[3][skip] + #elif $album[3] == 'Downloaded' or $album[3] == 'Snatched': + $album[3][retry] + #else: + $album[3] + #end if +
+#include os.path.abspath($appPath+"/data/interfaces/default/_inc_footer.tmpl") \ No newline at end of file diff --git a/data/interfaces/default/config.tmpl b/data/interfaces/default/config.tmpl new file mode 100644 index 00000000..0697a50d --- /dev/null +++ b/data/interfaces/default/config.tmpl @@ -0,0 +1,238 @@ +#import os.path +#import config +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_header.tmpl") +
+ +
+
+
+

Web Interface

+ + + + + + + + + + + + + + + + +
+

+ HTTP Host:

+
+ i.e. localhost or 0.0.0.0 +

+
+

+ HTTP Username:

+ +

+
+

+ HTTP Port:

+ +

+
+

+ HTTP Password:

+ +

+
+

Launch Browser on Startup:

+
+ +

Download Settings

+ + + + + + + + + + + + + + + + + + + + + + + +
+

SABnzbd Host:


+ + usually localhost:8080 +
+

SABnzbd Username:

+
+
+ +

SABnzbd API:

+
+
+ +

SABnzbd Password:

+
+
+ +

SABnzbd Category:

+
+
+ +

Music Download Directory:


+ + Absolute or relative path to the dir where SAB downloads your music
+ i.e. Downloads/music or /Users/name/Downloads/music
+
+
+ +

Usenet Retention:

+
+ +

Search Providers

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+

NZBMatrix:

+
+

+ NZBMatrix Username:
+ +

+
+

+ NZBMatrix API:
+ +

+
+
+ +

Newznab:

+
+
+ +

+ Newznab Host:
+
+ i.e. http://nzb.su +

+
+
+ +

+ Newznab API:
+ +

+
+
+ +

NZBs.org:

+
+
+ +

+ NZBs.org UID:
+ +

+
+
+ +

+ NZBs.org Hash:
+ +

+
+ +

Quality & Post Processing

+ + + + + + + + + + + + + + + + +
+

Album Quality:

+ Include lossless
+ Convert lossless to mp3 +
+

+

iTunes:

+ Move downloads to iTunes +

+
+
+ +

Path to iTunes folder:
+
+ i.e. Music/iTunes or /Users/name/Music/iTunes +

+
+ Renaming & Metadata: +

+ Rename & add metadata +
+ Delete leftover files +

+
+
+

Album Art:

+ Add album art +
+ +


+ (For now, all changes require a restart to take effect)

+
+
+#include os.path.abspath($appPath+"/data/interfaces/default/_inc_footer.tmpl") \ No newline at end of file diff --git a/data/interfaces/default/history.tmpl b/data/interfaces/default/history.tmpl new file mode 100644 index 00000000..0c03e2bf --- /dev/null +++ b/data/interfaces/default/history.tmpl @@ -0,0 +1,3 @@ +#import os.path +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_header.tmpl") +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_footer.tmpl") \ No newline at end of file diff --git a/data/interfaces/default/index.tmpl b/data/interfaces/default/index.tmpl new file mode 100644 index 00000000..570c355a --- /dev/null +++ b/data/interfaces/default/index.tmpl @@ -0,0 +1,33 @@ +#import os.path +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_header.tmpl") + + + + + + + #for $artist in $artists + + + + + + #end for +
Artist NameStatusUpcoming Albums
+ $artist[0] + (link) + [delete] + + #if $artist[2] == 'Active': + $artist[2] (pause) + #else: + $artist[2](resume) + #end if + + #try + $artist[3] $artist[4] + #except + None + #end try +
+#include os.path.abspath($appPath+"/data/interfaces/default/_inc_footer.tmpl") \ No newline at end of file diff --git a/data/interfaces/default/manage.tmpl b/data/interfaces/default/manage.tmpl new file mode 100644 index 00000000..92da4055 --- /dev/null +++ b/data/interfaces/default/manage.tmpl @@ -0,0 +1,28 @@ +#attr $path = "" +#import os.path +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_header.tmpl") + +
+

Import or Sync Your iTunes Library/Music Folder

+

Enter the full path to your iTunes XML file or music folder + i.e. /Users/"username"/Music/iTunes/iTunes Music Library.xml + or /Users/"username"/Music/iTunes/iTunes Media/Music + (artists should have their own directories for folder import to work) + note: This process can take a LONG time! + Once you click "Submit" you can navigate away from this + page while the process runs.

+
+ + +
+
+
+ +
+ +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_footer.tmpl") \ No newline at end of file diff --git a/data/interfaces/default/search.tmpl b/data/interfaces/default/search.tmpl new file mode 100644 index 00000000..4ac94ebd --- /dev/null +++ b/data/interfaces/default/search.tmpl @@ -0,0 +1,31 @@ +#import os.path +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_header.tmpl") + +
+ Results: +
+

+#include os.path.abspath($appPath+"/data/interfaces/default/_inc_footer.tmpl") \ No newline at end of file diff --git a/data/interfaces/default/upcoming.tmpl b/data/interfaces/default/upcoming.tmpl new file mode 100644 index 00000000..0c03e2bf --- /dev/null +++ b/data/interfaces/default/upcoming.tmpl @@ -0,0 +1,3 @@ +#import os.path +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_header.tmpl") +#include os.path.abspath($appPath+"/data/interfaces/default/_inc_footer.tmpl") \ No newline at end of file diff --git a/headphones.py b/headphones.py index 0dc8a3c6..64d2ab32 100755 --- a/headphones.py +++ b/headphones.py @@ -106,8 +106,9 @@ def serverstart(): cherrypy.engine.subscribe('start', browser, priority=90) logger.log(u"Starting Headphones on port:" + settings['http_port']) - cherrypy.quickstart(webServer.Headphones(), config = conf) - + root = webServer.Headphones("data/interfaces/default/") + cherrypy.quickstart(root, config = conf) + if __name__ == '__main__': serverstart() diff --git a/webServer.py b/webServer.py index 9b581918..80e901a6 100644 --- a/webServer.py +++ b/webServer.py @@ -13,15 +13,22 @@ import sys import configobj from headphones import FULL_PATH, config_file import logger +from Cheetah.Template import Template database = os.path.join(FULL_PATH, 'headphones.db') class Headphones: + + def __init__(self,templatePath): + """docstring for __init__""" + self.templatePath = templatePath def index(self): - page = [templates._header] - page.append(templates._logobar) - page.append(templates._nav) + + filename = os.path.join(self.templatePath,"index.tmpl") + template = Template(file=filename) + template.rootPath = "." + template.appPath = "." #Display Database if it exists: if os.path.exists(database): #logger.log(u"Loading artists from the database...") @@ -30,129 +37,71 @@ class Headphones: c.execute('SELECT ArtistName, ArtistID, Status from artists order by ArtistSortName collate nocase') results = c.fetchall() i = 0 - page.append('''
- - - - - - ''') + template.artists = [] while i < len(results): c.execute('''SELECT AlbumTitle, ReleaseDate, DateAdded, AlbumID from albums WHERE ArtistID='%s' order by ReleaseDate DESC''' % results[i][1]) latestalbum = c.fetchall() today = datetime.date.today() - if len(latestalbum) > 0: - if latestalbum[0][1] > datetime.date.isoformat(today): - newalbumName = '%s' % (latestalbum[0][3], latestalbum[0][0]) - releaseDate = '(%s)' % latestalbum[0][1] - else: - newalbumName = 'None' - releaseDate = "" if len(latestalbum) == 0: - newalbumName = 'None' - releaseDate = "" - if results[i][2] == 'Paused': - newStatus = '''%s(resume)''' % (results[i][2], results[i][1]) - else: - newStatus = '''%s(pause)''' % (results[i][2], results[i][1]) - page.append(''' - - ''' % (results[i][1], results[i][0], results[i][1], results[i][1], newStatus, newalbumName, releaseDate)) + results[i][3] = 'None' + results[i][4] = "" + elif latestalbum[0][1] > datetime.date.isoformat(today): + results[i][3] = '%s' % (latestalbum[0][3], latestalbum[0][0]) + results[i][4] = '(%s)' % latestalbum[0][1] + + template.artists.append(results[i]) i = i+1 c.close() - page.append('''
Artist NameStatusUpcoming Albums
%s - (link) [delete]%s%s %s
''') - - else: - page.append("""
Add some artists to the database!
""") - page.append(templates._footer) - return page + return str(template) index.exposed = True - def artistPage(self, ArtistID): - page = [templates._header] - page.append(templates._logobar) - page.append(templates._nav) + filename = os.path.join(self.templatePath,"artistPage.tmpl") + template = Template(file=filename) + template.rootPath = "." + template.appPath = "." + template.artistID = ArtistID conn=sqlite3.connect(database) c=conn.cursor() c.execute('''SELECT ArtistName from artists WHERE ArtistID="%s"''' % ArtistID) artistname = c.fetchall() + template.artistName = artistname[0] c.execute('''SELECT AlbumTitle, ReleaseDate, AlbumID, Status, ArtistName, AlbumASIN from albums WHERE ArtistID="%s" order by ReleaseDate DESC''' % ArtistID) results = c.fetchall() c.close() i = 0 - page.append('''
-

%s

- - - - - - - ''' % (artistname[0])) + template.albums = [] while i < len(results): - if results[i][3] == 'Skipped': - newStatus = '''%s [want]''' % (results[i][3], results[i][2], ArtistID) - elif results[i][3] == 'Wanted': - newStatus = '''%s[skip]''' % (results[i][3], results[i][2], ArtistID) - elif results[i][3] == 'Downloaded': - newStatus = '''%s[retry]''' % (results[i][3], results[i][2], ArtistID) - elif results[i][3] == 'Snatched': - newStatus = '''%s[retry]''' % (results[i][3], results[i][2], ArtistID) - else: - newStatus = '%s' % (results[i][3]) - page.append(''' - - - ''' % (results[i][5], results[i][2], results[i][0], results[i][2], results[i][1], newStatus)) + template.albums.append(results[i]) i = i+1 - page.append('''
Album NameRelease DateStatus
%s - (link)%s%s
''') - page.append(templates._footer) - return page + return str(template) artistPage.exposed = True def albumPage(self, AlbumID): - page = [templates._header] - page.append(templates._logobar) - page.append(templates._nav) + filename = os.path.join(self.templatePath,"albumPage.tmpl") + template = Template(file=filename) + template.rootPath = "." + template.appPath = "." conn=sqlite3.connect(database) c=conn.cursor() c.execute('''SELECT ArtistID, ArtistName, AlbumTitle, TrackTitle, TrackDuration, TrackID, AlbumASIN from tracks WHERE AlbumID="%s"''' % AlbumID) results = c.fetchall() - if results[0][6]: - albumart = '''


''' % results[0][6] - else: - albumart = '' c.close() + template.albumASIN = results[0][6] + template.artistID = results[0][0] + template.artistName = results[0][1] + template.albumTitle = results[0][2] + template.tracks = [] i = 0 - page.append('''
- %s - %s
- Download
%s
-
- - - - - ''' % (results[0][0], results[0][1], results[0][2], AlbumID, results[0][0], albumart)) while i < len(results): - if results[i][4]: - duration = time.strftime("%M:%S", time.gmtime(int(results[i][4])/1000)) - else: - duration = 'n/a' - page.append(''' - - ''' % (i+1, results[i][3], results[i][5], duration)) + track = list(results[i]) + track.append(i+1) + template.tracks.append(track) i = i+1 - page.append('''
Track #Track TitleDuration
%s%s (link)%s
''') - - page.append(templates._footer) - return page - + return str(template) albumPage.exposed = True @@ -182,15 +131,17 @@ class Headphones: findArtist.exposed = True def artistInfo(self, artistid): - page = [templates._header] + + filename = os.path.join(self.templatePath,"artistInfo.tmpl") + template = Template(file=filename) + template.rootPath = "." + template.appPath = "." inc = ws.ArtistIncludes(releases=(m.Release.TYPE_OFFICIAL, m.Release.TYPE_ALBUM), releaseGroups=True) artist = ws.Query().getArtistById(artistid, inc) - page.append('''Artist Name: %s
''' % artist.name) - page.append('''Unique ID: %s

Albums:
''' % u.extractUuid(artist.id)) - for rg in artist.getReleaseGroups(): - page.append('''%s
''' % rg.title) - return page - + template.artistName = artist.name + template.artistUuid = artistid + template.releaseGroups = artist.getReleaseGroups() + return str(template) artistInfo.exposed = True def addArtist(self, artistid): @@ -308,38 +259,25 @@ class Headphones: unqueueAlbum.exposed = True def upcoming(self): - page = [templates._header] - page.append(templates._logobar) - page.append(templates._nav) - page.append(templates._footer) - return page + filename = os.path.join(self.templatePath,"upcoming.tmpl") + template = Template(file=filename) + template.rootPath = "." + template.appPath = "." + return str(template) upcoming.exposed = True def manage(self): + filename = os.path.join(self.templatePath,"manage.tmpl") + template = Template(file=filename) + template.rootPath = "." + template.appPath = "." config = configobj.ConfigObj(config_file) try: path = config['General']['path_to_xml'] except: path = 'Absolute path to iTunes XML or Top-Level Music Directory' - page = [templates._header] - page.append(templates._logobar) - page.append(templates._nav) - page.append('''

Import or Sync Your iTunes Library/Music Folder


- Enter the full path to your iTunes XML file or music folder

- i.e. /Users/"username"/Music/iTunes/iTunes Music Library.xml
- or /Users/"username"/Music/iTunes/iTunes Media/Music

(artists should have their own directories for folder import to work) -

note: This process can take a LONG time!

- Once you click "Submit" you can navigate away from this - page while the process runs.


-
- -


-
''' % path) - page.append(templates._footer) - return page + template.path = path + return str(template) manage.exposed = True def importItunes(self, path): @@ -365,21 +303,19 @@ class Headphones: def history(self): - page = [templates._header] - page.append(templates._logobar) - page.append(templates._nav) - page.append(templates._footer) - return page + filename = os.path.join(self.templatePath,"history.tmpl") + template = Template(file=filename) + template.rootPath = "." + template.appPath = "." + return str(template) history.exposed = True def config(self): - page = [templates._header] - page.append(templates._logobar) - page.append(templates._nav) - page.append(config.form) - page.append(templates._footer) - return page - + filename = os.path.join(self.templatePath,"config.tmpl") + template = Template(file=filename) + template.rootPath = "." + template.appPath = "." + return str(template) config.exposed = True @@ -445,4 +381,4 @@ class Headphones: python = sys.executable os.execl(python, python, * sys.argv) - restart.exposed = True \ No newline at end of file + restart.exposed = True