diff --git a/CHANGES.md b/CHANGES.md index 85632875..240c1738 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,14 @@ +### 0.16.10 (2018-05-21 23:30:00 UTC) + +* Fix importing TV shows with utf8 characters in parent folders on Windows +* Fix utf8 in folders for SickGear-NG.py post processing script, script version bumped 1.5 to 1.6 +* Fix incorrect logic mixing seasons +* Remove NMA notifier + + ### 0.16.9 (2018-05-17 15:30:00 UTC) * Fix authorisation issue affecting some providers diff --git a/HACKS.txt b/HACKS.txt index e1911c23..c8727b41 100644 --- a/HACKS.txt +++ b/HACKS.txt @@ -10,7 +10,6 @@ Libs with customisations... /lib/hachoir_parser/guess.py /lib/hachoir_parser/misc/torrent.py /lib/lockfile/mkdirlockfile.py -/lib/pynma/pynma.py /lib/tmdb_api/tmdb_api.py /lib/tornado /lib/tvdb_api/tvdb_api.py diff --git a/autoProcessTV/SickGear-NG/SickGear-NG.py b/autoProcessTV/SickGear-NG/SickGear-NG.py index d18d2330..4597f011 100755 --- a/autoProcessTV/SickGear-NG/SickGear-NG.py +++ b/autoProcessTV/SickGear-NG/SickGear-NG.py @@ -63,7 +63,7 @@ # Send PostProcessing requests to SickGear # -# PostProcessing-Script version: 1.5. +# PostProcessing-Script version: 1.6. # @@ -157,7 +157,7 @@ import re import sys import warnings -__version__ = '1.5' +__version__ = '1.6' verbose = 0 or 'yes' == os.environ.get('NZBPO_SG_VERBOSE', 'no') @@ -294,9 +294,22 @@ class Ek: except UnicodeEncodeError: return x.encode(SYS_ENCODING, 'ignore') + @staticmethod + def win_encode_unicode(x): + if isinstance(x, str): + try: + return x.decode('UTF-8') + except UnicodeDecodeError: + return x + return x + @staticmethod def ek(func, *args, **kwargs): if 'nt' == os.name: + # convert all str parameter values to unicode + args = tuple([x if not isinstance(x, str) else win_encode_unicode(x) for x in args]) + kwargs = {k: x if not isinstance(x, str) else win_encode_unicode(x) for k, x in + kwargs.iteritems()} func_result = func(*args, **kwargs) else: func_result = func(*[Ek.encode_item(x) if type(x) == str else x for x in args], **kwargs) diff --git a/gui/slick/images/notifiers/nma.png b/gui/slick/images/notifiers/nma.png deleted file mode 100644 index 15dfa7f4..00000000 Binary files a/gui/slick/images/notifiers/nma.png and /dev/null differ diff --git a/gui/slick/interfaces/default/config_notifications.tmpl b/gui/slick/interfaces/default/config_notifications.tmpl index cc21718a..3e31b01f 100644 --- a/gui/slick/interfaces/default/config_notifications.tmpl +++ b/gui/slick/interfaces/default/config_notifications.tmpl @@ -852,7 +852,6 @@
Pushover
Growl
Prowl
-
NMA
Libnotify
@@ -1379,84 +1378,6 @@ -
-
- -

Notify My Android

-

Notify My Android is a Prowl-like Android app and API that sends notifications from applications directly to Android devices.

-
-
-
- -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
Click below to test
- - -
- -
-
- -
diff --git a/gui/slick/js/configNotifications.js b/gui/slick/js/configNotifications.js index 9795fa7f..ae423a26 100644 --- a/gui/slick/js/configNotifications.js +++ b/gui/slick/js/configNotifications.js @@ -409,25 +409,6 @@ $(document).ready(function(){ }); }); - $('#test-nma').click(function () { - var nmaApi = $.trim($('#nma-api').val()); - var nmaPriority = $('#nma-priority').val(); - if (!nmaApi) { - $('#test-nma-result').html('Please fill out the necessary fields above.'); - $('#nma-api').addClass('warning'); - return; - } - $('#nma-api').removeClass('warning'); - $(this).prop('disabled', !0); - $('#test-nma-result').html(loading); - $.get(sbRoot + '/home/test_nma', - {nma_api: nmaApi, nma_priority: nmaPriority}) - .done(function (data) { - $('#test-nma-result').html(data); - $('#test-nma').prop('disabled', !1); - }); - }); - $('#test-pushalot').click(function () { var pushalotAuthorizationtoken = $.trim($('#pushalot-authorizationtoken').val()); if (!pushalotAuthorizationtoken) { diff --git a/lib/pynma/__init__.py b/lib/pynma/__init__.py deleted file mode 100644 index f884b504..00000000 --- a/lib/pynma/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/python - -__version__ = '1.01' - -from .pynma import PyNMA diff --git a/lib/pynma/pynma.py b/lib/pynma/pynma.py deleted file mode 100644 index e735eddd..00000000 --- a/lib/pynma/pynma.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/python - -from . import __version__ -from xml.dom.minidom import parseString - -import requests - - -class PyNMA(object): - """ - http://www.notifymyandroid.com/api.jsp - PyNMA(apikey=None, developerkey=None) - takes 2 optional arguments: - - (opt) apykey: a string containing 1 key or an array of keys - - (opt) developerkey: where you can store your developer key - """ - - def __init__(self, apikey=None, developerkey=None): - - self._developerkey = None - self.developerkey(developerkey) - - self.api_server = 'https://www.notifymyandroid.com' - self.add_path = '/publicapi/notify' - self.user_agent = 'PyNMA/v%s' % __version__ - - key = [] - if apikey: - key = (apikey, [apikey])[str == type(apikey)] - - self._apikey = self.uniq(key) - - @staticmethod - def uniq(seq): - # Not order preserving - return list({}.fromkeys(seq).keys()) - - def addkey(self, key): - """ - Add a key (register ?) - """ - if str == type(key): - if key not in self._apikey: - self._apikey.append(key) - - elif list == type(key): - for k in key: - if k not in self._apikey: - self._apikey.append(k) - - def delkey(self, key): - """ - Removes a key (unregister ?) - """ - if str == type(key): - if key in self._apikey: - self._apikey.remove(key) - - elif list == type(key): - for k in key: - if key in self._apikey: - self._apikey.remove(k) - - def developerkey(self, developerkey): - """ - Sets the developer key (and check it has the good length) - """ - if str == type(developerkey) and 48 == len(developerkey): - self._developerkey = developerkey - - def push(self, application='', event='', description='', url='', content_type=None, priority=0, batch_mode=False, html=False): - """ - Pushes a message on the registered API keys. - takes 5 arguments: - - (req) application: application name [256] - - (req) event: event name [1000] - - (req) description: description [10000] - - (opt) url: url [512] - - (opt) contenttype: Content Type (act: None (plain text) or text/html) - - (opt) priority: from -2 (lowest) to 2 (highest) (def:0) - - (opt) batch_mode: call API 5 by 5 (def:False) - - (opt) html: shortcut for content_type=text/html - - Warning: using batch_mode will return error only if all API keys are bad - http://www.notifymyandroid.com/api.jsp - """ - datas = {'application': application[:256].encode('utf8'), - 'event': event[:1000].encode('utf8'), - 'description': description[:10000].encode('utf8'), - 'priority': priority} - - if url: - datas['url'] = url[:2000] - - if self._developerkey: - datas['developerkey'] = self._developerkey - - if 'text/html' == content_type or True == html: # Currently only accepted content type - datas['content-type'] = 'text/html' - - results = {} - - if not batch_mode: - for key in self._apikey: - datas['apikey'] = key - res = self.callapi('POST', self.add_path, datas) - results[key] = res - else: - datas['apikey'] = ','.join(self._apikey) - res = self.callapi('POST', self.add_path, datas) - results[datas['apikey']] = res - - return results - - def callapi(self, method, path, args): - headers = {'User-Agent': self.user_agent} - - if 'POST' == method: - headers['Content-type'] = 'application/x-www-form-urlencoded' - - try: - resp = requests.post('%s:443%s' % (self.api_server, path), data=args, headers=headers).text - res = self._parse_response(resp) - except Exception as e: - res = {'type': 'pynmaerror', - 'code': 600, - 'message': str(e)} - pass - - return res - - @staticmethod - def _parse_response(response): - - root = parseString(response).firstChild - - for elem in root.childNodes: - if elem.TEXT_NODE == elem.nodeType: - continue - - if 'success' == elem.tagName: - res = dict(list(elem.attributes.items())) - res['message'] = '' - res['type'] = elem.tagName - return res - - if 'error' == elem.tagName: - res = dict(list(elem.attributes.items())) - res['message'] = elem.firstChild.nodeValue - res['type'] = elem.tagName - return res diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 9b229535..9731eb2d 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -391,13 +391,6 @@ PROWL_NOTIFY_ONSUBTITLEDOWNLOAD = False PROWL_API = None PROWL_PRIORITY = '0' -USE_NMA = False -NMA_NOTIFY_ONSNATCH = False -NMA_NOTIFY_ONDOWNLOAD = False -NMA_NOTIFY_ONSUBTITLEDOWNLOAD = False -NMA_API = None -NMA_PRIORITY = '0' - USE_LIBNOTIFY = False LIBNOTIFY_NOTIFY_ONSNATCH = False LIBNOTIFY_NOTIFY_ONDOWNLOAD = False @@ -671,7 +664,6 @@ def initialize(console_logging=True): PUSHOVER_USERKEY, PUSHOVER_APIKEY, PUSHOVER_PRIORITY, PUSHOVER_DEVICE, PUSHOVER_SOUND, \ USE_BOXCAR2, BOXCAR2_NOTIFY_ONSNATCH, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, \ BOXCAR2_ACCESSTOKEN, BOXCAR2_SOUND, \ - USE_NMA, NMA_NOTIFY_ONSNATCH, NMA_NOTIFY_ONDOWNLOAD, NMA_NOTIFY_ONSUBTITLEDOWNLOAD, NMA_API, NMA_PRIORITY, \ USE_PUSHALOT, PUSHALOT_NOTIFY_ONSNATCH, PUSHALOT_NOTIFY_ONDOWNLOAD, \ PUSHALOT_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHALOT_AUTHORIZATIONTOKEN, \ USE_PUSHBULLET, PUSHBULLET_NOTIFY_ONSNATCH, PUSHBULLET_NOTIFY_ONDOWNLOAD, \ @@ -700,7 +692,7 @@ def initialize(console_logging=True): for stanza in ('General', 'Blackhole', 'SABnzbd', 'NZBget', 'Emby', 'Kodi', 'XBMC', 'PLEX', 'Growl', 'Prowl', 'Twitter', 'Slack', 'Discordapp', 'Boxcar2', 'NMJ', 'NMJv2', 'Synology', 'SynologyNotifier', - 'pyTivo', 'NMA', 'Pushalot', 'Pushbullet', 'Subtitles'): + 'pyTivo', 'Pushalot', 'Pushbullet', 'Subtitles'): check_section(CFG, stanza) update_config = False @@ -1087,13 +1079,6 @@ def initialize(console_logging=True): PYTIVO_SHARE_NAME = check_setting_str(CFG, 'pyTivo', 'pytivo_share_name', '') PYTIVO_TIVO_NAME = check_setting_str(CFG, 'pyTivo', 'pytivo_tivo_name', '') - USE_NMA = bool(check_setting_int(CFG, 'NMA', 'use_nma', 0)) - NMA_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'NMA', 'nma_notify_onsnatch', 0)) - NMA_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'NMA', 'nma_notify_ondownload', 0)) - NMA_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'NMA', 'nma_notify_onsubtitledownload', 0)) - NMA_API = check_setting_str(CFG, 'NMA', 'nma_api', '') - NMA_PRIORITY = check_setting_str(CFG, 'NMA', 'nma_priority', '0') - USE_PUSHALOT = bool(check_setting_int(CFG, 'Pushalot', 'use_pushalot', 0)) PUSHALOT_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Pushalot', 'pushalot_notify_onsnatch', 0)) PUSHALOT_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Pushalot', 'pushalot_notify_ondownload', 0)) @@ -1913,14 +1898,6 @@ def save_config(): new_config['Prowl']['prowl_api'] = PROWL_API new_config['Prowl']['prowl_priority'] = PROWL_PRIORITY - new_config['NMA'] = {} - new_config['NMA']['use_nma'] = int(USE_NMA) - new_config['NMA']['nma_notify_onsnatch'] = int(NMA_NOTIFY_ONSNATCH) - new_config['NMA']['nma_notify_ondownload'] = int(NMA_NOTIFY_ONDOWNLOAD) - new_config['NMA']['nma_notify_onsubtitledownload'] = int(NMA_NOTIFY_ONSUBTITLEDOWNLOAD) - new_config['NMA']['nma_api'] = NMA_API - new_config['NMA']['nma_priority'] = NMA_PRIORITY - new_config['Libnotify'] = {} new_config['Libnotify']['use_libnotify'] = int(USE_LIBNOTIFY) new_config['Libnotify']['libnotify_notify_onsnatch'] = int(LIBNOTIFY_NOTIFY_ONSNATCH) diff --git a/sickbeard/encodingKludge.py b/sickbeard/encodingKludge.py index e9ec28b7..67067b20 100644 --- a/sickbeard/encodingKludge.py +++ b/sickbeard/encodingKludge.py @@ -25,6 +25,7 @@ import sickbeard # encodings. It tries to just use unicode, but if that fails then it tries forcing it to utf-8. Any functions # which return something should always return unicode. + def fixStupidEncodings(x, silent=False): if type(x) == str: try: @@ -41,7 +42,6 @@ def fixStupidEncodings(x, silent=False): return None - def fixListEncodings(x): if type(x) != list and type(x) != tuple: return x @@ -66,8 +66,21 @@ def fixParaLists(x): return x +def win_encode_unicode(x): + if isinstance(x, str): + try: + return x.decode('UTF-8') + except UnicodeDecodeError: + return x + return x + + def ek(func, *args, **kwargs): if os.name == 'nt': + # convert all str parameter values to unicode + args = tuple([x if not isinstance(x, str) else win_encode_unicode(x) for x in args]) + kwargs = {k: x if not isinstance(x, str) else win_encode_unicode(x) for k, x in + kwargs.iteritems()} result = func(*args, **kwargs) else: result = func(*[callPeopleStupid(x) if type(x) in (str, unicode) else fixParaLists(x) for x in args], **kwargs) diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py index 1ff173c1..4c9c7e08 100644 --- a/sickbeard/notifiers/__init__.py +++ b/sickbeard/notifiers/__init__.py @@ -32,7 +32,6 @@ import pushbullet import pushover import growl import prowl -import nma from . import libnotify from lib import libtrakt @@ -68,7 +67,6 @@ class NotifierFactory(object): PUSHOVER=pushover.PushoverNotifier, GROWL=growl.GrowlNotifier, PROWL=prowl.ProwlNotifier, - NMA=nma.NMANotifier, LIBNOTIFY=libnotify.LibnotifyNotifier, # social diff --git a/sickbeard/notifiers/nma.py b/sickbeard/notifiers/nma.py deleted file mode 100644 index 3ed63278..00000000 --- a/sickbeard/notifiers/nma.py +++ /dev/null @@ -1,38 +0,0 @@ -import sickbeard -from sickbeard.notifiers.generic import Notifier - -from lib.pynma import pynma - - -class NMANotifier(Notifier): - - def _notify(self, title, body, nma_api=None, nma_priority=None, **kwargs): - - nma_api = self._choose(nma_api, sickbeard.NMA_API) - nma_priority = self._choose(nma_priority, sickbeard.NMA_PRIORITY) - - batch = False - - p = pynma.PyNMA() - keys = nma_api.split(',') - p.addkey(keys) - - if 1 < len(keys): - batch = True - - self._log_debug('Sending notice with priority=%s, batch=%s' % (nma_priority, batch)) - response = p.push('SickGear', title, body, priority=nma_priority, batch_mode=batch) - - result = False - try: - if u'200' != response[nma_api][u'code']: - self._log_error('Notification failed') - else: - result = True - except (StandardError, Exception): - pass - - return result - - -notifier = NMANotifier diff --git a/sickbeard/search.py b/sickbeard/search.py index d8266aab..6538ddc7 100644 --- a/sickbeard/search.py +++ b/sickbeard/search.py @@ -707,9 +707,9 @@ def search_providers(show, episodes, manual_search=False, torrent_only=False, tr best_season_result.provider.providerType), logger.DEBUG) my_db = db.DBConnection() - sql = 'SELECT episode FROM tv_episodes WHERE showid = %s AND (season IN (%s))' %\ + sql = 'SELECT season, episode FROM tv_episodes WHERE showid = %s AND (season IN (%s))' %\ (show.indexerid, ','.join([str(x.season) for x in episodes])) - ep_nums = [int(x['episode']) for x in my_db.select(sql)] + ep_nums = [(int(x['season']), int(x['episode'])) for x in my_db.select(sql)] logger.log(u'Executed query: [%s]' % sql) logger.log(u'Episode list: %s' % ep_nums, logger.DEBUG) @@ -717,11 +717,10 @@ def search_providers(show, episodes, manual_search=False, torrent_only=False, tr all_wanted = True any_wanted = False for ep_num in ep_nums: - for season in set([x.season for x in episodes]): - if not show.wantEpisode(season, ep_num, season_qual): - all_wanted = False - else: - any_wanted = True + if not show.wantEpisode(ep_num[0], ep_num[1], season_qual): + all_wanted = False + else: + any_wanted = True # if we need every ep in the season and there's nothing better then just download this and # be done with it (unless single episodes are preferred) @@ -730,8 +729,7 @@ def search_providers(show, episodes, manual_search=False, torrent_only=False, tr (best_season_result.provider.providerType, best_season_result.name)) ep_objs = [] for ep_num in ep_nums: - for season in set([x.season for x in episodes]): - ep_objs.append(show.getEpisode(season, ep_num)) + ep_objs.append(show.getEpisode(ep_num[0], ep_num[1])) best_season_result.episodes = ep_objs return [best_season_result] @@ -770,8 +768,7 @@ def search_providers(show, episodes, manual_search=False, torrent_only=False, tr u'the episodes that you do not want to "don\'t download"') ep_objs = [] for ep_num in ep_nums: - for season in set([x.season for x in episodes]): - ep_objs.append(show.getEpisode(season, ep_num)) + ep_objs.append(show.getEpisode(ep_num[0], ep_num[1])) best_season_result.episodes = ep_objs ep_num = MULTI_EP_RESULT diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index c30bd6d2..d7ae9a77 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -1450,14 +1450,6 @@ class Home(MainHandler): return notifiers.NotifierFactory().get('PROWL').test_notify(prowl_api, prowl_priority) - def test_nma(self, nma_api=None, nma_priority=0): - self.set_header('Cache-Control', 'max-age=0,no-cache,no-store') - - if None is not nma_api and starify(nma_api, True): - nma_api = sickbeard.NMA_API - - return notifiers.NotifierFactory().get('NMA').test_notify(nma_api, nma_priority) - def test_libnotify(self, *args, **kwargs): self.set_header('Cache-Control', 'max-age=0,no-cache,no-store') @@ -3298,7 +3290,7 @@ class NewHomeAddShows(Home): if not file_list: try: file_list = ek.ek(os.listdir, root_dir) - except: + except (StandardError, Exception): continue for cur_file in file_list: @@ -6605,8 +6597,6 @@ class ConfigNotifications(Config): growl_notify_onsubtitledownload=None, growl_host=None, growl_password=None, use_prowl=None, prowl_notify_onsnatch=None, prowl_notify_ondownload=None, prowl_notify_onsubtitledownload=None, prowl_api=None, prowl_priority=0, - use_nma=None, nma_notify_onsnatch=None, nma_notify_ondownload=None, - nma_notify_onsubtitledownload=None, nma_api=None, nma_priority=0, use_libnotify=None, libnotify_notify_onsnatch=None, libnotify_notify_ondownload=None, libnotify_notify_onsubtitledownload=None, # use_pushalot=None, pushalot_notify_onsnatch=None, pushalot_notify_ondownload=None, @@ -6820,15 +6810,6 @@ class ConfigNotifications(Config): sickbeard.PYTIVO_SHARE_NAME = pytivo_share_name sickbeard.PYTIVO_TIVO_NAME = pytivo_tivo_name - sickbeard.USE_NMA = config.checkbox_to_value(use_nma) - sickbeard.NMA_NOTIFY_ONSNATCH = config.checkbox_to_value(nma_notify_onsnatch) - sickbeard.NMA_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(nma_notify_ondownload) - sickbeard.NMA_NOTIFY_ONSUBTITLEDOWNLOAD = config.checkbox_to_value(nma_notify_onsubtitledownload) - key = nma_api.strip() - if not starify(key, True): - sickbeard.NMA_API = key - sickbeard.NMA_PRIORITY = nma_priority - # sickbeard.USE_PUSHALOT = config.checkbox_to_value(use_pushalot) # sickbeard.PUSHALOT_NOTIFY_ONSNATCH = config.checkbox_to_value(pushalot_notify_onsnatch) # sickbeard.PUSHALOT_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(pushalot_notify_ondownload)