459 lines
26 KiB
Markdown
459 lines
26 KiB
Markdown
# PLANO — Brasiliana Fotográfica → S3
|
||
|
||
> **Comece por aqui.** Documento de transferência: uma sessão nova consegue
|
||
> retomar o trabalho só com este arquivo. Detalhe técnico completo em
|
||
> `README.md`.
|
||
|
||
**Objetivo:** os 13.036 itens da Brasiliana Fotográfica — metadados e imagens
|
||
em qualidade de preservação — depositados em `s3://brasiliana`, organizados
|
||
como acervo arquivístico (procedência + checksums).
|
||
|
||
**Autorização:** a Biblioteca Nacional foi consultada. Confirmou que o material
|
||
é público e que não tem equipe técnica para fornecer um dump; a coleta por
|
||
scraping é o caminho combinado. Ritmo cortês e identificação continuam valendo.
|
||
|
||
> **Reorganização de pastas em 2026-09-10.** Scripts + estado (catálogo,
|
||
> `.sqlite`, `.log`, `.tmp/`, credenciais) mudaram de raiz para `pipeline/`;
|
||
> visualizações foram para `web/`; `exemplo-item/` virou `examples/exemplo-item/`;
|
||
> `censo.py` virou `archive/censo.py`. Todo comando de terminal abaixo já foi
|
||
> atualizado para o novo caminho. Detalhe completo em `README.md` →
|
||
> "Estrutura do repositório".
|
||
>
|
||
> **Mudança de plano em 2026-09-10 (importante, ver 2.6): o achado 2.4 abaixo
|
||
> não se sustentou.** Cloudflare passou a bloquear bitstream via curl também
|
||
> pra itens sem cache de borda — não só HTML. **Tudo (Fases 2 e 3) roda pelo
|
||
> navegador agora, trilha única**, não mais A/B separadas por tipo de nome.
|
||
> A Fase 4 (legado) segue via curl normalmente — domínio diferente
|
||
> (`objdigital.bn.br`), sem esse bloqueio.
|
||
|
||
---
|
||
|
||
## 1. Estado em 2026-09-30
|
||
|
||
**Coleta concluída em 2026-09-13.** Conferido em 2026-09-30 contra o ledger
|
||
(`pipeline/subidor.sqlite`, tabela `enviados`) e a listagem do bucket.
|
||
|
||
| | Estado |
|
||
|---|---|
|
||
| Fase 1 (metadados) | ✅ `catalogo.jsonl` com **13.060 itens** (o falso-positivo `/1` não está nele), também no bucket, idêntico ao local |
|
||
| Imagem de preservação | ✅ **12.991 itens**, 13.194 arquivos, 127,4 GB (121 itens com 2 a 8 imagens: 203 extras) |
|
||
| Sem preservação | ⚠️ **69 itens**: a origem responde HTTP 500 ao bitstream (`errors.md`). Todos, menos o `7523`, têm a miniatura |
|
||
| Miniatura do DSpace | ✅ 13.060 arquivos em 13.059 itens |
|
||
| Fase 4 (legado objdigital) | ✅ 2.137 arquivos (1.899 JPG, 213 PDF, 25 outros), 9,6 GB |
|
||
| Derivados | ✅ `thumb256` 13.059 e `medio` 13.059 |
|
||
| Blog | ✅ 636 posts em `wordpress/` + `wordpress-posts.jsonl` |
|
||
| Bucket | ✅ 81.269 objetos, 139,2 GB, mais 487 objetos (172 MB) em `descricao/` |
|
||
| `MANIFEST.md` | ✅ versão final no bucket (2026-09-30) |
|
||
| Descrição NOBRADE | ✅ ver §9, também no bucket em `descricao/` |
|
||
| Mural | ✅ no ar em https://xn--2dk.xyz/brasiliana/; o visor NOBRADE está no branch `feat/nobrade` (§9, fase 7) |
|
||
|
||
Nenhum navegador ou subidor precisa estar rodando: a fila local está zerada.
|
||
|
||
---
|
||
|
||
## 2. Cinco achados que não devem ser redescobertos
|
||
|
||
Cada um destes custou horas. Nenhum é óbvio, e vários são contraintuitivos.
|
||
|
||
### 2.1 O sitemap está sete anos desatualizado
|
||
`htmlmap`/`sitemap` são de abril/2019 e listam ~5.300 dos 13.036 itens. Enumerar
|
||
por eles perde **59% do acervo sem erro aparente** — o crawl termina limpo, pela
|
||
metade. Fonte correta: `browse?type=title&rpp=100&offset=N`, percorrido por
|
||
comunidade (o que de quebra etiqueta a instituição de origem).
|
||
|
||
### 2.2 O arquivo de preservação está no DSpace, não no objdigital
|
||
O `DC.identifier` aponta para `objdigital.bn.br` e parece ser o master. É o
|
||
contrário: o bitstream do DSpace tem 5533×4065 (7,4 MB) contra ~2600×2100
|
||
(147 KB) do objdigital. O maior medido: 8679×6484, 34,7 MB — EXIF mostra
|
||
Hasselblad H3D II-39MS a 7216×5412.
|
||
**Inverter isso arquiva o acervo a um quarto da resolução, e nada avisa.**
|
||
|
||
O PDF de 71,9 MB do item 14582 no objdigital não é a mesma imagem melhor: é
|
||
outro objeto, um álbum de várias páginas.
|
||
|
||
### 2.3 O Cloudflare bloqueia automação de navegador — não IP, não geografia
|
||
Medido na mesma máquina, mesmo IP, mesmo instante:
|
||
|
||
| Cliente | Páginas HTML |
|
||
|---|---|
|
||
| Chrome/Brave do usuário | ✅ 200 |
|
||
| `fetch()` de dentro da página | ✅ 200 (>100 seguidas) |
|
||
| Playwright *headed* | ❌ 200 na 1ª, 403 depois |
|
||
| Playwright *headless* | ❌ 403 |
|
||
| curl / httpx | ❌ 403 |
|
||
| Servidor (Hetzner Helsinki) | ❌ 403 |
|
||
|
||
**Proxies não ajudam** — o bloqueio dispara na segunda requisição da mesma
|
||
sessão, não por origem. Testado e descartado. Não repita.
|
||
|
||
### 2.4 Bitstreams passam por curl; páginas HTML não
|
||
`bitstream/...` responde 200 a `curl -L` simples, até com UA de curl. Só o HTML
|
||
é desafiado. É isso que permite baixar os 116 GB fora do navegador, num servidor.
|
||
|
||
### 2.5 Nome de arquivo com percent-encoding leva 403
|
||
Testado com cinco user-agents (Chrome, Safari, Firefox, Googlebot, curl):
|
||
**todos 403** numa URL com `%28`/`%20`, enquanto `curl/8.7.1` puro dá **200**
|
||
numa URL de nome simples. O gatilho é o caminho, não o cliente — variar
|
||
user-agent não resolve. O navegador busca os dois casos sem problema.
|
||
|
||
Daí as duas trilhas — **modelo original, superado, ver 2.6**. Itens da BN
|
||
usam `imagem.jpg` (trilha A); os do IMS usam nomes descritivos com espaços
|
||
e acentos (trilha B).
|
||
|
||
### 2.6 O achado 2.4 não se sustentou — Cloudflare bloqueia bitstream também
|
||
Testado ao vivo em 2026-09-10: item nunca antes acessado, buscado pelo
|
||
navegador (200 OK) e **imediatamente depois** via curl na Finlândia — 403,
|
||
página real do Cloudflare ("Attention Required"). O único item que passava
|
||
por curl (`6066`) só passava porque já tinha sido baixado com sucesso antes
|
||
e ficou em cache de borda (`cf-cache-status: HIT`) — sobra de um caso, não
|
||
regra geral. Pré-aquecer a URL pelo navegador antes de tentar via curl
|
||
**não** transfere o cache pra tornar o curl aceito (testado, falha igual).
|
||
|
||
**Consequência: não existe mais trilha A via servidor.** Tudo — nome simples
|
||
ou com encoding — precisa passar pelo navegador vivo (`fetch()` de dentro da
|
||
página). `baixador.py` na Finlândia fica só pra Fase 4 (objdigital, domínio
|
||
diferente, sem esse bloqueio — ver 2.11).
|
||
|
||
### 2.7 Itens com múltiplos bitstreams reais — não é caso raro
|
||
115 itens (de ~13.058) têm **2 a 6 imagens reais** no bundle ORIGINAL (contagem final no ledger: 121 itens, 2 a 8 imagens), não
|
||
uma. `citation_pdf_url` não é gerado pra esses (o gerador de citação do
|
||
DSpace não sabe qual é "a" imagem quando há mais de uma) — por isso ficam
|
||
sem `preservation_url` na extração simples. Sintoma: `full_table` tem
|
||
`dc.description` mencionando álbum/página (ex.: "Álbum 0259"), igual ao
|
||
caso do PDF de 71,9 MB do achado 2.2 — mesmo fenômeno, mas dentro do
|
||
próprio DSpace, não só no objdigital.
|
||
|
||
**Como enumerar as imagens reais de um item**, em ordem de confiabilidade:
|
||
1. Contar `.file-wrapper` na página normal do item (não `?show=full`) — bate
|
||
com o número real de bitstreams.
|
||
2. Tentar sequências `/bitstream/{PREFIX}/{h}/{seq}/qualquer-nome.jpg` pra
|
||
`seq` de 1 até N — funciona quando as sequências são contíguas a partir
|
||
de 1 (maioria dos casos).
|
||
3. Quando (2) falha (sequências não contíguas): pegar o nome real do
|
||
arquivo a partir do `<img src>` de cada `.file-wrapper` (é a miniatura,
|
||
nome com `.jpg` duplicado no final — ex. `nome.jpg.jpg`), tirar o último
|
||
`.jpg`, e buscar `/bitstream/handle/{PREFIX}/{h}/{nome-real}` (rota por
|
||
nome exato, não por sequência).
|
||
|
||
`preservation_url` = a maior imagem encontrada (compatibilidade com o
|
||
pipeline); `all_preservation_urls`/`all_preservation_sizes` guardam todas,
|
||
ordenadas da maior pra menor.
|
||
|
||
**Exceção conhecida sem conserto:** handle `20.500.12156.1/7523` — `HTTP
|
||
500` do próprio servidor da BN ao buscar os bitstreams (não é problema de
|
||
nome/padrão). Provável arquivo corrompido do lado deles.
|
||
|
||
### 2.8b Achado 2.8 falha ~62% das vezes em alguns lotes — bitstream de LICENÇA, não thumbnail
|
||
`seq_master+1` às vezes é o bitstream de **LICENÇA** do DSpace (texto puro,
|
||
"LICENÇA DE VEICULAÇÃO E DISTRIBUIÇÃO..."), não a miniatura — visto em
|
||
Marinha e IMS, **2.655 de 4.278 thumbnails** (62%!) baixados errado num
|
||
lote, **146 já tinham subido pro bucket** antes de descobrir (limpo).
|
||
O filtro de tamanho do v1 (`> 2MB → rejeita`) não pega isso: o texto da
|
||
licença é pequeno o bastante (781 bytes) pra passar. **Fix:** validar
|
||
magic bytes (JPEG `FFD8`/PNG) antes de aceitar, tentar seq+2/+3 se falhar,
|
||
e cair pro método do achado 2.7 (`<img src>` da página) como último
|
||
recurso — `baixador-thumb.js` v2. Também blindado no `subidor.py`: rejeita
|
||
qualquer upload cujo conteúdo não comece com magic bytes de imagem,
|
||
independente do nome do arquivo (defesa em camadas).
|
||
|
||
**Lição:** tamanho pequeno não é prova de "é a miniatura" — só magic bytes
|
||
provam que é imagem de verdade.
|
||
|
||
### 2.8 Miniatura gerada pelo DSpace: sequência N+1 (quando contígua)
|
||
Pra item com bitstream original na sequência N, a miniatura que o DSpace
|
||
gera automaticamente costuma ficar na sequência N+1 — confirmado no handle
|
||
`6066`: seq 1 = master (7,7 MB), seq 2 = thumb (56 KB). Mesma rota
|
||
filename-agnostic do achado 2.4 original (o nome na URL não importa, só a
|
||
sequência). Quando as sequências não são contíguas (itens do achado 2.7 via
|
||
método 3), a miniatura de cada imagem é o próprio `<img src>` do
|
||
`.file-wrapper` correspondente — não precisa de request extra.
|
||
|
||
### 2.9 objdigital às vezes tem PDF (álbum), não só JPG — extração pegava o identificador errado
|
||
Alguns itens têm mais de um `DC.identifier` apontando pro objdigital: um
|
||
`.htm` (página de landing) e um `.pdf` (o álbum de verdade, múltiplas
|
||
páginas — mesmo fenômeno do PDF de 71,9 MB do item 14582, achado 2.2). A
|
||
extração original pegava o **primeiro** identificador que batesse com
|
||
"objdigital", que pra 44 itens (a maioria uma sequência do Museu
|
||
Aeroespacial, `14526-14570`, mais o `584`) era o `.htm`, não o `.pdf` —
|
||
perdendo o conteúdo real. De 235 itens com PDF disponível, 191 já estavam
|
||
certos por acaso (o PDF vinha primeiro na lista); só 44 precisaram de
|
||
correção manual (feita em `catalogo.jsonl` e no IndexedDB, antes do
|
||
`baixador.py --somente-legado` alcançar esses handles — nada foi
|
||
contaminado no bucket). **Vale re-checar outros itens com múltiplos
|
||
`DC.identifier` de objdigital por precaução, não só os que têm `.pdf`.**
|
||
|
||
Recheque feito (2026-09-10): mapeamos todos os padrões de extensão em
|
||
2.231 itens com 2+ identifiers objdigital. Achados adicionais:
|
||
- **5 itens** (`1081, 1082, 1084, 4077, 4084`) têm **só HTML**, sem
|
||
`.jpg`/`.pdf` nenhum — são páginas de um visualizador de zoom profundo
|
||
(OpenSeadragon/DZI, pirâmide de blocos, não um arquivo único). **3 já
|
||
tinham sido baixados e subidos como se fossem imagem** (arquivos de
|
||
~2,4 KB, só a página HTML do visualizador) — limpo do bucket, `legacy_url`
|
||
zerado pros 5 (não vale a complexidade de espelhar a pirâmide de tiles
|
||
pra tão poucos itens).
|
||
- **11 itens** têm `.sid` (MrSID, formato comprimido de imagem grande)
|
||
além do `.jpg` — não capturado, ficou como gap conhecido (baixo volume,
|
||
não priorizado).
|
||
|
||
### 2.10 O crawl da Fase 1 não é 100% completo — achado via referência cruzada com o WordPress
|
||
Cruzando os handles citados nos 636 posts do WordPress contra o catálogo,
|
||
2 itens reais (`1799` "Princesa Isabel menina", `4798` "Vista panorâmica de
|
||
Canudos...") existem no site mas não foram enumerados pela Fase 1 — ambos
|
||
sem `citation_pdf_url`, formato de metadado antigo (um é de 2015-04-16,
|
||
uma das primeiras entradas do sistema). Adicionados manualmente ao
|
||
catálogo depois de descobertos.
|
||
|
||
**Isso só foi achado por acaso** (porque um post do blog citava esses
|
||
handles especificamente) — não existe verificação exaustiva de que a
|
||
enumeração por `browse?type=title` capturou 100% dos itens de cada
|
||
comunidade. Pode haver mais itens faltando que nenhum post referencia.
|
||
Não investigado a fundo: seria preciso comparar a contagem de cada
|
||
comunidade contra alguma fonte independente (a BN não expõe OAI-PMH nem
|
||
count via API, até onde sabemos).
|
||
|
||
### 2.11 O objdigital só responde em HTTPS — não era bloqueio
|
||
`legacy_url` na fonte vem como `http://objdigital.bn.br/...`. Conexão HTTP
|
||
simples (porta 80) é resetada (`Recv failure: Connection reset by peer`),
|
||
local e da Finlândia. HTTPS funciona liso com curl puro, local (não
|
||
testado da Finlândia — motivo original de "não alcançável" pode ser outro,
|
||
não investigado). Fix: forçar `https://` no `legacy_url` antes de baixar
|
||
(já aplicado em `baixador.py`).
|
||
|
||
### 2.12 Caractere `#` no nome do arquivo corrompe URL no IndexedDB
|
||
78 itens (mesmo álbum "Album 0035/0259/0260") têm `#` literal no nome real
|
||
do arquivo (ex.: `Alb 0260 199 CT #.jpg`). Algum processo que passou esse
|
||
nome por `new URL(...).pathname` sofreu o efeito clássico: `#` não
|
||
percentado é tratado como início de **fragmento da URL**, e tudo depois
|
||
dele é descartado — a URL salva no IndexedDB virou `.../Alb%20...%20CT%20`
|
||
(sem sequência, sem `#`, sem `.jpg`), 404 garantido. O `catalogo.jsonl`
|
||
local nunca foi tocado por esse bug (tem a URL certa, com `%23`) — fix é
|
||
só reescrever o campo no IndexedDB a partir do catálogo
|
||
(`pipeline/reparo-hash-url.js`).
|
||
|
||
**Lição:** nunca usar `new URL()`/`.pathname` pra manipular nomes de
|
||
arquivo vindos de fonte externa sem antes confirmar que não têm `#`, `?`
|
||
ou outros caracteres especiais de URL não codificados.
|
||
|
||
### 2.13 O mesmo `#` quebra de novo — desta vez no redirect do próprio DSpace
|
||
|
||
Mesmo com a URL do achado 2.12 corrigida no IndexedDB (`%23` correto, forma
|
||
antiga `/bitstream/PREFIX/ID/SEQ/arquivo`), os 78 itens continuavam dando
|
||
404. O DSpace responde a essa forma antiga com um redirect para a forma
|
||
canônica nova (`/bitstream/handle/PREFIX/ID/arquivo`, sem número de
|
||
sequência) — e o `Location` do redirect tem o `#` sem escapar de novo,
|
||
então o `fetch()` do navegador trunca no fragmento ao seguir o redirect
|
||
(`finalUrl` chega faltando `#.jpg`, 404). Fix: pedir direto a forma
|
||
canônica (`/bitstream/handle/...`), pulando o redirect — testado, `200`,
|
||
JPEG válido. `preservation_url` desses 78 itens reescrito no IndexedDB
|
||
para a forma canônica.
|
||
|
||
**Lição:** com `#` no nome do arquivo, não confiar em nenhum redirect do
|
||
servidor — ele pode ter o mesmo bug do lado de lá. Preferir sempre a URL
|
||
final/canônica quando ela for conhecida.
|
||
|
||
### 2.14 Dá pra ler o progresso do BAIXA/BAIXA_THUMB sem o Chrome conectado
|
||
|
||
O progresso das trilhas via navegador (`localStorage.bras_baixados`,
|
||
`bras_thumbs_v2`) sobrevive num arquivo leveldb comum no disco —
|
||
`~/Library/Application Support/Google/Chrome/Default/Local Storage/leveldb`
|
||
— mesmo com a extensão Claude-in-Chrome desconectada (ex.: conflito de conta
|
||
OAuth, sessão anterior perdida). Basta copiar o diretório (evita brigar com
|
||
o `LOCK` que o Chrome mantém aberto) e ler com uma lib leveldb qualquer
|
||
(`classic-level` via npm, sem dependência nativa externa). O valor vem com
|
||
1 byte de prefixo indicando encoding (`0x00`=UTF-16LE, `0x01`=UTF-8/Latin1)
|
||
antes do JSON de verdade. Script pronto: `pipeline/tools/ler-localstorage.js`.
|
||
|
||
**Lição:** perder a conexão com a extensão do navegador não significa perder
|
||
visibilidade do progresso — boa parte do estado do app mora em arquivos
|
||
comuns no disco do usuário, não só "dentro do navegador".
|
||
|
||
---
|
||
|
||
## 3. O acervo
|
||
|
||
DSpace 4.2, handles `20.500.12156.1/*`. **13.058 itens reais** (13.059
|
||
descobertos no crawl, menos 1 falso-positivo — `.../1` é a página raiz da
|
||
comunidade, não um item). Contagem original por comunidade abaixo era de
|
||
13.036; a diferença é ruído de borda (comunidades ganham/perdem item ao
|
||
longo do tempo), não erro de coleta.
|
||
|
||
| Instituição | Itens | | Instituição | Itens |
|
||
|---|--:|---|---|--:|
|
||
| Instituto Moreira Salles | 5.133 | | Fiocruz | 548 |
|
||
| Biblioteca Nacional | 2.726 | | Marinha (DPHDM) | 456 |
|
||
| Museu Aeroespacial | 1.143 | | Arquivo Nacional | 383 |
|
||
| Museu da República | 906 | | Arq. Geral da Cidade do RJ | 248 |
|
||
| Museu Histórico Nacional | 649 | | Leibniz-Institut, Leipzig | 216 |
|
||
| IHGB | 206 | | Fund. Joaquim Nabuco | 190 |
|
||
| Museu Goeldi | 95 | | FGV CPDOC | 79 |
|
||
| IBGE | 58 | | | |
|
||
|
||
**~139,5 GB projetados** (recalculado em 2026-09-10 com médias reais de
|
||
357-474 arquivos já no bucket por categoria, não mais os 6 originais):
|
||
preservação+extras ~136,9 GB (13.152 arquivos, 10,7 MB médio), thumbnails
|
||
~0,9 GB, legado ~1,5 GB (taxa de sucesso ~75%, muito 404 genuíno),
|
||
metadados+WordPress+catálogo <0,2 GB combinados.
|
||
|
||
---
|
||
|
||
## 4. Runbook
|
||
|
||
### Fase 1 — metadados (navegador) ✅ COMPLETA
|
||
Cole `pipeline/coletor-resume.js` (pendentes + erros juntos, numa passada só)
|
||
numa aba em `https://brasilianafotografica.bn.gov.br/brasiliana/`. Acompanhar
|
||
com `await BRAS.status()`. Deixe a aba **ativa na janela dela**: o Chromium
|
||
estrangula `setTimeout` em abas de fundo até 1×/min, e o loop passa a
|
||
rastejar sem erro nenhum. Ao terminar: `await BRAS.exportar()`.
|
||
|
||
### Fases 2 e 3 — trilha única via navegador (não tem mais trilha A/servidor)
|
||
Ver achado 2.6. Na mesma aba (mesmo IndexedDB `bras`), cole em sequência:
|
||
```js
|
||
// pipeline/baixador-navegador.js -- imagem principal, todos os itens
|
||
BAIXA.quantos(); BAIXA.iniciar();
|
||
// pipeline/baixador-thumb.js -- miniaturas
|
||
BAIXA_THUMB.quantos(); BAIXA_THUMB.iniciar();
|
||
// pipeline/baixador-extras.js -- 2a+ imagem dos itens com multiplos bitstreams
|
||
// (rodar reparo-multibitstream.js antes, se ainda nao rodou)
|
||
BAIXA_EXTRA.quantos(); BAIXA_EXTRA.iniciar();
|
||
```
|
||
Em paralelo, em outro terminal:
|
||
```bash
|
||
cd pipeline
|
||
set -a; . .s3env; set +a
|
||
python3 subidor.py --vigiar --catalogo catalogo.jsonl
|
||
```
|
||
Downloads automáticos do Chrome exigem permissão em
|
||
`chrome://settings/content/automaticDownloads` (adicionar
|
||
`https://brasilianafotografica.bn.gov.br`) — sem isso o download "funciona"
|
||
no JS (sem erro) mas nenhum arquivo chega no disco. Vale pro domínio
|
||
inteiro, uma vez só.
|
||
|
||
### Fase 4 — cópias legadas (máquina local)
|
||
```bash
|
||
cd pipeline
|
||
set -a; . .s3env; set +a
|
||
python3 baixador.py --catalogo catalogo.jsonl --somente-legado
|
||
```
|
||
Via curl direto, sem navegador (ver achado 2.11). ~2.707 itens têm
|
||
`legacy_url`, ~328 KB em média.
|
||
|
||
---
|
||
|
||
## 5. Arquivos e credenciais
|
||
|
||
Layout do repo (detalhe em `README.md` → "Estrutura do repositório"):
|
||
scripts + estado ao vivo em `pipeline/`, visualizações em `web/`, item de
|
||
referência em `examples/`, código morto em `archive/`.
|
||
|
||
| Arquivo | O quê |
|
||
|---|---|
|
||
| `tasks/PLANO.md` | Este documento |
|
||
| `README.md` | Referência técnica completa (raiz do projeto) |
|
||
| `pipeline/coletor.js` | Fase 1 — console do navegador, IndexedDB, autoinício |
|
||
| `pipeline/baixador.py` | Fases 2 e 4 — curl → S3, um arquivo por vez |
|
||
| `pipeline/baixador-navegador.js` | Fase 3 — navegador → pasta Downloads |
|
||
| `pipeline/subidor.py` | Fase 3 — Downloads → S3, apaga na hora |
|
||
| `archive/censo.py` | Versão Playwright — **não funciona**, mantida pelo parsing |
|
||
| `pipeline/.s3env.exemplo` | Modelo; chaves reais em `/Users/polux/Projetos/tocador/.env` |
|
||
|
||
**S3:** `hel1.your-objectstorage.com`, bucket `brasiliana` (Hetzner).
|
||
Credenciais em `/Users/polux/Projetos/tocador/.env`
|
||
(`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`). Cópia local em
|
||
`pipeline/.s3env`. Na Finlândia: `/root/.s3env`.
|
||
|
||
**Servidor:** `ssh finland` → 89.167.95.136 (Hetzner Helsinki, root, 31 GB livres).
|
||
|
||
---
|
||
|
||
## 6. Estrutura no bucket
|
||
|
||
```
|
||
s3://brasiliana/
|
||
MANIFEST.md o que é, como foi coletado, quando
|
||
catalogo.jsonl uma linha por item
|
||
itens/20.500.12156.1_6066/
|
||
metadata.json Dublin Core + URL de origem + data UTC
|
||
preservacao/imagem.jpg 5533×4065, 7,4 MB
|
||
legado/icon843660.jpg 147 KB, referência de origem
|
||
manifest-sha256.txt checksum de cada arquivo
|
||
```
|
||
|
||
Não negociável: **SHA-256 de tudo** e **URL de origem + data/hora de captura**.
|
||
Sem os dois é pasta de imagens, não arquivo.
|
||
|
||
---
|
||
|
||
## 7. Pendências
|
||
|
||
1. ~~Terminar a Fase 1 e exportar o catálogo.~~ ✅ 13.060 itens, 2026-09-13.
|
||
2. ~~Medir a fração da trilha B.~~ Obsoleto: desde 2026-09-10 tudo roda por uma
|
||
trilha única no navegador (ver 2.6), e a coleta acabou.
|
||
3. ~~Confirmar a projeção de ~116 GB.~~ ✅ Medido: 127,4 GB de preservação e
|
||
139,2 GB no bucket, somando tudo.
|
||
4. ~~Decidir sobre os PDFs de álbum do objdigital.~~ ✅ Guardados como cópia
|
||
legada: são 213 PDF entre os 2.137 arquivos de `legado/`.
|
||
5. ~~Gerar `MANIFEST.md` e `catalogo.jsonl` no bucket.~~ ✅ `catalogo.jsonl`
|
||
no bucket é idêntico ao local (ETag multipart confere); `MANIFEST.md`
|
||
finalizado e reenviado em 2026-09-30.
|
||
6. Os 69 itens sem preservação dependem da origem voltar a servir o
|
||
bitstream (`errors.md`). Não há ação possível do nosso lado.
|
||
7. O que falta da descrição e do mural está em §9 (0.2, 7.3, 7.4).
|
||
|
||
## 8. Direitos
|
||
|
||
Majoritariamente domínio público por antiguidade, mas as 15 instituições têm
|
||
políticas distintas. `dc.rights` e a instituição de origem são preservados
|
||
**por item**: a decisão de redistribuir é item a item, não do acervo em bloco.
|
||
Arquivar para si é uma coisa; republicar é outra.
|
||
|
||
## 9. Descrição arquivística (NOBRADE)
|
||
|
||
Resumo da norma e decisões de aplicação em [`CONARQ.md`](../CONARQ.md).
|
||
Implementação no branch `feat/nobrade`: `cd pipeline && python3 -m nobrade && python3 -m nobrade.mural`.
|
||
|
||
| # | Tarefa | Entrega | Depende de | Estado |
|
||
|---|---|---|---|---|
|
||
| **0 — Decisões** |||||
|
||
| 0.1 | Definir nome da entidade custodiadora e código provisório (`BR RJXYZ`) | `pipeline/nobrade/config.py` | — | ✅ provisório `BR RJXYZ` |
|
||
| 0.2 | Pedir código de entidade ao CONARQ | `descricao/pedido-codigo-conarq.md` | 0.1 | 📝 rascunho pronto (formulário CODEARQ, Res. CONARQ 28/2009); envio é do usuário |
|
||
| 0.3 | Fixar a convenção do código de referência (`BR RJXYZ.BF.IMS.GF.12345.01`) | `CONARQ.md` §5.2 | 0.1 | ✅ |
|
||
| **1 — Normalizadores (cada um gera uma tabela de revisão)** |||||
|
||
| 1.1 | Datas: mais de 20 formatos de `dc.date` → forma NOBRADE (`[1860?]`, `[18--]`) + ISO 8601 + original | `descricao/revisao/datas.tsv` | — | ✅ |
|
||
| 1.2 | Atribuir data aproximada aos `s.d.` a partir do fotógrafo | coluna em `datas.tsv` | 1.1, 1.4 | ✅ |
|
||
| 1.3 | Séries: 2.657 combinações de `dc.source` → séries canônicas por instituição | `descricao/revisao/series.tsv` | — | ✅ |
|
||
| 1.4 | Autoridades: fotógrafos (`dc.contributor`) e colecionadores, com variantes deduplicadas | `descricao/autoridades.jsonl` | — | ✅ |
|
||
| 1.5 | Suporte/espécie: `dc.type` → gênero + espécie + suporte | `descricao/revisao/tipos.tsv` | — | ✅ |
|
||
| 1.6 | Direitos: `dc.rights` → ~4 categorias, mantendo o original | `descricao/revisao/direitos.tsv` | — | ✅ |
|
||
| 1.7 | Data tópica: `dc.coverage` → cidade (UF) | campo 1.3 | — | ✅ |
|
||
| 1.8 | Assuntos: `dc.subject` separado em pt/en | campo 8.1 | — | ✅ |
|
||
| **2 — Montagem da hierarquia** |||||
|
||
| 2.1 | `nobrade`: níveis 0→5 com `id`, `parent_id`, `nivel`, `codigo` | `descricao/unidades.jsonl` | 0.3, 1.3 | ✅ |
|
||
| 2.2 | Preencher os elementos por nível a partir dos normalizadores | campos `"1.3"`, `"2.1"`… | 1.x, 2.1 | ✅ |
|
||
| 2.3 | Nível 5 para os handles com várias imagens | registros filhos | 2.1 | ✅ toda imagem é nível 5 |
|
||
| 2.4 | Somar dimensão e suporte nos níveis 1–3 | campo 1.5 agregado | 2.2 | ✅ |
|
||
| **3 — Textos dos níveis altos** |||||
|
||
| 3.1 | Nível 1: história arquivística, procedência, acesso, arranjo | `descricao/textos/nivel1.md` | — | ✅ |
|
||
| 3.2 | Nível 2: breve histórico das 15 instituições | `descricao/textos/secoes/` | — | ✅ fatos conferidos na web, fontes em cada arquivo (2026-09-30) |
|
||
| 3.3 | Nível 3: âmbito e conteúdo das séries principais | `descricao/textos/series/` | 1.3 | ✅ resumo automático |
|
||
| 3.4 | Biografias de fotógrafos a partir dos posts do WordPress | campo 2.2 das autoridades | 1.4 | ✅ fontes nas autoridades |
|
||
| **4 — Relações e fontes** |||||
|
||
| 4.1 | 5.1 Originais: instituição + handle + Sophia + objdigital | campo automático | 2.1 | ✅ |
|
||
| 4.2 | 5.2 Cópias: preservação, legado, miniaturas no S3 | campo automático | 2.1 | ✅ |
|
||
| 4.3 | 5.4 Publicações: posts do WordPress → handles citados | campo 5.4 | — | ✅ |
|
||
| **5 — Validação** |||||
|
||
| 5.1 | Validador dos 7 obrigatórios por nível | `descricao/pendencias.md` | 2.x | ✅ |
|
||
| 5.2 | Rodar, corrigir e repetir até zerar as pendências | relatório limpo | 5.1 | ✅ 0 pendências |
|
||
| **6 — Exportação e publicação** |||||
|
||
| 6.1 | Exportar EAD 3 | `descricao/ead/brasiliana.xml` | 5.2 | ✅ valida |
|
||
| 6.2 | Exportar EAC-CPF | `descricao/eac/*.xml` | 1.4 | ✅ valida |
|
||
| 6.3 | Validar contra os XSD | xmllint limpo | 6.1, 6.2 | ✅ |
|
||
| 6.4 | Subir `descricao/` para `s3://brasiliana/descricao/` e atualizar o MANIFEST | objetos no bucket | 6.3 | ✅ 487 objetos, 172 MB, com `manifest-sha256.txt`; MANIFEST final (2026-09-30) |
|
||
| 6.5 | (opcional) CSV de importação do AtoM | `descricao/atom.csv` | 5.2 | ✅ |
|
||
| **7 — Mural** |||||
|
||
| 7.1 | Cartão vira visor: painel à esquerda (desktop) ou folha abaixo da imagem (celular); palco com zoom real (roda, pinça, duplo clique, arrastar, + − encaixar, F = só a imagem); barra "← mural \| filtros (n)" no topo do painel para voltar ao Atlas 3D e abrir os filtros por cima do visor | `web/wall.html` | 2.2 | ✅ |
|
||
| 7.2 | Ficha arquivística recolhível com os obrigatórios NOBRADE: código (clique copia), nível, arranjo clicável (Brasiliana › instituição › série), data na forma da norma + "na origem", selo "atribuída" nas datas atribuídas pelo arquivista, produtor na forma autorizada ISAAR, dimensão e suporte, original (5.1), reprodução (4.2), citar (copia a referência com o código) | `web/wall.html`, `nobrade/mural.py` | 2.2 | ✅ |
|
||
| 7.2b | Filtros reagrupados pela NOBRADE: Arranjo (instituição → série em cascata), Data, Pontos de acesso (autor pela autoridade ISAAR, lugar, assunto, pessoa, coleção citada), Suporte e uso (espécie e suporte da 1.5, e condição de reprodução da 4.2, filtro novo); link direto `#BR RJXYZ…` abre a peça pelo código de referência | `web/wall.html` | 7.2 | ✅ |
|
||
| 7.2c | Correções de dados que saíram do visor: ano implausível na origem (ex. `20-12-1395`) vira data ilegível, com nota; datas atribuídas por série ou instituição usam o miolo p10–p90 (`[1933-1943?]` em vez de `[1800-1999?]`); o histograma do mural só usa datas com até 30 anos de amplitude | `nobrade/datas.py`, `montar.py`, `mural.py` | 1.1 | ✅ |
|
||
| 7.3 | Publicar em `xyz/brasiliana` | commit | 7.x | ✅ publicado em 30/09 (`index.html` + `atlas-map.json`), no ar em https://xn--2dk.xyz/brasiliana/ |
|
||
| 7.4 | Derivado `derivados/grande/` (WebP de 2.560 px) para zoom nítido. O visor já carrega sob demanda se o mapa tiver `grande: true`; falta gerar a partir das imagens de preservação no bucket | `derivados/grande/` | 7.1 | ⏳ |
|