python-linkplay 0.0.11__tar.gz → 0.0.14__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.
- {python_linkplay-0.0.11/src/python_linkplay.egg-info → python_linkplay-0.0.14}/PKG-INFO +1 -1
- python_linkplay-0.0.14/src/linkplay/__version__.py +1 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/linkplay/bridge.py +28 -4
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/linkplay/consts.py +4 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/linkplay/controller.py +24 -19
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/linkplay/utils.py +0 -2
- {python_linkplay-0.0.11 → python_linkplay-0.0.14/src/python_linkplay.egg-info}/PKG-INFO +1 -1
- python_linkplay-0.0.11/src/linkplay/__version__.py +0 -1
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/LICENSE +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/README.md +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/pyproject.toml +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/setup.cfg +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/setup.py +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/linkplay/__init__.py +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/linkplay/__main__.py +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/linkplay/discovery.py +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/linkplay/endpoint.py +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/linkplay/exceptions.py +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/python_linkplay.egg-info/SOURCES.txt +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/python_linkplay.egg-info/dependency_links.txt +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/python_linkplay.egg-info/not-zip-safe +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/python_linkplay.egg-info/requires.txt +0 -0
- {python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/python_linkplay.egg-info/top_level.txt +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = '0.0.14'
|
@@ -4,6 +4,7 @@ from typing import Any
|
|
4
4
|
|
5
5
|
from linkplay.consts import (
|
6
6
|
INPUT_MODE_MAP,
|
7
|
+
LOGGER,
|
7
8
|
PLAY_MODE_SEND_MAP,
|
8
9
|
ChannelType,
|
9
10
|
DeviceAttribute,
|
@@ -130,6 +131,11 @@ class LinkPlayPlayer:
|
|
130
131
|
await self.bridge.request(LinkPlayCommand.PAUSE)
|
131
132
|
self.properties[PlayerAttribute.PLAYING_STATUS] = PlayingStatus.PAUSED
|
132
133
|
|
134
|
+
async def stop(self) -> None:
|
135
|
+
"""Stop the current playing track and remove the selected source."""
|
136
|
+
await self.bridge.request(LinkPlayCommand.STOP)
|
137
|
+
self.properties[PlayerAttribute.PLAYING_STATUS] = PlayingStatus.STOPPED
|
138
|
+
|
133
139
|
async def toggle(self) -> None:
|
134
140
|
"""Start playing if the player is currently not playing. Stops playing if it is."""
|
135
141
|
await self.bridge.request(LinkPlayCommand.TOGGLE)
|
@@ -230,9 +236,12 @@ class LinkPlayPlayer:
|
|
230
236
|
@property
|
231
237
|
def play_mode(self) -> PlayingMode:
|
232
238
|
"""Returns the current playing mode of the player."""
|
233
|
-
|
234
|
-
|
235
|
-
|
239
|
+
try:
|
240
|
+
return PlayingMode(
|
241
|
+
self.properties.get(PlayerAttribute.PLAYBACK_MODE, PlayingMode.IDLE)
|
242
|
+
)
|
243
|
+
except ValueError:
|
244
|
+
return PlayingMode(PlayingMode.IDLE)
|
236
245
|
|
237
246
|
@property
|
238
247
|
def loop_mode(self) -> LoopMode:
|
@@ -250,11 +259,13 @@ class LinkPlayBridge:
|
|
250
259
|
endpoint: LinkPlayEndpoint
|
251
260
|
device: LinkPlayDevice
|
252
261
|
player: LinkPlayPlayer
|
262
|
+
multiroom: LinkPlayMultiroom | None
|
253
263
|
|
254
264
|
def __init__(self, *, endpoint: LinkPlayEndpoint):
|
255
265
|
self.endpoint = endpoint
|
256
266
|
self.device = LinkPlayDevice(self)
|
257
267
|
self.player = LinkPlayPlayer(self)
|
268
|
+
self.multiroom = None
|
258
269
|
|
259
270
|
def __str__(self) -> str:
|
260
271
|
if self.device.name == "":
|
@@ -268,14 +279,20 @@ class LinkPlayBridge:
|
|
268
279
|
"endpoint": self.endpoint.to_dict(),
|
269
280
|
"device": self.device.to_dict(),
|
270
281
|
"player": self.player.to_dict(),
|
282
|
+
"multiroom": self.multiroom.to_dict() if self.multiroom else None,
|
271
283
|
}
|
272
284
|
|
273
285
|
async def json_request(self, command: str) -> dict[str, str]:
|
274
286
|
"""Performs a GET request on the given command and returns the result as a JSON object."""
|
275
|
-
|
287
|
+
LOGGER.debug(str.format("Request {} at {}", command, self.endpoint))
|
288
|
+
response = await self.endpoint.json_request(command)
|
289
|
+
LOGGER.debug(str.format("Response {}: {}", command, response))
|
290
|
+
return response
|
276
291
|
|
277
292
|
async def request(self, command: str) -> None:
|
278
293
|
"""Performs a GET request on the given command and verifies the result."""
|
294
|
+
|
295
|
+
LOGGER.debug(str.format("Request command at {}: {}", self.endpoint, command))
|
279
296
|
await self.endpoint.request(command)
|
280
297
|
|
281
298
|
|
@@ -290,6 +307,13 @@ class LinkPlayMultiroom:
|
|
290
307
|
self.leader = leader
|
291
308
|
self.followers = []
|
292
309
|
|
310
|
+
def to_dict(self):
|
311
|
+
"""Return the state of the LinkPlayMultiroom."""
|
312
|
+
return {
|
313
|
+
"leader": self.leader.to_dict(),
|
314
|
+
"followers": [follower.to_dict() for follower in self.followers],
|
315
|
+
}
|
316
|
+
|
293
317
|
async def update_status(self, bridges: list[LinkPlayBridge]) -> None:
|
294
318
|
"""Updates the multiroom status."""
|
295
319
|
properties: dict[Any, Any] = await self.leader.json_request(
|
@@ -1,5 +1,8 @@
|
|
1
|
+
import logging
|
1
2
|
from enum import IntFlag, StrEnum
|
2
3
|
|
4
|
+
LOGGER = logging.getLogger("linkplay")
|
5
|
+
|
3
6
|
API_ENDPOINT: str = "{}/httpapi.asp?command={}"
|
4
7
|
API_TIMEOUT: int = 2
|
5
8
|
UNKNOWN_TRACK_PLAYING: str = "Unknown"
|
@@ -79,6 +82,7 @@ class LinkPlayCommand(StrEnum):
|
|
79
82
|
VOLUME = "setPlayerCmd:vol:{}"
|
80
83
|
PLAYLIST = "setPlayerCmd:playlist:uri:{}"
|
81
84
|
PAUSE = "setPlayerCmd:pause"
|
85
|
+
STOP = "setPlayerCmd:stop"
|
82
86
|
TOGGLE = "setPlayerCmd:onepause"
|
83
87
|
EQUALIZER_MODE = "setPlayerCmd:equalizer:{}"
|
84
88
|
LOOP_MODE = "setPlayerCmd:loopmode:{}"
|
@@ -40,31 +40,36 @@ class LinkPlayController:
|
|
40
40
|
async def discover_multirooms(self) -> None:
|
41
41
|
"""Attempts to discover multirooms on the local network."""
|
42
42
|
|
43
|
+
# Find and update existing multirooms
|
44
|
+
multirooms = [bridge.multiroom for bridge in self.bridges if bridge.multiroom]
|
45
|
+
|
46
|
+
removed_multirooms = []
|
47
|
+
for multiroom in multirooms:
|
48
|
+
for follower in multiroom.followers:
|
49
|
+
follower.multiroom = None
|
50
|
+
await multiroom.update_status(self.bridges)
|
51
|
+
if len(multiroom.followers) > 0:
|
52
|
+
for follower in multiroom.followers:
|
53
|
+
follower.multiroom = multiroom
|
54
|
+
else:
|
55
|
+
multiroom.leader.multiroom = None
|
56
|
+
removed_multirooms.append(multiroom)
|
57
|
+
|
43
58
|
# Create new multirooms from new bridges
|
44
|
-
new_multirooms = []
|
45
59
|
for bridge in self.bridges:
|
46
|
-
|
47
|
-
multiroom for multiroom in self.multirooms if multiroom.leader == bridge
|
48
|
-
)
|
49
|
-
|
50
|
-
if has_multiroom:
|
60
|
+
if bridge.multiroom:
|
51
61
|
continue
|
52
62
|
|
53
63
|
multiroom = LinkPlayMultiroom(bridge)
|
54
64
|
await multiroom.update_status(self.bridges)
|
55
65
|
if len(multiroom.followers) > 0:
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
await multiroom.update_status(self.bridges)
|
66
|
+
multirooms.append(multiroom)
|
67
|
+
bridge.multiroom = multiroom
|
68
|
+
for follower in multiroom.followers:
|
69
|
+
follower.multiroom = multiroom
|
61
70
|
|
62
|
-
# Remove multirooms
|
63
|
-
|
64
|
-
multiroom for multiroom in self.multirooms if not multiroom.followers
|
65
|
-
]
|
66
|
-
for empty_multiroom in empty_multirooms:
|
67
|
-
self.multirooms.remove(empty_multiroom)
|
71
|
+
# Remove multirooms with no followers
|
72
|
+
multirooms = [item for item in multirooms if item not in removed_multirooms]
|
68
73
|
|
69
|
-
#
|
70
|
-
self.multirooms
|
74
|
+
# Update multirooms in controller
|
75
|
+
self.multirooms = multirooms
|
@@ -24,8 +24,6 @@ from linkplay.consts import (
|
|
24
24
|
)
|
25
25
|
from linkplay.exceptions import LinkPlayRequestException
|
26
26
|
|
27
|
-
_LOGGER = logging.getLogger(__name__)
|
28
|
-
|
29
27
|
|
30
28
|
async def session_call_api(endpoint: str, session: ClientSession, command: str) -> str:
|
31
29
|
"""Calls the LinkPlay API and returns the result as a string.
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = '0.0.11'
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/python_linkplay.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
{python_linkplay-0.0.11 → python_linkplay-0.0.14}/src/python_linkplay.egg-info/top_level.txt
RENAMED
File without changes
|