Pour toi : recommandations diverses et déjà-possédé réellement exclu

Deux défauts enchaînés : la requête Kitsu cumulait les genres en ET
(quatre catégories → 1 seul titre, précisément le téléchargement à
l'origine des genres), et l'exclusion échouait car « Titre - Saison 1 -
E3 » ne normalisait jamais vers « Titre » canonique.

- Une requête Kitsu par genre, fusion entrelacée (chaque genre contribue)
- normalize_title retire saison/épisode en boucle avec frontières de mots
  (« - Saison 1 - E3 », « S1 E1 » → titre canonique ; « Série 9 » intact)
- test de non-régession : le possédé avec marqueurs n'est plus recommandé
This commit is contained in:
Roman
2026-09-25 15:23:29 +00:00
parent d5fa546dd7
commit fed61adc56
3 changed files with 86 additions and 23 deletions
+42 -9
View File
@@ -297,16 +297,15 @@ async def history(monkeypatch):
return ["Fantasy", "Adventure"] if anime_id == "46474" else []
async def fake_kitsu_anime(params: dict) -> list[dict]:
slugs = frozenset(params["filter[categories]"].split(","))
assert params["sort"] == "-userCount"
catalog = {
frozenset(["fantasy", "adventure", "action", "comedy"]): [
{"title": "Helck", "kitsu_id": "999"},
{"title": "Sousou no Frieren", "kitsu_id": "46474"},
{"title": "Konosuba", "kitsu_id": "1"},
],
}
return catalog.get(slugs, [])
# Une catégorie par requête (le cumul Kitsu est un ET trop restrictif)
assert "," not in params["filter[categories]"]
return [
{"title": "Helck", "kitsu_id": "999"},
{"title": "Sousou no Frieren", "kitsu_id": "46474"},
{"title": "Konosuba", "kitsu_id": "1"},
]
service = DiscoverService()
service.test_user_id = user_id # pour les assertions du test
@@ -325,6 +324,40 @@ async def test_for_you_aggregates_genres_and_excludes_owned(history):
assert "Sousou no Frieren" in titles
assert "Konosuba" in titles
async def test_for_you_excludes_owned_with_episode_markers(monkeypatch):
"""Régression : « Titre - Saison 1 - E3 » possédé doit exclure le « Titre »
canonique recommandé (la normalisation retire saison ET épisode, en boucle)."""
cursor = await db.execute(
"INSERT INTO users (username, password_hash) VALUES (?, ?)",
("reg-user", "x" * 64),
)
user_id = cursor.lastrowid
await db.execute(
"INSERT INTO downloads (source_key, video_url, title, status) VALUES (?,?,?,?)",
("kr", "https://v/r", "The Eminence in Shadow - Saison 1 - E3", "done"),
)
await db.execute(
"INSERT INTO favorites (user_id, source, source_id, title, image_url, payload) "
"VALUES (?,?,?,?,?,?)",
(user_id, "vostfree", "r", "Favori R", None, '{"genres": ["Fantasy"]}'),
)
async def fake_match(title: str):
return None # genres apportés par le favori
async def fake_kitsu_anime(params: dict) -> list[dict]:
return [
{"title": "The Eminence in Shadow", "kitsu_id": "1"},
{"title": "Autre Anime", "kitsu_id": "2"},
]
service = DiscoverService()
monkeypatch.setattr(service, "_kitsu_match_for_title", fake_match)
monkeypatch.setattr(service, "_kitsu_anime", fake_kitsu_anime)
result = await service.for_you(user_id=user_id, limit=10)
titles = [item["title"] for item in result["items"]]
assert "The Eminence in Shadow" not in titles # possédé (« - Saison 1 - E3 »)
assert "Autre Anime" in titles
async def test_for_you_cold_start_without_history(monkeypatch):
"""Aucun téléchargement/favori/Sonarr : amorçage signalé (non caché)."""