Merge branch 'refs/heads/develop' into nosql

This commit is contained in:
Ruud
2014-02-24 22:54:04 +01:00
18 changed files with 269 additions and 34 deletions
@@ -49,6 +49,7 @@ class ClientScript(Plugin):
'scripts/page/settings.js', 'scripts/page/settings.js',
'scripts/page/about.js', 'scripts/page/about.js',
'scripts/page/manage.js', 'scripts/page/manage.js',
'scripts/misc/downloaders.js',
], ],
} }
+11
View File
@@ -1,4 +1,5 @@
from base64 import b32decode, b16encode from base64 import b32decode, b16encode
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent
from couchpotato.core.helpers.variable import mergeDicts from couchpotato.core.helpers.variable import mergeDicts
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
@@ -42,6 +43,7 @@ class Downloader(Provider):
addEvent('download.remove_failed', self._removeFailed) addEvent('download.remove_failed', self._removeFailed)
addEvent('download.pause', self._pause) addEvent('download.pause', self._pause)
addEvent('download.process_complete', self._processComplete) addEvent('download.process_complete', self._processComplete)
addApiView('download.%s.test' % self.getName().lower(), self._test)
def getEnabledProtocol(self): def getEnabledProtocol(self):
for download_protocol in self.protocol: for download_protocol in self.protocol:
@@ -158,6 +160,15 @@ class Downloader(Provider):
(d_manual and manual or d_manual is False) and \ (d_manual and manual or d_manual is False) and \
(not data or self.isCorrectProtocol(data.get('protocol'))) (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): def _pause(self, release_download, pause = True):
if self.isDisabled(manual = True, data = {}): if self.isDisabled(manual = True, data = {}):
return return
@@ -1,5 +1,6 @@
from __future__ import with_statement from __future__ import with_statement
from couchpotato.core.downloaders.base import Downloader from couchpotato.core.downloaders.base import Downloader
from couchpotato.core.helpers.encoding import sp
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.environment import Env from couchpotato.environment import Env
import os import os
@@ -67,6 +68,20 @@ class Blackhole(Downloader):
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
def getEnabledProtocol(self): def getEnabledProtocol(self):
if self.conf('use_for') == 'both': if self.conf('use_for') == 'both':
return super(Blackhole, self).getEnabledProtocol() return super(Blackhole, self).getEnabledProtocol()
+14 -2
View File
@@ -20,14 +20,14 @@ class Deluge(Downloader):
log = CPLog(__name__) log = CPLog(__name__)
drpc = None drpc = None
def connect(self): def connect(self, reconnect = False):
# Load host from config and split out port. # Load host from config and split out port.
host = cleanHost(self.conf('host'), protocol = False).split(':') host = cleanHost(self.conf('host'), protocol = False).split(':')
if not isInt(host[1]): if not isInt(host[1]):
log.error('Config properties are not filled in correctly, port is missing.') log.error('Config properties are not filled in correctly, port is missing.')
return False 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')) self.drpc = DelugeRPC(host[0], port = host[1], username = self.conf('username'), password = self.conf('password'))
return self.drpc return self.drpc
@@ -86,6 +86,11 @@ class Deluge(Downloader):
log.info('Torrent sent to Deluge successfully.') log.info('Torrent sent to Deluge successfully.')
return self.downloadReturnId(remote_torrent) return self.downloadReturnId(remote_torrent)
def test(self):
if self.connect(True) and self.drpc.test():
return True
return False
def getAllDownloadStatus(self, ids): def getAllDownloadStatus(self, ids):
log.debug('Checking Deluge download status.') log.debug('Checking Deluge download status.')
@@ -178,6 +183,13 @@ class DelugeRPC(object):
self.client = DelugeClient() self.client = DelugeClient()
self.client.connect(self.host, int(self.port), self.username, self.password) 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): def add_torrent_magnet(self, torrent, options):
torrent_id = False torrent_id = False
try: try:
+27 -7
View File
@@ -16,7 +16,6 @@ log = CPLog(__name__)
class NZBGet(Downloader): class NZBGet(Downloader):
protocol = ['nzb'] protocol = ['nzb']
rpc = 'xmlrpc' rpc = 'xmlrpc'
def download(self, data = None, media = None, filedata = None): 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)) 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 = self.getRPC()
rpc = xmlrpclib.ServerProxy(url)
try: try:
if rpc.writelog('INFO', 'CouchPotato connected to drop off %s.' % nzb_name): 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) log.error('NZBGet could not add %s to the queue.', nzb_name)
return False 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): def getAllDownloadStatus(self, ids):
log.debug('Checking NZBGet download status.') 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 = self.getRPC()
rpc = xmlrpclib.ServerProxy(url)
try: try:
if rpc.writelog('INFO', 'CouchPotato connected to check status'): 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']) 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 = self.getRPC()
rpc = xmlrpclib.ServerProxy(url)
try: try:
if rpc.writelog('INFO', 'CouchPotato connected to delete some history'): if rpc.writelog('INFO', 'CouchPotato connected to delete some history'):
@@ -194,3 +210,7 @@ class NZBGet(Downloader):
return False return False
return True 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)
@@ -42,6 +42,14 @@ class NZBVortex(Downloader):
log.error('Something went wrong sending the NZB file: %s', traceback.format_exc()) log.error('Something went wrong sending the NZB file: %s', traceback.format_exc())
return False return False
def test(self):
try:
login_result = self.login()
except:
return False
return login_result
def getAllDownloadStatus(self, ids): def getAllDownloadStatus(self, ids):
raw_statuses = self.call('nzb') raw_statuses = self.call('nzb')
@@ -1,5 +1,6 @@
from __future__ import with_statement from __future__ import with_statement
from couchpotato.core.downloaders.base import Downloader from couchpotato.core.downloaders.base import Downloader
from couchpotato.core.helpers.encoding import sp
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
import os import os
import traceback import traceback
@@ -56,3 +57,17 @@ class Pneumatic(Downloader):
log.info('Failed to download file %s: %s', (data.get('name'), traceback.format_exc())) log.info('Failed to download file %s: %s', (data.get('name'), traceback.format_exc()))
return False return False
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
+20 -3
View File
@@ -20,6 +20,7 @@ class rTorrent(Downloader):
protocol = ['torrent', 'torrent_magnet'] protocol = ['torrent', 'torrent_magnet']
rt = None rt = None
error_msg = ''
# Migration url to host options # Migration url to host options
def __init__(self): def __init__(self):
@@ -48,9 +49,9 @@ class rTorrent(Downloader):
self.rt = None self.rt = None
return True return True
def connect(self): def connect(self, reconnect = False):
# Already connected? # Already connected?
if self.rt is not None: if not reconnect and self.rt is not None:
return self.rt return self.rt
url = cleanHost(self.conf('host'), protocol = True, ssl = self.conf('ssl')) url = cleanHost(self.conf('host'), protocol = True, ssl = self.conf('ssl'))
@@ -69,9 +70,25 @@ class rTorrent(Downloader):
else: else:
self.rt = RTorrent(url) 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 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'): if data.get('seed_time'):
log.info('seeding time ignored, not supported') log.info('seeding time ignored, not supported')
@@ -64,6 +64,26 @@ class Sabnzbd(Downloader):
log.error('Error getting data from SABNZBd: %s', sab_data) log.error('Error getting data from SABNZBd: %s', sab_data)
return False 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): def getAllDownloadStatus(self, ids):
log.debug('Checking SABnzbd download status.') log.debug('Checking SABnzbd download status.')
@@ -45,6 +45,16 @@ class Synology(Downloader):
finally: finally:
return self.downloadReturnId('') if response else False 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): def getEnabledProtocol(self):
if self.conf('use_for') == 'both': if self.conf('use_for') == 'both':
return super(Synology, self).getEnabledProtocol() return super(Synology, self).getEnabledProtocol()
@@ -147,3 +157,6 @@ class SynologyRPC(object):
self._logout() self._logout()
return result return result
def test(self):
return bool(self._login())
@@ -19,14 +19,14 @@ class Transmission(Downloader):
log = CPLog(__name__) log = CPLog(__name__)
trpc = None trpc = None
def connect(self): def connect(self, reconnect = False):
# Load host from config and split out port. # Load host from config and split out port.
host = cleanHost(self.conf('host'), protocol = False).split(':') host = cleanHost(self.conf('host'), protocol = False).split(':')
if not isInt(host[1]): if not isInt(host[1]):
log.error('Config properties are not filled in correctly, port is missing.') log.error('Config properties are not filled in correctly, port is missing.')
return False 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')) 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 return self.trpc
@@ -83,6 +83,11 @@ class Transmission(Downloader):
log.info('Torrent sent to Transmission successfully.') log.info('Torrent sent to Transmission successfully.')
return self.downloadReturnId(remote_torrent['torrent-added']['hashString']) 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): def getAllDownloadStatus(self, ids):
log.debug('Checking Transmission download status.') log.debug('Checking Transmission download status.')
@@ -115,6 +115,17 @@ class uTorrent(Downloader):
return self.downloadReturnId(torrent_hash) 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): def getAllDownloadStatus(self, ids):
log.debug('Checking uTorrent download status.') log.debug('Checking uTorrent download status.')
@@ -322,3 +333,10 @@ class uTorrentAPI(object):
def get_files(self, hash): def get_files(self, hash):
action = 'action=getfiles&hash=%s' % hash action = 'action=getfiles&hash=%s' % hash
return self._request(action) 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'))
@@ -12,12 +12,12 @@ log = CPLog(__name__)
class ILoveTorrents(TorrentProvider): class ILoveTorrents(TorrentProvider):
urls = { urls = {
'download': 'http://www.ilovetorrents.me/%s', 'download': 'https://www.ilovetorrents.me/%s',
'detail': 'http://www.ilovetorrents.me/%s', 'detail': 'https//www.ilovetorrents.me/%s',
'search': 'http://www.ilovetorrents.me/browse.php?search=%s&page=%s&cat=%s', 'search': 'https://www.ilovetorrents.me/browse.php?search=%s&page=%s&cat=%s',
'test': 'http://www.ilovetorrents.me/', 'test': 'https://www.ilovetorrents.me/',
'login': 'http://www.ilovetorrents.me/takelogin.php', 'login': 'https://www.ilovetorrents.me/takelogin.php',
'login_check': 'http://www.ilovetorrents.me' 'login_check': 'https://www.ilovetorrents.me'
} }
cat_ids = [ cat_ids = [
@@ -11,11 +11,11 @@ log = CPLog(__name__)
class IPTorrents(TorrentProvider): class IPTorrents(TorrentProvider):
urls = { urls = {
'test': 'http://www.iptorrents.com/', 'test': 'https://www.iptorrents.com/',
'base_url': 'http://www.iptorrents.com', 'base_url': 'https://www.iptorrents.com',
'login': 'http://www.iptorrents.com/torrents/', 'login': 'https://www.iptorrents.com/torrents/',
'login_check': 'http://www.iptorrents.com/inbox.php', 'login_check': 'https://www.iptorrents.com/inbox.php',
'search': 'http://www.iptorrents.com/torrents/?l%d=1%s&q=%s&qf=ti&p=%d', 'search': 'https://www.iptorrents.com/torrents/?l%d=1%s&q=%s&qf=ti&p=%d',
} }
cat_ids = [ cat_ids = [
@@ -31,15 +31,13 @@ class ThePirateBay(TorrentMagnetProvider):
proxy_list = [ proxy_list = [
'https://tpb.ipredator.se', 'https://tpb.ipredator.se',
'https://thepiratebay.se', 'https://thepiratebay.se',
'https://depiraatbaai.be', 'http://pirateproxy.ca',
'https://piratereverse.info', 'http://tpb.al',
'https://tpb.pirateparty.org.uk', 'http://www.tpb.gr',
'https://argumentomteemigreren.nl', 'http://nl.tpb.li',
'https://livepirate.com', 'http://proxybay.eu',
'https://www.getpirate.com', 'https://www.getpirate.com',
'https://tpb.partipirate.org', 'http://pirateproxy.ca',
'https://tpb.piraten.lu',
'https://kuiken.co',
] ]
def _searchOnTitle(self, title, movie, quality, results): def _searchOnTitle(self, title, movie, quality, results):
@@ -11,7 +11,7 @@ config = [{
'tab': 'searcher', 'tab': 'searcher',
'list': 'torrent_providers', 'list': 'torrent_providers',
'name': 'TorrentShack', 'name': 'TorrentShack',
'description': 'See <a href="http://www.torrentshack.net/">TorrentShack</a>', 'description': 'See <a href="https://www.torrentshack.net/">TorrentShack</a>',
'options': [ 'options': [
{ {
'name': 'enabled', 'name': 'enabled',
@@ -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("<span"));
return 'Test '+name;
},
});
window.Downloaders = new DownloadersBase();
+7
View File
@@ -111,6 +111,13 @@ class RTorrent:
"Error: Minimum rTorrent version required is {0}".format( "Error: Minimum rTorrent version required is {0}".format(
MIN_RTORRENT_VERSION_STR) MIN_RTORRENT_VERSION_STR)
def test_connection(self):
try:
self._verify_conn()
except:
return False
return True
def _meets_version_requirement(self): def _meets_version_requirement(self):
return self._get_client_version_tuple() >= MIN_RTORRENT_VERSION return self._get_client_version_tuple() >= MIN_RTORRENT_VERSION