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..3bcf1f31 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
@@ -42,6 +43,7 @@ class Downloader(Provider):
addEvent('download.remove_failed', self._removeFailed)
addEvent('download.pause', self._pause)
addEvent('download.process_complete', self._processComplete)
+ addApiView('download.%s.test' % self.getName().lower(), self._test)
def getEnabledProtocol(self):
for download_protocol in self.protocol:
@@ -158,6 +160,15 @@ class Downloader(Provider):
(d_manual and manual or d_manual is False) and \
(not data or self.isCorrectProtocol(data.get('protocol')))
+ def _test(self):
+ t = self.test()
+ if isinstance(t, tuple):
+ return {'success': t[0], 'msg': t[1]}
+ return {'success': t}
+
+ 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/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 c5f80167..59300958 100644
--- a/couchpotato/core/downloaders/deluge/main.py
+++ b/couchpotato/core/downloaders/deluge/main.py
@@ -20,14 +20,14 @@ class Deluge(Downloader):
log = CPLog(__name__)
drpc = None
- 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
@@ -86,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.')
@@ -178,6 +183,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..3dad8670 100644
--- a/couchpotato/core/downloaders/nzbget/main.py
+++ b/couchpotato/core/downloaders/nzbget/main.py
@@ -16,7 +16,6 @@ log = CPLog(__name__)
class NZBGet(Downloader):
protocol = ['nzb']
-
rpc = 'xmlrpc'
def download(self, data = None, media = None, filedata = None):
@@ -31,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):
@@ -68,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'):
@@ -158,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'):
@@ -194,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 236e624c..d1525c89 100644
--- a/couchpotato/core/downloaders/nzbvortex/main.py
+++ b/couchpotato/core/downloaders/nzbvortex/main.py
@@ -42,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 8e21e7fc..c4cb0fd6 100755
--- a/couchpotato/core/downloaders/rtorrent/main.py
+++ b/couchpotato/core/downloaders/rtorrent/main.py
@@ -20,6 +20,7 @@ class rTorrent(Downloader):
protocol = ['torrent', 'torrent_magnet']
rt = None
+ error_msg = ''
# Migration url to host options
def __init__(self):
@@ -48,9 +49,9 @@ class rTorrent(Downloader):
self.rt = None
return True
- 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'))
@@ -69,9 +70,25 @@ class rTorrent(Downloader):
else:
self.rt = RTorrent(url)
+ self.error_msg = ''
+ try:
+ self.rt._verify_conn()
+ except AssertionError as e:
+ self.error_msg = e.message
+ self.rt = None
+
return self.rt
- def updateProviderGroup(self, name, data):
+ def test(self):
+ 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'):
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..ba58c090 100644
--- a/couchpotato/core/downloaders/sabnzbd/main.py
+++ b/couchpotato/core/downloaders/sabnzbd/main.py
@@ -64,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 f964f37f..7e5b6098 100644
--- a/couchpotato/core/downloaders/synology/main.py
+++ b/couchpotato/core/downloaders/synology/main.py
@@ -45,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()
@@ -147,3 +157,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 2daeab46..4c42bf0f 100644
--- a/couchpotato/core/downloaders/transmission/main.py
+++ b/couchpotato/core/downloaders/transmission/main.py
@@ -19,14 +19,14 @@ class Transmission(Downloader):
log = CPLog(__name__)
trpc = None
- 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:
+ 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
@@ -83,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 e0d6a921..6a5e4257 100644
--- a/couchpotato/core/downloaders/utorrent/main.py
+++ b/couchpotato/core/downloaders/utorrent/main.py
@@ -115,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.')
@@ -322,3 +333,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'))
diff --git a/couchpotato/core/providers/torrent/ilovetorrents/main.py b/couchpotato/core/providers/torrent/ilovetorrents/main.py
index 74bf0c40..d15be35b 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 = [
diff --git a/couchpotato/core/providers/torrent/iptorrents/main.py b/couchpotato/core/providers/torrent/iptorrents/main.py
index b4e038ca..5c22ae04 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 = [
diff --git a/couchpotato/core/providers/torrent/thepiratebay/main.py b/couchpotato/core/providers/torrent/thepiratebay/main.py
index 8ccefeb1..e355813b 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):
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',
diff --git a/couchpotato/static/scripts/misc/downloaders.js b/couchpotato/static/scripts/misc/downloaders.js
new file mode 100644
index 00000000..5127275c
--- /dev/null
+++ b/couchpotato/static/scripts/misc/downloaders.js
@@ -0,0 +1,75 @@
+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;
+
+ 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 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);
+
+ },
+
+ testButtonName: function(fieldset){
+ var name = String(fieldset.getElement('h2').innerHTML).substring(0,String(fieldset.getElement('h2').innerHTML).indexOf("= MIN_RTORRENT_VERSION