@@ -594,6 +594,37 @@ def _apply_diversification(self, pool: list, targets: dict, max_results: int) ->
594594
595595 return result
596596
597+ def _filter_candidates_by_watched_and_genres (
598+ self , candidates : list [dict ], watched_tmdb : set [int ], whitelist : set [int ], existing_ids : set [int ] | None = None
599+ ) -> list [dict ]:
600+ """
601+ Filter candidates by watched items and genre whitelist.
602+
603+ Args:
604+ candidates: List of candidate items to filter
605+ watched_tmdb: Set of watched TMDB IDs to exclude
606+ whitelist: Set of preferred genre IDs
607+ existing_ids: Optional set of IDs to exclude (for deduplication)
608+
609+ Returns:
610+ Filtered list of candidates
611+ """
612+ filtered = []
613+ existing = existing_ids or set ()
614+
615+ for it in candidates :
616+ item_id = it .get ("id" )
617+ if not item_id or item_id in existing :
618+ continue
619+ if item_id in watched_tmdb :
620+ continue
621+ if not RecommendationFiltering .passes_top_genre_whitelist (it .get ("genre_ids" ), whitelist ):
622+ continue
623+ filtered .append (it )
624+ existing .add (item_id )
625+
626+ return filtered
627+
597628 async def get_recommendations_for_theme (self , theme_id : str , content_type : str , limit : int = 20 ) -> list [dict ]:
598629 """Parse theme and fetch recommendations with strict filtering."""
599630 params = {}
@@ -667,13 +698,7 @@ async def get_recommendations_for_theme(self, theme_id: str, content_type: str,
667698 )
668699
669700 # Initial filter
670- filtered = []
671- for it in candidates :
672- if it .get ("id" ) in watched_tmdb :
673- continue
674- if not RecommendationFiltering .passes_top_genre_whitelist (it .get ("genre_ids" ), whitelist ):
675- continue
676- filtered .append (it )
701+ filtered = self ._filter_candidates_by_watched_and_genres (candidates , watched_tmdb , whitelist )
677702
678703 # If we still don't have enough candidates, fetch more pages
679704 max_page_fetched = max (pages_to_fetch ) if pages_to_fetch else 0
@@ -688,21 +713,18 @@ async def get_recommendations_for_theme(self, theme_id: str, content_type: str,
688713 self .tmdb_service .get_discover (content_type , page = p , ** params ) for p in additional_pages
689714 ]
690715 additional_results = await asyncio .gather (* additional_tasks , return_exceptions = True )
691- # Track already processed IDs to avoid duplicates
692- existing_ids = { it . get ( "id" ) for it in filtered }
716+ # Collect new candidates from additional pages
717+ new_candidates = []
693718 for res in additional_results :
694719 if isinstance (res , Exception ):
695720 continue
696- for it in res .get ("results" , []):
697- item_id = it .get ("id" )
698- if not item_id or item_id in existing_ids :
699- continue
700- if item_id in watched_tmdb :
701- continue
702- if not RecommendationFiltering .passes_top_genre_whitelist (it .get ("genre_ids" ), whitelist ):
703- continue
704- filtered .append (it )
705- existing_ids .add (item_id )
721+ new_candidates .extend (res .get ("results" , []))
722+ # Filter new candidates, excluding already processed ones
723+ existing_ids = {it .get ("id" ) for it in filtered }
724+ additional_filtered = self ._filter_candidates_by_watched_and_genres (
725+ new_candidates , watched_tmdb , whitelist , existing_ids
726+ )
727+ filtered .extend (additional_filtered )
706728 except Exception as e :
707729 logger .warning (f"Failed to fetch additional pages: { e } " )
708730
0 commit comments