camstreamerlib 3.2.2 → 3.2.3

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.
@@ -6,32 +6,43 @@ export type TField = {
6
6
  text: string;
7
7
  color?: string;
8
8
  };
9
- export type TService = {
10
- id: number;
11
- enabled: number;
12
- schedule: string;
13
- name: string;
14
- identifier: string;
15
- cameraList: number[];
16
- };
9
+ export type TService = Record<string, any>;
17
10
  export type TServiceList = {
18
11
  services: TService[];
19
12
  };
13
+ export type TNetworkCameraList = {
14
+ name: string;
15
+ ip: string;
16
+ }[];
17
+ export type TImage = {
18
+ name: string;
19
+ path: string;
20
+ storage: string;
21
+ };
20
22
  export declare enum ImageType {
21
23
  PNG = 0,
22
24
  JPEG = 1
23
25
  }
26
+ export type TCoordinates = 'top_left' | 'top_right' | 'top' | 'bottom_left' | 'bottom_right' | 'bottom' | 'left' | 'right' | 'center' | '';
24
27
  export declare class CamOverlayAPI {
25
28
  private client;
26
29
  constructor(options?: CamOverlayOptions | IClient);
27
- updateCGText(serviceID: number, fields: TField[]): Promise<void>;
28
- updateCGImagePos(serviceID: number, coordinates?: string, x?: number, y?: number): Promise<void>;
29
- updateCGImage(serviceID: number, path: string, coordinates?: string, x?: number, y?: number): Promise<void>;
30
+ checkCameraTime(): Promise<boolean>;
31
+ listImages(): Promise<TImage[]>;
32
+ uploadImage(file: Buffer, fileName: string): Promise<void>;
33
+ getNetworkCameraList(): Promise<TNetworkCameraList>;
30
34
  updateInfoticker(serviceID: number, text: string): Promise<void>;
31
35
  setEnabled(serviceID: number, enabled: boolean): Promise<void>;
32
36
  isEnabled(serviceID: number): Promise<boolean>;
37
+ getSingleService(serviceId: number): Promise<TService>;
38
+ getServices(): Promise<TService[]>;
39
+ updateSingleService(serviceId: number, serviceJson: TService): Promise<void>;
33
40
  updateServices(servicesJson: TServiceList): Promise<void>;
34
- updateCGImageFromData(serviceID: number, imageType: ImageType, imageData: Buffer, coordinates?: string, x?: number, y?: number): Promise<void>;
35
- promiseCGUpdate(serviceID: number, action: string, params: string, contentType?: string, data?: Buffer): Promise<void>;
36
- private formCoordinates;
41
+ updateCGText(serviceID: number, fields: TField[]): Promise<void>;
42
+ updateCGImagePos(serviceID: number, coordinates?: TCoordinates, x?: number, y?: number): Promise<void>;
43
+ updateCGImage(serviceID: number, path: string, coordinates?: TCoordinates, x?: number, y?: number): Promise<void>;
44
+ updateCGImageFromData(serviceID: number, imageType: ImageType, imageData: Buffer, coordinates?: TCoordinates, x?: number, y?: number): Promise<void>;
45
+ private promiseCGUpdate;
46
+ private get;
47
+ private post;
37
48
  }
package/CamOverlayAPI.js CHANGED
@@ -26,32 +26,39 @@ class CamOverlayAPI {
26
26
  this.client = new DefaultAgent_1.DefaultAgent(options);
27
27
  }
28
28
  }
29
- updateCGText(serviceID, fields) {
30
- let field_specs = '';
31
- for (const field of fields) {
32
- const name = field.field_name;
33
- field_specs += `&${name}=${field.text}`;
34
- if (field.color !== undefined) {
35
- field_specs += `&${name}_color=${field.color}`;
36
- }
37
- }
38
- return this.promiseCGUpdate(serviceID, 'update_text', field_specs);
29
+ checkCameraTime() {
30
+ return __awaiter(this, void 0, void 0, function* () {
31
+ const cameraTime = yield this.get('/local/camoverlay/api/camera_time.cgi');
32
+ return cameraTime.state;
33
+ });
39
34
  }
40
- updateCGImagePos(serviceID, coordinates = '', x = 0, y = 0) {
41
- const coord = this.formCoordinates(coordinates, x, y);
42
- return this.promiseCGUpdate(serviceID, 'update_image', coord);
35
+ listImages() {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ const images = yield this.get('/local/camoverlay/api/upload_image.cgi?action=list');
38
+ return images.list;
39
+ });
43
40
  }
44
- updateCGImage(serviceID, path, coordinates = '', x = 0, y = 0) {
45
- const coord = this.formCoordinates(coordinates, x, y);
46
- const update = `&image=${path}`;
47
- return this.promiseCGUpdate(serviceID, 'update_image', update + coord);
41
+ uploadImage(file, fileName) {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ const formData = new FormData();
44
+ formData.append('target', 'SD0');
45
+ formData.append('uploadedFile[]', file, fileName);
46
+ const path = '/local/camoverlay/api/upload_image.cgi?action=upload';
47
+ yield this.post(path, formData);
48
+ });
49
+ }
50
+ getNetworkCameraList() {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ const response = yield this.get('/local/camoverlay/api/network_camera_list.cgi');
53
+ return response.camera_list;
54
+ });
48
55
  }
49
56
  updateInfoticker(serviceID, text) {
50
57
  return __awaiter(this, void 0, void 0, function* () {
51
58
  const path = `/local/camoverlay/api/infoticker.cgi?service_id=${serviceID}&text=${text}`;
52
59
  const res = yield this.client.get(path);
53
60
  if (!res.ok) {
54
- throw new Error(JSON.stringify(res));
61
+ throw new Error(yield (0, common_1.responseStringify)(res));
55
62
  }
56
63
  });
57
64
  }
@@ -60,7 +67,7 @@ class CamOverlayAPI {
60
67
  const path = `/local/camoverlay/api/enabled.cgi?id_${serviceID}=${enabled ? 1 : 0}`;
61
68
  const res = yield this.client.post(path, '');
62
69
  if (!res.ok) {
63
- throw new Error(JSON.stringify(res));
70
+ throw new Error(yield (0, common_1.responseStringify)(res));
64
71
  }
65
72
  });
66
73
  }
@@ -78,39 +85,110 @@ class CamOverlayAPI {
78
85
  throw new Error('Service not found.');
79
86
  }
80
87
  else {
81
- throw new Error(JSON.stringify(res));
88
+ throw new Error(yield (0, common_1.responseStringify)(res));
82
89
  }
83
90
  });
84
91
  }
92
+ getSingleService(serviceId) {
93
+ return __awaiter(this, void 0, void 0, function* () {
94
+ return this.get('/local/camoverlay/api/services.cgi', { action: 'get', service_id: serviceId.toString() });
95
+ });
96
+ }
97
+ getServices() {
98
+ return __awaiter(this, void 0, void 0, function* () {
99
+ const serviceList = yield this.get('/local/camoverlay/api/services.cgi?action=get');
100
+ return serviceList.services;
101
+ });
102
+ }
103
+ updateSingleService(serviceId, serviceJson) {
104
+ return __awaiter(this, void 0, void 0, function* () {
105
+ const path = '/local/camoverlay/api/services.cgi';
106
+ yield this.post(path, JSON.stringify(serviceJson), {
107
+ action: 'set',
108
+ service_id: serviceId.toString(),
109
+ });
110
+ });
111
+ }
85
112
  updateServices(servicesJson) {
86
113
  return __awaiter(this, void 0, void 0, function* () {
87
114
  const path = '/local/camoverlay/api/services.cgi?action=set';
88
115
  const res = yield this.client.post(path, JSON.stringify(servicesJson));
89
116
  if (!res.ok) {
90
- throw new Error(JSON.stringify(res));
117
+ throw new Error(yield (0, common_1.responseStringify)(res));
91
118
  }
92
119
  });
93
120
  }
121
+ updateCGText(serviceID, fields) {
122
+ const params = {};
123
+ for (const field of fields) {
124
+ const name = field.field_name;
125
+ params[name] = field.text;
126
+ if (field.color !== undefined) {
127
+ params[`${name}_color`] = field.color;
128
+ }
129
+ }
130
+ return this.promiseCGUpdate(serviceID, 'update_text', params);
131
+ }
132
+ updateCGImagePos(serviceID, coordinates = '', x = 0, y = 0) {
133
+ const params = {
134
+ coord_system: coordinates,
135
+ pos_x: x,
136
+ pos_y: y,
137
+ };
138
+ return this.promiseCGUpdate(serviceID, 'update_image', params);
139
+ }
140
+ updateCGImage(serviceID, path, coordinates = '', x = 0, y = 0) {
141
+ const params = {
142
+ coord_system: coordinates,
143
+ pos_x: x,
144
+ pos_y: y,
145
+ image: path,
146
+ };
147
+ return this.promiseCGUpdate(serviceID, 'update_image', params);
148
+ }
94
149
  updateCGImageFromData(serviceID, imageType, imageData, coordinates = '', x = 0, y = 0) {
95
- const coord = this.formCoordinates(coordinates, x, y);
96
150
  const contentType = imageType === ImageType.PNG ? 'image/png' : 'image/jpeg';
97
- return this.promiseCGUpdate(serviceID, 'update_image', coord, contentType, imageData);
151
+ const params = {
152
+ coord_system: coordinates,
153
+ pos_x: x,
154
+ pos_y: y,
155
+ };
156
+ return this.promiseCGUpdate(serviceID, 'update_image', params, contentType, imageData);
98
157
  }
99
- promiseCGUpdate(serviceID, action, params, contentType, data) {
158
+ promiseCGUpdate(serviceID, action, params = {}, contentType, data) {
100
159
  return __awaiter(this, void 0, void 0, function* () {
101
- const path = `/local/camoverlay/api/customGraphics.cgi?action=${action}&service_id=${serviceID}${params}`;
160
+ const path = `/local/camoverlay/api/customGraphics.cgi`;
102
161
  let headers = {};
103
162
  if (contentType !== undefined && data) {
104
163
  headers = { 'Content-Type': contentType };
105
164
  }
106
- const res = yield this.client.post(path, data !== null && data !== void 0 ? data : '', {}, headers);
165
+ const res = yield this.client.post(path, data !== null && data !== void 0 ? data : '', Object.assign({ action: action, service_id: serviceID.toString() }, params), headers);
107
166
  if (!res.ok) {
108
- throw new Error(JSON.stringify(res));
167
+ throw new Error(yield (0, common_1.responseStringify)(res));
109
168
  }
110
169
  });
111
170
  }
112
- formCoordinates(coordinates, x, y) {
113
- return coordinates !== '' ? `&coord_system=${coordinates}&pos_x=${x}&pos_y=${y}` : '';
171
+ get(path, params) {
172
+ return __awaiter(this, void 0, void 0, function* () {
173
+ const res = yield this.client.get(path, params);
174
+ if (res.ok) {
175
+ return yield res.json();
176
+ }
177
+ else {
178
+ throw new Error(yield (0, common_1.responseStringify)(res));
179
+ }
180
+ });
181
+ }
182
+ post(path, data, params) {
183
+ return __awaiter(this, void 0, void 0, function* () {
184
+ const res = yield this.client.post(path, data, params);
185
+ if (res.ok) {
186
+ return yield res.json();
187
+ }
188
+ else {
189
+ throw new Error(yield (0, common_1.responseStringify)(res));
190
+ }
191
+ });
114
192
  }
115
193
  }
116
194
  exports.CamOverlayAPI = CamOverlayAPI;
@@ -34,6 +34,16 @@ export type TServiceList = {
34
34
  export type TAlign = 'A_RIGHT' | 'A_LEFT' | 'A_CENTER';
35
35
  export type TextFit = 'TFM_SCALE' | 'TFM_TRUNCATE' | 'TFM_OVERFLOW';
36
36
  export type TWriteTextParams = [string, string, number, number, number, number, TAlign, TextFit?];
37
+ export interface CamOverlayDrawingAPI {
38
+ on(event: 'open', listener: () => void): this;
39
+ on(event: 'close', listener: () => void): this;
40
+ on(event: 'error', listener: (err: Error) => void): this;
41
+ on(event: 'message', listener: (msg: string) => void): this;
42
+ emit(event: 'open'): boolean;
43
+ emit(event: 'close'): boolean;
44
+ emit(event: 'error', err: Error): boolean;
45
+ emit(event: 'message', msg: string): boolean;
46
+ }
37
47
  export declare class CamOverlayDrawingAPI extends EventEmitter {
38
48
  private tls;
39
49
  private tlsInsecure;
@@ -73,7 +73,7 @@ class CamOverlayDrawingAPI extends EventEmitter {
73
73
  });
74
74
  }
75
75
  removeImage() {
76
- return this.sendMessage({ command: 'remove_image_v2' });
76
+ return this.sendMessage({ command: 'remove_image_v2', params: [] });
77
77
  }
78
78
  createWsClient() {
79
79
  const options = {
@@ -35,6 +35,14 @@ export type TResponse = {
35
35
  call_id: number;
36
36
  message: string;
37
37
  };
38
+ export interface CamScripterAPICameraEventsGenerator {
39
+ on(event: 'open', listener: () => void): this;
40
+ on(event: 'close', listener: () => void): this;
41
+ on(event: 'error', listener: (err: Error) => void): this;
42
+ emit(event: 'open'): boolean;
43
+ emit(event: 'close'): boolean;
44
+ emit(event: 'error', err: Error): boolean;
45
+ }
38
46
  export declare class CamScripterAPICameraEventsGenerator extends EventEmitter {
39
47
  private tls;
40
48
  private tlsInsecure;
@@ -28,8 +28,11 @@ export declare class CamStreamerAPI {
28
28
  private client;
29
29
  constructor(options?: CamStreamerAPIOptions | IClient);
30
30
  getStreamList(): Promise<TStreamList>;
31
+ getStream(streamID: string): Promise<TStreamAttributes>;
31
32
  getStreamParameter(streamID: string, paramName: string): Promise<string>;
33
+ setStream(streamID: string, params: TStreamAttributes): Promise<void>;
32
34
  setStreamParameter(streamID: string, paramName: string, value: string): Promise<void>;
33
35
  isStreaming(streamID: string): Promise<boolean>;
34
- get(path: string): Promise<any>;
36
+ deleteStream(streamID: string): Promise<void>;
37
+ private get;
35
38
  }
package/CamStreamerAPI.js CHANGED
@@ -8,6 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
11
22
  Object.defineProperty(exports, "__esModule", { value: true });
12
23
  exports.CamStreamerAPI = void 0;
13
24
  const common_1 = require("./internal/common");
@@ -27,12 +38,24 @@ class CamStreamerAPI {
27
38
  return streamListRes.data;
28
39
  });
29
40
  }
41
+ getStream(streamID) {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ const stream = yield this.get(`/local/camstreamer/stream/get.cgi?stream_id=${streamID}`);
44
+ return stream.data;
45
+ });
46
+ }
30
47
  getStreamParameter(streamID, paramName) {
31
48
  return __awaiter(this, void 0, void 0, function* () {
32
49
  const stream = yield this.get(`/local/camstreamer/stream/get.cgi?stream_id=${streamID}`);
33
50
  return stream.data[paramName];
34
51
  });
35
52
  }
53
+ setStream(streamID, params) {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ const { streamDelay, startTime, stopTime } = params, rest = __rest(params, ["streamDelay", "startTime", "stopTime"]);
56
+ yield this.get('/local/camstreamer/stream/set.cgi', Object.assign({ stream_id: streamID, streamDelay: streamDelay !== null && streamDelay !== void 0 ? streamDelay : '', startTime: startTime !== null && startTime !== void 0 ? startTime : 'null', stopTime: stopTime !== null && stopTime !== void 0 ? stopTime : 'null' }, rest));
57
+ });
58
+ }
36
59
  setStreamParameter(streamID, paramName, value) {
37
60
  return __awaiter(this, void 0, void 0, function* () {
38
61
  yield this.get(`/local/camstreamer/stream/set.cgi?stream_id=${streamID}&${paramName}=${value}`);
@@ -44,14 +67,19 @@ class CamStreamerAPI {
44
67
  return response.data.is_streaming === 1;
45
68
  });
46
69
  }
47
- get(path) {
70
+ deleteStream(streamID) {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ yield this.get('/local/camstreamer/stream/remove.cgi', { stream_id: streamID });
73
+ });
74
+ }
75
+ get(path, parameters) {
48
76
  return __awaiter(this, void 0, void 0, function* () {
49
- const res = yield this.client.get(path);
77
+ const res = yield this.client.get(path, parameters);
50
78
  if (res.ok) {
51
79
  return yield res.json();
52
80
  }
53
81
  else {
54
- throw new Error(JSON.stringify(res));
82
+ throw new Error(yield (0, common_1.responseStringify)(res));
55
83
  }
56
84
  });
57
85
  }
@@ -1,5 +1,4 @@
1
1
  /// <reference types="node" />
2
- import * as EventEmitter from 'events';
3
2
  import { HttpOptions, IClient } from './internal/common';
4
3
  export type CamSwitcherAPIOptions = HttpOptions;
5
4
  export type TStreamInfo = {
@@ -21,14 +20,16 @@ export type TPlaylistInfo = {
21
20
  sortIndexOverview: number;
22
21
  stream_list: TStreamInfo[];
23
22
  };
23
+ export type TPlaylistList = Record<string, TPlaylistInfo>;
24
24
  export type TClipInfo = {
25
25
  niceName: string;
26
26
  channel: string;
27
27
  keyboard: object;
28
28
  sortIndexOverview: number;
29
29
  };
30
- export type TPlaylistList = Record<string, TPlaylistInfo>;
31
30
  export type TClipList = Record<string, TClipInfo>;
31
+ export type TApiClipType = 'audio' | 'video';
32
+ export type TClipStorage = 'SD_DISK' | 'FLASH';
32
33
  export type TPlaylistQueue = {
33
34
  playlist_queue_list: string[];
34
35
  };
@@ -37,16 +38,44 @@ export type TOutputInfo = {
37
38
  ws: string;
38
39
  ws_initial_message: string;
39
40
  };
40
- export declare class CamSwitcherAPI extends EventEmitter {
41
+ export type TSilenceChannel = 'mono' | 'stereo';
42
+ export type TAvailableCameraList = {
43
+ camera_list: {
44
+ name: string;
45
+ ip: string;
46
+ }[];
47
+ };
48
+ export type TStorageInfo = {
49
+ storage: TClipStorage;
50
+ writable: boolean;
51
+ size: number;
52
+ available: number;
53
+ };
54
+ declare const cgiNames: {
55
+ camera: string;
56
+ audio: string;
57
+ playlist: string;
58
+ clip: string;
59
+ tracker: string;
60
+ };
61
+ export type TSourceType = keyof typeof cgiNames;
62
+ export declare class CamSwitcherAPI {
41
63
  private client;
42
64
  constructor(options?: CamSwitcherAPIOptions | IClient);
65
+ generateSilence(sampleRate: number, channels: TSilenceChannel): Promise<void>;
66
+ getIpListFromNetworkCheck(): Promise<TAvailableCameraList>;
67
+ getMaxFps(source: number): Promise<number>;
68
+ getStorageInfo(): Promise<TStorageInfo[]>;
69
+ getOutputInfo(): Promise<TOutputInfo>;
43
70
  getPlaylistList(): Promise<TPlaylistList>;
44
- getClipList(): Promise<TClipList>;
45
71
  playlistSwitch(playlistName: string): Promise<void>;
46
- playlistQueueList(): Promise<TPlaylistQueue>;
47
- playlistQueueClear(): Promise<void>;
48
72
  playlistQueuePush(playlistName: string): Promise<void>;
73
+ playlistQueueClear(): Promise<void>;
74
+ playlistQueueList(): Promise<TPlaylistQueue>;
49
75
  playlistQueuePlayNext(): Promise<void>;
50
- getOutputInfo(): Promise<TOutputInfo>;
51
- get(path: string): Promise<any>;
76
+ getClipList(): Promise<TClipList>;
77
+ addNewClip(file: Buffer, clipType: TApiClipType, storage: TClipStorage, id: string, fileName: string): Promise<void>;
78
+ removeClip(id: string, storage: TClipStorage): Promise<{}>;
79
+ private get;
52
80
  }
81
+ export {};
package/CamSwitcherAPI.js CHANGED
@@ -10,60 +10,101 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.CamSwitcherAPI = void 0;
13
- const EventEmitter = require("events");
14
13
  const DefaultAgent_1 = require("./DefaultAgent");
15
14
  const common_1 = require("./internal/common");
16
- class CamSwitcherAPI extends EventEmitter {
15
+ const cgiNames = {
16
+ camera: 'streams',
17
+ audio: 'audios',
18
+ playlist: 'playlists',
19
+ clip: 'clips',
20
+ tracker: 'trackers',
21
+ };
22
+ class CamSwitcherAPI {
17
23
  constructor(options = {}) {
18
- super();
19
24
  if ((0, common_1.isClient)(options)) {
20
25
  this.client = options;
21
26
  }
22
27
  else {
23
28
  this.client = new DefaultAgent_1.DefaultAgent(options);
24
29
  }
25
- EventEmitter.call(this);
30
+ }
31
+ generateSilence(sampleRate, channels) {
32
+ return this.get('/local/camswitcher/generate_silence.cgi', { sample_rate: sampleRate.toString(), channels });
33
+ }
34
+ getIpListFromNetworkCheck() {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ return (yield this.get('/local/camswitcher/network_camera_list.cgi')).data;
37
+ });
38
+ }
39
+ getMaxFps(source) {
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ return (yield this.get('/local/camswitcher/get_max_framerate.cgi', { video_source: source.toString() })).data;
42
+ });
43
+ }
44
+ getStorageInfo() {
45
+ return __awaiter(this, void 0, void 0, function* () {
46
+ return (yield this.get('/local/camswitcher/get_storage.cgi')).data;
47
+ });
48
+ }
49
+ getOutputInfo() {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ return (yield this.get('/local/camswitcher/output_info.cgi')).data;
52
+ });
26
53
  }
27
54
  getPlaylistList() {
28
55
  return this.get('/local/camswitcher/playlists.cgi?action=get');
29
56
  }
30
- getClipList() {
31
- return this.get('/local/camswitcher/clips.cgi?action=get');
32
- }
33
57
  playlistSwitch(playlistName) {
34
58
  return __awaiter(this, void 0, void 0, function* () {
35
59
  yield this.get(`/local/camswitcher/playlist_switch.cgi?playlist_name=${playlistName}`);
36
60
  });
37
61
  }
38
- playlistQueueList() {
39
- return this.get('/local/camswitcher/playlist_queue_list.cgi');
62
+ playlistQueuePush(playlistName) {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ yield this.get(`/local/camswitcher/playlist_queue_push.cgi?playlist_name=${playlistName}`);
65
+ });
40
66
  }
41
67
  playlistQueueClear() {
42
68
  return __awaiter(this, void 0, void 0, function* () {
43
69
  yield this.get('/local/camswitcher/playlist_queue_clear.cgi');
44
70
  });
45
71
  }
46
- playlistQueuePush(playlistName) {
47
- return __awaiter(this, void 0, void 0, function* () {
48
- yield this.get(`/local/camswitcher/playlist_queue_push.cgi?playlist_name=${playlistName}`);
49
- });
72
+ playlistQueueList() {
73
+ return this.get('/local/camswitcher/playlist_queue_list.cgi');
50
74
  }
51
75
  playlistQueuePlayNext() {
52
76
  return __awaiter(this, void 0, void 0, function* () {
53
77
  yield this.get('/local/camswitcher/playlist_queue_play_next.cgi');
54
78
  });
55
79
  }
56
- getOutputInfo() {
57
- return this.get('/local/camswitcher/output_info.cgi');
80
+ getClipList() {
81
+ return this.get('/local/camswitcher/clips.cgi?action=get');
82
+ }
83
+ addNewClip(file, clipType, storage, id, fileName) {
84
+ return __awaiter(this, void 0, void 0, function* () {
85
+ const formData = new FormData();
86
+ formData.append('clip_name', id);
87
+ formData.append('clip_type', clipType);
88
+ formData.append('file', file, fileName);
89
+ const path = `/local/camswitcher/clip_upload.cgi?storage=${storage}`;
90
+ const res = yield this.client.post(path, formData);
91
+ const output = (yield res.json());
92
+ if (output.status !== 200) {
93
+ throw new Error('Error on camera: ' + output.message);
94
+ }
95
+ });
96
+ }
97
+ removeClip(id, storage) {
98
+ return this.get(`/local/camswitcher/clip_remove.cgi`, { clip_name: id, storage });
58
99
  }
59
- get(path) {
100
+ get(path, parameters = {}) {
60
101
  return __awaiter(this, void 0, void 0, function* () {
61
- const res = yield this.client.get(path);
102
+ const res = yield this.client.get(path, parameters);
62
103
  if (res.ok) {
63
104
  return yield res.json();
64
105
  }
65
106
  else {
66
- throw new Error(JSON.stringify(res));
107
+ throw new Error(yield (0, common_1.responseStringify)(res));
67
108
  }
68
109
  });
69
110
  }
@@ -2,6 +2,22 @@
2
2
  import * as EventEmitter from 'events';
3
3
  import { HttpOptions } from './internal/common';
4
4
  export type CamSwitcherEventsOptions = HttpOptions;
5
+ export type TEvent = {
6
+ type: string;
7
+ date: Record<string, string | number | boolean> & {
8
+ type: string;
9
+ };
10
+ };
11
+ export interface CamSwitcherEvents {
12
+ on(event: 'open', listener: () => void): this;
13
+ on(event: 'close', listener: () => void): this;
14
+ on(event: 'event', listener: (data: TEvent) => void): this;
15
+ on(event: 'error', listener: (err: Error) => void): this;
16
+ emit(event: 'open'): boolean;
17
+ emit(event: 'close'): boolean;
18
+ emit(event: 'event', data: TEvent): boolean;
19
+ emit(event: 'error', err: Error): boolean;
20
+ }
5
21
  export declare class CamSwitcherEvents extends EventEmitter {
6
22
  private tls;
7
23
  private tlsInsecure;
@@ -14,6 +30,7 @@ export declare class CamSwitcherEvents extends EventEmitter {
14
30
  constructor(options?: CamSwitcherEventsOptions);
15
31
  connect(): void;
16
32
  disconnect(): void;
33
+ resendInitData(): void;
17
34
  private createWsClient;
18
35
  private get;
19
36
  }
@@ -33,6 +33,12 @@ class CamSwitcherEvents extends EventEmitter {
33
33
  disconnect() {
34
34
  this.ws.close();
35
35
  }
36
+ resendInitData() {
37
+ const request = {
38
+ command: 'sendInitData',
39
+ };
40
+ this.ws.send(JSON.stringify(request));
41
+ }
36
42
  createWsClient() {
37
43
  const options = {
38
44
  ip: this.ip,
@@ -49,21 +55,28 @@ class CamSwitcherEvents extends EventEmitter {
49
55
  try {
50
56
  const token = yield this.get('/local/camswitcher/ws_authorization.cgi');
51
57
  this.ws.send(JSON.stringify({ authorization: token }));
52
- this.emit('open');
53
58
  }
54
59
  catch (err) {
55
60
  this.emit('error', err);
56
- this.ws.close();
57
- this.ws.open();
58
61
  }
59
62
  }));
60
63
  this.ws.on('message', (data) => {
61
64
  try {
62
65
  const parsedData = JSON.parse(data.toString());
63
- this.emit('event', parsedData);
66
+ if (parsedData.type === 'authorization') {
67
+ if (parsedData.state === 'OK') {
68
+ this.emit('open');
69
+ }
70
+ else {
71
+ this.emit('error', new Error(data.toString()));
72
+ }
73
+ }
74
+ else {
75
+ this.emit('event', parsedData);
76
+ }
64
77
  }
65
78
  catch (err) {
66
- console.error(err);
79
+ this.emit('error', err);
67
80
  }
68
81
  });
69
82
  this.ws.on('error', (err) => {
package/CameraVapix.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
+ /// <reference types="node" />
3
4
  import { WritableStream } from 'node:stream/web';
4
- import { EventEmitter2 as EventEmitter } from 'eventemitter2';
5
5
  import { HttpOptions, IClient } from './internal/common';
6
6
  export type CameraVapixOptions = HttpOptions;
7
7
  export type TApplicationList = {
@@ -41,20 +41,58 @@ export type TGuardTour = {
41
41
  waitTimeViewType: unknown;
42
42
  }[];
43
43
  };
44
- export declare class CameraVapix extends EventEmitter {
44
+ export type TAudioSampleRates = {
45
+ sampleRate: number;
46
+ bitRates: number[];
47
+ };
48
+ export type TSDCardInfo = {
49
+ available: boolean;
50
+ totalSize: number;
51
+ freeSize: number;
52
+ };
53
+ export type TPtzOverview = Record<number, {
54
+ id: number;
55
+ name: string;
56
+ }[]>;
57
+ export type TCameraPTZItem = {
58
+ name: string;
59
+ id: number;
60
+ data: TCameraPTZItemData;
61
+ };
62
+ export type TCameraPTZItemData = {
63
+ pan?: number;
64
+ tilt?: number;
65
+ zoom?: number;
66
+ };
67
+ export declare class CameraVapix {
45
68
  private client;
46
69
  constructor(options?: CameraVapixOptions | IClient);
47
- vapixGet(path: string): Promise<Response>;
48
- vapixPost(path: string, data: string, contentType?: string): Promise<Response>;
70
+ vapixGet(path: string, parameters?: Record<string, string>): Promise<Response>;
71
+ vapixPost(path: string, data: string | Buffer | FormData, contentType?: string): Promise<Response>;
72
+ getCameraImage(camera: string, compression: string, resolution: string, outputStream: WritableStream): Promise<WritableStream<any>>;
73
+ getEventDeclarations(): Promise<string>;
74
+ getSupportedAudioSampleRate(): Promise<TAudioSampleRates[]>;
75
+ checkSdCard(): Promise<TSDCardInfo>;
76
+ downloadCameraReport(): Promise<Response>;
77
+ getMaxFps(channel: number): Promise<number>;
78
+ getTimezone(): Promise<string>;
79
+ getHeaders(): Promise<Record<string, string>>;
80
+ setHeaders(headers: Record<string, string>): Promise<Response>;
81
+ private parseGetParametrs;
49
82
  getParameterGroup(groupNames: string): Promise<Record<string, string>>;
50
83
  setParameter(params: Record<string, string>): Promise<Response>;
51
- getPTZPresetList(channel: string): Promise<string[]>;
52
- goToPreset(channel: number, presetName: string): Promise<Response>;
53
84
  getGuardTourList(): Promise<TGuardTour[]>;
54
85
  setGuardTourEnabled(gourTourID: string, enable: boolean): Promise<Response>;
86
+ private parsePtz;
87
+ private parseCameraPtzFromReq;
88
+ getPTZPresetList(channel: number): Promise<string[]>;
89
+ listPtzVideoSourceOverview(): Promise<TPtzOverview>;
90
+ goToPreset(channel: number, presetName: string): Promise<Response>;
91
+ getPtzPosition(camera: number): Promise<TCameraPTZItemData>;
55
92
  getInputState(port: number): Promise<boolean>;
56
93
  setOutputState(port: number, active: boolean): Promise<Response>;
57
94
  getApplicationList(): Promise<TApplication[]>;
58
- getCameraImage(camera: string, compression: string, resolution: string, outputStream: WritableStream): Promise<WritableStream<any>>;
59
- getEventDeclarations(): Promise<string>;
95
+ startApplication(applicationID: string): Promise<void>;
96
+ restartApplication(applicationID: string): Promise<void>;
97
+ stopApplication(applicationID: string): Promise<void>;
60
98
  }
package/CameraVapix.js CHANGED
@@ -8,16 +8,25 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
11
22
  Object.defineProperty(exports, "__esModule", { value: true });
12
23
  exports.CameraVapix = void 0;
13
24
  const prettifyXml = require("prettify-xml");
14
25
  const xml2js_1 = require("xml2js");
15
- const eventemitter2_1 = require("eventemitter2");
16
26
  const common_1 = require("./internal/common");
17
27
  const DefaultAgent_1 = require("./DefaultAgent");
18
- class CameraVapix extends eventemitter2_1.EventEmitter2 {
28
+ class CameraVapix {
19
29
  constructor(options = {}) {
20
- super();
21
30
  if ((0, common_1.isClient)(options)) {
22
31
  this.client = options;
23
32
  }
@@ -25,8 +34,8 @@ class CameraVapix extends eventemitter2_1.EventEmitter2 {
25
34
  this.client = new DefaultAgent_1.DefaultAgent(options);
26
35
  }
27
36
  }
28
- vapixGet(path) {
29
- return this.client.get(path);
37
+ vapixGet(path, parameters) {
38
+ return this.client.get(path, parameters);
30
39
  }
31
40
  vapixPost(path, data, contentType) {
32
41
  let headers = {};
@@ -35,17 +44,174 @@ class CameraVapix extends eventemitter2_1.EventEmitter2 {
35
44
  }
36
45
  return this.client.post(path, data, {}, headers);
37
46
  }
47
+ getCameraImage(camera, compression, resolution, outputStream) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ const path = `/axis-cgi/jpg/image.cgi?resolution=${resolution}&compression=${compression}&camera=${camera}`;
50
+ const res = yield this.vapixGet(path);
51
+ if (res.body) {
52
+ void res.body.pipeTo(outputStream);
53
+ }
54
+ return outputStream;
55
+ });
56
+ }
57
+ getEventDeclarations() {
58
+ return __awaiter(this, void 0, void 0, function* () {
59
+ const data = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">' +
60
+ '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
61
+ 'xmlns:xsd="http://www.w3.org/2001/XMLSchema">' +
62
+ '<GetEventInstances xmlns="http://www.axis.com/vapix/ws/event1"/>' +
63
+ '</s:Body>' +
64
+ '</s:Envelope>';
65
+ const declarations = yield (yield this.vapixPost('/vapix/services', data, 'application/soap+xml')).text();
66
+ return prettifyXml(declarations);
67
+ });
68
+ }
69
+ getSupportedAudioSampleRate() {
70
+ var _a, _b;
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ const url = '/axis-cgi/audio/streamingcapabilities.cgi';
73
+ const formData = { apiVersion: '1.0', method: 'list' };
74
+ const res = yield this.vapixPost(url, JSON.stringify(formData));
75
+ try {
76
+ const encoders = (yield res.json()).data.encoders;
77
+ const data = (_b = (_a = encoders.aac) !== null && _a !== void 0 ? _a : encoders.AAC) !== null && _b !== void 0 ? _b : [];
78
+ return data.map((item) => {
79
+ return {
80
+ sampleRate: item.sample_rate,
81
+ bitRates: item.bit_rates,
82
+ };
83
+ });
84
+ }
85
+ catch (err) {
86
+ return [];
87
+ }
88
+ });
89
+ }
90
+ checkSdCard() {
91
+ return __awaiter(this, void 0, void 0, function* () {
92
+ const res = yield this.vapixGet('/axis-cgi/disks/list.cgi', {
93
+ diskid: 'SD_DISK',
94
+ });
95
+ const result = yield (0, xml2js_1.parseStringPromise)(yield res.text(), {
96
+ ignoreAttrs: false,
97
+ mergeAttrs: true,
98
+ explicitArray: false,
99
+ });
100
+ const data = result.root.disks.disk;
101
+ return {
102
+ available: data.status === 'OK',
103
+ totalSize: parseInt(data.totalsize),
104
+ freeSize: parseInt(data.freesize),
105
+ };
106
+ });
107
+ }
108
+ downloadCameraReport() {
109
+ return __awaiter(this, void 0, void 0, function* () {
110
+ const res = yield this.vapixGet('/axis-cgi/serverreport.cgi', { mode: 'text' });
111
+ if (res.ok) {
112
+ return res;
113
+ }
114
+ else {
115
+ throw new Error(yield (0, common_1.responseStringify)(res));
116
+ }
117
+ });
118
+ }
119
+ getMaxFps(channel) {
120
+ return __awaiter(this, void 0, void 0, function* () {
121
+ const data = JSON.stringify({ apiVersion: '1.0', method: 'getCaptureModes' });
122
+ const res = yield this.vapixPost('/axis-cgi/capturemode.cgi', data);
123
+ if (!res.ok) {
124
+ throw new Error(yield (0, common_1.responseStringify)(res));
125
+ }
126
+ const response = (yield res.json());
127
+ const channels = response.data;
128
+ if (channels === undefined) {
129
+ throw new Error(`Malformed reply from camera`);
130
+ }
131
+ const channelData = channels.find((x) => x.channel === channel);
132
+ if (channelData === undefined) {
133
+ throw new Error(`Video channel '${channel}' not found`);
134
+ }
135
+ const captureModes = channelData.captureMode;
136
+ const captureMode = captureModes.find((x) => x.enabled === true);
137
+ if (captureMode === undefined) {
138
+ throw new Error(`No enabled capture mode found.`);
139
+ }
140
+ const maxFps = parseInt(captureMode.maxFPS, 10);
141
+ if (isNaN(maxFps)) {
142
+ throw new Error(`Max fps not specified for given capture mode.`);
143
+ }
144
+ return maxFps;
145
+ });
146
+ }
147
+ getTimezone() {
148
+ var _a, _b;
149
+ return __awaiter(this, void 0, void 0, function* () {
150
+ const data = JSON.stringify({ apiVersion: '1.0', method: 'getDateTimeInfo' });
151
+ const res = yield this.vapixPost('/axis-cgi/time.cgi', data);
152
+ if (res.ok) {
153
+ return (_b = (_a = ((yield res.json()))) === null || _a === void 0 ? void 0 : _a.timeZone) !== null && _b !== void 0 ? _b : 'Europe/Prague';
154
+ }
155
+ else {
156
+ throw new Error(yield (0, common_1.responseStringify)(res));
157
+ }
158
+ });
159
+ }
160
+ getHeaders() {
161
+ var _a;
162
+ return __awaiter(this, void 0, void 0, function* () {
163
+ try {
164
+ const data = JSON.stringify({ apiVersion: '1.0', method: 'list' });
165
+ const res = yield this.vapixPost('/axis-cgi/customhttpheader.cgi', data);
166
+ if (res.ok) {
167
+ return (_a = (yield res.json()).data) !== null && _a !== void 0 ? _a : {};
168
+ }
169
+ else {
170
+ return {};
171
+ }
172
+ }
173
+ catch (e) {
174
+ return {};
175
+ }
176
+ });
177
+ }
178
+ setHeaders(headers) {
179
+ return __awaiter(this, void 0, void 0, function* () {
180
+ const data = JSON.stringify({ apiVersion: '1.0', method: 'set', params: headers });
181
+ return this.vapixPost('/axis-cgi/customhttpheader.cgi', data);
182
+ });
183
+ }
184
+ parseGetParametrs(response) {
185
+ const params = {};
186
+ const lines = response.split(/[\r\n]/);
187
+ for (let i = 0; i < lines.length; i++) {
188
+ if (lines[i].substring(0, 7) === '# Error') {
189
+ continue;
190
+ }
191
+ if (lines[i].length) {
192
+ const p = lines[i].split(/=(.+)/);
193
+ if (p.length >= 2) {
194
+ const paramName = p[0].replace('root.', '');
195
+ params[paramName] = String(p[1]);
196
+ }
197
+ else if (p[0].substring(0, 7) !== '# Error') {
198
+ params[p[0].slice(0, -1)] = '';
199
+ }
200
+ }
201
+ }
202
+ return params;
203
+ }
38
204
  getParameterGroup(groupNames) {
39
205
  return __awaiter(this, void 0, void 0, function* () {
40
206
  const response = yield (yield this.vapixGet(`/axis-cgi/param.cgi?action=list&group=${encodeURIComponent(groupNames)}`)).text();
41
207
  const params = {};
42
208
  const lines = response.split(/[\r\n]/);
43
- for (const line of lines) {
44
- const delimiterPos = line.indexOf('=');
45
- if (delimiterPos !== -1) {
46
- const key = line.substring(0, delimiterPos);
47
- const value = line.substring(delimiterPos + 1);
48
- params[key] = value;
209
+ for (let i = 0; i < lines.length; i++) {
210
+ if (lines[i].length) {
211
+ const p = lines[i].split('=');
212
+ if (p.length >= 2) {
213
+ params[p[0]] = p[1];
214
+ }
49
215
  }
50
216
  }
51
217
  return params;
@@ -59,26 +225,6 @@ class CameraVapix extends eventemitter2_1.EventEmitter2 {
59
225
  postData = postData.slice(0, postData.length - 1);
60
226
  return this.vapixPost('/axis-cgi/param.cgi', postData);
61
227
  }
62
- getPTZPresetList(channel) {
63
- return __awaiter(this, void 0, void 0, function* () {
64
- const response = yield (yield this.vapixGet(`/axis-cgi/com/ptz.cgi?query=presetposcam&camera=${encodeURIComponent(channel)}`)).text();
65
- const positions = [];
66
- const lines = response.split(/[\r\n]/);
67
- for (const line of lines) {
68
- if (line.indexOf('presetposno') !== -1) {
69
- const delimiterPos = line.indexOf('=');
70
- if (delimiterPos !== -1) {
71
- const value = line.substring(delimiterPos + 1);
72
- positions.push(value);
73
- }
74
- }
75
- }
76
- return positions;
77
- });
78
- }
79
- goToPreset(channel, presetName) {
80
- return this.vapixPost('/axis-cgi/com/ptz.cgi', `camera=${encodeURIComponent(channel)}&gotoserverpresetname=${encodeURIComponent(presetName)}`);
81
- }
82
228
  getGuardTourList() {
83
229
  return __awaiter(this, void 0, void 0, function* () {
84
230
  const gTourList = new Array();
@@ -122,6 +268,121 @@ class CameraVapix extends eventemitter2_1.EventEmitter2 {
122
268
  options[gourTourID + '.Running'] = enable ? 'yes' : 'no';
123
269
  return this.setParameter(options);
124
270
  }
271
+ parsePtz(parsed) {
272
+ const res = [];
273
+ parsed.forEach((value) => {
274
+ const valueData = value.split('=');
275
+ if (valueData.length < 2) {
276
+ return;
277
+ }
278
+ if (!valueData[0].startsWith('presetposno')) {
279
+ return;
280
+ }
281
+ const id = Number(valueData[0].replace('presetposno', ''));
282
+ if (Number.isNaN(id)) {
283
+ return;
284
+ }
285
+ const data = valueData[1].split(':');
286
+ const getValue = (valueName) => {
287
+ for (const d of data) {
288
+ const p = d.split('=');
289
+ if (p[0] === valueName) {
290
+ return Number(p[1]);
291
+ }
292
+ }
293
+ return 0;
294
+ };
295
+ res.push({
296
+ id,
297
+ name: data[0],
298
+ data: {
299
+ pan: getValue('pan'),
300
+ tilt: getValue('tilt'),
301
+ zoom: getValue('zoom'),
302
+ },
303
+ });
304
+ });
305
+ return res;
306
+ }
307
+ parseCameraPtzFromReq(response) {
308
+ const json = JSON.parse(response);
309
+ const parsed = {};
310
+ Object.keys(json).forEach((key) => {
311
+ if (!key.startsWith('Camera ')) {
312
+ return;
313
+ }
314
+ const camera = Number(key.replace('Camera ', ''));
315
+ if (json[key].presets !== undefined) {
316
+ parsed[camera] = this.parsePtz(json[key].presets);
317
+ }
318
+ });
319
+ return parsed;
320
+ }
321
+ getPTZPresetList(channel) {
322
+ return __awaiter(this, void 0, void 0, function* () {
323
+ const response = yield (yield this.vapixGet(`/axis-cgi/com/ptz.cgi?query=presetposcam&camera=${encodeURIComponent(channel)}`)).text();
324
+ const positions = [];
325
+ const lines = response.split(/[\r\n]/);
326
+ for (const line of lines) {
327
+ if (line.indexOf('presetposno') !== -1) {
328
+ const delimiterPos = line.indexOf('=');
329
+ if (delimiterPos !== -1) {
330
+ const value = line.substring(delimiterPos + 1);
331
+ positions.push(value);
332
+ }
333
+ }
334
+ }
335
+ return positions;
336
+ });
337
+ }
338
+ listPtzVideoSourceOverview() {
339
+ return __awaiter(this, void 0, void 0, function* () {
340
+ try {
341
+ const response = yield this.vapixGet(`/axis-cgi/com/ptz.cgi`, {
342
+ query: 'presetposall',
343
+ format: 'json',
344
+ });
345
+ const data = this.parseCameraPtzFromReq(yield response.text());
346
+ const res = {};
347
+ Object.keys(data).forEach((camera) => {
348
+ res[Number(camera) - 1] = data[Number(camera)].map((_a) => {
349
+ var { data } = _a, d = __rest(_a, ["data"]);
350
+ return d;
351
+ });
352
+ });
353
+ return res;
354
+ }
355
+ catch (err) {
356
+ return [];
357
+ }
358
+ });
359
+ }
360
+ goToPreset(channel, presetName) {
361
+ return this.vapixPost('/axis-cgi/com/ptz.cgi', `camera=${encodeURIComponent(channel)}&gotoserverpresetname=${encodeURIComponent(presetName)}`);
362
+ }
363
+ getPtzPosition(camera) {
364
+ return __awaiter(this, void 0, void 0, function* () {
365
+ try {
366
+ const res = yield this.vapixGet(`/axis-cgi/com/ptz.cgi`, {
367
+ query: 'position',
368
+ camera: camera.toString(),
369
+ });
370
+ const data = this.parseGetParametrs(yield res.text());
371
+ return {
372
+ pan: Number(data.pan),
373
+ tilt: Number(data.tilt),
374
+ zoom: Number(data.zoom),
375
+ };
376
+ }
377
+ catch (err) {
378
+ return {
379
+ pan: 0,
380
+ tilt: 0,
381
+ zoom: 0,
382
+ };
383
+ }
384
+ });
385
+ }
125
386
  getInputState(port) {
126
387
  return __awaiter(this, void 0, void 0, function* () {
127
388
  const response = yield (yield this.vapixPost('/axis-cgi/io/port.cgi', `checkactive=${encodeURIComponent(port)}`)).text();
@@ -129,11 +390,13 @@ class CameraVapix extends eventemitter2_1.EventEmitter2 {
129
390
  });
130
391
  }
131
392
  setOutputState(port, active) {
132
- return this.vapixPost('/axis-cgi/io/port.cgi', `action=${encodeURIComponent(port)}:${active ? '/' : '\\'}`);
393
+ return __awaiter(this, void 0, void 0, function* () {
394
+ return this.vapixPost('/axis-cgi/io/port.cgi', `action=${encodeURIComponent(port)}:${active ? '/' : '\\'}`);
395
+ });
133
396
  }
134
397
  getApplicationList() {
135
398
  return __awaiter(this, void 0, void 0, function* () {
136
- const xml = yield this.vapixGet('/axis-cgi/applications/list.cgi');
399
+ const xml = yield (yield this.vapixGet('/axis-cgi/applications/list.cgi')).text();
137
400
  const result = (yield (0, xml2js_1.parseStringPromise)(xml));
138
401
  const apps = [];
139
402
  for (let i = 0; i < result.reply.application.length; i++) {
@@ -142,26 +405,55 @@ class CameraVapix extends eventemitter2_1.EventEmitter2 {
142
405
  return apps;
143
406
  });
144
407
  }
145
- getCameraImage(camera, compression, resolution, outputStream) {
408
+ startApplication(applicationID) {
146
409
  return __awaiter(this, void 0, void 0, function* () {
147
- const path = `/axis-cgi/jpg/image.cgi?resolution=${resolution}&compression=${compression}&camera=${camera}`;
148
- const res = yield this.vapixGet(path);
149
- if (res.body) {
150
- void res.body.pipeTo(outputStream);
410
+ const res = yield this.vapixGet('/axis-cgi/applications/control.cgi', {
411
+ package: applicationID.toLowerCase(),
412
+ action: 'start',
413
+ });
414
+ const text = (yield res.text()).trim().toLowerCase();
415
+ if (res.ok && text === 'ok') {
416
+ return;
417
+ }
418
+ else if (text.startsWith('error:') && text.substring(7) === '6') {
419
+ return;
420
+ }
421
+ else {
422
+ throw new Error(yield (0, common_1.responseStringify)(res));
151
423
  }
152
- return outputStream;
153
424
  });
154
425
  }
155
- getEventDeclarations() {
426
+ restartApplication(applicationID) {
156
427
  return __awaiter(this, void 0, void 0, function* () {
157
- const data = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">' +
158
- '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
159
- 'xmlns:xsd="http://www.w3.org/2001/XMLSchema">' +
160
- '<GetEventInstances xmlns="http://www.axis.com/vapix/ws/event1"/>' +
161
- '</s:Body>' +
162
- '</s:Envelope>';
163
- const declarations = yield this.vapixPost('/vapix/services', data, 'application/soap+xml');
164
- return prettifyXml(declarations);
428
+ const res = yield this.vapixGet('/axis-cgi/applications/control.cgi', {
429
+ package: applicationID.toLowerCase(),
430
+ action: 'restart',
431
+ });
432
+ const text = (yield res.text()).trim().toLowerCase();
433
+ if (res.ok && text === 'ok') {
434
+ return;
435
+ }
436
+ else {
437
+ throw new Error(yield (0, common_1.responseStringify)(res));
438
+ }
439
+ });
440
+ }
441
+ stopApplication(applicationID) {
442
+ return __awaiter(this, void 0, void 0, function* () {
443
+ const res = yield this.vapixGet('/axis-cgi/applications/control.cgi', {
444
+ package: applicationID.toLowerCase(),
445
+ action: 'stop',
446
+ });
447
+ const text = (yield res.text()).trim().toLowerCase();
448
+ if (res.ok && text === 'ok') {
449
+ return;
450
+ }
451
+ else if (text.startsWith('error:') && text.substring(7) === '6') {
452
+ return;
453
+ }
454
+ else {
455
+ throw new Error(yield (0, common_1.responseStringify)(res));
456
+ }
165
457
  });
166
458
  }
167
459
  }
package/VapixEvents.d.ts CHANGED
@@ -1,6 +1,31 @@
1
1
  import { EventEmitter2 as EventEmitter } from 'eventemitter2';
2
2
  import { WsOptions } from './internal/common';
3
3
  export type VapixEventsOptions = WsOptions;
4
+ type TEventMessage = {
5
+ apiVersion: string;
6
+ method: string;
7
+ params: {
8
+ notification: {
9
+ timestamp: number;
10
+ topic: string;
11
+ message: {
12
+ source: Record<string, string>;
13
+ data: Record<string, string>;
14
+ key: Record<string, string>;
15
+ };
16
+ };
17
+ };
18
+ };
19
+ export interface VapixEvents {
20
+ on(event: 'open', listener: () => void): this;
21
+ on(event: 'close', listener: () => void): this;
22
+ on(event: 'error', listener: (err: Error) => void): this;
23
+ on(event: string, listener: (data: TEventMessage) => void): this;
24
+ emit(event: 'open'): boolean;
25
+ emit(event: 'close'): boolean;
26
+ emit(event: 'error', err: Error): boolean;
27
+ emit(event: string, msg: TEventMessage): boolean;
28
+ }
4
29
  export declare class VapixEvents extends EventEmitter {
5
30
  private tls;
6
31
  private tlsInsecure;
@@ -15,3 +40,4 @@ export declare class VapixEvents extends EventEmitter {
15
40
  private createWsClient;
16
41
  private isReservedEventName;
17
42
  }
43
+ export {};
@@ -8,6 +8,16 @@ export type WsClientOptions = WsOptions & {
8
8
  pingInterval?: number;
9
9
  protocol?: string;
10
10
  };
11
+ export interface WsClient {
12
+ on(event: 'open', listener: () => void): this;
13
+ on(event: 'close', listener: () => void): this;
14
+ on(event: 'message', listener: (data: Buffer) => void): this;
15
+ on(event: 'error', listener: (err: Error) => void): this;
16
+ emit(event: 'open'): boolean;
17
+ emit(event: 'close'): boolean;
18
+ emit(event: 'message', data: Buffer): boolean;
19
+ emit(event: 'error', err: Error): boolean;
20
+ }
11
21
  export declare class WsClient extends EventEmitter {
12
22
  private user;
13
23
  private pass;
@@ -20,4 +20,5 @@ export interface IClient {
20
20
  }
21
21
  export declare function isClient(arg?: Options | IClient): arg is IClient;
22
22
  export declare function isBrowserEnvironment(): boolean;
23
+ export declare function responseStringify(res: Response): Promise<string>;
23
24
  export {};
@@ -1,6 +1,15 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isBrowserEnvironment = exports.isClient = void 0;
12
+ exports.responseStringify = exports.isBrowserEnvironment = exports.isClient = void 0;
4
13
  function isClient(arg = {}) {
5
14
  return 'get' in arg && 'post' in arg;
6
15
  }
@@ -9,3 +18,12 @@ function isBrowserEnvironment() {
9
18
  return typeof process === 'undefined' || process.versions === null || process.versions.node === null;
10
19
  }
11
20
  exports.isBrowserEnvironment = isBrowserEnvironment;
21
+ function responseStringify(res) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ return JSON.stringify({
24
+ status: res.status,
25
+ body: yield res.text(),
26
+ });
27
+ });
28
+ }
29
+ exports.responseStringify = responseStringify;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camstreamerlib",
3
- "version": "3.2.2",
3
+ "version": "3.2.3",
4
4
  "description": "Helper library for CamStreamer ACAP applications.",
5
5
  "prettier": "@camstreamer/prettier-config",
6
6
  "dependencies": {