Home Assistant Unofficial Reference 2024.12.1
media_player.py
Go to the documentation of this file.
1 """Support for interfacing with an instance of getchannels.com."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from pychannels import Channels
8 import voluptuous as vol
9 
11  PLATFORM_SCHEMA as MEDIA_PLAYER_PLATFORM_SCHEMA,
12  MediaPlayerEntity,
13  MediaPlayerEntityFeature,
14  MediaPlayerState,
15  MediaType,
16 )
17 from homeassistant.const import ATTR_SECONDS, CONF_HOST, CONF_NAME, CONF_PORT
18 from homeassistant.core import HomeAssistant
19 from homeassistant.helpers import config_validation as cv, entity_platform
20 from homeassistant.helpers.entity_platform import AddEntitiesCallback
21 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
22 
23 from .const import SERVICE_SEEK_BACKWARD, SERVICE_SEEK_BY, SERVICE_SEEK_FORWARD
24 
25 DATA_CHANNELS = "channels"
26 DEFAULT_NAME = "Channels"
27 DEFAULT_PORT = 57000
28 
29 PLATFORM_SCHEMA = MEDIA_PLAYER_PLATFORM_SCHEMA.extend(
30  {
31  vol.Required(CONF_HOST): cv.string,
32  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
33  vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
34  }
35 )
36 
37 
39  hass: HomeAssistant,
40  config: ConfigType,
41  async_add_entities: AddEntitiesCallback,
42  discovery_info: DiscoveryInfoType | None = None,
43 ) -> None:
44  """Set up the Channels platform."""
45  device = ChannelsPlayer(config[CONF_NAME], config[CONF_HOST], config[CONF_PORT])
46  async_add_entities([device], True)
47 
48  platform = entity_platform.async_get_current_platform()
49 
50  platform.async_register_entity_service(
51  SERVICE_SEEK_FORWARD,
52  None,
53  "seek_forward",
54  )
55  platform.async_register_entity_service(
56  SERVICE_SEEK_BACKWARD,
57  None,
58  "seek_backward",
59  )
60  platform.async_register_entity_service(
61  SERVICE_SEEK_BY,
62  {vol.Required(ATTR_SECONDS): vol.Coerce(int)},
63  "seek_by",
64  )
65 
66 
68  """Representation of a Channels instance."""
69 
70  _attr_media_content_type = MediaType.CHANNEL
71  _attr_supported_features = (
72  MediaPlayerEntityFeature.PLAY
73  | MediaPlayerEntityFeature.PAUSE
74  | MediaPlayerEntityFeature.STOP
75  | MediaPlayerEntityFeature.VOLUME_MUTE
76  | MediaPlayerEntityFeature.NEXT_TRACK
77  | MediaPlayerEntityFeature.PREVIOUS_TRACK
78  | MediaPlayerEntityFeature.PLAY_MEDIA
79  | MediaPlayerEntityFeature.SELECT_SOURCE
80  )
81 
82  def __init__(self, name, host, port):
83  """Initialize the Channels app."""
84 
85  self._name_name = name
86  self._host_host = host
87  self._port_port = port
88 
89  self.clientclient = Channels(self._host_host, self._port_port)
90 
91  self.statusstatus = None
92  self.mutedmuted = None
93 
94  self.channel_numberchannel_number = None
95  self.channel_namechannel_name = None
96  self.channel_image_urlchannel_image_url = None
97 
98  self.now_playing_titlenow_playing_title = None
99  self.now_playing_episode_titlenow_playing_episode_title = None
100  self.now_playing_season_numbernow_playing_season_number = None
101  self.now_playing_episode_numbernow_playing_episode_number = None
102  self.now_playing_summarynow_playing_summary = None
103  self.now_playing_image_urlnow_playing_image_url = None
104 
105  self.favorite_channelsfavorite_channels = []
106 
108  """Update the favorite channels from the client."""
109  self.favorite_channelsfavorite_channels = self.clientclient.favorite_channels()
110 
111  def update_state(self, state_hash):
112  """Update all the state properties with the passed in dictionary."""
113  self.statusstatus = state_hash.get("status", "stopped")
114  self.mutedmuted = state_hash.get("muted", False)
115 
116  channel_hash = state_hash.get("channel")
117  np_hash = state_hash.get("now_playing")
118 
119  if channel_hash:
120  self.channel_numberchannel_number = channel_hash.get("channel_number")
121  self.channel_namechannel_name = channel_hash.get("channel_name")
122  self.channel_image_urlchannel_image_url = channel_hash.get("channel_image_url")
123  else:
124  self.channel_numberchannel_number = None
125  self.channel_namechannel_name = None
126  self.channel_image_urlchannel_image_url = None
127 
128  if np_hash:
129  self.now_playing_titlenow_playing_title = np_hash.get("title")
130  self.now_playing_episode_titlenow_playing_episode_title = np_hash.get("episode_title")
131  self.now_playing_season_numbernow_playing_season_number = np_hash.get("season_number")
132  self.now_playing_episode_numbernow_playing_episode_number = np_hash.get("episode_number")
133  self.now_playing_summarynow_playing_summary = np_hash.get("summary")
134  self.now_playing_image_urlnow_playing_image_url = np_hash.get("image_url")
135  else:
136  self.now_playing_titlenow_playing_title = None
137  self.now_playing_episode_titlenow_playing_episode_title = None
138  self.now_playing_season_numbernow_playing_season_number = None
139  self.now_playing_episode_numbernow_playing_episode_number = None
140  self.now_playing_summarynow_playing_summary = None
141  self.now_playing_image_urlnow_playing_image_url = None
142 
143  @property
144  def name(self):
145  """Return the name of the player."""
146  return self._name_name
147 
148  @property
149  def state(self) -> MediaPlayerState | None:
150  """Return the state of the player."""
151  if self.statusstatus == "stopped":
152  return MediaPlayerState.IDLE
153 
154  if self.statusstatus == "paused":
155  return MediaPlayerState.PAUSED
156 
157  if self.statusstatus == "playing":
158  return MediaPlayerState.PLAYING
159 
160  return None
161 
162  def update(self) -> None:
163  """Retrieve latest state."""
164  self.update_favorite_channelsupdate_favorite_channels()
165  self.update_stateupdate_state(self.clientclient.status())
166 
167  @property
168  def source_list(self):
169  """List of favorite channels."""
170  return [channel["name"] for channel in self.favorite_channelsfavorite_channels]
171 
172  @property
173  def is_volume_muted(self):
174  """Boolean if volume is currently muted."""
175  return self.mutedmuted
176 
177  @property
178  def media_content_id(self):
179  """Content ID of current playing channel."""
180  return self.channel_numberchannel_number
181 
182  @property
183  def media_image_url(self):
184  """Image url of current playing media."""
185  if self.now_playing_image_urlnow_playing_image_url:
186  return self.now_playing_image_urlnow_playing_image_url
187  if self.channel_image_urlchannel_image_url:
188  return self.channel_image_urlchannel_image_url
189 
190  return "https://getchannels.com/assets/img/icon-1024.png"
191 
192  @property
193  def media_title(self):
194  """Title of current playing media."""
195  if self.statestatestatestatestate:
196  return self.now_playing_titlenow_playing_title
197 
198  return None
199 
200  def mute_volume(self, mute: bool) -> None:
201  """Mute (true) or unmute (false) player."""
202  if mute != self.mutedmuted:
203  response = self.clientclient.toggle_muted()
204  self.update_stateupdate_state(response)
205 
206  def media_stop(self) -> None:
207  """Send media_stop command to player."""
208  self.statusstatus = "stopped"
209  response = self.clientclient.stop()
210  self.update_stateupdate_state(response)
211 
212  def media_play(self) -> None:
213  """Send media_play command to player."""
214  response = self.clientclient.resume()
215  self.update_stateupdate_state(response)
216 
217  def media_pause(self) -> None:
218  """Send media_pause command to player."""
219  response = self.clientclient.pause()
220  self.update_stateupdate_state(response)
221 
222  def media_next_track(self) -> None:
223  """Seek ahead."""
224  response = self.clientclient.skip_forward()
225  self.update_stateupdate_state(response)
226 
227  def media_previous_track(self) -> None:
228  """Seek back."""
229  response = self.clientclient.skip_backward()
230  self.update_stateupdate_state(response)
231 
232  def select_source(self, source: str) -> None:
233  """Select a channel to tune to."""
234  for channel in self.favorite_channelsfavorite_channels:
235  if channel["name"] == source:
236  response = self.clientclient.play_channel(channel["number"])
237  self.update_stateupdate_state(response)
238  break
239 
241  self, media_type: MediaType | str, media_id: str, **kwargs: Any
242  ) -> None:
243  """Send the play_media command to the player."""
244  if media_type == MediaType.CHANNEL:
245  response = self.clientclient.play_channel(media_id)
246  self.update_stateupdate_state(response)
247  elif media_type in {MediaType.MOVIE, MediaType.EPISODE, MediaType.TVSHOW}:
248  response = self.clientclient.play_recording(media_id)
249  self.update_stateupdate_state(response)
250 
251  def seek_forward(self):
252  """Seek forward in the timeline."""
253  response = self.clientclient.seek_forward()
254  self.update_stateupdate_state(response)
255 
256  def seek_backward(self):
257  """Seek backward in the timeline."""
258  response = self.clientclient.seek_backward()
259  self.update_stateupdate_state(response)
260 
261  def seek_by(self, seconds):
262  """Seek backward in the timeline."""
263  response = self.clientclient.seek(seconds)
264  self.update_stateupdate_state(response)
None play_media(self, MediaType|str media_type, str media_id, **Any kwargs)
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: media_player.py:43