1 """Support to interface with the Plex API."""
3 from __future__
import annotations
9 from .const
import DOMAIN, SERVERS
10 from .errors
import MediaNotFound
11 from .helpers
import get_plex_data, get_plex_server, pretty_title
15 """Unknown media type."""
18 EXPANDABLES = [
"album",
"artist",
"playlist",
"season",
"show"]
19 ITEM_TYPE_MEDIA_CLASS = {
20 "album": MediaClass.ALBUM,
21 "artist": MediaClass.ARTIST,
22 "clip": MediaClass.VIDEO,
23 "episode": MediaClass.EPISODE,
24 "mixed": MediaClass.DIRECTORY,
25 "movie": MediaClass.MOVIE,
26 "playlist": MediaClass.PLAYLIST,
27 "season": MediaClass.SEASON,
28 "show": MediaClass.TV_SHOW,
29 "station": MediaClass.ARTIST,
30 "track": MediaClass.TRACK,
31 "video": MediaClass.VIDEO,
36 hass, is_internal, media_content_type, media_content_id, *, platform=None
38 """Implement the websocket media browsing helper."""
44 url =
URL(media_content_id)
47 if media_content_type ==
"hub":
48 _, hub_location, hub_identifier = url.parts
49 elif media_content_type
in [
"library",
"server"]
and len(url.parts) > 2:
50 _, media_content_id, special_folder = url.parts
52 media_content_id = url.name
54 if media_content_type
in (
"plex_root",
None):
55 return root_payload(hass, is_internal, platform=platform)
57 def item_payload(item, short_name=False, extra_params=None):
58 """Create response payload for a single media item."""
60 media_class = ITEM_TYPE_MEDIA_CLASS[item.type]
61 except KeyError
as err:
65 "media_class": media_class,
67 server_id, item.ratingKey, params=extra_params
69 "media_content_type": item.type,
71 "can_expand": item.type
in EXPANDABLES,
73 if hasattr(item,
"thumbUrl"):
74 plex_server.thumbnail_cache.setdefault(
str(item.ratingKey), item.thumbUrl)
76 thumbnail = item.thumbUrl
82 payload[
"thumbnail"] = thumbnail
87 """Create response payload to describe libraries of the Plex server."""
89 title=plex_server.friendly_name,
90 media_class=MediaClass.DIRECTORY,
92 media_content_type=
"server",
96 children_media_class=MediaClass.DIRECTORY,
97 thumbnail=
"https://brands.home-assistant.io/_/plex/logo.png",
99 if platform !=
"sonos":
100 server_info.children.append(
103 for library
in plex_server.library.sections():
104 if library.type ==
"photo":
106 if library.type !=
"artist" and platform ==
"sonos":
109 server_info.children.append(playlists_payload())
112 def library_contents(library):
113 """Create response payload to describe contents of a specific library."""
116 for item
in library.all():
119 except UnknownMediaType:
123 def playlists_payload():
124 """Create response payload for all available playlists."""
126 "title":
"Playlists",
127 "media_class": MediaClass.DIRECTORY,
129 "media_content_type":
"playlists",
134 for playlist
in plex_server.playlists():
136 playlist.type !=
"directory"
137 and playlist.playlistType !=
"audio"
138 and platform ==
"sonos"
142 playlists_info[
"children"].append(
item_payload(playlist))
143 except UnknownMediaType:
146 response.children_media_class = MediaClass.PLAYLIST
150 """Create response payload for the provided media query."""
152 media = plex_server.lookup_media(**payload)
153 except MediaNotFound:
158 except UnknownMediaType:
160 if media_info.can_expand:
161 media_info.children = []
162 if media.TYPE ==
"artist" and platform !=
"sonos":
163 if (station := media.station())
is not None:
167 media_info.children.append(
item_payload(item, short_name=
True))
168 except UnknownMediaType:
172 if media_content_type ==
"hub":
173 if hub_location ==
"server":
176 for x
in plex_server.library.hubs()
177 if x.hubIdentifier == hub_identifier
179 media_content_id = f
"server/{hub.hubIdentifier}"
181 library_section = plex_server.library.sectionByID(
int(hub_location))
183 x
for x
in library_section.hubs()
if x.hubIdentifier == hub_identifier
185 media_content_id = f
"{hub.librarySectionID}/{hub.hubIdentifier}"
187 children_media_class = ITEM_TYPE_MEDIA_CLASS[hub.type]
188 except KeyError
as err:
192 "media_class": MediaClass.DIRECTORY,
194 "media_content_type":
"hub",
198 "children_media_class": children_media_class,
200 for item
in hub.items:
201 if hub.type ==
"station":
202 if platform ==
"sonos":
207 hub_context = hub.context.split(
".")[-1]
208 if hub_context
in (
"continue",
"inprogress",
"ondeck"):
209 extra_params = {
"resume": 1}
210 payload[
"children"].append(
216 if media_content_type ==
"server":
217 library_or_section = plex_server.library
218 children_media_class = MediaClass.DIRECTORY
219 title = plex_server.friendly_name
220 elif media_content_type ==
"library":
221 library_or_section = plex_server.library.sectionByID(
int(media_content_id))
222 title = library_or_section.title
224 children_media_class = ITEM_TYPE_MEDIA_CLASS[library_or_section.TYPE]
225 except KeyError
as err:
227 f
"Unknown type received: {library_or_section.TYPE}"
231 f
"Media not found: {media_content_type} / {media_content_id}"
236 "media_class": MediaClass.DIRECTORY,
238 server_id, f
"{media_content_id}/{special_folder}"
240 "media_content_type": media_content_type,
244 "children_media_class": children_media_class,
247 if special_folder ==
"Recommended":
248 for item
in library_or_section.hubs():
249 if item.type ==
"photo":
256 if media_content_type ==
"server":
257 return server_payload()
259 if media_content_type ==
"library":
260 library_id =
int(media_content_id)
261 library = plex_server.library.sectionByID(library_id)
262 return library_contents(library)
264 except UnknownMediaType
as err:
266 f
"Media not found: {media_content_type} / {media_content_id}"
269 if media_content_type ==
"playlists":
270 return playlists_payload()
273 "media_type": DOMAIN,
274 "plex_key":
int(media_content_id),
278 raise BrowseError(f
"Media not found: {media_content_type} / {media_content_id}")
283 """Create a media_content_id URL for playable Plex media."""
284 if isinstance(media_id, int):
285 media_id =
str(media_id)
286 if isinstance(media_id, str)
and not media_id.startswith(
"/"):
287 media_id = f
"/{media_id}"
299 """Return root payload for Plex."""
311 if len(children) == 1:
316 media_class=MediaClass.DIRECTORY,
318 media_content_type=
"plex_root",
326 """Create response payload for a single library section."""
328 children_media_class = ITEM_TYPE_MEDIA_CLASS[section.TYPE]
329 except KeyError
as err:
331 server_id = section._server.machineIdentifier
334 media_class=MediaClass.DIRECTORY,
336 media_content_type=
"library",
339 children_media_class=children_media_class,
344 """Create response payload for special library folders."""
345 title = f
"{special_type} ({parent_payload.title})"
346 special_library_id = f
"{parent_payload.media_content_id}/{special_type}"
349 media_class=parent_payload.media_class,
350 media_content_id=special_library_id,
351 media_content_type=parent_payload.media_content_type,
354 children_media_class=parent_payload.children_media_class,
359 """Create response payload for a hub."""
360 if hasattr(hub,
"librarySectionID"):
361 media_content_id = f
"{hub.librarySectionID}/{hub.hubIdentifier}"
363 media_content_id = f
"server/{hub.hubIdentifier}"
364 server_id = hub._server.machineIdentifier
367 "media_class": MediaClass.DIRECTORY,
369 "media_content_type":
"hub",
377 """Create response payload for a music station."""
378 server_id = station._server.machineIdentifier
381 media_class=ITEM_TYPE_MEDIA_CLASS[station.type],
383 media_content_type=
"station",
391 media_content_id: str,
393 """Generate an url for a Plex media browser image."""
394 return f
"/api/plex_image_proxy/{server_id}/{media_content_id}"
PlexData get_plex_data(HomeAssistant hass)
def pretty_title(media, short_name=False)
PlexServer get_plex_server(HomeAssistant hass, str server_id)