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.
|
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)))
|
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 cached:
|
||||||
if fix_scene_numbering:
|
if fix_scene_numbering:
|
||||||
cached_fixed = copy.copy(cached)
|
cached_fixed = copy.deepcopy(cached)
|
||||||
cached_fixed.fix_scene_numbering()
|
cached_fixed.fix_scene_numbering()
|
||||||
return cached_fixed
|
return cached_fixed
|
||||||
return cached
|
return cached
|
||||||
|
@ -248,7 +248,7 @@ class NameParser(object):
|
||||||
name_parser_cache.add(name, final_result)
|
name_parser_cache.add(name, final_result)
|
||||||
|
|
||||||
if fix_scene_numbering:
|
if fix_scene_numbering:
|
||||||
result_fixed = copy.copy(final_result)
|
result_fixed = copy.deepcopy(final_result)
|
||||||
result_fixed.fix_scene_numbering()
|
result_fixed.fix_scene_numbering()
|
||||||
return result_fixed
|
return result_fixed
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,8 @@ class TVEpisode(tv.TVEpisode):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._season = season
|
self._season = season
|
||||||
self._episode = episode
|
self._episode = episode
|
||||||
|
self._scene_season = season
|
||||||
|
self._scene_episode = episode
|
||||||
self._airdate = datetime.date(2010, 3, 9)
|
self._airdate = datetime.date(2010, 3, 9)
|
||||||
self.show = TVShow()
|
self.show = TVShow()
|
||||||
self._status = Quality.compositeStatus(common.DOWNLOADED, common.Quality.SDTV)
|
self._status = Quality.compositeStatus(common.DOWNLOADED, common.Quality.SDTV)
|
||||||
|
|
|
@ -258,7 +258,7 @@ class BTNProvider(generic.TorrentProvider):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Do a general name search for the episode, formatted like SXXEYY
|
# 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]
|
to_return = [search_params]
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ class DTTProvider(generic.TorrentProvider):
|
||||||
return search_string
|
return search_string
|
||||||
|
|
||||||
def _get_episode_search_strings(self, episode):
|
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):
|
def _doSearch(self, search_params, show=None, age=None):
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,8 @@ class EZRSSProvider(generic.TorrentProvider):
|
||||||
if ep_obj.show.air_by_date:
|
if ep_obj.show.air_by_date:
|
||||||
params['date'] = str(ep_obj.airdate)
|
params['date'] = str(ep_obj.airdate)
|
||||||
else:
|
else:
|
||||||
params['season'] = ep_obj.season
|
params['season'] = ep_obj.scene_season
|
||||||
params['episode'] = ep_obj.episode
|
params['episode'] = ep_obj.scene_episode
|
||||||
|
|
||||||
return [params]
|
return [params]
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import sys
|
||||||
import re
|
import re
|
||||||
import urllib
|
import urllib
|
||||||
import urllib2
|
import urllib2
|
||||||
import copy
|
|
||||||
import itertools
|
import itertools
|
||||||
import operator
|
import operator
|
||||||
import collections
|
import collections
|
||||||
|
@ -41,7 +41,6 @@ from sickbeard import encodingKludge as ek
|
||||||
from sickbeard.exceptions import ex
|
from sickbeard.exceptions import ex
|
||||||
from lib.hachoir_parser import createParser
|
from lib.hachoir_parser import createParser
|
||||||
from sickbeard.name_parser.parser import NameParser, InvalidNameException
|
from sickbeard.name_parser.parser import NameParser, InvalidNameException
|
||||||
from sickbeard import scene_numbering
|
|
||||||
from sickbeard.common import Quality, Overview
|
from sickbeard.common import Quality, Overview
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,13 +242,8 @@ class GenericProvider:
|
||||||
|
|
||||||
self._checkAuth()
|
self._checkAuth()
|
||||||
|
|
||||||
# XEM episode scene numbering
|
|
||||||
with episode.lock:
|
|
||||||
sceneEpisode = copy.deepcopy(episode)
|
|
||||||
sceneEpisode.convertToSceneNumbering()
|
|
||||||
|
|
||||||
logger.log(u'Searching "%s" for "%s" as "%s"'
|
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()
|
self.cache.updateCache()
|
||||||
results = self.cache.searchCache(episode, manualSearch)
|
results = self.cache.searchCache(episode, manualSearch)
|
||||||
|
@ -264,7 +258,7 @@ class GenericProvider:
|
||||||
|
|
||||||
itemList = []
|
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)
|
itemList += self._doSearch(cur_search_string, show=episode.show)
|
||||||
|
|
||||||
for item in itemList:
|
for item in itemList:
|
||||||
|
@ -314,21 +308,20 @@ class GenericProvider:
|
||||||
|
|
||||||
itemList = []
|
itemList = []
|
||||||
results = {}
|
results = {}
|
||||||
sceneSeasons = {}
|
seasons = {}
|
||||||
searchSeason = False
|
searchSeason = False
|
||||||
|
|
||||||
|
|
||||||
# convert wanted seasons and episodes to XEM scene numbering
|
# convert wanted seasons and episodes to XEM scene numbering
|
||||||
seasonEp = show.getAllEpisodes(season)
|
seasonEp = show.getAllEpisodes(season)
|
||||||
wantedEp = [x for x in seasonEp if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)]
|
wantedEp = [x for x in seasonEp if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)]
|
||||||
map(lambda x: x.convertToSceneNumbering(), wantedEp)
|
[seasons.setdefault(x.scene_season, []).append(x) for x in wantedEp]
|
||||||
for x in wantedEp: sceneSeasons.setdefault(x.season, []).append(x)
|
|
||||||
|
|
||||||
if wantedEp == seasonEp and not show.air_by_date:
|
if wantedEp == seasonEp:
|
||||||
searchSeason = True
|
searchSeason = True
|
||||||
|
|
||||||
for sceneSeason, sceneEpisodes in sceneSeasons.iteritems():
|
for season, episodes in seasons.iteritems():
|
||||||
for curString in self._get_season_search_strings(show, sceneSeason, sceneEpisodes, searchSeason):
|
for curString in self._get_season_search_strings(show, season, episodes, searchSeason):
|
||||||
itemList += self._doSearch(curString)
|
itemList += self._doSearch(curString)
|
||||||
|
|
||||||
for item in itemList:
|
for item in itemList:
|
||||||
|
|
|
@ -153,8 +153,8 @@ class HDBitsProvider(generic.TorrentProvider):
|
||||||
if episode:
|
if episode:
|
||||||
post_data['tvdb'] = {
|
post_data['tvdb'] = {
|
||||||
'id': show.indexerid,
|
'id': show.indexerid,
|
||||||
'season': episode.season,
|
'season': episode.scene_season,
|
||||||
'episode': episode.episode
|
'episode': episode.scene_episode
|
||||||
}
|
}
|
||||||
|
|
||||||
if season:
|
if season:
|
||||||
|
|
|
@ -149,8 +149,8 @@ class HDTorrentsProvider(generic.TorrentProvider):
|
||||||
else:
|
else:
|
||||||
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
||||||
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
||||||
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode}
|
'episodenumber': ep_obj.scene_episode}
|
||||||
|
|
||||||
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
||||||
|
|
||||||
|
@ -181,8 +181,6 @@ class HDTorrentsProvider(generic.TorrentProvider):
|
||||||
if not data:
|
if not data:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Remove HDTorrents NEW list
|
# Remove HDTorrents NEW list
|
||||||
split_data = data.partition('<!-- Show New Torrents After Last Visit -->\n\n\n\n')
|
split_data = data.partition('<!-- Show New Torrents After Last Visit -->\n\n\n\n')
|
||||||
data = split_data[2]
|
data = split_data[2]
|
||||||
|
|
|
@ -130,8 +130,8 @@ class IPTorrentsProvider(generic.TorrentProvider):
|
||||||
else:
|
else:
|
||||||
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
||||||
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
||||||
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode} + ' %s' % add_string
|
'episodenumber': ep_obj.scene_episode} + ' %s' % add_string
|
||||||
|
|
||||||
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
||||||
|
|
||||||
|
|
|
@ -208,12 +208,12 @@ class KATProvider(generic.TorrentProvider):
|
||||||
else:
|
else:
|
||||||
for show_name in set(allPossibleShowNames(ep_obj.show)):
|
for show_name in set(allPossibleShowNames(ep_obj.show)):
|
||||||
ep_string = sanitizeSceneName(show_name) + ' ' + \
|
ep_string = sanitizeSceneName(show_name) + ' ' + \
|
||||||
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode} + '|' + \
|
'episodenumber': ep_obj.scene_episode} + '|' + \
|
||||||
sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode} + '|' + \
|
'episodenumber': ep_obj.scene_episode} + '|' + \
|
||||||
sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode} + ' %s category:tv' % add_string
|
'episodenumber': ep_obj.scene_episode} + ' %s category:tv' % add_string
|
||||||
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
||||||
|
|
||||||
return [search_string]
|
return [search_string]
|
||||||
|
|
|
@ -273,7 +273,7 @@ class NewzbinProvider(generic.NZBProvider):
|
||||||
|
|
||||||
nameList = set(show_name_helpers.allPossibleShowNames(ep_obj.show))
|
nameList = set(show_name_helpers.allPossibleShowNames(ep_obj.show))
|
||||||
if not ep_obj.show.air_by_date:
|
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:
|
else:
|
||||||
searchStr = " OR ".join(['^"' + x + ' - ' + str(ep_obj.airdate) + '"' for x in nameList])
|
searchStr = " OR ".join(['^"' + x + ' - ' + str(ep_obj.airdate) + '"' for x in nameList])
|
||||||
return [searchStr]
|
return [searchStr]
|
||||||
|
|
|
@ -127,8 +127,8 @@ class NewznabProvider(generic.NZBProvider):
|
||||||
params['season'] = date_str.partition('-')[0]
|
params['season'] = date_str.partition('-')[0]
|
||||||
params['ep'] = date_str.partition('-')[2].replace('-', '/')
|
params['ep'] = date_str.partition('-')[2].replace('-', '/')
|
||||||
else:
|
else:
|
||||||
params['season'] = ep_obj.season
|
params['season'] = ep_obj.scene_season
|
||||||
params['ep'] = ep_obj.episode
|
params['ep'] = ep_obj.scene_episode
|
||||||
|
|
||||||
to_return = [params]
|
to_return = [params]
|
||||||
|
|
||||||
|
@ -166,21 +166,21 @@ class NewznabProvider(generic.NZBProvider):
|
||||||
if data is None:
|
if data is None:
|
||||||
return self._checkAuth()
|
return self._checkAuth()
|
||||||
|
|
||||||
status = data.status
|
if 'status' in data:
|
||||||
if status:
|
if data.status in [200, 301]:
|
||||||
if status in [200, 301]:
|
|
||||||
return True
|
return True
|
||||||
if status == 100:
|
if data.status == 100:
|
||||||
raise AuthException("Your API key for " + self.name + " is incorrect, check your config.")
|
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.")
|
raise AuthException("Your account on " + self.name + " has been suspended, contact the administrator.")
|
||||||
elif status == 102:
|
elif data.status == 102:
|
||||||
raise AuthException(
|
raise AuthException(
|
||||||
"Your account isn't allowed to use the API on " + self.name + ", contact the administrator")
|
"Your account isn't allowed to use the API on " + self.name + ", contact the administrator")
|
||||||
else:
|
else:
|
||||||
logger.log(u"Unknown error given from " + self.name + ": " + data.feed.title,
|
logger.log(u"Unknown error given from " + self.name + ": " + data.feed.title,
|
||||||
logger.ERROR)
|
logger.ERROR)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _doSearch(self, search_params, show=None, max_age=0):
|
def _doSearch(self, search_params, show=None, max_age=0):
|
||||||
|
|
||||||
|
|
|
@ -167,8 +167,8 @@ class NextGenProvider(generic.TorrentProvider):
|
||||||
else:
|
else:
|
||||||
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
||||||
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
||||||
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode}
|
'episodenumber': ep_obj.scene_episode}
|
||||||
|
|
||||||
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ class NyaaProvider(generic.TorrentProvider):
|
||||||
return names
|
return names
|
||||||
|
|
||||||
def _get_episode_search_strings(self, ep_obj):
|
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):
|
def _doSearch(self, search_string, show=None, age=None):
|
||||||
|
|
||||||
|
@ -136,8 +136,8 @@ class NyaaProvider(generic.TorrentProvider):
|
||||||
|
|
||||||
# parse the file name
|
# parse the file name
|
||||||
try:
|
try:
|
||||||
myParser = NameParser(show=episode.show)
|
myParser = NameParser(False)
|
||||||
parse_result = myParser.parse(title)
|
parse_result = myParser.parse(title, True)
|
||||||
except InvalidNameException:
|
except InvalidNameException:
|
||||||
logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING)
|
logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -115,8 +115,8 @@ class PublicHDProvider(generic.TorrentProvider):
|
||||||
else:
|
else:
|
||||||
for show_name in set(allPossibleShowNames(ep_obj.show)):
|
for show_name in set(allPossibleShowNames(ep_obj.show)):
|
||||||
ep_string = sanitizeSceneName(show_name) + ' ' + \
|
ep_string = sanitizeSceneName(show_name) + ' ' + \
|
||||||
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode}
|
'episodenumber': ep_obj.scene_episode}
|
||||||
|
|
||||||
for x in add_string.split('|'):
|
for x in add_string.split('|'):
|
||||||
to_search = re.sub('\s+', ' ', ep_string + ' %s' % x)
|
to_search = re.sub('\s+', ' ', ep_string + ' %s' % x)
|
||||||
|
|
|
@ -138,8 +138,8 @@ class SCCProvider(generic.TorrentProvider):
|
||||||
else:
|
else:
|
||||||
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
||||||
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
||||||
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode}
|
'episodenumber': ep_obj.scene_episode}
|
||||||
|
|
||||||
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
||||||
|
|
||||||
|
|
|
@ -214,12 +214,12 @@ class ThePirateBayProvider(generic.TorrentProvider):
|
||||||
else:
|
else:
|
||||||
for show_name in set(allPossibleShowNames(ep_obj.show)):
|
for show_name in set(allPossibleShowNames(ep_obj.show)):
|
||||||
ep_string = sanitizeSceneName(show_name) + ' ' + \
|
ep_string = sanitizeSceneName(show_name) + ' ' + \
|
||||||
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode} + '|' + \
|
'episodenumber': ep_obj.scene_episode} + '|' + \
|
||||||
sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode} + '|' + \
|
'episodenumber': ep_obj.scene_episode} + '|' + \
|
||||||
sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode}
|
'episodenumber': ep_obj.scene_episode}
|
||||||
|
|
||||||
ep_string += ' %s' % add_string
|
ep_string += ' %s' % add_string
|
||||||
|
|
||||||
|
|
|
@ -152,8 +152,8 @@ class TorrentDayProvider(generic.TorrentProvider):
|
||||||
else:
|
else:
|
||||||
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
||||||
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
||||||
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode}
|
'episodenumber': ep_obj.scene_episode}
|
||||||
|
|
||||||
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
||||||
|
|
||||||
|
|
|
@ -133,8 +133,8 @@ class TorrentLeechProvider(generic.TorrentProvider):
|
||||||
else:
|
else:
|
||||||
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
|
||||||
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
|
||||||
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season,
|
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
|
||||||
'episodenumber': ep_obj.episode}
|
'episodenumber': ep_obj.scene_episode}
|
||||||
|
|
||||||
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
|
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):
|
if episode.show.air_by_date and episode.airdate != datetime.date.fromordinal(1):
|
||||||
epStrings = [str(episode.airdate)]
|
epStrings = [str(episode.airdate)]
|
||||||
else:
|
else:
|
||||||
epStrings = ["S%02iE%02i" % (int(episode.season), int(episode.episode)),
|
epStrings = ["S%02iE%02i" % (int(episode.scene_season), int(episode.scene_episode)),
|
||||||
"%ix%02i" % (int(episode.season), int(episode.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
|
# 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
|
# 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):
|
class TVEpisode(object):
|
||||||
def __init__(self, show, season, episode, file=""):
|
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._name = ""
|
||||||
self._season = season
|
self._season = season
|
||||||
self._episode = episode
|
self._episode = episode
|
||||||
|
self._scene_season = scene_season
|
||||||
|
self._scene_episode = scene_episode
|
||||||
self._description = ""
|
self._description = ""
|
||||||
self._subtitles = list()
|
self._subtitles = list()
|
||||||
self._subtitles_searchcount = 0
|
self._subtitles_searchcount = 0
|
||||||
|
@ -1162,6 +1166,8 @@ class TVEpisode(object):
|
||||||
name = property(lambda self: self._name, dirty_setter("_name"))
|
name = property(lambda self: self._name, dirty_setter("_name"))
|
||||||
season = property(lambda self: self._season, dirty_setter("_season"))
|
season = property(lambda self: self._season, dirty_setter("_season"))
|
||||||
episode = property(lambda self: self._episode, dirty_setter("_episode"))
|
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"))
|
description = property(lambda self: self._description, dirty_setter("_description"))
|
||||||
subtitles = property(lambda self: self._subtitles, dirty_setter("_subtitles"))
|
subtitles = property(lambda self: self._subtitles, dirty_setter("_subtitles"))
|
||||||
subtitles_searchcount = property(lambda self: self._subtitles_searchcount, dirty_setter("_subtitles_searchcount"))
|
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')
|
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):
|
def _ep_name(self):
|
||||||
"""
|
"""
|
||||||
Returns the name of the episode to use during renaming. Combines the names of related episodes.
|
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,
|
'%0S': '%02d' % self.season,
|
||||||
'%E': str(self.episode),
|
'%E': str(self.episode),
|
||||||
'%0E': '%02d' % 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),
|
'%RN': release_name(self.release_name),
|
||||||
'%RG': release_group(self.release_name),
|
'%RG': release_group(self.release_name),
|
||||||
'%AD': str(self.airdate).replace('-', ' '),
|
'%AD': str(self.airdate).replace('-', ' '),
|
||||||
|
@ -2105,25 +2125,3 @@ class TVEpisode(object):
|
||||||
self.saveToDB()
|
self.saveToDB()
|
||||||
for relEp in self.relatedEps:
|
for relEp in self.relatedEps:
|
||||||
relEp.saveToDB()
|
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):
|
def setUp(self):
|
||||||
super(PPPrivateTests, self).setUp()
|
super(PPPrivateTests, self).setUp()
|
||||||
|
|
||||||
sickbeard.showList = [TVShow(0000), TVShow(0001)]
|
sickbeard.showList = [TVShow(1,0000), TVShow(1,0001)]
|
||||||
|
|
||||||
self.pp = PostProcessor(test.FILEPATH)
|
self.pp = PostProcessor(test.FILEPATH)
|
||||||
self.show_obj = TVShow(0002)
|
self.show_obj = TVShow(1,0002)
|
||||||
|
|
||||||
self.db = test.db.DBConnection()
|
self.db = test.db.DBConnection()
|
||||||
newValueDict = {"tvdbid": 1002,
|
newValueDict = {"indexerid": 1002,
|
||||||
"name": test.SHOWNAME,
|
"name": test.SHOWNAME,
|
||||||
"description": "description",
|
"description": "description",
|
||||||
"airdate": 1234,
|
"airdate": 1234,
|
||||||
|
@ -69,20 +69,21 @@ class PPPrivateTests(test.SickbeardTestDBCase):
|
||||||
self.db.upsert("tv_episodes", newValueDict, controlValueDict)
|
self.db.upsert("tv_episodes", newValueDict, controlValueDict)
|
||||||
|
|
||||||
self.ep_obj = TVEpisode(self.show_obj, test.SEASON, test.EPISODE, test.FILEPATH)
|
self.ep_obj = TVEpisode(self.show_obj, test.SEASON, test.EPISODE, test.FILEPATH)
|
||||||
|
print
|
||||||
|
|
||||||
def test__find_ep_destination_folder(self):
|
def test__find_ep_destination_folder(self):
|
||||||
self.show_obj.location = test.FILEDIR
|
self.show_obj.location = test.FILEDIR
|
||||||
self.ep_obj.show.seasonfolders = 1
|
self.ep_obj.show.seasonfolders = 1
|
||||||
sickbeard.SEASON_FOLDERS_FORMAT = 'Season %02d'
|
sickbeard.SEASON_FOLDERS_FORMAT = 'Season %02d'
|
||||||
calculatedPath = self.pp._find_ep_destination_folder(self.ep_obj)
|
calculatedPath = self.ep_obj.proper_path()
|
||||||
ecpectedPath = os.path.join(test.FILEDIR, "Season 0" + str(test.SEASON))
|
expectedPath = os.path.join(test.FILEDIR, "Season 0" + str(test.SEASON))
|
||||||
self.assertEqual(calculatedPath, ecpectedPath)
|
self.assertEqual(calculatedPath, expectedPath)
|
||||||
|
|
||||||
|
|
||||||
class PPBasicTests(test.SickbeardTestDBCase):
|
class PPBasicTests(test.SickbeardTestDBCase):
|
||||||
|
|
||||||
def test_process(self):
|
def test_process(self):
|
||||||
show = TVShow(3)
|
show = TVShow(1,3)
|
||||||
show.name = test.SHOWNAME
|
show.name = test.SHOWNAME
|
||||||
show.location = test.SHOWDIR
|
show.location = test.SHOWDIR
|
||||||
show.saveToDB()
|
show.saveToDB()
|
||||||
|
|
Loading…
Reference in a new issue