示例#1
0
def _build_root_paths(
    entry: ConfigEntry,
    media_directories: MediaDirectories,
) -> BrowseMediaSource:
    """Build base categories for System Bridge media."""
    return BrowseMediaSource(
        domain=DOMAIN,
        identifier="",
        media_class=MEDIA_CLASS_DIRECTORY,
        media_content_type="",
        title=entry.title,
        can_play=False,
        can_expand=True,
        children=[
            BrowseMediaSource(
                domain=DOMAIN,
                identifier=f"{entry.entry_id}~~{directory.key}",
                media_class=MEDIA_CLASS_DIRECTORY,
                media_content_type="",
                title=f"{directory.key[:1].capitalize()}{directory.key[1:]}",
                can_play=False,
                can_expand=True,
                children=[],
                children_media_class=MEDIA_CLASS_DIRECTORY,
            ) for directory in media_directories.directories
        ],
        children_media_class=MEDIA_CLASS_DIRECTORY,
    )
示例#2
0
    def _build_bridges(self) -> BrowseMediaSource:
        """Build bridges for System Bridge media."""
        children = []
        for entry in self.hass.config_entries.async_entries(DOMAIN):
            if entry.entry_id is not None:
                children.append(
                    BrowseMediaSource(
                        domain=DOMAIN,
                        identifier=entry.entry_id,
                        media_class=MEDIA_CLASS_DIRECTORY,
                        media_content_type="",
                        title=entry.title,
                        can_play=False,
                        can_expand=True,
                        children=[],
                        children_media_class=MEDIA_CLASS_DIRECTORY,
                    ))

        return BrowseMediaSource(
            domain=DOMAIN,
            identifier="",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_type="",
            title=self.name,
            can_play=False,
            can_expand=True,
            children=children,
            children_media_class=MEDIA_CLASS_DIRECTORY,
        )
    def _browse_recording_folders(self, identifier, folders):
        base = BrowseMediaSource(
            domain=DOMAIN,
            identifier=identifier["original"],
            media_class=MEDIA_CLASS_DIRECTORY,
            children_media_class=MEDIA_CLASS_VIDEO,
            media_content_type=None,
            title=self._generate_recording_title(identifier),
            can_play=False,
            can_expand=True,
            thumbnail=None,
            children=[
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=self._create_recordings_folder_identifier(identifier, folder),
                    media_class=MEDIA_CLASS_DIRECTORY,
                    children_media_class=MEDIA_CLASS_VIDEO,
                    media_content_type=None,
                    title=self._generate_recording_title(identifier, folder),
                    can_play=False,
                    can_expand=True,
                    thumbnail=None
                )
                for folder in folders if not folder['name'].endswith('.mp4')
            ]
        )

        return base
 def _build_main_listing(self):
     """Build main browse listing."""
     parent_source = BrowseMediaSource(
         domain=DOMAIN,
         identifier=None,
         title=self.entry.title,
         media_class=MEDIA_CLASS_CHANNEL,
         media_content_type=MEDIA_TYPE_MUSIC,
         can_play=False,
         can_expand=True,
         children_media_class=MEDIA_CLASS_DIRECTORY,
         children=[],
     )
     for library, media_class in LIBRARY_MEDIA_CLASS_MAP.items():
         child_source = BrowseMediaSource(
             domain=DOMAIN,
             identifier=library,
             title=LIBRARY_TITLE_MAP[library],
             media_class=MEDIA_CLASS_DIRECTORY,
             media_content_type=MEDIA_TYPE_MUSIC,
             children_media_class=media_class,
             can_play=False,
             can_expand=True,
         )
         parent_source.children.append(child_source)
     return parent_source
示例#5
0
    async def async_browse_search(self, query: str) -> BrowseMediaSource:
        """Return all media items found by the query string."""
        assert self._device

        result = await self._device.async_search_directory(
            container_id=ROOT_OBJECT_ID,
            search_criteria=query,
            metadata_filter=DLNA_BROWSE_FILTER,
        )

        children = [
            self._didl_to_media_source(child) for child in result.result
            if isinstance(child, didl_lite.DidlObject)
        ]

        media_source = BrowseMediaSource(
            domain=DOMAIN,
            identifier=self._make_identifier(Action.SEARCH, query),
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_type="",
            title="Search results",
            can_play=False,
            can_expand=True,
            children=children,
        )

        if media_source.children:
            media_source.calculate_children_class()

        return media_source
    def _browse_recordings(self, identifier, recordings):
        base = BrowseMediaSource(
            domain=DOMAIN,
            identifier=identifier["original"],
            media_class=MEDIA_CLASS_DIRECTORY,
            children_media_class=MEDIA_CLASS_VIDEO,
            media_content_type=None,
            title=self._generate_recording_title(identifier),
            can_play=False,
            can_expand=True,
            thumbnail=None,
            children=[
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=f"{identifier['original']}/{recording['name']}",
                    media_class=MEDIA_CLASS_VIDEO,
                    media_content_type=MEDIA_TYPE_VIDEO,
                    title=self._generate_recording_title(identifier, recording),
                    can_play=True,
                    can_expand=False,
                    thumbnail=None,
                )
                for recording in recordings
            ]
        )

        return base
示例#7
0
def _build_categories(title):
    """Build base categories for Xbox media."""
    _, name, thumbnail = title.split("#", 2)
    base = BrowseMediaSource(
        domain=DOMAIN,
        identifier=f"{title}",
        media_class=MEDIA_CLASS_GAME,
        media_content_type="",
        title=name,
        can_play=False,
        can_expand=True,
        children=[],
        children_media_class=MEDIA_CLASS_DIRECTORY,
        thumbnail=thumbnail,
    )

    owners = ["my", "community"]
    kinds = ["gameclips", "screenshots"]
    for owner in owners:
        for kind in kinds:
            base.children.append(
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=f"{title}~~{owner}#{kind}",
                    media_class=MEDIA_CLASS_DIRECTORY,
                    media_content_type="",
                    title=f"{owner.title()} {kind.title()}",
                    can_play=False,
                    can_expand=True,
                    children_media_class=MEDIA_CLASS_MAP[kind],
                )
            )

    return base
示例#8
0
    async def _build_recent(
        self,
        data: ProtectData,
        camera_id: str,
        event_type: SimpleEventType,
        days: int,
        build_children: bool = False,
    ) -> BrowseMediaSource:
        """Build media source for events in relative days."""

        base_id = f"{data.api.bootstrap.nvr.id}:browse:{camera_id}:{event_type.value}"
        title = f"Last {days} Days"
        if days == 1:
            title = "Last 24 Hours"

        source = BrowseMediaSource(
            domain=DOMAIN,
            identifier=f"{base_id}:recent:{days}",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_type="video/mp4",
            title=title,
            can_play=False,
            can_expand=True,
            children_media_class=MEDIA_CLASS_VIDEO,
        )

        if not build_children:
            return source

        now = dt_util.now()

        args = {
            "data": data,
            "start": now - timedelta(days=days),
            "end": now,
            "reserve": True,
        }
        if event_type != SimpleEventType.ALL:
            args["event_type"] = get_ufp_event(event_type)

        camera: Camera | None = None
        if camera_id != "all":
            camera = data.api.bootstrap.cameras.get(camera_id)
            args["camera_id"] = camera_id

        events = await self._build_events(**args)  # type: ignore[arg-type]
        source.children = events
        source.title = self._breadcrumb(
            data,
            title,
            camera=camera,
            event_type=event_type,
            count=len(events),
        )
        return source
示例#9
0
    async def _async_build_by_tag(
        self, item: MediaSourceItem
    ) -> list[BrowseMediaSource]:
        """Handle browsing radio stations by tags."""
        category, _, tag = (item.identifier or "").partition("/")
        if category == "tag" and tag:
            stations = await self.radios.stations(
                filter_by=FilterBy.TAG_EXACT,
                filter_term=tag,
                hide_broken=True,
                order=Order.NAME,
                reverse=False,
            )
            return self._async_build_stations(stations)

        if category == "tag":
            tags = await self.radios.tags(
                hide_broken=True,
                limit=100,
                order=Order.STATION_COUNT,
                reverse=True,
            )

            # Now we have the top tags, reorder them by name
            tags.sort(key=lambda tag: tag.name)

            return [
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=f"tag/{tag.name}",
                    media_class=MEDIA_CLASS_DIRECTORY,
                    media_content_type=MEDIA_TYPE_MUSIC,
                    title=tag.name.title(),
                    can_play=False,
                    can_expand=True,
                )
                for tag in tags
            ]

        if not item.identifier:
            return [
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier="tag",
                    media_class=MEDIA_CLASS_DIRECTORY,
                    media_content_type=MEDIA_TYPE_MUSIC,
                    title="By Category",
                    can_play=False,
                    can_expand=True,
                )
            ]

        return []
示例#10
0
    async def _build_month(
        self,
        data: ProtectData,
        camera_id: str,
        event_type: SimpleEventType,
        start: date,
        build_children: bool = False,
    ) -> BrowseMediaSource:
        """Build media source for selectors for a given month."""

        base_id = f"{data.api.bootstrap.nvr.id}:browse:{camera_id}:{event_type.value}"

        title = f"{start.strftime('%B %Y')}"
        source = BrowseMediaSource(
            domain=DOMAIN,
            identifier=f"{base_id}:range:{start.year}:{start.month}",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_type=VIDEO_FORMAT,
            title=title,
            can_play=False,
            can_expand=True,
            children_media_class=MEDIA_CLASS_VIDEO,
        )

        if not build_children:
            return source

        month = start.month
        children = [
            self._build_days(data, camera_id, event_type, start, is_all=True)
        ]
        while start.month == month:
            children.append(
                self._build_days(data,
                                 camera_id,
                                 event_type,
                                 start,
                                 is_all=False))
            start = start + timedelta(hours=24)

        camera: Camera | None = None
        if camera_id != "all":
            camera = data.api.bootstrap.cameras.get(camera_id)

        source.children = await asyncio.gather(*children)
        source.title = self._breadcrumb(
            data,
            title,
            camera=camera,
            event_type=event_type,
        )

        return source
示例#11
0
    async def async_browse_media(
        self,
        item: MediaSourceItem,
    ) -> BrowseMediaSource:
        """Return media."""
        if item.identifier:
            raise BrowseError("Unknown item")

        can_stream_hls = "stream" in self.hass.config.components

        # Root. List cameras.
        component: EntityComponent = self.hass.data[DOMAIN]
        children = []
        not_shown = 0
        for camera in component.entities:
            camera = cast(Camera, camera)
            stream_type = camera.frontend_stream_type

            if stream_type is None:
                content_type = camera.content_type

            elif can_stream_hls and stream_type == StreamType.HLS:
                content_type = FORMAT_CONTENT_TYPE[HLS_PROVIDER]

            else:
                not_shown += 1
                continue

            children.append(
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=camera.entity_id,
                    media_class=MEDIA_CLASS_VIDEO,
                    media_content_type=content_type,
                    title=camera.name,
                    thumbnail=f"/api/camera_proxy/{camera.entity_id}",
                    can_play=True,
                    can_expand=False,
                ))

        return BrowseMediaSource(
            domain=DOMAIN,
            identifier=None,
            media_class=MEDIA_CLASS_APP,
            media_content_type="",
            title="Camera",
            can_play=False,
            can_expand=True,
            children_media_class=MEDIA_CLASS_VIDEO,
            children=children,
            not_shown=not_shown,
        )
示例#12
0
    async def async_browse_media(self,
                                 item: MediaSourceItem) -> BrowseMediaSource:
        """Browse media."""
        dms_data = get_domain_data(self.hass)
        if not dms_data.sources:
            raise BrowseError("No sources have been configured")

        source_id, media_id = _parse_identifier(item)
        LOGGER.debug("Browsing for %s / %s", source_id, media_id)

        if not source_id and len(dms_data.sources) > 1:
            # Browsing the root of dlna_dms with more than one server, return
            # all known servers.
            base = BrowseMediaSource(
                domain=DOMAIN,
                identifier="",
                media_class=MEDIA_CLASS_DIRECTORY,
                media_content_type=MEDIA_TYPE_CHANNELS,
                title=self.name,
                can_play=False,
                can_expand=True,
                children_media_class=MEDIA_CLASS_CHANNEL,
            )

            base.children = [
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=
                    f"{source_id}/{PATH_OBJECT_ID_FLAG}{ROOT_OBJECT_ID}",
                    media_class=MEDIA_CLASS_CHANNEL,
                    media_content_type=MEDIA_TYPE_CHANNEL,
                    title=source.name,
                    can_play=False,
                    can_expand=True,
                    thumbnail=source.icon,
                ) for source_id, source in dms_data.sources.items()
            ]

            return base

        if not source_id:
            # No source specified, default to the first registered
            source_id = next(iter(dms_data.sources))

        try:
            source = dms_data.sources[source_id]
        except KeyError as err:
            raise BrowseError(f"Unknown source ID: {source_id}") from err

        return await source.async_browse_media(media_id)
示例#13
0
    def _didl_to_media_source(
        self,
        item: didl_lite.DidlObject,
        browsed_children: DmsDevice.BrowseResult | None = None,
    ) -> BrowseMediaSource:
        """Convert a DIDL-Lite object to a browse media source."""
        children: list[BrowseMediaSource] | None = None

        if browsed_children:
            children = [
                self._didl_to_media_source(child)
                for child in browsed_children.result
                if isinstance(child, didl_lite.DidlObject)
            ]

        # Can expand if it has children (even if we don't have them yet), or its
        # a container type. Otherwise the front-end will try to play it (even if
        # can_play is False).
        try:
            child_count = int(item.child_count)
        except (AttributeError, TypeError, ValueError):
            child_count = 0
        can_expand = (bool(children) or child_count > 0
                      or isinstance(item, didl_lite.Container))

        # Can play if item has any resource that can be streamed over the network
        can_play = any(_resource_is_streaming(res) for res in item.res)

        # Use server name for root object, not "root"
        title = self.name if item.id == ROOT_OBJECT_ID else item.title

        mime_type = _resource_mime_type(item.res[0]) if item.res else None
        media_content_type = mime_type or item.upnp_class

        media_source = BrowseMediaSource(
            domain=DOMAIN,
            identifier=self._make_identifier(Action.OBJECT, item.id),
            media_class=MEDIA_CLASS_MAP.get(item.upnp_class, ""),
            media_content_type=media_content_type,
            title=title,
            can_play=can_play,
            can_expand=can_expand,
            children=children,
            thumbnail=self._didl_thumbnail_url(item),
        )

        if media_source.children:
            media_source.calculate_children_class()

        return media_source
示例#14
0
    def _build_item_response(self,
                             iteminfo: ItemInfo,
                             path: Path,
                             is_child=False):
        mime_type, _ = mimetypes.guess_type(str(path))
        is_file = path.is_file()
        is_dir = path.is_dir()

        # Make sure it's a file or directory
        if not is_file and not is_dir:
            return None

        # Check that it's a media file
        if is_file and (not mime_type
                        or mime_type.split("/")[0] not in MEDIA_MIME_TYPES):
            return None

        title = path.name
        if is_dir:
            title += "/"

        media_class = MEDIA_CLASS_MAP.get(
            mime_type and mime_type.split("/")[0], MEDIA_CLASS_DIRECTORY)

        media = BrowseMediaSource(
            domain=DOMAIN,
            identifier=
            f"{iteminfo.entry_id}/{path.relative_to(iteminfo.target_dir)}",
            media_class=media_class,
            media_content_type=mime_type or "",
            title=title,
            can_play=is_file,
            can_expand=is_dir,
        )

        if is_file or is_child:
            return media

        # Append first level children
        media.children = []
        for child_path in path.iterdir():
            child = self._build_item_response(iteminfo, child_path, True)
            if child:
                media.children.append(child)

        # Sort children showing directories first, then by name
        media.children.sort(key=lambda child: (child.can_play, child.title))

        return media
示例#15
0
    async def _async_build_by_country(
            self, radios: RadioBrowser,
            item: MediaSourceItem) -> list[BrowseMediaSource]:
        """Handle browsing radio stations by country."""
        category, _, country_code = (item.identifier or "").partition("/")
        if country_code:
            stations = await radios.stations(
                filter_by=FilterBy.COUNTRY_CODE_EXACT,
                filter_term=country_code,
                hide_broken=True,
                order=Order.NAME,
                reverse=False,
            )
            return self._async_build_stations(radios, stations)

        # We show country in the root additionally, when there is no item
        if not item.identifier or category == "country":
            countries = await radios.countries(order=Order.NAME)
            return [
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=f"country/{country.code}",
                    media_class=MEDIA_CLASS_DIRECTORY,
                    media_content_type=MEDIA_TYPE_MUSIC,
                    title=country.name,
                    can_play=False,
                    can_expand=True,
                    thumbnail=country.favicon,
                ) for country in countries
            ]

        return []
示例#16
0
    def _browse_recordings(
            self, identifier: RecordingIdentifier,
            recordings: list[dict[str, Any]]) -> BrowseMediaSource:
        """Browse Frigate recordings."""
        base = self._get_recording_base_media_source(identifier)

        for recording in recordings:
            title = self._generate_recording_title(identifier, recording)
            if not title:
                _LOGGER.warning("Skipping non-standard recording name: %s",
                                recording["name"])
                continue
            base.children.append(
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=attr.evolve(identifier,
                                           recording_name=recording["name"]),
                    media_class=identifier.media_class,
                    media_content_type=identifier.media_type,
                    title=title,
                    can_play=True,
                    can_expand=False,
                    thumbnail=None,
                ))
        return base
示例#17
0
    async def async_browse_media(
        self,
        item: MediaSourceItem,
    ) -> BrowseMediaSource:
        """Return media."""
        radios = self.radios

        if radios is None:
            raise BrowseError("Radio Browser not initialized")

        return BrowseMediaSource(
            domain=DOMAIN,
            identifier=None,
            media_class=MEDIA_CLASS_CHANNEL,
            media_content_type=MEDIA_TYPE_MUSIC,
            title=self.entry.title,
            can_play=False,
            can_expand=True,
            children_media_class=MEDIA_CLASS_DIRECTORY,
            children=[
                *await self._async_build_popular(radios, item),
                *await self._async_build_by_tag(radios, item),
                *await self._async_build_by_language(radios, item),
                *await self._async_build_by_country(radios, item),
            ],
        )
示例#18
0
    async def _async_build_popular(
            self, radios: RadioBrowser,
            item: MediaSourceItem) -> list[BrowseMediaSource]:
        """Handle browsing popular radio stations."""
        if item.identifier == "popular":
            stations = await radios.stations(
                hide_broken=True,
                limit=250,
                order=Order.CLICK_COUNT,
                reverse=True,
            )
            return self._async_build_stations(radios, stations)

        if not item.identifier:
            return [
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier="popular",
                    media_class=MEDIA_CLASS_DIRECTORY,
                    media_content_type=MEDIA_TYPE_MUSIC,
                    title="Popular",
                    can_play=False,
                    can_expand=True,
                )
            ]

        return []
示例#19
0
    async def async_browse_media(
        self,
        item: MediaSourceItem,
    ) -> BrowseMediaSource:
        """Return media."""
        if item.identifier:
            provider, _, params = item.identifier.partition("?")
            return self._provider_item(provider, params)

        # Root. List providers.
        manager: SpeechManager = self.hass.data[DOMAIN]
        children = [
            self._provider_item(provider) for provider in manager.providers
        ]
        return BrowseMediaSource(
            domain=DOMAIN,
            identifier=None,
            media_class=MEDIA_CLASS_APP,
            media_content_type="",
            title=self.name,
            can_play=False,
            can_expand=True,
            children_media_class=MEDIA_CLASS_APP,
            children=children,
        )
    async def _build_item(mass: MusicAssistant,
                          item: MediaItemType,
                          can_expand=True,
                          media_class=None):
        """Return BrowseMediaSource for MediaItem."""
        if hasattr(item, "artists"):
            title = f"{item.artists[0].name} - {item.name}"
        else:
            title = item.name
        url = await mass.metadata.get_image_url_for_item(item,
                                                         allow_local=False,
                                                         local_as_base64=False)
        if url and url.startswith("http"):
            url = f"https://images.weserv.nl/?w={THUMB_SIZE}&url={url}"
        # disable image proxy due to 'authSig' bug in HA frontend
        # elif url:
        #     url = f"/api/mass/image_proxy?size={THUMB_SIZE}&url={url}"

        return BrowseMediaSource(
            domain=DOMAIN,
            identifier=item.uri,
            title=title,
            media_class=media_class or item.media_type.value,
            media_content_type=MEDIA_CONTENT_TYPE_FLAC,
            can_play=True,
            can_expand=can_expand,
            thumbnail=url,
        )
示例#21
0
    def _browse_recording_folders(
        self, identifier: RecordingIdentifier, folders: list[dict[str, Any]]
    ) -> BrowseMediaSource:
        """Browse Frigate recording folders."""
        base = self._get_recording_base_media_source(identifier)

        for folder in folders:
            if folder["name"].endswith(".mp4"):
                continue
            title = self._generate_recording_title(identifier, folder)
            if not title:
                _LOGGER.warning("Skipping non-standard folder name: %s", folder["name"])
                continue
            base.children.append(
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=attr.evolve(
                        identifier,
                        **identifier.get_changes_to_set_next_empty(folder["name"]),
                    ),
                    media_class=MEDIA_CLASS_DIRECTORY,
                    children_media_class=MEDIA_CLASS_DIRECTORY,
                    media_content_type=identifier.media_type,
                    title=title,
                    can_play=False,
                    can_expand=True,
                    thumbnail=None,
                )
            )
        return base
 def _build_media_kind(
     cls,
     config: ConfigEntry,
     device: dr.DeviceEntry,
     kind: str,
     full_title: bool = True,
 ) -> BrowseMediaSource:
     return BrowseMediaSource(
         domain=DOMAIN,
         identifier=f"{config.entry_id}#{device.id}#{kind}",
         media_class=MEDIA_CLASS_DIRECTORY,
         media_content_type=(
             MEDIA_TYPE_VIDEO if kind == "movies" else MEDIA_TYPE_IMAGE
         ),
         title=(
             f"{config.title} {device.name} {kind.title()}"
             if full_title
             else kind.title()
         ),
         can_play=False,
         can_expand=True,
         children_media_class=(
             MEDIA_CLASS_VIDEO if kind == "movies" else MEDIA_CLASS_IMAGE
         ),
     )
 def _build_label_sources(self, identifier,
                          shown_event_count) -> BrowseMediaSource:
     sources = []
     for l in self.labels:
         after = int(
             identifier['after']) if not identifier['after'] == '' else None
         before = int(identifier['before']
                      ) if not identifier['before'] == '' else None
         count = self._count_by(after=after,
                                before=before,
                                camera=identifier['camera'],
                                label=l,
                                zone=identifier['zone'])
         if count == 0 or count == shown_event_count:
             continue
         sources.append(
             BrowseMediaSource(
                 domain=DOMAIN,
                 identifier=
                 f"clips/{identifier['name']}.{l}/{identifier['after']}/{identifier['before']}/{identifier['camera']}/{l}/{identifier['zone']}",
                 media_class=MEDIA_CLASS_DIRECTORY,
                 children_media_class=MEDIA_CLASS_VIDEO,
                 media_content_type=None,
                 title=f"{l.replace('_', ' ').title()} ({count})",
                 can_play=False,
                 can_expand=True,
                 thumbnail=None))
     return sources
示例#24
0
 def _build_zone_sources(
     self,
     summary_data: EventSummaryData,
     identifier: EventSearchIdentifier,
     shown_event_count: int,
 ) -> BrowseMediaSource:
     """Build zone media sources."""
     sources = []
     for zone in summary_data.zones:
         count = self._count_by(summary_data, attr.evolve(identifier, zone=zone))
         if count in (0, shown_event_count):
             continue
         sources.append(
             BrowseMediaSource(
                 domain=DOMAIN,
                 identifier=attr.evolve(
                     identifier,
                     name=f"{identifier.name}.{zone}",
                     zone=zone,
                 ),
                 media_class=MEDIA_CLASS_DIRECTORY,
                 children_media_class=MEDIA_CLASS_DIRECTORY,
                 media_content_type=identifier.media_type,
                 title=f"{get_friendly_name(zone)} ({count})",
                 can_play=False,
                 can_expand=True,
                 thumbnail=None,
             )
         )
     return sources
示例#25
0
    async def async_browse_media(
        self,
        media_content_type: str = None,
        media_content_id: str = None,
    ) -> BrowseMedia:
        if not MediaBrowser.media_cache:
            conf = self.hass.data[DOMAIN][DATA_CONFIG]
            conf = conf.get("media_source") or MEDIA_DEFAULT
            MediaBrowser.media_cache = [YandexSource(**item) for item in conf]

        for media in MediaBrowser.media_cache:
            if (media.media_content_id == media_content_id
                    and media.media_content_type == media_content_type):
                return media

        return BrowseMediaSource(
            title=self.name,
            children=MediaBrowser.media_cache,
            domain=None,
            identifier=None,
            media_class=None,
            media_content_type=None,
            can_play=False,
            can_expand=True,
        )
示例#26
0
 def _build_zone_sources(self, identifier, shown_event_count) -> BrowseMediaSource:
     sources = []
     for z in self.zones:
         after = int(identifier["after"]) if not identifier["after"] == "" else None
         before = (
             int(identifier["before"]) if not identifier["before"] == "" else None
         )
         count = self._count_by(
             after=after,
             before=before,
             camera=identifier["camera"],
             label=identifier["label"],
             zone=z,
         )
         if count == 0 or count == shown_event_count:
             continue
         sources.append(
             BrowseMediaSource(
                 domain=DOMAIN,
                 identifier=f"clips/{identifier['name']}.{z}/{identifier['after']}/{identifier['before']}/{identifier['camera']}/{identifier['label']}/{z}",
                 media_class=MEDIA_CLASS_DIRECTORY,
                 children_media_class=MEDIA_CLASS_VIDEO,
                 media_content_type=MEDIA_CLASS_VIDEO,
                 title=f"{z.replace('_', ' ').title()} ({count})",
                 can_play=False,
                 can_expand=True,
                 thumbnail=None,
             )
         )
     return sources
示例#27
0
 def _build_event_response(
     cls, identifier: EventSearchIdentifier, events: list[dict[str, Any]]
 ) -> BrowseMediaSource:
     children = []
     for event in events:
         children.append(
             BrowseMediaSource(
                 domain=DOMAIN,
                 identifier=EventIdentifier(
                     identifier.frigate_instance_id,
                     frigate_media_type=identifier.frigate_media_type,
                     name=(
                         f"{event['camera']}-{event['id']}."
                         + identifier.frigate_media_type.extension
                     ),
                 ),
                 media_class=identifier.media_class,
                 media_content_type=identifier.media_type,
                 title=f"{dt.datetime.fromtimestamp(event['start_time'], DEFAULT_TIME_ZONE).strftime(DATE_STR_FORMAT)} [{int(event['end_time']-event['start_time'])}s, {event['label'].capitalize()} {int(event['top_score']*100)}%]",
                 can_play=identifier.media_type == MEDIA_TYPE_VIDEO,
                 can_expand=False,
                 thumbnail=f"data:image/jpeg;base64,{event['thumbnail']}",
             )
         )
     return children
示例#28
0
    async def _build_game_library(self):
        """Display installed games across all consoles."""
        apps = await self.client.smartglass.get_installed_apps()
        games = {
            game.one_store_product_id: game
            for game in apps.result
            if game.is_game and game.title_id
        }

        app_details = await self.client.catalog.get_products(
            games.keys(),
            FieldsTemplate.BROWSE,
        )

        images = {
            prod.product_id: prod.localized_properties[0].images
            for prod in app_details.products
        }

        return BrowseMediaSource(
            domain=DOMAIN,
            identifier="",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_type="",
            title="Xbox Game Media",
            can_play=False,
            can_expand=True,
            children=[_build_game_item(game, images) for game in games.values()],
            children_media_class=MEDIA_CLASS_GAME,
        )
示例#29
0
    async def _build_events_type(
        self,
        data: ProtectData,
        camera_id: str,
        event_type: SimpleEventType,
        build_children: bool = False,
    ) -> BrowseMediaSource:
        """Build folder media source for a selectors for a given event type."""

        base_id = f"{data.api.bootstrap.nvr.id}:browse:{camera_id}:{event_type.value}"

        title = EVENT_NAME_MAP[event_type].title()
        source = BrowseMediaSource(
            domain=DOMAIN,
            identifier=base_id,
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_type=VIDEO_FORMAT,
            title=title,
            can_play=False,
            can_expand=True,
            children_media_class=MEDIA_CLASS_VIDEO,
        )

        if not build_children or data.api.bootstrap.recording_start is None:
            return source

        children = [
            self._build_recent(data, camera_id, event_type, 1),
            self._build_recent(data, camera_id, event_type, 7),
            self._build_recent(data, camera_id, event_type, 30),
        ]

        start, end = _get_start_end(self.hass,
                                    data.api.bootstrap.recording_start)
        while end > start:
            children.append(
                self._build_month(data, camera_id, event_type, end.date()))
            end = (end - timedelta(days=1)).replace(day=1)

        camera: Camera | None = None
        if camera_id != "all":
            camera = data.api.bootstrap.cameras.get(camera_id)
        source.children = await asyncio.gather(*children)
        source.title = self._breadcrumb(data, title, camera=camera)

        return source
示例#30
0
    async def async_browse_media(
        self,
        item: MediaSourceItem,
    ) -> BrowseMediaSource:
        """Return media."""
        if item.identifier:
            raise BrowseError("Unknown item")

        supported_stream_types: list[str | None] = [None]

        if "stream" in self.hass.config.components:
            supported_stream_types.append(STREAM_TYPE_HLS)

        # Root. List cameras.
        component: EntityComponent = self.hass.data[DOMAIN]
        children = []
        for camera in component.entities:
            camera = cast(Camera, camera)
            stream_type = camera.frontend_stream_type

            if stream_type not in supported_stream_types:
                continue

            children.append(
                BrowseMediaSource(
                    domain=DOMAIN,
                    identifier=camera.entity_id,
                    media_class=MEDIA_CLASS_VIDEO,
                    media_content_type=FORMAT_CONTENT_TYPE[HLS_PROVIDER],
                    title=camera.name,
                    thumbnail=f"/api/camera_proxy/{camera.entity_id}",
                    can_play=True,
                    can_expand=False,
                ))

        return BrowseMediaSource(
            domain=DOMAIN,
            identifier=None,
            media_class=MEDIA_CLASS_APP,
            media_content_type="",
            title="Camera",
            can_play=False,
            can_expand=True,
            children_media_class=MEDIA_CLASS_VIDEO,
            children=children,
        )