Home Assistant Unofficial Reference 2024.12.1
media_player.py
Go to the documentation of this file.
1 """Demo implementation of the media player."""
2 
3 from __future__ import annotations
4 
5 from datetime import datetime
6 from typing import Any
7 
9  MediaPlayerDeviceClass,
10  MediaPlayerEntity,
11  MediaPlayerEntityFeature,
12  MediaPlayerState,
13  MediaType,
14  RepeatMode,
15 )
16 from homeassistant.config_entries import ConfigEntry
17 from homeassistant.core import HomeAssistant
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 import homeassistant.util.dt as dt_util
20 
21 
23  hass: HomeAssistant,
24  config_entry: ConfigEntry,
25  async_add_entities: AddEntitiesCallback,
26 ) -> None:
27  """Set up the Demo config entry."""
29  [
31  "Living Room",
32  "eyU3bRy2x44",
33  "♥♥ The Best Fireplace Video (3 hours)",
34  300,
35  ),
37  "Bedroom", "kxopViU98Xo", "Epic sax guy 10 hours", 360000
38  ),
40  DemoMusicPlayer("Kitchen"),
42  DemoBrowsePlayer("Browse"),
43  DemoGroupPlayer("Group"),
44  ]
45  )
46 
47 
48 SOUND_MODE_LIST = ["Music", "Movie"]
49 DEFAULT_SOUND_MODE = "Music"
50 
51 YOUTUBE_PLAYER_SUPPORT = (
52  MediaPlayerEntityFeature.PAUSE
53  | MediaPlayerEntityFeature.VOLUME_SET
54  | MediaPlayerEntityFeature.VOLUME_MUTE
55  | MediaPlayerEntityFeature.TURN_ON
56  | MediaPlayerEntityFeature.TURN_OFF
57  | MediaPlayerEntityFeature.PLAY_MEDIA
58  | MediaPlayerEntityFeature.PLAY
59  | MediaPlayerEntityFeature.SHUFFLE_SET
60  | MediaPlayerEntityFeature.SELECT_SOUND_MODE
61  | MediaPlayerEntityFeature.SEEK
62  | MediaPlayerEntityFeature.STOP
63 )
64 
65 MUSIC_PLAYER_SUPPORT = (
66  MediaPlayerEntityFeature.PAUSE
67  | MediaPlayerEntityFeature.VOLUME_SET
68  | MediaPlayerEntityFeature.VOLUME_MUTE
69  | MediaPlayerEntityFeature.TURN_ON
70  | MediaPlayerEntityFeature.TURN_OFF
71  | MediaPlayerEntityFeature.CLEAR_PLAYLIST
72  | MediaPlayerEntityFeature.GROUPING
73  | MediaPlayerEntityFeature.PLAY
74  | MediaPlayerEntityFeature.SHUFFLE_SET
75  | MediaPlayerEntityFeature.REPEAT_SET
76  | MediaPlayerEntityFeature.VOLUME_STEP
77  | MediaPlayerEntityFeature.PREVIOUS_TRACK
78  | MediaPlayerEntityFeature.NEXT_TRACK
79  | MediaPlayerEntityFeature.SELECT_SOUND_MODE
80  | MediaPlayerEntityFeature.STOP
81 )
82 
83 NETFLIX_PLAYER_SUPPORT = (
84  MediaPlayerEntityFeature.PAUSE
85  | MediaPlayerEntityFeature.TURN_ON
86  | MediaPlayerEntityFeature.TURN_OFF
87  | MediaPlayerEntityFeature.SELECT_SOURCE
88  | MediaPlayerEntityFeature.PLAY
89  | MediaPlayerEntityFeature.SHUFFLE_SET
90  | MediaPlayerEntityFeature.PREVIOUS_TRACK
91  | MediaPlayerEntityFeature.NEXT_TRACK
92  | MediaPlayerEntityFeature.SELECT_SOUND_MODE
93  | MediaPlayerEntityFeature.STOP
94 )
95 
96 BROWSE_PLAYER_SUPPORT = MediaPlayerEntityFeature.BROWSE_MEDIA
97 
98 
100  """A demo media players."""
101 
102  _attr_should_poll = False
103  _attr_sound_mode_list = SOUND_MODE_LIST
104 
105  # We only implement the methods that we support
106 
107  def __init__(
108  self, name: str, device_class: MediaPlayerDeviceClass | None = None
109  ) -> None:
110  """Initialize the demo device."""
111  self._attr_name_attr_name = name
112  self._attr_state_attr_state = MediaPlayerState.PLAYING
113  self._attr_volume_level_attr_volume_level = 1.0
114  self._attr_is_volume_muted_attr_is_volume_muted = False
115  self._attr_shuffle_attr_shuffle = False
116  self._attr_sound_mode_attr_sound_mode = DEFAULT_SOUND_MODE
117  self._attr_device_class_attr_device_class = device_class
118 
119  def turn_on(self) -> None:
120  """Turn the media player on."""
121  self._attr_state_attr_state = MediaPlayerState.PLAYING
122  self.schedule_update_ha_stateschedule_update_ha_state()
123 
124  def turn_off(self) -> None:
125  """Turn the media player off."""
126  self._attr_state_attr_state = MediaPlayerState.OFF
127  self.schedule_update_ha_stateschedule_update_ha_state()
128 
129  def mute_volume(self, mute: bool) -> None:
130  """Mute the volume."""
131  self._attr_is_volume_muted_attr_is_volume_muted = mute
132  self.schedule_update_ha_stateschedule_update_ha_state()
133 
134  def volume_up(self) -> None:
135  """Increase volume."""
136  assert self.volume_levelvolume_level is not None
137  self._attr_volume_level_attr_volume_level = min(1.0, self.volume_levelvolume_level + 0.1)
138  self.schedule_update_ha_stateschedule_update_ha_state()
139 
140  def volume_down(self) -> None:
141  """Decrease volume."""
142  assert self.volume_levelvolume_level is not None
143  self._attr_volume_level_attr_volume_level = max(0.0, self.volume_levelvolume_level - 0.1)
144  self.schedule_update_ha_stateschedule_update_ha_state()
145 
146  def set_volume_level(self, volume: float) -> None:
147  """Set the volume level, range 0..1."""
148  self._attr_volume_level_attr_volume_level = volume
149  self.schedule_update_ha_stateschedule_update_ha_state()
150 
151  def media_play(self) -> None:
152  """Send play command."""
153  self._attr_state_attr_state = MediaPlayerState.PLAYING
154  self.schedule_update_ha_stateschedule_update_ha_state()
155 
156  def media_pause(self) -> None:
157  """Send pause command."""
158  self._attr_state_attr_state = MediaPlayerState.PAUSED
159  self.schedule_update_ha_stateschedule_update_ha_state()
160 
161  def media_stop(self) -> None:
162  """Send stop command."""
163  self._attr_state_attr_state = MediaPlayerState.OFF
164  self.schedule_update_ha_stateschedule_update_ha_state()
165 
166  def set_shuffle(self, shuffle: bool) -> None:
167  """Enable/disable shuffle mode."""
168  self._attr_shuffle_attr_shuffle = shuffle
169  self.schedule_update_ha_stateschedule_update_ha_state()
170 
171  def select_sound_mode(self, sound_mode: str) -> None:
172  """Select sound mode."""
173  self._attr_sound_mode_attr_sound_mode = sound_mode
174  self.schedule_update_ha_stateschedule_update_ha_state()
175 
176 
178  """A Demo media player that only supports YouTube."""
179 
180  # We only implement the methods that we support
181 
182  _attr_app_name = "YouTube"
183  _attr_media_content_type = MediaType.MOVIE
184  _attr_supported_features = YOUTUBE_PLAYER_SUPPORT
185 
186  def __init__(
187  self, name: str, youtube_id: str, media_title: str, duration: int
188  ) -> None:
189  """Initialize the demo device."""
190  super().__init__(name)
191  self._attr_media_content_id_attr_media_content_id = youtube_id
192  self._attr_media_title_attr_media_title = media_title
193  self._attr_media_duration_attr_media_duration = duration
194  self._progress_progress: int | None = int(duration * 0.15)
195  self._progress_updated_at_progress_updated_at = dt_util.utcnow()
196 
197  @property
198  def media_image_url(self) -> str:
199  """Return the image url of current playing media."""
200  return f"https://img.youtube.com/vi/{self.media_content_id}/hqdefault.jpg"
201 
202  @property
203  def media_position(self) -> int | None:
204  """Position of current playing media in seconds."""
205  if self._progress_progress is None:
206  return None
207 
208  position = self._progress_progress
209 
210  if self.statestatestatestatestate == MediaPlayerState.PLAYING:
211  position += int(
212  (dt_util.utcnow() - self._progress_updated_at_progress_updated_at).total_seconds()
213  )
214 
215  return position
216 
217  @property
218  def media_position_updated_at(self) -> datetime | None:
219  """When was the position of the current playing media valid.
220 
221  Returns value from homeassistant.util.dt.utcnow().
222  """
223  if self.statestatestatestatestate == MediaPlayerState.PLAYING:
224  return self._progress_updated_at_progress_updated_at
225  return None
226 
228  self, media_type: MediaType | str, media_id: str, **kwargs: Any
229  ) -> None:
230  """Play a piece of media."""
231  self._attr_media_content_id_attr_media_content_id = media_id
232  self.schedule_update_ha_stateschedule_update_ha_state()
233 
234  def media_pause(self) -> None:
235  """Send pause command."""
236  self._progress_progress = self.media_positionmedia_positionmedia_position
237  self._progress_updated_at_progress_updated_at = dt_util.utcnow()
238  super().media_pause()
239 
240 
242  """A Demo media player."""
243 
244  # We only implement the methods that we support
245 
246  _attr_media_album_name = "Bounzz"
247  _attr_media_content_id = "bounzz-1"
248  _attr_media_content_type = MediaType.MUSIC
249  _attr_media_duration = 213
250  _attr_media_image_url = (
251  "https://graph.facebook.com/v2.5/107771475912710/picture?type=large"
252  )
253  _attr_supported_features = MUSIC_PLAYER_SUPPORT
254 
255  tracks = [
256  ("Technohead", "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)"),
257  ("Paul Elstak", "Luv U More"),
258  ("Dune", "Hardcore Vibes"),
259  ("Nakatomi", "Children Of The Night"),
260  ("Party Animals", "Have You Ever Been Mellow? (Flamman & Abraxas Radio Mix)"),
261  ("Rob G.*", "Ecstasy, You Got What I Need"),
262  ("Lipstick", "I'm A Raver"),
263  ("4 Tune Fairytales", "My Little Fantasy (Radio Edit)"),
264  ("Prophet", "The Big Boys Don't Cry"),
265  ("Lovechild", "All Out Of Love (DJ Weirdo & Sim Remix)"),
266  ("Stingray & Sonic Driver", "Cold As Ice (El Bruto Remix)"),
267  ("Highlander", "Hold Me Now (Bass-D & King Matthew Remix)"),
268  ("Juggernaut", 'Ruffneck Rules Da Artcore Scene (12" Edit)'),
269  ("Diss Reaction", "Jiiieehaaaa "),
270  ("Flamman And Abraxas", "Good To Go (Radio Mix)"),
271  ("Critical Mass", "Dancing Together"),
272  (
273  "Charly Lownoise & Mental Theo",
274  "Ultimate Sex Track (Bass-D & King Matthew Remix)",
275  ),
276  ]
277 
278  def __init__(self, name: str = "Walkman") -> None:
279  """Initialize the demo device."""
280  super().__init__(name)
281  self._cur_track_cur_track = 0
282  self._attr_group_members_attr_group_members: list[str] = []
283  self._attr_repeat_attr_repeat = RepeatMode.OFF
284 
285  @property
286  def media_title(self) -> str:
287  """Return the title of current playing media."""
288  return self.trackstrackstracks[self._cur_track_cur_track][1] if self.trackstrackstracks else ""
289 
290  @property
291  def media_artist(self) -> str:
292  """Return the artist of current playing media (Music track only)."""
293  return self.trackstrackstracks[self._cur_track_cur_track][0] if self.trackstrackstracks else ""
294 
295  @property
296  def media_track(self) -> int:
297  """Return the track number of current media (Music track only)."""
298  return self._cur_track_cur_track + 1
299 
300  def media_previous_track(self) -> None:
301  """Send previous track command."""
302  if self._cur_track_cur_track > 0:
303  self._cur_track_cur_track -= 1
304  self.schedule_update_ha_stateschedule_update_ha_state()
305 
306  def media_next_track(self) -> None:
307  """Send next track command."""
308  if self._cur_track_cur_track < len(self.trackstrackstracks) - 1:
309  self._cur_track_cur_track += 1
310  self.schedule_update_ha_stateschedule_update_ha_state()
311 
312  def clear_playlist(self) -> None:
313  """Clear players playlist."""
314  self.trackstrackstracks = []
315  self._cur_track_cur_track = 0
316  self._attr_state_attr_state_attr_state = MediaPlayerState.OFF
317  self.schedule_update_ha_stateschedule_update_ha_state()
318 
319  def set_repeat(self, repeat: RepeatMode) -> None:
320  """Enable/disable repeat mode."""
321  self._attr_repeat_attr_repeat = repeat
322  self.schedule_update_ha_stateschedule_update_ha_state()
323 
324  def join_players(self, group_members: list[str]) -> None:
325  """Join `group_members` as a player group with the current player."""
326  self._attr_group_members_attr_group_members = [self.entity_identity_id, *group_members]
327  self.schedule_update_ha_stateschedule_update_ha_state()
328 
329  def unjoin_player(self) -> None:
330  """Remove this player from any group."""
331  self._attr_group_members_attr_group_members = []
332  self.schedule_update_ha_stateschedule_update_ha_state()
333 
334 
336  """A Demo media player that only supports Netflix."""
337 
338  # We only implement the methods that we support
339 
340  _attr_app_name = "Netflix"
341  _attr_media_content_id = "house-of-cards-1"
342  _attr_media_content_type = MediaType.TVSHOW
343  _attr_media_duration = 3600
344  _attr_media_image_url = (
345  "https://graph.facebook.com/v2.5/HouseofCards/picture?width=400"
346  )
347  _attr_media_season = "1"
348  _attr_media_series_title = "House of Cards"
349  _attr_source_list = ["dvd", "youtube"]
350  _attr_supported_features = NETFLIX_PLAYER_SUPPORT
351 
352  def __init__(self) -> None:
353  """Initialize the demo device."""
354  super().__init__("Lounge room", MediaPlayerDeviceClass.TV)
355  self._cur_episode_cur_episode = 1
356  self._episode_count_episode_count = 13
357  self._attr_source_attr_source = "dvd"
358 
359  @property
360  def media_title(self) -> str:
361  """Return the title of current playing media."""
362  return f"Chapter {self._cur_episode}"
363 
364  @property
365  def media_episode(self) -> str:
366  """Return the episode of current playing media (TV Show only)."""
367  return str(self._cur_episode_cur_episode)
368 
369  def media_previous_track(self) -> None:
370  """Send previous track command."""
371  if self._cur_episode_cur_episode > 1:
372  self._cur_episode_cur_episode -= 1
373  self.schedule_update_ha_stateschedule_update_ha_state()
374 
375  def media_next_track(self) -> None:
376  """Send next track command."""
377  if self._cur_episode_cur_episode < self._episode_count_episode_count:
378  self._cur_episode_cur_episode += 1
379  self.schedule_update_ha_stateschedule_update_ha_state()
380 
381  def select_source(self, source: str) -> None:
382  """Set the input source."""
383  self._attr_source_attr_source = source
384  self.schedule_update_ha_stateschedule_update_ha_state()
385 
386 
388  """A Demo media player that supports browse."""
389 
390  _attr_supported_features = BROWSE_PLAYER_SUPPORT
391 
392 
394  """A Demo media player that supports grouping."""
395 
396  _attr_supported_features = (
397  YOUTUBE_PLAYER_SUPPORT
398  | MediaPlayerEntityFeature.GROUPING
399  | MediaPlayerEntityFeature.TURN_OFF
400  )
None __init__(self, str name, MediaPlayerDeviceClass|None device_class=None)
None join_players(self, list[str] group_members)
None play_media(self, MediaType|str media_type, str media_id, **Any kwargs)
None __init__(self, str name, str youtube_id, str media_title, int duration)
None schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1244
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: media_player.py:26