camstreamerlib 4.0.0-beta.3 → 4.0.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -99,13 +99,15 @@ const audioDeviceFromRequestSchema = zod_1.z.object({
99
99
  });
100
100
  exports.audioDeviceRequestSchema = zod_1.z.object({ devices: zod_1.z.array(audioDeviceFromRequestSchema) });
101
101
  exports.maxFpsResponseSchema = zod_1.z.object({
102
- data: zod_1.z.array(zod_1.z.object({
102
+ data: zod_1.z
103
+ .array(zod_1.z.object({
103
104
  channel: zod_1.z.number(),
104
105
  captureMode: zod_1.z.array(zod_1.z.object({
105
106
  enabled: zod_1.z.boolean(),
106
107
  maxFPS: zod_1.z.number().optional(),
107
108
  })),
108
- })),
109
+ }))
110
+ .optional(),
109
111
  });
110
112
  exports.dateTimeinfoSchema = zod_1.z.object({
111
113
  data: zod_1.z.object({
@@ -118,15 +120,11 @@ exports.dateTimeinfoSchema = zod_1.z.object({
118
120
  });
119
121
  exports.audioSampleRatesResponseSchema = zod_1.z.object({
120
122
  data: zod_1.z.object({
121
- encoders: zod_1.z.union([
122
- zod_1.z.object({
123
- aac: zod_1.z.array(audioSampleRatesSchema),
124
- AAC: zod_1.z.undefined(),
125
- }),
126
- zod_1.z.object({
127
- AAC: zod_1.z.array(audioSampleRatesSchema),
128
- aac: zod_1.z.undefined(),
129
- }),
130
- ]),
123
+ encoders: zod_1.z
124
+ .object({
125
+ aac: zod_1.z.array(audioSampleRatesSchema),
126
+ AAC: zod_1.z.array(audioSampleRatesSchema),
127
+ })
128
+ .partial(),
131
129
  }),
132
130
  });
@@ -121,10 +121,10 @@ export class CamOverlayDrawingAPI extends EventEmitter {
121
121
  }
122
122
  if (dataJSON.call_id !== undefined) {
123
123
  if (errorResponse !== undefined) {
124
- this.sendMessages[dataJSON.call_id].reject(new Error(errorResponse.error));
124
+ this.sendMessages[dataJSON.call_id]?.reject(new Error(errorResponse.error));
125
125
  }
126
126
  else {
127
- this.sendMessages[dataJSON.call_id].resolve(dataJSON);
127
+ this.sendMessages[dataJSON.call_id]?.resolve(dataJSON);
128
128
  }
129
129
  delete this.sendMessages[dataJSON.call_id];
130
130
  }
@@ -194,6 +194,9 @@ export class CamOverlayDrawingAPI extends EventEmitter {
194
194
  const now = Date.now();
195
195
  for (const callId in this.sendMessages) {
196
196
  const msg = this.sendMessages[callId];
197
+ if (!msg) {
198
+ continue;
199
+ }
197
200
  if (now - msg.sentTimestamp > 10000) {
198
201
  reconnect = true;
199
202
  msg.reject(new Error('Message timeout'));
@@ -220,7 +223,7 @@ export class CamOverlayDrawingAPI extends EventEmitter {
220
223
  }
221
224
  reportClose() {
222
225
  for (const callId in this.sendMessages) {
223
- this.sendMessages[callId].reject(new Error('Connection lost'));
226
+ this.sendMessages[callId]?.reject(new Error('Connection lost'));
224
227
  }
225
228
  this.sendMessages = {};
226
229
  this.emit('close');
@@ -1,11 +1,22 @@
1
1
  import { CamOverlayDrawingAPI, CamOverlayDrawingOptions } from '../CamOverlayDrawingAPI';
2
2
  import ResourceManager from './ResourceManager';
3
3
  import { Frame, TFrameOptions } from './Frame';
4
- export declare const COORD: Record<string, [number, number]>;
4
+ export declare const COORD: {
5
+ readonly top_left: readonly [-1, -1];
6
+ readonly center_left: readonly [-1, 0];
7
+ readonly bottom_left: readonly [-1, 1];
8
+ readonly top_center: readonly [0, -1];
9
+ readonly center: readonly [0, 0];
10
+ readonly bottom_center: readonly [0, 1];
11
+ readonly top_right: readonly [1, -1];
12
+ readonly center_right: readonly [1, 0];
13
+ readonly bottom_right: readonly [1, 1];
14
+ };
15
+ type TCoAlignment = keyof typeof COORD;
5
16
  export type TPainterOptions = TFrameOptions & {
6
17
  screenWidth: number;
7
18
  screenHeight: number;
8
- coAlignment: string;
19
+ coAlignment: TCoAlignment;
9
20
  };
10
21
  export declare class Painter extends Frame {
11
22
  private screenWidth;
@@ -24,7 +35,7 @@ export declare class Painter extends Frame {
24
35
  registerImage(moniker: string, fileName: string): void;
25
36
  registerFont(moniker: string, fileName: string): void;
26
37
  setScreenSize(sw: number, sh: number): void;
27
- setCoAlignment(coAlignment: string): void;
38
+ setCoAlignment(coAlignment: TCoAlignment): void;
28
39
  protected layoutChanged(): void;
29
40
  display(scale?: number): Promise<void>;
30
41
  hide(): Promise<void>;
@@ -82,6 +82,9 @@ export class Painter extends Frame {
82
82
  let lastCachedLayer;
83
83
  for (let i = 0; i < this.layers.length; i++) {
84
84
  const layer = this.layers[i];
85
+ if (layer === undefined) {
86
+ continue;
87
+ }
85
88
  if (layer.cairoCache !== undefined &&
86
89
  layer.surfaceCache !== undefined &&
87
90
  surface === undefined &&
@@ -115,7 +118,7 @@ export class Painter extends Frame {
115
118
  }
116
119
  for (let i = layerIdx; i < this.layers.length; i++) {
117
120
  const currentLayer = this.layers[i];
118
- if (currentLayer.surfaceCache !== undefined && currentLayer.cairoCache !== undefined) {
121
+ if (currentLayer?.surfaceCache !== undefined && currentLayer.cairoCache !== undefined) {
119
122
  await this.cleanupSurface(currentLayer.surfaceCache, currentLayer.cairoCache);
120
123
  currentLayer.surfaceCache = undefined;
121
124
  currentLayer.cairoCache = undefined;
@@ -15,30 +15,26 @@ export default class ResourceManager {
15
15
  this.fontFileNames[moniker] = process.env.INSTALL_PATH + '/fonts/' + fileName;
16
16
  }
17
17
  async image(moniker) {
18
- if (moniker in this.images) {
18
+ if (this.images[moniker] !== undefined) {
19
19
  return this.images[moniker];
20
20
  }
21
- else if (moniker in this.imgFileNames) {
21
+ if (this.imgFileNames[moniker] !== undefined) {
22
22
  const imgData = await fs.readFile(this.imgFileNames[moniker]);
23
23
  this.images[moniker] = await this.co.uploadImageData(imgData);
24
24
  return this.images[moniker];
25
25
  }
26
- else {
27
- throw new Error('Error! Unknown image requested!');
28
- }
26
+ throw new Error('Error! Unknown image requested!');
29
27
  }
30
28
  async font(moniker) {
31
- if (moniker in this.fonts) {
29
+ if (this.fonts[moniker] !== undefined) {
32
30
  return this.fonts[moniker];
33
31
  }
34
- else if (moniker in this.fontFileNames) {
32
+ if (this.fontFileNames[moniker] !== undefined) {
35
33
  const fontData = await fs.readFile(this.fontFileNames[moniker]);
36
34
  this.fonts[moniker] = await this.co.uploadFontData(fontData);
37
35
  return this.fonts[moniker];
38
36
  }
39
- else {
40
- throw new Error('Error! Unknown font requested!');
41
- }
37
+ throw new Error('Error! Unknown font requested!');
42
38
  }
43
39
  clear() {
44
40
  this.images = {};
@@ -88,10 +88,10 @@ export class CamScripterAPICameraEventsGenerator extends EventEmitter {
88
88
  }
89
89
  if (dataJSON.call_id !== undefined) {
90
90
  if (errorResponse !== undefined) {
91
- this.sendMessages[dataJSON.call_id].reject(new Error(errorResponse.error));
91
+ this.sendMessages[dataJSON.call_id]?.reject(new Error(errorResponse.error));
92
92
  }
93
93
  else {
94
- this.sendMessages[dataJSON.call_id].resolve(dataJSON);
94
+ this.sendMessages[dataJSON.call_id]?.resolve(dataJSON);
95
95
  }
96
96
  delete this.sendMessages[dataJSON.call_id];
97
97
  }
@@ -124,6 +124,9 @@ export class CamScripterAPICameraEventsGenerator extends EventEmitter {
124
124
  const now = Date.now();
125
125
  for (const callId in this.sendMessages) {
126
126
  const msg = this.sendMessages[callId];
127
+ if (!msg) {
128
+ continue;
129
+ }
127
130
  if (now - msg.sentTimestamp > 10000) {
128
131
  reconnect = true;
129
132
  msg.reject(new Error('Message timeout'));
@@ -147,7 +150,7 @@ export class CamScripterAPICameraEventsGenerator extends EventEmitter {
147
150
  }
148
151
  reportClose() {
149
152
  for (const callId in this.sendMessages) {
150
- this.sendMessages[callId].reject(new Error('Connection lost'));
153
+ this.sendMessages[callId]?.reject(new Error('Connection lost'));
151
154
  }
152
155
  this.sendMessages = {};
153
156
  this.emit('close');
@@ -292,16 +292,12 @@ const parseBitrateOptionsToBitrateVapixParams = (firmWareVersion, bitrateMode, c
292
292
  if (bitrateMode === null) {
293
293
  return '';
294
294
  }
295
- if (bitrateMode === 'VBR') {
296
- return 'videobitratemode=vbr';
297
- }
298
- if (bitrateMode === 'MBR') {
299
- return `videobitratemode=mbr&videomaxbitrate=${cameraOptions.maximumBitRate}`;
300
- }
301
- if (bitrateMode === 'ABR') {
302
- return `videobitratemode=abr&videoabrtargetbitrate=${cameraOptions.maximumBitRate}&videoabrretentiontime=${cameraOptions.retentionTime}&videoabrmaxbitrate=${cameraOptions.bitRateLimit}`;
303
- }
304
- throw new Error('Unknown bitrateMode param in getVapixParams method.');
295
+ const data = {
296
+ VBR: 'videobitratemode=vbr',
297
+ MBR: `videobitratemode=mbr&videomaxbitrate=${cameraOptions.maximumBitRate}`,
298
+ ABR: `videobitratemode=abr&videoabrtargetbitrate=${cameraOptions.maximumBitRate}&videoabrretentiontime=${cameraOptions.retentionTime}&videoabrmaxbitrate=${cameraOptions.bitRateLimit}`,
299
+ };
300
+ return data[bitrateMode];
305
301
  };
306
302
  const parseVapixParamsToBitrateOptions = (bitrateVapixParams) => {
307
303
  const params = {};
@@ -312,7 +308,7 @@ const parseVapixParamsToBitrateOptions = (bitrateVapixParams) => {
312
308
  const bitrateMode = params['videobitratemode'] !== undefined ? params['videobitratemode'].toUpperCase() : undefined;
313
309
  const hasLowerFw = bitrateMode === undefined && params['videomaxbitrate'] !== undefined;
314
310
  if (hasLowerFw) {
315
- const maximumBitRate = parseInt(params['videomaxbitrate'], 10);
311
+ const maximumBitRate = parseInt(params['videomaxbitrate'] ?? '0', 10);
316
312
  return {
317
313
  bitrateMode: 'MBR',
318
314
  maximumBitRate: maximumBitRate,
@@ -321,19 +317,19 @@ const parseVapixParamsToBitrateOptions = (bitrateVapixParams) => {
321
317
  };
322
318
  }
323
319
  if (bitrateMode === 'ABR') {
324
- const maximumBitRate = parseInt(params['videoabrtargetbitrate'], 10);
325
- const retentionTime = parseInt(params['videoabrretentiontime'], 10);
326
- const bitrateLimit = parseInt(params['videoabrmaxbitrate'], 10);
320
+ const maximumBitRate = parseInt(params['videoabrtargetbitrate'] ?? '0', 10);
321
+ const retentionTime = parseInt(params['videoabrretentiontime'] ?? '0', 10);
322
+ const bitRateLimit = parseInt(params['videoabrmaxbitrate'] ?? '0', 10);
327
323
  return {
328
- bitrateMode: bitrateMode,
329
- maximumBitRate: maximumBitRate,
330
- retentionTime: retentionTime,
331
- bitRateLimit: bitrateLimit,
324
+ bitrateMode,
325
+ maximumBitRate,
326
+ retentionTime,
327
+ bitRateLimit,
332
328
  };
333
329
  }
334
330
  else if (bitrateMode === 'MBR') {
335
- const maximumBitRate = parseInt(params['videomaxbitrate'], 10);
336
- const oldMaximumBitrateParamValue = parseInt(params['videombrmaxbitrate'], 10);
331
+ const maximumBitRate = params['videomaxbitrate'] !== undefined ? parseInt(params['videomaxbitrate'], 10) : null;
332
+ const oldMaximumBitrateParamValue = parseInt(params['videombrmaxbitrate'] ?? '0', 10);
337
333
  return {
338
334
  bitrateMode: bitrateMode,
339
335
  maximumBitRate: maximumBitRate ?? oldMaximumBitrateParamValue,
package/esm/VapixAPI.d.ts CHANGED
@@ -1,13 +1,13 @@
1
- import { IClient, TParameters, TResponse } from './internal/common';
1
+ import { IClient, TParameters } from './internal/common';
2
2
  import { TApplication, TAudioSampleRates, TSDCardInfo, TPtzOverview, TCameraPTZItem, TCameraPTZItemData, TAudioDevice } from './types/VapixAPI';
3
3
  import { ProxyClient } from './internal/ProxyClient';
4
4
  import { TCameraImageConfig, TProxyParam } from './types/common';
5
5
  export declare class VapixAPI<Client extends IClient = IClient> {
6
6
  client: ProxyClient<Client>;
7
7
  constructor(client: Client, getProxyUrl: () => string);
8
- getUrlEncoded(proxy: TProxyParam | undefined, path: string, parameters?: TParameters, headers?: Record<string, string>): Promise<TResponse>;
9
- postJson(proxy: TProxyParam | undefined, path: string, jsonData: Record<string, any>, headers?: Record<string, string>): Promise<TResponse>;
10
- getCameraImage(params: TCameraImageConfig, proxy?: TProxyParam): Promise<TResponse>;
8
+ getUrlEncoded(proxy: TProxyParam, path: string, parameters?: TParameters, headers?: Record<string, string>): Promise<import("./internal/common").TResponse>;
9
+ postJson(proxy: TProxyParam, path: string, jsonData: Record<string, any>, headers?: Record<string, string>): Promise<import("./internal/common").TResponse>;
10
+ getCameraImage(params: TCameraImageConfig, proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
11
11
  getEventDeclarations(proxy?: TProxyParam): Promise<string>;
12
12
  getSupportedAudioSampleRate(proxy?: TProxyParam): Promise<TAudioSampleRates[]>;
13
13
  performAutofocus(proxy?: TProxyParam): Promise<void>;
@@ -16,8 +16,8 @@ export declare class VapixAPI<Client extends IClient = IClient> {
16
16
  unmountSDCard(proxy?: TProxyParam): Promise<number>;
17
17
  private _doSDCardMountAction;
18
18
  fetchSDCardJobProgress(jobId: number, proxy?: TProxyParam): Promise<number>;
19
- downloadCameraReport(proxy?: TProxyParam): Promise<TResponse>;
20
- getSystemLog(proxy?: TProxyParam): Promise<TResponse>;
19
+ downloadCameraReport(proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
20
+ getSystemLog(proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
21
21
  getMaxFps(channel: number, proxy?: TProxyParam): Promise<number>;
22
22
  getTimezone(proxy?: TProxyParam): Promise<string>;
23
23
  getDateTimeInfo(proxy?: TProxyParam): Promise<{
@@ -32,7 +32,7 @@ export declare class VapixAPI<Client extends IClient = IClient> {
32
32
  getDevicesSettings(proxy?: TProxyParam): Promise<TAudioDevice[]>;
33
33
  fetchRemoteDeviceInfo<T extends Record<string, any>>(payload: T, proxy?: TProxyParam): Promise<any>;
34
34
  getHeaders(proxy?: TProxyParam): Promise<Record<string, string>>;
35
- setHeaders(headers: Record<string, string>, proxy?: TProxyParam): Promise<TResponse>;
35
+ setHeaders(headers: Record<string, string>, proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
36
36
  getParameter(paramNames: string | string[], proxy?: TProxyParam): Promise<Record<string, string>>;
37
37
  setParameter(params: Record<string, string | number | boolean>, proxy?: TProxyParam): Promise<boolean>;
38
38
  getGuardTourList(proxy?: TProxyParam): Promise<{
@@ -54,10 +54,10 @@ export declare class VapixAPI<Client extends IClient = IClient> {
54
54
  getPTZPresetList(channel: number, proxy?: TProxyParam): Promise<string[]>;
55
55
  listPTZ(camera: number, proxy?: TProxyParam): Promise<TCameraPTZItem[]>;
56
56
  listPtzVideoSourceOverview(proxy?: TProxyParam): Promise<TPtzOverview>;
57
- goToPreset(channel: number, presetName: string, proxy?: TProxyParam): Promise<TResponse>;
57
+ goToPreset(channel: number, presetName: string, proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
58
58
  getPtzPosition(camera: number, proxy?: TProxyParam): Promise<TCameraPTZItemData>;
59
59
  getInputState(port: number, proxy?: TProxyParam): Promise<boolean>;
60
- setOutputState(port: number, active: boolean, proxy?: TProxyParam): Promise<TResponse>;
60
+ setOutputState(port: number, active: boolean, proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
61
61
  getApplicationList(proxy?: TProxyParam): Promise<TApplication[]>;
62
62
  startApplication(applicationID: string, proxy?: TProxyParam): Promise<void>;
63
63
  restartApplication(applicationID: string, proxy?: TProxyParam): Promise<void>;
package/esm/VapixAPI.js CHANGED
@@ -11,7 +11,7 @@ export class VapixAPI {
11
11
  constructor(client, getProxyUrl) {
12
12
  this.client = new ProxyClient(client, getProxyUrl);
13
13
  }
14
- async getUrlEncoded(proxy = null, path, parameters, headers = {}) {
14
+ async getUrlEncoded(proxy, path, parameters, headers = {}) {
15
15
  const data = paramToUrl(parameters);
16
16
  const head = { ...headers, 'Content-Type': 'application/x-www-form-urlencoded' };
17
17
  const res = await this.client.post(proxy, path, data, {}, head);
@@ -20,7 +20,7 @@ export class VapixAPI {
20
20
  }
21
21
  return res;
22
22
  }
23
- async postJson(proxy = null, path, jsonData, headers = {}) {
23
+ async postJson(proxy, path, jsonData, headers = {}) {
24
24
  const data = JSON.stringify(jsonData);
25
25
  const head = { ...headers, 'Content-Type': 'application/json' };
26
26
  const res = await this.client.post(proxy, path, data, {}, head);
@@ -231,9 +231,9 @@ export class VapixAPI {
231
231
  const gTour = {
232
232
  id: gTourBaseName,
233
233
  camNbr: response[gTourBaseName + '.CamNbr'],
234
- name: response[gTourBaseName + '.Name'],
234
+ name: response[gTourBaseName + '.Name'] ?? 'Guard Tour ' + (i + 1),
235
235
  randomEnabled: response[gTourBaseName + '.RandomEnabled'],
236
- running: response[gTourBaseName + '.Running'],
236
+ running: response[gTourBaseName + '.Running'] ?? 'no',
237
237
  timeBetweenSequences: response[gTourBaseName + '.TimeBetweenSequences'],
238
238
  tour: [],
239
239
  };
@@ -298,8 +298,12 @@ export class VapixAPI {
298
298
  });
299
299
  const data = parseCameraPtzResponse(await response.text());
300
300
  const res = {};
301
- Object.keys(data).forEach((camera) => {
302
- res[Number(camera) - 1] = data[Number(camera)].map(({ data: itemData, ...d }) => d);
301
+ Object.keys(data)
302
+ .map(Number)
303
+ .forEach((camera) => {
304
+ if (data[camera] !== undefined) {
305
+ res[camera - 1] = data[camera]?.map(({ data: itemData, ...d }) => d);
306
+ }
303
307
  });
304
308
  return res;
305
309
  }
@@ -323,26 +327,26 @@ export class VapixAPI {
323
327
  }
324
328
  async getInputState(port, proxy = null) {
325
329
  const response = await (await this.getUrlEncoded(proxy, '/axis-cgi/io/port.cgi', { checkactive: port.toString() })).text();
326
- return response.split('=')[1].indexOf('active') === 0;
330
+ return response.split('=')[1]?.indexOf('active') === 0;
327
331
  }
328
332
  async setOutputState(port, active, proxy = null) {
329
333
  return this.getUrlEncoded(proxy, '/axis-cgi/io/port.cgi', { action: active ? `${port}:/` : `${port}:\\` });
330
334
  }
331
335
  async getApplicationList(proxy = null) {
332
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/applications/list.cgi');
336
+ const res = await this.client.get(proxy, '/axis-cgi/applications/list.cgi');
333
337
  const xml = await res.text();
334
338
  const result = (await parseStringPromise(xml));
335
339
  const apps = [];
336
- for (let i = 0; i < result.reply.application.length; i++) {
340
+ for (const app of result.reply.application) {
337
341
  apps.push({
338
- ...result.reply.application[i].$,
339
- appId: APP_IDS.find((id) => id.toLowerCase() === result.reply.application[i].$.Name.toLowerCase()) ?? null,
342
+ ...app.$,
343
+ appId: APP_IDS.find((id) => id.toLowerCase() === app.$.Name.toLowerCase()) ?? null,
340
344
  });
341
345
  }
342
346
  return apps;
343
347
  }
344
348
  async startApplication(applicationID, proxy = null) {
345
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/applications/control.cgi', {
349
+ const res = await this.client.get(proxy, '/axis-cgi/applications/control.cgi', {
346
350
  package: applicationID.toLowerCase(),
347
351
  action: 'start',
348
352
  });
@@ -352,7 +356,7 @@ export class VapixAPI {
352
356
  }
353
357
  }
354
358
  async restartApplication(applicationID, proxy = null) {
355
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/applications/control.cgi', {
359
+ const res = await this.client.get(proxy, '/axis-cgi/applications/control.cgi', {
356
360
  package: applicationID.toLowerCase(),
357
361
  action: 'restart',
358
362
  });
@@ -362,7 +366,7 @@ export class VapixAPI {
362
366
  }
363
367
  }
364
368
  async stopApplication(applicationID, proxy = null) {
365
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/applications/control.cgi', {
369
+ const res = await this.client.get(proxy, '/axis-cgi/applications/control.cgi', {
366
370
  package: applicationID.toLowerCase(),
367
371
  action: 'stop',
368
372
  });
@@ -389,14 +393,14 @@ export class VapixAPI {
389
393
  const parseParameters = (response) => {
390
394
  const params = {};
391
395
  const lines = response.split(/[\r\n]/);
392
- for (let i = 0; i < lines.length; i++) {
393
- if (lines[i].length === 0 || lines[i].substring(0, 7) === '# Error') {
396
+ for (const line of lines) {
397
+ if (line.length === 0 || line.substring(0, 7) === '# Error') {
394
398
  continue;
395
399
  }
396
- const delimiterPos = lines[i].indexOf('=');
400
+ const delimiterPos = line.indexOf('=');
397
401
  if (delimiterPos !== -1) {
398
- const paramName = lines[i].substring(0, delimiterPos);
399
- const paramValue = lines[i].substring(delimiterPos + 1);
402
+ const paramName = line.substring(0, delimiterPos);
403
+ const paramValue = line.substring(delimiterPos + 1);
400
404
  params[paramName] = paramValue;
401
405
  }
402
406
  }
@@ -442,7 +446,7 @@ const parsePtz = (parsed) => {
442
446
  };
443
447
  res.push({
444
448
  id,
445
- name: data[0],
449
+ name: data[0] ?? 'Preset ' + id,
446
450
  data: {
447
451
  pan: getValue('pan'),
448
452
  tilt: getValue('tilt'),
@@ -39,10 +39,10 @@ export class VapixEvents extends EventEmitter {
39
39
  this.ws.on('open', () => {
40
40
  const topics = [];
41
41
  const eventNames = this.eventNames();
42
- for (let i = 0; i < eventNames.length; i++) {
43
- if (!this.isReservedEventName(eventNames[i])) {
42
+ for (const eventName of eventNames) {
43
+ if (!this.isReservedEventName(eventName)) {
44
44
  const topic = {
45
- topicFilter: eventNames[i],
45
+ topicFilter: eventName,
46
46
  };
47
47
  topics.push(topic);
48
48
  }
@@ -4,17 +4,17 @@ export class Digest {
4
4
  getAuthHeader(user, pass, method, uri, wwwAuthenticateHeader) {
5
5
  const digestItems = {};
6
6
  const digestArr = wwwAuthenticateHeader.substring(wwwAuthenticateHeader.indexOf('Digest') + 6).split(',');
7
- for (let i = 0; i < digestArr.length; i++) {
8
- const pos = digestArr[i].indexOf('=');
9
- const key = digestArr[i].substring(0, pos).trim();
10
- const value = digestArr[i].substring(pos + 1).trim();
7
+ for (const arg of digestArr) {
8
+ const pos = arg.indexOf('=');
9
+ const key = arg.substring(0, pos).trim();
10
+ const value = arg.substring(pos + 1).trim();
11
11
  digestItems[key] = value.replace(/"/g, '');
12
12
  }
13
13
  const HA1 = crypto.createHash('md5').update(`${user}:${digestItems['realm']}:${pass}`).digest('hex');
14
14
  const HA2 = crypto.createHash('md5').update(`${method}:${uri}`).digest('hex');
15
15
  const ncValue = ('00000000' + this.nonceCount.toString(16)).slice(-8);
16
16
  let response;
17
- if (digestItems['qop']) {
17
+ if (digestItems['qop'] !== undefined) {
18
18
  response = crypto
19
19
  .createHash('md5')
20
20
  .update(`${HA1}:${digestItems['nonce']}:${ncValue}:162d50aa594e9648:auth:${HA2}`)
@@ -29,7 +29,7 @@ export class Digest {
29
29
  `nonce="${digestItems['nonce']}",` +
30
30
  `uri="${uri}",` +
31
31
  `response="${response}"`;
32
- if (digestItems['qop']) {
32
+ if (digestItems['qop'] !== undefined) {
33
33
  header += `,qop=auth,nc=${ncValue},cnonce="162d50aa594e9648"`;
34
34
  }
35
35
  this.nonceCount++;
@@ -36,7 +36,7 @@ export class DefaultClient {
36
36
  return this.httpRequestSender.sendRequest(options, data);
37
37
  }
38
38
  getBaseConnectionParams(method, path, params) {
39
- let pathName = addParametersToPath(path, params);
39
+ const pathName = addParametersToPath(path, params);
40
40
  return {
41
41
  method: method,
42
42
  protocol: this.tls ? 'https:' : 'http:',
@@ -86,7 +86,7 @@ export class HttpServer extends EventEmitter {
86
86
  close() {
87
87
  this.server.close();
88
88
  for (const key in this.sockets) {
89
- this.sockets[key].destroy();
89
+ this.sockets[key]?.destroy();
90
90
  }
91
91
  }
92
92
  }