scrypted-detection-trainer 0.1.8 → 0.1.9
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/dist/main.nodejs.js +1 -1
- package/dist/main.nodejs.js.map +1 -1
- package/dist/plugin.zip +0 -0
- package/out/main.nodejs.js +69 -16
- package/out/main.nodejs.js.map +1 -1
- package/out/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/main.ts +35 -14
package/out/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED
package/src/main.ts
CHANGED
|
@@ -10,6 +10,8 @@ import sdk, {
|
|
|
10
10
|
ObjectsDetected,
|
|
11
11
|
ObjectDetector,
|
|
12
12
|
} from '@scrypted/sdk';
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import path from 'path';
|
|
13
15
|
|
|
14
16
|
const { systemManager, deviceManager, mediaManager } = sdk;
|
|
15
17
|
|
|
@@ -55,13 +57,16 @@ class DetectionTrainer extends ScryptedDeviceBase implements Settings, HttpReque
|
|
|
55
57
|
private lastCapture = new Map<string, number>();
|
|
56
58
|
// Map<captureId, CaptureRecord>
|
|
57
59
|
private captures = new Map<string, CaptureRecord>();
|
|
58
|
-
// Map<captureId, jpegBuffer>
|
|
59
|
-
private images = new Map<string, Buffer>();
|
|
60
60
|
// Active event listeners
|
|
61
61
|
private listeners: (() => void)[] = [];
|
|
62
|
+
// Directory for storing images on disk
|
|
63
|
+
private imgDir: string;
|
|
62
64
|
|
|
63
65
|
constructor(nativeId?: string) {
|
|
64
66
|
super(nativeId);
|
|
67
|
+
// Use a stable directory inside the plugin's volume
|
|
68
|
+
this.imgDir = path.join(process.env.SCRYPTED_PLUGIN_VOLUME || '/tmp', 'detection-trainer-images');
|
|
69
|
+
try { fs.mkdirSync(this.imgDir, { recursive: true }); } catch {}
|
|
65
70
|
this.loadState();
|
|
66
71
|
this.registerListeners();
|
|
67
72
|
}
|
|
@@ -79,26 +84,43 @@ class DetectionTrainer extends ScryptedDeviceBase implements Settings, HttpReque
|
|
|
79
84
|
} catch (e) {
|
|
80
85
|
this.console.warn('Could not load captures from storage:', e);
|
|
81
86
|
}
|
|
82
|
-
//
|
|
87
|
+
// Clean up any old base64 image entries from previous versions
|
|
83
88
|
for (const [id] of this.captures) {
|
|
84
|
-
|
|
85
|
-
if (raw) this.images.set(id, Buffer.from(raw, 'base64'));
|
|
89
|
+
try { this.storage.removeItem(`img:${id}`); } catch {}
|
|
86
90
|
}
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
private saveCaptures() {
|
|
90
|
-
|
|
94
|
+
try {
|
|
95
|
+
this.storage.setItem('captures', JSON.stringify([...this.captures.values()]));
|
|
96
|
+
} catch (e) {
|
|
97
|
+
this.console.warn('Could not save captures:', e);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private imgPath(id: string): string {
|
|
102
|
+
return path.join(this.imgDir, `${id}.jpg`);
|
|
91
103
|
}
|
|
92
104
|
|
|
93
105
|
private saveImage(id: string, buf: Buffer) {
|
|
94
|
-
|
|
106
|
+
try {
|
|
107
|
+
fs.writeFileSync(this.imgPath(id), buf);
|
|
108
|
+
} catch (e) {
|
|
109
|
+
this.console.warn(`Could not save image ${id}:`, e);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private loadImage(id: string): Buffer | undefined {
|
|
114
|
+
try {
|
|
115
|
+
const p = this.imgPath(id);
|
|
116
|
+
if (fs.existsSync(p)) return fs.readFileSync(p);
|
|
117
|
+
} catch {}
|
|
118
|
+
return undefined;
|
|
95
119
|
}
|
|
96
120
|
|
|
97
121
|
private deleteCapture(id: string) {
|
|
98
|
-
|
|
99
|
-
if (old) this.storage.removeItem(`img:${id}`);
|
|
122
|
+
try { fs.unlinkSync(this.imgPath(id)); } catch {}
|
|
100
123
|
this.captures.delete(id);
|
|
101
|
-
this.images.delete(id);
|
|
102
124
|
this.saveCaptures();
|
|
103
125
|
}
|
|
104
126
|
|
|
@@ -249,7 +271,6 @@ class DetectionTrainer extends ScryptedDeviceBase implements Settings, HttpReque
|
|
|
249
271
|
};
|
|
250
272
|
|
|
251
273
|
this.captures.set(id, record);
|
|
252
|
-
this.images.set(id, jpeg);
|
|
253
274
|
this.saveImage(id, jpeg);
|
|
254
275
|
this.saveCaptures();
|
|
255
276
|
|
|
@@ -264,8 +285,8 @@ class DetectionTrainer extends ScryptedDeviceBase implements Settings, HttpReque
|
|
|
264
285
|
|
|
265
286
|
// Serve image
|
|
266
287
|
if (path.startsWith('/img/')) {
|
|
267
|
-
const id = path.slice(5);
|
|
268
|
-
const img = this.
|
|
288
|
+
const id = path.slice(5).replace(/[^a-zA-Z0-9_\-]/g, ''); // sanitize
|
|
289
|
+
const img = this.loadImage(id);
|
|
269
290
|
if (!img) return response.send('Not found', { code: 404 });
|
|
270
291
|
return response.send(img, { headers: { 'Content-Type': 'image/jpeg', 'Cache-Control': 'max-age=3600' } });
|
|
271
292
|
}
|
|
@@ -339,7 +360,7 @@ class DetectionTrainer extends ScryptedDeviceBase implements Settings, HttpReque
|
|
|
339
360
|
const dataset: { filename: string; content: string; encoding: string }[] = [];
|
|
340
361
|
|
|
341
362
|
for (const record of labeled) {
|
|
342
|
-
const img = this.
|
|
363
|
+
const img = this.loadImage(record.id);
|
|
343
364
|
if (!img) continue;
|
|
344
365
|
|
|
345
366
|
const fname = `${record.id}`;
|