mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Support browsing multiple Spotify accounts (#66256)
* Support browsing multiple Spotify accounts * Fix rebase mistakes * Address review comments * Return root spotify node with config entries as children * Add util to get spotify URI for media browser URL * Only support browsing spotify with config entry specified
This commit is contained in:
parent
370832f527
commit
dbd26c7faf
@ -30,7 +30,11 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda
|
|||||||
from . import config_flow
|
from . import config_flow
|
||||||
from .browse_media import async_browse_media
|
from .browse_media import async_browse_media
|
||||||
from .const import DOMAIN, LOGGER, SPOTIFY_SCOPES
|
from .const import DOMAIN, LOGGER, SPOTIFY_SCOPES
|
||||||
from .util import is_spotify_media_type, resolve_spotify_media_type
|
from .util import (
|
||||||
|
is_spotify_media_type,
|
||||||
|
resolve_spotify_media_type,
|
||||||
|
spotify_uri_from_media_browser_url,
|
||||||
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
CONFIG_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
@ -50,6 +54,7 @@ PLATFORMS = [Platform.MEDIA_PLAYER]
|
|||||||
__all__ = [
|
__all__ = [
|
||||||
"async_browse_media",
|
"async_browse_media",
|
||||||
"DOMAIN",
|
"DOMAIN",
|
||||||
|
"spotify_uri_from_media_browser_url",
|
||||||
"is_spotify_media_type",
|
"is_spotify_media_type",
|
||||||
"resolve_spotify_media_type",
|
"resolve_spotify_media_type",
|
||||||
]
|
]
|
||||||
|
@ -6,11 +6,13 @@ import logging
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from spotipy import Spotify
|
from spotipy import Spotify
|
||||||
|
import yarl
|
||||||
|
|
||||||
from homeassistant.backports.enum import StrEnum
|
from homeassistant.backports.enum import StrEnum
|
||||||
from homeassistant.components.media_player import BrowseError, BrowseMedia
|
from homeassistant.components.media_player import BrowseError, BrowseMedia
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
MEDIA_CLASS_ALBUM,
|
MEDIA_CLASS_ALBUM,
|
||||||
|
MEDIA_CLASS_APP,
|
||||||
MEDIA_CLASS_ARTIST,
|
MEDIA_CLASS_ARTIST,
|
||||||
MEDIA_CLASS_DIRECTORY,
|
MEDIA_CLASS_DIRECTORY,
|
||||||
MEDIA_CLASS_EPISODE,
|
MEDIA_CLASS_EPISODE,
|
||||||
@ -137,15 +139,53 @@ class UnknownMediaType(BrowseError):
|
|||||||
|
|
||||||
async def async_browse_media(
|
async def async_browse_media(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
media_content_type: str,
|
media_content_type: str | None,
|
||||||
media_content_id: str,
|
media_content_id: str | None,
|
||||||
*,
|
*,
|
||||||
can_play_artist: bool = True,
|
can_play_artist: bool = True,
|
||||||
) -> BrowseMedia:
|
) -> BrowseMedia:
|
||||||
"""Browse Spotify media."""
|
"""Browse Spotify media."""
|
||||||
if not (info := next(iter(hass.data[DOMAIN].values()), None)):
|
parsed_url = None
|
||||||
raise BrowseError("No Spotify accounts available")
|
info = None
|
||||||
return await async_browse_media_internal(
|
|
||||||
|
# Check if caller is requesting the root nodes
|
||||||
|
if media_content_type is None and media_content_id is None:
|
||||||
|
children = []
|
||||||
|
for config_entry_id, info in hass.data[DOMAIN].items():
|
||||||
|
config_entry = hass.config_entries.async_get_entry(config_entry_id)
|
||||||
|
assert config_entry is not None
|
||||||
|
children.append(
|
||||||
|
BrowseMedia(
|
||||||
|
title=config_entry.title,
|
||||||
|
media_class=MEDIA_CLASS_APP,
|
||||||
|
media_content_id=f"{MEDIA_PLAYER_PREFIX}{config_entry_id}",
|
||||||
|
media_content_type=f"{MEDIA_PLAYER_PREFIX}library",
|
||||||
|
thumbnail="https://brands.home-assistant.io/_/spotify/logo.png",
|
||||||
|
can_play=False,
|
||||||
|
can_expand=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return BrowseMedia(
|
||||||
|
title="Spotify",
|
||||||
|
media_class=MEDIA_CLASS_APP,
|
||||||
|
media_content_id=MEDIA_PLAYER_PREFIX,
|
||||||
|
media_content_type="spotify",
|
||||||
|
thumbnail="https://brands.home-assistant.io/_/spotify/logo.png",
|
||||||
|
can_play=False,
|
||||||
|
can_expand=True,
|
||||||
|
children=children,
|
||||||
|
)
|
||||||
|
|
||||||
|
if media_content_id is None or not media_content_id.startswith(MEDIA_PLAYER_PREFIX):
|
||||||
|
raise BrowseError("Invalid Spotify URL specified")
|
||||||
|
|
||||||
|
# Check for config entry specifier, and extract Spotify URI
|
||||||
|
parsed_url = yarl.URL(media_content_id)
|
||||||
|
if (info := hass.data[DOMAIN].get(parsed_url.host)) is None:
|
||||||
|
raise BrowseError("Invalid Spotify account specified")
|
||||||
|
media_content_id = parsed_url.name
|
||||||
|
|
||||||
|
result = await async_browse_media_internal(
|
||||||
hass,
|
hass,
|
||||||
info.client,
|
info.client,
|
||||||
info.session,
|
info.session,
|
||||||
@ -155,6 +195,13 @@ async def async_browse_media(
|
|||||||
can_play_artist=can_play_artist,
|
can_play_artist=can_play_artist,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Build new URLs with config entry specifyers
|
||||||
|
result.media_content_id = str(parsed_url.with_name(result.media_content_id))
|
||||||
|
if result.children:
|
||||||
|
for child in result.children:
|
||||||
|
child.media_content_id = str(parsed_url.with_name(child.media_content_id))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
async def async_browse_media_internal(
|
async def async_browse_media_internal(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
@ -3,6 +3,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
import yarl
|
||||||
|
|
||||||
from .const import MEDIA_PLAYER_PREFIX
|
from .const import MEDIA_PLAYER_PREFIX
|
||||||
|
|
||||||
|
|
||||||
@ -22,3 +24,11 @@ def fetch_image_url(item: dict[str, Any], key="images") -> str | None:
|
|||||||
return item.get(key, [])[0].get("url")
|
return item.get(key, [])[0].get("url")
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def spotify_uri_from_media_browser_url(media_content_id: str) -> str:
|
||||||
|
"""Extract spotify URI from media browser URL."""
|
||||||
|
if media_content_id and media_content_id.startswith(MEDIA_PLAYER_PREFIX):
|
||||||
|
parsed_url = yarl.URL(media_content_id)
|
||||||
|
media_content_id = parsed_url.name
|
||||||
|
return media_content_id
|
||||||
|
Loading…
x
Reference in New Issue
Block a user