"""Выгрузка каталога: Markdown, HTML с поиском, JSON, CSV.""" from __future__ import annotations import csv import html import json from datetime import datetime from pathlib import Path from . import config, db def fetch_all(con) -> list[dict]: rows = con.execute( "SELECT d.id, d.title, d.author, d.year, d.pages, d.ext, d.size, d.lang," " d.kind, d.folder, d.rel_path, d.path, d.description, d.theses," " d.keywords, d.scanned, d.error, u.keywords AS user_keywords" " FROM docs d LEFT JOIN user_keywords u ON u.path = d.path" " ORDER BY d.folder, d.title").fetchall() out = [] for r in rows: d = dict(r) d["theses"] = json.loads(d["theses"] or "[]") d["keywords"] = json.loads(d["keywords"] or "[]") d["user_keywords"] = json.loads(d["user_keywords"] or "[]") out.append(d) return out def _size(n: int) -> str: for unit in ("Б", "КБ", "МБ", "ГБ"): if n < 1024: return "%.0f %s" % (n, unit) n /= 1024.0 return "%.1f ТБ" % n # -------------------------------------------------------------------------- # Markdown # -------------------------------------------------------------------------- def to_markdown(docs: list[dict], root: str, path: Path) -> Path: by_folder: dict[str, list[dict]] = {} for d in docs: by_folder.setdefault(d["folder"], []).append(d) lines = [ "# Каталог библиотеки", "", "Источник: `%s` " % root, "Документов: **%d**, разделов: **%d** " % (len(docs), len(by_folder)), "Составлен: %s" % datetime.now().strftime("%d.%m.%Y %H:%M"), "", "## Разделы", "", ] for folder in sorted(by_folder): anchor = folder.lower().replace(" ", "-").replace("\\", "-").replace(".", "") lines.append("- [%s](#%s) — %d" % (folder, anchor, len(by_folder[folder]))) lines.append("") for folder in sorted(by_folder): lines += ["", "## %s" % folder, ""] for d in sorted(by_folder[folder], key=lambda x: (x["title"] or "").lower()): head = "### %s" % (d["title"] or d["rel_path"]) lines.append(head) facts = [d["ext"].lstrip("."), d["kind"] or ""] if d["author"]: facts.append(d["author"]) if d["year"]: facts.append(str(d["year"])) if d["pages"]: facts.append("%d с." % d["pages"]) facts.append(_size(d["size"])) if d["scanned"]: facts.append("скан") lines.append("*%s*" % " · ".join(f for f in facts if f)) lines.append("") lines.append(d["description"] or "") if d["theses"]: lines.append("") lines.append("**Тезисы:**") for t in d["theses"]: lines.append("- %s" % t) if d["keywords"]: lines.append("") lines.append("**Ключевые слова:** %s" % ", ".join(d["keywords"])) if d["user_keywords"]: lines.append("") lines.append("**Свои ключевые слова:** %s" % ", ".join(d["user_keywords"])) lines.append("") lines.append("`%s`" % d["rel_path"]) lines.append("") path.parent.mkdir(parents=True, exist_ok=True) path.write_text("\n".join(lines), encoding="utf-8") return path # -------------------------------------------------------------------------- # HTML с поиском # -------------------------------------------------------------------------- HTML_TEMPLATE = """ Каталог библиотеки

Каталог библиотеки

""" def to_html(docs: list[dict], root: str, path: Path) -> Path: data = [{ "t": d["title"] or d["rel_path"], "a": d["author"] or "", "y": d["year"] or "", "pg": d["pages"] or 0, "e": d["ext"], "l": d["lang"] or "", "kind": d["kind"] or "", "f": d["path"], "p": d["rel_path"], "fold": d["folder"], "d": d["description"] or "", "th": d["theses"], "k": d["keywords"], "mk": d["user_keywords"], "sz": _size(d["size"]), "sc": 1 if d["scanned"] else 0, } for d in docs] exts = sorted({d["ext"] for d in docs}) folders = sorted({d["folder"] for d in docs}) # " раньше времени. payload = json.dumps(data, ensure_ascii=False).replace("%s' % (e, html.escape(e.lstrip("."))) for e in exts)) .replace("__FOLDERS__", "".join( '' % (html.escape(f), html.escape(f[:70])) for f in folders))) path.parent.mkdir(parents=True, exist_ok=True) path.write_text(out, encoding="utf-8") return path # -------------------------------------------------------------------------- # JSON / CSV # -------------------------------------------------------------------------- def to_json(docs: list[dict], path: Path) -> Path: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(docs, ensure_ascii=False, indent=1), encoding="utf-8") return path def to_csv(docs: list[dict], path: Path) -> Path: path.parent.mkdir(parents=True, exist_ok=True) cols = ("title", "author", "year", "pages", "kind", "lang", "ext", "size", "folder", "rel_path", "description") with open(path, "w", encoding="utf-8-sig", newline="") as f: w = csv.writer(f, delimiter=";") w.writerow(["Название", "Автор", "Год", "Страниц", "Тип", "Язык", "Формат", "Размер", "Раздел", "Путь", "Описание", "Ключевые слова", "Свои ключевые слова"]) for d in docs: w.writerow([d.get(c, "") for c in cols] + [", ".join(d["keywords"]), ", ".join(d["user_keywords"])]) return path def build_all(con, out_dir: Path | None = None) -> dict[str, Path]: out_dir = Path(out_dir or config.OUT_DIR) docs = fetch_all(con) root = db.get_meta(con, "root", str(config.DEFAULT_ROOT)) return { "html": to_html(docs, root, out_dir / "catalog.html"), "md": to_markdown(docs, root, out_dir / "catalog.md"), "json": to_json(docs, out_dir / "catalog.json"), "csv": to_csv(docs, out_dir / "catalog.csv"), }