diff --git a/SABnzbd.py b/SABnzbd.py index 7edb217..5716c59 100755 --- a/SABnzbd.py +++ b/SABnzbd.py @@ -17,18 +17,8 @@ import sys import imp -if sys.version_info[:2] < (2, 7) or sys.version_info[:2] >= (3, 0): - print("Sorry, requires Python 2.7.") - sys.exit(1) - -# Make sure UTF-8 is default 8bit encoding -if not hasattr(sys, "setdefaultencoding"): - imp.reload(sys) -try: - sys.setdefaultencoding('utf-8') -except: - print('Sorry, you MUST add the SABnzbd folder to the PYTHONPATH environment variable') - print('or find another way to force Python to use UTF-8 for text encoding.') +if sys.version_info[:2] <= (3, 0): + print("Sorry, requires Python 3") sys.exit(1) import logging @@ -45,10 +35,10 @@ import re try: import Cheetah - if Cheetah.Version[0] != '2': + if Cheetah.Version[0] != '3': raise ValueError except ValueError: - print("Sorry, requires Python module Cheetah 2.0rc7 or higher.") + print("Sorry, requires Python module Cheetah 3 or higher.") sys.exit(1) except: print("The Python module Cheetah is required") @@ -72,13 +62,7 @@ except: SQLITE_DLL = False import locale -import builtins -try: - locale.setlocale(locale.LC_ALL, "") - builtins.__dict__['codepage'] = locale.getlocale()[1] or 'cp1252' -except: - # Work-around for Python-ports with bad "locale" support - builtins.__dict__['codepage'] = 'cp1252' + import sabnzbd import sabnzbd.lang @@ -1078,8 +1062,7 @@ def main(): logdir = sabnzbd.cfg.log_dir.get_path() if fork and not logdir: - print("Error:") - print("I refuse to fork without a log directory!") + print("Error: I refuse to fork without a log directory!") sys.exit(1) if clean_up: @@ -1161,16 +1144,11 @@ def main(): logging.info('Arguments = %s', sabnzbd.CMDLINE) # Find encoding; relevant for unrar activities - try: - preferredencoding = locale.getpreferredencoding() - logging.info('Preferred encoding = %s', preferredencoding) - except: - logging.info('Preferred encoding = ERROR') - preferredencoding = '' + logging.info('Preferred encoding = %s', sys.stdin.encoding) # On Linux/FreeBSD/Unix "UTF-8" is strongly, strongly adviced: - if not sabnzbd.WIN32 and not sabnzbd.DARWIN and not ('utf' in preferredencoding.lower() and '8' in preferredencoding.lower()): - logging.warning(T("SABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.") % preferredencoding) + if not sabnzbd.WIN32 and not sabnzbd.DARWIN and not ('utf' in sys.stdin.encoding.lower() and '8' in sys.stdin.encoding.lower()): + logging.warning(T("SABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.") % sys.stdin.encoding) # SSL Information logging.info("SSL version = %s", ssl.OPENSSL_VERSION) diff --git a/sabnzbd/__init__.py b/sabnzbd/__init__.py index 9f6f505..47ab909 100644 --- a/sabnzbd/__init__.py +++ b/sabnzbd/__init__.py @@ -269,13 +269,13 @@ def initialize(pause_downloader=False, clean_up=False, evalSched=False, repair=0 cfg.quota_size.callback(guard_quota_size) cfg.quota_day.callback(guard_quota_dp) cfg.quota_period.callback(guard_quota_dp) - cfg.fsys_type.callback(guard_fsys_type) +###### cfg.fsys_type.callback(guard_fsys_type) cfg.language.callback(sabnzbd.notifier.reset_growl) cfg.enable_https_verification.callback(guard_https_ver) guard_https_ver() # Set Posix filesystem encoding - sabnzbd.encoding.change_fsys(cfg.fsys_type()) +###### sabnzbd.encoding.change_fsys(cfg.fsys_type()) # Set cache limit if not cfg.cache_limit() or (cfg.cache_limit() == '200M' and (sabnzbd.WIN32 or sabnzbd.DARWIN)): @@ -512,9 +512,9 @@ def guard_quota_dp(): scheduler.restart(force=True) -def guard_fsys_type(): - """ Callback for change of file system naming type """ - sabnzbd.encoding.change_fsys(cfg.fsys_type()) +# def guard_fsys_type(): +# """ Callback for change of file system naming type """ +# sabnzbd.encoding.change_fsys(cfg.fsys_type()) def set_https_verification(value): @@ -882,9 +882,6 @@ def save_data(data, _id, path, do_pickle=True, silent=False): try: with open(path, 'wb') as data_file: if do_pickle: - if cfg.use_pickle(): - pickle.dump(data, data_file) - else: pickle.dump(data, data_file) else: data_file.write(data) @@ -915,9 +912,6 @@ def load_data(_id, path, remove=True, do_pickle=True, silent=False): try: with open(path, 'rb') as data_file: if do_pickle: - if cfg.use_pickle(): - data = pickle.load(data_file) - else: data = pickle.load(data_file) else: data = data_file.read() @@ -951,9 +945,6 @@ def save_admin(data, _id): for t in range(3): try: with open(path, 'wb') as data_file: - if cfg.use_pickle(): - data = pickle.dump(data, data_file) - else: data = pickle.dump(data, data_file) break except: @@ -976,9 +967,6 @@ def load_admin(_id, remove=False, silent=False): try: with open(path, 'rb') as data_file: - if cfg.use_pickle(): - data = pickle.load(data_file) - else: data = pickle.load(data_file) if remove: misc.remove_file(path) diff --git a/sabnzbd/assembler.py b/sabnzbd/assembler.py index cafabb9..bc99e6c 100644 --- a/sabnzbd/assembler.py +++ b/sabnzbd/assembler.py @@ -45,13 +45,9 @@ from sabnzbd.rating import Rating class Assembler(Thread): do = None # Link to the instance of this method - def __init__(self, queue=None): + def __init__(self): Thread.__init__(self) - - if queue: - self.queue = queue - else: - self.queue = queue.Queue() + self.queue = queue.Queue() Assembler.do = self def stop(self): diff --git a/sabnzbd/cfg.py b/sabnzbd/cfg.py index 8370072..ee1af01 100644 --- a/sabnzbd/cfg.py +++ b/sabnzbd/cfg.py @@ -79,7 +79,6 @@ configlock = OptionBool('misc', 'config_lock', 0) ############################################################################## # One time trackers ############################################################################## -converted_nzo_pickles = OptionBool('misc', 'converted_nzo_pickles', False) warned_old_queue = OptionNumber('misc', 'warned_old_queue', QUEUE_VERSION) sched_converted = OptionBool('misc', 'sched_converted', False) notified_new_skin = OptionNumber('misc', 'notified_new_skin', 0) @@ -255,7 +254,6 @@ allow_incomplete_nzb = OptionBool('misc', 'allow_incomplete_nzb', False) enable_bonjour = OptionBool('misc', 'enable_bonjour', True) reject_duplicate_files = OptionBool('misc', 'reject_duplicate_files', False) max_art_opt = OptionBool('misc', 'max_art_opt', False) -use_pickle = OptionBool('misc', 'use_pickle', False) ipv6_hosting = OptionBool('misc', 'ipv6_hosting', False) fixed_ports = OptionBool('misc', 'fixed_ports', False) api_warnings = OptionBool('misc', 'api_warnings', True, protect=True) @@ -270,7 +268,7 @@ req_completion_rate = OptionNumber('misc', 'req_completion_rate', 100.2, 100, 20 selftest_host = OptionStr('misc', 'selftest_host', 'self-test.sabnzbd.org') movie_rename_limit = OptionStr('misc', 'movie_rename_limit', '100M') size_limit = OptionStr('misc', 'size_limit', '0') -fsys_type = OptionNumber('misc', 'fsys_type', 0, 0, 2) +###### fsys_type = OptionNumber('misc', 'fsys_type', 0, 0, 2) show_sysload = OptionNumber('misc', 'show_sysload', 2, 0, 2) history_limit = OptionNumber('misc', 'history_limit', 10, 0) wait_ext_drive = OptionNumber('misc', 'wait_ext_drive', 5, 1, 60) diff --git a/sabnzbd/config.py b/sabnzbd/config.py index c012471..d0dfc3e 100644 --- a/sabnzbd/config.py +++ b/sabnzbd/config.py @@ -26,7 +26,7 @@ import threading import shutil import time import random -from hashlib import md5 +import uuid from urllib.parse import urlparse import sabnzbd.misc from sabnzbd.constants import CONFIG_VERSION, NORMAL_PRIORITY, DEFAULT_PRIORITY, MAX_WIN_DFOLDER @@ -727,7 +727,7 @@ def _read_config(path, try_backup=False): return False, 'Cannot create INI file %s' % path try: - fp = open(path, 'rb') + fp = open(path, 'r') lines = fp.read().split('\n') if len(lines) == 1: fp.seek(0) @@ -1093,13 +1093,4 @@ def validate_notempty(root, value, default): def create_api_key(): """ Return a new randomized API_KEY """ - # Create some values to seed md5 - t = str(time.time()) - r = str(random.random()) - # Create the md5 instance and give it the current time - m = md5(t) - # Update the md5 instance with the random variable - m.update(r) - - # Return a hex digest of the md5, eg 49f68a5c8493ec2c0bf489821c21fc3b - return m.hexdigest() + return uuid.uuid4().hex diff --git a/sabnzbd/encoding.py b/sabnzbd/encoding.py index fd64b5e..97d1979 100644 --- a/sabnzbd/encoding.py +++ b/sabnzbd/encoding.py @@ -52,6 +52,7 @@ def change_fsys(value): def platform_encode(p): + return p """ Return Unicode name, if not already Unicode, decode with UTF-8 or latin1 """ if isinstance(p, str): try: @@ -92,6 +93,7 @@ def special_fixer(p): def unicoder(p, force=False): + return p """ Make sure a Unicode string is returned When `force` is True, ignore filesystem encoding """ @@ -109,6 +111,7 @@ def unicoder(p, force=False): def xml_name(p, keep_escape=False, encoding=None): + return p """ Prepare name for use in HTML/XML contect """ if isinstance(p, str): @@ -135,18 +138,8 @@ class LatinFilter(Filter): def filter(self, val, str=str, **kw): if isinstance(val, str): return val - elif isinstance(val, str): - try: - if sabnzbd.WIN32: - return val.decode(codepage) - else: - return val.decode('utf-8') - except: - return val.decode(codepage, 'replace') - elif val is None: - return '' else: - return str(str(val)) + return str(val) class EmailFilter(Filter): @@ -155,6 +148,9 @@ class EmailFilter(Filter): """ def filter(self, val, str=str, **kw): + return val + + if isinstance(val, str): return val elif isinstance(val, str): @@ -174,32 +170,11 @@ class EmailFilter(Filter): # # Use to transform 8-bit console output to plain Python strings # -import string -TAB_850 = \ - "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" \ - "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" \ - "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF" \ - "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF" \ - "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF" \ - "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF" \ - "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF" \ - "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF" - -TAB_LATIN = \ - "\xC7\xFC\xE9\xE2\xE4\xE0\xE5\xE7\xEA\xEB\xE8\xEF\xEE\xEC\xC4\xC5" \ - "\xC9\xE6\xC6\xF4\xF6\xF2\xFB\xF9\xFF\xD6\xDC\xF8\xA3\xD8\xD7\x66" \ - "\xE1\xED\xF3\xFA\xF1\xD1\xAA\xBA\xBF\xAE\xAC\xDB\xBC\xA1\xAB\xBB" \ - "\x7E\x7E\x7E\x7E\x7E\xC1\xC2\xC0\xA9\x7E\x7E\x7E\x7E\xA2\xA5\x7E" \ - "\x7E\x7E\x7E\x7E\x7E\x7E\xE3\xc3\x7E\x7E\x7E\x7E\x7E\x7E\x7E\xA4" \ - "\xF0\xD0\xCA\xCB\xC8\x7E\xCD\xCE\xCF\x7E\x7E\x7E\x7E\xA6\xCC\x7E" \ - "\xD3\xDF\xD4\xD2\xF5\xD5\xB5\xFE\xDE\xDA\xDB\xD9\xFD\xDD\xAF\xB4" \ - "\xAD\xB1\x5F\xBE\xB6\xA7\xF7\xB8\xB0\xA8\xB7\xB9\xB3\xB2\x7E\xA0" - -gTABLE_850_LATIN = string.maketrans(TAB_850, TAB_LATIN) -gTABLE_LATIN_850 = string.maketrans(TAB_LATIN, TAB_850) + def TRANS(p): + return p """ For Windows: Translate CP850 to Python's Latin-1 and return in Unicode Others: return original string """ @@ -215,6 +190,7 @@ def TRANS(p): def UNTRANS(p): + return p """ For Windows: Translate Python's Latin-1 to CP850 Others: return original string """ @@ -230,6 +206,7 @@ def UNTRANS(p): def fixup_ff4(p): + return p """ Fix incompatibility between CherryPy and Firefox-4 on OSX, where a filename contains &#xx; encodings """ @@ -279,6 +256,7 @@ def html_escape(txt): def deunicode(p): + return p """ Return the correct 8bit ASCII encoding for the platform: Latin-1 for Windows/Posix-non-UTF and UTF-8 for OSX/Posix-UTF """ @@ -303,4 +281,3 @@ def deunicode(p): return p -auto_fsys() diff --git a/sabnzbd/getipaddress.py b/sabnzbd/getipaddress.py index 447d691..0438745 100644 --- a/sabnzbd/getipaddress.py +++ b/sabnzbd/getipaddress.py @@ -77,9 +77,10 @@ def publicipv4(): # we only want IPv4 resolving, so socket.AF_INET: result = addresslookup4(sabnzbd.cfg.selftest_host()) except: - # something very bad: no urllib2, no resolving of selftest_host, no network at all + # something very bad: no urllib2, no resolving of selftest_host, no network at all public_ipv4 = None return public_ipv4 + # we got one or more IPv4 address(es), so let's connect to them for item in result: selftest_ipv4 = item[4][0] # get next IPv4 address of sabnzbd.cfg.selftest_host() @@ -90,8 +91,8 @@ def publicipv4(): req.add_header('User-Agent', 'SABnzbd+/%s' % sabnzbd.version.__version__ ) # specify the Host, because we only provide the IPv4 address in the URL: req.add_header('Host', sabnzbd.cfg.selftest_host()) - # get the response - public_ipv4 = urllib.request.urlopen(req, timeout=2).read() # timeout 2 seconds, in case the website is not accessible + # get the response, timeout 2 seconds, in case the website is not accessible + public_ipv4 = urllib.request.urlopen(req, timeout=2).read().decode('utf-8') # ... check the response is indeed an IPv4 address: socket.inet_aton(public_ipv4) # if we got anything else than a plain IPv4 address, this will raise an exception # if we get here without exception, we're done: @@ -101,6 +102,7 @@ def publicipv4(): # the connect OR the inet_aton raised an exception, so: # continue the for loop to try next server IPv4 address pass + if not ipv4_found: public_ipv4 = None return public_ipv4 diff --git a/sabnzbd/lang.py b/sabnzbd/lang.py index aaa1f47..6527b09 100644 --- a/sabnzbd/lang.py +++ b/sabnzbd/lang.py @@ -67,7 +67,7 @@ def set_language(language=None): lng = gettext.translation(_DOMAIN, _LOCALEDIR, [language], fallback=True, codeset='latin-1') # The unicode flag will make _() return Unicode - lng.install(str=True, names=['lgettext']) + lng.install(names=['lgettext']) builtins.__dict__['T'] = builtins.__dict__['_'] # Unicode builtins.__dict__['Ta'] = builtins.__dict__['_'] # Unicode (Used to Latin-1, compatibility support) builtins.__dict__['Tx'] = builtins.__dict__['_'] # Dynamic translation (unicode) diff --git a/sabnzbd/scheduler.py b/sabnzbd/scheduler.py index df7f941..495e011 100644 --- a/sabnzbd/scheduler.py +++ b/sabnzbd/scheduler.py @@ -299,7 +299,7 @@ def sort_schedules(all_events, now=None): if not all_events: break - events.sort(lambda x, y: x[0] - y[0]) + events.sort(key=lambda x, y: x[0] - y[0]) return events diff --git a/sabnzbd/utils/kronos.py b/sabnzbd/utils/kronos.py index 3453028..6364b4e 100644 --- a/sabnzbd/utils/kronos.py +++ b/sabnzbd/utils/kronos.py @@ -361,7 +361,7 @@ class DayTaskRescheduler: now[3], now[4] = self.timeonday # seconds now[5] = 0 - return time.mktime(now) + return time.mktime(tuple(now)) def reschedule(self, scheduler): """Reschedule this task according to the daytime for the task.