diff --git a/definitions/base.js b/definitions/base.js index 4a97692c..48f021cd 100644 --- a/definitions/base.js +++ b/definitions/base.js @@ -3105,6 +3105,31 @@ module.exports = function(s,config,lang){ } ] }, + { + "name": "detail=detector_object_ignore_not_move", + "field": lang["Ignore Non-Moving"], + "default": "0", + "fieldType": "select", + "selector": "h_obj_ignore_move", + "possible": [ + { + "name": lang.No, + "value": "0" + }, + { + "name": lang.Yes, + "value": "1" + } + ] + }, + { + hidden: true, + "name": "detail=detector_object_move_percent", + "field": lang['Minimum Movement'], + "description": lang.inPercent, + "default": "5", + "form-group-class": "h_obj_ignore_move_input h_obj_ignore_move_1" + }, { isAdvanced: true, "name": "detail=detector_send_frames_object", diff --git a/languages/en_CA.json b/languages/en_CA.json index 54047166..8daab026 100644 --- a/languages/en_CA.json +++ b/languages/en_CA.json @@ -196,6 +196,8 @@ "Trigger Camera Groups": "Trigger Camera Groups", "Motion Detection": "Motion Detection", "Object Detection": "Object Detection", + "Minimum Movement": "Minimum Movement", + "inPercent": "In Percent", "Hide Detection on Stream": "Hide Detection on Stream", "JPEG Mode": "JPEG Mode", "Reconnect Stream": "Reconnect Stream", @@ -394,7 +396,7 @@ "Found Devices": "Found Devices", "Switch on for Still Image": "Switch on for Still Image", "Live Stream Toggle": "Live Stream Toggle", - "RegionNote": "When adding points click on the edge of the polygon. Right click a point to remove.", + "RegionNote": "When adding points click on the edge of the polygon. Right click a point to remove it. The dimensions here are based on the Detector Settings of your Monitor. Regions will automatically scale to match Object Detection dimensions.", "Points": "Points", "Minimum Change": "Minimum Change", "Maximum Change": "Maximum Change", @@ -841,6 +843,7 @@ "Delete Motionless Video": "Delete Motionless Video", "Send Frames": "Send Frames Push frames to be analyzed", "Detector Rate": "Detector Rate (FPS)", + "Ignore Non-Moving": "Ignore Non-Moving", "Feed-in Image Width": "Feed-in Image Width", "Feed-in Image Height": "Feed-in Image Height", "Check for Motion First": "Check for Motion First", diff --git a/libs/events/tracking.js b/libs/events/tracking.js new file mode 100644 index 00000000..b0bdff2c --- /dev/null +++ b/libs/events/tracking.js @@ -0,0 +1,157 @@ +const movingThings = require('shinobi-node-moving-things-tracker').Tracker +module.exports = (s,config,lang,app,io) => { + const objectTrackers = {} + const objectTrackerTimeouts = {} + function resetObjectTracker(trackerId,matrices){ + const Tracker = movingThings.newTracker(); + objectTrackers[trackerId] = { + frameCount: 1, + tracker: Tracker, + lastPositions: [] + } + return objectTrackers[trackerId] + } + function setLastTracked(trackerId, trackedMatrices){ + const theTracker = objectTrackers[trackerId] + theTracker.lastPositions = trackedMatrices + } + function getTracked(trackerId){ + const theTracker = objectTrackers[trackerId] + const frameCount = theTracker.frameCount + const trackedObjects = theTracker.tracker.getJSONOfTrackedItems().map((matrix) => { + return { + id: matrix.id, + tag: matrix.name, + x: matrix.x, + y: matrix.y, + width: matrix.w, + height: matrix.h, + confidence: matrix.confidence, + isZombie: matrix.isZombie, + } + }) + return trackedObjects; + } + function trackObject(trackerId,matrices){ + if(!objectTrackers[trackerId]){ + resetObjectTracker(trackerId) + } + const mappedMatrices = matrices.map((matrix) => { + return { + x: matrix.x, + y: matrix.y, + w: matrix.width, + h: matrix.height, + confidence: matrix.confidence, + name: matrix.tag, + } + }); + const theTracker = objectTrackers[trackerId] + theTracker.tracker.updateTrackedItemsWithNewFrame(mappedMatrices, theTracker.frameCount); + ++theTracker.frameCount + } + function trackObjectWithTimeout(trackerId,matrices){ + clearTimeout(objectTrackerTimeouts[trackerId]); + objectTrackerTimeouts[trackerId] = setTimeout(() => { + objectTrackers[trackerId].tracker.reset() + delete(objectTrackers[trackerId]) + delete(objectTrackerTimeouts[trackerId]) + },1000 * 60); + trackObject(trackerId,matrices); + } + function objectHasMoved(matrices, options = {}) { + const { imgHeight = 1, imgWidth = 1, threshold = 0 } = options; + for (let i = 0; i < matrices.length; i++) { + const current = matrices[i]; + if (i < matrices.length - 1) { + const next = matrices[i + 1]; + let totalDistanceMoved = 0; + let numPointsCompared = 0; + if (next) { + // Compare each corner of the matrices + const currentCorners = [ + { x: current.x, y: current.y }, + { x: current.x + current.width, y: current.y }, + { x: current.x, y: current.y + current.height }, + { x: current.x + current.width, y: current.y + current.height } + ]; + const nextCorners = [ + { x: next.x, y: next.y }, + { x: next.x + next.width, y: next.y }, + { x: next.x, y: next.y + next.height }, + { x: next.x + next.width, y: next.y + next.height } + ]; + for (let j = 0; j < currentCorners.length; j++) { + const currentCorner = currentCorners[j]; + const nextCorner = nextCorners[j]; + const dx = nextCorner.x - currentCorner.x; + const dy = nextCorner.y - currentCorner.y; + const distanceMoved = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); + const distanceMovedPercent = + (100 * distanceMoved) / Math.max(current.width, current.height); + totalDistanceMoved += distanceMovedPercent; + numPointsCompared++; + } + const averageDistanceMoved = totalDistanceMoved / numPointsCompared; + if (averageDistanceMoved < threshold) { + continue; + } else { + return true; + } + } + } + } + return false; + } + function groupMatricesById(matrices) { + const matrixById = {}; + const matrixTags = {}; + + matrices.forEach(matrix => { + const id = matrix.id; + const tag = matrix.tag; + if (!matrixById[id]) { + matrixById[id] = []; + } + matrixTags[tag] = id; + matrixById[id].push(matrix); + }); + + return matrixById + } + function getAllMatricesThatMoved(monitorConfig,matrices){ + const monitorDetails = monitorConfig.details + const imgWidth = parseInt(monitorDetails.detector_scale_x_object) || 1280 + const imgHeight = parseInt(monitorDetails.detector_scale_y_object) || 720 + const objectMovePercent = parseInt(monitorDetails.detector_object_move_percent) || 5 + const groupKey = monitorConfig.ke + const monitorId = monitorConfig.mid + const trackerId = `${groupKey}${monitorId}` + const theTracker = objectTrackers[trackerId] + const lastPositions = theTracker.lastPositions + const sortedById = groupMatricesById([...lastPositions,...matrices]) + const movedMatrices = [] + for (const objectId in sortedById) { + const sortedList = sortedById[objectId] + if(sortedList[1]){ + const matrixHasMoved = objectHasMoved(sortedList,{ + threshold: objectMovePercent, + imgWidth: imgWidth, + imgHeight: imgHeight, + }); + if(matrixHasMoved){ + movedMatrices.push(sortedList[1]) + } + } + } + return movedMatrices + } + return { + trackObjectWithTimeout, + resetObjectTracker, + trackObject, + getTracked, + setLastTracked, + getAllMatricesThatMoved, + } +} diff --git a/libs/events/utils.js b/libs/events/utils.js index 679824b5..16994645 100644 --- a/libs/events/utils.js +++ b/libs/events/utils.js @@ -24,6 +24,12 @@ module.exports = (s,config,lang,app,io) => { cutVideoLength, reEncodeVideoAndBinOriginalAddToQueue } = require('../video/utils.js')(s,config,lang) + const { + getTracked, + setLastTracked, + trackObjectWithTimeout, + getAllMatricesThatMoved, + } = require('./tracking.js')(s,config,lang,app,io) const { isEven, fetchTimeout, @@ -97,7 +103,7 @@ module.exports = (s,config,lang,app,io) => { } return newString } - const isAtleastOneMatrixInRegion = function(regions,matrices,callback){ + const isAtleastOneMatrixInRegion = function(regions,matrices){ var regionPolys = [] var matrixPoints = [] regions.forEach(function(region,n){ @@ -108,46 +114,20 @@ module.exports = (s,config,lang,app,io) => { regionPolys[n] = new P(new V(0,0), polyPoints) }) var collisions = [] - var foundInRegion = false matrices.forEach(function(matrix){ var matrixPoly = new B(new V(matrix.x, matrix.y), matrix.width, matrix.height).toPolygon() + var foundInRegion = false regionPolys.forEach(function(region,n){ - var response = new SAT.Response() - var collided = SAT.testPolygonPolygon(matrixPoly, region, response) - if(collided === true){ - collisions.push({ - matrix: matrix, - region: regions[n] - }) - foundInRegion = true + if(!foundInRegion){ + var response = new SAT.Response() + var collided = SAT.testPolygonPolygon(matrixPoly, region, response) + if(collided === true){ + foundInRegion = true + collisions.push(matrix) + } } }) }) - if(callback)callback(foundInRegion,collisions) - return foundInRegion - } - const scanMatricesforCollisions = function(region,matrices){ - var matrixPoints = [] - var collisions = [] - if (!region || !matrices){ - if(callback)callback(collisions) - return collisions - } - var polyPoints = [] - region.points.forEach(function(point){ - polyPoints.push(new V(parseInt(point[0]),parseInt(point[1]))) - }) - var regionPoly = new P(new V(0,0), polyPoints) - matrices.forEach(function(matrix){ - if (matrix){ - var matrixPoly = new B(new V(matrix.x, matrix.y), matrix.width, matrix.height).toPolygon() - var response = new SAT.Response() - var collided = SAT.testPolygonPolygon(matrixPoly, regionPoly, response) - if(collided === true){ - collisions.push(matrix) - } - } - }) return collisions } const getLargestMatrix = (matrices) => { @@ -367,22 +347,6 @@ module.exports = (s,config,lang,app,io) => { } }) } - const checkForObjectsInRegions = (monitorConfig,eventDetails,filter,d,didCountingAlready) => { - const monitorDetails = monitorConfig.details - if(hasMatrices(eventDetails) && monitorDetails.detector_obj_region === '1'){ - var regions = s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].parsedObjects.cords - var isMatrixInRegions = isAtleastOneMatrixInRegion(regions,eventDetails.matrices) - if(isMatrixInRegions){ - s.debugLog('Matrix in region!') - if(filter.countObjects && monitorDetails.detector_obj_count === '1' && monitorDetails.detector_obj_count_in_region === '1' && !didCountingAlready){ - countObjects(d) - } - }else{ - return false - } - } - return true - } const runEventExecutions = async (eventTime,monitorConfig,eventDetails,forceSave,filter,d, triggerEvent) => { const monitorDetails = monitorConfig.details const detailString = JSON.stringify(eventDetails) @@ -674,6 +638,8 @@ module.exports = (s,config,lang,app,io) => { } const triggerEvent = async (d,forceSave) => { var didCountingAlready = false + const groupKey = d.ke + const monitorId = d.mid || d.id const filter = { halt : false, addToMotionCounter : true, @@ -698,7 +664,6 @@ module.exports = (s,config,lang,app,io) => { s.onEventTriggerBeforeFilterExtensions.forEach(function(extender){ extender(d,filter) }) - const eventDetails = d.details const passedEventFilters = checkEventFilters(d,activeMonitor.details,filter) if(!passedEventFilters)return; const eventTime = new Date() @@ -722,20 +687,37 @@ module.exports = (s,config,lang,app,io) => { ){ addToEventCounter(d) } + const eventDetails = d.details if( (filter.countObjects || monitorDetails.detector_obj_count === '1') && monitorDetails.detector_obj_count_in_region !== '1' ){ didCountingAlready = true - countObjects(d) + countObjects(eventDetails.matrices) } if(filter.useLock){ const passedMotionLock = checkMotionLock(d,monitorDetails) if(!passedMotionLock)return } - const passedObjectInRegionCheck = checkForObjectsInRegions(monitorConfig,eventDetails,filter,d,didCountingAlready) - if(!passedObjectInRegionCheck)return - + const thisHasMatrices = hasMatrices(eventDetails) + if(thisHasMatrices && monitorDetails.detector_obj_region === '1'){ + var regions = s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].parsedObjects.cordsForObjectDetection + var matricesInRegions = isAtleastOneMatrixInRegion(regions,eventDetails.matrices) + eventDetails.matrices = matricesInRegions + if(matricesInRegions.length === 0)return; + if(filter.countObjects && monitorDetails.detector_obj_count === '1' && monitorDetails.detector_obj_count_in_region === '1' && !didCountingAlready){ + countObjects(eventDetails.matrices) + } + } + if(thisHasMatrices && monitorDetails.detector_object_ignore_not_move === '1'){ + const trackerId = `${groupKey}${monitorId}` + trackObjectWithTimeout(trackerId,eventDetails.matrices) + const trackedObjects = getTracked(trackerId) + const objectsThatMoved = getAllMatricesThatMoved(monitorConfig,trackedObjects) + setLastTracked(trackerId, trackedObjects) + if(objectsThatMoved.length === 0)return; + eventDetails.matrices = objectsThatMoved + } // d.doObjectDetection = ( eventDetails.reason !== 'object' && @@ -762,10 +744,34 @@ module.exports = (s,config,lang,app,io) => { doObjectDetection: d.doObjectDetection },`DETECTOR_${monitorConfig.ke}${monitorConfig.mid}`); } + function convertRegionPointsToNewDimensions(regions, options) { + const { fromWidth, fromHeight, toWidth, toHeight } = options; + + // Compute the conversion factors for x and y coordinates + const xFactor = toWidth / fromWidth; + const yFactor = toHeight / fromHeight; + + // Clone the regions array and update the points for each region + const newRegions = regions.map(region => { + const { points } = region; + + // Clone the points array and update the coordinates + const newPoints = points.map(([x, y]) => { + const newX = Math.round(x * xFactor); + const newY = Math.round(y * yFactor); + return [newX.toString(), newY.toString()]; + }); + + // Clone the region object and update the points + return { ...region, points: newPoints }; + }); + + return newRegions; + } return { countObjects: countObjects, - isAtleastOneMatrixInRegion: isAtleastOneMatrixInRegion, - scanMatricesforCollisions: scanMatricesforCollisions, + isAtleastOneMatrixInRegion, + convertRegionPointsToNewDimensions, getLargestMatrix: getLargestMatrix, addToEventCounter: addToEventCounter, clearEventCounter: clearEventCounter, @@ -774,7 +780,6 @@ module.exports = (s,config,lang,app,io) => { checkEventFilters: checkEventFilters, checkMotionLock: checkMotionLock, runMultiEventBasedRecord: runMultiEventBasedRecord, - checkForObjectsInRegions: checkForObjectsInRegions, runEventExecutions: runEventExecutions, createEventBasedRecording: createEventBasedRecording, closeEventBasedRecording: closeEventBasedRecording, diff --git a/libs/monitor/utils.js b/libs/monitor/utils.js index b881272a..01ce2840 100644 --- a/libs/monitor/utils.js +++ b/libs/monitor/utils.js @@ -26,6 +26,7 @@ module.exports = (s,config,lang) => { const { addEventDetailsToString, closeEventBasedRecording, + convertRegionPointsToNewDimensions, triggerEvent, } = require('../events/utils.js')(s,config,lang) const { @@ -1703,7 +1704,18 @@ module.exports = (s,config,lang) => { activeMonitor.details = e.details switch(v){ case'cords': - activeMonitor.parsedObjects[v] = Object.values(s.parseJSON(e.details[v])) + const fromWidth = parseInt(e.details.detector_scale_x) || 640 + const fromHeight = parseInt(e.details.detector_scale_y) || 480 + const toWidth = parseInt(e.details.detector_scale_x_object) || 1280 + const toHeight = parseInt(e.details.detector_scale_y_object) || 720 + const theCords = Object.values(s.parseJSON(e.details[v])) || []; + activeMonitor.parsedObjects.cordsForObjectDetection = convertRegionPointsToNewDimensions(theCords,{ + fromWidth, + fromHeight, + toWidth, + toHeight, + }); + activeMonitor.parsedObjects.cords = theCords break; default: activeMonitor.parsedObjects[v] = s.parseJSON(e.details[v]) diff --git a/package-lock.json b/package-lock.json index bf2b493b..5e9c67d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.226.0", "async": "^3.2.2", - "backblaze-b2": "^0.9.12", + "backblaze-b2": "^1.7.0", "body-parser": "^1.19.0", "bson": "^4.6.1", "connection-tester": "^0.2.0", @@ -35,6 +35,7 @@ "mysql": "^2.18.1", "node-abort-controller": "^3.0.1", "node-fetch": "^2.6.7", + "shinobi-node-moving-things-tracker": "^0.9.1", "node-onvif-events": "^2.0.5", "node-ssh": "^12.0.4", "node-telegram-bot-api": "^0.58.0", @@ -1384,6 +1385,17 @@ "node": ">=14.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@discordjs/collection": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", @@ -1694,15 +1706,34 @@ "follow-redirects": "^1.14.4" } }, - "node_modules/backblaze-b2": { - "version": "0.9.12", - "resolved": "https://registry.npmjs.org/backblaze-b2/-/backblaze-b2-0.9.12.tgz", - "integrity": "sha1-b0IHJs7G0L787ohqS7bfUOnAGco=", + "node_modules/axios-retry": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.4.0.tgz", + "integrity": "sha512-VdgaP+gHH4iQYCCNUWF2pcqeciVOdGrBBAYUfTY+wPcO5Ltvp/37MLFNCmJKo7Gj3SHvCSdL8ouI1qLYJN3liA==", "dependencies": { - "node-sha1": "^1.0.1", - "q": "^1.4.1", - "request": "^2.67.0", - "request-progress": "^3.0.0" + "@babel/runtime": "^7.15.4", + "is-retry-allowed": "^2.2.0" + } + }, + "node_modules/backblaze-b2": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/backblaze-b2/-/backblaze-b2-1.7.0.tgz", + "integrity": "sha512-8cVsKkXspuM1UeLI8WWSWw2JHfB7/IvqTtzvwhHqqhNyqcYl8iZ2lFpeuXGKcFA1TiSRlgALXWFJ9eKG6+3ZPg==", + "dependencies": { + "axios": "^0.21.1", + "axios-retry": "^3.1.9", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/backblaze-b2/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" } }, "node_modules/backoff": { @@ -4365,6 +4396,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-shared-array-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", @@ -4735,6 +4777,11 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5035,6 +5082,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/munkres-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/munkres-js/-/munkres-js-1.2.2.tgz", + "integrity": "sha512-0oF4tBDvzx20CYzQ44tTJMfwTBJWXe7cE73Sa/u7Mz7X8jRtyOXOGE9kJBhCfX7Akku3Iy/WHa0sRgqLRq2xaQ==" + }, "node_modules/mv": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", @@ -5174,6 +5226,20 @@ "node": ">= 6.13.0" } }, + "node_modules/node-moving-things-tracker": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/node-moving-things-tracker/-/node-moving-things-tracker-0.9.1.tgz", + "integrity": "sha512-JVa+DbQRgOsOcfIIxhw3kTUfO407RdXnVqNgPvAlhUHu7PWziUah+MuTcaN4rRktBicj/l2scI64a2crBgrzKw==", + "dependencies": { + "lodash.isequal": "^4.5.0", + "minimist": "^1.2.0", + "munkres-js": "^1.2.2", + "uuid": "^3.2.1" + }, + "bin": { + "shinobi-node-moving-things-tracker": "main.js" + } + }, "node_modules/node-onvif-events": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/node-onvif-events/-/node-onvif-events-2.0.5.tgz", @@ -5182,11 +5248,6 @@ "onvif": "git+https://github.com/agsh/onvif.git" } }, - "node_modules/node-sha1": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/node-sha1/-/node-sha1-1.0.1.tgz", - "integrity": "sha1-Mu2EfYUTFXuW3sa3noxHvK63jhw=" - }, "node_modules/node-ssh": { "version": "12.0.4", "resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-12.0.4.tgz", @@ -5839,15 +5900,6 @@ "node": "*" } }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", @@ -5907,6 +5959,11 @@ "node": ">= 0.10" } }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -5976,14 +6033,6 @@ "node": ">= 6" } }, - "node_modules/request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", - "dependencies": { - "throttleit": "^1.0.0" - } - }, "node_modules/request-promise": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", @@ -6946,11 +6995,6 @@ "node": ">=8.0.0" } }, - "node_modules/throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=" - }, "node_modules/tildify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", @@ -8846,6 +8890,14 @@ "tslib": "^2.3.1" } }, + "@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, "@discordjs/collection": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", @@ -9078,15 +9130,33 @@ "follow-redirects": "^1.14.4" } }, - "backblaze-b2": { - "version": "0.9.12", - "resolved": "https://registry.npmjs.org/backblaze-b2/-/backblaze-b2-0.9.12.tgz", - "integrity": "sha1-b0IHJs7G0L787ohqS7bfUOnAGco=", + "axios-retry": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.4.0.tgz", + "integrity": "sha512-VdgaP+gHH4iQYCCNUWF2pcqeciVOdGrBBAYUfTY+wPcO5Ltvp/37MLFNCmJKo7Gj3SHvCSdL8ouI1qLYJN3liA==", "requires": { - "node-sha1": "^1.0.1", - "q": "^1.4.1", - "request": "^2.67.0", - "request-progress": "^3.0.0" + "@babel/runtime": "^7.15.4", + "is-retry-allowed": "^2.2.0" + } + }, + "backblaze-b2": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/backblaze-b2/-/backblaze-b2-1.7.0.tgz", + "integrity": "sha512-8cVsKkXspuM1UeLI8WWSWw2JHfB7/IvqTtzvwhHqqhNyqcYl8iZ2lFpeuXGKcFA1TiSRlgALXWFJ9eKG6+3ZPg==", + "requires": { + "axios": "^0.21.1", + "axios-retry": "^3.1.9", + "lodash": "^4.17.21" + }, + "dependencies": { + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + } } }, "backoff": { @@ -11097,6 +11167,11 @@ "is-unc-path": "^1.0.0" } }, + "is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==" + }, "is-shared-array-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", @@ -11373,6 +11448,11 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -11588,6 +11668,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "munkres-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/munkres-js/-/munkres-js-1.2.2.tgz", + "integrity": "sha512-0oF4tBDvzx20CYzQ44tTJMfwTBJWXe7cE73Sa/u7Mz7X8jRtyOXOGE9kJBhCfX7Akku3Iy/WHa0sRgqLRq2xaQ==" + }, "mv": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", @@ -11697,6 +11782,17 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" }, + "shinobi-node-moving-things-tracker": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/node-moving-things-tracker/-/node-moving-things-tracker-0.9.1.tgz", + "integrity": "sha512-JVa+DbQRgOsOcfIIxhw3kTUfO407RdXnVqNgPvAlhUHu7PWziUah+MuTcaN4rRktBicj/l2scI64a2crBgrzKw==", + "requires": { + "lodash.isequal": "^4.5.0", + "minimist": "^1.2.0", + "munkres-js": "^1.2.2", + "uuid": "^3.2.1" + } + }, "node-onvif-events": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/node-onvif-events/-/node-onvif-events-2.0.5.tgz", @@ -11705,11 +11801,6 @@ "onvif": "git+https://github.com/agsh/onvif.git" } }, - "node-sha1": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/node-sha1/-/node-sha1-1.0.1.tgz", - "integrity": "sha1-Mu2EfYUTFXuW3sa3noxHvK63jhw=" - }, "node-ssh": { "version": "12.0.4", "resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-12.0.4.tgz", @@ -12205,11 +12296,6 @@ "resolved": "https://registry.npmjs.org/pushover-notifications/-/pushover-notifications-1.2.2.tgz", "integrity": "sha512-+3Xcj+kiMiouZK1Ws8yGBTyl8WMPZZdELgl/iVxYqNwDdlaObBHMhEGPRC6Zb9t0BE27ikOoOqSIO1cKZOtsDA==" }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" - }, "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", @@ -12254,6 +12340,11 @@ "resolve": "^1.1.6" } }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -12327,14 +12418,6 @@ } } }, - "request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", - "requires": { - "throttleit": "^1.0.0" - } - }, "request-promise": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", @@ -13071,11 +13154,6 @@ "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.1.tgz", "integrity": "sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw==" }, - "throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=" - }, "tildify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", diff --git a/package.json b/package.json index 9c654a03..1358974a 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.226.0", "async": "^3.2.2", - "backblaze-b2": "^0.9.12", + "backblaze-b2": "^1.7.0", "body-parser": "^1.19.0", "bson": "^4.6.1", "connection-tester": "^0.2.0", @@ -41,6 +41,7 @@ "mysql": "^2.18.1", "node-abort-controller": "^3.0.1", "node-fetch": "^2.6.7", + "shinobi-node-moving-things-tracker": "^0.9.1", "node-onvif-events": "^2.0.5", "node-ssh": "^12.0.4", "node-telegram-bot-api": "^0.58.0", diff --git a/web/assets/js/bs5.monitorsUtils.js b/web/assets/js/bs5.monitorsUtils.js index 706a9e00..8c473a18 100644 --- a/web/assets/js/bs5.monitorsUtils.js +++ b/web/assets/js/bs5.monitorsUtils.js @@ -647,7 +647,7 @@ function drawMatrices(event,options){ var html = '' $.each(event.details.matrices,function(n,matrix){ html += `