Files
script.service.ultimate/lib/streaming_providers/providers/hrti/models.py
T
2026-01-06 16:41:03 +01:00

254 lines
7.6 KiB
Python

# [file name]: models.py
# [file content begin]
# streaming_providers/providers/hrti/models.py
from dataclasses import dataclass
from typing import Any, Dict, Optional
from ...base.auth.base_auth import BaseAuthToken
from ...base.auth.credentials import UserPasswordCredentials
from .constants import HRTiDefaults
@dataclass
class HRTiCredentials(UserPasswordCredentials):
"""
HRTi specific username/password credentials
"""
def __init__(self, username: str, password: str):
super().__init__(username=username, password=password)
# credential_type is not a property in base class, so we don't set it
def to_auth_payload(self) -> Dict[str, Any]:
"""Convert to authentication payload for HRTi"""
return {
"Username": self.username,
"Password": self.password,
"OperatorReferenceId": HRTiDefaults.OPERATOR_REFERENCE_ID,
}
def validate(self) -> bool:
"""Validate HRTi credentials"""
return bool(self.username and self.password)
class HRTiAuthToken(BaseAuthToken):
"""
HRTi specific authentication token
"""
def __init__(
self,
access_token: str,
token_type: str,
expires_in: int,
issued_at: float,
user_id: str = "",
valid_from: str = "",
valid_to: str = "",
refresh_token: Optional[str] = None,
):
super().__init__(
access_token=access_token,
token_type=token_type,
expires_in=expires_in,
issued_at=issued_at,
refresh_token=refresh_token,
)
# HRTi specific fields
self.user_id = user_id
self.valid_from = valid_from
self.valid_to = valid_to
# Don't set credential_type - it's not in base class
def to_dict(self) -> Dict[str, Any]:
"""Convert token to dictionary"""
base_dict = {
"access_token": self.access_token,
"token_type": self.token_type,
"expires_in": self.expires_in,
"issued_at": self.issued_at,
"refresh_token": self.refresh_token or "",
}
# Add HRTi specific fields
base_dict.update(
{
"user_id": self.user_id,
"valid_from": self.valid_from,
"valid_to": self.valid_to,
}
)
# Add auth_level if available
if hasattr(self, "auth_level") and self.auth_level:
base_dict["auth_level"] = self.auth_level.value
return base_dict
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "HRTiAuthToken":
"""Create token from dictionary"""
return cls(
access_token=data["access_token"],
token_type=data.get("token_type", "Client"),
expires_in=data.get("expires_in", 86400),
issued_at=data.get("issued_at", 0),
user_id=data.get("user_id", ""),
valid_from=data.get("valid_from", ""),
valid_to=data.get("valid_to", ""),
refresh_token=data.get("refresh_token"),
)
def is_valid(self) -> bool:
"""Check if token is still valid"""
import time
if not self.access_token:
return False
# Basic expiration check
current_time = time.time()
buffer_time = 300 # 5 minutes buffer
return current_time < (self.issued_at + self.expires_in - buffer_time)
@dataclass
class HRTiChannel:
"""
HRTi channel information
"""
id: str
name: str
reference_id: str
streaming_url: str
icon_url: str
is_radio: bool = False
description: Optional[str] = None
sort_order: int = 0
def __post_init__(self):
"""Validate channel data after initialization"""
if not self.id or not self.name or not self.reference_id:
raise ValueError("Channel must have id, name, and reference_id")
@classmethod
def from_api_response(cls, data: Dict[str, Any]) -> "HRTiChannel":
"""Create channel from API response data"""
return cls(
id=data.get("ReferenceId", ""),
name=data.get("Name", ""),
reference_id=data.get("ReferenceId", ""),
streaming_url=data.get("StreamingURL", ""),
icon_url=data.get("Icon", ""),
is_radio=data.get("Radio", False),
description=data.get("Description"),
sort_order=data.get("SortOrder", 0),
)
def to_dict(self) -> Dict[str, Any]:
"""Convert channel to dictionary"""
return {
"id": self.id,
"name": self.name,
"reference_id": self.reference_id,
"streaming_url": self.streaming_url,
"icon_url": self.icon_url,
"is_radio": self.is_radio,
"description": self.description,
"sort_order": self.sort_order,
}
@dataclass
class HRTiEpgEntry:
"""
HRTi EPG (Electronic Program Guide) entry
"""
reference_id: str
title: str
description_short: str
description_long: str
start_time: str
end_time: str
image_url: str
channel_reference_id: str
content_rating: Optional[str] = None
episode_number: Optional[str] = None
season_number: Optional[str] = None
@classmethod
def from_api_response(cls, data: Dict[str, Any], channel_id: str) -> "HRTiEpgEntry":
"""Create EPG entry from API response"""
return cls(
reference_id=data.get("ReferenceId", ""),
title=data.get("Title", ""),
description_short=data.get("DescriptionShort", ""),
description_long=data.get("DescriptionLong", ""),
start_time=data.get("TimeStart", ""),
end_time=data.get("TimeEnd", ""),
image_url=data.get("ImagePath", ""),
channel_reference_id=channel_id,
content_rating=data.get("ContentRating"),
episode_number=data.get("EpisodeNr"),
season_number=data.get("SeasonNr"),
)
def to_dict(self) -> Dict[str, Any]:
"""Convert EPG entry to dictionary"""
return {
"reference_id": self.reference_id,
"title": self.title,
"description_short": self.description_short,
"description_long": self.description_long,
"start_time": self.start_time,
"end_time": self.end_time,
"image_url": self.image_url,
"channel_reference_id": self.channel_reference_id,
"content_rating": self.content_rating,
"episode_number": self.episode_number,
"season_number": self.season_number,
}
@dataclass
class HRTiSession:
"""
HRTi playback session information
"""
session_id: str
authorized: bool
drm_id: str
channel_reference_id: str
content_reference_id: str
@classmethod
def from_api_response(cls, data: Dict[str, Any]) -> "HRTiSession":
"""Create session from API response"""
return cls(
session_id=data.get("SessionId", ""),
authorized=data.get("Authorized", False),
drm_id=data.get("DrmId", ""),
channel_reference_id=data.get("ChannelReferenceId", ""),
content_reference_id=data.get("ContentReferenceId", ""),
)
def to_dict(self) -> Dict[str, Any]:
"""Convert session to dictionary"""
return {
"session_id": self.session_id,
"authorized": self.authorized,
"drm_id": self.drm_id,
"channel_reference_id": self.channel_reference_id,
"content_reference_id": self.content_reference_id,
}
# [file content end]