2023-01-12 01:04:47 +00:00
#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 : 3 px }
#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
2023-02-13 21:00:11 +00:00
#set $ curStatus , $ curQuality = $ Quality . split_composite_status ( int ( $ hItem [ ' action ' ] ) )
2023-01-12 01:04:47 +00:00
#set $ display_name = ' <span data-sort= " %s " > %s - S %02i E %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>
2023-02-13 21:00:11 +00:00
<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>
2023-01-12 01:04:47 +00:00
<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 ]
2023-02-13 21:00:11 +00:00
#set $ provider = $ providers . get_by_id ( $ generic . GenericProvider . make_id ( $ hItem [ ' provider ' ] ) )
2023-01-12 01:04:47 +00:00
#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 %02i E %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 ' ] )
2023-02-13 21:00:11 +00:00
#set $ curStatus , $ curQuality = $ Quality . split_composite_status ( int ( $ action [ ' action ' ] ) )
2023-01-12 01:04:47 +00:00
#set $ basename = $ os . path . basename ( $ action [ ' resource ' ] )
#if $ curStatus in $ SNATCHED_ANY + [ $ FAILED ]
2023-02-13 21:00:11 +00:00
#set $ provider = $ providers . get_by_id ( $ generic . GenericProvider . make_id ( $ action [ ' provider ' ] ) )
2023-01-12 01:04:47 +00:00
#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 ' ] )
2023-02-13 21:00:11 +00:00
#set $ curStatus , $ curQuality = $ Quality . split_composite_status ( int ( $ action [ ' action ' ] ) )
2023-01-12 01:04:47 +00:00
#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 %s E %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">
2023-02-13 21:00:11 +00:00
#set $ provider = $ providers . get_by_id ( $ generic . GenericProvider . make_id ( $ hItem [ ' provider ' ] ) )
2023-01-12 01:04:47 +00:00
#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>
2023-02-13 21:00:11 +00:00
#for $ cur_provider in $ sorted ( $ sickgear . newznab_providers , key = lambda x : x . last_recent_search or SGDatetime ( 2000 , 1 , 1 ) , reverse = True )
2023-01-12 01:04:47 +00:00
#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 %s style= " 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 %s style= " 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 ' )