core/homeassistant/components/plex/models.py

180 lines
6.2 KiB
Python

"""Models to represent various Plex objects used in the integration."""
import logging
from homeassistant.components.media_player import MediaType
from homeassistant.helpers.template import result_as_boolean
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 = MediaType.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} -"
f" {media.seasonEpisode} -"
f" {self.media_title}"
)
elif media.type == "movie":
self.media_content_type = MediaType.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 = MediaType.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 = MediaType.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
class PlexMediaSearchResult:
"""Represents results from a Plex media media_content_id search.
Results are used by media_player.play_media implementations.
"""
def __init__(self, media, params=None) -> None:
"""Initialize the result."""
self.media = media
self._params = params or {}
@property
def offset(self) -> int:
"""Provide the appropriate offset in ms based on payload contents."""
if offset := self._params.get("offset", 0):
return offset * 1000
resume = self._params.get("resume", False)
if isinstance(resume, str):
resume = result_as_boolean(resume)
if resume:
return self.media.viewOffset
return 0
@property
def shuffle(self) -> bool:
"""Return value of shuffle parameter."""
shuffle = self._params.get("shuffle", False)
if isinstance(shuffle, str):
shuffle = result_as_boolean(shuffle)
return shuffle