Browse Source

Merge branch 'hotfix/0.21.7'

tags/release_0.21.7^0 release_0.21.7
JackDandy 5 years ago
parent
commit
db699b6735
  1. 12
      CHANGES.md
  2. 31
      lib/rtorrent/__init__.py
  3. 3
      lib/rtorrent/common.py
  4. 9
      lib/rtorrent/compat.py
  5. 5
      lib/rtorrent/err.py
  6. 7
      lib/rtorrent/file.py
  7. 7
      lib/rtorrent/group.py
  8. 4
      lib/rtorrent/lib/bencode.py
  9. 55
      lib/rtorrent/lib/torrentparser.py
  10. 14
      lib/rtorrent/lib/xmlrpc/basic_auth.py
  11. 9
      lib/rtorrent/lib/xmlrpc/scgi.py
  12. 7
      lib/rtorrent/peer.py
  13. 15
      lib/rtorrent/rpc/__init__.py
  14. 22
      lib/rtorrent/torrent.py
  15. 10
      lib/rtorrent/tracker.py
  16. 9
      sickbeard/providers/iptorrents.py
  17. 13
      sickbeard/providers/scenetime.py
  18. 10
      sickbeard/providers/skytorrents.py
  19. 12
      sickbeard/providers/torrentday.py
  20. 10
      sickbeard/providers/torrentleech.py
  21. 7
      sickbeard/webserve.py
  22. 4
      sickbeard/webserveInit.py

12
CHANGES.md

@ -1,4 +1,12 @@
### 0.21.6 (2020-01-21 22:30:00 UTC)
### 0.21.7 (2020-01-24 15:05:00 UTC)
* Fix rTorrent py3 compat
* Fix edit show with multiple list values under py3
* Change improve search performance of some providers
* Change cache control of static files sent to browser to ensure page content is updated
### 0.21.6 (2020-01-21 22:30:00 UTC)
* Fix Kodi service addon + bump to 1.0.7 (select "Check for updates" on menu of "SickGear Add-on repository")
* Change Kodi Add-on/"What's new" list order to be latest version info at top
@ -6,7 +14,7 @@
* Fix a rare post processing issue that created `dictionary changed size` error
* Fix ensure PySocks is available for Requests/urllib3
* Fix fanart image update issue
* Change add examples to config/general/advanced/"Proxy host" that show scheme and authentication usage
* Change add examples that show scheme and authentication usage to config/general/advanced/"Proxy host"
* Change add warning that Kodi Add-on requires IP to setting config/general/"Allow IP use for connections"
* Change About page version string

31
lib/rtorrent/__init__.py

@ -17,24 +17,28 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import os.path
import time
from .common import convert_version_tuple_to_str, find_torrent, is_valid_port, join_uri, update_uri
from .compat import urlparse, xmlrpclib
from .lib.torrentparser import TorrentParser
from .lib.xmlrpc.basic_auth import BasicAuthTransport
from .lib.xmlrpc.http import HTTPServerProxy
from .lib.xmlrpc.scgi import SCGIServerProxy
from .rpc import Method
import rpc # @UnresolvedImport
from . import rpc
from .common import convert_version_tuple_to_str, find_torrent, is_valid_port, join_uri, update_uri
from .compat import urlparse, xmlrpclib
from .file import File, methods as file_methods
from .group import Group
from .peer import Peer, methods as peer_methods
from .rpc import Method
from .torrent import Torrent, methods as torrent_methods
from .tracker import Tracker, methods as tracker_methods
from _23 import filter_iter, filter_list, map_list
__version__ = '0.2.10'
__author__ = 'Chris Lucas'
__maintainer__ = 'SickGear'
@ -180,15 +184,15 @@ class RTorrent(object):
@todo: add validity check for specified view
"""
self.torrents = []
retriever_methods = filter(lambda m: m.is_retriever() and m.is_available(self), torrent_methods)
retriever_methods = filter_list(lambda m: m.is_retriever() and m.is_available(self), torrent_methods)
mc = rpc.Multicall(self)
if self.method_exists('d.multicall2'):
mc.add('d.multicall2', '', view, 'd.hash=',
*map(lambda m2: ((getattr(m2, 'aliases') or [''])[-1] or m2.rpc_call) + '=', retriever_methods))
*map_list(lambda m2: ((getattr(m2, 'aliases') or [''])[-1] or m2.rpc_call) + '=', retriever_methods))
else:
mc.add('d.multicall', view, 'd.get_hash=',
*map(lambda m1: m1.rpc_call + '=', retriever_methods))
*map_list(lambda m1: m1.rpc_call + '=', retriever_methods))
results = mc.call()[0] # only sent one call, only need first result
@ -236,7 +240,7 @@ class RTorrent(object):
try:
call, arg = x.split('=')
method = rpc.find_method(call)
method_name = filter(lambda m: self.method_exists(m), (method.rpc_call,) + method.aliases)[0]
method_name = next(filter_iter(lambda m: self.method_exists(m), (method.rpc_call,) + method.aliases))
param += ['%s=%s' % (method_name, arg)]
except (BaseException, Exception):
pass
@ -263,7 +267,7 @@ class RTorrent(object):
max_retries = 10
while max_retries:
try:
t = filter(lambda td: td.info_hash.upper() == info_hash, self.get_torrents())[0]
t = next(filter_iter(lambda td: td.info_hash.upper() == info_hash, self.get_torrents()))
break
except (BaseException, Exception):
time.sleep(self.request_interval)
@ -322,7 +326,7 @@ class RTorrent(object):
if verify_load:
while verify_retries:
try:
t = filter(lambda td: td.info_hash == info_hash, self.get_torrents())[0]
t = next(filter_iter(lambda td: td.info_hash == info_hash, self.get_torrents()))
break
except (BaseException, Exception):
time.sleep(self.request_interval)
@ -412,14 +416,17 @@ class RTorrent(object):
@raise AssertionError: if invalid port is given
"""
assert is_valid_port(port), 'Valid port range is 0-65535'
# noinspection PyUnresolvedReferences
self.dht_port = self._p.set_dht_port(port)
def enable_check_hash(self):
"""Alias for set_check_hash(True)"""
# noinspection PyUnresolvedReferences
self.set_check_hash(True)
def disable_check_hash(self):
"""Alias for set_check_hash(False)"""
# noinspection PyUnresolvedReferences
self.set_check_hash(False)
def find_torrent(self, info_hash):
@ -430,7 +437,7 @@ class RTorrent(object):
method = rpc.find_method('d.get_local_id')
result = True
try:
func = filter(lambda m: self.method_exists(m), (method.rpc_call,) + method.aliases)[0]
func = next(filter_iter(lambda m: self.method_exists(m), (method.rpc_call,) + method.aliases))
getattr(self.get_connection(), func)(info_hash)
except(xmlrpclib.Fault, BaseException):
result = False
@ -459,7 +466,7 @@ class RTorrent(object):
"""
mc = rpc.Multicall(self)
for method in filter(lambda m: m.is_retriever() and m.is_available(self), methods):
for method in filter_iter(lambda m: m.is_retriever() and m.is_available(self), methods):
mc.add(method)
mc.call()

3
lib/rtorrent/common.py

@ -17,10 +17,11 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from compat import is_py3, urlparse, urlunparse, ParseResult
import os
from .compat import is_py3, urlparse, urlunparse, ParseResult
def bool_to_int(value):
"""Translates python booleans to RPC-safe integers"""

9
lib/rtorrent/compat.py

@ -26,15 +26,18 @@ def is_py3():
if is_py3():
# noinspection PyCompatibility
# noinspection PyCompatibility,PyUnresolvedReferences
from urllib.parse import parse_qs, ParseResult, urlparse, urlunparse
# noinspection PyCompatibility
# noinspection PyCompatibility,PyUnresolvedReferences
from urllib.request import urlopen
# noinspection PyUnresolvedReferences
import xmlrpc.client as xmlrpclib
else:
# noinspection PyCompatibility,PyUnresolvedReferences
from urllib2 import urlopen
# noinspection PyProtectedMember
# noinspection PyCompatibility,PyProtectedMember,PyUnresolvedReferences
from urlparse import parse_qs, ParseResult, urlparse, urlunparse
# noinspection PyUnresolvedReferences
import xmlrpclib

5
lib/rtorrent/err.py

@ -18,15 +18,14 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from common import convert_version_tuple_to_str
from .common import convert_version_tuple_to_str
class RTorrentVersionError(Exception):
def __init__(self, min_version, cur_version):
self.min_version = min_version
self.cur_version = cur_version
self.msg = 'Minimum version required: {0}'.format(
convert_version_tuple_to_str(min_version))
self.msg = 'Minimum version required: {0}'.format(convert_version_tuple_to_str(min_version))
def __str__(self):
return self.msg

7
lib/rtorrent/file.py

@ -18,9 +18,11 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from . import rpc
from .common import safe_repr
from .rpc import Method
import rpc
from _23 import filter_iter
class File(object):
@ -30,6 +32,7 @@ class File(object):
self._rt_obj = _rt_obj
self.info_hash = info_hash # : info hash for the torrent the file is associated with
self.index = index # : The position of the file within the file list
self.path = ''
for k in kwargs:
setattr(self, k, kwargs.get(k, None))
@ -45,7 +48,7 @@ class File(object):
"""
mc = rpc.Multicall(self)
for method in filter(lambda m: m.is_retriever() and m.is_available(self._rt_obj), methods):
for method in filter_iter(lambda m: m.is_retriever() and m.is_available(self._rt_obj), methods):
mc.add(method, self.rpc_id)
mc.call()

