import { FrigateCardMediaPlayer, MediaLoadedCapabilities, MediaLoadedInfo, MediaTechnology, } from '../types.js'; import { dispatchFrigateCardEvent } from './basic.js'; const MEDIA_INFO_HEIGHT_CUTOFF = 50; const MEDIA_INFO_WIDTH_CUTOFF = MEDIA_INFO_HEIGHT_CUTOFF; /** * Create a MediaLoadedInfo object. * @param source An event or HTMLElement that should be used as a source. * @returns A new MediaLoadedInfo object or null if one could not be created. */ export function createMediaLoadedInfo( source: Event | HTMLElement, options?: { player?: FrigateCardMediaPlayer; capabilities?: MediaLoadedCapabilities; technology?: MediaTechnology[]; }, ): MediaLoadedInfo | null { let target: HTMLElement | EventTarget; if (source instanceof Event) { target = source.composedPath()[0]; } else { target = source; } if (target instanceof HTMLImageElement) { return { width: (target as HTMLImageElement).naturalWidth, height: (target as HTMLImageElement).naturalHeight, ...options, }; } else if (target instanceof HTMLVideoElement) { return { width: (target as HTMLVideoElement).videoWidth, height: (target as HTMLVideoElement).videoHeight, ...options, }; } else if (target instanceof HTMLCanvasElement) { return { width: (target as HTMLCanvasElement).width, height: (target as HTMLCanvasElement).height, player: options?.player, ...options, }; } return null; } /** * Dispatch a Frigate card media loaded event. * @param element The element to send the event. * @param source An event or HTMLElement that should be used as a source. */ export function dispatchMediaLoadedEvent( target: HTMLElement, source: Event | HTMLElement, options?: { player?: FrigateCardMediaPlayer; capabilities?: MediaLoadedCapabilities; technology?: MediaTechnology[]; }, ): void { const mediaLoadedInfo = createMediaLoadedInfo(source, options); if (mediaLoadedInfo) { dispatchExistingMediaLoadedInfoAsEvent(target, mediaLoadedInfo); } } /** * Dispatch a pre-existing MediaLoadedInfo object as an event. * @param element The element to send the event. * @param MediaLoadedInfo The MediaLoadedInfo object to send. */ export function dispatchExistingMediaLoadedInfoAsEvent( target: EventTarget, MediaLoadedInfo: MediaLoadedInfo, ): void { dispatchFrigateCardEvent(target, 'media:loaded', MediaLoadedInfo); } /** * Dispatch a media unloaded event. * @param element The element to send the event. */ export function dispatchMediaUnloadedEvent(element: HTMLElement): void { dispatchFrigateCardEvent(element, 'media:unloaded'); } export function dispatchMediaVolumeChangeEvent(target: HTMLElement): void { dispatchFrigateCardEvent(target, 'media:volumechange'); } export function dispatchMediaPlayEvent(target: HTMLElement): void { dispatchFrigateCardEvent(target, 'media:play'); } export function dispatchMediaPauseEvent(target: HTMLElement): void { dispatchFrigateCardEvent(target, 'media:pause'); } /** * Determine if a MediaLoadedInfo object is valid/acceptable. * @param info The MediaLoadedInfo object. * @returns True if the object is valid, false otherwise. */ export function isValidMediaLoadedInfo(info: MediaLoadedInfo): boolean { return ( info.height >= MEDIA_INFO_HEIGHT_CUTOFF && info.width >= MEDIA_INFO_WIDTH_CUTOFF ); } // Facilitates correct typing of event handlers. export interface FrigateCardMediaLoadedEventTarget extends EventTarget { addEventListener( event: 'frigate-card:media:loaded', listener: ( this: FrigateCardMediaLoadedEventTarget, ev: CustomEvent, ) => void, options?: AddEventListenerOptions | boolean, ): void; addEventListener( event: 'frigate-card:media:unloaded', listener: (this: FrigateCardMediaLoadedEventTarget, ev: CustomEvent) => void, options?: AddEventListenerOptions | boolean, ): void; addEventListener( type: string, callback: EventListenerOrEventListenerObject, options?: AddEventListenerOptions | boolean, ): void; removeEventListener( event: 'frigate-card:media:loaded', listener: ( this: FrigateCardMediaLoadedEventTarget, ev: CustomEvent, ) => void, options?: boolean | EventListenerOptions, ): void; removeEventListener( event: 'frigate-card:media:unloaded', listener: (this: FrigateCardMediaLoadedEventTarget, ev: CustomEvent) => void, options?: boolean | EventListenerOptions, ): void; removeEventListener( type: string, callback: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions, ): void; }