"""What the TUI knows about the server's books beyond the files: title, author, read status and which books exist at all (so a book can be listed before it is downloaded). Set only by `sync`; the reader's position is progress.py. """ from __future__ import annotations import json import os from pathlib import Path from . import paths _DATA_DIR = paths.data_dir() _META_FILE = _DATA_DIR / "library.json" def _load_all() -> dict[str, dict]: try: data = json.loads(_META_FILE.read_text()) except (OSError, ValueError): return {} return data if isinstance(data, dict) else {} def _save_all(data: dict[str, dict]) -> None: _DATA_DIR.mkdir(parents=True, exist_ok=True) tmp = _META_FILE.with_suffix(".tmp") tmp.write_text(json.dumps(data, indent=1)) os.replace(tmp, _META_FILE) def is_read(book_key: str) -> bool: entry = _load_all().get(book_key) return bool(entry and entry.get("is_read")) def get(book_key: str) -> dict | None: return _load_all().get(book_key) def get_extra(name: str, default=None): """A setting kept beside the books (stored under '_'): the folder order, the sort.""" entry = _load_all().get("_" + name) return entry["value"] if isinstance(entry, dict) and "value" in entry else default def set_extra(name: str, value) -> None: data = _load_all() data["_" + name] = {"value": value} _save_all(data) def set_local_pages(book_key: str, pages: int) -> None: """A book's length worked out from the file here (the server's meta may not have it).""" data = _load_all() entry = data.setdefault("_pages", {"value": {}}) entry.setdefault("value", {})[book_key] = int(pages) _save_all(data) def local_pages() -> dict[str, int]: return dict(get_extra("pages", {}) or {}) def remote_entries() -> dict[str, dict]: """Every server book: key -> {server_id, title, author, is_read, uploaded_at}.""" return {k: v for k, v in _load_all().items() if isinstance(v, dict) and v.get("server_id") is not None} def set_remote(entries: dict[str, dict]) -> None: """Replace the server books with `entries` (a book deleted on the server drops out).""" data = {k: v for k, v in _load_all().items() if not (isinstance(v, dict) and v.get("server_id") is not None)} data.update(entries) _save_all(data)