7
lib/rtorrent/group.py

@ -18,8 +18,10 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from . import rpc
from .rpc import Method
import rpc
from _23 import filter_iter
class Group(object):
@ -28,6 +30,7 @@ class Group(object):
def __init__(self, _rt_obj, name):
self._rt_obj = _rt_obj
self.name = name
self.multicall_add = None
self.methods = [
# RETRIEVERS
@ -69,7 +72,7 @@ class Group(object):
def _get_method(self, *choices):
try:
return filter(lambda method: self._rt_obj.method_exists(method), choices)[0]
return next(filter_iter(lambda method: self._rt_obj.method_exists(method), choices))
except (BaseException, Exception):
pass

4
lib/rtorrent/lib/bencode.py

@ -42,8 +42,10 @@ _py3 = sys.version_info[0] == 3
if _py3:
_VALID_STRING_TYPES = (str,)
_VALID_INTEGER_TYPES = (int, )
else:
_VALID_STRING_TYPES = (str, unicode) # @UndefinedVariable
_VALID_INTEGER_TYPES = (int, long)
_TYPE_INT = 1
_TYPE_STRING = 2
@ -267,7 +269,7 @@ def _encode_dict(data):
def encode(data):
if isinstance(data, bool):
return False
elif isinstance(data, (int, long)):
elif isinstance(data, _VALID_INTEGER_TYPES):
return _encode_int(data)
elif isinstance(data, bytes):
return _encode_string(data)

55
lib/rtorrent/lib/torrentparser.py

@ -117,58 +117,3 @@ class TorrentParser(object):
setattr(self, key, self._torrent_decoded[k])
self._calc_info_hash()
class NewTorrentParser(object):
@staticmethod
def _read_file(fp):
return fp.read()
@staticmethod
def _write_file(fp):
fp.write()
return fp
@staticmethod
def _decode_torrent(data):
return bencode.decode(data)
def __init__(self, infile):
self.input = infile
self._raw_torrent = None
self._decoded_torrent = None
self._hash_outdated = False
if isinstance(self.input, (str, bytes)):
# path to file?
if os.path.isfile(self.input):
self._raw_torrent = self._read_file(open(self.input, 'rb'))
else:
# assume input was the raw torrent data (do we really want
# this?)
self._raw_torrent = self.input
# file-like object?
elif self.input.hasattr('read'):
self._raw_torrent = self._read_file(self.input)
assert self._raw_torrent is not None, 'Invalid input: input must be a path or a file-like object'
self._decoded_torrent = self._decode_torrent(self._raw_torrent)
assert isinstance(
self._decoded_torrent, dict), 'File could not be decoded'
def _calc_info_hash(self):
self.info_hash = None
info_dict = self._torrent_decoded['info']
self.info_hash = hashlib.sha1(bencode.encode(
info_dict)).hexdigest().upper()
return self.info_hash
def set_tracker(self, tracker):
self._decoded_torrent['announce'] = tracker
def get_tracker(self):
return self._decoded_torrent.get('announce')

14
lib/rtorrent/lib/xmlrpc/basic_auth.py

@ -22,6 +22,7 @@
from ...compat import xmlrpclib
from six import PY2
# noinspection PyUnresolvedReferences
from six.moves import http_client as httplib
from _23 import b64encodestring
@ -68,9 +69,16 @@ class BasicAuthTransport(xmlrpclib.Transport):
h.set_debuglevel(1)
try:
self.send_request(h, handler, request_body)
self.send_host(h, host)
self.send_user_agent(h)
if not PY2:
# noinspection PyArgumentList
self.send_request(h, handler, request_body, False)
else:
# noinspection PyArgumentList
self.send_request(h, handler, request_body)
# noinspection PyUnresolvedReferences
self.send_host(h, host)
# noinspection PyUnresolvedReferences
self.send_user_agent(h)
self.send_auth(h)
self.send_content(h, request_body)

9
lib/rtorrent/lib/xmlrpc/scgi.py

@ -84,10 +84,11 @@ from __future__ import print_function
import re
import socket
import sys
from ...compat import urlparse, xmlrpclib
from _23 import decode_bytes
class SCGITransport(xmlrpclib.Transport):
@ -116,11 +117,7 @@ class SCGITransport(xmlrpclib.Transport):
# noinspection PyAttributeOutsideInit
self.verbose = verbose
if sys.version_info[0] > 2:
# noinspection PyArgumentList
sock.send(bytes(request_body, 'utf-8')) # py3
else:
sock.send(request_body)
sock.send(decode_bytes(request_body))
return self.parse_response(sock.makefile())
finally:
if sock:

7
lib/rtorrent/peer.py

@ -18,24 +18,25 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from . import rpc
from .common import safe_repr
from .rpc import Method
import rpc
class Peer(object):
"""Represents an individual peer within a L{Torrent} instance."""
def __init__(self, _rt_obj, info_hash, **kwargs):
self._rt_obj = _rt_obj
self.id = None
self.info_hash = info_hash # : info hash for the torrent the peer is associated with
for k in kwargs:
setattr(self, k, kwargs.get(k, None))
self.rpc_id = '{0}:p{1}'.format(
self.info_hash, self.id) # : unique id to pass to rTorrent
self.info_hash, self.id or '') # : unique id to pass to rTorrent
def __repr__(self):
return safe_repr('Peer(id={0})', self.id)
return safe_repr('Peer(id={0})', self.id or '')
def update(self):
"""Refresh peer data

15
lib/rtorrent/rpc/__init__.py

@ -27,6 +27,8 @@ import re
import rtorrent
from _23 import filter_iter, map_list
def get_varname(rpc_call):
"""Transform rpc method into variable name.
@ -92,8 +94,8 @@ class Method(object):
if rt_obj.get_client_version_tuple() >= self.min_version:
try:
self.varname = get_varname(filter(lambda f: rt_obj.method_exists(f),
(self.rpc_call,) + tuple(getattr(self, 'aliases', '')))[0])
self.varname = get_varname(next(filter_iter(lambda f: rt_obj.method_exists(f),
(self.rpc_call,) + tuple(getattr(self, 'aliases', '')))))
return True
except IndexError:
pass
@ -160,7 +162,7 @@ class Multicall(object):
getattr(xmc, rpc_call)(*args)
try:
results = tuple(filter(lambda x: isinstance(x, list), xmc().results)[0])
results = tuple(next(filter_iter(lambda x: isinstance(x, list), xmc().results)))
except IndexError:
return [[]]
@ -195,7 +197,7 @@ def call_method(class_obj, method, *args):
if 'RTorrent' == class_obj.__class__.__name__:
rt_obj = class_obj
else:
# noinspection PyProtectedMember
# noinspection PyProtectedMember,PyUnresolvedReferences
rt_obj = class_obj._rt_obj
# check if rpc method is even available
@ -214,9 +216,10 @@ def find_method(rpc_call):
"""Return L{Method} instance associated with given RPC call"""
try:
rpc_call = rpc_call.lower()
return filter(lambda m: rpc_call in map(lambda n: n.lower(), [m.rpc_call] + list(getattr(m, 'aliases', []))),
return next(filter_iter(lambda m: rpc_call in map_list(
lambda n: n.lower(), [m.rpc_call] + list(getattr(m, 'aliases', []))),
rtorrent.methods + rtorrent.torrent.methods +
rtorrent.file.methods + rtorrent.tracker.methods + rtorrent.peer.methods)[0]
rtorrent.file.methods + rtorrent.tracker.methods + rtorrent.peer.methods))
except IndexError:
return -1

