mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-01 00:43:37 +00:00
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:
parent
18b781532c
commit
5772de9eec
36 changed files with 570 additions and 873 deletions
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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'])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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()):
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 = []
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)):
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue