From: Marcel van der Veldt Date: Wed, 19 Jul 2023 23:11:36 +0000 (+0200) Subject: Switch to SVG for all provider icons (#782) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=189329cd20707ade14e9ddd44883fd72ae80c3d0;p=music-assistant-server.git Switch to SVG for all provider icons (#782) --- diff --git a/music_assistant/common/models/config_entries.py b/music_assistant/common/models/config_entries.py index 4e9974dc..ae2c673a 100644 --- a/music_assistant/common/models/config_entries.py +++ b/music_assistant/common/models/config_entries.py @@ -10,7 +10,6 @@ from typing import Any from mashumaro import DataClassDictMixin from music_assistant.common.models.enums import ProviderType -from music_assistant.common.models.provider import ProviderManifest from music_assistant.constants import ( CONF_AUTO_PLAY, CONF_CROSSFADE_DURATION, @@ -183,7 +182,6 @@ class Config(DataClassDictMixin): return value.value res = self.to_dict() - res.pop("manifest", None) # filter out from storage res["values"] = { x.key: _handle_value(x) for x in self.values.values() @@ -244,7 +242,6 @@ class ProviderConfig(Config): type: ProviderType domain: str instance_id: str - manifest: ProviderManifest | None = None # copied here for UI convenience only # enabled: boolean to indicate if the provider is enabled enabled: bool = True # name: an (optional) custom name for this provider instance/config @@ -274,7 +271,6 @@ class CoreConfig(Config): """CoreController Configuration.""" domain: str # domain/name of the core module - manifest: ProviderManifest | None = None # copied here for UI convenience only # last_error: an optional error message if the module could not be setup with this config last_error: str | None = None diff --git a/music_assistant/common/models/provider.py b/music_assistant/common/models/provider.py index 5e6a66f7..b953ee3e 100644 --- a/music_assistant/common/models/provider.py +++ b/music_assistant/common/models/provider.py @@ -37,15 +37,16 @@ class ProviderManifest(DataClassORJSONMixin): load_by_default: bool = False # depends_on: depends on another provider to function depends_on: str | None = None - # icon: icon url (svg or transparent png) max 256 pixels - # may also be a direct base64 encoded image string - # if this attribute is omitted and an icon.svg or icon.png is found in the provider - # folder, it will be read instead. + # icon: name of the material design icon (https://pictogrammers.com/library/mdi) 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 + # icon_svg: svg icon (full xml string) + # if this attribute is omitted and an icon.svg is found in the provider + # folder, the file contents will be read instead. + icon_svg: str | None = None + # icon_svg_dark: optional separate dark svg icon (full xml string) + # if this attribute is omitted and an icon_dark.svg is found in the provider + # folder, the file contents will be read instead. + icon_svg_dark: str | None = None @classmethod async def parse(cls: "ProviderManifest", manifest_file: str) -> "ProviderManifest": diff --git a/music_assistant/constants.py b/music_assistant/constants.py index 8ed067ac..38c06e89 100755 --- a/music_assistant/constants.py +++ b/music_assistant/constants.py @@ -76,3 +76,12 @@ MASS_LOGO_ONLINE: Final[ ] = "https://github.com/home-assistant/brands/raw/master/custom_integrations/mass/icon%402x.png" ENCRYPT_SUFFIX = "_encrypted_" SECURE_STRING_SUBSTITUTE = "this_value_is_encrypted" +CONFIGURABLE_CORE_CONTROLLERS = ( + "streams", + "webserver", + "players", + "metadata", + "cache", + "music", + "player_queues", +) diff --git a/music_assistant/server/controllers/cache.py b/music_assistant/server/controllers/cache.py index 7e84dce2..fdb2cddc 100644 --- a/music_assistant/server/controllers/cache.py +++ b/music_assistant/server/controllers/cache.py @@ -43,7 +43,7 @@ class CacheController(CoreController): self.manifest.description = ( "Music Assistant's core controller for caching data throughout the application." ) - self.manifest.icon = "mdi-memory" + self.manifest.icon = "memory" async def get_config_entries( self, diff --git a/music_assistant/server/controllers/config.py b/music_assistant/server/controllers/config.py index 08a2ec8e..a08784ef 100644 --- a/music_assistant/server/controllers/config.py +++ b/music_assistant/server/controllers/config.py @@ -32,6 +32,7 @@ from music_assistant.constants import ( CONF_PLAYERS, CONF_PROVIDERS, CONF_SERVER_ID, + CONFIGURABLE_CORE_CONTROLLERS, ENCRYPT_SUFFIX, ) from music_assistant.server.helpers.api import api_command @@ -50,16 +51,6 @@ isfile = wrap(os.path.isfile) remove = wrap(os.remove) rename = wrap(os.rename) -CONFIGURABLE_CORE_CONTROLLERS = ( - "streams", - "webserver", - "players", - "metadata", - "cache", - "music", - "player_queues", -) - class ConfigController: """Controller that handles storage of persistent configuration settings.""" @@ -172,7 +163,7 @@ class ConfigController: ) -> list[ProviderConfig]: """Return all known provider configurations, optionally filtered by ProviderType.""" raw_values: dict[str, dict] = self.get(CONF_PROVIDERS, {}) - prov_entries = {x.domain for x in self.mass.get_available_providers()} + prov_entries = {x.domain for x in self.mass.get_provider_manifests()} return [ await self.get_provider_config(prov_conf["instance_id"]) for prov_conf in raw_values.values() @@ -189,16 +180,12 @@ class ConfigController: config_entries = await self.get_provider_config_entries( raw_conf["domain"], instance_id=instance_id, values=raw_conf.get("values") ) - for prov in self.mass.get_available_providers(): + for prov in self.mass.get_provider_manifests(): if prov.domain == raw_conf["domain"]: - manifest = prov break else: raise KeyError(f'Unknown provider domain: {raw_conf["domain"]}') - conf: ProviderConfig = ProviderConfig.parse(config_entries, raw_conf) - # always copy the manifest to help the UI a bit - conf.manifest = manifest - return conf + return ProviderConfig.parse(config_entries, raw_conf) raise KeyError(f"No config found for provider id {instance_id}") @api_command("config/providers/get_value") @@ -234,7 +221,7 @@ class ConfigController: values: the (intermediate) raw values for config entries sent with the action. """ # lookup provider manifest and module - for prov in self.mass.get_available_providers(): + for prov in self.mass.get_provider_manifests(): if prov.domain == provider_domain: prov_mod = await get_provider_module(provider_domain) break @@ -446,7 +433,7 @@ class ConfigController: for conf in await self.get_provider_configs(provider_domain=provider_domain): # return if there is already a config return - for prov in self.mass.get_available_providers(): + for prov in self.mass.get_provider_manifests(): if prov.domain == provider_domain: manifest = prov break @@ -482,13 +469,9 @@ class ConfigController: @api_command("config/core/get") async def get_core_config(self, domain: str) -> CoreConfig: """Return configuration for a single core controller.""" - core_controller: CoreController = getattr(self.mass, domain) raw_conf = self.get(f"{CONF_CORE}/{domain}", {"domain": domain}) config_entries = await self.get_core_config_entries(domain) - conf: CoreConfig = CoreConfig.parse(config_entries, raw_conf) - # always copy the manifest to help the UI a bit - conf.manifest = core_controller.manifest - return conf + return CoreConfig.parse(config_entries, raw_conf) @api_command("config/core/get_value") async def get_core_config_value(self, domain: str, key: str) -> ConfigValueType: @@ -662,7 +645,7 @@ class ConfigController: Returns: newly created ProviderConfig. """ # lookup provider manifest and module - for prov in self.mass.get_available_providers(): + for prov in self.mass.get_provider_manifests(): if prov.domain == provider_domain: manifest = prov break diff --git a/music_assistant/server/controllers/metadata.py b/music_assistant/server/controllers/metadata.py index 4ab8ce52..2c46a618 100755 --- a/music_assistant/server/controllers/metadata.py +++ b/music_assistant/server/controllers/metadata.py @@ -53,7 +53,7 @@ class MetaDataController(CoreController): self.manifest.description = ( "Music Assistant's core controller which handles all metadata for music." ) - self.manifest.icon = "mdi-book-information-variant" + self.manifest.icon = "book-information-variant" async def setup(self, config: CoreConfig) -> None: # noqa: ARG002 """Async initialize of module.""" diff --git a/music_assistant/server/controllers/music.py b/music_assistant/server/controllers/music.py index c61c12c2..664553cd 100755 --- a/music_assistant/server/controllers/music.py +++ b/music_assistant/server/controllers/music.py @@ -75,7 +75,7 @@ class MusicController(CoreController): self.manifest.description = ( "Music Assistant's core controller which manages all music from all providers." ) - self.manifest.icon = "mdi-archive-music" + self.manifest.icon = "archive-music" self._sync_task: asyncio.Task | None = None async def get_config_entries( diff --git a/music_assistant/server/controllers/player_queues.py b/music_assistant/server/controllers/player_queues.py index 592f76f3..5e9e59fe 100755 --- a/music_assistant/server/controllers/player_queues.py +++ b/music_assistant/server/controllers/player_queues.py @@ -49,7 +49,7 @@ class PlayerQueuesController(CoreController): self.manifest.description = ( "Music Assistant's core controller which manages the queues for all players." ) - self.manifest.icon = "mdi-playlist-music" + self.manifest.icon = "playlist-music" async def close(self) -> None: """Cleanup on exit.""" diff --git a/music_assistant/server/controllers/players.py b/music_assistant/server/controllers/players.py index 86e7203d..977c8967 100755 --- a/music_assistant/server/controllers/players.py +++ b/music_assistant/server/controllers/players.py @@ -51,7 +51,7 @@ class PlayerController(CoreController): self.manifest.description = ( "Music Assistant's core controller which manages all players from all providers." ) - self.manifest.icon = "mdi-speaker-multiple" + self.manifest.icon = "speaker-multiple" self._poll_task: asyncio.Task | None = None async def setup(self, config: CoreConfig) -> None: # noqa: ARG002 diff --git a/music_assistant/server/controllers/streams.py b/music_assistant/server/controllers/streams.py index cd461da4..85f48103 100644 --- a/music_assistant/server/controllers/streams.py +++ b/music_assistant/server/controllers/streams.py @@ -271,7 +271,7 @@ class StreamsController(CoreController): "streaming audio to players on the local network as well as " "some player specific local control callbacks." ) - self.manifest.icon = "mdi-cast-audio" + self.manifest.icon = "cast-audio" @property def base_url(self) -> str: diff --git a/music_assistant/server/controllers/webserver.py b/music_assistant/server/controllers/webserver.py index 28317193..2c802102 100644 --- a/music_assistant/server/controllers/webserver.py +++ b/music_assistant/server/controllers/webserver.py @@ -64,7 +64,7 @@ class WebserverController(CoreController): self.manifest.description = ( "The built-in webserver that hosts the Music Assistant Websockets API and frontend" ) - self.manifest.icon = "mdi-web-box" + self.manifest.icon = "web-box" @property def base_url(self) -> str: diff --git a/music_assistant/server/helpers/images.py b/music_assistant/server/helpers/images.py index fa153627..66880ee5 100644 --- a/music_assistant/server/helpers/images.py +++ b/music_assistant/server/helpers/images.py @@ -3,7 +3,6 @@ from __future__ import annotations import asyncio import random -from base64 import b64encode from io import BytesIO from typing import TYPE_CHECKING @@ -79,12 +78,10 @@ async def create_collage(mass: MusicAssistant, images: list[MediaItemImage]) -> async def get_icon_string(icon_path: str) -> str: - """Get icon as (base64 encoded) string.""" + """Get svg icon as string.""" ext = icon_path.rsplit(".")[-1] - assert ext in ("png", "svg", "ico", "jpg") - async with aiofiles.open(icon_path, "rb") as _file: - img_data = await _file.read() - enc_image = b64encode(img_data).decode() - if ext == "svg": - return f"data:image/svg+xml;base64,{enc_image}" - return f"data:image/{ext};base64,{enc_image}" + assert ext == "svg" + async with aiofiles.open(icon_path, "r") as _file: + xml_data = await _file.read() + xml_data = xml_data.replace("\n", "").strip() + return xml_data diff --git a/music_assistant/server/models/core_controller.py b/music_assistant/server/models/core_controller.py index 782299ca..6018c095 100644 --- a/music_assistant/server/models/core_controller.py +++ b/music_assistant/server/models/core_controller.py @@ -38,7 +38,7 @@ class CoreController: name=f"{self.domain.title()} Core controller", description=f"{self.domain.title()} Core controller", codeowners=["@music-assistant"], - icon="mdi:puzzle-outline", + icon="puzzle-outline", ) async def get_config_entries( diff --git a/music_assistant/server/providers/airplay/manifest.json b/music_assistant/server/providers/airplay/manifest.json index 4e26fb48..38598a2f 100644 --- a/music_assistant/server/providers/airplay/manifest.json +++ b/music_assistant/server/providers/airplay/manifest.json @@ -10,5 +10,5 @@ "builtin": false, "load_by_default": true, "depends_on": "slimproto", - "icon": "md:airplay" + "icon":"cast-variant" } diff --git a/music_assistant/server/providers/chromecast/manifest.json b/music_assistant/server/providers/chromecast/manifest.json index 8dd1f46f..dcb77c89 100644 --- a/music_assistant/server/providers/chromecast/manifest.json +++ b/music_assistant/server/providers/chromecast/manifest.json @@ -9,5 +9,5 @@ "multi_instance": false, "builtin": false, "load_by_default": true, - "icon": "md:cast" + "icon": "cast" } diff --git a/music_assistant/server/providers/deezer/icon.svg b/music_assistant/server/providers/deezer/icon.svg index 0704de6c..04948c25 100644 --- a/music_assistant/server/providers/deezer/icon.svg +++ b/music_assistant/server/providers/deezer/icon.svg @@ -1,53 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/music_assistant/server/providers/dlna/icon.png b/music_assistant/server/providers/dlna/icon.png deleted file mode 100644 index 14c34a41..00000000 Binary files a/music_assistant/server/providers/dlna/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/dlna/icon.svg b/music_assistant/server/providers/dlna/icon.svg new file mode 100755 index 00000000..10e19efa --- /dev/null +++ b/music_assistant/server/providers/dlna/icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/music_assistant/server/providers/dlna/manifest.json b/music_assistant/server/providers/dlna/manifest.json index a5eea0be..b637e980 100644 --- a/music_assistant/server/providers/dlna/manifest.json +++ b/music_assistant/server/providers/dlna/manifest.json @@ -8,5 +8,6 @@ "documentation": "https://github.com/music-assistant/hass-music-assistant/discussions/1139", "multi_instance": false, "builtin": false, - "load_by_default": true + "load_by_default": true, + "icon": "dlna" } diff --git a/music_assistant/server/providers/fanarttv/manifest.json b/music_assistant/server/providers/fanarttv/manifest.json index 092c1227..fcac306e 100644 --- a/music_assistant/server/providers/fanarttv/manifest.json +++ b/music_assistant/server/providers/fanarttv/manifest.json @@ -9,5 +9,5 @@ "multi_instance": false, "builtin": true, "load_by_default": true, - "icon": "mdi-folder-information" + "icon": "folder-information" } diff --git a/music_assistant/server/providers/filesystem_local/manifest.json b/music_assistant/server/providers/filesystem_local/manifest.json index 16ad423a..5f8a6a29 100644 --- a/music_assistant/server/providers/filesystem_local/manifest.json +++ b/music_assistant/server/providers/filesystem_local/manifest.json @@ -7,5 +7,5 @@ "requirements": [], "documentation": "https://github.com/music-assistant/hass-music-assistant/discussions/820", "multi_instance": true, - "icon": "mdi:mdi-harddisk" + "icon": "harddisk" } diff --git a/music_assistant/server/providers/filesystem_smb/manifest.json b/music_assistant/server/providers/filesystem_smb/manifest.json index 4566279e..88981a6d 100644 --- a/music_assistant/server/providers/filesystem_smb/manifest.json +++ b/music_assistant/server/providers/filesystem_smb/manifest.json @@ -7,5 +7,5 @@ "requirements": [], "documentation": "https://github.com/music-assistant/hass-music-assistant/discussions/820", "multi_instance": true, - "icon": "mdi:mdi-network" + "icon": "network" } diff --git a/music_assistant/server/providers/musicbrainz/icon.svg b/music_assistant/server/providers/musicbrainz/icon.svg new file mode 100644 index 00000000..fde0f687 --- /dev/null +++ b/music_assistant/server/providers/musicbrainz/icon.svg @@ -0,0 +1 @@ +MusicBrainz diff --git a/music_assistant/server/providers/musicbrainz/icon_dark.svg b/music_assistant/server/providers/musicbrainz/icon_dark.svg new file mode 100644 index 00000000..249e9ada --- /dev/null +++ b/music_assistant/server/providers/musicbrainz/icon_dark.svg @@ -0,0 +1,16 @@ + + + + + + + + + +MusicBrainz icon + + + + + + diff --git a/music_assistant/server/providers/plex/icon.png b/music_assistant/server/providers/plex/icon.png deleted file mode 100644 index 85bf53fe..00000000 Binary files a/music_assistant/server/providers/plex/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/plex/icon.svg b/music_assistant/server/providers/plex/icon.svg new file mode 100644 index 00000000..7c994b84 --- /dev/null +++ b/music_assistant/server/providers/plex/icon.svg @@ -0,0 +1,4 @@ + diff --git a/music_assistant/server/providers/qobuz/icon.png b/music_assistant/server/providers/qobuz/icon.png deleted file mode 100644 index 9d7b726c..00000000 Binary files a/music_assistant/server/providers/qobuz/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/qobuz/icon.svg b/music_assistant/server/providers/qobuz/icon.svg new file mode 100755 index 00000000..38d3349f --- /dev/null +++ b/music_assistant/server/providers/qobuz/icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/music_assistant/server/providers/qobuz/icon_dark.svg b/music_assistant/server/providers/qobuz/icon_dark.svg new file mode 100755 index 00000000..2fc68c88 --- /dev/null +++ b/music_assistant/server/providers/qobuz/icon_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/music_assistant/server/providers/radiobrowser/icon.png b/music_assistant/server/providers/radiobrowser/icon.png deleted file mode 100644 index 20672a23..00000000 Binary files a/music_assistant/server/providers/radiobrowser/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/radiobrowser/manifest.json b/music_assistant/server/providers/radiobrowser/manifest.json index e2760875..6e00344e 100644 --- a/music_assistant/server/providers/radiobrowser/manifest.json +++ b/music_assistant/server/providers/radiobrowser/manifest.json @@ -6,5 +6,6 @@ "codeowners": ["@gieljnssns"], "requirements": ["git+https://github.com/gieljnssns/python-radios.git@main"], "documentation": "https://github.com/orgs/music-assistant/discussions/1202", - "multi_instance": false + "multi_instance": false, + "icon": "radio" } diff --git a/music_assistant/server/providers/slimproto/cli.py b/music_assistant/server/providers/slimproto/cli.py index 0e172ff3..bc3232d3 100644 --- a/music_assistant/server/providers/slimproto/cli.py +++ b/music_assistant/server/providers/slimproto/cli.py @@ -745,7 +745,7 @@ class LmsCli: players.append(player_item_from_mass(start_index + index, mass_player)) return ServerStatusResponse( { - "httpport": self.mass.streams.port, + "httpport": self.mass.streams.publish_port, "ip": self.mass.streams.publish_ip, "version": "7.999.999", "uuid": self.mass.server_id, diff --git a/music_assistant/server/providers/slimproto/icon.png b/music_assistant/server/providers/slimproto/icon.png deleted file mode 100644 index 18531d79..00000000 Binary files a/music_assistant/server/providers/slimproto/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/slimproto/icon.svg b/music_assistant/server/providers/slimproto/icon.svg new file mode 100755 index 00000000..20dc9b94 --- /dev/null +++ b/music_assistant/server/providers/slimproto/icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/music_assistant/server/providers/sonos/icon.png b/music_assistant/server/providers/sonos/icon.png deleted file mode 100644 index d00f12ac..00000000 Binary files a/music_assistant/server/providers/sonos/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/sonos/icon.svg b/music_assistant/server/providers/sonos/icon.svg new file mode 100644 index 00000000..60d9e677 --- /dev/null +++ b/music_assistant/server/providers/sonos/icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/music_assistant/server/providers/soundcloud/icon.png b/music_assistant/server/providers/soundcloud/icon.png deleted file mode 100644 index e9dde20b..00000000 Binary files a/music_assistant/server/providers/soundcloud/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/soundcloud/icon.svg b/music_assistant/server/providers/soundcloud/icon.svg new file mode 100644 index 00000000..446f2a1c --- /dev/null +++ b/music_assistant/server/providers/soundcloud/icon.svg @@ -0,0 +1 @@ + diff --git a/music_assistant/server/providers/spotify/icon.png b/music_assistant/server/providers/spotify/icon.png deleted file mode 100644 index 1ed40491..00000000 Binary files a/music_assistant/server/providers/spotify/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/spotify/icon.svg b/music_assistant/server/providers/spotify/icon.svg new file mode 100644 index 00000000..843cf994 --- /dev/null +++ b/music_assistant/server/providers/spotify/icon.svg @@ -0,0 +1 @@ + diff --git a/music_assistant/server/providers/theaudiodb/manifest.json b/music_assistant/server/providers/theaudiodb/manifest.json index 832c4a5b..43e7cf22 100644 --- a/music_assistant/server/providers/theaudiodb/manifest.json +++ b/music_assistant/server/providers/theaudiodb/manifest.json @@ -9,5 +9,5 @@ "multi_instance": false, "builtin": true, "load_by_default": true, - "icon": "mdi-folder-information" + "icon": "folder-information" } diff --git a/music_assistant/server/providers/tidal/icon.png b/music_assistant/server/providers/tidal/icon.png deleted file mode 100644 index 917bb964..00000000 Binary files a/music_assistant/server/providers/tidal/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/tidal/icon.svg b/music_assistant/server/providers/tidal/icon.svg new file mode 100755 index 00000000..8bf8e023 --- /dev/null +++ b/music_assistant/server/providers/tidal/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/music_assistant/server/providers/tidal/icon_dark.svg b/music_assistant/server/providers/tidal/icon_dark.svg new file mode 100755 index 00000000..889198f7 --- /dev/null +++ b/music_assistant/server/providers/tidal/icon_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/music_assistant/server/providers/tunein/icon.png b/music_assistant/server/providers/tunein/icon.png deleted file mode 100644 index 18c537c3..00000000 Binary files a/music_assistant/server/providers/tunein/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/tunein/icon.svg b/music_assistant/server/providers/tunein/icon.svg new file mode 100644 index 00000000..55cc9fee --- /dev/null +++ b/music_assistant/server/providers/tunein/icon.svg @@ -0,0 +1,4 @@ + diff --git a/music_assistant/server/providers/ugp/manifest.json b/music_assistant/server/providers/ugp/manifest.json index c8b38de3..a2aeccea 100644 --- a/music_assistant/server/providers/ugp/manifest.json +++ b/music_assistant/server/providers/ugp/manifest.json @@ -9,5 +9,5 @@ "multi_instance": false, "builtin": false, "load_by_default": false, - "icon": "mdi:mdi-speaker-multiple" + "icon": "speaker-multiple" } diff --git a/music_assistant/server/providers/url/manifest.json b/music_assistant/server/providers/url/manifest.json index 4a68a459..3658a1db 100644 --- a/music_assistant/server/providers/url/manifest.json +++ b/music_assistant/server/providers/url/manifest.json @@ -10,5 +10,5 @@ "builtin": true, "hidden": true, "load_by_default": true, - "icon": "mdi:mdi-web" + "icon": "web" } diff --git a/music_assistant/server/providers/ytmusic/icon.png b/music_assistant/server/providers/ytmusic/icon.png deleted file mode 100644 index cf6726df..00000000 Binary files a/music_assistant/server/providers/ytmusic/icon.png and /dev/null differ diff --git a/music_assistant/server/providers/ytmusic/icon.svg b/music_assistant/server/providers/ytmusic/icon.svg new file mode 100755 index 00000000..22ba913e --- /dev/null +++ b/music_assistant/server/providers/ytmusic/icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/music_assistant/server/server.py b/music_assistant/server/server.py index 04929840..99e79b09 100644 --- a/music_assistant/server/server.py +++ b/music_assistant/server/server.py @@ -24,6 +24,7 @@ from music_assistant.constants import ( API_SCHEMA_VERSION, CONF_PROVIDERS, CONF_SERVER_ID, + CONFIGURABLE_CORE_CONTROLLERS, MIN_SCHEMA_VERSION, ROOT_LOGGER_NAME, ) @@ -48,6 +49,8 @@ from .models import ProviderInstanceType if TYPE_CHECKING: from types import TracebackType + from music_assistant.server.models.core_controller import CoreController + EventCallBackType = Callable[[MassEvent], None] EventSubscriptionType = tuple[ EventCallBackType, tuple[EventType, ...] | None, tuple[str, ...] | None @@ -86,7 +89,7 @@ class MusicAssistant: # we dynamically register command handlers which can be consumed by the apis self.command_handlers: dict[str, APICommandHandler] = {} self._subscribers: set[EventSubscriptionType] = set() - self._available_providers: dict[str, ProviderManifest] = {} + self._provider_manifests: dict[str, ProviderManifest] = {} self._providers: dict[str, ProviderInstanceType] = {} self._tracked_tasks: dict[str, asyncio.Task] = {} self.closing = False @@ -122,6 +125,10 @@ class MusicAssistant: self.players = PlayerController(self) self.player_queues = PlayerQueuesController(self) self.streams = StreamsController(self) + # add manifests for core controllers + for controller_name in CONFIGURABLE_CORE_CONTROLLERS: + controller: CoreController = getattr(self, controller_name) + self._provider_manifests[controller.domain] = controller.manifest await self.cache.setup(await self.config.get_core_config("cache")) await self.webserver.setup(await self.config.get_core_config("webserver")) await self.music.setup(await self.config.get_core_config("music")) @@ -181,10 +188,10 @@ class MusicAssistant: homeassistant_addon=self.running_as_hass_addon, ) - @api_command("providers/available") - def get_available_providers(self) -> list[ProviderManifest]: - """Return all available Providers.""" - return list(self._available_providers.values()) + @api_command("providers/manifests") + def get_provider_manifests(self) -> list[ProviderManifest]: + """Return all Provider manifests.""" + return list(self._provider_manifests.values()) @api_command("providers") def get_providers( @@ -356,7 +363,7 @@ class MusicAssistant: raise SetupFailedError("Configuration is invalid") from err domain = conf.domain - prov_manifest = self._available_providers.get(domain) + prov_manifest = self._provider_manifests.get(domain) # check for other instances of this provider existing = next((x for x in self.providers if x.domain == domain), None) if existing and not prov_manifest.multi_instance: @@ -437,10 +444,10 @@ class MusicAssistant: async def _load_providers(self) -> None: """Load providers from config.""" # load all available providers from manifest files - await self.__load_available_providers() + await self.__load_provider_manifests() # create default config for any 'load_by_default' providers (e.g. URL provider) - for prov_manifest in self._available_providers.values(): + for prov_manifest in self._provider_manifests.values(): if not prov_manifest.load_by_default: continue await self.config.create_default_provider_config(prov_manifest.domain) @@ -469,7 +476,7 @@ class MusicAssistant: continue tg.create_task(load_provider(prov_conf)) - async def __load_available_providers(self) -> None: + async def __load_provider_manifests(self) -> None: """Preload all available provider manifest files.""" for dir_str in os.listdir(PROVIDERS_PATH): dir_path = os.path.join(PROVIDERS_PATH, dir_str) @@ -484,21 +491,17 @@ class MusicAssistant: continue try: provider_manifest = await ProviderManifest.parse(file_path) - # check for icon file - if not provider_manifest.icon: - for icon_file in ("icon.svg", "icon.png"): - icon_path = os.path.join(dir_path, icon_file) - if os.path.isfile(icon_path): - provider_manifest.icon = await get_icon_string(icon_path) - break + # check for icon.svg file + if not provider_manifest.icon_svg: + icon_path = os.path.join(dir_path, "icon.svg") + if os.path.isfile(icon_path): + provider_manifest.icon_svg = await get_icon_string(icon_path) # 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 + if not provider_manifest.icon_svg_dark: + icon_path = os.path.join(dir_path, "icon_dark.svg") + if os.path.isfile(icon_path): + provider_manifest.icon_svg_dark = await get_icon_string(icon_path) + self._provider_manifests[provider_manifest.domain] = provider_manifest LOGGER.debug("Loaded manifest for provider %s", dir_str) except Exception as exc: # pylint: disable=broad-except LOGGER.exception(