From 9e7ad9f5b28511fe5d574807e163b718fd273f7f Mon Sep 17 00:00:00 2001 From: JackDandy Date: Sat, 20 May 2017 02:10:33 +0100 Subject: [PATCH] Add persistent hide/unhide cards to Add show/Trakt and Add show/IMDb Cards. Change simplify dropdowns at all Add show/Cards. --- CHANGES.md | 4 + gui/slick/css/dark.css | 4 + gui/slick/css/light.css | 4 + gui/slick/css/style.css | 6 + .../interfaces/default/home_browseShows.tmpl | 309 +++++++++++------- sickbeard/__init__.py | 7 +- sickbeard/webserve.py | 28 +- 7 files changed, 236 insertions(+), 126 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 05c9311d..04234984 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -52,6 +52,10 @@ * Change do not have shows checked by default on import page. To re-enable import shows checked by default, 1) On config page 'Save' 2) Stop SG 3) Find 'import_default_checked_shows' in config.ini and set '1' 4) Start SG * Add Nyaa (.si) torrent provider +* Add Trakt watchlist to Add show/Trakt Cards +* Change revoke application access at Trakt when account is deleted in SG +* Add persistent hide/unhide cards to Add show/Trakt and Add show/IMDb Cards +* Change simplify dropdowns at all Add show/Cards [develop changelog] diff --git a/gui/slick/css/dark.css b/gui/slick/css/dark.css index c651622d..fe1bb8a5 100644 --- a/gui/slick/css/dark.css +++ b/gui/slick/css/dark.css @@ -293,11 +293,13 @@ a.ui-font{ background-image:linear-gradient(to left, rgba(51, 51, 51, 1), rgba(51, 51, 51, 0)) } +.show-toggle-hide, td.tvShow a{ color:#ddd; text-decoration:none } +.show-toggle-hide:hover, td.tvShow a:hover span, td.tvShow a:hover{ cursor:pointer; @@ -1288,6 +1290,7 @@ input sizing (for config pages) .showlist-select optgroup, #pickShow optgroup, #showfilter optgroup, +#showsort optgroup, #editAProvider optgroup{ color:#eee; background-color:rgb(51, 51, 51) @@ -1296,6 +1299,7 @@ input sizing (for config pages) .showlist-select optgroup option, #pickShow optgroup option, #showfilter optgroup option, +#showsort optgroup option, #editAProvider optgroup option{ color:#222; background-color:#ddd diff --git a/gui/slick/css/light.css b/gui/slick/css/light.css index b47c0e41..d031ef28 100644 --- a/gui/slick/css/light.css +++ b/gui/slick/css/light.css @@ -308,11 +308,13 @@ a.ui-font{ background-image:linear-gradient(to left, rgba(223, 218, 207, 1), rgba(223, 218, 207, 0)) } +.show-toggle-hide, td.tvShow a{ color:#000; text-decoration:none } +.show-toggle-hide:hover, td.tvShow a:hover span, td.tvShow a:hover{ cursor:pointer; @@ -1254,6 +1256,7 @@ input sizing (for config pages) .showlist-select optgroup, #pickShow optgroup, #showfilter optgroup, +#showsort optgroup, #editAProvider optgroup{ color:#eee; background-color:#888 @@ -1262,6 +1265,7 @@ input sizing (for config pages) .showlist-select optgroup option, #pickShow optgroup option, #showfilter optgroup option, +#showsort optgroup option, #editAProvider optgroup option{ color:#222; background-color:#fff diff --git a/gui/slick/css/style.css b/gui/slick/css/style.css index ff26b39d..78eca8f2 100644 --- a/gui/slick/css/style.css +++ b/gui/slick/css/style.css @@ -882,6 +882,12 @@ home.tmpl background-image:linear-gradient(to left, rgba(223, 218, 207, 1), rgba(223, 218, 207, 0)) } +.show-toggle-hide{ + position:absolute; + top:272px; + right:2px +} + .show-date{ position:relative; overflow:hidden; diff --git a/gui/slick/interfaces/default/home_browseShows.tmpl b/gui/slick/interfaces/default/home_browseShows.tmpl index a11a2a73..d4f7a12a 100644 --- a/gui/slick/interfaces/default/home_browseShows.tmpl +++ b/gui/slick/interfaces/default/home_browseShows.tmpl @@ -38,41 +38,40 @@ $(document).ready(function(){ // initialise combos for dirty page refreshes - $('#showsort').val('original'); - $('#showsortdirection').val('asc'); - $('#showfilter').val('*'); + $('#showsort').val('*'); - var $container = [$('#container')]; - jQuery.each($container, function(j){ - this.isotope({ - itemSelector: '.show-card', - sortBy: 'original-order', - layoutMode: 'masonry', - masonry: { - columnWidth: 188, - isFitWidth: !0, - gutter: 12 - }, - getSortData: { - premiered: '[data-premiered] parseInt', - name: function( itemElem ) { - var name = $( itemElem ).attr('data-name') || ''; + $('#container').isotope({ + itemSelector: '.show-card', + sortBy: 'original-order', + layoutMode: 'masonry', + masonry: { + columnWidth: 188, + isFitWidth: !0, + gutter: 12 + }, + getSortData: { + premiered: '[data-premiered] parseInt', + name: function( itemElem ) { + var name = $( itemElem ).attr('data-name') || ''; #end raw -#if not $sg_var('SORT_ARTICLE'): - name = name.replace(/^(?:(?:A(?!\s+to)n?)|The)\s(\w)/i, '$1'); +#if not $sg_var('SORT_ARTICLE') + name = name.replace(/^(?:(?:A(?!\s+to)n?)|The)\s(\w)/i, '$1'); #end if #raw - return name.toLowerCase(); - }, - rating: '[data-rating] parseInt', - votes: '[data-votes] parseInt', - } - }); + return name.toLowerCase(); + }, + rating: '[data-rating] parseInt', + votes: '[data-votes] parseInt', + } }); $('#showsort').on('change', function(){ var sortCriteria, el$ = $('#container'), shuffle = !1; - switch (this.value) { + switch (this.value.replace('by_', '')) { + case 'asc': + case 'desc': + sortCriteria = 'order'; + break; case 'original': sortCriteria = 'original-order' break; @@ -95,33 +94,84 @@ $(document).ready(function(){ break; } - if (!shuffle){ + var showSort = $('#showsort option'); + if('order' === sortCriteria){ + showSort.filter($('option[value="asc"], option[value="desc"]')).removeClass('selected'); + showSort.filter($('option[value="' + this.value + '"]')).addClass('selected'); + el$.one('layoutComplete', llUpdate); - el$.isotope({sortBy: sortCriteria}); - } else { - // shuffle rating_votes where it can already be sorted by ratings which leaves it nothing to do. - function t(sortCriteria, lastPhase){ - return function(){ - var el$ = $('#container'); - if (!lastPhase){ - lastPhase = !0; - el$.isotope({sortBy: sortCriteria}); - } else { - el$.off('layoutComplete'); - el$.isotope('layout'); - llUpdate(); + el$.isotope({sortAscending: 'asc' == this.value}); + } else if(0 == this.value.indexOf('by_')){ + showSort.filter($('option[value^="by_"][class*="selected"]')).removeClass('selected'); + showSort.filter($('option[value="' + this.value + '"]')).addClass('selected'); + + if (!shuffle){ + el$.one('layoutComplete', llUpdate); + el$.isotope({sortBy: sortCriteria}); + } else { + // shuffle rating_votes where it can already be sorted by ratings which leaves it nothing to do. + function t(sortCriteria, lastPhase){ + return function(){ + var el$ = $('#container'); + if (!lastPhase){ + lastPhase = !0; + el$.isotope({sortBy: sortCriteria}); + } else { + el$.off('layoutComplete'); + el$.isotope('layout'); + llUpdate(); + } } } + el$.on('layoutComplete', t(sortCriteria, !1)); + el$.isotope({sortBy: 'random'}); } - el$.on('layoutComplete', t(sortCriteria, !1)); - el$.isotope({sortBy: 'random'}); + } else { + showSort.filter($('option[value^="*"], #showsort option[value^="."]')).removeClass('selected'); + showSort.filter($('option[value="' + this.value + '"]')).addClass('selected'); + + var showCards = $('.show-card'), filter = this.value; + if('.hide' === this.value){ + showCards.filter($('.hide')).removeClass('hide').addClass('to-hide'); + filter = '.to-hide'; + } else { + showCards.filter($('.to-hide')).removeClass('to-hide').addClass('hide'); + } + + var el$ = $('#container'); + el$.one('layoutComplete', llUpdate); + el$.isotope({ filter: filter }); } }); - $('#showsortdirection').on('change', function(){ - var el$ = $('#container') - el$.one('layoutComplete', llUpdate); - el$.isotope({sortAscending: ('asc' == this.value)}); + $('#container').on('click', '.show-toggle-hide', function(event){ + var that = $(this); + event.preventDefault(); + + $.getJSON(this.href, function(data){ + if(data.success){ + var showCards = $('.show-card'), thisCard = $(that).parents('div[class*="show-card "]'), + numShows = showCards.length, numHidden, showSort = $('#showsort option'), filter = 'to-hide'; + + if(thisCard.hasClass(filter)){ + title = 'Hide'; + thisCard.removeClass(filter); + } else { + filter = 'hide'; + title = 'Unhide'; + thisCard.addClass(filter); + } + numHidden = showCards.filter($('.' + filter)).length; + that.attr('title', title); + + showSort.filter($('option[value=".hide"]')).text('Hidden (' + numHidden + ')'); + showSort.filter($('option[value="*"]')).text('All (' + (0 == numHidden ? '' : (numShows - numHidden) + '/') + numShows + ')'); + + var el$ = $('#container') + el$.on('layoutComplete', llUpdate); + el$.isotope(); + } + }); }); $('#showfilter').on('change', function(){ @@ -160,15 +210,35 @@ $(document).ready(function(){ #set $mode = $kwargs and $kwargs.get('mode', '') #if $all_shows or ($kwargs and $kwargs.get('show_header'))
- View: - + #set $num_all = len($all_shows) #set $selected = ' class="selected"' - #if 'Trakt' == $browse_type + + + + + #if 'Ani' not in $browse_type + + #end if + + + + + + + + + + + + + + + + #if 'Ani' not in $browse_type + #end if - - - Sort By: - - - Sort Order: -

$browse_title

- #if $kwargs and $kwargs.get('oldest'): + #if $kwargs and $kwargs.get('oldest')
First aired from $kwargs['oldest'] until $kwargs['newest']
@@ -264,7 +319,7 @@ $(document).ready(function(){
#if $all_shows #set $poster_id = 0 - #for $this_show in $all_shows: + #for $this_show in $all_shows #set $poster_id += 1 #set $title_html = $this_show['title'].replace('"', '"').replace("'", ''') @@ -276,7 +331,15 @@ $(document).ready(function(){ #set $overview = $this_show['overview'] #end if -
+ #set $known = 'not' + #set $show_id = $this_show['show_id'] + #if ':' in $show_id + #set $known = '' + #set $show_id = $show_id[2:] + #end if + #set $hide = ('', 'hide ')[$show_id in $sickbeard.BROWSELIST_HIDDEN] + +
#if $kwargs and 'newseasons' == $mode#Air#else#First air#end if##echo ('s', 'ed')[$this_show['when_past']]#: $this_show['premiered_str'] #if $this_show.get('ended_str')# - Ended: $this_show['ended_str']#end if#

Click for more at $browse_type"> - #if 'poster' in $this_show['images']: + #if 'poster' in $this_show['images'] #set $image = $this_show['images']['poster']['thumb'] - #else: + #else   #end if
@@ -298,17 +361,19 @@ $(document).ready(function(){
#echo ((re.sub('^((?:A(?!\s+to)n?)|The)\s(\w)', r'\1 \2', $this_show['title']), $this_show['title'])[$sg_var('SORT_ARTICLE')], ' ')['' == $this_show['title']]#
- + #if 'Ani' not in $browse_type + + #end if

$this_show['rating']%$this_show['votes'] votes

- #if 'url_tvdb' in $this_show and $this_show['url_tvdb']: + #if 'url_tvdb' in $this_show and $this_show['url_tvdb'] tvdb #end if
- #if ':' in $this_show['show_id']: + #if ':' in $this_show['show_id']

In library

#else Add Show @@ -323,7 +388,7 @@ $(document).ready(function(){
#end for
- #if $kwargs and $kwargs.get('footnote'): + #if $kwargs and $kwargs.get('footnote')
$kwargs['footnote']
@@ -331,7 +396,7 @@ $(document).ready(function(){ #else

- #if $kwargs and $kwargs.get('error_msg'): + #if $kwargs and $kwargs.get('error_msg') $kwargs['error_msg'] #else $browse_type API did not return results, this can happen from time to time. diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 4afcd539..fda97e5a 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -450,6 +450,7 @@ EPISODE_VIEW_DISPLAY_PAUSED = False EPISODE_VIEW_POSTERS = True EPISODE_VIEW_MISSED_RANGE = None HISTORY_LAYOUT = None +BROWSELIST_HIDDEN = [] FUZZY_DATING = False TRIM_ZERO = False @@ -541,7 +542,7 @@ def initialize(console_logging=True): EPISODE_VIEW_MISSED_RANGE, EPISODE_VIEW_POSTERS, FANART_PANEL, FANART_RATINGS, \ EPISODE_VIEW_VIEWMODE, EPISODE_VIEW_BACKGROUND, EPISODE_VIEW_BACKGROUND_TRANSLUCENT, \ DISPLAY_SHOW_VIEWMODE, DISPLAY_SHOW_BACKGROUND, DISPLAY_SHOW_BACKGROUND_TRANSLUCENT, \ - DISPLAY_SHOW_VIEWART, DISPLAY_SHOW_MINIMUM, DISPLAY_SHOW_SPECIALS, HISTORY_LAYOUT + DISPLAY_SHOW_VIEWART, DISPLAY_SHOW_MINIMUM, DISPLAY_SHOW_SPECIALS, HISTORY_LAYOUT, BROWSELIST_HIDDEN # Gen Config/Misc global LAUNCH_BROWSER, UPDATE_SHOWS_ON_START, SHOW_UPDATE_HOUR, \ TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, ACTUAL_LOG_DIR, LOG_DIR, INDEXER_TIMEOUT, ROOT_DIRS, \ @@ -1099,6 +1100,9 @@ def initialize(console_logging=True): EPISODE_VIEW_MISSED_RANGE = check_setting_int(CFG, 'GUI', 'episode_view_missed_range', 7) HISTORY_LAYOUT = check_setting_str(CFG, 'GUI', 'history_layout', 'detailed') + BROWSELIST_HIDDEN = [ + x.strip() for x in check_setting_str(CFG, 'GUI', 'browselist_hidden', '').split('|~|') if x.strip()] + # initialize NZB and TORRENT providers providerList = providers.makeProviderList() @@ -1849,6 +1853,7 @@ def save_config(): new_config['GUI']['showlist_tagview'] = SHOWLIST_TAGVIEW new_config['GUI']['show_tag_default'] = SHOW_TAG_DEFAULT new_config['GUI']['history_layout'] = HISTORY_LAYOUT + new_config['GUI']['browselist_hidden'] = '|~|'.join(BROWSELIST_HIDDEN) new_config['Subtitles'] = {} new_config['Subtitles']['use_subtitles'] = int(USE_SUBTITLES) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 7baa3109..be8414bc 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3373,6 +3373,10 @@ class NewHomeAddShows(Home): except (IndexError, KeyError): pass + if not normalised: + error_msg = 'No items in watchlist. Use the "Add to watchlist" button at the Trakt website' + return self.browse_shows(browse_type, browse_title, filtered, error_msg=error_msg, show_header=1, **kwargs) + oldest_dt = 9999999 newest_dt = 0 oldest = None @@ -3427,7 +3431,7 @@ class NewHomeAddShows(Home): kwargs.update(dict(oldest=oldest, newest=newest, error_msg=error_msg)) - if 'recommended' not in kwargs.get('mode', ''): + if 'recommended' not in kwargs.get('mode', '') and 'watchlist' not in kwargs.get('mode', ''): mode = kwargs.get('mode', '').split('-') if mode: func = 'trakt_%s' % mode[0] @@ -3438,6 +3442,20 @@ class NewHomeAddShows(Home): sickbeard.save_config() return self.browse_shows(browse_type, browse_title, filtered, **kwargs) + @staticmethod + def show_toggle_hide(ids): + save_config = False + for sid in ids.split(':'): + if 3 < len(sid) < 12: + save_config = True + if sid in sickbeard.BROWSELIST_HIDDEN: + sickbeard.BROWSELIST_HIDDEN.remove(sid) + else: + sickbeard.BROWSELIST_HIDDEN += [sid] + if save_config: + sickbeard.save_config() + return json.dumps({'success': save_config}) + @staticmethod def encode_html(text): @@ -3463,7 +3481,8 @@ class NewHomeAddShows(Home): t.kwargs = kwargs dedupe = [] - t.all_shows_inlibrary = 0 + t.num_inlibrary = 0 + t.num_hidden = 0 for item in shows: item['show_id'] = '' for index, tvdb in enumerate(['tvdb', 'tvrage']): @@ -3475,7 +3494,7 @@ class NewHomeAddShows(Home): # check tvshow indexer is not using the same id from another indexer if tvshow and (index + 1) == tvshow.indexer: item['show_id'] = u'%s:%s' % (tvshow.indexer, tvshow.indexerid) - t.all_shows_inlibrary += 1 + t.num_inlibrary += 1 break if None is not config.to_int(item['show_id'], None): @@ -3488,6 +3507,9 @@ class NewHomeAddShows(Home): dedupe.append(item['show_id']) t.all_shows.append(item) + if item['show_id'].split(':')[-1] in sickbeard.BROWSELIST_HIDDEN: + t.num_hidden += 1 + return t.respond() def import_shows(self, *args, **kwargs):