diff --git a/pychromecast/controllers/__init__.py b/pychromecast/controllers/__init__.py index ba3c60dcb..1ff9f72a5 100644 --- a/pychromecast/controllers/__init__.py +++ b/pychromecast/controllers/__init__.py @@ -203,5 +203,5 @@ class QuickPlayController(BaseController, abc.ABC): """ABC for controller which supports quick play.""" @abc.abstractmethod - def quick_play(self, *, media_id: str, **kwargs: Any) -> None: + def quick_play(self, *, media_id: str, timeout: float, **kwargs: Any) -> None: """Quick Play support for a controller.""" diff --git a/pychromecast/controllers/bbciplayer.py b/pychromecast/controllers/bbciplayer.py index 07ecc6b3a..03b87f009 100644 --- a/pychromecast/controllers/bbciplayer.py +++ b/pychromecast/controllers/bbciplayer.py @@ -27,6 +27,7 @@ def quick_play( self, *, media_id: str, + timeout: float, is_live: bool = False, metadata: dict[str, Any] | None = None, **kwargs: Any, @@ -44,5 +45,6 @@ def quick_play( stream_type=stream_type, metadata=metadata, media_info={"customData": {"secondary_title": subtitle}}, + timeout=timeout, **kwargs, ) diff --git a/pychromecast/controllers/bbcsounds.py b/pychromecast/controllers/bbcsounds.py index e054e6c0a..ef4ae5110 100644 --- a/pychromecast/controllers/bbcsounds.py +++ b/pychromecast/controllers/bbcsounds.py @@ -25,6 +25,7 @@ def quick_play( self, *, media_id: str, + timeout: float, is_live: bool = False, metadata: dict[str, Any] | None = None, **kwargs: Any, @@ -39,5 +40,6 @@ def quick_play( media_type=None, stream_type=stream_type, metadata=metadata, + timeout=timeout, **kwargs, ) diff --git a/pychromecast/controllers/media.py b/pychromecast/controllers/media.py index 64addffb3..bff568dcc 100644 --- a/pychromecast/controllers/media.py +++ b/pychromecast/controllers/media.py @@ -544,12 +544,12 @@ def _send_start_play_media( # pylint: disable=too-many-locals self.send_message(msg, inc_session_id=True, callback_function=callback_function) - def quick_play(self, *, media_id: str, **kwargs: Any) -> None: + def quick_play(self, *, media_id: str, timeout: float, **kwargs: Any) -> None: """Quick Play""" media_type = kwargs.pop("media_type", "video/mp4") - response_handler = WaitResponse(30) + response_handler = WaitResponse(timeout) self.play_media( media_id, media_type, **kwargs, callback_function=response_handler.callback ) diff --git a/pychromecast/controllers/supla.py b/pychromecast/controllers/supla.py index 742599ef8..486617090 100644 --- a/pychromecast/controllers/supla.py +++ b/pychromecast/controllers/supla.py @@ -56,10 +56,10 @@ def play_media( ) def quick_play( - self, *, media_id: str, is_live: bool = False, **kwargs: Any + self, *, media_id: str, timeout: float, is_live: bool = False, **kwargs: Any ) -> None: """Quick Play""" - response_handler = WaitResponse(10) + response_handler = WaitResponse(timeout) self.play_media( media_id, is_live=is_live, diff --git a/pychromecast/controllers/yleareena.py b/pychromecast/controllers/yleareena.py index 8f7516e4b..c40b2a118 100644 --- a/pychromecast/controllers/yleareena.py +++ b/pychromecast/controllers/yleareena.py @@ -61,12 +61,13 @@ def quick_play( self, *, media_id: str, + timeout: float, audio_lang: str = "", text_lang: str = "off", **kwargs: Any, ) -> None: """Quick Play""" - response_handler = WaitResponse(10) + response_handler = WaitResponse(timeout) self.play_areena_media( media_id, audio_language=audio_lang, diff --git a/pychromecast/controllers/youtube.py b/pychromecast/controllers/youtube.py index 1e5f9224d..5c4e8a9d7 100644 --- a/pychromecast/controllers/youtube.py +++ b/pychromecast/controllers/youtube.py @@ -2,11 +2,14 @@ Controller to interface with the YouTube-app. Use the media controller to play, pause etc. """ + import logging import threading -from typing import Any +from typing import Any, cast from casttube import YouTubeSession # type: ignore[import-untyped] +from casttube.YouTubeSession import HEADERS # type: ignore[import-untyped] +import requests from . import QuickPlayController from ..const import MESSAGE_TYPE @@ -22,15 +25,64 @@ _LOGGER = logging.getLogger(__name__) +class TimeoutYouTubeSession(YouTubeSession): # type: ignore[misc] + """A youtube session with timeout.""" + + def __init__(self, screen_id: str, timeout: float) -> None: + """Initialize.""" + super().__init__(screen_id) + self.__timeout = timeout + + def _do_post( + self, + url: Any, + data: Any = None, + params: Any = None, + headers: Any = None, + session_request: Any = False, + ) -> Any: + """ + Calls requests.post with custom headers, + increments RID(request id) on every post. + will raise if response is not 200 + :param url:(str) request url + :param data: (dict) the POST body + :param params:(dict) POST url params + :param headers:(dict) Additional headers for the request + :param session_request:(bool) True to increment session + request counter(req_count) + :return: POST response + """ + if headers: + headers = {**HEADERS, **headers} + else: + headers = HEADERS + response = requests.post( + url, headers=headers, data=data, params=params, timeout=self.__timeout + ) + # 404 resets the sid, session counters + # 400 in session probably means bad sid + # If user did a bad request (eg. remove an non-existing video from queue) + # bind restores the session. + if response.status_code in (404, 400) and session_request: + self._bind() + response.raise_for_status() + if session_request: + self._req_count += 1 + self._rid += 1 + return response + + class YouTubeController(QuickPlayController): """Controller to interact with Youtube.""" _session: YouTubeSession _screen_id: str | None = None - def __init__(self) -> None: + def __init__(self, timeout: float = 10) -> None: super().__init__(YOUTUBE_NAMESPACE, APP_YOUTUBE) self.status_update_event = threading.Event() + self._timeout = timeout def start_session_if_none(self) -> None: """ @@ -38,7 +90,9 @@ def start_session_if_none(self) -> None: """ if not (self._screen_id and self._session): self.update_screen_id() - self._session = YouTubeSession(screen_id=self._screen_id) + self._session = TimeoutYouTubeSession( + screen_id=cast(str, self._screen_id), timeout=self._timeout + ) def play_video(self, video_id: str, playlist_id: str | None = None) -> None: """ @@ -112,11 +166,14 @@ def quick_play( self, *, media_id: str, + timeout: float, playlist_id: str | None = None, enqueue: bool = False, **kwargs: Any, ) -> None: """Quick Play""" + self._timeout = timeout + if enqueue: self.add_to_queue(media_id, **kwargs) else: