diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py index 9be243d2..2afc2124 100644 --- a/sickbeard/helpers.py +++ b/sickbeard/helpers.py @@ -994,3 +994,123 @@ def real_path(path): Returns: the canonicalized absolute pathname. The resulting path will have no symbolic link, '/./' or '/../' components. """ return ek.ek(os.path.normpath, ek.ek(os.path.normcase, ek.ek(os.path.realpath, path))) + +def _copy(self, obj, objectmap=None): + """ + + Create a deep copy of an object without using the python 'copy' module. + Using copy.deepcopy() doesn't work because builtins like id and hasattr + aren't available when this is called. + + self + obj + The object to make a deep copy of. + objectmap + A mapping between original objects and the corresponding copy. This is + used to handle circular references. + + TypeError + If an object is encountered that we don't know how to make a copy of. + NamespaceViolationError + If an unexpected error occurs while copying. This isn't the greatest + solution, but in general the idea is we just need to abort the wrapped + function call. + + A new reference is created to every non-simple type of object. That is, + everything except objects of type str, unicode, int, etc. + + The deep copy of obj with circular/recursive references preserved. + """ + try: + # If this is a top-level call to _copy, create a new objectmap for use + # by recursive calls to _copy. + if objectmap is None: + objectmap = {} + # If this is a circular reference, use the copy we already made. + elif _saved_id(obj) in objectmap: + return objectmap[_saved_id(obj)] + + # types.InstanceType is included because the user can provide an instance + # of a class of their own in the list of callback args to settimer. + if _is_in(type(obj), [str, unicode, int, long, float, complex, bool, frozenset, + types.NoneType, types.FunctionType, types.LambdaType, + types.MethodType, types.InstanceType]): + return obj + + elif type(obj) is list: + temp_list = [] + # Need to save this in the objectmap before recursing because lists + # might have circular references. + objectmap[_saved_id(obj)] = temp_list + + for item in obj: + temp_list.append(self._copy(item, objectmap)) + + return temp_list + + elif type(obj) is tuple: + temp_list = [] + + for item in obj: + temp_list.append(self._copy(item, objectmap)) + + # I'm not 100% confident on my reasoning here, so feel free to point + # out where I'm wrong: There's no way for a tuple to directly contain + # a circular reference to itself. Instead, it has to contain, for + # example, a dict which has the same tuple as a value. In that + # situation, we can avoid infinite recursion and properly maintain + # circular references in our copies by checking the objectmap right + # after we do the copy of each item in the tuple. The existence of the + # dictionary would keep the recursion from being infinite because those + # are properly handled. That just leaves making sure we end up with + # only one copy of the tuple. We do that here by checking to see if we + # just made a copy as a result of copying the items above. If so, we + # return the one that's already been made. + if _saved_id(obj) in objectmap: + return objectmap[_saved_id(obj)] + + retval = tuple(temp_list) + objectmap[_saved_id(obj)] = retval + return retval + + elif type(obj) is set: + temp_list = [] + # We can't just store this list object in the objectmap because it isn't + # a set yet. If it's possible to have a set contain a reference to + # itself, this could result in infinite recursion. However, sets can + # only contain hashable items so I believe this can't happen. + + for item in obj: + temp_list.append(self._copy(item, objectmap)) + + retval = set(temp_list) + objectmap[_saved_id(obj)] = retval + return retval + + elif type(obj) is dict: + temp_dict = {} + # Need to save this in the objectmap before recursing because dicts + # might have circular references. + objectmap[_saved_id(obj)] = temp_dict + + for key, value in obj.items(): + temp_key = self._copy(key, objectmap) + temp_dict[temp_key] = self._copy(value, objectmap) + + return temp_dict + + # We don't copy certain objects. This is because copying an emulated file + # object, for example, will cause the destructor of the original one to + # be invoked, which will close the actual underlying file. As the object + # is wrapped and the client does not have access to it, it's safe to not + # wrap it. + elif isinstance(obj, (NamespaceObjectWrapper, emulfile.emulated_file, + emulcomm.emulated_socket, thread.LockType, + virtual_namespace.VirtualNamespace)): + return obj + + else: + raise TypeError("_copy is not implemented for objects of type " + str(type(obj))) + + except Exception, e: + self._handle_violation("_copy failed on " + str(obj) + " with message " + str(e)) \ No newline at end of file diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index aefd2b26..82e6595f 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -193,7 +193,7 @@ class NameParser(object): if cached: if fix_scene_numbering: - cached_fixed = copy.copy(cached) + cached_fixed = copy.deepcopy(cached) cached_fixed.fix_scene_numbering() return cached_fixed return cached @@ -248,7 +248,7 @@ class NameParser(object): name_parser_cache.add(name, final_result) if fix_scene_numbering: - result_fixed = copy.copy(final_result) + result_fixed = copy.deepcopy(final_result) result_fixed.fix_scene_numbering() return result_fixed diff --git a/sickbeard/naming.py b/sickbeard/naming.py index 33148168..1f08b49a 100644 --- a/sickbeard/naming.py +++ b/sickbeard/naming.py @@ -54,6 +54,8 @@ class TVEpisode(tv.TVEpisode): self._name = name self._season = season self._episode = episode + self._scene_season = season + self._scene_episode = episode self._airdate = datetime.date(2010, 3, 9) self.show = TVShow() self._status = Quality.compositeStatus(common.DOWNLOADED, common.Quality.SDTV) diff --git a/sickbeard/providers/btn.py b/sickbeard/providers/btn.py index 2ddb8599..24fad569 100644 --- a/sickbeard/providers/btn.py +++ b/sickbeard/providers/btn.py @@ -258,7 +258,7 @@ class BTNProvider(generic.TorrentProvider): else: # Do a general name search for the episode, formatted like SXXEYY - search_params['name'] = "S%02dE%02d" % (ep_obj.season, ep_obj.episode) + search_params['name'] = "S%02dE%02d" % (ep_obj.scene_season, ep_obj.scene_episode) to_return = [search_params] diff --git a/sickbeard/providers/dtt.py b/sickbeard/providers/dtt.py index 83e77f2d..881958fb 100644 --- a/sickbeard/providers/dtt.py +++ b/sickbeard/providers/dtt.py @@ -63,7 +63,7 @@ class DTTProvider(generic.TorrentProvider): return search_string def _get_episode_search_strings(self, episode): - return self._get_season_search_strings(episode.show, episode.season) + return self._get_season_search_strings(episode.show, episode.scene_season) def _doSearch(self, search_params, show=None, age=None): diff --git a/sickbeard/providers/ezrss.py b/sickbeard/providers/ezrss.py index f141e302..7cab1b26 100644 --- a/sickbeard/providers/ezrss.py +++ b/sickbeard/providers/ezrss.py @@ -95,8 +95,8 @@ class EZRSSProvider(generic.TorrentProvider): if ep_obj.show.air_by_date: params['date'] = str(ep_obj.airdate) else: - params['season'] = ep_obj.season - params['episode'] = ep_obj.episode + params['season'] = ep_obj.scene_season + params['episode'] = ep_obj.scene_episode return [params] diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index 997d6d1e..02b1c3f0 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -25,7 +25,7 @@ import sys import re import urllib import urllib2 -import copy + import itertools import operator import collections @@ -41,7 +41,6 @@ from sickbeard import encodingKludge as ek from sickbeard.exceptions import ex from lib.hachoir_parser import createParser from sickbeard.name_parser.parser import NameParser, InvalidNameException -from sickbeard import scene_numbering from sickbeard.common import Quality, Overview @@ -243,13 +242,8 @@ class GenericProvider: self._checkAuth() - # XEM episode scene numbering - with episode.lock: - sceneEpisode = copy.deepcopy(episode) - sceneEpisode.convertToSceneNumbering() - logger.log(u'Searching "%s" for "%s" as "%s"' - % (self.name, episode.prettyName(), sceneEpisode.prettyName())) + % (self.name, episode.prettyName(), episode.scene_prettyName())) self.cache.updateCache() results = self.cache.searchCache(episode, manualSearch) @@ -264,7 +258,7 @@ class GenericProvider: itemList = [] - for cur_search_string in self._get_episode_search_strings(sceneEpisode): + for cur_search_string in self._get_episode_search_strings(episode): itemList += self._doSearch(cur_search_string, show=episode.show) for item in itemList: @@ -314,21 +308,20 @@ class GenericProvider: itemList = [] results = {} - sceneSeasons = {} + seasons = {} searchSeason = False # convert wanted seasons and episodes to XEM scene numbering seasonEp = show.getAllEpisodes(season) wantedEp = [x for x in seasonEp if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)] - map(lambda x: x.convertToSceneNumbering(), wantedEp) - for x in wantedEp: sceneSeasons.setdefault(x.season, []).append(x) + [seasons.setdefault(x.scene_season, []).append(x) for x in wantedEp] - if wantedEp == seasonEp and not show.air_by_date: + if wantedEp == seasonEp: searchSeason = True - for sceneSeason, sceneEpisodes in sceneSeasons.iteritems(): - for curString in self._get_season_search_strings(show, sceneSeason, sceneEpisodes, searchSeason): + for season, episodes in seasons.iteritems(): + for curString in self._get_season_search_strings(show, season, episodes, searchSeason): itemList += self._doSearch(curString) for item in itemList: diff --git a/sickbeard/providers/hdbits.py b/sickbeard/providers/hdbits.py index a8bc8479..b89f4a1d 100644 --- a/sickbeard/providers/hdbits.py +++ b/sickbeard/providers/hdbits.py @@ -153,8 +153,8 @@ class HDBitsProvider(generic.TorrentProvider): if episode: post_data['tvdb'] = { 'id': show.indexerid, - 'season': episode.season, - 'episode': episode.episode + 'season': episode.scene_season, + 'episode': episode.scene_episode } if season: diff --git a/sickbeard/providers/hdtorrents.py b/sickbeard/providers/hdtorrents.py index e4e1b8b3..cce85c1a 100644 --- a/sickbeard/providers/hdtorrents.py +++ b/sickbeard/providers/hdtorrents.py @@ -149,8 +149,8 @@ class HDTorrentsProvider(generic.TorrentProvider): else: for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) @@ -181,8 +181,6 @@ class HDTorrentsProvider(generic.TorrentProvider): if not data: continue - - # Remove HDTorrents NEW list split_data = data.partition('\n\n\n\n') data = split_data[2] diff --git a/sickbeard/providers/iptorrents.py b/sickbeard/providers/iptorrents.py index 76ae5bfd..7207d385 100644 --- a/sickbeard/providers/iptorrents.py +++ b/sickbeard/providers/iptorrents.py @@ -130,8 +130,8 @@ class IPTorrentsProvider(generic.TorrentProvider): else: for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + ' %s' % add_string + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} + ' %s' % add_string search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) diff --git a/sickbeard/providers/kat.py b/sickbeard/providers/kat.py index 50247643..4d3748ca 100644 --- a/sickbeard/providers/kat.py +++ b/sickbeard/providers/kat.py @@ -208,12 +208,12 @@ class KATProvider(generic.TorrentProvider): else: for show_name in set(allPossibleShowNames(ep_obj.show)): ep_string = sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + '|' + \ - sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + '|' + \ - sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + ' %s category:tv' % add_string + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} + '|' + \ + sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} + '|' + \ + sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} + ' %s category:tv' % add_string search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) return [search_string] diff --git a/sickbeard/providers/newzbin.py b/sickbeard/providers/newzbin.py index d93eeace..2eb364a4 100644 --- a/sickbeard/providers/newzbin.py +++ b/sickbeard/providers/newzbin.py @@ -273,7 +273,7 @@ class NewzbinProvider(generic.NZBProvider): nameList = set(show_name_helpers.allPossibleShowNames(ep_obj.show)) if not ep_obj.show.air_by_date: - searchStr = " OR ".join(['^"' + x + ' - %dx%02d"' % (ep_obj.season, ep_obj.episode) for x in nameList]) + searchStr = " OR ".join(['^"' + x + ' - %dx%02d"' % (ep_obj.scene_season, ep_obj.scene_episode) for x in nameList]) else: searchStr = " OR ".join(['^"' + x + ' - ' + str(ep_obj.airdate) + '"' for x in nameList]) return [searchStr] diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py index 68196fa8..e55d31dc 100644 --- a/sickbeard/providers/newznab.py +++ b/sickbeard/providers/newznab.py @@ -127,8 +127,8 @@ class NewznabProvider(generic.NZBProvider): params['season'] = date_str.partition('-')[0] params['ep'] = date_str.partition('-')[2].replace('-', '/') else: - params['season'] = ep_obj.season - params['ep'] = ep_obj.episode + params['season'] = ep_obj.scene_season + params['ep'] = ep_obj.scene_episode to_return = [params] @@ -166,21 +166,21 @@ class NewznabProvider(generic.NZBProvider): if data is None: return self._checkAuth() - status = data.status - if status: - if status in [200, 301]: + if 'status' in data: + if data.status in [200, 301]: return True - if status == 100: + if data.status == 100: raise AuthException("Your API key for " + self.name + " is incorrect, check your config.") - elif status == 101: + elif data.status == 101: raise AuthException("Your account on " + self.name + " has been suspended, contact the administrator.") - elif status == 102: + elif data.status == 102: raise AuthException( "Your account isn't allowed to use the API on " + self.name + ", contact the administrator") else: logger.log(u"Unknown error given from " + self.name + ": " + data.feed.title, logger.ERROR) - return False + return False + return True def _doSearch(self, search_params, show=None, max_age=0): diff --git a/sickbeard/providers/nextgen.py b/sickbeard/providers/nextgen.py index 9eae9f17..56d10fa5 100644 --- a/sickbeard/providers/nextgen.py +++ b/sickbeard/providers/nextgen.py @@ -167,8 +167,8 @@ class NextGenProvider(generic.TorrentProvider): else: for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) diff --git a/sickbeard/providers/nyaatorrents.py b/sickbeard/providers/nyaatorrents.py index e3265c16..671817ac 100644 --- a/sickbeard/providers/nyaatorrents.py +++ b/sickbeard/providers/nyaatorrents.py @@ -67,7 +67,7 @@ class NyaaProvider(generic.TorrentProvider): return names def _get_episode_search_strings(self, ep_obj): - return self._get_season_search_strings(ep_obj.show, ep_obj.season) + return self._get_season_search_strings(ep_obj.show, ep_obj.scene_season) def _doSearch(self, search_string, show=None, age=None): @@ -136,8 +136,8 @@ class NyaaProvider(generic.TorrentProvider): # parse the file name try: - myParser = NameParser(show=episode.show) - parse_result = myParser.parse(title) + myParser = NameParser(False) + parse_result = myParser.parse(title, True) except InvalidNameException: logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING) continue diff --git a/sickbeard/providers/publichd.py b/sickbeard/providers/publichd.py index 35473b5a..eef309de 100644 --- a/sickbeard/providers/publichd.py +++ b/sickbeard/providers/publichd.py @@ -115,8 +115,8 @@ class PublicHDProvider(generic.TorrentProvider): else: for show_name in set(allPossibleShowNames(ep_obj.show)): ep_string = sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} for x in add_string.split('|'): to_search = re.sub('\s+', ' ', ep_string + ' %s' % x) diff --git a/sickbeard/providers/scc.py b/sickbeard/providers/scc.py index a4591ace..874857f0 100644 --- a/sickbeard/providers/scc.py +++ b/sickbeard/providers/scc.py @@ -138,8 +138,8 @@ class SCCProvider(generic.TorrentProvider): else: for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) diff --git a/sickbeard/providers/thepiratebay.py b/sickbeard/providers/thepiratebay.py index c98dd4fd..1d4e9e5a 100644 --- a/sickbeard/providers/thepiratebay.py +++ b/sickbeard/providers/thepiratebay.py @@ -214,12 +214,12 @@ class ThePirateBayProvider(generic.TorrentProvider): else: for show_name in set(allPossibleShowNames(ep_obj.show)): ep_string = sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + '|' + \ - sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + '|' + \ - sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} + '|' + \ + sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} + '|' + \ + sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} ep_string += ' %s' % add_string diff --git a/sickbeard/providers/torrentday.py b/sickbeard/providers/torrentday.py index 60a98e5a..a732dfcc 100644 --- a/sickbeard/providers/torrentday.py +++ b/sickbeard/providers/torrentday.py @@ -152,8 +152,8 @@ class TorrentDayProvider(generic.TorrentProvider): else: for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) diff --git a/sickbeard/providers/torrentleech.py b/sickbeard/providers/torrentleech.py index ac1c9324..8c229187 100644 --- a/sickbeard/providers/torrentleech.py +++ b/sickbeard/providers/torrentleech.py @@ -133,8 +133,8 @@ class TorrentLeechProvider(generic.TorrentProvider): else: for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, - 'episodenumber': ep_obj.episode} + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) diff --git a/sickbeard/show_name_helpers.py b/sickbeard/show_name_helpers.py index 37c39ea3..2f8665bb 100644 --- a/sickbeard/show_name_helpers.py +++ b/sickbeard/show_name_helpers.py @@ -170,8 +170,8 @@ def makeSceneSearchString(episode): if episode.show.air_by_date and episode.airdate != datetime.date.fromordinal(1): epStrings = [str(episode.airdate)] else: - epStrings = ["S%02iE%02i" % (int(episode.season), int(episode.episode)), - "%ix%02i" % (int(episode.season), int(episode.episode))] + epStrings = ["S%02iE%02i" % (int(episode.scene_season), int(episode.scene_episode)), + "%ix%02i" % (int(episode.scene_season), int(episode.scene_episode))] # for single-season shows just search for the show name -- if total ep count (exclude s0) is less than 11 # due to the amount of qualities and releases, it is easy to go over the 50 result limit on rss feeds otherwise diff --git a/sickbeard/tv.py b/sickbeard/tv.py index ba152e30..52842f16 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -1125,10 +1125,14 @@ def dirty_setter(attr_name): class TVEpisode(object): def __init__(self, show, season, episode, file=""): + # Convert season/episode to XEM scene numbering + scene_season, scene_episode = sickbeard.scene_numbering.get_scene_numbering(show.indexerid, season, episode) self._name = "" self._season = season self._episode = episode + self._scene_season = scene_season + self._scene_episode = scene_episode self._description = "" self._subtitles = list() self._subtitles_searchcount = 0 @@ -1162,6 +1166,8 @@ class TVEpisode(object): name = property(lambda self: self._name, dirty_setter("_name")) season = property(lambda self: self._season, dirty_setter("_season")) episode = property(lambda self: self._episode, dirty_setter("_episode")) + scene_season = property(lambda self: self._scene_season, dirty_setter("_scene_season")) + scene_episode = property(lambda self: self._scene_episode, dirty_setter("_scene_episode")) description = property(lambda self: self._description, dirty_setter("_description")) subtitles = property(lambda self: self._subtitles, dirty_setter("_subtitles")) subtitles_searchcount = property(lambda self: self._subtitles_searchcount, dirty_setter("_subtitles_searchcount")) @@ -1728,6 +1734,16 @@ class TVEpisode(object): return self._format_pattern('%SN - %Sx%0E - %EN') + def scene_prettyName(self): + """ + Returns the name of this episode in a "pretty" human-readable format. Used for logging + and notifications and such. + + Returns: A string representing the episode's name and season/ep numbers + """ + + return self._format_pattern('%SN - %SSx%0SE - %EN') + def _ep_name(self): """ Returns the name of the episode to use during renaming. Combines the names of related episodes. @@ -1827,6 +1843,10 @@ class TVEpisode(object): '%0S': '%02d' % self.season, '%E': str(self.episode), '%0E': '%02d' % self.episode, + '%XS': str(self.scene_season), + '%0XS': '%02d' % self.scene_season, + '%XE': str(self.scene_episode), + '%0XE': '%02d' % self.scene_episode, '%RN': release_name(self.release_name), '%RG': release_group(self.release_name), '%AD': str(self.airdate).replace('-', ' '), @@ -2105,25 +2125,3 @@ class TVEpisode(object): self.saveToDB() for relEp in self.relatedEps: relEp.saveToDB() - - def convertToSceneNumbering(self): - if self.show.air_by_date: return - - if self.season is None: return # can't work without a season - if self.episode is None: return # need to know the episode - - indexer_id = self.show.indexerid - - (self.season, self.episode) = sickbeard.scene_numbering.get_scene_numbering(indexer_id, self.season, - self.episode) - - def convertToIndexer(self): - if self.show.air_by_date: return - - if self.season is None: return # can't work without a season - if self.episode is None: return # need to know the episode - - indexer_id = self.show.indexerid - - (self.season, self.episode) = sickbeard.scene_numbering.get_indexer_numbering(indexer_id, self.season, - self.episode) diff --git a/tests/pp_tests.py b/tests/pp_tests.py index 2360ea9d..cd34ac22 100644 --- a/tests/pp_tests.py +++ b/tests/pp_tests.py @@ -47,13 +47,13 @@ class PPPrivateTests(test.SickbeardTestDBCase): def setUp(self): super(PPPrivateTests, self).setUp() - sickbeard.showList = [TVShow(0000), TVShow(0001)] + sickbeard.showList = [TVShow(1,0000), TVShow(1,0001)] self.pp = PostProcessor(test.FILEPATH) - self.show_obj = TVShow(0002) + self.show_obj = TVShow(1,0002) self.db = test.db.DBConnection() - newValueDict = {"tvdbid": 1002, + newValueDict = {"indexerid": 1002, "name": test.SHOWNAME, "description": "description", "airdate": 1234, @@ -69,20 +69,21 @@ class PPPrivateTests(test.SickbeardTestDBCase): self.db.upsert("tv_episodes", newValueDict, controlValueDict) self.ep_obj = TVEpisode(self.show_obj, test.SEASON, test.EPISODE, test.FILEPATH) + print def test__find_ep_destination_folder(self): self.show_obj.location = test.FILEDIR self.ep_obj.show.seasonfolders = 1 sickbeard.SEASON_FOLDERS_FORMAT = 'Season %02d' - calculatedPath = self.pp._find_ep_destination_folder(self.ep_obj) - ecpectedPath = os.path.join(test.FILEDIR, "Season 0" + str(test.SEASON)) - self.assertEqual(calculatedPath, ecpectedPath) + calculatedPath = self.ep_obj.proper_path() + expectedPath = os.path.join(test.FILEDIR, "Season 0" + str(test.SEASON)) + self.assertEqual(calculatedPath, expectedPath) class PPBasicTests(test.SickbeardTestDBCase): def test_process(self): - show = TVShow(3) + show = TVShow(1,3) show.name = test.SHOWNAME show.location = test.SHOWDIR show.saveToDB()