22
lib/rtorrent/torrent.py

@ -18,13 +18,14 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from . import rpc
from .common import safe_repr
from .file import File, methods as file_methods
from .peer import Peer, methods as peer_methods
from .tracker import Tracker, methods as tracker_methods
from .rpc import Method
import rpc
from .tracker import Tracker, methods as tracker_methods
from _23 import filter_iter, filter_list
class Torrent(object):
@ -33,6 +34,9 @@ class Torrent(object):
def __init__(self, _rt_obj, info_hash, **kwargs):
self._rt_obj = _rt_obj
self.info_hash = info_hash # : info hash for the torrent
self.hash_checking = None
self.multicall_add = None
self.name = None
self.rpc_id = self.info_hash # : unique id to pass to rTorrent
for k in kwargs:
setattr(self, k, kwargs.get(k, None))
@ -49,7 +53,7 @@ class Torrent(object):
def __repr__(self):
return safe_repr('Torrent(info_hash="{0}" name="{1}")',
self.info_hash, self.name)
self.info_hash, self.name or '')
def _call_custom_methods(self):
"""only calls methods that check instance variables."""
@ -66,7 +70,7 @@ class Torrent(object):
@note: also assigns return value to self.peers
"""
self.peers = []
retriever_methods = filter(lambda m: m.is_retriever() and m.is_available(self._rt_obj), peer_methods)
retriever_methods = filter_list(lambda m: m.is_retriever() and m.is_available(self._rt_obj), peer_methods)
mc = rpc.Multicall(self)
# need to leave 2nd arg empty (dunno why)
@ -93,7 +97,7 @@ class Torrent(object):
@note: also assigns return value to self.trackers
"""
self.trackers = []
retriever_methods = filter(lambda m: m.is_retriever() and m.is_available(self._rt_obj), tracker_methods)
retriever_methods = filter_list(lambda m: m.is_retriever() and m.is_available(self._rt_obj), tracker_methods)
mc = rpc.Multicall(self)
# need to leave 2nd arg empty (dunno why)
@ -121,7 +125,7 @@ class Torrent(object):
"""
self.files = []
retriever_methods = filter(lambda m: m.is_retriever() and m.is_available(self._rt_obj), file_methods)
retriever_methods = filter_list(lambda m: m.is_retriever() and m.is_available(self._rt_obj), file_methods)
mc = rpc.Multicall(self)
# 2nd arg can be anything, but it'll return all files in torrent
@ -151,7 +155,7 @@ class Torrent(object):
def _get_method(self, *choices):
try:
return filter(lambda method: self._rt_obj.method_exists(method), choices)[0]
return next(filter_iter(lambda method: self._rt_obj.method_exists(method), choices))
except (BaseException, Exception):
pass
@ -272,7 +276,7 @@ class Torrent(object):
"""
mc = rpc.Multicall(self)
for method in filter(lambda m: m.is_retriever() and m.is_available(self._rt_obj), methods):
for method in filter_iter(lambda m: m.is_retriever() and m.is_available(self._rt_obj), methods):
mc.add(method, self.rpc_id)
mc.call()

10
lib/rtorrent/tracker.py

@ -18,9 +18,11 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from . import rpc
from .common import safe_repr
from .rpc import Method
import rpc
from _23 import filter_iter
class Tracker(object):
@ -29,6 +31,10 @@ class Tracker(object):
def __init__(self, _rt_obj, info_hash, **kwargs):
self._rt_obj = _rt_obj
self.info_hash = info_hash # : info hash for the torrent using this tracker
self.group = None
self.multicall_add = None
self.set_enabled = lambda x: True
self.url = None
for k in kwargs:
setattr(self, k, kwargs.get(k, None))
@ -58,7 +64,7 @@ class Tracker(object):
"""
mc = rpc.Multicall(self)
for method in filter(lambda fx: fx.is_retriever() and fx.is_available(self._rt_obj), methods):
for method in filter_iter(lambda fx: fx.is_retriever() and fx.is_available(self._rt_obj), methods):
mc.add(method, self.rpc_id)
mc.call()

9
sickbeard/providers/iptorrents.py

@ -129,10 +129,6 @@ class IPTorrentsProvider(generic.TorrentProvider):
try:
head = head if None is not head else self._header_row(
tr, header_strip='(?i)(?:leechers|seeders|size);')
seeders, leechers = [try_int(tr.find('td', class_='t_' + x).get_text().strip())
for x in ('seeders', 'leechers')]
if self._reject_item(seeders, leechers):
continue
dl = tr.find('a', href=rc['get'])['href']
dl_id = rc['id'].findall(dl)[0]
@ -140,6 +136,11 @@ class IPTorrentsProvider(generic.TorrentProvider):
if lrs_found:
break
seeders, leechers = [try_int(tr.find('td', class_='t_' + x).get_text().strip())
for x in ('seeders', 'leechers')]
if self._reject_item(seeders, leechers):
continue
info = tr.find('a', href=rc['info'])
title = (info.attrs.get('title') or info.get_text()).strip()
size = cells[head['size']].get_text().strip()

13
sickbeard/providers/scenetime.py

@ -83,7 +83,6 @@ class SceneTimeProvider(generic.TorrentProvider):
def _search_urls(self, mode, last_recent_search, urls):
results = []
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict([(k, re.compile('(?i)' + v)) for (k, v) in iteritems({
@ -123,6 +122,13 @@ class SceneTimeProvider(generic.TorrentProvider):
cnt_search += 1
try:
head = head if None is not head else self._header_row(tr)
info = tr.find('a', href=rc['info'])
dl_id = re.sub(rc['get'], r'\1', str(info.attrs['href']))
lrs_found = dl_id == last_recent_search
if lrs_found:
break
seeders, leechers, size = [try_int(n, n) for n in [
cells[head[x]].get_text().strip() for x in ('seed', 'leech', 'size')]]
if None is tr.find('a', href=rc['cats']) or self._reject_item(
@ -130,11 +136,6 @@ class SceneTimeProvider(generic.TorrentProvider):
self.freeleech and (None is rc['fl'].search(cells[1].get_text()))):
continue
info = tr.find('a', href=rc['info'])
dl_id = re.sub(rc['get'], r'\1', str(info.attrs['href']))
lrs_found = dl_id == last_recent_search
if lrs_found:
break
title = (info.attrs.get('title') or info.get_text()).strip()
download_url = self._link('%s/%s' % (dl_id, str(title).replace(' ', '.')))
except (AttributeError, TypeError, ValueError, KeyError):

10
sickbeard/providers/skytorrents.py

@ -61,7 +61,6 @@ class SkytorrentsProvider(generic.TorrentProvider):
def _search_urls(self, mode, last_recent_search, urls):
results = []
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict([(k, re.compile('(?i)' + v)) for (k, v) in iteritems({
@ -96,10 +95,6 @@ class SkytorrentsProvider(generic.TorrentProvider):
cnt_search += 1
try:
head = head if None is not head else self._header_row(tr)
seeders, leechers, size = [try_int(n, n) for n in [
cells[head[x]].get_text().strip() for x in ('seed', 'leech', 'size')]]
if self._reject_item(seeders, leechers):
continue
dl = tr.find('a', href=rc['get'])['href']
dl_id = rc['get'].findall(dl)[0]
@ -107,6 +102,11 @@ class SkytorrentsProvider(generic.TorrentProvider):
if lrs_found:
break
seeders, leechers, size = [try_int(n, n) for n in [
cells[head[x]].get_text().strip() for x in ('seed', 'leech', 'size')]]
if self._reject_item(seeders, leechers):
continue
info = tr.select_one(
'[alt*="magnet"], [title*="magnet"]') \
or tr.find('a', href=rc['info'])

12
sickbeard/providers/torrentday.py

@ -85,8 +85,8 @@ class TorrentDayProvider(generic.TorrentProvider):
return results
def _search_urls(self, mode, last_recent_search, urls):
results = []
results = []
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in iteritems(dict(get='download', id=r'download.*?/([\d]+)')))
@ -124,16 +124,18 @@ class TorrentDayProvider(generic.TorrentProvider):
try:
head = head if None is not head else self._header_row(
tr, header_strip='(?i)(?:leechers|seeders|size);')
seeders, leechers, size = [try_int(n, n) for n in [
cells[head[x]].get_text().strip() for x in ('seed', 'leech', 'size')]]
if self._reject_item(seeders, leechers):
continue
dl = tr.find('a', href=rc['get'])['href']
dl_id = rc['id'].findall(dl)[0]
lrs_found = dl_id == last_recent_search
if lrs_found:
break
seeders, leechers, size = [try_int(n, n) for n in [
cells[head[x]].get_text().strip() for x in ('seed', 'leech', 'size')]]
if self._reject_item(seeders, leechers):
continue
title = tr.find('a', href=re.compile('/t/%s' % dl_id)).get_text().strip()
download_url = self._link(dl)
except (AttributeError, TypeError, ValueError, IndexError):

10
sickbeard/providers/torrentleech.py

@ -116,10 +116,6 @@ class TorrentLeechProvider(generic.TorrentProvider):
cnt_search += 1
try:
head = head if None is not head else self._header_row(tr)
seeders, leechers = [try_int(n) for n in [
tr.find('td', class_=x).get_text().strip() for x in ('seeders', 'leechers')]]
if self._reject_item(seeders, leechers):
continue
dl = tr.find('a', href=rc['get'])['href']
dl_id = rc['id'].findall(dl)[0]
@ -127,9 +123,15 @@ class TorrentLeechProvider(generic.TorrentProvider):
if lrs_found:
break
seeders, leechers = [try_int(n) for n in [
tr.find('td', class_=x).get_text().strip() for x in ('seeders', 'leechers')]]
if self._reject_item(seeders, leechers):
continue
info = tr.find('td', class_='name').a
title = (info.attrs.get('title') or info.get_text()).strip()
size = cells[head['size']].get_text().strip()
# noinspection PyUnresolvedReferences
download_url = self._link(dl, url_quote=PY2 and isinstance(dl, unicode) or None)
except (AttributeError, TypeError, ValueError):
continue

7
sickbeard/webserve.py

@ -166,6 +166,8 @@ class BaseStaticFileHandler(StaticFileHandler):
def set_extra_headers(self, path):
self.set_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nocache, noodp, noydir, noimageindex, nosnippet')
self.set_header('Cache-Control', 'no-cache, max-age=0')
self.set_header('Pragma', 'no-cache')
if sickbeard.SEND_SECURITY_HEADERS:
self.set_header('X-Frame-Options', 'SAMEORIGIN')
@ -175,10 +177,11 @@ class RouteHandler(LegacyBaseHandler):
def data_received(self, *args):
pass
@staticmethod
def decode_data(data):
def decode_data(self, data):
if isinstance(data, binary_type):
return decode_str(data)
if isinstance(data, list):
return [self.decode_data(d) for d in data]
if not isinstance(data, string_types):
return data
if not PY2:

4
sickbeard/webserveInit.py

@ -118,7 +118,7 @@ class WebServer(threading.Thread):
self.app.add_handlers(self.re_host_pattern, [
# favicon
(r'%s/(favicon\.ico)' % self.options['web_root'], webserve.BaseStaticFileHandler,
{'path': os.path.join(self.options['data_root'], 'images/ico/favicon.ico')}),
{'path': os.path.join(self.options['data_root'], 'images', 'ico')}),
# images
(r'%s/images/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,
@ -162,7 +162,7 @@ class WebServer(threading.Thread):
self.app.add_handlers(self.re_host_pattern, [
# favicon
(r'%s/(favicon\.ico)' % self.options['web_root'], webserve.BaseStaticFileHandler,
{'path': os.path.join(self.options['data_root'], 'images/ico/favicon.ico')}),
{'path': os.path.join(self.options['data_root'], 'images', 'ico')}),
# images
(r'%s/images/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,

Loading…
Cancel
Save