obok: linux: improve Kobo Desktop directory searching

The Kobo Desktop program will (when running under Wine on Linux) put all
of its data in the current working directory. This means that there
may be more than one Kobo.sqlite floating around by the user, which
leads to Obok showing an outdated list of books and the user being
confused by Obok cannot find the full list of books.

Solving this completely appears to be a bit too complicated, so this
patch is a best-effort improvement for the worst cases which can be
caused by this:

 1. If the user deletes the files but Obok has already cached the path,
    previously Obok would just error out rather than trying to search
    for a new Kobo.sqlite path and updating the cache.

 2. We search $HOME before searching /, which speeds up initial usage of
    Obok in the common case (usually Kobo Desktop will be installed in
    ~/.wine/drive_c) and also ensures that we correctly preference the
    current user's Kobo Desktop installation.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
This commit is contained in:
Aleksa Sarai 2022-02-20 03:16:26 +11:00
parent f4634b5eab
commit ad33aea18d
No known key found for this signature in database
GPG key ID: 9D94B96321B9D012

View file

@ -376,36 +376,50 @@ class KoboLibrary(object):
elif sys.platform.startswith('darwin'):
self.kobodir = os.path.join(os.environ['HOME'], "Library", "Application Support", "Kobo", "Kobo Desktop Edition")
elif sys.platform.startswith('linux'):
# Since on Linux, you have to run Kobo Desktop within Wine,
# there is no guarantee where Kobo.sqlite (and the rest of
# the kobo directory) might be.
#
# It should also be noted that Kobo Desktop will store all
# of it files in the current directory where you run it,
# meaning that a user might accidentally create several
# Kobo.sqlite files which are all separate and then be
# confused why Obok can't find any of the new books. Sadly
# there isn't a trivial way to deal with this.
#sets ~/.config/calibre as the location to store the kobodir location info file and creates this directory if necessary
kobodir_cache_dir = os.path.join(os.environ['HOME'], ".config", "calibre")
# We cache the kobodir we find in ~/.config/calibre.
kobodir_cache_dir = os.path.join(os.environ['HOME'], ".config", "calibre", "plugins", "obok")
if not os.path.isdir(kobodir_cache_dir):
os.mkdir(kobodir_cache_dir)
kobodir_cache_file = os.path.join(kobodir_cache_dir, "kobo-location")
#appends the name of the file we're storing the kobodir location info to the above path
kobodir_cache_file = str(kobodir_cache_dir) + "/" + "kobo location"
try:
# If the cached version exists and the path does really
# contain Kobo.sqlite, use that.
with open(kobodir_cache_file, "r") as f:
cached_kobodir = f.read().strip()
assert os.path.isfile(os.path.join(cached_kobodir, "Kobo.sqlite"))
self.kobodir = cached_kobodir
except (AssertionError, FileNotFoundError):
# If there was no cached version, search the entire
# filesystem tree for a directory containing
# "Kobo.sqlite".
#
# We first search $HOME to avoid picking another user's
# Kobo.sqlite file, but then fallback to / if there was
# nothing in $HOME.
for candidate_root in (os.environ["HOME"], "/"):
for root, _, files in os.walk(candidate_root):
if "Kobo.sqlite" in files:
with open(kobodir_cache_file, "w") as f:
f.write("%s/\n" % (root,))
self.kobodir = root
break
"""if the above file does not exist, recursively searches from the root
of the filesystem until kobodir is found and stores the location of kobodir
in that file so this loop can be skipped in the future"""
original_stdout = sys.stdout
if not os.path.isfile(kobodir_cache_file):
for root, dirs, files in os.walk('/'):
for file in files:
if file == 'Kobo.sqlite':
kobo_linux_path = str(root)
with open(kobodir_cache_file, 'w') as f:
sys.stdout = f
print(kobo_linux_path, end='')
sys.stdout = original_stdout
f = open(kobodir_cache_file, 'r' )
self.kobodir = f.read()
# desktop versions use Kobo.sqlite
# Desktop versions use Kobo.sqlite.
kobodb = os.path.join(self.kobodir, "Kobo.sqlite")
# check for existence of file
if (not(os.path.isfile(kobodb))):
if not os.path.isfile(kobodb):
# give up here, we haven't found anything useful
self.kobodir = u""
kobodb = u""