diff --git a/LazyLibrarian.py b/LazyLibrarian.py
index 3afd0982..9dc9aa9d 100644
--- a/LazyLibrarian.py
+++ b/LazyLibrarian.py
@@ -1,140 +1,140 @@
-#!/usr/bin/env python
-# -*- coding: UTF-8 -*-
-
-# This file is part of Lazylibrarian.
-# Lazylibrarian 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.
-# Lazylibrarian 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 Lazylibrarian. If not, see .
-
-# Purpose:
-# Main file for starting LazyLibrarian
-
-import logging
-import signal
-import sys
-import time
-
-import lazylibrarian
-from lazylibrarian import startup, webStart
-from lazylibrarian.formatter import thread_name
-from lazylibrarian.cleanup import UNBUNDLER
-
-# The following should probably be made configurable at the settings level
-# This fix is put in place for systems with broken SSL (like QNAP)
-opt_out_of_certificate_verification = True
-if opt_out_of_certificate_verification:
- # noinspection PyBroadException
- try:
- import ssl
-
- # noinspection PyProtectedMember
- ssl._create_default_https_context = ssl._create_unverified_context
- except Exception:
- pass
-
-# ==== end block (should be configurable at settings level)
-
-MIN_PYTHON_VERSION = (3, 7)
-
-if sys.version_info < MIN_PYTHON_VERSION:
- sys.stderr.write("This version of Lazylibrarian requires Python %d.%d or later.\n" % MIN_PYTHON_VERSION)
- exit(0)
-
-
-def sig_shutdown(*args):
- lazylibrarian.SIGNAL = 'shutdown'
-
-
-def main():
- # rename this thread
- thread_name("MAIN")
- starter = startup.StartupLazyLibrarian()
- # Set up a console-only logger until config is read
- starter.init_loggers(console_only=True)
- # Read command line and return options
- options, configfile = starter.startup_parsecommandline(__file__, args=sys.argv[1:])
- # Load config.ini and initialize CONFIG and DIRS
- starter.load_config(configfile)
- # Read logging config and initialize loggers
- starter.init_loggers(console_only=False)
- # Run initialization that needs CONFIG to be loaded
- starter.init_misc(lazylibrarian.config2.CONFIG)
- starter.init_caches(lazylibrarian.config2.CONFIG)
- starter.init_database()
- starter.init_build_debug_header(online=True)
- starter.init_build_lists(lazylibrarian.config2.CONFIG)
- logger = logging.getLogger(__name__)
-
- version_file = starter.create_version_file('version.txt')
- starter.init_version_checks(version_file)
-
- if lazylibrarian.DAEMON:
- lazylibrarian.daemonize()
-
- # Try to start the server.
- if options.port:
- lazylibrarian.config2.CONFIG.set_int('HTTP_PORT', options.port)
- logger.info('Starting LazyLibrarian on forced port: %s, webroot "%s"' %
- (lazylibrarian.config2.CONFIG['HTTP_PORT'], lazylibrarian.config2.CONFIG['HTTP_ROOT']))
- else:
- logger.info('Starting LazyLibrarian on port: %s, webroot "%s"' %
- (lazylibrarian.config2.CONFIG['HTTP_PORT'], lazylibrarian.config2.CONFIG['HTTP_ROOT']))
-
- webStart.initialize({
- 'http_port': lazylibrarian.config2.CONFIG.get_int('HTTP_PORT'),
- 'http_host': lazylibrarian.config2.CONFIG['HTTP_HOST'],
- 'http_root': lazylibrarian.config2.CONFIG['HTTP_ROOT'],
- 'http_user': lazylibrarian.config2.CONFIG['HTTP_USER'],
- 'http_pass': lazylibrarian.config2.CONFIG['HTTP_PASS'],
- 'http_proxy': lazylibrarian.config2.CONFIG.get_bool('HTTP_PROXY'),
- 'https_enabled': lazylibrarian.config2.CONFIG.get_bool('HTTPS_ENABLED'),
- 'https_cert': lazylibrarian.config2.CONFIG['HTTPS_CERT'],
- 'https_key': lazylibrarian.config2.CONFIG['HTTPS_KEY'],
- 'opds_enabled': lazylibrarian.config2.CONFIG['OPDS_ENABLED'],
- 'opds_authentication': lazylibrarian.config2.CONFIG.get_bool('OPDS_AUTHENTICATION'),
- 'opds_username': lazylibrarian.config2.CONFIG['OPDS_USERNAME'],
- 'opds_password': lazylibrarian.config2.CONFIG['OPDS_PASSWORD'],
- 'authentication': lazylibrarian.config2.CONFIG['AUTH_TYPE'],
- 'login_timeout': 43800,
- })
-
- if options.userid:
- lazylibrarian.LOGINUSER = options.userid
- else:
- lazylibrarian.LOGINUSER = None
-
- if lazylibrarian.config2.CONFIG.get_bool('LAUNCH_BROWSER') and not options.nolaunch:
- starter.launch_browser(lazylibrarian.config2.CONFIG['HTTP_HOST'],
- lazylibrarian.config2.CONFIG['HTTP_PORT'],
- lazylibrarian.config2.CONFIG['HTTP_ROOT'])
-
- starter.start_schedulers()
-
- signal.signal(signal.SIGTERM, sig_shutdown)
-
- while True:
- if not lazylibrarian.SIGNAL:
- try:
- time.sleep(1)
- except KeyboardInterrupt:
- starter.shutdown(doquit=True)
- else:
- if lazylibrarian.SIGNAL == 'shutdown':
- starter.shutdown(doquit=True)
- elif lazylibrarian.SIGNAL == 'restart':
- starter.shutdown(restart=True)
- elif lazylibrarian.SIGNAL == 'update':
- starter.shutdown(update=True)
- lazylibrarian.SIGNAL = None
-
-
-if __name__ == "__main__":
- UNBUNDLER.prepare_module_unbundling()
- main()
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+# This file is part of Lazylibrarian.
+# Lazylibrarian 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.
+# Lazylibrarian 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 Lazylibrarian. If not, see .
+
+# Purpose:
+# Main file for starting LazyLibrarian
+
+import logging
+import signal
+import sys
+import time
+
+import lazylibrarian
+from lazylibrarian import startup, webStart
+from lazylibrarian.formatter import thread_name
+from lazylibrarian.cleanup import UNBUNDLER
+
+# The following should probably be made configurable at the settings level
+# This fix is put in place for systems with broken SSL (like QNAP)
+opt_out_of_certificate_verification = True
+if opt_out_of_certificate_verification:
+ # noinspection PyBroadException
+ try:
+ import ssl
+
+ # noinspection PyProtectedMember
+ ssl._create_default_https_context = ssl._create_unverified_context
+ except Exception:
+ pass
+
+# ==== end block (should be configurable at settings level)
+
+MIN_PYTHON_VERSION = (3, 7)
+
+if sys.version_info < MIN_PYTHON_VERSION:
+ sys.stderr.write("This version of Lazylibrarian requires Python %d.%d or later.\n" % MIN_PYTHON_VERSION)
+ exit(0)
+
+
+def sig_shutdown():
+ lazylibrarian.SIGNAL = 'shutdown'
+
+
+def main():
+ # rename this thread
+ thread_name("MAIN")
+ starter = startup.StartupLazyLibrarian()
+ # Set up a console-only logger until config is read
+ starter.init_loggers(console_only=True)
+ # Read command line and return options
+ options, configfile = starter.startup_parsecommandline(__file__, args=sys.argv[1:])
+ # Load config.ini and initialize CONFIG and DIRS
+ starter.load_config(configfile)
+ # Read logging config and initialize loggers
+ starter.init_loggers(console_only=False)
+ # Run initialization that needs CONFIG to be loaded
+ starter.init_misc(lazylibrarian.config2.CONFIG)
+ starter.init_caches(lazylibrarian.config2.CONFIG)
+ starter.init_database()
+ starter.init_build_debug_header(online=True)
+ starter.init_build_lists(lazylibrarian.config2.CONFIG)
+ logger = logging.getLogger(__name__)
+
+ version_file = starter.create_version_file('version.txt')
+ starter.init_version_checks(version_file)
+
+ if lazylibrarian.DAEMON:
+ lazylibrarian.daemonize()
+
+ # Try to start the server.
+ if options.port:
+ lazylibrarian.config2.CONFIG.set_int('HTTP_PORT', options.port)
+ logger.info('Starting LazyLibrarian on forced port: %s, webroot "%s"' %
+ (lazylibrarian.config2.CONFIG['HTTP_PORT'], lazylibrarian.config2.CONFIG['HTTP_ROOT']))
+ else:
+ logger.info('Starting LazyLibrarian on port: %s, webroot "%s"' %
+ (lazylibrarian.config2.CONFIG['HTTP_PORT'], lazylibrarian.config2.CONFIG['HTTP_ROOT']))
+
+ webStart.initialize({
+ 'http_port': lazylibrarian.config2.CONFIG.get_int('HTTP_PORT'),
+ 'http_host': lazylibrarian.config2.CONFIG['HTTP_HOST'],
+ 'http_root': lazylibrarian.config2.CONFIG['HTTP_ROOT'],
+ 'http_user': lazylibrarian.config2.CONFIG['HTTP_USER'],
+ 'http_pass': lazylibrarian.config2.CONFIG['HTTP_PASS'],
+ 'http_proxy': lazylibrarian.config2.CONFIG.get_bool('HTTP_PROXY'),
+ 'https_enabled': lazylibrarian.config2.CONFIG.get_bool('HTTPS_ENABLED'),
+ 'https_cert': lazylibrarian.config2.CONFIG['HTTPS_CERT'],
+ 'https_key': lazylibrarian.config2.CONFIG['HTTPS_KEY'],
+ 'opds_enabled': lazylibrarian.config2.CONFIG['OPDS_ENABLED'],
+ 'opds_authentication': lazylibrarian.config2.CONFIG.get_bool('OPDS_AUTHENTICATION'),
+ 'opds_username': lazylibrarian.config2.CONFIG['OPDS_USERNAME'],
+ 'opds_password': lazylibrarian.config2.CONFIG['OPDS_PASSWORD'],
+ 'authentication': lazylibrarian.config2.CONFIG['AUTH_TYPE'],
+ 'login_timeout': 43800,
+ })
+
+ if options.userid:
+ lazylibrarian.LOGINUSER = options.userid
+ else:
+ lazylibrarian.LOGINUSER = None
+
+ if lazylibrarian.config2.CONFIG.get_bool('LAUNCH_BROWSER') and not options.nolaunch:
+ starter.launch_browser(lazylibrarian.config2.CONFIG['HTTP_HOST'],
+ lazylibrarian.config2.CONFIG['HTTP_PORT'],
+ lazylibrarian.config2.CONFIG['HTTP_ROOT'])
+
+ starter.start_schedulers()
+
+ signal.signal(signal.SIGTERM, sig_shutdown)
+
+ while True:
+ if not lazylibrarian.SIGNAL:
+ try:
+ time.sleep(1)
+ except KeyboardInterrupt:
+ starter.shutdown(doquit=True)
+ else:
+ if lazylibrarian.SIGNAL == 'shutdown':
+ starter.shutdown(doquit=True)
+ elif lazylibrarian.SIGNAL == 'restart':
+ starter.shutdown(restart=True)
+ elif lazylibrarian.SIGNAL == 'update':
+ starter.shutdown(update=True)
+ lazylibrarian.SIGNAL = None
+
+
+if __name__ == "__main__":
+ UNBUNDLER.prepare_module_unbundling()
+ main()
diff --git a/example.dicts.json b/example.dicts.json
new file mode 100644
index 00000000..a48b648b
--- /dev/null
+++ b/example.dicts.json
@@ -0,0 +1,37 @@
+{
+ "filename_dict": {
+ "<": "",
+ ">": "",
+ "...": "",
+ " & ": " ",
+ " = ": " ",
+ "?": "",
+ "$": "s",
+ "|": "",
+ " + ": " ",
+ "\"": "",
+ ",": "",
+ "*": "",
+ ":": "",
+ ";": "",
+ "'": "",
+ "//": "/",
+ "\\\\": "\\"
+ },
+ "umlaut_dict": {
+ "\u00e4": "ae",
+ "\u00f6": "oe",
+ "\u00fc": "ue",
+ "\u00c4": "Ae",
+ "\u00d6": "Oe",
+ "\u00dc": "Ue",
+ "\u00df": "ss"
+ },
+ "apostrophe_dict": {
+ "`": "'",
+ "\u2018": "'",
+ "\u2019": "'",
+ "\u201c": "\"",
+ "\u201d": "\""
+ }
+}
diff --git a/lazylibrarian/filesystem.py b/lazylibrarian/filesystem.py
index 5104f4ed..947ca3d7 100644
--- a/lazylibrarian/filesystem.py
+++ b/lazylibrarian/filesystem.py
@@ -15,7 +15,7 @@ from datetime import datetime
from typing import Optional
from lazylibrarian.configtypes import ConfigDict
-from lazylibrarian.formatter import make_bytestr, make_unicode, unaccented, replace_all, namedic, get_list
+from lazylibrarian.formatter import make_bytestr, make_unicode, unaccented, replace_all, get_list
class DirectoryHolder:
@@ -440,7 +440,7 @@ def safe_move(src, dst, action='move'):
drive, path = os.path.splitdrive(dst)
logger.debug("drive=[%s] path=[%s]" % (drive, path))
# strip some characters windows can't handle
- newpath = replace_all(path, namedic)
+ newpath = replace_all(path, lazylibrarian.DICTS.get('filename_dict', {}))
# windows filenames can't end in space or dot
while newpath and newpath[-1] in '. ':
newpath = newpath[:-1]
diff --git a/lazylibrarian/startup.py b/lazylibrarian/startup.py
index 06ce292c..a1b63250 100644
--- a/lazylibrarian/startup.py
+++ b/lazylibrarian/startup.py
@@ -308,6 +308,7 @@ class StartupLazyLibrarian:
def init_build_lists(self, config: ConfigDict):
lazylibrarian.GRGENRES = self.build_genres()
+ lazylibrarian.DICTS = self.build_dicts()
lazylibrarian.MONTHNAMES = self.build_monthtable(config)
lazylibrarian.NEWUSER_MSG = self.build_logintemplate()
lazylibrarian.NEWFILE_MSG = self.build_filetemplate()
@@ -419,6 +420,25 @@ class StartupLazyLibrarian:
self.logger.error('No valid genres.json file found')
return {"genreLimit": 4, "genreUsers": 10, "genreExclude": [], "genreExcludeParts": [], "genreReplace": {}}
+ def build_dicts(self):
+ for json_file in [os.path.join(DIRS.DATADIR, 'dicts.json'),
+ os.path.join(DIRS.PROG_DIR, 'example.dicts.json')]:
+ if path_isfile(json_file):
+ try:
+ with open(syspath(json_file), 'r', encoding='utf-8') as json_data:
+ res = json.load(json_data)
+ self.logger.info("Loaded dicts from %s" % json_file)
+ return res
+ except Exception as e:
+ self.logger.error('Failed to load %s, %s %s' % (json_file, type(e).__name__, str(e)))
+ self.logger.error('No valid dicts.json file found')
+ return {"filename_dict": {'<': '', '>': '', '...': '', ' & ': ' ', ' = ': ' ', '?': '', '$': 's', '|': '', ' + ': ' ',
+ '"': '', ',': '', '*': '', ':': '', ';': '', '\'': '', '//': '/', '\\\\': '\\'},
+ "umlaut_dict": {u'\xe4': 'ae', u'\xf6': 'oe', u'\xfc': 'ue', u'\xc4': 'Ae', u'\xd6': 'Oe', u'\xdc': 'Ue', u'\xdf': 'ss'},
+ "apostrophe_dict": {u'\u0060': "'", u'\u2018': u"'", u'\u2019': u"'", u'\u201c': u'"', u'\u201d': u'"'}
+ }
+
+
def build_monthtable(self, config: ConfigDict):
table = []
json_file = os.path.join(DIRS.DATADIR, 'monthnames.json')