mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-11 05:33:37 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
ad270399b9
23 changed files with 207 additions and 95 deletions
|
@ -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):
|
||||
"""
|
||||
<Purpose>
|
||||
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.
|
||||
<Arguments>
|
||||
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.
|
||||
<Exceptions>
|
||||
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.
|
||||
<Side Effects>
|
||||
A new reference is created to every non-simple type of object. That is,
|
||||
everything except objects of type str, unicode, int, etc.
|
||||
<Returns>
|
||||
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))
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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('<!-- Show New Torrents After Last Visit -->\n\n\n\n')
|
||||
data = split_data[2]
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 True
|
||||
|
||||
def _doSearch(self, search_params, show=None, max_age=0):
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue