示例#1
0
    async def async_browse_media_applications(self, expanded):
        """Return application media objects."""
        if expanded:
            children = [
                BrowseMedia(
                    title=application["label"],
                    media_class=MEDIA_CLASS_APP,
                    media_content_id=application_id,
                    media_content_type=MEDIA_TYPE_APP,
                    can_play=True,
                    can_expand=False,
                    thumbnail=self.get_browse_image_url(MEDIA_TYPE_APP,
                                                        application_id,
                                                        media_image_id=None),
                ) for application_id, application in
                self._tv.applications.items()
            ]
        else:
            children = None

        return BrowseMedia(
            title="Applications",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_id="applications",
            media_content_type=MEDIA_TYPE_APPS,
            children_media_class=MEDIA_CLASS_APP,
            can_play=False,
            can_expand=True,
            children=children,
        )
示例#2
0
    async def async_browse_media(self,
                                 media_content_type=None,
                                 media_content_id=None):
        """Implement the websocket media browsing helper."""
        if media_content_id not in (None, "root"):
            raise BrowseError(
                f"Media not found: {media_content_type} / {media_content_id}")

        presets = self._state.get_preset_details()

        radio = [
            BrowseMedia(
                title=preset.name,
                media_class=MEDIA_CLASS_MUSIC,
                media_content_id=f"preset:{preset.index}",
                media_content_type=MEDIA_TYPE_MUSIC,
                can_play=True,
                can_expand=False,
            ) for preset in presets.values()
        ]

        root = BrowseMedia(
            title="Root",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_id="root",
            media_content_type="library",
            can_play=False,
            can_expand=True,
            children=radio,
        )

        return root
示例#3
0
async def library_payload(player):
    """Create response payload to describe contents of library."""

    library_info = {
        "title": "Music Library",
        "media_class": MEDIA_CLASS_DIRECTORY,
        "media_content_id": "library",
        "media_content_type": "library",
        "can_play": False,
        "can_expand": True,
        "children": [],
    }

    for item in LIBRARY:
        media_class = CONTENT_TYPE_MEDIA_CLASS[item]
        result = await player.async_browse(
            MEDIA_TYPE_TO_SQUEEZEBOX[item],
            limit=1,
        )
        if result is not None and result.get("items") is not None:
            library_info["children"].append(
                BrowseMedia(
                    title=item,
                    media_class=media_class["children"],
                    media_content_id=item,
                    media_content_type=item,
                    can_play=True,
                    can_expand=True,
                ))

    response = BrowseMedia(**library_info)
    return response
示例#4
0
def library_payload():
    """
    Create response payload to describe contents of a specific library.

    Used by async_browse_media.
    """
    library_info = {
        "title": "Media Library",
        "media_class": MEDIA_CLASS_DIRECTORY,
        "media_content_id": "library",
        "media_content_type": "library",
        "can_play": False,
        "can_expand": True,
        "children": [],
    }

    for item in [{"name": n, "type": t} for t, n in LIBRARY_MAP.items()]:
        library_info["children"].append(
            item_payload({
                "name": item["name"],
                "type": item["type"],
                "uri": item["type"]
            }))
    response = BrowseMedia(**library_info)
    response.children_media_class = MEDIA_CLASS_DIRECTORY
    return response
示例#5
0
    async def async_browse_media_channels(self, expanded):
        """Return channel media objects."""
        if expanded:
            children = [
                BrowseMedia(
                    title=channel.get("name", f"Channel: {channel_id}"),
                    media_class=MEDIA_CLASS_CHANNEL,
                    media_content_id=f"alltv/{channel_id}",
                    media_content_type=MEDIA_TYPE_CHANNEL,
                    can_play=True,
                    can_expand=False,
                ) for channel_id, channel in self._tv.channels.items()
            ]
        else:
            children = None

        return BrowseMedia(
            title="Channels",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_id="channels",
            media_content_type=MEDIA_TYPE_CHANNELS,
            children_media_class=MEDIA_CLASS_CHANNEL,
            can_play=False,
            can_expand=True,
            children=children,
        )
示例#6
0
 def playlists_payload():
     """Create response payload for all available playlists."""
     playlists_info = {**PLAYLISTS_BROWSE_PAYLOAD, "children": []}
     for playlist in entity.plex_server.playlists():
         try:
             playlists_info["children"].append(item_payload(playlist))
         except UnknownMediaType:
             continue
     response = BrowseMedia(**playlists_info)
     response.children_media_class = MEDIA_CLASS_PLAYLIST
     return response
示例#7
0
def library_payload(media_library, get_thumbnail_url=None):
    """
    Create response payload to describe contents of a specific library.

    Used by async_browse_media.
    """
    if not media_library.browse_by_idstring(
            "tracks",
            "",
            max_items=1,
    ):
        raise BrowseError("Local library not found")

    children = []
    for item in media_library.browse():
        with suppress(UnknownMediaType):
            children.append(item_payload(item, get_thumbnail_url))

    return BrowseMedia(
        title="Music Library",
        media_class=MEDIA_CLASS_DIRECTORY,
        media_content_id="library",
        media_content_type="library",
        can_play=False,
        can_expand=True,
        children=children,
    )
示例#8
0
async def browse_node(entity, media_library, media_content_type,
                      media_content_id):
    """Browse a node of a Volumio media hierarchy."""
    json_item = json.loads(media_content_id)
    navigation = await media_library.browse(json_item["uri"])
    if "lists" not in navigation:
        raise BrowseError(
            f"Media not found: {media_content_type} / {media_content_id}")

    # we only use the first list since the second one could include all tracks
    first_list = navigation["lists"][0]
    children = [
        _item_payload(entity, item, parent_item=json_item)
        for item in first_list["items"]
    ]
    info = navigation.get("info")
    title = first_list.get("title")
    if not title:
        if info:
            title = f"{info.get('album')} ({info.get('artist')})"
        else:
            title = "Media Library"

    payload = _raw_item_payload(entity, json_item, title=title, info=info)
    return BrowseMedia(**payload, children=children)
示例#9
0
    def item_payload(item):
        """Create response payload for a single media item."""
        try:
            media_class = ITEM_TYPE_MEDIA_CLASS[item.type]
        except KeyError as err:
            _LOGGER.debug("Unknown type received: %s", item.type)
            raise UnknownMediaType from err
        payload = {
            "title": item.title,
            "media_class": media_class,
            "media_content_id": str(item.ratingKey),
            "media_content_type": item.type,
            "can_play": True,
            "can_expand": item.type in EXPANDABLES,
        }
        if hasattr(item, "thumbUrl"):
            entity.plex_server.thumbnail_cache.setdefault(
                str(item.ratingKey), item.thumbUrl)

            if is_internal:
                thumbnail = item.thumbUrl
            else:
                thumbnail = entity.get_browse_image_url(
                    item.type, item.ratingKey)

            payload["thumbnail"] = thumbnail

        return BrowseMedia(**payload)
示例#10
0
def library_payload(roon_server, zone_id, media_content_id):
    """Create response payload for the library."""

    opts = {
        "hierarchy": "browse",
        "zone_or_output_id": zone_id,
        "count": ITEM_LIMIT,
    }

    # Roon starts browsing for a zone where it left off - so start from the top unless otherwise specified
    if media_content_id is None or media_content_id == "Explore":
        opts["pop_all"] = True
        content_id = "Explore"
    else:
        opts["item_key"] = media_content_id
        content_id = media_content_id

    result_header = roon_server.roonapi.browse_browse(opts)
    _LOGGER.debug("Result header %s", result_header)

    header = result_header["list"]
    title = header.get("title")

    subtitle = header.get("subtitle")
    if subtitle is None:
        list_title = title
    else:
        list_title = f"{title} ({subtitle})"

    total_count = header["count"]

    library_image_id = header.get("image_key")

    library_info = BrowseMedia(
        title=list_title,
        media_content_id=content_id,
        media_content_type="library",
        media_class=MEDIA_CLASS_DIRECTORY,
        can_play=False,
        can_expand=True,
        children=[],
    )

    result_detail = roon_server.roonapi.browse_load(opts)
    _LOGGER.debug("Result detail %s", result_detail)

    items = result_detail["items"]
    count = len(items)

    if count < total_count:
        _LOGGER.debug("Exceeded limit of %d, loaded %d/%d", ITEM_LIMIT, count,
                      total_count)

    for item in items:
        if item.get("title") in EXCLUDE_ITEMS:
            continue
        entry = item_payload(roon_server, item, library_image_id)
        library_info.children.append(entry)

    return library_info
示例#11
0
def item_payload(item, coordinator, get_thumbnail_url=None):
    """
    Create response payload for a single media item.

    Used by async_browse_media.
    """
    thumbnail = None

    if "app_id" in item:
        media_content_type = MEDIA_TYPE_APP
        media_content_id = item["app_id"]
        if get_thumbnail_url:
            thumbnail = get_thumbnail_url(media_content_type, media_content_id)
    elif "channel_number" in item:
        media_content_type = MEDIA_TYPE_CHANNEL
        media_content_id = item["channel_number"]
    else:
        media_content_type = item["type"]
        media_content_id = ""

    title = item["title"]
    can_play = media_content_type in PLAYABLE_MEDIA_TYPES and media_content_id
    can_expand = media_content_type in EXPANDABLE_MEDIA_TYPES

    return BrowseMedia(
        title=title,
        media_class=CONTENT_TYPE_MEDIA_CLASS[media_content_type],
        media_content_type=media_content_type,
        media_content_id=media_content_id,
        can_play=can_play,
        can_expand=can_expand,
        thumbnail=thumbnail,
    )
示例#12
0
def item_payload(item, get_thumbnail_url=None):
    """
    Create response payload for a single media item.

    Used by async_browse_media.
    """
    media_type = get_media_type(item)
    try:
        media_class = SONOS_TO_MEDIA_CLASSES[media_type]
    except KeyError as err:
        _LOGGER.debug("Unknown media type received %s", media_type)
        raise UnknownMediaType from err

    content_id = get_content_id(item)
    thumbnail = None
    if getattr(item, "album_art_uri", None):
        thumbnail = get_thumbnail_url(media_class, content_id)

    return BrowseMedia(
        title=item.title,
        thumbnail=thumbnail,
        media_class=media_class,
        media_content_id=content_id,
        media_content_type=SONOS_TO_MEDIA_TYPES[media_type],
        can_play=can_play(item.item_class),
        can_expand=can_expand(item),
    )
示例#13
0
def library_payload(coordinator, get_thumbnail_url=None):
    """
    Create response payload to describe contents of a specific library.

    Used by async_browse_media.
    """
    library_info = BrowseMedia(
        media_class=MEDIA_CLASS_DIRECTORY,
        media_content_id="library",
        media_content_type="library",
        title="Media Library",
        can_play=False,
        can_expand=True,
        children=[],
    )

    library = {
        MEDIA_TYPE_APPS: "Apps",
        MEDIA_TYPE_CHANNELS: "Channels",
    }

    for item in [{
            "title": name,
            "type": type_
    } for type_, name in library.items()]:
        if (item["type"] == MEDIA_TYPE_CHANNELS
                and coordinator.data.info.device_type != "tv"):
            continue

        library_info.children.append(
            item_payload(
                {
                    "title": item["title"],
                    "type": item["type"]
                },
                coordinator,
                get_thumbnail_url,
            ))

    if all(child.media_content_type == MEDIA_TYPE_APPS
           for child in library_info.children):
        library_info.children_media_class = MEDIA_CLASS_APP
    elif all(child.media_content_type == MEDIA_TYPE_CHANNELS
             for child in library_info.children):
        library_info.children_media_class = MEDIA_CLASS_CHANNEL

    return library_info
示例#14
0
def build_item_response(media_library, payload, get_thumbnail_url=None):
    """Create response payload for the provided media query."""
    if payload["search_type"] == MEDIA_TYPE_ALBUM and payload[
            "idstring"].startswith(("A:GENRE", "A:COMPOSER")):
        payload["idstring"] = "A:ALBUMARTIST/" + "/".join(
            payload["idstring"].split("/")[2:])

    media = media_library.browse_by_idstring(
        MEDIA_TYPES_TO_SONOS[payload["search_type"]],
        payload["idstring"],
        full_album_art_uri=True,
        max_items=0,
    )

    if media is None:
        return

    thumbnail = None
    title = None

    # Fetch album info for titles and thumbnails
    # Can't be extracted from track info
    if (payload["search_type"] == MEDIA_TYPE_ALBUM
            and media[0].item_class == "object.item.audioItem.musicTrack"):
        item = get_media(media_library, payload["idstring"],
                         SONOS_ALBUM_ARTIST)
        title = getattr(item, "title", None)
        thumbnail = get_thumbnail_url(SONOS_ALBUM_ARTIST, payload["idstring"])

    if not title:
        try:
            title = urllib.parse.unquote(payload["idstring"].split("/")[1])
        except IndexError:
            title = LIBRARY_TITLES_MAPPING[payload["idstring"]]

    try:
        media_class = SONOS_TO_MEDIA_CLASSES[MEDIA_TYPES_TO_SONOS[
            payload["search_type"]]]
    except KeyError:
        _LOGGER.debug("Unknown media type received %s", payload["search_type"])
        return None

    children = []
    for item in media:
        with suppress(UnknownMediaType):
            children.append(item_payload(item, get_thumbnail_url))

    return BrowseMedia(
        title=title,
        thumbnail=thumbnail,
        media_class=media_class,
        media_content_id=payload["idstring"],
        media_content_type=payload["search_type"],
        children=children,
        can_play=can_play(payload["search_type"]),
        can_expand=can_expand(payload["search_type"]),
    )
示例#15
0
def _list_payload(item, children=None):
    return BrowseMedia(
        title=item["name"],
        media_class=MEDIA_CLASS_DIRECTORY,
        children_media_class=_item_to_children_media_class(item),
        media_content_type=MEDIA_TYPE_MUSIC,
        media_content_id=json.dumps(item),
        can_play=False,
        can_expand=True,
    )
示例#16
0
def special_library_payload(parent_payload, special_type):
    """Create response payload for special library folders."""
    title = f"{special_type} ({parent_payload.title})"
    return BrowseMedia(
        title=title,
        media_class=parent_payload.media_class,
        media_content_id=f"{parent_payload.media_content_id}:{special_type}",
        media_content_type=parent_payload.media_content_type,
        can_play=False,
        can_expand=True,
        children_media_class=parent_payload.children_media_class,
    )
示例#17
0
def server_payload(plex_server):
    """Create response payload to describe libraries of the Plex server."""
    server_info = BrowseMedia(
        title=plex_server.friendly_name,
        media_class=MEDIA_CLASS_DIRECTORY,
        media_content_id=plex_server.machine_identifier,
        media_content_type="server",
        can_play=False,
        can_expand=True,
        children_media_class=MEDIA_CLASS_DIRECTORY,
    )
    server_info.children = []
    server_info.children.append(special_library_payload(
        server_info, "On Deck"))
    server_info.children.append(
        special_library_payload(server_info, "Recently Added"))
    for library in plex_server.library.sections():
        if library.type == "photo":
            continue
        server_info.children.append(library_section_payload(library))
    server_info.children.append(BrowseMedia(**PLAYLISTS_BROWSE_PAYLOAD))
    return server_info
示例#18
0
async def browse_top_level(media_library):
    """Browse the top-level of a Volumio media hierarchy."""
    navigation = await media_library.browse()
    children = [_list_payload(item) for item in navigation["lists"]]
    return BrowseMedia(
        media_class=MEDIA_CLASS_DIRECTORY,
        media_content_id="library",
        media_content_type="library",
        title="Media Library",
        can_play=False,
        can_expand=True,
        children=children,
    )
示例#19
0
async def library_payload():
    """
    Create response payload to describe contents of a specific library.

    Used by async_browse_media.
    """
    library_info = BrowseMedia(
        media_class=MEDIA_CLASS_DIRECTORY,
        media_content_id="library",
        media_content_type="library",
        title="Media Library",
        can_play=False,
        can_expand=True,
        children=[],
    )

    library = {
        "library_music": "Music",
        MEDIA_TYPE_MOVIE: "Movies",
        MEDIA_TYPE_TVSHOW: "TV shows",
        MEDIA_TYPE_CHANNEL: "Channels",
    }

    library_info.children = await asyncio.gather(
        *[
            item_payload(
                {
                    "label": item["label"],
                    "type": item["type"],
                    "uri": item["type"],
                },
            )
            for item in [
                {"label": name, "type": type_} for type_, name in library.items()
            ]
        ]
    )

    return library_info
示例#20
0
    async def async_browse_media_favorites(self, list_id, expanded):
        """Return channel media objects."""
        if expanded:
            favorites = await self._tv.getFavoriteList(list_id)
            if favorites:

                def get_name(channel):
                    channel_data = self._tv.channels.get(str(channel["ccid"]))
                    if channel_data:
                        return channel_data["name"]
                    return f"Channel: {channel['ccid']}"

                children = [
                    BrowseMedia(
                        title=get_name(channel),
                        media_class=MEDIA_CLASS_CHANNEL,
                        media_content_id=f"{list_id}/{channel['ccid']}",
                        media_content_type=MEDIA_TYPE_CHANNEL,
                        can_play=True,
                        can_expand=False,
                    ) for channel in favorites
                ]
            else:
                children = None
        else:
            children = None

        favorite = self._tv.favorite_lists[list_id]
        return BrowseMedia(
            title=favorite.get("name", f"Favorites {list_id}"),
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_id=f"favorites/{list_id}",
            media_content_type=MEDIA_TYPE_CHANNELS,
            children_media_class=MEDIA_CLASS_CHANNEL,
            can_play=False,
            can_expand=True,
            children=children,
        )
示例#21
0
async def build_item_response(media_library, payload, get_thumbnail_url=None):
    """Create response payload for the provided media query."""
    search_id = payload["search_id"]
    search_type = payload["search_type"]

    _, title, media = await get_media_info(media_library, search_id, search_type)
    thumbnail = await get_thumbnail_url(search_type, search_id)

    if media is None:
        return None

    children = await asyncio.gather(
        *[item_payload(item, get_thumbnail_url) for item in media]
    )

    if search_type in (MEDIA_TYPE_TVSHOW, MEDIA_TYPE_MOVIE) and search_id == "":
        children.sort(key=lambda x: x.title.replace("The ", "", 1), reverse=False)

    response = BrowseMedia(
        media_class=CONTAINER_TYPES_SPECIFIC_MEDIA_CLASS.get(
            search_type, MEDIA_CLASS_DIRECTORY
        ),
        media_content_id=search_id,
        media_content_type=search_type,
        title=title,
        can_play=search_type in PLAYABLE_MEDIA_TYPES and search_id,
        can_expand=True,
        children=children,
        thumbnail=thumbnail,
    )

    if search_type == "library_music":
        response.children_media_class = MEDIA_CLASS_MUSIC
    else:
        response.calculate_children_class()

    return response
示例#22
0
    async def async_browse_media_root(self):
        """Return root media objects."""

        return BrowseMedia(
            title="Library",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_id="",
            media_content_type="",
            can_play=False,
            can_expand=True,
            children=[
                await self.async_browse_media_channels(False),
                await self.async_browse_media_applications(False),
                await self.async_browse_media_favorite_lists(False),
            ],
        )
示例#23
0
def library_section_payload(section):
    """Create response payload for a single library section."""
    try:
        children_media_class = ITEM_TYPE_MEDIA_CLASS[section.TYPE]
    except KeyError as err:
        _LOGGER.debug("Unknown type received: %s", section.TYPE)
        raise UnknownMediaType from err
    return BrowseMedia(
        title=section.title,
        media_class=MEDIA_CLASS_DIRECTORY,
        media_content_id=str(section.key),
        media_content_type="library",
        can_play=False,
        can_expand=True,
        children_media_class=children_media_class,
    )
示例#24
0
def item_payload(roon_server, item, list_image_id):
    """Create response payload for a single media item."""

    title = item["title"]
    subtitle = item.get("subtitle")
    if subtitle is None:
        display_title = title
    else:
        display_title = f"{title} ({subtitle})"

    image_id = item.get("image_key") or list_image_id

    image = None
    if image_id:
        image = roon_server.roonapi.get_image(image_id)

    media_content_id = item["item_key"]
    media_content_type = "library"

    hint = item.get("hint")
    if hint == "list":
        media_class = MEDIA_CLASS_DIRECTORY
        can_expand = True
    elif hint == "action_list":
        media_class = MEDIA_CLASS_PLAYLIST
        can_expand = False
    elif hint == "action":
        media_content_type = "track"
        media_class = MEDIA_CLASS_TRACK
        can_expand = False
    else:
        # Roon API says to treat unknown as a list
        media_class = MEDIA_CLASS_DIRECTORY
        can_expand = True
        _LOGGER.warning("Unknown hint %s - %s", title, hint)

    payload = {
        "title": display_title,
        "media_class": media_class,
        "media_content_id": media_content_id,
        "media_content_type": media_content_type,
        "can_play": True,
        "can_expand": can_expand,
        "thumbnail": image,
    }

    return BrowseMedia(**payload)
示例#25
0
def build_item_response(coordinator, payload, get_thumbnail_url=None):
    """Create response payload for the provided media query."""
    search_id = payload["search_id"]
    search_type = payload["search_type"]

    thumbnail = None
    title = None
    media = None
    children_media_class = None

    if search_type == MEDIA_TYPE_APPS:
        title = "Apps"
        media = [{
            "app_id": item.app_id,
            "title": item.name,
            "type": MEDIA_TYPE_APP
        } for item in coordinator.data.apps]
        children_media_class = MEDIA_CLASS_APP
    elif search_type == MEDIA_TYPE_CHANNELS:
        title = "Channels"
        media = [{
            "channel_number": item.number,
            "title": item.name,
            "type": MEDIA_TYPE_CHANNEL,
        } for item in coordinator.data.channels]
        children_media_class = MEDIA_CLASS_CHANNEL

    if media is None:
        return None

    return BrowseMedia(
        media_class=CONTAINER_TYPES_SPECIFIC_MEDIA_CLASS.get(
            search_type, MEDIA_CLASS_DIRECTORY),
        media_content_id=search_id,
        media_content_type=search_type,
        title=title,
        can_play=search_type in PLAYABLE_MEDIA_TYPES and search_id,
        can_expand=True,
        children=[
            item_payload(item, coordinator, get_thumbnail_url)
            for item in media
        ],
        children_media_class=children_media_class,
        thumbnail=thumbnail,
    )
示例#26
0
def item_payload(item: InstalledPackage, images: dict[str, list[Image]]):
    """Create response payload for a single media item."""
    thumbnail = None
    image = _find_media_image(images.get(item.one_store_product_id, []))
    if image is not None:
        thumbnail = image.uri
        if thumbnail[0] == "/":
            thumbnail = f"https:{thumbnail}"

    return BrowseMedia(
        media_class=TYPE_MAP[item.content_type]["class"],
        media_content_id=item.one_store_product_id,
        media_content_type=TYPE_MAP[item.content_type]["type"],
        title=item.name,
        can_play=True,
        can_expand=False,
        thumbnail=thumbnail,
    )
示例#27
0
    async def async_browse_media_favorite_lists(self, expanded):
        """Return favorite media objects."""
        if self._tv.favorite_lists and expanded:
            children = [
                await self.async_browse_media_favorites(list_id, False)
                for list_id in self._tv.favorite_lists
            ]
        else:
            children = None

        return BrowseMedia(
            title="Favorites",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_id="favorite_lists",
            media_content_type=MEDIA_TYPE_CHANNELS,
            children_media_class=MEDIA_CLASS_CHANNEL,
            can_play=False,
            can_expand=True,
            children=children,
        )
示例#28
0
def item_payload(item):
    """
    Create response payload for a single media item.

    Used by async_browse_media.
    """
    try:
        media_type = item["type"]
        media_id = item["uri"]
    except KeyError as err:
        _LOGGER.debug("Missing type or URI for media item: %s", item)
        raise MissingMediaInformation from err

    try:
        media_class = CONTENT_TYPE_MEDIA_CLASS[media_type]
    except KeyError as err:
        _LOGGER.debug("Unknown media type received: %s", media_type)
        raise UnknownMediaType from err

    can_expand = media_type not in [
        MEDIA_TYPE_TRACK,
        MEDIA_TYPE_EPISODE,
    ]

    payload = {
        "title": item.get("name"),
        "media_class": media_class["parent"],
        "children_media_class": media_class["children"],
        "media_content_id": media_id,
        "media_content_type": media_type,
        "can_play": media_type in PLAYABLE_MEDIA_TYPES,
        "can_expand": can_expand,
    }

    if "images" in item:
        payload["thumbnail"] = fetch_image_url(item)
    elif MEDIA_TYPE_ALBUM in item:
        payload["thumbnail"] = fetch_image_url(item[MEDIA_TYPE_ALBUM])

    return BrowseMedia(**payload)
示例#29
0
async def build_item_response(entity, player, payload):
    """Create response payload for search described by payload."""
    internal_request = is_internal_request(entity.opp)

    search_id = payload["search_id"]
    search_type = payload["search_type"]

    media_class = CONTENT_TYPE_MEDIA_CLASS[search_type]

    if search_id and search_id != search_type:
        browse_id = (SQUEEZEBOX_ID_BY_TYPE[search_type], search_id)
    else:
        browse_id = None

    result = await player.async_browse(
        MEDIA_TYPE_TO_SQUEEZEBOX[search_type],
        limit=BROWSE_LIMIT,
        browse_id=browse_id,
    )

    children = None

    if result is not None and result.get("items"):
        item_type = CONTENT_TYPE_TO_CHILD_TYPE[search_type]
        child_media_class = CONTENT_TYPE_MEDIA_CLASS[item_type]

        children = []
        for item in result["items"]:
            item_id = str(item["id"])
            item_thumbnail = None

            artwork_track_id = item.get("artwork_track_id")
            if artwork_track_id:
                if internal_request:
                    item_thumbnail = player.generate_image_url_from_track_id(
                        artwork_track_id)
                else:
                    item_thumbnail = entity.get_browse_image_url(
                        item_type, item_id, artwork_track_id)

            children.append(
                BrowseMedia(
                    title=item["title"],
                    media_class=child_media_class["item"],
                    media_content_id=item_id,
                    media_content_type=item_type,
                    can_play=True,
                    can_expand=child_media_class["children"] is not None,
                    thumbnail=item_thumbnail,
                ))

    if children is None:
        raise BrowseError(f"Media not found: {search_type} / {search_id}")

    return BrowseMedia(
        title=result.get("title"),
        media_class=media_class["item"],
        children_media_class=media_class["children"],
        media_content_id=search_id,
        media_content_type=search_type,
        can_play=True,
        children=children,
        can_expand=True,
    )
示例#30
0
def browse_media(  # noqa: C901
        entity,
        is_internal,
        media_content_type=None,
        media_content_id=None):
    """Implement the websocket media browsing helper."""
    def item_payload(item):
        """Create response payload for a single media item."""
        try:
            media_class = ITEM_TYPE_MEDIA_CLASS[item.type]
        except KeyError as err:
            _LOGGER.debug("Unknown type received: %s", item.type)
            raise UnknownMediaType from err
        payload = {
            "title": item.title,
            "media_class": media_class,
            "media_content_id": str(item.ratingKey),
            "media_content_type": item.type,
            "can_play": True,
            "can_expand": item.type in EXPANDABLES,
        }
        if hasattr(item, "thumbUrl"):
            entity.plex_server.thumbnail_cache.setdefault(
                str(item.ratingKey), item.thumbUrl)

            if is_internal:
                thumbnail = item.thumbUrl
            else:
                thumbnail = entity.get_browse_image_url(
                    item.type, item.ratingKey)

            payload["thumbnail"] = thumbnail

        return BrowseMedia(**payload)

    def library_payload(library_id):
        """Create response payload to describe contents of a specific library."""
        library = entity.plex_server.library.sectionByID(library_id)
        library_info = library_section_payload(library)
        library_info.children = []
        library_info.children.append(
            special_library_payload(library_info, "On Deck"))
        library_info.children.append(
            special_library_payload(library_info, "Recently Added"))
        for item in library.all():
            try:
                library_info.children.append(item_payload(item))
            except UnknownMediaType:
                continue
        return library_info

    def playlists_payload():
        """Create response payload for all available playlists."""
        playlists_info = {**PLAYLISTS_BROWSE_PAYLOAD, "children": []}
        for playlist in entity.plex_server.playlists():
            try:
                playlists_info["children"].append(item_payload(playlist))
            except UnknownMediaType:
                continue
        response = BrowseMedia(**playlists_info)
        response.children_media_class = MEDIA_CLASS_PLAYLIST
        return response

    def build_item_response(payload):
        """Create response payload for the provided media query."""
        media = entity.plex_server.lookup_media(**payload)

        if media is None:
            return None

        try:
            media_info = item_payload(media)
        except UnknownMediaType:
            return None
        if media_info.can_expand:
            media_info.children = []
            for item in media:
                try:
                    media_info.children.append(item_payload(item))
                except UnknownMediaType:
                    continue
        return media_info

    if media_content_id and ":" in media_content_id:
        media_content_id, special_folder = media_content_id.split(":")
    else:
        special_folder = None

    if (media_content_type and media_content_type == "server"
            and media_content_id != entity.plex_server.machine_identifier):
        raise BrowseError(
            f"Plex server with ID '{media_content_id}' is not associated with {entity.entity_id}"
        )

    if special_folder:
        if media_content_type == "server":
            library_or_section = entity.plex_server.library
            children_media_class = MEDIA_CLASS_DIRECTORY
            title = entity.plex_server.friendly_name
        elif media_content_type == "library":
            library_or_section = entity.plex_server.library.sectionByID(
                int(media_content_id))
            title = library_or_section.title
            try:
                children_media_class = ITEM_TYPE_MEDIA_CLASS[
                    library_or_section.TYPE]
            except KeyError as err:
                raise BrowseError(
                    f"Unknown type received: {library_or_section.TYPE}"
                ) from err
        else:
            raise BrowseError(
                f"Media not found: {media_content_type} / {media_content_id}")

        payload = {
            "title": title,
            "media_class": MEDIA_CLASS_DIRECTORY,
            "media_content_id": f"{media_content_id}:{special_folder}",
            "media_content_type": media_content_type,
            "can_play": False,
            "can_expand": True,
            "children": [],
            "children_media_class": children_media_class,
        }

        method = SPECIAL_METHODS[special_folder]
        items = getattr(library_or_section, method)()
        for item in items:
            try:
                payload["children"].append(item_payload(item))
            except UnknownMediaType:
                continue

        return BrowseMedia(**payload)

    try:
        if media_content_type in ["server", None]:
            return server_payload(entity.plex_server)

        if media_content_type == "library":
            return library_payload(int(media_content_id))

    except UnknownMediaType as err:
        raise BrowseError(
            f"Media not found: {media_content_type} / {media_content_id}"
        ) from err

    if media_content_type == "playlists":
        return playlists_payload()

    payload = {
        "media_type": DOMAIN,
        "plex_key": int(media_content_id),
    }
    response = build_item_response(payload)
    if response is None:
        raise BrowseError(
            f"Media not found: {media_content_type} / {media_content_id}")
    return response