#!/usr/bin/env python3 """ Save all Markdown documents in your CodiMD history to a local directory. """ import json from pathlib import Path from urllib.error import HTTPError from urllib.parse import quote from urllib.request import Request, urlopen import sys from common import get_sessionid, check_accessibility, print_block_heading def slurp(url, session_id): """Retrieve a (protected) CodiMD resource and return it as a bytes object.""" request = Request(url, headers={"Cookie": f"connect.sid={session_id}"}) with urlopen(request) as stream: return stream.read() def prepare_target_dir(pathname): """Create the directory to dump documents to, but refuse to override an existing one.""" target_dir = Path(pathname) if target_dir.exists(): raise SystemExit(f"ERROR: the target directory {target_dir} already exists. Delete it, then re-execute this " f"script") target_dir.mkdir() return target_dir def export_from_codimd(instance_url, session_id, export_to): check_accessibility(instance_url, session_id, "connect.sid") """Retrieve CodiMD document history and try to download each document.""" print_block_heading(f"Trying to fetch history ({instance_url})") try: data = json.loads(slurp(f"{instance_url}/history", session_id)) except OSError as error: raise SystemExit(f"error: couldn't access the /history endpoint: {error}") except json.JSONDecodeError as error: raise SystemExit(f"error: received malformed JSON: {error}") print_block_heading(f"Preparing target directory ({export_to})") target_dir = prepare_target_dir(export_to) num_ok = num_fail = 0 print_block_heading(f"Accessing history and trying to fetch each document") for row in data["history"]: document_id = row["id"] document_url = f"{instance_url}/{quote(document_id)}" try: contents = slurp(f"{document_url}/download", session_id) with open(Path(target_dir, f"{document_id}.md"), mode="wb") as stream: stream.write(contents) with open(Path(target_dir, f"history.json"), mode="w") as stream: json.dump(data, stream) num_ok += 1 except HTTPError as error: # history might reference deleted or otherwise inaccessible notes error_msg = f"HTTP {error.code} {error.reason}" print(f"{error_msg}: {document_url}", file=sys.stderr) num_fail += 1 print(f"Done: {num_ok} notes successfully downloaded, {num_fail} not accessible.") if __name__ == "__main__": export_from_codimd("https://md.inf.tu-dresden.de", get_sessionid("CodiMD", "connect.sid"), "codimd-documents")