From 8daea634b28907af58bc2f53a39e3ede99ae9bce Mon Sep 17 00:00:00 2001 From: Phil Borman Date: Tue, 13 Feb 2018 17:41:07 +0100 Subject: [PATCH 1/8] Changed directory to match git clone --- init/lazylibrarian.default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init/lazylibrarian.default b/init/lazylibrarian.default index 292984054..06d2ffcad 100644 --- a/init/lazylibrarian.default +++ b/init/lazylibrarian.default @@ -8,7 +8,7 @@ # the service to not start. # [required] set path where lazylibrarian is installed: -APP_PATH=/opt/lazylibrarian +APP_PATH=/opt/LazyLibrarian # [optional] change to 1 to enable daemon ENABLE_DAEMON=1 From 34921e989b63c55363ce7ebe74b17dc87f17b67a Mon Sep 17 00:00:00 2001 From: Phil Borman Date: Tue, 13 Feb 2018 17:41:43 +0100 Subject: [PATCH 2/8] Optimisation for matching books/folders, move/copy to subfolder optimisation --- lazylibrarian/postprocess.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/lazylibrarian/postprocess.py b/lazylibrarian/postprocess.py index 1759b5533..72a9fe551 100644 --- a/lazylibrarian/postprocess.py +++ b/lazylibrarian/postprocess.py @@ -30,7 +30,7 @@ import lib.zipfile as zipfile else: import lib3.zipfile as zipfile - + from lazylibrarian import database, logger, utorrent, transmission, qbittorrent, \ deluge, rtorrent, synology, sabnzbd, nzbget from lazylibrarian.bookwork import audioRename, seriesInfo @@ -160,11 +160,11 @@ def move_into_subdir(sourcedir, targetdir, fname, move='move'): # move the book and any related files too, other book formats, or opf, jpg with same title # (files begin with fname) from sourcedir to new targetdir # can't move metadata.opf or cover.jpg or similar as can't be sure they are ours + # return how many files you moved + cnt = 0 list_dir = os.listdir(makeBytestr(sourcedir)) list_dir = [makeUnicode(item) for item in list_dir] for ourfile in list_dir: - if int(lazylibrarian.LOGLEVEL) > 2: - logger.debug("Checking %s for %s" % (ourfile, fname)) if ourfile.startswith(fname) or is_valid_booktype(ourfile, booktype="audiobook"): if is_valid_booktype(ourfile, booktype="book") \ or is_valid_booktype(ourfile, booktype="audiobook") \ @@ -174,12 +174,18 @@ def move_into_subdir(sourcedir, targetdir, fname, move='move'): if lazylibrarian.CONFIG['DESTINATION_COPY'] or move == 'copy': shutil.copyfile(os.path.join(sourcedir, ourfile), os.path.join(targetdir, ourfile)) setperm(os.path.join(targetdir, ourfile)) + logger.debug("copy_into_subdir %s" % ourfile) + cnt += 1 else: shutil.move(os.path.join(sourcedir, ourfile), os.path.join(targetdir, ourfile)) setperm(os.path.join(targetdir, ourfile)) + logger.debug("move_into_subdir %s" % ourfile) + cnt += 1 except Exception as why: - logger.debug("Failed to copy/move file %s to [%s], %s %s" % + logger.warn("Failed to copy/move file %s to [%s], %s %s" % (ourfile, targetdir, type(why).__name__, str(why))) + continue + return cnt def unpack_archive(pp_path, download_dir, title): @@ -399,7 +405,7 @@ def processDir(reset=False): pp_path = os.path.join(download_dir, fname) if int(lazylibrarian.LOGLEVEL) > 2: - logger.debug("processDir %s %s" % (type(pp_path), repr(pp_path))) + logger.debug("processDir found %s %s" % (type(pp_path), repr(pp_path))) if os.path.isfile(pp_path): # Check for single file downloads first. Book/mag file in download root. @@ -416,7 +422,7 @@ def processDir(reset=False): logger.debug("Skipping %s, found a .bts file" % download_dir) else: aname = os.path.splitext(fname)[0] - while aname[-1] in '. ': + while aname[-1] in '_. ': aname = aname[:-1] targetdir = os.path.join(download_dir, aname) if not os.path.isdir(targetdir): @@ -430,10 +436,14 @@ def processDir(reset=False): if os.path.isdir(targetdir): if book['NZBmode'] in ['torrent', 'magnet', 'torznab'] and \ lazylibrarian.CONFIG['KEEP_SEEDING']: - move_into_subdir(download_dir, targetdir, fname, move='copy') + cnt = move_into_subdir(download_dir, targetdir, aname, move='copy') else: - move_into_subdir(download_dir, targetdir, fname) + cnt = move_into_subdir(download_dir, targetdir, aname) pp_path = targetdir + if cnt: # mark the folder to skip next time round + btsfile = os.path.join(targetdir, "%s.bts" % aname) + with open(btsfile, 'a'): + os.utime(btsfile, None) else: # Is file an archive, if so look inside and extract to new dir res = unpack_archive(pp_path, download_dir, matchtitle) @@ -442,7 +452,7 @@ def processDir(reset=False): else: logger.debug('Skipping unhandled file %s' % fname) - elif os.path.isdir(pp_path): + if os.path.isdir(pp_path): logger.debug('Found folder (%s%%) [%s] for %s %s' % (match, pp_path, book_type, matchtitle)) @@ -475,6 +485,8 @@ def processDir(reset=False): skipped = True if not skipped: matches.append([match, pp_path, book]) + if match == 100: # no point looking any further + break else: logger.debug('%s is not a file or a directory?' % pp_path) else: From 7e545fe6ed4a7376abb681a46a1022b233d1ea28 Mon Sep 17 00:00:00 2001 From: Phil Borman Date: Tue, 13 Feb 2018 17:43:28 +0100 Subject: [PATCH 3/8] Message changes --- lazylibrarian/cache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lazylibrarian/cache.py b/lazylibrarian/cache.py index c723b254c..bd463b8fc 100644 --- a/lazylibrarian/cache.py +++ b/lazylibrarian/cache.py @@ -149,7 +149,7 @@ def get_cached_request(url, useCache=True, cache="XML"): if valid_cache: lazylibrarian.CACHE_HIT = int(lazylibrarian.CACHE_HIT) + 1 - logger.debug("CacheHandler: Returning CACHED response for %s" % url) + logger.debug("CacheHandler: Returning CACHED response %s for %s" % (hashfilename, url)) if cache == "JSON": try: source = json.load(open(hashfilename)) From 3817403a3e7eff3d25046a52551bef0393bd3c3e Mon Sep 17 00:00:00 2001 From: Phil Borman Date: Tue, 13 Feb 2018 17:43:56 +0100 Subject: [PATCH 4/8] Fix for testing calibredb 2.xx and python3 --- lazylibrarian/calibre.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/lazylibrarian/calibre.py b/lazylibrarian/calibre.py index 10c6f98f1..641902c73 100644 --- a/lazylibrarian/calibre.py +++ b/lazylibrarian/calibre.py @@ -16,7 +16,7 @@ import cherrypy import lazylibrarian from lazylibrarian import logger, database -from lazylibrarian.formatter import unaccented, getList +from lazylibrarian.formatter import unaccented, getList, makeUnicode from lazylibrarian.importer import addAuthorNameToDB, search_for, import_book from lazylibrarian.librarysync import find_book_in_db from lib.fuzzywuzzy import fuzz @@ -356,21 +356,20 @@ def calibreTest(): if '(calibre ' in res and res.endswith(')'): # extract calibredb version number res = res.split('(calibre ')[1] - res = 'calibredb ok, version ' + res[:-1] + vernum = res[:-1] + res = 'calibredb ok, version ' + vernum # get a list of categories and counters from the database cats, err, rc = calibredb('list_categories', ['-i']) cnt = 0 - if rc: + if not len(cats): res = res + '\nDatabase READ Failed' else: - res = res + '\nDatabase: ' + err for entry in cats.split('\n'): - try: - words = entry.split() - if words[-1].isdigit(): - cnt += int(words[-1]) - except IndexError: - cnt += 0 + words = entry.split() + if 'ITEMS' in words: + idx = words.index('ITEMS') + 1 + if words[idx].isdigit(): + cnt += int(words[idx]) if cnt: res = res + '\nDatabase READ ok' wrt, err, rc = calibredb('add', ['--authors', 'LazyLibrarian', '--title', 'dummy', '--empty'], []) @@ -378,7 +377,10 @@ def calibreTest(): res = res + '\nDatabase WRITE Failed' else: calibre_id = wrt.split("book ids: ", 1)[1].split("\n", 1)[0] - rmv, err, rc = calibredb('remove', ['--permanent', calibre_id], []) + if vernum.startswith('2'): + rmv, err, rc = calibredb('remove', [calibre_id], []) + else: + rmv, err, rc = calibredb('remove', ['--permanent', calibre_id], []) if not rc: res = res + '\nDatabase WRITE ok' else: @@ -421,9 +423,13 @@ def calibredb(cmd=None, prelib=None, postlib=None): p = Popen(params, stdout=PIPE, stderr=PIPE) res, err = p.communicate() rc = p.returncode + res = makeUnicode(res) + err = makeUnicode(err) if rc: if 'Errno 111' in err: logger.debug("calibredb returned %s: Connection refused" % rc) + elif cmd == 'list_categories' and len(res): + rc = 0 # false error return of 1 on v2.xx calibredb else: logger.debug("calibredb returned %s: res[%s] err[%s]" % (rc, res, err)) except Exception as e: @@ -444,6 +450,8 @@ def calibredb(cmd=None, prelib=None, postlib=None): try: q = Popen(params, stdout=PIPE, stderr=PIPE) res, err = q.communicate() + res = makeUnicode(res) + err = makeUnicode(err) rc = q.returncode if rc: logger.debug("calibredb retry returned %s: res[%s] err[%s]" % (rc, res, err)) From 4efa5400154046cb36034a37a3fc21775bf4c0c6 Mon Sep 17 00:00:00 2001 From: Phil Borman Date: Tue, 13 Feb 2018 17:45:45 +0100 Subject: [PATCH 5/8] Message changes --- lazylibrarian/transmission.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lazylibrarian/transmission.py b/lazylibrarian/transmission.py index 27b0ad4d4..c8818625e 100644 --- a/lazylibrarian/transmission.py +++ b/lazylibrarian/transmission.py @@ -220,7 +220,7 @@ def torrentAction(method, arguments): session_id = response.headers['x-transmission-session-id'] if not session_id: - logger.error("Expected a Session ID from Transmission") + logger.error("Expected a Session ID from Transmission, got %s" % response.status_code) return # Prepare next request From 4755ed939338ae24a72d513053b3f0c18ad0f564 Mon Sep 17 00:00:00 2001 From: Phil Borman Date: Tue, 13 Feb 2018 17:46:07 +0100 Subject: [PATCH 6/8] Pycharm tidying --- lazylibrarian/__init__.py | 1 - lazylibrarian/librarysync.py | 1 - lazylibrarian/versioncheck.py | 6 ++---- lib3/feedparser.py | 9 ++++----- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/lazylibrarian/__init__.py b/lazylibrarian/__init__.py index 6fe042398..e704fe784 100644 --- a/lazylibrarian/__init__.py +++ b/lazylibrarian/__init__.py @@ -882,7 +882,6 @@ def config_write(part=None): CFG.set(section, key.lower(), value) - # sanity check for typos... for key in list(CONFIG.keys()): if key not in list(CONFIG_DEFINITIONS.keys()): diff --git a/lazylibrarian/librarysync.py b/lazylibrarian/librarysync.py index 258e4d2ca..a218344c2 100644 --- a/lazylibrarian/librarysync.py +++ b/lazylibrarian/librarysync.py @@ -514,7 +514,6 @@ def LibraryScan(startdir=None, library='eBook', authid=None, remove=True): filename = os.path.join(rootdir, files) if PY2: filename = filename.encode(lazylibrarian.SYS_ENCODING) - id3r = None if TinyTag: try: id3r = TinyTag.get(filename) diff --git a/lazylibrarian/versioncheck.py b/lazylibrarian/versioncheck.py index df21ccfac..c2d62e35f 100644 --- a/lazylibrarian/versioncheck.py +++ b/lazylibrarian/versioncheck.py @@ -74,10 +74,8 @@ def runGit(args): shell=True, cwd=lazylibrarian.PROG_DIR) output, err = p.communicate() - if output: - output = makeUnicode(output).strip('\n') - if err: - err = makeUnicode(err) + output = makeUnicode(output).strip('\n') + err = makeUnicode(err) logmsg('debug', '(RunGit)Git output: [%s]' % output) diff --git a/lib3/feedparser.py b/lib3/feedparser.py index ee8416c11..642a45296 100644 --- a/lib3/feedparser.py +++ b/lib3/feedparser.py @@ -192,15 +192,16 @@ def _xmlescape(data,entities={}): # sgmllib is not available by default in Python 3; if the end user doesn't have # it available then we'll lose illformed XML parsing and content santizing +_SGML_AVAILABLE = 0 try: import sgmllib + _SGML_AVAILABLE = 1 except ImportError: # This is probably Python 3, which doesn't include sgmllib anymore try: - import lib.sgmllib3 as sgmllib + import lib3.sgmllib as sgmllib + _SGML_AVAILABLE = 1 except ImportError: - _SGML_AVAILABLE = 0 - # Mock sgmllib enough to allow subclassing later on class sgmllib(object): class SGMLParser(object): @@ -208,8 +209,6 @@ def goahead(self, i): pass def parse_starttag(self, i): pass -else: - _SGML_AVAILABLE = 1 # sgmllib defines a number of module-level regular expressions that are # insufficient for the XML parsing feedparser needs. Rather than modify From f21b17b52444cf9ebe58b4eecf62913fe41f5177 Mon Sep 17 00:00:00 2001 From: Phil Borman Date: Tue, 13 Feb 2018 18:08:14 +0100 Subject: [PATCH 7/8] Pycharm tidying --- lazylibrarian/bookwork.py | 3 ++- lazylibrarian/directparser.py | 1 + lazylibrarian/librarysync.py | 2 +- lazylibrarian/notifiers/prowl.py | 2 ++ lazylibrarian/notifiers/pushover.py | 2 ++ lazylibrarian/notifiers/tweet.py | 2 +- lazylibrarian/postprocess.py | 2 +- lazylibrarian/qbittorrent.py | 5 ++++- lazylibrarian/torrentparser.py | 1 + lazylibrarian/utorrent.py | 8 ++++++-- lazylibrarian/versioncheck.py | 2 -- 11 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lazylibrarian/bookwork.py b/lazylibrarian/bookwork.py index 61e223b8c..4599514c8 100644 --- a/lazylibrarian/bookwork.py +++ b/lazylibrarian/bookwork.py @@ -23,6 +23,7 @@ from lazylibrarian.formatter import safe_unicode, plural, cleanName, unaccented, formatAuthorName, \ is_valid_booktype, check_int, getList, replace_all, makeUnicode, makeBytestr from lib.fuzzywuzzy import fuzz +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_parse import quote_plus, urlencode try: from lib.tinytag import TinyTag @@ -102,7 +103,7 @@ def audioRename(bookid): return book_filename if check_int(total, 0) and check_int(total, 0) != cnt: - logger.warn("%s: Reported %s parts, got %i" % (exists['BookName'], b, cnt)) + logger.warn("%s: Reported %s parts, got %i" % (exists['BookName'], total, cnt)) return book_filename if '/' in track: # does the track include total (eg 1/12) diff --git a/lazylibrarian/directparser.py b/lazylibrarian/directparser.py index ec95f8f4e..d27901a4c 100644 --- a/lazylibrarian/directparser.py +++ b/lazylibrarian/directparser.py @@ -18,6 +18,7 @@ from lazylibrarian.formatter import plural, formatAuthorName, makeUnicode from lazylibrarian.torrentparser import url_fix from lib.six import PY2 +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_parse import urlparse, urlencode if PY2: diff --git a/lazylibrarian/librarysync.py b/lazylibrarian/librarysync.py index a218344c2..757cb6a95 100644 --- a/lazylibrarian/librarysync.py +++ b/lazylibrarian/librarysync.py @@ -29,7 +29,7 @@ from lazylibrarian.importer import update_totals, addAuthorNameToDB from lib.fuzzywuzzy import fuzz from lib.mobi import Mobi - +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_parse import quote_plus, urlencode try: diff --git a/lazylibrarian/notifiers/prowl.py b/lazylibrarian/notifiers/prowl.py index b19b730e0..353405e9b 100644 --- a/lazylibrarian/notifiers/prowl.py +++ b/lazylibrarian/notifiers/prowl.py @@ -2,7 +2,9 @@ from lazylibrarian import logger from lazylibrarian.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD from lib.six import PY2 +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_parse import urlencode +# noinspection PyUnresolvedReferences from lib.six.moves.http_client import HTTPSConnection diff --git a/lazylibrarian/notifiers/pushover.py b/lazylibrarian/notifiers/pushover.py index 952ee9501..2a7fca3ce 100644 --- a/lazylibrarian/notifiers/pushover.py +++ b/lazylibrarian/notifiers/pushover.py @@ -19,7 +19,9 @@ from lib.six import PY2 +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_parse import urlencode +# noinspection PyUnresolvedReferences from lib.six.moves.http_client import HTTPSConnection import lazylibrarian diff --git a/lazylibrarian/notifiers/tweet.py b/lazylibrarian/notifiers/tweet.py index d927d0dee..a1f29cd4a 100644 --- a/lazylibrarian/notifiers/tweet.py +++ b/lazylibrarian/notifiers/tweet.py @@ -22,7 +22,7 @@ import lib.oauth2 as oauth import lib.pythontwitter as twitter - +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_parse import parse_qsl diff --git a/lazylibrarian/postprocess.py b/lazylibrarian/postprocess.py index 72a9fe551..9788c5029 100644 --- a/lazylibrarian/postprocess.py +++ b/lazylibrarian/postprocess.py @@ -183,7 +183,7 @@ def move_into_subdir(sourcedir, targetdir, fname, move='move'): cnt += 1 except Exception as why: logger.warn("Failed to copy/move file %s to [%s], %s %s" % - (ourfile, targetdir, type(why).__name__, str(why))) + (ourfile, targetdir, type(why).__name__, str(why))) continue return cnt diff --git a/lazylibrarian/qbittorrent.py b/lazylibrarian/qbittorrent.py index b0be21463..eb5fbc091 100644 --- a/lazylibrarian/qbittorrent.py +++ b/lazylibrarian/qbittorrent.py @@ -23,10 +23,13 @@ from lazylibrarian import logger from lazylibrarian.common import USER_AGENT from lazylibrarian.formatter import check_int, getList, makeBytestr, makeUnicode - +# noinspection PyUnresolvedReferences from lib.six.moves import http_cookiejar +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_parse import urlencode +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_request import HTTPCookieProcessor, build_opener, Request +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_error import URLError diff --git a/lazylibrarian/torrentparser.py b/lazylibrarian/torrentparser.py index c8eadd6c8..3525217e2 100644 --- a/lazylibrarian/torrentparser.py +++ b/lazylibrarian/torrentparser.py @@ -18,6 +18,7 @@ from lazylibrarian.cache import fetchURL from lazylibrarian.formatter import plural, unaccented, makeUnicode from lib.six import PY2, PY3, text_type +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_parse import quote_plus, quote, urlencode, urlsplit, urlunsplit if PY2: diff --git a/lazylibrarian/utorrent.py b/lazylibrarian/utorrent.py index 62e80708d..698a016c3 100644 --- a/lazylibrarian/utorrent.py +++ b/lazylibrarian/utorrent.py @@ -19,10 +19,14 @@ from lazylibrarian.common import USER_AGENT from lazylibrarian.formatter import check_int, getList from lib.six import PY2 +# noinspection PyUnresolvedReferences from lib.six.moves import http_cookiejar -from lib.six.moves.urllib_parse import quote_plus, urlencode, urljoin +# noinspection PyUnresolvedReferences +from lib.six.moves.urllib_parse import urljoin, urlencode +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_request import HTTPCookieProcessor, HTTPBasicAuthHandler, \ build_opener, install_opener, Request +# noinspection PyUnresolvedReferences from lib.six.moves.urllib_error import HTTPError @@ -144,7 +148,7 @@ def setprio(self, hashid, priority, *files): return self._action(params) def _action(self, params, body=None, content_type=None): - url = self.base_url + '/gui/' + '?token=' + self.token + '&' + urllib.urlencode(params) + url = self.base_url + '/gui/' + '?token=' + self.token + '&' + urlencode(params) request = Request(url) if lazylibrarian.CONFIG['PROXY_HOST']: for item in getList(lazylibrarian.CONFIG['PROXY_TYPE']): diff --git a/lazylibrarian/versioncheck.py b/lazylibrarian/versioncheck.py index c2d62e35f..7eb370883 100644 --- a/lazylibrarian/versioncheck.py +++ b/lazylibrarian/versioncheck.py @@ -26,8 +26,6 @@ except ImportError: import lib.requests as requests -from lib.six import PY2 - from lazylibrarian import logger, version from lazylibrarian.common import USER_AGENT, proxyList from lazylibrarian.formatter import check_int, makeUnicode From f208dac62b93e2f062baeef845a3fa45ab8bf730 Mon Sep 17 00:00:00 2001 From: Phil Borman Date: Tue, 13 Feb 2018 19:50:38 +0100 Subject: [PATCH 8/8] Speedup for empty strings --- lazylibrarian/formatter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lazylibrarian/formatter.py b/lazylibrarian/formatter.py index 76b7ae872..f2d7dfc56 100644 --- a/lazylibrarian/formatter.py +++ b/lazylibrarian/formatter.py @@ -230,8 +230,8 @@ def md5_utf8(txt): def makeUnicode(txt): # convert a bytestring to unicode, don't know what encoding it might be so try a few # it could be a file on a windows filesystem, unix... - if txt is None: - return txt + if txt is None or not txt: + return u'' elif isinstance(txt, text_type): return txt for encoding in [lazylibrarian.SYS_ENCODING, 'latin-1', 'utf-8']: @@ -248,8 +248,8 @@ def makeUnicode(txt): def makeBytestr(txt): # convert unicode to bytestring, needed for os.walk and os.listdir # listdir falls over if given unicode startdir and a filename in a subdir can't be decoded to ascii - if txt is None: - return txt + if txt is None or not txt: + return b'' elif not isinstance(txt, text_type): # nothing to do if already bytestring return txt for encoding in [lazylibrarian.SYS_ENCODING, 'latin-1', 'utf-8']: