def _get_config_or_raise(self, config_id: str) -> ConfigEntry: """Get a config entry from a URL.""" entry = self.hass.config_entries.async_get_entry(config_id) if not entry: raise MediaSourceError( f"Unable to find config entry with id: {config_id}") return entry
def _get_device_or_raise(self, device_id: str) -> dr.DeviceEntry: """Get a config entry from a URL.""" device_registry = dr.async_get(self.hass) device = device_registry.async_get(device_id) if not device: raise MediaSourceError(f"Unable to find device with id: {device_id}") return device
def _get_path_or_raise(cls, path: str | None) -> str: """Verify path is a valid motionEye path.""" if not path: return "/" if PurePath(path).root == "/": return path raise MediaSourceError( f"motionEye media path must start with '/', received: {path}")
def _get_camera_id_or_raise( cls, config: ConfigEntry, device: dr.DeviceEntry ) -> int: """Get a config entry from a URL.""" for identifier in device.identifiers: data = split_motioneye_device_identifier(identifier) if data is not None: return data[2] raise MediaSourceError(f"Could not find camera id for device id: {device.id}")
def _get_client(self, identifier: Identifier) -> FrigateApiClient: """Get client for a given identifier.""" config_entry = get_config_entry_for_frigate_instance_id( self.hass, identifier.frigate_instance_id) if config_entry: client: FrigateApiClient = (self.hass.data[DOMAIN].get( config_entry.entry_id, {}).get(ATTR_CLIENT)) if client: return client raise MediaSourceError( "Could not find client for frigate instance id: %s" % identifier.frigate_instance_id)
def _verify_kind_or_raise(cls, kind: str) -> None: """Verify kind is an expected value.""" if kind in MEDIA_CLASS_MAP: return raise MediaSourceError(f"Unknown media type: {kind}")
async def async_browse_media( self, item: MediaSourceItem, media_types: tuple[str] = MEDIA_MIME_TYPES ) -> BrowseMediaSource: """Browse media.""" if item.identifier is None: base = BrowseMediaSource( domain=DOMAIN, identifier="", media_class=MEDIA_CLASS_DIRECTORY, children_media_class=MEDIA_CLASS_VIDEO, media_content_type=MEDIA_TYPE_VIDEO, title=NAME, can_play=False, can_expand=True, thumbnail=None, children=[], ) for config_entry in self.hass.config_entries.async_entries(DOMAIN): frigate_instance_id = get_frigate_instance_id_for_config_entry( self.hass, config_entry ) if frigate_instance_id: clips_identifier = EventSearchIdentifier( frigate_instance_id, FrigateMediaType.CLIPS ) recording_identifier = RecordingIdentifier(frigate_instance_id) snapshots_identifier = EventSearchIdentifier( frigate_instance_id, FrigateMediaType.SNAPSHOTS ) # Use the media class of the children to help distinguish # the icons in the frontend. base.children.extend( [ BrowseMediaSource( domain=DOMAIN, identifier=clips_identifier, media_class=MEDIA_CLASS_DIRECTORY, children_media_class=clips_identifier.media_class, media_content_type=clips_identifier.media_type, title=f"Clips [{config_entry.title}]", can_play=False, can_expand=True, thumbnail=None, children=[], ), BrowseMediaSource( domain=DOMAIN, identifier=recording_identifier, media_class=MEDIA_CLASS_DIRECTORY, children_media_class=recording_identifier.media_class, media_content_type=recording_identifier.media_type, title=f"Recordings [{config_entry.title}]", can_play=False, can_expand=True, thumbnail=None, children=[], ), BrowseMediaSource( domain=DOMAIN, identifier=snapshots_identifier, media_class=MEDIA_CLASS_DIRECTORY, children_media_class=snapshots_identifier.media_class, media_content_type=snapshots_identifier.media_type, title=f"Snapshots [{config_entry.title}]", can_play=False, can_expand=True, thumbnail=None, children=[], ), ], ) return base identifier = Identifier.from_str( item.identifier, default_frigate_instance_id=self._get_default_frigate_instance_id(), ) if isinstance(identifier, EventSearchIdentifier): if identifier.frigate_media_type == FrigateMediaType.CLIPS: media_kwargs = {"has_clip": True} else: media_kwargs = {"has_snapshot": True} try: events = await self._get_client(identifier).async_get_events( after=identifier.after, before=identifier.before, camera=identifier.camera, label=identifier.label, zone=identifier.zone, limit=10000 if identifier.name.endswith(".all") else ITEM_LIMIT, **media_kwargs, ) except FrigateApiClientError as exc: raise MediaSourceError from exc return self._browse_events( await self._get_event_summary_data(identifier), identifier, events ) if isinstance(identifier, RecordingIdentifier): path = identifier.get_integration_proxy_path() try: recordings_folder = await self._get_client(identifier).async_get_path( path ) except FrigateApiClientError as exc: raise MediaSourceError from exc if identifier.hour is None: return self._browse_recording_folders(identifier, recordings_folder) return self._browse_recordings(identifier, recordings_folder) raise MediaSourceError("Invalid media source identifier: %s" % item.identifier)