Refactor LastFM to use shorthand attributes (#91606)

* Preliminary PR for the coordinator

* Preliminary PR for the coordinator

* Preliminary PR for the coordinator

* Apply suggestions from code review

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Preliminary PR for the coordinator

* Preliminary PR for the coordinator

* Preliminary PR for the coordinator

* Preliminary PR for the coordinator

* Preliminary PR for the coordinator

* Preliminary PR for the coordinator

* Preliminary PR for the coordinator

* Apply feedback

* Apply feedback

* Apply feedback

* Apply feedback

* Apply feedback

* Update homeassistant/components/lastfm/sensor.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update homeassistant/components/lastfm/sensor.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Apply feedback

* Apply feedback

* Fix tests

* Update homeassistant/components/lastfm/sensor.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Fix tests

* Fix feedback

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
pull/91679/head
Joost Lekkerkerker 2023-04-19 14:13:43 +02:00 committed by GitHub
parent f3e6d6dfc0
commit 88f5f04be8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 76 deletions

View File

@ -3,10 +3,8 @@ from __future__ import annotations
import hashlib
import logging
import re
import pylast as lastfm
from pylast import WSError
from pylast import LastFMNetwork, Track, User, WSError
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
@ -16,7 +14,9 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
_LOGGER = logging.getLogger(__name__)
LOGGER = logging.getLogger(__name__)
CONF_USERS = "users"
ATTR_LAST_PLAYED = "last_played"
ATTR_PLAY_COUNT = "play_count"
@ -24,9 +24,6 @@ ATTR_TOP_PLAYED = "top_played"
STATE_NOT_SCROBBLING = "Not Scrobbling"
CONF_USERS = "users"
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_API_KEY): cv.string,
@ -35,6 +32,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
)
def format_track(track: Track) -> str:
"""Format the track."""
return f"{track.artist} - {track.title}"
def setup_platform(
hass: HomeAssistant,
config: ConfigType,
@ -42,88 +44,46 @@ def setup_platform(
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Last.fm sensor platform."""
api_key = config[CONF_API_KEY]
users = config[CONF_USERS]
lastfm_api = lastfm.LastFMNetwork(api_key=api_key)
lastfm_api = LastFMNetwork(api_key=config[CONF_API_KEY])
entities = []
for username in users:
for username in config[CONF_USERS]:
try:
lastfm_api.get_user(username).get_image()
entities.append(LastfmSensor(username, lastfm_api))
except WSError as error:
_LOGGER.error(error)
user = lastfm_api.get_user(username)
entities.append(LastFmSensor(user, lastfm_api))
except WSError as exc:
LOGGER.error("Failed to load LastFM user `%s`: %r", username, exc)
return
add_entities(entities, True)
class LastfmSensor(SensorEntity):
class LastFmSensor(SensorEntity):
"""A class for the Last.fm account."""
_attr_attribution = "Data provided by Last.fm"
_attr_icon = "mdi:radio-fm"
def __init__(self, user, lastfm_api):
def __init__(self, user: User, lastfm_api: LastFMNetwork) -> None:
"""Initialize the sensor."""
self._unique_id = hashlib.sha256(user.encode("utf-8")).hexdigest()
self._user = lastfm_api.get_user(user)
self._name = user
self._lastfm = lastfm_api
self._state = "Not Scrobbling"
self._playcount = None
self._lastplayed = None
self._topplayed = None
self._cover = None
@property
def unique_id(self):
"""Return the unique ID of the sensor."""
return self._unique_id
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def native_value(self):
"""Return the state of the sensor."""
return self._state
self._attr_unique_id = hashlib.sha256(user.name.encode("utf-8")).hexdigest()
self._attr_name = user.name
self._user = user
def update(self) -> None:
"""Update device state."""
self._cover = self._user.get_image()
self._playcount = self._user.get_playcount()
if recent_tracks := self._user.get_recent_tracks(limit=2):
last = recent_tracks[0]
self._lastplayed = f"{last.track.artist} - {last.track.title}"
self._attr_entity_picture = self._user.get_image()
if now_playing := self._user.get_now_playing():
self._attr_native_value = format_track(now_playing)
else:
self._attr_native_value = STATE_NOT_SCROBBLING
top_played = None
if top_tracks := self._user.get_top_tracks(limit=1):
top = str(top_tracks[0])
if (toptitle := re.search("', '(.+?)',", top)) and (
topartist := re.search("'(.+?)',", top)
):
self._topplayed = f"{topartist.group(1)} - {toptitle.group(1)}"
if (now_playing := self._user.get_now_playing()) is None:
self._state = STATE_NOT_SCROBBLING
return
self._state = f"{now_playing.artist} - {now_playing.title}"
@property
def extra_state_attributes(self):
"""Return the state attributes."""
return {
ATTR_LAST_PLAYED: self._lastplayed,
ATTR_PLAY_COUNT: self._playcount,
ATTR_TOP_PLAYED: self._topplayed,
top_played = format_track(top_tracks[0].item)
last_played = None
if last_tracks := self._user.get_recent_tracks(limit=1):
last_played = format_track(last_tracks[0].track)
play_count = self._user.get_playcount()
self._attr_extra_state_attributes = {
ATTR_LAST_PLAYED: last_played,
ATTR_PLAY_COUNT: play_count,
ATTR_TOP_PLAYED: top_played,
}
@property
def entity_picture(self):
"""Avatar of the user."""
return self._cover

View File

@ -24,6 +24,7 @@ class MockUser:
def __init__(self, now_playing_result):
"""Initialize the mock."""
self._now_playing_result = now_playing_result
self.name = "test"
def get_playcount(self):
"""Get mock play count."""
@ -48,7 +49,9 @@ class MockUser:
@pytest.fixture(name="lastfm_network")
def lastfm_network_fixture():
"""Create fixture for LastFMNetwork."""
with patch("pylast.LastFMNetwork") as lastfm_network:
with patch(
"homeassistant.components.lastfm.sensor.LastFMNetwork"
) as lastfm_network:
yield lastfm_network