Files
script.service.ultimate/lib/streaming_providers/base/managers/bookmarks.py
T
2026-10-03 20:39:40 +02:00

110 lines
3.4 KiB
Python

# streaming_providers/base/managers/bookmarks.py
"""
BookmarksManager ABC.
Public interface
----------------
get_bookmarks(**kw) -> List[Bookmark] [abstract]
update_bookmark(content_id, position_seconds, ...) -> Bookmark [abstract]
delete_bookmark(content_id, **kw) -> None [abstract]
Constructor contract
--------------------
Four required keyword-only collaborators.
Return-value conventions
------------------------
get_bookmarks returns [] when the user has no bookmarks. Not an error.
update_bookmark raises RuntimeError if the provider rejects the write
(e.g. content inaccessible, backend error). It is called on every
playback stop / pause, so providers should tolerate a write that
overwrites the same position with a no-op rather than failing.
delete_bookmark raises KeyError if no bookmark exists for content_id,
so callers can distinguish "already gone" from "successfully deleted".
The base ProviderBookmarksMixin documents the same rule.
Caller guidance
---------------
`position_seconds = -1` marks the content as completed. A position
that reaches the model's COMPLETION_THRESHOLD (>= 95% by default) is
also treated as completed by the caller -- providers just store what
they are given.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, List, Optional
from ..models.bookmark import Bookmark, ContentType
from ..protocols import AuthProtocol
from ..utils.logger import logger
class BookmarksManager(ABC):
"""Abstract base for provider bookmarks managers."""
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
# ------------------------------------------------------------------
# Abstract
# ------------------------------------------------------------------
@abstractmethod
def get_bookmarks(self, **kw: Any) -> List[Bookmark]:
"""
Return all bookmarks for the authenticated user.
Return [] when the user has no bookmarks.
"""
raise NotImplementedError
@abstractmethod
def update_bookmark(
self,
content_id: str,
position_seconds: int,
content_type: ContentType,
duration_seconds: Optional[int] = None,
title: Optional[str] = None,
**kw: Any,
) -> Bookmark:
"""
Save or update a bookmark.
Called on playback stop / pause, so should be tolerant of
repeated writes to the same position (a no-op write is fine).
Raises RuntimeError if the provider rejects the write.
"""
raise NotImplementedError
@abstractmethod
def delete_bookmark(self, content_id: str, **kw: Any) -> None:
"""
Delete a bookmark.
Raises:
KeyError: if no bookmark exists for content_id.
RuntimeError: on backend failure.
"""
raise NotImplementedError