mirror of
https://github.com/nirvana-7777/script.service.ultimate.git
synced 2026-09-29 20:42:40 +02:00
167 lines
5.8 KiB
Python
167 lines
5.8 KiB
Python
# streaming_providers/base/vod_operations.py
|
|
"""
|
|
VOD-related operations separated from core registry.
|
|
Follows the same pattern as ChannelOperations and EventOperations.
|
|
"""
|
|
|
|
from typing import Dict, List, Optional, Union
|
|
|
|
from .models.vod import VodCategory, VodItem, build_slug_map
|
|
from .utils.logger import logger
|
|
|
|
|
|
class VodOperations:
|
|
"""Handles all VOD browsing and manifest operations."""
|
|
|
|
def __init__(self, registry):
|
|
self.registry = registry
|
|
logger.debug("VodOperations: Initialized")
|
|
|
|
# ------------------------------------------------------------------
|
|
# Internal helpers
|
|
# ------------------------------------------------------------------
|
|
|
|
def _get_provider(self, provider_name: str):
|
|
provider = self.registry.get_provider(provider_name)
|
|
if not provider:
|
|
raise ValueError(f"Provider '{provider_name}' not found or disabled")
|
|
return provider
|
|
|
|
def _resolve_path_to_ids(
|
|
self, provider_name: str, slug_segments: List[str]
|
|
) -> List[str]:
|
|
"""
|
|
Walk the VOD tree segment by segment, converting URL slugs to
|
|
content_ids.
|
|
|
|
Strategy per segment:
|
|
1. Ask the provider for the children of the current path (using
|
|
already-resolved IDs up to this point).
|
|
2. Build a slug → id map for those children.
|
|
3. Look up the next slug in that map.
|
|
4. If found, append the resolved id and continue.
|
|
5. If not found, raise ValueError (→ 404).
|
|
|
|
Returns the fully resolved list of content_ids.
|
|
"""
|
|
provider = self._get_provider(provider_name)
|
|
resolved_ids: List[str] = []
|
|
|
|
for slug in slug_segments:
|
|
children = provider.get_vod_category(resolved_ids)
|
|
slug_map = build_slug_map(children)
|
|
|
|
if slug not in slug_map:
|
|
raise ValueError(
|
|
f"VOD path segment '{slug}' not found under "
|
|
f"'{'/'.join(resolved_ids) or 'root'}' "
|
|
f"for provider '{provider_name}'"
|
|
)
|
|
|
|
resolved_ids.append(slug_map[slug])
|
|
|
|
return resolved_ids
|
|
|
|
# ------------------------------------------------------------------
|
|
# Public API
|
|
# ------------------------------------------------------------------
|
|
|
|
def get_vod_node(
|
|
self,
|
|
provider_name: str,
|
|
slug_segments: List[str],
|
|
) -> List[Union[VodCategory, VodItem]]:
|
|
"""
|
|
Resolve a slug path and return the children of that node.
|
|
|
|
Args:
|
|
provider_name: Provider to query.
|
|
slug_segments: URL path segments as slugs, e.g.
|
|
["sports", "golf", "pga"].
|
|
Empty list → root level.
|
|
|
|
Returns:
|
|
Mixed list of VodCategory and VodItem entries.
|
|
|
|
Raises:
|
|
ValueError: Provider not found, or any path segment does not
|
|
resolve to a known child (→ 404).
|
|
"""
|
|
provider = self._get_provider(provider_name)
|
|
|
|
if not slug_segments:
|
|
# Root — no resolution needed
|
|
children = provider.get_vod_category([])
|
|
logger.info(
|
|
f"Retrieved {len(children)} root VOD entries from '{provider_name}'"
|
|
)
|
|
return children
|
|
|
|
# Pass slug segments directly to the provider.
|
|
# Providers whose content_ids are full route paths (e.g. Discovery+)
|
|
# will join the segments themselves into the correct CMS route.
|
|
# The old slug-walking approach (_resolve_path_to_ids) is bypassed
|
|
# because it fetches every intermediate level unnecessarily and fails
|
|
# when the provider's tree is too deep or slugs don't match exactly.
|
|
children = provider.get_vod_category(slug_segments)
|
|
|
|
logger.info(
|
|
f"Retrieved {len(children)} VOD entries from '{provider_name}' "
|
|
f"at path '{'/'.join(slug_segments)}'"
|
|
)
|
|
return children
|
|
|
|
def get_vod_manifest(
|
|
self, provider_name: str, vod_id: str, **kwargs
|
|
) -> Optional[str]:
|
|
"""
|
|
Get manifest URL for a specific VOD item.
|
|
|
|
Delegates directly to provider.get_manifest(content_id) — identical
|
|
to channel and event manifest resolution.
|
|
"""
|
|
provider = self._get_provider(provider_name)
|
|
manifest_url = provider.get_manifest(content_id=vod_id, **kwargs)
|
|
if manifest_url:
|
|
logger.debug(
|
|
f"Retrieved manifest for VOD '{vod_id}' from '{provider_name}'"
|
|
)
|
|
return manifest_url
|
|
|
|
def get_vod_drm_configs(
|
|
self, provider_name: str, vod_id: str, **kwargs
|
|
):
|
|
"""
|
|
Get DRM configs for a specific VOD item.
|
|
|
|
Delegates directly to provider.get_drm(content_id).
|
|
"""
|
|
provider = self._get_provider(provider_name)
|
|
return provider.get_drm(content_id=vod_id, **kwargs)
|
|
|
|
def get_all_vod_roots(self) -> Dict[str, List[Union[VodCategory, VodItem]]]:
|
|
"""
|
|
Get root VOD entries from all enabled providers that implement VOD.
|
|
|
|
Providers that return implements_vod=False are silently skipped.
|
|
"""
|
|
enabled = self.registry.get_enabled_providers()
|
|
logger.info(f"Fetching VOD roots from {len(enabled)} providers")
|
|
|
|
result = {}
|
|
total = 0
|
|
|
|
for name in enabled:
|
|
try:
|
|
provider = self.registry.get_provider(name)
|
|
if not getattr(provider, "implements_vod", False):
|
|
continue
|
|
entries = self.get_vod_node(name, [])
|
|
result[name] = entries
|
|
total += len(entries)
|
|
except Exception as e:
|
|
logger.error(f"Failed to get VOD root from '{name}': {e}")
|
|
result[name] = []
|
|
|
|
logger.info(f"Retrieved {total} total root VOD entries")
|
|
return result |