mirror of
https://github.com/SickGear/SickGear.git
synced 2024-11-25 06:15:04 +00:00
e56303798c
Initial SickGear for Python 3.
887 lines
41 KiB
Cheetah
887 lines
41 KiB
Cheetah
#import datetime
|
|
#import re
|
|
##
|
|
#import sickgear
|
|
#from sickgear import history, providers, WEB_PORT
|
|
#from sickgear.common import Quality, statusStrings, SNATCHED_ANY, SNATCHED_PROPER, DOWNLOADED, SUBTITLED, ARCHIVED, FAILED
|
|
#from sickgear.helpers import human
|
|
#from sickgear.providers import generic
|
|
#from sickgear.sgdatetime import SGDatetime
|
|
<% def sg_var(varname, default=False): return getattr(sickgear, varname, default) %>#slurp#
|
|
<% def sg_str(varname, default=''): return getattr(sickgear, varname, default) %>#slurp#
|
|
##
|
|
#import humanize
|
|
##
|
|
#set $layout = $sg_str('HISTORY_LAYOUT', 'detailed')
|
|
#set $layout_name = 'watched' in $layout and 'Watched' or 'stats' in $layout and 'Activity Hits' or 'provider_failures'in $layout and 'Connect Failures' or 'Activity'
|
|
#set sg_port = str($getVar('sbHttpPort', WEB_PORT))
|
|
#set global $title = 'History : %s' % $layout_name
|
|
#set global $header = 'History <span class="grey-text">: %s</span>' % $layout_name
|
|
#set global $sbPath = '..'
|
|
#set global $topmenu = 'home'
|
|
##
|
|
#import os.path
|
|
#include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_top.tmpl')
|
|
##
|
|
#set $checked = ' checked="checked"'
|
|
|
|
<script src="$sbRoot/js/history.js?v=$sbPID"></script>
|
|
|
|
<script>
|
|
<!--
|
|
\$.SickGear.history = {
|
|
layoutName: '$layout',
|
|
isCompact: #echo ('!1', '!0')['compact' in $layout]#,
|
|
isTrashit: #echo ('!1', '!0')[bool($sg_var('TRASH_REMOVE_SHOW'))]#,
|
|
useSubtitles: #echo ('!1', '!0')[bool($sg_var('USE_SUBTITLES'))]#,
|
|
lastDeleteFiles: '#echo ('', $checked)[$getVar('last_delete_files', False)]#',
|
|
lastDeleteRecords: '#echo ('', $checked)[$getVar('last_delete_records', False)]#',
|
|
};
|
|
|
|
\$(document).ready(function() {
|
|
|
|
#set $fuzzydate = 'airdate'
|
|
#if $sg_var('FUZZY_DATING')
|
|
fuzzyMoment({
|
|
containerClass: '.${fuzzydate}',
|
|
dateHasTime: !0,
|
|
dateFormat: '$sg_str('DATE_PRESET', '%x')',
|
|
timeFormat: '$sg_str('TIME_PRESET_W_SECONDS', '%I:%M:%S %p')',
|
|
trimZero: #echo ('!1', '!0')[$sg_var('TRIM_ZERO')]#,
|
|
dtGlue: ', '
|
|
});
|
|
#end if
|
|
});
|
|
//-->
|
|
</script>
|
|
|
|
#if $varExists('header')
|
|
<h1 class="header">$header</h1>
|
|
#else
|
|
<h1 class="title">$title</h1>
|
|
#end if
|
|
#if $varExists('earliest') and $earliest
|
|
<div class="grey-text" style="clear:both;margin:-8px 0 1.5em 2px;font-size:0.85em;float:left">
|
|
Stats range from <span class="${fuzzydate}">$SGDatetime.sbfdatetime($datetime.datetime.strptime(str($earliest), $history.dateFormat))</span> until <span class="${fuzzydate}">$SGDatetime.sbfdatetime($datetime.datetime.strptime(str($latest), $history.dateFormat))</span>
|
|
</div>
|
|
#end if
|
|
|
|
#set $selected = ' selected="selected" class="selected"'
|
|
##
|
|
<div id="results-sortby" class="h2footer pull-right">Layout:
|
|
<select name="limit" id="limit" class="form-control form-control-inline input-sm">
|
|
<option value="100"#echo ('', $selected)['100' == $limit]#>100</option>
|
|
<option value="250"#echo ('', $selected)['250' == $limit]#>250</option>
|
|
<option value="500"#echo ('', $selected)['500' == $limit]#>500</option>
|
|
<option value="0"#echo ('', $selected)['0' == $limit]#>All</option>
|
|
</select>
|
|
|
|
<span style="margin-left:5px">
|
|
<select name="HistoryLayout" class="form-control form-control-inline input-sm" onchange="location = this.options[this.selectedIndex].value">
|
|
<optgroup label="Activity">
|
|
<option value="$sbRoot/set-layout-history/?layout=compact"#echo ('', $selected)['compact' == $sg_str('HISTORY_LAYOUT')]#>Compact</option>
|
|
<option value="$sbRoot/set-layout-history/?layout=detailed"#echo ('', $selected)['detailed' == $sg_str('HISTORY_LAYOUT', 'detailed')]#>Detailed</option>
|
|
</optgroup>
|
|
<optgroup label="Watched">
|
|
<option value="$sbRoot/set-layout-history/?layout=compact_watched"#echo ('', $selected)['compact_watched' == $sg_str('HISTORY_LAYOUT')]#>Compact</option>
|
|
<option value="$sbRoot/set-layout-history/?layout=detailed_watched"#echo ('', $selected)['detailed_watched' == $sg_str('HISTORY_LAYOUT')]#>Detailed</option>
|
|
</optgroup>
|
|
<optgroup label="Stats">
|
|
<option value="$sbRoot/set-layout-history/?layout=compact_stats"#echo ('', $selected)['compact_stats' == $sg_str('HISTORY_LAYOUT')]#>Activity hits</option>
|
|
<option value="$sbRoot/set-layout-history/?layout=graph_stats"#echo ('', $selected)['graph_stats' == $sg_str('HISTORY_LAYOUT')]#>Graphed hits</option>
|
|
<option value="$sbRoot/set-layout-history/?layout=connect_failures"#echo ('', $selected)['connect_failures' == $sg_str('HISTORY_LAYOUT')]#>Connect fails</option>
|
|
</optgroup>
|
|
</select>
|
|
</span>
|
|
</div>
|
|
|
|
<style>
|
|
#watched-help thead tr th, #watched-help tbody tr td{text-align:left}
|
|
#watched-help tbody td ol, #watched-help tbody td ul, #watched-help tbody td p{margin-bottom:0}
|
|
#watched-help tbody td img{margin-right:3px}
|
|
#watched-help .vmid{vertical-align:middle}
|
|
#history-table .age{display:none}
|
|
#history-table.event-age .age{display:inline-block}
|
|
#history-table.event-age .date{display:none}
|
|
</style>
|
|
##
|
|
#if 'failure' not in $layout
|
|
##
|
|
<table id="history-table" data-table-group="$layout" class="sickbeardTable tablesorter $layout" cellspacing="1" border="0" cellpadding="0">
|
|
##
|
|
#end if
|
|
##
|
|
##
|
|
#if 'detailed' == $layout
|
|
##
|
|
##
|
|
<thead>
|
|
<tr>
|
|
<th class="text-nowrap">Time</th>
|
|
<th width="35%">Episode</th>
|
|
<th>Action</th>
|
|
<th>Provider</th>
|
|
<th>Quality</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tfoot>
|
|
<tr>
|
|
<th class="text-nowrap" colspan="5"> </th>
|
|
</tr>
|
|
</tfoot>
|
|
|
|
<tbody>
|
|
#for $hItem in $history_results
|
|
#set $curStatus, $curQuality = $Quality.splitCompositeStatus(int($hItem['action']))
|
|
#set $display_name = '<span data-sort="%s">%s - S%02iE%02i</span>' % (
|
|
$hItem['data_name'],
|
|
(('<span class="article">%s</span> %s' % ($hItem['name1'], $hItem['name2'])), $hItem['show_name'])[$sg_var('SORT_ARTICLE') or not $hItem['name1']],
|
|
int($hItem['season']), int($hItem['episode']))
|
|
<tr>
|
|
#set $curdatetime = $datetime.datetime.strptime(str($hItem['date']), $history.dateFormat)
|
|
<td><div class="${fuzzydate}" data-sort="$time.mktime($curdatetime.timetuple())">$SGDatetime.sbfdatetime($curdatetime, show_seconds=True)</div></td>
|
|
<td class="tvShow"><a href="$sbRoot/home/view-show?tvid_prodid=$hItem['tvid_prodid']#season-$hItem['season']">$display_name#if $Quality.splitCompositeStatus($hItem['action'])[0] == $SNATCHED_PROPER then ' <span class="quality Proper">Proper</span>' else ''#</a></td>
|
|
<td#echo ('', ' class="subtitles_column"')[$SUBTITLED == $curStatus]#>
|
|
#if $SUBTITLED == $curStatus
|
|
<img width="16" height="11" src="$sbRoot/images/flags/<%= hItem["resource"][len(hItem["resource"])-6:len(hItem["resource"])-4] + '.png' %>">
|
|
#end if
|
|
<span class="help" title="$os.path.basename($hItem["resource"])">$statusStrings[$curStatus].replace('SD DVD', 'SD DVD/BR/BD')</span>
|
|
</td>
|
|
<td class="provider">
|
|
#if $DOWNLOADED == $curStatus
|
|
#if '-1' != $hItem['provider']
|
|
<span><i>$hItem['provider']</i></span>
|
|
#end if
|
|
#else
|
|
#if '-1' != $hItem['provider'] and len($hItem['provider'])
|
|
#if $curStatus in $SNATCHED_ANY + [$FAILED]
|
|
#set $provider = $providers.getProviderClass($generic.GenericProvider.make_id($hItem['provider']))
|
|
#if None is not $provider
|
|
<img src="$sbRoot/images/providers/<%= provider.image_name() %>" width="16" height="16" /><span>$provider.name</span>
|
|
#else
|
|
<img src="$sbRoot/images/providers/missing.png" width="16" height="16" title="missing provider" /><span>Missing Provider</span>
|
|
#end if
|
|
#else
|
|
<img src="$sbRoot/images/subtitles/<%= hItem['provider']+'.png' %>" width="16" height="16" /><span><%= hItem['provider'].capitalize() %></span>
|
|
#end if
|
|
#end if
|
|
#end if
|
|
</td>
|
|
<td><span class="hide">$curQuality</span><span class="quality $Quality.get_quality_css($curQuality)">$Quality.get_quality_ui($curQuality)</span></td>
|
|
</tr>
|
|
#end for
|
|
##
|
|
##
|
|
#elif ('compact' == $layout)
|
|
##
|
|
##
|
|
<thead>
|
|
<tr>
|
|
<th class="text-nowrap">Time</th>
|
|
<th width="#echo '3%s%%' % ('5', '0')[$sg_var('USE_SUBTITLES')]#">Episode</th>
|
|
<th>Snatched</th>
|
|
<th>Downloaded</th>
|
|
#if $sg_var('USE_SUBTITLES')
|
|
<th>Subtitled</th>
|
|
#end if
|
|
<th width="14%">Quality</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tfoot>
|
|
<tr>
|
|
<th class="text-nowrap" colspan="6"> </th>
|
|
</tr>
|
|
</tfoot>
|
|
|
|
<tbody>
|
|
#for $hItem in $compact_results
|
|
#set $curdatetime = $datetime.datetime.strptime(str($hItem['actions'][0]['time']), $history.dateFormat)
|
|
#set $display_name = '<span data-sort="%s">%s - S%02iE%02i</span>' % (
|
|
$hItem['data_name'],
|
|
(('<span class="article">%s</span> %s' % ($hItem['name1'], $hItem['name2'])), $hItem['show_name'])[$sg_var('SORT_ARTICLE') or not $hItem['name1']],
|
|
int($hItem['season']), int($hItem['episode']))
|
|
#set $prov_list = []
|
|
#set $down_list = []
|
|
#set $order = 1
|
|
#set $ordinal_indicators = {'1':'st', '2':'nd', '3':'rd'}
|
|
#for $action in reversed($hItem['actions'])
|
|
#set $curStatus, $curQuality = $Quality.splitCompositeStatus(int($action['action']))
|
|
#set $basename = $os.path.basename($action['resource'])
|
|
#if $curStatus in $SNATCHED_ANY + [$FAILED]
|
|
#set $provider = $providers.getProviderClass($generic.GenericProvider.make_id($action['provider']))
|
|
#if None is not $provider
|
|
#set $prov_list += ['<span%s><img class="help" src="%s/images/providers/%s" width="16" height="16" alt="%s" title="%s.. %s: %s" /></span>'\
|
|
% (('', ' class="fail"')[$FAILED == $curStatus], $sbRoot, $provider.image_name(), $provider.name,
|
|
('%s%s' % ($order, 'th' if $order in [11, 12, 13] or str($order)[-1] not in $ordinal_indicators else $ordinal_indicators[str($order)[-1]]), 'Snatch failed')[$FAILED == $curStatus],
|
|
$provider.name, $basename)]
|
|
#set $order += (0, 1)[$curStatus in $SNATCHED_ANY]
|
|
#else
|
|
#set $prov_list += ['<img src="%s/images/providers/missing.png" width="16" height="16" alt="missing provider" title="missing provider" />'\
|
|
% $sbRoot]
|
|
#end if
|
|
#end if
|
|
#if $curStatus in [$DOWNLOADED, $ARCHIVED]
|
|
#set $match = $re.search(r'\-(\w+)\.\w{3}\Z', $basename)
|
|
#set $non_scene_note = ''
|
|
#if not $match
|
|
## This fallback is for when idiots add a space and word to a release group. The space is converted
|
|
## to '\' which makes the regex parsing the scene group name fail, therefore we arrive here.
|
|
## A better solution would be to find where such data is parsed and saved to the db and perhaps
|
|
## fix at that point. But, in the meantime...
|
|
#set $non_scene_resource = re.sub(r'(\-\w+)([\\]\w+)?(\.\w{3})\Z', r'\1\3', $action['resource'])
|
|
#if $non_scene_resource
|
|
#set $non_scene_note = ' (Non scene name: %s)' % $action['resource'].partition('-')[-1]
|
|
#set $basename = $os.path.basename($non_scene_resource)
|
|
#set $match = $re.search(r'\-(\w+)\.\w{3}\Z', $basename)
|
|
#end if
|
|
#end if
|
|
#if $match
|
|
#if $match.group(1).upper() in ('X264', '720P')
|
|
#set $match = $re.search(r'(\w+)\-.*\-' + $match.group(1) + r'\.\w{3}\Z', $os.path.basename($hItem['resource']), re.I)
|
|
#end if
|
|
#if $match
|
|
#set $down_list += ['<span class="help" title="%s%s"><i>%s</i></span>'\
|
|
% ($basename, $non_scene_note, $match.group(1).upper())]
|
|
#end if
|
|
#end if
|
|
#end if
|
|
#end for
|
|
<tr>
|
|
<td><div class="${fuzzydate}" data-sort="$time.mktime($curdatetime.timetuple())">$SGDatetime.sbfdatetime($curdatetime, show_seconds=True)</div></td>
|
|
<td class="tvShow">
|
|
<span><a href="$sbRoot/home/view-show?tvid_prodid=$hItem['tvid_prodid']#season-$hItem['season']">$display_name#if 'proper' in $hItem['resource'].lower or 'repack' in $hItem['resource'].lower then ' <span class="quality Proper">Proper</span>' else ''#</a></span>
|
|
</td>
|
|
<td class="provider" provider="<%= str(sorted(hItem['actions'], key=lambda x: x['time'], reverse=True)[0]['provider']) %>">
|
|
#echo ''.join($prov_list)#
|
|
</td>
|
|
<td>
|
|
#echo ' '.join($down_list)#
|
|
</td>
|
|
#if $sg_var('USE_SUBTITLES')
|
|
<td>
|
|
#for $action in reversed($hItem['actions'])
|
|
#set $curStatus, $curQuality = $Quality.splitCompositeStatus(int($action['action']))
|
|
#if $SUBTITLED == $curStatus
|
|
<img src="$sbRoot/images/subtitles/<%= action['provider'] + '.png' %>" width="16" height="16" alt="$action['provider']" title="<%= action['provider'].capitalize() %>:$os.path.basename($action['resource'])" />
|
|
<span> / </span>
|
|
<img width="16" height="11" src="$sbRoot/images/flags/<%= action['resource'][len(action['resource'])-6:len(action['resource'])-4] + '.png' %>" style="vertical-align:middle !important">
|
|
|
|
#end if
|
|
#end for
|
|
</td>
|
|
#end if
|
|
<td quality="$curQuality"><span class="quality $Quality.get_quality_css($curQuality)">$Quality.get_quality_ui($curQuality)</span></td>
|
|
</tr>
|
|
#end for
|
|
##
|
|
##
|
|
#elif 'watched' in $layout
|
|
##
|
|
##
|
|
<thead>
|
|
<tr>
|
|
<th><span class="date">Event Date</span><span class="age">Event Age</span></th>
|
|
<th width="8%">Played</th>
|
|
<th class="text-nowrap" width="15%">Label (Profile)</th>
|
|
<th class="text-nowrap">Episode</th>
|
|
<th class="text-nowrap" width="10%">Quality</th>
|
|
<th class="text-nowrap" width="10%">Size</th>
|
|
<th width="10%">Delete</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tfoot>
|
|
<tr>
|
|
<th>
|
|
<i style="background-image:url($sbRoot/images/legend16.png)" id="show-watched-help" title="Toggle help" class="add-qtip icon-glyph"></i>
|
|
<span id="row-count" style="font-size:12px;line-height:20px;float:left"></span>
|
|
</th>
|
|
<th colspan="4"></th>
|
|
<th><span id="sum-size" style="border-top:solid 1px #ddd">0 Bytes</span></th>
|
|
<th>
|
|
#if $len($results)
|
|
<input id="del-watched" type="button" class="btn" value="Submit">
|
|
#end if
|
|
</th>
|
|
</tr>
|
|
</tfoot>
|
|
|
|
<tbody id="tbody">
|
|
#if not $results
|
|
<tr colspan="7">
|
|
<td colspan="7" style="text-align:center">
|
|
<p>Media marked watched or unwatched will list in this space</p>
|
|
</td>
|
|
</tr>
|
|
#else
|
|
#for $hItem in $results
|
|
#if $hItem.hide
|
|
#continue
|
|
#end if
|
|
#set $compact = 'compact' in $layout and $hItem['rowid'] not in $mru_row_ids
|
|
##
|
|
#set $curdatetime = $datetime.datetime.fromtimestamp($hItem.get('date_watched'))
|
|
#set $curage = ($datetime.datetime.now() - $curdatetime).days
|
|
#set $display_name = '<span data-sort="%s"%s>%s - S%sE%s</span>' % (
|
|
$hItem.get('data_name'),
|
|
('', ' class="grey-text"')[$hItem.get('deleted')],
|
|
(('<span class="article">%s</span> %s' % ($hItem.get('name1'), $hItem.get('name2'))), $hItem.get('show_name'))[$sg_var('SORT_ARTICLE') or not $hItem.get('name1')],
|
|
$hItem.get('season'), $hItem.get('episode'))
|
|
<tr data-tvep-id="$hItem['tvep_id']" data-file="$hItem['location']"#if $compact# class="hide"#end if#>
|
|
<td>
|
|
<div class="date ${fuzzydate}" data-sort="$curage">$SGDatetime.sbfdatetime($curdatetime)</div>
|
|
<div class="age">${curage}d</div>
|
|
</td>
|
|
<td>
|
|
#set $float_played = int($hItem.get('played'))/100.0
|
|
#set $value = ($float_played, int($float_played))[int($float_played) == $float_played]
|
|
<span#if not $bool($int($value))# class="add-qtip" title="Marked Unwatched"#end if#>$value</span>
|
|
</td>
|
|
<td>
|
|
#set $label = re.sub(r'\{[^}]+\}$', '', $hItem.get('label'))
|
|
#set $client = ''
|
|
#try
|
|
#set $client = re.findall(r'\{([^}]+)\}$', $hItem.get('label'))[0].lower()
|
|
#set $client_label = ('%s %s' % ($client, $label)).strip(' ')
|
|
<img height="16px" style="margin-right:3px" src="$sbRoot/images/notifiers/${client}.png"><span data-sort="$client_label" style="vertical-align:middle">$label</span>
|
|
#except
|
|
<span data-sort="${label}">$label</span>
|
|
#pass
|
|
#end try
|
|
</td>
|
|
<td class="tvShow text-nowrap">
|
|
<span class="add-qtip#if not $hItem.get('deleted')#"#else# strike-deleted" title="file no longer exists"#end if#>
|
|
<a href="$sbRoot/home/view-show?tvid_prodid=$hItem['tvid_prodid']#season-$hItem.get('season')">$display_name</a>
|
|
</span>
|
|
</td>
|
|
<td quality="$hItem.get('quality')" class="text-nowrap">
|
|
<span class="quality $Quality.get_quality_css($hItem.get('quality')) add-qtip" title="#if $hItem.get('deleted')#file no longer exists#else#$hItem['location']#end if#">$Quality.qualityStrings[$hItem.get('quality')].replace('SD DVD', 'SD DVD/BR/BD')</span>
|
|
</td>
|
|
<td class="size text-nowrap">
|
|
<span#if $hItem.get('deleted')# class="add-qtip grey-text strike-deleted" title="file no longer exists"#end if# data-sort="$hItem.get('file_size')">$human($hItem.get('file_size'))</span>
|
|
</td>
|
|
<td class="#echo ('green', 'red')[100 > $hItem.get('mru_count')]#-bg">
|
|
<input id="del-$hItem.get('rowid')-$hItem.get('tvid')-$hItem.get('prodid')"
|
|
title="last event<br>#echo ('watched', 'unwatched')[100 > $hItem.get('mru_count')]#"
|
|
type="checkbox" class="del-check add-qtip">
|
|
#if $hItem.get('mru_count')
|
|
<span style="position:absolute">
|
|
<i class="icon-glyph" style="top:-6px;right:4px;position:relative; opacity: 0.4;background-position: -95px -119px"></i>
|
|
</span>
|
|
#end if
|
|
</td>
|
|
</tr>
|
|
#end for
|
|
#end if
|
|
</tbody>
|
|
</table>
|
|
|
|
#def row_class()
|
|
#set global $row += 1
|
|
#echo ('even', 'odd')[bool($row % 2)]
|
|
#end def
|
|
<table id="watched-help" style="#if $hide_watched_help#display:none;#end if#margin-top:15px" class="sickbeardTable tablesorter" cellspacing="1" border="0" cellpadding="0">
|
|
<thead>
|
|
<tr>
|
|
<th colspan="2">General help</th>
|
|
</tr>
|
|
</thead>
|
|
#set global $row = 0
|
|
<tbody>
|
|
<tr class="$row_class()">
|
|
<td colspan="2">
|
|
<p>Filters are saved per layout. Examples;</p>
|
|
<ul>
|
|
<li>Event Date/Age, or Played: <span class="grey-text">>7 and <60</span> (between 7d and 60d) , <span class="grey-text">>1</span> (played more than once)</li>
|
|
<li>Label (Profile): <span class="grey-text">emby or kodi</span> , <span class="grey-text">!kodi and !plex</span> , <span class="grey-text">emby user2</span> , <span class="grey-text">emby user"</span> (single end quote excludes user2)</li>
|
|
<li>Quality: <span class="grey-text">sd or dl</span> , <span class="grey-text">blu</span></li>
|
|
<li>Size: <span class="grey-text"><0</span> (deleted media) <span class="grey-text">>321000000</span> (files greater than byte size)</li>
|
|
</ul>
|
|
</td>
|
|
</tr>
|
|
<tr class="$row_class()">
|
|
<td colspan="2">
|
|
<p>The above table is sorted first by played and then by date of event (i.e. watched/unwatched)</p>
|
|
</td>
|
|
</tr>
|
|
<tr class="$row_class()">
|
|
<td colspan="2">
|
|
<p>To multi-select checkboxes or column headers, click then hold shift and click</p>
|
|
</td>
|
|
</tr>
|
|
<tr class="$row_class()">
|
|
<td colspan="2">
|
|
<p style="margin-bottom:6px">Key for <span class="grey-text">Delete</span> column;</p>
|
|
<ul>
|
|
<li style="line-height:25px"><span class="contrast-text green-bg" style="padding:4px 18px 0 6px;margin:0 6px 0 0">Green
|
|
<span style="position:absolute">
|
|
<i class="icon-glyph" style="position:relative;top:-2px;right:8px;opacity: 0.4;background-position:-95px -119px"></i>
|
|
</span>
|
|
</span>Watched at least once at client</li>
|
|
<li style="line-height:25px"><span class="contrast-text red-bg" style="padding:4px 20px 0 6px;margin:0 6px 0 0">Red
|
|
</span>Partially watched or set 'unwatched' at client
|
|
</li>
|
|
</ul>
|
|
</td>
|
|
</tr>
|
|
<tr class="$row_class()">
|
|
<td colspan="2">
|
|
<p>To find how much freespace a delete will yield, the size tally increases for selected episodes that have a media file</p>
|
|
</td>
|
|
</tr>
|
|
<tr class="$row_class()">
|
|
<td colspan="2">
|
|
<p>A mapping in the client notification section is needed for results if a player library folder is different to a parent folder</p>
|
|
</td>
|
|
</tr>
|
|
<tr class="$row_class()">
|
|
<td colspan="2">
|
|
<p>In <span class="grey-text">Compact</span> layout, deleting records removes all episode related records. <span class="grey-text">Detailed</span> layout allows for individual selection [<a rel="dialog" href="https://raw.githubusercontent.com/wiki/SickGear/SickGear/images/screenies/watched.png">Show me</a>]</p>
|
|
</td>
|
|
</tr>
|
|
<tr class="$row_class()">
|
|
<td colspan="2">
|
|
<p>Any script can add to the watched list by making a <a href="https://github.com/SickGear/SickGear/wiki/API#sg.updatewatchedstate">documented API call</a> to <code>sg.updatewatchedstate</code></p>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
<thead>
|
|
<tr>
|
|
<th width="20%">Supported clients</th>
|
|
<th>To use</th>
|
|
</tr>
|
|
</thead>
|
|
#set global $row = 0
|
|
<tbody>
|
|
<tr class="$row_class()">
|
|
<td><img height="16px" src="$sbRoot/images/notifiers/kodi.png"><span class="vmid">Kodi</span>
|
|
<br><em class="grey-text">Matrix and newer builds</em>
|
|
<p>Episodes marked watched or unwatched are pushed in real-time and shown above.</p>
|
|
</td>
|
|
<td>
|
|
<p>Oct 2022: Replace "<span class="grey-text">/kodi/</span>" with "<span class="grey-text">/kodi-legacy/</span>" in the following guide for Leia, Krypton, Jarvis, or Isengard</p>
|
|
<br>
|
|
<p>In Kodi media player;</p>
|
|
<ol>
|
|
<li>Install the SickGear repo to access its Kodi Add-on
|
|
<ul style="padding-left:20px">
|
|
<li>in <b class="boldest">Filemanager</b>, add a source with <span class="grey-text"><ip>:<port>/kodi/</span> (e.g. <span class="grey-text">http://192.168.0.10:$sg_port/kodi/</span> or<br>
|
|
for SSL <span class="grey-text">https://192.168.0.10:$sg_port/kodi/</span> ... <a href="https://github.com/SickGear/SickGear/wiki/Install-SickGear-%5B81%5D-Media-Apps">see SSL guide</a>) and name it for example, <span class="grey-text">SickGear</span><br>
|
|
- <em>You must allow <span class="highlight-text">Unknown Sources</span> in Kodi settings if not already</em> </li>
|
|
<li>in <b class="boldest">System/Add-ons</b>, "<span class="grey-text">Install from zip file</span>", select the <span class="grey-text">SickGear</span> source</li>
|
|
<li>select <span class="grey-text">repository.sickgear</span> from the list, and install the repository zip<br>
|
|
- <em>Kodi will connect to the SickGear app to download and install its Add-on repository</em></li>
|
|
</ul>
|
|
<li>Install the SickGear Add-on from the repo</li>
|
|
<ul style="padding-left:20px">
|
|
<li>in <b class="boldest">System/Add-ons</b>, "<span class="grey-text">Install from zip repository</span>", select "<span class="grey-text">SickGear Add-on repository</span>" / "<span class="grey-text">Services</span>"<br>
|
|
<li>select Add-on "<span class="grey-text">SickGear Watched State Updater</span>"</li>
|
|
<li>configure Add-on and restart Kodi after install or after switching profiles for the first time</li>
|
|
</ul>
|
|
</ol>
|
|
</td>
|
|
</tr>
|
|
<tr class="$row_class()">
|
|
<td><img height="16px" src="$sbRoot/images/notifiers/emby.png"><span class="vmid">Emby</span>
|
|
<p>Episode watch states are periodically fetched and shown above.</p>
|
|
</td>
|
|
<td>
|
|
<ol>
|
|
<li>Enable Emby Media Server in <b class="boldest">config/Notifications</b></li>
|
|
<li>Choose an interval for updating watched states</li>
|
|
</ol>
|
|
</td>
|
|
</tr>
|
|
<tr class="$row_class()">
|
|
<td><img height="16px" src="$sbRoot/images/notifiers/plex.png"><span class="vmid">Plex</span>
|
|
<p>Episode watch states are periodically fetched and shown above.</p>
|
|
</td>
|
|
<td>
|
|
<ol>
|
|
<li>Enable Plex Media Server in <b class="boldest">config/Notifications</b></li>
|
|
<li>Choose an interval for updating watched states</li>
|
|
</ol>
|
|
</td>
|
|
</tr>
|
|
##
|
|
##
|
|
#elif 'stats' in $layout
|
|
##
|
|
##
|
|
#set sum = 0
|
|
#for $hItem in $stat_results
|
|
#set $sum += $hItem['count']
|
|
#end for
|
|
##
|
|
#if 'graph' in $layout
|
|
<tbody>
|
|
<tr><td>
|
|
#set $labels = []
|
|
#set $perc = []
|
|
#for $hItem in $stat_results
|
|
#set $p = (float($hItem['count']) / float($sum)) * 100
|
|
#if 1 <= $p:
|
|
#set $labels += [$hItem['provider']]
|
|
#set $perc += ['%s' % re.sub(r'(\d+)(\.\d)\d+', r'\1\2', str($p))]
|
|
#end if
|
|
#end for
|
|
<script src="$sbRoot/js/plot.ly/plotly-latest.min.js?v=$sbPID"></script>
|
|
<script src="$sbRoot/js/plot.ly/numeric/1.2.6/numeric.min.js?v=$sbPID"></script>
|
|
|
|
<div id="plot-canvas" style="margin:15px auto 15px;width:550px;height:350px"></div>
|
|
<style>
|
|
.modebar-btn[data-title*="edit plot"]{display:none !important}
|
|
</style>
|
|
<script>
|
|
Plotly.newPlot('plot-canvas', [
|
|
{
|
|
values: [#echo ', '.join($perc)#],
|
|
labels: [#echo '\'%s\'' % '\', \''.join($labels)#],
|
|
name: 'SickGear provider activity',
|
|
hoverinfo: 'label+percent+name',
|
|
domain: {x: [0, .5]},
|
|
hole: .42,
|
|
type: 'pie'
|
|
}
|
|
],
|
|
{title: 'SickGear provider activity (1% and above for #echo ('latest %s' % $limit, 'all')['0' == $limit]#)',
|
|
annotations: [{font: {size: 14}, showarrow: false, text: 'Activity', x: 0.16, y: 0.5}]
|
|
}, {displaylogo: !1, showLink: !1});
|
|
</script>
|
|
</td></tr>
|
|
##
|
|
##
|
|
#else
|
|
##
|
|
##
|
|
<thead>
|
|
<tr>
|
|
<th>Provider</th>
|
|
<th>Activity Hits</th>
|
|
<th>Activity %</th>
|
|
<th>Latest Activity</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tfoot>
|
|
<tr>
|
|
<th class="text-nowrap" colspan="4"> </th>
|
|
</tr>
|
|
</tfoot>
|
|
|
|
<tbody>
|
|
#for $hItem in $stat_results
|
|
<tr>
|
|
<td class="provider text-nowrap">
|
|
#set $provider = $providers.getProviderClass($generic.GenericProvider.make_id($hItem['provider']))
|
|
#if None is not $provider
|
|
<img src="$sbRoot/images/providers/<%= provider.image_name() %>" width="16" height="16"><span data-sort="$hItem['provider']">$provider.name</span>
|
|
#else
|
|
<img src="$sbRoot/images/providers/missing.png" width="16" height="16" title="missing provider"><span data-sort="$hItem['provider']">Missing Provider</span>
|
|
#end if
|
|
</td>
|
|
<td>$hItem['count']</td>
|
|
<td>#echo '%s%%' % re.sub(r'(\d+)(\.\d)\d+', r'\1\2', str((float($hItem['count'])/float($sum))*100))#</td>
|
|
#set $curdatetime = $datetime.datetime.strptime(str($hItem['latest']), $history.dateFormat)
|
|
<td><div class="${fuzzydate}" data-sort="$hItem['latest']">$SGDatetime.sbfdatetime($curdatetime)</div></td>
|
|
</tr>
|
|
#end for
|
|
#end if
|
|
##
|
|
##
|
|
#elif 'failures' in $layout
|
|
##
|
|
##
|
|
<div id="server-failures">
|
|
<div style="padding-bottom:10px">
|
|
#for ($check, $check_name, $check_url) in [
|
|
('tvdb', 'TVDB Api', 'api.thetvdb.com'), ('thexem', 'The Xem', 'thexem.info'), ('github', 'GitHub', 'github.com'),
|
|
]
|
|
<div id="check-$check" data-check="check_$check" class="check-site" style="margin-bottom:10px">
|
|
<input type="button" class="btn" value="Check $check_name">
|
|
<span style="line-height:26px">Test if site is up<span class="result"></span>
|
|
<a class="addQTip" style="margin-left:2px;display:none" href="$sickgear.helpers.anon_url('http://www.isitdownrightnow.com/downorjustme.php?url=' + $check_url)" rel="noreferrer" onclick="window.open(this.href, '_blank'); return !1;" title="View full report for $check_name in new tab"><img alt="[IsItDown]" height="16" width="16" src="$sbRoot/images/iidrn.png" /></a>
|
|
</span>
|
|
</div>
|
|
#end for
|
|
</div>
|
|
|
|
#if $sickgear.USE_NZBS
|
|
<style>
|
|
table.last_rls th{padding-right:20px}
|
|
table.last_rls td{vertical-align:middle;line-height:1.1em}
|
|
table.last_rls span.prov-name{display:inline-block;white-space:nowrap;overflow:hidden;vertical-align: middle}
|
|
table.last_rls img{margin:0 5px}
|
|
.status{padding:4px 20px;display:block}
|
|
</style>
|
|
<div style="padding-bottom:20px">
|
|
<table style="margin-bottom:10px" class="manageTable last_rls server-failures tablesorter hover-highlight focus-highlight text-center tablesorter-default" cellspacing="0" border="0" cellpadding="0">
|
|
<thead>
|
|
<tr>
|
|
<th class="text-left" style="width:13em"></th>
|
|
<th class="text-center">last release age</th>
|
|
<th class="text-center">dated</th>
|
|
<th class="text-center">provider is...</th>
|
|
</tr>
|
|
</thead>
|
|
#set global $row = 0
|
|
<tbody>
|
|
#for $cur_provider in $sorted($sickgear.newznabProviderList, key=lambda x: x.last_recent_search or SGDatetime(2000,1,1), reverse=True)
|
|
#set $last_rls_date = '-'
|
|
#set $last_rls_age = None
|
|
#set $last_rls_age_str = '-'
|
|
#if $cur_provider.last_recent_search
|
|
#set $last_rls_date = $SGDatetime.sbfdatetime($cur_provider.last_recent_search)
|
|
#set $last_rls_timedelta = ($SGDatetime.now() - $cur_provider.last_recent_search)
|
|
#set $last_rls_age = $last_rls_timedelta.days
|
|
#set $last_rls_age_str = '%s days ago' % $last_rls_age
|
|
#set $tmp = $humanize.naturalday($cur_provider.last_recent_search, format='')
|
|
#if $tmp
|
|
#set $last_rls_age_str = $humanize.naturaltime($last_rls_timedelta)
|
|
#if 'yesterday' == $tmp
|
|
#set $is_now_night = 6 > $SGDatetime.now().hour
|
|
#set $is_last_evening = 18 <= $cur_provider.last_recent_search.hour
|
|
#if not ($is_now_night and $is_last_evening)
|
|
#set $last_rls_age_str = $humanize.naturalday($cur_provider.last_recent_search)
|
|
#end if
|
|
#end if
|
|
#end if
|
|
#end if
|
|
#set $status_class = 'yellow-bg'
|
|
#set $status_text = 'not enabled'
|
|
#if $cur_provider.is_active()
|
|
#if not $cur_provider.enable_recentsearch
|
|
#set $status_text = 'recent ' + $status_text
|
|
#else
|
|
#set $status_class = 'contrast-text green-bg'
|
|
#set $status_text = 'enabled'
|
|
#if '-' != $last_rls_date
|
|
#if 4 > $last_rls_age
|
|
#set $status_text = 'normal'
|
|
#else
|
|
#set $status_class = 'contrast-text'
|
|
#if 14 >= $last_rls_age
|
|
#set $status_class += ' blue-bg'
|
|
#set $status_text = 'overdue'
|
|
#else
|
|
#set $status_class += ' red-bg'
|
|
#set $status_text = 'not normal'
|
|
#end if
|
|
#end if
|
|
#end if
|
|
#end if
|
|
#end if
|
|
<tr class="$row_class()#echo ('',' grey-text')[not $cur_provider.is_active()]#">
|
|
<td class="text-left">
|
|
<span class="prov-name"><img height="16px" src="$sbRoot/images/providers/$cur_provider.image_name()">$cur_provider.name</span>
|
|
</td>
|
|
<td>$last_rls_age_str</td>
|
|
<td>$last_rls_date</td>
|
|
<td><span class="status $status_class">$status_text</span></td>
|
|
</tr>
|
|
#end for
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
#end if
|
|
|
|
#if $domain_fail_cnt or $provider_fail_cnt
|
|
<style>
|
|
.component-group{min-height:50px}
|
|
.component-group.bubblelist{padding:0;border-bottom:none}
|
|
.component-group.bubblelist .item a{font-size:14px;padding-right:14px}
|
|
</style>
|
|
#set $dev = (1, 3)[False]
|
|
#set $last_n = 0
|
|
#set $show_bubble = 1 < $domain_fail_cnt or 1 < $provider_fail_cnt
|
|
|
|
#if $show_bubble:
|
|
<div class="component-group bubblelist" style="margin:0 0 3px">
|
|
<div class="type bgcol">
|
|
<span class="list"><div class="item text">Bubble links:</div>
|
|
#if 1 < $domain_fail_cnt
|
|
#for $n, $item in enumerate($domain_fail_stats * $dev)
|
|
#if $len($item['fails'])
|
|
#set $last_n = $n + 1
|
|
<div class="item"><a href="#$item['id']-section-$n" rel="noreferrer">#if $item['img']#<img height="16px" src="$sbRoot/images/$item['img']">#elif $item['cls']#<i class="$item['cls']"></i>#end if#$item['name']</a></div>
|
|
#end if
|
|
#end for
|
|
#end if
|
|
#if 1 < $provider_fail_cnt
|
|
#for $n, $prov in enumerate($provider_fail_stats * $dev)
|
|
#if $len($prov['fails'])
|
|
#set $n += $last_n
|
|
<div class="item"><a href="#$prov['id']-section-$n" rel="noreferrer"><img height="16px" src="$sbRoot/images/providers/$prov['prov_img']">$prov['name']</a></div>
|
|
#end if
|
|
#end for
|
|
#end if
|
|
</span>
|
|
</div>
|
|
</div>
|
|
#end if
|
|
<p id="bubble-after">When a server cannot be contacted over a period, SickGear backs off and waits an increasing interval between each retry</p>
|
|
#end if
|
|
|
|
#if not $domain_fail_cnt
|
|
<p>No current domain failures. Failure stats display here when appropriate.</p>
|
|
#else
|
|
#for $n, $item in enumerate($domain_fail_stats * $dev)
|
|
#if $len($item['fails'])
|
|
|
|
<!-- $item['name'] -->
|
|
<div class="component-group bubble">
|
|
<div name="$item['id']-section-$n" style="text-align:left">
|
|
#set $item_class = '<span %sstyle="vertical-align:middle">'
|
|
#set $item_class = $item_class % ''
|
|
|
|
<input type="button" class="shows-more btn" value="Expand" style="display:none"><input type="button" class="shows-less btn" value="Collapse">#if $item['img']#<img height="16px" src="$sbRoot/images/$item['img']">#elif $item['cls']#<i class="$item['cls']"></i>#end if#$item_class$item['name']
|
|
#if $item['next_try']
|
|
#set nt = $str($item['next_try']).split('.', 2)[0][::-1].replace(':', ' m', 1).replace(':', ' h', 1)[::-1]
|
|
... is paused until $SGDatetime.sbftime($SGDatetime.now() + $item['next_try'], markup=True) (in ${nt}s) <input type="button" data-domain="$item['name']" class="domain-retry btn" id="$item['id']-btn-retry" value="Ignore pause on next search">
|
|
#end if
|
|
</span>
|
|
</div>
|
|
<table class="manageTable server-failures tablesorter hover-highlight focus-highlight text-center" cellspacing="0" border="0" cellpadding="0">
|
|
<thead>
|
|
<tr>
|
|
<th class="text-center" style="width:13em;padding-right:20px">period of 1hr</th>
|
|
<th class="text-center" style="padding-right:20px">server/timeout</th>
|
|
<th class="text-center" style="padding-right:20px">network</th>
|
|
<th class="text-center" style="padding-right:20px">no data</th>
|
|
<th class="text-center" style="padding-right:20px">other</th>
|
|
#if $item['has_limit']
|
|
<th class="text-center" style="padding-right:20px">hit limit</th>
|
|
#end if
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
#set $day = []
|
|
#for $fail in $item['fails']
|
|
#set $child = True
|
|
#if $fail['date'] not in $day
|
|
#set $day += [$fail['date']]
|
|
#set $child = False
|
|
#end if
|
|
#slurp#
|
|
<tr#if $fail['multirow'] and $child# class="tablesorter-childRow"#end if#>
|
|
#if $fail['multirow']
|
|
#if not $child
|
|
<td><a href="#" class="server-fail-parent-toggle" title="Totals (expand for detail)">$SGDatetime.sbfdate($fail['date_time'])</a></td>
|
|
#else
|
|
<td>$SGDatetime.sbftime($fail['date_time'], markup=True)</td>
|
|
#end if
|
|
#else
|
|
<td>$SGDatetime.sbfdatetime($fail['date_time'], markup=True)</td>
|
|
#end if
|
|
#set $blank = '-'
|
|
#set $title=None
|
|
#if $fail['http']['count']
|
|
#set $title=$fail['http']['code']
|
|
#end if
|
|
<td>#if $fail['http']['count']#<span title="#if $child or not $fail['multirow']#$title#else#Expand for fail codes#end if#">$fail['http']['count']</span>#else#$blank#end if# / #echo $fail['timeout'].get('count', 0) or $blank#</td>
|
|
<td>#echo ($fail['connection'].get('count', 0) + $fail['connection_timeout'].get('count', 0)) or $blank#</td>
|
|
<td>#echo $fail['nodata'].get('count', 0) or $blank#</td>
|
|
<td>#echo $fail['other'].get('count', 0) or $blank#</td>
|
|
#if $item['has_limit']
|
|
<td>#echo $fail.get('limit', {}).get('count', 0) or $blank#</td>
|
|
#end if
|
|
</tr>
|
|
#end for
|
|
</tbody>
|
|
</table>
|
|
</div><!-- /$item['name'] -->
|
|
#end if
|
|
#end for
|
|
#end if
|
|
|
|
#if not $provider_fail_cnt
|
|
<p>No current provider failures. Failure stats display here when appropriate.</p>
|
|
#else
|
|
#for $n, $prov in enumerate($provider_fail_stats * $dev)
|
|
#if $len($prov['fails'])
|
|
|
|
<!-- $prov['name'] -->
|
|
<div class="component-group bubble#if $n + 1 == $len($provider_fail_stats * $dev)# last#end if#">
|
|
#set $n += $last_n
|
|
<div name="$prov['id']-section-$n" style="text-align:left">
|
|
#set $prov_class = '<span %sstyle="vertical-align:middle">'
|
|
#if not $prov['active']
|
|
#set $prov_class = $prov_class % 'class="grey-text" '
|
|
#else
|
|
#set $prov_class = $prov_class % ''
|
|
#end if
|
|
<input type="button" class="shows-more btn" value="Expand" style="display:none"><input type="button" class="shows-less btn" value="Collapse"><img src="$sbRoot/images/providers/$prov['prov_img']" width="16" height="16" style="margin:0 6px 0 3px">$prov_class$prov['name']
|
|
#if $prov['active']
|
|
#if $prov['next_try']
|
|
#set nt = $str($prov['next_try']).split('.', 2)[0][::-1].replace(':', ' m', 1).replace(':', ' h', 1)[::-1]
|
|
... is paused until $SGDatetime.sbftime($SGDatetime.now() + $prov['next_try'], markup=True) (in ${nt}s) <input type="button" class="provider-retry btn" id="$prov['id']-btn-retry" value="Ignore pause on next search">
|
|
#end if
|
|
#else
|
|
... is not enabled
|
|
#end if
|
|
</span>
|
|
</div>
|
|
<table class="manageTable server-failures tablesorter hover-highlight focus-highlight text-center" cellspacing="0" border="0" cellpadding="0">
|
|
<thead>
|
|
<tr>
|
|
<th class="text-center" style="width:13em;padding-right:20px">period of 1hr</th>
|
|
<th class="text-center" style="padding-right:20px">server/timeout</th>
|
|
<th class="text-center" style="padding-right:20px">network</th>
|
|
<th class="text-center" style="padding-right:20px">no data</th>
|
|
<th class="text-center" style="padding-right:20px">other</th>
|
|
#if $prov['has_limit']
|
|
<th class="text-center" style="padding-right:20px">hit limit</th>
|
|
#end if
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
#set $day = []
|
|
#for $fail in $prov['fails']
|
|
#set $child = True
|
|
#if $fail['date'] not in $day
|
|
#set $day += [$fail['date']]
|
|
#set $child = False
|
|
#end if
|
|
#slurp#
|
|
<tr#if $fail['multirow'] and $child# class="tablesorter-childRow"#end if#>
|
|
#if $fail['multirow']
|
|
#if not $child
|
|
<td><a href="#" class="server-fail-parent-toggle" title="Totals (expand for detail)">$SGDatetime.sbfdate($fail['date_time'])</a></td>
|
|
#else
|
|
<td>$SGDatetime.sbftime($fail['date_time'], markup=True)</td>
|
|
#end if
|
|
#else
|
|
<td>$SGDatetime.sbfdatetime($fail['date_time'], markup=True)</td>
|
|
#end if
|
|
#set $blank = '-'
|
|
#set $title=None
|
|
#if $fail['http']['count']
|
|
#set $title=$fail['http']['code']
|
|
#end if
|
|
<td>#if $fail['http']['count']#<span title="#if $child or not $fail['multirow']#$title#else#Expand for fail codes#end if#">$fail['http']['count']</span>#else#$blank#end if# / #echo $fail['timeout'].get('count', 0) or $blank#</td>
|
|
<td>#echo ($fail['connection'].get('count', 0) + $fail['connection_timeout'].get('count', 0)) or $blank#</td>
|
|
<td>#echo $fail['nodata'].get('count', 0) or $blank#</td>
|
|
<td>#echo $fail['other'].get('count', 0) or $blank#</td>
|
|
#if $prov['has_limit']
|
|
<td>#echo $fail.get('limit', {}).get('count', 0) or $blank#</td>
|
|
#end if
|
|
</tr>
|
|
#end for
|
|
</tbody>
|
|
</table>
|
|
</div><!-- /$prov['name'] -->
|
|
#end if
|
|
#end for
|
|
#end if
|
|
</div>
|
|
##
|
|
##
|
|
#end if
|
|
#if 'failure' not in $layout
|
|
</tbody>
|
|
</table>
|
|
#end if
|
|
|
|
#include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_bottom.tmpl')
|