Skip to content

Instantly share code, notes, and snippets.

@Terrance
Created May 8, 2023 22:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Terrance/128d00e84462984ee194b194c4c14d06 to your computer and use it in GitHub Desktop.
Save Terrance/128d00e84462984ee194b194c4c14d06 to your computer and use it in GitHub Desktop.
Script to migrate reading history and highlights from Readera (reads from an unzipped backup file) to Librera (writes to a profile directory), a pair of Android reading apps.
#!/usr/bin/env python3
import hashlib
import json
import logging
import os.path
from pathlib import Path
LOG = logging.getLogger(__name__)
PROGRESS = {
"cp": False, # crop pages
"d": 0, # delta
"dc": False, # double pages cover
"dp": False, # double pages normal
"lk": 1, # lock (0 = None, 1 = Yes, 2 = None)
# "p": 1, # progress ratio
"s": 120, # scroll speed
"sp": False, # split pages
# "t": 1682461584539, # time
"x": 0, # x-axis offset
"y": 0, # y-axis offset
"z": 100 # zoom percent
}
BOOKMARK = {
"isF": False,
# "p": 0.54811203, # position ratio
# "path": "$aroot/path/to/file.epub",
# "t": 1682461584539, # time
# "text": "quoted text",
}
def sha1(target: Path):
with open(target, "rb") as f:
return hashlib.sha1(f.read()).hexdigest()
def main(sroot: Path, aroot: Path, rdir: Path, ldir: Path, hfile: Path):
LOG.info("Loading Readera library")
with open(rdir / "library.json") as f:
readera = json.load(f)
LOG.info("Loading Librera profile")
with open(ldir / "app-Progress.json") as f:
librera_progress = json.load(f)
with open(ldir / "app-Recent.json") as f:
librera_recent = json.load(f)
with open(ldir / "app-Bookmarks.json") as f:
librera_bookmarks = json.load(f)
hashes: dict[str, Path]
try:
LOG.info("Loading hashes")
with open(hfile) as f:
hashes = {k: Path(v) for k, v in json.load(f).items()}
except:
LOG.exception("Regenerating hashes")
hashes = {}
for path in sroot.rglob("*"):
if path.is_file():
relpath = path.relative_to(sroot)
LOG.debug(relpath)
hashes[sha1(path)] = relpath
LOG.info("Saving hashes")
with open(hfile, "w") as f:
json.dump(hashes, f, default=lambda o: str(o))
LOG.info("Processing Readera library")
for doc in readera["docs"]:
try:
path = hashes[doc["data"]["doc_sha1"]]
except KeyError:
continue
if not doc["data"]["doc_have_read_time"]:
continue
position = json.loads(doc["data"]["doc_position"])
if position["ratio"] <= 0:
continue
lpath = os.path.join(aroot, path)
LOG.debug(lpath)
time = max(
doc["data"]["doc_have_read_time"],
doc["data"]["doc_last_read_time"],
)
progress = dict(PROGRESS)
progress["p"] = position["ratio"]
progress["t"] = time
librera_progress[path.name] = progress
recent = {
"path": lpath,
"time": time,
}
librera_recent.append(recent)
for citation in doc["citations"]:
bookmark = dict(BOOKMARK)
bookmark["p"] = citation["note_index"]
bookmark["path"] = lpath
bookmark["t"] = citation["note_insert_time"]
bookmark["text"] = citation["note_body"]
librera_bookmarks[citation["note_insert_time"]] = bookmark
LOG.info("Saving Librera profile")
with open(ldir / "app-Progress.json", "w") as f:
json.dump(librera_progress, f)
with open(ldir / "app-Recent.json", "w") as f:
json.dump(librera_recent, f)
with open(ldir / "app-Bookmarks.json", "w") as f:
json.dump(librera_bookmarks, f)
if __name__ == "__main__":
import sys
logging.basicConfig(level=logging.DEBUG)
main(*(Path(arg) for arg in sys.argv[1:]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment