From d2f9414e7d3a5de148eb82e655a5efaea53e01ef Mon Sep 17 00:00:00 2001 From: Rafael Tavares Juliani Date: Mon, 15 Jun 2026 20:45:19 -0300 Subject: [PATCH] =?UTF-8?q?(add):=20Adi=C3=A7=C3=A3o=20de=20gest=C3=A7ao?= =?UTF-8?q?=20do=20Museu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 + .../LogicaPrefixos/processarPrefixo_M.php | 92 +++++- .../LogicaPrefixos/processarPrefixo_eM.php | 2 +- pasta_publica/Mjson/processador.php | 261 ++++++++++++++++++ pasta_publica/index.php | 20 +- 5 files changed, 375 insertions(+), 8 deletions(-) create mode 100644 pasta_publica/Mjson/processador.php diff --git a/README.md b/README.md index e328c1c..6882d8b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,15 @@ Os ":" (dois pontos) serão substituídos por \_dp\_; o "." (ponto), por \_p\_ e ### 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 diff --git a/pasta_publica/LogicaPrefixos/processarPrefixo_M.php b/pasta_publica/LogicaPrefixos/processarPrefixo_M.php index 9a3cdc8..fabe0de 100644 --- a/pasta_publica/LogicaPrefixos/processarPrefixo_M.php +++ b/pasta_publica/LogicaPrefixos/processarPrefixo_M.php @@ -2,7 +2,97 @@ 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' => '' + ]; + } } ?> \ No newline at end of file diff --git a/pasta_publica/LogicaPrefixos/processarPrefixo_eM.php b/pasta_publica/LogicaPrefixos/processarPrefixo_eM.php index 946e6d8..f1061d6 100644 --- a/pasta_publica/LogicaPrefixos/processarPrefixo_eM.php +++ b/pasta_publica/LogicaPrefixos/processarPrefixo_eM.php @@ -45,7 +45,7 @@ function processarPrefixo_eM($NAAN, $ark_sem_NAAN, $tem_interrogacao, $resto) { 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]; } diff --git a/pasta_publica/Mjson/processador.php b/pasta_publica/Mjson/processador.php new file mode 100644 index 0000000..8045dc6 --- /dev/null +++ b/pasta_publica/Mjson/processador.php @@ -0,0 +1,261 @@ + $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; +} +?> \ No newline at end of file diff --git a/pasta_publica/index.php b/pasta_publica/index.php index 7ec4e52..695b42b 100644 --- a/pasta_publica/index.php +++ b/pasta_publica/index.php @@ -47,7 +47,7 @@ function init() { $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 === '') { - 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 -------------------------- 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; - $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 { @@ -169,6 +170,8 @@ function init() { $identificador_ark = $resultado["ok"]; + $consulta_original_encontrada = ($index === 0); + $index++; } while ($tamanho > 1 && !$identificador_ark); @@ -176,8 +179,9 @@ function init() { $resultado['qrark'] = $qrark; - $resultado['ark_full'] = $ark_full; // <-- use este no JS/analytics - $resultado['tem_interrogacao'] = $tem_interrogacao; + $resultado['ark_full'] = $ark_full; // <-- use este no JS/analytics + $resultado['tem_interrogacao'] = $tem_interrogacao; + $resultado['consulta_original_encontrada'] = $consulta_original_encontrada; return $resultado; @@ -198,6 +202,8 @@ $qrark = $conteudo["qrark"]; $tem_interrogacao = $conteudo['tem_interrogacao']; +$consulta_original_encontrada = $conteudo['consulta_original_encontrada']; + function slug_titulo($s) { $s = trim((string)$s); if ($s === '') return ''; @@ -263,6 +269,7 @@ background: linear-gradient(to right, #FFC371, #FF5F6D); /* W3C, IE 10+/ Edge, F const arkFull = ; // "68745/eM8Rf/gJ.ht" const qrark = ; // boolean const consultaMetadados = ; // boolean + const consulta_original_encontrada = ; const tituloSlug = ; // "o-titulo-do-livro" const spinner = document.getElementById('spinner'); @@ -282,6 +289,7 @@ background: linear-gradient(to right, #FFC371, #FF5F6D); /* W3C, IE 10+/ Edge, F if (ok) { const parts = []; + if (!consulta_original_encontrada) parts.push('404'); if (qrark) parts.push('qrcodeLivro'); if (consultaMetadados) parts.push('meta'); if (tituloSlug) parts.push(tituloSlug);