Commit 5e61bc6c authored by echel0n's avatar echel0n

Refactored TV show episodes cache to store episodes by show ID

parent b49e766e
......@@ -571,7 +571,7 @@ class Core(object):
self.log.info('Loading show {} and populating episode cache'.format(show.name))
show = TVShow(show.indexer_id, show.indexer)
self.shows.update({(show.indexer_id, show.indexer): show})
show.episodes()
show.episodes
except Exception as e:
self.log.debug('There was an error loading show: {}'.format(show.name))
......
......@@ -33,21 +33,9 @@ class MutexLock(AbstractFileLock):
return self.mutex.release_write_lock()
def region_key_generator(namespace, fn):
if not namespace:
namespace = fn.__name__
elif isinstance(namespace, tuple):
namespace = ':'.join(str(x) for x in namespace)
def generate_keys(*arg):
return "{namespace}:{identity}".format(namespace=namespace, identity=':'.join(str(x) for x in arg))
return generate_keys
def configure_regions(cache_dir, replace_existing_backend=False):
tv_episodes_cache.configure('dogpile.cache.dbm', replace_existing_backend=replace_existing_backend,
arguments={'filename': os.path.join(cache_dir, 'tv_episodes.dbm'), 'lock_factory': MutexLock})
tv_episodes_cache = make_region(function_key_generator=region_key_generator)
tv_episodes_cache = make_region()
......@@ -74,7 +74,7 @@ class QuicksearchCache(object):
qsData = {
'category': 'shows',
'showid': indexer_id,
'seasons': len(set([s.season for s in show.episodes()])),
'seasons': len(set([s.season for s in show.episodes])),
'name': show.name,
'img': sickrage.app.config.web_root + showImage(indexer_id, 'poster_thumb').url
}
......@@ -84,7 +84,7 @@ class QuicksearchCache(object):
session.commit()
sql_t = []
for e in show.episodes():
for e in show.episodes:
qsData = {
'category': 'episodes',
'showid': e.showid,
......
......@@ -198,7 +198,7 @@ def make_scene_season_search_string(show_id, season, episode, extraSearchType=No
seasonStrings.append("%02d" % ab_number)
else:
numseasons = len(set([s.season for s in show_object.episodes() if s.season > 0]))
numseasons = len(set([s.season for s in show_object.episodes if s.season > 0]))
seasonStrings = ["S%02d" % int(episode_object.scene_season)]
showNames = set(make_scene_show_search_strings(show_id, episode_object.scene_season))
......@@ -232,7 +232,7 @@ def make_scene_search_string(show_id, season, episode):
show_object = find_show(show_id)
show_object = show_object.get_episode(season, episode)
numseasons = len(set([s.season for s in show_object.episodes() if s.season > 0]))
numseasons = len(set([s.season for s in show_object.episodes if s.season > 0]))
# see if we should use dates instead of episodes
if (show_object.air_by_date or show_object.sports) and show_object.airdate > datetime.date.min:
......
......@@ -468,7 +468,7 @@ class QueueItemRename(ShowQueueItem):
ep_obj_rename_list = []
for cur_ep_obj in (x for x in show_obj.episodes() if x.location):
for cur_ep_obj in (x for x in show_obj.episodes if x.location):
# Only want to rename if we have a location
if cur_ep_obj.location:
if cur_ep_obj.related_episodes:
......@@ -535,7 +535,7 @@ class QueueItemUpdate(ShowQueueItem):
# get episodes from database
db_episodes = {}
for data in show_obj.episodes():
for data in show_obj.episodes:
if data.season not in db_episodes:
db_episodes[data.season] = {}
db_episodes[data.season].update({data.episode: True})
......
......@@ -211,7 +211,7 @@ def pick_best_result(results, season_pack=False):
quality_size = sickrage.app.config.quality_sizes[cur_result.quality]
if season_pack and not len(cur_result.episodes):
episode_count = len([x for x in show_obj.episodes() if x.season == cur_result.season])
episode_count = len([x for x in show_obj.episodes if x.season == cur_result.season])
file_size = float(cur_result.size / episode_count / 1000000)
else:
file_size = float(cur_result.size / len(cur_result.episodes) / 1000000)
......@@ -426,7 +426,7 @@ def search_providers(show_id, season, episode, manualSearch=False, downCurQualit
season_qual = best_season_result.quality
sickrage.app.log.debug("The quality of the season " + best_season_result.provider.type + " is " + Quality.qualityStrings[season_qual])
all_episodes = set([x.episode for x in show_object.episodes() if x.season == best_season_result.season])
all_episodes = set([x.episode for x in show_object.episodes if x.season == best_season_result.season])
sickrage.app.log.debug("Episodes list: {}".format(','.join(map(str, all_episodes))))
......
......@@ -109,7 +109,7 @@ class BacklogSearcher(object):
# check through the list of statuses to see if we want any
wanted = []
for episode_object in show.episodes():
for episode_object in show.episodes:
if not episode_object.season > 0 or not datetime.date.today() > episode_object.airdate > from_date:
continue
......
......@@ -92,7 +92,7 @@ class DailySearcher(object):
sickrage.app.log.debug("Seeing if we need anything for today from {}".format(show.name))
# check through the list of statuses to see if we want any
for episode_object in show.episodes():
for episode_object in show.episodes:
if not episode_object.season > 0 or not episode_object.airdate >= from_date:
continue
......
......@@ -189,7 +189,7 @@ class TraktSearcher(object):
sickrage.app.log.debug("COLLECTION::SYNC::START - Look for Episodes to Add to Trakt Collection")
for s in get_show_list():
for e in s.episodes():
for e in s.episodes:
trakt_id = IndexerApi(s.indexer).trakt_id
if not self._check_in_list(trakt_id, str(e.showid), e.season, e.episode, 'Collection'):
sickrage.app.log.debug("Adding Episode %s S%02dE%02d to collection" % (s.name, e.season, e.episode))
......@@ -211,7 +211,7 @@ class TraktSearcher(object):
"COLLECTION::REMOVE::START - Look for Episodes to Remove From Trakt Collection")
for s in get_show_list():
for e in s.episodes():
for e in s.episodes:
if e.location:
continue
......@@ -238,7 +238,7 @@ class TraktSearcher(object):
"WATCHLIST::REMOVE::START - Look for Episodes to Remove from Trakt Watchlist")
for s in get_show_list():
for e in s.episodes():
for e in s.episodes:
trakt_id = IndexerApi(s.indexer).trakt_id
if self._check_in_list(trakt_id, str(e.showid), e.season, e.episode):
sickrage.app.log.debug(
......
......@@ -30,6 +30,7 @@ from mutagen.mp4 import MP4, MP4StreamInfoError
from sqlalchemy import orm
import sickrage
from sickrage.core import tv_episodes_cache
from sickrage.core.common import NAMING_EXTEND, NAMING_LIMITED_EXTEND, NAMING_LIMITED_EXTEND_E_PREFIXED, NAMING_DUPLICATE, NAMING_SEPARATED_REPEAT
from sickrage.core.common import Quality, SKIPPED, UNKNOWN, UNAIRED, statusStrings
from sickrage.core.databases.main import MainDB
......@@ -66,9 +67,9 @@ class TVEpisode(object):
query = session.query(MainDB.TVEpisode).filter_by(showid=showid, indexer=indexer, season=season, episode=episode).one()
self._data_local = query.as_dict()
episodes = self.show.episodes()
episodes = self.show.episodes
episodes.append(self)
self.show.refresh_episodes()
tv_episodes_cache.set(str(self.showid), episodes)
self.populate_episode(season, episode)
# self.checkForMetaFiles()
......@@ -276,7 +277,7 @@ class TVEpisode(object):
@property
def related_episodes(self):
return [x for x in self.show.episodes() if x.location and x.location == self.location and x.season == self.season and x.episode != self.episode]
return [x for x in self.show.episodes if x.location and x.location == self.location and x.season == self.season and x.episode != self.episode]
def save(self):
with sickrage.app.main_db.session() as session:
......@@ -290,12 +291,11 @@ class TVEpisode(object):
session.commit()
try:
episodes = self.show.episodes()
episodes = self.show.episodes
index = next((i for i, x in enumerate(episodes) if
x.showid == self.showid and x.indexer == self.indexer and x.season == self.season and x.episode == self.episode))
episodes[index] = self
self.show.episodes.set(episodes)
self.show.refresh_episodes()
tv_episodes_cache.set(str(self.showid), episodes)
except StopIteration:
pass
......@@ -307,9 +307,8 @@ class TVEpisode(object):
episode=self.episode).delete()
session.commit()
self.show.episodes.set([x for x in self.show.episodes() if
x.showid != self.showid and x.indexer != self.indexer and x.season != self.season and x.episode != self.episode])
self.show.refresh_episodes()
tv_episodes_cache.set(str(self.showid), [x for x in self.show.episodes if
x.showid != self.showid and x.indexer != self.indexer and x.season != self.season and x.episode != self.episode])
def refresh_subtitles(self):
"""Look for subtitles files and refresh the subtitles property"""
......
......@@ -26,9 +26,9 @@ import re
import shutil
import stat
import traceback
from threading import Lock
import send2trash
from dogpile.cache.api import NO_VALUE
from sqlalchemy import orm
from unidecode import unidecode
......@@ -343,11 +343,14 @@ class TVShow(object):
def last_proper_search(self, value):
self._data_local['last_proper_search'] = value
@tv_episodes_cache.cache_on_arguments(namespace=(__name__, 'episodes'))
@property
def episodes(self):
with sickrage.app.main_db.session() as session:
query = session.query(MainDB.TVShow).filter_by(indexer_id=self.indexer_id, indexer=self.indexer).one()
return [TVEpisode(showid=self.indexer_id, indexer=self.indexer, season=x.season, episode=x.episode) for x in query.episodes]
if tv_episodes_cache.get(str(self.indexer_id)) == NO_VALUE:
with sickrage.app.main_db.session() as session:
query = session.query(MainDB.TVShow).filter_by(indexer_id=self.indexer_id, indexer=self.indexer).one()
tv_episodes_cache.set(str(self.indexer_id),
[TVEpisode(showid=self.indexer_id, indexer=self.indexer, season=x.season, episode=x.episode) for x in query.episodes])
return tv_episodes_cache.get(str(self.indexer_id))
@property
def imdb_info(self):
......@@ -474,7 +477,7 @@ class TVShow(object):
cur_time = datetime.datetime.now(sickrage.app.tz)
new_episodes = []
for episode_object in self.episodes():
for episode_object in self.episodes:
if episode_object.status != UNAIRED or episode_object.season == 0 or episode_object.airdate < datetime.date.min:
continue
......@@ -503,7 +506,7 @@ class TVShow(object):
def total_size(self):
_total_size = 0
_related_episodes = set()
for episode_object in self.episodes():
for episode_object in self.episodes:
[_related_episodes.add(related_episode.indexer_id) for related_episode in episode_object.related_episodes]
if episode_object.indexer_id not in _related_episodes:
_total_size += episode_object.file_size
......@@ -531,13 +534,8 @@ class TVShow(object):
session.query(MainDB.TVShow).filter_by(indexer_id=self.indexer_id, indexer=self.indexer).delete()
session.commit()
def refresh_episodes(self):
self.episodes.refresh(self)
def flush_episodes(self, refresh=True):
self.episodes.set([x for x in self.episodes() if x.showid != self.indexer_id and x.indexer != self.indexer])
if refresh:
self.refresh_episodes()
def flush_episodes(self):
tv_episodes_cache.set(str(self.indexer_id), [])
def load_from_indexer(self, cache=True, tvapi=None):
if self.indexer is not INDEXER_TVRAGE:
......@@ -642,7 +640,7 @@ class TVShow(object):
season = query.season
episode = query.episode
episodes = self.episodes()
episodes = self.episodes
try:
index = next((i for i, x in enumerate(episodes) if
......@@ -652,9 +650,7 @@ class TVShow(object):
except StopIteration:
tv_episode = TVEpisode(showid=self.indexer_id, indexer=self.indexer, season=season, episode=episode)
episodes.append(tv_episode)
self.episodes.set(episodes)
finally:
self.refresh_episodes()
tv_episodes_cache.set(str(self.indexer_id), episodes)
return tv_episode
except orm.exc.MultipleResultsFound:
......@@ -699,7 +695,7 @@ class TVShow(object):
sickrage.app.log.debug(str(self.indexer_id) + ": Writing NFOs for all episodes")
for episode_obj in self.episodes():
for episode_obj in self.episodes:
if episode_obj.location == '':
continue
......@@ -714,7 +710,7 @@ class TVShow(object):
sickrage.app.log.debug(str(self.indexer_id) + ": Updating video metadata for all episodes")
for episode_obj in self.episodes():
for episode_obj in self.episodes:
if episode_obj.location == '':
continue
......@@ -982,7 +978,7 @@ class TVShow(object):
self.save()
# remove episodes from show episode cache
self.flush_episodes(refresh=False)
self.flush_episodes()
# remove from show cache
del sickrage.app.shows[(self.indexer_id, self.indexer)]
......@@ -1050,7 +1046,7 @@ class TVShow(object):
# run through all locations from DB, check that they exist
sickrage.app.log.debug(str(self.indexer_id) + ": Loading all episodes with a location from the database")
for curEp in self.episodes():
for curEp in self.episodes:
if curEp.location == '':
continue
......@@ -1106,7 +1102,7 @@ class TVShow(object):
sickrage.app.log.debug("%s: Downloading subtitles" % self.indexer_id)
try:
for episode in self.episodes():
for episode in self.episodes:
episode.download_subtitles()
except Exception:
sickrage.app.log.error("%s: Error occurred when downloading subtitles for %s" % (self.indexer_id, self.name))
......
......@@ -868,7 +868,7 @@ class CMD_EpisodeSetStatus(ApiCall):
return await _responds(RESULT_FAILURE, msg="Episode not found")
else:
# get all episode numbers in specified season
ep_list = [x for x in show_obj.episodes() if x.season == self.s]
ep_list = [x for x in show_obj.episodes if x.season == self.s]
def _epResult(result_code, ep, msg=""):
return {'season': ep.season, 'episode': ep.episode, 'status': _get_status_strings(ep.status),
......@@ -1128,7 +1128,7 @@ class CMD_Backlog(ApiCall):
if s.paused:
continue
for e in sorted(s.episodes(), key=lambda x: (x.season, x.episode), reverse=True):
for e in sorted(s.episodes, key=lambda x: (x.season, x.episode), reverse=True):
curEpCat = s.get_overview(int(e.status or -1))
if curEpCat and curEpCat in (Overview.WANTED, Overview.QUAL):
showEps += [e]
......@@ -2678,7 +2678,7 @@ class CMD_ShowsStats(ApiCall):
overall_stats['episodes']['snatched'] += show.episodes_snatched or 0
overall_stats['episodes']['downloaded'] += show.episodes_downloaded or 0
overall_stats['episodes']['total'] += len(show.episodes()) or 0
overall_stats['episodes']['total'] += len(show.episodes) or 0
overall_stats['total_size'] += show.total_size or 0
return await _responds(RESULT_SUCCESS, {
......
......@@ -66,7 +66,7 @@ class CalendarHandler(BaseHandler, ABC):
if show.status.lower() not in ['continuing', 'returning series'] or show.paused:
continue
for episode in show.episodes():
for episode in show.episodes:
if not past_date <= episode.airdate < future_date:
continue
......
......@@ -116,7 +116,7 @@ class HomeHandler(BaseHandler, ABC):
'ep_airs_prev': show.airs_prev or datetime.date.min,
'ep_snatched': show.episodes_snatched or 0,
'ep_downloaded': show.episodes_downloaded or 0,
'ep_total': len(show.episodes()),
'ep_total': len(show.episodes),
'total_size': show.total_size or 0
}
......@@ -138,7 +138,7 @@ class ShowProgressHandler(BaseHandler, ABC):
episodes_snatched = show.episodes_snatched
episodes_downloaded = show.episodes_downloaded
episodes_total = len(show.episodes()) - show.episodes_special - show.episodes_unaired
episodes_total = len(show.episodes) - show.episodes_special - show.episodes_unaired
progressbar_percent = int(episodes_downloaded * 100 / episodes_total if episodes_total > 0 else 1)
progress_text = '?'
......@@ -778,7 +778,7 @@ class DisplayShowHandler(BaseHandler, ABC):
if not show_obj:
return self._genericMessage(_("Error"), _("Show not in show list"))
episode_objects = sorted(show_obj.episodes(), key=lambda x: (x.season, x.episode), reverse=True)
episode_objects = sorted(show_obj.episodes, key=lambda x: (x.season, x.episode), reverse=True)
season_results = list({x.season for x in episode_objects})
......@@ -1221,7 +1221,7 @@ class TestRenameHandler(BaseHandler, ABC):
episode_objects = []
for cur_ep_obj in (x for x in show_object.episodes() if x.location):
for cur_ep_obj in (x for x in show_object.episodes if x.location):
if cur_ep_obj.location:
if cur_ep_obj.related_episodes:
for cur_related_ep in cur_ep_obj.related_episodes + [cur_ep_obj]:
......
......@@ -368,7 +368,7 @@ class EpisodeStatusesHandler(BaseHandler, ABC):
# if we have no status then this is as far as we need to go
if len(status_list):
for show in sorted(get_show_list(), key=lambda d: d.name):
for episode in show.episodes():
for episode in show.episodes:
if episode.season != 0 and episode.status in status_list:
if show.indexer_id not in ep_counts:
ep_counts[show.indexer_id] = 1
......@@ -492,7 +492,7 @@ class SubtitleMissedHandler(BaseHandler, ABC):
if not s.subtitles == 1:
continue
for e in s.episodes():
for e in s.episodes:
if e.season != 0 and (str(e.status).endswith('4') or str(e.status).endswith('6')):
status_results += [{
'show_name': s.name,
......@@ -598,7 +598,7 @@ class BacklogOverviewHandler(BaseHandler, ABC):
show_results[curShow.indexer_id] = []
for curResult in sorted(curShow.episodes(), key=lambda x: (x.season, x.episode), reverse=True):
for curResult in sorted(curShow.episodes, key=lambda x: (x.season, x.episode), reverse=True):
cur_ep_cat = curShow.get_overview(int(curResult.status or -1))
if cur_ep_cat:
ep_cats["{}x{}".format(curResult.season, curResult.episode)] = cur_ep_cat
......
......@@ -270,7 +270,7 @@ class GenericMetadata(object):
def create_season_posters(self, show_obj, force=False):
if self.season_posters and show_obj:
result = []
for ep_obj in show_obj.episodes():
for ep_obj in show_obj.episodes:
if not self._has_season_poster(show_obj, ep_obj.season) or force:
sickrage.app.log.debug("Metadata provider " + self.name + " creating season posters for " + show_obj.name)
result = result + [self.save_season_poster(show_obj, ep_obj.season)]
......@@ -281,7 +281,7 @@ class GenericMetadata(object):
if self.season_banners and show_obj:
result = []
sickrage.app.log.debug("Metadata provider " + self.name + " creating season banners for " + show_obj.name)
for ep_obj in show_obj.episodes():
for ep_obj in show_obj.episodes:
if not self._has_season_banner(show_obj, ep_obj.season) or force:
result = result + [self.save_season_banner(show_obj, ep_obj.season)]
return all(result)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment