From d35b146e7be5a647c0cd2ea7b124745fa80be6a7 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Fri, 6 Jan 2023 11:39:49 +0200 Subject: [PATCH 01/22] upgrade jade to pug & eslint fixes --- app.js | 12 +- downloading/download.js | 3 +- downloading/yt-dlp-download.js | 14 +- lib/transcribing.js | 20 +- lib/websockets.js | 12 +- package-lock.json | 2467 +++++++++-------- package.json | 10 +- queue/newQueue.js | 36 +- queue/queue.js | 8 +- routes/admin.js | 8 +- routes/api.js | 15 +- routes/index.js | 2 +- routes/player.js | 10 +- routes/transcribe.js | 6 +- transcribe/transcribe-wrapped.js | 16 +- ...addTranslation.jade => addTranslation.pug} | 0 views/{admin.jade => admin.pug} | 0 views/{error.jade => error.pug} | 0 views/{files.jade => files.pug} | 0 ...amounts-header.jade => amounts-header.pug} | 0 ...social-buttons.jade => social-buttons.pug} | 0 ...results.jade => transcription-results.pug} | 0 .../{upload-form.jade => upload-form.pug} | 0 views/index/index.jade | 23 - views/index/index.pug | 23 + ...error-handling.jade => error-handling.pug} | 0 .../{file-handling.jade => file-handling.pug} | 0 ...ork-handling.jade => network-handling.pug} | 0 ...dropdowns.jade => selection-dropdowns.pug} | 0 .../index/js/{js-index.jade => js-index.pug} | 10 +- views/index/js/{js-util.jade => js-util.pug} | 0 ...-header.jade => styles-amounts-header.pug} | 0 .../{styles-form.jade => styles-form.pug} | 0 .../{styles-social.jade => styles-social.pug} | 0 ....jade => styles-transcription-results.pug} | 0 views/{layout.jade => layout.pug} | 0 ...ptionsDisplay.jade => captionsDisplay.pug} | 0 ...secondCaptions.jade => secondCaptions.pug} | 0 .../{videoProgress.jade => videoProgress.pug} | 0 views/player/{player.jade => player.pug} | 4 +- .../{styles-player.jade => styles-player.pug} | 0 views/{queue.jade => queue.pug} | 0 views/stats/{stats.jade => stats.pug} | 0 .../{styles-global.jade => styles-global.pug} | 0 44 files changed, 1360 insertions(+), 1339 deletions(-) rename views/addTranslation/{addTranslation.jade => addTranslation.pug} (100%) rename views/{admin.jade => admin.pug} (100%) rename views/{error.jade => error.pug} (100%) rename views/{files.jade => files.pug} (100%) rename views/index/components/{amounts-header.jade => amounts-header.pug} (100%) rename views/index/components/{social-buttons.jade => social-buttons.pug} (100%) rename views/index/components/{transcription-results.jade => transcription-results.pug} (100%) rename views/index/components/{upload-form.jade => upload-form.pug} (100%) delete mode 100644 views/index/index.jade create mode 100644 views/index/index.pug rename views/index/js/controllers/{error-handling.jade => error-handling.pug} (100%) rename views/index/js/controllers/{file-handling.jade => file-handling.pug} (100%) rename views/index/js/controllers/{network-handling.jade => network-handling.pug} (100%) rename views/index/js/controllers/{selection-dropdowns.jade => selection-dropdowns.pug} (100%) rename views/index/js/{js-index.jade => js-index.pug} (98%) rename views/index/js/{js-util.jade => js-util.pug} (100%) rename views/index/styles/{styles-amounts-header.jade => styles-amounts-header.pug} (100%) rename views/index/styles/{styles-form.jade => styles-form.pug} (100%) rename views/index/styles/{styles-social.jade => styles-social.pug} (100%) rename views/index/styles/{styles-transcription-results.jade => styles-transcription-results.pug} (100%) rename views/{layout.jade => layout.pug} (100%) rename views/player/js/{captionsDisplay.jade => captionsDisplay.pug} (100%) rename views/player/js/{secondCaptions.jade => secondCaptions.pug} (100%) rename views/player/js/{videoProgress.jade => videoProgress.pug} (100%) rename views/player/{player.jade => player.pug} (99%) rename views/player/{styles-player.jade => styles-player.pug} (100%) rename views/{queue.jade => queue.pug} (100%) rename views/stats/{stats.jade => stats.pug} (100%) rename views/styles/{styles-global.jade => styles-global.pug} (100%) diff --git a/app.js b/app.js index 48b3705..a8e86b6 100644 --- a/app.js +++ b/app.js @@ -31,14 +31,14 @@ if (!fs.existsSync('.env')) { const hourInMilliseconds = 1000 * 60 * 60; -function runDeleteLoop() { +function runDeleteLoop () { setTimeout(() => { deleteOldFiles(true); runDeleteLoop(); }, hourInMilliseconds); // repeat every 1000 milliseconds (1 second) } -if(process.env.NODE_ENV === 'production'){ +if (process.env.NODE_ENV === 'production') { deleteOldFiles(true); runDeleteLoop(); } @@ -60,10 +60,10 @@ createWebSocketServer(server); l = console.log; -// l = function(l){ +// l = function(l) { // var stack = (new Error()).stack.split(/\n/); // // Chrome includes a single "Error" line, FF doesn't. -// if(stack[0].indexOf('Error') === 0){ +// if (stack[0].indexOf('Error') === 0) { // stack = stack.slice(1); // } // var args = [].slice.apply(arguments).concat([stack[1].trim()]); @@ -79,7 +79,7 @@ fs.mkdirSync('transcriptions', { recursive: true }) // view engine setup app.set('views', path.join(__dirname, 'views')); -app.set('view engine', 'jade'); +app.set('view engine', 'pug'); app.use(favicon(path.join(__dirname,'public','images','favicon.ico'))); app.use(logger('dev')); @@ -88,7 +88,7 @@ app.use(bodyParser.urlencoded({ extended: true, limit: '1mb' })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); // assumes nginx -// if(!isProd){ +// if (!isProd) { app.use(express.static(__dirname)); // } diff --git a/downloading/download.js b/downloading/download.js index e61f7e6..100789c 100644 --- a/downloading/download.js +++ b/downloading/download.js @@ -6,7 +6,8 @@ l = console.log; // async usage // rejects if not found -const ytDlpBinaryPath = which.sync('yt-dlp'); +const ytDlpName = process.platform === 'win32' ? 'YoutubeDL' : 'yt-dlp'; +const ytDlpBinaryPath = which.sync(ytDlpName); const ytDlpWrap = new YTDlpWrap(ytDlpBinaryPath); diff --git a/downloading/yt-dlp-download.js b/downloading/yt-dlp-download.js index 731e456..47731d0 100644 --- a/downloading/yt-dlp-download.js +++ b/downloading/yt-dlp-download.js @@ -7,11 +7,11 @@ const {formatStdErr} = require('../helpers/formatStdErr'); // yt-dlp --no-mtime -f '\''bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best'\'' const l = console.log; - -const ytDlpPath = which.sync('yt-dlp') +const ytDlpName = process.platform === 'win32' ? 'YoutubeDL' : 'yt-dlp'; +const ytDlpPath = which.sync(ytDlpName); // get data from youtube-dlp stdout string -function extractDataFromString(string){ +function extractDataFromString (string) { const percentDownloaded = parseInt(string.match(/(\d+\.?\d*)%/)[1]); const totalFileSize = string.match(/of\s+(.*?)\s+at/)[1]; const downloadSpeed = string.match(/at\s+(.*?)\s+ETA/)[1]; @@ -29,9 +29,9 @@ function extractDataFromString(string){ } // delete from transcription array (used to get rid of the yt-dlp process) -function deleteFromGlobalTranscriptionsBasedOnWebsocketNumber(websocketNumber) { +function deleteFromGlobalTranscriptionsBasedOnWebsocketNumber (websocketNumber) { // check for websocket number and type - function matchDownloadProcessByWebsocketNumber(transcriptionProcess){ + function matchDownloadProcessByWebsocketNumber (transcriptionProcess) { return transcriptionProcess.websocketNumber === websocketNumber && transcriptionProcess.type === 'download'; } @@ -64,7 +64,7 @@ async function downloadFile ({ l(latestDownloadInfo); // only run if ETA is in the string - if(!latestDownloadInfo.includes('ETA')) return + if (!latestDownloadInfo.includes('ETA')) return const { percentDownloaded, totalFileSize, downloadSpeed, fileSizeUnit, fileSizeValue } = extractDataFromString(latestDownloadInfo); @@ -154,7 +154,7 @@ async function downloadFileApi ({ l(latestDownloadInfo); // only run if ETA is in the string - if(!latestDownloadInfo.includes('ETA')) return + if (!latestDownloadInfo.includes('ETA')) return const { percentDownloaded, totalFileSize, downloadSpeed, fileSizeUnit, fileSizeValue } = extractDataFromString(latestDownloadInfo); currentPercentDownload = percentDownloaded; diff --git a/lib/transcribing.js b/lib/transcribing.js index 272254d..d5932f1 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -1,9 +1,9 @@ -const fs = require("fs-extra"); -const {autoDetectLanguage} = require("../transcribe/transcribing"); -const {formatStdErr} = require("../helpers/formatStdErr"); -const { getLanguageCodeForAllLanguages } = require("../constants/constants"); -const filenamify = require("filenamify"); -const path = require("path"); +const fs = require('fs-extra'); +const {autoDetectLanguage} = require('../transcribe/transcribing'); +const {formatStdErr} = require('../helpers/formatStdErr'); +const { getLanguageCodeForAllLanguages } = require('../constants/constants'); +const filenamify = require('filenamify'); +const path = require('path'); async function writeToProcessingDataFile (processingDataPath, dataObject) { // save data to the file @@ -74,9 +74,9 @@ function handleStdErr ({ const outputFileExtensions = ['.srt', '.vtt', '.txt'] // rename files to proper names for api (remove file extension) -async function moveFiles(randomNumber, fileExtension){ +async function moveFiles (randomNumber, fileExtension) { const holderFolder = `${process.cwd()}/transcriptions/${randomNumber}`; - for(const extension of outputFileExtensions){ + for (const extension of outputFileExtensions) { const oldLocation = `${holderFolder}/${randomNumber}.${fileExtension}${extension}` await fs.move(oldLocation, `${holderFolder}/${randomNumber}${extension}`) } @@ -92,7 +92,7 @@ function handleProcessClose ({ processingDataPath, originalUpload, randomNumber const processFinishedSuccessfullyBasedOnStatusCode = code === 0; // if process failed - if(!processFinishedSuccessfullyBasedOnStatusCode){ + if (!processFinishedSuccessfullyBasedOnStatusCode) { // if process errored out await writeToProcessingDataFile(processingDataPath, { status: 'error', @@ -142,7 +142,7 @@ const makeFileNameSafe = function (string) { } // -function createFileNames(originalFileName){ +function createFileNames (originalFileName) { // name of file without extension const originalFileNameWithoutExtension = path.parse(originalFileName).name; diff --git a/lib/websockets.js b/lib/websockets.js index 5bcfe23..b822a74 100644 --- a/lib/websockets.js +++ b/lib/websockets.js @@ -3,7 +3,7 @@ const WebSocketServer = WebSocket.WebSocketServer; const { getQueueInformationByWebsocketNumber } = require('../queue/newQueue'); const { updateQueueItemStatus } = require('../queue/queue'); -function deleteFromGlobalTranscriptionsBasedOnWebsocketNumber(websocketNumber) { +function deleteFromGlobalTranscriptionsBasedOnWebsocketNumber (websocketNumber) { // find transcription based on websocketNumber const closerTranscription = global['transcriptions'].find(function (transcription) { return transcription.websocketNumber === websocketNumber; @@ -17,10 +17,10 @@ function deleteFromGlobalTranscriptionsBasedOnWebsocketNumber(websocketNumber) { /** when websocket disconnects **/ -function deleteWebsocketAndEndProcesses({ websocketNumber, websocketConnection, websocket, index }) { +function deleteWebsocketAndEndProcesses ({ websocketNumber, websocketConnection, websocket, index }) { l(`Disconnected user found: ${websocketNumber}`); - function matchByWebsocketNumber(item) { + function matchByWebsocketNumber (item) { return item.websocketNumber === websocketNumber; } @@ -63,7 +63,7 @@ function deleteWebsocketAndEndProcesses({ websocketNumber, websocketConnection, sendOutQueuePositionUpdate(); } -function sendOutQueuePositionUpdate(){ +function sendOutQueuePositionUpdate () { // loop through websockets and tell them one less is processing for (let [, websocket] of global.webSocketData.entries() ) { // the actual websocket @@ -78,7 +78,7 @@ function sendOutQueuePositionUpdate(){ // l('queuePosition'); // l(queuePosition); - if(queuePosition) { + if (queuePosition) { websocketConnection.send(JSON.stringify({ message: 'queue', placeInQueue: queuePosition @@ -115,7 +115,7 @@ function checkForDeath () { } // run on first connection -function setupWebsocket(websocketConnection, request) { +function setupWebsocket (websocketConnection, request) { // random number generated from the frontend (last part of the hit url) const websocketNumber = request.url.split('/')[1]; diff --git a/package-lock.json b/package-lock.json index e84a68c..649a708 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,26 +10,26 @@ "dependencies": { "await-spawn": "^4.0.2", "axios": "^1.1.3", - "body-parser": "~1.13.2", + "body-parser": "^1.20.1", "cookie-parser": "~1.3.5", "cyrillic-to-latin": "^2.0.0", - "debug": "~2.2.0", + "debug": "^4.3.4", "dotenv": "^16.0.3", - "express": "~4.15.5", + "express": "^4.18.2", "express-session": "^1.17.3", "ffprobe": "^1.1.2", "filenamify": "^4.3.0", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "google-translate-api-browser": "^3.0.0", - "jade": "~1.11.0", "language-name-map": "^0.3.0", "lodash": "^4.17.21", "moment": "^2.29.4", - "morgan": "~1.6.1", + "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", "node-fetch": "^2.6.7", "promise-queue": "^2.2.5", + "pug": "^3.0.2", "serve-favicon": "^2.5.0", "srt2vtt": "^1.3.1", "which": "^3.0.0", @@ -41,6 +41,46 @@ "eslint": "^8.30.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", @@ -64,29 +104,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -101,29 +118,6 @@ "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -191,9 +185,9 @@ } }, "node_modules/acorn": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", - "integrity": "sha512-pXK8ez/pVjqFdAgBkF1YPVRacuLQ9EXBKaKWaeh58WNfMkCmZhOZzu+NtKSPD5PHmCCHheQ5cD29qM1K4QTxIg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "bin": { "acorn": "bin/acorn" }, @@ -201,14 +195,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-globals": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", - "integrity": "sha512-j3/4pkfih8W4NK22gxVSXcEonTpAHOHh0hu5BoZrKcOsW/4oBPxTi4Yk3SAj+FhC1f3+bRTkXdm4019gw1vg9g==", - "dependencies": { - "acorn": "^2.1.0" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -225,27 +211,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", - "dependencies": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", - "engines": { - "node": ">=0.4.2" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -287,9 +252,14 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/asap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", - "integrity": "sha512-Ej9qjcXY+8Tuy1cNqiwNMwFRXOy9UwgTeMA8LxreodygIPV48lx8PU1ecFxb5ZeU1DpMKxiq6vGLTxcitWZPbA==" + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "node_modules/assert-never": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", + "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" }, "node_modules/asynckit": { "version": "0.4.0", @@ -317,6 +287,17 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -343,11 +324,14 @@ ] }, "node_modules/basic-auth": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz", - "integrity": "sha512-uvq3I/zC5TmG0WZJDzsXzIytU9GiiSq23Gl27Dq9sV81JTfPfQhtdADECP1DJZeJoZPuYU0Y81hWC5y/dOR+Yw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/bl": { @@ -374,20 +358,47 @@ } }, "node_modules/body-parser": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz", - "integrity": "sha512-ypX8/9uws2W+CjPp3QMmz1qklzlhRBknQve22Y+WFecHql+qDFfG+VVNX7sooA4Q3+2fdq4ZZj6Xr07gA90RZg==", - "dependencies": { - "bytes": "2.1.0", - "content-type": "~1.0.1", - "debug": "~2.2.0", - "depd": "~1.0.1", - "http-errors": "~1.3.1", - "iconv-lite": "0.4.11", - "on-finished": "~2.3.0", - "qs": "4.0.0", - "raw-body": "~2.1.2", - "type-is": "~1.6.6" + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" }, "engines": { "node": ">= 0.8" @@ -443,9 +454,24 @@ } }, "node_modules/bytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz", - "integrity": "sha512-k9VSlRfRi5JYyQWMylSOgjld96ta1qaQUIvmn+na0BzViclH04PBumewv4z5aeXNkn6Z/gAN5FtPeBLvV20F9w==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/callsites": { "version": "3.1.0", @@ -456,26 +482,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", - "dependencies": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -493,44 +499,11 @@ } }, "node_modules/character-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz", - "integrity": "sha512-6OEBVBlf/y8LaAphnbAnt743O3zMhlBer+FO5D40H6wqAdU9B1TvuApkejgLW0cvv0tEZNLktv1AnRI+C87ueQ==" - }, - "node_modules/clean-css": { - "version": "3.4.28", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", - "integrity": "sha512-aTWyttSdI2mYi07kWqHi24NUU9YlELFKGOAgFzZjDN1064DMAOy2FBuoyGmkKRlXkbpXd0EVHmiVkbKhKoirTw==", - "dependencies": { - "commander": "2.8.x", - "source-map": "0.4.x" - }, - "bin": { - "cleancss": "bin/cleancss" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clean-css/node_modules/commander": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", - "integrity": "sha512-+pJLBFVk+9ZZdlAOB5WuIElVPPth47hILFkmGym57aq8kwxsowvByvB0DHs1vQAhyMZzdcpTtF0VDKGkSDR4ZQ==", - "dependencies": { - "graceful-readlink": ">= 1.0.0" - }, - "engines": { - "node": ">= 0.6.x" - } - }, - "node_modules/cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", "dependencies": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" + "is-regex": "^1.0.3" } }, "node_modules/codepage": { @@ -608,22 +581,44 @@ } }, "node_modules/constantinople": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", - "integrity": "sha512-UnEggAQrmhxuTxlb7n1OsTtagNXWUv2CRlOogZhWOU4jLK4EJEbF8UDSNxuGu+jVtWNtO2j51ab2H1wlBIzF/w==", - "deprecated": "Please update to at least constantinople 3.1.1", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", "dependencies": { - "acorn": "^2.1.0" + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" } }, "node_modules/content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, "engines": { "node": ">= 0.6" } }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -691,46 +686,32 @@ "node": ">= 8" } }, - "node_modules/css": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", - "integrity": "sha512-qmTYWhHk910nQWnGqMAiWWPQlB6tESiWgNebQJmiozOAGcBAQ1+U/UzUOkhdrcshlkSRRiKWodwmVvO0OmnIGg==", - "dependencies": { - "css-parse": "1.0.4", - "css-stringify": "1.0.5" - } - }, - "node_modules/css-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", - "integrity": "sha512-pfstzKVRZiHprDXdsmtfH1HYUEw22lzjuHdnpe1hscwoQvgW2C5zDQIBE0RKoALEReTn9W1ECdY8uaT/kO4VfA==" - }, - "node_modules/css-stringify": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", - "integrity": "sha512-aIThpcErhG5EyHorGqNlTh0TduNBqLrrXLO3x5rku3ZKBxuVfY+T7noyM2G2X/01iQANqJUb6d3+FLoa+N7Xwg==" - }, "node_modules/cyrillic-to-latin": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cyrillic-to-latin/-/cyrillic-to-latin-2.0.0.tgz", "integrity": "sha512-8hljBJfU3cKuBa0IkOTb95/U9OV/BKuwyqUd6mIvziiJ6JYRt0KSXAYz2Z7k60AqBPPc+3UBl5nHN8b7WAIWuQ==" }, "node_modules/debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha512-X0rGvJcskG1c3TgSCPqHJ0XJgwlcvOC7elJ5Y0hYuKBZoVqWpAMfLOeIh2UI/DCQ5ruodIjvsugZtjUYUw2pUw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "ms": "0.7.1" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "ms": "2.1.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -754,17 +735,21 @@ } }, "node_modules/depd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", - "integrity": "sha512-OEWAMbCkK9IWQ8pfTvHBhCSqHgR+sk5pbiYqq0FqfARG4Cy+cRsCbITx6wh5pcsmfBPiJAcbd98tfdz5fnBbag==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/doctrine": { "version": "3.0.0", @@ -778,6 +763,11 @@ "node": ">=6.0.0" } }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==" + }, "node_modules/dotenv": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", @@ -917,23 +907,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -946,12 +919,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/espree": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", @@ -1049,38 +1016,41 @@ } }, "node_modules/express": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/express/-/express-4.15.5.tgz", - "integrity": "sha512-E5kemI7MqPbkLstU1xLG3VB7TgSRyJu4N765mQinL9agWiD5HzpK5IZTUYuqd8m0M8A8ReM23xBqcwiSzrDRGQ==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { - "accepts": "~1.3.3", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "content-disposition": "0.5.2", - "content-type": "~1.0.2", - "cookie": "0.3.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.1", - "encodeurl": "~1.0.1", + "depd": "2.0.0", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "etag": "~1.8.0", - "finalhandler": "~1.0.6", + "etag": "~1.8.1", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.1", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~1.1.5", - "qs": "6.5.0", - "range-parser": "~1.2.0", - "send": "0.15.6", - "serve-static": "1.12.6", - "setprototypeof": "1.0.3", - "statuses": "~1.3.1", - "type-is": "~1.6.15", - "utils-merge": "1.0.0", - "vary": "~1.1.1" + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "engines": { "node": ">= 0.10.0" @@ -1120,14 +1090,6 @@ "ms": "2.0.0" } }, - "node_modules/express-session/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/express-session/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1153,9 +1115,9 @@ ] }, "node_modules/express/node_modules/cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "engines": { "node": ">= 0.6" } @@ -1168,34 +1130,40 @@ "ms": "2.0.0" } }, - "node_modules/express/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/express/node_modules/qs": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", - "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg==", + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { - "node": ">=0.6" + "node": ">= 0.8" } }, - "node_modules/express/node_modules/statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", - "engines": { - "node": ">= 0.6" - } + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -1271,16 +1239,16 @@ } }, "node_modules/finalhandler": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", - "integrity": "sha512-immlyyYCPWG2tajlYBhZ6cjLAv1QAclU8tKS0d27ZtPqm/+iddy16GT3xLExg+V4lIETLpPwaYQAlZHNE//dPA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.1", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { @@ -1300,12 +1268,15 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/finalhandler/node_modules/statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/find-up": { @@ -1376,9 +1347,9 @@ } }, "node_modules/forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha512-Ua9xNhH0b8pwE3yRbFfXJvfdWF0UHNCdeyb2sbi9Ul/M+r3PTdrz7Cv4SCfZRMjmzEM9PhraqfZFbGTIg3OMyA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "engines": { "node": ">= 0.6" } @@ -1410,6 +1381,24 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -1467,17 +1456,23 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, - "node_modules/graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==" - }, "node_modules/grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1487,24 +1482,55 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/http-errors": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", - "integrity": "sha512-gMygNskMurDCWfoCdyh1gOeDfSbkAHXqz94QoPj5IHIUjC/BG8/xv7FSEUr7waR5RcAya4j58bft9Wu/wHNeXA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "inherits": "~2.0.1", - "statuses": "1" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/iconv-lite": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz", - "integrity": "sha512-8UmnaYeP5puk18SkBrYULVTiq7REcimhx+ykJVJBiaz89DQmVQAfS29ZhHah86la90/t0xy4vRk86/2cCwNodA==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, "engines": { - "node": ">=0.8.0" + "node": ">=0.10.0" } }, "node_modules/ieee754": { @@ -1576,17 +1602,32 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ipaddr.js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", - "integrity": "sha512-RbrsPoo4IkisyHhS9VDa3ybxnu0wOo0uTAhaELmwxq244p18X7Dk0fQoJvh/QTkIUO296fbjgvMqK3ry84eVVA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "engines": { "node": ">= 0.10" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } }, "node_modules/is-extglob": { "version": "2.1.1", @@ -1623,6 +1664,21 @@ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1633,38 +1689,6 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "node_modules/jade": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", - "integrity": "sha512-J76sbGKeLtu7uwW97Ntzb1UvGnpKTDplYa9ROr2gNRhM+SxvlBSG0Ees3TQ8+7ya2UVkzMEeFxhRhEpN68s7Tg==", - "deprecated": "Jade has been renamed to pug, please install the latest version of pug instead of jade", - "dependencies": { - "character-parser": "1.2.1", - "clean-css": "^3.1.9", - "commander": "~2.6.0", - "constantinople": "~3.0.1", - "jstransformer": "0.0.2", - "mkdirp": "~0.5.0", - "transformers": "2.1.0", - "uglify-js": "^2.4.19", - "void-elements": "~2.0.1", - "with": "~4.0.0" - }, - "bin": { - "jade": "bin/jade.js" - } - }, - "node_modules/jade/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -1675,6 +1699,11 @@ "url": "https://opencollective.com/js-sdsl" } }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -1734,23 +1763,12 @@ } }, "node_modules/jstransformer": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", - "integrity": "sha512-b7tmf91j1ChMuYhwbPBnNgB62dmHuqiHpOdd6QLKzde8HydZqm+ud3qWreGWecSxPBFFNOf1Ozjx0xo2plFdHA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", "dependencies": { "is-promise": "^2.0.0", - "promise": "^6.0.1" - } - }, - "node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" + "promise": "^7.0.1" } }, "node_modules/language-name-map": { @@ -1758,14 +1776,6 @@ "resolved": "https://registry.npmjs.org/language-name-map/-/language-name-map-0.3.0.tgz", "integrity": "sha512-uoBHtfY6h4S2RoIpyqvQGhynX2hshQu/9S4ySbppGxG5VwEsiWZJ83xSjzx25Mb+Bmc+WxpQC0H54eNZVMWLuA==" }, - "node_modules/lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1805,14 +1815,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1835,11 +1837,14 @@ } }, "node_modules/mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha512-sAaYXszED5ALBt665F0wMQCUXpGuZsGdopoqcHPdL39ZYdi7uHoZlhrfZfhv8WzivhBzr/oXwaj+yiK5wY8MXQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "bin": { "mime": "cli.js" + }, + "engines": { + "node": ">=4" } }, "node_modules/mime-db": { @@ -1881,6 +1886,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -1890,24 +1906,37 @@ } }, "node_modules/morgan": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.6.1.tgz", - "integrity": "sha512-WWxlTx5xCqbtSeX/gPVHUZBhAhSMfYQLgPrWHEN0FYnF+zf1Ju/Zct6rpeKmvzibrYF4QvFVws7IN61BxnKu+Q==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "dependencies": { - "basic-auth": "~1.0.3", - "debug": "~2.2.0", - "depd": "~1.0.1", + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.0" + "on-headers": "~1.0.2" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha512-lRLiIR9fSNpnP6TC4v8+4OU7oStC01esuNowdQ34L+Gk8e5Puoc88IqJ+XAY/B3Mn2ZKis8l8HX90oU8ivzUHg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/multer": { "version": "1.4.5-lts.1", @@ -1926,17 +1955,6 @@ "node": ">= 6.0.0" } }, - "node_modules/multer/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/native-promise-only": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", @@ -1983,6 +2001,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -2011,14 +2037,6 @@ "wrappy": "1" } }, - "node_modules/optimist": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", - "dependencies": { - "wordwrap": "~0.0.2" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -2113,6 +2131,11 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -2133,11 +2156,11 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "node_modules/promise": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", - "integrity": "sha512-O+uwGKreKNKkshzZv2P7N64lk6EP17iXBn0PbUnNQhk+Q0AHLstiTrjkx3v5YBd3cxUe7Sq6KyRhl/A0xUjk7Q==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "dependencies": { - "asap": "~1.0.0" + "asap": "~2.0.3" } }, "node_modules/promise-queue": { @@ -2149,15 +2172,15 @@ } }, "node_modules/proxy-addr": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", - "integrity": "sha512-av1MQ5vwTiMICwU75KSf/vJ6a+AXP0MtP+aYBqm2RFlire7BP6sWlfOLc8+6wIQrywycqSpJWm5zNkYFkRARWA==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dependencies": { - "forwarded": "~0.1.0", - "ipaddr.js": "1.4.0" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.10" } }, "node_modules/proxy-from-env": { @@ -2165,6 +2188,118 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/pug": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", + "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==", + "dependencies": { + "pug-code-gen": "^3.0.2", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "node_modules/pug-code-gen": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz", + "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.0.0", + "pug-runtime": "^3.0.0", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "node_modules/pug-error": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" + }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "dependencies": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "dependencies": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==" + }, + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dependencies": { + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -2175,9 +2310,18 @@ } }, "node_modules/qs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", - "integrity": "sha512-8MPmJ83uBOPsQj5tQCv4g04/nTiY+d17yl9o3Bw73vC6XlEm2POIRRlOgWJ8i74bkGLII670cDJJZkgiZ2sIkg==" + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -2216,31 +2360,19 @@ } }, "node_modules/raw-body": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", - "integrity": "sha512-x4d27vsIG04gZ1imkuDXB9Rd/EkAx5kYzeMijIYw1PAor0Ld3nTlkQQwDjKu42GdRUFCX1AfGnTSQB4O57eWVg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dependencies": { - "bytes": "2.4.0", - "iconv-lite": "0.4.13", + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "engines": { "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", - "integrity": "sha512-SvUX8+c/Ga454a4fprIdIUzUN9xfd1YTvYh7ub5ZPJ+ZJ/+K2Bp6IpWGmnw8r3caLTsmhvJAKZz3qjIo9+XuCQ==" - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", - "integrity": "sha512-QwVuTNQv7tXC5mMWFX5N5wGjmybjNBBD8P3BReTkPmipoxTUFgWM2gXNvldHQr6T14DH0Dh6qBVg98iJt7u4mQ==", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -2267,12 +2399,20 @@ "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "engines": { - "node": ">=0.10" + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-from": { @@ -2294,17 +2434,6 @@ "node": ">=0.10.0" } }, - "node_modules/right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", - "dependencies": { - "align-text": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -2348,24 +2477,29 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/send": { - "version": "0.15.6", - "resolved": "https://registry.npmjs.org/send/-/send-0.15.6.tgz", - "integrity": "sha512-e1/758VJ+GsPg8vE+Z/xE7R36IWogUl8rrrs53CsfHrT2IyZyPggfvbHT8HTV3yBNKrUHYUTsBQ9pXQYkcB4YQ==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { "debug": "2.6.9", - "depd": "~1.1.1", - "destroy": "~1.0.4", - "encodeurl": "~1.0.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.3.4", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.3.1" + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" @@ -2379,57 +2513,20 @@ "ms": "2.0.0" } }, - "node_modules/send/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/http-errors/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" - }, - "node_modules/send/node_modules/ms": { + "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/send/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "node_modules/send/node_modules/statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/serve-favicon": { @@ -2458,23 +2555,23 @@ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "node_modules/serve-static": { - "version": "1.12.6", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.6.tgz", - "integrity": "sha512-M2CMkmVnR22x7taVSeYGdfIhnh/mhanPZqqBCSRAvVZNkrhaOpOLlwimKpJR+NhFpD/8Dr9G0YpAtkDkCcAVJQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { - "encodeurl": "~1.0.1", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.15.6" + "parseurl": "~1.3.3", + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha512-9jphSf3UbIgpOX/RKvX02iw/rN2TKdusnsPpGfO/rkcsrd+IRqgHZb4VGnmL0Cynps8Nj2hN45wsi30BzrHDIw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/shebang-command": { "version": "2.0.0", @@ -2497,15 +2594,17 @@ "node": ">=8" } }, - "node_modules/source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha512-Y8nIfcb1s/7DcobUz1yOO1GSp7gyL+D9zLHDehT7iRESqGSxjJ448Sg7rvfgsRJCnKLdSl11uGf0s9X80cH0/A==", + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dependencies": { - "amdefine": ">=0.0.4" + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" }, - "engines": { - "node": ">=0.8.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/srt2vtt": { @@ -2518,11 +2617,11 @@ } }, "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/streamsearch": { @@ -2588,6 +2687,17 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2599,61 +2709,32 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/transformers": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", - "integrity": "sha512-zJf5m2EIOngmBbDe2fhTPpCjzM2qkZVqrFJZc2jaln+KBeEaYKhS2QMOIkfVrNUyoOwqgbTwOHATzr3jZRQDyg==", - "deprecated": "Deprecated, use jstransformer", - "dependencies": { - "css": "~1.0.8", - "promise": "~2.0", - "uglify-js": "~2.2.5" - } - }, - "node_modules/transformers/node_modules/is-promise": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", - "integrity": "sha512-mjWH5XxnhMA8cFnDchr6qRP9S/kLntKuEfIYku+PaN1CnS8v+OG9O/BKpRCVRJvpIkgAZm0Pf5Is3iSSOILlcg==" - }, - "node_modules/transformers/node_modules/promise": { + "node_modules/to-fast-properties": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", - "integrity": "sha512-OgMc+sxI3zWF8D5BJGtA0z7/IsrDy1/0cPaDv6HPpqa2fSTo7AdON5U10NbZCUeF+zCAj3PtfPE50Hf02386aA==", - "dependencies": { - "is-promise": "~1" - } - }, - "node_modules/transformers/node_modules/source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", - "dependencies": { - "amdefine": ">=0.0.4" - }, + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "engines": { - "node": ">=0.8.0" + "node": ">=4" } }, - "node_modules/transformers/node_modules/uglify-js": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", - "integrity": "sha512-viLk+/8G0zm2aKt1JJAVcz5J/5ytdiNaIsKgrre3yvSUjwVG6ZUujGH7E2TiPigZUwLYCe7eaIUEP2Zka2VJPA==", - "dependencies": { - "optimist": "~0.3.5", - "source-map": "~0.1.7" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { - "node": ">=0.4.0" + "node": ">=0.6" } }, + "node_modules/token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/trim-repeated": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", @@ -2706,38 +2787,6 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, - "node_modules/uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", - "dependencies": { - "source-map": "~0.5.1", - "yargs": "~3.10.0" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - }, - "optionalDependencies": { - "uglify-to-browserify": "~1.0.0" - } - }, - "node_modules/uglify-js/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", - "optional": true - }, "node_modules/uid-safe": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", @@ -2788,9 +2837,9 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha512-HwU9SLQEtyo+0uoKXd1nkLqigUWLB+QuNQR4OcmB73eWqksM5ovuqcycks2x043W8XVb75rG1HQ0h93TMXkzQQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "engines": { "node": ">= 0.4.0" } @@ -2815,9 +2864,9 @@ } }, "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", "engines": { "node": ">=0.10.0" } @@ -2850,32 +2899,18 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/with": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", - "integrity": "sha512-mJZFpyEc1JTAdxhi/vhVeAM2S7vsltEKDiexDDo1HuAzlYKhcVUU6cwY8cHrFYdt82ZNkfKCeyhA3IYFegI0Kg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", "dependencies": { - "acorn": "^1.0.1", - "acorn-globals": "^1.0.3" - } - }, - "node_modules/with/node_modules/acorn": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", - "integrity": "sha512-FsqWmApWGMGLKKNpHt12PMc5AK7BaZee0WRh04fCysmTzHe+rrKOa2MKjORhnzfpe4r0JnfdqHn02iDA9Dqj2A==", - "bin": { - "acorn": "bin/acorn" + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" }, "engines": { - "node": ">=0.4.0" + "node": ">= 10.0.0" } }, "node_modules/word-wrap": { @@ -2887,14 +2922,6 @@ "node": ">=0.10.0" } }, - "node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2929,17 +2956,6 @@ "node": ">=0.4" } }, - "node_modules/yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", - "dependencies": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -2964,6 +2980,31 @@ } }, "dependencies": { + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + }, + "@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==" + }, + "@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", @@ -2979,23 +3020,6 @@ "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@humanwhocodes/config-array": { @@ -3007,23 +3031,6 @@ "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.5" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@humanwhocodes/module-importer": { @@ -3074,17 +3081,9 @@ } }, "acorn": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", - "integrity": "sha512-pXK8ez/pVjqFdAgBkF1YPVRacuLQ9EXBKaKWaeh58WNfMkCmZhOZzu+NtKSPD5PHmCCHheQ5cD29qM1K4QTxIg==" - }, - "acorn-globals": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", - "integrity": "sha512-j3/4pkfih8W4NK22gxVSXcEonTpAHOHh0hu5BoZrKcOsW/4oBPxTi4Yk3SAj+FhC1f3+bRTkXdm4019gw1vg9g==", - "requires": { - "acorn": "^2.1.0" - } + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" }, "ajv": { "version": "6.12.6", @@ -3098,21 +3097,6 @@ "uri-js": "^4.2.2" } }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - } - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==" - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -3145,9 +3129,14 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "asap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", - "integrity": "sha512-Ej9qjcXY+8Tuy1cNqiwNMwFRXOy9UwgTeMA8LxreodygIPV48lx8PU1ecFxb5ZeU1DpMKxiq6vGLTxcitWZPbA==" + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "assert-never": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", + "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" }, "asynckit": { "version": "0.4.0", @@ -3172,6 +3161,14 @@ "proxy-from-env": "^1.1.0" } }, + "babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "requires": { + "@babel/types": "^7.9.6" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3184,9 +3181,12 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "basic-auth": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz", - "integrity": "sha512-uvq3I/zC5TmG0WZJDzsXzIytU9GiiSq23Gl27Dq9sV81JTfPfQhtdADECP1DJZeJoZPuYU0Y81hWC5y/dOR+Yw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } }, "bl": { "version": "4.1.0", @@ -3211,20 +3211,45 @@ } }, "body-parser": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz", - "integrity": "sha512-ypX8/9uws2W+CjPp3QMmz1qklzlhRBknQve22Y+WFecHql+qDFfG+VVNX7sooA4Q3+2fdq4ZZj6Xr07gA90RZg==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "requires": { - "bytes": "2.1.0", - "content-type": "~1.0.1", - "debug": "~2.2.0", - "depd": "~1.0.1", - "http-errors": "~1.3.1", - "iconv-lite": "0.4.11", - "on-finished": "~2.3.0", - "qs": "4.0.0", - "raw-body": "~2.1.2", - "type-is": "~1.6.6" + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + } } }, "brace-expansion": { @@ -3260,9 +3285,18 @@ } }, "bytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz", - "integrity": "sha512-k9VSlRfRi5JYyQWMylSOgjld96ta1qaQUIvmn+na0BzViclH04PBumewv4z5aeXNkn6Z/gAN5FtPeBLvV20F9w==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } }, "callsites": { "version": "3.1.0", @@ -3270,20 +3304,6 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==" - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3295,37 +3315,11 @@ } }, "character-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz", - "integrity": "sha512-6OEBVBlf/y8LaAphnbAnt743O3zMhlBer+FO5D40H6wqAdU9B1TvuApkejgLW0cvv0tEZNLktv1AnRI+C87ueQ==" - }, - "clean-css": { - "version": "3.4.28", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", - "integrity": "sha512-aTWyttSdI2mYi07kWqHi24NUU9YlELFKGOAgFzZjDN1064DMAOy2FBuoyGmkKRlXkbpXd0EVHmiVkbKhKoirTw==", - "requires": { - "commander": "2.8.x", - "source-map": "0.4.x" - }, - "dependencies": { - "commander": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", - "integrity": "sha512-+pJLBFVk+9ZZdlAOB5WuIElVPPth47hILFkmGym57aq8kwxsowvByvB0DHs1vQAhyMZzdcpTtF0VDKGkSDR4ZQ==", - "requires": { - "graceful-readlink": ">= 1.0.0" - } - } - } - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" + "is-regex": "^1.0.3" } }, "codepage": { @@ -3385,17 +3379,28 @@ } }, "constantinople": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", - "integrity": "sha512-UnEggAQrmhxuTxlb7n1OsTtagNXWUv2CRlOogZhWOU4jLK4EJEbF8UDSNxuGu+jVtWNtO2j51ab2H1wlBIzF/w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", "requires": { - "acorn": "^2.1.0" + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" } }, "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==" + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } }, "content-type": { "version": "1.0.4", @@ -3448,43 +3453,26 @@ } } }, - "css": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", - "integrity": "sha512-qmTYWhHk910nQWnGqMAiWWPQlB6tESiWgNebQJmiozOAGcBAQ1+U/UzUOkhdrcshlkSRRiKWodwmVvO0OmnIGg==", - "requires": { - "css-parse": "1.0.4", - "css-stringify": "1.0.5" - } - }, - "css-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", - "integrity": "sha512-pfstzKVRZiHprDXdsmtfH1HYUEw22lzjuHdnpe1hscwoQvgW2C5zDQIBE0RKoALEReTn9W1ECdY8uaT/kO4VfA==" - }, - "css-stringify": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", - "integrity": "sha512-aIThpcErhG5EyHorGqNlTh0TduNBqLrrXLO3x5rku3ZKBxuVfY+T7noyM2G2X/01iQANqJUb6d3+FLoa+N7Xwg==" - }, "cyrillic-to-latin": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cyrillic-to-latin/-/cyrillic-to-latin-2.0.0.tgz", "integrity": "sha512-8hljBJfU3cKuBa0IkOTb95/U9OV/BKuwyqUd6mIvziiJ6JYRt0KSXAYz2Z7k60AqBPPc+3UBl5nHN8b7WAIWuQ==" }, "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha512-X0rGvJcskG1c3TgSCPqHJ0XJgwlcvOC7elJ5Y0hYuKBZoVqWpAMfLOeIh2UI/DCQ5ruodIjvsugZtjUYUw2pUw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { - "ms": "0.7.1" + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" - }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3505,14 +3493,14 @@ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "depd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", - "integrity": "sha512-OEWAMbCkK9IWQ8pfTvHBhCSqHgR+sk5pbiYqq0FqfARG4Cy+cRsCbITx6wh5pcsmfBPiJAcbd98tfdz5fnBbag==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, "doctrine": { "version": "3.0.0", @@ -3523,6 +3511,11 @@ "esutils": "^2.0.2" } }, + "doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==" + }, "dotenv": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", @@ -3595,26 +3588,11 @@ "text-table": "^0.2.0" }, "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true } } }, @@ -3718,44 +3696,47 @@ "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" }, "express": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/express/-/express-4.15.5.tgz", - "integrity": "sha512-E5kemI7MqPbkLstU1xLG3VB7TgSRyJu4N765mQinL9agWiD5HzpK5IZTUYuqd8m0M8A8ReM23xBqcwiSzrDRGQ==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "requires": { - "accepts": "~1.3.3", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "content-disposition": "0.5.2", - "content-type": "~1.0.2", - "cookie": "0.3.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.1", - "encodeurl": "~1.0.1", + "depd": "2.0.0", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "etag": "~1.8.0", - "finalhandler": "~1.0.6", + "etag": "~1.8.1", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.1", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~1.1.5", - "qs": "6.5.0", - "range-parser": "~1.2.0", - "send": "0.15.6", - "serve-static": "1.12.6", - "setprototypeof": "1.0.3", - "statuses": "~1.3.1", - "type-is": "~1.6.15", - "utils-merge": "1.0.0", - "vary": "~1.1.1" + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "dependencies": { "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, "debug": { "version": "2.6.9", @@ -3765,25 +3746,23 @@ "ms": "2.0.0" } }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "qs": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", - "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg==" + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==" + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, @@ -3815,11 +3794,6 @@ "ms": "2.0.0" } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -3894,16 +3868,16 @@ } }, "finalhandler": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", - "integrity": "sha512-immlyyYCPWG2tajlYBhZ6cjLAv1QAclU8tKS0d27ZtPqm/+iddy16GT3xLExg+V4lIETLpPwaYQAlZHNE//dPA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.1", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "dependencies": { @@ -3920,10 +3894,13 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==" + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } } } }, @@ -3969,9 +3946,9 @@ } }, "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha512-Ua9xNhH0b8pwE3yRbFfXJvfdWF0UHNCdeyb2sbi9Ul/M+r3PTdrz7Cv4SCfZRMjmzEM9PhraqfZFbGTIg3OMyA==" + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" }, "fresh": { "version": "0.5.2", @@ -3994,6 +3971,21 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -4036,36 +4028,58 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==" - }, "grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, "http-errors": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", - "integrity": "sha512-gMygNskMurDCWfoCdyh1gOeDfSbkAHXqz94QoPj5IHIUjC/BG8/xv7FSEUr7waR5RcAya4j58bft9Wu/wHNeXA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "requires": { - "inherits": "~2.0.1", - "statuses": "1" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" } }, "iconv-lite": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz", - "integrity": "sha512-8UmnaYeP5puk18SkBrYULVTiq7REcimhx+ykJVJBiaz89DQmVQAfS29ZhHah86la90/t0xy4vRk86/2cCwNodA==" + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } }, "ieee754": { "version": "1.2.1", @@ -4110,14 +4124,26 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ipaddr.js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", - "integrity": "sha512-RbrsPoo4IkisyHhS9VDa3ybxnu0wOo0uTAhaELmwxq244p18X7Dk0fQoJvh/QTkIUO296fbjgvMqK3ry84eVVA==" + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "requires": { + "has": "^1.0.3" + } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "requires": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } }, "is-extglob": { "version": "2.1.1", @@ -4145,6 +4171,15 @@ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -4155,39 +4190,17 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "jade": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", - "integrity": "sha512-J76sbGKeLtu7uwW97Ntzb1UvGnpKTDplYa9ROr2gNRhM+SxvlBSG0Ees3TQ8+7ya2UVkzMEeFxhRhEpN68s7Tg==", - "requires": { - "character-parser": "1.2.1", - "clean-css": "^3.1.9", - "commander": "~2.6.0", - "constantinople": "~3.0.1", - "jstransformer": "0.0.2", - "mkdirp": "~0.5.0", - "transformers": "2.1.0", - "uglify-js": "^2.4.19", - "void-elements": "~2.0.1", - "with": "~4.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "requires": { - "minimist": "^1.2.6" - } - } - } - }, "js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", "dev": true }, + "js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==" + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -4233,20 +4246,12 @@ } }, "jstransformer": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", - "integrity": "sha512-b7tmf91j1ChMuYhwbPBnNgB62dmHuqiHpOdd6QLKzde8HydZqm+ud3qWreGWecSxPBFFNOf1Ozjx0xo2plFdHA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", "requires": { "is-promise": "^2.0.0", - "promise": "^6.0.1" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "requires": { - "is-buffer": "^1.1.5" + "promise": "^7.0.1" } }, "language-name-map": { @@ -4254,11 +4259,6 @@ "resolved": "https://registry.npmjs.org/language-name-map/-/language-name-map-0.3.0.tgz", "integrity": "sha512-uoBHtfY6h4S2RoIpyqvQGhynX2hshQu/9S4ySbppGxG5VwEsiWZJ83xSjzx25Mb+Bmc+WxpQC0H54eNZVMWLuA==" }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==" - }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4289,11 +4289,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==" - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -4310,9 +4305,9 @@ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha512-sAaYXszED5ALBt665F0wMQCUXpGuZsGdopoqcHPdL39ZYdi7uHoZlhrfZfhv8WzivhBzr/oXwaj+yiK5wY8MXQ==" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { "version": "1.52.0", @@ -4341,27 +4336,50 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, "moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "morgan": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.6.1.tgz", - "integrity": "sha512-WWxlTx5xCqbtSeX/gPVHUZBhAhSMfYQLgPrWHEN0FYnF+zf1Ju/Zct6rpeKmvzibrYF4QvFVws7IN61BxnKu+Q==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "requires": { - "basic-auth": "~1.0.3", - "debug": "~2.2.0", - "depd": "~1.0.1", + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.0" + "on-headers": "~1.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } } }, "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha512-lRLiIR9fSNpnP6TC4v8+4OU7oStC01esuNowdQ34L+Gk8e5Puoc88IqJ+XAY/B3Mn2ZKis8l8HX90oU8ivzUHg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "multer": { "version": "1.4.5-lts.1", @@ -4375,16 +4393,6 @@ "object-assign": "^4.1.1", "type-is": "^1.6.4", "xtend": "^4.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "requires": { - "minimist": "^1.2.6" - } - } } }, "native-promise-only": { @@ -4416,6 +4424,11 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -4438,14 +4451,6 @@ "wrappy": "1" } }, - "optimist": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", - "requires": { - "wordwrap": "~0.0.2" - } - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -4510,6 +4515,11 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -4527,11 +4537,11 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "promise": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", - "integrity": "sha512-O+uwGKreKNKkshzZv2P7N64lk6EP17iXBn0PbUnNQhk+Q0AHLstiTrjkx3v5YBd3cxUe7Sq6KyRhl/A0xUjk7Q==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "requires": { - "asap": "~1.0.0" + "asap": "~2.0.3" } }, "promise-queue": { @@ -4540,12 +4550,12 @@ "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==" }, "proxy-addr": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", - "integrity": "sha512-av1MQ5vwTiMICwU75KSf/vJ6a+AXP0MtP+aYBqm2RFlire7BP6sWlfOLc8+6wIQrywycqSpJWm5zNkYFkRARWA==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "requires": { - "forwarded": "~0.1.0", - "ipaddr.js": "1.4.0" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" } }, "proxy-from-env": { @@ -4553,6 +4563,118 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "pug": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", + "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==", + "requires": { + "pug-code-gen": "^3.0.2", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "requires": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "pug-code-gen": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz", + "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==", + "requires": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.0.0", + "pug-runtime": "^3.0.0", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "pug-error": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" + }, + "pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "requires": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "requires": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "requires": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "requires": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "requires": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==" + }, + "pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "requires": { + "pug-error": "^2.0.0" + } + }, + "pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -4560,9 +4682,12 @@ "dev": true }, "qs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", - "integrity": "sha512-8MPmJ83uBOPsQj5tQCv4g04/nTiY+d17yl9o3Bw73vC6XlEm2POIRRlOgWJ8i74bkGLII670cDJJZkgiZ2sIkg==" + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } }, "queue-microtask": { "version": "1.2.3", @@ -4581,25 +4706,14 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", - "integrity": "sha512-x4d27vsIG04gZ1imkuDXB9Rd/EkAx5kYzeMijIYw1PAor0Ld3nTlkQQwDjKu42GdRUFCX1AfGnTSQB4O57eWVg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "requires": { - "bytes": "2.4.0", - "iconv-lite": "0.4.13", + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", - "integrity": "sha512-SvUX8+c/Ga454a4fprIdIUzUN9xfd1YTvYh7ub5ZPJ+ZJ/+K2Bp6IpWGmnw8r3caLTsmhvJAKZz3qjIo9+XuCQ==" - }, - "iconv-lite": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", - "integrity": "sha512-QwVuTNQv7tXC5mMWFX5N5wGjmybjNBBD8P3BReTkPmipoxTUFgWM2gXNvldHQr6T14DH0Dh6qBVg98iJt7u4mQ==" - } } }, "readable-stream": { @@ -4622,10 +4736,15 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } }, "resolve-from": { "version": "4.0.0", @@ -4639,14 +4758,6 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", - "requires": { - "align-text": "^0.1.1" - } - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -4670,24 +4781,29 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "send": { - "version": "0.15.6", - "resolved": "https://registry.npmjs.org/send/-/send-0.15.6.tgz", - "integrity": "sha512-e1/758VJ+GsPg8vE+Z/xE7R36IWogUl8rrrs53CsfHrT2IyZyPggfvbHT8HTV3yBNKrUHYUTsBQ9pXQYkcB4YQ==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "requires": { "debug": "2.6.9", - "depd": "~1.1.1", - "destroy": "~1.0.4", - "encodeurl": "~1.0.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.3.4", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.3.1" + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "dependencies": { "debug": { @@ -4696,50 +4812,22 @@ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" }, "dependencies": { - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==" + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } } } }, @@ -4768,20 +4856,20 @@ } }, "serve-static": { - "version": "1.12.6", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.6.tgz", - "integrity": "sha512-M2CMkmVnR22x7taVSeYGdfIhnh/mhanPZqqBCSRAvVZNkrhaOpOLlwimKpJR+NhFpD/8Dr9G0YpAtkDkCcAVJQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "requires": { - "encodeurl": "~1.0.1", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.15.6" + "parseurl": "~1.3.3", + "send": "0.18.0" } }, "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha512-9jphSf3UbIgpOX/RKvX02iw/rN2TKdusnsPpGfO/rkcsrd+IRqgHZb4VGnmL0Cynps8Nj2hN45wsi30BzrHDIw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "shebang-command": { "version": "2.0.0", @@ -4798,12 +4886,14 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha512-Y8nIfcb1s/7DcobUz1yOO1GSp7gyL+D9zLHDehT7iRESqGSxjJ448Sg7rvfgsRJCnKLdSl11uGf0s9X80cH0/A==", + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "requires": { - "amdefine": ">=0.0.4" + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" } }, "srt2vtt": { @@ -4816,9 +4906,9 @@ } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, "streamsearch": { "version": "1.1.0", @@ -4865,6 +4955,11 @@ "has-flag": "^4.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4876,53 +4971,26 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==" + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "transformers": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", - "integrity": "sha512-zJf5m2EIOngmBbDe2fhTPpCjzM2qkZVqrFJZc2jaln+KBeEaYKhS2QMOIkfVrNUyoOwqgbTwOHATzr3jZRQDyg==", - "requires": { - "css": "~1.0.8", - "promise": "~2.0", - "uglify-js": "~2.2.5" - }, - "dependencies": { - "is-promise": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", - "integrity": "sha512-mjWH5XxnhMA8cFnDchr6qRP9S/kLntKuEfIYku+PaN1CnS8v+OG9O/BKpRCVRJvpIkgAZm0Pf5Is3iSSOILlcg==" - }, - "promise": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", - "integrity": "sha512-OgMc+sxI3zWF8D5BJGtA0z7/IsrDy1/0cPaDv6HPpqa2fSTo7AdON5U10NbZCUeF+zCAj3PtfPE50Hf02386aA==", - "requires": { - "is-promise": "~1" - } - }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", - "requires": { - "amdefine": ">=0.0.4" - } - }, - "uglify-js": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", - "integrity": "sha512-viLk+/8G0zm2aKt1JJAVcz5J/5ytdiNaIsKgrre3yvSUjwVG6ZUujGH7E2TiPigZUwLYCe7eaIUEP2Zka2VJPA==", - "requires": { - "optimist": "~0.3.5", - "source-map": "~0.1.7" - } - } - } - }, "trim-repeated": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", @@ -4960,29 +5028,6 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", - "optional": true - }, "uid-safe": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", @@ -5021,9 +5066,9 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha512-HwU9SLQEtyo+0uoKXd1nkLqigUWLB+QuNQR4OcmB73eWqksM5ovuqcycks2x043W8XVb75rG1HQ0h93TMXkzQQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "vary": { "version": "1.1.2", @@ -5036,9 +5081,9 @@ "integrity": "sha512-BOuDjFFYvJdZO6e/N65AlaDItXo2TgyLjeyRYcqgAPkXpp5yTJcvkL2n+syO1r9Qc5g96tfBD2tuiMhYDmaGcA==" }, "void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" }, "webidl-conversions": { "version": "3.0.1", @@ -5062,25 +5107,15 @@ "isexe": "^2.0.0" } }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==" - }, "with": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", - "integrity": "sha512-mJZFpyEc1JTAdxhi/vhVeAM2S7vsltEKDiexDDo1HuAzlYKhcVUU6cwY8cHrFYdt82ZNkfKCeyhA3IYFegI0Kg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", "requires": { - "acorn": "^1.0.1", - "acorn-globals": "^1.0.3" - }, - "dependencies": { - "acorn": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", - "integrity": "sha512-FsqWmApWGMGLKKNpHt12PMc5AK7BaZee0WRh04fCysmTzHe+rrKOa2MKjORhnzfpe4r0JnfdqHn02iDA9Dqj2A==" - } + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" } }, "word-wrap": { @@ -5089,11 +5124,6 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==" - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -5111,17 +5141,6 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 0647f8a..97da7c3 100644 --- a/package.json +++ b/package.json @@ -17,26 +17,26 @@ "dependencies": { "await-spawn": "^4.0.2", "axios": "^1.1.3", - "body-parser": "~1.13.2", + "body-parser": "^1.20.1", "cookie-parser": "~1.3.5", "cyrillic-to-latin": "^2.0.0", - "debug": "~2.2.0", + "debug": "^4.3.4", "dotenv": "^16.0.3", - "express": "~4.15.5", + "express": "^4.18.2", "express-session": "^1.17.3", "ffprobe": "^1.1.2", "filenamify": "^4.3.0", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "google-translate-api-browser": "^3.0.0", - "jade": "~1.11.0", "language-name-map": "^0.3.0", "lodash": "^4.17.21", "moment": "^2.29.4", - "morgan": "~1.6.1", + "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", "node-fetch": "^2.6.7", "promise-queue": "^2.2.5", + "pug": "^3.0.2", "serve-favicon": "^2.5.0", "srt2vtt": "^1.3.1", "which": "^3.0.0", diff --git a/queue/newQueue.js b/queue/newQueue.js index 59929b0..834b612 100644 --- a/queue/newQueue.js +++ b/queue/newQueue.js @@ -1,13 +1,13 @@ const transcribeWrapped = require('../transcribe/transcribe-wrapped'); // const { sendOutQueuePositionUpdate } = require('../lib/websockets'); -const WebSocket = require("ws"); +const WebSocket = require('ws'); const l = console.log; const maxConcurrentJobs = Number(process.env.CONCURRENT_AMOUNT); // create set of numbers from x, such as 1,2,3 -function createNumberSet(x) { +function createNumberSet (x) { return Array.from({length: x}, (_, i) => i + 1); } @@ -17,14 +17,14 @@ const numberSet = createNumberSet(maxConcurrentJobs); global.jobProcesses = {}; -for(const number of numberSet){ +for (const number of numberSet) { global.jobProcesses[number] = undefined; } l(global.jobProcesses); // find process number of job to clear it when done -function findProcessNumber(websocketNumber) { +function findProcessNumber (websocketNumber) { for (let processNumber in global.jobProcesses) { const hasOwnProperty = global.jobProcesses.hasOwnProperty(processNumber) @@ -32,7 +32,7 @@ function findProcessNumber(websocketNumber) { if (hasOwnProperty) { const matchesByWebsocket = global.jobProcesses[processNumber]?.websocketNumber === websocketNumber; - if(matchesByWebsocket){ + if (matchesByWebsocket) { return processNumber } } @@ -42,7 +42,7 @@ function findProcessNumber(websocketNumber) { // TODO: throw an error here? } -function sendOutQueuePositionUpdate(){ +function sendOutQueuePositionUpdate () { // loop through websockets and tell them one less is processing for (let [, websocket] of global['webSocketData'].entries() ) { // the actual websocket @@ -57,7 +57,7 @@ function sendOutQueuePositionUpdate(){ // l('queuePosition'); // l(queuePosition); - if(queuePosition) { + if (queuePosition) { websocketConnection.send(JSON.stringify({ message: 'queue', placeInQueue: queuePosition @@ -72,7 +72,7 @@ function sendOutQueuePositionUpdate(){ // run transcribe job and remove from queue and run next queue item if available -async function runJob(jobObject){ +async function runJob (jobObject) { const { websocketNumber } = jobObject; // simulate job running @@ -81,7 +81,7 @@ async function runJob(jobObject){ l('job done'); - } catch (err){ + } catch (err) { l('error from runjob'); l(err); } @@ -91,7 +91,7 @@ async function runJob(jobObject){ l(processNumber); // run the next item from the queue - if(global.newQueue.length){ + if (global.newQueue.length) { const nextQueueItem = global.newQueue.shift(); nextQueueItem.processNumber = Number(processNumber); @@ -108,7 +108,7 @@ async function runJob(jobObject){ global.newQueue = []; // add job to process if available otherwise add to queue -function addToJobProcessOrQueue(jobObject){ +function addToJobProcessOrQueue (jobObject) { const { websocketNumber, skipToFront } = jobObject; l('skipToFront'); @@ -118,7 +118,7 @@ function addToJobProcessOrQueue(jobObject){ for (let processNumber in global.jobProcesses) { const propValue = global.jobProcesses[processNumber]; - if(propValue === undefined){ + if (propValue === undefined) { jobObject.processNumber = Number(processNumber); global.jobProcesses[processNumber] = jobObject; @@ -130,12 +130,12 @@ function addToJobProcessOrQueue(jobObject){ // TODO: add got in queue time here // push to newQueue if all processes are busy - if(skipToFront){ + if (skipToFront) { // last skip to front item const lastItem = global.newQueue.filter(queueItem => queueItem.skipToFront === true).slice(-1)[0]; // insert after latest skipToFront - if(lastItem){ + if (lastItem) { const lastItemIndex = global.newQueue.indexOf(lastItem); // insert after last item with skipToFront @@ -154,12 +154,12 @@ function addToJobProcessOrQueue(jobObject){ } // get amount of running jobs (used to calculate queue position) -function amountOfRunningJobs(){ +function amountOfRunningJobs () { let amount = 0; for (let processNumber in global.jobProcesses) { const propValue = global.jobProcesses[processNumber]; - if(propValue !== undefined){ + if (propValue !== undefined) { amount++; } } @@ -168,9 +168,9 @@ function amountOfRunningJobs(){ } // get position in queue based on websocketNumber -function getQueueInformationByWebsocketNumber(websocketNumber){ +function getQueueInformationByWebsocketNumber (websocketNumber) { for (const [index, queueItem] of global.newQueue.entries()) { - if(queueItem.websocketNumber === websocketNumber){ + if (queueItem.websocketNumber === websocketNumber) { return { queuePosition: index + 1, // 1 queueLength: global.newQueue.length, // 4 diff --git a/queue/queue.js b/queue/queue.js index bfb955a..bc90aa3 100644 --- a/queue/queue.js +++ b/queue/queue.js @@ -2,22 +2,22 @@ global.queueJobs = []; global.queueItems = []; -function addItemToQueue(queueData){ +function addItemToQueue (queueData) { global.queueItems.push(queueData) } -function addItemToQueueJobs(queueData){ +function addItemToQueueJobs (queueData) { global.queueJobs.push(queueData) } -function updateQueueItemStatus(websocketNumber, status){ +function updateQueueItemStatus (websocketNumber, status) { const item = global.queueItems.find((item) => item.websocketNumber === websocketNumber); if (item && item.status !== 'completed') { item.status = status; } } -function getNumberOfPendingOrProcessingJobs(ip){ +function getNumberOfPendingOrProcessingJobs (ip) { const numberOfPendingOrProcessingJobs = global.queueItems.filter((item) => item.ip === ip && (item.status === 'pending' || item.status === 'processing')).length; return numberOfPendingOrProcessingJobs; } diff --git a/routes/admin.js b/routes/admin.js index 4667455..b7922e8 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -108,9 +108,9 @@ router.get('/admin', async function (req, res, next) { const cleanedUpJobProcessObject = {}; - for(const jobProcessNumber in jobProcesses){ + for (const jobProcessNumber in jobProcesses) { let value = jobProcesses[jobProcessNumber]; - if(!value){ + if (!value) { cleanedUpJobProcessObject[jobProcessNumber] = {}; continue } @@ -132,9 +132,9 @@ router.get('/admin', async function (req, res, next) { // l(global.newQueue); // cleanup new queue items - for(const queueItem of global.newQueue){ + for (const queueItem of global.newQueue) { - if(!queueItem) continue + if (!queueItem) continue let newItem = Object.assign({}, queueItem); diff --git a/routes/api.js b/routes/api.js index 020ec96..52dffdf 100644 --- a/routes/api.js +++ b/routes/api.js @@ -9,7 +9,7 @@ const transcribe = require('../transcribe/transcribe-api-wrapped') const constants = require('../constants/constants'); const filenamify = require('filenamify'); const createTranslatedFiles = require('../translate/translate-files-api'); -const { downloadFileApi, getFilename} = require("../downloading/yt-dlp-download"); +const { downloadFileApi, getFilename} = require('../downloading/yt-dlp-download'); const { languagesToTranslateTo, newLanguagesMap, translationLanguages } = constants; const { modelsArray, whisperLanguagesHumanReadableArray } = constants; const { writeToProcessingDataFile, createFileNames, makeFileNameSafe } = require('../lib/transcribing'); @@ -37,7 +37,7 @@ router.post('/api', upload.single('file'), async function (req, res, next) { // get file names const file = req.file; let originalFileName, uploadFileName; - if(file){ + if (file) { originalFileName = file.originalname; uploadFileName = file.filename; } @@ -55,28 +55,29 @@ router.post('/api', upload.single('file'), async function (req, res, next) { const authTokenStringsAsArray = authTokenString.split(','); const authedByToken = authTokenStringsAsArray.includes(apiToken); - if(process.env.NODE_ENV === 'production' && !authedByToken){ + if (process.env.NODE_ENV === 'production' && !authedByToken) { return res.status(401).json({ error: 'Unauthorized' }); } // nothing to transcribe - if(!downloadLink && !file){ + if (!downloadLink && !file) { + // eslint-disable-next-line quotes return res.status(400).json({error: `Please pass either a 'file' or 'downloadLink'`}); } // bad model name - if(!validModelValues.includes(model)) { + if (!validModelValues.includes(model)) { return res.status(400).send({error: `Your model of '${model}' is not valid. Please choose one of the following: ${validModelValues.join(', ')}`}); } // bad language name - if(!whisperLanguagesHumanReadableArray.includes(language)) { + if (!whisperLanguagesHumanReadableArray.includes(language)) { return res.status(400).send({error: `Your language of '${language}' is not valid. Please choose one of the following: ${whisperLanguagesHumanReadableArray.join(', ')}`}); } // TODO: implement this let originalFileNameWithExtension, originalFileExtension, originalFileNameWithoutExtension, directorySafeFileNameWithoutExtension; - if(file){ + if (file) { ({ originalFileNameWithExtension, originalFileExtension, diff --git a/routes/index.js b/routes/index.js index ebc92f2..48a07ec 100644 --- a/routes/index.js +++ b/routes/index.js @@ -90,7 +90,7 @@ router.get('/queue', function (req, res, next) { }) }); -// router.get("/transcriptions/:path/:filename" , async function(req, res, next){ +// router.get("/transcriptions/:path/:filename" , async function(req, res, next) { // console.log(req.params); // res.sendFile(`${process.cwd()}/transcriptions/${req.params.path}/${req.params.filename}`); // }); diff --git a/routes/player.js b/routes/player.js index aa6980a..c877bfa 100644 --- a/routes/player.js +++ b/routes/player.js @@ -78,7 +78,7 @@ router.get('/player/:filename' , async function (req, res, next) { }); /** player route to add translation **/ -router.get("/player/:filename/add" , async function(req, res, next){ +router.get('/player/:filename/add' , async function (req, res, next) { try { const fileNameWithoutExtension = req.params.filename @@ -100,7 +100,7 @@ router.get("/player/:filename/add" , async function(req, res, next){ // vttPath, // fileSource }) - } catch (err){ + } catch (err) { l('err'); l(err); res.send(err); @@ -176,7 +176,7 @@ router.post('/player/:filename/add' , async function (req, res, next) { }); /** CHANGE KEEP MEDIA **/ -router.post("/player/:filename/keepMedia" , async function(req, res, next){ +router.post('/player/:filename/keepMedia' , async function (req, res, next) { try { const { password } = req.query; @@ -200,7 +200,7 @@ router.post("/player/:filename/keepMedia" , async function(req, res, next){ const processingData = JSON.parse(await fs.readFile(processingDataPath, 'utf8')); - if(shouldKeepMedia){ + if (shouldKeepMedia) { processingData.keepMedia = true; } else { processingData.keepMedia = false; @@ -210,7 +210,7 @@ router.post("/player/:filename/keepMedia" , async function(req, res, next){ return res.redirect(`/player/${req.params.filename}`) - } catch (err){ + } catch (err) { l('err'); l(err); res.send(err); diff --git a/routes/transcribe.js b/routes/transcribe.js index 2755d78..82df72d 100644 --- a/routes/transcribe.js +++ b/routes/transcribe.js @@ -62,7 +62,7 @@ router.post('/file', upload.single('file'), async function (req, res, next) { const uploadTimeFinished = new Date(); // this shouldn't happen but there's some sort of frontend bug - if(!language || language === 'undefined' || language === 'Auto-Detect'){ + if (!language || language === 'undefined' || language === 'Auto-Detect') { language = 'auto-detect'; } @@ -79,7 +79,7 @@ router.post('/file', upload.single('file'), async function (req, res, next) { l(downloadLink); - function matchByWebsocketNumber(item) { + function matchByWebsocketNumber (item) { return item.websocketNumber === websocketNumber; } @@ -287,7 +287,7 @@ router.get('/checkingOutstandingProcesses', async function (req, res, next) { l('outstandingJobsAmount'); l(outstandingJobsAmount); - if(outstandingJobsAmount >= 3) { + if (outstandingJobsAmount >= 3) { res.send('tooMany'); } else { res.send('ok'); diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index d15e0f2..42ce98e 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -16,12 +16,12 @@ const { updateQueueItemStatus } = require('../queue/queue'); // const {amountOfRunningJobs} = require("../queue/newQueue"); const maxConcurrentJobs = Number(process.env.CONCURRENT_AMOUNT); -function amountOfRunningJobs(){ +function amountOfRunningJobs () { let amount = 0; for (let processNumber in global.jobProcesses) { const propValue = global.jobProcesses[processNumber]; - if(propValue !== undefined){ + if (propValue !== undefined) { amount++; } } @@ -69,7 +69,7 @@ async function transcribe ({ }) { return new Promise(async (resolve, reject) => { - function webSocketIsStillAlive(webSocketNumber) { + function webSocketIsStillAlive (webSocketNumber) { return global.webSocketData.some(item => item.websocketNumber === webSocketNumber); } @@ -438,8 +438,8 @@ async function transcribe ({ characterCount: strippedText.length, } - if(downloadLink) fileDetailsObject.downloadLink = downloadLink; - if(user) fileDetailsObject.user = user; + if (downloadLink) fileDetailsObject.downloadLink = downloadLink; + if (user) fileDetailsObject.user = user; // save processing_data.json await fs.appendFile(`${originalContainingDir}/processing_data.json`, JSON.stringify(fileDetailsObject), 'utf8'); @@ -448,11 +448,11 @@ async function transcribe ({ const renamedDirectory = `./transcriptions/${fileSafeNameWithDateTimestamp}`; await fs.rename(originalContainingDir, renamedDirectory) - function matchByWebsocketNumber(item) { + function matchByWebsocketNumber (item) { return item.websocketNumber === websocketNumber; } - function removeFromArrayByWebsocketNumber(array) { + function removeFromArrayByWebsocketNumber (array) { const index = array.findIndex(matchByWebsocketNumber); if (index > -1) { array.splice(index, 1); @@ -475,7 +475,7 @@ async function transcribe ({ reject(err); l('websocket connection'); // if websocket is still connected - if(websocketConnection.readyState === 1) { + if (websocketConnection.readyState === 1) { sendToWebsocket({ message: 'error', text: 'The transcription failed, please try again or try again later' diff --git a/views/addTranslation/addTranslation.jade b/views/addTranslation/addTranslation.pug similarity index 100% rename from views/addTranslation/addTranslation.jade rename to views/addTranslation/addTranslation.pug diff --git a/views/admin.jade b/views/admin.pug similarity index 100% rename from views/admin.jade rename to views/admin.pug diff --git a/views/error.jade b/views/error.pug similarity index 100% rename from views/error.jade rename to views/error.pug diff --git a/views/files.jade b/views/files.pug similarity index 100% rename from views/files.jade rename to views/files.pug diff --git a/views/index/components/amounts-header.jade b/views/index/components/amounts-header.pug similarity index 100% rename from views/index/components/amounts-header.jade rename to views/index/components/amounts-header.pug diff --git a/views/index/components/social-buttons.jade b/views/index/components/social-buttons.pug similarity index 100% rename from views/index/components/social-buttons.jade rename to views/index/components/social-buttons.pug diff --git a/views/index/components/transcription-results.jade b/views/index/components/transcription-results.pug similarity index 100% rename from views/index/components/transcription-results.jade rename to views/index/components/transcription-results.pug diff --git a/views/index/components/upload-form.jade b/views/index/components/upload-form.pug similarity index 100% rename from views/index/components/upload-form.jade rename to views/index/components/upload-form.pug diff --git a/views/index/index.jade b/views/index/index.jade deleted file mode 100644 index 1a83cbe..0000000 --- a/views/index/index.jade +++ /dev/null @@ -1,23 +0,0 @@ -extends ../layout - -block content - script(src='/javascripts/circle-progress.min.js') - - include ../styles/styles-global.jade - include styles/styles-social.jade - include styles/styles-amounts-header.jade - include styles/styles-form.jade - include styles/styles-transcription-results.jade - - include components/social-buttons.jade - - .container - - include components/amounts-header.jade - - h1#header File Upload - include components/upload-form.jade - - include components/transcription-results.jade - - include js/js-index.jade \ No newline at end of file diff --git a/views/index/index.pug b/views/index/index.pug new file mode 100644 index 0000000..7dd8a76 --- /dev/null +++ b/views/index/index.pug @@ -0,0 +1,23 @@ +extends ../layout + +block content + script(src='/javascripts/circle-progress.min.js') + + include ../styles/styles-global + include styles/styles-social + include styles/styles-amounts-header + include styles/styles-form + include styles/styles-transcription-results + + include components/social-buttons + + .container + + include components/amounts-header + + h1#header File Upload + include components/upload-form + + include components/transcription-results + + include js/js-index \ No newline at end of file diff --git a/views/index/js/controllers/error-handling.jade b/views/index/js/controllers/error-handling.pug similarity index 100% rename from views/index/js/controllers/error-handling.jade rename to views/index/js/controllers/error-handling.pug diff --git a/views/index/js/controllers/file-handling.jade b/views/index/js/controllers/file-handling.pug similarity index 100% rename from views/index/js/controllers/file-handling.jade rename to views/index/js/controllers/file-handling.pug diff --git a/views/index/js/controllers/network-handling.jade b/views/index/js/controllers/network-handling.pug similarity index 100% rename from views/index/js/controllers/network-handling.jade rename to views/index/js/controllers/network-handling.pug diff --git a/views/index/js/controllers/selection-dropdowns.jade b/views/index/js/controllers/selection-dropdowns.pug similarity index 100% rename from views/index/js/controllers/selection-dropdowns.jade rename to views/index/js/controllers/selection-dropdowns.pug diff --git a/views/index/js/js-index.jade b/views/index/js/js-index.pug similarity index 98% rename from views/index/js/js-index.jade rename to views/index/js/js-index.pug index dd663d7..554492b 100644 --- a/views/index/js/js-index.jade +++ b/views/index/js/js-index.pug @@ -1,8 +1,8 @@ -include js-util.jade -include controllers/selection-dropdowns.jade -include controllers/file-handling.jade -include controllers/error-handling.jade -include controllers/network-handling.jade +include js-util +include controllers/selection-dropdowns +include controllers/file-handling +include controllers/error-handling +include controllers/network-handling script. l = console.log; diff --git a/views/index/js/js-util.jade b/views/index/js/js-util.pug similarity index 100% rename from views/index/js/js-util.jade rename to views/index/js/js-util.pug diff --git a/views/index/styles/styles-amounts-header.jade b/views/index/styles/styles-amounts-header.pug similarity index 100% rename from views/index/styles/styles-amounts-header.jade rename to views/index/styles/styles-amounts-header.pug diff --git a/views/index/styles/styles-form.jade b/views/index/styles/styles-form.pug similarity index 100% rename from views/index/styles/styles-form.jade rename to views/index/styles/styles-form.pug diff --git a/views/index/styles/styles-social.jade b/views/index/styles/styles-social.pug similarity index 100% rename from views/index/styles/styles-social.jade rename to views/index/styles/styles-social.pug diff --git a/views/index/styles/styles-transcription-results.jade b/views/index/styles/styles-transcription-results.pug similarity index 100% rename from views/index/styles/styles-transcription-results.jade rename to views/index/styles/styles-transcription-results.pug diff --git a/views/layout.jade b/views/layout.pug similarity index 100% rename from views/layout.jade rename to views/layout.pug diff --git a/views/player/js/captionsDisplay.jade b/views/player/js/captionsDisplay.pug similarity index 100% rename from views/player/js/captionsDisplay.jade rename to views/player/js/captionsDisplay.pug diff --git a/views/player/js/secondCaptions.jade b/views/player/js/secondCaptions.pug similarity index 100% rename from views/player/js/secondCaptions.jade rename to views/player/js/secondCaptions.pug diff --git a/views/player/js/videoProgress.jade b/views/player/js/videoProgress.pug similarity index 100% rename from views/player/js/videoProgress.jade rename to views/player/js/videoProgress.pug diff --git a/views/player/player.jade b/views/player/player.pug similarity index 99% rename from views/player/player.jade rename to views/player/player.pug index 31dc1df..d3df743 100644 --- a/views/player/player.jade +++ b/views/player/player.pug @@ -2,8 +2,8 @@ extends ../layout block content - include ../styles/styles-global.jade - include styles-player.jade + include ../styles/styles-global + include styles-player main section.video-container diff --git a/views/player/styles-player.jade b/views/player/styles-player.pug similarity index 100% rename from views/player/styles-player.jade rename to views/player/styles-player.pug diff --git a/views/queue.jade b/views/queue.pug similarity index 100% rename from views/queue.jade rename to views/queue.pug diff --git a/views/stats/stats.jade b/views/stats/stats.pug similarity index 100% rename from views/stats/stats.jade rename to views/stats/stats.pug diff --git a/views/styles/styles-global.jade b/views/styles/styles-global.pug similarity index 100% rename from views/styles/styles-global.jade rename to views/styles/styles-global.pug From 63be88ed60f63c63eb805a4ff80edb7c6cd51a97 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Fri, 6 Jan 2023 15:31:23 +0200 Subject: [PATCH 02/22] refactor requires --- lib/transcribing.js | 7 ++++--- transcribe/transcribe-api-wrapped.js | 12 ++++++------ transcribe/transcribe-wrapped.js | 19 ++++++++++--------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/transcribing.js b/lib/transcribing.js index d5932f1..bfd054a 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -1,10 +1,11 @@ const fs = require('fs-extra'); -const {autoDetectLanguage} = require('../transcribe/transcribing'); -const {formatStdErr} = require('../helpers/formatStdErr'); -const { getLanguageCodeForAllLanguages } = require('../constants/constants'); const filenamify = require('filenamify'); const path = require('path'); +const {autoDetectLanguage} = require('../transcribe/transcribing'); +const {formatStdErr} = require('../helpers/formatStdErr'); +const {getLanguageCodeForAllLanguages} = require('../constants/constants'); + async function writeToProcessingDataFile (processingDataPath, dataObject) { // save data to the file const processingDataExists = await fs.exists(processingDataPath) diff --git a/transcribe/transcribe-api-wrapped.js b/transcribe/transcribe-api-wrapped.js index acc63db..42cf3f8 100644 --- a/transcribe/transcribe-api-wrapped.js +++ b/transcribe/transcribe-api-wrapped.js @@ -1,16 +1,16 @@ const which = require('which'); -const spawn = require('child_process').spawn; +const {spawn} = require('child_process'); const fs = require('fs-extra'); const ffprobe = require('ffprobe'); const WebSocket = require('ws'); -let convert = require('cyrillic-to-latin') -const projectConstants = require('../constants/constants'); -const { shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLanguageCodeForAllLanguages } = projectConstants; -const forHumans = require('../helpers/helpers').forHumans; +let convert = require('cyrillic-to-latin'); + +const {shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLanguageCodeForAllLanguages} = require('../constants/constants'); +const {forHumans} = require('../helpers/helpers'); const createTranslatedFiles = require('../translate/translate-files-api'); const {formatStdErr} = require('../helpers/formatStdErr'); -const LTHost = process.env.LIBRETRANSLATE; const { handleStdErr, handleStdOut, handleProcessClose } = require('../lib/transcribing') +const LTHost = process.env.LIBRETRANSLATE; function getCodeFromLanguageName (languageName) { return translationLanguages.find(function (filteredLanguage) { diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index 42ce98e..c957142 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -1,19 +1,20 @@ const which = require('which'); -const spawn = require('child_process').spawn; +const {spawn} = require('child_process'); const fs = require('fs-extra'); const ffprobe = require('ffprobe'); const WebSocket = require('ws'); const path = require('path'); -const projectConstants = require('../constants/constants'); -const { shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLanguageCodeForAllLanguages } = projectConstants; -const forHumans = require('../helpers/helpers').forHumans; + +const {shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLanguageCodeForAllLanguages} = require('../constants/constants'); +const {forHumans} = require('../helpers/helpers'); +const {formatStdErr} = require('../helpers/formatStdErr'); const createTranslatedFiles = require('../translate/create-translated-files'); +const {convertChineseTraditionalToSimplified, convertSerbianCyrillicToLatin} = require('../lib/convertText'); +const {stripOutTextAndTimestamps} = require('../translate/helpers'); +const {updateQueueItemStatus} = require('../queue/queue'); +// const {amountOfRunningJobs} = require('../queue/newQueue'); + const multipleGpusEnabled = process.env.MULTIPLE_GPUS === 'true'; -const { formatStdErr } = require('../helpers/formatStdErr') -const { convertChineseTraditionalToSimplified, convertSerbianCyrillicToLatin } = require('../lib/convertText'); -const { stripOutTextAndTimestamps } = require('../translate/helpers') -const { updateQueueItemStatus } = require('../queue/queue'); -// const {amountOfRunningJobs} = require("../queue/newQueue"); const maxConcurrentJobs = Number(process.env.CONCURRENT_AMOUNT); function amountOfRunningJobs () { From fb3efaa80a31b223ac1763fe37d2b210af86c06f Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Fri, 6 Jan 2023 16:04:43 +0200 Subject: [PATCH 03/22] refactor amount of running jobs function --- helpers/helpers.js | 8 +++++++- queue/newQueue.js | 15 --------------- routes/transcribe.js | 6 +++--- transcribe/transcribe-wrapped.js | 25 +++++-------------------- 4 files changed, 15 insertions(+), 39 deletions(-) diff --git a/helpers/helpers.js b/helpers/helpers.js index 666a2f5..0b77199 100644 --- a/helpers/helpers.js +++ b/helpers/helpers.js @@ -86,9 +86,15 @@ const decrementBySecond = timeRemainingValues => { } } +const getamountOfRunningJobs = () => + Object.values(global.jobProcesses) + .filter(propValue => propValue !== undefined) + .length; + module.exports = { forHumans, forHumansNoSeconds, decrementBySecond, - forHumansHoursAndMinutes + forHumansHoursAndMinutes, + getamountOfRunningJobs } diff --git a/queue/newQueue.js b/queue/newQueue.js index 834b612..c15f744 100644 --- a/queue/newQueue.js +++ b/queue/newQueue.js @@ -153,20 +153,6 @@ function addToJobProcessOrQueue (jobObject) { sendOutQueuePositionUpdate(); } -// get amount of running jobs (used to calculate queue position) -function amountOfRunningJobs () { - let amount = 0; - for (let processNumber in global.jobProcesses) { - const propValue = global.jobProcesses[processNumber]; - - if (propValue !== undefined) { - amount++; - } - } - - return amount; -} - // get position in queue based on websocketNumber function getQueueInformationByWebsocketNumber (websocketNumber) { for (const [index, queueItem] of global.newQueue.entries()) { @@ -184,7 +170,6 @@ function getQueueInformationByWebsocketNumber (websocketNumber) { module.exports = { addToJobProcessOrQueue, - amountOfRunningJobs, getQueueInformationByWebsocketNumber } diff --git a/routes/transcribe.js b/routes/transcribe.js index 82df72d..46a0c47 100644 --- a/routes/transcribe.js +++ b/routes/transcribe.js @@ -13,10 +13,10 @@ const fs = require('fs-extra'); const { downloadFile, getFilename } = require('../downloading/yt-dlp-download'); const transcribeWrapped = require('../transcribe/transcribe-wrapped'); const { languagesToTranslateTo } = require('../constants/constants'); -const {forHumansNoSeconds} = require('../helpers/helpers'); +const {forHumansNoSeconds, getamountOfRunningJobs} = require('../helpers/helpers'); const {makeFileNameSafe} = require('../lib/files'); const { addItemToQueue, getNumberOfPendingOrProcessingJobs } = require('../queue/queue'); -const { addToJobProcessOrQueue, amountOfRunningJobs } = require('../queue/newQueue'); +const {addToJobProcessOrQueue} = require('../queue/newQueue'); const nodeEnv = process.env.NODE_ENV || 'development'; @@ -181,7 +181,7 @@ router.post('/file', upload.single('file'), async function (req, res, next) { // load websocket by passed number - const currentlyRunningJobs = amountOfRunningJobs(); + const currentlyRunningJobs = getamountOfRunningJobs(); const amountInQueue = global.newQueue.length const totalOutstanding = currentlyRunningJobs + amountInQueue - maxConcurrentJobs + 1; diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index c957142..5ac1843 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -6,41 +6,26 @@ const WebSocket = require('ws'); const path = require('path'); const {shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLanguageCodeForAllLanguages} = require('../constants/constants'); -const {forHumans} = require('../helpers/helpers'); +const {forHumans, getamountOfRunningJobs} = require('../helpers/helpers'); const {formatStdErr} = require('../helpers/formatStdErr'); const createTranslatedFiles = require('../translate/create-translated-files'); const {convertChineseTraditionalToSimplified, convertSerbianCyrillicToLatin} = require('../lib/convertText'); const {stripOutTextAndTimestamps} = require('../translate/helpers'); const {updateQueueItemStatus} = require('../queue/queue'); -// const {amountOfRunningJobs} = require('../queue/newQueue'); const multipleGpusEnabled = process.env.MULTIPLE_GPUS === 'true'; const maxConcurrentJobs = Number(process.env.CONCURRENT_AMOUNT); - -function amountOfRunningJobs () { - let amount = 0; - for (let processNumber in global.jobProcesses) { - const propValue = global.jobProcesses[processNumber]; - - if (propValue !== undefined) { - amount++; - } - } - - return amount; -} - -const l = console.log; - const concurrentAmount = process.env.CONCURRENT_AMOUNT; const nodeEnvironment = process.env.NODE_ENV; const libreTranslateHostPath = process.env.LIBRETRANSLATE; +const l = console.log; + // l(`libreTranslateHostPath: ${libreTranslateHostPath}`) const isProd = nodeEnvironment === 'production'; -const whisperPath = which.sync('whisper') +const whisperPath = which.sync('whisper'); global.transcriptions = []; @@ -222,7 +207,7 @@ async function transcribe ({ // log output from bash (it all comes through stderr for some reason?) whisperProcess.stderr.on('data', data => { - const currentlyRunningJobs = amountOfRunningJobs(); + const currentlyRunningJobs = getamountOfRunningJobs(); const amountInQueue = global.newQueue.length const totalOutstanding = currentlyRunningJobs + amountInQueue; From cd754b42b94803e3feab8e21764163d4b2e9832e Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sat, 7 Jan 2023 10:09:21 +0200 Subject: [PATCH 04/22] refactor formatStdErr --- helpers/formatStdErr.js | 94 +++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 59 deletions(-) diff --git a/helpers/formatStdErr.js b/helpers/formatStdErr.js index 1334af5..9e59786 100644 --- a/helpers/formatStdErr.js +++ b/helpers/formatStdErr.js @@ -1,62 +1,38 @@ -const l = console.log; - -const ten = ' 10%|█ | 5332/52135 [00:10<01:25, 545.77frames/s]'; - -function formatStdErr (stdErrData) { - // if a progress output - if (stdErrData.includes('frames/s')) { - // looks like: '█ ' - const progressBar = stdErrData.split('|')[1].split('|')[0] - - // looks like: '10%' - let percentDone = stdErrData.split('|')[0].trim(); - - // looks like: 10 - let percentDoneAsNumber = Number(stdErrData.split('%')[0].trim()); - - // looks like: '00:10<01:25, 545.77frames/s]' - let timeLeftPortion = stdErrData.split('[')[1].split('[')[0] - - // looks like: '00:10<01:25' - const firstPortion = timeLeftPortion.split(',')[0] - - // looks like: '00:10' - const timeElapsed = firstPortion.split('<')[0] - - // looks like: '01:25' - const timeRemainingString = timeLeftPortion.split('<')[1].split(',')[0] - - // looks like: '545.77' - const speed = timeLeftPortion.split('<')[1].split(',')[1].split('frames')[0].trim() - - // looks like: '545.77' - const splitTimeRemaining = timeRemainingString.split(':') - - // looks like: '01' - const secondsRemaining = Number(splitTimeRemaining.pop()); - - // looks like: '25' - const minutesRemaining = Number(splitTimeRemaining.pop()); - - // looks like: 'NaN' - const hoursRemaining = Number(splitTimeRemaining.pop()); - - // format for lib - return { - progressBar, - percentDone, - timeElapsed, - speed, - percentDoneAsNumber, - timeRemaining: { - string: timeRemainingString, - hoursRemaining, - minutesRemaining, - secondsRemaining - }, - } - } else { - return false +// example of stdErrData: ' 10%|█ | 5332/52135 [00:10<01:25, 545.77frames/s]' + +const formatStdErr = stdErrData => { + // a cleaner and more concise approach + const dataRegex = /^\D*((\d+)%)\|([\u2588\u258C\s]+)\|\s*\d+\/\d+\s\[(\d\d:\d\d)<((?:(\d\d):)?(\d\d):(\d\d)|\?),\s*(\d+\.\d\d|\?)frames\/s\]/; + + // if not a progress output + if (!dataRegex.test(stdErrData)) return false; + + const [ + wholeMatch, + percentDone, // looks like: '10%' + percentDoneAsNumber, // looks like: '10' + progressBar, // looks like: '█ ' + timeElapsed, // looks like: '00:10' + timeRemaining, // looks like: '01:25' + hoursRemaining, // looks like: 'undefined' + minutesRemaining, // looks like: '25' + secondsRemaining, // looks like: '01' + speed // looks like: '545.77' + ] = stdErrData.match(dataRegex); + + // format for lib + return { + progressBar, + percentDone, + timeElapsed, + speed, + percentDoneAsNumber: +percentDoneAsNumber, + timeRemaining: { + string: timeRemaining, + hoursRemaining: +hoursRemaining, + minutesRemaining: +minutesRemaining, + secondsRemaining: +secondsRemaining + }, } } From 09722af5ee54923a51f8f9ef25fecbbf4eb887b0 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sat, 7 Jan 2023 10:10:25 +0200 Subject: [PATCH 05/22] fix minor pug issue --- views/index/components/upload-form.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/index/components/upload-form.pug b/views/index/components/upload-form.pug index aa3579e..42a579b 100644 --- a/views/index/components/upload-form.pug +++ b/views/index/components/upload-form.pug @@ -41,7 +41,7 @@ form.form#form .group label#disable-download-link(for='downloadLink') Enter a link for automatic download p.disabled-paste-button PASTE - input(disabled #disable-download-link style="cursor:pointer;")(type='text' value="Paid Feature, More Info Coming Soon") + input(disabled #disable-download-link style="cursor:pointer;" type='text' value="Paid Feature, More Info Coming Soon") if ytdlp label(for='downloadLink') Enter a link for automatic download p.paste-button PASTE From cd1a90fd675bac584c4fa781fd78df60b84d6952 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sun, 8 Jan 2023 09:29:02 +0200 Subject: [PATCH 06/22] regex bugfix --- helpers/formatStdErr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/formatStdErr.js b/helpers/formatStdErr.js index 9e59786..020dbe0 100644 --- a/helpers/formatStdErr.js +++ b/helpers/formatStdErr.js @@ -2,7 +2,7 @@ const formatStdErr = stdErrData => { // a cleaner and more concise approach - const dataRegex = /^\D*((\d+)%)\|([\u2588\u258C\s]+)\|\s*\d+\/\d+\s\[(\d\d:\d\d)<((?:(\d\d):)?(\d\d):(\d\d)|\?),\s*(\d+\.\d\d|\?)frames\/s\]/; + const dataRegex = /^\D*((\d+)%)\|([\u2580-\u2590\s]+)\|\s*\d+\/\d+\s\[(\d\d:\d\d)<((?:(\d\d):)?(\d\d):(\d\d)|\?),\s*(\d+\.\d\d|\?)frames\/s\]/; // if not a progress output if (!dataRegex.test(stdErrData)) return false; From a12a125cde91fa8438ccfa60c35aa44f5b056fdc Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sun, 8 Jan 2023 09:30:33 +0200 Subject: [PATCH 07/22] refactor convert functions --- lib/convertText.js | 46 ++++++++++++++-------------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/lib/convertText.js b/lib/convertText.js index a607eee..34ff4fd 100644 --- a/lib/convertText.js +++ b/lib/convertText.js @@ -1,41 +1,23 @@ const fs = require('fs-extra'); const convert = require('cyrillic-to-latin'); -const { simplified } = require('zh-convert'); +const {simplified} = require('zh-convert'); -async function convertSerbianCyrillicToLatin ({ - transcribedSrtFilePath, - transcribedVttFilePath, - transcribedTxtFilePath, -}) { - let data = await fs.readFile(transcribedSrtFilePath, 'utf-8'); - let latinCharactersText = convert(data); - await fs.writeFile(transcribedSrtFilePath, latinCharactersText, 'utf-8'); +const fileTypes = ['srt', 'vtt', 'txt']; - data = await fs.readFile(transcribedVttFilePath, 'utf-8'); - latinCharactersText = convert(data); - await fs.writeFile(transcribedVttFilePath, latinCharactersText, 'utf-8'); - - data = await fs.readFile(transcribedTxtFilePath, 'utf-8'); - latinCharactersText = convert(data); - await fs.writeFile(transcribedTxtFilePath, latinCharactersText, 'utf-8'); +const convertSerbianCyrillicToLatin = async path => { + fileTypes.forEach(async fileType => { + const data = await fs.readFile(`${path}.${fileType}`, 'utf-8'); + const latinCharactersText = convert(data); + await fs.writeFile(`${path}.${fileType}`, latinCharactersText, 'utf-8'); + }); } -async function convertChineseTraditionalToSimplified ({ - transcribedSrtFilePath, - transcribedVttFilePath, - transcribedTxtFilePath, -}) { - let data = await fs.readFile(transcribedSrtFilePath, 'utf-8'); - let simplifiedText = simplified(data); - await fs.writeFile(transcribedSrtFilePath, simplifiedText, 'utf-8'); - - data = await fs.readFile(transcribedVttFilePath, 'utf-8'); - simplifiedText = simplified(data); - await fs.writeFile(transcribedVttFilePath, simplifiedText, 'utf-8'); - - data = await fs.readFile(transcribedTxtFilePath, 'utf-8'); - simplifiedText = simplified(data); - await fs.writeFile(transcribedTxtFilePath, simplifiedText, 'utf-8'); +const convertChineseTraditionalToSimplified = async path => { + fileTypes.forEach(async fileType => { + const data = await fs.readFile(`${path}.${fileType}`, 'utf-8'); + const simplifiedText = simplified(data); + await fs.writeFile(`${path}.${fileType}`, simplifiedText, 'utf-8'); + }); } module.exports = { From ceb1cdb18ed1fec14dee8e68282ec1489908dfaf Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sun, 8 Jan 2023 15:25:51 +0200 Subject: [PATCH 08/22] pulling out transcribe code into functions --- helpers/helpers.js | 7 +- lib/transcribing.js | 72 +++++ lib/websockets.js | 37 +-- transcribe/transcribe-api-wrapped.js | 15 +- transcribe/transcribe-wrapped.js | 272 ++++++------------ transcribe/transcribing.js | 30 -- .../index/js/controllers/network-handling.pug | 2 +- 7 files changed, 176 insertions(+), 259 deletions(-) diff --git a/helpers/helpers.js b/helpers/helpers.js index 0b77199..13c74ca 100644 --- a/helpers/helpers.js +++ b/helpers/helpers.js @@ -91,10 +91,15 @@ const getamountOfRunningJobs = () => .filter(propValue => propValue !== undefined) .length; +const sendToWebsocket = (websocketConnection, data) => { + websocketConnection.send(JSON.stringify(data), function () {}); +} + module.exports = { forHumans, forHumansNoSeconds, decrementBySecond, forHumansHoursAndMinutes, - getamountOfRunningJobs + getamountOfRunningJobs, + sendToWebsocket, } diff --git a/lib/transcribing.js b/lib/transcribing.js index bfd054a..a445d90 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -5,6 +5,12 @@ const path = require('path'); const {autoDetectLanguage} = require('../transcribe/transcribing'); const {formatStdErr} = require('../helpers/formatStdErr'); const {getLanguageCodeForAllLanguages} = require('../constants/constants'); +const { stripOutTextAndTimestamps } = require('../translate/helpers'); +const { convertSerbianCyrillicToLatin, convertChineseTraditionalToSimplified } = require('./convertText'); + +const isProd = process.env.NODE_ENV === 'production'; +const multipleGpusEnabled = process.env.MULTIPLE_GPUS === 'true'; + async function writeToProcessingDataFile (processingDataPath, dataObject) { // save data to the file @@ -122,6 +128,68 @@ function handleProcessClose ({ processingDataPath, originalUpload, randomNumber } } +const buildWhisperArguments = ({filePath, language, model, randomNumber}) => { + // queue up arguments, path is the first one + const arguments = [filePath]; + + const languageIsAutoDetect = language === 'auto-detect'; + + // don't pass a language to use auto-detect + !languageIsAutoDetect && arguments.push('--language', language); + + arguments.push(...[ + // model to use + '--model', model, + // dont show the text output but show the progress thing + '--verbose', 'False', + // folder to save .txt, .vtt and .srt + '-o', 'transcriptions/' + randomNumber + ]); + + // alternate + // todo: do an 'express' queue and a 'large files' queue + if (isProd && multipleGpusEnabled) { + if (topLevelValue === 1) { + arguments.push('--device', 'cuda:0'); + } else if (topLevelValue === 2) { + arguments.push('--device', 'cuda:1'); + } + } + + return arguments; +} + +const convertLanguageText = async (language, path) => { + // convert Serbian text from Cyrillic to Latin + if (language === 'Serbian') { + await convertSerbianCyrillicToLatin(path); + } + + // convert Chinese characters to Simplified + if (language === 'Chinese') { + await convertChineseTraditionalToSimplified(path); + } +} + +const updateFileDetails = async ({websocketConnection, filename, language, model, duration}) => { + const fileDetails = ` + Filename: ${filename} + Language: ${language} + Model: ${model} + Upload Duration: ${duration} + `.replace(/^ +/gm, ''); // remove indentation + + // update file details + websocketConnection.send(JSON.stringify({ + message: 'fileDetails', + fileDetails + }), function () {}); +} + +const removeFromArrayByWsNumber = (array, wsNumber) => { + return array.filter(item => item.websocketNumber !== wsNumber); +} + // example file from multer // { // fieldname: 'file', @@ -165,6 +233,10 @@ module.exports = { handleStdOut, handleStdErr, handleProcessClose, + buildWhisperArguments, + convertLanguageText, + updateFileDetails, + removeFromArrayByWsNumber, // file name helpers makeFileNameSafe, diff --git a/lib/websockets.js b/lib/websockets.js index b822a74..b34833b 100644 --- a/lib/websockets.js +++ b/lib/websockets.js @@ -2,60 +2,33 @@ const WebSocket = require('ws'); const WebSocketServer = WebSocket.WebSocketServer; const { getQueueInformationByWebsocketNumber } = require('../queue/newQueue'); const { updateQueueItemStatus } = require('../queue/queue'); - -function deleteFromGlobalTranscriptionsBasedOnWebsocketNumber (websocketNumber) { - // find transcription based on websocketNumber - const closerTranscription = global['transcriptions'].find(function (transcription) { - return transcription.websocketNumber === websocketNumber; - }) - - const transcriptionIndex = global.transcriptions.indexOf(closerTranscription); - if (transcriptionIndex > -1) { // only splice array when item is found - global.transcriptions.splice(transcriptionIndex, 1); // 2nd parameter means remove one item only - } -} - +const {removeFromArrayByWsNumber} = require('./transcribing'); /** when websocket disconnects **/ function deleteWebsocketAndEndProcesses ({ websocketNumber, websocketConnection, websocket, index }) { l(`Disconnected user found: ${websocketNumber}`); - function matchByWebsocketNumber (item) { - return item.websocketNumber === websocketNumber; - } - // disconnect websocket and delete from global holder websocketConnection.terminate(); global.webSocketData.splice(index, 1); l(`${websocketNumber} Deleted from global.webSocketData`); // find transcription based on websocketNumber - const foundProcess = global.transcriptions.find(matchByWebsocketNumber) - - const existingProcess = foundProcess && foundProcess.spawnedProcess; + const foundProcess = global.transcriptions.find(item => item.websocketNumber === websocketNumber); // kill the process - if (existingProcess) { + if (foundProcess?.spawnedProcess) { // TODO: save processing info and conditionally kill foundProcess.spawnedProcess.kill('SIGINT'); l(`Found and killed process: ${websocketNumber}`); // delete from transcription array - const transcriptionIndex = global.transcriptions.findIndex(matchByWebsocketNumber); - if (index > -1) { // only splice array when item is found - global.transcriptions.splice(transcriptionIndex, 1); // 2nd parameter means remove one item only - } + global.transcriptions = removeFromArrayByWsNumber(global.transcriptions, websocketNumber); } // delete from queue - const queueIndex = global.newQueue.findIndex(matchByWebsocketNumber); - - if (queueIndex > -1) { // only splice array when item is found - global.newQueue.splice(queueIndex, 1); // 2nd parameter means remove one item only - - l(`${websocketNumber} Deleted from global.newQueue`); - } + global.newQueue = removeFromArrayByWsNumber(global.newQueue, websocketNumber); // only updates if not marked as completed updateQueueItemStatus(websocketNumber, 'abandoned'); diff --git a/transcribe/transcribe-api-wrapped.js b/transcribe/transcribe-api-wrapped.js index 42cf3f8..4f8f56a 100644 --- a/transcribe/transcribe-api-wrapped.js +++ b/transcribe/transcribe-api-wrapped.js @@ -9,7 +9,7 @@ const {shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLang const {forHumans} = require('../helpers/helpers'); const createTranslatedFiles = require('../translate/translate-files-api'); const {formatStdErr} = require('../helpers/formatStdErr'); -const { handleStdErr, handleStdOut, handleProcessClose } = require('../lib/transcribing') +const { handleStdErr, handleStdOut, handleProcessClose, buildWhisperArguments } = require('../lib/transcribing') const LTHost = process.env.LIBRETRANSLATE; function getCodeFromLanguageName (languageName) { @@ -21,7 +21,6 @@ function getCodeFromLanguageName (languageName) { const { // autoDetectLanguage, - buildArguments, // moveAndRenameFilesAndFolder, // saveTranscriptionCompletedInformation, // writeToProcessingDataFile, @@ -51,15 +50,11 @@ async function transcribe ({ const startingDate = new Date(); l(startingDate); - const whisperArguments = buildArguments({ - uploadedFilePath: originalUpload, // file to use - language, // - model, - randomNumber, - }) + const whisperArguments = buildWhisperArguments({ + language, model, filePath: originalUpload, randomNumber + }); - l('whisperArguments'); - l(whisperArguments); + l({whisperArguments}); // start whisper process const whisperProcess = spawn(whisperPath, whisperArguments); diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index 5ac1843..e5a2e9a 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -6,33 +6,26 @@ const WebSocket = require('ws'); const path = require('path'); const {shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLanguageCodeForAllLanguages} = require('../constants/constants'); -const {forHumans, getamountOfRunningJobs} = require('../helpers/helpers'); +const {forHumans, getamountOfRunningJobs, sendToWebsocket} = require('../helpers/helpers'); const {formatStdErr} = require('../helpers/formatStdErr'); const createTranslatedFiles = require('../translate/create-translated-files'); -const {convertChineseTraditionalToSimplified, convertSerbianCyrillicToLatin} = require('../lib/convertText'); +const {buildWhisperArguments, convertLanguageText, updateFileDetails, removeFromArrayByWsNumber} = require('../lib/transcribing'); const {stripOutTextAndTimestamps} = require('../translate/helpers'); const {updateQueueItemStatus} = require('../queue/queue'); -const multipleGpusEnabled = process.env.MULTIPLE_GPUS === 'true'; const maxConcurrentJobs = Number(process.env.CONCURRENT_AMOUNT); const concurrentAmount = process.env.CONCURRENT_AMOUNT; -const nodeEnvironment = process.env.NODE_ENV; const libreTranslateHostPath = process.env.LIBRETRANSLATE; const l = console.log; // l(`libreTranslateHostPath: ${libreTranslateHostPath}`) -const isProd = nodeEnvironment === 'production'; const whisperPath = which.sync('whisper'); global.transcriptions = []; -function sendToWebsocket (websocketConnection, data) { - websocketConnection.send(JSON.stringify(data), function () {}); -} - async function transcribe ({ uploadedFilePath, language, @@ -55,12 +48,10 @@ async function transcribe ({ }) { return new Promise(async (resolve, reject) => { - function webSocketIsStillAlive (webSocketNumber) { - return global.webSocketData.some(item => item.websocketNumber === webSocketNumber); - } + const webSocketIsStillAlive = num => global.webSocketData.some(item => item.websocketNumber === num); // if the upload was removed from the queue, don't run it - if (webSocketIsStillAlive(websocketNumber) === false) { + if (!webSocketIsStillAlive(websocketNumber)) { l('DIDNT HAVE THE QUEUE DATA MATCH, ABORTING'); // if they're not in the queue, cut them off // TODO: change to reject? @@ -74,7 +65,8 @@ async function transcribe ({ sendToWebsocket(websocketConnection, { message: 'starting', text: 'Whisper initializing, updates to come...' - }) + }); + updateQueueItemStatus(websocketNumber, 'processing'); // fixes bug with windows @@ -83,95 +75,48 @@ async function transcribe ({ // get the upload file name // the ugly generated file id made the during the upload (for moving the upload over) let uploadFolderFileName = uploadedFilePath.split(osSpecificPathSeparator).pop(); - const originalUpload = `./uploads/${uploadFolderFileName}`; - + const uploadDurationInSecondsHumanReadable = forHumans(uploadDurationInSeconds); + let displayLanguage = language === 'auto-detect' ? 'Auto-Detect' : language; const fileDetailsJSON = { filename: directorySafeFileNameWithExtension, - language, + language: displayLanguage, model, uploadDurationInSeconds, uploadDurationInSecondsHumanReadable, } - let displayLanguage; - if (language === 'auto-detect') { - displayLanguage = 'Auto-Detect'; - } else { - displayLanguage = language; - } - // just do JSON, then loop through properties on the frontend - let fileDetails = ` - Filename: ${directorySafeFileNameWithExtension} - Language: ${displayLanguage} - Model: ${model} - Upload Duration: ${uploadDurationInSecondsHumanReadable} - `.replace(/^ +/gm, ''); // remove indentation - - // update filedetails - websocketConnection.send(JSON.stringify({ - message: 'fileDetails', - fileDetails - }), function () {}); + updateFileDetails({ + websocketConnection, language: displayLanguage, model, duration: uploadDurationInSecondsHumanReadable, filename: directorySafeFileNameWithExtension + }); /** INSTANTIATE WHISPER PROCESS **/ - // queue up arguments, path is the first one - let arguments = [uploadedFilePath]; - - const languageIsAutoDetect = language === 'auto-detect'; - - // don't pass a language to use auto-detect - if (!languageIsAutoDetect) { - arguments.push('--language', language); - } - - // set the language for whisper (if undefined with auto-detect and translate off that) - if (model) { - arguments.push('--model', model); - } - - // alternate - // todo: do an 'express' queue and a 'large files' queue - if (isProd && multipleGpusEnabled) { - if (topLevelValue === 1) { - arguments.push('--device', 'cuda:0'); - } else if (topLevelValue === 2) { - arguments.push('--device', 'cuda:1'); - } - } - - // dont show the text output but show the progress thing - arguments.push('--verbose', 'False'); - - // folder to save .txt, .vtt and .srt - arguments.push('-o', 'transcriptions/' + uploadGeneratedFilename); - - l('transcribe arguments'); - l(arguments); - - const whisperProcess = spawn(whisperPath, arguments); - - // TODO: rename - let serverNumber = processNumber + const whisperArguments = buildWhisperArguments({ + filePath: uploadedFilePath, language, model, randomNumber: uploadGeneratedFilename + }); + l({whisperArguments}); + + const whisperProcess = spawn(whisperPath, whisperArguments); // add process globally to kill it when user leaves const process = { websocketNumber, spawnedProcess: whisperProcess, - serverNumber, + processNumber, type: 'transcription', } - global.transcriptions.push(process) + + global.transcriptions.push(process); // find auto-detected language let foundLanguage; // console output from stdoutt whisperProcess.stdout.on('data', data => { - websocketConnection.send(JSON.stringify(`stdout: ${data}`), function () {}); + sendToWebsocket(websocketConnection, `stdout: ${data}`); l(`STDOUT: ${data}`); // TODO: pull this out into own function @@ -184,31 +129,22 @@ async function transcribe ({ l(`DETECTED LANGUAGE FOUND: ${foundLanguage}`); if (language === 'auto-detect' && foundLanguage) { - language = foundLanguage - displayLanguage = `${language} (Auto-Detected)` + language = foundLanguage; + displayLanguage = `${language} (Auto-Detected)`; } // send data to frontend with updated language // TODO: when it's JSON, just add the detected language here as a property - fileDetails = ` - Filename: ${directorySafeFileNameWithExtension} - Language: ${displayLanguage} - Model: ${model} - Upload Duration: ${uploadDurationInSecondsHumanReadable} - `.replace(/^ +/gm, ''); // remove indentation - - // update file details - websocketConnection.send(JSON.stringify({ - message: 'fileDetails', - fileDetails - }), function () {}); + updateFileDetails({ + websocketConnection, language: displayLanguage, model, duration: uploadDurationInSecondsHumanReadable, filename: directorySafeFileNameWithExtension + }); } }); // log output from bash (it all comes through stderr for some reason?) whisperProcess.stderr.on('data', data => { const currentlyRunningJobs = getamountOfRunningJobs(); - const amountInQueue = global.newQueue.length + const amountInQueue = global.newQueue.length; const totalOutstanding = currentlyRunningJobs + amountInQueue; let outputString = ` @@ -221,113 +157,91 @@ async function transcribe ({ Translating: ${shouldTranslate}`; outputString = outputString.replace(/\s+/g, ' '); - l(outputString); - - - + l({outputString}); // loop through and do with websockets - for (let [, websocket] of global['webSocketData'].entries() ) { - const websocketConnection = websocket.websocket; - const clientWebsocketNumber = websocket.websocketNumber; - const websocketFromProcess = websocketNumber; - - let ownershipPerson = 'others' - if (clientWebsocketNumber === websocketFromProcess) { - ownershipPerson = 'you' - } - + global.webSocketData.forEach(({websocket: websocketConnection, websocketNumber: clientWebsocketNumber}) => { + const ownershipPerson = clientWebsocketNumber === websocketNumber ? 'you' : 'others'; const formattedProgress = formatStdErr(data.toString()); - // l('formattedProgress'); - // l(formattedProgress); - const { percentDoneAsNumber, percentDone, speed, timeRemaining } = formattedProgress; + const {percentDoneAsNumber, percentDone, speed, timeRemaining} = formattedProgress; - let processingString = ''; - if (timeRemaining) { - processingString = `[${percentDone}] ${timeRemaining.string} Remaining, Speed ${speed}f/s` - } + const processingString = timeRemaining ? `[${percentDone}] ${timeRemaining.string} Remaining, Speed ${speed}f/s` : ''; // TODO: pull into function // pass latest data to all the open sockets if (websocketConnection.readyState === WebSocket.OPEN) { /** websocketData message **/ - websocketConnection.send(JSON.stringify({ + sendToWebsocket(websocketConnection, { message: 'websocketData', processingData: processingString, // processingData: data.toString(), ownershipPerson, - serverNumber, // on the frontend we'll react different if it's on server 1 or two + processNumber, // on the frontend we'll react different if it's on server 1 or two formattedProgress, percentDone: percentDoneAsNumber, timeRemaining, speed, - })); + }); } - } + }); }); - // save date when starting to see how long it's taking const startingDate = new Date(); - l(startingDate); + l({startingDate}); /** AFTER WHISPER FINISHES, DO THE FILE MANIPULATION / TRANSLATION **/ - whisperProcess.on('close', async (code) => { + whisperProcess.on('close', async code => { try { - l('code'); - l(code); - + l({code}); + if (!language || language === 'auto-detect') { language = foundLanguage; } - const processFinishedSuccessfully = code === 0 + const processFinishedSuccessfully = code === 0; // successful output if (processFinishedSuccessfully) { // TODO: pull out all this moving stuff into its own function - + const originalContainingDir = `./transcriptions/${uploadGeneratedFilename}`; - - const originalDirectoryAndNewFileName = `${originalContainingDir}/${directorySafeFileNameWithoutExtension}` - - await fs.move(originalUpload, `${originalContainingDir}/${directorySafeFileNameWithExtension}`, { overwrite: true }) + + const originalDirectoryAndNewFileName = `${originalContainingDir}/${directorySafeFileNameWithoutExtension}`; + + l({originalUpload, originalContainingDir, directorySafeFileNameWithExtension}); + await fs.move(originalUpload, `${originalContainingDir}/${directorySafeFileNameWithExtension}`, {overwrite: true}); // turn this to a loop /** COPY TO BETTER NAME, SRT, VTT, TXT **/ - const transcribedSrtFilePath = `${originalDirectoryAndNewFileName}.srt`; + const fileTypes = ['srt', 'vtt', 'txt']; + // doesn't work + // fileTypes.forEach(async fileType => { + // await fs.move(`${originalContainingDir}/${uploadFolderFileName}.${fileType}`, `${originalDirectoryAndNewFileName}.${fileType}`, { overwrite: true }); + // }); + const srtPath = `${originalDirectoryAndNewFileName}.srt`; - const transcribedVttFilePath = `${originalDirectoryAndNewFileName}.vtt`; + const vttPath = `${originalDirectoryAndNewFileName}.vtt`; - const transcribedTxtFilePath = `${originalDirectoryAndNewFileName}.txt`; + const txtPath = `${originalDirectoryAndNewFileName}.txt`; // copy srt with the original filename // SOURCE, ORIGINAL // TODO: could probably move here instead of copy - await fs.move(`${originalContainingDir}/${uploadFolderFileName}.srt`, transcribedSrtFilePath, { overwrite: true }) + await fs.move(`${originalContainingDir}/${uploadFolderFileName}.srt`, srtPath, { overwrite: true }) - await fs.move(`${originalContainingDir}/${uploadFolderFileName}.vtt`, transcribedVttFilePath, { overwrite: true }) + await fs.move(`${originalContainingDir}/${uploadFolderFileName}.vtt`, vttPath, { overwrite: true }) - await fs.move(`${originalContainingDir}/${uploadFolderFileName}.txt`, transcribedTxtFilePath, { overwrite: true }) + await fs.move(`${originalContainingDir}/${uploadFolderFileName}.txt`, txtPath, { overwrite: true }) - // convert Serbian text from Cyrillic to Latin - if (language === 'Serbian') { - await convertSerbianCyrillicToLatin({ transcribedSrtFilePath, transcribedVttFilePath, transcribedTxtFilePath }) - } - - // convert Chinese characters to Simplified - if (language === 'Chinese') { - await convertChineseTraditionalToSimplified({ transcribedSrtFilePath, transcribedVttFilePath, transcribedTxtFilePath }) - } + await convertLanguageText(language, originalDirectoryAndNewFileName); updateQueueItemStatus(websocketNumber, 'completed'); // return await so queue moves on, don't need to wait for translations resolve(code); - l(`should translate: ${shouldTranslate}`) - - const vttPath = `${originalDirectoryAndNewFileName}.vtt`; + l({shouldTranslate}); // copy original as copied await fs.copy(vttPath, `${originalDirectoryAndNewFileName}_${language}.vtt`) @@ -339,10 +253,10 @@ async function transcribe ({ /** TRANSLATION FUNCTIONALITY **/ if (libreTranslateHostPath, shouldTranslate) { // tell frontend that we're translating now - websocketConnection.send(JSON.stringify({ + sendToWebsocket(websocketConnection, { languageUpdate: 'Doing translations with LibreTranslate', message: 'languageUpdate' - }), function () {}); + }); l('hitting LibreTranslate'); translationStarted = true; // hit libretranslate @@ -363,28 +277,28 @@ async function transcribe ({ // TODO: just have a function called "sendFileInfoToClient(fileInfoJSON)" const outputText = ` - filename: ${originalFileNameWithExtension} - processingSeconds: ${processingSeconds} - processingSecondsHumanReadable: ${forHumans(processingSeconds)} - language: ${language} - model: ${model} - upload: ${uploadFolderFileName} - uploadDurationInSeconds: ${uploadDurationInSeconds} - uploadDurationInSecondsHumanReadable: ${forHumans(uploadDurationInSeconds)} - processingRatio: ${processingRatio} - startedAt: ${startingDate.toUTCString()} - finishedAT: ${new Date().toUTCString()} - `.replace(/^ +/gm, ''); // remove indentation + filename: ${originalFileNameWithExtension} + processingSeconds: ${processingSeconds} + processingSecondsHumanReadable: ${forHumans(processingSeconds)} + language: ${language} + model: ${model} + upload: ${uploadFolderFileName} + uploadDurationInSeconds: ${uploadDurationInSeconds} + uploadDurationInSecondsHumanReadable: ${forHumans(uploadDurationInSeconds)} + processingRatio: ${processingRatio} + startedAt: ${startingDate.toUTCString()} + finishedAT: ${new Date().toUTCString()} + `.replace(/^ +/gm, ''); // remove indentation // tell frontend upload is done - websocketConnection.send(JSON.stringify({ + sendToWebsocket(websocketConnection, { status: 'Completed', - urlSrt: transcribedSrtFilePath, - urlVtt: transcribedVttFilePath, - urlTxt: transcribedTxtFilePath, + urlSrt: srtPath, + urlVtt: vttPath, + urlTxt: txtPath, filename: fileSafeNameWithDateTimestamp, detailsString: outputText - }), function () {}); + }); const translationStartedAndCompleted = translationStarted && translationFinished; @@ -422,11 +336,10 @@ async function transcribe ({ wordsPerMinute, fileSizeInMB, characterCount: strippedText.length, + user, + downloadLink, } - if (downloadLink) fileDetailsObject.downloadLink = downloadLink; - if (user) fileDetailsObject.user = user; - // save processing_data.json await fs.appendFile(`${originalContainingDir}/processing_data.json`, JSON.stringify(fileDetailsObject), 'utf8'); @@ -434,19 +347,8 @@ async function transcribe ({ const renamedDirectory = `./transcriptions/${fileSafeNameWithDateTimestamp}`; await fs.rename(originalContainingDir, renamedDirectory) - function matchByWebsocketNumber (item) { - return item.websocketNumber === websocketNumber; - } - - function removeFromArrayByWebsocketNumber (array) { - const index = array.findIndex(matchByWebsocketNumber); - if (index > -1) { - array.splice(index, 1); - } - } - - removeFromArrayByWebsocketNumber(global.transcriptions, websocketNumber); - + // remove from global.transcriptions + global.transcriptions = removeFromArrayByWsNumber(global.transcriptions, websocketNumber); } else { l('FAILED!'); @@ -454,7 +356,7 @@ async function transcribe ({ throw new Error('Transcription has been ended') } - l(`child process exited with code ${code}`); + // l(`child process exited with code ${code}`); } catch (err) { updateQueueItemStatus(websocketNumber, 'errored'); @@ -481,10 +383,10 @@ async function transcribe ({ updateQueueItemStatus(websocketNumber, 'errored'); - websocketConnection.send(JSON.stringify({ + sendToWebsocket(websocketConnection, { message: 'error', text: 'The transcription failed, please try again or try again later' - }), function () {}); + }); reject(err); throw err; diff --git a/transcribe/transcribing.js b/transcribe/transcribing.js index 39a8a52..bd4e3f3 100644 --- a/transcribe/transcribing.js +++ b/transcribe/transcribing.js @@ -10,35 +10,6 @@ const libreTranslateHostPath = process.env.LIBRETRANSLATE; const isProd = nodeEnvironment === 'production'; -function buildArguments ({ - uploadedFilePath, - language, - model, - randomNumber -}) { - /** INSTANTIATE WHISPER PROCESS **/ - // queue up arguments, path is the first one - let arguments = []; - - // first argument is path to file - arguments.push(uploadedFilePath); - - // these don't have to be defined - if (language) arguments.push('--language', language); - if (model) arguments.push('--model', model); - - // dont show the text output but show the progress thing - arguments.push('--verbose', 'False'); - - // folder to save .txt, .vtt and .srt - arguments.push('-o', `transcriptions/${randomNumber}`); - - l('transcribe arguments'); - l(arguments); - - return arguments -} - async function translateIfNeeded ({ language, shouldTranslate, processingDataPath, directoryAndFileName}) { const shouldTranslateFromLanguage = shouldTranslateFrom(language); l(`should translate from language: ${shouldTranslateFromLanguage}`) @@ -115,7 +86,6 @@ module.exports = { moveAndRenameFilesAndFolder, saveTranscriptionCompletedInformation, translateIfNeeded, - buildArguments, // autoDetectLanguage, // writeToProcessingDataFile } diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index a6df03b..72dc647 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -185,7 +185,7 @@ script. //- destructure the data object -osb910 let { ownershipPerson, - serverNumber: processNumber, + processNumber, percentDone, timeRemaining, processingData, From 04e53065494f8935a9eb3700e15ab3157736fce4 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Wed, 11 Jan 2023 09:35:30 +0200 Subject: [PATCH 09/22] use an object to store and pass file info instead of a string --- constants/constants.js | 1 + lib/transcribing.js | 19 +- transcribe/transcribe-wrapped.js | 190 ++++++------------ .../components/transcription-results.pug | 6 +- .../index/js/controllers/network-handling.pug | 42 +++- .../styles/styles-transcription-results.pug | 17 +- 6 files changed, 133 insertions(+), 142 deletions(-) diff --git a/constants/constants.js b/constants/constants.js index 29b289d..dfc8d96 100644 --- a/constants/constants.js +++ b/constants/constants.js @@ -13,6 +13,7 @@ const languagesArray = whisperLanguagesHumanReadableArray.map(lang => ({value: l languagesArray.unshift({value: 'auto-detect', name: 'Auto-Detect'}); function getLanguageCodeForAllLanguages (languageName) { + l(Object.values(languageNameMap)); let foundLanguageCode; Object.keys(languageNameMap).forEach(languageCode =>{ if (languageNameMap[languageCode].name === languageName) { diff --git a/lib/transcribing.js b/lib/transcribing.js index a445d90..42e64b0 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -7,6 +7,7 @@ const {formatStdErr} = require('../helpers/formatStdErr'); const {getLanguageCodeForAllLanguages} = require('../constants/constants'); const { stripOutTextAndTimestamps } = require('../translate/helpers'); const { convertSerbianCyrillicToLatin, convertChineseTraditionalToSimplified } = require('./convertText'); +const { sendToWebsocket } = require('../helpers/helpers'); const isProd = process.env.NODE_ENV === 'production'; const multipleGpusEnabled = process.env.MULTIPLE_GPUS === 'true'; @@ -132,7 +133,7 @@ const buildWhisperArguments = ({filePath, language, model, randomNumber}) => { // queue up arguments, path is the first one const arguments = [filePath]; - const languageIsAutoDetect = language === 'auto-detect'; + const languageIsAutoDetect = /auto-detect/i.test(language); // don't pass a language to use auto-detect !languageIsAutoDetect && arguments.push('--language', language); @@ -180,16 +181,23 @@ const updateFileDetails = async ({websocketConnection, filename, language, model `.replace(/^ +/gm, ''); // remove indentation // update file details - websocketConnection.send(JSON.stringify({ - message: 'fileDetails', - fileDetails - }), function () {}); + sendToWebsocket(websocketConnection, {message: 'fileDetails', fileDetails}); } const removeFromArrayByWsNumber = (array, wsNumber) => { return array.filter(item => item.websocketNumber !== wsNumber); } +const updateDetectedLanguage = ({dataAsString, fileInfo, websocketConnection}) => { + const detectedLang = dataAsString.match(/Detected language: ([a-z]+)\b/i)[1]; + l(`DETECTED LANGUAGE FOUND: ${detectedLang}`); + fileInfo.language = detectedLang; + fileInfo.languageCode = getLanguageCodeForAllLanguages(detectedLang); + fileInfo.isAutoDetected = true; + sendToWebsocket(websocketConnection, {message: 'fileDetails', ...fileInfo}); + return detectedLang; +} + // example file from multer // { // fieldname: 'file', @@ -237,6 +245,7 @@ module.exports = { convertLanguageText, updateFileDetails, removeFromArrayByWsNumber, + updateDetectedLanguage, // file name helpers makeFileNameSafe, diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index e5a2e9a..f6d5b7b 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -9,7 +9,7 @@ const {shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLang const {forHumans, getamountOfRunningJobs, sendToWebsocket} = require('../helpers/helpers'); const {formatStdErr} = require('../helpers/formatStdErr'); const createTranslatedFiles = require('../translate/create-translated-files'); -const {buildWhisperArguments, convertLanguageText, updateFileDetails, removeFromArrayByWsNumber} = require('../lib/transcribing'); +const {buildWhisperArguments, convertLanguageText, updateFileDetails, removeFromArrayByWsNumber, updateDetectedLanguage} = require('../lib/transcribing'); const {stripOutTextAndTimestamps} = require('../translate/helpers'); const {updateQueueItemStatus} = require('../queue/queue'); @@ -74,28 +74,34 @@ async function transcribe ({ // get the upload file name // the ugly generated file id made the during the upload (for moving the upload over) - let uploadFolderFileName = uploadedFilePath.split(osSpecificPathSeparator).pop(); + const uploadFolderFileName = uploadedFilePath.split(osSpecificPathSeparator).pop(); const originalUpload = `./uploads/${uploadFolderFileName}`; const uploadDurationInSecondsHumanReadable = forHumans(uploadDurationInSeconds); - let displayLanguage = language === 'auto-detect' ? 'Auto-Detect' : language; - const fileDetailsJSON = { - filename: directorySafeFileNameWithExtension, - language: displayLanguage, + const fileInfo = { + filename: originalFileNameWithExtension, + fileExtension: path.parse(originalFileNameWithExtension).ext, + fileSizeInMB, + directoryFileName: directorySafeFileNameWithoutExtension, + language: language === 'auto-detect' ? 'Auto-Detect' : language, + languageCode: getLanguageCodeForAllLanguages(language), model, + upload: uploadFolderFileName, uploadDurationInSeconds, - uploadDurationInSecondsHumanReadable, + uploadDuration: uploadDurationInSecondsHumanReadable, + user, + downloadLink, + processNumber, + translationStarted: false, + translationFinished: false, } - // just do JSON, then loop through properties on the frontend - updateFileDetails({ - websocketConnection, language: displayLanguage, model, duration: uploadDurationInSecondsHumanReadable, filename: directorySafeFileNameWithExtension - }); + sendToWebsocket(websocketConnection, {message: 'fileDetails', ...fileInfo}); /** INSTANTIATE WHISPER PROCESS **/ const whisperArguments = buildWhisperArguments({ - filePath: uploadedFilePath, language, model, randomNumber: uploadGeneratedFilename + filePath: uploadedFilePath, language: fileInfo.language, model, randomNumber: uploadGeneratedFilename }); l({whisperArguments}); @@ -111,10 +117,7 @@ async function transcribe ({ global.transcriptions.push(process); - // find auto-detected language - let foundLanguage; - - // console output from stdoutt + // console output from stdout whisperProcess.stdout.on('data', data => { sendToWebsocket(websocketConnection, `stdout: ${data}`); l(`STDOUT: ${data}`); @@ -123,21 +126,7 @@ async function transcribe ({ // check if language is autodetected) const dataAsString = data.toString(); if (dataAsString.includes('Detected language:')) { - - // parse out the language from the console output - foundLanguage = dataAsString.split(':')[1].substring(1).trimEnd(); - - l(`DETECTED LANGUAGE FOUND: ${foundLanguage}`); - if (language === 'auto-detect' && foundLanguage) { - language = foundLanguage; - displayLanguage = `${language} (Auto-Detected)`; - } - - // send data to frontend with updated language - // TODO: when it's JSON, just add the detected language here as a property - updateFileDetails({ - websocketConnection, language: displayLanguage, model, duration: uploadDurationInSecondsHumanReadable, filename: directorySafeFileNameWithExtension - }); + foundLanguage = updateDetectedLanguage({dataAsString, fileInfo, websocketConnection}); } }); @@ -145,42 +134,32 @@ async function transcribe ({ whisperProcess.stderr.on('data', data => { const currentlyRunningJobs = getamountOfRunningJobs(); const amountInQueue = global.newQueue.length; - const totalOutstanding = currentlyRunningJobs + amountInQueue; - - let outputString = ` - STDERR: ${data}, - Duration: ${uploadDurationInSecondsHumanReadable}, - Model: ${model}, - Language: ${displayLanguage}, - Filename: ${directorySafeFileNameWithExtension}, - Queue: ${totalOutstanding}, - Translating: ${shouldTranslate}`; - - outputString = outputString.replace(/\s+/g, ' '); - l({outputString}); + const totalOutstanding = currentlyRunningJobs + amountInQueue; // what for? + + l({STDERR: data, ...fileInfo, queue: totalOutstanding, translating: shouldTranslate}); + // loop through and do with websockets global.webSocketData.forEach(({websocket: websocketConnection, websocketNumber: clientWebsocketNumber}) => { + const ownershipPerson = clientWebsocketNumber === websocketNumber ? 'you' : 'others'; + fileInfo.ownershipPerson = ownershipPerson; const formattedProgress = formatStdErr(data.toString()); + fileInfo.formattedProgress = formattedProgress; const {percentDoneAsNumber, percentDone, speed, timeRemaining} = formattedProgress; + fileInfo.percentDone = percentDoneAsNumber; + fileInfo.timeRemaining = timeRemaining; + fileInfo.speed = speed; const processingString = timeRemaining ? `[${percentDone}] ${timeRemaining.string} Remaining, Speed ${speed}f/s` : ''; + fileInfo.processingData = processingString; - // TODO: pull into function // pass latest data to all the open sockets if (websocketConnection.readyState === WebSocket.OPEN) { /** websocketData message **/ sendToWebsocket(websocketConnection, { message: 'websocketData', - processingData: processingString, - // processingData: data.toString(), - ownershipPerson, - processNumber, // on the frontend we'll react different if it's on server 1 or two - formattedProgress, - percentDone: percentDoneAsNumber, - timeRemaining, - speed, + ...fileInfo }); } }); @@ -188,17 +167,13 @@ async function transcribe ({ // save date when starting to see how long it's taking const startingDate = new Date(); - l({startingDate}); + fileInfo.startedAt = startingDate.toUTCString(); /** AFTER WHISPER FINISHES, DO THE FILE MANIPULATION / TRANSLATION **/ whisperProcess.on('close', async code => { try { l({code}); - if (!language || language === 'auto-detect') { - language = foundLanguage; - } - const processFinishedSuccessfully = code === 0; // successful output @@ -207,7 +182,7 @@ async function transcribe ({ const originalContainingDir = `./transcriptions/${uploadGeneratedFilename}`; - const originalDirectoryAndNewFileName = `${originalContainingDir}/${directorySafeFileNameWithoutExtension}`; + fileInfo.originalDirectoryAndNewFileName = `${originalContainingDir}/${directorySafeFileNameWithoutExtension}`; l({originalUpload, originalContainingDir, directorySafeFileNameWithExtension}); await fs.move(originalUpload, `${originalContainingDir}/${directorySafeFileNameWithExtension}`, {overwrite: true}); @@ -217,13 +192,13 @@ async function transcribe ({ const fileTypes = ['srt', 'vtt', 'txt']; // doesn't work // fileTypes.forEach(async fileType => { - // await fs.move(`${originalContainingDir}/${uploadFolderFileName}.${fileType}`, `${originalDirectoryAndNewFileName}.${fileType}`, { overwrite: true }); + // await fs.move(`${originalContainingDir}/${uploadFolderFileName}.${fileType}`, `${fileInfo.originalDirectoryAndNewFileName}.${fileType}`, { overwrite: true }); // }); - const srtPath = `${originalDirectoryAndNewFileName}.srt`; + const srtPath = `${fileInfo.originalDirectoryAndNewFileName}.srt`; - const vttPath = `${originalDirectoryAndNewFileName}.vtt`; + const vttPath = `${fileInfo.originalDirectoryAndNewFileName}.vtt`; - const txtPath = `${originalDirectoryAndNewFileName}.txt`; + const txtPath = `${fileInfo.originalDirectoryAndNewFileName}.txt`; // copy srt with the original filename // SOURCE, ORIGINAL @@ -234,7 +209,7 @@ async function transcribe ({ await fs.move(`${originalContainingDir}/${uploadFolderFileName}.txt`, txtPath, { overwrite: true }) - await convertLanguageText(language, originalDirectoryAndNewFileName); + await convertLanguageText(fileInfo.language, fileInfo.originalDirectoryAndNewFileName); updateQueueItemStatus(websocketNumber, 'completed'); @@ -244,12 +219,17 @@ async function transcribe ({ l({shouldTranslate}); // copy original as copied - await fs.copy(vttPath, `${originalDirectoryAndNewFileName}_${language}.vtt`) + await fs.copy(vttPath, `${fileInfo.originalDirectoryAndNewFileName}_${fileInfo.language}.vtt`) // strip out text and timestamps here to save in processing_data.json - const { strippedText, timestampsArray } = await stripOutTextAndTimestamps(vttPath) + const {strippedText, timestampsArray} = await stripOutTextAndTimestamps(vttPath); + fileInfo.strippedText = strippedText; + fileInfo.characterCount = strippedText.length; + fileInfo.timestampsArray = timestampsArray; + const wordCount = strippedText.split(' ').length; + fileInfo.wordCount = wordCount; + const wordsPerMinute = Math.round(wordCount / (uploadDurationInSeconds / 60)); - let translationStarted, translationFinished = false; /** TRANSLATION FUNCTIONALITY **/ if (libreTranslateHostPath, shouldTranslate) { // tell frontend that we're translating now @@ -258,37 +238,25 @@ async function transcribe ({ message: 'languageUpdate' }); l('hitting LibreTranslate'); - translationStarted = true; + fileInfo.translationStarted = true; // hit libretranslate await createTranslatedFiles({ - directoryAndFileName: originalDirectoryAndNewFileName, - language, + directoryAndFileName: fileInfo.originalDirectoryAndNewFileName, + language: fileInfo.language, websocketConnection, - strippedText, - timestampsArray + strippedText: fileInfo.strippedText, + timestampsArray: fileInfo.timestampsArray, }) - translationFinished = true; + fileInfo.translationFinished = true; } // just post-processing, you can return the response const processingSeconds = Math.round((new Date() - startingDate) / 1000); + fileInfo.processingSeconds = processingSeconds; + fileInfo.processingTime = forHumans(processingSeconds); const processingRatio = (uploadDurationInSeconds/processingSeconds).toFixed(2); - - // TODO: just have a function called "sendFileInfoToClient(fileInfoJSON)" - const outputText = ` - filename: ${originalFileNameWithExtension} - processingSeconds: ${processingSeconds} - processingSecondsHumanReadable: ${forHumans(processingSeconds)} - language: ${language} - model: ${model} - upload: ${uploadFolderFileName} - uploadDurationInSeconds: ${uploadDurationInSeconds} - uploadDurationInSecondsHumanReadable: ${forHumans(uploadDurationInSeconds)} - processingRatio: ${processingRatio} - startedAt: ${startingDate.toUTCString()} - finishedAT: ${new Date().toUTCString()} - `.replace(/^ +/gm, ''); // remove indentation + fileInfo.processingRatio = processingRatio; // tell frontend upload is done sendToWebsocket(websocketConnection, { @@ -296,52 +264,28 @@ async function transcribe ({ urlSrt: srtPath, urlVtt: vttPath, urlTxt: txtPath, - filename: fileSafeNameWithDateTimestamp, - detailsString: outputText + ...fileInfo }); - const translationStartedAndCompleted = translationStarted && translationFinished; + const translationStartedAndCompleted = fileInfo.translationStarted && fileInfo.translationFinished; let translatedLanguages = []; if (translationStartedAndCompleted) { // TODO: this is named wrong, should be languagesToTranslateTo // remove the original language from languagesToTranslateTo - translatedLanguages = languagesToTranscribe.filter(e => e !== language); + translatedLanguages = languagesToTranscribe.filter(e => e !== fileInfo.language); + fileInfo.languagesToTranslateTo = translatedLanguages; } - const wordCount = strippedText.split(' ').length; - const wordsPerMinute = Math.round(wordCount / (uploadDurationInSeconds / 60)); - - // data to save to processing_data.json - const fileDetailsObject = { - filename: originalFileNameWithExtension, - processingSeconds, - processingSecondsHumanReadable: forHumans(processingSeconds), - language, - languageCode: getLanguageCodeForAllLanguages(language), - model, - upload: uploadFolderFileName, - uploadDurationInSeconds, - uploadDurationInSecondsHumanReadable, - processingRatio, - startedAt: startingDate.toUTCString(), - finishedAT: new Date().toUTCString(), - status: 'completed', - translatedLanguages, - fileExtension: path.parse(originalFileNameWithExtension).ext, - directoryFileName: directorySafeFileNameWithoutExtension, - strippedText, - timestampsArray, - wordCount, - wordsPerMinute, - fileSizeInMB, - characterCount: strippedText.length, - user, - downloadLink, - } + fileInfo.wordsPerMinute = wordsPerMinute; + // BUG: undefined on the frontend + fileInfo.finishedAt = new Date().toUTCString(); + l('finishedAt', fileInfo.finishedAt); + fileInfo.status = 'Completed'; + l({fileInfo}); // save processing_data.json - await fs.appendFile(`${originalContainingDir}/processing_data.json`, JSON.stringify(fileDetailsObject), 'utf8'); + await fs.appendFile(`${originalContainingDir}/processing_data.json`, JSON.stringify(fileInfo), 'utf8'); // TODO: if no link passed, because if link was passed no need to rename directory const renamedDirectory = `./transcriptions/${fileSafeNameWithDateTimestamp}`; diff --git a/views/index/components/transcription-results.pug b/views/index/components/transcription-results.pug index 536d82c..bd04bcd 100644 --- a/views/index/components/transcription-results.pug +++ b/views/index/components/transcription-results.pug @@ -4,9 +4,9 @@ .progress p#timeEstimator p#latestData - p#processingData - p#secondProcessingData - p#finishedData + section#processingData.info + section#secondProcessingData.info + section#finishedData.info // kind of duplicated, not sure it's needed a#startNewUpload.startNewUpload.btn(onclick='(function(){ window.open(window.location.href, \'_blank\').focus(); })();') Start Another Transcription diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index 72dc647..5ee023a 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -184,11 +184,20 @@ script. let loopStarted; //- destructure the data object -osb910 let { + filename, + processingTime, + language, + model, + upload, + uploadDuration, + processingRatio, + startedAt, + finishedAt, + processingData, ownershipPerson, processNumber, percentDone, timeRemaining, - processingData, formattedProgress } = data; const myUpload = ownershipPerson === 'you'; @@ -251,7 +260,7 @@ script. const progressUpdate = `[${latestProgress.percentDone}] ${globalTimeRemaining.string} Remaining, Speed ${latestProgress.speed}f/s`; - $('#processingData').html(`${processFeedback}${progressUpdate}`); + $('#processingData').html(`${processFeedback}${processingData}`); }, 1000); } @@ -294,11 +303,16 @@ script. // $('#latestData').css("font-size", "20px"); } - const renderFileDetails = data => { + const renderFileDetails = ({filename, language, model, uploadDuration, isAutoDetected = false}) => { l('file details data'); const niceDate = new Date().toString().replace(/GMT.*/g, ''); - const niceString = `Started At: ${niceDate}`; - $('#finishedData').html(data.fileDetails + niceString); + $('#finishedData').html(` +

Filename: ${filename}

+

Language: ${language}${isAutoDetected ? ' (Auto-Detected)' : ''}

+

Model: ${model}

+

Upload Duration: ${uploadDuration}

+

Started At: ${niceDate}

+ `); } const renderTranslationUpdate = data => { @@ -316,10 +330,24 @@ script. } const renderCompletionFeedback = ({data}) => { + const { + filename, processingTime, language, model, upload, uploadDuration, processingRatio, startedAt, finishedAt, isAutoDetected = false + } = data; + l({finishedAt}); l('completed data'); if (window.decrementInterval) clearInterval(window.decrementInterval); $('#latestData').html(`Congratulations, you're done!`); - $('#finishedData').html(data.detailsString); + $('#finishedData').html(` +

Filename: ${filename}

+

Processing Time: ${processingTime}

+

Language: ${language}${isAutoDetected ? ' (Auto-Detected)' : ''}

+

Model: ${model}

+

Upload Name: ${upload}

+

Upload Duration: ${uploadDuration}

+

Processing Ratio: ${processingRatio}

+

Started At: ${startedAt}

+

Finished At: ${finishedAt}

+ `); $('#header').html('Transcription Completed'); $('#processingData').hide(); // show refresh button @@ -327,7 +355,7 @@ script. $('#startNewUpload').hide(); // redirect to the player page // 2 seconds to let the user see the completion message - setTimeout(() => window.location.href = `/player/${data.filename}`, 2000); + //- setTimeout(() => window.location.href = `/player/${data.filename}`, 2000); } const renderError = data => { diff --git a/views/index/styles/styles-transcription-results.pug b/views/index/styles/styles-transcription-results.pug index 1073035..2d57f4a 100644 --- a/views/index/styles/styles-transcription-results.pug +++ b/views/index/styles/styles-transcription-results.pug @@ -20,13 +20,22 @@ style. text-align: center; } + .info { + display: flex; + flex-direction: column; + gap: 0.5em; + } + + .info p { + margin: 0; + } + #finishedData { text-align: left; + margin-left: -44px; + margin-block: 0.5em; font-size: 1.125rem; color: white; - margin-top: -12px; - margin-left: -44px; - margin-bottom: 7px; } #latestData, #processingData, #secondProcessingData, #refreshButton, #startNewUpload, .downloadLink { @@ -44,7 +53,7 @@ style. margin-top: -10px; } - #latestData, #processingData, #secondProcessingData, #timeEstimator, #finishedData { + #latestData, #processingData, #secondProcessingData, #timeEstimator { white-space: pre; } From 4287e604d9b7f3ac6e4433da490ed234e5049e6c Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Wed, 11 Jan 2023 16:24:52 +0200 Subject: [PATCH 10/22] fix redirection bug --- views/index/js/controllers/network-handling.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index 5ee023a..4e6449f 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -355,7 +355,7 @@ script. $('#startNewUpload').hide(); // redirect to the player page // 2 seconds to let the user see the completion message - //- setTimeout(() => window.location.href = `/player/${data.filename}`, 2000); + setTimeout(() => window.location.href = `/player/${data.filename}`, 2000); } const renderError = data => { From 34ad352738ccd4200264a04a7af911580bf62270 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Thu, 12 Jan 2023 10:26:06 +0200 Subject: [PATCH 11/22] bugfixes --- constants/constants.js | 6 +- lib/transcribing.js | 21 ++++++ routes/admin.js | 2 +- routes/api.js | 12 ++-- routes/player.js | 7 +- routes/transcribe.js | 4 +- transcribe/transcribe-wrapped.js | 66 ++++++------------- .../index/js/controllers/network-handling.pug | 7 +- views/player/player.pug | 6 +- 9 files changed, 65 insertions(+), 66 deletions(-) diff --git a/constants/constants.js b/constants/constants.js index dfc8d96..04b8711 100644 --- a/constants/constants.js +++ b/constants/constants.js @@ -68,7 +68,7 @@ const translationLanguages = [ {'code':'uk','name':'Ukranian'} ]; -const languagesToTranslateTo = [ +const targetLanguages = [ // {"code":"ar","name":"Arabic"}, // haven't got these two to work // {"code":"zh","name":"Chinese"}, // webvtt format is too broken after translate {'code':'en','name':'English'}, @@ -99,7 +99,7 @@ const languagesToTranscribe = [ // } function shouldTranslateFrom (languageName) { - return languagesToTranslateTo.includes(languageName); + return targetLanguages.includes(languageName); } let newLanguagesMap = []; @@ -136,6 +136,6 @@ module.exports = { newLanguagesMap, allLanguages, modelsArray, - languagesToTranslateTo, + targetLanguages, whisperLanguagesHumanReadableArray } diff --git a/lib/transcribing.js b/lib/transcribing.js index 42e64b0..f27c371 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -8,6 +8,7 @@ const {getLanguageCodeForAllLanguages} = require('../constants/constants'); const { stripOutTextAndTimestamps } = require('../translate/helpers'); const { convertSerbianCyrillicToLatin, convertChineseTraditionalToSimplified } = require('./convertText'); const { sendToWebsocket } = require('../helpers/helpers'); +const createTranslatedFiles = require('../translate/create-translated-files'); const isProd = process.env.NODE_ENV === 'production'; const multipleGpusEnabled = process.env.MULTIPLE_GPUS === 'true'; @@ -198,6 +199,25 @@ const updateDetectedLanguage = ({dataAsString, fileInfo, websocketConnection}) = return detectedLang; } +const handleTranslation = async (fileInfo, websocketConnection) => { + sendToWebsocket(websocketConnection, { + languageUpdate: 'Doing translations with LibreTranslate', + message: 'languageUpdate' + }); + l('hitting LibreTranslate'); + fileInfo.translationStarted = true; + // hit libretranslate + await createTranslatedFiles({ + directoryAndFileName: fileInfo.originalDirectoryAndNewFileName, + language: fileInfo.language, + websocketConnection, + strippedText: fileInfo.strippedText, + timestampsArray: fileInfo.timestampsArray, + }); + + fileInfo.translationFinished = true; +} + // example file from multer // { // fieldname: 'file', @@ -246,6 +266,7 @@ module.exports = { updateFileDetails, removeFromArrayByWsNumber, updateDetectedLanguage, + handleTranslation, // file name helpers makeFileNameSafe, diff --git a/routes/admin.js b/routes/admin.js index b7922e8..142dbbd 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -77,7 +77,7 @@ router.get('/learnserbian', async function (req, res, next) { l(files); files = files.filter(function (file) { - return file.processingData.translatedLanguages.length; + return file.processingData.targetLanguages.length; }); // TODO: finishedAT is misspelled diff --git a/routes/api.js b/routes/api.js index 52dffdf..cd6679e 100644 --- a/routes/api.js +++ b/routes/api.js @@ -10,7 +10,7 @@ const constants = require('../constants/constants'); const filenamify = require('filenamify'); const createTranslatedFiles = require('../translate/translate-files-api'); const { downloadFileApi, getFilename} = require('../downloading/yt-dlp-download'); -const { languagesToTranslateTo, newLanguagesMap, translationLanguages } = constants; +const { targetLanguages, newLanguagesMap, translationLanguages } = constants; const { modelsArray, whisperLanguagesHumanReadableArray } = constants; const { writeToProcessingDataFile, createFileNames, makeFileNameSafe } = require('../lib/transcribing'); @@ -194,7 +194,7 @@ router.get('/api/:sdHash', async function (req, res, next) { const { language, languageCode, - translatedLanguages, + targetLanguages, status: transcriptionStatus, progress } = processingData; @@ -221,11 +221,11 @@ router.get('/api/:sdHash', async function (req, res, next) { webVtt: originalVtt }) - // for (const translatedLanguage of translatedLanguages) { - // const originalVtt = await fs.readFile(`./transcriptions/${sdHash}/${sdHash}_${translatedLanguage}.vtt`, 'utf8'); + // for (const languages of targetLanguages) { + // const originalVtt = await fs.readFile(`./transcriptions/${sdHash}/${sdHash}_${targetLanguage}.vtt`, 'utf8'); // subtitles.push({ - // language: translatedLanguage, - // languageCode: getCodeFromLanguageName(translatedLanguage), + // language: targetLanguage, + // languageCode: getCodeFromLanguageName(targetLanguage), // webVtt: originalVtt // }) // } diff --git a/routes/player.js b/routes/player.js index c877bfa..9279e99 100644 --- a/routes/player.js +++ b/routes/player.js @@ -18,6 +18,7 @@ router.get('/player/:filename' , async function (req, res, next) { const processDirectory = process.cwd(); const containingFolder = `${processDirectory}/transcriptions/${fileNameWithoutExtension}` + l({containingFolder}); const processingDataPath = `${containingFolder}/processing_data.json`; @@ -29,11 +30,11 @@ router.get('/player/:filename' , async function (req, res, next) { // l('filePathWithoutExtension') // l(filePathWithoutExtension); - const translatedLanguages = processingData.translatedLanguages; + const targetLanguages = processingData.targetLanguages; // TODO: check that it doesn't include the original language? or it never will? const languagesToLoop = newLanguagesMap.filter(function (language) { - return translatedLanguages.includes(language.name) + return targetLanguages.includes(language.name) }); delete processingData.strippedText; @@ -158,7 +159,7 @@ router.post('/player/:filename/add' , async function (req, res, next) { await fs.writeFile(newVttPath, reformatted, 'utf-8'); - processingData.translatedLanguages.push(language); + processingData.targetLanguages.push(language); processingData.keepMedia = true; diff --git a/routes/transcribe.js b/routes/transcribe.js index 46a0c47..17af1c6 100644 --- a/routes/transcribe.js +++ b/routes/transcribe.js @@ -12,7 +12,7 @@ const fs = require('fs-extra'); const { downloadFile, getFilename } = require('../downloading/yt-dlp-download'); const transcribeWrapped = require('../transcribe/transcribe-wrapped'); -const { languagesToTranslateTo } = require('../constants/constants'); +const { targetLanguages } = require('../constants/constants'); const {forHumansNoSeconds, getamountOfRunningJobs} = require('../helpers/helpers'); const {makeFileNameSafe} = require('../lib/files'); const { addItemToQueue, getNumberOfPendingOrProcessingJobs } = require('../queue/queue'); @@ -252,7 +252,7 @@ router.post('/file', upload.single('file'), async function (req, res, next) { // websocket/queue websocketConnection, websocketNumber, - languagesToTranslateTo, + targetLanguages, } // l('transcriptionJobItem'); diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index f6d5b7b..63fd0cd 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -9,7 +9,7 @@ const {shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLang const {forHumans, getamountOfRunningJobs, sendToWebsocket} = require('../helpers/helpers'); const {formatStdErr} = require('../helpers/formatStdErr'); const createTranslatedFiles = require('../translate/create-translated-files'); -const {buildWhisperArguments, convertLanguageText, updateFileDetails, removeFromArrayByWsNumber, updateDetectedLanguage} = require('../lib/transcribing'); +const {buildWhisperArguments, convertLanguageText, updateFileDetails, removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation} = require('../lib/transcribing'); const {stripOutTextAndTimestamps} = require('../translate/helpers'); const {updateQueueItemStatus} = require('../queue/queue'); @@ -80,8 +80,9 @@ async function transcribe ({ const uploadDurationInSecondsHumanReadable = forHumans(uploadDurationInSeconds); const fileInfo = { - filename: originalFileNameWithExtension, - fileExtension: path.parse(originalFileNameWithExtension).ext, + filename: directorySafeFileNameWithExtension, + fileExtension: path.parse(directorySafeFileNameWithExtension).ext, + fileSafeNameWithDateTimestamp, fileSizeInMB, directoryFileName: directorySafeFileNameWithoutExtension, language: language === 'auto-detect' ? 'Auto-Detect' : language, @@ -145,14 +146,11 @@ async function transcribe ({ fileInfo.ownershipPerson = ownershipPerson; const formattedProgress = formatStdErr(data.toString()); fileInfo.formattedProgress = formattedProgress; - const {percentDoneAsNumber, percentDone, speed, timeRemaining} = formattedProgress; fileInfo.percentDone = percentDoneAsNumber; fileInfo.timeRemaining = timeRemaining; fileInfo.speed = speed; - - const processingString = timeRemaining ? `[${percentDone}] ${timeRemaining.string} Remaining, Speed ${speed}f/s` : ''; - fileInfo.processingData = processingString; + fileInfo.processingData = timeRemaining ? `[${percentDone}] ${timeRemaining.string} Remaining, Speed ${speed}f/s` : ''; // pass latest data to all the open sockets if (websocketConnection.readyState === WebSocket.OPEN) { @@ -183,8 +181,7 @@ async function transcribe ({ const originalContainingDir = `./transcriptions/${uploadGeneratedFilename}`; fileInfo.originalDirectoryAndNewFileName = `${originalContainingDir}/${directorySafeFileNameWithoutExtension}`; - - l({originalUpload, originalContainingDir, directorySafeFileNameWithExtension}); + // await fs.move(originalUpload, `${fileSafeNameWithDateTimestamp}`, {overwrite: true}); await fs.move(originalUpload, `${originalContainingDir}/${directorySafeFileNameWithExtension}`, {overwrite: true}); // turn this to a loop @@ -229,25 +226,11 @@ async function transcribe ({ const wordCount = strippedText.split(' ').length; fileInfo.wordCount = wordCount; const wordsPerMinute = Math.round(wordCount / (uploadDurationInSeconds / 60)); + fileInfo.wordsPerMinute = wordsPerMinute; /** TRANSLATION FUNCTIONALITY **/ if (libreTranslateHostPath, shouldTranslate) { - // tell frontend that we're translating now - sendToWebsocket(websocketConnection, { - languageUpdate: 'Doing translations with LibreTranslate', - message: 'languageUpdate' - }); - l('hitting LibreTranslate'); - fileInfo.translationStarted = true; - // hit libretranslate - await createTranslatedFiles({ - directoryAndFileName: fileInfo.originalDirectoryAndNewFileName, - language: fileInfo.language, - websocketConnection, - strippedText: fileInfo.strippedText, - timestampsArray: fileInfo.timestampsArray, - }) - fileInfo.translationFinished = true; + await handleTranslation(fileInfo, websocketConnection); } // just post-processing, you can return the response @@ -257,33 +240,17 @@ async function transcribe ({ const processingRatio = (uploadDurationInSeconds/processingSeconds).toFixed(2); fileInfo.processingRatio = processingRatio; - - // tell frontend upload is done - sendToWebsocket(websocketConnection, { - status: 'Completed', - urlSrt: srtPath, - urlVtt: vttPath, - urlTxt: txtPath, - ...fileInfo - }); + fileInfo.finishedAt = new Date().toUTCString(); + fileInfo.status = 'Completed'; const translationStartedAndCompleted = fileInfo.translationStarted && fileInfo.translationFinished; - let translatedLanguages = []; if (translationStartedAndCompleted) { - // TODO: this is named wrong, should be languagesToTranslateTo - // remove the original language from languagesToTranslateTo - translatedLanguages = languagesToTranscribe.filter(e => e !== fileInfo.language); - fileInfo.languagesToTranslateTo = translatedLanguages; + // remove the original language from targetLanguages + fileInfo.targetLanguages = languagesToTranscribe.filter(lang => lang !== fileInfo.language); } - fileInfo.wordsPerMinute = wordsPerMinute; - // BUG: undefined on the frontend - fileInfo.finishedAt = new Date().toUTCString(); - l('finishedAt', fileInfo.finishedAt); - fileInfo.status = 'Completed'; l({fileInfo}); - // save processing_data.json await fs.appendFile(`${originalContainingDir}/processing_data.json`, JSON.stringify(fileInfo), 'utf8'); @@ -294,6 +261,15 @@ async function transcribe ({ // remove from global.transcriptions global.transcriptions = removeFromArrayByWsNumber(global.transcriptions, websocketNumber); + // tell frontend upload is done + sendToWebsocket(websocketConnection, { + status: 'Completed', + urlSrt: srtPath, + urlVtt: vttPath, + urlTxt: txtPath, + ...fileInfo + }); + } else { l('FAILED!'); reject(); diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index 4e6449f..d87d76d 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -331,9 +331,10 @@ script. const renderCompletionFeedback = ({data}) => { const { - filename, processingTime, language, model, upload, uploadDuration, processingRatio, startedAt, finishedAt, isAutoDetected = false + filename, processingTime, language, model, upload, uploadDuration, processingRatio, startedAt, finishedAt, isAutoDetected = false, + fileSafeNameWithDateTimestamp, } = data; - l({finishedAt}); + l({data}); l('completed data'); if (window.decrementInterval) clearInterval(window.decrementInterval); $('#latestData').html(`Congratulations, you're done!`); @@ -355,7 +356,7 @@ script. $('#startNewUpload').hide(); // redirect to the player page // 2 seconds to let the user see the completion message - setTimeout(() => window.location.href = `/player/${data.filename}`, 2000); + setTimeout(() => window.location.href = `/player/${fileSafeNameWithDateTimestamp}`, 2000); } const renderError = data => { diff --git a/views/player/player.pug b/views/player/player.pug index d3df743..63e2bad 100644 --- a/views/player/player.pug +++ b/views/player/player.pug @@ -28,7 +28,7 @@ block content a.btn.startAnotherTranscription(href='/') Start Another Transcription // ORIGINAL LANGUAGE FILES - if processingData.translatedLanguages.length > 1 + if processingData.targetLanguages.length > 1 span Original Language: .srtLinks.links span SRT (#{processingData.language}) @@ -43,10 +43,10 @@ block content a(download href=`${filePathWithoutExtension}.txt`) Download // TRANSLATED FILES // - if processingData.translatedLanguages.length > 0 + if processingData.targetLanguages.length > 0 p#translationsHeader Translations: // translated VTT files - each language in processingData.translatedLanguages + each language in processingData.targetLanguages .links span VTT (#{language}) a(href=`${filePathWithoutExtension}_${language}.vtt`) View From dbcd543f62e2a2013c72986c381efbee6de32795 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Thu, 12 Jan 2023 16:40:51 +0200 Subject: [PATCH 12/22] refactor & organize the moving functionality --- constants/constants.js | 2 +- lib/transcribing.js | 36 +++++++++------ transcribe/transcribe-wrapped.js | 75 +++++++------------------------- 3 files changed, 39 insertions(+), 74 deletions(-) diff --git a/constants/constants.js b/constants/constants.js index 04b8711..d493d40 100644 --- a/constants/constants.js +++ b/constants/constants.js @@ -13,7 +13,7 @@ const languagesArray = whisperLanguagesHumanReadableArray.map(lang => ({value: l languagesArray.unshift({value: 'auto-detect', name: 'Auto-Detect'}); function getLanguageCodeForAllLanguages (languageName) { - l(Object.values(languageNameMap)); + // l(Object.values(languageNameMap)); let foundLanguageCode; Object.keys(languageNameMap).forEach(languageCode =>{ if (languageNameMap[languageCode].name === languageName) { diff --git a/lib/transcribing.js b/lib/transcribing.js index f27c371..4c9f5ea 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -173,23 +173,13 @@ const convertLanguageText = async (language, path) => { } } -const updateFileDetails = async ({websocketConnection, filename, language, model, duration}) => { - const fileDetails = ` - Filename: ${filename} - Language: ${language} - Model: ${model} - Upload Duration: ${duration} - `.replace(/^ +/gm, ''); // remove indentation - - // update file details - sendToWebsocket(websocketConnection, {message: 'fileDetails', fileDetails}); -} - const removeFromArrayByWsNumber = (array, wsNumber) => { return array.filter(item => item.websocketNumber !== wsNumber); } -const updateDetectedLanguage = ({dataAsString, fileInfo, websocketConnection}) => { +const updateDetectedLanguage = ({data, fileInfo, websocketConnection}) => { + const dataAsString = data.toString(); + if (!dataAsString.includes('Detected language:')) return; const detectedLang = dataAsString.match(/Detected language: ([a-z]+)\b/i)[1]; l(`DETECTED LANGUAGE FOUND: ${detectedLang}`); fileInfo.language = detectedLang; @@ -218,6 +208,24 @@ const handleTranslation = async (fileInfo, websocketConnection) => { fileInfo.translationFinished = true; } +// need a better name? +const moveSubtitleFiles = async fileInfo => { + + await fs.move(fileInfo.originalUpload, `${fileInfo.originalContainingDir}/${fileInfo.fileSafeNameWithExt}`, {overwrite: true}); + + fileInfo.srtPath = `${fileInfo.originalDirectoryAndNewFileName}.srt`; + fileInfo.vttPath = `${fileInfo.originalDirectoryAndNewFileName}.vtt`; + fileInfo.txtPath = `${fileInfo.originalDirectoryAndNewFileName}.txt`; + + /** COPY TO BETTER NAME, SRT, VTT, TXT **/ + const fileTypes = ['srt', 'vtt', 'txt']; + + // copy srt with the original filename + for (const fileType of fileTypes) { + await fs.move(`${fileInfo.originalContainingDir}/${fileInfo.upload}.${fileType}`, `${fileInfo.originalDirectoryAndNewFileName}.${fileType}`, {overwrite: true}); + } +} + // example file from multer // { // fieldname: 'file', @@ -254,6 +262,7 @@ function createFileNames (originalFileName) { module.exports = { // handle processing data file writeToProcessingDataFile, + moveSubtitleFiles, detectLanguageFromString, @@ -263,7 +272,6 @@ module.exports = { handleProcessClose, buildWhisperArguments, convertLanguageText, - updateFileDetails, removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation, diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index 63fd0cd..67f4d99 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -5,11 +5,10 @@ const ffprobe = require('ffprobe'); const WebSocket = require('ws'); const path = require('path'); -const {shouldTranslateFrom, languagesToTranscribe, translationLanguages, getLanguageCodeForAllLanguages} = require('../constants/constants'); +const {languagesToTranscribe, getLanguageCodeForAllLanguages} = require('../constants/constants'); const {forHumans, getamountOfRunningJobs, sendToWebsocket} = require('../helpers/helpers'); const {formatStdErr} = require('../helpers/formatStdErr'); -const createTranslatedFiles = require('../translate/create-translated-files'); -const {buildWhisperArguments, convertLanguageText, updateFileDetails, removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation} = require('../lib/transcribing'); +const {buildWhisperArguments, convertLanguageText, removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation, moveSubtitleFiles} = require('../lib/transcribing'); const {stripOutTextAndTimestamps} = require('../translate/helpers'); const {updateQueueItemStatus} = require('../queue/queue'); @@ -19,9 +18,6 @@ const libreTranslateHostPath = process.env.LIBRETRANSLATE; const l = console.log; -// l(`libreTranslateHostPath: ${libreTranslateHostPath}`) - - const whisperPath = which.sync('whisper'); global.transcriptions = []; @@ -60,7 +56,6 @@ async function transcribe ({ } try { - // inform frontend their processing has started sendToWebsocket(websocketConnection, { message: 'starting', @@ -82,6 +77,7 @@ async function transcribe ({ const fileInfo = { filename: directorySafeFileNameWithExtension, fileExtension: path.parse(directorySafeFileNameWithExtension).ext, + fileSafeNameWithExt: directorySafeFileNameWithExtension, fileSafeNameWithDateTimestamp, fileSizeInMB, directoryFileName: directorySafeFileNameWithoutExtension, @@ -89,8 +85,12 @@ async function transcribe ({ languageCode: getLanguageCodeForAllLanguages(language), model, upload: uploadFolderFileName, + uploadGeneratedFilename, + originalContainingDir: `./transcriptions/${uploadGeneratedFilename}`, + originalDirectoryAndNewFileName: `./transcriptions/${uploadGeneratedFilename}/${directorySafeFileNameWithoutExtension}`, uploadDurationInSeconds, uploadDuration: uploadDurationInSecondsHumanReadable, + originalUpload, user, downloadLink, processNumber, @@ -109,26 +109,18 @@ async function transcribe ({ const whisperProcess = spawn(whisperPath, whisperArguments); // add process globally to kill it when user leaves - const process = { + global.transcriptions.push({ websocketNumber, spawnedProcess: whisperProcess, processNumber, type: 'transcription', - } - - global.transcriptions.push(process); + }); // console output from stdout whisperProcess.stdout.on('data', data => { sendToWebsocket(websocketConnection, `stdout: ${data}`); l(`STDOUT: ${data}`); - - // TODO: pull this out into own function - // check if language is autodetected) - const dataAsString = data.toString(); - if (dataAsString.includes('Detected language:')) { - foundLanguage = updateDetectedLanguage({dataAsString, fileInfo, websocketConnection}); - } + updateDetectedLanguage({data, fileInfo, websocketConnection}); }); // log output from bash (it all comes through stderr for some reason?) @@ -176,35 +168,8 @@ async function transcribe ({ // successful output if (processFinishedSuccessfully) { - // TODO: pull out all this moving stuff into its own function - - const originalContainingDir = `./transcriptions/${uploadGeneratedFilename}`; - - fileInfo.originalDirectoryAndNewFileName = `${originalContainingDir}/${directorySafeFileNameWithoutExtension}`; - // await fs.move(originalUpload, `${fileSafeNameWithDateTimestamp}`, {overwrite: true}); - await fs.move(originalUpload, `${originalContainingDir}/${directorySafeFileNameWithExtension}`, {overwrite: true}); - // turn this to a loop - /** COPY TO BETTER NAME, SRT, VTT, TXT **/ - const fileTypes = ['srt', 'vtt', 'txt']; - // doesn't work - // fileTypes.forEach(async fileType => { - // await fs.move(`${originalContainingDir}/${uploadFolderFileName}.${fileType}`, `${fileInfo.originalDirectoryAndNewFileName}.${fileType}`, { overwrite: true }); - // }); - const srtPath = `${fileInfo.originalDirectoryAndNewFileName}.srt`; - - const vttPath = `${fileInfo.originalDirectoryAndNewFileName}.vtt`; - - const txtPath = `${fileInfo.originalDirectoryAndNewFileName}.txt`; - - // copy srt with the original filename - // SOURCE, ORIGINAL - // TODO: could probably move here instead of copy - await fs.move(`${originalContainingDir}/${uploadFolderFileName}.srt`, srtPath, { overwrite: true }) - - await fs.move(`${originalContainingDir}/${uploadFolderFileName}.vtt`, vttPath, { overwrite: true }) - - await fs.move(`${originalContainingDir}/${uploadFolderFileName}.txt`, txtPath, { overwrite: true }) + await moveSubtitleFiles(fileInfo); await convertLanguageText(fileInfo.language, fileInfo.originalDirectoryAndNewFileName); @@ -213,13 +178,11 @@ async function transcribe ({ // return await so queue moves on, don't need to wait for translations resolve(code); - l({shouldTranslate}); - // copy original as copied - await fs.copy(vttPath, `${fileInfo.originalDirectoryAndNewFileName}_${fileInfo.language}.vtt`) + await fs.copy(fileInfo.vttPath, `${fileInfo.originalDirectoryAndNewFileName}_${fileInfo.language}.vtt`) // strip out text and timestamps here to save in processing_data.json - const {strippedText, timestampsArray} = await stripOutTextAndTimestamps(vttPath); + const {strippedText, timestampsArray} = await stripOutTextAndTimestamps(fileInfo.vttPath); fileInfo.strippedText = strippedText; fileInfo.characterCount = strippedText.length; fileInfo.timestampsArray = timestampsArray; @@ -252,11 +215,11 @@ async function transcribe ({ l({fileInfo}); // save processing_data.json - await fs.appendFile(`${originalContainingDir}/processing_data.json`, JSON.stringify(fileInfo), 'utf8'); + await fs.appendFile(`${fileInfo.originalContainingDir}/processing_data.json`, JSON.stringify(fileInfo), 'utf8'); // TODO: if no link passed, because if link was passed no need to rename directory const renamedDirectory = `./transcriptions/${fileSafeNameWithDateTimestamp}`; - await fs.rename(originalContainingDir, renamedDirectory) + await fs.rename(fileInfo.originalContainingDir, renamedDirectory) // remove from global.transcriptions global.transcriptions = removeFromArrayByWsNumber(global.transcriptions, websocketNumber); @@ -264,9 +227,6 @@ async function transcribe ({ // tell frontend upload is done sendToWebsocket(websocketConnection, { status: 'Completed', - urlSrt: srtPath, - urlVtt: vttPath, - urlTxt: txtPath, ...fileInfo }); @@ -290,9 +250,8 @@ async function transcribe ({ }) websocketConnection.terminate() } - l('err here'); l(err.stack); - l(err); + l({err}); throw err; } }); @@ -311,9 +270,7 @@ async function transcribe ({ throw err; } - }); - } module.exports = transcribe; From dc57246b2e1de2ea7408add702e90d0ffb7abed7 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Thu, 12 Jan 2023 19:30:23 +0200 Subject: [PATCH 13/22] refactor basic parts of the /file post router --- downloading/yt-dlp-download.js | 5 +-- helpers/helpers.js | 6 ++-- lib/transcribing.js | 21 ++---------- routes/api.js | 7 ++-- routes/transcribe.js | 59 +++++++++------------------------- 5 files changed, 26 insertions(+), 72 deletions(-) diff --git a/downloading/yt-dlp-download.js b/downloading/yt-dlp-download.js index 47731d0..7493892 100644 --- a/downloading/yt-dlp-download.js +++ b/downloading/yt-dlp-download.js @@ -3,6 +3,7 @@ const spawn = require('child_process').spawn; const fs = require('fs-extra'); const projectConstants = require('../constants/constants'); const {formatStdErr} = require('../helpers/formatStdErr'); +const { generateRandomNumber } = require('../helpers/helpers'); // yt-dlp --no-mtime -f '\''bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best'\'' @@ -247,10 +248,6 @@ async function getFilename (videoUrl) { const testUrl = 'https://www.youtube.com/watch?v=wnhvanMdx4s'; -function generateRandomNumber () { - return Math.floor(Math.random() * 10000000000).toString(); -} - const randomNumber = generateRandomNumber(); async function main () { diff --git a/helpers/helpers.js b/helpers/helpers.js index 13c74ca..582d252 100644 --- a/helpers/helpers.js +++ b/helpers/helpers.js @@ -52,8 +52,6 @@ function forHumansHoursAndMinutes ( seconds ) { return returntext.trim(); } - - const decrementBySecond = timeRemainingValues => { let {secondsRemaining, minutesRemaining, hoursRemaining} = timeRemainingValues; @@ -95,6 +93,9 @@ const sendToWebsocket = (websocketConnection, data) => { websocketConnection.send(JSON.stringify(data), function () {}); } +// TODO: not the world's greatest implemention +const generateRandomNumber = () => Math.floor(Math.random() * 10_000_000_000).toString(); + module.exports = { forHumans, forHumansNoSeconds, @@ -102,4 +103,5 @@ module.exports = { forHumansHoursAndMinutes, getamountOfRunningJobs, sendToWebsocket, + generateRandomNumber, } diff --git a/lib/transcribing.js b/lib/transcribing.js index 4c9f5ea..b37b372 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -13,17 +13,14 @@ const createTranslatedFiles = require('../translate/create-translated-files'); const isProd = process.env.NODE_ENV === 'production'; const multipleGpusEnabled = process.env.MULTIPLE_GPUS === 'true'; - async function writeToProcessingDataFile (processingDataPath, dataObject) { // save data to the file const processingDataExists = await fs.exists(processingDataPath) - l('processingDataExists') - l(processingDataExists); + l({processingDataExists}); if (processingDataExists) { const fileData = await fs.readFile(processingDataPath, 'utf8') - l('fileData'); - l(fileData); + l({fileData}); const existingProcessingData = JSON.parse(fileData); @@ -35,15 +32,6 @@ async function writeToProcessingDataFile (processingDataPath, dataObject) { } } -function detectLanguageFromString (dataAsString) { - if (!dataAsString) return false - if (dataAsString.includes('Detected language:')) { - // parse out the language from the console output - return dataAsString.split(':')[1].substring(1).trimEnd(); - } - return false; -} - function handleStdOut (data) { l(`STDOUT: ${data}`) @@ -61,8 +49,7 @@ function handleStdErr ({ // get value from the whisper output string const formattedProgress = formatStdErr(data.toString()); - l('formattedProgress'); - l(formattedProgress); + l({formattedProgress}); const { percentDoneAsNumber, percentDone, speed, timeRemaining } = formattedProgress; @@ -264,8 +251,6 @@ module.exports = { writeToProcessingDataFile, moveSubtitleFiles, - detectLanguageFromString, - // handle output from the whisper process handleStdOut, handleStdErr, diff --git a/routes/api.js b/routes/api.js index cd6679e..c337ae2 100644 --- a/routes/api.js +++ b/routes/api.js @@ -13,14 +13,10 @@ const { downloadFileApi, getFilename} = require('../downloading/yt-dlp-download' const { targetLanguages, newLanguagesMap, translationLanguages } = constants; const { modelsArray, whisperLanguagesHumanReadableArray } = constants; const { writeToProcessingDataFile, createFileNames, makeFileNameSafe } = require('../lib/transcribing'); +const { generateRandomNumber } = require('../helpers/helpers'); const l = console.log; -// generate random 10 digit number -function generateRandomNumber () { - return Math.floor(Math.random() * 10000000000).toString(); -} - const storage = multer.diskStorage({ // notice you are calling the multer.diskStorage() method here, not multer() destination: function (req, file, cb) { cb(null, './uploads/') @@ -31,6 +27,7 @@ let upload = multer({ storage }); router.post('/api', upload.single('file'), async function (req, res, next) { try { + l('post request to /api') // fix body data const postBodyData = Object.assign({},req.body) diff --git a/routes/transcribe.js b/routes/transcribe.js index 17af1c6..c3a3925 100644 --- a/routes/transcribe.js +++ b/routes/transcribe.js @@ -13,7 +13,7 @@ const fs = require('fs-extra'); const { downloadFile, getFilename } = require('../downloading/yt-dlp-download'); const transcribeWrapped = require('../transcribe/transcribe-wrapped'); const { targetLanguages } = require('../constants/constants'); -const {forHumansNoSeconds, getamountOfRunningJobs} = require('../helpers/helpers'); +const {forHumansNoSeconds, getamountOfRunningJobs, sendToWebsocket, generateRandomNumber} = require('../helpers/helpers'); const {makeFileNameSafe} = require('../lib/files'); const { addItemToQueue, getNumberOfPendingOrProcessingJobs } = require('../queue/queue'); const {addToJobProcessOrQueue} = require('../queue/newQueue'); @@ -46,46 +46,27 @@ router.post('/file', upload.single('file'), async function (req, res, next) { const pathname = urlObject.pathname; const isYtdlp = pathname === '/ytdlp'; - l('isYtdlp'); - l(isYtdlp); + l({isYtdlp}); let language = req.body.language; - let model = req.body.model; - const websocketNumber = req.body.websocketNumber; const shouldTranslate = req.body.shouldTranslate === 'true'; - const downloadLink = req.body.downloadLink; - const { user, skipToFront, uploadTimeStarted } = req.body + const {model, websocketNumber, downloadLink, user, skipToFront, uploadTimeStarted} = req.body; const passedFile = req.file; let downloadedFile = false; + let filename; const uploadTimeFinished = new Date(); - // this shouldn't happen but there's some sort of frontend bug - if (!language || language === 'undefined' || language === 'Auto-Detect') { - language = 'auto-detect'; - } - - // make the model medium by default - if (!model) { - model = 'medium'; - } - - if (model === 'tiny.en' || model === 'base.en' || model === 'small.en' || model === 'medium.en') { + if (/\.en$/.test(model)) { language = 'English' } - let filename; - - l(downloadLink); - - function matchByWebsocketNumber (item) { - return item.websocketNumber === websocketNumber; - } + l({downloadLink}); // websocket number is pushed when it connects on page load // l(global.webSocketData); - const websocket = global.webSocketData.find(matchByWebsocketNumber) + const websocket = global.webSocketData.find(item => item.websocketNumber === websocketNumber); if (websocket) { websocketConnection = websocket.websocket; } else { @@ -93,32 +74,25 @@ router.post('/file', upload.single('file'), async function (req, res, next) { } let originalFileNameWithExtension, uploadedFilePath, uploadGeneratedFilename; + if (passedFile) { - originalFileNameWithExtension = req.file.originalname; - uploadedFilePath = req.file.path; - uploadGeneratedFilename = req.file.filename; - l('uploadedFilePath'); - l(uploadedFilePath); + originalFileNameWithExtension = passedFile.originalname; + uploadedFilePath = passedFile.path; + uploadGeneratedFilename = passedFile.filename; + l({uploadedFilePath}); } else if (downloadLink) { - - websocketConnection.send(JSON.stringify({ + sendToWebsocket(websocketConnection, { message: 'downloadInfo', fileName: downloadLink, percentDownloaded: 0, - }), function () {}); - - // TODO: not the world's greatest implemention - function generateRandomNumber () { - return Math.floor(Math.random() * 10000000000).toString(); - } + }); const randomNumber = generateRandomNumber(); filename = await getFilename(downloadLink); // remove linebreaks, this was causing bugs filename = filename.replace(/\r?\n|\r/g, ''); - l('filename'); - l(filename); + l({filename}); uploadGeneratedFilename = filename; originalFileNameWithExtension = filename; const baseName = path.parse(filename).name; @@ -145,8 +119,7 @@ router.post('/file', upload.single('file'), async function (req, res, next) { // ERROR } - l('uploadedFilePath'); - l(uploadedFilePath); + l({uploadedFilePath}); // get upload duration const ffprobeResponse = await ffprobe(uploadedFilePath, { path: ffprobePath }); From cfc6cad4f82dc561883b3c3d5a9a3f331374e01f Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Fri, 13 Jan 2023 10:50:14 +0200 Subject: [PATCH 14/22] node-mpv as an alternative method to get file duration --- lib/transcribing.js | 16 ++++++++++++++++ package-lock.json | 11 +++++++++++ package.json | 1 + routes/transcribe.js | 7 ++++--- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/transcribing.js b/lib/transcribing.js index b37b372..b2c09c8 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -1,6 +1,8 @@ const fs = require('fs-extra'); const filenamify = require('filenamify'); const path = require('path'); +const which = require('which'); +const mpvAPI = require('node-mpv'); const {autoDetectLanguage} = require('../transcribe/transcribing'); const {formatStdErr} = require('../helpers/formatStdErr'); @@ -10,6 +12,8 @@ const { convertSerbianCyrillicToLatin, convertChineseTraditionalToSimplified } = const { sendToWebsocket } = require('../helpers/helpers'); const createTranslatedFiles = require('../translate/create-translated-files'); +const mpvPath = which.sync('mpv'); + const isProd = process.env.NODE_ENV === 'production'; const multipleGpusEnabled = process.env.MULTIPLE_GPUS === 'true'; @@ -117,6 +121,17 @@ function handleProcessClose ({ processingDataPath, originalUpload, randomNumber } } +// Alternative method to get duration due to ffprobe limitation +const getDurationByMpv = async filePath => { + const mpv = new mpvAPI({audio_only: true}); + await mpv.start(); + await mpv.load(filePath); + await mpv.volume(0); + const duration = await mpv.getDuration(); + mpv.stop(); + return duration; +}; + const buildWhisperArguments = ({filePath, language, model, randomNumber}) => { // queue up arguments, path is the first one const arguments = [filePath]; @@ -250,6 +265,7 @@ module.exports = { // handle processing data file writeToProcessingDataFile, moveSubtitleFiles, + getDurationByMpv, // handle output from the whisper process handleStdOut, diff --git a/package-lock.json b/package-lock.json index 649a708..614648b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", "node-fetch": "^2.6.7", + "node-mpv": "^2.0.0-beta.2", "promise-queue": "^2.2.5", "pug": "^3.0.2", "serve-favicon": "^2.5.0", @@ -1993,6 +1994,11 @@ } } }, + "node_modules/node-mpv": { + "version": "2.0.0-beta.2", + "resolved": "https://registry.npmjs.org/node-mpv/-/node-mpv-2.0.0-beta.2.tgz", + "integrity": "sha512-jf1InAB6tSXYlLs53DSw7ZEGCAhuWibILMF8GU6FmX6jXvkScLfGa9B7nmrIidG8euDpi3hdnUht0PqrHlAbXA==" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4419,6 +4425,11 @@ "whatwg-url": "^5.0.0" } }, + "node-mpv": { + "version": "2.0.0-beta.2", + "resolved": "https://registry.npmjs.org/node-mpv/-/node-mpv-2.0.0-beta.2.tgz", + "integrity": "sha512-jf1InAB6tSXYlLs53DSw7ZEGCAhuWibILMF8GU6FmX6jXvkScLfGa9B7nmrIidG8euDpi3hdnUht0PqrHlAbXA==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", diff --git a/package.json b/package.json index 97da7c3..1c2f847 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", "node-fetch": "^2.6.7", + "node-mpv": "^2.0.0-beta.2", "promise-queue": "^2.2.5", "pug": "^3.0.2", "serve-favicon": "^2.5.0", diff --git a/routes/transcribe.js b/routes/transcribe.js index c3a3925..54c0881 100644 --- a/routes/transcribe.js +++ b/routes/transcribe.js @@ -7,7 +7,7 @@ const multer = require('multer'); const express = require('express'); const router = express.Router(); const which = require('which'); -const ffprobePath = which.sync('ffprobe') +const ffprobePath = which.sync('ffprobe'); const fs = require('fs-extra'); const { downloadFile, getFilename } = require('../downloading/yt-dlp-download'); @@ -17,6 +17,7 @@ const {forHumansNoSeconds, getamountOfRunningJobs, sendToWebsocket, generateRand const {makeFileNameSafe} = require('../lib/files'); const { addItemToQueue, getNumberOfPendingOrProcessingJobs } = require('../queue/queue'); const {addToJobProcessOrQueue} = require('../queue/newQueue'); +const {getDurationByMpv} = require('../lib/transcribing'); const nodeEnv = process.env.NODE_ENV || 'development'; @@ -125,8 +126,8 @@ router.post('/file', upload.single('file'), async function (req, res, next) { const ffprobeResponse = await ffprobe(uploadedFilePath, { path: ffprobePath }); const audioStream = ffprobeResponse.streams.filter(stream => stream.codec_type === 'audio')[0]; - const uploadDurationInSeconds = Math.round(audioStream.duration); - + const uploadDurationInSeconds = Math.round(audioStream.duration || await getDurationByMpv(uploadedFilePath)); + const stats = await fs.promises.stat(uploadedFilePath); const fileSizeInBytes = stats.size; const fileSizeInMB = Number(fileSizeInBytes / 1048576).toFixed(1); From 09ab9aa1bb8f269683c908c43a830d4e512ecd8e Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Fri, 13 Jan 2023 13:35:44 +0200 Subject: [PATCH 15/22] organize off-limit errors --- lib/transcribing.js | 15 ++++++++++++- routes/transcribe.js | 38 ++++++++++---------------------- transcribe/transcribe-wrapped.js | 5 ++++- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/lib/transcribing.js b/lib/transcribing.js index b2c09c8..54fc272 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -9,7 +9,7 @@ const {formatStdErr} = require('../helpers/formatStdErr'); const {getLanguageCodeForAllLanguages} = require('../constants/constants'); const { stripOutTextAndTimestamps } = require('../translate/helpers'); const { convertSerbianCyrillicToLatin, convertChineseTraditionalToSimplified } = require('./convertText'); -const { sendToWebsocket } = require('../helpers/helpers'); +const {sendToWebsocket, forHumansNoSeconds} = require('../helpers/helpers'); const createTranslatedFiles = require('../translate/create-translated-files'); const mpvPath = which.sync('mpv'); @@ -132,6 +132,18 @@ const getDurationByMpv = async filePath => { return duration; }; +const throwOffLimitsErrors = (res, duration, fileSize) => { + const secondsInHour = 60 * 60; + if (duration > secondsInHour) { + const uploadLengthErrorMessage = `Your upload length is ${forHumansNoSeconds(duration)}, but currently the maximum length allowed is only 1 hour`; + return res.status(400).send(uploadLengthErrorMessage); + } + if (fileSize > uploadLimitInMB) { + const uploadSizeErrorMessage = `Your upload size is ${fileSize} MB, but the maximum size currently allowed is ${uploadLimitInMB} MB.`; + return res.status(400).send(uploadSizeErrorMessage); + } +} + const buildWhisperArguments = ({filePath, language, model, randomNumber}) => { // queue up arguments, path is the first one const arguments = [filePath]; @@ -266,6 +278,7 @@ module.exports = { writeToProcessingDataFile, moveSubtitleFiles, getDurationByMpv, + throwOffLimitsErrors, // handle output from the whisper process handleStdOut, diff --git a/routes/transcribe.js b/routes/transcribe.js index 54c0881..d9b7c81 100644 --- a/routes/transcribe.js +++ b/routes/transcribe.js @@ -13,11 +13,11 @@ const fs = require('fs-extra'); const { downloadFile, getFilename } = require('../downloading/yt-dlp-download'); const transcribeWrapped = require('../transcribe/transcribe-wrapped'); const { targetLanguages } = require('../constants/constants'); -const {forHumansNoSeconds, getamountOfRunningJobs, sendToWebsocket, generateRandomNumber} = require('../helpers/helpers'); +const {getamountOfRunningJobs, sendToWebsocket, generateRandomNumber} = require('../helpers/helpers'); const {makeFileNameSafe} = require('../lib/files'); const { addItemToQueue, getNumberOfPendingOrProcessingJobs } = require('../queue/queue'); const {addToJobProcessOrQueue} = require('../queue/newQueue'); -const {getDurationByMpv} = require('../lib/transcribing'); +const {getDurationByMpv, throwOffLimitsErrors} = require('../lib/transcribing'); const nodeEnv = process.env.NODE_ENV || 'development'; @@ -127,59 +127,44 @@ router.post('/file', upload.single('file'), async function (req, res, next) { const audioStream = ffprobeResponse.streams.filter(stream => stream.codec_type === 'audio')[0]; const uploadDurationInSeconds = Math.round(audioStream.duration || await getDurationByMpv(uploadedFilePath)); - + const stats = await fs.promises.stat(uploadedFilePath); const fileSizeInBytes = stats.size; const fileSizeInMB = Number(fileSizeInBytes / 1048576).toFixed(1); // TODO: pull out into a function // error if on FS and over file size limit or duration limit - const domainName = req.hostname; - const isFreeSubtitles = domainName === 'freesubtitles.ai'; + const isFreeSubtitles = req.hostname === 'freesubtitles.ai'; if (isFreeSubtitles && !isYtdlp) { - - const amountOfSecondsInHour = 60 * 60; - if (uploadDurationInSeconds > amountOfSecondsInHour) { - const uploadLengthErrorMessage = `Your upload length is ${forHumansNoSeconds(uploadDurationInSeconds)}, but currently the maximum length allowed is only 1 hour`; - return res.status(400).send(uploadLengthErrorMessage); - } - if (fileSizeInMB > uploadLimitInMB) { - const uploadSizeErrorMessage = `Your upload size is ${fileSizeInMB} MB, but the maximum size currently allowed is ${uploadLimitInMB} MB.`; - return res.status(400).send(uploadSizeErrorMessage); - } + throwOffLimitsErrors(res, uploadDurationInSeconds, fileSizeInMB); } // TODO: pull into its own function /** WEBSOCKET FUNCTIONALITY **/ // load websocket by passed number - const currentlyRunningJobs = getamountOfRunningJobs(); const amountInQueue = global.newQueue.length const totalOutstanding = currentlyRunningJobs + amountInQueue - maxConcurrentJobs + 1; - l('totaloutstanding'); - l(totalOutstanding); + l({totalOutstanding}); /** WEBSOCKET FUNCTIONALITY END **/ - const originalFileExtension = path.parse(originalFileNameWithExtension).ext; - const originalFileNameWithoutExtension = path.parse(originalFileNameWithExtension).name; + const {ext: fileExtension, name: fileNameNoExtension} = path.parse(originalFileNameWithExtension); // directory name - const directorySafeFileNameWithoutExtension = makeFileNameSafe(originalFileNameWithoutExtension) + const directorySafeFileNameWithoutExtension = makeFileNameSafe(fileNameNoExtension); // used for the final media resting place - const directorySafeFileNameWithExtension = `${directorySafeFileNameWithoutExtension}${originalFileExtension}` + const directorySafeFileNameWithExtension = `${directorySafeFileNameWithoutExtension}${fileExtension}`; const timestampString = moment(new Date()).format('DD-MMMM-YYYY_HH_mm_ss'); - const separator = '--' - - const fileSafeNameWithDateTimestamp = `${directorySafeFileNameWithoutExtension}${separator}${timestampString}`; + const fileSafeNameWithDateTimestamp = `${directorySafeFileNameWithoutExtension}--${timestampString}`; - const fileSafeNameWithDateTimestampAndExtension = `${directorySafeFileNameWithoutExtension}${separator}${timestampString}${originalFileExtension}`; + const fileSafeNameWithDateTimestampAndExtension = `${directorySafeFileNameWithoutExtension}--${timestampString}${fileExtension}`; // pass ip to queue const ip = req.headers['x-forwarded-for'] || @@ -208,6 +193,7 @@ router.post('/file', upload.single('file'), async function (req, res, next) { uploadedFilePath, language, model, + fileExtension, directorySafeFileNameWithoutExtension, directorySafeFileNameWithExtension, originalFileNameWithExtension, diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index 67f4d99..07bd927 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -28,6 +28,8 @@ async function transcribe ({ model, websocketConnection, websocketNumber, + fileNameNoExtension, + fileExtension, directorySafeFileNameWithoutExtension, directorySafeFileNameWithExtension, originalFileNameWithExtension, @@ -76,7 +78,8 @@ async function transcribe ({ const fileInfo = { filename: directorySafeFileNameWithExtension, - fileExtension: path.parse(directorySafeFileNameWithExtension).ext, + fileNameNoExtension, + fileExtension, fileSafeNameWithExt: directorySafeFileNameWithExtension, fileSafeNameWithDateTimestamp, fileSizeInMB, From ff8069f8ad1ffdd34022309c49cfe7624a2e18ef Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sat, 14 Jan 2023 14:10:39 +0200 Subject: [PATCH 16/22] improve & refactor filenames --- lib/transcribing.js | 28 +++++----- routes/admin.js | 16 +++--- routes/api.js | 18 +++---- routes/player.js | 12 ++--- routes/transcribe.js | 53 +++++++++---------- transcribe/transcribe-api-wrapped.js | 6 +-- transcribe/transcribe-wrapped.js | 29 +++++----- transcribe/transcribing.js | 4 +- views/files.pug | 2 +- .../index/js/controllers/network-handling.pug | 11 ++-- 10 files changed, 89 insertions(+), 90 deletions(-) diff --git a/lib/transcribing.js b/lib/transcribing.js index 54fc272..34848ed 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -1,8 +1,8 @@ const fs = require('fs-extra'); const filenamify = require('filenamify'); const path = require('path'); -const which = require('which'); const mpvAPI = require('node-mpv'); +const moment = require('moment/moment'); const {autoDetectLanguage} = require('../transcribe/transcribing'); const {formatStdErr} = require('../helpers/formatStdErr'); @@ -12,7 +12,6 @@ const { convertSerbianCyrillicToLatin, convertChineseTraditionalToSimplified } = const {sendToWebsocket, forHumansNoSeconds} = require('../helpers/helpers'); const createTranslatedFiles = require('../translate/create-translated-files'); -const mpvPath = which.sync('mpv'); const isProd = process.env.NODE_ENV === 'production'; const multipleGpusEnabled = process.env.MULTIPLE_GPUS === 'true'; @@ -45,7 +44,7 @@ function handleStdOut (data) { } function handleStdErr ({ - model, language, originalFileName, processingDataPath + model, language, fileNameWithExtension, processingDataPath }) { return function (data) { (async function () { @@ -64,7 +63,7 @@ function handleStdErr ({ model, language, languageCode: getLanguageCodeForAllLanguages(language), - originalFileName + fileNameWithExtension }) })() @@ -225,7 +224,7 @@ const handleTranslation = async (fileInfo, websocketConnection) => { // need a better name? const moveSubtitleFiles = async fileInfo => { - await fs.move(fileInfo.originalUpload, `${fileInfo.originalContainingDir}/${fileInfo.fileSafeNameWithExt}`, {overwrite: true}); + await fs.move(fileInfo.originalUpload, `${fileInfo.originalContainingDir}/${fileInfo.safeFileNameWithExtension}`, {overwrite: true}); fileInfo.srtPath = `${fileInfo.originalDirectoryAndNewFileName}.srt`; fileInfo.vttPath = `${fileInfo.originalDirectoryAndNewFileName}.vtt`; @@ -254,22 +253,25 @@ const moveSubtitleFiles = async fileInfo => { // make sure the file name is safe for the file system const makeFileNameSafe = function (string) { - return filenamify(string, {replacement: '_' }) // replace all non-URL-safe characters with an underscore + return filenamify(string, {replacement: '_' }) // replace non-URL-safe characters with an underscore .split(':').join(':') // replace chinese colon with english colon .replace(/[&\/\\#,+()$~%.'":*?<>{}!]/g, '') // remove special characters .replace(/\s+/g,'_') // replace spaces with underscores } // -function createFileNames (originalFileName) { - // name of file without extension - const originalFileNameWithoutExtension = path.parse(originalFileName).name; +const createFileNames = fileNameWithExtension => { + const {name: fileNameNoExtension, ext: fileExtension} = path.parse(fileNameWithExtension); + const safeDirNameNoExtension = makeFileNameSafe(fileNameNoExtension); + const timestampString = moment(new Date()).format('DD-MMMM-YYYY_HH_mm_ss'); return { - originalFileNameWithExtension: originalFileName, // original file name - originalFileExtension: path.parse(originalFileName).ext, // file extension - originalFileNameWithoutExtension, // file name with extension removed - directorySafeFileNameWithoutExtension: makeFileNameSafe(originalFileNameWithoutExtension), // safe file name for directory name + fileNameNoExtension, + fileExtension, + safeDirNameNoExtension, + safeFileNameWithExtension: `${safeDirNameNoExtension}${fileExtension}`, + safeFileNameWithDateTimestamp: `${safeDirNameNoExtension}--${timestampString}`, + safeFileNameWithDateTimestampAndExtension: `${safeDirNameNoExtension}--${timestampString}${fileExtension}`, } } diff --git a/routes/admin.js b/routes/admin.js index 142dbbd..9952024 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -116,10 +116,10 @@ router.get('/admin', async function (req, res, next) { } let newItem = Object.assign({}, value); - delete newItem.directorySafeFileNameWithoutExtension; - delete newItem.directorySafeFileNameWithExtension; - delete newItem.fileSafeNameWithDateTimestamp - delete newItem.fileSafeNameWithDateTimestampAndExtension + delete newItem.safeDirNameNoExtension; + delete newItem.safeFileNameWithExtension; + delete newItem.safeFileNameWithDateTimestamp + delete newItem.safeFileNameWithDateTimestampAndExtension cleanedUpJobProcessObject[jobProcessNumber] = newItem; } @@ -138,10 +138,10 @@ router.get('/admin', async function (req, res, next) { let newItem = Object.assign({}, queueItem); - delete newItem.directorySafeFileNameWithoutExtension; - delete newItem.directorySafeFileNameWithExtension; - delete newItem.fileSafeNameWithDateTimestamp - delete newItem.fileSafeNameWithDateTimestampAndExtension + delete newItem.safeDirNameNoExtension; + delete newItem.safeFileNameWithExtension; + delete newItem.safeFileNameWithDateTimestamp + delete newItem.safeFileNameWithDateTimestampAndExtension cleanedUpNewQueue.push(newItem); } diff --git a/routes/api.js b/routes/api.js index c337ae2..f5cf988 100644 --- a/routes/api.js +++ b/routes/api.js @@ -33,9 +33,9 @@ router.post('/api', upload.single('file'), async function (req, res, next) { // get file names const file = req.file; - let originalFileName, uploadFileName; + let fileNameWithExtension, uploadFileName; if (file) { - originalFileName = file.originalname; + fileNameWithExtension = file.originalname; uploadFileName = file.filename; } @@ -73,14 +73,14 @@ router.post('/api', upload.single('file'), async function (req, res, next) { } // TODO: implement this - let originalFileNameWithExtension, originalFileExtension, originalFileNameWithoutExtension, directorySafeFileNameWithoutExtension; + let fileExtension, originalFileNameWithoutExtension, safeDirNameNoExtension; if (file) { ({ - originalFileNameWithExtension, - originalFileExtension, + fileNameWithExtension, + fileExtension, originalFileNameWithoutExtension, - directorySafeFileNameWithoutExtension - } = createFileNames(originalFileName)); + safeDirNameNoExtension + } = createFileNames(fileNameWithExtension)); } // random ten digit number @@ -148,9 +148,9 @@ router.post('/api', upload.single('file'), async function (req, res, next) { await transcribe({ language, model, - originalFileExtension, + fileExtension, uploadFileName: matchingFile, - originalFileName, + fileNameWithExtension, randomNumber }) diff --git a/routes/player.js b/routes/player.js index 9279e99..4e952fe 100644 --- a/routes/player.js +++ b/routes/player.js @@ -25,7 +25,7 @@ router.get('/player/:filename' , async function (req, res, next) { const processingData = JSON.parse(await fs.readFile(processingDataPath, 'utf8')); - const filePathWithoutExtension = `/transcriptions/${fileNameWithoutExtension}/${processingData.directoryFileName}`; + const filePathWithoutExtension = `/transcriptions/${fileNameWithoutExtension}/${processingData.safeDirNameNoExtension}`; // l('filePathWithoutExtension') // l(filePathWithoutExtension); @@ -92,7 +92,7 @@ router.get('/player/:filename/add' , async function (req, res, next) { const processingData = JSON.parse(await fs.readFile(processingDataPath, 'utf8')); - const originalVtt = await fs.readFile(`${containingFolder}/${processingData.directoryFileName}.vtt`, 'utf8'); + const originalVtt = await fs.readFile(`${containingFolder}/${processingData.safeDirNameNoExtension}.vtt`, 'utf8'); res.render('addTranslation/addTranslation', { title: 'Add Translation', @@ -126,9 +126,9 @@ router.post('/player/:filename/add' , async function (req, res, next) { const processingData = JSON.parse(await fs.readFile(processingDataPath, 'utf8')); - const originalVttPath = `${containingFolder}/${processingData.directoryFileName}.vtt`; + const originalVttPath = `${containingFolder}/${processingData.safeDirNameNoExtension}.vtt`; - const originalVtt = await fs.readFile(`${containingFolder}/${processingData.directoryFileName}.vtt`, 'utf8'); + const originalVtt = await fs.readFile(`${containingFolder}/${processingData.safeDirNameNoExtension}.vtt`, 'utf8'); const inputStream = new Readable(newVtt); @@ -153,9 +153,9 @@ router.post('/player/:filename/add' , async function (req, res, next) { l(reformatted); l('refomatted'); - const newVttPath = `${containingFolder}/${processingData.directoryFileName}_${language}.vtt`; + const newVttPath = `${containingFolder}/${processingData.safeDirNameNoExtension}_${language}.vtt`; - const originalFileVtt = `${containingFolder}/${processingData.directoryFileName}_${processingData.language}.vtt`; + const originalFileVtt = `${containingFolder}/${processingData.safeDirNameNoExtension}_${processingData.language}.vtt`; await fs.writeFile(newVttPath, reformatted, 'utf-8'); diff --git a/routes/transcribe.js b/routes/transcribe.js index d9b7c81..41638cb 100644 --- a/routes/transcribe.js +++ b/routes/transcribe.js @@ -13,11 +13,11 @@ const fs = require('fs-extra'); const { downloadFile, getFilename } = require('../downloading/yt-dlp-download'); const transcribeWrapped = require('../transcribe/transcribe-wrapped'); const { targetLanguages } = require('../constants/constants'); -const {getamountOfRunningJobs, sendToWebsocket, generateRandomNumber} = require('../helpers/helpers'); +const {getamountOfRunningJobs, sendToWebsocket, generateRandomNumber, forHumans} = require('../helpers/helpers'); const {makeFileNameSafe} = require('../lib/files'); const { addItemToQueue, getNumberOfPendingOrProcessingJobs } = require('../queue/queue'); const {addToJobProcessOrQueue} = require('../queue/newQueue'); -const {getDurationByMpv, throwOffLimitsErrors} = require('../lib/transcribing'); +const {getDurationByMpv, throwOffLimitsErrors, createFileNames} = require('../lib/transcribing'); const nodeEnv = process.env.NODE_ENV || 'development'; @@ -74,10 +74,10 @@ router.post('/file', upload.single('file'), async function (req, res, next) { throw new Error('no websocket!'); } - let originalFileNameWithExtension, uploadedFilePath, uploadGeneratedFilename; + let fileNameWithExtension, uploadedFilePath, uploadGeneratedFilename; if (passedFile) { - originalFileNameWithExtension = passedFile.originalname; + fileNameWithExtension = passedFile.originalname; uploadedFilePath = passedFile.path; uploadGeneratedFilename = passedFile.filename; l({uploadedFilePath}); @@ -95,9 +95,8 @@ router.post('/file', upload.single('file'), async function (req, res, next) { filename = filename.replace(/\r?\n|\r/g, ''); l({filename}); uploadGeneratedFilename = filename; - originalFileNameWithExtension = filename; - const baseName = path.parse(filename).name; - const extension = path.parse(filename).ext; + fileNameWithExtension = filename; + const {name: baseName, ext: extension} = path.parse(filename); uploadedFilePath = `uploads/${randomNumber}${extension}`; res.send('download'); @@ -120,6 +119,15 @@ router.post('/file', upload.single('file'), async function (req, res, next) { // ERROR } + const { + fileNameNoExtension, + fileExtension, + safeDirNameNoExtension, + safeFileNameWithExtension, + safeFileNameWithDateTimestamp, + safeFileNameWithDateTimestampAndExtension, + } = createFileNames(fileNameWithExtension); + l({uploadedFilePath}); // get upload duration @@ -128,13 +136,12 @@ router.post('/file', upload.single('file'), async function (req, res, next) { const audioStream = ffprobeResponse.streams.filter(stream => stream.codec_type === 'audio')[0]; const uploadDurationInSeconds = Math.round(audioStream.duration || await getDurationByMpv(uploadedFilePath)); + const stats = await fs.promises.stat(uploadedFilePath); const fileSizeInBytes = stats.size; const fileSizeInMB = Number(fileSizeInBytes / 1048576).toFixed(1); - // TODO: pull out into a function // error if on FS and over file size limit or duration limit - const isFreeSubtitles = req.hostname === 'freesubtitles.ai'; if (isFreeSubtitles && !isYtdlp) { throwOffLimitsErrors(res, uploadDurationInSeconds, fileSizeInMB); @@ -152,20 +159,6 @@ router.post('/file', upload.single('file'), async function (req, res, next) { /** WEBSOCKET FUNCTIONALITY END **/ - const {ext: fileExtension, name: fileNameNoExtension} = path.parse(originalFileNameWithExtension); - - // directory name - const directorySafeFileNameWithoutExtension = makeFileNameSafe(fileNameNoExtension); - - // used for the final media resting place - const directorySafeFileNameWithExtension = `${directorySafeFileNameWithoutExtension}${fileExtension}`; - - const timestampString = moment(new Date()).format('DD-MMMM-YYYY_HH_mm_ss'); - - const fileSafeNameWithDateTimestamp = `${directorySafeFileNameWithoutExtension}--${timestampString}`; - - const fileSafeNameWithDateTimestampAndExtension = `${directorySafeFileNameWithoutExtension}--${timestampString}${fileExtension}`; - // pass ip to queue const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress || @@ -175,7 +168,7 @@ router.post('/file', upload.single('file'), async function (req, res, next) { addItemToQueue({ model, language, - filename: originalFileNameWithExtension, + filename: fileNameWithExtension, ip, uploadDurationInSeconds, shouldTranslate, @@ -193,15 +186,17 @@ router.post('/file', upload.single('file'), async function (req, res, next) { uploadedFilePath, language, model, + fileNameWithExtension, + fileNameNoExtension, fileExtension, - directorySafeFileNameWithoutExtension, - directorySafeFileNameWithExtension, - originalFileNameWithExtension, - fileSafeNameWithDateTimestamp, - fileSafeNameWithDateTimestampAndExtension, + safeDirNameNoExtension, + safeFileNameWithExtension, + safeFileNameWithDateTimestamp, + safeFileNameWithDateTimestampAndExtension, uploadGeneratedFilename, shouldTranslate, uploadDurationInSeconds, + uploadDuration: forHumans(uploadDurationInSeconds), fileSizeInMB, ...(user && { user }), ...(downloadLink && { downloadLink }), diff --git a/transcribe/transcribe-api-wrapped.js b/transcribe/transcribe-api-wrapped.js index 4f8f56a..ba6c307 100644 --- a/transcribe/transcribe-api-wrapped.js +++ b/transcribe/transcribe-api-wrapped.js @@ -33,9 +33,9 @@ const whisperPath = which.sync('whisper') async function transcribe ({ language, model, - originalFileExtension, + fileExtension, uploadFileName, - originalFileName, + fileNameWithExtension, randomNumber // standin for claimId or something like that }) { return new Promise(async (resolve, reject) => { @@ -63,7 +63,7 @@ async function transcribe ({ whisperProcess.stdout.on('data', (data) => l(`STDOUT: ${data}`)); /** console output from stderr **/ // (progress comes through stderr for some reason) - whisperProcess.stderr.on('data', handleStdErr({ model, language, originalFileName, processingDataPath })); + whisperProcess.stderr.on('data', handleStdErr({ model, language, fileNameWithExtension, processingDataPath })); /** whisper responds with 0 or 1 process code **/ whisperProcess.on('close', handleProcessClose({ processingDataPath, originalUpload, randomNumber })) diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index 07bd927..08ca71e 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -28,16 +28,17 @@ async function transcribe ({ model, websocketConnection, websocketNumber, + fileNameWithExtension, fileNameNoExtension, fileExtension, - directorySafeFileNameWithoutExtension, - directorySafeFileNameWithExtension, - originalFileNameWithExtension, - fileSafeNameWithDateTimestamp, - fileSafeNameWithDateTimestampAndExtension, + safeDirNameNoExtension, + safeFileNameWithExtension, + safeFileNameWithDateTimestamp, + safeFileNameWithDateTimestampAndExtension, uploadGeneratedFilename, shouldTranslate, uploadDurationInSeconds, + uploadDuration, fileSizeInMB, user, downloadLink, @@ -74,25 +75,23 @@ async function transcribe ({ const uploadFolderFileName = uploadedFilePath.split(osSpecificPathSeparator).pop(); const originalUpload = `./uploads/${uploadFolderFileName}`; - const uploadDurationInSecondsHumanReadable = forHumans(uploadDurationInSeconds); - const fileInfo = { - filename: directorySafeFileNameWithExtension, + filename: fileNameWithExtension, fileNameNoExtension, fileExtension, - fileSafeNameWithExt: directorySafeFileNameWithExtension, - fileSafeNameWithDateTimestamp, + safeFileNameWithExtension, + safeFileNameWithDateTimestamp, fileSizeInMB, - directoryFileName: directorySafeFileNameWithoutExtension, - language: language === 'auto-detect' ? 'Auto-Detect' : language, + safeDirNameNoExtension, + language, languageCode: getLanguageCodeForAllLanguages(language), model, upload: uploadFolderFileName, uploadGeneratedFilename, originalContainingDir: `./transcriptions/${uploadGeneratedFilename}`, - originalDirectoryAndNewFileName: `./transcriptions/${uploadGeneratedFilename}/${directorySafeFileNameWithoutExtension}`, + originalDirectoryAndNewFileName: `./transcriptions/${uploadGeneratedFilename}/${safeDirNameNoExtension}`, uploadDurationInSeconds, - uploadDuration: uploadDurationInSecondsHumanReadable, + uploadDuration, originalUpload, user, downloadLink, @@ -221,7 +220,7 @@ async function transcribe ({ await fs.appendFile(`${fileInfo.originalContainingDir}/processing_data.json`, JSON.stringify(fileInfo), 'utf8'); // TODO: if no link passed, because if link was passed no need to rename directory - const renamedDirectory = `./transcriptions/${fileSafeNameWithDateTimestamp}`; + const renamedDirectory = `./transcriptions/${safeFileNameWithDateTimestamp}`; await fs.rename(fileInfo.originalContainingDir, renamedDirectory) // remove from global.transcriptions diff --git a/transcribe/transcribing.js b/transcribe/transcribing.js index bd4e3f3..a6d8b19 100644 --- a/transcribe/transcribing.js +++ b/transcribe/transcribing.js @@ -55,14 +55,14 @@ async function moveAndRenameFilesAndFolder ({ originalUpload, uploadFileName, sdHash, - originalFileExtension, + fileExtension, }) { const originalUploadPath = originalUpload; // the directory with the output from whisper let currentContainingDir = `./transcriptions/${sdHash}`; - const newUploadPath = `${currentContainingDir}/${sdHash}${originalFileExtension}` + const newUploadPath = `${currentContainingDir}/${sdHash}${fileExtension}` // rename original upload to use the original file upload name await fs.move(originalUploadPath, newUploadPath) diff --git a/views/files.pug b/views/files.pug index 7175c60..4e8cdd1 100644 --- a/views/files.pug +++ b/views/files.pug @@ -27,7 +27,7 @@ block content a(href='/player/' + file.name target="_blank") #{file.name} td(data-sort-value=file.processingData.language) #{file.processingData.language} td(data-sort-value=file.processingData.keepMedia) #{file.processingData.keepMedia} - td(data-sort-value=file.processingData.uploadDurationInSeconds data-type="number") #{file.processingData.uploadDurationInSecondsHumanReadable} + td(data-sort-value=file.processingData.uploadDurationInSeconds data-type="number") #{file.processingData.uploadDuration} td(data-sort-value=file.timestamp data-type) #{file.formattedDate} diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index d87d76d..b503414 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -179,6 +179,9 @@ script. let latestProgress, globalTimeRemaining, myUploadStarted = false; + const toTitleCase = str => !str || !str.trim() + ? str : str.toLowerCase().replace(/\b[a-z]/g, ltr => ltr.toUpperCase()); + const renderProcessingFeedback = ({data, hitTheBackend}) => { l('websocket data'); let loopStarted; @@ -308,7 +311,7 @@ script. const niceDate = new Date().toString().replace(/GMT.*/g, ''); $('#finishedData').html(`

Filename: ${filename}

-

Language: ${language}${isAutoDetected ? ' (Auto-Detected)' : ''}

+

Language: ${toTitleCase(language)}${isAutoDetected ? ' (Auto-Detected)' : ''}

Model: ${model}

Upload Duration: ${uploadDuration}

Started At: ${niceDate}

@@ -332,7 +335,7 @@ script. const renderCompletionFeedback = ({data}) => { const { filename, processingTime, language, model, upload, uploadDuration, processingRatio, startedAt, finishedAt, isAutoDetected = false, - fileSafeNameWithDateTimestamp, + safeFileNameWithDateTimestamp, } = data; l({data}); l('completed data'); @@ -341,7 +344,7 @@ script. $('#finishedData').html(`

Filename: ${filename}

Processing Time: ${processingTime}

-

Language: ${language}${isAutoDetected ? ' (Auto-Detected)' : ''}

+

Language: ${toTitleCase(language)}${isAutoDetected ? ' (Auto-Detected)' : ''}

Model: ${model}

Upload Name: ${upload}

Upload Duration: ${uploadDuration}

@@ -356,7 +359,7 @@ script. $('#startNewUpload').hide(); // redirect to the player page // 2 seconds to let the user see the completion message - setTimeout(() => window.location.href = `/player/${fileSafeNameWithDateTimestamp}`, 2000); + setTimeout(() => window.location.href = `/player/${safeFileNameWithDateTimestamp}`, 2000); } const renderError = data => { From 934b9c8a97059dd412857d2447227b1a795850b2 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sat, 14 Jan 2023 16:38:43 +0200 Subject: [PATCH 17/22] capitalize model on frontend --- views/index/js/controllers/network-handling.pug | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index b503414..12167fc 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -312,7 +312,7 @@ script. $('#finishedData').html(`

Filename: ${filename}

Language: ${toTitleCase(language)}${isAutoDetected ? ' (Auto-Detected)' : ''}

-

Model: ${model}

+

Model: ${toTitleCase(model)}

Upload Duration: ${uploadDuration}

Started At: ${niceDate}

`); @@ -345,7 +345,7 @@ script.

Filename: ${filename}

Processing Time: ${processingTime}

Language: ${toTitleCase(language)}${isAutoDetected ? ' (Auto-Detected)' : ''}

-

Model: ${model}

+

Model: ${toTitleCase(model)}

Upload Name: ${upload}

Upload Duration: ${uploadDuration}

Processing Ratio: ${processingRatio}

From a026d838acfd0827050f76582112803bb8ad5a2d Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sat, 14 Jan 2023 17:22:57 +0200 Subject: [PATCH 18/22] add translating status to the frontend --- .gitignore | 4 +++- transcribe/transcribe-wrapped.js | 1 + views/index/js/controllers/network-handling.pug | 6 ++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 2c4de2b..e8aaa9d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ downloads public/javascripts/ffmpeg-core.wasm .env -constants/apiTokens.txt \ No newline at end of file +constants/apiTokens.txt + +*.log \ No newline at end of file diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index 08ca71e..1ed4bbd 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -96,6 +96,7 @@ async function transcribe ({ user, downloadLink, processNumber, + shouldTranslate, translationStarted: false, translationFinished: false, } diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index 12167fc..05f3a32 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -306,13 +306,14 @@ script. // $('#latestData').css("font-size", "20px"); } - const renderFileDetails = ({filename, language, model, uploadDuration, isAutoDetected = false}) => { + const renderFileDetails = ({filename, language, model, shouldTranslate, uploadDuration, isAutoDetected = false}) => { l('file details data'); const niceDate = new Date().toString().replace(/GMT.*/g, ''); $('#finishedData').html(`

Filename: ${filename}

Language: ${toTitleCase(language)}${isAutoDetected ? ' (Auto-Detected)' : ''}

Model: ${toTitleCase(model)}

+

Translating: ${shouldTranslate ? 'Yes' : 'No'}

Upload Duration: ${uploadDuration}

Started At: ${niceDate}

`); @@ -334,7 +335,7 @@ script. const renderCompletionFeedback = ({data}) => { const { - filename, processingTime, language, model, upload, uploadDuration, processingRatio, startedAt, finishedAt, isAutoDetected = false, + filename, processingTime, language, model, shouldTranslate, upload, uploadDuration, processingRatio, startedAt, finishedAt, isAutoDetected = false, safeFileNameWithDateTimestamp, } = data; l({data}); @@ -346,6 +347,7 @@ script.

Processing Time: ${processingTime}

Language: ${toTitleCase(language)}${isAutoDetected ? ' (Auto-Detected)' : ''}

Model: ${toTitleCase(model)}

+

Translating: ${shouldTranslate ? 'Yes' : 'No'}

Upload Name: ${upload}

Upload Duration: ${uploadDuration}

Processing Ratio: ${processingRatio}

From 8d1a892ff72612e115d7fbaf901fbf1af554e709 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sat, 14 Jan 2023 20:19:14 +0200 Subject: [PATCH 19/22] refactor circle progress --- .../index/js/controllers/network-handling.pug | 57 +++++++------------ views/index/js/js-index.pug | 14 ++--- 2 files changed, 27 insertions(+), 44 deletions(-) diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index 05f3a32..5e46097 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -1,5 +1,13 @@ script. - const renderDownloadInfo = ({ data, circleProgress }) => { + + const changeCircleProgress = num => { + window.circleProgress.attr({ + max: 100, + value: +num, + }); + } + + const renderDownloadInfo = ({data}) => { // let's use my algo for calculating the ETA because it's more accurate // therefore all we need is percentage // we'll calculate, seconds elapsed, seconds remaining @@ -33,16 +41,10 @@ script. $('#progress').html(`${percentDownloaded}% downloaded`); document.title = `${percentDownloaded}% Downloaded - ${fileName}`; - circleProgress.attr({ - max: 100, - value: Number(percentDownloaded), - }); + changeCircleProgress(percentDownloaded); if (percentDownloaded === 100) { - circleProgress.attr({ - max: 100, - value: 0, - }); + changeCircleProgress(0); $('.progress').hide(); } else { $('.progress').show(); @@ -74,7 +76,7 @@ script. // global vars used for using in the decrementing function let globalEstimatedSecondsRemaining, globalTimeElapsedInSeconds, globalUploadedAmountInMB; - const progressUpload = (evt, startDate, circleProgress, fileName) => { + const progressUpload = (evt, startDate, fileName) => { l(evt); $('#form').hide(); $('#startNewUpload').show(); @@ -96,16 +98,10 @@ script. $('#progress').html(`${percentUpload}% uploaded`); document.title = `${percentUpload}% Uploaded - ${fileName}`; - circleProgress.attr({ - max: 100, - value: Number(percentUpload), - }); + changeCircleProgress(percentUpload); if (percentUpload === 100) { - circleProgress.attr({ - max: 100, - value: 0, - }); + changeCircleProgress(0); $('.progress').hide(); } else { $('.progress').show(); @@ -133,19 +129,15 @@ script. } } - const loadAjax = ({ response, circleProgress }) => { + const loadAjax = () => { if(downloadStarted) downloadFinished = true; if(transcriptionFailed) return - l({response}); $('#processingData').show(); $('#latestData').show(); $('#progress').hide(); $('#timeEstimator').hide(); $('#header').html('Processing..'); - circleProgress.attr({ - max: 100, - value: 0, - }); + changeCircleProgress(0); $('.progress').show(); } @@ -241,10 +233,7 @@ script. $('#processingData').show(); // actual process data coming back if (percentDone > 0) { - circleProgress.attr({ - max: 100, - value: percentDone, - }); + changeCircleProgress(percentDone); if (percentDone === 100) { $('.progress').hide(); @@ -285,7 +274,7 @@ script. } } - const renderStartingFeedback = ({ data, circleProgress }) => { + const renderStartingFeedback = ({data}) => { inTheQueue = false; document.title = `Starting processing..`; l('starting data'); @@ -294,15 +283,9 @@ script. $('#processingData').hide(); $('#secondProcessingData').hide(); myProcessingStarted = true; - circleProgress.attr({ - max: 100, - value: 100, - }); + changeCircleProgress(100); $('.progress').show(); - circleProgress.attr({ - max: 100, - value: 0, - }); + changeCircleProgress(0); // $('#latestData').css("font-size", "20px"); } diff --git a/views/index/js/js-index.pug b/views/index/js/js-index.pug index 554492b..10a4627 100644 --- a/views/index/js/js-index.pug +++ b/views/index/js/js-index.pug @@ -16,7 +16,7 @@ script. l(ytdlp) // global variables - let circleProgress, hitTheBackend, videoDurationInSeconds, filename, uploadStarted; + let hitTheBackend, videoDurationInSeconds, filename, uploadStarted; let processStarted, processFailed, uploadFinished, processingData, timeRemaining; let downloadStarted, downloadFinished; let transcriptionFailed = false; @@ -66,7 +66,7 @@ script. $(document).ready(() => { // start progress at 100 and rewind it when starting // I did this by accident the first time but I like it so I kept it - circleProgress = new CircleProgress('.progress', { + window.circleProgress = new CircleProgress('.progress', { max: 100, value: 100, textFormat: 'vertical', @@ -243,7 +243,7 @@ script. const submitDate = new Date(); /** upload progress / countdown functionality **/ - if(!downloadLink) ajax.upload.addEventListener('progress', evt => progressUpload(evt, submitDate, circleProgress, fileName)); + if(!downloadLink) ajax.upload.addEventListener('progress', evt => progressUpload(evt, submitDate, fileName)); ajax.addEventListener('error', err => ce(err), false); @@ -272,7 +272,7 @@ script. if (response === 'download') { } else { - loadAjax({response, circleProgress}); + loadAjax({response}); } } @@ -329,16 +329,16 @@ script. const downloadingIsFinished = message === 'downloadingFinished'; - isDownloadingInfo && renderDownloadInfo({data , circleProgress }); + isDownloadingInfo && renderDownloadInfo({data}); - downloadingIsFinished && loadAjax({circleProgress}) + downloadingIsFinished && loadAjax() // WEBSOCKET DATA COMING FROM THE BACKEND isProcessingInfo && renderProcessingFeedback({data, hitTheBackend}); sendingQueueInformation && renderQueue({place: data.placeInQueue, log: 'initial queue data'}); - transcriptionIsStarting && renderStartingFeedback({ data, circleProgress }); + transcriptionIsStarting && renderStartingFeedback({data}); isFileDetailsMessage && renderFileDetails(data); From 76f178e501b9b73ce97f68c7f881b3c381ddae3a Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sun, 15 Jan 2023 08:21:11 +0200 Subject: [PATCH 20/22] pass the capitalizing function from the backend --- helpers/helpers.js | 4 ++++ routes/index.js | 6 ++++-- views/index/js/controllers/network-handling.pug | 6 ++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/helpers/helpers.js b/helpers/helpers.js index 582d252..054d180 100644 --- a/helpers/helpers.js +++ b/helpers/helpers.js @@ -96,6 +96,9 @@ const sendToWebsocket = (websocketConnection, data) => { // TODO: not the world's greatest implemention const generateRandomNumber = () => Math.floor(Math.random() * 10_000_000_000).toString(); +const toTitleCase = str => !str || !str.trim() ? str + : str.toLowerCase().replace(/\b[a-z]/g, ltr => ltr.toUpperCase()); + module.exports = { forHumans, forHumansNoSeconds, @@ -104,4 +107,5 @@ module.exports = { getamountOfRunningJobs, sendToWebsocket, generateRandomNumber, + toTitleCase, } diff --git a/routes/index.js b/routes/index.js index 48a07ec..df16a07 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,6 +1,6 @@ const express = require('express'); const router = express.Router(); -const {forHumans, decrementBySecond} = require('../helpers/helpers') +const {forHumans, decrementBySecond, toTitleCase} = require('../helpers/helpers') const { modelsArray, languagesArray } = require('../constants/constants'); const fs = require('fs-extra') @@ -29,7 +29,8 @@ router.get('/', function (req, res, next) { uploadLimitInMB, modelsArray, languagesArray, - decrementBySecond + decrementBySecond, + toTitleCase, }); }); @@ -66,6 +67,7 @@ router.get('/ytdlp', async function (req, res, next) { modelsArray, languagesArray, decrementBySecond, + toTitleCase, ytdlp: true, user, skipToFront: skip diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index 5e46097..4cd2da3 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -1,5 +1,7 @@ script. + const toTitleCase = !{toTitleCase}; + const changeCircleProgress = num => { window.circleProgress.attr({ max: 100, @@ -171,9 +173,6 @@ script. let latestProgress, globalTimeRemaining, myUploadStarted = false; - const toTitleCase = str => !str || !str.trim() - ? str : str.toLowerCase().replace(/\b[a-z]/g, ltr => ltr.toUpperCase()); - const renderProcessingFeedback = ({data, hitTheBackend}) => { l('websocket data'); let loopStarted; @@ -255,7 +254,6 @@ script. $('#processingData').html(`${processFeedback}${processingData}`); }, 1000); } - } else { $('#processingData').html(`${processFeedback}Transcription starting soon..`); } From ad1e523d752d6e9296511c4222c87e85d51ce6a9 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sun, 15 Jan 2023 11:31:32 +0200 Subject: [PATCH 21/22] completion data ssr --- lib/transcribing.js | 19 ++++++++++++++++++- transcribe/transcribe-wrapped.js | 5 +++-- .../index/js/controllers/network-handling.pug | 18 ++---------------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/transcribing.js b/lib/transcribing.js index 34848ed..98b7baf 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -9,7 +9,7 @@ const {formatStdErr} = require('../helpers/formatStdErr'); const {getLanguageCodeForAllLanguages} = require('../constants/constants'); const { stripOutTextAndTimestamps } = require('../translate/helpers'); const { convertSerbianCyrillicToLatin, convertChineseTraditionalToSimplified } = require('./convertText'); -const {sendToWebsocket, forHumansNoSeconds} = require('../helpers/helpers'); +const {sendToWebsocket, forHumansNoSeconds, toTitleCase} = require('../helpers/helpers'); const createTranslatedFiles = require('../translate/create-translated-files'); @@ -239,6 +239,22 @@ const moveSubtitleFiles = async fileInfo => { } } +const generateCompletionDataHTML = data => { + l('generating completion data html') + return ` +

Filename: ${data.filename}

+

Processing Time: ${data.processingTime}

+

Language: ${toTitleCase(data.language)}${data.isAutoDetected ? ' (Auto-Detected)' : ''}

+

Model: ${toTitleCase(data.model)}

+

Translating: ${data.shouldTranslate ? 'Yes' : 'No'}

+

Upload Name: ${data.upload}

+

Upload Duration: ${data.uploadDuration}

+

Processing Ratio: ${data.processingRatio}

+

Started At: ${data.startedAt}

+

Finished At: ${data.finishedAt}

+ `; +} + // example file from multer // { // fieldname: 'file', @@ -291,6 +307,7 @@ module.exports = { removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation, + generateCompletionDataHTML, // file name helpers makeFileNameSafe, diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index 1ed4bbd..749ffb4 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -8,7 +8,7 @@ const path = require('path'); const {languagesToTranscribe, getLanguageCodeForAllLanguages} = require('../constants/constants'); const {forHumans, getamountOfRunningJobs, sendToWebsocket} = require('../helpers/helpers'); const {formatStdErr} = require('../helpers/formatStdErr'); -const {buildWhisperArguments, convertLanguageText, removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation, moveSubtitleFiles} = require('../lib/transcribing'); +const {buildWhisperArguments, convertLanguageText, removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation, moveSubtitleFiles, generateCompletionDataHTML} = require('../lib/transcribing'); const {stripOutTextAndTimestamps} = require('../translate/helpers'); const {updateQueueItemStatus} = require('../queue/queue'); @@ -216,6 +216,8 @@ async function transcribe ({ fileInfo.targetLanguages = languagesToTranscribe.filter(lang => lang !== fileInfo.language); } + fileInfo.completionDataHTML = generateCompletionDataHTML(fileInfo); + l({fileInfo}); // save processing_data.json await fs.appendFile(`${fileInfo.originalContainingDir}/processing_data.json`, JSON.stringify(fileInfo), 'utf8'); @@ -226,7 +228,6 @@ async function transcribe ({ // remove from global.transcriptions global.transcriptions = removeFromArrayByWsNumber(global.transcriptions, websocketNumber); - // tell frontend upload is done sendToWebsocket(websocketConnection, { status: 'Completed', diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index 4cd2da3..8eec9ef 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -315,26 +315,12 @@ script. } const renderCompletionFeedback = ({data}) => { - const { - filename, processingTime, language, model, shouldTranslate, upload, uploadDuration, processingRatio, startedAt, finishedAt, isAutoDetected = false, - safeFileNameWithDateTimestamp, - } = data; + const {safeFileNameWithDateTimestamp, completionDataHTML} = data; l({data}); l('completed data'); if (window.decrementInterval) clearInterval(window.decrementInterval); $('#latestData').html(`Congratulations, you're done!`); - $('#finishedData').html(` -

Filename: ${filename}

-

Processing Time: ${processingTime}

-

Language: ${toTitleCase(language)}${isAutoDetected ? ' (Auto-Detected)' : ''}

-

Model: ${toTitleCase(model)}

-

Translating: ${shouldTranslate ? 'Yes' : 'No'}

-

Upload Name: ${upload}

-

Upload Duration: ${uploadDuration}

-

Processing Ratio: ${processingRatio}

-

Started At: ${startedAt}

-

Finished At: ${finishedAt}

- `); + $('#finishedData').html(completionDataHTML); $('#header').html('Transcription Completed'); $('#processingData').hide(); // show refresh button From c73c5514ca10b9df6029b6b1bc6fd72a1b0f2682 Mon Sep 17 00:00:00 2001 From: Omar Shareef Abdul-Bar Date: Sun, 15 Jan 2023 11:59:51 +0200 Subject: [PATCH 22/22] file details ssr --- lib/transcribing.js | 40 +++++++++++-------- transcribe/transcribe-wrapped.js | 3 +- translate/create-translated-files.js | 9 ++--- .../index/js/controllers/network-handling.pug | 11 +---- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/lib/transcribing.js b/lib/transcribing.js index 98b7baf..37e0dae 100644 --- a/lib/transcribing.js +++ b/lib/transcribing.js @@ -120,6 +120,28 @@ function handleProcessClose ({ processingDataPath, originalUpload, randomNumber } } +const generateFileDetailsHTML = data => ` +

Filename: ${data.filename}

+

Language: ${toTitleCase(data.language)}${data.isAutoDetected ? ' (Auto-Detected)' : ''}

+

Model: ${toTitleCase(data.model)}

+

Translating: ${data.shouldTranslate ? 'Yes' : 'No'}

+

Upload Duration: ${data.uploadDuration}

+

Started At: ${data.niceDate}

+`; + +const generateCompletionDataHTML = data => ` +

Filename: ${data.filename}

+

Processing Time: ${data.processingTime}

+

Language: ${toTitleCase(data.language)}${data.isAutoDetected ? ' (Auto-Detected)' : ''}

+

Model: ${toTitleCase(data.model)}

+

Translating: ${data.shouldTranslate ? 'Yes' : 'No'}

+

Upload Name: ${data.upload}

+

Upload Duration: ${data.uploadDuration}

+

Processing Ratio: ${data.processingRatio}

+

Started At: ${data.startedAt}

+

Finished At: ${data.finishedAt}

+`; + // Alternative method to get duration due to ffprobe limitation const getDurationByMpv = async filePath => { const mpv = new mpvAPI({audio_only: true}); @@ -198,6 +220,7 @@ const updateDetectedLanguage = ({data, fileInfo, websocketConnection}) => { fileInfo.language = detectedLang; fileInfo.languageCode = getLanguageCodeForAllLanguages(detectedLang); fileInfo.isAutoDetected = true; + fileInfo.fileDetailsHTML = generateFileDetailsHTML(fileInfo); sendToWebsocket(websocketConnection, {message: 'fileDetails', ...fileInfo}); return detectedLang; } @@ -239,22 +262,6 @@ const moveSubtitleFiles = async fileInfo => { } } -const generateCompletionDataHTML = data => { - l('generating completion data html') - return ` -

Filename: ${data.filename}

-

Processing Time: ${data.processingTime}

-

Language: ${toTitleCase(data.language)}${data.isAutoDetected ? ' (Auto-Detected)' : ''}

-

Model: ${toTitleCase(data.model)}

-

Translating: ${data.shouldTranslate ? 'Yes' : 'No'}

-

Upload Name: ${data.upload}

-

Upload Duration: ${data.uploadDuration}

-

Processing Ratio: ${data.processingRatio}

-

Started At: ${data.startedAt}

-

Finished At: ${data.finishedAt}

- `; -} - // example file from multer // { // fieldname: 'file', @@ -307,6 +314,7 @@ module.exports = { removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation, + generateFileDetailsHTML, generateCompletionDataHTML, // file name helpers diff --git a/transcribe/transcribe-wrapped.js b/transcribe/transcribe-wrapped.js index 749ffb4..93c3b86 100644 --- a/transcribe/transcribe-wrapped.js +++ b/transcribe/transcribe-wrapped.js @@ -8,7 +8,7 @@ const path = require('path'); const {languagesToTranscribe, getLanguageCodeForAllLanguages} = require('../constants/constants'); const {forHumans, getamountOfRunningJobs, sendToWebsocket} = require('../helpers/helpers'); const {formatStdErr} = require('../helpers/formatStdErr'); -const {buildWhisperArguments, convertLanguageText, removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation, moveSubtitleFiles, generateCompletionDataHTML} = require('../lib/transcribing'); +const {buildWhisperArguments, convertLanguageText, removeFromArrayByWsNumber, updateDetectedLanguage, handleTranslation, moveSubtitleFiles, generateCompletionDataHTML, generateFileDetailsHTML} = require('../lib/transcribing'); const {stripOutTextAndTimestamps} = require('../translate/helpers'); const {updateQueueItemStatus} = require('../queue/queue'); @@ -101,6 +101,7 @@ async function transcribe ({ translationFinished: false, } + fileInfo.fileDetailsHTML = generateFileDetailsHTML(fileInfo); sendToWebsocket(websocketConnection, {message: 'fileDetails', ...fileInfo}); /** INSTANTIATE WHISPER PROCESS **/ diff --git a/translate/create-translated-files.js b/translate/create-translated-files.js index a71251d..68c452f 100644 --- a/translate/create-translated-files.js +++ b/translate/create-translated-files.js @@ -4,7 +4,8 @@ const fs = require('fs-extra'); const { languagesToTranscribe, allLanguages } = require('../constants/constants');; const { reformatVtt } = require('./helpers') const { simplified } = require('zh-convert'); -const translateText = require('./google-translate-browser') +const translateText = require('./google-translate-browser'); +const {sendToWebsocket} = require('../helpers/helpers'); const convert = require('cyrillic-to-latin'); @@ -67,11 +68,7 @@ async function createTranslatedFiles ({ try { // no need to translate just copy the file if (languageToConvertTo !== language) { - websocketConnection.send(JSON.stringify({ - languageUpdate: `Translating into ${languageToConvertTo}..`, - message: 'languageUpdate' - }), function () {}); - + sendToWebsocket(websocketConnection, {message: 'languageUpdate', languageUpdate: `Translating into ${languageToConvertTo}..`}); const sourceLanguageCode = getCodeFromLanguageName(language); const targetLanguageCode = getCodeFromLanguageName(languageToConvertTo); diff --git a/views/index/js/controllers/network-handling.pug b/views/index/js/controllers/network-handling.pug index 8eec9ef..62487db 100644 --- a/views/index/js/controllers/network-handling.pug +++ b/views/index/js/controllers/network-handling.pug @@ -287,17 +287,10 @@ script. // $('#latestData').css("font-size", "20px"); } - const renderFileDetails = ({filename, language, model, shouldTranslate, uploadDuration, isAutoDetected = false}) => { + const renderFileDetails = ({fileDetailsHTML}) => { l('file details data'); const niceDate = new Date().toString().replace(/GMT.*/g, ''); - $('#finishedData').html(` -

Filename: ${filename}

-

Language: ${toTitleCase(language)}${isAutoDetected ? ' (Auto-Detected)' : ''}

-

Model: ${toTitleCase(model)}

-

Translating: ${shouldTranslate ? 'Yes' : 'No'}

-

Upload Duration: ${uploadDuration}

-

Started At: ${niceDate}

- `); + $('#finishedData').html(fileDetailsHTML); } const renderTranslationUpdate = data => {