Library-Screen synct jetzt selbstständig statt den expliziten `sync`-Befehl vorauszusetzen: einmal im Hintergrund direkt nach dem Start (neue Bücher/ Fortschritt erscheinen, sobald fertig), einmal abgewartet beim Beenden über q (DioraTuiApp.action_quit). Beides best-effort — ohne gespeicherte Zugangsdaten oder bei Netzwerkfehlern bleibt die lokale Bibliothek unangetastet nutzbar. Bibliotheksliste sortiert jetzt nach zuletzt geöffnetem Buch (progress.json updated_at, neueste zuerst) und blendet gelesene Bücher standardmäßig aus (EBook.is_read aus dem Sync-Snapshot, lokal in library.json gespiegelt) — r-Taste zeigt sie für die Sitzung wieder an. Getestet: vollständig isoliert (Pfad-Konstanten gemonkeypatcht statt echter ~/.config-/~/.local/share-Dateien) gegen einen echten Dev-Server mit zwei Büchern unterschiedlichen Gelesen-Status und Fortschritts-Zeitstempeln — Auto-Sync, Filter-Default, Toggle und Sortierreihenfolge korrekt bestätigt; Sync-vor-dem-Beenden separat verifiziert (kein echter Hänger, nur ein Test-Timing-Artefakt ohne pilot.pause()).
43 lines
1.2 KiB
Python
43 lines
1.2 KiB
Python
"""Local per-book metadata pulled from the server — currently just "read"
|
|
status (EBook.is_read from the /api/sync/ snapshot). Kept separate from
|
|
progress.py (reading position): different concern, different cadence — this
|
|
is only ever set by `diora-tui sync`, never by the reader itself.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from platformdirs import user_data_dir
|
|
|
|
_DATA_DIR = Path(user_data_dir("diora-tui", "diora"))
|
|
_META_FILE = _DATA_DIR / "library.json"
|
|
|
|
|
|
def _load_all() -> dict[str, dict]:
|
|
if not _META_FILE.exists():
|
|
return {}
|
|
try:
|
|
return json.loads(_META_FILE.read_text())
|
|
except (json.JSONDecodeError, OSError):
|
|
return {}
|
|
|
|
|
|
def _save_all(data: dict[str, dict]) -> None:
|
|
_DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
_META_FILE.write_text(json.dumps(data, indent=2))
|
|
|
|
|
|
def is_read(book_id: str) -> bool:
|
|
entry = _load_all().get(book_id)
|
|
return bool(entry and entry.get("is_read"))
|
|
|
|
|
|
def set_many(read_status: dict[str, bool]) -> None:
|
|
if not read_status:
|
|
return
|
|
data = _load_all()
|
|
for book_id, read in read_status.items():
|
|
data.setdefault(book_id, {})["is_read"] = read
|
|
_save_all(data)
|