Merge pull request #1103 from JackDandy/feature/AddPruneUntil

Add keep up to x most recent downloads
This commit is contained in:
JackDandy 2018-05-30 03:38:12 +01:00 committed by GitHub
commit e440155b2c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 173 additions and 60 deletions

View file

@ -1,5 +1,10 @@
### 0.17.0 (2018-xx-xx xx:xx:xx UTC)
* Change add "Keep up to x most recent downloads" to Edit Show/Other
* Change add "Keep up to x most recent downloads" to Manage/Bulk Change/Edit
* Change append number of downloads to keep to the number of file(s) at Display Show
* Change add "Keep up to x most recent downloads" to add show finally step
* Add prune to refreshDir/rescan
* Update Tornado Web Server 5.0.1 (35a538f) to 5.0.1 (2b2a220a)
* Add HDME torrent provider
* Add HorribleSubs torrent provider

View file

@ -3230,7 +3230,7 @@ td.tableright{
}
.optionWrapper{
width:450px;
width:475px;
margin-left:auto;
margin-right:auto;
padding:6px 12px
@ -3246,7 +3246,7 @@ td.tableright{
.optionWrapper div.selectChoices{
float:left;
width:175px;
width:200px;
margin-left:25px
}

View file

@ -677,6 +677,7 @@ name = '' if not client else get_client_instance(sickbeard.TORRENT_METHOD)().nam
<input type="checkbox" name="${cur_torrent_provider.get_id()}_scene_nuked_active" id="${cur_torrent_provider.get_id()}_scene_nuked_active" <%= html_checked if cur_torrent_provider.scene_nuked_active else '' %>>
<span>$filter_scene_nuked_active_desc</span>
</label>
<span class="hide-if-${cur_torrent_provider.get_id()}_enable_backlog">&nbsp;</span>
#end if
</div>
</div>

View file

@ -336,7 +336,9 @@
<span class="label addQTip" title="Location#echo (' no longer exists" style="background-color:#8f1515"', '"')[$showLoc[1]]#>$showLoc[0]</span>
<span class="label addQTip" title="Size">$human($get_size($showLoc[0]))</span>
#set $filecount = sum([$c for $k, $c in $ep_counts['videos'].items()])
<span class="label addQTip" title="Videos">#echo ('No', $filecount)[0 < $filecount]# file$maybe_plural($filecount)</span>
#set $to_prune = $show.prune - $filecount
#set $keep_or_prune = ('', ' (%s)' % ('%s to prune' % abs($to_prune), 'keep %s' % $show.prune)[0 <= $to_prune])[bool($show.prune)]
<span class="label addQTip" title="Videos">#echo '%s file%s%s' % (('No', $filecount)[0 < $filecount], $maybe_plural($filecount), $keep_or_prune)#</span>
#if $show.paused
<span class="label label-paused">Paused</span>
#end if

View file

@ -227,6 +227,16 @@
<div id="core-component-group3" class="component-group">
<div class="field-pair">
<label for="prune">
<span class="component-title">Keep up to</span>
<span class="component-desc">
<input type="text" name="prune" id="prune" value="#echo $show.prune and $show.prune or ''#" class="form-control form-control-inline input-sm input75" style="width:50px">
<p>most recent downloads (blank for all)</p>
</span>
</label>
</div>
<div class="field-pair">
<label for="location">
<span class="component-title">Location for files</span>

View file

@ -61,7 +61,17 @@
#pass
#end try
<div class="field-pair #if $sg_str('SHOWLIST_TAGVIEW') != 'custom' then 'hidden' else ''#" style="margin-top:10px">
<div class="field-pair alt" style="margin-top:10px">
<label for="prune">
<span class="component-title">Keep up to</span>
<span class="component-desc">
<input type="text" name="prune" id="prune" value="" class="form-control form-control-inline input-sm input75" style="width:50px">
<p>most recent downloads (blank for all)</p>
</span>
</label>
</div>
<div class="field-pair #if $sg_str('SHOWLIST_TAGVIEW') != 'custom' then 'hidden' else ''#">
<label for="tag">
<span class="component-title">Place show in group</span>
<span class="component-desc">

View file

@ -169,8 +169,16 @@
</div><br />
</div>
<div class="optionWrapper" >
<span class="selectTitle">Keep up to <span class="grey-text">(0 = no prune)</span></span>
<div class="selectChoices">
<input type="text" name="prune" id="prune" value="#if None is not $prune_value then $prune_value else ''#" class="form-control form-control-inline input-sm input75" style="width:50px;margin-top:0">
<span>blank = no change</span>
</div><br />
</div>
<div class="optionWrapper #if $sg_str('SHOWLIST_TAGVIEW') != 'custom' then 'hidden' else ''#">
<span class="selectTitle">Show is grouped in</span>
<span class="selectTitle">Place show in group</span>
<div class="selectChoices">
<select id="edit_tag" name="tag" class="form-control form-control-inline input-sm">
<option value="keep">&lt; keep &gt;</option>

View file

@ -27,7 +27,7 @@ from sickbeard import encodingKludge as ek
from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException
MIN_DB_VERSION = 9 # oldest db version we support migrating from
MAX_DB_VERSION = 20009
MAX_DB_VERSION = 20010
TEST_BASE_VERSION = None # the base production db version, only needed for TEST db versions (>=100000)
@ -198,7 +198,7 @@ class InitialSchema(db.SchemaUpgrade):
# = Main DB Migrations =
# ======================
# Add new migrations at the bottom of the list; subclass the previous migration.
# 0 -> 20007
# 0 -> 20009
def execute(self):
db.backup_database('sickbeard.db', self.checkDBVersion())
@ -250,14 +250,15 @@ class InitialSchema(db.SchemaUpgrade):
# tv_episodes_watched
'CREATE TABLE tv_episodes_watched (tvep_id NUMERIC NOT NULL, clientep_id TEXT, label TEXT,'
' played NUMERIC DEFAULT 0 NOT NULL, date_watched NUMERIC NOT NULL, date_added NUMERIC,'
' status NUMERIC, location TEXT, file_size NUMERIC, hide INT default 0 not null)',
' status NUMERIC, location TEXT, file_size NUMERIC, hide INT DEFAULT 0 not null)',
# tv_shows
'CREATE TABLE tv_shows (show_id INTEGER PRIMARY KEY, indexer_id NUMERIC, indexer NUMERIC,'
' show_name TEXT, location TEXT, network TEXT, genre TEXT, classification TEXT, runtime NUMERIC,'
' quality NUMERIC, airs TEXT, status TEXT, flatten_folders NUMERIC, paused NUMERIC, startyear NUMERIC,'
' air_by_date NUMERIC, lang TEXT, subtitles NUMERIC, notify_list TEXT, imdb_id TEXT,'
' last_update_indexer NUMERIC, dvdorder NUMERIC, archive_firstmatch NUMERIC, rls_require_words TEXT,'
' rls_ignore_words TEXT, sports NUMERIC, anime NUMERIC, scene NUMERIC, overview TEXT, tag TEXT)',
' rls_ignore_words TEXT, sports NUMERIC, anime NUMERIC, scene NUMERIC, overview TEXT, tag TEXT,'
' prune INT DEFAULT 0)',
'CREATE UNIQUE INDEX idx_indexer_id ON tv_shows (indexer_id)',
# tv_shows_not_found
'CREATE TABLE tv_shows_not_found (indexer NUMERIC NOT NULL, indexer_id NUMERIC NOT NULL,'
@ -1406,3 +1407,17 @@ class AddWatched(db.SchemaUpgrade):
self.setDBVersion(20009)
return self.checkDBVersion()
# 20009 -> 20010
class AddPrune(db.SchemaUpgrade):
def execute(self):
if not self.hasColumn('tv_shows', 'prune'):
logger.log('Adding prune to tv_shows')
db.backup_database('sickbeard.db', self.checkDBVersion())
self.addColumn('tv_shows', 'prune', 'INT', 0)
self.setDBVersion(20010)
return self.checkDBVersion()

View file

@ -554,6 +554,7 @@ def MigrationCode(myDB):
20006: sickbeard.mainDB.DBIncreaseTo20007,
20007: sickbeard.mainDB.AddWebdlTypesTable,
20008: sickbeard.mainDB.AddWatched,
20009: sickbeard.mainDB.AddPrune,
# 20002: sickbeard.mainDB.AddCoolSickGearFeature3,
}

View file

@ -175,6 +175,39 @@ def sanitizeFileName(name):
return name
def remove_file(filepath, tree=False, prefix_failure='', log_level=logger.MESSAGE):
"""
Remove file based on setting for trash v permanent delete
:param filepath: Path and file name
:type filepath: String
:param tree: Remove file tree
:type tree: Bool
:param prefix_failure: Text to prepend to error log, e.g. show id
:type prefix_failure: String
:param log_level: Log level to use for error
:type log_level: Int
:return: Type of removal ('Deleted' or 'Trashed') if filepath does not exist or None if no removal occurred
:rtype: String or None
"""
result = None
if filepath:
try:
result = 'Deleted'
if sickbeard.TRASH_REMOVE_SHOW:
result = 'Trashed'
ek.ek(send2trash, filepath)
elif tree:
ek.ek(shutil.rmtree, filepath)
else:
ek.ek(os.remove, filepath)
except OSError as e:
logger.log(u'%sUnable to %s %s %s: %s' % (prefix_failure, ('delete', 'trash')[sickbeard.TRASH_REMOVE_SHOW],
('file', 'dir')[tree], filepath, str(e.strerror)), log_level)
return (None, result)[filepath and not ek.ek(os.path.exists, filepath)]
def remove_file_failed(filename):
try:
ek.ek(os.remove, filename)

View file

@ -417,23 +417,15 @@ class ImageCache:
void = False
if not void and need_images[self.FANART]:
action = ('delete', 'trash')[sickbeard.TRASH_REMOVE_SHOW]
cache_path = self.fanart_path(show_id).replace('%s.fanart.jpg' % show_id, '')
# num_images = len(fnmatch.filter(os.listdir(cache_path), '*.jpg'))
for cache_dir in ek.ek(glob.glob, cache_path):
if show_id in sickbeard.FANART_RATINGS:
del (sickbeard.FANART_RATINGS[show_id])
logger.log(u'Attempt to %s purge cache file %s' % (action, cache_dir), logger.DEBUG)
try:
if sickbeard.TRASH_REMOVE_SHOW:
send2trash(cache_dir)
else:
shutil.rmtree(cache_dir)
except OSError as e:
logger.log(u'Unable to %s %s: %s / %s' % (action, cache_dir, repr(e), str(e)), logger.WARNING)
result = helpers.remove_file(cache_dir, tree=True)
if result:
logger.log(u'%s cache file %s' % (result, cache_dir), logger.DEBUG)
try:
checked_files = []

View file

@ -177,10 +177,11 @@ class ShowQueue(generic_queue.GenericQueue):
def addShow(self, indexer, indexer_id, showDir, default_status=None, quality=None, flatten_folders=None,
lang='en', subtitles=None, anime=None, scene=None, paused=None, blacklist=None, whitelist=None,
wanted_begin=None, wanted_latest=None, tag=None, new_show=False, show_name=None, upgrade_once=False):
wanted_begin=None, wanted_latest=None, prune=None, tag=None,
new_show=False, show_name=None, upgrade_once=False):
queueItemObj = QueueItemAdd(indexer, indexer_id, showDir, default_status, quality, flatten_folders, lang,
subtitles, anime, scene, paused, blacklist, whitelist,
wanted_begin, wanted_latest, tag,
wanted_begin, wanted_latest, prune, tag,
new_show=new_show, show_name=show_name, upgrade_once=upgrade_once)
self.add_item(queueItemObj)
@ -238,7 +239,7 @@ class ShowQueueItem(generic_queue.QueueItem):
class QueueItemAdd(ShowQueueItem):
def __init__(self, indexer, indexer_id, showDir, default_status, quality, flatten_folders, lang, subtitles, anime,
scene, paused, blacklist, whitelist, default_wanted_begin, default_wanted_latest, tag,
scene, paused, blacklist, whitelist, default_wanted_begin, default_wanted_latest, prune, tag,
scheduled_update=False, new_show=False, show_name=None, upgrade_once=False):
self.indexer = indexer
@ -257,6 +258,7 @@ class QueueItemAdd(ShowQueueItem):
self.paused = paused
self.blacklist = blacklist
self.whitelist = whitelist
self.prune = prune
self.tag = tag
self.new_show = new_show
self.showname = show_name
@ -348,6 +350,7 @@ class QueueItemAdd(ShowQueueItem):
self.show.anime = self.anime if None is not self.anime else sickbeard.ANIME_DEFAULT
self.show.scene = self.scene if None is not self.scene else sickbeard.SCENE_DEFAULT
self.show.paused = self.paused if None is not self.paused else False
self.show.prune = self.prune if None is not self.prune else 0
self.show.tag = self.tag if None is not self.tag else 'Show List'
if self.show.anime:

View file

@ -118,6 +118,7 @@ class TVShow(object):
self._rls_ignore_words = ''
self._rls_require_words = ''
self._overview = ''
self._prune = 0
self._tag = ''
self._mapped_ids = {}
self._not_found_count = None
@ -165,6 +166,7 @@ class TVShow(object):
rls_ignore_words = property(lambda self: self._rls_ignore_words, dirty_setter('_rls_ignore_words'))
rls_require_words = property(lambda self: self._rls_require_words, dirty_setter('_rls_require_words'))
overview = property(lambda self: self._overview, dirty_setter('_overview'))
prune = property(lambda self: self._prune, dirty_setter('_prune'))
tag = property(lambda self: self._tag, dirty_setter('_tag'))
def _helper_load_failed_db(self):
@ -976,6 +978,10 @@ class TVShow(object):
if not self.overview:
self.overview = sqlResults[0]['overview']
self.prune = sqlResults[0]['prune']
if not self.prune:
self.prune = 0
self.tag = sqlResults[0]['tag']
if not self.tag:
self.tag = 'Show List'
@ -1197,17 +1203,9 @@ class TVShow(object):
+ ek.ek(glob.glob, ic.poster_thumb_path(self.indexerid).replace('poster.jpg', '*')) \
+ ek.ek(glob.glob, ic.fanart_path(self.indexerid).replace('%s.fanart.jpg' % self.indexerid, '')):
cache_dir = ek.ek(os.path.isdir, cache_obj)
logger.log('Attempt to %s cache %s %s' % (action, cache_dir and 'dir' or 'file', cache_obj))
try:
if sickbeard.TRASH_REMOVE_SHOW:
ek.ek(send2trash, cache_obj)
elif cache_dir:
ek.ek(shutil.rmtree, cache_obj)
else:
ek.ek(os.remove, cache_obj)
except OSError as e:
logger.log('Unable to %s %s: %s / %s' % (action, cache_obj, repr(e), str(e)), logger.WARNING)
result = helpers.remove_file(cache_obj, tree=cache_dir, log_level=logger.WARNING)
if result:
logger.log('%s cache %s %s' % (result, cache_dir and 'dir' or 'file', cache_obj))
show_id = '%s' % self.indexerid
if show_id in sickbeard.FANART_RATINGS:
@ -1227,14 +1225,9 @@ class TVShow(object):
except:
logger.log('Unable to change permissions of %s' % self._location, logger.WARNING)
if sickbeard.TRASH_REMOVE_SHOW:
ek.ek(send2trash, self.location)
else:
ek.ek(shutil.rmtree, self.location)
logger.log('%s show folder %s' %
(('Deleted', 'Trashed')[sickbeard.TRASH_REMOVE_SHOW],
self._location))
result = helpers.remove_file(self.location, tree=True)
if result:
logger.log('%s show folder %s' % (result, self._location))
except exceptions.ShowDirNotFoundException:
logger.log('Show folder does not exist, no need to %s %s' % (action, self._location), logger.WARNING)
@ -1260,8 +1253,15 @@ class TVShow(object):
logger.log('%s: Loading all episodes for [%s] with a location from the database' % (self.indexerid, self.name))
myDB = db.DBConnection()
sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE showid = ? AND location != ''", [self.indexerid])
sqlResults = myDB.select(
'SELECT * FROM tv_episodes'
' WHERE showid = ? AND location != ""'
' ORDER BY season, episode DESC',
[self.indexerid])
kept = 0
deleted = 0
attempted = []
sql_l = []
for ep in sqlResults:
curLoc = ek.ek(os.path.normpath, ep['location'])
@ -1275,6 +1275,22 @@ class TVShow(object):
logger.DEBUG)
continue
# if the path exist and if it's in our show dir
if (self.prune and curEp.location not in attempted and 0 < helpers.get_size(curEp.location) and
ek.ek(os.path.normpath, curLoc).startswith(ek.ek(os.path.normpath, self.location))):
with curEp.lock:
if curEp.status in Quality.DOWNLOADED:
# locations repeat but attempt to delete once
attempted += curEp.location
if kept >= self.prune:
result = helpers.remove_file(curEp.location, prefix_failure=u'%s: ' % self.indexerid)
if result:
logger.log(u'%s: %s file %s' % (self.indexerid,
result, curEp.location), logger.DEBUG)
deleted += 1
else:
kept += 1
# if the path doesn't exist or if it's not in our show dir
if not ek.ek(os.path.isfile, curLoc) or not ek.ek(os.path.normpath, curLoc).startswith(
ek.ek(os.path.normpath, self.location)):
@ -1308,6 +1324,11 @@ class TVShow(object):
if sickbeard.AIRDATE_EPISODES:
curEp.airdateModifyStamp()
if deleted:
logger.log('%s: %s %s media file%s and kept %s most recent downloads' % (
self.indexerid, ('Permanently deleted', 'Trashed')[sickbeard.TRASH_REMOVE_SHOW],
deleted, helpers.maybe_plural(deleted), kept))
if 0 < len(sql_l):
myDB = db.DBConnection()
myDB.mass_action(sql_l)
@ -1429,6 +1450,7 @@ class TVShow(object):
'rls_ignore_words': self.rls_ignore_words,
'rls_require_words': self.rls_require_words,
'overview': self.overview,
'prune': self.prune,
'tag': self.tag,
}
@ -1458,7 +1480,8 @@ class TVShow(object):
+ 'quality: %s\n' % self.quality \
+ 'scene: %s\n' % self.is_scene \
+ 'sports: %s\n' % self.is_sports \
+ 'anime: %s\n' % self.is_anime
+ 'anime: %s\n' % self.is_anime \
+ 'prune: %s\n' % self.prune
def wantEpisode(self, season, episode, quality, manualSearch=False, multi_ep=False):

View file

@ -2986,6 +2986,7 @@ class CMD_SickGearShow(ApiCall):
showDict["requirewords"] = showObj.rls_require_words
if self.overview:
showDict["overview"] = showObj.overview
showDict["prune"] = showObj.prune
showDict["tag"] = showObj.tag
showDict["imdb_id"] = showObj.imdbid
showDict["classification"] = showObj.classification
@ -4189,6 +4190,7 @@ class CMD_SickGearShows(ApiCall):
"upgrade_once": curShow.upgrade_once,
"ignorewords": curShow.rls_ignore_words,
"requirewords": curShow.rls_require_words,
"prune": curShow.prune,
"tag": curShow.tag,
"imdb_id": curShow.imdbid,
"classification": curShow.classification,

View file

@ -2171,7 +2171,7 @@ class Home(MainHandler):
([], ['translucent'])[sickbeard.DISPLAY_SHOW_BACKGROUND_TRANSLUCENT] +
[{0: 'reg', 1: 'pro', 2: 'pro ii'}.get(sickbeard.DISPLAY_SHOW_VIEWMODE)])
def editShow(self, show=None, location=None, anyQualities=[], bestQualities=[], exceptions_list=[],
def editShow(self, show=None, prune=None, location=None, anyQualities=[], bestQualities=[], exceptions_list=[],
flatten_folders=None, paused=None, directCall=False, air_by_date=None, sports=None, dvdorder=None,
indexerLang=None, subtitles=None, upgrade_once=None, rls_ignore_words=None,
rls_require_words=None, anime=None, blacklist=None, whitelist=None,
@ -2334,6 +2334,7 @@ class Home(MainHandler):
showObj.subtitles = subtitles
showObj.air_by_date = air_by_date
showObj.tag = tag
showObj.prune = config.minimax(prune, 0, 0, 9999)
if not directCall:
showObj.lang = indexer_lang
@ -4100,8 +4101,8 @@ class NewHomeAddShows(Home):
quality_preset=None, anyQualities=None, bestQualities=None, upgrade_once=None,
flatten_folders=None, subtitles=None,
fullShowPath=None, other_shows=None, skipShow=None, providedIndexer=None, anime=None,
scene=None, blacklist=None, whitelist=None, wanted_begin=None, wanted_latest=None, tag=None,
return_to=None, cancel_form=None):
scene=None, blacklist=None, whitelist=None, wanted_begin=None, wanted_latest=None,
prune=None, tag=None, return_to=None, cancel_form=None):
"""
Receive tvdb id, dir, and other options and create a show from them. If extra show dirs are
provided then it forwards back to new_show, if not it goes to /home.
@ -4211,12 +4212,13 @@ class NewHomeAddShows(Home):
wanted_begin = config.minimax(wanted_begin, 0, -1, 10)
wanted_latest = config.minimax(wanted_latest, 0, -1, 10)
prune = config.minimax(prune, 0, 0, 9999)
# add the show
sickbeard.showQueueScheduler.action.addShow(indexer, indexer_id, show_dir, int(defaultStatus), newQuality,
flatten_folders, indexerLang, subtitles, anime,
scene, None, blacklist, whitelist,
wanted_begin, wanted_latest, tag, new_show=new_show,
wanted_begin, wanted_latest, prune, tag, new_show=new_show,
show_name=show_name, upgrade_once=upgrade_once)
# ui.notifications.message('Show added', 'Adding the specified show into ' + show_dir)
@ -4641,6 +4643,9 @@ class Manage(MainHandler):
paused_all_same = True
last_paused = None
prune_all_same = True
last_prune = None
tag_all_same = True
last_tag = None
@ -4685,6 +4690,13 @@ class Manage(MainHandler):
else:
last_paused = curShow.paused
if prune_all_same:
# if we had a value already and this value is different then they're not all the same
if last_prune not in (None, curShow.prune):
prune_all_same = False
else:
last_prune = curShow.prune
if tag_all_same:
# if we had a value already and this value is different then they're not all the same
if last_tag not in (None, curShow.tag):
@ -4738,6 +4750,7 @@ class Manage(MainHandler):
t.showList = toEdit
t.upgrade_once_value = last_upgrade_once if upgrade_once_all_same else None
t.paused_value = last_paused if paused_all_same else None
t.prune_value = last_prune if prune_all_same else None
t.tag_value = last_tag if tag_all_same else None
t.anime_value = last_anime if anime_all_same else None
t.flatten_folders_value = last_flatten_folders if flatten_folders_all_same else None
@ -4752,7 +4765,7 @@ class Manage(MainHandler):
def massEditSubmit(self, upgrade_once=None, paused=None, anime=None, sports=None, scene=None,
flatten_folders=None, quality_preset=False, subtitles=None, air_by_date=None, anyQualities=[],
bestQualities=[], toEdit=None, tag=None, *args, **kwargs):
bestQualities=[], toEdit=None, prune=None, tag=None, *args, **kwargs):
dir_map = {}
for cur_arg in kwargs:
@ -4798,6 +4811,8 @@ class Manage(MainHandler):
new_paused = True if paused == 'enable' else False
new_paused = 'on' if new_paused else 'off'
new_prune = (config.minimax(prune, 0, 0, 9999), showObj.prune)[prune in (None, '', 'keep')]
if tag == 'keep':
new_tag = showObj.tag
else:
@ -4854,7 +4869,7 @@ class Manage(MainHandler):
paused=new_paused, sports=new_sports,
subtitles=new_subtitles, anime=new_anime,
scene=new_scene, air_by_date=new_air_by_date,
tag=new_tag, directCall=True)
prune=new_prune, tag=new_tag, directCall=True)
if curErrors:
logger.log(u'Errors: ' + str(curErrors), logger.ERROR)
@ -5531,16 +5546,9 @@ class History(MainHandler):
# locations repeat with watch events but attempt to delete once
attempted += [r['location']]
try:
if sickbeard.TRASH_REMOVE_SHOW:
ek.ek(send2trash, r['location'])
else:
ek.ek(os.remove, r['location'])
except OSError as e:
logger.log(u'Unable to delete file %s: %s' % (r['location'], str(e.strerror)))
if not ek.ek(os.path.isfile, r['location']):
logger.log(u'Deleted file %s' % r['location'])
result = helpers.remove_file(r['location'])
if result:
logger.log(u'%s file %s' % (result, r['location']))
deleted.update({r['tvep_id']: row_show_ids[r['rowid']]})
if row_show_ids[r['rowid']] not in refresh: