mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-23 19:23:37 +00:00
32987134ba
Cleanup most init warnings. Cleanup some vars, pythonic instead of js. Some typos and python var/func names for Scheduler. Remove legacy handlers deprecated in 2020. Remove some legacy tagged stuff. Cleanup ConfigParser and 23.py Change cleanup vendored scandir. Remove redundant pkg_resources.py in favour of the vendor folder. Remove backports. Remove trakt checker. Change remove redundant WindowsSelectorEventLoopPolicy from webserveInit. Cleanup varnames and providers Various minor tidy ups to remove ide warnings.
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.split_composite_status(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.split_composite_status($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.get_by_id($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.split_composite_status(int($action['action']))
|
|
#set $basename = $os.path.basename($action['resource'])
|
|
#if $curStatus in $SNATCHED_ANY + [$FAILED]
|
|
#set $provider = $providers.get_by_id($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.split_composite_status(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.get_by_id($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.newznab_providers, 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')
|