Skip to content

Commit

Permalink
v1.1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
seydx committed Jan 25, 2022
1 parent fdbd03a commit ac1e646
Show file tree
Hide file tree
Showing 19 changed files with 241 additions and 153 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# Changelog
All notable changes to this project will be documented in this file.

# v1.1.5 - 2022-01-25

## Other Changes
- Improved debug/error logging for recording
- Minor ui improvements

## Bugfixes
- Minor bugfixes

# v1.1.4 - 2022-01-24

## Other Changes
Expand Down
204 changes: 102 additions & 102 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "camera.ui",
"version": "1.1.4",
"version": "1.1.5",
"description": "NVR like user interface for RTSP capable cameras.",
"author": "SeydX (https://github.com/SeydX/camera.ui)",
"scripts": {
Expand Down Expand Up @@ -65,7 +65,7 @@
"eslint": "^8.7.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jest": "^25.7.0",
"eslint-plugin-jest": "^26.0.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-unicorn": "^40.1.0",
"jest": "^27.4.7",
Expand Down
20 changes: 18 additions & 2 deletions src/api/middlewares/user.validation.middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@
import crypto from 'crypto';

import ConfigService from '../../services/config/config.service.js';
import LoggerService from '../../services/logger/logger.service.js';

import * as UserModel from '../components/users/users.model.js';

const { log } = LoggerService;
const validPermissions = ConfigService.interface.permissionLevels;

const loginAttempt = () => {
log.warn(
`Failed login attempt! If you have forgotten your password you can reset to the default of master/master by removing the user in the "database.json" file (${ConfigService.databaseFilePath}) and then restarting camera.ui`,
'Interface',
'interface'
);
};

export const hasAuthValidFields = (req, res, next) => {
let errors = [];

Expand Down Expand Up @@ -69,12 +79,16 @@ export const isPasswordAndUserMatch = async (req, res, next) => {
const user = await UserModel.findByName(req.body.username);

if (!user) {
res.status(403).send({
loginAttempt();

return res.status(403).send({
statusCode: 403,
message: 'Forbidden',
});
} else if (!user?.password) {
res.status(403).send({
loginAttempt();

return res.status(403).send({
statusCode: 403,
message: 'Password missing',
});
Expand All @@ -94,6 +108,8 @@ export const isPasswordAndUserMatch = async (req, res, next) => {

return next();
} else {
loginAttempt();

return res.status(401).send({
statusCode: 401,
message: 'Invalid username or password',
Expand Down
8 changes: 4 additions & 4 deletions src/common/ffmpeg.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const storeFrameFromVideoBuffer = (camera, fileBuffer, outputPath) => {

ffmpeg.stderr.on('data', (data) => {
errors = errors.slice(-5);
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' - '));
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' '));
});

ffmpeg.on('error', (error) => reject(error));
Expand Down Expand Up @@ -202,7 +202,7 @@ export const getAndStoreSnapshot = (

ffmpeg.stderr.on('data', (data) => {
errors = errors.slice(-5);
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' - '));
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' '));
});

let imageBuffer = Buffer.alloc(0);
Expand Down Expand Up @@ -271,7 +271,7 @@ export const storeSnapshotFromVideo = async (camera, recordingPath, fileName) =>

ffmpeg.stderr.on('data', (data) => {
errors = errors.slice(-5);
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' - '));
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' '));
});

ffmpeg.on('error', (error) => reject(error));
Expand Down Expand Up @@ -358,7 +358,7 @@ export const storeVideo = (camera, recordingPath, fileName, recordingTimer) => {

ffmpeg.stderr.on('data', (data) => {
errors = errors.slice(-5);
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' - '));
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' '));
});

ffmpeg.on('error', (error) => reject(error));
Expand Down
2 changes: 1 addition & 1 deletion src/controller/camera/services/stream.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export default class StreamService {

this.streamSession.stderr.on('data', (data) => {
errors = errors.slice(-5);
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' - '));
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' '));
});

