diff --git a/couchpotato/core/providers/base.py b/couchpotato/core/providers/base.py index 50a659b0..c2187246 100644 --- a/couchpotato/core/providers/base.py +++ b/couchpotato/core/providers/base.py @@ -4,9 +4,11 @@ from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.environment import Env from urlparse import urlparse +import cookielib import re import time import traceback +import urllib2 log = CPLog(__name__) @@ -48,6 +50,8 @@ class YarrProvider(Provider): sizeMb = ['mb', 'mib'] sizeKb = ['kb', 'kib'] + login_opener = None + def __init__(self): addEvent('provider.belongs_to', self.belongsTo) @@ -56,6 +60,34 @@ class YarrProvider(Provider): addEvent('nzb.feed', self.feed) + def login(self): + + try: + cookiejar = cookielib.CookieJar() + opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar)) + urllib2.install_opener(opener) + log.info2('Logging into %s', self.urls['login']) + f = opener.open(self.urls['login'], self.getLoginParams()) + f.read() + f.close() + self.login_opener = opener + return True + except: + log.error('Failed to login %s: %s', (self.getName(), traceback.format_exc())) + + return False + + def loginDownload(self, url = '', nzb_id = ''): + try: + if not self.login_opener and not self.login(): + log.error('Failed downloading from %s', self.getName()) + return self.urlopen(url, opener = self.login_opener) + except: + log.error('Failed downloading from %s: %s', (self.getName(), traceback.format_exc())) + + def getLoginParams(self): + return '' + def download(self, url = '', nzb_id = ''): try: return self.urlopen(url, headers = {'User-Agent': Env.getIdentifier()}, show_error = False) diff --git a/couchpotato/core/providers/nzb/ftdworld/__init__.py b/couchpotato/core/providers/nzb/ftdworld/__init__.py new file mode 100644 index 00000000..e11f486a --- /dev/null +++ b/couchpotato/core/providers/nzb/ftdworld/__init__.py @@ -0,0 +1,31 @@ +from .main import FTDWorld + +def start(): + return FTDWorld() + +config = [{ + 'name': 'ftdworld', + 'groups': [ + { + 'tab': 'searcher', + 'subtab': 'nzb_providers', + 'name': 'FTDWorld', + 'description': 'Free provider, less accurate. See FTDWorld', + 'options': [ + { + 'name': 'enabled', + 'type': 'enabler', + }, + { + 'name': 'username', + 'default': '', + }, + { + 'name': 'password', + 'default': '', + 'type': 'password', + }, + ], + }, + ], +}] diff --git a/couchpotato/core/providers/nzb/ftdworld/main.py b/couchpotato/core/providers/nzb/ftdworld/main.py new file mode 100644 index 00000000..8b27e00b --- /dev/null +++ b/couchpotato/core/providers/nzb/ftdworld/main.py @@ -0,0 +1,107 @@ +from bs4 import BeautifulSoup +from couchpotato.core.event import fireEvent +from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode, \ + simplifyString +from couchpotato.core.helpers.variable import tryInt, getTitle +from couchpotato.core.logger import CPLog +from couchpotato.core.providers.nzb.base import NZBProvider +from couchpotato.environment import Env +from dateutil.parser import parse +import re +import time + +log = CPLog(__name__) + + +class FTDWorld(NZBProvider): + + urls = { + 'search': 'http://ftdworld.net/category.php?%s', + 'detail': 'http://ftdworld.net/spotinfo.php?id=%s', + 'download': 'http://ftdworld.net/cgi-bin/nzbdown.pl?fileID=%s', + 'login': 'http://ftdworld.net/index.php', + } + + http_time_between_calls = 1 #seconds + + cat_ids = [ + ([4, 11], ['dvdr']), + ([1], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr', 'brrip']), + ([10, 13, 14], ['bd50', '720p', '1080p']), + ] + cat_backup_id = [1] + + def search(self, movie, quality): + + results = [] + if self.isDisabled(): + return results + + q = '%s %s' % (simplifyString(getTitle(movie['library'])), movie['library']['year']) + + params = { + 'ctitle': q, + 'customQuery': 'usr', + 'cage': Env.setting('retention', 'nzb'), + 'csizemin': quality.get('size_min'), + 'csizemax': quality.get('size_max'), + 'ccategory': 14, + 'ctype': ','.join([str(x) for x in self.getCatId(quality['identifier'])]), + } + + cache_key = 'ftdworld.%s.%s' % (movie['library']['identifier'], q) + data = self.getCache(cache_key, self.urls['search'] % tryUrlencode(params), opener = self.login_opener) + + if data: + try: + + html = BeautifulSoup(data) + main_table = html.find('table', attrs = {'id':'ftdresult'}) + + if not main_table: + return results + + items = main_table.find_all('tr', attrs = {'class': re.compile('tcontent')}) + + for item in items: + tds = item.find_all('td') + nzb_id = tryInt(item.attrs['data-spot']) + + up = item.find('img', attrs = {'src': re.compile('up.png')}) + down = item.find('img', attrs = {'src': re.compile('down.png')}) + + new = { + 'id': nzb_id, + 'type': 'nzb', + 'provider': self.getName(), + 'name': toUnicode(item.find('a', attrs = {'href': re.compile('./spotinfo')}).text.strip()), + 'age': self.calculateAge(int(time.mktime(parse(tds[2].text).timetuple()))), + 'size': 0, + 'url': self.urls['download'] % nzb_id, + 'download': self.loginDownload, + 'detail_url': self.urls['detail'] % nzb_id, + 'description': '', + 'score': (tryInt(up.attrs['title'].split(' ')[0]) * 3) - (tryInt(down.attrs['title'].split(' ')[0]) * 3), + } + + is_correct_movie = fireEvent('searcher.correct_movie', + nzb = new, movie = movie, quality = quality, + imdb_results = False, single = True) + + if is_correct_movie: + new['score'] += fireEvent('score.calculate', new, movie, single = True) + results.append(new) + self.found(new) + + return results + except SyntaxError: + log.error('Failed to parse XML response from NZBClub') + + return results + + def getLoginParams(self): + return tryUrlencode({ + 'userlogin': self.conf('username'), + 'passlogin': self.conf('password'), + 'submit': 'Log In', + }) diff --git a/couchpotato/core/providers/nzb/newznab/__init__.py b/couchpotato/core/providers/nzb/newznab/__init__.py index b0e8b484..c9507f91 100644 --- a/couchpotato/core/providers/nzb/newznab/__init__.py +++ b/couchpotato/core/providers/nzb/newznab/__init__.py @@ -11,7 +11,9 @@ config = [{ 'subtab': 'nzb_providers', 'name': 'newznab', 'order': 10, - 'description': 'Enable multiple NewzNab providers such as NZB.su and nzbs.org', + 'description': 'Enable NewzNab providers such as NZB.su, \ + NZBs.org, DOGnzb.cr, \ + Spotweb', 'wizard': True, 'options': [ { diff --git a/couchpotato/core/providers/torrent/base.py b/couchpotato/core/providers/torrent/base.py index fc2d35e2..79d5b1e6 100644 --- a/couchpotato/core/providers/torrent/base.py +++ b/couchpotato/core/providers/torrent/base.py @@ -1,9 +1,6 @@ from couchpotato.core.helpers.variable import getImdb, md5 from couchpotato.core.logger import CPLog from couchpotato.core.providers.base import YarrProvider -import cookielib -import traceback -import urllib2 log = CPLog(__name__) @@ -11,7 +8,6 @@ log = CPLog(__name__) class TorrentProvider(YarrProvider): type = 'torrent' - login_opener = None def imdbMatch(self, url, imdbId): if getImdb(url) == imdbId: @@ -28,30 +24,3 @@ class TorrentProvider(YarrProvider): return getImdb(data) == imdbId return False - - def login(self): - - try: - cookiejar = cookielib.CookieJar() - opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar)) - urllib2.install_opener(opener) - f = opener.open(self.urls['login'], self.getLoginParams()) - f.read() - f.close() - self.login_opener = opener - return True - except: - log.error('Failed to login %s: %s', (self.getName(), traceback.format_exc())) - - return False - - def loginDownload(self, url = '', nzb_id = ''): - try: - if not self.login_opener and not self.login(): - log.error('Failed downloading from %s', self.getName()) - return self.urlopen(url, opener = self.login_opener) - except: - log.error('Failed downloading from %s: %s', (self.getName(), traceback.format_exc())) - - def getLoginParams(self): - return ''