From 518f5ebae5c90bc67074500835cd09ec12c51903 Mon Sep 17 00:00:00 2001 From: JackDandy Date: Wed, 18 Mar 2015 22:22:54 +0000 Subject: [PATCH] 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. --- CHANGES.md | 7 + gui/slick/css/dark.css | 2 + gui/slick/css/style.css | 14 +- gui/slick/interfaces/default/inc_bottom.tmpl | 7 +- .../default/manage_episodeStatuses.tmpl | 128 +++++++++++------- gui/slick/js/manageEpisodeStatuses.js | 77 ++++++----- sickbeard/webserve.py | 27 ++-- 7 files changed, 161 insertions(+), 101 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index af856ea6..2260c12b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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] diff --git a/gui/slick/css/dark.css b/gui/slick/css/dark.css index d421f1d4..71caaf03 100644 --- a/gui/slick/css/dark.css +++ b/gui/slick/css/dark.css @@ -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; diff --git a/gui/slick/css/style.css b/gui/slick/css/style.css index ae96007e..49dad9e1 100644 --- a/gui/slick/css/style.css +++ b/gui/slick/css/style.css @@ -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 ========================================================================== */ diff --git a/gui/slick/interfaces/default/inc_bottom.tmpl b/gui/slick/interfaces/default/inc_bottom.tmpl index b2d0d809..f194a3c9 100644 --- a/gui/slick/interfaces/default/inc_bottom.tmpl +++ b/gui/slick/interfaces/default/inc_bottom.tmpl @@ -56,11 +56,8 @@ ( '', ' (+%s snatched)'\ -% ( - str(ep_snatched), - '%s'\ - % (localRoot, str(ep_snatched)) - )['Episode Overview' != localheader] +% '%s' + % (localRoot, str(ep_snatched)) )[0 < ep_snatched] %> / $ep_total episodes downloaded $ep_percentage | recent search: <%= str(sickbeard.recentSearchScheduler.timeLeft()).split('.')[0] %> diff --git a/gui/slick/interfaces/default/manage_episodeStatuses.tmpl b/gui/slick/interfaces/default/manage_episodeStatuses.tmpl index b9587f86..7cabd7cf 100644 --- a/gui/slick/interfaces/default/manage_episodeStatuses.tmpl +++ b/gui/slick/interfaces/default/manage_episodeStatuses.tmpl @@ -16,70 +16,96 @@

$title

#end if -#if not $whichStatus or ($whichStatus and not $ep_counts): +#if not $whichStatus or ($whichStatus and not $ep_counts) -#if $whichStatus: -

None of your episodes have status $common.statusStrings[$int($whichStatus)]

-#end if + #if $whichStatus: +

no episodes have status $common.statusStrings[$int($whichStatus)].lower()

+ #end if -
- Manage episodes with status - -
+
+ + Manage episodes with status + + +
#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 + -
- + + -

${len($sorted_show_ids)} Shows containing $common.statusStrings[$int($whichStatus)] episodes

+

$ep_count episode#echo ('s', '')[1 == $ep_count]# marked $common.statusStrings[$int($whichStatus)].lower() in ${len($sorted_show_ids)} show#echo ('s', '')[1 == len($sorted_show_ids)]#

-#if $whichStatus in ($common.ARCHIVED, $common.IGNORED, $common.SNATCHED): - #set $row_class = 'good' -#else - #set $row_class = $common.Overview.overviewStrings[$whichStatus] -#end if - + -
- Set checked shows/episodes to + #for $curStatus in $statusList: + + #end for + + -#if $int($whichStatus) in [$common.SNATCHED, $common.SNATCHED_PROPER] - $statusList.append($common.FAILED) -#end if + Override checked status to + + +
-#for $curStatus in $statusList: - -#end for - - - +
+ + + +
-
- - - -
- - -#for $cur_indexer_id in $sorted_show_ids: - - - - -#end for -
$show_names[$cur_indexer_id] ($ep_counts[$cur_indexer_id])
-
+ + + + #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 + + + + + #end for + +
+ $show_names[$cur_indexer_id] ($output) +
+ #end if diff --git a/gui/slick/js/manageEpisodeStatuses.js b/gui/slick/js/manageEpisodeStatuses.js index 8b31e102..d002dc94 100644 --- a/gui/slick/js/manageEpisodeStatuses.js +++ b/gui/slick/js/manageEpisodeStatuses.js @@ -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 ' ' + return ' ' + ' ' + '' - + ' ' + season + 'x' + episode + '' - + ' ' + name + '' + + ' ' + ep_id + '' + + ' ' + name + (airdate_never ? ' (airdate is never, this should change in time)' : '') + '' + ' '; } @@ -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. diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 13f59897..76842872 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -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: