Sincronizar mu-plugins/ y scripts/ con el estado real del sitio (2026-07-16)

Este repo llevaba desde el 28-jun sin actualizarse (salvo sync_carta_from_prod.py).
Se pone al dia con 3 semanas de trabajo que solo vivian en el checkout local
completo del proyecto:

- Fix del buscador (issue #178): AND obligatorio en FULLTEXT (antes devolvia
  practicamente todo el sitio con cualquier busqueda), exclusion de paginas
  indice residuales de la migracion K2, soporte de frase exacta entre comillas.
- Nuevos mu-plugins ya desplegados a prod: fea-carta-id-api, fea-cloudflare-realip,
  fea-crear-autor-api, fea-gsc-verification, fea-legacy-redirect (cutover
  Joomla->WP, ver issue #162).
- TTS multi-voz por autor, scripts de traduccion, sync de audio a prod,
  homenajes Mardones/Galarreta.

Se mantiene la estructura plana del repo (mu-plugins/ + scripts/, sin el
wordpress/wp-content/ del checkout completo) tal y como documenta el README:
es la convencion establecida para este repo, mas limpia para quien solo
necesita leer el codigo. Anadido .gitignore (cache de Python que no debia
commitearse).

Fuente: checkout local completo del proyecto, rama main (commit 69e849d).
This commit is contained in:
2026-07-15 20:26:43 -04:00
parent d044e229dc
commit 6b61250b0b
35 changed files with 1482 additions and 45 deletions
+31 -7
View File
@@ -45,6 +45,22 @@ def creds():
KEY, GID = creds()
H_JSON = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}
# Voz clonada por autor (WP user_id -> voice_id). Issue #152: solo se aplica a
# los artículos de ese autor; el resto sigue con la voz por defecto (Nico).
AUTHOR_VOICES = {
382: "FrayMarcosFeadulta2026", # Fray Marcos
383: "PagolaFeadulta2026", # José Antonio Pagola
774: "SicreFeadulta2026", # José Luis Sicre
386: "ArregiFeadulta2026", # José Arregi
}
def voice_for_author(author_id, default_voice):
try:
return AUTHOR_VOICES.get(int(author_id), default_voice)
except (TypeError, ValueError):
return default_voice
def _q(url):
return f"{url}?GroupId={GID}" if GID else url
@@ -83,7 +99,7 @@ def get_post_text(pid):
raw = html.unescape(raw)
paras = [re.sub(r"\s+", " ", p).strip() for p in raw.split("\n") if len(p.strip()) > 1]
paras = trim_after_author_signature(paras)
return d["title"], "\n\n".join(paras)
return d["title"], "\n\n".join(paras), d.get("author")
def is_author_signature(text):
@@ -114,12 +130,20 @@ def is_author_signature(text):
def trim_after_author_signature(paras):
out = []
"""Corta tras la firma final del autor, buscando desde el final hacia
atrás para no confundirla con encabezados iniciales (p.ej. "CORPUS (A)",
"DOMINGO XI (A)") que también matchean la heurística de is_author_signature
pero aparecen como primer párrafo, no como firma. Solo cuenta como firma
si hay al menos 200 caracteres de contenido real antes de ella."""
prefix_len = 0
prefix_lens = []
for p in paras:
out.append(p)
if is_author_signature(p):
break
return out
prefix_lens.append(prefix_len)
prefix_len += len(p)
for i in range(len(paras) - 1, -1, -1):
if prefix_lens[i] > 200 and is_author_signature(paras[i]):
return paras[: i + 1]
return paras
def _sent_pause(n_words, short, long_):
@@ -413,7 +437,7 @@ def main():
elif cmd == "carta":
pid, voice_id = sys.argv[2], sys.argv[3]
model = sys.argv[4] if len(sys.argv) > 4 else "speech-2.8-turbo"
title, text = get_post_text(int(pid))
title, text, _author = get_post_text(int(pid))
name = sys.argv[5] if len(sys.argv) > 5 else f"carta-minimax-{pid}-{model.split('-')[-1]}"
text = add_pauses(text)
print(f"Post #{pid}: «{title}» ({len(text)} car con pausas)")