From 9ac8ae184d832cd7d1238e6226f18cbf99ffd4e2 Mon Sep 17 00:00:00 2001 From: Nirvana Date: Sun, 22 Mar 2026 12:41:42 +0100 Subject: [PATCH] Prepare recordings --- .../providers/magenta2/provider.py | 556 +-------------- .../providers/magenta2/smil_manager.py | 643 ++++++++++++++++++ 2 files changed, 680 insertions(+), 519 deletions(-) create mode 100644 lib/streaming_providers/providers/magenta2/smil_manager.py diff --git a/lib/streaming_providers/providers/magenta2/provider.py b/lib/streaming_providers/providers/magenta2/provider.py index 73fa88c..cfdd4e3 100644 --- a/lib/streaming_providers/providers/magenta2/provider.py +++ b/lib/streaming_providers/providers/magenta2/provider.py @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- import base64 import json -import re import time import uuid from datetime import datetime, timedelta @@ -16,6 +15,7 @@ from ...base.network import HTTPManagerFactory, ProxyConfigManager from ...base.provider import StreamingProvider from ...base.utils.logger import logger from .recordings_manager import RecordingsManager +from .smil_manager import SmilManager from .vod_manager import VodManager from .auth import Magenta2Authenticator, Magenta2Credentials, Magenta2UserCredentials from .config_models import ProviderConfig @@ -30,17 +30,11 @@ from .constants import ( DRM_SYSTEM_WIDEVINE, ERROR_CODES, MAGENTA2_CLIENT_IDS, - MAGENTA2_FALLBACK_ACCOUNT_URI, MAGENTA2_LOGO, MAGENTA2_PLATFORMS, MODE_LIVE, QUALITY_RANK, - SMIL_CACHE_DURATION, - SMIL_CLIENT_ID, SUPPORTED_COUNTRIES, - VOD_PREFIX_EPISODE, - VOD_PREFIX_MOVIE_MV, - VOD_PREFIX_MOVIE_SH, ) from .discovery import DiscoveryService from .endpoint_manager import EndpointManager @@ -123,6 +117,7 @@ class Magenta2Provider(StreamingProvider): self.provider_config: Optional[ProviderConfig] = None self._vod_manager: Optional[VodManager] = None self._recordings_manager: Optional[RecordingsManager] = None + self._smil_manager: Optional[SmilManager] = None # 🚨 INITIALIZE AUTHENTICATOR FIRST (with minimal config) # Use fallback client IDs initially @@ -299,12 +294,22 @@ class Magenta2Provider(StreamingProvider): ) logger.info("✓ RecordingsManager initialized with discovered config") + self._smil_manager = SmilManager( + http_manager=self.http_manager, + provider_name=self.provider_name, + session_id=self.session_id, + call_id_callback=self._generate_call_id, + auth_callback=self._ensure_authenticated, + platform_config=self.platform_config, + endpoint_manager=self.endpoint_manager, + provider_config=self.endpoint_manager.config, + vod_manager=self._vod_manager, + ) + logger.info("✓ SmilManager initialized with discovered config") + # Initialize auth tokens (lazy - populated on first use) self.device_token = None self._persona_cache: Optional[PersonaResult] = None - self._smil_cache: Dict[str, Tuple[float, Dict]] = {} # channel_id -> (timestamp, smil_data) - self._smil_cache_ttl = SMIL_CACHE_DURATION - logger.info("Magenta2 provider initialization completed successfully") @staticmethod @@ -1125,6 +1130,7 @@ class Magenta2Provider(StreamingProvider): "accept-encoding": "gzip", } + def _pvr_auth_headers(self) -> Dict[str, str]: """ Build authentication headers for nPVR (Audience) recording endpoints. @@ -1164,27 +1170,9 @@ class Magenta2Provider(StreamingProvider): raise RuntimeError("VodManager not available - configuration discovery may have failed") return self._vod_manager.get_children(content_id=content_id, **kwargs) - def get_recordings( - self, - include_deleted: bool = False, - **kwargs, - ): - """ - Return a list of Recording objects from the nPVR backend. - Args: - include_deleted: When True, include recordings with status - TO_DELETE or DELETED. Defaults to False. - limit: Max recordings per request (default/max 500). - offset: 1-based page offset (default 1). - - Returns: - List of :class:`Recording` objects. - - Raises: - RuntimeError: When RecordingsManager is not initialised or the - API request fails. - """ + def get_recordings(self, include_deleted: bool = False, **kwargs): + """Return a list of Recording objects from the nPVR backend.""" if not self._recordings_manager: raise RuntimeError( "RecordingsManager not available — configuration discovery may have failed" @@ -1194,41 +1182,21 @@ class Magenta2Provider(StreamingProvider): ) def delete_recording(self, recording_id: str, **kwargs) -> None: - """ - Permanently delete a recording on the nPVR backend. - - Args: - recording_id: The recording's ``id`` field as returned by - get_recordings() (not externalRecordingId). - - Raises: - RuntimeError: When RecordingsManager is not initialised or the - API returns a non-success status. - KeyError: When the recording does not exist on the provider. - """ + """Permanently delete a recording on the nPVR backend.""" if not self._recordings_manager: raise RuntimeError( "RecordingsManager not available — configuration discovery may have failed" ) self._recordings_manager.delete_recording(recording_id) - def get_recording_manifest( - self, recording_id: str, **kwargs - ) -> Optional[str]: + def get_recording_manifest(self, recording_id: str, **kwargs) -> Optional[str]: """ Return the playback URL for a specific recording by ID. For recordings already in memory (returned by get_recordings), the - ``manifest_script`` field on the Recording object already contains the - playback URL. This method performs a fresh API lookup — use it only - when the Recording object is not available. - - Args: - recording_id: The recording's ``id`` field. - - Returns: - The ``playbackUrl`` string, or None when unavailable (e.g. - recording is still PENDING or FAILED). + manifest_script field already contains the playback URL. This method + performs a fresh API lookup — use it only when the Recording object is + not available. """ if not self._recordings_manager: return None @@ -1292,403 +1260,28 @@ class Magenta2Provider(StreamingProvider): logger.error(f"Error getting manifest for {channel.name}: {e}") return None - @staticmethod - def _parse_smil_for_mpd(smil_content: str, channel_id: str) -> Optional[str]: - """ - Parse SMIL response to extract MPD URL from