Make error handling and console logging consistent

This commit is contained in:
Dermot Duffy
2022-06-20 03:03:27 +00:00
parent bd393d953a
commit 4901905ca1
11 changed files with 132 additions and 99 deletions
+12 -8
View File
@@ -75,7 +75,7 @@ import {
frigateCardHasAction, frigateCardHasAction,
getActionConfigGivenAction, getActionConfigGivenAction,
} from './utils/action.js'; } from './utils/action.js';
import { contentsChanged } from './utils/basic.js'; import { contentsChanged, errorToConsole } from './utils/basic.js';
import { getCameraIcon, getCameraID, getCameraTitle } from './utils/camera.js'; import { getCameraIcon, getCameraID, getCameraTitle } from './utils/camera.js';
import { import {
getEntityIcon, getEntityIcon,
@@ -673,7 +673,7 @@ export class FrigateCard extends LitElement {
try { try {
entityList = await getAllEntities(this._hass); entityList = await getAllEntities(this._hass);
} catch (e) { } catch (e) {
console.error(e); errorToConsole(e as Error);
} }
const cameras: Map<string, CameraConfig> = new Map(); const cameras: Map<string, CameraConfig> = new Map();
@@ -688,7 +688,11 @@ export class FrigateCard extends LitElement {
if (config.camera_entity) { if (config.camera_entity) {
try { try {
entity = await getExtendedEntity(this._hass, config.camera_entity, cache); entity = await getExtendedEntity(this._hass, config.camera_entity, cache);
} catch (e) {} } catch (e) {
// Silently ignore errors here, as non-Frigate camera entities may not
// necessarily have a registry entry and otherwise this would cause
// log spam for those cases.
}
} }
if (!config.frigate.camera_name && entity) { if (!config.frigate.camera_name && entity) {
@@ -717,7 +721,7 @@ export class FrigateCard extends LitElement {
cache, cache,
); );
} catch (e) { } catch (e) {
console.error(e); errorToConsole(e as Error);
} }
if (config.triggers.motion) { if (config.triggers.motion) {
@@ -1180,7 +1184,7 @@ export class FrigateCard extends LitElement {
try { try {
response = await homeAssistantSignPath(this._hass, path); response = await homeAssistantSignPath(this._hass, path);
} catch (e) { } catch (e) {
console.error(e); errorToConsole(e as Error);
} }
if (!response) { if (!response) {
@@ -1860,7 +1864,7 @@ export class FrigateCard extends LitElement {
} }
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
"frigate-card": FrigateCard 'frigate-card': FrigateCard;
} }
} }
+22 -18
View File
@@ -9,7 +9,7 @@ import {
LitElement, LitElement,
PropertyValues, PropertyValues,
TemplateResult, TemplateResult,
unsafeCSS unsafeCSS,
} from 'lit'; } from 'lit';
import { customElement, property, state } from 'lit/decorators.js'; import { customElement, property, state } from 'lit/decorators.js';
import { createRef, Ref, ref } from 'lit/directives/ref.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js';
@@ -33,16 +33,16 @@ import {
LiveProvider, LiveProvider,
MediaShowInfo, MediaShowInfo,
TransitionEffect, TransitionEffect,
WebRTCCardConfig WebRTCCardConfig,
} from '../types.js'; } from '../types.js';
import { stopEventFromActivatingCardWideActions } from '../utils/action.js'; import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
import { contentsChanged } from '../utils/basic.js'; import { contentsChanged, errorToConsole } from '../utils/basic.js';
import { getCameraIcon, getCameraTitle } from '../utils/camera.js'; import { getCameraIcon, getCameraTitle } from '../utils/camera.js';
import { homeAssistantSignPath } from '../utils/ha'; import { homeAssistantSignPath } from '../utils/ha';
import { getFullDependentBrowseMediaQueryParameters } from '../utils/ha/browse-media.js'; import { getFullDependentBrowseMediaQueryParameters } from '../utils/ha/browse-media.js';
import { import {
dispatchExistingMediaShowInfoAsEvent, dispatchExistingMediaShowInfoAsEvent,
dispatchMediaShowEvent dispatchMediaShowEvent,
} from '../utils/media-info.js'; } from '../utils/media-info.js';
import { View } from '../view.js'; import { View } from '../view.js';
import { AutoMediaPlugin, AutoMediaPluginType } from './embla-plugins/automedia.js'; import { AutoMediaPlugin, AutoMediaPluginType } from './embla-plugins/automedia.js';
@@ -52,8 +52,8 @@ import { dispatchErrorMessageEvent } from './message.js';
import './next-prev-control.js'; import './next-prev-control.js';
import { FrigateCardNextPreviousControl } from './next-prev-control.js'; import { FrigateCardNextPreviousControl } from './next-prev-control.js';
import './title-control.js'; import './title-control.js';
import "./surround-thumbnails"; import './surround-thumbnails';
import "../patches/ha-camera-stream"; import '../patches/ha-camera-stream';
// Number of seconds a signed URL is valid for. // Number of seconds a signed URL is valid for.
const URL_SIGN_EXPIRY_SECONDS = 24 * 60 * 60; const URL_SIGN_EXPIRY_SECONDS = 24 * 60 * 60;
@@ -913,7 +913,7 @@ export class FrigateCardLiveWebRTCCard extends LitElement {
// Set the id to ensure that the relevant CSS styles will have // Set the id to ensure that the relevant CSS styles will have
// sufficient specifity to overcome some styles that are otherwise // sufficient specifity to overcome some styles that are otherwise
// applied to <ha-card> in Safari. // applied to <ha-card> in Safari.
webrtcElement.id = "webrtc"; webrtcElement.id = 'webrtc';
} }
return html`${webrtcElement}`; return html`${webrtcElement}`;
}; };
@@ -1021,7 +1021,11 @@ export class FrigateCardLiveJSMPEG extends LitElement {
* @returns A URL or null. * @returns A URL or null.
*/ */
protected async _getURL(): Promise<string | null> { protected async _getURL(): Promise<string | null> {
if (!this.hass || !this.cameraConfig?.frigate.client_id || !this.cameraConfig?.frigate.camera_name) { if (
!this.hass ||
!this.cameraConfig?.frigate.client_id ||
!this.cameraConfig?.frigate.camera_name
) {
return null; return null;
} }
@@ -1033,8 +1037,8 @@ export class FrigateCardLiveJSMPEG extends LitElement {
`/jsmpeg/${this.cameraConfig.frigate.camera_name}`, `/jsmpeg/${this.cameraConfig.frigate.camera_name}`,
URL_SIGN_EXPIRY_SECONDS, URL_SIGN_EXPIRY_SECONDS,
); );
} catch (err) { } catch (e) {
console.warn(err); errorToConsole(e as Error);
return null; return null;
} }
if (!response) { if (!response) {
@@ -1182,12 +1186,12 @@ export class FrigateCardLiveJSMPEG extends LitElement {
} }
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
"frigate-card-live-jsmpeg": FrigateCardLiveJSMPEG 'frigate-card-live-jsmpeg': FrigateCardLiveJSMPEG;
"frigate-card-live-webrtc-card": FrigateCardLiveWebRTCCard 'frigate-card-live-webrtc-card': FrigateCardLiveWebRTCCard;
"frigate-card-live-ha": FrigateCardLiveFrigate 'frigate-card-live-ha': FrigateCardLiveFrigate;
"frigate-card-live-provider": FrigateCardLiveProvider 'frigate-card-live-provider': FrigateCardLiveProvider;
"frigate-card-live-carousel": FrigateCardLiveCarousel 'frigate-card-live-carousel': FrigateCardLiveCarousel;
"frigate-card-live": FrigateCardLive 'frigate-card-live': FrigateCardLive;
} }
} }
+19 -16
View File
@@ -6,7 +6,7 @@ import {
fromUnixTime, fromUnixTime,
getUnixTime, getUnixTime,
startOfHour, startOfHour,
sub sub,
} from 'date-fns'; } from 'date-fns';
import { import {
CSSResultGroup, CSSResultGroup,
@@ -14,7 +14,7 @@ import {
LitElement, LitElement,
PropertyValues, PropertyValues,
TemplateResult, TemplateResult,
unsafeCSS unsafeCSS,
} from 'lit'; } from 'lit';
import { customElement, property } from 'lit/decorators.js'; import { customElement, property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js'; import { classMap } from 'lit/directives/class-map.js';
@@ -28,7 +28,7 @@ import {
TimelineItem, TimelineItem,
TimelineOptions, TimelineOptions,
TimelineOptionsCluster, TimelineOptionsCluster,
TimelineWindow TimelineWindow,
} from 'vis-timeline/esnext'; } from 'vis-timeline/esnext';
import { CAMERA_BIRDSEYE } from '../const'; import { CAMERA_BIRDSEYE } from '../const';
import { localize } from '../localize/localize'; import { localize } from '../localize/localize';
@@ -42,10 +42,10 @@ import {
frigateCardConfigDefaults, frigateCardConfigDefaults,
FrigateCardError, FrigateCardError,
FrigateEvent, FrigateEvent,
TimelineConfig TimelineConfig,
} from '../types'; } from '../types';
import { stopEventFromActivatingCardWideActions } from '../utils/action'; import { stopEventFromActivatingCardWideActions } from '../utils/action';
import { dispatchFrigateCardEvent, prettifyTitle } from '../utils/basic'; import { dispatchFrigateCardEvent, errorToConsole, prettifyTitle } from '../utils/basic';
import { getCameraTitle } from '../utils/camera.js'; import { getCameraTitle } from '../utils/camera.js';
import { import {
getRecordingSegments, getRecordingSegments,
@@ -53,7 +53,7 @@ import {
getUniqueFrigateCameraEventsID, getUniqueFrigateCameraEventsID,
getUniqueFrigateCameraID, getUniqueFrigateCameraID,
RecordingSegments, RecordingSegments,
RecordingSummary RecordingSummary,
} from '../utils/frigate'; } from '../utils/frigate';
import { import {
createEventParentForChildren, createEventParentForChildren,
@@ -61,7 +61,7 @@ import {
generateRecordingIdentifier, generateRecordingIdentifier,
getBrowseMediaQueryParameters, getBrowseMediaQueryParameters,
isTrueMedia, isTrueMedia,
multipleBrowseMediaQuery multipleBrowseMediaQuery,
} from '../utils/ha/browse-media'; } from '../utils/ha/browse-media';
import { View, ViewContext } from '../view'; import { View, ViewContext } from '../view';
import { dispatchFrigateCardErrorEvent, dispatchMessageEvent } from './message.js'; import { dispatchFrigateCardErrorEvent, dispatchMessageEvent } from './message.js';
@@ -300,7 +300,7 @@ class TimelineDataManager {
this._dateStart, this._dateStart,
this._dateEnd, this._dateEnd,
), ),
...(recordings ? [this._fetchRecordings(element, hass, cameras)] : []), ...(recordings ? [this._fetchRecordings(hass, cameras)] : []),
]); ]);
return true; return true;
@@ -315,7 +315,6 @@ class TimelineDataManager {
* @param end Fetch events that start earlier than this date. * @param end Fetch events that start earlier than this date.
*/ */
protected async _fetchRecordings( protected async _fetchRecordings(
element: HTMLElement,
hass: ExtendedHomeAssistant, hass: ExtendedHomeAssistant,
cameras: Map<string, CameraConfig>, cameras: Map<string, CameraConfig>,
): Promise<void> { ): Promise<void> {
@@ -329,7 +328,7 @@ class TimelineDataManager {
if (!config.frigate.camera_name) { if (!config.frigate.camera_name) {
return; return;
} }
let summary: RecordingSummary; let summary: RecordingSummary = [];
try { try {
summary = await getRecordingsSummary( summary = await getRecordingsSummary(
hass, hass,
@@ -337,7 +336,9 @@ class TimelineDataManager {
config.frigate.camera_name, config.frigate.camera_name,
); );
} catch (e) { } catch (e) {
return dispatchFrigateCardErrorEvent(element, e as FrigateCardError); // Recording failure should not disrupt the rest of the timeline
// experience.
errorToConsole(e as Error);
} }
for (const dayData of summary) { for (const dayData of summary) {
@@ -691,7 +692,9 @@ export class FrigateCardTimelineCore extends LitElement {
), ),
]); ]);
results.set(camera, { segments: cameraResults[0], summary: cameraResults[1] }); results.set(camera, { segments: cameraResults[0], summary: cameraResults[1] });
} catch (e) {} } catch (e) {
errorToConsole(e as Error);
}
}; };
const cameras = camera ? [camera] : [...(this.cameras?.keys() ?? [])]; const cameras = camera ? [camera] : [...(this.cameras?.keys() ?? [])];
await Promise.all(cameras.map((camera) => fetch(camera, this.cameras?.get(camera)))); await Promise.all(cameras.map((camera) => fetch(camera, this.cameras?.get(camera))));
@@ -1239,8 +1242,8 @@ export class FrigateCardTimelineCore extends LitElement {
} }
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
"frigate-card-timeline-core": FrigateCardTimelineCore 'frigate-card-timeline-core': FrigateCardTimelineCore;
"frigate-card-timeline": FrigateCardTimeline 'frigate-card-timeline': FrigateCardTimeline;
} }
} }
-1
View File
@@ -320,7 +320,6 @@
"invalid_configuration": "Invalid configuration", "invalid_configuration": "Invalid configuration",
"invalid_configuration_no_hint": "No location hint available (bad or missing type?)", "invalid_configuration_no_hint": "No location hint available (bad or missing type?)",
"invalid_elements_config": "Invalid picture elements configuration", "invalid_elements_config": "Invalid picture elements configuration",
"invalid_keys": "Invalid keys",
"invalid_response": "Received invalid response from Home Assistant for request", "invalid_response": "Received invalid response from Home Assistant for request",
"jsmpeg_no_player": "Could not start JSMPEG player", "jsmpeg_no_player": "Could not start JSMPEG player",
"jsmpeg_no_sign": "Could not retrieve or sign JSMPEG websocket path", "jsmpeg_no_sign": "Could not retrieve or sign JSMPEG websocket path",
-1
View File
@@ -322,7 +322,6 @@
"invalid_configuration": "Configuração inválida", "invalid_configuration": "Configuração inválida",
"invalid_configuration_no_hint": "Nenhuma dica de local disponível (tipo incorreto ou ausente?)", "invalid_configuration_no_hint": "Nenhuma dica de local disponível (tipo incorreto ou ausente?)",
"invalid_elements_config": "Configuração de elementos de imagem inválida", "invalid_elements_config": "Configuração de elementos de imagem inválida",
"invalid_keys": "Chaves inválidas",
"invalid_response": "Resposta inválida recebida do Home Assistant para a solicitação", "invalid_response": "Resposta inválida recebida do Home Assistant para a solicitação",
"jsmpeg_no_player": "Não foi possível iniciar o player JSMPEG", "jsmpeg_no_player": "Não foi possível iniciar o player JSMPEG",
"jsmpeg_no_sign": "Não foi possível recuperar ou assinar o caminho do websocket JSMPEG", "jsmpeg_no_sign": "Não foi possível recuperar ou assinar o caminho do websocket JSMPEG",
+20 -18
View File
@@ -9,7 +9,7 @@ import {
NoActionConfig, NoActionConfig,
Themes, Themes,
ToggleActionConfig, ToggleActionConfig,
UrlActionConfig UrlActionConfig,
} from 'custom-card-helpers'; } from 'custom-card-helpers';
import { StyleInfo } from 'lit/directives/style-map.js'; import { StyleInfo } from 'lit/directives/style-map.js';
import { z } from 'zod'; import { z } from 'zod';
@@ -44,7 +44,8 @@ const FRIGATE_CARD_VIEWS = [
] as const; ] as const;
export type FrigateCardView = typeof FRIGATE_CARD_VIEWS[number]; export type FrigateCardView = typeof FRIGATE_CARD_VIEWS[number];
export type FrigateCardUserSpecifiedView = typeof FRIGATE_CARD_VIEWS_USER_SPECIFIED[number]; export type FrigateCardUserSpecifiedView =
typeof FRIGATE_CARD_VIEWS_USER_SPECIFIED[number];
export const FRIGATE_CARD_VIEW_DEFAULT = 'live' as const; export const FRIGATE_CARD_VIEW_DEFAULT = 'live' as const;
const FRIGATE_MENU_STYLES = ['none', 'hidden', 'overlay', 'hover', 'outside'] as const; const FRIGATE_MENU_STYLES = ['none', 'hidden', 'overlay', 'hover', 'outside'] as const;
@@ -395,14 +396,16 @@ const cameraConfigSchema = z
// this card. // this card.
id: z.string().optional(), id: z.string().optional(),
frigate: z.object({ frigate: z
// No URL validation to allow relative URLs within HA (e.g. Frigate addon). .object({
url: z.string().optional(), // No URL validation to allow relative URLs within HA (e.g. Frigate addon).
client_id: z.string().default(cameraConfigDefault.frigate.client_id), url: z.string().optional(),
camera_name: z.string().optional(), client_id: z.string().default(cameraConfigDefault.frigate.client_id),
label: z.string().optional(), camera_name: z.string().optional(),
zone: z.string().optional(), label: z.string().optional(),
}).default(cameraConfigDefault.frigate), zone: z.string().optional(),
})
.default(cameraConfigDefault.frigate),
// Camera identifiers for WebRTC. // Camera identifiers for WebRTC.
webrtc_card: webrtcCardCameraConfigSchema.optional(), webrtc_card: webrtcCardCameraConfigSchema.optional(),
@@ -414,14 +417,13 @@ const cameraConfigSchema = z
}) })
.default(cameraConfigDefault.dependencies), .default(cameraConfigDefault.dependencies),
triggers: z.object({ triggers: z
motion: z.boolean().default(cameraConfigDefault.triggers.motion), .object({
occupancy: z.boolean().default(cameraConfigDefault.triggers.occupancy), motion: z.boolean().default(cameraConfigDefault.triggers.motion),
entities: z occupancy: z.boolean().default(cameraConfigDefault.triggers.occupancy),
.string() entities: z.string().array().default(cameraConfigDefault.triggers.entities),
.array() })
.default(cameraConfigDefault.triggers.entities), .default(cameraConfigDefault.triggers),
}).default(cameraConfigDefault.triggers),
}) })
.default(cameraConfigDefault); .default(cameraConfigDefault);
export type CameraConfig = z.infer<typeof cameraConfigSchema>; export type CameraConfig = z.infer<typeof cameraConfigSchema>;
+17
View File
@@ -1,4 +1,5 @@
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { FrigateCardError } from '../types';
/** /**
* Dispatch a Frigate Card event. * Dispatch a Frigate Card event.
@@ -60,3 +61,19 @@ export function arrayMove(target: unknown[], from: number, to: number): void {
export function contentsChanged(n: unknown, o: unknown): boolean { export function contentsChanged(n: unknown, o: unknown): boolean {
return !isEqual(n, o); return !isEqual(n, o);
} }
/**
* Log an error as a warning to the console.
* @param e The Error object.
* @param func The Console func to call.
*/
export function errorToConsole(e: Error, func?: CallableFunction): void {
if (!func) {
func = console.warn;
}
if (e instanceof FrigateCardError && e.context) {
func(e, e.context);
} else {
func(e);
}
}
+2 -2
View File
@@ -51,7 +51,7 @@ const recordingSegmentsSchema = recordingSegmentSchema.array();
export type RecordingSegments = z.infer<typeof recordingSegmentsSchema>; export type RecordingSegments = z.infer<typeof recordingSegmentsSchema>;
/** /**
* Get the recordings summary. * Get the recordings summary. May throw.
* @param hass The Home Assistant object. * @param hass The Home Assistant object.
* @param client_id The Frigate client_id. * @param client_id The Frigate client_id.
* @param camera_name The Frigate camera name. * @param camera_name The Frigate camera name.
@@ -70,7 +70,7 @@ export const getRecordingsSummary = async (
}; };
/** /**
* Get the recording segments.. * Get the recording segments. May throw.
* @param hass The Home Assistant object. * @param hass The Home Assistant object.
* @param client_id The Frigate client_id. * @param client_id The Frigate client_id.
* @param camera_name The Frigate camera name. * @param camera_name The Frigate camera name.
+3 -3
View File
@@ -5,7 +5,7 @@ import {
EntityList, EntityList,
entityListSchema, entityListSchema,
ExtendedEntity, ExtendedEntity,
extendedEntitySchema extendedEntitySchema,
} from '../../types.js'; } from '../../types.js';
export class ExtendedEntityCache { export class ExtendedEntityCache {
@@ -78,7 +78,7 @@ export const getExtendedEntity = async (
}; };
/** /**
* Get the extended entity information for an array of entities. * Get the extended entity information for an array of entities. May throw.
* @param hass The Home Assistant object. * @param hass The Home Assistant object.
* @param entities An array of entity ids. * @param entities An array of entity ids.
* @param cache An optional ExtendedEntityCache. * @param cache An optional ExtendedEntityCache.
@@ -98,7 +98,7 @@ export const getExtendedEntities = async (
}; };
/** /**
* Get a list of all entities from the entity registry. * Get a list of all entities from the entity registry. May throw.
* @param hass The Home Assistant object. * @param hass The Home Assistant object.
* @returns An entity list object. * @returns An entity list object.
*/ */
+25 -25
View File
@@ -9,7 +9,7 @@ import {
FrigateCardError, FrigateCardError,
SignedPath, SignedPath,
signedPathSchema, signedPathSchema,
StateParameters StateParameters,
} from '../../types.js'; } from '../../types.js';
import { stateIcon } from '../icons/state-icon.js'; import { stateIcon } from '../icons/state-icon.js';
import { getParseErrorKeys } from '../zod.js'; import { getParseErrorKeys } from '../zod.js';
@@ -26,27 +26,30 @@ export async function homeAssistantWSRequest<T>(
schema: ZodSchema<T>, schema: ZodSchema<T>,
request: MessageBase, request: MessageBase,
): Promise<T> { ): Promise<T> {
const response = await hass.callWS<T>(request); let response;
try {
response = await hass.callWS<T>(request);
} catch (e) {
if (!(e instanceof Error)) {
throw new FrigateCardError(localize('error.failed_response'), {
request: request,
response: e,
});
}
throw e;
}
if (!response) { if (!response) {
const error_message = `${localize('error.empty_response')}: ${JSON.stringify( throw new FrigateCardError(localize('error.empty_response'), {
request, request: request,
)}`; });
console.warn(error_message);
throw new Error(error_message);
} }
const parseResult = schema.safeParse(response); const parseResult = schema.safeParse(response);
if (!parseResult.success) { if (!parseResult.success) {
const keys = getParseErrorKeys<T>(parseResult.error); throw new FrigateCardError(localize('error.invalid_response'), {
const error_message = localize('error.invalid_response');
console.warn(
`${error_message}: ${JSON.stringify(request)}. ${localize(
'error.invalid_keys',
)}: ${keys}`,
);
throw new FrigateCardError(error_message, {
request: request, request: request,
invalid_keys: keys, response: response,
invalid_keys: getParseErrorKeys<T>(parseResult.error),
}); });
} }
return parseResult.data; return parseResult.data;
@@ -96,9 +99,7 @@ export async function homeAssistantHTTPRequest<T>(
let signResponse: string | null | undefined; let signResponse: string | null | undefined;
try { try {
signResponse = await homeAssistantSignPath(hass, url); signResponse = await homeAssistantSignPath(hass, url);
} catch (e) { } catch (e) {}
console.warn(e);
}
if (!signResponse) { if (!signResponse) {
throw new FrigateCardError(localize('error.failed_sign'), { throw new FrigateCardError(localize('error.failed_sign'), {
@@ -127,21 +128,20 @@ export async function homeAssistantHTTPRequest<T>(
try { try {
raw_json = await response.json(); raw_json = await response.json();
} catch (e) { } catch (e) {
console.warn(e);
throw new FrigateCardError(localize('error.undecodable_response'), { throw new FrigateCardError(localize('error.undecodable_response'), {
url: signedURL.toString(), url: signedURL.toString(),
}); });
} }
try { const parseResult = schema.safeParse(raw_json);
return schema.parse(raw_json); if (!parseResult.success) {
} catch (e) {
console.warn(e);
throw new FrigateCardError(localize('error.invalid_response'), { throw new FrigateCardError(localize('error.invalid_response'), {
url: signedURL.toString(), url: signedURL.toString(),
response: raw_json, raw_json: raw_json,
invalid_keys: getParseErrorKeys<T>(parseResult.error),
}); });
} }
return parseResult.data;
} }
interface HassStateDifference { interface HassStateDifference {
+11 -6
View File
@@ -2,10 +2,11 @@ import { HomeAssistant } from 'custom-card-helpers';
import QuickLRU from 'quick-lru'; import QuickLRU from 'quick-lru';
import { homeAssistantWSRequest } from '.'; import { homeAssistantWSRequest } from '.';
import { import {
FrigateBrowseMediaSource, FrigateBrowseMediaSource,
ResolvedMedia, ResolvedMedia,
resolvedMediaSchema resolvedMediaSchema,
} from '../../types.js'; } from '../../types.js';
import { errorToConsole } from '../basic';
// It's important the cache size be at least as large as the largest likely // It's important the cache size be at least as large as the largest likely
// media query or media items will from a given query will be evicted for other // media query or media items will from a given query will be evicted for other
@@ -30,7 +31,6 @@ export class ResolvedMediaCache {
return this._cache.has(id); return this._cache.has(id);
} }
/** /**
* Get resolved media information given an id. * Get resolved media information given an id.
* @param id The id. * @param id The id.
@@ -55,7 +55,7 @@ export class ResolvedMediaCache {
* @param hass The Home Assistant object. * @param hass The Home Assistant object.
* @param mediaSource The media source object. * @param mediaSource The media source object.
* @param cache An optional ResolvedMediaCache object. * @param cache An optional ResolvedMediaCache object.
* @returns * @returns The resolved media or `null`.
*/ */
export const resolveMedia = async ( export const resolveMedia = async (
hass: HomeAssistant, hass: HomeAssistant,
@@ -73,7 +73,12 @@ export const resolveMedia = async (
type: 'media_source/resolve_media', type: 'media_source/resolve_media',
media_content_id: mediaSource.media_content_id, media_content_id: mediaSource.media_content_id,
}; };
const resolvedMedia = await homeAssistantWSRequest(hass, resolvedMediaSchema, request); let resolvedMedia: ResolvedMedia | null = null;
try {
resolvedMedia = await homeAssistantWSRequest(hass, resolvedMediaSchema, request);
} catch (e) {
errorToConsole(e as Error);
}
if (cache && resolvedMedia) { if (cache && resolvedMedia) {
cache.set(mediaSource.media_content_id, resolvedMedia); cache.set(mediaSource.media_content_id, resolvedMedia);
} }