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_HASH = None
TORRENTLEECH = False
TORRENTLEECH_KEY = None
BTN = False
BTN_API_KEY = None
@ -193,6 +190,7 @@ THEPIRATEBAY_PROXY_URL = None
THEPIRATEBAY_BLACKLIST = None
TORRENTLEECH = False
TORRENTLEECH_KEY = None
TORRENTLEECH_USERNAME = None
TORRENTLEECH_PASSWORD = None
@ -232,6 +230,11 @@ HDBITS = False
HDBITS_USERNAME = None
HDBITS_PASSKEY = None
SPEEDCD = False
SPEEDCD_USERNAME = None
SPEEDCD_PASSWORD = None
SPEEDCD_FREELEECH = None
ADD_SHOWS_WO_DIR = None
CREATE_MISSING_SHOW_DIRS = None
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",
"%(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_multi_ep_type = {0: ["-%(episodenumber)02d"] * len(naming_ep_type),

View file

@ -50,20 +50,18 @@ except ImportError:
from xml.dom.minidom import Node
import sickbeard
from sickbeard.exceptions import MultipleShowObjectsException, ex
from sickbeard import logger, classes
from sickbeard.common import USER_AGENT, mediaExtensions, subtitleExtensions, XML_NSMAP
from sickbeard import db
from sickbeard import encodingKludge as ek
from sickbeard import notifiers
from sickbeard import exceptions
from lib import subliminal
#from sickbeard.subtitles import EXTENSIONS
urllib._urlopener = classes.SickBeardURLopener()
session = requests.Session()
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.
"""
global session
if not session:
session = requests.Session()
req_headers = ['User-Agent', USER_AGENT, 'Accept-Encoding', 'gzip,deflate']
if headers:
for cur_header in headers:
@ -191,9 +193,9 @@ Returns a byte-string retrieved from the url provider.
"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:
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:
logger.log(u"HTTP error " + str(e.errno) + " while loading URL " + url, logger.WARNING)
return None
@ -207,9 +209,9 @@ Returns a byte-string retrieved from the url provider.
return None
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):
@ -220,8 +222,12 @@ def _remove_file_failed(file):
def download_file(url, filename):
global session
if not session:
session = requests.Session()
try:
r = requests.get(url, stream=True, verify=False)
r = session.get(url, stream=True, verify=False)
with open(filename, 'wb') as fp:
for chunk in r.iter_content(chunk_size=1024):
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)))
def _copy(self, obj, objectmap=None):
"""
<Purpose>
Create a deep copy of an object without using the python 'copy' module.
Using copy.deepcopy() doesn't work because builtins like id and hasattr
aren't available when this is called.
<Arguments>
self
obj
The object to make a deep copy of.
objectmap
A mapping between original objects and the corresponding copy. This is
used to handle circular references.
<Exceptions>
TypeError
If an object is encountered that we don't know how to make a copy of.
NamespaceViolationError
If an unexpected error occurs while copying. This isn't the greatest
solution, but in general the idea is we just need to abort the wrapped
function call.
<Side Effects>
A new reference is created to every non-simple type of object. That is,
everything except objects of type str, unicode, int, etc.
<Returns>
The deep copy of obj with circular/recursive references preserved.
"""
def validateShow(show, season=None, episode=None):
indexer_lang = show.lang
try:
# If this is a top-level call to _copy, create a new objectmap for use
# by recursive calls to _copy.
if objectmap is None:
objectmap = {}
# If this is a circular reference, use the copy we already made.
elif _saved_id(obj) in objectmap:
return objectmap[_saved_id(obj)]
lINDEXER_API_PARMS = sickbeard.indexerApi(show.indexer).api_params.copy()
# types.InstanceType is included because the user can provide an instance
# of a class of their own in the list of callback args to settimer.
if _is_in(type(obj), [str, unicode, int, long, float, complex, bool, frozenset,
types.NoneType, types.FunctionType, types.LambdaType,
types.MethodType, types.InstanceType]):
return obj
if indexer_lang and not indexer_lang == 'en':
lINDEXER_API_PARMS['language'] = indexer_lang
elif type(obj) is list:
temp_list = []
# Need to save this in the objectmap before recursing because lists
# might have circular references.
objectmap[_saved_id(obj)] = temp_list
t = sickbeard.indexerApi(show.indexer).indexer(**lINDEXER_API_PARMS)
if season is None and episode is None:
return t
for item in obj:
temp_list.append(self._copy(item, objectmap))
return temp_list
elif type(obj) is tuple:
temp_list = []
for item in obj:
temp_list.append(self._copy(item, objectmap))
# I'm not 100% confident on my reasoning here, so feel free to point
# out where I'm wrong: There's no way for a tuple to directly contain
# a circular reference to itself. Instead, it has to contain, for
# example, a dict which has the same tuple as a value. In that
# situation, we can avoid infinite recursion and properly maintain
# circular references in our copies by checking the objectmap right
# after we do the copy of each item in the tuple. The existence of the
# dictionary would keep the recursion from being infinite because those
# are properly handled. That just leaves making sure we end up with
# only one copy of the tuple. We do that here by checking to see if we
# just made a copy as a result of copying the items above. If so, we
# return the one that's already been made.
if _saved_id(obj) in objectmap:
return objectmap[_saved_id(obj)]
retval = tuple(temp_list)
objectmap[_saved_id(obj)] = retval
return retval
elif type(obj) is set:
temp_list = []
# We can't just store this list object in the objectmap because it isn't
# a set yet. If it's possible to have a set contain a reference to
# itself, this could result in infinite recursion. However, sets can
# only contain hashable items so I believe this can't happen.
for item in obj:
temp_list.append(self._copy(item, objectmap))
retval = set(temp_list)
objectmap[_saved_id(obj)] = retval
return retval
elif type(obj) is dict:
temp_dict = {}
# Need to save this in the objectmap before recursing because dicts
# might have circular references.
objectmap[_saved_id(obj)] = temp_dict
for key, value in obj.items():
temp_key = self._copy(key, objectmap)
temp_dict[temp_key] = self._copy(value, objectmap)
return temp_dict
# We don't copy certain objects. This is because copying an emulated file
# object, for example, will cause the destructor of the original one to
# be invoked, which will close the actual underlying file. As the object
# is wrapped and the client does not have access to it, it's safe to not
# wrap it.
elif isinstance(obj, (NamespaceObjectWrapper, emulfile.emulated_file,
emulcomm.emulated_socket, thread.LockType,
virtual_namespace.VirtualNamespace)):
return obj
else:
raise TypeError("_copy is not implemented for objects of type " + str(type(obj)))
except Exception, e:
self._handle_violation("_copy failed on " + str(obj) + " with message " + str(e))
return t[show.indexerid][season][episode]
except (sickbeard.indexer_episodenotfound, sickbeard.indexer_seasonnotfound):
pass

View file

@ -343,44 +343,17 @@ class GenericMetadata():
"""
all_eps = [ep_obj] + ep_obj.relatedEps
indexer_lang = ep_obj.show.lang
# 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)
# validate show
if not helpers.validateShow(ep_obj.show):
return None
# try all included episodes in case some have thumbs and others don't
for cur_ep in all_eps:
try:
myEp = indexer_show_obj[cur_ep.season][cur_ep.episode]
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?")
myEp = helpers.validateShow(cur_ep.show, cur_ep.season, cur_ep.episode)
if not myEp:
continue
thumb_url = getattr(myEp, 'filename', None)
if thumb_url is not None:
return thumb_url

View file

@ -193,7 +193,7 @@ class NameParser(object):
if cached:
if fix_scene_numbering:
cached_fixed = copy.deepcopy(cached)
cached_fixed = copy.copy(cached)
cached_fixed.fix_scene_numbering()
return cached_fixed
return cached
@ -248,7 +248,7 @@ class NameParser(object):
name_parser_cache.add(name, final_result)
if fix_scene_numbering:
result_fixed = copy.deepcopy(final_result)
result_fixed = copy.copy(final_result)
result_fixed.fix_scene_numbering()
return result_fixed

View file

@ -191,7 +191,7 @@ class BTNProvider(generic.TorrentProvider):
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:
return []
@ -210,47 +210,35 @@ class BTNProvider(generic.TorrentProvider):
# Search by name if we don't have tvdb or tvrage id
current_params['series'] = sanitizeSceneName(name)
if searchSeason:
whole_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
whole_season_params['category'] = 'Season'
whole_season_params['name'] = 'Season ' + str(season)
whole_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
whole_season_params['category'] = '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
partial_season_params['category'] = 'Episode'
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)
# Search for episodes in the season
search_params.append(self._get_episode_search_strings(show, season, episode, abd)[0])
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 [{}]
search_params = {'category': 'Episode'}
if ep_obj.show.indexer == 1:
search_params['tvdb'] = ep_obj.show.indexerid
elif ep_obj.show.indexer == 2:
search_params['tvrage'] = ep_obj.show.indexerid
if show.indexer == 1:
search_params['tvdb'] = show.indexerid
elif show.indexer == 2:
search_params['tvrage'] = show.indexerid
else:
search_params['series'] = sanitizeSceneName(ep_obj.show.name)
search_params['series'] = sanitizeSceneName(show.name)
if ep_obj.show.air_by_date:
date_str = str(ep_obj.airdate)
if abd:
date_str = str(episode)
# BTN uses dots in dates, we just search for the date since that
# combined with the series identifier should result in just one episode
@ -258,7 +246,7 @@ class BTNProvider(generic.TorrentProvider):
else:
# Do a general name search for the episode, formatted like SXXEYY
search_params['name'] = "S%02dE%02d" % (ep_obj.scene_season, ep_obj.scene_episode)
search_params['name'] = "S%02dE%02d" % (season, episode)
to_return = [search_params]
@ -266,11 +254,11 @@ class BTNProvider(generic.TorrentProvider):
if 'series' in search_params:
# 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:
# don't add duplicates
if cur_exception == ep_obj.show.name:
if cur_exception == show.name:
continue
# 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)
return quality
def findSeasonResults(self, show, season):
return generic.TorrentProvider.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)
def _dtt_show_id(self, show_name):
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 = []
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
@ -62,8 +61,8 @@ class DTTProvider(generic.TorrentProvider):
return search_string
def _get_episode_search_strings(self, episode):
return self._get_season_search_strings(episode.show, episode.scene_season)
def _get_episode_search_strings(self, show, season, episode, abd=False):
return self._get_season_search_strings(show, season, episode, abd)
def _doSearch(self, search_params, show=None, age=None):

View file

@ -57,7 +57,7 @@ class EZRSSProvider(generic.TorrentProvider):
return quality
def findSeasonResults(self, show, season):
def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
results = {}
@ -66,11 +66,11 @@ class EZRSSProvider(generic.TorrentProvider):
logger.WARNING)
return results
results = generic.TorrentProvider.findSeasonResults(self, show, season)
results = generic.TorrentProvider.getSearchResults(self, show, season, ep_objs, seasonSearch, manualSearch)
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 = {}
@ -81,22 +81,24 @@ class EZRSSProvider(generic.TorrentProvider):
params['season'] = season
params['episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['episode']
return [params]
def _get_episode_search_strings(self, ep_obj):
def _get_episode_search_strings(self, show, season, episode, abd=False):
params = {}
if not ep_obj:
if not episode:
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:
params['date'] = str(ep_obj.airdate)
if abd:
params['date'] = str(episode)
else:
params['season'] = ep_obj.scene_season
params['episode'] = ep_obj.scene_episode
params['season'] = season
params['episode'] = episode
return [params]

View file

@ -214,10 +214,10 @@ class GenericProvider:
def _doSearch(self, search_params, show=None, age=None):
return []
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False):
def _get_season_search_strings(self, show, season, episode, abd=False):
return []
def _get_episode_search_strings(self, ep_obj):
def _get_episode_search_strings(self, show, season, episode, abd=False):
return []
def _get_title_and_url(self, item):
@ -238,91 +238,38 @@ class GenericProvider:
return (title, url)
def findEpisode(self, episode, 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):
def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
itemList = []
results = {}
seasons = {}
searchSeason = False
self._checkAuth()
# convert wanted seasons and episodes to XEM scene numbering
seasonEp = show.getAllEpisodes(season)
wantedEp = [x for x in seasonEp if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)]
[seasons.setdefault(x.scene_season, []).append(x) for x in wantedEp]
for ep_obj in ep_objs:
logger.log(u'Searching "%s" for "%s" as "%s"'
% (self.name, ep_obj.prettyName(), ep_obj.scene_prettyName()))
if wantedEp == seasonEp:
searchSeason = True
self.cache.updateCache()
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():
for curString in self._get_season_search_strings(show, season, episodes, searchSeason):
itemList += self._doSearch(curString)
# 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
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:
@ -373,7 +320,7 @@ class GenericProvider:
# make sure we want the episode
wantEp = True
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
break
@ -411,7 +358,7 @@ class GenericProvider:
if epNum in results:
results[epNum].append(result)
else:
results[epNum] = [result]
results = {epNum:[result]}
return results

View file

@ -18,7 +18,7 @@ import generic
import sickbeard
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.name_parser.parser import NameParser, InvalidNameException
@ -66,72 +66,87 @@ class HDBitsProvider(generic.TorrentProvider):
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()
results = self.cache.searchCache(episode, manualSearch)
logger.log(u"Cache results: " + str(results), logger.DEBUG)
# 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)]
else:
wantedEps = [show.getEpisode(season, episode)]
# 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
for ep_obj in wantedEps:
season = ep_obj.scene_season
episode = ep_obj.scene_episode
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:
logger.log(u"No data returned from " + self.search_url, logger.ERROR)
return []
# 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
if self._checkAuthFromData(parsedJSON):
results = []
itemList += self.getURL(self.search_url, post_data=self._make_post_data_JSON(show=show, season=season, episode=episode), json=True)
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
try:
myParser = NameParser()
parse_result = myParser.parse(title)
except InvalidNameException:
logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING)
continue
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 = []
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)
for item in items:
(title, url) = self._get_title_and_url(item)
# 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
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):
logger.log(u"Ignoring result " + title + " because we don't want an episode that is " +
Quality.qualityStrings[quality], logger.DEBUG)
continue
quality = self.getQuality(item)
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])
result.url = url
result.name = title
result.quality = quality
logger.log(u"Found result " + title + " at " + url, logger.DEBUG)
results.append(result)
result = self.getResult([episode])
result.url = url
result.name = title
result.quality = quality
results.append(result)
return results
@ -153,8 +168,8 @@ class HDBitsProvider(generic.TorrentProvider):
if episode:
post_data['tvdb'] = {
'id': show.indexerid,
'season': episode.scene_season,
'episode': episode.scene_episode
'season': season,
'episode': episode
}
if season:

View file

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

View file

@ -92,46 +92,37 @@ class IPTorrentsProvider(generic.TorrentProvider):
return True
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False):
search_string = {'Episode': []}
def _get_season_search_strings(self, show, season, episode, abd=False):
if not show:
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 = {'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 []
search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
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': []}
if not ep_obj:
if not episode:
return []
if ep_obj.show.air_by_date:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
if abd:
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate)
str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string)
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) + ' ' + \
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
'episodenumber': ep_obj.scene_episode} + ' %s' % add_string
sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': episode} + ' %s' % add_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.session = requests.Session()
def isEnabled(self):
return sickbeard.KAT
@ -164,56 +166,40 @@ class KATProvider(generic.TorrentProvider):
logger.log(u"Failed parsing " + self.name + " Traceback: " + traceback.format_exc(), logger.ERROR)
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False):
search_string = {'Episode': []}
def _get_season_search_strings(self, show, season, episode, abd=False):
search_string = {'Season': [], 'Episode': []}
if not show:
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:
search_string = {'Season': [], 'Episode': []}
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['Season'].append(ep_string)
ep_string = show_name + ' Season ' + str(season) + ' -Ep*' + ' category:tv' #2) ShowName Season X
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=''):
search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
def _get_episode_search_strings(self, show, season, episode, abd=False, add_string=''):
search_string = {'Episode': []}
if not ep_obj:
return []
self.show = ep_obj.show
if ep_obj.show.air_by_date:
for show_name in set(allPossibleShowNames(ep_obj.show)):
if abd:
for show_name in set(allPossibleShowNames(show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate)
str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string)
else:
for show_name in set(allPossibleShowNames(ep_obj.show)):
for show_name in set(allPossibleShowNames(show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
'episodenumber': ep_obj.scene_episode} + '|' + \
sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season,
'episodenumber': ep_obj.scene_episode} + '|' + \
sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.scene_season,
'episodenumber': ep_obj.scene_episode} + ' %s category:tv' % add_string
sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': episode} + '|' + \
sickbeard.config.naming_ep_type[0] % {'seasonnumber': season,
'episodenumber': episode} + '|' + \
sickbeard.config.naming_ep_type[3] % {'seasonnumber': season,
'episodenumber': episode} + ' %s category:tv' % add_string
search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
return [search_string]
@ -308,21 +294,24 @@ class KATProvider(generic.TorrentProvider):
def getURL(self, url, post_data=None, headers=None):
if not self.session:
self.session = requests.Session()
try:
# 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 = requests.get(url, proxies=proxies, verify=False)
r = self.session.get(url, proxies=proxies, verify=False)
else:
r = requests.get(url, verify=False)
r = self.session.get(url, verify=False)
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
logger.log(u"Error loading " + self.name + " URL: " + str(sys.exc_info()) + " - " + ex(e), logger.ERROR)
return None
@ -339,6 +328,9 @@ class KATProvider(generic.TorrentProvider):
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()
if not torrent_hash:
@ -346,7 +338,7 @@ class KATProvider(generic.TorrentProvider):
return False
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:
logger.log("Unable to connect to Torcache: " + ex(e), logger.ERROR)
return False

View file

@ -251,32 +251,11 @@ class NewzbinProvider(generic.NZBProvider):
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))
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 _get_episode_search_strings(self, show, season, episode, abd=False):
return ['^' + x for x in show_name_helpers.makeSceneSearchString(show, season, episode, abd)]
def _doSearch(self, searchStr, show=None, age=None):

View file

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

View file

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

View file

@ -54,20 +54,17 @@ class NyaaProvider(generic.TorrentProvider):
quality = Quality.sceneQuality(title)
return quality
def findSeasonResults(self, show, season):
results = {}
results = generic.TorrentProvider.findSeasonResults(self, show, season)
def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
results = generic.TorrentProvider.getSearchResults(self, show, season, ep_objs, seasonSearch, manualSearch)
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.extend(show_name_helpers.makeSceneShowSearchStrings(show))
return names
def _get_episode_search_strings(self, ep_obj):
return self._get_season_search_strings(ep_obj.show, ep_obj.scene_season)
def _get_episode_search_strings(self, show, season, episode, abd=False):
return self._get_season_search_strings(show, season, episode, abd)
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)
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):
name_regex = '(.*?)\.?(\[.*]|\d+\.TPB)\.torrent$'
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)
data = self.provider.getURL(url)
data = self.provider.getRSSFeed(url)
return data

View file

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

View file

@ -85,11 +85,11 @@ class OmgwtfnzbsProvider(generic.NZBProvider):
return True
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False):
return [x for x in show_name_helpers.makeSceneSeasonSearchString(show, season)]
def _get_season_search_strings(self, show, season, episode, abd=False):
return [x for x in show_name_helpers.makeSceneSeasonSearchString(show, season, episode, abd)]
def _get_episode_search_strings(self, ep_obj):
return [x for x in show_name_helpers.makeSceneSearchString(ep_obj)]
def _get_episode_search_strings(self, show, season, episode, abd=False):
return [x for x in show_name_helpers.makeSceneSearchString(show, season, episode, abd)]
def _get_title_and_url(self, item):
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.session = requests.Session()
def isEnabled(self):
return sickbeard.PUBLICHD
@ -72,51 +74,41 @@ class PublicHDProvider(generic.TorrentProvider):
quality = Quality.sceneQuality(item[0])
return quality
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False):
search_string = {'Episode': []}
def _get_season_search_strings(self, show, season, episode, abd=False):
if not show:
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:
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)
ep_string = show_name + ' Season ' + str(season) #2) ShowName Season X
search_string['Season'].append(ep_string)
ep_string = show_name + ' Season ' + str(season) #2) ShowName Season X
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 []
search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
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': []}
if not ep_obj:
if not episode:
return []
self.show = ep_obj.show
if ep_obj.show.air_by_date:
for show_name in set(allPossibleShowNames(ep_obj.show)):
if abd:
for show_name in set(allPossibleShowNames(show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate)
str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string)
else:
for show_name in set(allPossibleShowNames(ep_obj.show)):
for show_name in set(allPossibleShowNames(show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
'episodenumber': ep_obj.scene_episode}
sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': episode}
for x in add_string.split('|'):
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):
if not self.session:
self.session = requests.Session()
try:
# 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)
r = requests.get(url, verify=False)
r = self.session.get(url, verify=False)
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
logger.log(u"Error loading " + self.name + " URL: " + str(sys.exc_info()) + " - " + ex(e), logger.ERROR)
return None
@ -229,6 +224,9 @@ class PublicHDProvider(generic.TorrentProvider):
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()
if not torrent_hash:
@ -236,7 +234,7 @@ class PublicHDProvider(generic.TorrentProvider):
return False
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:
logger.log("Unable to connect to Torcache: " + ex(e), logger.ERROR)
return False

View file

@ -42,6 +42,7 @@ class TorrentRssProvider(generic.TorrentProvider):
self.url = re.sub('\/$', '', url)
self.enabled = True
self.supportsBacklog = False
self.session = requests.Session()
def configStr(self):
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))
def getURL(self, url, post_data=None, headers=None):
if not self.session:
self.session = requests.Session()
try:
parsed = list(urlparse.urlparse(url))
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:
logger.log(u"Error loading " + self.name + " URL: " + ex(e), logger.ERROR)
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)
r.status_code) + ': ' + clients.http_error_code[r.status_code], logger.WARNING)
return None
return response.content
return r.content
def dumpHTML(self, data):

View file

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

View file

