mirror of
https://github.com/nirvana-7777/script.service.ultimate.git
synced 2026-09-18 07:02:27 +02:00
Add hrti
This commit is contained in:
@@ -464,22 +464,39 @@ class HRTiAuthenticator(BaseAuthenticator):
|
||||
self._user_id = self._user_id or ''
|
||||
|
||||
def authorize_session(self, content_type: str, content_ref_id: str,
|
||||
channel_id: str = None, **kwargs) -> Optional[Dict[str, Any]]:
|
||||
content_drm_id: str = None,
|
||||
video_store_ids: list = None,
|
||||
channel_id: str = None,
|
||||
start_time: str = None,
|
||||
end_time: str = None) -> Optional[Dict[str, Any]]:
|
||||
"""Authorize a playback session"""
|
||||
try:
|
||||
bearer_token = self._current_token.access_token if self._current_token else ''
|
||||
headers = self._get_api_headers(bearer_token)
|
||||
|
||||
# Set referer based on content type
|
||||
if channel_id is None:
|
||||
headers['referer'] = f'{self.config.base_website}/videostore'
|
||||
else:
|
||||
if content_type == "tlive":
|
||||
headers['referer'] = f'{self.config.base_website}/live/tv?channel={channel_id}'
|
||||
elif content_type == "rlive":
|
||||
headers['referer'] = f'{self.config.base_website}/live/radio'
|
||||
else:
|
||||
headers['referer'] = f'{self.config.base_website}/live/'
|
||||
|
||||
payload = {
|
||||
"ContentType": content_type,
|
||||
"ContentReferenceId": content_ref_id,
|
||||
"ContentDrmId": f"{content_ref_id}_drm",
|
||||
"VideostoreReferenceIds": kwargs.get('video_store_ids', []),
|
||||
"ContentDrmId": content_drm_id or f"{content_ref_id}_drm",
|
||||
"VideostoreReferenceIds": video_store_ids,
|
||||
"ChannelReferenceId": channel_id,
|
||||
"StartTime": kwargs.get('start_time'),
|
||||
"EndTime": kwargs.get('end_time')
|
||||
"StartTime": start_time,
|
||||
"EndTime": end_time
|
||||
}
|
||||
|
||||
logger.debug(f"Authorizing session - type: {content_type}, ref: {content_ref_id}, drm: {content_drm_id}")
|
||||
|
||||
response = self.http_manager.post(
|
||||
self.config.api_endpoints['authorize_session'],
|
||||
operation='api',
|
||||
@@ -490,7 +507,9 @@ class HRTiAuthenticator(BaseAuthenticator):
|
||||
|
||||
result = response.json()
|
||||
if 'Result' in result:
|
||||
logger.debug("HRTi session authorization successful")
|
||||
authorized = result['Result'].get('Authorized', False)
|
||||
session_id = result['Result'].get('SessionId') or result['Result'].get('DrmId')
|
||||
logger.debug(f"Session authorization result - authorized: {authorized}, session_id: {session_id}")
|
||||
return result['Result']
|
||||
else:
|
||||
logger.warning("No result in session authorization response")
|
||||
@@ -500,8 +519,40 @@ class HRTiAuthenticator(BaseAuthenticator):
|
||||
logger.error(f"HRTi session authorization failed: {e}")
|
||||
return None
|
||||
|
||||
def report_session_event(self, session_id: str, channel_id: str = None) -> bool:
|
||||
"""Report session event (like play start)"""
|
||||
try:
|
||||
bearer_token = self._current_token.access_token if self._current_token else ''
|
||||
headers = self._get_api_headers(bearer_token)
|
||||
|
||||
# Set referer based on channel
|
||||
if channel_id is None:
|
||||
headers['referer'] = f'{self.config.base_website}/videostore'
|
||||
else:
|
||||
headers['referer'] = f'{self.config.base_website}/live/tv?channel={channel_id}'
|
||||
|
||||
payload = {
|
||||
"SessionEventId": 1, # 1 = play start
|
||||
"SessionId": session_id
|
||||
}
|
||||
|
||||
response = self.http_manager.post(
|
||||
self.config.api_endpoints['report_session'],
|
||||
operation='api',
|
||||
headers=headers,
|
||||
data=json.dumps(payload)
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
logger.debug(f"Session event reported for session {session_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Session event reporting failed: {e}")
|
||||
return False
|
||||
|
||||
def get_license_data(self, session_id: str) -> str:
|
||||
"""Generate license data for DRM"""
|
||||
"""Generate license data for DRM - returns base64 encoded string"""
|
||||
try:
|
||||
drm_license = {
|
||||
'userId': self._user_id or '',
|
||||
@@ -509,8 +560,14 @@ class HRTiAuthenticator(BaseAuthenticator):
|
||||
'merchant': self.config.merchant
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
f"Creating license data - userId: {self._user_id}, sessionId: {session_id}, merchant: {self.config.merchant}")
|
||||
|
||||
# Encode to JSON then to base64
|
||||
license_bytes = json.dumps(drm_license).encode('utf-8')
|
||||
license_b64 = base64.b64encode(license_bytes).decode('utf-8')
|
||||
|
||||
logger.debug(f"License data (base64, first 30 chars): {license_b64[:30]}...")
|
||||
return license_b64
|
||||
|
||||
except Exception as e:
|
||||
|
||||
@@ -29,6 +29,7 @@ class HRTiDefaults:
|
||||
'channels': f'{BASE_URL}/api/api/ott/GetChannels',
|
||||
'programme': f'{BASE_URL}/api/api/ott/GetProgramme',
|
||||
'authorize_session': f'{BASE_URL}/api/api/ott/AuthorizeSession',
|
||||
'report_session': f'{BASE_URL}/api/api/ott/ReportSessionEvent',
|
||||
'register_device': f'{HSAPI_BASE_URL}/RegisterDevice',
|
||||
'content_ratings': f'{HSAPI_BASE_URL}/ContentRatingsGet',
|
||||
'profiles': f'{HSAPI_BASE_URL}/ProfilesGet'
|
||||
|
||||
@@ -217,34 +217,90 @@ class HRTiProvider(StreamingProvider):
|
||||
|
||||
def enrich_channel_data(self, channel: StreamingChannel, **kwargs) -> Optional[StreamingChannel]:
|
||||
"""
|
||||
Enrich channel with manifest URL and additional data
|
||||
Enrich channel with manifest URL and DRM configuration
|
||||
"""
|
||||
try:
|
||||
# For HRTi, we need to authorize a session to get the manifest
|
||||
manifest_url = self.get_manifest(channel.channel_id, **kwargs)
|
||||
logger.debug(f"Enriching channel: {channel.name} ({channel.channel_id})")
|
||||
|
||||
# For live channels, we need to authorize a session first
|
||||
content_type = "rlive" if channel.content_type == "AUDIO" else "tlive"
|
||||
|
||||
# Parse the streaming URL to get content DRM ID
|
||||
from urllib.parse import urlparse
|
||||
parts = urlparse(channel.manifest_script)
|
||||
path_parts = parts.path.strip('/').split('/')
|
||||
|
||||
# Content DRM ID format: directory1_directory2
|
||||
# Example: /cdn1oiv/hrtliveorigin/... -> cdn1oiv_hrtliveorigin
|
||||
content_drm_id = None
|
||||
if len(path_parts) >= 2:
|
||||
content_drm_id = f"{path_parts[0]}_{path_parts[1]}"
|
||||
|
||||
logger.debug(f"Content DRM ID for {channel.name}: {content_drm_id}")
|
||||
|
||||
# Authorize session
|
||||
session_data = self.auth.authorize_session(
|
||||
content_type=content_type,
|
||||
content_ref_id=channel.channel_id,
|
||||
content_drm_id=content_drm_id,
|
||||
video_store_ids=None,
|
||||
channel_id=channel.channel_id,
|
||||
start_time=None,
|
||||
end_time=None
|
||||
)
|
||||
|
||||
if not session_data:
|
||||
logger.warning(f"Failed to authorize session for channel {channel.name}")
|
||||
return channel
|
||||
|
||||
# Check if authorized
|
||||
if not session_data.get('Authorized', False):
|
||||
logger.warning(f"Session not authorized for channel {channel.name}")
|
||||
return channel
|
||||
|
||||
logger.debug(f"Session authorized for {channel.name}")
|
||||
|
||||
# Report session event (play start)
|
||||
session_id = session_data.get('SessionId') or session_data.get('DrmId')
|
||||
if session_id:
|
||||
self.auth.report_session_event(session_id, channel.channel_id)
|
||||
|
||||
# Set the manifest URL - use the streaming URL from channel data
|
||||
manifest_url = channel.manifest_script
|
||||
if manifest_url:
|
||||
# HRTi manifests are dynamic and session-based
|
||||
channel.set_dynamic_manifest(manifest_url)
|
||||
logger.debug(f"Set manifest for {channel.name}: {manifest_url}")
|
||||
|
||||
# Set DRM configuration
|
||||
drm_configs = self.get_drm(channel.channel_id, **kwargs)
|
||||
if drm_configs:
|
||||
channel.use_cdm = True
|
||||
channel.cdm_type = "widevine"
|
||||
# Set license URL from first Widevine config
|
||||
for config in drm_configs:
|
||||
if config.system == DRMSystem.WIDEVINE:
|
||||
channel.license_url = config.license.server_url
|
||||
break
|
||||
else:
|
||||
channel.use_cdm = False
|
||||
channel.cdm_type = None
|
||||
# Set DRM configuration with session data
|
||||
drm_configs = self.get_drm(channel.channel_id, session_data, **kwargs)
|
||||
if drm_configs:
|
||||
channel.use_cdm = True
|
||||
channel.cdm_type = "widevine"
|
||||
|
||||
return channel
|
||||
# Set license URL from the first Widevine config
|
||||
for config in drm_configs:
|
||||
if config.system == DRMSystem.WIDEVINE:
|
||||
channel.license_url = config.license.server_url
|
||||
|
||||
# Build the complete license key for inputstream.adaptive
|
||||
# Format: server_url|req_headers|req_data|response_format
|
||||
license_key_parts = [
|
||||
config.license.server_url,
|
||||
config.license.req_headers,
|
||||
'R{SSM}', # Placeholder - inputstream will replace with actual challenge
|
||||
'JBlicense' # Response is JSON, extract 'license' field
|
||||
]
|
||||
channel.license_key = '|'.join(license_key_parts)
|
||||
|
||||
logger.debug(f"Set DRM config for {channel.name}")
|
||||
logger.debug(f"License URL: {config.license.server_url}")
|
||||
break
|
||||
else:
|
||||
logger.warning(f"Could not fetch manifest for channel {channel.name} ({channel.channel_id})")
|
||||
return channel
|
||||
logger.warning(f"No DRM config for {channel.name}")
|
||||
channel.use_cdm = False
|
||||
channel.cdm_type = None
|
||||
|
||||
return channel
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error enriching channel data for {channel.name}: {e}")
|
||||
|
||||
Reference in New Issue
Block a user