diff --git a/CHANGES.md b/CHANGES.md
index 281caf6..aa31a8b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,4 +1,10 @@
-### 0.23.20 (2020-05-13 18:35:00 UTC)
+### 0.23.21 (2020-05-17 10:20:00 UTC)
+
+* Fix provider Nebulance
+* Fix provider MoreThan
+
+
+### 0.23.20 (2020-05-13 18:35:00 UTC)
* Fix restart to release and free resources from previous run process
* Change fanart lib to get_url
diff --git a/sickbeard/providers/morethan.py b/sickbeard/providers/morethan.py
index 3f327b7..b2622fb 100644
--- a/sickbeard/providers/morethan.py
+++ b/sickbeard/providers/morethan.py
@@ -67,7 +67,7 @@ class MoreThanProvider(generic.TorrentProvider):
for (k, v) in iteritems({'info': r'torrents.php\?id', 'get': 'download', 'nuked': 'nuked'})])
for mode in search_params:
for search_string in search_params[mode]:
- search_string = unidecode(search_string)
+ search_string = unidecode(search_string).replace('.', ' ')
search_url = self.urls['search'] % (search_string,
self._categories_string(mode, template='filter_cat[%s]=1'))
diff --git a/sickbeard/providers/nebulance.py b/sickbeard/providers/nebulance.py
index bf3b78a..4882bb4 100644
--- a/sickbeard/providers/nebulance.py
+++ b/sickbeard/providers/nebulance.py
@@ -15,6 +15,10 @@
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see .
+try:
+ import json
+except ImportError:
+ from lib import simplejson as json
import re
import traceback
@@ -24,7 +28,7 @@ from ..helpers import try_int
from bs4_parser import BS4Parser
-from _23 import filter_list, unidecode
+from _23 import filter_list, unidecode, unquote_plus
from six import iteritems
@@ -37,15 +41,18 @@ class NebulanceProvider(generic.TorrentProvider):
self.urls = {'config_provider_home_uri': self.url_base,
'login_action': self.url_base + 'login.php',
'user': self.url_base + 'ajax.php?action=index',
+ 'api_key': self.url_base + 'user.php?action=edit&userid=%s',
+ 'api': self.url_base + 'api.php',
'browse': self.url_base + 'ajax.php?action=browse&auth=%s&passkey=%s',
'search': '&searchstr=%s',
'get': self.url_base + 'torrents.php?action=download&authkey=%s&torrent_pass=%s&id=%s'}
self.url = self.urls['config_provider_home_uri']
- self.user_authkey, self.user_passkey = 2 * [None]
+ self.user_authkey, self.user_passkey, self.uid = 3 * [None]
self.chk_td = True
- self.username, self.password, self.freeleech, self.scene, self.minseed, self.minleech = 6 * [None]
+ self.username, self.password, self.api_key, self.scene, self.minseed, self.minleech = 6 * [None]
+ self.api_priority = False
def _authorised(self, **kwargs):
@@ -58,11 +65,18 @@ class NebulanceProvider(generic.TorrentProvider):
if self.should_skip():
return False
if 'response' in response:
- self.user_authkey, self.user_passkey = [response['response'].get(v) for v in ('authkey', 'passkey')]
+ self.user_authkey, self.user_passkey, self.uid = [response['response'].get(v)
+ for v in ('authkey', 'passkey', 'id')]
return self.user_authkey
def _search_provider(self, search_params, **kwargs):
+ if self.api_priority:
+ return self.api_key and self._search_rpc(search_params) or self._search(search_params)
+ return self._search(search_params) or self.api_key and self._search_rpc(search_params) or []
+
+ def _search(self, search_params):
+
results = []
if not self._authorised():
return results
@@ -85,25 +99,23 @@ class NebulanceProvider(generic.TorrentProvider):
cnt = len(items[mode])
try:
for item in data_json.get('response', {}).get('results', []):
- if self.freeleech and not item.get('isFreeleech'):
- continue
-
- seeders, leechers, group_name, torrent_id, size = [try_int(n, n) for n in [
- item.get(x) for x in ['seeders', 'leechers', 'groupName', 'torrentId', 'size']]]
+ seeders, leechers, group_name, torrent_id, size, title = [try_int(n, n) for n in [
+ item.get(x) for x in ['seeders', 'leechers', 'groupName', 'torrentId', 'size', 'rlsName']]]
if self._reject_item(seeders, leechers):
continue
- try:
- title_parts = group_name.split('[')
- maybe_res = re.findall(r'((?:72|108|216)0\w)', title_parts[1])
- maybe_ext = re.findall('(?i)(%s)' % '|'.join(common.mediaExtensions), title_parts[1])
- detail = title_parts[1].split('/')
- detail[1] = detail[1].strip().lower().replace('mkv', 'x264')
- title = '%s.%s' % (BS4Parser(title_parts[0].strip()).soup.string, '.'.join(
- (maybe_res and [maybe_res[0]] or []) +
- [detail[0].strip(), detail[1], maybe_ext and maybe_ext[0].lower() or 'mkv']))
- except (IndexError, KeyError):
- title = self.regulate_title(item, group_name)
+ if None is title:
+ try:
+ title_parts = group_name.split('[')
+ maybe_res = re.findall(r'((?:72|108|216)0\w)', title_parts[1])
+ maybe_ext = re.findall('(?i)(%s)' % '|'.join(common.mediaExtensions), title_parts[1])
+ detail = title_parts[1].split('/')
+ detail[1] = detail[1].strip().lower().replace('mkv', 'x264')
+ title = '%s.%s' % (BS4Parser(title_parts[0].strip()).soup.string, '.'.join(
+ (maybe_res and [maybe_res[0]] or []) +
+ [detail[0].strip(), detail[1], maybe_ext and maybe_ext[0].lower() or 'mkv']))
+ except (IndexError, KeyError):
+ title = self.regulate_title(item, group_name)
download_url = self.urls['get'] % (self.user_authkey, self.user_passkey, torrent_id)
if title and download_url:
@@ -164,5 +176,59 @@ class NebulanceProvider(generic.TorrentProvider):
title += + any(tags[4]) and ('.%s' % tags[4][0]) or ''
return title
+ def _search_rpc(self, search_params):
+
+ results = []
+
+ items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
+
+ json_rpc = (lambda args:
+ '{"jsonrpc": "2.0", "id": 1, "method": "getTorrents", "params": ["%s", %s, %s, %s, %s]}' %
+ (self.api_key, json.dumps(args.get('params', '')), 100, args.get('page', 0), 0))
+
+ for mode in search_params:
+ for search_string in search_params[mode]:
+ search_string = unquote_plus(unidecode(search_string))
+
+ params = {'release': search_string}
+ if 'Cache' == mode:
+ params = {'age': '< %s' % (24 * 60 * 60)}
+ elif 'Propers' == mode:
+ params.update({'age': '< %s' % (4 * 24 * 60 * 60)})
+
+ response = self.get_url(self.urls['api'], post_data=json_rpc({'params': params}), parse_json=True)
+ if self.should_skip():
+ return results
+
+ data_json = response and response.get('result', {}).get('items') or []
+
+ cnt = len(items[mode])
+ for cur_item in data_json:
+ seeders, leechers, size, download = [try_int(n, n) for n in [
+ cur_item.get(x) for x in ['seed', 'leech', 'size', 'download']]]
+ if not self._reject_item(seeders, leechers):
+ items[mode].append((cur_item.get('rls_name'), '%s%s' % (self.url_base.rstrip('/'), download),
+ seeders, self._bytesizer(size)))
+
+ self._log_search(mode, len(items[mode]) - cnt,
+ ('search_string: ' + str(search_string), self.name)['Cache' == mode])
+
+ results = self._sort_seeding(mode, results + items[mode])
+
+ return results
+
+ def ui_string(self, key):
+ profile_page = 'profile page'
+ if self._authorised():
+ profile_page = '%s' % (self.urls['api_key'] % self.uid, profile_page)
+
+ return ('%s_api_key' % self.get_id()) == key and 'API key' or \
+ ('%s_api_key_tip' % self.get_id()) == key and \
+ '\'API key\' is at %s %s with "Download" enabled
' \
+ '%s has no result or is not set' \
+ % (self.name, profile_page,
+ ('and is used if Username/Password', 'Username/Password is used if API')[self.api_priority]) \
+ or ''
+
provider = NebulanceProvider()
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index 20fec54..c38ef30 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -8332,15 +8332,14 @@ class EventLogs(MainHandler):
self.set_header('Content-Length', ek.ek(os.path.getsize, logfile_name))
self.set_header('Content-Disposition', 'attachment; filename=sickgear.log')
with open(logfile_name, 'rb') as logfile:
- try:
- while True:
+ while True:
+ try:
data = logfile.read(4096)
if not data:
break
self.write(data)
- self.finish()
- except (BaseException, Exception):
- return
+ except (BaseException, Exception):
+ break
def view_log(self, min_level=logger.MESSAGE, max_lines=500):