4 lines
26 KiB
JavaScript
4 lines
26 KiB
JavaScript
import{d3 as e,d_ as t,d$ as n,e0 as a,e1 as r,e2 as i,l as s,e3 as o,e4 as c,e5 as g,e6 as l,db as u,dT as m,k as d,i as f,dh as h,e7 as p,dn as _,d9 as y,d7 as b,e8 as w,e9 as D,ea as C,dQ as v,j as T,eb as I,dc as S,de as M,dd as F}from"./card-c642ee74.js";import{C as $}from"./engine-86b0096c.js";import{C as z,G as N,g as E}from"./engine-generic-bb62ddef.js";import{a as R,V as Y}from"./media-c9012082.js";import{s as x,e as H}from"./startOfHour-4de961cf.js";function j(t){return e(1e3*t)}const Z=n.object({camera:n.string(),end_time:n.number().nullable(),false_positive:n.boolean().nullable(),has_clip:n.boolean(),has_snapshot:n.boolean(),id:n.string(),label:n.string(),sub_label:n.string().nullable(),start_time:n.number(),top_score:n.number().nullable(),zones:n.string().array(),retain_indefinitely:n.boolean().optional()}).array(),q=n.object({hour:n.preprocess((e=>Number(e)),n.number().min(0).max(23)),duration:n.number().min(0),events:n.number().min(0)}),U=n.object({day:n.preprocess((e=>"string"==typeof e?a(e):e),n.date()),events:n.number(),hours:q.array()}).array(),W=n.object({start_time:n.number(),end_time:n.number(),id:n.string()}).array(),Q=n.object({success:n.boolean(),message:n.string()}),k=n.object({camera:n.string(),day:n.string(),label:n.string(),sub_label:n.string().nullable(),zones:n.string().array()}).array(),P=n.object({name:n.string().optional(),features:n.string().array().optional(),presets:n.string().array().optional()}),A=n.object({camera:n.string(),snapshot:n.object({frame_time:n.number()}).nullable(),has_clip:n.boolean(),has_snapshot:n.boolean(),label:n.string(),current_zones:n.string().array()}),O=n.object({before:A,after:A,type:n.enum(["new","update","end"])});const L=async(e,t)=>await r(e,Z,{type:"frigate/events/get",...t},!0),V=e=>"birdseye"===e.frigate.camera_name;class G extends z{constructor(e,t,n){super(e,t,n),this._frigateEventHandler=e=>{const t=!e.before.has_snapshot&&e.after.has_snapshot||e.before.snapshot?.frame_time!==e.after.snapshot?.frame_time,n=!e.before.has_clip&&e.after.has_clip,a=this.getConfig();if(a.frigate.zones?.length&&!a.frigate.zones.some((t=>e.after.current_zones.includes(t)))||a.frigate.labels?.length&&!a.frigate.labels.includes(e.after.label))return;const r=a.triggers.events;(r.includes("events")||r.includes("snapshots")&&t||r.includes("clips")&&n)&&this._eventCallback?.({fidelity:"high",cameraID:this.getID(),type:e.type,clip:n&&r.includes("clips"),snapshot:t&&r.includes("snapshots")})}}async initialize(e){return await this._initializeConfig(e.hass,e.entityRegistryManager),await this._initializeCapabilities(e.hass),await this._subscribeToEvents(e.hass,e.frigateEventWatcher),await super.initialize(e)}async _initializeConfig(e,n){const a=this.getConfig(),r=!!a.frigate?.camera_name,i=a.triggers.motion||a.triggers.occupancy;let g=null;const l=o(a);if(l&&(!r||i)&&(g=await n.getEntity(e,l),!g))throw new c(s("error.no_camera_entity"),a);if(g&&!r){const e=this._getFrigateCameraNameFromEntity(g);e&&(this._config.frigate.camera_name=e)}if(i){const r=await n.getMatchingEntities(e,(e=>e.config_entry_id===g?.config_entry_id&&!e.disabled_by&&e.entity_id.startsWith("binary_sensor.")));if(a.triggers.motion){const e=this._getMotionSensor(a,[...r.values()]);e&&a.triggers.entities.push(e)}if(a.triggers.occupancy){const e=this._getOccupancySensor(a,[...r.values()]);e&&a.triggers.entities.push(...e)}a.triggers.entities=(u=a.triggers.entities)&&u.length?t(u):[]}var u}async _initializeCapabilities(e){const t=this.getConfig(),n=g(this.getConfig()),a=await this._getPTZCapabilities(e,t),r=n||a?{...a,...n}:null,i=V(t);this._capabilities=new l({"favorite-events":!i,"favorite-recordings":!1,seek:!i,clips:!i,snapshots:!i,recordings:!i,live:!0,menu:!0,substream:!0,...r&&{ptz:r}},{disable:t.capabilities?.disable,disableExcept:t.capabilities?.disable_except})}_getFrigateCameraNameFromEntity(e){if("frigate"===e.platform&&e.unique_id&&"string"==typeof e.unique_id){const t=e.unique_id.match(/:camera:(?<camera>[^:]+)$/);if(t&&t.groups)return t.groups.camera}return null}async _getPTZCapabilities(e,t){if(!t.frigate.camera_name||V(t))return null;let n=null;try{n=await(async(e,t,n)=>await r(e,P,{type:"frigate/ptz/info",instance_id:t,camera:n},!0))(e,t.frigate.client_id,t.frigate.camera_name)}catch(e){return u(e),null}const a=[...n.features?.includes("pt")?["continuous"]:[]],i=[...n.features?.includes("zoom")?["continuous"]:[]],s=n.presets;return a.length||i.length||s?.length?{...a&&{left:a,right:a,up:a,down:a},...i&&{zoomIn:i,zoomOut:i},...s&&{presets:s}}:null}_getMotionSensor(e,t){return e.frigate.camera_name?t.find((t=>"string"==typeof t.unique_id&&!!t.unique_id?.match(new RegExp(`:motion_sensor:${e.frigate.camera_name}`))))?.entity_id??null:null}_getOccupancySensor(e,t){const n=[],a=(e,a)=>{const r=t.find((t=>"string"==typeof t.unique_id&&!!t.unique_id?.match(new RegExp(`:occupancy_sensor:${e}_${a}`))))?.entity_id??null;r&&n.push(r)};if(e.frigate.camera_name){const t=e.frigate.zones?.length?e.frigate.zones:[e.frigate.camera_name],r=e.frigate.labels?.length?e.frigate.labels:["all"];for(const e of t)for(const t of r)a(e,t);if(n.length)return n}return null}async _subscribeToEvents(e,t){const n=this.getConfig();if(!n.triggers.events.length||!n.frigate.camera_name)return;
|
||
/* istanbul ignore next -- exercising the matcher is not possible when the
|
||
test uses an event watcher -- @preserve */const a={instanceID:n.frigate.client_id,callback:e=>this._frigateEventHandler(e),matcher:e=>e.after.camera===n.frigate.camera_name};await t.subscribe(e,a),this._onDestroy((()=>t.unsubscribe(a)))}}class J{constructor(){this._requests=[],this._unsubscribeCallback={}}async subscribe(e,t){const n=!this._hasSubscribers(t.instanceID);this._requests.push(t),n&&(this._unsubscribeCallback[t.instanceID]=await e.connection.subscribeMessage((e=>this._receiveHandler(t.instanceID,e)),{type:"frigate/events/subscribe",instance_id:t.instanceID}))}async unsubscribe(e){this._requests=this._requests.filter((t=>t!==e)),this._hasSubscribers(e.instanceID)||(await this._unsubscribeCallback[e.instanceID](),delete this._unsubscribeCallback[e.instanceID])}_hasSubscribers(e){return!!this._requests.filter((t=>t.instanceID===e)).length}_receiveHandler(e,t){let n;try{n=JSON.parse(t)}catch(e){return void console.warn("Received non-JSON payload as Frigate event",t)}const a=O.safeParse(n);if(a.success)for(const t of this._requests)t.instanceID!==e||t.matcher&&!t.matcher(a.data)||t.callback(a.data);else console.warn("Received malformed Frigate event from Home Assistant",t)}}function B(e,t){const n=function(e){if(!X[e]){const t=new Intl.DateTimeFormat("en-US",{hourCycle:"h23",timeZone:"America/New_York",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(new Date("2014-06-25T04:00:00.123Z")),n="06/25/2014, 00:00:00"===t||"06/25/2014 00:00:00"===t;X[e]=n?new Intl.DateTimeFormat("en-US",{hourCycle:"h23",timeZone:e,year:"numeric",month:"numeric",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}):new Intl.DateTimeFormat("en-US",{hour12:!1,timeZone:e,year:"numeric",month:"numeric",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}return X[e]}(t);return"formatToParts"in n?function(e,t){try{const n=e.formatToParts(t),a=[];for(let e=0;e<n.length;e++){const t=K[n[e].type];void 0!==t&&(a[t]=parseInt(n[e].value,10))}return a}catch(e){if(e instanceof RangeError)return[NaN];throw e}}(n,e):function(e,t){const n=e.format(t),a=/(\d+)\/(\d+)\/(\d+),? (\d+):(\d+):(\d+)/.exec(n);return[parseInt(a[3],10),parseInt(a[1],10),parseInt(a[2],10),parseInt(a[4],10),parseInt(a[5],10),parseInt(a[6],10)]}(n,e)}const K={year:0,month:1,day:2,hour:3,minute:4,second:5};const X={};function ee(e,t,n,a,r,i,s){const o=new Date(0);return o.setUTCFullYear(e,t,n),o.setUTCHours(a,r,i,s),o}const te=36e5,ne=6e4,ae={timezone:/([Z+-].*)$/,timezoneZ:/^(Z)$/,timezoneHH:/^([+-]\d{2})$/,timezoneHHMM:/^([+-])(\d{2}):?(\d{2})$/};function re(e,t,n){if(!e)return 0;let a,r,i=ae.timezoneZ.exec(e);if(i)return 0;if(i=ae.timezoneHH.exec(e),i)return a=parseInt(i[1],10),se(a)?-a*te:NaN;if(i=ae.timezoneHHMM.exec(e),i){a=parseInt(i[2],10);const e=parseInt(i[3],10);return se(a,e)?(r=Math.abs(a)*te+e*ne,"+"===i[1]?-r:r):NaN}if(function(e){if(oe[e])return!0;try{return new Intl.DateTimeFormat(void 0,{timeZone:e}),oe[e]=!0,!0}catch(e){return!1}}(e)){t=new Date(t||Date.now());const a=n?t:function(e){return ee(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),e.getMilliseconds())}(t),r=ie(a,e),i=n?r:function(e,t,n){const a=e.getTime();let r=a-t;const i=ie(new Date(r),n);if(t===i)return t;r-=i-t;const s=ie(new Date(r),n);if(i===s)return i;return Math.max(i,s)}(t,r,e);return-i}return NaN}function ie(e,t){const n=B(e,t),a=ee(n[0],n[1]-1,n[2],n[3]%24,n[4],n[5],0).getTime();let r=e.getTime();const i=r%1e3;return r-=i>=0?i:1e3+i,a-r}function se(e,t){return-23<=e&&e<=23&&(null==t||0<=t&&t<=59)}const oe={};function ce(e){const t=new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),e.getMilliseconds()));return t.setUTCFullYear(e.getFullYear()),+e-+t}const ge=36e5,le=6e4,ue=2,me={dateTimePattern:/^([0-9W+-]+)(T| )(.*)/,datePattern:/^([0-9W+-]+)(.*)/,plainTime:/:/,YY:/^(\d{2})$/,YYY:[/^([+-]\d{2})$/,/^([+-]\d{3})$/,/^([+-]\d{4})$/],YYYY:/^(\d{4})/,YYYYY:[/^([+-]\d{4})/,/^([+-]\d{5})/,/^([+-]\d{6})/],MM:/^-(\d{2})$/,DDD:/^-?(\d{3})$/,MMDD:/^-?(\d{2})-?(\d{2})$/,Www:/^-?W(\d{2})$/,WwwD:/^-?W(\d{2})-?(\d{1})$/,HH:/^(\d{2}([.,]\d*)?)$/,HHMM:/^(\d{2}):?(\d{2}([.,]\d*)?)$/,HHMMSS:/^(\d{2}):?(\d{2}):?(\d{2}([.,]\d*)?)$/,timeZone:/(Z|[+-]\d{2}(?::?\d{2})?| UTC| [a-zA-Z]+\/[a-zA-Z_]+(?:\/[a-zA-Z_]+)?)$/};function de(e,t={}){if(arguments.length<1)throw new TypeError("1 argument required, but only "+arguments.length+" present");if(null===e)return new Date(NaN);const n=null==t.additionalDigits?ue:Number(t.additionalDigits);if(2!==n&&1!==n&&0!==n)throw new RangeError("additionalDigits must be 0, 1 or 2");if(e instanceof Date||"object"==typeof e&&"[object Date]"===Object.prototype.toString.call(e))return new Date(e.getTime());if("number"==typeof e||"[object Number]"===Object.prototype.toString.call(e))return new Date(e);if("[object String]"!==Object.prototype.toString.call(e))return new Date(NaN);const a=function(e){const t={};let n,a=me.dateTimePattern.exec(e);a?(t.date=a[1],n=a[3]):(a=me.datePattern.exec(e),a?(t.date=a[1],n=a[2]):(t.date=null,n=e));if(n){const e=me.timeZone.exec(n);e?(t.time=n.replace(e[1],""),t.timeZone=e[1].trim()):t.time=n}return t}(e),{year:r,restDateString:i}=function(e,t){if(e){const n=me.YYY[t],a=me.YYYYY[t];let r=me.YYYY.exec(e)||a.exec(e);if(r){const t=r[1];return{year:parseInt(t,10),restDateString:e.slice(t.length)}}if(r=me.YY.exec(e)||n.exec(e),r){const t=r[1];return{year:100*parseInt(t,10),restDateString:e.slice(t.length)}}}return{year:null}}(a.date,n),s=function(e,t){if(null===t)return null;let n,a,r;if(!e||!e.length)return n=new Date(0),n.setUTCFullYear(t),n;let i=me.MM.exec(e);if(i)return n=new Date(0),a=parseInt(i[1],10)-1,ye(t,a)?(n.setUTCFullYear(t,a),n):new Date(NaN);if(i=me.DDD.exec(e),i){n=new Date(0);const e=parseInt(i[1],10);return function(e,t){if(t<1)return!1;const n=_e(e);if(n&&t>366)return!1;if(!n&&t>365)return!1;return!0}(t,e)?(n.setUTCFullYear(t,0,e),n):new Date(NaN)}if(i=me.MMDD.exec(e),i){n=new Date(0),a=parseInt(i[1],10)-1;const e=parseInt(i[2],10);return ye(t,a,e)?(n.setUTCFullYear(t,a,e),n):new Date(NaN)}if(i=me.Www.exec(e),i)return r=parseInt(i[1],10)-1,be(r)?fe(t,r):new Date(NaN);if(i=me.WwwD.exec(e),i){r=parseInt(i[1],10)-1;const e=parseInt(i[2],10)-1;return be(r,e)?fe(t,r,e):new Date(NaN)}return null}(i,r);if(null===s||isNaN(s.getTime()))return new Date(NaN);if(s){const e=s.getTime();let n,r=0;if(a.time&&(r=function(e){let t,n,a=me.HH.exec(e);if(a)return t=parseFloat(a[1].replace(",",".")),we(t)?t%24*ge:NaN;if(a=me.HHMM.exec(e),a)return t=parseInt(a[1],10),n=parseFloat(a[2].replace(",",".")),we(t,n)?t%24*ge+n*le:NaN;if(a=me.HHMMSS.exec(e),a){t=parseInt(a[1],10),n=parseInt(a[2],10);const e=parseFloat(a[3].replace(",","."));return we(t,n,e)?t%24*ge+n*le+1e3*e:NaN}return null}(a.time),null===r||isNaN(r)))return new Date(NaN);if(a.timeZone||t.timeZone){if(n=re(a.timeZone||t.timeZone,new Date(e+r)),isNaN(n))return new Date(NaN)}else n=ce(new Date(e+r)),n=ce(new Date(e+r+n));return new Date(e+r+n)}return new Date(NaN)}function fe(e,t,n){t=t||0,n=n||0;const a=new Date(0);a.setUTCFullYear(e,0,4);const r=7*t+n+1-(a.getUTCDay()||7);return a.setUTCDate(a.getUTCDate()+r),a}const he=[31,28,31,30,31,30,31,31,30,31,30,31],pe=[31,29,31,30,31,30,31,31,30,31,30,31];function _e(e){return e%400==0||e%4==0&&e%100!=0}function ye(e,t,n){if(t<0||t>11)return!1;if(null!=n){if(n<1)return!1;const a=_e(e);if(a&&n>pe[t])return!1;if(!a&&n>he[t])return!1}return!0}function be(e,t){return!(e<0||e>52)&&(null==t||!(t<0||t>6))}function we(e,t,n){return!(e<0||e>=25)&&((null==t||!(t<0||t>=60))&&(null==n||!(n<0||n>=60)))}const De=e=>{const t=Intl.DateTimeFormat().resolvedOptions().timeZone,n=Math.round(e.end_time?e.end_time-e.start_time:Date.now()/1e3-e.start_time),a=null!==e.top_score?` ${Math.round(100*e.top_score)}%`:"";return`${m(function(e,t,n){const a=re(t,e=de(e,n),!0),r=new Date(e.getTime()-a),i=new Date(0);return i.setFullYear(r.getUTCFullYear(),r.getUTCMonth(),r.getUTCDate()),i.setHours(r.getUTCHours(),r.getUTCMinutes(),r.getUTCSeconds(),r.getUTCMilliseconds()),i}(1e3*e.start_time,t))} [${n}s, ${d(e.label)}${a}]`};class Ce extends R{constructor(e,t,n,a,r,i){super(e,t),this._event=n,this._contentID=a,this._thumbnail=r,this._subLabels=i??null}getStartTime(){return j(this._event.start_time)}getEndTime(){return this._event.end_time?j(this._event.end_time):null}inProgress(){return!this.getEndTime()}getVideoContentType(){return Y.HLS}getID(){return this._event.id}getContentID(){return this._contentID}getTitle(){return De(this._event)}getThumbnail(){return this._thumbnail}isFavorite(){return this._event.retain_indefinitely??null}setFavorite(e){this._event.retain_indefinitely=e}getWhat(){return[this._event.label]}getWhere(){const e=this._event.zones;return e.length?e:null}getScore(){return this._event.top_score}getTags(){return this._subLabels}isGroupableWith(e){return this.getMediaType()===e.getMediaType()&&f(this.getWhere(),e.getWhere())&&f(this.getWhat(),e.getWhat())}}class ve extends R{constructor(e,t,n,a,r,i){super(e,t),this._recording=n,this._id=a,this._contentID=r,this._title=i}getID(){return this._id}getStartTime(){return this._recording.startTime}getEndTime(){return this._recording.endTime}inProgress(){return!this.getEndTime()}getVideoContentType(){return Y.HLS}getContentID(){return this._contentID}getTitle(){return this._title}getEventCount(){return this._recording.events}}class Te{static createEventViewMedia(e,t,n,a,r){return"clip"===e&&!a.has_clip||"snapshot"===e&&!a.has_snapshot||!n.frigate.client_id||!n.frigate.camera_name?null:new Ce(e,t,a,((e,t,n,a)=>`media-source://frigate/${e}/event/${a}/${t}/${n.id}`)(n.frigate.client_id,n.frigate.camera_name,a,"clip"===e?"clips":"snapshots"),((e,t)=>`/api/frigate/${e}/thumbnail/${t.id}`)(n.frigate.client_id,a),r)}static createRecordingViewMedia(e,t,n,a){return n.frigate.client_id&&n.frigate.camera_name?new ve("recording",e,t,((e,t)=>`${e.frigate?.client_id??""}/${e.frigate.camera_name??""}/${t.startTime.getTime()}/${t.endTime.getTime()}`)(n,t),((e,t,n)=>["media-source://frigate",e,"recordings",t,`${n.startTime.getFullYear()}-${String(n.startTime.getMonth()+1).padStart(2,"0")}-${String(String(n.startTime.getDate()).padStart(2,"0"))}`,String(n.startTime.getHours()).padStart(2,"0")].join("/"))(n.frigate.client_id,n.frigate.camera_name,t),((e,t)=>`${e} ${m(t.startTime)}`)(a,t)):null}}class Ie{static isFrigateMedia(e){return this.isFrigateEvent(e)||this.isFrigateRecording(e)}static isFrigateEvent(e){return e instanceof Ce}static isFrigateRecording(e){return e instanceof ve}}class Se{static isFrigateEventQueryResults(e){return e.engine===p.Frigate&&e.type===C.Event}static isFrigateRecordingQueryResults(e){return e.engine===p.Frigate&&e.type===C.Recording}static isFrigateRecordingSegmentsResults(e){return e.engine===p.Frigate&&e.type===C.RecordingSegments}}class Me extends N{constructor(e,t,n,a,r){super(t,r),this._throttledSegmentGarbageCollector=h(this._garbageCollectSegments.bind(this),36e5,{leading:!1,trailing:!0}),this._entityRegistryManager=e,this._frigateEventWatcher=new J,this._recordingSegmentsCache=n,this._requestCache=a}getEngineType(){return p.Frigate}async createCamera(e,t){const n=new G(t,this,{eventCallback:this._eventCallback});return await n.initialize({hass:e,entityRegistryManager:this._entityRegistryManager,stateWatcher:this._stateWatcher,frigateEventWatcher:this._frigateEventWatcher})}async getMediaDownloadPath(e,t,n){return Ie.isFrigateEvent(n)?{endpoint:`/api/frigate/${t.frigate.client_id}/notifications/${n.getID()}/`+(_.isClip(n)?"clip.mp4":"snapshot.jpg")+"?download=true",sign:!0}:Ie.isFrigateRecording(n)?{endpoint:`/api/frigate/${t.frigate.client_id}/recording/${t.frigate.camera_name}/start/${Math.floor(n.getStartTime().getTime()/1e3)}/end/${Math.floor(n.getEndTime().getTime()/1e3)}?download=true`,sign:!0}:null}generateDefaultEventQuery(e,t,n){const a=[...e.getCameraConfigs(t)],r=y(a.map((e=>e?.frigate.zones)),f),i=y(a.map((e=>e?.frigate.labels)),f);if(1===r.length&&1===i.length)return[{type:b.Event,cameraIDs:t,...i[0]&&{what:new Set(i[0])},...r[0]&&{where:new Set(r[0])},...n}];const s=[];for(const a of t){const t=e.getCameraConfig(a);t&&s.push({type:b.Event,cameraIDs:new Set([a]),...t.frigate.labels&&{what:new Set(t.frigate.labels)},...t.frigate.zones&&{where:new Set(t.frigate.zones)},...n})}return s.length?s:null}generateDefaultRecordingQuery(e,t,n){return[{type:b.Recording,cameraIDs:t,...n}]}generateDefaultRecordingSegmentsQuery(e,t,n){return n.start&&n.end?[{type:b.RecordingSegments,cameraIDs:t,start:n.start,end:n.end,...n}]:null}async favoriteMedia(e,t,n,a){Ie.isFrigateEvent(n)&&(await async function(e,t,n,a){const o={type:"frigate/event/retain",instance_id:t,event_id:n,retain:a},c=await r(e,Q,o,!0);if(!c.success)throw new i(s("error.failed_retain"),{request:o,response:c})}(e,t.frigate.client_id,n.getID(),a),n.setFavorite(a))}_buildInstanceToCameraIDMapFromQuery(e,t){const n=new Map;for(const a of t){const t=this._getQueryableCameraConfig(e,a),r=t?.frigate.client_id;r&&(n.has(r)||n.set(r,new Set),n.get(r)?.add(a))}return n}_getFrigateCameraNamesForCameraIDs(e,t){const n=new Set;for(const a of t){const t=this._getQueryableCameraConfig(e,a);t?.frigate.camera_name&&n.add(t.frigate.camera_name)}return n}async getEvents(e,t,n,a){const r=new Map,i=async(i,s)=>{if(!s||!s.size)return;const o={...n,cameraIDs:s},c=a?.useCache??1?this._requestCache.get(o):null;if(c)return void r.set(n,c);const g={instance_id:i,cameras:Array.from(this._getFrigateCameraNamesForCameraIDs(t,s)),...n.what&&{labels:Array.from(n.what)},...n.where&&{zones:Array.from(n.where)},...n.tags&&{sub_labels:Array.from(n.tags)},...n.end&&{before:Math.floor(n.end.getTime()/1e3)},...n.start&&{after:Math.floor(n.start.getTime()/1e3)},...n.limit&&{limit:n.limit},...n.hasClip&&{has_clip:n.hasClip},...n.hasSnapshot&&{has_snapshot:n.hasSnapshot},...n.favorite&&{favorites:n.favorite},limit:n?.limit??$},l={type:C.Event,engine:p.Frigate,instanceID:i,events:await L(e,g),expiry:v(new Date,{seconds:60}),cached:!1};(a?.useCache??1)&&this._requestCache.set(n,{...l,cached:!0},l.expiry),r.set(o,l)},s=this._buildInstanceToCameraIDMapFromQuery(t,n.cameraIDs);return await Promise.all(Array.from(s.keys()).map((e=>i(e,s.get(e))))),r.size?r:null}async getRecordings(e,t,n,a){const i=new Map,s=async(n,s)=>{const o={...n,cameraIDs:new Set([s])},c=a?.useCache??1?this._requestCache.get(o):null;if(c)return void i.set(o,c);const g=this._getQueryableCameraConfig(t,s);if(!g||!g.frigate.camera_name)return;const l=await(async(e,t,n)=>await r(e,U,{type:"frigate/recordings/summary",instance_id:t,camera:n,timezone:e.config.time_zone},!0))(e,g.frigate.client_id,g.frigate.camera_name);let u=[];for(const e of l??[])for(const t of e.hours){const n=v(e.day,{hours:t.hour}),a=x(n),r=H(n);(!o.start||a>=o.start)&&(!o.end||r<=o.end)&&u.push({cameraID:s,startTime:a,endTime:r,events:t.events})}void 0!==o.limit&&(u=S(u,(e=>e.startTime),"desc").slice(0,o.limit));const m={type:C.Recording,engine:p.Frigate,instanceID:g.frigate.client_id,recordings:u,expiry:v(new Date,{seconds:60}),cached:!1};(a?.useCache??1)&&this._requestCache.set(o,{...m,cached:!0},m.expiry),i.set(o,m)};return await Promise.all(Array.from(n.cameraIDs).map((e=>s(n,e)))),i.size?i:null}async getRecordingSegments(e,t,n,a){const i=new Map,s=async(n,s)=>{const o={...n,cameraIDs:new Set([s])},c=this._getQueryableCameraConfig(t,s);if(!c||!c.frigate.camera_name)return;const g={start:o.start,end:o.end},l=a?.useCache??1?this._recordingSegmentsCache.get(s,g):null;if(l)return void i.set(o,{type:C.RecordingSegments,engine:p.Frigate,instanceID:c.frigate.client_id,segments:l,cached:!0});const u={instance_id:c.frigate.client_id,camera:c.frigate.camera_name,after:Math.floor(o.start.getTime()/1e3),before:Math.floor(o.end.getTime()/1e3)},m=await(async(e,t)=>await r(e,W,{type:"frigate/recordings/get",...t},!0))(e,u);(a?.useCache??1)&&this._recordingSegmentsCache.add(s,g,m),i.set(o,{type:C.RecordingSegments,engine:p.Frigate,instanceID:c.frigate.client_id,segments:m,cached:!1})};return await Promise.all(Array.from(n.cameraIDs).map((e=>s(n,e)))),w((()=>this._throttledSegmentGarbageCollector(e,t))),i.size?i:null}_getCameraIDMatch(e,t,n,a){if(1===t.cameraIDs.size)return[...t.cameraIDs][0];for(const[t,r]of e.getCameraConfigEntries())if(r.frigate.client_id===n&&r.frigate.camera_name===a)return t;return null}generateMediaFromEvents(e,t,n,a){if(!Se.isFrigateEventQueryResults(a))return null;const r=[];for(const e of a.events){const i=this._getCameraIDMatch(t,n,a.instanceID,e.camera);if(!i)continue;const s=this._getQueryableCameraConfig(t,i);if(!s)continue;let o=null;if(n.hasClip||n.hasSnapshot||!e.has_clip&&!e.has_snapshot?n.hasSnapshot&&e.has_snapshot?o="snapshot":n.hasClip&&e.has_clip&&(o="clip"):o=e.has_clip?"clip":"snapshot",!o)continue;const c=Te.createEventViewMedia(o,i,s,e,e.sub_label?this._splitSubLabels(e.sub_label):void 0);c&&r.push(c)}return r}generateMediaFromRecordings(e,t,n,a){if(!Se.isFrigateRecordingQueryResults(a))return null;const r=[];for(const n of a.recordings){const a=this._getQueryableCameraConfig(t,n.cameraID);if(!a)continue;const i=Te.createRecordingViewMedia(n.cameraID,n,a,this.getCameraMetadata(e,a).title);i&&r.push(i)}return r}getQueryResultMaxAge(e){return e.type===b.Event||e.type===b.Recording?60:null}async getMediaSeekTime(e,t,n,a,r){const i=n.getStartTime(),s=n.getEndTime();if(!i||!s||a<i||a>s)return null;const o=n.getCameraID(),c={cameraIDs:new Set([o]),start:i,end:s,type:b.RecordingSegments},g=await this.getRecordingSegments(e,t,c,r);return g?this._getSeekTimeInSegments(i,a,Array.from(g.values())[0].segments):null}_getQueryableCameraConfig(e,t){const n=e.getCameraConfig(t);return!n||V(n)?null:n}_splitSubLabels(e){return e.split(",").map((e=>e.trim()))}async getMediaMetadata(e,t,n,a){const i=new Map;if((a?.useCache??1)&&this._requestCache.has(n)){const e=this._requestCache.get(n);if(e)return i.set(n,e),i}const s=new Set,o=new Set,c=new Set,g=new Set,l=this._buildInstanceToCameraIDMapFromQuery(t,n.cameraIDs),u=async(n,a)=>{const i=this._getFrigateCameraNamesForCameraIDs(t,a);for(const t of await(async(e,t)=>await r(e,k,{type:"frigate/events/summary",instance_id:t,timezone:e.config.time_zone},!0))(e,n))i.has(t.camera)&&(t.label&&s.add(t.label),t.zones.length&&t.zones.forEach(o.add,o),t.day&&c.add(t.day),t.sub_label&&this._splitSubLabels(t.sub_label).forEach(g.add,g))},m=async n=>{const r=await this.getRecordings(e,t,{type:b.Recording,cameraIDs:n},a);if(r)for(const e of r.values())if(Se.isFrigateRecordingQueryResults(e))for(const t of e.recordings)c.add(M(t.startTime))};await D([...l.entries()],(([e,t])=>(async()=>{await Promise.all([u(e,t),m(t)])})()));const d={type:C.MediaMetadata,engine:p.Frigate,metadata:{...s.size&&{what:s},...o.size&&{where:o},...c.size&&{days:c},...g.size&&{tags:g}},expiry:v(new Date,{seconds:60}),cached:!1};return(a?.useCache??1)&&this._requestCache.set(n,{...d,cached:!0},d.expiry),i.set(n,d),i}async _garbageCollectSegments(e,t){const n=this._recordingSegmentsCache.getCameraIDs(),a={cameraIDs:new Set(n),type:b.Recording},r=(e,t)=>`${e}/${t.getDate()}/${t.getHours()}`,i=await this.getRecordings(e,t,a);if(i)for(const[e,t]of i){if(!Se.isFrigateRecordingQueryResults(t))continue;const n=new Set;for(const e of t.recordings)n.add(r(e.cameraID,e.startTime));const a=Array.from(e.cameraIDs)[0];this._recordingSegmentsCache.expireMatches(a,(e=>{const t=r(a,j(e.start_time));return!n.has(t)}))}}_getSeekTimeInSegments(e,t,n){if(!n.length)return null;let a=0;for(const r of n){const n=j(r.start_time);if(n>t)break;const i=j(r.end_time),s=n<e?e:n;a+=(i>t?t:i).getTime()-s.getTime()}return a/1e3}getMediaCapabilities(e){return{canFavorite:_.isEvent(e),canDownload:!0}}getCameraMetadata(e,t){const n=super.getCameraMetadata(e,t);return{title:t.title??T(e,t.camera_entity)??T(e,t.webrtc_card?.entity)??d(t.frigate?.camera_name)??t.id??"",icon:n.icon,engineLogo:I}}getCameraEndpoints(e,t){const n=(()=>{if(!e.frigate.url)return null;if(!e.frigate.camera_name)return{endpoint:e.frigate.url};const n=`${e.frigate.url}/cameras/`+e.frigate.camera_name;if("live"===t?.view)return{endpoint:n};const a=`${e.frigate.url}/events?camera=`+e.frigate.camera_name,r=`${e.frigate.url}/recording/`+e.frigate.camera_name;switch(t?.media?.getMediaType()){case"clip":case"snapshot":return{endpoint:a};case"recording":const e=t.media.getStartTime();if(e)return{endpoint:r+F(e,"yyyy-MM-dd/HH")}}switch(t?.view){case"clip":case"clips":case"snapshots":case"snapshot":return{endpoint:a};case"recording":case"recordings":return{endpoint:r}}return{endpoint:n}})(),a=E(e,{url:e.go2rtc?.url??`/api/frigate/${e.frigate.client_id}/mse`,stream:e.go2rtc?.stream??e.frigate.camera_name}),r={endpoint:`/api/frigate/${e.frigate.client_id}/jsmpeg/${e.frigate.camera_name}`,sign:!0},i=(()=>{const t=e.frigate.camera_name?e.frigate.camera_name:null;return t?{endpoint:t}:null})();return{...super.getCameraEndpoints(e,t),...n&&{ui:n},...a&&{go2rtc:a},...r&&{jsmpeg:r},...i&&{webrtcCard:i}}}async executePTZAction(e,t,n,a){const r=t.camera_entity;("preset"!==n||a?.preset)&&await e.callService("frigate","ptz",{entity_id:r,action:"stop"===a?.phase?"stop":"zoom_in"===n||"zoom_out"===n?"zoom":"preset"===n?"preset":"move",..."stop"!==a?.phase&&{argument:"zoom_in"===n?"in":"zoom_out"===n?"out":"preset"===n?a?.preset:n}})}}export{Me as FrigateCameraManagerEngine};
|