1 """Media player support for Bravia TV integration."""
3 from __future__
import annotations
5 from datetime
import datetime
12 MediaPlayerDeviceClass,
14 MediaPlayerEntityFeature,
21 from .
import BraviaTVConfigEntry
22 from .const
import SourceType
23 from .entity
import BraviaTVEntity
28 config_entry: BraviaTVConfigEntry,
29 async_add_entities: AddEntitiesCallback,
31 """Set up Bravia TV Media Player from a config_entry."""
33 coordinator = config_entry.runtime_data
34 unique_id = config_entry.unique_id
35 assert unique_id
is not None
43 """Representation of a Bravia TV Media Player."""
46 _attr_assumed_state =
True
47 _attr_device_class = MediaPlayerDeviceClass.TV
48 _attr_supported_features = (
49 MediaPlayerEntityFeature.PAUSE
50 | MediaPlayerEntityFeature.VOLUME_STEP
51 | MediaPlayerEntityFeature.VOLUME_MUTE
52 | MediaPlayerEntityFeature.VOLUME_SET
53 | MediaPlayerEntityFeature.PREVIOUS_TRACK
54 | MediaPlayerEntityFeature.NEXT_TRACK
55 | MediaPlayerEntityFeature.TURN_ON
56 | MediaPlayerEntityFeature.TURN_OFF
57 | MediaPlayerEntityFeature.SELECT_SOURCE
58 | MediaPlayerEntityFeature.PLAY
59 | MediaPlayerEntityFeature.STOP
60 | MediaPlayerEntityFeature.PLAY_MEDIA
61 | MediaPlayerEntityFeature.BROWSE_MEDIA
65 def state(self) -> MediaPlayerState:
66 """Return the state of the device."""
67 if self.coordinator.is_on:
68 return MediaPlayerState.ON
69 return MediaPlayerState.OFF
73 """Return the current input source."""
74 return self.coordinator.source
78 """List of available input sources."""
79 return self.coordinator.source_list
83 """Volume level of the media player (0..1)."""
84 return self.coordinator.volume_level
88 """Boolean if volume is currently muted."""
89 return self.coordinator.volume_muted
93 """Title of current playing media."""
94 return self.coordinator.media_title
98 """Channel currently playing."""
99 return self.coordinator.media_channel
103 """Content ID of current playing media."""
104 return self.coordinator.media_content_id
108 """Content type of current playing media."""
109 return self.coordinator.media_content_type
113 """Duration of current playing media in seconds."""
114 return self.coordinator.media_duration
118 """Position of current playing media in seconds."""
119 return self.coordinator.media_position
123 """When was the position of the current playing media valid."""
124 return self.coordinator.media_position_updated_at
127 """Turn the device on."""
131 """Turn the device off."""
135 """Set volume level, range 0..1."""
139 """Send volume up command."""
143 """Send volume down command."""
147 """Send mute command."""
148 await self.coordinator.async_volume_mute(mute)
152 media_content_type: MediaType | str |
None =
None,
153 media_content_id: str |
None =
None,
155 """Browse apps and channels."""
156 if not media_content_id:
157 await self.coordinator.async_update_sources()
160 path = media_content_id.partition(
"/")
161 if path[0] ==
"apps":
163 if path[0] ==
"channels":
166 raise BrowseError(f
"Media not found: {media_content_type} / {media_content_id}")
169 """Return root media objects."""
173 media_class=MediaClass.DIRECTORY,
175 media_content_type=
"",
185 """Return apps media objects."""
190 media_class=MediaClass.APP,
191 media_content_id=uri,
192 media_content_type=MediaType.APP,
196 MediaType.APP, uri, media_image_id=
None
199 for uri, item
in self.coordinator.source_map.items()
200 if item[
"type"] == SourceType.APP
206 title=
"Applications",
207 media_class=MediaClass.DIRECTORY,
208 media_content_id=
"apps",
209 media_content_type=MediaType.APPS,
210 children_media_class=MediaClass.APP,
217 """Return channels media objects."""
222 media_class=MediaClass.CHANNEL,
223 media_content_id=uri,
224 media_content_type=MediaType.CHANNEL,
228 for uri, item
in self.coordinator.source_map.items()
229 if item[
"type"] == SourceType.CHANNEL
236 media_class=MediaClass.DIRECTORY,
237 media_content_id=
"channels",
238 media_content_type=MediaType.CHANNELS,
239 children_media_class=MediaClass.CHANNEL,
247 media_content_type: MediaType | str,
248 media_content_id: str,
249 media_image_id: str |
None =
None,
250 ) -> tuple[bytes |
None, str |
None]:
251 """Serve album art. Returns (content, content_type)."""
252 if media_content_type == MediaType.APP
and media_content_id:
253 if icon := self.coordinator.source_map[media_content_id].
get(
"icon"):
257 content_type = content_type.replace(
"Content-Type: ",
"")
258 return (content, content_type)
262 self, media_type: MediaType | str, media_id: str, **kwargs: Any
264 """Play a piece of media."""
268 """Set the input source."""
272 """Send play command."""
276 """Send pause command."""
280 """Send pause command that toggle play/pause."""
284 """Send media stop command to media player."""
288 """Send next track command."""
292 """Send previous track command."""
web.Response get(self, web.Request request, str config_key)