PyChromecast 14.0.2__tar.gz → 14.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/PKG-INFO +1 -1
  2. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/PyChromecast.egg-info/PKG-INFO +1 -1
  3. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/PyChromecast.egg-info/SOURCES.txt +1 -0
  4. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/const.py +2 -0
  5. PyChromecast-14.0.4/pychromecast/controllers/heartbeat.py +90 -0
  6. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/socket_client.py +17 -79
  7. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pyproject.toml +1 -1
  8. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/requirements.txt +1 -1
  9. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/LICENSE +0 -0
  10. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/MANIFEST.in +0 -0
  11. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/PyChromecast.egg-info/dependency_links.txt +0 -0
  12. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/PyChromecast.egg-info/not-zip-safe +0 -0
  13. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/PyChromecast.egg-info/requires.txt +0 -0
  14. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/PyChromecast.egg-info/top_level.txt +0 -0
  15. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/README.rst +0 -0
  16. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/__init__.py +0 -0
  17. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/config.py +0 -0
  18. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/__init__.py +0 -0
  19. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/bbciplayer.py +0 -0
  20. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/bbcsounds.py +0 -0
  21. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/bubbleupnp.py +0 -0
  22. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/dashcast.py +0 -0
  23. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/homeassistant.py +0 -0
  24. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/homeassistant_media.py +0 -0
  25. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/media.py +0 -0
  26. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/multizone.py +0 -0
  27. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/nrkradio.py +0 -0
  28. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/nrktv.py +0 -0
  29. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/plex.py +0 -0
  30. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/receiver.py +0 -0
  31. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/shaka.py +0 -0
  32. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/supla.py +0 -0
  33. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/yleareena.py +0 -0
  34. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/controllers/youtube.py +0 -0
  35. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/dial.py +0 -0
  36. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/discovery.py +0 -0
  37. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/error.py +0 -0
  38. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/generated/authority_keys_pb2.py +0 -0
  39. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/generated/authority_keys_pb2.pyi +0 -0
  40. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/generated/cast_channel_pb2.py +0 -0
  41. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/generated/cast_channel_pb2.pyi +0 -0
  42. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/generated/logging_pb2.py +0 -0
  43. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/generated/logging_pb2.pyi +0 -0
  44. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/generated/readme.txt +0 -0
  45. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/models.py +0 -0
  46. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/quick_play.py +0 -0
  47. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/pychromecast/response_handler.py +0 -0
  48. {PyChromecast-14.0.2 → PyChromecast-14.0.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyChromecast
3
- Version: 14.0.2
3
+ Version: 14.0.4
4
4
  Summary: Python module to talk to Google Chromecast.
5
5
  Author-email: Paulus Schoutsen <paulus@paulusschoutsen.nl>
6
6
  Project-URL: Homepage, https://github.com/home-assistant-libs/pychromecast
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyChromecast
3
- Version: 14.0.2
3
+ Version: 14.0.4
4
4
  Summary: Python module to talk to Google Chromecast.
5
5
  Author-email: Paulus Schoutsen <paulus@paulusschoutsen.nl>
6
6
  Project-URL: Homepage, https://github.com/home-assistant-libs/pychromecast
@@ -25,6 +25,7 @@ pychromecast/controllers/bbciplayer.py
25
25
  pychromecast/controllers/bbcsounds.py
26
26
  pychromecast/controllers/bubbleupnp.py
27
27
  pychromecast/controllers/dashcast.py
28
+ pychromecast/controllers/heartbeat.py
28
29
  pychromecast/controllers/homeassistant.py
29
30
  pychromecast/controllers/homeassistant_media.py
30
31
  pychromecast/controllers/media.py
@@ -70,3 +70,5 @@ CAST_TYPES = {
70
70
  MESSAGE_TYPE = "type"
71
71
  REQUEST_ID = "requestId"
72
72
  SESSION_ID = "sessionId"
73
+
74
+ PLATFORM_DESTINATION_ID = "receiver-0"
@@ -0,0 +1,90 @@
1
+ """Controller to send and respond to heartbeat messages."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import time
7
+
8
+ from . import BaseController
9
+
10
+ from ..const import MESSAGE_TYPE, PLATFORM_DESTINATION_ID
11
+ from ..error import ControllerNotRegistered, NotConnected, PyChromecastStopped
12
+
13
+ # pylint: disable-next=no-name-in-module
14
+ from ..generated.cast_channel_pb2 import CastMessage
15
+
16
+ NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat"
17
+
18
+ TYPE_PING = "PING"
19
+ TYPE_PONG = "PONG"
20
+
21
+ HB_PING_TIME = 10
22
+ HB_PONG_TIME = 10
23
+
24
+
25
+ class HeartbeatController(BaseController):
26
+ """Controller to send and respond to heartbeat messages."""
27
+
28
+ def __init__(self) -> None:
29
+ super().__init__(NS_HEARTBEAT, target_platform=True)
30
+ self.last_ping = 0.0
31
+ self.last_pong = time.time()
32
+ self.logger = logging.getLogger(__name__)
33
+
34
+ def receive_message(self, _message: CastMessage, data: dict) -> bool:
35
+ """
36
+ Called when a heartbeat message is received.
37
+
38
+ data is message.payload_utf8 interpreted as a JSON dict.
39
+ """
40
+ if self._socket_client is None:
41
+ raise ControllerNotRegistered
42
+
43
+ if self._socket_client.is_stopped:
44
+ return True
45
+
46
+ if data[MESSAGE_TYPE] == TYPE_PING:
47
+ try:
48
+ self._socket_client.send_message(
49
+ PLATFORM_DESTINATION_ID,
50
+ self.namespace,
51
+ {MESSAGE_TYPE: TYPE_PONG},
52
+ no_add_request_id=True,
53
+ )
54
+ except PyChromecastStopped:
55
+ self._socket_client.logger.debug(
56
+ "Heartbeat error when sending response, "
57
+ "Chromecast connection has stopped"
58
+ )
59
+
60
+ return True
61
+
62
+ if data[MESSAGE_TYPE] == TYPE_PONG:
63
+ self.reset()
64
+ return True
65
+
66
+ return False
67
+
68
+ def ping(self) -> None:
69
+ """Send a ping message."""
70
+ if self._socket_client is None:
71
+ raise ControllerNotRegistered
72
+
73
+ self.last_ping = time.time()
74
+ try:
75
+ self.send_message({MESSAGE_TYPE: TYPE_PING})
76
+ except NotConnected:
77
+ self._socket_client.logger.error(
78
+ "Chromecast is disconnected. Cannot ping until reconnected."
79
+ )
80
+
81
+ def reset(self) -> None:
82
+ """Reset expired counter."""
83
+ self.last_pong = time.time()
84
+
85
+ def is_expired(self) -> bool:
86
+ """Indicates if connection has expired."""
87
+ if time.time() - self.last_ping > HB_PING_TIME:
88
+ self.ping()
89
+
90
+ return (time.time() - self.last_pong) > HB_PING_TIME + HB_PONG_TIME
@@ -24,8 +24,9 @@ from struct import pack, unpack
24
24
 
25
25
  import zeroconf
26
26
 
27
- from .const import MESSAGE_TYPE, REQUEST_ID, SESSION_ID
27
+ from .const import MESSAGE_TYPE, PLATFORM_DESTINATION_ID, REQUEST_ID, SESSION_ID
28
28
  from .controllers import BaseController, CallbackType
29
+ from .controllers.heartbeat import NS_HEARTBEAT, HeartbeatController
29
30
  from .controllers.media import MediaController
30
31
  from .controllers.receiver import CastStatus, CastStatusListener, ReceiverController
31
32
  from .dial import get_host_from_service
@@ -42,12 +43,7 @@ from .generated.cast_channel_pb2 import CastMessage
42
43
  from .models import HostServiceInfo, MDNSServiceInfo
43
44
 
44
45
  NS_CONNECTION = "urn:x-cast:com.google.cast.tp.connection"
45
- NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat"
46
46
 
47
- PLATFORM_DESTINATION_ID = "receiver-0"
48
-
49
- TYPE_PING = "PING"
50
- TYPE_PONG = "PONG"
51
47
  TYPE_CONNECT = "CONNECT"
52
48
  TYPE_CLOSE = "CLOSE"
53
49
  TYPE_LOAD = "LOAD"
@@ -65,8 +61,7 @@ CONNECTION_STATUS_FAILED_RESOLVE = "FAILED_RESOLVE"
65
61
  # The socket connection was lost and needs to be retried
66
62
  CONNECTION_STATUS_LOST = "LOST"
67
63
 
68
- HB_PING_TIME = 10
69
- HB_PONG_TIME = 10
64
+ SELECT_TIMEOUT = 5.0
70
65
  TIMEOUT_TIME = 30.0
71
66
  RETRY_TIME = 5.0
72
67
 
@@ -566,9 +561,13 @@ class SocketClient(threading.Thread, CastStatusListener):
566
561
  # A connection has been established at this point by self._check_connection
567
562
  assert self.socket is not None
568
563
 
569
- # poll the socket, as well as the socketpair to allow us to be interrupted
564
+ # Poll the socket and the socketpair, with a timeout of SELECT_TIMEOUT
565
+ # The timeout ensures we call _check_connection often enough to avoid
566
+ # the HeartbeatController from detecting a timeout
567
+ # The socketpair allow us to be interrupted on shutdown without waiting
568
+ # for the SELECT_TIMEOUT timout to expire
570
569
  try:
571
- ready = self.selector.select()
570
+ ready = self.selector.select(SELECT_TIMEOUT)
572
571
  except (ValueError, OSError) as exc:
573
572
  self.logger.error(
574
573
  "[%s(%s):%s] Error in select call: %s",
@@ -687,7 +686,10 @@ class SocketClient(threading.Thread, CastStatusListener):
687
686
  # route message to handlers
688
687
  if message.namespace in self._handlers:
689
688
  # debug messages
690
- if message.namespace != NS_HEARTBEAT:
689
+ if (
690
+ message.namespace != NS_HEARTBEAT
691
+ or self.heartbeat_controller.logger.isEnabledFor(logging.DEBUG)
692
+ ):
691
693
  self.logger.debug(
692
694
  "[%s(%s):%s] Received: %s",
693
695
  self.fn or "",
@@ -871,7 +873,10 @@ class SocketClient(threading.Thread, CastStatusListener):
871
873
  be_size = pack(">I", msg.ByteSize())
872
874
 
873
875
  # Log all messages except heartbeat
874
- if msg.namespace != NS_HEARTBEAT:
876
+ if (
877
+ msg.namespace != NS_HEARTBEAT
878
+ or self.heartbeat_controller.logger.isEnabledFor(logging.DEBUG)
879
+ ):
875
880
  self.logger.debug(
876
881
  "[%s(%s):%s] Sending: %s",
877
882
  self.fn or "",
@@ -1060,73 +1065,6 @@ class ConnectionController(BaseController):
1060
1065
  return False
1061
1066
 
1062
1067
 
1063
- class HeartbeatController(BaseController):
1064
- """Controller to respond to heartbeat messages."""
1065
-
1066
- def __init__(self) -> None:
1067
- super().__init__(NS_HEARTBEAT, target_platform=True)
1068
- self.last_ping = 0.0
1069
- self.last_pong = time.time()
1070
-
1071
- def receive_message(self, _message: CastMessage, data: dict) -> bool:
1072
- """
1073
- Called when a heartbeat message is received.
1074
-
1075
- data is message.payload_utf8 interpreted as a JSON dict.
1076
- """
1077
- if self._socket_client is None:
1078
- raise ControllerNotRegistered
1079
-
1080
- if self._socket_client.is_stopped:
1081
- return True
1082
-
1083
- if data[MESSAGE_TYPE] == TYPE_PING:
1084
- try:
1085
- self._socket_client.send_message(
1086
- PLATFORM_DESTINATION_ID,
1087
- self.namespace,
1088
- {MESSAGE_TYPE: TYPE_PONG},
1089
- no_add_request_id=True,
1090
- )
1091
- except PyChromecastStopped:
1092
- self._socket_client.logger.debug(
1093
- "Heartbeat error when sending response, "
1094
- "Chromecast connection has stopped"
1095
- )
1096
-
1097
- return True
1098
-
1099
- if data[MESSAGE_TYPE] == TYPE_PONG:
1100
- self.reset()
1101
- return True
1102
-
1103
- return False
1104
-
1105
- def ping(self) -> None:
1106
- """Send a ping message."""
1107
- if self._socket_client is None:
1108
- raise ControllerNotRegistered
1109
-
1110
- self.last_ping = time.time()
1111
- try:
1112
- self.send_message({MESSAGE_TYPE: TYPE_PING})
1113
- except NotConnected:
1114
- self._socket_client.logger.error(
1115
- "Chromecast is disconnected. Cannot ping until reconnected."
1116
- )
1117
-
1118
- def reset(self) -> None:
1119
- """Reset expired counter."""
1120
- self.last_pong = time.time()
1121
-
1122
- def is_expired(self) -> bool:
1123
- """Indicates if connection has expired."""
1124
- if time.time() - self.last_ping > HB_PING_TIME:
1125
- self.ping()
1126
-
1127
- return (time.time() - self.last_pong) > HB_PING_TIME + HB_PONG_TIME
1128
-
1129
-
1130
1068
  def new_socket() -> socket.socket:
1131
1069
  """
1132
1070
  Create a new socket with OS-specific parameters
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyChromecast"
7
- version = "14.0.2"
7
+ version = "14.0.4"
8
8
  description = "Python module to talk to Google Chromecast."
9
9
  readme = "README.rst"
10
10
  authors = [
@@ -1,3 +1,3 @@
1
1
  casttube==0.2.1
2
- protobuf==4.25.2
2
+ protobuf==5.28.2
3
3
  zeroconf==0.135.0
File without changes
File without changes
File without changes
File without changes