Skip to content

Arreglar !lyrics, que nunca funcionó con la lyricsgenius fijada - #38

Merged
Isma-L154 merged 1 commit into
mainfrom
arreglo-lyrics-issue-37
Sep 12, 2026
Merged

Isma-L154 merged 1 commit into
mainfrom
arreglo-lyrics-issue-37

Conversation

@Isma-L154

Copy link
Copy Markdown
Owner

Cierra #37.

344 tests (antes 332). !lyrics no funcionaba, y no había funcionado nunca
con la versión de lyricsgenius que fija requirements.txt.

Qué pasaba

Cada consulta moría al construir el cliente:

WARNING loopify.lyrics: Genius lookup failed for 'KAROL G, Judeline, rusowsky - BbY WOW':
  Genius.__init__() got an unexpected keyword argument 'quiet'

quiet era de la serie 2.x. La 3.12.2 fijada no lo tiene, y tampoco tiene
verbose
: no imprime nada por su cuenta, así que nunca hubo nada que
silenciar. El argumento se elimina, no se sustituye.

Por qué pasó desapercibido

El TypeError ocurría al construir, así que se llevaba toda consulta, y el
comando respondía "Couldn't find lyrics for ...". Eso se lee como una búsqueda
sin resultados, no como una construcción rota — el comando parecía funcionar y
simplemente no encontrar nada nunca.

El bug es anterior al #32. Lo que cambió es que el #32 sustituyó
print(f"[Lyrics] Error: {e}") por una llamada real al logger, y entonces el
motivo apareció en journalctl con nivel y nombre de logger.

Dos problemas relacionados, arreglados de paso

  • No se pasaba timeout. Una consulta podía clavar un hilo del executor
    indefinidamente — y un hilo del executor clavado retrasa el cierre del loop,
    el techo del que iba el Un reinicio tras reproducir música agota TimeoutStopSec y dispara una alerta falsa #35. Ahora está acotado a 10 s (el defecto de la
    librería es 5 s).
  • Sin token se construía el cliente igual, y lyricsgenius entonces cae a leer
    $GENIUS_ACCESS_TOKEN y lanza KeyError. Ahora fetch se rinde antes, que es
    además la respuesta honesta para quien teclea !lyrics en un despliegue sin
    token.

Sobre los valores por defecto

skip_non_songs=True y remove_section_headers=False coinciden con los defectos
actuales de la librería, pero se pasan explícitos porque dependemos de ese
comportamiento: Genius indexa tracklists y páginas de créditos, y las marcas
[Chorus] se quieren en el embed. Los tests los afirman en vez de confiar en que
los defectos no cambien.

Tests

tests/test_lyrics_api.py es nuevo — este módulo no tenía ningún test, que es
exactamente cómo un TypeError en un constructor pudo vivir aquí sin que nadie
se enterase. Ninguno habla con Genius; comprueban que la librería instalada
acepta lo que le pasamos, que la falta de token se maneja antes de que pueda
lanzar, que la llamada está acotada, y que la búsqueda bloqueante nunca corre en
el event loop.

Cómo probarlo

pytest tests/test_lyrics_api.py     # 12
pytest                              # 344

Verificado contra la API real desde el servidor:

token presente: True
timeout del cliente: 10.0
OK -> Bohemian Rhapsody / Queen
   primeros 60 chars: [Intro] | Is this the real life? Is this just fantasy? | Caught
   conserva cabeceras de seccion: True
sin coincidencia -> None

En Discord, tras desplegar:

!lyrics Bohemian Rhapsody - Queen     -> la letra, con sus [Intro]/[Chorus]
!lyrics asdkjhaskdjh                  -> "Couldn't find lyrics", sin traza
!lyrics            (con algo sonando) -> usa el titulo de la pista actual

Y en journalctl no debe quedar ningún Genius lookup failed.

Every lookup died in the client constructor:

    WARNING loopify.lyrics: Genius lookup failed for '...':
      Genius.__init__() got an unexpected keyword argument 'quiet'

`quiet` belonged to lyricsgenius 2.x. The pinned 3.12.2 has no such argument and
no `verbose` either — it prints nothing of its own, so there was never anything
to silence and the argument is simply dropped rather than replaced.

The TypeError happened while building the client, so it took out every query,
and the command answered "Couldn't find lyrics for ..." — which reads like a
failed search rather than a broken build. That is why it went unnoticed: the
command appeared to work and simply never found anything.

The bug predates the cleanup in #32. What changed is that #32 replaced
`print(f"[Lyrics] Error: {e}")` with a real logger call, so the reason finally
showed up in journalctl with a level and a logger name attached.

Two related problems fixed alongside it:

- No timeout was passed, so a lookup could pin an executor thread indefinitely —
  and a pinned executor thread delays the loop's shutdown, the ceiling #35 was
  about. It is now bounded at 10s (the library default is 5s).
- A missing token built a client anyway, and lyricsgenius then falls back to
  $GENIUS_ACCESS_TOKEN and raises KeyError. `fetch` now gives up before that,
  which is also the honest answer for a user typing !lyrics on a deployment
  without a token.

`skip_non_songs=True` and `remove_section_headers=False` match the library's
current defaults, but stay explicit because the behaviour is relied on: Genius
indexes tracklists and credits pages, and the `[Chorus]` markers are wanted in
the embed. Tests assert both rather than trusting the defaults to hold.

tests/test_lyrics_api.py is new — this module had no tests at all, which is
exactly how a TypeError in a constructor lived here unnoticed. Nothing in them
talks to Genius; they check that the installed library accepts what we pass, that
a missing token is handled before it can raise, that the call is bounded, and
that the blocking search never runs on the event loop.

Verified against the real API from the server: "Bohemian Rhapsody" / "Queen"
comes back with its section headers intact, and a nonsense query returns None
with no traceback.

Tests: 344, up from 332.

Closes #37
@Isma-L154
Isma-L154 merged commit 1ea2431 into main Sep 12, 2026
3 checks passed
@Isma-L154
Isma-L154 deleted the arreglo-lyrics-issue-37 branch September 12, 2026 06:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant