mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Clean up Sonos attributes for radio streams (#33063)
This commit is contained in:
parent
5893f6b14b
commit
699ca44260
@ -336,6 +336,7 @@ homeassistant/components/solax/* @squishykid
|
|||||||
homeassistant/components/soma/* @ratsept
|
homeassistant/components/soma/* @ratsept
|
||||||
homeassistant/components/somfy/* @tetienne
|
homeassistant/components/somfy/* @tetienne
|
||||||
homeassistant/components/songpal/* @rytilahti
|
homeassistant/components/songpal/* @rytilahti
|
||||||
|
homeassistant/components/sonos/* @amelchio
|
||||||
homeassistant/components/spaceapi/* @fabaff
|
homeassistant/components/spaceapi/* @fabaff
|
||||||
homeassistant/components/speedtestdotnet/* @rohankapoorcom
|
homeassistant/components/speedtestdotnet/* @rohankapoorcom
|
||||||
homeassistant/components/spider/* @peternijssen
|
homeassistant/components/spider/* @peternijssen
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
"name": "Sonos",
|
"name": "Sonos",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/sonos",
|
"documentation": "https://www.home-assistant.io/integrations/sonos",
|
||||||
"requirements": ["pysonos==0.0.24"],
|
"requirements": ["pysonos==0.0.25"],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
"st": "urn:schemas-upnp-org:device:ZonePlayer:1"
|
"st": "urn:schemas-upnp-org:device:ZonePlayer:1"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"codeowners": []
|
"codeowners": ["@amelchio"]
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,12 @@ import datetime
|
|||||||
import functools as ft
|
import functools as ft
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
import urllib
|
|
||||||
|
|
||||||
import async_timeout
|
import async_timeout
|
||||||
import pysonos
|
import pysonos
|
||||||
from pysonos import alarms
|
from pysonos import alarms
|
||||||
from pysonos.exceptions import SoCoException, SoCoUPnPException
|
from pysonos.exceptions import SoCoException, SoCoUPnPException
|
||||||
|
import pysonos.music_library
|
||||||
import pysonos.snapshot
|
import pysonos.snapshot
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -338,19 +338,6 @@ def _timespan_secs(timespan):
|
|||||||
return sum(60 ** x[0] * int(x[1]) for x in enumerate(reversed(timespan.split(":"))))
|
return sum(60 ** x[0] * int(x[1]) for x in enumerate(reversed(timespan.split(":"))))
|
||||||
|
|
||||||
|
|
||||||
def _is_radio_uri(uri):
|
|
||||||
"""Return whether the URI is a stream (not a playlist)."""
|
|
||||||
radio_schemes = (
|
|
||||||
"x-rincon-mp3radio:",
|
|
||||||
"x-sonosapi-stream:",
|
|
||||||
"x-sonosapi-radio:",
|
|
||||||
"x-sonosapi-hls:",
|
|
||||||
"hls-radio:",
|
|
||||||
"x-rincon-stream:",
|
|
||||||
)
|
|
||||||
return uri.startswith(radio_schemes)
|
|
||||||
|
|
||||||
|
|
||||||
class SonosEntity(MediaPlayerDevice):
|
class SonosEntity(MediaPlayerDevice):
|
||||||
"""Representation of a Sonos entity."""
|
"""Representation of a Sonos entity."""
|
||||||
|
|
||||||
@ -515,17 +502,6 @@ class SonosEntity(MediaPlayerDevice):
|
|||||||
# Skip unknown types
|
# Skip unknown types
|
||||||
_LOGGER.error("Unhandled favorite '%s': %s", fav.title, ex)
|
_LOGGER.error("Unhandled favorite '%s': %s", fav.title, ex)
|
||||||
|
|
||||||
def _radio_artwork(self, url):
|
|
||||||
"""Return the private URL with artwork for a radio stream."""
|
|
||||||
if url in UNAVAILABLE_VALUES:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if url.find("tts_proxy") > 0:
|
|
||||||
# If the content is a tts don't try to fetch an image from it.
|
|
||||||
return None
|
|
||||||
|
|
||||||
return f"http://{self.soco.ip_address}:1400/getaa?s=1&u={urllib.parse.quote(url, safe='')}"
|
|
||||||
|
|
||||||
def _attach_player(self):
|
def _attach_player(self):
|
||||||
"""Get basic information and add event subscriptions."""
|
"""Get basic information and add event subscriptions."""
|
||||||
try:
|
try:
|
||||||
@ -576,6 +552,14 @@ class SonosEntity(MediaPlayerDevice):
|
|||||||
|
|
||||||
self._shuffle = self.soco.shuffle
|
self._shuffle = self.soco.shuffle
|
||||||
self._uri = None
|
self._uri = None
|
||||||
|
self._media_duration = None
|
||||||
|
self._media_position = None
|
||||||
|
self._media_position_updated_at = None
|
||||||
|
self._media_image_url = None
|
||||||
|
self._media_artist = None
|
||||||
|
self._media_album_name = None
|
||||||
|
self._media_title = None
|
||||||
|
self._source_name = None
|
||||||
|
|
||||||
update_position = new_status != self._status
|
update_position = new_status != self._status
|
||||||
self._status = new_status
|
self._status = new_status
|
||||||
@ -587,8 +571,11 @@ class SonosEntity(MediaPlayerDevice):
|
|||||||
else:
|
else:
|
||||||
track_info = self.soco.get_current_track_info()
|
track_info = self.soco.get_current_track_info()
|
||||||
self._uri = track_info["uri"]
|
self._uri = track_info["uri"]
|
||||||
|
self._media_artist = track_info.get("artist")
|
||||||
|
self._media_album_name = track_info.get("album")
|
||||||
|
self._media_title = track_info.get("title")
|
||||||
|
|
||||||
if _is_radio_uri(track_info["uri"]):
|
if self.soco.is_radio_uri(track_info["uri"]):
|
||||||
variables = event and event.variables
|
variables = event and event.variables
|
||||||
self.update_media_radio(variables, track_info)
|
self.update_media_radio(variables, track_info)
|
||||||
else:
|
else:
|
||||||
@ -604,74 +591,29 @@ class SonosEntity(MediaPlayerDevice):
|
|||||||
|
|
||||||
def update_media_linein(self, source):
|
def update_media_linein(self, source):
|
||||||
"""Update state when playing from line-in/tv."""
|
"""Update state when playing from line-in/tv."""
|
||||||
self._media_duration = None
|
|
||||||
self._media_position = None
|
|
||||||
self._media_position_updated_at = None
|
|
||||||
|
|
||||||
self._media_image_url = None
|
|
||||||
|
|
||||||
self._media_artist = None
|
|
||||||
self._media_album_name = None
|
|
||||||
self._media_title = source
|
self._media_title = source
|
||||||
|
|
||||||
self._source_name = source
|
self._source_name = source
|
||||||
|
|
||||||
def update_media_radio(self, variables, track_info):
|
def update_media_radio(self, variables, track_info):
|
||||||
"""Update state when streaming radio."""
|
"""Update state when streaming radio."""
|
||||||
self._media_duration = None
|
try:
|
||||||
self._media_position = None
|
library = pysonos.music_library.MusicLibrary(self.soco)
|
||||||
self._media_position_updated_at = None
|
album_art_uri = variables["current_track_meta_data"].album_art_uri
|
||||||
|
self._media_image_url = library.build_album_art_full_uri(album_art_uri)
|
||||||
|
except (TypeError, KeyError, AttributeError):
|
||||||
|
pass
|
||||||
|
|
||||||
media_info = self.soco.avTransport.GetMediaInfo([("InstanceID", 0)])
|
# Radios without tagging can have the radio URI as title. Non-playing
|
||||||
self._media_image_url = self._radio_artwork(media_info["CurrentURI"])
|
# radios will not have a current title. In these cases we try to use
|
||||||
|
# the radio name instead.
|
||||||
self._media_artist = track_info.get("artist")
|
try:
|
||||||
self._media_album_name = None
|
if self.soco.is_radio_uri(self._media_title) or self.state != STATE_PLAYING:
|
||||||
self._media_title = track_info.get("title")
|
self._media_title = variables["enqueued_transport_uri_meta_data"].title
|
||||||
|
except (TypeError, KeyError, AttributeError):
|
||||||
if self._media_artist and self._media_title:
|
pass
|
||||||
# artist and album name are in the data, concatenate
|
|
||||||
# that do display as artist.
|
|
||||||
# "Information" field in the sonos pc app
|
|
||||||
self._media_artist = "{artist} - {title}".format(
|
|
||||||
artist=self._media_artist, title=self._media_title
|
|
||||||
)
|
|
||||||
elif variables:
|
|
||||||
# "On Now" field in the sonos pc app
|
|
||||||
current_track_metadata = variables.get("current_track_meta_data")
|
|
||||||
if current_track_metadata:
|
|
||||||
self._media_artist = current_track_metadata.radio_show.split(",")[0]
|
|
||||||
|
|
||||||
# For radio streams we set the radio station name as the title.
|
|
||||||
current_uri_metadata = media_info["CurrentURIMetaData"]
|
|
||||||
if current_uri_metadata not in UNAVAILABLE_VALUES:
|
|
||||||
# currently soco does not have an API for this
|
|
||||||
current_uri_metadata = pysonos.xml.XML.fromstring(
|
|
||||||
pysonos.utils.really_utf8(current_uri_metadata)
|
|
||||||
)
|
|
||||||
|
|
||||||
md_title = current_uri_metadata.findtext(
|
|
||||||
".//{http://purl.org/dc/elements/1.1/}title"
|
|
||||||
)
|
|
||||||
|
|
||||||
if md_title not in UNAVAILABLE_VALUES:
|
|
||||||
self._media_title = md_title
|
|
||||||
|
|
||||||
if self._media_artist and self._media_title:
|
|
||||||
# some radio stations put their name into the artist
|
|
||||||
# name, e.g.:
|
|
||||||
# media_title = "Station"
|
|
||||||
# media_artist = "Station - Artist - Title"
|
|
||||||
# detect this case and trim from the front of
|
|
||||||
# media_artist for cosmetics
|
|
||||||
trim = f"{self._media_title} - "
|
|
||||||
chars = min(len(self._media_artist), len(trim))
|
|
||||||
|
|
||||||
if self._media_artist[:chars].upper() == trim[:chars].upper():
|
|
||||||
self._media_artist = self._media_artist[chars:]
|
|
||||||
|
|
||||||
# Check if currently playing radio station is in favorites
|
# Check if currently playing radio station is in favorites
|
||||||
self._source_name = None
|
media_info = self.soco.avTransport.GetMediaInfo([("InstanceID", 0)])
|
||||||
for fav in self._favorites:
|
for fav in self._favorites:
|
||||||
if fav.reference.get_uri() == media_info["CurrentURI"]:
|
if fav.reference.get_uri() == media_info["CurrentURI"]:
|
||||||
self._source_name = fav.title
|
self._source_name = fav.title
|
||||||
@ -710,12 +652,6 @@ class SonosEntity(MediaPlayerDevice):
|
|||||||
|
|
||||||
self._media_image_url = track_info.get("album_art")
|
self._media_image_url = track_info.get("album_art")
|
||||||
|
|
||||||
self._media_artist = track_info.get("artist")
|
|
||||||
self._media_album_name = track_info.get("album")
|
|
||||||
self._media_title = track_info.get("title")
|
|
||||||
|
|
||||||
self._source_name = None
|
|
||||||
|
|
||||||
def update_volume(self, event=None):
|
def update_volume(self, event=None):
|
||||||
"""Update information about currently volume settings."""
|
"""Update information about currently volume settings."""
|
||||||
if event:
|
if event:
|
||||||
@ -936,7 +872,7 @@ class SonosEntity(MediaPlayerDevice):
|
|||||||
if len(fav) == 1:
|
if len(fav) == 1:
|
||||||
src = fav.pop()
|
src = fav.pop()
|
||||||
uri = src.reference.get_uri()
|
uri = src.reference.get_uri()
|
||||||
if _is_radio_uri(uri):
|
if self.soco.is_radio_uri(uri):
|
||||||
self.soco.play_uri(uri, title=source)
|
self.soco.play_uri(uri, title=source)
|
||||||
else:
|
else:
|
||||||
self.soco.clear_queue()
|
self.soco.clear_queue()
|
||||||
|
@ -1543,7 +1543,7 @@ pysnmp==4.4.12
|
|||||||
pysoma==0.0.10
|
pysoma==0.0.10
|
||||||
|
|
||||||
# homeassistant.components.sonos
|
# homeassistant.components.sonos
|
||||||
pysonos==0.0.24
|
pysonos==0.0.25
|
||||||
|
|
||||||
# homeassistant.components.spc
|
# homeassistant.components.spc
|
||||||
pyspcwebgw==0.4.0
|
pyspcwebgw==0.4.0
|
||||||
|
@ -583,7 +583,7 @@ pysmartthings==0.7.0
|
|||||||
pysoma==0.0.10
|
pysoma==0.0.10
|
||||||
|
|
||||||
# homeassistant.components.sonos
|
# homeassistant.components.sonos
|
||||||
pysonos==0.0.24
|
pysonos==0.0.25
|
||||||
|
|
||||||
# homeassistant.components.spc
|
# homeassistant.components.spc
|
||||||
pyspcwebgw==0.4.0
|
pyspcwebgw==0.4.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user