(add): Adição de gestçao do Museu

This commit is contained in:
Rafael Tavares Juliani 2026-06-15 20:45:19 -03:00
parent 2b8862c5cd
commit d2f9414e7d
5 changed files with 375 additions and 8 deletions

View File

@ -21,7 +21,15 @@ Os ":" (dois pontos) serão substituídos por \_dp\_; o "." (ponto), por \_p\_ e
### Instruções para o prefixo M ### Instruções para o prefixo M
O prefixo M é do Meta Museu da Matemática da Editora Moan. Ele sempre redireciona para o gitea da editora, para o repositório do museu. Ele sempre buscará um README.md em que contém os metadados, as variações, a visualização do objeto e, no mesmo diretório, os os arquivos correspondentes.
Se a busca pelo ARK for com a interrogação, isto é, tentando acessar os metadados, o solicitante será redirecionado para uma API que retornará um json com todos os metadados.
#### Sobre os nomes dos arquivos
Os ARKs serão pastas no gitea e as variações serão ãncoras no arquivo README.md. Os nomes das pastas deve ter o título do objeto catalogado com "_° no lugar de espaças, tudo em minúculas e o hífen "-" como separador para indicar o ARK e aí, dentro da pasta o README.md. Exemplo "osso_de_ishango-M3GD/README.md". Seguindo a natureza hierárquica dos ARKs, se for um objeto que é parte do original (mais geral), deve-se criar uma pasta dentro da original seguindo os mesmos critério e dentro dela um outro README.md.
Obs.: Esses ARKs não possuem apontamento. O padrão é sempre como descrito acima. Caso precise alterar, será necessário uma mudança no código.
## Observações ## Observações

View File

@ -2,7 +2,97 @@
function processarPrefixo_M($NAAN, $ark_sem_NAAN, $tem_interrogacao, $resto) { function processarPrefixo_M($NAAN, $ark_sem_NAAN, $tem_interrogacao, $resto) {
$site_base = 'https://gitea.livro.online';
$usuario = "metamuseudamatematica";
$repositorio = "arcevo";
$branch = "main";
// Constrói a URL base para o redirecionamento final (caso não seja JSON)
$localizacao_base = $site_base . '/' . $usuario . '/' . $repositorio . '/src/branch/' . $branch . '/';
$variacao_arr = explode('.', $ark_sem_NAAN);
$variacao = count($variacao_arr) > 1 ? end($variacao_arr) : false;
$ark_procurado = '-' . ltrim($variacao_arr[0] , '/');
// O recursive=1 é OBRIGATÓRIO para ver pastas dentro de pastas
$api_url = "https://gitea.livro.online/api/v1/repos/$usuario/$repositorio/git/trees/$branch?recursive=1";
$options = [
"http" => [ "method" => "GET", "header" => "User-Agent: PHP-Script\r\n" ]
];
$context = stream_context_create($options);
$response = @file_get_contents($api_url, false, $context);
$dados = json_decode($response);
$destino='';
$titulo='';
$encontrado = false;
if (isset($dados->tree)) {
foreach ($dados->tree as $item) {
// Se NÃO for pasta (tree), pula para o próximo item
if ($item->type !== 'tree') {
continue;
}
// Se chegou aqui, é uma pasta.
if (str_ends_with($item->path, $ark_procurado)) {
// Define o destino padrão (redirecionamento)
$destino = $variacao
? $localizacao_base . "{$item->path}/README.md#variação-{$variacao}"
: $localizacao_base . "{$item->path}/README.md";
$titulo = strstr($item->path, $ark_procurado, true);
$encontrado = true;
// SE TIVER INTERROGAÇÃO -> ACIONA API JSON
if ($tem_interrogacao) {
require __DIR__ . '/../Mjson/processador.php';
buscarOuCriarJson(
$item->path,
$variacao,
$usuario,
$repositorio,
$branch,
$site_base
);
}
break;
}
}
}
if ($encontrado) {
return [
'ok' => true,
'destino' => $destino,
'msg' => $destino . ' encontrado.',
'titulo' => $titulo
];
} else {
// Se saiu do loop sem encontrar nada, retorna FALSE
return [
'ok' => false,
'destino' => '',
'msg' => 'ark:68745/' . $ark_sem_NAAN . ' não encontrada.',
'titulo' => ''
];
}
} }
?> ?>

View File

@ -45,7 +45,7 @@ function processarPrefixo_eM($NAAN, $ark_sem_NAAN, $tem_interrogacao, $resto) {
if ($apontamento){ if ($apontamento){
return ['ok' => true, 'destino' => $apontamento.$resto, 'msg' => $ark_formatado.' encontrado. Direcionando...', 'titulo' => $titulo]; return ['ok' => true, 'destino' => $apontamento, 'msg' => $ark_formatado.' encontrado. Direcionando...', 'titulo' => $titulo];
} }

View File

@ -0,0 +1,261 @@
<?php
function buscarOuCriarJson($path_item, $variacao, $usuario, $repositorio, $branch, $site_gitea) {
header('Content-Type: application/json; charset=utf-8');
// URL RAW
$url_markdown_raw = "$site_gitea/$usuario/$repositorio/raw/branch/$branch/$path_item/README.md";
// Nome do arquivo local
$nome_base = str_replace('/', '_b_', $path_item);
if ($variacao) {
$nome_base .= "_p_" . $variacao;
}
$caminho_json_local = __DIR__ . '/' . $nome_base . ".json";
// Verificação de Datas
$precisa_atualizar = false;
if (!file_exists($caminho_json_local)) {
$precisa_atualizar = true;
} else {
$data_local = filemtime($caminho_json_local);
$data_remota = _obterDataModificacaoRemota($url_markdown_raw);
if ($data_remota === false || $data_remota > $data_local) {
$precisa_atualizar = true;
}
}
// Ação
if ($precisa_atualizar) {
$conteudo_md = @file_get_contents($url_markdown_raw);
if ($conteudo_md === false) {
echo json_encode(['ok' => false, 'msg' => 'Erro ao baixar MD.', 'url' => $url_markdown_raw]);
exit;
}
$config = [
'usuario' => $usuario,
'repositorio' => $repositorio,
'branch' => $branch,
'site_gitea' => $site_gitea
];
// Processa o Scrapping
$dados_processados = _realizarScraping($conteudo_md, $variacao, $path_item, $config);
// Gera o JSON final
$json_final = json_encode($dados_processados, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
file_put_contents($caminho_json_local, $json_final);
echo $json_final;
exit;
} else {
readfile($caminho_json_local);
exit;
}
}
// --- Funções de Parsing ---
function _realizarScraping($markdown, $variacao, $path_original, $config) {
// Configura data para Horário de Brasília (GMT-3)
try {
$dataBrasilia = new DateTime('now', new DateTimeZone('America/Sao_Paulo'));
$dataGeracao = $dataBrasilia->format('Y-m-d H:i:s');
} catch (Exception $e) {
// Fallback caso o servidor não tenha timezone configurado
$dataGeracao = date('Y-m-d H:i:s') . ' (Server Time)';
}
$json = [
'meta' => [
'path_original' => $path_original,
'variacao' => $variacao,
'gerado_em' => $dataGeracao
]
];
// Mapeamento de campos especiais que vão para a RAIZ
$mapeamentoEspeciais = [
'identificador_do_registro' => 'ark',
'visualizacao_publica_ark' => 'link_visualizacao_publica',
'visualizacao_no_meta_museu_da_matematica_editora_moan' => 'link_meta_museu',
'denominacao' => 'titulo',
'outras_denominacoes' => 'outras_denominacoes',
'tipo_de_bem_objeto_original' => 'tipo_bem',
'categoria_museologica' => 'categoria_museologica',
'subcategoria' => 'subcategoria'
];
$linhas = explode("\n", $markdown);
$secaoAtual = 'inicio';
$chaveAtual = null;
$dadosSecoes = [];
$dadosSecoes[$secaoAtual] = [];
foreach ($linhas as $linha) {
$linha = trim($linha);
if ($linha === '') continue;
// 1. TÍTULOS (##)
if (preg_match('/^#{2,4}\s+(.*)$/', $linha, $matches)) {
$nomeSecaoRaw = $matches[1];
$secaoAtual = _limparChave($nomeSecaoRaw);
$chaveAtual = null;
if (!isset($dadosSecoes[$secaoAtual])) {
$dadosSecoes[$secaoAtual] = [];
}
continue;
}
// 2. CHAVE-VALOR (**Chave:** Valor)
if (preg_match('/.*\*\*(.+?):\*\*\s*(.*)$/', $linha, $matches)) {
$chaveRaw = $matches[1];
$valorInicial = $matches[2];
$chaveLimpa = _limparChave($chaveRaw);
$valorLimpo = _limparTextoGeral($valorInicial);
if (array_key_exists($chaveLimpa, $mapeamentoEspeciais)) {
$chaveRaiz = $mapeamentoEspeciais[$chaveLimpa];
$json[$chaveRaiz] = $valorLimpo;
$chaveAtual = null;
} else {
$chaveAtual = $chaveLimpa;
$dadosSecoes[$secaoAtual][$chaveAtual] = $valorLimpo;
}
continue;
}
// 3. ITENS DE LISTA (- Item)
if (preg_match('/^-\s+(.*)$/', $linha, $matches) && !preg_match('/^-{3,}$/', $linha)) {
$itemLista = _limparTextoGeral($matches[1]);
if ($chaveAtual) {
if (!is_array($dadosSecoes[$secaoAtual][$chaveAtual])) {
$valAtual = $dadosSecoes[$secaoAtual][$chaveAtual];
if ($valAtual === '') {
$dadosSecoes[$secaoAtual][$chaveAtual] = [];
} else {
$dadosSecoes[$secaoAtual][$chaveAtual] = [$valAtual];
}
}
$dadosSecoes[$secaoAtual][$chaveAtual][] = $itemLista;
} else {
if (!isset($dadosSecoes[$secaoAtual]['lista_geral'])) {
$dadosSecoes[$secaoAtual]['lista_geral'] = [];
}
$dadosSecoes[$secaoAtual]['lista_geral'][] = $itemLista;
}
continue;
}
// 4. TEXTO GERAL
if (substr($linha, 0, 3) !== '```') {
$textoLimpo = _limparTextoGeral($linha);
if ($textoLimpo === '') continue;
if ($chaveAtual) {
$valAtual = $dadosSecoes[$secaoAtual][$chaveAtual];
if (is_array($valAtual)) {
$chaveAtual = null;
goto texto_geral_rotulo;
}
if ($valAtual !== '') {
$dadosSecoes[$secaoAtual][$chaveAtual] .= " " . $textoLimpo;
} else {
$dadosSecoes[$secaoAtual][$chaveAtual] = $textoLimpo;
}
} else {
texto_geral_rotulo:
if (!isset($dadosSecoes[$secaoAtual]['texto_geral'])) {
$dadosSecoes[$secaoAtual]['texto_geral'] = '';
}
$sep = ($dadosSecoes[$secaoAtual]['texto_geral'] !== '') ? " " : "";
$dadosSecoes[$secaoAtual]['texto_geral'] .= $sep . $textoLimpo;
}
}
}
// --- MONTAGEM DO JSON FINAL ---
foreach ($dadosSecoes as $nomeSecao => $conteudo) {
if ($nomeSecao === 'inicio' && empty($conteudo)) continue;
if (empty($conteudo)) continue;
if (count($conteudo) === 1 && isset($conteudo['lista_geral'])) {
$json[$nomeSecao] = $conteudo['lista_geral'];
}
elseif (count($conteudo) === 1 && isset($conteudo['texto_geral'])) {
$json[$nomeSecao] = $conteudo['texto_geral'];
}
else {
$objetoLimpo = [];
foreach ($conteudo as $k => $v) {
if ($k === 'lista_geral') {
$objetoLimpo['itens'] = $v;
} elseif ($k === 'texto_geral') {
$objetoLimpo['descricao_geral'] = $v;
} else {
$objetoLimpo[$k] = $v;
}
}
$json[$nomeSecao] = $objetoLimpo;
}
}
return $json;
}
/**
* LIMPEZA AGRESSIVA PARA CHAVES
*/
function _limparChave($texto) {
// 1. Remove qualquer caractere que NÃO seja Letra, Número ou Espaço
$texto = preg_replace('/[^\p{L}\p{N}\s]/u', '', $texto);
// 2. Transliteração
$texto = iconv('UTF-8', 'ASCII//TRANSLIT', $texto);
// 3. Formatação
$texto = trim($texto);
$texto = strtolower($texto);
$texto = preg_replace('/\s+/', '_', $texto);
return $texto;
}
/**
* Limpeza para Valores (Mantém pontuação básica, remove emojis)
*/
function _limparTextoGeral($texto) {
// Remove apenas símbolos gráficos e emojis
$texto = preg_replace('/[\p{So}\p{Sk}\p{Sm}\p{Sc}\p{Co}\p{Cn}]/u', '', $texto);
return trim($texto);
}
function _obterDataModificacaoRemota($url) {
$options = [ 'http' => [ 'method' => 'HEAD', 'header' => "User-Agent: PHP-Script\r\n" ] ];
$context = stream_context_create($options);
$headers = @get_headers($url, 1, $context);
if ($headers && isset($headers['Last-Modified'])) {
return strtotime($headers['Last-Modified']);
}
return false;
}
?>

View File

@ -47,7 +47,7 @@ function init() {
$ark = ""; $ark = "";
return ['ok'=>false,'destino'=>'','msg'=>'Nenhum ARK foi passado...','qrark'=> false,'ark_full'=>'', 'tem_interrogacao'=>false]; return ['ok'=>false,'destino'=>'','msg'=>'Nenhum ARK foi passado...','qrark'=> false,'ark_full'=>'', 'tem_interrogacao'=>false, 'consulta_original_encontrada' => false];
} }
@ -94,7 +94,7 @@ function init() {
if ($ark === '') { if ($ark === '') {
return ['ok'=>false,'destino'=>'','msg'=>'ARK vazio.','qrark'=>$qrark,'ark_full'=>'', 'tem_interrogacao'=>false]; return ['ok'=>false,'destino'=>'','msg'=>'ARK vazio.','qrark'=>$qrark,'ark_full'=>'', 'tem_interrogacao'=>false, 'consulta_original_encontrada' => false];
} }
@ -124,7 +124,7 @@ function init() {
//-------------------------- FIM PREFIXOS ARK -------------------------- //-------------------------- FIM PREFIXOS ARK --------------------------
if (!is_callable($buscar_ark)) { if (!is_callable($buscar_ark)) {
return ['ok'=>false,'destino'=>'','msg'=>'Prefixo ARK desconhecido.','qrark'=>$qrark,'ark_full'=>$ark_full, 'tem_interrogacao'=>$tem_interrogacao]; return ['ok'=>false,'destino'=>'','msg'=>'Prefixo ARK desconhecido.','qrark'=>$qrark,'ark_full'=>$ark_full, 'tem_interrogacao'=>$tem_interrogacao, 'consulta_original_encontrada' => false];
} }
@ -134,8 +134,9 @@ function init() {
$identificador_ark = false; $identificador_ark = false;
$resultado = ['ok'=>false,'destino'=>'','msg'=>'ARK não encontrado.Erro não identificado.','qrark'=>$qrark,'ark'=>$ark_full, 'tem_interrogacao'=>$tem_interrogacao]; $resultado = ['ok'=>false,'destino'=>'','msg'=>'ARK não encontrado.Erro não identificado.','qrark'=>$qrark,'ark'=>$ark_full, 'tem_interrogacao'=>$tem_interrogacao, 'consulta_original_encontrada' => false];
$consulta_original_encontrada = false;
do { do {
@ -169,6 +170,8 @@ function init() {
$identificador_ark = $resultado["ok"]; $identificador_ark = $resultado["ok"];
$consulta_original_encontrada = ($index === 0);
$index++; $index++;
} while ($tamanho > 1 && !$identificador_ark); } while ($tamanho > 1 && !$identificador_ark);
@ -178,6 +181,7 @@ function init() {
$resultado['qrark'] = $qrark; $resultado['qrark'] = $qrark;
$resultado['ark_full'] = $ark_full; // <-- use este no JS/analytics $resultado['ark_full'] = $ark_full; // <-- use este no JS/analytics
$resultado['tem_interrogacao'] = $tem_interrogacao; $resultado['tem_interrogacao'] = $tem_interrogacao;
$resultado['consulta_original_encontrada'] = $consulta_original_encontrada;
return $resultado; return $resultado;
@ -198,6 +202,8 @@ $qrark = $conteudo["qrark"];
$tem_interrogacao = $conteudo['tem_interrogacao']; $tem_interrogacao = $conteudo['tem_interrogacao'];
$consulta_original_encontrada = $conteudo['consulta_original_encontrada'];
function slug_titulo($s) { function slug_titulo($s) {
$s = trim((string)$s); $s = trim((string)$s);
if ($s === '') return ''; if ($s === '') return '';
@ -263,6 +269,7 @@ background: linear-gradient(to right, #FFC371, #FF5F6D); /* W3C, IE 10+/ Edge, F
const arkFull = <?= json_encode($arkFull) ?>; // "68745/eM8Rf/gJ.ht" const arkFull = <?= json_encode($arkFull) ?>; // "68745/eM8Rf/gJ.ht"
const qrark = <?= json_encode($qrark) ?>; // boolean const qrark = <?= json_encode($qrark) ?>; // boolean
const consultaMetadados = <?= json_encode($tem_interrogacao) ?>; // boolean const consultaMetadados = <?= json_encode($tem_interrogacao) ?>; // boolean
const consulta_original_encontrada = <?= json_encode($consulta_original_encontrada) ?>;
const tituloSlug = <?= json_encode($tituloSlug) ?>; // "o-titulo-do-livro" const tituloSlug = <?= json_encode($tituloSlug) ?>; // "o-titulo-do-livro"
const spinner = document.getElementById('spinner'); const spinner = document.getElementById('spinner');
@ -282,6 +289,7 @@ background: linear-gradient(to right, #FFC371, #FF5F6D); /* W3C, IE 10+/ Edge, F
if (ok) { if (ok) {
const parts = []; const parts = [];
if (!consulta_original_encontrada) parts.push('404');
if (qrark) parts.push('qrcodeLivro'); if (qrark) parts.push('qrcodeLivro');
if (consultaMetadados) parts.push('meta'); if (consultaMetadados) parts.push('meta');
if (tituloSlug) parts.push(tituloSlug); if (tituloSlug) parts.push(tituloSlug);