FIX: Mako Runtime error on startup (#227), IMP: Added Status filters on comic details page

This commit is contained in:
evilhero 2013-02-25 10:36:43 -05:00
parent ea6d704d67
commit 533076caff
7 changed files with 208 additions and 55 deletions

View File

@ -213,8 +213,16 @@
</table>
</div>
</div>
<div class="table_wrapper">
<div id="checkboxControls" style="float: right; vertical-align: middle; margin: 3px; margin-top: -1px;">
<div style="padding-bottom: 5px;">
<label for="Wanted" class="checkbox inline Wanted"><input type="checkbox" id="Wanted" checked="checked" /> Wanted: <b>${isCounts['Wanted']}</b></label>
<label for="Archived" class="checkbox inline Archived"><input type="checkbox" id="Archived" checked="checked" /> Archived: <b>${isCounts['Archived']}</b></label>
<label for="Downloaded" class="checkbox inline Downloaded"><input type="checkbox" id="Downloaded" checked="checked" /> Downloaded: <b>${isCounts['Downloaded']}</b></label>
<label for="Skipped" class="checkbox inline Skipped"><input type="checkbox" id="Skipped" checked="checked" /> Skipped: <b>${isCounts['Skipped']}</b></label>
</div>
</div>
<div class="table_wrapper">
<form action="markissues" method="get" id="markissues">
<div id="markissue">Mark selected issues as
<select name="action" onChange="doAjaxCall('markissues',$(this),'table',true);" data-success="selected issues marked">
@ -249,10 +257,15 @@
grade = 'X'
elif issue['Status'] == 'Snatched':
grade = 'C'
elif issue['Status'] == 'Downloaded':
grade = 'A'
elif issue['Status'] == 'Archived':
grade = 'A'
else:
grade = 'A'
%>
<tr class="grade${grade}">
<tr class="${issue['Status']} grade${grade}">
<td id="select"><input type="checkbox" name="${issue['IssueID']}" class="checkbox" value="${issue['IssueID']}"/></td>
<td id="issuenumber">${issue['Issue_Number']}</td>
<td id="issuename">${issue['IssueName']}</td>
@ -267,21 +280,6 @@
<a href="#" onclick="doAjaxCall('queueissue?ComicID=${issue['ComicID']}&IssueID=${issue['IssueID']}&ComicIssue=${issue['Issue_Number']}&mode=want', $(this),'table')" data-success="Retrying the same version of '${issue['ComicName']}' '${issue['Issue_Number']}'" title="Retry the same download again"><img src="interfaces/default/images/retry_icon.png" height="25" width="25" /></a>
<a href="#" title="Mark issue as Skipped" onclick="doAjaxCall('unqueueissue?IssueID=${issue['IssueID']}&ComicID=${issue['ComicID']}',$(this),'table')" data-success="'${issue['Issue_Number']}' has been marked as skipped"><img src="interfaces/default/images/skipped_icon.png" height="25" width="25" /></a>
%else:
%if issue['inCacheDIR']:
<%
try:
with open(os.path.join(mylar.CACHE_DIR,issue['Location'])) as f:
linky = issue['Location']
except IOError as e:
linky = None
%>
%if linky:
<a href="cache/${linky}"><img src="interfaces/default/images/download_icon.png" height="25" width="25" title="Download the issue" /></a>
%endif
%else:
<a href="#" onclick="doAjaxCall('downloadLocal?IssueID=${issue['IssueID']}', $(this), 'table')" ><img src="interfaces/default/images/copy_icon.png" height="25" width="25" title="Copy issue to local cache (ready for download)" /></a>
%endif
<a href="#" onclick="doAjaxCall('queueissue?ComicID=${issue['ComicID']}&IssueID=${issue['IssueID']}&ComicIssue=${issue['Issue_Number']}&mode=want', $(this),'table')" data-success="Retrying the same version of '${issue['ComicName']}' '${issue['Issue_Number']}'" title="Retry the same download again"><img src="interfaces/default/images/retry_icon.png" height="25" width="25" /></a>
<a href="#" title="Mark issue as Skipped" onclick="doAjaxCall('unqueueissue?IssueID=${issue['IssueID']}&ComicID=${issue['ComicID']}',$(this),'table')" data-success="'${issue['Issue_Number']}' has been marked as skipped"><img src="interfaces/default/images/skipped_icon.png" height="25" width="25" /></a>
%endif
@ -306,8 +304,40 @@
<%def name="javascriptIncludes()">
<script src="js/libs/jquery.dataTables.min.js"></script>
<script>
// show/hide different types of rows when the checkboxes are changed
$("#checkboxControls input").change(function(e){
var whichClass = $(this).attr('id')
$(this).showHideRows(whichClass)
return
$('tr.'+whichClass).each(function(i){
$(this).toggle();
});
});
// initially show/hide all the rows according to the checkboxes
$("#checkboxControls input").each(function(e){
var status = this.checked;
$("tr."+$(this).attr('id')).each(function(e){
if (status) {
$(this).show();
} else {
$(this).hide();
}
});
});
$.fn.showHideRows = function(whichClass){
var status = $('#checkboxControls > input, #'+whichClass).prop('checked')
$("tr."+whichClass).each(function(e){
if (status) {
$(this).show();
} else {
$(this).hide();
}
});
}
hideServerDivs = function () {
$("#customoptions").slideUp();

View File

@ -52,10 +52,10 @@
<fieldset>
<legend>Bragging Rights</legend>
<div>
<label><strong># of Comics you're watching: </strong> ${comicinfo['COUNT_COMICS']}</br>
<label><strong># of Series you're watching: </strong> ${comicinfo['COUNT_COMICS']}</br>
<label><strong># of Issues you're watching: </strong> ${comicinfo['COUNT_ISSUES']}</br>
<label><strong># of Issues you actually have: </strong> ${comicinfo['COUNT_HAVES']}</br>
<label><strong> ... total HD-space being used: </strong></br>
<label><strong> ... total HD-space being used: </strong> ${comicinfo['COUNT_SIZE']}</br>
</div>
</fieldset>
<fieldset>

View File

@ -771,6 +771,30 @@ div#searchbar .mini-icon {
margin-left: 6px;
margin-top: 6px;
}
.checkbox.inline {
padding: 0 5px;
}
.checkbox.inline > input {
margin-right: 5px;
margin-left: 0;
}
.Skipped {
background-color: #bedeed;
height: 30px;
}
.Downloaded {
background-color: #c3e3c8;
height: 30px;
}
.Archived {
background-color: #ffda8a;
height: 30px;
}
.Wanted {
background-color: #ffb0b0;
height: 30px;
}
.comictable legend {
font-size: 14px
font-weight: bold;

View File

@ -63,6 +63,7 @@
<th id="select"></th>
<th id="comicname">Comic Name</th>
<th id="comicyear">Year</th>
<th id="issues">Issues</th>
<th id="status">Status</th>
<th id="importdate">Import Date</th>
<th id="addcomic">Options</th>
@ -74,7 +75,8 @@
<tr>
<td id="select"><input type="checkbox" style="vertical-align: middle; margin: 3px; margin-top: -1px;" name="${result['ComicName']}" class="checkbox" /></td>
<td id="comicname"><a href="${result['ComicName']}" title="${result['ComicName']}" target="_blank">${result['ComicName']}</td>
<td id="comicissues"><title="${result['ComicYear']}">${result['ComicYear']}</td>
<td id="comicyear"><title="${result['ComicYear']}">${result['ComicYear']}</td>
<td id="comicissues"><title="${result['IssueCount']}">${result['IssueCount']}</td>
<td id="status">${result['Status']}
%if result['WatchMatch'] is not None:
<img src="interfaces/default/images/green-circle.png" height="10" width="10"/>

View File

@ -738,7 +738,7 @@ def dbcheck():
c.execute('CREATE TABLE IF NOT EXISTS weekly (SHIPDATE text, PUBLISHER text, ISSUE text, COMIC VARCHAR(150), EXTRA text, STATUS text)')
# c.execute('CREATE TABLE IF NOT EXISTS sablog (nzo_id TEXT, ComicName TEXT, ComicYEAR TEXT, ComicIssue TEXT, name TEXT, nzo_complete TEXT)')
c.execute('CREATE TABLE IF NOT EXISTS importresults (impID TEXT, ComicName TEXT, ComicYear TEXT, Status TEXT, ImportDate TEXT, ComicFilename TEXT, ComicLocation TEXT, WatchMatch TEXT)')
# c.execute('CREATE TABLE IF NOT EXISTS readlist (IssueID TEXT, ComicName TEXT, Issue_Number TEXT, Status TEXT, DateAdded TEXT)')
c.execute('CREATE TABLE IF NOT EXISTS readlist (IssueID TEXT, ComicName TEXT, Issue_Number TEXT, Status TEXT, DateAdded TEXT, Location TEXT, inCacheDir TEXT)')
conn.commit
c.close
@ -810,15 +810,15 @@ def dbcheck():
except sqlite3.OperationalError:
c.execute('ALTER TABLE importresults ADD COLUMN impID TEXT')
# try:
# c.execute('SELECT inCacheDIR from readlist')
# except sqlite3.OperationalError:
# c.execute('ALTER TABLE readlist ADD COLUMN inCacheDIR TEXT')
try:
c.execute('SELECT inCacheDIR from readlist')
except sqlite3.OperationalError:
c.execute('ALTER TABLE readlist ADD COLUMN inCacheDIR TEXT')
# try:
# c.execute('SELECT Location from readlist')
# except sqlite3.OperationalError:
# c.execute('ALTER TABLE readlist ADD COLUMN Location TEXT')
try:
c.execute('SELECT Location from readlist')
except sqlite3.OperationalError:
c.execute('ALTER TABLE readlist ADD COLUMN Location TEXT')
#if it's prior to Wednesday, the issue counts will be inflated by one as the online db's everywhere
#prepare for the next 'new' release of a series. It's caught in updater.py, so let's just store the

View File

@ -124,7 +124,32 @@ def bytes_to_mb(bytes):
mb = int(bytes)/1048576
size = '%.1f MB' % mb
return size
def human_size(size_bytes):
"""
format a size in bytes into a 'human' file size, e.g. bytes, KB, MB, GB, TB, PB
Note that bytes/KB will be reported in whole numbers but MB and above will have greater precision
e.g. 1 byte, 43 bytes, 443 KB, 4.3 MB, 4.43 GB, etc
"""
if size_bytes == 1:
# because I really hate unnecessary plurals
return "1 byte"
suffixes_table = [('bytes',0),('KB',0),('MB',1),('GB',2),('TB',2), ('PB',2)]
num = float(size_bytes)
for suffix, precision in suffixes_table:
if num < 1024.0:
break
num /= 1024.0
if precision == 0:
formatted_size = "%d" % num
else:
formatted_size = str(round(num, ndigits=precision))
return "%s %s" % (formatted_size, suffix)
def replace_all(text, dic):
for i, j in dic.iteritems():
text = text.replace(i, j)

View File

@ -69,9 +69,33 @@ class WebInterface(object):
def artistPage(self, ComicID):
myDB = db.DBConnection()
comic = myDB.action('SELECT * FROM comics WHERE ComicID=?', [ComicID]).fetchone()
issues = myDB.select('SELECT * from issues WHERE ComicID=? order by Int_IssueNumber DESC', [ComicID])
if comic is None:
raise cherrypy.HTTPRedirect("home")
issues = myDB.select('SELECT * FROM issues WHERE ComicID=? order by Int_IssueNumber DESC', [ComicID])
isCounts = {}
isCounts[1] = 0 #1 skipped
isCounts[2] = 0 #2 wanted
isCounts[3] = 0 #3 archived
isCounts[4] = 0 #4 downloaded
isCounts[5] = 0 #5 read
for curResult in issues:
baseissues = {'skipped':1,'wanted':2,'archived':3,'downloaded':4}
for seas in baseissues:
if seas in curResult['Status'].lower():
sconv = baseissues[seas]
isCounts[sconv]+=1
continue
print ("skipped: " + str(isCounts[1]))
print ("wanted: " + str(isCounts[2]))
print ("archived: " + str(isCounts[3]))
print ("downloaded: " + str(isCounts[4]))
isCounts = {
"Skipped" : str(isCounts[1]),
"Wanted" : str(isCounts[2]),
"Archived" : str(isCounts[3]),
"Downloaded" : str(isCounts[4])
}
usethefuzzy = comic['UseFuzzy']
skipped2wanted = "0"
if usethefuzzy is None: usethefuzzy = "0"
@ -82,9 +106,9 @@ class WebInterface(object):
"fuzzy_year2" : helpers.radio(int(usethefuzzy), 2),
"skipped2wanted" : helpers.checked(skipped2wanted)
}
return serve_template(templatename="artistredone.html", title=comic['ComicName'], comic=comic, issues=issues, comicConfig=comicConfig)
return serve_template(templatename="artistredone.html", title=comic['ComicName'], comic=comic, issues=issues, comicConfig=comicConfig, isCounts=isCounts)
artistPage.exposed = True
def searchit(self, name, issue=None, mode=None):
type = 'comic' # let's default this to comic search only for the time being (will add story arc, characters, etc later)
#mode dictates type of search:
@ -101,14 +125,13 @@ class WebInterface(object):
elif type == 'comic' and mode == 'want':
searchresults = mb.findComic(name, mode, issue)
searchresults = sorted(searchresults, key=itemgetter('comicyear','issues'), reverse=True)
searchresults = sorted(searchresults, key=itemgetter('comicyear','issues'), reverse=True)
#print ("Results: " + str(searchresults))
return serve_template(templatename="searchresults.html", title='Search Results for: "' + name + '"', searchresults=searchresults, type=type, imported=None, ogcname=None)
searchit.exposed = True
def addComic(self, comicid, comicname=None, comicyear=None, comicimage=None, comicissues=None, comicpublisher=None, imported=None, ogcname=None):
myDB = db.DBConnection()
print ("I'm here.")
if imported == "confirm":
# if it's coming from the importer and it's just for confirmation, record the right selection and break.
# if it's 'confirmed' coming in as the value for imported
@ -120,7 +143,7 @@ class WebInterface(object):
confirmedid = "C" + str(comicid)
confirms = myDB.action("SELECT * FROM importresults WHERE WatchMatch=?", [ogcname])
if confirms is None:
print ("There are no results that match...this is an ERROR.")
logger.Error("There are no results that match...this is an ERROR.")
else:
for confirm in confirms:
controlValue = {"impID": confirm['impID']}
@ -131,11 +154,11 @@ class WebInterface(object):
sresults = []
cresults = []
mismatch = "no"
print ("comicid: " + str(comicid))
print ("comicname: " + str(comicname))
print ("comicyear: " + str(comicyear))
print ("comicissues: " + str(comicissues))
print ("comicimage: " + str(comicimage))
#print ("comicid: " + str(comicid))
#print ("comicname: " + str(comicname))
#print ("comicyear: " + str(comicyear))
#print ("comicissues: " + str(comicissues))
#print ("comicimage: " + str(comicimage))
#here we test for exception matches (ie. comics spanning more than one volume, known mismatches, etc).
CV_EXcomicid = myDB.action("SELECT * from exceptions WHERE ComicID=?", [comicid]).fetchone()
if CV_EXcomicid is None: # pass #
@ -149,7 +172,7 @@ class WebInterface(object):
logger.info(u"I couldn't find an exact match for " + str(comicname) + " (" + str(comicyear) + ") - gathering data for Error-Checking screen (this could take a minute)..." )
i = 0
loopie, cnt = parseit.ComChk(comicname, comicyear, comicpublisher, comicissues, comicid)
print ("total count : " + str(cnt))
logger.info("total count : " + str(cnt))
while (i < cnt):
try:
stoopie = loopie['comchkchoice'][i]
@ -643,6 +666,31 @@ class WebInterface(object):
return serve_template(templatename="history.html", title="History", history=history)
return page
history.exposed = True
def readlist(self):
myDB = db.DBConnection()
readlist = myDB.select("SELECT * from readlist order by DateAdded DESC")
return serve_template(templatename="readlist.html", title="Readlist", readlist=readlist)
return page
readlist.exposed = True
def addtoreadlist(self, IssueID):
myDB = db.DBConnection()
readlist = myDB.action("SELECT * from issues where IssueID=?", [IssueID]).fetchone()
if readlist is None:
logger.error("Cannot locate IssueID - aborting..")
else:
logger.info("attempting to add..issueid " + readlist['IssueID'])
ctrlval = {"IssueID": IssueID}
newval = {"DateAdded": helpers.today(),
"Status": "added",
"Issue_Number": readlist['Issue_Number'],
"ComicName": readlist['ComicName']}
myDB.upsert("readlist", newval, ctrlval)
logger.info("Added " + str(readlist['ComicName']) + " # " + str(readlist['Issue_Number']) + " to the Reading list.")
raise cherrypy.HTTPRedirect("artistPage?ComicID=%s" % readlist['ComicID'])
addtoreadlist.exposed = True
def logs(self):
if mylar.LOG_LEVEL is None or mylar.LOG_LEVEL == '':
@ -694,8 +742,9 @@ class WebInterface(object):
logger.debug("sucessfully copied to cache...Enabling Download link")
controlValueDict = {'IssueID': IssueID}
newValueDict = {'inCacheDIR': 'True'}
myDB.upsert("issues", newValueDict, controlValueDict)
newValueDict = {'inCacheDIR': 'True',
'Location': issueFILE}
myDB.upsert("readlist", newValueDict, controlValueDict)
#print("DB updated - Download link now enabled.")
@ -781,6 +830,16 @@ class WebInterface(object):
def importResults(self):
myDB = db.DBConnection()
results = myDB.select("SELECT * FROM importresults WHERE WatchMatch is Null OR WatchMatch LIKE 'C%' group by ComicName COLLATE NOCASE")
#this is to get the count of issues;
for result in results:
countthis = myDB.action("SELECT count(*) FROM importresults WHERE ComicName=?", [result['ComicName']]).fetchall()
countit = countthis[0][0]
ctrlVal = {"ComicName": result['ComicName']}
newVal = {"IssueCount": countit}
myDB.upsert("importresults", newVal, ctrlVal)
logger.info("counted " + str(countit) + " issues for " + str(result['ComicName']))
#need to reload results now
results = myDB.select("SELECT * FROM importresults WHERE WatchMatch is Null OR WatchMatch LIKE 'C%' group by ComicName COLLATE NOCASE")
watchresults = myDB.select("SELECT * FROM importresults WHERE WatchMatch is not Null AND WatchMatch NOT LIKE 'C%' group by ComicName COLLATE NOCASE")
return serve_template(templatename="importresults.html", title="Import Results", results=results, watchresults=watchresults)
importResults.exposed = True
@ -853,6 +912,9 @@ class WebInterface(object):
maxyear = int(yearTOP) - (int(minISSUE) / 12)
yearRANGE.append(str(maxyear))
print ("there is a " + str(maxyear) + " year variation based on the 12 issues/year")
else:
print ("no year detected in any issues...Nulling the value")
yearRANGE = None
#determine a best-guess to # of issues in series
#this needs to be reworked / refined ALOT more.
#minISSUE = highest issue #, startISSUE = lowest issue #
@ -865,20 +927,25 @@ class WebInterface(object):
print ("issues present on system : " + str(len(comicstoIMP)))
print ("versioning checking: ")
cnsplit = ComicName.split()
cnwords = len(cnsplit)
cnvers = cnsplit[cnwords-1]
#cnwords = len(cnsplit)
#cnvers = cnsplit[cnwords-1]
ogcname = ComicName
if 'v' in cnvers:
print ("possible versioning detected.")
if cnvers[1:].isdigit():
print (cnvers + " - assuming versioning. Removing from initial search pattern.")
ComicName = ComicName[:-((len(cnvers))+1)]
print ("new comicname is : " + str(ComicName))
for splitt in cnsplit:
print ("split")
if 'v' in str(splitt):
print ("possible versioning detected.")
if splitt[1:].isdigit():
print (splitt + " - assuming versioning. Removing from initial search pattern.")
ComicName = re.sub(str(splitt), '', ComicName)
print ("new comicname is : " + str(ComicName))
# we need to pass the original comicname here into the entire importer module
# so that we can reference the correct issues later.
mode='series'
sresults = mb.findComic(ComicName, mode, issue=numissues, limityear=yearRANGE)
if yearRANGE is None:
sresults = mb.findComic(ComicName, mode, issue=numissues)
else:
sresults = mb.findComic(ComicName, mode, issue=numissues, limityear=yearRANGE)
type='comic'
if len(sresults) == 1:
@ -890,6 +957,7 @@ class WebInterface(object):
print ("no results, removing the year from the agenda and re-querying.")
sresults = mb.findComic(ComicName, mode, issue=numissues)
if len(sresults) == 1:
sr = sresults[0]
print ("only one result...automagik-mode enabled for " + str(sr['comicid']))
resultset = 1
else:
@ -916,12 +984,16 @@ class WebInterface(object):
CCOMICS = myDB.action("SELECT COUNT(*) FROM comics").fetchall()
CHAVES = myDB.action("SELECT COUNT(*) FROM issues WHERE Status='Downloaded' OR Status='Archived'").fetchall()
CISSUES = myDB.action("SELECT COUNT(*) FROM issues").fetchall()
CSIZE = myDB.action("select SUM(ComicSize) from issues where Status='Downloaded' or Status='Archived'").fetchall()
COUNT_COMICS = CCOMICS[0][0]
COUNT_HAVES = CHAVES[0][0]
COUNT_ISSUES = CISSUES[0][0]
COUNT_SIZE = helpers.human_size(CSIZE[0][0])
comicinfo = { "COUNT_COMICS" : COUNT_COMICS,
"COUNT_HAVES" : COUNT_HAVES,
"COUNT_ISSUES" : COUNT_ISSUES }
"COUNT_ISSUES" : COUNT_ISSUES,
"COUNT_SIZE" : COUNT_SIZE }
config = {
"http_host" : mylar.HTTP_HOST,