From 33078c97b16cf32f22c70c5e89218cb87f663b5b Mon Sep 17 00:00:00 2001 From: Nabheet Sandhu Date: Tue, 21 Feb 2023 04:04:48 +0000 Subject: [PATCH 01/19] Proposal to resolve error where postData was being sent on a GET request. --- libs/control/ptz.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) 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){ From af914b4150e96d8b65b70f5ef2940ff7896c8d2a Mon Sep 17 00:00:00 2001 From: Ian Rubado Date: Wed, 15 Mar 2023 19:50:57 -0400 Subject: [PATCH 02/19] New config option to drop timelapse frames --- libs/timelapse.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/timelapse.js b/libs/timelapse.js index 5e72be1f..d556d854 100644 --- a/libs/timelapse.js +++ b/libs/timelapse.js @@ -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 === false){ 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 === false ){ s.insertTimelapseFrameDatabaseRow(e,queryInfo,filePath) } } From ac5305c2b56b8f392c2f214e85c48060c1f7948f Mon Sep 17 00:00:00 2001 From: Ian Rubado Date: Wed, 15 Mar 2023 22:18:06 -0400 Subject: [PATCH 03/19] Fixed boolean logic --- libs/timelapse.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/timelapse.js b/libs/timelapse.js index d556d854..205dd81b 100644 --- a/libs/timelapse.js +++ b/libs/timelapse.js @@ -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 && config.dropTimeLapseFrames === false){ + 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 if (config.dropTimeLapseFrames === false ){ + }else if (config.dropTimeLapseFrames != true ){ s.insertTimelapseFrameDatabaseRow(e,queryInfo,filePath) } } From 301f3a690efa1c43f4b676cdafdc796a6e86abb0 Mon Sep 17 00:00:00 2001 From: Moe Date: Wed, 15 Mar 2023 20:47:04 -0700 Subject: [PATCH 04/19] !457 fix --- libs/notifications/emailByUser.js | 1 - 1 file changed, 1 deletion(-) 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( From 2a4565062813a75d0ea0fd72575b0260129a1a8c Mon Sep 17 00:00:00 2001 From: Moe Date: Fri, 17 Mar 2023 08:37:48 -0700 Subject: [PATCH 05/19] make path (Monitors) and size (Videos) columns longer --- libs/database/migrate/2023-03-11.js | 12 ++++++++++++ libs/database/preQueries.js | 1 + libs/database/utils.js | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 libs/database/migrate/2023-03-11.js diff --git a/libs/database/migrate/2023-03-11.js b/libs/database/migrate/2023-03-11.js new file mode 100644 index 00000000..475f4651 --- /dev/null +++ b/libs/database/migrate/2023-03-11.js @@ -0,0 +1,12 @@ +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'}, + ]) +} diff --git a/libs/database/preQueries.js b/libs/database/preQueries.js index 946d8ce6..7c3ba7a9 100644 --- a/libs/database/preQueries.js +++ b/libs/database/preQueries.js @@ -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, } From 7be60707c8d154f6209ab33b529927e8d42adf1c Mon Sep 17 00:00:00 2001 From: Mike Hurley Date: Fri, 17 Mar 2023 15:39:14 +0000 Subject: [PATCH 06/19] Adjust all integer column types to bigint --- libs/database/preQueries.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/database/preQueries.js b/libs/database/preQueries.js index 7c3ba7a9..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',[ From 2e65403317fc4a240a84d69e541d11cfe30af00f Mon Sep 17 00:00:00 2001 From: Moe Date: Fri, 17 Mar 2023 08:41:48 -0700 Subject: [PATCH 07/19] make size (Cloud Videos and Files) columns longer --- libs/database/migrate/2023-03-11.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/database/migrate/2023-03-11.js b/libs/database/migrate/2023-03-11.js index 475f4651..c05d5645 100644 --- a/libs/database/migrate/2023-03-11.js +++ b/libs/database/migrate/2023-03-11.js @@ -9,4 +9,10 @@ module.exports = async function(s,config){ 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'}, + ]) } From a15fe04ace16b066808eb2ba4c832e6bdfe704f1 Mon Sep 17 00:00:00 2001 From: Moe Date: Sun, 26 Mar 2023 23:31:21 -0700 Subject: [PATCH 08/19] update mp4frag --- package-lock.json | 67 ++++++++++++++++++++++++----------------------- package.json | 4 +-- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5e9c67d5..c6b9c0e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,12 +30,11 @@ "knex": "^0.21.21", "ldapauth-fork": "^5.0.2", "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 +45,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", @@ -4969,9 +4969,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 +5229,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 +6318,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", @@ -11589,9 +11591,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 +11784,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 +12634,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..386e5360 100644 --- a/package.json +++ b/package.json @@ -36,12 +36,11 @@ "knex": "^0.21.21", "ldapauth-fork": "^5.0.2", "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 +51,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", From 545a6f64ffe2c88fbdd3096c6659c6d6cc9f3808 Mon Sep 17 00:00:00 2001 From: Unicate Date: Tue, 28 Mar 2023 09:08:07 +0700 Subject: [PATCH 09/19] fix typo for function splitForFFMPEG --- libs/events/utils.js | 4 ++-- libs/ffmpeg.js | 4 ++-- libs/ffmpeg/utils.js | 6 +++--- libs/monitor.js | 8 ++++---- libs/monitor/utils.js | 6 +++--- libs/timelapse.js | 4 ++-- libs/video/utils.js | 8 ++++---- test/run.js | 6 +++--- 8 files changed, 23 insertions(+), 23 deletions(-) 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/timelapse.js b/libs/timelapse.js index 5e72be1f..a50de947 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, @@ -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/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){ From e22713033de6610790278f05abcea48555c76915 Mon Sep 17 00:00:00 2001 From: Moe Date: Tue, 28 Mar 2023 08:42:58 -0700 Subject: [PATCH 10/19] update convertJsonToAccordionHtml --- web/assets/js/bs5.dashboard-base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 += `
  • ${key} ${isObject ? recurseJson(value,true) : `: ${value}`}
  • ` + if(value === 0 || value === false || value)html += `
  • ${key} ${isObject ? recurseJson(value,true) : `: ${value}`}
  • ` }) html += `` return html From 4ce0eb1415fc9e91d9625431cf39c3a51ceafcd0 Mon Sep 17 00:00:00 2001 From: Moe Date: Tue, 28 Mar 2023 08:43:12 -0700 Subject: [PATCH 11/19] make Poseidon the default Stream Type --- web/assets/js/bs5.monitorSettings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/assets/js/bs5.monitorSettings.js b/web/assets/js/bs5.monitorSettings.js index 8ceb2315..317c7de7 100644 --- a/web/assets/js/bs5.monitorSettings.js +++ b/web/assets/js/bs5.monitorSettings.js @@ -58,8 +58,8 @@ function generateDefaultMonitorSettings(){ "hwaccel_vcodec": "", "hwaccel_device": "", "use_coprocessor": null, - "stream_type": "hls", - "stream_flv_type": "ws", + "stream_type": "mp4", + "stream_flv_type": "http", "stream_flv_maxLatency": "", "stream_mjpeg_clients": "", "stream_vcodec": "copy", From 1a70e8888c81c2f55e3ee3e7d390ea7f7c1ccf87 Mon Sep 17 00:00:00 2001 From: Moe Date: Wed, 29 Mar 2023 09:36:49 -0700 Subject: [PATCH 12/19] add README viewer to plugin manager --- languages/en_CA.json | 1 + libs/plugins/superUser.js | 25 ++++ package-lock.json | 196 +++++++++++-------------- package.json | 5 +- web/assets/css/super.pluginManager.css | 5 + web/assets/js/super.pluginManager.js | 23 +++ 6 files changed, 146 insertions(+), 109 deletions(-) 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/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/package-lock.json b/package-lock.json index c6b9c0e0..afb3542b 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": "^1.7.0", + "backblaze-b2": "^0.9.12", "body-parser": "^1.19.0", "bson": "^4.6.1", "connection-tester": "^0.2.0", @@ -29,8 +29,9 @@ "jsonfile": "^3.0.1", "knex": "^0.21.21", "ldapauth-fork": "^5.0.2", + "marked": "^4.3.0", "moment": "^2.29.4", - "mp4frag": "^0.6.0", + "mp4frag": "^0.2.0", "mqtt": "^4.3.7", "mysql": "^2.18.1", "node-abort-controller": "^3.0.1", @@ -1385,17 +1386,6 @@ "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", @@ -1706,34 +1696,15 @@ "follow-redirects": "^1.14.4" } }, - "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": { - "@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==", + "version": "0.9.12", + "resolved": "https://registry.npmjs.org/backblaze-b2/-/backblaze-b2-0.9.12.tgz", + "integrity": "sha1-b0IHJs7G0L787ohqS7bfUOnAGco=", "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-sha1": "^1.0.1", + "q": "^1.4.1", + "request": "^2.67.0", + "request-progress": "^3.0.0" } }, "node_modules/backoff": { @@ -4396,17 +4367,6 @@ "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", @@ -4837,6 +4797,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,12 +4940,9 @@ } }, "node_modules/mp4frag": { - "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" - } + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.2.0.tgz", + "integrity": "sha512-zrLws5vFuUvaivVXu4ZPg7fdJynSbcIT6kI00okZ+jCvxqMIs6zhhh7sw16BE+lL1OD6RyCsFgJEdzxZaeb5fQ==" }, "node_modules/mqtt": { "version": "4.3.7", @@ -5237,6 +5205,11 @@ "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", @@ -5889,6 +5862,15 @@ "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", @@ -5948,11 +5930,6 @@ "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", @@ -6022,6 +5999,14 @@ "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", @@ -6997,6 +6982,11 @@ "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", @@ -8892,14 +8882,6 @@ "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", @@ -9132,33 +9114,15 @@ "follow-redirects": "^1.14.4" } }, - "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": { - "@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==", + "version": "0.9.12", + "resolved": "https://registry.npmjs.org/backblaze-b2/-/backblaze-b2-0.9.12.tgz", + "integrity": "sha1-b0IHJs7G0L787ohqS7bfUOnAGco=", "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" - } - } + "node-sha1": "^1.0.1", + "q": "^1.4.1", + "request": "^2.67.0", + "request-progress": "^3.0.0" } }, "backoff": { @@ -11169,11 +11133,6 @@ "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", @@ -11492,6 +11451,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", @@ -11591,9 +11555,9 @@ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "mp4frag": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.6.0.tgz", - "integrity": "sha512-MvBAaWkW94SSpam/QsCmbMi7+ZY2YHzAjj6Uno7AZ6qxH7gZstN+L3jFopdN5F3/5mRK25gvA4k0DVpCbDe7+g==" + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/mp4frag/-/mp4frag-0.2.0.tgz", + "integrity": "sha512-zrLws5vFuUvaivVXu4ZPg7fdJynSbcIT6kI00okZ+jCvxqMIs6zhhh7sw16BE+lL1OD6RyCsFgJEdzxZaeb5fQ==" }, "mqtt": { "version": "4.3.7", @@ -11792,6 +11756,11 @@ "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", @@ -12287,6 +12256,11 @@ "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", @@ -12331,11 +12305,6 @@ "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", @@ -12409,6 +12378,14 @@ } } }, + "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", @@ -13155,6 +13132,11 @@ "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 386e5360..f93379a6 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": "^1.7.0", + "backblaze-b2": "^0.9.12", "body-parser": "^1.19.0", "bson": "^4.6.1", "connection-tester": "^0.2.0", @@ -35,8 +35,9 @@ "jsonfile": "^3.0.1", "knex": "^0.21.21", "ldapauth-fork": "^5.0.2", + "marked": "^4.3.0", "moment": "^2.29.4", - "mp4frag": "^0.6.0", + "mp4frag": "^0.2.0", "mqtt": "^4.3.7", "mysql": "^2.18.1", "node-abort-controller": "^3.0.1", 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/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(){
    ${lang['Time Created']} : ${module.created}
    ${lang['Last Modified']} : ${module.lastModified}
    + ${lang.Notes} ${module.hasInstaller ? ` ${lang['Run Installer']} @@ -74,6 +75,7 @@ $(document).ready(function(){
    +
    `) var newBlock = $(`.card[package-name="${module.name}"]`) @@ -186,6 +188,24 @@ $(document).ready(function(){ objDiv.scrollTop = objDiv.scrollHeight; },100) } + function getReadme(packageName){ + return new Promise(function(resolve){ + $.get(`${superApiPrefix}${$user.sessionKey}/plugins/readme/${packageName}`,function(data){ + if(!data.ok)console.error(data); + resolve(data.readme || '') + }) + }) + } + async function toggleReadme(packageName){ + var readmeView = loadedBlocks[packageName].block.find('.readme-view') + var isHidden = readmeView.hasClass('d-none') + if(isHidden){ + var readmeHTML = await getReadme(packageName) + readmeView.removeClass('d-none').html(readmeHTML) + }else{ + readmeView.addClass('d-none').empty() + } + } $('body') .on(`submit`,`[plugin-manager-command-line]`,function(e){ e.preventDefault() @@ -206,6 +226,9 @@ $(document).ready(function(){ var card = el.parents('[package-name]') var packageName = card.attr('package-name') switch(action){ + case'readmeToggle': + toggleReadme(packageName) + break; case'run': var scriptName = el.attr('data-script') runModuleCommand(packageName,scriptName,function(data){ From a79976142b01d9ec9940490ad89910e801c1e5fa Mon Sep 17 00:00:00 2001 From: Moe Date: Wed, 29 Mar 2023 10:55:58 -0700 Subject: [PATCH 13/19] fix reverted packages in package.json --- package-lock.json | 183 +++++++++++++++++++++++++++------------------- package.json | 4 +- 2 files changed, 111 insertions(+), 76 deletions(-) diff --git a/package-lock.json b/package-lock.json index afb3542b..c8d597bd 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", @@ -31,7 +31,7 @@ "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", @@ -1386,6 +1386,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", @@ -1696,15 +1707,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": { @@ -4367,6 +4397,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", @@ -4940,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", @@ -5205,11 +5249,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", @@ -5862,15 +5901,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", @@ -5930,6 +5960,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", @@ -5999,14 +6034,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", @@ -6982,11 +7009,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", @@ -8882,6 +8904,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", @@ -9114,15 +9144,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": { @@ -11133,6 +11181,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", @@ -11555,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", @@ -11756,11 +11809,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", @@ -12256,11 +12304,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", @@ -12305,6 +12348,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", @@ -12378,14 +12426,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", @@ -13132,11 +13172,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 f93379a6..4cd861e4 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", @@ -37,7 +37,7 @@ "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", From 12151602ef49a9ee92c28d42aaf1782cff4d0750 Mon Sep 17 00:00:00 2001 From: Elad Bar Date: Thu, 6 Apr 2023 17:11:25 +0000 Subject: [PATCH 14/19] Fix super config default values --- .gitignore | 1 + web/assets/js/super.configEditor.js | 663 +++++++++++++++------------- 2 files changed, 360 insertions(+), 304 deletions(-) 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/web/assets/js/super.configEditor.js b/web/assets/js/super.configEditor.js index f63bc7b1..6ce3b060 100644 --- a/web/assets/js/super.configEditor.js +++ b/web/assets/js/super.configEditor.js @@ -1,321 +1,376 @@ -$(document).ready(function(){ - var schema = { - "title": "Main Configuration", - "type": "object", - "properties": { - "debugLog": { +$(document).ready(function () { + var schema = { + "title": "Main Configuration", + "type": "object", + "properties": { + "debugLog": { + "title": "Enable Debug Log", + "type": "boolean", + "default": false + }, + "subscriptionId": { + "title": "Fill in subscription ID", + "type": "string", + "default": null + }, + "port": { + "title": "Server port", + "type": "integer", + "default": 8080 + }, + "passwordType": { + "title": "Password type", + "type": "string", + "enum": [ + "sha256", + "sha512", + "md5" + ], + "default": "sha256" + }, + "addStorage": { + "type": "array", + "format": "table", + "title": "Additional Storage", + "description": "Separate storage locations that can be set for different monitors.", + "uniqueItems": true, + "items": { + "type": "object", + "title": "Storage Array", + "properties": { + "name": { + "type": "string", + }, + "path": { + "type": "string", + "default": "__DIR__/videos2" + } + } + }, + "default": [ + { + "name": "second", + "path": "__DIR__/videos2" + } + ] + }, + "plugins": { + "type": "array", + "format": "table", + "title": "Plugins", + "descripton": "Elaborate Plugin connection settings.", + "uniqueItems": true, + "items": { + "type": "object", + "title": "Plugin", + "properties": { + "plug": { + "type": "string", + "default": "pluginName" + }, + "key": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "host", + "client" + ], + "default": "client" + }, + "https": { + "type": "boolean", + "descripton": "Only for Host mode.", + "default": false + }, + "host": { + "type": "string", + "descripton": "Only for Host mode.", + "default": "localhost" + }, + "port": { + "type": "integer", + "descripton": "Only for Host mode.", + "default": 8082 + }, + "type": { + "type": "string", + "default": "detector" + } + } + } + }, + "pluginKeys": { + "type": "object", + "format": "table", + "title": "Plugin Keys", + "description": "Quick client connection setup for plugins. Just add the plugin key to make it ready for incoming connections.", + "uniqueItems": true, + "items": { + "type": "object", + "title": "Plugin Key", + "properties": {} + } + }, + "db": { + "type": "object", + "format": "table", + "title": "Database Options", + "description": "Credentials to connect to where detailed information is stored.", + "properties": { + "host": { + "title": "Hostname / IP", + "type": "string", + "default": "127.0.0.1" + }, + "user": { + "title": "Username", + "type": "string", + "default": "majesticflame" + }, + "password": { + "title": "Password", + "type": "string", + "default": "" + }, + "database": { + "type": "string", + "default": "ccio" + }, + "port": { + "type": "integer", + "default": 3306 + } + }, + "default": { + "host": "127.0.0.1", + "user": "majesticflame", + "password": "", + "database": "ccio", + "port": 3306 + } + }, + "cron": { + "type": "object", + "format": "table", + "title": "CRON Options", + "properties": { + "key": { + "type": "string", + }, + "deleteOld": { + "type": "boolean", + "description": "cron will delete videos older than Max Number of Days per account.", + "default": true + }, + "deleteNoVideo": { + "type": "boolean", + "description": "cron will delete SQL rows that it thinks have no video files.", + "default": true + }, + "deleteOverMax": { + "type": "boolean", + "description": "cron will delete files that are over the set maximum storage per account.", + "default": true + }, + } + }, + "mail": { + "type": "object", + "format": "table", + "title": "Email Options", + "properties": { + "service": { + "type": "string", + }, + "host": { + "type": "string", + }, + "auth": { + "type": "object", + "properties": { + "user": { + "type": "string", + }, + "pass": { + "type": "string", + }, + }, + }, + "secure": { "type": "boolean", "default": false }, - "subscriptionId": { - "type": "string", + "ignoreTLS": { + "type": "boolean", }, - "port": { - "type": "integer", - "default": 8080 - }, - "passwordType": { - "type": "string", - "enum": [ - "sha256", - "sha512", - "md5" - ], - "default": "sha256" - }, - "addStorage": { - "type": "array", - "format": "table", - "title": "Additional Storage", - "description": "Separate storage locations that can be set for different monitors.", - "uniqueItems": true, - "items": { - "type": "object", - "title": "Storage Array", - "properties": { - "name": { - "type": "string", - }, - "path": { - "type": "string", - "default": "__DIR__/videos2" - } - } + "requireTLS": { + "type": "boolean", }, - "default": [ - { - "name": "second", - "path": "__DIR__/videos2" - } - ] - }, - "plugins": { - "type": "array", - "format": "table", - "title": "Plugins", - "descripton": "Elaborate Plugin connection settings.", - "uniqueItems": true, - "items": { - "type": "object", - "title": "Plugin", - "properties": { - "plug": { - "type": "string", - "default": "pluginName" - }, - "key": { - "type": "string" - }, - "mode": { - "type": "string", - "enum": [ - "host", - "client" - ], - "default": "client" - }, - "https": { - "type": "boolean", - "descripton": "Only for Host mode.", - "default": false - }, - "host": { - "type": "string", - "descripton": "Only for Host mode.", - "default": "localhost" - }, - "port": { - "type": "integer", - "descripton": "Only for Host mode.", - "default": 8082 - }, - "type": { - "type": "string", - "default": "detector" - } - } - }, - "default": [ - { - "name": "second", - "path": "__DIR__/videos2" - } - ] - }, - "pluginKeys": { - "type": "object", - "format": "table", - "title": "Plugin Keys", - "description": "Quick client connection setup for plugins. Just add the plugin key to make it ready for incoming connections.", - "uniqueItems": true, - "items": { - "type": "object", - "title": "Plugin Key", - "properties": {} + "port": { + "type": "integer", } - }, - "db": { - "type": "object", - "format": "table", - "title": "Database Options", - "description": "Credentials to connect to where detailed information is stored.", - "properties": { - "host": { - "type": "string", - "default": "127.0.0.1" - }, - "user": { - "type": "string", - "default": "majesticflame" - }, - "password": { - "type": "string", - "default": "" - }, - "database": { - "type": "string", - "default": "ccio" - }, - "port": { - "type": "integer", - "default": 3306 - } - }, - "default": { - "host": "127.0.0.1", - "user": "majesticflame", - "password": "", - "database": "ccio", - "port":3306 - } - }, - "cron": { - "type": "object", - "format": "table", - "title": "CRON Options", - "properties": { - "key": { - "type": "string", - }, - "deleteOld": { - "type": "boolean", - "description": "cron will delete videos older than Max Number of Days per account.", - "default": true - }, - "deleteNoVideo": { - "type": "boolean", - "description": "cron will delete SQL rows that it thinks have no video files.", - "default": true - }, - "deleteOverMax": { - "type": "boolean", - "description": "cron will delete files that are over the set maximum storage per account.", - "default": true - }, - } - }, - "mail": { - "type": "object", - "format": "table", - "title": "Email Options", - "properties": { - "service": { - "type": "string", - }, - "host": { - "type": "string", - }, - "auth": { - "type": "object", - "properties": { - "user": { - "type": "string", - }, - "pass": { - "type": "string", - }, - }, - }, - "secure": { - "type": "boolean", - "default": false - }, - "ignoreTLS": { - "type": "boolean", - }, - "requireTLS": { - "type": "boolean", - }, - "port": { - "type": "integer", - } - } - }, - "detectorMergePamRegionTriggers": { - "type": "boolean", - "default": true - }, - "doSnapshot": { - "type": "boolean", - "default": true - }, - "discordBot": { - "type": "boolean", - "default": false - }, - "dropInEventServer": { - "type": "boolean", - "default": false - }, - "ftpServer": { - "type": "boolean", - "default": false - }, - "oldPowerVideo": { - "type": "boolean", - "default": false - }, - "wallClockTimestampAsDefault": { - "type": "boolean", - "default": true - }, - "defaultMjpeg": { - "type": "string", - }, - "streamDir": { - "type": "string", - }, - "videosDir": { - "type": "string", - }, - "windowsTempDir": { - "type": "string", } + }, + "detectorMergePamRegionTriggers": { + "type": "boolean", + "default": true + }, + "doSnapshot": { + "type": "boolean", + "default": true + }, + "discordBot": { + "type": "boolean", + "default": false + }, + "dropInEventServer": { + "type": "boolean", + "default": false + }, + "ftpServer": { + "type": "boolean", + "default": false + }, + "oldPowerVideo": { + "type": "boolean", + "default": false + }, + "wallClockTimestampAsDefault": { + "type": "boolean", + "default": true + }, + "defaultMjpeg": { + "type": "string", + }, + "streamDir": { + "type": "string", + }, + "videosDir": { + "type": "string", + }, + "windowsTempDir": { + "type": "string", + }, + "enableFaceManager": { + "type": "boolean", + "default": false, + "title": "Enable Face Manager", + "description": "Enable / Disable face manager for face recognition plugins in the dashboard." } - }; + } + }; - var configurationTab = $('#config') - var configurationForm = configurationTab.find('form') + const configurationTab = $("#config"); + const configurationForm = configurationTab.find("form"); - // Set default options - JSONEditor.defaults.options.theme = 'bootstrap3'; - JSONEditor.defaults.options.iconlib = 'fontawesome4'; + const moduleData = { + endpoint: null, + configurationEditor: null + } - // Initialize the editor - var configurationEditor = new JSONEditor(document.getElementById("configForHumans"),{ - theme: 'bootstrap3', - schema: schema + const handleGetConfigurationData = data => { + const dataConfig = data.config; + const dataConfigKeys = Object.keys(dataConfig); + const schemaItemsKeys = Object.keys(schema.properties); + + const schemaWithoutData = schemaItemsKeys.filter( + (sk) => !dataConfigKeys.includes(sk) + ); + const dataWithoutSchema = dataConfigKeys.filter( + (dk) => !schemaItemsKeys.includes(dk) + ); + + schemaWithoutData.forEach((sk) => { + const schemaItem = schema.properties[sk]; + const defaultConfig = schemaItem.default; + + data.config[sk] = defaultConfig; }); - function loadConfiguationIntoEditor(){ - $.get(superApiPrefix + $user.sessionKey + '/system/configure',function(data){ - configurationEditor.setValue(data.config); - }) + if (dataWithoutSchema.length > 0) { + dataWithoutSchema.forEach((dk) => { + const schemaItem = { + title: dk, + options: { + hidden: true, + }, + }; + + schema.properties[dk] = schemaItem; + }); + + // Set default options + JSONEditor.defaults.options.theme = "bootstrap3"; + JSONEditor.defaults.options.iconlib = "fontawesome4"; } - // configurationEditor.on("change", function() { - // // Do something... - // }); - 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(){ - $.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; }) From f6c34befa22019f149fe78497893ee77f7237289 Mon Sep 17 00:00:00 2001 From: Moe Date: Thu, 6 Apr 2023 12:10:38 -0700 Subject: [PATCH 15/19] add protocol prefix to s3-based endpoint --- libs/uploaders/s3based.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/uploaders/s3based.js b/libs/uploaders/s3based.js index c800bd7a..34c053be 100644 --- a/libs/uploaders/s3based.js +++ b/libs/uploaders/s3based.js @@ -70,6 +70,9 @@ module.exports = function(s,config,lang){ if(!userDetails.whcs_endpoint ){ userDetails.whcs_endpoint = 's3.wasabisys.com' } + if(userDetails.whcs_endpoint.indexOf('://') === -1){ + userDetails.whcs_endpoint = `https://${userDetails.whcs_endpoint}` + } s.group[e.ke].whcs = new S3Client({ endpoint: userDetails.whcs_endpoint, credentials: { From 0f4b4321afbd9d3364bc4edfe7c904041c053d91 Mon Sep 17 00:00:00 2001 From: Felix Eckhofer Date: Sat, 8 Apr 2023 16:44:41 +0200 Subject: [PATCH 16/19] Allow docker image to run as non-root --- Docker/init.sh | 2 +- Dockerfile | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 From 1ca8edd78b46cda101badd1e9a6096a6501cbb11 Mon Sep 17 00:00:00 2001 From: Moe Date: Tue, 11 Apr 2023 13:02:43 -0700 Subject: [PATCH 17/19] auto close snapshot worker after 10 seconds if left hanging --- libs/cameraThread/snapshot.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/cameraThread/snapshot.js b/libs/cameraThread/snapshot.js index ebc2ad8d..677bc656 100644 --- a/libs/cameraThread/snapshot.js +++ b/libs/cameraThread/snapshot.js @@ -45,7 +45,9 @@ const rawMonitorConfig = jsonData.rawMonitorConfig // var writeToStderr = function(text){ // process.stderr.write(Buffer.from(text)) // } - +var timeout = setTimeout(() => { + exitAction() +},10000) var snapProcess = spawn(ffmpegAbsolutePath,ffmpegCommandString,{detached: true}) snapProcess.stderr.on('data',(data)=>{ writeToStderr(data.toString()) @@ -54,6 +56,7 @@ snapProcess.stdout.on('data',(data)=>{ writeToStderr(data.toString()) }) snapProcess.on('close',function(data){ + clearTimeout(timeout) if(useIcon){ var iconStream = fs.createWriteStream(iconImageFile); var fileCopy = fs.createReadStream(temporaryImageFile).pipe(iconStream) From d627e1ce925967bd245024c7302d4407203b5b78 Mon Sep 17 00:00:00 2001 From: Moe Date: Wed, 19 Apr 2023 09:22:57 -0700 Subject: [PATCH 18/19] minor tuning to Power Video - add download button for currently playing videos - make it force all playing videos to be half the width of the container. This will force 2 playing videos per row rather than squishing all into 1 row. --- definitions/base.js | 12 ++++++++++++ web/assets/css/bs5.powerVideo.css | 2 +- web/assets/js/bs5.dashboard-base.js | 12 +++++++----- web/assets/js/bs5.powerVideo.js | 27 ++++++++++++++++++--------- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/definitions/base.js b/definitions/base.js index cf94ac10..104bda38 100644 --- a/definitions/base.js +++ b/definitions/base.js @@ -7962,6 +7962,18 @@ module.exports = function(s,config,lang){ isFormGroupGroup: true, 'section-class': 'text-center', "info": [ + { + "fieldType": "btn-group", + "normalWidth": true, + "btns": [ + { + "fieldType": "btn", + "class": `btn-success btn-sm`, + "attribute": `powerVideo-control="downloadPlaying" title="${lang['Download']}"`, + "btnContent": ``, + } + ], + }, { "fieldType": "btn-group", "normalWidth": true, diff --git a/web/assets/css/bs5.powerVideo.css b/web/assets/css/bs5.powerVideo.css index 3a7737d2..42f23544 100644 --- a/web/assets/css/bs5.powerVideo.css +++ b/web/assets/css/bs5.powerVideo.css @@ -40,7 +40,7 @@ #powerVideo .videoPlayer .videoPlayer-detection-info { position: absolute; padding: 20px 10px 20px 10px; - /* height: 100%; */ + height: 100%; width: 100%; top: 0; left: 0; diff --git a/web/assets/js/bs5.dashboard-base.js b/web/assets/js/bs5.dashboard-base.js index 5e489d56..a098f15d 100644 --- a/web/assets/js/bs5.dashboard-base.js +++ b/web/assets/js/bs5.dashboard-base.js @@ -875,11 +875,13 @@ function downloadJSON(jsonData,filename){ .attr('download',filename) [0].click() } -function downloadFile(downloadUrl,fileName){ - var a = document.createElement('a') - a.href = downloadUrl - a.download = fileName - a.click() +function downloadFile(url,filename) { + const link = document.createElement("a"); + link.href = url; + link.download = filename; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); } function notifyIfActionFailed(data){ if(data.ok === false){ diff --git a/web/assets/js/bs5.powerVideo.js b/web/assets/js/bs5.powerVideo.js index 71ee360f..00a55b3c 100644 --- a/web/assets/js/bs5.powerVideo.js +++ b/web/assets/js/bs5.powerVideo.js @@ -456,12 +456,7 @@ $(document).ready(function(e){ motionMeterProgressBarTextBox.text('0') } function resetWidthForActiveVideoPlayers(){ - var numberOfMonitors = 0 - powerVideoMonitorViewsElement.find(`.videoPlayer .videoNow`).each(function(n,videoEl){ - if(videoEl.currentTime > 0)numberOfMonitors += 1 - }) - var widthOfBlock = 100 / numberOfMonitors - powerVideoMonitorViewsElement.find('.videoPlayer').css('width',`${widthOfBlock}%`) + powerVideoMonitorViewsElement.find('.videoPlayer').css('width',`49.8%`) } function loadVideoIntoMonitorSlot(video,selectedTime){ if(!video)return @@ -472,11 +467,10 @@ $(document).ready(function(e){ // if(numberOfMonitors > 3)numberOfMonitors = 3 //start new row after 3 if(numberOfMonitors == 1)numberOfMonitors = 2 //make single monitor not look like a doofus if(timeToStartAt < 0)timeToStartAt = 0 - var widthOfBlock = 100 / numberOfMonitors var videoContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${video.mid}] .videoPlayer-buffers`) if(videoContainer.length === 0){ if(!monitorSlotPlaySpeeds)monitorSlotPlaySpeeds[video.mid] = {} - powerVideoMonitorViewsElement.append(`
    + powerVideoMonitorViewsElement.append(`
    @@ -488,7 +482,7 @@ $(document).ready(function(e){
    `) videoContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${video.mid}] .videoPlayer-buffers`) }else{ - powerVideoMonitorViewsElement.find('.videoPlayer').css('width',`${widthOfBlock}%`) + powerVideoMonitorViewsElement.find('.videoPlayer').css('width',`49.8%`) } var videoCurrentNow = videoContainer.find('.videoNow') var videoCurrentAfter = videoContainer.find('.videoAfter') @@ -675,6 +669,18 @@ $(document).ready(function(e){ }) lastPowerVideoSelectedMonitors = ([]).concat(monitorIdsSelectedNow || []) } + function getFilenameFromUrl(url) { + const parts = url.split("/"); + return parts[parts.length - 1]; + } + function downloadAllPlayingVideos(){ + getAllActiveVideosInSlots().each(function(n,video){ + if(video.currentSrc){ + var filename = getFilenameFromUrl(video.currentSrc) + downloadFile(video.currentSrc,filename) + } + }) + } powerVideoMonitorsListElement.on('change','input',onPowerVideoSettingsChange); powerVideoVideoLimitElement.change(onPowerVideoSettingsChange); powerVideoEventLimitElement.change(onPowerVideoSettingsChange); @@ -689,6 +695,9 @@ $(document).ready(function(e){ var el = $(this) var controlType = el.attr('powerVideo-control') switch(controlType){ + case'downloadPlaying': + downloadAllPlayingVideos() + break; case'toggleMute': toggleMute() break; From 175fe8491b2b9cd28a97dcfe7e3b396aada95c3a Mon Sep 17 00:00:00 2001 From: Moe Date: Wed, 19 Apr 2023 10:04:10 -0700 Subject: [PATCH 19/19] Add Single Download and View to Power Viewer --- web/assets/css/bs5.powerVideo.css | 6 +++++ web/assets/js/bs5.dashboard-base.js | 4 +++ web/assets/js/bs5.powerVideo.js | 41 ++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/web/assets/css/bs5.powerVideo.css b/web/assets/css/bs5.powerVideo.css index 42f23544..c3596f2a 100644 --- a/web/assets/css/bs5.powerVideo.css +++ b/web/assets/css/bs5.powerVideo.css @@ -183,3 +183,9 @@ #powerVideo .vis-labelset .vis-label { color: #fff; } + +#powerVideo .videoPlayer-detection-info-buttons { + position: absolute; + top: 5px; + right: 5px; +} diff --git a/web/assets/js/bs5.dashboard-base.js b/web/assets/js/bs5.dashboard-base.js index a098f15d..eca99660 100644 --- a/web/assets/js/bs5.dashboard-base.js +++ b/web/assets/js/bs5.dashboard-base.js @@ -883,6 +883,10 @@ function downloadFile(url,filename) { link.click(); document.body.removeChild(link); } +function getFilenameFromUrl(url) { + const parts = url.split("/"); + return parts[parts.length - 1]; +} function notifyIfActionFailed(data){ if(data.ok === false){ new PNotify({ diff --git a/web/assets/js/bs5.powerVideo.js b/web/assets/js/bs5.powerVideo.js index 00a55b3c..3bbe57ac 100644 --- a/web/assets/js/bs5.powerVideo.js +++ b/web/assets/js/bs5.powerVideo.js @@ -472,6 +472,10 @@ $(document).ready(function(e){ if(!monitorSlotPlaySpeeds)monitorSlotPlaySpeeds[video.mid] = {} powerVideoMonitorViewsElement.append(`
    +
    + + +
    @@ -566,9 +570,15 @@ $(document).ready(function(e){ var selectedMonitors = Object.keys(form).filter(key => form[key] == '1') return selectedMonitors } + function getActiveVideoInSlot(monitorId){ + return powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid="${monitorId}"] video.videoNow`)[0] + } function getAllActiveVideosInSlots(){ return powerVideoMonitorViewsElement.find('video.videoNow') } + function getActiveVideoRow(monitorId){ + return currentlyPlayingVideos[monitorId] + } function pauseAllSlots(){ getAllActiveVideosInSlots().each(function(n,video){ if(!video.paused)video.pause() @@ -669,18 +679,27 @@ $(document).ready(function(e){ }) lastPowerVideoSelectedMonitors = ([]).concat(monitorIdsSelectedNow || []) } - function getFilenameFromUrl(url) { - const parts = url.split("/"); - return parts[parts.length - 1]; + function downloadPlayingVideo(video){ + if(video.currentSrc){ + var filename = getFilenameFromUrl(video.currentSrc) + downloadFile(video.currentSrc,filename) + } } function downloadAllPlayingVideos(){ getAllActiveVideosInSlots().each(function(n,video){ - if(video.currentSrc){ - var filename = getFilenameFromUrl(video.currentSrc) - downloadFile(video.currentSrc,filename) - } + downloadPlayingVideo(video) }) } + function openVideoPlayerTabFromViewer(el){ + var monitorId = el.attr('data-mid') || el.parents('[data-mid]').attr('data-mid') + var video = getActiveVideoRow(monitorId) + createVideoPlayerTab(video) + } + function downloadPlayingVideoTabFromViewer(el){ + var monitorId = el.attr('data-mid') || el.parents('[data-mid]').attr('data-mid') + var video = getActiveVideoInSlot(monitorId) + downloadPlayingVideo(video) + } powerVideoMonitorsListElement.on('change','input',onPowerVideoSettingsChange); powerVideoVideoLimitElement.change(onPowerVideoSettingsChange); powerVideoEventLimitElement.change(onPowerVideoSettingsChange); @@ -695,6 +714,14 @@ $(document).ready(function(e){ var el = $(this) var controlType = el.attr('powerVideo-control') switch(controlType){ + // single video affected + case'downloadVideo': + downloadPlayingVideoTabFromViewer(el) + break; + case'openVideoPlayer': + openVideoPlayerTabFromViewer(el) + break; + // all videos affected case'downloadPlaying': downloadAllPlayingVideos() break;