Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upstream #54

Merged
merged 12 commits into from
Feb 29, 2016
Binary file added gui/slick/images/providers/norbits.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions sickbeard/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
from sickbeard.providers import btn, newznab, rsstorrent, womble, thepiratebay, torrentleech, kat, iptorrents, torrentz, \
omgwtfnzbs, scc, hdtorrents, torrentday, hdbits, hounddawgs, speedcd, nyaatorrents, bluetigers, xthor, abnormal, phxbit, torrentbytes, cpasbien,\
freshontv, morethantv, bitsoup, t411, tokyotoshokan, shazbat, rarbg, alpharatio, tntvillage, binsearch, torrentproject, extratorrent, \
scenetime, btdigg, transmitthenet, tvchaosuk, bitcannon, pretome, gftracker, hdspace, newpct, elitetorrent, bitsnoop, danishbits, hd4free, limetorrents
scenetime, btdigg, transmitthenet, tvchaosuk, bitcannon, pretome, gftracker, hdspace, newpct, elitetorrent, bitsnoop, danishbits, hd4free, limetorrents, \
norbits

__all__ = [
'womble', 'btn', 'thepiratebay', 'kat', 'torrentleech', 'scc', 'hdtorrents',
Expand All @@ -35,7 +36,8 @@
'shazbat', 'rarbg', 'tntvillage', 'binsearch', 'bluetigers',
'xthor', 'abnormal', 'phxbit', 'scenetime', 'btdigg', 'transmitthenet', 'tvchaosuk',
'torrentproject', 'extratorrent', 'bitcannon', 'torrentz', 'pretome', 'gftracker',
'hdspace', 'newpct', 'elitetorrent', 'bitsnoop', 'danishbits', 'hd4free', 'limetorrents'
'hdspace', 'newpct', 'elitetorrent', 'bitsnoop', 'danishbits', 'hd4free', 'limetorrents',
'norbits'
]


Expand Down
144 changes: 144 additions & 0 deletions sickbeard/providers/norbits.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# coding=utf-8
'''A Norbits (https://norbits.net) provider'''

# URL: https://sickrage.github.io
#
# This file is part of SickRage.
#
# SickRage is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickRage is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.

from requests.compat import urlencode

from sickbeard import logger, tvcache

from sickrage.helper.exceptions import AuthException
from sickrage.providers.torrent.TorrentProvider import TorrentProvider

try:
import json
except ImportError:
import simplejson as json


class NorbitsProvider(TorrentProvider): # pylint: disable=too-many-instance-attributes
'''Main provider object'''

def __init__(self):
''' Initialize the class '''
TorrentProvider.__init__(self, 'Norbits')

self.username = None
self.passkey = None
self.ratio = None
self.minseed = None
self.minleech = None

self.cache = tvcache.TVCache(self, min_time=20) # only poll Norbits every 15 minutes max

self.url = 'https://norbits.net'
self.urls = {'search': self.url + '/api2.php?action=torrents',
'download': self.url + '/download.php?'}

self.logger = logger.Logger()

def _check_auth(self):

if not self.username or not self.passkey:
raise AuthException(('Your authentication credentials for %s are '
'missing, check your config.') % self.name)

return True

def _checkAuthFromData(self, parsed_json): # pylint: disable=invalid-name
''' Check that we are authenticated. '''

if 'status' in parsed_json and 'message' in parsed_json:
if parsed_json.get('status') == 3:
self.logger.log((u'Invalid username or password. '
'Check your settings'), logger.WARNING)

return True

def search(self, search_params, age=0, ep_obj=None): # pylint: disable=too-many-locals
''' Do the actual searching and JSON parsing'''

results = []

for mode in search_params:
items = []
self.logger.log(u'Search Mode: {}'.format(mode), logger.DEBUG)

for search_string in search_params[mode]:
if mode != 'RSS':
self.logger.log('Search string: {}'.format(search_string.decode('utf-8')),
logger.DEBUG)

post_data = {
'username': self.username,
'passkey': self.passkey,
'category': '2', # TV Category
'search': search_string,
}

self._check_auth()
parsed_json = self.get_url(self.urls['search'],
post_data=json.dumps(post_data),
json=True)

if not parsed_json:
return []

if self._checkAuthFromData(parsed_json):
if parsed_json and 'data' in parsed_json:
json_items = parsed_json['data']
else:
self.logger.log((u'Resulting JSON from provider is not correct, '
'not parsing it'), logger.ERROR)
if 'torrents' in json_items:
for item in json_items['torrents']:
seeders = item['seeders']
leechers = item['leechers']
title = item['name']
info_hash = item['info_hash']
size = item['size']
download_url = ('{}{}'.format(self.urls['download'],
urlencode({'id': item['id'],
'passkey': self.passkey})))

if seeders < self.minseed or leechers < self.minleech:
self.logger.log((u'Discarding torrent because it does not meet '
'the minimum seeders or leechers: '
'{} (S:{} L:{})').format
(title, seeders, leechers), logger.DEBUG)
continue
else:
item = title, download_url, size, seeders, leechers, info_hash
if mode != "RSS":
self.logger.log((u'Found result: {} with {} seeders and {}'
'leechers').format(title,
seeders,
leechers), logger.DEBUG)

items.append(item)
# For each search mode sort all the items by seeders if available
items.sort(key=lambda tup: tup[3], reverse=True)

results += items

return results

def seed_ratio(self):
return self.ratio

provider = NorbitsProvider() # pylint: disable=invalid-name
4 changes: 2 additions & 2 deletions sickbeard/providers/tntvillage.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@ def _check_auth(self):
return True

def login(self):
if any(dict_from_cookiejar(self.session.cookies).values()):
if len(dict_from_cookiejar(self.session.cookies)) == 3:
return True

login_params = {'UserName': self.username,
'PassWord': self.password,
'CookieDate': 0,
'CookieDate': 1,
'submit': 'Connettiti al Forum'}

response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
Expand Down
16 changes: 14 additions & 2 deletions sickbeard/providers/tvchaosuk.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.

import re
import time
from requests.utils import dict_from_cookiejar

from sickbeard import logger, tvcache
Expand Down Expand Up @@ -65,7 +66,9 @@ def _check_auth(self):
raise AuthException('Your authentication credentials for ' + self.name + ' are missing, check your config.')

def login(self):
if any(dict_from_cookiejar(self.session.cookies).values()):
# cloudflare leaves __cfduid cookie even if cookie is expired,
# there are 4 cookies when cookie is valid
if len(dict_from_cookiejar(self.session.cookies)) == 4:
return True

login_params = {
Expand All @@ -77,12 +80,21 @@ def login(self):
}

# Must be done twice, or it isnt really logged in
response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
# first time gets __cfduid, if we already have __cfduid this might get the cookie
response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
if not response:
logger.log(u"Unable to connect to provider", logger.WARNING)
return False

# if the first post only got the __cfduid then sleep 5 seconds for cloudflare anti-bot
# and then get the actual cookie
if len(dict_from_cookiejar(self.session.cookies)) < 4:
time.sleep(5)
response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
if not response:
logger.log(u"Unable to connect to provider", logger.WARNING)
return False

if re.search('Error: Username or password incorrect!', response):
logger.log(u"Invalid username or password. Check your settings", logger.WARNING)
return False
Expand Down