diff --git a/couchpotato/core/downloaders/__init__.py b/couchpotato/core/downloaders/__init__.py index 5fb7125f..a81ce881 100644 --- a/couchpotato/core/downloaders/__init__.py +++ b/couchpotato/core/downloaders/__init__.py @@ -1,4 +1,4 @@ -config = { +config = [{ 'name': 'download_providers', 'groups': [ { @@ -10,4 +10,4 @@ config = { 'options': [], }, ], -} +}] diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index 5ff33c05..1c359967 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -136,11 +136,11 @@ class Transmission(Downloader): def removeFailed(self, item): log.info('%s failed downloading, deleting...', item['name']) - return self.trpc.remove_torrent(item['hashString'], True) + return self.trpc.remove_torrent(item['id'], True) def processComplete(self, item, delete_files = False): log.debug('Requesting Transmission to remove the torrent %s%s.', (item['name'], ' and cleanup the downloaded files' if delete_files else '')) - return self.trpc.remove_torrent(item['hashString'], delete_files) + return self.trpc.remove_torrent(item['id'], delete_files) class TransmissionRPC(object): diff --git a/couchpotato/core/downloaders/utorrent/main.py b/couchpotato/core/downloaders/utorrent/main.py index ce82c8c2..d5262e23 100644 --- a/couchpotato/core/downloaders/utorrent/main.py +++ b/couchpotato/core/downloaders/utorrent/main.py @@ -107,9 +107,9 @@ class uTorrent(Downloader): count += 1 # Check if torrent is saved in subfolder of torrent name - data = self.utorrent_api.get_files(torrent_hash) + getfiles_data = self.utorrent_api.get_files(torrent_hash) - torrent_files = json.loads(data) + torrent_files = json.loads(getfiles_data) if torrent_files.get('error'): log.error('Error getting data from uTorrent: %s', torrent_files.get('error')) return False @@ -200,7 +200,7 @@ class uTorrent(Downloader): if not self.connect(): return False return self.utorrent_api.remove_torrent(item['id'], remove_data = delete_files) - + def removeReadOnly(self, folder): #Removes all read-only flags in a folder if folder and os.path.isdir(folder): diff --git a/couchpotato/core/loader.py b/couchpotato/core/loader.py index 2016d287..9362bb8c 100644 --- a/couchpotato/core/loader.py +++ b/couchpotato/core/loader.py @@ -1,6 +1,5 @@ from couchpotato.core.event import fireEvent from couchpotato.core.logger import CPLog -import glob import os import traceback @@ -81,17 +80,10 @@ class Loader(object): def addFromDir(self, plugin_type, priority, module, dir_name): # Load dir module - try: - m = __import__(module) - splitted = module.split('.') - for sub in splitted[1:]: - m = getattr(m, sub) - except: - raise + self.addModule(priority, plugin_type, module, os.path.basename(dir_name)) - for cur_file in glob.glob(os.path.join(dir_name, '*')): - name = os.path.basename(cur_file) - if os.path.isdir(os.path.join(dir_name, name)) and name != 'static' and os.path.isfile(os.path.join(cur_file, '__init__.py')): + for name in os.listdir(dir_name): + if os.path.isdir(os.path.join(dir_name, name)) and name != 'static' and os.path.isfile(os.path.join(dir_name, name, '__init__.py')): module_name = '%s.%s' % (module, name) self.addModule(priority, plugin_type, module_name, name) diff --git a/couchpotato/core/notifications/__init__.py b/couchpotato/core/notifications/__init__.py index 8ac24dfb..5958fe66 100644 --- a/couchpotato/core/notifications/__init__.py +++ b/couchpotato/core/notifications/__init__.py @@ -1,4 +1,4 @@ -config = { +config = [{ 'name': 'notification_providers', 'groups': [ { @@ -10,4 +10,4 @@ config = { 'options': [], }, ], -} +}] diff --git a/couchpotato/core/notifications/email/main.py b/couchpotato/core/notifications/email/main.py index f94688d5..508e0823 100644 --- a/couchpotato/core/notifications/email/main.py +++ b/couchpotato/core/notifications/email/main.py @@ -2,6 +2,7 @@ from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.variable import splitString from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification +from couchpotato.environment import Env from email.mime.text import MIMEText import smtplib import traceback @@ -23,7 +24,7 @@ class Email(Notification): smtp_pass = self.conf('smtp_pass') # Make the basic message - message = MIMEText(toUnicode(message)) + message = MIMEText(toUnicode(message), _charset = Env.get('encoding')) message['Subject'] = self.default_title message['From'] = from_address message['To'] = to_address diff --git a/couchpotato/core/notifications/plex/__init__.py b/couchpotato/core/notifications/plex/__init__.py old mode 100644 new mode 100755 index c00ea6d4..d68ddb19 --- a/couchpotato/core/notifications/plex/__init__.py +++ b/couchpotato/core/notifications/plex/__init__.py @@ -17,10 +17,15 @@ config = [{ 'type': 'enabler', }, { - 'name': 'host', + 'name': 'media_server', + 'label': 'Media Server', 'default': 'localhost', - 'description': 'Default should be on localhost', - 'advanced': True, + 'description': 'Hostname/IP, default localhost' + }, + { + 'name': 'clients', + 'default': '', + 'description': 'Comma separated list of client names\'s (computer names). Top right when you start Plex' }, { 'name': 'on_snatch', diff --git a/couchpotato/core/notifications/plex/main.py b/couchpotato/core/notifications/plex/main.py old mode 100644 new mode 100755 index f6088f5b..5558289d --- a/couchpotato/core/notifications/plex/main.py +++ b/couchpotato/core/notifications/plex/main.py @@ -1,79 +1,184 @@ from couchpotato.core.event import addEvent from couchpotato.core.helpers.encoding import tryUrlencode -from couchpotato.core.helpers.variable import cleanHost, splitString +from couchpotato.core.helpers.variable import cleanHost from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification -from urllib2 import URLError +from datetime import datetime from urlparse import urlparse from xml.dom import minidom +import json +import requests import traceback +try: + import xml.etree.cElementTree as etree +except ImportError: + import xml.etree.ElementTree as etree + log = CPLog(__name__) class Plex(Notification): + client_update_time = 5 * 60 + http_time_between_calls = 0 + def __init__(self): super(Plex, self).__init__() + + self.clients = {} + self.clients_updated = None + addEvent('renamer.after', self.addToLibrary) - def addToLibrary(self, message = None, group = None): + def updateClients(self, force = False): + if not self.conf('media_server'): + log.warning("Plex media server hostname is required") + return + + since_update = ((datetime.now() - self.clients_updated).total_seconds())\ + if self.clients_updated is not None else None + + if force or self.clients_updated is None or since_update > self.client_update_time: + self.clients = {} + + data = self.urlopen('%s/clients' % self.createHost(self.conf('media_server'), port = 32400)) + client_result = etree.fromstring(data) + + clients = [x.strip().lower() for x in self.conf('clients').split(',')] + + for server in client_result.findall('Server'): + if server.get('name').lower() in clients: + clients.remove(server.get('name').lower()) + protocol = server.get('protocol', 'xbmchttp') + + if protocol in ['xbmcjson', 'xbmchttp']: + self.clients[server.get('name')] = { + 'name': server.get('name'), + 'address': server.get('address'), + 'port': server.get('port'), + 'protocol': protocol + } + + if len(clients) > 0: + log.info2('Unable to find plex clients: %s', ', '.join(clients)) + + log.info2('Found hosts: %s', ', '.join(self.clients.keys())) + + self.clients_updated = datetime.now() + + + def addToLibrary(self, message = None, group = {}): if self.isDisabled(): return - if not group: group = {} log.info('Sending notification to Plex') - hosts = self.getHosts(port = 32400) - for host in hosts: + source_type = ['movie'] + base_url = '%s/library/sections' % self.createHost(self.conf('media_server'), port = 32400) + refresh_url = '%s/%%s/refresh' % base_url - source_type = ['movie'] - base_url = '%s/library/sections' % host - refresh_url = '%s/%%s/refresh' % base_url + try: + sections_xml = self.urlopen(base_url) + xml_sections = minidom.parseString(sections_xml) + sections = xml_sections.getElementsByTagName('Directory') - try: - sections_xml = self.urlopen(base_url) - xml_sections = minidom.parseString(sections_xml) - sections = xml_sections.getElementsByTagName('Directory') + for s in sections: + if s.getAttribute('type') in source_type: + url = refresh_url % s.getAttribute('key') + x = self.urlopen(url) - for s in sections: - if s.getAttribute('type') in source_type: - url = refresh_url % s.getAttribute('key') - self.urlopen(url) - - except: - log.error('Plex library update failed for %s, Media Server not running: %s', (host, traceback.format_exc(1))) - return False + except: + log.error('Plex library update failed for %s, Media Server not running: %s', + (self.conf('media_server'), traceback.format_exc(1))) + return False return True - def notify(self, message = '', data = None, listener = None): - if not data: data = {} + def sendHTTP(self, command, client): + url = 'http://%s:%s/xbmcCmds/xbmcHttp/?%s' % ( + client['address'], + client['port'], + tryUrlencode(command) + ) - hosts = self.getHosts(port = 3000) - successful = 0 - for host in hosts: - if self.send({'command': 'ExecBuiltIn', 'parameter': 'Notification(CouchPotato, %s)' % message}, host): - successful += 1 - - return successful == len(hosts) - - def send(self, command, host): - - url = '%s/xbmcCmds/xbmcHttp/?%s' % (host, tryUrlencode(command)) headers = {} try: - self.urlopen(url, headers = headers, show_error = False) - except URLError: - log.error("Couldn't sent command to Plex, probably just running Media Server") - return False - except: - log.error("Couldn't sent command to Plex: %s", traceback.format_exc()) + self.urlopen(url, headers = headers, timeout = 3, show_error = False) + except Exception, err: + log.error("Couldn't sent command to Plex: %s", err) return False - log.info('Plex notification to %s successful.', host) return True + def notifyHTTP(self, message = '', data = {}, listener = None): + total = 0 + successful = 0 + + data = { + 'command': 'ExecBuiltIn', + 'parameter': 'Notification(CouchPotato, %s)' % message + } + + for name, client in self.clients.items(): + if client['protocol'] == 'xbmchttp': + total += 1 + if self.sendHTTP(data, client): + successful += 1 + + return successful == total + + def sendJSON(self, method, params, client): + log.debug('sendJSON("%s", %s, %s)', (method, params, client)) + url = 'http://%s:%s/jsonrpc' % ( + client['address'], + client['port'] + ) + + headers = { + 'Content-Type': 'application/json' + } + + request = { + 'id':1, + 'jsonrpc': '2.0', + 'method': method, + 'params': params + } + + try: + requests.post(url, headers = headers, timeout = 3, data = json.dumps(request)) + except Exception, err: + log.error("Couldn't sent command to Plex: %s", err) + return False + + return True + + def notifyJSON(self, message = '', data = {}, listener = None): + total = 0 + successful = 0 + + params = { + 'title': 'CouchPotato', + 'message': message + } + + for name, client in self.clients.items(): + if client['protocol'] == 'xbmcjson': + total += 1 + if self.sendJSON('GUI.ShowNotification', params, client): + successful += 1 + + return successful == total + + def notify(self, message = '', data = {}, listener = None, force = False): + self.updateClients(force) + + http_result = self.notifyHTTP(message, data, listener) + json_result = self.notifyJSON(message, data, listener) + + return http_result and json_result + def test(self, **kwargs): test_type = self.testNotifyName() @@ -83,7 +188,8 @@ class Plex(Notification): success = self.notify( message = self.test_message, data = {}, - listener = 'test' + listener = 'test', + force = True ) success2 = self.addToLibrary() @@ -91,17 +197,12 @@ class Plex(Notification): 'success': success or success2 } - def getHosts(self, port = None): + def createHost(self, host, port = None): - raw_hosts = splitString(self.conf('host')) - hosts = [] + h = cleanHost(host) + p = urlparse(h) + h = h.rstrip('/') + if port and not p.port: + h += ':%s' % port - for h in raw_hosts: - h = cleanHost(h) - p = urlparse(h) - h = h.rstrip('/') - if port and not p.port: - h += ':%s' % port - hosts.append(h) - - return hosts + return h diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index ce7c1b49..c90c48c6 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -121,7 +121,7 @@ class Plugin(object): # http request def urlopen(self, url, timeout = 30, params = None, headers = None, opener = None, multipart = False, show_error = True): - url = ss(url) + url = urllib2.quote(ss(url), safe = "%/:=&?~#+!$,;'@()*[]") if not headers: headers = {} if not params: params = {} diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 1149c036..e12a712a 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -1,7 +1,7 @@ from couchpotato import get_session from couchpotato.api import addApiView from couchpotato.core.event import addEvent -from couchpotato.core.helpers.encoding import toUnicode +from couchpotato.core.helpers.encoding import toUnicode, ss from couchpotato.core.helpers.variable import mergeDicts, md5, getExt from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin @@ -192,15 +192,19 @@ class QualityPlugin(Plugin): return None def containsTag(self, quality, words, cur_file = ''): + cur_file = ss(cur_file) # Check alt and tags - for tag_type in ['alternative', 'tags']: - for alt in quality.get(tag_type, []): - if isinstance(alt, tuple) and '.'.join(alt) in '.'.join(words): + for tag_type in ['alternative', 'tags', 'label']: + qualities = quality.get(tag_type, []) + qualities = [qualities] if isinstance(qualities, (str, unicode)) else qualities + + for alt in qualities: + if (isinstance(alt, tuple) and '.'.join(alt) in '.'.join(words)) or (isinstance(alt, (str, unicode)) and ss(alt.lower()) in cur_file.lower()): log.debug('Found %s via %s %s in %s', (quality['identifier'], tag_type, quality.get(tag_type), cur_file)) return True - if list(set(quality.get(tag_type, [])) & set(words)): + if list(set(qualities) & set(words)): log.debug('Found %s via %s %s in %s', (quality['identifier'], tag_type, quality.get(tag_type), cur_file)) return True diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index 0662d008..9990bda7 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -1,7 +1,8 @@ from couchpotato import get_session from couchpotato.core.event import fireEvent, addEvent from couchpotato.core.helpers.encoding import toUnicode, simplifyString, ss -from couchpotato.core.helpers.variable import getExt, getImdb, tryInt +from couchpotato.core.helpers.variable import getExt, getImdb, tryInt, \ + splitString from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import File, Movie @@ -741,9 +742,14 @@ class Scanner(Plugin): def createStringIdentifier(self, file_path, folder = '', exclude_filename = False): - identifier = file_path.replace(folder, '') # root folder + year = self.findYear(file_path) + + identifier = file_path.replace(folder, '').lstrip(os.path.sep) # root folder identifier = os.path.splitext(identifier)[0] # ext + path_split = splitString(identifier, os.path.sep) + identifier = path_split[-2] if len(path_split) > 1 and len(path_split[-2]) > len(path_split[-1]) else path_split[-1] # Only get filename + if exclude_filename: identifier = identifier[:len(identifier) - len(os.path.split(identifier)[-1])] @@ -757,7 +763,6 @@ class Scanner(Plugin): identifier = re.sub(self.clean, '::', simplifyString(identifier)).strip(':') # Year - year = self.findYear(identifier) if year and identifier[:4] != year: identifier = '%s %s' % (identifier.split(year)[0].strip(), year) else: diff --git a/couchpotato/core/providers/automation/__init__.py b/couchpotato/core/providers/automation/__init__.py index a217948a..93f6c10a 100644 --- a/couchpotato/core/providers/automation/__init__.py +++ b/couchpotato/core/providers/automation/__init__.py @@ -1,4 +1,4 @@ -config = { +config = [{ 'name': 'automation_providers', 'groups': [ { @@ -18,4 +18,4 @@ config = { 'options': [], }, ], -} +}] diff --git a/couchpotato/core/providers/automation/bluray/__init__.py b/couchpotato/core/providers/automation/bluray/__init__.py index e0675247..ed270056 100644 --- a/couchpotato/core/providers/automation/bluray/__init__.py +++ b/couchpotato/core/providers/automation/bluray/__init__.py @@ -18,6 +18,13 @@ config = [{ 'default': False, 'type': 'enabler', }, + { + 'name': 'backlog', + 'advanced': True, + 'description': 'Parses the history until the minimum movie year is reached. (Will be disabled once it has completed)', + 'default': False, + 'type': 'bool', + }, ], }, ], diff --git a/couchpotato/core/providers/automation/bluray/main.py b/couchpotato/core/providers/automation/bluray/main.py index 235a1e5f..d98557ec 100644 --- a/couchpotato/core/providers/automation/bluray/main.py +++ b/couchpotato/core/providers/automation/bluray/main.py @@ -1,3 +1,4 @@ +from bs4 import BeautifulSoup from couchpotato.core.helpers.rss import RSS from couchpotato.core.helpers.variable import tryInt from couchpotato.core.logger import CPLog @@ -10,11 +11,49 @@ class Bluray(Automation, RSS): interval = 1800 rss_url = 'http://www.blu-ray.com/rss/newreleasesfeed.xml' + backlog_url = 'http://www.blu-ray.com/movies/movies.php?show=newreleases&page=%s' def getIMDBids(self): movies = [] + if self.conf('backlog'): + + page = 0 + while True: + page = page + 1 + + url = self.backlog_url % page + data = self.getHTMLData(url) + soup = BeautifulSoup(data) + + try: + # Stop if the release year is before the minimal year + page_year = soup.body.find_all('center')[3].table.tr.find_all('td', recursive = False)[3].h3.get_text().split(', ')[1] + if tryInt(page_year) < self.getMinimal('year'): + break + + for table in soup.body.find_all('center')[3].table.tr.find_all('td', recursive = False)[3].find_all('table')[1:20]: + name = table.h3.get_text().lower().split('blu-ray')[0].strip() + year = table.small.get_text().split('|')[1].strip() + + if not name.find('/') == -1: # make sure it is not a double movie release + continue + + if tryInt(year) < self.getMinimal('year'): + continue + + imdb = self.search(name, year) + + if imdb: + if self.isMinimalMovie(imdb): + movies.append(imdb['imdb']) + except: + log.debug('Error loading page: %s', page) + break + + self.conf('backlog', value = False) + rss_movies = self.getRSSData(self.rss_url) for movie in rss_movies: diff --git a/couchpotato/core/providers/automation/flixster/__init__.py b/couchpotato/core/providers/automation/flixster/__init__.py new file mode 100644 index 00000000..1c6c4590 --- /dev/null +++ b/couchpotato/core/providers/automation/flixster/__init__.py @@ -0,0 +1,34 @@ +from .main import Flixster + +def start(): + return Flixster() + +config = [{ + 'name': 'flixster', + 'groups': [ + { + 'tab': 'automation', + 'list': 'watchlist_providers', + 'name': 'flixster_automation', + 'label': 'Flixster', + 'description': 'Import movies from any public Flixster watchlist', + 'options': [ + { + 'name': 'automation_enabled', + 'default': False, + 'type': 'enabler', + }, + { + 'name': 'automation_ids_use', + 'label': 'Use', + }, + { + 'name': 'automation_ids', + 'label': 'User ID', + 'type': 'combined', + 'combine': ['automation_ids_use', 'automation_ids'], + }, + ], + }, + ], +}] diff --git a/couchpotato/core/providers/automation/flixster/main.py b/couchpotato/core/providers/automation/flixster/main.py new file mode 100644 index 00000000..46dcfba3 --- /dev/null +++ b/couchpotato/core/providers/automation/flixster/main.py @@ -0,0 +1,48 @@ +from couchpotato.core.helpers.variable import tryInt, splitString +from couchpotato.core.logger import CPLog +from couchpotato.core.providers.automation.base import Automation +import json + +log = CPLog(__name__) + + +class Flixster(Automation): + + url = 'http://www.flixster.com/api/users/%s/movies/ratings?scoreTypes=wts' + + interval = 60 + + def getIMDBids(self): + + ids = splitString(self.conf('automation_ids')) + + if len(ids) == 0: + return [] + + movies = [] + + for movie in self.getWatchlist(): + imdb_id = self.search(movie.get('title'), movie.get('year'), imdb_only = True) + movies.append(imdb_id) + + return movies + + def getWatchlist(self): + + enablers = [tryInt(x) for x in splitString(self.conf('automation_ids_use'))] + ids = splitString(self.conf('automation_ids')) + + index = -1 + movies = [] + for user_id in ids: + + index += 1 + if not enablers[index]: + continue + + data = json.loads(self.getHTMLData(self.url % user_id)) + + for movie in data: + movies.append({'title': movie['movie']['title'], 'year': movie['movie']['year'] }) + + return movies diff --git a/couchpotato/core/providers/nzb/__init__.py b/couchpotato/core/providers/nzb/__init__.py index 36098bb3..88d9865d 100644 --- a/couchpotato/core/providers/nzb/__init__.py +++ b/couchpotato/core/providers/nzb/__init__.py @@ -1,4 +1,4 @@ -config = { +config = [{ 'name': 'nzb_providers', 'groups': [ { @@ -11,4 +11,4 @@ config = { 'options': [], }, ], -} +}] diff --git a/couchpotato/core/providers/torrent/__init__.py b/couchpotato/core/providers/torrent/__init__.py index 250bcead..12dda708 100644 --- a/couchpotato/core/providers/torrent/__init__.py +++ b/couchpotato/core/providers/torrent/__init__.py @@ -1,4 +1,4 @@ -config = { +config = [{ 'name': 'torrent_providers', 'groups': [ { @@ -11,4 +11,4 @@ config = { 'options': [], }, ], -} +}] diff --git a/couchpotato/core/providers/torrent/torrentshack/main.py b/couchpotato/core/providers/torrent/torrentshack/main.py index 353b606e..6b3b5548 100644 --- a/couchpotato/core/providers/torrent/torrentshack/main.py +++ b/couchpotato/core/providers/torrent/torrentshack/main.py @@ -15,7 +15,7 @@ class TorrentShack(TorrentProvider): 'login' : 'https://torrentshack.net/login.php', 'login_check': 'https://torrentshack.net/inbox.php', 'detail' : 'https://torrentshack.net/torrent/%s', - 'search' : 'https://torrentshack.net/torrents.php?searchstr=%s&filter_cat[%d]=1', + 'search' : 'https://torrentshack.net/torrents.php?action=advanced&searchstr=%s&scene=%s&filter_cat[%d]=1', 'download' : 'https://torrentshack.net/%s', } @@ -31,7 +31,9 @@ class TorrentShack(TorrentProvider): def _searchOnTitle(self, title, movie, quality, results): - url = self.urls['search'] % (tryUrlencode('"%s" %s' % (title.replace(':', ''), movie['library']['year'])), self.getCatId(quality['identifier'])[0]) + scene_only = '1' if self.conf('scene_only') else '' + + url = self.urls['search'] % (tryUrlencode('%s %s' % (title.replace(':', ''), movie['library']['year'])), scene_only, self.getCatId(quality['identifier'])[0]) data = self.getHTMLData(url, opener = self.login_opener) if data: @@ -49,22 +51,15 @@ class TorrentShack(TorrentProvider): link = result.find('span', attrs = {'class' : 'torrent_name_link'}).parent url = result.find('td', attrs = {'class' : 'torrent_td'}).find('a') - extra_info = '' - if result.find('span', attrs = {'class' : 'torrent_extra_info'}): - extra_info = result.find('span', attrs = {'class' : 'torrent_extra_info'}).text - - if not self.conf('scene_only') or extra_info != '[NotScene]': - results.append({ - 'id': link['href'].replace('torrents.php?torrentid=', ''), - 'name': unicode(link.span.string).translate({ord(u'\xad'): None}), - 'url': self.urls['download'] % url['href'], - 'detail_url': self.urls['download'] % link['href'], - 'size': self.parseSize(result.find_all('td')[4].string), - 'seeders': tryInt(result.find_all('td')[6].string), - 'leechers': tryInt(result.find_all('td')[7].string), - }) - else: - log.info('Not adding release %s [NotScene]' % unicode(link.span.string).translate({ord(u'\xad'): None})) + results.append({ + 'id': link['href'].replace('torrents.php?torrentid=', ''), + 'name': unicode(link.span.string).translate({ord(u'\xad'): None}), + 'url': self.urls['download'] % url['href'], + 'detail_url': self.urls['download'] % link['href'], + 'size': self.parseSize(result.find_all('td')[4].string), + 'seeders': tryInt(result.find_all('td')[6].string), + 'leechers': tryInt(result.find_all('td')[7].string), + }) except: log.error('Failed to parsing %s: %s', (self.getName(), traceback.format_exc())) diff --git a/libs/synchronousdeluge/client.py b/libs/synchronousdeluge/client.py index 98a80848..22419e80 100644 --- a/libs/synchronousdeluge/client.py +++ b/libs/synchronousdeluge/client.py @@ -1,4 +1,5 @@ import os +import platform from collections import defaultdict from itertools import imap @@ -23,22 +24,48 @@ class DelugeClient(object): self._request_counter = 0 def _get_local_auth(self): - xdg_config = os.path.expanduser(os.environ.get("XDG_CONFIG_HOME", "~/.config")) - config_home = os.path.join(xdg_config, "deluge") - auth_file = os.path.join(config_home, "auth") - + auth_file = "" username = password = "" - with open(auth_file) as fd: - for line in fd: + if platform.system() in ('Windows', 'Microsoft'): + appDataPath = os.environ.get("APPDATA") + if not appDataPath: + import _winreg + hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") + appDataReg = _winreg.QueryValueEx(hkey, "AppData") + appDataPath = appDataReg[0] + _winreg.CloseKey(hkey) + + auth_file = os.path.join(appDataPath, "deluge", "auth") + else: + from xdg.BaseDirectory import save_config_path + try: + auth_file = os.path.join(save_config_path("deluge"), "auth") + except OSError, e: + return username, password + + + if os.path.exists(auth_file): + for line in open(auth_file): if line.startswith("#"): + # This is a comment line + continue + line = line.strip() + try: + lsplit = line.split(":") + except Exception, e: continue - auth = line.split(":") - if len(auth) >= 2 and auth[0] == "localclient": - username, password = auth[0], auth[1] - break + if len(lsplit) == 2: + username, password = lsplit + elif len(lsplit) == 3: + username, password, level = lsplit + else: + continue - return username, password + if username == "localclient": + return (username, password) + + return ("", "") def _create_module_method(self, module, method): fullname = "{0}.{1}".format(module, method)