From 964ed5f497cc62a9ba043bea8e098b76dea1af3d Mon Sep 17 00:00:00 2001 From: mikke89 Date: Mon, 20 Jan 2014 22:09:03 +0100 Subject: [PATCH 01/15] Added test connection button for uTorrent --- couchpotato/core/_base/clientscript/main.py | 1 + couchpotato/core/downloaders/base.py | 13 +++ couchpotato/core/downloaders/utorrent/main.py | 7 ++ .../static/scripts/misc/downloaders.js | 80 +++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 couchpotato/static/scripts/misc/downloaders.js diff --git a/couchpotato/core/_base/clientscript/main.py b/couchpotato/core/_base/clientscript/main.py index 248d2bc5..c1be7e73 100644 --- a/couchpotato/core/_base/clientscript/main.py +++ b/couchpotato/core/_base/clientscript/main.py @@ -49,6 +49,7 @@ class ClientScript(Plugin): 'scripts/page/settings.js', 'scripts/page/about.js', 'scripts/page/manage.js', + 'scripts/misc/downloaders.js', ], } diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index 71da65ee..fa274922 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -1,4 +1,5 @@ from base64 import b32decode, b16encode +from couchpotato.api import addApiView from couchpotato.core.event import addEvent from couchpotato.core.helpers.variable import mergeDicts from couchpotato.core.logger import CPLog @@ -14,6 +15,7 @@ class Downloader(Provider): protocol = [] http_time_between_calls = 0 status_support = True + testable = False torrent_sources = [ 'http://torrage.com/torrent/%s.torrent', @@ -42,6 +44,8 @@ class Downloader(Provider): addEvent('download.remove_failed', self._removeFailed) addEvent('download.pause', self._pause) addEvent('download.process_complete', self._processComplete) + addApiView('download.%s.is_testable' % self.getName().lower(), self.isTestable) + addApiView('download.%s.test' % self.getName().lower(), self._test) def getEnabledProtocol(self): for download_protocol in self.protocol: @@ -158,6 +162,15 @@ class Downloader(Provider): (d_manual and manual or d_manual is False) and \ (not data or self.isCorrectProtocol(data.get('protocol'))) + def isTestable(self): + return {'success': self.testable} + + def _test(self): + return {'success': self.test()} + + def test(self): + return False + def _pause(self, release_download, pause = True): if self.isDisabled(manual = True, data = {}): return diff --git a/couchpotato/core/downloaders/utorrent/main.py b/couchpotato/core/downloaders/utorrent/main.py index e527230c..6e3e4df3 100644 --- a/couchpotato/core/downloaders/utorrent/main.py +++ b/couchpotato/core/downloaders/utorrent/main.py @@ -1,5 +1,6 @@ from base64 import b16encode, b32decode from bencode import bencode as benc, bdecode +from couchpotato.api import addApiView from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList from couchpotato.core.helpers.encoding import isInt, ss, sp from couchpotato.core.helpers.variable import tryInt, tryFloat, cleanHost @@ -24,6 +25,7 @@ class uTorrent(Downloader): protocol = ['torrent', 'torrent_magnet'] utorrent_api = None + testable = True status_flags = { 'STARTED' : 1, 'CHECKING' : 2, @@ -46,6 +48,11 @@ class uTorrent(Downloader): return self.utorrent_api + def test(self): + if self.connect() and self.utorrent_api.get_status(): + return True + return False + def download(self, data = None, media = None, filedata = None): if not media: media = {} if not data: data = {} diff --git a/couchpotato/static/scripts/misc/downloaders.js b/couchpotato/static/scripts/misc/downloaders.js new file mode 100644 index 00000000..eee45b40 --- /dev/null +++ b/couchpotato/static/scripts/misc/downloaders.js @@ -0,0 +1,80 @@ +var DownloadersBase = new Class({ + + Implements: [Events], + + initialize: function(){ + var self = this; + + // Add test buttons to settings page + App.addEvent('load', self.addTestButtons.bind(self)); + + }, + + // Downloaders setting tests + addTestButtons: function(){ + var self = this; + + var setting_page = App.getPage('Settings'); + setting_page.addEvent('create', function(){ + Object.each(setting_page.tabs.downloaders.groups, self.addTestButton.bind(self)) + }) + + }, + + addTestButton: function(fieldset, plugin_name){ + var self = this, + button_name = self.testButtonName(fieldset); + + if(button_name.contains('Downloaders')) return; + + Api.request('download.'+plugin_name+'.is_testable', { + 'onComplete': function(json){ + if(json.success){ + // Only add test button if downloader is testable + new Element('.ctrlHolder.test_button').adopt( + new Element('a.button', { + 'text': button_name, + 'events': { + 'click': function(){ + var button = fieldset.getElement('.test_button .button'); + button.set('text', 'Connecting...'); + + Api.request('download.'+plugin_name+'.test', { + 'onComplete': function(json){ + + button.set('text', button_name); + + if(json.success){ + var message = new Element('span.success', { + 'text': 'Connection successful' + }).inject(button, 'after') + } + else { + var message = new Element('span.failed', { + 'text': 'Connection failed. Check logs for details.' + }).inject(button, 'after') + } + + (function(){ + message.destroy(); + }).delay(3000) + } + }); + } + } + }) + ).inject(fieldset); + } + } + }); + + }, + + testButtonName: function(fieldset){ + var name = String(fieldset.getElement('h2').innerHTML).substring(0,String(fieldset.getElement('h2').innerHTML).indexOf(" Date: Tue, 21 Jan 2014 00:24:36 +0100 Subject: [PATCH 02/15] Added connection test to the rest of downloaders --- couchpotato/core/downloaders/deluge/main.py | 15 ++++++++++++- couchpotato/core/downloaders/nzbget/main.py | 22 +++++++++++++++++++ .../core/downloaders/nzbvortex/main.py | 9 ++++++++ couchpotato/core/downloaders/rtorrent/main.py | 13 +++++++++-- couchpotato/core/downloaders/sabnzbd/main.py | 11 ++++++++++ couchpotato/core/downloaders/synology/main.py | 14 ++++++++++++ .../core/downloaders/transmission/main.py | 8 ++++++- libs/rtorrent/__init__.py | 7 ++++++ 8 files changed, 95 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/downloaders/deluge/main.py b/couchpotato/core/downloaders/deluge/main.py index 53b87d91..4fe23aa2 100644 --- a/couchpotato/core/downloaders/deluge/main.py +++ b/couchpotato/core/downloaders/deluge/main.py @@ -19,6 +19,7 @@ class Deluge(Downloader): protocol = ['torrent', 'torrent_magnet'] log = CPLog(__name__) drpc = None + testable = True def connect(self): # Load host from config and split out port. @@ -27,11 +28,16 @@ class Deluge(Downloader): log.error('Config properties are not filled in correctly, port is missing.') return False - if not self.drpc: + if not (self.drpc and self.drpc.test()): self.drpc = DelugeRPC(host[0], port = host[1], username = self.conf('username'), password = self.conf('password')) return self.drpc + def test(self): + if self.connect() and self.drpc.test(): + return True + return False + def download(self, data = None, media = None, filedata = None): if not media: media = {} if not data: data = {} @@ -178,6 +184,13 @@ class DelugeRPC(object): self.client = DelugeClient() self.client.connect(self.host, int(self.port), self.username, self.password) + def test(self): + try: + self.connect() + except: + return False + return True + def add_torrent_magnet(self, torrent, options): torrent_id = False try: diff --git a/couchpotato/core/downloaders/nzbget/main.py b/couchpotato/core/downloaders/nzbget/main.py index a690572c..8b9c88d1 100644 --- a/couchpotato/core/downloaders/nzbget/main.py +++ b/couchpotato/core/downloaders/nzbget/main.py @@ -18,6 +18,28 @@ class NZBGet(Downloader): protocol = ['nzb'] rpc = 'xmlrpc' + testable = True + + def test(self): + url = cleanHost(host = self.conf('host'), ssl = self.conf('ssl'), username = self.conf('username'), password = self.conf('password')) + self.rpc + rpc = xmlrpclib.ServerProxy(url) + + try: + if rpc.writelog('INFO', 'CouchPotato connected to test connection'): + log.debug('Successfully connected to NZBGet') + else: + log.info('Successfully connected to NZBGet, but unable to send a message') + except socket.error: + log.error('NZBGet is not responding. Please ensure that NZBGet is running and host setting is correct.') + return False + except xmlrpclib.ProtocolError as e: + if e.errcode == 401: + log.error('Password is incorrect.') + else: + log.error('Protocol Error: %s', e) + return False + + return True def download(self, data = None, media = None, filedata = None): if not media: media = {} diff --git a/couchpotato/core/downloaders/nzbvortex/main.py b/couchpotato/core/downloaders/nzbvortex/main.py index 205ceb1b..048aa44d 100644 --- a/couchpotato/core/downloaders/nzbvortex/main.py +++ b/couchpotato/core/downloaders/nzbvortex/main.py @@ -24,6 +24,15 @@ class NZBVortex(Downloader): protocol = ['nzb'] api_level = None session_id = None + testable = True + + def test(self): + try: + login_result = self.login() + except: + return False + + return login_result def download(self, data = None, media = None, filedata = None): if not media: media = {} diff --git a/couchpotato/core/downloaders/rtorrent/main.py b/couchpotato/core/downloaders/rtorrent/main.py index f934de5f..a35cb006 100755 --- a/couchpotato/core/downloaders/rtorrent/main.py +++ b/couchpotato/core/downloaders/rtorrent/main.py @@ -18,6 +18,7 @@ class rTorrent(Downloader): protocol = ['torrent', 'torrent_magnet'] rt = None + testable = True # Migration url to host options def __init__(self): @@ -37,9 +38,9 @@ class rTorrent(Downloader): self.deleteConf('url') - def connect(self): + def connect(self, reconnect = False): # Already connected? - if self.rt is not None: + if not reconnect and self.rt is not None: return self.rt url = cleanHost(self.conf('host'), protocol = True, ssl = self.conf('ssl')) + '/' + self.conf('rpc_url').strip('/ ') + '/' @@ -53,8 +54,16 @@ class rTorrent(Downloader): else: self.rt = RTorrent(url) + if not self.rt.test_connection(): + self.rt = None + return self.rt + def test(self): + if not self.connect(True): + return False + return True + def _update_provider_group(self, name, data): if data.get('seed_time'): log.info('seeding time ignored, not supported') diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index 72c23708..a21aee0e 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -15,6 +15,17 @@ log = CPLog(__name__) class Sabnzbd(Downloader): protocol = ['nzb'] + testable = True + + def test(self): + try: + queue = self.call({ + 'mode': 'version', + }) + except: + return False + + return bool(queue) def download(self, data = None, media = None, filedata = None): if not media: media = {} diff --git a/couchpotato/core/downloaders/synology/main.py b/couchpotato/core/downloaders/synology/main.py index 26a4558d..2ffbb8d8 100644 --- a/couchpotato/core/downloaders/synology/main.py +++ b/couchpotato/core/downloaders/synology/main.py @@ -13,6 +13,17 @@ class Synology(Downloader): protocol = ['nzb', 'torrent', 'torrent_magnet'] status_support = False + testable = True + + def test(self): + host = cleanHost(self.conf('host'), protocol = False).split(':') + try: + srpc = SynologyRPC(host[0], host[1], self.conf('username'), self.conf('password')) + test_result = srpc.test() + except: + return False + + return test_result def download(self, data = None, media = None, filedata = None): if not media: media = {} @@ -147,3 +158,6 @@ class SynologyRPC(object): self._logout() return result + + def test(self): + return bool(self._login()) diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index d3f17598..5e952306 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -18,6 +18,7 @@ class Transmission(Downloader): protocol = ['torrent', 'torrent_magnet'] log = CPLog(__name__) trpc = None + testable = True def connect(self): # Load host from config and split out port. @@ -26,11 +27,16 @@ class Transmission(Downloader): log.error('Config properties are not filled in correctly, port is missing.') return False - if not self.trpc: + if not (self.trpc and self.trpc.get_session()): self.trpc = TransmissionRPC(host[0], port = host[1], rpc_url = self.conf('rpc_url').strip('/ '), username = self.conf('username'), password = self.conf('password')) return self.trpc + def test(self): + if self.connect() and self.trpc.get_session(): + return True + return False + def download(self, data = None, media = None, filedata = None): if not media: media = {} if not data: data = {} diff --git a/libs/rtorrent/__init__.py b/libs/rtorrent/__init__.py index 683ef1c7..52b4bbe1 100755 --- a/libs/rtorrent/__init__.py +++ b/libs/rtorrent/__init__.py @@ -98,6 +98,13 @@ class RTorrent: "Error: Minimum rTorrent version required is {0}".format( MIN_RTORRENT_VERSION_STR) + def test_connection(self): + try: + self._verify_conn() + except: + return False + return True + def _meets_version_requirement(self): return self._get_client_version_tuple() >= MIN_RTORRENT_VERSION From dfbb84caae02db65082422e30cd25d7ddf052016 Mon Sep 17 00:00:00 2001 From: mikke89 Date: Tue, 21 Jan 2014 01:12:34 +0100 Subject: [PATCH 03/15] Small fix deluge --- couchpotato/core/downloaders/deluge/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/downloaders/deluge/main.py b/couchpotato/core/downloaders/deluge/main.py index 4fe23aa2..b94da29a 100644 --- a/couchpotato/core/downloaders/deluge/main.py +++ b/couchpotato/core/downloaders/deluge/main.py @@ -21,20 +21,20 @@ class Deluge(Downloader): drpc = None testable = True - def connect(self): + def connect(self, reconnect = False): # Load host from config and split out port. host = cleanHost(self.conf('host'), protocol = False).split(':') if not isInt(host[1]): log.error('Config properties are not filled in correctly, port is missing.') return False - if not (self.drpc and self.drpc.test()): + if not self.drpc or reconnect: self.drpc = DelugeRPC(host[0], port = host[1], username = self.conf('username'), password = self.conf('password')) return self.drpc def test(self): - if self.connect() and self.drpc.test(): + if self.connect(True) and self.drpc.test(): return True return False From 723cbcd8bd88196d8a1f610b365d1e686c066418 Mon Sep 17 00:00:00 2001 From: mikke89 Date: Tue, 21 Jan 2014 01:15:08 +0100 Subject: [PATCH 04/15] Added 'test connection' button for downloaders --- couchpotato/core/_base/clientscript/main.py | 1 + couchpotato/core/downloaders/base.py | 13 +++ couchpotato/core/downloaders/deluge/main.py | 17 +++- couchpotato/core/downloaders/nzbget/main.py | 22 +++++ .../core/downloaders/nzbvortex/main.py | 9 +++ couchpotato/core/downloaders/rtorrent/main.py | 13 ++- couchpotato/core/downloaders/sabnzbd/main.py | 11 +++ couchpotato/core/downloaders/synology/main.py | 14 ++++ .../core/downloaders/transmission/main.py | 8 +- couchpotato/core/downloaders/utorrent/main.py | 7 ++ .../static/scripts/misc/downloaders.js | 80 +++++++++++++++++++ libs/rtorrent/__init__.py | 7 ++ 12 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 couchpotato/static/scripts/misc/downloaders.js diff --git a/couchpotato/core/_base/clientscript/main.py b/couchpotato/core/_base/clientscript/main.py index 248d2bc5..c1be7e73 100644 --- a/couchpotato/core/_base/clientscript/main.py +++ b/couchpotato/core/_base/clientscript/main.py @@ -49,6 +49,7 @@ class ClientScript(Plugin): 'scripts/page/settings.js', 'scripts/page/about.js', 'scripts/page/manage.js', + 'scripts/misc/downloaders.js', ], } diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index 71da65ee..fa274922 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -1,4 +1,5 @@ from base64 import b32decode, b16encode +from couchpotato.api import addApiView from couchpotato.core.event import addEvent from couchpotato.core.helpers.variable import mergeDicts from couchpotato.core.logger import CPLog @@ -14,6 +15,7 @@ class Downloader(Provider): protocol = [] http_time_between_calls = 0 status_support = True + testable = False torrent_sources = [ 'http://torrage.com/torrent/%s.torrent', @@ -42,6 +44,8 @@ class Downloader(Provider): addEvent('download.remove_failed', self._removeFailed) addEvent('download.pause', self._pause) addEvent('download.process_complete', self._processComplete) + addApiView('download.%s.is_testable' % self.getName().lower(), self.isTestable) + addApiView('download.%s.test' % self.getName().lower(), self._test) def getEnabledProtocol(self): for download_protocol in self.protocol: @@ -158,6 +162,15 @@ class Downloader(Provider): (d_manual and manual or d_manual is False) and \ (not data or self.isCorrectProtocol(data.get('protocol'))) + def isTestable(self): + return {'success': self.testable} + + def _test(self): + return {'success': self.test()} + + def test(self): + return False + def _pause(self, release_download, pause = True): if self.isDisabled(manual = True, data = {}): return diff --git a/couchpotato/core/downloaders/deluge/main.py b/couchpotato/core/downloaders/deluge/main.py index 53b87d91..b94da29a 100644 --- a/couchpotato/core/downloaders/deluge/main.py +++ b/couchpotato/core/downloaders/deluge/main.py @@ -19,19 +19,25 @@ class Deluge(Downloader): protocol = ['torrent', 'torrent_magnet'] log = CPLog(__name__) drpc = None + testable = True - def connect(self): + def connect(self, reconnect = False): # Load host from config and split out port. host = cleanHost(self.conf('host'), protocol = False).split(':') if not isInt(host[1]): log.error('Config properties are not filled in correctly, port is missing.') return False - if not self.drpc: + if not self.drpc or reconnect: self.drpc = DelugeRPC(host[0], port = host[1], username = self.conf('username'), password = self.conf('password')) return self.drpc + def test(self): + if self.connect(True) and self.drpc.test(): + return True + return False + def download(self, data = None, media = None, filedata = None): if not media: media = {} if not data: data = {} @@ -178,6 +184,13 @@ class DelugeRPC(object): self.client = DelugeClient() self.client.connect(self.host, int(self.port), self.username, self.password) + def test(self): + try: + self.connect() + except: + return False + return True + def add_torrent_magnet(self, torrent, options): torrent_id = False try: diff --git a/couchpotato/core/downloaders/nzbget/main.py b/couchpotato/core/downloaders/nzbget/main.py index a690572c..8b9c88d1 100644 --- a/couchpotato/core/downloaders/nzbget/main.py +++ b/couchpotato/core/downloaders/nzbget/main.py @@ -18,6 +18,28 @@ class NZBGet(Downloader): protocol = ['nzb'] rpc = 'xmlrpc' + testable = True + + def test(self): + url = cleanHost(host = self.conf('host'), ssl = self.conf('ssl'), username = self.conf('username'), password = self.conf('password')) + self.rpc + rpc = xmlrpclib.ServerProxy(url) + + try: + if rpc.writelog('INFO', 'CouchPotato connected to test connection'): + log.debug('Successfully connected to NZBGet') + else: + log.info('Successfully connected to NZBGet, but unable to send a message') + except socket.error: + log.error('NZBGet is not responding. Please ensure that NZBGet is running and host setting is correct.') + return False + except xmlrpclib.ProtocolError as e: + if e.errcode == 401: + log.error('Password is incorrect.') + else: + log.error('Protocol Error: %s', e) + return False + + return True def download(self, data = None, media = None, filedata = None): if not media: media = {} diff --git a/couchpotato/core/downloaders/nzbvortex/main.py b/couchpotato/core/downloaders/nzbvortex/main.py index 205ceb1b..048aa44d 100644 --- a/couchpotato/core/downloaders/nzbvortex/main.py +++ b/couchpotato/core/downloaders/nzbvortex/main.py @@ -24,6 +24,15 @@ class NZBVortex(Downloader): protocol = ['nzb'] api_level = None session_id = None + testable = True + + def test(self): + try: + login_result = self.login() + except: + return False + + return login_result def download(self, data = None, media = None, filedata = None): if not media: media = {} diff --git a/couchpotato/core/downloaders/rtorrent/main.py b/couchpotato/core/downloaders/rtorrent/main.py index f934de5f..a35cb006 100755 --- a/couchpotato/core/downloaders/rtorrent/main.py +++ b/couchpotato/core/downloaders/rtorrent/main.py @@ -18,6 +18,7 @@ class rTorrent(Downloader): protocol = ['torrent', 'torrent_magnet'] rt = None + testable = True # Migration url to host options def __init__(self): @@ -37,9 +38,9 @@ class rTorrent(Downloader): self.deleteConf('url') - def connect(self): + def connect(self, reconnect = False): # Already connected? - if self.rt is not None: + if not reconnect and self.rt is not None: return self.rt url = cleanHost(self.conf('host'), protocol = True, ssl = self.conf('ssl')) + '/' + self.conf('rpc_url').strip('/ ') + '/' @@ -53,8 +54,16 @@ class rTorrent(Downloader): else: self.rt = RTorrent(url) + if not self.rt.test_connection(): + self.rt = None + return self.rt + def test(self): + if not self.connect(True): + return False + return True + def _update_provider_group(self, name, data): if data.get('seed_time'): log.info('seeding time ignored, not supported') diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index 72c23708..fd23211e 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -15,6 +15,17 @@ log = CPLog(__name__) class Sabnzbd(Downloader): protocol = ['nzb'] + testable = True + + def test(self): + try: + sab_data = self.call({ + 'mode': 'version', + }) + except: + return False + + return bool(sab_data) def download(self, data = None, media = None, filedata = None): if not media: media = {} diff --git a/couchpotato/core/downloaders/synology/main.py b/couchpotato/core/downloaders/synology/main.py index 26a4558d..2ffbb8d8 100644 --- a/couchpotato/core/downloaders/synology/main.py +++ b/couchpotato/core/downloaders/synology/main.py @@ -13,6 +13,17 @@ class Synology(Downloader): protocol = ['nzb', 'torrent', 'torrent_magnet'] status_support = False + testable = True + + def test(self): + host = cleanHost(self.conf('host'), protocol = False).split(':') + try: + srpc = SynologyRPC(host[0], host[1], self.conf('username'), self.conf('password')) + test_result = srpc.test() + except: + return False + + return test_result def download(self, data = None, media = None, filedata = None): if not media: media = {} @@ -147,3 +158,6 @@ class SynologyRPC(object): self._logout() return result + + def test(self): + return bool(self._login()) diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index d3f17598..5e952306 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -18,6 +18,7 @@ class Transmission(Downloader): protocol = ['torrent', 'torrent_magnet'] log = CPLog(__name__) trpc = None + testable = True def connect(self): # Load host from config and split out port. @@ -26,11 +27,16 @@ class Transmission(Downloader): log.error('Config properties are not filled in correctly, port is missing.') return False - if not self.trpc: + if not (self.trpc and self.trpc.get_session()): self.trpc = TransmissionRPC(host[0], port = host[1], rpc_url = self.conf('rpc_url').strip('/ '), username = self.conf('username'), password = self.conf('password')) return self.trpc + def test(self): + if self.connect() and self.trpc.get_session(): + return True + return False + def download(self, data = None, media = None, filedata = None): if not media: media = {} if not data: data = {} diff --git a/couchpotato/core/downloaders/utorrent/main.py b/couchpotato/core/downloaders/utorrent/main.py index e527230c..6e3e4df3 100644 --- a/couchpotato/core/downloaders/utorrent/main.py +++ b/couchpotato/core/downloaders/utorrent/main.py @@ -1,5 +1,6 @@ from base64 import b16encode, b32decode from bencode import bencode as benc, bdecode +from couchpotato.api import addApiView from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList from couchpotato.core.helpers.encoding import isInt, ss, sp from couchpotato.core.helpers.variable import tryInt, tryFloat, cleanHost @@ -24,6 +25,7 @@ class uTorrent(Downloader): protocol = ['torrent', 'torrent_magnet'] utorrent_api = None + testable = True status_flags = { 'STARTED' : 1, 'CHECKING' : 2, @@ -46,6 +48,11 @@ class uTorrent(Downloader): return self.utorrent_api + def test(self): + if self.connect() and self.utorrent_api.get_status(): + return True + return False + def download(self, data = None, media = None, filedata = None): if not media: media = {} if not data: data = {} diff --git a/couchpotato/static/scripts/misc/downloaders.js b/couchpotato/static/scripts/misc/downloaders.js new file mode 100644 index 00000000..eee45b40 --- /dev/null +++ b/couchpotato/static/scripts/misc/downloaders.js @@ -0,0 +1,80 @@ +var DownloadersBase = new Class({ + + Implements: [Events], + + initialize: function(){ + var self = this; + + // Add test buttons to settings page + App.addEvent('load', self.addTestButtons.bind(self)); + + }, + + // Downloaders setting tests + addTestButtons: function(){ + var self = this; + + var setting_page = App.getPage('Settings'); + setting_page.addEvent('create', function(){ + Object.each(setting_page.tabs.downloaders.groups, self.addTestButton.bind(self)) + }) + + }, + + addTestButton: function(fieldset, plugin_name){ + var self = this, + button_name = self.testButtonName(fieldset); + + if(button_name.contains('Downloaders')) return; + + Api.request('download.'+plugin_name+'.is_testable', { + 'onComplete': function(json){ + if(json.success){ + // Only add test button if downloader is testable + new Element('.ctrlHolder.test_button').adopt( + new Element('a.button', { + 'text': button_name, + 'events': { + 'click': function(){ + var button = fieldset.getElement('.test_button .button'); + button.set('text', 'Connecting...'); + + Api.request('download.'+plugin_name+'.test', { + 'onComplete': function(json){ + + button.set('text', button_name); + + if(json.success){ + var message = new Element('span.success', { + 'text': 'Connection successful' + }).inject(button, 'after') + } + else { + var message = new Element('span.failed', { + 'text': 'Connection failed. Check logs for details.' + }).inject(button, 'after') + } + + (function(){ + message.destroy(); + }).delay(3000) + } + }); + } + } + }) + ).inject(fieldset); + } + } + }); + + }, + + testButtonName: function(fieldset){ + var name = String(fieldset.getElement('h2').innerHTML).substring(0,String(fieldset.getElement('h2').innerHTML).indexOf("= MIN_RTORRENT_VERSION From f20cce01761025e07950fafa92a48a12b2571f11 Mon Sep 17 00:00:00 2001 From: mikke89 Date: Tue, 21 Jan 2014 01:38:37 +0100 Subject: [PATCH 05/15] Small fix --- couchpotato/core/downloaders/sabnzbd/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index a21aee0e..fd23211e 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -19,13 +19,13 @@ class Sabnzbd(Downloader): def test(self): try: - queue = self.call({ + sab_data = self.call({ 'mode': 'version', }) except: return False - return bool(queue) + return bool(sab_data) def download(self, data = None, media = None, filedata = None): if not media: media = {} From ebc5a66375c65aa94b09d9afcc32432a3babb29d Mon Sep 17 00:00:00 2001 From: mikke89 Date: Sun, 26 Jan 2014 18:17:23 +0100 Subject: [PATCH 06/15] Fixed 'connection test' for Transmission and Sabnzbd --- couchpotato/core/downloaders/sabnzbd/main.py | 2 +- couchpotato/core/downloaders/transmission/main.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index fd23211e..6b96d95e 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -20,7 +20,7 @@ class Sabnzbd(Downloader): def test(self): try: sab_data = self.call({ - 'mode': 'version', + 'mode': 'qstatus', }) except: return False diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index 5e952306..eb73b62e 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -20,20 +20,20 @@ class Transmission(Downloader): trpc = None testable = True - def connect(self): + def connect(self, reconnect = True): # Load host from config and split out port. host = cleanHost(self.conf('host'), protocol = False).split(':') if not isInt(host[1]): log.error('Config properties are not filled in correctly, port is missing.') return False - if not (self.trpc and self.trpc.get_session()): + if not self.trpc or reconnect: self.trpc = TransmissionRPC(host[0], port = host[1], rpc_url = self.conf('rpc_url').strip('/ '), username = self.conf('username'), password = self.conf('password')) return self.trpc def test(self): - if self.connect() and self.trpc.get_session(): + if self.connect(True) and self.trpc.get_session(): return True return False From 18c8e803a4cb34511591f4cfe62ad4038920951f Mon Sep 17 00:00:00 2001 From: mikke89 Date: Sun, 26 Jan 2014 18:26:32 +0100 Subject: [PATCH 07/15] Fixed 'connection test' for Transmission and Sabnzbd --- couchpotato/core/downloaders/sabnzbd/main.py | 2 +- couchpotato/core/downloaders/transmission/main.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index fd23211e..6b96d95e 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -20,7 +20,7 @@ class Sabnzbd(Downloader): def test(self): try: sab_data = self.call({ - 'mode': 'version', + 'mode': 'qstatus', }) except: return False diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index 5e952306..5b519763 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -20,20 +20,20 @@ class Transmission(Downloader): trpc = None testable = True - def connect(self): + def connect(self, reconnect = False): # Load host from config and split out port. host = cleanHost(self.conf('host'), protocol = False).split(':') if not isInt(host[1]): log.error('Config properties are not filled in correctly, port is missing.') return False - if not (self.trpc and self.trpc.get_session()): + if not self.trpc or reconnect: self.trpc = TransmissionRPC(host[0], port = host[1], rpc_url = self.conf('rpc_url').strip('/ '), username = self.conf('username'), password = self.conf('password')) return self.trpc def test(self): - if self.connect() and self.trpc.get_session(): + if self.connect(True) and self.trpc.get_session(): return True return False From 1f18d2b09c48f60399b71e808a2749ae18eb8438 Mon Sep 17 00:00:00 2001 From: mikke89 Date: Fri, 21 Feb 2014 02:09:16 +0100 Subject: [PATCH 08/15] Test downloader connection: Check version of uTorrent and Sabnzbd --- couchpotato/core/downloaders/base.py | 5 ++++- couchpotato/core/downloaders/sabnzbd/main.py | 11 ++++++++++- couchpotato/core/downloaders/utorrent/main.py | 15 ++++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index fa274922..bb57cca7 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -166,7 +166,10 @@ class Downloader(Provider): return {'success': self.testable} def _test(self): - return {'success': self.test()} + t = self.test() + if isinstance(t,tuple): + return {'success': t[0], 'msg': t[1] } + return {'success': t } def test(self): return False diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index 6b96d95e..b6ef7f21 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -19,13 +19,22 @@ class Sabnzbd(Downloader): def test(self): try: + sab_data = self.call({ + 'mode': 'version', + }) + v = sab_data.split('.') + if int(v[0]) == 0 and int(v[1]) < 7: + return False, 'Your Sabnzbd client is too old, please update to newest version.' + sab_data = self.call({ 'mode': 'qstatus', }) + if not sab_data: + return False except: return False - return bool(sab_data) + return True def download(self, data = None, media = None, filedata = None): if not media: media = {} diff --git a/couchpotato/core/downloaders/utorrent/main.py b/couchpotato/core/downloaders/utorrent/main.py index 6e3e4df3..d74c05cc 100644 --- a/couchpotato/core/downloaders/utorrent/main.py +++ b/couchpotato/core/downloaders/utorrent/main.py @@ -49,8 +49,14 @@ class uTorrent(Downloader): return self.utorrent_api def test(self): - if self.connect() and self.utorrent_api.get_status(): + if self.connect(): + build_version = self.utorrent_api.get_build() + if not build_version: + return False + if build_version < 25406: # This build corresponds to version 3.0.0 stable + return False, 'Your uTorrent client is too old, please update to newest version.' return True + return False def download(self, data = None, media = None, filedata = None): @@ -329,3 +335,10 @@ class uTorrentAPI(object): def get_files(self, hash): action = 'action=getfiles&hash=%s' % hash return self._request(action) + + def get_build(self): + data = self._request('') + if not data: + return False + response = json.loads(data) + return int(response.get('build')) From 499b8193ab340db6c31f22844a441374b21f6c86 Mon Sep 17 00:00:00 2001 From: mikke89 Date: Fri, 21 Feb 2014 02:26:04 +0100 Subject: [PATCH 09/15] Added return message text to frontend --- couchpotato/static/scripts/misc/downloaders.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/couchpotato/static/scripts/misc/downloaders.js b/couchpotato/static/scripts/misc/downloaders.js index eee45b40..8d03c241 100644 --- a/couchpotato/static/scripts/misc/downloaders.js +++ b/couchpotato/static/scripts/misc/downloaders.js @@ -50,8 +50,10 @@ var DownloadersBase = new Class({ }).inject(button, 'after') } else { + var msg_text = 'Connection failed. Check logs for details.'; + if(json.hasOwnProperty('msg')) msg_text = json.msg; var message = new Element('span.failed', { - 'text': 'Connection failed. Check logs for details.' + 'text': msg_text }).inject(button, 'after') } From 893dde9958acb60567a493a1b9f72b9ccd0aacd7 Mon Sep 17 00:00:00 2001 From: mikke89 Date: Fri, 21 Feb 2014 20:28:49 +0100 Subject: [PATCH 10/15] rTorrent connection test: Error message on version check fail --- couchpotato/core/downloaders/rtorrent/main.py | 19 ++++++++++++++----- couchpotato/core/downloaders/sabnzbd/main.py | 1 + 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/couchpotato/core/downloaders/rtorrent/main.py b/couchpotato/core/downloaders/rtorrent/main.py index a35cb006..563e3bb7 100755 --- a/couchpotato/core/downloaders/rtorrent/main.py +++ b/couchpotato/core/downloaders/rtorrent/main.py @@ -19,6 +19,7 @@ class rTorrent(Downloader): protocol = ['torrent', 'torrent_magnet'] rt = None testable = True + error_msg = '' # Migration url to host options def __init__(self): @@ -54,15 +55,23 @@ class rTorrent(Downloader): else: self.rt = RTorrent(url) - if not self.rt.test_connection(): - self.rt = None + self.error_msg = '' + try: + self.rt._verify_conn() + except AssertionError as e: + self.error_msg = e.message + self.rt = None return self.rt def test(self): - if not self.connect(True): - return False - return True + if self.connect(True): + return True + + if self.error_msg: + return False, 'Connection failed: ' + self.error_msg + + return False def _update_provider_group(self, name, data): if data.get('seed_time'): diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index b6ef7f21..9eea8c9a 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -26,6 +26,7 @@ class Sabnzbd(Downloader): if int(v[0]) == 0 and int(v[1]) < 7: return False, 'Your Sabnzbd client is too old, please update to newest version.' + # the version check will work even with wrong api key, so we need the next check as well sab_data = self.call({ 'mode': 'qstatus', }) From 6b357674d0faff52df0fef2cf16c84dcb07a53ac Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 24 Feb 2014 18:18:39 +0000 Subject: [PATCH 11/15] Replaced proxies Remove dead/blocked proxies, Added in new unblocked/working links --- .../core/providers/torrent/thepiratebay/main.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/couchpotato/core/providers/torrent/thepiratebay/main.py b/couchpotato/core/providers/torrent/thepiratebay/main.py index f8b77787..c366c517 100644 --- a/couchpotato/core/providers/torrent/thepiratebay/main.py +++ b/couchpotato/core/providers/torrent/thepiratebay/main.py @@ -31,15 +31,13 @@ class ThePirateBay(TorrentMagnetProvider): proxy_list = [ 'https://tpb.ipredator.se', 'https://thepiratebay.se', - 'https://depiraatbaai.be', - 'https://piratereverse.info', - 'https://tpb.pirateparty.org.uk', - 'https://argumentomteemigreren.nl', - 'https://livepirate.com', + 'http://pirateproxy.ca', + 'http://tpb.al', + 'http://www.tpb.gr', + 'http://nl.tpb.li', + 'http://proxybay.eu', 'https://www.getpirate.com', - 'https://tpb.partipirate.org', - 'https://tpb.piraten.lu', - 'https://kuiken.co', + 'http://pirateproxy.ca', ] def _searchOnTitle(self, title, movie, quality, results): From 0050e5cdfc76ede9b3d91f0a8b5ac6c687729b93 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 24 Feb 2014 18:23:18 +0000 Subject: [PATCH 12/15] Changed http to https adjusted http to SSL, better security when dealing with logins. --- couchpotato/core/providers/torrent/iptorrents/main.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/couchpotato/core/providers/torrent/iptorrents/main.py b/couchpotato/core/providers/torrent/iptorrents/main.py index 35ce25c0..4a2c6dbf 100644 --- a/couchpotato/core/providers/torrent/iptorrents/main.py +++ b/couchpotato/core/providers/torrent/iptorrents/main.py @@ -11,11 +11,11 @@ log = CPLog(__name__) class IPTorrents(TorrentProvider): urls = { - 'test': 'http://www.iptorrents.com/', - 'base_url': 'http://www.iptorrents.com', - 'login': 'http://www.iptorrents.com/torrents/', - 'login_check': 'http://www.iptorrents.com/inbox.php', - 'search': 'http://www.iptorrents.com/torrents/?l%d=1%s&q=%s&qf=ti&p=%d', + 'test': 'https://www.iptorrents.com/', + 'base_url': 'https://www.iptorrents.com', + 'login': 'https://www.iptorrents.com/torrents/', + 'login_check': 'https://www.iptorrents.com/inbox.php', + 'search': 'https://www.iptorrents.com/torrents/?l%d=1%s&q=%s&qf=ti&p=%d', } cat_ids = [ From fb95d7923fc49b29afd180ae1ef22ff32fbe9a69 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 24 Feb 2014 20:46:47 +0000 Subject: [PATCH 13/15] HTTP to HTTPS Updated URL's to SSL, better account security. --- .../core/providers/torrent/ilovetorrents/main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/couchpotato/core/providers/torrent/ilovetorrents/main.py b/couchpotato/core/providers/torrent/ilovetorrents/main.py index 6d56ea48..f8ed67a3 100644 --- a/couchpotato/core/providers/torrent/ilovetorrents/main.py +++ b/couchpotato/core/providers/torrent/ilovetorrents/main.py @@ -12,12 +12,12 @@ log = CPLog(__name__) class ILoveTorrents(TorrentProvider): urls = { - 'download': 'http://www.ilovetorrents.me/%s', - 'detail': 'http://www.ilovetorrents.me/%s', - 'search': 'http://www.ilovetorrents.me/browse.php?search=%s&page=%s&cat=%s', - 'test': 'http://www.ilovetorrents.me/', - 'login': 'http://www.ilovetorrents.me/takelogin.php', - 'login_check': 'http://www.ilovetorrents.me' + 'download': 'https://www.ilovetorrents.me/%s', + 'detail': 'https//www.ilovetorrents.me/%s', + 'search': 'https://www.ilovetorrents.me/browse.php?search=%s&page=%s&cat=%s', + 'test': 'https://www.ilovetorrents.me/', + 'login': 'https://www.ilovetorrents.me/takelogin.php', + 'login_check': 'https://www.ilovetorrents.me' } cat_ids = [ From 188a1a3b03664a1344b8ac9c104c9d2b941d676f Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 24 Feb 2014 20:56:01 +0000 Subject: [PATCH 14/15] HTTP to HTTPS Updated URL to SSL, better account security. --- couchpotato/core/providers/torrent/torrentshack/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/providers/torrent/torrentshack/__init__.py b/couchpotato/core/providers/torrent/torrentshack/__init__.py index 0e552116..058236e4 100644 --- a/couchpotato/core/providers/torrent/torrentshack/__init__.py +++ b/couchpotato/core/providers/torrent/torrentshack/__init__.py @@ -11,7 +11,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'TorrentShack', - 'description': 'See TorrentShack', + 'description': 'See TorrentShack', 'options': [ { 'name': 'enabled', From 2b3d755c642d2e8b516ee68e7ac0f014c90fada4 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 24 Feb 2014 22:48:12 +0100 Subject: [PATCH 15/15] Cleanup downloader testbuttons PR --- couchpotato/core/downloaders/base.py | 11 +-- .../core/downloaders/blackhole/main.py | 15 ++++ couchpotato/core/downloaders/deluge/main.py | 11 ++- couchpotato/core/downloaders/nzbget/main.py | 56 +++++++-------- .../core/downloaders/nzbvortex/main.py | 17 +++-- .../core/downloaders/pneumatic/main.py | 15 ++++ couchpotato/core/downloaders/rtorrent/main.py | 3 +- couchpotato/core/downloaders/sabnzbd/main.py | 41 ++++++----- couchpotato/core/downloaders/synology/main.py | 21 +++--- .../core/downloaders/transmission/main.py | 11 ++- couchpotato/core/downloaders/utorrent/main.py | 24 +++---- .../static/scripts/misc/downloaders.js | 71 +++++++++---------- 12 files changed, 152 insertions(+), 144 deletions(-) diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index bb57cca7..3bcf1f31 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -15,7 +15,6 @@ class Downloader(Provider): protocol = [] http_time_between_calls = 0 status_support = True - testable = False torrent_sources = [ 'http://torrage.com/torrent/%s.torrent', @@ -44,7 +43,6 @@ class Downloader(Provider): addEvent('download.remove_failed', self._removeFailed) addEvent('download.pause', self._pause) addEvent('download.process_complete', self._processComplete) - addApiView('download.%s.is_testable' % self.getName().lower(), self.isTestable) addApiView('download.%s.test' % self.getName().lower(), self._test) def getEnabledProtocol(self): @@ -162,14 +160,11 @@ class Downloader(Provider): (d_manual and manual or d_manual is False) and \ (not data or self.isCorrectProtocol(data.get('protocol'))) - def isTestable(self): - return {'success': self.testable} - def _test(self): t = self.test() - if isinstance(t,tuple): - return {'success': t[0], 'msg': t[1] } - return {'success': t } + if isinstance(t, tuple): + return {'success': t[0], 'msg': t[1]} + return {'success': t} def test(self): return False diff --git a/couchpotato/core/downloaders/blackhole/main.py b/couchpotato/core/downloaders/blackhole/main.py index 8449d09b..9a018354 100644 --- a/couchpotato/core/downloaders/blackhole/main.py +++ b/couchpotato/core/downloaders/blackhole/main.py @@ -1,5 +1,6 @@ from __future__ import with_statement from couchpotato.core.downloaders.base import Downloader +from couchpotato.core.helpers.encoding import sp from couchpotato.core.logger import CPLog from couchpotato.environment import Env import os @@ -67,6 +68,20 @@ class Blackhole(Downloader): return False + def test(self): + directory = self.conf('directory') + if directory and os.path.isdir(directory): + + test_file = sp(os.path.join(directory, 'couchpotato_test.txt')) + + # Check if folder is writable + self.createFile(test_file, 'This is a test file') + if os.path.isfile(test_file): + os.remove(test_file) + return True + + return False + def getEnabledProtocol(self): if self.conf('use_for') == 'both': return super(Blackhole, self).getEnabledProtocol() diff --git a/couchpotato/core/downloaders/deluge/main.py b/couchpotato/core/downloaders/deluge/main.py index 3d72be73..59300958 100644 --- a/couchpotato/core/downloaders/deluge/main.py +++ b/couchpotato/core/downloaders/deluge/main.py @@ -19,7 +19,6 @@ class Deluge(Downloader): protocol = ['torrent', 'torrent_magnet'] log = CPLog(__name__) drpc = None - testable = True def connect(self, reconnect = False): # Load host from config and split out port. @@ -33,11 +32,6 @@ class Deluge(Downloader): return self.drpc - def test(self): - if self.connect(True) and self.drpc.test(): - return True - return False - def download(self, data = None, media = None, filedata = None): if not media: media = {} if not data: data = {} @@ -92,6 +86,11 @@ class Deluge(Downloader): log.info('Torrent sent to Deluge successfully.') return self.downloadReturnId(remote_torrent) + def test(self): + if self.connect(True) and self.drpc.test(): + return True + return False + def getAllDownloadStatus(self, ids): log.debug('Checking Deluge download status.') diff --git a/couchpotato/core/downloaders/nzbget/main.py b/couchpotato/core/downloaders/nzbget/main.py index 8b9c88d1..3dad8670 100644 --- a/couchpotato/core/downloaders/nzbget/main.py +++ b/couchpotato/core/downloaders/nzbget/main.py @@ -16,30 +16,7 @@ log = CPLog(__name__) class NZBGet(Downloader): protocol = ['nzb'] - rpc = 'xmlrpc' - testable = True - - def test(self): - url = cleanHost(host = self.conf('host'), ssl = self.conf('ssl'), username = self.conf('username'), password = self.conf('password')) + self.rpc - rpc = xmlrpclib.ServerProxy(url) - - try: - if rpc.writelog('INFO', 'CouchPotato connected to test connection'): - log.debug('Successfully connected to NZBGet') - else: - log.info('Successfully connected to NZBGet, but unable to send a message') - except socket.error: - log.error('NZBGet is not responding. Please ensure that NZBGet is running and host setting is correct.') - return False - except xmlrpclib.ProtocolError as e: - if e.errcode == 401: - log.error('Password is incorrect.') - else: - log.error('Protocol Error: %s', e) - return False - - return True def download(self, data = None, media = None, filedata = None): if not media: media = {} @@ -53,8 +30,7 @@ class NZBGet(Downloader): nzb_name = ss('%s.nzb' % self.createNzbName(data, media)) - url = cleanHost(host = self.conf('host'), ssl = self.conf('ssl'), username = self.conf('username'), password = self.conf('password')) + self.rpc - rpc = xmlrpclib.ServerProxy(url) + rpc = self.getRPC() try: if rpc.writelog('INFO', 'CouchPotato connected to drop off %s.' % nzb_name): @@ -90,12 +66,31 @@ class NZBGet(Downloader): log.error('NZBGet could not add %s to the queue.', nzb_name) return False + def test(self): + rpc = self.getRPC() + + try: + if rpc.writelog('INFO', 'CouchPotato connected to test connection'): + log.debug('Successfully connected to NZBGet') + else: + log.info('Successfully connected to NZBGet, but unable to send a message') + except socket.error: + log.error('NZBGet is not responding. Please ensure that NZBGet is running and host setting is correct.') + return False + except xmlrpclib.ProtocolError as e: + if e.errcode == 401: + log.error('Password is incorrect.') + else: + log.error('Protocol Error: %s', e) + return False + + return True + def getAllDownloadStatus(self, ids): log.debug('Checking NZBGet download status.') - url = cleanHost(host = self.conf('host'), ssl = self.conf('ssl'), username = self.conf('username'), password = self.conf('password')) + self.rpc - rpc = xmlrpclib.ServerProxy(url) + rpc = self.getRPC() try: if rpc.writelog('INFO', 'CouchPotato connected to check status'): @@ -180,8 +175,7 @@ class NZBGet(Downloader): log.info('%s failed downloading, deleting...', release_download['name']) - url = cleanHost(host = self.conf('host'), ssl = self.conf('ssl'), username = self.conf('username'), password = self.conf('password')) + self.rpc - rpc = xmlrpclib.ServerProxy(url) + rpc = self.getRPC() try: if rpc.writelog('INFO', 'CouchPotato connected to delete some history'): @@ -216,3 +210,7 @@ class NZBGet(Downloader): return False return True + + def getRPC(self): + url = cleanHost(host = self.conf('host'), ssl = self.conf('ssl'), username = self.conf('username'), password = self.conf('password')) + self.rpc + return xmlrpclib.ServerProxy(url) diff --git a/couchpotato/core/downloaders/nzbvortex/main.py b/couchpotato/core/downloaders/nzbvortex/main.py index e02f7c1e..d1525c89 100644 --- a/couchpotato/core/downloaders/nzbvortex/main.py +++ b/couchpotato/core/downloaders/nzbvortex/main.py @@ -24,15 +24,6 @@ class NZBVortex(Downloader): protocol = ['nzb'] api_level = None session_id = None - testable = True - - def test(self): - try: - login_result = self.login() - except: - return False - - return login_result def download(self, data = None, media = None, filedata = None): if not media: media = {} @@ -51,6 +42,14 @@ class NZBVortex(Downloader): log.error('Something went wrong sending the NZB file: %s', traceback.format_exc()) return False + def test(self): + try: + login_result = self.login() + except: + return False + + return login_result + def getAllDownloadStatus(self, ids): raw_statuses = self.call('nzb') diff --git a/couchpotato/core/downloaders/pneumatic/main.py b/couchpotato/core/downloaders/pneumatic/main.py index 6af22d2d..bc1f6d04 100644 --- a/couchpotato/core/downloaders/pneumatic/main.py +++ b/couchpotato/core/downloaders/pneumatic/main.py @@ -1,5 +1,6 @@ from __future__ import with_statement from couchpotato.core.downloaders.base import Downloader +from couchpotato.core.helpers.encoding import sp from couchpotato.core.logger import CPLog import os import traceback @@ -56,3 +57,17 @@ class Pneumatic(Downloader): log.info('Failed to download file %s: %s', (data.get('name'), traceback.format_exc())) return False return False + + def test(self): + directory = self.conf('directory') + if directory and os.path.isdir(directory): + + test_file = sp(os.path.join(directory, 'couchpotato_test.txt')) + + # Check if folder is writable + self.createFile(test_file, 'This is a test file') + if os.path.isfile(test_file): + os.remove(test_file) + return True + + return False diff --git a/couchpotato/core/downloaders/rtorrent/main.py b/couchpotato/core/downloaders/rtorrent/main.py index fed2bfe2..c5850f93 100755 --- a/couchpotato/core/downloaders/rtorrent/main.py +++ b/couchpotato/core/downloaders/rtorrent/main.py @@ -19,7 +19,6 @@ class rTorrent(Downloader): protocol = ['torrent', 'torrent_magnet'] rt = None - testable = True error_msg = '' # Migration url to host options @@ -49,7 +48,7 @@ class rTorrent(Downloader): self.rt = None return True - def connect(self): + def connect(self, reconnect = False): # Already connected? if not reconnect and self.rt is not None: return self.rt diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index 9eea8c9a..ba58c090 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -15,27 +15,6 @@ log = CPLog(__name__) class Sabnzbd(Downloader): protocol = ['nzb'] - testable = True - - def test(self): - try: - sab_data = self.call({ - 'mode': 'version', - }) - v = sab_data.split('.') - if int(v[0]) == 0 and int(v[1]) < 7: - return False, 'Your Sabnzbd client is too old, please update to newest version.' - - # the version check will work even with wrong api key, so we need the next check as well - sab_data = self.call({ - 'mode': 'qstatus', - }) - if not sab_data: - return False - except: - return False - - return True def download(self, data = None, media = None, filedata = None): if not media: media = {} @@ -85,6 +64,26 @@ class Sabnzbd(Downloader): log.error('Error getting data from SABNZBd: %s', sab_data) return False + def test(self): + try: + sab_data = self.call({ + 'mode': 'version', + }) + v = sab_data.split('.') + if int(v[0]) == 0 and int(v[1]) < 7: + return False, 'Your Sabnzbd client is too old, please update to newest version.' + + # the version check will work even with wrong api key, so we need the next check as well + sab_data = self.call({ + 'mode': 'qstatus', + }) + if not sab_data: + return False + except: + return False + + return True + def getAllDownloadStatus(self, ids): log.debug('Checking SABnzbd download status.') diff --git a/couchpotato/core/downloaders/synology/main.py b/couchpotato/core/downloaders/synology/main.py index 7fb0ee57..7e5b6098 100644 --- a/couchpotato/core/downloaders/synology/main.py +++ b/couchpotato/core/downloaders/synology/main.py @@ -13,17 +13,6 @@ class Synology(Downloader): protocol = ['nzb', 'torrent', 'torrent_magnet'] status_support = False - testable = True - - def test(self): - host = cleanHost(self.conf('host'), protocol = False).split(':') - try: - srpc = SynologyRPC(host[0], host[1], self.conf('username'), self.conf('password')) - test_result = srpc.test() - except: - return False - - return test_result def download(self, data = None, media = None, filedata = None): if not media: media = {} @@ -56,6 +45,16 @@ class Synology(Downloader): finally: return self.downloadReturnId('') if response else False + def test(self): + host = cleanHost(self.conf('host'), protocol = False).split(':') + try: + srpc = SynologyRPC(host[0], host[1], self.conf('username'), self.conf('password')) + test_result = srpc.test() + except: + return False + + return test_result + def getEnabledProtocol(self): if self.conf('use_for') == 'both': return super(Synology, self).getEnabledProtocol() diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index d64c270e..4c42bf0f 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -18,7 +18,6 @@ class Transmission(Downloader): protocol = ['torrent', 'torrent_magnet'] log = CPLog(__name__) trpc = None - testable = True def connect(self, reconnect = False): # Load host from config and split out port. @@ -32,11 +31,6 @@ class Transmission(Downloader): return self.trpc - def test(self): - if self.connect(True) and self.trpc.get_session(): - return True - return False - def download(self, data = None, media = None, filedata = None): if not media: media = {} if not data: data = {} @@ -89,6 +83,11 @@ class Transmission(Downloader): log.info('Torrent sent to Transmission successfully.') return self.downloadReturnId(remote_torrent['torrent-added']['hashString']) + def test(self): + if self.connect(True) and self.trpc.get_session(): + return True + return False + def getAllDownloadStatus(self, ids): log.debug('Checking Transmission download status.') diff --git a/couchpotato/core/downloaders/utorrent/main.py b/couchpotato/core/downloaders/utorrent/main.py index e1a111e4..6a5e4257 100644 --- a/couchpotato/core/downloaders/utorrent/main.py +++ b/couchpotato/core/downloaders/utorrent/main.py @@ -1,6 +1,5 @@ from base64 import b16encode, b32decode from bencode import bencode as benc, bdecode -from couchpotato.api import addApiView from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList from couchpotato.core.helpers.encoding import isInt, ss, sp from couchpotato.core.helpers.variable import tryInt, tryFloat, cleanHost @@ -25,7 +24,6 @@ class uTorrent(Downloader): protocol = ['torrent', 'torrent_magnet'] utorrent_api = None - testable = True status_flags = { 'STARTED' : 1, 'CHECKING' : 2, @@ -48,17 +46,6 @@ class uTorrent(Downloader): return self.utorrent_api - def test(self): - if self.connect(): - build_version = self.utorrent_api.get_build() - if not build_version: - return False - if build_version < 25406: # This build corresponds to version 3.0.0 stable - return False, 'Your uTorrent client is too old, please update to newest version.' - return True - - return False - def download(self, data = None, media = None, filedata = None): if not media: media = {} if not data: data = {} @@ -128,6 +115,17 @@ class uTorrent(Downloader): return self.downloadReturnId(torrent_hash) + def test(self): + if self.connect(): + build_version = self.utorrent_api.get_build() + if not build_version: + return False + if build_version < 25406: # This build corresponds to version 3.0.0 stable + return False, 'Your uTorrent client is too old, please update to newest version.' + return True + + return False + def getAllDownloadStatus(self, ids): log.debug('Checking uTorrent download status.') diff --git a/couchpotato/static/scripts/misc/downloaders.js b/couchpotato/static/scripts/misc/downloaders.js index 8d03c241..5127275c 100644 --- a/couchpotato/static/scripts/misc/downloaders.js +++ b/couchpotato/static/scripts/misc/downloaders.js @@ -27,48 +27,41 @@ var DownloadersBase = new Class({ if(button_name.contains('Downloaders')) return; - Api.request('download.'+plugin_name+'.is_testable', { - 'onComplete': function(json){ - if(json.success){ - // Only add test button if downloader is testable - new Element('.ctrlHolder.test_button').adopt( - new Element('a.button', { - 'text': button_name, - 'events': { - 'click': function(){ - var button = fieldset.getElement('.test_button .button'); - button.set('text', 'Connecting...'); + new Element('.ctrlHolder.test_button').adopt( + new Element('a.button', { + 'text': button_name, + 'events': { + 'click': function(){ + var button = fieldset.getElement('.test_button .button'); + button.set('text', 'Connecting...'); - Api.request('download.'+plugin_name+'.test', { - 'onComplete': function(json){ + Api.request('download.'+plugin_name+'.test', { + 'onComplete': function(json){ - button.set('text', button_name); + button.set('text', button_name); - if(json.success){ - var message = new Element('span.success', { - 'text': 'Connection successful' - }).inject(button, 'after') - } - else { - var msg_text = 'Connection failed. Check logs for details.'; - if(json.hasOwnProperty('msg')) msg_text = json.msg; - var message = new Element('span.failed', { - 'text': msg_text - }).inject(button, 'after') - } + if(json.success){ + var message = new Element('span.success', { + 'text': 'Connection successful' + }).inject(button, 'after') + } + else { + var msg_text = 'Connection failed. Check logs for details.'; + if(json.hasOwnProperty('msg')) msg_text = json.msg; + var message = new Element('span.failed', { + 'text': msg_text + }).inject(button, 'after') + } - (function(){ - message.destroy(); - }).delay(3000) - } - }); - } - } - }) - ).inject(fieldset); - } - } - }); + (function(){ + message.destroy(); + }).delay(3000) + } + }); + } + } + }) + ).inject(fieldset); }, @@ -79,4 +72,4 @@ var DownloadersBase = new Class({ }); -window.Downloaders = new DownloadersBase(); \ No newline at end of file +window.Downloaders = new DownloadersBase();