Files
brasiliano/pipeline/converte-wordpress-md.py
rodado 290c4cc21d feat: acervo Brasiliana Fotográfica coletado e mural 3D no ar
Captura integral do acervo da Brasiliana Fotográfica (Biblioteca Nacional)
para s3://brasiliana: 13.060 itens, 12.985 com imagem de preservação, 13.059
com miniatura derivada, 2.137 cópias legadas e 636 posts do blog. 41.444
objetos no ledger.

Os 75 itens sem preservação estão em errors.md: a página do item responde
200, mas a origem serve o bitstream com HTTP 500. Nenhum fica fora do mural,
porque todos têm thumbnail.

Não versionado, por viver no bucket ou ser reconstruível: catálogo,
posts .jsonl, atlas .webp, sqlite de estado e logs. Credenciais ficam de
fora pelo .gitignore.
2026-09-13 20:17:02 +02:00

76 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""
Converte wordpress-posts.jsonl (saido do coletor-wordpress.js) em um .md
por post, com front-matter YAML. Imagens NAO sao baixadas -- os posts so
usam miniaturas dos mesmos handles que o acervo principal ja cobre (ver
PLANO.md); o valor novo aqui e o texto + o mapeamento pra handles.
Uso: python3 converte-wordpress-md.py [wordpress-posts.jsonl] [pasta-saida]
"""
import json, re, sys, unicodedata
from pathlib import Path
ENTRADA = Path(sys.argv[1] if len(sys.argv) > 1 else "wordpress-posts.jsonl")
SAIDA = Path(sys.argv[2] if len(sys.argv) > 2 else "../wordpress")
SAIDA.mkdir(parents=True, exist_ok=True)
def slug(txt):
txt = unicodedata.normalize("NFKD", txt).encode("ascii", "ignore").decode()
txt = re.sub(r"[^a-zA-Z0-9]+", "-", txt).strip("-").lower()
return txt[:80] or "sem-titulo"
def yaml_str(s):
if s is None:
return "null"
return '"' + str(s).replace("\\", "\\\\").replace('"', '\\"') + '"'
def yaml_lista(items):
if not items:
return "[]"
return "[" + ", ".join(yaml_str(i) for i in items) + "]"
n_ok = n_erro = 0
for linha in open(ENTRADA, encoding="utf-8"):
if not linha.strip():
continue
post = json.loads(linha)
if post.get("erro"):
n_erro += 1
continue
titulo = post.get("titulo") or f"post-{post['id']}"
nome_arquivo = f"{post['id']}-{slug(titulo)}.md"
frontmatter = "\n".join([
"---",
f"id: {post['id']}",
f"url: {yaml_str(post.get('url'))}",
f"titulo: {yaml_str(titulo)}",
f"autor: {yaml_str(post.get('autor'))}",
f"data: {yaml_str(post.get('data_iso'))}",
f"categorias: {yaml_lista(post.get('categorias') or [])}",
f"handles_referenciados: {yaml_lista(post.get('handles_referenciados') or [])}",
f"fetched_at: {yaml_str(post.get('fetched_at'))}",
"---",
])
corpo = post.get("corpo") or "*(sem conteúdo extraído)*"
# nota de referencia pros handles, com link relativo pro nosso acervo
handles = post.get("handles_referenciados") or []
nota_handles = ""
if handles:
linhas_h = "\n".join(f"- `{h}` — `itens/{h.replace('/', '_')}/`" for h in handles)
nota_handles = f"\n\n---\n\n**Itens do acervo referenciados neste post:**\n\n{linhas_h}\n"
conteudo = f"{frontmatter}\n\n# {titulo}\n\n{corpo}{nota_handles}\n"
(SAIDA / nome_arquivo).write_text(conteudo, encoding="utf-8")
n_ok += 1
print(f"{n_ok} arquivos .md gerados em {SAIDA.resolve()}")
print(f"{n_erro} posts com erro na coleta, pulados")