Created
May 8, 2023 22:08
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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