mirror of
https://github.com/rembo10/headphones.git
synced 2026-07-03 15:54:01 +01:00
Added descriptions from last fm, formatted album page, added retry buttons
This commit is contained in:
+32
-7
@@ -102,15 +102,15 @@ a.blue {
|
||||
|
||||
container { }
|
||||
|
||||
body { background-color: #EBF4FB; min-width: 907px; }
|
||||
body { background-color: #EBF4FB; min-width: 930px; }
|
||||
|
||||
header { min-height: 68px; width: 100%; min-width: 907px; padding-left: 0px; padding-right: 10px; background-color: #CDC9C9; position: fixed; z-index: 998; }
|
||||
header { min-height: 68px; width: 100%; min-width: 930px; padding-left: 0px; padding-right: 10px; background-color: #CDC9C9; position: fixed; z-index: 998; }
|
||||
|
||||
h1 { font-size: 24px; }
|
||||
h2 { font-size: 20px; }
|
||||
h3 { font-size: 16px; }
|
||||
|
||||
p.indented { margin-left: 20px; font-size: 14px; }
|
||||
p.indented { padding-top: 20px; margin-left: 20px; font-size: 14px; }
|
||||
|
||||
div#updatebar { text-align: center; min-width: 970px; width: 100%; background-color: light-blue; float: left; }
|
||||
div#logo { float: left; padding-left: 10px; }
|
||||
@@ -120,7 +120,7 @@ ul#nav li { margin: 40px 0px auto 10px; display: inline; }
|
||||
ul#nav li a { padding: 5px; font-size: 16px; font-weight: bold; color: #330000; text-decoration: none; }
|
||||
ul#nav li a:hover { background-color: #a3e532; }
|
||||
|
||||
div#subhead_container { height: 30px; width:100%; min-width: 907px; background-color:#330000; float: left; list-style-type: none; z-index: 998; overflow: hidden; }
|
||||
div#subhead_container { height: 30px; width:100%; min-width: 930px; background-color:#330000; float: left; list-style-type: none; z-index: 998; overflow: hidden; }
|
||||
ul#subhead_menu { margin-top: 5px; }
|
||||
ul#subhead_menu li { width: 100%; height: 100%; display: inline; }
|
||||
ul#subhead_menu li a { padding: 5px 15px 10px 15px; vertical-align: middle; color: white; font-size: 16px; text-decoration: none; }
|
||||
@@ -131,6 +131,9 @@ div#searchbar { margin: 24px 30px auto auto; float: right; }
|
||||
div#main { margin: 0; padding: 80px 0 0 0; }
|
||||
|
||||
.table_wrapper { border-radius: 20px; -webkit-border-radius: 20px; -moz-border-radius: 20px; width: 88%; margin: 20px auto 0 auto; padding: 25px; background-color: white; position: relative; min-height: 200px; clear: both; _height: 302px; zoom: 1; }
|
||||
.manage_wrapper { width: 88%; margin: 20px auto 0 auto; padding: 25px; min-height: 150px; clear: both; _height: 302px; zoom: 1; }
|
||||
.table_wrapper_left { padding: 25px; background-color: #ffffff; float: left; width: 40%; height: 200px; margin-top: 25px; margin-left: 30px; margin-right: auto; -moz-border-radius: 20px; border-radius: 20px; }
|
||||
.table_wrapper_right{ padding: 25px; background-color: #ffffff; width: 40%; height: 200px; margin-top: 25px; margin-left: auto; margin-right: 30px; -moz-border-radius: 20px; border-radius: 20px; }
|
||||
|
||||
table#artist_table { background-color: white; width: 100%; padding: 20px; }
|
||||
|
||||
@@ -144,6 +147,7 @@ table#artist_table td#album { vertical-align: middle; text-align: left; min-widt
|
||||
table#artist_table td#have { vertical-align: middle; }
|
||||
|
||||
div#paddingheader { padding-top: 48px; font-size: 24px; font-weight: bold; text-align: center; }
|
||||
div#nopaddingheader { font-size: 24px; font-weight: bold; text-align: center; }
|
||||
table#album_table { background-color: white; }
|
||||
|
||||
table#album_table th#select { vertical-align: middle; text-align: left; min-width: 25px; }
|
||||
@@ -161,15 +165,15 @@ table#album_table td#type { vertical-align: middle; text-align: center; }
|
||||
table#album_table td#have { vertical-align: middle; }
|
||||
|
||||
img.albumArt { float: left; padding-right: 5px; }
|
||||
div#albumheader { height: 200px; }
|
||||
div#albumheader { padding-top: 48px; height: 200px; }
|
||||
div#track_wrapper { padding-top: 20px; text-align: center; font-size: 16px; }
|
||||
|
||||
table#track_table th#number { text-align: left; min-width: 50px; }
|
||||
table#track_table th#number { text-align: right; min-width: 20px; }
|
||||
table#track_table th#name { text-align: center; min-width: 350px; }
|
||||
table#track_table th#duration { width: 175px; text-align: center; min-width: 100px; }
|
||||
table#track_table th#have { width: 175px; text-align: center; min-width: 100px; }
|
||||
|
||||
table#track_table td#number { vertical-align: middle; text-align: left; }
|
||||
table#track_table td#number { vertical-align: middle; text-align: right; }
|
||||
table#track_table td#name { vertical-align: middle; text-align: center; }
|
||||
table#track_table td#duration { vertical-align: middle; text-align: center; }
|
||||
table#track_table td#have { vertical-align: middle; text-align: center; }
|
||||
@@ -182,6 +186,27 @@ table#log_table th#timestamp { text-align: left; min-width: 165px; }
|
||||
table#log_table th#level { text-align: left; min-width: 75px; }
|
||||
table#log_table th#message { text-align: left; min-width: 200px; }
|
||||
|
||||
table#upcoming_table th#albumart { text-align: center; min-width: 50px; }
|
||||
table#upcoming_table th#albumname { text-align: center; min-width: 200px; }
|
||||
table#upcoming_table th#artistname { text-align: center; min-width: 150px; }
|
||||
table#upcoming_table th#reldate { text-align: center; min-width: 100px; }
|
||||
table#upcoming_table th#type { text-align: center; min-width: 75px; }
|
||||
|
||||
table#upcoming_table td#albumart { vertical-align: middle; text-align: center; min-width: 50px; }
|
||||
table#upcoming_table td#albumname { vertical-align: middle; text-align: center; min-width: 200px; }
|
||||
table#upcoming_table td#artistname { vertical-align: middle; text-align: center; min-width: 150px; }
|
||||
table#upcoming_table td#reldate { vertical-align: middle; text-align: center; min-width: 100px; }
|
||||
table#upcoming_table td#type { vertical-align: middle; text-align: center; min-width: 75px; }
|
||||
table#upcoming_table td#status { vertical-align: middle; text-align: center; }
|
||||
|
||||
table#searchresults_table th#albumname { text-align: left; min-width: 225px; }
|
||||
table#searchresults_table th#artistname { text-align: center; min-width: 325px; }
|
||||
table#searchresults_table th#score { text-align: center; min-width: 75px; }
|
||||
|
||||
table#searchresults_table td#albumname { vertical-align: middle; text-align: left; min-width: 200px; }
|
||||
table#searchresults_table td#artistname { vertical-align: middle; text-align: left; min-width: 300px; }
|
||||
table#searchresults_table td#score { vertical-align: middle; text-align: center; min-width: 75px; }
|
||||
|
||||
div.progress-container { border: 1px solid #ccc; width: 100px; height: 14px; margin: 2px 5px 2px 0; padding: 1px; float: left; background: white; }
|
||||
div.progress-container > div { background-color: #a3e532; height: 14px; }
|
||||
.havetracks { font-size: 13px; margin-left: 36px; padding-bottom: 3px; vertical-align: middle; }
|
||||
|
||||
@@ -7,26 +7,36 @@
|
||||
<%def name="headerIncludes()">
|
||||
<div id="subhead_container">
|
||||
<ul id="subhead_menu">
|
||||
<li><a href="refreshArtist?ArtistID=${album['ArtistID']}">Mark Album as Wanted</a></li>
|
||||
<li><a href="deleteArtist?ArtistID=${album['ArtistID']}">Delete Artist</a></li>
|
||||
%if album['Status'] == 'Paused':
|
||||
<li><a href="resumeArtist?ArtistID=${album['ArtistID']}">Resume Artist</a></li>
|
||||
%if album['Status'] == 'Skipped':
|
||||
<li><a href="queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&new=False">Mark Album as Wanted</a></li>
|
||||
%elif album['Status'] == 'Snatched' or 'Downloaded':
|
||||
<li><a href="queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&new=False">Retry Download</a></li>
|
||||
<li><a href="queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&new=True">Try New Version</a></li>
|
||||
%else:
|
||||
<li><a href="pauseArtist?ArtistID=${album['ArtistID']}">Pause Artist</a></li>
|
||||
%endif
|
||||
<li><a href="getExtras?ArtistID=${album['ArtistID']}">Get Extras</a></li>
|
||||
<li><a href="unqueueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&new=False">Mark Album as Skipped</a></li>
|
||||
%endif
|
||||
</ul>
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
<%def name="body()">
|
||||
<div class="table_wrapper">
|
||||
<h2><a href="artistPage?ArtistID=${album['ArtistID']}"><- Back to ${album['ArtistName']}</a></h2>
|
||||
<div id="albumheader">
|
||||
<img src="http://ec1.images-amazon.com/images/P/${album['AlbumASIN']}.01.LZZZZZZZ.jpg" height="200" width="200" alt="albumart" class="albumArt">
|
||||
<h1>${album['AlbumTitle']}</h1>
|
||||
<h2>${album['ArtistName']}</h2>
|
||||
<br>
|
||||
<%
|
||||
totalduration = myDB.action("SELECT SUM(TrackDuration) FROM tracks WHERE AlbumID=?", [album['AlbumID']]).fetchone()[0]
|
||||
totaltracks = len(myDB.select("SELECT TrackTitle from tracks WHERE AlbumID=?", [album['AlbumID']]))
|
||||
%>
|
||||
<h3>Tracks: ${totaltracks}</h3>
|
||||
<h3>Duration: ${helpers.convert_milliseconds(totalduration)}</h3>
|
||||
%if description:
|
||||
<h3>Description: </h3>
|
||||
${description['Summary']}
|
||||
%endif
|
||||
</div>
|
||||
<div id="track_wrapper">
|
||||
<table class="display" id="track_table">
|
||||
@@ -35,14 +45,18 @@
|
||||
<th id="number">#</th>
|
||||
<th id="name">Track Title</th>
|
||||
<th id="duration">Duration</th>
|
||||
<th id="have">Have</th>
|
||||
<th id="have"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%
|
||||
i = 0
|
||||
%>
|
||||
%for track in tracks:
|
||||
<%
|
||||
trackmatch = 'asd'
|
||||
if len(trackmatch):
|
||||
i += 1
|
||||
have = myDB.select('SELECT TrackTitle from have WHERE ArtistName like ? AND AlbumTitle like ? AND TrackTitle like ?', [album['ArtistName'], album['AlbumTitle'], track['TrackTitle']])
|
||||
if len(have):
|
||||
grade = 'A'
|
||||
check = '<img src="images/checkmark.png" alt="checkmark">'
|
||||
else:
|
||||
@@ -50,9 +64,9 @@
|
||||
check = ''
|
||||
%>
|
||||
<tr class="grade${grade}">
|
||||
<td id="number">#</td>
|
||||
<td id="number">${i}</td>
|
||||
<td id="name">${track['TrackTitle']}</td>
|
||||
<td id="duration">${track['TrackDuration']}</td>
|
||||
<td id="duration">${helpers.convert_milliseconds(track['TrackDuration'])}</td>
|
||||
<td id="have">${check}</td>
|
||||
</tr>
|
||||
%endfor
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<p class="indented">Mark selected albums as
|
||||
<select name="action">
|
||||
<option value="Wanted">Wanted</option>
|
||||
<option value="WantedNew">Wanted (new only)</option>
|
||||
<option value="Skipped">Skipped</option>
|
||||
<option value="Downloaded">Downloaded</option>
|
||||
</select>
|
||||
@@ -74,7 +75,15 @@
|
||||
<td id="albumname"><a href="albumPage?AlbumID=${album['AlbumID']}">${album['AlbumTitle']}</a></td>
|
||||
<td id="reldate">${album['ReleaseDate']}</td>
|
||||
<td id="type">${album['Type']}</td>
|
||||
<td id="status">${album['Status']}</td>
|
||||
<td id="status">${album['Status']}
|
||||
%if album['Status'] == 'Skipped':
|
||||
[<a href="queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}">want</a>]
|
||||
%elif album['Status'] == 'Wanted':
|
||||
[<a href="unqueueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}">skip</a>]
|
||||
%else:
|
||||
[<a href="queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}" title="Retry the same download again">retry</a>][<a href="queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&new=True" title="Try a new download, skipping all previously tried nzbs">new</a>]
|
||||
%endif
|
||||
</td>
|
||||
<td id="have"><span title="${percent}"><span><div class="progress-container"><div style="width:${percent}%"><div class="havetracks">${havetracks}/${totaltracks}</div></div></div></td>
|
||||
</tr>
|
||||
%endfor
|
||||
@@ -110,7 +119,7 @@
|
||||
"sInfoEmpty":"Showing 0 to 0 of 0 albums",
|
||||
"sInfoFiltered":"(filtered from _MAX_ total albums)"},
|
||||
"bPaginate": false,
|
||||
"aaSorting": [[3, 'asc'],[2,'desc']]
|
||||
"aaSorting": [[4, 'asc'],[3,'desc']]
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<li><a href="config">settings</a></li>
|
||||
</ul>
|
||||
<div id="searchbar">
|
||||
<form action="findArtist" method="get">
|
||||
<form action="search" method="get">
|
||||
<input type="text" value="" onfocus="if(this.value==this.defaultValue) this.value='';" name="name" />
|
||||
<select name="type">
|
||||
<option value="artist">Artist</option>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<%inherit file="base.html"/>
|
||||
<form action="configUpdate" method="post">
|
||||
<div id="config">
|
||||
<div class="table_wrapper">
|
||||
<h1>Web Interface</h1>
|
||||
<table>
|
||||
@@ -216,5 +217,4 @@
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<%inherit file="base.html" />
|
||||
@@ -1,4 +1,7 @@
|
||||
<%inherit file="base.html"/>
|
||||
<%!
|
||||
from headphones import helpers
|
||||
%>
|
||||
|
||||
<%def name="headerIncludes()">
|
||||
<div id="subhead_container">
|
||||
@@ -22,6 +25,7 @@
|
||||
<th id="filename">File Name</th>
|
||||
<th id="size">Size</th>
|
||||
<th id="status">Status</th>
|
||||
<th id="action"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -39,8 +43,9 @@
|
||||
<tr class="grade${grade}">
|
||||
<td id="dateadded">${item['DateAdded']}</td>
|
||||
<td id="filename"><a href="${item['URL']}">${item['Title']}</a></td>
|
||||
<td id="size">${item['Size']}</td>
|
||||
<td id="size">${helpers.bytes_to_mb(item['Size'])}</td>
|
||||
<td id="status">${item['Status']}</td>
|
||||
<td id="action">[<a href="queueAlbum?AlbumID=${item['AlbumID']}&redirect=history">retry</a>][<a href="queueAlbum?AlbumID=${item['AlbumID']}&new=True&redirect=history">new</a>]</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</tbody>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<%inherit file="base.html" />
|
||||
<%!
|
||||
import headphones
|
||||
%>
|
||||
|
||||
<%def name="body()">
|
||||
<div class="table_wrapper">
|
||||
<h1>Scan Music Library</h1><br />
|
||||
@@ -10,24 +14,44 @@
|
||||
as soon as you click 'Submit'
|
||||
<br /><br />
|
||||
<form action="musicScan" method="GET" align="center">
|
||||
%if headphones.MUSIC_DIR:
|
||||
<input type="text" value="${headphones.MUSIC_DIR}" name="path" size="70" />
|
||||
%else:
|
||||
<input type="text" value="Enter a Music Directory to scan" onfocus="if
|
||||
(this.value==this.defaultValue) this.value='';" name="path" size="70" />
|
||||
%endif
|
||||
<input type="submit" /></form>
|
||||
</div>
|
||||
<div class="table_wrapper">
|
||||
|
||||
<div class="table_wrapper_left">
|
||||
<h1>Import Last.FM Artists</h1><br />
|
||||
Enter the username whose artists you want to import:<br /><br />
|
||||
<form action="importLastFM" method="GET" align="center">
|
||||
<input type="text" value="%s" onfocus="if
|
||||
<%
|
||||
if headphones.LASTFM_USERNAME:
|
||||
lastfmvalue = headphones.LASTFM_USERNAME
|
||||
else:
|
||||
lastfmvalue = 'Last.fm Username'
|
||||
%>
|
||||
<input type="text" value="${lastfmvalue}" onfocus="if
|
||||
(this.value==this.defaultValue) this.value='';" name="username" size="18" />
|
||||
<input type="submit" /></form><br /><br /></div></div>
|
||||
<div class="tableright"><div class="config"><h1>Placeholder :-)</h1><br />
|
||||
<input type="submit" /></form><br /><br />
|
||||
</div>
|
||||
|
||||
<div class="table_wrapper_right">
|
||||
<h1>Placeholder :-)</h1><br />
|
||||
<br /><br />
|
||||
<form action="" method="GET" align="center">
|
||||
<input type="text" value="" onfocus="if
|
||||
(this.value==this.defaultValue) this.value='';" name="" size="18" />
|
||||
<input type="submit" /></form><br /><br /></div></div><br />
|
||||
<div class="table"><div class="config"><h1>Force Search</h1><br />
|
||||
<input type="submit" /></form><br /><br />
|
||||
</div>
|
||||
|
||||
<div class="table_wrapper">
|
||||
<h1>Force Search</h1><br />
|
||||
<a href="forceSearch">Force Check for Wanted Albums</a><br /><br />
|
||||
<a href="forceUpdate">Force Update Active Artists</a><br /><br />
|
||||
<a href="forcePostProcess">Force Post-Process Albums in Download Folder</a><br /><br /><br />
|
||||
<a href="checkGithub">Check for Headphones Updates</a><br /><br /><br /></div></div>''' % (music_dir_input, lastfm_user_text))
|
||||
<a href="checkGithub">Check for Headphones Updates</a><br /><br /><br />
|
||||
</div>
|
||||
</%def>
|
||||
@@ -0,0 +1,70 @@
|
||||
<%inherit file="base.html" />
|
||||
|
||||
<%def name="body()">
|
||||
|
||||
<div id="paddingheader">
|
||||
<h1>Search Results<h1>
|
||||
</div>
|
||||
<table class="display" id="searchresults_table">
|
||||
<thead>
|
||||
<tr>
|
||||
%if type == 'album':
|
||||
<th id="albumname">Album Name</th>
|
||||
%endif
|
||||
<th id="artistname">Artist Name</th>
|
||||
<th id="score">Score</th>
|
||||
<th id="add"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
%if searchresults:
|
||||
%for result in searchresults:
|
||||
<%
|
||||
if result['score'] == 100:
|
||||
grade = 'A'
|
||||
else:
|
||||
grade = 'Z'
|
||||
%>
|
||||
<tr class="grade${grade}">
|
||||
%if type == 'album':
|
||||
<td id="albumname"><a href="${result['albumurl']}">${result['title']}</a></td>
|
||||
%endif
|
||||
<td id="artistname"><a href="${result['url']}">${result['uniquename']}</a></td>
|
||||
<td id="score">${result['score']}</td>
|
||||
%if type == 'album':
|
||||
<td id="add"><a href="addReleaseById?rid=${result['albumid']}">Add this album</a></td>
|
||||
%else:
|
||||
<td id="add"><a href="addArtist?artistid=${result['id']}">Add this artist</a></td>
|
||||
%endif
|
||||
</tr>
|
||||
%endfor
|
||||
%endif
|
||||
</tbody>
|
||||
</table>
|
||||
</%def>
|
||||
|
||||
<%def name="headIncludes()">
|
||||
<link rel="stylesheet" href="css/data_table.css">
|
||||
</%def>
|
||||
|
||||
<%def name="javascriptIncludes()">
|
||||
<script src="js/libs/jquery.dataTables.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function()
|
||||
{
|
||||
$('#searchresults_table').dataTable(
|
||||
{
|
||||
"oLanguage": {
|
||||
"sLengthMenu":"Show _MENU_ results per page",
|
||||
"sEmptyTable": "No results",
|
||||
"sInfo":"Showing _TOTAL_ results",
|
||||
"sInfoEmpty":"Showing 0 to 0 of 0 results",
|
||||
"sInfoFiltered":"(filtered from _MAX_ total results)"},
|
||||
"bPaginate": false,
|
||||
"bFilter": false,
|
||||
"aaSorting": []
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</%def>
|
||||
@@ -6,6 +6,6 @@
|
||||
|
||||
<%def name="body()">
|
||||
<div class="table_wrapper">
|
||||
Headphones is ${message}
|
||||
<h1>Headphones is ${message}</h1>
|
||||
</div>
|
||||
</%def>
|
||||
@@ -9,7 +9,7 @@
|
||||
<th id="artistname">Artist</th>
|
||||
<th id="albumname">Album Name</th>
|
||||
<th id="reldate">Release Date</th>
|
||||
<th id="type">Release Type</th>
|
||||
<th id="type">Type</th>
|
||||
<th id="status">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -26,30 +26,38 @@
|
||||
%endfor
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<form action="markAlbums" method="get">
|
||||
<p class="indented">Mark selected albums as
|
||||
<select name="action">
|
||||
<option value="Skipped">Skipped</option>
|
||||
<option value="Downloaded">Downloaded</option>
|
||||
</select>
|
||||
<input type="submit" value="Go">
|
||||
</p>
|
||||
<div class="table_wrapper">
|
||||
<h1>Wanted Albums</h1>
|
||||
<table class="display" id="upcoming_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="select"><input type="checkbox" onClick="toggle(this)" /></th>
|
||||
<th id="albumart"></th>
|
||||
<th id="artistname">Artist</th>
|
||||
<th id="albumname">Album Name</th>
|
||||
<th id="reldate">Release Date</th>
|
||||
<th id="type">Release Type</th>
|
||||
<th id="status">Status</th>
|
||||
<th id="type">Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
%for album in wanted:
|
||||
<tr class="gradeZ">
|
||||
<td id="select"><input type="checkbox" name="${album['AlbumID']}" class="checkbox" /></th>
|
||||
<td id="albumart"><img src="http://ec1.images-amazon.com/images/P/${album['AlbumASIN']}.01.MZZZZZZZ.jpg" height="50" width="50"></td>
|
||||
<td id="artistname">${album['ArtistName']}</td>
|
||||
<td id="albumname"><a href="albumPage?AlbumID=${album['AlbumID']}">${album['AlbumTitle']}</a></td>
|
||||
<td id="reldate">${album['ReleaseDate']}</td>
|
||||
<td id="type">${album['Type']}</td>
|
||||
<td id="status">${album['Status']}</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</tbody>
|
||||
|
||||
@@ -429,6 +429,7 @@ def dbcheck():
|
||||
c.execute('CREATE TABLE IF NOT EXISTS snatched (AlbumID TEXT, Title TEXT, Size INTEGER, URL TEXT, DateAdded TEXT, Status TEXT, FolderName TEXT)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS have (ArtistName TEXT, AlbumTitle TEXT, TrackNumber TEXT, TrackTitle TEXT, TrackLength TEXT, BitRate TEXT, Genre TEXT, Date TEXT, TrackID TEXT)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS lastfmcloud (ArtistName TEXT, ArtistID TEXT, Count INTEGER)')
|
||||
c.execute('CREATE TABLE IF NOT EXISTS descriptions (ReleaseGroupID TEXT, ReleaseID TEXT, Summary TEXT, Content TEXT)')
|
||||
|
||||
try:
|
||||
c.execute('SELECT IncludeExtras from artists')
|
||||
|
||||
@@ -215,6 +215,8 @@ def addArtisttoDB(artistid, extrasonly=False):
|
||||
|
||||
myDB.upsert("albums", newValueDict, controlValueDict)
|
||||
|
||||
lastfm.getAlbumDescription(rg['id'], release_dict['releaselist'])
|
||||
|
||||
# I changed the albumid from releaseid -> rgid, so might need to delete albums that have a releaseid
|
||||
for release in release_dict['releaselist']:
|
||||
myDB.action('DELETE from albums WHERE AlbumID=?', [release['releaseid']])
|
||||
|
||||
+44
-1
@@ -4,7 +4,7 @@ from collections import defaultdict
|
||||
import random
|
||||
|
||||
import headphones
|
||||
from headphones import db
|
||||
from headphones import db, logger
|
||||
|
||||
api_key = '395e6ec6bb557382fc41fde867bce66f'
|
||||
|
||||
@@ -91,4 +91,47 @@ def getArtists():
|
||||
for artistid in artistlist:
|
||||
importer.addArtisttoDB(artistid)
|
||||
|
||||
def getAlbumDescription(rgid, releaselist):
|
||||
|
||||
myDB = db.DBConnection()
|
||||
result = myDB.select('SELECT Summary from descriptions WHERE ReleaseGroupID=?', [rgid])
|
||||
|
||||
if result:
|
||||
return
|
||||
|
||||
for release in releaselist:
|
||||
|
||||
mbid = release['releaseid']
|
||||
url = 'http://ws.audioscrobbler.com/2.0/?method=album.getInfo&mbid=%s&api_key=%s' % (mbid, api_key)
|
||||
logger.info('Checking last.fm for: ' + mbid)
|
||||
data = urllib.urlopen(url).read()
|
||||
|
||||
if data == 'Album not found':
|
||||
logger.info('Release id not on last fm, skipping')
|
||||
continue
|
||||
|
||||
try:
|
||||
d = minidom.parseString(data)
|
||||
|
||||
albuminfo = d.getElementsByTagName("album")
|
||||
|
||||
for item in albuminfo:
|
||||
summarynode = item.getElementsByTagName("summary")[0].childNodes
|
||||
contentnode = item.getElementsByTagName("content")[0].childNodes
|
||||
for node in summarynode:
|
||||
summary = node.data
|
||||
for node in contentnode:
|
||||
content = node.data
|
||||
|
||||
controlValueDict = {'ReleaseGroupID': rgid}
|
||||
newValueDict = {'ReleaseID': mbid,
|
||||
'Summary': summary,
|
||||
'Content': content}
|
||||
myDB.upsert("descriptions", newValueDict, controlValueDict)
|
||||
logger.info('Inserted description')
|
||||
break
|
||||
|
||||
except:
|
||||
continue
|
||||
|
||||
|
||||
@@ -66,6 +66,47 @@ def findArtist(name, limit=1):
|
||||
})
|
||||
|
||||
return artistlist
|
||||
|
||||
def findRelease(name, limit=1):
|
||||
|
||||
with mb_lock:
|
||||
|
||||
releaselist = []
|
||||
attempt = 0
|
||||
releaseResults = None
|
||||
|
||||
chars = set('!?')
|
||||
if any((c in chars) for c in name):
|
||||
name = '"'+name+'"'
|
||||
|
||||
while attempt < 5:
|
||||
|
||||
try:
|
||||
releaseResults = q.getReleases(ws.ReleaseFilter(query=name, limit=limit))
|
||||
break
|
||||
except WebServiceError, e:
|
||||
logger.warn('Attempt to query MusicBrainz for %s failed: %s' % (name, e))
|
||||
attempt += 1
|
||||
time.sleep(5)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
if not releaseResults:
|
||||
return False
|
||||
|
||||
for result in releaseResults:
|
||||
|
||||
releaselist.append({
|
||||
'uniquename': result.release.artist.name,
|
||||
'title': result.release.title,
|
||||
'id': u.extractUuid(result.release.artist.id),
|
||||
'albumid': u.extractUuid(result.release.id),
|
||||
'url': result.release.artist.id,
|
||||
'albumurl': result.release.id,
|
||||
'score': result.score
|
||||
})
|
||||
|
||||
return releaselist
|
||||
|
||||
def getArtist(artistid, extrasonly=False):
|
||||
|
||||
|
||||
+26
-54
@@ -10,7 +10,7 @@ import threading
|
||||
|
||||
import headphones
|
||||
|
||||
from headphones import logger, searcher, db, importer, lastfm
|
||||
from headphones import logger, searcher, db, importer, mb, lastfm
|
||||
from headphones.helpers import checked, radio
|
||||
|
||||
|
||||
@@ -50,140 +50,112 @@ class WebInterface(object):
|
||||
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)
|
||||
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=10)
|
||||
searchresults = mb.findArtist(name, limit=20)
|
||||
else:
|
||||
searchresults = mb.findRelease(name, limit=10)
|
||||
|
||||
findArtist.exposed = True
|
||||
|
||||
def artistInfo(self, artistid):
|
||||
page = [templates._header]
|
||||
page.append(templates._logobar)
|
||||
page.append(templates._nav)
|
||||
artist = mb.getArtist(artistid)
|
||||
if artist['artist_begindate']:
|
||||
begindate = artist['artist_begindate']
|
||||
else:
|
||||
begindate = ''
|
||||
if artist['artist_enddate']:
|
||||
enddate = artist['artist_enddate']
|
||||
else:
|
||||
enddate = ''
|
||||
page.append('''<div class="table"><p class="center">Artist Information:</p>''')
|
||||
page.append('''<p class="mediumtext">Artist Name: %s (%s)</br> ''' % (artist['artist_name'], artist['artist_type']))
|
||||
page.append('''<p class="mediumtext">Years Active: %s - %s <br /><br />''' % (begindate, enddate))
|
||||
page.append('''MusicBrainz Link: <a class="external" href="http://www.musicbrainz.org/artist/%s">http://www.musicbrainz.org/artist/%s</a></br></br><b>Albums:</b><br />''' % (artistid, artistid))
|
||||
for rg in artist['releasegroups']:
|
||||
page.append('''%s <br />''' % rg['title'])
|
||||
page.append('''<div class="center"><a href="addArtist?artistid=%s">Add this artist!</a></div>''' % artistid)
|
||||
return page
|
||||
|
||||
artistInfo.exposed = True
|
||||
searchresults = mb.findRelease(name, limit=20)
|
||||
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()
|
||||
time.sleep(5)
|
||||
threading.Thread(target=lastfm.getSimilar).start()
|
||||
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % artistid)
|
||||
|
||||
addArtist.exposed = True
|
||||
|
||||
def getExtras(self, ArtistID):
|
||||
|
||||
myDB = db.DBConnection()
|
||||
controlValueDict = {'ArtistID': ArtistID}
|
||||
newValueDict = {'IncludeExtras': 1}
|
||||
myDB.upsert("artists", newValueDict, controlValueDict)
|
||||
|
||||
threading.Thread(target=importer.addArtisttoDB, args=[ArtistID, True]).start()
|
||||
time.sleep(10)
|
||||
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
||||
|
||||
getExtras.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("home")
|
||||
|
||||
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("home")
|
||||
|
||||
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])
|
||||
|
||||
raise cherrypy.HTTPRedirect("home")
|
||||
|
||||
deleteArtist.exposed = True
|
||||
|
||||
def refreshArtist(self, ArtistID):
|
||||
importer.addArtisttoDB(ArtistID)
|
||||
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
||||
refreshArtist.exposed=True
|
||||
|
||||
def markAlbums(self, ArtistID=None, action=None, **args):
|
||||
myDB = db.DBConnection()
|
||||
if action == 'WantedNew':
|
||||
newaction = 'Wanted'
|
||||
else:
|
||||
newaction = action
|
||||
for mbid in args:
|
||||
controlValueDict = {'AlbumID': mbid}
|
||||
newValueDict = {'Status': action}
|
||||
newValueDict = {'Status': newaction}
|
||||
myDB.upsert("albums", newValueDict, controlValueDict)
|
||||
if action == 'Wanted':
|
||||
searcher.searchNZB(mbid, new=False)
|
||||
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
||||
if action == 'WantedNew':
|
||||
searcher.searchNZB(mbid, new=True)
|
||||
if ArtistID:
|
||||
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
||||
else:
|
||||
raise cherrypy.HTTPRedirect("upcoming")
|
||||
markAlbums.exposed = True
|
||||
|
||||
|
||||
def queueAlbum(self, AlbumID, ArtistID, new=False):
|
||||
def queueAlbum(self, AlbumID, ArtistID=None, new=False, redirect=None):
|
||||
logger.info(u"Marking album: " + AlbumID + "as wanted...")
|
||||
myDB = db.DBConnection()
|
||||
controlValueDict = {'AlbumID': AlbumID}
|
||||
newValueDict = {'Status': 'Wanted'}
|
||||
myDB.upsert("albums", newValueDict, controlValueDict)
|
||||
searcher.searchNZB(AlbumID, new)
|
||||
raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)
|
||||
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 upcoming(self):
|
||||
|
||||
Reference in New Issue
Block a user