From 5cf4b8b4d30257543757db4cf2fe9502a4b9c73c Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 28 Dec 2012 23:01:35 +0100 Subject: [PATCH] Binsearch provider --- .../core/providers/nzb/binsearch/__init__.py | 22 +++++ couchpotato/core/providers/nzb/binsearch/main.py | 99 ++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 couchpotato/core/providers/nzb/binsearch/__init__.py create mode 100644 couchpotato/core/providers/nzb/binsearch/main.py diff --git a/couchpotato/core/providers/nzb/binsearch/__init__.py b/couchpotato/core/providers/nzb/binsearch/__init__.py new file mode 100644 index 0000000..42281ec --- /dev/null +++ b/couchpotato/core/providers/nzb/binsearch/__init__.py @@ -0,0 +1,22 @@ +from .main import BinSearch + +def start(): + return BinSearch() + +config = [{ + 'name': 'binsearch', + 'groups': [ + { + 'tab': 'searcher', + 'subtab': 'nzb_providers', + 'name': 'binsearch', + 'description': 'Free provider, less accurate. See BinSearch', + 'options': [ + { + 'name': 'enabled', + 'type': 'enabler', + }, + ], + }, + ], +}] diff --git a/couchpotato/core/providers/nzb/binsearch/main.py b/couchpotato/core/providers/nzb/binsearch/main.py new file mode 100644 index 0000000..a7e27b5 --- /dev/null +++ b/couchpotato/core/providers/nzb/binsearch/main.py @@ -0,0 +1,99 @@ +from bs4 import BeautifulSoup +from couchpotato.core.helpers.encoding import tryUrlencode +from couchpotato.core.helpers.variable import tryInt +from couchpotato.core.logger import CPLog +from couchpotato.core.providers.nzb.base import NZBProvider +from couchpotato.environment import Env +import re +import traceback + +log = CPLog(__name__) + + +class BinSearch(NZBProvider): + + urls = { + 'download': 'https://www.binsearch.info/fcgi/nzb.fcgi?q=%s', + 'detail': 'https://www.binsearch.info%s', + 'search': 'https://www.binsearch.info/index.php?%s', + } + + http_time_between_calls = 4 # Seconds + + def _search(self, movie, quality, results): + + q = '%s %s' % (movie['library']['identifier'], quality.get('identifier')) + arguments = tryUrlencode({ + 'q': q, + 'm': 'n', + 'max': 250, + 'adv_age': Env.setting('retention', 'nzb'), + 'adv_sort': 'date', + 'adv_col': 'on', + 'adv_nfo': 'on', + 'minsize': quality.get('size_min'), + 'maxsize': quality.get('size_max'), + }) + + data = self.getHTMLData(self.urls['search'] % arguments) + + if data: + try: + + html = BeautifulSoup(data) + main_table = html.find('table', attrs = {'id':'r2'}) + + if not main_table: + return + + items = main_table.find_all('tr') + + for row in items: + title = row.find('span', attrs = {'class':'s'}) + + if not title: continue + + nzb_id = row.find('input', attrs = {'type':'checkbox'})['name'] + info = row.find('span', attrs = {'class':'d'}) + size_match = re.search('size:.(?P[0-9\.]+.[GMB]+)', info.text) + + def extra_check(item): + parts = re.search('available:.(?P\d+)./.(?P\d+)', info.text) + total = tryInt(parts.group('total')) + parts = tryInt(parts.group('parts')) + + if (total / parts) < 0.95 or ((total / parts) >= 0.95 and not 'par2' in info.text.lower()): + log.info2('Wrong: \'%s\', not complete: %s out of %s', (item['name'], parts, total)) + return False + + if 'requires password' in info.text.lower(): + log.info2('Wrong: \'%s\', passworded', (item['name'])) + return False + + return True + + results.append({ + 'id': nzb_id, + 'name': title.text, + 'age': tryInt(re.search('(?P\d+d)', row.find_all('td')[-1:][0].text).group('size')[:-1]), + 'size': self.parseSize(size_match.group('size')), + 'url': self.urls['download'] % nzb_id, + 'detail_url': self.urls['detail'] % info.find('a')['href'], + 'extra_check': extra_check + }) + + except: + log.error('Failed to parse HTML response from BinSearch: %s', traceback.format_exc()) + + def download(self, url = '', nzb_id = ''): + + params = {'action': 'nzb'} + params[nzb_id] = 'on' + + try: + return self.urlopen(url, params = params, show_error = False) + except: + log.error('Failed getting nzb from %s: %s', (self.getName(), traceback.format_exc())) + + return 'try_next' +