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 '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 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
[develop changelog]

View file

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

View file

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

View file

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

View file

@ -16,70 +16,96 @@
<h1 class="title">$title</h1>
#end if
#if not $whichStatus or ($whichStatus and not $ep_counts):
#if not $whichStatus or ($whichStatus and not $ep_counts)
#if $whichStatus:
<h3>None of your episodes have status <span class="grey-text">$common.statusStrings[$int($whichStatus)]</span></h3>
#end if
#if $whichStatus:
<h3>no episodes have status <span class="grey-text">$common.statusStrings[$int($whichStatus)].lower()</span></h3>
#end if
<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]:
<option value="$curStatus">$common.statusStrings[$curStatus]</option>
#end for
</select>
<input class="btn btn-inline" type="submit" value="Manage" />
</form>
<form action="$sbRoot/manage/episodeStatuses" method="get">
Manage episodes with status
<select name="whichStatus" class="form-control form-control-inline input-sm" style="margin:0 10px">
#for $curStatus in [$common.SKIPPED, $common.UNKNOWN, $common.SNATCHED, $common.WANTED, $common.ARCHIVED, $common.IGNORED]:
<option value="$curStatus">$common.statusStrings[$curStatus]</option>
#end for
</select>
<input class="btn btn-inline" type="submit" value="Manage">
</form>
#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>
<form action="$sbRoot/manage/changeEpisodeStatuses" method="post">
<input type="hidden" id="oldStatus" name="oldStatus" value="$whichStatus" />
<form action="$sbRoot/manage/changeEpisodeStatuses" method="post">
<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):
#set $row_class = 'good'
#else
#set $row_class = $common.Overview.overviewStrings[$whichStatus]
#end if
<input type="hidden" id="row_class" value="$row_class" />
<input type="hidden" id="row_class" value="$row_class">
<div class="form-group">
Set checked shows/episodes to <select name="newStatus" class="form-control form-control-inline input-sm">
#set $statusList = [$common.SKIPPED, $common.WANTED, $common.ARCHIVED, $common.IGNORED]
#if $int($whichStatus) in $statusList
$statusList.remove($int($whichStatus))
#end if
<div class="form-group">
<span>Set checked shows/episodes to</span>
<select name="newStatus" class="form-control form-control-inline input-sm" style="margin:0 10px 0 5px">
#for $curStatus in $statusList:
<option value="$curStatus">$common.statusStrings[$curStatus]</option>
#end for
</select>
<input class="btn btn-inline go" type="submit" value="Go">
#if $int($whichStatus) in [$common.SNATCHED, $common.SNATCHED_PROPER]
$statusList.append($common.FAILED)
#end if
<span class="red-text" style="margin:0 0 0 30px">Override checked status to</span>
<select name="wantedStatus" class="form-control form-control-inline input-sm" style="margin:0 10px 0 5px">
<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:
<option value="$curStatus">$common.statusStrings[$curStatus]</option>
#end for
</select>
<input class="btn btn-inline go" type="submit" value="Go" />
</div>
<div class="form-group">
<input type="button" class="btn btn-xs selectAllShows" value="Select all">
<input type="button" class="btn btn-xs unselectAllShows" value="Clear all">
<input type="button" class="btn btn-xs expandAll" value="Expand All Shows">
</div>
<div class="form-group">
<input type="button" class="btn btn-xs selectAllShows" value="Select all">
<input type="button" class="btn btn-xs unselectAllShows" value="Clear all">
<input type="button" class="btn btn-xs expandAll" value="Expand All Shows">
</div>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0">
#for $cur_indexer_id in $sorted_show_ids:
<tr id="$cur_indexer_id">
<th><input type="checkbox" class="allCheck" id="allCheck-$cur_indexer_id" name="$cur_indexer_id-all" /></th>
<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>
</tr>
#end for
</table>
</form>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0">
<thead></thead>
<tbody>
#for $cur_indexer_id in $sorted_show_ids:
#if 0 == int($never_counts[$cur_indexer_id])
#set $output = '%d' % $ep_counts[$cur_indexer_id]
#elif $ep_counts[$cur_indexer_id] != $never_counts[$cur_indexer_id]
#set $diff = $ep_counts[$cur_indexer_id] - $never_counts[$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]]
#else
#set $output = '%s never with an airdate' % (('all %s %ss', '%s %s')[1 == $ep_counts[$cur_indexer_id]] % ($ep_counts[$cur_indexer_id], 'episode'))
#end if
<tr id="$cur_indexer_id" class="header">
<td><input type="checkbox" class="allCheck" id="allCheck-$cur_indexer_id" name="$cur_indexer_id-all"></td>
<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

View file

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

View file

@ -1487,7 +1487,7 @@ class Home(MainHandler):
sql_l = []
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')
@ -2481,7 +2481,7 @@ class Manage(MainHandler):
myDB = db.DBConnection()
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)
result = {}
@ -2492,7 +2492,7 @@ class Manage(MainHandler):
if cur_season not in result:
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)
@ -2516,12 +2516,14 @@ class Manage(MainHandler):
myDB = db.DBConnection()
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(
status_list)) + ') AND season != 0 AND tv_episodes.showid = tv_shows.indexer_id ORDER BY show_name',
status_list)
ep_counts = {}
ep_count = 0
never_counts = {}
show_names = {}
sorted_show_ids = []
for cur_status_result in status_results:
@ -2530,6 +2532,11 @@ class Manage(MainHandler):
ep_counts[cur_indexer_id] = 1
else:
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']
if cur_indexer_id not in sorted_show_ids:
@ -2537,11 +2544,12 @@ class Manage(MainHandler):
t.show_names = show_names
t.ep_counts = ep_counts
t.ep_count = ep_count
t.never_counts = never_counts
t.sorted_show_ids = sorted_show_ids
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)]
if status_list[0] == SNATCHED:
status_list = Quality.SNATCHED + Quality.SNATCHED_PROPER
@ -2550,17 +2558,20 @@ class Manage(MainHandler):
# make a list of all shows and their associated args
for arg in kwargs:
indexer_id, what = arg.split('-')
# we don't care about unchecked checkboxes
if kwargs[arg] != 'on':
continue
indexer_id, what = arg.split('-')
if indexer_id not in to_change:
to_change[indexer_id] = []
to_change[indexer_id].append(what)
if sickbeard.common.WANTED == int(wantedStatus):
newStatus = sickbeard.common.WANTED
myDB = db.DBConnection()
for cur_indexer_id in to_change: