text: """Models to represent various Plex objects used in the integration."""
  import logging
  
  from homeassistant.components.media_player.const import (
      MEDIA_TYPE_MOVIE,
      MEDIA_TYPE_MUSIC,
      MEDIA_TYPE_TVSHOW,
      MEDIA_TYPE_VIDEO,
  )
  from homeassistant.util import dt as dt_util
  
  LIVE_TV_SECTION = "Live TV"
  TRANSIENT_SECTION = "Preroll"
  UNKNOWN_SECTION = "Unknown"
  SPECIAL_SECTIONS = {
      -2: TRANSIENT_SECTION,
      -4: LIVE_TV_SECTION,
  }
  
  _LOGGER = logging.getLogger(__name__)
  
  
  class PlexSession:
      """Represents a Plex playback session."""
  
      def __init__(self, plex_server, session):
          """Initialize the object."""
          self.plex_server = plex_server
  
          # Available on both media and session objects
          self.media_content_id = None
          self.media_content_type = None
          self.media_content_rating = None
          self.media_duration = None
          self.media_image_url = None
          self.media_library_title = None
          self.media_summary = None
          self.media_title = None
          # TV Shows
          self.media_episode = None
          self.media_season = None
          self.media_series_title = None
          # Music
          self.media_album_name = None
          self.media_album_artist = None
          self.media_artist = None
          self.media_track = None
  
          # Only available on sessions
          self.player = next(iter(session.players), None)
          self.device_product = self.player.product
          self.media_position = session.viewOffset
          self.session_key = session.sessionKey
          self.state = self.player.state
          self.username = next(iter(session.usernames), None)
  
          # Used by sensor entity
          sensor_user_list = [self.username, self.device_product]
          self.sensor_title = None
          self.sensor_user = " - ".join(filter(None, sensor_user_list))
  
          self.update_media(session)
  
      def __repr__(self):
          """Return representation of the session."""
          return f"<{self.session_key}:{self.sensor_title}>"
  
      def update_media(self, media):
          """Update attributes from a media object."""
          self.media_content_id = media.ratingKey
          self.media_content_rating = getattr(media, "contentRating", None)
          self.media_image_url = self.get_media_image_url(media)
          self.media_summary = media.summary
          self.media_title = media.title
  
          if media.duration:
              self.media_duration = int(media.duration / 1000)
  
          if media.librarySectionID in SPECIAL_SECTIONS:
              self.media_library_title = SPECIAL_SECTIONS[media.librarySectionID]
          elif media.librarySectionID and media.librarySectionID < 1:
              self.media_library_title = UNKNOWN_SECTION
              _LOGGER.warning(
                  "Unknown library section ID (%s) for title '%s', please create an issue",
                  media.librarySectionID,
                  media.title,
              )
          else:
              self.media_library_title = (
                  media.section().title if media.librarySectionID is not None else ""
              )
  
          if media.type == "episode":
              self.media_content_type = MEDIA_TYPE_TVSHOW
              self.media_season = media.seasonNumber
              self.media_series_title = media.grandparentTitle
              if media.index is not None:
                  self.media_episode = media.index
              self.sensor_title = f"{self.media_series_title} - {media.seasonEpisode} - {self.media_title}"
          elif media.type == "movie":
              self.media_content_type = MEDIA_TYPE_MOVIE
              if media.year is not None and media.title is not None:
                  self.media_title += f" ({media.year!s})"
              self.sensor_title = self.media_title
          elif media.type == "track":
              self.media_content_type = MEDIA_TYPE_MUSIC
              self.media_album_name = media.parentTitle
              self.media_album_artist = media.grandparentTitle
              self.media_track = media.index
              self.media_artist = media.originalTitle or self.media_album_artist
              self.sensor_title = (
                  f"{self.media_artist} - {self.media_album_name} - {self.media_title}"
              )
          elif media.type == "clip":
              self.media_content_type = MEDIA_TYPE_VIDEO
              self.sensor_title = media.title
          else:
              self.sensor_title = "Unknown"
  
      @property
      def media_position(self):
          """Return the current playback position."""
          return self._media_position
  
      @media_position.setter
      def media_position(self, offset):
          """Set the current playback position."""
          self._media_position = int(offset / 1000)
          self.media_position_updated_at = dt_util.utcnow()
  
      def get_media_image_url(self, media):
          """Get the image URL from a media object."""
          thumb_url = media.thumbUrl
          if media.type == "episode" and not self.plex_server.option_use_episode_art:
              if SPECIAL_SECTIONS.get(media.librarySectionID) == LIVE_TV_SECTION:
                  thumb_url = media.grandparentThumb
              else:
                  thumb_url = media.url(media.grandparentThumb)
  
          if thumb_url is None:
              thumb_url = media.url(media.art)
  
          return thumb_url
  