2 Commits

Author SHA1 Message Date
root 66912a0b71 fix: filtre content_type, doublons seasonaux, et is_admin manquant
CI / Test (Python 3.11) (pull_request) Has been cancelled
CI / Test (Python 3.12) (pull_request) Has been cancelled
CI / Lint (pull_request) Has been cancelled
CI / Type Check (pull_request) Has been cancelled
CI / Summary (pull_request) Has been cancelled
- Bug 1: Ajout du champ 'type' dans les dict de AnimeReleasesFetcher
  (get_seasonal_anime, get_scheduled_anime, get_top_anime, search_anime)
  et dans _get_fallback_recommendations pour que le filtre content_type
  fonctionne correctement
- Bug 2: Déduplication par mal_id dans get_seasonal_anime() pour
  éviter les doublons retournés par l'API Jikan
- Bug 3: Ajout de is_admin dans get_current_user_from_token(),
  get_optional_user(), le constructeur User du register, et la
  réponse /me
2026-04-03 15:19:15 +00:00
root 693615a7dc fix: corriger les imports cassés dans router_watchlist.py
CI / Test (Python 3.11) (push) Has been cancelled
CI / Test (Python 3.12) (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Type Check (push) Has been cancelled
CI / Summary (push) Has been cancelled
Remplace 'from main import watchlist_manager' par 'from app.watchlist import watchlist_manager'
et 'from main import auto_download_scheduler' par 'from app.auto_download_scheduler import auto_download_scheduler'.
watchlist_manager n'est pas exposé dans main.py, ce qui causait un ImportError 500
sur GET /api/watchlist.

Lié à #15
2026-04-03 06:39:34 +00:00
4 changed files with 34 additions and 15 deletions
+5
View File
@@ -285,6 +285,7 @@ class RecommendationEngine:
'score': 9.09,
'episodes': 64,
'status': 'Finished Airing',
'type': 'TV',
'genres': ['Action', 'Adventure', 'Fantasy'],
'synopsis': 'Two brothers lose their mother to an incurable disease. With the power of alchemy, they use taboo knowledge to resurrect her. The process fails, and as a toll for crossing into the realm of God, they lose their bodies.',
'images': {},
@@ -298,6 +299,7 @@ class RecommendationEngine:
'score': 8.51,
'episodes': 75,
'status': 'Finished Airing',
'type': 'TV',
'genres': ['Action', 'Drama', 'Fantasy'],
'synopsis': 'Centuries ago, mankind was slaughtered to near extinction by monstrous humanoid creatures called titans. To protect what remains, humanity built walls and lived peacefully for a hundred years.',
'images': {},
@@ -311,6 +313,7 @@ class RecommendationEngine:
'score': 8.63,
'episodes': 37,
'status': 'Finished Airing',
'type': 'TV',
'genres': ['Mystery', 'Police', 'Psychological'],
'synopsis': 'A shinigami, as a god of death, can kill any person—provided they see their victim\'s face and write their victim\'s name in a notebook called a Death Note.',
'images': {},
@@ -324,6 +327,7 @@ class RecommendationEngine:
'score': 8.48,
'episodes': 26,
'status': 'Finished Airing',
'type': 'TV',
'genres': ['Action', 'Adventure', 'Supernatural'],
'synopsis': 'It is the Taisho Period in Japan. Tanjiro, a kindhearted boy who sells charcoal for a living, finds his family slaughtered by a demon. To make matters worse, his younger sister Nezuko is turned into a demon.',
'images': {},
@@ -337,6 +341,7 @@ class RecommendationEngine:
'score': 8.35,
'episodes': 24,
'status': 'Finished Airing',
'type': 'TV',
'genres': ['Action', 'Supernatural'],
'synopsis': 'Yuji Itadori is a boy with tremendous physical strength, though he lives a completely ordinary high school life. One day, to save a friend who has been attacked by curses, he eats the finger of a curse.',
'images': {},
+15 -6
View File
@@ -92,7 +92,12 @@ class AnimeReleasesFetcher:
data = response.json()
anime_list = []
for anime in data.get('data', [])[:20]:
seen_mal_ids = set()
for anime in data.get('data', []):
mal_id = anime.get('mal_id')
if not mal_id or mal_id in seen_mal_ids:
continue
seen_mal_ids.add(mal_id)
anime_list.append({
'title': anime.get('title', ''),
'title_japanese': anime.get('title_japanese', ''),
@@ -105,9 +110,10 @@ class AnimeReleasesFetcher:
'cover_image': self._extract_cover_image(anime),
'images': anime.get('images', {}),
'url': anime.get('url', ''),
'mal_id': anime.get('mal_id')
'mal_id': mal_id,
'type': anime.get('type', '')
})
return anime_list
return anime_list[:20]
except Exception as e:
logger.error(f"Error fetching seasonal anime: {e}", exc_info=True)
return []
@@ -143,7 +149,8 @@ class AnimeReleasesFetcher:
'cover_image': self._extract_cover_image(anime),
'broadcast': anime.get('broadcast', {}),
'url': anime.get('url', ''),
'mal_id': anime.get('mal_id')
'mal_id': anime.get('mal_id'),
'type': anime.get('type', '')
})
return anime_list
except Exception as e:
@@ -178,7 +185,8 @@ class AnimeReleasesFetcher:
'cover_image': self._extract_cover_image(anime),
'images': anime.get('images', {}),
'url': anime.get('url', ''),
'mal_id': anime.get('mal_id')
'mal_id': anime.get('mal_id'),
'type': anime.get('type', '')
})
return anime_list
except Exception as e:
@@ -209,7 +217,8 @@ class AnimeReleasesFetcher:
'cover_image': self._extract_cover_image(anime),
'images': anime.get('images', {}),
'url': anime.get('url', ''),
'mal_id': anime.get('mal_id')
'mal_id': anime.get('mal_id'),
'type': anime.get('type', '')
})
return anime_list
except Exception as e:
+4
View File
@@ -54,6 +54,7 @@ async def get_current_user_from_token(
email=user.email,
full_name=user.full_name,
is_active=user.is_active,
is_admin=user.is_admin,
created_at=user.created_at,
last_login=user.last_login,
)
@@ -79,6 +80,7 @@ async def get_optional_user(
email=user.email,
full_name=user.full_name,
is_active=user.is_active,
is_admin=user.is_admin,
created_at=user.created_at,
last_login=user.last_login,
)
@@ -108,6 +110,7 @@ async def register(user_data: UserCreate):
email=user.email,
full_name=user.full_name,
is_active=user.is_active,
is_admin=user.is_admin,
created_at=user.created_at,
last_login=user.last_login,
)
@@ -174,6 +177,7 @@ async def get_me(current_user: User = Depends(get_current_user_from_token)):
"email": current_user.email,
"full_name": current_user.full_name,
"is_active": current_user.is_active,
"is_admin": current_user.is_admin,
"created_at": current_user.created_at,
"last_login": current_user.last_login,
}
+10 -9
View File
@@ -47,7 +47,7 @@ async def add_to_watchlist(
current_user: User = Depends(get_current_user_from_token),
):
"""Add an anime to the watchlist"""
from main import watchlist_manager
from app.watchlist import watchlist_manager
try:
existing = watchlist_manager.get_by_anime_url(
@@ -81,7 +81,7 @@ async def get_watchlist(
html: bool = Query(False),
current_user: Optional[User] = Depends(get_optional_user),
):
from main import watchlist_manager
from app.watchlist import watchlist_manager
is_htmx = request.headers.get("HX-Request")
@@ -108,7 +108,7 @@ async def get_watchlist_settings(
current_user: User = Depends(get_current_user_from_token),
):
"""Get global watchlist settings"""
from main import watchlist_manager
from app.watchlist import watchlist_manager
return watchlist_manager.get_settings()
@@ -120,7 +120,8 @@ async def update_watchlist_settings(
current_user: User = Depends(get_current_user_from_token),
):
"""Update global watchlist settings"""
from main import auto_download_scheduler, watchlist_manager
from app.auto_download_scheduler import auto_download_scheduler
from app.watchlist import watchlist_manager
try:
updated_settings = watchlist_manager.update_settings(settings)
@@ -148,7 +149,7 @@ async def get_watchlist_item(
current_user: User = Depends(get_current_user_from_token),
):
"""Get a specific watchlist item"""
from main import watchlist_manager
from app.watchlist import watchlist_manager
item = watchlist_manager.get_by_id(item_id)
if not item or item.user_id != current_user.id:
@@ -164,7 +165,7 @@ async def update_watchlist_item(
current_user: User = Depends(get_current_user_from_token),
):
"""Update a watchlist item"""
from main import watchlist_manager
from app.watchlist import watchlist_manager
item = watchlist_manager.get_by_id(item_id)
if not item or item.user_id != current_user.id:
@@ -190,7 +191,7 @@ async def delete_from_watchlist(
current_user: User = Depends(get_current_user_from_token),
):
"""Remove an anime from the watchlist"""
from main import watchlist_manager
from app.watchlist import watchlist_manager
item = watchlist_manager.get_by_id(item_id)
if not item or item.user_id != current_user.id:
@@ -219,7 +220,7 @@ async def check_watchlist_now(
current_user: User = Depends(get_current_user_from_token),
):
"""Trigger an immediate check for new episodes"""
from main import auto_download_scheduler
from app.auto_download_scheduler import auto_download_scheduler
background_tasks.add_task(auto_download_scheduler.trigger_check_now)
response.headers["HX-Trigger"] = json.dumps(
@@ -239,6 +240,6 @@ async def get_watchlist_stats(
current_user: User = Depends(get_current_user_from_token),
):
"""Get watchlist statistics for the user"""
from main import watchlist_manager
from app.watchlist import watchlist_manager
return watchlist_manager.get_stats(current_user.id)