Découvrir v2 : rails par type, exploration par genre

- Rails Nouveautés séparés : 🆕 animés (tri date Kitsu) et 🆕 séries & films
  (French-Stream) — chaque type garde son rail, plus d'écrasement mutuel
- Section 🎭 Explorer : chips type × genre — animés via catégories Kitsu,
  séries (/<genre>-series-/) et films (/films/<genre>/) via French-Stream ;
  état dans l'URL (/discover?t=serie&g=medical), partageable
- Scraper : browse(media_type, genre) + catalogue YAML surchargeable ;
  parsing div.short mutualisé avec les nouveautés
- Films réels retirés du mode « Animés » (ils suivent le rail séries)
- Endpoints /api/discover (latest_anime/latest_serie), /api/discover/genres,
  /api/discover/browse — parcours filtré par la préférence du compte
- Warmup démarrage : latest_by_type()
This commit is contained in:
Roman
2026-09-25 14:48:29 +00:00
parent 248ec60d35
commit d747c574b8
12 changed files with 526 additions and 84 deletions
+14 -5
View File
@@ -90,7 +90,7 @@ async def test_search_anime_filters_serie(client, admin_cookies, monkeypatch):
await client.put("/auth/preferences", json={"content_preference": "anime"}, cookies=admin_cookies)
r = await client.get("/api/search", params={"q": "test"}, cookies=admin_cookies)
types = {x["media_type"] for x in r.json()["results"]}
assert types == {"anime", "film"} # les films restent avec les animés
assert types == {"anime"} # le mode animés reste sur l'animation (films réels → côté séries)
async def test_search_serie_skips_anime_sources(client, admin_cookies, monkeypatch):
@@ -112,21 +112,30 @@ async def test_search_serie_skips_anime_sources(client, admin_cookies, monkeypat
r = await client.get("/api/search", params={"q": "test"}, cookies=admin_cookies)
assert r.status_code == 200
assert queried == [] # source anime-only ignorée
assert {x["media_type"] for x in r.json()["results"]} == {"serie"}
assert {x["media_type"] for x in r.json()["results"]} == {"serie", "film"}
# ---------------------------------------------------------------- filtrage découverte
async def test_discover_latest_filtered_by_preference(client, admin_cookies, monkeypatch):
"""Rails par type : chaque mode n'expose que ses rails (les films suivent les séries)."""
await _patch_sources(monkeypatch, MixedSource())
r = await client.get("/api/discover", cookies=admin_cookies)
assert {i["media_type"] for i in r.json()["latest"]} == {"anime", "serie", "film"}
data = r.json()
assert {i["media_type"] for i in data["latest_anime"]} == {"anime"}
assert {i["media_type"] for i in data["latest_serie"]} == {"serie", "film"}
await client.put("/auth/preferences", json={"content_preference": "serie"}, cookies=admin_cookies)
r = await client.get("/api/discover", cookies=admin_cookies)
assert {i["media_type"] for i in r.json()["latest"]} == {"serie"}
data = (await client.get("/api/discover", cookies=admin_cookies)).json()
assert data["latest_anime"] == []
assert {i["media_type"] for i in data["latest_serie"]} == {"serie", "film"}
await client.put("/auth/preferences", json={"content_preference": "anime"}, cookies=admin_cookies)
data = (await client.get("/api/discover", cookies=admin_cookies)).json()
assert {i["media_type"] for i in data["latest_anime"]} == {"anime"}
assert data["latest_serie"] == []
async def test_discover_hides_kitsu_sections_in_serie_mode(client, admin_cookies, monkeypatch):
"""Incontournables et Pour toi (Kitsu = animés) disparaissent en mode séries."""