# if this attribute is omitted and an icon.svg or icon.png is found in the provider
# folder, it will be read instead.
icon: str | None = None
+ # icon_dark: optional separate dark icon
+ # if this attribute is omitted and an icon_dark.svg or icon_dark.png is found in the provider
+ # folder, it will be read instead.
+ icon_dark: str | None = None
@classmethod
async def parse(cls: "ProviderManifest", manifest_file: str) -> "ProviderManifest":
from __future__ import annotations
from dataclasses import dataclass
-from typing import TYPE_CHECKING, Any
+from typing import Any
from uuid import uuid4
from mashumaro import DataClassDictMixin
from .enums import MediaType
-from .media_items import ItemMapping, MediaItemImage, StreamDetails
-
-if TYPE_CHECKING:
- from .media_items import Album, Radio, Track
+from .media_items import Album, ItemMapping, MediaItemImage, Radio, StreamDetails, Track
@dataclass
_filename = os.path.join(self.mass.storage_path, filename)
async with aiofiles.open(_filename, "r", encoding="utf-8") as _file:
self._data = json_loads(await _file.read())
+ LOGGER.debug("Loaded persistent settings from %s", filename)
return
except FileNotFoundError:
pass
except JSON_DECODE_EXCEPTIONS: # pylint: disable=catching-non-exception
LOGGER.error("Error while reading persistent storage file %s", filename)
- else:
- LOGGER.debug("Loaded persistent settings from %s", filename)
LOGGER.debug("Started with empty storage: No persistent storage file found.")
async def _async_save(self):
player = self.get(player_id, True)
if player.powered == powered:
return
- # send stop at power off
- if not powered:
+ # stop player at power off
+ if not powered and player.state in (PlayerState.PLAYING, PlayerState.PAUSED):
await self.cmd_stop(player_id)
# unsync player at power off
if not powered and player.synced_to is not None:
if group_player.powered:
return group_player.player_id
# guess source from player's current url
- if player.current_url:
+ if player.current_url and player.state in (PlayerState.PLAYING, PlayerState.PAUSED):
if self.mass.webserver.base_url in player.current_url:
return player.player_id
if ":" in player.current_url:
try:
self._discovery_running = True
self.logger.debug("Sonos discovery started...")
- discovered_devices: set[soco.SoCo] = await asyncio.to_thread(soco.discover, 10)
+ discovered_devices: set[soco.SoCo] = await asyncio.to_thread(
+ soco.discover, 30, allow_network_scan=True
+ )
if discovered_devices is None:
discovered_devices = set()
new_device_ids = {item.uid for item in discovered_devices}
if os.path.isfile(icon_path):
provider_manifest.icon = await get_icon_string(icon_path)
break
+ # check for dark_icon file
+ if not provider_manifest.icon_dark:
+ for icon_file in ("icon_dark.svg", "icon_dark.png"):
+ icon_path = os.path.join(dir_path, icon_file)
+ if os.path.isfile(icon_path):
+ provider_manifest.icon_dark = await get_icon_string(icon_path)
+ break
self._available_providers[provider_manifest.domain] = provider_manifest
LOGGER.debug("Loaded manifest for provider %s", dir_str)
except Exception as exc: # pylint: disable=broad-except
"python-slugify==8.0.1",
"mashumaro==3.7",
"memory-tempfile==2.2.3",
- "music-assistant-frontend==20230414.0",
+ "music-assistant-frontend==20230419.0",
"pillow==9.5.0",
"unidecode==1.3.6",
"xmltodict==0.13.0",
git+https://github.com/pytube/pytube.git@refs/pull/1501/head
mashumaro==3.7
memory-tempfile==2.2.3
-music-assistant-frontend==20230414.0
+music-assistant-frontend==20230419.0
orjson==3.8.9
pillow==9.5.0
plexapi==4.13.4