query(" CREATE TABLE IF NOT EXISTS harpa_hinos ( id INT AUTO_INCREMENT PRIMARY KEY, numero INT NOT NULL UNIQUE, titulo VARCHAR(255) NOT NULL, letra LONGTEXT NULL, categoria VARCHAR(120) NULL, audio_url TEXT NULL, autor VARCHAR(120) NULL, slug VARCHAR(255) NOT NULL UNIQUE, ativo TINYINT(1) DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 "); try{ $pdo->query(" ALTER TABLE harpa_hinos ADD COLUMN autor VARCHAR(120) NULL AFTER audio_url "); }catch(Throwable $e){} $pdo->query(" CREATE TABLE IF NOT EXISTS harpa_acessos ( id INT AUTO_INCREMENT PRIMARY KEY, hino_id INT NULL, numero INT NULL, page_url TEXT NULL, user_ip VARCHAR(80) NULL, user_agent TEXT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 "); } } if(!function_exists('harpa_slug')){ function harpa_slug($numero, $titulo){ return core_slug($numero . '-' . $titulo); } } if(!function_exists('harpa_get_all')){ function harpa_get_all($pdo){ harpa_create_tables($pdo); $stmt = $pdo->query(" SELECT * FROM harpa_hinos WHERE ativo = 1 ORDER BY numero ASC "); return $stmt->fetchAll(PDO::FETCH_ASSOC); } } if(!function_exists('harpa_get_by_slug')){ function harpa_get_by_slug($pdo, $slug){ harpa_create_tables($pdo); $stmt = $pdo->prepare(" SELECT * FROM harpa_hinos WHERE slug = ? AND ativo = 1 LIMIT 1 "); $stmt->execute([$slug]); return $stmt->fetch(PDO::FETCH_ASSOC); } } if(!function_exists('harpa_get_by_numero')){ function harpa_get_by_numero($pdo, $numero){ harpa_create_tables($pdo); $stmt = $pdo->prepare(" SELECT * FROM harpa_hinos WHERE numero = ? AND ativo = 1 LIMIT 1 "); $stmt->execute([(int)$numero]); return $stmt->fetch(PDO::FETCH_ASSOC); } } if(!function_exists('harpa_get_previous')){ function harpa_get_previous($pdo, $numero){ harpa_create_tables($pdo); $stmt = $pdo->prepare(" SELECT * FROM harpa_hinos WHERE numero < ? AND ativo = 1 ORDER BY numero DESC LIMIT 1 "); $stmt->execute([(int)$numero]); return $stmt->fetch(PDO::FETCH_ASSOC); } } if(!function_exists('harpa_get_next')){ function harpa_get_next($pdo, $numero){ harpa_create_tables($pdo); $stmt = $pdo->prepare(" SELECT * FROM harpa_hinos WHERE numero > ? AND ativo = 1 ORDER BY numero ASC LIMIT 1 "); $stmt->execute([(int)$numero]); return $stmt->fetch(PDO::FETCH_ASSOC); } } if(!function_exists('harpa_save_hino')){ function harpa_save_hino($pdo, $numero, $titulo, $letra = '', $audioUrl = '', $categoria = '', $autor = ''){ harpa_create_tables($pdo); $slug = harpa_slug($numero, $titulo); if($autor === ''){ $autor = harpa_extract_author($letra); } $stmt = $pdo->prepare(" INSERT INTO harpa_hinos (numero, titulo, letra, categoria, audio_url, autor, slug, ativo) VALUES (?, ?, ?, ?, ?, ?, ?, 1) ON DUPLICATE KEY UPDATE titulo = VALUES(titulo), letra = VALUES(letra), categoria = VALUES(categoria), audio_url = VALUES(audio_url), autor = VALUES(autor), slug = VALUES(slug), ativo = 1 "); $stmt->execute([ (int)$numero, $titulo, $letra, $categoria, $audioUrl, $autor, $slug ]); return [ 'numero' => (int)$numero, 'titulo' => $titulo, 'slug' => $slug, 'autor' => $autor ]; } } if(!function_exists('harpa_register_access')){ function harpa_register_access($pdo, $hino){ harpa_create_tables($pdo); $stmt = $pdo->prepare(" INSERT INTO harpa_acessos (hino_id, numero, page_url, user_ip, user_agent) VALUES (?, ?, ?, ?, ?) "); return $stmt->execute([ $hino['id'] ?? null, $hino['numero'] ?? null, $_SERVER['REQUEST_URI'] ?? '', $_SERVER['REMOTE_ADDR'] ?? '', $_SERVER['HTTP_USER_AGENT'] ?? '' ]); } } if(!function_exists('harpa_is_author_signature')){ function harpa_is_author_signature($linha){ $linha = trim((string)$linha); if($linha === ''){ return false; } return (bool)preg_match('/^[A-ZÁÉÍÓÚÂÊÔÃÕÇ]\.?([A-ZÁÉÍÓÚÂÊÔÃÕÇ]\.?){1,6}$/u', $linha); } } if(!function_exists('harpa_extract_author')){ function harpa_extract_author($letra){ $texto = trim((string)$letra); if($texto === ''){ return ''; } $linhas = preg_split('/\R/u', $texto); $autores = []; foreach($linhas as $linha){ $linha = trim($linha); if(harpa_is_author_signature($linha)){ $autores[] = $linha; continue; } if(preg_match('/\s+([A-ZÁÉÍÓÚÂÊÔÃÕÇ]\.?([A-ZÁÉÍÓÚÂÊÔÃÕÇ]\.?){1,6})\s*$/u', $linha, $m)){ $autores[] = trim($m[1]); } } $autores = array_values(array_unique($autores)); return implode(', ', $autores); } } if(!function_exists('harpa_sync_authors')){ function harpa_sync_authors($pdo){ harpa_create_tables($pdo); $stmt = $pdo->query(" SELECT id, letra, autor FROM harpa_hinos "); $hinos = $stmt->fetchAll(PDO::FETCH_ASSOC); $update = $pdo->prepare(" UPDATE harpa_hinos SET autor = ? WHERE id = ? "); $total = 0; foreach($hinos as $hino){ if(!empty($hino['autor'])){ continue; } $autor = harpa_extract_author($hino['letra']); if($autor !== ''){ $update->execute([$autor, $hino['id']]); $total++; } } return $total; } } if(!function_exists('harpa_is_upper_line')){ function harpa_is_upper_line($linha){ $linha = trim((string)$linha); if($linha === ''){ return false; } if(harpa_is_author_signature($linha)){ return false; } $somenteLetras = preg_replace('/[^A-Za-zÀ-ÿ]/u', '', $linha); if(mb_strlen($somenteLetras, 'UTF-8') < 8){ return false; } return $linha === mb_strtoupper($linha, 'UTF-8'); } } if(!function_exists('harpa_normalize_lyrics_text')){ function harpa_normalize_lyrics_text($letra){ $texto = trim((string)$letra); if($texto === ''){ return ''; } $texto = str_replace(["\r\n", "\r"], "\n", $texto); $texto = preg_replace('/^\s*[A-ZÁÉÍÓÚÂÊÔÃÕÇ]\.?([A-ZÁÉÍÓÚÂÊÔÃÕÇ]\.?){1,6}\s*$/mu', '', $texto); $texto = preg_replace('/\s+[A-ZÁÉÍÓÚÂÊÔÃÕÇ]\.?([A-ZÁÉÍÓÚÂÊÔÃÕÇ]\.?){1,6}\s*$/mu', '', $texto); $texto = preg_replace('/^(\d+)\.\s*/mu', "$1 ", $texto); $texto = preg_replace('/([^\n])\s+([2-9])\s+([A-ZÁÉÍÓÚÂÊÔÃÕÇ])/u', "$1\n$2 $3", $texto); $texto = preg_replace('/([A-ZÁÉÍÓÚÂÊÔÃÕÇ]{2,}[,;!?.])([A-ZÁÉÍÓÚÂÊÔÃÕÇ][a-záéíóúâêôãõç])/u', "$1\n$2", $texto); $texto = preg_replace("/\n{3,}/", "\n\n", $texto); return trim($texto); } } if(!function_exists('harpa_detect_lyrics_blocks')){ function harpa_detect_lyrics_blocks($letra){ $texto = harpa_normalize_lyrics_text($letra); if($texto === ''){ return []; } $linhas = preg_split('/\n/u', $texto); $blocos = []; $atual = []; $tipoAtual = 'estrofe'; $numeroAtual = null; $flush = function() use (&$blocos, &$atual, &$tipoAtual, &$numeroAtual){ if(empty($atual)){ return; } $blocos[] = [ 'tipo' => $tipoAtual, 'numero' => $numeroAtual, 'linhas' => $atual ]; $atual = []; $tipoAtual = 'estrofe'; $numeroAtual = null; }; $totalLinhas = count($linhas); for($i = 0; $i < $totalLinhas; $i++){ $linha = trim($linhas[$i]); if($linha === ''){ $proximaLinha = ''; for($j = $i + 1; $j < $totalLinhas; $j++){ $teste = trim($linhas[$j]); if($teste !== ''){ $proximaLinha = $teste; break; } } $proximaEhNumero = preg_match('/^(\d+)\s+/u', $proximaLinha); $proximaEhCoro = harpa_is_upper_line($proximaLinha); if( $tipoAtual === 'coro' && $proximaLinha !== '' && $proximaEhCoro ){ continue; } if( $tipoAtual === 'estrofe' && $proximaLinha !== '' && !$proximaEhNumero && !$proximaEhCoro ){ continue; } $flush(); continue; } if(harpa_is_author_signature($linha)){ continue; } if(preg_match('/^(\d+)\s+(.*)$/u', $linha, $m)){ $flush(); $tipoAtual = 'estrofe'; $numeroAtual = (int)$m[1]; $resto = trim($m[2]); if($resto !== ''){ $atual[] = $resto; } continue; } $linhaEhCoro = harpa_is_upper_line($linha); if($linhaEhCoro && $tipoAtual !== 'coro'){ $flush(); $tipoAtual = 'coro'; } if(!$linhaEhCoro && $tipoAtual === 'coro'){ $flush(); $tipoAtual = 'estrofe'; } $atual[] = $linha; } $flush(); $blocosUnidos = []; foreach($blocos as $bloco){ $ultimo = count($blocosUnidos) - 1; if( $ultimo >= 0 && $bloco['tipo'] === 'coro' && $blocosUnidos[$ultimo]['tipo'] === 'coro' ){ $blocosUnidos[$ultimo]['linhas'] = array_merge( $blocosUnidos[$ultimo]['linhas'], [''], $bloco['linhas'] ); }else{ $blocosUnidos[] = $bloco; } } return $blocosUnidos; } } if(!function_exists('harpa_format_lyrics')){ function harpa_format_lyrics($letra){ $blocos = harpa_detect_lyrics_blocks($letra); if(empty($blocos)){ return ''; } $html = ''; $numeroVisualEstrofe = 0; foreach($blocos as $bloco){ if($bloco['tipo'] === 'coro'){ $html .= '
'; $html .= '
Refrão / Coro
'; }else{ $numeroVisualEstrofe++; $numero = $bloco['numero'] ?: $numeroVisualEstrofe; $html .= '
'; $html .= '
Estrofe ' . e($numero) . '
'; } foreach($bloco['linhas'] as $linha){ if(trim($linha) === ''){ $html .= '
'; }else{ $html .= '
' . e($linha) . '
'; } } $html .= '
'; } return $html; } }