feat: descrição arquivística NOBRADE multinível com exportação EAD 3, EAC-CPF e AtoM
- pipeline/nobrade: normalizadores de datas (ISO 8601-2), séries, autoridades, espécie/suporte, direitos, lugar e assuntos; montagem dos níveis 0–5 com código de referência BR RJXYZ.BF.<seção>.<série>.<handle>.<imagem> - validador dos elementos obrigatórios: 0 pendências em 26.454 unidades - EAD 3 e 457 EAC-CPF validados contra os XSD - mural: cartão com código, data normalizada, série e reprodução; filtro por série
This commit is contained in:
@@ -20,3 +20,10 @@ pipeline/rejeitados/
|
|||||||
web/atlas/*.webp
|
web/atlas/*.webp
|
||||||
pipeline/catalogo.jsonl
|
pipeline/catalogo.jsonl
|
||||||
pipeline/wordpress-posts.jsonl
|
pipeline/wordpress-posts.jsonl
|
||||||
|
|
||||||
|
# descrição NOBRADE: saídas pesadas, regeneradas por `python -m nobrade` (vão para o bucket)
|
||||||
|
descricao/unidades.jsonl
|
||||||
|
descricao/ead/
|
||||||
|
descricao/eac/
|
||||||
|
descricao/atom.csv
|
||||||
|
__pycache__/
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ Este arquivo resume a norma (seções 1–4) e registra as decisões de aplicaç
|
|||||||
tomadas para a cópia digital da Brasiliana Fotográfica (seção 5). A
|
tomadas para a cópia digital da Brasiliana Fotográfica (seção 5). A
|
||||||
implementação está em `pipeline/nobrade/` e a saída em `descricao/`.
|
implementação está em `pipeline/nobrade/` e a saída em `descricao/`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd pipeline
|
||||||
|
python3 -m nobrade # descricao/: unidades, autoridades, revisão, pendências, EAD 3, EAC-CPF, AtoM
|
||||||
|
python3 -m nobrade.mural # leva código, data, série e suporte para web/atlas/atlas-map.json
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. O que é a NOBRADE
|
## 1. O que é a NOBRADE
|
||||||
@@ -79,6 +85,11 @@ Em **negrito**, os 7 obrigatórios.
|
|||||||
não expuser os níveis, o elemento 1.4 tem de listar os títulos de todos os
|
não expuser os níveis, o elemento 1.4 tem de listar os títulos de todos os
|
||||||
níveis superiores (1.1.4).
|
níveis superiores (1.1.4).
|
||||||
- Exemplos da norma: `BR MN`, `BR CPDOC JG`, `BR AN Q6.LEG.COR,TEL`.
|
- Exemplos da norma: `BR MN`, `BR CPDOC JG`, `BR AN Q6.LEG.COR,TEL`.
|
||||||
|
- Na prática (código CODEARQ), o código da entidade leva a UF colada à sigla,
|
||||||
|
e as partes da unidade vão separadas por ponto. Exemplo do Arquivo Geral da
|
||||||
|
Cidade do Rio de Janeiro: `BR RJAGCRJ.SOP.NL.AVE.03.01` = país · UF+entidade ·
|
||||||
|
fundo (Secretaria de Obras Públicas) · série (Negrão de Lima) · subsérie
|
||||||
|
(Avenidas) · dossiê 03 · item 01, a imagem em si.
|
||||||
|
|
||||||
### 1.2 Título
|
### 1.2 Título
|
||||||
- Registrar o título original. Na falta dele, atribuir um título formado a
|
- Registrar o título original. Na falta dele, atribuir um título formado a
|
||||||
@@ -155,18 +166,25 @@ de origem. Por isso:
|
|||||||
|
|
||||||
| Nível | Unidade | Origem | Código |
|
| Nível | Unidade | Origem | Código |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 0 | Acervo da entidade | — | `BR XYZ` |
|
| 0 | Acervo da entidade | — | `BR RJXYZ` |
|
||||||
| 1 | Coleção Brasiliana Fotográfica (cópia digital) | — | `BR XYZ BF` |
|
| 1 | Coleção Brasiliana Fotográfica (cópia digital) | — | `BR RJXYZ.BF` |
|
||||||
| 2 | Seção = instituição de origem | `community` | `BR XYZ BF.IMS` |
|
| 2 | Seção = instituição de origem | `community` | `BR RJXYZ.BF.IMS` |
|
||||||
| 3 | Série = coleção/fundo de origem | `dc.source` normalizado | `BR XYZ BF.IMS.GF` |
|
| 3 | Série = coleção/fundo de origem | `dc.source` normalizado | `BR RJXYZ.BF.IMS.GF` |
|
||||||
| 4 | Dossiê = item do DSpace (handle) | `handle` | `BR XYZ BF.IMS.GF.12345` |
|
| 4 | Dossiê = item do DSpace (handle) | `handle` | `BR RJXYZ.BF.IMS.GF.12345` |
|
||||||
| 5 | Item documental = cada imagem do dossiê | bitstreams | `BR XYZ BF.IMS.GF.12345.2` |
|
| 5 | Item documental = cada imagem do dossiê | ledger do bucket | `BR RJXYZ.BF.IMS.GF.12345.01` |
|
||||||
|
|
||||||
- `BR XYZ` é **provisório** até o CONARQ atribuir um código. A troca é uma
|
- `RJXYZ` é **provisório** até o CONARQ atribuir um código. A troca é uma
|
||||||
constante em `pipeline/nobrade/config.py`.
|
constante em `pipeline/nobrade/config.py`.
|
||||||
|
- **Toda imagem é um item de nível 5**, mesmo quando o dossiê tem só uma
|
||||||
|
(`.01`), como no AGCRJ. Os 115 dossiês com várias imagens têm `.01`–`.06`.
|
||||||
- O código do dossiê termina no número do handle (proc. 1.1.2.2), então
|
- O código do dossiê termina no número do handle (proc. 1.1.2.2), então
|
||||||
sobrevive a reclassificações de série sem perder a ligação com a origem.
|
sobrevive a reclassificações de série sem perder a ligação com a origem.
|
||||||
- Itens sem série identificável ficam na série `AV` ("Avulsos") da sua seção.
|
- Itens sem série identificável ficam na série `AV` ("Avulsos") da sua seção.
|
||||||
|
Notações de caixa e de negativo em `dc.source` (`CX 14`, `NV 2056`) não viram
|
||||||
|
série: vão para 5.1 como notação na origem.
|
||||||
|
- O IHGB é a única instituição que publica o próprio código NOBRADE
|
||||||
|
(`BR RJIHGB 064IG 0278`, em `dc.identifier`). Ele fica em 5.1 como código na
|
||||||
|
origem.
|
||||||
|
|
||||||
### 5.3 De onde vem cada elemento
|
### 5.3 De onde vem cada elemento
|
||||||
|
|
||||||
@@ -174,7 +192,7 @@ de origem. Por isso:
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1.2 Título | `dc.title` | nome da coleção, instituição ou série |
|
| 1.2 Título | `dc.title` | nome da coleção, instituição ou série |
|
||||||
| 1.3 Data | `dc.date` normalizado + ISO 8601. `dc.coverage` → data tópica | datas-limite dos filhos |
|
| 1.3 Data | `dc.date` normalizado + ISO 8601. `dc.coverage` → data tópica | datas-limite dos filhos |
|
||||||
| 1.5 Dimensão | `dc.type` → espécie + suporte. Cópia digital: pixels e bytes | soma por espécie |
|
| 1.5 Dimensão | `dc.type` → espécie + suporte; cor e medidas que AN e AGCRJ põem em `dc.description`. Cópia digital: arquivos e bytes | soma por espécie |
|
||||||
| 2.1 Produtor | `dc.contributor` (fotógrafo), forma autorizada | colecionador / instituição |
|
| 2.1 Produtor | `dc.contributor` (fotógrafo), forma autorizada | colecionador / instituição |
|
||||||
| 2.3 Hist. arquivística | `dc.date.accessioned` (entrada no DSpace), data da coleta | relato da coleta (nível 1) |
|
| 2.3 Hist. arquivística | `dc.date.accessioned` (entrada no DSpace), data da coleta | relato da coleta (nível 1) |
|
||||||
| 2.4 Procedência | Brasiliana Fotográfica, handle, data da coleta | idem, agregado |
|
| 2.4 Procedência | Brasiliana Fotográfica, handle, data da coleta | idem, agregado |
|
||||||
@@ -202,12 +220,46 @@ de origem. Por isso:
|
|||||||
- `descricao/eac/`: um EAC-CPF por autoridade.
|
- `descricao/eac/`: um EAC-CPF por autoridade.
|
||||||
- `descricao/pendencias.md`: relatório do validador dos obrigatórios.
|
- `descricao/pendencias.md`: relatório do validador dos obrigatórios.
|
||||||
- `descricao/revisao/*.tsv`: tabelas dos normalizadores para revisão manual.
|
- `descricao/revisao/*.tsv`: tabelas dos normalizadores para revisão manual.
|
||||||
Uma correção feita ali prevalece na próxima geração.
|
- `pipeline/nobrade/ajustes/series.tsv` (colunas `instituicao`, `dc_source`,
|
||||||
|
`titulo`): correção manual de série, que prevalece sobre a regra na próxima
|
||||||
|
geração.
|
||||||
|
- `descricao/atom.csv`: importação no AtoM (modelo ISAD).
|
||||||
|
|
||||||
### 5.5 Pendências fora do código
|
Versionados no git: textos, revisão, autoridades e pendências. `unidades.jsonl`,
|
||||||
|
`ead/`, `eac/` e `atom.csv` são regenerados e vão para o bucket.
|
||||||
|
|
||||||
|
### 5.5 Decisões de normalização
|
||||||
|
|
||||||
|
- **Datas:** 190 padrões distintos na origem. Saem na forma da norma
|
||||||
|
(`[ca. 1905]`, `[193-?]`, `8/2/1890-18/4/1890`) e em ISO 8601-2/EDTF
|
||||||
|
(`1905~`, `193X?`, `1890-02-08/1890-04-18`). `circa` fica como `ca.`,
|
||||||
|
convenção do AACR2, que a norma cita. Os 167 carimbos de registro do DSpace
|
||||||
|
gravados em `dc.date` não são tratados como data de produção. Os dossiês sem
|
||||||
|
data recebem uma data atribuída (proc. 1.3.3.2), `[A-B?]`, a partir do
|
||||||
|
período de atividade do autor, ou senão das datas-limite da série, ou senão
|
||||||
|
das da instituição. A base da atribuição fica anotada.
|
||||||
|
- **Título ausente:** atribuído entre colchetes a partir da descrição ou dos
|
||||||
|
assuntos (proc. 1.2).
|
||||||
|
- **Espécie ausente:** presumida fotografia, com nota. O repositório inteiro é
|
||||||
|
fotográfico.
|
||||||
|
- **Autoridades:** grafias unidas por chave sem acento e por inversão ("Marc
|
||||||
|
Ferrez" → "Ferrez, Marc"). A forma autorizada é a variante com datas mais
|
||||||
|
completas; as outras viram remissivas (8.1.4). Anônimos não viram autoridade.
|
||||||
|
- **Assuntos:** as traduções inglesas que o DSpace da BN repete ficam separadas
|
||||||
|
(`assuntos_eng`). Os assuntos seguem o vocabulário da origem, sem controle
|
||||||
|
adicional.
|
||||||
|
- **Direitos:** quatro categorias: domínio público, uso cultural liberado,
|
||||||
|
requer autorização do detentor, e consultar o detentor. O texto da origem
|
||||||
|
fica em 6.2.
|
||||||
|
- **Valores corrompidos na origem** (fragmentos de XML ou hash no lugar do
|
||||||
|
texto): desconsiderados e anotados em 6.2.
|
||||||
|
|
||||||
|
### 5.6 Pendências fora do código
|
||||||
|
|
||||||
- [ ] Pedir ao CONARQ o código da entidade custodiadora (proc. 1.1.1) e
|
- [ ] Pedir ao CONARQ o código da entidade custodiadora (proc. 1.1.1) e
|
||||||
substituir `BR XYZ`.
|
substituir `RJXYZ`, além de definir o nome da entidade (`ENTIDADE_NOME`).
|
||||||
- [ ] Revisar `descricao/revisao/series.tsv` e `datas.tsv` (valores que o
|
- [ ] Revisar `descricao/revisao/series.tsv` e `datas.tsv` (valores que o
|
||||||
normalizador não resolveu).
|
normalizador não resolveu).
|
||||||
- [ ] Revisar os textos dos níveis 2 e 3 em `descricao/textos/`.
|
- [ ] Revisar os textos dos níveis 2 e 3 em `descricao/textos/`. Os das
|
||||||
|
seções são rascunhos.
|
||||||
|
- [ ] Revisar as 813 datas atribuídas pelo arquivista (`revisao/datas.tsv`).
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
|
|||||||
|
# Pendências da descrição NOBRADE
|
||||||
|
|
||||||
|
Gerado por `python -m nobrade`. Obrigatórios reprovam; avisos pedem revisão.
|
||||||
|
|
||||||
|
| Nível | Unidades |
|
||||||
|
|---|--:|
|
||||||
|
| 0 acervo | 1 |
|
||||||
|
| 1 coleção | 1 |
|
||||||
|
| 2 seção | 15 |
|
||||||
|
| 3 série | 115 |
|
||||||
|
| 4 dossiê | 13.060 |
|
||||||
|
| 5 item | 13.262 |
|
||||||
|
|
||||||
|
## Obrigatórios faltando: 0
|
||||||
|
|
||||||
|
Nenhum. Todas as unidades têm os elementos obrigatórios do seu nível.
|
||||||
|
|
||||||
|
## Avisos
|
||||||
|
|
||||||
|
| Aviso | Dossiês |
|
||||||
|
|---|--:|
|
||||||
|
| 4.2 condição de reprodução não informada na origem | 8.036 |
|
||||||
|
| 1.5 espécie presumida | 5.422 |
|
||||||
|
| 2.1 autoria não identificada | 3.287 |
|
||||||
|
| nível 3 em Avulsos — série de origem não identificada | 2.865 |
|
||||||
|
| 3.1 sem âmbito e conteúdo | 2.775 |
|
||||||
|
| 1.3 data atribuída pelo arquivista — conferir | 813 |
|
||||||
|
| valores corrompidos na origem | 105 |
|
||||||
|
| 6.1 preservação indisponível na origem | 69 |
|
||||||
@@ -0,0 +1,458 @@
|
|||||||
|
id forma_autorizada tipo ocorrencias variantes
|
||||||
|
A0001 Ferrez, Marc, 1843-1923 pessoa 1960 Ferrez, Marc | Marc Ferrez | Marc Ferrez (Autoria)
|
||||||
|
A0002 Malta, Augusto, 1864-1957 pessoa 1175 Augusto Malta | MALTA, Augusto | Malta, Augusto | Malta, Augusto,1864-1957
|
||||||
|
A0003 Escola de Aviação Militar entidade coletiva 596 ""
|
||||||
|
A0004 Santos, Guilherme pessoa 420 ""
|
||||||
|
A0005 Gutierrez, Juan, 1859-1897 pessoa 373 Gutierrez, Juan | Gutierrez, Juan, m. 1897
|
||||||
|
A0006 Kfuri, Jorge, 1893-1965 pessoa 294 Kfuri, Jorge
|
||||||
|
A0007 Klumb, Revert Henrique, fl. 1855-1880 pessoa 290 Klumb, Revert Henrique
|
||||||
|
A0008 Leuzinger, Georges pessoa 257 ""
|
||||||
|
A0009 Escola de Aeronáutica entidade coletiva 174 ""
|
||||||
|
A0010 Officina de Paulo Robin entidade coletiva 169 ""
|
||||||
|
A0011 Robin, Paulo, m. 1897 pessoa 158 ""
|
||||||
|
A0012 Photographia Brazileira entidade coletiva 126 ""
|
||||||
|
A0013 Wischral, Arthur pessoa 124 ""
|
||||||
|
A0014 Gaensly, Guilherme, 1843-1928 pessoa 123 Gaensly, Guilherme
|
||||||
|
A0015 Escola de Aeronáutica Militar entidade coletiva 88 ""
|
||||||
|
A0016 Merrill, D. B. (Dana B.) pessoa 86 ""
|
||||||
|
A0017 Pacheco, Joaquim Insley, 1830-1912 pessoa 82 Pacheco, Joaquim Insley | Pacheco, Joaquim Insley, m. 1912
|
||||||
|
A0018 Azevedo, Militão Augusto de pessoa 75 ""
|
||||||
|
A0019 Museu Aeroespacial entidade coletiva 74 ""
|
||||||
|
A0020 Lamberg, Moritz pessoa 73 ""
|
||||||
|
A0021 Stahl, Augusto pessoa 72 ""
|
||||||
|
A0022 Barros, Justiniano José de pessoa 72 ""
|
||||||
|
A0023 Barros, Flávio de pessoa 71 ""
|
||||||
|
A0024 Holland, S. H pessoa 63 ""
|
||||||
|
A0025 Photographia Americana entidade coletiva 63 ""
|
||||||
|
A0026 Marc Ferrez & Cia entidade coletiva 62 ""
|
||||||
|
A0027 Rondon, Benjamin pessoa 62 Benjamin Rondon | [Rondon, Benjamin]
|
||||||
|
A0028 Gabinete Fotográfico da Comissão de Obras do Porto (RJ) entidade coletiva 58 ""
|
||||||
|
A0029 Pastore, Vincenzo pessoa 58 ""
|
||||||
|
A0030 Henschel, Alberto, 1827-1882 pessoa 57 Alberto Henschel | Henschel, Alberto
|
||||||
|
A0031 Gorham, Reginald pessoa 56 ""
|
||||||
|
A0032 Pinto, J., 1884-1951 pessoa 56 J. PInto | J. Pinto | Pinto, J.
|
||||||
|
A0033 Torres pessoa ou entidade 55 ""
|
||||||
|
A0034 BOSCAGLI, José pessoa 54 ""
|
||||||
|
A0035 Mendo, Ignácio F., fl. 1870 pessoa 54 ""
|
||||||
|
A0036 Krausz, Alfredo pessoa 53 ""
|
||||||
|
A0037 [s.n.] pessoa ou entidade 52 [S.N] | [s.n]
|
||||||
|
A0038 Quaas, Otto Rudolf pessoa 51 ""
|
||||||
|
A0039 Malta, Uriel, 1910-1994 pessoa 51 ""
|
||||||
|
A0040 Escola de Aeronáutica do Exército entidade coletiva 46 ""
|
||||||
|
A0041 Robin, Paul Théodore, m. 1897 pessoa 46 ""
|
||||||
|
A0042 Frisch, Albert pessoa 45 ""
|
||||||
|
A0043 Riedel, Augusto, 1836-ca.1877 pessoa 45 Riedel, Augusto
|
||||||
|
A0044 Klumb, Revert Henry, ca. 1826-ca. 1886 pessoa 44 ""
|
||||||
|
A0045 Fidanza, Felipe Augusto, ca.1847-1904 pessoa 44 Fidanza, Felipe Augusto
|
||||||
|
A0046 A. Ribeiro pessoa ou entidade 44 Ribeiro, A | Ribeiro, A.
|
||||||
|
A0047 Frond, Victor, 1821-1881 pessoa 43 Frond, Victor
|
||||||
|
A0048 Rodrigues & C°. Editores e Proprietários pessoa ou entidade 39 ""
|
||||||
|
A0049 Justa, O pessoa 38 ""
|
||||||
|
A0050 Ribeiro, Antônio Caetano da Costa pessoa 38 ""
|
||||||
|
A0051 Maison Chic pessoa ou entidade 37 ""
|
||||||
|
A0052 Musso, Luiz pessoa 37 ""
|
||||||
|
A0053 Musso & Cia entidade coletiva 37 ""
|
||||||
|
A0054 Paul Erbe pessoa ou entidade 36 ""
|
||||||
|
A0055 Guimarães, José Ferreira, 1841-1924 pessoa 36 Guimarães, José Ferreira
|
||||||
|
A0056 Horácio Coelho pessoa ou entidade 35 ""
|
||||||
|
A0057 Prugner, Gustavo pessoa 35 ""
|
||||||
|
A0058 Stahl & Cia entidade coletiva 35 ""
|
||||||
|
A0059 Teixeira, José pessoa 35 José Teixeira | Teixeira, José,
|
||||||
|
A0060 Phototypia A. Ribeiro pessoa ou entidade 33 ""
|
||||||
|
A0061 Photo Lindemann &Cª entidade coletiva 31 ""
|
||||||
|
A0062 Malta, Aristógiton, 1904-1954 pessoa 31 Malta, Aristógiton
|
||||||
|
A0063 Mulock, Benjamin Robert, 1829-1863 pessoa 31 ""
|
||||||
|
A0064 Silva, Pedro Gonsalves da pessoa 31 ""
|
||||||
|
A0065 Christiano Junior pessoa ou entidade 30 ""
|
||||||
|
A0066 Thomaz Farkas (Autoria) pessoa ou entidade 28 Thomaz Farkas
|
||||||
|
A0067 Ribeyrolles, Charles, 1812-1860 pessoa 28 ""
|
||||||
|
A0068 Vianna, José Baptista Barreira pessoa 28 ""
|
||||||
|
A0069 Christiano Junior, 1830-1902 pessoa 28 ""
|
||||||
|
A0070 Tondella, Manoel pessoa 28 ""
|
||||||
|
A0071 Amoretty, Augusto, 1845-1906 pessoa 26 Amoretty, Augusto
|
||||||
|
A0072 Huebner, George pessoa 26 ""
|
||||||
|
A0073 Vedani, Camillo pessoa 25 ""
|
||||||
|
A0074 Manuel, F. (Frédéric) pessoa 25 ""
|
||||||
|
A0075 Ferreira, Antonio Luiz pessoa 24 ""
|
||||||
|
A0076 Martins, Henrique pessoa 24 ""
|
||||||
|
A0077 Huber, Jacques (1867-1914) pessoa 24 Huber, Jacques | Jacques Huber
|
||||||
|
A0078 Julien Mandel (1893 - 1961) pessoa ou entidade 23 ""
|
||||||
|
A0079 Menezes, J pessoa 23 ""
|
||||||
|
A0080 Dietze, Albert Richard, fl. 1869 pessoa 22 ""
|
||||||
|
A0081 Parente, Nicola Maria pessoa 22 ""
|
||||||
|
A0082 Abrahão, Benjamin pessoa 22 ""
|
||||||
|
A0083 Henschel & Benque pessoa ou entidade 21 ""
|
||||||
|
A0084 Villela, João Ferreira, fl. 1861-1880 pessoa 21 Villela, João Ferreira
|
||||||
|
A0085 Photo Lopes Rio entidade coletiva 20 ""
|
||||||
|
A0086 Oswaldo Cruz pessoa ou entidade 20 Cruz, Oswaldo
|
||||||
|
A0087 Casa Leuzinger entidade coletiva 20 ""
|
||||||
|
A0088 Alkmim, Chichico pessoa 20 ""
|
||||||
|
A0089 Queiroz, Anastacio pessoa 20 ""
|
||||||
|
A0090 Lunara pessoa ou entidade 20 ""
|
||||||
|
A0091 Hees, Pedro, 1841-1880 pessoa 19 ""
|
||||||
|
A0092 Ayres, Joaquim pessoa 19 ""
|
||||||
|
A0093 José Louro pessoa ou entidade 19 ""
|
||||||
|
A0094 Preising, Theodor pessoa 18 ""
|
||||||
|
A0095 IBGE pessoa ou entidade 18 ""
|
||||||
|
A0096 Garbe, Walter pessoa 17 ""
|
||||||
|
A0097 Provável Uriel Malta pessoa ou entidade 16 ""
|
||||||
|
A0098 Thiele & Kollien pessoa ou entidade 16 ""
|
||||||
|
A0099 Pacheco, Bernardo José pessoa 16 ""
|
||||||
|
A0100 Christiano Junior E Pacheco pessoa ou entidade 16 ""
|
||||||
|
A0101 Mascarenhas, Therezio pessoa 16 ""
|
||||||
|
A0102 Photo Mortimer entidade coletiva 15 ""
|
||||||
|
A0103 Piereck, Louis, 1880-1931 pessoa 15 Piereck, Louis
|
||||||
|
A0104 Instituto de Expansão Comercial entidade coletiva 15 ""
|
||||||
|
A0105 Lobo, Antônio Araújo de Souza; Oliveira, Antônio Barbosa pessoa 15 ""
|
||||||
|
A0106 Trindade, J. S pessoa 14 ""
|
||||||
|
A0107 Oficina de Paulo Robin entidade coletiva 14 ""
|
||||||
|
A0108 H&J Tourte Éditeurs entidade coletiva 14 ""
|
||||||
|
A0109 Corrêa, J. A pessoa 14 ""
|
||||||
|
A0110 Bippus, Carlos pessoa 13 ""
|
||||||
|
A0111 Papelaria e Typographia Botelho pessoa ou entidade 13 ""
|
||||||
|
A0112 [sem autor] pessoa ou entidade 13 ""
|
||||||
|
A0113 João Stamato pessoa ou entidade 13 ""
|
||||||
|
A0114 Photographia Allemã entidade coletiva 12 Photographia Allemã (Firma)
|
||||||
|
A0115 Silva, Pio pessoa 12 ""
|
||||||
|
A0116 Benoist, Philippe, 1813-1905 pessoa 12 ""
|
||||||
|
A0117 LTM (Firma) pessoa ou entidade 12 LTM
|
||||||
|
A0118 Fidanza, Filipe Augusto, fl. 1861-1920 pessoa 12 ""
|
||||||
|
A0119 Tondella, Manoel, Photografia Tondella pessoa 12 ""
|
||||||
|
A0120 Garcia, F pessoa 11 ""
|
||||||
|
A0121 Subcomissão de Estudos dos Portos de Fortaleza e Camocim (CE) pessoa ou entidade 11 ""
|
||||||
|
A0122 Mulock, Benjamin pessoa 11 ""
|
||||||
|
A0123 Christiano Jr. & Pacheco pessoa ou entidade 11 ""
|
||||||
|
A0124 William Notman pessoa ou entidade 11 ""
|
||||||
|
A0125 Centennial Photographic Co pessoa ou entidade 11 ""
|
||||||
|
A0126 Boote, Samuel, 1844-1921 pessoa 11 ""
|
||||||
|
A0127 Costa, Hermina de Carvalho Menna da, 18- -19- pessoa 10 ""
|
||||||
|
A0128 Terragno, Luiz pessoa 10 ""
|
||||||
|
A0129 Joaquim Insley Pacheco (Autoria) pessoa ou entidade 10 ""
|
||||||
|
A0130 Lohse, Ernst (1873-1930) pessoa 10 ""
|
||||||
|
A0131 Bocage, Francisco du pessoa 10 ""
|
||||||
|
A0132 Lindemann, Rodolpho pessoa 10 ""
|
||||||
|
A0133 Jacottet, Louis-Julien, 1806-1880 pessoa 10 ""
|
||||||
|
A0134 Biblioteca Nacional (Brasil) entidade coletiva 10 ""
|
||||||
|
A0135 Carneiro & Gaspar pessoa ou entidade 10 ""
|
||||||
|
A0136 Editores & propriedade de Rodrigues & Co. Rua do Ouvidor, 57 pessoa 10 ""
|
||||||
|
A0137 Passos, Elysio Pereira dos pessoa 9 ""
|
||||||
|
A0138 Wessel pessoa ou entidade 9 ""
|
||||||
|
A0139 Moura, Miguel de, 1883- pessoa 9 Moura, Miguel de, n. 1883
|
||||||
|
A0140 Florence, Hercule pessoa 9 ""
|
||||||
|
A0141 Niemeyer, Louis pessoa 9 ""
|
||||||
|
A0142 The Aircraft Operating Co. Ltd pessoa ou entidade 8 ""
|
||||||
|
A0143 Hagmann, Gottfried (1874-1946) pessoa 8 ""
|
||||||
|
A0144 Goston, João pessoa 8 ""
|
||||||
|
A0145 Sorrieu, Frédéric, n. 1807 pessoa 8 ""
|
||||||
|
A0146 Champagne pessoa ou entidade 8 ""
|
||||||
|
A0147 Lima, Eudozio pessoa 8 ""
|
||||||
|
A0148 Bate E Cia entidade coletiva 8 ""
|
||||||
|
A0149 Huebner & Amaral pessoa ou entidade 8 ""
|
||||||
|
A0150 Photo Bippus entidade coletiva 8 ""
|
||||||
|
A0151 Rosen, Henrique, m. 1892 pessoa 8 ""
|
||||||
|
A0152 Peixoto, Antonio Carlos de Sampaio, m. 1914 pessoa 8 ""
|
||||||
|
A0153 King, John pessoa 7 ""
|
||||||
|
A0154 Angelo Regato (Fotógrafo) pessoa ou entidade 7 ""
|
||||||
|
A0155 Leuzinger, George, 1813-1892 pessoa 7 ""
|
||||||
|
A0156 Perez, M pessoa 7 ""
|
||||||
|
A0157 Martineau, Willian pessoa 7 ""
|
||||||
|
A0158 Musso, Luís, [? -1908] pessoa 7 ""
|
||||||
|
A0159 Carvalho, Alfredo Climaco de pessoa 7 ""
|
||||||
|
A0160 Tondella, Manoel, Photographia Tondella entidade coletiva 7 ""
|
||||||
|
A0161 Moraites, P pessoa 7 ""
|
||||||
|
A0162 Scheidemantel, Bernardo, 1834-1908 pessoa 7 ""
|
||||||
|
A0163 Affonso, José dos Santos pessoa 6 ""
|
||||||
|
A0164 G. Leuzinger & Filhos pessoa ou entidade 6 ""
|
||||||
|
A0165 Wanderley, Luiz Lavenère pessoa 6 ""
|
||||||
|
A0166 Gomes Junior pessoa ou entidade 6 ""
|
||||||
|
A0167 Destacamento de Aviação de Curitiba entidade coletiva 6 ""
|
||||||
|
A0168 Photo Bippus Rio entidade coletiva 6 ""
|
||||||
|
A0169 Photo Rotativo entidade coletiva 5 ""
|
||||||
|
A0170 Thiele pessoa ou entidade 5 ""
|
||||||
|
A0171 Silva, Paulo Bracy Gama da pessoa 5 ""
|
||||||
|
A0172 Photographia Artística de Miguel de Moura entidade coletiva 5 ""
|
||||||
|
A0173 Stahl & Wahnschaffe pessoa ou entidade 5 ""
|
||||||
|
A0174 Coutinho, Abilio pessoa 5 ""
|
||||||
|
A0175 Silva, Ezequiel pessoa 5 ""
|
||||||
|
A0176 Barza, Constantino pessoa 5 ""
|
||||||
|
A0177 Bianchi, Luis, 1876-1940 pessoa 5 ""
|
||||||
|
A0178 Lavenère, L pessoa 5 ""
|
||||||
|
A0179 J. J Oliveira, Manoel Tondella pessoa 5 ""
|
||||||
|
A0180 Lombaerts & Comp. Editores pessoa ou entidade 4 ""
|
||||||
|
A0181 Keller, Franz, 1835-1890 pessoa 4 Keller, Franz
|
||||||
|
A0182 Van Nyvel, Guimarães & C pessoa 4 ""
|
||||||
|
A0183 Silva, Arsenio da pessoa 4 ""
|
||||||
|
A0184 Büsch, Fritz pessoa 4 ""
|
||||||
|
A0185 Duruy, A. (Alexandre), fl. 1845-1881 pessoa 4 ""
|
||||||
|
A0186 Charpentier pessoa ou entidade 4 ""
|
||||||
|
A0187 Ateliers D. A. Longuet Imp. Phot pessoa ou entidade 4 ""
|
||||||
|
A0188 Ducasble, Alfredo pessoa 4 ""
|
||||||
|
A0189 Frisch, Christoph Albert, 1840-1918 pessoa 4 ""
|
||||||
|
A0190 Calcagno, Luiz Bartolomeu pessoa 4 ""
|
||||||
|
A0191 Cardoso, Antônio Lopes pessoa 4 ""
|
||||||
|
A0192 Pedro Le Houërou Photographo pessoa ou entidade 4 ""
|
||||||
|
A0193 Skarke, Fernando pessoa 4 ""
|
||||||
|
A0194 Livraria Lombaerts & C pessoa ou entidade 3 ""
|
||||||
|
A0195 Soper, Fred Lowe, 1893-1977 pessoa 3 ""
|
||||||
|
A0196 Monnerat, Roberto Mario pessoa 3 ""
|
||||||
|
A0197 Law, Henry, 1824-1900 pessoa 3 ""
|
||||||
|
A0198 Paranaguá, Francisco Vilela Barbosa, Marquês de, 1769-1846 pessoa 3 ""
|
||||||
|
A0199 Mora (Fotógrafo) pessoa ou entidade 3 ""
|
||||||
|
A0200 G. & A. Overbeck pessoa ou entidade 3 G & A Overbeck | G&A Overbeck
|
||||||
|
A0201 Glaziou, Auguste François Marie, 1833-1897 pessoa 3 ""
|
||||||
|
A0202 Cesar, Carlos pessoa 3 ""
|
||||||
|
A0203 Cunha, Silvio pessoa 3 ""
|
||||||
|
A0204 Archanjo Sobrinho pessoa ou entidade 3 ""
|
||||||
|
A0205 Lobo, A. de Barros pessoa 2 ""
|
||||||
|
A0206 Barreiros, A pessoa 2 ""
|
||||||
|
A0207 Lombaerts & Comp., Editores pessoa 2 ""
|
||||||
|
A0208 Izabel Jacintha Reeckell pessoa ou entidade 2 ""
|
||||||
|
A0209 Madame Reeckell pessoa ou entidade 2 ""
|
||||||
|
A0210 Eduardo de Los Rios pessoa ou entidade 2 ""
|
||||||
|
A0211 Photo Weiss- Estúdio/Agência entidade coletiva 2 Photo Weiss - Estúdio/Agência
|
||||||
|
A0212 Museu Aero Espacial entidade coletiva 2 ""
|
||||||
|
A0213 Soucasaux, Francisco pessoa 2 ""
|
||||||
|
A0214 Photographia Atayama entidade coletiva 2 ""
|
||||||
|
A0215 Comissão de desobstrução dos rios da Baixada Fluminense (RJ) entidade coletiva 2 ""
|
||||||
|
A0216 Dias, Bastos pessoa 2 ""
|
||||||
|
A0217 Costa, Osvaldo Gilson Fonseca, 1948 pessoa 2 ""
|
||||||
|
A0218 Campos, Augusto César Malta de, 1864-1957 pessoa 2 ""
|
||||||
|
A0219 Horacio Coppola pessoa ou entidade 2 ""
|
||||||
|
A0220 Rossi, Giulio, 1824-1884 pessoa 2 ""
|
||||||
|
A0221 Marcel Gautherot pessoa ou entidade 2 ""
|
||||||
|
A0222 Gioconda Rizzo pessoa ou entidade 2 ""
|
||||||
|
A0223 Braz pessoa ou entidade 2 ""
|
||||||
|
A0224 Laurens, J pessoa 2 ""
|
||||||
|
A0225 Laurens, Jules-Joseph-Augustin, 1825-1901 pessoa 2 ""
|
||||||
|
A0226 Bernieri, J pessoa 2 ""
|
||||||
|
A0227 Sommer, Giorgio, 1834-1914 pessoa 2 ""
|
||||||
|
A0228 Pacheco & Filho pessoa ou entidade 2 PACHECO & FILHO
|
||||||
|
A0229 Schleier J pessoa ou entidade 2 ""
|
||||||
|
A0230 Lewis, John C. A pessoa 2 ""
|
||||||
|
A0231 Moreira, Archimedes pessoa 2 ""
|
||||||
|
A0232 Vannini, N pessoa 2 ""
|
||||||
|
A0233 Fragoso, Armando pessoa 2 ""
|
||||||
|
A0234 Huberti (Fotógrafo) pessoa ou entidade 2 Huberti
|
||||||
|
A0235 Barboza, João de Almeida pessoa 2 ""
|
||||||
|
A0236 Firpo, João pessoa 2 ""
|
||||||
|
A0237 Forni, Agostino pessoa 2 ""
|
||||||
|
A0238 Trebby, Frederico pessoa 2 ""
|
||||||
|
A0239 Galeria Universal de Carlos Cesar pessoa ou entidade 2 ""
|
||||||
|
A0240 Trebby y Cia entidade coletiva 2 ""
|
||||||
|
A0241 Filgueiras, A pessoa 2 ""
|
||||||
|
A0242 Sá, Gazzi de, 1901-1981 pessoa 2 ""
|
||||||
|
A0243 Fernandes, Gonçalves, 1909-1986 pessoa 2 ""
|
||||||
|
A0244 A. Filgueiras Photo Amador entidade coletiva 2 ""
|
||||||
|
A0245 Agfa Tropex pessoa ou entidade 2 ""
|
||||||
|
A0246 Aliwu pessoa ou entidade 2 ""
|
||||||
|
A0247 Ultzmann, Robert, 1842-1889 pessoa 2 ""
|
||||||
|
A0248 Benque, Francisco e Henschel, Alberto pessoa 2 ""
|
||||||
|
A0249 Carneiro, Joaquim Feliciano Alves e Tavares pessoa 2 ""
|
||||||
|
A0250 Lobo, Antônio Araújo de Souza pessoa 2 ""
|
||||||
|
A0251 Oliveira, Antônio Barbosa pessoa 2 ""
|
||||||
|
A0252 Pinto. J pessoa ou entidade 2 ""
|
||||||
|
A0253 Ducasble, Alfredo | Fotografia Parisienne entidade coletiva 2 ""
|
||||||
|
A0254 Soucasaux, Augusto pessoa 2 ""
|
||||||
|
A0255 s/nome pessoa ou entidade 2 ""
|
||||||
|
A0256 Photographia Popular Oliveira & Tondella entidade coletiva 2 ""
|
||||||
|
A0257 Tondella, Manoel. Photografia Tondella pessoa 2 ""
|
||||||
|
A0258 Du Bocage, F., F. Du Bocage Photographia entidade coletiva 2 ""
|
||||||
|
A0259 Mello, Borges de, Photographia modelo Borges de Mello entidade coletiva 2 ""
|
||||||
|
A0260 1º Comando do Exército entidade coletiva 2 ""
|
||||||
|
A0261 Silveira, J pessoa 2 ""
|
||||||
|
A0262 Guimarães, Antonio de Oliveira pessoa 2 ""
|
||||||
|
A0263 Furne fils et H. Tournier pessoa ou entidade 2 ""
|
||||||
|
A0264 Carneiro & Smith pessoa ou entidade 2 ""
|
||||||
|
A0265 Sabino pessoa ou entidade 2 ""
|
||||||
|
A0266 Arthur e J. J. Wischral pessoa ou entidade 2 ""
|
||||||
|
A0267 A. C. da Costa Ribeiro pessoa ou entidade 2 ""
|
||||||
|
A0268 Pittigliani, Armando pessoa 2 ""
|
||||||
|
A0269 Photographia Marc Ferrez entidade coletiva 2 ""
|
||||||
|
A0270 Sobrosa Rio pessoa ou entidade 1 ""
|
||||||
|
A0271 Sobrosa, Antenor pessoa 1 ""
|
||||||
|
A0272 José Francisco Corrêa et C pessoa ou entidade 1 ""
|
||||||
|
A0273 Corrêa, José Francisco pessoa 1 ""
|
||||||
|
A0274 Castro, Jorge de pessoa 1 ""
|
||||||
|
A0275 Duarte, B. J. (Benedito Junqueira), 1910-1995 pessoa 1 ""
|
||||||
|
A0276 Vosylius, Kazys pessoa 1 ""
|
||||||
|
A0277 Leon de Rennes pessoa ou entidade 1 ""
|
||||||
|
A0278 Foto aérea Campo Marinha no Galeão entidade coletiva 1 ""
|
||||||
|
A0279 Lopes pessoa ou entidade 1 ""
|
||||||
|
A0280 Nicola Parente pessoa ou entidade 1 ""
|
||||||
|
A0281 Ferrez, Luciano (1884 - 1955) pessoa 1 ""
|
||||||
|
A0282 Jean Manzon pessoa ou entidade 1 ""
|
||||||
|
A0283 Valuos, Guilherme pessoa 1 ""
|
||||||
|
A0284 Viggiani, N pessoa 1 ""
|
||||||
|
A0285 Dutra, Olavo - Fotógrafo pessoa 1 ""
|
||||||
|
A0286 Fotógrafo: Vernaut, Benjamin pessoa 1 ""
|
||||||
|
A0287 Photographia Guimarães entidade coletiva 1 ""
|
||||||
|
A0288 E. Av. M pessoa ou entidade 1 ""
|
||||||
|
A0289 Monteiro, Augusto pessoa 1 ""
|
||||||
|
A0290 Stille, Paul pessoa 1 ""
|
||||||
|
A0291 cios e préTheodor pessoa ou entidade 1 ""
|
||||||
|
A0292 [Otto Hees?] pessoa ou entidade 1 ""
|
||||||
|
A0293 Studio Paul entidade coletiva 1 ""
|
||||||
|
A0294 Dr. Menescal pessoa ou entidade 1 ""
|
||||||
|
A0295 Rembrandt - Rio pessoa ou entidade 1 ""
|
||||||
|
A0296 Bellati, R. (Fotógrafo) pessoa 1 ""
|
||||||
|
A0297 Somlo, Tomas pessoa 1 ""
|
||||||
|
A0298 Emerico pessoa ou entidade 1 ""
|
||||||
|
A0299 Carlos Moskovics pessoa ou entidade 1 ""
|
||||||
|
A0300 Musso, Luís, m. 1908 pessoa 1 ""
|
||||||
|
A0301 Agência Nacional entidade coletiva 1 ""
|
||||||
|
A0302 Walery pessoa ou entidade 1 ""
|
||||||
|
A0303 Klumb, Henrique Revert pessoa 1 ""
|
||||||
|
A0304 Coutinho, A pessoa 1 ""
|
||||||
|
A0305 Clerget pessoa ou entidade 1 ""
|
||||||
|
A0306 Adam, Victor Jean, 1801-1866 pessoa 1 ""
|
||||||
|
A0307 Courtois, J pessoa 1 ""
|
||||||
|
A0308 Mason, Samuel J pessoa 1 ""
|
||||||
|
A0309 Bradley & Rulofson pessoa ou entidade 1 ""
|
||||||
|
A0310 H. Delie and E. Bechard pessoa ou entidade 1 ""
|
||||||
|
A0311 Noël, Alphonse Léon, 1807-1884 pessoa 1 ""
|
||||||
|
A0312 Helios (Fotógrafo) pessoa ou entidade 1 ""
|
||||||
|
A0313 Nadar, Felix, 1820-1910 pessoa 1 ""
|
||||||
|
A0314 Photographia Popular entidade coletiva 1 ""
|
||||||
|
A0315 Angerer, Ludwig, 1827-1879 pessoa 1 ""
|
||||||
|
A0316 Schoefft, O pessoa 1 ""
|
||||||
|
A0317 Mourgeon, C pessoa 1 ""
|
||||||
|
A0318 Antunes, F pessoa 1 ""
|
||||||
|
A0319 Aguiar, Francisco Marcellino de Souza, 1855-1935 pessoa 1 ""
|
||||||
|
A0320 Marc Ferrez & Filhos pessoa ou entidade 1 ""
|
||||||
|
A0321 Zaccaria, G pessoa 1 ""
|
||||||
|
A0322 Photograhia Vesuvio de Nicola Maria Parente pessoa ou entidade 1 ""
|
||||||
|
A0323 Silveira, Pedro Satyro de Souza da pessoa 1 ""
|
||||||
|
A0324 Rocha, J. C. da pessoa 1 ""
|
||||||
|
A0325 Photographia Americana de Moreira & Roltgen entidade coletiva 1 ""
|
||||||
|
A0326 Moreira & Roltgen pessoa ou entidade 1 ""
|
||||||
|
A0327 Lopes & Ca pessoa ou entidade 1 ""
|
||||||
|
A0328 Photographia Imperial de Lopes & Ca entidade coletiva 1 ""
|
||||||
|
A0329 Atelier Photograhico Hygino Soares entidade coletiva 1 ""
|
||||||
|
A0330 Nunes, Henrique, 1820-1895 pessoa 1 ""
|
||||||
|
A0331 Luys, Jules Bernard, 1828-1897 pessoa 1 ""
|
||||||
|
A0332 Wegner & Mottu pessoa ou entidade 1 ""
|
||||||
|
A0333 Brogi, Giacomo, 1822-1881 pessoa 1 ""
|
||||||
|
A0334 Con, Frederico Carlos pessoa 1 ""
|
||||||
|
A0335 Fenton, Roger, 1819-1869 pessoa 1 ""
|
||||||
|
A0336 Banchieri, Manoel pessoa 1 ""
|
||||||
|
A0337 Fratelli Alinari Fotografi pessoa ou entidade 1 ""
|
||||||
|
A0338 Photographie Technique A. Fernique pessoa ou entidade 1 ""
|
||||||
|
A0339 Typographia Imperial & Real de Vienna pessoa ou entidade 1 ""
|
||||||
|
A0340 Clairin, Georges-Jules-Victor, 1843-1919 pessoa 1 ""
|
||||||
|
A0341 Gilleta & Gilly pessoa ou entidade 1 ""
|
||||||
|
A0342 Arena, Giacomo, 1818-1906 pessoa 1 ""
|
||||||
|
A0343 Jerace, Francesco, 1854 - 1937 pessoa 1 ""
|
||||||
|
A0344 Calzolari, Icilio pessoa 1 ""
|
||||||
|
A0345 Fumeo, Pietro, 1831-1898 pessoa 1 ""
|
||||||
|
A0346 Trinquart (Fotógrafo) pessoa ou entidade 1 ""
|
||||||
|
A0347 Berthier, Paul, 1822-1912 pessoa 1 ""
|
||||||
|
A0348 Albert, Joseph, 1825-1886 pessoa 1 ""
|
||||||
|
A0349 Photographie Americaine pessoa ou entidade 1 ""
|
||||||
|
A0350 Kaun Phot pessoa ou entidade 1 ""
|
||||||
|
A0351 Mauritshuis (Haia, Holanda) pessoa 1 ""
|
||||||
|
A0352 Salentin, Hubert, 1822-1910 pessoa 1 ""
|
||||||
|
A0353 Boker, Carl, 1836-1905 pessoa 1 ""
|
||||||
|
A0354 Sonderland, F, 1836-1896 pessoa 1 ""
|
||||||
|
A0355 C. & A. Overbeck pessoa ou entidade 1 ""
|
||||||
|
A0356 Bosch, E pessoa 1 ""
|
||||||
|
A0357 Werff, Adriaen van der, 1659 - 1722 pessoa 1 ""
|
||||||
|
A0358 Gleyre, Charles, 1806-1874 pessoa 1 ""
|
||||||
|
A0359 Goupil & Cie pessoa ou entidade 1 ""
|
||||||
|
A0360 Stacey, C.A pessoa 1 ""
|
||||||
|
A0361 Draper, Henry, 1837-1882 pessoa 1 ""
|
||||||
|
A0362 Ludwig, Johann Fridrich, 1670-1752 pessoa 1 ""
|
||||||
|
A0363 Meireles, Vítor, 1832-1903 pessoa 1 ""
|
||||||
|
A0364 José da Santíssima Trindade, Bispo, 1762-1835 pessoa 1 ""
|
||||||
|
A0365 Lucarell, Mario pessoa 1 ""
|
||||||
|
A0366 Costa, Heitor da Silva, 1837-1947 pessoa 1 ""
|
||||||
|
A0367 Foto Lucarelli entidade coletiva 1 ""
|
||||||
|
A0368 Lima, José Otávio Correia, 1878-1974 pessoa 1 ""
|
||||||
|
A0369 Read, R. A pessoa 1 ""
|
||||||
|
A0370 Severino (Fotógrafo) pessoa ou entidade 1 ""
|
||||||
|
A0371 Hospe, Joseph pessoa 1 ""
|
||||||
|
A0372 Photo Lindemann entidade coletiva 1 ""
|
||||||
|
A0373 Conti, José Carlos pessoa 1 ""
|
||||||
|
A0374 Photo Studio Huberti entidade coletiva 1 ""
|
||||||
|
A0375 Boquel, Julien pessoa 1 ""
|
||||||
|
A0376 Silva, M. Nogueira da pessoa 1 ""
|
||||||
|
A0377 Hoenen, Carlos pessoa 1 ""
|
||||||
|
A0378 Fábrica de Ferro de Ipanema pessoa ou entidade 1 ""
|
||||||
|
A0379 Rio Branco, José Maria da Silva Paranhos, Barão do, 1845-1912 pessoa 1 ""
|
||||||
|
A0380 Nickelsen (Fotógrafo) pessoa ou entidade 1 ""
|
||||||
|
A0381 Lima, Antonio Mariano de, 1858-1902 pessoa 1 ""
|
||||||
|
A0382 Mello, Affonso de Oliveira pessoa 1 ""
|
||||||
|
A0383 Lavinthal, Joaquim Ferreira dos Santos pessoa 1 ""
|
||||||
|
A0384 Photo Lavinthal entidade coletiva 1 ""
|
||||||
|
A0385 Vieira, Valério, 1862-1941 pessoa 1 ""
|
||||||
|
A0386 Bate & Cia entidade coletiva 1 ""
|
||||||
|
A0387 Micheles (Fotógrafo) pessoa ou entidade 1 ""
|
||||||
|
A0388 Rochet, Louis, 1813-1878 pessoa 1 ""
|
||||||
|
A0389 Mafra, João Maximiniano pessoa 1 ""
|
||||||
|
A0390 Fleury, André Augusto de Pádua, 1830-1895 pessoa 1 ""
|
||||||
|
A0391 Faro, Gonçalo Paes de Azevedo, 1846-1900 pessoa 1 ""
|
||||||
|
A0392 Liais, Emmanuel, 1826-1900 pessoa 1 ""
|
||||||
|
A0393 Hermida Pazos, José, 1829-1921 pessoa 1 ""
|
||||||
|
A0394 Aquidabã pessoa ou entidade 1 ""
|
||||||
|
A0395 Oliveira, C. de pessoa 1 ""
|
||||||
|
A0396 Oliveira, Candido Marinho pessoa 1 ""
|
||||||
|
A0397 Satrap Photo entidade coletiva 1 ""
|
||||||
|
A0398 Agfa Brovira pessoa ou entidade 1 ""
|
||||||
|
A0399 Ferrez, Gilberto pessoa 1 ""
|
||||||
|
A0400 Boute pessoa ou entidade 1 ""
|
||||||
|
A0401 Buvelot & Prat pessoa ou entidade 1 ""
|
||||||
|
A0402 Panigai, Marco di pessoa 1 ""
|
||||||
|
A0403 David Latino & Franklin pessoa ou entidade 1 ""
|
||||||
|
A0404 Leuthold e Dursky pessoa ou entidade 1 ""
|
||||||
|
A0405 Antunes, Humberto Saraiva pessoa 1 ""
|
||||||
|
A0406 Castro pessoa ou entidade 1 ""
|
||||||
|
A0407 Comp. Lith. Hartmann-Reichenbach entidade coletiva 1 ""
|
||||||
|
A0408 Photographia Guilherme Gaensly entidade coletiva 1 ""
|
||||||
|
A0409 Papeleria Travassos pessoa ou entidade 1 ""
|
||||||
|
A0410 Phototipie Marius Bar pessoa ou entidade 1 ""
|
||||||
|
A0411 Bureu Poste pessoa ou entidade 1 ""
|
||||||
|
A0412 Edição A. Moura pessoa ou entidade 1 ""
|
||||||
|
A0413 Bureau Poste pessoa ou entidade 1 ""
|
||||||
|
A0414 Ao Cantineiro Naval pessoa ou entidade 1 ""
|
||||||
|
A0415 Henschel e Benque pessoa ou entidade 1 ""
|
||||||
|
A0416 Mello, Marcos A. de pessoa 1 ""
|
||||||
|
A0417 Soares, José Severino pessoa 1 ""
|
||||||
|
A0418 Bastos, A pessoa 1 ""
|
||||||
|
A0419 Henschel, Albert, 1827-1882 pessoa 1 ""
|
||||||
|
A0420 Bonfioti, J pessoa 1 ""
|
||||||
|
A0421 Foto Chic entidade coletiva 1 ""
|
||||||
|
A0422 Barboza, Theotonio pessoa 1 ""
|
||||||
|
A0423 Rogato, Guilherme pessoa 1 ""
|
||||||
|
A0424 Photo Skarke entidade coletiva 1 ""
|
||||||
|
A0425 Serviço Photographico de Vida Domestica entidade coletiva 1 ""
|
||||||
|
A0426 Foto Studio Gloria entidade coletiva 1 ""
|
||||||
|
A0427 Fotografia Alemã entidade coletiva 1 ""
|
||||||
|
A0428 Brady, Mathew B., ca. 1823-1896 pessoa 1 ""
|
||||||
|
A0429 Photograhia Popular Oliveira & Tondella pessoa ou entidade 1 ""
|
||||||
|
A0430 Photografia Popular Oliveira & Tondella pessoa ou entidade 1 ""
|
||||||
|
A0431 Manoel Tondella, Photografia Tondella pessoa 1 ""
|
||||||
|
A0432 Claude Lévi-Strauss pessoa ou entidade 1 ""
|
||||||
|
A0433 Monteiro,Photographie Chic Monteiro & C pessoa 1 ""
|
||||||
|
A0434 Edgard Egydio de Souza pessoa ou entidade 1 ""
|
||||||
|
A0435 S/A pessoa ou entidade 1 ""
|
||||||
|
A0436 Chapelin E Pereira pessoa ou entidade 1 ""
|
||||||
|
A0437 Poluceno & Pinho pessoa ou entidade 1 ""
|
||||||
|
A0438 <ns:Co & Pinho pessoa ou entidade 1 ""
|
||||||
|
A0439 Thiele & Kollien [?]; Photo Bippus Rio [?] entidade coletiva 1 ""
|
||||||
|
A0440 Photographia Central entidade coletiva 1 ""
|
||||||
|
A0441 Veiga, Bernardo Saturnino da pessoa 1 ""
|
||||||
|
A0442 Phototypie Berthaud pessoa ou entidade 1 ""
|
||||||
|
A0443 Marinho, P pessoa 1 ""
|
||||||
|
A0444 A. Editora entidade coletiva 1 ""
|
||||||
|
A0445 511-73, Marc pessoa 1 ""
|
||||||
|
A0446 J. Stamato pessoa ou entidade 1 ""
|
||||||
|
A0447 DADE pessoa ou entidade 1 ""
|
||||||
|
A0448 Annunciato pessoa ou entidade 1 ""
|
||||||
|
A0449 Benque pessoa ou entidade 1 ""
|
||||||
|
A0450 Chapelin pessoa ou entidade 1 ""
|
||||||
|
A0451 Scheidemantel, B pessoa 1 ""
|
||||||
|
A0452 Photo Braz Rio entidade coletiva 1 ""
|
||||||
|
A0453 Scheuenstuhl, Paulo pessoa 1 ""
|
||||||
|
A0454 Caras & Caretas pessoa ou entidade 1 ""
|
||||||
|
A0455 Leonar pessoa ou entidade 1 ""
|
||||||
|
A0456 Azevedo, J. Faria de pessoa 1 ""
|
||||||
|
A0457 Basto, F pessoa 1 ""
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,104 @@
|
|||||||
|
instituicao categoria detentor originais n
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 3928
|
||||||
|
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacional (Brasil) 1889
|
||||||
|
Museu Aeroespacial consultar o detentor Museu Aeroespacial "" 1143
|
||||||
|
Museu da Republica consultar o detentor Museu da República "" 838
|
||||||
|
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) "" 826
|
||||||
|
Museu Historico Nacional consultar o detentor Museu Histórico Nacional "" 649
|
||||||
|
Fiocruz consultar o detentor Fundação Oswaldo Cruz. Casa de Oswaldo Cruz "" 548
|
||||||
|
Instituto Moreira Salles domínio público Instituto Moreira Salles Em domínio público | Liberado para uso de natureza cultural 479
|
||||||
|
Diretoria do Patrimonio Historico e Documentacao da Marinha consultar o detentor Diretoria do Patrimônio Histórico e Documentação da Marinha "" 450
|
||||||
|
Arquivo Nacional consultar o detentor Arquivo Nacional (Brasil) "" 383
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "" 310
|
||||||
|
Arquivo Geral da Cidade do Rio de Janeiro consultar o detentor Arquivo Geral da Cidade do Rio de Janeiro "" 248
|
||||||
|
Leibniz-Institut fuer Laenderkunde, Leipzig requer autorização do detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 212
|
||||||
|
Fundacao Joaquim Nabuco consultar o detentor Fundação Joaquim Nabuco "" 189
|
||||||
|
Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro Em domínio público | Liberado para uso de natureza cultural 176
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Instituto Moreira Salles | Requer liberação de direitos de imagem junto ao detentor indicado no Copyright 172
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles 116
|
||||||
|
Museu Paraense Emilio Goeldi consultar o detentor Museu Paraense Emílio Goeldi "" 95
|
||||||
|
Escola de Ciencias Sociais (FGV CPDOC) consultar o detentor Fundação Getulio Vargas. Escola de Ciências Sociais (FGV CPDOC) "" 79
|
||||||
|
Museu da Republica consultar o detentor Flávio de Barros / Acervo Museu da República / Imagem recuperada digitalmente pelo Instituto Moreira Salles Flávio de Barros / Acervo Museu da República / Imagem recuperada digitalmente pelo Instituto Moreira Salles 68
|
||||||
|
Instituto Brasileiro de Geografia e Estatistica consultar o detentor Instituto Brasileiro de Geografia e Estatística "" 58
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | Liberado apenas para uso de natureza cultural 52
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Acervo Instituto Moreira Salles 27
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Solicitar imagem junto ao detentor dos direitos indicado no Copyright 19
|
||||||
|
Instituto Historico e Geografico Brasileiro consultar o detentor Instituto Histórico e Geográfico Brasileiro "" 17
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Dom João de Orleans e Bragança/ Instituto Moreira Salles Dom João de Orleans e Bragança/ Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 10
|
||||||
|
Instituto Historico e Geografico Brasileiro consultar o detentor Convênio Instituto Histórico e Geográfico Brasileiro / Instituto Moreira Salles Convênio Instituto Histórico e Geográfico Brasileiro / Instituto Moreira Salles 10
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Diários Associados - Rio de Janeiro/ Acervo Instituto Moreira Salles Diários Associados - Rio de Janeiro/ Acervo Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 4
|
||||||
|
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacional (Brazil) 2
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Flávio de Barros / Acervo Instituto Geográfico e Histórico da Bahia / Imagem recuperada digitalmente pelo Instituto Moreira Salles Flávio de Barros / Acervo Instituto Geográfico e Histórico da Bahia / Imagem recuperada digitalmente pelo Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 2
|
||||||
|
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca nacional (Brasil) 2
|
||||||
|
Instituto Moreira Salles domínio público Instituto Moreira Salles "Em domínio público | >
|
||||||
|
<ns:Fiera uso de natureza cultural" 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Instituto Moreira | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | ue>
|
||||||
|
</ns:FieldValue>
|
||||||
|
<ns:FieldValue uid=""{5094c229-4 no Copyright" 1
|
||||||
|
Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro /ns:omínio público | Liberado para uso de natureza cultural 1
|
||||||
|
Instituto Moreira Salles uso cultural liberado Instituto Moreira Salles "f1}"">Atual Túblico | Liberado para uso de natureza cultural" 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | lue>
|
||||||
|
ar imagem junto ao detentor dos direitos indicado no Copyright" 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 45c-5d93acdmagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles goryituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 7 circa</ns:Fiem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Leibniz-Institut fuer Laenderkunde, Leipzig consultar o detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | 969b9e69c2810518cd1da941cd001da8c71cos direitos indicado no Copyright 1
|
||||||
|
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacioanl (Brasil) 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | ns:CategoryValue>FOTOGRAFIA:COLEÇÕES DO ACERVO:COLEÇcado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | DO ACERVO:COLEÇÃOjunto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | 5daf98}"">Elaborado por Grandjean de Montigny em 1827,ado no Copyright" 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles egor | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Biblioteca Nacional consultar o detentor Bilbioteca Nacional (Brasil) Bilbioteca Nacional (Brasil) 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles S:Tratuto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | s:FieldValue uid=""{48b5771a-326a-42ce-9f83-0b9c225178e4}"">
|
||||||
|
<ns:Ent" 1
|
||||||
|
Instituto Moreira Salles uso cultural liberado Instituto Moreira Salles <ns:Eio público | Liberado para uso de natureza cultural 1
|
||||||
|
Diretoria do Patrimonio Historico e Documentacao da Marinha consultar o detentor Diretoria do Patrimônio Histórico e Documentação da Marinha DPHDM 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | acbe6cdb314}"">
|
||||||
|
<nto ao detentor dos direitos indicado no Copyright" 1
|
||||||
|
Instituto Moreira Salles domínio público Instituto Moreira Salles "Em domínio público | b6979}"">sp: 13,0 x 18,0 cm</ns:ultural" 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 4bb3d1a793c4ba619352175229f38606or dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles domínio público Instituto Moreira Salles "Em domínio público | lue>
|
||||||
|
</ns:FieldValue>
|
||||||
|
<na cultural" 1
|
||||||
|
Instituto Moreira Salles domínio público Instituto Moreira Salles Em domínio público | ns:F 1
|
||||||
|
Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro Em domínio público | s:Fi 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | f05ea53de7866ce3bcunto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Acervo Instituto Moreira Salles | Liberado apenas para uso de natureza cultural 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 0dlicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | 7094}"">
|
||||||
|
<ns:EnumValue id=""64"">Ferrez, reitos indicado no Copyright" 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | terna</ns:CategoryValue>
|
||||||
|
<ns:CategoryValitos indicado no Copyright" 1
|
||||||
|
Museu da Republica consultar o detentor Flávio de Barros/ Álbum Canônico Virtual de Canudos/ Acervo Instituto Moreira Salles/ Copyright Museu da República Flávio de Barros/ Álbum Canônico Virtual de Canudos/ Acervo Instituto Moreira Salles/ Copyright Museu da República 1
|
||||||
|
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioeca Nacional (Brasil) 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 90d9-22fa7imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | ue>
|
||||||
|
<ns:CategoryValue>FOetentor dos direitos indicado no Copyright" 1
|
||||||
|
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacional 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles <ns:EnumValue idlles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacioinal (Brasil) 1
|
||||||
|
Biblioteca Nacional consultar o detentor Bilioteca Nacional (Brasil) Bilioteca Nacional (Brasil) 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Fiel | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | aleceu no Rio de Janeiro em 1923.</nss direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | elho</tar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro "Em domínio público | >
|
||||||
|
<ns:CategoryValue>FOTOGRAFIA:ARQU" 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles PALAVRAS-CHAVE:La Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Leibniz-Institut fuer Laenderkunde, Leipzig consultar o detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | c679ac249ad19699ccf88058daf8075965819afe7ba6b7772b961b58119c760bd0f6c 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Pessoas</ns:CategoryVaes | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 6572455391487c6de95a8490303151ec19e40cd302bc659533d2a2949624Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 074007300000000006a00000001554368720055003a007b003900380063006pyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | b4d39078a18217be451480f38ed41348631ea3208cd4aos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles 80stituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Biblioteca Nacional consultar o detentor Bibioteca Nacional (Brasil) Bibioteca Nacional (Brasil) 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles oryValue>FOTOGira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Leibniz-Institut fuer Laenderkunde, Leipzig requer autorização do detentor Leibniz-Institut für Länderkunde 9b3 | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles {5stituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | 109"">Ltar imagem junto ao detentor dos direitos indicado no Copyright" 1
|
||||||
|
Instituto Moreira Salles requer autorização do detentor ro em 1923.oreira Salles ro em 1923.oreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
|
||||||
|
Leibniz-Institut fuer Laenderkunde, Leipzig consultar o detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | 3db9 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | dValue>
|
||||||
|
<ns:FieldValue uid=""{8b30dbb7-97ef-4a5c-8a40-18no Copyright" 1
|
||||||
|
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | EnumValue id=""160"">nto ao detentor dos direitos indicado no Copyright" 1
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
|||||||
|
instituicao dc_type genero especie suporte presumida n
|
||||||
|
Instituto Moreira Salles Fotografia/ Papel iconográfico fotografia papel false 2633
|
||||||
|
Biblioteca Nacional Fotografia iconográfico fotografia "" false 1852
|
||||||
|
Instituto Moreira Salles Negativo/ Vidro iconográfico negativo fotográfico vidro false 1304
|
||||||
|
Museu Aeroespacial "" iconográfico fotografia "" true 1143
|
||||||
|
Museu da Republica "" iconográfico fotografia "" true 907
|
||||||
|
Instituto Moreira Salles Diapositivo/ Vidro iconográfico diapositivo vidro false 655
|
||||||
|
Museu Historico Nacional "" iconográfico fotografia "" true 649
|
||||||
|
Fiocruz "" iconográfico fotografia "" true 548
|
||||||
|
Diretoria do Patrimonio Historico e Documentacao da Marinha "" iconográfico fotografia "" true 450
|
||||||
|
Arquivo Nacional "" iconográfico fotografia "" true 383
|
||||||
|
Biblioteca Nacional "" iconográfico fotografia "" true 371
|
||||||
|
Biblioteca Nacional Manuscrito textual manuscrito "" false 294
|
||||||
|
Instituto Moreira Salles "" iconográfico fotografia "" true 263
|
||||||
|
Arquivo Geral da Cidade do Rio de Janeiro "" iconográfico fotografia "" true 248
|
||||||
|
Leibniz-Institut fuer Laenderkunde, Leipzig Fotografia/ Papel iconográfico fotografia papel false 206
|
||||||
|
Fundacao Joaquim Nabuco "" iconográfico fotografia "" true 189
|
||||||
|
Instituto Historico e Geografico Brasileiro Fotografia/ Papel iconográfico fotografia papel false 179
|
||||||
|
Biblioteca Nacional Livro bibliográfico livro "" false 127
|
||||||
|
Instituto Moreira Salles Reprodução Fotomecânica/ Papel iconográfico reprodução fotomecânica papel false 124
|
||||||
|
Museu Paraense Emilio Goeldi "" iconográfico fotografia "" true 95
|
||||||
|
Escola de Ciencias Sociais (FGV CPDOC) "" iconográfico fotografia "" true 79
|
||||||
|
Biblioteca Nacional Gravura iconográfico gravura "" false 61
|
||||||
|
Instituto Brasileiro de Geografia e Estatistica "" iconográfico fotografia "" true 58
|
||||||
|
Instituto Moreira Salles Fotografia iconográfico fotografia "" false 55
|
||||||
|
Instituto Moreira Salles NEGATIVO/ Vidro iconográfico negativo fotográfico vidro false 50
|
||||||
|
Instituto Moreira Salles FOTOGRAFIA/ Papel iconográfico fotografia papel false 41
|
||||||
|
Instituto Historico e Geografico Brasileiro "" iconográfico fotografia "" true 27
|
||||||
|
Instituto Moreira Salles Negativo flexível iconográfico negativo fotográfico flexível false 16
|
||||||
|
Biblioteca Nacional Álbum iconográfico álbum fotográfico "" false 15
|
||||||
|
Leibniz-Institut fuer Laenderkunde, Leipzig Negativo/ Vidro iconográfico negativo fotográfico vidro false 9
|
||||||
|
Instituto Moreira Salles Outros iconográfico fotografia "" true 4
|
||||||
|
Instituto Moreira Salles NEGATIVO flexível iconográfico negativo fotográfico flexível false 4
|
||||||
|
Biblioteca Nacional Desenho iconográfico desenho "" false 3
|
||||||
|
Biblioteca Nacional Artigo de Periódico bibliográfico periódico "" false 2
|
||||||
|
Instituto Moreira Salles DIAPOSITIVO/ Vidro iconográfico diapositivo vidro false 2
|
||||||
|
Instituto Moreira Salles REPRODUÇÃO FOTOMECÂNICA/ Papel iconográfico reprodução fotomecânica papel false 1
|
||||||
|
Instituto Moreira Salles Fotografia/ Papel resinado iconográfico fotografia papel resinado false 1
|
||||||
|
Biblioteca Nacional Vista panorâmica iconográfico fotografia "" false 1
|
||||||
|
Instituto Moreira Salles da197f8b9ebf4apel iconográfico fotografia "" true 1
|
||||||
|
Instituto Moreira Salles Negativo/ Papel iconográfico negativo fotográfico papel false 1
|
||||||
|
Instituto Moreira Salles Fotografia/ Tecido iconográfico fotografia tecido false 1
|
||||||
|
Leibniz-Institut fuer Laenderkunde, Leipzig bee2e5afia/ Papel iconográfico fotografia "" true 1
|
||||||
|
Instituto Moreira Salles 481b791d7a/ Papel iconográfico fotografia "" true 1
|
||||||
|
Instituto Moreira Salles 3ceegrafia/ Papel iconográfico fotografia "" true 1
|
||||||
|
Instituto Moreira Salles """{frodução Fotomecânica/ Papel" iconográfico fotografia "" true 1
|
||||||
|
Instituto Moreira Salles 4778-rafia/ Papel iconográfico fotografia "" true 1
|
||||||
|
Instituto Moreira Salles yValue>FOa/ Papel iconográfico fotografia "" true 1
|
||||||
|
Instituto Moreira Salles 93gativo/ Vidro iconográfico fotografia "" true 1
|
||||||
|
Diretoria do Patrimonio Historico e Documentacao da Marinha Fotografia iconográfico fotografia "" false 1
|
||||||
|
@@ -0,0 +1,6 @@
|
|||||||
|
# Nível 0 — acervo da entidade custodiadora
|
||||||
|
|
||||||
|
## 3.1 Âmbito e conteúdo
|
||||||
|
|
||||||
|
Cópias digitais de acervos fotográficos brasileiros, mantidas para preservação
|
||||||
|
e consulta. Hoje, uma coleção: a Brasiliana Fotográfica (BR RJXYZ.BF).
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
# Nível 1 — Coleção Brasiliana Fotográfica (cópia digital)
|
||||||
|
|
||||||
|
Cada seção `## N.N` preenche o elemento de mesmo número da NOBRADE no nível 1.
|
||||||
|
Lido por `pipeline/nobrade/montar.py`. Seções vazias são ignoradas.
|
||||||
|
|
||||||
|
## 2.2 História administrativa/Biografia
|
||||||
|
|
||||||
|
Coleção formada em setembro de 2026 para preservar uma cópia integral da
|
||||||
|
Brasiliana Fotográfica, portal criado em 2015 pela Biblioteca Nacional e pelo
|
||||||
|
Instituto Moreira Salles para reunir, num único repositório DSpace, acervos
|
||||||
|
fotográficos dos séculos XIX e XX de instituições brasileiras e estrangeiras.
|
||||||
|
O eixo temático é o do próprio portal: a fotografia produzida no Brasil ou
|
||||||
|
sobre o Brasil.
|
||||||
|
|
||||||
|
## 2.3 História arquivística
|
||||||
|
|
||||||
|
Natureza da acumulação: coleção. Reunida intencionalmente por cópia digital,
|
||||||
|
sem transferência de custódia dos originais, que permanecem nas 15
|
||||||
|
instituições de origem (5.1 de cada dossiê).
|
||||||
|
|
||||||
|
A Biblioteca Nacional foi consultada antes da coleta. Confirmou que o material
|
||||||
|
é público e que não tinha equipe técnica para fornecer um dump; a coleta por
|
||||||
|
raspagem, em ritmo cortês e com identificação, foi o caminho combinado.
|
||||||
|
|
||||||
|
Intervenções técnicas, em ordem:
|
||||||
|
|
||||||
|
1. Metadados (setembro de 2026): 13.060 itens enumerados pelo índice de
|
||||||
|
navegação ao vivo do DSpace (`browse?type=title`), comunidade a comunidade.
|
||||||
|
O sitemap oficial, gerado em abril de 2019, lista só cerca de 41% do acervo
|
||||||
|
e foi descartado como fonte. O registro completo de cada item
|
||||||
|
(`?show=full`) foi colhido a partir de um navegador real, porque o
|
||||||
|
Cloudflare do site bloqueia automação.
|
||||||
|
2. Arquivos: para cada item foi guardado o bitstream do DSpace como imagem de
|
||||||
|
preservação (maior resolução disponível; digitalizações de até 34,7 MB), a
|
||||||
|
miniatura gerada pelo DSpace e, quando existia, a cópia legada do
|
||||||
|
objdigital.bn.br, de resolução bem menor, guardada como procedência. 115
|
||||||
|
itens tinham de 2 a 6 imagens reais, e todas foram guardadas (nível 5).
|
||||||
|
3. Cada arquivo foi baixado, somado (SHA-256), enviado ao bucket e apagado do
|
||||||
|
disco local. O ledger do envio é a fonte dos elementos 5.2 e 1.5 de cada
|
||||||
|
dossiê.
|
||||||
|
4. Coleta concluída em 13 de setembro de 2026.
|
||||||
|
|
||||||
|
Sinistros e dispersões: 69 itens não têm imagem de preservação porque a origem
|
||||||
|
responde HTTP 500 ao bitstream, embora a página do item responda 200. Foram
|
||||||
|
feitas três rodadas de tentativa. Nesses itens a cópia guarda só a miniatura
|
||||||
|
(ver 6.1 de cada um e `errors.md`). Arquivos que chegaram corrompidos ou que
|
||||||
|
eram pirâmides de blocos (DZI) em vez de imagem foram rejeitados pelo ledger e
|
||||||
|
refeitos.
|
||||||
|
|
||||||
|
## 2.4 Procedência
|
||||||
|
|
||||||
|
Brasiliana Fotográfica (https://brasilianafotografica.bn.gov.br/), repositório
|
||||||
|
DSpace 4.2 mantido pela Biblioteca Nacional, handles `20.500.12156.1/*`. Cópia
|
||||||
|
obtida por raspagem combinada com a Biblioteca Nacional, 9–13 de setembro de 2026.
|
||||||
|
Inclui também os 636 posts do blog editorial do portal, usados em 5.4 e nas
|
||||||
|
fontes das autoridades.
|
||||||
|
|
||||||
|
## 3.2 Avaliação, eliminação e temporalidade
|
||||||
|
|
||||||
|
Nenhum item foi eliminado: a coleção é uma cópia integral. Entre as versões de
|
||||||
|
um mesmo arquivo foi mantida a de maior resolução (preservação), e a cópia
|
||||||
|
legada do objdigital foi guardada como procedência, nunca como substituta.
|
||||||
|
Arquivos rejeitados na validação (corrompidos, em formato de blocos, ou de
|
||||||
|
licença em vez de imagem) foram descartados e registrados no ledger.
|
||||||
|
|
||||||
|
## 3.3 Incorporações
|
||||||
|
|
||||||
|
Não há incorporações previstas. Uma nova coleta completa pode ser feita se a
|
||||||
|
origem publicar itens novos; o `fetched_at` de cada dossiê permite comparar.
|
||||||
|
|
||||||
|
## 3.4 Sistema de arranjo
|
||||||
|
|
||||||
|
Arranjo em quatro níveis abaixo da coleção:
|
||||||
|
|
||||||
|
- seção (nível 2): instituição de origem, conforme a comunidade do DSpace;
|
||||||
|
- série (nível 3): coleção ou fundo de origem, normalizado a partir de
|
||||||
|
`dc.source`. Itens sem coleção identificável ficam na série AV (Avulsos) da
|
||||||
|
seção;
|
||||||
|
- dossiê (nível 4): um item do DSpace, identificado pelo número do handle;
|
||||||
|
- item documental (nível 5): cada imagem do dossiê, numerada `01`, `02`…
|
||||||
|
|
||||||
|
Código de referência: `BR RJXYZ.BF.<seção>.<série>.<handle>.<imagem>`.
|
||||||
|
|
||||||
|
## 4.2 Condições de reprodução
|
||||||
|
|
||||||
|
Cada dossiê traz em 4.2 a condição informada pela origem (domínio público, uso
|
||||||
|
cultural liberado, reprodução sujeita a autorização, ou não informada) e o
|
||||||
|
detentor dos direitos. As instituições têm políticas distintas: a decisão de
|
||||||
|
reproduzir é item a item, junto ao detentor indicado.
|
||||||
|
|
||||||
|
## 4.3 Idioma
|
||||||
|
|
||||||
|
Descrições em português. Há legendas e títulos originais em francês, inglês,
|
||||||
|
latim, alemão, italiano, ucraniano e húngaro, registrados em 4.3 de cada
|
||||||
|
dossiê (ISO 639-2).
|
||||||
|
|
||||||
|
## 4.4 Características físicas e requisitos técnicos
|
||||||
|
|
||||||
|
Arquivos digitais JPEG (com alguns PNG e PDF), abertos em qualquer visualizador
|
||||||
|
de imagem. Os maiores passam de 8.000 px no lado maior. Nenhum requisito
|
||||||
|
especial.
|
||||||
|
|
||||||
|
## 4.5 Instrumentos de pesquisa
|
||||||
|
|
||||||
|
- Mural 3D navegável com busca e filtros: https://xn--2dk.xyz/brasiliana/
|
||||||
|
- Esta descrição em EAD 3: `descricao/ead/brasiliana.xml` (no bucket, em
|
||||||
|
`s3://brasiliana/descricao/`).
|
||||||
|
- Catálogo bruto em Dublin Core: `s3://brasiliana/catalogo.jsonl`.
|
||||||
|
|
||||||
|
## 5.1 Existência e localização dos originais
|
||||||
|
|
||||||
|
Os originais pertencem às 15 instituições de origem, listadas como seções. Cada
|
||||||
|
dossiê indica a instituição, o endereço do item na Brasiliana Fotográfica e,
|
||||||
|
quando a origem publica, o código ou a notação da instituição.
|
||||||
|
|
||||||
|
## 6.2 Notas gerais
|
||||||
|
|
||||||
|
Os valores dos metadados de origem que foram normalizados (datas, direitos,
|
||||||
|
nomes) estão preservados em 6.2 de cada dossiê e no `catalogo.jsonl`. Valores
|
||||||
|
visivelmente corrompidos na origem, com fragmentos de XML ou hash no lugar do
|
||||||
|
texto, foram desconsiderados e anotados.
|
||||||
|
|
||||||
|
## 7.1 Nota do arquivista
|
||||||
|
|
||||||
|
Descrição gerada automaticamente a partir dos metadados Dublin Core colhidos,
|
||||||
|
por `pipeline/nobrade`, com tabelas de revisão em `descricao/revisao/`.
|
||||||
|
Fontes: registros `?show=full` do DSpace, ledger de envio do bucket, blog da
|
||||||
|
Brasiliana Fotográfica. Responsável: rafapolo.
|
||||||
|
|
||||||
|
## 8.1 Pontos de acesso e indexação de assuntos
|
||||||
|
|
||||||
|
Pontos de acesso: título (1.2), autores em forma autorizada ISAAR(CPF)
|
||||||
|
(`descricao/autoridades.jsonl`, com as variantes como remissivas), data
|
||||||
|
tópica e lugares (`dc.coverage`), assuntos (`dc.subject`, com os termos em
|
||||||
|
português separados das traduções inglesas) e período (ISO 8601-2). Os
|
||||||
|
assuntos seguem o vocabulário da origem, sem controle adicional nesta versão.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção AGCRJ
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Arquivo público do município do Rio de Janeiro. O conjunto inclui a Coleção Augusto Malta, fotógrafo oficial da prefeitura no início do século XX.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção AN
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Arquivo Nacional, Rio de Janeiro, órgão central do Sistema de Gestão de Documentos de Arquivo da administração pública federal, criado em 1838.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção BN
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Biblioteca nacional do Brasil, com origem na Real Biblioteca trazida de Portugal em 1810, no Rio de Janeiro. Mantém a Brasiliana Fotográfica. A maior parte do seu conjunto aqui vem da Coleção Thereza Christina Maria, doada por D. Pedro II.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção COC
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Casa de Oswaldo Cruz, unidade da Fundação Oswaldo Cruz dedicada à memória e à história das ciências e da saúde. O conjunto vem de fundos institucionais e pessoais ligados à saúde pública.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção CPDOC
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Centro de Pesquisa e Documentação de História Contemporânea do Brasil, da Fundação Getulio Vargas, Rio de Janeiro, criado em 1973. Guarda arquivos pessoais de figuras da vida pública brasileira.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção DPHDM
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Órgão da Marinha do Brasil responsável pelo patrimônio histórico e documental naval. O conjunto é formado sobretudo por álbuns fotográficos de viagens, escolas de aprendizes marinheiros e aviação naval.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção FUNDAJ
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Fundação Joaquim Nabuco, instituição federal de pesquisa sediada no Recife. O conjunto documenta sobretudo Pernambuco e o Nordeste.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção IBGE
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Instituto Brasileiro de Geografia e Estatística. O conjunto documenta municípios brasileiros, trabalhos geográficos de campo e eventos institucionais.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção IFL
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Leibniz-Institut für Länderkunde, instituto de pesquisa em geografia regional em Leipzig, Alemanha. Participa da Brasiliana Fotográfica por convênio com o Instituto Moreira Salles.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção IHGB
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Instituto Histórico e Geográfico Brasileiro, fundado em 1838 no Rio de Janeiro. Participa da Brasiliana Fotográfica por convênio com o Instituto Moreira Salles.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção IMS
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Instituição cultural privada criada em 1992, no Rio de Janeiro, pela família Moreira Salles. Seu acervo fotográfico, com coleções como Gilberto Ferrez, Mestres do Século XIX e Pedro Corrêa do Lago, é o maior conjunto da Brasiliana Fotográfica, da qual é parceira fundadora com a Biblioteca Nacional.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção MHN
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Museu Histórico Nacional, Rio de Janeiro, criado em 1922. O conjunto inclui as coleções Miguel Calmon e Juan Gutierrez.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção MPEG
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Museu Paraense Emílio Goeldi, instituição de pesquisa sediada em Belém, dedicada ao estudo da Amazônia.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção MR
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Museu instalado no Palácio do Catete, Rio de Janeiro, antiga sede da Presidência da República. O conjunto inclui as coleções Família Passos, Getúlio Vargas, Nilo Peçanha e as fotografias de Flávio de Barros sobre Canudos.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seção MUSAL
|
||||||
|
|
||||||
|
Rascunho — conferir antes de publicar.
|
||||||
|
|
||||||
|
## 2.2 História administrativa
|
||||||
|
|
||||||
|
Museu da Força Aérea Brasileira, no Campo dos Afonsos, Rio de Janeiro. O conjunto reúne sobretudo fotografias aéreas e de aviação militar das décadas de 1920 e 1930.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Textos das séries (nível 3)
|
||||||
|
|
||||||
|
Um arquivo `<SEÇÃO>.<SÉRIE>.md` (ex.: `IMS.GF.md`) com seções `## 2.2`,
|
||||||
|
`## 3.1` ou `## 3.4` substitui o texto gerado para aquela série. Sem arquivo,
|
||||||
|
o 3.1 é o resumo automático: quantidade, datas-limite, principais autores e
|
||||||
|
lugares. Os códigos das séries estão em `../revisao/series.tsv`.
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
"""python -m nobrade (de dentro de pipeline/)
|
||||||
|
|
||||||
|
Gera a descrição NOBRADE completa em descricao/: unidades, autoridades,
|
||||||
|
tabelas de revisão, pendências, EAD 3, EAC-CPF e CSV do AtoM, e valida os XML
|
||||||
|
contra os XSD de nobrade/xsd/ quando o xmllint está disponível.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from collections import defaultdict
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from . import exporta, montar, valida
|
||||||
|
from .config import SAIDA
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print('montando unidades…', flush=True)
|
||||||
|
unidades, aut = montar.monta()
|
||||||
|
lista = sorted(unidades.values(), key=lambda u: (u['nivel'], u['id']))
|
||||||
|
lista = [{k: v for k, v in u.items() if not k.startswith('_') and v is not None} for u in lista]
|
||||||
|
pend = valida.valida(lista)
|
||||||
|
print(f'{len(lista)} unidades, {len(aut.registros)} autoridades, {pend} pendências obrigatórias')
|
||||||
|
|
||||||
|
print('exportando EAD 3, EAC-CPF e AtoM…', flush=True)
|
||||||
|
exporta.ead(lista, aut.registros)
|
||||||
|
usos = defaultdict(list)
|
||||||
|
for u in lista:
|
||||||
|
if u['nivel'] == 4:
|
||||||
|
for p in u['2.1']:
|
||||||
|
if p.get('id'):
|
||||||
|
usos[p['id']].append(u['id'])
|
||||||
|
exporta.eac(list(aut.registros.values()), usos)
|
||||||
|
exporta.atom(lista)
|
||||||
|
|
||||||
|
if shutil.which('xmllint') and '--sem-xsd' not in sys.argv:
|
||||||
|
xsd = Path(__file__).parent / 'xsd'
|
||||||
|
r = subprocess.run(['xmllint', '--noout', '--huge', '--schema', xsd / 'ead3.xsd',
|
||||||
|
SAIDA / 'ead' / 'brasiliana.xml'], capture_output=True, text=True)
|
||||||
|
print('EAD 3:', (r.stderr.strip().splitlines() or ['?'])[-1])
|
||||||
|
eacs = sorted((SAIDA / 'eac').glob('*.xml'))
|
||||||
|
r = subprocess.run(['xmllint', '--noout', '--schema', xsd / 'cpf.xsd', *eacs],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
falhas = [x for x in r.stderr.splitlines() if 'fails to validate' in x or 'error' in x.lower()]
|
||||||
|
print(f'EAC-CPF: {len(eacs)} arquivos, {len(falhas)} com erro')
|
||||||
|
for x in falhas[:10]:
|
||||||
|
print(' ', x)
|
||||||
|
return 1 if pend else 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
"""Registros de autoridade (ISAAR(CPF)) para produtores — elemento 2.1 e 8.1.
|
||||||
|
|
||||||
|
Junta as grafias de `dc.contributor` ("Malta, Augusto", "Malta, Augusto,
|
||||||
|
1864-1957", "Marc Ferrez" e "Ferrez, Marc") numa forma autorizada, com as
|
||||||
|
variantes como remissivas (proc. 8.1.4).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import unicodedata
|
||||||
|
from collections import Counter, defaultdict
|
||||||
|
|
||||||
|
ANONIMO = re.compile(r'(?i)^\s*(an[oô]nimo|autoria n[aã]o identificada|s/\s*autor|sem autor|desconhecid[oa]|'
|
||||||
|
r'n[aã]o identificad[oa]|autor n[aã]o identificado|autor desconhecido)\s*\.?$')
|
||||||
|
COLETIVA = re.compile(r'(?i)\b(escola|officina|oficina|photographia|fotografia|photo|foto|studio|est[uú]dio|atelier|'
|
||||||
|
r'casa|companhia|cia\.?|museu|instituto|minist[eé]rio|servi[cç]o|diretoria|departamento|'
|
||||||
|
r'comiss[aã]o|biblioteca|arquivo|editora|lith|litografia|tipografia|typ|&|irm[aã]os|'
|
||||||
|
r'sociedade|empresa|jornal|revista|ag[eê]ncia|governo|prefeitura|marinha|ex[eé]rcito|'
|
||||||
|
r'for[cç]a|aeron[aá]utica|avia[cç][aã]o|universidade|fundação)\b')
|
||||||
|
DATAS = re.compile(r',?\s*((?:ca\.\s*|fl\.\s*|m\.\s*|n\.\s*)?\d{4}\??(?:\s*-\s*(?:ca\.\s*)?\d{0,4}\??)?)\.?\s*$')
|
||||||
|
PARTICULAS = {'de', 'da', 'do', 'das', 'dos', 'e', 'von', 'van', 'du', 'del', 'di'}
|
||||||
|
|
||||||
|
|
||||||
|
def _chave(s: str) -> str:
|
||||||
|
s = ''.join(c for c in unicodedata.normalize('NFD', s.lower()) if unicodedata.category(c) != 'Mn')
|
||||||
|
s = re.sub(r'\(.*?\)', '', s)
|
||||||
|
return re.sub(r'[^\w,]+', ' ', s).strip(' ,')
|
||||||
|
|
||||||
|
|
||||||
|
def _separa_datas(nome: str) -> tuple[str, str | None]:
|
||||||
|
nome = nome.strip().rstrip('.')
|
||||||
|
if m := DATAS.search(nome):
|
||||||
|
if ',' in nome[:m.start()] or m[1].startswith(('fl', 'm.', 'n.', 'ca')):
|
||||||
|
return nome[:m.start()].strip(' ,'), m[1]
|
||||||
|
return nome, None
|
||||||
|
|
||||||
|
|
||||||
|
def _inverte(nome: str) -> str | None:
|
||||||
|
"""'Marc Ferrez' → 'Ferrez, Marc'. Só para nomes de pessoa sem vírgula."""
|
||||||
|
partes = nome.split()
|
||||||
|
if len(partes) < 2 or ',' in nome:
|
||||||
|
return None
|
||||||
|
i = len(partes) - 1
|
||||||
|
while i > 1 and partes[i - 1].lower() in PARTICULAS:
|
||||||
|
i -= 1
|
||||||
|
return f"{' '.join(partes[i:])}, {' '.join(partes[:i])}"
|
||||||
|
|
||||||
|
|
||||||
|
def periodo(datas: str | None) -> tuple[int, int] | None:
|
||||||
|
"""Anos prováveis de atividade: fl. A-B, ou nascimento+15 até a morte."""
|
||||||
|
if not datas:
|
||||||
|
return None
|
||||||
|
anos = [int(a) for a in re.findall(r'\d{4}', datas)]
|
||||||
|
if not anos:
|
||||||
|
return None
|
||||||
|
if datas.startswith('fl'):
|
||||||
|
return (anos[0], anos[-1]) if len(anos) > 1 else (anos[0], anos[0])
|
||||||
|
if datas.startswith('m.'):
|
||||||
|
return None
|
||||||
|
if len(anos) == 2:
|
||||||
|
return anos[0] + 15, anos[1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Autoridades:
|
||||||
|
def __init__(self):
|
||||||
|
self.contagem: Counter = Counter()
|
||||||
|
|
||||||
|
def registra(self, nome: str):
|
||||||
|
if nome and nome.strip() and not ANONIMO.match(nome):
|
||||||
|
self.contagem[nome.strip()] += 1
|
||||||
|
|
||||||
|
def resolve(self):
|
||||||
|
"""Agrupa as grafias. Depois disso `forma(nome)` devolve o id da autoridade."""
|
||||||
|
grupos: dict[str, Counter] = defaultdict(Counter)
|
||||||
|
for nome, n in self.contagem.items():
|
||||||
|
base, _ = _separa_datas(nome)
|
||||||
|
grupos[_chave(base)][nome] += n
|
||||||
|
# grafias diretas ("Marc Ferrez") que batem com uma invertida já conhecida
|
||||||
|
for k in list(grupos):
|
||||||
|
if ',' in k:
|
||||||
|
continue
|
||||||
|
nome = next(iter(grupos[k]))
|
||||||
|
if COLETIVA.search(nome):
|
||||||
|
continue
|
||||||
|
inv = _inverte(_separa_datas(nome)[0])
|
||||||
|
if inv and _chave(inv) in grupos and _chave(inv) != k:
|
||||||
|
grupos[_chave(inv)].update(grupos.pop(k))
|
||||||
|
|
||||||
|
self.registros: dict[str, dict] = {}
|
||||||
|
self._id_de: dict[str, str] = {}
|
||||||
|
for k, variantes in sorted(grupos.items(), key=lambda kv: -sum(kv[1].values())):
|
||||||
|
# forma autorizada: a variante mais completa (com datas) e mais usada
|
||||||
|
# (datas com início e fim > só uma data > nenhuma), depois frequência
|
||||||
|
def peso(v):
|
||||||
|
dt = _separa_datas(v)[1] or ''
|
||||||
|
return (len(re.findall(r'\d{4}', dt)), variantes[v], v)
|
||||||
|
forma = max(variantes, key=peso)
|
||||||
|
forma = forma.strip().rstrip('.')
|
||||||
|
base, datas = _separa_datas(forma)
|
||||||
|
tipo = 'entidade coletiva' if COLETIVA.search(base) else ('pessoa' if ',' in base else 'pessoa ou entidade')
|
||||||
|
if re.match(r'(?i)fam[ií]lia\b', base):
|
||||||
|
tipo = 'família'
|
||||||
|
aid = 'A' + str(len(self.registros) + 1).zfill(4)
|
||||||
|
self.registros[aid] = {
|
||||||
|
'id': aid, 'forma_autorizada': forma, 'nome': base, 'datas_existencia': datas,
|
||||||
|
'tipo': tipo, 'variantes': sorted(v for v in variantes if v.strip().rstrip('.') != forma),
|
||||||
|
'ocorrencias': sum(variantes.values()), 'periodo_atividade': periodo(datas),
|
||||||
|
'fontes': [],
|
||||||
|
}
|
||||||
|
for v in variantes:
|
||||||
|
self._id_de[v] = aid
|
||||||
|
|
||||||
|
def id(self, nome: str) -> str | None:
|
||||||
|
return self._id_de.get((nome or '').strip())
|
||||||
|
|
||||||
|
def __getitem__(self, aid: str) -> dict:
|
||||||
|
return self.registros[aid]
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
"""Normalizadores de campo único: espécie/suporte (1.5), características
|
||||||
|
físicas (1.5/4.4), direitos (4.2), idioma (4.3), lugar (1.3.1 data tópica) e
|
||||||
|
assuntos (8.1)."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import unicodedata
|
||||||
|
|
||||||
|
CORROMPIDO = re.compile(r'[<>{}]|ns:|PALAVRAS-CHAVE|^[0-9a-f]{6,}|\d[a-f]\d[a-f]\d')
|
||||||
|
|
||||||
|
|
||||||
|
def sem_acento(s: str) -> str:
|
||||||
|
return ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')
|
||||||
|
|
||||||
|
|
||||||
|
def corrompido(v: str | None) -> bool:
|
||||||
|
return bool(v) and bool(CORROMPIDO.search(v))
|
||||||
|
|
||||||
|
|
||||||
|
# ── 1.5 espécie e suporte (a partir de dc.type) ─────────────────────────────
|
||||||
|
ESPECIES = [ # (padrão, gênero, espécie)
|
||||||
|
(r'^negativo', 'iconográfico', 'negativo fotográfico'),
|
||||||
|
(r'^diapositivo', 'iconográfico', 'diapositivo'),
|
||||||
|
(r'reprodu[cç][aã]o fotomec', 'iconográfico', 'reprodução fotomecânica'),
|
||||||
|
(r'^(fotografia|vista panor)', 'iconográfico', 'fotografia'),
|
||||||
|
(r'^gravura', 'iconográfico', 'gravura'),
|
||||||
|
(r'^desenho', 'iconográfico', 'desenho'),
|
||||||
|
(r'^[áa]lbum', 'iconográfico', 'álbum fotográfico'),
|
||||||
|
(r'^manuscrito', 'textual', 'manuscrito'),
|
||||||
|
(r'^livro', 'bibliográfico', 'livro'),
|
||||||
|
(r'^artigo de peri', 'bibliográfico', 'periódico'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def especie(tipo: str | None) -> dict:
|
||||||
|
"""{'genero', 'especie', 'suporte', 'presumida'}. Sem dc.type (ou com lixo),
|
||||||
|
presume fotografia — o acervo inteiro é um repositório fotográfico — e marca."""
|
||||||
|
t = (tipo or '').strip()
|
||||||
|
if t and not corrompido(t):
|
||||||
|
base, _, sup = t.partition('/')
|
||||||
|
b = sem_acento(base.strip().lower())
|
||||||
|
for pat, gen, esp in ESPECIES:
|
||||||
|
if re.search(pat, b) or re.search(pat, base.strip().lower()):
|
||||||
|
suporte = sup.strip().lower() or None
|
||||||
|
if esp == 'negativo fotográfico' and 'flex' in b:
|
||||||
|
suporte = 'flexível'
|
||||||
|
return {'genero': gen, 'especie': esp, 'suporte': suporte, 'presumida': False}
|
||||||
|
return {'genero': 'iconográfico', 'especie': 'fotografia', 'suporte': None, 'presumida': True,
|
||||||
|
'original': t or None}
|
||||||
|
|
||||||
|
|
||||||
|
# ── características físicas que algumas instituições põem em dc.description ──
|
||||||
|
FISICO = re.compile(
|
||||||
|
r'(?i)^\s*(p\s*&\s*b|p/b|preto e branco|cor(ida)?|colorid[ao]|s[ée]pia|'
|
||||||
|
r'albumina|gelatina|prata|col[oó]dio|cianotipia|platina|carv[aã]o|ambr[oó]tipo|daguerre[oó]tipo|'
|
||||||
|
r'negativo|acetato|nitrato|vidro|papel|cart[aã]o|\d+[,.]?\d*\s*x\s*\d+|processo:|segunda gera)')
|
||||||
|
|
||||||
|
|
||||||
|
def e_fisico(v: str) -> bool:
|
||||||
|
return bool(FISICO.match(v)) and len(v) < 120
|
||||||
|
|
||||||
|
|
||||||
|
def cor(fisico: list[str]) -> str | None:
|
||||||
|
t = ' '.join(fisico).lower()
|
||||||
|
if re.search(r'p\s*&\s*b|p/b|preto e branco', t):
|
||||||
|
return 'p&b'
|
||||||
|
if re.search(r'colorid|\bcor\b', t):
|
||||||
|
return 'cor'
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# ── 4.2 condições de reprodução ─────────────────────────────────────────────
|
||||||
|
def direitos(textos: list[str], instituicao: str) -> dict:
|
||||||
|
"""{'categoria', 'detentor', 'texto', 'originais'}."""
|
||||||
|
limpos = list(dict.fromkeys(t.strip() for t in textos if t and t.strip() and t.strip() != 'None'))
|
||||||
|
junto = sem_acento(' '.join(limpos).lower())
|
||||||
|
if re.search(r'dominio publico|omínio público|omi?nio publico', junto):
|
||||||
|
cat = 'domínio público'
|
||||||
|
elif 'liberado para uso de natureza cultural' in junto:
|
||||||
|
cat = 'uso cultural liberado'
|
||||||
|
elif re.search(r'solicitar|requer libera', junto):
|
||||||
|
cat = 'requer autorização do detentor'
|
||||||
|
else:
|
||||||
|
cat = 'consultar o detentor'
|
||||||
|
detentor = None
|
||||||
|
for t in limpos:
|
||||||
|
a = sem_acento(t.lower())
|
||||||
|
if corrompido(t) or re.search(r'dominio publico|solicitar|requer|liberado', a) or len(t) < 6:
|
||||||
|
continue
|
||||||
|
if 'bibli' in a and 'nac' in a:
|
||||||
|
detentor = 'Biblioteca Nacional (Brasil)'
|
||||||
|
elif 'moreira' in a and 'salles' in a and '/' not in t:
|
||||||
|
detentor = 'Instituto Moreira Salles'
|
||||||
|
else:
|
||||||
|
detentor = t
|
||||||
|
break
|
||||||
|
detentor = detentor or instituicao
|
||||||
|
frases = {
|
||||||
|
'domínio público': 'Imagem em domínio público.',
|
||||||
|
'uso cultural liberado': 'Uso liberado para fins de natureza cultural.',
|
||||||
|
'requer autorização do detentor': 'Reprodução sujeita a autorização do detentor dos direitos.',
|
||||||
|
'consultar o detentor': 'Condições de reprodução não informadas na origem; consultar o detentor.',
|
||||||
|
}
|
||||||
|
return {'categoria': cat, 'detentor': detentor,
|
||||||
|
'texto': f'{frases[cat]} Detentor indicado: {detentor}.',
|
||||||
|
'originais': limpos or None}
|
||||||
|
|
||||||
|
|
||||||
|
# ── 4.3 idioma ───────────────────────────────────────────────────────────────
|
||||||
|
NOMES_IDIOMA = {'por': 'português', 'fre': 'francês', 'eng': 'inglês', 'lat': 'latim', 'ger': 'alemão',
|
||||||
|
'ita': 'italiano', 'ukr': 'ucraniano', 'hun': 'húngaro', 'spa': 'espanhol'}
|
||||||
|
|
||||||
|
|
||||||
|
def idiomas(vs: list[str]) -> list[dict]:
|
||||||
|
out = []
|
||||||
|
for v in vs:
|
||||||
|
c = (v or '').strip().lower()
|
||||||
|
if c in NOMES_IDIOMA and c not in [o['codigo'] for o in out]:
|
||||||
|
out.append({'codigo': c, 'nome': NOMES_IDIOMA[c]})
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
# ── 1.3.1 data tópica e 8.1 lugares ─────────────────────────────────────────
|
||||||
|
UF = {'AC', 'AL', 'AP', 'AM', 'BA', 'CE', 'DF', 'ES', 'GO', 'MA', 'MT', 'MS', 'MG', 'PA', 'PB', 'PR', 'PE',
|
||||||
|
'PI', 'RJ', 'RN', 'RS', 'RO', 'RR', 'SC', 'SP', 'SE', 'TO'}
|
||||||
|
ESTADOS = {'rio de janeiro': 'RJ', 'sao paulo': 'SP', 'bahia': 'BA', 'pernambuco': 'PE', 'minas gerais': 'MG',
|
||||||
|
'para': 'PA', 'amazonas': 'AM', 'parana': 'PR', 'rio grande do sul': 'RS', 'santa catarina': 'SC',
|
||||||
|
'ceara': 'CE', 'maranhao': 'MA', 'espirito santo': 'ES', 'goias': 'GO', 'mato grosso': 'MT',
|
||||||
|
'paraiba': 'PB', 'alagoas': 'AL', 'sergipe': 'SE', 'piaui': 'PI', 'rio grande do norte': 'RN'}
|
||||||
|
PAISES = {'brasil', 'brazil'}
|
||||||
|
|
||||||
|
|
||||||
|
def lugar(coberturas: list[str]) -> str | None:
|
||||||
|
"""A forma mais específica de cidade: 'Cidade (UF)'. Junta 'Rio de Janeiro' + 'RJ'."""
|
||||||
|
cs = [c.strip() for c in coberturas if c and c.strip() and not corrompido(c)]
|
||||||
|
for c in cs:
|
||||||
|
if m := re.fullmatch(r'(.+?)\s*(?:\(|,\s*|\s-\s*)([A-Z]{2})\)?', c):
|
||||||
|
if m[2] in UF and sem_acento(m[1].lower()) not in PAISES:
|
||||||
|
return f'{m[1].strip()} ({m[2]})'
|
||||||
|
ufs = [c for c in cs if c in UF]
|
||||||
|
for c in cs:
|
||||||
|
k = sem_acento(c.lower())
|
||||||
|
if k in PAISES or c in UF or '(estado)' in k or 'state' in k:
|
||||||
|
continue
|
||||||
|
if re.search(r'\(([^)]+)\)$', c): # "Paris (França)", "Rio de Janeiro (Brazil)"
|
||||||
|
nome, pais = re.match(r'(.+?)\s*\(([^)]+)\)$', c).groups()
|
||||||
|
if sem_acento(pais.lower()) in PAISES:
|
||||||
|
uf = ESTADOS.get(sem_acento(nome.lower()))
|
||||||
|
return f'{nome} ({uf})' if uf else nome
|
||||||
|
return c
|
||||||
|
uf = ufs[0] if ufs else ESTADOS.get(k)
|
||||||
|
return f'{c} ({uf})' if uf else c
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# ── 8.1 assuntos: separa as traduções inglesas que o DSpace da BN repete ─────
|
||||||
|
EN = {'the', 'and', 'of', 'in', 'on', 'women', 'men', 'children', 'streets', 'street', 'buildings', 'building',
|
||||||
|
'churches', 'church', 'views', 'view', 'slaves', 'railroads', 'railroad', 'harbors', 'harbor', 'landscapes',
|
||||||
|
'portraits', 'bridges', 'rivers', 'houses', 'squares', 'parks', 'gardens', 'mountains', 'beaches',
|
||||||
|
'ships', 'soldiers', 'history', 'photographs', 'people', 'indians', 'coffee', 'workers', 'palaces',
|
||||||
|
'monuments', 'waterfalls', 'boats', 'plantations', 'aerial', 'military', 'city', 'cities', 'public',
|
||||||
|
'social', 'life', 'customs', 'description', 'travel', 'transportation', 'agriculture', 'industry',
|
||||||
|
'architecture', 'fountains', 'hospitals', 'schools', 'markets', 'lakes', 'bays', 'islands', 'forts',
|
||||||
|
'wars', 'war', 'emperors', 'kings', 'queens', 'nobility', 'family', 'families', 'politicians'}
|
||||||
|
PT = {'de', 'da', 'do', 'das', 'dos', 'e', 'em', 'no', 'na', 'nos', 'nas', 'para', 'com'}
|
||||||
|
|
||||||
|
|
||||||
|
def idioma_termo(t: str) -> str:
|
||||||
|
if re.search(r'[ãõçáéíóúâêô]', t.lower()):
|
||||||
|
return 'por'
|
||||||
|
palavras = set(re.findall(r'[a-z]+', t.lower()))
|
||||||
|
if palavras & PT:
|
||||||
|
return 'por'
|
||||||
|
if palavras & EN or re.search(r'\((?:brazil|state)', t.lower()):
|
||||||
|
return 'eng'
|
||||||
|
return 'por'
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
"""Constantes da descrição NOBRADE — decisões registradas em CONARQ.md §5."""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
RAIZ = Path(__file__).resolve().parents[2]
|
||||||
|
PIPELINE = RAIZ / 'pipeline'
|
||||||
|
CATALOGO = PIPELINE / 'catalogo.jsonl'
|
||||||
|
LEDGER = PIPELINE / 'subidor.sqlite'
|
||||||
|
POSTS = PIPELINE / 'wordpress-posts.jsonl'
|
||||||
|
ERROS = RAIZ / 'errors.md'
|
||||||
|
AJUSTES = Path(__file__).resolve().parent / 'ajustes'
|
||||||
|
SAIDA = RAIZ / 'descricao'
|
||||||
|
TEXTOS = SAIDA / 'textos'
|
||||||
|
REVISAO = SAIDA / 'revisao'
|
||||||
|
|
||||||
|
# 1.1 — código da entidade custodiadora. PROVISÓRIO até o CONARQ atribuir um
|
||||||
|
# (proc. 1.1.1). Trocar aqui regenera todos os códigos de referência.
|
||||||
|
# Formato do CODEARQ, como o AGCRJ usa: país, espaço, UF + sigla, e as partes
|
||||||
|
# da unidade separadas por ponto — BR RJAGCRJ.SOP.NL.AVE.03.01
|
||||||
|
PAIS = 'BR'
|
||||||
|
ENTIDADE = 'RJXYZ'
|
||||||
|
ENTIDADE_NOME = 'xyz — cópia digital de acervos fotográficos'
|
||||||
|
ENTIDADE_SITE = 'https://xn--2dk.xyz/brasiliana/'
|
||||||
|
COLECAO = 'BF'
|
||||||
|
COLECAO_TITULO = 'Coleção Brasiliana Fotográfica (cópia digital)'
|
||||||
|
RESPONSAVEL = 'rafapolo'
|
||||||
|
BUCKET = 's3://brasiliana'
|
||||||
|
|
||||||
|
REGRAS = ('NOBRADE: Norma brasileira de descrição arquivística (CONARQ, 2006); '
|
||||||
|
'ISAD(G) 2ª ed. (CIA, 2000); ISAAR(CPF) 2ª ed. (CIA, 2004); '
|
||||||
|
'datas em ISO 8601-2 (EDTF); idiomas em ISO 639-2; países em ISO 3166.')
|
||||||
|
|
||||||
|
ORIGEM_NOME = 'Brasiliana Fotográfica'
|
||||||
|
ORIGEM_SITE = 'https://brasilianafotografica.bn.gov.br/'
|
||||||
|
HANDLE_URL = 'https://brasilianafotografica.bn.gov.br/brasiliana/handle/{}'
|
||||||
|
|
||||||
|
# Nível 2 — uma seção por instituição de origem (campo `community` do catálogo).
|
||||||
|
# sigla → (nome autorizado, cidade)
|
||||||
|
INSTITUICOES = {
|
||||||
|
'Instituto Moreira Salles': ('IMS', 'Instituto Moreira Salles', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Biblioteca Nacional': ('BN', 'Biblioteca Nacional (Brasil)', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Museu Aeroespacial': ('MUSAL', 'Museu Aeroespacial', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Museu da Republica': ('MR', 'Museu da República', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Museu Historico Nacional': ('MHN', 'Museu Histórico Nacional', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Fiocruz': ('COC', 'Fundação Oswaldo Cruz. Casa de Oswaldo Cruz', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Diretoria do Patrimonio Historico e Documentacao da Marinha':
|
||||||
|
('DPHDM', 'Diretoria do Patrimônio Histórico e Documentação da Marinha', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Arquivo Nacional': ('AN', 'Arquivo Nacional (Brasil)', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Arquivo Geral da Cidade do Rio de Janeiro':
|
||||||
|
('AGCRJ', 'Arquivo Geral da Cidade do Rio de Janeiro', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Leibniz-Institut fuer Laenderkunde, Leipzig':
|
||||||
|
('IFL', 'Leibniz-Institut für Länderkunde', 'Leipzig (Alemanha)'),
|
||||||
|
'Instituto Historico e Geografico Brasileiro':
|
||||||
|
('IHGB', 'Instituto Histórico e Geográfico Brasileiro', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Fundacao Joaquim Nabuco': ('FUNDAJ', 'Fundação Joaquim Nabuco', 'Recife (PE)'),
|
||||||
|
'Museu Paraense Emilio Goeldi': ('MPEG', 'Museu Paraense Emílio Goeldi', 'Belém (PA)'),
|
||||||
|
'Escola de Ciencias Sociais (FGV CPDOC)':
|
||||||
|
('CPDOC', 'Fundação Getulio Vargas. Escola de Ciências Sociais (FGV CPDOC)', 'Rio de Janeiro (RJ)'),
|
||||||
|
'Instituto Brasileiro de Geografia e Estatistica':
|
||||||
|
('IBGE', 'Instituto Brasileiro de Geografia e Estatística', 'Rio de Janeiro (RJ)'),
|
||||||
|
}
|
||||||
|
|
||||||
|
# 4.1 — obrigatório nos níveis 0 e 1
|
||||||
|
ACESSO = ('Sem restrição de acesso à descrição. As cópias digitais são mantidas '
|
||||||
|
f'para preservação em {BUCKET} e consultáveis pelo mural em {ENTIDADE_SITE}. '
|
||||||
|
'O acesso aos originais segue as regras de cada instituição de origem '
|
||||||
|
'(ver 5.1 em cada dossiê).')
|
||||||
|
|
||||||
|
|
||||||
|
def codigo(*partes: str) -> str:
|
||||||
|
"""BR RJXYZ, BR RJXYZ.BF, BR RJXYZ.BF.IMS.GF.12345.01 …"""
|
||||||
|
return f'{PAIS} ' + '.'.join((ENTIDADE,) + tuple(p for p in partes if p))
|
||||||
@@ -0,0 +1,333 @@
|
|||||||
|
"""Normalização de dc.date para o elemento 1.3 da NOBRADE.
|
||||||
|
|
||||||
|
Saída de `interpreta(texto)`:
|
||||||
|
forma — como a NOBRADE manda exibir: `1914`, `[1860]`, `[1902?]`,
|
||||||
|
`[ca. 1905]`, `[193-]`, `[18--?]`, `8/2/1890-18/4/1890`
|
||||||
|
iso — ISO 8601-2 (EDTF), para indexação e intercâmbio (proc. 1.3.2.7):
|
||||||
|
`1914`, `1902?`, `1905~`, `193X`, `18XX?`, `1931/1937`, `../1921`
|
||||||
|
inicio, fim — anos inteiros (ou None) para filtrar e ordenar
|
||||||
|
qualidade — `exata` | `atribuida` | `incerta` | `aproximada`
|
||||||
|
tipo — `produção` (padrão) ou `publicação`
|
||||||
|
motivo — quando não deu para interpretar: `sem data`, `registro de sistema`,
|
||||||
|
`ilegível`
|
||||||
|
|
||||||
|
A regra geral: tira do texto as marcas (colchetes, `?`, `circa`, qualificadores
|
||||||
|
entre parênteses), interpreta o que sobra como ponto ou intervalo e remonta a
|
||||||
|
forma com as marcas no padrão da norma (proc. 1.3.2.1–1.3.2.4).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import unicodedata
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
MESES = {
|
||||||
|
'jan': 1, 'janeiro': 1, 'fev': 2, 'fevereiro': 2, 'mar': 3, 'março': 3, 'marco': 3,
|
||||||
|
'abr': 4, 'abril': 4, 'mai': 5, 'maio': 5, 'jun': 6, 'junho': 6,
|
||||||
|
'jul': 7, 'julho': 7, 'ago': 8, 'agosto': 8, 'set': 9, 'setembro': 9,
|
||||||
|
'out': 10, 'outubro': 10, 'nov': 11, 'novembro': 11, 'dez': 12, 'dezembro': 12,
|
||||||
|
}
|
||||||
|
MES_RE = '(' + '|'.join(sorted(MESES, key=len, reverse=True)) + r')\.?'
|
||||||
|
|
||||||
|
SEM_DATA = re.compile(r'^(s\.?\s*/?\s*d\.?|s/data|sem data|s\.?\s*n\.?|n[aã]o identificad[ao])$', re.I)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Ponto:
|
||||||
|
ano: int
|
||||||
|
mes: int | None = None
|
||||||
|
dia: int | None = None
|
||||||
|
prec: str = 'ano' # dia | mes | ano | decada | seculo
|
||||||
|
|
||||||
|
def forma(self) -> str:
|
||||||
|
if self.prec == 'dia':
|
||||||
|
return f'{self.dia}/{self.mes}/{self.ano}'
|
||||||
|
if self.prec == 'mes':
|
||||||
|
return f'{self.mes}/{self.ano}'
|
||||||
|
if self.prec == 'decada':
|
||||||
|
return f'{self.ano // 10}-'
|
||||||
|
if self.prec == 'seculo':
|
||||||
|
return f'{self.ano // 100}--'
|
||||||
|
return str(self.ano)
|
||||||
|
|
||||||
|
def iso(self) -> str:
|
||||||
|
if self.prec == 'dia':
|
||||||
|
return f'{self.ano:04d}-{self.mes:02d}-{self.dia:02d}'
|
||||||
|
if self.prec == 'mes':
|
||||||
|
return f'{self.ano:04d}-{self.mes:02d}'
|
||||||
|
if self.prec == 'decada':
|
||||||
|
return f'{self.ano // 10}X'
|
||||||
|
if self.prec == 'seculo':
|
||||||
|
return f'{self.ano // 100}XX'
|
||||||
|
return f'{self.ano:04d}'
|
||||||
|
|
||||||
|
def limites(self) -> tuple[int, int]:
|
||||||
|
if self.prec == 'decada':
|
||||||
|
return self.ano, self.ano + 9
|
||||||
|
if self.prec == 'seculo':
|
||||||
|
return self.ano, self.ano + 99
|
||||||
|
return self.ano, self.ano
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Data:
|
||||||
|
original: str
|
||||||
|
inicio_p: Ponto | None = None
|
||||||
|
fim_p: Ponto | None = None
|
||||||
|
relacao: str = '' # '' | 'antes' | 'depois'
|
||||||
|
colchete: bool = False
|
||||||
|
incerta: bool = False
|
||||||
|
aproximada: bool = False
|
||||||
|
tipo: str = 'produção'
|
||||||
|
motivo: str = ''
|
||||||
|
notas: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ok(self) -> bool:
|
||||||
|
return self.inicio_p is not None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def qualidade(self) -> str:
|
||||||
|
if self.aproximada:
|
||||||
|
return 'aproximada'
|
||||||
|
if self.incerta:
|
||||||
|
return 'incerta'
|
||||||
|
if self.colchete:
|
||||||
|
return 'atribuida'
|
||||||
|
return 'exata'
|
||||||
|
|
||||||
|
def forma(self) -> str:
|
||||||
|
if not self.ok:
|
||||||
|
return '[s.d.]'
|
||||||
|
a = self.inicio_p.forma()
|
||||||
|
if self.relacao == 'antes':
|
||||||
|
s = f'antes de {a}'
|
||||||
|
elif self.relacao == 'depois':
|
||||||
|
s = f'depois de {a}'
|
||||||
|
elif self.fim_p and self.fim_p != self.inicio_p:
|
||||||
|
s = f'{a}-{self.fim_p.forma()}'
|
||||||
|
else:
|
||||||
|
s = a
|
||||||
|
if self.aproximada:
|
||||||
|
s = 'ca. ' + s
|
||||||
|
if self.incerta:
|
||||||
|
s += '?'
|
||||||
|
if self.colchete or self.aproximada or self.incerta or self.relacao:
|
||||||
|
s = f'[{s}]'
|
||||||
|
return s
|
||||||
|
|
||||||
|
def iso(self) -> str | None:
|
||||||
|
if not self.ok:
|
||||||
|
return None
|
||||||
|
q = ('%' if self.incerta else '~') if self.aproximada else ('?' if self.incerta else '')
|
||||||
|
a = self.inicio_p.iso() + q
|
||||||
|
if self.relacao == 'antes':
|
||||||
|
return f'../{a}'
|
||||||
|
if self.relacao == 'depois':
|
||||||
|
return f'{a}/..'
|
||||||
|
if self.fim_p and self.fim_p != self.inicio_p:
|
||||||
|
return f'{a}/{self.fim_p.iso()}{q}'
|
||||||
|
return a
|
||||||
|
|
||||||
|
def anos(self) -> tuple[int | None, int | None]:
|
||||||
|
if not self.ok:
|
||||||
|
return None, None
|
||||||
|
i, f = self.inicio_p.limites()
|
||||||
|
if self.fim_p:
|
||||||
|
f = self.fim_p.limites()[1]
|
||||||
|
if self.relacao == 'antes':
|
||||||
|
return None, f
|
||||||
|
if self.relacao == 'depois':
|
||||||
|
return i, None
|
||||||
|
return i, f
|
||||||
|
|
||||||
|
def registro(self) -> dict:
|
||||||
|
i, f = self.anos()
|
||||||
|
return {
|
||||||
|
'original': self.original, 'forma': self.forma(), 'iso': self.iso(),
|
||||||
|
'inicio': i, 'fim': f, 'qualidade': self.qualidade if self.ok else None,
|
||||||
|
'tipo': self.tipo, 'motivo': self.motivo or None,
|
||||||
|
'notas': self.notas or None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _sem_acento(s: str) -> str:
|
||||||
|
return ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')
|
||||||
|
|
||||||
|
|
||||||
|
def _ano(s: str, base: int | None = None) -> int:
|
||||||
|
n = int(s)
|
||||||
|
if len(s) == 2:
|
||||||
|
return (base // 100 * 100 if base else 1900) + n
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
def _ponto(s: str) -> tuple[Ponto | None, bool]:
|
||||||
|
"""Um ponto no tempo. Devolve (ponto, incerto) — incerto quando o próprio
|
||||||
|
formato carrega a dúvida, como `193?` (década) ou `?/08/1938` (dia)."""
|
||||||
|
s = s.strip(' .,:;')
|
||||||
|
s = re.sub(r'^[-–]\s*', '', s)
|
||||||
|
if not s:
|
||||||
|
return None, False
|
||||||
|
if m := re.fullmatch(r'(\d{4})', s):
|
||||||
|
return Ponto(int(m[1])), False
|
||||||
|
if m := re.fullmatch(r'(\d{3})-', s):
|
||||||
|
return Ponto(int(m[1]) * 10, prec='decada'), False
|
||||||
|
if m := re.fullmatch(r'(\d{3})-?\?', s):
|
||||||
|
return Ponto(int(m[1]) * 10, prec='decada'), True
|
||||||
|
if m := re.fullmatch(r'(\d{2})(?:-{2,3}|_)', s):
|
||||||
|
return Ponto(int(m[1]) * 100, prec='seculo'), False
|
||||||
|
if m := re.fullmatch(r'(\d{2})(?:-{2})?\?', s):
|
||||||
|
return Ponto(int(m[1]) * 100, prec='seculo'), True
|
||||||
|
if m := re.fullmatch(r'(\d{3})--', s): # [186--]: década escrita com traço a mais
|
||||||
|
return Ponto(int(m[1]) * 10, prec='decada'), False
|
||||||
|
# dia/mês/ano, com separadores tortos: 22-12--1938, 14 -07-1928, 05/12-1934
|
||||||
|
if m := re.fullmatch(r'(\d{1,2})\s*[-/.]\s*(\d{1,2})\s*[-/.]+\s*(\d{4}|\d{2})', s):
|
||||||
|
d, mo, a = int(m[1]), int(m[2]), _ano(m[3])
|
||||||
|
if 1 <= mo <= 12 and 1 <= d <= 31:
|
||||||
|
return Ponto(a, mo, d, 'dia'), len(m[3]) == 2
|
||||||
|
if m := re.fullmatch(r'(\d{4})\s*[-/]\s*(\d{1,2})\s*[-/]\s*(\d{1,2})', s):
|
||||||
|
a, mo, d = int(m[1]), int(m[2]), int(m[3])
|
||||||
|
if 1 <= mo <= 12 and 1 <= d <= 31:
|
||||||
|
return Ponto(a, mo, d, 'dia'), False
|
||||||
|
# dia desconhecido: 2-/12/1923, ?/08/1938
|
||||||
|
if m := re.fullmatch(r'(?:\d?-|\?)\s*/\s*(\d{1,2})\s*/\s*(\d{4})', s):
|
||||||
|
return Ponto(int(m[2]), int(m[1]), prec='mes'), False
|
||||||
|
if m := re.fullmatch(r'(\d{1,2})\s*/\s*(\d{4})', s):
|
||||||
|
if 1 <= int(m[1]) <= 12:
|
||||||
|
return Ponto(int(m[2]), int(m[1]), prec='mes'), False
|
||||||
|
if m := re.fullmatch(r'(\d{4})\s*/\s*(\d{1,2})', s):
|
||||||
|
if 1 <= int(m[2]) <= 12:
|
||||||
|
return Ponto(int(m[1]), int(m[2]), prec='mes'), False
|
||||||
|
t = _sem_acento(s.lower())
|
||||||
|
if m := re.fullmatch(rf'(\d{{1,2}})\s*(?:de\s+)?{MES_RE}\s*,?\s*(?:de\s+)?(\d{{4}})', t):
|
||||||
|
return Ponto(int(m[3]), MESES[m[2]], int(m[1]), 'dia'), False
|
||||||
|
if m := re.fullmatch(rf'{MES_RE}\s*,?\s*(?:de\s+)?(\d{{4}})', t):
|
||||||
|
return Ponto(int(m[2]), MESES[m[1]], prec='mes'), False
|
||||||
|
if m := re.fullmatch(r'(?:decada de )?(\d{3})\d(?: decada)?( provavel)?', t):
|
||||||
|
if 'decada' in t:
|
||||||
|
return Ponto(int(m[1]) * 10, prec='decada'), bool(m[2])
|
||||||
|
if m := re.fullmatch(r'(\d{2}) seculo', t):
|
||||||
|
return Ponto((int(m[1]) - 1) * 100, prec='seculo'), False
|
||||||
|
return None, False
|
||||||
|
|
||||||
|
|
||||||
|
def _intervalo(s: str) -> tuple[Ponto | None, Ponto | None, bool]:
|
||||||
|
t = _sem_acento(s.lower()).strip(' .,:;')
|
||||||
|
t = re.sub(r'^entre\s+', '', t)
|
||||||
|
p, inc = _ponto(t)
|
||||||
|
if p:
|
||||||
|
return p, None, inc
|
||||||
|
# dias ou meses coordenados: "15 e 16 de outubro de 1930", "outubro e novembro de 1930"
|
||||||
|
if m := re.fullmatch(rf'(\d{{1,2}})\s+e\s+(\d{{1,2}})\s+(?:de\s+)?{MES_RE}\s+(?:de\s+)?(\d{{4}})', t):
|
||||||
|
mo, a = MESES[m[3]], int(m[4])
|
||||||
|
return Ponto(a, mo, int(m[1]), 'dia'), Ponto(a, mo, int(m[2]), 'dia'), False
|
||||||
|
if m := re.fullmatch(rf'{MES_RE}\s+e\s+{MES_RE}\s+(?:de\s+)?(\d{{4}})', t):
|
||||||
|
a = int(m[3])
|
||||||
|
return Ponto(a, MESES[m[1]], prec='mes'), Ponto(a, MESES[m[2]], prec='mes'), False
|
||||||
|
# 1859-61: segundo ano abreviado
|
||||||
|
if m := re.fullmatch(r'(\d{4})\s*-\s*(\d{2})', t):
|
||||||
|
a = int(m[1])
|
||||||
|
b = _ano(m[2], a)
|
||||||
|
if b > a:
|
||||||
|
return Ponto(a), Ponto(b), False
|
||||||
|
# o traço separa só entre um ano e o início do outro — `193-` é década, não intervalo
|
||||||
|
for sep in (r'\s+e\s+', r'\s+a\s+', r'(?<=[\d?])\s*[-–]\s*(?=\d)', r'\s*/\s*'):
|
||||||
|
partes = re.split(sep, t)
|
||||||
|
if len(partes) != 2:
|
||||||
|
continue
|
||||||
|
# "/" só separa anos inteiros (1952/1953); com meses é data (1910/12)
|
||||||
|
if sep == r'\s*/\s*' and not all(re.fullmatch(r'\d{4}', p) for p in partes):
|
||||||
|
continue
|
||||||
|
a, ia = _ponto(partes[0])
|
||||||
|
b, ib = _ponto(partes[1])
|
||||||
|
if a and b and b.limites()[1] >= a.limites()[0]:
|
||||||
|
return a, b, ia or ib
|
||||||
|
return None, None, False
|
||||||
|
|
||||||
|
|
||||||
|
def interpreta(texto: str | None) -> Data:
|
||||||
|
original = (texto or '').strip()
|
||||||
|
d = Data(original)
|
||||||
|
s = original
|
||||||
|
if not s:
|
||||||
|
d.motivo = 'sem data'
|
||||||
|
return d
|
||||||
|
if re.fullmatch(r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z', s):
|
||||||
|
# carimbo de registro no DSpace gravado no campo errado — não é produção
|
||||||
|
d.motivo = 'registro de sistema'
|
||||||
|
d.notas.append(f'dc.date traz a data de registro no sistema de origem ({s}), não a de produção')
|
||||||
|
return d
|
||||||
|
|
||||||
|
# partes separadas por ";" com qualificador: fica a de produção, o resto vira nota
|
||||||
|
partes = [p.strip() for p in re.split(r';(?![^(]*\))', s) if p.strip()]
|
||||||
|
if len(partes) > 1:
|
||||||
|
principal = next((p for p in partes if re.search(r'produ', p, re.I)), partes[0])
|
||||||
|
d.notas += [f'dc.date também registra: {p}' for p in partes if p is not principal]
|
||||||
|
s = principal
|
||||||
|
|
||||||
|
if m := re.search(r'\(([^)]*)\)\s*$', s):
|
||||||
|
q = m[1].lower()
|
||||||
|
if 'publica' in q:
|
||||||
|
d.tipo = 'publicação'
|
||||||
|
if 'atribu' in q:
|
||||||
|
d.colchete = True
|
||||||
|
s = s[:m.start()].strip()
|
||||||
|
|
||||||
|
if re.search(r'[\[\]{]', s):
|
||||||
|
d.colchete = True
|
||||||
|
s = re.sub(r'[\[\]{}]', '', s)
|
||||||
|
s = re.sub(r'^\s*-\s*', '', s)
|
||||||
|
s = re.sub(r'^(RJ|[A-Z]{2}),\s*', '', s) # [RJ, ca. 1860]: lugar vai na data tópica
|
||||||
|
s = re.sub(r'(\d)\.(\d{3})\b', r'\1\2', s) # 1.885 → 1885
|
||||||
|
s = re.sub(r'\s*:?\.\s*$', '', s).strip()
|
||||||
|
|
||||||
|
if SEM_DATA.fullmatch(s):
|
||||||
|
d.motivo = 'sem data'
|
||||||
|
return d
|
||||||
|
|
||||||
|
s, n = re.subn(r'\b(circa|cica|cira|ca\.?|c\.)\s*|(?<=\[)c(?=\d)|^c(?=\d)', '', s, flags=re.I)
|
||||||
|
if n:
|
||||||
|
d.aproximada = True
|
||||||
|
s, n = re.subn(r'\s*\b(anterior|antes de)\b\s*', ' ', s, flags=re.I)
|
||||||
|
if n:
|
||||||
|
d.relacao = 'antes'
|
||||||
|
s, n = re.subn(r'\s*\b(posterior|depois de)\b\s*', ' ', s, flags=re.I)
|
||||||
|
if n:
|
||||||
|
d.relacao = 'depois'
|
||||||
|
s = s.strip()
|
||||||
|
# interrogação no fim vale para a data inteira; dentro de um ponto (193?) é o ponto que diz
|
||||||
|
if re.search(r'\d{4}\s*\?\s*$', s) or re.search(r'\d{4}\?\s*\]?$', original):
|
||||||
|
d.incerta = True
|
||||||
|
s = re.sub(r'\s*\?\s*$', '', s)
|
||||||
|
|
||||||
|
# "Foto aérea da Fábrica ... - SP - 23-06-1933": só a data do fim interessa
|
||||||
|
if not re.match(r'[\d?]', s) and not re.match(rf'(?i){MES_RE}|entre|decada|década', _sem_acento(s)):
|
||||||
|
if m := re.search(r'(\d{1,2}-\d{1,2}-\d{4}|\d{4})\s*$', s):
|
||||||
|
d.notas.append(f'data extraída do texto: {original}')
|
||||||
|
s = m[1]
|
||||||
|
|
||||||
|
p, inc = _ponto(s)
|
||||||
|
if p:
|
||||||
|
d.inicio_p, d.incerta = p, d.incerta or inc
|
||||||
|
return d
|
||||||
|
a, b, inc = _intervalo(s)
|
||||||
|
if a:
|
||||||
|
d.inicio_p, d.fim_p, d.incerta = a, b, d.incerta or inc
|
||||||
|
return d
|
||||||
|
# "1900-" (colchete aberto): dali em diante
|
||||||
|
if m := re.fullmatch(r'(\d{4})\s*-', s):
|
||||||
|
d.inicio_p, d.relacao = Ponto(int(m[1])), 'depois'
|
||||||
|
return d
|
||||||
|
d.motivo = 'ilegível'
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def atribuida(inicio: int, fim: int, base: str) -> dict:
|
||||||
|
"""Data atribuída pelo arquivista a partir de outra fonte (proc. 1.3.3.2)."""
|
||||||
|
d = Data('', Ponto(inicio), Ponto(fim) if fim != inicio else None, incerta=True, colchete=True)
|
||||||
|
r = d.registro()
|
||||||
|
r['original'] = None
|
||||||
|
r['notas'] = [f'data atribuída pelo arquivista: {base}']
|
||||||
|
return r
|
||||||
@@ -0,0 +1,352 @@
|
|||||||
|
"""Exportação da descrição: EAD 3 (descrições), EAC-CPF (autoridades) e CSV
|
||||||
|
de importação do AtoM (modelo ISAD). A NOBRADE não impõe formato; recomenda o
|
||||||
|
EAD para intercâmbio (nota 13).
|
||||||
|
|
||||||
|
Correspondência NOBRADE → EAD 3:
|
||||||
|
1.1 unitid · 1.2 unittitle · 1.3 unitdate (@normal em ISO 8601-2) ·
|
||||||
|
1.4 @level · 1.5 physdesc + physdescstructured · 2.1 origination ·
|
||||||
|
2.2 bioghist · 2.3 custodhist · 2.4 acqinfo · 3.1 scopecontent ·
|
||||||
|
3.2 appraisal · 3.3 accruals · 3.4 arrangement · 4.1 accessrestrict ·
|
||||||
|
4.2 userestrict · 4.3 langmaterial · 4.4 phystech · 4.5 otherfindaid ·
|
||||||
|
5.1 originalsloc · 5.2 altformavail + dao · 5.3 relatedmaterial ·
|
||||||
|
5.4 bibliography · 6.1 odd[@localtype=conservacao] · 6.2 odd ·
|
||||||
|
7.1 processinfo · 7.2 control/conventiondeclaration · 7.3 control/maintenancehistory ·
|
||||||
|
8.1 controlaccess
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import re
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from collections import defaultdict
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
from .config import ENTIDADE, ENTIDADE_NOME, PAIS, REGRAS, SAIDA
|
||||||
|
|
||||||
|
EAD = 'http://ead3.archivists.org/schema/'
|
||||||
|
CPF = 'urn:isbn:1-931666-33-4'
|
||||||
|
XLINK = 'http://www.w3.org/1999/xlink'
|
||||||
|
NIVEL_EAD = {1: ('collection', None), 2: ('otherlevel', 'seção'), 3: ('series', None),
|
||||||
|
4: ('file', None), 5: ('item', None)}
|
||||||
|
HOJE = date.today().isoformat()
|
||||||
|
|
||||||
|
|
||||||
|
# ── texto plano de cada elemento (usado por EAD, AtoM e mural) ──────────────
|
||||||
|
def texto(u: dict, el: str) -> str | None:
|
||||||
|
v = u.get(el)
|
||||||
|
if v is None:
|
||||||
|
return None
|
||||||
|
if el == '1.2':
|
||||||
|
return v['titulo']
|
||||||
|
if el == '1.3':
|
||||||
|
p = v.get('producao') or {}
|
||||||
|
return p.get('forma')
|
||||||
|
if el == '1.5':
|
||||||
|
return v.get('texto')
|
||||||
|
if el == '2.1':
|
||||||
|
return '; '.join(p['forma'] for p in v)
|
||||||
|
if el == '4.2':
|
||||||
|
return v['texto'] if isinstance(v, dict) else v
|
||||||
|
if el == '4.3':
|
||||||
|
return '; '.join(i['nome'] for i in v) if isinstance(v, list) else v
|
||||||
|
if el == '5.1':
|
||||||
|
return v.get('texto') or v.get('instituicao') if isinstance(v, dict) else v
|
||||||
|
if el == '5.2':
|
||||||
|
if isinstance(v, str):
|
||||||
|
return v
|
||||||
|
partes = [f"{c['tipo']}: {c['chave']} (SHA-256 {c['sha256']})" for c in v.get('nesta_entidade') or []]
|
||||||
|
partes += [f"{c['entidade']}: {c['url']}" for c in v.get('em_outras_entidades') or []]
|
||||||
|
return '; '.join(partes) or None
|
||||||
|
if el in ('5.3', '5.4', '6.2') and isinstance(v, list):
|
||||||
|
return '\n'.join(v)
|
||||||
|
if el == '7.3':
|
||||||
|
return '; '.join(f'{k}: {x}' for k, x in v.items())
|
||||||
|
if el == '8.1' and isinstance(v, dict):
|
||||||
|
return None
|
||||||
|
return v if isinstance(v, str) else None
|
||||||
|
|
||||||
|
|
||||||
|
# ── EAD 3 ────────────────────────────────────────────────────────────────────
|
||||||
|
def _sub(pai, tag, txt=None, **attrs):
|
||||||
|
e = ET.SubElement(pai, f'{{{EAD}}}{tag}', {k.rstrip('_'): str(x) for k, x in attrs.items() if x is not None})
|
||||||
|
if txt is not None:
|
||||||
|
e.text = txt
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
def _paragrafos(pai, tag, txt, head=None, **attrs):
|
||||||
|
if not txt:
|
||||||
|
return
|
||||||
|
e = _sub(pai, tag, **attrs)
|
||||||
|
if head:
|
||||||
|
_sub(e, 'head', head)
|
||||||
|
for par in [p.strip() for p in re.split(r'\n\s*\n|\n(?=[-\d])', txt) if p.strip()]:
|
||||||
|
_sub(e, 'p', re.sub(r'\s+', ' ', par))
|
||||||
|
|
||||||
|
|
||||||
|
def _nome(pai, forma: str, aid: str | None, tipo: str | None, relator=None):
|
||||||
|
tag = {'entidade coletiva': 'corpname', 'família': 'famname'}.get(tipo, 'persname')
|
||||||
|
e = _sub(pai, tag, identifier=aid, relator=relator)
|
||||||
|
_sub(e, 'part', forma)
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
def _componente(pai, u: dict, aut: dict, tag='c'):
|
||||||
|
nivel, outro = NIVEL_EAD[u['nivel']]
|
||||||
|
c = pai if tag == 'archdesc' else _sub(pai, 'c', level=nivel, otherlevel=outro, id=_xmlid(u['id']))
|
||||||
|
did = _sub(c, 'did')
|
||||||
|
_sub(did, 'unitid', u['1.1'], countrycode=PAIS, repositorycode=f'{PAIS}-{ENTIDADE}')
|
||||||
|
_sub(did, 'unittitle', u['1.2']['titulo'])
|
||||||
|
p = u['1.3'].get('producao') or {}
|
||||||
|
cert = {'aproximada': 'approximate', 'incerta': 'uncertain', 'atribuida': 'inferred',
|
||||||
|
'atribuída pelo arquivista': 'inferred'}.get(p.get('qualidade'))
|
||||||
|
_sub(did, 'unitdate', p.get('forma') or '[s.d.]', normal=p.get('iso'),
|
||||||
|
datechar='publication' if p.get('tipo') == 'publicação' else 'creation', certainty=cert,
|
||||||
|
unitdatetype='inclusive' if u['nivel'] < 4 else None)
|
||||||
|
orig = _sub(did, 'origination')
|
||||||
|
for pr in u['2.1']:
|
||||||
|
_nome(orig, pr['forma'], pr.get('id'), (aut.get(pr.get('id')) or {}).get('tipo'),
|
||||||
|
relator=pr.get('funcao'))
|
||||||
|
dim = u['1.5']
|
||||||
|
_sub(did, 'physdesc', dim['texto'])
|
||||||
|
for esp, n in (dim.get('por_especie') or {}).items():
|
||||||
|
ps = _sub(did, 'physdescstructured', physdescstructuredtype='materialtype', coverage='part')
|
||||||
|
_sub(ps, 'quantity', str(n))
|
||||||
|
_sub(ps, 'unittype', esp)
|
||||||
|
if isinstance(u.get('4.3'), list):
|
||||||
|
lm = _sub(did, 'langmaterial')
|
||||||
|
for i in u['4.3']:
|
||||||
|
_sub(lm, 'language', i['nome'], langcode=i['codigo'])
|
||||||
|
if u['nivel'] == 5:
|
||||||
|
for cp in (u.get('5.2') or {}).get('nesta_entidade') or []:
|
||||||
|
_sub(did, 'dao', daotype='derived', href=cp['chave'], linktitle=cp['tipo'],
|
||||||
|
identifier=f"sha256:{cp['sha256']}")
|
||||||
|
|
||||||
|
_paragrafos(c, 'bioghist', u.get('2.2'))
|
||||||
|
_paragrafos(c, 'custodhist', u.get('2.3'))
|
||||||
|
_paragrafos(c, 'acqinfo', u.get('2.4'))
|
||||||
|
_paragrafos(c, 'scopecontent', u.get('3.1'))
|
||||||
|
_paragrafos(c, 'appraisal', u.get('3.2'))
|
||||||
|
_paragrafos(c, 'accruals', u.get('3.3'))
|
||||||
|
_paragrafos(c, 'arrangement', u.get('3.4'))
|
||||||
|
_paragrafos(c, 'accessrestrict', u.get('4.1'))
|
||||||
|
_paragrafos(c, 'userestrict', texto(u, '4.2'))
|
||||||
|
_paragrafos(c, 'phystech', u.get('4.4'))
|
||||||
|
_paragrafos(c, 'otherfindaid', u.get('4.5'))
|
||||||
|
_paragrafos(c, 'originalsloc', texto(u, '5.1'))
|
||||||
|
if u['nivel'] != 5:
|
||||||
|
_paragrafos(c, 'altformavail', texto(u, '5.2'))
|
||||||
|
if isinstance(u.get('5.3'), list):
|
||||||
|
rm = _sub(c, 'relatedmaterial')
|
||||||
|
for x in u['5.3']:
|
||||||
|
_sub(rm, 'p', x)
|
||||||
|
if isinstance(u.get('5.4'), list):
|
||||||
|
bib = _sub(c, 'bibliography')
|
||||||
|
for x in u['5.4']:
|
||||||
|
_sub(bib, 'bibref', x)
|
||||||
|
elif u.get('5.4'):
|
||||||
|
_paragrafos(c, 'bibliography', u['5.4'])
|
||||||
|
_paragrafos(c, 'odd', u.get('6.1'), head='Notas sobre conservação', localtype='conservacao')
|
||||||
|
_paragrafos(c, 'odd', texto(u, '6.2'), head='Notas gerais')
|
||||||
|
_paragrafos(c, 'processinfo', u.get('7.1'))
|
||||||
|
|
||||||
|
ca = u.get('8.1')
|
||||||
|
if isinstance(ca, dict):
|
||||||
|
ctl = _sub(c, 'controlaccess')
|
||||||
|
for s in ca.get('assuntos') or []:
|
||||||
|
_sub(_sub(ctl, 'subject', lang='por'), 'part', s)
|
||||||
|
for s in ca.get('assuntos_eng') or []:
|
||||||
|
_sub(_sub(ctl, 'subject', lang='eng'), 'part', s)
|
||||||
|
if u['1.3'].get('topica'):
|
||||||
|
_sub(_sub(ctl, 'geogname', localtype='data tópica'), 'part', u['1.3']['topica'])
|
||||||
|
for s in ca.get('lugares') or []:
|
||||||
|
_sub(_sub(ctl, 'geogname'), 'part', s)
|
||||||
|
for pr in u['2.1']:
|
||||||
|
if pr.get('id'):
|
||||||
|
_nome(ctl, pr['forma'], pr['id'], (aut.get(pr['id']) or {}).get('tipo'))
|
||||||
|
if len(ctl) == 0:
|
||||||
|
c.remove(ctl)
|
||||||
|
elif ca:
|
||||||
|
_paragrafos(c, 'processinfo', ca, head='Pontos de acesso e indexação')
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def _xmlid(cod: str) -> str:
|
||||||
|
return 'u-' + re.sub(r'[^\w.-]', '_', cod)
|
||||||
|
|
||||||
|
|
||||||
|
def ead(unidades: list[dict], aut: dict):
|
||||||
|
filhos = defaultdict(list)
|
||||||
|
por_id = {}
|
||||||
|
for u in unidades:
|
||||||
|
por_id[u['id']] = u
|
||||||
|
if u.get('pai'):
|
||||||
|
filhos[u['pai']].append(u['id'])
|
||||||
|
col = next(u for u in unidades if u['nivel'] == 1)
|
||||||
|
|
||||||
|
ET.register_namespace('', EAD)
|
||||||
|
raiz = ET.Element(f'{{{EAD}}}ead')
|
||||||
|
ctrl = _sub(raiz, 'control', langencoding='iso639-2b', scriptencoding='iso15924',
|
||||||
|
dateencoding='iso8601', countryencoding='iso3166-1', repositoryencoding='iso15511')
|
||||||
|
_sub(ctrl, 'recordid', col['id'])
|
||||||
|
fd = _sub(ctrl, 'filedesc')
|
||||||
|
ts = _sub(fd, 'titlestmt')
|
||||||
|
_sub(ts, 'titleproper', col['1.2']['titulo'])
|
||||||
|
_sub(ctrl, 'maintenancestatus', value='new')
|
||||||
|
ag = _sub(ctrl, 'maintenanceagency', countrycode=PAIS)
|
||||||
|
_sub(ag, 'agencycode', f'{PAIS}-{ENTIDADE}')
|
||||||
|
_sub(ag, 'agencyname', ENTIDADE_NOME)
|
||||||
|
ld = _sub(ctrl, 'languagedeclaration')
|
||||||
|
_sub(ld, 'language', 'português', langcode='por')
|
||||||
|
_sub(ld, 'script', 'latino', scriptcode='Latn')
|
||||||
|
cd = _sub(ctrl, 'conventiondeclaration')
|
||||||
|
_sub(cd, 'citation', REGRAS)
|
||||||
|
mh = _sub(ctrl, 'maintenancehistory')
|
||||||
|
ev = _sub(mh, 'maintenanceevent')
|
||||||
|
_sub(ev, 'eventtype', value='created')
|
||||||
|
_sub(ev, 'eventdatetime', HOJE, standarddatetime=HOJE)
|
||||||
|
_sub(ev, 'agenttype', value='machine')
|
||||||
|
_sub(ev, 'agent', 'pipeline/nobrade')
|
||||||
|
|
||||||
|
arch = _sub(raiz, 'archdesc', level='collection')
|
||||||
|
_componente(arch, col, aut, tag='archdesc')
|
||||||
|
rep = arch.find(f'{{{EAD}}}did')
|
||||||
|
r = _sub(rep, 'repository')
|
||||||
|
_sub(_sub(r, 'corpname', identifier=f'{PAIS}-{ENTIDADE}'), 'part', ENTIDADE_NOME)
|
||||||
|
dsc = _sub(arch, 'dsc')
|
||||||
|
|
||||||
|
def desce(pai_xml, cod):
|
||||||
|
for fid in sorted(filhos[cod], key=lambda x: (len(x), x)):
|
||||||
|
c = _componente(pai_xml, por_id[fid], aut)
|
||||||
|
desce(c, fid)
|
||||||
|
desce(dsc, col['id'])
|
||||||
|
|
||||||
|
(SAIDA / 'ead').mkdir(exist_ok=True)
|
||||||
|
ET.indent(raiz, space=' ')
|
||||||
|
ET.ElementTree(raiz).write(SAIDA / 'ead' / 'brasiliana.xml', encoding='utf-8', xml_declaration=True)
|
||||||
|
|
||||||
|
|
||||||
|
# ── EAC-CPF ──────────────────────────────────────────────────────────────────
|
||||||
|
def _c(pai, tag, txt=None, **attrs):
|
||||||
|
e = ET.SubElement(pai, f'{{{CPF}}}{tag}', {k.rstrip('_'): str(x) for k, x in attrs.items() if x is not None})
|
||||||
|
if txt is not None:
|
||||||
|
e.text = txt
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
def eac(autoridades: list[dict], usos: dict[str, list[str]]):
|
||||||
|
ET.register_namespace('', CPF)
|
||||||
|
ET.register_namespace('xlink', XLINK)
|
||||||
|
pasta = SAIDA / 'eac'
|
||||||
|
pasta.mkdir(exist_ok=True)
|
||||||
|
for a in autoridades:
|
||||||
|
raiz = ET.Element(f'{{{CPF}}}eac-cpf')
|
||||||
|
ctrl = _c(raiz, 'control')
|
||||||
|
_c(ctrl, 'recordId', f"{PAIS}-{ENTIDADE}-{a['id']}")
|
||||||
|
_c(ctrl, 'maintenanceStatus', 'new')
|
||||||
|
ag = _c(ctrl, 'maintenanceAgency')
|
||||||
|
_c(ag, 'agencyCode', f'{PAIS}-{ENTIDADE}')
|
||||||
|
_c(ag, 'agencyName', ENTIDADE_NOME)
|
||||||
|
ld = _c(ctrl, 'languageDeclaration')
|
||||||
|
_c(ld, 'language', 'português', languageCode='por')
|
||||||
|
_c(ld, 'script', 'latino', scriptCode='Latn')
|
||||||
|
cd = _c(ctrl, 'conventionDeclaration')
|
||||||
|
_c(cd, 'citation', 'ISAAR(CPF) 2ª ed.; NOBRADE (CONARQ, 2006), proc. 8.1.3–8.1.4')
|
||||||
|
mh = _c(ctrl, 'maintenanceHistory')
|
||||||
|
ev = _c(mh, 'maintenanceEvent')
|
||||||
|
_c(ev, 'eventType', 'created')
|
||||||
|
_c(ev, 'eventDateTime', HOJE, standardDateTime=HOJE)
|
||||||
|
_c(ev, 'agentType', 'machine')
|
||||||
|
_c(ev, 'agent', 'pipeline/nobrade')
|
||||||
|
if a['fontes']:
|
||||||
|
src = _c(ctrl, 'sources')
|
||||||
|
for f in a['fontes']:
|
||||||
|
s = _c(src, 'source')
|
||||||
|
_c(s, 'sourceEntry', f)
|
||||||
|
|
||||||
|
cpf = _c(raiz, 'cpfDescription')
|
||||||
|
ident = _c(cpf, 'identity')
|
||||||
|
_c(ident, 'entityType', {'entidade coletiva': 'corporateBody', 'família': 'family'}.get(a['tipo'], 'person'))
|
||||||
|
ne = _c(ident, 'nameEntry', localType='autorizada')
|
||||||
|
_c(ne, 'part', a['nome'])
|
||||||
|
if a['datas_existencia']:
|
||||||
|
_c(ne, 'useDates').append(_data_eac(a['datas_existencia']))
|
||||||
|
_c(ne, 'authorizedForm', 'NOBRADE')
|
||||||
|
for v in a['variantes']:
|
||||||
|
nv = _c(ident, 'nameEntry', localType='variante')
|
||||||
|
_c(nv, 'part', v)
|
||||||
|
_c(nv, 'alternativeForm', 'NOBRADE')
|
||||||
|
desc = _c(cpf, 'description')
|
||||||
|
if a['datas_existencia']:
|
||||||
|
ex = _c(desc, 'existDates')
|
||||||
|
ex.append(_data_eac(a['datas_existencia']))
|
||||||
|
bh = _c(desc, 'biogHist')
|
||||||
|
_c(bh, 'p', f"Autor de {a['ocorrencias']} dossiês da Coleção Brasiliana Fotográfica (cópia digital)."
|
||||||
|
+ (f" Tipo presumido: {a['tipo']}." if a['tipo'] == 'pessoa ou entidade' else ''))
|
||||||
|
if usos.get(a['id']):
|
||||||
|
rel = _c(cpf, 'relations')
|
||||||
|
for cod in usos[a['id']][:500]:
|
||||||
|
r = _c(rel, 'resourceRelation', resourceRelationType='creatorOf')
|
||||||
|
_c(r, 'relationEntry', cod)
|
||||||
|
ET.indent(raiz, space=' ')
|
||||||
|
ET.ElementTree(raiz).write(pasta / f"{a['id']}.xml", encoding='utf-8', xml_declaration=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _data_eac(datas: str):
|
||||||
|
anos = re.findall(r'\d{4}', datas)
|
||||||
|
if len(anos) >= 2:
|
||||||
|
e = ET.Element(f'{{{CPF}}}dateRange')
|
||||||
|
_c(e, 'fromDate', datas.split('-')[0].strip(), standardDate=anos[0])
|
||||||
|
_c(e, 'toDate', datas.split('-')[-1].strip(), standardDate=anos[1])
|
||||||
|
return e
|
||||||
|
e = ET.Element(f'{{{CPF}}}date', standardDate=anos[0] if anos else None)
|
||||||
|
e.text = datas
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
# ── AtoM (modelo CSV ISAD da versão 2.x) ────────────────────────────────────
|
||||||
|
ATOM = ['legacyId', 'parentId', 'identifier', 'title', 'levelOfDescription', 'extentAndMedium',
|
||||||
|
'repository', 'archivalHistory', 'acquisition', 'scopeAndContent', 'appraisal', 'accruals',
|
||||||
|
'arrangement', 'accessConditions', 'reproductionConditions', 'language', 'physicalCharacteristics',
|
||||||
|
'findingAids', 'locationOfOriginals', 'locationOfCopies', 'relatedUnitsOfDescription',
|
||||||
|
'publicationNote', 'generalNote', 'subjectAccessPoints', 'placeAccessPoints', 'nameAccessPoints',
|
||||||
|
'descriptionIdentifier', 'rules', 'archivistNote', 'eventDates', 'eventTypes', 'eventStartDates',
|
||||||
|
'eventEndDates', 'eventActors', 'culture']
|
||||||
|
NIVEL_ATOM = {1: 'Coleção', 2: 'Seção', 3: 'Série', 4: 'Dossiê', 5: 'Item documental'}
|
||||||
|
|
||||||
|
|
||||||
|
def atom(unidades: list[dict]):
|
||||||
|
with (SAIDA / 'atom.csv').open('w', encoding='utf-8', newline='') as f:
|
||||||
|
w = csv.DictWriter(f, fieldnames=ATOM)
|
||||||
|
w.writeheader()
|
||||||
|
for u in unidades:
|
||||||
|
if u['nivel'] == 0:
|
||||||
|
continue
|
||||||
|
p = u['1.3'].get('producao') or {}
|
||||||
|
ca = u.get('8.1') if isinstance(u.get('8.1'), dict) else {}
|
||||||
|
w.writerow({
|
||||||
|
'legacyId': u['id'], 'parentId': u['pai'] if u['nivel'] > 1 else '',
|
||||||
|
'identifier': u['1.1'].split('.')[-1] if u['nivel'] > 1 else u['1.1'],
|
||||||
|
'title': u['1.2']['titulo'], 'levelOfDescription': NIVEL_ATOM[u['nivel']],
|
||||||
|
'extentAndMedium': texto(u, '1.5'), 'repository': ENTIDADE_NOME,
|
||||||
|
'archivalHistory': u.get('2.3'), 'acquisition': u.get('2.4'),
|
||||||
|
'scopeAndContent': u.get('3.1'), 'appraisal': u.get('3.2'), 'accruals': u.get('3.3'),
|
||||||
|
'arrangement': u.get('3.4'), 'accessConditions': u.get('4.1'),
|
||||||
|
'reproductionConditions': texto(u, '4.2'),
|
||||||
|
'language': '|'.join(i['codigo'] for i in u['4.3']) if isinstance(u.get('4.3'), list) else '',
|
||||||
|
'physicalCharacteristics': u.get('4.4'), 'findingAids': u.get('4.5'),
|
||||||
|
'locationOfOriginals': texto(u, '5.1'), 'locationOfCopies': texto(u, '5.2'),
|
||||||
|
'relatedUnitsOfDescription': texto(u, '5.3'), 'publicationNote': texto(u, '5.4'),
|
||||||
|
'generalNote': '\n'.join(x for x in [u.get('6.1'), texto(u, '6.2')] if x),
|
||||||
|
'subjectAccessPoints': '|'.join(ca.get('assuntos') or []),
|
||||||
|
'placeAccessPoints': '|'.join(ca.get('lugares') or []),
|
||||||
|
'nameAccessPoints': '|'.join(ca.get('nomes') or []),
|
||||||
|
'descriptionIdentifier': u['id'], 'rules': u.get('7.2') or '',
|
||||||
|
'archivistNote': u.get('7.1'),
|
||||||
|
'eventDates': p.get('forma'), 'eventTypes': 'Produção',
|
||||||
|
'eventStartDates': f"{p['inicio']}-01-01" if p.get('inicio') else '',
|
||||||
|
'eventEndDates': f"{p['fim']}-12-31" if p.get('fim') else '',
|
||||||
|
'eventActors': '|'.join(x['forma'] for x in u['2.1'] if x.get('id')),
|
||||||
|
'culture': 'pt_BR',
|
||||||
|
})
|
||||||
@@ -0,0 +1,487 @@
|
|||||||
|
"""Monta a descrição multinível (níveis 0–5) a partir do catálogo, do ledger do
|
||||||
|
bucket e dos posts do blog. Escreve descricao/unidades.jsonl,
|
||||||
|
descricao/autoridades.jsonl e as tabelas de revisão.
|
||||||
|
|
||||||
|
Cada unidade é um objeto com `id` (= código de referência), `pai`, `nivel` e os
|
||||||
|
elementos da NOBRADE pelo número: "1.1", "1.2", … "8.1".
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import ast
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sqlite3
|
||||||
|
from collections import Counter, defaultdict
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
import polars as pl
|
||||||
|
|
||||||
|
from . import campos, datas, series
|
||||||
|
from .autoridades import Autoridades
|
||||||
|
from .config import (ACESSO, BUCKET, CATALOGO, COLECAO, COLECAO_TITULO, ENTIDADE_NOME, HANDLE_URL,
|
||||||
|
INSTITUICOES, LEDGER, ORIGEM_NOME, ORIGEM_SITE, POSTS, REGRAS, RESPONSAVEL, REVISAO,
|
||||||
|
SAIDA, TEXTOS, codigo)
|
||||||
|
|
||||||
|
NIVEIS = {0: 'acervo da entidade custodiadora', 1: 'coleção', 2: 'seção', 3: 'série',
|
||||||
|
4: 'dossiê', 5: 'item documental'}
|
||||||
|
MESES_ABNT = ['jan.', 'fev.', 'mar.', 'abr.', 'maio', 'jun.', 'jul.', 'ago.', 'set.', 'out.', 'nov.', 'dez.']
|
||||||
|
HOJE = date.today().isoformat()
|
||||||
|
|
||||||
|
|
||||||
|
# ── leitura das fontes ──────────────────────────────────────────────────────
|
||||||
|
def _valores(item: dict) -> dict[str, list[str]]:
|
||||||
|
vs = defaultdict(list)
|
||||||
|
for row in item.get('full_table') or []:
|
||||||
|
v = (row.get('value') or '').strip()
|
||||||
|
if v and v not in vs[row['field']]:
|
||||||
|
vs[row['field']].append(v)
|
||||||
|
return vs
|
||||||
|
|
||||||
|
|
||||||
|
def _ledger() -> dict[str, list[dict]]:
|
||||||
|
arquivos = defaultdict(list)
|
||||||
|
if not LEDGER.exists():
|
||||||
|
return arquivos
|
||||||
|
con = sqlite3.connect(LEDGER)
|
||||||
|
for h, nome, b, sha, quando, tipo in con.execute(
|
||||||
|
'select handle, nome, bytes, sha256, quando, tipo from enviados order by handle, tipo, nome'):
|
||||||
|
arquivos[h].append({'nome': nome, 'bytes': b, 'sha256': sha, 'quando': quando, 'tipo': tipo})
|
||||||
|
return arquivos
|
||||||
|
|
||||||
|
|
||||||
|
def _abnt(post: dict) -> str:
|
||||||
|
autor = (post.get('autor') or '').strip()
|
||||||
|
partes = autor.split()
|
||||||
|
autor_abnt = f'{partes[-1].upper()}, {" ".join(partes[:-1])}' if len(partes) > 1 else autor.upper()
|
||||||
|
d = datetime.fromisoformat(post['data_iso'][:10])
|
||||||
|
acesso = (post.get('fetched_at') or HOJE)[:10]
|
||||||
|
a = datetime.fromisoformat(acesso)
|
||||||
|
return (f"{autor_abnt}. {post['titulo']}. {ORIGEM_NOME}, Rio de Janeiro, "
|
||||||
|
f"{d.day} {MESES_ABNT[d.month - 1]} {d.year}. Disponível em: {post['url']}. "
|
||||||
|
f"Acesso em: {a.day} {MESES_ABNT[a.month - 1]} {a.year}.")
|
||||||
|
|
||||||
|
|
||||||
|
def _posts() -> tuple[dict[str, list[dict]], list[dict]]:
|
||||||
|
por_handle, todos = defaultdict(list), []
|
||||||
|
if not POSTS.exists():
|
||||||
|
return por_handle, todos
|
||||||
|
for linha in POSTS.open(encoding='utf-8'):
|
||||||
|
p = json.loads(linha)
|
||||||
|
if p.get('erro') or not p.get('titulo'):
|
||||||
|
continue
|
||||||
|
hs = p.get('handles_referenciados') or []
|
||||||
|
if isinstance(hs, str):
|
||||||
|
hs = ast.literal_eval(hs)
|
||||||
|
cats = p.get('categorias') or []
|
||||||
|
if isinstance(cats, str):
|
||||||
|
cats = ast.literal_eval(cats)
|
||||||
|
ref = {'titulo': p['titulo'], 'url': p['url'], 'autor': p.get('autor'), 'data': p['data_iso'][:10],
|
||||||
|
'categorias': cats, 'abnt': _abnt(p)}
|
||||||
|
todos.append(ref)
|
||||||
|
for h in hs:
|
||||||
|
por_handle[h].append(ref)
|
||||||
|
return por_handle, todos
|
||||||
|
|
||||||
|
|
||||||
|
def _textos(caminho) -> dict[str, str]:
|
||||||
|
"""Um .md com seções "## 2.3 História arquivística" → {'2.3': texto}."""
|
||||||
|
if not caminho.exists():
|
||||||
|
return {}
|
||||||
|
out, atual, buf = {}, None, []
|
||||||
|
for linha in caminho.read_text(encoding='utf-8').splitlines():
|
||||||
|
if m := re.match(r'^##\s+(\d\.\d)\b', linha):
|
||||||
|
if atual:
|
||||||
|
out[atual] = '\n'.join(buf).strip()
|
||||||
|
atual, buf = m[1], []
|
||||||
|
elif atual:
|
||||||
|
buf.append(linha)
|
||||||
|
if atual:
|
||||||
|
out[atual] = '\n'.join(buf).strip()
|
||||||
|
return {k: v for k, v in out.items() if v}
|
||||||
|
|
||||||
|
|
||||||
|
def _mb(b: int) -> str:
|
||||||
|
return f'{b / 1e6:.1f} MB'.replace('.', ',') if b < 1e9 else f'{b / 1e9:.1f} GB'.replace('.', ',')
|
||||||
|
|
||||||
|
|
||||||
|
def _formato(nome: str) -> str:
|
||||||
|
ext = nome.rsplit('.', 1)[-1].lower() if '.' in nome else ''
|
||||||
|
return {'jpg': 'JPEG', 'jpeg': 'JPEG', 'png': 'PNG', 'tif': 'TIFF', 'tiff': 'TIFF', 'webp': 'WebP',
|
||||||
|
'pdf': 'PDF', 'gif': 'GIF'}.get(ext, ext.upper() or 'desconhecido')
|
||||||
|
|
||||||
|
|
||||||
|
def _limites(ds: list[dict]) -> dict:
|
||||||
|
ini = [d['inicio'] for d in ds if d and d.get('inicio')]
|
||||||
|
fim = [d['fim'] for d in ds if d and d.get('fim')]
|
||||||
|
if not ini and not fim:
|
||||||
|
return {'forma': '[s.d.]', 'iso': None, 'inicio': None, 'fim': None, 'qualidade': None,
|
||||||
|
'tipo': 'produção'}
|
||||||
|
a, b = min(ini or fim), max(fim or ini)
|
||||||
|
return {'forma': f'{a}-{b}' if a != b else str(a), 'iso': f'{a}/{b}' if a != b else str(a),
|
||||||
|
'inicio': a, 'fim': b, 'qualidade': 'datas-limite', 'tipo': 'produção'}
|
||||||
|
|
||||||
|
|
||||||
|
def _dimensao(especies: Counter, n_itens: int, bytes_: int) -> dict:
|
||||||
|
partes = [f'{n} {e}' for e, n in especies.most_common()]
|
||||||
|
return {'por_especie': dict(especies), 'arquivos_digitais': n_itens, 'bytes': bytes_,
|
||||||
|
'texto': f"iconográfico: {', '.join(partes)}; eletrônico: {n_itens} arquivos digitais ({_mb(bytes_)})"}
|
||||||
|
|
||||||
|
|
||||||
|
# ── montagem ────────────────────────────────────────────────────────────────
|
||||||
|
def monta():
|
||||||
|
SAIDA.mkdir(exist_ok=True)
|
||||||
|
REVISAO.mkdir(parents=True, exist_ok=True)
|
||||||
|
ledger = _ledger()
|
||||||
|
posts_de, posts = _posts()
|
||||||
|
|
||||||
|
itens = []
|
||||||
|
for linha in CATALOGO.open(encoding='utf-8'):
|
||||||
|
if linha.strip():
|
||||||
|
it = json.loads(linha)
|
||||||
|
it['_v'] = _valores(it)
|
||||||
|
itens.append(it)
|
||||||
|
|
||||||
|
# séries (nível 3)
|
||||||
|
fontes = [(it['handle'], it['community'], (it['_v']['dc.source'] or [None])[0]) for it in itens]
|
||||||
|
serie_de, series_ = series.monta(fontes)
|
||||||
|
|
||||||
|
# autoridades
|
||||||
|
aut = Autoridades()
|
||||||
|
for it in itens:
|
||||||
|
for f in ('dc.contributor', 'dc.contributor.author', 'dc.contributor.other'):
|
||||||
|
for v in it['_v'][f]:
|
||||||
|
aut.registra(v)
|
||||||
|
aut.resolve()
|
||||||
|
for reg in aut.registros.values(): # biografias no blog (3.4) → fontes da autoridade
|
||||||
|
if reg['tipo'] == 'pessoa' and ',' in reg['nome']:
|
||||||
|
sob, nome = [x.strip() for x in reg['nome'].split(',', 1)]
|
||||||
|
primeiro = nome.split()[0] if nome else ''
|
||||||
|
for p in posts:
|
||||||
|
if 'Biografia' in p['categorias'] and sob in p['titulo'] and primeiro in p['titulo']:
|
||||||
|
reg['fontes'].append(p['abnt'])
|
||||||
|
|
||||||
|
unidades: dict[str, dict] = {}
|
||||||
|
filhos = defaultdict(list)
|
||||||
|
rev_datas, rev_tipos, rev_direitos, rev_lugares = [], [], [], []
|
||||||
|
|
||||||
|
def add(u: dict):
|
||||||
|
unidades[u['id']] = u
|
||||||
|
if u['pai']:
|
||||||
|
filhos[u['pai']].append(u['id'])
|
||||||
|
|
||||||
|
# níveis 4 e 5
|
||||||
|
for it in itens:
|
||||||
|
v, h = it['_v'], it['handle']
|
||||||
|
inst = it['community']
|
||||||
|
sigla_i, nome_i, cidade_i = INSTITUICOES[inst]
|
||||||
|
sg, notacao = serie_de[h]
|
||||||
|
num = h.rsplit('/', 1)[-1]
|
||||||
|
cod = codigo(COLECAO, sigla_i, sg, num)
|
||||||
|
pasta = h.replace('/', '_')
|
||||||
|
|
||||||
|
titulo = (v['dc.title'] or [it.get('title') or ''])[0].strip()
|
||||||
|
titulo_atribuido = False
|
||||||
|
if not titulo: # proc. 1.2: título atribuído a partir da própria unidade, entre colchetes
|
||||||
|
base = next((x for x in v['dc.description'] + v['dc.subject'] + v['dc.coverage']
|
||||||
|
if not campos.corrompido(x)), 'Sem título')
|
||||||
|
titulo, titulo_atribuido = f"[{base.split('. ')[0][:90]}]", True
|
||||||
|
d = datas.interpreta((v['dc.date'] or [''])[0])
|
||||||
|
data = d.registro()
|
||||||
|
if len(v['dc.date']) > 1:
|
||||||
|
data['notas'] = (data['notas'] or []) + [f'outra data na origem: {x}' for x in v['dc.date'][1:]]
|
||||||
|
|
||||||
|
produtores = []
|
||||||
|
for f in ('dc.contributor', 'dc.contributor.author', 'dc.contributor.other'):
|
||||||
|
for nome in v[f]:
|
||||||
|
aid = aut.id(nome)
|
||||||
|
if aid and aid not in [p['id'] for p in produtores]:
|
||||||
|
produtores.append({'id': aid, 'forma': aut[aid]['forma_autorizada'],
|
||||||
|
'funcao': 'autor' if f != 'dc.contributor.other' else 'outro'})
|
||||||
|
if not produtores:
|
||||||
|
produtores = [{'id': None, 'forma': 'Autoria não identificada', 'funcao': 'autor'}]
|
||||||
|
|
||||||
|
descricoes = [x for x in v['dc.description'] if not campos.corrompido(x)]
|
||||||
|
fisico = [x for x in descricoes if campos.e_fisico(x)]
|
||||||
|
conteudo = [x for x in descricoes if x not in fisico]
|
||||||
|
esp = campos.especie((v['dc.type'] or [None])[0])
|
||||||
|
cor = campos.cor(fisico)
|
||||||
|
|
||||||
|
arquivos = ledger.get(h, [])
|
||||||
|
preserv = sorted((a for a in arquivos if a['tipo'] == 'preservacao'),
|
||||||
|
key=lambda a: (a['nome'] != 'imagem.jpg', a['nome']))
|
||||||
|
imagens = preserv or [a for a in arquivos if a['tipo'] == 'thumbnail']
|
||||||
|
total = sum(a['bytes'] or 0 for a in imagens)
|
||||||
|
|
||||||
|
direitos = campos.direitos(v['dc.rights'] + [str(it.get('rights') or '')], nome_i)
|
||||||
|
lugar = campos.lugar(v['dc.coverage'])
|
||||||
|
assuntos = [s for s in v['dc.subject'] if not campos.corrompido(s)]
|
||||||
|
codigo_origem = next((re.sub(r'\.\w{3,4}$', '', x) for x in v['dc.identifier'] + v['dc.description']
|
||||||
|
if re.match(r'BR ?[A-Z]{2}[A-Z]{2,}\s', x)), None)
|
||||||
|
sophia = next((x for x in v['dc.relation'] if 'sophia' in x), None)
|
||||||
|
objdigital = [x for x in v['dc.identifier'] if 'objdigital' in x]
|
||||||
|
|
||||||
|
notas = ['Título atribuído pelo arquivista: a origem não informa título.'] if titulo_atribuido else []
|
||||||
|
if d.original and data['forma'] != d.original:
|
||||||
|
notas.append(f'Data como consta na origem: {d.original}')
|
||||||
|
notas += data['notas'] or []
|
||||||
|
if esp['presumida']:
|
||||||
|
notas.append('Espécie documental não informada na origem; presumida fotografia'
|
||||||
|
+ (f" (valor na origem: {esp['original']})" if esp.get('original') else '') + '.')
|
||||||
|
if direitos['originais']:
|
||||||
|
notas.append('Direitos como constam na origem: ' + ' | '.join(direitos['originais']))
|
||||||
|
lixo = [f"{f}: {x[:60]}" for f, xs in v.items() for x in xs if campos.corrompido(x)
|
||||||
|
and f in ('dc.type', 'dc.rights', 'dc.source', 'dc.subject', 'dc.date', 'dc.coverage')]
|
||||||
|
if lixo:
|
||||||
|
notas.append('Valores corrompidos na origem, desconsiderados: ' + '; '.join(lixo))
|
||||||
|
|
||||||
|
conservacao = None
|
||||||
|
if not preserv:
|
||||||
|
conservacao = ('Arquivo de preservação indisponível na origem (o repositório responde HTTP 500 '
|
||||||
|
'ao bitstream; ver errors.md). A cópia guarda apenas a miniatura gerada pelo DSpace.')
|
||||||
|
|
||||||
|
dossie = {
|
||||||
|
'id': cod, 'pai': codigo(COLECAO, sigla_i, sg), 'nivel': 4, 'handle': h,
|
||||||
|
'1.1': cod,
|
||||||
|
'1.2': {'titulo': titulo, 'atribuido': titulo.startswith('[')},
|
||||||
|
'1.3': {'producao': data, 'topica': lugar},
|
||||||
|
'1.4': {'nivel': 4, 'nome': NIVEIS[4]},
|
||||||
|
'1.5': {'genero': esp['genero'], 'especie': esp['especie'], 'suporte': esp['suporte'], 'cor': cor,
|
||||||
|
'fisico': fisico or None, 'arquivos_digitais': len(imagens), 'bytes': total,
|
||||||
|
'texto': (f"1 {esp['especie']}" + (f' {cor}' if cor else '')
|
||||||
|
+ (f", {esp['suporte']}" if esp['suporte'] else '')
|
||||||
|
+ (f" ({'; '.join(fisico)})" if fisico else '')
|
||||||
|
+ f"; {len(imagens)} arquivo{'s' if len(imagens) != 1 else ''} digita"
|
||||||
|
+ f"{'is' if len(imagens) != 1 else 'l'} ({_mb(total)})")},
|
||||||
|
'2.1': produtores,
|
||||||
|
'2.3': (f"Registrado no repositório DSpace da {ORIGEM_NOME}"
|
||||||
|
+ (f" em {v['dc.date.accessioned'][0][:10]}" if v['dc.date.accessioned'] else '')
|
||||||
|
+ f". Cópia digital capturada em {it['fetched_at'][:10]} e armazenada em "
|
||||||
|
f"{BUCKET}/itens/{pasta}/ com SHA-256 de cada arquivo."),
|
||||||
|
'2.4': (f"{ORIGEM_NOME} ({ORIGEM_SITE}), repositório mantido pela Biblioteca Nacional; "
|
||||||
|
f"coleta combinada com a Biblioteca Nacional, em {it['fetched_at'][:10]}. Handle {h}."),
|
||||||
|
'3.1': ' '.join(conteudo) or None,
|
||||||
|
'4.2': direitos,
|
||||||
|
'4.3': campos.idiomas(v['dc.language']) or None,
|
||||||
|
'4.4': (f"Arquivo{'s' if len(imagens) > 1 else ''} digita{'is' if len(imagens) > 1 else 'l'} "
|
||||||
|
f"{', '.join(sorted({_formato(a['nome']) for a in imagens})) or '—'}; "
|
||||||
|
'abre em qualquer visualizador de imagem.'
|
||||||
|
+ (f" Original: {'; '.join(fisico)}." if fisico else '')),
|
||||||
|
'5.1': {'instituicao': nome_i, 'local': cidade_i, 'url': HANDLE_URL.format(h),
|
||||||
|
'codigo_na_origem': codigo_origem, 'notacao_na_origem': notacao, 'sophia': sophia,
|
||||||
|
'texto': f"Original sob a guarda de {nome_i}, {cidade_i}"
|
||||||
|
+ (f", código {codigo_origem}" if codigo_origem else '')
|
||||||
|
+ (f", notação {notacao}" if notacao else '') + f". {HANDLE_URL.format(h)}"},
|
||||||
|
'5.2': {'nesta_entidade': [{'tipo': a['tipo'], 'chave': (f"{BUCKET}/derivados/thumb256/{a['nome']}"
|
||||||
|
if a['tipo'] == 'derivado-thumb256'
|
||||||
|
else f"{BUCKET}/itens/{pasta}/{a['tipo']}/{a['nome']}"),
|
||||||
|
'bytes': a['bytes'], 'sha256': a['sha256']} for a in arquivos],
|
||||||
|
'em_outras_entidades': [{'entidade': 'Biblioteca Nacional (Brasil) — BNDigital', 'url': u}
|
||||||
|
for u in objdigital] or None},
|
||||||
|
'5.3': (v['dc.relation.ispartof'] + v['dcterms.relation']) or None,
|
||||||
|
'5.4': [p['abnt'] for p in posts_de.get(h, [])] or None,
|
||||||
|
'6.1': conservacao,
|
||||||
|
'6.2': notas or None,
|
||||||
|
'7.1': (f'Descrição gerada pelo pipeline/nobrade a partir dos metadados Dublin Core colhidos '
|
||||||
|
f'da {ORIGEM_NOME} ({it["source_url"]}); responsável: {RESPONSAVEL}.'),
|
||||||
|
'7.3': {'coleta': it['fetched_at'][:10], 'descricao': HOJE},
|
||||||
|
'8.1': {'assuntos': [s for s in assuntos if campos.idioma_termo(s) == 'por'] or None,
|
||||||
|
'assuntos_eng': [s for s in assuntos if campos.idioma_termo(s) == 'eng'] or None,
|
||||||
|
'lugares': [c for c in v['dc.coverage'] if not campos.corrompido(c)] or None,
|
||||||
|
'nomes': [p['forma'] for p in produtores if p['id']] or None,
|
||||||
|
'periodo': data['iso']},
|
||||||
|
'_sd': not d.ok, '_especie': esp['especie'], '_serie': (inst, sg),
|
||||||
|
}
|
||||||
|
add(dossie)
|
||||||
|
rev_datas.append({'handle': h, 'original': d.original, 'forma': data['forma'], 'iso': data['iso'],
|
||||||
|
'inicio': data['inicio'], 'fim': data['fim'], 'qualidade': data['qualidade'],
|
||||||
|
'motivo': data['motivo']})
|
||||||
|
rev_tipos.append({'instituicao': inst, 'dc_type': (v['dc.type'] or [''])[0], 'genero': esp['genero'],
|
||||||
|
'especie': esp['especie'], 'suporte': esp['suporte'] or '', 'presumida': esp['presumida']})
|
||||||
|
rev_direitos.append({'instituicao': inst, 'categoria': direitos['categoria'], 'detentor': direitos['detentor'],
|
||||||
|
'originais': ' | '.join(direitos['originais'] or [])})
|
||||||
|
rev_lugares.append({'coverage': ' | '.join(v['dc.coverage']), 'data_topica': lugar or ''})
|
||||||
|
|
||||||
|
for i, a in enumerate(imagens, 1):
|
||||||
|
ci = f'{cod}.{i:02d}'
|
||||||
|
add({
|
||||||
|
'id': ci, 'pai': cod, 'nivel': 5, 'handle': h,
|
||||||
|
'1.1': ci,
|
||||||
|
'1.2': {'titulo': f"{titulo} [imagem {i} de {len(imagens)}]", 'atribuido': True},
|
||||||
|
'1.3': {'producao': data},
|
||||||
|
'1.4': {'nivel': 5, 'nome': NIVEIS[5]},
|
||||||
|
'1.5': {'genero': 'eletrônico', 'especie': 'arquivo de imagem', 'bytes': a['bytes'],
|
||||||
|
'texto': f"1 arquivo digital {_formato(a['nome'])} ({_mb(a['bytes'] or 0)})"},
|
||||||
|
'2.1': produtores,
|
||||||
|
'4.4': f"{_formato(a['nome'])}; SHA-256 {a['sha256']}"
|
||||||
|
+ ('; miniatura — preservação indisponível na origem' if a['tipo'] == 'thumbnail' else ''),
|
||||||
|
'5.2': {'nesta_entidade': [{'tipo': a['tipo'], 'chave': f"{BUCKET}/itens/{pasta}/{a['tipo']}/{a['nome']}",
|
||||||
|
'bytes': a['bytes'], 'sha256': a['sha256']}]},
|
||||||
|
'7.3': {'descricao': HOJE},
|
||||||
|
})
|
||||||
|
|
||||||
|
# níveis 3, 2, 1, 0 — de baixo para cima, agregando os filhos
|
||||||
|
textos1 = _textos(TEXTOS / 'nivel1.md')
|
||||||
|
textos0 = _textos(TEXTOS / 'nivel0.md')
|
||||||
|
por_serie = defaultdict(list)
|
||||||
|
for u in unidades.values():
|
||||||
|
if u['nivel'] == 4:
|
||||||
|
por_serie[u['_serie']].append(u)
|
||||||
|
|
||||||
|
# datas atribuídas aos s.d. (proc. 1.3.3.2): período do fotógrafo, senão datas-limite da série
|
||||||
|
rev_por_handle = {r['handle']: r for r in rev_datas}
|
||||||
|
lim_secao = {inst: _limites([u['1.3']['producao'] for (i, _), us in por_serie.items() if i == inst
|
||||||
|
for u in us if not u['_sd']]) for inst, _ in por_serie}
|
||||||
|
lim_serie = {k: _limites([u['1.3']['producao'] for u in us if not u['_sd']]) for k, us in por_serie.items()}
|
||||||
|
for k, us in por_serie.items():
|
||||||
|
for u in us:
|
||||||
|
if not u['_sd']:
|
||||||
|
continue
|
||||||
|
per = next((aut[p['id']]['periodo_atividade'] for p in u['2.1']
|
||||||
|
if p['id'] and aut[p['id']]['periodo_atividade']), None)
|
||||||
|
if per:
|
||||||
|
nova = datas.atribuida(*per, 'período de atividade do autor')
|
||||||
|
elif lim_serie[k]['inicio']:
|
||||||
|
nova = datas.atribuida(lim_serie[k]['inicio'], lim_serie[k]['fim'], 'datas-limite da série')
|
||||||
|
elif lim_secao[k[0]]['inicio']:
|
||||||
|
nova = datas.atribuida(lim_secao[k[0]]['inicio'], lim_secao[k[0]]['fim'],
|
||||||
|
'datas-limite da instituição de origem')
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
nova['original'] = u['1.3']['producao']['original']
|
||||||
|
nova['notas'] = nova['notas'] + (u['1.3']['producao']['notas'] or [])
|
||||||
|
u['1.3']['producao'] = nova
|
||||||
|
u['8.1']['periodo'] = nova['iso']
|
||||||
|
for fid in filhos[u['id']]:
|
||||||
|
unidades[fid]['1.3']['producao'] = nova
|
||||||
|
r = rev_por_handle[u['handle']]
|
||||||
|
r.update(forma=nova['forma'], iso=nova['iso'], inicio=nova['inicio'], fim=nova['fim'],
|
||||||
|
qualidade='atribuída pelo arquivista')
|
||||||
|
|
||||||
|
def agrega(us: list[dict]) -> dict:
|
||||||
|
esp = Counter(u['_especie'] for u in us)
|
||||||
|
n = sum(u['1.5']['arquivos_digitais'] for u in us)
|
||||||
|
b = sum(u['1.5']['bytes'] for u in us)
|
||||||
|
autores = Counter(p['forma'] for u in us for p in u['2.1'] if p['id'])
|
||||||
|
lugares = Counter(u['1.3']['topica'] for u in us if u['1.3'].get('topica'))
|
||||||
|
return {'data': _limites([u['1.3']['producao'] for u in us]), 'dim': _dimensao(esp, n, b),
|
||||||
|
'autores': autores, 'lugares': lugares, 'dossies': len(us)}
|
||||||
|
|
||||||
|
def resumo(a: dict) -> str:
|
||||||
|
s = f"{a['dossies']} dossiês, {a['data']['forma']}."
|
||||||
|
if a['autores']:
|
||||||
|
s += ' Principais autores: ' + '; '.join(f'{k} ({n})' for k, n in a['autores'].most_common(5)) + '.'
|
||||||
|
if a['lugares']:
|
||||||
|
s += ' Principais lugares: ' + '; '.join(f'{k} ({n})' for k, n in a['lugares'].most_common(5)) + '.'
|
||||||
|
return s
|
||||||
|
|
||||||
|
rev_series = []
|
||||||
|
por_secao = defaultdict(list)
|
||||||
|
for (inst, sg), us in sorted(por_serie.items()):
|
||||||
|
sigla_i, nome_i, cidade_i = INSTITUICOES[inst]
|
||||||
|
info = series_[(inst, sg)]
|
||||||
|
cod = codigo(COLECAO, sigla_i, sg)
|
||||||
|
a = agrega(us)
|
||||||
|
t = _textos(TEXTOS / 'series' / f'{sigla_i}.{sg}.md')
|
||||||
|
titulo = info['titulo'] if sg != 'AV' else f'Avulsos — {nome_i}'
|
||||||
|
produtor = re.sub(r'(?i)^(cole[cç][aã]o( particular)?|fundo|arquivo|s[ée]rie|conv[eê]nio)\s+(d[aeo]s?\s+)?', '', titulo)
|
||||||
|
add({
|
||||||
|
'id': cod, 'pai': codigo(COLECAO, sigla_i), 'nivel': 3,
|
||||||
|
'1.1': cod, '1.2': {'titulo': titulo, 'atribuido': sg == 'AV'},
|
||||||
|
'1.3': {'producao': a['data']}, '1.4': {'nivel': 3, 'nome': NIVEIS[3]},
|
||||||
|
'1.5': a['dim'],
|
||||||
|
'2.1': [{'id': None, 'forma': nome_i if sg == 'AV' else produtor, 'funcao': 'colecionador'}],
|
||||||
|
'2.2': t.get('2.2'),
|
||||||
|
'3.1': t.get('3.1') or resumo(a),
|
||||||
|
'3.4': t.get('3.4') or ('Dossiês ordenados pelo número do handle na origem.' if sg != 'AV' else
|
||||||
|
'Reúne os dossiês sem coleção/fundo de origem identificável em dc.source; '
|
||||||
|
'a notação da origem, quando há, fica em 5.1 de cada dossiê.'),
|
||||||
|
'5.1': {'instituicao': nome_i, 'local': cidade_i,
|
||||||
|
'variantes_na_origem': dict(info['variantes'].most_common()) or None},
|
||||||
|
'7.3': {'descricao': HOJE},
|
||||||
|
})
|
||||||
|
por_secao[inst].extend(us)
|
||||||
|
for var, n in (info['variantes'].most_common() or [('', info['n'])]):
|
||||||
|
rev_series.append({'instituicao': inst, 'codigo': cod, 'titulo': titulo, 'dc_source': var, 'n': n})
|
||||||
|
|
||||||
|
todos = []
|
||||||
|
for inst, us in sorted(por_secao.items(), key=lambda kv: -len(kv[1])):
|
||||||
|
sigla_i, nome_i, cidade_i = INSTITUICOES[inst]
|
||||||
|
cod = codigo(COLECAO, sigla_i)
|
||||||
|
a = agrega(us)
|
||||||
|
t = _textos(TEXTOS / 'secoes' / f'{sigla_i}.md')
|
||||||
|
add({
|
||||||
|
'id': cod, 'pai': codigo(COLECAO), 'nivel': 2,
|
||||||
|
'1.1': cod, '1.2': {'titulo': f'Seção {nome_i}', 'atribuido': True},
|
||||||
|
'1.3': {'producao': a['data']}, '1.4': {'nivel': 2, 'nome': NIVEIS[2]},
|
||||||
|
'1.5': a['dim'],
|
||||||
|
'2.1': [{'id': None, 'forma': nome_i, 'funcao': 'instituição custodiadora dos originais'}],
|
||||||
|
'2.2': t.get('2.2'),
|
||||||
|
'3.1': t.get('3.1') or resumo(a),
|
||||||
|
'3.4': f"{len(filhos[cod])} séries, por coleção ou fundo de origem.",
|
||||||
|
'5.1': {'instituicao': nome_i, 'local': cidade_i},
|
||||||
|
'7.3': {'descricao': HOJE},
|
||||||
|
})
|
||||||
|
todos.extend(us)
|
||||||
|
|
||||||
|
a = agrega(todos)
|
||||||
|
c1 = codigo(COLECAO)
|
||||||
|
add({
|
||||||
|
'id': c1, 'pai': codigo(), 'nivel': 1,
|
||||||
|
'1.1': c1, '1.2': {'titulo': COLECAO_TITULO, 'atribuido': False},
|
||||||
|
'1.3': {'producao': a['data'], 'acumulacao': {'forma': '2026', 'iso': '2026'}},
|
||||||
|
'1.4': {'nivel': 1, 'nome': NIVEIS[1]}, '1.5': a['dim'],
|
||||||
|
'2.1': [{'id': None, 'forma': ENTIDADE_NOME, 'funcao': 'colecionador'}],
|
||||||
|
'2.2': textos1.get('2.2'), '2.3': textos1.get('2.3'), '2.4': textos1.get('2.4'),
|
||||||
|
'3.1': textos1.get('3.1') or resumo(a), '3.2': textos1.get('3.2'), '3.3': textos1.get('3.3'),
|
||||||
|
'3.4': textos1.get('3.4'),
|
||||||
|
'4.1': textos1.get('4.1') or ACESSO, '4.2': textos1.get('4.2'),
|
||||||
|
'4.3': textos1.get('4.3'), '4.4': textos1.get('4.4'), '4.5': textos1.get('4.5'),
|
||||||
|
'5.1': textos1.get('5.1'), '5.4': textos1.get('5.4'),
|
||||||
|
'6.2': textos1.get('6.2'),
|
||||||
|
'7.1': textos1.get('7.1'), '7.2': REGRAS, '7.3': {'descricao': HOJE},
|
||||||
|
'8.1': textos1.get('8.1'),
|
||||||
|
})
|
||||||
|
c0 = codigo()
|
||||||
|
add({
|
||||||
|
'id': c0, 'pai': None, 'nivel': 0,
|
||||||
|
'1.1': c0, '1.2': {'titulo': f'Acervo {ENTIDADE_NOME}', 'atribuido': False},
|
||||||
|
'1.3': {'producao': a['data']}, '1.4': {'nivel': 0, 'nome': NIVEIS[0]}, '1.5': a['dim'],
|
||||||
|
'2.1': [{'id': None, 'forma': ENTIDADE_NOME, 'funcao': 'entidade custodiadora'}],
|
||||||
|
'2.2': textos0.get('2.2'), '3.1': textos0.get('3.1'),
|
||||||
|
'4.1': textos0.get('4.1') or ACESSO, '7.2': REGRAS, '7.3': {'descricao': HOJE},
|
||||||
|
})
|
||||||
|
|
||||||
|
# 1.4: títulos dos níveis superiores (proc. 1.1.4)
|
||||||
|
for u in unidades.values():
|
||||||
|
cad, p = [], u['pai']
|
||||||
|
while p:
|
||||||
|
cad.append(unidades[p]['1.2']['titulo'])
|
||||||
|
p = unidades[p]['pai']
|
||||||
|
u['1.4']['hierarquia'] = list(reversed(cad)) or None
|
||||||
|
|
||||||
|
ordem = sorted(unidades.values(), key=lambda u: (u['nivel'], u['id']))
|
||||||
|
with (SAIDA / 'unidades.jsonl').open('w', encoding='utf-8') as f:
|
||||||
|
for u in ordem:
|
||||||
|
f.write(json.dumps({k: x for k, x in u.items() if not k.startswith('_') and x is not None},
|
||||||
|
ensure_ascii=False) + '\n')
|
||||||
|
with (SAIDA / 'autoridades.jsonl').open('w', encoding='utf-8') as f:
|
||||||
|
for r in aut.registros.values():
|
||||||
|
f.write(json.dumps(r, ensure_ascii=False) + '\n')
|
||||||
|
|
||||||
|
# tabelas de revisão
|
||||||
|
pl.DataFrame(rev_datas, infer_schema_length=None).filter(pl.col('qualidade').is_null() | (pl.col('qualidade') != 'exata')) \
|
||||||
|
.sort('motivo', 'original', nulls_last=True).write_csv(REVISAO / 'datas.tsv', separator='\t')
|
||||||
|
pl.DataFrame(rev_series, infer_schema_length=None).sort('codigo', 'n', descending=[False, True]) \
|
||||||
|
.write_csv(REVISAO / 'series.tsv', separator='\t')
|
||||||
|
pl.DataFrame(rev_tipos, infer_schema_length=None).group_by(pl.all()).len('n').sort('n', descending=True) \
|
||||||
|
.write_csv(REVISAO / 'tipos.tsv', separator='\t')
|
||||||
|
pl.DataFrame(rev_direitos, infer_schema_length=None).group_by(pl.all()).len('n').sort('n', descending=True) \
|
||||||
|
.write_csv(REVISAO / 'direitos.tsv', separator='\t')
|
||||||
|
pl.DataFrame(rev_lugares, infer_schema_length=None).group_by(pl.all()).len('n').sort('n', descending=True) \
|
||||||
|
.write_csv(REVISAO / 'lugares.tsv', separator='\t')
|
||||||
|
pl.DataFrame([{'id': r['id'], 'forma_autorizada': r['forma_autorizada'], 'tipo': r['tipo'],
|
||||||
|
'ocorrencias': r['ocorrencias'], 'variantes': ' | '.join(r['variantes'])}
|
||||||
|
for r in aut.registros.values()], infer_schema_length=None).write_csv(REVISAO / 'autoridades.tsv', separator='\t')
|
||||||
|
|
||||||
|
return unidades, aut
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
"""Leva a descrição NOBRADE para o mural: grava no `meta` de cada peça do
|
||||||
|
web/atlas/atlas-map.json o código de referência, a data normalizada, a série
|
||||||
|
e o suporte, sem re-renderizar os atlas .webp.
|
||||||
|
|
||||||
|
python -m nobrade.mural (de dentro de pipeline/, depois de python -m nobrade)
|
||||||
|
|
||||||
|
Campos novos em meta (curtos: o mapa inteiro desce para o navegador):
|
||||||
|
ref código de referência (1.1) dt data na forma da NOBRADE (1.3)
|
||||||
|
ano ano inicial, para o histograma si índice em `series` do mapa (nível 3)
|
||||||
|
sup espécie e suporte (1.5) rep categoria de reprodução (4.2)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from .config import RAIZ, SAIDA
|
||||||
|
|
||||||
|
MAPA = RAIZ / 'web' / 'atlas' / 'atlas-map.json'
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
series, dossies = {}, {}
|
||||||
|
for linha in (SAIDA / 'unidades.jsonl').open(encoding='utf-8'):
|
||||||
|
u = json.loads(linha)
|
||||||
|
if u['nivel'] == 3:
|
||||||
|
series[u['id']] = u['1.2']['titulo']
|
||||||
|
elif u['nivel'] == 4:
|
||||||
|
dossies[u['handle']] = u
|
||||||
|
|
||||||
|
d = json.loads(MAPA.read_text(encoding='utf-8'))
|
||||||
|
titulos = sorted(set(series.values()), key=str.casefold)
|
||||||
|
idx = {t: i for i, t in enumerate(titulos)}
|
||||||
|
d['series'] = titulos
|
||||||
|
feitos = 0
|
||||||
|
for h, e in d['map'].items():
|
||||||
|
u = dossies.get(h)
|
||||||
|
if not u:
|
||||||
|
continue
|
||||||
|
p = u['1.3']['producao']
|
||||||
|
dim = u['1.5']
|
||||||
|
sup = dim['especie'] + (f" {dim['cor']}" if dim.get('cor') else '') + (f", {dim['suporte']}" if dim.get('suporte') else '')
|
||||||
|
e['meta'].update({
|
||||||
|
'ref': u['1.1'], 'dt': p.get('forma'), 'ano': p.get('inicio') or p.get('fim'),
|
||||||
|
'si': idx[series[u['pai']]], 'sup': sup, 'rep': u['4.2']['categoria'],
|
||||||
|
})
|
||||||
|
feitos += 1
|
||||||
|
MAPA.write_text(json.dumps(d, ensure_ascii=False, separators=(',', ':')), encoding='utf-8')
|
||||||
|
print(f'{feitos} de {len(d["map"])} peças com descrição NOBRADE; {len(titulos)} séries')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
"""Nível 3 — séries a partir de `dc.source`.
|
||||||
|
|
||||||
|
O campo traz, misturados, o nome da coleção/fundo de origem ("Coleção Gilberto
|
||||||
|
Ferrez" e "Gilberto Ferrez"), sufixos da instituição ("… / Museu da
|
||||||
|
República"), notações de caixa ("CX 14") e lixo de extração. A regra:
|
||||||
|
|
||||||
|
1. limpa o valor até uma chave (sem prefixo Coleção/Fundo/Arquivo, sem sufixo
|
||||||
|
institucional, sem notação no fim, sem acento, sem pontuação);
|
||||||
|
2. chaves com pelo menos MINIMO itens viram série;
|
||||||
|
3. valor raro que contém a chave de uma série vai para ela (os "Negativo de
|
||||||
|
vidro MPEG639, Coleção Fotográfica do Museu Paraense…");
|
||||||
|
4. o resto vai para a série AV (Avulsos) da instituição, e o valor original
|
||||||
|
fica como notação na origem (5.1).
|
||||||
|
|
||||||
|
Correções manuais em `ajustes/series.tsv` (instituicao, dc.source, titulo)
|
||||||
|
prevalecem sobre a regra.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import re
|
||||||
|
import unicodedata
|
||||||
|
from collections import Counter, defaultdict
|
||||||
|
|
||||||
|
from .config import AJUSTES
|
||||||
|
|
||||||
|
MINIMO = 3
|
||||||
|
|
||||||
|
# variantes que a limpeza não junta sozinha: chave → chave canônica
|
||||||
|
ALIAS = {
|
||||||
|
'd teresa cristina maria': 'thereza christina maria',
|
||||||
|
'teresa cristina maria': 'thereza christina maria',
|
||||||
|
'federacao brasileira para o progresso feminino fbpf': 'federacao brasileira pelo progresso feminino',
|
||||||
|
'federacao brasileira para o progresso feminino': 'federacao brasileira pelo progresso feminino',
|
||||||
|
'fotografica mpeg': 'fotografica do museu paraense emilio goeldi',
|
||||||
|
'brascan cem anos no brasil': 'brascan cem anos no brasil',
|
||||||
|
'escola de ciencias sociais fgv cpdoc': 'escola de ciencias sociais fgv cpdoc',
|
||||||
|
'escola de ciencias sociais': 'escola de ciencias sociais fgv cpdoc',
|
||||||
|
'dos eventos institucionais': 'eventos institucionais',
|
||||||
|
'mestres do sec xix': 'mestres do seculo xix',
|
||||||
|
'cristovao barcellos': 'cristovao barcelos',
|
||||||
|
}
|
||||||
|
|
||||||
|
# notação de caixa/negativo/foto: é localização na origem (5.1), não série
|
||||||
|
NOTACAO = re.compile(r'(?i)^\s*(cx|caixas?|nv|foto|negativo|estampa)\b')
|
||||||
|
|
||||||
|
PREFIXO = re.compile(r'^(convenio|colecao particular|colecao|fundo|arquivo|acervo|serie)\s+(d[aeo]s?\s+)?')
|
||||||
|
LIXO = re.compile(r'[<>{}]|ns:|^[0-9a-f]{12,}')
|
||||||
|
|
||||||
|
|
||||||
|
def sem_acento(s: str) -> str:
|
||||||
|
return ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')
|
||||||
|
|
||||||
|
|
||||||
|
def limpa(v: str) -> str:
|
||||||
|
s = v.strip()
|
||||||
|
s = re.sub(r'\s*/\s*(acervo|museu|ibge|instituto moreira).*$', '', s, flags=re.I)
|
||||||
|
s = re.sub(r'\s+-\s+(museu|funda|fgv|ibge).*$', '', s, flags=re.I)
|
||||||
|
s = re.sub(r'\s*\((museu|ibram)[^)]*\)', '', s, flags=re.I)
|
||||||
|
s = re.sub(r'\s*/\s*ibge$', '', s, flags=re.I)
|
||||||
|
s = re.sub(r'\s*(?:-\s*|\()\s*\w*\d\w*\)?\s*$', '', s) # "- 1123K", "(148T)", "- EFi9"
|
||||||
|
s = sem_acento(s.lower())
|
||||||
|
s = re.sub(r'\bsec\.?\s', 'sec ', s)
|
||||||
|
s = re.sub(r'[^\w\s]', ' ', s)
|
||||||
|
s = re.sub(r'\s+', ' ', s).strip()
|
||||||
|
s = PREFIXO.sub('', s)
|
||||||
|
return ALIAS.get(s, s)
|
||||||
|
|
||||||
|
|
||||||
|
def sigla(titulo: str, usadas: set[str]) -> str:
|
||||||
|
if m := re.match(r'(?i)[áa]lbum\s+(\d+)', titulo):
|
||||||
|
base = f'A{m[1]}'
|
||||||
|
usadas.add(base)
|
||||||
|
return base
|
||||||
|
miolo = PREFIXO.sub('', sem_acento(titulo.lower()))
|
||||||
|
palavras = [p for p in re.findall(r'[a-z0-9]+', miolo) if p not in {'de', 'da', 'do', 'das', 'dos', 'e', 'a', 'o'}]
|
||||||
|
base = ''.join(p[0] for p in palavras).upper()[:6] or 'S'
|
||||||
|
if len(base) < 2 and palavras:
|
||||||
|
base = palavras[0][:4].upper()
|
||||||
|
s, n = base, 2
|
||||||
|
while s in usadas or s == 'AV':
|
||||||
|
s, n = f'{base}{n}', n + 1
|
||||||
|
usadas.add(s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def _titulo(variantes: Counter) -> str:
|
||||||
|
"""A variante mais frequente; se ela não diz o que é, herda o tipo
|
||||||
|
(Coleção/Fundo/Série) de outra variante — "Thereza Christina Maria" +
|
||||||
|
"Coleção D. Teresa…" → "Coleção Thereza Christina Maria"."""
|
||||||
|
tipo_re = r'(?i)^(cole[cç][aã]o( particular)?|fundo|arquivo|s[ée]rie|conv[eê]nio|[áa]lbum)\b'
|
||||||
|
_, v = max((n, v) for v, n in variantes.items())
|
||||||
|
v = re.sub(r'\s+', ' ', v).strip()
|
||||||
|
v = re.sub(r'\s*[-/]\s*(Acervo|Museu|Fundação|Instituto Moreira|IBGE).*$', '', v)
|
||||||
|
v = re.sub(r'\s*\((Museu|IBRAM)[^)]*\)', '', v)
|
||||||
|
if not re.match(tipo_re, v):
|
||||||
|
tipos = Counter(m[1].capitalize() for x in variantes if (m := re.match(tipo_re, x.strip())))
|
||||||
|
v = f"{tipos.most_common(1)[0][0] if tipos else 'Coleção'} {v}"
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def _ajustes() -> dict[tuple[str, str], str]:
|
||||||
|
p = AJUSTES / 'series.tsv'
|
||||||
|
if not p.exists():
|
||||||
|
return {}
|
||||||
|
with p.open(encoding='utf-8') as f:
|
||||||
|
return {(r['instituicao'], r['dc_source']): r['titulo'] for r in csv.DictReader(f, delimiter='\t')}
|
||||||
|
|
||||||
|
|
||||||
|
def monta(fontes: list[tuple[str, str, str | None]]):
|
||||||
|
"""fontes: (handle, instituição, dc.source | None).
|
||||||
|
|
||||||
|
Devolve (por_handle, series): por_handle[handle] = (sigla, notação na origem
|
||||||
|
ou None); series[(instituição, sigla)] = {'titulo', 'variantes', 'n'}.
|
||||||
|
"""
|
||||||
|
ajuste = _ajustes()
|
||||||
|
chaves = defaultdict(Counter) # (inst, chave) → Counter(valor original)
|
||||||
|
for _, inst, v in fontes:
|
||||||
|
if v and not LIXO.search(v) and not NOTACAO.match(v) and (inst, v) not in ajuste:
|
||||||
|
chaves[(inst, limpa(v))][v] += 1
|
||||||
|
|
||||||
|
series: dict[tuple[str, str], dict] = {}
|
||||||
|
sigla_de: dict[tuple[str, str], str] = {}
|
||||||
|
usadas: dict[str, set[str]] = defaultdict(set)
|
||||||
|
fortes = defaultdict(list) # inst → [chave]
|
||||||
|
for (inst, chave), variantes in sorted(chaves.items(), key=lambda kv: -sum(kv[1].values())):
|
||||||
|
if not chave or sum(variantes.values()) < MINIMO:
|
||||||
|
continue
|
||||||
|
titulo = _titulo(variantes)
|
||||||
|
sg = sigla(titulo, usadas[inst])
|
||||||
|
sigla_de[(inst, chave)] = sg
|
||||||
|
series[(inst, sg)] = {'titulo': titulo, 'variantes': variantes, 'n': 0}
|
||||||
|
fortes[inst].append(chave)
|
||||||
|
for (inst, v), titulo in ajuste.items():
|
||||||
|
k = (inst, 'ajuste:' + titulo)
|
||||||
|
if k not in sigla_de:
|
||||||
|
sg = sigla(titulo, usadas[inst])
|
||||||
|
sigla_de[k] = sg
|
||||||
|
series[(inst, sg)] = {'titulo': titulo, 'variantes': Counter(), 'n': 0}
|
||||||
|
|
||||||
|
por_handle = {}
|
||||||
|
for handle, inst, v in fontes:
|
||||||
|
sg = None
|
||||||
|
if v and (inst, v) in ajuste:
|
||||||
|
sg = sigla_de[(inst, 'ajuste:' + ajuste[(inst, v)])]
|
||||||
|
series[(inst, sg)]['variantes'][v] += 1
|
||||||
|
elif v and not LIXO.search(v):
|
||||||
|
chave = limpa(v)
|
||||||
|
sg = sigla_de.get((inst, chave))
|
||||||
|
if sg is None:
|
||||||
|
# o valor raro contém o nome de uma série forte da mesma instituição?
|
||||||
|
for forte in sorted(fortes[inst], key=len, reverse=True):
|
||||||
|
if len(forte) > 5 and re.search(rf'\b{re.escape(forte)}\b', chave):
|
||||||
|
sg = sigla_de[(inst, forte)]
|
||||||
|
series[(inst, sg)]['variantes'][v] += 1
|
||||||
|
break
|
||||||
|
if sg is None:
|
||||||
|
sg = 'AV'
|
||||||
|
series.setdefault((inst, 'AV'), {'titulo': 'Avulsos', 'variantes': Counter(), 'n': 0})
|
||||||
|
series[(inst, sg)]['n'] += 1
|
||||||
|
# o valor original fica como notação na origem quando não é o próprio nome da série
|
||||||
|
notacao = v if v and (sg == 'AV' or limpa(v) not in {limpa(x) for x in [series[(inst, sg)]['titulo']]}) else None
|
||||||
|
por_handle[handle] = (sg, notacao)
|
||||||
|
return por_handle, series
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
"""Validador dos elementos obrigatórios da NOBRADE, por nível.
|
||||||
|
|
||||||
|
Obrigatórios: 1.1, 1.2, 1.3 (data de produção), 1.4, 1.5, 2.1; 4.1 só nos
|
||||||
|
níveis 0 e 1. Além deles, lista avisos que não reprovam mas pedem revisão.
|
||||||
|
Escreve descricao/pendencias.md e devolve o número de pendências.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections import Counter, defaultdict
|
||||||
|
|
||||||
|
from .config import SAIDA
|
||||||
|
|
||||||
|
|
||||||
|
def verifica(u: dict) -> tuple[list[str], list[str]]:
|
||||||
|
erros, avisos = [], []
|
||||||
|
n = u['nivel']
|
||||||
|
if not u.get('1.1'):
|
||||||
|
erros.append('1.1 código de referência ausente')
|
||||||
|
if not (u.get('1.2') or {}).get('titulo', '').strip():
|
||||||
|
erros.append('1.2 título ausente')
|
||||||
|
prod = (u.get('1.3') or {}).get('producao') or {}
|
||||||
|
if not prod.get('inicio') and not prod.get('fim'):
|
||||||
|
erros.append('1.3 data de produção ausente')
|
||||||
|
if not (u.get('1.4') or {}).get('nome'):
|
||||||
|
erros.append('1.4 nível ausente')
|
||||||
|
if not (u.get('1.5') or {}).get('texto'):
|
||||||
|
erros.append('1.5 dimensão e suporte ausente')
|
||||||
|
if not u.get('2.1'):
|
||||||
|
erros.append('2.1 produtor ausente')
|
||||||
|
if n <= 1 and not u.get('4.1'):
|
||||||
|
erros.append('4.1 condições de acesso ausente (obrigatório nos níveis 0 e 1)')
|
||||||
|
|
||||||
|
if n == 4:
|
||||||
|
if prod.get('qualidade') == 'atribuída pelo arquivista' or (prod.get('notas') or [''])[0].startswith('data atribuída'):
|
||||||
|
avisos.append('1.3 data atribuída pelo arquivista — conferir')
|
||||||
|
if prod.get('motivo') == 'ilegível':
|
||||||
|
avisos.append('1.3 data da origem ilegível')
|
||||||
|
if all(p.get('id') is None for p in u.get('2.1') or []):
|
||||||
|
avisos.append('2.1 autoria não identificada')
|
||||||
|
if u['id'].split('.')[-2] == 'AV':
|
||||||
|
avisos.append('nível 3 em Avulsos — série de origem não identificada')
|
||||||
|
if any('presumida' in x for x in u.get('6.2') or []):
|
||||||
|
avisos.append('1.5 espécie presumida')
|
||||||
|
if any('corrompidos' in x for x in u.get('6.2') or []):
|
||||||
|
avisos.append('valores corrompidos na origem')
|
||||||
|
if u.get('6.1'):
|
||||||
|
avisos.append('6.1 preservação indisponível na origem')
|
||||||
|
if (u.get('4.2') or {}).get('categoria') == 'consultar o detentor':
|
||||||
|
avisos.append('4.2 condição de reprodução não informada na origem')
|
||||||
|
if not (u.get('3.1') or '').strip():
|
||||||
|
avisos.append('3.1 sem âmbito e conteúdo')
|
||||||
|
return erros, avisos
|
||||||
|
|
||||||
|
|
||||||
|
def valida(unidades) -> int:
|
||||||
|
erros, avisos = defaultdict(list), defaultdict(list)
|
||||||
|
por_nivel = Counter()
|
||||||
|
for u in unidades:
|
||||||
|
por_nivel[u['nivel']] += 1
|
||||||
|
e, a = verifica(u)
|
||||||
|
for x in e:
|
||||||
|
erros[x].append(u['id'])
|
||||||
|
for x in a:
|
||||||
|
avisos[x].append(u['id'])
|
||||||
|
|
||||||
|
total = sum(len(v) for v in erros.values())
|
||||||
|
linhas = ['# Pendências da descrição NOBRADE', '',
|
||||||
|
'Gerado por `python -m nobrade`. Obrigatórios reprovam; avisos pedem revisão.', '',
|
||||||
|
'| Nível | Unidades |', '|---|--:|']
|
||||||
|
nomes = {0: 'acervo', 1: 'coleção', 2: 'seção', 3: 'série', 4: 'dossiê', 5: 'item'}
|
||||||
|
linhas += [f'| {n} {nomes[n]} | {c:,} |'.replace(',', '.') for n, c in sorted(por_nivel.items())]
|
||||||
|
linhas += ['', f'## Obrigatórios faltando: {total}', '']
|
||||||
|
if not erros:
|
||||||
|
linhas.append('Nenhum. Todas as unidades têm os elementos obrigatórios do seu nível.')
|
||||||
|
for k, ids in sorted(erros.items(), key=lambda kv: -len(kv[1])):
|
||||||
|
linhas += [f'### {k} — {len(ids)}', '', *[f'- `{i}`' for i in ids[:50]]]
|
||||||
|
if len(ids) > 50:
|
||||||
|
linhas.append(f'- … e mais {len(ids) - 50}')
|
||||||
|
linhas.append('')
|
||||||
|
linhas += ['', '## Avisos', '', '| Aviso | Dossiês |', '|---|--:|']
|
||||||
|
linhas += [f'| {k} | {len(v):,} |'.replace(',', '.') for k, v in sorted(avisos.items(), key=lambda kv: -len(kv[1]))]
|
||||||
|
linhas.append('')
|
||||||
|
(SAIDA / 'pendencias.md').write_text('\n'.join(linhas), encoding='utf-8')
|
||||||
|
return total
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Subconjunto do xlink.xsd da LoC (http://www.loc.gov/standards/xlink/xlink.xsd),
|
||||||
|
que responde 403 a clientes fora do navegador: só o que o cpf.xsd usa. -->
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
targetNamespace="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
attributeFormDefault="qualified">
|
||||||
|
<xs:attribute name="href" type="xs:anyURI"/>
|
||||||
|
<xs:attribute name="role" type="xs:string"/>
|
||||||
|
<xs:attribute name="arcrole" type="xs:string"/>
|
||||||
|
<xs:attribute name="title" type="xs:string"/>
|
||||||
|
<xs:attribute name="show">
|
||||||
|
<xs:simpleType><xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="new"/><xs:enumeration value="replace"/><xs:enumeration value="embed"/>
|
||||||
|
<xs:enumeration value="other"/><xs:enumeration value="none"/>
|
||||||
|
</xs:restriction></xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="actuate">
|
||||||
|
<xs:simpleType><xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="onLoad"/><xs:enumeration value="onRequest"/>
|
||||||
|
<xs:enumeration value="other"/><xs:enumeration value="none"/>
|
||||||
|
</xs:restriction></xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attributeGroup name="simpleLink">
|
||||||
|
<xs:attribute name="type" type="xs:string" fixed="simple" form="qualified"/>
|
||||||
|
<xs:attribute ref="xlink:href" use="optional"/>
|
||||||
|
<xs:attribute ref="xlink:role" use="optional"/>
|
||||||
|
<xs:attribute ref="xlink:arcrole" use="optional"/>
|
||||||
|
<xs:attribute ref="xlink:title" use="optional"/>
|
||||||
|
<xs:attribute ref="xlink:show" use="optional"/>
|
||||||
|
<xs:attribute ref="xlink:actuate" use="optional"/>
|
||||||
|
</xs:attributeGroup>
|
||||||
|
</xs:schema>
|
||||||
@@ -0,0 +1,287 @@
|
|||||||
|
<?xml version='1.0'?>
|
||||||
|
<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
|
||||||
|
<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns ="http://www.w3.org/1999/xhtml"
|
||||||
|
xml:lang="en">
|
||||||
|
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<div>
|
||||||
|
<h1>About the XML namespace</h1>
|
||||||
|
|
||||||
|
<div class="bodytext">
|
||||||
|
<p>
|
||||||
|
This schema document describes the XML namespace, in a form
|
||||||
|
suitable for import by other schema documents.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
See <a href="http://www.w3.org/XML/1998/namespace.html">
|
||||||
|
http://www.w3.org/XML/1998/namespace.html</a> and
|
||||||
|
<a href="http://www.w3.org/TR/REC-xml">
|
||||||
|
http://www.w3.org/TR/REC-xml</a> for information
|
||||||
|
about this namespace.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Note that local names in this namespace are intended to be
|
||||||
|
defined only by the World Wide Web Consortium or its subgroups.
|
||||||
|
The names currently defined in this namespace are listed below.
|
||||||
|
They should not be used with conflicting semantics by any Working
|
||||||
|
Group, specification, or document instance.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
See further below in this document for more information about <a
|
||||||
|
href="#usage">how to refer to this schema document from your own
|
||||||
|
XSD schema documents</a> and about <a href="#nsversioning">the
|
||||||
|
namespace-versioning policy governing this schema document</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:attribute name="lang">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h3>lang (as an attribute name)</h3>
|
||||||
|
<p>
|
||||||
|
denotes an attribute whose value
|
||||||
|
is a language code for the natural language of the content of
|
||||||
|
any element; its value is inherited. This name is reserved
|
||||||
|
by virtue of its definition in the XML specification.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>Notes</h4>
|
||||||
|
<p>
|
||||||
|
Attempting to install the relevant ISO 2- and 3-letter
|
||||||
|
codes as the enumerated possible values is probably never
|
||||||
|
going to be a realistic possibility.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
|
||||||
|
http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
|
||||||
|
and the IANA language subtag registry at
|
||||||
|
<a href="http://www.iana.org/assignments/language-subtag-registry">
|
||||||
|
http://www.iana.org/assignments/language-subtag-registry</a>
|
||||||
|
for further information.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The union allows for the 'un-declaration' of xml:lang with
|
||||||
|
the empty string.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:simpleType>
|
||||||
|
<xs:union memberTypes="xs:language">
|
||||||
|
<xs:simpleType>
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value=""/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:union>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="space">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h3>space (as an attribute name)</h3>
|
||||||
|
<p>
|
||||||
|
denotes an attribute whose
|
||||||
|
value is a keyword indicating what whitespace processing
|
||||||
|
discipline is intended for the content of the element; its
|
||||||
|
value is inherited. This name is reserved by virtue of its
|
||||||
|
definition in the XML specification.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:simpleType>
|
||||||
|
<xs:restriction base="xs:NCName">
|
||||||
|
<xs:enumeration value="default"/>
|
||||||
|
<xs:enumeration value="preserve"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h3>base (as an attribute name)</h3>
|
||||||
|
<p>
|
||||||
|
denotes an attribute whose value
|
||||||
|
provides a URI to be used as the base for interpreting any
|
||||||
|
relative URIs in the scope of the element on which it
|
||||||
|
appears; its value is inherited. This name is reserved
|
||||||
|
by virtue of its definition in the XML Base specification.</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
See <a
|
||||||
|
href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
|
||||||
|
for information about this attribute.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="id" type="xs:ID">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h3>id (as an attribute name)</h3>
|
||||||
|
<p>
|
||||||
|
denotes an attribute whose value
|
||||||
|
should be interpreted as if declared to be of type ID.
|
||||||
|
This name is reserved by virtue of its definition in the
|
||||||
|
xml:id specification.</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
See <a
|
||||||
|
href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
|
||||||
|
for information about this attribute.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attributeGroup name="specialAttrs">
|
||||||
|
<xs:attribute ref="xml:base"/>
|
||||||
|
<xs:attribute ref="xml:lang"/>
|
||||||
|
<xs:attribute ref="xml:space"/>
|
||||||
|
<xs:attribute ref="xml:id"/>
|
||||||
|
</xs:attributeGroup>
|
||||||
|
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h3>Father (in any context at all)</h3>
|
||||||
|
|
||||||
|
<div class="bodytext">
|
||||||
|
<p>
|
||||||
|
denotes Jon Bosak, the chair of
|
||||||
|
the original XML Working Group. This name is reserved by
|
||||||
|
the following decision of the W3C XML Plenary and
|
||||||
|
XML Coordination groups:
|
||||||
|
</p>
|
||||||
|
<blockquote>
|
||||||
|
<p>
|
||||||
|
In appreciation for his vision, leadership and
|
||||||
|
dedication the W3C XML Plenary on this 10th day of
|
||||||
|
February, 2000, reserves for Jon Bosak in perpetuity
|
||||||
|
the XML name "xml:Father".
|
||||||
|
</p>
|
||||||
|
</blockquote>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<div xml:id="usage" id="usage">
|
||||||
|
<h2><a name="usage">About this schema document</a></h2>
|
||||||
|
|
||||||
|
<div class="bodytext">
|
||||||
|
<p>
|
||||||
|
This schema defines attributes and an attribute group suitable
|
||||||
|
for use by schemas wishing to allow <code>xml:base</code>,
|
||||||
|
<code>xml:lang</code>, <code>xml:space</code> or
|
||||||
|
<code>xml:id</code> attributes on elements they define.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
To enable this, such a schema must import this schema for
|
||||||
|
the XML namespace, e.g. as follows:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<schema . . .>
|
||||||
|
. . .
|
||||||
|
<import namespace="http://www.w3.org/XML/1998/namespace"
|
||||||
|
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
or
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<import namespace="http://www.w3.org/XML/1998/namespace"
|
||||||
|
schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Subsequently, qualified reference to any of the attributes or the
|
||||||
|
group defined below will have the desired effect, e.g.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<type . . .>
|
||||||
|
. . .
|
||||||
|
<attributeGroup ref="xml:specialAttrs"/>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
will define a type which will schema-validate an instance element
|
||||||
|
with any of those attributes.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<div id="nsversioning" xml:id="nsversioning">
|
||||||
|
<h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
|
||||||
|
<div class="bodytext">
|
||||||
|
<p>
|
||||||
|
In keeping with the XML Schema WG's standard versioning
|
||||||
|
policy, this schema document will persist at
|
||||||
|
<a href="http://www.w3.org/2009/01/xml.xsd">
|
||||||
|
http://www.w3.org/2009/01/xml.xsd</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
At the date of issue it can also be found at
|
||||||
|
<a href="http://www.w3.org/2001/xml.xsd">
|
||||||
|
http://www.w3.org/2001/xml.xsd</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The schema document at that URI may however change in the future,
|
||||||
|
in order to remain compatible with the latest version of XML
|
||||||
|
Schema itself, or with the XML namespace itself. In other words,
|
||||||
|
if the XML Schema or XML namespaces change, the version of this
|
||||||
|
document at <a href="http://www.w3.org/2001/xml.xsd">
|
||||||
|
http://www.w3.org/2001/xml.xsd
|
||||||
|
</a>
|
||||||
|
will change accordingly; the version at
|
||||||
|
<a href="http://www.w3.org/2009/01/xml.xsd">
|
||||||
|
http://www.w3.org/2009/01/xml.xsd
|
||||||
|
</a>
|
||||||
|
will not change.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Previous dated (and unchanging) versions of this schema
|
||||||
|
document are at:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="http://www.w3.org/2009/01/xml.xsd">
|
||||||
|
http://www.w3.org/2009/01/xml.xsd</a></li>
|
||||||
|
<li><a href="http://www.w3.org/2007/08/xml.xsd">
|
||||||
|
http://www.w3.org/2007/08/xml.xsd</a></li>
|
||||||
|
<li><a href="http://www.w3.org/2004/10/xml.xsd">
|
||||||
|
http://www.w3.org/2004/10/xml.xsd</a></li>
|
||||||
|
<li><a href="http://www.w3.org/2001/03/xml.xsd">
|
||||||
|
http://www.w3.org/2001/03/xml.xsd</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
</xs:schema>
|
||||||
|
|
||||||
+43
-43
@@ -399,47 +399,47 @@ Arquivar para si é uma coisa; republicar é outra.
|
|||||||
## 9. Descrição arquivística (NOBRADE)
|
## 9. Descrição arquivística (NOBRADE)
|
||||||
|
|
||||||
Resumo da norma e decisões de aplicação em [`CONARQ.md`](../CONARQ.md).
|
Resumo da norma e decisões de aplicação em [`CONARQ.md`](../CONARQ.md).
|
||||||
Implementação no branch `feat/nobrade`.
|
Implementação no branch `feat/nobrade`: `cd pipeline && python3 -m nobrade && python3 -m nobrade.mural`.
|
||||||
|
|
||||||
| # | Tarefa | Entrega | Depende de |
|
| # | Tarefa | Entrega | Depende de | Estado |
|
||||||
|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| **0 — Decisões** ||||
|
| **0 — Decisões** |||||
|
||||||
| 0.1 | Definir nome da entidade custodiadora e código provisório (`BR XYZ`) | `pipeline/nobrade/config.py` | — |
|
| 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 | e-mail enviado | 0.1 |
|
| 0.2 | Pedir código de entidade ao CONARQ | e-mail enviado | 0.1 | ⏳ depende de você |
|
||||||
| 0.3 | Fixar a convenção do código de referência (`BR XYZ BF.IMS.GF.12345`) | `CONARQ.md` §5.2 | 0.1 |
|
| 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 — 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.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.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.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.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.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.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.7 | Data tópica: `dc.coverage` → cidade (UF) | campo 1.3 | — | ✅ |
|
||||||
| 1.8 | Assuntos: `dc.subject` separado em pt/en | campo 8.1 | — |
|
| 1.8 | Assuntos: `dc.subject` separado em pt/en | campo 8.1 | — | ✅ |
|
||||||
| **2 — Montagem da hierarquia** ||||
|
| **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.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.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 |
|
| 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 |
|
| 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 — Textos dos níveis altos** |||||
|
||||||
| 3.1 | Nível 1: história arquivística, procedência, acesso, arranjo | `descricao/textos/nivel1.md` | — |
|
| 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 16 instituições | `descricao/textos/secoes/` | — |
|
| 3.2 | Nível 2: breve histórico das 16 instituições | `descricao/textos/secoes/` | — | 📝 rascunho |
|
||||||
| 3.3 | Nível 3: âmbito e conteúdo das séries principais | `descricao/textos/series/` | 1.3 |
|
| 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 |
|
| 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 — Relações e fontes** |||||
|
||||||
| 4.1 | 5.1 Originais: instituição + handle + Sophia + objdigital | campo automático | 2.1 |
|
| 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.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 | — |
|
| 4.3 | 5.4 Publicações: posts do WordPress → handles citados | campo 5.4 | — | ✅ |
|
||||||
| **5 — Validação** ||||
|
| **5 — Validação** |||||
|
||||||
| 5.1 | Validador dos 7 obrigatórios por nível | `descricao/pendencias.md` | 2.x |
|
| 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 |
|
| 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 — Exportação e publicação** |||||
|
||||||
| 6.1 | Exportar EAD 3 | `descricao/ead/brasiliana.xml` | 5.2 |
|
| 6.1 | Exportar EAD 3 | `descricao/ead/brasiliana.xml` | 5.2 | ✅ valida |
|
||||||
| 6.2 | Exportar EAC-CPF | `descricao/eac/*.xml` | 1.4 |
|
| 6.2 | Exportar EAC-CPF | `descricao/eac/*.xml` | 1.4 | ✅ valida |
|
||||||
| 6.3 | Validar contra os XSD | xmllint limpo | 6.1, 6.2 |
|
| 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 |
|
| 6.4 | Subir `descricao/` para `s3://brasiliana/descricao/` e atualizar o MANIFEST | objetos no bucket | 6.3 | ⏳ aguardando ok |
|
||||||
| 6.5 | (opcional) CSV de importação do AtoM | `descricao/atom.csv` | 5.2 |
|
| 6.5 | (opcional) CSV de importação do AtoM | `descricao/atom.csv` | 5.2 | ✅ |
|
||||||
| **7 — Mural** ||||
|
| **7 — Mural** |||||
|
||||||
| 7.1 | Cartão com código de referência, data normalizada, suporte, "original em" | `web/wall.html` | 2.2 |
|
| 7.1 | Cartão com código de referência, data normalizada, suporte, "original em" | `web/wall.html` | 2.2 | ✅ |
|
||||||
| 7.2 | Filtro por série (nível 3) | `web/wall.html` | 1.3 |
|
| 7.2 | Filtro por série (nível 3) | `web/wall.html` | 1.3 | ✅ |
|
||||||
| 7.3 | Publicar em `xyz/brasiliana` | commit | 7.x |
|
| 7.3 | Publicar em `xyz/brasiliana` | commit | 7.x | ⏳ aguardando ok |
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+38
-12
@@ -426,6 +426,8 @@
|
|||||||
#card-footer a { color: #d8b04a; text-decoration: none; }
|
#card-footer a { color: #d8b04a; text-decoration: none; }
|
||||||
#card-footer a:hover { text-decoration: underline; }
|
#card-footer a:hover { text-decoration: underline; }
|
||||||
#card-rights { margin-top: 6px; font-size: .68rem; color: #777; }
|
#card-rights { margin-top: 6px; font-size: .68rem; color: #777; }
|
||||||
|
#card-ref { font: .7rem/1.3 ui-monospace, SFMono-Regular, Menlo, monospace; color: #8a8a82; margin-top: 4px; }
|
||||||
|
#card-ref .serie { font-family: system-ui, -apple-system, sans-serif; letter-spacing: .02em; }
|
||||||
|
|
||||||
/* stepping between pieces without a keyboard */
|
/* stepping between pieces without a keyboard */
|
||||||
#card-nav { display: flex; gap: 9px; margin-top: 16px; }
|
#card-nav { display: flex; gap: 9px; margin-top: 16px; }
|
||||||
@@ -635,6 +637,10 @@
|
|||||||
<label for="f-colecao">Coleção</label>
|
<label for="f-colecao">Coleção</label>
|
||||||
<select id="f-colecao"><option value="">todas</option></select>
|
<select id="f-colecao"><option value="">todas</option></select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="f-row">
|
||||||
|
<label for="f-serie">Série (arranjo NOBRADE)</label>
|
||||||
|
<select id="f-serie"><option value="">todas</option></select>
|
||||||
|
</div>
|
||||||
<div class="f-row">
|
<div class="f-row">
|
||||||
<label for="f-pessoa">Pessoa</label>
|
<label for="f-pessoa">Pessoa</label>
|
||||||
<select id="f-pessoa"><option value="">todas</option></select>
|
<select id="f-pessoa"><option value="">todas</option></select>
|
||||||
@@ -660,6 +666,7 @@
|
|||||||
<div id="card-img-wrap"><img id="card-img" alt=""></div>
|
<div id="card-img-wrap"><img id="card-img" alt=""></div>
|
||||||
<div id="card-title">—</div>
|
<div id="card-title">—</div>
|
||||||
<div id="card-date">—</div>
|
<div id="card-date">—</div>
|
||||||
|
<div id="card-ref"></div>
|
||||||
<div id="card-contrib"></div>
|
<div id="card-contrib"></div>
|
||||||
<div id="card-tags"></div>
|
<div id="card-tags"></div>
|
||||||
<div id="card-related" hidden></div>
|
<div id="card-related" hidden></div>
|
||||||
@@ -1063,6 +1070,7 @@ renderer.domElement.addEventListener('pointermove', e => {
|
|||||||
// (the "hole" always opens in the middle, wherever you clicked).
|
// (the "hole" always opens in the middle, wherever you clicked).
|
||||||
let atlasSources = []; // { source, size } per atlas page — used to crop the tile into the card canvas
|
let atlasSources = []; // { source, size } per atlas page — used to crop the tile into the card canvas
|
||||||
let atlasEntries = null, TPR = 1;
|
let atlasEntries = null, TPR = 1;
|
||||||
|
let seriesTitles = []; // títulos das séries NOBRADE (nível 3); meta.si indexa aqui
|
||||||
let selected = null;
|
let selected = null;
|
||||||
let selectedAt = 0;
|
let selectedAt = 0;
|
||||||
|
|
||||||
@@ -1393,11 +1401,20 @@ function tileThumbUrl(handle, px) {
|
|||||||
|
|
||||||
function showCard(data) {
|
function showCard(data) {
|
||||||
const meta = data.meta || {};
|
const meta = data.meta || {};
|
||||||
document.getElementById('card-type').textContent = meta.type || 'Fotografia';
|
document.getElementById('card-type').textContent = meta.sup || meta.type || 'Fotografia';
|
||||||
document.getElementById('card-community').textContent = meta.community || '—';
|
document.getElementById('card-community').textContent = meta.community || '—';
|
||||||
document.getElementById('card-date-tag').textContent = prettyDate(meta.date) || 's.d.';
|
document.getElementById('card-date-tag').textContent = meta.dt || prettyDate(meta.date) || 's.d.';
|
||||||
document.getElementById('card-title').textContent = meta.title || '(sem título)';
|
document.getElementById('card-title').textContent = meta.title || '(sem título)';
|
||||||
document.getElementById('card-date').textContent = prettyDate(meta.date);
|
document.getElementById('card-date').textContent = meta.dt || prettyDate(meta.date);
|
||||||
|
// código de referência NOBRADE e a série (nível 3) a que a peça pertence
|
||||||
|
const refEl = document.getElementById('card-ref');
|
||||||
|
refEl.textContent = meta.ref || '';
|
||||||
|
if (meta.si != null && seriesTitles[meta.si]) {
|
||||||
|
const sr = document.createElement('div');
|
||||||
|
sr.className = 'serie';
|
||||||
|
sr.textContent = seriesTitles[meta.si];
|
||||||
|
refEl.appendChild(sr);
|
||||||
|
}
|
||||||
document.getElementById('card-contrib').textContent = meta.contributor ? meta.contributor : '';
|
document.getElementById('card-contrib').textContent = meta.contributor ? meta.contributor : '';
|
||||||
// this piece's dc.subject, one chip each (accent/case duplicates folded)
|
// this piece's dc.subject, one chip each (accent/case duplicates folded)
|
||||||
const tagsEl = document.getElementById('card-tags');
|
const tagsEl = document.getElementById('card-tags');
|
||||||
@@ -1406,7 +1423,8 @@ function showCard(data) {
|
|||||||
renderRelated(data);
|
renderRelated(data);
|
||||||
document.getElementById('card-handle').textContent = data.handle || '';
|
document.getElementById('card-handle').textContent = data.handle || '';
|
||||||
document.getElementById('card-link').href = data.handle ? sourceUrl(data.handle) : '#';
|
document.getElementById('card-link').href = data.handle ? sourceUrl(data.handle) : '#';
|
||||||
document.getElementById('card-rights').textContent = meta.rights ? `Direitos: ${meta.rights}` : '';
|
document.getElementById('card-rights').textContent =
|
||||||
|
[meta.rep && meta.rep[0].toUpperCase() + meta.rep.slice(1), meta.rights && `Direitos: ${meta.rights}`].filter(Boolean).join(' · ');
|
||||||
|
|
||||||
// crop this tile out of the atlas image for a (still small, but framed) preview
|
// crop this tile out of the atlas image for a (still small, but framed) preview
|
||||||
const entry = atlasEntries[data.handle];
|
const entry = atlasEntries[data.handle];
|
||||||
@@ -1493,6 +1511,7 @@ function flattenMeta(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function yearOf(meta) {
|
function yearOf(meta) {
|
||||||
|
if (meta && Number.isInteger(meta.ano)) return meta.ano;
|
||||||
const m = String((meta || {}).date || '').match(/(1[5-9]\d{2}|20\d{2})/);
|
const m = String((meta || {}).date || '').match(/(1[5-9]\d{2}|20\d{2})/);
|
||||||
return m ? parseInt(m[1], 10) : null;
|
return m ? parseInt(m[1], 10) : null;
|
||||||
}
|
}
|
||||||
@@ -1961,6 +1980,7 @@ function setupFilters(mapData) {
|
|||||||
const a = cleanAuthor(meta.contributor);
|
const a = cleanAuthor(meta.contributor);
|
||||||
m.userData._author = a ? authorKey(a) : '';
|
m.userData._author = a ? authorKey(a) : '';
|
||||||
m.userData._type = cleanType(meta.type);
|
m.userData._type = cleanType(meta.type);
|
||||||
|
m.userData._serie = meta.si != null ? seriesTitles[meta.si] || '' : '';
|
||||||
Object.assign(m.userData, (({ st, ct, bh, tp, col, pes }) => ({ _st: st, _ct: ct, _bh: bh, _tp: tp, _col: col, _pes: pes }))(subjectFacets(meta)));
|
Object.assign(m.userData, (({ st, ct, bh, tp, col, pes }) => ({ _st: st, _ct: ct, _bh: bh, _tp: tp, _col: col, _pes: pes }))(subjectFacets(meta)));
|
||||||
// one haystack per piece: every metadata field, not a chosen few
|
// one haystack per piece: every metadata field, not a chosen few
|
||||||
// the handle is the map's key, not a field of meta — it still has to be
|
// the handle is the map's key, not a field of meta — it still has to be
|
||||||
@@ -1992,6 +2012,7 @@ function setupFilters(mapData) {
|
|||||||
const selTopico = document.getElementById('f-topico');
|
const selTopico = document.getElementById('f-topico');
|
||||||
const selColecao = document.getElementById('f-colecao');
|
const selColecao = document.getElementById('f-colecao');
|
||||||
const selPessoa = document.getElementById('f-pessoa');
|
const selPessoa = document.getElementById('f-pessoa');
|
||||||
|
const selSerie = document.getElementById('f-serie');
|
||||||
const fillSelect = (sel, rows, first) => {
|
const fillSelect = (sel, rows, first) => {
|
||||||
sel.replaceChildren(Object.assign(document.createElement('option'), { value: '', textContent: first }));
|
sel.replaceChildren(Object.assign(document.createElement('option'), { value: '', textContent: first }));
|
||||||
rows.forEach(([value, n]) => {
|
rows.forEach(([value, n]) => {
|
||||||
@@ -2036,7 +2057,7 @@ function setupFilters(mapData) {
|
|||||||
sel.value = value;
|
sel.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = { search: '', institution: '', yearLo: decadeMin, yearHi: decadeMax, yearTouched: false, author: '', type: '', estado: '', cidade: '', bairro: '', topico: '', colecao: '', pessoa: '' };
|
const state = { search: '', institution: '', yearLo: decadeMin, yearHi: decadeMax, yearTouched: false, author: '', type: '', estado: '', cidade: '', bairro: '', topico: '', colecao: '', pessoa: '', serie: '' };
|
||||||
|
|
||||||
function resetYear() {
|
function resetYear() {
|
||||||
state.yearTouched = false;
|
state.yearTouched = false;
|
||||||
@@ -2064,6 +2085,7 @@ function setupFilters(mapData) {
|
|||||||
(!state.topico || d._tp.has(topicPrefix() + state.topico)) &&
|
(!state.topico || d._tp.has(topicPrefix() + state.topico)) &&
|
||||||
(!state.colecao || d._col.has(state.colecao)) &&
|
(!state.colecao || d._col.has(state.colecao)) &&
|
||||||
(!state.pessoa || d._pes.has(state.pessoa)) &&
|
(!state.pessoa || d._pes.has(state.pessoa)) &&
|
||||||
|
(!state.serie || d._serie === state.serie) &&
|
||||||
terms.every(t => d._hay.includes(t));
|
terms.every(t => d._hay.includes(t));
|
||||||
if (okRest && d._year != null) {
|
if (okRest && d._year != null) {
|
||||||
const i = Math.floor((d._year - decadeMin) / 10);
|
const i = Math.floor((d._year - decadeMin) / 10);
|
||||||
@@ -2131,6 +2153,7 @@ function setupFilters(mapData) {
|
|||||||
if (state.topico) out.push({ key: 'topico', text: state.topico });
|
if (state.topico) out.push({ key: 'topico', text: state.topico });
|
||||||
if (state.colecao) out.push({ key: 'colecao', text: state.colecao });
|
if (state.colecao) out.push({ key: 'colecao', text: state.colecao });
|
||||||
if (state.pessoa) out.push({ key: 'pessoa', text: state.pessoa });
|
if (state.pessoa) out.push({ key: 'pessoa', text: state.pessoa });
|
||||||
|
if (state.serie) out.push({ key: 'serie', text: state.serie });
|
||||||
if (state.type) out.push({ key: 'type', text: state.type });
|
if (state.type) out.push({ key: 'type', text: state.type });
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -2145,6 +2168,7 @@ function setupFilters(mapData) {
|
|||||||
if (key === 'topico') { state.topico = ''; selTopico.value = ''; }
|
if (key === 'topico') { state.topico = ''; selTopico.value = ''; }
|
||||||
if (key === 'colecao') { state.colecao = ''; selColecao.value = ''; }
|
if (key === 'colecao') { state.colecao = ''; selColecao.value = ''; }
|
||||||
if (key === 'pessoa') { state.pessoa = ''; selPessoa.value = ''; }
|
if (key === 'pessoa') { state.pessoa = ''; selPessoa.value = ''; }
|
||||||
|
if (key === 'serie') { state.serie = ''; selSerie.value = ''; }
|
||||||
if (key === 'author') { state.author = ''; selAuthor.value = ''; }
|
if (key === 'author') { state.author = ''; selAuthor.value = ''; }
|
||||||
if (key === 'year') resetYear();
|
if (key === 'year') resetYear();
|
||||||
apply();
|
apply();
|
||||||
@@ -2192,6 +2216,7 @@ function setupFilters(mapData) {
|
|||||||
selTopico.addEventListener('change', () => { state.topico = selTopico.value; apply(); });
|
selTopico.addEventListener('change', () => { state.topico = selTopico.value; apply(); });
|
||||||
selColecao.addEventListener('change', () => { state.colecao = selColecao.value; apply(); });
|
selColecao.addEventListener('change', () => { state.colecao = selColecao.value; apply(); });
|
||||||
selPessoa.addEventListener('change', () => { state.pessoa = selPessoa.value; apply(); });
|
selPessoa.addEventListener('change', () => { state.pessoa = selPessoa.value; apply(); });
|
||||||
|
selSerie.addEventListener('change', () => { state.serie = selSerie.value; apply(); });
|
||||||
selAuthor.addEventListener('change', () => { state.author = selAuthor.value; apply(); });
|
selAuthor.addEventListener('change', () => { state.author = selAuthor.value; apply(); });
|
||||||
|
|
||||||
function onYear(e) {
|
function onYear(e) {
|
||||||
@@ -2211,8 +2236,8 @@ function setupFilters(mapData) {
|
|||||||
|
|
||||||
clearBtn.addEventListener('click', () => {
|
clearBtn.addEventListener('click', () => {
|
||||||
clearTimeout(searchTimer);
|
clearTimeout(searchTimer);
|
||||||
state.search = ''; state.institution = ''; state.type = ''; state.author = ''; state.estado = state.cidade = state.bairro = state.topico = state.colecao = state.pessoa = '';
|
state.search = ''; state.institution = ''; state.type = ''; state.author = ''; state.estado = state.cidade = state.bairro = state.topico = state.colecao = state.pessoa = state.serie = '';
|
||||||
searchInput.value = ''; selInst.value = ''; selType.value = ''; selAuthor.value = ''; selEstado.value = ''; selColecao.value = ''; selPessoa.value = ''; rebuildPlace();
|
searchInput.value = ''; selInst.value = ''; selType.value = ''; selAuthor.value = ''; selEstado.value = ''; selColecao.value = ''; selPessoa.value = ''; selSerie.value = ''; rebuildPlace();
|
||||||
resetYear();
|
resetYear();
|
||||||
apply();
|
apply();
|
||||||
});
|
});
|
||||||
@@ -2220,13 +2245,14 @@ function setupFilters(mapData) {
|
|||||||
fillSelect(selEstado, tally('', d => d._st, 1), 'todos');
|
fillSelect(selEstado, tally('', d => d._st, 1), 'todos');
|
||||||
fillSelect(selColecao, tally('', d => d._col, 1), 'todas');
|
fillSelect(selColecao, tally('', d => d._col, 1), 'todas');
|
||||||
fillSelect(selPessoa, tally('', d => d._pes, 5), 'todas');
|
fillSelect(selPessoa, tally('', d => d._pes, 5), 'todas');
|
||||||
|
fillSelect(selSerie, tally('', d => d._serie ? [d._serie] : [], 1), 'todas');
|
||||||
|
|
||||||
// a tag on the card applies itself as a filter; the URL carries the filters
|
// a tag on the card applies itself as a filter; the URL carries the filters
|
||||||
// (?estado=…&topico=…) so a filtered wall can be shared and survives a reload
|
// (?estado=…&topico=…) so a filtered wall can be shared and survives a reload
|
||||||
const URL_KEYS = { q: 'search', inst: 'institution', autor: 'author', tipo: 'type', estado: 'estado', cidade: 'cidade',
|
const URL_KEYS = { q: 'search', inst: 'institution', autor: 'author', tipo: 'type', estado: 'estado', cidade: 'cidade',
|
||||||
bairro: 'bairro', topico: 'topico', colecao: 'colecao', pessoa: 'pessoa' };
|
bairro: 'bairro', topico: 'topico', colecao: 'colecao', pessoa: 'pessoa', serie: 'serie' };
|
||||||
const SELECTS = { institution: selInst, author: selAuthor, type: selType, estado: selEstado, cidade: selCidade,
|
const SELECTS = { institution: selInst, author: selAuthor, type: selType, estado: selEstado, cidade: selCidade,
|
||||||
bairro: selBairro, topico: selTopico, colecao: selColecao, pessoa: selPessoa };
|
bairro: selBairro, topico: selTopico, colecao: selColecao, pessoa: selPessoa, serie: selSerie };
|
||||||
function syncUrl() {
|
function syncUrl() {
|
||||||
const p = new URLSearchParams();
|
const p = new URLSearchParams();
|
||||||
Object.entries(URL_KEYS).forEach(([k, f]) => { if (state[f]) p.set(k, state[f]); });
|
Object.entries(URL_KEYS).forEach(([k, f]) => { if (state[f]) p.set(k, state[f]); });
|
||||||
@@ -2326,6 +2352,7 @@ async function main() {
|
|||||||
const mapData = JSON.parse(await catalogue.blob.text());
|
const mapData = JSON.parse(await catalogue.blob.text());
|
||||||
TPR = mapData.size / mapData.tile;
|
TPR = mapData.size / mapData.tile;
|
||||||
atlasEntries = mapData.map;
|
atlasEntries = mapData.map;
|
||||||
|
seriesTitles = mapData.series || [];
|
||||||
const handles = Object.keys(mapData.map);
|
const handles = Object.keys(mapData.map);
|
||||||
|
|
||||||
// the note only earns its space in placeholder mode — the piece count already
|
// the note only earns its space in placeholder mode — the piece count already
|
||||||
@@ -2342,9 +2369,8 @@ async function main() {
|
|||||||
for (const entry of Object.values(mapData.map)) {
|
for (const entry of Object.values(mapData.map)) {
|
||||||
const meta = entry.meta || {};
|
const meta = entry.meta || {};
|
||||||
if (meta.community) institutions.add(meta.community);
|
if (meta.community) institutions.add(meta.community);
|
||||||
const m = String(meta.date || '').match(/(1[5-9]\d{2}|20\d{2})/);
|
const y = yearOf(meta);
|
||||||
if (m) {
|
if (y != null) {
|
||||||
const y = parseInt(m[1], 10);
|
|
||||||
if (y < minYear) minYear = y;
|
if (y < minYear) minYear = y;
|
||||||
if (y > maxYear) maxYear = y;
|
if (y > maxYear) maxYear = y;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user