Fixed enumerateSequences and other methods for reading image and video files.

This commit is contained in:
mmcwilliams 2024-07-31 14:39:21 -04:00
parent 59afb15a10
commit 169940a83e
14 changed files with 224 additions and 56 deletions

View File

@ -33,10 +33,10 @@ class CameraSerialPortMock extends serialport_1.SerialPortMock {
this._mockSend(Commands.CAMERA_IDENTIFIER, 2); this._mockSend(Commands.CAMERA_IDENTIFIER, 2);
break; break;
case Commands.CAMERA: case Commands.CAMERA:
this._mockSend(Commands.CAMERA, 300); this._mockSend(Commands.CAMERA, 250);
break; break;
case Commands.CAMERA_OPEN: case Commands.CAMERA_OPEN:
this._mockSend(Commands.CAMERA_OPEN, 150); this._mockSend(Commands.CAMERA_OPEN, 125);
break; break;
case Commands.CAMERA_CLOSE: case Commands.CAMERA_CLOSE:
this._mockSend(Commands.CAMERA_FORWARD, 3); this._mockSend(Commands.CAMERA_FORWARD, 3);

View File

@ -8,9 +8,15 @@ interface VideoObject {
hash: string; hash: string;
name: string; name: string;
} }
interface ImageObject {
path: string;
hash: string;
name: string;
}
export declare class Files { export declare class Files {
static exists(path: string): Promise<boolean>; static exists(path: string): Promise<boolean>;
static enumerateSequences(path: string): Promise<SequenceObject[]>; static enumerateSequences(path: string): Promise<SequenceObject[]>;
static enumerateVideos(path: string): Promise<VideoObject[]>; static enumerateVideos(path: string): Promise<VideoObject[]>;
static enumerateSequence(path: string): Promise<ImageObject[]>;
} }
export type { SequenceObject, VideoObject }; export type { SequenceObject, VideoObject, ImageObject };

75
dist/files/index.js vendored
View File

@ -1,21 +1,26 @@
"use strict"; "use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.Files = void 0; exports.Files = void 0;
const promises_1 = __importDefault(require("fs/promises")); const promises_1 = require("fs/promises");
const hash_1 = require("../hash"); const hash_1 = require("../hash");
const path_1 = require("path"); const path_1 = require("path");
const fileExtensions = [ const videoExtensions = [
'.mp4', '.mp4',
'.mkv', '.mkv',
'.mov' '.mov'
]; ];
const imageExtensions = [
'.jpg',
'.jpeg',
'.png',
'.tif',
'.tiff',
'.bmp'
];
class Files { class Files {
static async exists(path) { static async exists(path) {
try { try {
await promises_1.default.access(path); await (0, promises_1.access)(path);
return true; return true;
} }
catch { catch {
@ -26,20 +31,23 @@ class Files {
const dirs = []; const dirs = [];
let all; let all;
let stats; let stats;
let dirPath;
path = await (0, promises_1.realpath)(path);
try { try {
all = await promises_1.default.readdir(path); all = await (0, promises_1.readdir)(path);
} }
catch (err) { catch (err) {
throw err; throw err;
} }
for (let elem of all) { for (let elem of all) {
dirPath = (0, path_1.join)(path, elem);
try { try {
stats = await promises_1.default.lstat(elem); stats = await (0, promises_1.lstat)(dirPath);
if (stats.isDirectory()) { if (stats.isDirectory()) {
dirs.push({ dirs.push({
path: elem, path: dirPath,
hash: hash_1.Hashes.stringHash(elem), hash: hash_1.Hashes.stringHash(dirPath),
name: (0, path_1.basename)(elem) name: (0, path_1.basename)(dirPath)
}); });
} }
} }
@ -53,20 +61,23 @@ class Files {
const videos = []; const videos = [];
let all; let all;
let stats; let stats;
let filePath;
path = await (0, promises_1.realpath)(path);
try { try {
all = await promises_1.default.readdir(path); all = await (0, promises_1.readdir)(path);
} }
catch (err) { catch (err) {
throw err; throw err;
} }
for (let elem of all) { for (let elem of all) {
filePath = (0, path_1.join)(path, elem);
try { try {
stats = await promises_1.default.lstat(elem); stats = await (0, promises_1.lstat)(filePath);
if (stats.isFile() && fileExtensions.indexOf((0, path_1.extname)((0, path_1.basename)(elem))) !== -1) { if (stats.isFile() && videoExtensions.indexOf((0, path_1.extname)((0, path_1.basename)(elem).toLowerCase())) !== -1) {
videos.push({ videos.push({
path: elem, path: filePath,
hash: hash_1.Hashes.stringHash(elem), hash: hash_1.Hashes.stringHash(filePath),
name: (0, path_1.basename)(elem) name: (0, path_1.basename)(filePath)
}); });
} }
} }
@ -76,6 +87,36 @@ class Files {
} }
return videos; return videos;
} }
static async enumerateSequence(path) {
const dirs = [];
let all;
let stats;
let filePath;
path = await (0, promises_1.realpath)(path);
try {
all = await (0, promises_1.readdir)(path);
}
catch (err) {
throw err;
}
for (let elem of all) {
filePath = (0, path_1.join)(path, elem);
try {
stats = await (0, promises_1.lstat)(filePath);
if (stats.isFile() && imageExtensions.indexOf((0, path_1.extname)((0, path_1.basename)(elem).toLowerCase())) !== -1) {
dirs.push({
path: filePath,
hash: hash_1.Hashes.stringHash(filePath),
name: (0, path_1.basename)(filePath)
});
}
}
catch (err) {
//
}
}
return dirs;
}
} }
exports.Files = Files; exports.Files = Files;
module.exports = { Files }; module.exports = { Files };

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/files/index.ts"],"names":[],"mappings":";;;;;;AAAA,2DAA6B;AAE7B,kCAAiC;AACjC,+BAAyC;AAczC,MAAM,cAAc,GAAc;IACjC,MAAM;IACN,MAAM;IACN,MAAM;CACN,CAAC;AAEF,MAAa,KAAK;IACV,MAAM,CAAC,KAAK,CAAC,MAAM,CAAE,IAAa;QACxC,IAAI,CAAC;YACJ,MAAM,kBAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACtB,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAE,IAAa;QACpD,MAAM,IAAI,GAAsB,EAAE,CAAC;QACnC,IAAI,GAAc,CAAC;QACnB,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACJ,GAAG,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,GAAG,CAAC;QACX,CAAC;QAED,KAAK,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC;gBACJ,KAAK,GAAG,MAAM,kBAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC1B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACzB,IAAI,CAAC,IAAI,CAAC;wBACT,IAAI,EAAG,IAAI;wBACX,IAAI,EAAG,aAAM,CAAC,UAAU,CAAC,IAAI,CAAC;wBAC9B,IAAI,EAAG,IAAA,eAAQ,EAAC,IAAI,CAAC;qBACrB,CAAC,CAAC;gBACJ,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,EAAE;YACH,CAAC;QACF,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,eAAe,CAAE,IAAa;QACjD,MAAM,MAAM,GAAmB,EAAE,CAAC;QAClC,IAAI,GAAc,CAAC;QACnB,IAAI,KAAa,CAAC;QAElB,IAAI,CAAC;YACJ,GAAG,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,GAAG,CAAC;QACX,CAAC;QAED,KAAK,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC;gBACJ,KAAK,GAAG,MAAM,kBAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC1B,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,cAAc,CAAC,OAAO,CAAC,IAAA,cAAO,EAAC,IAAA,eAAQ,EAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC9E,MAAM,CAAC,IAAI,CAAC;wBACX,IAAI,EAAG,IAAI;wBACX,IAAI,EAAG,aAAM,CAAC,UAAU,CAAC,IAAI,CAAC;wBAC9B,IAAI,EAAG,IAAA,eAAQ,EAAC,IAAI,CAAC;qBACrB,CAAC,CAAC;gBACJ,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,EAAE;YACH,CAAC;QACF,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;CACD;AAlED,sBAkEC;AAGD,MAAM,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/files/index.ts"],"names":[],"mappings":";;;AAAA,0CAA+D;AAE/D,kCAAiC;AACjC,+BAA+C;AAoB/C,MAAM,eAAe,GAAc;IAClC,MAAM;IACN,MAAM;IACN,MAAM;CACN,CAAC;AAEF,MAAM,eAAe,GAAc;IAClC,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;CACN,CAAC;AAEF,MAAa,KAAK;IACV,MAAM,CAAC,KAAK,CAAC,MAAM,CAAE,IAAa;QACxC,IAAI,CAAC;YACJ,MAAM,IAAA,iBAAM,EAAC,IAAI,CAAC,CAAC;YACnB,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAE,IAAa;QACpD,MAAM,IAAI,GAAsB,EAAE,CAAC;QACnC,IAAI,GAAc,CAAC;QACnB,IAAI,KAAa,CAAC;QAClB,IAAI,OAAgB,CAAC;QAErB,IAAI,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,CAAC,CAAC;QAE5B,IAAI,CAAC;YACJ,GAAG,GAAG,MAAM,IAAA,kBAAO,EAAC,IAAI,CAAC,CAAA;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,GAAG,CAAC;QACX,CAAC;QAED,KAAK,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;YACtB,OAAO,GAAG,IAAA,WAAI,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC3B,IAAI,CAAC;gBACJ,KAAK,GAAG,MAAM,IAAA,gBAAK,EAAC,OAAO,CAAC,CAAC;gBAC1B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACzB,IAAI,CAAC,IAAI,CAAC;wBACT,IAAI,EAAG,OAAO;wBACd,IAAI,EAAG,aAAM,CAAC,UAAU,CAAC,OAAO,CAAC;wBACjC,IAAI,EAAG,IAAA,eAAQ,EAAC,OAAO,CAAC;qBACxB,CAAC,CAAC;gBACJ,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,EAAE;YACH,CAAC;QACF,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,eAAe,CAAE,IAAa;QACjD,MAAM,MAAM,GAAmB,EAAE,CAAC;QAClC,IAAI,GAAc,CAAC;QACnB,IAAI,KAAa,CAAC;QAClB,IAAI,QAAiB,CAAC;QAEtB,IAAI,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,CAAC,CAAC;QAE5B,IAAI,CAAC;YACJ,GAAG,GAAG,MAAM,IAAA,kBAAO,EAAC,IAAI,CAAC,CAAA;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,GAAG,CAAC;QACX,CAAC;QAED,KAAK,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;YACtB,QAAQ,GAAG,IAAA,WAAI,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC5B,IAAI,CAAC;gBACJ,KAAK,GAAG,MAAM,IAAA,gBAAK,EAAC,QAAQ,CAAC,CAAC;gBAC3B,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,eAAe,CAAC,OAAO,CAAC,IAAA,cAAO,EAAC,IAAA,eAAQ,EAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC7F,MAAM,CAAC,IAAI,CAAC;wBACX,IAAI,EAAG,QAAQ;wBACf,IAAI,EAAG,aAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;wBAClC,IAAI,EAAG,IAAA,eAAQ,EAAC,QAAQ,CAAC;qBACzB,CAAC,CAAC;gBACJ,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,EAAE;YACH,CAAC;QACF,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAE,IAAa;QACnD,MAAM,IAAI,GAAmB,EAAE,CAAC;QAChC,IAAI,GAAc,CAAC;QACnB,IAAI,KAAa,CAAC;QAClB,IAAI,QAAiB,CAAC;QAEtB,IAAI,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,CAAC,CAAC;QAE5B,IAAI,CAAC;YACJ,GAAG,GAAG,MAAM,IAAA,kBAAO,EAAC,IAAI,CAAC,CAAA;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,GAAG,CAAC;QACX,CAAC;QAED,KAAK,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;YACtB,QAAQ,GAAG,IAAA,WAAI,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC5B,IAAI,CAAC;gBACJ,KAAK,GAAG,MAAM,IAAA,gBAAK,EAAC,QAAQ,CAAC,CAAC;gBAC3B,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,eAAe,CAAC,OAAO,CAAC,IAAA,cAAO,EAAC,IAAA,eAAQ,EAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC7F,IAAI,CAAC,IAAI,CAAC;wBACT,IAAI,EAAG,QAAQ;wBACf,IAAI,EAAG,aAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;wBAClC,IAAI,EAAG,IAAA,eAAQ,EAAC,QAAQ,CAAC;qBACzB,CAAC,CAAC;gBACJ,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,EAAE;YACH,CAAC;QACF,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AA5GD,sBA4GC;AAGD,MAAM,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC"}

4
dist/index.js vendored
View File

@ -192,8 +192,8 @@ async function cameraOpen() {
} }
app.get('/', async (req, res, next) => { app.get('/', async (req, res, next) => {
const sequencesArr = await files_1.Files.enumerateSequences(sequences); const sequencesArr = await files_1.Files.enumerateSequences(sequences);
const videosArr = await files_1.Files.enumerateVideos(videos); //const videosArr : VideoObject[] = await Files.enumerateVideos(videos);
const html = index({ sequences: sequencesArr, videos: videosArr, width, height }); const html = index({ sequences: sequencesArr, width, height });
res.send(html); res.send(html);
}); });
async function main() { async function main() {

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,8 @@
import type { SequenceObject } from '../files';
export declare class Sequence { export declare class Sequence {
private log;
private current; private current;
private images;
private running; private running;
private progress; private progress;
private frames; private frames;
@ -7,5 +10,8 @@ export declare class Sequence {
start(): void; start(): void;
stop(): void; stop(): void;
isRunning(): boolean; isRunning(): boolean;
load(seq: SequenceObject): void;
private enumerate;
unload(): void;
getState(): SequenceState; getState(): SequenceState;
} }

View File

@ -1,9 +1,13 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.Sequence = void 0; exports.Sequence = void 0;
const files_1 = require("../files");
const log_1 = require("../log");
class Sequence { class Sequence {
constructor() { constructor() {
this.current = null; this.current = null;
this.images = [];
this.log = (0, log_1.createLog)('seq');
} }
start() { start() {
this.running = true; this.running = true;
@ -14,6 +18,28 @@ class Sequence {
isRunning() { isRunning() {
return this.running; return this.running;
} }
load(seq) {
this.current = seq;
this.enumerate();
}
async enumerate() {
if (this.current === null) {
this.log.error('Cannot enumerate sequence because it is not set');
return;
}
try {
this.images = await files_1.Files.enumerateSequence(this.current.path);
}
catch (err) {
this.log.error(`Error enumerating images in sequence: ${this.current.name}`, err);
return;
}
this.log.info(`Sequence ${this.current.name} contains ${this.images.length} image${this.images.length === 1 ? '' : 's'}`);
}
unload() {
this.current = null;
this.images = [];
}
getState() { getState() {
return { return {
hash: this.current.hash, hash: this.current.hash,

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sequence/index.ts"],"names":[],"mappings":";;;AAEA,MAAa,QAAQ;IAMpB;QALQ,YAAO,GAAoB,IAAI,CAAC;IAKxB,CAAC;IAEV,KAAK;QACX,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IAEM,IAAI;QACV,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACtB,CAAC;IAEM,SAAS;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAEM,QAAQ;QACd,OAAO;YACN,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,QAAQ,EAAG,IAAI,CAAC,QAAQ;SACxB,CAAA;IACF,CAAC;CACD;AA3BD,4BA2BC"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sequence/index.ts"],"names":[],"mappings":";;;AAAA,oCAAiC;AACjC,gCAAkC;AAIlC,MAAa,QAAQ;IAQpB;QANQ,YAAO,GAAoB,IAAI,CAAC;QAChC,WAAM,GAAmB,EAAE,CAAC;QAMnC,IAAI,CAAC,GAAG,GAAG,IAAA,eAAS,EAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAEM,KAAK;QACX,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IAEM,IAAI;QACV,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACtB,CAAC;IAEM,SAAS;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAEM,IAAI,CAAE,GAAoB;QAChC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QACnB,IAAI,CAAC,SAAS,EAAE,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,SAAS;QACtB,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAG,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;YAClE,OAAO;QACR,CAAC;QAED,IAAI,CAAC;YACJ,IAAI,CAAC,MAAM,GAAG,MAAM,aAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,yCAAyC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;YAClF,OAAO;QACR,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,IAAI,aAAa,IAAI,CAAC,MAAM,CAAC,MAAM,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3H,CAAC;IAEM,MAAM;QACZ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IAClB,CAAC;IAEM,QAAQ;QACd,OAAO;YACN,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,QAAQ,EAAG,IAAI,CAAC,QAAQ;SACxB,CAAA;IACF,CAAC;CACD;AAzDD,4BAyDC"}

View File

@ -47,10 +47,10 @@ class CameraSerialPortMock extends SerialPortMock {
this._mockSend(Commands.CAMERA_IDENTIFIER, 2); this._mockSend(Commands.CAMERA_IDENTIFIER, 2);
break; break;
case Commands.CAMERA : case Commands.CAMERA :
this._mockSend(Commands.CAMERA, 300); this._mockSend(Commands.CAMERA, 250);
break; break;
case Commands.CAMERA_OPEN : case Commands.CAMERA_OPEN :
this._mockSend(Commands.CAMERA_OPEN, 150); this._mockSend(Commands.CAMERA_OPEN, 125);
break; break;
case Commands.CAMERA_CLOSE : case Commands.CAMERA_CLOSE :
this._mockSend(Commands.CAMERA_FORWARD, 3); this._mockSend(Commands.CAMERA_FORWARD, 3);

View File

@ -1,7 +1,7 @@
import fs from 'fs/promises'; import { access, lstat, readdir, realpath } from 'fs/promises';
import type { Stats } from 'fs'; import type { Stats } from 'fs';
import { Hashes } from '../hash'; import { Hashes } from '../hash';
import { basename, extname } from 'path'; import { basename, extname, join } from 'path';
interface SequenceObject { interface SequenceObject {
path : string, path : string,
@ -15,16 +15,31 @@ interface VideoObject {
name : string name : string
} }
const fileExtensions : string[] = [ interface ImageObject {
path : string,
hash : string,
name : string
}
const videoExtensions : string[] = [
'.mp4', '.mp4',
'.mkv', '.mkv',
'.mov' '.mov'
]; ];
const imageExtensions : string[] = [
'.jpg',
'.jpeg',
'.png',
'.tif',
'.tiff',
'.bmp'
];
export class Files { export class Files {
public static async exists (path : string) : Promise<boolean> { public static async exists (path : string) : Promise<boolean> {
try { try {
await fs.access(path); await access(path);
return true; return true;
} catch { } catch {
return false; return false;
@ -35,20 +50,25 @@ export class Files {
const dirs : SequenceObject[] = []; const dirs : SequenceObject[] = [];
let all : string[]; let all : string[];
let stats : Stats; let stats : Stats;
let dirPath : string;
path = await realpath(path);
try { try {
all = await fs.readdir(path) all = await readdir(path)
} catch (err) { } catch (err) {
throw err; throw err;
} }
for (let elem of all) { for (let elem of all) {
dirPath = join(path, elem);
try { try {
stats = await fs.lstat(elem); stats = await lstat(dirPath);
if (stats.isDirectory()) { if (stats.isDirectory()) {
dirs.push({ dirs.push({
path : elem, path : dirPath,
hash : Hashes.stringHash(elem), hash : Hashes.stringHash(dirPath),
name : basename(elem) name : basename(dirPath)
}); });
} }
} catch (err) { } catch (err) {
@ -63,21 +83,25 @@ export class Files {
const videos : VideoObject[] = []; const videos : VideoObject[] = [];
let all : string[]; let all : string[];
let stats : Stats; let stats : Stats;
let filePath : string;
path = await realpath(path);
try { try {
all = await fs.readdir(path) all = await readdir(path)
} catch (err) { } catch (err) {
throw err; throw err;
} }
for (let elem of all) { for (let elem of all) {
filePath = join(path, elem);
try { try {
stats = await fs.lstat(elem); stats = await lstat(filePath);
if (stats.isFile() && fileExtensions.indexOf(extname(basename(elem))) !== -1) { if (stats.isFile() && videoExtensions.indexOf(extname(basename(elem).toLowerCase())) !== -1) {
videos.push({ videos.push({
path : elem, path : filePath,
hash : Hashes.stringHash(elem), hash : Hashes.stringHash(filePath),
name : basename(elem) name : basename(filePath)
}); });
} }
} catch (err) { } catch (err) {
@ -87,7 +111,40 @@ export class Files {
return videos; return videos;
} }
public static async enumerateSequence (path : string) : Promise<ImageObject[]> {
const dirs : ImageObject[] = [];
let all : string[];
let stats : Stats;
let filePath : string;
path = await realpath(path);
try {
all = await readdir(path)
} catch (err) {
throw err;
}
for (let elem of all) {
filePath = join(path, elem);
try {
stats = await lstat(filePath);
if (stats.isFile() && imageExtensions.indexOf(extname(basename(elem).toLowerCase())) !== -1) {
dirs.push({
path : filePath,
hash : Hashes.stringHash(filePath),
name : basename(filePath)
});
}
} catch (err) {
//
}
}
return dirs;
}
} }
export type { SequenceObject, VideoObject }; export type { SequenceObject, VideoObject, ImageObject };
module.exports = { Files }; module.exports = { Files };

View File

@ -150,7 +150,6 @@ function onWssConnection (ws : WebSocketExtended, req : Request) {
ws.ip = ip; ws.ip = ip;
ws.session = uuid(); ws.session = uuid();
ws.on('message', function (data) { onClientMessage(data, ws) }); ws.on('message', function (data) { onClientMessage(data, ws) });
} }
async function onClientMessage (data : any, ws : WebSocket) { async function onClientMessage (data : any, ws : WebSocket) {
@ -183,8 +182,8 @@ async function cameraOpen () {
app.get('/', async (req : Request, res : Response, next : NextFunction) => { app.get('/', async (req : Request, res : Response, next : NextFunction) => {
const sequencesArr : SequenceObject[] = await Files.enumerateSequences(sequences); const sequencesArr : SequenceObject[] = await Files.enumerateSequences(sequences);
const videosArr : VideoObject[] = await Files.enumerateVideos(videos); //const videosArr : VideoObject[] = await Files.enumerateVideos(videos);
const html : string = index({ sequences : sequencesArr, videos : videosArr, width, height }); const html : string = index({ sequences : sequencesArr, width, height });
res.send(html); res.send(html);
}); });
@ -204,8 +203,6 @@ async function main () {
log.info(`filmout_manager WebSocket server running on port ${wsPort}`); log.info(`filmout_manager WebSocket server running on port ${wsPort}`);
ffmpeg.listFormats(); ffmpeg.listFormats();
} }

View File

@ -1,12 +1,19 @@
import type { SequenceObject } from '../files'; import { Files } from '../files';
import { createLog } from '../log'
import type { Logger } from 'winston';
import type { SequenceObject, ImageObject } from '../files';
export class Sequence { export class Sequence {
private log : Logger;
private current : SequenceObject = null; private current : SequenceObject = null;
private images : ImageObject[] = [];
private running : boolean; private running : boolean;
private progress : number; private progress : number;
private frames : number; private frames : number;
constructor () {} constructor () {
this.log = createLog('seq');
}
public start () { public start () {
this.running = true; this.running = true;
@ -20,6 +27,32 @@ export class Sequence {
return this.running; return this.running;
} }
public load (seq : SequenceObject) {
this.current = seq;
this.enumerate();
}
private async enumerate () {
if (this.current === null) {
this.log.error('Cannot enumerate sequence because it is not set');
return;
}
try {
this.images = await Files.enumerateSequence(this.current.path);
} catch (err) {
this.log.error(`Error enumerating images in sequence: ${this.current.name}`, err);
return;
}
this.log.info(`Sequence ${this.current.name} contains ${this.images.length} image${this.images.length === 1 ? '' : 's'}`);
}
public unload () {
this.current = null;
this.images = [];
}
public getState () : SequenceState { public getState () : SequenceState {
return { return {
hash : this.current.hash, hash : this.current.hash,

View File

@ -5,18 +5,20 @@
</head> </head>
<body> <body>
<div>Screen Resolution : {{width}}x{{height}}</div> <div>Screen Resolution : {{width}}x{{height}}</div>
<select name="sequence" id="sequence"> <!--
<option> - Select Image Sequence - </option>
{{#each sequences}}
<option value="{{this.hash}}">{{this.name}}</option>
{{/each}}
</select>
<select name="video" id="video"> <select name="video" id="video">
<option> - Select Video - </option> <option> - Select Video - </option>
{{#each videos}} {{#each videos}}
<option value="{{this.hash}}">{{this.name}}</option> <option value="{{this.hash}}">{{this.name}}</option>
{{/each}} {{/each}}
</select> </select>
-->
<select name="sequence" id="sequence">
<option> - Select Image Sequence - </option>
{{#each sequences}}
<option value="{{this.hash}}">{{this.name}}</option>
{{/each}}
</select>
<button id="open" onclick="client.cameraOpen()">Open Gate</button> <button id="open" onclick="client.cameraOpen()">Open Gate</button>
<script src="/static/js/index.js"></script> <script src="/static/js/index.js"></script>
</body> </body>