diff --git a/gui/slick/css/style.css b/gui/slick/css/style.css index fc2e45c02296549b9130ddf88b591d689172ae48..8e403ceedff6c3c17e8a9ca372049247b8e0fd1c 100644 --- a/gui/slick/css/style.css +++ b/gui/slick/css/style.css @@ -1386,7 +1386,7 @@ schedule.mako ========================================================================== */ .key { - margin-bottom: 20px; + line-height: 30px; } .listing-key { @@ -1408,6 +1408,10 @@ schedule.mako background-color: #FFDDDD; } +.listing-snatched { + background-color: #EBC1EA; +} + .listing-toofar { background-color: #BEDEED; } @@ -1427,6 +1431,11 @@ span.listing-overdue { border: 1px solid #890000; } +span.listing-snatched { + color: #652164; + border: 1px solid #652164; +} + span.listing-toofar { color: #1D5068; border: 1px solid #1D5068; diff --git a/gui/slick/js/ajaxEpSearch.js b/gui/slick/js/ajaxEpSearch.js index ca107faabae57203a9917db2fd7d2b082fc610b8..75c20dfe34894d18007e73f5dd62c33c65d27af8 100644 --- a/gui/slick/js/ajaxEpSearch.js +++ b/gui/slick/js/ajaxEpSearch.js @@ -94,10 +94,24 @@ function updateImages(data) { spanCompleteEpisodes.prop('title','Search'); spanCompleteEpisodes.prop('alt','Search'); if (ep.overview.toLowerCase() === 'snatched') { - elementCompleteEpisodes.closest('tr').remove(); - } else { - enableLink(elementCompleteEpisodes); + // Find Banner or Poster + var actionElement = elementCompleteEpisodes.closest('div.ep_listing'); + if (actionElement.length === 0) { + if (elementCompleteEpisodes.closest('table.calendarTable').length === 0) { + // List view + actionElement = elementCompleteEpisodes.closest('tr'); + } + // else - Calendar view is ignored + } + + if (actionElement.length) { + // remove any listing-* classes and add listing-snatched (keeping non listing-* classes) + actionElement.attr('class', function (i, value) { + return value.replace(/(^|\s)listing-\S+/g, ''); + }).addClass('listing-snatched'); + } } + enableLink(elementCompleteEpisodes); } } }); diff --git a/gui/slick/views/schedule.mako b/gui/slick/views/schedule.mako index db05a1b48ee79fdb7c198ec7a4e77ccd8c93c0f4..0762b22644db25612677a87018fc0d61cc45977e 100644 --- a/gui/slick/views/schedule.mako +++ b/gui/slick/views/schedule.mako @@ -1,11 +1,15 @@ <%inherit file="/layouts/main.mako"/> <%! - import sickbeard - from sickbeard.helpers import anon_url - from sickbeard import sbdatetime import datetime import time import re + + import sickbeard + from sickbeard.helpers import anon_url + from sickbeard import sbdatetime + from sickbeard.common import Quality + + SNATCHED = Quality.SNATCHED + Quality.SNATCHED_PROPER + Quality.SNATCHED_BEST # type = list %> <%block name="scripts"> <script type="text/javascript" src="${srRoot}/js/ajaxEpSearch.js?${sbPID}"></script> @@ -16,17 +20,17 @@ <%namespace file="/inc_defs.mako" import="renderQualityPill"/> <div class="row"> <div class="col-md-12"> - <div class="pull-right"> + <div class="pull-right key"> % if 'calendar' != layout: <b>${_('Key')}:</b> <span class="listing-key listing-overdue">${_('Missed')}</span> + <span class="listing-key listing-snatched">${_('Snatched')}</span> <span class="listing-key listing-current">${_('Today')}</span> <span class="listing-key listing-default">${_('Soon')}</span> <span class="listing-key listing-toofar">${_('Later')}</span> % endif - <a class="btn btn-inline forceBacklog btn-cal-subscribe" href=""> - <i class="icon-calendar icon-white"></i> - ${_('Subscribe')} + <a class="btn btn-inline btn-cal-subscribe" href=""> + <i class="fa fa-calendar"></i>${_('Subscribe')} </a> </div> </div> @@ -107,6 +111,7 @@ <% cur_indexer = int(cur_result[b'indexer']) run_time = cur_result[b'runtime'] + snatched_status = int(cur_result[b'epstatus']) in SNATCHED if int(cur_result[b'paused']) and not sickbeard.COMING_EPS_DISPLAY_PAUSED: continue @@ -116,7 +121,12 @@ if run_time: cur_ep_enddate += datetime.timedelta(minutes = run_time) - if cur_ep_enddate < today: + if snatched_status: + if cur_result[b'location']: + continue + else: + show_div = 'listing-snatched' + elif cur_ep_enddate < today: show_div = 'listing-overdue' elif cur_ep_airdate >= next_week.date(): show_div = 'listing-toofar' @@ -222,6 +232,10 @@ <% continue %> % endif + % if int(cur_result[b'epstatus']) in SNATCHED: + <% continue %> + % endif + <% cur_indexer = int(cur_result[b'indexer']) %> <% run_time = cur_result[b'runtime'] %> <% airday = cur_result[b'localtime'].date() %> @@ -273,19 +287,25 @@ <!-- start non list view //--> <% cur_segment = None - too_late_header = False - missed_header = False - today_header = False show_div = 'ep_listing listing-default' + headers = { + 'snatched': _('Snatched'), + 'missed': _('Missed'), + 'later': _('Later') + } %> % for cur_result in results: <% cur_indexer = int(cur_result[b'indexer']) + snatched_status = int(cur_result[b'epstatus']) in SNATCHED if int(cur_result[b'paused']) and not sickbeard.COMING_EPS_DISPLAY_PAUSED: continue + if cur_result[b'location'] and snatched_status: + continue + run_time = cur_result[b'runtime'] cur_ep_airdate = cur_result[b'localtime'].date() @@ -293,6 +313,8 @@ cur_ep_enddate = cur_result[b'localtime'] + datetime.timedelta(minutes = run_time) else: cur_ep_enddate = cur_result[b'localtime'] + + this_day_name = datetime.date.fromordinal(cur_ep_airdate.toordinal()).strftime('%A').decode(sickbeard.SYS_ENCODING).capitalize() %> % if sickbeard.COMING_EPS_SORT == 'network': <% show_network = ('no network', cur_result[b'network'])[bool(cur_result[b'network'])] %> @@ -303,7 +325,9 @@ </div> % endif - % if cur_ep_enddate < today: + % if snatched_status: + <% show_div = 'ep_listing listing-snatched' %> + % elif cur_ep_enddate < today: <% show_div = 'ep_listing listing-overdue' %> % elif cur_ep_airdate >= next_week.date(): <% show_div = 'ep_listing listing-toofar' %> @@ -315,36 +339,36 @@ % endif % endif % elif sickbeard.COMING_EPS_SORT == 'date': - <div> - % if cur_segment != cur_ep_airdate: - % if cur_ep_enddate < today and cur_ep_airdate != today.date() and not missed_header: - <h2 class="day">${_('Missed')}</h2> - <% missed_header = True %> - % elif cur_ep_airdate >= next_week.date() and not too_late_header: - <h2 class="day">${_('Later')}</h2> - <% too_late_header = True %> - % elif cur_ep_enddate >= today and cur_ep_airdate < next_week.date(): - % if cur_ep_airdate == today.date(): - <h2 class="day">${datetime.date.fromordinal(cur_ep_airdate.toordinal()).strftime('%A').decode(sickbeard.SYS_ENCODING).capitalize()} - <span style="font-size: 14px; vertical-align: top;">[Today]</span> - </h2> - <% today_header = True %> - % else: - <h2 class="day">${datetime.date.fromordinal(cur_ep_airdate.toordinal()).strftime('%A').decode(sickbeard.SYS_ENCODING).capitalize()}</h2> - % endif - % endif - <% cur_segment = cur_ep_airdate %> - % endif + % if snatched_status: + <% cur_category = 'snatched' %> + % elif cur_ep_enddate < today and cur_ep_airdate != today.date(): + <% cur_category = 'missed' %> + % elif cur_ep_airdate >= next_week.date(): + <% cur_category = 'later' %> + % elif cur_ep_airdate == today.date(): + <% cur_category = 'today' %> + % elif cur_ep_enddate > today and cur_ep_airdate < next_week.date(): + <% cur_category = this_day_name %> + % endif - % if cur_ep_airdate == today.date() and not today_header: - <h2 class="day">${datetime.date.fromordinal(cur_ep_airdate.toordinal()).strftime('%A').decode(sickbeard.SYS_ENCODING).capitalize()} - <span style="font-size: 14px; vertical-align: top;">[Today]</span> + % if cur_segment != cur_category: + <div> + % if cur_category in ('snatched', 'missed', 'later'): + <h2 class="day">${headers[cur_category]}</h2> + % else: + <h2 class="day">${this_day_name} + % if cur_category == 'today': + <span style="font-size: 14px; vertical-align: top;">[${_('Today')}]</span> + % endif </h2> - <% today_header = True %> % endif - </div> + <% cur_segment = cur_category %> + </div> + % endif - % if cur_ep_enddate < today: + % if snatched_status: + <% show_div = 'ep_listing listing-snatched' %> + % elif cur_ep_enddate < today: <% show_div = 'ep_listing listing-overdue' %> % elif cur_ep_airdate >= next_week.date(): <% show_div = 'ep_listing listing-toofar' %> @@ -356,7 +380,9 @@ % endif % endif % elif sickbeard.COMING_EPS_SORT == 'show': - % if cur_ep_enddate < today: + % if snatched_status: + <% show_div = 'ep_listing listing-snatched listingradius' %> + % elif cur_ep_enddate < today: <% show_div = 'ep_listing listing-overdue listingradius' %> % elif cur_ep_airdate >= next_week.date(): <% show_div = 'ep_listing listing-toofar listingradius' %> diff --git a/sickrage/show/ComingEpisodes.py b/sickrage/show/ComingEpisodes.py index 76c3a4e790538b35a63ab806332c17886b5f90ff..bd8f431594735cbb984a575531f56d3f27c767d0 100644 --- a/sickrage/show/ComingEpisodes.py +++ b/sickrage/show/ComingEpisodes.py @@ -20,7 +20,7 @@ import sickbeard from datetime import date, timedelta -from sickbeard.common import WANTED, UNAIRED +from sickbeard.common import WANTED, UNAIRED, Quality from sickbeard.db import DBConnection from sickbeard.network_timezones import parse_date_time from sickbeard.sbdatetime import sbdatetime @@ -28,19 +28,21 @@ from sickrage.helper.common import dateFormat, timeFormat from sickrage.helper.quality import get_quality_string from operator import itemgetter +SNATCHED = Quality.SNATCHED + Quality.SNATCHED_PROPER + Quality.SNATCHED_BEST # type = list class ComingEpisodes(object): """ - Missed: yesterday...(less than 1 week) + Snatched: snatched but not yet processed (no re-downloads) + Missed: yesterday...(less than sickbeard.COMING_EPS_MISSED_RANGE) Today: today Soon: tomorrow till next week Later: later than next week """ - categories = ['later', 'missed', 'soon', 'today'] + categories = ['snatched', 'missed', 'today', 'soon', 'later'] sorts = { - 'date': (lambda a, b: a[b'localtime'] < b[b'localtime']), - 'network': (lambda a, b: (a[b'network'], a[b'localtime']) < (b[b'network'], b[b'localtime'])), - 'show': (lambda a, b: (a[b'show_name'], a[b'localtime']) < (b[b'show_name'], b[b'localtime'])), + 'date': itemgetter(b'snatchedsort', b'localtime'), + 'network': itemgetter(b'network', b'localtime'), + 'show': itemgetter(b'show_name', b'localtime'), } def __init__(self): @@ -65,10 +67,13 @@ class ComingEpisodes(object): db = DBConnection(row_type='dict') fields_to_select = ', '.join( - ['airdate', 'airs', 'e.description as description', 'episode', 'imdb_id', 'e.indexer', 'indexer_id', 'name', 'network', - 'paused', 'quality', 'runtime', 'season', 'show_name', 'showid', 's.status'] + ['airdate', 'airs', 'e.description as description', 'episode', 'imdb_id', 'e.indexer', 'indexer_id', + 'e.location', 'name', 'network', 'paused', 'quality', 'runtime', 'season', 'show_name', 'showid', + 'e.status as epstatus', 's.status'] ) + status_list = [WANTED, UNAIRED] + SNATCHED + sql_l = [] for show_obj in sickbeard.showList: next_air_date = show_obj.nextEpisode() @@ -80,8 +85,8 @@ class ComingEpisodes(object): 'AND airdate <= ? ' 'AND airdate >= ? ' 'AND s.indexer_id = e.showid ' - 'AND e.status IN (' + ','.join(['?'] * 2) + ')', - [show_obj.indexerid, next_air_date or today, recently, WANTED, UNAIRED] + 'AND e.status IN (' + ','.join(['?'] * len(status_list)) + ')', + [show_obj.indexerid, next_air_date or today, recently] + status_list ] ) @@ -95,9 +100,9 @@ class ComingEpisodes(object): for index, item in enumerate(results): results[index][b'localtime'] = sbdatetime.convert_to_setting( parse_date_time(item[b'airdate'], item[b'airs'], item[b'network'])) + results[index][b'snatchedsort'] = int(not results[index][b'epstatus'] in SNATCHED) - results.sort(key=itemgetter(b'localtime')) - results.sort(ComingEpisodes.sorts[sort]) + results.sort(key=ComingEpisodes.sorts[sort]) if not group: return results @@ -111,7 +116,12 @@ class ComingEpisodes(object): result[b'airs'] = str(result[b'airs']).replace('am', ' AM').replace('pm', ' PM').replace(' ', ' ') result[b'airdate'] = result[b'localtime'].toordinal() - if result[b'airdate'] < today: + if result[b'epstatus'] in SNATCHED: + if result[b'location']: + continue + else: + category = 'snatched' + elif result[b'airdate'] < today: category = 'missed' elif result[b'airdate'] >= next_week: category = 'later'