Change request handling in torrent clients

Simplify request responses within torrent clients. There is no need to
pass the response through the parent class when dealing with requests.
In many places this makes the code more readable and simplifies logic.
This commit is contained in:
Sami Haahtinen 2015-05-06 20:25:12 +03:00
parent 1feb7a73d0
commit deda4bc65a
6 changed files with 203 additions and 191 deletions

View file

@ -31,6 +31,7 @@
* Add General Config/Interface/"Group show list shows into:"... to divide shows into groups on the Show List page
* Change Show List progress bar code, smaller page load, efficient use of js render engine
* Change values used for date sorting on home page and episode view for improved compatibility with posix systems
* Change response handling in downloaders to simplify logic.
[develop changelog]
Fix issue changing a custom show list group name that is in use. The bug resulted in the db containing stale group names

View file

@ -22,6 +22,7 @@ from base64 import b64encode
import sickbeard
from sickbeard import logger
from sickbeard.clients.generic import GenericClient
from lib.requests.exceptions import RequestException
class DelugeAPI(GenericClient):
@ -33,134 +34,148 @@ class DelugeAPI(GenericClient):
def _get_auth(self):
post_data = json.dumps({"method": "auth.login",
"params": [self.password],
"id": 1
})
post_data = json.dumps({'method': 'auth.login',
'params': [self.password],
'id': 1})
try:
self.response = self.session.post(self.url, data=post_data.encode('utf-8'), verify=sickbeard.TORRENT_VERIFY_CERT)
except:
return None
self.auth = self.session.post(
self.url,
data=post_data.encode('utf-8'),
verify=sickbeard.TORRENT_VERIFY_CERT
).json()['result']
self.auth = self.response.json()["result"]
post_data = json.dumps({'method': 'web.connected',
'params': [],
'id': 10})
post_data = json.dumps({"method": "web.connected",
"params": [],
"id": 10
})
try:
self.response = self.session.post(self.url, data=post_data.encode('utf-8'), verify=sickbeard.TORRENT_VERIFY_CERT)
except:
return None
connected = self.session.post(
self.url,
data=post_data.encode('utf-8'),
verify=sickbeard.TORRENT_VERIFY_CERT
).json()['result']
connected = self.response.json()['result']
if not connected:
post_data = json.dumps({"method": "web.get_hosts",
"params": [],
"id": 11
})
try:
self.response = self.session.post(self.url, data=post_data.encode('utf-8'), verify=sickbeard.TORRENT_VERIFY_CERT)
except:
return None
hosts = self.response.json()['result']
if len(hosts) == 0:
logger.log(self.name + u': WebUI does not contain daemons', logger.ERROR)
return None
post_data = json.dumps({"method": "web.connect",
"params": [hosts[0][0]],
"id": 11
})
try:
self.response = self.session.post(self.url, data=post_data.encode('utf-8'), verify=sickbeard.TORRENT_VERIFY_CERT)
except:
return None
post_data = json.dumps({"method": "web.connected",
"params": [],
"id": 10
})
try:
self.response = self.session.post(self.url, data=post_data.encode('utf-8'), verify=sickbeard.TORRENT_VERIFY_CERT)
except:
return None
connected = self.response.json()['result']
if not connected:
logger.log(self.name + u': WebUI could not connect to daemon', logger.ERROR)
post_data = json.dumps({'method': 'web.get_hosts',
'params': [],
'id': 11})
hosts = self.session.post(
self.url,
data=post_data.encode('utf-8'),
verify=sickbeard.TORRENT_VERIFY_CERT
).json()['result']
if len(hosts) == 0:
logger.log(self.name + u': WebUI does not contain daemons',
logger.ERROR)
return None
post_data = json.dumps({'method': 'web.connect',
'params': [hosts[0][0]],
'id': 11})
self.session.post(self.url, data=post_data.encode('utf-8'),
verify=sickbeard.TORRENT_VERIFY_CERT)
post_data = json.dumps({'method': 'web.connected',
'params': [],
'id': 10})
connected = self.session.post(
self.url,
data=post_data.encode('utf-8'),
verify=sickbeard.TORRENT_VERIFY_CERT
).json()['result']
if not connected:
logger.log(self.name + u': WebUI could not connect to daemon',
logger.ERROR)
return None
except RequestException:
return None
return self.auth
def _add_torrent_uri(self, result):
post_data = json.dumps({"method": "core.add_torrent_magnet",
"params": [result.url, {"move_completed": "true",
"move_completed_path": sickbeard.TV_DOWNLOAD_DIR}],
"id": 2
post_data = json.dumps({
'method': 'core.add_torrent_magnet',
'params': [result.url, {
'move_completed': 'true',
'move_completed_path': sickbeard.TV_DOWNLOAD_DIR
}],
'id': 2
})
self._request(method='post', data=post_data)
result.hash = self._request(method='post',
data=post_data).json()['result']
result.hash = self.response.json()['result']
return self.response.json()['result']
return result.hash
def _add_torrent_file(self, result):
post_data = json.dumps({"method": "core.add_torrent_file",
"params": [result.name + '.torrent', b64encode(result.content),
{"move_completed": "true",
"move_completed_path": sickbeard.TV_DOWNLOAD_DIR}],
"id": 2
})
self._request(method='post', data=post_data)
post_data = json.dumps({'method':
'core.add_torrent_file',
'params': [result.name + '.torrent',
b64encode(result.content),
{'move_completed': 'true',
'move_completed_path':
sickbeard.TV_DOWNLOAD_DIR}],
'id': 2})
result.hash = self._request(method='post',
data=post_data).json()['result']
result.hash = self.response.json()['result']
return self.response.json()['result']
return result.hash
def _set_torrent_label(self, result):
label = sickbeard.TORRENT_LABEL
if ' ' in label:
logger.log(self.name + u': Invalid label. Label must not contain a space', logger.ERROR)
logger.log(self.name +
u': Invalid label. Label must not contain a space',
logger.ERROR)
return False
if label:
# check if label already exists and create it if not
post_data = json.dumps({"method": 'label.get_labels',
"params": [],
"id": 3
post_data = json.dumps({
'method': 'label.get_labels',
'params': [],
'id': 3
})
self._request(method='post', data=post_data)
labels = self.response.json()['result']
labels = self._request(method='post',
data=post_data).json()['result']
if labels != None:
if labels is not None:
if label not in labels:
logger.log(self.name + ': ' + label + u" label does not exist in Deluge we must add it",
logger.log(self.name + ': ' + label +
u' label does not exist in ' +
u'Deluge we must add it',
logger.DEBUG)
post_data = json.dumps({"method": 'label.add',
"params": [label],
"id": 4
post_data = json.dumps({
'method': 'label.add',
'params': [label],
'id': 4
})
self._request(method='post', data=post_data)
logger.log(self.name + ': ' + label + u" label added to Deluge", logger.DEBUG)
logger.log(self.name + ': ' + label +
u' label added to Deluge', logger.DEBUG)
# add label to torrent
post_data = json.dumps({"method": 'label.set_torrent',
"params": [result.hash, label],
"id": 5
# add label to torrent
post_data = json.dumps({
'method': 'label.set_torrent',
'params': [result.hash, label],
'id': 5
})
self._request(method='post', data=post_data)
logger.log(self.name + ': ' + label + u" label added to torrent", logger.DEBUG)
logger.log(self.name + ': ' + label +
u' label added to torrent',
logger.DEBUG)
else:
logger.log(self.name + ': ' + u"label plugin not detected", logger.DEBUG)
logger.log(self.name + ': ' +
u'label plugin not detected',
logger.DEBUG)
return False
return not self.response.json()['error']
return True
def _set_torrent_ratio(self, result):
@ -169,53 +184,43 @@ class DelugeAPI(GenericClient):
ratio = result.ratio
if ratio:
post_data = json.dumps({"method": "core.set_torrent_stop_at_ratio",
"params": [result.hash, True],
"id": 5
})
post_data = json.dumps({'method': 'core.set_torrent_stop_at_ratio',
'params': [result.hash, True],
'id': 5})
self._request(method='post', data=post_data)
post_data = json.dumps({"method": "core.set_torrent_stop_ratio",
"params": [result.hash, float(ratio)],
"id": 6
})
post_data = json.dumps({'method': 'core.set_torrent_stop_ratio',
'params': [result.hash, float(ratio)],
'id': 6})
self._request(method='post', data=post_data)
return not self.response.json()['error']
return True
def _set_torrent_path(self, result):
if sickbeard.TORRENT_PATH:
post_data = json.dumps({"method": "core.set_torrent_move_completed",
"params": [result.hash, True],
"id": 7
post_data = json.dumps({
'method': 'core.set_torrent_move_completed',
'params': [result.hash, True],
'id': 7
})
self._request(method='post', data=post_data)
post_data = json.dumps({"method": "core.set_torrent_move_completed_path",
"params": [result.hash, sickbeard.TORRENT_PATH],
"id": 8
post_data = json.dumps({
'method': 'core.set_torrent_move_completed_path',
'params': [result.hash, sickbeard.TORRENT_PATH],
'id': 8
})
self._request(method='post', data=post_data)
return not self.response.json()['error']
return True
def _set_torrent_pause(self, result):
if sickbeard.TORRENT_PAUSED:
post_data = json.dumps({"method": "core.pause_torrent",
"params": [[result.hash]],
"id": 9
})
post_data = json.dumps({'method': 'core.pause_torrent',
'params': [[result.hash]],
'id': 9})
self._request(method='post', data=post_data)
return not self.response.json()['error']
return True
api = DelugeAPI()
api = DelugeAPI()

View file

@ -36,8 +36,8 @@ class DownloadStationAPI(GenericClient):
auth_url = self.host + 'webapi/auth.cgi?api=SYNO.API.Auth&version=2&method=login&account=' + self.username + '&passwd=' + self.password + '&session=DownloadStation&format=sid'
try:
self.response = self.session.get(auth_url, verify=False)
self.auth = self.response.json()['data']['sid']
response = self.session.get(auth_url, verify=False)
self.auth = response.json()['data']['sid']
except:
return None
@ -53,9 +53,9 @@ class DownloadStationAPI(GenericClient):
}
if sickbeard.TORRENT_PATH:
data['destination'] = sickbeard.TORRENT_PATH
self._request(method='post', data=data)
response = self._request(method='post', data=data)
return self.response.json()['success']
return response.json()['success']
def _add_torrent_file(self, result):
@ -68,8 +68,8 @@ class DownloadStationAPI(GenericClient):
if sickbeard.TORRENT_PATH:
data['destination'] = sickbeard.TORRENT_PATH
files = {'file':(result.name + '.torrent', result.content)}
self._request(method='post', data=data, files=files)
response = self._request(method='post', data=data, files=files)
return self.response.json()['success']
return response.json()['success']
api = DownloadStationAPI()
api = DownloadStationAPI()

View file

@ -9,7 +9,7 @@ from sickbeard.exceptions import ex
from sickbeard.clients import http_error_code
from lib.bencode import bencode, bdecode
from lib import requests
from lib.requests import exceptions
class GenericClient(object):
def __init__(self, name, host=None, username=None, password=None):
@ -20,34 +20,38 @@ class GenericClient(object):
self.host = sickbeard.TORRENT_HOST if host is None else host
self.url = None
self.response = None
self.auth = None
self.last_time = time.time()
self.session = requests.session()
self.session.auth = (self.username, self.password)
def _request(self, method='get', params={}, data=None, files=None):
response = None
if time.time() > self.last_time + 1800 or not self.auth:
self.last_time = time.time()
self._get_auth()
logger.log(
self.name + u': Requested a ' + method.upper() + ' connection to url ' + self.url + ' with Params= ' + str(
params) + ' Data=' + str(data if data else 'None')[0:99] + (
'...' if len(data if data else 'None') > 200 else ''), logger.DEBUG)
self.name + u': Requested a ' + method.upper() +
' connection to url ' + self.url + ' with Params= ' + str(params) +
' Data=' + str(data if data else 'None')[0:99] +
('...' if len(data if data else 'None') > 200 else ''),
logger.DEBUG
)
logger.log(
self.name + u': Requested a ' + method.upper() + ' connection to url ' + self.url + ' with Params= ' + str(
params) + (
(' Data=' + str(data)[0:100] + ('...' if len(data) > 100 else '')) if data is not None else ""),
logger.DEBUG)
self.name + u': Requested a ' + method.upper() +
' connection to url ' + self.url + ' with Params= ' + str(params) +
((' Data=' + str(data)[0:100] + ('...' if len(data) > 100 else ''))
if data is not None else ''),
logger.DEBUG
)
if not self.auth:
logger.log(self.name + u': Authentication Failed', logger.ERROR)
return False
try:
self.response = self.session.__getattribute__(method)(self.url, params=params, data=data, files=files,
response = self.session.__getattribute__(method)(self.url, params=params, data=data, files=files,
timeout=120, verify=False)
except requests.exceptions.ConnectionError, e:
logger.log(self.name + u': Unable to connect ' + ex(e), logger.ERROR)
@ -66,78 +70,78 @@ class GenericClient(object):
logger.ERROR)
return False
if self.response.status_code == 401:
if response.status_code == 401:
logger.log(self.name + u': Invalid Username or Password, check your config', logger.ERROR)
return False
if self.response.status_code in http_error_code.keys():
logger.log(self.name + u': ' + http_error_code[self.response.status_code], logger.DEBUG)
if response.status_code in http_error_code.keys():
logger.log(self.name + u': ' + http_error_code[response.status_code], logger.DEBUG)
return False
logger.log(self.name + u': Response to ' + method.upper() + ' request is ' + self.response.text, logger.DEBUG)
logger.log(self.name + u': Response to ' + method.upper() + ' request is ' + response.text, logger.DEBUG)
return True
return response
def _get_auth(self):
"""
'''
This should be overridden and should return the auth_id needed for the client
"""
'''
return None
def _add_torrent_uri(self, result):
"""
'''
This should be overridden should return the True/False from the client
when a torrent is added via url (magnet or .torrent link)
"""
'''
return False
def _add_torrent_file(self, result):
"""
'''
This should be overridden should return the True/False from the client
when a torrent is added via result.content (only .torrent file)
"""
'''
return False
def _set_torrent_label(self, result):
"""
'''
This should be overridden should return the True/False from the client
when a torrent is set with label
"""
'''
return True
def _set_torrent_ratio(self, result):
"""
'''
This should be overridden should return the True/False from the client
when a torrent is set with ratio
"""
'''
return True
def _set_torrent_seed_time(self, result):
"""
'''
This should be overridden should return the True/False from the client
when a torrent is set with a seed time
"""
'''
return True
def _set_torrent_priority(self, result):
"""
'''
This should be overriden should return the True/False from the client
when a torrent is set with result.priority (-1 = low, 0 = normal, 1 = high)
"""
'''
return True
def _set_torrent_path(self, torrent_path):
"""
'''
This should be overridden should return the True/False from the client
when a torrent is set with path
"""
'''
return True
def _set_torrent_pause(self, result):
"""
'''
This should be overridden should return the True/False from the client
when a torrent is set with pause
"""
'''
return True
def _get_torrent_hash(self, result):
@ -148,7 +152,7 @@ class GenericClient(object):
result.hash = b16encode(b32decode(result.hash)).lower()
else:
result.content = result.provider.getURL(result.url)
info = bdecode(result.content)["info"]
info = bdecode(result.content)['info']
result.hash = sha1(bencode(info)).hexdigest()
return result
@ -205,20 +209,21 @@ class GenericClient(object):
return r_code
def testAuthentication(self):
response = None
try:
self.response = self.session.get(self.url, timeout=120, verify=False)
except requests.exceptions.ConnectionError, e:
response = self.session.get(self.url, timeout=120, verify=False)
if response.status_code == 401:
return False, 'Error: Invalid ' + self.name + ' Username or Password, check your config!'
except requests.exceptions.ConnectionError:
return False, 'Error: ' + self.name + ' Connection Error'
except (requests.exceptions.MissingSchema, requests.exceptions.InvalidURL):
return False, 'Error: Invalid ' + self.name + ' host'
if self.response.status_code == 401:
return False, 'Error: Invalid ' + self.name + ' Username or Password, check your config!'
try:
self._get_auth()
if self.response.status_code == 200 and self.auth:
authenticated = self._get_auth()
# FIXME: This test is redundant
if authenticated and self.auth:
return True, 'Success: Connected and Authenticated'
else:
return False, 'Error: Unable to get ' + self.name + ' Authentication, check your config!'

View file

@ -37,9 +37,9 @@ class TransmissionAPI(GenericClient):
post_data = json.dumps({'method': 'session-get', })
try:
self.response = self.session.post(self.url, data=post_data.encode('utf-8'), timeout=120,
response = self.session.post(self.url, data=post_data.encode('utf-8'), timeout=120,
verify=sickbeard.TORRENT_VERIFY_CERT)
self.auth = re.search('X-Transmission-Session-Id:\s*(\w+)', self.response.text).group(1)
self.auth = re.search('X-Transmission-Session-Id:\s*(\w+)', response.text).group(1)
except:
return None
@ -62,9 +62,9 @@ class TransmissionAPI(GenericClient):
post_data = json.dumps({'arguments': arguments,
'method': 'torrent-add',
})
self._request(method='post', data=post_data)
response = self._request(method='post', data=post_data)
return self.response.json()['result'] == "success"
return response.json()['result'] == 'success'
def _add_torrent_file(self, result):
@ -75,9 +75,9 @@ class TransmissionAPI(GenericClient):
post_data = json.dumps({'arguments': arguments,
'method': 'torrent-add',
})
self._request(method='post', data=post_data)
response = self._request(method='post', data=post_data)
return self.response.json()['result'] == "success"
return response.json()['result'] == 'success'
def _set_torrent_ratio(self, result):
@ -101,9 +101,9 @@ class TransmissionAPI(GenericClient):
post_data = json.dumps({'arguments': arguments,
'method': 'torrent-set',
})
self._request(method='post', data=post_data)
response = self._request(method='post', data=post_data)
return self.response.json()['result'] == "success"
return response.json()['result'] == 'success'
def _set_torrent_seed_time(self, result):
@ -117,9 +117,9 @@ class TransmissionAPI(GenericClient):
post_data = json.dumps({'arguments': arguments,
'method': 'torrent-set',
})
self._request(method='post', data=post_data)
response = self._request(method='post', data=post_data)
return self.response.json()['result'] == "success"
return response.json()['result'] == 'success'
else:
return True
@ -139,12 +139,14 @@ class TransmissionAPI(GenericClient):
else:
arguments['priority-normal'] = []
post_data = json.dumps({'arguments': arguments,
'method': 'torrent-set',
})
self._request(method='post', data=post_data)
post_data = json.dumps({
'arguments': arguments,
'method': 'torrent-set',
return self.response.json()['result'] == "success"
})
response = self._request(method='post', data=post_data)
return response.json()['result'] == 'success'
api = TransmissionAPI()

View file

@ -42,13 +42,12 @@ class uTorrentAPI(GenericClient):
def _get_auth(self):
try:
self.response = self.session.get(self.url + 'token.html', verify=False)
self.auth = re.findall("<div.*?>(.*?)</", self.response.text)[0]
response = self.session.get(self.url + 'token.html', verify=False)
self.auth = re.findall('<div.*?>(.*?)</', response.text)[0]
return self.auth if not response.status_code == 404 else None
except:
return None
return self.auth if not self.response.status_code == 404 else None
def _add_torrent_uri(self, result):
params = {'action': 'add-url', 's': result.url}
@ -112,15 +111,15 @@ class uTorrentAPI(GenericClient):
else:
return False
else:
return True
return True
def _set_torrent_priority(self, result):
if result.priority == 1:
params = {'action': 'queuetop', 'hash': result.hash}
return self._request(params=params)
else:
return True
return True
def _set_torrent_pause(self, result):
@ -132,4 +131,4 @@ class uTorrentAPI(GenericClient):
return self._request(params=params)
api = uTorrentAPI()
api = uTorrentAPI()