Découverte : le filtre par préférence s'applique avant la troncature du rail

En mode séries, le rail Nouveautés était vide : discover.latest() triait par
date de sortie Kitsu (catalogue animés uniquement) puis tronquait à 24 AVANT
le filtrage — les séries et films réels, absents de Kitsu (donc sans date),
étaient systématiquement évincés.

- allowed (types autorisés par préférence) descend dans discover.latest()
  et filtre dès la collecte des sources
- remplissage du rail équilibré par type (round-robin) : en mode « les deux »,
  8 animés / 8 séries / 8 films au lieu de 24 animés
- test de non-régression : 9 séries conservées face à 30 animés datés
This commit is contained in:
Roman
2026-09-25 14:22:10 +00:00
parent 79a44297fd
commit 248ec60d35
3 changed files with 66 additions and 7 deletions
+40 -1
View File
@@ -191,6 +191,45 @@ async def test_latest_orders_by_kitsu_start_date(monkeypatch):
assert result[0]["rating"] is None
async def test_latest_serie_preference_keeps_undated_titles(monkeypatch):
"""Régression : en mode séries, les titres sans date Kitsu ne doivent pas être
évincés du rail par la troncature (les séries n'existent pas chez Kitsu)."""
import app.services.discover as discover_module
animes = [
SearchResult(source="vostfree", source_id=str(n), title=f"Animé {n}", url=f"https://a/{n}")
for n in range(1, 31)
]
series = [
SearchResult(
source="french_stream", source_id=str(n), title=f"Série {n}",
url=f"https://s/{n}", media_type="serie",
)
for n in range(1, 10)
]
class AnimeSource(_FakeSource):
name, label, base_url, media_types = "vostfree", "Vostfree", "https://a", ("anime",)
class SerieSource(_FakeSource):
name, label, base_url, media_types = "french_stream", "French-Stream", "https://s", ("serie", "film")
monkeypatch.setattr(discover_module, "all_sources", lambda: [AnimeSource(animes), SerieSource(series)])
async def enabled(name: str) -> bool:
return True
monkeypatch.setattr(discover_module, "is_source_enabled", enabled)
async def fake_match(title: str):
return None # rien chez Kitsu → aucune date de sortie
service = DiscoverService()
monkeypatch.setattr(service, "_kitsu_match_for_title", fake_match)
result = await service.latest(limit=24, allowed={"serie"})
assert {item["media_type"] for item in result} == {"serie"}
assert len(result) == 9 # les 9 séries, malgré 30 animés sans filtre interne
async def test_latest_skips_broken_source_and_uses_cache(monkeypatch):
"""Une source en échec disparaît sans erreur, et le TTL évite les re-scrapes."""
import app.services.discover as discover_module
@@ -336,7 +375,7 @@ async def test_api_discover_requires_auth(client):
async def test_api_discover_sections(client, admin_cookies, monkeypatch):
async def fake_latest(limit: int = 24):
async def fake_latest(limit: int = 24, allowed: set[str] | None = None):
return [
{"source": "vostfree", "label": "Vostfree", "source_id": "a", "title": "T",
"start_date": "2026-01-01", "status": "current", "rating": 8.1},