PyChromecast 14.0.0__tar.gz → 14.0.2__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 (47) hide show
  1. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/PKG-INFO +7 -1
  2. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/PyChromecast.egg-info/PKG-INFO +7 -1
  3. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/README.rst +6 -0
  4. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/const.py +3 -0
  5. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/homeassistant.py +29 -1
  6. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/plex.py +2 -0
  7. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/youtube.py +1 -0
  8. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/response_handler.py +4 -0
  9. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/socket_client.py +36 -37
  10. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pyproject.toml +6 -1
  11. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/requirements.txt +1 -1
  12. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/LICENSE +0 -0
  13. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/MANIFEST.in +0 -0
  14. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/PyChromecast.egg-info/SOURCES.txt +0 -0
  15. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/PyChromecast.egg-info/dependency_links.txt +0 -0
  16. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/PyChromecast.egg-info/not-zip-safe +0 -0
  17. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/PyChromecast.egg-info/requires.txt +0 -0
  18. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/PyChromecast.egg-info/top_level.txt +0 -0
  19. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/__init__.py +0 -0
  20. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/config.py +0 -0
  21. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/__init__.py +0 -0
  22. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/bbciplayer.py +0 -0
  23. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/bbcsounds.py +0 -0
  24. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/bubbleupnp.py +0 -0
  25. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/dashcast.py +0 -0
  26. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/homeassistant_media.py +0 -0
  27. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/media.py +0 -0
  28. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/multizone.py +0 -0
  29. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/nrkradio.py +0 -0
  30. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/nrktv.py +0 -0
  31. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/receiver.py +0 -0
  32. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/shaka.py +0 -0
  33. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/supla.py +0 -0
  34. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/controllers/yleareena.py +0 -0
  35. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/dial.py +0 -0
  36. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/discovery.py +0 -0
  37. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/error.py +0 -0
  38. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/generated/authority_keys_pb2.py +0 -0
  39. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/generated/authority_keys_pb2.pyi +0 -0
  40. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/generated/cast_channel_pb2.py +0 -0
  41. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/generated/cast_channel_pb2.pyi +0 -0
  42. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/generated/logging_pb2.py +0 -0
  43. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/generated/logging_pb2.pyi +0 -0
  44. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/generated/readme.txt +0 -0
  45. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/models.py +0 -0
  46. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/pychromecast/quick_play.py +0 -0
  47. {PyChromecast-14.0.0 → PyChromecast-14.0.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyChromecast
3
- Version: 14.0.0
3
+ Version: 14.0.2
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
@@ -192,3 +192,9 @@ work. Without him it would not have been possible!
192
192
 
193
193
  .. _Linux style wildcard: http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm
194
194
  .. _Fred Clift: https://github.com/minektur
195
+
196
+ |ohf-logo|
197
+
198
+ .. |ohf-logo| image:: https://www.openhomefoundation.org/badges/pychromecast.png
199
+ :alt: PyChromecast - A library from the Open Home Foundation
200
+ :target: https://www.openhomefoundation.org/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyChromecast
3
- Version: 14.0.0
3
+ Version: 14.0.2
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
@@ -192,3 +192,9 @@ work. Without him it would not have been possible!
192
192
 
193
193
  .. _Linux style wildcard: http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm
194
194
  .. _Fred Clift: https://github.com/minektur
195
+
196
+ |ohf-logo|
197
+
198
+ .. |ohf-logo| image:: https://www.openhomefoundation.org/badges/pychromecast.png
199
+ :alt: PyChromecast - A library from the Open Home Foundation
200
+ :target: https://www.openhomefoundation.org/
@@ -175,3 +175,9 @@ work. Without him it would not have been possible!
175
175
 
176
176
  .. _Linux style wildcard: http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm
177
177
  .. _Fred Clift: https://github.com/minektur
178
+
179
+ |ohf-logo|
180
+
181
+ .. |ohf-logo| image:: https://www.openhomefoundation.org/badges/pychromecast.png
182
+ :alt: PyChromecast - A library from the Open Home Foundation
183
+ :target: https://www.openhomefoundation.org/
@@ -14,6 +14,7 @@ REQUEST_TIMEOUT = 10.0
14
14
 
15
15
  MF_CANTON = "Canton Elektronik GmbH + Co. KG"
16
16
  MF_GOOGLE = "Google Inc."
17
+ MF_HARMAN = "HARMAN International Industries"
17
18
  MF_JBL = "JBL"
18
19
  MF_LENOVO = "LENOVO"
19
20
  MF_LG = "LG"
@@ -42,11 +43,13 @@ CAST_TYPES = {
42
43
  "nest audio": (CAST_TYPE_AUDIO, MF_GOOGLE),
43
44
  "nest wifi point": (CAST_TYPE_AUDIO, MF_GOOGLE),
44
45
  "bravia 4k vh2": (CAST_TYPE_CHROMECAST, MF_SONY),
46
+ "bravia 4k vh21": (CAST_TYPE_CHROMECAST, MF_SONY),
45
47
  "C4A": (CAST_TYPE_AUDIO, MF_SONY),
46
48
  "JBL Link 10": (CAST_TYPE_AUDIO, MF_JBL),
47
49
  "JBL Link 20": (CAST_TYPE_AUDIO, MF_JBL),
48
50
  "JBL Link 300": (CAST_TYPE_AUDIO, MF_JBL),
49
51
  "JBL Link 500": (CAST_TYPE_AUDIO, MF_JBL),
52
+ "JBL Link Portable": (CAST_TYPE_AUDIO, MF_HARMAN),
50
53
  "lenovocd-24502f": (CAST_TYPE_AUDIO, MF_LENOVO),
51
54
  "Lenovo Smart Display 7": (CAST_TYPE_CHROMECAST, MF_LENOVO),
52
55
  "LG WK7 ThinQ Speaker": (CAST_TYPE_AUDIO, MF_LG),
@@ -4,6 +4,7 @@ Controller to interface with Home Assistant
4
4
 
5
5
  from collections.abc import Callable
6
6
  from functools import partial
7
+ import logging
7
8
  import threading
8
9
  from typing import Any
9
10
 
@@ -29,6 +30,8 @@ ERR_WRONG_INSTANCE = 20
29
30
  ERR_NOT_CONNECTED = 21
30
31
  ERR_FETCH_CONFIG_FAILED = 22
31
32
 
33
+ _LOGGER = logging.getLogger(__name__)
34
+
32
35
 
33
36
  class HomeAssistantController(BaseController):
34
37
  """Controller to interact with Home Assistant."""
@@ -45,6 +48,7 @@ class HomeAssistantController(BaseController):
45
48
  app_id: str = APP_HOMEASSISTANT_LOVELACE,
46
49
  hass_connect_timeout: float = DEFAULT_HASS_CONNECT_TIMEOUT,
47
50
  ) -> None:
51
+ _LOGGER.debug("HomeAssistantController.__init__")
48
52
  super().__init__(app_namespace, app_id)
49
53
  self.hass_url = hass_url
50
54
  self.hass_uuid = hass_uuid
@@ -77,16 +81,19 @@ class HomeAssistantController(BaseController):
77
81
  def channel_connected(self) -> None:
78
82
  """Called when a channel has been openend that supports the
79
83
  namespace of this controller."""
84
+ _LOGGER.debug("HomeAssistantController.channel_connected")
80
85
  self.get_status()
81
86
 
82
87
  def channel_disconnected(self) -> None:
83
88
  """Called when a channel is disconnected."""
89
+ _LOGGER.debug("HomeAssistantController.channel_disconnected")
84
90
  self.status = None
85
91
  self._hass_connecting_event.set()
86
92
 
87
93
  def receive_message(self, _message: CastMessage, data: dict) -> bool:
88
94
  """Called when a message is received."""
89
95
  if data.get("type") == "receiver_status":
96
+ _LOGGER.debug("HomeAssistantController.receive_message %s", data)
90
97
  if data["hassUrl"] != self.hass_url or data["hassUUID"] != self.hass_uuid:
91
98
  self.logger.info("Received status for another instance")
92
99
  self.unregister()
@@ -96,6 +103,9 @@ class HomeAssistantController(BaseController):
96
103
  self.status = data
97
104
 
98
105
  if was_connected or not self.hass_connected:
106
+ _LOGGER.debug(
107
+ "HomeAssistantController.receive_message already connected"
108
+ )
99
109
  return True
100
110
 
101
111
  # We just got connected, call the callbacks.
@@ -104,6 +114,7 @@ class HomeAssistantController(BaseController):
104
114
  return True
105
115
 
106
116
  if data.get("type") == "receiver_error":
117
+ _LOGGER.debug("HomeAssistantController.receive_message %s", data)
107
118
  if data.get("error_code") == ERR_WRONG_INSTANCE:
108
119
  self.logger.info("Received ERR_WRONG_INSTANCE")
109
120
  self.unregister()
@@ -113,14 +124,19 @@ class HomeAssistantController(BaseController):
113
124
 
114
125
  def _call_on_connect_callbacks(self, msg_sent: bool) -> None:
115
126
  """Call on connect callbacks."""
127
+ _LOGGER.debug("HomeAssistantController._call_on_connect_callbacks %s", msg_sent)
116
128
  while self._on_connect:
117
129
  self._on_connect.pop()(msg_sent, None)
118
130
 
119
131
  def _connect_hass(self, callback_function: CallbackType) -> None:
120
132
  """Connect to Home Assistant and call the provided callback."""
133
+ _LOGGER.debug("HomeAssistantController._connect_hass")
121
134
  self._on_connect.append(callback_function)
122
135
 
123
136
  if not self._hass_connecting_event.is_set():
137
+ _LOGGER.debug(
138
+ "HomeAssistantController._connect_hass _hass_connecting_event not set"
139
+ )
124
140
  return
125
141
 
126
142
  self._hass_connecting_event.clear()
@@ -135,6 +151,9 @@ class HomeAssistantController(BaseController):
135
151
  }
136
152
  )
137
153
  except Exception: # pylint: disable=broad-except
154
+ _LOGGER.debug(
155
+ "HomeAssistantController._connect_hass failed to send connect message"
156
+ )
138
157
  self._hass_connecting_event.set()
139
158
  self._call_on_connect_callbacks(False)
140
159
  raise
@@ -143,10 +162,10 @@ class HomeAssistantController(BaseController):
143
162
  try:
144
163
  if not self._hass_connecting_event.is_set():
145
164
  self.logger.warning("_connect_hass failed for %s", self.hass_url)
165
+ self._call_on_connect_callbacks(False)
146
166
  raise PyChromecastError() # pylint: disable=broad-exception-raised
147
167
  finally:
148
168
  self._hass_connecting_event.set()
149
- self._call_on_connect_callbacks(False)
150
169
 
151
170
  def show_demo(self) -> None:
152
171
  """Show the demo."""
@@ -154,6 +173,7 @@ class HomeAssistantController(BaseController):
154
173
 
155
174
  def get_status(self, *, callback_function: CallbackType | None = None) -> None:
156
175
  """Get status of Home Assistant Cast."""
176
+ _LOGGER.debug("HomeAssistantController.get_status")
157
177
  self._send_connected_message(
158
178
  {
159
179
  "type": "get_status",
@@ -171,6 +191,7 @@ class HomeAssistantController(BaseController):
171
191
  callback_function: CallbackType | None = None,
172
192
  ) -> None:
173
193
  """Show a Lovelace UI."""
194
+ _LOGGER.debug("HomeAssistantController.show_lovelace_view")
174
195
  self._send_connected_message(
175
196
  {
176
197
  "type": "show_lovelace_view",
@@ -186,10 +207,17 @@ class HomeAssistantController(BaseController):
186
207
  self, data: dict[str, Any], callback_function: CallbackType | None
187
208
  ) -> None:
188
209
  """Send a message to a connected Home Assistant Cast"""
210
+ _LOGGER.debug("HomeAssistantController._send_connected_message %s", data)
189
211
  if self.hass_connected:
212
+ _LOGGER.debug(
213
+ "HomeAssistantController._send_connected_message already connected"
214
+ )
190
215
  self.send_message_nocheck(data, callback_function=callback_function)
191
216
  return
192
217
 
218
+ _LOGGER.debug(
219
+ "HomeAssistantController._send_connected_message not yet connected"
220
+ )
193
221
  self._connect_hass(
194
222
  chain_on_success(
195
223
  partial(self.send_message_nocheck, data), callback_function
@@ -108,6 +108,8 @@ def media_to_chromecast_command( # pylint: disable=invalid-name, too-many-local
108
108
  dict: Returs a dict formatted correctly to start playback on a Chromecast.
109
109
  """
110
110
 
111
+ machineIdentifier = None
112
+ token = None
111
113
  if media is not None:
112
114
  # Lets set some params for the user if they use plexapi.
113
115
  server: PlexServer = (
@@ -84,6 +84,7 @@ class YouTubeController(QuickPlayController):
84
84
  super().__init__(YOUTUBE_NAMESPACE, APP_YOUTUBE)
85
85
  self.status_update_event = threading.Event()
86
86
  self._timeout = timeout
87
+ self._session = None
87
88
 
88
89
  def start_session_if_none(self) -> None:
89
90
  """
@@ -3,11 +3,14 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from collections.abc import Callable
6
+ import logging
6
7
  import threading
7
8
  from typing import Protocol
8
9
 
9
10
  from .error import RequestFailed, RequestTimeout
10
11
 
12
+ _LOGGER = logging.getLogger(__name__)
13
+
11
14
  CallbackType = Callable[[bool, dict | None], None]
12
15
  """Signature of optional callback functions supported by methods sending messages.
13
16
 
@@ -61,6 +64,7 @@ def chain_on_success(
61
64
 
62
65
  def _callback(msg_sent: bool, response: dict | None) -> None:
63
66
  if not msg_sent:
67
+ _LOGGER.debug("Not calling on_success %s", on_success)
64
68
  if callback_function:
65
69
  callback_function(msg_sent, response)
66
70
  return
@@ -10,31 +10,31 @@ Without him this would not have been possible.
10
10
  from __future__ import annotations
11
11
 
12
12
  import abc
13
- from dataclasses import dataclass
14
13
  import errno
15
14
  import json
16
15
  import logging
17
- import select
16
+ import selectors
18
17
  import socket
19
18
  import ssl
20
19
  import threading
21
20
  import time
22
21
  from collections import defaultdict
22
+ from dataclasses import dataclass
23
23
  from struct import pack, unpack
24
24
 
25
25
  import zeroconf
26
26
 
27
- from .controllers import CallbackType, BaseController
27
+ from .const import MESSAGE_TYPE, REQUEST_ID, SESSION_ID
28
+ from .controllers import BaseController, CallbackType
28
29
  from .controllers.media import MediaController
29
30
  from .controllers.receiver import CastStatus, CastStatusListener, ReceiverController
30
- from .const import MESSAGE_TYPE, REQUEST_ID, SESSION_ID
31
31
  from .dial import get_host_from_service
32
32
  from .error import (
33
33
  ChromecastConnectionError,
34
34
  ControllerNotRegistered,
35
- UnsupportedNamespace,
36
35
  NotConnected,
37
36
  PyChromecastStopped,
37
+ UnsupportedNamespace,
38
38
  )
39
39
 
40
40
  # pylint: disable-next=no-name-in-module
@@ -64,13 +64,9 @@ CONNECTION_STATUS_FAILED = "FAILED"
64
64
  CONNECTION_STATUS_FAILED_RESOLVE = "FAILED_RESOLVE"
65
65
  # The socket connection was lost and needs to be retried
66
66
  CONNECTION_STATUS_LOST = "LOST"
67
- # Check for select poll method
68
- SELECT_HAS_POLL = hasattr(select, "poll")
69
67
 
70
68
  HB_PING_TIME = 10
71
69
  HB_PONG_TIME = 10
72
- POLL_TIME_BLOCKING = 5.0
73
- POLL_TIME_NON_BLOCKING = 0.01
74
70
  TIMEOUT_TIME = 30.0
75
71
  RETRY_TIME = 5.0
76
72
 
@@ -215,6 +211,11 @@ class SocketClient(threading.Thread, CastStatusListener):
215
211
  self.connecting = True
216
212
  self.first_connection = True
217
213
  self.socket: socket.socket | ssl.SSLSocket | None = None
214
+ self.selector = selectors.DefaultSelector()
215
+ self.wakeup_selector_key = self.selector.register(
216
+ self.socketpair[0], selectors.EVENT_READ
217
+ )
218
+ self.remote_selector_key: selectors.SelectorKey | None = None
218
219
 
219
220
  # dict mapping namespace on Controller objects
220
221
  self._handlers: dict[str, set[BaseController]] = defaultdict(set)
@@ -238,8 +239,10 @@ class SocketClient(threading.Thread, CastStatusListener):
238
239
  tries = self.tries
239
240
 
240
241
  if self.socket is not None:
242
+ self.selector.unregister(self.socket)
241
243
  self.socket.close()
242
244
  self.socket = None
245
+ self.remote_selector_key = None
243
246
 
244
247
  # Make sure nobody is blocking.
245
248
  for callback_function in self._request_callbacks.values():
@@ -288,10 +291,15 @@ class SocketClient(threading.Thread, CastStatusListener):
288
291
  try:
289
292
  if self.socket is not None:
290
293
  # If we retry connecting, we need to clean up the socket again
291
- self.socket.close() # type: ignore[unreachable]
294
+ self.selector.unregister(self.socket) # type: ignore[unreachable]
295
+ self.socket.close()
292
296
  self.socket = None
297
+ self.remote_selector_key = None
293
298
 
294
299
  self.socket = new_socket()
300
+ self.remote_selector_key = self.selector.register(
301
+ self.socket, selectors.EVENT_READ
302
+ )
295
303
  self.socket.settimeout(self.timeout)
296
304
  self._report_connection_status(
297
305
  ConnectionStatus(
@@ -530,7 +538,7 @@ class SocketClient(threading.Thread, CastStatusListener):
530
538
  self.logger.debug("Thread started...")
531
539
  while not self.stop.is_set():
532
540
  try:
533
- if self._run_once(timeout=POLL_TIME_BLOCKING) == 1:
541
+ if self._run_once() == 1:
534
542
  break
535
543
  except Exception: # pylint: disable=broad-except
536
544
  self._force_recon = True
@@ -545,7 +553,7 @@ class SocketClient(threading.Thread, CastStatusListener):
545
553
  # Clean up
546
554
  self._cleanup()
547
555
 
548
- def _run_once(self, timeout: float = POLL_TIME_NON_BLOCKING) -> int:
556
+ def _run_once(self) -> int:
549
557
  """Receive from the socket and handle data."""
550
558
  # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements
551
559
 
@@ -559,20 +567,8 @@ class SocketClient(threading.Thread, CastStatusListener):
559
567
  assert self.socket is not None
560
568
 
561
569
  # poll the socket, as well as the socketpair to allow us to be interrupted
562
- rlist = [self.socket, self.socketpair[0]]
563
570
  try:
564
- if SELECT_HAS_POLL is True:
565
- # Map file descriptors to socket objects because select.select does not support fd > 1024
566
- # https://stackoverflow.com/questions/14250751/how-to-increase-filedescriptors-range-in-python-select
567
- fd_to_socket = {rlist_item.fileno(): rlist_item for rlist_item in rlist}
568
-
569
- poll_obj = select.poll()
570
- for poll_fd in rlist:
571
- poll_obj.register(poll_fd, select.POLLIN)
572
- poll_result = poll_obj.poll(timeout * 1000) # timeout in milliseconds
573
- can_read = [fd_to_socket[fd] for fd, _status in poll_result]
574
- else:
575
- can_read, _, _ = select.select(rlist, [], [], timeout)
571
+ ready = self.selector.select()
576
572
  except (ValueError, OSError) as exc:
577
573
  self.logger.error(
578
574
  "[%s(%s):%s] Error in select call: %s",
@@ -584,9 +580,10 @@ class SocketClient(threading.Thread, CastStatusListener):
584
580
  self._force_recon = True
585
581
  return 0
586
582
 
583
+ can_read = {key for key, _ in ready}
587
584
  # read message from chromecast
588
585
  message = None
589
- if self.socket in can_read and not self._force_recon:
586
+ if self.remote_selector_key in can_read and not self._force_recon:
590
587
  try:
591
588
  message = self._read_message()
592
589
  except InterruptLoop as exc:
@@ -611,18 +608,17 @@ class SocketClient(threading.Thread, CastStatusListener):
611
608
  if self.stop.is_set():
612
609
  return 1
613
610
  raise
614
- except socket.error:
611
+ except socket.error as exc:
615
612
  self._force_recon = True
616
613
  self.logger.error(
617
- "[%s(%s):%s] Error reading from socket.",
614
+ "[%s(%s):%s] Error reading from socket: %s",
618
615
  self.fn or "",
619
616
  self.host,
620
617
  self.port,
618
+ exc,
621
619
  )
622
- else:
623
- data = _dict_from_message_payload(message)
624
620
 
625
- if self.socketpair[0] in can_read:
621
+ if self.wakeup_selector_key in can_read:
626
622
  # Clear the socket's buffer
627
623
  self.socketpair[0].recv(128)
628
624
 
@@ -635,6 +631,7 @@ class SocketClient(threading.Thread, CastStatusListener):
635
631
  return 0
636
632
 
637
633
  # See if any handlers will accept this message
634
+ data = _dict_from_message_payload(message)
638
635
  self._route_message(message, data)
639
636
 
640
637
  if REQUEST_ID in data and data[REQUEST_ID] in self._request_callbacks:
@@ -652,8 +649,8 @@ class SocketClient(threading.Thread, CastStatusListener):
652
649
  # check if connection is expired
653
650
  reset = False
654
651
  if self._force_recon:
655
- self.logger.warning(
656
- "[%s(%s):%s] Error communicating with socket, resetting connection",
652
+ self.logger.debug(
653
+ "[%s(%s):%s] Forced reconnection",
657
654
  self.fn or "",
658
655
  self.host,
659
656
  self.port,
@@ -661,7 +658,7 @@ class SocketClient(threading.Thread, CastStatusListener):
661
658
  reset = True
662
659
 
663
660
  elif self.heartbeat_controller.is_expired():
664
- self.logger.warning(
661
+ self.logger.info(
665
662
  "[%s(%s):%s] Heartbeat timeout, resetting connection",
666
663
  self.fn or "",
667
664
  self.host,
@@ -767,6 +764,7 @@ class SocketClient(threading.Thread, CastStatusListener):
767
764
 
768
765
  self.socketpair[0].close()
769
766
  self.socketpair[1].close()
767
+ self.selector.close()
770
768
 
771
769
  self.connecting = True
772
770
 
@@ -897,17 +895,18 @@ class SocketClient(threading.Thread, CastStatusListener):
897
895
  else:
898
896
  callback_function(True, None)
899
897
  self.socket.sendall(be_size + msg.SerializeToString())
900
- except socket.error:
898
+ except socket.error as exc:
901
899
  if callback_function:
902
900
  callback_function(False, None)
903
901
  if not no_add_request_id:
904
902
  self._request_callbacks.pop(request_id, None)
905
903
  self._force_recon = True
906
- self.logger.info(
907
- "[%s(%s):%s] Error writing to socket.",
904
+ self.logger.warning(
905
+ "[%s(%s):%s] Error writing to socket: %s",
908
906
  self.fn or "",
909
907
  self.host,
910
908
  self.port,
909
+ exc,
911
910
  )
912
911
  else:
913
912
  if callback_function:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyChromecast"
7
- version = "14.0.0"
7
+ version = "14.0.2"
8
8
  description = "Python module to talk to Google Chromecast."
9
9
  readme = "README.rst"
10
10
  authors = [
@@ -31,6 +31,11 @@ classifiers=[
31
31
  [tool.black]
32
32
  exclude = 'pb2'
33
33
 
34
+ [tool.rstcheck]
35
+ # README.rst has embedded python examples which show the interactive interpreter output
36
+ # that's not valid Python, so we disable the check
37
+ ignore_languages = ["python"]
38
+
34
39
  [tool.setuptools]
35
40
  platforms = ["any"]
36
41
  zip-safe = false
@@ -1,3 +1,3 @@
1
1
  casttube==0.2.1
2
2
  protobuf==4.25.2
3
- zeroconf==0.131.0
3
+ zeroconf==0.135.0
File without changes
File without changes
File without changes