this.streamSession.on('exit', (code, signal) => {
Expand Down
2 changes: 1 addition & 1 deletion src/controller/camera/services/videoanalysis.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ export default class VideoAnalysisService {

cp.stderr.on('data', (data) => {
errors = errors.slice(-5);
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' - '));
errors.push(data.toString().replace(/(\r\n|\n|\r)/gm, ' '));
});

cp.on('exit', (code, signal) => {
Expand Down
29 changes: 23 additions & 6 deletions src/controller/camera/utils/camera.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { createServer } from 'net';
import { once } from 'events';
import readline from 'readline';
import { spawn } from 'child_process';

import LoggerService from '../../../services/logger/logger.service.js';
Expand Down Expand Up @@ -264,25 +265,41 @@ export const startFFMPegFragmetedMP4Session = async (
'frag_keyframe+empty_moov+default_base_moof',
'-max_muxing_queue_size',
'1024',
'-vsync',
'cfr',
'tcp://127.0.0.1:' + serverPort,
];

log.debug(`Recording command: ${videoProcessor} ${arguments_.join(' ')}`, cameraName);

const cp = spawn(videoProcessor, arguments_, { env: process.env });

const stderr = readline.createInterface({
input: cp.stderr,
terminal: false,
});

let errors = [];

stderr.on('line', (line) => {
if (/\[(panic|fatal|error)]/.test(line)) {
errors = errors.slice(-5);
errors.push(line);

log.debug(line, cameraName);
} else if (cameraDebug) {
log.debug(line, cameraName);
}
});

cp.on('exit', (code, signal) => {
if (code === 1) {
log.error(`FFmpeg recording process exited with error! (${signal})`, cameraName, 'Homebridge');
errors.unshift(`FFmpeg recording process exited with error! (${signal})`);
log.error(errors.join(' - '), cameraName, 'Homebridge');
} else {
log.debug('FFmpeg recording process exited (expected)', cameraName);
}
});

if (cameraDebug) {
cp.stdout.on('data', (data) => log.debug(data.toString(), cameraName));
cp.stderr.on('data', (data) => log.debug(data.toString(), cameraName));
}
});
};

Expand Down
4 changes: 2 additions & 2 deletions src/controller/motion/motion.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,8 @@ export default class MotionController {
':' +
ConfigService.ui.mqtt.port,
{
username: ConfigService.ui.mqtt.username,
password: ConfigService.ui.mqtt.password,
username: ConfigService.ui.mqtt.username || '',
password: ConfigService.ui.mqtt.password || '',
}
);

Expand Down
11 changes: 11 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export default class Interface extends EventEmitter {
);
}

/**
* The modules are imported dynamically.
* They should only be loaded when the user wants to start camera.ui
*/

// configure server
this.log.debug('Configuring server...');
this.#server = new (await import('./api/index.js')).default(this);
Expand Down Expand Up @@ -82,6 +87,9 @@ export default class Interface extends EventEmitter {
this.#server.listen(this.config.ui.port);
}

