Plugin Framework Upgrades

plugin-touch-ups
Moe 2024-09-25 16:40:35 -07:00
parent 01db3ac7a9
commit db9895a236
10 changed files with 195 additions and 69 deletions

View File

@ -3151,12 +3151,30 @@ module.exports = function(s,config,lang){
}
]
},
{
hidden: true,
"id": "detectorsSelected",
"name": "detail=detectors_selected",
"field": lang["Detectors Selected"],
"description": lang.fieldTextDetectorsSelected,
"default": "all",
"attribute": "multiple",
"fieldType": "select",
"form-group-class": "h_casc_input h_casc_1",
"possible": [
{
"name": `${lang.All} (${lang.Default})`,
"value": "all"
}
]
},
{
"name": "detail=detector_object_ignore_not_move",
"field": lang["Ignore Non-Moving"],
"default": "0",
"fieldType": "select",
"selector": "h_obj_ignore_move",
"form-group-class": "h_casc_input h_casc_1",
"possible": [
{
"name": lang.No,
@ -3183,6 +3201,7 @@ module.exports = function(s,config,lang){
"description": lang["fieldTextDetectorSendFramesObject"],
"default": "1",
"fieldType": "select",
"form-group-class": "h_casc_input h_casc_1",
"possible": [
{
"name": lang.No,
@ -3222,6 +3241,7 @@ module.exports = function(s,config,lang){
"default": "1",
"example": "",
"fieldType": "select",
"form-group-class": "h_casc_input h_casc_1",
"possible": [
{
"name": lang.No,
@ -3242,6 +3262,7 @@ module.exports = function(s,config,lang){
"example": "",
"selector": "h_det_mot_fir",
"fieldType": "select",
"form-group-class": "h_casc_input h_casc_1",
"possible": [
{
"name": lang.No,
@ -3290,7 +3311,6 @@ module.exports = function(s,config,lang){
]
},
{
isAdvanced: true,
hidden: true,
"name": lang['Event-Based Recording'],
"input-mapping": "detector_sip_buffer",

View File

@ -544,6 +544,7 @@
"Time-lapse Tool": "Time-lapse Tool",
"total": "total",
"MB": "MB",
"All": "All",
"Calendar": "Calendar",
"Leave blank for random.": "Leave blank for random.",
"Currently viewing": "Currently viewing",
@ -697,6 +698,7 @@
"Minutes": "Minutes",
"Custom": "Custom",
"Detector": "Detector",
"Detectors Selected": "Detectors Selected",
"Audio Detector": "Audio Detector",
"Audio Detection": "Audio Detection",
"Minimum dB": "Minimum dB",
@ -1218,6 +1220,7 @@
"Preview": "Preview",
"Websocket Connected": "Websocket Connected",
"Websocket Disconnected": "Websocket Disconnected",
"Disconnected": "Disconnected",
"Videos Merge": "Videos Merge",
"Channel ID": "Channel ID",
"Recipient ID": "Recipient ID",
@ -1588,6 +1591,7 @@
"MQTT Client": "MQTT Client",
"Buffer Time from Event": "Buffer Time from Event",
"detected": "detected",
"fieldTextDetectorsSelected": "Select which detectors to send frames to.",
"fieldTextEventFilters": "Enable to have all Events honor your Event Filter rules.",
"fieldTextBufferTimeFromEvent": "The amount of seconds to record before the trigger happened. If this is consistently inaccurate you will need to look at the <a target='_blank' href='https://hub.shinobi.video/articles/view/DmWIID78VtvEfnf'>optimization guide</a> or force encoding on the server.",
"fieldTextMode": "This is the primary task of the monitor.",
@ -1932,6 +1936,8 @@
"HowToConnectDes1": "<b>This feature is available to Mobile License subscribers.</b> To get an API Key please login to your <a href='https: //licenses.shinobi.video/login' target='_blank'>Shinobi<b>Shop</b></a> account and create a key associated to <b>any active Subscription ID</b>. <a href='https://hub.shinobi.video/articles/view/3Yhivc6djTtuBPE' target='_blank'>Learn More.</a>",
"HowToConnectDes2": "If you would like to get access to a private (dedicated) P2P server please create an account at the <a href='https: //licenses.shinobi.video/login' target='_blank'>Shinobi<b>Shop</b></a> and contact us via the Live Chat widget",
"User": "User",
"Save Unknown Faces": "Save Unknown Faces",
"saveUnknownFacesFieldText": "Save Unknown faces to the Face Manager. Manual sorting may still be required.",
"Current Version": "Current Version",
"Default is Global value": "Default is Global value",
"rejectUnauth": "Ignore server certificate"

View File

@ -40,7 +40,7 @@ module.exports = (s,config,lang) => {
const monitorId = options.mid || options.id
const groupKey = options.ke
//if(!frameBuffer || imageSaveEventLock[groupKey + monitorId])return;
if(!frameBuffer || frameBuffer.length === 0 || imageSaveEventLock[groupKey + monitorId]) return;
if(!frameBuffer || frameBuffer.length === 0 || imageSaveEventLock[groupKey + monitorId]) return;
const eventTime = options.time
const objectsFound = options.matrices
const monitorConfig = Object.assign({id: monitorId},s.group[groupKey].rawMonitorConfigurations[monitorId])
@ -678,17 +678,37 @@ module.exports = (s,config,lang) => {
const activeMonitor = s.group[groupKey].activeMonitors[monitorId]
const theEmitter = activeMonitor.secondaryDetectorOutput
if(!activeMonitor.sendingFromSecondaryDetectorOuput){
s.debugLog('start sending object frames',groupKey,monitorId)
theEmitter.on('data',activeMonitor.secondaryDetectorOuputContentWriter = (data) => {
const monitorConfig = s.group[groupKey].rawMonitorConfigurations[monitorId]
const monitorDetails = monitorConfig.details;
let chosenDetector = monitorDetails.detectors_selected;
if(chosenDetector instanceof Array)chosenDetector = chosenDetector.join(',');
let sendToDetector = (data) => {
s.ocvTx({
f : 'frame',
mon : s.group[groupKey].rawMonitorConfigurations[monitorId].details,
mon : monitorDetails,
ke : groupKey,
id : monitorId,
time : s.formattedTime(),
frame : data
})
})
}
if(chosenDetector && !(chosenDetector.includes('all'))){
const pluginsGettingIt = chosenDetector.split(',').map(item => item.trim()).filter(item => !!item);
sendToDetector = (data) => {
for(pluginName of pluginsGettingIt){
s.sendToDetector(pluginName, {
f : 'frame',
mon : monitorDetails,
ke : groupKey,
id : monitorId,
time : s.formattedTime(),
frame : data
})
}
}
}
s.debugLog('start sending object frames',groupKey,monitorId)
theEmitter.on('data', activeMonitor.secondaryDetectorOuputContentWriter = sendToDetector)
}
clearTimeout(activeMonitor.sendingFromSecondaryDetectorOuput)
activeMonitor.sendingFromSecondaryDetectorOuput = setTimeout(() => {

View File

@ -87,6 +87,8 @@ module.exports = function(s,config){
createExtension(`onSubscriptionCheck`)
createExtension(`onDataPortMessage`)
createExtension(`onHttpRequestUpgrade`,null,true)
createExtension(`onPluginConnected`)
createExtension(`onPluginDisconnected`)
/////// CRON ////////
createExtension(`onCronGroupProcessed`)
createExtension(`onCronGroupProcessedAwaited`)

View File

@ -1186,7 +1186,6 @@ module.exports = (s,config,lang) => {
})
}
if(e.details.detector === '1'){
s.ocvTx({f:'init_monitor',id:monitorId,ke:groupKey})
//frames from motion detect
if(e.details.detector_pam === '1'){
// activeMonitor.spawn.stdio[3].pipe(activeMonitor.p2p).pipe(activeMonitor.pamDiff)

View File

@ -43,18 +43,7 @@ module.exports = function(s,config,lang,app,io){
s.detectorPluginArray = []
s.isAtleatOneDetectorPluginConnected = false
s.addDetectorPlugin = function(name,d){
if(config.useOldPluginConnectionMethod === true){
s.ocv = {
started: s.timeObject(),
id: d.id,
plug: d.plug,
notice: d.notice,
isClientPlugin: d.isClientPlugin,
isHostPlugin: d.isHostPlugin,
connectionType: d.connectionType
}
}
s.connectedDetectorPlugins[d.plug] = {
const newDetector = {
started: s.timeObject(),
id: d.id,
plug: d.plug,
@ -62,15 +51,22 @@ module.exports = function(s,config,lang,app,io){
isClientPlugin: d.isClientPlugin,
isHostPlugin: d.isHostPlugin,
connectionType: d.connectionType
};
if(config.useOldPluginConnectionMethod === true){
s.ocv = newDetector
}
s.connectedDetectorPlugins[d.plug] = newDetector
s.resetDetectorPluginArray()
s.runExtensionsForArray('onPluginConnected', null, [d.plug, newDetector])
}
s.removeDetectorPlugin = function(name){
const theDetector = Object.assign({}, s.connectedDetectorPlugins[name])
if(config.oldPluginConnectionMethod === true && s.ocv && s.ocv.plug === name){
delete(s.ocv)
}
delete(s.connectedDetectorPlugins[name])
s.resetDetectorPluginArray(name)
s.runExtensionsForArray('onPluginDisconnected', null, [name, theDetector])
}
s.resetDetectorPluginArray = function(){
pluginArray = []
@ -164,6 +160,10 @@ module.exports = function(s,config,lang,app,io){
})
}
}
s.sendToDetector = function(pluginName, data){
const detector = s.connectedPlugins[pluginName];
if(detector)detector.tx(data);
}
s.sendDetectorInfoToClient = function(data,txFunction){
s.detectorPluginArray.forEach(function(name){
var detectorData = Object.assign(data,{
@ -363,7 +363,33 @@ module.exports = function(s,config,lang,app,io){
}
}
}
function onMonitorUpdate(monitorConfig){
// console.log('Sending Monitor Info to Plugin', monitorConfig.mid)
s.sendToAllDetectors({ f: 'monitorUpdate', monitorConfig });
}
function sendCopyOfAllMonitorConfigs(){
const groupKeys = Object.keys(s.group);
for(groupKey of groupKeys){
const monitorConfigs = Object.values(s.group[groupKey].rawMonitorConfigurations);
for(monitorConfig of monitorConfigs){
onMonitorUpdate(monitorConfig)
}
}
}
/**
* API : Get List of Connected Plugins
*/
app.get(config.webPaths.apiPrefix+':auth/plugins/list', async (req,res) => {
s.auth(req.params, async (resp) => {
s.closeJsonResponse(res,{
ok: true,
plugins: s.connectedDetectorPlugins
})
},res,req)
})
s.onSocketAuthentication(onSocketAuthentication)
s.onWebSocketDisconnection(onWebSocketDisconnection)
s.onWebSocketConnection(onWebSocketConnection)
s.onMonitorStart(onMonitorUpdate)
s.onPluginConnected(sendCopyOfAllMonitorConfigs)
}

View File

@ -56,8 +56,11 @@ module.exports = function(__dirname, config){
if(!config.hostPort){config.hostPort = 8082}
if(config.systemLog === undefined){config.systemLog = true}
if(config.connectionType === undefined)config.connectionType = 'websocket'
const imageBuffers = {}
s = {
group: {},
monitors: {},
monitorInfo: {},
dir: {},
isWin: (process.platform === 'win32'),
s: (json) => {
@ -217,16 +220,26 @@ module.exports = function(__dirname, config){
cn.emit('init',{ok:true,plug:config.plug,notice:config.notice,type:config.type})
}
break;
case'init_monitor':
retryConnection = 0
if(s.group[d.ke] && s.group[d.ke][d.id]){
s.group[d.ke][d.id].numberOfTriggers = 0
delete(s.group[d.ke][d.id].cords)
delete(s.group[d.ke][d.id].buffer)
s.onCameraInitExtensions.forEach((extender) => {
extender(d,cn,tx)
})
case'monitorUpdate':
var monitorConfig = d.monitorConfig;
var groupKey = monitorConfig.ke;
var monitorId = monitorConfig.mid;
var monitorDetails = monitorConfig.details;
var monitorKey = `${groupKey}${monitorId}`
if(!s.monitors[monitorKey])s.monitors[monitorKey] = Object.assign({}, monitorConfig);
var isObjectDetectionSeparate = monitorDetails.detector_use_detect_object === '1'
var width = parseFloat(isObjectDetectionSeparate && monitorDetails.detector_scale_x_object ? monitorDetails.detector_scale_x_object : monitorDetails.detector_scale_x)
var height = parseFloat(isObjectDetectionSeparate && monitorDetails.detector_scale_y_object ? monitorDetails.detector_scale_y_object : monitorDetails.detector_scale_y)
s.monitorInfo[monitorKey] = {
isObjectDetectionSeparate,
width,
height,
}
delete(imageBuffers[monitorKey])
for(extender of s.onCameraInitExtensions){
extender(monitorConfig, cn, tx)
}
// console.log(monitorId, 'registered', s.monitorInfo[monitorKey])
break;
case'frameFromRam':
if(!s.group[d.ke]){
@ -239,29 +252,22 @@ module.exports = function(__dirname, config){
break;
case'frame':
try{
if(!s.group[d.ke]){
s.group[d.ke]={}
}
if(!s.group[d.ke][d.id]){
s.group[d.ke][d.id] = {}
s.onCameraInitExtensions.forEach((extender) => {
extender(d,cn,tx)
})
}
if(!s.group[d.ke][d.id].buffer){
s.group[d.ke][d.id].buffer = [d.frame];
const monitorKey = `${d.id}${d.ke}`;
imageBuffers[monitorKey]
if(!imageBuffers[monitorKey]){
imageBuffers[monitorKey] = [d.frame];
}else{
s.group[d.ke][d.id].buffer.push(d.frame)
imageBuffers[monitorKey].push(d.frame)
}
if(d.frame[d.frame.length-2] === 0xFF && d.frame[d.frame.length-1] === 0xD9){
var buffer = Buffer.concat(s.group[d.ke][d.id].buffer);
var buffer = Buffer.concat(imageBuffers[monitorKey]);
processImage(buffer,d,tx)
s.group[d.ke][d.id].buffer = null
imageBuffers[monitorKey] = null
}
}catch(err){
if(err){
s.systemLog(err)
delete(s.group[d.ke][d.id].buffer)
delete(imageBuffers[monitorKey])
}
}
break;

View File

@ -32,8 +32,11 @@ module.exports = function(__dirname, config){
if(!config.hostPort){config.hostPort = 8082}
if(config.systemLog === undefined){config.systemLog = true}
if(config.connectionType === undefined)config.connectionType = 'websocket'
const imageBuffers = {}
s = {
group: {},
monitors: {},
monitorInfo: {},
dir: {},
isWin: (process.platform === 'win32'),
s: (json) => {
@ -192,16 +195,26 @@ module.exports = function(__dirname, config){
cn.emit('init',{ok:true,plug:config.plug,notice:config.notice,type:config.type})
}
break;
case'init_monitor':
retryConnection = 0
if(s.group[d.ke] && s.group[d.ke][d.id]){
s.group[d.ke][d.id].numberOfTriggers = 0
delete(s.group[d.ke][d.id].cords)
delete(s.group[d.ke][d.id].buffer)
s.onCameraInitExtensions.forEach((extender) => {
extender(d,cn,tx)
})
case'monitorUpdate':
var monitorConfig = d.monitorConfig;
var groupKey = monitorConfig.ke;
var monitorId = monitorConfig.mid;
var monitorDetails = monitorConfig.details;
var monitorKey = `${groupKey}${monitorId}`
if(!s.monitors[monitorKey])s.monitors[monitorKey] = Object.assign({}, monitorConfig);
var isObjectDetectionSeparate = monitorDetails.detector_use_detect_object === '1'
var width = parseFloat(isObjectDetectionSeparate && monitorDetails.detector_scale_x_object ? monitorDetails.detector_scale_x_object : monitorDetails.detector_scale_x)
var height = parseFloat(isObjectDetectionSeparate && monitorDetails.detector_scale_y_object ? monitorDetails.detector_scale_y_object : monitorDetails.detector_scale_y)
s.monitorInfo[monitorKey] = {
isObjectDetectionSeparate,
width,
height,
}
delete(imageBuffers[monitorKey])
for(extender of s.onCameraInitExtensions){
extender(monitorConfig, cn, tx)
}
// console.log(monitorId, 'registered', s.monitorInfo[monitorKey])
break;
case'frameFromRam':
if(!s.group[d.ke]){
@ -214,29 +227,22 @@ module.exports = function(__dirname, config){
break;
case'frame':
try{
if(!s.group[d.ke]){
s.group[d.ke]={}
}
if(!s.group[d.ke][d.id]){
s.group[d.ke][d.id] = {}
s.onCameraInitExtensions.forEach((extender) => {
extender(d,cn,tx)
})
}
if(!s.group[d.ke][d.id].buffer){
s.group[d.ke][d.id].buffer = [d.frame];
const monitorKey = `${d.id}${d.ke}`;
imageBuffers[monitorKey]
if(!imageBuffers[monitorKey]){
imageBuffers[monitorKey] = [d.frame];
}else{
s.group[d.ke][d.id].buffer.push(d.frame)
imageBuffers[monitorKey].push(d.frame)
}
if(d.frame[d.frame.length-2] === 0xFF && d.frame[d.frame.length-1] === 0xD9){
var buffer = Buffer.concat(s.group[d.ke][d.id].buffer);
var buffer = Buffer.concat(imageBuffers[monitorKey]);
processImage(buffer,d,tx)
s.group[d.ke][d.id].buffer = null
imageBuffers[monitorKey] = null
}
}catch(err){
if(err){
s.systemLog(err)
delete(s.group[d.ke][d.id].buffer)
delete(imageBuffers[monitorKey])
}
}
break;

View File

@ -15,6 +15,7 @@ var monSectionPresets = $('#monSectionPresets')
var copySettingsSelector = $('#copy_settings')
var monitorPresetsSelection = $('#monitorPresetsSelection')
var monitorPresetsNameField = $('#monitorPresetsName')
var detectorsSelected = $('#detectorsSelected')
var monitorsList = monitorEditorWindow.find('.monitors_list')
var editorForm = monitorEditorWindow.find('form')
var tagsInput = monitorEditorWindow.find('[name="tags"]')
@ -566,7 +567,37 @@ function drawInputMapSelectorHtml(options,parent){
</div>`
parent.prepend(html)
}
function importIntoMonitorEditor(options){
function getPluginsList(monitorConfig){
return new Promise((resolve) => {
const chosenDetectors = safeJsonParse(monitorConfig.details).detectors_selected || [];
$.get(getApiPrefix() + '/plugins/list',function(data){
var plugins = data.plugins || {};
var pluginNames = Object.keys(plugins)
var disconnectedPlugins = chosenDetectors.filter(item => !pluginNames.includes(item));
var html = createOptionHtml({
value: 'all',
label: `${lang.All} (${lang.Default})`
});
$.each(plugins, function(name, pluginInfo){
html += createOptionHtml({
value: name,
label: name,
selected: chosenDetectors.includes(name),
})
});
$.each(disconnectedPlugins, function(n, name){
html += createOptionHtml({
value: name,
label: `${name} (${lang.Disconnected})`,
selected: true,
})
});
detectorsSelected.html(html)
resolve(plugins)
})
})
}
async function importIntoMonitorEditor(options){
var monitorConfig = options.values || options
var monitorId = monitorConfig.mid
var monitorDetails = safeJsonParse(monitorConfig.details);
@ -686,6 +717,9 @@ function importIntoMonitorEditor(options){
}
}
});
//
await getPluginsList(monitorConfig)
//
copySettingsSelector.val('0').change()
var tmp = '';
$.each(loadedMonitors,function(n,monitor){
@ -1319,9 +1353,11 @@ editorForm.find('[name="type"]').change(function(e){
break;
case'detector_plugged':
addDetectorPlugin(d.plug,d)
if(monitorEditorSelectedMonitor)getPluginsList(monitorEditorSelectedMonitor);
break;
case'detector_unplugged':
removeDetectorPlugin(d.plug)
if(monitorEditorSelectedMonitor)getPluginsList(monitorEditorSelectedMonitor);
break;
}
})
@ -1335,6 +1371,7 @@ editorForm.find('[name="type"]').change(function(e){
drawMonitorListToSelector(monitorsList.find('optgroup'),false,'host')
monitorsList.val(theSelected)
checkToOpenSideMenu()
if(monitorEditorSelectedMonitor)getPluginsList(monitorEditorSelectedMonitor)
}
addOnTabAway('monitorSettings', function(){
if(isSideBarMenuCollapsed()){

View File

@ -147,7 +147,11 @@ $(document).ready(function(){
$.post(superApiPrefix + $user.sessionKey + '/plugins/download',{
downloadUrl: url,
packageRoot: packageRoot,
},callback)
},function(data){
setTimeout(function(){
callback(data)
},3000)
})
}
})
}