Home Assistant Unofficial Reference 2024.12.1
models.py
Go to the documentation of this file.
1 """Models to represent various Plex objects used in the integration."""
2 
3 import logging
4 
5 from homeassistant.components.media_player import MediaType
6 from homeassistant.helpers.template import result_as_boolean
7 from homeassistant.util import dt as dt_util
8 
9 LIVE_TV_SECTION = "Live TV"
10 TRANSIENT_SECTION = "Preroll"
11 UNKNOWN_SECTION = "Unknown"
12 SPECIAL_SECTIONS = {
13  -2: TRANSIENT_SECTION,
14  -4: LIVE_TV_SECTION,
15 }
16 
17 _LOGGER = logging.getLogger(__name__)
18 
19 
21  """Represents a Plex playback session."""
22 
23  def __init__(self, plex_server, session):
24  """Initialize the object."""
25  self.plex_serverplex_server = plex_server
26 
27  # Available on both media and session objects
28  self.media_content_idmedia_content_id = None
29  self.media_content_typemedia_content_type = None
30  self.media_content_ratingmedia_content_rating = None
31  self.media_durationmedia_duration = None
32  self.media_image_urlmedia_image_url = None
33  self.media_library_titlemedia_library_title = None
34  self.media_summarymedia_summary = None
35  self.media_titlemedia_title = None
36  # TV Shows
37  self.media_episodemedia_episode = None
38  self.media_seasonmedia_season = None
39  self.media_series_titlemedia_series_title = None
40  # Music
41  self.media_album_namemedia_album_name = None
42  self.media_album_artistmedia_album_artist = None
43  self.media_artistmedia_artist = None
44  self.media_trackmedia_track = None
45 
46  # Only available on sessions
47  self.playerplayer = next(iter(session.players), None)
48  self.device_productdevice_product = self.playerplayer.product
49  self.media_positionmedia_positionmedia_positionmedia_position = session.viewOffset
50  self.session_keysession_key = session.sessionKey
51  self.statestate = self.playerplayer.state
52  self.usernameusername = next(iter(session.usernames), None)
53 
54  # Used by sensor entity
55  sensor_user_list = [self.usernameusername, self.device_productdevice_product]
56  self.sensor_titlesensor_title = None
57  self.sensor_usersensor_user = " - ".join(filter(None, sensor_user_list))
58 
59  self.update_mediaupdate_media(session)
60 
61  def __repr__(self):
62  """Return representation of the session."""
63  return f"<{self.session_key}:{self.sensor_title}>"
64 
65  def update_media(self, media):
66  """Update attributes from a media object."""
67  self.media_content_idmedia_content_id = media.ratingKey
68  self.media_content_ratingmedia_content_rating = getattr(media, "contentRating", None)
69  self.media_image_urlmedia_image_url = self.get_media_image_urlget_media_image_url(media)
70  self.media_summarymedia_summary = media.summary
71  self.media_titlemedia_title = media.title
72 
73  if media.duration:
74  self.media_durationmedia_duration = int(media.duration / 1000)
75 
76  if media.librarySectionID in SPECIAL_SECTIONS:
77  self.media_library_titlemedia_library_title = SPECIAL_SECTIONS[media.librarySectionID]
78  elif media.librarySectionID and media.librarySectionID < 1:
79  self.media_library_titlemedia_library_title = UNKNOWN_SECTION
80  _LOGGER.warning(
81  (
82  "Unknown library section ID (%s) for title '%s',"
83  " please create an issue"
84  ),
85  media.librarySectionID,
86  media.title,
87  )
88  else:
89  self.media_library_titlemedia_library_title = (
90  media.section().title if media.librarySectionID is not None else ""
91  )
92 
93  if media.type == "episode":
94  self.media_content_typemedia_content_type = MediaType.TVSHOW
95  self.media_seasonmedia_season = media.seasonNumber
96  self.media_series_titlemedia_series_title = media.grandparentTitle
97  if media.index is not None:
98  self.media_episodemedia_episode = media.index
99  self.sensor_titlesensor_title = (
100  f"{self.media_series_title} -"
101  f" {media.seasonEpisode} -"
102  f" {self.media_title}"
103  )
104  elif media.type == "movie":
105  self.media_content_typemedia_content_type = MediaType.MOVIE
106  if media.year is not None and media.title is not None:
107  self.media_titlemedia_title += f" ({media.year!s})"
108  self.sensor_titlesensor_title = self.media_titlemedia_title
109  elif media.type == "track":
110  self.media_content_typemedia_content_type = MediaType.MUSIC
111  self.media_album_namemedia_album_name = media.parentTitle
112  self.media_album_artistmedia_album_artist = media.grandparentTitle
113  self.media_trackmedia_track = media.index
114  self.media_artistmedia_artist = media.originalTitle or self.media_album_artistmedia_album_artist
115  self.sensor_titlesensor_title = (
116  f"{self.media_artist} - {self.media_album_name} - {self.media_title}"
117  )
118  elif media.type == "clip":
119  self.media_content_typemedia_content_type = MediaType.VIDEO
120  self.sensor_titlesensor_title = media.title
121  else:
122  self.sensor_titlesensor_title = "Unknown"
123 
124  @property
125  def media_position(self):
126  """Return the current playback position."""
127  return self._media_position_media_position
128 
129  @media_position.setter
130  def media_position(self, offset):
131  """Set the current playback position."""
132  self._media_position_media_position = int(offset / 1000)
133  self.media_position_updated_atmedia_position_updated_at = dt_util.utcnow()
134 
135  def get_media_image_url(self, media):
136  """Get the image URL from a media object."""
137  thumb_url = media.thumbUrl
138  if media.type == "episode" and not self.plex_serverplex_server.option_use_episode_art:
139  if SPECIAL_SECTIONS.get(media.librarySectionID) == LIVE_TV_SECTION:
140  thumb_url = media.grandparentThumb
141  else:
142  thumb_url = media.url(media.grandparentThumb)
143 
144  if thumb_url is None:
145  thumb_url = media.url(media.art)
146 
147  return thumb_url
148 
149 
151  """Represents results from a Plex media media_content_id search.
152 
153  Results are used by media_player.play_media implementations.
154  """
155 
156  def __init__(self, media, params=None) -> None:
157  """Initialize the result."""
158  self.mediamedia = media
159  self._params_params = params or {}
160 
161  @property
162  def offset(self) -> int:
163  """Provide the appropriate offset in ms based on payload contents."""
164  if offset := self._params_params.get("offset", 0):
165  return offset * 1000
166  resume = self._params_params.get("resume", False)
167  if isinstance(resume, str):
168  resume = result_as_boolean(resume)
169  if resume:
170  return self.mediamedia.viewOffset
171  return 0
172 
173  @property
174  def shuffle(self) -> bool:
175  """Return value of shuffle parameter."""
176  shuffle = self._params_params.get("shuffle", False)
177  if isinstance(shuffle, str):
178  shuffle = result_as_boolean(shuffle)
179  return shuffle
def __init__(self, plex_server, session)
Definition: models.py:23
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
bool result_as_boolean(Any|None template_result)
Definition: template.py:1277