/**
* Stops camera.ui and all started servers and controllers
*/
async close() {
await this.database?.interface.write();

Expand All @@ -98,6 +106,9 @@ export default class Interface extends EventEmitter {
this.#server?.close();
}

/**
* Starts camera.ui as "worker" in standalone mode
*/
#startAsWorker() {
let shuttingDown = false;

Expand Down
24 changes: 18 additions & 6 deletions ui/src/components/add-camera.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ v-dialog(v-model="dialog" width="600" scrollable @click:outside="closeDialog")
v-card
v-card-title {{ $t('add_camera') }}
v-divider
v-card-text.tw-p-7.text-default.tw-relative(:class="loading ? 'tw-overflow-hidden' : ''")
.tw-flex.tw-items-center.tw-justify-center.tw-absolute.tw-inset-0.tw-z-10(v-if="loading" style="background: rgba(0, 0, 0, 0.5);")
v-progress-circular(indeterminate color="var(--cui-primary)")
v-form(ref="form" v-model="valid" lazy-validation)
.tw-block

v-card-text.tw-p-7.text-default
v-form.tw-relative(ref="form" v-model="valid" lazy-validation)
.tw-flex.tw-items-center.tw-justify-center.tw-absolute.tw-inset-0.tw-z-10(v-if="loading")
v-progress-circular(indeterminate color="var(--cui-primary)")
.tw-block(v-else)
div
h2.tw-mb-5 {{ $t('general') }}

Expand Down Expand Up @@ -378,6 +378,14 @@ export default {
},
},
watch: {
dialog(visible) {
if (visible) {
setTimeout(() => this.$refs.form.reset(), 100);
}
},
},
mounted() {
this.env = process.env.NODE_ENV;
this.moduleName = this.uiConfig?.env?.moduleName || 'camera.ui';
Expand All @@ -388,6 +396,10 @@ export default {
methods: {
async createCamera() {
if (this.loading) {
return;
}
const valid = this.$refs.form.validate();
if (valid) {
Expand Down
26 changes: 19 additions & 7 deletions ui/src/i18n/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,28 @@ import Vue from 'vue';
import VueI18n from 'vue-i18n';
import Languages from './languages';

const validLanguages = {
de: 'german',
nl: 'dutch',
en: 'english',
/**
* Update this each time a new translation is added
* This is displayed in the interface for selecting the language
*
* Key (e.g. "en") represents the language shortcut also added to the "languages" array
* Value (e.g. "English (en)") represents the Text which is displayed in the interface
*/
const languageList = {
de: 'German (de)',
nl: 'Dutch (nl)',
en: 'English (en)',
};

/**
* Update this array each time a new translation is added
* It must be a valid language shortcut, please see languages.js for available shortcuts
*/
const languages = ['de', 'nl', 'en'];

const supportedLanguages = (lang) => {
switch (lang) {
case 'de':
case 'nl':
case languages.find((l) => l === lang):
return lang;
default:
return 'en';
Expand Down Expand Up @@ -43,4 +55,4 @@ const index18n = new VueI18n({
messages: loadLanguage(lang),
});

export { index18n as i18n, currentLanguage, loadLanguage, supportedLanguages, validLanguages };
export { index18n as i18n, currentLanguage, loadLanguage, supportedLanguages, languageList };
3 changes: 0 additions & 3 deletions ui/src/i18n/locale/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@
"download_failed": "Download fehlgeschlagen",
"drop_files_here": "Datei hierher ziehen",
"drop_widgets_here": "Widgets hier droppen",
"dutch": "Niederländisch",
"dwell_time": "Verweilzeit",
"dwell_time_info": "Verweilzeit bedeutet, dass ein Bewegungsmelder nach dem Auslösen einen Zeitraum von N-Sekunden benötigt, in dem er keine Bewegung erkennt, um wieder in den Standard-Erkennungsmodus zurückzukehren. Dadurch wird verhindert, dass der Sensor mehrere Alarme für dieselbe Bewegung aussendet",
"email": "Email",
Expand All @@ -139,7 +138,6 @@
"encoder_options": "Encoder Optionen",
"encoder_options_info": "Options to be passed to the video encoder.",
"endpoints": "Endpunkte",
"english": "Englisch",
"enter_new_password": "Bitte geben Sie ein neues Passwort ein",
"error": "Fehler",
"exclude": "Ausschließen",
Expand Down Expand Up @@ -168,7 +166,6 @@
"general": "Allgemein",
"general_information": "Allgemeine Informationen",
"general_settings": "Allgemeine Einstellungen",
"german": "Deutsch",
"go_back": "Zurück",
"gray": "Grau",
"green": "Grün",
Expand Down
3 changes: 0 additions & 3 deletions ui/src/i18n/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@
"download_failed": "Download failed",
"drop_files_here": "Drop files here",
"drop_widgets_here": "Drop widgets here",
"dutch": "Dutch",
"dwell_time": "Dwell Time",
"dwell_time_info": "Dwell time means that after a Motion Detector is tripped it will need a N-seconds period in which it detects no motion in order to \"reset\" back to its default detection mode. This prevents the sensor from sending out multiple alerts for the same motion",
"email": "Email",
Expand All @@ -138,7 +137,6 @@
"encoder_options": "Encoder Options",
"encoder_options_info": "Options to be passed to the video encoder.",
"endpoints": "Endpoints",
"english": "English",
"enter_new_password": "Please enter a new password",
"error": "Error",
"exclude": "Exclude",
Expand Down Expand Up @@ -167,7 +165,6 @@
"general": "General",
"general_information": "General Information",
"general_settings": "General Settings",
"german": "German",
"go_back": "Back",
"gray": "Gray",
"green": "Green",
Expand Down
3 changes: 0 additions & 3 deletions ui/src/i18n/locale/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@
"download_failed": "Download mislukt",
"drop_files_here": "Drop files here",
"drop_widgets_here": "Drop widgets here",
"dutch": "Nederlands",
"dwell_time": "Stilstandtijd",
"dwell_time_info": "Stilstandtijd betekent dat nadat een bewegingsdetector is geactiveerd, deze een periode van N seconden nodig heeft waarin geen beweging wordt waargenomen om terug te keren naar de standaard detectiemodus. Dit voorkomt dat de sensor meerdere waarschuwingen afgeeft voor dezelfde beweging",
"email": "Email",
Expand All @@ -138,7 +137,6 @@
"encoder_options": "Encoder Opties",
"encoder_options_info": "Options to be passed to the video encoder.",
"endpoints": "Endpunkte",
"english": "Engels",
"enter_new_password": "Voer een nieuw wachtwoord in",
"error": "Fout",
"exclude": "Exclusief",
Expand Down Expand Up @@ -167,7 +165,6 @@
"general": "Algemeen",
"general_information": "Algemene informatie",
"general_settings": "Algemene Instellingen",
"german": "Duits",
"go_back": "Terug",
"gray": "Grijs",
"green": "Groen",
Expand Down
Loading

0 comments on commit ac1e646

Please sign in to comment.