Reduce Spotify API usage (#66315)

This commit is contained in:
Franck Nijhof 2022-02-11 22:16:41 +01:00 committed by GitHub
parent 2e6ee5165e
commit caedef5f1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 8 deletions

View File

@ -1,6 +1,11 @@
"""The spotify integration.""" """The spotify integration."""
from __future__ import annotations
from datetime import timedelta
from typing import Any
import aiohttp import aiohttp
import requests
from spotipy import Spotify, SpotifyException from spotipy import Spotify, SpotifyException
import voluptuous as vol import voluptuous as vol
@ -20,13 +25,16 @@ from homeassistant.helpers.config_entry_oauth2_flow import (
async_get_config_entry_implementation, async_get_config_entry_implementation,
) )
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from . import config_flow from . import config_flow
from .const import ( from .const import (
DATA_SPOTIFY_CLIENT, DATA_SPOTIFY_CLIENT,
DATA_SPOTIFY_DEVICES,
DATA_SPOTIFY_ME, DATA_SPOTIFY_ME,
DATA_SPOTIFY_SESSION, DATA_SPOTIFY_SESSION,
DOMAIN, DOMAIN,
LOGGER,
MEDIA_PLAYER_PREFIX, MEDIA_PLAYER_PREFIX,
SPOTIFY_SCOPES, SPOTIFY_SCOPES,
) )
@ -112,9 +120,34 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
except SpotifyException as err: except SpotifyException as err:
raise ConfigEntryNotReady from err raise ConfigEntryNotReady from err
async def _update_devices() -> list[dict[str, Any]]:
try:
devices: dict[str, Any] | None = await hass.async_add_executor_job(
spotify.devices
)
except (requests.RequestException, SpotifyException) as err:
raise UpdateFailed from err
if devices is None:
return []
return devices.get("devices", [])
device_coordinator: DataUpdateCoordinator[
list[dict[str, Any]]
] = DataUpdateCoordinator(
hass,
LOGGER,
name=f"{entry.title} Devices",
update_interval=timedelta(minutes=5),
update_method=_update_devices,
)
await device_coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = { hass.data[DOMAIN][entry.entry_id] = {
DATA_SPOTIFY_CLIENT: spotify, DATA_SPOTIFY_CLIENT: spotify,
DATA_SPOTIFY_DEVICES: device_coordinator,
DATA_SPOTIFY_ME: current_user, DATA_SPOTIFY_ME: current_user,
DATA_SPOTIFY_SESSION: session, DATA_SPOTIFY_SESSION: session,
} }

View File

@ -1,8 +1,13 @@
"""Define constants for the Spotify integration.""" """Define constants for the Spotify integration."""
import logging
DOMAIN = "spotify" DOMAIN = "spotify"
LOGGER = logging.getLogger(__package__)
DATA_SPOTIFY_CLIENT = "spotify_client" DATA_SPOTIFY_CLIENT = "spotify_client"
DATA_SPOTIFY_DEVICES = "spotify_devices"
DATA_SPOTIFY_ME = "spotify_me" DATA_SPOTIFY_ME = "spotify_me"
DATA_SPOTIFY_SESSION = "spotify_session" DATA_SPOTIFY_SESSION = "spotify_session"

View File

@ -52,7 +52,7 @@ from homeassistant.const import (
STATE_PAUSED, STATE_PAUSED,
STATE_PLAYING, STATE_PLAYING,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session
from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.device_registry import DeviceEntryType
@ -62,6 +62,7 @@ from homeassistant.util.dt import utc_from_timestamp
from .const import ( from .const import (
DATA_SPOTIFY_CLIENT, DATA_SPOTIFY_CLIENT,
DATA_SPOTIFY_DEVICES,
DATA_SPOTIFY_ME, DATA_SPOTIFY_ME,
DATA_SPOTIFY_SESSION, DATA_SPOTIFY_SESSION,
DOMAIN, DOMAIN,
@ -269,7 +270,6 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
) )
self._currently_playing: dict | None = {} self._currently_playing: dict | None = {}
self._devices: list[dict] | None = []
self._playlist: dict | None = None self._playlist: dict | None = None
self._attr_name = self._name self._attr_name = self._name
@ -290,6 +290,11 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
"""Return spotify API.""" """Return spotify API."""
return self._spotify_data[DATA_SPOTIFY_CLIENT] return self._spotify_data[DATA_SPOTIFY_CLIENT]
@property
def _devices(self) -> list:
"""Return spotify devices."""
return self._spotify_data[DATA_SPOTIFY_DEVICES].data
@property @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo:
"""Return device information about this entity.""" """Return device information about this entity."""
@ -517,14 +522,14 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
current = self._spotify.current_playback() current = self._spotify.current_playback()
self._currently_playing = current or {} self._currently_playing = current or {}
self._playlist = None
context = self._currently_playing.get("context") context = self._currently_playing.get("context")
if context is not None and context["type"] == MEDIA_TYPE_PLAYLIST: if context is not None and (
self._playlist is None or self._playlist["uri"] != context["uri"]
):
self._playlist = None
if context["type"] == MEDIA_TYPE_PLAYLIST:
self._playlist = self._spotify.playlist(current["context"]["uri"]) self._playlist = self._spotify.playlist(current["context"]["uri"])
devices = self._spotify.devices() or {}
self._devices = devices.get("devices", [])
async def async_browse_media(self, media_content_type=None, media_content_id=None): async def async_browse_media(self, media_content_type=None, media_content_id=None):
"""Implement the websocket media browsing helper.""" """Implement the websocket media browsing helper."""
@ -543,6 +548,22 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
media_content_id, media_content_id,
) )
@callback
def _handle_devices_update(self) -> None:
"""Handle updated data from the coordinator."""
if not self.enabled:
return
self.async_write_ha_state()
async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
self.async_on_remove(
self._spotify_data[DATA_SPOTIFY_DEVICES].async_add_listener(
self._handle_devices_update
)
)
async def async_browse_media_internal( async def async_browse_media_internal(
hass, hass,