Files
brasiliano/pipeline/reprojeta-meta-mapa.mjs
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

63 lines
2.4 KiB
JavaScript

// reprojeta-meta-mapa.mjs — reescreve SÓ o `meta` de cada item do
// web/atlas/atlas-map.json a partir do pipeline/catalogo.jsonl, sem re-renderizar
// os atlas .webp (posições, cores e recortes das peças ficam intactos).
//
// Use quando as regras de metadados do web/build-atlas.js mudarem e não valer a
// pena reconstruir 47 MB de imagem. As regras aqui têm de espelhar as de
// summarize()/pickAll() lá — em 2026-09-12 as duas foram escritas juntas.
//
// node pipeline/reprojeta-meta-mapa.mjs (da raiz do projeto)
import fs from 'node:fs';
import readline from 'node:readline';
const MAP = 'web/atlas/atlas-map.json';
const pickAll = (item, field, noUrls) => {
const out = [];
for (const row of item.full_table || []) {
if (row.field !== field) continue;
const v = String(row.value ?? '').trim();
if (!v || out.includes(v)) continue;
if (noUrls && /^https?:\/\//i.test(v)) continue;
out.push(v);
}
return out;
};
const some = (i, f, noUrls) => { const v = pickAll(i, f, noUrls); return v.length ? v : undefined; };
const one = (i, f) => pickAll(i, f)[0] || undefined;
const d = JSON.parse(fs.readFileSync(MAP, 'utf8'));
const wanted = new Set(Object.keys(d.map));
const extra = new Map();
const rl = readline.createInterface({ input: fs.createReadStream('pipeline/catalogo.jsonl'), crlfDelay: Infinity });
for await (const line of rl) {
if (!line.trim()) continue;
const o = JSON.parse(line);
if (!wanted.has(o.handle)) continue;
extra.set(o.handle, {
subject: some(o, 'dc.subject'),
description: some(o, 'dc.description'),
coverage: some(o, 'dc.coverage'),
source: one(o, 'dc.source'),
publisher: one(o, 'dc.publisher'),
relation: some(o, 'dc.relation', true),
identifier: some(o, 'dc.identifier', true),
});
}
let enriched = 0, missing = 0;
for (const [h, e] of Object.entries(d.map)) {
const add = extra.get(h);
if (!add) { missing++; continue; }
let touched = false;
for (const [k, v] of Object.entries(add)) if (v !== undefined) { e.meta[k] = v; touched = true; }
// deriváveis da chave: não repetir (ver build-atlas.js)
delete e.meta.handle;
delete e.meta.source_url;
if (touched) enriched++;
}
const out = JSON.stringify(d);
fs.writeFileSync(MAP, out);
console.log(`itens: ${wanted.size} | enriquecidos: ${enriched} | sem registro: ${missing}`);
console.log(`atlas-map.json: ${(out.length / 1048576).toFixed(2)} MB`);