diff --git a/homeassistant/components/bang_olufsen/const.py b/homeassistant/components/bang_olufsen/const.py index 95d0aca6ed6..caa4cef8a13 100644 --- a/homeassistant/components/bang_olufsen/const.py +++ b/homeassistant/components/bang_olufsen/const.py @@ -17,14 +17,46 @@ from homeassistant.components.media_player import ( class BangOlufsenSource: """Class used for associating device source ids with friendly names. May not include all sources.""" - URI_STREAMER: Final[Source] = Source(name="Audio Streamer", id="uriStreamer") - BLUETOOTH: Final[Source] = Source(name="Bluetooth", id="bluetooth") - CHROMECAST: Final[Source] = Source(name="Chromecast built-in", id="chromeCast") - LINE_IN: Final[Source] = Source(name="Line-In", id="lineIn") - SPDIF: Final[Source] = Source(name="Optical", id="spdif") - NET_RADIO: Final[Source] = Source(name="B&O Radio", id="netRadio") - DEEZER: Final[Source] = Source(name="Deezer", id="deezer") - TIDAL: Final[Source] = Source(name="Tidal", id="tidal") + URI_STREAMER: Final[Source] = Source( + name="Audio Streamer", + id="uriStreamer", + is_seekable=False, + ) + BLUETOOTH: Final[Source] = Source( + name="Bluetooth", + id="bluetooth", + is_seekable=False, + ) + CHROMECAST: Final[Source] = Source( + name="Chromecast built-in", + id="chromeCast", + is_seekable=False, + ) + LINE_IN: Final[Source] = Source( + name="Line-In", + id="lineIn", + is_seekable=False, + ) + SPDIF: Final[Source] = Source( + name="Optical", + id="spdif", + is_seekable=False, + ) + NET_RADIO: Final[Source] = Source( + name="B&O Radio", + id="netRadio", + is_seekable=False, + ) + DEEZER: Final[Source] = Source( + name="Deezer", + id="deezer", + is_seekable=True, + ) + TIDAL: Final[Source] = Source( + name="Tidal", + id="tidal", + is_seekable=True, + ) BANG_OLUFSEN_STATES: dict[str, MediaPlayerState] = { @@ -162,6 +194,7 @@ FALLBACK_SOURCES: Final[SourceArray] = SourceArray( is_playable=False, name="Audio Streamer", type=SourceTypeEnum(value="uriStreamer"), + is_seekable=False, ), Source( id="bluetooth", @@ -169,6 +202,7 @@ FALLBACK_SOURCES: Final[SourceArray] = SourceArray( is_playable=False, name="Bluetooth", type=SourceTypeEnum(value="bluetooth"), + is_seekable=False, ), Source( id="spotify", @@ -176,6 +210,7 @@ FALLBACK_SOURCES: Final[SourceArray] = SourceArray( is_playable=False, name="Spotify Connect", type=SourceTypeEnum(value="spotify"), + is_seekable=True, ), Source( id="lineIn", @@ -183,6 +218,7 @@ FALLBACK_SOURCES: Final[SourceArray] = SourceArray( is_playable=True, name="Line-In", type=SourceTypeEnum(value="lineIn"), + is_seekable=False, ), Source( id="spdif", @@ -190,6 +226,7 @@ FALLBACK_SOURCES: Final[SourceArray] = SourceArray( is_playable=True, name="Optical", type=SourceTypeEnum(value="spdif"), + is_seekable=False, ), Source( id="netRadio", @@ -197,6 +234,7 @@ FALLBACK_SOURCES: Final[SourceArray] = SourceArray( is_playable=True, name="B&O Radio", type=SourceTypeEnum(value="netRadio"), + is_seekable=False, ), Source( id="deezer", @@ -204,6 +242,7 @@ FALLBACK_SOURCES: Final[SourceArray] = SourceArray( is_playable=True, name="Deezer", type=SourceTypeEnum(value="deezer"), + is_seekable=True, ), Source( id="tidalConnect", @@ -211,6 +250,7 @@ FALLBACK_SOURCES: Final[SourceArray] = SourceArray( is_playable=True, name="Tidal Connect", type=SourceTypeEnum(value="tidalConnect"), + is_seekable=True, ), ] ) diff --git a/homeassistant/components/bang_olufsen/media_player.py b/homeassistant/components/bang_olufsen/media_player.py index 7aedcaeb5db..81190613c3b 100644 --- a/homeassistant/components/bang_olufsen/media_player.py +++ b/homeassistant/components/bang_olufsen/media_player.py @@ -94,7 +94,6 @@ BANG_OLUFSEN_FEATURES = ( | MediaPlayerEntityFeature.PLAY_MEDIA | MediaPlayerEntityFeature.PREVIOUS_TRACK | MediaPlayerEntityFeature.REPEAT_SET - | MediaPlayerEntityFeature.SEEK | MediaPlayerEntityFeature.SELECT_SOURCE | MediaPlayerEntityFeature.STOP | MediaPlayerEntityFeature.TURN_OFF @@ -124,7 +123,6 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): _attr_icon = "mdi:speaker-wireless" _attr_name = None _attr_device_class = MediaPlayerDeviceClass.SPEAKER - _attr_supported_features = BANG_OLUFSEN_FEATURES def __init__(self, entry: ConfigEntry, client: MozartClient) -> None: """Initialize the media player.""" @@ -485,6 +483,17 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): self.async_write_ha_state() + @property + def supported_features(self) -> MediaPlayerEntityFeature: + """Flag media player features that are supported.""" + features = BANG_OLUFSEN_FEATURES + + # Add seeking if supported by the current source + if self._source_change.is_seekable is True: + features |= MediaPlayerEntityFeature.SEEK + + return features + @property def state(self) -> MediaPlayerState: """Return the current state of the media player.""" @@ -631,17 +640,12 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): async def async_media_seek(self, position: float) -> None: """Seek to position in ms.""" - if self._source_change.id == BangOlufsenSource.DEEZER.id: - await self._client.seek_to_position(position_ms=int(position * 1000)) - # Try to prevent the playback progress from bouncing in the UI. - self._attr_media_position_updated_at = utcnow() - self._playback_progress = PlaybackProgress(progress=int(position)) + await self._client.seek_to_position(position_ms=int(position * 1000)) + # Try to prevent the playback progress from bouncing in the UI. + self._attr_media_position_updated_at = utcnow() + self._playback_progress = PlaybackProgress(progress=int(position)) - self.async_write_ha_state() - else: - raise HomeAssistantError( - translation_domain=DOMAIN, translation_key="non_deezer_seeking" - ) + self.async_write_ha_state() async def async_media_previous_track(self) -> None: """Send the previous track command.""" diff --git a/homeassistant/components/bang_olufsen/strings.json b/homeassistant/components/bang_olufsen/strings.json index b0cb88985d2..3e336f7d2d8 100644 --- a/homeassistant/components/bang_olufsen/strings.json +++ b/homeassistant/components/bang_olufsen/strings.json @@ -29,9 +29,6 @@ "m3u_invalid_format": { "message": "Media sources with the .m3u extension are not supported." }, - "non_deezer_seeking": { - "message": "Seeking is currently only supported when using Deezer" - }, "invalid_source": { "message": "Invalid source: {invalid_source}. Valid sources are: {valid_sources}" }, diff --git a/tests/components/bang_olufsen/test_media_player.py b/tests/components/bang_olufsen/test_media_player.py index a19423d8e82..5cf2a9654bf 100644 --- a/tests/components/bang_olufsen/test_media_player.py +++ b/tests/components/bang_olufsen/test_media_player.py @@ -673,10 +673,12 @@ async def test_async_media_next_track( @pytest.mark.parametrize( ("source", "expected_result", "seek_called_times"), [ - # Deezer source, seek expected + # Seekable source, seek expected (BangOlufsenSource.DEEZER, does_not_raise(), 1), - # Non deezer source, seek shouldn't work - (BangOlufsenSource.TIDAL, pytest.raises(HomeAssistantError), 0), + # Non seekable source, seek shouldn't work + (BangOlufsenSource.LINE_IN, pytest.raises(HomeAssistantError), 0), + # Malformed source, seek shouldn't work + (Source(), pytest.raises(HomeAssistantError), 0), ], ) async def test_async_media_seek(