diff --git a/lib/streaming_providers/providers/rtlplus/vod_manager.py b/lib/streaming_providers/providers/rtlplus/vod_manager.py index 801f1dd..34ab3ef 100644 --- a/lib/streaming_providers/providers/rtlplus/vod_manager.py +++ b/lib/streaming_providers/providers/rtlplus/vod_manager.py @@ -418,22 +418,7 @@ class RTLPlusVodManager: # Program contents (handles movies, numbered seasons, monthly archives) # ------------------------------------------------------------------ - def _get_program_contents( - self, - program_id: str, - cursor: Optional[str] = None, - page_size: int = 24, - slug: Optional[str] = None, - ) -> Dict[str, Any]: - """ - Get program contents - handles movies, series with season selectors, or direct episodes. - - Returns either: - - A direct movie (playable) - - Numbered seasons (Staffel 1, 2, etc.) - - Monthly archive selector (2026-05, 2026-04, etc.) - - Direct episodes (when no selector is present) - """ + def _get_program_contents(self, program_id: str, cursor=None, page_size=24, slug=None): seo = slug or f"p_{program_id}" location = f"{self.cfg.base_website}{seo}-p_{program_id}" @@ -452,8 +437,16 @@ class RTLPlusVodManager: logger.debug(f"Blocks count: {len(layout.get('blocks', []))}") # FIRST: Check if this is a movie (direct playable video) - movie_item = self._find_direct_video_in_layout(layout) + logger.debug("Calling _find_direct_video_in_layout") + try: + movie_item = self._find_direct_video_in_layout(layout) + logger.debug(f"_find_direct_video_in_layout returned: {movie_item is not None}") + except Exception as e: + logger.error(f"Error in _find_direct_video_in_layout: {e}", exc_info=True) + movie_item = None + if movie_item: + logger.debug(f"Found movie: {movie_item.name}") layout_title = ( layout.get("entity", {}).get("metadata", {}).get("title") or layout.get("seo", {}).get("title") @@ -473,10 +466,11 @@ class RTLPlusVodManager: "total": 1, } - # SECOND: Extract monthly archive selector (for news/reality shows) + # SECOND: Extract monthly archive selector + logger.debug("Calling _extract_season_selector_with_episodes") try: season_selector, current_episodes = self._extract_season_selector_with_episodes(layout) - logger.debug(f"Monthly selector: {len(season_selector)} months, {len(current_episodes)} current episodes") + logger.debug(f"Got {len(season_selector)} months, {len(current_episodes)} episodes") except Exception as e: logger.error(f"Error in _extract_season_selector_with_episodes: {e}", exc_info=True) season_selector, current_episodes = [], [] @@ -678,55 +672,71 @@ class RTLPlusVodManager: return seasons def _find_direct_video_in_layout(self, layout: Dict) -> Optional[VodItem]: - """ - Find a direct playable video item in a program layout. - Skips any blocks that are selectors (monthly or numbered seasons). - """ + logger.debug("Entering _find_direct_video_in_layout") + if not layout or not isinstance(layout, dict): + logger.warning("Layout is None or not a dict") return None - for block in layout.get("blocks", []): + for block_idx, block in enumerate(layout.get("blocks", [])): + logger.debug(f"Processing block {block_idx} in _find_direct_video_in_layout") + if not block or not isinstance(block, dict): + logger.debug(f"Block {block_idx} is None or not dict") continue - # Skip blocks that are selectors (they contain episodes, not direct video) + # Skip blocks that are selectors alt_content = block.get("alternativeContent", {}) - if alt_content.get("selectorTemplateId") == "Selector": - continue # This is a monthly selector block, skip it + if alt_content and alt_content.get("selectorTemplateId") == "Selector": + logger.debug(f"Block {block_idx} is a Selector, skipping") + continue # Check block type - skip season selectors tealium = block.get("analytics", {}).get("tealium", {}) if tealium.get("template_name") == "SelectorCardListM": - continue # This is a numbered season selector, skip it + logger.debug(f"Block {block_idx} is SelectorCardListM, skipping") + continue - # Collect items from standard content location + # Collect items content = block.get("content", {}) - items = list(content.get("items", []) or []) if isinstance(content, dict) else [] + items = content.get("items", []) if isinstance(content, dict) else [] + logger.debug(f"Block {block_idx} has {len(items)} items") - # Also check alternativeContent for concurrent blocks (only if not selector) + # Also check alternativeContent if isinstance(alt_content, dict): for cb in alt_content.get("concurrentBlocks", []): if isinstance(cb, dict): cb_items = cb.get("content", {}).get("items", []) if cb_items: items.extend(cb_items) + logger.debug(f"Added {len(cb_items)} items from concurrentBlocks") + + for item_idx, item in enumerate(items): + logger.debug(f"Processing item {item_idx}") - for item in items: if not item or not isinstance(item, dict): continue if item.get("itemType") != "classic": continue - item_content = item.get("itemContent", {}) + item_content = item.get("itemContent") if not item_content or not isinstance(item_content, dict): continue + # Check for video in action target action = item_content.get("action", {}) if isinstance(action, dict): target = action.get("target", {}) if isinstance(target, dict): + # Handle lock-wrapped targets + if target.get("type") == "lock": + lock_value = target.get("value_lock", {}) + if isinstance(lock_value, dict): + target = lock_value.get("originalTarget", {}) + value_layout = target.get("value_layout", {}) if isinstance(value_layout, dict) and value_layout.get("type") == "video": + logger.debug(f"Found video in action target: {value_layout.get('id')}") vod_item = self._extract_vod_item_from_block_item(item) if vod_item: clip_id = value_layout.get("id") @@ -737,6 +747,7 @@ class RTLPlusVodManager: if item_content.get("type") == "video": clip_id = item_content.get("id") if clip_id: + logger.debug(f"Found direct video: {clip_id}") vod_item = VodItem.create_episode( name=item_content.get("title", clip_id), content_id=clip_id, @@ -748,21 +759,7 @@ class RTLPlusVodManager: vod_item.logo_url = self._extract_thumbnail(item_content) return vod_item - # Check alternative action locations - for action_key in ("onClickAction", "primaryAction", "secondaryAction"): - alt_action = item_content.get(action_key, {}) - if isinstance(alt_action, dict): - alt_target = alt_action.get("target", {}) - if isinstance(alt_target, dict): - alt_value = alt_target.get("value_layout", {}) - if isinstance(alt_value, dict) and alt_value.get("type") == "video": - vod_item = self._extract_vod_item_from_block_item(item) - if vod_item: - clip_id = alt_value.get("id") - if clip_id: - vod_item.content_id = clip_id - return vod_item - + logger.debug("No video found in _find_direct_video_in_layout") return None def _extract_direct_episodes_from_layout(self, layout: Dict) -> List[VodItem]: