@camera.ui/cli 0.0.49 → 0.0.51
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.
- package/LICENSE.md +1 -1
- package/README.md +10 -1
- package/dist/commands/artifacts.d.ts +9 -0
- package/dist/commands/artifacts.js +116 -0
- package/dist/commands/artifacts.js.map +1 -0
- package/dist/commands/bundle.d.ts +34 -1
- package/dist/commands/bundle.js +402 -57
- package/dist/commands/bundle.js.map +1 -1
- package/dist/commands/create.js +140 -93
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/publish.js +95 -39
- package/dist/commands/publish.js.map +1 -1
- package/dist/index.js +13 -4
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +24 -5
- package/dist/utils/banners.d.ts +3 -1
- package/dist/utils/banners.js +15 -11
- package/dist/utils/banners.js.map +1 -1
- package/dist/utils/logger.d.ts +12 -24
- package/dist/utils/logger.js +57 -83
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/parser.d.ts +11 -4
- package/dist/utils/parser.js +27 -185
- package/dist/utils/parser.js.map +1 -1
- package/dist/utils/templates.d.ts +13 -1
- package/dist/utils/templates.js +148 -68
- package/dist/utils/templates.js.map +1 -1
- package/dist/utils/utils.js +13 -11
- package/dist/utils/utils.js.map +1 -1
- package/dist/utils/versions.js +1 -2
- package/dist/utils/versions.js.map +1 -1
- package/package.json +29 -43
- package/templates/base/README.md +2 -2
- package/templates/base/SECURITY.md +1 -1
- package/templates/base/package.json +2 -3
- package/templates/base/updates.config.js +1 -1
- package/templates/go/go.mod +5 -0
- package/templates/go/postinstall.js +85 -0
- package/templates/go/src/main.go +51 -0
- package/templates/python/requirements.txt +1 -1
- package/templates/python/ruff.toml +2 -2
- package/templates/python/src/main.py +299 -28
- package/templates/typescript/contract.ts +36 -0
- package/templates/typescript/eslint.config.js +13 -3
- package/templates/typescript/package.eslint.json +2 -2
- package/templates/typescript/package.json +4 -4
- package/templates/typescript/src/index.ts +96 -27
- package/templates/typescript/src/sensor.ts +207 -0
- package/CHANGELOG.md +0 -8
- package/CONTRIBUTING.md +0 -1
- package/scripts/chmod.js +0 -17
- package/templates/base/cameraui.config.js +0 -10
- package/templates/base/eslint.config.js +0 -64
- package/templates/base/src/index.js +0 -41
|
@@ -1,46 +1,115 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { API_EVENT, BasePlugin } from '@camera.ui/sdk';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
public logger: LoggerService;
|
|
5
|
-
public api: PluginAPI;
|
|
3
|
+
import { ExampleLightControl, ExampleMotionSensor } from './sensor.js';
|
|
6
4
|
|
|
5
|
+
import type { CameraDevice, DeviceStorage, LightControl, LoggerService, MotionSensor, PluginAPI } from '@camera.ui/sdk';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Sample Plugin
|
|
9
|
+
*
|
|
10
|
+
* Demonstrates the camera.ui plugin architecture with sensors:
|
|
11
|
+
* - MotionSensor: External motion events (webhooks, ONVIF, etc.)
|
|
12
|
+
* - LightControl: Controllable light with on/brightness
|
|
13
|
+
*
|
|
14
|
+
* The contract (provides/consumes) is defined in contract.ts.
|
|
15
|
+
*/
|
|
16
|
+
export default class SamplePlugin extends BasePlugin {
|
|
17
|
+
// Maps to track cameras and sensors
|
|
7
18
|
private cameras = new Map<string, CameraDevice>();
|
|
19
|
+
private motionSensors = new Map<string, MotionSensor>();
|
|
20
|
+
private lightControls = new Map<string, LightControl>();
|
|
21
|
+
|
|
22
|
+
constructor(logger: LoggerService, api: PluginAPI, storage: DeviceStorage<any>) {
|
|
23
|
+
super(logger, api, storage);
|
|
24
|
+
|
|
25
|
+
// Register lifecycle event handlers
|
|
26
|
+
this.api.on(API_EVENT.FINISH_LAUNCHING, this.onFinishLaunching.bind(this));
|
|
27
|
+
this.api.on(API_EVENT.SHUTDOWN, this.onShutdown.bind(this));
|
|
28
|
+
}
|
|
8
29
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Configure cameras at startup.
|
|
32
|
+
* Called for cameras already assigned to this plugin.
|
|
33
|
+
*/
|
|
34
|
+
public async configureCameras(cameras: CameraDevice[]): Promise<void> {
|
|
35
|
+
for (const camera of cameras) {
|
|
36
|
+
await this.setupCamera(camera);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Called when a camera is selected for this plugin at runtime.
|
|
42
|
+
*/
|
|
43
|
+
public async onCameraAdded(camera: CameraDevice): Promise<void> {
|
|
44
|
+
this.logger.log('Camera selected:', camera.name);
|
|
45
|
+
await this.setupCamera(camera);
|
|
46
|
+
}
|
|
12
47
|
|
|
13
|
-
|
|
14
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Called when a camera is deselected from this plugin.
|
|
50
|
+
*/
|
|
51
|
+
public async onCameraReleased(cameraId: string): Promise<void> {
|
|
52
|
+
const camera = this.cameras.get(cameraId);
|
|
53
|
+
if (!camera) return;
|
|
15
54
|
|
|
16
|
-
this.
|
|
17
|
-
this.logger.log('Camera selected:', cameraDevice.name);
|
|
55
|
+
this.logger.log('Camera deselected:', camera.name);
|
|
18
56
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
57
|
+
// Remove sensors
|
|
58
|
+
const motion = this.motionSensors.get(cameraId);
|
|
59
|
+
if (motion) {
|
|
60
|
+
await camera.removeSensor(motion.id);
|
|
61
|
+
this.motionSensors.delete(cameraId);
|
|
62
|
+
}
|
|
23
63
|
|
|
24
|
-
this.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
64
|
+
const light = this.lightControls.get(cameraId);
|
|
65
|
+
if (light) {
|
|
66
|
+
await camera.removeSensor(light.id);
|
|
67
|
+
this.lightControls.delete(cameraId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.cameras.delete(cameraId);
|
|
31
71
|
}
|
|
32
72
|
|
|
33
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Set up sensors for a camera.
|
|
75
|
+
*/
|
|
76
|
+
private async setupCamera(camera: CameraDevice): Promise<void> {
|
|
77
|
+
if (this.cameras.has(camera.id)) return;
|
|
78
|
+
|
|
79
|
+
this.cameras.set(camera.id, camera);
|
|
80
|
+
|
|
81
|
+
// Create motion sensor
|
|
82
|
+
const motion = new ExampleMotionSensor(`Motion - ${camera.name}`);
|
|
83
|
+
this.motionSensors.set(camera.id, motion);
|
|
84
|
+
await camera.addSensor(motion);
|
|
34
85
|
|
|
35
|
-
|
|
36
|
-
|
|
86
|
+
// Create light control
|
|
87
|
+
const light = new ExampleLightControl(camera, `Light - ${camera.name}`);
|
|
88
|
+
this.lightControls.set(camera.id, light);
|
|
89
|
+
await camera.addSensor(light);
|
|
90
|
+
|
|
91
|
+
this.logger.log(`Sensors registered for ${camera.name}`);
|
|
92
|
+
|
|
93
|
+
// Example: Trigger motion after 5 seconds (for testing)
|
|
94
|
+
// setTimeout(() => motion.trigger(), 5000);
|
|
37
95
|
}
|
|
38
96
|
|
|
39
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Called when the plugin has finished launching.
|
|
99
|
+
*/
|
|
100
|
+
private onFinishLaunching(): void {
|
|
40
101
|
this.logger.log('Plugin started');
|
|
41
102
|
}
|
|
42
103
|
|
|
43
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Called when camera.ui is shutting down.
|
|
106
|
+
*/
|
|
107
|
+
private async onShutdown(): Promise<void> {
|
|
44
108
|
this.logger.log('Shutting down plugin');
|
|
109
|
+
|
|
110
|
+
// Cleanup all sensors
|
|
111
|
+
this.motionSensors.clear();
|
|
112
|
+
this.lightControls.clear();
|
|
113
|
+
this.cameras.clear();
|
|
45
114
|
}
|
|
46
115
|
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { ClassifierDetectorSensor, LightControl, MotionSensor } from '@camera.ui/sdk';
|
|
2
|
+
|
|
3
|
+
import type { CameraDevice, ClassifierResult, Detection, JsonSchema, ModelSpec, VideoFrameData } from '@camera.ui/sdk';
|
|
4
|
+
|
|
5
|
+
// ============ MOTION SENSOR (External Events) ============
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Example Motion Sensor
|
|
9
|
+
*
|
|
10
|
+
* Use this for external motion sources:
|
|
11
|
+
* - ONVIF camera events
|
|
12
|
+
* - SMTP notifications
|
|
13
|
+
* - Webhook triggers
|
|
14
|
+
* - API polling
|
|
15
|
+
*
|
|
16
|
+
* For frame-based detection, extend MotionDetectorSensor instead.
|
|
17
|
+
*/
|
|
18
|
+
export class ExampleMotionSensor extends MotionSensor {
|
|
19
|
+
constructor(name: string) {
|
|
20
|
+
super(name);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Trigger motion from external event
|
|
25
|
+
*/
|
|
26
|
+
trigger(detections: Detection[] = []): void {
|
|
27
|
+
this.detected = true;
|
|
28
|
+
this.detections = detections;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Clear motion state
|
|
33
|
+
*/
|
|
34
|
+
reset(): void {
|
|
35
|
+
this.detected = false;
|
|
36
|
+
this.detections = [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============ LIGHT CONTROL ============
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Example Light Control
|
|
44
|
+
*
|
|
45
|
+
* Bidirectional control sensor - consumers can read and write state.
|
|
46
|
+
* Implements setOn/setBrightness to handle state changes.
|
|
47
|
+
*/
|
|
48
|
+
export class ExampleLightControl extends LightControl {
|
|
49
|
+
private cameraDevice: CameraDevice;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Storage schema for per-sensor configuration
|
|
53
|
+
* These settings are persisted and shown in the UI.
|
|
54
|
+
*/
|
|
55
|
+
schema: JsonSchema[] = [
|
|
56
|
+
{
|
|
57
|
+
type: 'number',
|
|
58
|
+
key: 'defaultBrightness',
|
|
59
|
+
title: 'Default Brightness',
|
|
60
|
+
description: 'Default brightness level (0-100)',
|
|
61
|
+
defaultValue: 100,
|
|
62
|
+
minimum: 0,
|
|
63
|
+
maximum: 100,
|
|
64
|
+
store: true,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: 'boolean',
|
|
68
|
+
key: 'autoOff',
|
|
69
|
+
title: 'Auto-Off',
|
|
70
|
+
description: 'Automatically turn off after timeout',
|
|
71
|
+
defaultValue: false,
|
|
72
|
+
store: true,
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
constructor(camera: CameraDevice, name = 'Light') {
|
|
77
|
+
super(name);
|
|
78
|
+
this.cameraDevice = camera;
|
|
79
|
+
|
|
80
|
+
// Initialize state
|
|
81
|
+
this.on = false;
|
|
82
|
+
this.brightness = 100;
|
|
83
|
+
|
|
84
|
+
// Log state changes
|
|
85
|
+
this.onPropertyChanged.subscribe(({ property, value }) => {
|
|
86
|
+
this.cameraDevice.logger.debug(`${this.name}: ${property} = ${value}`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Called when consumer sets 'on' property
|
|
92
|
+
*/
|
|
93
|
+
async setOn(value: boolean): Promise<void> {
|
|
94
|
+
this.cameraDevice.logger.log(`Light turned ${value ? 'ON' : 'OFF'}`);
|
|
95
|
+
this.on = value;
|
|
96
|
+
|
|
97
|
+
// Apply default brightness when turning on
|
|
98
|
+
if (value && this.storage) {
|
|
99
|
+
const defaultBrightness = this.storage.values.defaultBrightness ?? 100;
|
|
100
|
+
this.brightness = defaultBrightness;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Called when consumer sets 'brightness' property
|
|
106
|
+
*/
|
|
107
|
+
async setBrightness(value: number): Promise<void> {
|
|
108
|
+
this.cameraDevice.logger.log(`Light brightness: ${value}%`);
|
|
109
|
+
this.brightness = value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ============ CLASSIFIER (Multi-Provider Example) ============
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Example Classifier Sensor
|
|
117
|
+
*
|
|
118
|
+
* Multi-provider sensor: Multiple classifiers can be registered per camera.
|
|
119
|
+
* Example use cases:
|
|
120
|
+
* - Bird species classifier (triggers on 'bird' from object detection)
|
|
121
|
+
* - Dog breed classifier (triggers on 'dog')
|
|
122
|
+
* - Plant species classifier
|
|
123
|
+
*
|
|
124
|
+
* The DetectionCoordinator calls detectClassifications() when triggerLabels are detected.
|
|
125
|
+
*/
|
|
126
|
+
export class ExampleClassifier extends ClassifierDetectorSensor {
|
|
127
|
+
private cameraDevice: CameraDevice;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Schema for classifier configuration
|
|
131
|
+
*/
|
|
132
|
+
schema: JsonSchema[] = [
|
|
133
|
+
{
|
|
134
|
+
type: 'number',
|
|
135
|
+
key: 'confidenceThreshold',
|
|
136
|
+
title: 'Confidence Threshold',
|
|
137
|
+
description: 'Minimum confidence for classifications (0-1)',
|
|
138
|
+
defaultValue: 0.5,
|
|
139
|
+
minimum: 0.1,
|
|
140
|
+
maximum: 1.0,
|
|
141
|
+
step: 0.05,
|
|
142
|
+
store: true,
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
constructor(camera: CameraDevice, name = 'Classifier') {
|
|
147
|
+
super(name);
|
|
148
|
+
this.cameraDevice = camera;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Model specification
|
|
153
|
+
*
|
|
154
|
+
* - input: Frame size and format expected by the model
|
|
155
|
+
* - outputLabels: Labels this classifier can output
|
|
156
|
+
* - triggerLabels: Object labels that trigger classification
|
|
157
|
+
*/
|
|
158
|
+
get modelSpec(): ModelSpec {
|
|
159
|
+
return {
|
|
160
|
+
input: {
|
|
161
|
+
width: 224,
|
|
162
|
+
height: 224,
|
|
163
|
+
format: 'rgb',
|
|
164
|
+
},
|
|
165
|
+
// Trigger when object detection finds these labels
|
|
166
|
+
triggerLabels: ['animal'],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Classify objects in a frame
|
|
172
|
+
*
|
|
173
|
+
* Called by DetectionCoordinator when triggerLabels are detected.
|
|
174
|
+
* The frame is pre-scaled to modelSpec.input dimensions.
|
|
175
|
+
*/
|
|
176
|
+
async detectClassifications(frame: VideoFrameData, _triggerRegions?: Detection[]): Promise<ClassifierResult> {
|
|
177
|
+
const threshold = this.storage?.values.confidenceThreshold ?? 0.5;
|
|
178
|
+
|
|
179
|
+
// TODO: Implement your classification model here
|
|
180
|
+
// Example: Load TensorFlow model and run inference
|
|
181
|
+
//
|
|
182
|
+
// const predictions = await this.model.classify(frame.data);
|
|
183
|
+
// return {
|
|
184
|
+
// detected: predictions.length > 0,
|
|
185
|
+
// detections: predictions.map(p => ({
|
|
186
|
+
// label: p.label,
|
|
187
|
+
// confidence: p.score,
|
|
188
|
+
// box: triggerRegions?.[0]?.box ?? { x: 0, y: 0, width: 1, height: 1 },
|
|
189
|
+
// })),
|
|
190
|
+
// };
|
|
191
|
+
|
|
192
|
+
this.cameraDevice.logger.debug(`Classifying frame ${frame.width}x${frame.height}, threshold: ${threshold}`);
|
|
193
|
+
|
|
194
|
+
// Return empty result (placeholder)
|
|
195
|
+
return {
|
|
196
|
+
detected: false,
|
|
197
|
+
detections: [],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Cleanup when sensor is destroyed
|
|
203
|
+
*/
|
|
204
|
+
async destroy(): Promise<void> {
|
|
205
|
+
// Release model resources if needed
|
|
206
|
+
}
|
|
207
|
+
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
All notable changes to this project will be documented in this file.
|
|
2
|
-
|
|
3
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
4
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
|
-
|
|
6
|
-
## [X.X.X] - ???
|
|
7
|
-
|
|
8
|
-
- Initial Release
|
package/CONTRIBUTING.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Contributing
|
package/scripts/chmod.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { execSync } from 'node:child_process';
|
|
2
|
-
import { platform } from 'node:os';
|
|
3
|
-
import { dirname, resolve } from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
|
|
6
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
-
const __dirname = dirname(__filename);
|
|
8
|
-
|
|
9
|
-
const isWindows = platform() === 'win32';
|
|
10
|
-
|
|
11
|
-
function chmod() {
|
|
12
|
-
const scriptPath = resolve(__dirname, '../dist/index.js');
|
|
13
|
-
const arg = isWindows ? 'echo "Skipping chmod command on Windows"' : `chmod +x ${scriptPath}`;
|
|
14
|
-
execSync(arg, { stdio: 'inherit' });
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
chmod();
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import jsLint from '@eslint/js';
|
|
2
|
-
import stylistic from '@stylistic/eslint-plugin';
|
|
3
|
-
import globals from 'globals';
|
|
4
|
-
|
|
5
|
-
export default [
|
|
6
|
-
{
|
|
7
|
-
files: ['**/*.{js,mjs,cjs,ts,mts}'],
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
ignores: ['**/dist/**', '**/node_modules/**', '**/public/**', '**/build/**', '**/bundle/**', '**/test/**', '**/wasm/**', '**/example/**'],
|
|
11
|
-
},
|
|
12
|
-
jsLint.configs.recommended,
|
|
13
|
-
stylistic.configs['disable-legacy'],
|
|
14
|
-
stylistic.configs.customize({
|
|
15
|
-
indent: 2,
|
|
16
|
-
quotes: 'single',
|
|
17
|
-
semi: true,
|
|
18
|
-
commaDangle: 'always-multiline',
|
|
19
|
-
jsx: false,
|
|
20
|
-
arrowParens: true,
|
|
21
|
-
braceStyle: '1tbs',
|
|
22
|
-
blockSpacing: true,
|
|
23
|
-
quoteProps: 'as-needed',
|
|
24
|
-
}),
|
|
25
|
-
{
|
|
26
|
-
languageOptions: {
|
|
27
|
-
globals: { ...globals.node },
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
rules: {
|
|
31
|
-
'@stylistic/generator-star-spacing': ['error', { before: true, after: false }],
|
|
32
|
-
|
|
33
|
-
// Stylistic specific rules
|
|
34
|
-
'@stylistic/max-len': ['error', { code: 170, tabWidth: 2 }],
|
|
35
|
-
'@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
|
|
36
|
-
'@stylistic/operator-linebreak': 'off',
|
|
37
|
-
'@stylistic/comma-dangle': [
|
|
38
|
-
'error',
|
|
39
|
-
{
|
|
40
|
-
arrays: 'always-multiline',
|
|
41
|
-
objects: 'always-multiline',
|
|
42
|
-
imports: 'always-multiline',
|
|
43
|
-
exports: 'only-multiline',
|
|
44
|
-
functions: 'always-multiline',
|
|
45
|
-
enums: 'always-multiline',
|
|
46
|
-
generics: 'always-multiline',
|
|
47
|
-
tuples: 'always-multiline',
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
|
|
51
|
-
semi: [1, 'always'],
|
|
52
|
-
// quotes: ['error', 'single'],
|
|
53
|
-
'comma-dangle': ['error', 'only-multiline'],
|
|
54
|
-
'no-multiple-empty-lines': ['warn', { max: 1, maxEOF: 0 }],
|
|
55
|
-
'eol-last': ['error', 'always'],
|
|
56
|
-
'space-before-function-paren': ['error', { named: 'never' }],
|
|
57
|
-
|
|
58
|
-
'no-unused-vars': 'off',
|
|
59
|
-
'no-case-declarations': 'off',
|
|
60
|
-
'no-async-promise-executor': 'off',
|
|
61
|
-
'no-control-regex': 'off',
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
];
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export default class SamplePlugin {
|
|
2
|
-
constructor(logger, api) {
|
|
3
|
-
this.logger = logger;
|
|
4
|
-
this.api = api;
|
|
5
|
-
|
|
6
|
-
this.camera = new Map();
|
|
7
|
-
|
|
8
|
-
this.api.on('finishLaunching', this.start.bind(this));
|
|
9
|
-
this.api.on('shutdown', this.stop.bind(this));
|
|
10
|
-
|
|
11
|
-
this.api.deviceManager.on('cameraSelected', (cameraDevice) => {
|
|
12
|
-
this.logger.log('Camera selected:', cameraDevice.name);
|
|
13
|
-
|
|
14
|
-
if (!this.cameras.has(cameraDevice.id)) {
|
|
15
|
-
this.cameras.set(cameraDevice.id, cameraDevice);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
this.api.deviceManager.on('cameraDeselected', (cameraId) => {
|
|
20
|
-
const cameraDevice = this.cameras.get(cameraId);
|
|
21
|
-
if (cameraDevice) {
|
|
22
|
-
this.logger.log('Camera deselected:', cameraDevice.name);
|
|
23
|
-
this.cameras.delete(cameraId);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async configureCameras() {}
|
|
29
|
-
|
|
30
|
-
async getCapabilities() {
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
start() {
|
|
35
|
-
this.logger.log('Finished launching plugin');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
stop() {
|
|
39
|
-
this.logger.log('Shutting down plugin');
|
|
40
|
-
}
|
|
41
|
-
}
|