Beispiel #1
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
Beispiel #2
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
Beispiel #3
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
Beispiel #4
0
async def async_library_items(jelly_cm: JellyfinClientManager,
                              media_content_type_in=None,
                              media_content_id_in=None,
                              canPlayList=True) -> BrowseMediaSource:
    """
    Create response payload to describe contents of a specific library.

    Used by async_browse_media.
    """
    _LOGGER.debug(
        f'>> async_library_items: {media_content_id_in} / {canPlayList}')

    library_info = None
    query = None

    if (media_content_type_in is None):
        media_content_type = None
        media_content_id = None
    else:
        media_content_type, media_content_id = JellyfinSource.parse_mediasource_identifier(
            media_content_id_in)
    _LOGGER.debug(
        f'-- async_library_items: {media_content_type} / {media_content_id}')

    if media_content_type in [None, "library"]:
        library_info = BrowseMediaSource(
            domain=DOMAIN,
            identifier=f'library{IDENTIFIER_SPLIT}library',
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_type="library",
            title="Media Library",
            can_play=False,
            can_expand=True,
            children=[],
        )
    elif media_content_type in [
            MEDIA_CLASS_DIRECTORY, MEDIA_TYPE_ARTIST, MEDIA_TYPE_ALBUM,
            MEDIA_TYPE_PLAYLIST, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_SEASON
    ]:
        query = {
            "ParentId": media_content_id,
            "sortBy": "SortName",
            "sortOrder": "Ascending"
        }

        parent_item = await jelly_cm.get_item(media_content_id)
        library_info = BrowseMediaSource(
            domain=DOMAIN,
            identifier=
            f'{media_content_type}{IDENTIFIER_SPLIT}{media_content_id}',
            media_class=media_content_type,
            media_content_type=media_content_type,
            title=parent_item["Name"],
            can_play=IsPlayable(parent_item["Type"], canPlayList),
            can_expand=True,
            thumbnail=jelly_cm.get_artwork_url(media_content_id),
            children=[],
        )
    else:
        query = {"Id": media_content_id}
        library_info = BrowseMediaSource(
            domain=DOMAIN,
            identifier=
            f'{media_content_type}{IDENTIFIER_SPLIT}{media_content_id}',
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_type=media_content_type,
            title="",
            can_play=True,
            can_expand=False,
            thumbnail=jelly_cm.get_artwork_url(media_content_id),
            children=[],
        )
    _LOGGER.debug(f'-- async_library_items: 1')

    items = await jelly_cm.get_items(query)
    for item in items:
        if media_content_type in [
                None, "library", MEDIA_CLASS_DIRECTORY, MEDIA_TYPE_ARTIST,
                MEDIA_TYPE_ALBUM, MEDIA_TYPE_PLAYLIST, MEDIA_TYPE_TVSHOW,
                MEDIA_TYPE_SEASON
        ]:
            if item["IsFolder"]:
                library_info.children_media_class = MEDIA_CLASS_DIRECTORY
                library_info.children.append(
                    BrowseMediaSource(
                        domain=DOMAIN,
                        identifier=
                        f'{Type2Mediatype(item["Type"])}{IDENTIFIER_SPLIT}{item["Id"]}',
                        media_class=Type2Mediaclass(item["Type"]),
                        media_content_type=Type2Mimetype(item["Type"]),
                        title=item["Name"],
                        can_play=IsPlayable(item["Type"], canPlayList),
                        can_expand=True,
                        children=[],
                        thumbnail=jelly_cm.get_artwork_url(item["Id"])))
            else:
                library_info.children_media_class = Type2Mediaclass(
                    item["Type"])
                library_info.children.append(
                    BrowseMediaSource(
                        domain=DOMAIN,
                        identifier=
                        f'{Type2Mediatype(item["Type"])}{IDENTIFIER_SPLIT}{item["Id"]}',
                        media_class=Type2Mediaclass(item["Type"]),
                        media_content_type=Type2Mimetype(item["Type"]),
                        title=item["Name"],
                        can_play=IsPlayable(item["Type"], canPlayList),
                        can_expand=False,
                        children=[],
                        thumbnail=jelly_cm.get_artwork_url(item["Id"])))
        else:
            library_info.domain = DOMAIN
            library_info.identifier = f'{Type2Mediatype(item["Type"])}{IDENTIFIER_SPLIT}{item["Id"]}',
            library_info.title = item["Name"]
            library_info.media_content_type = Type2Mimetype(item["Type"])
            library_info.media_class = Type2Mediaclass(item["Type"])
            library_info.can_expand = False
            library_info.can_play = IsPlayable(item["Type"], canPlayList),
            break

    _LOGGER.debug(f'<< async_library_items {library_info.as_dict()}')
    return library_info
Beispiel #5
0
    async def _build_camera(self,
                            data: ProtectData,
                            camera_id: str,
                            build_children: bool = False) -> BrowseMediaSource:
        """Build media source for selectors for a UniFi Protect camera."""

        name = "All Cameras"
        is_doorbell = data.api.bootstrap.has_doorbell
        has_smart = data.api.bootstrap.has_smart_detections
        camera: Camera | None = None
        if camera_id != "all":
            camera = data.api.bootstrap.cameras.get(camera_id)
            if camera is None:
                raise BrowseError(f"Unknown Camera ID: {camera_id}")
            name = camera.name or camera.market_name or camera.type
            is_doorbell = camera.feature_flags.has_chime
            has_smart = camera.feature_flags.has_smart_detect

        thumbnail_url: str | None = None
        if camera is not None:
            thumbnail_url = await self._get_camera_thumbnail_url(camera)
        source = BrowseMediaSource(
            domain=DOMAIN,
            identifier=f"{data.api.bootstrap.nvr.id}:browse:{camera_id}",
            media_class=MEDIA_CLASS_DIRECTORY,
            media_content_type=VIDEO_FORMAT,
            title=name,
            can_play=False,
            can_expand=True,
            thumbnail=thumbnail_url,
            children_media_class=MEDIA_CLASS_VIDEO,
        )

        if not build_children:
            return source

        source.children = [
            await self._build_events_type(data, camera_id,
                                          SimpleEventType.MOTION),
        ]

        if is_doorbell:
            source.children.insert(
                0,
                await self._build_events_type(data, camera_id,
                                              SimpleEventType.RING),
            )

        if has_smart:
            source.children.append(await self._build_events_type(
                data, camera_id, SimpleEventType.SMART))

        if is_doorbell or has_smart:
            source.children.insert(
                0,
                await self._build_events_type(data, camera_id,
                                              SimpleEventType.ALL),
            )

        source.title = self._breadcrumb(data, name)

        return source
Beispiel #6
0
    async def _build_days(
        self,
        data: ProtectData,
        camera_id: str,
        event_type: SimpleEventType,
        start: date,
        is_all: bool = True,
        build_children: bool = False,
    ) -> BrowseMediaSource:
        """Build media source for events for a given day or whole month."""

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

        if is_all:
            title = "Whole Month"
            identifier = f"{base_id}:range:{start.year}:{start.month}:all"
        else:
            title = f"{start.strftime('%x')}"
            identifier = f"{base_id}:range:{start.year}:{start.month}:{start.day}"
        source = BrowseMediaSource(
            domain=DOMAIN,
            identifier=identifier,
            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

        start_dt = datetime(
            year=start.year,
            month=start.month,
            day=start.day,
            hour=0,
            minute=0,
            second=0,
            tzinfo=dt_util.DEFAULT_TIME_ZONE,
        )
        if is_all:
            if start_dt.month < 12:
                end_dt = start_dt.replace(month=start_dt.month + 1)
            else:
                end_dt = start_dt.replace(year=start_dt.year + 1, month=1)
        else:
            end_dt = start_dt + timedelta(hours=24)

        args = {
            "data": data,
            "start": start_dt,
            "end": end_dt,
            "reserve": False,
        }
        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

        title = f"{start.strftime('%B %Y')} > {title}"
        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