mirror of
https://github.com/nirvana-7777/script.service.ultimate.git
synced 2026-10-07 16:32:19 +02:00
170 lines
6.4 KiB
Python
170 lines
6.4 KiB
Python
# streaming_providers/base/managers/recordings.py
|
|
"""
|
|
RecordingsManager ABC.
|
|
|
|
Public interface
|
|
----------------
|
|
handles_recording_id(recording_id) -> bool [concrete]
|
|
get_recordings(**kw) -> List[Channel] [abstract]
|
|
delete_recording(recording_id, **kw) -> None [abstract]
|
|
schedule_recording(content_id, **kw) -> Channel|bool [concrete, optional]
|
|
|
|
Constructor contract
|
|
--------------------
|
|
Four required keyword-only collaborators. No **kwargs. Subclasses accept
|
|
extra keyword-only args explicitly and call super().__init__ with only
|
|
the four required.
|
|
|
|
Return-value conventions
|
|
------------------------
|
|
get_recordings returns [] when the provider has no recordings. Callers
|
|
should treat an empty list as "no recordings", not as an error.
|
|
|
|
delete_recording raises KeyError when the recording does not exist, and
|
|
ProviderError subclasses (usually ServerError / EntitlementError) on
|
|
transport or permission failures. Returning silently on a failed delete
|
|
would hide real errors.
|
|
|
|
schedule_recording is optional -- the ABC provides a default that raises
|
|
NotImplementedYetError. Providers that support scheduling override it.
|
|
|
|
Recording identity
|
|
------------------
|
|
A recording is identified by its provider-side recording_id, which is a
|
|
distinct namespace from content_id. Some providers use the same value
|
|
for both; some do not. The ABC treats them as separate parameters so
|
|
that distinction is preserved.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from typing import Any, List
|
|
|
|
from ..errors import NotImplementedYetError
|
|
from ..models import Channel
|
|
from ..protocols import AuthProtocol
|
|
from ..utils.logger import logger
|
|
|
|
|
|
class RecordingsManager(ABC):
|
|
"""
|
|
Abstract base for provider recordings managers.
|
|
|
|
Recording identity
|
|
------------------
|
|
A recording is identified by its provider-side recording_id, which
|
|
is a distinct namespace from content_id. Some providers use the same
|
|
value for both; some do not. The ABC treats them as separate
|
|
parameters so that distinction is preserved.
|
|
|
|
No manifest method
|
|
------------------
|
|
This ABC deliberately has no get_manifest method. Recordings are
|
|
played via the same content_id that a channel or VOD manager
|
|
resolves -- the provider's router decides which manager owns the
|
|
manifest fetch. Some providers resolve a recording's manifest
|
|
through their ChannelManager (the API shares the codename
|
|
namespace between a channel and its recordings, as simpliTV does);
|
|
others may route through VodManager or a dedicated playback path.
|
|
The recordings manager's job is the *list* and the *delete*, not
|
|
the playback URL.
|
|
|
|
Providers that need a recording's manifest should implement the
|
|
routing in their provider's get_manifest, not by adding a
|
|
get_manifest method here. See providers/simpli/provider.py for
|
|
the pattern.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
http_manager: Any,
|
|
auth: AuthProtocol,
|
|
country: str,
|
|
config: Any,
|
|
) -> None:
|
|
if not isinstance(auth, AuthProtocol):
|
|
logger.warning(
|
|
f"{self.__class__.__name__}: auth does not match AuthProtocol "
|
|
f"(missing one of get_access_token / build_headers / "
|
|
f"invalidate). Got {type(auth).__name__}."
|
|
)
|
|
self.http_manager = http_manager
|
|
self.auth = auth
|
|
self.country = country
|
|
self.config = config
|
|
|
|
# ------------------------------------------------------------------
|
|
# Routing
|
|
# ------------------------------------------------------------------
|
|
|
|
def handles_recording_id(self, recording_id: str) -> bool:
|
|
"""
|
|
True if this manager can handle the given recording_id.
|
|
|
|
Default: True. Override in providers whose recording IDs have a
|
|
distinguishable prefix or format, so a router can dispatch
|
|
without a wasted request. Not used by the base provider; a
|
|
provider that surfaces recordings through multiple managers can
|
|
consult this to route delete/update calls.
|
|
"""
|
|
return True
|
|
|
|
# ------------------------------------------------------------------
|
|
# Abstract
|
|
# ------------------------------------------------------------------
|
|
|
|
@abstractmethod
|
|
def get_recordings(self, **kw: Any) -> List[Channel]:
|
|
"""
|
|
Return recordings for the authenticated user.
|
|
|
|
Return [] when the provider has no recordings. Do NOT raise
|
|
NotFoundError for "no recordings" -- that is a valid empty
|
|
result, not a missing resource.
|
|
|
|
Recording objects are returned as Channel instances (or a
|
|
Channel subclass carrying extra fields such as recording_id,
|
|
start/stop times, and the underlying content_id). The base
|
|
Channel shape is preserved because downstream callers expect a
|
|
content_id and a name.
|
|
|
|
Providers whose recordings are conceptually distinct from their
|
|
channels (e.g. cloud-PVR recordings that store their own
|
|
programme metadata) should subclass Channel with the extra
|
|
fields they need, and document them in the subclass's docstring.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def delete_recording(self, recording_id: str, **kw: Any) -> None:
|
|
"""
|
|
Delete a recording.
|
|
|
|
Raises:
|
|
KeyError: if the recording does not exist.
|
|
ProviderError: on transport / permission / server failure.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
# ------------------------------------------------------------------
|
|
# Concrete -- optional
|
|
# ------------------------------------------------------------------
|
|
|
|
def schedule_recording(self, content_id: str, **kw: Any) -> Any:
|
|
"""
|
|
Schedule a recording of content_id.
|
|
|
|
Optional. Return value is provider-specific: some providers
|
|
return the created recording (a Channel), others return a bool
|
|
indicating success. The ABC does not constrain the shape
|
|
because there is no shared one across providers.
|
|
|
|
Default raises NotImplementedYetError. Providers that support
|
|
scheduling override this.
|
|
"""
|
|
raise NotImplementedYetError(
|
|
f"{self.__class__.__name__}.schedule_recording is not "
|
|
f"implemented"
|
|
) |