Giatso : Critical Fixes and Matrix Support
parent
e7f2b443c1
commit
aa20e613a4
|
@ -12,6 +12,8 @@
|
||||||
"accountAdded": "Account Added",
|
"accountAdded": "Account Added",
|
||||||
"accountAddedText": "Account has been added.",
|
"accountAddedText": "Account has been added.",
|
||||||
"monitorDeleted": "Monitor Deleted",
|
"monitorDeleted": "Monitor Deleted",
|
||||||
|
"accountCreationError": "Account Creation Error",
|
||||||
|
"accountEditError": "Account Edit Error",
|
||||||
"Unmute": "Unmute",
|
"Unmute": "Unmute",
|
||||||
"byUser": "by user",
|
"byUser": "by user",
|
||||||
"accountDeleted": "Account Deleted",
|
"accountDeleted": "Account Deleted",
|
||||||
|
@ -34,7 +36,6 @@
|
||||||
"Active Monitors": "Active Monitors",
|
"Active Monitors": "Active Monitors",
|
||||||
"Storage Use": "Storage Use",
|
"Storage Use": "Storage Use",
|
||||||
"Use Raw Snapshot": "Use Raw Snapshot",
|
"Use Raw Snapshot": "Use Raw Snapshot",
|
||||||
"Account Edited": "Account Edited",
|
|
||||||
"Failed to Edit Account": "Failed to Edit Account",
|
"Failed to Edit Account": "Failed to Edit Account",
|
||||||
"How to Connect": "How to Connect",
|
"How to Connect": "How to Connect",
|
||||||
"Login": "Login",
|
"Login": "Login",
|
||||||
|
@ -559,7 +560,14 @@
|
||||||
"InvalidJSONText": "Please ensure this is a valid JSON string for Shinobi monitor configuration.",
|
"InvalidJSONText": "Please ensure this is a valid JSON string for Shinobi monitor configuration.",
|
||||||
"Passwords don't match": "Passwords don't match",
|
"Passwords don't match": "Passwords don't match",
|
||||||
"Email address is in use.": "Email address is in use.",
|
"Email address is in use.": "Email address is in use.",
|
||||||
|
"Account Created": "Account Created",
|
||||||
|
"Account Edited": "Account Edited",
|
||||||
|
"Compression Info": "Compression Info",
|
||||||
|
"Compression Error": "Compression Error",
|
||||||
"Group Key is in use.": "Group Key is in use.",
|
"Group Key is in use.": "Group Key is in use.",
|
||||||
|
"adminAccountCreatedMsg": "Your account has been created. Access the account at the primary login page (Non-Superuser).",
|
||||||
|
"adminAccountEditedMsg": "Your account has been edited. You may need to restart Shinobi for some changes to take effect.",
|
||||||
|
"createSubAccountsInfo": "If you are looking to share cameras with another account you may create them in the Sub-Account manager of your non-superuser Dashboard.",
|
||||||
"Create Sub-Accounts at /admin": "Create Sub-Accounts at /admin",
|
"Create Sub-Accounts at /admin": "Create Sub-Accounts at /admin",
|
||||||
"No Events found for this video": "No Events found for this video",
|
"No Events found for this video": "No Events found for this video",
|
||||||
"Video and Time Span (Minutes)": "Video and Time Span (Minutes)",
|
"Video and Time Span (Minutes)": "Video and Time Span (Minutes)",
|
||||||
|
@ -1057,6 +1065,7 @@
|
||||||
"Monitor mode is already": "Monitor mode is already",
|
"Monitor mode is already": "Monitor mode is already",
|
||||||
"Monitor or Key does not exist.": "Monitor or Key does not exist.",
|
"Monitor or Key does not exist.": "Monitor or Key does not exist.",
|
||||||
"No Group with this key exists": "No Group with this key exists",
|
"No Group with this key exists": "No Group with this key exists",
|
||||||
|
"Group with this key exists already": "Group with this key exists already",
|
||||||
"Downloaded!": "Downloaded!",
|
"Downloaded!": "Downloaded!",
|
||||||
"Downloading...": "Downloading...",
|
"Downloading...": "Downloading...",
|
||||||
"Loading...": "Loading...",
|
"Loading...": "Loading...",
|
||||||
|
|
|
@ -360,10 +360,19 @@ module.exports = function(s,config,lang){
|
||||||
})
|
})
|
||||||
},7000)
|
},7000)
|
||||||
}
|
}
|
||||||
const getLargestMatrix = (matrices) => {
|
const getLargestMatrix = (matrices,imgWidth,imgHeight) => {
|
||||||
var largestMatrix = {width: 0, height: 0}
|
var largestMatrix = {width: 0, height: 0}
|
||||||
|
const maxWidth = imgWidth * 0.95;
|
||||||
|
const maxHeight = imgHeight * 0.95;
|
||||||
matrices.forEach((matrix) => {
|
matrices.forEach((matrix) => {
|
||||||
if(matrix.width > largestMatrix.width && matrix.height > largestMatrix.height)largestMatrix = matrix
|
const matrixWidth = matrix.width
|
||||||
|
const matrixHeight = matrix.height
|
||||||
|
if(
|
||||||
|
matrixWidth > largestMatrix.width &&
|
||||||
|
matrixHeight > largestMatrix.height &&
|
||||||
|
matrixWidth <= maxWidth &&
|
||||||
|
matrixHeight <= maxHeight
|
||||||
|
)largestMatrix = matrix;
|
||||||
})
|
})
|
||||||
return largestMatrix.x ? largestMatrix : null
|
return largestMatrix.x ? largestMatrix : null
|
||||||
}
|
}
|
||||||
|
@ -377,7 +386,7 @@ module.exports = function(s,config,lang){
|
||||||
const imageCenterX = imgWidth / 2
|
const imageCenterX = imgWidth / 2
|
||||||
const imageCenterY = imgHeight / 2
|
const imageCenterY = imgHeight / 2
|
||||||
const matrices = event.details.matrices || []
|
const matrices = event.details.matrices || []
|
||||||
const largestMatrix = getLargestMatrix(matrices.filter(matrix => trackingTarget.indexOf(matrix.tag) > -1))
|
const largestMatrix = getLargestMatrix(matrices.filter(matrix => trackingTarget.indexOf(matrix.tag) > -1),imgWidth,imgHeight)
|
||||||
if(!largestMatrix)return;
|
if(!largestMatrix)return;
|
||||||
const monitorConfig = s.group[event.ke].rawMonitorConfigurations[event.id]
|
const monitorConfig = s.group[event.ke].rawMonitorConfigurations[event.id]
|
||||||
const invertedVerticalAxis = monitorConfig.details.control_invert_y === '1'
|
const invertedVerticalAxis = monitorConfig.details.control_invert_y === '1'
|
||||||
|
@ -414,6 +423,7 @@ module.exports = function(s,config,lang){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function setHomePositionPreset(e){
|
function setHomePositionPreset(e){
|
||||||
|
const monitorId = e.mid || e.id
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setPresetForCurrentPosition({
|
setPresetForCurrentPosition({
|
||||||
|
|
|
@ -7,7 +7,9 @@ module.exports = (s,config,lang) => {
|
||||||
if(config.doCronAsWorker===undefined)config.doCronAsWorker = true;
|
if(config.doCronAsWorker===undefined)config.doCronAsWorker = true;
|
||||||
const startWorker = () => {
|
const startWorker = () => {
|
||||||
const pathToWorkerScript = __dirname + `/cron/worker.js`
|
const pathToWorkerScript = __dirname + `/cron/worker.js`
|
||||||
const workerProcess = new Worker(pathToWorkerScript)
|
const workerProcess = new Worker(pathToWorkerScript,{
|
||||||
|
workerData: config
|
||||||
|
})
|
||||||
workerProcess.on('message',function(data){
|
workerProcess.on('message',function(data){
|
||||||
if(data.time === 'moment()')data.time = moment();
|
if(data.time === 'moment()')data.time = moment();
|
||||||
switch(data.f){
|
switch(data.f){
|
||||||
|
|
|
@ -3,8 +3,8 @@ const path = require('path');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const exec = require('child_process').exec;
|
const exec = require('child_process').exec;
|
||||||
const spawn = require('child_process').spawn;
|
const spawn = require('child_process').spawn;
|
||||||
const { parentPort, isMainThread } = require('worker_threads');
|
const { parentPort, isMainThread, workerData } = require('worker_threads');
|
||||||
const config = require(process.cwd() + '/conf.json')
|
const config = workerData
|
||||||
process.on('uncaughtException', function (err) {
|
process.on('uncaughtException', function (err) {
|
||||||
errorLog('uncaughtException',err);
|
errorLog('uncaughtException',err);
|
||||||
});
|
});
|
||||||
|
|
|
@ -590,9 +590,6 @@ module.exports = (s,config,lang,app,io) => {
|
||||||
if(autoCompressionEnabled){
|
if(autoCompressionEnabled){
|
||||||
reEncodeVideoAndBinOriginalAddToQueue({
|
reEncodeVideoAndBinOriginalAddToQueue({
|
||||||
video: response.insertQuery,
|
video: response.insertQuery,
|
||||||
targetVideoCodec: 'vp9',
|
|
||||||
targetAudioCodec: 'libopus',
|
|
||||||
targetQuality: '-q:v 1 -q:a 1',
|
|
||||||
targetExtension: 'webm',
|
targetExtension: 'webm',
|
||||||
doSlowly: false,
|
doSlowly: false,
|
||||||
automated: true,
|
automated: true,
|
||||||
|
|
|
@ -73,6 +73,7 @@ module.exports = (s,config,lang) => {
|
||||||
doResolve(response)
|
doResolve(response)
|
||||||
}
|
}
|
||||||
try{
|
try{
|
||||||
|
proc.removeAllListeners()
|
||||||
proc.on('exit',() => {
|
proc.on('exit',() => {
|
||||||
response.msg = 'proc.on.exit'
|
response.msg = 'proc.on.exit'
|
||||||
clearTimeout(killTimer)
|
clearTimeout(killTimer)
|
||||||
|
@ -148,6 +149,7 @@ module.exports = (s,config,lang) => {
|
||||||
clearInterval(activeMonitor.getMonitorCpuUsage);
|
clearInterval(activeMonitor.getMonitorCpuUsage);
|
||||||
clearInterval(activeMonitor.objectCountIntervals);
|
clearInterval(activeMonitor.objectCountIntervals);
|
||||||
clearTimeout(activeMonitor.timeoutToRestart)
|
clearTimeout(activeMonitor.timeoutToRestart)
|
||||||
|
clearTimeout(activeMonitor.fatalErrorTimeout);
|
||||||
delete(activeMonitor.onvifConnection)
|
delete(activeMonitor.onvifConnection)
|
||||||
// if(activeMonitor.onChildNodeExit){
|
// if(activeMonitor.onChildNodeExit){
|
||||||
// activeMonitor.onChildNodeExit()
|
// activeMonitor.onChildNodeExit()
|
||||||
|
@ -709,7 +711,7 @@ module.exports = (s,config,lang) => {
|
||||||
clearTimeout(activeMonitor.trigger_timer)
|
clearTimeout(activeMonitor.trigger_timer)
|
||||||
delete(activeMonitor.trigger_timer)
|
delete(activeMonitor.trigger_timer)
|
||||||
clearInterval(activeMonitor.detector_notrigger_timeout)
|
clearInterval(activeMonitor.detector_notrigger_timeout)
|
||||||
clearTimeout(activeMonitor.err_fatal_timeout);
|
clearTimeout(activeMonitor.fatalErrorTimeout);
|
||||||
activeMonitor.isStarted = false
|
activeMonitor.isStarted = false
|
||||||
activeMonitor.isRecording = false
|
activeMonitor.isRecording = false
|
||||||
s.tx({f:'monitor_stopping',mid:monitorId,ke:groupKey,time:s.formattedTime()},'GRP_'+groupKey);
|
s.tx({f:'monitor_stopping',mid:monitorId,ke:groupKey,time:s.formattedTime()},'GRP_'+groupKey);
|
||||||
|
@ -1119,7 +1121,7 @@ module.exports = (s,config,lang) => {
|
||||||
}
|
}
|
||||||
if(e.details.record_timelapse === '1'){
|
if(e.details.record_timelapse === '1'){
|
||||||
var timelapseRecordingDirectory = s.getTimelapseFrameDirectory(e)
|
var timelapseRecordingDirectory = s.getTimelapseFrameDirectory(e)
|
||||||
activeMonitor.spawn.stdio[7].on('data',function(data){
|
activeMonitor.spawn.stdio[7].on('data', async function(data){
|
||||||
var fileStream = activeMonitor.recordTimelapseWriter
|
var fileStream = activeMonitor.recordTimelapseWriter
|
||||||
if(!fileStream){
|
if(!fileStream){
|
||||||
var currentDate = s.formattedTime(null,'YYYY-MM-DD')
|
var currentDate = s.formattedTime(null,'YYYY-MM-DD')
|
||||||
|
@ -1219,7 +1221,7 @@ module.exports = (s,config,lang) => {
|
||||||
activeMonitor.spawn.stdout.on('data',frameToStreamPrimary)
|
activeMonitor.spawn.stdout.on('data',frameToStreamPrimary)
|
||||||
}
|
}
|
||||||
if(e.details.stream_channels && e.details.stream_channels !== ''){
|
if(e.details.stream_channels && e.details.stream_channels !== ''){
|
||||||
e.details.stream_channels.forEach((fields,number) => {
|
s.parseJSON(e.details.stream_channels,{}).forEach((fields,number) => {
|
||||||
attachStreamChannelHandlers({
|
attachStreamChannelHandlers({
|
||||||
ke: groupKey,
|
ke: groupKey,
|
||||||
mid: monitorId,
|
mid: monitorId,
|
||||||
|
@ -1267,9 +1269,6 @@ module.exports = (s,config,lang) => {
|
||||||
s.debugLog('Queue Automatic Compression',response.insertQuery)
|
s.debugLog('Queue Automatic Compression',response.insertQuery)
|
||||||
reEncodeVideoAndBinOriginalAddToQueue({
|
reEncodeVideoAndBinOriginalAddToQueue({
|
||||||
video: response.insertQuery,
|
video: response.insertQuery,
|
||||||
targetVideoCodec: 'vp9',
|
|
||||||
targetAudioCodec: 'libopus',
|
|
||||||
targetQuality: '-q:v 1 -q:a 1',
|
|
||||||
targetExtension: 'webm',
|
targetExtension: 'webm',
|
||||||
doSlowly: false,
|
doSlowly: false,
|
||||||
automated: true,
|
automated: true,
|
||||||
|
@ -1285,6 +1284,19 @@ module.exports = (s,config,lang) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
async function doFatalErrorCatch(e,d){
|
||||||
|
const groupKey = e.ke
|
||||||
|
const monitorId = e.mid || e.id
|
||||||
|
if(activeMonitor.isStarted === true){
|
||||||
|
const activeMonitor = getActiveMonitor(groupKey,monitorId)
|
||||||
|
activeMonitor.isStarted = false
|
||||||
|
await cameraDestroy(e)
|
||||||
|
activeMonitor.isStarted = true
|
||||||
|
fatalError(e,d)
|
||||||
|
}else{
|
||||||
|
await cameraDestroy(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
function cameraFilterFfmpegLog(e){
|
function cameraFilterFfmpegLog(e){
|
||||||
var checkLog = function(d,x){return d.indexOf(x)>-1}
|
var checkLog = function(d,x){return d.indexOf(x)>-1}
|
||||||
const groupKey = e.ke
|
const groupKey = e.ke
|
||||||
|
@ -1323,30 +1335,18 @@ module.exports = (s,config,lang) => {
|
||||||
break;
|
break;
|
||||||
case checkLog(d,'Connection refused'):
|
case checkLog(d,'Connection refused'):
|
||||||
case checkLog(d,'Connection timed out'):
|
case checkLog(d,'Connection timed out'):
|
||||||
//restart
|
|
||||||
activeMonitor.timeoutToRestart = setTimeout(function(){
|
|
||||||
s.userLog(e,{type:lang['Connection timed out'],msg:lang['Retrying...']});
|
|
||||||
fatalError(e,'Connection timed out');
|
|
||||||
},1000)
|
|
||||||
break;
|
|
||||||
case checkLog(d,'Immediate exit requested'):
|
case checkLog(d,'Immediate exit requested'):
|
||||||
await cameraDestroy(e)
|
|
||||||
activeMonitor.timeoutToRestart = setTimeout(() => {
|
|
||||||
launchMonitorProcesses(e)
|
|
||||||
},15000)
|
|
||||||
break;
|
|
||||||
case checkLog(d,'mjpeg_decode_dc'):
|
case checkLog(d,'mjpeg_decode_dc'):
|
||||||
case checkLog(d,'bad vlc'):
|
case checkLog(d,'bad vlc'):
|
||||||
|
case checkLog(d,'does not contain an image sequence pattern or a pattern is invalid.'):
|
||||||
case checkLog(d,'error dc'):
|
case checkLog(d,'error dc'):
|
||||||
await cameraDestroy(e)
|
// activeMonitor.timeoutToRestart = setTimeout(() => {
|
||||||
activeMonitor.timeoutToRestart = setTimeout(() => {
|
// doFatalErrorCatch(e,d)
|
||||||
launchMonitorProcesses(e)
|
// },15000)
|
||||||
},15000)
|
|
||||||
break;
|
break;
|
||||||
case checkLog(d,'No route to host'):
|
case checkLog(d,'No route to host'):
|
||||||
await cameraDestroy(e)
|
activeMonitor.timeoutToRestart = setTimeout(async () => {
|
||||||
activeMonitor.timeoutToRestart = setTimeout(() => {
|
doFatalErrorCatch(e,d)
|
||||||
launchMonitorProcesses(e)
|
|
||||||
},60000)
|
},60000)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1425,6 +1425,7 @@ module.exports = (s,config,lang) => {
|
||||||
const monitorConfig = theGroup.rawMonitorConfigurations[monitorId]
|
const monitorConfig = theGroup.rawMonitorConfigurations[monitorId]
|
||||||
const doPingTest = e.type !== 'socket' && e.type !== 'dashcam' && e.protocol !== 'udp' && e.type !== 'local' && e.details.skip_ping !== '1';
|
const doPingTest = e.type !== 'socket' && e.type !== 'dashcam' && e.protocol !== 'udp' && e.type !== 'local' && e.details.skip_ping !== '1';
|
||||||
const startMonitorInQueue = theGroup.startMonitorInQueue
|
const startMonitorInQueue = theGroup.startMonitorInQueue
|
||||||
|
if(!activeMonitor.isStarted)return;
|
||||||
// e = monitor object
|
// e = monitor object
|
||||||
clearTimeout(activeMonitor.resetFatalErrorCountTimer)
|
clearTimeout(activeMonitor.resetFatalErrorCountTimer)
|
||||||
activeMonitor.resetFatalErrorCountTimer = setTimeout(()=>{
|
activeMonitor.resetFatalErrorCountTimer = setTimeout(()=>{
|
||||||
|
@ -1601,17 +1602,18 @@ module.exports = (s,config,lang) => {
|
||||||
const groupKey = e.ke
|
const groupKey = e.ke
|
||||||
const monitorId = e.mid || e.id
|
const monitorId = e.mid || e.id
|
||||||
const activeMonitor = getActiveMonitor(groupKey,monitorId)
|
const activeMonitor = getActiveMonitor(groupKey,monitorId)
|
||||||
const monitorDetails = getMonitorConfiguration(groupKey,monitorId).details
|
const monitorConfig = copyMonitorConfiguration(groupKey,monitorId)
|
||||||
|
const monitorDetails = monitorConfig.details
|
||||||
const maxCount = !monitorDetails.fatal_max || isNaN(monitorDetails.fatal_max) ? 0 : parseFloat(monitorDetails.fatal_max);
|
const maxCount = !monitorDetails.fatal_max || isNaN(monitorDetails.fatal_max) ? 0 : parseFloat(monitorDetails.fatal_max);
|
||||||
clearTimeout(activeMonitor.err_fatal_timeout);
|
clearTimeout(activeMonitor.fatalErrorTimeout);
|
||||||
++activeMonitor.errorFatalCount;
|
++activeMonitor.errorFatalCount;
|
||||||
if(activeMonitor.isStarted === true){
|
if(activeMonitor.isStarted === true){
|
||||||
activeMonitor.err_fatal_timeout = setTimeout(function(){
|
activeMonitor.fatalErrorTimeout = setTimeout(function(){
|
||||||
if(maxCount !== 0 && activeMonitor.errorFatalCount > maxCount){
|
if(maxCount !== 0 && activeMonitor.errorFatalCount > maxCount){
|
||||||
s.userLog(e,{type:lang["Fatal Error"],msg:lang.onFatalErrorExit});
|
s.userLog(e,{type:lang["Fatal Error"],msg:lang.onFatalErrorExit});
|
||||||
s.camera('stop',{mid:monitorId,ke:groupKey})
|
s.camera('stop',{mid:monitorId,ke:groupKey})
|
||||||
}else{
|
}else{
|
||||||
launchMonitorProcesses(s.cleanMonitorObject(e))
|
launchMonitorProcesses(monitorConfig)
|
||||||
};
|
};
|
||||||
},5000);
|
},5000);
|
||||||
}else{
|
}else{
|
||||||
|
@ -1623,7 +1625,6 @@ module.exports = (s,config,lang) => {
|
||||||
status: lang.Died,
|
status: lang.Died,
|
||||||
code: 7
|
code: 7
|
||||||
});
|
});
|
||||||
const monitorConfig = copyMonitorConfiguration(groupKey,monitorId)
|
|
||||||
s.onMonitorDiedExtensions.forEach(function(extender){
|
s.onMonitorDiedExtensions.forEach(function(extender){
|
||||||
extender(monitorConfig,e)
|
extender(monitorConfig,e)
|
||||||
})
|
})
|
||||||
|
@ -1753,6 +1754,7 @@ module.exports = (s,config,lang) => {
|
||||||
copyMonitorConfiguration,
|
copyMonitorConfiguration,
|
||||||
getMonitorConfiguration,
|
getMonitorConfiguration,
|
||||||
isGroupBelowMaxMonitorCount,
|
isGroupBelowMaxMonitorCount,
|
||||||
|
setNoEventsDetector,
|
||||||
cameraDestroy: cameraDestroy,
|
cameraDestroy: cameraDestroy,
|
||||||
createSnapshot: createSnapshot,
|
createSnapshot: createSnapshot,
|
||||||
processKill: processKill,
|
processKill: processKill,
|
||||||
|
|
|
@ -24,4 +24,5 @@ module.exports = function(s,config,lang){
|
||||||
require('./notifications/pushover.js')(s,config,lang,getSnapshot)
|
require('./notifications/pushover.js')(s,config,lang,getSnapshot)
|
||||||
require('./notifications/webhook.js')(s,config,lang,getSnapshot)
|
require('./notifications/webhook.js')(s,config,lang,getSnapshot)
|
||||||
require('./notifications/mqtt.js')(s,config,lang,getSnapshot)
|
require('./notifications/mqtt.js')(s,config,lang,getSnapshot)
|
||||||
|
require('./notifications/matrix.js')(s,config,lang,getSnapshot)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,386 @@
|
||||||
|
const fs = require("fs")
|
||||||
|
const fetch = require("node-fetch")
|
||||||
|
module.exports = function(s,config,lang,getSnapshot){
|
||||||
|
const {
|
||||||
|
getEventBasedRecordingUponCompletion,
|
||||||
|
} = require('../events/utils.js')(s,config,lang)
|
||||||
|
//matrix bot
|
||||||
|
if(config.matrixBot === true){
|
||||||
|
const sdk = require("matrix-js-sdk")
|
||||||
|
try{
|
||||||
|
function sendFile(file,groupKey){
|
||||||
|
const client = s.group[groupKey].matrixBot
|
||||||
|
const roomId = s.group[groupKey].matrixBotRoom
|
||||||
|
const {
|
||||||
|
buffer,
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
info,
|
||||||
|
opttype,
|
||||||
|
} = file;
|
||||||
|
client.uploadContent(buffer, {
|
||||||
|
name: name,
|
||||||
|
type: opttype,
|
||||||
|
}).then(function(url) {
|
||||||
|
const content = {
|
||||||
|
msgtype: type || "m.file",
|
||||||
|
body: name,
|
||||||
|
info: info,
|
||||||
|
url: url.content_uri
|
||||||
|
};
|
||||||
|
client.sendMessage(roomId, content);
|
||||||
|
}).catch(err => {
|
||||||
|
s.userLog({
|
||||||
|
ke: groupKey,
|
||||||
|
mid: '$USER'
|
||||||
|
},{
|
||||||
|
type: 'matrix.org Error',
|
||||||
|
msg: err
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const sendMessage = function(data,files,groupKey){
|
||||||
|
if(!data)data = {};
|
||||||
|
const client = s.group[groupKey].matrixBot
|
||||||
|
const roomId = s.group[groupKey].matrixBotRoom
|
||||||
|
if(!client){
|
||||||
|
s.userLog({ke:groupKey,mid:'$USER'},{type:'matrix.org Error'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(client.sendMessage){
|
||||||
|
if(data.text){
|
||||||
|
const sendBody = {
|
||||||
|
"body": data.text,
|
||||||
|
"msgtype": "m.text"
|
||||||
|
}
|
||||||
|
client.sendMessage(roomId, sendBody);
|
||||||
|
}
|
||||||
|
files.forEach((file) => {
|
||||||
|
sendFile(file,groupKey)
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
s.userLog({
|
||||||
|
ke: groupKey,
|
||||||
|
mid: '$USER'
|
||||||
|
},{
|
||||||
|
type: 'matrix.org Error',
|
||||||
|
msg: '!sendMessage'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onEventTriggerBeforeFilterForMatrixBot = function(d,filter){
|
||||||
|
filter.matrixBot = false
|
||||||
|
}
|
||||||
|
const onEventTriggerForMatrixBot = async (d,filter) => {
|
||||||
|
const monitorConfig = s.group[d.ke].rawMonitorConfigurations[d.id]
|
||||||
|
// d = event object
|
||||||
|
const isEnabled = filter.matrixBot || monitorConfig.details.detector_matrixbot === '1' || monitorConfig.details.notify_matrix === '1'
|
||||||
|
if(s.group[d.ke].matrixBot && isEnabled && !s.group[d.ke].activeMonitors[d.id].detector_matrixbot){
|
||||||
|
var detector_matrixbot_timeout
|
||||||
|
if(!monitorConfig.details.detector_matrixbot_timeout||monitorConfig.details.detector_matrixbot_timeout===''){
|
||||||
|
detector_matrixbot_timeout = 1000 * 60 * 10;
|
||||||
|
}else{
|
||||||
|
detector_matrixbot_timeout = parseFloat(monitorConfig.details.detector_matrixbot_timeout) * 1000 * 60;
|
||||||
|
}
|
||||||
|
s.group[d.ke].activeMonitors[d.id].detector_matrixbot = setTimeout(function(){
|
||||||
|
clearTimeout(s.group[d.ke].activeMonitors[d.id].detector_matrixbot);
|
||||||
|
s.group[d.ke].activeMonitors[d.id].detector_matrixbot = null
|
||||||
|
},detector_matrixbot_timeout)
|
||||||
|
await getSnapshot(d,monitorConfig)
|
||||||
|
if(d.screenshotBuffer){
|
||||||
|
const imageEventText = `${lang.Event} ${d.screenshotName} ${d.currentTimestamp}`
|
||||||
|
sendMessage({
|
||||||
|
text: imageEventText,
|
||||||
|
},[
|
||||||
|
{
|
||||||
|
buffer: d.screenshotBuffer,
|
||||||
|
name: d.screenshotName+'.jpg',
|
||||||
|
type: 'm.image',
|
||||||
|
opttype: 'image/jpeg',
|
||||||
|
info: {
|
||||||
|
mimetype: 'image/jpeg',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],d.ke)
|
||||||
|
}
|
||||||
|
if(monitorConfig.details.detector_matrixbot_send_video === '1'){
|
||||||
|
let videoPath = null
|
||||||
|
let videoName = null
|
||||||
|
const eventBasedRecording = await getEventBasedRecordingUponCompletion({
|
||||||
|
ke: d.ke,
|
||||||
|
mid: d.mid
|
||||||
|
})
|
||||||
|
if(eventBasedRecording.filePath){
|
||||||
|
videoPath = eventBasedRecording.filePath
|
||||||
|
videoName = eventBasedRecording.filename
|
||||||
|
}else{
|
||||||
|
const siftedVideoFileFromRam = await s.mergeDetectorBufferChunks(d)
|
||||||
|
videoPath = siftedVideoFileFromRam.filePath
|
||||||
|
videoName = siftedVideoFileFromRam.filename
|
||||||
|
}
|
||||||
|
if(videoPath){
|
||||||
|
sendMessage({},[
|
||||||
|
{
|
||||||
|
buffer: await fs.promises.readFile(videoPath),
|
||||||
|
name: videoName,
|
||||||
|
type: 'm.video',
|
||||||
|
opttype: 'video/mp4',
|
||||||
|
info: {
|
||||||
|
mimetype: 'video/mp4',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],d.ke)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onTwoFactorAuthCodeNotificationForMatrixBot = function(user){
|
||||||
|
// r = user
|
||||||
|
if(r.details.factor_matrixbot === '1'){
|
||||||
|
const eventText = `${user.lang['2-Factor Authentication']} : ${user.lang['Enter this code to proceed']} **${factorAuthKey}** ${user.lang.FactorAuthText1}`
|
||||||
|
sendMessage({
|
||||||
|
text: eventText,
|
||||||
|
},[],d.ke)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const loadMatrixBotForUser = function(user){
|
||||||
|
const userDetails = s.parseJSON(user.details);
|
||||||
|
//matrixbot
|
||||||
|
if(!s.group[user.ke].matrixBot &&
|
||||||
|
config.matrixBot === true &&
|
||||||
|
userDetails.matrixbot === '1' &&
|
||||||
|
userDetails.matrixbot_baseUrl &&
|
||||||
|
userDetails.matrixbot_accessToken &&
|
||||||
|
userDetails.matrixbot_userId &&
|
||||||
|
userDetails.matrixbot_roomId
|
||||||
|
){
|
||||||
|
s.debugLog(`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`)
|
||||||
|
s.debugLog(`Matrix Connecting... ${userDetails.matrixbot_baseUrl}`)
|
||||||
|
const client = sdk.createClient({
|
||||||
|
baseUrl: userDetails.matrixbot_baseUrl,
|
||||||
|
accessToken: userDetails.matrixbot_accessToken,
|
||||||
|
userId: userDetails.matrixbot_userId
|
||||||
|
});
|
||||||
|
s.group[user.ke].matrixBot = client
|
||||||
|
s.group[user.ke].matrixBotRoom = userDetails.matrixbot_roomId
|
||||||
|
client.startClient();
|
||||||
|
client.once('sync', function(state, prevState, res) {
|
||||||
|
s.userLog({
|
||||||
|
ke: user.ke,
|
||||||
|
mid: '$USER'
|
||||||
|
},{
|
||||||
|
type: 'matrix.org',
|
||||||
|
msg: lang.Ready
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const unloadMatrixBotForUser = function(user){
|
||||||
|
if(s.group[user.ke].matrixBot && s.group[user.ke].matrixBot.stopClient){
|
||||||
|
s.group[user.ke].matrixBot.stopClient()
|
||||||
|
delete(s.group[user.ke].matrixBot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onDetectorNoTriggerTimeoutForMatrixBot = function(e){
|
||||||
|
//e = monitor object
|
||||||
|
var currentTime = new Date()
|
||||||
|
if(e.details.detector_notrigger_matrixbot === '1'){
|
||||||
|
var html = '*'+lang.NoMotionEmailText2+' ' + (e.details.detector_notrigger_timeout || 10) + ' '+lang.minutes+'.*\n'
|
||||||
|
html += '**' + lang['Monitor Name'] + '** : '+e.name + '\n'
|
||||||
|
html += '**' + lang['Monitor ID'] + '** : '+e.id + '\n'
|
||||||
|
html += currentTime
|
||||||
|
const eventText = `${lang['"No Motion" Detector']} : ${html}`
|
||||||
|
sendMessage({
|
||||||
|
text: eventText,
|
||||||
|
},[],e.ke)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onMonitorUnexpectedExitForMatrixBot = (monitorConfig) => {
|
||||||
|
const isEnabled = monitorConfig.details.detector_matrixbot === '1' || monitorConfig.details.notify_matrix === '1'
|
||||||
|
if(isEnabled && monitorConfig.details.notify_onUnexpectedExit === '1'){
|
||||||
|
const ffmpegCommand = s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].ffmpeg
|
||||||
|
const description = lang['Process Crashed for Monitor'] + '\n' + ffmpegCommand
|
||||||
|
const currentTime = new Date()
|
||||||
|
const eventText = `${lang['Process Unexpected Exit']} : ${monitorConfig.name} : ${description}`
|
||||||
|
sendMessage({
|
||||||
|
text: eventText,
|
||||||
|
},[],monitorConfig.ke)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.loadGroupAppExtender(loadMatrixBotForUser)
|
||||||
|
s.unloadGroupAppExtender(unloadMatrixBotForUser)
|
||||||
|
s.onTwoFactorAuthCodeNotification(onTwoFactorAuthCodeNotificationForMatrixBot)
|
||||||
|
s.onEventTrigger(onEventTriggerForMatrixBot)
|
||||||
|
s.onEventTriggerBeforeFilter(onEventTriggerBeforeFilterForMatrixBot)
|
||||||
|
s.onDetectorNoTriggerTimeout(onDetectorNoTriggerTimeoutForMatrixBot)
|
||||||
|
s.onMonitorUnexpectedExit(onMonitorUnexpectedExitForMatrixBot)
|
||||||
|
s.definitions["Monitor Settings"].blocks["Notifications"].info[0].info.push(
|
||||||
|
{
|
||||||
|
"name": "detail=notify_matrix",
|
||||||
|
"field": "Matrix.org",
|
||||||
|
"description": "",
|
||||||
|
"default": "0",
|
||||||
|
"example": "",
|
||||||
|
"selector": "h_det_matrixbot",
|
||||||
|
"fieldType": "select",
|
||||||
|
"possible": [
|
||||||
|
{
|
||||||
|
"name": lang.No,
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": lang.Yes,
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
s.definitions["Monitor Settings"].blocks["Notifications"].info.push({
|
||||||
|
"evaluation": "$user.details.use_matrixbot !== '0'",
|
||||||
|
isFormGroupGroup: true,
|
||||||
|
"name": "Matrix.org",
|
||||||
|
"color": "purple",
|
||||||
|
"section-class": "h_det_matrixbot_input h_det_matrixbot_1",
|
||||||
|
"info": [
|
||||||
|
{
|
||||||
|
"name": "detail=detector_matrixbot_send_video",
|
||||||
|
"field": lang["Attach Video Clip"] + ` (${lang['on Event']})`,
|
||||||
|
"description": "",
|
||||||
|
"default": "0",
|
||||||
|
"example": "",
|
||||||
|
"fieldType": "select",
|
||||||
|
"possible": [
|
||||||
|
{
|
||||||
|
"name": lang.No,
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": lang.Yes,
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "detail=detector_matrixbot_timeout",
|
||||||
|
"field": lang['Allow Next Alert'] + ` (${lang['on Event']})`,
|
||||||
|
"description": "",
|
||||||
|
"default": "10",
|
||||||
|
"example": "",
|
||||||
|
"possible": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "detail=detector_notrigger_matrixbot",
|
||||||
|
"field": lang['No Trigger'],
|
||||||
|
"description": lang.noTriggerText,
|
||||||
|
"default": "0",
|
||||||
|
"example": "",
|
||||||
|
"fieldType": "select",
|
||||||
|
"possible": [
|
||||||
|
{
|
||||||
|
"name": lang.No,
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": lang.Yes,
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
s.definitions["Account Settings"].blocks["2-Factor Authentication"].info.push({
|
||||||
|
"name": "detail=factor_matrixbot",
|
||||||
|
"field": 'Matrix.org',
|
||||||
|
"default": "1",
|
||||||
|
"example": "",
|
||||||
|
"fieldType": "select",
|
||||||
|
"possible": [
|
||||||
|
{
|
||||||
|
"name": lang.No,
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": lang.Yes,
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
s.definitions["Account Settings"].blocks["Matrix.org"] = {
|
||||||
|
"evaluation": "$user.details.use_matrixbot !== '0'",
|
||||||
|
"name": "Matrix.org",
|
||||||
|
"color": "purple",
|
||||||
|
"info": [
|
||||||
|
{
|
||||||
|
"name": "detail=matrixbot",
|
||||||
|
"selector":"u_matrixbot_bot",
|
||||||
|
"field": lang.Enabled,
|
||||||
|
"default": "0",
|
||||||
|
"example": "",
|
||||||
|
"fieldType": "select",
|
||||||
|
"possible": [
|
||||||
|
{
|
||||||
|
"name": lang.No,
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": lang.Yes,
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hidden: true,
|
||||||
|
"name": "detail=matrixbot_baseUrl",
|
||||||
|
"placeholder": "",
|
||||||
|
"field": lang["Host"],
|
||||||
|
"form-group-class":"u_matrixbot_bot_input u_matrixbot_bot_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hidden: true,
|
||||||
|
"name": "detail=matrixbot_userId",
|
||||||
|
"placeholder": "xxxxxxxxxxxxxxxxxx",
|
||||||
|
"field": lang["User ID"],
|
||||||
|
"form-group-class":"u_matrixbot_bot_input u_matrixbot_bot_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hidden: true,
|
||||||
|
"name": "detail=matrixbot_roomId",
|
||||||
|
"placeholder": "xxxxxxxxxxxxxxxxxx",
|
||||||
|
"field": lang["Room ID"],
|
||||||
|
"form-group-class":"u_matrixbot_bot_input u_matrixbot_bot_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hidden: true,
|
||||||
|
"name": "detail=matrixbot_accessToken",
|
||||||
|
"fieldType": "password",
|
||||||
|
"placeholder": "XXXXXXXXXXXXXXXXXXXXXXXX",
|
||||||
|
"field": lang.Token,
|
||||||
|
"form-group-class":"u_matrixbot_bot_input u_matrixbot_bot_1",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
s.definitions["Event Filters"].blocks["Action for Selected"].info.push({
|
||||||
|
"name": "actions=matrixBot",
|
||||||
|
"field": 'Matrix.org',
|
||||||
|
"fieldType": "select",
|
||||||
|
"form-group-class": "actions-row",
|
||||||
|
"default": "",
|
||||||
|
"example": "1",
|
||||||
|
"possible": [
|
||||||
|
{
|
||||||
|
"name": lang['Original Choice'],
|
||||||
|
"value": "",
|
||||||
|
"selected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": lang.Yes,
|
||||||
|
"value": "1",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}catch(err){
|
||||||
|
console.log(err)
|
||||||
|
console.log('Could not start Matrix bot, please run "npm install matrix-js-sdk" inside the Shinobi folder.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -323,13 +323,14 @@ module.exports = (s,config,lang) => {
|
||||||
function reEncodeVideoAndBinOriginalAddToQueue(data){
|
function reEncodeVideoAndBinOriginalAddToQueue(data){
|
||||||
const groupKey = data.video.ke
|
const groupKey = data.video.ke
|
||||||
if(!reEncodeVideoAndBinOriginalQueue[groupKey]){
|
if(!reEncodeVideoAndBinOriginalQueue[groupKey]){
|
||||||
reEncodeVideoAndBinOriginalQueue[groupKey] = async.queue(async function(data, callback) {
|
reEncodeVideoAndBinOriginalQueue[groupKey] = async.queue(function(data, callback) {
|
||||||
const response = await reEncodeVideoAndBinOriginal(data)
|
reEncodeVideoAndBinOriginal(data).then((response) => {
|
||||||
callback(response)
|
callback(response)
|
||||||
|
})
|
||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
reEncodeVideoAndBinOriginalQueue[groupKey].push(data,(response) => {
|
reEncodeVideoAndBinOriginalQueue[groupKey].push(data, function(response){
|
||||||
resolve(response)
|
resolve(response)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -348,7 +349,7 @@ module.exports = (s,config,lang) => {
|
||||||
targetAudioCodec = targetAudioCodec || `copy`
|
targetAudioCodec = targetAudioCodec || `copy`
|
||||||
targetQuality = targetQuality || ``
|
targetQuality = targetQuality || ``
|
||||||
onPercentChange = onPercentChange || function(){};
|
onPercentChange = onPercentChange || function(){};
|
||||||
if(!targetVideoCodec || !targetAudioCodec){
|
if(!targetVideoCodec || !targetAudioCodec || !targetQuality){
|
||||||
switch(targetExtension){
|
switch(targetExtension){
|
||||||
case'mp4':
|
case'mp4':
|
||||||
targetVideoCodec = `libx264`
|
targetVideoCodec = `libx264`
|
||||||
|
@ -359,7 +360,7 @@ module.exports = (s,config,lang) => {
|
||||||
case'mkv':
|
case'mkv':
|
||||||
targetVideoCodec = `vp9`
|
targetVideoCodec = `vp9`
|
||||||
targetAudioCodec = `libopus`
|
targetAudioCodec = `libopus`
|
||||||
targetQuality = `-q:v 1 -q:a 1`
|
targetQuality = `-q:v 1 -b:a 96K`
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,6 +428,8 @@ module.exports = (s,config,lang) => {
|
||||||
},'GRP_'+groupKey);
|
},'GRP_'+groupKey);
|
||||||
onPercentChange(percent)
|
onPercentChange(percent)
|
||||||
s.debugLog('stderr',outputFilePath,`${percent}%`)
|
s.debugLog('stderr',outputFilePath,`${percent}%`)
|
||||||
|
}else{
|
||||||
|
s.debugLog('stderr',lang['Compression Info'],text)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
videoBuildProcess.on('exit',async function(data){
|
videoBuildProcess.on('exit',async function(data){
|
||||||
|
|
|
@ -790,8 +790,9 @@ module.exports = function(s,config,lang,app,io){
|
||||||
r[n].status = activeMonitor.monitorStatus
|
r[n].status = activeMonitor.monitorStatus
|
||||||
r[n].code = activeMonitor.monitorStatusCode
|
r[n].code = activeMonitor.monitorStatusCode
|
||||||
r[n].subStreamChannel = activeMonitor.subStreamChannel
|
r[n].subStreamChannel = activeMonitor.subStreamChannel
|
||||||
|
r[n].subStreamActive = !!activeMonitor.subStreamProcess
|
||||||
}
|
}
|
||||||
var buildStreamURL = function(type,channelNumber){
|
function getStreamUrl(type,channelNumber){
|
||||||
var streamURL
|
var streamURL
|
||||||
if(channelNumber){channelNumber = '/'+channelNumber}else{channelNumber=''}
|
if(channelNumber){channelNumber = '/'+channelNumber}else{channelNumber=''}
|
||||||
switch(type){
|
switch(type){
|
||||||
|
@ -810,7 +811,22 @@ module.exports = function(s,config,lang,app,io){
|
||||||
case'mp4':
|
case'mp4':
|
||||||
streamURL='/'+req.params.auth+'/mp4/'+v.ke+'/'+v.mid+channelNumber+'/s.mp4'
|
streamURL='/'+req.params.auth+'/mp4/'+v.ke+'/'+v.mid+channelNumber+'/s.mp4'
|
||||||
break;
|
break;
|
||||||
|
case'useSubstream':
|
||||||
|
try{
|
||||||
|
const monitorConfig = s.group[v.ke].rawMonitorConfigurations[v.mid]
|
||||||
|
const monitorDetails = monitorConfig.details
|
||||||
|
const subStreamChannelNumber = 1 + (monitorDetails.stream_channels || []).length
|
||||||
|
const subStreamType = monitorConfig.details.substream.output.stream_type
|
||||||
|
streamURL = getStreamUrl(subStreamType,subStreamChannelNumber)
|
||||||
|
}catch(err){
|
||||||
|
s.debugLog(err)
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return streamURL
|
||||||
|
}
|
||||||
|
var buildStreamURL = function(type,channelNumber){
|
||||||
|
var streamURL = getStreamUrl(type,channelNumber)
|
||||||
if(streamURL){
|
if(streamURL){
|
||||||
if(!r[n].streamsSortedByType[type]){
|
if(!r[n].streamsSortedByType[type]){
|
||||||
r[n].streamsSortedByType[type]=[]
|
r[n].streamsSortedByType[type]=[]
|
||||||
|
@ -1374,6 +1390,7 @@ module.exports = function(s,config,lang,app,io){
|
||||||
dataPipe.pipe(res)
|
dataPipe.pipe(res)
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.error('onGetVideoData ERROR',err,videoDetails)
|
console.error('onGetVideoData ERROR',err,videoDetails)
|
||||||
|
res.status(404)
|
||||||
res.end(user.lang['File Not Found in Database'])
|
res.end(user.lang['File Not Found in Database'])
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
|
@ -1383,6 +1400,7 @@ module.exports = function(s,config,lang,app,io){
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
res.status(404)
|
||||||
res.end(user.lang['File Not Found in Database'])
|
res.end(user.lang['File Not Found in Database'])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1463,6 +1481,7 @@ module.exports = function(s,config,lang,app,io){
|
||||||
if(videoRow){
|
if(videoRow){
|
||||||
sendVideo(videoRow)
|
sendVideo(videoRow)
|
||||||
}else{
|
}else{
|
||||||
|
res.status(404)
|
||||||
res.end(user.lang['File Not Found in Database'])
|
res.end(user.lang['File Not Found in Database'])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1829,9 +1848,6 @@ module.exports = function(s,config,lang,app,io){
|
||||||
response.ok = true
|
response.ok = true
|
||||||
reEncodeVideoAndBinOriginalAddToQueue({
|
reEncodeVideoAndBinOriginalAddToQueue({
|
||||||
video: r,
|
video: r,
|
||||||
targetVideoCodec: 'vp9',
|
|
||||||
targetAudioCodec: 'libopus',
|
|
||||||
targetQuality: '-q:v 1 -q:a 1',
|
|
||||||
targetExtension: 'webm',
|
targetExtension: 'webm',
|
||||||
doSlowly: false
|
doSlowly: false
|
||||||
}).then((encodeResponse) => {
|
}).then((encodeResponse) => {
|
||||||
|
|
|
@ -292,16 +292,17 @@ module.exports = function(s,config,lang,app){
|
||||||
//found address already exists
|
//found address already exists
|
||||||
endData.msg = lang['Email address is in use.'];
|
endData.msg = lang['Email address is in use.'];
|
||||||
}else{
|
}else{
|
||||||
endData.ok = true
|
|
||||||
//create new
|
//create new
|
||||||
//user id
|
//user id
|
||||||
form.uid = s.gid()
|
form.uid = s.gid()
|
||||||
//check to see if custom key set
|
//check to see if custom key set
|
||||||
if(!form.ke||form.ke===''){
|
if(!form.ke){
|
||||||
form.ke=s.gid()
|
form.ke = s.gid()
|
||||||
}else{
|
}else{
|
||||||
form.ke = form.ke.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '')
|
form.ke = form.ke.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '').trim()
|
||||||
}
|
}
|
||||||
|
if(!s.group[form.ke]){
|
||||||
|
endData.ok = true
|
||||||
//check if "details" is object
|
//check if "details" is object
|
||||||
if(form.details instanceof Object){
|
if(form.details instanceof Object){
|
||||||
form.details = JSON.stringify(form.details)
|
form.details = JSON.stringify(form.details)
|
||||||
|
@ -317,11 +318,14 @@ module.exports = function(s,config,lang,app){
|
||||||
pass: s.createHash(form.pass),
|
pass: s.createHash(form.pass),
|
||||||
details: form.details
|
details: form.details
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
s.tx({f:'add_account',details:form.details,ke:form.ke,uid:form.uid,mail:form.mail},'$')
|
s.tx({f:'add_account',details:form.details,ke:form.ke,uid:form.uid,mail:form.mail},'$')
|
||||||
endData.user = Object.assign(form,{})
|
endData.user = Object.assign(form,{})
|
||||||
//init user
|
//init user
|
||||||
s.loadGroup(form)
|
s.loadGroup(form)
|
||||||
|
}else{
|
||||||
|
endData.msg = lang["Group with this key exists already"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
close()
|
close()
|
||||||
})
|
})
|
||||||
|
|
|
@ -35,9 +35,36 @@ function saveAccountSettings(){
|
||||||
postData.account = $.aN.selected
|
postData.account = $.aN.selected
|
||||||
}
|
}
|
||||||
$.post(superApiPrefix + $user.sessionKey+'/accounts/'+webPath,postData,function(data){
|
$.post(superApiPrefix + $user.sessionKey+'/accounts/'+webPath,postData,function(data){
|
||||||
console.log(data)
|
if(webPath === 'editAdmin'){
|
||||||
if(data.ok === true){
|
if(data.ok === true){
|
||||||
$.aN.e.modal('hide')
|
$.aN.e.modal('hide')
|
||||||
|
new PNotify({
|
||||||
|
title: lang['Account Edited'],
|
||||||
|
text: lang.adminAccountEditedMsg,
|
||||||
|
type: 'success'
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
new PNotify({
|
||||||
|
title: lang.accountEditError,
|
||||||
|
text: lang['Failed to Edit Account'],
|
||||||
|
type: 'error'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(data.ok === true){
|
||||||
|
$.aN.e.modal('hide')
|
||||||
|
new PNotify({
|
||||||
|
title: lang['Account Created'],
|
||||||
|
text: lang.adminAccountCreatedMsg,
|
||||||
|
type: 'success'
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
new PNotify({
|
||||||
|
title: lang.accountCreationError,
|
||||||
|
text: data.msg + '<br>' + lang.createSubAccountsInfo,
|
||||||
|
type: 'error'
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -54,7 +81,11 @@ $.aN.e.on('change','[name="mail"]',function(){
|
||||||
var thisVal = $(this).val()
|
var thisVal = $(this).val()
|
||||||
$.each(loadedUsers,function(n,user){
|
$.each(loadedUsers,function(n,user){
|
||||||
if($.aN.selected && user.ke !== $.aN.selected.ke && thisVal.toLowerCase() === user.mail.toLowerCase()){
|
if($.aN.selected && user.ke !== $.aN.selected.ke && thisVal.toLowerCase() === user.mail.toLowerCase()){
|
||||||
new PNotify({text:lang['Email address is in use.'],type:'error'})
|
new PNotify({
|
||||||
|
title: lang.accountCreationError,
|
||||||
|
text: lang['Email address is in use.'],
|
||||||
|
type: 'error'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -63,7 +94,11 @@ $.aN.e.on('change','[name="ke"]',function(){
|
||||||
var thisVal = $(this).val()
|
var thisVal = $(this).val()
|
||||||
$.each(loadedUsers,function(n,user){
|
$.each(loadedUsers,function(n,user){
|
||||||
if(!$.aN.modeIsEdit() && user.ke === thisVal){
|
if(!$.aN.modeIsEdit() && user.ke === thisVal){
|
||||||
new PNotify({text:lang['Group Key is in use.'] + ' ' + lang['Create Sub-Accounts at /admin'],type:'error'})
|
new PNotify({
|
||||||
|
title: lang.accountCreationError,
|
||||||
|
text: lang['Group Key is in use.'] + ' ' + lang.createSubAccountsInfo,
|
||||||
|
type: 'error'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -54,8 +54,7 @@
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link logout">
|
<a class="nav-link logout">
|
||||||
<i class="fa fa-sign-out-alt"></i>
|
<p><%-lang.Logout%></p>
|
||||||
<p class="d-lg-none d-xl-none"><%-lang.Logout%></p>
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -244,14 +243,12 @@ $.ccio.ws.on('f',function(d){
|
||||||
d.msg = 'Saved Preferences'
|
d.msg = 'Saved Preferences'
|
||||||
break;
|
break;
|
||||||
case'edit_account':
|
case'edit_account':
|
||||||
d.msg='Account Edited';
|
|
||||||
$.each(d.form,function(n,v){
|
$.each(d.form,function(n,v){
|
||||||
$.ccio.accounts[d.ke][n]=v
|
$.ccio.accounts[d.ke][n]=v
|
||||||
})
|
})
|
||||||
$('[ke="'+d.ke+'"] .mail').text(d.form.mail)
|
$('[ke="'+d.ke+'"] .mail').text(d.form.mail)
|
||||||
break;
|
break;
|
||||||
case'add_account':
|
case'add_account':
|
||||||
d.msg='Account Created';
|
|
||||||
$.ccio.tm(0,d,'#accounts-list')
|
$.ccio.tm(0,d,'#accounts-list')
|
||||||
$.aN.selected = $.ccio.accounts[d.ke]
|
$.aN.selected = $.ccio.accounts[d.ke]
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue