Le serveur garde la trace de ce qu'il entend, et repère la rotation (2.4.0)

Le balayage ne servait qu'à trouver un morceau guetté, puis oubliait tout. Il
note désormais chaque titre annoncé par les stations, même sans guet en cours :
un onglet Écoutes montre l'historique, et la rotation — passages et stations
distinctes, par titre et par artiste — sur les 100 dernières remontées.

Pour que l'historique soit fiable, un tour va maintenant jusqu'au bout après une
trouvaille (l'enregistrement part aussitôt, le début du morceau n'est pas
perdu), et la liste des stations est mise en cache une demi-heure au lieu
d'interroger l'annuaire à chaque tour.

Essayé sur de vraies radios : une station alternait le vrai titre et un titre de
repli, ce qui doublait les passages. Un titre déjà relevé sur la même station
dans les dix minutes est donc ignoré.

Première moitié de la reconnaissance des morceaux ; l'écoute continue et
l'empreinte sonore suivront.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
tuxgyverandClaude Sonnet 5 committed 2026-09-20 17:59:32 +02:00
1 parent 53f5fc1148
commit 7810bef8a3
12 files changed
+380 -20

No files matched your search

+18
View File
@@ -27,6 +27,7 @@ from fastapi import Body, Depends, FastAPI, Header, HTTPException, Query, Reques
from fastapi.responses import FileResponse, HTMLResponse, PlainTextResponse, Response
from . import config as config_module
from . import rotation
from .sources import catalogs, radio
from .storage import Storage
from .workers import Downloader, Watcher, safe_name
@@ -200,6 +201,23 @@ async def sweep() -> dict:
raise HTTPException(status_code=502, detail=f"Annuaire indisponible : {str(error)[:120]}")
@app.get("/api/heard", dependencies=[Depends(authorised)])
def heard(limit: int = Query(default=100, ge=1, le=500), q: str | None = None) -> dict:
"""Ce que les stations ont annoncé, le plus récent d'abord ; `q` filtre sur le texte."""
return {
"items": storage.heard(limit, q.strip() if q else None),
"total": storage.heard_count(),
"history": config.history,
}
@app.get("/api/rotation", dependencies=[Depends(authorised)])
def rotation_view(last: int = Query(default=100, ge=1, le=500),
top: int = Query(default=20, ge=1, le=100)) -> dict:
"""Ce qui tourne sur les `last` dernières remontées, tous titres et artistes confondus."""
return rotation.rotation(storage.heard(last), top)
@app.get("/api/queue", dependencies=[Depends(authorised)])
def queue_state() -> dict:
pending = storage.media_since(0, state=None)