mirror of
https://github.com/nirvana-7777/script.service.ultimate.git
synced 2026-10-06 07:52:26 +02:00
143 lines
5.4 KiB
Python
143 lines
5.4 KiB
Python
# streaming_providers/providers/_template/models.py
|
|
"""
|
|
{TODO: Provider name} models.
|
|
|
|
What is needed:
|
|
* A custom AuthToken subclass -- MANDATORY for any provider with auth.
|
|
BaseAuthToken is an ABC with an abstract to_dict(), so it cannot be
|
|
instantiated directly. The minimal subclass below is live code, not
|
|
an example; auth.py imports it.
|
|
* A custom Channel subclass -- optional (extra per-channel fields; see
|
|
MoveTV's MoveTVChannel, Discovery's DiscoveryChannel, simpliTV's
|
|
SimpliTVChannel).
|
|
* A custom Credentials subclass -- optional (unusual login payload; see
|
|
HRTi's HRTiCredentials).
|
|
|
|
A provider WITHOUT auth can delete the AuthToken subclass. A provider that
|
|
uses plain Channel and UserPasswordCredentials needs nothing else here.
|
|
|
|
Rules
|
|
-----
|
|
* When overriding to_dict(), call super().to_dict() and add your fields.
|
|
Channel.to_dict() chains correctly. BaseAuthToken.to_dict() is abstract,
|
|
so an AuthToken subclass implements it in full.
|
|
* to_dict() keys on Channel subclasses are TitleCase, no underscores
|
|
("YourField"), matching the base serializer.
|
|
* Custom Channel subclasses are returned from ChannelManager.get_channels()
|
|
as-is; nothing in the base inspects the concrete type. Use the inherited
|
|
factories (create_live_channel / create_vod_channel / create_radio_channel);
|
|
they use cls(...) and therefore return your subclass.
|
|
* Custom AuthToken subclasses are returned from your Auth's
|
|
_perform_authentication(); the base never inspects their type beyond the
|
|
attributes it needs (access_token, expires_in, is_expired).
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any, Dict
|
|
|
|
from ...base.auth.base_auth import BaseAuthToken
|
|
|
|
# from ...base.models import Channel
|
|
# from ...base.auth.credentials import UserPasswordCredentials
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# AuthToken subclass (mandatory when the provider has auth)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@dataclass
|
|
class YourAuthToken(BaseAuthToken):
|
|
"""
|
|
Minimal concrete token.
|
|
|
|
Add provider-specific claims as new fields WITH DEFAULTS, after the
|
|
base fields, and include them in to_dict()/from_dict().
|
|
|
|
to_dict() must exist even if you never persist tokens (the ABC
|
|
requires it). Implement it for real so enabling persistence later
|
|
needs no follow-up edit.
|
|
|
|
VERIFY against base/auth/base_auth.py: the field list below mirrors
|
|
the README example. If BaseAuthToken has required fields not listed
|
|
here, add them to to_dict() and from_dict().
|
|
"""
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
return {
|
|
"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,
|
|
"refresh_expires_in": self.refresh_expires_in,
|
|
"auth_level": self.auth_level.value,
|
|
"credential_type": self.credential_type,
|
|
}
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: Dict[str, Any]) -> "YourAuthToken":
|
|
"""
|
|
Reconstruct from a persisted dict. Used by Auth._load_session().
|
|
|
|
Mirror to_dict(). auth_level is serialized via `.value`, so it
|
|
must be converted back to its enum here (see base_auth.py);
|
|
until you do, keep persistence off or let _load_session() return
|
|
None -- a failed load only costs one re-authentication.
|
|
"""
|
|
return cls(
|
|
access_token=data["access_token"],
|
|
token_type=data.get("token_type", "Bearer"),
|
|
expires_in=data.get("expires_in", 0),
|
|
issued_at=data.get("issued_at", 0),
|
|
refresh_token=data.get("refresh_token"),
|
|
refresh_expires_in=data.get("refresh_expires_in", 0),
|
|
# TODO: auth_level=..., credential_type=...
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Example: custom Channel subclass
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# @dataclass
|
|
# class YourChannel(Channel):
|
|
# """
|
|
# Channel with provider-specific extra fields.
|
|
#
|
|
# Keep the base class's field names and defaults; add new fields after
|
|
# them so positional construction still works. Never remove or rename
|
|
# base fields -- downstream consumers read them.
|
|
# """
|
|
#
|
|
# codename: str = ""
|
|
# recording_id: str = ""
|
|
#
|
|
# def to_dict(self) -> Dict[str, Any]:
|
|
# result = super().to_dict()
|
|
# result["Codename"] = self.codename
|
|
# result["RecordingId"] = self.recording_id
|
|
# return result
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Example: custom Credentials subclass
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# @dataclass
|
|
# class YourCredentials(UserPasswordCredentials):
|
|
# """
|
|
# Credentials with a provider-specific payload shape.
|
|
#
|
|
# Only needed when the login payload isn't the usual
|
|
# {username, password} (HRTi's grant_access takes
|
|
# {Username, Password, OperatorReferenceId}, for example).
|
|
# """
|
|
#
|
|
# operator_reference_id: str = "default"
|
|
#
|
|
# def to_auth_payload(self) -> Dict[str, Any]:
|
|
# return {
|
|
# "Username": self.username,
|
|
# "Password": self.password,
|
|
# "OperatorReferenceId": self.operator_reference_id,
|
|
# } |