Add indication of shows with never aired episodes and other changes to the Episode Overview page.

Add "Collapse" button and visuals for Expanding... and Collapsing... states.
Add the number of episodes marked with the status being queried.
Add indication of shows with never aired episodes.
Change to separate "Set as wanted" to prevent disaster selection.
Remove restriction to not display snatched eps link in footer.
Change the shows episodes count text colour to visually separete from year numbers at the end of show names.
This commit is contained in:
JackDandy 2015-03-18 22:22:54 +00:00
parent eee3d05b1a
commit 518f5ebae5
7 changed files with 161 additions and 101 deletions

View file

@ -58,6 +58,13 @@
* Change the episodes downloaded stat to display e.g. 2843 / 2844 as 99.9% instead of rounding to 100% * Change the episodes downloaded stat to display e.g. 2843 / 2844 as 99.9% instead of rounding to 100%
* Change 'never' episode row color away from blue on Display Show page when indexer airdate is not defined * Change 'never' episode row color away from blue on Display Show page when indexer airdate is not defined
* Add tint to archived episode row colour to differentiate it from downloaded episodes on the Display Show page * Add tint to archived episode row colour to differentiate it from downloaded episodes on the Display Show page
* Add indication of shows with never aired episodes on Episode Overview page
* Add "Collapse" button and visuals for Expanding... and Collapsing... states
* Add the number of episodes marked with the status being queried to Episode Overview page
* Add indication of shows with never aired episodes on Episode Overview page
* Change to separate "Set as wanted" to prevent disaster selection on Episode Overview page
* Remove restriction to not display snatched eps link in footer on Episode Overview page
* Change the shows episodes count text colour to visually separete from year numbers at the end of show names
* Fix release group not recognised from manually downloaded filename * Fix release group not recognised from manually downloaded filename
[develop changelog] [develop changelog]

View file

@ -382,11 +382,13 @@ ul.tags li a{
border:1px solid #111 border:1px solid #111
} }
.sickbeardTable tr.header td,
.sickbeardTable th{ .sickbeardTable th{
color:#fff; color:#fff;
background-color:#15528F background-color:#15528F
} }
.sickbeardTable tr.header td,
.sickbeardTable th, .sickbeardTable th,
.sickbeardTable td{ .sickbeardTable td{
border-top:1px solid #222; border-top:1px solid #222;

View file

@ -1324,6 +1324,7 @@ span.snatched b{
clear:both clear:both
} }
.sickbeardTable tr.header td,
.sickbeardTable th{ .sickbeardTable th{
color:#fff; color:#fff;
text-align:center; text-align:center;
@ -1331,13 +1332,18 @@ span.snatched b{
white-space:nowrap white-space:nowrap
} }
.sickbeardTable th, .sickbeardTable tr.header td,
.sickbeardTable th,
.sickbeardTable td{ .sickbeardTable td{
border-top:1px solid #fff; border-top:1px solid #fff;
border-left:1px solid #fff; border-left:1px solid #fff;
padding:4px padding:4px
} }
.sickbeardTable tr.header td{
padding:4px 8px
}
th.row-seasonheader{ th.row-seasonheader{
border:none; border:none;
background-color:#fff; background-color:#fff;
@ -2247,6 +2253,7 @@ div.metadataDiv .disabled{
manage*.tmpl manage*.tmpl
========================================================================== */ ========================================================================== */
.sickbeardTable tr.header td,
.manageTable th{ .manageTable th{
white-space:normal; white-space:normal;
line-height:24px line-height:24px
@ -2300,6 +2307,11 @@ a.whitelink{
color:#fff color:#fff
} }
input.get_more_eps,
input.get_less_eps{
display:none
}
/* ======================================================================= /* =======================================================================
404.tmpl 404.tmpl
========================================================================== */ ========================================================================== */

View file

@ -56,11 +56,8 @@
( (
'', '',
' (<span class="footerhighlight">+%s</span> snatched)'\ ' (<span class="footerhighlight">+%s</span> snatched)'\
% ( % '<a href="%s/manage/episodeStatuses?whichStatus=2" title="View overview of snatched episodes">%s</a>'
str(ep_snatched), % (localRoot, str(ep_snatched))
'<a href="%s/manage/episodeStatuses?whichStatus=2" title="View overview of snatched episodes">%s</a>'\
% (localRoot, str(ep_snatched))
)['Episode Overview' != localheader]
)[0 < ep_snatched] )[0 < ep_snatched]
%>&nbsp;/&nbsp;<span class="footerhighlight">$ep_total</span> episodes downloaded $ep_percentage %>&nbsp;/&nbsp;<span class="footerhighlight">$ep_total</span> episodes downloaded $ep_percentage
| recent search: <span class="footerhighlight"><%= str(sickbeard.recentSearchScheduler.timeLeft()).split('.')[0] %></span> | recent search: <span class="footerhighlight"><%= str(sickbeard.recentSearchScheduler.timeLeft()).split('.')[0] %></span>

View file

@ -16,70 +16,96 @@
<h1 class="title">$title</h1> <h1 class="title">$title</h1>
#end if #end if
#if not $whichStatus or ($whichStatus and not $ep_counts): #if not $whichStatus or ($whichStatus and not $ep_counts)
#if $whichStatus: #if $whichStatus:
<h3>None of your episodes have status <span class="grey-text">$common.statusStrings[$int($whichStatus)]</span></h3> <h3>no episodes have status <span class="grey-text">$common.statusStrings[$int($whichStatus)].lower()</span></h3>
#end if #end if
<form action="$sbRoot/manage/episodeStatuses" method="get"> <form action="$sbRoot/manage/episodeStatuses" method="get">
Manage episodes with status <select name="whichStatus" class="form-control form-control-inline input-sm">
#for $curStatus in [$common.SKIPPED, $common.UNKNOWN, $common.SNATCHED, $common.WANTED, $common.ARCHIVED, $common.IGNORED]: Manage episodes with status
<option value="$curStatus">$common.statusStrings[$curStatus]</option> <select name="whichStatus" class="form-control form-control-inline input-sm" style="margin:0 10px">
#end for
</select> #for $curStatus in [$common.SKIPPED, $common.UNKNOWN, $common.SNATCHED, $common.WANTED, $common.ARCHIVED, $common.IGNORED]:
<input class="btn btn-inline" type="submit" value="Manage" /> <option value="$curStatus">$common.statusStrings[$curStatus]</option>
</form> #end for
</select>
<input class="btn btn-inline" type="submit" value="Manage">
</form>
#else #else
#if $whichStatus in ($common.ARCHIVED, $common.IGNORED, $common.SNATCHED):
#set $row_class = 'good'
#else
#set $row_class = $common.Overview.overviewStrings[$whichStatus]
#end if
#set $statusList = [$common.SKIPPED, $common.ARCHIVED, $common.IGNORED]
#if $int($whichStatus) in $statusList
$statusList.remove($int($whichStatus))
#end if
#if $int($whichStatus) in [$common.SNATCHED, $common.SNATCHED_PROPER]
$statusList.append($common.FAILED)
#end if
<script type="text/javascript" src="$sbRoot/js/manageEpisodeStatuses.js?$sbPID"></script> <script type="text/javascript" src="$sbRoot/js/manageEpisodeStatuses.js?$sbPID"></script>
<form action="$sbRoot/manage/changeEpisodeStatuses" method="post"> <form action="$sbRoot/manage/changeEpisodeStatuses" method="post">
<input type="hidden" id="oldStatus" name="oldStatus" value="$whichStatus" /> <input type="hidden" id="oldStatus" name="oldStatus" value="$whichStatus">
<h3>${len($sorted_show_ids)} Shows containing <span class="grey-text">$common.statusStrings[$int($whichStatus)]</span> episodes</h3> <h3><span class="grey-text">$ep_count</span> episode#echo ('s', '')[1 == $ep_count]# marked <span class="grey-text">$common.statusStrings[$int($whichStatus)].lower()</span> in <span class="grey-text">${len($sorted_show_ids)}</span> show#echo ('s', '')[1 == len($sorted_show_ids)]#</h3>
#if $whichStatus in ($common.ARCHIVED, $common.IGNORED, $common.SNATCHED): <input type="hidden" id="row_class" value="$row_class">
#set $row_class = 'good'
#else
#set $row_class = $common.Overview.overviewStrings[$whichStatus]
#end if
<input type="hidden" id="row_class" value="$row_class" />
<div class="form-group"> <div class="form-group">
Set checked shows/episodes to <select name="newStatus" class="form-control form-control-inline input-sm"> <span>Set checked shows/episodes to</span>
#set $statusList = [$common.SKIPPED, $common.WANTED, $common.ARCHIVED, $common.IGNORED] <select name="newStatus" class="form-control form-control-inline input-sm" style="margin:0 10px 0 5px">
#if $int($whichStatus) in $statusList #for $curStatus in $statusList:
$statusList.remove($int($whichStatus)) <option value="$curStatus">$common.statusStrings[$curStatus]</option>
#end if #end for
</select>
<input class="btn btn-inline go" type="submit" value="Go">
#if $int($whichStatus) in [$common.SNATCHED, $common.SNATCHED_PROPER] <span class="red-text" style="margin:0 0 0 30px">Override checked status to</span>
$statusList.append($common.FAILED) <select name="wantedStatus" class="form-control form-control-inline input-sm" style="margin:0 10px 0 5px">
#end if <option value="$common.UNKNOWN">nothing</option>
<option value="$common.WANTED">$common.statusStrings[$common.WANTED]</option>
</select>
<input class="btn btn-inline go" type="submit" value="Go">
</div>
#for $curStatus in $statusList: <div class="form-group">
<option value="$curStatus">$common.statusStrings[$curStatus]</option> <input type="button" class="btn btn-xs selectAllShows" value="Select all">
#end for <input type="button" class="btn btn-xs unselectAllShows" value="Clear all">
</select> <input type="button" class="btn btn-xs expandAll" value="Expand All Shows">
<input class="btn btn-inline go" type="submit" value="Go" /> </div>
</div>
<div class="form-group"> <table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0">
<input type="button" class="btn btn-xs selectAllShows" value="Select all"> <thead></thead>
<input type="button" class="btn btn-xs unselectAllShows" value="Clear all"> <tbody>
<input type="button" class="btn btn-xs expandAll" value="Expand All Shows"> #for $cur_indexer_id in $sorted_show_ids:
</div> #if 0 == int($never_counts[$cur_indexer_id])
#set $output = '%d' % $ep_counts[$cur_indexer_id]
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0"> #elif $ep_counts[$cur_indexer_id] != $never_counts[$cur_indexer_id]
#for $cur_indexer_id in $sorted_show_ids: #set $diff = $ep_counts[$cur_indexer_id] - $never_counts[$cur_indexer_id]
<tr id="$cur_indexer_id"> #set $output = '%d' % $diff + ('', (' episode%s plus %s never with an airdate' % (('s', '')[1 == $ep_counts[$cur_indexer_id]], $never_counts[$cur_indexer_id])))[0 < $never_counts[$cur_indexer_id]]
<th><input type="checkbox" class="allCheck" id="allCheck-$cur_indexer_id" name="$cur_indexer_id-all" /></th> #else
<th colspan="2" style="width: 100%; text-align: left;"><a class="whitelink" href="$sbRoot/home/displayShow?show=$cur_indexer_id">$show_names[$cur_indexer_id]</a> ($ep_counts[$cur_indexer_id]) <input type="button" class="pull-right get_more_eps btn" id="$cur_indexer_id" value="Expand" /></th> #set $output = '%s never with an airdate' % (('all %s %ss', '%s %s')[1 == $ep_counts[$cur_indexer_id]] % ($ep_counts[$cur_indexer_id], 'episode'))
</tr> #end if
#end for <tr id="$cur_indexer_id" class="header">
</table> <td><input type="checkbox" class="allCheck" id="allCheck-$cur_indexer_id" name="$cur_indexer_id-all"></td>
</form> <td colspan="2" style="width:100%;text-align:left">
<a class="whitelink" href="$sbRoot/home/displayShow?show=$cur_indexer_id">$show_names[$cur_indexer_id]</a> <span style="color:#999">($output)</span><input type="button" class="pull-right get_more_eps btn" id="$cur_indexer_id-more" value="Expand"><input type="button" class="pull-right get_less_eps btn" id="$cur_indexer_id-less" value="Collapse">
</td>
</tr>
#end for
</tbody>
</table>
</form>
#end if #end if

View file

@ -1,17 +1,18 @@
$(document).ready(function() { $(document).ready(function() {
function make_row(indexer_id, season, episode, name, checked) { function make_row(indexer_id, season, episode, name, checked, airdate_never) {
var checkedbox = (checked ? ' checked' : ''), var checkedbox = (checked ? ' checked' : ''),
row_class = $('#row_class').val(); row_class = $('#row_class').val(),
ep_id = season + 'x' + episode;
return ' <tr class="' + row_class + '">' return ' <tr id="ep-' + indexer_id + '-' + ep_id + '" class="' + (airdate_never ? 'airdate-never' : row_class) + '">'
+ ' <td class="tableleft" align="center">' + ' <td class="tableleft" align="center">'
+ '<input type="checkbox"' + '<input type="checkbox"'
+ ' class="' + indexer_id + '-epcheck"' + ' class="' + indexer_id + '-epcheck"'
+ ' name="' + indexer_id + '-' + season + 'x' + episode + '"' + ' name="' + indexer_id + '-' + ep_id + '"'
+ checkedbox+'></td>' + checkedbox+'></td>'
+ ' <td>' + season + 'x' + episode + '</td>' + ' <td>' + ep_id + '</td>'
+ ' <td class="tableright" style="width: 100%">' + name + '</td>' + ' <td class="tableright" style="width: 100%">' + name + (airdate_never ? ' (<strong><em>airdate is never, this should change in time</em></strong>)' : '') + '</td>'
+ ' </tr>'; + ' </tr>';
} }
@ -27,48 +28,52 @@ $(document).ready(function() {
$('.' + indexer_id + '-epcheck').prop('checked', $(this).prop('checked')); $('.' + indexer_id + '-epcheck').prop('checked', $(this).prop('checked'));
}); });
$('.get_more_eps').click(function(){ $('.get_more_eps').show();
var cur_indexer_id = $(this).attr('id'); function show_episodes(btn_element) {
var checked = $('#allCheck-' + cur_indexer_id).prop('checked'); var match = btn_element.attr('id').match(/(.*)[-](.*)/);
var last_row = $('tr#' + cur_indexer_id); if (null == match)
return false;
$.getJSON(sbRoot + '/manage/showEpisodeStatuses',
{
indexer_id: cur_indexer_id,
whichStatus: $('#oldStatus').val()
},
function (data) {
$.each(data, function(season,eps){
$.each(eps, function(episode, name) {
last_row.after(make_row(cur_indexer_id, season, episode, name, checked));
});
});
});
$(this).hide();
($('.get_more_eps:visible').length == 0 ? $('.expandAll').hide() : '');
});
$('.expandAll').click(function() { var cur_indexer_id = match[1], action = match[2], checked = $('#allCheck-' + cur_indexer_id).prop('checked'),
$('.get_more_eps').each(function() { show_header = $('tr#' + cur_indexer_id), episode_rows = $('tr[id*="ep-' + cur_indexer_id + '"]'),
var cur_indexer_id = $(this).attr('id'); void_var = 'more' == action && episode_rows.show() || episode_rows.hide();
var checked = $('#allCheck-' + cur_indexer_id).prop('checked');
var last_row = $('tr#' + cur_indexer_id);
$('input#' + match[0]).val('more' == action ? 'Expanding...' : 'Collapsing...');
if (0 == episode_rows.length) {
$.getJSON(sbRoot + '/manage/showEpisodeStatuses', $.getJSON(sbRoot + '/manage/showEpisodeStatuses',
{ {
indexer_id: cur_indexer_id, indexer_id: cur_indexer_id,
whichStatus: $('#oldStatus').val() whichStatus: $('#oldStatus').val()
}, },
function (data) { function (data) {
$.each(data, function(season, eps) { $.each(data, function(season, eps){
$.each(eps, function(episode, name) { $.each(eps, function(episode, meta) {
last_row.after(make_row(cur_indexer_id, season, episode, name, checked)); show_header.after(make_row(cur_indexer_id, season, episode, meta.name, checked, meta.airdate_never));
}); });
}); });
$('input#' + match[0]).val('more' == action ? 'Expand' : 'Collapse');
btn_element.hide();
$('input[id="' + cur_indexer_id + '-' + ('more' == action ? 'less' : 'more') + '"]').show();
}); });
$(this).hide(); } else {
}); $('input#' + match[0]).val('more' == action ? 'Expand' : 'Collapse');
btn_element.hide();
$('input[id="' + cur_indexer_id + '-' + ('more' == action ? 'less' : 'more') + '"]').show();
}
}
$('.get_more_eps,.get_less_eps').click(function(){
show_episodes($(this));
($('.get_more_eps:visible').length == 0 ? $('.expandAll').hide() : '');
});
$('.expandAll').click(function() {
$(this).hide(); $(this).hide();
$('.get_more_eps').each(function() {
show_episodes($(this));
});
}); });
// selects all visible episode checkboxes. // selects all visible episode checkboxes.

View file

@ -1487,7 +1487,7 @@ class Home(MainHandler):
sql_l = [] sql_l = []
for curEp in eps.split('|'): for curEp in eps.split('|'):
logger.log(u'Attempting to set status on episode ' + curEp + ' to ' + status, logger.DEBUG) logger.log(u'Attempting to set status on episode %s to %s' % (curEp, status), logger.DEBUG)
epInfo = curEp.split('x') epInfo = curEp.split('x')
@ -2481,7 +2481,7 @@ class Manage(MainHandler):
myDB = db.DBConnection() myDB = db.DBConnection()
cur_show_results = myDB.select( cur_show_results = myDB.select(
'SELECT season, episode, name FROM tv_episodes WHERE showid = ? AND season != 0 AND status IN (' + ','.join( 'SELECT season, episode, name, airdate FROM tv_episodes WHERE showid = ? AND season != 0 AND status IN (' + ','.join(
['?'] * len(status_list)) + ')', [int(indexer_id)] + status_list) ['?'] * len(status_list)) + ')', [int(indexer_id)] + status_list)
result = {} result = {}
@ -2492,7 +2492,7 @@ class Manage(MainHandler):
if cur_season not in result: if cur_season not in result:
result[cur_season] = {} result[cur_season] = {}
result[cur_season][cur_episode] = cur_result['name'] result[cur_season][cur_episode] = {'name': cur_result['name'], 'airdate_never': (True, False)[1000 < int(cur_result['airdate'])]}
return json.dumps(result) return json.dumps(result)
@ -2516,12 +2516,14 @@ class Manage(MainHandler):
myDB = db.DBConnection() myDB = db.DBConnection()
status_results = myDB.select( status_results = myDB.select(
'SELECT show_name, tv_shows.indexer_id as indexer_id FROM tv_episodes, tv_shows WHERE tv_episodes.status IN (' + ','.join( 'SELECT show_name, tv_shows.indexer_id as indexer_id, airdate FROM tv_episodes, tv_shows WHERE tv_episodes.status IN (' + ','.join(
['?'] * len( ['?'] * len(
status_list)) + ') AND season != 0 AND tv_episodes.showid = tv_shows.indexer_id ORDER BY show_name', status_list)) + ') AND season != 0 AND tv_episodes.showid = tv_shows.indexer_id ORDER BY show_name',
status_list) status_list)
ep_counts = {} ep_counts = {}
ep_count = 0
never_counts = {}
show_names = {} show_names = {}
sorted_show_ids = [] sorted_show_ids = []
for cur_status_result in status_results: for cur_status_result in status_results:
@ -2530,6 +2532,11 @@ class Manage(MainHandler):
ep_counts[cur_indexer_id] = 1 ep_counts[cur_indexer_id] = 1
else: else:
ep_counts[cur_indexer_id] += 1 ep_counts[cur_indexer_id] += 1
ep_count += 1
if cur_indexer_id not in never_counts:
never_counts[cur_indexer_id] = 0
if 1000 > int(cur_status_result['airdate']):
never_counts[cur_indexer_id] += 1
show_names[cur_indexer_id] = cur_status_result['show_name'] show_names[cur_indexer_id] = cur_status_result['show_name']
if cur_indexer_id not in sorted_show_ids: if cur_indexer_id not in sorted_show_ids:
@ -2537,11 +2544,12 @@ class Manage(MainHandler):
t.show_names = show_names t.show_names = show_names
t.ep_counts = ep_counts t.ep_counts = ep_counts
t.ep_count = ep_count
t.never_counts = never_counts
t.sorted_show_ids = sorted_show_ids t.sorted_show_ids = sorted_show_ids
return t.respond() return t.respond()
def changeEpisodeStatuses(self, oldStatus, newStatus, *args, **kwargs): def changeEpisodeStatuses(self, oldStatus, newStatus, wantedStatus=sickbeard.common.UNKNOWN, *args, **kwargs):
status_list = [int(oldStatus)] status_list = [int(oldStatus)]
if status_list[0] == SNATCHED: if status_list[0] == SNATCHED:
status_list = Quality.SNATCHED + Quality.SNATCHED_PROPER status_list = Quality.SNATCHED + Quality.SNATCHED_PROPER
@ -2550,17 +2558,20 @@ class Manage(MainHandler):
# make a list of all shows and their associated args # make a list of all shows and their associated args
for arg in kwargs: for arg in kwargs:
indexer_id, what = arg.split('-')
# we don't care about unchecked checkboxes # we don't care about unchecked checkboxes
if kwargs[arg] != 'on': if kwargs[arg] != 'on':
continue continue
indexer_id, what = arg.split('-')
if indexer_id not in to_change: if indexer_id not in to_change:
to_change[indexer_id] = [] to_change[indexer_id] = []
to_change[indexer_id].append(what) to_change[indexer_id].append(what)
if sickbeard.common.WANTED == int(wantedStatus):
newStatus = sickbeard.common.WANTED
myDB = db.DBConnection() myDB = db.DBConnection()
for cur_indexer_id in to_change: for cur_indexer_id in to_change: