O objdigital fechou a porta 80 e passou a servir em https://objdigital.bn.br/objdigital2/acervo_digital/. Três cópias legadas do bucket baixadas pelo endereço novo voltaram com sha256 idêntico. Dos 565 legados marcados como 404 permanente, 348 existem no endereço novo (330 JPEG, 18 PDF), 41 são páginas de visualizador Deep Zoom e 176 seguem 404. Lista em pipeline/legado-caminho-novo.tsv. MANIFEST corrigido: 2.112 cópias legadas são imagem; as outras 25 no bucket são páginas HTML do visualizador.
48 KiB
TODO — Brasiliana → S3
Handoff em 2026-09-10 ~15h UTC: sessão
fix-image-pipeline-extrasperdeu conexão com a extensão Claude-in-Chrome e encerrou a pedido do usuário. Trabalho passado pra sessãochrome-extension-connection(tem o navegador conectado). Ver mensagem de handoff enviada via SendMessage pro contexto completo do estado no momento da troca — resumo abaixo já reflete isso.Atualização ~17h UTC (mesma sessão): aba antiga do coletor não é acessível por esta sessão (grupo de abas é por sessão) mas continuou rodando sozinha o tempo todo — confirmado por progresso do
bras_baixadosno localStorage (compartilhado por origem). Por isso o download principal (BAIXA) não foi reiniciado nesta aba (evitar duplicar ~8 mil downloads pesados em paralelo); só os 78 itens do achado 2.11 foram baixados cirurgicamente aqui.BAIXA_THUMBv2 foi iniciado numa aba nova (chavebras_thumbs_v2, começa do zero, ~13.059 itens). Durante a sessão houve uma queda de rede/extensão de alguns minutos (mesmo tipo de falha que derrubou a sessão anterior) — gerou ~1.280 erros transitórios no thumb v2 que precisam de uma segunda passada (BAIXA_THUMB.retomar()) depois que a primeira terminar.
Ver
tasks/PLANO.mdpro histórico/achados/runbook. Itens concluídos saem daqui e vão pratasks/done/(ex.:tasks/done/TODO-2026-09-10.md). Scripts e estado empipeline/(reorganização de 2026-09-10).
Em andamento (não mexer, só monitorar)
-
Upload pro S3 — CONCLUÍDO. A fila de
~/Downloadsestá em 0; tudo que foi baixado está no bucket. Total no ledger: 41.444 objetos. Opipeline/vigia-30min.shsegue de pé: a cada 30 min sobe o que aparecer e apaga do disco só depois do HEAD confirmar no bucket. Não editarvigia-30min.shnemrodar-paralelo.shenquanto rodam (o bash lê o script aos poucos) e não relançar osubidor.pyantigo (achado 2.22). Threads: 6, não 16 — ver achado 2.24. -
Download principal (1 imagem de preservação por item) — navegador. 2026-09-11 20:45 UTC: 12.986/13.059 (99,44%), faltam 73 — medido pela fonte autoritativa (bucket ∪ fila local), não pelo
bras_baixados. Parado há ~9h (último arquivo em~/Downloadsàs 13:19 local = 11:19 UTC). Lista exata dos 73 empipeline/faltantes-preservacao.jsonl({handle, url}). Scriptpipeline/baixar-faltantes-73.jscolado e rodado pelo usuário ~22:52 local (20:52 UTC) — lista embutida, chave própriabras_faltantes_73, imune ao achado 2.16. Resultado parcial: 2/73 (10993,10995, 31 MB). Os outros 71 estão falhando — ver achado 2.17. Recontagem de 12/09: faltam 211, não 73 — ver achado 2.23.
Achado 2.17 — os 71 restantes falham, e não é malformação de URL (2026-09-11 21:25 UTC)
bras_faltantes_73 = 2 e só 2 arquivos de preservação novos apareceram em
~/Downloads (22:52 local). O disco e a chave concordam — aqui o achado 2.16
não se aplica, o número é real.
Os 71 que falham têm URL estruturalmente idêntica às 2 que passaram
(mesmo host, mesmo /brasiliana/bitstream/PREFIX/ID/SEQ/arquivo, 21 dos 71 com
%20 no nome, igual às que funcionaram). Diferenças observadas, nenhuma
conclusiva: as 2 que passaram são SEQ=1; entre as 71 há SEQ 1 (58), 4 (11),
3 (1) e 5 (1).
Hipótese principal: as 2 que passaram estavam em cache de borda do Cloudflare
— exatamente o caso do item 6066 descrito no cabeçalho do
baixador-navegador.js (cf-cache-status: HIT), e não a regra geral. Se for
isso, o fetch de aba não basta para estes 71 e o problema é de origem, não de
script.
Próximo passo (precisa do console da aba): rodar FALTA.status() e
FALTA.erros() — o script guarda {handle, url, erro} de cada falha, e o
código HTTP decide o caminho:
- 404 → bitstream não existe nesse
SEQ; repararpreservation_urlno catálogo (mesma família dos achados 2.9/2.11/2.13) e regerar o script. - 403 → bloqueio de origem/Cloudflare; nem a aba resolve, precisa de outra saída.
- 500 → transitório;
FALTA.retomar()mais tarde deve pegar.
Enquanto isso o script pode ainda estar rodando: cada erro dorme 60 s de backoff, então 71 falhas levam ~71 min a partir das 22:52 local (fim previsto ~00:05).
Achado 2.18 — é recusa da origem, não URL errada; e a v1 do script ajudou a causar (2026-09-12)
FALTA.status() do usuário: atual: "43/73", erros: 101, feito: 0,
fase: "baixando".
Três leituras, em ordem de importância:
feito: 0no item 43 —10993e10995são os itens 1 e 2 da lista e baixaram com sucesso às 22:52; nesta passada falharam. Mesma URL, uma hora depois. Logo não é URL errada, é a origem recusando.erros: 101comatual: 43/73— mais erros que itens tentados só é possível com dois ou mais loops concorrentes somando no mesmoS. Cadainiciar()/retomar()sobre um script já rodando cria outro loop. Isso quebrou a pausa de 3 s combinada com a BN e provavelmente disparou rate-limit.total: 73(e não 71) — oFEITOSfoi lido vazio na largada dessa passada.
Hipóteses mortas (não perder tempo com elas de novo):
- Sequência errada no
preservation_url: os 2 que funcionaram têm exatamente a mesma forma dos 13 "divergentes" (catálogoseq=1, thumb emseq=3), e 58 dos 71 têmseqcoerente com o thumb e falham igual. - Bloqueio geral do Cloudflare: 71/71 desses itens têm thumb baixado com sucesso — o item responde; só o bitstream de preservação não.
pipeline/baixar-faltantes-v2.js corrige os defeitos da v1 (que eram meus):
guarda contra iniciar() duplo, aborta depois de 5 erros seguidos em vez de
moer os 71 com 60 s cada, pausa de 5 s, backoff de 30 s, e registra o código HTTP
separado (FALTA.resumo() devolve a tabela de códigos). Recarregar a aba antes
de colar — parar() não alcança closures de colagens anteriores.
- Thumbnails — ✅ concluído 100% (13.059/13.059).
retomar()já foi rodado uma vez (08h local); não re-rodar. - Fase 4 (legado objdigital) — ✅ concluído (2ª passada terminou): 2.137 ok / 565 erro (2.702/2.707 processados; os 565 são 404 permanentes confirmados via curl direto, atrito real da fonte legada, não bug). Confirmado em 2026-09-11 ~20h UTC:
select erro,count(*)devolve sóHTTP 404(565) — nenhumHTTP 0restante, então a 3ª passada não tem o que reprocessar; não reiniciar de novo. substituído pelosubidor.pysubidor-paralelo.pyem 2026-09-12 (achado 2.22); o texto a seguir é histórico. (pipeline/,--vigiar, PID 97295) — vivo há 1d8h, vigiando~/Downloads. 2026-09-11 ~20h UTC: fila local de 19.897 arquivosBRAS__/ ~77 GB (12.511 thumb, 1.660__imagem, 5.726 com nome original). Bucket: 33.388 objetos / 60,3 GB, 8.080 itens commetadata.json(61,9% dos 13.059). 2026-09-12 09:45 UTC: 16.207 enviados, fila de 18.286. Taxa nas horas acordadas ≈ 650–740 arq/h ≈ 2,0–2,4 GB/h.
⚠️ O relógio é de horas ACORDADAS, não de horas corridas. Os envios pararam às 22:30 UTC de 11/set e só voltaram às 09:00 UTC de 12/set — 10,5 h de silêncio, que é a máquina dormindo (00:30–11:00 local), não falha do subidor (o processo seguiu vivo e voltou sozinho). Por isso:
- fila de 18.286 ÷ ~700 arq/h = ~26 h de máquina acordada
- em dias normais (~14 h acordado), isso vira ~2 dias de calendário
- com
caffeinate -issegurando a máquina acordada, ~26 h corridas
Vale decidir isso conscientemente: é a diferença entre terminar em ~1 dia ou ~2.
Achado 2.15 — aba do coletor inalcançável, e storage da origem aparece vazio (2026-09-11 ~20h UTC)
Tentativa de retomar a trilha 1 sozinho falhou, mas rendeu dois fatos novos:
- Sobraram instâncias headless do Chrome de uma sessão anterior, uma delas
lançada com o perfil padrão (
--user-data-dirdefault). Mortas (PIDs 89329, 89327, 14818); o Chrome real do usuário (PID 57263, aberto desde 9/set) foi preservado. Nunca subir headless sem--user-data-dirpróprio — disputa o perfil onde mora todo o estado do coletor. - Numa aba nova em
https://brasilianafotografica.bn.gov.br(mesmo perfil, mesma origem),localStoragedevolve 0 chaves eindexedDB.databases()devolve [] — enquantoler-localstorage.js, lendo o leveldb do disco do mesmo perfil/origem, devolvebras_baixados: 12.974. Ou seja: o contexto vivo e o disco discordam. Não dá praBAIXA.retomar()numa aba nova: sem o IndexedDBbras,alvos()devolveria[].
Não colar baixador-navegador.js numa aba nesse estado: se o storage
estiver mesmo zerado, FEITOS começa vazio e a fila vira os ~13 mil itens
inteiros de novo (centenas de GB, e carga indevida na fonte). O caminho seguro
é o usuário voltar na aba original do coletor (a que já tem BAIXA no
window) e rodar BAIXA.status() / BAIXA.retomar() lá.
Achado 2.16 — bras_baixados anda PRA TRÁS; não usar como medida (2026-09-11 20:45 UTC)
O contador caiu de 12.974 → 12.111 entre 20:14 e 20:43 UTC (três leituras seguidas devolvem 12.111; o leveldb foi escrito pelo Chrome às 22:24 local, 19 min antes da leitura — é gravação real, não cache velho).
Causa provável: marcar() reescreve o array inteiro a partir do FEITOS
carregado quando o script foi colado. Qualquer aba com snapshot velho que ainda
marque um item sobrescreve a lista boa por uma mais curta. Com duas abas vivas
(v1 e v2 conviveram), a lista é sempre a do último escritor, não a união.
Consequência prática: bras_baixados não mede progresso — subestima. A
medida autoritativa é bucket ∪ fila local em ~/Downloads:
# handles com preservação no bucket (do aws s3 ls --recursive)
awk '... itens/<handle>/<arquivo!=metadata.json, sem "thumb">' → 8.080
# handles de preservação ainda na fila local
ls ~/Downloads | grep '^BRAS__' | grep -v thumb | sed -E 's/^BRAS__(.+)__.*/\1/' → 7.271
# união → 12.986 de 13.059 (faltam 73, listados em pipeline/faltantes-preservacao.jsonl)
Isso também refaz a conta do achado 2.15: o risco de recolar o script não é "85 itens", é re-baixar ~950+ que o contador esqueceu (ou tudo, se o storage estiver mesmo zerado).
Concluído agora
- Thumbnails contaminados com bitstream de LICENÇA (achado 2.8b): 2.653 arquivos locais apagados de
~/Downloads, 146 já subidos removidos do bucket,subidor.pyblindado com validação de magic bytes (rejeita e apaga automaticamente qualquer coisa que não comece com JPEG/PNG, mesmo que o nome diga o contrário).baixador-thumb.jsv2 escrito com validação + fallback — falta só reconectar o navegador pra trocar o script rodando. - WordPress → .md: 636/637 posts colhidos (1 erro), exportados e convertidos —
wordpress/{id}-{slug}.mdno repo (front-matter YAML: id/url/título/autor/data/categorias/handles referenciados) +wordpress-posts.jsonle a pastawordpress/subindo pro bucket agora. - Bug de corrida em arquivo temporário:
baixador.pyesubidor.pymoram na mesma pasta e usavam o mesmo nome fixo (.tmp/metadata.json) — rodando ao mesmo tempo, um apagava o arquivo que o outro tinha acabado de criar. Derrubou obaixador.pyde verdade (crash, não só log de erro). Corrigido: nome agora inclui o PID. 3 itens (1081,1082,1084) já tinham subido um HTML de visualizador como se fosse "legado" antes da correção — limpo do bucket, metadata regenerado. - PDFs de álbum perdidos no objdigital: 44 itens (achado 2.9 do PLANO.md) tinham PDF disponível mas a extração pegava um
.htmde landing page em vez do PDF de verdade. Corrigido emcatalogo.jsonle no IndexedDB antes dobaixador.py --somente-legadoalcançar esses handles (confirmado: nada contaminado no bucket).baixador.pyreiniciado (PID 37909) com o catálogo corrigido.
Concluído nesta sessão (chrome-extension-connection, ~17h UTC)
pipeline/reparo-hash-url.jscolado e rodado — 78/78 corrigidos no IndexedDB- Achado 2.13 (novo): mesmo bug do
#reaparecia no redirect do DSpace (forma antiga → canônica). Fix: usar/bitstream/handle/PREFIX/ID/arquivodireto.preservation_urldos 78 reescrito de novo com a forma canônica. - Os 78 itens baixados cirurgicamente — concluído 78/78, 0 erros (script à parte, não o
BAIXA.retomar()geral — aba antiga com o loop principal continua rodando sozinha, ver nota de handoff acima) BAIXA_THUMBv2 iniciado (aba nova, não foi possível parar a v1 na aba antiga — ver nota acima; sem risco de dado ruim no bucket graças à validação de magic bytes já nosubidor.py)- Thumbnails v2: CONCLUÍDO 100% —
BAIXA_THUMB.retomar()rodado (2026-09-11 ~08h local) recuperou todos os 1.281 erros da queda de rede (13.059/13.059 ok, 0 erro permanente) baixador.py --somente-legadoreiniciado uma vez (2026-09-11 ~08h local, PID 88387) depois que a passada anterior terminou (2.113 ok, 589 erro de 2.702 processados) — idempotente, só reprocessa não-'ok'- Checagem de status a cada 30 min retomada nesta sessão (ver
/loop)
Mural (web/wall.html) — sessão fix-mobile-wall-click-layout, 2026-09-12
No ar em https://xn--2dk.xyz/brasiliana/. Commits em rafapolo/xyz:
d8c3364 e a6085fa (empurrados pela sessão paralela brasiliano-ae, contêm
trabalho das duas) e f645008. O mural é publicado copiando
web/wall.html → xyz/brasiliana/index.html e web/atlas/atlas-map.json →
xyz/brasiliana/atlas/atlas-map.json.
Achado 3.1 — a metade descritiva do catálogo nunca chegou ao mural
Buscar "indigenista" não achava nada, mesmo com 42 peças classificadas
dc.subject = Política indigenista. A busca livre estava certa (varre todo o
meta recursivamente); quem descartava era o summarize() do
web/build-atlas.js, que projetava 8 campos e jogava fora assunto,
descrição, lugar, fonte, editor, relação e código de arquivo.
Havia um segundo bug atrás: pickDC() devolve só a primeira ocorrência do
campo. Como o catálogo repete dc.subject (78.835 linhas para 13.060
registros, ~6 por item), mesmo incluindo o campo sobreviveria um assunto por
peça. O pickAll() novo coleta todas, deduplicadas, na ordem.
Regras que ficaram (espelhadas em pipeline/reprojeta-meta-mapa.mjs):
- entram:
dc.subject,dc.description,dc.coverage,dc.source,dc.publisher,dc.relation,dc.identifier - ficam de fora:
dc.language(é sempre"por"— casaria ~2.000 itens por acidente, já que a busca é por substring) edc.format("JPG") dc.identifieredc.relationentram sem as URLs: era 1,1 MB de texto que ninguém busca, escondendo o que presta — os códigos de arquivo (013RJ012036) e os nomes de coleção (Gilberto Ferrez,Diários Associados)handleesource_urlsaíram dometa: o primeiro é a chave sob a qual o item já está arquivado no mapa, o segundo é o mesmo endereço para todos com o handle no meio. O mural remonta a URL numa linha (sourceUrl()) e injeta o handle na palha da busca, então buscar5546continua achando a peça.
Verificado no navegador: indigenista → 42, Gilberto Ferrez → 2.120,
013RJ012036 → 2, amazônia → 156, 5546 → 1. E o ruído sumiu: show=full
e brasilianafotografica saíram de 12.552 para 0.
Achado 3.2 — não vale pré-comprimir o atlas-map.json
Medido, não chutado:
- No fio já vem gzipado.
curl -sIem https://xn--2dk.xyz/brasiliana/atlas/atlas-map.json respondecontent-encoding: gzip. Pré-comprimir só moveria os mesmos bytes, ao custo de umDecompressionStreamno carregador e de um arquivo ilegível. (O host não oferece brotli, eDecompressionStreamnão decodifica brotli.) - No repositório também. O git comprime todo blob com zlib no pack, então
um JSON de 8 MB não ocupa 8 MB lá dentro — ocupa aproximadamente o que o
.gzocuparia, e ainda dá diff.
Encolher o conteúdo foi o que valeu, e só até certo ponto — o gzip come quase todo o ganho estrutural:
| variante | cru | gzip |
|---|---|---|
| com os campos descritivos | 9,61 MB | 1,11 MB |
sem source_url e meta.handle (feito) |
8,00 MB | 1,05 MB |
| + dicionário nos campos de vocabulário pequeno | 6,96 MB | 0,99 MB |
| + dicionário de assuntos/lugares/descrições | 5,14 MB | 0,93 MB |
As duas últimas linhas quase dobram a economia crua e rendem 30-60 KB no fio
cada, em troca de uma camada de dicionário no carregador — troca ruim. Onde o
tamanho cru ainda pesa é o JSON.parse no celular, não o download. Referência:
antes de tudo isso o mapa era 5,52 MB / 0,73 MB.
Consertos de interação (todos verificados por CDP num Chrome real)
- Toque numa peça abria e fechava a ficha no mesmo gesto (metade de cima da
tela). Um toque dispara
pointerupe depois umclickde compatibilidade, que caía no backdrop recém-aparecido; a guarda de 400 ms usavastopPropagation(), que não alcança listeners do mesmo nó — e quem fecha a ficha é um listener do próprio#card-wrap. Agora éstopImmediatePropagation(). - Tela inicial "sem estilo":
#title-screenera irmão flex do<p>e, invisível, ainda tomava metade da linha; e a regra#loading ppegava também o subtítulo, jogando-o em maiúsculas com tracking. Virouposition:absolutee#loading-msg. - Painel de filtros fugia do dedo no arrasto da década: o chip do filtro
aparecia e inseria uma linha inteira acima do corpo; o badge de contagem
crescia o header. Chips agora só com o painel fechado, badge reserva a caixa
com
visibility. - Movimento da parede: a câmera mirava o alvo enquanto estava atrás dele
(inclinava a vista a cada arrasto — era isso que fazia a parede "nadar"); o
easing era fração por frame (a 120 Hz convergia 2× mais rápido que a 60).
Agora constante de tempo,
lookAtremovido, e soltar em movimento joga a parede com desaceleração. Zoom do scroll virou multiplicativo. - Back/forward do navegador andam pelas peças abertas, com
#handlena URL (link direto reabre a peça). Mudar um filtro recolhe a ficha com um passo de histórico, mesmo comapply()rodando a cada frame do slider. - Filtros alcançáveis com a peça aberta: o painel estava em
z-index: 15debaixo do#card-wrap(20). Agora 25 (scrim 24), e no celular a ficha estaciona acima do peek da sheet para não cobrir ‹ anterior / próxima ›.
Miniaturas derivadas + reconciliação do ledger — 2026-09-12
Mural no ar com 13.059 peças (antes 12.552): commits bba32f6,
6a82a5e, 1ecded1 e e930158 em rafapolo/xyz. Desta vez o atlas/ inteiro foi junto, não só o
atlas-map.json — o formato do map mudou (ver achado 3.4).
Números fechados em 13/09 (medidos contra catálogo × ledger):
| itens no catálogo | 13.060 |
| com imagem de preservação | 12.991 |
| com thumbnail do DSpace | 13.059 |
com miniatura derivada (derivados/thumb256/) |
13.059 |
| no mural | 13.059 |
| fora do mural | 1 — só 7523 |
Os 8 que faltavam (7802, 7814, 7817, 7848, 7852, 7861, 7875,
8075) entraram: eles têm thumbnail/thumb_3.jpg de imagem real no
bucket (109–250 KB). A afirmação anterior de que o thumbnail deles era texto
de licença estava errada — o texto era o thumb_2 do material antigo do
finland, não o objeto do bucket.
Os 73 faltantes de preservação (achado 2.17/2.18) não ficam de fora do mural: têm thumbnail do DSpace, que basta para o tile de 128px. Faltar preservação e faltar no mural são coisas diferentes.
- Miniaturas derivadas — 13.051 itens (99,93%)
em
s3://brasiliana/derivados/thumb256/(256px WebP q80, ~8 KB cada, 100 MB no total). Prefixoderivados/deliberadamente fora deitens/:itens/é material de origem,derivados/é reconstruível do zero. Misturar os dois apagaria a procedência que o MANIFEST garante. Composição final (medida, igual à do MANIFEST): 12.849 derivadas da imagem de preservação + 202 derivadas dothumbnail/do DSpace (itens com miniatura mas sem preservação coletada). Caminho até lá: 6.338 no finland a partir do bucket, 6.483 locais a partir de~/Downloads, 164 do DSpace, e +66 do material do achado 2.21. - MANIFEST.md atualizado e subido — seção
derivados/, os achados 2.19 e 2.20 abaixo, e a nota de quethumbnail/do DSpace não é miniatura (achado 3.3). Re-subido em 12/09 com 13.051 / 99,93%, os 9 ausentes nomeados e a divergência 13.058 × 13.060 anotada. build-atlas.jsparou de descartar item sem título — a guardaif (!o.title) continueescondia do mural11749(Museu Aeroespacial) e6241(Instituto Moreira Salles), que têm imagem; o card já cai pra "(sem título)" sozinho. 12.983 → 12.985.- Wordmark "Acervo Brasiliana" ganhou fundo preto — só tinha
text-shadow, que some sobre peça clara, e peça clara é metade do acervo. Mesmo preto da dica do rodapé. - Rótulo de contagem deixou de dizer "no acervo" — dizia "N peças no acervo" como se o mural fosse o acervo inteiro; agora diz "peças com imagem". Foi essa frase que levantou a dúvida de que faltavam miniaturas.
web/build-atlas.jsganhou--thumbs=DIR— a fonte antiga (~/Downloads) é varrida pelosubidor.pyconforme sobe, então nunca tem o acervo inteiro ao mesmo tempo. Agora a fonte é reconstruível do bucket.- Ledger
subidor.sqlitereconciliado com o bucket: 28.553 linhas = 28.553 objetos, zero divergência nos dois sentidos. Backups em/private/tmp/claude-501/.../scratchpad/subidor.sqlite.bak-*. - 145 linhas dethumbnailsem objeto no bucket — são os bitstreams de LICENÇA do achado 2.8b, removidos do bucket mas deixados no ledger (426–815 bytes, só 5 sha256 distintos entre os 145). Apagadas. - 3 objetos no bucket sem linha nenhuma — inseridos, sha256 recalculado do próprio objeto. - 2.137 objetoslegado/que nenhum ledger de upload conhecia: obaixador.pysó anota nobaixador.sqlite. Importados, para quesubidor.sqliteseja ledger único. - 13.051 derivados registrados comotipo='derivado-thumb256'. - 63 "órfãos" de preservação/thumbnail eram falso positivo: gravados durante a própria listagem do bucket. Conferidos no S3, estão lá.
Achado 2.24 — 16 threads estouram o OpenSSL do macOS (SIGSEGV)
O subidor-paralelo.py morreu com segmentation fault no arranque da
passada das 10:56 de 13/09, e por isso nada subiu durante horas (o
vigia-30min só tentaria de novo meia hora depois). O relatório do macOS
aponta a pilha dentro do libcrypto:
libcrypto.3.dylib ossl_x509_store_ctx_get_by_subject
libcrypto.3.dylib X509_STORE_CTX_get1_issuer
libssl.3.dylib ssl_verify_internal / tls_post_process_server_certificate
É corrida de thread na verificação de certificado TLS quando muitas threads
fazem handshake ao mesmo tempo — bug do OpenSSL, não do nosso código. Com 4
threads subiu 50 arquivos a 19 GB/h sem problema. Default baixado para 6
threads no subidor-paralelo.py, no vigia-30min.sh e no
rodar-paralelo.sh. Não vale voltar a subir: acima de ~8 o ganho é nulo (o
link satura) e o risco de crash volta.
Achado 2.25 — 75 itens com HTTP 500 persistente na origem (não é só o 7523)
Passada de 13/09 com a aba conectada: 108 imagens novas baixaram, e 74
falharam com erro que não passa — 45 × HTTP 500, 26 de rede e 3 de blob
curto, com retry sem recuperar nenhuma. Somando o 7523, são 75 itens
cujos bitstreams de preservação a origem não serve. Lista em
pipeline/falhas-500-2026-09-13.txt.
Isso substitui o achado 2.23 (que falava em 211 faltantes): os outros 136 baixaram. Nenhum dos 75 fica fora do mural — todos têm thumbnail do DSpace.
Diagnóstico que vale registrar: os 500 são do item, não do ritmo. Com 3
requisições simultâneas, 6545 e 6555 davam 500 enquanto 1014, 8128,
10039, 14358 e 6520 davam 200 no mesmo instante, inclusive em série com
3 s de espaçamento. E os itens ruins são vizinhos de id, então em ordem
crescente eles davam erros seguidos e disparavam o aborto automático — por
isso o motor passou a embaralhar a lista.
Achado 2.26 — nova rodada sobre os 75 (13/09 noite): o que recupera e a armadilha da sequência
Recuperados (3): 6433 e 6520 por curl — a origem serve a ~11 KB/s, e o
"erro de rede" do navegador era estouro de tempo; 6656 no navegador na
sequência 3 (5,4 MB, 1604×2612) — o catálogo apontava a sequência 2, que é
o texto de licença.
Curl não escala: depois dos 2 primeiros o Cloudflare devolveu 403
(5.484 bytes) para 23 seguidos. Parado para não piorar o bloqueio.
Armadilha — não aceitar "qualquer imagem em qualquer sequência". A 1ª
versão do motor que varria as sequências 1–6 trouxe 8 "sucessos"; 7 eram o
thumbnail/thumb_3.jpg que já estava no bucket (sha256 idêntico, 27–170 KB,
~800 px). Retidos antes de subir e descartados. A estrutura típica de um item
DSpace deste acervo:
| sequência | conteúdo |
|---|---|
| 1 | imagem de preservação (nos itens com defeito: HTTP 500) |
| 2 | bitstream de licença (texto, 426–821 bytes) |
| 3 | thumbnail gerado pelo DSpace |
| 4–6 | inexistente |
A versão corrigida calcula SHA-256 no navegador e rejeita qualquer candidato
cujo hash já esteja no ledger como thumbnail ou legado, e grava com prefixo
HOLD__ (o subidor-paralelo.py ignora) para conferência antes de subir.
Achado 2.27 — os itens do IMS morrem num corte de 300 s; o 500 é o mesmo por sequência e por nome
Terceira rodada sobre os 75 (13/09, 21h), com um motor que registra o tempo de cada tentativa. Três comportamentos distintos, todos da origem:
- Corte em ~300 s sem resposta (
rede@301s), em 12 itens do Instituto Moreira Salles (8145–8316). A requisição não recebe nem cabeçalho: um teste comRange: bytes=0-1023estourou 18 s sem resposta, então não é transferência lenta que cai no meio — o servidor trava antes de responder e algo no caminho corta em 5 min. Retomar em pedaços não ajuda. - Corte em ~32 s em 3 itens (
8271,8275,8277): mesma família, limite diferente. 500imediato (0 s) em 11 itens (8739–9148). A forma canônica/bitstream/handle/20.500.12156.1/<id>/<arquivo>— que busca pelo nome em vez da sequência — também devolve500em 0,2 s (8739,6545). O defeito está no servidor localizar o bitstream, não no endereçamento.
Estrutura das sequências nos itens do IMS: 1 = preservação, 2 = thumbnail (sem bitstream de licença, ao contrário dos do Museu Aeroespacial/Arquivo Nacional/Fiocruz, onde 2 é licença e 3 é thumbnail). Varrer 1–6 nesses itens só gasta tempo: 3–6 não existem.
Recuperado nesta rodada: 8396 (Biblioteca Nacional, sequência 3, 13,5 MB,
3361×4453) — mesmo padrão de 6656 e 7939, onde o catálogo aponta a
sequência 2 (licença) e a imagem está na 3.
Achado 2.28 — a cópia legada: só existe para a Biblioteca Nacional, e 25 "cópias" são páginas HTML
Medido em 14/09. A cópia legada vem do objdigital.bn.br e só existe para
itens da Biblioteca Nacional: 2.702 dos 13.060 têm legacy_url, todos da BN.
Os 16% de cobertura não são falta — os outros 10.358 itens não têm cópia legada
na origem.
elegíveis (legacy_url no catálogo) |
2.702 |
no bucket como legado/ |
2.137 |
| — imagens JPG | 1.899 (859 MB) |
| — PDF de álbum | 213 (8,3 GB) |
| — páginas HTML | 25 (~2,4 KB cada) |
| HTTP 404 permanente | 565 (499 jpg, 41 html, 22 pdf, 2 htm, 1 sid) |
As 25 páginas HTML não são imagem. São o visualizador Seadragon do
objdigital (viewer.openDzi("GeneratedImages/dzc_output.xml")): a imagem mora
numa pirâmide de tiles Deep Zoom ao lado da página. Itens: 586, 587, 630,
802–806, 808, 809, 811, 812, 814, 816, 817, 870, 1080,
1083, 1085, 1086, 3198, 3545, 3546, 3866, 6655. Todos têm
imagem de preservação no bucket, então nenhum ficou sem imagem. Não foram
apagados — é decisão do usuário (ver pendência). Mesma família do bug de
1081/1082/1084 (HTML de visualizador subido como legado), que foi limpo
na época; estes 25 escaparam.
O objdigital não saiu do ar — mudou de endereço. Em 14/09 a porta 80
fechou nos dois IPs (200.9.175.46, 177.223.196.160), mas a 443 está aberta
e o site responde em https://objdigital.bn.br/objdigital2/acervo_digital/...
(o próprio visualizador Seadragon carrega o script desse prefixo). Prova de que
é a mesma fonte: 3 cópias legadas sorteadas do bucket, baixadas pelo endereço
novo, voltaram com sha256 idêntico. Correção de uma afirmação anterior
desta sessão: o icon573843.jpg usado como "controle" não tinha baixado
antes — ele é um dos 565 erros (item 10), e responde 200 no endereço novo.
Consequência: a maior parte dos 565 "404 permanentes" existe no endereço
novo. Sondagem completa por HEAD em 14/09 (pipeline/legado-caminho-novo.tsv):
| no endereço novo | itens |
|---|---|
200 com image/jpeg |
330 |
200 com application/pdf |
18 (o maior, 52 MB) |
200 com text/html (visualizador Deep Zoom, não arquivo) |
41 |
404 de verdade |
176 |
Recuperáveis como arquivo: 348 (~0,3 GB). As 41 páginas HTML somam-se às 25
já no bucket: 66 itens cuja imagem só existe como pirâmide de tiles. A pirâmide Deep Zoom das 25 páginas HTML
também responde (item 3545: dzc_output.xml, 5744×4245, tiles de 256 px).
**O baixador.py usa o endereço antigo (http://…/acervo_digital/) e precisa
ser atualizado antes de qualquer nova passada.
Achado 2.22 — o gargalo do upload era o subidor.py, não o link; troca pelo paralelo
Eu tinha escrito aqui que o gargalo era o link de casa. Errado. Medido em
12/09 (networkQuality): 69 Mbps de upload (~31 GB/h), contra ~1,3 GB/h
reais. O subidor.py sobe um arquivo por vez, espera 1,5 s de "estabilidade" e
dispara três aws s3 cp por arquivo (arquivo, metadata.json, manifest),
cada um pagando a partida do aws-cli: ~5 s por arquivo, seja miniatura de 74 KB
ou preservação de 40 MB.
Além de lento, ele estava estragando duas coisas:
- 873 manifests com linha errada,
derivado-thumb256/<handle>.webp. É consequência de eu ter registrado os derivados no ledger: ele lista toda linha do handle, e esse caminho não existe emitens/<handle>/. - Duplicatas
(N)voltando ao bucket depois da limpeza do achado 2.20 (ex.:5304,thumb_2.jpgethumb_2 (1).jpgcom o mesmo sha256).
Substituto: pipeline/subidor-paralelo.py (boto3, threads, HEAD antes de apagar
o local, manifest uma vez por item, sem linha de derivado, duplicata e rejeito
registrados) + pipeline/rodar-paralelo.sh. Teste com boto3 contra o bucket:
PUT de 20 MB a 27 Mbps num único stream.
Testes antes de soltar, com o que cada um mostrou:
- Lote de 30: todos eram rebaixa já presente no bucket e foram apagados do
disco sem HEAD e sem registro. Foi o que motivou a conferência por HEAD e a
tabela
descartados. Para esses 30, a garantia é só o ledger, reconciliado com o bucket às 12:50. - Lote de 150: 150 descartes, 150 conferidos no bucket.
- Lote de 800: 319 enviados (319 conferidos,
image/jpeg) + 481 descartes conferidos; manifests dos 319 sem linha de derivado, sha do metadata batendo. - Primeira execução real (18:4x UTC) interrompida: o log mostrava TIFF
indo para
rejeitados/(achado 2.19, correção). Assinaturas corrigidas; os 21 da quarentena (19 TIFF + 2 BMP) voltaram para a fila; relançado às 18:59.
Antes do relançamento, 180 arquivos locais (0,25 GB) já presentes no S3 foram
apagados do disco a pedido, cada um com MD5 local = ETag do objeto e registro em
descartados. Os outros 13.922 não estavam no bucket.
Achado 2.23 — faltam 211 preservações depois da fila, não 73
Cruzando catálogo × (ledger ∪ fila) em 12/09: 12.849 / 13.060 itens terão imagem de preservação quando a fila acabar (thumbnail: 13.059). Os 211:
- 71 da lista conhecida (
faltantes-preservacao.jsonl, recusa da origem); - 1 sem
preservation_urlno catálogo; - 139 fora de qualquer lista. Exemplo:
10039–10049, que no bucket têm sóthumbnail/emetadata.json. Desses: 8 rejeitados no upload antigo, 12 com sólegado/, ~119 sem rastro (nem bucket, nem fila, nem log).
Hipóteses, nenhuma confirmada: (a) o "12.986/13.059" do achado 2.16 contou
objetos legado/ e manifest como preservação, porque o awk só excluía
metadata.json e thumbnail; (b) parte dos ~119 pode ser TIFF apagado pelo
subidor.py antigo antes do trecho que o subidor.log cobre.
Achado 2.21 — a sessão de 11/09 já tinha as miniaturas no finland, e eu não olhei
/root/brasiliana-wall/ no finland tinha, desde 11/09 13:17–13:41:
downloads-flat/ (20.411 arquivos, todos THUMB__, 2,2 GB), s3-thumbs/
(5.168 handles do bucket, 851 MB) e o web/atlas/ cujos quatro .webp batem
byte a byte com o que estava publicado no xyz até 12/09. O mural de 12.552
peças foi construído lá, a partir das miniaturas do DSpace — não de
~/Downloads, como o comentário do build-atlas.js leva a crer.
A união desses dois diretórios cobre 13.041 handles, praticamente todos JPEG válido. Eu puxei ~63 GB de imagens de preservação do bucket para derivar 12.985 miniaturas sem ver que 3 GB de miniatura já estavam no disco da mesma máquina, cobrindo mais itens que o meu resultado. Aproveitados depois: +66 peças (74 no delta, 8 eram licença).
Lição de runbook: antes de gerar qualquer coisa no finland, ls /root e
cat /root/.bash_history. Sessões anteriores deixam material lá e nada no
projeto local registra isso.
Limpeza feita em 12/09: /root/brasiliana-wall e /root/thumbs apagados
(3,4 GB; disco 27 → 31 GB livres), depois de verificar que os 13.041 handles
estavam todos cobertos pelo bucket (7.038) ou pela fila do Mac (6.785) —
zero cópias exclusivas. Ficaram de pé, de propósito: /root/.s3env (600, de
08/09, anterior às nossas sessões — pode ser setup permanente da máquina) e
/root/brasiliana/ (44 MB, baixador.py + catálogo + sqlite com 13 linhas).
Achado 2.19 — a contaminação de LICENÇA também atinge a preservação, não só a miniatura
O achado 2.8b tratou isso como problema da trilha de thumbnail. Não é: os
handles 20.500.12156.1/6656 e 20.500.12156.1/7939 têm, em
~/Downloads, um "imagem.jpg" que é na verdade o bitstream de LICENÇA do
DSpace — 777 bytes de texto UTF-8 com CRLF e extensão .jpg. A validação de
magic bytes do subidor.py barra no upload, então nada disso chegou ao
bucket; o efeito é que esses dois itens não têm imagem coletada e ninguém
percebeu, porque a fila local os contava como prontos.
Implicação: qualquer contagem de "preservação pronta" que leia ~/Downloads
pelo nome do arquivo está 2 itens otimista. A contagem pelo bucket está certa.
Atualização 12/09: não são 2, são 10. Ao derivar as miniaturas do material
do finland (achado 2.21) apareceram mais oito com o mesmo defeito, todos
na trilha de thumbnail: 7802, 7814, 7817, 7848, 7852, 7861,
7875, 8075. São exatamente os itens que sobram fora do mural. O bloco
78xx sugere que a contaminação vem em lote, por faixa de handle — vale
varrer essa faixa inteira antes de dar o acervo por fechado.
Correção 12/09 (noite) — a regra de validação estava errada. O subidor.py
só aceitava JPEG/PNG e apagava o resto como "bitstream de licença". Pelo
próprio subidor.log, dos 40 arquivos que ele apagou assim, só 1 era
texto de licença: 36 eram TIFF (II*\0, ~8 MB, com extensão .jpg),
2 BMP e 1 ZIP (001AAN014011.jpg.zip, item 2384). Resultado, item a
item (lista com URL em pipeline/apagados-pelo-subidor-antigo.jsonl):
- 8 itens ficaram sem nenhuma imagem de preservação:
14358,14359,14360,14361,14362,14363,14364,14368(TIFF, série "Alb 0261"). - 18 itens perderam só bitstreams extras (
extra_seqN, TIFF), mas têm a imagem principal no bucket ou na fila.10993/10995(BMP) e2384(ZIP) voltaram por rebaixa e estão na fila. Osubidor-paralelo.pyaceita TIFF/BMP/GIF/JP2/WebP pela assinatura e manda qualquer outra coisa parapipeline/rejeitados/com linha na tabelarejeitados— nunca apaga. Os 8 casos78xxde thumbnail com texto de licença (acima) foram detectados pelovipsthumbnail, não por essa regra, e continuam valendo.
Achado 2.20 — 3.511 duplicatas (N) no bucket, do Chrome rebaixando por cima
Objetos arquivo (1).jpg convivendo com arquivo.jpg byte a byte idêntico —
sufixo que o Chrome põe ao rebaixar um arquivo que já existe em ~/Downloads,
e que o subidor.py subiu como se fosse nome legítimo. Confirmadas idênticas
por ETag + tamanho (não só tamanho) antes de apagar: 3.511 objetos,
0,39 GB, removidos do bucket e do ledger na mesma passada.
Não foram tocados, e precisam de decisão:
- 30 objetos cujo gêmeo tem tamanho diferente — não são duplicata, são versões distintas do mesmo nome. Precisam de conferência individual.
- 43 objetos cujo nome tem
(N)mas que são o único arquivo do item — candidatos a renomear, nunca a apagar.
aws s3api list-objects-v2 com --query "Contents[].[Key,Size,ETag]" resolve
isso sem baixar nada; o ETag é o MD5 pra upload simples (só os 2.612 objetos
multipart do bucket não servem pra comparação direta).
Achado 3.3 — o thumbnail/ do DSpace não é uma miniatura
Medido em amostra de 300: 721 a 3.709 px no maior lado, média 1.087; menor lado nunca abaixo de 462. São derivados de resolução média, não miniaturas de listagem. Duas consequências:
- Servem tão bem quanto a imagem de preservação pro tile de 128px do mural — por isso deu pra cobrir os 164 itens sem preservação sem perda visível.
- A linha "Miniatura | ~13.005 elegíveis" do MANIFEST descreve ~1 MB por arquivo, não ~8 KB. Quem ler esperando miniatura vai baixar 100x mais do que imagina.
Achado 3.4 — publicar o mural agora exige mandar o atlas/ junto
O wall.html de 12:32 passou a derivar handle (chave do map) e source_url
(mesmo prefixo pra todo item) em JS, em vez de lê-los de cada peça. O
summarize() do build-atlas.js acompanhou. Resultado: 8,2 MB de map com
12.983 peças contra 10 MB com 12.552 — menos peso com 431 peças a mais.
Mas isso quebra a nota antiga de que "o atlas/ já está commitado lá e não
muda a cada alteração do mural": map e wall.html agora são um par acoplado
por formato. Publicar um sem o outro deixa o mural sem link e sem busca por
handle.
Pendente
-
dc.rightsausente em 5.833 itens (44,7%) — confirmado como característica real da fonte, não bug. Só precisa ficar documentado no MANIFEST final, sem ação de reparo. -
web/build-atlas.jsnão está versionado em lugar nenhum —brasiliano/não é repo git e oxyzsó recebe oindex.htmle oatlas/. A correção dosummarize()/pickAll()(achado 3.1) vive só no disco desta máquina; umrmleva junto. Mesma exposição vale parapipeline/inteiro. -
Encolher mais o
atlas-map.jsonsó com dicionário (achado 3.2): 8,00 → 5,14 MB crus por ~120 KB no fio. Só vale se oJSON.parseno celular virar problema medido — não antes. -
30 objetos
(N)com tamanho diferente do gêmeo (achado 2.20) — conferência individual, não dá pra automatizar com segurança. -
43 objetos
(N)que são o único arquivo do item (achado 2.20) — renomear tirando o sufixo, pra o nome não mentir sobre haver um original ao lado. -
Handles
6656e7939sem imagem de preservação (achado 2.19) — rebaixar; o que há hoje na fila local é o bitstream de licença. -
Conferir os códigos HTTP que nunca foram tabulados — o runbook do achado 2.18 manda rodar
FALTA.erros()no console e rotear por código (404 → reparar URL, 403 → bloqueio de origem, 500 → transitório, retomar). Esse passo nunca foi executado: o achado 2.18 concluiu "é recusa da origem" a partir dostatus()agregado, não da tabela de erros por handle. Sem isso não dá pra saber quantos dos 71 são reparáveis. -
Reconferir o handle
7523(HTTP 500) — registrado uma vez e tratado como falha permanente da origem desde então, mas 500 costuma ser transitório e nunca houve segunda tentativa. Não dá pra testar porcurl, e agora está provado com controle (12/09): com User-Agent, Accept, Accept-Language e Referer de Chrome, o7523devolve403de 5.484 bytes (página do Cloudflare) — e o item10, que sabidamente funciona e está no bucket, devolve exatamente o mesmo403de 5.484 bytes. É bloqueio geral a requisição sem sessão real, nada específico do7523. Precisa da aba; a extensão Claude-in-Chrome seguia desconectada em duas tentativas no mesmo dia. -
Reconciliar 13.058 vs 13.060 — o MANIFEST fala em 13.058 itens reais, o
catalogo.jsonltem 13.060 handles distintos. Diferença de 2 nunca explicada; anotada no MANIFEST como pendência. -
Depois que os 212 faltantes baixarem e subirem (pedido do usuário, 13/09): 1. conferir se todos os itens têm miniatura em
derivados/thumb256/e gerar as que faltarem (as novas preservações não têm derivado ainda); 2. regerar o mural 3D com o conjunto completo — de preferência derivando no finland direto do bucket (itens/*/preservacao/*), que é tráfego intra-Hetzner, em vez de puxar pro Mac; 3. republicarwall.html+atlas/norafapolo/xyz(par acoplado, achado 3.4). -
Quando o
rodar-paralelo.shterminar (log termina em===== ... FIM): 1. conferir no log as três fases sem!!!, a linhaFIM da fila(enviados, duplicatas, rejeitados, falhas) e ospendente:que ficaram no disco; 2.ls pipeline/rejeitados/+select * from rejeitados— só deve ter texto de licença; imagem ali é bug de assinatura; 3. reconciliar ledger × bucket (mesmo diff do achado de 12/09: 0 divergências nos dois sentidos) e amostrar manifests (grep derivado= 0); 4. varrer~/Downloads: apagar o que tiver MD5 = ETag no bucket (mesmo método dos 180 de 12/09), manter o resto; 5. atualizar a tabela de contagens do MANIFEST com os números fechados. -
Rebaixar o que o
subidor.pyantigo apagou (achado 2.19, correção): 8 itens sem preservação (14358–14364,14368) + ~20extra_seqNem TIFF — lista com URL empipeline/apagados-pelo-subidor-antigo.jsonl. Precisa da aba do navegador. -
Recontar os faltantes de preservação (211)— feito em 13/09: 136 baixaram, sobraram 75 com defeito de origem (achado 2.25), listados empipeline/falhas-500-2026-09-13.txt. Script usado:pipeline/baixar-faltantes-v3.js(ou o motorF5colado direto na aba). -
subidor.pyantigo: aposentar ou corrigir a regra de assinatura antes de qualquer uso futuro — do jeito que está, apaga TIFF. -
Rebaixar os 69 que sobraram (achados 2.25–2.27; 6 recuperados em 13/09 à noite) quando a origem se recuperar — todos têm thumbnail, falta a preservação. Um
FALTA3.retomar()/F5.iniciar()na aba basta; o que já baixou fica marcado nolocalStorage(bras_faltantes_v3). -
Handle
8396sem imagem e sem diagnóstico — não está empipeline/faltantes-preservacao.jsonlnem nas exceções conhecidas do MANIFEST; apareceu ao cruzar catálogo × miniaturas. Precisa de uma tentativa avulsa pra saber se é recusa da origem (achado 2.18) ou outra coisa. -
.gitdorafapolo/xyzestá em 2,5 GB e cada publicação do atlas soma ~51 MB permanentes (binário não faz delta). Se o mural for republicar atlas com frequência, tirar os.webpdo git — LFS, ou servir do próprio bucket, que já tem os thumbs emderivados/thumb256/. -
Crawl da Fase 1 pode ter mais buracos (achado 2.10 do PLANO.md): 2 itens reais (
1799,4798) foram achados faltando no catálogo só porque o WordPress os citava — já corrigidos, mas não existe verificação exaustiva de que a enumeração porbrowse?type=titlepegou 100% de cada comunidade. Sem ideia barata de auditar isso por completo agora. -
Baixar os 348 legados recuperáveis pelo endereço novo (achado 2.28) — atualizar antes o
baixador.pyparahttps://objdigital.bn.br/objdigital2/acervo_digital/. -
Decidir o que fazer com as 66 páginas HTML de visualizador (25 já em
legado/+ 41 no endereço novo; achado 2.28): apagar do bucket e do ledger (não são imagem), ou montar a imagem a partir dos tiles Deep Zoom quando o objdigital voltar. Todos os 25 itens já têm preservação.
Ao final (não fazer antes do download terminar)
- Gerar
MANIFEST.md(o que é, como foi coletado, quando) — feito; atualizado em 2026-09-12 comderivados/e os achados 2.19/2.20/3.3 - Confirmar no bucket que a contagem de itens/checksums bate com os 13.058 itens reais esperados
Notas técnicas úteis pra retomar
- Downloads automáticos do Chrome exigem permissão manual em
chrome://settings/content/automaticDownloads(site adicionado:https://brasilianafotografica.bn.gov.br) — já concedida, vale pra novos scripts também, não só o original. BRAS,BAIXA,BAIXA_THUMB,BAIXA_EXTRA— todos nowindowda mesma aba, mesmo IndexedDB (bras). Todos sobrevivem a fechar/reabrir a aba (dado fica salvo), mas o loop para e precisa recolar o script certo pra retomar.- Regerar as miniaturas derivadas (tudo reconstruível, nada precisa ser
guardado): no finland,
apt install libvips-tools parallel+ s5cmd; pra cada chave deitens/*/preservacao/*,s5cmd catnum tmp evipsthumbnail "$TMP" --size 256 --output "$OUT[Q=80,strip]", comparallel -j 10. ~640 thumbs/min, tráfego intra-Hetzner (bucket éhel1, o finland também) — não passa pelo link de casa. O que ainda está só em~/Downloadssai mais barato derivado localmente commagick: mandar os 71 GB pro finland custaria os mesmos dias do upload pendente. - Cuidado ao parsear
s5cmd ls: nomes de arquivo do acervo têm espaço duplo (48094 Álbum 311 - ...jpg).awk '{$1="";$2="";$3=""; print}' recolapsa esses espaços e produz chaves que não existem — 31 downloads falharam assim antes de eu perceber. Usesed -E 's|^[0-9/]+ +[0-9:]+ +[0-9]+ ||'`, que preserva o resto literal. sqlite3desta máquina tem.sqlitercforçando modo box: qualquer script que leia a saída precisa desqlite3 -init /dev/null -noheader -separator $'\t', senão vem borda de tabela no lugar dos dados (me custou um diff inteiro de falso positivo).until ! pgrep -f X; do sleep; donenunca termina: a linha de comando do próprio loop contémX, então opgrep -fse acha e a condição nunca vira falsa. Um loop desses ficou girando horas depois do trabalho acabar (12/09, morto à mão). Esperar por PID (while kill -0 $PID) ou usarpgrep -f '[t]humb-local'para o padrão não casar consigo mesmo.- Parar processo lançado em background: SIGTERM, não SIGINT. Processo
iniciado com
&num shell não interativo herda o SIGINT ignorado (osubidor.pyficou 60 s vivo depois dokill -INT). Com SIGTERM, oaws s3 cpfilho termina órfão, o que é inofensivo: sem linha no ledger e sem apagar o local, o próximo uploader sobe de novo a mesma chave. - Upload de casa: 69 Mbps (
networkQuality -s, 12/09); download 312 Mbps. - Assinaturas aceitas como imagem (
subidor-paralelo.py): JPEGFFD8, PNG, TIFFII*\0/MM\0*, GIF, JP2, BMPBM, WebP. Content-Type sai do conteúdo, não da extensão (TIFF chega com nome.jpg). vipsthumbnail --outputé relativo à pasta do arquivo de entrada, não ao diretório corrente:vipsthumbnail tmp/x.img --output out/y.webptenta gravar emtmp/out/y.webpe falha. Usar caminho absoluto na saída. (Custou uma miniatura "refeita" que não foi refeita, em 13/09.)- Scripts-fonte em
pipeline/:coletor.js/coletor-resume.js(metadados),baixador-navegador.js(preservação, todos os itens),baixador-thumb.js(miniaturas),baixador-extras.js(2a+ imagem de itens multi-bitstream),reparo-multibitstream.js(enumera bitstreams reais de um item).