@ -18,9 +18,10 @@
import re
import datetime
import urlparse
import sickbeard
import generic
from sickbeard.common import Quality
from sickbeard import logger
from sickbeard import tvcache
@ -32,7 +33,7 @@ from sickbeard.common import Overview
from sickbeard.exceptions import ex
from sickbeard import clients
from lib import requests
from lib.requests import exceptions
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.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):
return sickbeard.SPEEDCD
@ -75,10 +78,10 @@ class SpeedCDProvider(generic.TorrentProvider):
}
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:
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:
logger.log(u'Unable to connect to ' + self.name + ' provider: ' + ex(e), logger.ERROR)
return False
@ -90,55 +93,43 @@ class SpeedCDProvider(generic.TorrentProvider):
return True
def _get_season_search_strings(self, show, season=None):
search_string = {'Episode': []}
def _get_season_search_strings(self, show, season, episode, abd=False):
if not show:
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 wantedEp == seasonEp and not show.air_by_date:
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)
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)
#Building the search string with the episodes we need
for ep_obj in wantedEp:
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 []
search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
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': []}
if not ep_obj:
if not episode:
return []
if ep_obj.show.air_by_date:
for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) +' '+ str(ep_obj.airdate)
if abd:
for show_name in set(show_name_helpers.allPossibleShowNames(show)):
ep_string = show_name_helpers.sanitizeSceneName(show_name) +' '+ str(episode)
search_string['Episode'].append(ep_string)
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) +' '+ \
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))
return [search_string]
def _doSearch(self, search_params, show=None):
def _doSearch(self, search_params, show=None, age=None):
results = []
items = {'Season': [], 'Episode': [], 'RSS': []}
@ -197,25 +188,34 @@ class SpeedCDProvider(generic.TorrentProvider):
return (title, url)
def getURL(self, url, headers=None):
def getURL(self, url, post_data=None, headers=None):
if not self.session:
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:
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:
logger.log(u"Error loading "+self.name+" URL: " + ex(e), logger.ERROR)
return None
if response.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)
if r.status_code != 200:
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 response.content
return r.content
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.session = requests.Session()
def isEnabled(self):
return sickbeard.THEPIRATEBAY
@ -170,56 +172,45 @@ class ThePirateBayProvider(generic.TorrentProvider):
return title
def _get_season_search_strings(self, show, season, wantedEp, searchSeason=False):
search_string = {'Episode': []}
def _get_season_search_strings(self, show, season, episode, abd=False):
if not show:
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:
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)
ep_string = show_name + ' Season ' + str(season) + ' -Ep*' #2) ShowName Season X
search_string['Season'].append(ep_string)
ep_string = show_name + ' Season ' + str(season) + ' -Ep*' #2) ShowName Season X
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 []
search_string['Episode'] = self._get_episode_search_strings(show, season, episode, abd)[0]['Episode']
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': []}
if not ep_obj:
if not episode:
return []
self.show = ep_obj.show
if ep_obj.show.air_by_date:
for show_name in set(allPossibleShowNames(ep_obj.show)):
if abd:
for show_name in set(allPossibleShowNames(show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \
str(ep_obj.airdate) + '|' + \
helpers.custom_strftime('%Y %b {S}', ep_obj.airdate)
str(episode) + '|' + \
helpers.custom_strftime('%Y %b {S}', episode)
search_string['Episode'].append(ep_string)
else:
for show_name in set(allPossibleShowNames(ep_obj.show)):
for show_name in set(allPossibleShowNames(show)):
ep_string = sanitizeSceneName(show_name) + ' ' + \
sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
'episodenumber': ep_obj.scene_episode} + '|' + \
sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season,
'episodenumber': ep_obj.scene_episode} + '|' + \
sickbeard.config.naming_ep_type[3] % {'seasonnumber': ep_obj.scene_season,
'episodenumber': ep_obj.scene_episode}
sickbeard.config.naming_ep_type[2] % {'seasonnumber': season,
'episodenumber': episode} + '|' + \
sickbeard.config.naming_ep_type[0] % {'seasonnumber': season,
'episodenumber': episode} + '|' + \
sickbeard.config.naming_ep_type[3] % {'seasonnumber': season,
'episodenumber': episode}
ep_string += ' %s' % add_string
@ -302,6 +293,9 @@ class ThePirateBayProvider(generic.TorrentProvider):
if not headers:
headers = {}
if not self.session:
self.session = requests.Session()
# Glype Proxies does not support Direct Linking.
# We have to fake a search on the proxy site to get data
if self.proxy.isEnabled():
@ -314,9 +308,9 @@ class ThePirateBayProvider(generic.TorrentProvider):
"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:
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:
logger.log(u"Error loading " + self.name + " URL: " + str(sys.exc_info()) + " - " + ex(e), logger.ERROR)
return None
@ -332,6 +326,8 @@ class ThePirateBayProvider(generic.TorrentProvider):
"""
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()
@ -340,7 +336,7 @@ class ThePirateBayProvider(generic.TorrentProvider):
return False
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:
logger.log("Unable to connect to Torcache: " + ex(e), logger.ERROR)
return False

View file

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

View file

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

View file

@ -56,7 +56,7 @@ class TvTorrentsProvider(generic.TorrentProvider):
def _checkAuthFromData(self, data):
if data is None:
if data is None or data.feed is None:
return self._checkAuth()
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 + ')'
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:
logger.log(u"No data returned from " + rss_url, logger.ERROR)

View file

@ -25,7 +25,7 @@ import datetime
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 sab
@ -349,67 +349,23 @@ def isFirstBestMatch(result):
return 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):
def searchProviders(show, season, episode=None, manualSearch=False):
logger.log(u"Searching for stuff we need from " + show.name + " season " + str(season))
foundResults = {}
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():
@ -417,7 +373,7 @@ def findSeason(show, season):
continue
try:
curResults = curProvider.findSeasonResults(show, season)
curResults = curProvider.getSearchResults(show, season, wantedEps, seasonSearch, manualSearch)
# make a list of all the results for this provider
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())
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
if not foundEpisode:
if not foundResults:
ui.notifications.message('No downloads were found',
"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())
self.success = result
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
logger.log(u"Downloading episode from " + foundEpisode.url)
result = search.snatchEpisode(foundResult)
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
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
self.success = result
def finish(self):
# 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 = ?",
[self.show.indexerid, self.segment])
else:
segment_year, segment_month = map(int, self.segment.split('-'))
min_date = datetime.date(segment_year, segment_month, 1)
season_year, season_month = map(int, self.segment.split('-'))
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
if segment_month == 12:
max_date = datetime.date(segment_year, 12, 31)
if season_month == 12:
max_date = datetime.date(season_year, 12, 31)
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(
"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)
results = search.findSeason(self.show, self.segment)
results = search.searchProviders(self.show, self.segment)
# download whatever we find
for curResult in results:
@ -273,13 +274,8 @@ class FailedQueueItem(generic_queue.QueueItem):
failed_history.revertEpisode(self.show, season, episode)
for season, episode in self.segment.iteritems():
epObj = self.show.getEpisode(season, episode)
if self.show.air_by_date:
results = search.findSeason(self.show, str(epObj.airdate)[:7])
else:
results = search.findSeason(self.show, season)
# get search results
results = search.searchProviders(self.show, season, episode)
# download whatever we find
for curResult in results:

View file

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

View file

@ -23,7 +23,9 @@ import datetime
import threading
import re
import glob
from time import sleep
import traceback
import shutil
import sickbeard
@ -241,6 +243,7 @@ class TVShow(object):
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
if (update_date - last_airdate) < datetime.timedelta(days=450) and (
update_date - last_update_indexer) > datetime.timedelta(days=30):
@ -307,8 +310,49 @@ class TVShow(object):
# create TVEpisodes from each media file (if possible)
for mediaFile in mediaFiles:
sceneConvert = False
parse_result = 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)
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.splitext, ep_file_name)[0]
parse_result = None
try:
np = NameParser(False)
parse_result = np.parse(ep_file_name)
@ -2087,8 +2130,7 @@ class TVEpisode(object):
self.location)
if self.show.subtitles and sickbeard.SUBTITLES_DIR != '':
related_subs = postProcessor.PostProcessor(self.location).list_associated_files(
sickbeard.SUBTITLES_DIR, subtitles_only=True)
related_subs = postProcessor.PostProcessor(self.location).list_associated_files(sickbeard.SUBTITLES_DIR, subtitles_only=True)
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)
@ -2104,8 +2146,7 @@ class TVEpisode(object):
logger.log(str(self.indexerid) + u": Unable to rename file " + cur_related_file, logger.ERROR)
for cur_related_sub in related_subs:
cur_result = helpers.rename_ep_file(cur_related_sub, absolute_proper_subs_path,
absolute_current_path_no_ext_length)
cur_result = helpers.rename_ep_file(cur_related_sub, absolute_proper_subs_path,absolute_current_path_no_ext_length)
if cur_result == False:
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,
nextgen_username=None, nextgen_password=None,
newzbin_username=None, newzbin_password=None,
speedcd_username=None, speedcd_password=None, speedcd_freeleech=None,
provider_order=None):
results = []

View file

@ -74,13 +74,14 @@ def test_generator(tvdbdid, show_name, curData, forceSearch):
show.quality = curData["q"]
show.saveToDB()
sickbeard.showList.append(show)
episode = None
for epNumber in curData["e"]:
episode = TVEpisode(show, curData["s"], epNumber)
episode.status = c.WANTED
episode.saveToDB()
bestResult = search.findEpisode(episode, forceSearch)
bestResult = search.searchProviders(show, episode.season, episode.episode, forceSearch)
if not bestResult:
self.assertEqual(curData["b"], bestResult)
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
"""
# 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)):
os.remove(os.path.join(TESTDIR, TESTDBNAME))
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 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):
def loadFromDB(self):
@ -50,9 +52,29 @@ class XEMBasicTests(test.SickbeardTestDBCase):
show = sickbeard.helpers.findCertainShow(sickbeard.showList, 111051)
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(
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__":
print "=================="
print "STARTING - XEM Scene Numbering TESTS"