taiageweb/scripts/trebep_a_audio.py

107 lines
3.7 KiB
Python

"""
Convierte TREBEP.md a audio dividido por Títulos.
Genera un MP3 por Título (8 Títulos + Disposiciones) en audios/mp3/bloque1/.
Usa edge_tts (es-ES-AlvaroNeural) + ffmpeg, igual que md_a_audio_con_edge_y_metadatos.py
"""
import asyncio
import edge_tts
import re
import os
from pathlib import Path
def limpiar_markdown(texto):
texto = re.sub(r'```.*?```', ' [código] ', texto, flags=re.DOTALL)
texto = re.sub(r'\|.*?\|', '', texto)
texto = re.sub(r'[#*_~`>]', '', texto)
return ' '.join(texto.split())
def dividir_por_titulos(md_path):
"""
Devuelve lista de (nombre_fichero, titulo_meta, texto_seccion).
Las secciones son los 8 Títulos + un bloque final de Disposiciones.
"""
texto = Path(md_path).read_text(encoding='utf-8')
secciones = []
# Separar por ## TÍTULO
partes = re.split(r'(?=^## TÍTULO)', texto, flags=re.MULTILINE)
for parte in partes:
if not parte.strip():
continue
match = re.match(r'^## (TÍTULO ([IVX]+)) · (.+)', parte, re.MULTILINE)
if match:
titulo_num = match.group(2)
titulo_texto = match.group(3).strip()
num_romano = {'I': 1, 'II': 2, 'III': 3, 'IV': 4,
'V': 5, 'VI': 6, 'VII': 7, 'VIII': 8}.get(titulo_num, 0)
nombre = f'trebep_titulo{num_romano:02d}_audio'
meta = f'TREBEP · Título {titulo_num}: {titulo_texto}'
# Si hay disposiciones al final de TÍTULO VIII, separarlas
idx_disp = parte.find('\n#### Disposición adicional primera')
if idx_disp != -1:
secciones.append((nombre, meta, parte[:idx_disp]))
disp_texto = parte[idx_disp:]
secciones.append(('trebep_disposiciones_audio',
'TREBEP · Disposiciones adicionales, transitorias y finales',
disp_texto))
else:
secciones.append((nombre, meta, parte))
else:
# Bloque inicial (antes del primer Título): ignorar si es mínimo
if len(parte.strip()) > 100:
secciones.append(('trebep_intro_audio', 'TREBEP · Introducción', parte))
return secciones
async def generar_audio(nombre, meta, texto, mp3_dir):
mp3_path = mp3_dir / f'{nombre.replace("_audio", "")}.mp3'
temp_path = mp3_dir / f'{nombre}.temp.mp3'
if mp3_path.exists():
print(f'⏭️ Ya existe, omitiendo: {mp3_path.name}')
return
texto_limpio = limpiar_markdown(texto)
print(f'🎙️ Generando: {mp3_path.name} ({len(texto_limpio.split())} palabras)...')
comunicar = edge_tts.Communicate(texto_limpio, 'es-ES-AlvaroNeural')
await comunicar.save(str(temp_path))
meta_escaped = meta.replace('"', '\\"')
comando = (
f'ffmpeg -i "{temp_path}" -codec:a libmp3lame -b:a 192k -ar 44100 '
f'-metadata title="{meta_escaped}" -id3v2_version 3 -write_id3v1 1 '
f'-y "{mp3_path}" > /dev/null 2>&1'
)
os.system(comando)
if temp_path.exists():
temp_path.unlink()
print(f'✅ Listo: {mp3_path.name} (Título: {meta})')
async def main():
base_dir = Path(__file__).parent.parent
md_path = base_dir / 'bloque1' / 'leyes' / 'TREBEP.md'
mp3_dir = base_dir / 'audios' / 'mp3' / 'bloque1'
mp3_dir.mkdir(parents=True, exist_ok=True)
secciones = dividir_por_titulos(md_path)
print(f'\nTREBEP.md → {len(secciones)} secciones de audio\n')
for nombre, meta, texto in secciones:
await generar_audio(nombre, meta, texto, mp3_dir)
print('\n🎧 Todos los audios del TREBEP generados en:', mp3_dir)
if __name__ == '__main__':
asyncio.run(main())