2014-03-10 05:18:05 +00:00
|
|
|
import re
|
|
|
|
import time
|
|
|
|
from hashlib import sha1
|
|
|
|
from base64 import b16encode, b32decode
|
|
|
|
|
|
|
|
import sickbeard
|
|
|
|
from sickbeard import logger
|
|
|
|
from sickbeard.exceptions import ex
|
|
|
|
from sickbeard.clients import http_error_code
|
|
|
|
from lib.bencode import bencode, bdecode
|
|
|
|
from lib import requests
|
2014-04-02 05:44:47 +00:00
|
|
|
from lib.requests import exceptions
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
class GenericClient(object):
|
|
|
|
def __init__(self, name, host=None, username=None, password=None):
|
|
|
|
|
|
|
|
self.name = name
|
|
|
|
self.username = sickbeard.TORRENT_USERNAME if username is None else username
|
|
|
|
self.password = sickbeard.TORRENT_PASSWORD if password is None else password
|
|
|
|
self.host = sickbeard.TORRENT_HOST if host is None else host
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
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)
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-20 18:03:22 +00:00
|
|
|
def _request(self, method='get', params={}, data=None, files=None):
|
2014-03-10 05:18:05 +00:00
|
|
|
|
|
|
|
if time.time() > self.last_time + 1800 or not self.auth:
|
|
|
|
self.last_time = time.time()
|
|
|
|
self._get_auth()
|
2014-03-25 05:57:24 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2014-04-26 07:09:00 +00:00
|
|
|
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)
|
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
if not self.auth:
|
2014-03-25 05:57:24 +00:00
|
|
|
logger.log(self.name + u': Authentication Failed', logger.ERROR)
|
2014-03-10 05:18:05 +00:00
|
|
|
return False
|
|
|
|
try:
|
2014-03-25 05:57:24 +00:00
|
|
|
self.response = self.session.__getattribute__(method)(self.url, params=params, data=data, files=files,
|
2014-05-01 08:17:00 +00:00
|
|
|
timeout=20, verify=False)
|
2014-03-10 05:18:05 +00:00
|
|
|
except requests.exceptions.ConnectionError, e:
|
|
|
|
logger.log(self.name + u': Unable to connect ' + ex(e), logger.ERROR)
|
|
|
|
return False
|
|
|
|
except (requests.exceptions.MissingSchema, requests.exceptions.InvalidURL):
|
|
|
|
logger.log(self.name + u': Invalid Host', logger.ERROR)
|
|
|
|
return False
|
|
|
|
except requests.exceptions.HTTPError, e:
|
|
|
|
logger.log(self.name + u': Invalid HTTP Request ' + ex(e), logger.ERROR)
|
|
|
|
return False
|
|
|
|
except requests.exceptions.Timeout, e:
|
|
|
|
logger.log(self.name + u': Connection Timeout ' + ex(e), logger.ERROR)
|
|
|
|
return False
|
|
|
|
except Exception, e:
|
2014-03-25 05:57:24 +00:00
|
|
|
logger.log(self.name + u': Unknown exception raised when send torrent to ' + self.name + ': ' + ex(e),
|
|
|
|
logger.ERROR)
|
2014-03-10 05:18:05 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
if self.response.status_code == 401:
|
2014-03-25 05:57:24 +00:00
|
|
|
logger.log(self.name + u': Invalid Username or Password, check your config', logger.ERROR)
|
2014-03-10 05:18:05 +00:00
|
|
|
return False
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
if self.response.status_code in http_error_code.keys():
|
|
|
|
logger.log(self.name + u': ' + http_error_code[self.response.status_code], logger.DEBUG)
|
|
|
|
return False
|
2014-03-25 05:57:24 +00:00
|
|
|
|
|
|
|
logger.log(self.name + u': Response to ' + method.upper() + ' request is ' + self.response.text, logger.DEBUG)
|
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
def _get_auth(self):
|
|
|
|
"""
|
|
|
|
This should be overridden and should return the auth_id needed for the client
|
|
|
|
"""
|
|
|
|
return None
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
def _add_torrent_uri(self, result):
|
|
|
|
"""
|
2014-04-26 07:09:00 +00:00
|
|
|
This should be overridden should return the True/False from the client
|
2014-03-10 05:18:05 +00:00
|
|
|
when a torrent is added via url (magnet or .torrent link)
|
|
|
|
"""
|
2014-03-25 05:57:24 +00:00
|
|
|
return False
|
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
def _add_torrent_file(self, result):
|
|
|
|
"""
|
2014-04-26 07:09:00 +00:00
|
|
|
This should be overridden should return the True/False from the client
|
2014-03-10 05:18:05 +00:00
|
|
|
when a torrent is added via result.content (only .torrent file)
|
|
|
|
"""
|
2014-03-25 05:57:24 +00:00
|
|
|
return False
|
2014-03-10 05:18:05 +00:00
|
|
|
|
|
|
|
def _set_torrent_label(self, result):
|
|
|
|
"""
|
2014-04-26 07:09:00 +00:00
|
|
|
This should be overridden should return the True/False from the client
|
2014-03-10 05:18:05 +00:00
|
|
|
when a torrent is set with label
|
|
|
|
"""
|
|
|
|
return True
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
def _set_torrent_ratio(self, result):
|
|
|
|
"""
|
2014-04-26 07:09:00 +00:00
|
|
|
This should be overridden should return the True/False from the client
|
2014-03-10 05:18:05 +00:00
|
|
|
when a torrent is set with ratio
|
|
|
|
"""
|
|
|
|
return True
|
|
|
|
|
2014-04-28 14:34:27 +00:00
|
|
|
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
|
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
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):
|
|
|
|
"""
|
2014-04-26 07:09:00 +00:00
|
|
|
This should be overridden should return the True/False from the client
|
2014-03-10 05:18:05 +00:00
|
|
|
when a torrent is set with path
|
2014-03-25 05:57:24 +00:00
|
|
|
"""
|
2014-03-10 05:18:05 +00:00
|
|
|
return True
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
def _set_torrent_pause(self, result):
|
|
|
|
"""
|
2014-04-26 07:09:00 +00:00
|
|
|
This should be overridden should return the True/False from the client
|
2014-03-10 05:18:05 +00:00
|
|
|
when a torrent is set with pause
|
|
|
|
"""
|
|
|
|
return True
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
def _get_torrent_hash(self, result):
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
if result.url.startswith('magnet'):
|
2014-07-28 19:19:41 +00:00
|
|
|
result.hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0]
|
|
|
|
if len(result.hash) == 32:
|
|
|
|
result.hash = b16encode(b32decode(result.hash)).lower()
|
|
|
|
else:
|
|
|
|
result.content = result.provider.getURL(result.url)
|
2014-08-18 02:14:07 +00:00
|
|
|
info = bdecode(result.content)["info"]
|
|
|
|
result.hash = sha1(bencode(info)).hexdigest()
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2014-07-28 19:19:41 +00:00
|
|
|
return result
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
def sendTORRENT(self, result):
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
r_code = False
|
|
|
|
|
|
|
|
logger.log(u'Calling ' + self.name + ' Client', logger.DEBUG)
|
|
|
|
|
|
|
|
if not self._get_auth():
|
2014-03-25 05:57:24 +00:00
|
|
|
logger.log(self.name + u': Authentication Failed', logger.ERROR)
|
2014-03-10 05:18:05 +00:00
|
|
|
return r_code
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
try:
|
2014-07-28 19:19:41 +00:00
|
|
|
# Sets per provider seed ratio
|
|
|
|
result.ratio = result.provider.seedRatio()
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
if result.url.startswith('magnet'):
|
|
|
|
r_code = self._add_torrent_uri(result)
|
|
|
|
else:
|
|
|
|
r_code = self._add_torrent_file(result)
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
if not r_code:
|
2014-05-02 12:50:28 +00:00
|
|
|
logger.log(self.name + u': Unable to send Torrent: Return code undefined', logger.ERROR)
|
2014-03-10 05:18:05 +00:00
|
|
|
return False
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
if not self._set_torrent_pause(result):
|
|
|
|
logger.log(self.name + u': Unable to set the pause for Torrent', logger.ERROR)
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
if not self._set_torrent_label(result):
|
|
|
|
logger.log(self.name + u': Unable to set the label for Torrent', logger.ERROR)
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
if not self._set_torrent_ratio(result):
|
|
|
|
logger.log(self.name + u': Unable to set the ratio for Torrent', logger.ERROR)
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-04-28 14:34:27 +00:00
|
|
|
if not self._set_torrent_seed_time(result):
|
|
|
|
logger.log(self.name + u': Unable to set the seed time for Torrent', logger.ERROR)
|
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
if not self._set_torrent_path(result):
|
|
|
|
logger.log(self.name + u': Unable to set the path for Torrent', logger.ERROR)
|
|
|
|
|
|
|
|
if result.priority != 0 and not self._set_torrent_priority(result):
|
|
|
|
logger.log(self.name + u': Unable to set priority for Torrent', logger.ERROR)
|
|
|
|
|
|
|
|
except Exception, e:
|
|
|
|
logger.log(self.name + u': Failed Sending Torrent ', logger.ERROR)
|
|
|
|
logger.log(self.name + u': Exception raised when sending torrent: ' + ex(e), logger.DEBUG)
|
|
|
|
return r_code
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
return r_code
|
|
|
|
|
|
|
|
def testAuthentication(self):
|
|
|
|
|
|
|
|
try:
|
|
|
|
self.response = self.session.get(self.url, timeout=20, verify=False)
|
|
|
|
except requests.exceptions.ConnectionError, e:
|
|
|
|
return False, 'Error: ' + self.name + ' Connection Error'
|
|
|
|
except (requests.exceptions.MissingSchema, requests.exceptions.InvalidURL):
|
2014-03-25 05:57:24 +00:00
|
|
|
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:
|
|
|
|
return True, 'Success: Connected and Authenticated'
|
|
|
|
else:
|
|
|
|
return False, 'Error: Unable to get ' + self.name + ' Authentication, check your config!'
|
|
|
|
except Exception:
|
|
|
|
return False, 'Error: Unable to connect to ' + self.name
|