mirror of
https://github.com/SickGear/SickGear.git
synced 2025-01-05 17:43:37 +00:00
Change improve management of Transmission config/Search/Torrent Search "Downloaded files location".
This commit is contained in:
parent
944064d92d
commit
3bc0823670
8 changed files with 129 additions and 135 deletions
|
@ -39,6 +39,7 @@
|
|||
* Fix alternative unicode show names from breaking search
|
||||
* Change show update, set shows with newly added airdate or existing episodes with future or never dates, to "Wanted"
|
||||
* Fix rare NameParser case where numeric episode name was parsed as episode number
|
||||
* Change improve management of Transmission config/Search/Torrent Search "Downloaded files location"
|
||||
|
||||
|
||||
### 0.11.7 (2016-03-06 12:30:00 UTC)
|
||||
|
|
|
@ -489,8 +489,9 @@
|
|||
<span class="component-title" id="directory_title">Downloaded files location</span>
|
||||
<span class="component-desc">
|
||||
<input type="text" name="torrent_path" id="torrent_path" value="$sickbeard.TORRENT_PATH" class="form-control input-sm input350">
|
||||
<p class="clear-left note">where <span id="torrent_client">the torrent client</span> will save downloaded files (blank for client default)
|
||||
<span id="path_synology"> <b>note:</b> the destination has to be a shared folder for Synology DS</span></p>
|
||||
<p class="clear-left note">where <span id="torrent_client">the torrent client</span> will save downloaded files <span id="path_blank">(blank for client default)</span>
|
||||
<span id="path_synology"> <b>note:</b> the destination has to be a shared folder for Synology DS</span>
|
||||
<span id="path_transmission" class="red-text"> (v2.92 and newer <em>cannot</em> be blank)</span></p>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -57,6 +57,8 @@ $(document).ready(function(){
|
|||
torrent_seed_time_option = '#torrent_seed_time_option',
|
||||
torrent_high_bandwidth_option = '#torrent_high_bandwidth_option',
|
||||
torrent_label_option = '#torrent_label_option',
|
||||
path_blank = '#path_blank',
|
||||
path_transmission = '#path_transmission',
|
||||
path_synology = '#path_synology',
|
||||
torrent_paused_option = '#torrent_paused_option';
|
||||
|
||||
|
@ -71,6 +73,8 @@ $(document).ready(function(){
|
|||
$(torrent_seed_time_option).hide();
|
||||
$(torrent_high_bandwidth_option).hide();
|
||||
$(torrent_label_option).show();
|
||||
$(path_blank).show();
|
||||
$(path_transmission).hide();
|
||||
$(path_synology).hide();
|
||||
$(torrent_paused_option).show();
|
||||
|
||||
|
@ -83,6 +87,8 @@ $(document).ready(function(){
|
|||
$(torrent_high_bandwidth_option).show();
|
||||
$(torrent_label_option).hide();
|
||||
//$('#directory_title').text(client + directory);
|
||||
$(path_blank).hide();
|
||||
$(path_transmission).show();
|
||||
} else if ('deluge' == selectedProvider){
|
||||
client = 'Deluge';
|
||||
$(torrent_verify_cert_option).show();
|
||||
|
|
|
@ -25,130 +25,134 @@ class GenericClient(object):
|
|||
self.session = requests.session()
|
||||
self.session.auth = (self.username, self.password)
|
||||
|
||||
def _request(self, method='get', params={}, data=None, files=None):
|
||||
response = None
|
||||
def _request(self, method='get', params=None, data=None, files=None, **kwargs):
|
||||
|
||||
params = params or {}
|
||||
|
||||
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 ''),
|
||||
'%s: Requested a %s connection to url %s with Params= %s' % (self.name, method.upper(), self.url, params) +
|
||||
' Data= ' + ('None' if not data else '%s%s' % (data[0:99], ('', '...')[200 < len(data)])) +
|
||||
' Json= ' + ('None' if not kwargs.get('json') else '%s%s' %
|
||||
(str(kwargs.get('json'))[0:99],
|
||||
('', '...')[200 < len(str(kwargs.get('json')))])),
|
||||
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 ''),
|
||||
'%s: Requested a %s connection to url %s with Params= %s' % (self.name, method.upper(), self.url, params) +
|
||||
('' if not data else ' Data= %s%s' % (data[0:100], ('', '...')[100 < len(data)])) +
|
||||
('' if not kwargs.get('json') else ' Json= %s%s' % (str(kwargs.get('json'))[0:100],
|
||||
('', '...')[100 < len(str(kwargs.get('json')))])),
|
||||
logger.DEBUG
|
||||
)
|
||||
|
||||
if not self.auth:
|
||||
logger.log(self.name + u': Authentication Failed', logger.ERROR)
|
||||
logger.log('%s: Authentication Failed' % self.name, logger.ERROR)
|
||||
return False
|
||||
try:
|
||||
response = self.session.__getattribute__(method)(self.url, params=params, data=data, files=files,
|
||||
timeout=120, verify=False)
|
||||
timeout=120, verify=False, **kwargs)
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
logger.log(self.name + u': Unable to connect ' + ex(e), logger.ERROR)
|
||||
logger.log('%s: Unable to connect %s' % (self.name, ex(e)), logger.ERROR)
|
||||
return False
|
||||
except (requests.exceptions.MissingSchema, requests.exceptions.InvalidURL):
|
||||
logger.log(self.name + u': Invalid Host', logger.ERROR)
|
||||
logger.log('%s: Invalid Host' % self.name, logger.ERROR)
|
||||
return False
|
||||
except requests.exceptions.HTTPError as e:
|
||||
logger.log(self.name + u': Invalid HTTP Request ' + ex(e), logger.ERROR)
|
||||
logger.log('%s: Invalid HTTP Request %s' % (self.name, ex(e)), logger.ERROR)
|
||||
return False
|
||||
except requests.exceptions.Timeout as e:
|
||||
logger.log(self.name + u': Connection Timeout ' + ex(e), logger.ERROR)
|
||||
logger.log('%s: Connection Timeout %s' % (self.name, ex(e)), logger.ERROR)
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.log(self.name + u': Unknown exception raised when sending torrent to ' + self.name + ': ' + ex(e),
|
||||
logger.log('%s: Unknown exception raised when sending torrent to %s: %s' % (self.name, self.name, ex(e)),
|
||||
logger.ERROR)
|
||||
return False
|
||||
|
||||
if response.status_code == 401:
|
||||
logger.log(self.name + u': Invalid Username or Password, check your config', logger.ERROR)
|
||||
if 401 == response.status_code:
|
||||
logger.log('%s: Invalid Username or Password, check your config' % self.name, logger.ERROR)
|
||||
return False
|
||||
|
||||
if response.status_code in http_error_code.keys():
|
||||
logger.log(self.name + u': ' + http_error_code[response.status_code], logger.DEBUG)
|
||||
logger.log('%s: %s' % (self.name, http_error_code[response.status_code]), logger.DEBUG)
|
||||
return False
|
||||
|
||||
logger.log(self.name + u': Response to ' + method.upper() + ' request is ' + response.text, logger.DEBUG)
|
||||
logger.log('%s: Response to %s request is %s' % (self.name, method.upper(), response.text), logger.DEBUG)
|
||||
|
||||
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):
|
||||
@staticmethod
|
||||
def _get_torrent_hash(result):
|
||||
|
||||
if result.url.startswith('magnet'):
|
||||
result.hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0]
|
||||
if len(result.hash) == 32:
|
||||
if 32 == len(result.hash):
|
||||
result.hash = b16encode(b32decode(result.hash)).lower()
|
||||
else:
|
||||
info = bdecode(result.content)['info']
|
||||
|
@ -156,14 +160,14 @@ class GenericClient(object):
|
|||
|
||||
return result
|
||||
|
||||
def sendTORRENT(self, result):
|
||||
def send_torrent(self, result):
|
||||
|
||||
r_code = False
|
||||
|
||||
logger.log(u'Calling ' + self.name + ' Client', logger.DEBUG)
|
||||
logger.log('Calling %s Client' % self.name, logger.DEBUG)
|
||||
|
||||
if not self._get_auth():
|
||||
logger.log(self.name + u': Authentication Failed', logger.ERROR)
|
||||
logger.log('%s: Authentication Failed' % self.name, logger.ERROR)
|
||||
return r_code
|
||||
|
||||
try:
|
||||
|
@ -178,52 +182,51 @@ class GenericClient(object):
|
|||
r_code = self._add_torrent_file(result)
|
||||
|
||||
if not r_code:
|
||||
logger.log(self.name + u': Unable to send Torrent: Return code undefined', logger.ERROR)
|
||||
logger.log('%s: Unable to send Torrent: Return code undefined' % self.name, logger.ERROR)
|
||||
return False
|
||||
|
||||
if not self._set_torrent_pause(result):
|
||||
logger.log(self.name + u': Unable to set the pause for Torrent', logger.ERROR)
|
||||
logger.log('%s: Unable to set the pause for Torrent' % self.name, logger.ERROR)
|
||||
|
||||
if not self._set_torrent_label(result):
|
||||
logger.log(self.name + u': Unable to set the label for Torrent', logger.ERROR)
|
||||
logger.log('%s: Unable to set the label for Torrent' % self.name, logger.ERROR)
|
||||
|
||||
if not self._set_torrent_ratio(result):
|
||||
logger.log(self.name + u': Unable to set the ratio for Torrent', logger.ERROR)
|
||||
logger.log('%s: Unable to set the ratio for Torrent' % self.name, logger.ERROR)
|
||||
|
||||
if not self._set_torrent_seed_time(result):
|
||||
logger.log(self.name + u': Unable to set the seed time for Torrent', logger.ERROR)
|
||||
logger.log('%s: Unable to set the seed time for Torrent' % self.name, logger.ERROR)
|
||||
|
||||
if not self._set_torrent_path(result):
|
||||
logger.log(self.name + u': Unable to set the path for Torrent', logger.ERROR)
|
||||
logger.log('%s: Unable to set the path for Torrent' % self.name, 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)
|
||||
if 0 != result.priority and not self._set_torrent_priority(result):
|
||||
logger.log('%s: Unable to set priority for Torrent' % self.name, logger.ERROR)
|
||||
|
||||
except Exception as e:
|
||||
logger.log(self.name + u': Failed Sending Torrent: ' + result.name + ' - ' + result.hash, logger.ERROR)
|
||||
logger.log(self.name + u': Exception raised when sending torrent: ' + ex(e), logger.DEBUG)
|
||||
logger.log('%s: Failed sending torrent: %s - %s' % (self.name, result.name, result.hash), logger.ERROR)
|
||||
logger.log('%s: Exception raised when sending torrent: %s' % (self.name, ex(e)), logger.DEBUG)
|
||||
return r_code
|
||||
|
||||
return r_code
|
||||
|
||||
def testAuthentication(self):
|
||||
response = None
|
||||
def test_authentication(self):
|
||||
|
||||
try:
|
||||
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!'
|
||||
if 401 == response.status_code:
|
||||
return False, 'Error: Invalid %s Username or Password, check your config!' % self.name
|
||||
except requests.exceptions.ConnectionError:
|
||||
return False, 'Error: ' + self.name + ' Connection Error'
|
||||
return False, 'Error: %s Connection Error' % self.name
|
||||
except (requests.exceptions.MissingSchema, requests.exceptions.InvalidURL):
|
||||
return False, 'Error: Invalid ' + self.name + ' host'
|
||||
return False, 'Error: Invalid %s host' % self.name
|
||||
|
||||
try:
|
||||
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!'
|
||||
return False, 'Error: Unable to get %s Authentication, check your config!' % self.name
|
||||
except Exception:
|
||||
return False, 'Error: Unable to connect to ' + self.name
|
||||
return False, 'Error: Unable to connect to %s' % self.name
|
||||
|
|
|
@ -145,7 +145,7 @@ class rTorrentAPI(GenericClient):
|
|||
|
||||
return True
|
||||
|
||||
def testAuthentication(self):
|
||||
def test_authentication(self):
|
||||
try:
|
||||
self._get_auth()
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import re
|
||||
import json
|
||||
from base64 import b64encode
|
||||
|
||||
import sickbeard
|
||||
|
@ -31,93 +30,82 @@ class TransmissionAPI(GenericClient):
|
|||
super(TransmissionAPI, self).__init__('Transmission', host, username, password)
|
||||
|
||||
self.url = self.host + 'transmission/rpc'
|
||||
self.blankable, self.download_dir = None, None
|
||||
|
||||
def _get_auth(self):
|
||||
|
||||
post_data = json.dumps({'method': 'session-get', })
|
||||
|
||||
try:
|
||||
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+)', response.text).group(1)
|
||||
response = self.session.post(self.url, json={'method': 'session-get'},
|
||||
timeout=120, verify=sickbeard.TORRENT_VERIFY_CERT)
|
||||
self.auth = re.search(r'(?i)X-Transmission-Session-Id:\s*(\w+)', response.text).group(1)
|
||||
except:
|
||||
return None
|
||||
|
||||
self.session.headers.update({'x-transmission-session-id': self.auth})
|
||||
|
||||
#Validating Transmission authorization
|
||||
post_data = json.dumps({'arguments': {},
|
||||
'method': 'session-get',
|
||||
})
|
||||
self._request(method='post', data=post_data)
|
||||
# Validating Transmission authorization
|
||||
response = self._request(method='post', json={'method': 'session-get', 'arguments': {}})
|
||||
|
||||
try:
|
||||
resp = response.json()
|
||||
self.blankable = 14386 >= int(re.findall(r'.*[(](\d+)', resp.get('arguments', {}).get('version', '(0)'))[0])
|
||||
self.download_dir = resp.get('arguments', {}).get('download-dir', '')
|
||||
except:
|
||||
pass
|
||||
|
||||
return self.auth
|
||||
|
||||
def _add_torrent_uri(self, result):
|
||||
|
||||
arguments = {'filename': result.url,
|
||||
'paused': 1 if sickbeard.TORRENT_PAUSED else 0,
|
||||
'download-dir': sickbeard.TORRENT_PATH
|
||||
}
|
||||
post_data = json.dumps({'arguments': arguments,
|
||||
'method': 'torrent-add',
|
||||
})
|
||||
response = self._request(method='post', data=post_data)
|
||||
|
||||
return response.json()['result'] == 'success'
|
||||
return self._add_torrent({'filename': result.url})
|
||||
|
||||
def _add_torrent_file(self, result):
|
||||
|
||||
arguments = {'metainfo': b64encode(result.content),
|
||||
'paused': 1 if sickbeard.TORRENT_PAUSED else 0,
|
||||
'download-dir': sickbeard.TORRENT_PATH
|
||||
}
|
||||
post_data = json.dumps({'arguments': arguments,
|
||||
'method': 'torrent-add',
|
||||
})
|
||||
response = self._request(method='post', data=post_data)
|
||||
return self._add_torrent({'metainfo': b64encode(result.content)})
|
||||
|
||||
return response.json()['result'] == 'success'
|
||||
def _add_torrent(self, t_object):
|
||||
|
||||
download_dir = None
|
||||
if sickbeard.TORRENT_PATH or self.blankable:
|
||||
download_dir = sickbeard.TORRENT_PATH
|
||||
elif self.download_dir:
|
||||
download_dir = self.download_dir
|
||||
else:
|
||||
logger.log('Path required for Transmission Downloaded files location', logger.ERROR)
|
||||
|
||||
if not download_dir and not self.blankable:
|
||||
return False
|
||||
|
||||
t_object.update({'paused': (0, 1)[sickbeard.TORRENT_PAUSED], 'download-dir': download_dir})
|
||||
response = self._request(method='post', json={'method': 'torrent-add', 'arguments': t_object})
|
||||
|
||||
return 'success' == response.json().get('result', '')
|
||||
|
||||
def _set_torrent_ratio(self, result):
|
||||
|
||||
ratio = None
|
||||
if result.ratio:
|
||||
ratio = result.ratio
|
||||
|
||||
mode = 0
|
||||
ratio, mode = (result.ratio, None)[not result.ratio], 0
|
||||
if ratio:
|
||||
if float(ratio) == -1:
|
||||
ratio = 0
|
||||
mode = 2
|
||||
elif float(ratio) >= 0:
|
||||
ratio = float(ratio)
|
||||
mode = 1 # Stop seeding at seedRatioLimit
|
||||
if -1 == float(ratio):
|
||||
ratio, mode = 0, 2
|
||||
elif 0 <= float(ratio):
|
||||
ratio, mode = float(ratio), 1 # Stop seeding at seedRatioLimit
|
||||
|
||||
arguments = {'ids': [result.hash],
|
||||
'seedRatioLimit': ratio,
|
||||
'seedRatioMode': mode
|
||||
}
|
||||
post_data = json.dumps({'arguments': arguments,
|
||||
'method': 'torrent-set',
|
||||
})
|
||||
response = self._request(method='post', data=post_data)
|
||||
response = self._request(method='post', json={
|
||||
'method': 'torrent-set',
|
||||
'arguments': {'ids': [result.hash], 'seedRatioLimit': ratio, 'seedRatioMode': mode}})
|
||||
|
||||
return response.json()['result'] == 'success'
|
||||
return 'success' == response.json().get('result', '')
|
||||
|
||||
def _set_torrent_seed_time(self, result):
|
||||
|
||||
if result.provider.seed_time or (sickbeard.TORRENT_SEED_TIME and sickbeard.TORRENT_SEED_TIME != -1):
|
||||
if result.provider.seed_time or (sickbeard.TORRENT_SEED_TIME and -1 != sickbeard.TORRENT_SEED_TIME):
|
||||
seed_time = result.provider.seed_time or sickbeard.TORRENT_SEED_TIME
|
||||
arguments = {'ids': [result.hash],
|
||||
'seedIdleLimit': int(seed_time) * 60,
|
||||
'seedIdleMode': 1}
|
||||
|
||||
post_data = json.dumps({'arguments': arguments,
|
||||
'method': 'torrent-set'})
|
||||
response = self._request(method='post', data=post_data)
|
||||
response = self._request(method='post', json={
|
||||
'method': 'torrent-set',
|
||||
'arguments': {'ids': [result.hash], 'seedIdleLimit': int(seed_time) * 60, 'seedIdleMode': 1}})
|
||||
|
||||
return response.json()['result'] == 'success'
|
||||
return 'success' == response.json().get('result', '')
|
||||
else:
|
||||
return True
|
||||
|
||||
|
@ -125,9 +113,9 @@ class TransmissionAPI(GenericClient):
|
|||
|
||||
arguments = {'ids': [result.hash]}
|
||||
|
||||
if result.priority == -1:
|
||||
if -1 == result.priority:
|
||||
arguments['priority-low'] = []
|
||||
elif result.priority == 1:
|
||||
elif 1 == result.priority:
|
||||
# set high priority for all files in torrent
|
||||
arguments['priority-high'] = []
|
||||
# move torrent to the top if the queue
|
||||
|
@ -137,14 +125,9 @@ class TransmissionAPI(GenericClient):
|
|||
else:
|
||||
arguments['priority-normal'] = []
|
||||
|
||||
post_data = json.dumps({
|
||||
'arguments': arguments,
|
||||
'method': 'torrent-set',
|
||||
response = self._request(method='post', json={'method': 'torrent-set', 'arguments': arguments})
|
||||
|
||||
})
|
||||
response = self._request(method='post', data=post_data)
|
||||
|
||||
return response.json()['result'] == 'success'
|
||||
return 'success' == response.json().get('result', '')
|
||||
|
||||
|
||||
api = TransmissionAPI()
|
||||
|
|
|
@ -139,7 +139,7 @@ def snatch_episode(result, end_status=SNATCHED):
|
|||
return False
|
||||
# Snatches torrent with client
|
||||
client = clients.getClientIstance(sickbeard.TORRENT_METHOD)()
|
||||
dl_result = client.sendTORRENT(result)
|
||||
dl_result = client.send_torrent(result)
|
||||
else:
|
||||
logger.log(u'Unknown result type, unable to download it', logger.ERROR)
|
||||
dl_result = False
|
||||
|
|
|
@ -676,7 +676,7 @@ class Home(MainHandler):
|
|||
|
||||
client = clients.getClientIstance(torrent_method)
|
||||
|
||||
connection, accesMsg = client(host, username, password).testAuthentication()
|
||||
connection, accesMsg = client(host, username, password).test_authentication()
|
||||
|
||||
return accesMsg
|
||||
|
||||
|
|
Loading…
Reference in a new issue