diff --git a/.gitignore b/.gitignore index cf316300..aeb881d2 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ dist generatedLanguageFiles faces unknownFaces +.idea/ diff --git a/Docker/init.sh b/Docker/init.sh index e94374b3..59347938 100644 --- a/Docker/init.sh +++ b/Docker/init.sh @@ -81,7 +81,7 @@ if [ ! -e "/config/conf.json" ]; then node tools/modifyConfiguration.js cpuUsageMarker=CPU subscriptionId=$SUBSCRIPTION_ID thisIsDocker=true pluginKeys="$PLUGIN_KEYS" databaseType="$DB_TYPE" db="$DATABASE_CONFIG" ssl="$SSL_CONFIG" cp /config/conf.json conf.json fi -sudo sed -i -e 's/change_this_to_something_very_random__just_anything_other_than_this/'"$cronKey"'/g' conf.json +sed -i -e 's/change_this_to_something_very_random__just_anything_other_than_this/'"$cronKey"'/g' conf.json echo "=============" diff --git a/Dockerfile b/Dockerfile index 6f4f1072..a94abea0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -88,6 +88,7 @@ COPY . . #RUN rm -rf /home/Shinobi/plugins COPY ./plugins /home/Shinobi/plugins RUN chmod -R 777 /home/Shinobi/plugins +RUN chmod 777 /home/Shinobi RUN npm i npm@latest -g && \ npm install --unsafe-perm && \ npm install pm2 -g diff --git a/languages/en_CA.json b/languages/en_CA.json index f39fdf3b..92b89cf4 100644 --- a/languages/en_CA.json +++ b/languages/en_CA.json @@ -858,6 +858,7 @@ "Country of Plates": "Country of Plates", "Email on No Motion": "Email on \"No Motion\"", "Discord on No Motion": "Discord on \"No Motion\"", + "No README found": "No README found", "Timeout": "Timeout", "Controllable": "Controllable", "Custom Base URL": "Custom Base URL Leave blank to use Host URL", diff --git a/libs/control/ptz.js b/libs/control/ptz.js index 708da2e3..abdf0aec 100644 --- a/libs/control/ptz.js +++ b/libs/control/ptz.js @@ -47,11 +47,21 @@ module.exports = function(s,config,lang){ ok: true, type: lang[doStart ? 'Control Triggered' : 'Control Trigger Ended'] } - const theRequest = fetchWithAuthentication(requestUrl,{ - method: controlUrlMethod || controlOptions.method, - digestAuth: hasDigestAuthEnabled, - postData: controlOptions.postData || null - }); + var fetchWithAuthData; + if (controlOptions.postData){ + fetchWithAuthData = { + method: controlUrlMethod || controlOptions.method, + digestAuth: hasDigestAuthEnabled, + postData: controlOptions.postData + } + } + else{ + fetchWithAuthData = { + method: controlUrlMethod || controlOptions.method, + digestAuth: hasDigestAuthEnabled + } + } + const theRequest = fetchWithAuthentication(requestUrl,fetchWithAuthData); theRequest.then(res => res.text()) .then((data) => { if(doStart){ diff --git a/libs/database/migrate/2023-03-11.js b/libs/database/migrate/2023-03-11.js new file mode 100644 index 00000000..c05d5645 --- /dev/null +++ b/libs/database/migrate/2023-03-11.js @@ -0,0 +1,18 @@ +module.exports = async function(s,config){ + s.debugLog('Updating database to 2023-03-11') + const { + alterColumn, + } = require('../utils.js')(s,config) + await alterColumn('Monitors',[ + {name: 'path', length: 255, type: 'string'}, + ]) + await alterColumn('Videos',[ + {name: 'size', length: 15, type: 'bigInteger'}, + ]) + await alterColumn('Cloud Videos',[ + {name: 'size', length: 15, type: 'bigInteger'}, + ]) + await alterColumn('Files',[ + {name: 'size', length: 15, type: 'bigInteger'}, + ]) +} diff --git a/libs/database/preQueries.js b/libs/database/preQueries.js index 946d8ce6..0726f896 100644 --- a/libs/database/preQueries.js +++ b/libs/database/preQueries.js @@ -46,7 +46,7 @@ module.exports = function(s,config){ {name: 'ke', length: 50, type: 'string'}, {name: 'mid', length: 100, type: 'string'}, {name: 'name', length: 100, type: 'string'}, - {name: 'size', type: 'integer'}, + {name: 'size', type: 'bigint'}, {name: 'details', type: 'text'}, {name: 'status', type: 'integer', length: 1, defaultTo: 0}, {name: 'archive', type: 'tinyint', length: 1, defaultTo: 0}, @@ -58,7 +58,7 @@ module.exports = function(s,config){ {name: 'ke', length: 50, type: 'string'}, {name: 'mid', length: 100, type: 'string'}, {name: 'ext', type: 'string', length: 10, defaultTo: 'mp4'}, - {name: 'size', type: 'integer'}, + {name: 'size', type: 'bigint'}, {name: 'status', type: 'tinyint', length: 1, defaultTo: 0}, {name: 'archive', type: 'tinyint', length: 1, defaultTo: 0}, {name: 'objects', length: 510, type: 'string'}, @@ -75,7 +75,7 @@ module.exports = function(s,config){ {name: 'ke', length: 50, type: 'string'}, {name: 'mid', length: 100, type: 'string'}, {name: 'href', length: 50, type: 'text'}, - {name: 'size', type: 'integer'}, + {name: 'size', type: 'bigint'}, {name: 'details', type: 'text'}, {name: 'status', type: 'integer', length: 1, defaultTo: 0}, {name: 'archive', type: 'tinyint', length: 1, defaultTo: 0}, @@ -112,7 +112,7 @@ module.exports = function(s,config){ {name: 'mid', length: 100, type: 'string'}, {name: 'filename', length: 50, type: 'string'}, {name: 'time', type: 'timestamp', defaultTo: currentTimestamp()}, - {name: 'size', type: 'integer'}, + {name: 'size', type: 'bigint'}, {name: 'archive', length: 1, type: 'tinyint', defaultTo: 0}, {name: 'saveDir', length: 255, type: 'string'}, {name: 'details', type: 'text'}, @@ -127,7 +127,7 @@ module.exports = function(s,config){ {name: 'href', type: 'text'}, {name: 'filename', length: 50, type: 'string'}, {name: 'time', type: 'timestamp', defaultTo: currentTimestamp()}, - {name: 'size', type: 'integer'}, + {name: 'size', type: 'bigint'}, {name: 'details', type: 'text'}, ]); await createTable('Logs',[ @@ -181,6 +181,7 @@ module.exports = function(s,config){ // additional requirements for older installs await require('./migrate/2022-08-22.js')(s,config) await require('./migrate/2022-12-18.js')(s,config) + await require('./migrate/2023-03-11.js')(s,config) delete(s.preQueries) } } diff --git a/libs/database/utils.js b/libs/database/utils.js index e7481a09..36f2903e 100644 --- a/libs/database/utils.js +++ b/libs/database/utils.js @@ -442,6 +442,23 @@ module.exports = function(s,config){ } } } + async function alterColumn(tableName,columns){ + try{ + for (let i = 0; i < columns.length; i++) { + const column = columns[i] + if(!column)return; + await s.databaseEngine.schema.alterTable(tableName, table => { + let action = table[column.type](column.name,column.length) + if(column.defaultTo !== null && column.defaultTo !== undefined){ + action = action.defaultTo(column.defaultTo) + } + action.alter() + }) + } + }catch(err){ + s.debugLog(err) + } + } async function createTable(tableName,columns,onSuccess){ try{ const exists = await s.databaseEngine.schema.hasTable(tableName) @@ -478,6 +495,7 @@ module.exports = function(s,config){ sqlQueryBetweenTimesWithPermissions: sqlQueryBetweenTimesWithPermissions, currentTimestamp, createTable, + alterColumn, addColumn, isMySQL, } diff --git a/libs/events/utils.js b/libs/events/utils.js index 199025f3..d02db6d6 100644 --- a/libs/events/utils.js +++ b/libs/events/utils.js @@ -15,7 +15,7 @@ module.exports = (s,config,lang) => { const acceptableOperators = ['indexOf','!indexOf','===','!==','>=','>','<','<='] // Event Filters /> const { - splitForFFPMEG + splitForFFMPEG } = require('../ffmpeg/utils.js')(s,config,lang) const { moveCameraPtzToMatrix @@ -556,7 +556,7 @@ module.exports = (s,config,lang) => { s.debugLog(ffmpegCommand) activeMonitor.eventBasedRecording.process = spawn( config.ffmpegDir, - splitForFFPMEG(ffmpegCommand) + splitForFFMPEG(ffmpegCommand) ) activeMonitor.eventBasedRecording.process.stderr.on('data',function(data){ s.userLog(d,{ diff --git a/libs/ffmpeg.js b/libs/ffmpeg.js index 297541b1..7f79edbe 100644 --- a/libs/ffmpeg.js +++ b/libs/ffmpeg.js @@ -5,7 +5,7 @@ module.exports = async (s,config,lang,onFinish) => { const { sanitizedFfmpegCommand, createPipeArray, - splitForFFPMEG, + splitForFFMPEG, checkForWindows, checkForUnix, checkStaticBuilds, @@ -66,7 +66,7 @@ module.exports = async (s,config,lang,onFinish) => { //hold ffmpeg command for log stream activeMonitor.ffmpeg = sanitizedFfmpegCommand(e,ffmpegCommandString) //clean the string of spatial impurities and split for spawn() - const ffmpegCommandParsed = splitForFFPMEG(ffmpegCommandString) + const ffmpegCommandParsed = splitForFFMPEG(ffmpegCommandString) try{ fs.rmSync(e.sdir + 'cmd.txt') }catch(err){ diff --git a/libs/ffmpeg/utils.js b/libs/ffmpeg/utils.js index 4ac8331c..e20402ec 100644 --- a/libs/ffmpeg/utils.js +++ b/libs/ffmpeg/utils.js @@ -38,7 +38,7 @@ module.exports = (s,config,lang) => { activeProbes[auth] = 1 var stderr = '' var stdout = '' - const probeCommand = splitForFFPMEG(`${customInput ? customInput + ' ' : ''}-analyzeduration 10000 -probesize 10000 -v quiet -print_format json -show_format -show_streams -i "${url}"`) + const probeCommand = splitForFFMPEG(`${customInput ? customInput + ' ' : ''}-analyzeduration 10000 -probesize 10000 -v quiet -print_format json -show_format -show_streams -i "${url}"`) var processTimeout = null var ffprobeLocation = config.ffmpegDir.split('/') ffprobeLocation[ffprobeLocation.length - 1] = 'ffprobe' @@ -184,7 +184,7 @@ module.exports = (s,config,lang) => { } return stdioPipes } - const splitForFFPMEG = function(ffmpegCommandAsString) { + const splitForFFMPEG = function(ffmpegCommandAsString) { return ffmpegCommandAsString.replace(/\s+/g,' ').trim().match(/\\?.|^$/g).reduce((p, c) => { if(c === '"'){ p.quote ^= 1; @@ -378,7 +378,7 @@ Run "npm install ffbinaries" to get this static FFmpeg downloader.` validateDimensions: validateDimensions, sanitizedFfmpegCommand: sanitizedFfmpegCommand, createPipeArray: createPipeArray, - splitForFFPMEG: splitForFFPMEG, + splitForFFMPEG: splitForFFMPEG, checkForWindows: checkForWindows, checkForUnix: checkForUnix, checkForNpmStatic: checkForNpmStatic, diff --git a/libs/monitor.js b/libs/monitor.js index bd0c6f86..4a366722 100644 --- a/libs/monitor.js +++ b/libs/monitor.js @@ -12,7 +12,7 @@ module.exports = function(s,config,lang){ asyncSetTimeout, } = require('./basic/utils.js')(process.cwd(),config) const { - splitForFFPMEG, + splitForFFMPEG, } = require('./ffmpeg/utils.js')(s,config,lang) const { processKill, @@ -194,7 +194,7 @@ module.exports = function(s,config,lang){ var iconImageFile = streamDir + 'icon.jpg' const snapRawFilters = monitor.details.cust_snap_raw if(snapRawFilters)outputOptions.push(snapRawFilters); - var ffmpegCmd = splitForFFPMEG(`-y -loglevel warning ${isDetectorStream ? '-live_start_index 2' : ''} -re ${inputOptions.join(' ')} -i "${url}" ${outputOptions.join(' ')} -f image2 -an -frames:v 1 "${temporaryImageFile}"`) + var ffmpegCmd = splitForFFMPEG(`-y -loglevel warning ${isDetectorStream ? '-live_start_index 2' : ''} -re ${inputOptions.join(' ')} -i "${url}" ${outputOptions.join(' ')} -f image2 -an -frames:v 1 "${temporaryImageFile}"`) try{ await fs.promises.mkdir(streamDir, {recursive: true}, (err) => {s.debugLog(err)}) }catch(err){ @@ -316,7 +316,7 @@ module.exports = function(s,config,lang){ //not exist var cat = 'cat '+copiedItems.join(' ')+' > '+allts exec(cat,function(){ - var merger = spawn(config.ffmpegDir,splitForFFPMEG(('-re -i '+allts+' -acodec copy -vcodec copy -t 00:00:' + videoLength + ' '+pathDir+mergedFile))) + var merger = spawn(config.ffmpegDir,splitForFFMPEG(('-re -i '+allts+' -acodec copy -vcodec copy -t 00:00:' + videoLength + ' '+pathDir+mergedFile))) merger.stderr.on('data',function(data){ s.userLog(monitor,{type:"Buffer Merge",msg:data.toString()}) }) @@ -405,7 +405,7 @@ module.exports = function(s,config,lang){ ke: groupKey, mid: '$USER' },{type:lang['Videos Merge'],msg:mergedFile}) - var merger = spawn(config.ffmpegDir,splitForFFPMEG(('-re -loglevel warning -i ' + mergedRawFilepath + ' -acodec copy -vcodec copy ' + mergedFilepath))) + var merger = spawn(config.ffmpegDir,splitForFFMPEG(('-re -loglevel warning -i ' + mergedRawFilepath + ' -acodec copy -vcodec copy ' + mergedFilepath))) merger.stderr.on('data',function(data){ s.userLog({ ke: groupKey, diff --git a/libs/monitor/utils.js b/libs/monitor/utils.js index 01ce2840..feb7be82 100644 --- a/libs/monitor/utils.js +++ b/libs/monitor/utils.js @@ -16,7 +16,7 @@ module.exports = (s,config,lang) => { createWarningsForConfiguration, buildMonitorConfigPartialFromWarnings, createPipeArray, - splitForFFPMEG, + splitForFFMPEG, sanitizedFfmpegCommand, } = require('../ffmpeg/utils.js')(s,config,lang) const { @@ -220,7 +220,7 @@ module.exports = (s,config,lang) => { }) } const temporaryImageFile = streamDir + s.gid(5) + '.jpg' - const ffmpegCmd = splitForFFPMEG(`-y -loglevel warning -re ${inputOptions.join(' ')} -i "${url}" ${outputOptions.join(' ')} -f image2 -an -frames:v 1 "${temporaryImageFile}"`) + const ffmpegCmd = splitForFFMPEG(`-y -loglevel warning -re ${inputOptions.join(' ')} -i "${url}" ${outputOptions.join(' ')} -f image2 -an -frames:v 1 "${temporaryImageFile}"`) const snapProcess = spawn('ffmpeg',ffmpegCmd,{detached: true}) snapProcess.stderr.on('data',function(data){ // s.debugLog(data.toString()) @@ -306,7 +306,7 @@ module.exports = (s,config,lang) => { }); const ffmpegCommandString = ffmpegCommand.join(' ') activeMonitor.ffmpegSubstream = sanitizedFfmpegCommand(e,ffmpegCommandString) - const ffmpegCommandParsed = splitForFFPMEG(ffmpegCommandString) + const ffmpegCommandParsed = splitForFFMPEG(ffmpegCommandString) activeMonitor.subStreamChannel = channelNumber; s.userLog({ ke: groupKey, diff --git a/libs/notifications/emailByUser.js b/libs/notifications/emailByUser.js index 6f78f0c1..a9af1153 100644 --- a/libs/notifications/emailByUser.js +++ b/libs/notifications/emailByUser.js @@ -42,7 +42,6 @@ module.exports = function (s, config, lang, getSnapshot) { s.debugLog(result); }); }) - console.log(sendBody) } catch (err) { s.debugLog(err) s.userLog( diff --git a/libs/plugins/superUser.js b/libs/plugins/superUser.js index 042426c2..434c420a 100644 --- a/libs/plugins/superUser.js +++ b/libs/plugins/superUser.js @@ -4,6 +4,7 @@ const unzipper = require('unzipper') const spawn = require('child_process').spawn const exec = require('child_process').execSync const treekill = require('tree-kill'); +const marked = require('marked').parse; const { Worker } = require('worker_threads'); @@ -342,6 +343,20 @@ module.exports = async (s,config,lang,app,io,currentUse) => { } }) } + async function getPluginReadme(name,asHTML){ + const modulePath = getModulePath(name) + const readmePath = modulePath + 'README.md' + let readmeData = lang['No README found'] + try{ + readmeData = await fs.promises.readFile(readmePath,'utf8') + }catch(err){ + console.log(err) + } + if(asHTML){ + readmeData = marked(readmeData) + } + return readmeData + } /** * API : Superuser : Custom Auto Load Package Download. */ @@ -549,6 +564,16 @@ module.exports = async (s,config,lang,app,io,currentUse) => { s.closeJsonResponse(res,{ok: true}) },res,req) }) + /** + * API : Superuser : Get Plugin README + */ + app.get(config.webPaths.superApiPrefix+':auth/plugins/readme/:pluginName', async (req,res) => { + s.superAuth(req.params, async (resp) => { + const name = req.params.pluginName + const readme = await getPluginReadme(name,true); + s.closeJsonResponse(res,{ok: true, readme: readme}) + },res,req) + }) s.onProcessReady(async () => { // Initialize Modules on Start await initializeAllModules(); diff --git a/libs/timelapse.js b/libs/timelapse.js index 5e72be1f..f5cd1f82 100644 --- a/libs/timelapse.js +++ b/libs/timelapse.js @@ -9,7 +9,7 @@ module.exports = function(s,config,lang,app,io){ sendTimelapseFrameToMasterNode, } = require('./childNode/childUtils.js')(s,config,lang) const { - splitForFFPMEG, + splitForFFMPEG, } = require('./ffmpeg/utils.js')(s,config,lang) const { getFileDirectory, @@ -49,7 +49,7 @@ module.exports = function(s,config,lang,app,io){ size: fileStats.size, time: timeNow } - if(config.childNodes.enabled === true && config.childNodes.mode === 'child' && config.childNodes.host){ + if(config.childNodes.enabled === true && config.childNodes.mode === 'child' && config.childNodes.host && config.dropTimeLapseFrames != true){ var currentDate = s.formattedTime(timeNow,'YYYY-MM-DD') const childNodeData = { ke: e.ke, @@ -60,7 +60,7 @@ module.exports = function(s,config,lang,app,io){ queryInfo: queryInfo } sendTimelapseFrameToMasterNode(filePath,childNodeData) - }else{ + }else if (config.dropTimeLapseFrames != true ){ s.insertTimelapseFrameDatabaseRow(e,queryInfo,filePath) } } @@ -239,7 +239,7 @@ module.exports = function(s,config,lang,app,io){ const numberOfFrames = framesAccepted.length const commandString = `-y -threads 1 -re -f concat -safe 0 -r ${framesPerSecond} -i "${concatListFile}" -q:v 1 -c:v libx264 -preset ultrafast -r ${framesPerSecond} "${finalMp4OutputLocation}"` s.debugLog("ffmpeg",commandString) - const videoBuildProcess = spawn(config.ffmpegDir,splitForFFPMEG(commandString)) + const videoBuildProcess = spawn(config.ffmpegDir,splitForFFMPEG(commandString)) videoBuildProcess.stdout.on('data',function(data){ s.debugLog('stdout',finalMp4OutputLocation,data.toString()) }) diff --git a/libs/video/utils.js b/libs/video/utils.js index 76e2e0eb..8512e660 100644 --- a/libs/video/utils.js +++ b/libs/video/utils.js @@ -4,7 +4,7 @@ const async = require('async'); module.exports = (s,config,lang) => { const { ffprobe, - splitForFFPMEG, + splitForFFMPEG, } = require('../ffmpeg/utils.js')(s,config,lang) const { copyFile, @@ -257,7 +257,7 @@ module.exports = (s,config,lang) => { const finalMp4OutputLocation = options.output const commandString = `-y -threads 1 -f concat -safe 0 -i "${concatListFile}" -c:v copy -an -preset ultrafast "${finalMp4OutputLocation}"` s.debugLog("stitchMp4Files",commandString) - const videoBuildProcess = spawn(config.ffmpegDir,splitForFFPMEG(commandString)) + const videoBuildProcess = spawn(config.ffmpegDir,splitForFFMPEG(commandString)) videoBuildProcess.stdout.on('data',function(data){ s.debugLog('stdout',finalMp4OutputLocation,data.toString()) }) @@ -286,7 +286,7 @@ module.exports = (s,config,lang) => { const outputFilePath = `${videoFolder}${tempFilename}` const commandString = `-y -threads 1 -re -i "${inputFilePath}" -c:v copy -c:a copy -preset ultrafast "${outputFilePath}"` fixingAlready[fixingId] = true - const videoBuildProcess = spawn(config.ffmpegDir,splitForFFPMEG(commandString)) + const videoBuildProcess = spawn(config.ffmpegDir,splitForFFMPEG(commandString)) videoBuildProcess.stdout.on('data',function(data){ s.debugLog('stdout',outputFilePath,data.toString()) }) @@ -409,7 +409,7 @@ module.exports = (s,config,lang) => { oldName: filename, name: finalFilename, },'GRP_'+groupKey); - const videoBuildProcess = spawn(config.ffmpegDir,splitForFFPMEG(commandString)) + const videoBuildProcess = spawn(config.ffmpegDir,splitForFFMPEG(commandString)) videoBuildProcess.stdout.on('data',function(data){ s.debugLog('stdout',outputFilePath,data.toString()) }) diff --git a/package-lock.json b/package-lock.json index 5e9c67d5..c8d597bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,13 +29,13 @@ "jsonfile": "^3.0.1", "knex": "^0.21.21", "ldapauth-fork": "^5.0.2", + "marked": "^4.3.0", "moment": "^2.29.4", - "mp4frag": "^0.2.0", + "mp4frag": "^0.6.0", "mqtt": "^4.3.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", @@ -46,6 +46,7 @@ "pixel-change": "^1.1.0", "pushover-notifications": "^1.2.2", "sat": "^0.7.1", + "shinobi-node-moving-things-tracker": "^0.9.1", "shinobi-onvif": "0.1.9", "shinobi-sound-detection": "^0.1.13", "shinobi-zwave": "^1.0.11", @@ -4837,6 +4838,17 @@ "node": ">=0.10.0" } }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -4969,9 +4981,12 @@ } }, "node_modules/mp4frag": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.2.0.tgz", - "integrity": "sha512-zrLws5vFuUvaivVXu4ZPg7fdJynSbcIT6kI00okZ+jCvxqMIs6zhhh7sw16BE+lL1OD6RyCsFgJEdzxZaeb5fQ==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.6.0.tgz", + "integrity": "sha512-MvBAaWkW94SSpam/QsCmbMi7+ZY2YHzAjj6Uno7AZ6qxH7gZstN+L3jFopdN5F3/5mRK25gvA4k0DVpCbDe7+g==", + "engines": { + "node": ">=10" + } }, "node_modules/mqtt": { "version": "4.3.7", @@ -5226,20 +5241,6 @@ "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", @@ -6329,6 +6330,19 @@ "resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz", "integrity": "sha1-aP0CXrBJC09WegJ/C/IkgLX4QTM=" }, + "node_modules/shinobi-node-moving-things-tracker": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/shinobi-node-moving-things-tracker/-/shinobi-node-moving-things-tracker-0.9.1.tgz", + "integrity": "sha512-pcI/IJ9D87RJiTGEsBYvtb2FTQXkHCkuyv6dYaXB5KVpnhQJGyf37BvAbvCNuCJmlffBGTMClY2dg84ZwHl/Ow==", + "dependencies": { + "lodash.isequal": "^4.5.0", + "minimist": "^1.2.0", + "munkres-js": "^1.2.2" + }, + "bin": { + "shinobi-node-moving-things-tracker": "main.js" + } + }, "node_modules/shinobi-onvif": { "version": "0.1.9", "resolved": "https://registry.npmjs.org/shinobi-onvif/-/shinobi-onvif-0.1.9.tgz", @@ -11490,6 +11504,11 @@ "object-visit": "^1.0.0" } }, + "marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==" + }, "md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -11589,9 +11608,9 @@ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "mp4frag": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.2.0.tgz", - "integrity": "sha512-zrLws5vFuUvaivVXu4ZPg7fdJynSbcIT6kI00okZ+jCvxqMIs6zhhh7sw16BE+lL1OD6RyCsFgJEdzxZaeb5fQ==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.6.0.tgz", + "integrity": "sha512-MvBAaWkW94SSpam/QsCmbMi7+ZY2YHzAjj6Uno7AZ6qxH7gZstN+L3jFopdN5F3/5mRK25gvA4k0DVpCbDe7+g==" }, "mqtt": { "version": "4.3.7", @@ -11782,17 +11801,6 @@ "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", @@ -12643,6 +12651,16 @@ "resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz", "integrity": "sha1-aP0CXrBJC09WegJ/C/IkgLX4QTM=" }, + "shinobi-node-moving-things-tracker": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/shinobi-node-moving-things-tracker/-/shinobi-node-moving-things-tracker-0.9.1.tgz", + "integrity": "sha512-pcI/IJ9D87RJiTGEsBYvtb2FTQXkHCkuyv6dYaXB5KVpnhQJGyf37BvAbvCNuCJmlffBGTMClY2dg84ZwHl/Ow==", + "requires": { + "lodash.isequal": "^4.5.0", + "minimist": "^1.2.0", + "munkres-js": "^1.2.2" + } + }, "shinobi-onvif": { "version": "0.1.9", "resolved": "https://registry.npmjs.org/shinobi-onvif/-/shinobi-onvif-0.1.9.tgz", diff --git a/package.json b/package.json index 1358974a..4cd861e4 100644 --- a/package.json +++ b/package.json @@ -35,13 +35,13 @@ "jsonfile": "^3.0.1", "knex": "^0.21.21", "ldapauth-fork": "^5.0.2", + "marked": "^4.3.0", "moment": "^2.29.4", - "mp4frag": "^0.2.0", + "mp4frag": "^0.6.0", "mqtt": "^4.3.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", @@ -52,6 +52,7 @@ "pixel-change": "^1.1.0", "pushover-notifications": "^1.2.2", "sat": "^0.7.1", + "shinobi-node-moving-things-tracker": "^0.9.1", "shinobi-onvif": "0.1.9", "shinobi-sound-detection": "^0.1.13", "shinobi-zwave": "^1.0.11", diff --git a/test/run.js b/test/run.js index 2e18014c..d81bffa3 100644 --- a/test/run.js +++ b/test/run.js @@ -135,14 +135,14 @@ module.exports = function(s,config,lang,io){ } }, "ffmpeg.js" : { - splitForFFPMEG : function(next){ + splitForFFMPEG : function(next){ var expectedResult = [ 'flag1', 'flag2', 'fl ag3', ] - var testResult = s.splitForFFPMEG('flag1 flag2 "fl ag3"') - checkResult('Internal Function : splitForFFPMEG',JSON.stringify(expectedResult),JSON.stringify(testResult)) + var testResult = s.splitForFFMPEG('flag1 flag2 "fl ag3"') + checkResult('Internal Function : splitForFFMPEG',JSON.stringify(expectedResult),JSON.stringify(testResult)) next() }, "ffmpeg" : function(next){ diff --git a/web/assets/css/super.pluginManager.css b/web/assets/css/super.pluginManager.css index 14f6690a..10bb8054 100644 --- a/web/assets/css/super.pluginManager.css +++ b/web/assets/css/super.pluginManager.css @@ -7,3 +7,8 @@ border-radius: 5px; max-height: 300px; } +.readme-view { + padding: 1rem 2rem; + border: 1px solid #009dff; + border-radius: 10px; +} diff --git a/web/assets/js/bs5.dashboard-base.js b/web/assets/js/bs5.dashboard-base.js index 7ba5d49a..5e489d56 100644 --- a/web/assets/js/bs5.dashboard-base.js +++ b/web/assets/js/bs5.dashboard-base.js @@ -986,7 +986,7 @@ function convertJsonToAccordionHtml(theJson){ keys.forEach((key) => { var value = innerJson[key] var isObject = typeof value === 'object' || typeof value === 'array' - if(value)html += `
This is a change being applied to the configuration file (conf.json). Are you sure you want to do this? You must restart Shinobi for these changes to take effect. The JSON below is what you are about to save.
' - html += `${newConfiguration}`
- $.confirm.create({
- title: 'Save Configuration',
- body: html,
- clickOptions: {
- class: 'btn-success',
- title: lang.Save,
- },
- clickCallback: function(){
- $.post(superApiPrefix + $user.sessionKey + '/system/configure',{
- data: newConfiguration
- },function(data){
- // console.log(data)
- })
- }
- })
- }else{
- new PNotify({text:'Invalid JSON Syntax, Cannot Save.',type:'error'})
- }
+
+ const configurationEditor = new JSONEditor(
+ document.getElementById("configForHumans"), {
+ schema: schema,
}
- configurationTab.find('.submit').click(function(){
- submitConfiguration()
- })
- configurationForm.submit(function(e){
- e.preventDefault()
- submitConfiguration()
- return false;
- })
- $.ccio.ws.on('f',function(d){
- switch(d.f){
- case'init_success':
- loadConfiguationIntoEditor()
- break;
+ );
+
+ configurationEditor.setValue(data.config);
+
+ moduleData.configurationEditor = configurationEditor;
+ window.configurationEditor = configurationEditor;
+ };
+
+ const handlePostConfigurationData = data => {
+ // console.log(data);
+ }
+
+ function loadConfiguationIntoEditor(d) {
+ moduleData.endpoint = `${superApiPrefix}${$user.sessionKey}/system/configure`;
+
+ $.get(moduleData.endpoint, handleGetConfigurationData);
+ }
+
+ var submitConfiguration = function () {
+ var errors = configurationEditor.validate();
+ console.log(errors.length)
+ console.log(errors)
+ if (errors.length === 0) {
+ var newConfiguration = JSON.stringify(configurationEditor.getValue(), null, 3)
+ var html = 'This is a change being applied to the configuration file (conf.json). Are you sure you want to do this? You must restart Shinobi for these changes to take effect. The JSON below is what you are about to save.
' + html += `${newConfiguration}`
+ $.confirm.create({
+ title: 'Save Configuration',
+ body: html,
+ clickOptions: {
+ class: 'btn-success',
+ title: lang.Save,
+ },
+ clickCallback: function () {
+ const requestData = {
+ data: newConfiguration
+ };
+
+ $.post(moduleData.endpoint, requestData, handlePostConfigurationData);
}
- })
- window.configurationEditor = configurationEditor
+ })
+ } else {
+ new PNotify({ text: 'Invalid JSON Syntax, Cannot Save.', type: 'error' });
+ }
+ };
+
+ configurationTab.find('.submit').click(function () {
+ submitConfiguration();
+ });
+
+ configurationForm.submit(function (e) {
+ e.preventDefault();
+ submitConfiguration();
+ return false;
+ });
+
+ $.ccio.ws.on("f", d => {
+ if (d.f === "init_success") {
+ loadConfiguationIntoEditor();
+ }
+ });
+
+ window.configurationEditor = configurationEditor;
})
diff --git a/web/assets/js/super.pluginManager.js b/web/assets/js/super.pluginManager.js
index 590f2bfe..7dcf7ea7 100644
--- a/web/assets/js/super.pluginManager.js
+++ b/web/assets/js/super.pluginManager.js
@@ -47,6 +47,7 @@ $(document).ready(function(){