Complete re-code of season/episode search code.

Switched from using standard requests to using sessions.
Fixed bug in speedcd that was preventing config from saving.
This commit is contained in:
echel0n 2014-04-27 03:31:54 -07:00
parent 18b781532c
commit 5772de9eec
36 changed files with 570 additions and 873 deletions

View file

@ -178,9 +178,6 @@ TVTORRENTS = False
TVTORRENTS_DIGEST = None TVTORRENTS_DIGEST = None
TVTORRENTS_HASH = None TVTORRENTS_HASH = None
TORRENTLEECH = False
TORRENTLEECH_KEY = None
BTN = False BTN = False
BTN_API_KEY = None BTN_API_KEY = None
@ -193,6 +190,7 @@ THEPIRATEBAY_PROXY_URL = None
THEPIRATEBAY_BLACKLIST = None THEPIRATEBAY_BLACKLIST = None
TORRENTLEECH = False TORRENTLEECH = False
TORRENTLEECH_KEY = None
TORRENTLEECH_USERNAME = None TORRENTLEECH_USERNAME = None
TORRENTLEECH_PASSWORD = None TORRENTLEECH_PASSWORD = None
@ -232,6 +230,11 @@ HDBITS = False
HDBITS_USERNAME = None HDBITS_USERNAME = None
HDBITS_PASSKEY = None HDBITS_PASSKEY = None
SPEEDCD = False
SPEEDCD_USERNAME = None
SPEEDCD_PASSWORD = None
SPEEDCD_FREELEECH = None
ADD_SHOWS_WO_DIR = None ADD_SHOWS_WO_DIR = None
CREATE_MISSING_SHOW_DIRS = None CREATE_MISSING_SHOW_DIRS = None
RENAME_EPISODES = False RENAME_EPISODES = False

View file

@ -32,6 +32,12 @@ naming_ep_type = ("%(seasonnumber)dx%(episodenumber)02d",
"s%(seasonnumber)02de%(episodenumber)02d", "s%(seasonnumber)02de%(episodenumber)02d",
"S%(seasonnumber)02dE%(episodenumber)02d", "S%(seasonnumber)02dE%(episodenumber)02d",
"%(seasonnumber)02dx%(episodenumber)02d") "%(seasonnumber)02dx%(episodenumber)02d")
sports_ep_type = ("%(seasonnumber)dx%(episodenumber)02d",
"s%(seasonnumber)02de%(episodenumber)02d",
"S%(seasonnumber)02dE%(episodenumber)02d",
"%(seasonnumber)02dx%(episodenumber)02d")
naming_ep_type_text = ("1x02", "s01e02", "S01E02", "01x02") naming_ep_type_text = ("1x02", "s01e02", "S01E02", "01x02")
naming_multi_ep_type = {0: ["-%(episodenumber)02d"] * len(naming_ep_type), naming_multi_ep_type = {0: ["-%(episodenumber)02d"] * len(naming_ep_type),

View file

@ -50,20 +50,18 @@ except ImportError:
from xml.dom.minidom import Node from xml.dom.minidom import Node
import sickbeard import sickbeard
from sickbeard.exceptions import MultipleShowObjectsException, ex from sickbeard.exceptions import MultipleShowObjectsException, ex
from sickbeard import logger, classes from sickbeard import logger, classes
from sickbeard.common import USER_AGENT, mediaExtensions, subtitleExtensions, XML_NSMAP from sickbeard.common import USER_AGENT, mediaExtensions, subtitleExtensions, XML_NSMAP
from sickbeard import db from sickbeard import db
from sickbeard import encodingKludge as ek from sickbeard import encodingKludge as ek
from sickbeard import notifiers from sickbeard import notifiers
from sickbeard import exceptions
from lib import subliminal from lib import subliminal
#from sickbeard.subtitles import EXTENSIONS
urllib._urlopener = classes.SickBeardURLopener() urllib._urlopener = classes.SickBeardURLopener()
session = requests.Session()
def indentXML(elem, level=0): def indentXML(elem, level=0):
''' '''
@ -172,6 +170,10 @@ def getURL(url, post_data=None, headers=None, params=None, json=False):
Returns a byte-string retrieved from the url provider. Returns a byte-string retrieved from the url provider.
""" """
global session
if not session:
session = requests.Session()
req_headers = ['User-Agent', USER_AGENT, 'Accept-Encoding', 'gzip,deflate'] req_headers = ['User-Agent', USER_AGENT, 'Accept-Encoding', 'gzip,deflate']
if headers: if headers:
for cur_header in headers: for cur_header in headers:
@ -191,9 +193,9 @@ Returns a byte-string retrieved from the url provider.
"https": sickbeard.PROXY_SETTING, "https": sickbeard.PROXY_SETTING,
} }
resp = requests.get(url, params=params, data=post_data, headers=dict(zip(it, it)), proxies=proxies, verify=False) r = session.get(url, params=params, data=post_data, headers=dict(zip(it, it)), proxies=proxies, verify=False)
else: else:
resp = requests.get(url, params=params, data=post_data, headers=dict(zip(it, it)), verify=False) r = session.get(url, params=params, data=post_data, headers=dict(zip(it, it)), verify=False)
except requests.HTTPError, e: except requests.HTTPError, e:
logger.log(u"HTTP error " + str(e.errno) + " while loading URL " + url, logger.WARNING) logger.log(u"HTTP error " + str(e.errno) + " while loading URL " + url, logger.WARNING)
return None return None
@ -207,9 +209,9 @@ Returns a byte-string retrieved from the url provider.
return None return None
if json: if json:
return resp.json() if resp.ok else None return r.json() if r.ok else None
return resp.content if resp.ok else None return r.content if r.ok else None
def _remove_file_failed(file): def _remove_file_failed(file):
@ -220,8 +222,12 @@ def _remove_file_failed(file):
def download_file(url, filename): def download_file(url, filename):
global session
if not session:
session = requests.Session()
try: try:
r = requests.get(url, stream=True, verify=False) r = session.get(url, stream=True, verify=False)
with open(filename, 'wb') as fp: with open(filename, 'wb') as fp:
for chunk in r.iter_content(chunk_size=1024): for chunk in r.iter_content(chunk_size=1024):
if chunk: if chunk:
@ -995,122 +1001,19 @@ def real_path(path):
""" """
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): def validateShow(show, season=None, episode=None):
""" indexer_lang = show.lang
<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: try:
# If this is a top-level call to _copy, create a new objectmap for use lINDEXER_API_PARMS = sickbeard.indexerApi(show.indexer).api_params.copy()
# 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 if indexer_lang and not indexer_lang == 'en':
# of a class of their own in the list of callback args to settimer. lINDEXER_API_PARMS['language'] = indexer_lang
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: t = sickbeard.indexerApi(show.indexer).indexer(**lINDEXER_API_PARMS)
temp_list = [] if season is None and episode is None:
# Need to save this in the objectmap before recursing because lists return t
# might have circular references.
objectmap[_saved_id(obj)] = temp_list
for item in obj: return t[show.indexerid][season][episode]
temp_list.append(self._copy(item, objectmap)) except (sickbeard.indexer_episodenotfound, sickbeard.indexer_seasonnotfound):
pass
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))

View file

@ -343,44 +343,17 @@ class GenericMetadata():
""" """
all_eps = [ep_obj] + ep_obj.relatedEps all_eps = [ep_obj] + ep_obj.relatedEps
indexer_lang = ep_obj.show.lang # validate show
if not helpers.validateShow(ep_obj.show):
# get a TVDB object
try:
# There's gotta be a better way of doing this but we don't wanna
# change the language value elsewhere
lINDEXER_API_PARMS = sickbeard.indexerApi(ep_obj.show.indexer).api_params.copy()
lINDEXER_API_PARMS['actors'] = True
if indexer_lang and not indexer_lang == 'en':
lINDEXER_API_PARMS['language'] = indexer_lang
if ep_obj.show.dvdorder != 0:
lINDEXER_API_PARMS['dvdorder'] = True
t = sickbeard.indexerApi(ep_obj.show.indexer).indexer(**lINDEXER_API_PARMS)
indexer_show_obj = t[ep_obj.show.indexerid]
except sickbeard.indexer_shownotfound, e:
raise exceptions.ShowNotFoundException(e.message)
except sickbeard.indexer_error, e:
logger.log(u"Unable to connect to " + sickbeard.indexerApi(
ep_obj.show.indexer).name + " while creating meta files - skipping - " + ex(e), logger.ERROR)
return None return None
# try all included episodes in case some have thumbs and others don't # try all included episodes in case some have thumbs and others don't
for cur_ep in all_eps: for cur_ep in all_eps:
try: myEp = helpers.validateShow(cur_ep.show, cur_ep.season, cur_ep.episode)
myEp = indexer_show_obj[cur_ep.season][cur_ep.episode] if not myEp:
except (sickbeard.indexer_episodenotfound, sickbeard.indexer_seasonnotfound):
logger.log(u"Unable to find episode " + str(cur_ep.season) + "x" + str(
cur_ep.episode) + " on " + sickbeard.indexerApi(
ep_obj.show.indexer).name + ".. has it been removed? Should I delete from db?")
continue continue
thumb_url = getattr(myEp, 'filename', None) thumb_url = getattr(myEp, 'filename', None)
if thumb_url is not None: if thumb_url is not None:
return thumb_url return thumb_url

View file

@ -193,7 +193,7 @@ class NameParser(object):
if cached: if cached:
if fix_scene_numbering: if fix_scene_numbering:
cached_fixed = copy.deepcopy(cached) cached_fixed = copy.copy(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.deepcopy(final_result) result_fixed = copy.copy(final_result)
result_fixed.fix_scene_numbering() result_fixed.fix_scene_numbering()
return result_fixed return result_fixed

View file

@ -191,7 +191,7 @@ class BTNProvider(generic.TorrentProvider):
return (title, url) return (title, url)
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
if not show: if not show:
return [] return []
@ -210,47 +210,35 @@ class BTNProvider(generic.TorrentProvider):
# Search by name if we don't have tvdb or tvrage id # Search by name if we don't have tvdb or tvrage id
current_params['series'] = sanitizeSceneName(name) current_params['series'] = sanitizeSceneName(name)
if searchSeason: whole_season_params = current_params.copy()
whole_season_params = current_params.copy() partial_season_params = current_params.copy()
partial_season_params = current_params.copy() # Search for entire seasons: no need to do special things for air by date shows
# Search for entire seasons: no need to do special things for air by date shows whole_season_params['category'] = 'Season'
whole_season_params['category'] = 'Season' whole_season_params['name'] = 'Season ' + str(season)
whole_season_params['name'] = 'Season ' + str(season)
search_params.append(whole_season_params) search_params.append(whole_season_params)
# Search for episodes in the season # Search for episodes in the season
partial_season_params['category'] = 'Episode' search_params.append(self._get_episode_search_strings(show, season, episode, abd)[0])
if show.air_by_date:
# Search for the year of the air by date show
partial_season_params['name'] = str(season).split('-')[0]
else:
# Search for any result which has Sxx in the name
partial_season_params['name'] = 'S%02d' % int(season)
search_params.append(partial_season_params)
else:
search_params.append(current_params)
return search_params return search_params
def _get_episode_search_strings(self, ep_obj): def _get_episode_search_strings(self, show, season, episode, abd=False):
if not ep_obj: if not episode:
return [{}] return [{}]
search_params = {'category': 'Episode'} search_params = {'category': 'Episode'}
if ep_obj.show.indexer == 1: if show.indexer == 1:
search_params['tvdb'] = ep_obj.show.indexerid search_params['tvdb'] = show.indexerid
elif ep_obj.show.indexer == 2: elif show.indexer == 2:
search_params['tvrage'] = ep_obj.show.indexerid search_params['tvrage'] = show.indexerid
else: else:
search_params['series'] = sanitizeSceneName(ep_obj.show.name) search_params['series'] = sanitizeSceneName(show.name)
if ep_obj.show.air_by_date: if abd:
date_str = str(ep_obj.airdate) date_str = str(episode)
# BTN uses dots in dates, we just search for the date since that # BTN uses dots in dates, we just search for the date since that
# combined with the series identifier should result in just one episode # combined with the series identifier should result in just one episode
@ -258,7 +246,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.scene_season, ep_obj.scene_episode) search_params['name'] = "S%02dE%02d" % (season, episode)
to_return = [search_params] to_return = [search_params]
@ -266,11 +254,11 @@ class BTNProvider(generic.TorrentProvider):
if 'series' in search_params: if 'series' in search_params:
# add new query string for every exception # add new query string for every exception
name_exceptions = scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) name_exceptions = scene_exceptions.get_scene_exceptions(show.indexerid)
for cur_exception in name_exceptions: for cur_exception in name_exceptions:
# don't add duplicates # don't add duplicates
if cur_exception == ep_obj.show.name: if cur_exception == show.name:
continue continue
# copy all other parameters before setting the show name for this exception # copy all other parameters before setting the show name for this exception

View file

@ -46,14 +46,13 @@ class DTTProvider(generic.TorrentProvider):
quality = Quality.sceneQuality(url) quality = Quality.sceneQuality(url)
return quality return quality
def findSeasonResults(self, show, season): def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
return generic.TorrentProvider.getSearchResults(self, show, season, ep_objs, seasonSearch, manualSearch)
return generic.TorrentProvider.findSeasonResults(self, show, season)
def _dtt_show_id(self, show_name): def _dtt_show_id(self, show_name):
return sanitizeSceneName(show_name).replace('.', '-').lower() return sanitizeSceneName(show_name).replace('.', '-').lower()
def _get_season_search_strings(self, show, season, wantedEp=None, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = [] search_string = []
for show_name in set(show_name_helpers.allPossibleShowNames(show)): for show_name in set(show_name_helpers.allPossibleShowNames(show)):
@ -62,8 +61,8 @@ class DTTProvider(generic.TorrentProvider):
return search_string return search_string
def _get_episode_search_strings(self, episode): def _get_episode_search_strings(self, show, season, episode, abd=False):
return self._get_season_search_strings(episode.show, episode.scene_season) return self._get_season_search_strings(show, season, episode, abd)
def _doSearch(self, search_params, show=None, age=None): def _doSearch(self, search_params, show=None, age=None):

View file

@ -57,7 +57,7 @@ class EZRSSProvider(generic.TorrentProvider):
return quality return quality
def findSeasonResults(self, show, season): def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
results = {} results = {}
@ -66,11 +66,11 @@ class EZRSSProvider(generic.TorrentProvider):
logger.WARNING) logger.WARNING)
return results return results
results = generic.TorrentProvider.findSeasonResults(self, show, season) results = generic.TorrentProvider.getSearchResults(self, show, season, ep_objs, seasonSearch, manualSearch)
return results return results
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
params = {} params = {}
@ -81,22 +81,24 @@ class EZRSSProvider(generic.TorrentProvider):
params['season'] = season params['season'] = season
params['episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['episode']
return [params] return [params]
def _get_episode_search_strings(self, ep_obj): def _get_episode_search_strings(self, show, season, episode, abd=False):
params = {} params = {}
if not ep_obj: if not episode:
return params return params
params['show_name'] = helpers.sanitizeSceneName(ep_obj.show.name, ezrss=True).replace('.', ' ').encode('utf-8') params['show_name'] = helpers.sanitizeSceneName(show.name, ezrss=True).replace('.', ' ').encode('utf-8')
if ep_obj.show.air_by_date: if abd:
params['date'] = str(ep_obj.airdate) params['date'] = str(episode)
else: else:
params['season'] = ep_obj.scene_season params['season'] = season
params['episode'] = ep_obj.scene_episode params['episode'] = episode
return [params] return [params]

View file

@ -214,10 +214,10 @@ class GenericProvider:
def _doSearch(self, search_params, show=None, age=None): def _doSearch(self, search_params, show=None, age=None):
return [] return []
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
return [] return []
def _get_episode_search_strings(self, ep_obj): def _get_episode_search_strings(self, show, season, episode, abd=False):
return [] return []
def _get_title_and_url(self, item): def _get_title_and_url(self, item):
@ -238,91 +238,38 @@ class GenericProvider:
return (title, url) return (title, url)
def findEpisode(self, episode, manualSearch=False): def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
self._checkAuth()
logger.log(u'Searching "%s" for "%s" as "%s"'
% (self.name, episode.prettyName(), episode.scene_prettyName()))
self.cache.updateCache()
results = self.cache.searchCache(episode, manualSearch)
logger.log(u"Cache results: " + str(results), logger.DEBUG)
logger.log(u"manualSearch: " + str(manualSearch), logger.DEBUG)
# if we got some results then use them no matter what.
# OR
# return anyway unless we're doing a manual search
if results or not manualSearch:
return results
itemList = []
for cur_search_string in self._get_episode_search_strings(episode):
itemList += self._doSearch(cur_search_string, show=episode.show)
for item in itemList:
(title, url) = self._get_title_and_url(item)
# parse the file name
try:
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
if episode.show.air_by_date:
if parse_result.air_date != episode.airdate:
logger.log(u"Episode " + title + " didn't air on " + str(episode.airdate) + ", skipping it",
logger.DEBUG)
continue
elif parse_result.season_number != episode.season or episode.episode not in parse_result.episode_numbers:
logger.log(u"Episode " + title + " isn't " + str(episode.season) + "x" + str(
episode.episode) + ", skipping it", logger.DEBUG)
continue
quality = self.getQuality(item)
if not episode.show.wantEpisode(episode.season, episode.episode, quality, manualSearch):
logger.log(
u"Ignoring result " + title + " because we don't want an episode that is " + Quality.qualityStrings[
quality], logger.DEBUG)
continue
logger.log(u"Found result " + title + " at " + url, logger.DEBUG)
result = self.getResult([episode])
result.url = url
result.name = title
result.quality = quality
result.provider = self
result.content = None
results.append(result)
return results
def findSeasonResults(self, show, season):
itemList = [] itemList = []
results = {} results = {}
seasons = {}
searchSeason = False
self._checkAuth()
# convert wanted seasons and episodes to XEM scene numbering for ep_obj in ep_objs:
seasonEp = show.getAllEpisodes(season) logger.log(u'Searching "%s" for "%s" as "%s"'
wantedEp = [x for x in seasonEp if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)] % (self.name, ep_obj.prettyName(), ep_obj.scene_prettyName()))
[seasons.setdefault(x.scene_season, []).append(x) for x in wantedEp]
if wantedEp == seasonEp: self.cache.updateCache()
searchSeason = True results = self.cache.searchCache(ep_obj, manualSearch)
logger.log(u"Cache results: " + str(results), logger.DEBUG)
logger.log(u"manualSearch: " + str(manualSearch), logger.DEBUG)
for season, episodes in seasons.iteritems(): # if we got some results then use them no matter what.
for curString in self._get_season_search_strings(show, season, episodes, searchSeason): # OR
itemList += self._doSearch(curString) # return anyway unless we're doing a manual search
if results or not manualSearch:
return results
abd = False
if show.air_by_date:
abd = True
if seasonSearch:
for curString in self._get_season_search_strings(show, ep_obj.scene_season, ep_obj.scene_episode, abd=abd):
itemList += self._doSearch(curString)
else:
for curString in self._get_episode_search_strings(show, ep_obj.scene_season, ep_obj.scene_episode, abd=abd):
itemList += self._doSearch(curString, show=show)
for item in itemList: for item in itemList:
@ -373,7 +320,7 @@ class GenericProvider:
# make sure we want the episode # make sure we want the episode
wantEp = True wantEp = True
for epNo in actual_episodes: for epNo in actual_episodes:
if not show.wantEpisode(actual_season, epNo, quality): if not show.wantEpisode(actual_season, epNo, quality, manualSearch=manualSearch):
wantEp = False wantEp = False
break break
@ -411,7 +358,7 @@ class GenericProvider:
if epNum in results: if epNum in results:
results[epNum].append(result) results[epNum].append(result)
else: else:
results[epNum] = [result] results = {epNum:[result]}
return results return results

View file

@ -18,7 +18,7 @@ import generic
import sickbeard import sickbeard
from sickbeard import logger, tvcache, exceptions from sickbeard import logger, tvcache, exceptions
from sickbeard.common import Quality from sickbeard.common import Quality, Overview
from sickbeard.exceptions import ex, AuthException from sickbeard.exceptions import ex, AuthException
from sickbeard.name_parser.parser import NameParser, InvalidNameException from sickbeard.name_parser.parser import NameParser, InvalidNameException
@ -66,72 +66,87 @@ class HDBitsProvider(generic.TorrentProvider):
return True return True
def findEpisode(self, episode, manualSearch=False): def searchProviders(self, show, season, episode=None, manualSearch=False):
itemList = []
results = {}
logger.log(u"Searching " + self.name + " for " + episode.prettyName()) logger.log(u"Searching for stuff we need from " + show.name + " season " + str(season))
self.cache.updateCache() # gather all episodes for season and then pick out the wanted episodes and compare to determin if we want whole season or just a few episodes
results = self.cache.searchCache(episode, manualSearch) if episode is None:
logger.log(u"Cache results: " + str(results), logger.DEBUG) seasonEps = show.getAllEpisodes(season)
wantedEps = [x for x in seasonEps if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)]
else:
wantedEps = [show.getEpisode(season, episode)]
# if we got some results then use them no matter what. for ep_obj in wantedEps:
# OR season = ep_obj.scene_season
# return anyway unless we're doing a manual search episode = ep_obj.scene_episode
if results or not manualSearch:
return results
parsedJSON = self.getURL(self.search_url, post_data=self._make_post_data_JSON(show=episode.show, episode=episode), json=True) self.cache.updateCache()
results = self.cache.searchCache(episode, manualSearch)
logger.log(u"Cache results: " + str(results), logger.DEBUG)
if not parsedJSON: # if we got some results then use them no matter what.
logger.log(u"No data returned from " + self.search_url, logger.ERROR) # OR
return [] # return anyway unless we're doing a manual search
if results or not manualSearch:
return results
if self._checkAuthFromData(parsedJSON): itemList += self.getURL(self.search_url, post_data=self._make_post_data_JSON(show=show, season=season, episode=episode), json=True)
results = []
if parsedJSON and 'data' in parsedJSON:
items = parsedJSON['data']
else:
logger.log(u"Resulting JSON from " + self.name + " isn't correct, not parsing it", logger.ERROR)
items = []
for item in items: for parsedJSON in itemList:
if not parsedJSON:
logger.log(u"No data returned from " + self.search_url, logger.ERROR)
return []
(title, url) = self._get_title_and_url(item) if self._checkAuthFromData(parsedJSON):
results = []
# parse the file name if parsedJSON and 'data' in parsedJSON:
try: items = parsedJSON['data']
myParser = NameParser() else:
parse_result = myParser.parse(title) logger.log(u"Resulting JSON from " + self.name + " isn't correct, not parsing it", logger.ERROR)
except InvalidNameException: items = []
logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING)
continue
if episode.show.air_by_date: for item in items:
if parse_result.air_date != episode.airdate:
logger.log(u"Episode " + title + " didn't air on " + str(episode.airdate) + ", skipping it", (title, url) = self._get_title_and_url(item)
logger.DEBUG)
# parse the file name
try:
myParser = NameParser()
parse_result = myParser.parse(title, True)
except InvalidNameException:
logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING)
continue continue
elif parse_result.season_number != episode.season or episode.episode not in parse_result.episode_numbers:
logger.log(u"Episode " + title + " isn't " + str(episode.season) + "x" + str(
episode.episode) + ", skipping it", logger.DEBUG)
continue
quality = self.getQuality(item) if episode.show.air_by_date:
if parse_result.air_date != episode.airdate:
logger.log(u"Episode " + title + " didn't air on " + str(episode.airdate) + ", skipping it",
logger.DEBUG)
continue
elif parse_result.season_number != episode.season or episode.episode not in parse_result.episode_numbers:
logger.log(u"Episode " + title + " isn't " + str(episode.season) + "x" + str(
episode.episode) + ", skipping it", logger.DEBUG)
continue
if not episode.show.wantEpisode(episode.season, episode.episode, quality, manualSearch): quality = self.getQuality(item)
logger.log(u"Ignoring result " + title + " because we don't want an episode that is " +
Quality.qualityStrings[quality], logger.DEBUG)
continue
logger.log(u"Found result " + title + " at " + url, logger.DEBUG) if not episode.show.wantEpisode(episode.season, episode.episode, quality, manualSearch):
logger.log(u"Ignoring result " + title + " because we don't want an episode that is " +
Quality.qualityStrings[quality], logger.DEBUG)
continue
result = self.getResult([episode]) logger.log(u"Found result " + title + " at " + url, logger.DEBUG)
result.url = url
result.name = title
result.quality = quality
results.append(result) result = self.getResult([episode])
result.url = url
result.name = title
result.quality = quality
results.append(result)
return results return results
@ -153,8 +168,8 @@ class HDBitsProvider(generic.TorrentProvider):
if episode: if episode:
post_data['tvdb'] = { post_data['tvdb'] = {
'id': show.indexerid, 'id': show.indexerid,
'season': episode.scene_season, 'season': season,
'episode': episode.scene_episode 'episode': episode
} }
if season: if season:

View file

@ -111,46 +111,36 @@ class HDTorrentsProvider(generic.TorrentProvider):
return True return True
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []}
if not show: if not show:
return [] return []
self.show = show search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
if searchSeason: search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
for ep_obj in wantedEp:
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
if not search_string['Episode']:
return []
return [search_string] return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''): def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if not episode:
return [] return []
if ep_obj.show.air_by_date: if abd:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \ str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate) helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(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.scene_season, sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} 'episodenumber': episode}
search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) search_string['Episode'].append(re.sub('\s+', ' ', ep_string))

View file

@ -92,46 +92,37 @@ class IPTorrentsProvider(generic.TorrentProvider):
return True return True
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []}
if not show: if not show:
return [] return []
self.show = show search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
if searchSeason: search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
for ep_obj in wantedEp:
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
if not search_string['Episode']:
return []
return [search_string] return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''): def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if not episode:
return [] return []
if ep_obj.show.air_by_date: if abd:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \ str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate) helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(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.scene_season, sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} + ' %s' % add_string 'episodenumber': episode} + ' %s' % add_string
search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) search_string['Episode'].append(re.sub('\s+', ' ', ep_string))

View file

@ -61,6 +61,8 @@ class KATProvider(generic.TorrentProvider):
self.searchurl = self.url + 'usearch/%s/?field=seeders&sorder=desc' #order by seed self.searchurl = self.url + 'usearch/%s/?field=seeders&sorder=desc' #order by seed
self.session = requests.Session()
def isEnabled(self): def isEnabled(self):
return sickbeard.KAT return sickbeard.KAT
@ -164,56 +166,40 @@ class KATProvider(generic.TorrentProvider):
logger.log(u"Failed parsing " + self.name + " Traceback: " + traceback.format_exc(), logger.ERROR) logger.log(u"Failed parsing " + self.name + " Traceback: " + traceback.format_exc(), logger.ERROR)
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []} search_string = {'Season': [], 'Episode': []}
if not show: if not show:
return [] return []
self.show = show for show_name in set(allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) + ' -S%02d' % int(season) + 'E' + ' category:tv' #1) ShowName SXX -SXXE
search_string['Season'].append(ep_string)
if searchSeason: ep_string = show_name + ' Season ' + str(season) + ' -Ep*' + ' category:tv' #2) ShowName Season X
search_string = {'Season': [], 'Episode': []} search_string['Season'].append(ep_string)
for show_name in set(allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) + ' -S%02d' % int(season) + 'E' + ' category:tv' #1) ShowName SXX -SXXE
search_string['Season'].append(ep_string)
ep_string = show_name + ' Season ' + str(season) + ' -Ep*' + ' category:tv' #2) ShowName Season X search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string['Season'].append(ep_string)
for ep_obj in wantedEp:
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
if not search_string['Episode']:
return []
return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''):
def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if abd:
return [] for show_name in set(allPossibleShowNames(show)):
self.show = ep_obj.show
if ep_obj.show.air_by_date:
for show_name in set(allPossibleShowNames(ep_obj.show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \ ep_string = sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \ str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate) helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(allPossibleShowNames(ep_obj.show)): for show_name in set(allPossibleShowNames(show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \ ep_string = sanitizeSceneName(show_name) + ' ' + \
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} + '|' + \ 'episodenumber': episode} + '|' + \
sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season, sickbeard.config.naming_ep_type[0] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} + '|' + \ 'episodenumber': episode} + '|' + \
sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.scene_season, sickbeard.config.naming_ep_type[3] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} + ' %s category:tv' % add_string 'episodenumber': 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]
@ -308,21 +294,24 @@ class KATProvider(generic.TorrentProvider):
def getURL(self, url, post_data=None, headers=None): def getURL(self, url, post_data=None, headers=None):
if not self.session:
self.session = requests.Session()
try: try:
# Remove double-slashes from url # Remove double-slashes from url
parsed = list(urlparse.urlparse(url)) parsed = list(urlparse.urlparse(url))
parsed[2] = re.sub("/{2,}", "/", parsed[2]) # replace two or more / with one parsed[2] = re.sub("/{2,}", "/", parsed[2]) # replace two or more / with one
url = urlparse.urlunparse(parsed) url = urlparse.urlunparse(parsed)
if sickbeard.PROXY_SETTING: if sickbeard.PROXY_SETTING:
proxies = { proxies = {
"http": sickbeard.PROXY_SETTING, "http": sickbeard.PROXY_SETTING,
"https": sickbeard.PROXY_SETTING, "https": sickbeard.PROXY_SETTING,
} }
r = requests.get(url, proxies=proxies, verify=False) r = self.session.get(url, proxies=proxies, verify=False)
else: else:
r = requests.get(url, verify=False) r = self.session.get(url, verify=False)
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e: except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
logger.log(u"Error loading " + self.name + " URL: " + str(sys.exc_info()) + " - " + ex(e), logger.ERROR) logger.log(u"Error loading " + self.name + " URL: " + str(sys.exc_info()) + " - " + ex(e), logger.ERROR)
return None return None
@ -339,6 +328,9 @@ class KATProvider(generic.TorrentProvider):
Save the result to disk. Save the result to disk.
""" """
if not self.session:
self.session = requests.Session()
torrent_hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0].upper() torrent_hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0].upper()
if not torrent_hash: if not torrent_hash:
@ -346,7 +338,7 @@ class KATProvider(generic.TorrentProvider):
return False return False
try: try:
r = requests.get('http://torcache.net/torrent/' + torrent_hash + '.torrent', verify=False) r = self.session.get('http://torcache.net/torrent/' + torrent_hash + '.torrent', verify=False)
except Exception, e: except Exception, e:
logger.log("Unable to connect to Torcache: " + ex(e), logger.ERROR) logger.log("Unable to connect to Torcache: " + ex(e), logger.ERROR)
return False return False

View file

@ -251,32 +251,11 @@ class NewzbinProvider(generic.NZBProvider):
return data return data
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
return ['^' + x for x in show_name_helpers.makeSceneSeasonSearchString(show, season, episode, abd)]
nameList = set(show_name_helpers.allPossibleShowNames(show)) def _get_episode_search_strings(self, show, season, episode, abd=False):
return ['^' + x for x in show_name_helpers.makeSceneSearchString(show, season, episode, abd)]
if show.air_by_date:
suffix = ''
else:
suffix = 'x'
searchTerms = ['^"' + x + ' - ' + str(season) + suffix + '"' for x in nameList]
#searchTerms += ['^"'+x+' - Season '+str(season)+'"' for x in nameList]
searchStr = " OR ".join(searchTerms)
searchStr += " -subpack -extras"
logger.log("Searching newzbin for string " + searchStr, logger.DEBUG)
return [searchStr]
def _get_episode_search_strings(self, ep_obj):
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.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]
def _doSearch(self, searchStr, show=None, age=None): def _doSearch(self, searchStr, show=None, age=None):

View file

@ -80,7 +80,7 @@ class NewznabProvider(generic.NZBProvider):
def isEnabled(self): def isEnabled(self):
return self.enabled return self.enabled
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
if not show: if not show:
return [{}] return [{}]
@ -94,41 +94,35 @@ class NewznabProvider(generic.NZBProvider):
cur_params = {} cur_params = {}
# search # search
cur_params['q'] = helpers.sanitizeSceneName(cur_exception) cur_params['q'] = helpers.sanitizeSceneName(cur_exception)
# air-by-date means &season=2010&q=2010.03, no other way to do it atm # season
if show.air_by_date: cur_params['season'] = str(season)
cur_params['season'] = str(season).split('-')[0] to_return.append(cur_params)
if 'q' in cur_params:
cur_params['q'] += '.' + str(season).replace('-', '.')
else:
cur_params['q'] = str(season).replace('-', '.')
else:
cur_params['season'] = str(season)
to_return.append(cur_params) # episode
to_return['episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['ep']
return to_return return to_return
def _get_episode_search_strings(self, ep_obj): def _get_episode_search_strings(self, show, season, episode, abd=False):
params = {} params = {}
if not ep_obj: if not episode:
return [params] return [params]
# search # search
params['q'] = helpers.sanitizeSceneName(ep_obj.show.name) params['q'] = helpers.sanitizeSceneName(show.name)
if ep_obj.show.air_by_date: if abd:
date_str = str(ep_obj.airdate) date_str = str(episode)
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.scene_season params['season'] = season
params['ep'] = ep_obj.scene_episode params['ep'] = episode
to_return = [params] to_return = [params]
@ -136,11 +130,11 @@ class NewznabProvider(generic.NZBProvider):
if 'q' in params: if 'q' in params:
# add new query strings for exceptions # add new query strings for exceptions
name_exceptions = scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) name_exceptions = scene_exceptions.get_scene_exceptions(show.indexerid)
for cur_exception in name_exceptions: for cur_exception in name_exceptions:
# don't add duplicates # don't add duplicates
if cur_exception == ep_obj.show.name: if cur_exception == show.name:
continue continue
cur_return = params.copy() cur_return = params.copy()

View file

@ -129,46 +129,38 @@ class NextGenProvider(generic.TorrentProvider):
logger.log(u'Failed to login:' + str(error), logger.ERROR) logger.log(u'Failed to login:' + str(error), logger.ERROR)
return False return False
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []}
if not show: if not show:
return [] return []
self.show = show search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
if searchSeason: search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
for ep_obj in wantedEp:
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
if not search_string['Episode']:
return []
return [search_string] return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''): def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if not episode:
return [] return []
if ep_obj.show.air_by_date: if abd:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \ str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate) helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(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.scene_season, sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} 'episodenumber': episode}
search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) search_string['Episode'].append(re.sub('\s+', ' ', ep_string))

View file

@ -54,20 +54,17 @@ class NyaaProvider(generic.TorrentProvider):
quality = Quality.sceneQuality(title) quality = Quality.sceneQuality(title)
return quality return quality
def findSeasonResults(self, show, season): def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
results = {} results = generic.TorrentProvider.getSearchResults(self, show, season, ep_objs, seasonSearch, manualSearch)
results = generic.TorrentProvider.findSeasonResults(self, show, season)
return results return results
def _get_season_search_strings(self, show, season, wantedEp=None, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
names = [] names = []
names.extend(show_name_helpers.makeSceneShowSearchStrings(show)) names.extend(show_name_helpers.makeSceneShowSearchStrings(show))
return names return names
def _get_episode_search_strings(self, ep_obj): def _get_episode_search_strings(self, show, season, episode, abd=False):
return self._get_season_search_strings(ep_obj.show, ep_obj.scene_season) return self._get_season_search_strings(show, season, episode, abd)
def _doSearch(self, search_string, show=None, age=None): def _doSearch(self, search_string, show=None, age=None):
@ -109,74 +106,6 @@ class NyaaProvider(generic.TorrentProvider):
return generic.TorrentProvider._get_title_and_url(self, item) return generic.TorrentProvider._get_title_and_url(self, item)
def findEpisode(self, episode, manualSearch=False):
self._checkAuth()
logger.log(u"Searching " + self.name + " for " + episode.prettyName())
self.cache.updateCache()
results = self.cache.searchCache(episode, manualSearch)
logger.log(u"Cache results: " + str(results), logger.DEBUG)
# if we got some results then use them no matter what.
# OR
# return anyway unless we're doing a manual search
if results or not manualSearch:
return results
itemList = []
for cur_search_string in self._get_episode_search_strings(episode):
itemList += self._doSearch(cur_search_string, show=episode.show)
for item in itemList:
(title, url) = self._get_title_and_url(item)
# parse the file name
try:
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
if episode.show.air_by_date:
if parse_result.air_date != episode.airdate:
logger.log("Episode " + title + " didn't air on " + str(episode.airdate) + ", skipping it",
logger.DEBUG)
continue
elif episode.show.anime and episode.show.absolute_numbering:
if episode.absolute_number not in parse_result.ab_episode_numbers:
logger.log("Episode " + title + " isn't " + str(episode.absolute_number) + ", skipping it",
logger.DEBUG)
continue
elif parse_result.season_number != episode.season or episode.episode not in parse_result.episode_numbers:
logger.log(
"Episode " + title + " isn't " + str(episode.season) + "x" + str(episode.episode) + ", skipping it",
logger.DEBUG)
continue
quality = self.getQuality(item, episode.show.anime)
if not episode.show.wantEpisode(episode.season, episode.episode, quality, manualSearch):
logger.log(
u"Ignoring result " + title + " because we don't want an episode that is " + Quality.qualityStrings[
quality], logger.DEBUG)
continue
logger.log(u"Found result " + title + " at " + url, logger.DEBUG)
result = self.getResult([episode])
result.url = url
result.name = title
result.quality = quality
results.append(result)
return results
def _extract_name_from_filename(self, filename): def _extract_name_from_filename(self, filename):
name_regex = '(.*?)\.?(\[.*]|\d+\.TPB)\.torrent$' name_regex = '(.*?)\.?(\[.*]|\d+\.TPB)\.torrent$'
logger.log(u"Comparing " + name_regex + " against " + filename, logger.DEBUG) logger.log(u"Comparing " + name_regex + " against " + filename, logger.DEBUG)
@ -204,7 +133,7 @@ class NyaaCache(tvcache.TVCache):
logger.log(u"NyaaTorrents cache update URL: " + url, logger.DEBUG) logger.log(u"NyaaTorrents cache update URL: " + url, logger.DEBUG)
data = self.provider.getURL(url) data = self.provider.getRSSFeed(url)
return data return data

View file

@ -53,11 +53,11 @@ class NZBsProvider(generic.NZBProvider):
if sickbeard.NZBS_UID in (None, "") or sickbeard.NZBS_HASH in (None, ""): if sickbeard.NZBS_UID in (None, "") or sickbeard.NZBS_HASH in (None, ""):
raise exceptions.AuthException("NZBs.org authentication details are empty, check your config") raise exceptions.AuthException("NZBs.org authentication details are empty, check your config")
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
return ['^' + x for x in show_name_helpers.makeSceneSeasonSearchString(show, season)] return ['^' + x for x in show_name_helpers.makeSceneSeasonSearchString(show, season, episode, abd)]
def _get_episode_search_strings(self, ep_obj): def _get_episode_search_strings(self, show, season, episode, abd=False):
return ['^' + x for x in show_name_helpers.makeSceneSearchString(ep_obj)] return ['^' + x for x in show_name_helpers.makeSceneSearchString(show, season, episode, abd)]
def _doSearch(self, curString, show=None, age=None): def _doSearch(self, curString, show=None, age=None):

View file

@ -42,11 +42,11 @@ class NZBsRUSProvider(generic.NZBProvider):
if sickbeard.NZBSRUS_UID in (None, "") or sickbeard.NZBSRUS_HASH in (None, ""): if sickbeard.NZBSRUS_UID in (None, "") or sickbeard.NZBSRUS_HASH in (None, ""):
raise exceptions.AuthException("NZBs'R'US authentication details are empty, check your config") raise exceptions.AuthException("NZBs'R'US authentication details are empty, check your config")
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
return ['^' + x for x in show_name_helpers.makeSceneSeasonSearchString(show, season)] return ['^' + x for x in show_name_helpers.makeSceneSeasonSearchString(show, season, episode, abd)]
def _get_episode_search_strings(self, ep_obj): def _get_episode_search_strings(self, show, season, episode, abd=False):
return ['^' + x for x in show_name_helpers.makeSceneSearchString(ep_obj)] return ['^' + x for x in show_name_helpers.makeSceneSearchString(show, season, episode, abd)]
def _doSearch(self, search, show=None, age=None): def _doSearch(self, search, show=None, age=None):
params = {'uid': sickbeard.NZBSRUS_UID, params = {'uid': sickbeard.NZBSRUS_UID,

View file

@ -85,11 +85,11 @@ class OmgwtfnzbsProvider(generic.NZBProvider):
return True return True
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
return [x for x in show_name_helpers.makeSceneSeasonSearchString(show, season)] return [x for x in show_name_helpers.makeSceneSeasonSearchString(show, season, episode, abd)]
def _get_episode_search_strings(self, ep_obj): def _get_episode_search_strings(self, show, season, episode, abd=False):
return [x for x in show_name_helpers.makeSceneSearchString(ep_obj)] return [x for x in show_name_helpers.makeSceneSearchString(show, season, episode, abd)]
def _get_title_and_url(self, item): def _get_title_and_url(self, item):
return (item['release'], item['getnzb']) return (item['release'], item['getnzb'])

View file

@ -61,6 +61,8 @@ class PublicHDProvider(generic.TorrentProvider):
self.categories = {'Season': ['23'], 'Episode': ['7', '14', '24'], 'RSS': ['7', '14', '23', '24']} self.categories = {'Season': ['23'], 'Episode': ['7', '14', '24'], 'RSS': ['7', '14', '23', '24']}
self.session = requests.Session()
def isEnabled(self): def isEnabled(self):
return sickbeard.PUBLICHD return sickbeard.PUBLICHD
@ -72,51 +74,41 @@ class PublicHDProvider(generic.TorrentProvider):
quality = Quality.sceneQuality(item[0]) quality = Quality.sceneQuality(item[0])
return quality return quality
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []}
if not show: if not show:
return [] return []
self.show = show search_string = {'Season': [], 'Episode': []}
for show_name in set(allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX -SXXE
search_string['Season'].append(ep_string)
if searchSeason: ep_string = show_name + ' Season ' + str(season) #2) ShowName Season X
search_string = {'Season': [], 'Episode': []} search_string['Season'].append(ep_string)
for show_name in set(allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX -SXXE
search_string['Season'].append(ep_string)
ep_string = show_name + ' Season ' + str(season) #2) ShowName Season X search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string['Season'].append(ep_string)
for ep_obj in wantedEp:
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
if not search_string['Episode']:
return []
return [search_string] return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''): def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if not episode:
return [] return []
self.show = ep_obj.show if abd:
for show_name in set(allPossibleShowNames(show)):
if ep_obj.show.air_by_date:
for show_name in set(allPossibleShowNames(ep_obj.show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \ ep_string = sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \ str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate) helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(allPossibleShowNames(ep_obj.show)): for show_name in set(allPossibleShowNames(show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \ ep_string = sanitizeSceneName(show_name) + ' ' + \
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} 'episodenumber': 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)
@ -206,13 +198,16 @@ class PublicHDProvider(generic.TorrentProvider):
def getURL(self, url, post_data=None, headers=None): def getURL(self, url, post_data=None, headers=None):
if not self.session:
self.session = requests.Session()
try: try:
# Remove double-slashes from url # Remove double-slashes from url
parsed = list(urlparse.urlparse(url)) parsed = list(urlparse.urlparse(url))
parsed[2] = re.sub("/{2,}", "/", parsed[2]) # replace two or more / with one parsed[2] = re.sub("/{2,}", "/", parsed[2]) # replace two or more / with one
url = urlparse.urlunparse(parsed) url = urlparse.urlunparse(parsed)
r = requests.get(url, verify=False) r = self.session.get(url, verify=False)
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e: except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
logger.log(u"Error loading " + self.name + " URL: " + str(sys.exc_info()) + " - " + ex(e), logger.ERROR) logger.log(u"Error loading " + self.name + " URL: " + str(sys.exc_info()) + " - " + ex(e), logger.ERROR)
return None return None
@ -229,6 +224,9 @@ class PublicHDProvider(generic.TorrentProvider):
Save the result to disk. Save the result to disk.
""" """
if not self.session:
self.session = requests.Session()
torrent_hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0].upper() torrent_hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0].upper()
if not torrent_hash: if not torrent_hash:
@ -236,7 +234,7 @@ class PublicHDProvider(generic.TorrentProvider):
return False return False
try: try:
r = requests.get('http://torcache.net/torrent/' + torrent_hash + '.torrent', verify=False) r = self.session.get('http://torcache.net/torrent/' + torrent_hash + '.torrent', verify=False)
except Exception, e: except Exception, e:
logger.log("Unable to connect to Torcache: " + ex(e), logger.ERROR) logger.log("Unable to connect to Torcache: " + ex(e), logger.ERROR)
return False return False

View file

@ -42,6 +42,7 @@ class TorrentRssProvider(generic.TorrentProvider):
self.url = re.sub('\/$', '', url) self.url = re.sub('\/$', '', url)
self.enabled = True self.enabled = True
self.supportsBacklog = False self.supportsBacklog = False
self.session = requests.Session()
def configStr(self): def configStr(self):
return self.name + '|' + self.url + '|' + str(int(self.enabled)) return self.name + '|' + self.url + '|' + str(int(self.enabled))
@ -114,20 +115,24 @@ class TorrentRssProvider(generic.TorrentProvider):
return (False, 'Error when trying to load RSS: ' + ex(e)) return (False, 'Error when trying to load RSS: ' + ex(e))
def getURL(self, url, post_data=None, headers=None): def getURL(self, url, post_data=None, headers=None):
if not self.session:
self.session = requests.Session()
try: try:
parsed = list(urlparse.urlparse(url)) parsed = list(urlparse.urlparse(url))
parsed[2] = re.sub("/{2,}", "/", parsed[2]) # replace two or more / with one parsed[2] = re.sub("/{2,}", "/", parsed[2]) # replace two or more / with one
response = requests.get(url, verify=False) r = self.session.get(url, verify=False)
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e: except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
logger.log(u"Error loading " + self.name + " URL: " + ex(e), logger.ERROR) logger.log(u"Error loading " + self.name + " URL: " + ex(e), logger.ERROR)
return None return None
if response.status_code != 200: if r.status_code != 200:
logger.log(self.name + u" page requested with url " + url + " returned status code is " + str( logger.log(self.name + u" page requested with url " + url + " returned status code is " + str(
response.status_code) + ': ' + clients.http_error_code[response.status_code], logger.WARNING) r.status_code) + ': ' + clients.http_error_code[r.status_code], logger.WARNING)
return None return None
return response.content return r.content
def dumpHTML(self, data): def dumpHTML(self, data):

View file

@ -100,46 +100,38 @@ class SCCProvider(generic.TorrentProvider):
return True return True
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []}
if not show: if not show:
return [] return []
self.show = show search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
if searchSeason: search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
for ep_obj in wantedEp:
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
if not search_string['Episode']:
return []
return [search_string] return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''): def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if not episode:
return [] return []
if ep_obj.show.air_by_date: if abd:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \ str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate) helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(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.scene_season, sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} 'episodenumber': episode}
search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) search_string['Episode'].append(re.sub('\s+', ' ', ep_string))

View file

@ -18,9 +18,10 @@
import re import re
import datetime import datetime
import urlparse
import sickbeard import sickbeard
import generic import generic
from sickbeard.common import Quality from sickbeard.common import Quality
from sickbeard import logger from sickbeard import logger
from sickbeard import tvcache from sickbeard import tvcache
@ -32,7 +33,7 @@ from sickbeard.common import Overview
from sickbeard.exceptions import ex from sickbeard.exceptions import ex
from sickbeard import clients from sickbeard import clients
from lib import requests from lib import requests
from lib.requests import exceptions
class SpeedCDProvider(generic.TorrentProvider): class SpeedCDProvider(generic.TorrentProvider):
@ -55,7 +56,9 @@ class SpeedCDProvider(generic.TorrentProvider):
self.categories = {'Season': {'c14':1}, 'Episode': {'c2':1, 'c49':1}, 'RSS': {'c14':1, 'c2':1, 'c49':1}} self.categories = {'Season': {'c14':1}, 'Episode': {'c2':1, 'c49':1}, 'RSS': {'c14':1, 'c2':1, 'c49':1}}
self.session = None self.session = requests.Session()
self.headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36'}
def isEnabled(self): def isEnabled(self):
return sickbeard.SPEEDCD return sickbeard.SPEEDCD
@ -75,10 +78,10 @@ class SpeedCDProvider(generic.TorrentProvider):
} }
self.session = requests.Session() self.session = requests.Session()
self.session.headers.update({'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20130519 Firefox/24.0)'}) self.session.headers.update(self.headers)
try: try:
response = self.session.post(self.urls['login'], data=login_params, timeout=30) response = self.session.post(self.urls['login'], data=login_params, timeout=30, verify=False)
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e: except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
logger.log(u'Unable to connect to ' + self.name + ' provider: ' + ex(e), logger.ERROR) logger.log(u'Unable to connect to ' + self.name + ' provider: ' + ex(e), logger.ERROR)
return False return False
@ -90,55 +93,43 @@ class SpeedCDProvider(generic.TorrentProvider):
return True return True
def _get_season_search_strings(self, show, season=None): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []}
if not show: if not show:
return [] return []
seasonEp = show.getAllEpisodes(season)
wantedEp = [x for x in seasonEp if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)]
#If Every episode in Season is a wanted Episode then search for Season first #If Every episode in Season is a wanted Episode then search for Season first
if wantedEp == seasonEp and not show.air_by_date: search_string = {'Season': [], 'Episode': []}
search_string = {'Season': [], 'Episode': []} for show_name in set(show_name_helpers.allPossibleShowNames(show)):
for show_name in set(show_name_helpers.allPossibleShowNames(show)): ep_string = show_name +' S%02d' % int(season) #1) ShowName SXX
ep_string = show_name +' S%02d' % int(season) #1) ShowName SXX search_string['Season'].append(ep_string)
search_string['Season'].append(ep_string)
#Building the search string with the episodes we need #Building the search string with the episodes we need
for ep_obj in wantedEp: search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
#If no Episode is needed then return an empty list
if not search_string['Episode']:
return []
return [search_string] return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''): def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if not episode:
return [] return []
if ep_obj.show.air_by_date: if abd:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) +' '+ str(ep_obj.airdate) ep_string = show_name_helpers.sanitizeSceneName(show_name) +' '+ str(episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(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, 'episodenumber': ep_obj.episode} sickbeard.config.naming_ep_type[2] % {'seasonnumber': season, 'episodenumber': episode}
search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
return [search_string] return [search_string]
def _doSearch(self, search_params, show=None): def _doSearch(self, search_params, show=None, age=None):
results = [] results = []
items = {'Season': [], 'Episode': [], 'RSS': []} items = {'Season': [], 'Episode': [], 'RSS': []}
@ -197,25 +188,34 @@ class SpeedCDProvider(generic.TorrentProvider):
return (title, url) return (title, url)
def getURL(self, url, headers=None): def getURL(self, url, post_data=None, headers=None):
if not self.session: if not self.session:
self._doLogin() self._doLogin()
if not headers:
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36'}
try: try:
response = self.session.get(url, headers=headers) # Remove double-slashes from url
parsed = list(urlparse.urlparse(url))
parsed[2] = re.sub("/{2,}", "/", parsed[2]) # replace two or more / with one
url = urlparse.urlunparse(parsed)
if sickbeard.PROXY_SETTING:
proxies = {
"http": sickbeard.PROXY_SETTING,
"https": sickbeard.PROXY_SETTING,
}
r = self.session.get(url, proxies=proxies, verify=False)
else:
r = self.session.get(url, verify=False)
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e: except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
logger.log(u"Error loading "+self.name+" URL: " + ex(e), logger.ERROR) logger.log(u"Error loading "+self.name+" URL: " + ex(e), logger.ERROR)
return None return None
if response.status_code != 200: if r.status_code != 200:
logger.log(self.name + u" page requested with url " + url +" returned status code is " + str(response.status_code) + ': ' + clients.http_error_code[response.status_code], logger.WARNING) logger.log(self.name + u" page requested with url " + url +" returned status code is " + str(r.status_code) + ': ' + clients.http_error_code[r.status_code], logger.WARNING)
return None return None
return response.content return r.content
def findPropers(self, search_date=datetime.datetime.today()): def findPropers(self, search_date=datetime.datetime.today()):

View file

@ -72,6 +72,8 @@ class ThePirateBayProvider(generic.TorrentProvider):
self.re_title_url = '/torrent/(?P<id>\d+)/(?P<title>.*?)//1".+?(?P<url>magnet.*?)//1".+?(?P<seeders>\d+)</td>.+?(?P<leechers>\d+)</td>' self.re_title_url = '/torrent/(?P<id>\d+)/(?P<title>.*?)//1".+?(?P<url>magnet.*?)//1".+?(?P<seeders>\d+)</td>.+?(?P<leechers>\d+)</td>'
self.session = requests.Session()
def isEnabled(self): def isEnabled(self):
return sickbeard.THEPIRATEBAY return sickbeard.THEPIRATEBAY
@ -170,56 +172,45 @@ class ThePirateBayProvider(generic.TorrentProvider):
return title return title
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []}
if not show: if not show:
return [] return []
self.show = show search_string = {'Season': [], 'Episode': []}
for show_name in set(allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
if searchSeason: ep_string = show_name + ' Season ' + str(season) + ' -Ep*' #2) ShowName Season X
search_string = {'Season': [], 'Episode': []} search_string['Season'].append(ep_string)
for show_name in set(allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
ep_string = show_name + ' Season ' + str(season) + ' -Ep*' #2) ShowName Season X search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string['Season'].append(ep_string)
for ep_obj in wantedEp:
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
if not search_string['Episode']:
return []
return [search_string] return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''): def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if not episode:
return [] return []
self.show = ep_obj.show if abd:
for show_name in set(allPossibleShowNames(show)):
if ep_obj.show.air_by_date:
for show_name in set(allPossibleShowNames(ep_obj.show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \ ep_string = sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \ str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate) helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(allPossibleShowNames(ep_obj.show)): for show_name in set(allPossibleShowNames(show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \ ep_string = sanitizeSceneName(show_name) + ' ' + \
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} + '|' + \ 'episodenumber': episode} + '|' + \
sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season, sickbeard.config.naming_ep_type[0] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} + '|' + \ 'episodenumber': episode} + '|' + \
sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.scene_season, sickbeard.config.naming_ep_type[3] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} 'episodenumber': episode}
ep_string += ' %s' % add_string ep_string += ' %s' % add_string
@ -302,6 +293,9 @@ class ThePirateBayProvider(generic.TorrentProvider):
if not headers: if not headers:
headers = {} headers = {}
if not self.session:
self.session = requests.Session()
# Glype Proxies does not support Direct Linking. # Glype Proxies does not support Direct Linking.
# We have to fake a search on the proxy site to get data # We have to fake a search on the proxy site to get data
if self.proxy.isEnabled(): if self.proxy.isEnabled():
@ -314,9 +308,9 @@ class ThePirateBayProvider(generic.TorrentProvider):
"https": sickbeard.PROXY_SETTING, "https": sickbeard.PROXY_SETTING,
} }
r = requests.get(url, headers=headers, proxies=proxies, verify=False) r = self.session.get(url, headers=headers, proxies=proxies, verify=False)
else: else:
r = requests.get(url, headers=headers, verify=False) r = self.session.get(url, headers=headers, verify=False)
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e: except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
logger.log(u"Error loading " + self.name + " URL: " + str(sys.exc_info()) + " - " + ex(e), logger.ERROR) logger.log(u"Error loading " + self.name + " URL: " + str(sys.exc_info()) + " - " + ex(e), logger.ERROR)
return None return None
@ -332,6 +326,8 @@ class ThePirateBayProvider(generic.TorrentProvider):
""" """
Save the result to disk. Save the result to disk.
""" """
if not self.session:
self.session = requests.Session()
torrent_hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0].upper() torrent_hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0].upper()
@ -340,7 +336,7 @@ class ThePirateBayProvider(generic.TorrentProvider):
return False return False
try: try:
r = requests.get('http://torcache.net/torrent/' + torrent_hash + '.torrent', verify=False) r = self.session.get('http://torcache.net/torrent/' + torrent_hash + '.torrent', verify=False)
except Exception, e: except Exception, e:
logger.log("Unable to connect to Torcache: " + ex(e), logger.ERROR) logger.log("Unable to connect to Torcache: " + ex(e), logger.ERROR)
return False return False

View file

@ -113,47 +113,38 @@ class TorrentDayProvider(generic.TorrentProvider):
return True return True
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []}
if not show: if not show:
return [] return []
self.show = show search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
if searchSeason: search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
for ep_obj in wantedEp:
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
if not search_string['Episode']:
return []
return [search_string] return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''): def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if not episode:
return [] return []
if ep_obj.show.air_by_date: if abd:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \ str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate) helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(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.scene_season, sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} 'episodenumber': episode}
search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) search_string['Episode'].append(re.sub('\s+', ' ', ep_string))

View file

@ -95,46 +95,38 @@ class TorrentLeechProvider(generic.TorrentProvider):
return True return True
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False): def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Episode': []}
if not show: if not show:
return [] return []
self.show = show search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
if searchSeason: search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
search_string = {'Season': [], 'Episode': []}
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name + ' S%02d' % int(season) #1) ShowName SXX
search_string['Season'].append(ep_string)
for ep_obj in wantedEp:
search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
if not search_string['Episode']:
return []
return [search_string] return [search_string]
def _get_episode_search_strings(self, ep_obj, add_string=''): def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []} search_string = {'Episode': []}
if not ep_obj: if not episode:
return [] return []
if ep_obj.show.air_by_date: if abd:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \ str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate) helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string) search_string['Episode'].append(ep_string)
else: else:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)): for show_name in set(show_name_helpers.allPossibleShowNames(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.scene_season, sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': ep_obj.scene_episode} 'episodenumber': episode}
search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) search_string['Episode'].append(re.sub('\s+', ' ', ep_string))

View file

@ -56,7 +56,7 @@ class TvTorrentsProvider(generic.TorrentProvider):
def _checkAuthFromData(self, data): def _checkAuthFromData(self, data):
if data is None: if data is None or data.feed is None:
return self._checkAuth() return self._checkAuth()
description_text = data.feed.title description_text = data.feed.title
@ -84,7 +84,7 @@ class TvTorrentsCache(tvcache.TVCache):
rss_url = self.provider.url + 'RssServlet?digest=' + sickbeard.TVTORRENTS_DIGEST + '&hash=' + sickbeard.TVTORRENTS_HASH + '&fname=true&exclude=(' + ignore_regex + ')' rss_url = self.provider.url + 'RssServlet?digest=' + sickbeard.TVTORRENTS_DIGEST + '&hash=' + sickbeard.TVTORRENTS_HASH + '&fname=true&exclude=(' + ignore_regex + ')'
logger.log(self.provider.name + u" cache update URL: " + rss_url, logger.DEBUG) logger.log(self.provider.name + u" cache update URL: " + rss_url, logger.DEBUG)
data = self.provider.getURL(rss_url) data = self.provider.getRSSFeed(rss_url)
if not data: if not data:
logger.log(u"No data returned from " + rss_url, logger.ERROR) logger.log(u"No data returned from " + rss_url, logger.ERROR)

View file

@ -25,7 +25,7 @@ import datetime
import sickbeard import sickbeard
from common import SNATCHED, SNATCHED_PROPER, SNATCHED_BEST, Quality, SEASON_RESULT, MULTI_EP_RESULT from common import SNATCHED, SNATCHED_PROPER, SNATCHED_BEST, Quality, SEASON_RESULT, MULTI_EP_RESULT, Overview
from sickbeard import logger, db, show_name_helpers, exceptions, helpers from sickbeard import logger, db, show_name_helpers, exceptions, helpers
from sickbeard import sab from sickbeard import sab
@ -349,67 +349,23 @@ def isFirstBestMatch(result):
return False return False
def searchProviders(show, season, episode=None, manualSearch=False):
def findEpisode(episode, manualSearch=False):
logger.log(u"Searching for " + episode.prettyName())
foundResults = []
didSearch = False
for curProvider in providers.sortedProviderList():
if not curProvider.isActive():
continue
try:
curFoundResults = curProvider.findEpisode(episode, manualSearch=manualSearch)
except exceptions.AuthException, e:
logger.log(u"Authentication error: " + ex(e), logger.ERROR)
continue
except Exception, e:
logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
logger.log(traceback.format_exc(), logger.DEBUG)
continue
didSearch = True
# skip non-tv crap
curFoundResults = filter(
lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name,
episode.show),
curFoundResults)
# loop all results and see if any of them are good enough that we can stop searching
done_searching = False
for cur_result in curFoundResults:
done_searching = isFinalResult(cur_result)
logger.log(u"Should we stop searching after finding " + cur_result.name + ": " + str(done_searching),
logger.DEBUG)
if done_searching:
break
foundResults += curFoundResults
# if we did find a result that's good enough to stop then don't continue
if done_searching:
break
if not didSearch:
logger.log(u"No NZB/Torrent providers found or enabled in the sickbeard config. Please check your settings.",
logger.ERROR)
bestResult = pickBestResult(foundResults, episode.show)
return bestResult
def findSeason(show, season):
logger.log(u"Searching for stuff we need from " + show.name + " season " + str(season)) logger.log(u"Searching for stuff we need from " + show.name + " season " + str(season))
foundResults = {} foundResults = {}
didSearch = False didSearch = False
seasonSearch = False
# gather all episodes for season and then pick out the wanted episodes and compare to determin if we want whole season or just a few episodes
if episode is None:
seasonEps = show.getAllEpisodes(season)
wantedEps = [x for x in seasonEps if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)]
if len(seasonEps) == len(wantedEps):
seasonSearch = True
else:
ep_obj = show.getEpisode(season, episode)
wantedEps = [ep_obj]
for curProvider in providers.sortedProviderList(): for curProvider in providers.sortedProviderList():
@ -417,7 +373,7 @@ def findSeason(show, season):
continue continue
try: try:
curResults = curProvider.findSeasonResults(show, season) curResults = curProvider.getSearchResults(show, season, wantedEps, seasonSearch, manualSearch)
# make a list of all the results for this provider # make a list of all the results for this provider
for curEp in curResults: for curEp in curResults:

View file

@ -93,28 +93,29 @@ class ManualSearchQueueItem(generic_queue.QueueItem):
logger.log("Beginning manual search for " + self.ep_obj.prettyName()) logger.log("Beginning manual search for " + self.ep_obj.prettyName())
foundEpisode = search.findEpisode(self.ep_obj, manualSearch=True) foundResults = search.searchProviders(self.ep_obj.show, self.ep_obj.season, self.ep_obj.episode, manualSearch=True)
result = False result = False
if not foundEpisode: if not foundResults:
ui.notifications.message('No downloads were found', ui.notifications.message('No downloads were found',
"Couldn't find a download for <i>%s</i>" % self.ep_obj.prettyName()) "Couldn't find a download for <i>%s</i>" % self.ep_obj.prettyName())
logger.log(u"Unable to find a download for " + self.ep_obj.prettyName()) logger.log(u"Unable to find a download for " + self.ep_obj.prettyName())
self.success = result
else: else:
for foundResult in foundResults:
# just use the first result for now
logger.log(u"Downloading " + foundResult.name + " from " + foundResult.provider.name)
# just use the first result for now result = search.snatchEpisode(foundResult)
logger.log(u"Downloading episode from " + foundEpisode.url)
result = search.snatchEpisode(foundEpisode) providerModule = foundResult.provider
if not result:
ui.notifications.error('Error while attempting to snatch ' + foundResult.name + ', check your logs')
elif providerModule == None:
ui.notifications.error('Provider is configured incorrectly, unable to download')
providerModule = foundEpisode.provider self.success = result
if not result:
ui.notifications.error('Error while attempting to snatch ' + foundEpisode.name + ', check your logs')
elif providerModule == None:
ui.notifications.error('Provider is configured incorrectly, unable to download')
self.success = result
def finish(self): def finish(self):
# don't let this linger if something goes wrong # don't let this linger if something goes wrong
@ -195,14 +196,14 @@ class BacklogQueueItem(generic_queue.QueueItem):
statusResults = myDB.select("SELECT status FROM tv_episodes WHERE showid = ? AND season = ?", statusResults = myDB.select("SELECT status FROM tv_episodes WHERE showid = ? AND season = ?",
[self.show.indexerid, self.segment]) [self.show.indexerid, self.segment])
else: else:
segment_year, segment_month = map(int, self.segment.split('-')) season_year, season_month = map(int, self.segment.split('-'))
min_date = datetime.date(segment_year, segment_month, 1) min_date = datetime.date(season_year, season_month, 1)
# it's easier to just hard code this than to worry about rolling the year over or making a month length map # it's easier to just hard code this than to worry about rolling the year over or making a month length map
if segment_month == 12: if season_month == 12:
max_date = datetime.date(segment_year, 12, 31) max_date = datetime.date(season_year, 12, 31)
else: else:
max_date = datetime.date(segment_year, segment_month + 1, 1) - datetime.timedelta(days=1) max_date = datetime.date(season_year, season_month + 1, 1) - datetime.timedelta(days=1)
statusResults = myDB.select( statusResults = myDB.select(
"SELECT status FROM tv_episodes WHERE showid = ? AND airdate >= ? AND airdate <= ?", "SELECT status FROM tv_episodes WHERE showid = ? AND airdate >= ? AND airdate <= ?",
@ -215,7 +216,7 @@ class BacklogQueueItem(generic_queue.QueueItem):
generic_queue.QueueItem.execute(self) generic_queue.QueueItem.execute(self)
results = search.findSeason(self.show, self.segment) results = search.searchProviders(self.show, self.segment)
# download whatever we find # download whatever we find
for curResult in results: for curResult in results:
@ -273,13 +274,8 @@ class FailedQueueItem(generic_queue.QueueItem):
failed_history.revertEpisode(self.show, season, episode) failed_history.revertEpisode(self.show, season, episode)
for season, episode in self.segment.iteritems(): # get search results
epObj = self.show.getEpisode(season, episode) results = search.searchProviders(self.show, season, episode)
if self.show.air_by_date:
results = search.findSeason(self.show, str(epObj.airdate)[:7])
else:
results = search.findSeason(self.show, season)
# download whatever we find # download whatever we find
for curResult in results: for curResult in results:

View file

@ -119,14 +119,14 @@ def makeSceneShowSearchStrings(show):
return map(sanitizeSceneName, showNames) return map(sanitizeSceneName, showNames)
def makeSceneSeasonSearchString(show, segment, extraSearchType=None): def makeSceneSeasonSearchString(show, season, episode, abd=False, extraSearchType=None):
myDB = db.DBConnection() myDB = db.DBConnection()
if show.air_by_date: if show.air_by_date:
numseasons = 0 numseasons = 0
# the search string for air by date shows is just # the search string for air by date shows is just
seasonStrings = [segment] seasonStrings = [season]
else: else:
numseasonsSQlResult = myDB.select( numseasonsSQlResult = myDB.select(
@ -134,7 +134,7 @@ def makeSceneSeasonSearchString(show, segment, extraSearchType=None):
[show.indexerid]) [show.indexerid])
numseasons = int(numseasonsSQlResult[0][0]) numseasons = int(numseasonsSQlResult[0][0])
seasonStrings = ["S%02d" % int(segment)] seasonStrings = ["S%02d" % int(season)]
showNames = set(makeSceneShowSearchStrings(show)) showNames = set(makeSceneShowSearchStrings(show))
@ -152,33 +152,36 @@ def makeSceneSeasonSearchString(show, segment, extraSearchType=None):
for cur_season in seasonStrings: for cur_season in seasonStrings:
toReturn.append(curShow + "." + cur_season) toReturn.append(curShow + "." + cur_season)
# episode
toReturn.extend(makeSceneSearchString(show, season, episode, abd))
return toReturn return toReturn
def makeSceneSearchString(episode): def makeSceneSearchString(show, season, episode, abd=False):
myDB = db.DBConnection() myDB = db.DBConnection()
numseasonsSQlResult = myDB.select( numseasonsSQlResult = myDB.select(
"SELECT COUNT(DISTINCT season) as numseasons FROM tv_episodes WHERE showid = ? and season != 0", "SELECT COUNT(DISTINCT season) as numseasons FROM tv_episodes WHERE showid = ? and season != 0",
[episode.show.indexerid]) [show.indexerid])
numseasons = int(numseasonsSQlResult[0][0]) numseasons = int(numseasonsSQlResult[0][0])
numepisodesSQlResult = myDB.select( numepisodesSQlResult = myDB.select(
"SELECT COUNT(episode) as numepisodes FROM tv_episodes WHERE showid = ? and season != 0", "SELECT COUNT(episode) as numepisodes FROM tv_episodes WHERE showid = ? and season != 0",
[episode.show.indexerid]) [show.indexerid])
numepisodes = int(numepisodesSQlResult[0][0]) numepisodes = int(numepisodesSQlResult[0][0])
# see if we should use dates instead of episodes # see if we should use dates instead of episodes
if episode.show.air_by_date and episode.airdate != datetime.date.fromordinal(1): if abd and episode != datetime.date.fromordinal(1):
epStrings = [str(episode.airdate)] epStrings = [str(episode.airdate)]
else: else:
epStrings = ["S%02iE%02i" % (int(episode.scene_season), int(episode.scene_episode)), epStrings = ["S%02iE%02i" % (int(season), int(episode)),
"%ix%02i" % (int(episode.scene_season), int(episode.scene_episode))] "%ix%02i" % (int(season), int(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
if numseasons == 1 and numepisodes < 11: if numseasons == 1 and numepisodes < 11:
epStrings = [''] epStrings = ['']
showNames = set(makeSceneShowSearchStrings(episode.show)) showNames = set(makeSceneShowSearchStrings(show))
toReturn = [] toReturn = []

View file

@ -23,7 +23,9 @@ import datetime
import threading import threading
import re import re
import glob import glob
from time import sleep
import traceback import traceback
import shutil
import sickbeard import sickbeard
@ -241,6 +243,7 @@ class TVShow(object):
last_update_indexer = datetime.date.fromordinal(self.last_update_indexer) last_update_indexer = datetime.date.fromordinal(self.last_update_indexer)
# in the first year after ended (last airdate), update every 30 days
# in the first year after ended (last airdate), update every 30 days # in the first year after ended (last airdate), update every 30 days
if (update_date - last_airdate) < datetime.timedelta(days=450) and ( if (update_date - last_airdate) < datetime.timedelta(days=450) and (
update_date - last_update_indexer) > datetime.timedelta(days=30): update_date - last_update_indexer) > datetime.timedelta(days=30):
@ -307,8 +310,49 @@ class TVShow(object):
# create TVEpisodes from each media file (if possible) # create TVEpisodes from each media file (if possible)
for mediaFile in mediaFiles: for mediaFile in mediaFiles:
sceneConvert = False
parse_result = None
curEpisode = None curEpisode = None
i = 0
try:
while i < 2:
i+=1
np = NameParser(False)
parse_result = np.parse(mediaFile, sceneConvert)
if helpers.validateShow(self, parse_result.season_number, parse_result.episode_numbers[0]):
ep = TVEpisode(self, parse_result.season_number, parse_result.episode_numbers[0])
proper_path = ep.proper_path()
proper_absolute_path = ek.ek(os.path.join, self._location, proper_path)
src_path = ek.ek(os.path.dirname, mediaFile)
dest_path = ek.ek(os.path.dirname, proper_absolute_path)
orig_extension = mediaFile.rpartition('.')[-1]
new_base_name = ek.ek(os.path.basename, proper_path)
new_file_name = new_base_name + '.' + orig_extension
old_file_name = ek.ek(os.path.basename, mediaFile)
new_mediaFile = os.path.join(dest_path, new_file_name)
if old_file_name == new_file_name or os.path.exists(new_mediaFile):break
if os.path.exists(os.path.join(src_path, old_file_name)):
old_mediaFile = os.path.join(src_path, old_file_name)
elif os.path.exists(os.path.join(dest_path, old_file_name)):
old_mediaFile = os.path.join(dest_path, old_file_name)
else:break
logger.log(u"Scene Converting file %s to %s" % (old_file_name, new_file_name), logger.MESSAGE)
if not os.path.exists(dest_path):
shutil.move(src_path, dest_path)
shutil.move(old_mediaFile, new_mediaFile)
mediaFile = new_mediaFile
# converted
break
sceneConvert = True
except Exception:
continue
logger.log(str(self.indexerid) + u": Creating episode from " + mediaFile, logger.DEBUG) logger.log(str(self.indexerid) + u": Creating episode from " + mediaFile, logger.DEBUG)
try: try:
@ -326,7 +370,6 @@ class TVShow(object):
ep_file_name = ek.ek(os.path.basename, curEpisode.location) ep_file_name = ek.ek(os.path.basename, curEpisode.location)
ep_file_name = ek.ek(os.path.splitext, ep_file_name)[0] ep_file_name = ek.ek(os.path.splitext, ep_file_name)[0]
parse_result = None
try: try:
np = NameParser(False) np = NameParser(False)
parse_result = np.parse(ep_file_name) parse_result = np.parse(ep_file_name)
@ -2087,8 +2130,7 @@ class TVEpisode(object):
self.location) self.location)
if self.show.subtitles and sickbeard.SUBTITLES_DIR != '': if self.show.subtitles and sickbeard.SUBTITLES_DIR != '':
related_subs = postProcessor.PostProcessor(self.location).list_associated_files( related_subs = postProcessor.PostProcessor(self.location).list_associated_files(sickbeard.SUBTITLES_DIR, subtitles_only=True)
sickbeard.SUBTITLES_DIR, subtitles_only=True)
absolute_proper_subs_path = ek.ek(os.path.join, sickbeard.SUBTITLES_DIR, self.formatted_filename()) absolute_proper_subs_path = ek.ek(os.path.join, sickbeard.SUBTITLES_DIR, self.formatted_filename())
logger.log(u"Files associated to " + self.location + ": " + str(related_files), logger.DEBUG) logger.log(u"Files associated to " + self.location + ": " + str(related_files), logger.DEBUG)
@ -2104,8 +2146,7 @@ class TVEpisode(object):
logger.log(str(self.indexerid) + u": Unable to rename file " + cur_related_file, logger.ERROR) logger.log(str(self.indexerid) + u": Unable to rename file " + cur_related_file, logger.ERROR)
for cur_related_sub in related_subs: for cur_related_sub in related_subs:
cur_result = helpers.rename_ep_file(cur_related_sub, absolute_proper_subs_path, cur_result = helpers.rename_ep_file(cur_related_sub, absolute_proper_subs_path,absolute_current_path_no_ext_length)
absolute_current_path_no_ext_length)
if cur_result == False: if cur_result == False:
logger.log(str(self.indexerid) + u": Unable to rename file " + cur_related_sub, logger.ERROR) logger.log(str(self.indexerid) + u": Unable to rename file " + cur_related_sub, logger.ERROR)

View file

@ -1397,6 +1397,7 @@ class ConfigProviders:
hdbits_username=None, hdbits_passkey=None, hdbits_username=None, hdbits_passkey=None,
nextgen_username=None, nextgen_password=None, nextgen_username=None, nextgen_password=None,
newzbin_username=None, newzbin_password=None, newzbin_username=None, newzbin_password=None,
speedcd_username=None, speedcd_password=None, speedcd_freeleech=None,
provider_order=None): provider_order=None):
results = [] results = []

View file

@ -74,13 +74,14 @@ def test_generator(tvdbdid, show_name, curData, forceSearch):
show.quality = curData["q"] show.quality = curData["q"]
show.saveToDB() show.saveToDB()
sickbeard.showList.append(show) sickbeard.showList.append(show)
episode = None
for epNumber in curData["e"]: for epNumber in curData["e"]:
episode = TVEpisode(show, curData["s"], epNumber) episode = TVEpisode(show, curData["s"], epNumber)
episode.status = c.WANTED episode.status = c.WANTED
episode.saveToDB() episode.saveToDB()
bestResult = search.findEpisode(episode, forceSearch) bestResult = search.searchProviders(show, episode.season, episode.episode, forceSearch)
if not bestResult: if not bestResult:
self.assertEqual(curData["b"], bestResult) self.assertEqual(curData["b"], bestResult)
self.assertEqual(curData["b"], bestResult.name) #first is expected, second is choosen one self.assertEqual(curData["b"], bestResult.name) #first is expected, second is choosen one

View file

@ -179,7 +179,7 @@ def tearDown_test_db():
although this seams not to work on my system it leaves me with an zero kb file although this seams not to work on my system it leaves me with an zero kb file
""" """
# uncomment next line so leave the db intact between test and at the end # uncomment next line so leave the db intact between test and at the end
#return False return False
if os.path.exists(os.path.join(TESTDIR, TESTDBNAME)): if os.path.exists(os.path.join(TESTDIR, TESTDBNAME)):
os.remove(os.path.join(TESTDIR, TESTDBNAME)) os.remove(os.path.join(TESTDIR, TESTDBNAME))
if os.path.exists(os.path.join(TESTDIR, TESTCACHEDBNAME)): if os.path.exists(os.path.join(TESTDIR, TESTCACHEDBNAME)):

View file

@ -27,7 +27,9 @@ sys.path.append(os.path.abspath('../lib'))
import test_lib as test import test_lib as test
import sickbeard import sickbeard
from sickbeard.tv import TVShow, TVEpisode from sickbeard.helpers import sanitizeSceneName
from sickbeard.show_name_helpers import allPossibleShowNames
from sickbeard.tv import TVShow
class XEMBasicTests(test.SickbeardTestDBCase): class XEMBasicTests(test.SickbeardTestDBCase):
def loadFromDB(self): def loadFromDB(self):
@ -50,9 +52,29 @@ class XEMBasicTests(test.SickbeardTestDBCase):
show = sickbeard.helpers.findCertainShow(sickbeard.showList, 111051) show = sickbeard.helpers.findCertainShow(sickbeard.showList, 111051)
ep = show.getEpisode(2014, 34) ep = show.getEpisode(2014, 34)
scene_ep_string = sanitizeSceneName(show.name) + ' ' + \
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep.scene_season,
'episodenumber': ep.scene_episode} + '|' + \
sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep.scene_season,
'episodenumber': ep.scene_episode} + '|' + \
sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep.scene_season,
'episodenumber': ep.scene_episode} + ' %s category:tv' % ''
scene_season_string = show.name + ' S%02d' % int(ep.scene_season) + ' -S%02d' % int(ep.scene_season) + 'E' + ' category:tv' #1) ShowName SXX -SXXE
print( print(
u'Searching "%s" for "%s" as "%s"' % (show.name, ep.prettyName(), ep.scene_prettyName())) u'Searching "%s" for "%s" as "%s"' % (show.name, ep.prettyName(), ep.scene_prettyName()))
print('Scene episode search strings: %s' % (scene_ep_string))
print('Scene season search strings: %s' % (scene_season_string))
def test_renaming(self):
self.file_name = 'American Pickers - S04E01 - Jurassic Pick.avi'
orig_extension = self.file_name.rpartition('.')[-1]
new_base_name = os.path.basename(proper_path)
new_file_name = new_base_name + '.' + orig_extension
if __name__ == "__main__": if __name__ == "__main__":
print "==================" print "=================="
print "STARTING - XEM Scene Numbering TESTS" print "STARTING - XEM Scene Numbering TESTS"